mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
043f6a8b33
commit
4d2e17f9c0
|
@ -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/";
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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));
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
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) {
|
for(auto& medium : emulator->media) {
|
||||||
auto item = new MenuItem{&libraryMenu};
|
auto item = new MenuItem{&manufacturerMenu};
|
||||||
item->setText({medium.name, " ..."}).onActivate([=] {
|
item->setText({medium.name, " ..."}).onActivate([=] {
|
||||||
program->loadMedium(*emulator, medium);
|
program->loadMedium(*emulator, medium);
|
||||||
});
|
});
|
||||||
loadBootableMedia.append(item);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//add icarus menu options -- but only if icarus binary is present
|
//add icarus menu options -- but only if icarus binary is present
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
|
@ -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");
|
||||||
|
|
Loading…
Reference in New Issue