diff --git a/higan/emulator/cheat.hpp b/higan/emulator/cheat.hpp new file mode 100644 index 00000000..929c6780 --- /dev/null +++ b/higan/emulator/cheat.hpp @@ -0,0 +1,48 @@ +#pragma once + +namespace Emulator { + +struct Cheat { + struct Code { + uint addr; + uint data; + maybe comp; + }; + + explicit operator bool() const { + return codes.size() > 0; + } + + auto reset() -> void { + codes.reset(); + } + + auto append(uint addr, uint data, maybe comp = nothing) -> void { + codes.append({addr, data, comp}); + } + + auto assign(const string_vector& list) -> void { + reset(); + for(auto& entry : list) { + for(auto code : entry.split("+")) { + auto part = code.split("/"); + if(part.size() == 2) append(part[0].hex(), part[1].hex()); + if(part.size() == 3) append(part[0].hex(), part[2].hex(), part[1].hex()); + } + } + } + + auto find(uint addr, uint comp) -> maybe { + for(auto& code : codes) { + if(code.addr == addr && (!code.comp || code.comp() == comp)) { + return code.data; + } + } + return nothing; + } + +private: + vector codes; +}; + +} diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 51a56357..f9045b27 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -11,13 +11,20 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "100.02"; + static const string Version = "100.03"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; //incremented only when serialization format changes static const string SerializerVersion = "100"; + + namespace Constants { + namespace Colorburst { + static constexpr double NTSC = 315.0 / 88.0 * 1'000'000.0; + static constexpr double PAL = 283.75 * 15'625.0 + 25.0; + } + } } #include "interface.hpp" diff --git a/higan/emulator/scheduler.hpp b/higan/emulator/scheduler.hpp new file mode 100644 index 00000000..876cc383 --- /dev/null +++ b/higan/emulator/scheduler.hpp @@ -0,0 +1,65 @@ +#pragma once + +namespace Emulator { + +struct Scheduler { + enum class Mode : uint { + Run, + SynchronizeMaster, + SynchronizeSlave, + }; + + enum class Event : uint { + Step, + Frame, + Synchronize, + }; + + auto reset(cothread_t master_) -> void { + master = resume = master_; + host = co_active(); + } + + auto enter(Mode mode_ = Mode::Run) -> Event { + mode = mode_; + host = co_active(); + co_switch(resume); + return event; + } + + auto exit(Event event_) -> void { + event = event_; + resume = co_active(); + co_switch(host); + } + + auto synchronize(cothread_t thread) -> void { + if(thread == master) { + while(enter(Mode::SynchronizeMaster) != Event::Synchronize); + } else { + resume = thread; + while(enter(Mode::SynchronizeSlave) != Event::Synchronize); + } + } + + auto synchronize() -> void { + if(co_active() == master) { + if(mode == Mode::SynchronizeMaster) return exit(Event::Synchronize); + } else { + if(mode == Mode::SynchronizeSlave) return exit(Event::Synchronize); + } + } + + auto synchronizing() const -> bool { + return mode == Mode::SynchronizeSlave; + } + +private: + cothread_t host = nullptr; //program thread (used to exit scheduler) + cothread_t resume = nullptr; //resume thread (used to enter scheduler) + cothread_t master = nullptr; //primary thread (used to synchronize components) + Mode mode = Mode::Run; + Event event = Event::Step; +}; + +} diff --git a/higan/emulator/thread.hpp b/higan/emulator/thread.hpp new file mode 100644 index 00000000..f047d84b --- /dev/null +++ b/higan/emulator/thread.hpp @@ -0,0 +1,27 @@ +#pragma once + +namespace Emulator { + +struct Thread { + virtual ~Thread() { + if(thread) co_delete(thread); + } + + auto create(auto (*entrypoint)() -> void, double frequency_) -> void { + if(thread) co_delete(thread); + thread = co_create(64 * 1024 * sizeof(void*), entrypoint); + frequency = frequency_ + 0.5; //round to nearest whole number + clock = 0; + } + + auto serialize(serializer& s) -> void { + s.integer(frequency); + s.integer(clock); + } + + cothread_t thread = nullptr; + uint frequency = 0; + int64 clock = 0; +}; + +} diff --git a/higan/fc/GNUmakefile b/higan/fc/GNUmakefile index 13531ff1..9eed6a49 100644 --- a/higan/fc/GNUmakefile +++ b/higan/fc/GNUmakefile @@ -1,16 +1,13 @@ processors += r6502 -objects += fc-interface fc-system fc-scheduler fc-controller +objects += fc-interface fc-system fc-controller objects += fc-memory fc-cartridge fc-cpu fc-apu fc-ppu -objects += fc-cheat obj/fc-interface.o: fc/interface/interface.cpp $(call rwildcard,fc/interface/) obj/fc-system.o: fc/system/system.cpp $(call rwildcard,fc/system/) -obj/fc-scheduler.o: fc/scheduler/scheduler.cpp $(call rwildcard,fc/scheduler/) obj/fc-controller.o: fc/controller/controller.cpp $(call rwildcard,fc/controller/) obj/fc-memory.o: fc/memory/memory.cpp $(call rwildcard,fc/memory/) obj/fc-cartridge.o: fc/cartridge/cartridge.cpp $(call rwildcard,fc/cartridge/) obj/fc-cpu.o: fc/cpu/cpu.cpp $(call rwildcard,fc/cpu/) obj/fc-apu.o: fc/apu/apu.cpp $(call rwildcard,fc/apu/) obj/fc-ppu.o: fc/ppu/ppu.cpp $(call rwildcard,fc/ppu/) -obj/fc-cheat.o: fc/cheat/cheat.cpp $(call rwildcard,fc/cheat/) diff --git a/higan/fc/apu/apu.cpp b/higan/fc/apu/apu.cpp index 8333109c..859d734f 100644 --- a/higan/fc/apu/apu.cpp +++ b/higan/fc/apu/apu.cpp @@ -88,8 +88,8 @@ auto APU::power() -> void { } auto APU::reset() -> void { - create(APU::Enter, 21'477'272); - stream = Emulator::audio.createStream(1, 21'477'272.0 / 12.0); + create(APU::Enter, system.colorburst() * 6.0); + stream = Emulator::audio.createStream(1, system.colorburst() / 2.0); pulse[0].reset(); pulse[1].reset(); diff --git a/higan/fc/cartridge/cartridge.cpp b/higan/fc/cartridge/cartridge.cpp index e6c869f4..3f5dcec0 100644 --- a/higan/fc/cartridge/cartridge.cpp +++ b/higan/fc/cartridge/cartridge.cpp @@ -49,7 +49,7 @@ auto Cartridge::power() -> void { } auto Cartridge::reset() -> void { - create(Cartridge::Enter, 21'477'272); + create(Cartridge::Enter, system.colorburst() * 6.0); board->reset(); } diff --git a/higan/fc/cheat/cheat.cpp b/higan/fc/cheat/cheat.cpp deleted file mode 100644 index b50c99f0..00000000 --- a/higan/fc/cheat/cheat.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include - -namespace Famicom { - -Cheat cheat; - -auto Cheat::reset() -> void { - codes.reset(); -} - -auto Cheat::append(uint addr, uint data) -> void { - codes.append({addr, Unused, data}); -} - -auto Cheat::append(uint addr, uint comp, uint data) -> void { - codes.append({addr, comp, data}); -} - -auto Cheat::find(uint addr, uint comp) -> maybe { - for(auto& code : codes) { - if(code.addr == addr && (code.comp == Unused || code.comp == comp)) { - return code.data; - } - } - return nothing; -} - -} diff --git a/higan/fc/cheat/cheat.hpp b/higan/fc/cheat/cheat.hpp deleted file mode 100644 index 4400f07c..00000000 --- a/higan/fc/cheat/cheat.hpp +++ /dev/null @@ -1,17 +0,0 @@ -struct Cheat { - struct Code { - uint addr; - uint comp; - uint data; - }; - vector codes; - enum : uint { Unused = ~0u }; - - alwaysinline auto enable() const -> bool { return codes.size() > 0; } - auto reset() -> void; - auto append(uint addr, uint data) -> void; - auto append(uint addr, uint comp, uint data) -> void; - auto find(uint addr, uint comp) -> maybe; -}; - -extern Cheat cheat; diff --git a/higan/fc/cpu/cpu.cpp b/higan/fc/cpu/cpu.cpp index 99d92c8b..25da48cb 100644 --- a/higan/fc/cpu/cpu.cpp +++ b/higan/fc/cpu/cpu.cpp @@ -44,7 +44,7 @@ auto CPU::power() -> void { auto CPU::reset() -> void { R6502::reset(); - create(CPU::Enter, 21'477'272); + create(CPU::Enter, system.colorburst() * 6.0); regs.pc = bus.read(0xfffc) << 0; regs.pc |= bus.read(0xfffd) << 8; diff --git a/higan/fc/fc.hpp b/higan/fc/fc.hpp index 9b647383..7cd552ff 100644 --- a/higan/fc/fc.hpp +++ b/higan/fc/fc.hpp @@ -4,39 +4,25 @@ //started: 2011-09-05 #include +#include +#include +#include + #include namespace Famicom { using File = Emulator::File; - - struct Thread { - ~Thread() { - if(thread) co_delete(thread); - } - - auto create(auto (*entrypoint)() -> void, uint frequency) -> void { - if(thread) co_delete(thread); - thread = co_create(65'536 * sizeof(void*), entrypoint); - this->frequency = frequency; - clock = 0; - } - - auto serialize(serializer& s) -> void { - s.integer(frequency); - s.integer(clock); - } - - cothread_t thread = nullptr; - uint frequency = 0; - int64 clock = 0; - }; + using Thread = Emulator::Thread; + using Scheduler = Emulator::Scheduler; + using Cheat = Emulator::Cheat; + extern Scheduler scheduler; + extern Cheat cheat; struct Cothread : Thread { auto step(uint clocks) -> void; auto synchronizeCPU() -> void; }; - #include #include #include #include @@ -44,7 +30,6 @@ namespace Famicom { #include #include #include - #include inline auto Cothread::step(uint clocks) -> void { clock += clocks * (uint64)cpu.frequency; diff --git a/higan/fc/interface/interface.cpp b/higan/fc/interface/interface.cpp index b772f53c..81ac8933 100644 --- a/higan/fc/interface/interface.cpp +++ b/higan/fc/interface/interface.cpp @@ -164,15 +164,7 @@ auto Interface::unserialize(serializer& s) -> bool { } auto Interface::cheatSet(const string_vector& list) -> void { - cheat.reset(); - for(auto& codeset : list) { - auto codes = codeset.split("+"); - for(auto& code : codes) { - auto part = code.split("/"); - if(part.size() == 2) cheat.append(part[0].hex(), part[1].hex()); - if(part.size() == 3) cheat.append(part[0].hex(), part[1].hex(), part[2].hex()); - } - } + cheat.assign(list); } auto Interface::cap(const string& name) -> bool { diff --git a/higan/fc/memory/memory.cpp b/higan/fc/memory/memory.cpp index b5d8e014..e2eaa4ca 100644 --- a/higan/fc/memory/memory.cpp +++ b/higan/fc/memory/memory.cpp @@ -17,7 +17,7 @@ auto Bus::read(uint16 addr) -> uint8 { else if(addr <= 0x3fff) data = ppu.readIO(addr); else if(addr <= 0x4017) data = cpu.readIO(addr); - if(cheat.enable()) { + if(cheat) { if(auto result = cheat.find(addr, data)) return result(); } diff --git a/higan/fc/ppu/ppu.cpp b/higan/fc/ppu/ppu.cpp index 9c76f1fc..3ae5a28d 100644 --- a/higan/fc/ppu/ppu.cpp +++ b/higan/fc/ppu/ppu.cpp @@ -56,7 +56,7 @@ auto PPU::power() -> void { } auto PPU::reset() -> void { - create(PPU::Enter, 21'477'272); + create(PPU::Enter, system.colorburst() * 6.0); memory::fill(&io, sizeof(IO)); memory::fill(&latch, sizeof(Latches)); diff --git a/higan/fc/scheduler/scheduler.cpp b/higan/fc/scheduler/scheduler.cpp deleted file mode 100644 index 6310097a..00000000 --- a/higan/fc/scheduler/scheduler.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include - -namespace Famicom { - -Scheduler scheduler; - -auto Scheduler::reset() -> void { - host = co_active(); - resume = cpu.thread; -} - -auto Scheduler::enter(Mode mode_) -> Event { - mode = mode_; - host = co_active(); - co_switch(resume); - if(event == Event::Frame) ppu.refresh(); - return event; -} - -auto Scheduler::exit(Event event_) -> void { - event = event_; - resume = co_active(); - co_switch(host); -} - -auto Scheduler::synchronize(cothread_t thread) -> void { - if(thread == cpu.thread) { - while(enter(Mode::SynchronizeCPU) != Event::Synchronize); - } else { - resume = thread; - while(enter(Mode::SynchronizeAll) != Event::Synchronize); - } -} - -auto Scheduler::synchronize() -> void { - if(co_active() == cpu.thread && mode == Mode::SynchronizeCPU) return exit(Event::Synchronize); - if(co_active() != cpu.thread && mode == Mode::SynchronizeAll) return exit(Event::Synchronize); -} - -auto Scheduler::synchronizing() const -> bool { - return mode == Mode::SynchronizeAll; -} - -} diff --git a/higan/fc/scheduler/scheduler.hpp b/higan/fc/scheduler/scheduler.hpp deleted file mode 100644 index 87be9c70..00000000 --- a/higan/fc/scheduler/scheduler.hpp +++ /dev/null @@ -1,28 +0,0 @@ -struct Scheduler { - enum class Mode : uint { - Run, - SynchronizeCPU, - SynchronizeAll, - }; - - enum class Event : uint { - Unknown, - Frame, - Synchronize, - }; - - auto reset() -> void; - auto enter(Mode = Mode::Run) -> Event; - auto exit(Event) -> void; - auto synchronize(cothread_t) -> void; - auto synchronize() -> void; - auto synchronizing() const -> bool; - -private: - cothread_t host = nullptr; - cothread_t resume = nullptr; - Mode mode = Mode::Run; - Event event = Event::Unknown; -}; - -extern Scheduler scheduler; diff --git a/higan/fc/system/system.cpp b/higan/fc/system/system.cpp index 7b00bc83..0de5e517 100644 --- a/higan/fc/system/system.cpp +++ b/higan/fc/system/system.cpp @@ -6,9 +6,11 @@ namespace Famicom { #include "video.cpp" #include "serialization.cpp" System system; +Scheduler scheduler; +Cheat cheat; auto System::run() -> void { - scheduler.enter(); + if(scheduler.enter() == Scheduler::Event::Frame) ppu.refresh(); } auto System::runToSave() -> void { @@ -30,6 +32,7 @@ auto System::load() -> bool { } auto document = BML::unserialize(information.manifest); if(!cartridge.load()) return false; + information.colorburst = Emulator::Constants::Colorburst::NTSC; serializeInit(); return information.loaded = true; } @@ -66,7 +69,7 @@ auto System::reset() -> void { cpu.reset(); apu.reset(); ppu.reset(); - scheduler.reset(); + scheduler.reset(cpu.thread); peripherals.reset(); } diff --git a/higan/fc/system/system.hpp b/higan/fc/system/system.hpp index 708411c0..c28aec40 100644 --- a/higan/fc/system/system.hpp +++ b/higan/fc/system/system.hpp @@ -1,5 +1,6 @@ struct System { auto loaded() const -> bool { return information.loaded; } + auto colorburst() const -> double { return information.colorburst; } auto run() -> void; auto runToSave() -> void; @@ -27,6 +28,7 @@ struct System { struct Information { bool loaded = false; + double colorburst = 0.0; string manifest; } information; diff --git a/higan/gb/GNUmakefile b/higan/gb/GNUmakefile index 7b3ded9a..2ede01c7 100644 --- a/higan/gb/GNUmakefile +++ b/higan/gb/GNUmakefile @@ -1,16 +1,13 @@ processors += lr35902 -objects += gb-interface gb-system gb-scheduler +objects += gb-interface gb-system objects += gb-memory gb-cartridge objects += gb-cpu gb-ppu gb-apu -objects += gb-cheat obj/gb-interface.o: gb/interface/interface.cpp $(call rwildcard,gb/interface/) obj/gb-system.o: gb/system/system.cpp $(call rwildcard,gb/system/) -obj/gb-scheduler.o: gb/scheduler/scheduler.cpp $(call rwildcard,gb/scheduler/) obj/gb-cartridge.o: gb/cartridge/cartridge.cpp $(call rwildcard,gb/cartridge/) obj/gb-memory.o: gb/memory/memory.cpp $(call rwildcard,gb/memory/) obj/gb-cpu.o: gb/cpu/cpu.cpp $(call rwildcard,gb/cpu/) obj/gb-ppu.o: gb/ppu/ppu.cpp $(call rwildcard,gb/ppu/) obj/gb-apu.o: gb/apu/apu.cpp $(call rwildcard,gb/apu/) -obj/gb-cheat.o: gb/cheat/cheat.cpp $(call rwildcard,gb/cheat/) diff --git a/higan/gb/cheat/cheat.cpp b/higan/gb/cheat/cheat.cpp deleted file mode 100644 index 4792c867..00000000 --- a/higan/gb/cheat/cheat.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include - -namespace GameBoy { - -Cheat cheat; - -auto Cheat::reset() -> void { - codes.reset(); -} - -auto Cheat::append(uint addr, uint data) -> void { - codes.append({addr, Unused, data}); -} - -auto Cheat::append(uint addr, uint comp, uint data) -> void { - codes.append({addr, comp, data}); -} - -auto Cheat::find(uint addr, uint comp) -> maybe { - for(auto& code : codes) { - if(code.addr == addr && (code.comp == Unused || code.comp == comp)) { - return code.data; - } - } - return nothing; -} - -} diff --git a/higan/gb/cheat/cheat.hpp b/higan/gb/cheat/cheat.hpp deleted file mode 100644 index ee8c1004..00000000 --- a/higan/gb/cheat/cheat.hpp +++ /dev/null @@ -1,18 +0,0 @@ -struct Cheat { - struct Code { - uint addr; - uint comp; - uint data; - }; - vector codes; - enum : uint { Unused = ~0u }; - - alwaysinline auto enable() const -> bool { return codes.size() > 0; } - - auto reset() -> void; - auto append(uint addr, uint data) -> void; - auto append(uint addr, uint comp, uint data) -> void; - auto find(uint addr, uint comp) -> maybe; -}; - -extern Cheat cheat; diff --git a/higan/gb/gb.hpp b/higan/gb/gb.hpp index cdfd5883..9fefc4a0 100644 --- a/higan/gb/gb.hpp +++ b/higan/gb/gb.hpp @@ -4,41 +4,26 @@ //started: 2010-12-27 #include +#include +#include +#include + #include namespace GameBoy { using File = Emulator::File; - - struct Thread { - ~Thread() { - if(thread) co_delete(thread); - } - - auto create(auto (*entrypoint)() -> void, uint frequency) -> void { - if(thread) co_delete(thread); - thread = co_create(65'536 * sizeof(void*), entrypoint); - this->frequency = frequency; - clock = 0; - } - - auto serialize(serializer& s) -> void { - s.integer(frequency); - s.integer(clock); - } - - cothread_t thread = nullptr; - uint frequency = 0; - int64 clock = 0; - }; + using Thread = Emulator::Thread; + using Scheduler = Emulator::Scheduler; + using Cheat = Emulator::Cheat; + extern Scheduler scheduler; + extern Cheat cheat; #include #include - #include #include #include #include #include - #include } #include diff --git a/higan/gb/interface/interface.cpp b/higan/gb/interface/interface.cpp index 80df4046..37694ad4 100644 --- a/higan/gb/interface/interface.cpp +++ b/higan/gb/interface/interface.cpp @@ -163,15 +163,7 @@ auto Interface::unserialize(serializer& s) -> bool { } auto Interface::cheatSet(const string_vector& list) -> void { - cheat.reset(); - for(auto& codeset : list) { - auto codes = codeset.split("+"); - for(auto& code : codes) { - auto part = code.split("/"); - if(part.size() == 2) cheat.append(part[0].hex(), part[1].hex()); - if(part.size() == 3) cheat.append(part[0].hex(), part[1].hex(), part[2].hex()); - } - } + cheat.assign(list); } auto Interface::lcdScanline() -> void { diff --git a/higan/gb/memory/memory.cpp b/higan/gb/memory/memory.cpp index 42c167b5..51ad6adf 100644 --- a/higan/gb/memory/memory.cpp +++ b/higan/gb/memory/memory.cpp @@ -38,7 +38,7 @@ auto Memory::free() -> void { auto Bus::read(uint16 addr) -> uint8 { uint8 data = mmio[addr]->readIO(addr); - if(cheat.enable()) { + if(cheat) { if(auto result = cheat.find(addr, data)) return result(); } diff --git a/higan/gb/scheduler/scheduler.cpp b/higan/gb/scheduler/scheduler.cpp deleted file mode 100644 index a1c88b2f..00000000 --- a/higan/gb/scheduler/scheduler.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include - -namespace GameBoy { - -Scheduler scheduler; - -auto Scheduler::power() -> void { - host = co_active(); - resume = cpu.thread; -} - -auto Scheduler::enter(Mode mode_) -> Event { - mode = mode_; - host = co_active(); - co_switch(resume); - if(event == Event::Frame) ppu.refresh(); - return event; -} - -auto Scheduler::exit(Event event_) -> void { - event = event_; - resume = co_active(); - co_switch(host); -} - -auto Scheduler::synchronize(cothread_t thread) -> void { - if(thread == cpu.thread) { - while(enter(Mode::SynchronizeCPU) != Event::Synchronize); - } else { - resume = thread; - while(enter(Mode::SynchronizeAll) != Event::Synchronize); - } -} - -auto Scheduler::synchronize() -> void { - if(co_active() == cpu.thread && mode == Mode::SynchronizeCPU) return exit(Event::Synchronize); - if(co_active() != cpu.thread && mode == Mode::SynchronizeAll) return exit(Event::Synchronize); -} - -auto Scheduler::synchronizing() const -> bool { - return mode == Mode::SynchronizeAll; -} - -} diff --git a/higan/gb/scheduler/scheduler.hpp b/higan/gb/scheduler/scheduler.hpp deleted file mode 100644 index ea6d289b..00000000 --- a/higan/gb/scheduler/scheduler.hpp +++ /dev/null @@ -1,29 +0,0 @@ -struct Scheduler { - enum class Mode : uint { - Run, - SynchronizeCPU, - SynchronizeAll, - }; - - enum class Event : uint { - Unknown, - Step, - Frame, - Synchronize, - }; - - auto power() -> void; - auto enter(Mode = Mode::Run) -> Event; - auto exit(Event) -> void; - auto synchronize(cothread_t) -> void; - auto synchronize() -> void; - auto synchronizing() const -> bool; - -private: - cothread_t host = nullptr; - cothread_t resume = nullptr; - Mode mode = Mode::Run; - Event event = Event::Unknown; -}; - -extern Scheduler scheduler; diff --git a/higan/gb/system/system.cpp b/higan/gb/system/system.cpp index 9eddbd96..9a2f96f0 100644 --- a/higan/gb/system/system.cpp +++ b/higan/gb/system/system.cpp @@ -5,9 +5,11 @@ namespace GameBoy { #include "video.cpp" #include "serialization.cpp" System system; +Scheduler scheduler; +Cheat cheat; auto System::run() -> void { - scheduler.enter(); + if(scheduler.enter() == Scheduler::Event::Frame) ppu.refresh(); } auto System::runToSave() -> void { @@ -71,7 +73,7 @@ auto System::power() -> void { cpu.power(); ppu.power(); apu.power(); - scheduler.power(); + scheduler.reset(cpu.thread); _clocksExecuted = 0; } diff --git a/higan/gba/GNUmakefile b/higan/gba/GNUmakefile index a47fbcd9..31c9c3e8 100644 --- a/higan/gba/GNUmakefile +++ b/higan/gba/GNUmakefile @@ -1,12 +1,11 @@ processors += arm -objects += gba-memory gba-interface gba-scheduler gba-system +objects += gba-memory gba-interface gba-system objects += gba-cartridge gba-player objects += gba-cpu gba-ppu gba-apu obj/gba-memory.o: gba/memory/memory.cpp $(call rwildcard,gba/memory) obj/gba-interface.o: gba/interface/interface.cpp $(call rwildcard,gba/interface) -obj/gba-scheduler.o: gba/scheduler/scheduler.cpp $(call rwildcard,gba/scheduler) obj/gba-system.o: gba/system/system.cpp $(call rwildcard,gba/system) obj/gba-cartridge.o: gba/cartridge/cartridge.cpp $(call rwildcard,gba/cartridge) obj/gba-player.o: gba/player/player.cpp $(call rwildcard,gba/player) diff --git a/higan/gba/gba.hpp b/higan/gba/gba.hpp index 72844083..296e430c 100644 --- a/higan/gba/gba.hpp +++ b/higan/gba/gba.hpp @@ -4,10 +4,16 @@ //started: 2012-03-19 #include +#include +#include + #include namespace GameBoyAdvance { using File = Emulator::File; + using Thread = Emulator::Thread; + using Scheduler = Emulator::Scheduler; + extern Scheduler scheduler; enum : uint { //mode flags for bus read, write: Nonsequential = 1, //N cycle @@ -21,30 +27,7 @@ namespace GameBoyAdvance { Signed = 256, //sign extended }; - struct Thread { - ~Thread() { - if(thread) co_delete(thread); - } - - auto create(auto (*entrypoint)() -> void, uint frequency) -> void { - if(thread) co_delete(thread); - thread = co_create(65'536 * sizeof(void*), entrypoint); - this->frequency = frequency; - clock = 0; - } - - auto serialize(serializer& s) -> void { - s.integer(frequency); - s.integer(clock); - } - - cothread_t thread = nullptr; - uint frequency = 0; - int clock = 0; - }; - #include - #include #include #include #include diff --git a/higan/gba/scheduler/scheduler.cpp b/higan/gba/scheduler/scheduler.cpp deleted file mode 100644 index 40c4d075..00000000 --- a/higan/gba/scheduler/scheduler.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include - -namespace GameBoyAdvance { - -Scheduler scheduler; - -auto Scheduler::power() -> void { - host = co_active(); - resume = cpu.thread; -} - -auto Scheduler::enter(Mode mode_) -> Event { - mode = mode_; - host = co_active(); - co_switch(resume); - if(event == Event::Frame) ppu.refresh(); - return event; -} - -auto Scheduler::exit(Event event_) -> void { - event = event_; - resume = co_active(); - co_switch(host); -} - -auto Scheduler::synchronize(cothread_t thread) -> void { - if(thread == cpu.thread) { - while(enter(Mode::SynchronizeCPU) != Event::Synchronize); - } else { - resume = thread; - while(enter(Mode::SynchronizeAll) != Event::Synchronize); - } -} - -auto Scheduler::synchronize() -> void { - if(co_active() == cpu.thread && mode == Mode::SynchronizeCPU) return exit(Event::Synchronize); - if(co_active() != cpu.thread && mode == Mode::SynchronizeAll) return exit(Event::Synchronize); -} - -auto Scheduler::synchronizing() const -> bool { - return mode == Mode::SynchronizeAll; -} - -} diff --git a/higan/gba/scheduler/scheduler.hpp b/higan/gba/scheduler/scheduler.hpp deleted file mode 100644 index 76c41e25..00000000 --- a/higan/gba/scheduler/scheduler.hpp +++ /dev/null @@ -1,28 +0,0 @@ -struct Scheduler { - enum class Mode : uint { - Run, - SynchronizeCPU, - SynchronizeAll, - }; - - enum class Event : uint { - Unknown, - Frame, - Synchronize, - }; - - auto power() -> void; - auto enter(Mode = Mode::Run) -> Event; - auto exit(Event) -> void; - auto synchronize(cothread_t) -> void; - auto synchronize() -> void; - auto synchronizing() const -> bool; - -private: - cothread_t host = nullptr; - cothread_t resume = nullptr; - Mode mode = Mode::Run; - Event event = Event::Unknown; -}; - -extern Scheduler scheduler; diff --git a/higan/gba/system/system.cpp b/higan/gba/system/system.cpp index 8fd109a1..baa650e2 100644 --- a/higan/gba/system/system.cpp +++ b/higan/gba/system/system.cpp @@ -7,6 +7,7 @@ namespace GameBoyAdvance { #include "serialization.cpp" BIOS bios; System system; +Scheduler scheduler; auto System::init() -> void { } @@ -29,7 +30,7 @@ auto System::power() -> void { ppu.power(); apu.power(); cartridge.power(); - scheduler.power(); + scheduler.reset(cpu.thread); } auto System::load() -> bool { @@ -61,7 +62,7 @@ auto System::unload() -> void { } auto System::run() -> void { - while(scheduler.enter() != Scheduler::Event::Frame); + if(scheduler.enter() == Scheduler::Event::Frame) ppu.refresh(); } auto System::runToSave() -> void { diff --git a/higan/md/GNUmakefile b/higan/md/GNUmakefile index 11f083d8..01261213 100644 --- a/higan/md/GNUmakefile +++ b/higan/md/GNUmakefile @@ -1,14 +1,14 @@ processors += m68k z80 objects += md-interface -objects += md-cpu md-apu md-vdp md-ym2612 -objects += md-system md-scheduler md-cartridge +objects += md-cpu md-apu md-vdp md-psg md-ym2612 +objects += md-system md-cartridge obj/md-interface.o: md/interface/interface.cpp $(call rwildcard,md/interface) obj/md-cpu.o: md/cpu/cpu.cpp $(call rwildcard,md/cpu) obj/md-apu.o: md/apu/apu.cpp $(call rwildcard,md/apu) obj/md-vdp.o: md/vdp/vdp.cpp $(call rwildcard,md/vdp) +obj/md-psg.o: md/psg/psg.cpp $(call rwildcard,md/psg) obj/md-ym2612.o: md/ym2612/ym2612.cpp $(call rwildcard,md/ym2612) obj/md-system.o: md/system/system.cpp $(call rwildcard,md/system) -obj/md-scheduler.o: md/scheduler/scheduler.cpp $(call rwildcard,md/scheduler) obj/md-cartridge.o: md/cartridge/cartridge.cpp $(call rwildcard,md/cartridge) diff --git a/higan/md/apu/apu.cpp b/higan/md/apu/apu.cpp index af9da5e2..ccf0aa8e 100644 --- a/higan/md/apu/apu.cpp +++ b/higan/md/apu/apu.cpp @@ -4,4 +4,22 @@ namespace MegaDrive { APU apu; +auto APU::Enter() -> void { + while(true) scheduler.synchronize(), apu.main(); +} + +auto APU::main() -> void { + step(frequency); +} + +auto APU::step(uint clocks) -> void { +} + +auto APU::power() -> void { +} + +auto APU::reset() -> void { + create(APU::Enter, system.colorburst()); +} + } diff --git a/higan/md/apu/apu.hpp b/higan/md/apu/apu.hpp index 8826a45b..b9def4e3 100644 --- a/higan/md/apu/apu.hpp +++ b/higan/md/apu/apu.hpp @@ -1,4 +1,12 @@ +//Zilog Z80 + struct APU : Processor::Z80, Thread { + static auto Enter() -> void; + auto main() -> void; + auto step(uint clocks) -> void; + + auto power() -> void; + auto reset() -> void; }; extern APU apu; diff --git a/higan/md/cartridge/cartridge.cpp b/higan/md/cartridge/cartridge.cpp index 220c7657..7ba76cd2 100644 --- a/higan/md/cartridge/cartridge.cpp +++ b/higan/md/cartridge/cartridge.cpp @@ -18,13 +18,50 @@ auto Cartridge::load() -> bool { auto document = BML::unserialize(information.manifest); information.title = document["information/title"].text(); - return false; + if(auto node = document["board/rom"]) { + rom.size = node["size"].natural(); + rom.mask = bit::round(rom.size) - 1; + if(rom.size) { + rom.data = new uint8[rom.mask + 1]; + if(auto name = node["name"].text()) { + if(auto fp = interface->open(pathID(), name, File::Read, File::Required)) { + fp->read(rom.data, rom.size); + } + } + } + } + + if(auto node = document["board/ram"]) { + ram.size = node["size"].natural(); + ram.mask = bit::round(ram.size) - 1; + if(ram.size) { + ram.data = new uint8[ram.mask + 1]; + if(auto name = node["name"].text()) { + if(auto fp = interface->open(pathID(), name, File::Read)) { + fp->read(ram.data, ram.size); + } + } + } + } + + return true; } auto Cartridge::save() -> void { + auto document = BML::unserialize(information.manifest); + + if(auto name = document["board/ram/name"].text()) { + if(auto fp = interface->open(pathID(), name, File::Write)) { + fp->write(ram.data, ram.size); + } + } } auto Cartridge::unload() -> void { + delete[] rom.data; + delete[] ram.data; + rom = Memory(); + ram = Memory(); } auto Cartridge::power() -> void { @@ -33,4 +70,11 @@ auto Cartridge::power() -> void { auto Cartridge::reset() -> void { } +auto Cartridge::read(uint24 addr) -> uint8 { + return rom.data[addr & rom.mask]; +} + +auto Cartridge::write(uint24 addr, uint8 data) -> void { +} + } diff --git a/higan/md/cartridge/cartridge.hpp b/higan/md/cartridge/cartridge.hpp index 31b5aada..efdb400d 100644 --- a/higan/md/cartridge/cartridge.hpp +++ b/higan/md/cartridge/cartridge.hpp @@ -10,12 +10,24 @@ struct Cartridge { auto power() -> void; auto reset() -> void; + auto read(uint24 addr) -> uint8; + auto write(uint24 addr, uint8 data) -> void; + struct Information { uint pathID = 0; string sha256; string manifest; string title; } information; + + struct Memory { + uint8* data = nullptr; + uint size = 0; + uint mask = 0; + }; + + Memory rom; + Memory ram; }; extern Cartridge cartridge; diff --git a/higan/md/cpu/cpu.cpp b/higan/md/cpu/cpu.cpp index f37a27cd..41142d61 100644 --- a/higan/md/cpu/cpu.cpp +++ b/higan/md/cpu/cpu.cpp @@ -4,4 +4,48 @@ namespace MegaDrive { CPU cpu; +auto CPU::Enter() -> void { + cpu.boot(); + while(true) scheduler.synchronize(), cpu.main(); +} + +auto CPU::boot() -> void { + r.sp = readLong(0); + r.pc = readLong(4); +} + +auto CPU::main() -> void { + instruction(); +} + +auto CPU::step(uint clocks) -> void { + clock += clocks; + while(clock >= frequency) { + clock -= frequency; + scheduler.exit(Scheduler::Event::Frame); + } +} + +auto CPU::power() -> void { + M68K::power(); +} + +auto CPU::reset() -> void { + M68K::reset(); + create(CPU::Enter, system.colorburst() * 15.0 / 7.0); +} + +auto CPU::read(uint32 addr) -> uint8 { + addr = (uint24)addr; + + if(addr < 0x400000) return cartridge.read(addr); + return 0x00; +} + +auto CPU::write(uint32 addr, uint8 data) -> void { + addr = (uint24)addr; + + if(addr < 0x400000) return cartridge.write(addr, data); +} + } diff --git a/higan/md/cpu/cpu.hpp b/higan/md/cpu/cpu.hpp index 938a423d..b2f099c7 100644 --- a/higan/md/cpu/cpu.hpp +++ b/higan/md/cpu/cpu.hpp @@ -1,4 +1,16 @@ +//Motorola 68000 + struct CPU : Processor::M68K, Thread { + static auto Enter() -> void; + auto boot() -> void; + auto main() -> void; + auto step(uint clocks) -> void override; + + auto power() -> void; + auto reset() -> void; + + auto read(uint32 addr) -> uint8 override; + auto write(uint32 addr, uint8 data) -> void override; }; extern CPU cpu; diff --git a/higan/md/interface/interface.cpp b/higan/md/interface/interface.cpp index 0fc8317f..4720d3e0 100644 --- a/higan/md/interface/interface.cpp +++ b/higan/md/interface/interface.cpp @@ -81,8 +81,7 @@ auto Interface::loaded() -> bool { } auto Interface::load(uint id) -> bool { - system.load(); - return false; + return system.load(); } auto Interface::save() -> void { diff --git a/higan/md/md.hpp b/higan/md/md.hpp index 20b06b6e..a361d2ab 100644 --- a/higan/md/md.hpp +++ b/higan/md/md.hpp @@ -4,41 +4,25 @@ //started: 2016-07-08 #include +#include +#include + #include #include namespace MegaDrive { using File = Emulator::File; - - struct Thread { - ~Thread() { - if(thread) co_delete(thread); - } - - auto create(auto (*entrypoint)() -> void, uint frequency) -> void { - if(thread) co_delete(thread); - thread = co_create(65'536 * sizeof(void*), entrypoint); - this->frequency = frequency; - clock = 0; - } - - auto serialize(serializer& s) -> void { - s.integer(frequency); - s.integer(clock); - } - - cothread_t thread = nullptr; - uint frequency = 0; - int64 clock = 0; - }; + using Thread = Emulator::Thread; + using Scheduler = Emulator::Scheduler; + extern Scheduler scheduler; #include #include #include + #include #include #include - #include #include } diff --git a/higan/md/psg/psg.cpp b/higan/md/psg/psg.cpp new file mode 100644 index 00000000..9dc14fcd --- /dev/null +++ b/higan/md/psg/psg.cpp @@ -0,0 +1,25 @@ +#include + +namespace MegaDrive { + +PSG psg; + +auto PSG::Enter() -> void { + while(true) scheduler.synchronize(), psg.main(); +} + +auto PSG::main() -> void { + step(frequency); +} + +auto PSG::step(uint clocks) -> void { +} + +auto PSG::power() -> void { +} + +auto PSG::reset() -> void { + create(PSG::Enter, system.colorburst()); +} + +} diff --git a/higan/md/psg/psg.hpp b/higan/md/psg/psg.hpp new file mode 100644 index 00000000..f9d20933 --- /dev/null +++ b/higan/md/psg/psg.hpp @@ -0,0 +1,12 @@ +//TI SN76489 + +struct PSG : Thread { + static auto Enter() -> void; + auto main() -> void; + auto step(uint clocks) -> void; + + auto power() -> void; + auto reset() -> void; +}; + +extern PSG psg; diff --git a/higan/md/scheduler/scheduler.cpp b/higan/md/scheduler/scheduler.cpp deleted file mode 100644 index 64025895..00000000 --- a/higan/md/scheduler/scheduler.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include - -namespace MegaDrive { - -Scheduler scheduler; - -} diff --git a/higan/md/scheduler/scheduler.hpp b/higan/md/scheduler/scheduler.hpp deleted file mode 100644 index 40553d4d..00000000 --- a/higan/md/scheduler/scheduler.hpp +++ /dev/null @@ -1,4 +0,0 @@ -struct Scheduler { -}; - -extern Scheduler scheduler; diff --git a/higan/md/system/system.cpp b/higan/md/system/system.cpp index 8daf5656..92eb06c6 100644 --- a/higan/md/system/system.cpp +++ b/higan/md/system/system.cpp @@ -3,8 +3,13 @@ namespace MegaDrive { System system; +Scheduler scheduler; auto System::run() -> void { + if(scheduler.enter() == Scheduler::Event::Frame) { + static uint32 output[1280 * 480] = {0}; + Emulator::video.refresh(output, 1280 * sizeof(uint32), 1280, 480); + } } auto System::load() -> bool { @@ -14,6 +19,7 @@ auto System::load() -> bool { } else return false; auto document = BML::unserialize(information.manifest); if(!cartridge.load()) return false; + information.colorburst = Emulator::Constants::Colorburst::NTSC; return information.loaded = true; } @@ -27,11 +33,29 @@ auto System::unload() -> void { auto System::power() -> void { cartridge.power(); + cpu.power(); + apu.power(); + vdp.power(); + psg.power(); + ym2612.power(); reset(); } auto System::reset() -> void { + Emulator::video.reset(); + Emulator::video.setInterface(interface); + Emulator::video.setPalette(); + + Emulator::audio.reset(); + Emulator::audio.setInterface(interface); + cartridge.reset(); + cpu.reset(); + apu.reset(); + vdp.reset(); + psg.reset(); + ym2612.reset(); + scheduler.reset(cpu.thread); } } diff --git a/higan/md/system/system.hpp b/higan/md/system/system.hpp index 4e6a5c3c..2a406015 100644 --- a/higan/md/system/system.hpp +++ b/higan/md/system/system.hpp @@ -1,5 +1,6 @@ struct System { - auto loaded() const { return information.manifest; } + auto loaded() const -> bool { return information.loaded; } + auto colorburst() const -> double { return information.colorburst; } auto run() -> void; @@ -12,6 +13,7 @@ struct System { struct Information { bool loaded = false; string manifest; + double colorburst = 0.0; } information; }; diff --git a/higan/md/vdp/vdp.cpp b/higan/md/vdp/vdp.cpp index 0ad16e26..d3bfd8fc 100644 --- a/higan/md/vdp/vdp.cpp +++ b/higan/md/vdp/vdp.cpp @@ -1,7 +1,28 @@ #include +//256-width = colorburst * 15 / 10 +//320-width = colorburst * 15 / 8 + namespace MegaDrive { VDP vdp; +auto VDP::Enter() -> void { + while(true) scheduler.synchronize(), vdp.main(); +} + +auto VDP::main() -> void { + step(frequency); +} + +auto VDP::step(uint clocks) -> void { +} + +auto VDP::power() -> void { +} + +auto VDP::reset() -> void { + create(VDP::Enter, system.colorburst() * 15.0 / 10.0); +} + } diff --git a/higan/md/vdp/vdp.hpp b/higan/md/vdp/vdp.hpp index 1e50b73d..d8d0e404 100644 --- a/higan/md/vdp/vdp.hpp +++ b/higan/md/vdp/vdp.hpp @@ -1,4 +1,12 @@ +//Yamaha YM7101 + struct VDP : Thread { + static auto Enter() -> void; + auto main() -> void; + auto step(uint clocks) -> void; + + auto power() -> void; + auto reset() -> void; }; extern VDP vdp; diff --git a/higan/md/ym2612/ym2612.cpp b/higan/md/ym2612/ym2612.cpp index 245ec448..f21e6c28 100644 --- a/higan/md/ym2612/ym2612.cpp +++ b/higan/md/ym2612/ym2612.cpp @@ -4,4 +4,22 @@ namespace MegaDrive { YM2612 ym2612; +auto YM2612::Enter() -> void { + while(true) scheduler.synchronize(), ym2612.main(); +} + +auto YM2612::main() -> void { + step(frequency); +} + +auto YM2612::step(uint clocks) -> void { +} + +auto YM2612::power() -> void { +} + +auto YM2612::reset() -> void { + create(YM2612::Enter, system.colorburst() * 15.0 / 7.0); +} + } diff --git a/higan/md/ym2612/ym2612.hpp b/higan/md/ym2612/ym2612.hpp index 3cfa4278..e77161b8 100644 --- a/higan/md/ym2612/ym2612.hpp +++ b/higan/md/ym2612/ym2612.hpp @@ -1,6 +1,12 @@ //Yamaha YM2612 struct YM2612 : Thread { + static auto Enter() -> void; + auto main() -> void; + auto step(uint clocks) -> void; + + auto power() -> void; + auto reset() -> void; }; extern YM2612 ym2612; diff --git a/higan/processor/GNUmakefile b/higan/processor/GNUmakefile index e2487a13..2aaa74f7 100644 --- a/higan/processor/GNUmakefile +++ b/higan/processor/GNUmakefile @@ -22,4 +22,4 @@ obj/processor-r65816.o: processor/r65816/r65816.cpp $(call rwildcard,processor obj/processor-spc700.o: processor/spc700/spc700.cpp $(call rwildcard,processor/spc700) obj/processor-upd96050.o: processor/upd96050/upd96050.cpp $(call rwildcard,processor/upd96050) obj/processor-v30mz.o: processor/v30mz/v30mz.cpp $(call rwildcard,processor/v30mz) -obj/processor-z80.o: processor/z80/z80.cpp $(call rwildcard,z80) +obj/processor-z80.o: processor/z80/z80.cpp $(call rwildcard,processor/z80) diff --git a/higan/processor/m68k/m68k.cpp b/higan/processor/m68k/m68k.cpp index eff7b0d0..c170ae94 100644 --- a/higan/processor/m68k/m68k.cpp +++ b/higan/processor/m68k/m68k.cpp @@ -3,4 +3,46 @@ namespace Processor { +#include "memory.cpp" + +auto M68K::instruction() -> void { + instructionsExecuted++; + + auto opcode = readWord(r.pc); + r.pc += 2; + + //nop + if(opcode == 0x4e71) { + step(5); + return; + } + + //bra disp + if((opcode & 0xff00) == 0x6000) { + int displacement = (int8)opcode; + if(!displacement) displacement = (int16)readWord(r.pc); + r.pc += displacement; + step(12); + return; + } + + instructionsExecuted--; + r.pc -= 2; + print("[M68K] unimplemented instruction: ", hex(r.pc, 6L), " = ", hex(opcode, 4L), "\n"); + print("[M68K] executed ", instructionsExecuted, " instructions\n"); + while(true) step(5); +} + +auto M68K::power() -> void { +} + +auto M68K::reset() -> void { + instructionsExecuted = 0; + + for(auto& n : r.d) n = 0; + for(auto& n : r.a) n = 0; + r.pc = 0x000200; + r.ccr.value = 0; +} + } diff --git a/higan/processor/m68k/m68k.hpp b/higan/processor/m68k/m68k.hpp index 0f62df17..8fb2f87e 100644 --- a/higan/processor/m68k/m68k.hpp +++ b/higan/processor/m68k/m68k.hpp @@ -5,6 +5,42 @@ namespace Processor { struct M68K { + virtual auto step(uint clocks) -> void = 0; + virtual auto read(uint32 addr) -> uint8 = 0; + virtual auto write(uint32 addr, uint8 data) -> void = 0; + + auto power() -> void; + auto reset() -> void; + auto instruction() -> void; + + //memory.cpp + auto readByte(uint32 addr) -> uint8; + auto readWord(uint32 addr) -> uint16; + auto readLong(uint32 addr) -> uint32; + auto readQuad(uint32 addr) -> uint64; + + struct Registers { + //todo: this is almost certainly UB or IB due to alignment rules ... + union { + uint32_t d[8]; + struct { uint32_t d0, d1, d2, d3, d4, d5, d6, d7; }; + }; + union { + uint32_t a[8]; + struct { uint32_t a0, a1, a2, a3, a4, a5, a6; union { uint32_t a7, sp; }; }; + }; + uint32 pc; + union CCR { + uint8_t value = 0; + BooleanBitField c; //carry + BooleanBitField v; //overflow + BooleanBitField z; //zero + BooleanBitField n; //negative + BooleanBitField x; //extend + } ccr; + } r; + + uint instructionsExecuted = 0; }; } diff --git a/higan/processor/m68k/memory.cpp b/higan/processor/m68k/memory.cpp new file mode 100644 index 00000000..ff174f86 --- /dev/null +++ b/higan/processor/m68k/memory.cpp @@ -0,0 +1,32 @@ +auto M68K::readByte(uint32 addr) -> uint8 { + return read(addr); +} + +auto M68K::readWord(uint32 addr) -> uint16 { + uint16 data; + data |= read(addr + 0) << 8; + data |= read(addr + 1) << 0; + return data; +} + +auto M68K::readLong(uint32 addr) -> uint32 { + uint32 data; + data |= read(addr + 0) << 24; + data |= read(addr + 1) << 16; + data |= read(addr + 2) << 8; + data |= read(addr + 3) << 0; + return data; +} + +auto M68K::readQuad(uint32 addr) -> uint64 { + uint64 data; + data |= (uint64)read(addr + 0) << 56; + data |= (uint64)read(addr + 1) << 48; + data |= (uint64)read(addr + 2) << 40; + data |= (uint64)read(addr + 3) << 32; + data |= (uint64)read(addr + 4) << 24; + data |= (uint64)read(addr + 5) << 16; + data |= (uint64)read(addr + 6) << 8; + data |= (uint64)read(addr + 7) << 0; + return data; +} diff --git a/higan/sfc/GNUmakefile b/higan/sfc/GNUmakefile index 92b02600..a47a9734 100644 --- a/higan/sfc/GNUmakefile +++ b/higan/sfc/GNUmakefile @@ -1,8 +1,8 @@ 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-interface sfc-system sfc-controller +objects += sfc-cartridge sfc-memory +objects += sfc-cpu sfc-smp sfc-dsp sfc-ppu objects += sfc-expansion sfc-satellaview sfc-superdisc objects += sfc-21fx objects += sfc-icd2 sfc-mcc sfc-nss sfc-event @@ -15,10 +15,8 @@ objects += sfc-bsmemory sfc-sufamiturbo obj/sfc-interface.o: sfc/interface/interface.cpp $(call rwildcard,sfc/interface) obj/sfc-system.o: sfc/system/system.cpp $(call rwildcard,sfc/system/) -obj/sfc-scheduler.o: sfc/scheduler/scheduler.cpp $(call rwildcard,sfc/scheduler/) obj/sfc-controller.o: sfc/controller/controller.cpp $(call rwildcard,sfc/controller/) obj/sfc-cartridge.o: sfc/cartridge/cartridge.cpp $(call rwildcard,sfc/cartridge/) -obj/sfc-cheat.o: sfc/cheat/cheat.cpp $(call rwildcard,sfc/cheat/) obj/sfc-memory.o: sfc/memory/memory.cpp $(call rwildcard,sfc/memory/) obj/sfc-cpu.o: sfc/cpu/cpu.cpp $(call rwildcard,sfc/cpu/) diff --git a/higan/sfc/cheat/cheat.cpp b/higan/sfc/cheat/cheat.cpp deleted file mode 100644 index 5263695d..00000000 --- a/higan/sfc/cheat/cheat.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include - -namespace SuperFamicom { - -Cheat cheat; - -auto Cheat::reset() -> void { - codes.reset(); -} - -auto Cheat::append(uint addr, uint data) -> void { - codes.append({addr, Unused, data}); -} - -auto Cheat::append(uint addr, uint comp, uint data) -> void { - codes.append({addr, comp, data}); -} - -auto Cheat::find(uint addr, uint comp) -> maybe { - //WRAM mirroring: $00-3f,80-bf:0000-1fff -> $7e:0000-1fff - if((addr & 0x40e000) == 0x000000) addr = 0x7e0000 | (addr & 0x1fff); - - for(auto& code : codes) { - if(code.addr == addr && (code.comp == Unused || code.comp == comp)) { - return code.data; - } - } - - return nothing; -} - -} diff --git a/higan/sfc/cheat/cheat.hpp b/higan/sfc/cheat/cheat.hpp deleted file mode 100644 index 0c4bddd3..00000000 --- a/higan/sfc/cheat/cheat.hpp +++ /dev/null @@ -1,19 +0,0 @@ -struct Cheat { - enum : uint { Unused = ~0u }; - - alwaysinline auto enable() const -> bool { return codes.size() > 0; } - - auto reset() -> void; - auto append(uint addr, uint data) -> void; - auto append(uint addr, uint comp, uint data) -> void; - auto find(uint addr, uint comp) -> maybe; - - struct Code { - uint addr; - uint comp; - uint data; - }; - vector codes; -}; - -extern Cheat cheat; diff --git a/higan/sfc/coprocessor/sa1/sa1.cpp b/higan/sfc/coprocessor/sa1/sa1.cpp index 79b33345..e4bcb688 100644 --- a/higan/sfc/coprocessor/sa1/sa1.cpp +++ b/higan/sfc/coprocessor/sa1/sa1.cpp @@ -117,7 +117,7 @@ auto SA1::power() -> void { } auto SA1::reset() -> void { - create(SA1::Enter, system.cpuFrequency()); + create(SA1::Enter, system.colorburst() * 6.0); cpubwram.dma = false; for(auto addr : range(iram.size())) { diff --git a/higan/sfc/coprocessor/superfx/superfx.cpp b/higan/sfc/coprocessor/superfx/superfx.cpp index d0b46ac3..ab961162 100644 --- a/higan/sfc/coprocessor/superfx/superfx.cpp +++ b/higan/sfc/coprocessor/superfx/superfx.cpp @@ -48,7 +48,7 @@ auto SuperFX::power() -> void { auto SuperFX::reset() -> void { GSU::reset(); - create(SuperFX::Enter, system.cpuFrequency()); + create(SuperFX::Enter, system.colorburst() * 6.0); romMask = rom.size() - 1; ramMask = ram.size() - 1; diff --git a/higan/sfc/cpu/cpu.cpp b/higan/sfc/cpu/cpu.cpp index 1358ac2b..c2c9899f 100644 --- a/higan/sfc/cpu/cpu.cpp +++ b/higan/sfc/cpu/cpu.cpp @@ -114,7 +114,7 @@ auto CPU::power() -> void { } auto CPU::reset() -> void { - create(Enter, system.cpuFrequency()); + create(Enter, system.colorburst() * 6.0); coprocessors.reset(); PPUcounter::reset(); diff --git a/higan/sfc/dsp/dsp.cpp b/higan/sfc/dsp/dsp.cpp index 3356e4b4..018c11d6 100644 --- a/higan/sfc/dsp/dsp.cpp +++ b/higan/sfc/dsp/dsp.cpp @@ -244,8 +244,8 @@ auto DSP::power() -> void { } auto DSP::reset() -> void { - create(Enter, system.apuFrequency()); - stream = Emulator::audio.createStream(2, system.apuFrequency() / 768.0); + create(Enter, 32040.0 * 768.0); + stream = Emulator::audio.createStream(2, 32040.0); REG(FLG) = 0xe0; state.noise = 0x4000; diff --git a/higan/sfc/interface/interface.cpp b/higan/sfc/interface/interface.cpp index ef64804c..84ea2f48 100644 --- a/higan/sfc/interface/interface.cpp +++ b/higan/sfc/interface/interface.cpp @@ -134,8 +134,8 @@ auto Interface::title() -> string { auto Interface::videoFrequency() -> double { switch(system.region()) { default: - case System::Region::NTSC: return system.cpuFrequency() / (262.0 * 1364.0 - 4.0); - case System::Region::PAL: return system.cpuFrequency() / (312.0 * 1364.0); + case System::Region::NTSC: return (system.colorburst() * 6.0) / (262.0 * 1364.0 - 4.0); + case System::Region::PAL: return (system.colorburst() * 6.0) / (312.0 * 1364.0); } } @@ -170,7 +170,7 @@ auto Interface::videoColor(uint32 color) -> uint64 { } auto Interface::audioFrequency() -> double { - return system.apuFrequency() / 768.0; + return 32040.0; } auto Interface::loaded() -> bool { @@ -236,30 +236,10 @@ auto Interface::unserialize(serializer& s) -> bool { auto Interface::cheatSet(const string_vector& list) -> void { cheat.reset(); - #if defined(SFC_SUPERGAMEBOY) - if(cartridge.has.ICD2) { - GameBoy::cheat.reset(); - for(auto& codeset : list) { - auto codes = codeset.split("+"); - for(auto& code : codes) { - auto part = code.split("/"); - if(part.size() == 2) GameBoy::cheat.append(part[0].hex(), part[1].hex()); - if(part.size() == 3) GameBoy::cheat.append(part[0].hex(), part[1].hex(), part[2].hex()); - } - } - return; - } + if(cartridge.has.ICD2) return GameBoy::cheat.assign(list); #endif - - for(auto& codeset : list) { - auto codes = codeset.split("+"); - for(auto& code : codes) { - auto part = code.split("/"); - if(part.size() == 2) cheat.append(part[0].hex(), part[1].hex()); - if(part.size() == 3) cheat.append(part[0].hex(), part[1].hex(), part[2].hex()); - } - } + cheat.assign(list); } auto Interface::cap(const string& name) -> bool { diff --git a/higan/sfc/memory/memory-inline.hpp b/higan/sfc/memory/memory-inline.hpp index f4127fff..92387c1e 100644 --- a/higan/sfc/memory/memory-inline.hpp +++ b/higan/sfc/memory/memory-inline.hpp @@ -67,7 +67,8 @@ auto Bus::reduce(uint addr, uint mask) -> uint { auto Bus::read(uint24 addr, uint8 data) -> uint8 { data = reader[lookup[addr]](target[addr], data); - if(cheat.enable()) { + if(cheat) { + if(!(addr & 0x40e000)) addr = 0x7e0000 | (addr & 0x1fff); //de-mirror WRAM if(auto result = cheat.find(addr, data)) return result(); } return data; diff --git a/higan/sfc/ppu/ppu.cpp b/higan/sfc/ppu/ppu.cpp index 41a94aaa..ce71bd08 100644 --- a/higan/sfc/ppu/ppu.cpp +++ b/higan/sfc/ppu/ppu.cpp @@ -95,7 +95,7 @@ auto PPU::power() -> void { } auto PPU::reset() -> void { - create(Enter, system.cpuFrequency()); + create(Enter, system.colorburst() * 6.0); PPUcounter::reset(); memory::fill(output, 512 * 480 * sizeof(uint32)); diff --git a/higan/sfc/ppu/ppu.hpp b/higan/sfc/ppu/ppu.hpp index 16fb631d..4ce4cb77 100644 --- a/higan/sfc/ppu/ppu.hpp +++ b/higan/sfc/ppu/ppu.hpp @@ -154,7 +154,7 @@ privileged: friend class PPU::Object; friend class PPU::Window; friend class PPU::Screen; - friend class Scheduler; + friend class System; }; extern PPU ppu; diff --git a/higan/sfc/scheduler/scheduler.cpp b/higan/sfc/scheduler/scheduler.cpp deleted file mode 100644 index b02987c2..00000000 --- a/higan/sfc/scheduler/scheduler.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include - -namespace SuperFamicom { - -Scheduler scheduler; - -auto Scheduler::reset() -> void { - host = co_active(); - resume = cpu.thread; -} - -auto Scheduler::enter(Mode mode_) -> Event { - mode = mode_; - host = co_active(); - co_switch(resume); - if(event == Event::Frame) ppu.refresh(); - return event; -} - -auto Scheduler::exit(Event event_) -> void { - event = event_; - resume = co_active(); - co_switch(host); -} - -auto Scheduler::synchronize(cothread_t thread) -> void { - if(thread == cpu.thread) { - while(enter(Mode::SynchronizeCPU) != Event::Synchronize); - } else { - resume = thread; - while(enter(Mode::SynchronizeAll) != Event::Synchronize); - } -} - -auto Scheduler::synchronize() -> void { - if(co_active() == cpu.thread && mode == Mode::SynchronizeCPU) return exit(Event::Synchronize); - if(co_active() != cpu.thread && mode == Mode::SynchronizeAll) return exit(Event::Synchronize); -} - -auto Scheduler::synchronizing() const -> bool { - return mode == Mode::SynchronizeAll; -} - -} diff --git a/higan/sfc/scheduler/scheduler.hpp b/higan/sfc/scheduler/scheduler.hpp deleted file mode 100644 index e53dcf1e..00000000 --- a/higan/sfc/scheduler/scheduler.hpp +++ /dev/null @@ -1,29 +0,0 @@ -struct Scheduler { - enum class Mode : uint { - Run, - SynchronizeCPU, - SynchronizeAll, - }; - - enum class Event : uint { - Unknown, - Frame, - Synchronize, - Debugger, - }; - - auto reset() -> void; - auto enter(Mode = Mode::Run) -> Event; - auto exit(Event) -> void; - auto synchronize(cothread_t) -> void; - auto synchronize() -> void; - auto synchronizing() const -> bool; - -private: - cothread_t host = nullptr; //program thread (used to exit emulation) - cothread_t resume = nullptr; //resume thread (used to re-enter emulation) - Mode mode = Mode::Run; //determines when to exit emulation thread - Event event = Event::Unknown; //set by exit(), returned by enter() -}; - -extern Scheduler scheduler; diff --git a/higan/sfc/sfc.hpp b/higan/sfc/sfc.hpp index 247d9d17..15ccb6fd 100644 --- a/higan/sfc/sfc.hpp +++ b/higan/sfc/sfc.hpp @@ -4,6 +4,10 @@ //started: 2004-10-14 #include +#include +#include +#include + #include #include #include @@ -17,28 +21,11 @@ namespace SuperFamicom { using File = Emulator::File; - - struct Thread { - virtual ~Thread() { - if(thread) co_delete(thread); - } - - auto create(auto (*entrypoint)() -> void, uint frequency) -> void { - if(thread) co_delete(thread); - thread = co_create(65'536 * sizeof(void*), entrypoint); - this->frequency = frequency; - clock = 0; - } - - auto serialize(serializer& s) -> void { - s.integer(frequency); - s.integer(clock); - } - - cothread_t thread = nullptr; - uint frequency = 0; - int64 clock = 0; - }; + using Thread = Emulator::Thread; + using Scheduler = Emulator::Scheduler; + using Cheat = Emulator::Cheat; + extern Scheduler scheduler; + extern Cheat cheat; //dynamic thread bound to CPU (coprocessors and peripherals) struct Cothread : Thread { @@ -57,11 +44,9 @@ namespace SuperFamicom { #include #include #include - #include #include #include #include - #include #include #include diff --git a/higan/sfc/smp/smp.cpp b/higan/sfc/smp/smp.cpp index 77a193ad..fde01f4b 100644 --- a/higan/sfc/smp/smp.cpp +++ b/higan/sfc/smp/smp.cpp @@ -43,7 +43,7 @@ auto SMP::power() -> void { } auto SMP::reset() -> void { - create(Enter, system.apuFrequency()); + create(Enter, 32040.0 * 768.0); regs.pc.l = iplrom[62]; regs.pc.h = iplrom[63]; diff --git a/higan/sfc/system/system.cpp b/higan/sfc/system/system.cpp index 8ae4048f..229085a6 100644 --- a/higan/sfc/system/system.cpp +++ b/higan/sfc/system/system.cpp @@ -3,14 +3,15 @@ namespace SuperFamicom { System system; - +Scheduler scheduler; +Cheat cheat; #include "video.cpp" #include "peripherals.cpp" #include "random.cpp" #include "serialization.cpp" auto System::run() -> void { - scheduler.enter(); + if(scheduler.enter() == Scheduler::Event::Frame) ppu.refresh(); } auto System::runToSave() -> void { @@ -72,8 +73,9 @@ auto System::load() -> bool { if(system["region"].text() == "NTSC") information.region = Region::NTSC; if(system["region"].text() == "PAL" ) information.region = Region::PAL; - information.cpuFrequency = region() == Region::NTSC ? 21'477'272 : 21'281'370; - information.apuFrequency = 24'606'720; + information.colorburst = region() == Region::NTSC + ? Emulator::Constants::Colorburst::NTSC + : Emulator::Constants::Colorburst::PAL * 4.0 / 5.0; if(cartridge.has.ICD2) icd2.load(); if(cartridge.has.MCC) mcc.load(); @@ -203,7 +205,7 @@ auto System::reset() -> void { if(cartridge.has.SPC7110) cpu.coprocessors.append(&spc7110); if(cartridge.has.MSU1) cpu.coprocessors.append(&msu1); - scheduler.reset(); + scheduler.reset(cpu.thread); peripherals.reset(); } diff --git a/higan/sfc/system/system.hpp b/higan/sfc/system/system.hpp index 10db0eb4..26809de9 100644 --- a/higan/sfc/system/system.hpp +++ b/higan/sfc/system/system.hpp @@ -5,8 +5,7 @@ struct System { inline auto loaded() const -> bool { return information.loaded; } inline auto region() const -> Region { return information.region; } - inline auto cpuFrequency() const -> uint { return information.cpuFrequency; } - inline auto apuFrequency() const -> uint { return information.apuFrequency; } + inline auto colorburst() const -> double { return information.colorburst; } auto run() -> void; auto runToSave() -> void; @@ -32,8 +31,7 @@ private: string manifest; bool loaded = false; Region region = Region::NTSC; - uint cpuFrequency = 0; - uint apuFrequency = 0; + double colorburst = 0.0; } information; uint serializeSize = 0; diff --git a/higan/ws/GNUmakefile b/higan/ws/GNUmakefile index ff48dfa7..3308351f 100644 --- a/higan/ws/GNUmakefile +++ b/higan/ws/GNUmakefile @@ -1,17 +1,14 @@ processors += v30mz -objects += ws-interface ws-system ws-scheduler +objects += ws-interface ws-system objects += ws-memory ws-eeprom ws-cartridge objects += ws-cpu ws-ppu ws-apu -objects += ws-cheat obj/ws-interface.o: ws/interface/interface.cpp $(call rwildcard,ws/interface/) obj/ws-system.o: ws/system/system.cpp $(call rwildcard,ws/system/) -obj/ws-scheduler.o: ws/scheduler/scheduler.cpp $(call rwildcard,ws/scheduler/) obj/ws-memory.o: ws/memory/memory.cpp $(call rwildcard,ws/memory/) obj/ws-eeprom.o: ws/eeprom/eeprom.cpp $(call rwildcard,ws/eeprom/) obj/ws-cartridge.o: ws/cartridge/cartridge.cpp $(call rwildcard,ws/cartridge/) obj/ws-cpu.o: ws/cpu/cpu.cpp $(call rwildcard,ws/cpu/) obj/ws-ppu.o: ws/ppu/ppu.cpp $(call rwildcard,ws/ppu/) obj/ws-apu.o: ws/apu/apu.cpp $(call rwildcard,ws/apu/) -obj/ws-cheat.o: ws/cheat/cheat.cpp $(call rwildcard,ws/cheat/) diff --git a/higan/ws/cheat/cheat.cpp b/higan/ws/cheat/cheat.cpp deleted file mode 100644 index bb80f0e5..00000000 --- a/higan/ws/cheat/cheat.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include - -namespace WonderSwan { - -Cheat cheat; - -auto Cheat::reset() -> void { - codes.reset(); -} - -auto Cheat::append(uint addr, uint data) -> void { - codes.append({addr, Unused, data}); -} - -auto Cheat::append(uint addr, uint comp, uint data) -> void { - codes.append({addr, comp, data}); -} - -auto Cheat::find(uint addr, uint comp) -> maybe { - for(auto& code : codes) { - if(code.addr == addr && (code.comp == Unused || code.comp == comp)) { - return code.data; - } - } - return nothing; -} - -} diff --git a/higan/ws/cheat/cheat.hpp b/higan/ws/cheat/cheat.hpp deleted file mode 100644 index ee8c1004..00000000 --- a/higan/ws/cheat/cheat.hpp +++ /dev/null @@ -1,18 +0,0 @@ -struct Cheat { - struct Code { - uint addr; - uint comp; - uint data; - }; - vector codes; - enum : uint { Unused = ~0u }; - - alwaysinline auto enable() const -> bool { return codes.size() > 0; } - - auto reset() -> void; - auto append(uint addr, uint data) -> void; - auto append(uint addr, uint comp, uint data) -> void; - auto find(uint addr, uint comp) -> maybe; -}; - -extern Cheat cheat; diff --git a/higan/ws/interface/interface.cpp b/higan/ws/interface/interface.cpp index 4932998d..d08a5695 100644 --- a/higan/ws/interface/interface.cpp +++ b/higan/ws/interface/interface.cpp @@ -128,15 +128,7 @@ auto Interface::unserialize(serializer& s) -> bool { } auto Interface::cheatSet(const string_vector& list) -> void { - cheat.reset(); - for(auto& codeset : list) { - auto codes = codeset.split("+"); - for(auto& code : codes) { - auto part = code.split("/"); - if(part.size() == 2) cheat.append(part[0].hex(), part[1].hex()); - if(part.size() == 3) cheat.append(part[0].hex(), part[1].hex(), part[2].hex()); - } - } + cheat.assign(list); } auto Interface::cap(const string& name) -> bool { diff --git a/higan/ws/memory/memory.cpp b/higan/ws/memory/memory.cpp index 6e5f3604..9c402a56 100644 --- a/higan/ws/memory/memory.cpp +++ b/higan/ws/memory/memory.cpp @@ -35,7 +35,7 @@ auto Bus::read(uint20 addr) -> uint8 { if(addr.bits(16,19) == 0) data = iram.read(addr); if(addr.bits(16,19) == 1) data = cartridge.ramRead(addr); if(addr.bits(16,19) >= 2) data = cartridge.romRead(addr); - if(cheat.enable()) { + if(cheat) { if(auto result = cheat.find(addr, data)) data = result(); } return data; diff --git a/higan/ws/scheduler/scheduler.cpp b/higan/ws/scheduler/scheduler.cpp deleted file mode 100644 index a8ff677b..00000000 --- a/higan/ws/scheduler/scheduler.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include - -namespace WonderSwan { - -Scheduler scheduler; - -auto Scheduler::power() -> void { - host = co_active(); - resume = cpu.thread; -} - -auto Scheduler::enter(Mode mode_) -> Event { - mode = mode_; - host = co_active(); - co_switch(resume); - if(event == Event::Frame) ppu.refresh(); - return event; -} - -auto Scheduler::exit(Event event_) -> void { - event = event_; - resume = co_active(); - co_switch(host); -} - -auto Scheduler::synchronize(cothread_t thread) -> void { - if(thread == cpu.thread) { - while(enter(Mode::SynchronizeCPU) != Event::Synchronize); - } else { - resume = thread; - while(enter(Mode::SynchronizeAll) != Event::Synchronize); - } -} - -auto Scheduler::synchronize() -> void { - if(co_active() == cpu.thread && mode == Mode::SynchronizeCPU) return exit(Event::Synchronize); - if(co_active() != cpu.thread && mode == Mode::SynchronizeAll) return exit(Event::Synchronize); -} - -auto Scheduler::synchronizing() const -> bool { - return mode == Mode::SynchronizeAll; -} - -} diff --git a/higan/ws/scheduler/scheduler.hpp b/higan/ws/scheduler/scheduler.hpp deleted file mode 100644 index 76c41e25..00000000 --- a/higan/ws/scheduler/scheduler.hpp +++ /dev/null @@ -1,28 +0,0 @@ -struct Scheduler { - enum class Mode : uint { - Run, - SynchronizeCPU, - SynchronizeAll, - }; - - enum class Event : uint { - Unknown, - Frame, - Synchronize, - }; - - auto power() -> void; - auto enter(Mode = Mode::Run) -> Event; - auto exit(Event) -> void; - auto synchronize(cothread_t) -> void; - auto synchronize() -> void; - auto synchronizing() const -> bool; - -private: - cothread_t host = nullptr; - cothread_t resume = nullptr; - Mode mode = Mode::Run; - Event event = Event::Unknown; -}; - -extern Scheduler scheduler; diff --git a/higan/ws/system/system.cpp b/higan/ws/system/system.cpp index eceae137..8fad565c 100644 --- a/higan/ws/system/system.cpp +++ b/higan/ws/system/system.cpp @@ -3,6 +3,8 @@ namespace WonderSwan { System system; +Scheduler scheduler; +Cheat cheat; #include "io.cpp" #include "video.cpp" #include "serialization.cpp" @@ -74,7 +76,7 @@ auto System::power() -> void { ppu.power(); apu.power(); cartridge.power(); - scheduler.power(); + scheduler.reset(cpu.thread); bus.map(this, 0x0060); bus.map(this, 0x00ba, 0x00be); @@ -86,7 +88,7 @@ auto System::power() -> void { } auto System::run() -> void { - scheduler.enter(); + if(scheduler.enter() == Scheduler::Event::Frame) ppu.refresh(); pollKeypad(); } diff --git a/higan/ws/ws.hpp b/higan/ws/ws.hpp index 4768d75c..3383b9ec 100644 --- a/higan/ws/ws.hpp +++ b/higan/ws/ws.hpp @@ -4,10 +4,19 @@ //started: 2016-01-26 #include +#include +#include +#include + #include namespace WonderSwan { using File = Emulator::File; + using Thread = Emulator::Thread; + using Scheduler = Emulator::Scheduler; + using Cheat = Emulator::Cheat; + extern Scheduler scheduler; + extern Cheat cheat; enum class Model : uint { WonderSwan, //SW-001 (ASWAN) @@ -17,37 +26,13 @@ namespace WonderSwan { enum : uint { Byte = 1, Word = 2, Long = 4 }; - struct Thread { - ~Thread() { - if(thread) co_delete(thread); - } - - auto create(auto (*entrypoint)() -> void, uint frequency) -> void { - if(thread) co_delete(thread); - thread = co_create(65'536 * sizeof(void*), entrypoint); - this->frequency = frequency; - clock = 0; - } - - auto serialize(serializer& s) -> void { - s.integer(frequency); - s.integer(clock); - } - - cothread_t thread = nullptr; - uint frequency = 0; - int64 clock = 0; - }; - #include #include #include - #include #include #include #include #include - #include } #include diff --git a/icarus/core/core.cpp b/icarus/core/core.cpp index 8dbb3342..e8162e24 100644 --- a/icarus/core/core.cpp +++ b/icarus/core/core.cpp @@ -68,7 +68,7 @@ auto Icarus::import(string location) -> string { if(type == ".fc" || type == ".nes") return famicomImport(buffer, location); if(type == ".sfc" || type == ".smc") return superFamicomImport(buffer, location); - if(type == ".smd") return megaDriveImport(buffer, location); + if(type == ".md") return megaDriveImport(buffer, location); if(type == ".gb") return gameBoyImport(buffer, location); if(type == ".gbc") return gameBoyColorImport(buffer, location); if(type == ".gba") return gameBoyAdvanceImport(buffer, location); diff --git a/icarus/icarus.cpp b/icarus/icarus.cpp index 25b5166f..e702f5c2 100644 --- a/icarus/icarus.cpp +++ b/icarus/icarus.cpp @@ -68,7 +68,7 @@ auto nall::main(string_vector args) -> void { if(string source = BrowserDialog() .setTitle("Load ROM Image") .setPath(settings["icarus/Path"].text()) - .setFilters("ROM Files|*.fc:*.nes:*.sfc:*.smc:*.smd:*.gb:*.gbc:*.gba:*.ws:*.wsc:*.bs:*.st:*.zip") + .setFilters("ROM Files|*.fc:*.nes:*.sfc:*.smc:*.md:*.gb:*.gbc:*.gba:*.ws:*.wsc:*.bs:*.st:*.zip") .openFile()) { if(string target = icarus.import(source)) { settings["icarus/Path"].setValue(Location::path(source));