From 1929ad47d2030dce1014a350469243d1197fe53e Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sat, 9 Apr 2016 20:21:18 +1000 Subject: [PATCH] Update to v098r03 release. byuu says: It took several hours, but I've rebuilt much of the SNES' bus memory mapping architecture. The new design unifies the cartridge string-based mapping ("00-3f,80-bf:8000-ffff") and internal bus.map calls. The map() function now has an accompanying unmap() function, and instead of a fixed 256 callbacks, it'll scan to find the first available slot. unmap() will free slots up when zero addresses reference a given slot. The controllers and expansion port are now both entirely dynamic. Instead of load/unload/power/reset, they only have the constructor (power/reset/load) and destructor (unload). What this means is you can now dynamically change even expansion port devices after the system is loaded. Note that this is incredibly dangerous and stupid, but ... oh well. The whole point of this was for 21fx. There's no way to change the expansion port device prior to loading a game, but if the 21fx isn't active, then the reset vector hijack won't work. Now you can load a 21fx game, change the expansion port device, and simply reset the system to active the device. The unification of design between controller port devices and expansion port devices is nice, and overall this results in a reduction of code (all of the Mapping stuff in Cartridge is gone, replaced with direct bus mapping.) And there's always the potential to expand this system more in the future now. The big missing feature right now is the ability to push/pop mappings. So if you look at how the 21fx does the reset vector, you might vomit a little bit. But ... it works. Also changed exit(0) to _exit(0) in the POSIX version of nall::execute. [The _exit(0) thing is an attempt to make higan not crash when it tries to launch icarus and it's not on $PATH. The theory is that higan forks, then the child tries to exec icarus and fails, so it exits, all the unique_ptrs clean up their resources and tell the X server to free things the parent process is still using. Calling _exit() prevents destructors from running, and seems to prevent the problem. -Ed.] --- higan/emulator/emulator.hpp | 2 +- higan/sfc/GNUmakefile | 3 +- higan/sfc/cartridge/cartridge.hpp | 14 -- higan/sfc/cartridge/markup.cpp | 36 ++---- higan/sfc/controller/controller.cpp | 5 +- higan/sfc/controller/gamepad/gamepad.cpp | 4 +- higan/sfc/controller/justifier/justifier.cpp | 2 +- higan/sfc/controller/mouse/mouse.cpp | 8 +- higan/sfc/controller/multitap/multitap.cpp | 4 +- .../sfc/controller/superscope/superscope.cpp | 12 +- higan/sfc/controller/usart/usart.cpp | 2 +- higan/sfc/coprocessor/sdd1/sdd1.cpp | 8 +- higan/sfc/cpu/cpu.cpp | 52 +++----- higan/sfc/cpu/cpu.hpp | 1 - higan/sfc/cpu/joypad.cpp | 12 +- higan/sfc/cpu/mmio.cpp | 8 +- higan/sfc/expansion/21fx/21fx.cpp | 91 ++++++------- higan/sfc/expansion/21fx/21fx.hpp | 12 +- higan/sfc/expansion/expansion.cpp | 17 +++ higan/sfc/expansion/expansion.hpp | 6 + .../sfc/expansion/satellaview/satellaview.cpp | 31 ++--- .../sfc/expansion/satellaview/satellaview.hpp | 11 +- higan/sfc/expansion/superdisc/superdisc.cpp | 46 +++---- higan/sfc/expansion/superdisc/superdisc.hpp | 13 +- higan/sfc/interface/interface.cpp | 2 +- higan/sfc/memory/memory.cpp | 121 +++++++++++------- higan/sfc/memory/memory.hpp | 13 +- higan/sfc/ppu/ppu.cpp | 12 +- higan/sfc/ppu/ppu.hpp | 1 - higan/sfc/ppu/video.cpp | 16 +-- higan/sfc/sfc.hpp | 4 +- higan/sfc/system/device.cpp | 47 ------- higan/sfc/system/device.hpp | 35 ----- higan/sfc/system/peripherals.cpp | 66 ++++++++++ higan/sfc/system/peripherals.hpp | 35 +++++ higan/sfc/system/serialization.cpp | 1 - higan/sfc/system/system.cpp | 42 +----- higan/sfc/system/system.hpp | 4 +- higan/target-tomoko/program/media.cpp | 5 +- nall/run.hpp | 4 +- 40 files changed, 389 insertions(+), 419 deletions(-) create mode 100644 higan/sfc/expansion/expansion.cpp delete mode 100644 higan/sfc/system/device.cpp delete mode 100644 higan/sfc/system/device.hpp create mode 100644 higan/sfc/system/peripherals.cpp create mode 100644 higan/sfc/system/peripherals.hpp diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 2c3006f2..901aee50 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -7,7 +7,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "098.02"; + static const string Version = "098.03"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/sfc/GNUmakefile b/higan/sfc/GNUmakefile index 288e2e7b..92b02600 100644 --- a/higan/sfc/GNUmakefile +++ b/higan/sfc/GNUmakefile @@ -3,7 +3,7 @@ processors += r65816 spc700 arm gsu hg51b upd96050 objects += sfc-interface sfc-system sfc-scheduler sfc-controller objects += sfc-cartridge sfc-cheat objects += sfc-memory sfc-cpu sfc-smp sfc-dsp sfc-ppu -objects += sfc-satellaview sfc-superdisc +objects += sfc-expansion sfc-satellaview sfc-superdisc objects += sfc-21fx objects += sfc-icd2 sfc-mcc sfc-nss sfc-event objects += sfc-sa1 sfc-superfx @@ -26,6 +26,7 @@ obj/sfc-smp.o: sfc/smp/smp.cpp $(call rwildcard,sfc/smp/) obj/sfc-dsp.o: sfc/dsp/dsp.cpp $(call rwildcard,sfc/dsp/) obj/sfc-ppu.o: sfc/ppu/ppu.cpp $(call rwildcard,sfc/ppu/) +obj/sfc-expansion.o: sfc/expansion/expansion.cpp $(call rwildcard,sfc/expansion/) obj/sfc-satellaview.o: sfc/expansion/satellaview/satellaview.cpp $(call rwildcard,sfc/expansion/satellaview/) obj/sfc-superdisc.o: sfc/expansion/superdisc/superdisc.cpp $(call rwildcard,sfc/expansion/superdisc/) obj/sfc-21fx.o: sfc/expansion/21fx/21fx.cpp $(call rwildcard,sfc/expansion/21fx/) diff --git a/higan/sfc/cartridge/cartridge.hpp b/higan/sfc/cartridge/cartridge.hpp index 5813269a..e465e708 100644 --- a/higan/sfc/cartridge/cartridge.hpp +++ b/higan/sfc/cartridge/cartridge.hpp @@ -35,20 +35,6 @@ struct Cartridge : property { MappedRAM rom; MappedRAM ram; - struct Mapping { - function uint8> reader; - function void> writer; - string addr; - uint size = 0; - uint base = 0; - uint mask = 0; - - Mapping() = default; - Mapping(const function&, const function&); - Mapping(SuperFamicom::Memory&); - }; - vector mapping; - struct Memory { unsigned id; string name; diff --git a/higan/sfc/cartridge/markup.cpp b/higan/sfc/cartridge/markup.cpp index 7cc43faf..7e28690b 100644 --- a/higan/sfc/cartridge/markup.cpp +++ b/higan/sfc/cartridge/markup.cpp @@ -1,13 +1,3 @@ -Cartridge::Mapping::Mapping(SuperFamicom::Memory& memory) { - this->reader = {&SuperFamicom::Memory::read, &memory}; - this->writer = {&SuperFamicom::Memory::write, &memory}; -} - -Cartridge::Mapping::Mapping(const function& reader, const function& writer) { - this->reader = reader; - this->writer = writer; -} - auto Cartridge::parseMarkup(const string& markup) -> void { auto document = BML::unserialize(markup); auto information = document["information"]; @@ -16,7 +6,6 @@ auto Cartridge::parseMarkup(const string& markup) -> void { this->information.title.cartridge = information["title"].text(); _region = board["region"].text() == "pal" ? Region::PAL : Region::NTSC; - mapping.reset(); if(auto node = board["rom"]) parseMarkupROM(node); if(auto node = board["ram"]) parseMarkupRAM(node); if(auto node = board["icd2"]) parseMarkupICD2(node); @@ -40,13 +29,13 @@ auto Cartridge::parseMarkup(const string& markup) -> void { } auto Cartridge::parseMarkupMap(Markup::Node map, SuperFamicom::Memory& memory) -> void { - Mapping m{memory}; - m.addr = map["address"].text(); - m.size = map["size"].natural(); - m.base = map["base"].natural(); - m.mask = map["mask"].natural(); - if(m.size == 0) m.size = memory.size(); - if(m.size != 0) mapping.append(m); + auto addr = map["address"].text(); + auto size = map["size"].natural(); + auto base = map["base"].natural(); + auto mask = map["mask"].natural(); + if(size == 0) size = memory.size(); + if(size == 0) return; + bus.map({&SuperFamicom::Memory::read, &memory}, {&SuperFamicom::Memory::write, &memory}, addr, size, base, mask); } auto Cartridge::parseMarkupMap( @@ -54,12 +43,11 @@ auto Cartridge::parseMarkupMap( const function& reader, const function& writer ) -> void { - Mapping m{reader, writer}; - m.addr = map["address"].text(); - m.size = map["size"].natural(); - m.base = map["base"].natural(); - m.mask = map["mask"].natural(); - mapping.append(m); + auto addr = map["address"].text(); + auto size = map["size"].natural(); + auto base = map["base"].natural(); + auto mask = map["mask"].natural(); + bus.map(reader, writer, addr, size, base, mask); } auto Cartridge::parseMarkupMemory(MappedRAM& ram, Markup::Node node, uint id, bool writable) -> void { diff --git a/higan/sfc/controller/controller.cpp b/higan/sfc/controller/controller.cpp index 153238f9..4a88e14a 100644 --- a/higan/sfc/controller/controller.cpp +++ b/higan/sfc/controller/controller.cpp @@ -15,8 +15,9 @@ Controller::Controller(bool port) : port(port) { auto Controller::Enter() -> void { while(true) { - if(co_active() == device.controllerPort1->thread) device.controllerPort1->main(); - if(co_active() == device.controllerPort2->thread) device.controllerPort2->main(); + scheduler.synchronize(); + if(co_active() == peripherals.controllerPort1->thread) peripherals.controllerPort1->main(); + if(co_active() == peripherals.controllerPort2->thread) peripherals.controllerPort2->main(); } } diff --git a/higan/sfc/controller/gamepad/gamepad.cpp b/higan/sfc/controller/gamepad/gamepad.cpp index e2c38f6e..7d34331d 100644 --- a/higan/sfc/controller/gamepad/gamepad.cpp +++ b/higan/sfc/controller/gamepad/gamepad.cpp @@ -9,7 +9,7 @@ Gamepad::Gamepad(bool port) : Controller(port) { auto Gamepad::data() -> uint2 { if(counter >= 16) return 1; - if(latched == 1) return interface->inputPoll(port, (uint)Device::ID::Gamepad, B); + if(latched == 1) return interface->inputPoll(port, Device::Gamepad, B); //note: D-pad physically prevents up+down and left+right from being pressed at the same time switch(counter++) { @@ -36,7 +36,7 @@ auto Gamepad::latch(bool data) -> void { counter = 0; if(latched == 0) { - auto id = (uint)Device::ID::Gamepad; + auto id = Device::Gamepad; b = interface->inputPoll(port, id, B); y = interface->inputPoll(port, id, Y); select = interface->inputPoll(port, id, Select); diff --git a/higan/sfc/controller/justifier/justifier.cpp b/higan/sfc/controller/justifier/justifier.cpp index df499da7..973925c5 100644 --- a/higan/sfc/controller/justifier/justifier.cpp +++ b/higan/sfc/controller/justifier/justifier.cpp @@ -1,7 +1,7 @@ Justifier::Justifier(bool port, bool chained): Controller(port), chained(chained), -device(chained == false ? (unsigned)Device::ID::Justifier : (unsigned)Device::ID::Justifiers) +device(chained == false ? Device::Justifier : Device::Justifiers) { create(Controller::Enter, 21477272); latched = 0; diff --git a/higan/sfc/controller/mouse/mouse.cpp b/higan/sfc/controller/mouse/mouse.cpp index ddf977f5..30660068 100644 --- a/higan/sfc/controller/mouse/mouse.cpp +++ b/higan/sfc/controller/mouse/mouse.cpp @@ -64,10 +64,10 @@ auto Mouse::latch(bool data) -> void { latched = data; counter = 0; - x = interface->inputPoll(port, (unsigned)Device::ID::Mouse, X); //-n = left, 0 = center, +n = right - y = interface->inputPoll(port, (unsigned)Device::ID::Mouse, Y); //-n = up, 0 = center, +n = down - l = interface->inputPoll(port, (unsigned)Device::ID::Mouse, Left); - r = interface->inputPoll(port, (unsigned)Device::ID::Mouse, Right); + x = interface->inputPoll(port, Device::Mouse, X); //-n = left, 0 = center, +n = right + y = interface->inputPoll(port, Device::Mouse, Y); //-n = up, 0 = center, +n = down + l = interface->inputPoll(port, Device::Mouse, Left); + r = interface->inputPoll(port, Device::Mouse, Right); dx = x < 0; //0 = right, 1 = left dy = y < 0; //0 = down, 1 = up diff --git a/higan/sfc/controller/multitap/multitap.cpp b/higan/sfc/controller/multitap/multitap.cpp index b17ae23b..7d21bc53 100644 --- a/higan/sfc/controller/multitap/multitap.cpp +++ b/higan/sfc/controller/multitap/multitap.cpp @@ -24,8 +24,8 @@ auto Multitap::data() -> uint2 { port2 = 3; //controller 4 } - bool data1 = interface->inputPoll(port, (unsigned)Device::ID::Multitap, port1 * 12 + index); - bool data2 = interface->inputPoll(port, (unsigned)Device::ID::Multitap, port2 * 12 + index); + bool data1 = interface->inputPoll(port, Device::Multitap, port1 * 12 + index); + bool data2 = interface->inputPoll(port, Device::Multitap, port2 * 12 + index); return (data2 << 1) | (data1 << 0); } diff --git a/higan/sfc/controller/superscope/superscope.cpp b/higan/sfc/controller/superscope/superscope.cpp index 575c3884..d67839c2 100644 --- a/higan/sfc/controller/superscope/superscope.cpp +++ b/higan/sfc/controller/superscope/superscope.cpp @@ -46,8 +46,8 @@ auto SuperScope::main() -> void { if(next < prev) { //Vcounter wrapped back to zero; update cursor coordinates for start of new frame - int nx = interface->inputPoll(port, (unsigned)Device::ID::SuperScope, X); - int ny = interface->inputPoll(port, (unsigned)Device::ID::SuperScope, Y); + int nx = interface->inputPoll(port, Device::SuperScope, X); + int ny = interface->inputPoll(port, Device::SuperScope, Y); nx += x; ny += y; x = max(-16, min(256 + 16, nx)); @@ -64,7 +64,7 @@ auto SuperScope::data() -> uint2 { if(counter == 0) { //turbo is a switch; toggle is edge sensitive - bool newturbo = interface->inputPoll(port, (unsigned)Device::ID::SuperScope, Turbo); + bool newturbo = interface->inputPoll(port, Device::SuperScope, Turbo); if(newturbo && !turbo) { turbo = !turbo; //toggle state turbolock = true; @@ -75,7 +75,7 @@ auto SuperScope::data() -> uint2 { //trigger is a button //if turbo is active, trigger is level sensitive; otherwise, it is edge sensitive trigger = false; - bool newtrigger = interface->inputPoll(port, (unsigned)Device::ID::SuperScope, Trigger); + bool newtrigger = interface->inputPoll(port, Device::SuperScope, Trigger); if(newtrigger && (turbo || !triggerlock)) { trigger = true; triggerlock = true; @@ -84,11 +84,11 @@ auto SuperScope::data() -> uint2 { } //cursor is a button; it is always level sensitive - cursor = interface->inputPoll(port, (unsigned)Device::ID::SuperScope, Cursor); + cursor = interface->inputPoll(port, Device::SuperScope, Cursor); //pause is a button; it is always edge sensitive pause = false; - bool newpause = interface->inputPoll(port, (unsigned)Device::ID::SuperScope, Pause); + bool newpause = interface->inputPoll(port, Device::SuperScope, Pause); if(newpause && !pauselock) { pause = true; pauselock = true; diff --git a/higan/sfc/controller/usart/usart.cpp b/higan/sfc/controller/usart/usart.cpp index 450ac195..ca9751a9 100644 --- a/higan/sfc/controller/usart/usart.cpp +++ b/higan/sfc/controller/usart/usart.cpp @@ -80,7 +80,7 @@ auto USART::data() -> uint2 { if(iobit()) { if(counter >= 16) return 1; uint2 result = 0; - if(counter < 12) result = interface->inputPoll(port, (uint)Device::ID::Gamepad, counter); + if(counter < 12) result = interface->inputPoll(port, Device::Gamepad, counter); if(latched == 0) counter++; return result; } diff --git a/higan/sfc/coprocessor/sdd1/sdd1.cpp b/higan/sfc/coprocessor/sdd1/sdd1.cpp index 1bfbbfe1..de01bd4f 100644 --- a/higan/sfc/coprocessor/sdd1/sdd1.cpp +++ b/higan/sfc/coprocessor/sdd1/sdd1.cpp @@ -11,10 +11,6 @@ auto SDD1::init() -> void { } 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({&SDD1::dma_read, &sdd1}, {&SDD1::dma_write, &sdd1}, 0x00, 0x3f, 0x4300, 0x437f); - bus.map({&SDD1::dma_read, &sdd1}, {&SDD1::dma_write, &sdd1}, 0x80, 0xbf, 0x4300, 0x437f); } auto SDD1::unload() -> void { @@ -26,6 +22,10 @@ auto SDD1::power() -> void { } auto SDD1::reset() -> void { + //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({&SDD1::dma_read, &sdd1}, {&SDD1::dma_write, &sdd1}, "00-3f,80-bf:4300-437f"); + sdd1_enable = 0x00; xfer_enable = 0x00; dma_ready = false; diff --git a/higan/sfc/cpu/cpu.cpp b/higan/sfc/cpu/cpu.cpp index c751e245..9094fdd3 100644 --- a/higan/sfc/cpu/cpu.cpp +++ b/higan/sfc/cpu/cpu.cpp @@ -85,38 +85,6 @@ auto CPU::main() -> void { instruction(); } -auto CPU::enable() -> void { - function uint8> reader; - function void> writer; - - reader = {&CPU::apuPortRead, this}; - writer = {&CPU::apuPortWrite, this}; - bus.map(reader, writer, 0x00, 0x3f, 0x2140, 0x217f); - bus.map(reader, writer, 0x80, 0xbf, 0x2140, 0x217f); - - reader = {&CPU::cpuPortRead, this}; - writer = {&CPU::cpuPortWrite, this}; - bus.map(reader, writer, 0x00, 0x3f, 0x2180, 0x2183); - bus.map(reader, writer, 0x80, 0xbf, 0x2180, 0x2183); - - bus.map(reader, writer, 0x00, 0x3f, 0x4016, 0x4017); - bus.map(reader, writer, 0x80, 0xbf, 0x4016, 0x4017); - - bus.map(reader, writer, 0x00, 0x3f, 0x4200, 0x421f); - bus.map(reader, writer, 0x80, 0xbf, 0x4200, 0x421f); - - reader = {&CPU::dmaPortRead, this}; - writer = {&CPU::dmaPortWrite, this}; - bus.map(reader, writer, 0x00, 0x3f, 0x4300, 0x437f); - bus.map(reader, writer, 0x80, 0xbf, 0x4300, 0x437f); - - reader = [](uint24 addr, uint8) -> uint8 { return cpu.wram[addr]; }; - writer = [](uint24 addr, uint8 data) -> void { cpu.wram[addr] = data; }; - bus.map(reader, writer, 0x00, 0x3f, 0x0000, 0x1fff, 0x002000); - bus.map(reader, writer, 0x80, 0xbf, 0x0000, 0x1fff, 0x002000); - bus.map(reader, writer, 0x7e, 0x7f, 0x0000, 0xffff, 0x020000); -} - auto CPU::power() -> void { for(auto& byte : wram) byte = random(0x55); @@ -155,6 +123,26 @@ auto CPU::reset() -> void { coprocessors.reset(); PPUcounter::reset(); + function uint8> reader; + function void> writer; + + reader = {&CPU::apuPortRead, this}; + writer = {&CPU::apuPortWrite, this}; + bus.map(reader, writer, "00-3f,80-bf:2140-217f"); + + reader = {&CPU::cpuPortRead, this}; + writer = {&CPU::cpuPortWrite, this}; + bus.map(reader, writer, "00-3f,80-bf:2180-2183,4016-4017,4200-421f"); + + reader = {&CPU::dmaPortRead, this}; + writer = {&CPU::dmaPortWrite, this}; + bus.map(reader, writer, "00-3f,80-bf:4300-437f"); + + reader = [](uint24 addr, uint8) -> uint8 { return cpu.wram[addr]; }; + writer = [](uint24 addr, uint8 data) -> void { cpu.wram[addr] = data; }; + bus.map(reader, writer, "00-3f,80-bf:0000-1fff", 0x2000); + bus.map(reader, writer, "7e-7f:0000-ffff", 0x20000); + //CPU regs.pc = 0x000000; regs.x.h = 0x00; diff --git a/higan/sfc/cpu/cpu.hpp b/higan/sfc/cpu/cpu.hpp index 236750b5..c31e5de0 100644 --- a/higan/sfc/cpu/cpu.hpp +++ b/higan/sfc/cpu/cpu.hpp @@ -16,7 +16,6 @@ struct CPU : Processor::R65816, Thread, PPUcounter { static auto Enter() -> void; auto main() -> void; - auto enable() -> void; auto power() -> void; auto reset() -> void; diff --git a/higan/sfc/cpu/joypad.cpp b/higan/sfc/cpu/joypad.cpp index e60402d3..aaa81406 100644 --- a/higan/sfc/cpu/joypad.cpp +++ b/higan/sfc/cpu/joypad.cpp @@ -7,14 +7,14 @@ auto CPU::stepAutoJoypadPoll() -> void { if(status.auto_joypad_active && status.auto_joypad_latch) { if(status.auto_joypad_counter == 0) { - device.controllerPort1->latch(1); - device.controllerPort2->latch(1); - device.controllerPort1->latch(0); - device.controllerPort2->latch(0); + SuperFamicom::peripherals.controllerPort1->latch(1); + SuperFamicom::peripherals.controllerPort2->latch(1); + SuperFamicom::peripherals.controllerPort1->latch(0); + SuperFamicom::peripherals.controllerPort2->latch(0); } - uint2 port0 = device.controllerPort1->data(); - uint2 port1 = device.controllerPort2->data(); + uint2 port0 = SuperFamicom::peripherals.controllerPort1->data(); + uint2 port1 = SuperFamicom::peripherals.controllerPort2->data(); status.joy1 = status.joy1 << 1 | port0.bit(0); status.joy2 = status.joy2 << 1 | port1.bit(0); diff --git a/higan/sfc/cpu/mmio.cpp b/higan/sfc/cpu/mmio.cpp index 08228b4d..433657e8 100644 --- a/higan/sfc/cpu/mmio.cpp +++ b/higan/sfc/cpu/mmio.cpp @@ -16,7 +16,7 @@ auto CPU::cpuPortRead(uint24 addr, uint8 data) -> uint8 { //1-0 = Joypad serial data if(addr == 0x4016) { uint8 r = regs.mdr & 0xfc; - r |= device.controllerPort1->data(); + r |= SuperFamicom::peripherals.controllerPort1->data(); return r; } @@ -26,7 +26,7 @@ auto CPU::cpuPortRead(uint24 addr, uint8 data) -> uint8 { //4-2 = Always 1 (pins are connected to GND) //1-0 = Joypad serial data uint8 r = (regs.mdr & 0xe0) | 0x1c; - r |= device.controllerPort2->data(); + r |= SuperFamicom::peripherals.controllerPort2->data(); return r; } @@ -183,8 +183,8 @@ auto CPU::cpuPortWrite(uint24 addr, uint8 data) -> void { //bit 0 is shared between JOYSER0 and JOYSER1, therefore //strobing $4016.d0 affects both controller port latches. //$4017 bit 0 writes are ignored. - device.controllerPort1->latch(data.bit(0)); - device.controllerPort2->latch(data.bit(0)); + SuperFamicom::peripherals.controllerPort1->latch(data.bit(0)); + SuperFamicom::peripherals.controllerPort2->latch(data.bit(0)); } //NMITIMEN diff --git a/higan/sfc/expansion/21fx/21fx.cpp b/higan/sfc/expansion/21fx/21fx.cpp index 636990d2..0a213556 100644 --- a/higan/sfc/expansion/21fx/21fx.cpp +++ b/higan/sfc/expansion/21fx/21fx.cpp @@ -2,10 +2,56 @@ namespace SuperFamicom { -S21FX s21fx; +S21FX::S21FX() { + create(S21FX::Enter, 10'000'000); + + resetVector.byte(0) = bus.read(0xfffc, 0x00); + resetVector.byte(1) = bus.read(0xfffd, 0x00); + + bus.map({&S21FX::read, this}, {&S21FX::write, this}, "00-3f,80-bf:2184-21ff"); + bus.map({&S21FX::read, this}, {&S21FX::write, this}, "00:fffc-fffd"); + + booted = false; + + for(auto& byte : ram) byte = 0xdb; //stp + ram[0] = 0x6c; //jmp ($fffc) + ram[1] = 0xfc; + ram[2] = 0xff; + + if(auto buffer = file::read({interface->path(ID::System), "21fx.rom"})) { + memory::copy(ram, sizeof(ram), buffer.data(), buffer.size()); + } + + string filename{interface->path(ID::SuperFamicom), "21fx.so"}; + if(link.openAbsolute(filename)) { + linkInit = link.sym("fx_init"); + linkMain = link.sym("fx_main"); + } +} + +S21FX::~S21FX() { + bus.unmap("00-3f,80-bf:2184-21ff"); + bus.unmap("00:fffc-fffd"); + + //note: this is an awful hack ... + //since the bus maps are lambdas, we can't safely restore the original reset vector handler + //as such, we install a basic read-only lambda that simply returns the known reset vector + //the downside is that if 00:fffc-fffd were anything but ROM; it will now only act as ROM + //given that this is the only device that hooks the reset vector like this, + //it's not worth the added complexity to support some form of reversible bus mapping hooks + uint vector = resetVector; + bus.map([vector](uint24 addr, uint8) -> uint8 { + return vector >> addr * 8; + }, [](uint24, uint8) -> void { + }, "00:fffc-fffd", 2); + + if(link.open()) link.close(); + linkInit.reset(); + linkMain.reset(); +} auto S21FX::Enter() -> void { - while(true) scheduler.synchronize(), s21fx.main(); + while(true) scheduler.synchronize(), peripherals.expansionPort->main(); } auto S21FX::main() -> void { @@ -21,47 +67,6 @@ auto S21FX::main() -> void { while(true) step(10'000'000); } -auto S21FX::init() -> void { -} - -auto S21FX::load() -> void { - resetVector.byte(0) = bus.read(0xfffc, 0x00); - resetVector.byte(1) = bus.read(0xfffd, 0x00); - - for(auto& byte : ram) byte = 0xdb; //stp - ram[0] = 0x6c; //jmp ($fffc) - ram[1] = 0xfc; - ram[2] = 0xff; - - bus.map({&S21FX::read, &s21fx}, {&S21FX::write, &s21fx}, 0x00, 0x00, 0xfffc, 0xfffd); - bus.map({&S21FX::read, &s21fx}, {&S21FX::write, &s21fx}, 0x00, 0x3f, 0x2184, 0x21ff); - bus.map({&S21FX::read, &s21fx}, {&S21FX::write, &s21fx}, 0x80, 0xbf, 0x2184, 0x21ff); - - if(auto buffer = file::read({interface->path(ID::System), "21fx.rom"})) { - memory::copy(ram, sizeof(ram), buffer.data(), buffer.size()); - } - - string filename{interface->path(ID::SuperFamicom), "21fx.so"}; - if(link.openAbsolute(filename)) { - linkInit = link.sym("fx_init"); - linkMain = link.sym("fx_main"); - } -} - -auto S21FX::unload() -> void { - if(link.open()) link.close(); - linkInit.reset(); - linkMain.reset(); -} - -auto S21FX::power() -> void { -} - -auto S21FX::reset() -> void { - create(S21FX::Enter, 10'000'000); - booted = false; -} - auto S21FX::read(uint24 addr, uint8 data) -> uint8 { addr &= 0x40ffff; diff --git a/higan/sfc/expansion/21fx/21fx.hpp b/higan/sfc/expansion/21fx/21fx.hpp index 9ddffd2d..e76d9ecb 100644 --- a/higan/sfc/expansion/21fx/21fx.hpp +++ b/higan/sfc/expansion/21fx/21fx.hpp @@ -1,11 +1,9 @@ -struct S21FX : Cothread, Memory { +struct S21FX : Expansion { + S21FX(); + ~S21FX(); + static auto Enter() -> void; auto main() -> void; - auto init() -> void; - auto load() -> void; - auto unload() -> void; - auto power() -> void; - auto reset() -> void; auto read(uint24 addr, uint8 data) -> uint8; auto write(uint24 addr, uint8 data) -> void; @@ -36,5 +34,3 @@ private: vector snesBuffer; //SNES -> Link vector linkBuffer; //Link -> SNES }; - -extern S21FX s21fx; diff --git a/higan/sfc/expansion/expansion.cpp b/higan/sfc/expansion/expansion.cpp new file mode 100644 index 00000000..235561b3 --- /dev/null +++ b/higan/sfc/expansion/expansion.cpp @@ -0,0 +1,17 @@ +#include + +namespace SuperFamicom { + +Expansion::Expansion() { + if(!thread) create(Expansion::Enter, 1); +} + +auto Expansion::Enter() -> void { + while(true) scheduler.synchronize(), peripherals.expansionPort->main(); +} + +auto Expansion::main() -> void { + step(1); +} + +} diff --git a/higan/sfc/expansion/expansion.hpp b/higan/sfc/expansion/expansion.hpp index 9f42ca4e..c5cd820d 100644 --- a/higan/sfc/expansion/expansion.hpp +++ b/higan/sfc/expansion/expansion.hpp @@ -1,3 +1,9 @@ +struct Expansion : Cothread { + Expansion(); + static auto Enter() -> void; + virtual auto main() -> void; +}; + #include #include #include diff --git a/higan/sfc/expansion/satellaview/satellaview.cpp b/higan/sfc/expansion/satellaview/satellaview.cpp index 90b64c78..77981128 100644 --- a/higan/sfc/expansion/satellaview/satellaview.cpp +++ b/higan/sfc/expansion/satellaview/satellaview.cpp @@ -2,30 +2,17 @@ namespace SuperFamicom { -Satellaview satellaview; - -auto Satellaview::init() -> void { -} - -auto Satellaview::load() -> void { - bus.map({&Satellaview::read, &satellaview}, {&Satellaview::write, &satellaview}, 0x00, 0x3f, 0x2188, 0x219f); - bus.map({&Satellaview::read, &satellaview}, {&Satellaview::write, &satellaview}, 0x80, 0xbf, 0x2188, 0x219f); -} - -auto Satellaview::unload() -> void { -} - -auto Satellaview::power() -> void { -} - -auto Satellaview::reset() -> void { +Satellaview::Satellaview() { + bus.map({&Satellaview::read, this}, {&Satellaview::write, this}, "00-3f,80-bf:2188-219f"); memory::fill(®s, sizeof regs); } -auto Satellaview::read(uint24 addr, uint8 data) -> uint8 { - addr &= 0xffff; +Satellaview::~Satellaview() { + bus.unmap("00-3f,80-bf:2188-219f"); +} - switch(addr) { +auto Satellaview::read(uint24 addr, uint8 data) -> uint8 { + switch(addr &= 0xffff) { case 0x2188: return regs.r2188; case 0x2189: return regs.r2189; case 0x218a: return regs.r218a; @@ -81,9 +68,7 @@ auto Satellaview::read(uint24 addr, uint8 data) -> uint8 { } auto Satellaview::write(uint24 addr, uint8 data) -> void { - addr &= 0xffff; - - switch(addr) { + switch(addr &= 0xffff) { case 0x2188: { regs.r2188 = data; } break; diff --git a/higan/sfc/expansion/satellaview/satellaview.hpp b/higan/sfc/expansion/satellaview/satellaview.hpp index 7d520535..9c64c12d 100644 --- a/higan/sfc/expansion/satellaview/satellaview.hpp +++ b/higan/sfc/expansion/satellaview/satellaview.hpp @@ -1,9 +1,6 @@ -struct Satellaview : Memory { - auto init() -> void; - auto load() -> void; - auto unload() -> void; - auto power() -> void; - auto reset() -> void; +struct Satellaview : Expansion { + Satellaview(); + ~Satellaview(); auto read(uint24 addr, uint8 data) -> uint8; auto write(uint24 addr, uint8 data) -> void; @@ -21,5 +18,3 @@ private: uint8 r2192_hour, r2192_minute, r2192_second; } regs; }; - -extern Satellaview satellaview; diff --git a/higan/sfc/expansion/superdisc/superdisc.cpp b/higan/sfc/expansion/superdisc/superdisc.cpp index 2d8a71f7..367e6775 100644 --- a/higan/sfc/expansion/superdisc/superdisc.cpp +++ b/higan/sfc/expansion/superdisc/superdisc.cpp @@ -2,12 +2,29 @@ namespace SuperFamicom { -SuperDisc superdisc; #include "nec.cpp" #include "sony.cpp" +SuperDisc::SuperDisc() { + create(&SuperDisc::Enter, 75); + + bus.map({&SuperDisc::read, this}, {&SuperDisc::write, this}, "00-3f,80-bf:21e0-21e5"); + + r.irqEnable = 0x00; + + nec.command.reset(); + nec.data = 0x00; + + sony.command = 0x00; + sony.data = 0x00; +} + +SuperDisc::~SuperDisc() { + bus.unmap("00-3f,80-bf:21e0-21e5"); +} + auto SuperDisc::Enter() -> void { - while(true) scheduler.synchronize(), superdisc.main(); + while(true) scheduler.synchronize(), peripherals.expansionPort->main(); } auto SuperDisc::main() -> void { @@ -27,31 +44,6 @@ auto SuperDisc::main() -> void { synchronizeCPU(); } -auto SuperDisc::init() -> void { -} - -auto SuperDisc::load() -> void { - bus.map({&SuperDisc::read, &superdisc}, {&SuperDisc::write, &superdisc}, 0x00, 0x3f, 0x21e0, 0x21e5); - bus.map({&SuperDisc::read, &superdisc}, {&SuperDisc::write, &superdisc}, 0x80, 0xbf, 0x21e0, 0x21e5); -} - -auto SuperDisc::unload() -> void { -} - -auto SuperDisc::power() -> void { - create(&SuperDisc::Enter, 75); -} - -auto SuperDisc::reset() -> void { - r.irqEnable = 0x00; - - nec.command.reset(); - nec.data = 0x00; - - sony.command = 0x00; - sony.data = 0x00; -} - auto SuperDisc::read(uint24 addr, uint8 data) -> uint8 { addr = 0x21e0 | (addr & 7); diff --git a/higan/sfc/expansion/superdisc/superdisc.hpp b/higan/sfc/expansion/superdisc/superdisc.hpp index da305a6a..6dd98042 100644 --- a/higan/sfc/expansion/superdisc/superdisc.hpp +++ b/higan/sfc/expansion/superdisc/superdisc.hpp @@ -1,13 +1,10 @@ -struct SuperDisc : Cothread, Memory { +struct SuperDisc : Expansion { + SuperDisc(); + ~SuperDisc(); + static auto Enter() -> void; auto main() -> void; - auto init() -> void; - auto load() -> void; - auto unload() -> void; - auto power() -> void; - auto reset() -> void; - auto read(uint24 addr, uint8 data) -> uint8; auto write(uint24 addr, uint8 data) -> void; @@ -39,5 +36,3 @@ private: uint8 data; } sony; }; - -extern SuperDisc superdisc; diff --git a/higan/sfc/interface/interface.cpp b/higan/sfc/interface/interface.cpp index 60d6039f..cd6fd848 100644 --- a/higan/sfc/interface/interface.cpp +++ b/higan/sfc/interface/interface.cpp @@ -425,7 +425,7 @@ auto Interface::unload() -> void { } auto Interface::connect(uint port, uint device) -> void { - SuperFamicom::device.connect(port, (SuperFamicom::Device::ID)device); + SuperFamicom::peripherals.connect(port, device); } auto Interface::power() -> void { diff --git a/higan/sfc/memory/memory.cpp b/higan/sfc/memory/memory.cpp index 878693e6..28b7e4e3 100644 --- a/higan/sfc/memory/memory.cpp +++ b/higan/sfc/memory/memory.cpp @@ -4,63 +4,98 @@ namespace SuperFamicom { Bus bus; -Bus::Bus() { - lookup = new uint8 [16 * 1024 * 1024]; - target = new uint32[16 * 1024 * 1024]; -} - Bus::~Bus() { - delete[] lookup; - delete[] target; + if(lookup) delete[] lookup; + if(target) delete[] target; } auto Bus::reset() -> void { - function uint8> reader = [](uint24, uint8 data) { return data; }; - function void> writer = [](uint24, uint8) {}; + for(auto id : range(256)) { + reader[id].reset(); + writer[id].reset(); + counter[id] = 0; + } - idcount = 0; - map(reader, writer, 0x00, 0xff, 0x0000, 0xffff); + if(lookup) delete[] lookup; + if(target) delete[] target; + + lookup = new uint8 [16 * 1024 * 1024](); + target = new uint32[16 * 1024 * 1024](); + + reader[0] = [](uint24, uint8 data) -> uint8 { return data; }; + writer[0] = [](uint24, uint8) -> void {}; } -auto Bus::map() -> void { - for(auto& m : cartridge.mapping) { - lstring part = m.addr.split(":", 1L); - lstring banks = part(0).split(","); - lstring addrs = part(1).split(","); - for(auto& bank : banks) { - for(auto& addr : addrs) { - lstring bankpart = bank.split("-", 1L); - lstring addrpart = addr.split("-", 1L); - uint banklo = hex(bankpart(0)); - uint bankhi = hex(bankpart(1, bankpart(0))); - uint addrlo = hex(addrpart(0)); - uint addrhi = hex(addrpart(1, addrpart(0))); - map(m.reader, m.writer, banklo, bankhi, addrlo, addrhi, m.size, m.base, m.mask); +auto Bus::map( + const function& read, + const function& write, + const string& addr, uint size, uint base, uint mask +) -> void { + uint id = 1; + while(counter[id]) { + if(++id >= 256) return print("SFC error: bus map exhausted\n"); + } +//print("map[", hex(id, 2), "] => ", addr, "\n"); + + reader[id] = read; + writer[id] = write; + + auto p = addr.split(":", 1L); + auto banks = p(0).split(","); + auto addrs = p(1).split(","); + for(auto& bank : banks) { + for(auto& addr : addrs) { + auto bankRange = bank.split("-", 1L); + auto addrRange = addr.split("-", 1L); + uint bankLo = hex(bankRange(0)); + uint bankHi = hex(bankRange(1, bankRange(0))); + uint addrLo = hex(addrRange(0)); + uint addrHi = hex(addrRange(1, addrRange(0))); + + for(uint bank = bankLo; bank <= bankHi; bank++) { + for(uint addr = addrLo; addr <= addrHi; addr++) { + uint pid = lookup[bank << 16 | addr]; + if(pid && --counter[pid] == 0) { + reader[pid].reset(); + writer[pid].reset(); + } + + uint offset = reduce(bank << 16 | addr, mask); + if(size) offset = base + mirror(offset, size - base); + lookup[bank << 16 | addr] = id; + target[bank << 16 | addr] = offset; + counter[id]++; + } } } } } -auto Bus::map( - const function& reader, - const function& writer, - uint8 banklo, uint8 bankhi, uint16 addrlo, uint16 addrhi, - uint size, uint base, uint mask -) -> void { - assert(banklo <= bankhi); - assert(addrlo <= addrhi); - assert(idcount < 255); +auto Bus::unmap(const string& addr) -> void { + auto p = addr.split(":", 1L); + auto banks = p(0).split(","); + auto addrs = p(1).split(","); + for(auto& bank : banks) { + for(auto& addr : addrs) { + auto bankRange = bank.split("-", 1L); + auto addrRange = addr.split("-", 1L); + uint bankLo = hex(bankRange(0)); + uint bankHi = hex(bankRange(1, bankRange(0))); + uint addrLo = hex(addrRange(0)); + uint addrHi = hex(addrRange(1, addrRange(1))); - uint id = idcount++; - this->reader[id] = reader; - this->writer[id] = writer; + for(uint bank = bankLo; bank <= bankHi; bank++) { + for(uint addr = addrLo; addr <= addrHi; addr++) { + uint pid = lookup[bank << 16 | addr]; + if(pid && --counter[pid] == 0) { + reader[pid].reset(); + writer[pid].reset(); + } - for(uint bank = banklo; bank <= bankhi; bank++) { - for(uint addr = addrlo; addr <= addrhi; addr++) { - uint offset = reduce(bank << 16 | addr, mask); - if(size) offset = base + mirror(offset, size - base); - lookup[bank << 16 | addr] = id; - target[bank << 16 | addr] = offset; + lookup[bank << 16 | addr] = 0; + target[bank << 16 | addr] = 0; + } + } } } } diff --git a/higan/sfc/memory/memory.hpp b/higan/sfc/memory/memory.hpp index 31a537a2..5b6f5323 100644 --- a/higan/sfc/memory/memory.hpp +++ b/higan/sfc/memory/memory.hpp @@ -45,27 +45,26 @@ struct Bus { alwaysinline static auto mirror(uint addr, uint size) -> uint; alwaysinline static auto reduce(uint addr, uint mask) -> uint; - Bus(); ~Bus(); alwaysinline auto read(uint24 addr, uint8 data) -> uint8; alwaysinline auto write(uint24 addr, uint8 data) -> void; auto reset() -> void; - auto map() -> void; auto map( - const function& reader, - const function& writer, - uint8 banklo, uint8 bankhi, uint16 addrlo, uint16 addrhi, - uint size = 0, uint base = 0, uint mask = 0 + const function& read, + const function& write, + const string& addr, uint size = 0, uint base = 0, uint mask = 0 ) -> void; + auto unmap(const string& addr) -> void; +private: uint8* lookup = nullptr; uint32* target = nullptr; - uint idcount = 0; function uint8> reader[256]; function void> writer[256]; + uint24 counter[256]; }; extern Bus bus; diff --git a/higan/sfc/ppu/ppu.cpp b/higan/sfc/ppu/ppu.cpp index 2ad1cd5f..bdf11374 100644 --- a/higan/sfc/ppu/ppu.cpp +++ b/higan/sfc/ppu/ppu.cpp @@ -86,14 +86,6 @@ auto PPU::addClocks(uint clocks) -> void { } } -auto PPU::enable() -> void { - function uint8> reader{&PPU::read, this}; - function void> writer{&PPU::write, this}; - - bus.map(reader, writer, 0x00, 0x3f, 0x2100, 0x213f); - bus.map(reader, writer, 0x80, 0xbf, 0x2100, 0x213f); -} - auto PPU::power() -> void { for(auto& n : vram) n = random(0x00); for(auto& n : oam) n = random(0x00); @@ -105,6 +97,10 @@ auto PPU::reset() -> void { PPUcounter::reset(); memory::fill(output, 512 * 480 * sizeof(uint32)); + function uint8> reader{&PPU::read, this}; + function void> writer{&PPU::write, this}; + bus.map(reader, writer, "00-3f,80-bf:2100-213f"); + regs.ppu1_mdr = random(0xff); regs.ppu2_mdr = random(0xff); diff --git a/higan/sfc/ppu/ppu.hpp b/higan/sfc/ppu/ppu.hpp index 7d9ae9d2..c10f5c4a 100644 --- a/higan/sfc/ppu/ppu.hpp +++ b/higan/sfc/ppu/ppu.hpp @@ -13,7 +13,6 @@ struct PPU : Thread, PPUcounter { static auto Enter() -> void; auto main() -> void; - auto enable() -> void; auto power() -> void; auto reset() -> void; diff --git a/higan/sfc/ppu/video.cpp b/higan/sfc/ppu/video.cpp index 01f080e1..ae43e6b9 100644 --- a/higan/sfc/ppu/video.cpp +++ b/higan/sfc/ppu/video.cpp @@ -144,17 +144,17 @@ auto Video::drawCursor(uint32 color, int x, int y) -> void { } auto Video::drawCursors() -> void { - switch((Device::ID)settings.controllerPort2) { - case Device::ID::SuperScope: - if(dynamic_cast(device.controllerPort2)) { - auto& controller = (SuperScope&)*device.controllerPort2; + switch(settings.controllerPort2) { + case Device::SuperScope: + if(dynamic_cast(peripherals.controllerPort2)) { + auto& controller = (SuperScope&)*peripherals.controllerPort2; drawCursor(0xff0000ff, controller.x, controller.y); } break; - case Device::ID::Justifier: - case Device::ID::Justifiers: - if(dynamic_cast(device.controllerPort2)) { - auto& controller = (Justifier&)*device.controllerPort2; + case Device::Justifier: + case Device::Justifiers: + if(dynamic_cast(peripherals.controllerPort2)) { + auto& controller = (Justifier&)*peripherals.controllerPort2; drawCursor(0xffff0000, controller.player1.x, controller.player1.y); if(!controller.chained) break; drawCursor(0xff00bf00, controller.player2.x, controller.player2.y); diff --git a/higan/sfc/sfc.hpp b/higan/sfc/sfc.hpp index de0ea562..05fc0ceb 100644 --- a/higan/sfc/sfc.hpp +++ b/higan/sfc/sfc.hpp @@ -25,7 +25,7 @@ namespace SuperFamicom { namespace SuperFamicom { struct Thread { - ~Thread() { + virtual ~Thread() { if(thread) co_delete(thread); } @@ -61,10 +61,10 @@ namespace SuperFamicom { #include #include + #include #include #include #include - #include #include #include #include diff --git a/higan/sfc/system/device.cpp b/higan/sfc/system/device.cpp deleted file mode 100644 index d448d54e..00000000 --- a/higan/sfc/system/device.cpp +++ /dev/null @@ -1,47 +0,0 @@ -Device device; - -Device::Device() { - connect(0, ID::None); - connect(1, ID::None); - connect(2, ID::None); -} - -Device::~Device() { - if(controllerPort1) delete controllerPort1; - if(controllerPort2) delete controllerPort2; -} - -auto Device::connect(uint port, Device::ID id) -> void { - if(port == 0 || port == 1) { - Controller*& controller = (port == 0 ? controllerPort1 : controllerPort2); - - if(controller) { - delete controller; - controller = nullptr; - } - - switch(id) { default: - case ID::None: controller = new Controller(port); break; - case ID::Gamepad: controller = new Gamepad(port); break; - case ID::Multitap: controller = new Multitap(port); break; - case ID::Mouse: controller = new Mouse(port); break; - case ID::SuperScope: controller = new SuperScope(port); break; - case ID::Justifier: controller = new Justifier(port, false); break; - case ID::Justifiers: controller = new Justifier(port, true); break; - case ID::USART: controller = new USART(port); break; - } - - switch(port) { - case 0: settings.controllerPort1 = (uint)id; break; - case 1: settings.controllerPort2 = (uint)id; break; - } - } - - if(port == 2) { - settings.expansionPort = (uint)id; - } - - cpu.peripherals.reset(); - cpu.peripherals.append(controllerPort1); - cpu.peripherals.append(controllerPort2); -} diff --git a/higan/sfc/system/device.hpp b/higan/sfc/system/device.hpp deleted file mode 100644 index b8289e3d..00000000 --- a/higan/sfc/system/device.hpp +++ /dev/null @@ -1,35 +0,0 @@ -struct Device { - enum class Port : uint { - Controller1, - Controller2, - Expansion, - }; - - enum class ID : uint { - None, - - //controller port devices - Gamepad, - Multitap, - Mouse, - SuperScope, - Justifier, - Justifiers, - USART, - - //expansion port devices - Satellaview, - SuperDisc, - S21FX, - }; - - Device(); - ~Device(); - - auto connect(uint port, Device::ID id) -> void; - - Controller* controllerPort1 = nullptr; - Controller* controllerPort2 = nullptr; -}; - -extern Device device; diff --git a/higan/sfc/system/peripherals.cpp b/higan/sfc/system/peripherals.cpp new file mode 100644 index 00000000..9a6a1457 --- /dev/null +++ b/higan/sfc/system/peripherals.cpp @@ -0,0 +1,66 @@ +Peripherals peripherals; + +auto Peripherals::unload() -> void { + delete controllerPort1; + delete controllerPort2; + delete expansionPort; + controllerPort1 = nullptr; + controllerPort2 = nullptr; + expansionPort = nullptr; +} + +auto Peripherals::reset() -> void { + connect(0, settings.controllerPort1); + connect(1, settings.controllerPort2); + connect(2, settings.expansionPort); +} + +auto Peripherals::connect(uint port, uint id) -> void { + if(port == Port::Controller1) { + settings.controllerPort1 = id; + if(!system.loaded()) return; + + delete controllerPort1; + switch(id) { default: + case Device::None: controllerPort1 = new Controller(0); break; + case Device::Gamepad: controllerPort1 = new Gamepad(0); break; + case Device::Multitap: controllerPort1 = new Multitap(0); break; + case Device::Mouse: controllerPort1 = new Mouse(0); break; + case Device::USART: controllerPort1 = new USART(0); break; + } + } + + if(port == Port::Controller2) { + settings.controllerPort2 = id; + if(!system.loaded()) return; + + delete controllerPort2; + switch(id) { default: + case Device::None: controllerPort2 = new Controller(1); break; + case Device::Gamepad: controllerPort2 = new Gamepad(1); break; + case Device::Multitap: controllerPort2 = new Multitap(1); break; + case Device::Mouse: controllerPort2 = new Mouse(1); break; + case Device::SuperScope: controllerPort2 = new SuperScope(1); break; + case Device::Justifier: controllerPort2 = new Justifier(1, false); break; + case Device::Justifiers: controllerPort2 = new Justifier(1, true); break; + } + } + + if(port == Port::Expansion) { + settings.expansionPort = id; + if(!system.loaded()) return; + + delete expansionPort; + switch(id) { default: + case Device::None: expansionPort = new Expansion; break; + case Device::Satellaview: expansionPort = new Satellaview; break; + case Device::SuperDisc: expansionPort = new SuperDisc; break; + case Device::S21FX: expansionPort = new S21FX; break; + } + } + + cpu.peripherals.reset(); + cpu.peripherals.append(controllerPort1); + cpu.peripherals.append(controllerPort2); + cpu.peripherals.append(expansionPort); +} diff --git a/higan/sfc/system/peripherals.hpp b/higan/sfc/system/peripherals.hpp new file mode 100644 index 00000000..e0396955 --- /dev/null +++ b/higan/sfc/system/peripherals.hpp @@ -0,0 +1,35 @@ +struct Port { enum : uint { + Controller1, + Controller2, + Expansion, +};}; + +struct Device { enum : uint { + None, + + //controller port peripherals + Gamepad, + Multitap, + Mouse, + SuperScope, + Justifier, + Justifiers, + USART, + + //expansion port peripherals + Satellaview, + SuperDisc, + S21FX, +};}; + +struct Peripherals { + auto unload() -> void; + auto reset() -> void; + auto connect(uint port, uint id) -> void; + + Controller* controllerPort1 = nullptr; + Controller* controllerPort2 = nullptr; + Expansion* expansionPort = nullptr; +}; + +extern Peripherals peripherals; diff --git a/higan/sfc/system/serialization.cpp b/higan/sfc/system/serialization.cpp index d73b9bda..d0e34a85 100644 --- a/higan/sfc/system/serialization.cpp +++ b/higan/sfc/system/serialization.cpp @@ -39,7 +39,6 @@ auto System::unserialize(serializer& s) -> bool { auto System::serialize(serializer& s) -> void { s.integer((uint&)_region); - s.integer((uint&)_expansionPort); } auto System::serializeAll(serializer& s) -> void { diff --git a/higan/sfc/system/system.cpp b/higan/sfc/system/system.cpp index ebcda475..5c8bdce6 100644 --- a/higan/sfc/system/system.cpp +++ b/higan/sfc/system/system.cpp @@ -4,13 +4,12 @@ namespace SuperFamicom { System system; -#include "device.cpp" +#include "peripherals.cpp" #include "random.cpp" #include "serialization.cpp" auto System::loaded() const -> bool { return _loaded; } auto System::region() const -> Region { return _region; } -auto System::expansionPort() const -> Device::ID { return _expansionPort; } auto System::cpuFrequency() const -> uint { return _cpuFrequency; } auto System::apuFrequency() const -> uint { return _apuFrequency; } @@ -34,10 +33,6 @@ auto System::runToSave() -> void { auto System::init() -> void { assert(interface != nullptr); - satellaview.init(); - superdisc.init(); - s21fx.init(); - icd2.init(); mcc.init(); nss.init(); @@ -55,16 +50,14 @@ auto System::init() -> void { msu1.init(); bsmemory.init(); - - device.connect(0, (Device::ID)settings.controllerPort1); - device.connect(1, (Device::ID)settings.controllerPort2); - device.connect(2, (Device::ID)settings.expansionPort); } auto System::term() -> void { } auto System::load() -> void { + bus.reset(); + interface->loadRequest(ID::SystemManifest, "manifest.bml", true); auto document = BML::unserialize(information.manifest); @@ -74,20 +67,9 @@ auto System::load() -> void { cartridge.load(); _region = cartridge.region() == Cartridge::Region::NTSC ? Region::NTSC : Region::PAL; - _expansionPort = (Device::ID)settings.expansionPort; _cpuFrequency = region() == Region::NTSC ? 21'477'272 : 21'281'370; _apuFrequency = 24'606'720; - bus.reset(); - bus.map(); - - cpu.enable(); - ppu.enable(); - - if(expansionPort() == Device::ID::Satellaview) satellaview.load(); - if(expansionPort() == Device::ID::SuperDisc) superdisc.load(); - if(expansionPort() == Device::ID::S21FX) s21fx.load(); - if(cartridge.hasICD2()) icd2.load(); if(cartridge.hasMCC()) mcc.load(); if(cartridge.hasNSSDIP()) nss.load(); @@ -113,9 +95,7 @@ auto System::load() -> void { auto System::unload() -> void { if(!loaded()) return; - if(expansionPort() == Device::ID::Satellaview) satellaview.unload(); - if(expansionPort() == Device::ID::SuperDisc) superdisc.unload(); - if(expansionPort() == Device::ID::S21FX) s21fx.unload(); + peripherals.unload(); if(cartridge.hasICD2()) icd2.unload(); if(cartridge.hasMCC()) mcc.unload(); @@ -148,10 +128,6 @@ auto System::power() -> void { dsp.power(); ppu.power(); - if(expansionPort() == Device::ID::Satellaview) satellaview.power(); - if(expansionPort() == Device::ID::SuperDisc) superdisc.power(); - if(expansionPort() == Device::ID::S21FX) s21fx.power(); - if(cartridge.hasICD2()) icd2.power(); if(cartridge.hasMCC()) mcc.power(); if(cartridge.hasNSSDIP()) nss.power(); @@ -179,10 +155,6 @@ auto System::reset() -> void { dsp.reset(); ppu.reset(); - if(expansionPort() == Device::ID::Satellaview) satellaview.reset(); - if(expansionPort() == Device::ID::SuperDisc) superdisc.reset(); - if(expansionPort() == Device::ID::S21FX) s21fx.reset(); - if(cartridge.hasICD2()) icd2.reset(); if(cartridge.hasMCC()) mcc.reset(); if(cartridge.hasNSSDIP()) nss.reset(); @@ -212,13 +184,9 @@ auto System::reset() -> void { if(cartridge.hasSharpRTC()) cpu.coprocessors.append(&sharprtc); if(cartridge.hasSPC7110()) cpu.coprocessors.append(&spc7110); if(cartridge.hasMSU1()) cpu.coprocessors.append(&msu1); - if(expansionPort() == Device::ID::SuperDisc) cpu.coprocessors.append(&superdisc); - if(expansionPort() == Device::ID::S21FX) cpu.coprocessors.append(&s21fx); scheduler.reset(); - device.connect(0, (Device::ID)settings.controllerPort1); - device.connect(1, (Device::ID)settings.controllerPort2); - device.connect(2, (Device::ID)settings.expansionPort); + peripherals.reset(); } } diff --git a/higan/sfc/system/system.hpp b/higan/sfc/system/system.hpp index 1d2ce323..2de5837f 100644 --- a/higan/sfc/system/system.hpp +++ b/higan/sfc/system/system.hpp @@ -1,13 +1,12 @@ struct Interface; -#include "device.hpp" +#include "peripherals.hpp" struct System { enum class Region : bool { NTSC = 0, PAL = 1 }; auto loaded() const -> bool; auto region() const -> Region; - auto expansionPort() const -> Device::ID; auto cpuFrequency() const -> uint; auto apuFrequency() const -> uint; @@ -35,7 +34,6 @@ private: bool _loaded = false; Region _region = Region::NTSC; - Device::ID _expansionPort = Device::ID::None; uint _cpuFrequency = 0; uint _apuFrequency = 0; uint _serializeSize = 0; diff --git a/higan/target-tomoko/program/media.cpp b/higan/target-tomoko/program/media.cpp index 578070e3..870ad26c 100644 --- a/higan/target-tomoko/program/media.cpp +++ b/higan/target-tomoko/program/media.cpp @@ -20,10 +20,11 @@ auto Program::loadMedia(Emulator::Interface& interface, Emulator::Interface::Med mediaPaths(media.id) = location; folderPaths.append(location); + //note: the order of operations in this block of code is critical emulator = &interface; - connectDevices(); //(expansion port) devices must be connected prior to load + connectDevices(); emulator->load(media.id); - updateAudio(); //audio must be updated after load (audio frequency varies by region) + updateAudio(); emulator->power(); presentation->resizeViewport(); diff --git a/nall/run.hpp b/nall/run.hpp index eb4955e8..b12fd1fb 100644 --- a/nall/run.hpp +++ b/nall/run.hpp @@ -36,7 +36,9 @@ template inline auto execute(const string& name, P&&... p) -> str close(fd[0]); close(fd[1]); execvp(name, (char* const*)argv); - exit(0); + //this is called only if execvp fails: + //use _exit instead of exit, to avoid destroying key shared file descriptors + _exit(0); } else { close(fd[1]);