From 50d4564e0eca995f720c134f25b1a89f376a82cb Mon Sep 17 00:00:00 2001 From: zeromus Date: Sat, 23 Jun 2012 08:52:12 +0000 Subject: [PATCH] nes-support mapper 116 --- BizHawk.Emulation/BizHawk.Emulation.csproj | 1 + .../Consoles/Nintendo/Docs/compatibility.txt | 1 + .../Consoles/Nintendo/NES/BoardSystem.cs | 5 + .../Nintendo/NES/Boards/MMC3_family/MMC3.cs | 15 +- .../Nintendo/NES/Boards/MMC3_family/TxROM.cs | 3 + .../Consoles/Nintendo/NES/Boards/Mapper116.cs | 237 ++++++++++++++++++ .../Consoles/Nintendo/NES/Boards/SxROM.cs | 19 +- .../Consoles/Nintendo/NES/Boards/VRC2_4.cs | 44 ++-- .../Consoles/Nintendo/NES/NES.cs | 3 +- 9 files changed, 300 insertions(+), 28 deletions(-) create mode 100644 BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Mapper116.cs diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj index 4ee9e1ea5c..612af9f6b1 100644 --- a/BizHawk.Emulation/BizHawk.Emulation.csproj +++ b/BizHawk.Emulation/BizHawk.Emulation.csproj @@ -147,6 +147,7 @@ + diff --git a/BizHawk.Emulation/Consoles/Nintendo/Docs/compatibility.txt b/BizHawk.Emulation/Consoles/Nintendo/Docs/compatibility.txt index c088857db1..1965611b44 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/Docs/compatibility.txt +++ b/BizHawk.Emulation/Consoles/Nintendo/Docs/compatibility.txt @@ -87,6 +87,7 @@ Open bus and bus conflict emulation is not considered complete or thorough in an 112 Misc (CN) Nothing 113 =USELESS= Junk 115 MMC3Variant Decent +116 Unlicensed Minimal (missing correct mirroring logic) 118 TLSROM Complete 119 TQROM Complete 140 Misc (J) Complete diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs index eb1893c835..715c1ffaeb 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs @@ -76,6 +76,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo for (int i = 0; i < 4; i++) ser.Sync("mirroring" + i, ref mirroring[i]); } + public virtual void SyncIRQ(bool flag) + { + NES.irq_cart = flag; + } + public virtual void Dispose() { } int[] mirroring = new int[4]; diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/MMC3.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/MMC3.cs index 216bc58b40..02a6f33776 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/MMC3.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/MMC3.cs @@ -14,12 +14,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo //state int reg_addr; bool chr_mode, prg_mode; - ByteBuffer regs = new ByteBuffer(8); + public ByteBuffer regs = new ByteBuffer(8); public byte mirror; int a12_old; byte irq_reload, irq_counter; - protected bool irq_pending, irq_enable, irq_reload_flag; + public bool irq_pending, irq_enable, irq_reload_flag; public bool wram_enable, wram_write_protect; //it really seems like these should be the same but i cant seem to unify them. @@ -72,7 +72,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo Sync(); } - void Sync() + public void Sync() { if (prg_mode) { @@ -140,7 +140,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo protected virtual void SyncIRQ() { - board.NES.irq_cart = irq_pending; + board.SyncIRQ(irq_pending); } public void WritePRG(int addr, byte value) @@ -279,7 +279,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo public abstract class MMC3Board_Base : NES.NESBoardBase { //state - protected MMC3 mmc3; + public MMC3 mmc3; + public int extra_vrom; + public override void AddressPPU(int addr) { @@ -303,6 +305,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo { base.SyncState(ser); mmc3.SyncState(ser); + ser.Sync("extra_vrom", ref extra_vrom); } protected virtual int Get_CHRBank_1K(int addr) @@ -329,7 +332,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo { addr = MapCHR(addr); if (VROM != null) - return VROM[addr]; + return VROM[addr + extra_vrom]; else return VRAM[addr]; } else return base.ReadPPU(addr); diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/TxROM.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/TxROM.cs index 5b3db1a88a..649bcc58c5 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/TxROM.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/TxROM.cs @@ -37,6 +37,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo //analyze board type switch (Cart.board_type) { + case "MAPPER116_HACKY": + break; + case "MAPPER004": break; case "NES-TBROM": //tecmo world cup soccer (DE) [untested] diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Mapper116.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Mapper116.cs new file mode 100644 index 0000000000..1099a40373 --- /dev/null +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Mapper116.cs @@ -0,0 +1,237 @@ +//TODO - emulation of mirroring is all bolloxed. + +using System; +using System.IO; +using System.Diagnostics; + +namespace BizHawk.Emulation.Consoles.Nintendo +{ + class Mapper116 : NES.NESBoardBase + { + class MMC3_CustomBoard : MMC3Board_Base + { + public override void WritePRG(int addr, byte value) + { + base.WritePRG(addr, value); + SetMirrorType(mmc3.MirrorType); //often redundant, but gets the job done + } + + public override bool Configure(NES.EDetectionOrigin origin) + { + BaseSetup(); + return true; + } + + public MMC3_CustomBoard(Mapper116 master) + { + this.master = master; + } + + public override void SyncIRQ(bool flag) + { + master.SyncIRQ(flag); + } + + Mapper116 master; + + } + + //configuration + + //state + int mode; + SxROM mmc1; + MMC3_CustomBoard mmc3; + VRC2_4 vrc2; + + public override void SyncState(Serializer ser) + { + ser.Sync("mod", ref mode); + mmc1.SyncState(ser); + mmc3.SyncState(ser); + vrc2.SyncState(ser); + SyncIRQ(mmc3.mmc3.irq_pending); + } + + public override bool Configure(NES.EDetectionOrigin origin) + { + string oldBoardType = Cart.board_type; + + //configure + switch (Cart.board_type) + { + case "MAPPER116": + break; + default: + return false; + } + + SetMirrorType(Cart.pad_h, Cart.pad_v); + + Cart.board_type = "MAPPER116_HACKY"; + + vrc2 = new VRC2_4(); + vrc2.Create(NES); + vrc2.Configure(origin); + //not exactly the same as fceu-mm. is it important? + for(int i=0;i<16;i++) + vrc2.chr_bank_reg_1k[i] = 0x0F; + vrc2.SyncCHR(); + + mmc3 = new MMC3_CustomBoard(this); + mmc3.Create(NES); + mmc3.Configure(origin); + + //is this important? not sure. + mmc3.mmc3.regs[0] = 0; + mmc3.mmc3.regs[1] = 2; + mmc3.mmc3.regs[2] = 3; + mmc3.mmc3.regs[3] = 4; + mmc3.mmc3.regs[4] = 5; + mmc3.mmc3.regs[5] = 7; + mmc3.mmc3.Sync(); + + mmc1 = new SxROM(); + mmc1.Create(NES); + mmc1.Configure(origin); + mmc1_reset(); + + Cart.board_type = oldBoardType; + + mode = 0; + Sync(); + + return true; + } + + public override void PostConfigure() + { + SyncRoms(); + base.PostConfigure(); + } + + public override void SyncIRQ(bool flag) + { + if(mode == 1) + base.SyncIRQ(flag); + } + + void SyncRoms() + { + foreach (var board in new NES.NESBoardBase[] { mmc3, vrc2, mmc1 }) + { + board.ROM = ROM; + board.VROM = VROM; + board.VRAM = VRAM; + board.WRAM = WRAM; + } + } + + void Sync() + { + } + + void mmc1_reset() + { + mmc1.mmc1.StandardReset(); + } + + void WriteModeControl(int addr, byte value) + { + if ((addr & 0x4100) != 0x4100) return; + mode = value & 3; + bool chr_base = value.Bit(2); + + vrc2.extra_vrom = mmc3.extra_vrom = chr_base ? 256 * 1024 : 0; + + //fceu-mm has special "hacky hacky" logic here to initialize mmc1 a special way sometimes. read about it on the nesdevwiki. not sure how important it is + if ((addr & 1) == 1) + { + mmc1_reset(); + } + + Sync(); + if(mode == 1) SyncIRQ(mmc3.mmc3.irq_pending); + Console.Write("MODE: {0} ",mode); + if (mode == 0) Console.WriteLine("(vrc2)"); + if (mode == 1) Console.WriteLine("(mmc3)"); + if (mode == 2) Console.WriteLine("(mmc1)"); + if (mode == 3) Console.WriteLine("(mmc1)"); + } + + public override void WriteEXP(int addr, byte value) + { + WriteModeControl(addr + 0x4000, value); + } + + public override void WritePPU(int addr, byte value) + { + switch (mode) + { + case 0: vrc2.WritePPU(addr, value); break; + case 1: mmc3.WritePPU(addr, value); break; + case 2: + case 3: mmc1.WritePPU(addr, value); break; + } + } + + public override byte ReadPPU(int addr) + { + switch (mode) + { + case 0: return vrc2.ReadPPU(addr); + case 1: return mmc3.ReadPPU(addr); + case 2: + case 3: return mmc1.ReadPPU(addr); + + } + return 0; + } + + public override void WritePRG(int addr, byte value) + { + Console.WriteLine("{0:X4} = {1:X2}", addr+0x8000, value); + switch (mode) + { + case 0: + addr += 0x8000; + if((addr & 0xF000) < 0xB000) addr &= 0xF000; //Garou Densetsu Special depends on this + addr -= 0x8000; + + vrc2.WritePRG(addr, value); + break; + case 1: mmc3.WritePRG(addr, value); break; + case 2: + case 3: mmc1.WritePRG(addr, value); break; + } + } + + public override byte ReadPRG(int addr) + { + switch (mode) + { + case 0: return vrc2.ReadPRG(addr); + case 1: return mmc3.ReadPRG(addr); + case 2: + case 3: return mmc1.ReadPRG(addr); + } + return 0; + } + + public override void AddressPPU(int addr) + { + mmc3.AddressPPU(addr); + } + + public override void ClockPPU() + { + mmc3.ClockPPU(); + } + + + public override void SyncState(Serializer ser) + { + base.SyncState(ser); + } + } +} diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/SxROM.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/SxROM.cs index f09ca796f6..9256da9adb 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/SxROM.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/SxROM.cs @@ -27,7 +27,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo public class MMC1 { NES.NESBoardBase board; - MMC1_SerialController scnt = new MMC1_SerialController(); + public MMC1_SerialController scnt = new MMC1_SerialController(); public MMC1(NES.NESBoardBase board) { @@ -89,6 +89,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo public Action Reset; public Action WriteRegister; + public void ResetShift() + { + shift_count = shift_val = 0; + } + public void Write(int addr, byte value) { int data = value & 1; @@ -121,11 +126,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo prg_slot = 1; } - void StandardReset() + public void StandardReset() { prg_mode = 1; prg_slot = 1; chr_mode = 1; + scnt.Reset(); mirror = NES.NESBoardBase.EMirrorType.Horizontal; } @@ -134,7 +140,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo scnt.Write(addr, value); } - void SerialWriteRegister(int addr, int value) + //logical register writes, called from the serial controller + public void SerialWriteRegister(int addr, int value) { switch (addr) { @@ -156,7 +163,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo break; } //board.NES.LogLine("mapping.. chr_mode={0}, chr={1},{2}", chr_mode, chr_0, chr_1); - //board.NES.LogLine("mapping.. prg_mode={0}, prg_slot{1}, prg={2}", prg_mode, prg_slot, prg); + board.NES.LogLine("mapping.. prg_mode={0}, prg_slot{1}, prg={2}", prg_mode, prg_slot, prg); } public int Get_PRGBank(int addr) @@ -201,7 +208,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo protected int vram_mask; //state - protected MMC1 mmc1; + public MMC1 mmc1; public override void WritePRG(int addr, byte value) { @@ -254,6 +261,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo { switch (Cart.board_type) { + case "MAPPER116_HACKY": + break; case "MAPPER001": break; case "NES-SAROM": //dragon warrior diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC2_4.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC2_4.cs index c3535e6144..07ad67a830 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC2_4.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/VRC2_4.cs @@ -1,4 +1,6 @@ -using System; +//TODO - for chr, refactor to use 8 registers of 8 bits instead of 16 registers of 4 bits. more realistic, less weird code. + +using System; using System.IO; using System.Diagnostics; @@ -10,21 +12,23 @@ namespace BizHawk.Emulation.Consoles.Nintendo { //configuration int prg_bank_mask_8k, chr_bank_mask_1k; + int prg_reg_mask_8k; Func remap; Func fix_chr; int type; //state - int[] prg_bank_reg_8k = new int[2]; - int[] chr_bank_reg_1k = new int[16]; + public int[] prg_bank_reg_8k = new int[2]; + public int[] chr_bank_reg_1k = new int[16]; bool prg_mode; ByteBuffer prg_banks_8k = new ByteBuffer(4); - ByteBuffer chr_banks_1k = new ByteBuffer(8); + public ByteBuffer chr_banks_1k = new ByteBuffer(8); bool irq_mode; bool irq_enabled, irq_pending, irq_autoen; byte irq_reload; byte irq_counter; int irq_prescaler; + public int extra_vrom; public override void Dispose() { @@ -45,6 +49,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo ser.Sync("irq_reload", ref irq_reload); ser.Sync("irq_counter", ref irq_counter); ser.Sync("irq_prescaler", ref irq_prescaler); + ser.Sync("extra_vrom", ref extra_vrom); if (ser.IsReader) { @@ -71,7 +76,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo } } - void SyncCHR() + public void SyncCHR() { //Console.Write("{0}: ", NES.ppu.ppur.status.sl); for (int i = 0; i < 8; i++) @@ -102,6 +107,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo case "MAPPER025": throw new InvalidOperationException("someone will need to bug me to set these up for failsafe mapping"); + case "MAPPER116_HACKY": + remap = (addr) => addr; + type = 2; + break; + case "KONAMI-VRC-4": AssertPrg(128,256); AssertChr(128,256); AssertVram(0); AssertWram(0,2,8); type = 4; @@ -134,7 +144,15 @@ namespace BizHawk.Emulation.Consoles.Nintendo prg_bank_mask_8k = Cart.prg_size / 8 - 1; chr_bank_mask_1k = Cart.chr_size - 1; - prg_bank_reg_8k[0] = prg_bank_reg_8k[1] = 0; + if(type == 4) prg_reg_mask_8k = 0x1F; + else prg_reg_mask_8k = 0xF; + + //this VRC2 variant has an extra large PRG reg + if (Cart.board_type == "MAPPER116_HACKY") + prg_reg_mask_8k = 0x1F; + + prg_bank_reg_8k[0] = 0; + prg_bank_reg_8k[1] = 1; SyncPRG(); SyncCHR(); SetMirrorType(EMirrorType.Vertical); @@ -159,7 +177,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo int ofs = addr & ((1 << 10) - 1); bank_1k = chr_banks_1k[bank_1k]; addr = (bank_1k << 10) | ofs; - return VROM[addr]; + return VROM[addr + extra_vrom]; } else return base.ReadPPU(addr); } @@ -171,17 +189,14 @@ namespace BizHawk.Emulation.Consoles.Nintendo switch (addr) { default: - Console.WriteLine("missed case: {0:X4}", addr); + Console.WriteLine("missed case: {0:X4}", addr + 0x8000); break; case 0x0000: //$8000 case 0x0001: case 0x0002: case 0x0003: - if(type==4) - prg_bank_reg_8k[0] = value & 0x1F; - else - prg_bank_reg_8k[0] = value & 0xF; + prg_bank_reg_8k[0] = value & prg_reg_mask_8k; SyncPRG(); break; @@ -207,10 +222,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo case 0x2001: //$A001 case 0x2002: //$A002 case 0x2003: //$A003 - if(type==4) - prg_bank_reg_8k[1] = value & 0x1F; - else - prg_bank_reg_8k[1] = value & 0xF; + prg_bank_reg_8k[1] = value & prg_reg_mask_8k; SyncPRG(); break; diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs index 3bf5ecee63..c7ca1f9c56 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs @@ -530,7 +530,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo cart = choice; board.Create(this); board.Configure(origin); - board.PostConfigure(); if (origin == EDetectionOrigin.BootGodDB) { @@ -573,6 +572,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo if (cart.vram_size != 0) board.VRAM = new byte[cart.vram_size * 1024]; + board.PostConfigure(); + HardReset(); SetupMemoryDomains(); }