From 4d96c1333467272bcd4927f59d37144cab92ea87 Mon Sep 17 00:00:00 2001 From: Souryo Date: Sat, 18 Mar 2017 19:11:26 -0400 Subject: [PATCH] Headerless rom support (when found in built-in game database) --- Core/GameDatabase.cpp | 70 ++++++++++++++++++++++++++++++++ Core/GameDatabase.h | 1 + Core/RomData.h | 30 ++++++-------- Core/RomLoader.cpp | 14 +++++-- Core/iNesLoader.cpp | 16 +++++--- Core/iNesLoader.h | 2 +- GUI.NET/Dependencies/MesenDB.txt | 3 +- 7 files changed, 107 insertions(+), 29 deletions(-) diff --git a/Core/GameDatabase.cpp b/Core/GameDatabase.cpp index fd02a2e1..073bea6e 100644 --- a/Core/GameDatabase.cpp +++ b/Core/GameDatabase.cpp @@ -226,6 +226,76 @@ uint8_t GameDatabase::GetSubMapper(GameInfo &info) return 0; } +bool GameDatabase::GetiNesHeader(uint32_t romCrc, NESHeader &nesHeader) +{ + GameInfo info = {}; + InitDatabase(); + auto result = _gameDatabase.find(romCrc); + if(result != _gameDatabase.end()) { + MessageManager::Log("[DB] Headerless ROM file found - using game database data."); + + info = result->second; + + nesHeader.Byte9 = 0; + if(info.PrgRomSize > 4096) { + uint16_t prgSize = info.PrgRomSize / 16; + nesHeader.PrgCount = prgSize & 0xFF; + nesHeader.Byte9 |= (prgSize & 0xF00) >> 8; + } else { + nesHeader.PrgCount = info.PrgRomSize / 16; + } + + if(info.ChrRomSize > 2048) { + uint16_t chrSize = info.ChrRomSize / 8; + nesHeader.ChrCount = chrSize & 0xFF; + nesHeader.Byte9 |= (chrSize & 0xF00) >> 4; + } else { + nesHeader.ChrCount = info.ChrRomSize / 8; + } + + nesHeader.Byte6 = (info.MapperID & 0x0F) << 4; + if(info.HasBattery) { + nesHeader.Byte6 |= 0x02; + } + if(info.Mirroring.compare("v") == 0) { + nesHeader.Byte6 |= 0x01; + } + + nesHeader.Byte7 = (info.MapperID & 0xF0); + GameSystem system = GetGameSystem(info.System); + if(system == GameSystem::Playchoice) { + nesHeader.Byte7 |= 0x02; + } else if(system == GameSystem::VsUniSystem) { + nesHeader.Byte7 |= 0x01; + } + + //Don't set this, otherwise the header will be used over the game DB data + //nesHeader.Byte7 |= 0x08; //NES 2.0 marker + + nesHeader.Byte8 = ((GetSubMapper(info) & 0x0F) << 4) | ((info.MapperID & 0xF00) >> 8); + + nesHeader.Byte10 = 0; + if(info.SaveRamSize > 0) { + nesHeader.Byte10 |= ((int)log2(info.SaveRamSize * 1024) - 6) << 4; + } + if(info.WorkRamSize > 0) { + nesHeader.Byte10 |= ((int)log2(info.WorkRamSize * 1024) - 6); + } + + nesHeader.Byte11 = 0; + if(info.ChrRamSize > 0) { + nesHeader.Byte11 |= ((int)log2(info.ChrRamSize * 1024) - 6); + } + + nesHeader.Byte12 = system == GameSystem::NesPal ? 0x01 : 0; + nesHeader.Byte13 = 0; //VS PPU variant + + return true; + } + + return false; +} + void GameDatabase::SetGameInfo(uint32_t romCrc, RomData &romData, bool updateRomData) { GameInfo info = {}; diff --git a/Core/GameDatabase.h b/Core/GameDatabase.h index 9b04e875..f5590847 100644 --- a/Core/GameDatabase.h +++ b/Core/GameDatabase.h @@ -20,4 +20,5 @@ private: public: static void InitializeInputDevices(string inputType, GameSystem system); static void SetGameInfo(uint32_t romCrc, RomData &romData, bool updateRomData); + static bool GetiNesHeader(uint32_t romCrc, NESHeader &nesHeader); }; \ No newline at end of file diff --git a/Core/RomData.h b/Core/RomData.h index 4b984d17..614f031f 100644 --- a/Core/RomData.h +++ b/Core/RomData.h @@ -69,16 +69,6 @@ struct NESHeader } } - uint32_t GetPrgCount() - { - if(PrgCount == 0) { - //0 prg banks is a special value meaning 256 banks - return 256; - } else { - return PrgCount; - } - } - bool HasBattery() { return (Byte6 & 0x02) == 0x02; @@ -130,9 +120,13 @@ struct NESHeader uint32_t GetPrgSize() { if(GetRomHeaderVersion() == RomHeaderVersion::Nes2_0) { - return (((Byte9 & 0x0F) << 4) | GetPrgCount()) * 0x4000; + return (((Byte9 & 0x0F) << 4) | PrgCount) * 0x4000; } else { - return GetPrgCount() * 0x4000; + if(PrgCount == 0) { + return 256 * 0x4000; //0 is a special value and means 256 + } else { + return PrgCount * 0x4000; + } } } @@ -205,16 +199,18 @@ struct NESHeader void SanitizeHeader(size_t romLength) { - size_t calculatedLength = sizeof(NESHeader) + 0x4000 * GetPrgCount(); + size_t calculatedLength = sizeof(NESHeader) + GetPrgSize(); while(calculatedLength > romLength) { + Byte9 = 0; PrgCount--; - calculatedLength = sizeof(NESHeader) + 0x4000 * GetPrgCount(); + calculatedLength = sizeof(NESHeader) + GetPrgSize(); } - calculatedLength = sizeof(NESHeader) + 0x4000 * GetPrgCount() + 0x2000 * ChrCount; + calculatedLength = sizeof(NESHeader) + GetPrgSize() + GetChrSize(); while(calculatedLength > romLength) { + Byte9 = 0; ChrCount--; - calculatedLength = sizeof(NESHeader) + 0x4000 * GetPrgCount() + 0x2000 * ChrCount; + calculatedLength = sizeof(NESHeader) + GetPrgSize() + GetChrSize(); } } }; @@ -252,7 +248,7 @@ struct GameInfo string Board; string Pcb; string Chip; - uint8_t MapperID; + uint16_t MapperID; uint32_t PrgRomSize; uint32_t ChrRomSize; uint32_t ChrRamSize; diff --git a/Core/RomLoader.cpp b/Core/RomLoader.cpp index 0cf7a37a..0adb4ea4 100644 --- a/Core/RomLoader.cpp +++ b/Core/RomLoader.cpp @@ -113,7 +113,7 @@ bool RomLoader::LoadFromMemory(uint8_t* buffer, size_t length, string romName) if(memcmp(buffer, "NES\x1a", 4) == 0) { iNesLoader loader; - _romData = loader.LoadRom(fileData); + _romData = loader.LoadRom(fileData, nullptr); } else if(memcmp(buffer, "FDS\x1a", 4) == 0 || memcmp(buffer, "\x1*NINTENDO-HVC*", 15) == 0) { FdsLoader loader; _romData = loader.LoadRom(fileData, _filename); @@ -127,8 +127,14 @@ bool RomLoader::LoadFromMemory(uint8_t* buffer, size_t length, string romName) UnifLoader loader; _romData = loader.LoadRom(fileData); } else { - MessageManager::Log("Invalid rom file."); - _romData.Error = true; + NESHeader header = { }; + if(GameDatabase::GetiNesHeader(crc, header)) { + iNesLoader loader; + _romData = loader.LoadRom(fileData, &header); + } else { + MessageManager::Log("Invalid rom file."); + _romData.Error = true; + } } _romData.Crc32 = crc; @@ -175,7 +181,7 @@ bool RomLoader::LoadFile(string filename, istream *filestream, string ipsFilenam } else if(memcmp(header, "7z", 2) == 0) { SZReader reader; return LoadFromArchive(*input, reader, archiveFileIndex); - } else if(memcmp(header, "NES\x1a", 4) == 0 || memcmp(header, "NESM\x1a", 5) == 0 || memcmp(header, "NSFE", 4) == 0 || memcmp(header, "FDS\x1a", 4) == 0 || memcmp(header, "\x1*NINTENDO-HVC*", 15) == 0 || memcmp(header, "UNIF", 4) == 0) { + } else { if(archiveFileIndex > 0) { return false; } diff --git a/Core/iNesLoader.cpp b/Core/iNesLoader.cpp index bd2e77d1..d3ca3ef7 100644 --- a/Core/iNesLoader.cpp +++ b/Core/iNesLoader.cpp @@ -4,16 +4,20 @@ #include "GameDatabase.h" #include "EmulationSettings.h" -RomData iNesLoader::LoadRom(vector& romFile) +RomData iNesLoader::LoadRom(vector& romFile, NESHeader *preloadedHeader) { RomData romData; - uint8_t* buffer = romFile.data(); NESHeader header; - memcpy((char*)&header, buffer, sizeof(NESHeader)); - buffer += sizeof(NESHeader); - - header.SanitizeHeader(romFile.size()); + uint8_t* buffer = romFile.data(); + if(preloadedHeader) { + header = *preloadedHeader; + header.SanitizeHeader(romFile.size() + sizeof(NESHeader)); + } else { + memcpy((char*)&header, buffer, sizeof(NESHeader)); + buffer += sizeof(NESHeader); + header.SanitizeHeader(romFile.size()); + } romData.Format = RomFormat::iNes; diff --git a/Core/iNesLoader.h b/Core/iNesLoader.h index 11957db6..68f8be81 100644 --- a/Core/iNesLoader.h +++ b/Core/iNesLoader.h @@ -5,5 +5,5 @@ class iNesLoader { public: - RomData LoadRom(vector& romFile); + RomData LoadRom(vector& romFile, NESHeader *preloadedHeader); }; \ No newline at end of file diff --git a/GUI.NET/Dependencies/MesenDB.txt b/GUI.NET/Dependencies/MesenDB.txt index 8abad0d7..7273ba5c 100644 --- a/GUI.NET/Dependencies/MesenDB.txt +++ b/GUI.NET/Dependencies/MesenDB.txt @@ -4,7 +4,7 @@ # # Automatically generated database based on Nestopia's DB and NesCartDB # -# Generated on 22/02/2017 using: +# Generated on 18/03/2017 using: # -NesCartDB (dated 2016-08-20) # -Nestopia UE's latest DB (dated 2015-10-22) # @@ -177,6 +177,7 @@ 0DC53188,Famicom,HVC-SGROM,HVC-SGROM-03,MMC1A,1,256,,8,0,0,0,, 0E1683C5,Famicom,TAITO-X1-005,P3-034A,X1-005,80,128,128,,0,0,1,, 0E197A5E,Famicom,,,,0,32,8,,0,0,0,h, +0E76E4C1,Famicom,,,,190,256,128,,0,0,0,, 0E997CF6,Famicom,HVC-SNROM,HVC-SNROM-08,MMC1B2,1,256,,8,0,8,1,, 0EAA7515,Famicom,,,,2,128,,8,0,0,0,v, 0EC6C023,NesNtsc,NES-EKROM,NES-EKROM-01,MMC5,5,256,256,,0,8,1,,