BizHawk/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/Mapper253.cs

178 lines
3.8 KiB
C#

using BizHawk.Common;
using BizHawk.Common.NumberExtensions;
namespace BizHawk.Emulation.Cores.Nintendo.NES
{
internal sealed class Mapper253 : NesBoardBase
{
private byte[] _prg = new byte[2];
private byte[] chrlo = new byte[8];
private byte[] chrhi = new byte[8];
private bool _vLock;
private int _irqLatch, _irqClock, _irqCount;
private bool _irqA;
private int _prgBankMask8K, _chrBankMask1k;
public override bool Configure(EDetectionOrigin origin)
{
//analyze board type
switch (Cart.BoardType)
{
case "MAPPER253":
break;
default:
return false;
}
_prgBankMask8K = Cart.PrgSize / 8 - 1;
_chrBankMask1k = Cart.ChrSize - 1;
return true;
}
public override void SyncState(Serializer ser)
{
base.SyncState(ser);
ser.Sync("preg", ref _prg, false);
ser.Sync(nameof(chrlo), ref chrlo, false);
ser.Sync(nameof(chrhi), ref chrhi, false);
}
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)
{
addr += 0x8000;
if ((addr >= 0xB000) && (addr <= 0xE00C))
{
var ind = ((((addr & 8) | (addr >> 8)) >> 3) + 2) & 7;
var sar = addr & 4;
var clo = (chrlo[ind] & (0xF0 >> sar)) | ((value & 0x0F) << sar);
chrlo[ind] = (byte)clo;
if (ind == 0)
{
if (clo == 0xc8)
_vLock = false;
else if (clo == 0x88)
_vLock = true;
}
if (sar > 0)
chrhi[ind] = (byte)(value >> 4);
}
else
{
switch (addr)
{
case 0x8010: _prg[0] = value; break;
case 0xA010: _prg[1] = value; break;
case 0x9400: SetMirroring(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;
}
}
}
private void SetMirroring(int mirr)
{
switch(mirr & 3)
{
case 0: SetMirrorType(EMirrorType.Vertical); break;
case 1: SetMirrorType(EMirrorType.Horizontal); break;
case 2: SetMirrorType(EMirrorType.OneScreenA); break;
case 3: SetMirrorType(EMirrorType.OneScreenB); break;
}
}
public override byte ReadPrg(int addr)
{
int bank;
if (addr < 0x2000)
{
bank = _prg[0] & _prgBankMask8K;
}
else if (addr < 0x4000)
{
bank = _prg[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;
var chr = chrlo[x] | (chrhi[x] << 8);
int bank = (chr & _chrBankMask1k) << 10;
if ((chrlo[x] == 4 || chrlo[x] == 5) && !_vLock)
{
bank = chr & 1;
return Vram[(bank << 10) + (addr & 0x3FF)];
}
else
{
return Vrom[bank + (addr & 0x3FF)];
}
}
return base.ReadPpu(addr);
}
public override void WritePpu(int addr, byte value)
{
if (addr < 0x2000)
{
if (Vram != null)
{
int x = (addr >> 10) & 7;
var chr = chrlo[x] | (chrhi[x] << 8);
int bank = (chr & _chrBankMask1k) << 10;
if ((chrlo[x] == 4 || chrlo[x] == 5) && !_vLock)
{
bank = chr & 1;
Vram[(bank << 10) + (addr & 0x3FF)]=value;
}
}
}
else
{
NES.CIRAM[ApplyMirroring(addr)] = value;
}
}
}
}