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