166 lines
3.4 KiB
C#
166 lines
3.4 KiB
C#
using BizHawk.Common;
|
|
using BizHawk.Common.NumberExtensions;
|
|
|
|
namespace BizHawk.Emulation.Cores.Nintendo.NES
|
|
{
|
|
// Adapted from FCEUX src
|
|
internal sealed class Mapper252 : NesBoardBase
|
|
{
|
|
private byte[] preg = new byte[2];
|
|
private byte[] creg = new byte[8];
|
|
|
|
private int _prgBankMask8K, _chrBankMask1K;
|
|
private int _irqLatch, _irqClock, _irqCount;
|
|
private bool _irqA;
|
|
|
|
public override bool Configure(EDetectionOrigin origin)
|
|
{
|
|
switch (Cart.BoardType)
|
|
{
|
|
case "MAPPER252":
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
AssertPrg(256);
|
|
AssertChr(128);
|
|
AssertVram(2);
|
|
AssertWram(8);
|
|
_prgBankMask8K = Cart.PrgSize / 8 - 1;
|
|
_chrBankMask1K = Cart.ChrSize - 1;
|
|
SetMirrorType(EMirrorType.Vertical);
|
|
return true;
|
|
}
|
|
|
|
public override void SyncState(Serializer ser)
|
|
{
|
|
base.SyncState(ser);
|
|
ser.Sync(nameof(preg), ref preg, false);
|
|
ser.Sync(nameof(creg), ref creg, false);
|
|
ser.Sync(nameof(_irqLatch), ref _irqLatch);
|
|
ser.Sync(nameof(_irqClock), ref _irqClock);
|
|
ser.Sync(nameof(_irqCount), ref _irqCount);
|
|
ser.Sync(nameof(_irqA), ref _irqA);
|
|
}
|
|
|
|
public override void ClockCpu()
|
|
{
|
|
if (_irqA)
|
|
{
|
|
_irqClock += 3;
|
|
if (_irqClock >= 341)
|
|
{
|
|
_irqClock -= 341;
|
|
_irqCount++;
|
|
if (_irqCount==0x100)
|
|
{
|
|
IrqSignal=true;
|
|
_irqCount = _irqLatch;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public override void WritePrg(int addr, byte value)
|
|
{
|
|
WriteReg((addr + 0x8000), value);
|
|
}
|
|
|
|
public void WriteReg(int addr, byte value)
|
|
{
|
|
if (addr >= 0xB000 && addr < 0xF000)
|
|
{
|
|
var ind = ((((addr & 8) | (addr >> 8)) >> 3) + 2) & 7;
|
|
var sar = addr & 4;
|
|
creg[ind] = (byte)((creg[ind] & (0xF0 >> sar)) | ((value & 0x0F) << sar));
|
|
}
|
|
else
|
|
{
|
|
switch (addr & 0xF00C)
|
|
{
|
|
case 0x8000:
|
|
case 0x8004:
|
|
case 0x8008:
|
|
case 0x800C:
|
|
preg[0] = value;
|
|
break;
|
|
|
|
case 0xA000:
|
|
case 0xA004:
|
|
case 0xA008:
|
|
case 0xA00C:
|
|
preg[1] = value;
|
|
break;
|
|
|
|
case 0xF000: IrqSignal = false; _irqLatch &= 0xF0; _irqLatch |= value & 0xF; break;
|
|
case 0xF004: IrqSignal = false; _irqLatch &= 0x0F; _irqLatch |= value << 4; break;
|
|
case 0xF008: IrqSignal = false; _irqClock = 0; _irqCount = _irqLatch; _irqA = value.Bit(1); break;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
public override byte ReadPrg(int addr)
|
|
{
|
|
int bank;
|
|
|
|
if (addr < 0x2000)
|
|
{
|
|
bank = preg[0] & _prgBankMask8K;
|
|
}
|
|
else if (addr < 0x4000)
|
|
{
|
|
bank = preg[1] & _prgBankMask8K;
|
|
}
|
|
else if (addr < 0x6000)
|
|
{
|
|
bank = _prgBankMask8K - 1;
|
|
}
|
|
else
|
|
{
|
|
bank = _prgBankMask8K;
|
|
}
|
|
|
|
|
|
return Rom[(bank << 13) + (addr & 0x1FFF)];
|
|
}
|
|
|
|
public override byte ReadPpu(int addr)
|
|
{
|
|
if (addr < 0x2000)
|
|
{
|
|
int x = (addr >> 10) & 7;
|
|
|
|
int bank;
|
|
if (creg[x] == 6 || creg[x] == 7)
|
|
{
|
|
bank = creg[x] & 1;
|
|
return Vram[(bank << 10) + (addr & 0x3FF)];
|
|
}
|
|
else
|
|
{
|
|
bank = (creg[x] & _chrBankMask1K) << 10;
|
|
return Vrom[bank + (addr & 0x3FF)];
|
|
}
|
|
|
|
}
|
|
|
|
return base.ReadPpu(addr);
|
|
}
|
|
|
|
public override void WritePpu(int addr, byte value)
|
|
{
|
|
if (addr < 0x2000)
|
|
{
|
|
if (Vram != null)
|
|
Vram[addr&0x7FF] = value;
|
|
}
|
|
else
|
|
{
|
|
NES.CIRAM[ApplyMirroring(addr)] = value;
|
|
}
|
|
}
|
|
}
|
|
}
|