nes-add mapper012 (mmc3 variant, for dragon ball z 5). add concept of mmc3 chip revision variants to mmc3 code and game database, and add proper emulation thereof. pass a bunch of mmc3 tests. simplify (to almost nothing) iNES board detection to correspond to new paradigms of virtual board types. your savestates for mmc3 games are invalidated.

This commit is contained in:
zeromus 2012-04-14 08:28:42 +00:00
parent a1d798cc8f
commit 73fba31c34
9 changed files with 143 additions and 129 deletions

View File

@ -147,6 +147,7 @@
<Compile Include="Consoles\Nintendo\NES\Boards\Mapper046.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\DRROM.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\HKROM.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper012.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper044.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper049.cs" />
<Compile Include="Consoles\Nintendo\NES\Boards\MMC3_family\Mapper095.cs" />

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -11,116 +11,17 @@ namespace BizHawk.Emulation.Consoles.Nintendo
partial class NES
{
/// <summary>
/// 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
/// </summary>
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<string, string> Table = new Dictionary<string, string>();
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
{

View File

@ -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