using System; using System.IO; namespace MyNes.Core; [BoardInfo("MMC1", 1, 4, 64)] internal class Mapper001 : Board { private int address_reg; private byte[] reg = new byte[4]; private byte shift; private byte buffer; private bool flag_p; private bool flag_c; private bool flag_s; private bool enable_wram_enable; private int prg_hijackedbit; private bool use_hijacked; private bool use_sram_switch; private int sram_switch_mask; private int cpuCycles; internal override void HardReset() { base.HardReset(); cpuCycles = 0; address_reg = 0; reg = new byte[4]; reg[0] = 12; flag_c = false; flag_s = (flag_p = true); prg_hijackedbit = 0; reg[1] = (reg[2] = (reg[3] = 0)); buffer = 0; shift = 0; if (base.Chips.Contains("MMC1B") || base.Chips.Contains("MMC1B2")) { TogglePRGRAMEnable(enable: false); Console.WriteLine("MMC1: SRAM Disabled."); } enable_wram_enable = !base.Chips.Contains("MMC1A"); Console.WriteLine("MMC1: enable_wram_enable = " + enable_wram_enable); use_hijacked = (PRG_ROM_16KB_Mask & 0x10) == 16; if (use_hijacked) { prg_hijackedbit = 16; } use_sram_switch = false; if (PRG_RAM_08KB_Count > 0) { use_sram_switch = true; sram_switch_mask = (use_hijacked ? 8 : 24); sram_switch_mask &= PRG_RAM_08KB_Mask << 3; if (sram_switch_mask == 0) { use_sram_switch = false; } } Switch16KPRG(0xF | prg_hijackedbit, PRGArea.AreaC000); Console.WriteLine("MMC1: use_hijacked = " + use_hijacked); Console.WriteLine("MMC1: use_sram_switch = " + use_sram_switch); Console.WriteLine("MMC1: sram_switch_mask = " + sram_switch_mask.ToString("X2")); } internal override void WritePRG(ref ushort address, ref byte value) { if (cpuCycles > 0) { return; } cpuCycles = 3; if ((value & 0x80) == 128) { reg[0] |= 12; flag_s = (flag_p = true); shift = (buffer = 0); return; } if ((value & 1) == 1) { buffer |= (byte)(1 << (int)shift); } if (++shift < 5) { return; } address_reg = (address & 0x7FFF) >> 13; reg[address_reg] = buffer; shift = (buffer = 0); switch (address_reg) { case 0: flag_c = (reg[0] & 0x10) != 0; flag_p = (reg[0] & 8) != 0; flag_s = (reg[0] & 4) != 0; UpdatePRG(); UpdateCHR(); switch (reg[0] & 3) { case 0: Switch01KNMTFromMirroring(Mirroring.OneScA); break; case 1: Switch01KNMTFromMirroring(Mirroring.OneScB); break; case 2: Switch01KNMTFromMirroring(Mirroring.Vert); break; case 3: Switch01KNMTFromMirroring(Mirroring.Horz); break; } break; case 1: if (!flag_c) { Switch08KCHR(reg[1] >> 1); } else { Switch04KCHR(reg[1], CHRArea.Area0000); } if (use_sram_switch) { Switch08KPRG((reg[1] & sram_switch_mask) >> 3, PRGArea.Area6000); } if (use_hijacked) { prg_hijackedbit = reg[1] & 0x10; UpdatePRG(); } break; case 2: if (flag_c) { Switch04KCHR(reg[2], CHRArea.Area1000); } if (use_sram_switch) { Switch08KPRG((reg[2] & sram_switch_mask) >> 3, PRGArea.Area6000); } if (use_hijacked) { prg_hijackedbit = reg[2] & 0x10; UpdatePRG(); } break; case 3: if (enable_wram_enable) { TogglePRGRAMEnable((reg[3] & 0x10) == 0); } UpdatePRG(); break; } } private void UpdateCHR() { if (!flag_c) { Switch08KCHR(reg[1] >> 1); } else { Switch04KCHR(reg[1], CHRArea.Area0000); Switch04KCHR(reg[2], CHRArea.Area1000); } if (use_sram_switch) { Switch08KPRG((reg[1] & sram_switch_mask) >> 3, PRGArea.Area6000); } } private void UpdatePRG() { if (!flag_p) { Switch32KPRG(((reg[3] & 0xF) | prg_hijackedbit) >> 1, PRGArea.Area8000); } else if (flag_s) { Switch16KPRG((reg[3] & 0xF) | prg_hijackedbit, PRGArea.Area8000); Switch16KPRG(0xF | prg_hijackedbit, PRGArea.AreaC000); } else { Switch16KPRG(prg_hijackedbit, PRGArea.Area8000); Switch16KPRG((reg[3] & 0xF) | prg_hijackedbit, PRGArea.AreaC000); } } internal override void OnCPUClock() { if (cpuCycles > 0) { cpuCycles--; } } internal override void WriteStateData(ref BinaryWriter stream) { base.WriteStateData(ref stream); stream.Write(reg); stream.Write(shift); stream.Write(buffer); stream.Write(flag_p); stream.Write(flag_c); stream.Write(flag_s); stream.Write(enable_wram_enable); stream.Write(prg_hijackedbit); stream.Write(use_hijacked); stream.Write(use_sram_switch); stream.Write(cpuCycles); } internal override void ReadStateData(ref BinaryReader stream) { base.ReadStateData(ref stream); stream.Read(reg, 0, reg.Length); shift = stream.ReadByte(); buffer = stream.ReadByte(); flag_p = stream.ReadBoolean(); flag_c = stream.ReadBoolean(); flag_s = stream.ReadBoolean(); enable_wram_enable = stream.ReadBoolean(); prg_hijackedbit = stream.ReadInt32(); use_hijacked = stream.ReadBoolean(); use_sram_switch = stream.ReadBoolean(); cpuCycles = stream.ReadInt32(); } }