mirror of https://github.com/bsnes-emu/bsnes.git
Update to v100r02 release.
byuu says: Sigh ... I'm really not a good person. I'm inherently selfish. My responsibility and obligation right now is to work on loki, and then on the Tengai Makyou Zero translation, and then on improving the Famicom emulation. And yet ... it's not what I really want to do. That shouldn't matter; I should work on my responsibilities first. Instead, I'm going to be a greedy, self-centered asshole, and work on what I really want to instead. I'm really sorry, guys. I'm sure this will make a few people happy, and probably upset even more people. I'm also making zero guarantees that this ever gets finished. As always, I wish I could keep these things secret, so if I fail / give up, I could just drop it with no shame. But I would have to cut everyone out of the WIP process completely to make it happen. So, here goes ... This WIP adds the initial skeleton for Sega Mega Drive / Genesis emulation. God help us. (minor note: apparently the new extension for Mega Drive games is .md, neat. That's what I chose for the folders too. I thought it was .smd, so that'll be fixed in icarus for the next WIP.) (aside: this is why I wanted to get v100 out. I didn't want this code in a skeleton state in v100's source. Nor did I want really broken emulation, which the first release is sure to be, tarring said release.) ... So, basically, I've been ruminating on the legacy I want to leave behind with higan. 3D systems are just plain out. I'm never going to support them. They're too complex for my abilities, and they would run too slowly with my design style. I'm not willing to compromise my design ideals. And I would never want to play a 3D game system at native 240p/480i resolution ... but 1080p+ upscaling is not accurate, so that's a conflict I want to avoid entirely. It's also never going to emulate computer systems (X68K, PC-98, FM-Towns, etc) because holy shit that would completely destroy me. It's also never going emulate arcade machines. So I think of higan as a collection of 2D emulators for consoles and handhelds. I've gone over every major 2D gaming system there is, looking for ones with games I actually care about and enjoy. And I basically have five of those systems supported already. Looking at the remaining list, I see only three systems left that I have any interest in whatsoever: PC-Engine, Master System, Mega Drive. Again, I'm not in any way committing to emulating any of these, but ... if I had all of those in higan, I think I'd be content to really, truly, finally stop writing more emulators for the rest of my life. And so I decided to tackle the most difficult system first. If I'm successful, the Z80 core should cover a lot of the work on the SMS. And the HuC6280 should land somewhere between the NES and SNES in terms of difficulty ... closer to the NES. The systems that just don't appeal to me at all, which I will never touch, include, but are not limited to: * Atari 2600/5200/7800 * Lynx * Jaguar * Vectrex * Colecovision * Commodore 64 * Neo-Geo * Neo-Geo Pocket / Color * Virtual Boy * Super A'can * 32X * CD-i * etc, etc, etc. And really, even if something were mildly interesting in there ... we have to stop. I can't scale infinitely. I'm already way past my limit, but I'm doing this anyway. Too many cores bloats everything and kills quality on everything. I don't want higan to become MESS v2. I don't know what I'll do about the Famicom Disk System, PC-Engine CD, and Mega CD. I don't think I'll be able to achieve 60fps emulating the Mega CD, even if I tried to. I don't know what's going to happen here with even the Mega Drive. Maybe I'll get driven crazy with the documentation and quit. Maybe it'll end up being too complicated and I'll quit. Maybe the emulation will end up way too slow and I'll give up. Maybe it'll take me seven years to get any games playable at all. Maybe Steve Snake, AamirM and Mike Pavone will pool money to hire a hitman to come after me. Who knows. But this is what I want to do, so ... here goes nothing.
This commit is contained in:
parent
88c79e56a0
commit
3dd1aa9c1b
|
@ -11,7 +11,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "100.01";
|
||||
static const string Version = "100.02";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
processors += m68k z80
|
||||
|
||||
objects += md-interface
|
||||
objects += md-cpu md-apu md-vdp md-ym2612
|
||||
objects += md-system md-scheduler md-cartridge
|
||||
|
||||
obj/md-interface.o: md/interface/interface.cpp $(call rwildcard,md/interface)
|
||||
obj/md-cpu.o: md/cpu/cpu.cpp $(call rwildcard,md/cpu)
|
||||
obj/md-apu.o: md/apu/apu.cpp $(call rwildcard,md/apu)
|
||||
obj/md-vdp.o: md/vdp/vdp.cpp $(call rwildcard,md/vdp)
|
||||
obj/md-ym2612.o: md/ym2612/ym2612.cpp $(call rwildcard,md/ym2612)
|
||||
obj/md-system.o: md/system/system.cpp $(call rwildcard,md/system)
|
||||
obj/md-scheduler.o: md/scheduler/scheduler.cpp $(call rwildcard,md/scheduler)
|
||||
obj/md-cartridge.o: md/cartridge/cartridge.cpp $(call rwildcard,md/cartridge)
|
|
@ -0,0 +1,7 @@
|
|||
#include <md/md.hpp>
|
||||
|
||||
namespace MegaDrive {
|
||||
|
||||
APU apu;
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
struct APU : Processor::Z80, Thread {
|
||||
};
|
||||
|
||||
extern APU apu;
|
|
@ -0,0 +1,36 @@
|
|||
#include <md/md.hpp>
|
||||
|
||||
namespace MegaDrive {
|
||||
|
||||
Cartridge cartridge;
|
||||
|
||||
auto Cartridge::load() -> bool {
|
||||
information = Information();
|
||||
|
||||
if(auto pathID = interface->load(ID::MegaDrive, "Mega Drive", "md")) {
|
||||
information.pathID = pathID();
|
||||
} else return false;
|
||||
|
||||
if(auto fp = interface->open(pathID(), "manifest.bml", File::Read, File::Required)) {
|
||||
information.manifest = fp->reads();
|
||||
} else return false;
|
||||
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
information.title = document["information/title"].text();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto Cartridge::save() -> void {
|
||||
}
|
||||
|
||||
auto Cartridge::unload() -> void {
|
||||
}
|
||||
|
||||
auto Cartridge::power() -> void {
|
||||
}
|
||||
|
||||
auto Cartridge::reset() -> void {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
struct Cartridge {
|
||||
auto pathID() const -> uint { return information.pathID; }
|
||||
auto sha256() const -> string { return information.sha256; }
|
||||
auto manifest() const -> string { return information.manifest; }
|
||||
auto title() const -> string { return information.title; }
|
||||
|
||||
auto load() -> bool;
|
||||
auto save() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
struct Information {
|
||||
uint pathID = 0;
|
||||
string sha256;
|
||||
string manifest;
|
||||
string title;
|
||||
} information;
|
||||
};
|
||||
|
||||
extern Cartridge cartridge;
|
|
@ -0,0 +1,7 @@
|
|||
#include <md/md.hpp>
|
||||
|
||||
namespace MegaDrive {
|
||||
|
||||
CPU cpu;
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
struct CPU : Processor::M68K, Thread {
|
||||
};
|
||||
|
||||
extern CPU cpu;
|
|
@ -0,0 +1,128 @@
|
|||
#include <md/md.hpp>
|
||||
|
||||
namespace MegaDrive {
|
||||
|
||||
Interface* interface = nullptr;
|
||||
Settings settings;
|
||||
|
||||
Interface::Interface() {
|
||||
interface = this;
|
||||
|
||||
information.manufacturer = "Sega";
|
||||
information.name = "Mega Drive";
|
||||
information.width = 1280;
|
||||
information.height = 480;
|
||||
information.overscan = true;
|
||||
information.aspectRatio = 4.0 / 3.0;
|
||||
information.resettable = true;
|
||||
|
||||
information.capability.states = false;
|
||||
information.capability.cheats = false;
|
||||
|
||||
media.append({ID::MegaDrive, "Mega Drive", "md"});
|
||||
|
||||
Port controllerPort1{ID::Port::Controller1, "Controller Port 1"};
|
||||
Port controllerPort2{ID::Port::Controller2, "Controller Port 2"};
|
||||
|
||||
{ Device device{ID::Device::Gamepad, "Gamepad"};
|
||||
device.inputs.append({0, "Up" });
|
||||
device.inputs.append({0, "Down" });
|
||||
device.inputs.append({0, "Left" });
|
||||
device.inputs.append({0, "Right"});
|
||||
device.inputs.append({0, "A" });
|
||||
device.inputs.append({0, "B" });
|
||||
device.inputs.append({0, "C" });
|
||||
device.inputs.append({0, "X" });
|
||||
device.inputs.append({0, "Y" });
|
||||
device.inputs.append({0, "Z" });
|
||||
device.inputs.append({0, "Start"});
|
||||
controllerPort1.devices.append(device);
|
||||
controllerPort2.devices.append(device);
|
||||
}
|
||||
|
||||
ports.append(move(controllerPort1));
|
||||
ports.append(move(controllerPort2));
|
||||
}
|
||||
|
||||
auto Interface::manifest() -> string {
|
||||
return cartridge.manifest();
|
||||
}
|
||||
|
||||
auto Interface::title() -> string {
|
||||
return cartridge.title();
|
||||
}
|
||||
|
||||
auto Interface::videoFrequency() -> double {
|
||||
return 60.0;
|
||||
}
|
||||
|
||||
auto Interface::videoColors() -> uint32 {
|
||||
return 1 << 9;
|
||||
}
|
||||
|
||||
auto Interface::videoColor(uint32 color) -> uint64 {
|
||||
uint B = color.bits(0,2);
|
||||
uint G = color.bits(3,5);
|
||||
uint R = color.bits(6,8);
|
||||
|
||||
uint64 r = image::normalize(R, 3, 16);
|
||||
uint64 g = image::normalize(G, 3, 16);
|
||||
uint64 b = image::normalize(B, 3, 16);
|
||||
|
||||
return r << 32 | g << 16 | b << 0;
|
||||
}
|
||||
|
||||
auto Interface::audioFrequency() -> double {
|
||||
return 52'000.0;
|
||||
}
|
||||
|
||||
auto Interface::loaded() -> bool {
|
||||
return system.loaded();
|
||||
}
|
||||
|
||||
auto Interface::load(uint id) -> bool {
|
||||
system.load();
|
||||
return false;
|
||||
}
|
||||
|
||||
auto Interface::save() -> void {
|
||||
system.save();
|
||||
}
|
||||
|
||||
auto Interface::unload() -> void {
|
||||
system.unload();
|
||||
}
|
||||
|
||||
auto Interface::power() -> void {
|
||||
system.power();
|
||||
}
|
||||
|
||||
auto Interface::reset() -> void {
|
||||
system.reset();
|
||||
}
|
||||
|
||||
auto Interface::run() -> void {
|
||||
system.run();
|
||||
}
|
||||
|
||||
auto Interface::serialize() -> serializer {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Interface::unserialize(serializer& s) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto Interface::cap(const string& name) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto Interface::get(const string& name) -> any {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto Interface::set(const string& name, const any& value) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
namespace MegaDrive {
|
||||
|
||||
struct ID {
|
||||
enum : uint {
|
||||
System,
|
||||
MegaDrive,
|
||||
};
|
||||
|
||||
struct Port { enum : uint {
|
||||
Controller1,
|
||||
Controller2,
|
||||
};};
|
||||
|
||||
struct Device { enum : uint {
|
||||
Gamepad,
|
||||
};};
|
||||
};
|
||||
|
||||
struct Interface : Emulator::Interface {
|
||||
using Emulator::Interface::load;
|
||||
|
||||
Interface();
|
||||
|
||||
auto manifest() -> string override;
|
||||
auto title() -> string override;
|
||||
auto videoFrequency() -> double override;
|
||||
auto videoColors() -> uint32 override;
|
||||
auto videoColor(uint32 color) -> uint64 override;
|
||||
auto audioFrequency() -> double override;
|
||||
|
||||
auto loaded() -> bool override;
|
||||
auto load(uint id) -> bool override;
|
||||
auto save() -> void override;
|
||||
auto unload() -> void override;
|
||||
|
||||
auto power() -> void override;
|
||||
auto reset() -> void override;
|
||||
auto run() -> void override;
|
||||
|
||||
auto serialize() -> serializer override;
|
||||
auto unserialize(serializer&) -> bool override;
|
||||
|
||||
auto cap(const string& name) -> bool override;
|
||||
auto get(const string& name) -> any override;
|
||||
auto set(const string& name, const any& value) -> bool override;
|
||||
};
|
||||
|
||||
struct Settings {
|
||||
};
|
||||
|
||||
extern Interface* interface;
|
||||
extern Settings settings;
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
//license: GPLv3
|
||||
//started: 2016-07-08
|
||||
|
||||
#include <emulator/emulator.hpp>
|
||||
#include <processor/m68k/m68k.hpp>
|
||||
#include <processor/z80/z80.hpp>
|
||||
|
||||
namespace MegaDrive {
|
||||
using File = Emulator::File;
|
||||
|
||||
struct Thread {
|
||||
~Thread() {
|
||||
if(thread) co_delete(thread);
|
||||
}
|
||||
|
||||
auto create(auto (*entrypoint)() -> void, uint frequency) -> void {
|
||||
if(thread) co_delete(thread);
|
||||
thread = co_create(65'536 * sizeof(void*), entrypoint);
|
||||
this->frequency = frequency;
|
||||
clock = 0;
|
||||
}
|
||||
|
||||
auto serialize(serializer& s) -> void {
|
||||
s.integer(frequency);
|
||||
s.integer(clock);
|
||||
}
|
||||
|
||||
cothread_t thread = nullptr;
|
||||
uint frequency = 0;
|
||||
int64 clock = 0;
|
||||
};
|
||||
|
||||
#include <md/cpu/cpu.hpp>
|
||||
#include <md/apu/apu.hpp>
|
||||
#include <md/vdp/vdp.hpp>
|
||||
#include <md/ym2612/ym2612.hpp>
|
||||
|
||||
#include <md/system/system.hpp>
|
||||
#include <md/scheduler/scheduler.hpp>
|
||||
#include <md/cartridge/cartridge.hpp>
|
||||
}
|
||||
|
||||
#include <md/interface/interface.hpp>
|
|
@ -0,0 +1,7 @@
|
|||
#include <md/md.hpp>
|
||||
|
||||
namespace MegaDrive {
|
||||
|
||||
Scheduler scheduler;
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
struct Scheduler {
|
||||
};
|
||||
|
||||
extern Scheduler scheduler;
|
|
@ -0,0 +1,37 @@
|
|||
#include <md/md.hpp>
|
||||
|
||||
namespace MegaDrive {
|
||||
|
||||
System system;
|
||||
|
||||
auto System::run() -> void {
|
||||
}
|
||||
|
||||
auto System::load() -> bool {
|
||||
information = Information();
|
||||
if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
||||
information.manifest = fp->reads();
|
||||
} else return false;
|
||||
auto document = BML::unserialize(information.manifest);
|
||||
if(!cartridge.load()) return false;
|
||||
return information.loaded = true;
|
||||
}
|
||||
|
||||
auto System::save() -> void {
|
||||
cartridge.save();
|
||||
}
|
||||
|
||||
auto System::unload() -> void {
|
||||
cartridge.unload();
|
||||
}
|
||||
|
||||
auto System::power() -> void {
|
||||
cartridge.power();
|
||||
reset();
|
||||
}
|
||||
|
||||
auto System::reset() -> void {
|
||||
cartridge.reset();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
struct System {
|
||||
auto loaded() const { return information.manifest; }
|
||||
|
||||
auto run() -> void;
|
||||
|
||||
auto load() -> bool;
|
||||
auto save() -> void;
|
||||
auto unload() -> void;
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
struct Information {
|
||||
bool loaded = false;
|
||||
string manifest;
|
||||
} information;
|
||||
};
|
||||
|
||||
extern System system;
|
|
@ -0,0 +1,7 @@
|
|||
#include <md/md.hpp>
|
||||
|
||||
namespace MegaDrive {
|
||||
|
||||
VDP vdp;
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
struct VDP : Thread {
|
||||
};
|
||||
|
||||
extern VDP vdp;
|
|
@ -0,0 +1,7 @@
|
|||
#include <md/md.hpp>
|
||||
|
||||
namespace MegaDrive {
|
||||
|
||||
YM2612 ym2612;
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
//Yamaha YM2612
|
||||
|
||||
struct YM2612 : Thread {
|
||||
};
|
||||
|
||||
extern YM2612 ym2612;
|
|
@ -4,18 +4,22 @@ objects += $(if $(findstring arm,$(processors)),processor-arm)
|
|||
objects += $(if $(findstring gsu,$(processors)),processor-gsu)
|
||||
objects += $(if $(findstring hg51b,$(processors)),processor-hg51b)
|
||||
objects += $(if $(findstring lr35902,$(processors)),processor-lr35902)
|
||||
objects += $(if $(findstring m68k,$(processors)),processor-m68k)
|
||||
objects += $(if $(findstring r6502,$(processors)),processor-r6502)
|
||||
objects += $(if $(findstring r65816,$(processors)),processor-r65816)
|
||||
objects += $(if $(findstring spc700,$(processors)),processor-spc700)
|
||||
objects += $(if $(findstring upd96050,$(processors)),processor-upd96050)
|
||||
objects += $(if $(findstring v30mz,$(processors)),processor-v30mz)
|
||||
objects += $(if $(findstring z80,$(processors)),processor-z80)
|
||||
|
||||
obj/processor-arm.o: processor/arm/arm.cpp $(call rwildcard,processor/arm)
|
||||
obj/processor-gsu.o: processor/gsu/gsu.cpp $(call rwildcard,processor/gsu)
|
||||
obj/processor-hg51b.o: processor/hg51b/hg51b.cpp $(call rwildcard,processor/hg51b)
|
||||
obj/processor-lr35902.o: processor/lr35902/lr35902.cpp $(call rwildcard,processor/lr35902)
|
||||
obj/processor-m68k.o: processor/m68k/m68k.cpp $(call rwildcard,processor/m68k)
|
||||
obj/processor-r6502.o: processor/r6502/r6502.cpp $(call rwildcard,processor/r6502)
|
||||
obj/processor-r65816.o: processor/r65816/r65816.cpp $(call rwildcard,processor/r65816)
|
||||
obj/processor-spc700.o: processor/spc700/spc700.cpp $(call rwildcard,processor/spc700)
|
||||
obj/processor-upd96050.o: processor/upd96050/upd96050.cpp $(call rwildcard,processor/upd96050)
|
||||
obj/processor-v30mz.o: processor/v30mz/v30mz.cpp $(call rwildcard,processor/v30mz)
|
||||
obj/processor-z80.o: processor/z80/z80.cpp $(call rwildcard,z80)
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#include <processor/processor.hpp>
|
||||
#include "m68k.hpp"
|
||||
|
||||
namespace Processor {
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
//Motorola M68000
|
||||
|
||||
namespace Processor {
|
||||
|
||||
struct M68K {
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
#include <processor/processor.hpp>
|
||||
|
||||
namespace Processor {
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
//Zilog Z80
|
||||
|
||||
namespace Processor {
|
||||
|
||||
struct Z80 {
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
system name:Mega Drive
|
|
@ -3,6 +3,7 @@ flags += -DSFC_SUPERGAMEBOY
|
|||
|
||||
include fc/GNUmakefile
|
||||
include sfc/GNUmakefile
|
||||
include md/GNUmakefile
|
||||
include gb/GNUmakefile
|
||||
include gba/GNUmakefile
|
||||
include ws/GNUmakefile
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "../tomoko.hpp"
|
||||
#include <fc/interface/interface.hpp>
|
||||
#include <sfc/interface/interface.hpp>
|
||||
#include <md/interface/interface.hpp>
|
||||
#include <gb/interface/interface.hpp>
|
||||
#include <gba/interface/interface.hpp>
|
||||
#include <ws/interface/interface.hpp>
|
||||
|
@ -16,6 +17,7 @@ Program::Program(string_vector args) {
|
|||
|
||||
emulators.append(new Famicom::Interface);
|
||||
emulators.append(new SuperFamicom::Interface);
|
||||
emulators.append(new MegaDrive::Interface);
|
||||
emulators.append(new GameBoy::Interface);
|
||||
emulators.append(new GameBoyAdvance::Interface);
|
||||
emulators.append(new WonderSwan::Interface);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
Icarus::Icarus() {
|
||||
database.famicom = BML::unserialize(string::read(locate("Database/Famicom.bml")));
|
||||
database.superFamicom = BML::unserialize(string::read(locate("Database/Super Famicom.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")));
|
||||
|
@ -31,6 +32,7 @@ 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 == ".md") return megaDriveManifest(location);
|
||||
if(type == ".gb") return gameBoyManifest(location);
|
||||
if(type == ".gbc") return gameBoyColorManifest(location);
|
||||
if(type == ".gba") return gameBoyAdvanceManifest(location);
|
||||
|
@ -66,6 +68,7 @@ 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 == ".smd") 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);
|
||||
|
|
|
@ -22,6 +22,11 @@ struct Icarus {
|
|||
auto superFamicomManifestScan(vector<Markup::Node>& roms, Markup::Node node) -> void;
|
||||
auto superFamicomImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//mega-drive.cpp
|
||||
auto megaDriveManifest(string location) -> string;
|
||||
auto megaDriveManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
auto megaDriveImport(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
||||
//game-boy.cpp
|
||||
auto gameBoyManifest(string location) -> string;
|
||||
auto gameBoyManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||
|
@ -63,6 +68,7 @@ private:
|
|||
struct {
|
||||
Markup::Node famicom;
|
||||
Markup::Node superFamicom;
|
||||
Markup::Node megaDrive;
|
||||
Markup::Node gameBoy;
|
||||
Markup::Node gameBoyColor;
|
||||
Markup::Node gameBoyAdvance;
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
auto Icarus::megaDriveManifest(string location) -> string {
|
||||
vector<uint8_t> buffer;
|
||||
concatenate(buffer, {location, "program.rom"});
|
||||
return megaDriveManifest(buffer, location);
|
||||
}
|
||||
|
||||
auto Icarus::megaDriveManifest(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.megaDrive) {
|
||||
if(node["sha256"].text() == digest) {
|
||||
manifest.append(node.text(), "\n sha256: ", digest, "\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(settings["icarus/UseHeuristics"].boolean() && !manifest) {
|
||||
MegaDriveCartridge cartridge{location, buffer.data(), buffer.size()};
|
||||
manifest = cartridge.manifest;
|
||||
}
|
||||
|
||||
return manifest;
|
||||
}
|
||||
|
||||
auto Icarus::megaDriveImport(vector<uint8_t>& buffer, string location) -> string {
|
||||
auto name = Location::prefix(location);
|
||||
auto source = Location::path(location);
|
||||
string target{settings["Library/Location"].text(), "Mega Drive/", name, ".md/"};
|
||||
//if(directory::exists(target)) return failure("game already exists");
|
||||
|
||||
auto manifest = megaDriveManifest(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,19 @@
|
|||
struct MegaDriveCartridge {
|
||||
MegaDriveCartridge(string location, uint8_t* data, uint size);
|
||||
|
||||
string manifest;
|
||||
|
||||
//private:
|
||||
struct Information {
|
||||
} information;
|
||||
};
|
||||
|
||||
MegaDriveCartridge::MegaDriveCartridge(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("\n");
|
||||
manifest.append("note: heuristically generated by icarus\n");
|
||||
}
|
|
@ -20,6 +20,7 @@ Settings settings;
|
|||
|
||||
#include "heuristics/famicom.cpp"
|
||||
#include "heuristics/super-famicom.cpp"
|
||||
#include "heuristics/mega-drive.cpp"
|
||||
#include "heuristics/game-boy.cpp"
|
||||
#include "heuristics/game-boy-advance.cpp"
|
||||
#include "heuristics/wonderswan.cpp"
|
||||
|
@ -30,6 +31,7 @@ Settings settings;
|
|||
#include "core/core.cpp"
|
||||
#include "core/famicom.cpp"
|
||||
#include "core/super-famicom.cpp"
|
||||
#include "core/mega-drive.cpp"
|
||||
#include "core/game-boy.cpp"
|
||||
#include "core/game-boy-color.cpp"
|
||||
#include "core/game-boy-advance.cpp"
|
||||
|
@ -66,7 +68,7 @@ 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:*.gb:*.gbc:*.gba:*.ws:*.wsc:*.bs:*.st:*.zip")
|
||||
.setFilters("ROM Files|*.fc:*.nes:*.sfc:*.smc:*.smd:*.gb:*.gbc:*.gba:*.ws:*.wsc:*.bs:*.st:*.zip")
|
||||
.openFile()) {
|
||||
if(string target = icarus.import(source)) {
|
||||
settings["icarus/Path"].setValue(Location::path(source));
|
||||
|
|
Loading…
Reference in New Issue