////////////////////////////////////////////////////////////// // Mapper190 Nintendo MMC3 // ////////////////////////////////////////////////////////////////////////// using static VirtualNes.MMU; using static VirtualNes.Core.CPU; using INT = System.Int32; using BYTE = System.Byte; using System; //using Codice.CM.Client.Differences; namespace VirtualNes.Core { public class Mapper190 : Mapper { BYTE cbase; /* PowerOn OR RESET : cbase=0 */ BYTE mp190_lcchk; /* PowerOn OR RESET */ BYTE mp190_lcmd; BYTE mp190_cmd; BYTE irq_enable; BYTE irq_counter; BYTE irq_latch; BYTE lowoutdata; public Mapper190(NES parent) : base(parent) { } public override void Reset() { SetPROM_32K_Bank(0, 1, PROM_8K_SIZE - 2, PROM_8K_SIZE - 1); // DWORD crc = nes.rom.GetPROM_CRC(); // if( crc == 0x6F3D187A ) { // Temp_Buf=0; //Kof96 // } else { // Temp_Buf=1; //ST97 // } irq_enable = 0; irq_counter = 0; cbase = 0; /* PowerOn OR RESET : cbase=0 */ mp190_lcchk = 0; /* PowerOn OR RESET */ mp190_lcmd = 1; } //void Mapper190::WriteLow(WORD addr, BYTE data) public override void WriteLow(ushort addr, byte data) { /* For Initial Copy Protect check (KOF'96) */ if (addr == 0x5000) { mp190_lcmd = data; switch (data) { case 0xE0: SetPROM_32K_Bank(0); break; case 0xEE: SetPROM_32K_Bank(3); break; } } if ((addr == 0x5001) && (mp190_lcmd == 0x00)) { SetPROM_32K_Bank(7); } if (addr == 0x5080) { switch (data) { case 0x1: lowoutdata = 0x83; break; case 0x2: lowoutdata = 0x42; break; case 0x3: lowoutdata = 0x00; break; } } CPU_MEM_BANK[addr >> 13][addr & 0x1FFF] = data; } //BYTE Mapper190::ReadLow(WORD addr) public override byte ReadLow(ushort addr) { switch (addr) { case 0x5000: return lowoutdata; default: return CPU_MEM_BANK[addr >> 13][addr & 0x1FFF]; } } //void Mapper190::Write(WORD addr, BYTE data) public override void Write(ushort addr, byte data) { switch (addr & 0xE003) { case 0x8000: mp190_cmd = data; if ((mp190_cmd & 0x80) != 0) cbase = 1; else cbase = 0; break; case 0x8003: /* for Street Fighter Zero 2 '97 */ mp190_lcchk = data; switch (data) { case 0x28: SetPROM_8K_Bank(4, 0x1F); SetPROM_8K_Bank(5, 0x1F); SetPROM_8K_Bank(6, 0x17); SetPROM_8K_Bank(7, 0x1F); break; case 0x2A: SetPROM_8K_Bank(4, 0x1F); SetPROM_8K_Bank(5, 0x0F); SetPROM_8K_Bank(6, 0x17); SetPROM_8K_Bank(7, 0x1F); break; case 0x06: SetPROM_8K_Bank(4, 0x1E); SetPROM_8K_Bank(5, 0x1F); SetPROM_8K_Bank(6, 0x1F); SetPROM_8K_Bank(7, 0x1F); break; } break; case 0x8001: if ((mp190_lcchk == 0x6) || (mp190_lcmd == 0x0)) { switch (mp190_cmd & 0x07) { case 0: if (cbase == 0) { SetVROM_1K_Bank(0, data + 0x100); SetVROM_1K_Bank(1, data + 0x101); } else { SetVROM_1K_Bank(4, data + 0x100); SetVROM_1K_Bank(5, data + 0x101); } break; case 1: if (cbase == 0) { SetVROM_1K_Bank(2, data + 0x100); SetVROM_1K_Bank(3, data + 0x101); } else { SetVROM_1K_Bank(6, data + 0x100); SetVROM_1K_Bank(7, data + 0x101); } break; case 2: if (cbase == 0) { SetVROM_1K_Bank(4, data); } else { SetVROM_1K_Bank(0, data); } break; case 3: if (cbase == 0) { SetVROM_1K_Bank(5, data); } else { SetVROM_1K_Bank(1, data); } break; case 4: if (cbase == 0) { SetVROM_1K_Bank(6, data); } else { SetVROM_1K_Bank(2, data); } break; case 5: if (cbase == 0) { SetVROM_1K_Bank(7, data); } else { SetVROM_1K_Bank(3, data); } break; case 6: data = (byte)(data & ((PROM_8K_SIZE * 2) - 1)); if ((mp190_lcmd & 0x40) != 0) { SetPROM_8K_Bank(6, data); SetPROM_8K_Bank(4, (PROM_8K_SIZE - 1) * 2); } else { SetPROM_8K_Bank(4, data); SetPROM_8K_Bank(6, (PROM_8K_SIZE - 1) * 2); } break; case 7: data = (byte)(data & ((PROM_8K_SIZE * 2) - 1)); if ((mp190_lcmd & 0x40) != 0) { SetPROM_8K_Bank(5, data); SetPROM_8K_Bank(4, (PROM_8K_SIZE - 1) * 2); } else { SetPROM_8K_Bank(5, data); SetPROM_8K_Bank(6, (PROM_8K_SIZE - 1) * 2); } break; } } break; case 0xA000: if ((data & 0x1) == 0x1) SetVRAM_Mirror(VRAM_HMIRROR); else SetVRAM_Mirror(VRAM_VMIRROR); break; case 0xA001: break; case 0xC000: irq_counter = (byte)(data - 1); break; case 0xC001: irq_latch = (byte)(data - 1); break; case 0xC002: irq_counter = data; break; case 0xC003: irq_latch = data; break; case 0xE000: irq_counter = irq_latch; irq_enable = 0; nes.cpu.ClrIRQ(IRQ_MAPPER); break; case 0xE001: irq_enable = 1; break; case 0xE002: irq_counter = irq_latch; irq_enable = 0; nes.cpu.ClrIRQ(IRQ_MAPPER); break; case 0xE003: irq_enable = 1; irq_counter = irq_counter; break; } } //void Mapper190::HSync(INT scanline) public override void HSync(int scanline) { if ((scanline >= 0 && scanline <= 239)) { if (nes.ppu.IsDispON()) { if (irq_enable != 0) { if ((irq_counter--) == 0) { // nes.cpu.IRQ_NotPending(); nes.cpu.SetIRQ(IRQ_MAPPER); } } } } } //void Mapper190::SaveState(LPBYTE p) public override void SaveState(byte[] p) { p[0] = irq_enable; p[1] = irq_counter; p[2] = irq_latch; p[3] = cbase; p[4] = mp190_lcchk; p[5] = mp190_lcmd; p[6] = mp190_cmd; p[7] = lowoutdata; } //void Mapper190::LoadState(LPBYTE p) public override void LoadState(byte[] p) { irq_enable = p[0]; irq_counter = p[1]; irq_latch = p[2]; cbase = p[3]; mp190_lcchk = p[4]; mp190_lcmd = p[5]; mp190_cmd = p[6]; lowoutdata = p[7]; } public override bool IsStateSave() { return true; } } }