diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index a5ef90bc..f82705a5 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -12,7 +12,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "103.03"; + static const string Version = "103.04"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/fc/apu/apu.cpp b/higan/fc/apu/apu.cpp index 8a99c3e1..c249ecc0 100644 --- a/higan/fc/apu/apu.cpp +++ b/higan/fc/apu/apu.cpp @@ -153,7 +153,7 @@ auto APU::writeIO(uint16 addr, uint8 data) -> void { pulse[n].period = (pulse[n].period & 0x00ff) | (data << 8); pulse[n].sweep.pulsePeriod = (pulse[n].sweep.pulsePeriod & 0x00ff) | (data << 8); - pulse[n].dutyCounter = 7; + pulse[n].dutyCounter = 0; pulse[n].envelope.reloadDecay = true; if(enabledChannels & (1 << n)) { diff --git a/higan/fc/apu/pulse.cpp b/higan/fc/apu/pulse.cpp index 0be52b68..66b02d48 100644 --- a/higan/fc/apu/pulse.cpp +++ b/higan/fc/apu/pulse.cpp @@ -9,10 +9,10 @@ auto APU::Pulse::clock() -> uint8 { if(lengthCounter == 0) return 0; static const uint dutyTable[4][8] = { - {0, 1, 0, 0, 0, 0, 0, 0}, //12.5% - {0, 1, 1, 0, 0, 0, 0, 0}, //25.0% - {0, 1, 1, 1, 1, 0, 0, 0}, //50.0% - {1, 0, 0, 1, 1, 1, 1, 1}, //25.0% (inverted) + {0, 0, 0, 0, 0, 0, 0, 1}, //12.5% + {0, 0, 0, 0, 0, 0, 1, 1}, //25.0% + {0, 0, 0, 0, 1, 1, 1, 1}, //50.0% + {1, 1, 1, 1, 1, 1, 0, 0}, //25.0% (negated) }; uint8 result = dutyTable[duty][dutyCounter] ? envelope.volume() : 0; if(sweep.pulsePeriod < 0x008) result = 0; diff --git a/higan/md/bus/bus.cpp b/higan/md/bus/bus.cpp index ca78b524..d31bf0d6 100644 --- a/higan/md/bus/bus.cpp +++ b/higan/md/bus/bus.cpp @@ -73,9 +73,9 @@ auto BusCPU::readIO(uint24 addr) -> uint16 { | 0 << 0 //0 = Model 1; 1 = Model 2+ ); - case 0xa10002: return controllerPort1.readData(); - case 0xa10004: return controllerPort2.readData(); - case 0xa10006: return extensionPort.readData(); + case 0xa10002: return controllerPort1.device->readData(); + case 0xa10004: return controllerPort2.device->readData(); + case 0xa10006: return extensionPort.device->readData(); case 0xa10008: return controllerPort1.readControl(); case 0xa1000a: return controllerPort2.readControl(); @@ -89,9 +89,9 @@ auto BusCPU::readIO(uint24 addr) -> uint16 { auto BusCPU::writeIO(uint24 addr, uint16 data) -> void { switch(addr & ~1) { - case 0xa10002: return controllerPort1.writeData(data); - case 0xa10004: return controllerPort2.writeData(data); - case 0xa10006: return extensionPort.writeData(data); + case 0xa10002: return controllerPort1.device->writeData(data); + case 0xa10004: return controllerPort2.device->writeData(data); + case 0xa10006: return extensionPort.device->writeData(data); case 0xa10008: return controllerPort1.writeControl(data); case 0xa1000a: return controllerPort2.writeControl(data); diff --git a/higan/md/controller/controller.cpp b/higan/md/controller/controller.cpp index 9beb61a5..61d440fd 100644 --- a/higan/md/controller/controller.cpp +++ b/higan/md/controller/controller.cpp @@ -8,7 +8,7 @@ ControllerPort extensionPort; #include "gamepad/gamepad.cpp" Controller::Controller(uint port) : port(port) { - if(!handle()) create(Controller::Enter, 100); + if(!handle()) create(Controller::Enter, 1); } Controller::~Controller() { @@ -18,9 +18,9 @@ Controller::~Controller() { auto Controller::Enter() -> void { while(true) { scheduler.synchronize(); - if(controllerPort1.controller->active()) controllerPort1.controller->main(); - if(controllerPort2.controller->active()) controllerPort2.controller->main(); - if(extensionPort.controller->active()) extensionPort.controller->main(); + if(controllerPort1.device->active()) controllerPort1.device->main(); + if(controllerPort2.device->active()) controllerPort2.device->main(); + if(extensionPort.device->active()) extensionPort.device->main(); } } @@ -31,27 +31,19 @@ auto Controller::main() -> void { // -auto ControllerPort::connect(uint device) -> void { +auto ControllerPort::connect(uint deviceID) -> void { if(!system.loaded()) return; - delete controller; + delete device; - switch(device) { default: - case ID::Device::None: controller = new Controller(port); break; - case ID::Device::Gamepad: controller = new Gamepad(port); break; + switch(deviceID) { default: + case ID::Device::None: device = new Controller(port); break; + case ID::Device::Gamepad: device = new Gamepad(port); break; } cpu.peripherals.reset(); - cpu.peripherals.append(controllerPort1.controller); - cpu.peripherals.append(controllerPort2.controller); - cpu.peripherals.append(extensionPort.controller); -} - -auto ControllerPort::readData() -> uint8 { - return controller->readData(); -} - -auto ControllerPort::writeData(uint8 data) -> void { - return controller->writeData(data); + if(auto device = controllerPort1.device) cpu.peripherals.append(device); + if(auto device = controllerPort2.device) cpu.peripherals.append(device); + if(auto device = extensionPort.device) cpu.peripherals.append(device); } auto ControllerPort::readControl() -> uint8 { @@ -68,8 +60,8 @@ auto ControllerPort::power(uint port) -> void { } auto ControllerPort::unload() -> void { - delete controller; - controller = nullptr; + delete device; + device = nullptr; } auto ControllerPort::serialize(serializer& s) -> void { diff --git a/higan/md/controller/controller.hpp b/higan/md/controller/controller.hpp index 8d8a90e9..399a92d3 100644 --- a/higan/md/controller/controller.hpp +++ b/higan/md/controller/controller.hpp @@ -12,10 +12,7 @@ struct Controller : Thread { }; struct ControllerPort { - auto connect(uint device) -> void; - - auto readData() -> uint8; - auto writeData(uint8 data) -> void; + auto connect(uint deviceID) -> void; auto readControl() -> uint8; auto writeControl(uint8 data) -> void; @@ -26,7 +23,7 @@ struct ControllerPort { uint port; uint8 control; - Controller* controller = nullptr; + Controller* device = nullptr; }; extern ControllerPort controllerPort1; diff --git a/higan/md/system/system.cpp b/higan/md/system/system.cpp index 7122136c..8d5e8e5f 100644 --- a/higan/md/system/system.cpp +++ b/higan/md/system/system.cpp @@ -52,6 +52,7 @@ auto System::save() -> void { } auto System::unload() -> void { + cpu.peripherals.reset(); controllerPort1.unload(); controllerPort2.unload(); extensionPort.unload(); diff --git a/higan/processor/spc700/instructions.cpp b/higan/processor/spc700/instructions.cpp index 86a42e6c..6dcf9a28 100644 --- a/higan/processor/spc700/instructions.cpp +++ b/higan/processor/spc700/instructions.cpp @@ -413,15 +413,15 @@ auto SPC700::instructionIndirectXWrite(uint8& data) -> void { auto SPC700::instructionIndirectXIncrementRead(uint8& data) -> void { idle(PC); - data = read(page(X)); //todo: $f0-ff not accessible on this cycle? - idle(page(X++)); + idle(); //quirk: does not read internal SMP registers + data = read(page(X++)); ZF = data == 0; NF = data & 0x80; } auto SPC700::instructionIndirectXIncrementWrite(uint8& data) -> void { idle(PC); - idle(page(X)); //todo: $f0-ff not accessible on this cycle? + idle(); //quirk: does not read internal SMP registers write(page(X++), data); } diff --git a/higan/processor/spc700/spc700.hpp b/higan/processor/spc700/spc700.hpp index b2eb1f14..81493c76 100644 --- a/higan/processor/spc700/spc700.hpp +++ b/higan/processor/spc700/spc700.hpp @@ -3,6 +3,7 @@ namespace Processor { struct SPC700 { + virtual auto idle() -> void = 0; virtual auto read(uint16 address) -> uint8 = 0; virtual auto write(uint16 addessr, uint8 data) -> void = 0; virtual auto synchronizing() const -> bool = 0; diff --git a/higan/sfc/controller/controller.cpp b/higan/sfc/controller/controller.cpp index 2a84a8eb..18ef751f 100644 --- a/higan/sfc/controller/controller.cpp +++ b/higan/sfc/controller/controller.cpp @@ -2,6 +2,8 @@ namespace SuperFamicom { +ControllerPort controllerPort1; +ControllerPort controllerPort2; #include "gamepad/gamepad.cpp" #include "mouse/mouse.cpp" #include "super-multitap/super-multitap.cpp" @@ -19,8 +21,8 @@ Controller::~Controller() { auto Controller::Enter() -> void { while(true) { scheduler.synchronize(); - if(peripherals.controllerPort1->active()) peripherals.controllerPort1->main(); - if(peripherals.controllerPort2->active()) peripherals.controllerPort2->main(); + if(controllerPort1.device->active()) controllerPort1.device->main(); + if(controllerPort2.device->active()) controllerPort2.device->main(); } } @@ -43,4 +45,38 @@ auto Controller::iobit(bool data) -> void { } } +// + +auto ControllerPort::connect(uint deviceID) -> void { + if(!system.loaded()) return; + delete device; + + switch(deviceID) { default: + case ID::Device::None: device = new Controller(port); break; + case ID::Device::Gamepad: device = new Gamepad(port); break; + case ID::Device::Mouse: device = new Mouse(port); break; + case ID::Device::SuperMultitap: device = new SuperMultitap(port); break; + case ID::Device::SuperScope: device = new SuperScope(port); break; + case ID::Device::Justifier: device = new Justifier(port, false); break; + case ID::Device::Justifiers: device = new Justifier(port, true); break; + } + + cpu.peripherals.reset(); + if(auto device = controllerPort1.device) cpu.peripherals.append(device); + if(auto device = controllerPort2.device) cpu.peripherals.append(device); + if(auto device = expansionPort.device) cpu.peripherals.append(device); +} + +auto ControllerPort::power(uint port) -> void { + this->port = port; +} + +auto ControllerPort::unload() -> void { + delete device; + device = nullptr; +} + +auto ControllerPort::serialize(serializer& s) -> void { +} + } diff --git a/higan/sfc/controller/controller.hpp b/higan/sfc/controller/controller.hpp index 6c18e2d1..023aaca1 100644 --- a/higan/sfc/controller/controller.hpp +++ b/higan/sfc/controller/controller.hpp @@ -27,6 +27,20 @@ struct Controller : Thread { const bool port; }; +struct ControllerPort { + auto connect(uint deviceID) -> void; + + auto power(uint port) -> void; + auto unload() -> void; + auto serialize(serializer&) -> void; + + uint port; + Controller* device = nullptr; +}; + +extern ControllerPort controllerPort1; +extern ControllerPort controllerPort2; + #include "gamepad/gamepad.hpp" #include "mouse/mouse.hpp" #include "super-multitap/super-multitap.hpp" diff --git a/higan/sfc/coprocessor/icd2/icd2.cpp b/higan/sfc/coprocessor/icd2/icd2.cpp index ca5bc401..43bd0f47 100644 --- a/higan/sfc/coprocessor/icd2/icd2.cpp +++ b/higan/sfc/coprocessor/icd2/icd2.cpp @@ -46,7 +46,7 @@ auto ICD2::unload() -> void { } auto ICD2::power() -> void { - create(ICD2::Enter, system.colorburst() * 6.0 / 5.0); + create(ICD2::Enter, system.cpuFrequency() / 5.0); stream = Emulator::audio.createStream(2, frequency() / 2.0); stream->addFilter(Emulator::Filter::Order::First, Emulator::Filter::Type::HighPass, 20.0); stream->addFilter(Emulator::Filter::Order::Second, Emulator::Filter::Type::LowPass, 20000.0, 3); @@ -76,8 +76,7 @@ auto ICD2::power() -> void { } auto ICD2::reset() -> void { - auto frequency = system.colorburst() * 6.0; - create(ICD2::Enter, frequency / 5); + create(ICD2::Enter, system.cpuFrequency() / 5.0); r6003 = 0x00; r6004 = 0xff; diff --git a/higan/sfc/coprocessor/icd2/io.cpp b/higan/sfc/coprocessor/icd2/io.cpp index 5b4e885d..3ad1841b 100644 --- a/higan/sfc/coprocessor/icd2/io.cpp +++ b/higan/sfc/coprocessor/icd2/io.cpp @@ -56,7 +56,7 @@ auto ICD2::writeIO(uint24 addr, uint8 data) -> void { if((r6003 & 0x80) == 0x00 && (data & 0x80) == 0x80) { reset(); } - auto frequency = system.colorburst() * 6.0; + auto frequency = system.cpuFrequency(); switch(data & 3) { case 0: setFrequency(frequency / 4); break; //fast (glitchy, even on real hardware) case 1: setFrequency(frequency / 5); break; //normal diff --git a/higan/sfc/coprocessor/sa1/sa1.cpp b/higan/sfc/coprocessor/sa1/sa1.cpp index 9053ba45..3c288a18 100644 --- a/higan/sfc/coprocessor/sa1/sa1.cpp +++ b/higan/sfc/coprocessor/sa1/sa1.cpp @@ -131,7 +131,7 @@ auto SA1::unload() -> void { auto SA1::power() -> void { WDC65816::power(); - create(SA1::Enter, system.colorburst() * 6.0); + create(SA1::Enter, system.cpuFrequency()); cpubwram.dma = false; for(auto addr : range(iram.size())) { @@ -142,7 +142,7 @@ auto SA1::power() -> void { status.interruptPending = false; - status.scanlines = (system.region() == System::Region::NTSC ? 262 : 312); + status.scanlines = Region::PAL() ? 312 : 262; status.vcounter = 0; status.hcounter = 0; diff --git a/higan/sfc/coprocessor/superfx/superfx.cpp b/higan/sfc/coprocessor/superfx/superfx.cpp index c523149b..5419fb6e 100644 --- a/higan/sfc/coprocessor/superfx/superfx.cpp +++ b/higan/sfc/coprocessor/superfx/superfx.cpp @@ -44,7 +44,7 @@ auto SuperFX::unload() -> void { auto SuperFX::power() -> void { GSU::power(); - create(SuperFX::Enter, system.colorburst() * 6.0); + create(SuperFX::Enter, system.cpuFrequency()); romMask = rom.size() - 1; ramMask = ram.size() - 1; diff --git a/higan/sfc/cpu/cpu.cpp b/higan/sfc/cpu/cpu.cpp index f1cdbe91..b29a5791 100644 --- a/higan/sfc/cpu/cpu.cpp +++ b/higan/sfc/cpu/cpu.cpp @@ -62,7 +62,7 @@ auto CPU::load(Markup::Node node) -> bool { auto CPU::power() -> void { WDC65816::power(); - create(Enter, system.colorburst() * 6.0); + create(Enter, system.cpuFrequency()); coprocessors.reset(); PPUcounter::reset(); diff --git a/higan/sfc/cpu/io.cpp b/higan/sfc/cpu/io.cpp index 14f4a2aa..a590b1e4 100644 --- a/higan/sfc/cpu/io.cpp +++ b/higan/sfc/cpu/io.cpp @@ -16,7 +16,7 @@ auto CPU::readCPU(uint24 addr, uint8 data) -> uint8 { //1-0 = Joypad serial data case 0x4016: { uint8 v = r.mdr & 0xfc; - v |= SuperFamicom::peripherals.controllerPort1->data(); + v |= controllerPort1.device->data(); return v; } @@ -26,7 +26,7 @@ auto CPU::readCPU(uint24 addr, uint8 data) -> uint8 { //4-2 = Always 1 (pins are connected to GND) //1-0 = Joypad serial data uint8 v = (r.mdr & 0xe0) | 0x1c; - v |= SuperFamicom::peripherals.controllerPort2->data(); + v |= controllerPort2.device->data(); return v; } @@ -178,8 +178,8 @@ auto CPU::writeCPU(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. - SuperFamicom::peripherals.controllerPort1->latch(data.bit(0)); - SuperFamicom::peripherals.controllerPort2->latch(data.bit(0)); + controllerPort1.device->latch(data.bit(0)); + controllerPort2.device->latch(data.bit(0)); return; } diff --git a/higan/sfc/cpu/timing.cpp b/higan/sfc/cpu/timing.cpp index 2676802c..44af1e9f 100644 --- a/higan/sfc/cpu/timing.cpp +++ b/higan/sfc/cpu/timing.cpp @@ -145,14 +145,14 @@ auto CPU::joypadEdge() -> void { if(status.autoJoypadActive && status.autoJoypadLatch) { if(status.autoJoypadCounter == 0) { - SuperFamicom::peripherals.controllerPort1->latch(1); - SuperFamicom::peripherals.controllerPort2->latch(1); - SuperFamicom::peripherals.controllerPort1->latch(0); - SuperFamicom::peripherals.controllerPort2->latch(0); + controllerPort1.device->latch(1); + controllerPort2.device->latch(1); + controllerPort1.device->latch(0); + controllerPort2.device->latch(0); } - uint2 port0 = SuperFamicom::peripherals.controllerPort1->data(); - uint2 port1 = SuperFamicom::peripherals.controllerPort2->data(); + uint2 port0 = controllerPort1.device->data(); + uint2 port1 = controllerPort2.device->data(); io.joy1 = io.joy1 << 1 | port0.bit(0); io.joy2 = io.joy2 << 1 | port1.bit(0); diff --git a/higan/sfc/dsp/dsp.cpp b/higan/sfc/dsp/dsp.cpp index e95d28e5..f61d6460 100644 --- a/higan/sfc/dsp/dsp.cpp +++ b/higan/sfc/dsp/dsp.cpp @@ -229,7 +229,7 @@ auto DSP::load(Markup::Node node) -> bool { } auto DSP::power() -> void { - create(Enter, 32040.0 * 768.0); + create(Enter, system.apuFrequency()); stream = Emulator::audio.createStream(2, frequency() / 768.0); memory::fill(&state, sizeof(State)); diff --git a/higan/sfc/expansion/21fx/21fx.cpp b/higan/sfc/expansion/21fx/21fx.cpp index 0775ffb2..71b2e603 100644 --- a/higan/sfc/expansion/21fx/21fx.cpp +++ b/higan/sfc/expansion/21fx/21fx.cpp @@ -52,7 +52,7 @@ S21FX::~S21FX() { } auto S21FX::Enter() -> void { - while(true) scheduler.synchronize(), peripherals.expansionPort->main(); + while(true) scheduler.synchronize(), expansionPort.device->main(); } auto S21FX::step(uint clocks) -> void { diff --git a/higan/sfc/expansion/expansion.cpp b/higan/sfc/expansion/expansion.cpp index 34d9d19a..fc0aad87 100644 --- a/higan/sfc/expansion/expansion.cpp +++ b/higan/sfc/expansion/expansion.cpp @@ -2,12 +2,18 @@ namespace SuperFamicom { +ExpansionPort expansionPort; + Expansion::Expansion() { if(!handle()) create(Expansion::Enter, 1); } +Expansion::~Expansion() { + scheduler.remove(*this); +} + auto Expansion::Enter() -> void { - while(true) scheduler.synchronize(), peripherals.expansionPort->main(); + while(true) scheduler.synchronize(), expansionPort.device->main(); } auto Expansion::main() -> void { @@ -15,4 +21,33 @@ auto Expansion::main() -> void { synchronize(cpu); } +// + +auto ExpansionPort::connect(uint deviceID) -> void { + if(!system.loaded()) return; + delete device; + + switch(deviceID) { default: + case ID::Device::None: device = new Expansion; break; + case ID::Device::Satellaview: device = new Satellaview; break; + case ID::Device::S21FX: device = new S21FX; break; + } + + cpu.peripherals.reset(); + if(auto device = controllerPort1.device) cpu.peripherals.append(device); + if(auto device = controllerPort2.device) cpu.peripherals.append(device); + if(auto device = expansionPort.device) cpu.peripherals.append(device); +} + +auto ExpansionPort::power() -> void { +} + +auto ExpansionPort::unload() -> void { + delete device; + device = nullptr; +} + +auto ExpansionPort::serialize(serializer& s) -> void { +} + } diff --git a/higan/sfc/expansion/expansion.hpp b/higan/sfc/expansion/expansion.hpp index 63982a69..194ecad5 100644 --- a/higan/sfc/expansion/expansion.hpp +++ b/higan/sfc/expansion/expansion.hpp @@ -1,8 +1,21 @@ struct Expansion : Thread { Expansion(); + virtual ~Expansion(); static auto Enter() -> void; virtual auto main() -> void; }; +struct ExpansionPort { + auto connect(uint deviceID) -> void; + + auto power() -> void; + auto unload() -> void; + auto serialize(serializer&) -> void; + + Expansion* device = nullptr; +}; + +extern ExpansionPort expansionPort; + #include #include diff --git a/higan/sfc/interface/interface.cpp b/higan/sfc/interface/interface.cpp index eb3e9c19..73146b18 100644 --- a/higan/sfc/interface/interface.cpp +++ b/higan/sfc/interface/interface.cpp @@ -187,7 +187,9 @@ auto Interface::unload() -> void { } auto Interface::connect(uint port, uint device) -> void { - peripherals.connect(port, device); + if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device); + if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device); + if(port == ID::Port::Expansion) expansionPort.connect(settings.expansionPort = device); } auto Interface::power() -> void { diff --git a/higan/sfc/ppu/counter/counter-inline.hpp b/higan/sfc/ppu/counter/counter-inline.hpp index bf43cca1..c128543b 100644 --- a/higan/sfc/ppu/counter/counter-inline.hpp +++ b/higan/sfc/ppu/counter/counter-inline.hpp @@ -27,12 +27,12 @@ auto PPUcounter::tick(uint clocks) -> void { auto PPUcounter::vcounterTick() -> void { if(++status.vcounter == 128) status.interlace = ppu.interlace(); - if((system.region() == System::Region::NTSC && status.interlace == 0 && status.vcounter == 262) - || (system.region() == System::Region::NTSC && status.interlace == 1 && status.vcounter == 263) - || (system.region() == System::Region::NTSC && status.interlace == 1 && status.vcounter == 262 && status.field == 1) - || (system.region() == System::Region::PAL && status.interlace == 0 && status.vcounter == 312) - || (system.region() == System::Region::PAL && status.interlace == 1 && status.vcounter == 313) - || (system.region() == System::Region::PAL && status.interlace == 1 && status.vcounter == 312 && status.field == 1) + if((Region::NTSC() && status.interlace == 0 && status.vcounter == 262) + || (Region::NTSC() && status.interlace == 1 && status.vcounter == 263) + || (Region::NTSC() && status.interlace == 1 && status.vcounter == 262 && status.field == 1) + || (Region::PAL() && status.interlace == 0 && status.vcounter == 312) + || (Region::PAL() && status.interlace == 1 && status.vcounter == 313) + || (Region::PAL() && status.interlace == 1 && status.vcounter == 312 && status.field == 1) ) { status.vcounter = 0; status.field = !status.field; @@ -58,7 +58,7 @@ auto PPUcounter::hcounter(uint offset) const -> uint16 { return history.hcounter //dot 327 range = {1310, 1312, 1314} auto PPUcounter::hdot() const -> uint16 { - if(system.region() == System::Region::NTSC && status.interlace == 0 && vcounter() == 240 && field() == 1) { + if(Region::NTSC() && status.interlace == 0 && vcounter() == 240 && field() == 1) { return (hcounter() >> 2); } else { return (hcounter() - ((hcounter() > 1292) << 1) - ((hcounter() > 1310) << 1)) >> 2; @@ -66,7 +66,7 @@ auto PPUcounter::hdot() const -> uint16 { } auto PPUcounter::lineclocks() const -> uint16 { - if(system.region() == System::Region::NTSC && status.interlace == 0 && vcounter() == 240 && field() == 1) return 1360; + if(Region::NTSC() && status.interlace == 0 && vcounter() == 240 && field() == 1) return 1360; return 1364; } diff --git a/higan/sfc/ppu/io.cpp b/higan/sfc/ppu/io.cpp index 5aa0ea56..4587f92f 100644 --- a/higan/sfc/ppu/io.cpp +++ b/higan/sfc/ppu/io.cpp @@ -156,7 +156,7 @@ auto PPU::readIO(uint24 addr, uint8 data) -> uint8 { latch.vcounter = 0; ppu2.mdr.bits(0,3) = ppu2.version; - ppu2.mdr.bit ( 4) = system.region() == System::Region::PAL; //0 = NTSC + ppu2.mdr.bit ( 4) = Region::PAL(); //0 = NTSC, 1 = PAL if(!cpu.pio().bit(7)) { ppu2.mdr.bit( 6) = 1; } else { diff --git a/higan/sfc/ppu/ppu.cpp b/higan/sfc/ppu/ppu.cpp index d0aa57a7..98871815 100644 --- a/higan/sfc/ppu/ppu.cpp +++ b/higan/sfc/ppu/ppu.cpp @@ -87,7 +87,7 @@ auto PPU::load(Markup::Node node) -> bool { } auto PPU::power() -> void { - create(Enter, system.colorburst() * 6.0); + create(Enter, system.cpuFrequency()); PPUcounter::reset(); memory::fill(output, 512 * 480 * sizeof(uint32)); diff --git a/higan/sfc/smp/memory.cpp b/higan/sfc/smp/memory.cpp index 09922e32..af57334d 100644 --- a/higan/sfc/smp/memory.cpp +++ b/higan/sfc/smp/memory.cpp @@ -10,11 +10,11 @@ alwaysinline auto SMP::writeRAM(uint16 addr, uint8 data) -> void { } auto SMP::readPort(uint2 port) const -> uint8 { - return apuram[0xf4 + port]; + return io.port[0xf4 + port]; } auto SMP::writePort(uint2 port, uint8 data) -> void { - apuram[0xf4 + port] = data; + io.port[0xf4 + port] = data; } auto SMP::readBus(uint16 addr) -> uint8 { @@ -173,6 +173,11 @@ auto SMP::writeBus(uint16 addr, uint8 data) -> void { writeRAM(addr, data); //all writes, even to MMIO registers, appear on bus } +auto SMP::idle() -> void { + step(24); + cycleEdge(); +} + auto SMP::read(uint16 addr) -> uint8 { step(12); uint8 data = readBus(addr); diff --git a/higan/sfc/smp/serialization.cpp b/higan/sfc/smp/serialization.cpp index 215f392b..b12811b3 100644 --- a/higan/sfc/smp/serialization.cpp +++ b/higan/sfc/smp/serialization.cpp @@ -19,6 +19,8 @@ auto SMP::serialize(serializer& s) -> void { s.integer(io.dspAddr); + s.array(io.port); + s.integer(io.ram00f8); s.integer(io.ram00f9); diff --git a/higan/sfc/smp/smp.cpp b/higan/sfc/smp/smp.cpp index b53f5001..3b57f97f 100644 --- a/higan/sfc/smp/smp.cpp +++ b/higan/sfc/smp/smp.cpp @@ -34,16 +34,12 @@ auto SMP::load(Markup::Node node) -> bool { auto SMP::power() -> void { SPC700::power(); - create(Enter, 32040.0 * 768.0); + create(Enter, system.apuFrequency()); r.pc.byte.l = iplrom[62]; r.pc.byte.h = iplrom[63]; for(auto& byte : apuram) byte = random(0x00); - apuram[0x00f4] = 0x00; - apuram[0x00f5] = 0x00; - apuram[0x00f6] = 0x00; - apuram[0x00f7] = 0x00; io.clockCounter = 0; io.dspCounter = 0; @@ -63,6 +59,12 @@ auto SMP::power() -> void { //$00f2 io.dspAddr = 0x00; + //$00f4-00f7 + io.port[0] = 0x00; + io.port[1] = 0x00; + io.port[2] = 0x00; + io.port[3] = 0x00; + //$00f8,$00f9 io.ram00f8 = 0x00; io.ram00f9 = 0x00; diff --git a/higan/sfc/smp/smp.hpp b/higan/sfc/smp/smp.hpp index 7f3f4dcf..d03f1825 100644 --- a/higan/sfc/smp/smp.hpp +++ b/higan/sfc/smp/smp.hpp @@ -38,6 +38,9 @@ private: //$00f2 uint8 dspAddr; + //$00f4-00f7 + uint8 port[4]; + //$00f8,$00f9 uint8 ram00f8; uint8 ram00f9; @@ -52,6 +55,7 @@ private: auto readBus(uint16 addr) -> uint8; auto writeBus(uint16 addr, uint8 data) -> void; + auto idle() -> void override; auto read(uint16 addr) -> uint8 override; auto write(uint16 addr, uint8 data) -> void override; diff --git a/higan/sfc/system/peripherals.cpp b/higan/sfc/system/peripherals.cpp deleted file mode 100644 index dbd0a8f6..00000000 --- a/higan/sfc/system/peripherals.cpp +++ /dev/null @@ -1,63 +0,0 @@ -Peripherals peripherals; - -auto Peripherals::unload() -> void { - delete controllerPort1; - delete controllerPort2; - delete expansionPort; - controllerPort1 = nullptr; - controllerPort2 = nullptr; - expansionPort = nullptr; -} - -auto Peripherals::reset() -> void { - connect(ID::Port::Controller1, settings.controllerPort1); - connect(ID::Port::Controller2, settings.controllerPort2); - connect(ID::Port::Expansion, settings.expansionPort); -} - -auto Peripherals::connect(uint port, uint device) -> void { - if(port == ID::Port::Controller1) { - settings.controllerPort1 = device; - if(!system.loaded()) return; - - delete controllerPort1; - switch(device) { default: - case ID::Device::None: controllerPort1 = new Controller(0); break; - case ID::Device::Gamepad: controllerPort1 = new Gamepad(0); break; - case ID::Device::Mouse: controllerPort1 = new Mouse(0); break; - } - } - - if(port == ID::Port::Controller2) { - settings.controllerPort2 = device; - if(!system.loaded()) return; - - delete controllerPort2; - switch(device) { default: - case ID::Device::None: controllerPort2 = new Controller(1); break; - case ID::Device::Gamepad: controllerPort2 = new Gamepad(1); break; - case ID::Device::Mouse: controllerPort2 = new Mouse(1); break; - case ID::Device::SuperMultitap: controllerPort2 = new SuperMultitap(1); break; - case ID::Device::SuperScope: controllerPort2 = new SuperScope(1); break; - case ID::Device::Justifier: controllerPort2 = new Justifier(1, false); break; - case ID::Device::Justifiers: controllerPort2 = new Justifier(1, true); break; - } - } - - if(port == ID::Port::Expansion) { - settings.expansionPort = device; - if(!system.loaded()) return; - - delete expansionPort; - switch(device) { default: - case ID::Device::None: expansionPort = new Expansion; break; - case ID::Device::Satellaview: expansionPort = new Satellaview; break; - case ID::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/serialization.cpp b/higan/sfc/system/serialization.cpp index cc5202bf..6f0f5463 100644 --- a/higan/sfc/system/serialization.cpp +++ b/higan/sfc/system/serialization.cpp @@ -66,6 +66,10 @@ auto System::serializeAll(serializer& s) -> void { if(cartridge.has.MSU1) msu1.serialize(s); if(cartridge.has.SufamiTurboSlots) sufamiturboA.serialize(s), sufamiturboB.serialize(s); + + controllerPort1.serialize(s); + controllerPort2.serialize(s); + expansionPort.serialize(s); } //perform dry-run state save: diff --git a/higan/sfc/system/system.cpp b/higan/sfc/system/system.cpp index 8a7b2a4f..a1d13ee4 100644 --- a/higan/sfc/system/system.cpp +++ b/higan/sfc/system/system.cpp @@ -6,7 +6,6 @@ System system; Scheduler scheduler; Cheat cheat; #include "video.cpp" -#include "peripherals.cpp" #include "random.cpp" #include "serialization.cpp" @@ -65,11 +64,11 @@ auto System::load(Emulator::Interface* interface) -> bool { if(cartridge.region() == "NTSC") { information.region = Region::NTSC; - information.colorburst = Emulator::Constants::Colorburst::NTSC; + information.cpuFrequency = Emulator::Constants::Colorburst::NTSC * 6.0; } if(cartridge.region() == "PAL") { information.region = Region::PAL; - information.colorburst = Emulator::Constants::Colorburst::PAL * 4.0 / 5.0; + information.cpuFrequency = Emulator::Constants::Colorburst::PAL * 4.8; } if(cartridge.has.ICD2) icd2.load(); @@ -98,12 +97,17 @@ auto System::load(Emulator::Interface* interface) -> bool { auto System::save() -> void { if(!loaded()) return; + cartridge.save(); } auto System::unload() -> void { if(!loaded()) return; - peripherals.unload(); + + cpu.peripherals.reset(); + controllerPort1.unload(); + controllerPort2.unload(); + expansionPort.unload(); if(cartridge.has.ICD2) icd2.unload(); if(cartridge.has.MCC) mcc.unload(); @@ -176,7 +180,14 @@ auto System::power() -> void { if(cartridge.has.MSU1) cpu.coprocessors.append(&msu1); scheduler.primary(cpu); - peripherals.reset(); + + controllerPort1.power(ID::Port::Controller1); + controllerPort2.power(ID::Port::Controller2); + expansionPort.power(); + + controllerPort1.connect(settings.controllerPort1); + controllerPort2.connect(settings.controllerPort2); + expansionPort.connect(settings.expansionPort); } } diff --git a/higan/sfc/system/system.hpp b/higan/sfc/system/system.hpp index e8beb422..b5e5f5e9 100644 --- a/higan/sfc/system/system.hpp +++ b/higan/sfc/system/system.hpp @@ -3,7 +3,8 @@ struct System { inline auto loaded() const -> bool { return information.loaded; } inline auto region() const -> Region { return information.region; } - inline auto colorburst() const -> double { return information.colorburst; } + inline auto cpuFrequency() const -> double { return information.cpuFrequency; } + inline auto apuFrequency() const -> double { return information.apuFrequency; } auto run() -> void; auto runToSave() -> void; @@ -30,7 +31,8 @@ private: string manifest; bool loaded = false; Region region = Region::NTSC; - double colorburst = Emulator::Constants::Colorburst::NTSC; + double cpuFrequency = Emulator::Constants::Colorburst::NTSC * 6.0; + double apuFrequency = 32040.0 * 768.0; } information; uint serializeSize = 0; @@ -42,16 +44,6 @@ private: friend class Cartridge; }; -struct Peripherals { - auto unload() -> void; - auto reset() -> void; - auto connect(uint port, uint device) -> void; - - Controller* controllerPort1 = nullptr; - Controller* controllerPort2 = nullptr; - Expansion* expansionPort = nullptr; -}; - struct Random { auto seed(uint seed) -> void; auto operator()(uint result) -> uint; @@ -62,7 +54,6 @@ private: }; extern System system; -extern Peripherals peripherals; extern Random random; auto Region::NTSC() -> bool { return system.region() == System::Region::NTSC; }