diff --git a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj index 6de6939ee3..0876ed3bcb 100644 --- a/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj +++ b/BizHawk.Emulation.Cores/BizHawk.Emulation.Cores.csproj @@ -485,6 +485,7 @@ + diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/FFE/Mapper017.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/FFE/Mapper017.cs new file mode 100644 index 0000000000..990f3e9c15 --- /dev/null +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/Boards/FFE/Mapper017.cs @@ -0,0 +1,174 @@ +using BizHawk.Common; +using BizHawk.Common.NumberExtensions; + +namespace BizHawk.Emulation.Cores.Nintendo.NES +{ + public class Mapper017 : NES.NESBoardBase + { + private ByteBuffer prg_regs_8k = new ByteBuffer(4); + private ByteBuffer chr_regs_1k = new ByteBuffer(8); + + private int prg_mask_8k; + private int chr_mask_1k; + + private bool irq_enable; + private bool irq_pending; + private int irq_count; + private const int IRQ_DESTINATION = 0x10000; + + public override bool Configure(NES.EDetectionOrigin origin) + { + switch (Cart.board_type) + { + case "MAPPER017": + break; + default: + return false; + } + + prg_mask_8k = Cart.prg_size / 8 - 1; + chr_mask_1k = Cart.chr_size / 1 - 1; + + prg_regs_8k[0] = 0x00; + prg_regs_8k[1] = 0x01; + prg_regs_8k[2] = 0xFE; + prg_regs_8k[3] = 0xFF; + SetMirrorType(Cart.pad_h, Cart.pad_v); + + return true; + } + + public override void WriteEXP(int addr, byte value) + { + switch (addr & 0x7FF) + { + //Mirroring: + case 0x2FE: + case 0x2FF: + int mirroring = ((addr << 1) & 2) | ((value >> 4) & 1); + switch (mirroring) + { + case 0: SetMirrorType(EMirrorType.OneScreenA); break; + case 1: SetMirrorType(EMirrorType.OneScreenB); break; + case 2: SetMirrorType(EMirrorType.Vertical); break; + case 3: SetMirrorType(EMirrorType.Horizontal); break; + } + break; + + //IRQ + case 0x501: + irq_enable = value.Bit(0); + irq_pending = false; + irq_count = 0; + SyncIRQ(); + break; + case 0x502: + irq_count &= 0xFF00; + irq_count |= value; + break; + case 0x503: + irq_count &= 0x00FF; + irq_count |= value << 8; + irq_enable = true; + irq_pending = false; + break; + + //PRG + case 0x504: + case 0x505: + case 0x506: + case 0x507: + prg_regs_8k[addr & 3] = value; + break; + + //CHR + case 0x510: + case 0x511: + case 0x512: + case 0x513: + case 0x514: + case 0x515: + case 0x516: + case 0x517: + chr_regs_1k[addr & 7] = value; + break; + } + } + + public override void Dispose() + { + base.Dispose(); + prg_regs_8k.Dispose(); + chr_regs_1k.Dispose(); + } + + public override void SyncState(Serializer ser) + { + base.SyncState(ser); + + ser.Sync("prg_regs_8k", ref prg_regs_8k); + ser.Sync("chr_regs_1k", ref chr_regs_1k); + + ser.Sync("irq_enable", ref irq_enable); + ser.Sync("irq_pending", ref irq_pending); + ser.Sync("irq_count", ref irq_count); + } + + public override byte ReadPRG(int addr) + { + int bank_8k = prg_regs_8k[addr >> 13]; + bank_8k &= prg_mask_8k; + int offset = addr & 0x1FFF; + return ROM[bank_8k << 13 | offset]; + } + + public override void WritePPU(int addr, byte value) + { + if (addr < 0x2000 && VRAM != null) + { + VRAM[addr] = value; + } + base.WritePPU(addr, value); + } + + public override byte ReadPPU(int addr) + { + if (addr < 0x2000) + { + if (VRAM != null) return VRAM[addr]; + + int bank_1k = chr_regs_1k[addr >> 10]; + bank_1k &= chr_mask_1k; + int offset = addr & 0x3FF; + return VROM[bank_1k << 10 | offset]; + } + return base.ReadPPU(addr); + } + + public override void ClockCPU() + { + if (irq_enable) + { + ClockIRQ(); + } + } + + private void ClockIRQ() + { + irq_count++; + if (irq_count >= IRQ_DESTINATION) + { + irq_enable = false; + irq_pending = true; + } + + SyncIRQ(); + } + + private void SyncIRQ() + { + SyncIRQ(irq_pending); + } + + } +}