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

	CPS-2

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

#include "driver.h"
#include "deprecat.h"
#include "machine/eeprom.h"
#include "cpu/m68000/m68000.h"
#include "sound/qsound.h"
#include "chd.h"

#include "cps1.h"       /* External CPS1 definitions */

/*
Export this function so that the video routine can drive the
Q-Sound hardware
*/
#ifdef UNUSED_FUNCTION
WRITE16_HANDLER( cps2_qsound_sharedram_w )
{
    qsound_sharedram1_w(offset/2, data, 0xff00);
}
#endif


/*************************************
 *
 *  Constants
 *
 *************************************/

/* Maximum size of Q Sound Z80 region */
#define QSOUND_SIZE 0x50000

/* Maximum 680000 code size */
#undef  CODE_SIZE
#define CODE_SIZE   0x0400000


/*************************************
 *
 *  Global variables
 *
 *************************************/

static int readpaddle;
static int cps2networkpresent;


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

static INTERRUPT_GEN( cps2_interrupt )
{
	static int scancount;

	/* 2 is vblank, 4 is some sort of scanline interrupt, 6 is both at the same time. */

	if(scancount >= 261)
	{
		scancount = -1;
		cps1_scancalls = 0;
	}
	scancount++;

	if (cps1_cps_b_regs[0x10/2] & 0x8000)
		cps1_cps_b_regs[0x10/2] = cps1_cps_b_regs[0x10/2] & 0x1ff;
	if (cps1_cps_b_regs[0x12/2] & 0x8000)
		cps1_cps_b_regs[0x12/2] = cps1_cps_b_regs[0x12/2] & 0x1ff;

//  popmessage("%04x %04x - %04x %04x",cps1_scanline1,cps1_scanline2,cps1_cps_b_regs[0x10/2],cps1_cps_b_regs[0x12/2]);

	/* raster effects */
	if(cps1_scanline1 == scancount || (cps1_scanline1 < scancount && !cps1_scancalls))
	{
		cps1_cps_b_regs[0x10/2] = 0;
		cpunum_set_input_line(machine, 0, 4, HOLD_LINE);
		cps2_set_sprite_priorities();
		video_screen_update_partial(machine->primary_screen, 16 - 10 + scancount);	/* visarea.min_y - [first visible line?] + scancount */
		cps1_scancalls++;
//          popmessage("IRQ4 scancounter = %04i",scancount);
	}

	/* raster effects */
	if(cps1_scanline2 == scancount || (cps1_scanline2 < scancount && !cps1_scancalls))
	{
		cps1_cps_b_regs[0x12/2] = 0;
		cpunum_set_input_line(machine, 0, 4, HOLD_LINE);
		cps2_set_sprite_priorities();
		video_screen_update_partial(machine->primary_screen, 16 - 10 + scancount);	/* visarea.min_y - [first visible line?] + scancount */
		cps1_scancalls++;
//          popmessage("IRQ4 scancounter = %04i",scancount);
	}

	if(scancount == 256)  /* VBlank */
	{
		cps1_cps_b_regs[0x10/2] = cps1_scanline1;
		cps1_cps_b_regs[0x12/2] = cps1_scanline2;
		cpunum_set_input_line(machine, 0, 2, HOLD_LINE);
		if(cps1_scancalls)
		{
			cps2_set_sprite_priorities();
			video_screen_update_partial(machine->primary_screen, 256);
		}
		cps2_objram_latch();
	}
	//popmessage("Raster calls = %i",cps1_scancalls);
}


/*************************************
 *
 *  EEPROM
 *
 *************************************/

static const eeprom_interface cps2_eeprom_interface =
{
	6,		/* address bits */
	16,		/* data bits */
	"0110",	/*  read command */
	"0101",	/* write command */
	"0111"	/* erase command */
};

static NVRAM_HANDLER( cps2 )
{
	if (read_or_write)
		eeprom_save(file);
	else
	{
        eeprom_init(&cps2_eeprom_interface);

		if (file)
			eeprom_load(file);
	}
}

static WRITE16_HANDLER( cps2_eeprom_port_w )
{
    if (ACCESSING_BITS_8_15)
    {
	/* bit 0 - Unused */
	/* bit 1 - Unused */
	/* bit 2 - Unused */
	/* bit 3 - Unused? */
	/* bit 4 - Eeprom data  */
	/* bit 5 - Eeprom clock */
	/* bit 6 - */
	/* bit 7 - */

	/* EEPROM */
	eeprom_write_bit(data & 0x1000);
	eeprom_set_clock_line((data & 0x2000) ? ASSERT_LINE : CLEAR_LINE);
	eeprom_set_cs_line((data & 0x4000) ? CLEAR_LINE : ASSERT_LINE);
	}

	if (ACCESSING_BITS_0_7)
	{
	/* bit 0 - coin counter 1 */
	/* bit 0 - coin counter 2 */
	/* bit 2 - Unused */
	/* bit 3 - Allows access to Z80 address space (Z80 reset) */
	/* bit 4 - lock 1  */
	/* bit 5 - lock 2  */
	/* bit 6 - */
	/* bit 7 - */

        /* Z80 Reset */
		cpunum_set_input_line(machine, 1, INPUT_LINE_RESET, (data & 0x0008) ? CLEAR_LINE : ASSERT_LINE);

	coin_counter_w(0, data & 0x0001);
	if( (strncmp(machine->gamedrv->name,"pzloop2",8)==0) ||
 	    (strncmp(machine->gamedrv->name,"pzloop2j",8)==0) )
	{
		// Puzz Loop 2 uses coin counter 2 input to switch between stick and paddle controls
		readpaddle = data & 0x0002;
	}
	else
	{
		coin_counter_w(1, data & 0x0002);
	}

	if(strncmp(machine->gamedrv->name,"mmatrix",7)==0)		// Mars Matrix seems to require the coin lockout bit to be reversed
	{
		coin_lockout_w(0,data & 0x0010);
		coin_lockout_w(1,data & 0x0020);
		coin_lockout_w(2,data & 0x0040);
		coin_lockout_w(3,data & 0x0080);
	}
	else
	{
		coin_lockout_w(0,~data & 0x0010);
		coin_lockout_w(1,~data & 0x0020);
		coin_lockout_w(2,~data & 0x0040);
		coin_lockout_w(3,~data & 0x0080);
	}

	/*
    set_led_status(0,data & 0x01);
    set_led_status(1,data & 0x10);
    set_led_status(2,data & 0x20);
    */
    }
}


/*************************************
 *
 *  Sound ?
 *
 *************************************/

static READ16_HANDLER( cps2_qsound_volume_r )
{
	/* Extra adapter memory (0x660000-0x663fff) available when bit 14 = 0 */
	/* Network adapter (ssf2tb) present when bit 15 = 0 */
	/* Only game known to use both these so far is SSF2TB */

	if(cps2networkpresent)
		return 0x2021;
	else
		return 0xe021;
}


/*************************************
 *
 *  ???
 *
 *************************************/

static UINT8  cps2_read8(offs_t address)
{
	return m68k_read_pcrelative_8(address);
}

static UINT16 cps2_read16(offs_t address)
{
	return m68k_read_pcrelative_16(address);
}

static UINT32 cps2_read32(offs_t address)
{
	return m68k_read_pcrelative_32(address);
}


/*************************************
 *
 *  Read handlers
 *
 *************************************/

static READ16_HANDLER( kludge_r )
{
	return 0xffff;
}



/*************************************
 *
 *  Memory map
 *
 *************************************/

static ADDRESS_MAP_START( cps2_readmem, ADDRESS_SPACE_PROGRAM, 16 )
	AM_RANGE(0x000000, 0x3fffff) AM_READ(SMH_ROM)                   /* 68000 ROM */
	AM_RANGE(0x400000, 0x40000b) AM_READ(SMH_RAM)                   /* CPS2 object output */
	AM_RANGE(0x618000, 0x619fff) AM_READ(qsound_sharedram1_r)       /* Q RAM */
	AM_RANGE(0x662000, 0x662001) AM_READ(SMH_RAM)                   /* Network adapter related, accessed in SSF2TB */
	AM_RANGE(0x662008, 0x662009) AM_READ(SMH_RAM)                   /* Network adapter related, accessed in SSF2TB */
	AM_RANGE(0x662020, 0x662021) AM_READ(SMH_RAM)                   /* Network adapter related, accessed in SSF2TB */
	AM_RANGE(0x660000, 0x663fff) AM_READ(SMH_RAM)                   /* When bit 14 of 0x804030 equals 0 this space is available. Many games store highscores and other info here if available. */
	AM_RANGE(0x664000, 0x664001) AM_READ(SMH_RAM)                   /* Unknown - Only used if 0x660000-0x663fff available (could be RAM enable?) */
	AM_RANGE(0x700000, 0x701fff) AM_READ(cps2_objram1_r)			/* misfitmame - Object RAM, used by Razoola Suicide tester */
	AM_RANGE(0x708000, 0x709fff) AM_READ(cps2_objram2_r)            /* Object RAM */
	AM_RANGE(0x70a000, 0x70bfff) AM_READ(cps2_objram2_r)            /* mirror */
	AM_RANGE(0x70c000, 0x70dfff) AM_READ(cps2_objram2_r)            /* mirror */
	AM_RANGE(0x70e000, 0x70ffff) AM_READ(cps2_objram2_r)            /* mirror */
	AM_RANGE(0x800140, 0x80017f) AM_READ(cps1_cps_b_r)              /* mirror (sfa) */
	AM_RANGE(0x804000, 0x804001) AM_READ_PORT("IN0")                /* IN0 */
	AM_RANGE(0x804010, 0x804011) AM_READ_PORT("IN1")                /* IN1 */
	AM_RANGE(0x804020, 0x804021) AM_READ_PORT("IN2")                /* IN2 + EEPROM */
	AM_RANGE(0x804030, 0x804031) AM_READ(cps2_qsound_volume_r)      /* Master volume. Also when bit 14=0 addon memory is present, when bit 15=0 network adapter present. */
	AM_RANGE(0x8040b0, 0x8040b3) AM_READ(kludge_r)                  /* unknown (xmcotaj hangs if this is 0) */
	AM_RANGE(0x804140, 0x80417f) AM_READ(cps1_cps_b_r)              /* CPS-B custom */
	AM_RANGE(0x900000, 0x92ffff) AM_READ(SMH_RAM)                   /* Video RAM */
	AM_RANGE(0xff0000, 0xffffff) AM_READ(SMH_RAM)                   /* RAM */
ADDRESS_MAP_END

static ADDRESS_MAP_START( cps2_writemem, ADDRESS_SPACE_PROGRAM, 16 )
	AM_RANGE(0x000000, 0x3fffff) AM_WRITE(SMH_ROM)                  /* ROM */
	AM_RANGE(0x400000, 0x40000b) AM_WRITE(SMH_RAM) AM_BASE(&cps2_output) AM_SIZE(&cps2_output_size)    /* CPS2 output */
	AM_RANGE(0x618000, 0x619fff) AM_WRITE(qsound_sharedram1_w)        /* Q RAM */
	AM_RANGE(0x662000, 0x662001) AM_WRITE(SMH_RAM)                  /* Network adapter related, accessed in SSF2TB */
	AM_RANGE(0x662008, 0x662009) AM_WRITE(SMH_RAM)                  /* Network adapter related, accessed in SSF2TB (not sure if this port is write only yet)*/
	AM_RANGE(0x662020, 0x662021) AM_WRITE(SMH_RAM)                  /* Network adapter related, accessed in SSF2TB */
	AM_RANGE(0x660000, 0x663fff) AM_WRITE(SMH_RAM)                  /* When bit 14 of 0x804030 equals 0 this space is available. Many games store highscores and other info here if available. */
	AM_RANGE(0x664000, 0x664001) AM_WRITE(SMH_RAM)                  /* Unknown - Only used if 0x660000-0x663fff available (could be RAM enable?) */
	AM_RANGE(0x700000, 0x701fff) AM_WRITE(cps2_objram1_w) AM_BASE(&cps2_objram1)     /* Object RAM, no game seems to use it directly */
	AM_RANGE(0x708000, 0x709fff) AM_WRITE(cps2_objram2_w) AM_BASE(&cps2_objram2)     /* Object RAM */
	AM_RANGE(0x70a000, 0x70bfff) AM_WRITE(cps2_objram2_w)             /* mirror */
	AM_RANGE(0x70c000, 0x70dfff) AM_WRITE(cps2_objram2_w)             /* mirror */
	AM_RANGE(0x70e000, 0x70ffff) AM_WRITE(cps2_objram2_w)             /* mirror */
	AM_RANGE(0x800100, 0x80013f) AM_WRITE(cps1_cps_a_w) AM_BASE(&cps1_cps_a_regs)	/* mirror (sfa) */
	AM_RANGE(0x800140, 0x80017f) AM_WRITE(cps1_cps_b_w) AM_BASE(&cps1_cps_b_regs)	/* mirror (sfa) */
	AM_RANGE(0x804040, 0x804041) AM_WRITE(cps2_eeprom_port_w)         /* EEPROM */
	AM_RANGE(0x8040a0, 0x8040a1) AM_WRITE(SMH_NOP)                  /* Unknown (reset once on startup) */
	AM_RANGE(0x8040e0, 0x8040e1) AM_WRITE(cps2_objram_bank_w)         /* bit 0 = Object ram bank swap */
	AM_RANGE(0x804100, 0x80413f) AM_WRITE(cps1_cps_a_w) AM_BASE(&cps1_cps_a_regs)	/* CPS-A custom */
	AM_RANGE(0x804140, 0x80417f) AM_WRITE(cps1_cps_b_w) AM_BASE(&cps1_cps_b_regs)	/* CPS-B custom */
	AM_RANGE(0x900000, 0x92ffff) AM_WRITE(cps1_gfxram_w) AM_BASE(&cps1_gfxram) AM_SIZE(&cps1_gfxram_size)
	AM_RANGE(0xff0000, 0xffffff) AM_WRITE(SMH_RAM)                  /* RAM */
ADDRESS_MAP_END

static ADDRESS_MAP_START( phoenix_writemem, ADDRESS_SPACE_PROGRAM, 16 )
	AM_RANGE(0x000000, 0x3fffff) AM_WRITE(SMH_ROM)				/* ROM */
	AM_RANGE(0x618000, 0x619fff) AM_WRITE(qsound_sharedram1_w)		/* Q RAM */
	AM_RANGE(0x662000, 0x662001) AM_WRITE(SMH_RAM)				/* Network adapter related, accessed in SSF2TB */
	AM_RANGE(0x662008, 0x662009) AM_WRITE(SMH_RAM)				/* Network adapter related, accessed in SSF2TB (not sure if this port is write only yet)*/
	AM_RANGE(0x662020, 0x662021) AM_WRITE(SMH_RAM)				/* Network adapter related, accessed in SSF2TB */
	AM_RANGE(0x660000, 0x663fff) AM_WRITE(SMH_RAM)				/* When bit 14 of 0x804030 equals 0 this space is available. Many games store highscores and other info here if available. */
	AM_RANGE(0x664000, 0x664001) AM_WRITE(SMH_RAM)				/* Unknown - Only used if 0x660000-0x663fff available (could be RAM enable?) */
	AM_RANGE(0x700000, 0x701fff) AM_WRITE(cps2_objram1_w) AM_BASE(&cps2_objram1)	/* Object RAM, no game seems to use it directly */
	AM_RANGE(0x708000, 0x709fff) AM_WRITE(cps2_objram2_w) AM_BASE(&cps2_objram2)	/* Object RAM */
	AM_RANGE(0x70a000, 0x70bfff) AM_WRITE(cps2_objram2_w)			/* mirror */
	AM_RANGE(0x70c000, 0x70dfff) AM_WRITE(cps2_objram2_w)			/* mirror */
	AM_RANGE(0x70e000, 0x70ffff) AM_WRITE(cps2_objram2_w)			/* mirror */
	AM_RANGE(0x800100, 0x80013f) AM_WRITE(cps1_cps_a_w) AM_BASE(&cps1_cps_a_regs)	/* mirror (sfa) */
	AM_RANGE(0x800140, 0x80017f) AM_WRITE(cps1_cps_b_w) AM_BASE(&cps1_cps_b_regs)	/* mirror (sfa) */
	AM_RANGE(0x804040, 0x804041) AM_WRITE(cps2_eeprom_port_w)		/* EEPROM */
	AM_RANGE(0x8040a0, 0x8040a1) AM_WRITE(SMH_NOP)				/* Unknown (reset once on startup) */
	AM_RANGE(0x8040e0, 0x8040e1) AM_WRITE(cps2_objram_bank_w)		/* bit 0 = Object ram bank swap */
	AM_RANGE(0x804100, 0x80413f) AM_WRITE(cps1_cps_a_w) AM_BASE(&cps1_cps_a_regs)	/* CPS-A custom */
	AM_RANGE(0x804140, 0x80417f) AM_WRITE(cps1_cps_b_w) AM_BASE(&cps1_cps_b_regs)	/* CPS-B custom */
	AM_RANGE(0x900000, 0x92ffff) AM_WRITE(cps1_gfxram_w) AM_BASE(&cps1_gfxram) AM_SIZE(&cps1_gfxram_size)
	AM_RANGE(0xff0000, 0xffffef) AM_WRITE(SMH_RAM)				/* RAM */
	AM_RANGE(0xfffff0, 0xfffffb) AM_WRITE(SMH_RAM) AM_BASE(&cps2_output) AM_SIZE(&cps2_output_size)	/* CPS2 output */
ADDRESS_MAP_END

/*************************************
 *
 *  Generic port definitions
 *
 *************************************/

/* 4 players and 4 buttons */
static INPUT_PORTS_START( cps2_4p4b )
    PORT_START("IN0")      /* IN0 (0x00) */
    PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1)
    PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1)
    PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1)
    PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1)
    PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
    PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1)
    PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1)
    PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1)
    PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2)
    PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2)
    PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2)
    PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2)
    PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
    PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
    PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2)
    PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2)

    PORT_START("IN1")      /* IN1 (0x10) */
    PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(3)
    PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(3)
    PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(3)
    PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(3)
    PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(3)
    PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(3)
    PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(3)
    PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(3)
    PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(4)
    PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(4)
    PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(4)
    PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(4)
    PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(4)
    PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(4)
    PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(4)
    PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(4)

    PORT_START("IN2")      /* IN2 (0x20) */
    PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(eeprom_bit_r, NULL)
	PORT_SERVICE_NO_TOGGLE( 0x0002, IP_ACTIVE_LOW )
    PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_SERVICE1 )
    PORT_BIT( 0x00f8, IP_ACTIVE_LOW, IPT_UNKNOWN )
    PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_START1 )
    PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_START2 )
    PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_START3 )
    PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_START4 )
    PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_COIN1 )
    PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_COIN2 )
    PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_COIN3 )
    PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_COIN4 )
INPUT_PORTS_END

/* 4 players and 3 buttons */
static INPUT_PORTS_START( cps2_4p3b )
	PORT_INCLUDE(cps2_4p4b)

	PORT_MODIFY("IN0")
    PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON4 PORT_PLAYER(1) */
    PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON4 PORT_PLAYER(2) */

	PORT_MODIFY("IN1")
    PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON4 PORT_PLAYER(3) */
    PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON4 PORT_PLAYER(4) */
INPUT_PORTS_END

/* 4 players and 2 buttons */
static INPUT_PORTS_START( cps2_4p2b )
	PORT_INCLUDE(cps2_4p3b)

	PORT_MODIFY("IN0")
    PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON3 PORT_PLAYER(1) */
    PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON3 PORT_PLAYER(2) */

	PORT_MODIFY("IN1")
    PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON3 PORT_PLAYER(3) */
    PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON3 PORT_PLAYER(4) */
INPUT_PORTS_END

/* 3 players and 4 buttons */
static INPUT_PORTS_START( cps2_3p4b )
	PORT_INCLUDE(cps2_4p4b)

	PORT_MODIFY("IN1")
    PORT_BIT( 0xff00, IP_ACTIVE_LOW, IPT_UNUSED )           /* PORT_PLAYER(4) inputs */

	PORT_MODIFY("IN2")
    PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_UNUSED )           /* START4 */
    PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNUSED )           /* COIN4 */
INPUT_PORTS_END

/* 3 players and 3 buttons */
static INPUT_PORTS_START( cps2_3p3b )
	PORT_INCLUDE(cps2_3p4b)

	PORT_MODIFY("IN0")
    PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON4 PORT_PLAYER(1) */
    PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON4 PORT_PLAYER(2) */

	PORT_MODIFY("IN1")
    PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON4 PORT_PLAYER(3) */
INPUT_PORTS_END

/* 3 players and 2 buttons */
#ifdef UNUSED_DEFINITION
static INPUT_PORTS_START( cps2_3p2b )
	PORT_INCLUDE(cps2_3p3b)

	PORT_MODIFY("IN0")
    PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON3 PORT_PLAYER(1) */
    PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON3 PORT_PLAYER(2) */

	PORT_MODIFY("IN1")
    PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON3 PORT_PLAYER(3) */
INPUT_PORTS_END
#endif

/* 2 players and 4 buttons */
static INPUT_PORTS_START( cps2_2p4b )
	PORT_INCLUDE(cps2_3p4b)

	PORT_MODIFY("IN1")
    PORT_BIT( 0x00ff, IP_ACTIVE_LOW, IPT_UNUSED )           /* PORT_PLAYER(3) inputs */

	PORT_MODIFY("IN2")
    PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_UNUSED )           /* START3 */
    PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNUSED )           /* COIN3 */
INPUT_PORTS_END

/* 2 players and 3 buttons */
static INPUT_PORTS_START( cps2_2p3b )
	PORT_INCLUDE(cps2_2p4b)

	PORT_MODIFY("IN0")
    PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON4 PORT_PLAYER(1) */
    PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON4 PORT_PLAYER(2) */
INPUT_PORTS_END

/* 2 players and 2 buttons */
static INPUT_PORTS_START( cps2_2p2b )
	PORT_INCLUDE(cps2_2p3b)

	PORT_MODIFY("IN0")
    PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON3 PORT_PLAYER(1) */
    PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON3 PORT_PLAYER(2) */
INPUT_PORTS_END

/* 2 players and 1 button */
static INPUT_PORTS_START( cps2_2p1b )
	PORT_INCLUDE(cps2_2p2b)

	PORT_MODIFY("IN0")
    PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON2 PORT_PLAYER(1) */
    PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON2 PORT_PLAYER(2) */
INPUT_PORTS_END

/* 2 players and 6 buttons (2 rows of 3 buttons) */
static INPUT_PORTS_START( cps2_2p6b )
	PORT_INCLUDE(cps2_2p3b)

	PORT_MODIFY("IN1")
    PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1)
    PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(1)
    PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(1)
    PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2)
    PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(2)

	PORT_MODIFY("IN2")
    PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(2)
INPUT_PORTS_END

/* 1 player and 4 buttons */
static INPUT_PORTS_START( cps2_1p4b )
	PORT_INCLUDE(cps2_2p4b)

	PORT_MODIFY("IN0")
    PORT_BIT( 0xff00, IP_ACTIVE_LOW, IPT_UNUSED )           /* PORT_PLAYER(2) inputs */

	PORT_MODIFY("IN2")
    PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_UNUSED )           /* START2 */
    PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_UNUSED )           /* COIN2 */
INPUT_PORTS_END

/* 1 player and 3 buttons */
static INPUT_PORTS_START( cps2_1p3b )
	PORT_INCLUDE(cps2_1p4b)

	PORT_MODIFY("IN0")
    PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON4 PORT_PLAYER(1) */
INPUT_PORTS_END

/* 1 player and 2 buttons */
static INPUT_PORTS_START( cps2_1p2b )
	PORT_INCLUDE(cps2_1p3b)

	PORT_MODIFY("IN0")
    PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_UNUSED )           /* BUTTON3 PORT_PLAYER(1) */
INPUT_PORTS_END


/*************************************
 *
 *  Game-specific port definitions
 *
 *************************************/

/* According to the "test mode", buttons layout look like a 2 players 6 buttons machine where buttons have been removed */
static INPUT_PORTS_START( cybots )
	PORT_INCLUDE(cps2_2p6b)

	PORT_MODIFY("IN1")
    PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1)
    PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_UNUSED )                     /* BUTTON5 PORT_PLAYER(1) */
    PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_UNUSED )                     /* BUTTON6 PORT_PLAYER(1) */
    PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2)
    PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_UNUSED )                     /* BUTTON5 PORT_PLAYER(2) */

	PORT_MODIFY("IN2")
    PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNUSED )                     /* BUTTON6 PORT_PLAYER(2) */
INPUT_PORTS_END

/* 2 players, no joysticks which are replaced with 4 buttons, no other buttons */
static INPUT_PORTS_START( qndream )
	PORT_INCLUDE(cps2_2p4b)

	PORT_MODIFY("IN0")
    PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1)
    PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1)
    PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1)
    PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
    PORT_BIT( 0x00f0, IP_ACTIVE_LOW, IPT_UNUSED )
    PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2)
    PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2)
    PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
    PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
    PORT_BIT( 0xf000, IP_ACTIVE_LOW, IPT_UNUSED )
INPUT_PORTS_END

/* 2 players and 1 button - either 2 8-way joysticks, 2 2-way joysticks, or 2 paddles */
static INPUT_PORTS_START( pzloop2 )
	PORT_INCLUDE(cps2_2p1b)

	PORT_START("PADDLE1")
	PORT_BIT( 0xff, 0x00, IPT_DIAL ) PORT_SENSITIVITY(100) PORT_KEYDELTA(15) PORT_PLAYER(1)

	PORT_START("PADDLE2")
	PORT_BIT( 0xff, 0x00, IPT_DIAL ) PORT_SENSITIVITY(100) PORT_KEYDELTA(15) PORT_PLAYER(2)
INPUT_PORTS_END

/* 1 player and 3 buttons, but 2 coins slots */
static INPUT_PORTS_START( choko )
	PORT_INCLUDE(cps2_1p3b)

	PORT_MODIFY("IN2")
    PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_COIN2 )
INPUT_PORTS_END


/*************************************
 *
 *  Graphics layouts
 *
 *************************************/

static const gfx_layout cps1_layout8x8 =
{
	8,8,
	RGN_FRAC(1,1),
	4,
	{ 0, 1, 2, 3 },
	{ 1*4, 0*4, 3*4, 2*4, 5*4, 4*4, 7*4, 6*4 },
	{ 0*64, 1*64, 2*64, 3*64, 4*64, 5*64, 6*64, 7*64 },
	64*8
};

static const gfx_layout cps1_layout8x8_2 =
{
	8,8,
	RGN_FRAC(1,1),
	4,
	{ 0, 1, 2, 3 },
	{ 9*4, 8*4, 11*4, 10*4, 13*4, 12*4, 15*4, 14*4 },
	{ 0*64, 1*64, 2*64, 3*64, 4*64, 5*64, 6*64, 7*64 },
	64*8
};

static GFXLAYOUT_RAW( layout16x16, 4, 16, 16, 8*8, 128*8 )
static GFXLAYOUT_RAW( layout32x32, 4, 32, 32, 16*8, 512*8 )

static GFXDECODE_START( cps2 )
	GFXDECODE_ENTRY( "gfx", 0, cps1_layout8x8,   0, 0x100 )
	GFXDECODE_ENTRY( "gfx", 0, cps1_layout8x8_2, 0, 0x100 )
	GFXDECODE_ENTRY( "gfx", 0, layout16x16, 0, 0x100 )
	GFXDECODE_ENTRY( "gfx", 0, layout32x32, 0, 0x100 )
GFXDECODE_END


/*************************************
 *
 *  M68K encryption interface
 *
 *************************************/

static const m68k_encryption_interface cps2_encryption =
{
	cps2_read8, cps2_read16, cps2_read32,
	cps2_read16, cps2_read32
};


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

static MACHINE_DRIVER_START( cps2 )

	/* basic machine hardware */
	MDRV_CPU_ADD("main", M68000, 16000000)
	MDRV_CPU_CONFIG(cps2_encryption)
	MDRV_CPU_PROGRAM_MAP(cps2_readmem,cps2_writemem)
	MDRV_CPU_VBLANK_INT_HACK(cps2_interrupt,262)	// 262  /* ??? interrupts per frame */

	MDRV_CPU_ADD("audio", Z80, 8000000)
	MDRV_CPU_PROGRAM_MAP(qsound_sub_map,0)
	MDRV_CPU_PERIODIC_INT(irq0_line_hold, 251)	/* 251 is good (see 'mercy mercy mercy'section of sgemf attract mode for accurate sound sync */

//  MDRV_INTERLEAVE(262)  /* 262 scanlines, for raster effects */

	MDRV_NVRAM_HANDLER(cps2)

	/* video hardware */
	MDRV_VIDEO_ATTRIBUTES(VIDEO_UPDATE_BEFORE_VBLANK)

	MDRV_SCREEN_ADD("main", RASTER)
	MDRV_SCREEN_REFRESH_RATE(59.633333)
	MDRV_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0))
	MDRV_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)
	MDRV_SCREEN_SIZE(64*8, 32*8)
	MDRV_SCREEN_VISIBLE_AREA(8*8, (64-8)*8-1, 2*8, 30*8-1 )

	MDRV_GFXDECODE(cps2)
	MDRV_PALETTE_LENGTH(0xc00)

	MDRV_VIDEO_START(cps2)
	MDRV_VIDEO_EOF(cps1)
	MDRV_VIDEO_UPDATE(cps1)

	/* sound hardware */
	MDRV_SPEAKER_STANDARD_STEREO("left", "right")

	MDRV_SOUND_ADD("qsound", QSOUND, QSOUND_CLOCK)
	MDRV_SOUND_ROUTE(0, "left", 1.0)
	MDRV_SOUND_ROUTE(1, "right", 1.0)
MACHINE_DRIVER_END

static MACHINE_DRIVER_START( phoenix )
	MDRV_IMPORT_FROM(cps2)

	MDRV_CPU_MODIFY("main")
	MDRV_CPU_PROGRAM_MAP(cps2_readmem,phoenix_writemem)
MACHINE_DRIVER_END

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



/*************************************
 *
 *  Games initialisation
 *
 *************************************/

static DRIVER_INIT( cps2 )
{
	/* Decrypt the game - see machine/cps2crpt.c */
	DRIVER_INIT_CALL(cps2crpt);
	cps2networkpresent = 0;

	cpunum_set_clockscale(machine, 0, 0.7375f); /* RAM access waitstates etc. aren't emulated - slow the CPU to compensate */
}



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


/* misfitmame start */

ROM_START( suicide )
	ROM_REGION(CODE_SIZE, "main", 0 )
	ROM_LOAD16_WORD_SWAP( "suicide.03", 0x000000, 0x80000, CRC(4d5eea90) SHA1(c6f6361650d64401354111bf111bd924126b7035) )

	ROM_REGION( 0xC00000, "gfx", 0 )
	ROM_FILL(              0x000000, 0x800000, 0 )
	ROMX_LOAD( "pzf.14m",  0x800000, 0x100000, CRC(2d4881cb) SHA1(fd3baa183c25bed153b19c251980e2fb761600e2) , ROM_GROUPWORD | ROM_SKIP(6) )
	ROMX_LOAD( "pzf.16m",  0x800002, 0x100000, CRC(4b0fd1be) SHA1(377aafdcdb7a866b1c8487670e3598d8197976e4) , ROM_GROUPWORD | ROM_SKIP(6) )
	ROMX_LOAD( "pzf.18m",  0x800004, 0x100000, CRC(e43aac33) SHA1(d041e0688c3807d3363861a7f216de43b34d846c) , ROM_GROUPWORD | ROM_SKIP(6) )
	ROMX_LOAD( "pzf.20m",  0x800006, 0x100000, CRC(7f536ff1) SHA1(905b9d62ef7bef47297c7f4a4dd697aed6df38a5) , ROM_GROUPWORD | ROM_SKIP(6) )

	ROM_REGION(QSOUND_SIZE, "audio", 0 ) /* 64k for the audio CPU (+banks) */
	ROM_LOAD( "pzf.01",   0x00000, 0x08000, CRC(600fb2a3) SHA1(1fab1c2a23bf6ad8309d29ddbbc29435a8aeea13) )
	ROM_CONTINUE(         0x10000, 0x18000 )
	ROM_LOAD( "pzf.02",   0x28000, 0x20000, CRC(496076e0) SHA1(1ee4e135140afd0e8e03231e570cd77d140f6367) )

	ROM_REGION( 0x400000, "qsound", 0 ) /* QSound samples */
	ROM_LOAD16_WORD_SWAP( "pzf.11m",   0x000000, 0x200000, CRC(78442743) SHA1(b61190bb586871de6d54af580e3e1d9cc0de0acb) )
	ROM_LOAD16_WORD_SWAP( "pzf.12m",   0x200000, 0x200000, CRC(399d2c7b) SHA1(e849dea97b8d16540415c0d9bbc4f9f4eb755ec4) )
ROM_END

/* Misc */

GAME( 1996, suicide,  0,   cps2,    cps2_2p2b, cps2,   ROT0,   "Razoola", "Suicide Test", 0 )

/* misfitmame end */

