mirror of https://github.com/bsnes-emu/bsnes.git
Update to v101r14 release.
byuu says: Changelog: - rewrote the Z80 core to properly handle 0xDD (IX0 and 0xFD (IY) prefixes - added Processor::Z80::Bus as a new type of abstraction - all of the instructions implemented have their proper T-cycle counts now - added nall/certificates for my public keys The goal of `Processor::Z80::Bus` is to simulate the opcode fetches being 2-read + 2-wait states; operand+regular reads/writes being 3-read. For now, this puts the cycle counts inside the CPU core. At the moment, I can't think of any CPU core where this wouldn't be appropriate. But it's certainly possible that such a case exists. So this may not be the perfect solution. The reason for having it be a subclass of Processor::Z80 instead of virtual functions for the MasterSystem::CPU core to define is due to naming conflicts. I wanted the core to say `in(addr)` and have it take the four clocks. But I also wanted a version of the function that didn't consume time when called. One way to do that would be for the core to call `Z80::in(addr)`, which then calls the regular `in(addr)` that goes to `MasterSystem::CPU::in(addr)`. But I don't want to put the `Z80::` prefix on all of the opcodes. Very easy to forget it, and then end up not consuming any time. Another is to use uglier names in the `MasterSystem::CPU` core, like `read_`, `write_`, `in_`, `out_`, etc. But, yuck. So ... yeah, this is an experiment. We'll see how it goes.
This commit is contained in:
parent
7c96826eb0
commit
d91f3999cc
|
@ -12,7 +12,7 @@ using namespace nall;
|
|||
|
||||
namespace Emulator {
|
||||
static const string Name = "higan";
|
||||
static const string Version = "101.13";
|
||||
static const string Version = "101.14";
|
||||
static const string Author = "byuu";
|
||||
static const string License = "GPLv3";
|
||||
static const string Website = "http://byuu.org/";
|
||||
|
|
|
@ -17,30 +17,12 @@ auto APU::step(uint clocks) -> void {
|
|||
synchronize(cpu);
|
||||
}
|
||||
|
||||
auto APU::wait() -> void {
|
||||
step(1);
|
||||
}
|
||||
|
||||
auto APU::read(uint16 addr) -> uint8 {
|
||||
step(1);
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
auto APU::write(uint16 addr, uint8 data) -> void {
|
||||
step(1);
|
||||
}
|
||||
|
||||
auto APU::in(uint8 addr) -> uint8 {
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
auto APU::out(uint8 addr, uint8 data) -> void {
|
||||
}
|
||||
|
||||
auto APU::power() -> void {
|
||||
Z80::power(&busAPU);
|
||||
}
|
||||
|
||||
auto APU::reset() -> void {
|
||||
Z80::reset();
|
||||
create(APU::Enter, system.colorburst());
|
||||
}
|
||||
|
||||
|
|
|
@ -5,12 +5,6 @@ struct APU : Processor::Z80, Thread {
|
|||
auto main() -> void;
|
||||
auto step(uint clocks) -> void;
|
||||
|
||||
auto wait() -> void override;
|
||||
auto read(uint16 addr) -> uint8 override;
|
||||
auto write(uint16 addr, uint8 data) -> void override;
|
||||
auto in(uint8 addr) -> uint8 override;
|
||||
auto out(uint8 addr, uint8 data) -> void override;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace MegaDrive {
|
||||
|
||||
Bus bus;
|
||||
BusAPU busAPU;
|
||||
|
||||
auto Bus::readByte(uint24 addr) -> uint16 {
|
||||
if(addr < 0x400000) return cartridge.read(addr & ~1).byte(!addr.bit(0));
|
||||
|
@ -74,4 +75,20 @@ auto Bus::writeIO(uint24 addr, uint16 data) -> void {
|
|||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
auto BusAPU::read(uint16 addr) -> uint8 {
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
auto BusAPU::write(uint16 addr, uint8 data) -> void {
|
||||
}
|
||||
|
||||
auto BusAPU::in(uint8 addr) -> uint8 {
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
auto BusAPU::out(uint8 addr, uint8 data) -> void {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
struct APU_Bus : Processor::Z80::Bus {
|
||||
};
|
||||
|
||||
struct Bus {
|
||||
auto readByte(uint24 addr) -> uint16;
|
||||
auto readWord(uint24 addr) -> uint16;
|
||||
|
@ -11,4 +14,12 @@ private:
|
|||
uint8 ram[64 * 1024];
|
||||
};
|
||||
|
||||
struct BusAPU : Processor::Z80::Bus {
|
||||
auto read(uint16 addr) -> uint8 override;
|
||||
auto write(uint16 addr, uint8 data) -> void override;
|
||||
auto in(uint8 addr) -> uint8 override;
|
||||
auto out(uint8 addr, uint8 data) -> void override;
|
||||
};
|
||||
|
||||
extern Bus bus;
|
||||
extern BusAPU busAPU;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
struct Bus {
|
||||
auto read(uint16 addr) -> uint8;
|
||||
auto write(uint16 addr, uint8 data) -> void;
|
||||
struct Bus : Processor::Z80::Bus {
|
||||
auto read(uint16 addr) -> uint8 override;
|
||||
auto write(uint16 addr, uint8 data) -> void override;
|
||||
|
||||
auto in(uint8 addr) -> uint8;
|
||||
auto out(uint8 addr, uint8 data) -> void;
|
||||
auto in(uint8 addr) -> uint8 override;
|
||||
auto out(uint8 addr, uint8 data) -> void override;
|
||||
|
||||
private:
|
||||
uint8 ram[0x2000];
|
||||
|
|
|
@ -18,34 +18,12 @@ auto CPU::step(uint clocks) -> void {
|
|||
synchronize(psg);
|
||||
}
|
||||
|
||||
auto CPU::wait() -> void {
|
||||
step(1);
|
||||
}
|
||||
|
||||
auto CPU::read(uint16 addr) -> uint8 {
|
||||
step(1);
|
||||
return bus.read(addr);
|
||||
}
|
||||
|
||||
auto CPU::write(uint16 addr, uint8 data) -> void {
|
||||
step(1);
|
||||
return bus.write(addr, data);
|
||||
}
|
||||
|
||||
auto CPU::in(uint8 addr) -> uint8 {
|
||||
step(1);
|
||||
return bus.in(addr);
|
||||
}
|
||||
|
||||
auto CPU::out(uint8 addr, uint8 data) -> void {
|
||||
step(1);
|
||||
return bus.out(addr, data);
|
||||
}
|
||||
|
||||
auto CPU::power() -> void {
|
||||
Processor::Z80::power(&MasterSystem::bus);
|
||||
}
|
||||
|
||||
auto CPU::reset() -> void {
|
||||
Processor::Z80::reset();
|
||||
create(CPU::Enter, system.colorburst());
|
||||
}
|
||||
|
||||
|
|
|
@ -5,12 +5,6 @@ struct CPU : Processor::Z80, Thread {
|
|||
auto main() -> void;
|
||||
auto step(uint clocks) -> void;
|
||||
|
||||
auto wait() -> void override;
|
||||
auto read(uint16 addr) -> uint8 override;
|
||||
auto write(uint16 addr, uint8 data) -> void override;
|
||||
auto in(uint8 addr) -> uint8 override;
|
||||
auto out(uint8 addr, uint8 data) -> void override;
|
||||
|
||||
auto power() -> void;
|
||||
auto reset() -> void;
|
||||
};
|
||||
|
|
|
@ -1,120 +1,108 @@
|
|||
auto Z80::disassemble(uint16 pc) -> string {
|
||||
string output{hex(pc, 4L), " "};
|
||||
string s;
|
||||
s.append(hex(pc, 4L), " ");
|
||||
|
||||
output.append(pad(disassembleOpcode(pc), -18, ' '));
|
||||
uint8 prefix = 0x00;
|
||||
while(true) {
|
||||
auto code = bus->read(pc++);
|
||||
if(code == 0xdd || code == 0xfd) {
|
||||
prefix = code;
|
||||
continue;
|
||||
}
|
||||
s.append(pad(disassemble__(pc, prefix, code), -18L, ' '));
|
||||
break;
|
||||
}
|
||||
|
||||
output.append(
|
||||
" AF:", hex(r.af, 4L),
|
||||
" BC:", hex(r.bc, 4L),
|
||||
" DE:", hex(r.de, 4L),
|
||||
" HL:", hex(r.hl, 4L),
|
||||
" IX:", hex(r.ix, 4L),
|
||||
" IY:", hex(r.iy, 4L),
|
||||
" SP:", hex(r.sp, 4L)
|
||||
);
|
||||
s.append(" AF:", hex(r.af, 4L));
|
||||
s.append(" BC:", hex(r.bc, 4L));
|
||||
s.append(" DE:", hex(r.de, 4L));
|
||||
s.append(" HL:", hex(r.hl, 4L));
|
||||
s.append(" IX:", hex(r.ix, 4L));
|
||||
s.append(" IY:", hex(r.iy, 4L));
|
||||
s.append(" SP:", hex(r.sp, 4L));
|
||||
|
||||
return output;
|
||||
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 W hex(y << 8 | x << 0, 4L)
|
||||
#define R hex(pc + 2 + (int8)x, 4L)
|
||||
#define R hex(pc + 1 + (int8)x, 4L)
|
||||
|
||||
auto Z80::disassembleOpcode(uint16 pc) -> string {
|
||||
auto o = read(pc + 0);
|
||||
auto x = read(pc + 1);
|
||||
auto y = read(pc + 2);
|
||||
auto z = read(pc + 3);
|
||||
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);
|
||||
|
||||
switch(o) {
|
||||
case 0x00: return {"nop "};
|
||||
case 0x18: return {"jr $", R};
|
||||
case 0x20: return {"jr nz,$", R};
|
||||
case 0x28: return {"jr z,$", R};
|
||||
case 0x30: return {"jr nc,$", R};
|
||||
case 0x38: return {"jr c,$", R};
|
||||
case 0xb8: return {"cp b"};
|
||||
case 0xb9: return {"cp c"};
|
||||
case 0xba: return {"cp d"};
|
||||
case 0xbb: return {"cp e"};
|
||||
case 0xbc: return {"cp h"};
|
||||
case 0xbd: return {"cp l"};
|
||||
case 0xbe: return {"cp (hl)"};
|
||||
case 0xbf: return {"cp a"};
|
||||
case 0xc2: return {"jp nz,$", W};
|
||||
case 0xc3: return {"jp $", W};
|
||||
case 0xca: return {"jp z,$", W};
|
||||
case 0xd2: return {"jp nc,$", W};
|
||||
case 0xda: return {"jp c,$", W};
|
||||
case 0xdb: return {"in a,($", X, ")"};
|
||||
case 0xdd: return disassembleOpcodeDD(pc + 1);
|
||||
case 0xe2: return {"jp po,$", W};
|
||||
case 0xe9: return {"jp hl"};
|
||||
case 0xea: return {"jp pe,$", W};
|
||||
case 0xed: return disassembleOpcodeED(pc + 1);
|
||||
case 0xf2: return {"jp p,$", W};
|
||||
case 0xf3: return {"di "};
|
||||
case 0xfa: return {"jp m,$", W};
|
||||
case 0xfd: return disassembleOpcodeFD(pc + 1);
|
||||
case 0xfe: return {"cp $", X};
|
||||
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};
|
||||
}
|
||||
|
||||
return {"??? (", hex(o, 2L), " ", X, " ", Y, " ", Z, ")"};
|
||||
return {"???: ", hex(code, 2L)};
|
||||
}
|
||||
|
||||
auto Z80::disassembleOpcodeDD(uint16 pc) -> string {
|
||||
auto o = read(pc + 0);
|
||||
auto x = read(pc + 1);
|
||||
auto y = read(pc + 2);
|
||||
auto z = read(pc + 3);
|
||||
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);
|
||||
|
||||
switch(o) {
|
||||
case 0xe9: return {"jp ix"};
|
||||
switch(code) {
|
||||
}
|
||||
|
||||
return {"??? (dd ", hex(o, 2L), " ", X, " ", Y, ")"};
|
||||
return {"???: cb ", hex(code, 2L)};
|
||||
}
|
||||
|
||||
auto Z80::disassembleOpcodeED(uint16 pc) -> string {
|
||||
auto o = read(pc + 0);
|
||||
auto x = read(pc + 1);
|
||||
auto y = read(pc + 2);
|
||||
auto z = read(pc + 3);
|
||||
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);
|
||||
|
||||
switch(o) {
|
||||
case 0x40: return {"in b,(c)"};
|
||||
switch(code) {
|
||||
case 0x46: return {"im 0"};
|
||||
case 0x48: return {"in c,(c)"};
|
||||
case 0x50: return {"in d,(c)"};
|
||||
case 0x56: return {"im 1"};
|
||||
case 0x58: return {"in e,(c)"};
|
||||
case 0x5e: return {"im 2"};
|
||||
case 0x60: return {"in h,(c)"};
|
||||
case 0x68: return {"in l,(c)"};
|
||||
case 0x70: return {"in (c)"};
|
||||
case 0x78: return {"in a,(c)"};
|
||||
}
|
||||
|
||||
return {"??? (ed ", hex(o, 2L), " ", X, " ", Y, ")"};
|
||||
}
|
||||
|
||||
auto Z80::disassembleOpcodeFD(uint16 pc) -> string {
|
||||
auto o = read(pc + 0);
|
||||
auto x = read(pc + 1);
|
||||
auto y = read(pc + 2);
|
||||
auto z = read(pc + 3);
|
||||
|
||||
switch(o) {
|
||||
case 0xe9: return {"jp iy"};
|
||||
}
|
||||
|
||||
return {"??? (fd ", hex(o, 2L), " ", X, " ", Y, ")"};
|
||||
return {"???: ed ", hex(code, 2L)};
|
||||
}
|
||||
|
||||
#undef H
|
||||
#undef L
|
||||
#undef HL
|
||||
#undef W
|
||||
#undef X
|
||||
#undef Y
|
||||
#undef Z
|
||||
#undef W
|
||||
#undef R
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
auto Z80::trap(uint8_t prefix, uint8_t opcode) -> void {
|
||||
print("[Z80] unimplemented instruction: ", prefix ? pad(hex(prefix, 2L), ' ', -3) : "", hex(opcode, 2L), "\n");
|
||||
auto Z80::trap(uint8 prefix, uint8 code) -> void {
|
||||
print("[Z80] unimplemented instruction: ", prefix ? pad(hex(prefix, 2L), -3L, ' ') : "", hex(code, 2L), "\n");
|
||||
print("[Z80] instructions executed: ", --instructionsExecuted, "\n");
|
||||
while(true) wait();
|
||||
}
|
||||
|
||||
#define op(id, name, ...) case id: return instruction##name(__VA_ARGS__);
|
||||
|
||||
auto Z80::instruction() -> void {
|
||||
#if 1
|
||||
if(instructionsExecuted < 20)
|
||||
|
@ -14,76 +12,116 @@ auto Z80::instruction() -> void {
|
|||
|
||||
instructionsExecuted++;
|
||||
|
||||
r.r = (r.r & 0x80) | (r.r + 1 & 0x7f);
|
||||
auto code = opcode();
|
||||
if(code == 0xdd || code == 0xfd) {
|
||||
r.prefix = code;
|
||||
return;
|
||||
}
|
||||
instruction__(code);
|
||||
r.prefix = 0x00;
|
||||
}
|
||||
|
||||
auto opcode = read(r.pc++);
|
||||
switch(opcode) {
|
||||
#define op(id, name, ...) case id: return instruction##name(__VA_ARGS__);
|
||||
|
||||
#define A r.a
|
||||
#define F r.f
|
||||
#define B r.b
|
||||
#define C r.c
|
||||
#define D r.d
|
||||
#define E r.e
|
||||
#define H r.prefix == 0xdd ? r.ixh : r.prefix == 0xfd ? r.iyh : r.h
|
||||
#define L r.prefix == 0xdd ? r.ixl : r.prefix == 0xfd ? r.iyl : r.l
|
||||
|
||||
#define AF r.af
|
||||
#define BC r.bc
|
||||
#define DE r.de
|
||||
#define HL r.prefix == 0xdd ? r.ix : r.prefix == 0xfd ? r.iy : r.hl
|
||||
|
||||
#define CF r.p.c
|
||||
#define NF r.p.n
|
||||
#define PF r.p.p
|
||||
#define VF r.p.v
|
||||
#define XF r.p.x
|
||||
#define HF r.p.h
|
||||
#define YF r.p.y
|
||||
#define ZF r.p.z
|
||||
#define SF r.p.s
|
||||
|
||||
auto Z80::instruction__(uint8 code) -> void {
|
||||
switch(code) {
|
||||
op(0x00, NOP)
|
||||
op(0x18, JR_c, true)
|
||||
op(0x20, JR_c, r.p.z == 0)
|
||||
op(0x28, JR_c, r.p.z == 1)
|
||||
op(0x30, JR_c, r.p.c == 0)
|
||||
op(0x38, JR_c, r.p.c == 1)
|
||||
op(0xb8, CP_r, r.b)
|
||||
op(0xb9, CP_r, r.c)
|
||||
op(0xba, CP_r, r.d)
|
||||
op(0xbb, CP_r, r.e)
|
||||
op(0xbc, CP_r, r.h)
|
||||
op(0xbd, CP_r, r.l)
|
||||
op(0xbe, CP_ihl)
|
||||
op(0xbf, CP_r, r.a)
|
||||
op(0xc2, JP_c_nn, r.p.z == 0)
|
||||
op(0xc3, JP_c_nn, true)
|
||||
op(0xca, JP_c_nn, r.p.z == 1)
|
||||
op(0xd2, JP_c_nn, r.p.c == 0)
|
||||
op(0xda, JP_c_nn, r.p.c == 1)
|
||||
op(0x06, LD_r_n, B)
|
||||
op(0x0e, LD_r_n, C)
|
||||
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(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(0x36, LD_irr_n, HL)
|
||||
op(0x38, JR_c_e, CF == 1)
|
||||
op(0x3e, LD_r_n, A)
|
||||
op(0xc2, JP_c_nn, ZF == 0)
|
||||
op(0xc3, JP_c_nn, 1)
|
||||
op(0xca, JP_c_nn, ZF == 1)
|
||||
op(0xcb, CB, opcode())
|
||||
op(0xd2, JP_c_nn, CF == 0)
|
||||
op(0xda, JP_c_nn, CF == 1)
|
||||
op(0xdb, IN_a_in)
|
||||
op(0xdd, DD)
|
||||
op(0xe2, JP_c_nn, r.p.p == 0)
|
||||
op(0xe9, JP_rr, r.hl)
|
||||
op(0xea, JP_c_nn, r.p.p == 1)
|
||||
op(0xed, ED)
|
||||
op(0xf2, JP_c_nn, r.p.s == 0)
|
||||
op(0xe2, JP_c_nn, PF == 0)
|
||||
op(0xea, JP_c_nn, PF == 1)
|
||||
op(0xed, ED, opcode())
|
||||
op(0xf2, JP_c_nn, SF == 0)
|
||||
op(0xf3, DI)
|
||||
op(0xfa, JP_c_nn, r.p.s == 1)
|
||||
op(0xfd, FD)
|
||||
op(0xfa, JP_c_nn, SF == 1)
|
||||
op(0xfb, EI)
|
||||
op(0xfe, CP_n)
|
||||
}
|
||||
trap(0x00, opcode);
|
||||
|
||||
trap(0x00, code);
|
||||
}
|
||||
|
||||
auto Z80::instructionDD() -> void {
|
||||
auto opcode = read(r.pc++);
|
||||
switch(opcode) {
|
||||
op(0xe9, JP_rr, r.ix)
|
||||
auto Z80::instructionCB(uint8 code) -> void {
|
||||
switch(code) {
|
||||
}
|
||||
trap(0xdd, opcode);
|
||||
|
||||
trap(0xcb, code);
|
||||
}
|
||||
|
||||
auto Z80::instructionED() -> void {
|
||||
auto opcode = read(r.pc++);
|
||||
switch(opcode) {
|
||||
op(0x40, IN_r_ic, r.b)
|
||||
op(0x46, IM, 0)
|
||||
op(0x48, IN_r_ic, r.c)
|
||||
op(0x50, IN_r_ic, r.d)
|
||||
op(0x56, IM, 1)
|
||||
op(0x58, IN_r_ic, r.e)
|
||||
op(0x5e, IM, 2)
|
||||
op(0x60, IN_r_ic, r.h)
|
||||
op(0x68, IN_r_ic, r.l)
|
||||
op(0x70, IN_r_ic, r.flag)
|
||||
op(0x78, IN_r_ic, r.a)
|
||||
auto Z80::instructionED(uint8 code) -> void {
|
||||
switch(code) {
|
||||
op(0x46, IM_o, 0)
|
||||
op(0x56, IM_o, 1)
|
||||
op(0x5e, IM_o, 2)
|
||||
}
|
||||
trap(0xed, opcode);
|
||||
}
|
||||
|
||||
auto Z80::instructionFD() -> void {
|
||||
auto opcode = read(r.pc++);
|
||||
switch(opcode) {
|
||||
op(0xe9, JP_rr, r.iy)
|
||||
}
|
||||
trap(0xfd, opcode);
|
||||
trap(0xed, code);
|
||||
}
|
||||
|
||||
#undef op
|
||||
|
||||
#undef A
|
||||
#undef F
|
||||
#undef B
|
||||
#undef C
|
||||
#undef D
|
||||
#undef E
|
||||
#undef H
|
||||
#undef L
|
||||
|
||||
#undef AF
|
||||
#undef BC
|
||||
#undef DE
|
||||
#undef HL
|
||||
|
||||
#undef CF
|
||||
#undef NF
|
||||
#undef PF
|
||||
#undef VF
|
||||
#undef XF
|
||||
#undef HF
|
||||
#undef YF
|
||||
#undef ZF
|
||||
#undef SF
|
||||
|
|
|
@ -1,60 +1,68 @@
|
|||
auto Z80::CP(uint8 x) -> void {
|
||||
uint16 y = r.a - x;
|
||||
//legend:
|
||||
// a = r.a
|
||||
// e = relative operand
|
||||
// in = (operand)
|
||||
// irr = (register-word)
|
||||
// o = opcode bits
|
||||
// n = operand
|
||||
// nn = operand-word
|
||||
// r = register
|
||||
|
||||
r.p.c = y > 0xff;
|
||||
auto Z80::CP(uint8 x) -> void {
|
||||
uint9 y = r.a - x;
|
||||
|
||||
r.p.c = y.bit(8);
|
||||
r.p.n = 1;
|
||||
r.p.v = (r.a ^ x) & (r.a ^ y) & 0x80;
|
||||
r.p.x = y.bit(3);
|
||||
r.p.h = (r.a ^ y ^ x) & 0x10;
|
||||
r.p.z = y == 0;
|
||||
r.p.s = y & 0x80;
|
||||
}
|
||||
|
||||
auto Z80::instructionCP_ihl() -> void {
|
||||
CP(read(r.hl));
|
||||
r.p.y = y.bit(5);
|
||||
r.p.z = (uint8)y == 0;
|
||||
r.p.s = y.bit(7);
|
||||
}
|
||||
|
||||
auto Z80::instructionCP_n() -> void {
|
||||
CP(read(r.pc++));
|
||||
}
|
||||
|
||||
auto Z80::instructionCP_r(uint8_t& x) -> void {
|
||||
CP(x);
|
||||
CP(operand());
|
||||
}
|
||||
|
||||
auto Z80::instructionDI() -> void {
|
||||
r.di = 1;
|
||||
r.iff1 = 0;
|
||||
r.iff2 = 0;
|
||||
}
|
||||
|
||||
auto Z80::instructionIM(uint mode) -> void {
|
||||
r.im = mode;
|
||||
auto Z80::instructionEI() -> void {
|
||||
r.iff1 = 1;
|
||||
r.iff2 = 1;
|
||||
}
|
||||
|
||||
auto Z80::instructionIM_o(uint2 code) -> void {
|
||||
wait(4);
|
||||
r.im = code;
|
||||
}
|
||||
|
||||
auto Z80::instructionIN_a_in() -> void {
|
||||
r.a = in(read(r.pc++));
|
||||
}
|
||||
|
||||
auto Z80::instructionIN_r_ic(uint8_t& x) -> void {
|
||||
x = in(read(r.c));
|
||||
r.p.n = 0;
|
||||
r.p.p = parity(x);
|
||||
r.p.h = 0;
|
||||
r.p.z = x == 0;
|
||||
r.p.s = x & 0x80;
|
||||
r.a = in(operand());
|
||||
}
|
||||
|
||||
auto Z80::instructionJP_c_nn(bool c) -> void {
|
||||
auto lo = read(r.pc++);
|
||||
auto hi = read(r.pc++);
|
||||
auto lo = operand();
|
||||
auto hi = operand();
|
||||
if(c) r.pc = hi << 8 | lo << 0;
|
||||
}
|
||||
|
||||
auto Z80::instructionJP_rr(uint16_t& x) -> void {
|
||||
r.pc = x;
|
||||
auto Z80::instructionJR_c_e(bool c) -> void {
|
||||
auto e = operand();
|
||||
if(!c) return;
|
||||
wait(5);
|
||||
r.pc += (int8)e;
|
||||
}
|
||||
|
||||
auto Z80::instructionJR_c(bool c) -> void {
|
||||
auto d = read(r.pc++);
|
||||
if(c) r.pc += (int8)d;
|
||||
auto Z80::instructionLD_irr_n(uint16_t& x) -> void {
|
||||
write(x, operand());
|
||||
}
|
||||
|
||||
auto Z80::instructionLD_r_n(uint8_t& x) -> void {
|
||||
x = operand();
|
||||
}
|
||||
|
||||
auto Z80::instructionNOP() -> void {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
auto Z80::wait(uint clocks) -> void {
|
||||
step(clocks);
|
||||
}
|
||||
|
||||
auto Z80::opcode() -> uint8 {
|
||||
step(4);
|
||||
return bus->read(r.pc++);
|
||||
}
|
||||
|
||||
auto Z80::operand() -> uint8 {
|
||||
step(3);
|
||||
return bus->read(r.pc++);
|
||||
}
|
||||
|
||||
auto Z80::read(uint16 addr) -> uint8 {
|
||||
step(3);
|
||||
return bus->read(addr);
|
||||
}
|
||||
|
||||
auto Z80::write(uint16 addr, uint8 data) -> void {
|
||||
step(3);
|
||||
return bus->write(addr, data);
|
||||
}
|
||||
|
||||
auto Z80::in(uint8 addr) -> uint8 {
|
||||
step(4);
|
||||
return bus->in(addr);
|
||||
}
|
||||
|
||||
auto Z80::out(uint8 addr, uint8 data) -> void {
|
||||
step(4);
|
||||
return bus->out(addr, data);
|
||||
}
|
|
@ -3,11 +3,13 @@
|
|||
|
||||
namespace Processor {
|
||||
|
||||
#include "memory.cpp"
|
||||
#include "instruction.cpp"
|
||||
#include "instructions.cpp"
|
||||
#include "disassembler.cpp"
|
||||
|
||||
auto Z80::power() -> void {
|
||||
auto Z80::power(Z80::Bus* bus) -> void {
|
||||
this->bus = bus;
|
||||
}
|
||||
|
||||
auto Z80::reset() -> void {
|
||||
|
@ -15,16 +17,17 @@ auto Z80::reset() -> void {
|
|||
r.bc = 0x0000;
|
||||
r.de = 0x0000;
|
||||
r.hl = 0x0000;
|
||||
r.ir = 0x0000;
|
||||
r.ix = 0x0000;
|
||||
r.iy = 0x0000;
|
||||
r.sp = 0x0000;
|
||||
r.pc = 0x0000;
|
||||
r.i = 0x00;
|
||||
r.r = 0x00;
|
||||
|
||||
r.di = false;
|
||||
r.ei = false;
|
||||
r.iff1 = 0;
|
||||
r.iff2 = 0;
|
||||
r.im = 0;
|
||||
|
||||
instructionsExecuted = 0;
|
||||
}
|
||||
|
||||
auto Z80::parity(uint8_t value) const -> bool {
|
||||
|
|
|
@ -5,45 +5,55 @@
|
|||
namespace Processor {
|
||||
|
||||
struct Z80 {
|
||||
virtual auto wait() -> void = 0;
|
||||
virtual auto read(uint16 addr) -> uint8 = 0;
|
||||
virtual auto write(uint16 addr, uint8 data) -> void = 0;
|
||||
virtual auto in(uint8 addr) -> uint8 = 0;
|
||||
virtual auto out(uint8 addr, uint8 data) -> void = 0;
|
||||
struct Bus {
|
||||
virtual auto read(uint16 addr) -> uint8 = 0;
|
||||
virtual auto write(uint16 addr, uint8 data) -> void = 0;
|
||||
virtual auto in(uint8 addr) -> uint8 = 0;
|
||||
virtual auto out(uint8 addr, uint8 data) -> void = 0;
|
||||
};
|
||||
|
||||
virtual auto step(uint clocks) -> void = 0;
|
||||
|
||||
//z80.cpp
|
||||
auto power() -> void;
|
||||
auto power(Z80::Bus*) -> void;
|
||||
auto reset() -> void;
|
||||
|
||||
auto parity(uint8_t) const -> bool;
|
||||
|
||||
//memory.cpp
|
||||
auto wait(uint clocks = 1) -> void;
|
||||
auto opcode() -> uint8;
|
||||
auto operand() -> uint8;
|
||||
auto read(uint16 addr) -> uint8;
|
||||
auto write(uint16 addr, uint8 data) -> void;
|
||||
auto in(uint8 addr) -> uint8;
|
||||
auto out(uint8 addr, uint8 data) -> void;
|
||||
|
||||
//instruction.cpp
|
||||
auto trap(uint8_t prefix, uint8_t opcode) -> void;
|
||||
auto trap(uint8 prefix, uint8 code) -> void;
|
||||
auto instruction() -> void;
|
||||
auto instructionDD() -> void;
|
||||
auto instructionED() -> void;
|
||||
auto instructionFD() -> void;
|
||||
auto instruction__(uint8 code) -> void;
|
||||
auto instructionCB(uint8 code) -> void;
|
||||
auto instructionED(uint8 code) -> void;
|
||||
|
||||
//instructions.cpp
|
||||
auto CP(uint8 x) -> void;
|
||||
auto instructionCP_ihl() -> void;
|
||||
auto CP(uint8) -> void;
|
||||
auto instructionCP_n() -> void;
|
||||
auto instructionCP_r(uint8_t&) -> void;
|
||||
auto instructionDI() -> void;
|
||||
auto instructionIM(uint) -> void;
|
||||
auto instructionEI() -> void;
|
||||
auto instructionIM_o(uint2) -> void;
|
||||
auto instructionIN_a_in() -> void;
|
||||
auto instructionIN_r_ic(uint8_t&) -> void;
|
||||
auto instructionJP_c_nn(bool) -> void;
|
||||
auto instructionJP_rr(uint16_t&) -> void;
|
||||
auto instructionJR_c(bool) -> void;
|
||||
auto instructionJR_c_e(bool) -> void;
|
||||
auto instructionLD_irr_n(uint16_t&) -> void;
|
||||
auto instructionLD_r_n(uint8_t&) -> void;
|
||||
auto instructionNOP() -> void;
|
||||
|
||||
//disassembler.cpp
|
||||
auto disassemble(uint16 pc) -> string;
|
||||
auto disassembleOpcode(uint16 pc) -> string;
|
||||
auto disassembleOpcodeDD(uint16 pc) -> string;
|
||||
auto disassembleOpcodeED(uint16 pc) -> string;
|
||||
auto disassembleOpcodeFD(uint16 pc) -> string;
|
||||
auto disassemble__(uint16 pc, uint8 prefix, uint8 code) -> string;
|
||||
auto disassembleCB(uint16 pc, uint8 prefix, uint8 code) -> string;
|
||||
auto disassembleED(uint16 pc, uint8 prefix, uint8 code) -> string;
|
||||
|
||||
struct Registers {
|
||||
union {
|
||||
|
@ -77,22 +87,34 @@ struct Z80 {
|
|||
struct { uint8_t order_msb2(h, l); };
|
||||
};
|
||||
|
||||
uint16_t ix;
|
||||
uint16_t iy;
|
||||
union {
|
||||
uint16_t ix;
|
||||
struct { uint8_t order_msb2(ixh, ixl); };
|
||||
};
|
||||
|
||||
union {
|
||||
uint16_t iy;
|
||||
struct { uint8_t order_msb2(iyh, iyl); };
|
||||
};
|
||||
|
||||
union {
|
||||
uint16_t ir;
|
||||
struct { uint8_t order_msb2(i, r); };
|
||||
};
|
||||
|
||||
uint16_t sp;
|
||||
uint16_t pc;
|
||||
|
||||
uint8_t i;
|
||||
uint8_t r;
|
||||
|
||||
boolean di; //disable interrupt
|
||||
boolean ei; //enable interrupt
|
||||
uint2 im; //interrupt mode (0-2)
|
||||
boolean iff1; //interrupt flip-flop 1
|
||||
boolean iff2; //interrupt flip-flop 2
|
||||
uint2 im; //interrupt mode (0-2)
|
||||
|
||||
uint8_t prefix;
|
||||
uint8_t flag;
|
||||
} r;
|
||||
|
||||
private:
|
||||
Bus* bus = nullptr;
|
||||
uint64 instructionsExecuted = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIByDCCAU6gAwIBAgIJAI83xahWv0iSMAoGCCqGSM49BAMDMB4xDTALBgNVBAMM
|
||||
BGJ5dXUxDTALBgNVBAoMBGJ5dXUwIBcNMTYwODMxMDQ1MjEzWhgPMjA5MTA4MTMw
|
||||
NDUyMTNaMB4xDTALBgNVBAMMBGJ5dXUxDTALBgNVBAoMBGJ5dXUwdjAQBgcqhkjO
|
||||
PQIBBgUrgQQAIgNiAAT5ArnlLKmJZrkmDwBNroM+djFS1CM/KLVXGZQUmkjyDJSB
|
||||
/JeC/aT3v4g236kzcHu4+FBDPT1MhPUmtFC+mGjnWjtQsGHuTknGYXpjOEK77PXy
|
||||
LL2m9gXB0eKE0SkMIdijVjBUMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYE
|
||||
FErJPHQ5yHMo18r8c0LI4XmrKjnRMB8GA1UdIwQYMBaAFErJPHQ5yHMo18r8c0LI
|
||||
4XmrKjnRMAoGCCqGSM49BAMDA2gAMGUCMQDAcBz38wdb5lJmcMf8Y1eqPZxXkgCt
|
||||
OZklW1cXZnoB2w3yjdImujHVyEfhK684HCkCMEjsxEUPRf8tB0UKO836qKmAKFHW
|
||||
OYBX8Sx6jlzonkb1miqjxiNQdTmGdkWk1IsP8Q==
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,13 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIB6zCCAXCgAwIBAgIJAPQ6cLpDt9l8MAoGCCqGSM49BAMDMB4xDTALBgNVBAMM
|
||||
BGJ5dXUxDTALBgNVBAoMBGJ5dXUwIBcNMTYwODMxMDQ1MzQyWhgPMjA5MTA4MTMw
|
||||
NDUzNDJaMCIxETAPBgNVBAMMCGJ5dXUub3JnMQ0wCwYDVQQKDARieXV1MHYwEAYH
|
||||
KoZIzj0CAQYFK4EEACIDYgAEuYjwx8y8nO9yAR7Hb8AB8lB1SSXk1lBm9ofcEzkN
|
||||
SLOvrC+ESHR1C+w9krlbJlSq2wPA482DIW3aLukfNIdwhuTciVFBZfk0bgRgVqXq
|
||||
Ha+iyL64/naqzWGxk5m/HDkFo3QwcjAMBgNVHRMBAf8EAjAAMCIGA1UdEQEB/wQY
|
||||
MBaCCGJ5dXUub3JnggoqLmJ5dXUub3JnMB0GA1UdDgQWBBSJd/vrUirTNFcxur/9
|
||||
hN+Q55H+AzAfBgNVHSMEGDAWgBRKyTx0OchzKNfK/HNCyOF5qyo50TAKBggqhkjO
|
||||
PQQDAwNpADBmAjEAh5Jc3nepWmrRJDLaGzy7ews23uEcrz3PfBbtJrTC3qw5b2Ig
|
||||
fqZ6h5/nG7BXAeq9AjEAnxwn221GihthlL6nzSS5SRyjmR6crGfqWcQwSQTp8b+8
|
||||
DqXqRKiYVHoiedKJslCF
|
||||
-----END CERTIFICATE-----
|
Loading…
Reference in New Issue