diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj
index 9d387a75a1..655dfd0770 100644
--- a/BizHawk.Emulation/BizHawk.Emulation.csproj
+++ b/BizHawk.Emulation/BizHawk.Emulation.csproj
@@ -76,6 +76,7 @@
Code
+
diff --git a/BizHawk.Emulation/Buffer.cs b/BizHawk.Emulation/Buffer.cs
index c8c9275330..c20925a022 100644
--- a/BizHawk.Emulation/Buffer.cs
+++ b/BizHawk.Emulation/Buffer.cs
@@ -69,7 +69,15 @@ namespace BizHawk
{
public ByteBuffer(int amt) : base(amt) { }
public ByteBuffer(byte[] arr) : base(arr) { }
- public byte this[int index] { get { return Read08(index); } set { Write08(index, value); } }
+ public byte this[int index]
+ {
+ #if DEBUG
+ get { return arr[index]; }
+ set { arr[index] = value; }
+ #else
+ set { Write08(index, value); }
+ get { return Read08(index);}
+ #endif
+ }
}
-
}
\ No newline at end of file
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs
index bd9d57a69a..f7f496a33c 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs
@@ -6,6 +6,7 @@ using System.IO;
using System.Collections.Generic;
//TODO - consider bytebuffer for mirroring
+//TODO - could stringpool the bootgod DB for a pedantic optimization
namespace BizHawk.Emulation.Consoles.Nintendo
{
@@ -223,6 +224,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
public bool wram_battery;
public string board_type;
+ public string pcb;
public string sha1;
public string system;
@@ -230,7 +232,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
public override string ToString()
{
- return string.Format("pr={0},ch={1},wr={2},vr={3},ba={4},pa={5}|{6},brd={7},map={8},sys={9}", prg_size, chr_size, wram_size, vram_size, wram_battery?1:0, pad_h, pad_v, board_type, mapper, system);
+ return string.Format("map={0},pr={1},ch={2},wr={3},vr={4},ba={5},pa={6}|{7},brd={8},sys={9}", mapper, prg_size, chr_size, wram_size, vram_size, wram_battery ? 1 : 0, pad_h, pad_v, board_type, system);
}
}
@@ -241,10 +243,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo
{
public string name;
public List carts = new List();
- public override string ToString()
- {
- return string.Format("name={0}", name);
- }
}
///
@@ -371,6 +369,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
if (xmlreader.NodeType == XmlNodeType.Element && xmlreader.Name == "board")
{
currCart.board_type = xmlreader.GetAttribute("type");
+ currCart.pcb = xmlreader.GetAttribute("pcb");
int mapper = byte.Parse(xmlreader.GetAttribute("mapper"));
if (validate && mapper > 255) throw new Exception("didnt expect mapper>255!");
currCart.mapper = (byte)mapper;
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Irem_G101.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Irem_G101.cs
new file mode 100644
index 0000000000..e13e972031
--- /dev/null
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Irem_G101.cs
@@ -0,0 +1,162 @@
+using System;
+using System.IO;
+using System.Diagnostics;
+
+namespace BizHawk.Emulation.Consoles.Nintendo
+{
+ //AKA mapper 032
+
+ //Image Fight
+ //Major League
+ //Kaiketsu Yanchamaru 2
+
+ class Irem_G101 : NES.NESBoardBase
+ {
+ //configuration
+ int prg_bank_mask, chr_bank_mask;
+ bool oneScreenHack;
+
+ //state
+ ByteBuffer prg_regs_8k = new ByteBuffer(8);
+ ByteBuffer chr_regs_1k = new ByteBuffer(8);
+ int prg_mode, mirror_mode;
+
+ public override void Dispose()
+ {
+ prg_regs_8k.Dispose();
+ chr_regs_1k.Dispose();
+ }
+
+ public override bool Configure(NES.EDetectionOrigin origin)
+ {
+ //configure
+ switch (Cart.board_type)
+ {
+ case "IREM-G101":
+ if (Cart.pcb == "UNAMED-IF-13")
+ {
+ //special case for major league
+ oneScreenHack = true;
+ }
+ AssertPrg(128, 256); AssertChr(128); AssertWram(0, 8); AssertVram(0);
+ break;
+ default:
+ return false;
+ }
+
+ prg_bank_mask = Cart.prg_size / 8 - 1;
+ chr_bank_mask = Cart.chr_size - 1;
+
+ prg_regs_8k[0] = 0x00;
+ prg_regs_8k[1] = 0x01;
+ prg_regs_8k[2] = 0xFE; //constant
+ prg_regs_8k[3] = 0xFF; //constant
+ prg_regs_8k[4] = 0xFE; //constant //** NOTE ** according to disch's doc this would be fixed to 0. but it needs to be this to work. someone should let him know.
+ prg_regs_8k[5] = 0x01;
+ prg_regs_8k[6] = 0x00;
+ prg_regs_8k[7] = 0xFF; //constant
+
+ SyncMirror();
+
+ return true;
+ }
+
+ void SyncMirror()
+ {
+ if (oneScreenHack)
+ SetMirrorType(EMirrorType.OneScreenA);
+ else
+ if (mirror_mode == 0)
+ SetMirrorType(EMirrorType.Vertical);
+ else SetMirrorType(EMirrorType.Horizontal);
+ }
+
+ public override void WritePRG(int addr, byte value)
+ {
+ addr &= 0xF007;
+ switch (addr)
+ {
+ //$8000-$8007: [PPPP PPPP] PRG Reg 0
+ case 0x0000:
+ case 0x0001:
+ case 0x0002:
+ case 0x0003:
+ case 0x0004:
+ case 0x0005:
+ case 0x0006:
+ case 0x0007:
+ prg_regs_8k[0] = value;
+ prg_regs_8k[4 + 2] = value;
+ break;
+
+ //$9000-$9007: [.... ..PM]
+ //P = PRG Mode
+ //M = Mirroring (0=Vert, 1=Horz) **Ignore for Major League**
+ case 0x1000:
+ case 0x1001:
+ case 0x1002:
+ case 0x1003:
+ case 0x1004:
+ case 0x1005:
+ case 0x1006:
+ case 0x1007:
+ prg_mode = (value >> 1) & 1;
+ prg_mode <<= 2;
+ mirror_mode = value & 1;
+ SyncMirror();
+ break;
+
+ //$A000-$A007: [PPPP PPPP] PRG Reg 1
+ case 0x2000:
+ case 0x2001:
+ case 0x2002:
+ case 0x2003:
+ case 0x2004:
+ case 0x2005:
+ case 0x2006:
+ case 0x2007:
+ prg_regs_8k[1] = value;
+ prg_regs_8k[4 + 1] = value;
+ break;
+
+ //$B000-$B007: [CCCC CCCC] CHR Regs
+ case 0x3000:
+ case 0x3001:
+ case 0x3002:
+ case 0x3003:
+ case 0x3004:
+ case 0x3005:
+ case 0x3006:
+ case 0x3007:
+ chr_regs_1k[addr - 0x3000] = value;
+ break;
+ }
+ }
+
+ public override byte ReadPPU(int addr)
+ {
+ if (addr < 0x2000)
+ {
+ int bank_1k = addr >> 10;
+ int ofs = addr & ((1 << 10) - 1);
+ bank_1k = chr_regs_1k[bank_1k];
+ bank_1k &= chr_bank_mask;
+ addr = (bank_1k << 10) | ofs;
+ return VROM[addr];
+ }
+ else
+ return base.ReadPPU(addr);
+ }
+
+ public override byte ReadPRG(int addr)
+ {
+ int bank_8k = addr >> 13;
+ int ofs = addr & ((1 << 13) - 1);
+ bank_8k += prg_mode;
+ bank_8k = prg_regs_8k[bank_8k];
+ bank_8k &= prg_bank_mask;
+ addr = (bank_8k << 13) | ofs;
+ return ROM[addr];
+ }
+ }
+}
\ No newline at end of file
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Irem_H3001.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Irem_H3001.cs
index 98a6958be7..8cb6c14195 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Irem_H3001.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/Irem_H3001.cs
@@ -9,6 +9,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
//Daiku no Gen San 2
//Spartan X 2
+ //NOTE - fceux support for this mapper has some kind of -4 cpu cycle delay built into the timer. not sure yet whether we need that
+
class Irem_H3001 : NES.NESBoardBase
{
//configuration
@@ -21,6 +23,13 @@ namespace BizHawk.Emulation.Consoles.Nintendo
ushort irq_counter, irq_reload;
int clock_counter;
+ public override void Dispose()
+ {
+ base.Dispose();
+ prg_regs_8k.Dispose();
+ chr_regs_1k.Dispose();
+ }
+
public override bool Configure(NES.EDetectionOrigin origin)
{
//configure
@@ -29,6 +38,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
case "IREM-H3001":
AssertPrg(128, 256); AssertChr(128, 256); AssertVram(0); AssertWram(0);
break;
+ case "IREM-H3001-FLEX":
+ break;
default:
return false;
}
@@ -43,11 +54,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo
return true;
}
- public override void Dispose()
- {
- prg_regs_8k.Dispose();
- chr_regs_1k.Dispose();
- }
public override void ClockPPU()
{
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs
index b876c5038a..3f6496faf2 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs
@@ -339,6 +339,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo
public unsafe void LoadGame(IGame game)
{
+ Console.WriteLine("------");
+ Console.WriteLine("BEGIN NES rom analysis:");
byte[] file = game.GetFileData();
if (file.Length < 16) throw new Exception("Alleged NES rom too small to be anything useful");
if (file.Take(4).SequenceEqual(System.Text.Encoding.ASCII.GetBytes("UNIF")))
@@ -364,6 +366,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo
md5.TransformFinalBlock(file, 16, file.Length - 16);
hash_md5 = "md5:" + Util.BytesToHexString(md5.Hash);
}
+
+ Console.WriteLine("Found iNES header:");
+ CartInfo iNesHeaderInfo = header->Analyze();
+ Console.WriteLine("Since this is iNES we can confidently parse PRG/CHR banks to hash.");
+
Console.WriteLine("headerless rom hash: {0}", hash_sha1);
Console.WriteLine("headerless rom hash: {0}", hash_md5);
@@ -372,6 +379,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
choice = IdentifyFromBootGodDB(hash_sha1);
if (choice == null)
{
+ Console.WriteLine("Could not locate game in nescartdb");
if (USE_DATABASE)
{
choice = IdentifyFromGameDB(hash_md5);
@@ -382,12 +390,13 @@ namespace BizHawk.Emulation.Consoles.Nintendo
}
if (choice == null)
{
+ Console.WriteLine("Could not locate game in bizhawk gamedb");
Console.WriteLine("Attempting inference from iNES header");
- choice = header->Analyze();
+ choice = iNesHeaderInfo;
string iNES_board = iNESBoardDetector.Detect(choice);
if (iNES_board == null)
throw new Exception("couldnt identify NES rom");
- Console.WriteLine("trying board " + iNES_board);
+ Console.WriteLine("Chose board from iNES heuristics: " + iNES_board);
choice.board_type = iNES_board;
choice.game.name = game.Name;
origin = EDetectionOrigin.INES;
@@ -395,7 +404,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
else
{
origin = EDetectionOrigin.GameDB;
- Console.WriteLine("Chose board from gamedb: " + board);
+ Console.WriteLine("Chose board from bizhawk gamedb: " + choice.board_type);
}
}
else
@@ -404,10 +413,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
origin = EDetectionOrigin.BootGodDB;
}
- Console.WriteLine(choice.game);
- Console.WriteLine(choice);
-
- //todo - generate better name with region and system
+ //TODO - generate better name with region and system
game_name = choice.game.name;
//find a INESBoard to handle this
@@ -416,6 +422,13 @@ namespace BizHawk.Emulation.Consoles.Nintendo
if (boardType == null)
throw new Exception("No class implements the necessary board type: " + choice.board_type);
+ Console.WriteLine("Final game detection results:");
+ Console.WriteLine(choice);
+ Console.WriteLine("\"" + game_name + "\"");
+
+ Console.WriteLine("END NES rom analysis");
+ Console.WriteLine("------");
+
board = (INESBoard)Activator.CreateInstance(boardType);
cart = choice;
diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/iNES.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/iNES.cs
index 5f811050d4..2cfcc54f81 100644
--- a/BizHawk.Emulation/Consoles/Nintendo/NES/iNES.cs
+++ b/BizHawk.Emulation/Consoles/Nintendo/NES/iNES.cs
@@ -25,6 +25,9 @@ namespace BizHawk.Emulation.Consoles.Nintendo
//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);
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;
}
@@ -89,6 +92,7 @@ static string ClassifyTable = @"
7 128 0 8 0 NES-ANROM; marble madness
7 256 0 8 8 NES-AOROM; battletoads
13 32 0 8 16 NES-CPROM; videomation
+65 -1 -1 -1 -1 IREM-H3001-FLEX; //Ai Sensei No Oshiete - Watashi No Hoshi (J).nes
66 64 16 8 0 NES-MHROM; super mario bros / duck hunt
66 128 32 8 0 NES-GNROM; gumshoe
68 128 256 8 0 SUNSOFT-4; After Burner 2 (J)
@@ -173,7 +177,7 @@ static string ClassifyTable = @"
//let's not put a lot of hacks in here. that's what the databases are for.
//for example of one not to add: videomation hack to change vram = 8 -> 16
- Console.WriteLine("iNES: map:{0}, mirror:{1}, PRG:{2}, CHR:{3}, WRAM:{4}, VRAM:{5}, bat:{6}", ret.mapper, mirroring, ret.prg_size, ret.chr_size, ret.wram_size, ret.vram_size, ret.wram_battery ? 1 : 0);
+ Console.WriteLine("map={0},pr={1},ch={2},wr={3},vr={4},ba={5},mir={6}",ret.mapper, ret.prg_size, ret.chr_size, ret.wram_size, ret.vram_size, ret.wram_battery ? 1 : 0, mirroring);
return ret;
}
diff --git a/BizHawk.MultiClient/output/gamedb.txt b/BizHawk.MultiClient/output/gamedb.txt
index 1df246dae7..4b4af9ea21 100644
--- a/BizHawk.MultiClient/output/gamedb.txt
+++ b/BizHawk.MultiClient/output/gamedb.txt
@@ -2261,7 +2261,7 @@ B486A8ED Dai Makai Mura SGX
D4448D09BBFDE687C04F9E3310E023AB ti83_1.rom TI83 initPC=6ce
;--nes--;
-;these games seem to be in goodNES but not bootgod's DB
+;these games seem to be in goodNES but not bootgod's DB. maybe secretly bad dumps or unknown variants.
sha1:22E6986903141495BA4589AC65982F3FB4D0E37B Adventures of Lolo (U) NES board=NES-SEROM;PRG=32;CHR=32
sha1:99C18C91F051BFBA6836A7B6B213C77569D83767 After Burner 2 (J) NES board=SUNSOFT-4;PRG=128;CHR=256;WRAM=8
sha1:CF655333DCE649A3C7060E9989860F2FC74E473A Demon Sword (U) NES board=NES-SL1ROM;PRG=128;CHR=128
@@ -2269,6 +2269,7 @@ sha1:7786BA1FE8E7E9E542EEB13CF2A6E2A1AD7F696D Metal Gear (U) NES board=KONAMI-
sha1:894F20405286F5F75133CE4648300E2C67972B40 Solomon's Key (U) NES board=NES-CNROM;PRG=32;CHR=32
sha1:0C53B06E1D13AE917536BB39010914EA3D111FF5 Thunder & Lightning (U) NES board=NES-GNROM;PRG=128;CHR=32;bad
sha1:9BDFF9A19265D84979F43F0F6E925A735DDEB38B Wai Xing Zhan Shi (Ch) NES board=Mapper242;PRG=512;CHR=0;VRAM=8;WRAM=8
+sha1:91CECCFCAC90E417E9AEE80E8F7B560A20EB33CC Ai Sensei No Oshiete - Watashi No Hoshi (J) NES board=IREM-G101;PRG=256;CHR=128;WRAM=8
;and these are even labeled as bad in goodNES
sha1:984ADAEB85403EEF1BA85CDCF310FAAECEB409A0 Adventures of Captain Comic, The (Bad Dump) (U) NES board=COLORDREAMS-74*377;PRG=64;CHR=64;WRAM=0;VRAM=0;bad