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

      Poly-Play
	  (c) 1985 by VEB Polytechnik Karl-Marx-Stadt

      driver by Martin Buchholz (buchholz@mail.uni-greifswald.de)

      Very special thanks to the following people, each one of them spent
	  some of their spare time to make this driver working:
	  - Juergen Oppermann and Volker Hann for electronical assistance,
	    repair work and ROM dumping.
	  - Jan-Ole Christian from the Videogamemuseum in Berlin, which houses
	    one of the last existing Poly-Play arcade automatons. He also
		provided me with schematics and service manuals.


memory map:

0000 - 03ff OS ROM
0400 - 07ff Game ROM (used for Abfahrtslauf)
0800 - 0cff Menu Screen ROM

0d00 - 0fff work RAM

1000 - 4fff GAME ROM (pcb 2 - Abfahrtslauf          (1000 - 1bff),
                              Hirschjagd            (1c00 - 27ff),
							  Hase und Wolf         (2800 - 3fff),
                              Schmetterlingsfang    (4000 - 4fff)
5000 - 8fff GAME ROM (pcb 1 - Schiessbude           (5000 - 5fff)
                              Autorennen            (6000 - 73ff)
							  opto-akust. Merkspiel (7400 - 7fff)
							  Wasserrohrbruch       (8000 - 8fff)

e800 - ebff character ROM (chr 00..7f) 1 bit per pixel
ec00 - f7ff character RAM (chr 80..ff) 3 bit per pixel
f800 - ffff video RAM

I/O ports:

read:

83        IN1
          used as hardware random number generator

84        IN0
          bit 0 = fire button
          bit 1 = right
          bit 2 = left
          bit 3 = up
          bit 4 = down
          bit 5 = unused
          bit 6 = Summe Spiele
          bit 7 = coinage (+IRQ to make the game acknowledge it)

85        bit 0-4 = light organ (unemulated :)) )
          bit 5-7 = sound parameter (unemulated, it's very difficult to
		            figure out how those work)

86        ???

87        PIO Control register

write:
80	      Sound Channel 1
81        Sound Channel 2
82        generates 40 Hz timer for timeout in game title screens
83        generates main 75 Hz timer interrupt

The Poly-Play has a simple bookmarking system which can be activated
setting Bit 6 of PORTA (Summe Spiele) to low. It reads a double word
from 0c00 and displays it on the screen.
I currently haven't figured out how the I/O port handling for the book-
mark system works.

Uniquely the Poly-Play has a light organ which totally confuses you whilst
playing the automaton. Bits 1-5 of PORTB control the organ but it's not
emulated now. ;)

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

#include "driver.h"
#include "vidhrdw/generic.h"
#include "cpu/z80/z80.h"

static unsigned char *polyplay_ram;

void polyplay_reset(void);

/* video hardware access */
extern unsigned char *polyplay_characterram;
PALETTE_INIT( polyplay );
VIDEO_UPDATE( polyplay );
READ_HANDLER( polyplay_characterram_r );
WRITE_HANDLER( polyplay_characterram_w );

/* I/O Port handling */
READ_HANDLER( polyplay_input_read );
READ_HANDLER( polyplay_random_read );

/* sound handling */
void poly_sound(void);
void set_channel1(int active);
void set_channel2(int active);
int prescale1, prescale2;
static int channel1_active;
static int channel1_const;
static int channel2_active;
static int channel2_const;
static DRIVER_INIT( polyplay_sound );
void play_channel1(int data);
void play_channel2(int data);
int  polyplay_sh_start(const struct MachineSound *msound);
void polyplay_sh_stop(void);
void polyplay_sh_update(void);

/* timer handling */
static void polyplay_timer(int param);
int timer2_active;
WRITE_HANDLER( polyplay_start_timer2 );
WRITE_HANDLER( polyplay_sound_channel );


/* Polyplay Sound Interface */
static struct CustomSound_interface custom_interface =
{
	polyplay_sh_start,
	polyplay_sh_stop,
	polyplay_sh_update
};


MACHINE_INIT( polyplay )
{
	channel1_active = 0;
	channel1_const = 0;
	channel2_active = 0;
	channel2_const = 0;
	set_channel1(0);
	play_channel1(0);
	set_channel2(0);
	play_channel2(0);
}


/* work RAM access */
WRITE_HANDLER( polyplay_ram_w )
{
	polyplay_ram[offset] = data;
}

READ_HANDLER( polyplay_ram_r )
{
	return polyplay_ram[offset];
}

/* memory mapping */
static MEMORY_READ_START( polyplay_readmem )
	{ 0x0000, 0x0bff, MRA_ROM },
	{ 0x0c00, 0x0fff, polyplay_ram_r },
	{ 0x1000, 0x8fff, MRA_ROM },

	{ 0xe800, 0xebff, MRA_ROM},
	{ 0xec00, 0xf7ff, polyplay_characterram_r },
	{ 0xf800, 0xffff, videoram_r },
MEMORY_END

static MEMORY_WRITE_START( polyplay_writemem )
	{ 0x0000, 0x0bff, MWA_ROM },
	{ 0x0c00, 0x0fff, polyplay_ram_w, &polyplay_ram },
	{ 0x1000, 0x8fff, MWA_ROM },

	{ 0xe800, 0xebff, MWA_ROM },
	{ 0xec00, 0xf7ff, polyplay_characterram_w, &polyplay_characterram },
	{ 0xf800, 0xffff, videoram_w, &videoram, &videoram_size },
MEMORY_END


/* port mapping */
static PORT_READ_START( readport_polyplay )
	{ 0x84, 0x84, polyplay_input_read },
	{ 0x83, 0x83, polyplay_random_read },
PORT_END

static PORT_WRITE_START( writeport_polyplay )
	{ 0x80, 0x81, polyplay_sound_channel },
	{ 0x82, 0x82, polyplay_start_timer2 },
PORT_END

INPUT_PORTS_START( polyplay )
	PORT_START	/* IN0 */
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 )
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT | IPF_8WAY )
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT  | IPF_8WAY )
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP    | IPF_8WAY )
	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN  | IPF_8WAY )
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN )
	PORT_BITX(0x40, IP_ACTIVE_LOW, IPT_SERVICE, "Bookkeeping Info", KEYCODE_F2, IP_JOY_NONE )
	PORT_BIT_IMPULSE( 0x80, IP_ACTIVE_LOW, IPT_COIN1, 10)
INPUT_PORTS_END


WRITE_HANDLER( polyplay_sound_channel )
{
	switch(offset) {
	case 0x00:
		if (channel1_const) {
			if (data <= 1) {
				set_channel1(0);
			}
			channel1_const = 0;
			play_channel1(data*prescale1);

		}
		else {
			prescale1 = (data & 0x20) ? 16 : 1;
			if (data & 0x04) {
				set_channel1(1);
				channel1_const = 1;
			}
			if ((data == 0x41) || (data == 0x65) || (data == 0x45)) {
				set_channel1(0);
				play_channel1(0);
			}
		}
		break;
	case 0x01:
		if (channel2_const) {
			if (data <= 1) {
				set_channel2(0);
			}
			channel2_const = 0;
			play_channel2(data*prescale2);

		}
		else {
			prescale2 = (data & 0x20) ? 16 : 1;
			if (data & 0x04) {
				set_channel2(1);
				channel2_const = 1;
			}
			if ((data == 0x41) || (data == 0x65) || (data == 0x45)) {
				set_channel2(0);
				play_channel2(0);
			}
		}
		break;
	}
}

WRITE_HANDLER( polyplay_start_timer2 )
{
	if (data == 0x03) {
		timer2_active = 0;
	}
	else {
		if (data == 0xb5) {
			timer_set(TIME_IN_HZ(40), 1, polyplay_timer);
			timer2_active = 1;
		}
	}
}

/* random number generator */
READ_HANDLER( polyplay_random_read )
{
	return rand() % 0xff;
}

/* graphic sturctures */
static struct GfxLayout charlayout_1_bit =
{
	8,8,	/* 8*8 characters */
	128,	/* 128 characters */
	1,	    /* 1 bit per pixel */
	{ 0 },
	{ 0, 1, 2, 3, 4, 5, 6, 7 },	/* pretty straightforward layout */
	{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
	8*8	/* every char takes 8 consecutive bytes */
};

static struct GfxLayout charlayout_3_bit =
{
	8,8,	/* 8*8 characters */
	128,	/* 128 characters */
	3,	    /* 3 bit per pixel */
	{ 0, 128*8*8, 128*8*8 + 128*8*8 },    /* offset for each bitplane */
	{ 0, 1, 2, 3, 4, 5, 6, 7 },	/* pretty straightforward layout */
	{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
	8*8	/* every char takes 8 consecutive bytes */
};

static struct GfxDecodeInfo gfxdecodeinfo[] =
{
	{ 0, 0xe800, &charlayout_1_bit, 0, 1 },
	{ 0, 0xec00, &charlayout_3_bit, 2, 1 },
	{ -1 }	/* end of array */
};


/* the machine driver */

static MACHINE_DRIVER_START( polyplay )

	/* basic machine hardware */
	MDRV_CPU_ADD(Z80, 9830400/4)
	MDRV_CPU_MEMORY(polyplay_readmem,polyplay_writemem)
	MDRV_CPU_PORTS(readport_polyplay,writeport_polyplay)

	MDRV_FRAMES_PER_SECOND(50)
	MDRV_VBLANK_DURATION(0)	/* frames per second, vblank duration */

	MDRV_MACHINE_INIT(polyplay)

	/* video hardware */
	MDRV_VIDEO_ATTRIBUTES(VIDEO_TYPE_RASTER)
	MDRV_SCREEN_SIZE(64*8, 32*8)
	MDRV_VISIBLE_AREA(0*8, 64*8-1, 0*8, 32*8-1)
	MDRV_GFXDECODE(gfxdecodeinfo)
	MDRV_PALETTE_LENGTH(10)

	MDRV_PALETTE_INIT(polyplay)
	MDRV_VIDEO_START(generic)
	MDRV_VIDEO_UPDATE(polyplay)

	/* sound hardware */
	MDRV_SOUND_ADD(CUSTOM, custom_interface)
MACHINE_DRIVER_END



/* ROM loading and mapping */
ROM_START( polyplay )
	ROM_REGION( 0x10000, REGION_CPU1, 0 )	/* 64k for code */
	ROM_LOAD( "cpu_0000.37",       0x0000, 0x0400, 0x87884c5f )
	ROM_LOAD( "cpu_0400.36",       0x0400, 0x0400, 0xd5c84829 )
	ROM_LOAD( "cpu_0800.35",       0x0800, 0x0400, 0x5f36d08e )
	ROM_LOAD( "2_-_1000.14",       0x1000, 0x0400, 0x950dfcdb )
	ROM_LOAD( "2_-_1400.10",       0x1400, 0x0400, 0x829f74ca )
	ROM_LOAD( "2_-_1800.6",        0x1800, 0x0400, 0xb69306f5 )
	ROM_LOAD( "2_-_1c00.2",        0x1c00, 0x0400, 0xaede2280 )
	ROM_LOAD( "2_-_2000.15",       0x2000, 0x0400, 0x6c7ad0d8 )
	ROM_LOAD( "2_-_2400.11",       0x2400, 0x0400, 0xbc7462f0 )
	ROM_LOAD( "2_-_2800.7",        0x2800, 0x0400, 0x9ccf1958 )
	ROM_LOAD( "2_-_2c00.3",        0x2c00, 0x0400, 0x21827930 )
	ROM_LOAD( "2_-_3000.16",       0x3000, 0x0400, 0xb3b3c0ec )
	ROM_LOAD( "2_-_3400.12",       0x3400, 0x0400, 0xbd416cd0 )
	ROM_LOAD( "2_-_3800.8",        0x3800, 0x0400, 0x1c470b7c )
	ROM_LOAD( "2_-_3c00.4",        0x3c00, 0x0400, 0xb8354a19 )
	ROM_LOAD( "2_-_4000.17",       0x4000, 0x0400, 0x1e01041e )
	ROM_LOAD( "2_-_4400.13",       0x4400, 0x0400, 0xfe4d8959 )
	ROM_LOAD( "2_-_4800.9",        0x4800, 0x0400, 0xc45f1d9d )
	ROM_LOAD( "2_-_4c00.5",        0x4c00, 0x0400, 0x26950ad6 )
	ROM_LOAD( "1_-_5000.30",       0x5000, 0x0400, 0x9f5e2ba1 )
	ROM_LOAD( "1_-_5400.26",       0x5400, 0x0400, 0xb5f9a780 )
	ROM_LOAD( "1_-_5800.22",       0x5800, 0x0400, 0xd973ad12 )
	ROM_LOAD( "1_-_5c00.18",       0x5c00, 0x0400, 0x9c22ea79 )
	ROM_LOAD( "1_-_6000.31",       0x6000, 0x0400, 0x245c49ca )
	ROM_LOAD( "1_-_6400.27",       0x6400, 0x0400, 0x181e427e )
	ROM_LOAD( "1_-_6800.23",       0x6800, 0x0400, 0x8a6c1f97 )
	ROM_LOAD( "1_-_6c00.19",       0x6c00, 0x0400, 0x77901dc9 )
	ROM_LOAD( "1_-_7000.32",       0x7000, 0x0400, 0x83ffbe57 )
	ROM_LOAD( "1_-_7400.28",       0x7400, 0x0400, 0xe2a66531 )
	ROM_LOAD( "1_-_7800.24",       0x7800, 0x0400, 0x1d0803ef )
	ROM_LOAD( "1_-_7c00.20",       0x7c00, 0x0400, 0x17dfa7e4 )
	ROM_LOAD( "1_-_8000.33",       0x8000, 0x0400, 0x6ee02375 )
	ROM_LOAD( "1_-_8400.29",       0x8400, 0x0400, 0x9db09598 )
	ROM_LOAD( "1_-_8800.25",       0x8800, 0x0400, 0xca2f963f )
	ROM_LOAD( "1_-_8c00.21",       0x8c00, 0x0400, 0x0c7dec2d )
	ROM_LOAD( "char.1",            0xe800, 0x0400, 0x5242dd6b )
ROM_END


/* interrupt handling, the game runs in IM 2 */
READ_HANDLER( polyplay_input_read )
{
	int inp = input_port_0_r(offset);

	if ((inp & 0x80) == 0) {    /* Coin inserted */
		cpu_set_irq_line_and_vector(0, 0, HOLD_LINE, 0x50);
		coin_counter_w(0, 1);
		timer_set(TIME_IN_SEC(1), 2, polyplay_timer);
	}

	return inp;
}

static void polyplay_timer(int param)
{
	switch(param) {
	case 0:
		cpu_set_irq_line_and_vector(0, 0, HOLD_LINE, 0x4e);
		break;
	case 1:
		if (timer2_active) {
			timer_set(TIME_IN_HZ(40), 1, polyplay_timer);
			cpu_set_irq_line_and_vector(0, 0, HOLD_LINE, 0x4c);
		}
		break;
	case 2:
		coin_counter_w(0, 0);
		break;
	}
}

/* initialization */
static DRIVER_INIT( polyplay_sound )
{
	timer_pulse(TIME_IN_HZ(75), 0, polyplay_timer);
	timer2_active = 0;
}

/* game driver */
GAME( 1985, polyplay, 0, polyplay, polyplay, polyplay_sound, ROT0, "VEB Polytechnik Karl-Marx-Stadt", "Poly-Play" )
