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:
Tim Allen 2017-08-12 02:02:09 +10:00
parent 406b6a61a5
commit 55f19c3e0d
37 changed files with 292 additions and 213 deletions

View File

@ -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/";

View File

@ -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)

View File

@ -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);

View File

@ -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;

51
higan/md/apu/bus.cpp Normal file
View File

@ -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 {
}

View File

@ -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);

View File

@ -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;

View File

@ -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);
}

View File

@ -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 {
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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>

View File

@ -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);

View File

@ -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") {

View File

@ -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)++;

View File

@ -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)

View File

@ -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;

View File

@ -1,5 +0,0 @@
auto Bus::serialize(serializer& s) -> void {
Processor::Z80::Bus::serialize(s);
s.array(ram);
}

View File

@ -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 {
}
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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);
}

View File

@ -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>

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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

View File

@ -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
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -1 +1,3 @@
system name:Mega Drive
cpu version=0
rom name=tmss.rom size=0x800

Binary file not shown.

View File

@ -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));
}

View File

@ -1,6 +1,6 @@
struct Settings : Markup::Node {
Settings();
auto quit() -> void;
auto save() -> void;
};
extern Settings settings;

View File

@ -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();