From 643b0184d73397626e0e604b17a037d84206adb5 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sat, 16 Apr 2016 16:45:31 -0500 Subject: [PATCH] Implement more load instructions; bugfixes. --- src/disassembler.c | 1 + src/logging.h | 2 +- src/z80.c | 37 ++++++- src/z80_ops.inc.c | 294 ++++++++++++++++++++++++++++++----------------------- 4 files changed, 203 insertions(+), 131 deletions(-) diff --git a/src/disassembler.c b/src/disassembler.c index 5be17e6..7f0cbca 100644 --- a/src/disassembler.c +++ b/src/disassembler.c @@ -13,6 +13,7 @@ */ static char* format_bytestring(const uint8_t *bytes, size_t size) { + // TODO: smarter alignment; pad to full len (then remove pad from TRACE()) if (!size) return NULL; diff --git a/src/logging.h b/src/logging.h index 91590b2..f788457 100644 --- a/src/logging.h +++ b/src/logging.h @@ -12,7 +12,7 @@ #define LOG_MSG_(dest, level, type, extra, after, ...) \ do { \ - if (logging_level_ >= level) { \ + if (!level || logging_level_ >= level) { \ fprintf(dest, type " " __VA_ARGS__); \ extra \ fprintf(dest, "\n"); \ diff --git a/src/z80.c b/src/z80.c index 8a4ca38..2fed89f 100644 --- a/src/z80.c +++ b/src/z80.c @@ -103,9 +103,8 @@ static inline uint16_t get_pair(Z80 *z80, uint8_t pair) case REG_DE_: return (z80->regfile.d_ << 8) + z80->regfile.e_; case REG_HL_: return (z80->regfile.h_ << 8) + z80->regfile.l_; case REG_SP: return z80->regfile.sp; - default: FATAL("invalid call: get_pair(z80, %u)", pair) } - return 0; + FATAL("invalid call: get_pair(z80, %u)", pair) } /* @@ -123,7 +122,8 @@ static inline void set_pair(Z80 *z80, uint8_t pair, uint16_t value) case REG_DE_: z80->regfile.d_ = value >> 8; z80->regfile.e_ = value; break; case REG_HL_: z80->regfile.h_ = value >> 8; z80->regfile.l_ = value; break; case REG_SP: z80->regfile.sp = value; break; - default: FATAL("invalid call: set_pair(z80, %u, 0x%04X)", pair, value) + default: + FATAL("invalid call: set_pair(z80, %u, 0x%04X)", pair, value) } } @@ -161,6 +161,37 @@ static inline void update_flags(Z80 *z80, bool c, bool n, bool pv, bool f3, } /* + Extract an 8-bit register from the given opcode and return a pointer to it. +*/ +static inline uint8_t* extract_reg(Z80 *z80, uint8_t opcode) +{ + switch (opcode & 0x38) { + case 0x00: return &z80->regfile.b; + case 0x08: return &z80->regfile.c; + case 0x10: return &z80->regfile.d; + case 0x18: return &z80->regfile.e; + case 0x20: return &z80->regfile.h; + case 0x28: return &z80->regfile.l; + case 0x38: return &z80->regfile.a; + } + FATAL("invalid call: extract_reg(z80, 0x%02X)", opcode) +} + +/* + Extract a register pair from the given opcode and return its identifer. +*/ +static inline uint8_t extract_pair(uint8_t opcode) +{ + switch (opcode & 0x30) { + case 0x00: return REG_BC; + case 0x10: return REG_DE; + case 0x20: return REG_HL; + case 0x30: return REG_SP; + } + FATAL("invalid call: extract_pair(0x%02X)", opcode) +} + +/* Return the CPU's current interrupt mode. */ static inline uint8_t get_interrupt_mode(const Z80 *z80) diff --git a/src/z80_ops.inc.c b/src/z80_ops.inc.c index 37757c7..7d09207 100644 --- a/src/z80_ops.inc.c +++ b/src/z80_ops.inc.c @@ -21,90 +21,150 @@ static uint8_t z80_inst_unimplemented(Z80 *z80, uint8_t opcode) z80->except = true; z80->exc_code = Z80_EXC_UNIMPLEMENTED_OPCODE; z80->exc_data = opcode; - return 2; + return 4; } -// LD r, r' +/* + LD r, r' (0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x47, 0x48, 0x49, 0x4A, 0x4B, + 0x4C, 0x4D, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x57, 0x58, 0x59, + 0x5A, 0x5B, 0x5C, 0x5D, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x67, + 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6F, 0x78, 0x79, 0x7A, 0x7B, 0x7C, + 0x7D, 0x7F): + Load r' (8-bit register) into r (8-bit register). +*/ +static uint8_t z80_inst_ld_r_r(Z80 *z80, uint8_t opcode) +{ + uint8_t *dst = extract_reg(z80, opcode), + *src = extract_reg(z80, opcode << 3); + *dst = *src; + z80->regfile.pc++; + return 4; +} /* LD r, n (0x06, 0x0E, 0x16, 0x1E, 0x26, 0x2E, 0x3E): - Load the immediate value into the 8-bit register. + Load n (8-bit immediate) into r (8-bit register). */ static uint8_t z80_inst_ld_r_n(Z80 *z80, uint8_t opcode) { - uint8_t *reg; - - switch(opcode) { - case 0x3E: reg = &z80->regfile.a; break; - case 0x06: reg = &z80->regfile.b; break; - case 0x0E: reg = &z80->regfile.c; break; - case 0x16: reg = &z80->regfile.d; break; - case 0x1E: reg = &z80->regfile.e; break; - case 0x26: reg = &z80->regfile.h; break; - case 0x2E: reg = &z80->regfile.l; break; - } - + uint8_t *reg = extract_reg(z80, opcode); *reg = mmu_read_byte(z80->mmu, ++z80->regfile.pc); z80->regfile.pc++; return 7; } -// LD r, (HL) +/* + LD r, (HL) (0x46, 0x4E, 0x56, 0x5E, 0x66, 0x6E, 0x7E): + Load the contents of HL into r (8-bit register). +*/ +static uint8_t z80_inst_ld_r_hl(Z80 *z80, uint8_t opcode) +{ + uint8_t *reg = extract_reg(z80, opcode); + *reg = mmu_read_byte(z80->mmu, get_pair(z80, REG_HL)); + z80->regfile.pc++; + return 7; +} -// LD r, (IX+d) +/* + LD r, (IX+d) +*/ +// static uint8_t z80_inst_ld_r_ix(Z80 *z80, uint8_t opcode) -// LD r, (IY+d) +/* + LD r, (IY+d) +*/ +// static uint8_t z80_inst_ld_r_iy(Z80 *z80, uint8_t opcode) -// LD (HL), r +/* + LD (HL), r +*/ +// static uint8_t z80_inst_ld_hl_r(Z80 *z80, uint8_t opcode) -// LD (IX+d), r +/* + LD (IX+d), r +*/ +// static uint8_t z80_inst_ld_ix_r(Z80 *z80, uint8_t opcode) -// LD (IY+d), r +/* + LD (IY+d), r +*/ +// static uint8_t z80_inst_ld_iy_r(Z80 *z80, uint8_t opcode) -// LD (HL), n +/* + LD (HL), n +*/ +// static uint8_t z80_inst_ld_hl_n(Z80 *z80, uint8_t opcode) -// LD (IX+d), n +/* + LD (IX+d), n +*/ +// static uint8_t z80_inst_ld_ix_n(Z80 *z80, uint8_t opcode) -// LD (IY+d), n +/* + LD (IY+d), n +*/ +// static uint8_t z80_inst_ld_iy_n(Z80 *z80, uint8_t opcode) -// LD A, (BC) +/* + LD A, (BC) +*/ +// static uint8_t z80_inst_ld_a_bc(Z80 *z80, uint8_t opcode) -// LD A, (DE) +/* + LD A, (DE) +*/ +// static uint8_t z80_inst_ld_a_de(Z80 *z80, uint8_t opcode) -// LD A, (nn) +/* + LD A, (nn) +*/ +// static uint8_t z80_inst_ld_a_nn(Z80 *z80, uint8_t opcode) -// LD (BC), A +/* + LD (BC), A +*/ +// static uint8_t z80_inst_ld_bc_a(Z80 *z80, uint8_t opcode) -// LD (DE), A +/* + LD (DE), A +*/ +// static uint8_t z80_inst_ld_de_a(Z80 *z80, uint8_t opcode) -// LD (nn), A +/* + LD (nn), A +*/ +// static uint8_t z80_inst_ld_nn_a(Z80 *z80, uint8_t opcode) -// LD A, I +/* + LD A, I +*/ +// static uint8_t z80_inst_ld_a_i(Z80 *z80, uint8_t opcode) -// LD A, R +/* + LD A, R +*/ +// static uint8_t z80_inst_ld_a_r(Z80 *z80, uint8_t opcode) -// LD I,A +/* + LD I,A +*/ +// static uint8_t z80_inst_ld_i_a(Z80 *z80, uint8_t opcode) -// LD R, A +/* + LD R, A +*/ +// static uint8_t z80_inst_ld_r_a(Z80 *z80, uint8_t opcode) /* LD dd, nn (0x01, 0x11, 0x21, 0x31): - Load the two-byte immediate into the 16-bit register. + Load nn (16-bit immediate) into dd (16-bit register). */ static uint8_t z80_inst_ld_dd_nn(Z80 *z80, uint8_t opcode) { - uint8_t pair; - - switch(opcode) { - case 0x01: pair = REG_BC; break; - case 0x11: pair = REG_DE; break; - case 0x21: pair = REG_HL; break; - case 0x31: pair = REG_SP; break; - } - + uint8_t pair = extract_pair(opcode); set_pair(z80, pair, mmu_read_double(z80->mmu, ++z80->regfile.pc)); z80->regfile.pc += 2; - return 6; + return 10; } // LD IX, nn @@ -151,7 +211,7 @@ static uint8_t z80_inst_ld_dd_nn(Z80 *z80, uint8_t opcode) /* EXX (0xD9): - Exchange the 2-byte registers with their shadows + Exchange the 16-bit registers with their shadows (BC <=> BC', DE <=> DE', HL <=> HL'). */ static uint8_t z80_inst_exx(Z80 *z80, uint8_t opcode) @@ -220,22 +280,11 @@ static uint8_t z80_inst_exx(Z80 *z80, uint8_t opcode) /* INC r (0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, 0x3C): - Increment the 8-bit register encoded in the opcode. + Increment r (8-bit register). */ static uint8_t z80_inst_inc_r(Z80 *z80, uint8_t opcode) { - uint8_t *reg; - - switch(opcode) { - case 0x3C: reg = &z80->regfile.a; break; - case 0x04: reg = &z80->regfile.b; break; - case 0x0C: reg = &z80->regfile.c; break; - case 0x14: reg = &z80->regfile.d; break; - case 0x1C: reg = &z80->regfile.e; break; - case 0x24: reg = &z80->regfile.h; break; - case 0x2C: reg = &z80->regfile.l; break; - } - + uint8_t *reg = extract_reg(z80, opcode); bool halfcarry = !!(((*reg & 0x0F) + 1) & 0x10); (*reg)++; update_flags(z80, 0, 0, *reg == 0x80, !!(*reg & 0x08), halfcarry, @@ -276,8 +325,7 @@ static uint8_t z80_inst_nop(Z80 *z80, uint8_t opcode) /* HALT (0x76): - Suspend CPU operation by repeatedly executing NOPs until an interrupt or - reset. + Suspend CPU operation: execute NOPs until an interrupt or reset. */ static uint8_t z80_inst_halt(Z80 *z80, uint8_t opcode) { @@ -330,19 +378,11 @@ static uint8_t z80_inst_ei(Z80 *z80, uint8_t opcode) /* INC ss (0x03, 0x13, 0x23, 0x33): - Increment the 16-bit register encoded in the opcode. + Increment ss (16-bit register). */ static uint8_t z80_inst_inc_ss(Z80 *z80, uint8_t opcode) { - uint8_t pair; - - switch(opcode) { - case 0x03: pair = REG_BC; break; - case 0x13: pair = REG_DE; break; - case 0x23: pair = REG_HL; break; - case 0x33: pair = REG_SP; break; - } - + uint8_t pair = extract_pair(opcode); set_pair(z80, pair, get_pair(z80, pair) + 1); z80->regfile.pc++; return 6; @@ -533,54 +573,54 @@ static uint8_t (*instruction_lookup_table[256])(Z80*, uint8_t) = { [0x3D] = z80_inst_unimplemented, // TODO [0x3E] = z80_inst_ld_r_n, [0x3F] = z80_inst_unimplemented, // TODO - [0x40] = z80_inst_unimplemented, // TODO - [0x41] = z80_inst_unimplemented, // TODO - [0x42] = z80_inst_unimplemented, // TODO - [0x43] = z80_inst_unimplemented, // TODO - [0x44] = z80_inst_unimplemented, // TODO - [0x45] = z80_inst_unimplemented, // TODO - [0x46] = z80_inst_unimplemented, // TODO - [0x47] = z80_inst_unimplemented, // TODO - [0x48] = z80_inst_unimplemented, // TODO - [0x49] = z80_inst_unimplemented, // TODO - [0x4A] = z80_inst_unimplemented, // TODO - [0x4B] = z80_inst_unimplemented, // TODO - [0x4C] = z80_inst_unimplemented, // TODO - [0x4D] = z80_inst_unimplemented, // TODO - [0x4E] = z80_inst_unimplemented, // TODO - [0x4F] = z80_inst_unimplemented, // TODO - [0x50] = z80_inst_unimplemented, // TODO - [0x51] = z80_inst_unimplemented, // TODO - [0x52] = z80_inst_unimplemented, // TODO - [0x53] = z80_inst_unimplemented, // TODO - [0x54] = z80_inst_unimplemented, // TODO - [0x55] = z80_inst_unimplemented, // TODO - [0x56] = z80_inst_unimplemented, // TODO - [0x57] = z80_inst_unimplemented, // TODO - [0x58] = z80_inst_unimplemented, // TODO - [0x59] = z80_inst_unimplemented, // TODO - [0x5A] = z80_inst_unimplemented, // TODO - [0x5B] = z80_inst_unimplemented, // TODO - [0x5C] = z80_inst_unimplemented, // TODO - [0x5D] = z80_inst_unimplemented, // TODO - [0x5E] = z80_inst_unimplemented, // TODO - [0x5F] = z80_inst_unimplemented, // TODO - [0x60] = z80_inst_unimplemented, // TODO - [0x61] = z80_inst_unimplemented, // TODO - [0x62] = z80_inst_unimplemented, // TODO - [0x63] = z80_inst_unimplemented, // TODO - [0x64] = z80_inst_unimplemented, // TODO - [0x65] = z80_inst_unimplemented, // TODO - [0x66] = z80_inst_unimplemented, // TODO - [0x67] = z80_inst_unimplemented, // TODO - [0x68] = z80_inst_unimplemented, // TODO - [0x69] = z80_inst_unimplemented, // TODO - [0x6A] = z80_inst_unimplemented, // TODO - [0x6B] = z80_inst_unimplemented, // TODO - [0x6C] = z80_inst_unimplemented, // TODO - [0x6D] = z80_inst_unimplemented, // TODO - [0x6E] = z80_inst_unimplemented, // TODO - [0x6F] = z80_inst_unimplemented, // TODO + [0x40] = z80_inst_ld_r_r, + [0x41] = z80_inst_ld_r_r, + [0x42] = z80_inst_ld_r_r, + [0x43] = z80_inst_ld_r_r, + [0x44] = z80_inst_ld_r_r, + [0x45] = z80_inst_ld_r_r, + [0x46] = z80_inst_ld_r_hl, + [0x47] = z80_inst_ld_r_r, + [0x48] = z80_inst_ld_r_r, + [0x49] = z80_inst_ld_r_r, + [0x4A] = z80_inst_ld_r_r, + [0x4B] = z80_inst_ld_r_r, + [0x4C] = z80_inst_ld_r_r, + [0x4D] = z80_inst_ld_r_r, + [0x4E] = z80_inst_ld_r_hl, + [0x4F] = z80_inst_ld_r_r, + [0x50] = z80_inst_ld_r_r, + [0x51] = z80_inst_ld_r_r, + [0x52] = z80_inst_ld_r_r, + [0x53] = z80_inst_ld_r_r, + [0x54] = z80_inst_ld_r_r, + [0x55] = z80_inst_ld_r_r, + [0x56] = z80_inst_ld_r_hl, + [0x57] = z80_inst_ld_r_r, + [0x58] = z80_inst_ld_r_r, + [0x59] = z80_inst_ld_r_r, + [0x5A] = z80_inst_ld_r_r, + [0x5B] = z80_inst_ld_r_r, + [0x5C] = z80_inst_ld_r_r, + [0x5D] = z80_inst_ld_r_r, + [0x5E] = z80_inst_ld_r_hl, + [0x5F] = z80_inst_ld_r_r, + [0x60] = z80_inst_ld_r_r, + [0x61] = z80_inst_ld_r_r, + [0x62] = z80_inst_ld_r_r, + [0x63] = z80_inst_ld_r_r, + [0x64] = z80_inst_ld_r_r, + [0x65] = z80_inst_ld_r_r, + [0x66] = z80_inst_ld_r_hl, + [0x67] = z80_inst_ld_r_r, + [0x68] = z80_inst_ld_r_r, + [0x69] = z80_inst_ld_r_r, + [0x6A] = z80_inst_ld_r_r, + [0x6B] = z80_inst_ld_r_r, + [0x6C] = z80_inst_ld_r_r, + [0x6D] = z80_inst_ld_r_r, + [0x6E] = z80_inst_ld_r_hl, + [0x6F] = z80_inst_ld_r_r, [0x70] = z80_inst_unimplemented, // TODO [0x71] = z80_inst_unimplemented, // TODO [0x72] = z80_inst_unimplemented, // TODO @@ -589,14 +629,14 @@ static uint8_t (*instruction_lookup_table[256])(Z80*, uint8_t) = { [0x75] = z80_inst_unimplemented, // TODO [0x76] = z80_inst_halt, [0x77] = z80_inst_unimplemented, // TODO - [0x78] = z80_inst_unimplemented, // TODO - [0x79] = z80_inst_unimplemented, // TODO - [0x7A] = z80_inst_unimplemented, // TODO - [0x7B] = z80_inst_unimplemented, // TODO - [0x7C] = z80_inst_unimplemented, // TODO - [0x7D] = z80_inst_unimplemented, // TODO - [0x7E] = z80_inst_unimplemented, // TODO - [0x7F] = z80_inst_unimplemented, // TODO + [0x78] = z80_inst_ld_r_r, + [0x79] = z80_inst_ld_r_r, + [0x7A] = z80_inst_ld_r_r, + [0x7B] = z80_inst_ld_r_r, + [0x7C] = z80_inst_ld_r_r, + [0x7D] = z80_inst_ld_r_r, + [0x7E] = z80_inst_ld_r_hl, + [0x7F] = z80_inst_ld_r_r, [0x80] = z80_inst_unimplemented, // TODO [0x81] = z80_inst_unimplemented, // TODO [0x82] = z80_inst_unimplemented, // TODO