1
0
mirror of https://github.com/jscrane/r65emu.git synced 2025-08-05 05:26:24 +00:00

Z80 bugfixes

Work-in-progress merging z80 fixes
This commit is contained in:
Stephen Crane
2025-03-07 15:00:58 +00:00
committed by GitHub
parent 43d14585d1
commit 75622ef159
7 changed files with 267 additions and 381 deletions

View File

@@ -3,17 +3,24 @@
#undef PC
#define O(o, e) case o: e(); break
#define A(o, e, a) case o: e(a); break
#define C(o) case o:
#define D(e) default: e(); break
#define E(op, expr) case op: expr; break
#define O(op, fn) E(op, fn())
#define A(op, e, a) E(op, e(a))
#define C(op) case op:
#define D(fn) default: fn(); break
#if defined(UNDOCUMENTED_OPS)
#define U(op, expr) case op: expr; break
#else
#define U(op, expr)
#endif
class CPU: public Checkpointable {
public:
virtual ~CPU() {}
virtual void run(unsigned instructions) =0;
virtual void reset() =0;
virtual void raise(uint8_t level) =0;
virtual void raise(int level) =0;
virtual char *status(char *buf, size_t n, bool hdr = false) =0;
virtual void checkpoint(Stream &s) = 0;

View File

@@ -24,7 +24,7 @@ void i8080::reset() {
_halted = false;
}
void i8080::raise(uint8_t level) {
void i8080::raise(int level) {
if (flags.I) {
flags.I = 0;
_irq_pending = 0;

View File

@@ -13,7 +13,7 @@ public:
void run(unsigned);
void reset();
void raise(uint8_t);
void raise(int);
char *status(char *buf, size_t n, bool hdr=false);
void checkpoint(Stream &);
@@ -59,7 +59,7 @@ private:
} flags;
uint8_t SR;
};
uint8_t _irq_pending;
int _irq_pending;
PortDevice &_ports;
void _op(uint8_t op);

View File

@@ -76,7 +76,7 @@ void r6502::restore(Stream &s)
#endif
}
void r6502::raise(uint8_t level) {
void r6502::raise(int level) {
if (level < 0)
nmi();
else if (!P.bits.I)

View File

@@ -7,7 +7,7 @@
class r6502: public CPU {
public:
void raise(uint8_t);
void raise(int);
void reset();
void run(unsigned);
char *status(char *buf, size_t n, bool hdr=false);

View File

@@ -8,13 +8,26 @@
char *z80::status(char *buf, size_t n, bool hdr) {
#if DEBUGGING & DEBUG_CPU
uint8_t op = _mem[PC];
static bool first = true;
snprintf(buf, n,
"%s%04x %02x %04x %04x %04x %04x %04x %04x %04x %04x %04x %d%d%d "
"%04x %d%d%d%d%d%d%d%d",
hdr? "_pc_ op _af_ _bc_ _de_ _hl_ _af' _bc' _de' _hl' _ir_ imff _sp_ sz5h3pnc\r\n": "",
PC, op, AF, BC, DE, HL, AF_, BC_, DE_, HL_, IR, _im, _iff1, _iff2,
SP, flags.S, flags.Z, flags._5, flags.H, flags._3, flags.P, flags.N, flags.C);
"%s%04x %02x %d%d%d%d%d%d %02x %02x %d%d %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x ",
hdr || first? "PC A SZHPNC I R IFF BC DE HL A'F' B'C' D'E' H'L' IX IY SP OP\r\n": "",
PC, A, flags.S, flags.Z, flags.H, flags.P, flags.N, flags.C, I, R & 0x7f, _iff1, _iff2,
BC, DE, HL, AF_, BC_, DE_, HL_, IX, IY, SP);
first = false;
uint8_t op = _mem[PC], op1 = _mem[PC+1];
char obuf[16];
if (op == 0xdd || op == 0xfd) {
if (op1 == 0xcb)
snprintf(obuf, sizeof(obuf), "%02x cb %02x %02x", op, (byte)_mem[PC+2], (byte)_mem[PC+3]);
else
snprintf(obuf, sizeof(obuf), "%02x %02x", op, op1);
} else if (op == 0xed)
snprintf(obuf, sizeof(obuf), "ed %02x", op1);
else
snprintf(obuf, sizeof(obuf), "%02x", op);
strncat(buf, obuf, n);
#endif
return buf;
}
@@ -98,27 +111,47 @@ void z80::reset() {
}
void z80::_handle_interrupt() {
if (_irq_pending < 0 || _iff1) {
if (_halted) {
_halted = false;
PC++;
}
_push(PC);
if (_irq_pending < 0) { // NMI
_iff2 = _iff1;
PC = 0x0066;
ts(11);
} else {
_iff1 = _iff2 = false;
R++;
if (_im == 0 || _im == 1)
PC = 0x0038;
else if (_im == 2)
PC = _rw(_irq_pending + (0x100 * I));
ts(7);
}
}
int irq = _irq_pending;
_irq_pending = 0;
if (!irq && !_iff1) {
DBG_CPU(println("No interrupt!"));
return;
}
if (_halted) {
_halted = false;
PC++;
}
_push(PC);
if (irq < 0) { // NMI
DBG_CPU(println("NMI"));
_iff2 = _iff1;
PC = 0x66;
ts(11);
return;
}
_iff1 = _iff2 = false;
R++;
if (_im == 0)
switch (irq) {
case 0xc7: PC = 0x00; break;
case 0xcf: PC = 0x08; break;
case 0xd7: PC = 0x10; break;
case 0xdf: PC = 0x18; break;
case 0xe7: PC = 0x20; break;
case 0xef: PC = 0x28; break;
case 0xf7: PC = 0x30; break;
case 0xff: PC = 0x38; break;
}
else if (_im == 1)
PC = 0x38;
else if (_im == 2)
PC = _rw(irq + (0x100 * I));
ts(7);
DBG_CPU(printf("IM: %d PC: %04x\r\n", _im, PC));
}
void z80::daa() {
@@ -154,272 +187,129 @@ void z80::_step_idx(EXT_OP f) {
}
void z80::_ddfd(uint16_t &ix, uint8_t &ixL, uint8_t &ixH, EXT_OP op) {
switch (_fetch_op()) {
case 0x09:
_add16(ix, BC);
break;
case 0x19:
_add16(ix, DE);
break;
case 0x21:
ix = _rwpc();
break;
case 0x22:
_swPC(ix);
break;
case 0x23:
ix++;
_mc(IR, 1); _mc(IR, 1);
break;
case 0x24:
_inc(ixH);
break;
case 0x25:
_dec(ixH);
break;
case 0x26:
ixH = _rb(PC++);
break;
case 0x29:
_add16(ix, ix);
break;
case 0x2a:
ix = _rwPC();
break;
case 0x2b:
ix--;
_mc(IR, 1); _mc(IR, 1);
break;
case 0x2c:
_inc(ixL);
break;
case 0x2d:
_dec(ixL);
break;
case 0x2e:
ixL = _rb(PC++);
break;
case 0x34:
_incO(ix);
break;
case 0x35:
_decO(ix);
break;
case 0x36:
_sbO(ix);
break;
case 0x39:
_add16(ix, SP);
break;
case 0x44:
B = ixH;
break;
case 0x45:
B = ixL;
break;
case 0x46:
B = _rbO(ix);
break;
case 0x4c:
C = ixH;
break;
case 0x4d:
C = ixL;
break;
case 0x4e:
C = _rbO(ix);
break;
case 0x54:
D = ixH;
break;
case 0x55:
D = ixL;
break;
case 0x56:
D = _rbO(ix);
break;
case 0x5c:
E = ixH;
break;
case 0x5d:
E = ixL;
break;
case 0x5e:
E = _rbO(ix);
break;
case 0x60:
ixH = B;
break;
case 0x61:
ixH = C;
break;
case 0x62:
ixH = D;
break;
case 0x63:
ixH = E;
break;
case 0x64:
break;
case 0x65:
ixH = ixL;
break;
case 0x66:
H = _rbO(ix);
break;
case 0x67:
ixH = A;
break;
case 0x68:
ixL = B;
break;
case 0x69:
ixL = C;
break;
case 0x6a:
ixL = D;
break;
case 0x6b:
ixL = E;
break;
case 0x6c:
ixL = ixH;
break;
case 0x6d:
break;
case 0x6e:
L = _rbO(ix);
break;
case 0x6f:
ixL = A;
break;
case 0x70:
_sbO(ix, B);
break;
case 0x71:
_sbO(ix, C);
break;
case 0x72:
_sbO(ix, D);
break;
case 0x73:
_sbO(ix, E);
break;
case 0x74:
_sbO(ix, H);
break;
case 0x75:
_sbO(ix, L);
break;
case 0x77:
_sbO(ix, A);
break;
case 0x7c:
A = ixH;
break;
case 0x7d:
A = ixL;
break;
case 0x7e:
A = _rbO(ix);
break;
case 0x84:
_add(ixH);
break;
case 0x85:
_add(ixL);
break;
case 0x86:
_add(_rbO(ix));
break;
case 0x8c:
_adc(ixH);
break;
case 0x8d:
_adc(ixL);
break;
case 0x8e:
_adc(_rbO(ix));
break;
case 0x94:
_sub(ixH);
break;
case 0x95:
_sub(ixL);
break;
case 0x96:
_sub(_rbO(ix));
break;
case 0x9c:
_sbc(ixH);
break;
case 0x9d:
_sbc(ixL);
break;
case 0x9e:
_sbc(_rbO(ix));
break;
case 0xa4:
_and(ixH);
break;
case 0xa5:
_and(ixL);
break;
case 0xa6:
_and(_rbO(ix));
break;
case 0xac:
_xor(ixH);
break;
case 0xad:
_xor(ixL);
break;
case 0xae:
_xor(_rbO(ix));
break;
case 0xb4:
_or(ixH);
break;
case 0xb5:
_or(ixL);
break;
case 0xb6:
_or(_rbO(ix));
break;
case 0xbc:
_cmp(ixH);
break;
case 0xbd:
_cmp(ixL);
break;
case 0xbe:
_cmp(_rbO(ix));
break;
case 0xcb:
_step_idx(op);
break;
case 0xe1:
ix = _pop();
break;
case 0xe3:
_exSP(ix);
break;
case 0xe5:
_mc(IR, 1);
_push(ix);
break;
case 0xe9:
PC = ix;
break;
case 0xf9:
_mc(IR, 1); _mc(IR, 1);
SP = ix;
break;
uint8_t o = _fetch_op();
switch (o) {
E(0x09, _add16(ix, BC));
E(0x19, _add16(ix, DE));
E(0x21, ix = _rwpc());
E(0x22, _swPC(ix));
E(0x23, ix++; _mc(IR, 1); _mc(IR, 1));
U(0x24, _inc(ixH));
U(0x25, _dec(ixH));
U(0x26, ixH = _rb(PC++));
E(0x29, _add16(ix, ix));
E(0x2a, ix = _rwPC());
E(0x2b, ix--; _mc(IR, 1); _mc(IR, 1));
U(0x2c, _inc(ixL));
U(0x2d, _dec(ixL));
U(0x2e, ixL = _rb(PC++));
E(0x34, _incO(ix));
E(0x35, _decO(ix));
E(0x36, _sbO(ix));
E(0x39, _add16(ix, SP));
U(0x44, B = ixH);
U(0x45, B = ixL);
E(0x46, B = _rbO(ix));
U(0x4c, C = ixH);
U(0x4d, C = ixL);
E(0x4e, C = _rbO(ix));
U(0x54, D = ixH);
U(0x55, D = ixL);
E(0x56, D = _rbO(ix));
U(0x5c, E = ixH);
U(0x5d, E = ixL);
E(0x5e, E = _rbO(ix));
U(0x60, ixH = B);
U(0x61, ixH = C);
U(0x62, ixH = D);
U(0x63, ixH = E);
U(0x64, /* FIXME */);
U(0x65, ixH = ixL);
E(0x66, H = _rbO(ix));
U(0x67, ixH = A);
U(0x68, ixL = B);
U(0x69, ixL = C);
U(0x6a, ixL = D);
U(0x6b, ixL = E);
U(0x6c, ixL = ixH);
U(0x6d, /* FIXME */);
E(0x6e, L = _rbO(ix));
U(0x6f, ixL = A);
E(0x70, _sbO(ix, B));
E(0x71, _sbO(ix, C));
E(0x72, _sbO(ix, D));
E(0x73, _sbO(ix, E));
E(0x74, _sbO(ix, H));
E(0x75, _sbO(ix, L));
E(0x77, _sbO(ix, A));
U(0x7c, A = ixH);
U(0x7d, A = ixL);
E(0x7e, A = _rbO(ix));
U(0x84, _add(ixH));
U(0x85, _add(ixL));
E(0x86, _add(_rbO(ix)));
U(0x8c, _adc(ixH));
U(0x8d, _adc(ixL));
E(0x8e, _adc(_rbO(ix)));
U(0x94, _sub(ixH));
U(0x95, _sub(ixL));
E(0x96, _sub(_rbO(ix)));
U(0x9c, _sbc(ixH));
U(0x9d, _sbc(ixL));
E(0x9e, _sbc(_rbO(ix)));
U(0xa4, _and(ixH));
U(0xa5, _and(ixL));
E(0xa6, _and(_rbO(ix)));
U(0xac, _xor(ixH));
U(0xad, _xor(ixL));
E(0xae, _xor(_rbO(ix)));
U(0xb4, _or(ixH));
U(0xb5, _or(ixL));
E(0xb6, _or(_rbO(ix)));
U(0xbc, _cmp(ixH));
U(0xbd, _cmp(ixL));
E(0xbe, _cmp(_rbO(ix)));
E(0xcb, _step_idx(op));
E(0xe1, ix = _pop());
E(0xe3, _exSP(ix));
E(0xe5, _mc(IR, 1); _push(ix));
E(0xe9, PC = ix);
E(0xf9, _mc(IR, 1); _mc(IR, 1); SP = ix);
default:
ERR(printf("unimplemented dd/fd op: %02x\r\n", o));
}
}
void z80::ed() {
switch (_fetch_op()) {
uint8_t op = _fetch_op();
switch (op) {
O(0x40, inB);
O(0x41, outB);
O(0x42, sbcBC);
@@ -507,6 +397,9 @@ void z80::ed() {
O(0xb9, cpdr);
O(0xba, indr);
O(0xbb, outdr);
default:
ERR(printf("unimplemented ed op: %02x\r\n", op));
}
}

152
src/z80.h
View File

@@ -11,7 +11,7 @@ public:
void run(unsigned);
void reset();
void raise(uint8_t level) { _irq_pending = level; }
void raise(int level) { _irq_pending = level; }
char *status(char *buf, size_t n, bool hdr=false);
void checkpoint(Stream &);
@@ -145,7 +145,7 @@ private:
unsigned long _ts;
uint8_t _irq_pending;
int _irq_pending;
PortDevice &_ports;
uint8_t parity(uint8_t);
@@ -403,7 +403,11 @@ private:
inline void incb() { _inc(B); }
inline void decb() { _dec(B); }
inline void ldb() { B = _rb(PC++); }
inline void rlca() { flags.C = ((A & 0x80) >> 7); A = (A << 1) | flags.C; }
inline void rlca() {
flags.H = flags.N = 0;
flags.C = ((A & 0x80) >> 7);
A = (A << 1) | flags.C;
}
// 0x08
inline void exaf() { _exch(AF, AF_); }
@@ -431,6 +435,7 @@ private:
inline void rla() {
uint8_t b = (A << 1) | flags.C;
flags.C = (A & 0x80) >> 7;
flags.H = flags.N = 0;
A = b;
}
@@ -449,6 +454,7 @@ private:
inline void rra() {
uint8_t b = (A >> 1) | (flags.C << 7);
flags.C = (A & 1);
flags.H = flags.N = 0;
A = b;
}
@@ -490,7 +496,17 @@ private:
inline void inca() { _inc(A); }
inline void deca() { _dec(A); }
inline void lda() { A = _rb(PC++); }
inline void ccf() { flags.H = flags.C; flags.C = flags.N = 0; _35(A); }
inline void ccf() {
if (flags.C) {
flags.C = 0;
flags.H = 1;
} else {
flags.H = 0;
flags.C = 1;
}
flags.N = 0;
_35(A);
}
// 0x40
inline void ldbb() {}
@@ -1271,19 +1287,15 @@ private:
}
inline void cpi() {
uint8_t b = _rb(HL);
flags.H = ((b & 0x0f) > (A & 0x0f));
b = A - b;
_mc(HL, 1); _mc(HL, 1); _mc(HL, 1);
_mc(HL, 1); _mc(HL, 1);
uint8_t c = A;
uint8_t f = (flags.C != 0);
_sub(b);
HL++;
BC--;
b = A;
A = c;
if (flags.H) b--;
flags.C = f;
flags.N = 1;
flags.P = (BC != 0);
_35(b);
_sz35(b);
flags._5 = ((b & 0x02) != 0);
_memptr++;
}
@@ -1327,17 +1339,17 @@ private:
}
inline void cpd_() {
uint8_t b = _rb(HL);
uint8_t c = A - b - flags.H;
flags.H = ((b & 0x0f) > (A & 0x0f));
b = A - b;
_mc(HL, 1); _mc(HL, 1); _mc(HL, 1);
_mc(HL, 1); _mc(HL, 1);
HL--;
BC--;
flags.N = 1;
flags.P = (BC != 0);
_sz35(c);
flags._5 = ((c & 0x02) != 0);
_sz35(b);
flags._5 = ((b & 0x02) != 0);
_memptr--;
// FIXME: flag H
}
inline void ind() {
_mc(IR, 1);
@@ -1366,48 +1378,33 @@ private:
_sz35(B);
}
inline void ldir() {
uint8_t b = _rb(HL);
BC--;
_sb(DE, b);
_mc(DE, 1);
_mc(DE, 1);
uint8_t b;
do {
b = _rb(HL);
_sb(DE, b);
_mc(DE, 1);
_mc(DE, 1);
DE++;
HL++;
} while (--BC);
b += A;
flags.P = (BC != 0);
_35(b);
flags._5 = ((b & 0x02) != 0);
flags.N = flags.H = 0;
if (BC) {
_mc(DE, 1); _mc(DE, 1); _mc(DE, 1);
_mc(DE, 1); _mc(DE, 1);
PC -= 2;
_memptr = PC+1;
}
DE++;
HL++;
flags.N = flags.P = flags.H = 0;
}
inline void cpir() {
uint8_t b = _rb(HL);
_mc(HL, 1); _mc(HL, 1); _mc(HL, 1);
_mc(HL, 1); _mc(HL, 1);
uint8_t c = A;
uint8_t f = (flags.C != 0);
_sub(b);
BC--;
b -= A;
A = c;
flags.C = f;
flags.P = (BC != 0);
if (flags.H) b--;
_35(b);
flags._5 = ((b & 0x02) != 0);
_memptr++;
if (!flags.Z) {
uint8_t d;
do {
uint8_t b = _rb(HL++);
_mc(HL, 1); _mc(HL, 1); _mc(HL, 1);
_mc(HL, 1); _mc(HL, 1);
PC -= 2;
_memptr = PC+1;
}
HL++;
flags.H = ((b & 0x0f) > (A & 0xf));
d = A - b;
} while (--BC && d);
flags.N = 1;
flags.P = (BC != 0);
_sz35(d);
flags._5 = ((d & 0x02) != 0);
}
inline void inir() {
_mc(IR, 1);
@@ -1444,44 +1441,33 @@ private:
}
}
inline void lddr() {
uint8_t b = _rb(HL);
BC--;
_sb(DE, b);
_mc(DE, 1);
_mc(DE, 1);
uint8_t b;
do {
b = _rb(HL);
_sb(DE, b);
_mc(DE, 1);
_mc(DE, 1);
DE--;
HL--;
} while (--BC);
b += A;
flags.P = (BC != 0);
_35(b);
flags._5 = ((b & 0x02) != 0);
flags.N = flags.H = 0;
if (BC) {
_mc(DE, 1); _mc(DE, 1); _mc(DE, 1);
_mc(DE, 1); _mc(DE, 1);
PC -= 2;
_memptr = PC+1;
}
DE--;
HL--;
flags.N = flags.H = flags.P = 0;
}
inline void cpdr() {
uint8_t b = _rb(HL);
uint8_t c = A - b;
_mc(HL, 1); _mc(HL, 1); _mc(HL, 1);
_mc(HL, 1); _mc(HL, 1);
BC--;
flags.N = 1;
flags.P = (BC != 0);
_sz35(c);
flags._5 = ((c & 0x02) != 0);
// FIXME: flag H
_memptr--;
if (BC) {
uint8_t d;
do {
uint8_t b = _rb(HL--);
_mc(HL, 1); _mc(HL, 1); _mc(HL, 1);
_mc(HL, 1); _mc(HL, 1);
PC -= 2;
_memptr = PC+1;
}
HL--;
flags.H = ((b & 0x0f) > (A & 0xf));
d = A - b;
} while (--BC && d);
flags.N = 1;
flags.P = (BC != 0);
_sz35(d);
flags._5 = ((d & 0x02) != 0);
}
inline void indr() {
_mc(IR, 1);
@@ -1519,8 +1505,8 @@ private:
PC -= 2;
}
}
// 0xDDCB extended instructions
// 0xDDCB extended instructions
inline uint16_t _rbIX(uint8_t &b, uint8_t o) {
uint16_t a = _ads(IX, o);
_memptr = a;