//////////////////////////////////////////////////////////////////////////
// Mapper120  Tobidase Daisakusen                                       //
//////////////////////////////////////////////////////////////////////////
#include "BoardMMC3.h"

void	Mapper049::Reset()
{
//	nes->ppu->SetVromWrite(1);
	MMC3_RegReset();
	temp = 0;
//	nes->ppu->SetExtLatchMode( TRUE );
}

void	Mapper049::WriteLow( WORD addr, BYTE data )
{
	DEBUGOUT( "MPRWR A=%04X D=%02X L=%3d CYC=%d\n", addr&0xFFFF, data&0xFF, nes->GetScanline(), nes->cpu->GetTotalCycles() );
	if ((addr&0x4100)==0x4100) {
		temp=data;
//		temp &= 0x03;
//		if		( temp == 0 )	SetVRAM_Mirror( VRAM_VMIRROR );
//		else if ( temp == 1 )	SetVRAM_Mirror( VRAM_HMIRROR );
//		else if ( temp == 2 )	SetVRAM_Mirror( VRAM_MIRROR4L );
//		else					SetVRAM_Mirror( VRAM_MIRROR4H );
		FixCHR(MMC3_cmd);
	}
}

void	Mapper049::Write( WORD addr, BYTE data )
{
//	DEBUGOUT( "MPRWR A=%04X D=%02X L=%3d CYC=%d\n", addr&0xFFFF, data&0xFF, nes->GetScanline(), nes->cpu->GetTotalCycles() );
	MMC3CMDWrite(addr, data);
	MMC3_IRQWrite(addr, data);

	if((addr&0xE001)==0xE000) nes->cpu->ClrIRQ(IRQ_MAPPER);
}

void	Mapper049::MMC3CMDWrite(WORD A, BYTE V)
{
	switch (A & 0xE001) {
	case 0x8000:
		if ((V & 0x40) != (MMC3_cmd & 0x40))
			FixMMC3PRG(V);
		if ((V & 0x80) != (MMC3_cmd & 0x80))
			FixCHR(V);
		MMC3_cmd = V;
		break;
	case 0x8001:
	{
		int cbase = (MMC3_cmd & 0x80) << 5;
		MMC3_DRegBuf[MMC3_cmd & 0x7] = V;
		switch (MMC3_cmd & 0x07) {
		case 0:
			wrapc((cbase ^ 0x000), V & (~1));
			wrapc((cbase ^ 0x400), V | 1);
			break;
		case 1:
			wrapc((cbase ^ 0x800), V & (~1));
			wrapc((cbase ^ 0xC00), V | 1);
			break;
		case 2:
			wrapc(cbase ^ 0x1000, V);
			break;
		case 3:
			wrapc(cbase ^ 0x1400, V);
			break;
		case 4:
			wrapc(cbase ^ 0x1800, V);
			break;
		case 5:
			wrapc(cbase ^ 0x1C00, V);
			break;
		case 6:
			if (MMC3_cmd&0x40) pwrap(0xC000, V);
			else		   pwrap(0x8000, V);
			break;
		case 7:
			pwrap(0xA000, V);
			break;
		}
		break;
	}
	case 0xA000:
		MMC3_A000B = V;
		mwrap(MMC3_A000B);
		break;
	case 0xA001:
		MMC3_A001B = V;
		break;
	}
}

void	Mapper049::wrapc(WORD A, BYTE V)
{
	 if(temp&2)
		SetCRAM_8K_Bank(0);
	 else
		SetVROM_1K_Bank(A>>10,V);
}

void	Mapper049::FixCHR(BYTE V)
{
	int cbase = (V & 0x80) << 5;
	wrapc((cbase ^ 0x000), MMC3_DRegBuf[0] & (~1));
	wrapc((cbase ^ 0x400), MMC3_DRegBuf[0] | 1);
	wrapc((cbase ^ 0x800), MMC3_DRegBuf[1] & (~1));
	wrapc((cbase ^ 0xC00), MMC3_DRegBuf[1] | 1);
	wrapc(cbase ^ 0x1000, MMC3_DRegBuf[2]);
	wrapc(cbase ^ 0x1400, MMC3_DRegBuf[3]);
	wrapc(cbase ^ 0x1800, MMC3_DRegBuf[4]);
	wrapc(cbase ^ 0x1c00, MMC3_DRegBuf[5]);

	mwrap(MMC3_A000B);
}

void	Mapper049::HSync( INT scanline )
{
	if ((scanline >= 0 && scanline <= 239)) {
		if (nes->ppu->IsDispON())
		{
			if (MMC3_IRQa && !MMC3_IRQReload) {
				if (scanline == 0) {
					if (MMC3_IRQCount) {
						MMC3_IRQCount -= 1;
					}
				}
				if (!(MMC3_IRQCount)){
					MMC3_IRQReload = 0xFF;
					MMC3_IRQCount = MMC3_IRQLatch;
					nes->cpu->SetIRQ(IRQ_MAPPER);
				}
				MMC3_IRQCount--;
			}
		}
	}
}

void	Mapper049::PPU_ExtLatch( WORD ntbladr, BYTE& chr_l, BYTE& chr_h, BYTE& attr )
{
	INT loopy_v = nes->ppu->GetPPUADDR();
	INT loopy_y = nes->ppu->GetTILEY();
	INT tileofs = (PPUREG[0]&PPU_BGTBL_BIT)<<8;
	INT attradr = 0x23C0+(loopy_v&0x0C00)+((loopy_v&0x0380)>>4);
	INT attrsft = (ntbladr&0x0040)>>4;
	LPBYTE pNTBL = PPU_MEM_BANK[ntbladr>>10];
	INT ntbl_x  = ntbladr&0x001F;
	INT tileadr, ntb;

	ntb = (ntbladr>>10)&3;

	if(ntb==2)
	tileofs |= 0x1000;
	else if(ntb && temp)
	tileofs |= 0x1000;
	else
	tileofs |= 0x0000;

	attradr &= 0x3FF;
	attr = ((pNTBL[attradr+(ntbl_x>>2)]>>((ntbl_x&2)+attrsft))&3)<<2;
	tileadr = tileofs+pNTBL[ntbladr&0x03FF]*0x10+loopy_y;

	chr_l = PPU_MEM_BANK[tileadr>>10][ tileadr&0x03FF   ];
	chr_h = PPU_MEM_BANK[tileadr>>10][(tileadr&0x03FF)+8];
}

void	Mapper049::PPU_Latch( WORD addr )
{
	if(DirectInput.m_Sw[DIK_PAUSE]){
		nes->Dump_CRAM();
	}
}
