//////////////////////////////////////////////////////////////////////////
// Mapper019  Namcot 106                                                //
//////////////////////////////////////////////////////////////////////////
void	Mapper019::Reset()
{
	patch = 0;

	reg[0] = reg[1] = reg[2] = 0;

	::memset( exram, 0, sizeof(exram) );

	irq_enable = 0;
	irq_counter = 0;

	SetPROM_32K_Bank( 0, 1, PROM_8K_SIZE-2, PROM_8K_SIZE-1 );

	if( VROM_1K_SIZE >= 8 ) {
		SetVROM_8K_Bank( VROM_8K_SIZE-1 );
	}

	exsound_enable = 0xFF;

	DWORD	crc = nes->rom->GetPROM_CRC();

	if( crc == 0xb62a7b71 ) {	// Family Circuit '91(J)
		patch = 1;
	}

	if( crc == 0x14942c06 ) {	// Wagan Land 3(J)
		patch = 2;
	}

	if( crc == 0x968dcf09 ) {	// Final Lap(J)
		nes->SetRenderMethod( NES::PRE_ALL_RENDER );
	}
	if( crc == 0x3deac303 ) {	// Rolling Thunder(J)
		nes->SetRenderMethod( NES::POST_ALL_RENDER );
	}

	if( crc == 0xb1b9e187 ) {	// For Kaijuu Monogatari(J)
		nes->SetRenderMethod( NES::PRE_ALL_RENDER );
	}

	if( crc == 0x6901346e ) {	// For Sangokushi 2 - Haou no Tairiku(J)
		nes->SetRenderMethod( NES::PRE_ALL_RENDER );
	}

//	if( crc == 0xdd454208 ) {	// Hydlide 3(J)
//		nes->SetRenderMethod( NES::PRE_ALL_RENDER );
//	}

	if( crc == 0xaf15338f		// For Mindseeker(J)
	 || crc == 0xb1b9e187		// For Kaijuu Monogatari(J)
	 || crc == 0x96533999		// Dokuganryuu Masamune(J)
//	 || crc == 0x2b825ce1		// Namco Classic(J)
//	 || crc == 0x9a2b0641		// Namco Classic 2(J)
	 || crc == 0x3296ff7a		// Battle Fleet(J)
	 || crc == 0xdd454208 ) {	// Hydlide 3(J)
		exsound_enable = 0;
	}

	if( crc == 0x429fd177 ) {	// Famista '90(J)
		exsound_enable = 0;
	}

	if( exsound_enable ) {
		nes->apu->SelectExSound( 0x10 );
	}
}

BYTE	Mapper019::ReadLow( WORD addr )
{
BYTE	data = 0;

	switch( addr & 0xF800 ) {
		case	0x4800:
			if( addr == 0x4800 ) {
				if( exsound_enable ) {
					nes->apu->ExRead(addr);
					data = exram[reg[2]&0x7F];
				} else {
					data = WRAM[reg[2]&0x7F];
				}
				if( reg[2]&0x80 )
					reg[2] = (reg[2]+1)|0x80;
				return	data;
			}
			break;
		case	0x5000:
			return	(BYTE)irq_counter & 0x00FF;
		case	0x5800:
			return	(BYTE)((irq_counter>>8) & 0x7F);
		case	0x6000:
		case	0x6800:
		case	0x7000:
		case	0x7800:
			return	Mapper::ReadLow( addr );
	}

	return	(BYTE)(addr>>8);
}

void	Mapper019::WriteLow( WORD addr, BYTE data )
{
	switch( addr & 0xF800 ) {
		case	0x4800:
			if( addr == 0x4800 ) {
				if( exsound_enable ) {
					nes->apu->ExWrite( addr, data );
					exram[reg[2]&0x7F] = data;
				} else {
					WRAM[reg[2]&0x7F] = data;
				}
				if( reg[2]&0x80 )
					reg[2] = (reg[2]+1)|0x80;
			}
			break;
		case	0x5000:
			irq_counter = (irq_counter & 0xFF00) | (WORD)data;
//			if( irq_enable ) {
//				irq_counter++;
//			}
			nes->cpu->ClrIRQ( IRQ_MAPPER );
			break;
		case	0x5800:
			irq_counter = (irq_counter & 0x00FF) | ((WORD)(data & 0x7F) << 8);
			irq_enable  = data & 0x80;
//			if( irq_enable ) {
//				irq_counter++;
//			}
//			if( !irq_enable ) {
//				nes->cpu->ClrIRQ( IRQ_MAPPER );
//			}
			nes->cpu->ClrIRQ( IRQ_MAPPER );
			break;
		case	0x6000:
		case	0x6800:
		case	0x7000:
		case	0x7800:
			Mapper::WriteLow( addr, data );
			break;
	}
}

void	Mapper019::Write( WORD addr, BYTE data )
{
	switch( addr & 0xF800 ) {
		case	0x8000:
			if( (data < 0xE0) || (reg[0] != 0) ) {
				SetVROM_1K_Bank( 0, data );
			} else {
				SetCRAM_1K_Bank( 0, data&0x1F );
			}
			break;
		case	0x8800:
			if( (data < 0xE0) || (reg[0] != 0) ) {
				SetVROM_1K_Bank( 1, data );
			} else {
				SetCRAM_1K_Bank( 1, data&0x1F );
			}
			break;
		case	0x9000:
			if( (data < 0xE0) || (reg[0] != 0) ) {
				SetVROM_1K_Bank( 2, data );
			} else {
				SetCRAM_1K_Bank( 2, data&0x1F );
			}
			break;
		case	0x9800:
			if( (data < 0xE0) || (reg[0] != 0) ) {
				SetVROM_1K_Bank( 3, data );
			} else {
				SetCRAM_1K_Bank( 3, data&0x1F );
			}
			break;
		case	0xA000:
			if( (data < 0xE0) || (reg[1] != 0) ) {
				SetVROM_1K_Bank( 4, data );
			} else {
				SetCRAM_1K_Bank( 4, data&0x1F );
			}
			break;
		case	0xA800:
			if( (data < 0xE0) || (reg[1] != 0) ) {
				SetVROM_1K_Bank( 5, data );
			} else {
				SetCRAM_1K_Bank( 5, 5 );
			}
			break;
		case	0xB000:
			if( (data < 0xE0) || (reg[1] != 0) ) {
				SetVROM_1K_Bank( 6, data );
			} else {
				SetCRAM_1K_Bank( 6, data&0x1F );
			}
			break;
		case	0xB800:
			if( (data < 0xE0) || (reg[1] != 0) ) {
				SetVROM_1K_Bank( 7, data );
			} else {
				SetCRAM_1K_Bank( 7, data&0x1F );
			}
			break;
		case	0xC000:
			if( !patch ) {
				if( data <= 0xDF ) {
					SetVROM_1K_Bank( 8, data );
				} else {
					SetVRAM_1K_Bank( 8, data & 0x01 );
				}
			}
			break;
		case	0xC800:
			if( !patch ) {
				if( data <= 0xDF ) {
					SetVROM_1K_Bank( 9, data );
				} else {
					SetVRAM_1K_Bank( 9, data & 0x01 );
				}
			}
			break;
		case	0xD000:
			if( !patch ) {
				if( data <= 0xDF ) {
					SetVROM_1K_Bank( 10, data );
				} else {
					SetVRAM_1K_Bank( 10, data & 0x01 );
				}
			}
			break;
		case	0xD800:
			if( !patch ) {
				if( data <= 0xDF ) {
					SetVROM_1K_Bank( 11, data );
				} else {
					SetVRAM_1K_Bank( 11, data & 0x01 );
				}
			}
			break;
		case	0xE000:
			SetPROM_8K_Bank( 4, data & 0x3F );
			if( patch == 2 ) {
				if( data & 0x40 ) SetVRAM_Mirror( VRAM_VMIRROR );
				else		  SetVRAM_Mirror( VRAM_MIRROR4L );
			}
			break;
		case	0xE800:
			reg[0] = data & 0x40;
			reg[1] = data & 0x80;
			SetPROM_8K_Bank( 5, data & 0x3F );
			break;
		case	0xF000:
			SetPROM_8K_Bank( 6, data & 0x3F );
			break;
		case	0xF800:
			if( addr == 0xF800 ) {
				if( exsound_enable ) {
					nes->apu->ExWrite( addr, data );
				}
				reg[2] = data;
			}
			break;
	}
}

void	Mapper019::Clock( INT cycles )
{
	if( irq_enable ) {
		if( (irq_counter+=cycles) >= 0x7FFF ) {
//			irq_counter = 0x7FFF;
//			nes->cpu->IRQ_NotPending();

			irq_enable  = 0;
//			irq_counter &= 0x7FFF;
			irq_counter = 0x7FFF;
			nes->cpu->SetIRQ( IRQ_MAPPER );
		}
	}
}

void	Mapper019::SaveState( LPBYTE p )
{
	p[0] = reg[0];
	p[1] = reg[1];
	p[2] = reg[2];
	p[3] = irq_enable;
	*(WORD*)&p[4] = irq_counter;

	::memcpy( &p[8], exram, sizeof(exram) );
}

void	Mapper019::LoadState( LPBYTE p )
{
	reg[0] = p[0];
	reg[1] = p[1];
	reg[2] = p[2];
	irq_enable  = p[3];
	irq_counter = *(WORD*)&p[4];

	::memcpy( exram, &p[8], sizeof(exram) );
}
