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();
}