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 {
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 License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

@ -18,7 +18,8 @@ auto APU::step(uint clocks) -> void {
}
auto APU::power() -> void {
Z80::power(&busAPU);
Z80::bus = &busAPU;
Z80::power();
}
auto APU::reset() -> void {

View File

@ -2,10 +2,10 @@
namespace MegaDrive {
Bus bus;
BusCPU busCPU;
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 < 0xa00000) return 0x0000;
if(addr < 0xa10000) return 0x0000;
@ -15,7 +15,7 @@ auto Bus::readByte(uint24 addr) -> uint16 {
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 < 0xa00000) return 0x0000;
if(addr < 0xa10000) return 0x0000;
@ -26,7 +26,7 @@ auto Bus::readWord(uint24 addr) -> uint16 {
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 < 0xa00000) return;
if(addr < 0xa10000) return;
@ -36,7 +36,7 @@ auto Bus::writeByte(uint24 addr, uint16 data) -> void {
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 < 0xa00000) 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) {
case 0xa10002: return peripherals.controllerPort1->readData();
case 0xa10004: return peripherals.controllerPort2->readData();
@ -63,7 +63,7 @@ auto Bus::readIO(uint24 addr) -> uint16 {
return 0x0000;
}
auto Bus::writeIO(uint24 addr, uint16 data) -> void {
auto BusCPU::writeIO(uint24 addr, uint16 data) -> void {
switch(addr & ~1) {
case 0xa10002: return peripherals.controllerPort1->writeData(data);
case 0xa10004: return peripherals.controllerPort2->writeData(data);

View File

@ -1,11 +1,8 @@
struct APU_Bus : Processor::Z80::Bus {
};
struct Bus {
auto readByte(uint24 addr) -> uint16;
auto readWord(uint24 addr) -> uint16;
auto writeByte(uint24 addr, uint16 data) -> void;
auto writeWord(uint24 addr, uint16 data) -> void;
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;
@ -21,5 +18,5 @@ struct BusAPU : Processor::Z80::Bus {
auto out(uint8 addr, uint8 data) -> void override;
};
extern Bus bus;
extern BusCPU busCPU;
extern BusAPU busAPU;

View File

@ -10,8 +10,8 @@ auto CPU::Enter() -> void {
}
auto CPU::boot() -> void {
r.a[7] = readWord(0) << 16 | readWord(2) << 0;
r.pc = readWord(4) << 16 | readWord(6) << 0;
r.a[7] = bus->readWord(0) << 16 | bus->readWord(2) << 0;
r.pc = bus->readWord(4) << 16 | bus->readWord(6) << 0;
}
auto CPU::main() -> void {
@ -71,6 +71,7 @@ auto CPU::lower(Interrupt interrupt) -> void {
}
auto CPU::power() -> void {
M68K::bus = &busCPU;
M68K::power();
}
@ -81,9 +82,4 @@ auto CPU::reset() -> void {
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 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;
private:

View File

@ -10,7 +10,7 @@ auto VDP::dmaRun() -> void {
auto VDP::dmaLoad() -> void {
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);
io.dmaSource.bits(0,15)++;

View File

@ -19,11 +19,12 @@ auto CPU::step(uint clocks) -> void {
}
auto CPU::power() -> void {
Processor::Z80::power(&MasterSystem::bus);
Z80::bus = &MasterSystem::bus;
Z80::power();
}
auto CPU::reset() -> void {
Processor::Z80::reset();
Z80::reset();
create(CPU::Enter, system.colorburst());
}

View File

@ -1,9 +1,9 @@
template<> auto M68K::_read<Byte>(uint32 addr) -> uint32 {
return readByte(addr);
return bus->readByte(addr);
}
template<> auto M68K::_read<Word>(uint32 addr) -> uint32 {
return readWord(addr);
return bus->readWord(addr);
}
template<> auto M68K::_read<Long>(uint32 addr) -> uint32 {

View File

@ -5,6 +5,15 @@
namespace Processor {
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 : uint { Byte, Word, Long };
enum : bool { Reverse = 1, Extend = 1, Hold = 1 };
@ -48,13 +57,6 @@ struct 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 reset() -> void;
auto supervisor() -> bool;
@ -274,6 +276,7 @@ struct M68K {
uint instructionsExecuted = 0;
function<void ()> instructionTable[65536];
Bus* bus = nullptr;
private:
//disassembler.cpp

View File

@ -1,78 +1,78 @@
template<> auto M68K::read<Byte>(uint32 addr) -> uint32 {
step(4);
return readByte(addr);
return bus->readByte(addr);
}
template<> auto M68K::read<Word>(uint32 addr) -> uint32 {
step(4);
return readWord(addr);
return bus->readWord(addr);
}
template<> auto M68K::read<Long>(uint32 addr) -> uint32 {
step(4);
uint32 data = readWord(addr + 0) << 16;
uint32 data = bus->readWord(addr + 0) << 16;
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 {
step(4);
return writeByte(addr, data);
return bus->writeByte(addr, data);
}
template<> auto M68K::write<Word>(uint32 addr, uint32 data) -> void {
step(4);
return writeWord(addr, data);
return bus->writeWord(addr, data);
}
template<> auto M68K::write<Long>(uint32 addr, uint32 data) -> void {
step(4);
writeWord(addr + 0, data >> 16);
bus->writeWord(addr + 0, data >> 16);
step(4);
writeWord(addr + 2, data >> 0);
bus->writeWord(addr + 2, data >> 0);
}
template<> auto M68K::write<Byte, Reverse>(uint32 addr, uint32 data) -> void {
step(4);
return writeByte(addr, data);
return bus->writeByte(addr, data);
}
template<> auto M68K::write<Word, Reverse>(uint32 addr, uint32 data) -> void {
step(4);
return writeWord(addr, data);
return bus->writeWord(addr, data);
}
template<> auto M68K::write<Long, Reverse>(uint32 addr, uint32 data) -> void {
step(4);
writeWord(addr + 2, data >> 0);
bus->writeWord(addr + 2, data >> 0);
step(4);
writeWord(addr + 0, data >> 16);
bus->writeWord(addr + 0, data >> 16);
}
//
template<> auto M68K::readPC<Byte>() -> uint32 {
step(4);
auto data = readWord(r.pc);
auto data = bus->readWord(r.pc);
r.pc += 2;
return (uint8)data;
}
template<> auto M68K::readPC<Word>() -> uint32 {
step(4);
auto data = readWord(r.pc);
auto data = bus->readWord(r.pc);
r.pc += 2;
return data;
}
template<> auto M68K::readPC<Long>() -> uint32 {
step(4);
auto hi = readWord(r.pc);
auto hi = bus->readWord(r.pc);
r.pc += 2;
step(4);
auto lo = readWord(r.pc);
auto lo = bus->readWord(r.pc);
r.pc += 2;
return hi << 16 | lo << 0;
}

View File

@ -24,59 +24,100 @@ auto Z80::disassemble(uint16 pc) -> string {
return s;
}
#define H (prefix == 0xdd ? "ixh" : prefix == 0xfd ? "iyh" : "h")
#define L (prefix == 0xdd ? "ixl" : prefix == 0xfd ? "iyl" : "l")
#define HL (prefix == 0xdd ? "ix" : prefix == 0xfd ? "iy" : "hl")
#define W hex(y << 8 | x << 0, 4L)
#define X hex(x, 2L)
#define Y hex(y, 2L)
#define Z hex(z, 2L)
#define R hex(pc + 1 + (int8)x, 4L)
#define op(id, name, ...) case id: return {name, " ", string_vector{__VA_ARGS__}.merge(",")};
#define N string{"$", hex(byte(), 2L)}
#define IN string{"(", N, ")"}
#define NN string{"$", hex(word(), 4L)}
#define INN string{"(", NN, ")"}
#define E string{"$", hex(branch(), 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 x = bus->read(pc + 0);
auto y = bus->read(pc + 1);
auto z = bus->read(pc + 2);
auto byte = [&] {
return bus->read(pc++);
};
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) {
case 0x00: return {"nop "};
case 0x06: return {"ld b,$", X};
case 0x0e: return {"ld c,$", X};
case 0x16: return {"ld d,$", X};
case 0x18: return {"jr $", R};
case 0x1e: return {"ld e,$", X};
case 0x20: return {"jr nz,$", R};
case 0x26: return {"ld ", H, ",$", X};
case 0x28: return {"jr z,$", R};
case 0x2e: return {"ld ", L, ",$", X};
case 0x30: return {"jr nc,$", R};
case 0x36: return {"ld (", HL, "),$", X};
case 0x38: return {"jr c,$", R};
case 0x3e: return {"ld a,$", X};
case 0xc2: return {"jp nz,$", W};
case 0xc3: return {"jp $", W};
case 0xca: return {"jp z,$", W};
case 0xcb: return disassembleCB(++pc, prefix, x);
case 0xd2: return {"jp nc,$", W};
case 0xda: return {"jp c,$", W};
case 0xdb: return {"in a,($", X, ")"};
case 0xe2: return {"jp po,$", W};
case 0xea: return {"jp pe,$", W};
case 0xed: return disassembleED(++pc, prefix, x);
case 0xf2: return {"jp p,$", W};
case 0xf3: return {"di "};
case 0xfa: return {"jp m,$", W};
case 0xfb: return {"ei "};
case 0xfe: return {"cp $", X};
op(0x00, "nop ")
op(0x01, "ld ", "bc", NN)
op(0x06, "ld ", "b", N)
op(0x0e, "ld ", "c", N)
op(0x11, "ld ", "de", NN)
op(0x16, "ld ", "d", N)
op(0x18, "jr ", E)
op(0x1e, "ld ", "e", N)
op(0x20, "jr ", "nz", E)
op(0x21, "ld ", HL, NN)
op(0x26, "ld ", H, N)
op(0x28, "jr ", "z", E)
op(0x2e, "ld ", L, N)
op(0x30, "jr ", "nc", E)
op(0x31, "ld ", "sp", NN)
op(0x32, "ld ", INN, "a")
op(0x36, "ld ", IHL, N)
op(0x38, "jr ", "c", E)
op(0x3e, "ld ", "a", N)
op(0x70, "ld ", IHL, "b")
op(0x71, "ld ", IHL, "c")
op(0x72, "ld ", IHL, "d")
op(0x73, "ld ", IHL, "e")
op(0x74, "ld ", IHL, "h")
op(0x75, "ld ", IHL, "l")
op(0x77, "ld ", IHL, "a")
op(0xb8, "cp ", "b")
op(0xb9, "cp ", "c")
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)};
}
auto Z80::disassembleCB(uint16 pc, uint8 prefix, uint8 code) -> string {
auto x = bus->read(pc + 0);
auto y = bus->read(pc + 1);
auto z = bus->read(pc + 2);
auto read = [&] { return bus->read(pc++); };
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 x = bus->read(pc + 0);
auto y = bus->read(pc + 1);
auto z = bus->read(pc + 2);
auto read = [&] { return bus->read(pc++); };
switch(code) {
case 0x46: return {"im 0"};
case 0x56: return {"im 1"};
case 0x5e: return {"im 2"};
op(0x46, "im ", "0")
op(0x56, "im ", "1")
op(0x5e, "im ", "2")
}
return {"???: ed ", hex(code, 2L)};
}
#undef op
#undef N
#undef IN
#undef NN
#undef INN
#undef E
#undef H
#undef L
#undef HL
#undef W
#undef X
#undef Y
#undef Z
#undef R
#undef IHL

View File

@ -36,6 +36,7 @@ auto Z80::instruction() -> void {
#define BC r.bc
#define DE r.de
#define HL r.prefix == 0xdd ? r.ix : r.prefix == 0xfd ? r.iy : r.hl
#define SP r.sp
#define CF r.p.c
#define NF r.p.n
@ -50,19 +51,39 @@ auto Z80::instruction() -> void {
auto Z80::instruction__(uint8 code) -> void {
switch(code) {
op(0x00, NOP)
op(0x01, LD_rr_nn, BC)
op(0x06, LD_r_n, B)
op(0x0e, LD_r_n, C)
op(0x11, LD_rr_nn, DE)
op(0x16, LD_r_n, D)
op(0x18, JR_c_e, 1)
op(0x1e, LD_r_n, E)
op(0x20, JR_c_e, ZF == 0)
op(0x21, LD_rr_nn, HL)
op(0x26, LD_r_n, H)
op(0x28, JR_c_e, ZF == 1)
op(0x2e, LD_r_n, L)
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(0x38, JR_c_e, CF == 1)
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(0xc3, JP_c_nn, 1)
op(0xca, JP_c_nn, ZF == 1)
@ -115,6 +136,7 @@ auto Z80::instructionED(uint8 code) -> void {
#undef BC
#undef DE
#undef HL
#undef SP
#undef CF
#undef NF

View File

@ -2,6 +2,7 @@
// a = r.a
// e = relative operand
// in = (operand)
// inn = (operand-word)
// irr = (register-word)
// o = opcode bits
// n = operand
@ -21,10 +22,19 @@ auto Z80::CP(uint8 x) -> void {
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 {
CP(operand());
}
auto Z80::instructionCP_r(uint8& x) -> void {
CP(x);
}
auto Z80::instructionDI() -> void {
r.iff1 = 0;
r.iff2 = 0;
@ -57,13 +67,31 @@ auto Z80::instructionJR_c_e(bool c) -> void {
r.pc += (int8)e;
}
auto Z80::instructionLD_irr_n(uint16_t& x) -> void {
write(x, operand());
auto Z80::instructionLD_inn_a() -> void {
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();
}
auto Z80::instructionLD_rr_nn(uint16& x) -> void {
auto lo = operand();
auto hi = operand();
x = hi << 8 | lo << 0;
}
auto Z80::instructionNOP() -> void {
}

View File

@ -12,6 +12,13 @@ auto Z80::operand() -> uint8 {
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 {
step(3);
return bus->read(addr);

View File

@ -8,8 +8,7 @@ namespace Processor {
#include "instructions.cpp"
#include "disassembler.cpp"
auto Z80::power(Z80::Bus* bus) -> void {
this->bus = bus;
auto Z80::power() -> void {
}
auto Z80::reset() -> void {
@ -30,7 +29,7 @@ auto Z80::reset() -> void {
instructionsExecuted = 0;
}
auto Z80::parity(uint8_t value) const -> bool {
auto Z80::parity(uint8 value) const -> bool {
value ^= value >> 4;
value ^= value >> 2;
value ^= value >> 1;

View File

@ -15,15 +15,16 @@ struct Z80 {
virtual auto step(uint clocks) -> void = 0;
//z80.cpp
auto power(Z80::Bus*) -> void;
auto power() -> void;
auto reset() -> void;
auto parity(uint8_t) const -> bool;
auto parity(uint8) const -> bool;
//memory.cpp
auto wait(uint clocks = 1) -> void;
auto opcode() -> uint8;
auto operand() -> uint8;
auto displace(uint16&) -> uint16;
auto read(uint16 addr) -> uint8;
auto write(uint16 addr, uint8 data) -> void;
auto in(uint8 addr) -> uint8;
@ -38,15 +39,20 @@ struct Z80 {
//instructions.cpp
auto CP(uint8) -> void;
auto instructionCP_irr(uint16& x) -> void;
auto instructionCP_n() -> void;
auto instructionCP_r(uint8& x) -> void;
auto instructionDI() -> void;
auto instructionEI() -> void;
auto instructionIM_o(uint2) -> void;
auto instructionIN_a_in() -> void;
auto instructionJP_c_nn(bool) -> void;
auto instructionJR_c_e(bool) -> void;
auto instructionLD_irr_n(uint16_t&) -> void;
auto instructionLD_r_n(uint8_t&) -> void;
auto instructionLD_inn_a() -> 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;
//disassembler.cpp
@ -57,8 +63,8 @@ struct Z80 {
struct Registers {
union {
uint16_t af;
struct { uint8_t order_msb2(a, f); };
castable<uint16, uint16_t> af;
struct { castable<uint8, uint8_t> order_msb2(a, f); };
union {
BooleanBitField<uint16_t, 0> c; //carry
BooleanBitField<uint16_t, 1> n; //add / subtract
@ -73,48 +79,49 @@ struct Z80 {
};
union {
uint16_t bc;
struct { uint8_t order_msb2(b, c); };
castable<uint16, uint16_t> bc;
struct { castable<uint8, uint8_t> order_msb2(b, c); };
};
union {
uint16_t de;
struct { uint8_t order_msb2(d, e); };
castable<uint16, uint16_t> de;
struct { castable<uint8, uint8_t> order_msb2(d, e); };
};
union {
uint16_t hl;
struct { uint8_t order_msb2(h, l); };
castable<uint16, uint16_t> hl;
struct { castable<uint8, uint8_t> order_msb2(h, l); };
};
union {
uint16_t ix;
struct { uint8_t order_msb2(ixh, ixl); };
castable<uint16, uint16_t> ix;
struct { castable<uint8, uint8_t> order_msb2(ixh, ixl); };
};
union {
uint16_t iy;
struct { uint8_t order_msb2(iyh, iyl); };
castable<uint16, uint16_t> iy;
struct { castable<uint8, uint8_t> order_msb2(iyh, iyl); };
};
union {
uint16_t ir;
struct { uint8_t order_msb2(i, r); };
castable<uint16, uint16_t> ir;
struct { castable<uint8, uint8_t> order_msb2(i, r); };
};
uint16_t sp;
uint16_t pc;
uint16 sp;
uint16 pc;
boolean iff1; //interrupt flip-flop 1
boolean iff2; //interrupt flip-flop 2
uint2 im; //interrupt mode (0-2)
uint8_t prefix;
uint8_t flag;
uint8 prefix;
uint8 flag;
} r;
private:
Bus* bus = nullptr;
private:
uint64 instructionsExecuted = 0;
};

View File

@ -9,6 +9,15 @@ template<typename T> struct base_from_member {
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* {
T* array = new T[size];
for(uint i = 0; i < size; i++) array[i] = value;