diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper.cs index 40043ba..65d6d69 100644 --- a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper.cs +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper.cs @@ -81,9 +81,24 @@ namespace VirtualNes.Core { //todo : 实现加载mapper switch (no) - { - case 4: return new Mapper004(parent); - case 16: return new Mapper016(parent); + { + case 0: return new Mapper000(parent); + case 1: return new Mapper001(parent); + case 2: return new Mapper002(parent); + case 3: return new Mapper003(parent); + case 4: return new Mapper004(parent); + case 5: return new Mapper005(parent); + case 6: return new Mapper006(parent); + case 7: return new Mapper007(parent); + case 8: return new Mapper008(parent); + case 9: return new Mapper009(parent); + case 10: return new Mapper010(parent); + case 11: return new Mapper011(parent); + case 12: return new Mapper012(parent); + case 13: return new Mapper013(parent); + //case 14: return new Mapper014(parent); + case 15: return new Mapper015(parent); + case 16: return new Mapper016(parent); case 17: return new Mapper017(parent); case 18: return new Mapper018(parent); case 19: return new Mapper019(parent); @@ -97,7 +112,7 @@ namespace VirtualNes.Core case 32: return new Mapper032(parent); case 33: return new Mapper033(parent); case 34: return new Mapper034(parent); - case 35: return new Mapper035(parent); + //case 35: return new Mapper035(parent); case 40: return new Mapper040(parent); case 41: return new Mapper041(parent); case 42: return new Mapper042(parent); @@ -153,7 +168,7 @@ namespace VirtualNes.Core case 108: return new Mapper108(parent); case 109: return new Mapper109(parent); case 110: return new Mapper110(parent); - case 111: return new Mapper111(parent); + //case 111: return new Mapper111(parent); case 112: return new Mapper112(parent); case 113: return new Mapper113(parent); case 114: return new Mapper114(parent); diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper000.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper000.cs new file mode 100644 index 0000000..049e0f0 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper000.cs @@ -0,0 +1,47 @@ +////////////////////////////////////////////////////////////////////////// +// Mapper000 // +////////////////////////////////////////////////////////////////////////// +using static VirtualNes.MMU; +using static VirtualNes.Core.CPU; +using INT = System.Int32; +using BYTE = System.Byte; +using Codice.CM.Client.Differences; + +namespace VirtualNes.Core +{ + public class Mapper000 : Mapper + { + + public Mapper000(NES parent) : base(parent) { } + + public override void Reset() + { + switch (PROM_16K_SIZE) + { + default: + case 1: // 16K only + SetPROM_16K_Bank(4, 0); + SetPROM_16K_Bank(6, 0); + break; + case 2: // 32K + SetPROM_32K_Bank(0); + break; + } + + uint crc = nes.rom.GetPROM_CRC(); + if (crc == 0x4e7db5af) + { // Circus Charlie(J) + nes.SetRenderMethod(EnumRenderMethod.POST_RENDER); + } + if (crc == 0x57970078) + { // F-1 Race(J) + nes.SetRenderMethod(EnumRenderMethod.POST_RENDER); + } + if (crc == 0xaf2bbcbc // Mach Rider(JU) + || crc == 0x3acd4bf1) + { // Mach Rider(Alt)(JU) + nes.SetRenderMethod(EnumRenderMethod.POST_RENDER); + } + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper001.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper001.cs new file mode 100644 index 0000000..69d4e3d --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper001.cs @@ -0,0 +1,411 @@ +////////////////////////////////////////////////////////////////////////// +// Mapper001 Nintendo MMC1 // +////////////////////////////////////////////////////////////////////////// +using static VirtualNes.MMU; +using static VirtualNes.Core.CPU; +using INT = System.Int32; +using BYTE = System.Byte; +using Codice.CM.Client.Differences; + +namespace VirtualNes.Core +{ + public class Mapper001 : Mapper + { + + uint last_addr; + + BYTE patch; + BYTE wram_patch; + BYTE wram_bank; + BYTE wram_count; + + BYTE[] reg = new byte[4]; + BYTE shift, regbuf; + + public Mapper001(NES parent) : base(parent) { } + + public override void Reset() + { + reg[0] = 0x0C; // D3=1,D2=1 + reg[1] = reg[2] = reg[3] = 0; + shift = regbuf = 0; + + patch = 0; + wram_patch = 0; + + if (PROM_16K_SIZE < 32) + { + SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1); + } + else + { + // For 512K/1M byte Cartridge + SetPROM_16K_Bank(4, 0); + SetPROM_16K_Bank(6, 16 - 1); + + patch = 1; + } + + if (VROM_8K_SIZE != 0) + { + // SetVROM_8K_Bank( 0 ); + } + + uint crc = nes.rom.GetPROM_CRC(); + + if (crc == 0xb8e16bd0) + { // Snow Bros.(J) + patch = 2; + } + // if( crc == 0x9b565541 ) { // Triathron, The(J) + // nes.SetFrameIRQmode( FALSE ); + // } + if (crc == 0xc96c6f04) + { // Venus Senki(J) + nes.SetRenderMethod(EnumRenderMethod.POST_ALL_RENDER); + } + // if( crc == 0x5e3f7004 ) { // Softball Tengoku(J) + // } + + if (crc == 0x4d2edf70) + { // Night Rider(J) + nes.SetRenderMethod(EnumRenderMethod.TILE_RENDER); + } + if (crc == 0xcd2a73f0) + { // Pirates!(U) + nes.SetRenderMethod(EnumRenderMethod.TILE_RENDER); + patch = 2; + } + + // if( crc == 0x09efe54b ) { // Majaventure - Mahjong Senki(J) + // nes.SetFrameIRQmode( FALSE ); + // } + + if (crc == 0x11469ce3) + { // Viva! Las Vegas(J) + } + if (crc == 0xd878ebf5) + { // Ninja Ryukenden(J) + nes.SetRenderMethod(EnumRenderMethod.POST_ALL_RENDER); + } + + // if( crc == 0x7bd7b849 ) { // Nekketsu Koukou - Dodgeball Bu(J) + // } + + if (crc == 0x466efdc2) + { // Final Fantasy(J) + nes.SetRenderMethod(EnumRenderMethod.TILE_RENDER); + nes.ppu.SetExtMonoMode(true); + } + if (crc == 0xc9556b36) + { // Final Fantasy I&II(J) + nes.SetRenderMethod(EnumRenderMethod.TILE_RENDER); + nes.ppu.SetExtMonoMode(true); + nes.SetSAVERAM_SIZE(16 * 1024); + wram_patch = 2; + } + + if (crc == 0x717e1169) + { // Cosmic Wars(J) + nes.SetRenderMethod(EnumRenderMethod.PRE_ALL_RENDER); + } + + if (crc == 0xC05D2034) + { // Snake's Revenge(U) + nes.SetRenderMethod(EnumRenderMethod.PRE_ALL_RENDER); + } + + if (crc == 0xb8747abf // Best Play - Pro Yakyuu Special(J) + || crc == 0x29449ba9 // Nobunaga no Yabou - Zenkoku Ban(J) + || crc == 0x2b11e0b0 // Nobunaga no Yabou - Zenkoku Ban(J)(alt) + || crc == 0x4642dda6 // Nobunaga's Ambition(U) + || crc == 0xfb69743a // Aoki Ookami to Shiroki Mejika - Genghis Khan(J) + || crc == 0x2225c20f // Genghis Khan(U) + || crc == 0xabbf7217 // Sangokushi(J) + ) + { + + nes.SetSAVERAM_SIZE(16 * 1024); + wram_patch = 1; + wram_bank = 0; + wram_count = 0; + } + } + + //void Mapper001::Write(WORD addr, BYTE data) + public override void Write(ushort addr, byte data) + { + // DEBUGOUT( "MMC1 %04X=%02X\n", addr&0xFFFF,data&0xFF ); + + if (wram_patch == 1 && addr == 0xBFFF) + { + wram_count++; + wram_bank += (byte)(data & 0x01); + if (wram_count == 5) + { + if (wram_bank != 0) + { + SetPROM_Bank(3, &WRAM[0x2000], BANKTYPE_RAM); + } + else + { + SetPROM_Bank(3, &WRAM[0x0000], BANKTYPE_RAM); + } + wram_bank = wram_count = 0; + } + } + + if (patch != 1) + { + if ((addr & 0x6000) != (last_addr & 0x6000)) + { + shift = regbuf = 0; + } + last_addr = addr; + } + + if ((data & 0x80) != 0) + { + shift = regbuf = 0; + // reg[0] = 0x0C; // D3=1,D2=1 + reg[0] |= 0x0C; // D3=1,D2=1 残りはリセットされない + return; + } + + if ((data & 0x01) != 0) regbuf |= (byte)(1 << shift); + if (++shift < 5) + return; + addr = (ushort)((addr & 0x7FFF) >> 13); + reg[addr] = regbuf; + + // DEBUGOUT( "MMC1 %d=%02X\n", addr&0xFFFF,regbuf&0xFF ); + + regbuf = 0; + shift = 0; + + if (patch != 1) + { + // For Normal Cartridge + switch (addr) + { + case 0: + if ((reg[0] & 0x02) != 0) + { + if ((reg[0] & 0x01) != 0) SetVRAM_Mirror(VRAM_HMIRROR); + else SetVRAM_Mirror(VRAM_VMIRROR); + } + else + { + if ((reg[0] & 0x01) != 0) SetVRAM_Mirror(VRAM_MIRROR4H); + else SetVRAM_Mirror(VRAM_MIRROR4L); + } + break; + case 1: + // Register #1 + if (VROM_1K_SIZE != 0) + { + if ((reg[0] & 0x10) != 0) + { + // CHR 4K bank lower($0000-$0FFF) + SetVROM_4K_Bank(0, reg[1]); + // CHR 4K bank higher($1000-$1FFF) + SetVROM_4K_Bank(4, reg[2]); + } + else + { + // CHR 8K bank($0000-$1FFF) + SetVROM_8K_Bank(reg[1] >> 1); + } + } + else + { + // For Romancia + if ((reg[0] & 0x10) != 0) + { + SetCRAM_4K_Bank(0, reg[1]); + } + } + break; + case 2: + // Register #2 + if (VROM_1K_SIZE != 0) + { + if ((reg[0] & 0x10) != 0) + { + // CHR 4K bank lower($0000-$0FFF) + SetVROM_4K_Bank(0, reg[1]); + // CHR 4K bank higher($1000-$1FFF) + SetVROM_4K_Bank(4, reg[2]); + } + else + { + // CHR 8K bank($0000-$1FFF) + SetVROM_8K_Bank(reg[1] >> 1); + } + } + else + { + // For Romancia + if ((reg[0] & 0x10) != 0) + { + SetCRAM_4K_Bank(4, reg[2]); + } + } + break; + case 3: + if (!((reg[0] & 0x08) != 0)) + { + // PRG 32K bank ($8000-$FFFF) + SetPROM_32K_Bank(reg[3] >> 1); + } + else + { + if ((reg[0] & 0x04) != 0) + { + // PRG 16K bank ($8000-$BFFF) + SetPROM_16K_Bank(4, reg[3]); + SetPROM_16K_Bank(6, PROM_16K_SIZE - 1); + } + else + { + // PRG 16K bank ($C000-$FFFF) + SetPROM_16K_Bank(6, reg[3]); + SetPROM_16K_Bank(4, 0); + } + } + break; + } + } + else + { + // For 512K/1M byte Cartridge + INT PROM_BASE = 0; + if (PROM_16K_SIZE >= 32) + { + PROM_BASE = reg[1] & 0x10; + } + + // For FinalFantasy I&II + if (wram_patch == 2) + { + if (((reg[1] & 0x18) == 0)) + { + SetPROM_Bank(3, &WRAM[0x0000], BANKTYPE_RAM); + } + else + { + SetPROM_Bank(3, &WRAM[0x2000], BANKTYPE_RAM); + } + } + + // Register #0 + if (addr == 0) + { + if ((reg[0] & 0x02) != 0) + { + if ((reg[0] & 0x01) != 0) SetVRAM_Mirror(VRAM_HMIRROR); + else SetVRAM_Mirror(VRAM_VMIRROR); + } + else + { + if ((reg[0] & 0x01) != 0) SetVRAM_Mirror(VRAM_MIRROR4H); + else SetVRAM_Mirror(VRAM_MIRROR4L); + } + } + // Register #1 + if (VROM_1K_SIZE != 0) + { + if ((reg[0] & 0x10) != 0) + { + // CHR 4K bank lower($0000-$0FFF) + SetVROM_4K_Bank(0, reg[1]); + } + else + { + // CHR 8K bank($0000-$1FFF) + SetVROM_8K_Bank(reg[1] >> 1); + } + } + else + { + // For Romancia + if ((reg[0] & 0x10) != 0) + { + SetCRAM_4K_Bank(0, reg[1]); + } + } + // Register #2 + if (VROM_1K_SIZE != 0) + { + if ((reg[0] & 0x10) != 0) + { + // CHR 4K bank higher($1000-$1FFF) + SetVROM_4K_Bank(4, reg[2]); + } + } + else + { + // For Romancia + if ((reg[0] & 0x10) != 0) + { + SetCRAM_4K_Bank(4, reg[2]); + } + } + // Register #3 + if (((reg[0] & 0x08) == 0)) + { + // PRG 32K bank ($8000-$FFFF) + SetPROM_32K_Bank((reg[3] & (0xF + PROM_BASE)) >> 1); + } + else + { + if ((reg[0] & 0x04) != 0) + { + // PRG 16K bank ($8000-$BFFF) + SetPROM_16K_Bank(4, PROM_BASE + (reg[3] & 0x0F)); + if (PROM_16K_SIZE >= 32) SetPROM_16K_Bank(6, PROM_BASE + 16 - 1); + } + else + { + // PRG 16K bank ($C000-$FFFF) + SetPROM_16K_Bank(6, PROM_BASE + (reg[3] & 0x0F)); + if (PROM_16K_SIZE >= 32) SetPROM_16K_Bank(4, PROM_BASE); + } + } + } + } + + //void Mapper001::SaveState(LPBYTE p) + public override void SaveState(byte[] p) + { + p[0] = reg[0]; + p[1] = reg[1]; + p[2] = reg[2]; + p[3] = reg[3]; + p[4] = shift; + p[5] = regbuf; + + p[6] = wram_bank; + p[7] = wram_count; + } + + //void Mapper001::LoadState(LPBYTE p) + public override void LoadState(byte[] p) + { + reg[0] = p[0]; + reg[1] = p[1]; + reg[2] = p[2]; + reg[3] = p[3]; + shift = p[4]; + regbuf = p[5]; + + wram_bank = p[6]; + wram_count = p[7]; + } + + public override bool IsStateSave() + { + return true; + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper002.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper002.cs new file mode 100644 index 0000000..ece6fd4 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper002.cs @@ -0,0 +1,72 @@ +////////////////////////////////////////////////////////////////////////// +// Mapper002 UNROM // +////////////////////////////////////////////////////////////////////////// +using static VirtualNes.MMU; +using static VirtualNes.Core.CPU; +using INT = System.Int32; +using BYTE = System.Byte; +using Codice.CM.Client.Differences; + +namespace VirtualNes.Core +{ + public class Mapper002 : Mapper + { + + BYTE patch; + public Mapper002(NES parent) : base(parent) { } + + public override void Reset() + { + SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1); + + patch = 0; + + uint crc = nes.rom.GetPROM_CRC(); + // if( crc == 0x322c9b09 ) { // Metal Gear (Alt)(J) + //// nes.SetFrameIRQmode( FALSE ); + // } + // if( crc == 0xe7a3867b ) { // Dragon Quest 2(Alt)(J) + // nes.SetFrameIRQmode( FALSE ); + // } + //// if( crc == 0x9622fbd9 ) { // Ballblazer(J) + //// patch = 0; + //// } + if (crc == 0x8c3d54e8 // Ikari(J) + || crc == 0x655efeed // Ikari Warriors(U) + || crc == 0x538218b2) + { // Ikari Warriors(E) + patch = 1; + } + + if (crc == 0xb20c1030) + { // Shanghai(J)(original) + patch = 2; + } + } + + + //void Mapper002::WriteLow(WORD addr, BYTE data) + public override void WriteLow(ushort addr, byte data) + { + if (!nes.rom.IsSAVERAM()) + { + if (addr >= 0x5000 && patch == 1) + SetPROM_16K_Bank(4, data); + } + else + { + base.WriteLow(addr, data); + } + } + + //void Mapper002::Write(WORD addr, BYTE data) + public override void Write(ushort addr, byte data) + { + if (patch != 2) + SetPROM_16K_Bank(4, data); + else + SetPROM_16K_Bank(4, data >> 4); + } + + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper003.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper003.cs new file mode 100644 index 0000000..aac5c2d --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper003.cs @@ -0,0 +1,66 @@ +////////////////////////////////////////////////////////////////////////// +// Mapper003 CNROM // +////////////////////////////////////////////////////////////////////////// +using static VirtualNes.MMU; +using static VirtualNes.Core.CPU; +using INT = System.Int32; +using BYTE = System.Byte; +using Codice.CM.Client.Differences; + +namespace VirtualNes.Core +{ + public class Mapper003 : Mapper + { + + public Mapper003(NES parent) : base(parent) { } + + public override void Reset() + { + switch (PROM_16K_SIZE) + { + case 1: // 16K only + SetPROM_16K_Bank(4, 0); + SetPROM_16K_Bank(6, 0); + break; + case 2: // 32K + SetPROM_32K_Bank(0); + break; + } + // nes.SetRenderMethod( NES::TILE_RENDER ); + uint crc = nes.rom.GetPROM_CRC(); + + if (crc == 0x2b72fe7e) + { // Ganso Saiyuuki - Super Monkey Dai Bouken(J) + nes.SetRenderMethod( EnumRenderMethod.TILE_RENDER); + nes.ppu.SetExtNameTableMode(true); + } + + // if( crc == 0xE44D95B5 ) { // ひみつw + // } + } + +#if FALSE//0 +void Mapper003::WriteLow( WORD addr, BYTE data ) +{ + if( patch ) { + Mapper::WriteLow( addr, data ); + } else { + if( nes.rom.IsSAVERAM() ) { + Mapper::WriteLow( addr, data ); + } else { + if( addr >= 0x4800 ) { + SetVROM_8K_Bank( data & 0x03 ); + } + } + } +} +#endif + + //void Mapper003::Write(WORD addr, BYTE data) + public override void Write(ushort addr, byte data) + { + SetVROM_8K_Bank(data); + } + + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper005.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper005.cs new file mode 100644 index 0000000..5053bf1 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper005.cs @@ -0,0 +1,847 @@ +////////////////////////////////////////////////////////////////////////// +// Mapper005 Nintendo MMC5 // +////////////////////////////////////////////////////////////////////////// +using static VirtualNes.MMU; +using static VirtualNes.Core.CPU; +using INT = System.Int32; +using BYTE = System.Byte; +using Codice.CM.Client.Differences; + +namespace VirtualNes.Core +{ + public class Mapper005 : Mapper + { + BYTE sram_size; + + BYTE prg_size; // $5100 + BYTE chr_size; // $5101 + BYTE sram_we_a, sram_we_b; // $5102-$5103 + BYTE graphic_mode; // $5104 + BYTE nametable_mode; // $5105 + BYTE[] nametable_type = new byte[4]; // $5105 use + + BYTE sram_page; // $5113 + + BYTE fill_chr, fill_pal; // $5106-$5107 + BYTE split_control; // $5200 + BYTE split_scroll; // $5201 + BYTE split_page; // $5202 + + BYTE split_x; + ushort split_addr; + ushort split_yofs; + + BYTE chr_type; + BYTE chr_mode; // $5120-$512B use + //BYTE chr_page[2][8]; + BYTE[,] chr_page = new byte[2,8]; // $5120-$512B + LPBYTE BG_MEM_BANK[8]; // BGパターン用バンク + BYTE BG_MEM_PAGE[8]; + + BYTE irq_status; // $5204(R) + BYTE irq_enable; // $5204(W) + BYTE irq_line; // $5203 + BYTE irq_scanline; + BYTE irq_clear; // HSyncで使用 + BYTE irq_type; + + BYTE mult_a, mult_b; // $5205-$5206 + public Mapper005(NES parent) : base(parent) { } + + public override void 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設定 + SetBank_SRAM(3, 0); + + sram_size = 0; + nes.SetSAVERAM_SIZE(16 * 1024); + + uint 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) + public override byte ReadLow(ushort 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 = base.ReadLow(addr); + } + + return data; + } + + //void Mapper005::WriteLow(WORD addr, BYTE data) + public override void WriteLow(ushort addr, byte data) + { + INT i; + +#if FALSE//0 +if( addr >= 0x5000 && addr <=0x50FF ) { +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)!=0) + { + 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) + public override void Write(ushort 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 SetBank_CPU(uint addr, BYTE data) + { + if ((data & 0x80)!=0) + { + // 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 SetBank_SRAM(BYTE page, BYTE data) + { + if (sram_size == 0) data = (byte)((data > 3) ? 8 : 0); + if (sram_size == 1) data = (byte)((data > 3) ? 1 : 0); + if (sram_size == 2) data = (byte)((data > 3) ? 8 : data); + if (sram_size == 3) data = (byte)((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 = (ushort)(split_scroll & 0x07); + split_addr = (ushort)(((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) + public override void PPU_ExtLatchX(int x) + { + split_x = x; + } + + //void Mapper005::PPU_ExtLatch(WORD addr, BYTE& chr_l, BYTE& chr_h, BYTE& attr ) + public override void PPU_ExtLatch(ushort addr, ref byte chr_l, ref byte chr_h, ref byte attr) + { + ushort ntbladr, attradr, tileadr, tileofs; + ushort tile_yofs; + uint 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 = (ushort)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) + public override void SaveState(byte[] 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) + public override void LoadState(byte[] 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バンクの再設定処理 + // 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]; + // } + + SetBank_PPU(); + + } + + + public override bool IsStateSave() + { + return true; + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper006.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper006.cs new file mode 100644 index 0000000..d6cbedc --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper006.cs @@ -0,0 +1,112 @@ +////////////////////////////////////////////////////////////////////////// +// Mapper006 FFE F4xxx // +////////////////////////////////////////////////////////////////////////// +using static VirtualNes.MMU; +using static VirtualNes.Core.CPU; +using INT = System.Int32; +using BYTE = System.Byte; +using Codice.CM.Client.Differences; + +namespace VirtualNes.Core +{ + public class Mapper006 : Mapper + { + BYTE irq_enable; + INT irq_counter; + public Mapper006(NES parent) : base(parent) { } + + public override void Reset() + { + SetPROM_32K_Bank(0, 1, 14, 15); + + if (VROM_1K_SIZE != 0) + { + SetVROM_8K_Bank(0); + } + else + { + SetCRAM_8K_Bank(0); + } + + irq_enable = 0; + irq_counter = 0; + } + + //void Mapper006::WriteLow(WORD addr, BYTE data) + public override void WriteLow(ushort addr, byte data) + { + switch (addr) + { + case 0x42FE: + if ((data & 0x10) != 0) SetVRAM_Mirror(VRAM_MIRROR4H); + else SetVRAM_Mirror(VRAM_MIRROR4L); + break; + case 0x42FF: + if ((data & 0x10) != 0) SetVRAM_Mirror(VRAM_HMIRROR); + else SetVRAM_Mirror(VRAM_VMIRROR); + break; + + case 0x4501: + irq_enable = 0; + + nes.cpu.ClrIRQ(IRQ_MAPPER); + break; + case 0x4502: + irq_counter = (irq_counter & 0xFF00) | data; + break; + case 0x4503: + irq_counter = (irq_counter & 0x00FF) | ((INT)data << 8); + irq_enable = 0xFF; + + nes.cpu.ClrIRQ(IRQ_MAPPER); + break; + default: + base.WriteLow(addr, data); + break; + } + } + + //void Mapper006::Write(WORD addr, BYTE data) + public override void Write(ushort addr, byte data) + { + SetPROM_16K_Bank(4, (data & 0x3C) >> 2); + SetCRAM_8K_Bank(data & 0x03); + } + + //void Mapper006::HSync(INT scanline) + public override void HSync(int scanline) + { + if (irq_enable != 0) + { + irq_counter += 133; + if (irq_counter >= 0xFFFF) + { + // nes.cpu.IRQ(); + irq_counter = 0; + + nes.cpu.SetIRQ(IRQ_MAPPER); + } + } + } + + //void Mapper006::SaveState(LPBYTE p) + public override void SaveState(byte[] p) + { + //p[0] = irq_enable; + //*(INT*)&p[1] = irq_counter; + } + + //void Mapper006::LoadState(LPBYTE p) + public override void LoadState(byte[] p) + { + //irq_enable = p[0]; + //irq_counter = *(INT*)&p[1]; + } + + + public override bool IsStateSave() + { + return true; + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper007.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper007.cs new file mode 100644 index 0000000..a2c5a7a --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper007.cs @@ -0,0 +1,58 @@ +////////////////////////////////////////////////////////////////////////// +// Mapper007 AOROM/AMROM // +////////////////////////////////////////////////////////////////////////// +using static VirtualNes.MMU; +using static VirtualNes.Core.CPU; +using INT = System.Int32; +using BYTE = System.Byte; +using Codice.CM.Client.Differences; +using UnityEngine.UIElements; + +namespace VirtualNes.Core +{ + public class Mapper007 : Mapper + { + + BYTE patch; + public Mapper007(NES parent) : base(parent) { } + + public override void Reset() + { + patch = 0; + + SetPROM_32K_Bank(0); + SetVRAM_Mirror(VRAM_MIRROR4L); + + uint crc = nes.rom.GetPROM_CRC(); + if (crc == 0x3c9fe649) + { // WWF Wrestlemania Challenge(U) + SetVRAM_Mirror(VRAM_VMIRROR); + patch = 1; + } + if (crc == 0x09874777) + { // Marble Madness(U) + nes.SetRenderMethod( EnumRenderMethod.TILE_RENDER); + } + + if (crc == 0x279710DC // Battletoads (U) + || crc == 0xCEB65B06) + { // Battletoads Double Dragon (U) + nes.SetRenderMethod( EnumRenderMethod.PRE_ALL_RENDER); + ::memset(WRAM, 0, sizeof(WRAM)); + } + } + + //void Mapper007::Write(WORD addr, BYTE data) + public override void Write(ushort addr, byte data) + { + SetPROM_32K_Bank(data & 0x07); + + if (patch!=0) + { + if ((data & 0x10)!=0) SetVRAM_Mirror(VRAM_MIRROR4H); + else SetVRAM_Mirror(VRAM_MIRROR4L); + } + } + + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper008.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper008.cs new file mode 100644 index 0000000..90834d6 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper008.cs @@ -0,0 +1,32 @@ +////////////////////////////////////////////////////////////////////////// +// Mapper008 FFE F3xxx // +////////////////////////////////////////////////////////////////////////// +using static VirtualNes.MMU; +using static VirtualNes.Core.CPU; +using INT = System.Int32; +using BYTE = System.Byte; +using Codice.CM.Client.Differences; + +namespace VirtualNes.Core +{ + public class Mapper008 : Mapper + { + + public Mapper008(NES parent) : base(parent) { } + + public override void Reset() + { + SetPROM_32K_Bank(0, 1, 2, 3); + SetVROM_8K_Bank(0); + } + + //void Mapper008::Write(WORD addr, BYTE data) + public override void Write(ushort addr, byte data) + { + SetPROM_16K_Bank(4, (data & 0xF8) >> 3); + SetVROM_8K_Bank(data & 0x07); + } + + + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper009.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper009.cs new file mode 100644 index 0000000..5dccb25 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper009.cs @@ -0,0 +1,129 @@ +////////////////////////////////////////////////////////////////////////// +// Mapper009 Nintendo MMC2 // +////////////////////////////////////////////////////////////////////////// +using static VirtualNes.MMU; +using static VirtualNes.Core.CPU; +using INT = System.Int32; +using BYTE = System.Byte; +using Codice.CM.Client.Differences; + +namespace VirtualNes.Core +{ + public class Mapper009 : Mapper + { + BYTE[] reg = new byte[4]; + BYTE latch_a, latch_b; + + public Mapper009(NES parent) : base(parent) { } + + public override void Reset() + { + SetPROM_32K_Bank(0, PROM_8K_SIZE - 3, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1); + + reg[0] = 0; reg[1] = 4; + reg[2] = 0; reg[3] = 0; + + latch_a = 0xFE; + latch_b = 0xFE; + SetVROM_4K_Bank(0, 4); + SetVROM_4K_Bank(4, 0); + + nes.ppu.SetChrLatchMode(true); + } + + //void Mapper009::Write(WORD addr, BYTE data) + public override void Write(ushort addr, byte data) + { + switch (addr & 0xF000) + { + case 0xA000: + SetPROM_8K_Bank(4, data); + break; + case 0xB000: + reg[0] = data; + if (latch_a == 0xFD) + { + SetVROM_4K_Bank(0, reg[0]); + } + break; + case 0xC000: + reg[1] = data; + if (latch_a == 0xFE) + { + SetVROM_4K_Bank(0, reg[1]); + } + break; + case 0xD000: + reg[2] = data; + if (latch_b == 0xFD) + { + SetVROM_4K_Bank(4, reg[2]); + } + break; + case 0xE000: + reg[3] = data; + if (latch_b == 0xFE) + { + SetVROM_4K_Bank(4, reg[3]); + } + break; + case 0xF000: + if ((data & 0x01) != 0) SetVRAM_Mirror(VRAM_HMIRROR); + else SetVRAM_Mirror(VRAM_VMIRROR); + break; + } + } + + //void Mapper009::PPU_ChrLatch(WORD addr) + public override void PPU_ChrLatch(ushort addr) + { + if ((addr & 0x1FF0) == 0x0FD0 && latch_a != 0xFD) + { + latch_a = 0xFD; + SetVROM_4K_Bank(0, reg[0]); + } + else if ((addr & 0x1FF0) == 0x0FE0 && latch_a != 0xFE) + { + latch_a = 0xFE; + SetVROM_4K_Bank(0, reg[1]); + } + else if ((addr & 0x1FF0) == 0x1FD0 && latch_b != 0xFD) + { + latch_b = 0xFD; + SetVROM_4K_Bank(4, reg[2]); + } + else if ((addr & 0x1FF0) == 0x1FE0 && latch_b != 0xFE) + { + latch_b = 0xFE; + SetVROM_4K_Bank(4, reg[3]); + } + } + + //void Mapper009::SaveState(LPBYTE p) + public override void SaveState(byte[] p) + { + p[0] = reg[0]; + p[1] = reg[1]; + p[2] = reg[2]; + p[3] = reg[3]; + p[4] = latch_a; + p[5] = latch_b; + } + + //void Mapper009::LoadState(LPBYTE p) + public override void LoadState(byte[] p) + { + reg[0] = p[0]; + reg[1] = p[1]; + reg[2] = p[2]; + reg[3] = p[3]; + latch_a = p[4]; + latch_b = p[5]; + } + + public override bool IsStateSave() + { + return true; + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper010.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper010.cs new file mode 100644 index 0000000..aeb2833 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper010.cs @@ -0,0 +1,129 @@ +////////////////////////////////////////////////////////////////////////// +// Mapper010 Nintendo MMC4 // +////////////////////////////////////////////////////////////////////////// +using static VirtualNes.MMU; +using static VirtualNes.Core.CPU; +using INT = System.Int32; +using BYTE = System.Byte; +using Codice.CM.Client.Differences; + +namespace VirtualNes.Core +{ + public class Mapper010 : Mapper + { + BYTE[] reg = new byte[4]; + BYTE latch_a, latch_b; + + public Mapper010(NES parent) : base(parent) { } + + public override void Reset() + { + SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1); + + reg[0] = 0; reg[1] = 4; + reg[2] = 0; reg[3] = 0; + + latch_a = 0xFE; + latch_b = 0xFE; + SetVROM_4K_Bank(0, 4); + SetVROM_4K_Bank(4, 0); + + nes.ppu.SetChrLatchMode(true); + } + + //void Mapper010::Write(WORD addr, BYTE data) + public override void Write(ushort addr, byte data) + { + switch (addr & 0xF000) + { + case 0xA000: + SetPROM_16K_Bank(4, data); + break; + case 0xB000: + reg[0] = data; + if (latch_a == 0xFD) + { + SetVROM_4K_Bank(0, reg[0]); + } + break; + case 0xC000: + reg[1] = data; + if (latch_a == 0xFE) + { + SetVROM_4K_Bank(0, reg[1]); + } + break; + case 0xD000: + reg[2] = data; + if (latch_b == 0xFD) + { + SetVROM_4K_Bank(4, reg[2]); + } + break; + case 0xE000: + reg[3] = data; + if (latch_b == 0xFE) + { + SetVROM_4K_Bank(4, reg[3]); + } + break; + case 0xF000: + if ((data & 0x01) != 0) + SetVRAM_Mirror(VRAM_HMIRROR); + else SetVRAM_Mirror(VRAM_VMIRROR); + break; + } + } + + //void Mapper010::PPU_ChrLatch(WORD addr) + public override void PPU_ChrLatch(ushort addr) + { + if ((addr & 0x1FF0) == 0x0FD0 && latch_a != 0xFD) + { + latch_a = 0xFD; + SetVROM_4K_Bank(0, reg[0]); + } + else if ((addr & 0x1FF0) == 0x0FE0 && latch_a != 0xFE) + { + latch_a = 0xFE; + SetVROM_4K_Bank(0, reg[1]); + } + else if ((addr & 0x1FF0) == 0x1FD0 && latch_b != 0xFD) + { + latch_b = 0xFD; + SetVROM_4K_Bank(4, reg[2]); + } + else if ((addr & 0x1FF0) == 0x1FE0 && latch_b != 0xFE) + { + latch_b = 0xFE; + SetVROM_4K_Bank(4, reg[3]); + } + } + + //void Mapper010::SaveState(LPBYTE p) + public override void SaveState(byte[] p) + { + p[0] = reg[0]; + p[1] = reg[1]; + p[2] = reg[2]; + p[3] = reg[3]; + p[4] = latch_a; + p[5] = latch_b; + } + + //void Mapper010::LoadState(LPBYTE p) + public override void LoadState(byte[] p) + { + reg[0] = p[0]; + reg[1] = p[1]; + reg[2] = p[2]; + reg[3] = p[3]; + latch_a = p[4]; + latch_b = p[5]; + } + public override bool IsStateSave() + { + return true; + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper011.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper011.cs new file mode 100644 index 0000000..46188d1 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper011.cs @@ -0,0 +1,42 @@ +////////////////////////////////////////////////////////////////////////// +// Mapper011 Color Dreams // +////////////////////////////////////////////////////////////////////////// +using static VirtualNes.MMU; +using static VirtualNes.Core.CPU; +using INT = System.Int32; +using BYTE = System.Byte; +using Codice.CM.Client.Differences; + +namespace VirtualNes.Core +{ + public class Mapper011 : Mapper + { + + public Mapper011(NES parent) : base(parent) { } + + public override void Reset() + { + SetPROM_32K_Bank(0); + + if (VROM_1K_SIZE != 0) + { + SetVROM_8K_Bank(0); + // SetVROM_8K_Bank( 1 ); + } + SetVRAM_Mirror(VRAM_VMIRROR); + } + + //void Mapper011::Write(WORD addr, BYTE data) + public override void Write(ushort addr, byte data) + { + //DEBUGOUT("WR A:%04X D:%02X\n", addr, data); + SetPROM_32K_Bank(data); + if (VROM_1K_SIZE != 0) + { + SetVROM_8K_Bank(data >> 4); + } + } + + + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper012.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper012.cs new file mode 100644 index 0000000..51fcb4d --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper012.cs @@ -0,0 +1,331 @@ +using static VirtualNes.MMU; +using static VirtualNes.Core.CPU; +using INT = System.Int32; +using BYTE = System.Byte; +using Codice.CM.Client.Differences; + +namespace VirtualNes.Core +{ + public class Mapper012 : Mapper + { + uint vb0, vb1; + BYTE[] reg = new byte[8]; + BYTE prg0, prg1; + BYTE chr01, chr23, chr4, chr5, chr6, chr7; + BYTE we_sram; + + BYTE irq_enable; + BYTE irq_counter; + BYTE irq_latch; + BYTE irq_request; + BYTE irq_preset; + BYTE irq_preset_vbl; + + public Mapper012(NES parent) : base(parent) { } + + public override void Reset() + { + for (INT i = 0; i < 8; i++) + { + reg[i] = 0x00; + } + + prg0 = 0; + prg1 = 1; + SetBank_CPU(); + + vb0 = 0; + vb1 = 0; + chr01 = 0; + chr23 = 2; + chr4 = 4; + chr5 = 5; + chr6 = 6; + chr7 = 7; + SetBank_PPU(); + + we_sram = 0; // Disable + irq_enable = 0; // Disable + irq_counter = 0; + irq_latch = 0xFF; + irq_request = 0; + irq_preset = 0; + irq_preset_vbl = 0; + } + + //void Mapper012::WriteLow(WORD addr, BYTE data) + public override void WriteLow(ushort addr, byte data) + { + if (addr > 0x4100 && addr < 0x6000) + { + vb0 = (byte)((data & 0x01) << 8); + vb1 = (byte)((data & 0x10) << 4); + SetBank_PPU(); + } + else + { + base.WriteLow(addr, data); + } + } + + //BYTE Mapper012::ReadLow(WORD addr) + public override byte ReadLow(ushort addr) + { + return 0x01; + } + + //void Mapper012::Write(WORD addr, BYTE data) + public override void Write(ushort addr, byte data) + { + //DEBUGOUT( "MPRWR A=%04X D=%02X L=%3d CYC=%d\n", addr&0xFFFF, data&0xFF, nes.GetScanline(), nes.cpu.GetTotalCycles() ); + + switch (addr & 0xE001) + { + case 0x8000: + reg[0] = data; + SetBank_CPU(); + SetBank_PPU(); + break; + case 0x8001: + reg[1] = data; + + switch (reg[0] & 0x07) + { + case 0x00: + chr01 = (byte)(data & 0xFE); + SetBank_PPU(); + break; + case 0x01: + chr23 = (byte)(data & 0xFE); + SetBank_PPU(); + break; + case 0x02: + chr4 = data; + SetBank_PPU(); + break; + case 0x03: + chr5 = data; + SetBank_PPU(); + break; + case 0x04: + chr6 = data; + SetBank_PPU(); + break; + case 0x05: + chr7 = data; + SetBank_PPU(); + break; + case 0x06: + prg0 = data; + SetBank_CPU(); + break; + case 0x07: + prg1 = data; + SetBank_CPU(); + break; + } + break; + case 0xA000: + reg[2] = data; + if (!nes.rom.Is4SCREEN()) + { + if ((data & 0x01) != 0) SetVRAM_Mirror(VRAM_HMIRROR); + else SetVRAM_Mirror(VRAM_VMIRROR); + } + break; + case 0xA001: + reg[3] = data; + break; + case 0xC000: + reg[4] = data; + irq_latch = data; + break; + case 0xC001: + reg[5] = data; + if (nes.GetScanline() < 240) + { + irq_counter |= 0x80; + irq_preset = 0xFF; + } + else + { + irq_counter |= 0x80; + irq_preset_vbl = 0xFF; + irq_preset = 0; + } + break; + case 0xE000: + reg[6] = data; + irq_enable = 0; + irq_request = 0; + + nes.cpu.ClrIRQ(IRQ_MAPPER); + break; + case 0xE001: + reg[7] = data; + irq_enable = 1; + irq_request = 0; + break; + } + } + + //void Mapper012::HSync(INT scanline) + public override void HSync(int scanline) + { + if ((scanline >= 0 && scanline <= 239) && nes.ppu.IsDispON()) + { + if (irq_preset_vbl != 0) + { + irq_counter = irq_latch; + irq_preset_vbl = 0; + } + if (irq_preset != 0) + { + irq_counter = irq_latch; + irq_preset = 0; + } + else if (irq_counter > 0) + { + irq_counter--; + } + + if (irq_counter == 0) + { + // Some game set irq_latch to zero to disable irq. So check it here. + if (irq_enable != 0 && irq_latch != 0) + { + irq_request = 0xFF; + nes.cpu.SetIRQ(IRQ_MAPPER); + } + irq_preset = 0xFF; + } + } + } + + void SetBank_CPU() + { + if ((reg[0] & 0x40) != 0) + { + SetPROM_32K_Bank(PROM_8K_SIZE - 2, prg1, prg0, PROM_8K_SIZE - 1); + } + else + { + SetPROM_32K_Bank(prg0, prg1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1); + } + } + + void SetBank_PPU() + { + if (VROM_1K_SIZE != 0) + { + if ((reg[0] & 0x80) != 0) + { + SetVROM_8K_Bank( + (int)(vb0 + chr4), + (int)(vb0 + chr5), + (int)(vb0 + chr6), + (int)(vb0 + chr7), + (int)(vb1 + chr01), + (int)(vb1 + chr01 + 1), + (int)(vb1 + chr23), + (int)(vb1 + chr23 + 1) + ); + } + else + { + SetVROM_8K_Bank( + (int)(vb0 + chr01), + (int)(vb0 + chr01 + 1), + (int)(vb0 + chr23), + (int)(vb0 + chr23 + 1), + (int)(vb1 + chr4), + (int)(vb1 + chr5), + (int)(vb1 + chr6), + (int)(vb1 + chr7)) + ; + } + } + else + { + if ((reg[0] & 0x80) != 0) + { + SetCRAM_1K_Bank(4, (chr01 + 0) & 0x07); + SetCRAM_1K_Bank(5, (chr01 + 1) & 0x07); + SetCRAM_1K_Bank(6, (chr23 + 0) & 0x07); + SetCRAM_1K_Bank(7, (chr23 + 1) & 0x07); + SetCRAM_1K_Bank(0, chr4 & 0x07); + SetCRAM_1K_Bank(1, chr5 & 0x07); + SetCRAM_1K_Bank(2, chr6 & 0x07); + SetCRAM_1K_Bank(3, chr7 & 0x07); + } + else + { + SetCRAM_1K_Bank(0, (chr01 + 0) & 0x07); + SetCRAM_1K_Bank(1, (chr01 + 1) & 0x07); + SetCRAM_1K_Bank(2, (chr23 + 0) & 0x07); + SetCRAM_1K_Bank(3, (chr23 + 1) & 0x07); + SetCRAM_1K_Bank(4, chr4 & 0x07); + SetCRAM_1K_Bank(5, chr5 & 0x07); + SetCRAM_1K_Bank(6, chr6 & 0x07); + SetCRAM_1K_Bank(7, chr7 & 0x07); + } + } + } + + //void Mapper012::SaveState(LPBYTE p) + public override void SaveState(byte[] p) + { + //for (INT i = 0; i < 8; i++) + //{ + // p[i] = reg[i]; + //} + //p[8] = prg0; + //p[9] = prg1; + //p[10] = chr01; + //p[11] = chr23; + //p[12] = chr4; + //p[13] = chr5; + //p[14] = chr6; + //p[15] = chr7; + //p[16] = irq_enable; + //p[17] = (BYTE)irq_counter; + //p[18] = irq_latch; + //p[19] = irq_request; + //p[20] = irq_preset; + //p[21] = irq_preset_vbl; + //*((DWORD*)&p[22]) = vb0; + //*((DWORD*)&p[26]) = vb1; + } + + //void Mapper012::LoadState(LPBYTE p) + public override void LoadState(byte[] p) + { + //for (INT i = 0; i < 8; i++) + //{ + // reg[i] = p[i]; + //} + //prg0 = p[8]; + //prg1 = p[9]; + //chr01 = p[10]; + //chr23 = p[11]; + //chr4 = p[12]; + //chr5 = p[13]; + //chr6 = p[14]; + //chr7 = p[15]; + //irq_enable = p[16]; + //irq_counter = (INT)p[17]; + //irq_latch = p[18]; + //irq_request = p[19]; + //irq_preset = p[20]; + //irq_preset_vbl = p[21]; + //vb0 = *((DWORD*)&p[22]); + //vb1 = *((DWORD*)&p[26]); + } + + + public override bool IsStateSave() + { + return true; + } + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper013.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper013.cs new file mode 100644 index 0000000..31d9123 --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper013.cs @@ -0,0 +1,33 @@ +////////////////////////////////////////////////////////////////////////// +// Mapper013 CPROM // +////////////////////////////////////////////////////////////////////////// +using static VirtualNes.MMU; +using static VirtualNes.Core.CPU; +using INT = System.Int32; +using BYTE = System.Byte; +using Codice.CM.Client.Differences; + +namespace VirtualNes.Core +{ + public class Mapper013 : Mapper + { + + public Mapper013(NES parent) : base(parent) { } + + public override void Reset() + { + SetPROM_32K_Bank(0, 1, 2, 3); + SetCRAM_4K_Bank(0, 0); + SetCRAM_4K_Bank(4, 0); + } + + //void Mapper013::Write(WORD addr, BYTE data) + public override void Write(ushort addr, byte data) + { + SetPROM_32K_Bank((data & 0x30) >> 4); + SetCRAM_4K_Bank(4, data & 0x03); + } + + + } +} diff --git a/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper015.cs b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper015.cs new file mode 100644 index 0000000..6b0336e --- /dev/null +++ b/AxibugEmuOnline.Client/Assets/VirtualNes.Core/Mapper/Mapper015.cs @@ -0,0 +1,93 @@ +////////////////////////////////////////////////////////////////////////// +// Mapper015 100-in-1 chip // +////////////////////////////////////////////////////////////////////////// +using static VirtualNes.MMU; +using static VirtualNes.Core.CPU; +using INT = System.Int32; +using BYTE = System.Byte; +using Codice.CM.Client.Differences; + +namespace VirtualNes.Core +{ + public class Mapper015 : Mapper + { + + public Mapper015(NES parent) : base(parent) { } + + public override void Reset() + { + SetPROM_32K_Bank(0, 1, 2, 3); + } + + //void Mapper015::Write(WORD addr, BYTE data) + public override void Write(ushort addr, byte data) + { + switch (addr) + { + case 0x8000: + if ((data & 0x80) != 0) + { + SetPROM_8K_Bank(4, (data & 0x3F) * 2 + 1); + SetPROM_8K_Bank(5, (data & 0x3F) * 2 + 0); + SetPROM_8K_Bank(6, (data & 0x3F) * 2 + 3); + SetPROM_8K_Bank(7, (data & 0x3F) * 2 + 2); + } + else + { + SetPROM_8K_Bank(4, (data & 0x3F) * 2 + 0); + SetPROM_8K_Bank(5, (data & 0x3F) * 2 + 1); + SetPROM_8K_Bank(6, (data & 0x3F) * 2 + 2); + SetPROM_8K_Bank(7, (data & 0x3F) * 2 + 3); + } + if ((data & 0x40) != 0) + SetVRAM_Mirror(VRAM_HMIRROR); + else SetVRAM_Mirror(VRAM_VMIRROR); + break; + case 0x8001: + if ((data & 0x80) != 0) + { + SetPROM_8K_Bank(6, (data & 0x3F) * 2 + 1); + SetPROM_8K_Bank(7, (data & 0x3F) * 2 + 0); + } + else + { + SetPROM_8K_Bank(6, (data & 0x3F) * 2 + 0); + SetPROM_8K_Bank(7, (data & 0x3F) * 2 + 1); + } + break; + case 0x8002: + if ((data & 0x80) != 0) + { + SetPROM_8K_Bank(4, (data & 0x3F) * 2 + 1); + SetPROM_8K_Bank(5, (data & 0x3F) * 2 + 1); + SetPROM_8K_Bank(6, (data & 0x3F) * 2 + 1); + SetPROM_8K_Bank(7, (data & 0x3F) * 2 + 1); + } + else + { + SetPROM_8K_Bank(4, (data & 0x3F) * 2 + 0); + SetPROM_8K_Bank(5, (data & 0x3F) * 2 + 0); + SetPROM_8K_Bank(6, (data & 0x3F) * 2 + 0); + SetPROM_8K_Bank(7, (data & 0x3F) * 2 + 0); + } + break; + case 0x8003: + if ((data & 0x80) != 0) + { + SetPROM_8K_Bank(6, (data & 0x3F) * 2 + 1); + SetPROM_8K_Bank(7, (data & 0x3F) * 2 + 0); + } + else + { + SetPROM_8K_Bank(6, (data & 0x3F) * 2 + 0); + SetPROM_8K_Bank(7, (data & 0x3F) * 2 + 1); + } + if ((data & 0x40) != 0) SetVRAM_Mirror(VRAM_HMIRROR); + else SetVRAM_Mirror(VRAM_VMIRROR); + break; + } + } + + + } +}