From 4d2e17f9c0f13a7f18c559a16ef2b76eda32cf75 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Thu, 18 Aug 2016 08:04:50 +1000 Subject: [PATCH] Update to v101r09 release. byuu says: Sorry, two WIPs in one day. Got excited and couldn't wait. Changelog: - ADDQ, SUBQ shouldn't update flags when targeting an address register - ADDA should sign extend effective address reads - JSR was pushing the PC too early - some improvements to 8-bit register reads on the VDP (still needs work) - added H/V counter reads to the VDP IO port region - icarus: added support for importing Master System and Game Gear ROMs - tomoko: added library sub-menus for each manufacturer - still need to sort Game Gear after Mega Drive somehow ... The sub-menu system actually isn't all that bad. It is indeed a bit more annoying, but not as annoying as I thought it was going to be. However, it looks a hell of a lot nicer now. --- higan/emulator/emulator.hpp | 2 +- higan/md/vdp/io.cpp | 9 ++-- higan/md/vdp/vdp.cpp | 11 ++--- higan/processor/m68k/disassembler.cpp | 16 +++++-- higan/processor/m68k/instruction.cpp | 32 ++++++++----- higan/processor/m68k/instructions.cpp | 33 +++++++++----- higan/processor/m68k/m68k.hpp | 12 +++-- .../presentation/presentation.cpp | 22 ++++++--- .../presentation/presentation.hpp | 2 - icarus/core/core.cpp | 8 +++- icarus/core/core.hpp | 30 +++++++++---- icarus/core/game-gear.cpp | 45 +++++++++++++++++++ icarus/core/master-system.cpp | 45 +++++++++++++++++++ icarus/heuristics/game-gear.cpp | 20 +++++++++ icarus/heuristics/master-system.cpp | 20 +++++++++ icarus/icarus.cpp | 21 ++++++++- 16 files changed, 266 insertions(+), 62 deletions(-) create mode 100644 icarus/core/game-gear.cpp create mode 100644 icarus/core/master-system.cpp create mode 100644 icarus/heuristics/game-gear.cpp create mode 100644 icarus/heuristics/master-system.cpp diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 43f58cb8..582c2425 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -12,7 +12,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "101.08"; + static const string Version = "101.09"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/md/vdp/io.cpp b/higan/md/vdp/io.cpp index e638afdf..5894f41e 100644 --- a/higan/md/vdp/io.cpp +++ b/higan/md/vdp/io.cpp @@ -1,8 +1,6 @@ -//todo: does data mirroring occur for all VDP addresses; or just data/control ports? - auto VDP::readByte(uint24 addr) -> uint8 { auto data = readWord(addr & ~1); - return data << 8 | data << 0; + return data.byte(!addr.bit(0)); } auto VDP::writeByte(uint24 addr, uint8 data) -> void { @@ -24,6 +22,11 @@ auto VDP::readWord(uint24 addr) -> uint16 { return readControlPort(); } + //counter + case 0xc00008: case 0xc0000a: case 0xc0000c: case 0xc0000e: { + return state.y << 8 | (state.x >> 1) << 0; + } + } return 0x0000; diff --git a/higan/md/vdp/vdp.cpp b/higan/md/vdp/vdp.cpp index 8c8dd36d..0f2d68b7 100644 --- a/higan/md/vdp/vdp.cpp +++ b/higan/md/vdp/vdp.cpp @@ -1,8 +1,5 @@ #include -//256-width = colorburst * 15 / 10 -//320-width = colorburst * 15 / 8 - namespace MegaDrive { VDP vdp; @@ -25,19 +22,19 @@ auto VDP::main() -> void { cpu.lower(CPU::Interrupt::HorizontalBlank); for(uint x : range(320)) { run(); - step(1); + step(4); } if(io.horizontalBlankInterruptEnable) { cpu.raise(CPU::Interrupt::HorizontalBlank); } - step(22); + step(430); } else { if(state.y == 240) { if(io.verticalBlankInterruptEnable) { cpu.raise(CPU::Interrupt::VerticalBlank); } } - step(342); + step(1710); } } @@ -61,7 +58,7 @@ auto VDP::power() -> void { } auto VDP::reset() -> void { - create(VDP::Enter, system.colorburst() * 15.0 / 10.0); + create(VDP::Enter, system.colorburst() * 15.0 / 2.0); memory::fill(&io, sizeof(IO)); diff --git a/higan/processor/m68k/disassembler.cpp b/higan/processor/m68k/disassembler.cpp index 073ae657..f5506e52 100644 --- a/higan/processor/m68k/disassembler.cpp +++ b/higan/processor/m68k/disassembler.cpp @@ -126,8 +126,12 @@ template auto M68K::disassembleADDI(EffectiveAddress ea) -> string { return {"addi", _suffix(), " ", _immediate(), ",", _effectiveAddress(ea)}; } -template auto M68K::disassembleADDQ(uint4 immediate, EffectiveAddress modify) -> string { - return {"addq", _suffix(), " #", immediate, ",", _effectiveAddress(modify)}; +template auto M68K::disassembleADDQ(uint4 immediate, EffectiveAddress with) -> string { + return {"addq", _suffix(), " #", immediate, ",", _effectiveAddress(with)}; +} + +template auto M68K::disassembleADDQ(uint4 immediate, AddressRegister with) -> string { + return {"addq", _suffix(), " #", immediate, ",", _addressRegister(with)}; } template auto M68K::disassembleADDX(EffectiveAddress with, EffectiveAddress from) -> string { @@ -543,8 +547,12 @@ template auto M68K::disassembleSUBI(EffectiveAddress with) -> string return {"subi", _suffix(), " ", _immediate(), ",", _effectiveAddress(with)}; } -template auto M68K::disassembleSUBQ(uint4 immediate, EffectiveAddress ea) -> string { - return {"subq", _suffix(), " #", immediate, ",", _effectiveAddress(ea)}; +template auto M68K::disassembleSUBQ(uint4 immediate, EffectiveAddress with) -> string { + return {"subq", _suffix(), " #", immediate, ",", _effectiveAddress(with)}; +} + +template auto M68K::disassembleSUBQ(uint4 immediate, AddressRegister with) -> string { + return {"subq", _suffix(), " #", immediate, ",", _addressRegister(with)}; } template auto M68K::disassembleSUBX(EffectiveAddress with, EffectiveAddress from) -> string { diff --git a/higan/processor/m68k/instruction.cpp b/higan/processor/m68k/instruction.cpp index fd19db71..49fdf2c8 100644 --- a/higan/processor/m68k/instruction.cpp +++ b/higan/processor/m68k/instruction.cpp @@ -106,12 +106,16 @@ M68K::M68K() { if(mode == 7 && reg >= 2) continue; uint4 immediate = data ? (uint4)data : (uint4)8; - EffectiveAddress modify{mode, reg}; - bind(opcode | 0 << 6, ADDQ, immediate, modify); - bind(opcode | 1 << 6, ADDQ, immediate, modify); - bind(opcode | 2 << 6, ADDQ, immediate, modify); - - if(mode == 1) unbind(opcode | 0 << 6); + if(mode != 1) { + EffectiveAddress with{mode, reg}; + bind(opcode | 0 << 6, ADDQ, immediate, with); + bind(opcode | 1 << 6, ADDQ, immediate, with); + bind(opcode | 2 << 6, ADDQ, immediate, with); + } else { + AddressRegister with{reg}; + bind(opcode | 1 << 6, ADDQ, immediate, with); + bind(opcode | 2 << 6, ADDQ, immediate, with); + } } //ADDX @@ -1178,12 +1182,16 @@ M68K::M68K() { if(mode == 7 && reg >= 2) continue; auto immediate = data ? (uint4)data : (uint4)8; - EffectiveAddress ea{mode, reg}; - bind(opcode | 0 << 6, SUBQ, immediate, ea); - bind(opcode | 1 << 6, SUBQ, immediate, ea); - bind(opcode | 2 << 6, SUBQ, immediate, ea); - - if(mode == 1) unbind(opcode | 0 << 6); + if(mode != 1) { + EffectiveAddress with{mode, reg}; + bind(opcode | 0 << 6, SUBQ, immediate, with); + bind(opcode | 1 << 6, SUBQ, immediate, with); + bind(opcode | 2 << 6, SUBQ, immediate, with); + } else { + AddressRegister with{reg}; + bind(opcode | 1 << 6, SUBQ, immediate, with); + bind(opcode | 2 << 6, SUBQ, immediate, with); + } } //SUBX diff --git a/higan/processor/m68k/instructions.cpp b/higan/processor/m68k/instructions.cpp index 91dee2d5..9e4575ab 100644 --- a/higan/processor/m68k/instructions.cpp +++ b/higan/processor/m68k/instructions.cpp @@ -105,7 +105,7 @@ template auto M68K::instructionADD(DataRegister from, EffectiveAddres } template auto M68K::instructionADDA(AddressRegister ar, EffectiveAddress ea) -> void { - auto source = read(ea); + auto source = sign(read(ea)); auto target = read(ar); write(ar, source + target); } @@ -117,11 +117,16 @@ template auto M68K::instructionADDI(EffectiveAddress modify) -> void write(modify, result); } -template auto M68K::instructionADDQ(uint4 immediate, EffectiveAddress modify) -> void { - auto source = read(modify); - auto target = immediate; +template auto M68K::instructionADDQ(uint4 immediate, EffectiveAddress with) -> void { + auto source = immediate; + auto target = read(with); auto result = ADD(source, target); - write(modify, result); + write(with, result); +} + +template auto M68K::instructionADDQ(uint4 immediate, AddressRegister with) -> void { + auto result = read(with) + immediate; + write(with, result); } template auto M68K::instructionADDX(EffectiveAddress with, EffectiveAddress from) -> void { @@ -525,8 +530,9 @@ auto M68K::instructionJMP(EffectiveAddress target) -> void { } auto M68K::instructionJSR(EffectiveAddress target) -> void { + auto pc = fetch(target); push(r.pc); - r.pc = fetch(target); + r.pc = pc; } auto M68K::instructionLEA(AddressRegister ar, EffectiveAddress ea) -> void { @@ -745,7 +751,7 @@ auto M68K::instructionMULU(DataRegister with, EffectiveAddress from) -> void { auto M68K::instructionNBCD(EffectiveAddress with) -> void { auto source = 0u; auto target = read(with); - auto result = (uint64)target - source - r.x; + auto result = target - source - r.x; bool v = false; const bool adjustLo = (target ^ source ^ result) & 0x10; @@ -1001,7 +1007,7 @@ auto M68K::instructionRTS() -> void { auto M68K::instructionSBCD(EffectiveAddress with, EffectiveAddress from) -> void { auto source = read(from); auto target = read(with); - auto result = (uint64)target - source - r.x; + auto result = target - source - r.x; bool v = false; const bool adjustLo = (target ^ source ^ result) & 0x10; @@ -1080,11 +1086,16 @@ template auto M68K::instructionSUBI(EffectiveAddress with) -> void { write(with, result); } -template auto M68K::instructionSUBQ(uint4 immediate, EffectiveAddress ea) -> void { +template auto M68K::instructionSUBQ(uint4 immediate, EffectiveAddress with) -> void { auto source = immediate; - auto target = read(ea); + auto target = read(with); auto result = SUB(source, target); - write(ea, result); + write(with, result); +} + +template auto M68K::instructionSUBQ(uint4 immediate, AddressRegister with) -> void { + auto result = read(with) - immediate; + write(with, result); } template auto M68K::instructionSUBX(EffectiveAddress with, EffectiveAddress from) -> void { diff --git a/higan/processor/m68k/m68k.hpp b/higan/processor/m68k/m68k.hpp index 0595ba03..c06f222c 100644 --- a/higan/processor/m68k/m68k.hpp +++ b/higan/processor/m68k/m68k.hpp @@ -125,7 +125,8 @@ struct M68K { template auto instructionADD(DataRegister from, EffectiveAddress with) -> void; template auto instructionADDA(AddressRegister ar, EffectiveAddress ea) -> void; template auto instructionADDI(EffectiveAddress modify) -> void; - template auto instructionADDQ(uint4 immediate, EffectiveAddress modify) -> void; + template auto instructionADDQ(uint4 immediate, EffectiveAddress with) -> void; + template auto instructionADDQ(uint4 immediate, AddressRegister with) -> void; template auto instructionADDX(EffectiveAddress with, EffectiveAddress from) -> void; template auto AND(uint32 source, uint32 target) -> uint32; template auto instructionAND(EffectiveAddress from, DataRegister with) -> void; @@ -237,7 +238,8 @@ struct M68K { template auto instructionSUB(DataRegister source, EffectiveAddress target) -> void; template auto instructionSUBA(AddressRegister to, EffectiveAddress from) -> void; template auto instructionSUBI(EffectiveAddress with) -> void; - template auto instructionSUBQ(uint4 immediate, EffectiveAddress ea) -> void; + template auto instructionSUBQ(uint4 immediate, EffectiveAddress with) -> void; + template auto instructionSUBQ(uint4 immediate, AddressRegister with) -> void; template auto instructionSUBX(EffectiveAddress with, EffectiveAddress from) -> void; auto instructionSWAP(DataRegister with) -> void; auto instructionTAS(EffectiveAddress with) -> void; @@ -281,7 +283,8 @@ private: template auto disassembleADD(DataRegister from, EffectiveAddress with) -> string; template auto disassembleADDA(AddressRegister ar, EffectiveAddress ea) -> string; template auto disassembleADDI(EffectiveAddress modify) -> string; - template auto disassembleADDQ(uint4 immediate, EffectiveAddress modify) -> string; + template auto disassembleADDQ(uint4 immediate, EffectiveAddress with) -> string; + template auto disassembleADDQ(uint4 immediate, AddressRegister with) -> string; template auto disassembleADDX(EffectiveAddress with, EffectiveAddress from) -> string; template auto disassembleAND(EffectiveAddress from, DataRegister with) -> string; template auto disassembleAND(DataRegister from, EffectiveAddress with) -> string; @@ -379,7 +382,8 @@ private: template auto disassembleSUB(DataRegister source, EffectiveAddress target) -> string; template auto disassembleSUBA(AddressRegister to, EffectiveAddress from) -> string; template auto disassembleSUBI(EffectiveAddress with) -> string; - template auto disassembleSUBQ(uint4 immediate, EffectiveAddress ea) -> string; + template auto disassembleSUBQ(uint4 immediate, EffectiveAddress with) -> string; + template auto disassembleSUBQ(uint4 immediate, AddressRegister with) -> string; template auto disassembleSUBX(EffectiveAddress with, EffectiveAddress from) -> string; auto disassembleSWAP(DataRegister with) -> string; auto disassembleTAS(EffectiveAddress with) -> string; diff --git a/higan/target-tomoko/presentation/presentation.cpp b/higan/target-tomoko/presentation/presentation.cpp index af4c3bb0..0513af05 100644 --- a/higan/target-tomoko/presentation/presentation.cpp +++ b/higan/target-tomoko/presentation/presentation.cpp @@ -7,13 +7,23 @@ Presentation::Presentation() { presentation = this; libraryMenu.setText("Library"); + string_vector manufacturers; for(auto& emulator : program->emulators) { - for(auto& medium : emulator->media) { - auto item = new MenuItem{&libraryMenu}; - item->setText({medium.name, " ..."}).onActivate([=] { - program->loadMedium(*emulator, medium); - }); - loadBootableMedia.append(item); + if(!manufacturers.find(emulator->information.manufacturer)) { + manufacturers.append(emulator->information.manufacturer); + } + } + for(auto& manufacturer : manufacturers) { + Menu manufacturerMenu{&libraryMenu}; + manufacturerMenu.setText(manufacturer); + for(auto& emulator : program->emulators) { + if(emulator->information.manufacturer != manufacturer) continue; + for(auto& medium : emulator->media) { + auto item = new MenuItem{&manufacturerMenu}; + item->setText({medium.name, " ..."}).onActivate([=] { + program->loadMedium(*emulator, medium); + }); + } } } //add icarus menu options -- but only if icarus binary is present diff --git a/higan/target-tomoko/presentation/presentation.hpp b/higan/target-tomoko/presentation/presentation.hpp index 169a41d6..497e1f59 100644 --- a/higan/target-tomoko/presentation/presentation.hpp +++ b/higan/target-tomoko/presentation/presentation.hpp @@ -18,8 +18,6 @@ struct Presentation : Window { MenuBar menuBar{this}; Menu libraryMenu{&menuBar}; - vector loadBootableMedia; - MenuSeparator librarySeparator; Menu systemMenu{&menuBar}; MenuItem powerSystem{&systemMenu}; MenuItem resetSystem{&systemMenu}; diff --git a/icarus/core/core.cpp b/icarus/core/core.cpp index e8162e24..d63fe827 100644 --- a/icarus/core/core.cpp +++ b/icarus/core/core.cpp @@ -1,10 +1,12 @@ Icarus::Icarus() { database.famicom = BML::unserialize(string::read(locate("Database/Famicom.bml"))); database.superFamicom = BML::unserialize(string::read(locate("Database/Super Famicom.bml"))); + database.masterSystem = BML::unserialize(string::read(locate("Database/Master System.bml"))); database.megaDrive = BML::unserialize(string::read(locate("Database/Mega Drive.bml"))); database.gameBoy = BML::unserialize(string::read(locate("Database/Game Boy.bml"))); database.gameBoyColor = BML::unserialize(string::read(locate("Database/Game Boy Color.bml"))); database.gameBoyAdvance = BML::unserialize(string::read(locate("Database/Game Boy Advance.bml"))); + database.gameGear = BML::unserialize(string::read(locate("Database/Game Gear.bml"))); database.wonderSwan = BML::unserialize(string::read(locate("Database/WonderSwan.bml"))); database.wonderSwanColor = BML::unserialize(string::read(locate("Database/WonderSwan Color.bml"))); database.bsMemory = BML::unserialize(string::read(locate("Database/BS Memory.bml"))); @@ -32,10 +34,12 @@ auto Icarus::manifest(string location) -> string { auto type = Location::suffix(location).downcase(); if(type == ".fc") return famicomManifest(location); if(type == ".sfc") return superFamicomManifest(location); + if(type == ".ms") return masterSystemManifest(location); if(type == ".md") return megaDriveManifest(location); if(type == ".gb") return gameBoyManifest(location); if(type == ".gbc") return gameBoyColorManifest(location); if(type == ".gba") return gameBoyAdvanceManifest(location); + if(type == ".gg") return gameGearManifest(location); if(type == ".ws") return wonderSwanManifest(location); if(type == ".wsc") return wonderSwanColorManifest(location); if(type == ".bs") return bsMemoryManifest(location); @@ -68,10 +72,12 @@ auto Icarus::import(string location) -> string { if(type == ".fc" || type == ".nes") return famicomImport(buffer, location); if(type == ".sfc" || type == ".smc") return superFamicomImport(buffer, location); - if(type == ".md") return megaDriveImport(buffer, location); + if(type == ".ms" || type == ".sms") return masterSystemImport(buffer, location); + if(type == ".md" || type == ".smd" || type == ".gen") return megaDriveImport(buffer, location); if(type == ".gb") return gameBoyImport(buffer, location); if(type == ".gbc") return gameBoyColorImport(buffer, location); if(type == ".gba") return gameBoyAdvanceImport(buffer, location); + if(type == ".gg") return gameGearImport(buffer, location); if(type == ".ws") return wonderSwanImport(buffer, location); if(type == ".wsc") return wonderSwanColorImport(buffer, location); if(type == ".bs") return bsMemoryImport(buffer, location); diff --git a/icarus/core/core.hpp b/icarus/core/core.hpp index 6e6c6718..8e663c1c 100644 --- a/icarus/core/core.hpp +++ b/icarus/core/core.hpp @@ -22,6 +22,11 @@ struct Icarus { auto superFamicomManifestScan(vector& roms, Markup::Node node) -> void; auto superFamicomImport(vector& buffer, string location) -> string; + //master-system.cpp + auto masterSystemManifest(string location) -> string; + auto masterSystemManifest(vector& buffer, string location) -> string; + auto masterSystemImport(vector& buffer, string location) -> string; + //mega-drive.cpp auto megaDriveManifest(string location) -> string; auto megaDriveManifest(vector& buffer, string location) -> string; @@ -42,15 +47,10 @@ struct Icarus { auto gameBoyAdvanceManifest(vector& buffer, string location) -> string; auto gameBoyAdvanceImport(vector& buffer, string location) -> string; - //bs-memory.cpp - auto bsMemoryManifest(string location) -> string; - auto bsMemoryManifest(vector& buffer, string location) -> string; - auto bsMemoryImport(vector& buffer, string location) -> string; - - //sufami-turbo.cpp - auto sufamiTurboManifest(string location) -> string; - auto sufamiTurboManifest(vector& buffer, string location) -> string; - auto sufamiTurboImport(vector& buffer, string location) -> string; + //game-gear.cpp + auto gameGearManifest(string location) -> string; + auto gameGearManifest(vector& buffer, string location) -> string; + auto gameGearImport(vector& buffer, string location) -> string; //wonderswan.cpp auto wonderSwanManifest(string location) -> string; @@ -62,16 +62,28 @@ struct Icarus { auto wonderSwanColorManifest(vector& buffer, string location) -> string; auto wonderSwanColorImport(vector& buffer, string location) -> string; + //bs-memory.cpp + auto bsMemoryManifest(string location) -> string; + auto bsMemoryManifest(vector& buffer, string location) -> string; + auto bsMemoryImport(vector& buffer, string location) -> string; + + //sufami-turbo.cpp + auto sufamiTurboManifest(string location) -> string; + auto sufamiTurboManifest(vector& buffer, string location) -> string; + auto sufamiTurboImport(vector& buffer, string location) -> string; + private: string errorMessage; struct { Markup::Node famicom; Markup::Node superFamicom; + Markup::Node masterSystem; Markup::Node megaDrive; Markup::Node gameBoy; Markup::Node gameBoyColor; Markup::Node gameBoyAdvance; + Markup::Node gameGear; Markup::Node wonderSwan; Markup::Node wonderSwanColor; Markup::Node bsMemory; diff --git a/icarus/core/game-gear.cpp b/icarus/core/game-gear.cpp new file mode 100644 index 00000000..40b7b6b1 --- /dev/null +++ b/icarus/core/game-gear.cpp @@ -0,0 +1,45 @@ +auto Icarus::gameGearManifest(string location) -> string { + vector buffer; + concatenate(buffer, {location, "program.rom"}); + return gameGearManifest(buffer, location); +} + +auto Icarus::gameGearManifest(vector& buffer, string location) -> string { + string manifest; + + if(settings["icarus/UseDatabase"].boolean() && !manifest) { + string digest = Hash::SHA256(buffer.data(), buffer.size()).digest(); + for(auto node : database.gameGear) { + if(node["sha256"].text() == digest) { + manifest.append(node.text(), "\n sha256: ", digest, "\n"); + break; + } + } + } + + if(settings["icarus/UseHeuristics"].boolean() && !manifest) { + GameGearCartridge cartridge{location, buffer.data(), buffer.size()}; + manifest = cartridge.manifest; + } + + return manifest; +} + +auto Icarus::gameGearImport(vector& buffer, string location) -> string { + auto name = Location::prefix(location); + auto source = Location::path(location); + string target{settings["Library/Location"].text(), "Game Gear/", name, ".gg/"}; +//if(directory::exists(target)) return failure("game already exists"); + + auto manifest = gameGearManifest(buffer, location); + if(!manifest) return failure("failed to parse ROM image"); + + if(!directory::create(target)) return failure("library path unwritable"); + if(file::exists({source, name, ".sav"}) && !file::exists({target, "save.ram"})) { + file::copy({source, name, ".sav"}, {target, "save.ram"}); + } + + if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, manifest); + file::write({target, "program.rom"}, buffer); + return success(target); +} diff --git a/icarus/core/master-system.cpp b/icarus/core/master-system.cpp new file mode 100644 index 00000000..c0d75c82 --- /dev/null +++ b/icarus/core/master-system.cpp @@ -0,0 +1,45 @@ +auto Icarus::masterSystemManifest(string location) -> string { + vector buffer; + concatenate(buffer, {location, "program.rom"}); + return masterSystemManifest(buffer, location); +} + +auto Icarus::masterSystemManifest(vector& buffer, string location) -> string { + string manifest; + + if(settings["icarus/UseDatabase"].boolean() && !manifest) { + string digest = Hash::SHA256(buffer.data(), buffer.size()).digest(); + for(auto node : database.masterSystem) { + if(node["sha256"].text() == digest) { + manifest.append(node.text(), "\n sha256: ", digest, "\n"); + break; + } + } + } + + if(settings["icarus/UseHeuristics"].boolean() && !manifest) { + MasterSystemCartridge cartridge{location, buffer.data(), buffer.size()}; + manifest = cartridge.manifest; + } + + return manifest; +} + +auto Icarus::masterSystemImport(vector& buffer, string location) -> string { + auto name = Location::prefix(location); + auto source = Location::path(location); + string target{settings["Library/Location"].text(), "Master System/", name, ".ms/"}; +//if(directory::exists(target)) return failure("game already exists"); + + auto manifest = masterSystemManifest(buffer, location); + if(!manifest) return failure("failed to parse ROM image"); + + if(!directory::create(target)) return failure("library path unwritable"); + if(file::exists({source, name, ".sav"}) && !file::exists({target, "save.ram"})) { + file::copy({source, name, ".sav"}, {target, "save.ram"}); + } + + if(settings["icarus/CreateManifests"].boolean()) file::write({target, "manifest.bml"}, manifest); + file::write({target, "program.rom"}, buffer); + return success(target); +} diff --git a/icarus/heuristics/game-gear.cpp b/icarus/heuristics/game-gear.cpp new file mode 100644 index 00000000..3667f226 --- /dev/null +++ b/icarus/heuristics/game-gear.cpp @@ -0,0 +1,20 @@ +struct GameGearCartridge { + GameGearCartridge(string location, uint8_t* data, uint size); + + string manifest; + +//private: + struct Information { + } information; +}; + +GameGearCartridge::GameGearCartridge(string location, uint8_t* data, uint size) { + manifest.append("board\n"); + manifest.append(" rom name=program.rom size=0x", hex(size), "\n"); + manifest.append("\n"); + manifest.append("information\n"); + manifest.append(" title: ", Location::prefix(location), "\n"); + manifest.append(" sha256: ", Hash::SHA256(data, size).digest(), "\n"); + manifest.append("\n"); + manifest.append("note: heuristically generated by icarus\n"); +} diff --git a/icarus/heuristics/master-system.cpp b/icarus/heuristics/master-system.cpp new file mode 100644 index 00000000..79cee49e --- /dev/null +++ b/icarus/heuristics/master-system.cpp @@ -0,0 +1,20 @@ +struct MasterSystemCartridge { + MasterSystemCartridge(string location, uint8_t* data, uint size); + + string manifest; + +//private: + struct Information { + } information; +}; + +MasterSystemCartridge::MasterSystemCartridge(string location, uint8_t* data, uint size) { + manifest.append("board\n"); + manifest.append(" rom name=program.rom size=0x", hex(size), "\n"); + manifest.append("\n"); + manifest.append("information\n"); + manifest.append(" title: ", Location::prefix(location), "\n"); + manifest.append(" sha256: ", Hash::SHA256(data, size).digest(), "\n"); + manifest.append("\n"); + manifest.append("note: heuristically generated by icarus\n"); +} diff --git a/icarus/icarus.cpp b/icarus/icarus.cpp index e702f5c2..79fdab65 100644 --- a/icarus/icarus.cpp +++ b/icarus/icarus.cpp @@ -20,9 +20,11 @@ Settings settings; #include "heuristics/famicom.cpp" #include "heuristics/super-famicom.cpp" +#include "heuristics/master-system.cpp" #include "heuristics/mega-drive.cpp" #include "heuristics/game-boy.cpp" #include "heuristics/game-boy-advance.cpp" +#include "heuristics/game-gear.cpp" #include "heuristics/wonderswan.cpp" #include "heuristics/bs-memory.cpp" #include "heuristics/sufami-turbo.cpp" @@ -31,10 +33,12 @@ Settings settings; #include "core/core.cpp" #include "core/famicom.cpp" #include "core/super-famicom.cpp" +#include "core/master-system.cpp" #include "core/mega-drive.cpp" #include "core/game-boy.cpp" #include "core/game-boy-color.cpp" #include "core/game-boy-advance.cpp" +#include "core/game-gear.cpp" #include "core/wonderswan.cpp" #include "core/wonderswan-color.cpp" #include "core/bs-memory.cpp" @@ -68,8 +72,21 @@ auto nall::main(string_vector args) -> void { if(string source = BrowserDialog() .setTitle("Load ROM Image") .setPath(settings["icarus/Path"].text()) - .setFilters("ROM Files|*.fc:*.nes:*.sfc:*.smc:*.md:*.gb:*.gbc:*.gba:*.ws:*.wsc:*.bs:*.st:*.zip") - .openFile()) { + .setFilters("ROM Files|" + "*.fc:*.nes:" + "*.sfc:*.smc:" + "*.ms:*.sms:" + "*.md:*.smd:*.gen:" + "*.gb:" + "*.gbc:" + "*.gba:" + "*.gg:" + "*.ws:" + "*.wsc:" + "*.bs:" + "*.st:" + "*.zip" + ).openFile()) { if(string target = icarus.import(source)) { settings["icarus/Path"].setValue(Location::path(source)); return print(target, "\n");