Update to v089r16 release.

byuu says:

Changelog:
- eliminated <mmio>, <mcu> tags [they are merged to their parent nodes
  now]
- added <ram name= size=> tag to EpsonRTC, SharpRTC
- added <firmware> tag to DSP-n, ST-01n, ST-018, Cx4
- interface->path(0) now returns the system folder, which can be used
  for storage now
- as a fun proof-of-concept, I've simulated SNES warm power cycles by
  saving and loading work RAM (same effect if you instantly swapped
  carts)
  - long-term, I'm not sure how I want to do this. The power menu option
    makes no sense with warm RAM
  - I like the idea of decaying RAM based on timestamp from last play;
    and power can just force the timestamp to 0 (which will corrupt all
    RAM)
- Interface::firmware is gone. The cores now load firmware inside their
  boot up routines
- you now get a message on the screen if the emulator can't find
  firmware, should help with "I just get a black screen" messages

I'd like to start preparing for a v090 release. I think we're almost
there now. Have to update nall/cartridge and purify to handle XML
changes first.
This commit is contained in:
Tim Allen 2012-07-15 19:47:35 +10:00
parent 791e64951b
commit c1318961d8
37 changed files with 223 additions and 127 deletions

View File

@ -3,7 +3,7 @@
namespace Emulator {
static const char Name[] = "bsnes";
static const char Version[] = "089.15";
static const char Version[] = "089.16";
static const char Author[] = "byuu";
static const char License[] = "GPLv3";
}

View File

@ -21,10 +21,9 @@ struct Interface {
unsigned id;
string name;
string type;
string path;
string load;
};
vector<Media> firmware;
vector<Media> media;
struct Device {
@ -58,6 +57,7 @@ struct Interface {
virtual int16_t inputPoll(unsigned, unsigned, unsigned) { return 0; }
virtual unsigned dipSettings(const XML::Node&) { return 0; }
virtual string path(unsigned) { return ""; }
virtual void notify(const string &text) { print(text, "\n"); }
} *bind;
//callback bindings (provided by user interface)
@ -70,6 +70,7 @@ struct Interface {
int16_t inputPoll(unsigned port, unsigned device, unsigned input) { return bind->inputPoll(port, device, input); }
unsigned dipSettings(const XML::Node &node) { return bind->dipSettings(node); }
string path(unsigned group) { return bind->path(group); }
template<typename... Args> void notify(Args&... args) { return bind->notify({std::forward<Args>(args)...}); }
//information
virtual double videoFrequency() = 0;
@ -78,7 +79,7 @@ struct Interface {
//media interface
virtual bool loaded() { return false; }
virtual string sha256() { return ""; }
virtual unsigned group(unsigned id) { return 0u; }
virtual unsigned group(unsigned id) = 0;
virtual void load(unsigned id, const string &manifest) {}
virtual void save() {}
virtual void load(unsigned id, const stream &memory, const string &markup = "") {}

View File

@ -20,6 +20,18 @@ string Interface::sha256() {
return cartridge.sha256();
}
unsigned Interface::group(unsigned id) {
switch(id) {
case ID::ProgramROM:
case ID::ProgramRAM:
case ID::CharacterROM:
case ID::CharacterRAM:
return 1;
}
throw;
}
void Interface::load(unsigned id, const string &manifest) {
cartridge.load(manifest);
}
@ -112,7 +124,7 @@ Interface::Interface() {
information.capability.states = true;
information.capability.cheats = true;
media.append({ID::Famicom, "Famicom", "sys", "fc"});
media.append({ID::Famicom, "Famicom", "fc"});
{
Device device{0, ID::Port1 | ID::Port2, "Controller"};

View File

@ -4,6 +4,7 @@ namespace Famicom {
struct ID {
enum : unsigned {
System,
Famicom,
};
@ -26,6 +27,7 @@ struct Interface : Emulator::Interface {
bool loaded();
string sha256();
unsigned group(unsigned id);
void load(unsigned id, const string &manifest);
void save();
void load(unsigned id, const stream &stream, const string &manifest = "");

View File

@ -49,6 +49,8 @@ void Cartridge::load(System::Revision revision, const string &manifest) {
ramsize = numeral(ram["size"].data);
ramdata = allocate<uint8>(ramsize, 0xff);
system.load(revision);
//Super Game Boy core loads memory from Super Famicom core
if(revision != System::Revision::SuperGameBoy) {
if(rom["name"].exists()) interface->loadRequest(ID::ROM, rom["name"].data);
@ -71,8 +73,6 @@ void Cartridge::load(System::Revision revision, const string &manifest) {
case Mapper::HuC3: mapper = &huc3; break;
}
system.load(revision);
loaded = true;
sha256 = nall::sha256(romdata, romsize);
}

View File

@ -28,6 +28,23 @@ string Interface::sha256() {
return cartridge.sha256();
}
unsigned Interface::group(unsigned id) {
switch(id) {
case ID::GameBoyBootROM:
case ID::SuperGameBoyBootROM:
case ID::GameBoyColorBootROM:
return 0;
case ID::ROM:
case ID::RAM:
if(system.revision() == System::Revision::GameBoy) return ID::GameBoy;
if(system.revision() == System::Revision::SuperGameBoy) return ID::SuperGameBoy;
if(system.revision() == System::Revision::GameBoyColor) return ID::GameBoyColor;
throw;
}
throw;
}
void Interface::load(unsigned id, const string &manifest) {
if(id == ID::GameBoy) cartridge.load(System::Revision::GameBoy, manifest);
if(id == ID::SuperGameBoy) cartridge.load(System::Revision::SuperGameBoy, manifest);
@ -123,12 +140,8 @@ Interface::Interface() {
information.capability.states = true;
information.capability.cheats = true;
firmware.append({ID::GameBoyBootROM, "Game Boy", "sys", "boot.rom"});
firmware.append({ID::SuperGameBoyBootROM, "Super Game Boy", "sfc", "boot.rom"});
firmware.append({ID::GameBoyColorBootROM, "Game Boy Color", "sys", "boot.rom"});
media.append({ID::GameBoy, "Game Boy", "sys", "gb" });
media.append({ID::GameBoyColor, "Game Boy Color", "sys", "gbc"});
media.append({ID::GameBoy, "Game Boy", "gb" });
media.append({ID::GameBoyColor, "Game Boy Color", "gbc"});
{
Device device{0, ID::Device, "Controller"};

View File

@ -4,6 +4,7 @@ namespace GameBoy {
struct ID {
enum : unsigned {
System,
GameBoy,
SuperGameBoy,
GameBoyColor,
@ -39,6 +40,7 @@ struct Interface : Emulator::Interface {
bool loaded();
string sha256();
unsigned group(unsigned id);
void load(unsigned id, const string &manifest);
void save();
void load(unsigned id, const stream &stream, const string &manifest = "");

View File

@ -41,12 +41,24 @@ void System::runthreadtosave() {
}
void System::init() {
assert(interface != 0);
assert(interface != nullptr);
}
void System::load(Revision revision) {
this->revision = revision;
serialize_init();
if(revision == Revision::SuperGameBoy) return; //Super Famicom core loads boot ROM for SGB
string manifest, firmware;
manifest.readfile({interface->path(ID::System), "manifest.xml"});
XML::Document document(manifest);
interface->loadRequest(
revision == Revision::GameBoy ? ID::GameBoyBootROM : ID::GameBoyColorBootROM,
document["system"]["cpu"]["firmware"]["name"].data
);
if(!file::exists({interface->path(ID::System), document["system"]["cpu"]["firmware"]["name"].data})) {
interface->notify("Error: required firmware ", firmware, " not found.\n");
}
}
void System::power() {

View File

@ -16,6 +16,20 @@ bool Interface::loaded() {
return cartridge.loaded();
}
unsigned Interface::group(unsigned id) {
switch(id) {
case ID::BIOS:
return ID::System;
case ID::ROM:
case ID::RAM:
case ID::EEPROM:
case ID::FlashROM:
return ID::GameBoyAdvance;
}
throw;
}
void Interface::load(unsigned id, const string &manifest) {
cartridge.load(manifest);
}
@ -104,9 +118,7 @@ Interface::Interface() {
information.capability.states = true;
information.capability.cheats = false;
firmware.append({ID::BIOS, "Game Boy Advance", "sys", "bios.rom"});
media.append({ID::GameBoyAdvance, "Game Boy Advance", "sys", "gba"});
media.append({ID::GameBoyAdvance, "Game Boy Advance", "gba"});
{
Device device{0, ID::Device, "Controller"};

View File

@ -4,6 +4,7 @@ namespace GameBoyAdvance {
struct ID {
enum : unsigned {
System,
GameBoyAdvance,
};
@ -25,6 +26,7 @@ struct Interface : Emulator::Interface {
double audioFrequency();
bool loaded();
unsigned group(unsigned id);
void load(unsigned id, const string &manifest);
void save();
void load(unsigned id, const stream &stream, const string &manifest = "");

View File

@ -23,6 +23,15 @@ void System::power() {
}
void System::load() {
string manifest;
manifest.readfile({interface->path(ID::System), "manifest.xml"});
XML::Document document(manifest);
string firmware = document["system"]["cpu"]["firmware"]["name"].data;
interface->loadRequest(ID::BIOS, firmware);
if(!file::exists({interface->path(ID::System), firmware})) {
interface->notify("Error: required firmware ", firmware, " not found.\n");
}
serialize_init();
}

View File

@ -66,6 +66,14 @@ namespace nall {
return memory;
}
static bool read(const string &filename, uint8_t *data, unsigned size) {
file fp;
if(fp.open(filename, mode::read) == false) return false;
fp.read(data, size);
fp.close();
return true;
}
static bool write(const string &filename, const uint8_t *data, unsigned size) {
file fp;
if(fp.open(filename, mode::write) == false) return false;

View File

@ -4,16 +4,12 @@
<rom name="program.rom" size="0x100000"/>
<ram name="save.rwm" size="0x8000"/>
<psram name="flash.rwm" size="0x40000"/>
<mcu>
<map address="00-3f:8000-ffff"/>
<map address="80-bf:8000-ffff"/>
<map address="40-7f:0000-ffff"/>
<map address="c0-ff:0000-ffff"/>
<map address="20-3f:6000-7fff"/>
</mcu>
<mmio>
<map address="00-3f:5000-5fff"/>
<map address="80-bf:5000-5fff"/>
</mmio>
<map address="00-3f:8000-ffff"/>
<map address="80-bf:8000-ffff"/>
<map address="40-7f:0000-ffff"/>
<map address="c0-ff:0000-ffff"/>
<map address="20-3f:6000-7fff"/>
<map address="00-3f:5000-5fff"/>
<map address="80-bf:5000-5fff"/>
</bsx>
</cartridge>

View File

@ -1,4 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?>
<system name="Game Boy Advance">
<bios firmware="bios.rom" sha256="fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570"/>
<cpu>
<firmware name="bios.rom" size="16384" sha256="fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570"/>
</cpu>
</system>

View File

@ -1,4 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?>
<system name="Game Boy Color">
<boot firmware="boot.rom" sha256="4bf5021be357ce523a59ac5f4efff5d6371ae50112a6db0adf4a75916ad760a9"/>
<cpu>
<firmware name="boot.rom" size="2048" sha256="4bf5021be357ce523a59ac5f4efff5d6371ae50112a6db0adf4a75916ad760a9"/>
</cpu>
</system>

View File

@ -1,4 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?>
<system name="Game Boy">
<boot firmware="boot.rom" sha256="cf053eccb4ccafff9e67339d4e78e98dce7d1ed59be819d2a1ba2232c6fce1c7"/>
<cpu>
<firmware name="boot.rom" size="256" sha256="cf053eccb4ccafff9e67339d4e78e98dce7d1ed59be819d2a1ba2232c6fce1c7"/>
</cpu>
</system>

View File

@ -1,4 +1,6 @@
<?xml version='1.0' encoding='UTF-8'?>
<system name="Super Famicom">
<smp firmware="spc700.rom" sha256="c95f88b299030d5afa55b1031e2b5ef2dff650c4b4e6bb6f8b1359436521278f"/>
<smp>
<firmware name="spc700.rom" size="64" sha256="c95f88b299030d5afa55b1031e2b5ef2dff650c4b4e6bb6f8b1359436521278f"/>
</smp>
</system>

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<cartridge region="NTSC">
<boot firmware="boot.rom" sha256="0e4ddff32fc9d1eeaae812a157dd246459b00c9e14f2f61751f661f32361e360"/>
<rom name="program.rom" size="0x80000">
<map mode="linear" address="00-7f:8000-ffff"/>
<map mode="linear" address="80-ff:8000-ffff"/>
</rom>
<icd2 revision="1">
<firmware name="boot.rom" size="256" sha256="0e4ddff32fc9d1eeaae812a157dd246459b00c9e14f2f61751f661f32361e360"/>
<map address="00-3f:6000-7fff"/>
<map address="80-bf:6000-7fff"/>
</icd2>

1
bsnes/save.ram Executable file

File diff suppressed because one or more lines are too long

View File

@ -91,6 +91,8 @@ void Cartridge::load_satellaview(const string &manifest) {
auto &rom = document["cartridge"]["rom"];
if(rom["name"].exists()) {
unsigned size = numeral(rom["size"].data);
bsxflash.memory.map(allocate<uint8>(size, 0xff), size);
interface->loadRequest(ID::BsxFlashROM, rom["name"].data);
}
}
@ -101,6 +103,8 @@ void Cartridge::load_sufami_turbo_a(const string &manifest) {
auto &ram = document["cartridge"]["ram"];
if(rom["name"].exists()) {
unsigned size = numeral(rom["size"].data);
sufamiturbo.slotA.rom.map(allocate<uint8>(size, 0xff), size);
interface->loadRequest(ID::SufamiTurboSlotAROM, rom["name"].data);
}
@ -122,6 +126,8 @@ void Cartridge::load_sufami_turbo_b(const string &manifest) {
auto &ram = document["cartridge"]["ram"];
if(rom["name"].exists()) {
unsigned size = numeral(rom["size"].data);
sufamiturbo.slotB.rom.map(allocate<uint8>(size, 0xff), size);
interface->loadRequest(ID::SufamiTurboSlotBROM, rom["name"].data);
}

View File

@ -110,6 +110,12 @@ void Cartridge::parse_markup_icd2(XML::Node &root) {
interface->loadRequest(ID::SuperGameBoy, "Game Boy", "gb");
string firmware = root["firmware"]["name"].data;
interface->loadRequest(ID::SuperGameBoyBootROM, firmware);
if(!file::exists({interface->path(ID::SuperFamicom), firmware})) {
interface->notify("Error: required firmware ", firmware, " not found.\n");
}
icd2.revision = max(1, numeral(root["revision"].data));
for(auto &node : root) {
@ -122,7 +128,7 @@ void Cartridge::parse_markup_icd2(XML::Node &root) {
void Cartridge::parse_markup_bsx(XML::Node &root) {
if(root.exists() == false) return;
has_bs_cart = root["mmio"].exists();
has_bs_cart = root["map"].exists();
has_bs_slot = true;
interface->loadRequest(ID::Satellaview, "BS-X Satellaview", "bs");
@ -142,14 +148,7 @@ void Cartridge::parse_markup_bsx(XML::Node &root) {
mapping.append(m);
}
for(auto &node : root["mmio"]) {
if(node.name != "map") continue;
Mapping m({&BSXCartridge::mmio_read, &bsxcartridge}, {&BSXCartridge::mmio_write, &bsxcartridge});
parse_markup_map(m, node);
mapping.append(m);
}
for(auto &node : root["mcu"]) {
for(auto &node : root) {
if(node.name != "map") continue;
Mapping m({&BSXCartridge::mcu_read, &bsxcartridge}, {&BSXCartridge::mcu_write, &bsxcartridge});
parse_markup_map(m, node);
@ -238,7 +237,7 @@ void Cartridge::parse_markup_sa1(XML::Node &root) {
mapping.append(m);
}
for(auto &node : root["mmio"]) {
for(auto &node : root) {
if(node.name != "map") continue;
Mapping m({&SA1::mmio_read, &sa1}, {&SA1::mmio_write, &sa1});
parse_markup_map(m, node);
@ -267,7 +266,7 @@ void Cartridge::parse_markup_superfx(XML::Node &root) {
mapping.append(m);
}
for(auto &node : root["mmio"]) {
for(auto &node : root) {
if(node.name != "map") continue;
Mapping m({&SuperFX::mmio_read, &superfx}, {&SuperFX::mmio_write, &superfx});
parse_markup_map(m, node);
@ -279,8 +278,8 @@ void Cartridge::parse_markup_armdsp(XML::Node &root) {
if(root.exists() == false) return;
has_armdsp = true;
string firmware = root["firmware"].data;
string sha256 = root["sha256"].data;
string firmware = root["firmware"]["name"].data;
string sha256 = root["firmware"]["sha256"].data;
interface->loadRequest(ID::ArmDSP, firmware);
@ -300,8 +299,8 @@ void Cartridge::parse_markup_hitachidsp(XML::Node &root) {
hitachidsp.frequency = numeral(root["frequency"].data);
if(hitachidsp.frequency == 0) hitachidsp.frequency = 20000000;
string firmware = root["firmware"].data;
string sha256 = root["sha256"].data;
string firmware = root["firmware"]["name"].data;
string sha256 = root["firmware"]["sha256"].data;
interface->loadRequest(ID::HitachiDSP, firmware);
@ -313,7 +312,8 @@ void Cartridge::parse_markup_hitachidsp(XML::Node &root) {
mapping.append(m);
}
for(auto &node : root["mmio"]) {
for(auto &node : root) {
if(node.name != "map") continue;
Mapping m({&HitachiDSP::dsp_read, &hitachidsp}, {&HitachiDSP::dsp_write, &hitachidsp});
parse_markup_map(m, node);
mapping.append(m);
@ -333,8 +333,8 @@ void Cartridge::parse_markup_necdsp(XML::Node &root) {
= root["model"].data == "uPD7725" ? NECDSP::Revision::uPD7725
: root["model"].data == "uPD96050" ? NECDSP::Revision::uPD96050
: NECDSP::Revision::uPD7725;
string firmware = root["firmware"].data;
string sha256 = root["sha256"].data;
string firmware = root["firmware"]["name"].data;
string sha256 = root["firmware"]["sha256"].data;
if(necdsp.revision == NECDSP::Revision::uPD7725) {
interface->loadRequest(ID::Nec7725DSP, firmware);
@ -373,7 +373,7 @@ void Cartridge::parse_markup_epsonrtc(XML::Node &root) {
if(root.exists() == false) return;
has_epsonrtc = true;
string name = root["name"].data;
string name = root["ram"]["name"].data;
interface->loadRequest(ID::EpsonRTC, name);
memory.append({ID::EpsonRTC, name});
@ -389,7 +389,7 @@ void Cartridge::parse_markup_sharprtc(XML::Node &root) {
if(root.exists() == false) return;
has_sharprtc = true;
string name = root["name"].data;
string name = root["ram"]["name"].data;
interface->loadRequest(ID::SharpRTC, name);
memory.append({ID::SharpRTC, name});
@ -422,16 +422,9 @@ void Cartridge::parse_markup_spc7110(XML::Node &root) {
mapping.append(m);
}
for(auto &node : root["mmio"]) {
for(auto &node : root) {
if(node.name != "map") continue;
Mapping m({&SPC7110::mmio_read, &spc7110}, {&SPC7110::mmio_write, &spc7110});
parse_markup_map(m, node);
mapping.append(m);
}
for(auto &node : root["dcu"]) {
if(node.name != "map") continue;
Mapping m({&SPC7110::dcu_read, &spc7110}, {&SPC7110::dcu_write, &spc7110});
Mapping m({&SPC7110::read, &spc7110}, {&SPC7110::write, &spc7110});
parse_markup_map(m, node);
mapping.append(m);
}
@ -457,9 +450,9 @@ void Cartridge::parse_markup_sdd1(XML::Node &root) {
mapping.append(m);
}
for(auto &node : root["mmio"]) {
for(auto &node : root) {
if(node.name != "map") continue;
Mapping m({&SDD1::mmio_read, &sdd1}, {&SDD1::mmio_write, &sdd1});
Mapping m({&SDD1::read, &sdd1}, {&SDD1::write, &sdd1});
parse_markup_map(m, node);
mapping.append(m);
}

View File

@ -42,6 +42,11 @@ void BSXCartridge::memory_write(Memory &memory, unsigned addr, uint8 data) {
//mcu_access() allows mcu_read() and mcu_write() to share decoding logic
uint8 BSXCartridge::mcu_access(bool write, unsigned addr, uint8 data) {
if((addr & 0x40f000) == 0x005000) { //$00-3f|80-bf:5000-5fff
if(write == 0) return mmio_read(addr);
if(write == 1) return mmio_write(addr, data), 0;
}
if((addr & 0xe08000) == 0x008000) { //$00-1f:8000-ffff
if(r07 == 1) {
addr = ((addr & 0x1f0000) >> 1) | (addr & 0x7fff);
@ -101,7 +106,7 @@ uint8 BSXCartridge::mmio_read(unsigned addr) {
return r[n];
}
if((addr & 0xf8f000) == 0x105000) { //$10-17:5000-5fff
if((addr & 0xf8f000) == 0x105000) { //$10-17:5000-5fff
return memory_read(ram, ((addr >> 16) & 7) * 0x1000 + (addr & 0xfff));
}

View File

@ -14,8 +14,8 @@ void SDD1::init() {
void SDD1::load() {
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
//buffer address and transfer size information for use in SDD1::mcu_read()
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, {&SDD1::mmio_read, &sdd1}, {&SDD1::mmio_write, &sdd1});
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, {&SDD1::mmio_read, &sdd1}, {&SDD1::mmio_write, &sdd1});
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, {&SDD1::read, &sdd1}, {&SDD1::write, &sdd1});
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, {&SDD1::read, &sdd1}, {&SDD1::write, &sdd1});
}
void SDD1::unload() {
@ -42,7 +42,7 @@ void SDD1::reset() {
}
}
uint8 SDD1::mmio_read(unsigned addr) {
uint8 SDD1::read(unsigned addr) {
addr &= 0xffff;
if((addr & 0x4380) == 0x4300) {
@ -59,7 +59,7 @@ uint8 SDD1::mmio_read(unsigned addr) {
return cpu.regs.mdr;
}
void SDD1::mmio_write(unsigned addr, uint8 data) {
void SDD1::write(unsigned addr, uint8 data) {
addr &= 0xffff;
if((addr & 0x4380) == 0x4300) {

View File

@ -8,8 +8,8 @@ struct SDD1 {
void power();
void reset();
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
uint8 mmc_read(unsigned addr);
uint8 mcu_read(unsigned addr);

View File

@ -110,8 +110,9 @@ void SPC7110::reset() {
r4834 = 0x00;
}
uint8 SPC7110::mmio_read(unsigned addr) {
uint8 SPC7110::read(unsigned addr) {
cpu.synchronize_coprocessors();
if((addr & 0xff0000) == 0x500000) addr = 0x4800;
addr = 0x4800 | (addr & 0x3f);
switch(addr) {
@ -198,7 +199,7 @@ uint8 SPC7110::mmio_read(unsigned addr) {
return cpu.regs.mdr;
}
void SPC7110::mmio_write(unsigned addr, uint8 data) {
void SPC7110::write(unsigned addr, uint8 data) {
cpu.synchronize_coprocessors();
addr = 0x4800 | (addr & 0x3f);
@ -260,17 +261,6 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) {
}
}
//============
//SPC7110::DCU
//============
uint8 SPC7110::dcu_read(unsigned) {
return mmio_read(0x4800);
}
void SPC7110::dcu_write(unsigned, uint8) {
}
//===============
//SPC7110::MCUROM
//===============

View File

@ -15,11 +15,8 @@ struct SPC7110 : Coprocessor {
void add_clocks(unsigned clocks);
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
uint8 dcu_read(unsigned);
void dcu_write(unsigned, uint8);
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
uint8 mcurom_read(unsigned addr);
void mcurom_write(unsigned addr, uint8 data);

View File

@ -96,8 +96,8 @@ void CPU::op_step() {
}
void CPU::enable() {
function<uint8 (unsigned)> read = { &CPU::mmio_read, (CPU*)&cpu };
function<void (unsigned, uint8)> write = { &CPU::mmio_write, (CPU*)&cpu };
function<uint8 (unsigned)> read = {&CPU::mmio_read, (CPU*)&cpu};
function<void (unsigned, uint8)> write = {&CPU::mmio_write, (CPU*)&cpu};
bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, read, write);
bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, read, write);
@ -121,7 +121,6 @@ void CPU::enable() {
void CPU::power() {
cpu_version = config.cpu.version;
for(auto &n : wram) n = random(config.cpu.wram_init_value);
regs.a = regs.x = regs.y = 0x0000;
regs.s = 0x01ff;
@ -156,7 +155,8 @@ void CPU::reset() {
}
CPU::CPU() {
PPUcounter::scanline = { &CPU::scanline, this };
PPUcounter::scanline = {&CPU::scanline, this};
for(auto &n : wram) n = random(config.cpu.wram_init_value);
}
CPU::~CPU() {

View File

@ -25,6 +25,8 @@ string Interface::sha256() {
unsigned Interface::group(unsigned id) {
switch(id) {
case ID::IPLROM:
return 0;
case ID::ROM:
case ID::RAM:
case ID::SA1ROM:
@ -46,27 +48,31 @@ unsigned Interface::group(unsigned id) {
case ID::SDD1ROM:
case ID::SDD1RAM:
case ID::OBC1RAM:
case ID::SuperGameBoyBootROM:
case ID::BsxROM:
case ID::BsxRAM:
case ID::BsxPSRAM:
return 0;
return 1;
case ID::SuperGameBoy:
case ID::SuperGameBoyROM:
case ID::SuperGameBoyRAM:
return 1;
return 2;
case ID::Satellaview:
case ID::BsxFlashROM:
return 2;
return 3;
case ID::SufamiTurboSlotA:
case ID::SufamiTurboSlotAROM:
case ID::SufamiTurboSlotARAM:
return 3;
return 4;
case ID::SufamiTurboSlotB:
case ID::SufamiTurboSlotBROM:
case ID::SufamiTurboSlotBRAM:
return 4;
return 5;
}
return 0;
print(id, "\n");
return 1;
throw;
}
void Interface::load(unsigned id, const string &manifest) {
@ -143,6 +149,10 @@ void Interface::load(unsigned id, const stream &stream, const string &manifest)
if(id == ID::OBC1RAM) obc1.ram.read(stream);
if(id == ID::SuperGameBoyBootROM) {
stream.read(GameBoy::system.bootROM.sgb, min(stream.size(), 256u));
}
if(id == ID::SuperGameBoyROM) {
stream.read(GameBoy::cartridge.romdata, min(GameBoy::cartridge.romsize, stream.size()));
}
@ -306,12 +316,10 @@ Interface::Interface() {
information.capability.states = true;
information.capability.cheats = true;
firmware.append({ID::IPLROM, "Super Famicom", "sys", "spc700.rom"});
media.append({ID::SuperFamicom, "Super Famicom", "sys", "sfc"});
media.append({ID::SuperFamicom, "Super Game Boy", "sfc", "gb" });
media.append({ID::SuperFamicom, "BS-X Satellaview", "sfc", "bs" });
media.append({ID::SuperFamicom, "Sufami Turbo", "sfc", "st" });
media.append({ID::SuperFamicom, "Super Famicom", "sfc"});
media.append({ID::SuperFamicom, "Super Famicom", "gb", "Super Game Boy.sfc"});
media.append({ID::SuperFamicom, "Super Famicom", "bs", "BS-X Satellaview.sfc"});
media.append({ID::SuperFamicom, "Super Famicom", "st", "Sufami Turbo.sfc"});
{
Device device{0, ID::Port1 | ID::Port2, "Controller"};

View File

@ -4,14 +4,15 @@ namespace SuperFamicom {
struct ID {
enum : unsigned {
//cartridges
//cartridges (folders)
System,
SuperFamicom,
SuperGameBoy,
Satellaview,
SufamiTurboSlotA,
SufamiTurboSlotB,
//memory
//memory (files)
IPLROM,
ROM,
@ -43,6 +44,7 @@ struct ID {
OBC1RAM,
SuperGameBoyBootROM,
SuperGameBoyROM,
SuperGameBoyRAM,

View File

@ -92,6 +92,17 @@ void System::term() {
}
void System::load() {
string path = interface->path(ID::System), manifest;
manifest.readfile({path, "manifest.xml"});
XML::Document document(manifest);
string firmware = document["system"]["smp"]["firmware"]["name"].data;
interface->loadRequest(ID::IPLROM, document["system"]["smp"]["firmware"]["name"].data);
if(!file::exists({interface->path(ID::System), firmware})) {
interface->notify("Error: required firmware ", firmware, " not found.\n");
}
file::read({path, "wram.rwm"}, cpu.wram, 128 * 1024);
region = config.region;
expansion = config.expansion_port;
if(region == Region::Autodetect) {
@ -132,6 +143,9 @@ void System::load() {
}
void System::unload() {
string path = interface->path(ID::System);
file::write({path, "wram.rwm"}, cpu.wram, 128 * 1024);
if(expansion() == ExpansionPortDevice::BSX) bsxsatellaview.unload();
if(cartridge.has_gb_slot()) icd2.unload();
if(cartridge.has_bs_cart()) bsxcartridge.unload();

View File

@ -11,12 +11,5 @@ void Application::bootstrap() {
emulator.append(new GameBoy::Interface);
emulator.append(new GameBoyAdvance::Interface);
for(auto &system : emulator) {
system->bind = interface;
for(auto &firmware : system->firmware) {
filestream fs{application->path({firmware.name, ".", firmware.type, "/", firmware.path})};
system->load(firmware.id, fs);
}
}
for(auto &system : emulator) system->bind = interface;
}

View File

@ -31,8 +31,8 @@ void Application::commandLineLoad(string pathname) {
for(auto &emulator : this->emulator) {
for(auto &media : emulator->media) {
if(media.type != "sys") continue;
if(type != media.path) continue;
if(!media.load.empty()) continue;
if(type != media.type) continue;
return utility->loadMedia(emulator, media, pathname);
}
}

View File

@ -67,7 +67,7 @@ void Browser::bootstrap() {
for(auto &media : emulator->media) {
bool found = false;
for(auto &folder : folderList) {
if(folder.extension == media.path) {
if(folder.extension == media.type) {
found = true;
break;
}
@ -75,7 +75,7 @@ void Browser::bootstrap() {
if(found == true) continue;
Folder folder;
folder.extension = media.path;
folder.extension = media.type;
folder.path = application->basepath;
folder.selection = 0;
folderList.append(folder);

View File

@ -144,12 +144,16 @@ void Presentation::bootstrap() {
for(auto &media : emulator->media) {
Item *item = new Item;
item->setText({media.name, " ..."});
item->onActivate = [=, &media] {
utility->loadMedia(iEmulator->interface, media);
};
if(media.type == "sys") loadListSystem.append(item);
if(media.type != "sys") loadListSubsystem.append(item);
if(media.load.empty()) {
item->setText({media.name, " ..."});
loadListSystem.append(item);
} else {
item->setText({nall::basename(media.load), " ..."});
loadListSubsystem.append(item);
}
}
iEmulator->menu.setText(emulator->information.name);

View File

@ -114,3 +114,7 @@ unsigned Interface::dipSettings(const XML::Node &node) {
string Interface::path(unsigned group) {
return utility->path(group);
}
void Interface::notify(const string &text) {
MessageWindow::information(*presentation, text);
}

View File

@ -8,6 +8,7 @@ struct Interface : Emulator::Interface::Bind {
int16_t inputPoll(unsigned port, unsigned device, unsigned input);
unsigned dipSettings(const XML::Node &node);
string path(unsigned group);
void notify(const string &text);
};
extern Interface *interface;

View File

@ -10,8 +10,8 @@ void Utility::setInterface(Emulator::Interface *emulator) {
//load menu option selected
void Utility::loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media) {
string pathname;
if(media.type != "sys") pathname = application->path({media.name, ".", media.type, "/"});
if(!directory::exists(pathname)) pathname = browser->select({"Load ", media.name}, media.path);
if(!media.load.empty()) pathname = application->path({media.load, "/"});
if(!directory::exists(pathname)) pathname = browser->select("Load Media", media.type);
if(!directory::exists(pathname)) return;
if(!file::exists({pathname, "manifest.xml"})) return;
loadMedia(emulator, media, pathname);
@ -21,8 +21,9 @@ void Utility::loadMedia(Emulator::Interface *emulator, Emulator::Interface::Medi
void Utility::loadMedia(Emulator::Interface *emulator, Emulator::Interface::Media &media, const string &pathname) {
unload();
setInterface(emulator);
path(system().group(media.id)) = pathname;
if(media.type == "sys") this->pathname.append(pathname);
path(0) = application->path({media.name, ".sys/"});
path(media.id) = pathname;
if(media.load.empty()) this->pathname.append(pathname);
string manifest;
manifest.readfile({pathname, "manifest.xml"});
@ -38,7 +39,7 @@ void Utility::loadMedia(Emulator::Interface *emulator, Emulator::Interface::Medi
void Utility::loadRequest(unsigned id, const string &name, const string &type) {
string pathname = browser->select({"Load ", name}, type);
if(pathname.empty()) return;
this->path(system().group(id)) = pathname;
path(id) = pathname;
this->pathname.append(pathname);
string manifest;