mirror of
https://github.com/libretro/bsnes-libretro.git
synced 2024-11-23 08:59:40 +00:00
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 {
|
||||
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/";
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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); }
|
||||
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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)++;
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user