diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs index 1ce50b7f86..b415591fb8 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs @@ -83,6 +83,23 @@ namespace BizHawk.Emulation.Consoles.Nintendo mirroring[3] = d; } + protected void ApplyMemoryMapMask(int mask, ByteBuffer map) + { + byte bmask = (byte)mask; + for (int i = 0; i < map.len; i++) + map[i] &= bmask; + } + + //make sure you have bank-masked the map + protected int ApplyMemoryMap(int blockSizeBits, ByteBuffer map, int addr) + { + int bank = addr >> blockSizeBits; + int ofs = addr & ((1 << blockSizeBits) - 1); + bank = map[bank]; + addr = (bank << blockSizeBits) | ofs; + return addr; + } + public static EMirrorType CalculateMirrorType(int pad_h, int pad_v) { if (pad_h == 0) @@ -168,6 +185,18 @@ namespace BizHawk.Emulation.Consoles.Nintendo public virtual void AddressPPU(int addr) { } public virtual byte PeekPPU(int addr) { return ReadPPU(addr); } + /// + /// reads PPU from a pattern table address. asserts addr lt 0x2000 + /// This is just so that we can accelerate things a tiny bit by not checking against 0x2000 excessively + /// + protected virtual byte ReadPPUChr(int addr) + { + Debug.Assert(addr < 0x2000); + if (VROM != null) + return VROM[addr]; + else return VRAM[addr]; + } + public virtual byte ReadPPU(int addr) { if (addr < 0x2000) diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Mapper164.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Mapper164.cs index b4d29edc13..c474459a24 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Mapper164.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Mapper164.cs @@ -10,6 +10,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo //Mapper 164 //Final Fantasy V (Unl) + //state int prg; public override bool Configure(NES.EDetectionOrigin origin) @@ -44,5 +45,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo { return VROM[addr + (prg * 0x8000)]; } + + public override void SyncState(Serializer ser) + { + base.SyncState(ser); + ser.Sync("prg", ref prg); + } } } diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Mapper176.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Mapper176.cs new file mode 100644 index 0000000000..e0bdb3d1cb --- /dev/null +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Mapper176.cs @@ -0,0 +1,124 @@ +using System; +using System.IO; +using System.Diagnostics; + +namespace BizHawk.Emulation.Consoles.Nintendo +{ + class Mapper176 : NES.NESBoardBase + { + //configuration + int prg_bank_mask_8k, chr_bank_mask_8k; + + //state + int mirror; + ByteBuffer prg_banks_8k = new ByteBuffer(4); + ByteBuffer chr_banks_8k = new ByteBuffer(1); + Bit sbw; + + public override bool Configure(NES.EDetectionOrigin origin) + { + //configure + switch (Cart.board_type) + { + case "MAPPER176": + break; + default: + return false; + } + prg_bank_mask_8k = (Cart.prg_size / 8) - 1; + chr_bank_mask_8k = (Cart.chr_size / 8) - 1; + + mirror = 0; + SyncMirror(); + + sbw = 0; + prg_banks_8k[0] = 0; + prg_banks_8k[1] = 1; + prg_banks_8k[2] = 62; + prg_banks_8k[3] = 63; + ApplyMemoryMapMask(prg_bank_mask_8k,prg_banks_8k); + + chr_banks_8k[0] = 0; + ApplyMemoryMapMask(chr_bank_mask_8k, chr_banks_8k); + + return true; + } + + static readonly EMirrorType[] kMirrorTypes = {EMirrorType.Vertical,EMirrorType.Horizontal,EMirrorType.OneScreenA,EMirrorType.OneScreenB}; + void SyncMirror() + { + SetMirrorType(kMirrorTypes[mirror]); + } + + public override byte ReadPRG(int addr) + { + addr = ApplyMemoryMap(13,prg_banks_8k,addr); + return ROM[addr]; + } + + public override void WritePRG(int addr, byte value) + { + switch (addr) + { + case 0x2000: //0xA000 + mirror = value & 3; + SyncMirror(); + break; + case 0x2001: //0xA001 + //we_sram = data & 0x03; + break; + } + } + + public override byte ReadPPU(int addr) + { + if (addr < 0x2000) + { + addr = ApplyMemoryMap(13, chr_banks_8k, addr); + return base.ReadPPUChr(addr); + } + else return base.ReadPPU(addr); + } + + void SetPrg32k(int value) + { + for(int i=0;i<4;i++) + prg_banks_8k[i] = (byte)(value * 4 + i); + ApplyMemoryMapMask(prg_bank_mask_8k, prg_banks_8k); + } + + public override void WriteEXP(int addr, byte value) + { + switch (addr) + { + case 0x1000: //0x5000 + break; + case 0x1001: //0x5001 + if (sbw) SetPrg32k(value); + break; + case 0x1010: //0x5010 + if (value == 0x24) sbw = 1; + break; + case 0x1011: //0x5011 + if (sbw) SetPrg32k(value >> 1); + break; + case 0x1FF1: //0x5FF1 + SetPrg32k(value>>1); + break; + case 0x1FF2: //0x5FF2 + chr_banks_8k[0] = (byte)value; + ApplyMemoryMapMask(chr_bank_mask_8k, chr_banks_8k); + break; + } + } + + public override void SyncState(Serializer ser) + { + base.SyncState(ser); + ser.Sync("mirror", ref mirror); + ser.Sync("prg_banks_8k", ref prg_banks_8k); + ser.Sync("chr_banks_8k", ref chr_banks_8k); + ser.Sync("sbw", ref sbw); + } + } +}