AxibugEmuOnline/References/VirtuaNESex_src_191105/NES/Mapper/Mapper005.cpp
2024-08-05 17:58:53 +08:00

673 lines
15 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//////////////////////////////////////////////////////////////////////////
// Mapper005 Nintendo MMC5 //
//////////////////////////////////////////////////////////////////////////
#define MMC5_IRQ_METAL (1<<0)
void Mapper005::Reset()
{
INT i;
prg_size = 3;
chr_size = 3;
sram_we_a = 0x00;
sram_we_b = 0x00;
graphic_mode = 0;
nametable_mode = 0;
for( i = 0; i < 4; i++ ) {
nametable_type[i] = 0;
}
fill_chr = fill_pal = 0;
split_control = split_scroll = split_page = 0;
irq_enable = 0;
irq_status = 0;
irq_scanline = 0;
irq_line = 0;
irq_clear = 0;
irq_type = 0;
mult_a = mult_b = 0;
chr_type = 0;
chr_mode = 0;
for( i = 0; i < 8; i++ ) {
chr_page[0][i] = i;
chr_page[1][i] = 4+(i&0x03);
}
SetPROM_32K_Bank( PROM_8K_SIZE-1, PROM_8K_SIZE-1, PROM_8K_SIZE-1, PROM_8K_SIZE-1 );
SetVROM_8K_Bank( 0 );
for( i = 0; i < 8; i++ ) {
BG_MEM_BANK[i] = VROM+0x0400*i;
BG_MEM_PAGE[i] = i;
}
// SRAM<41>Ýè
SetBank_SRAM( 3, 0 );
sram_size = 0;
nes->SetSAVERAM_SIZE( 16*1024 );
DWORD crc = nes->rom->GetPROM_CRC();
if( crc == 0x2b548d75 // Bandit Kings of Ancient China(U)
|| crc == 0xf4cd4998 // Dai Koukai Jidai(J)
|| crc == 0x8fa95456 // Ishin no Arashi(J)
|| crc == 0x98c8e090 // Nobunaga no Yabou - Sengoku Gunyuu Den(J)
|| crc == 0x8e9a5e2f // L'Empereur(Alt)(U)
|| crc == 0x57e3218b // L'Empereur(U)
|| crc == 0x2f50bd38 // L'Empereur(J)
|| crc == 0xb56958d1 // Nobunaga's Ambition 2(U)
|| crc == 0xe6c28c5f // Suikoden - Tenmei no Chikai(J)
|| crc == 0xcd35e2e9 ) { // Uncharted Waters(U)
sram_size = 1;
nes->SetSAVERAM_SIZE( 32*1024 );
} else
if( crc == 0xf4120e58 // Aoki Ookami to Shiroki Mejika - Genchou Hishi(J)
|| crc == 0x286613d8 // Nobunaga no Yabou - Bushou Fuuun Roku(J)
|| crc == 0x11eaad26 // Romance of the Three Kingdoms 2(U)
|| crc == 0x95ba5733 ) { // Sangokushi 2(J)
sram_size = 2;
nes->SetSAVERAM_SIZE( 64*1024 );
}
if( crc == 0x95ca9ec7 ) { // Castlevania 3 - Dracula's Curse(U)
nes->SetRenderMethod( NES::TILE_RENDER );
}
if( crc == 0xcd9acf43 ) { // Metal Slader Glory(J)
irq_type = MMC5_IRQ_METAL;
}
if( crc == 0xe91548d8 ) { // Shin 4 Nin Uchi Mahjong - Yakuman Tengoku(J)
chr_type = 1;
}
nes->ppu->SetExtLatchMode( TRUE );
nes->apu->SelectExSound( 8 );
}
BYTE Mapper005::ReadLow( WORD addr )
{
BYTE data = (BYTE)(addr>>8);
switch( addr ) {
case 0x5015:
data = nes->apu->ExRead( addr );
break;
case 0x5204:
data = irq_status;
// irq_status = 0;
irq_status &= ~0x80;
nes->cpu->ClrIRQ( IRQ_MAPPER );
break;
case 0x5205:
data = mult_a*mult_b;
break;
case 0x5206:
data = (BYTE)(((WORD)mult_a*(WORD)mult_b)>>8);
break;
}
if( addr >= 0x5C00 && addr <= 0x5FFF ) {
if( graphic_mode >= 2 ) { // ExRAM mode
data = VRAM[0x0800+(addr&0x3FF)];
}
} else if( addr >= 0x6000 && addr <= 0x7FFF ) {
data = Mapper::ReadLow( addr );
}
return data;
}
void Mapper005::WriteLow( WORD addr, BYTE data )
{
INT i;
#if 0
if( addr >= 0x5000 && addr <=0x5100 ) {
DEBUGOUT( "$%04X=%02X C:%10d\n", addr, data, nes->cpu->GetTotalCycles() );
}
#endif
switch( addr ) {
case 0x5100:
prg_size = data & 0x03;
break;
case 0x5101:
chr_size = data & 0x03;
break;
case 0x5102:
sram_we_a = data & 0x03;
break;
case 0x5103:
sram_we_b = data & 0x03;
break;
case 0x5104:
graphic_mode = data & 0x03;
break;
case 0x5105:
nametable_mode = data;
for( i = 0; i < 4; i++ ) {
nametable_type[i] = data&0x03;
SetVRAM_1K_Bank( 8+i, nametable_type[i] );
data >>= 2;
}
break;
case 0x5106:
fill_chr = data;
break;
case 0x5107:
fill_pal = data & 0x03;
break;
case 0x5113:
SetBank_SRAM( 3, data&0x07 );
break;
case 0x5114:
case 0x5115:
case 0x5116:
case 0x5117:
SetBank_CPU( addr, data );
break;
case 0x5120:
case 0x5121:
case 0x5122:
case 0x5123:
case 0x5124:
case 0x5125:
case 0x5126:
case 0x5127:
chr_mode = 0;
chr_page[0][addr&0x07] = data;
SetBank_PPU();
break;
case 0x5128:
case 0x5129:
case 0x512A:
case 0x512B:
chr_mode = 1;
chr_page[1][(addr&0x03)+0] = data;
chr_page[1][(addr&0x03)+4] = data;
SetBank_PPU();
break;
case 0x5200:
split_control = data;
break;
case 0x5201:
split_scroll = data;
break;
case 0x5202:
split_page = data&0x3F;
break;
case 0x5203:
irq_line = data;
nes->cpu->ClrIRQ( IRQ_MAPPER );
break;
case 0x5204:
irq_enable = data;
nes->cpu->ClrIRQ( IRQ_MAPPER );
break;
case 0x5205:
mult_a = data;
break;
case 0x5206:
mult_b = data;
break;
default:
if( addr >= 0x5000 && addr <= 0x5015 ) {
nes->apu->ExWrite( addr, data );
} else if( addr >= 0x5C00 && addr <= 0x5FFF ) {
if( graphic_mode == 2 ) { // ExRAM
VRAM[0x0800+(addr&0x3FF)] = data;
} else if( graphic_mode != 3 ) { // Split,ExGraphic
if( irq_status&0x40 ) {
VRAM[0x0800+(addr&0x3FF)] = data;
} else {
VRAM[0x0800+(addr&0x3FF)] = 0;
}
}
} else if( addr >= 0x6000 && addr <= 0x7FFF ) {
if( sram_we_a == 0x02 && sram_we_b == 0x01 ) {
if( CPU_MEM_TYPE[3] == BANKTYPE_RAM ) {
CPU_MEM_BANK[3][addr&0x1FFF] = data;
}
}
}
break;
}
}
void Mapper005::Write( WORD addr, BYTE data )
{
if( sram_we_a == 0x02 && sram_we_b == 0x01 ) {
if( addr >= 0x8000 && addr < 0xE000 ) {
if( CPU_MEM_TYPE[addr>>13] == BANKTYPE_RAM ) {
CPU_MEM_BANK[addr>>13][addr&0x1FFF] = data;
}
}
}
}
void Mapper005::SetBank_CPU( WORD addr, BYTE data )
{
if( data & 0x80 ) {
// PROM Bank
switch( addr & 7 ) {
case 4:
if( prg_size == 3 ) {
SetPROM_8K_Bank( 4, data&0x7F );
}
break;
case 5:
if( prg_size == 1 || prg_size == 2 ) {
SetPROM_16K_Bank( 4, (data&0x7F)>>1 );
} else if( prg_size == 3 ) {
SetPROM_8K_Bank( 5, (data&0x7F) );
}
break;
case 6:
if( prg_size == 2 || prg_size == 3 ) {
SetPROM_8K_Bank( 6, (data&0x7F) );
}
break;
case 7:
if( prg_size == 0 ) {
SetPROM_32K_Bank( (data&0x7F)>>2 );
} else if( prg_size == 1 ) {
SetPROM_16K_Bank( 6, (data&0x7F)>>1 );
} else if( prg_size == 2 || prg_size == 3 ) {
SetPROM_8K_Bank( 7, (data&0x7F) );
}
break;
}
} else {
// WRAM Bank
switch( addr & 7 ) {
case 4:
if( prg_size == 3 ) {
SetBank_SRAM( 4, data&0x07 );
}
break;
case 5:
if( prg_size == 1 || prg_size == 2 ) {
SetBank_SRAM( 4, (data&0x06)+0 );
SetBank_SRAM( 5, (data&0x06)+1 );
} else if( prg_size == 3 ) {
SetBank_SRAM( 5, data&0x07 );
}
break;
case 6:
if( prg_size == 2 || prg_size == 3 ) {
SetBank_SRAM( 6, data&0x07 );
}
break;
}
}
}
void Mapper005::SetBank_SRAM( BYTE page, BYTE data )
{
if( sram_size == 0 ) data = (data > 3) ? 8 : 0;
if( sram_size == 1 ) data = (data > 3) ? 1 : 0;
if( sram_size == 2 ) data = (data > 3) ? 8 : data;
if( sram_size == 3 ) data = (data > 3) ? 4 : data;
if( data != 8 ) {
SetPROM_Bank( page, &WRAM[0x2000*data], BANKTYPE_RAM );
CPU_MEM_PAGE[page] = data;
} else {
CPU_MEM_TYPE[page] = BANKTYPE_ROM;
}
}
void Mapper005::SetBank_PPU()
{
INT i;
if( chr_mode == 0 ) {
// PPU SP Bank
switch( chr_size ) {
case 0:
SetVROM_8K_Bank( chr_page[0][7] );
break;
case 1:
SetVROM_4K_Bank( 0, chr_page[0][3] );
SetVROM_4K_Bank( 4, chr_page[0][7] );
break;
case 2:
SetVROM_2K_Bank( 0, chr_page[0][1] );
SetVROM_2K_Bank( 2, chr_page[0][3] );
SetVROM_2K_Bank( 4, chr_page[0][5] );
SetVROM_2K_Bank( 6, chr_page[0][7] );
break;
case 3:
SetVROM_8K_Bank( chr_page[0][0],
chr_page[0][1],
chr_page[0][2],
chr_page[0][3],
chr_page[0][4],
chr_page[0][5],
chr_page[0][6],
chr_page[0][7] );
break;
}
} else if( chr_mode == 1 ) {
// PPU BG Bank
switch( chr_size ) {
case 0:
for( i = 0; i < 8; i++ ) {
BG_MEM_BANK[i] = VROM+0x2000*(chr_page[1][7]%VROM_8K_SIZE)+0x0400*i;
BG_MEM_PAGE[i] = (chr_page[1][7]%VROM_8K_SIZE)*8+i;
}
break;
case 1:
for( i = 0; i < 4; i++ ) {
BG_MEM_BANK[i+0] = VROM+0x1000*(chr_page[1][3]%VROM_4K_SIZE)+0x0400*i;
BG_MEM_BANK[i+4] = VROM+0x1000*(chr_page[1][7]%VROM_4K_SIZE)+0x0400*i;
BG_MEM_PAGE[i+0] = (chr_page[1][3]%VROM_4K_SIZE)*4+i;
BG_MEM_PAGE[i+4] = (chr_page[1][7]%VROM_4K_SIZE)*4+i;
}
break;
case 2:
for( i = 0; i < 2; i++ ) {
BG_MEM_BANK[i+0] = VROM+0x0800*(chr_page[1][1]%VROM_2K_SIZE)+0x0400*i;
BG_MEM_BANK[i+2] = VROM+0x0800*(chr_page[1][3]%VROM_2K_SIZE)+0x0400*i;
BG_MEM_BANK[i+4] = VROM+0x0800*(chr_page[1][5]%VROM_2K_SIZE)+0x0400*i;
BG_MEM_BANK[i+6] = VROM+0x0800*(chr_page[1][7]%VROM_2K_SIZE)+0x0400*i;
BG_MEM_PAGE[i+0] = (chr_page[1][1]%VROM_2K_SIZE)*2+i;
BG_MEM_PAGE[i+2] = (chr_page[1][3]%VROM_2K_SIZE)*2+i;
BG_MEM_PAGE[i+4] = (chr_page[1][5]%VROM_2K_SIZE)*2+i;
BG_MEM_PAGE[i+6] = (chr_page[1][7]%VROM_2K_SIZE)*2+i;
}
break;
case 3:
for( i = 0; i < 8; i++ ) {
BG_MEM_BANK[i] = VROM+0x0400*(chr_page[1][i]%VROM_1K_SIZE);
BG_MEM_PAGE[i] = (chr_page[1][i]%VROM_1K_SIZE)+i;
}
break;
}
}
}
void Mapper005::HSync( INT scanline )
{
if( irq_type & MMC5_IRQ_METAL ) {
if( irq_scanline == irq_line ) {
irq_status |= 0x80;
}
}
// if( nes->ppu->IsDispON() && scanline < 239 ) {
if( nes->ppu->IsDispON() && scanline < 240 ) {
irq_scanline++;
irq_status |= 0x40;
irq_clear = 0;
} else if( irq_type & MMC5_IRQ_METAL ) {
irq_scanline = 0;
irq_status &= ~0x80;
irq_status &= ~0x40;
}
if( !(irq_type & MMC5_IRQ_METAL) ) {
if( irq_scanline == irq_line ) {
irq_status |= 0x80;
}
if( ++irq_clear > 2 ) {
irq_scanline = 0;
irq_status &= ~0x80;
irq_status &= ~0x40;
nes->cpu->ClrIRQ( IRQ_MAPPER );
}
}
if( (irq_enable & 0x80) && (irq_status & 0x80) && (irq_status & 0x40) ) {
nes->cpu->SetIRQ( IRQ_MAPPER );
/// nes->cpu->IRQ_NotPending();
#if 0
{
LPBYTE lpScn = nes->ppu->GetScreenPtr();
lpScn = lpScn+(256+16)*scanline;
for( INT i = 0; i < 256+16; i++ ) {
lpScn[i] = 22;
}
}
#endif
}
// For Split mode!
if( scanline == 0 ) {
split_yofs = split_scroll&0x07;
split_addr = ((split_scroll&0xF8)<<2);
} else if( nes->ppu->IsDispON() ) {
if( split_yofs == 7 ) {
split_yofs = 0;
if( (split_addr & 0x03E0) == 0x03A0 ) {
split_addr &= 0x001F;
} else {
if( (split_addr & 0x03E0) == 0x03E0 ) {
split_addr &= 0x001F;
} else {
split_addr += 0x0020;
}
}
} else {
split_yofs++;
}
}
}
void Mapper005::PPU_ExtLatchX( INT x )
{
split_x = x;
}
void Mapper005::PPU_ExtLatch( WORD addr, BYTE& chr_l, BYTE& chr_h, BYTE& attr )
{
WORD ntbladr, attradr, tileadr, tileofs;
WORD tile_yofs;
DWORD tilebank;
BOOL bSplit;
tile_yofs = nes->ppu->GetTILEY();
bSplit = FALSE;
if( split_control & 0x80 ) {
if( !(split_control&0x40) ) {
// Left side
if( (split_control&0x1F) > split_x ) {
bSplit = TRUE;
}
} else {
// Right side
if( (split_control&0x1F) <= split_x ) {
bSplit = TRUE;
}
}
}
if( !bSplit ) {
if( nametable_type[(addr&0x0C00)>>10] == 3 ) {
// Fill mode
if( graphic_mode == 1 ) {
// ExGraphic mode
ntbladr = 0x2000+(addr&0x0FFF);
// Get Nametable
tileadr = fill_chr*0x10+tile_yofs;
// Get TileBank
tilebank = 0x1000*((VRAM[0x0800+(ntbladr&0x03FF)]&0x3F)%VROM_4K_SIZE);
// Attribute
attr = (fill_pal<<2)&0x0C;
// Get Pattern
chr_l = VROM[tilebank+tileadr ];
chr_h = VROM[tilebank+tileadr+8];
} else {
// Normal
tileofs = (PPUREG[0]&PPU_BGTBL_BIT)?0x1000:0x0000;
tileadr = tileofs+fill_chr*0x10+tile_yofs;
attr = (fill_pal<<2)&0x0C;
// Get Pattern
if( chr_type ) {
chr_l = PPU_MEM_BANK[tileadr>>10][ tileadr&0x03FF ];
chr_h = PPU_MEM_BANK[tileadr>>10][(tileadr&0x03FF)+8];
} else {
chr_l = BG_MEM_BANK[tileadr>>10][ tileadr&0x03FF ];
chr_h = BG_MEM_BANK[tileadr>>10][(tileadr&0x03FF)+8];
}
}
} else if( graphic_mode == 1 ) {
// ExGraphic mode
ntbladr = 0x2000+(addr&0x0FFF);
// Get Nametable
tileadr = (WORD)PPU_MEM_BANK[ntbladr>>10][ntbladr&0x03FF]*0x10+tile_yofs;
// Get TileBank
tilebank = 0x1000*((VRAM[0x0800+(ntbladr&0x03FF)]&0x3F)%VROM_4K_SIZE);
// Get Attribute
attr = (VRAM[0x0800+(ntbladr&0x03FF)]&0xC0)>>4;
// Get Pattern
chr_l = VROM[tilebank+tileadr ];
chr_h = VROM[tilebank+tileadr+8];
} else {
// Normal or ExVRAM
tileofs = (PPUREG[0]&PPU_BGTBL_BIT)?0x1000:0x0000;
ntbladr = 0x2000+(addr&0x0FFF);
attradr = 0x23C0+(addr&0x0C00)+((addr&0x0380)>>4)+((addr&0x001C)>>2);
// Get Nametable
tileadr = tileofs+PPU_MEM_BANK[ntbladr>>10][ntbladr&0x03FF]*0x10+tile_yofs;
// Get Attribute
attr = PPU_MEM_BANK[attradr>>10][attradr&0x03FF];
if( ntbladr & 0x0002 ) attr >>= 2;
if( ntbladr & 0x0040 ) attr >>= 4;
attr = (attr&0x03)<<2;
// Get Pattern
if( chr_type ) {
chr_l = PPU_MEM_BANK[tileadr>>10][ tileadr&0x03FF ];
chr_h = PPU_MEM_BANK[tileadr>>10][(tileadr&0x03FF)+8];
} else {
chr_l = BG_MEM_BANK[tileadr>>10][ tileadr&0x03FF ];
chr_h = BG_MEM_BANK[tileadr>>10][(tileadr&0x03FF)+8];
}
}
} else {
ntbladr = ((split_addr&0x03E0)|(split_x&0x1F))&0x03FF;
// Get Split TileBank
tilebank = 0x1000*((INT)split_page%VROM_4K_SIZE);
tileadr = (WORD)VRAM[0x0800+ntbladr]*0x10+split_yofs;
// Get Attribute
attradr = 0x03C0+((ntbladr&0x0380)>>4)+((ntbladr&0x001C)>>2);
attr = VRAM[0x0800+attradr];
if( ntbladr & 0x0002 ) attr >>= 2;
if( ntbladr & 0x0040 ) attr >>= 4;
attr = (attr&0x03)<<2;
// Get Pattern
chr_l = VROM[tilebank+tileadr ];
chr_h = VROM[tilebank+tileadr+8];
}
}
void Mapper005::SaveState( LPBYTE p )
{
p[ 0] = prg_size;
p[ 1] = chr_size;
p[ 2] = sram_we_a;
p[ 3] = sram_we_b;
p[ 4] = graphic_mode;
p[ 5] = nametable_mode;
p[ 6] = nametable_type[0];
p[ 7] = nametable_type[1];
p[ 8] = nametable_type[2];
p[ 9] = nametable_type[3];
p[10] = sram_page;
p[11] = fill_chr;
p[12] = fill_pal;
p[13] = split_control;
p[14] = split_scroll;
p[15] = split_page;
p[16] = chr_mode;
p[17] = irq_status;
p[18] = irq_enable;
p[19] = irq_line;
p[20] = irq_scanline;
p[21] = irq_clear;
p[22] = mult_a;
p[23] = mult_b;
INT i, j;
for( j = 0; j < 2; j++ ) {
for( i = 0; i < 8; i++ ) {
p[24+j*8+i] = chr_page[j][i];
}
}
for( i = 0; i < 8; i++ ) {
p[40+i] = BG_MEM_PAGE[i];
}
}
void Mapper005::LoadState( LPBYTE p )
{
prg_size = p[ 0];
chr_size = p[ 1];
sram_we_a = p[ 2];
sram_we_b = p[ 3];
graphic_mode = p[ 4];
nametable_mode = p[ 5];
nametable_type[0] = p[ 6];
nametable_type[1] = p[ 7];
nametable_type[2] = p[ 8];
nametable_type[3] = p[ 9];
sram_page = p[10];
fill_chr = p[11];
fill_pal = p[12];
split_control = p[13];
split_scroll = p[14];
split_page = p[15];
chr_mode = p[16];
irq_status = p[17];
irq_enable = p[18];
irq_line = p[19];
irq_scanline = p[20];
irq_clear = p[21];
mult_a = p[22];
mult_b = p[23];
INT i, j;
for( j = 0; j < 2; j++ ) {
for( i = 0; i < 8; i++ ) {
chr_page[j][i] = p[24+j*8+i];
}
}
// BGƒoƒ“ƒNÌ<E2809A>Ä<EFBFBD>Ýè<E28099>ˆ<CB86>
for( i = 0; i < 8; i++ ) {
BG_MEM_PAGE[i] = p[40+i]%VROM_1K_SIZE;
}
for( i = 0; i < 8; i++ ) {
BG_MEM_BANK[i] = VROM+0x0400*BG_MEM_PAGE[i];
}
}