#include "pgm.h"

/*
	IGS Asic27a (type 2) proper emulation

	Used by:
		Martial Masters
		Bee Storm - DoDonPachi II
		Dragon World 2001
		Dragon World Pretty Chance
		Knights of Valour 2
		Knights of Valour 2 Plus - Nine Dragons
*/

static UINT8 asic27a_to_arm = 0;
static UINT8 asic27a_to_68k = 0;

static inline void pgm_cpu_sync()
{
	while (SekTotalCycles() > Arm7TotalCycles())
		Arm7Run(SekTotalCycles() - Arm7TotalCycles());
}

static void __fastcall asic27a_write_byte(UINT32 /*address*/, UINT8 data)
{
	// ddp2 requires this
	pgm_cpu_sync();
	asic27a_to_arm = data;
	Arm7SetIRQLine(ARM7_FIRQ_LINE, CPU_IRQSTATUS_ACK);
}

static void __fastcall asic27a_write_word(UINT32 /*address*/, UINT16 data)
{
	pgm_cpu_sync();
	asic27a_to_arm = data;
	Arm7SetIRQLine(ARM7_FIRQ_LINE, CPU_IRQSTATUS_ACK);
}

static UINT8 __fastcall asic27a_read_byte(UINT32 /*address*/)
{
	pgm_cpu_sync();
	return asic27a_to_68k;
}

static UINT16 __fastcall asic27a_read_word(UINT32 /*address*/)
{
	pgm_cpu_sync();
	return asic27a_to_68k;
}

static void asic27a_arm7_write_byte(UINT32 address, UINT8 data)
{
	switch (address)
	{
		case 0x38000000:
			asic27a_to_68k = data;
		return;
	}
}

static UINT8 asic27a_arm7_read_byte(UINT32 address)
{
	switch (address)
	{
		case 0x38000000:
			Arm7SetIRQLine(ARM7_FIRQ_LINE, CPU_IRQSTATUS_NONE);
			return asic27a_to_arm;
	}

	return 0;
}

static INT32 asic27aScan(INT32 nAction,INT32 *)
{
	struct BurnArea ba;

	if (nAction & ACB_MEMORY_RAM) {
		ba.Data		= PGMARMShareRAM;
		ba.nLen		= 0x0010000;
		ba.nAddress	= 0xd00000;
		ba.szName	= "ARM SHARE RAM";
		BurnAcb(&ba);

		ba.Data		= PGMARMRAM0;
		ba.nLen		= 0x0000400;
		ba.nAddress	= 0;
		ba.szName	= "ARM RAM 0";
		BurnAcb(&ba);

		ba.Data		= PGMARMRAM1;
		ba.nLen		= 0x0010000;
		ba.nAddress	= 0;
		ba.szName	= "ARM RAM 1";
		BurnAcb(&ba);

		ba.Data		= PGMARMRAM2;
		ba.nLen		= 0x0000400;
		ba.nAddress	= 0;
		ba.szName	= "ARM RAM 2";
		BurnAcb(&ba);
	}

	if (nAction & ACB_DRIVER_DATA) {
		Arm7Scan(nAction);

		SCAN_VAR(asic27a_to_arm);
		SCAN_VAR(asic27a_to_68k);
	}

 	return 0;
}

void install_protection_asic27a_martmast()
{
	pPgmScanCallback = asic27aScan;

	SekOpen(0);

	for (INT32 i = 0; i < 0x100000; i += 0x20000) { // mirroring verified on real hardware
		SekMapMemory(PGMARMShareRAM,	0xd00000 + i, 0xd0ffff+i, MAP_RAM);
		SekMapHandler(4,				0xd10000 + i, 0xd1ffff+i, MAP_READ | MAP_WRITE);
	}
	
	SekSetReadWordHandler(4, 	asic27a_read_word);
	SekSetReadByteHandler(4, 	asic27a_read_byte);
	SekSetWriteWordHandler(4, 	asic27a_write_word);
	SekSetWriteByteHandler(4, 	asic27a_write_byte);
	SekClose();

	Arm7Init(0);
	Arm7Open(0);
	Arm7MapMemory(PGMARMROM,			0x00000000, 0x00003fff, MAP_ROM);
	Arm7MapMemory(PGMUSER0,				0x08000000, 0x08000000+(nPGMExternalARMLen-1), MAP_ROM);
	Arm7MapMemory(PGMARMRAM0,			0x10000000, 0x100003ff, MAP_RAM);
	Arm7MapMemory(PGMARMRAM1,			0x18000000, 0x1800ffff, MAP_RAM);
	Arm7MapMemory(PGMARMShareRAM,		0x48000000, 0x4800ffff, MAP_RAM);
	Arm7MapMemory(PGMARMRAM2,			0x50000000, 0x500003ff, MAP_RAM);
	Arm7SetWriteByteHandler(asic27a_arm7_write_byte);
	Arm7SetReadByteHandler(asic27a_arm7_read_byte);
	Arm7Close();
}
