diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj
index 25aaead3dc..9b8f8d59d4 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 71757f091e..07d0b7ab25 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/Docs/compatibility.txt
+++ b/BizHawk.Emulation/Consoles/Nintendo/Docs/compatibility.txt
@@ -23,6 +23,7 @@ Open bus and bus conflict emulation is not considered complete or thorough in an
009 PxROM=MMC2 Complete
010 MMC4 Complete
011 Misc Complete
+012 DBZ5 Decent (mmc3 variant)
013 CPROM Complete
015 Multicart Junk
016 Bandai Decent
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs
index 8a852eed61..da8f136b58 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs
@@ -312,6 +312,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo
cart.DB_GameInfo = gi;
cart.game = game;
cart.board_type = dict["board"];
+ cart.prg_size = -1;
+ cart.vram_size = -1;
+ cart.wram_size = -1;
+ cart.chr_size = -1;
if (dict.ContainsKey("PRG"))
cart.prg_size = short.Parse(dict["PRG"]);
if (dict.ContainsKey("CHR"))
@@ -324,8 +328,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo
cart.pad_h = byte.Parse(dict["PAD_H"]);
if (dict.ContainsKey("PAD_V"))
cart.pad_v = byte.Parse(dict["PAD_V"]);
- if (dict.ContainsKey("bad"))
+ if (dict.ContainsKey("BAD"))
cart.bad = true;
+ if (dict.ContainsKey("MMC3"))
+ cart.chips.Add(dict["MMC3"]);
return cart;
}
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/MMC3_family.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/MMC3_family.cs
index 4702eec4f5..bcd1043216 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/MMC3_family.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/MMC3_family.cs
@@ -37,10 +37,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo
prg_regs_8k[1] = 1;
prg_regs_8k[2] = 0xFE; //constant
prg_regs_8k[3] = 0xFF; //constant
- prg_regs_8k[4+0] = 0xFE; //constant
- prg_regs_8k[4+1] = 1;
- prg_regs_8k[4+2] = 0;
- prg_regs_8k[4+3] = 0xFF; //constant
+ prg_regs_8k[4 + 0] = 0xFE; //constant
+ prg_regs_8k[4 + 1] = 1;
+ prg_regs_8k[4 + 2] = 0;
+ prg_regs_8k[4 + 3] = 0xFF; //constant
chr_regs_1k[0] = 0;
chr_regs_1k[1] = 1;
@@ -119,9 +119,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo
public byte mirror;
int a12_old;
byte irq_reload, irq_counter;
- protected bool irq_pending, irq_enable;
+ protected 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.
//theres no sense in delaying the IRQ, so its logic must be tied to the separator.
//the hint, of course, is that the countdown value is the same.
@@ -129,11 +129,35 @@ namespace BizHawk.Emulation.Consoles.Nintendo
int separator_counter;
int irq_countdown;
+
+ //configuration
+ public enum EMMC3Type
+ {
+ None, MMC3A, MMC3BSharp, MMC3BNonSharp, MMC3C
+ }
+ EMMC3Type _mmc3type = EMMC3Type.None;
+ public EMMC3Type MMC3Type
+ {
+ get { return _mmc3type; }
+ set
+ {
+ _mmc3type = value;
+ oldIrqType = (_mmc3type == EMMC3Type.MMC3A || _mmc3type == EMMC3Type.MMC3BNonSharp);
+ }
+ }
+ bool oldIrqType;
+
+
public NES.NESBoardBase.EMirrorType MirrorType { get { return mirror == 0 ? NES.NESBoardBase.EMirrorType.Vertical : NES.NESBoardBase.EMirrorType.Horizontal; } }
public MMC3(NES.NESBoardBase board, int num_prg_banks)
: base(board)
{
+ if (board.Cart.chips.Contains("MMC3A")) MMC3Type = EMMC3Type.MMC3A;
+ else if (board.Cart.chips.Contains("MMC3B")) MMC3Type = EMMC3Type.MMC3BSharp;
+ else if (board.Cart.chips.Contains("MMC3BNONSHARP")) MMC3Type = EMMC3Type.MMC3BNonSharp;
+ else if (board.Cart.chips.Contains("MMC3C")) MMC3Type = EMMC3Type.MMC3C;
+ else MMC3Type = EMMC3Type.MMC3C; //arbitrary choice. is it the best choice?
}
public override void SyncState(Serializer ser)
@@ -147,6 +171,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
ser.Sync("irq_enable", ref irq_enable);
ser.Sync("separator_counter", ref separator_counter);
ser.Sync("irq_countdown", ref irq_countdown);
+ ser.Sync("irq_reload_flag", ref irq_reload_flag);
ser.Sync("wram_enable", ref wram_enable);
ser.Sync("wram_write_protect", ref wram_write_protect);
}
@@ -180,6 +205,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
break;
case 0x4001: //$C001 - IRQ Clear
irq_counter = 0;
+ if (oldIrqType)
+ irq_reload_flag = true;
break;
case 0x6000: //$E000 - IRQ Acknowledge / Disable
irq_enable = false;
@@ -206,23 +233,27 @@ namespace BizHawk.Emulation.Consoles.Nintendo
void ClockIRQ()
{
- if (irq_counter == 0)
+ int last_irq_counter = irq_counter;
+ if (irq_reload_flag || irq_counter == 0)
{
irq_counter = irq_reload;
-
- //TODO - MMC3 variant behaviour??? not sure
- //was needed to pass 2-details.nes
- if (irq_counter == 0)
- IRQ_EQ_Pass();
}
else
{
irq_counter--;
- if (irq_counter == 0)
- {
- IRQ_EQ_Pass();
- }
}
+ if (irq_counter == 0)
+ {
+ if (oldIrqType)
+ {
+ if (last_irq_counter != 0 || irq_reload_flag)
+ IRQ_EQ_Pass();
+ }
+ else
+ IRQ_EQ_Pass();
+ }
+
+ irq_reload_flag = false;
}
public virtual void ClockPPU()
@@ -250,12 +281,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo
{
if (separator_counter > 0)
{
- separator_counter = 15;
+ separator_counter = 12;
}
else
{
- separator_counter = 15;
- irq_countdown = 15;
+ separator_counter = 12;
+ irq_countdown = 12;
}
}
@@ -382,7 +413,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
wram_mask = (Cart.wram_size * 1024) - 1;
int num_prg_banks = Cart.prg_size / 8;
- mapper = mmc3 = new MMC3(this,num_prg_banks);
+ mapper = mmc3 = new MMC3(this, num_prg_banks);
base.BaseSetup();
SetMirrorType(EMirrorType.Vertical);
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper012.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper012.cs
new file mode 100644
index 0000000000..bc2af84d9b
--- /dev/null
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/MMC3_family/Mapper012.cs
@@ -0,0 +1,57 @@
+using System;
+using System.IO;
+using System.Diagnostics;
+
+namespace BizHawk.Emulation.Consoles.Nintendo
+{
+ public class Mapper012 : MMC3Board_Base
+ {
+ public override bool Configure(NES.EDetectionOrigin origin)
+ {
+ //analyze board type
+ switch (Cart.board_type)
+ {
+ case "MAPPER012":
+ break;
+ default:
+ return false;
+ }
+
+ BaseSetup();
+ mmc3.MMC3Type = MMC3.EMMC3Type.MMC3A;
+
+ return true;
+ }
+
+ public override void SyncState(Serializer ser)
+ {
+ base.SyncState(ser);
+ ser.Sync("block0", ref block0);
+ ser.Sync("block1", ref block1);
+ }
+
+ int block0, block1;
+
+ public override void WritePRG(int addr, byte value)
+ {
+ base.WritePRG(addr, value);
+ }
+
+ public override void WriteEXP(int addr, byte value)
+ {
+ base.WriteEXP(addr, value);
+ block0 = value & 1;
+ block1 = (value >> 4) & 1;
+ }
+
+ protected override int Get_CHRBank_1K(int addr)
+ {
+ int bank_1k = base.Get_CHRBank_1K(addr);
+ if (addr < 0x1000)
+ bank_1k += (block0 << 8);
+ else bank_1k += (block1 << 8);
+ return bank_1k;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs
index 6d2ab9484b..9e9d473fa4 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs
@@ -487,6 +487,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo
{
origin = EDetectionOrigin.GameDB;
LoadWriteLine("Chose board from bizhawk gamedb: " + choice.board_type);
+ //gamedb entries that dont specify prg/chr sizes can infer it from the ines header
+ if (choice.prg_size == -1) choice.prg_size = iNesHeaderInfo.prg_size;
+ if (choice.chr_size == -1) choice.chr_size = iNesHeaderInfo.chr_size;
+ if (choice.vram_size == -1) choice.vram_size = iNesHeaderInfo.vram_size;
+ if (choice.wram_size == -1) choice.wram_size = iNesHeaderInfo.wram_size;
}
}
else
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.regs.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.regs.cs
index c2fbb6a776..ea9f7ff32e 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.regs.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.regs.cs
@@ -441,7 +441,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo
//the address isnt observed by the board till it gets clocked by a read or write.
//nes.board.AddressPPU(ppur.get_2007access());
}
+
vtoggle ^= true;
+
+ int addr = ppur.get_2007access() & 0x3FFF;
+ nes.board.AddressPPU(addr);
}
byte read_2006() { return PPUGenLatch; }
@@ -471,9 +475,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo
ppubus_write(addr, value);
}
- nes.board.AddressPPU(addr);
-
ppur.increment2007(ppur.status.rendering && reg_2001.PPUON, reg_2000.vram_incr32 != 0);
+
+ addr = ppur.get_2007access() & 0x3FFF;
+ nes.board.AddressPPU(addr);
}
byte read_2007()
{
@@ -492,9 +497,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo
ret = PALRAM[addr & 0x1F];
}
- nes.board.AddressPPU(addr);
-
ppur.increment2007(ppur.status.rendering && reg_2001.PPUON, reg_2000.vram_incr32 != 0);
+
+ addr = ppur.get_2007access() & 0x3FFF;
+ nes.board.AddressPPU(addr);
return ret;
}
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/iNES.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/iNES.cs
index 64f06d4a92..6e2a46b261 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/iNES.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/iNES.cs
@@ -11,116 +11,17 @@ namespace BizHawk.Emulation.Consoles.Nintendo
partial class NES
{
///
- /// attempts to classify a rom based on iNES header information
+ /// attempts to classify a rom based on iNES header information.
+ /// this used to be way more complex. but later, we changed to have a board class implement a "MAPPERXXX" virtual board type and all hacks will be in there
+ /// so theres nothing to do here but pick the board type corresponding to the cart
///
static class iNESBoardDetector
{
public static string Detect(CartInfo cartInfo)
{
- string key = string.Format("{0} {1} {2} {3} {4}", cartInfo.mapper, cartInfo.prg_size, cartInfo.chr_size, cartInfo.wram_size, cartInfo.vram_size);
- string board;
- Table.TryGetValue(key, out board);
- if (board == null)
- {
- //if it didnt work, try again with a different wram size. because iNES is weird that way
- key = string.Format("{0} {1} {2} {3} {4}", cartInfo.mapper, cartInfo.prg_size, cartInfo.chr_size, 8, cartInfo.vram_size);
- if (!Table.TryGetValue(key, out board))
- {
- //if it still didnt work, look for one with empty keys, to detect purely based on mapper
- key = string.Format("{0} {1} {2} {3} {4}", cartInfo.mapper, -1, -1, -1, -1);
- Table.TryGetValue(key, out board);
- }
- }
- return board;
+ return string.Format("MAPPER{0:d3}",cartInfo.mapper);
}
-
- public static Dictionary Table = new Dictionary();
- static iNESBoardDetector()
- {
- var sr = new StringReader(ClassifyTable);
- string line;
- while ((line = sr.ReadLine()) != null)
- {
- var parts = line.Split('\t');
- if (parts.Length < 6) continue;
- string key = parts[0] + "\t" + parts[1] + "\t" + parts[2] + "\t" + parts[3] + "\t" + parts[4];
- string board = line.Replace(key, "");
- board = board.TrimStart('\t');
- if (board.IndexOf(';') != -1)
- board = board.Substring(0, board.IndexOf(';'));
- Table[key] = board;
- }
- }
-
-//what to do about 034?
-
-//MAP PRG CHR WRAM VRAM BOARD
-static string ClassifyTable = @"
-0 -1 -1 -1 -1 MAPPER000
-1 -1 -1 -1 -1 MAPPER001
-2 -1 -1 -1 -1 MAPPER002
-3 -1 -1 -1 -1 MAPPER003
-4 -1 -1 -1 -1 MAPPER004
-5 -1 -1 -1 -1 MAPPER005
-7 -1 -1 -1 -1 MAPPER007
-9 -1 -1 -1 -1 MAPPER009
-10 -1 -1 -1 -1 MAPPER010
-11 -1 -1 -1 -1 MAPPER011
-13 -1 -1 -1 -1 MAPPER013
-19 -1 -1 -1 -1 MAPPER019
-21 -1 -1 -1 -1 MAPPER021
-22 -1 -1 -1 -1 MAPPER022
-23 -1 -1 -1 -1 MAPPER023
-23 -1 -1 -1 -1 MAPPER023
-25 -1 -1 -1 -1 MAPPER025
-26 -1 -1 -1 -1 MAPPER026
-32 -1 -1 -1 -1 MAPPER032
-33 -1 -1 -1 -1 MAPPER033
-44 -1 -1 -1 -1 MAPPER044
-46 -1 -1 -1 -1 MAPPER046
-49 -1 -1 -1 -1 MAPPER049
-64 -1 -1 -1 -1 MAPPER064
-65 -1 -1 -1 -1 MAPPER065
-66 -1 -1 -1 -1 MAPPER066
-68 -1 -1 -1 -1 MAPPER068
-69 -1 -1 -1 -1 MAPPER069
-70 -1 -1 -1 -1 MAPPER070
-71 -1 -1 -1 -1 MAPPER071
-72 -1 -1 -1 -1 MAPPER072
-73 -1 -1 -1 -1 MAPPER073
-75 -1 -1 -1 -1 MAPPER075
-77 -1 -1 -1 -1 MAPPER077
-78 -1 -1 -1 -1 MAPPER078
-79 -1 -1 -1 -1 MAPPER079
-80 -1 -1 -1 -1 MAPPER080
-82 -1 -1 -1 -1 MAPPER082
-85 -1 -1 -1 -1 MAPPER085
-86 -1 -1 -1 -1 MAPPER086
-87 -1 -1 -1 -1 MAPPER087
-89 -1 -1 -1 -1 MAPPER089
-93 -1 -1 -1 -1 MAPPER093
-97 -1 -1 -1 -1 MAPPER097
-105 -1 -1 -1 -1 MAPPER105
-107 -1 -1 -1 -1 MAPPER107
-113 -1 -1 -1 -1 MAPPER113
-115 -1 -1 -1 -1 MAPPER115
-140 -1 -1 -1 -1 MAPPER140
-152 -1 -1 -1 -1 MAPPER152
-164 -1 -1 -1 -1 MAPPER164
-180 -1 -1 -1 -1 MAPPER180
-182 -1 -1 -1 -1 MAPPER182
-184 -1 -1 -1 -1 MAPPER184
-189 -1 -1 -1 -1 MAPPER189
-191 -1 -1 -1 -1 MAPPER191
-193 -1 -1 -1 -1 MAPPER193
-210 -1 -1 -1 -1 MAPPER210
-227 -1 -1 -1 -1 MAPPER227
-232 -1 -1 -1 -1 MAPPER232
-240 -1 -1 -1 -1 MAPPER240
-242 -1 -1 -1 -1 MAPPER242
-248 -1 -1 -1 -1 MAPPER248
-";
-}
+ }
unsafe struct iNES_HEADER
{
diff --git a/BizHawk.MultiClient/output/gamedb.txt b/BizHawk.MultiClient/output/gamedb.txt
index b5a2fab0f2..95dae2eb5d 100644
--- a/BizHawk.MultiClient/output/gamedb.txt
+++ b/BizHawk.MultiClient/output/gamedb.txt
@@ -119,5 +119,11 @@ sha1:EC652EE1660E527098102E26A36A8B9B7BB3943F Castlevania (Konami Collection 20
sha1:B5C4E5E858113F5AA5E063BC79A12D7F6B856E6C Contra (Konami Collection 2002) NES board=NES-UNROM;PRG=128;WRAM=0;VRAM=8;PAD_H=1
;;;;;;;;;;;;;;;;;;;-----------------------------------------------------------------------
+;;;;;;;;;;;;;;;;;;;-----------------------------------------------------------------------
+;mmc3 homebrews that need chip specification
+sha1:35C157A921156E47FD3F6573D150F54108D0EDFC Blargg's 5.MMC3_rev_A.nes NES board=MAPPER004;MMC3=MMC3A
+sha1:0E971E2CCAD1DEE51A0C305ED38FAFD2E6CA3B41 Blargg's 6.MMC3_rev_B.nes NES board=MAPPER004;MMC3=MMC3B
+;;;;;;;;;;;;;;;;;;;-----------------------------------------------------------------------
+
#include gamedb_neshomebrew.txt
#include gamedb_user.txt