From 55f19c3e0d57ad4934379f470910814cc47ab1ce Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sat, 12 Aug 2017 02:02:09 +1000 Subject: [PATCH] Update to v103r32 release. byuu says: Changelog: - Master System: merged Bus into CPU - Mega Drive: merged BusCPU into CPU; BusAPU into AU - Mega Drive: added TMSS emulation; disabled by default [hex\_usr] - VDP lockout not yet emulated - processor/arm7tdmi: renamed interrupt() to exception() - processor/arm7tdmi: CPSR.F (FIQ disable) flag is set on reset - processor/arm7tdmi: pipeline decode stage caches CPSR.T (THUMB mode) [MerryMage] - fixes `msr_tests.gba` test F - processor/arm7tdmi/disassembler: add PC address to left of currently executing instruction - processor/arm7tdmi: stop forcing CPSR.M (mode flags) bit 4 high (I don't know what really happens here) - processor/arm7tdmi: undefined instructions now generate Undefined 0x4 exception - processor/arm7tdmi: thumbInstructionAddRegister masks PC by &~3 instead of &~2 - hopefully this is correct; &~2 felt very wrong - processor/arm7tdmi: thumbInstructionStackMultiple can use sequential timing for PC/LR PUSH/POP [Cydrak] - systems/Mega Drive.sys: added tmss.rom; enable with cpu version=1 - tomoko: detect when a ruby video/audio/input driver crashes higan; disable it on next program startup v104 blockers: - Mega Drive: support 8-bit SRAM (even if we don't support 16-bit; don't force 8-bit to 16-bit) - Mega Drive: add region detection support to icarus - ruby: add default audio device information so certain drivers won't default to silence out of the box --- higan/emulator/emulator.hpp | 2 +- higan/md/GNUmakefile | 3 +- higan/md/apu/apu.cpp | 3 +- higan/md/apu/apu.hpp | 16 ++- higan/md/apu/bus.cpp | 51 ++++++++ higan/md/apu/serialization.cpp | 5 + higan/md/bus/bus.hpp | 33 ------ higan/md/bus/serialization.cpp | 8 -- higan/md/{bus => cpu}/bus.cpp | 110 ++++++------------ higan/md/cpu/cpu.cpp | 23 +++- higan/md/cpu/cpu.hpp | 22 +++- higan/md/cpu/serialization.cpp | 7 ++ higan/md/md.hpp | 1 - higan/md/system/serialization.cpp | 2 - higan/md/system/system.cpp | 2 + higan/md/vdp/dma.cpp | 2 +- higan/ms/GNUmakefile | 3 +- higan/ms/bus/bus.hpp | 16 --- higan/ms/bus/serialization.cpp | 5 - higan/ms/{bus => cpu}/bus.cpp | 37 +++--- higan/ms/cpu/cpu.cpp | 6 +- higan/ms/cpu/cpu.hpp | 12 +- higan/ms/cpu/serialization.cpp | 3 + higan/ms/ms.hpp | 1 - higan/ms/system/serialization.cpp | 1 - higan/processor/arm7tdmi/arm7tdmi.cpp | 3 +- higan/processor/arm7tdmi/arm7tdmi.hpp | 28 +++-- higan/processor/arm7tdmi/disassembler.cpp | 14 ++- higan/processor/arm7tdmi/instruction.cpp | 26 ++++- higan/processor/arm7tdmi/instructions-arm.cpp | 7 +- .../processor/arm7tdmi/instructions-thumb.cpp | 15 ++- higan/processor/arm7tdmi/serialization.cpp | 3 + higan/systems/Mega Drive.sys/manifest.bml | 2 + higan/systems/Mega Drive.sys/tmss.rom | Bin 0 -> 2048 bytes .../configuration/configuration.cpp | 5 +- .../configuration/configuration.hpp | 2 +- higan/target-tomoko/program/program.cpp | 26 ++++- 37 files changed, 292 insertions(+), 213 deletions(-) create mode 100644 higan/md/apu/bus.cpp delete mode 100644 higan/md/bus/bus.hpp delete mode 100644 higan/md/bus/serialization.cpp rename higan/md/{bus => cpu}/bus.cpp (55%) delete mode 100644 higan/ms/bus/bus.hpp delete mode 100644 higan/ms/bus/serialization.cpp rename higan/ms/{bus => cpu}/bus.cpp (77%) create mode 100644 higan/systems/Mega Drive.sys/tmss.rom diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 5a7b7dfe..936ec043 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.31"; + static const string Version = "103.32"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/md/GNUmakefile b/higan/md/GNUmakefile index a8086bb1..03242ca5 100644 --- a/higan/md/GNUmakefile +++ b/higan/md/GNUmakefile @@ -2,7 +2,7 @@ processors += m68k z80 objects += md-interface objects += md-cpu md-apu md-vdp md-psg md-ym2612 -objects += md-system md-cartridge md-bus +objects += md-system md-cartridge objects += md-controller obj/md-interface.o: md/interface/interface.cpp $(call rwildcard,md/interface) @@ -13,5 +13,4 @@ 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-cartridge.o: md/cartridge/cartridge.cpp $(call rwildcard,md/cartridge) -obj/md-bus.o: md/bus/bus.cpp $(call rwildcard,md/bus) obj/md-controller.o: md/controller/controller.cpp $(call rwildcard,md/controller) diff --git a/higan/md/apu/apu.cpp b/higan/md/apu/apu.cpp index bfe0908b..55c99917 100644 --- a/higan/md/apu/apu.cpp +++ b/higan/md/apu/apu.cpp @@ -3,6 +3,7 @@ namespace MegaDrive { APU apu; +#include "bus.cpp" #include "serialization.cpp" auto APU::Enter() -> void { @@ -52,7 +53,7 @@ auto APU::enable(bool value) -> void { } auto APU::power() -> void { - Z80::bus = &busAPU; + Z80::bus = this; Z80::power(); bus->grant(false); create(APU::Enter, system.frequency() / 15.0); diff --git a/higan/md/apu/apu.hpp b/higan/md/apu/apu.hpp index 28e69d36..fcc65b8b 100644 --- a/higan/md/apu/apu.hpp +++ b/higan/md/apu/apu.hpp @@ -1,6 +1,7 @@ //Zilog Z80 -struct APU : Processor::Z80, Thread { +struct APU : Processor::Z80, Processor::Z80::Bus, Thread { + //z80.cpp static auto Enter() -> void; auto main() -> void; auto step(uint clocks) -> void override; @@ -13,10 +14,23 @@ struct APU : Processor::Z80, Thread { auto setNMI(bool value) -> void; auto setINT(bool value) -> void; + //bus.cpp + auto read(uint16 addr) -> uint8 override; + auto write(uint16 addr, uint8 data) -> void override; + + auto in(uint8 addr) -> uint8 override; + auto out(uint8 addr, uint8 data) -> void override; + //serialization.cpp auto serialize(serializer&) -> void; private: + uint8 ram[8 * 1024]; + + struct IO { + uint9 bank; + } io; + struct State { uint1 enabled; uint1 nmiLine; diff --git a/higan/md/apu/bus.cpp b/higan/md/apu/bus.cpp new file mode 100644 index 00000000..f1678597 --- /dev/null +++ b/higan/md/apu/bus.cpp @@ -0,0 +1,51 @@ +auto APU::read(uint16 addr) -> uint8 { + if((addr & 0xe000) == 0x0000) { + return ram[addr]; + } + + if(addr == 0x4000) return ym2612.readStatus(); + if(addr == 0x4001) return ym2612.readStatus(); + if(addr == 0x4002) return ym2612.readStatus(); + if(addr == 0x4003) return ym2612.readStatus(); + + if((addr & 0x8000) == 0x8000) { + return cartridge.read(io.bank << 15 | (addr & 0x7ffe)).byte(!addr.bit(0)); + } +} + +auto APU::write(uint16 addr, uint8 data) -> void { + if((addr & 0xe000) == 0x0000) { + ram[addr] = data; + return; + } + + if(addr == 0x4000) return ym2612.writeAddress(0 << 8 | data); + if(addr == 0x4001) return ym2612.writeData(data); + if(addr == 0x4002) return ym2612.writeAddress(1 << 8 | data); + if(addr == 0x4003) return ym2612.writeData(data); + + if(addr == 0x6000) { + //1-bit shift register + io.bank = data.bit(0) << 8 | io.bank >> 1; + return; + } + + if(addr == 0x7f11) return psg.write(data); + if(addr == 0x7f13) return psg.write(data); + if(addr == 0x7f15) return psg.write(data); + if(addr == 0x7f17) return psg.write(data); + + if((addr & 0x8000) == 0x8000) { + //todo: do 8-bit writes mirror to 16-bits? + return cartridge.write(io.bank << 15 | (addr & 0x7ffe), data << 8 | data << 0); + } +} + +//unused on Mega Drive +auto APU::in(uint8 addr) -> uint8 { + return 0x00; +} + +//unused on Mega Drive +auto APU::out(uint8 addr, uint8 data) -> void { +} diff --git a/higan/md/apu/serialization.cpp b/higan/md/apu/serialization.cpp index 335d7622..cb590f76 100644 --- a/higan/md/apu/serialization.cpp +++ b/higan/md/apu/serialization.cpp @@ -1,7 +1,12 @@ auto APU::serialize(serializer& s) -> void { Z80::serialize(s); + Z80::Bus::serialize(s); Thread::serialize(s); + s.array(ram); + + s.integer(io.bank); + s.integer(state.enabled); s.integer(state.nmiLine); s.integer(state.intLine); diff --git a/higan/md/bus/bus.hpp b/higan/md/bus/bus.hpp deleted file mode 100644 index ad73ebd4..00000000 --- a/higan/md/bus/bus.hpp +++ /dev/null @@ -1,33 +0,0 @@ -struct BusCPU : Processor::M68K::Bus { - auto readByte(uint24 addr) -> uint16 override; - auto readWord(uint24 addr) -> uint16 override; - auto writeByte(uint24 addr, uint16 data) -> void override; - auto writeWord(uint24 addr, uint16 data) -> void override; - - auto readIO(uint24 addr) -> uint16; - auto writeIO(uint24 addr, uint16 data) -> void; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - uint8 ram[64 * 1024]; -}; - -struct BusAPU : Processor::Z80::Bus { - auto read(uint16 addr) -> uint8 override; - auto write(uint16 addr, uint8 data) -> void override; - - auto in(uint8 addr) -> uint8 override; - auto out(uint8 addr, uint8 data) -> void override; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - uint8 ram[8 * 1024]; - uint9 bank; -}; - -extern BusCPU busCPU; -extern BusAPU busAPU; diff --git a/higan/md/bus/serialization.cpp b/higan/md/bus/serialization.cpp deleted file mode 100644 index fd7e2f71..00000000 --- a/higan/md/bus/serialization.cpp +++ /dev/null @@ -1,8 +0,0 @@ -auto BusCPU::serialize(serializer& s) -> void { - s.array(ram); -} - -auto BusAPU::serialize(serializer& s) -> void { - s.array(ram); - s.integer(bank); -} diff --git a/higan/md/bus/bus.cpp b/higan/md/cpu/bus.cpp similarity index 55% rename from higan/md/bus/bus.cpp rename to higan/md/cpu/bus.cpp index d31bf0d6..0a29882c 100644 --- a/higan/md/bus/bus.cpp +++ b/higan/md/cpu/bus.cpp @@ -1,14 +1,9 @@ -#include - -namespace MegaDrive { - -BusCPU busCPU; -BusAPU busAPU; -#include "serialization.cpp" - -auto BusCPU::readByte(uint24 addr) -> uint16 { - if(addr >= 0x000000 && addr <= 0x3fffff) return cartridge.read(addr & ~1).byte(!addr.bit(0)); - if(addr >= 0xa00000 && addr <= 0xa0ffff) return busAPU.granted() ? busAPU.read(addr) : (uint8)0x0000; +auto CPU::readByte(uint24 addr) -> uint16 { + if(addr >= 0x000000 && addr <= 0x3fffff) { + if(!io.romEnable) return tmss[addr & 0x7ff]; + return cartridge.read(addr & ~1).byte(!addr.bit(0)); + } + if(addr >= 0xa00000 && addr <= 0xa0ffff) return apu.granted() ? apu.read(addr) : (uint8)0x00; if(addr >= 0xa10000 && addr <= 0xa10fff) return readIO(addr & ~0xff00); if(addr >= 0xa11000 && addr <= 0xa11fff) return readIO(addr & ~0x00ff); if(addr >= 0xa13000 && addr <= 0xa130ff) return cartridge.readIO(addr); @@ -19,9 +14,12 @@ auto BusCPU::readByte(uint24 addr) -> uint16 { return 0x0000; } -auto BusCPU::readWord(uint24 addr) -> uint16 { - if(addr >= 0x000000 && addr <= 0x3fffff) return cartridge.read(addr); - if(addr >= 0xa00000 && addr <= 0xa0ffff) return busAPU.granted() ? busAPU.read(addr) : (uint8)0x0000; +auto CPU::readWord(uint24 addr) -> uint16 { + if(addr >= 0x000000 && addr <= 0x3fffff) { + if(!io.romEnable) return tmss[addr & 0x7fe | 0] << 8 | tmss[addr & 0x7fe | 1] << 0; + return cartridge.read(addr); + } + if(addr >= 0xa00000 && addr <= 0xa0ffff) return apu.granted() ? apu.read(addr) : (uint8)0x00; if(addr >= 0xa10000 && addr <= 0xa10fff) return readIO(addr & ~0xff00) << 0; if(addr >= 0xa11000 && addr <= 0xa11fff) return readIO(addr & ~0x00ff) << 8; if(addr >= 0xa13000 && addr <= 0xa130ff) return cartridge.readIO(addr); @@ -33,12 +31,14 @@ auto BusCPU::readWord(uint24 addr) -> uint16 { return 0x0000; } -auto BusCPU::writeByte(uint24 addr, uint16 data) -> void { +auto CPU::writeByte(uint24 addr, uint16 data) -> void { if(addr >= 0x000000 && addr <= 0x3fffff) return cartridge.write(addr & ~1, data << 8 | data << 0); - if(addr >= 0xa00000 && addr <= 0xa0ffff) return busAPU.granted() ? busAPU.write(addr, data) : (void)0; + if(addr >= 0xa00000 && addr <= 0xa0ffff) return apu.granted() ? apu.write(addr, data) : (void)0; if(addr >= 0xa10000 && addr <= 0xa10fff) return writeIO(addr & ~0xff00, data); if(addr >= 0xa11000 && addr <= 0xa11fff) return writeIO(addr & ~0x00ff, data); if(addr >= 0xa13000 && addr <= 0xa130ff) return cartridge.writeIO(addr, data); + if(addr >= 0xa14000 && addr <= 0xa140ff) return writeIO(addr & ~0xff00, data); + if(addr >= 0xa14100 && addr <= 0xa141ff) return writeIO(addr & ~0x00ff, data); if(addr >= 0xc00000 && addr <= 0xc0000f) return vdp.write(addr & ~1, data << 8 | data << 0); if(addr >= 0xc00010 && addr <= 0xc00017) return psg.write(data); if(addr >= 0xe00000 && addr <= 0xffffff) { @@ -47,12 +47,14 @@ auto BusCPU::writeByte(uint24 addr, uint16 data) -> void { } } -auto BusCPU::writeWord(uint24 addr, uint16 data) -> void { +auto CPU::writeWord(uint24 addr, uint16 data) -> void { if(addr >= 0x000000 && addr <= 0x3fffff) return cartridge.write(addr, data); - if(addr >= 0xa00000 && addr <= 0xa0ffff) return busAPU.granted() ? busAPU.write(addr, data) : (void)0; + if(addr >= 0xa00000 && addr <= 0xa0ffff) return apu.granted() ? apu.write(addr, data) : (void)0; if(addr >= 0xa10000 && addr <= 0xa10fff) return writeIO(addr & ~0xff00, data >> 0); if(addr >= 0xa11000 && addr <= 0xa11fff) return writeIO(addr & ~0x00ff, data >> 8); if(addr >= 0xa13000 && addr <= 0xa130ff) return cartridge.writeIO(addr, data); + if(addr >= 0xa14000 && addr <= 0xa140ff) return writeIO(addr & ~0xff00, data >> 0); + if(addr >= 0xa14100 && addr <= 0xa141ff) return writeIO(addr & ~0x00ff, data >> 8); if(addr >= 0xc00000 && addr <= 0xc0000f) return vdp.write(addr, data); if(addr >= 0xc00010 && addr <= 0xc00017) return psg.write(data); if(addr >= 0xe00000 && addr <= 0xffffff) { @@ -62,15 +64,13 @@ auto BusCPU::writeWord(uint24 addr, uint16 data) -> void { } } -// - -auto BusCPU::readIO(uint24 addr) -> uint16 { +auto CPU::readIO(uint24 addr) -> uint16 { switch(addr & ~1) { case 0xa10000: return ( !Region::NTSCJ() << 7 //0 = domestic (Japan); 1 = export | Region::PAL() << 6 //0 = NTSC; 1 = PAL | 1 << 5 //0 = Mega CD connected; 1 = no expansion connected - | 0 << 0 //0 = Model 1; 1 = Model 2+ + | io.version << 0 //0 = Model 1; 1 = Model 2+ ); case 0xa10002: return controllerPort1.device->readData(); @@ -81,13 +81,13 @@ auto BusCPU::readIO(uint24 addr) -> uint16 { case 0xa1000a: return controllerPort2.readControl(); case 0xa1000c: return extensionPort.readControl(); - case 0xa11100: return !busAPU.granted(); + case 0xa11100: return !apu.granted(); } return 0x0000; } -auto BusCPU::writeIO(uint24 addr, uint16 data) -> void { +auto CPU::writeIO(uint24 addr, uint16 data) -> void { switch(addr & ~1) { case 0xa10002: return controllerPort1.device->writeData(data); case 0xa10004: return controllerPort2.device->writeData(data); @@ -97,63 +97,19 @@ auto BusCPU::writeIO(uint24 addr, uint16 data) -> void { case 0xa1000a: return controllerPort2.writeControl(data); case 0xa1000c: return extensionPort.writeControl(data); - case 0xa11100: return busAPU.request(data.bit(0)); + case 0xa11100: return apu.request(data.bit(0)); case 0xa11200: return apu.enable(data.bit(0)); - } -} -// + case 0xa14000: + io.vdpEnable[0] = data == 0x5345; + return; -auto BusAPU::read(uint16 addr) -> uint8 { - if((addr & 0xe000) == 0x0000) { - return ram[addr]; - } + case 0xa14002: + io.vdpEnable[1] = data == 0x4741; + return; - if(addr == 0x4000) return ym2612.readStatus(); - if(addr == 0x4001) return ym2612.readStatus(); - if(addr == 0x4002) return ym2612.readStatus(); - if(addr == 0x4003) return ym2612.readStatus(); - - if((addr & 0x8000) == 0x8000) { - return cartridge.read(bank << 15 | (addr & 0x7ffe)).byte(!addr.bit(0)); - } -} - -auto BusAPU::write(uint16 addr, uint8 data) -> void { - if((addr & 0xe000) == 0x0000) { - ram[addr] = data; + case 0xa14100: + io.romEnable = data.bit(0); return; } - - if(addr == 0x4000) return ym2612.writeAddress(0 << 8 | data); - if(addr == 0x4001) return ym2612.writeData(data); - if(addr == 0x4002) return ym2612.writeAddress(1 << 8 | data); - if(addr == 0x4003) return ym2612.writeData(data); - - if(addr == 0x6000) { - //1-bit shift register - bank = data.bit(0) << 8 | bank >> 1; - return; - } - - if(addr == 0x7f11) return psg.write(data); - if(addr == 0x7f13) return psg.write(data); - if(addr == 0x7f15) return psg.write(data); - if(addr == 0x7f17) return psg.write(data); - - if((addr & 0x8000) == 0x8000) { - //todo: do 8-bit writes mirror to 16-bits? - return cartridge.write(bank << 15 | (addr & 0x7ffe), data << 8 | data << 0); - } -} - -//unused on Mega Drive -auto BusAPU::in(uint8 addr) -> uint8 { - return 0x00; -} - -//unused on Mega Drive -auto BusAPU::out(uint8 addr, uint8 data) -> void { -} - } diff --git a/higan/md/cpu/cpu.cpp b/higan/md/cpu/cpu.cpp index ab60a3d3..4b8499c3 100644 --- a/higan/md/cpu/cpu.cpp +++ b/higan/md/cpu/cpu.cpp @@ -3,6 +3,7 @@ namespace MegaDrive { CPU cpu; +#include "bus.cpp" #include "serialization.cpp" auto CPU::Enter() -> void { @@ -65,11 +66,31 @@ auto CPU::lower(Interrupt interrupt) -> void { state.interruptPending.bit((uint)interrupt) = 0; } +auto CPU::load(Markup::Node node) -> bool { + tmssEnable = false; + if(node["cpu/version"].natural() == 1) { + if(auto name = node["cpu/rom/name"].text()) { + if(auto fp = platform->open(ID::System, name, File::Read, File::Required)) { + fp->read(tmss, 2 * 1024); + tmssEnable = true; + } + } + } + + return true; +} + auto CPU::power() -> void { - M68K::bus = &busCPU; + M68K::bus = this; M68K::power(); create(CPU::Enter, system.frequency() / 7.0); + io = {}; + io.version = tmssEnable; + io.romEnable = !tmssEnable; + io.vdpEnable[0] = !tmssEnable; + io.vdpEnable[1] = !tmssEnable; + state = {}; state.interruptPending.bit((uint)Interrupt::Reset) = 1; } diff --git a/higan/md/cpu/cpu.hpp b/higan/md/cpu/cpu.hpp index 95cd5ae1..fb97ee29 100644 --- a/higan/md/cpu/cpu.hpp +++ b/higan/md/cpu/cpu.hpp @@ -1,6 +1,6 @@ //Motorola 68000 -struct CPU : Processor::M68K, Thread { +struct CPU : Processor::M68K, Processor::M68K::Bus, Thread { enum class Interrupt : uint { Reset, HorizontalBlank, @@ -9,6 +9,7 @@ struct CPU : Processor::M68K, Thread { using Thread::synchronize; + //cpu.cpp static auto Enter() -> void; auto main() -> void; auto step(uint clocks) -> void override; @@ -17,14 +18,33 @@ struct CPU : Processor::M68K, Thread { auto raise(Interrupt) -> void; auto lower(Interrupt) -> void; + auto load(Markup::Node) -> bool; auto power() -> void; + //bus.cpp + auto readByte(uint24 address) -> uint16 override; + auto readWord(uint24 address) -> uint16 override; + auto writeByte(uint24 address, uint16 data) -> void override; + auto writeWord(uint24 address, uint16 data) -> void override; + auto readIO(uint24 address) -> uint16; + auto writeIO(uint24 address, uint16 data) -> void; + //serialization.cpp auto serialize(serializer&) -> void; vector peripherals; private: + uint8 ram[64 * 1024]; + uint8 tmss[2 * 1024]; + uint1 tmssEnable; + + struct IO { + boolean version; //0 = Model 1; 1 = Model 2+ + boolean romEnable; + boolean vdpEnable[2]; + } io; + struct State { uint32 interruptLine; uint32 interruptPending; diff --git a/higan/md/cpu/serialization.cpp b/higan/md/cpu/serialization.cpp index ca8e5525..23acf588 100644 --- a/higan/md/cpu/serialization.cpp +++ b/higan/md/cpu/serialization.cpp @@ -2,6 +2,13 @@ auto CPU::serialize(serializer& s) -> void { M68K::serialize(s); Thread::serialize(s); + s.array(ram); + + s.boolean(io.version); + s.boolean(io.romEnable); + s.boolean(io.vdpEnable[0]); + s.boolean(io.vdpEnable[1]); + s.integer(state.interruptLine); s.integer(state.interruptPending); } diff --git a/higan/md/md.hpp b/higan/md/md.hpp index 504273ca..ac9094b3 100644 --- a/higan/md/md.hpp +++ b/higan/md/md.hpp @@ -55,7 +55,6 @@ namespace MegaDrive { #include #include - #include } #include diff --git a/higan/md/system/serialization.cpp b/higan/md/system/serialization.cpp index d5d80152..9ea9755d 100644 --- a/higan/md/system/serialization.cpp +++ b/higan/md/system/serialization.cpp @@ -55,8 +55,6 @@ auto System::unserialize(serializer& s) -> bool { auto System::serializeAll(serializer& s) -> void { system.serialize(s); - busCPU.serialize(s); - busAPU.serialize(s); cartridge.serialize(s); cpu.serialize(s); apu.serialize(s); diff --git a/higan/md/system/system.cpp b/higan/md/system/system.cpp index 8d5e8e5f..2bc8da27 100644 --- a/higan/md/system/system.cpp +++ b/higan/md/system/system.cpp @@ -27,6 +27,8 @@ auto System::load(Emulator::Interface* interface, maybe region) -> bool } else return false; auto document = BML::unserialize(information.manifest); + auto system = document["system"]; + if(!cpu.load(system)) return false; if(!cartridge.load()) return false; if(cartridge.region() == "NTSC-J") { diff --git a/higan/md/vdp/dma.cpp b/higan/md/vdp/dma.cpp index 73341728..6b8f425f 100644 --- a/higan/md/vdp/dma.cpp +++ b/higan/md/vdp/dma.cpp @@ -11,7 +11,7 @@ auto VDP::DMA::run() -> void { auto VDP::DMA::load() -> void { cpu.wait |= Wait::VDP_DMA; - auto data = busCPU.readWord(io.mode.bit(0) << 23 | io.source << 1); + auto data = cpu.readWord(io.mode.bit(0) << 23 | io.source << 1); vdp.writeDataPort(data); io.source.bits(0,15)++; diff --git a/higan/ms/GNUmakefile b/higan/ms/GNUmakefile index 9f09f3d1..196d19e0 100644 --- a/higan/ms/GNUmakefile +++ b/higan/ms/GNUmakefile @@ -2,7 +2,7 @@ processors += z80 objects += ms-interface objects += ms-cpu ms-vdp ms-psg -objects += ms-system ms-cartridge ms-bus +objects += ms-system ms-cartridge objects += ms-controller obj/ms-interface.o: ms/interface/interface.cpp $(call rwildcard,ms/interface) @@ -11,5 +11,4 @@ obj/ms-vdp.o: ms/vdp/vdp.cpp $(call rwildcard,ms/vdp) obj/ms-psg.o: ms/psg/psg.cpp $(call rwildcard,ms/psg) obj/ms-system.o: ms/system/system.cpp $(call rwildcard,ms/system) obj/ms-cartridge.o: ms/cartridge/cartridge.cpp $(call rwildcard,ms/cartridge) -obj/ms-bus.o: ms/bus/bus.cpp $(call rwildcard,ms/bus) obj/ms-controller.o: ms/controller/controller.cpp $(call rwildcard,ms/controller) diff --git a/higan/ms/bus/bus.hpp b/higan/ms/bus/bus.hpp deleted file mode 100644 index 7e4c38a4..00000000 --- a/higan/ms/bus/bus.hpp +++ /dev/null @@ -1,16 +0,0 @@ -struct Bus : Processor::Z80::Bus { - auto read(uint16 addr) -> uint8 override; - auto read_(uint16 addr) -> uint8; - auto write(uint16 addr, uint8 data) -> void override; - - auto in(uint8 addr) -> uint8 override; - auto out(uint8 addr, uint8 data) -> void override; - - //serialization.cpp - auto serialize(serializer&) -> void; - -private: - uint8 ram[0x2000]; -}; - -extern Bus bus; diff --git a/higan/ms/bus/serialization.cpp b/higan/ms/bus/serialization.cpp deleted file mode 100644 index 897396f0..00000000 --- a/higan/ms/bus/serialization.cpp +++ /dev/null @@ -1,5 +0,0 @@ -auto Bus::serialize(serializer& s) -> void { - Processor::Z80::Bus::serialize(s); - - s.array(ram); -} diff --git a/higan/ms/bus/bus.cpp b/higan/ms/cpu/bus.cpp similarity index 77% rename from higan/ms/bus/bus.cpp rename to higan/ms/cpu/bus.cpp index 4e3ad1f0..48c1a6dd 100644 --- a/higan/ms/bus/bus.cpp +++ b/higan/ms/cpu/bus.cpp @@ -1,28 +1,27 @@ -#include +auto CPU::read(uint16 addr) -> uint8 { + uint8 data; -namespace MasterSystem { + if(auto result = cartridge.read(addr)) { + data = result(); + } else if(addr >= 0xc000) { + data = ram[addr & 0x1fff]; + } -Bus bus; -#include "serialization.cpp" + if(auto result = cheat.find(addr, data)) { + data = result(); + } -auto Bus::read(uint16 addr) -> uint8 { - auto data = read_(addr); - if(auto result = cheat.find(addr, data)) data = result(); return data; } -auto Bus::read_(uint16 addr) -> uint8 { - if(auto data = cartridge.read(addr)) return data(); - if(addr >= 0xc000) return ram[addr & 0x1fff]; - return 0x00; +auto CPU::write(uint16 addr, uint8 data) -> void { + if(cartridge.write(addr, data)) { + } else if(addr >= 0xc000) { + ram[addr & 0x1fff] = data; + } } -auto Bus::write(uint16 addr, uint8 data) -> void { - if(cartridge.write(addr, data)) return; - if(addr >= 0xc000) ram[addr & 0x1fff] = data; -} - -auto Bus::in(uint8 addr) -> uint8 { +auto CPU::in(uint8 addr) -> uint8 { switch(addr >> 6) { case 0: { @@ -78,7 +77,7 @@ auto Bus::in(uint8 addr) -> uint8 { return 0xff; } -auto Bus::out(uint8 addr, uint8 data) -> void { +auto CPU::out(uint8 addr, uint8 data) -> void { if(addr == 0x06) { if(Model::GameGear()) return psg.balance(data); } @@ -99,5 +98,3 @@ auto Bus::out(uint8 addr, uint8 data) -> void { } } - -} diff --git a/higan/ms/cpu/cpu.cpp b/higan/ms/cpu/cpu.cpp index 42ab471b..48ec02b4 100644 --- a/higan/ms/cpu/cpu.cpp +++ b/higan/ms/cpu/cpu.cpp @@ -3,6 +3,7 @@ namespace MasterSystem { CPU cpu; +#include "bus.cpp" #include "serialization.cpp" auto CPU::Enter() -> void { @@ -53,6 +54,7 @@ auto CPU::setINT(bool value) -> void { } auto CPU::power() -> void { + Z80::bus = this; Z80::power(); create(CPU::Enter, system.colorburst()); @@ -61,8 +63,4 @@ auto CPU::power() -> void { memory::fill(&state, sizeof(State)); } -CPU::CPU() { - Z80::bus = &MasterSystem::bus; -} - } diff --git a/higan/ms/cpu/cpu.hpp b/higan/ms/cpu/cpu.hpp index 7124e0b8..49abace5 100644 --- a/higan/ms/cpu/cpu.hpp +++ b/higan/ms/cpu/cpu.hpp @@ -1,6 +1,7 @@ //Zilog Z80 -struct CPU : Processor::Z80, Thread { +struct CPU : Processor::Z80, Processor::Z80::Bus, Thread { + //cpu.cpp static auto Enter() -> void; auto main() -> void; auto step(uint clocks) -> void override; @@ -12,7 +13,12 @@ struct CPU : Processor::Z80, Thread { auto power() -> void; - CPU(); + //bus.cpp + auto read(uint16 addr) -> uint8 override; + auto write(uint16 addr, uint8 data) -> void override; + + auto in(uint8 addr) -> uint8 override; + auto out(uint8 addr, uint8 data) -> void override; //serialization.cpp auto serialize(serializer&) -> void; @@ -20,6 +26,8 @@ struct CPU : Processor::Z80, Thread { vector peripherals; private: + uint8 ram[8 * 1024]; + struct State { bool nmiLine; bool intLine; diff --git a/higan/ms/cpu/serialization.cpp b/higan/ms/cpu/serialization.cpp index 321bcc0a..e29b80e4 100644 --- a/higan/ms/cpu/serialization.cpp +++ b/higan/ms/cpu/serialization.cpp @@ -1,7 +1,10 @@ auto CPU::serialize(serializer& s) -> void { Z80::serialize(s); + Z80::Bus::serialize(s); Thread::serialize(s); + s.array(ram); + s.integer(state.nmiLine); s.integer(state.intLine); } diff --git a/higan/ms/ms.hpp b/higan/ms/ms.hpp index a3398e1e..c1c02dc8 100644 --- a/higan/ms/ms.hpp +++ b/higan/ms/ms.hpp @@ -47,7 +47,6 @@ namespace MasterSystem { #include #include - #include } #include diff --git a/higan/ms/system/serialization.cpp b/higan/ms/system/serialization.cpp index 2b7fd172..7966fc91 100644 --- a/higan/ms/system/serialization.cpp +++ b/higan/ms/system/serialization.cpp @@ -55,7 +55,6 @@ auto System::unserialize(serializer& s) -> bool { auto System::serializeAll(serializer& s) -> void { system.serialize(s); - bus.serialize(s); cartridge.serialize(s); cpu.serialize(s); vdp.serialize(s); diff --git a/higan/processor/arm7tdmi/arm7tdmi.cpp b/higan/processor/arm7tdmi/arm7tdmi.cpp index 097db5de..e3dc0d28 100644 --- a/higan/processor/arm7tdmi/arm7tdmi.cpp +++ b/higan/processor/arm7tdmi/arm7tdmi.cpp @@ -19,11 +19,12 @@ ARM7TDMI::ARM7TDMI() { auto ARM7TDMI::power() -> void { processor = {}; - interrupt(PSR::SVC, 0x00); processor.r15.modify = [&] { pipeline.reload = true; }; pipeline = {}; carry = 0; irq = 0; + cpsr().f = 1; + exception(PSR::SVC, 0x00); } } diff --git a/higan/processor/arm7tdmi/arm7tdmi.hpp b/higan/processor/arm7tdmi/arm7tdmi.hpp index ab067021..f153bb4a 100644 --- a/higan/processor/arm7tdmi/arm7tdmi.hpp +++ b/higan/processor/arm7tdmi/arm7tdmi.hpp @@ -57,7 +57,7 @@ struct ARM7TDMI { //instruction.cpp auto fetch() -> void; auto instruction() -> void; - auto interrupt(uint mode, uint32 address) -> void; + auto exception(uint mode, uint32 address) -> void; auto armInitialize() -> void; auto thumbInitialize() -> void; @@ -84,6 +84,7 @@ struct ARM7TDMI { auto armInstructionMultiply(uint4, uint4, uint4, uint4, uint1, uint1) -> void; auto armInstructionMultiplyLong(uint4, uint4, uint4, uint4, uint1, uint1, uint1) -> void; auto armInstructionSoftwareInterrupt(uint24 immediate) -> void; + auto armInstructionUndefined() -> void; //instructions-thumb.cpp auto thumbInstructionALU(uint3, uint3, uint4) -> void; @@ -108,6 +109,7 @@ struct ARM7TDMI { auto thumbInstructionShiftImmediate(uint3, uint3, uint5, uint2) -> void; auto thumbInstructionSoftwareInterrupt(uint8) -> void; auto thumbInstructionStackMultiple(uint8, uint1, uint1) -> void; + auto thumbInstructionUndefined() -> void; //serialization.cpp auto serialize(serializer&) -> void; @@ -117,9 +119,8 @@ struct ARM7TDMI { auto disassembleRegisters() -> string; struct GPR { - inline operator uint32_t() const { - return data; - } + inline operator uint32_t() const { return data; } + inline auto operator=(const GPR& value) -> GPR& { return operator=(value.data); } inline auto operator=(uint32 value) -> GPR& { data = value; @@ -127,12 +128,6 @@ struct ARM7TDMI { return *this; } - inline auto operator=(const GPR& value) -> GPR& { - data = value.data; - if(modify) modify(); - return *this; - } - uint32 data; function void> modify; }; @@ -217,6 +212,7 @@ struct ARM7TDMI { struct Instruction { uint32 address; uint32 instruction; + boolean thumb; //not used by fetch stage }; uint1 reload = 1; @@ -230,11 +226,8 @@ struct ARM7TDMI { boolean carry; boolean irq; - function armInstruction[4096]; - function thumbInstruction[65536]; - - function armDisassemble[4096]; - function thumbDisassemble[65536]; + function void> armInstruction[4096]; + function void> thumbInstruction[65536]; //disassembler.cpp auto armDisassembleBranch(int24, uint1) -> string; @@ -256,6 +249,7 @@ struct ARM7TDMI { auto armDisassembleMultiply(uint4, uint4, uint4, uint4, uint1, uint1) -> string; auto armDisassembleMultiplyLong(uint4, uint4, uint4, uint4, uint1, uint1, uint1) -> string; auto armDisassembleSoftwareInterrupt(uint24) -> string; + auto armDisassembleUndefined() -> string; auto thumbDisassembleALU(uint3, uint3, uint4) -> string; auto thumbDisassembleALUExtended(uint4, uint4, uint2) -> string; @@ -279,6 +273,10 @@ struct ARM7TDMI { auto thumbDisassembleShiftImmediate(uint3, uint3, uint5, uint2) -> string; auto thumbDisassembleSoftwareInterrupt(uint8) -> string; auto thumbDisassembleStackMultiple(uint8, uint1, uint1) -> string; + auto thumbDisassembleUndefined() -> string; + + function string> armDisassemble[4096]; + function string> thumbDisassemble[65536]; uint32 _pc; string _c; diff --git a/higan/processor/arm7tdmi/disassembler.cpp b/higan/processor/arm7tdmi/disassembler.cpp index 0af6714b..104b4cd8 100644 --- a/higan/processor/arm7tdmi/disassembler.cpp +++ b/higan/processor/arm7tdmi/disassembler.cpp @@ -20,10 +20,10 @@ auto ARM7TDMI::disassemble(maybe pc, maybe thumb) -> string { uint32 opcode = read(Word | Nonsequential, _pc & ~3); uint12 index = (opcode & 0x0ff00000) >> 16 | (opcode & 0x000000f0) >> 4; _c = _conditions[opcode >> 28]; - return armDisassemble[index](opcode); + return {hex(_pc, 8L), " ", armDisassemble[index](opcode)}; } else { uint16 opcode = read(Half | Nonsequential, _pc & ~1); - return thumbDisassemble[opcode](); + return {hex(_pc, 8L), " ", thumbDisassemble[opcode]()}; } } @@ -258,6 +258,11 @@ auto ARM7TDMI::armDisassembleSoftwareInterrupt return {"swi #0x", hex(immediate, 6L)}; } +auto ARM7TDMI::armDisassembleUndefined +() -> string { + return {"undefined"}; +} + // auto ARM7TDMI::thumbDisassembleALU @@ -397,6 +402,11 @@ auto ARM7TDMI::thumbDisassembleStackMultiple return {!mode ? "push" : "pop", " {", registers, "}"}; } +auto ARM7TDMI::thumbDisassembleUndefined +() -> string { + return {"undefined"}; +} + #undef _s #undef _move #undef _comp diff --git a/higan/processor/arm7tdmi/instruction.cpp b/higan/processor/arm7tdmi/instruction.cpp index 11245f3d..3fedc2b8 100644 --- a/higan/processor/arm7tdmi/instruction.cpp +++ b/higan/processor/arm7tdmi/instruction.cpp @@ -1,6 +1,7 @@ auto ARM7TDMI::fetch() -> void { pipeline.execute = pipeline.decode; pipeline.decode = pipeline.fetch; + pipeline.decode.thumb = cpsr().t; uint sequential = Sequential; if(pipeline.nonsequential) { @@ -30,14 +31,13 @@ auto ARM7TDMI::instruction() -> void { fetch(); if(irq && !cpsr().i) { - bool t = cpsr().t; - interrupt(PSR::IRQ, 0x18); - if(t) r(14).data += 2; + exception(PSR::IRQ, 0x18); + if(pipeline.execute.thumb) r(14).data += 2; return; } opcode = pipeline.execute.instruction; - if(!cpsr().t) { + if(!pipeline.execute.thumb) { if(!TST(opcode.bits(28,31))) return; uint12 index = (opcode & 0x0ff00000) >> 16 | (opcode & 0x000000f0) >> 4; armInstruction[index](opcode); @@ -46,9 +46,9 @@ auto ARM7TDMI::instruction() -> void { } } -auto ARM7TDMI::interrupt(uint mode, uint32 address) -> void { +auto ARM7TDMI::exception(uint mode, uint32 address) -> void { auto psr = cpsr(); - cpsr().m = 0x10 | mode; + cpsr().m = mode; spsr() = psr; cpsr().t = 0; if(cpsr().m == PSR::FIQ) cpsr().f = 1; @@ -353,6 +353,14 @@ auto ARM7TDMI::armInitialize() -> void { } #undef arguments + #define arguments + for(uint12 id : range(4096)) { + if(armInstruction[id]) continue; + auto opcode = pattern(".... ???? ???? ---- ---- ---- ???? ----") | id.bits(0,3) << 4 | id.bits(4,11) << 20; + bind(opcode, Undefined); + } + #undef arguments + #undef bind #undef pattern } @@ -519,6 +527,12 @@ auto ARM7TDMI::thumbInitialize() -> void { bind(opcode, StackMultiple, list, lrpc, mode); } + for(uint16 id : range(65536)) { + if(thumbInstruction[id]) continue; + auto opcode = pattern("???? ???? ???? ????") | id << 0; + bind(opcode, Undefined); + } + #undef bind #undef pattern } diff --git a/higan/processor/arm7tdmi/instructions-arm.cpp b/higan/processor/arm7tdmi/instructions-arm.cpp index 5cb1d503..dadfb3b6 100644 --- a/higan/processor/arm7tdmi/instructions-arm.cpp +++ b/higan/processor/arm7tdmi/instructions-arm.cpp @@ -304,5 +304,10 @@ auto ARM7TDMI::armInstructionMultiplyLong auto ARM7TDMI::armInstructionSoftwareInterrupt (uint24 immediate) -> void { - interrupt(PSR::SVC, 0x08); + exception(PSR::SVC, 0x08); +} + +auto ARM7TDMI::armInstructionUndefined +() -> void { + exception(PSR::UND, 0x04); } diff --git a/higan/processor/arm7tdmi/instructions-thumb.cpp b/higan/processor/arm7tdmi/instructions-thumb.cpp index 0585bdb0..628a5dc6 100644 --- a/higan/processor/arm7tdmi/instructions-thumb.cpp +++ b/higan/processor/arm7tdmi/instructions-thumb.cpp @@ -32,7 +32,7 @@ auto ARM7TDMI::thumbInstructionALUExtended auto ARM7TDMI::thumbInstructionAddRegister (uint8 immediate, uint3 d, uint1 mode) -> void { switch(mode) { - case 0: r(d) = (r(15) & ~2) + immediate * 4; break; //ADD pc (todo: is this really &~2 and not &~3?) + case 0: r(d) = (r(15) & ~3) + immediate * 4; break; //ADD pc case 1: r(d) = r(13) + immediate * 4; break; //ADD sp } } @@ -180,7 +180,7 @@ auto ARM7TDMI::thumbInstructionShiftImmediate auto ARM7TDMI::thumbInstructionSoftwareInterrupt (uint8 immediate) -> void { - interrupt(PSR::SVC, 0x08); + exception(PSR::SVC, 0x08); } auto ARM7TDMI::thumbInstructionStackMultiple @@ -203,9 +203,9 @@ auto ARM7TDMI::thumbInstructionStackMultiple } if(lrpc) { - switch(mode) { //todo: is this really always nonsequential? - case 0: write(Word | Nonsequential, sp, r(14)); break; //PUSH - case 1: r(15) = read(Word | Nonsequential, sp); break; //POP + switch(mode) { + case 0: write(Word | sequential, sp, r(14)); break; //PUSH + case 1: r(15) = read(Word | sequential, sp); break; //POP } sp += 4; } @@ -218,3 +218,8 @@ auto ARM7TDMI::thumbInstructionStackMultiple r(13) = r(13) - (bit::count(list) + lrpc) * 4; //PUSH } } + +auto ARM7TDMI::thumbInstructionUndefined +() -> void { + exception(PSR::UND, 0x04); +} diff --git a/higan/processor/arm7tdmi/serialization.cpp b/higan/processor/arm7tdmi/serialization.cpp index 6afbefed..b80a2e8e 100644 --- a/higan/processor/arm7tdmi/serialization.cpp +++ b/higan/processor/arm7tdmi/serialization.cpp @@ -61,8 +61,11 @@ auto ARM7TDMI::Pipeline::serialize(serializer& s) -> void { s.integer(nonsequential); s.integer(fetch.address); s.integer(fetch.instruction); + s.boolean(fetch.thumb); s.integer(decode.address); s.integer(decode.instruction); + s.boolean(decode.thumb); s.integer(execute.address); s.integer(execute.instruction); + s.boolean(execute.thumb); } diff --git a/higan/systems/Mega Drive.sys/manifest.bml b/higan/systems/Mega Drive.sys/manifest.bml index 016eab93..87e751e3 100644 --- a/higan/systems/Mega Drive.sys/manifest.bml +++ b/higan/systems/Mega Drive.sys/manifest.bml @@ -1 +1,3 @@ system name:Mega Drive + cpu version=0 + rom name=tmss.rom size=0x800 diff --git a/higan/systems/Mega Drive.sys/tmss.rom b/higan/systems/Mega Drive.sys/tmss.rom new file mode 100644 index 0000000000000000000000000000000000000000..72b946eb8beae8ae1665d613fbcd852f3425a8e0 GIT binary patch literal 2048 zcmd^A&ubGw6n?V}Z4OeiHMCTa4pAhPT2~L6mOv9~C}Ld+MW~37+H69#wqetVKYBU6G3(%J^b9UF^Be8|g zBk8wdBU()Wl+Tu9;a~t*4)>M7BQ093VR?6Yj+fK##FmT+-93c6_hRdQOV@SK(;viU zCXQ5$8^T@~zzbY1>1Z7QHC)#q5C|LbwrN~ryOndmFpA#K^7GeUMRKDC!<*1Kx;p>U zh{KSvntmg;%;g$nwmBA@dIBv-T&LP$DS^64Mw(K430UwGz^i2j`N%T<=7I-ekYs^; zIQSSK)G0e}JyxaMW{G^}OFZ|7(dsA%II);s!Cd5d7OPgyWB&LA$5p`3q#Om{iT-gu zZhkxyf4YKawvBcEHcPRPC?gYVBnFzF+o zcy2Cl?ecfWiHyVHQ~kuN*G_(k`*Swb$|Q~yB>u%n0Qt?vLiqUfF*9mNqbgL+-Pua5 zksrdkaj&z6dysjlC-h-HT}NZoU%f}tulMigdi|5Gs>g{XO~-cUs~m29e!kZmY5Mt2 zE!3UN*TCQFe7)LSo;$mIcduqrmwNc8DDyYsbbeGXJ?Qu0bc*!;Dr^Ui@t(H(KA?be zj_6=cUNtGdEMdow`^FHUMIsOZjYrfPJ-F65`4uiP+C^k6&Q2^>IPM)jDoL*5OB^90 zN<&ro$el`npVxvtn=MURS$^XlpS1-q&15Z`Pftx+GewK%?AhC*XyqsRteH8>F4$8= vtH`J4vJb%M#_y;GFt{kcY^CUe4ISOLf;r7B4OTM0S{LXNGHdv6;Gc~@Fa0oj literal 0 HcmV?d00001 diff --git a/higan/target-tomoko/configuration/configuration.cpp b/higan/target-tomoko/configuration/configuration.cpp index 14d736ec..ece53405 100644 --- a/higan/target-tomoko/configuration/configuration.cpp +++ b/higan/target-tomoko/configuration/configuration.cpp @@ -15,6 +15,7 @@ Settings::Settings() { set("Library/IgnoreManifests", false); set("Video/Driver", ruby::Video::optimalDriver()); + set("Video/Driver/Crashed", false); set("Video/Synchronize", false); set("Video/Shader", "Blur"); set("Video/BlurEmulation", true); @@ -41,6 +42,7 @@ Settings::Settings() { set("Video/Fullscreen/Exclusive", false); set("Audio/Driver", ruby::Audio::optimalDriver()); + set("Audio/Driver/Crashed", false); set("Audio/Device", ""); set("Audio/Frequency", 48000); set("Audio/Latency", 0); @@ -52,11 +54,12 @@ Settings::Settings() { set("Audio/Reverb/Enable", false); set("Input/Driver", ruby::Input::optimalDriver()); + set("Input/Driver/Crashed", false); set("Input/Frequency", 5); set("Input/FocusLoss/Pause", false); set("Input/FocusLoss/AllowInput", false); } -auto Settings::quit() -> void { +auto Settings::save() -> void { file::write(locate("settings.bml"), BML::serialize(*this)); } diff --git a/higan/target-tomoko/configuration/configuration.hpp b/higan/target-tomoko/configuration/configuration.hpp index 1ef04b21..892e14c8 100644 --- a/higan/target-tomoko/configuration/configuration.hpp +++ b/higan/target-tomoko/configuration/configuration.hpp @@ -1,6 +1,6 @@ struct Settings : Markup::Node { Settings(); - auto quit() -> void; + auto save() -> void; }; extern Settings settings; diff --git a/higan/target-tomoko/program/program.cpp b/higan/target-tomoko/program/program.cpp index a729c2c9..9f88e643 100644 --- a/higan/target-tomoko/program/program.cpp +++ b/higan/target-tomoko/program/program.cpp @@ -33,12 +33,26 @@ Program::Program(string_vector args) { new Presentation; presentation->setVisible(); + if(settings["Video/Driver/Crashed"].boolean()) { + settings["Video/Driver"].setValue("None"); + MessageDialog().setText("Video driver crash detected. Driver has been reset to 'None'").information(); + } + settings["Video/Driver/Crashed"].setValue(true); + settings.save(); video = Video::create(settings["Video/Driver"].text()); video->setContext(presentation->viewport.handle()); video->setBlocking(settings["Video/Synchronize"].boolean()); if(!video->ready()) MessageDialog().setText("Failed to initialize video driver").warning(); + settings["Video/Driver/Crashed"].setValue(false); + settings.save(); presentation->clearViewport(); + if(settings["Audio/Driver/Crashed"].boolean()) { + settings["Audio/Driver"].setValue("None"); + MessageDialog().setText("Audio driver crash detected. Driver has been reset to 'None'").information(); + } + settings["Audio/Driver/Crashed"].setValue(true); + settings.save(); audio = Audio::create(settings["Audio/Driver"].text()); audio->setExclusive(settings["Audio/Exclusive"].boolean()); audio->setContext(presentation->viewport.handle()); @@ -46,11 +60,21 @@ Program::Program(string_vector args) { audio->setBlocking(settings["Audio/Synchronize"].boolean()); audio->setChannels(2); if(!audio->ready()) MessageDialog().setText("Failed to initialize audio driver").warning(); + settings["Audio/Driver/Crashed"].setValue(false); + settings.save(); + if(settings["Input/Driver/Crashed"].boolean()) { + settings["Input/Driver"].setValue("None"); + MessageDialog().setText("Input driver crash detected. Driver has been reset to 'None'").information(); + } + settings["Input/Driver/Crashed"].setValue(true); + settings.save(); input = Input::create(settings["Input/Driver"].text()); input->setContext(presentation->viewport.handle()); input->onChange({&InputManager::onChange, &inputManager()}); if(!input->ready()) MessageDialog().setText("Failed to initialize input driver").warning(); + settings["Input/Driver/Crashed"].setValue(false); + settings.save(); new InputManager; new SettingsManager; @@ -97,7 +121,7 @@ auto Program::main() -> void { auto Program::quit() -> void { hasQuit = true; unloadMedium(); - settings.quit(); + settings.save(); inputManager->quit(); video.reset(); audio.reset();