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:
Tim Allen 2016-09-04 23:51:27 +10:00
parent d91f3999cc
commit 4c3f58150c
18 changed files with 249 additions and 141 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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