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.
This commit is contained in:
Tim Allen 2016-08-18 08:04:50 +10:00
parent 043f6a8b33
commit 4d2e17f9c0
16 changed files with 266 additions and 62 deletions

View File

@ -12,7 +12,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; 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 Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "http://byuu.org/"; static const string Website = "http://byuu.org/";

View File

@ -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 VDP::readByte(uint24 addr) -> uint8 {
auto data = readWord(addr & ~1); auto data = readWord(addr & ~1);
return data << 8 | data << 0; return data.byte(!addr.bit(0));
} }
auto VDP::writeByte(uint24 addr, uint8 data) -> void { auto VDP::writeByte(uint24 addr, uint8 data) -> void {
@ -24,6 +22,11 @@ auto VDP::readWord(uint24 addr) -> uint16 {
return readControlPort(); return readControlPort();
} }
//counter
case 0xc00008: case 0xc0000a: case 0xc0000c: case 0xc0000e: {
return state.y << 8 | (state.x >> 1) << 0;
}
} }
return 0x0000; return 0x0000;

View File

@ -1,8 +1,5 @@
#include <md/md.hpp> #include <md/md.hpp>
//256-width = colorburst * 15 / 10
//320-width = colorburst * 15 / 8
namespace MegaDrive { namespace MegaDrive {
VDP vdp; VDP vdp;
@ -25,19 +22,19 @@ auto VDP::main() -> void {
cpu.lower(CPU::Interrupt::HorizontalBlank); cpu.lower(CPU::Interrupt::HorizontalBlank);
for(uint x : range(320)) { for(uint x : range(320)) {
run(); run();
step(1); step(4);
} }
if(io.horizontalBlankInterruptEnable) { if(io.horizontalBlankInterruptEnable) {
cpu.raise(CPU::Interrupt::HorizontalBlank); cpu.raise(CPU::Interrupt::HorizontalBlank);
} }
step(22); step(430);
} else { } else {
if(state.y == 240) { if(state.y == 240) {
if(io.verticalBlankInterruptEnable) { if(io.verticalBlankInterruptEnable) {
cpu.raise(CPU::Interrupt::VerticalBlank); cpu.raise(CPU::Interrupt::VerticalBlank);
} }
} }
step(342); step(1710);
} }
} }
@ -61,7 +58,7 @@ auto VDP::power() -> void {
} }
auto VDP::reset() -> 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)); memory::fill(&io, sizeof(IO));

View File

@ -126,8 +126,12 @@ template<uint Size> auto M68K::disassembleADDI(EffectiveAddress ea) -> string {
return {"addi", _suffix<Size>(), " ", _immediate<Size>(), ",", _effectiveAddress<Size>(ea)}; return {"addi", _suffix<Size>(), " ", _immediate<Size>(), ",", _effectiveAddress<Size>(ea)};
} }
template<uint Size> auto M68K::disassembleADDQ(uint4 immediate, EffectiveAddress modify) -> string { template<uint Size> auto M68K::disassembleADDQ(uint4 immediate, EffectiveAddress with) -> string {
return {"addq", _suffix<Size>(), " #", immediate, ",", _effectiveAddress<Size>(modify)}; return {"addq", _suffix<Size>(), " #", immediate, ",", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleADDQ(uint4 immediate, AddressRegister with) -> string {
return {"addq", _suffix<Size>(), " #", immediate, ",", _addressRegister(with)};
} }
template<uint Size> auto M68K::disassembleADDX(EffectiveAddress with, EffectiveAddress from) -> string { template<uint Size> auto M68K::disassembleADDX(EffectiveAddress with, EffectiveAddress from) -> string {
@ -543,8 +547,12 @@ template<uint Size> auto M68K::disassembleSUBI(EffectiveAddress with) -> string
return {"subi", _suffix<Size>(), " ", _immediate<Size>(), ",", _effectiveAddress<Size>(with)}; return {"subi", _suffix<Size>(), " ", _immediate<Size>(), ",", _effectiveAddress<Size>(with)};
} }
template<uint Size> auto M68K::disassembleSUBQ(uint4 immediate, EffectiveAddress ea) -> string { template<uint Size> auto M68K::disassembleSUBQ(uint4 immediate, EffectiveAddress with) -> string {
return {"subq", _suffix<Size>(), " #", immediate, ",", _effectiveAddress<Size>(ea)}; return {"subq", _suffix<Size>(), " #", immediate, ",", _effectiveAddress<Size>(with)};
}
template<uint Size> auto M68K::disassembleSUBQ(uint4 immediate, AddressRegister with) -> string {
return {"subq", _suffix<Size>(), " #", immediate, ",", _addressRegister(with)};
} }
template<uint Size> auto M68K::disassembleSUBX(EffectiveAddress with, EffectiveAddress from) -> string { template<uint Size> auto M68K::disassembleSUBX(EffectiveAddress with, EffectiveAddress from) -> string {

View File

@ -106,12 +106,16 @@ M68K::M68K() {
if(mode == 7 && reg >= 2) continue; if(mode == 7 && reg >= 2) continue;
uint4 immediate = data ? (uint4)data : (uint4)8; uint4 immediate = data ? (uint4)data : (uint4)8;
EffectiveAddress modify{mode, reg}; if(mode != 1) {
bind(opcode | 0 << 6, ADDQ<Byte>, immediate, modify); EffectiveAddress with{mode, reg};
bind(opcode | 1 << 6, ADDQ<Word>, immediate, modify); bind(opcode | 0 << 6, ADDQ<Byte>, immediate, with);
bind(opcode | 2 << 6, ADDQ<Long>, immediate, modify); bind(opcode | 1 << 6, ADDQ<Word>, immediate, with);
bind(opcode | 2 << 6, ADDQ<Long>, immediate, with);
if(mode == 1) unbind(opcode | 0 << 6); } else {
AddressRegister with{reg};
bind(opcode | 1 << 6, ADDQ<Word>, immediate, with);
bind(opcode | 2 << 6, ADDQ<Long>, immediate, with);
}
} }
//ADDX //ADDX
@ -1178,12 +1182,16 @@ M68K::M68K() {
if(mode == 7 && reg >= 2) continue; if(mode == 7 && reg >= 2) continue;
auto immediate = data ? (uint4)data : (uint4)8; auto immediate = data ? (uint4)data : (uint4)8;
EffectiveAddress ea{mode, reg}; if(mode != 1) {
bind(opcode | 0 << 6, SUBQ<Byte>, immediate, ea); EffectiveAddress with{mode, reg};
bind(opcode | 1 << 6, SUBQ<Word>, immediate, ea); bind(opcode | 0 << 6, SUBQ<Byte>, immediate, with);
bind(opcode | 2 << 6, SUBQ<Long>, immediate, ea); bind(opcode | 1 << 6, SUBQ<Word>, immediate, with);
bind(opcode | 2 << 6, SUBQ<Long>, immediate, with);
if(mode == 1) unbind(opcode | 0 << 6); } else {
AddressRegister with{reg};
bind(opcode | 1 << 6, SUBQ<Word>, immediate, with);
bind(opcode | 2 << 6, SUBQ<Long>, immediate, with);
}
} }
//SUBX //SUBX

View File

@ -105,7 +105,7 @@ template<uint Size> auto M68K::instructionADD(DataRegister from, EffectiveAddres
} }
template<uint Size> auto M68K::instructionADDA(AddressRegister ar, EffectiveAddress ea) -> void { template<uint Size> auto M68K::instructionADDA(AddressRegister ar, EffectiveAddress ea) -> void {
auto source = read<Size>(ea); auto source = sign<Size>(read<Size>(ea));
auto target = read<Size>(ar); auto target = read<Size>(ar);
write<Long>(ar, source + target); write<Long>(ar, source + target);
} }
@ -117,11 +117,16 @@ template<uint Size> auto M68K::instructionADDI(EffectiveAddress modify) -> void
write<Size>(modify, result); write<Size>(modify, result);
} }
template<uint Size> auto M68K::instructionADDQ(uint4 immediate, EffectiveAddress modify) -> void { template<uint Size> auto M68K::instructionADDQ(uint4 immediate, EffectiveAddress with) -> void {
auto source = read<Size, Hold>(modify); auto source = immediate;
auto target = immediate; auto target = read<Size, Hold>(with);
auto result = ADD<Size>(source, target); auto result = ADD<Size>(source, target);
write<Size>(modify, result); write<Size>(with, result);
}
template<uint Size> auto M68K::instructionADDQ(uint4 immediate, AddressRegister with) -> void {
auto result = read<Size>(with) + immediate;
write<Long>(with, result);
} }
template<uint Size> auto M68K::instructionADDX(EffectiveAddress with, EffectiveAddress from) -> void { template<uint Size> 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 M68K::instructionJSR(EffectiveAddress target) -> void {
auto pc = fetch<Long>(target);
push<Long>(r.pc); push<Long>(r.pc);
r.pc = fetch<Long>(target); r.pc = pc;
} }
auto M68K::instructionLEA(AddressRegister ar, EffectiveAddress ea) -> void { 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 M68K::instructionNBCD(EffectiveAddress with) -> void {
auto source = 0u; auto source = 0u;
auto target = read<Byte, Hold>(with); auto target = read<Byte, Hold>(with);
auto result = (uint64)target - source - r.x; auto result = target - source - r.x;
bool v = false; bool v = false;
const bool adjustLo = (target ^ source ^ result) & 0x10; const bool adjustLo = (target ^ source ^ result) & 0x10;
@ -1001,7 +1007,7 @@ auto M68K::instructionRTS() -> void {
auto M68K::instructionSBCD(EffectiveAddress with, EffectiveAddress from) -> void { auto M68K::instructionSBCD(EffectiveAddress with, EffectiveAddress from) -> void {
auto source = read<Byte>(from); auto source = read<Byte>(from);
auto target = read<Byte, Hold>(with); auto target = read<Byte, Hold>(with);
auto result = (uint64)target - source - r.x; auto result = target - source - r.x;
bool v = false; bool v = false;
const bool adjustLo = (target ^ source ^ result) & 0x10; const bool adjustLo = (target ^ source ^ result) & 0x10;
@ -1080,11 +1086,16 @@ template<uint Size> auto M68K::instructionSUBI(EffectiveAddress with) -> void {
write<Size>(with, result); write<Size>(with, result);
} }
template<uint Size> auto M68K::instructionSUBQ(uint4 immediate, EffectiveAddress ea) -> void { template<uint Size> auto M68K::instructionSUBQ(uint4 immediate, EffectiveAddress with) -> void {
auto source = immediate; auto source = immediate;
auto target = read<Size, Hold>(ea); auto target = read<Size, Hold>(with);
auto result = SUB<Size>(source, target); auto result = SUB<Size>(source, target);
write<Size>(ea, result); write<Size>(with, result);
}
template<uint Size> auto M68K::instructionSUBQ(uint4 immediate, AddressRegister with) -> void {
auto result = read<Size>(with) - immediate;
write<Size>(with, result);
} }
template<uint Size> auto M68K::instructionSUBX(EffectiveAddress with, EffectiveAddress from) -> void { template<uint Size> auto M68K::instructionSUBX(EffectiveAddress with, EffectiveAddress from) -> void {

View File

@ -125,7 +125,8 @@ struct M68K {
template<uint Size> auto instructionADD(DataRegister from, EffectiveAddress with) -> void; template<uint Size> auto instructionADD(DataRegister from, EffectiveAddress with) -> void;
template<uint Size> auto instructionADDA(AddressRegister ar, EffectiveAddress ea) -> void; template<uint Size> auto instructionADDA(AddressRegister ar, EffectiveAddress ea) -> void;
template<uint Size> auto instructionADDI(EffectiveAddress modify) -> void; template<uint Size> auto instructionADDI(EffectiveAddress modify) -> void;
template<uint Size> auto instructionADDQ(uint4 immediate, EffectiveAddress modify) -> void; template<uint Size> auto instructionADDQ(uint4 immediate, EffectiveAddress with) -> void;
template<uint Size> auto instructionADDQ(uint4 immediate, AddressRegister with) -> void;
template<uint Size> auto instructionADDX(EffectiveAddress with, EffectiveAddress from) -> void; template<uint Size> auto instructionADDX(EffectiveAddress with, EffectiveAddress from) -> void;
template<uint Size> auto AND(uint32 source, uint32 target) -> uint32; template<uint Size> auto AND(uint32 source, uint32 target) -> uint32;
template<uint Size> auto instructionAND(EffectiveAddress from, DataRegister with) -> void; template<uint Size> auto instructionAND(EffectiveAddress from, DataRegister with) -> void;
@ -237,7 +238,8 @@ struct M68K {
template<uint Size> auto instructionSUB(DataRegister source, EffectiveAddress target) -> void; template<uint Size> auto instructionSUB(DataRegister source, EffectiveAddress target) -> void;
template<uint Size> auto instructionSUBA(AddressRegister to, EffectiveAddress from) -> void; template<uint Size> auto instructionSUBA(AddressRegister to, EffectiveAddress from) -> void;
template<uint Size> auto instructionSUBI(EffectiveAddress with) -> void; template<uint Size> auto instructionSUBI(EffectiveAddress with) -> void;
template<uint Size> auto instructionSUBQ(uint4 immediate, EffectiveAddress ea) -> void; template<uint Size> auto instructionSUBQ(uint4 immediate, EffectiveAddress with) -> void;
template<uint Size> auto instructionSUBQ(uint4 immediate, AddressRegister with) -> void;
template<uint Size> auto instructionSUBX(EffectiveAddress with, EffectiveAddress from) -> void; template<uint Size> auto instructionSUBX(EffectiveAddress with, EffectiveAddress from) -> void;
auto instructionSWAP(DataRegister with) -> void; auto instructionSWAP(DataRegister with) -> void;
auto instructionTAS(EffectiveAddress with) -> void; auto instructionTAS(EffectiveAddress with) -> void;
@ -281,7 +283,8 @@ private:
template<uint Size> auto disassembleADD(DataRegister from, EffectiveAddress with) -> string; template<uint Size> auto disassembleADD(DataRegister from, EffectiveAddress with) -> string;
template<uint Size> auto disassembleADDA(AddressRegister ar, EffectiveAddress ea) -> string; template<uint Size> auto disassembleADDA(AddressRegister ar, EffectiveAddress ea) -> string;
template<uint Size> auto disassembleADDI(EffectiveAddress modify) -> string; template<uint Size> auto disassembleADDI(EffectiveAddress modify) -> string;
template<uint Size> auto disassembleADDQ(uint4 immediate, EffectiveAddress modify) -> string; template<uint Size> auto disassembleADDQ(uint4 immediate, EffectiveAddress with) -> string;
template<uint Size> auto disassembleADDQ(uint4 immediate, AddressRegister with) -> string;
template<uint Size> auto disassembleADDX(EffectiveAddress with, EffectiveAddress from) -> string; template<uint Size> auto disassembleADDX(EffectiveAddress with, EffectiveAddress from) -> string;
template<uint Size> auto disassembleAND(EffectiveAddress from, DataRegister with) -> string; template<uint Size> auto disassembleAND(EffectiveAddress from, DataRegister with) -> string;
template<uint Size> auto disassembleAND(DataRegister from, EffectiveAddress with) -> string; template<uint Size> auto disassembleAND(DataRegister from, EffectiveAddress with) -> string;
@ -379,7 +382,8 @@ private:
template<uint Size> auto disassembleSUB(DataRegister source, EffectiveAddress target) -> string; template<uint Size> auto disassembleSUB(DataRegister source, EffectiveAddress target) -> string;
template<uint Size> auto disassembleSUBA(AddressRegister to, EffectiveAddress from) -> string; template<uint Size> auto disassembleSUBA(AddressRegister to, EffectiveAddress from) -> string;
template<uint Size> auto disassembleSUBI(EffectiveAddress with) -> string; template<uint Size> auto disassembleSUBI(EffectiveAddress with) -> string;
template<uint Size> auto disassembleSUBQ(uint4 immediate, EffectiveAddress ea) -> string; template<uint Size> auto disassembleSUBQ(uint4 immediate, EffectiveAddress with) -> string;
template<uint Size> auto disassembleSUBQ(uint4 immediate, AddressRegister with) -> string;
template<uint Size> auto disassembleSUBX(EffectiveAddress with, EffectiveAddress from) -> string; template<uint Size> auto disassembleSUBX(EffectiveAddress with, EffectiveAddress from) -> string;
auto disassembleSWAP(DataRegister with) -> string; auto disassembleSWAP(DataRegister with) -> string;
auto disassembleTAS(EffectiveAddress with) -> string; auto disassembleTAS(EffectiveAddress with) -> string;

View File

@ -7,13 +7,23 @@ Presentation::Presentation() {
presentation = this; presentation = this;
libraryMenu.setText("Library"); libraryMenu.setText("Library");
string_vector manufacturers;
for(auto& emulator : program->emulators) { for(auto& emulator : program->emulators) {
for(auto& medium : emulator->media) { if(!manufacturers.find(emulator->information.manufacturer)) {
auto item = new MenuItem{&libraryMenu}; manufacturers.append(emulator->information.manufacturer);
item->setText({medium.name, " ..."}).onActivate([=] { }
program->loadMedium(*emulator, medium); }
}); for(auto& manufacturer : manufacturers) {
loadBootableMedia.append(item); 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 //add icarus menu options -- but only if icarus binary is present

View File

@ -18,8 +18,6 @@ struct Presentation : Window {
MenuBar menuBar{this}; MenuBar menuBar{this};
Menu libraryMenu{&menuBar}; Menu libraryMenu{&menuBar};
vector<MenuItem*> loadBootableMedia;
MenuSeparator librarySeparator;
Menu systemMenu{&menuBar}; Menu systemMenu{&menuBar};
MenuItem powerSystem{&systemMenu}; MenuItem powerSystem{&systemMenu};
MenuItem resetSystem{&systemMenu}; MenuItem resetSystem{&systemMenu};

View File

@ -1,10 +1,12 @@
Icarus::Icarus() { Icarus::Icarus() {
database.famicom = BML::unserialize(string::read(locate("Database/Famicom.bml"))); database.famicom = BML::unserialize(string::read(locate("Database/Famicom.bml")));
database.superFamicom = BML::unserialize(string::read(locate("Database/Super 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.megaDrive = BML::unserialize(string::read(locate("Database/Mega Drive.bml")));
database.gameBoy = BML::unserialize(string::read(locate("Database/Game Boy.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.gameBoyColor = BML::unserialize(string::read(locate("Database/Game Boy Color.bml")));
database.gameBoyAdvance = BML::unserialize(string::read(locate("Database/Game Boy Advance.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.wonderSwan = BML::unserialize(string::read(locate("Database/WonderSwan.bml")));
database.wonderSwanColor = BML::unserialize(string::read(locate("Database/WonderSwan Color.bml"))); database.wonderSwanColor = BML::unserialize(string::read(locate("Database/WonderSwan Color.bml")));
database.bsMemory = BML::unserialize(string::read(locate("Database/BS Memory.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(); auto type = Location::suffix(location).downcase();
if(type == ".fc") return famicomManifest(location); if(type == ".fc") return famicomManifest(location);
if(type == ".sfc") return superFamicomManifest(location); if(type == ".sfc") return superFamicomManifest(location);
if(type == ".ms") return masterSystemManifest(location);
if(type == ".md") return megaDriveManifest(location); if(type == ".md") return megaDriveManifest(location);
if(type == ".gb") return gameBoyManifest(location); if(type == ".gb") return gameBoyManifest(location);
if(type == ".gbc") return gameBoyColorManifest(location); if(type == ".gbc") return gameBoyColorManifest(location);
if(type == ".gba") return gameBoyAdvanceManifest(location); if(type == ".gba") return gameBoyAdvanceManifest(location);
if(type == ".gg") return gameGearManifest(location);
if(type == ".ws") return wonderSwanManifest(location); if(type == ".ws") return wonderSwanManifest(location);
if(type == ".wsc") return wonderSwanColorManifest(location); if(type == ".wsc") return wonderSwanColorManifest(location);
if(type == ".bs") return bsMemoryManifest(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 == ".fc" || type == ".nes") return famicomImport(buffer, location);
if(type == ".sfc" || type == ".smc") return superFamicomImport(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 == ".gb") return gameBoyImport(buffer, location);
if(type == ".gbc") return gameBoyColorImport(buffer, location); if(type == ".gbc") return gameBoyColorImport(buffer, location);
if(type == ".gba") return gameBoyAdvanceImport(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 == ".ws") return wonderSwanImport(buffer, location);
if(type == ".wsc") return wonderSwanColorImport(buffer, location); if(type == ".wsc") return wonderSwanColorImport(buffer, location);
if(type == ".bs") return bsMemoryImport(buffer, location); if(type == ".bs") return bsMemoryImport(buffer, location);

View File

@ -22,6 +22,11 @@ struct Icarus {
auto superFamicomManifestScan(vector<Markup::Node>& roms, Markup::Node node) -> void; auto superFamicomManifestScan(vector<Markup::Node>& roms, Markup::Node node) -> void;
auto superFamicomImport(vector<uint8_t>& buffer, string location) -> string; auto superFamicomImport(vector<uint8_t>& buffer, string location) -> string;
//master-system.cpp
auto masterSystemManifest(string location) -> string;
auto masterSystemManifest(vector<uint8_t>& buffer, string location) -> string;
auto masterSystemImport(vector<uint8_t>& buffer, string location) -> string;
//mega-drive.cpp //mega-drive.cpp
auto megaDriveManifest(string location) -> string; auto megaDriveManifest(string location) -> string;
auto megaDriveManifest(vector<uint8_t>& buffer, string location) -> string; auto megaDriveManifest(vector<uint8_t>& buffer, string location) -> string;
@ -42,15 +47,10 @@ struct Icarus {
auto gameBoyAdvanceManifest(vector<uint8_t>& buffer, string location) -> string; auto gameBoyAdvanceManifest(vector<uint8_t>& buffer, string location) -> string;
auto gameBoyAdvanceImport(vector<uint8_t>& buffer, string location) -> string; auto gameBoyAdvanceImport(vector<uint8_t>& buffer, string location) -> string;
//bs-memory.cpp //game-gear.cpp
auto bsMemoryManifest(string location) -> string; auto gameGearManifest(string location) -> string;
auto bsMemoryManifest(vector<uint8_t>& buffer, string location) -> string; auto gameGearManifest(vector<uint8_t>& buffer, string location) -> string;
auto bsMemoryImport(vector<uint8_t>& buffer, string location) -> string; auto gameGearImport(vector<uint8_t>& buffer, string location) -> string;
//sufami-turbo.cpp
auto sufamiTurboManifest(string location) -> string;
auto sufamiTurboManifest(vector<uint8_t>& buffer, string location) -> string;
auto sufamiTurboImport(vector<uint8_t>& buffer, string location) -> string;
//wonderswan.cpp //wonderswan.cpp
auto wonderSwanManifest(string location) -> string; auto wonderSwanManifest(string location) -> string;
@ -62,16 +62,28 @@ struct Icarus {
auto wonderSwanColorManifest(vector<uint8_t>& buffer, string location) -> string; auto wonderSwanColorManifest(vector<uint8_t>& buffer, string location) -> string;
auto wonderSwanColorImport(vector<uint8_t>& buffer, string location) -> string; auto wonderSwanColorImport(vector<uint8_t>& buffer, string location) -> string;
//bs-memory.cpp
auto bsMemoryManifest(string location) -> string;
auto bsMemoryManifest(vector<uint8_t>& buffer, string location) -> string;
auto bsMemoryImport(vector<uint8_t>& buffer, string location) -> string;
//sufami-turbo.cpp
auto sufamiTurboManifest(string location) -> string;
auto sufamiTurboManifest(vector<uint8_t>& buffer, string location) -> string;
auto sufamiTurboImport(vector<uint8_t>& buffer, string location) -> string;
private: private:
string errorMessage; string errorMessage;
struct { struct {
Markup::Node famicom; Markup::Node famicom;
Markup::Node superFamicom; Markup::Node superFamicom;
Markup::Node masterSystem;
Markup::Node megaDrive; Markup::Node megaDrive;
Markup::Node gameBoy; Markup::Node gameBoy;
Markup::Node gameBoyColor; Markup::Node gameBoyColor;
Markup::Node gameBoyAdvance; Markup::Node gameBoyAdvance;
Markup::Node gameGear;
Markup::Node wonderSwan; Markup::Node wonderSwan;
Markup::Node wonderSwanColor; Markup::Node wonderSwanColor;
Markup::Node bsMemory; Markup::Node bsMemory;

45
icarus/core/game-gear.cpp Normal file
View File

@ -0,0 +1,45 @@
auto Icarus::gameGearManifest(string location) -> string {
vector<uint8_t> buffer;
concatenate(buffer, {location, "program.rom"});
return gameGearManifest(buffer, location);
}
auto Icarus::gameGearManifest(vector<uint8_t>& 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<uint8_t>& 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);
}

View File

@ -0,0 +1,45 @@
auto Icarus::masterSystemManifest(string location) -> string {
vector<uint8_t> buffer;
concatenate(buffer, {location, "program.rom"});
return masterSystemManifest(buffer, location);
}
auto Icarus::masterSystemManifest(vector<uint8_t>& 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<uint8_t>& 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);
}

View File

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

View File

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

View File

@ -20,9 +20,11 @@ Settings settings;
#include "heuristics/famicom.cpp" #include "heuristics/famicom.cpp"
#include "heuristics/super-famicom.cpp" #include "heuristics/super-famicom.cpp"
#include "heuristics/master-system.cpp"
#include "heuristics/mega-drive.cpp" #include "heuristics/mega-drive.cpp"
#include "heuristics/game-boy.cpp" #include "heuristics/game-boy.cpp"
#include "heuristics/game-boy-advance.cpp" #include "heuristics/game-boy-advance.cpp"
#include "heuristics/game-gear.cpp"
#include "heuristics/wonderswan.cpp" #include "heuristics/wonderswan.cpp"
#include "heuristics/bs-memory.cpp" #include "heuristics/bs-memory.cpp"
#include "heuristics/sufami-turbo.cpp" #include "heuristics/sufami-turbo.cpp"
@ -31,10 +33,12 @@ Settings settings;
#include "core/core.cpp" #include "core/core.cpp"
#include "core/famicom.cpp" #include "core/famicom.cpp"
#include "core/super-famicom.cpp" #include "core/super-famicom.cpp"
#include "core/master-system.cpp"
#include "core/mega-drive.cpp" #include "core/mega-drive.cpp"
#include "core/game-boy.cpp" #include "core/game-boy.cpp"
#include "core/game-boy-color.cpp" #include "core/game-boy-color.cpp"
#include "core/game-boy-advance.cpp" #include "core/game-boy-advance.cpp"
#include "core/game-gear.cpp"
#include "core/wonderswan.cpp" #include "core/wonderswan.cpp"
#include "core/wonderswan-color.cpp" #include "core/wonderswan-color.cpp"
#include "core/bs-memory.cpp" #include "core/bs-memory.cpp"
@ -68,8 +72,21 @@ auto nall::main(string_vector args) -> void {
if(string source = BrowserDialog() if(string source = BrowserDialog()
.setTitle("Load ROM Image") .setTitle("Load ROM Image")
.setPath(settings["icarus/Path"].text()) .setPath(settings["icarus/Path"].text())
.setFilters("ROM Files|*.fc:*.nes:*.sfc:*.smc:*.md:*.gb:*.gbc:*.gba:*.ws:*.wsc:*.bs:*.st:*.zip") .setFilters("ROM Files|"
.openFile()) { "*.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)) { if(string target = icarus.import(source)) {
settings["icarus/Path"].setValue(Location::path(source)); settings["icarus/Path"].setValue(Location::path(source));
return print(target, "\n"); return print(target, "\n");