#include "driver.h"
#include "cpu/m6809/m6809.h"
#include "machine/6821pia.h"
#include "machine/6522via.h"
#include "machine/ticket.h"
#include "video/tms34061.h"
#include "video/tlc34076.h"
#include "itech8.h"
#include "sound/2203intf.h"
#include "sound/3812intf.h"
#include "sound/okim6295.h"
#include <math.h>


#define FULL_LOGGING	0

#define CLOCK_8MHz		(8000000)
#define CLOCK_12MHz		(12000000)



/*************************************
 *
 *  Static data
 *
 *************************************/

static UINT8 blitter_int;
static UINT8 tms34061_int;
static UINT8 periodic_int;

static UINT8 sound_data;

static UINT8 pia_porta_data;
static UINT8 pia_portb_data;

static UINT8 *main_ram;
static size_t main_ram_size;

static const rectangle *visarea;



/*************************************
 *
 *  6821 PIA interface
 *
 *************************************/

static WRITE8_HANDLER( pia_porta_out );
static WRITE8_HANDLER( pia_portb_out );

static const pia6821_interface pia_interface =
{
	0, ticket_dispenser_r, 0, 0, 0, 0,		/* PIA inputs: A, B, CA1, CB1, CA2, CB2 */
	pia_porta_out, pia_portb_out, 0, 0,		/* PIA outputs: A, B, CA2, CB2 */
	0, 0									/* PIA IRQs: A, B */
};



/*************************************
 *
 *  6522 VIA interface
 *
 *************************************/

static void via_irq(int state);

static struct via6522_interface via_interface =
{
	/*inputs : A/B         */ 0, 0,
	/*inputs : CA/B1,CA/B2 */ 0, 0, 0, 0,
	/*outputs: A/B         */ 0, pia_portb_out,
	/*outputs: CA/B1,CA/B2 */ 0, 0, 0, 0,
	/*irq                  */ via_irq
};



/*************************************
 *
 *  Interrupt handling
 *
 *************************************/

void itech8_update_interrupts(int periodic, int tms34061, int blitter)
{
	/* update the states */
	if (periodic != -1) periodic_int = periodic;
	if (tms34061 != -1) tms34061_int = tms34061;
	if (blitter != -1) blitter_int = blitter;

	/* handle the 6809 case */
	if (Machine->drv->cpu[0].type == CPU_M6809)
	{
		/* just modify lines that have changed */
		if (periodic != -1) cpunum_set_input_line(0, INPUT_LINE_NMI, periodic ? ASSERT_LINE : CLEAR_LINE);
		if (tms34061 != -1) cpunum_set_input_line(0, M6809_IRQ_LINE, tms34061 ? ASSERT_LINE : CLEAR_LINE);
		if (blitter != -1) cpunum_set_input_line(0, M6809_FIRQ_LINE, blitter ? ASSERT_LINE : CLEAR_LINE);
	}

	/* handle the 68000 case */
	else
	{
		int level = 0;

		/* determine which level is active */
		if (blitter_int) level = 2;
		if (periodic_int) level = 3;

		/* update it */
		if (level)
			cpunum_set_input_line(0, level, ASSERT_LINE);
		else
			cpunum_set_input_line(0, 7, CLEAR_LINE);
	}
}



/*************************************
 *
 *  Interrupt generation
 *
 *************************************/

static INTERRUPT_GEN( generate_nmi )
{
	/* signal the NMI */
	itech8_update_interrupts(1, -1, -1);
	itech8_update_interrupts(0, -1, -1);

	if (FULL_LOGGING) logerror("------------ VBLANK (%d) --------------\n", video_screen_get_vpos(0));
}


static WRITE8_HANDLER( itech8_nmi_ack_w )
{
/* doesn't seem to hold for every game (e.g., hstennis) */
/*  cpunum_set_input_line(0, INPUT_LINE_NMI, CLEAR_LINE);*/
}


static void generate_sound_irq(int state)
{
	cpunum_set_input_line(1, M6809_FIRQ_LINE, state ? ASSERT_LINE : CLEAR_LINE);
}



/*************************************
 *
 *  Machine initialization
 *
 *************************************/

static TIMER_CALLBACK( behind_the_beam_update );


static MACHINE_START( itech8 )
{
	pia_config(0, &pia_interface);
}

static MACHINE_RESET( itech8 )
{
	/* make sure bank 0 is selected */
	if (machine->drv->cpu[0].type == CPU_M6809)
		memory_set_bankptr(1, &memory_region(REGION_CPU1)[0x4000]);

	/* reset the PIA (if used) */
	pia_reset();

	/* reset the VIA chip (if used) */
	via_config(0, &via_interface);
	via_set_clock(0, CLOCK_8MHz/4);
	via_reset();

	/* reset the ticket dispenser */
	ticket_dispenser_init(200, TICKET_MOTOR_ACTIVE_HIGH, TICKET_STATUS_ACTIVE_LOW);

	/* reset the palette chip */
	tlc34076_reset(6);

	/* set the visible area */
	if (visarea)
	{
		video_screen_set_visarea(0, visarea->min_x, visarea->max_x, visarea->min_y, visarea->max_y);
		visarea = NULL;
	}
}



/*************************************
 *
 *  Bank switching
 *
 *************************************/

static TIMER_CALLBACK( behind_the_beam_update )
{
	int scanline = param >> 8;
	int interval = param & 0xff;

	/* force a partial update to the current scanline */
	video_screen_update_partial(0, scanline);

	/* advance by the interval, and wrap to 0 */
	scanline += interval;
	if (scanline >= 256) scanline = 0;

	/* set a new timer */
	timer_set(video_screen_get_time_until_pos(0, scanline, 0), NULL, (scanline << 8) + interval, behind_the_beam_update);
}



/*************************************
 *
 *  Bank switching
 *
 *************************************/

static WRITE8_HANDLER( blitter_w )
{
	/* bit 0x20 on address 7 controls CPU banking */
	if (offset / 2 == 7)
		memory_set_bankptr(1, &memory_region(REGION_CPU1)[0x4000 + 0xc000 * ((data >> 5) & 1)]);

	/* the rest is handled by the video hardware */
	itech8_blitter_w(offset, data);
}


/*************************************
 *
 *  Input handling
 *
 *************************************/

/* used by most games */
static READ8_HANDLER( special_port0_r )
{
	UINT8 result = readinputport(0);
	result = (result & 0xfe) | (pia_portb_data & 0x01);
	return result;
}


/*************************************
 *
 *  6821 PIA handling
 *
 *************************************/

static WRITE8_HANDLER( pia_porta_out )
{
	logerror("PIA port A write = %02x\n", data);
	pia_porta_data = data;
}


static WRITE8_HANDLER( pia_portb_out )
{
	logerror("PIA port B write = %02x\n", data);

	/* bit 0 provides feedback to the main CPU */
	/* bit 4 controls the ticket dispenser */
	/* bit 5 controls the coin counter */
	/* bit 6 controls the diagnostic sound LED */
	pia_portb_data = data;
	ticket_dispenser_w(0, (data & 0x10) << 3);
	coin_counter_w(0, (data & 0x20) >> 5);
}


static WRITE8_HANDLER( ym2203_portb_out )
{
	logerror("YM2203 port B write = %02x\n", data);

	/* bit 0 provides feedback to the main CPU */
	/* bit 5 controls the coin counter */
	/* bit 6 controls the diagnostic sound LED */
	/* bit 7 controls the ticket dispenser */
	pia_portb_data = data;
	ticket_dispenser_w(0, data & 0x80);
	coin_counter_w(0, (data & 0x20) >> 5);
}



/*************************************
 *
 *  Sound communication
 *
 *************************************/

static TIMER_CALLBACK( delayed_sound_data_w )
{
	sound_data = param;
	cpunum_set_input_line(1, M6809_IRQ_LINE, ASSERT_LINE);
}


static WRITE8_HANDLER( sound_data_w )
{
	timer_call_after_resynch(NULL, data, delayed_sound_data_w);
}


static READ8_HANDLER( sound_data_r )
{
	cpunum_set_input_line(1, M6809_IRQ_LINE, CLEAR_LINE);
	return sound_data;
}



/*************************************
 *
 *  Sound 6522 VIA handling
 *
 *************************************/

static void via_irq(int state)
{
	if (state)
		cpunum_set_input_line(1, M6809_FIRQ_LINE, ASSERT_LINE);
	else
		cpunum_set_input_line(1, M6809_FIRQ_LINE, CLEAR_LINE);
}


/*************************************
 *
 *  NVRAM read/write
 *
 *************************************/

static NVRAM_HANDLER( itech8 )
{
	int i;

	if (read_or_write)
		mame_fwrite(file, main_ram, main_ram_size);
	else if (file)
		mame_fread(file, main_ram, main_ram_size);
	else
		for (i = 0; i < main_ram_size; i++)
			main_ram[i] = mame_rand(Machine);
}



/*************************************
 *
 *  Main CPU memory handlers
 *
 *************************************/

/*------ common layout with TMS34061 at 0000 ------*/
static ADDRESS_MAP_START( tmslo_map, ADDRESS_SPACE_PROGRAM, 8 )
	AM_RANGE(0x0000, 0x0fff) AM_READWRITE(itech8_tms34061_r, itech8_tms34061_w)
	AM_RANGE(0x1100, 0x1100) AM_WRITENOP
	AM_RANGE(0x1120, 0x1120) AM_WRITE(sound_data_w)
	AM_RANGE(0x1140, 0x1140) AM_READWRITE(special_port0_r, MWA8_RAM) AM_BASE(&itech8_grom_bank)
	AM_RANGE(0x1160, 0x1160) AM_READWRITE(input_port_1_r, itech8_page_w)
	AM_RANGE(0x1180, 0x1180) AM_READWRITE(input_port_2_r, tms34061_latch_w)
	AM_RANGE(0x11a0, 0x11a0) AM_WRITE(itech8_nmi_ack_w)
	AM_RANGE(0x11c0, 0x11df) AM_READWRITE(itech8_blitter_r, blitter_w)
	AM_RANGE(0x11e0, 0x11ff) AM_WRITE(itech8_palette_w)
	AM_RANGE(0x2000, 0x3fff) AM_RAM AM_BASE(&main_ram) AM_SIZE(&main_ram_size)
	AM_RANGE(0x4000, 0xffff) AM_ROMBANK(1)
ADDRESS_MAP_END


/*------ common layout with TMS34061 at 1000 ------*/
static ADDRESS_MAP_START( tmshi_map, ADDRESS_SPACE_PROGRAM, 8 )
	AM_RANGE(0x1000, 0x1fff) AM_READWRITE(itech8_tms34061_r, itech8_tms34061_w)
	AM_RANGE(0x0100, 0x0100) AM_WRITENOP
	AM_RANGE(0x0120, 0x0120) AM_WRITE(sound_data_w)
	AM_RANGE(0x0140, 0x0140) AM_READWRITE(special_port0_r, MWA8_RAM) AM_BASE(&itech8_grom_bank)
	AM_RANGE(0x0160, 0x0160) AM_READWRITE(input_port_1_r, itech8_page_w)
	AM_RANGE(0x0180, 0x0180) AM_READWRITE(input_port_2_r, tms34061_latch_w)
	AM_RANGE(0x01a0, 0x01a0) AM_WRITE(itech8_nmi_ack_w)
	AM_RANGE(0x01c0, 0x01df) AM_READWRITE(itech8_blitter_r, blitter_w)
	AM_RANGE(0x01e0, 0x01ff) AM_WRITE(itech8_palette_w)
	AM_RANGE(0x2000, 0x3fff) AM_RAM AM_BASE(&main_ram) AM_SIZE(&main_ram_size)
	AM_RANGE(0x4000, 0xffff) AM_ROMBANK(1)
ADDRESS_MAP_END


/*************************************
 *
 *  Sound CPU memory handlers
 *
 *************************************/

/*------ YM2203-based sound ------*/
static ADDRESS_MAP_START( sound2203_map, ADDRESS_SPACE_PROGRAM, 8 )
	AM_RANGE(0x0000, 0x0000) AM_WRITENOP
	AM_RANGE(0x1000, 0x1000) AM_READ(sound_data_r)
	AM_RANGE(0x2000, 0x2000) AM_MIRROR(0x0002) AM_READWRITE(YM2203_status_port_0_r, YM2203_control_port_0_w)
	AM_RANGE(0x2001, 0x2001) AM_MIRROR(0x0002) AM_WRITE(YM2203_write_port_0_w)
	AM_RANGE(0x3000, 0x37ff) AM_RAM
	AM_RANGE(0x4000, 0x4000) AM_READWRITE(OKIM6295_status_0_r, OKIM6295_data_0_w)
	AM_RANGE(0x8000, 0xffff) AM_ROM
ADDRESS_MAP_END


/*************************************
 *
 *  Port definitions
 *
 *************************************/

#define UNUSED_ANALOG	\
	PORT_START	\
	PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )

static INPUT_PORTS_START( gtg )
	PORT_START	/* 40 */
	PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_SPECIAL )	/* input from sound board */
	PORT_BIT( 0x06, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_DIPNAME( 0x08, 0x08, DEF_STR( Cabinet ))
	PORT_DIPSETTING(    0x08, DEF_STR( Upright ))
	PORT_DIPSETTING(    0x00, DEF_STR( Cocktail ))
	PORT_BIT( 0x70, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_SERVICE_NO_TOGGLE( 0x80, IP_ACTIVE_LOW )

	PORT_START	/* 60 */
	/* it is still unknown how the second player inputs are muxed in */
	/* currently we map both sets of controls to the same inputs */
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1)
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_COCKTAIL PORT_PLAYER(2)
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1)
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_COCKTAIL PORT_PLAYER(2)
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1)
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_COCKTAIL PORT_PLAYER(2)
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1)
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_COCKTAIL PORT_PLAYER(2)
	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 Swing") PORT_PLAYER(1)
	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P2 Swing") PORT_COCKTAIL PORT_PLAYER(2)
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_START1 )
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_COIN2 )
	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_COIN1 )

	PORT_START	/* 80 */
	PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )

	UNUSED_ANALOG	/* analog C */
	UNUSED_ANALOG	/* analog D */
	UNUSED_ANALOG	/* analog E */
	UNUSED_ANALOG	/* analog F */
INPUT_PORTS_END


/*************************************
 *
 *  Sound definitions
 *
 *************************************/

static struct YM2203interface ym2203_interface =
{
	0,
	0,
	0,
	ym2203_portb_out,
	generate_sound_irq
};


/*************************************
 *
 *  Machine driver
 *
 *************************************/

/************* core pieces ******************/

static MACHINE_DRIVER_START( itech8_core_lo )

	/* basic machine hardware */
	MDRV_CPU_ADD_TAG("main", M6809, CLOCK_8MHz/4)
	MDRV_CPU_PROGRAM_MAP(tmslo_map,0)
	MDRV_CPU_VBLANK_INT(generate_nmi,1)

	MDRV_SCREEN_REFRESH_RATE(60)

	MDRV_MACHINE_START(itech8)
	MDRV_MACHINE_RESET(itech8)
	MDRV_NVRAM_HANDLER(itech8)

	/* video hardware */
	MDRV_VIDEO_ATTRIBUTES(VIDEO_TYPE_RASTER | VIDEO_UPDATE_BEFORE_VBLANK)
	MDRV_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)
	MDRV_SCREEN_SIZE(512, 263)
	MDRV_PALETTE_LENGTH(256)

	MDRV_VIDEO_START(itech8)

	/* sound hardware */
	MDRV_SPEAKER_STANDARD_MONO("mono")

	MDRV_SOUND_ADD_TAG("oki", OKIM6295, CLOCK_8MHz/8) // was /128??
	MDRV_SOUND_CONFIG(okim6295_interface_region_1_pin7high) // was /128, not /132, so unsure so pin 7 not verified
	MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.75)
MACHINE_DRIVER_END


static MACHINE_DRIVER_START( itech8_core_hi )

	/* basic machine hardware */
	MDRV_IMPORT_FROM(itech8_core_lo)
	MDRV_CPU_MODIFY("main")
	MDRV_CPU_PROGRAM_MAP(tmshi_map,0)
MACHINE_DRIVER_END


static MACHINE_DRIVER_START( itech8_sound_ym2203 )

	/* basic machine hardware */
	MDRV_CPU_ADD_TAG("sound", M6809, CLOCK_8MHz/4)
	MDRV_CPU_PROGRAM_MAP(sound2203_map,0)

	/* sound hardware */
	MDRV_SOUND_ADD_TAG("ym", YM2203, CLOCK_8MHz/2)
	MDRV_SOUND_CONFIG(ym2203_interface)
	MDRV_SOUND_ROUTE(0, "mono", 0.07)
	MDRV_SOUND_ROUTE(1, "mono", 0.07)
	MDRV_SOUND_ROUTE(2, "mono", 0.07)
	MDRV_SOUND_ROUTE(3, "mono", 0.75)
MACHINE_DRIVER_END


/************* full drivers ******************/

static MACHINE_DRIVER_START( stratab_hi )

	/* basic machine hardware */
	MDRV_IMPORT_FROM(itech8_core_hi)
	MDRV_IMPORT_FROM(itech8_sound_ym2203)

	/* video hardware */
	MDRV_SCREEN_VISIBLE_AREA(0, 255, 0, 239)
	MDRV_VIDEO_UPDATE(itech8_2layer)
MACHINE_DRIVER_END


/* Misfitmame start */

ROM_START( itecdemo )
	ROM_REGION( 0x1c000, REGION_CPU1, 0 )
	ROM_LOAD( "u5d.bin", 0x04000, 0x4000, CRC(749a1336) SHA1(f3f1220fbb9b61214e7b4e675a6ab5bbe9db50af) )
	ROM_CONTINUE(        0x10000, 0xc000 )
	ROM_COPY( REGION_CPU1, 0x14000, 0x8000, 0x8000 )

	ROM_REGION( 0x10000, REGION_CPU2, 0 )
	ROM_LOAD( "u27d.bin", 0x08000, 0x8000, CRC(f0cd7332) SHA1(770b5d9b531495df0ff6350942cbd5147a875e9b) )

	ROM_REGION( 0xc0000, REGION_GFX1, 0 )
	ROM_LOAD( "grom0d.bin", 0x00000, 0x20000, CRC(e4f9fe36) SHA1(ad8cb4eb1d5d685bb22ca6fee5f1efcd682f8b38) )

	ROM_REGION( 0x20000, REGION_SOUND1, 0 )
	ROM_LOAD_OPTIONAL( "srom0d.bin", 0x00000, 0x20000, CRC(7ee8cdcd) SHA1(67dfd19f3eb3649d6f3f6631e44d0bd36b8d8d19) )
ROM_END


GAME( 1989, itecdemo, 0,      stratab_hi,        gtg,      0,        ROT0,   "Charles Doty", "Demo - Itec", 0 )
/* Misfitmame end */
