mirror of https://github.com/bsnes-emu/bsnes.git
Update to v101r10 release.
byuu says: Changelog: - 68K: MOVEQ is 8-bit signed - 68K: disassembler was print EOR for OR instructions - 68K: address/program-counter indexed mode had the signed-word/long bit backward - 68K: ADDQ/SUBQ #n,aN always works in long mode; regardless of size - 68K→VDP DMA needs to use `mode.bit(0)<<22|dmaSource`; increment by one instead of two - Z80: added registers and initial two instructions - MS: hooked up enough to load and start running games - Sonic the Hedgehog can execute exactly one instruction... whoo.
This commit is contained in:
parent
4d2e17f9c0
commit
0b70a01b47
|
@ -12,7 +12,7 @@ using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "101.09";
|
static const string Version = "101.10";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
static const string Website = "http://byuu.org/";
|
||||||
|
|
|
@ -17,6 +17,19 @@ auto APU::step(uint clocks) -> void {
|
||||||
synchronize(cpu);
|
synchronize(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto APU::wait() -> void {
|
||||||
|
step(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto APU::read(uint16 addr) -> uint8 {
|
||||||
|
step(1);
|
||||||
|
return 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto APU::write(uint16 addr, uint8 data) -> void {
|
||||||
|
step(1);
|
||||||
|
}
|
||||||
|
|
||||||
auto APU::power() -> void {
|
auto APU::power() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,10 @@ struct APU : Processor::Z80, Thread {
|
||||||
auto main() -> void;
|
auto main() -> void;
|
||||||
auto step(uint clocks) -> void;
|
auto step(uint clocks) -> void;
|
||||||
|
|
||||||
|
auto wait() -> void override;
|
||||||
|
auto read(uint16 addr) -> uint8 override;
|
||||||
|
auto write(uint16 addr, uint8 data) -> void override;
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,7 +17,7 @@ auto CPU::boot() -> void {
|
||||||
auto CPU::main() -> void {
|
auto CPU::main() -> void {
|
||||||
#if 0
|
#if 0
|
||||||
static file fp;
|
static file fp;
|
||||||
if(!fp) fp.open({Path::user(), "Desktop/trace.log"}, file::mode::write);
|
if(!fp) fp.open({Path::user(), "Desktop/tracer.log"}, file::mode::write);
|
||||||
fp.print(pad(disassemble(r.pc), -60, ' '), " ", disassembleRegisters().replace("\n", " "), "\n");
|
fp.print(pad(disassemble(r.pc), -60, ' '), " ", disassembleRegisters().replace("\n", " "), "\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ auto CPU::reset() -> void {
|
||||||
auto CPU::readByte(uint24 addr) -> uint8 {
|
auto CPU::readByte(uint24 addr) -> uint8 {
|
||||||
if(addr < 0x400000) return cartridge.readByte(addr);
|
if(addr < 0x400000) return cartridge.readByte(addr);
|
||||||
if(addr < 0xa00000) return 0x00;
|
if(addr < 0xa00000) return 0x00;
|
||||||
if(addr < 0xc00000) return rand();
|
if(addr < 0xc00000) return rand(), 0;
|
||||||
if(addr < 0xe00000) return vdp.readByte(addr);
|
if(addr < 0xe00000) return vdp.readByte(addr);
|
||||||
return ram[addr & 0xffff];
|
return ram[addr & 0xffff];
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ auto CPU::readByte(uint24 addr) -> uint8 {
|
||||||
auto CPU::readWord(uint24 addr) -> uint16 {
|
auto CPU::readWord(uint24 addr) -> uint16 {
|
||||||
if(addr < 0x400000) return cartridge.readWord(addr);
|
if(addr < 0x400000) return cartridge.readWord(addr);
|
||||||
if(addr < 0xa00000) return 0x0000;
|
if(addr < 0xa00000) return 0x0000;
|
||||||
if(addr < 0xc00000) return rand();
|
if(addr < 0xc00000) return rand(), 0;
|
||||||
if(addr < 0xe00000) return vdp.readWord(addr);
|
if(addr < 0xe00000) return vdp.readWord(addr);
|
||||||
uint16 data = ram[addr + 0 & 65535] << 8;
|
uint16 data = ram[addr + 0 & 65535] << 8;
|
||||||
return data | ram[addr + 1 & 65535] << 0;
|
return data | ram[addr + 1 & 65535] << 0;
|
||||||
|
|
|
@ -10,10 +10,10 @@ auto VDP::dmaRun() -> void {
|
||||||
auto VDP::dmaLoad() -> void {
|
auto VDP::dmaLoad() -> void {
|
||||||
cpu.wait |= Wait::VDP_DMA;
|
cpu.wait |= Wait::VDP_DMA;
|
||||||
|
|
||||||
auto data = cpu.readWord(io.dmaSource);
|
auto data = cpu.readWord(io.dmaMode.bit(0) << 23 | io.dmaSource << 1);
|
||||||
writeDataPort(data);
|
writeDataPort(data);
|
||||||
|
|
||||||
io.dmaSource.bits(0,15) += 2;
|
io.dmaSource.bits(0,15)++;
|
||||||
if(--io.dmaLength == 0) {
|
if(--io.dmaLength == 0) {
|
||||||
io.command.bit(5) = 0;
|
io.command.bit(5) = 0;
|
||||||
cpu.wait &=~ Wait::VDP_DMA;
|
cpu.wait &=~ Wait::VDP_DMA;
|
||||||
|
|
|
@ -4,4 +4,86 @@ namespace MasterSystem {
|
||||||
|
|
||||||
Cartridge cartridge;
|
Cartridge cartridge;
|
||||||
|
|
||||||
|
auto Cartridge::load() -> bool {
|
||||||
|
information = {};
|
||||||
|
|
||||||
|
switch(system.model()) {
|
||||||
|
case Model::MasterSystem:
|
||||||
|
if(auto pathID = interface->load(ID::MasterSystem, "Master System", "ms")) {
|
||||||
|
information.pathID = pathID();
|
||||||
|
} else return false;
|
||||||
|
break;
|
||||||
|
case Model::GameGear:
|
||||||
|
if(auto pathID = interface->load(ID::GameGear, "Game Gear", "gg")) {
|
||||||
|
information.pathID = pathID();
|
||||||
|
} else return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(auto fp = interface->open(pathID(), "manifest.bml", File::Read, File::Required)) {
|
||||||
|
information.manifest = fp->reads();
|
||||||
|
} else return false;
|
||||||
|
|
||||||
|
auto document = BML::unserialize(information.manifest);
|
||||||
|
information.title = document["information/title"].text();
|
||||||
|
|
||||||
|
if(auto node = document["board/rom"]) {
|
||||||
|
rom.size = node["size"].natural();
|
||||||
|
rom.mask = bit::round(rom.size) - 1;
|
||||||
|
if(rom.size) {
|
||||||
|
rom.data = new uint8[rom.mask + 1];
|
||||||
|
if(auto name = node["name"].text()) {
|
||||||
|
if(auto fp = interface->open(pathID(), name, File::Read, File::Required)) {
|
||||||
|
fp->read(rom.data, rom.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(auto node = document["board/ram"]) {
|
||||||
|
ram.size = node["size"].natural();
|
||||||
|
ram.mask = bit::round(ram.size) - 1;
|
||||||
|
if(ram.size) {
|
||||||
|
ram.data = new uint8[ram.mask + 1];
|
||||||
|
if(auto name = node["name"].text()) {
|
||||||
|
if(auto fp = interface->open(pathID(), name, File::Read)) {
|
||||||
|
fp->read(ram.data, ram.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Cartridge::save() -> void {
|
||||||
|
auto document = BML::unserialize(information.manifest);
|
||||||
|
|
||||||
|
if(auto name = document["board/ram/name"].text()) {
|
||||||
|
if(auto fp = interface->open(pathID(), name, File::Write)) {
|
||||||
|
fp->write(ram.data, ram.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Cartridge::unload() -> void {
|
||||||
|
delete[] rom.data;
|
||||||
|
delete[] ram.data;
|
||||||
|
rom = {};
|
||||||
|
ram = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Cartridge::read(uint16 addr) -> uint8 {
|
||||||
|
return rom.data[addr & rom.mask];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Cartridge::write(uint16 addr, uint8 data) -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Cartridge::power() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Cartridge::reset() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,35 @@
|
||||||
struct Cartridge {
|
struct Cartridge {
|
||||||
|
auto pathID() const -> uint { return information.pathID; }
|
||||||
|
auto sha256() const -> string { return information.sha256; }
|
||||||
|
auto manifest() const -> string { return information.manifest; }
|
||||||
|
auto title() const -> string { return information.title; }
|
||||||
|
|
||||||
|
auto load() -> bool;
|
||||||
|
auto save() -> void;
|
||||||
|
auto unload() -> void;
|
||||||
|
|
||||||
|
auto read(uint16 addr) -> uint8;
|
||||||
|
auto write(uint16 addr, uint8 data) -> void;
|
||||||
|
|
||||||
|
auto power() -> void;
|
||||||
|
auto reset() -> void;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Information {
|
||||||
|
uint pathID = 0;
|
||||||
|
string sha256;
|
||||||
|
string manifest;
|
||||||
|
string title;
|
||||||
|
} information;
|
||||||
|
|
||||||
|
struct Memory {
|
||||||
|
uint8* data = nullptr;
|
||||||
|
uint size = 0;
|
||||||
|
uint mask = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
Memory rom;
|
||||||
|
Memory ram;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Cartridge cartridge;
|
extern Cartridge cartridge;
|
||||||
|
|
|
@ -9,10 +9,36 @@ auto CPU::Enter() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::main() -> void {
|
auto CPU::main() -> void {
|
||||||
|
instruction();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::step(uint clocks) -> void {
|
auto CPU::step(uint clocks) -> void {
|
||||||
Thread::step(clocks);
|
Thread::step(clocks);
|
||||||
|
synchronize(vdp);
|
||||||
|
synchronize(psg);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::wait() -> void {
|
||||||
|
step(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::read(uint16 addr) -> uint8 {
|
||||||
|
step(1);
|
||||||
|
if(addr < 0xc000) return cartridge.read(addr);
|
||||||
|
return ram[addr & 0x1fff];
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::write(uint16 addr, uint8 data) -> void {
|
||||||
|
step(1);
|
||||||
|
if(addr < 0xc000) return cartridge.write(addr, data);
|
||||||
|
ram[addr & 0x1fff] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::power() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::reset() -> void {
|
||||||
|
create(CPU::Enter, system.colorburst());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,16 @@ struct CPU : Processor::Z80, Thread {
|
||||||
static auto Enter() -> void;
|
static auto Enter() -> void;
|
||||||
auto main() -> void;
|
auto main() -> void;
|
||||||
auto step(uint clocks) -> void;
|
auto step(uint clocks) -> void;
|
||||||
|
|
||||||
|
auto wait() -> void override;
|
||||||
|
auto read(uint16 addr) -> uint8 override;
|
||||||
|
auto write(uint16 addr, uint8 data) -> void override;
|
||||||
|
|
||||||
|
auto power() -> void;
|
||||||
|
auto reset() -> void;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 ram[0x2000]; //8KB
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CPU cpu;
|
extern CPU cpu;
|
||||||
|
|
|
@ -32,25 +32,29 @@ Interface::Interface() {
|
||||||
controllerPort1.devices.append(device);
|
controllerPort1.devices.append(device);
|
||||||
controllerPort2.devices.append(device);
|
controllerPort2.devices.append(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ports.append(move(controllerPort1));
|
||||||
|
ports.append(move(controllerPort2));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::manifest() -> string {
|
auto Interface::manifest() -> string {
|
||||||
return "";
|
return cartridge.manifest();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::title() -> string {
|
auto Interface::title() -> string {
|
||||||
return "";
|
return cartridge.title();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::videoSize() -> VideoSize {
|
auto Interface::videoSize() -> VideoSize {
|
||||||
return {256, 192};
|
return {256, 240};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::videoSize(uint width, uint height, bool arc) -> VideoSize {
|
auto Interface::videoSize(uint width, uint height, bool arc) -> VideoSize {
|
||||||
|
auto a = arc ? 8.0 / 7.0 : 1.0;
|
||||||
uint w = 256;
|
uint w = 256;
|
||||||
uint h = 192;
|
uint h = 240;
|
||||||
uint m = min(width / w, height / h);
|
uint m = min(width / (w * a), height / h);
|
||||||
return {w * m, h * m};
|
return {uint(w * a * m), uint(h * m)};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::videoFrequency() -> double {
|
auto Interface::videoFrequency() -> double {
|
||||||
|
@ -70,26 +74,33 @@ auto Interface::audioFrequency() -> double {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::loaded() -> bool {
|
auto Interface::loaded() -> bool {
|
||||||
return false;
|
return system.loaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::load(uint id) -> bool {
|
auto Interface::load(uint id) -> bool {
|
||||||
|
if(id == ID::MasterSystem) return system.load(Model::MasterSystem);
|
||||||
|
if(id == ID::GameGear) return system.load(Model::GameGear);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::save() -> void {
|
auto Interface::save() -> void {
|
||||||
|
system.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::unload() -> void {
|
auto Interface::unload() -> void {
|
||||||
|
system.unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::power() -> void {
|
auto Interface::power() -> void {
|
||||||
|
system.power();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::reset() -> void {
|
auto Interface::reset() -> void {
|
||||||
|
system.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::run() -> void {
|
auto Interface::run() -> void {
|
||||||
|
system.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Interface::serialize() -> serializer {
|
auto Interface::serialize() -> serializer {
|
||||||
|
|
|
@ -14,6 +14,11 @@ namespace MasterSystem {
|
||||||
using Scheduler = Emulator::Scheduler;
|
using Scheduler = Emulator::Scheduler;
|
||||||
extern Scheduler scheduler;
|
extern Scheduler scheduler;
|
||||||
|
|
||||||
|
enum class Model : uint {
|
||||||
|
MasterSystem,
|
||||||
|
GameGear,
|
||||||
|
};
|
||||||
|
|
||||||
struct Thread : Emulator::Thread {
|
struct Thread : Emulator::Thread {
|
||||||
auto create(auto (*entrypoint)() -> void, double frequency) -> void {
|
auto create(auto (*entrypoint)() -> void, double frequency) -> void {
|
||||||
Emulator::Thread::create(entrypoint, frequency);
|
Emulator::Thread::create(entrypoint, frequency);
|
||||||
|
|
|
@ -9,10 +9,19 @@ auto PSG::Enter() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PSG::main() -> void {
|
auto PSG::main() -> void {
|
||||||
|
step(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PSG::step(uint clocks) -> void {
|
auto PSG::step(uint clocks) -> void {
|
||||||
Thread::step(clocks);
|
Thread::step(clocks);
|
||||||
|
synchronize(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto PSG::power() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto PSG::reset() -> void {
|
||||||
|
create(PSG::Enter, system.colorburst());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,9 @@ struct PSG : Thread {
|
||||||
static auto Enter() -> void;
|
static auto Enter() -> void;
|
||||||
auto main() -> void;
|
auto main() -> void;
|
||||||
auto step(uint clocks) -> void;
|
auto step(uint clocks) -> void;
|
||||||
|
|
||||||
|
auto power() -> void;
|
||||||
|
auto reset() -> void;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern PSG psg;
|
extern PSG psg;
|
||||||
|
|
|
@ -6,22 +6,54 @@ System system;
|
||||||
Scheduler scheduler;
|
Scheduler scheduler;
|
||||||
|
|
||||||
auto System::run() -> void {
|
auto System::run() -> void {
|
||||||
|
if(scheduler.enter() == Scheduler::Event::Frame) vdp.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::load() -> bool {
|
auto System::load(Model model) -> bool {
|
||||||
return false;
|
information = {};
|
||||||
|
information.model = model;
|
||||||
|
|
||||||
|
if(auto fp = interface->open(ID::System, "manifest.bml", File::Read, File::Required)) {
|
||||||
|
information.manifest = fp->reads();
|
||||||
|
} else return false;
|
||||||
|
|
||||||
|
auto document = BML::unserialize(information.manifest);
|
||||||
|
if(!cartridge.load()) return false;
|
||||||
|
|
||||||
|
information.colorburst = Emulator::Constants::Colorburst::NTSC;
|
||||||
|
return information.loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::save() -> void {
|
auto System::save() -> void {
|
||||||
|
cartridge.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::unload() -> void {
|
auto System::unload() -> void {
|
||||||
|
cartridge.unload();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::power() -> void {
|
auto System::power() -> void {
|
||||||
|
cartridge.power();
|
||||||
|
cpu.power();
|
||||||
|
vdp.power();
|
||||||
|
psg.power();
|
||||||
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto System::reset() -> void {
|
auto System::reset() -> void {
|
||||||
|
Emulator::video.reset();
|
||||||
|
Emulator::video.setInterface(interface);
|
||||||
|
Emulator::video.setPalette();
|
||||||
|
|
||||||
|
Emulator::audio.reset();
|
||||||
|
Emulator::audio.setInterface(interface);
|
||||||
|
|
||||||
|
scheduler.reset();
|
||||||
|
cartridge.reset();
|
||||||
|
cpu.reset();
|
||||||
|
vdp.reset();
|
||||||
|
psg.reset();
|
||||||
|
scheduler.primary(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,24 @@
|
||||||
struct System {
|
struct System {
|
||||||
auto loaded() const -> bool { return false; }
|
auto loaded() const -> bool { return information.loaded; }
|
||||||
auto colorburst() const -> double { return 0.0; }
|
auto model() const -> Model { return information.model; }
|
||||||
|
auto colorburst() const -> double { return information.colorburst; }
|
||||||
|
|
||||||
auto run() -> void;
|
auto run() -> void;
|
||||||
|
|
||||||
auto load() -> bool;
|
auto load(Model model) -> bool;
|
||||||
auto save() -> void;
|
auto save() -> void;
|
||||||
auto unload() -> void;
|
auto unload() -> void;
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Information {
|
||||||
|
bool loaded = false;
|
||||||
|
Model model = Model::MasterSystem;
|
||||||
|
string manifest;
|
||||||
|
double colorburst = 0.0;
|
||||||
|
} information;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern System system;
|
extern System system;
|
||||||
|
|
|
@ -9,10 +9,28 @@ auto VDP::Enter() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VDP::main() -> void {
|
auto VDP::main() -> void {
|
||||||
|
for(uint y : range(262)) {
|
||||||
|
for(uint x : range(342)) {
|
||||||
|
step(1);
|
||||||
|
}
|
||||||
|
if(y == 240) scheduler.exit(Scheduler::Event::Frame);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VDP::step(uint clocks) -> void {
|
auto VDP::step(uint clocks) -> void {
|
||||||
Thread::step(clocks);
|
Thread::step(clocks);
|
||||||
|
synchronize(cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto VDP::refresh() -> void {
|
||||||
|
Emulator::video.refresh(buffer, 256 * sizeof(uint32), 256, 240);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto VDP::power() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto VDP::reset() -> void {
|
||||||
|
create(VDP::Enter, system.colorburst());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
//...
|
//TI TMS9918A (derivative)
|
||||||
|
|
||||||
struct VDP : Thread {
|
struct VDP : Thread {
|
||||||
static auto Enter() -> void;
|
static auto Enter() -> void;
|
||||||
auto main() -> void;
|
auto main() -> void;
|
||||||
auto step(uint clocks) -> void;
|
auto step(uint clocks) -> void;
|
||||||
|
auto refresh() -> void;
|
||||||
|
|
||||||
|
auto power() -> void;
|
||||||
|
auto reset() -> void;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32 buffer[256 * 240];
|
||||||
};
|
};
|
||||||
|
|
||||||
extern VDP vdp;
|
extern VDP vdp;
|
||||||
|
|
|
@ -432,11 +432,11 @@ template<uint Size> auto M68K::disassembleNOT(EffectiveAddress with) -> string {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<uint Size> auto M68K::disassembleOR(EffectiveAddress from, DataRegister with) -> string {
|
template<uint Size> auto M68K::disassembleOR(EffectiveAddress from, DataRegister with) -> string {
|
||||||
return {"eor", _suffix<Size>(), " ", _effectiveAddress<Size>(from), ",", _dataRegister(with)};
|
return {"or", _suffix<Size>(), " ", _effectiveAddress<Size>(from), ",", _dataRegister(with)};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<uint Size> auto M68K::disassembleOR(DataRegister from, EffectiveAddress with) -> string {
|
template<uint Size> auto M68K::disassembleOR(DataRegister from, EffectiveAddress with) -> string {
|
||||||
return {"eor", _suffix<Size>(), " ", _dataRegister(from), ",", _effectiveAddress<Size>(with)};
|
return {"or", _suffix<Size>(), " ", _dataRegister(from), ",", _effectiveAddress<Size>(with)};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<uint Size> auto M68K::disassembleORI(EffectiveAddress with) -> string {
|
template<uint Size> auto M68K::disassembleORI(EffectiveAddress with) -> string {
|
||||||
|
|
|
@ -32,7 +32,7 @@ template<uint Size> auto M68K::fetch(EffectiveAddress& ea) -> uint32 {
|
||||||
auto index = extension & 0x8000
|
auto index = extension & 0x8000
|
||||||
? read(AddressRegister{extension >> 12})
|
? read(AddressRegister{extension >> 12})
|
||||||
: read(DataRegister{extension >> 12});
|
: read(DataRegister{extension >> 12});
|
||||||
if(extension & 0x800) index = (int16)index;
|
if(!(extension & 0x800)) index = (int16)index;
|
||||||
return read(AddressRegister{ea.reg}) + index + (int8)extension;
|
return read(AddressRegister{ea.reg}) + index + (int8)extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ template<uint Size> auto M68K::fetch(EffectiveAddress& ea) -> uint32 {
|
||||||
auto index = extension & 0x8000
|
auto index = extension & 0x8000
|
||||||
? read(AddressRegister{extension >> 12})
|
? read(AddressRegister{extension >> 12})
|
||||||
: read(DataRegister{extension >> 12});
|
: read(DataRegister{extension >> 12});
|
||||||
if(extension & 0x800) index = (int16)index;
|
if(!(extension & 0x800)) index = (int16)index;
|
||||||
return base + index + (int8)extension;
|
return base + index + (int8)extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,8 +124,9 @@ template<uint Size> auto M68K::instructionADDQ(uint4 immediate, EffectiveAddress
|
||||||
write<Size>(with, result);
|
write<Size>(with, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Size is ignored: always uses Long
|
||||||
template<uint Size> auto M68K::instructionADDQ(uint4 immediate, AddressRegister with) -> void {
|
template<uint Size> auto M68K::instructionADDQ(uint4 immediate, AddressRegister with) -> void {
|
||||||
auto result = read<Size>(with) + immediate;
|
auto result = read<Long>(with) + immediate;
|
||||||
write<Long>(with, result);
|
write<Long>(with, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -687,7 +688,7 @@ template<uint Size> auto M68K::instructionMOVEP(EffectiveAddress from, DataRegis
|
||||||
}
|
}
|
||||||
|
|
||||||
auto M68K::instructionMOVEQ(DataRegister dr, uint8 immediate) -> void {
|
auto M68K::instructionMOVEQ(DataRegister dr, uint8 immediate) -> void {
|
||||||
write<Long>(dr, immediate);
|
write<Long>(dr, sign<Byte>(immediate));
|
||||||
|
|
||||||
r.c = 0;
|
r.c = 0;
|
||||||
r.v = 0;
|
r.v = 0;
|
||||||
|
@ -1093,9 +1094,10 @@ template<uint Size> auto M68K::instructionSUBQ(uint4 immediate, EffectiveAddress
|
||||||
write<Size>(with, result);
|
write<Size>(with, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Size is ignored: always uses Long
|
||||||
template<uint Size> auto M68K::instructionSUBQ(uint4 immediate, AddressRegister with) -> void {
|
template<uint Size> auto M68K::instructionSUBQ(uint4 immediate, AddressRegister with) -> void {
|
||||||
auto result = read<Size>(with) - immediate;
|
auto result = read<Long>(with) - immediate;
|
||||||
write<Size>(with, result);
|
write<Long>(with, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<uint Size> auto M68K::instructionSUBX(EffectiveAddress with, EffectiveAddress from) -> void {
|
template<uint Size> auto M68K::instructionSUBX(EffectiveAddress with, EffectiveAddress from) -> void {
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
#define op(id, name, ...) case id: return instruction##name(__VA_ARGS__);
|
||||||
|
|
||||||
|
auto Z80::instruction() -> void {
|
||||||
|
instructionsExecuted++;
|
||||||
|
|
||||||
|
r.r = (r.r & 0x80) | (r.r + 1 & 0x7f);
|
||||||
|
|
||||||
|
auto opcode = read(r.pc++);
|
||||||
|
switch(opcode) {
|
||||||
|
op(0x00, NOP)
|
||||||
|
op(0xf3, DI)
|
||||||
|
}
|
||||||
|
|
||||||
|
print("[Z80] unimplemented instruction: ", hex(opcode, 2L), "\n");
|
||||||
|
print("[Z80] instructions executed: ", --instructionsExecuted, "\n");
|
||||||
|
while(true) wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef op
|
|
@ -0,0 +1,5 @@
|
||||||
|
auto Z80::instructionDI() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Z80::instructionNOP() -> void {
|
||||||
|
}
|
|
@ -1,5 +1,25 @@
|
||||||
#include <processor/processor.hpp>
|
#include <processor/processor.hpp>
|
||||||
|
#include "z80.hpp"
|
||||||
|
|
||||||
namespace Processor {
|
namespace Processor {
|
||||||
|
|
||||||
|
#include "instruction.cpp"
|
||||||
|
#include "instructions.cpp"
|
||||||
|
|
||||||
|
auto Z80::power() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Z80::reset() -> void {
|
||||||
|
r.af = 0x0000;
|
||||||
|
r.bc = 0x0000;
|
||||||
|
r.de = 0x0000;
|
||||||
|
r.hl = 0x0000;
|
||||||
|
r.ix = 0x0000;
|
||||||
|
r.iy = 0x0000;
|
||||||
|
r.sp = 0x0000;
|
||||||
|
r.pc = 0x0000;
|
||||||
|
r.i = 0x00;
|
||||||
|
r.r = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,63 @@
|
||||||
namespace Processor {
|
namespace Processor {
|
||||||
|
|
||||||
struct Z80 {
|
struct Z80 {
|
||||||
|
virtual auto wait() -> void = 0;
|
||||||
|
virtual auto read(uint16 addr) -> uint8 = 0;
|
||||||
|
virtual auto write(uint16 addr, uint8 data) -> void = 0;
|
||||||
|
|
||||||
|
//z80.cpp
|
||||||
|
auto power() -> void;
|
||||||
|
auto reset() -> void;
|
||||||
|
|
||||||
|
//instruction.cpp
|
||||||
|
auto instruction() -> void;
|
||||||
|
|
||||||
|
//instructions.cpp
|
||||||
|
auto instructionDI() -> void;
|
||||||
|
auto instructionNOP() -> void;
|
||||||
|
|
||||||
|
struct Registers {
|
||||||
|
union {
|
||||||
|
uint16_t af;
|
||||||
|
struct { uint8_t order_msb2(a, f); };
|
||||||
|
union {
|
||||||
|
BooleanBitField<uint16_t, 0> c; //carry
|
||||||
|
BooleanBitField<uint16_t, 1> s; //subtract
|
||||||
|
BooleanBitField<uint16_t, 2> v; //overflow
|
||||||
|
//BooleanBitField<uint16_t, 3> _; //unused (copy of bit 3 of result)
|
||||||
|
BooleanBitField<uint16_t, 4> h; //half-carry
|
||||||
|
//BooleanBitField<uint16_t, 5> _; //unused (copy of bit 5 of result)
|
||||||
|
BooleanBitField<uint16_t, 6> z; //zero
|
||||||
|
BooleanBitField<uint16_t, 7> n; //negative
|
||||||
|
} p;
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint16_t bc;
|
||||||
|
struct { uint8_t order_msb2(b, c); };
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint16_t de;
|
||||||
|
struct { uint8_t order_msb2(d, e); };
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
uint16_t hl;
|
||||||
|
struct { uint8_t order_msb2(h, l); };
|
||||||
|
};
|
||||||
|
|
||||||
|
uint16_t ix;
|
||||||
|
uint16_t iy;
|
||||||
|
uint16_t sp;
|
||||||
|
uint16_t pc;
|
||||||
|
|
||||||
|
uint8_t i;
|
||||||
|
uint8_t r;
|
||||||
|
} r;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64 instructionsExecuted = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue