246 lines
5.8 KiB
C#
246 lines
5.8 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|