/***************************************************************************

	The Game Room Lethal Justice hardware

	driver by Aaron Giles

	Games supported:
		* Lethal Justice
		* Egg Venture

	Known bugs:
		* some DIP switches not understood
		* possible timing issue cuasing slight video flicker


         EU21     EU18     EU20   32.000MHz
         M6295    M6295    M6295       Xilinx
   Dip-8 2.000Mhz 2.000Mhz 2.000Mhz
J        VC9                 GUNCN
A  Dip-4 VC8                 Xilinx     EGR4
M               Mach210                 EGR6.3
M   M5M442256x4 Mach210 Mach210 Mach210 EGR3
A          11.2896MHz                   EGR2
     TMS34010           W241024x4       EGR1
 2803A                                  EGR5.3
    40.000MHz   Bt121 Mach210 Mach210 Mach210


Chips:
 TMS34010FNL-40     Main CPU
 Xilinx XC3042-70   Field Programmable Gate Array
 Bt121KPJ80         Triple 8-bit 80MHz VideoDAC
 AMD Mach210A-10JC  Programmable Logic Device (CPLD)
 ST ULN2803A        8 Darlington Transistor Array with common emitter

Note 1: Lethal Justice uses a 11.0592MHz OSC instead of the 11.2896MHz
Note 2: Lethal Justice uses a TMS34010FNL-50 instead of the TMS34010FNL-40

***************************************************************************/

#include "driver.h"
#include "cpu/tms34010/tms34010.h"
#include "lethalj.h"


static data16_t *code_rom;



/*************************************
 *
 *	Memory maps
 *
 *************************************/

static MEMORY_READ16_START( lethalj_readmem )
	{ TOBYTE(0x00000000), TOBYTE(0x003fffff), MRA16_RAM },
	{ TOBYTE(0x04000000), TOBYTE(0x0400000f), OKIM6295_status_0_lsb_r },
	{ TOBYTE(0x04000010), TOBYTE(0x0400001f), OKIM6295_status_1_lsb_r },
	{ TOBYTE(0x04100000), TOBYTE(0x0410000f), OKIM6295_status_2_lsb_r },
	{ TOBYTE(0x04100010), TOBYTE(0x0410001f), MRA16_NOP },	/* read but never examined */
	{ TOBYTE(0x04300000), TOBYTE(0x0430007f), lethalj_gun_r },
	{ TOBYTE(0x04500010), TOBYTE(0x0450001f), input_port_0_word_r },
	{ TOBYTE(0x04600000), TOBYTE(0x0460000f), input_port_1_word_r },
	{ TOBYTE(0xc0000000), TOBYTE(0xc00001ff), tms34010_io_register_r },
	{ TOBYTE(0xfc800000), TOBYTE(0xffffffff), MRA16_ROM },
MEMORY_END


static MEMORY_WRITE16_START( lethalj_writemem )
	{ TOBYTE(0x00000000), TOBYTE(0x003fffff), MWA16_RAM },
	{ TOBYTE(0x04000000), TOBYTE(0x0400000f), OKIM6295_data_0_lsb_w },
	{ TOBYTE(0x04000010), TOBYTE(0x0400001f), OKIM6295_data_1_lsb_w },
	{ TOBYTE(0x04100000), TOBYTE(0x0410000f), OKIM6295_data_2_lsb_w },
	{ TOBYTE(0x04200000), TOBYTE(0x0420001f), MWA16_NOP },	/* clocks bits through here */
	{ TOBYTE(0x04400000), TOBYTE(0x0440000f), MWA16_NOP },	/* clocks bits through here */
	{ TOBYTE(0x04700000), TOBYTE(0x047000ff), lethalj_blitter_w },
	{ TOBYTE(0xc0000000), TOBYTE(0xc00001ff), tms34010_io_register_w },
	{ TOBYTE(0xc0000240), TOBYTE(0xc000025f), MWA16_NOP },		/* seems to be a bug in their code, one of many. */
	{ TOBYTE(0xff800000), TOBYTE(0xffffffff), MWA16_ROM, &code_rom },
MEMORY_END



/*************************************
 *
 *	Input ports
 *
 *************************************/

INPUT_PORTS_START( lethalj )
	PORT_START
	PORT_BIT( 0x0003, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_BUTTON1 | IPF_PLAYER2 )
	PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_UNKNOWN )		/* ??? Seems to be rigged up to the auto scroll, and acts as a fast forward*/
	PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 | IPF_PLAYER1 ) 
	PORT_BIT( 0xffe0, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START
	PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_SERVICE1 )
	PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_UNKNOWN )
	PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_COIN1 )
	PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_COIN2 )
	PORT_DIPNAME( 0x00c0, 0x0000, DEF_STR( Coinage ))
	PORT_DIPSETTING(      0x0040, DEF_STR( 2C_1C ))
	PORT_DIPSETTING(      0x0000, DEF_STR( 1C_1C ))
	PORT_DIPSETTING(      0x0080, DEF_STR( 1C_2C ))
	PORT_DIPSETTING(      0x00c0, DEF_STR( Free_Play ))
	PORT_DIPNAME( 0x0300, 0x0100, DEF_STR( Lives ))
	PORT_DIPSETTING(      0x0000, "2" )
	PORT_DIPSETTING(      0x0100, "3" )
	PORT_DIPSETTING(      0x0200, "4" )
	PORT_DIPSETTING(      0x0300, "5" )
	PORT_DIPNAME( 0x0c10, 0x0010, "Right Gun Offset" )
	PORT_DIPSETTING(      0x0000, "-4" )
	PORT_DIPSETTING(      0x0400, "-3" )
	PORT_DIPSETTING(      0x0800, "-2" )
	PORT_DIPSETTING(      0x0c00, "-1" )
	PORT_DIPSETTING(      0x0010, "0" )
	PORT_DIPSETTING(      0x0410, "+1" )
	PORT_DIPSETTING(      0x0810, "+2" )
	PORT_DIPSETTING(      0x0c10, "+3" )
	PORT_DIPNAME( 0x3020, 0x0020, "Left Gun Offset" )
	PORT_DIPSETTING(      0x0000, "-4" )
	PORT_DIPSETTING(      0x1000, "-3" )
	PORT_DIPSETTING(      0x2000, "-2" )
	PORT_DIPSETTING(      0x3000, "-1" )
	PORT_DIPSETTING(      0x0020, "0" )
	PORT_DIPSETTING(      0x1020, "+1" )
	PORT_DIPSETTING(      0x2020, "+2" )
	PORT_DIPSETTING(      0x3020, "+3" )
	PORT_DIPNAME( 0x4000, 0x0000, "DIP E" )
	PORT_DIPSETTING(      0x0000, "0" )
	PORT_DIPSETTING(      0x4000, "1" )
	PORT_DIPNAME( 0x8000, 0x8000, "Global Gun Offset" )
	PORT_DIPSETTING(      0x0000, "-2.5" )
	PORT_DIPSETTING(      0x8000, "+0" )

	PORT_START				/* fake analog X */
	PORT_ANALOG( 0xff, 0x80, IPT_AD_STICK_X, 50, 10, 0, 255 )

	PORT_START				/* fake analog Y */
	PORT_ANALOG( 0xff, 0x80, IPT_AD_STICK_Y, 70, 10, 0, 255 )

	PORT_START				/* fake analog X */
	PORT_ANALOG( 0xff, 0x80, IPT_AD_STICK_X | IPF_PLAYER2, 50, 10, 0, 255 )

	PORT_START				/* fake analog Y */
	PORT_ANALOG( 0xff, 0x80, IPT_AD_STICK_Y | IPF_PLAYER2, 70, 10, 0, 255 )
INPUT_PORTS_END


INPUT_PORTS_START( eggventr )
	PORT_START
	PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_SERVICE1 )
	PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_UNKNOWN )
	PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_COIN1 )
	PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_COIN2 )
	PORT_DIPNAME( 0x0070, 0x0000, DEF_STR( Coinage ))
	PORT_DIPSETTING(      0x0040, DEF_STR( 8C_1C ))
	PORT_DIPSETTING(      0x0030, DEF_STR( 4C_1C ))
	PORT_DIPSETTING(      0x0020, DEF_STR( 3C_1C ))
	PORT_DIPSETTING(      0x0010, DEF_STR( 2C_1C ))
	PORT_DIPSETTING(      0x0000, DEF_STR( 1C_1C ))
	PORT_DIPSETTING(      0x0050, DEF_STR( 1C_2C ))
	PORT_DIPSETTING(      0x0060, DEF_STR( 1C_4C ))
	PORT_DIPSETTING(      0x0070, DEF_STR( Free_Play ))
	PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_DIPNAME( 0x0300, 0x0300, DEF_STR( Lives ) ) // Verified Correct
	PORT_DIPSETTING(      0x0000, "3" )
	PORT_DIPSETTING(      0x0100, "4" )
	PORT_DIPSETTING(      0x0200, "5" )
	PORT_DIPSETTING(      0x0300, "6" )
	PORT_DIPNAME( 0x0c00, 0x0800, DEF_STR( Difficulty ) ) // According to info from The Gameroom
	PORT_DIPSETTING(      0x0c00, "Very Easy" )
	PORT_DIPSETTING(      0x0400, "Easy" )
	PORT_DIPSETTING(      0x0800, "Medium" )
	PORT_DIPSETTING(      0x0000, "Hard" )
	PORT_DIPNAME( 0x1000, 0x1000, "Slot Machine" ) // Verified Correct - Unused for the Deluxe version?? Yes, the slot machine
	PORT_DIPSETTING(      0x0000, DEF_STR( Off ) ) // is present in the code as a 'bonus stage' (when the egg reaches Vegas?), 
	PORT_DIPSETTING(      0x1000, DEF_STR( On ) ) // but not actually called (EC). 
	PORT_BIT( 0xe000, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START
	PORT_BIT( 0x000f, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 | IPF_PLAYER1 )
	PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON1 | IPF_PLAYER2 )
	PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_START1 )
	PORT_BIT( 0x7f00, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_START2 )

	PORT_START				/* fake analog X */
	PORT_ANALOG( 0xff, 0x80, IPT_AD_STICK_X, 50, 10, 0, 255 )

	PORT_START				/* fake analog Y */
	PORT_ANALOG( 0xff, 0x80, IPT_AD_STICK_Y, 70, 10, 0, 255 )

	PORT_START				/* fake analog X */
	PORT_ANALOG( 0xff, 0x80, IPT_AD_STICK_X | IPF_PLAYER2, 50, 10, 0, 255 )

	PORT_START				/* fake analog Y */
	PORT_ANALOG( 0xff, 0x80, IPT_AD_STICK_Y | IPF_PLAYER2, 70, 10, 0, 255 )
INPUT_PORTS_END


INPUT_PORTS_START( eggventdx )
	PORT_START
	PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_SERVICE1 )
	PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_UNKNOWN )
	PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_COIN1 )
	PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_COIN2 )
	PORT_DIPNAME( 0x0070, 0x0000, DEF_STR( Coinage ))
	PORT_DIPSETTING(      0x0040, DEF_STR( 8C_1C ))
	PORT_DIPSETTING(      0x0030, DEF_STR( 4C_1C ))
	PORT_DIPSETTING(      0x0020, DEF_STR( 3C_1C ))
	PORT_DIPSETTING(      0x0010, DEF_STR( 2C_1C ))
	PORT_DIPSETTING(      0x0000, DEF_STR( 1C_1C ))
	PORT_DIPSETTING(      0x0050, DEF_STR( 1C_2C ))
	PORT_DIPSETTING(      0x0060, DEF_STR( 1C_4C ))
	PORT_DIPSETTING(      0x0070, DEF_STR( Free_Play ))
	PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_DIPNAME( 0x0300, 0x0300, DEF_STR( Lives ) ) // Verified Correct
	PORT_DIPSETTING(      0x0000, "3" )
	PORT_DIPSETTING(      0x0100, "4" )
	PORT_DIPSETTING(      0x0200, "5" )
	PORT_DIPSETTING(      0x0300, "6" )
	PORT_DIPNAME( 0x0c00, 0x0800, DEF_STR( Difficulty ) ) // According to info from The Gameroom
	PORT_DIPSETTING(      0x0c00, "Very Easy" )
	PORT_DIPSETTING(      0x0400, "Easy" )
	PORT_DIPSETTING(      0x0800, "Medium" )
	PORT_DIPSETTING(      0x0000, "Hard" )
	PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_UNUSED )
	PORT_BIT( 0xe000, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START
	PORT_BIT( 0x000f, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 | IPF_PLAYER1 )
	PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON1 | IPF_PLAYER2 )
	PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_START1 )
	PORT_BIT( 0x7f00, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_START2 )

	PORT_START				/* fake analog X */
	PORT_ANALOG( 0xff, 0x80, IPT_AD_STICK_X, 50, 10, 0, 255 )

	PORT_START				/* fake analog Y */
	PORT_ANALOG( 0xff, 0x80, IPT_AD_STICK_Y, 70, 10, 0, 255 )

	PORT_START				/* fake analog X */
	PORT_ANALOG( 0xff, 0x80, IPT_AD_STICK_X | IPF_PLAYER2, 50, 10, 0, 255 )

	PORT_START				/* fake analog Y */
	PORT_ANALOG( 0xff, 0x80, IPT_AD_STICK_Y | IPF_PLAYER2, 70, 10, 0, 255 )
INPUT_PORTS_END


/*************************************
 *
 *	Sound definition
 *
 *************************************/

static struct OKIM6295interface okim6295_interface =
{
	3,
	{ 2000000/132, 2000000/132, 2000000/132 },
	{ REGION_SOUND1, REGION_SOUND2, REGION_SOUND3 },
	{ 75, 75, 75 }
};



/*************************************
 *
 *	34010 configuration
 *
 *************************************/

static struct tms34010_config cpu_config =
{
	0,								/* halt on reset */
	NULL,							/* generate interrupt */
	NULL,							/* write to shiftreg function */
	NULL,							/* read from shiftreg function */
	NULL,							/* display address changed */
	NULL							/* display interrupt callback */
};



/*************************************
 *
 *	Machine drivers
 *
 *************************************/

MACHINE_DRIVER_START( lethalj )

	/* basic machine hardware */
	MDRV_CPU_ADD(TMS34010, 40000000/TMS34010_CLOCK_DIVIDER)
	MDRV_CPU_CONFIG(cpu_config)
	MDRV_CPU_MEMORY(lethalj_readmem,lethalj_writemem)

	MDRV_FRAMES_PER_SECOND(60)
	MDRV_VBLANK_DURATION((1000000 * (258 - 236)) / (60 * 258))

	/* video hardware */
	MDRV_VIDEO_ATTRIBUTES(VIDEO_TYPE_RASTER)
	MDRV_SCREEN_SIZE(512, 236)
	MDRV_VISIBLE_AREA(0, 511, 0, 235)

	MDRV_PALETTE_LENGTH(32768)

	MDRV_PALETTE_INIT(lethalj)
	MDRV_VIDEO_START(lethalj)
	MDRV_VIDEO_UPDATE(lethalj)

	/* sound hardware */
	MDRV_SOUND_ADD(OKIM6295, okim6295_interface)
MACHINE_DRIVER_END


MACHINE_DRIVER_START( eggventr )

	/* basic machine hardware */
	MDRV_IMPORT_FROM(lethalj)
	MDRV_CPU_MODIFY("main")

	/* Slightly different resolution then Lethal Justice */
	MDRV_VBLANK_DURATION((1000000 * (258 - 239)) / (60 * 258))
	MDRV_SCREEN_SIZE(512, 239)
	MDRV_VISIBLE_AREA(0, 511, 0, 238)

MACHINE_DRIVER_END


/*************************************
 *
 *	ROM definitions
 *
 *************************************/

ROM_START( lethalj )
	ROM_REGION( TOBYTE(0x400000), REGION_CPU1, 0 )		/* 34010 dummy region */

	ROM_REGION16_LE( 0x100000, REGION_USER1, ROMREGION_DISPOSE )	/* 34010 code */
	ROM_LOAD16_BYTE( "vc8",  0x000000, 0x080000, 0x8d568e1d )
	ROM_LOAD16_BYTE( "vc9",  0x000001, 0x080000, 0x8f22add4 )

	ROM_REGION16_LE( 0x600000, REGION_GFX1, 0 )			/* graphics data */
	ROM_LOAD16_BYTE( "gr1",  0x000000, 0x100000, 0x27f7b244 )
	ROM_LOAD16_BYTE( "gr2",  0x000001, 0x100000, 0x1f25d3ab )
	ROM_LOAD16_BYTE( "gr4",  0x200000, 0x100000, 0xc5838b4c )
	ROM_LOAD16_BYTE( "gr3",  0x200001, 0x100000, 0xba9fa057 )
	ROM_LOAD16_BYTE( "gr6",  0x400000, 0x100000, 0x51c99b85 )
	ROM_LOAD16_BYTE( "gr5",  0x400001, 0x100000, 0x80dda9b5 )

	ROM_REGION( 0x40000, REGION_SOUND1, 0)				/* sound data */
	ROM_LOAD( "sound1", 0x00000, 0x40000, 0x7d93ca66 )

	ROM_REGION( 0x40000, REGION_SOUND2, 0)				/* sound data */
	ROM_LOAD( "u21",    0x00000, 0x40000, 0x7d3beae0 )

	ROM_REGION( 0x40000, REGION_SOUND3, 0)				/* sound data */
	ROM_LOAD( "sound1", 0x00000, 0x40000, 0x7d93ca66 )
ROM_END


ROM_START( eggventr )
	ROM_REGION( TOBYTE(0x400000), REGION_CPU1, 0 )		/* 34010 dummy region */

	ROM_REGION16_LE( 0x100000, REGION_USER1, ROMREGION_DISPOSE )	/* 34010 code */
	ROM_LOAD16_BYTE( "eggvc8.10", 0x000000, 0x020000, 0x225d1164 )
	ROM_LOAD16_BYTE( "eggvc9.10", 0x000001, 0x020000, 0x42f6e904 )
	ROM_COPY( REGION_USER1, 0x000000, 0x040000, 0x040000 )
	ROM_COPY( REGION_USER1, 0x000000, 0x080000, 0x080000 )

	ROM_REGION16_LE( 0x600000, REGION_GFX1, 0 )			/* graphics data */
	ROM_LOAD16_BYTE( "egr1.bin",  0x000000, 0x100000, 0xf73f80d9 )
	ROM_LOAD16_BYTE( "egr2.bin",  0x000001, 0x100000, 0x3a9ba910 )
	ROM_LOAD16_BYTE( "egr4.bin",  0x200000, 0x100000, 0x4ea5900e )
	ROM_LOAD16_BYTE( "egr3.bin",  0x200001, 0x100000, 0x3f8dfc73 )
	ROM_LOAD16_BYTE( "egr6.3",    0x400000, 0x100000, 0xf299d818 )
	ROM_LOAD16_BYTE( "egr5.3",    0x400001, 0x100000, 0xebfca07b )

	ROM_REGION( 0x40000, REGION_SOUND1, 0)				/* sound data */
	ROM_LOAD( "eu18.bin", 0x00000, 0x40000, 0x3760b1db )

	ROM_REGION( 0x40000, REGION_SOUND2, 0)				/* sound data */
	ROM_LOAD( "eu18.bin", 0x00000, 0x40000, 0x3760b1db )

	ROM_REGION( 0x40000, REGION_SOUND3, 0)				/* sound data */
	ROM_LOAD( "eu18.bin", 0x00000, 0x40000, 0x3760b1db )
ROM_END

ROM_START( eggvntdx )
	ROM_REGION( TOBYTE(0x400000), REGION_CPU1, 0 )		/* 34010 dummy region */

	ROM_REGION16_LE( 0x100000, REGION_USER1, ROMREGION_DISPOSE )	/* 34010 code */
	ROM_LOAD16_BYTE( "eggdlx.vc8", 0x000000, 0x080000, 0xd7f56141 )
	ROM_LOAD16_BYTE( "eggdlx.vc9", 0x000001, 0x080000, 0xcc5f122e )

	ROM_REGION16_LE( 0x600000, REGION_GFX1, 0 )			/* graphics data */
	ROM_LOAD16_BYTE( "egr1.bin",     0x000000, 0x100000, 0xf73f80d9 )
	ROM_LOAD16_BYTE( "egr2.bin",     0x000001, 0x100000, 0x3a9ba910 )
	ROM_LOAD16_BYTE( "eggdlx.gr4",   0x200000, 0x100000, 0xcfb1e28b )
	ROM_LOAD16_BYTE( "eggdlx.gr3",   0x200001, 0x100000, 0xa7da3891 )
	ROM_LOAD16_BYTE( "eggdlx.gr6",   0x400000, 0x100000, 0x97d02e8a )
	ROM_LOAD16_BYTE( "eggdlx.gr5",   0x400001, 0x100000, 0x387d9176 )

	ROM_REGION( 0x40000, REGION_SOUND1, 0)				/* sound data */
	ROM_LOAD( "eu18.bin", 0x00000, 0x40000, 0x3760b1db )

	ROM_REGION( 0x40000, REGION_SOUND2, 0)				/* sound data */
	ROM_LOAD( "eu18.bin", 0x00000, 0x40000, 0x3760b1db )

	ROM_REGION( 0x40000, REGION_SOUND3, 0)				/* sound data */
	ROM_LOAD( "eu18.bin", 0x00000, 0x40000, 0x3760b1db )
ROM_END




/*************************************
 *
 *	Driver init
 *
 *************************************/

static DRIVER_INIT( lethalj )
{
	/* set up code ROMs */
	memcpy(code_rom, memory_region(REGION_USER1), memory_region_length(REGION_USER1));
}



/*************************************
 *
 *	Game drivers
 *
 *************************************/

GAME( 1996, lethalj,  0,        lethalj,  lethalj,  lethalj, ROT0, "The Game Room", "Lethal Justice" )
GAME( 1997, eggventr, 0,        eggventr, eggventr, lethalj, ROT0, "The Game Room", "Egg Venture" )
GAME( 1997, eggvntdx, eggventr, eggventr, eggventdx, lethalj, ROT0, "The Game Room", "Egg Venture Deluxe" )
