//////////////////////////////////////////////////////////////////////////
// Mapper090  PC-JY-??                                                  //
//////////////////////////////////////////////////////////////////////////
void	Mapper090::Reset()
{
	SetPROM_32K_Bank( PROM_8K_SIZE-4, PROM_8K_SIZE-3, PROM_8K_SIZE-2, PROM_8K_SIZE-1 );
	SetVROM_8K_Bank( 0 );

	patch = 0;

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

	if( crc == 0x2a268152 ) {
		patch = 1;
	}
	if( crc == 0x2224b882 ) {
		nes->SetRenderMethod( NES::TILE_RENDER );
	}

	irq_enable = 0;	// Disable
	irq_counter = 0;
	irq_latch = 0;
	irq_occur = 0;
	irq_preset = 0;
	irq_offset = 0;

	prg_6000 = 0;
	prg_E000 = 0;
	prg_size = 0;
	chr_size = 0;
	mir_mode = 0;
	mir_type = 0;

	key_val = 0;
	mul_val1 = mul_val2 = 0;

	for( INT i = 0; i < 4; i++ ) {
		prg_reg[i] = PROM_8K_SIZE-4+i;
		ntl_reg[i] = 0;
		nth_reg[i] = 0;
		chl_reg[i] = i;
		chh_reg[i] = 0;
		chl_reg[i+4] = i+4;
		chh_reg[i+4] = 0;
	}

	if( sw_val )
		sw_val = 0x00;
	else
		sw_val = 0xFF;

//	nes->SetRenderMethod( NES::PRE_ALL_RENDER );
}

BYTE	Mapper090::ReadLow( WORD addr )
{
DEBUGOUT( "RD:%04X\n", addr );

	switch( addr ) {
		case	0x5000:
			return	sw_val?0x00:0xFF;
		case	0x5800:
			return	(BYTE)(mul_val1*mul_val2);
		case	0x5801:
			return	(BYTE)((mul_val1*mul_val2)>>8);
		case	0x5803:
			return	key_val;
	}

	if( addr >= 0x6000 ) {
		return	Mapper::ReadLow( addr );
	}

//	return	sw_val?0x00:0xFF;
	return	(BYTE)(addr>>8);
}

void	Mapper090::WriteLow( WORD addr, BYTE data )
{
DEBUGOUT( "WR:%04X %02X\n", addr, data );

	if( addr == 0x5800 ) {
		mul_val1 = data;
	} else
	if( addr == 0x5801 ) {
		mul_val2 = data;
	} else
	if( addr == 0x5803 ) {
		key_val = data;
	}
}

void	Mapper090::Write( WORD addr, BYTE data )
{
	switch( addr & 0xF007 ) {
		case	0x8000:
		case	0x8001:
		case	0x8002:
		case	0x8003:
			prg_reg[addr&3] = data;
			SetBank_CPU();
			break;

		case	0x9000:
		case	0x9001:
		case	0x9002:
		case	0x9003:
		case	0x9004:
		case	0x9005:
		case	0x9006:
		case	0x9007:
			chl_reg[addr&7] = data;
			SetBank_PPU();
			break;

		case	0xA000:
		case	0xA001:
		case	0xA002:
		case	0xA003:
		case	0xA004:
		case	0xA005:
		case	0xA006:
		case	0xA007:
			chh_reg[addr&7] = data;
			SetBank_PPU();
			break;

		case	0xB000:
		case	0xB001:
		case	0xB002:
		case	0xB003:
			ntl_reg[addr&3] = data;
			SetBank_VRAM();
			break;

		case	0xB004:
		case	0xB005:
		case	0xB006:
		case	0xB007:
			nth_reg[addr&3] = data;
			SetBank_VRAM();
			break;

		case	0xC002:
			irq_enable = 0;
			irq_occur = 0;
			nes->cpu->ClrIRQ( IRQ_MAPPER );
			break;
		case	0xC003:
			irq_enable = 0xFF;
			irq_preset = 0xFF;
			break;
		case	0xC004:
			break;
		case	0xC005:
			if( irq_offset & 0x80 ) {
				irq_latch = data ^ (irq_offset | 1);
			} else {
				irq_latch = data | (irq_offset&0x27);
			}
			irq_preset = 0xFF;
			break;
		case	0xC006:
			if( patch ) {
				irq_offset = data;
			}
			break;

		case	0xD000:
			prg_6000 = data & 0x80;
			prg_E000 = data & 0x04;
			prg_size = data & 0x03;
			chr_size = (data & 0x18)>>3;
			mir_mode = data & 0x20;
			SetBank_CPU();
			SetBank_PPU();
			SetBank_VRAM();
			break;

		case	0xD001:
			mir_type = data & 0x03;
			SetBank_VRAM();
			break;

		case	0xD003:
			break;
	}
}

void	Mapper090::HSync( INT scanline )
{
	if( (scanline >= 0 && scanline <= 239) ) {
		if( nes->ppu->IsDispON() ) {
			if( irq_preset ) {
				irq_counter = irq_latch;
				irq_preset = 0;
			}
			if( irq_counter ) {
				irq_counter--;
			}
			if( !irq_counter ) {
				if( irq_enable ) {
//					irq_occur = 0xFF;
					nes->cpu->SetIRQ( IRQ_MAPPER );
				}
			}
		}
	}
}

void	Mapper090::Clock(INT cycles)
{
//	if( irq_occur ) {
//		nes->cpu->IRQ_NotPending();
//	}
}

void	Mapper090::SetBank_CPU()
{
	if( prg_size == 0 ) {
		SetPROM_32K_Bank( PROM_8K_SIZE-4, PROM_8K_SIZE-3, PROM_8K_SIZE-2, PROM_8K_SIZE-1 );
	} else
	if( prg_size == 1 ) {
		SetPROM_32K_Bank( prg_reg[1]*2, prg_reg[1]*2+1, PROM_8K_SIZE-2, PROM_8K_SIZE-1 );
	} else
	if( prg_size == 2 ) {
		if( prg_E000 ) {
			SetPROM_32K_Bank( prg_reg[0], prg_reg[1], prg_reg[2], prg_reg[3] );
		} else {
			if( prg_6000 ) {
				SetPROM_8K_Bank( 3, prg_reg[3] );
			}
			SetPROM_32K_Bank( prg_reg[0], prg_reg[1], prg_reg[2], PROM_8K_SIZE-1 );
		}
	} else {
		SetPROM_32K_Bank( prg_reg[3], prg_reg[2], prg_reg[1], prg_reg[0] );
	}
}

void	Mapper090::SetBank_PPU()
{
INT	bank[8];

	for( INT i = 0; i < 8; i++ ) {
		bank[i] = ((INT)chh_reg[i]<<8)|((INT)chl_reg[i]);
	}

	if( chr_size == 0 ) {
		SetVROM_8K_Bank( bank[0] );
	} else
	if( chr_size == 1 ) {
		SetVROM_4K_Bank( 0, bank[0] );
		SetVROM_4K_Bank( 4, bank[4] );
	} else
	if( chr_size == 2 ) {
		SetVROM_2K_Bank( 0, bank[0] );
		SetVROM_2K_Bank( 2, bank[2] );
		SetVROM_2K_Bank( 4, bank[4] );
		SetVROM_2K_Bank( 6, bank[6] );
	} else {
		SetVROM_8K_Bank( bank[0], bank[1], bank[2], bank[3], bank[4], bank[5], bank[6], bank[7] );
	}
}

void	Mapper090::SetBank_VRAM()
{
INT	bank[4];

	for( INT i = 0; i < 4; i++ ) {
		bank[i] = ((INT)nth_reg[i]<<8)|((INT)ntl_reg[i]);
	}

	if( !patch && mir_mode ) {
		for( INT i = 0; i < 4; i++ ) {
			if( !nth_reg[i] && (ntl_reg[i] == (BYTE)i) ) {
				mir_mode = 0;
			}
		}

		if( mir_mode ) {
			SetVROM_1K_Bank(  8, bank[0] );
			SetVROM_1K_Bank(  9, bank[1] );
			SetVROM_1K_Bank( 10, bank[2] );
			SetVROM_1K_Bank( 11, bank[3] );
		}
	} else {
		if( mir_type == 0 ) {
			SetVRAM_Mirror( VRAM_VMIRROR );
		} else
		if( mir_type == 1 ) {
			SetVRAM_Mirror( VRAM_HMIRROR );
		} else {
			SetVRAM_Mirror( VRAM_MIRROR4L );
		}
	}
}

void	Mapper090::SaveState( LPBYTE p )
{
INT	i;

	for( i = 0; i < 4; i++ ) {
		p[i] = prg_reg[i];
	}
	for( i = 0; i < 8; i++ ) {
		p[i+ 4] = chh_reg[i];
	}
	for( i = 0; i < 8; i++ ) {
		p[i+12] = chl_reg[i];
	}
	for( i = 0; i < 4; i++ ) {
		p[i+20] = nth_reg[i];
	}
	for( i = 0; i < 4; i++ ) {
		p[i+24] = ntl_reg[i];
	}
	p[28] = irq_enable;
	p[29] = irq_counter;
	p[30] = irq_latch;
	p[31] = prg_6000;
	p[32] = prg_E000;
	p[33] = prg_size;
	p[34] = chr_size;
	p[35] = mir_mode;
	p[36] = mir_type;
	p[37] = mul_val1;
	p[38] = mul_val2;
	p[39] = key_val;
	p[40] = irq_occur;
	p[41] = irq_preset;
	p[42] = irq_offset;
}

void	Mapper090::LoadState( LPBYTE p )
{
INT	i;

	for( i = 0; i < 4; i++ ) {
		prg_reg[i] = p[i];
	}
	for( i = 0; i < 8; i++ ) {
		chh_reg[i] = p[i+ 4];
	}
	for( i = 0; i < 8; i++ ) {
		chl_reg[i] = p[i+12];
	}
	for( i = 0; i < 4; i++ ) {
		nth_reg[i] = p[i+20];
	}
	for( i = 0; i < 4; i++ ) {
		ntl_reg[i] = p[i+24];
	}
	irq_enable  = p[28];
	irq_counter = p[29];
	irq_latch   = p[30];
	prg_6000    = p[31];
	prg_E000    = p[32];
	prg_size    = p[33];
	chr_size    = p[34];
	mir_mode    = p[35];
	mir_type    = p[36];
	mul_val1    = p[37];
	mul_val2    = p[38];
	key_val     = p[39];
	irq_occur   = p[40];
	irq_preset  = p[41];
	irq_offset  = p[42];
}
