From 4b177ca8d175f49ce5de74dfabce8cda4aceea60 Mon Sep 17 00:00:00 2001 From: zeromus Date: Mon, 28 Feb 2011 06:16:20 +0000 Subject: [PATCH] [NES] ppu fixes and improved rom classification infrastructure --- BizHawk.Emulation/BizHawk.Emulation.csproj | 1 + .../Consoles/Nintendo/NES/BoardDetector.cs | 47 +++++ .../Consoles/Nintendo/NES/Boards/NROM.cs | 7 + .../Consoles/Nintendo/NES/NES.cs | 162 +++++++++++++----- .../Consoles/Nintendo/NES/PPU.cs | 16 ++ .../Consoles/Nintendo/NES/PPU.run.cs | 63 ++++--- BizHawk.Emulation/Database/Database.cs | 31 +++- .../Interfaces/Base Implementations/Game.cs | 2 + .../Base Implementations/SmdGame.cs | 1 + BizHawk.Emulation/Interfaces/IGame.cs | 1 + .../BizHawk.MultiClient.csproj | 2 +- BizHawk.MultiClient/ConfigService.cs | 13 +- BizHawk.MultiClient/RomGame.cs | 25 ++- BizHawk.MultiClient/output/gamedb.txt | 13 ++ 14 files changed, 292 insertions(+), 92 deletions(-) create mode 100644 BizHawk.Emulation/Consoles/Nintendo/NES/BoardDetector.cs diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj index dbd56eebac..2a8a78c439 100644 --- a/BizHawk.Emulation/BizHawk.Emulation.csproj +++ b/BizHawk.Emulation/BizHawk.Emulation.csproj @@ -55,6 +55,7 @@ + diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/BoardDetector.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/BoardDetector.cs new file mode 100644 index 0000000000..aaae7bf8a1 --- /dev/null +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/BoardDetector.cs @@ -0,0 +1,47 @@ +//http://nesdev.parodius.com/bbs/viewtopic.php?p=4571&sid=db4c7e35316cc5d734606dd02f11dccb + +using System; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Collections.Generic; +using BizHawk.Emulation.CPUs.M6502; + + +namespace BizHawk.Emulation.Consoles.Nintendo +{ + partial class NES + { + static class BoardDetector + { + public static string Detect(RomInfo romInfo) + { + string key = string.Format("{0} {1} {2}",romInfo.MapperNumber,romInfo.PRG_Size,romInfo.CHR_Size); + string board; + Table.TryGetValue(key, out board); + return board; + } + + public static Dictionary Table = new Dictionary(); + static BoardDetector() + { + var sr = new StringReader(ClassifyTable); + string line; + while ((line = sr.ReadLine()) != null) + { + var parts = line.Split('\t'); + if (parts.Length < 4) continue; + line = line.Replace(parts[0],""); + line = line.TrimStart('\t'); + Table[line] = parts[0]; + } + } +//board MAP PRG CHR + static string ClassifyTable = @" +NROM 0 1 1 +NROM 0 2 1 +"; + + } + } +} \ No newline at end of file diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/NROM.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/NROM.cs index 6756244cb1..2b54b87aec 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/NROM.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/Boards/NROM.cs @@ -1,11 +1,18 @@ using System; +using System.Diagnostics; namespace BizHawk.Emulation.Consoles.Nintendo.Boards { public class NROM : NES.NESBoardBase { + public virtual void Initialize(NES.RomInfo romInfo, NES nes) + { + base.Initialize(romInfo, nes); + Debug.Assert(romInfo.PRG_Size < 3); + } public override byte ReadPRG(int addr) { + addr &= (RomInfo.PRG_Size << 14) - 1; return RomInfo.ROM[addr]; } } diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs index 17764890b9..3c08a50b64 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs @@ -8,25 +8,53 @@ namespace BizHawk.Emulation.Consoles.Nintendo { public partial class NES : IEmulator { + //the main rom class that contains all information necessary for the board to operate + public class RomInfo + { + public enum EHeaderType + { + None, INes + } + + public enum EMirrorType + { + Vertical, Horizontal, Other + } + + public EHeaderType HeaderType; + public int PRG_Size = -1, CHR_Size = -1, PRAM_Size = -1; + public string BoardName; + public EMirrorType MirrorType; + public bool Battery; + + public int MapperNumber; //it annoys me that this junky mapper number is even in here. it might be nice to wrap this class in something else to contain the MapperNumber + + public string MD5; + + public byte[] ROM, VROM; + } + public interface INESBoard { byte ReadPRG(int addr); byte ReadPPU(int addr); + byte ReadPRAM(int addr); void WritePRG(int addr, byte value); void WritePPU(int addr, byte value); + void WritePRAM(int addr, byte value); void Initialize(RomInfo romInfo, NES nes); }; public abstract class NESBoardBase : INESBoard { - public void Initialize(RomInfo romInfo, NES nes) + public virtual void Initialize(RomInfo romInfo, NES nes) { this.RomInfo = romInfo; this.NES = nes; - switch (romInfo.Mirroring) + switch (romInfo.MirrorType) { - case 0: SetMirroring(0, 0, 1, 1); break; - case 1: SetMirroring(0, 1, 0, 1); break; + case RomInfo.EMirrorType.Horizontal: SetMirroring(0, 0, 1, 1); break; + case RomInfo.EMirrorType.Vertical: SetMirroring(0, 1, 0, 1); break; default: SetMirroring(-1, -1, -1, -1); break; //crash! } } @@ -42,10 +70,21 @@ namespace BizHawk.Emulation.Consoles.Nintendo mirroring[3] = d; } + int ApplyMirroring(int addr) + { + int block = (addr >> 10) & 3; + block = mirroring[block]; + int ofs = addr & 0x3FF; + return (block << 10) | ofs | 0x2000; + } + public virtual byte ReadPRG(int addr) { return RomInfo.ROM[addr];} public virtual void WritePRG(int addr, byte value) { } + public virtual void WritePRAM(int addr, byte value) { } + public virtual byte ReadPRAM(int addr) { return 0xFF; } + public virtual void WritePPU(int addr, byte value) { @@ -54,10 +93,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo } else { - int block = (addr >> 10) & 3; - block = mirroring[block]; - int ofs = addr & 0x3FF; - NES.ppu.NTARAM[(block << 10) | ofs] = value; + NES.ppu.ppu_defaultWrite(ApplyMirroring(addr), value); } } @@ -69,10 +105,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo } else { - int block = (addr >> 10)&3; - block = mirroring[block]; - int ofs = addr & 0x3FF; - return NES.ppu.NTARAM[(block << 10) | ofs]; + return NES.ppu.ppu_defaultRead(ApplyMirroring(addr)); } } } @@ -438,9 +471,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo return input; } - public class RomInfo + public class RomHeaderInfo { - public int MapperNo, Mirroring, Num_PRG_Banks, Num_CHR_Banks; + public int MapperNo, Mirroring, Num_PRG_Banks, Num_CHR_Banks, Num_PRAM_Banks; + public bool Battery; public byte[] ROM, VROM; } @@ -486,15 +520,25 @@ namespace BizHawk.Emulation.Consoles.Nintendo public RomInfo Analyze() { var ret = new RomInfo(); - ret.MapperNo = (ROM_type>>4); - ret.MapperNo|=(ROM_type2&0xF0); - ret.Mirroring = (ROM_type&1); - if((ROM_type&8)!=0) ret.Mirroring=2; - ret.Num_PRG_Banks = ROM_size; - if (ret.Num_PRG_Banks == 0) - ret.Num_PRG_Banks = 256; - ret.Num_CHR_Banks = VROM_size; - + ret.MapperNumber = (ROM_type>>4); + ret.MapperNumber |= (ROM_type2 & 0xF0); + int mirroring = (ROM_type&1); + if((ROM_type&8)!=0) mirroring=2; + if (mirroring == 0) ret.MirrorType = RomInfo.EMirrorType.Horizontal; + else if (mirroring == 1) ret.MirrorType = RomInfo.EMirrorType.Vertical; + else ret.MirrorType = RomInfo.EMirrorType.Other; + ret.PRG_Size = ROM_size; + if (ret.PRG_Size == 0) + ret.PRG_Size = 256; + ret.CHR_Size = VROM_size; + ret.Battery = (ROM_type & 2) != 0; + + fixed (iNES_HEADER* self = &this) ret.PRAM_Size = self->reserve[0]; + //0 is supposed to mean 1 (for compatibility, as this is an extension to original iNES format) + //but we're not worrying about that for now) + + Console.WriteLine("iNES header: map:{0}, mirror:{1}, PRG:{2}, CHR:{3}, PRAM:{4}, bat:{5}", ret.MapperNumber, ret.MirrorType, ret.PRG_Size, ret.CHR_Size, ret.PRAM_Size, ret.Battery ? 1 : 0); + //fceux calls uppow2(PRG_Banks) here, and also ups the chr size as well //then it does something complicated that i don't understand with making sure it doesnt read too much data //fceux only allows this condition for mappers in the list "not_power2" which is only 228 @@ -503,20 +547,11 @@ namespace BizHawk.Emulation.Consoles.Nintendo } } - INESBoard Classify(RomInfo info) - { - //you may think that this should be table driven.. but im not so sure. - //i think this should be a backstop eventually, with other classification happening from the game database. - //if the gamedatabase has an exact answer for a game then the board can be determined.. - //otherwise we might try to find a general case handler below. - - if (info.MapperNo == 0 && info.Num_CHR_Banks == 1 && info.Num_PRG_Banks == 2 && info.Mirroring == 1) return new Boards.NROM(); - return null; - } + const bool ENABLE_DB = true; public unsafe void LoadGame(IGame game) { - byte[] file = game.GetRomData(); + byte[] file = game.GetFileData(); if (file.Length < 16) throw new InvalidOperationException("Alleged NES rom too small to be anything useful"); fixed (byte* bfile = &file[0]) { @@ -524,14 +559,59 @@ namespace BizHawk.Emulation.Consoles.Nintendo if (!header->CheckID()) throw new InvalidOperationException("iNES header not found"); header->Cleanup(); - romInfo = header->Analyze(); - board = Classify(romInfo); + //now that we know we have an iNES header, we can try to ignore it. + string hash; + using (var md5 = System.Security.Cryptography.MD5.Create()) + { + md5.TransformFinalBlock(file, 16, file.Length - 16); + hash = Util.BytesToHexString(md5.Hash); + } + Console.WriteLine("headerless rom hash: {0}", hash); + + GameInfo gi = null; + if (ENABLE_DB) gi = Database.CheckDatabase(hash); + else Console.WriteLine("database check disabled"); + + if (gi == null) + { + romInfo = header->Analyze(); + string board = BoardDetector.Detect(romInfo); + if (board == null) + throw new InvalidOperationException("Couldn't detect board type"); + romInfo.BoardName = board; + Console.WriteLine("board detected as " + board); + } + else + { + Console.WriteLine("found game in database: {0}", gi.Name); + romInfo = new RomInfo(); + romInfo.MD5 = hash; + var dict = gi.ParseOptionsDictionary(); + if (dict.ContainsKey("board")) + romInfo.BoardName = dict["board"]; + switch (dict["mirror"]) + { + case "V": romInfo.MirrorType = RomInfo.EMirrorType.Vertical; break; + case "H": romInfo.MirrorType = RomInfo.EMirrorType.Horizontal; break; + } + if (dict.ContainsKey("PRG")) + romInfo.PRG_Size = int.Parse(dict["PRG"]); + if (dict.ContainsKey("CHR")) + romInfo.CHR_Size = int.Parse(dict["CHR"]); + } + + //construct board (todo) + switch (romInfo.BoardName) + { + case "NROM": board = new Boards.NROM(); break; + } + if (board == null) throw new InvalidOperationException("Couldn't classify NES rom"); board.Initialize(romInfo, this); //we're going to go ahead and copy these out, just in case we need to pad them alter - romInfo.ROM = new byte[romInfo.Num_PRG_Banks * 16 * 1024]; - romInfo.VROM = new byte[romInfo.Num_CHR_Banks * 8 * 1024]; + romInfo.ROM = new byte[romInfo.PRG_Size * 16 * 1024]; + romInfo.VROM = new byte[romInfo.CHR_Size * 8 * 1024]; Array.Copy(file, 16, romInfo.ROM, 0, romInfo.ROM.Length); Array.Copy(file, 16 + romInfo.ROM.Length, romInfo.VROM, 0, romInfo.VROM.Length); } @@ -539,4 +619,8 @@ namespace BizHawk.Emulation.Consoles.Nintendo HardReset(); } } -} \ No newline at end of file +} + +//todo +//http://blog.ntrq.net/?p=428 +//cpu bus junk bits \ No newline at end of file diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.cs index 392d44d2bf..c9fb5141bc 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.cs @@ -13,16 +13,32 @@ namespace BizHawk.Emulation.Consoles.Nintendo { partial class PPU { + //when the ppu issues a write it goes through here and into the game board void ppubus_write(int addr, byte value) { nes.board.WritePPU(addr, value); } + //when the ppu issues a read it goes through here and into the game board byte ppubus_read(int addr) { return nes.board.ReadPPU(addr); } + //boards may not respond to a read, in which case this will get called. please apply mirroring logic beforehand + public byte ppu_defaultRead(int addr) + { + addr &= 0x7FF; + return NTARAM[addr]; + } + + //boards may not respond to a write, in which case this will get called. please apply mirroring logic beforehand + public void ppu_defaultWrite(int addr, byte value) + { + addr &= 0x7FF; + NTARAM[addr] = value; + } + enum PPUPHASE { VBL, BG, OBJ }; diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.run.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.run.cs index beb2c4e1bf..27b0e88162 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.run.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/PPU.run.cs @@ -68,7 +68,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo public fixed byte oam[4]; public fixed byte patterns[2]; public byte index; - byte pad; + public byte present; } //TODO - check flashing sirens in werewolf @@ -249,34 +249,40 @@ namespace BizHawk.Emulation.Consoles.Nintendo //look for sprites (was supposed to run concurrent with bg rendering) oamcounts[scanslot] = 0; oamcount = 0; - if (sl == 0xb1) - { - int zzz = 9; - } int spriteHeight = reg_2000.obj_size_16 ? 16 : 8; + + for (int i = 0; i < 64; i++) + fixed (TempOAM* oam = &oams[scanslot, i]) + oam->present = 0; + for (int i = 0; i < 64; i++) { int spr = i * 4; - if (yp >= OAM[spr] && yp < OAM[spr] + spriteHeight) { - //if we already have maxsprites, then this new one causes an overflow, - //set the flag and bail out. - if (oamcount >= 8 && reg_2001.PPUON) + if (yp >= OAM[spr] && yp < OAM[spr] + spriteHeight) { - Reg2002_objoverflow = true; - if (SPRITELIMIT) - break; - } + //if we already have maxsprites, then this new one causes an overflow, + //set the flag and bail out. + if (oamcount >= 8 && reg_2001.PPUON) + { + Reg2002_objoverflow = true; + if (SPRITELIMIT) + break; + } - //just copy some bytes into the internal sprite buffer - for (int j = 0; j < 4; j++) + //just copy some bytes into the internal sprite buffer fixed (TempOAM* oam = &oams[scanslot, oamcount]) - oam->oam[j] = OAM[spr + j]; + { + for (int j = 0; j < 4; j++) + oam->oam[j] = OAM[spr + j]; + oam->present = 1; + } - //note that we stuff the oam index into [6]. - //i need to turn this into a struct so we can have fewer magic numbers - oams[scanslot, oamcount].index = (byte)i; - oamcount++; + //note that we stuff the oam index into [6]. + //i need to turn this into a struct so we can have fewer magic numbers + oams[scanslot, oamcount].index = (byte)i; + oamcount++; + } } } oamcounts[scanslot] = oamcount; @@ -303,11 +309,6 @@ namespace BizHawk.Emulation.Consoles.Nintendo //fetch sprite patterns for (int s = 0; s < MAXSPRITES; s++) { - if (sl == 0x9E && s == 1) - { - int zzz = 9; - } - //if we have hit our eight sprite pattern and we dont have any more sprites, then bail if (s == oamcount && s >= 8) break; @@ -327,17 +328,24 @@ namespace BizHawk.Emulation.Consoles.Nintendo int patternNumber = oam->oam[1]; int patternAddress; + //create deterministic dummy fetch pattern + if (oam->present==0) + { + patternNumber = 0; + line = 0; + } + //8x16 sprite handling: if (reg_2000.obj_size_16) { int bank = (patternNumber & 1) << 12; patternNumber = patternNumber & ~1; - patternNumber |= (line >> 3); + patternNumber |= (line >> 3)&1; patternAddress = (patternNumber << 4) | bank; } else { - patternAddress = (patternNumber << 4) | (reg_2000.obj_pattern_hi << 9); + patternAddress = (patternNumber << 4) | (reg_2000.obj_pattern_hi << 12); } //offset into the pattern for the current line. @@ -347,6 +355,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo //garbage nametable fetches //reset the scroll counter, happens at cycle 304 + //TODO - compact this logic if (realSprite) { if ((sl == 0) && reg_2001.PPUON) diff --git a/BizHawk.Emulation/Database/Database.cs b/BizHawk.Emulation/Database/Database.cs index 2a91cb2e78..9c47ec38fd 100644 --- a/BizHawk.Emulation/Database/Database.cs +++ b/BizHawk.Emulation/Database/Database.cs @@ -25,12 +25,32 @@ namespace BizHawk return new string[0]; return MetaData.Split(';').Where(opt => string.IsNullOrEmpty(opt) == false).ToArray(); } + + public Dictionary ParseOptionsDictionary() + { + var ret = new Dictionary(); + foreach (var opt in GetOptions()) + { + var parts = opt.Split('='); + var key = parts[0]; + var value = parts.Length > 1 ? parts[1] : ""; + ret[key] = value; + } + return ret; + } } public static class Database { private static Dictionary db = new Dictionary(); + public static GameInfo CheckDatabase(string hash) + { + GameInfo ret = null; + db.TryGetValue(hash, out ret); + return ret; + } + public static void LoadDatabase(string path) { using (var reader = new StreamReader(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))) @@ -46,7 +66,7 @@ namespace BizHawk string[] items = line.Split('\t'); var Game = new GameInfo(); - Game.hash = items[0]; + Game.hash = items[0].ToUpper(); Game.Name = items[2]; Game.System = items[3]; Game.MetaData = items.Length >= 6 ? items[5] : null; @@ -61,13 +81,14 @@ namespace BizHawk public static GameInfo GetGameInfo(byte[] RomData, string fileName) { + GameInfo ret; string hash = string.Format("{0:X8}", CRC32.Calculate(RomData)); - if (db.ContainsKey(hash)) - return db[hash]; + if (db.TryGetValue(hash, out ret)) + return ret; hash = Util.BytesToHexString(System.Security.Cryptography.MD5.Create().ComputeHash(RomData)); - if (db.ContainsKey(hash)) - return db[hash]; + if (db.TryGetValue(hash, out ret)) + return ret; // rom is not in database. make some best-guesses var Game = new GameInfo(); diff --git a/BizHawk.Emulation/Interfaces/Base Implementations/Game.cs b/BizHawk.Emulation/Interfaces/Base Implementations/Game.cs index 5ff2e35f78..91e7fd7da9 100644 --- a/BizHawk.Emulation/Interfaces/Base Implementations/Game.cs +++ b/BizHawk.Emulation/Interfaces/Base Implementations/Game.cs @@ -37,6 +37,8 @@ namespace BizHawk } } + public byte[] GetFileData() { return null; } + public byte[] GetRomData() { return RomData; diff --git a/BizHawk.Emulation/Interfaces/Base Implementations/SmdGame.cs b/BizHawk.Emulation/Interfaces/Base Implementations/SmdGame.cs index 1ab945286d..a986706cf4 100644 --- a/BizHawk.Emulation/Interfaces/Base Implementations/SmdGame.cs +++ b/BizHawk.Emulation/Interfaces/Base Implementations/SmdGame.cs @@ -65,6 +65,7 @@ namespace BizHawk return output; } + public byte[] GetFileData() { return null; } public byte[] GetRomData() { return RomData; diff --git a/BizHawk.Emulation/Interfaces/IGame.cs b/BizHawk.Emulation/Interfaces/IGame.cs index ccf41dbfe7..912f7b0bdd 100644 --- a/BizHawk.Emulation/Interfaces/IGame.cs +++ b/BizHawk.Emulation/Interfaces/IGame.cs @@ -5,6 +5,7 @@ namespace BizHawk public interface IGame { byte[] GetRomData(); + byte[] GetFileData(); IList GetOptions(); string Name { get; } } diff --git a/BizHawk.MultiClient/BizHawk.MultiClient.csproj b/BizHawk.MultiClient/BizHawk.MultiClient.csproj index 068b4f8d7a..95886f58a6 100644 --- a/BizHawk.MultiClient/BizHawk.MultiClient.csproj +++ b/BizHawk.MultiClient/BizHawk.MultiClient.csproj @@ -317,7 +317,7 @@ - + diff --git a/BizHawk.MultiClient/ConfigService.cs b/BizHawk.MultiClient/ConfigService.cs index 75da242672..308a1366b3 100644 --- a/BizHawk.MultiClient/ConfigService.cs +++ b/BizHawk.MultiClient/ConfigService.cs @@ -12,12 +12,13 @@ namespace BizHawk.MultiClient try { var file = new FileInfo(filepath); - using (var reader = file.OpenText()) - { - var s = new JsonSerializer(); - var r = new JsonReader(reader); - config = (T) s.Deserialize(r, typeof (T)); - } + if(file.Exists) + using (var reader = file.OpenText()) + { + var s = new JsonSerializer(); + var r = new JsonReader(reader); + config = (T) s.Deserialize(r, typeof (T)); + } } catch { } return config; diff --git a/BizHawk.MultiClient/RomGame.cs b/BizHawk.MultiClient/RomGame.cs index 4ce5f2468f..67a7306e6f 100644 --- a/BizHawk.MultiClient/RomGame.cs +++ b/BizHawk.MultiClient/RomGame.cs @@ -7,6 +7,7 @@ namespace BizHawk.MultiClient public class RomGame : IGame { public byte[] RomData; + public byte[] FileData; public string System; private string name; @@ -24,22 +25,17 @@ namespace BizHawk.MultiClient var stream = file.GetStream(); - if (file.Extension == "NES") - { - RomData = Util.ReadAllBytes(stream); - } - else - { - int header = (int)(stream.Length % BankSize); - stream.Position = header; - int length = (int)stream.Length - header; + FileData = Util.ReadAllBytes(stream); - RomData = new byte[length]; - stream.Read(RomData, 0, length); + int header = (int)(stream.Length % BankSize); + stream.Position = header; + int length = (int)stream.Length - header; - if (file.Extension == "SMD") - RomData = DeInterleaveSMD(RomData); - } + RomData = new byte[length]; + stream.Read(RomData, 0, length); + + if (file.Extension == "SMD") + RomData = DeInterleaveSMD(RomData); var info = Database.GetGameInfo(RomData, file.FullName); name = info.Name; @@ -105,6 +101,7 @@ namespace BizHawk.MultiClient } public byte[] GetRomData() { return RomData; } + public byte[] GetFileData() { return FileData; } public IList GetOptions() { return options; } public string Name { get { return name; } } diff --git a/BizHawk.MultiClient/output/gamedb.txt b/BizHawk.MultiClient/output/gamedb.txt index 8dfe85f71d..240aaf0466 100644 --- a/BizHawk.MultiClient/output/gamedb.txt +++ b/BizHawk.MultiClient/output/gamedb.txt @@ -2257,3 +2257,16 @@ B486A8ED Dai Makai Mura SGX 1F041166 Madoo Granzort SGX D4448D09BBFDE687C04F9E3310E023AB ti83_1.rom TI83 initPC=6ce + +8E3630186E35D477231BF8FD50E54CDD Super Mario Bros. (U) NES board=NROM;mirror=V;PRG=2;CHR=1 +1457475741846A01399DC663135A60C1 Balloon Fight (JU) NES board=NROM;mirror=H;PRG=1;CHR=1 +576AB245B4F04C670AC312AB0D441697 Baseball (UE) NES board=NROM;mirror=H;PRG=1;CHR=1 +0F9C8D3D3099C70368411F6DF9EF49C1 Bomberman (U) NES board=NROM;mirror=V;PRG=1;CHR=1 +D2C42603A8EC74F51265C085AE26B9BB Burger Time (U) NES board=NROM;mirror=H;PRG=1;CHR=1 +EEBA6EF8992074C5EBBDF0ECD9468E10 Clu Clu Land (JU) NES board=NROM;mirror=H;PRG=1;CHR=1 +E36BC14876DA0E25C4EE2BBA193002C4 Defender 2 (U) NES board=NROM;mirror=V;PRG=1;CHR=1 +A2B5BDDB4C7A5A39C8FAC13E64494C9A Donkey Kong 3 (JUE) board=NROM;mirror=V;PRG=1;CHR=1 +6D4A94C344463E562344249E18E9B99F Donkey Kong (JU) NES board=NROM;mirror=H;PRG=1;CHR=1 +8B7C1E5B55A9E5FA23E895DF2D682914 Donkey Kong Jr (JU) NES board=NROM;mirror=H;PRG=1;CHR=1 +1CA706896A8D4F2A2B5480D941130A4A Donkey Kong Jr Math (U) NES board=NROM;mirror=V;PRG=1;CHR=1 +FA382374EB4A93A719064CA6C5A4E78C Duck Hunt (JUE) NES board=NROM;mirror=V;PRG=1;CHR=1