mirror of https://github.com/bsnes-emu/bsnes.git
Update to v101r15 release.
byuu says: Changelog: - added (poorly-named) castable<To, With> template - Z80 debugger rewritten to make declaring instructions much simpler - Z80 has more instructions implemented; supports displacement on (IX), (IY) now - added `Processor::M68K::Bus` to mirror `Processor::Z80::Bus` - it does add a pointer indirection; so I'm not sure if I want to do this for all of my emulator cores ...
This commit is contained in:
parent
d91f3999cc
commit
4c3f58150c
|
@ -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.14";
|
static const string Version = "101.15";
|
||||||
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/";
|
||||||
|
|
|
@ -18,7 +18,8 @@ auto APU::step(uint clocks) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto APU::power() -> void {
|
auto APU::power() -> void {
|
||||||
Z80::power(&busAPU);
|
Z80::bus = &busAPU;
|
||||||
|
Z80::power();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto APU::reset() -> void {
|
auto APU::reset() -> void {
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
namespace MegaDrive {
|
namespace MegaDrive {
|
||||||
|
|
||||||
Bus bus;
|
BusCPU busCPU;
|
||||||
BusAPU busAPU;
|
BusAPU busAPU;
|
||||||
|
|
||||||
auto Bus::readByte(uint24 addr) -> uint16 {
|
auto BusCPU::readByte(uint24 addr) -> uint16 {
|
||||||
if(addr < 0x400000) return cartridge.read(addr & ~1).byte(!addr.bit(0));
|
if(addr < 0x400000) return cartridge.read(addr & ~1).byte(!addr.bit(0));
|
||||||
if(addr < 0xa00000) return 0x0000;
|
if(addr < 0xa00000) return 0x0000;
|
||||||
if(addr < 0xa10000) return 0x0000;
|
if(addr < 0xa10000) return 0x0000;
|
||||||
|
@ -15,7 +15,7 @@ auto Bus::readByte(uint24 addr) -> uint16 {
|
||||||
return ram[addr & 0xffff];
|
return ram[addr & 0xffff];
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Bus::readWord(uint24 addr) -> uint16 {
|
auto BusCPU::readWord(uint24 addr) -> uint16 {
|
||||||
if(addr < 0x400000) return cartridge.read(addr);
|
if(addr < 0x400000) return cartridge.read(addr);
|
||||||
if(addr < 0xa00000) return 0x0000;
|
if(addr < 0xa00000) return 0x0000;
|
||||||
if(addr < 0xa10000) return 0x0000;
|
if(addr < 0xa10000) return 0x0000;
|
||||||
|
@ -26,7 +26,7 @@ auto Bus::readWord(uint24 addr) -> uint16 {
|
||||||
return data | ram[addr + 1 & 0xffff] << 0;
|
return data | ram[addr + 1 & 0xffff] << 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Bus::writeByte(uint24 addr, uint16 data) -> void {
|
auto BusCPU::writeByte(uint24 addr, uint16 data) -> void {
|
||||||
if(addr < 0x400000) return cartridge.write(addr & ~1, data << 8 | data << 0);
|
if(addr < 0x400000) return cartridge.write(addr & ~1, data << 8 | data << 0);
|
||||||
if(addr < 0xa00000) return;
|
if(addr < 0xa00000) return;
|
||||||
if(addr < 0xa10000) return;
|
if(addr < 0xa10000) return;
|
||||||
|
@ -36,7 +36,7 @@ auto Bus::writeByte(uint24 addr, uint16 data) -> void {
|
||||||
ram[addr & 0xffff] = data;
|
ram[addr & 0xffff] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Bus::writeWord(uint24 addr, uint16 data) -> void {
|
auto BusCPU::writeWord(uint24 addr, uint16 data) -> void {
|
||||||
if(addr < 0x400000) return cartridge.write(addr, data);
|
if(addr < 0x400000) return cartridge.write(addr, data);
|
||||||
if(addr < 0xa00000) return;
|
if(addr < 0xa00000) return;
|
||||||
if(addr < 0xa10000) return;
|
if(addr < 0xa10000) return;
|
||||||
|
@ -49,7 +49,7 @@ auto Bus::writeWord(uint24 addr, uint16 data) -> void {
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
auto Bus::readIO(uint24 addr) -> uint16 {
|
auto BusCPU::readIO(uint24 addr) -> uint16 {
|
||||||
switch(addr & ~1) {
|
switch(addr & ~1) {
|
||||||
case 0xa10002: return peripherals.controllerPort1->readData();
|
case 0xa10002: return peripherals.controllerPort1->readData();
|
||||||
case 0xa10004: return peripherals.controllerPort2->readData();
|
case 0xa10004: return peripherals.controllerPort2->readData();
|
||||||
|
@ -63,7 +63,7 @@ auto Bus::readIO(uint24 addr) -> uint16 {
|
||||||
return 0x0000;
|
return 0x0000;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Bus::writeIO(uint24 addr, uint16 data) -> void {
|
auto BusCPU::writeIO(uint24 addr, uint16 data) -> void {
|
||||||
switch(addr & ~1) {
|
switch(addr & ~1) {
|
||||||
case 0xa10002: return peripherals.controllerPort1->writeData(data);
|
case 0xa10002: return peripherals.controllerPort1->writeData(data);
|
||||||
case 0xa10004: return peripherals.controllerPort2->writeData(data);
|
case 0xa10004: return peripherals.controllerPort2->writeData(data);
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
struct APU_Bus : Processor::Z80::Bus {
|
struct BusCPU : Processor::M68K::Bus {
|
||||||
};
|
auto readByte(uint24 addr) -> uint16 override;
|
||||||
|
auto readWord(uint24 addr) -> uint16 override;
|
||||||
struct Bus {
|
auto writeByte(uint24 addr, uint16 data) -> void override;
|
||||||
auto readByte(uint24 addr) -> uint16;
|
auto writeWord(uint24 addr, uint16 data) -> void override;
|
||||||
auto readWord(uint24 addr) -> uint16;
|
|
||||||
auto writeByte(uint24 addr, uint16 data) -> void;
|
|
||||||
auto writeWord(uint24 addr, uint16 data) -> void;
|
|
||||||
|
|
||||||
auto readIO(uint24 addr) -> uint16;
|
auto readIO(uint24 addr) -> uint16;
|
||||||
auto writeIO(uint24 addr, uint16 data) -> void;
|
auto writeIO(uint24 addr, uint16 data) -> void;
|
||||||
|
@ -21,5 +18,5 @@ struct BusAPU : Processor::Z80::Bus {
|
||||||
auto out(uint8 addr, uint8 data) -> void override;
|
auto out(uint8 addr, uint8 data) -> void override;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Bus bus;
|
extern BusCPU busCPU;
|
||||||
extern BusAPU busAPU;
|
extern BusAPU busAPU;
|
||||||
|
|
|
@ -10,8 +10,8 @@ auto CPU::Enter() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::boot() -> void {
|
auto CPU::boot() -> void {
|
||||||
r.a[7] = readWord(0) << 16 | readWord(2) << 0;
|
r.a[7] = bus->readWord(0) << 16 | bus->readWord(2) << 0;
|
||||||
r.pc = readWord(4) << 16 | readWord(6) << 0;
|
r.pc = bus->readWord(4) << 16 | bus->readWord(6) << 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::main() -> void {
|
auto CPU::main() -> void {
|
||||||
|
@ -71,6 +71,7 @@ auto CPU::lower(Interrupt interrupt) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::power() -> void {
|
auto CPU::power() -> void {
|
||||||
|
M68K::bus = &busCPU;
|
||||||
M68K::power();
|
M68K::power();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,9 +82,4 @@ auto CPU::reset() -> void {
|
||||||
memory::fill(&state, sizeof(State));
|
memory::fill(&state, sizeof(State));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::readByte(uint24 addr) -> uint16 { return bus.readByte(addr); }
|
|
||||||
auto CPU::readWord(uint24 addr) -> uint16 { return bus.readWord(addr); }
|
|
||||||
auto CPU::writeByte(uint24 addr, uint16 data) -> void { return bus.writeByte(addr, data); }
|
|
||||||
auto CPU::writeWord(uint24 addr, uint16 data) -> void { return bus.writeWord(addr, data); }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,11 +20,6 @@ struct CPU : Processor::M68K, Thread {
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
vector<Thread*> peripherals;
|
vector<Thread*> peripherals;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -10,7 +10,7 @@ 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.dmaMode.bit(0) << 23 | io.dmaSource << 1);
|
auto data = busCPU.readWord(io.dmaMode.bit(0) << 23 | io.dmaSource << 1);
|
||||||
writeDataPort(data);
|
writeDataPort(data);
|
||||||
|
|
||||||
io.dmaSource.bits(0,15)++;
|
io.dmaSource.bits(0,15)++;
|
||||||
|
|
|
@ -19,11 +19,12 @@ auto CPU::step(uint clocks) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::power() -> void {
|
auto CPU::power() -> void {
|
||||||
Processor::Z80::power(&MasterSystem::bus);
|
Z80::bus = &MasterSystem::bus;
|
||||||
|
Z80::power();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::reset() -> void {
|
auto CPU::reset() -> void {
|
||||||
Processor::Z80::reset();
|
Z80::reset();
|
||||||
create(CPU::Enter, system.colorburst());
|
create(CPU::Enter, system.colorburst());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
template<> auto M68K::_read<Byte>(uint32 addr) -> uint32 {
|
template<> auto M68K::_read<Byte>(uint32 addr) -> uint32 {
|
||||||
return readByte(addr);
|
return bus->readByte(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> auto M68K::_read<Word>(uint32 addr) -> uint32 {
|
template<> auto M68K::_read<Word>(uint32 addr) -> uint32 {
|
||||||
return readWord(addr);
|
return bus->readWord(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> auto M68K::_read<Long>(uint32 addr) -> uint32 {
|
template<> auto M68K::_read<Long>(uint32 addr) -> uint32 {
|
||||||
|
|
|
@ -5,6 +5,15 @@
|
||||||
namespace Processor {
|
namespace Processor {
|
||||||
|
|
||||||
struct M68K {
|
struct M68K {
|
||||||
|
struct Bus {
|
||||||
|
virtual auto readByte(uint24 addr) -> uint16 = 0;
|
||||||
|
virtual auto readWord(uint24 addr) -> uint16 = 0;
|
||||||
|
virtual auto writeByte(uint24 addr, uint16 data) -> void = 0;
|
||||||
|
virtual auto writeWord(uint24 addr, uint16 data) -> void = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual auto step(uint clocks) -> void = 0;
|
||||||
|
|
||||||
enum : bool { User, Supervisor };
|
enum : bool { User, Supervisor };
|
||||||
enum : uint { Byte, Word, Long };
|
enum : uint { Byte, Word, Long };
|
||||||
enum : bool { Reverse = 1, Extend = 1, Hold = 1 };
|
enum : bool { Reverse = 1, Extend = 1, Hold = 1 };
|
||||||
|
@ -48,13 +57,6 @@ struct M68K {
|
||||||
};};
|
};};
|
||||||
|
|
||||||
M68K();
|
M68K();
|
||||||
|
|
||||||
virtual auto step(uint clocks) -> void = 0;
|
|
||||||
virtual auto readByte(uint24 addr) -> uint16 = 0;
|
|
||||||
virtual auto readWord(uint24 addr) -> uint16 = 0;
|
|
||||||
virtual auto writeByte(uint24 addr, uint16 data) -> void = 0;
|
|
||||||
virtual auto writeWord(uint24 addr, uint16 data) -> void = 0;
|
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
auto supervisor() -> bool;
|
auto supervisor() -> bool;
|
||||||
|
@ -274,6 +276,7 @@ struct M68K {
|
||||||
uint instructionsExecuted = 0;
|
uint instructionsExecuted = 0;
|
||||||
|
|
||||||
function<void ()> instructionTable[65536];
|
function<void ()> instructionTable[65536];
|
||||||
|
Bus* bus = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
//disassembler.cpp
|
//disassembler.cpp
|
||||||
|
|
|
@ -1,78 +1,78 @@
|
||||||
template<> auto M68K::read<Byte>(uint32 addr) -> uint32 {
|
template<> auto M68K::read<Byte>(uint32 addr) -> uint32 {
|
||||||
step(4);
|
step(4);
|
||||||
return readByte(addr);
|
return bus->readByte(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> auto M68K::read<Word>(uint32 addr) -> uint32 {
|
template<> auto M68K::read<Word>(uint32 addr) -> uint32 {
|
||||||
step(4);
|
step(4);
|
||||||
return readWord(addr);
|
return bus->readWord(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> auto M68K::read<Long>(uint32 addr) -> uint32 {
|
template<> auto M68K::read<Long>(uint32 addr) -> uint32 {
|
||||||
step(4);
|
step(4);
|
||||||
uint32 data = readWord(addr + 0) << 16;
|
uint32 data = bus->readWord(addr + 0) << 16;
|
||||||
step(4);
|
step(4);
|
||||||
return data | readWord(addr + 2) << 0;
|
return data | bus->readWord(addr + 2) << 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
template<> auto M68K::write<Byte>(uint32 addr, uint32 data) -> void {
|
template<> auto M68K::write<Byte>(uint32 addr, uint32 data) -> void {
|
||||||
step(4);
|
step(4);
|
||||||
return writeByte(addr, data);
|
return bus->writeByte(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> auto M68K::write<Word>(uint32 addr, uint32 data) -> void {
|
template<> auto M68K::write<Word>(uint32 addr, uint32 data) -> void {
|
||||||
step(4);
|
step(4);
|
||||||
return writeWord(addr, data);
|
return bus->writeWord(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> auto M68K::write<Long>(uint32 addr, uint32 data) -> void {
|
template<> auto M68K::write<Long>(uint32 addr, uint32 data) -> void {
|
||||||
step(4);
|
step(4);
|
||||||
writeWord(addr + 0, data >> 16);
|
bus->writeWord(addr + 0, data >> 16);
|
||||||
step(4);
|
step(4);
|
||||||
writeWord(addr + 2, data >> 0);
|
bus->writeWord(addr + 2, data >> 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> auto M68K::write<Byte, Reverse>(uint32 addr, uint32 data) -> void {
|
template<> auto M68K::write<Byte, Reverse>(uint32 addr, uint32 data) -> void {
|
||||||
step(4);
|
step(4);
|
||||||
return writeByte(addr, data);
|
return bus->writeByte(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> auto M68K::write<Word, Reverse>(uint32 addr, uint32 data) -> void {
|
template<> auto M68K::write<Word, Reverse>(uint32 addr, uint32 data) -> void {
|
||||||
step(4);
|
step(4);
|
||||||
return writeWord(addr, data);
|
return bus->writeWord(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> auto M68K::write<Long, Reverse>(uint32 addr, uint32 data) -> void {
|
template<> auto M68K::write<Long, Reverse>(uint32 addr, uint32 data) -> void {
|
||||||
step(4);
|
step(4);
|
||||||
writeWord(addr + 2, data >> 0);
|
bus->writeWord(addr + 2, data >> 0);
|
||||||
step(4);
|
step(4);
|
||||||
writeWord(addr + 0, data >> 16);
|
bus->writeWord(addr + 0, data >> 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
template<> auto M68K::readPC<Byte>() -> uint32 {
|
template<> auto M68K::readPC<Byte>() -> uint32 {
|
||||||
step(4);
|
step(4);
|
||||||
auto data = readWord(r.pc);
|
auto data = bus->readWord(r.pc);
|
||||||
r.pc += 2;
|
r.pc += 2;
|
||||||
return (uint8)data;
|
return (uint8)data;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> auto M68K::readPC<Word>() -> uint32 {
|
template<> auto M68K::readPC<Word>() -> uint32 {
|
||||||
step(4);
|
step(4);
|
||||||
auto data = readWord(r.pc);
|
auto data = bus->readWord(r.pc);
|
||||||
r.pc += 2;
|
r.pc += 2;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> auto M68K::readPC<Long>() -> uint32 {
|
template<> auto M68K::readPC<Long>() -> uint32 {
|
||||||
step(4);
|
step(4);
|
||||||
auto hi = readWord(r.pc);
|
auto hi = bus->readWord(r.pc);
|
||||||
r.pc += 2;
|
r.pc += 2;
|
||||||
step(4);
|
step(4);
|
||||||
auto lo = readWord(r.pc);
|
auto lo = bus->readWord(r.pc);
|
||||||
r.pc += 2;
|
r.pc += 2;
|
||||||
return hi << 16 | lo << 0;
|
return hi << 16 | lo << 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,59 +24,100 @@ auto Z80::disassemble(uint16 pc) -> string {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define H (prefix == 0xdd ? "ixh" : prefix == 0xfd ? "iyh" : "h")
|
#define op(id, name, ...) case id: return {name, " ", string_vector{__VA_ARGS__}.merge(",")};
|
||||||
#define L (prefix == 0xdd ? "ixl" : prefix == 0xfd ? "iyl" : "l")
|
|
||||||
#define HL (prefix == 0xdd ? "ix" : prefix == 0xfd ? "iy" : "hl")
|
#define N string{"$", hex(byte(), 2L)}
|
||||||
#define W hex(y << 8 | x << 0, 4L)
|
#define IN string{"(", N, ")"}
|
||||||
#define X hex(x, 2L)
|
#define NN string{"$", hex(word(), 4L)}
|
||||||
#define Y hex(y, 2L)
|
#define INN string{"(", NN, ")"}
|
||||||
#define Z hex(z, 2L)
|
#define E string{"$", hex(branch(), 4L)}
|
||||||
#define R hex(pc + 1 + (int8)x, 4L)
|
|
||||||
|
#define H string{prefix == 0xdd ? "ixh" : prefix == 0xfd ? "iyh" : "h"}
|
||||||
|
#define L string{prefix == 0xdd ? "ixl" : prefix == 0xfd ? "iyl" : "l"}
|
||||||
|
#define HL string{prefix == 0xdd ? "ix" : prefix == 0xfd ? "iy" : "hl"}
|
||||||
|
#define IHL string{"(", HL, displace(), ")"}
|
||||||
|
|
||||||
auto Z80::disassemble__(uint16 pc, uint8 prefix, uint8 code) -> string {
|
auto Z80::disassemble__(uint16 pc, uint8 prefix, uint8 code) -> string {
|
||||||
auto x = bus->read(pc + 0);
|
auto byte = [&] {
|
||||||
auto y = bus->read(pc + 1);
|
return bus->read(pc++);
|
||||||
auto z = bus->read(pc + 2);
|
};
|
||||||
|
|
||||||
|
auto word = [&] {
|
||||||
|
uint16 data = byte() << 0;
|
||||||
|
return data | byte() << 8;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto branch = [&] {
|
||||||
|
auto d = byte();
|
||||||
|
return pc + (int8)d;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto displace = [&] {
|
||||||
|
if(!prefix) return string{};
|
||||||
|
auto d = (int8)byte();
|
||||||
|
return d >= 0 ? string{"+$", hex(d, 2L)} : string{"-$", hex(-d, 2L)};
|
||||||
|
};
|
||||||
|
|
||||||
|
if(code == 0xcb) return code = byte(), disassembleCB(pc, prefix, code);
|
||||||
|
if(code == 0xed) return code = byte(), disassembleED(pc, prefix, code);
|
||||||
|
|
||||||
switch(code) {
|
switch(code) {
|
||||||
case 0x00: return {"nop "};
|
op(0x00, "nop ")
|
||||||
case 0x06: return {"ld b,$", X};
|
op(0x01, "ld ", "bc", NN)
|
||||||
case 0x0e: return {"ld c,$", X};
|
op(0x06, "ld ", "b", N)
|
||||||
case 0x16: return {"ld d,$", X};
|
op(0x0e, "ld ", "c", N)
|
||||||
case 0x18: return {"jr $", R};
|
op(0x11, "ld ", "de", NN)
|
||||||
case 0x1e: return {"ld e,$", X};
|
op(0x16, "ld ", "d", N)
|
||||||
case 0x20: return {"jr nz,$", R};
|
op(0x18, "jr ", E)
|
||||||
case 0x26: return {"ld ", H, ",$", X};
|
op(0x1e, "ld ", "e", N)
|
||||||
case 0x28: return {"jr z,$", R};
|
op(0x20, "jr ", "nz", E)
|
||||||
case 0x2e: return {"ld ", L, ",$", X};
|
op(0x21, "ld ", HL, NN)
|
||||||
case 0x30: return {"jr nc,$", R};
|
op(0x26, "ld ", H, N)
|
||||||
case 0x36: return {"ld (", HL, "),$", X};
|
op(0x28, "jr ", "z", E)
|
||||||
case 0x38: return {"jr c,$", R};
|
op(0x2e, "ld ", L, N)
|
||||||
case 0x3e: return {"ld a,$", X};
|
op(0x30, "jr ", "nc", E)
|
||||||
case 0xc2: return {"jp nz,$", W};
|
op(0x31, "ld ", "sp", NN)
|
||||||
case 0xc3: return {"jp $", W};
|
op(0x32, "ld ", INN, "a")
|
||||||
case 0xca: return {"jp z,$", W};
|
op(0x36, "ld ", IHL, N)
|
||||||
case 0xcb: return disassembleCB(++pc, prefix, x);
|
op(0x38, "jr ", "c", E)
|
||||||
case 0xd2: return {"jp nc,$", W};
|
op(0x3e, "ld ", "a", N)
|
||||||
case 0xda: return {"jp c,$", W};
|
op(0x70, "ld ", IHL, "b")
|
||||||
case 0xdb: return {"in a,($", X, ")"};
|
op(0x71, "ld ", IHL, "c")
|
||||||
case 0xe2: return {"jp po,$", W};
|
op(0x72, "ld ", IHL, "d")
|
||||||
case 0xea: return {"jp pe,$", W};
|
op(0x73, "ld ", IHL, "e")
|
||||||
case 0xed: return disassembleED(++pc, prefix, x);
|
op(0x74, "ld ", IHL, "h")
|
||||||
case 0xf2: return {"jp p,$", W};
|
op(0x75, "ld ", IHL, "l")
|
||||||
case 0xf3: return {"di "};
|
op(0x77, "ld ", IHL, "a")
|
||||||
case 0xfa: return {"jp m,$", W};
|
op(0xb8, "cp ", "b")
|
||||||
case 0xfb: return {"ei "};
|
op(0xb9, "cp ", "c")
|
||||||
case 0xfe: return {"cp $", X};
|
op(0xba, "cp ", "d")
|
||||||
|
op(0xbb, "cp ", "e")
|
||||||
|
op(0xbc, "cp ", H)
|
||||||
|
op(0xbd, "cp ", L)
|
||||||
|
op(0xbe, "cp ", IHL)
|
||||||
|
op(0xbf, "cp ", "a")
|
||||||
|
op(0xc2, "jp ", "nz", NN)
|
||||||
|
op(0xc3, "jp ", NN)
|
||||||
|
op(0xca, "jp ", "z", NN)
|
||||||
|
op(0xcb, "cb: ")
|
||||||
|
op(0xd2, "jp ", "nc", NN)
|
||||||
|
op(0xda, "jp ", "c", NN)
|
||||||
|
op(0xdb, "in ", "a", IN)
|
||||||
|
op(0xe2, "jp ", "po", NN)
|
||||||
|
op(0xea, "jp ", "pe", NN)
|
||||||
|
op(0xed, "ed: ")
|
||||||
|
op(0xf2, "jp ", "p", NN)
|
||||||
|
op(0xf3, "di ")
|
||||||
|
op(0xfa, "jp ", "m", NN)
|
||||||
|
op(0xfb, "ei ")
|
||||||
|
op(0xfe, "cp ", N)
|
||||||
}
|
}
|
||||||
|
|
||||||
return {"???: ", hex(code, 2L)};
|
return {"???: ", hex(code, 2L)};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Z80::disassembleCB(uint16 pc, uint8 prefix, uint8 code) -> string {
|
auto Z80::disassembleCB(uint16 pc, uint8 prefix, uint8 code) -> string {
|
||||||
auto x = bus->read(pc + 0);
|
auto read = [&] { return bus->read(pc++); };
|
||||||
auto y = bus->read(pc + 1);
|
|
||||||
auto z = bus->read(pc + 2);
|
|
||||||
|
|
||||||
switch(code) {
|
switch(code) {
|
||||||
}
|
}
|
||||||
|
@ -85,24 +126,26 @@ auto Z80::disassembleCB(uint16 pc, uint8 prefix, uint8 code) -> string {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Z80::disassembleED(uint16 pc, uint8 prefix, uint8 code) -> string {
|
auto Z80::disassembleED(uint16 pc, uint8 prefix, uint8 code) -> string {
|
||||||
auto x = bus->read(pc + 0);
|
auto read = [&] { return bus->read(pc++); };
|
||||||
auto y = bus->read(pc + 1);
|
|
||||||
auto z = bus->read(pc + 2);
|
|
||||||
|
|
||||||
switch(code) {
|
switch(code) {
|
||||||
case 0x46: return {"im 0"};
|
op(0x46, "im ", "0")
|
||||||
case 0x56: return {"im 1"};
|
op(0x56, "im ", "1")
|
||||||
case 0x5e: return {"im 2"};
|
op(0x5e, "im ", "2")
|
||||||
}
|
}
|
||||||
|
|
||||||
return {"???: ed ", hex(code, 2L)};
|
return {"???: ed ", hex(code, 2L)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef op
|
||||||
|
|
||||||
|
#undef N
|
||||||
|
#undef IN
|
||||||
|
#undef NN
|
||||||
|
#undef INN
|
||||||
|
#undef E
|
||||||
|
|
||||||
#undef H
|
#undef H
|
||||||
#undef L
|
#undef L
|
||||||
#undef HL
|
#undef HL
|
||||||
#undef W
|
#undef IHL
|
||||||
#undef X
|
|
||||||
#undef Y
|
|
||||||
#undef Z
|
|
||||||
#undef R
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ auto Z80::instruction() -> void {
|
||||||
#define BC r.bc
|
#define BC r.bc
|
||||||
#define DE r.de
|
#define DE r.de
|
||||||
#define HL r.prefix == 0xdd ? r.ix : r.prefix == 0xfd ? r.iy : r.hl
|
#define HL r.prefix == 0xdd ? r.ix : r.prefix == 0xfd ? r.iy : r.hl
|
||||||
|
#define SP r.sp
|
||||||
|
|
||||||
#define CF r.p.c
|
#define CF r.p.c
|
||||||
#define NF r.p.n
|
#define NF r.p.n
|
||||||
|
@ -50,19 +51,39 @@ auto Z80::instruction() -> void {
|
||||||
auto Z80::instruction__(uint8 code) -> void {
|
auto Z80::instruction__(uint8 code) -> void {
|
||||||
switch(code) {
|
switch(code) {
|
||||||
op(0x00, NOP)
|
op(0x00, NOP)
|
||||||
|
op(0x01, LD_rr_nn, BC)
|
||||||
op(0x06, LD_r_n, B)
|
op(0x06, LD_r_n, B)
|
||||||
op(0x0e, LD_r_n, C)
|
op(0x0e, LD_r_n, C)
|
||||||
|
op(0x11, LD_rr_nn, DE)
|
||||||
op(0x16, LD_r_n, D)
|
op(0x16, LD_r_n, D)
|
||||||
op(0x18, JR_c_e, 1)
|
op(0x18, JR_c_e, 1)
|
||||||
op(0x1e, LD_r_n, E)
|
op(0x1e, LD_r_n, E)
|
||||||
op(0x20, JR_c_e, ZF == 0)
|
op(0x20, JR_c_e, ZF == 0)
|
||||||
|
op(0x21, LD_rr_nn, HL)
|
||||||
op(0x26, LD_r_n, H)
|
op(0x26, LD_r_n, H)
|
||||||
op(0x28, JR_c_e, ZF == 1)
|
op(0x28, JR_c_e, ZF == 1)
|
||||||
op(0x2e, LD_r_n, L)
|
op(0x2e, LD_r_n, L)
|
||||||
op(0x30, JR_c_e, CF == 0)
|
op(0x30, JR_c_e, CF == 0)
|
||||||
|
op(0x31, LD_rr_nn, SP)
|
||||||
|
op(0x32, LD_inn_a)
|
||||||
op(0x36, LD_irr_n, HL)
|
op(0x36, LD_irr_n, HL)
|
||||||
op(0x38, JR_c_e, CF == 1)
|
op(0x38, JR_c_e, CF == 1)
|
||||||
op(0x3e, LD_r_n, A)
|
op(0x3e, LD_r_n, A)
|
||||||
|
op(0x70, LD_irr_r, HL, B)
|
||||||
|
op(0x71, LD_irr_r, HL, C)
|
||||||
|
op(0x72, LD_irr_r, HL, D)
|
||||||
|
op(0x73, LD_irr_r, HL, E)
|
||||||
|
op(0x74, LD_irr_r, HL, r.h)
|
||||||
|
op(0x75, LD_irr_r, HL, r.l)
|
||||||
|
op(0x77, LD_irr_r, HL, A)
|
||||||
|
op(0xb8, CP_r, B)
|
||||||
|
op(0xb9, CP_r, C)
|
||||||
|
op(0xba, CP_r, D)
|
||||||
|
op(0xbb, CP_r, E)
|
||||||
|
op(0xbc, CP_r, H)
|
||||||
|
op(0xbd, CP_r, L)
|
||||||
|
op(0xbe, CP_irr, HL)
|
||||||
|
op(0xbf, CP_r, A)
|
||||||
op(0xc2, JP_c_nn, ZF == 0)
|
op(0xc2, JP_c_nn, ZF == 0)
|
||||||
op(0xc3, JP_c_nn, 1)
|
op(0xc3, JP_c_nn, 1)
|
||||||
op(0xca, JP_c_nn, ZF == 1)
|
op(0xca, JP_c_nn, ZF == 1)
|
||||||
|
@ -115,6 +136,7 @@ auto Z80::instructionED(uint8 code) -> void {
|
||||||
#undef BC
|
#undef BC
|
||||||
#undef DE
|
#undef DE
|
||||||
#undef HL
|
#undef HL
|
||||||
|
#undef SP
|
||||||
|
|
||||||
#undef CF
|
#undef CF
|
||||||
#undef NF
|
#undef NF
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// a = r.a
|
// a = r.a
|
||||||
// e = relative operand
|
// e = relative operand
|
||||||
// in = (operand)
|
// in = (operand)
|
||||||
|
// inn = (operand-word)
|
||||||
// irr = (register-word)
|
// irr = (register-word)
|
||||||
// o = opcode bits
|
// o = opcode bits
|
||||||
// n = operand
|
// n = operand
|
||||||
|
@ -21,10 +22,19 @@ auto Z80::CP(uint8 x) -> void {
|
||||||
r.p.s = y.bit(7);
|
r.p.s = y.bit(7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Z80::instructionCP_irr(uint16& x) -> void {
|
||||||
|
auto addr = displace(x);
|
||||||
|
CP(read(addr));
|
||||||
|
}
|
||||||
|
|
||||||
auto Z80::instructionCP_n() -> void {
|
auto Z80::instructionCP_n() -> void {
|
||||||
CP(operand());
|
CP(operand());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Z80::instructionCP_r(uint8& x) -> void {
|
||||||
|
CP(x);
|
||||||
|
}
|
||||||
|
|
||||||
auto Z80::instructionDI() -> void {
|
auto Z80::instructionDI() -> void {
|
||||||
r.iff1 = 0;
|
r.iff1 = 0;
|
||||||
r.iff2 = 0;
|
r.iff2 = 0;
|
||||||
|
@ -57,13 +67,31 @@ auto Z80::instructionJR_c_e(bool c) -> void {
|
||||||
r.pc += (int8)e;
|
r.pc += (int8)e;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Z80::instructionLD_irr_n(uint16_t& x) -> void {
|
auto Z80::instructionLD_inn_a() -> void {
|
||||||
write(x, operand());
|
auto lo = operand();
|
||||||
|
auto hi = operand();
|
||||||
|
write(hi << 8 | lo << 0, r.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Z80::instructionLD_r_n(uint8_t& x) -> void {
|
auto Z80::instructionLD_irr_n(uint16& x) -> void {
|
||||||
|
auto addr = displace(x);
|
||||||
|
write(addr, operand());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Z80::instructionLD_irr_r(uint16& x, uint8& y) -> void {
|
||||||
|
auto addr = displace(x);
|
||||||
|
write(addr, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Z80::instructionLD_r_n(uint8& x) -> void {
|
||||||
x = operand();
|
x = operand();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Z80::instructionLD_rr_nn(uint16& x) -> void {
|
||||||
|
auto lo = operand();
|
||||||
|
auto hi = operand();
|
||||||
|
x = hi << 8 | lo << 0;
|
||||||
|
}
|
||||||
|
|
||||||
auto Z80::instructionNOP() -> void {
|
auto Z80::instructionNOP() -> void {
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,13 @@ auto Z80::operand() -> uint8 {
|
||||||
return bus->read(r.pc++);
|
return bus->read(r.pc++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Z80::displace(uint16& x) -> uint16 {
|
||||||
|
if(!r.prefix) return x;
|
||||||
|
auto d = read(x);
|
||||||
|
wait(5);
|
||||||
|
return x + (int8)d;
|
||||||
|
}
|
||||||
|
|
||||||
auto Z80::read(uint16 addr) -> uint8 {
|
auto Z80::read(uint16 addr) -> uint8 {
|
||||||
step(3);
|
step(3);
|
||||||
return bus->read(addr);
|
return bus->read(addr);
|
||||||
|
|
|
@ -8,8 +8,7 @@ namespace Processor {
|
||||||
#include "instructions.cpp"
|
#include "instructions.cpp"
|
||||||
#include "disassembler.cpp"
|
#include "disassembler.cpp"
|
||||||
|
|
||||||
auto Z80::power(Z80::Bus* bus) -> void {
|
auto Z80::power() -> void {
|
||||||
this->bus = bus;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Z80::reset() -> void {
|
auto Z80::reset() -> void {
|
||||||
|
@ -30,7 +29,7 @@ auto Z80::reset() -> void {
|
||||||
instructionsExecuted = 0;
|
instructionsExecuted = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Z80::parity(uint8_t value) const -> bool {
|
auto Z80::parity(uint8 value) const -> bool {
|
||||||
value ^= value >> 4;
|
value ^= value >> 4;
|
||||||
value ^= value >> 2;
|
value ^= value >> 2;
|
||||||
value ^= value >> 1;
|
value ^= value >> 1;
|
||||||
|
|
|
@ -15,15 +15,16 @@ struct Z80 {
|
||||||
virtual auto step(uint clocks) -> void = 0;
|
virtual auto step(uint clocks) -> void = 0;
|
||||||
|
|
||||||
//z80.cpp
|
//z80.cpp
|
||||||
auto power(Z80::Bus*) -> void;
|
auto power() -> void;
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
|
|
||||||
auto parity(uint8_t) const -> bool;
|
auto parity(uint8) const -> bool;
|
||||||
|
|
||||||
//memory.cpp
|
//memory.cpp
|
||||||
auto wait(uint clocks = 1) -> void;
|
auto wait(uint clocks = 1) -> void;
|
||||||
auto opcode() -> uint8;
|
auto opcode() -> uint8;
|
||||||
auto operand() -> uint8;
|
auto operand() -> uint8;
|
||||||
|
auto displace(uint16&) -> uint16;
|
||||||
auto read(uint16 addr) -> uint8;
|
auto read(uint16 addr) -> uint8;
|
||||||
auto write(uint16 addr, uint8 data) -> void;
|
auto write(uint16 addr, uint8 data) -> void;
|
||||||
auto in(uint8 addr) -> uint8;
|
auto in(uint8 addr) -> uint8;
|
||||||
|
@ -38,15 +39,20 @@ struct Z80 {
|
||||||
|
|
||||||
//instructions.cpp
|
//instructions.cpp
|
||||||
auto CP(uint8) -> void;
|
auto CP(uint8) -> void;
|
||||||
|
auto instructionCP_irr(uint16& x) -> void;
|
||||||
auto instructionCP_n() -> void;
|
auto instructionCP_n() -> void;
|
||||||
|
auto instructionCP_r(uint8& x) -> void;
|
||||||
auto instructionDI() -> void;
|
auto instructionDI() -> void;
|
||||||
auto instructionEI() -> void;
|
auto instructionEI() -> void;
|
||||||
auto instructionIM_o(uint2) -> void;
|
auto instructionIM_o(uint2) -> void;
|
||||||
auto instructionIN_a_in() -> void;
|
auto instructionIN_a_in() -> void;
|
||||||
auto instructionJP_c_nn(bool) -> void;
|
auto instructionJP_c_nn(bool) -> void;
|
||||||
auto instructionJR_c_e(bool) -> void;
|
auto instructionJR_c_e(bool) -> void;
|
||||||
auto instructionLD_irr_n(uint16_t&) -> void;
|
auto instructionLD_inn_a() -> void;
|
||||||
auto instructionLD_r_n(uint8_t&) -> void;
|
auto instructionLD_irr_n(uint16&) -> void;
|
||||||
|
auto instructionLD_irr_r(uint16&, uint8&) -> void;
|
||||||
|
auto instructionLD_r_n(uint8&) -> void;
|
||||||
|
auto instructionLD_rr_nn(uint16&) -> void;
|
||||||
auto instructionNOP() -> void;
|
auto instructionNOP() -> void;
|
||||||
|
|
||||||
//disassembler.cpp
|
//disassembler.cpp
|
||||||
|
@ -57,8 +63,8 @@ struct Z80 {
|
||||||
|
|
||||||
struct Registers {
|
struct Registers {
|
||||||
union {
|
union {
|
||||||
uint16_t af;
|
castable<uint16, uint16_t> af;
|
||||||
struct { uint8_t order_msb2(a, f); };
|
struct { castable<uint8, uint8_t> order_msb2(a, f); };
|
||||||
union {
|
union {
|
||||||
BooleanBitField<uint16_t, 0> c; //carry
|
BooleanBitField<uint16_t, 0> c; //carry
|
||||||
BooleanBitField<uint16_t, 1> n; //add / subtract
|
BooleanBitField<uint16_t, 1> n; //add / subtract
|
||||||
|
@ -73,48 +79,49 @@ struct Z80 {
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
uint16_t bc;
|
castable<uint16, uint16_t> bc;
|
||||||
struct { uint8_t order_msb2(b, c); };
|
struct { castable<uint8, uint8_t> order_msb2(b, c); };
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
uint16_t de;
|
castable<uint16, uint16_t> de;
|
||||||
struct { uint8_t order_msb2(d, e); };
|
struct { castable<uint8, uint8_t> order_msb2(d, e); };
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
uint16_t hl;
|
castable<uint16, uint16_t> hl;
|
||||||
struct { uint8_t order_msb2(h, l); };
|
struct { castable<uint8, uint8_t> order_msb2(h, l); };
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
uint16_t ix;
|
castable<uint16, uint16_t> ix;
|
||||||
struct { uint8_t order_msb2(ixh, ixl); };
|
struct { castable<uint8, uint8_t> order_msb2(ixh, ixl); };
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
uint16_t iy;
|
castable<uint16, uint16_t> iy;
|
||||||
struct { uint8_t order_msb2(iyh, iyl); };
|
struct { castable<uint8, uint8_t> order_msb2(iyh, iyl); };
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
uint16_t ir;
|
castable<uint16, uint16_t> ir;
|
||||||
struct { uint8_t order_msb2(i, r); };
|
struct { castable<uint8, uint8_t> order_msb2(i, r); };
|
||||||
};
|
};
|
||||||
|
|
||||||
uint16_t sp;
|
uint16 sp;
|
||||||
uint16_t pc;
|
uint16 pc;
|
||||||
|
|
||||||
boolean iff1; //interrupt flip-flop 1
|
boolean iff1; //interrupt flip-flop 1
|
||||||
boolean iff2; //interrupt flip-flop 2
|
boolean iff2; //interrupt flip-flop 2
|
||||||
uint2 im; //interrupt mode (0-2)
|
uint2 im; //interrupt mode (0-2)
|
||||||
|
|
||||||
uint8_t prefix;
|
uint8 prefix;
|
||||||
uint8_t flag;
|
uint8 flag;
|
||||||
} r;
|
} r;
|
||||||
|
|
||||||
private:
|
|
||||||
Bus* bus = nullptr;
|
Bus* bus = nullptr;
|
||||||
|
|
||||||
|
private:
|
||||||
uint64 instructionsExecuted = 0;
|
uint64 instructionsExecuted = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,15 @@ template<typename T> struct base_from_member {
|
||||||
T value;
|
T value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename To, typename With> struct castable {
|
||||||
|
operator To&() { return (To&)value; }
|
||||||
|
operator const To&() const { return (const To&)value; }
|
||||||
|
operator With&() { return value; }
|
||||||
|
operator const With&() const { return value; }
|
||||||
|
auto& operator=(const With& value) { return this->value = value; }
|
||||||
|
With value;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename T> inline auto allocate(uint size, const T& value) -> T* {
|
template<typename T> inline auto allocate(uint size, const T& value) -> T* {
|
||||||
T* array = new T[size];
|
T* array = new T[size];
|
||||||
for(uint i = 0; i < size; i++) array[i] = value;
|
for(uint i = 0; i < size; i++) array[i] = value;
|
||||||
|
|
Loading…
Reference in New Issue