using BizHawk.Common; namespace BizHawk.Emulation.Cores.Nintendo.NES { //AKA mapper 068 (and TENGEN-800042) //After Burner & After Burner 2 //Maharaja public sealed class Sunsoft4 : NES.NESBoardBase { //configuration int prg_bank_mask, chr_bank_mask, nt_bank_mask; //state ByteBuffer chr_regs_2k = new ByteBuffer(4); ByteBuffer nt_regs = new ByteBuffer(2); ByteBuffer prg_regs_16k = new ByteBuffer(2); bool flag_m, flag_r; public override void Dispose() { base.Dispose(); chr_regs_2k.Dispose(); nt_regs.Dispose(); prg_regs_16k.Dispose(); } public override void SyncState(Serializer ser) { base.SyncState(ser); ser.Sync("chr_regs_2k", ref chr_regs_2k); ser.Sync("nt_regs", ref nt_regs); ser.Sync("prg_regs_16k", ref prg_regs_16k); ser.Sync("flag_m", ref flag_m); ser.Sync("flag_r", ref flag_r); } public override bool Configure(NES.EDetectionOrigin origin) { //configure switch (Cart.board_type) { case "MAPPER068": break; case "TENGEN-800042": AssertPrg(128); AssertChr(256); AssertVram(0); AssertWram(0); break; case "SUNSOFT-4": AssertPrg(128); AssertChr(128,256); AssertVram(0); AssertWram(0,8); break; case "UNIF_NES-NTBROM": AssertPrg(128 + 16); AssertChr(128); Cart.wram_size = 8; Cart.vram_size = 0; /* The actual cart had 128k prg, with a small slot on the top that can load an optional daughterboard. * The UNIF dump has this as an extra 16k prg lump. I don't know how this lump is actually used, * though. */ break; default: return false; } SetMirrorType(EMirrorType.Vertical); prg_regs_16k[1] = 0xFF; prg_bank_mask = Cart.prg_size / 16 - 1; if (Cart.prg_size == 128 + 16) prg_bank_mask = 7; // ignore extra prg lump chr_bank_mask = Cart.chr_size / 2 - 1; nt_bank_mask = Cart.chr_size - 1; return true; } public override byte ReadPRG(int addr) { int bank_16k = addr >> 14; int ofs = addr & ((1 << 14) - 1); bank_16k = prg_regs_16k[bank_16k]; bank_16k &= prg_bank_mask; addr = (bank_16k << 14) | ofs; return ROM[addr]; } public override byte ReadPPU(int addr) { if (addr < 0x2000) { //chr comes from normal chr mapping int bank_2k = addr >> 11; int ofs = addr & ((1 << 11) - 1); bank_2k = chr_regs_2k[bank_2k]; bank_2k &= chr_bank_mask; addr = (bank_2k << 11) | ofs; return VROM[addr]; } else { //nametable may come from "NT-ROM" //which means from extra CHR data starting at bank 0x80 if (flag_r) { addr = ApplyMirroring(addr); int bank_1k = (addr >> 10) & 3; int ofs = addr & ((1 << 10) - 1); bank_1k = nt_regs[bank_1k] + 0x80; bank_1k &= nt_bank_mask; addr = (bank_1k << 10) | ofs; return VROM[addr]; } else return base.ReadPPU(addr); } } public override void WritePRG(int addr, byte value) { //Console.WriteLine("W{0:x4} {1:x2}", addr + 0x8000, value); switch (addr & 0xF000) { case 0x0000: //$8000 chr_regs_2k[0] = value; break; case 0x1000: //$9000 chr_regs_2k[1] = value; break; case 0x2000: //$A000 chr_regs_2k[2] = value; break; case 0x3000: //$B000 chr_regs_2k[3] = value; break; case 0x4000: //$C000 nt_regs[0] = (byte)(value & 0x7F); break; case 0x5000: //$D000 nt_regs[1] = (byte)(value & 0x7F); break; case 0x6000: //$E000 flag_m = (value & 1) != 0; flag_r = ((value >> 4) & 1) != 0; if (flag_m) SetMirrorType(EMirrorType.Horizontal); else SetMirrorType(EMirrorType.Vertical); break; case 0x7000: //$F000 prg_regs_16k[0] = value; break; } } } }