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

  machine.c

  Functions to emulate general aspects of the machine (RAM, ROM, interrupts,
  I/O ports)

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

#include "driver.h"
#include "cpu/m68000/m68000.h"

unsigned char *toypop_sound_sharedram, *toypop_m68000_sharedram, *toypop_customio;
static unsigned char interrupt_enable_mainCPU, interrupt_enable_sound, interrupt_enable_68k;
// variables used by the coinage of Libble Rabble
static int credits, coinsA, coinsB;
static int coinageA[8][2] = {{1,1},{2,1},{1,3},{3,1},{1,2},{2,3},{1,6},{3,2}};
static int coinageB[4][2] = {{1,1},{1,7},{1,5},{2,1}};

MACHINE_INIT( toypop )
{
	credits = coinsA = coinsB = 0;
	interrupt_enable_mainCPU = 0;
	interrupt_enable_sound = 0;
	interrupt_enable_68k = 0;
}

READ_HANDLER( toypop_sound_sharedram_r )
{
	/* to speed up emulation, we check for the loop the sound CPU sits in most of the time
	   and end the current iteration (things will start going again with the next IRQ) */
	if (offset == 0xa1 - 0x40 && toypop_sound_sharedram[offset] == 0 && activecpu_get_pc() == 0xe4df)
		cpu_spinuntil_int();
	return toypop_sound_sharedram[offset];
}

WRITE_HANDLER( toypop_sound_sharedram_w )
{
	toypop_sound_sharedram[offset] = data;
}

READ16_HANDLER( toypop_m68000_sharedram_r )
{
	return toypop_m68000_sharedram[offset];
}

WRITE16_HANDLER( toypop_m68000_sharedram_w )
{
	if (ACCESSING_LSB)
		toypop_m68000_sharedram[offset] = data & 0xff;
}

WRITE_HANDLER( toypop_main_interrupt_enable_w )
{
	interrupt_enable_mainCPU = 1;
}

WRITE_HANDLER( toypop_main_interrupt_disable_w )
{
	interrupt_enable_mainCPU = 0;
}

WRITE_HANDLER( toypop_sound_interrupt_enable_w )
{
	interrupt_enable_sound = 1;
}

WRITE_HANDLER( toypop_sound_interrupt_disable_w )
{
	interrupt_enable_sound = 0;
}

WRITE16_HANDLER( toypop_m68000_interrupt_enable_w )
{
	interrupt_enable_68k = 1;
}

WRITE16_HANDLER( toypop_m68000_interrupt_disable_w )
{
	interrupt_enable_68k = 0;
}

INTERRUPT_GEN( toypop_main_interrupt )
{
	if (interrupt_enable_mainCPU)
		irq0_line_hold();
}

INTERRUPT_GEN( toypop_sound_interrupt )
{
	if (interrupt_enable_sound)
		irq0_line_hold();
}

INTERRUPT_GEN( toypop_m68000_interrupt )
{
	if (interrupt_enable_68k)
		cpu_set_irq_line(2, 6, HOLD_LINE);
}

READ_HANDLER( toypop_customio_r )
{
	int mode = toypop_customio[8];

	/* mode 5 values are actually checked against these numbers during power up */
	if (mode == 5)
		switch (offset) {
			case 2:
				return 15;
			case 6:
				return 12;
			case 16:
				return 6;
			case 17:
				return 9;
			case 32:
				return 6;
			case 33:
				return 9;
			default:
				return toypop_customio[offset];
		}
	else
		switch (offset) {
			case 4:
				return readinputport(0) & 0x0f;
			case 5:
				return readinputport(0) >> 4;
			case 6:
				return readinputport(1) & 0x0f;
			case 7:
				return readinputport(1) >> 4;
			case 16:
				return readinputport(2) & 0x0f;
			case 17:
				return readinputport(2) >> 4;
			case 18:
				return readinputport(3) & 0x0f;
			case 19:
				return readinputport(3) >> 4;
			default:
				return toypop_customio[offset];
		}
}

READ_HANDLER( liblrabl_customio_r )
{
	static int lastcoin, laststart;
	int val, tmp, mode = toypop_customio[24];

	/* mode 7 values are actually checked against these numbers during power up */
	if (mode == 7)
		switch (offset) {
			case 2:
				return 15;
			case 6:
				return 12;
			case 18:
				return 14;
			case 39:
				return 6;
			default:
				return toypop_customio[offset];
		}
	else if (mode == 1)
		switch (offset) {
			case 0:		// Coin slots
				val = readinputport(3) & 0x0f;
				// bit 0 is a trigger for the coin 1 slot
				if ((val & 1) && !(lastcoin & 1)) {
					tmp = (readinputport(1) & 0xe0) >> 5;
					coinsA++;
					if (coinsA == coinageA[tmp][0]) {
						credits += coinageA[tmp][1];
						coinsA = 0;
					}
				}
				// bit 1 is a trigger for the coin 2 slot
				if ((val & 2) && !(lastcoin & 2)) {
					tmp = (readinputport(0) & 0x18) >> 3;
					coinsB++;
					if (coinsB == coinageB[tmp][0]) {
						credits += coinageB[tmp][1];
						coinsB = 0;
					}
				}
				return lastcoin = val;
			case 1:		// Start buttons
				val = readinputport(3) >> 4;
				// bit 0 is a trigger for the 1 player start
				if ((val & 1) && !(laststart & 1))
					credits--;
				// bit 1 is a trigger for the 2 player start
				if ((val & 2) && !(laststart & 2)) {
					if (credits >= 2)
						credits -= 2;
					else
						val &= ~2;	// otherwise you can start with no credits
				}
				return laststart = val;
			case 2:		// High BCD of credits
				return credits / 10;
			case 3:		// Low BCD of credits
				return credits % 10;
//			case 5:		// read, but unknown
//				return readinputport(2) >> 4;
			case 4:		// Right joystick
				return readinputport(4) >> 4;
			case 6:		// Player 2 right joystick in cocktail mode
				return readinputport(5) >> 4;
			case 16:
				return readinputport(1) >> 4;
			case 17:
				return readinputport(0) & 0x0f;
			case 18:
				return readinputport(0) >> 4;
			case 19:
				return readinputport(1) & 0x0f;
			case 34:	// Left joystick
				return readinputport(4) & 0x0f;
			case 36:	// Player 2 left joystick in cocktail mode
				return readinputport(5) & 0x0f;
			case 39:
				return readinputport(2) & 0x0f;
			default:
				return toypop_customio[offset];
		}
	else
		return toypop_customio[offset];
}

WRITE_HANDLER( toypop_sound_clear_w )
{
	cpu_set_reset_line(1, CLEAR_LINE);
}

WRITE_HANDLER( toypop_sound_assert_w )
{
	cpu_set_reset_line(1, ASSERT_LINE);
}

WRITE_HANDLER( toypop_m68000_clear_w )
{
	cpu_set_reset_line(2, CLEAR_LINE);
}

WRITE_HANDLER( toypop_m68000_assert_w )
{
	cpu_set_reset_line(2, ASSERT_LINE);
}
