/******************************************************************************
    Atari 400/800

    ANTIC video controller

    Juergen Buchmueller, June 1998
******************************************************************************/

#include "emu.h"
#include "cpu/m6502/m6502.h"
#include "includes/atari.h"

#ifdef MAME_DEBUG
#define VERBOSE 1
#else
#define VERBOSE 0
#endif

#define LOG(x)	do { if (VERBOSE) logerror x; } while (0)

ANTIC antic;

/**************************************************************
 *
 * Reset ANTIC
 *
 **************************************************************/

void antic_reset(void)
{
	/* reset the ANTIC read / write registers */
	memset(&antic.r, 0, sizeof(antic.r));
	memset(&antic.w, 0, sizeof(antic.w));
	antic.r.antic00 = 0xff;
	antic.r.antic01 = 0xff;
	antic.r.antic02 = 0xff;
	antic.r.antic03 = 0xff;
	antic.r.antic04 = 0xff;
	antic.r.antic05 = 0xff;
	antic.r.antic06 = 0xff;
	antic.r.antic07 = 0xff;
	antic.r.antic08 = 0xff;
	antic.r.antic09 = 0xff;
	antic.r.antic0a = 0xff;
	antic.r.penh	= 0x00;
	antic.r.penv	= 0x00;
	antic.r.antic0e = 0xff;
	antic.r.nmist	= 0x1f;
}

/**************************************************************
 *
 * Read ANTIC hardware registers
 *
 **************************************************************/
READ8_HANDLER ( atari_antic_r )
{
	UINT8 data = 0xff;

	switch (offset & 15)
	{
	case  0: /* nothing */
		data = antic.r.antic00;
		break;
	case  1: /* nothing */
		data = antic.r.antic01;
		break;
	case  2: /* nothing */
		data = antic.r.antic02;
		break;
	case  3: /* nothing */
		data = antic.r.antic03;
		break;
	case  4: /* nothing */
		data = antic.r.antic04;
		break;
	case  5: /* nothing */
		data = antic.r.antic05;
		break;
	case  6: /* nothing */
		data = antic.r.antic06;
		break;
	case  7: /* nothing */
		data = antic.r.antic07;
		break;
	case  8: /* nothing */
		data = antic.r.antic08;
		break;
	case  9: /* nothing */
		data = antic.r.antic09;
		break;
	case 10: /* WSYNC read */
		device_spin_until_trigger(space->machine().device("maincpu"), TRIGGER_HSYNC);
		antic.w.wsync = 1;
		data = antic.r.antic0a;
		break;
	case 11: /* vert counter (scanline / 2) */
		data = antic.r.vcount = antic.scanline >> 1;
		break;
	case 12: /* light pen horz pos */
		data = antic.r.penh;
		break;
	case 13: /* light pen vert pos */
		data = antic.r.penv;
		break;
	case 14: /* NMI enable */
		data = antic.r.antic0e;
		break;
	case 15: /* NMI status */
		data = antic.r.nmist;
		break;
	}
	return data;
}

/**************************************************************
 *
 * Write ANTIC hardware registers
 *
 **************************************************************/

WRITE8_HANDLER ( atari_antic_w )
{
	int temp;

	switch (offset & 15)
	{
	case  0:
		if( data == antic.w.dmactl )
			break;
		LOG(("ANTIC 00 write DMACTL $%02X\n", data));
		antic.w.dmactl = data;
		switch (data & 3)
		{
			case 0: antic.pfwidth =  0; break;
			case 1: antic.pfwidth = 32; break;
			case 2: antic.pfwidth = 40; break;
			case 3: antic.pfwidth = 48; break;
		}
		break;
	case  1:
		if( data == antic.w.chactl )
			break;
		LOG(("ANTIC 01 write CHACTL $%02X\n", data));
		antic.w.chactl = data;
		antic.chand = (data & 1) ? 0x00 : 0xff;
		antic.chxor = (data & 2) ? 0xff : 0x00;
		break;
	case  2:
		LOG(("ANTIC 02 write DLISTL $%02X\n", data));
		antic.w.dlistl = data;
		temp = (antic.w.dlisth << 8) + antic.w.dlistl;
		antic.dpage = temp & DPAGE;
		antic.doffs = temp & DOFFS;
		break;
	case  3:
		LOG(("ANTIC 03 write DLISTH $%02X\n", data));
		antic.w.dlisth = data;
		temp = (antic.w.dlisth << 8) + antic.w.dlistl;
		antic.dpage = temp & DPAGE;
		antic.doffs = temp & DOFFS;
		break;
	case  4:
		if( data == antic.w.hscrol )
			break;
		LOG(("ANTIC 04 write HSCROL $%02X\n", data));
		antic.w.hscrol = data & 15;
		break;
	case  5:
		if( data == antic.w.vscrol )
			break;
		LOG(("ANTIC 05 write VSCROL $%02X\n", data));
		antic.w.vscrol = data & 15;
		break;
	case  6:
		if( data == antic.w.pmbasl )
			break;
		LOG(("ANTIC 06 write PMBASL $%02X\n", data));
		/* antic.w.pmbasl = data; */
		break;
	case  7:
		if( data == antic.w.pmbash )
			break;
		LOG(("ANTIC 07 write PMBASH $%02X\n", data));
		antic.w.pmbash = data;
		antic.pmbase_s = (data & 0xfc) << 8;
		antic.pmbase_d = (data & 0xf8) << 8;
		break;
	case  8:
		if( data == antic.w.chbasl )
			break;
		LOG(("ANTIC 08 write CHBASL $%02X\n", data));
		/* antic.w.chbasl = data; */
		break;
	case  9:
		if( data == antic.w.chbash )
			break;
		LOG(("ANTIC 09 write CHBASH $%02X\n", data));
		antic.w.chbash = data;
		break;
	case 10: /* WSYNC write */
		LOG(("ANTIC 0A write WSYNC  $%02X\n", data));
		device_spin_until_trigger(space->machine().device("maincpu"), TRIGGER_HSYNC);
		antic.w.wsync = 1;
		break;
	case 11:
		if( data == antic.w.antic0b )
			break;
		LOG(("ANTIC 0B write ?????? $%02X\n", data));
		antic.w.antic0b = data;
		break;
	case 12:
		if( data == antic.w.antic0c )
			break;
		LOG(("ANTIC 0C write ?????? $%02X\n", data));
		antic.w.antic0c = data;
		break;
	case 13:
		if( data == antic.w.antic0d )
			break;
		LOG(("ANTIC 0D write ?????? $%02X\n", data));
		antic.w.antic0d = data;
		break;
	case 14:
		if( data == antic.w.nmien )
			break;
		LOG(("ANTIC 0E write NMIEN  $%02X\n", data));
		antic.w.nmien  = data;
		break;
	case 15:
		LOG(("ANTIC 0F write NMIRES $%02X\n", data));
		antic.r.nmist = 0x1f;
		antic.w.nmires = data;
		break;
	}
}

/*************  ANTIC mode 00: *********************************
 * generate 1-8 empty scanlines
 ***************************************************************/
ANTIC_RENDERER( antic_mode_0_xx )
{
	PREPARE();
	memset(dst, PBK, HWIDTH*4);
	POST();
}

/*************  ANTIC mode 01: *********************************
 * display list jump, eventually wait for vsync
 ***************************************************************/


/*************  ANTIC mode 02: *********************************
 * character mode 8x8:2 (32/40/48 byte per line)
 ***************************************************************/
#define MODE2(s) COPY4(dst, antic.pf_21[video->data[s]])

ANTIC_RENDERER( antic_mode_2_32 )
{
	PREPARE_TXT2(space, 32);
	REP32(MODE2);
	POST_TXT(32);
}
ANTIC_RENDERER( antic_mode_2_40 )
{
	PREPARE_TXT2(space, 40);
	REP40(MODE2);
	POST_TXT(40);
}
ANTIC_RENDERER( antic_mode_2_48 )
{
	PREPARE_TXT2(space, 48);
	REP48(MODE2);
	POST_TXT(48);
}

/*************  ANTIC mode 03: *********************************
 * character mode 8x10:2 (32/40/48 byte per line)
 ***************************************************************/
#define MODE3(s) COPY4(dst, antic.pf_21[video->data[s]])

ANTIC_RENDERER( antic_mode_3_32 )
{
	PREPARE_TXT3(space, 32);
	REP32(MODE3);
	POST_TXT(32);
}
ANTIC_RENDERER( antic_mode_3_40 )
{
	PREPARE_TXT3(space, 40);
	REP40(MODE3);
	POST_TXT(40);
}
ANTIC_RENDERER( antic_mode_3_48 )
{
	PREPARE_TXT3(space, 48);
	REP48(MODE3);
	POST_TXT(48);
}

/*************  ANTIC mode 04: *********************************
 * character mode 8x8:4 multi color (32/40/48 byte per line)
 ***************************************************************/
#define MODE4(s) COPY4(dst, antic.pf_x10b[video->data[s]])

ANTIC_RENDERER( antic_mode_4_32 )
{
	PREPARE_TXT45(space, 32,0);
	REP32(MODE4);
	POST_TXT(32);
}
ANTIC_RENDERER( antic_mode_4_40 )
{
	PREPARE_TXT45(space, 40,0);
	REP40(MODE4);
	POST_TXT(40);
}
ANTIC_RENDERER( antic_mode_4_48 )
{
	PREPARE_TXT45(space, 48,0);
	REP48(MODE4);
	POST_TXT(48);
}

/*************  ANTIC mode 05: *********************************
 * character mode 8x16:4 multi color (32/40/48 byte per line)
 ***************************************************************/
#define MODE5(s) COPY4(dst, antic.pf_x10b[video->data[s]])

ANTIC_RENDERER( antic_mode_5_32 )
{
	PREPARE_TXT45(space, 32,1);
	REP32(MODE5);
	POST_TXT(32);
}
ANTIC_RENDERER( antic_mode_5_40 )
{
	PREPARE_TXT45(space, 40,1);
	REP40(MODE5);
	POST_TXT(40);
}
ANTIC_RENDERER( antic_mode_5_48 )
{
	PREPARE_TXT45(space, 48,1);
	REP48(MODE5);
	POST_TXT(48);
}

/*************  ANTIC mode 06: *********************************
 * character mode 16x8:5 single color (16/20/24 byte per line)
 ***************************************************************/
#define MODE6(s) COPY8(dst, antic.pf_3210b2[video->data[s]], antic.pf_3210b2[video->data[s]+1])

ANTIC_RENDERER( antic_mode_6_32 )
{
	PREPARE_TXT67(space, 16,0);
	REP16(MODE6);
	POST_TXT(16);
}
ANTIC_RENDERER( antic_mode_6_40 )
{
	PREPARE_TXT67(space, 20,0);
	REP20(MODE6);
	POST_TXT(20);
}
ANTIC_RENDERER( antic_mode_6_48 )
{
	PREPARE_TXT67(space, 24,0);
	REP24(MODE6);
	POST_TXT(24);
}

/*************  ANTIC mode 07: *********************************
 * character mode 16x16:5 single color (16/20/24 byte per line)
 ***************************************************************/
#define MODE7(s) COPY8(dst, antic.pf_3210b2[video->data[s]], antic.pf_3210b2[video->data[s]+1])

ANTIC_RENDERER( antic_mode_7_32 )
{
	PREPARE_TXT67(space, 16,1);
	REP16(MODE7);
	POST_TXT(16);
}
ANTIC_RENDERER( antic_mode_7_40 )
{
	PREPARE_TXT67(space, 20,1);
	REP20(MODE7);
	POST_TXT(20);
}
ANTIC_RENDERER( antic_mode_7_48 )
{
	PREPARE_TXT67(space, 24,1);
	REP24(MODE7);
	POST_TXT(24);
}

/*************  ANTIC mode 08: *********************************
 * graphics mode 8x8:4 (8/10/12 byte per line)
 ***************************************************************/
#define MODE8(s) COPY16(dst, antic.pf_210b4[video->data[s]],antic.pf_210b4[video->data[s]+1],antic.pf_210b4[video->data[s]+2],antic.pf_210b4[video->data[s]+3])

ANTIC_RENDERER( antic_mode_8_32 )
{
	PREPARE_GFX8(space, 8);
	REP08(MODE8);
	POST_GFX(8);
}
ANTIC_RENDERER( antic_mode_8_40 )
{
	PREPARE_GFX8(space, 10);
	REP10(MODE8);
	POST_GFX(10);
}
ANTIC_RENDERER( antic_mode_8_48 )
{
	PREPARE_GFX8(space, 12);
	REP12(MODE8);
	POST_GFX(12);
}

/*************  ANTIC mode 09: *********************************
 * graphics mode 4x4:2 (8/10/12 byte per line)
 ***************************************************************/
#define MODE9(s) COPY8(dst, antic.pf_3210b2[video->data[s]], antic.pf_3210b2[video->data[s]+1])

ANTIC_RENDERER( antic_mode_9_32 )
{
	PREPARE_GFX9BC(space, 16);
	REP16(MODE9);
	POST_GFX(16);
}
ANTIC_RENDERER( antic_mode_9_40 )
{
	PREPARE_GFX9BC(space, 20);
	REP20(MODE9);
	POST_GFX(20);
}
ANTIC_RENDERER( antic_mode_9_48 )
{
	PREPARE_GFX9BC(space, 24);
	REP24(MODE9);
	POST_GFX(24);
}

/*************  ANTIC mode 0A: *********************************
 * graphics mode 4x4:4 (16/20/24 byte per line)
 ***************************************************************/
#define MODEA(s) COPY8(dst, antic.pf_210b2[video->data[s]], antic.pf_210b2[video->data[s]+1])

ANTIC_RENDERER( antic_mode_a_32 )
{
	PREPARE_GFXA(space, 16);
	REP16(MODEA);
	POST_GFX(16);
}
ANTIC_RENDERER( antic_mode_a_40 )
{
	PREPARE_GFXA(space, 20);
	REP20(MODEA);
	POST_GFX(20);
}
ANTIC_RENDERER( antic_mode_a_48 )
{
	PREPARE_GFXA(space, 24);
	REP24(MODEA);
	POST_GFX(24);
}

/*************  ANTIC mode 0B: *********************************
 * graphics mode 2x2:2 (16/20/24 byte per line)
 ***************************************************************/
#define MODEB(s) COPY8(dst, antic.pf_3210b2[video->data[s]], antic.pf_3210b2[video->data[s]+1])

ANTIC_RENDERER( antic_mode_b_32 )
{
	PREPARE_GFX9BC(space, 16);
	REP16(MODEB);
	POST_GFX(16);
}
ANTIC_RENDERER( antic_mode_b_40 )
{
	PREPARE_GFX9BC(space, 20);
	REP20(MODEB);
	POST_GFX(20);
}
ANTIC_RENDERER( antic_mode_b_48 )
{
	PREPARE_GFX9BC(space, 24);
	REP24(MODEB);
	POST_GFX(24);
}

/*************  ANTIC mode 0C: *********************************
 * graphics mode 2x1:2 (16/20/24 byte per line)
 ***************************************************************/
#define MODEC(s) COPY8(dst, antic.pf_3210b2[video->data[s]], antic.pf_3210b2[video->data[s]+1])

ANTIC_RENDERER( antic_mode_c_32 )
{
	PREPARE_GFX9BC(space, 16);
	REP16(MODEC);
	POST_GFX(16);
}
ANTIC_RENDERER( antic_mode_c_40 )
{
	PREPARE_GFX9BC(space, 20);
	REP20(MODEC);
	POST_GFX(20);
}
ANTIC_RENDERER( antic_mode_c_48 )
{
	PREPARE_GFX9BC(space, 24);
	REP24(MODEC);
	POST_GFX(24);
}

/*************  ANTIC mode 0D: *********************************
 * graphics mode 2x2:4 (32/40/48 byte per line)
 ***************************************************************/
#define MODED(s) COPY4(dst, antic.pf_x10b[video->data[s]])

ANTIC_RENDERER( antic_mode_d_32 )
{
	PREPARE_GFXDE(space, 32);
	REP32(MODED);
	POST_GFX(32);
}
ANTIC_RENDERER( antic_mode_d_40 )
{
	PREPARE_GFXDE(space, 40);
	REP40(MODED);
	POST_GFX(40);
}
ANTIC_RENDERER( antic_mode_d_48 )
{
	PREPARE_GFXDE(space, 48);
	REP48(MODED);
	POST_GFX(48);
}

/*************  ANTIC mode 0E: *********************************
 * graphics mode 2x1:4 (32/40/48 byte per line)
 ***************************************************************/
#define MODEE(s) COPY4(dst, antic.pf_x10b[video->data[s]])

ANTIC_RENDERER( antic_mode_e_32 )
{
	PREPARE_GFXDE(space, 32);
	REP32(MODEE);
	POST_GFX(32);
}
ANTIC_RENDERER( antic_mode_e_40 )
{
	PREPARE_GFXDE(space, 40);
	REP40(MODEE);
	POST_GFX(40);
}
ANTIC_RENDERER( antic_mode_e_48 )
{
	PREPARE_GFXDE(space, 48);
	REP48(MODEE);
	POST_GFX(48);
}

/*************  ANTIC mode 0F: *********************************
 * graphics mode 1x1:2 (32/40/48 byte per line)
 ***************************************************************/
#define MODEF(s) COPY4(dst, antic.pf_1b[video->data[s]])

ANTIC_RENDERER( antic_mode_f_32 )
{
	PREPARE_GFXF(space, 32);
	REP32(MODEF);
	POST_GFX(32);
}
ANTIC_RENDERER( antic_mode_f_40 )
{
	PREPARE_GFXF(space, 40);
	REP40(MODEF);
	POST_GFX(40);
}
ANTIC_RENDERER( antic_mode_f_48 )
{
	PREPARE_GFXF(space, 48);
	REP48(MODEF);
	POST_GFX(48);
}

