diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj index da3ced6aef..28f8a16142 100644 --- a/BizHawk.Emulation/BizHawk.Emulation.csproj +++ b/BizHawk.Emulation/BizHawk.Emulation.csproj @@ -204,6 +204,7 @@ + Code diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Mapper028.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Mapper028.cs new file mode 100644 index 0000000000..761a9e3342 --- /dev/null +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Mapper028.cs @@ -0,0 +1,196 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BizHawk.Emulation.Consoles.Nintendo +{ + // http://wiki.nesdev.com/w/index.php/User:Tepples/Multi-discrete_mapper + public class Mapper028 : NES.NESBoardBase + { + // config + int chr_mask_8k; + int prg_mask_16k; + + // state + int reg; + int chr; + int prg; + int mode; + int outer; + + // regennable state + int prglo; + int prghi; + + public override bool Configure(NES.EDetectionOrigin origin) + { + switch (Cart.board_type) + { + case "MAPPER028": + break; + default: + return false; + } + AssertPrg(32, 64, 128, 256, 512, 1024, 2048); + AssertChr(0); + chr_mask_8k = Cart.chr_size / 8 - 1; + prg_mask_16k = Cart.prg_size / 16 - 1; + Cart.wram_size = 0; + Cart.vram_size = 32; + return true; + } + + void Sync() + { + int outb = outer << 1; + // this can probably be rolled up, but i have no motivation to do so + // until it's been tested + switch (mode & 0x3c) + { + // 32K modes + case 0x00: + case 0x04: + prglo = outb; + prghi = outb | 1; + break; + case 0x10: + case 0x14: + prglo = outb & ~2 | prg & 2; + prghi = outb & ~2 | prg & 2 | 1; + break; + case 0x20: + case 0x24: + prglo = outb & ~6 | prg & 6; + prghi = outb & ~6 | prg & 6 | 1; + break; + case 0x30: + case 0x34: + prglo = outb & ~14 | prg & 14; + prghi = outb & ~14 | prg & 14 | 1; + break; + // bottom fixed modes + case 0x08: + prglo = outb; + prghi = outb | prg & 1; + break; + case 0x18: + prglo = outb; + prghi = outb & ~2 | prg & 3; + break; + case 0x28: + prglo = outb; + prghi = outb & ~6 | prg & 7; + break; + case 0x38: + prglo = outb; + prghi = outb & ~14 | prg & 15; + break; + // top fixed modes + case 0x0c: + prglo = outb | prg & 1; + prghi = outb | 1; + break; + case 0x1c: + prglo = outb & ~2 | prg & 3; + prghi = outb | 1; + break; + case 0x2c: + prglo = outb & ~6 | prg & 7; + prghi = outb | 1; + break; + case 0x3c: + prglo = outb & ~14 | prg & 15; + prghi = outb | 1; + break; + } + prglo &= prg_mask_16k; + prghi &= prg_mask_16k; + } + + void Mirror(byte value) + { + if ((mode & 2) == 0) + { + mode &= 0xfe; + mode |= value >> 4 & 1; + } + SyncMirror(); + } + + void SyncMirror() + { + switch (mode & 3) + { + case 0: SetMirrorType(EMirrorType.OneScreenA); break; + case 1: SetMirrorType(EMirrorType.OneScreenB); break; + case 2: SetMirrorType(EMirrorType.Vertical); break; + case 3: SetMirrorType(EMirrorType.Horizontal); break; + } + } + + public override void WriteEXP(int addr, byte value) + { + if (addr >= 0x1000) + reg = value & 0x81; + } + + public override void WritePRG(int addr, byte value) + { + switch (reg) + { + case 0x00: + chr = value & 3; + Mirror(value); + break; + case 0x01: + prg = value & 15; + Mirror(value); + Sync(); + break; + case 0x80: + mode = value & 63; + SyncMirror(); + Sync(); + break; + case 0x81: + outer = value & 63; + Sync(); + break; + } + } + + public override byte ReadPPU(int addr) + { + if (addr < 0x2000) + return VRAM[addr | chr << 13]; + else + return base.ReadPPU(addr); + } + + public override void WritePPU(int addr, byte value) + { + if (addr < 0x2000) + VRAM[addr | chr << 13] = value; + else + base.WritePPU(addr, value); + } + + public override byte ReadPRG(int addr) + { + return ROM[(addr & 0x3fff) | (addr < 0x4000 ? prglo : prghi) << 14]; + } + + public override void SyncState(Serializer ser) + { + base.SyncState(ser); + ser.Sync("reg", ref reg); + ser.Sync("chr", ref chr); + ser.Sync("prg", ref prg); + ser.Sync("mode", ref mode); + ser.Sync("outer", ref outer); + if (!ser.IsWriter) + Sync(); + } + } +}