mirror of https://github.com/bsnes-emu/bsnes.git
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
This commit is contained in:
parent
406b6a61a5
commit
55f19c3e0d
|
@ -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/";
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
|
@ -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);
|
||||
}
|
|
@ -1,14 +1,9 @@
|
|||
#include <md/md.hpp>
|
||||
|
||||
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 {
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<Thread*> 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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -55,7 +55,6 @@ namespace MegaDrive {
|
|||
|
||||
#include <md/system/system.hpp>
|
||||
#include <md/cartridge/cartridge.hpp>
|
||||
#include <md/bus/bus.hpp>
|
||||
}
|
||||
|
||||
#include <md/interface/interface.hpp>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -27,6 +27,8 @@ auto System::load(Emulator::Interface* interface, maybe<Region> 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") {
|
||||
|
|
|
@ -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)++;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
|
@ -1,5 +0,0 @@
|
|||
auto Bus::serialize(serializer& s) -> void {
|
||||
Processor::Z80::Bus::serialize(s);
|
||||
|
||||
s.array(ram);
|
||||
}
|
|
@ -1,28 +1,27 @@
|
|||
#include <ms/ms.hpp>
|
||||
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 {
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Thread*> peripherals;
|
||||
|
||||
private:
|
||||
uint8 ram[8 * 1024];
|
||||
|
||||
struct State {
|
||||
bool nmiLine;
|
||||
bool intLine;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@ namespace MasterSystem {
|
|||
|
||||
#include <ms/system/system.hpp>
|
||||
#include <ms/cartridge/cartridge.hpp>
|
||||
#include <ms/bus/bus.hpp>
|
||||
}
|
||||
|
||||
#include <ms/interface/interface.hpp>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<auto () -> 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<void (uint32 opcode)> armInstruction[4096];
|
||||
function<void ()> thumbInstruction[65536];
|
||||
|
||||
function<string (uint32 opcode)> armDisassemble[4096];
|
||||
function<string ()> thumbDisassemble[65536];
|
||||
function<auto (uint32 opcode) -> void> armInstruction[4096];
|
||||
function<auto () -> 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<auto (uint32 opcode) -> string> armDisassemble[4096];
|
||||
function<auto () -> string> thumbDisassemble[65536];
|
||||
|
||||
uint32 _pc;
|
||||
string _c;
|
||||
|
|
|
@ -20,10 +20,10 @@ auto ARM7TDMI::disassemble(maybe<uint32> pc, maybe<boolean> 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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
system name:Mega Drive
|
||||
cpu version=0
|
||||
rom name=tmss.rom size=0x800
|
||||
|
|
Binary file not shown.
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
struct Settings : Markup::Node {
|
||||
Settings();
|
||||
auto quit() -> void;
|
||||
auto save() -> void;
|
||||
};
|
||||
|
||||
extern Settings settings;
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue