534 lines
11 KiB
C++
534 lines
11 KiB
C++
#ifdef _NES_MAPPER_CPP_
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
// Mapper 5
|
|
void NES_mapper5::Reset()
|
|
{
|
|
wram_size = 1;
|
|
|
|
if(parent_NES->crc32() == 0x2b548d75 || // Bandit Kings of Ancient China (J)
|
|
parent_NES->crc32() == 0xf4cd4998 || // Dai Koukai Jidai (J)
|
|
parent_NES->crc32() == 0x8fa95456 || // Ishin no Arashi (J)
|
|
parent_NES->crc32() == 0x98c8e090 || // Nobunaga no Yabou - Sengoku Gunyuu Den (J)
|
|
parent_NES->crc32() == 0x57e3218b || // L'Empereur (J)
|
|
parent_NES->crc32() == 0x2f50bd38 || // L'Empereur (U)
|
|
parent_NES->crc32() == 0x8e9a5e2f || // L'Empereur (Alt)(U)
|
|
parent_NES->crc32() == 0xb56958d1 || // Nobunaga's Ambition 2 (J)
|
|
parent_NES->crc32() == 0xe6c28c5f || // Suikoden - Tenmei no Chikai (J)
|
|
parent_NES->crc32() == 0xcd35e2e9) // Uncharted Waters (J)
|
|
{
|
|
wram_size = 2;
|
|
}
|
|
|
|
if(parent_NES->crc32() == 0xf4120e58 || // Aoki Ookami to Shiroki Mejika - Genchou Hishi (J)
|
|
parent_NES->crc32() == 0x286613d8 || // Nobunaga no Yabou - Bushou Fuuun Roku (J)
|
|
parent_NES->crc32() == 0x11eaad26 || // Romance of the 3 Kingdoms 2 (J)
|
|
parent_NES->crc32() == 0x95ba5733) // Sangokushi 2 (J)
|
|
{
|
|
wram_size = 3;
|
|
}
|
|
|
|
// set SaveRAM
|
|
for(uint32 i = 0; i < 0x10000; i++)
|
|
{
|
|
wram[i] = parent_NES->ReadSaveRAM(i);
|
|
}
|
|
MMC5_set_WRAM_bank(3,0);
|
|
|
|
// Init ExSound
|
|
parent_NES->apu->SelectExSound(8);
|
|
|
|
// set CPU bank pointers
|
|
set_CPU_bank4(num_8k_ROM_banks-1);
|
|
set_CPU_bank5(num_8k_ROM_banks-1);
|
|
set_CPU_bank6(num_8k_ROM_banks-1);
|
|
set_CPU_bank7(num_8k_ROM_banks-1);
|
|
|
|
// set PPU bank pointers
|
|
set_PPU_banks(0,1,2,3,4,5,6,7);
|
|
|
|
for(i = 0; i < 8; i++)
|
|
{
|
|
chr_reg[i][0] = i;
|
|
chr_reg[i][1] = (i & 0x03) + 4;
|
|
}
|
|
wb[3] = 0;
|
|
wb[4] = wb[5] = wb[6] = 8;
|
|
|
|
prg_size = 3;
|
|
wram_protect0 = 0x02;
|
|
wram_protect1 = 0x01;
|
|
chr_size = 3;
|
|
gfx_mode = 0;
|
|
|
|
irq_enabled = 0;
|
|
irq_status = 0;
|
|
irq_line = 0;
|
|
|
|
split_control = 0;
|
|
split_bank = 0;
|
|
}
|
|
|
|
uint8 NES_mapper5::MemoryReadLow(uint32 addr)
|
|
{
|
|
uint8 ret = (uint8)(addr >> 8);
|
|
if(addr == 0x5204)
|
|
{
|
|
ret = irq_status;
|
|
irq_status &= ~0x80;
|
|
}
|
|
else if(addr == 0x5205)
|
|
{
|
|
ret = (uint8)((value0*value1) & 0x00FF);
|
|
}
|
|
else if(addr == 0x5206)
|
|
{
|
|
ret = (uint8)(((value0*value1) & 0xFF00) >> 8);
|
|
}
|
|
else if(addr >= 0x5C00 && addr <=0x5FFF)
|
|
{
|
|
if(gfx_mode == 2 || gfx_mode == 3)
|
|
{
|
|
uint8* nametable2 = parent_NES->ppu->get_namt() + 0x800;
|
|
ret = nametable2[addr & 0x3FF];
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void NES_mapper5::MemoryWriteLow(uint32 addr, uint8 data)
|
|
{
|
|
uint32 i;
|
|
|
|
switch(addr)
|
|
{
|
|
case 0x5100:
|
|
{
|
|
prg_size = data & 0x03;
|
|
}
|
|
break;
|
|
|
|
case 0x5101:
|
|
{
|
|
chr_size = data & 0x03;
|
|
}
|
|
break;
|
|
|
|
case 0x5102:
|
|
{
|
|
wram_protect0 = data & 0x03;
|
|
}
|
|
break;
|
|
|
|
case 0x5103:
|
|
{
|
|
wram_protect1 = data & 0x03;
|
|
}
|
|
break;
|
|
|
|
case 0x5104:
|
|
{
|
|
gfx_mode = data & 0x03;
|
|
}
|
|
break;
|
|
|
|
case 0x5105:
|
|
{
|
|
for(i = 0; i < 4; i++)
|
|
{
|
|
set_VRAM_bank(8+i, data & 0x03);
|
|
data >>= 2;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0x5106:
|
|
{
|
|
uint8* nametable3 = parent_NES->ppu->get_namt() + 0xC00;
|
|
for(i = 0; i < 0x3C0; i++)
|
|
{
|
|
nametable3[i] = data;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0x5107:
|
|
{
|
|
uint8* nametable3 = parent_NES->ppu->get_namt() + 0xC00;
|
|
data &= 0x03;
|
|
data = data | (data<<2) | (data<<4) | (data<<6);
|
|
for(i = 0x3C0; i < 0x400; i++)
|
|
{
|
|
nametable3[i] = data;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0x5113:
|
|
{
|
|
MMC5_set_WRAM_bank(3, data & 0x07);
|
|
}
|
|
break;
|
|
|
|
case 0x5114:
|
|
case 0x5115:
|
|
case 0x5116:
|
|
case 0x5117:
|
|
{
|
|
MMC5_set_CPU_bank(addr & 0x07, data);
|
|
}
|
|
break;
|
|
|
|
case 0x5120:
|
|
case 0x5121:
|
|
case 0x5122:
|
|
case 0x5123:
|
|
case 0x5124:
|
|
case 0x5125:
|
|
case 0x5126:
|
|
case 0x5127:
|
|
{
|
|
chr_reg[addr & 0x07][0] = data;
|
|
sync_Chr_banks(0);
|
|
}
|
|
break;
|
|
|
|
case 0x5128:
|
|
case 0x5129:
|
|
case 0x512A:
|
|
case 0x512B:
|
|
{
|
|
chr_reg[(addr & 0x03) + 0][1] = data;
|
|
chr_reg[(addr & 0x03) + 4][1] = data;
|
|
}
|
|
break;
|
|
|
|
case 0x5200:
|
|
{
|
|
split_control = data;
|
|
}
|
|
break;
|
|
|
|
case 0x5201:
|
|
{
|
|
//split_scroll = data;
|
|
}
|
|
break;
|
|
|
|
case 0x5202:
|
|
{
|
|
split_bank = data & 0x3F;
|
|
}
|
|
break;
|
|
|
|
case 0x5203:
|
|
{
|
|
irq_line = data;
|
|
}
|
|
break;
|
|
|
|
case 0x5204:
|
|
{
|
|
irq_enabled = data;
|
|
}
|
|
break;
|
|
|
|
case 0x5205:
|
|
{
|
|
value0 = data;
|
|
}
|
|
break;
|
|
|
|
case 0x5206:
|
|
{
|
|
value1 = data;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
if(addr >= 0x5000 && addr <= 0x5015)
|
|
{
|
|
parent_NES->apu->ExWrite(addr, data);
|
|
}
|
|
else if(addr >= 0x5C00 && addr <= 0x5FFF)
|
|
{
|
|
if(gfx_mode != 3)
|
|
{
|
|
uint8* nametable2 = parent_NES->ppu->get_namt() + 0x800;
|
|
nametable2[addr & 0x3FF] = data; //(irq_status & 0) ? data : 0x40;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void NES_mapper5::MemoryWriteSaveRAM(uint32 addr, uint8 data)
|
|
{
|
|
if(wram_protect0 == 0x02 && wram_protect1 == 0x01)
|
|
{
|
|
if(wb[3] != 8)
|
|
{
|
|
wram[wb[3]*0x2000+(addr&0x1FFF)] = data;
|
|
parent_NES->WriteSaveRAM(wb[3]*0x2000+(addr&0x1FFF), data);
|
|
}
|
|
}
|
|
parent_NES->WriteSaveRAM(addr&0x1FFF, wram[addr&0x1FFF]);
|
|
}
|
|
|
|
void NES_mapper5::MemoryWrite(uint32 addr, uint8 data)
|
|
{
|
|
if(wram_protect0 == 0x02 && wram_protect1 == 0x01)
|
|
{
|
|
if(addr >= 0x8000 && addr <= 0x9FFF)
|
|
{
|
|
if(wb[4] != 8)
|
|
{
|
|
wram[wb[4]*0x2000+(addr&0x1FFF)] = data;
|
|
parent_NES->WriteSaveRAM(wb[4]*0x2000+(addr&0x1FFF), data);
|
|
}
|
|
}
|
|
else if(addr >= 0xA000 && addr <= 0xBFFF)
|
|
{
|
|
if(wb[5] != 8)
|
|
{
|
|
wram[wb[5]*0x2000+(addr&0x1FFF)] = data;
|
|
parent_NES->WriteSaveRAM(wb[5]*0x2000+(addr&0x1FFF), data);
|
|
}
|
|
}
|
|
else if(addr >= 0xC000 && addr <= 0xDFFF)
|
|
{
|
|
if(wb[6] != 8)
|
|
{
|
|
wram[wb[6]*0x2000+(addr&0x1FFF)] = data;
|
|
parent_NES->WriteSaveRAM(wb[6]*0x2000+(addr&0x1FFF), data);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void NES_mapper5::HSync(uint32 scanline)
|
|
{
|
|
if(scanline <= 240)
|
|
{
|
|
if(scanline == irq_line)
|
|
{
|
|
if(parent_NES->ppu->spr_enabled() && parent_NES->ppu->bg_enabled())
|
|
{
|
|
irq_status |= 0x80;
|
|
}
|
|
}
|
|
if((irq_status & 0x80) && (irq_enabled & 0x80))
|
|
{
|
|
parent_NES->cpu->DoIRQ();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
irq_status |= 0x40;
|
|
}
|
|
}
|
|
|
|
void NES_mapper5::MMC5_set_CPU_bank(uint8 page, uint8 bank)
|
|
{
|
|
if(bank & 0x80)
|
|
{
|
|
if(prg_size == 0)
|
|
{
|
|
if(page == 7)
|
|
{
|
|
set_CPU_bank4((bank & 0x7C)+0);
|
|
set_CPU_bank5((bank & 0x7C)+1);
|
|
set_CPU_bank6((bank & 0x7C)+2);
|
|
set_CPU_bank7((bank & 0x7C)+3);
|
|
wb[4] = wb[5] = wb[6] = 8;
|
|
}
|
|
}
|
|
if(prg_size == 1)
|
|
{
|
|
if(page == 5)
|
|
{
|
|
set_CPU_bank4((bank & 0x7E)+0);
|
|
set_CPU_bank5((bank & 0x7E)+1);
|
|
wb[4] = wb[5] = 8;
|
|
}
|
|
if(page == 7)
|
|
{
|
|
set_CPU_bank6((bank & 0x7E)+0);
|
|
set_CPU_bank7((bank & 0x7E)+1);
|
|
wb[6] = 8;
|
|
}
|
|
}
|
|
if(prg_size == 2)
|
|
{
|
|
if(page == 5)
|
|
{
|
|
set_CPU_bank4((bank & 0x7E)+0);
|
|
set_CPU_bank5((bank & 0x7E)+1);
|
|
wb[4] = wb[5] = 8;
|
|
}
|
|
if(page == 6)
|
|
{
|
|
set_CPU_bank6(bank & 0x7F);
|
|
wb[6] = 8;
|
|
}
|
|
if(page == 7)
|
|
{
|
|
set_CPU_bank7(bank & 0x7F);
|
|
}
|
|
}
|
|
if(prg_size == 3)
|
|
{
|
|
if(page == 4)
|
|
{
|
|
set_CPU_bank4(bank & 0x7F);
|
|
wb[4] = 8;
|
|
}
|
|
if(page == 5)
|
|
{
|
|
set_CPU_bank5(bank & 0x7F);
|
|
wb[5] = 8;
|
|
}
|
|
if(page == 6)
|
|
{
|
|
set_CPU_bank6(bank & 0x7F);
|
|
wb[6] = 8;
|
|
}
|
|
if(page == 7)
|
|
{
|
|
set_CPU_bank7(bank & 0x7F);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(prg_size == 1)
|
|
{
|
|
if(page == 5)
|
|
{
|
|
MMC5_set_WRAM_bank(4, (bank & 0x06)+0);
|
|
MMC5_set_WRAM_bank(5, (bank & 0x06)+1);
|
|
}
|
|
}
|
|
if(prg_size == 2)
|
|
{
|
|
if(page == 5)
|
|
{
|
|
MMC5_set_WRAM_bank(4, (bank & 0x06)+0);
|
|
MMC5_set_WRAM_bank(5, (bank & 0x06)+1);
|
|
}
|
|
if(page == 6)
|
|
{
|
|
MMC5_set_WRAM_bank(6, bank & 0x07);
|
|
}
|
|
}
|
|
if(prg_size == 3)
|
|
{
|
|
if(page == 4)
|
|
{
|
|
MMC5_set_WRAM_bank(4, bank & 0x07);
|
|
}
|
|
if(page == 5)
|
|
{
|
|
MMC5_set_WRAM_bank(5, bank & 0x07);
|
|
}
|
|
if(page == 6)
|
|
{
|
|
MMC5_set_WRAM_bank(6, bank & 0x07);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void NES_mapper5::MMC5_set_WRAM_bank(uint8 page, uint8 bank)
|
|
{
|
|
if(bank != 8)
|
|
{
|
|
if(wram_size == 1) bank = (bank > 3) ? 8 : 0;
|
|
if(wram_size == 2) bank = (bank > 3) ? 1 : 0;
|
|
if(wram_size == 3) bank = (bank > 3) ? 8 : bank;
|
|
if(wram_size == 4) bank = (bank > 3) ? 4 : bank;
|
|
}
|
|
wb[page] = bank;
|
|
|
|
if(bank != 8)
|
|
{
|
|
NES_6502::Context context;
|
|
parent_NES->cpu->GetContext(&context);
|
|
context.mem_page[page] = wram + bank*0x2000;
|
|
parent_NES->cpu->SetContext(&context);
|
|
}
|
|
}
|
|
|
|
uint8 NES_mapper5::PPU_Latch_RenderScreen(uint8 mode, uint32 addr)
|
|
{
|
|
uint8 ex_pal = 0;
|
|
|
|
if(gfx_mode == 1 && mode == 1)
|
|
{
|
|
// ex gfx mode
|
|
uint8* nametable2 = parent_NES->ppu->get_namt() + 0x800;
|
|
uint32 bank = (nametable2[addr] & 0x3F) << 2;
|
|
set_PPU_banks(bank,bank+1,bank+2,bank+3,bank,bank+1,bank+2,bank+3);
|
|
ex_pal = ((nametable2[addr] & 0xC0) >> 4) | 0x01;
|
|
}
|
|
else
|
|
{
|
|
// normal
|
|
sync_Chr_banks(mode);
|
|
}
|
|
return ex_pal;
|
|
}
|
|
|
|
void NES_mapper5::sync_Chr_banks(uint8 mode)
|
|
{
|
|
if(chr_size == 0)
|
|
{
|
|
set_PPU_bank0(chr_reg[7][mode]*8+0);
|
|
set_PPU_bank1(chr_reg[7][mode]*8+1);
|
|
set_PPU_bank2(chr_reg[7][mode]*8+2);
|
|
set_PPU_bank3(chr_reg[7][mode]*8+3);
|
|
set_PPU_bank4(chr_reg[7][mode]*8+4);
|
|
set_PPU_bank5(chr_reg[7][mode]*8+5);
|
|
set_PPU_bank6(chr_reg[7][mode]*8+6);
|
|
set_PPU_bank7(chr_reg[7][mode]*8+7);
|
|
}
|
|
else if(chr_size == 1)
|
|
{
|
|
set_PPU_bank0(chr_reg[3][mode]*4+0);
|
|
set_PPU_bank1(chr_reg[3][mode]*4+1);
|
|
set_PPU_bank2(chr_reg[3][mode]*4+2);
|
|
set_PPU_bank3(chr_reg[3][mode]*4+3);
|
|
set_PPU_bank4(chr_reg[7][mode]*4+0);
|
|
set_PPU_bank5(chr_reg[7][mode]*4+1);
|
|
set_PPU_bank6(chr_reg[7][mode]*4+2);
|
|
set_PPU_bank7(chr_reg[7][mode]*4+3);
|
|
}
|
|
else if(chr_size == 2)
|
|
{
|
|
set_PPU_bank0(chr_reg[1][mode]*2+0);
|
|
set_PPU_bank1(chr_reg[1][mode]*2+1);
|
|
set_PPU_bank2(chr_reg[3][mode]*2+0);
|
|
set_PPU_bank3(chr_reg[3][mode]*2+1);
|
|
set_PPU_bank4(chr_reg[5][mode]*2+0);
|
|
set_PPU_bank5(chr_reg[5][mode]*2+1);
|
|
set_PPU_bank6(chr_reg[7][mode]*2+0);
|
|
set_PPU_bank7(chr_reg[7][mode]*2+1);
|
|
}
|
|
else
|
|
{
|
|
set_PPU_bank0(chr_reg[0][mode]);
|
|
set_PPU_bank1(chr_reg[1][mode]);
|
|
set_PPU_bank2(chr_reg[2][mode]);
|
|
set_PPU_bank3(chr_reg[3][mode]);
|
|
set_PPU_bank4(chr_reg[4][mode]);
|
|
set_PPU_bank5(chr_reg[5][mode]);
|
|
set_PPU_bank6(chr_reg[6][mode]);
|
|
set_PPU_bank7(chr_reg[7][mode]);
|
|
}
|
|
}
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
#endif
|