From 80e361c1110b7e808ce1ee75e4509d552803a465 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Wed, 27 Apr 2016 00:02:52 -0500 Subject: [PATCH] More instructions, mainly index-related; tweaks. --- src/disassembler/arguments.c | 8 ++- src/z80.c | 10 ++- src/z80.h | 1 + src/z80_ops.inc.c | 152 ++++++++++++++++++++++++++++++++++++++----- src/z80_tables.inc.c | 38 +++++------ 5 files changed, 165 insertions(+), 44 deletions(-) diff --git a/src/disassembler/arguments.c b/src/disassembler/arguments.c index f065d1c..213a698 100644 --- a/src/disassembler/arguments.c +++ b/src/disassembler/arguments.c @@ -370,8 +370,12 @@ static void decode_immediate( sprintf(arg, "($%04X)", bytes[shift + 1] + (bytes[shift + 2] << 8)); break; case AT_IX_IY: // Indexed offset - format = bytes[0] == 0xDD ? "(ix%+hhd)" : "(iy%+hhd)"; - sprintf(arg, format, (int8_t) bytes[shift + 1]); + if (bytes[shift + 1]) { + format = bytes[0] == 0xDD ? "(ix%+hhd)" : "(iy%+hhd)"; + sprintf(arg, format, (int8_t) bytes[shift + 1]); + } else { + sprintf(arg, bytes[0] == 0xDD ? "(ix)" : "(iy)"); + } break; case AT_PORT_IM: // Immediate port sprintf(arg, "($%02X)", bytes[shift + 1]); diff --git a/src/z80.c b/src/z80.c index a278e77..22a3506 100644 --- a/src/z80.c +++ b/src/z80.c @@ -72,6 +72,7 @@ void z80_power(Z80 *z80) regfile->iff1 = regfile->iff2 = 0; z80->except = false; + z80->last_index = NULL; z80->pending_cycles = 0; z80->trace.fresh = true; @@ -251,14 +252,11 @@ static inline bool extract_cond(const Z80 *z80, uint8_t opcode) } /* - Extract the current index register. + Return the address signified by a indirect index instruction. */ -static inline uint16_t* extract_index(Z80 *z80) +static inline uint16_t get_index_addr(Z80 *z80, int8_t offset) { - uint8_t prefix = mmu_read_byte(z80->mmu, z80->regfile.pc - 1); - if (prefix != 0xDD && prefix != 0xFD) - FATAL("invalid call: extract_index(z80, 0x%02X)", prefix) - return prefix == 0xDD ? &z80->regfile.ix : &z80->regfile.iy; + return *z80->last_index + offset; } /* diff --git a/src/z80.h b/src/z80.h index f3c50e7..044e19f 100644 --- a/src/z80.h +++ b/src/z80.h @@ -36,6 +36,7 @@ typedef struct { IO *io; bool except; uint8_t exc_code, exc_data; + uint16_t *last_index; double pending_cycles; Z80TraceInfo trace; } Z80; diff --git a/src/z80_ops.inc.c b/src/z80_ops.inc.c index e5e24c6..288e56f 100644 --- a/src/z80_ops.inc.c +++ b/src/z80_ops.inc.c @@ -74,9 +74,18 @@ static uint8_t z80_inst_ld_r_hl(Z80 *z80, uint8_t opcode) } /* - LD r, (IXY+d) + LD r, (IXY+d) (0xDD46, 0xDD4E, 0xDD56, 0xDD5E, 0xDD66, 0xDD6E, 0xDD7E, + 0xFD46, 0xFD4E, 0xFD56, 0xFD5E, 0xFD66, 0xFD6E, 0xFD7E): + Load (IX+d) or (IY+d) into r (8-bit register). */ -// static uint8_t z80_inst_ld_r_ixy(Z80 *z80, uint8_t opcode) +static uint8_t z80_inst_ld_r_ixy(Z80 *z80, uint8_t opcode) +{ + uint8_t *reg = extract_reg(z80, opcode); + uint16_t addr = get_index_addr(z80, ++z80->regfile.pc); + *reg = mmu_read_byte(z80->mmu, addr); + z80->regfile.pc++; + return 19; +} /* LD (HL), r (0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x77): @@ -92,9 +101,18 @@ static uint8_t z80_inst_ld_hl_r(Z80 *z80, uint8_t opcode) } /* - LD (IXY+d), r + LD (IXY+d), r (0xDD70, 0xDD71, 0xDD72, 0xDD73, 0xDD74, 0xDD75, 0xDD77, + 0xFD70, 0xFD71, 0xFD72, 0xFD73, 0xFD74, 0xFD75, 0xFD77): + Load r (8-bit register) into (IX+d) or (IY+d). */ -// static uint8_t z80_inst_ld_ixy_r(Z80 *z80, uint8_t opcode) +static uint8_t z80_inst_ld_ixy_r(Z80 *z80, uint8_t opcode) +{ + uint8_t *reg = extract_reg(z80, opcode << 3); + uint16_t addr = get_index_addr(z80, ++z80->regfile.pc); + mmu_write_byte(z80->mmu, addr, *reg); + z80->regfile.pc++; + return 19; +} /* LD (HL), n (0x36): @@ -111,9 +129,18 @@ static uint8_t z80_inst_ld_hl_n(Z80 *z80, uint8_t opcode) } /* - LD (IXY+d), n + LD (IXY+d), n (0xDD36, 0xFD36): + Load n (8-bit immediate) into (IX+d) or (IY+d). */ -// static uint8_t z80_inst_ld_ixy_n(Z80 *z80, uint8_t opcode) +static uint8_t z80_inst_ld_ixy_n(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + uint16_t addr = get_index_addr(z80, ++z80->regfile.pc); + uint8_t byte = mmu_read_byte(z80->mmu, ++z80->regfile.pc); + mmu_write_byte(z80->mmu, addr, byte); + z80->regfile.pc++; + return 19; +} /* LD A, (BC/DE) @@ -169,7 +196,7 @@ static uint8_t z80_inst_ld_nn_a(Z80 *z80, uint8_t opcode) // 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) @@ -190,7 +217,17 @@ static uint8_t z80_inst_ld_dd_nn(Z80 *z80, uint8_t opcode) return 10; } -// LD IXY, nn +/* + LD IXY, nn (0xDD21, 0xFD21): + Load nn (16-bit immediate) into IX or IY. +*/ +static uint8_t z80_inst_ld_ixy_nn(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + *z80->last_index = mmu_read_double(z80->mmu, ++z80->regfile.pc); + z80->regfile.pc += 2; + return 14; +} /* LD HL, (nn) (0x2A): @@ -221,6 +258,7 @@ static uint8_t z80_inst_ld_dd_inn(Z80 *z80, uint8_t opcode) } // LD IXY, (nn) +// static uint8_t z80_inst_ld_ixy_inn(Z80 *z80, uint8_t opcode) /* LD (nn), HL: (0x22): @@ -262,7 +300,7 @@ static uint8_t z80_inst_push_qq(Z80 *z80, uint8_t opcode) static uint8_t z80_inst_push_ixy(Z80 *z80, uint8_t opcode) { (void) opcode; - stack_push(z80, *extract_index(z80)); + stack_push(z80, *z80->last_index); z80->regfile.pc++; return 15; } @@ -286,7 +324,7 @@ static uint8_t z80_inst_pop_qq(Z80 *z80, uint8_t opcode) static uint8_t z80_inst_pop_ixy(Z80 *z80, uint8_t opcode) { (void) opcode; - *extract_index(z80) = stack_pop(z80); + *z80->last_index = stack_pop(z80); z80->regfile.pc++; return 14; } @@ -444,9 +482,15 @@ static uint8_t z80_inst_lddr(Z80 *z80, uint8_t opcode) // ADD A, (IXY+d) -// ADC A, s +// ADC A, r -// SUB s +// ADC A, n + +// ADC A, (HL) + +// ADC A, (IXY+d) + +// SUB r /* SUB n (0xD6): @@ -469,9 +513,19 @@ static uint8_t z80_inst_sub_n(Z80 *z80, uint8_t opcode) return 7; } -// SBC A, s +// SUB (HL) + +// SUB (IXY+d) + +// SBC A, r -// AND s +// SBC A, n + +// SBC A, (HL) + +// SBC A, (IXY+d) + +// AND r /* AND n (0xE6): @@ -491,7 +545,9 @@ static uint8_t z80_inst_and_n(Z80 *z80, uint8_t opcode) return 7; } -// OR s +// AND (HL) + +// AND (IXY+d) /* OR r (0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB7): @@ -528,7 +584,26 @@ static uint8_t z80_inst_or_n(Z80 *z80, uint8_t opcode) return 7; } -// XOR s +// OR (HL) + +/* + OR (IXY+d) (0xDDB6, 0xFDB6): + Bitwise OR A with (IX+d) or (IY+d). +*/ +static uint8_t z80_inst_or_ixy(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + uint8_t addr = get_index_addr(z80, ++z80->regfile.pc); + uint8_t val = mmu_read_byte(z80->mmu, addr); + uint8_t a = (z80->regfile.a |= val); + + bool parity = !(__builtin_popcount(a) % 2); + update_flags(z80, 0, 0, parity, !!(a & 0x08), 0, !!(a & 0x20), a == 0, + !!(a & 0x80), 0xFF); + + z80->regfile.pc++; + return 7; +} /* XOR r (0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAF): @@ -547,7 +622,27 @@ static uint8_t z80_inst_xor_r(Z80 *z80, uint8_t opcode) return 4; } -// CP s +/* + XOR n (0xEE): + Bitwise XOR A with n (8-bit immediate). +*/ +static uint8_t z80_inst_xor_n(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + uint8_t imm = mmu_read_byte(z80->mmu, ++z80->regfile.pc); + uint8_t a = (z80->regfile.a ^= imm); + + bool parity = !(__builtin_popcount(a) % 2); + update_flags(z80, 0, 0, parity, !!(a & 0x08), 0, !!(a & 0x20), a == 0, + !!(a & 0x80), 0xFF); + + z80->regfile.pc++; + return 7; +} + +// XOR (HL) + +// XOR (IXY+d) /* CP r (0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBF): @@ -589,6 +684,28 @@ static uint8_t z80_inst_cp_n(Z80 *z80, uint8_t opcode) } /* + CP (HL) (0xBE): + Set flags as if the memory pointed to by HL had been subtracted from A. +*/ +static uint8_t z80_inst_cp_hl(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + uint8_t n = mmu_read_byte(z80->mmu, get_pair(z80, REG_HL)); + uint8_t d = z80->regfile.a - n; + + bool c = (z80->regfile.a - n) != d; + bool v = (z80->regfile.a - n) != ((int8_t) d); + bool h = !!(((z80->regfile.a & 0x0F) - (n & 0x0F)) & 0x10); + update_flags(z80, c, 1, v, !!(n & 0x08), h, !!(n & 0x20), d == 0, + !!(d & 0x80), 0xFF); + + z80->regfile.pc++; + return 7; +} + +// CP (IXY+d) + +/* INC r (0x04, 0x0C, 0x14, 0x1C, 0x24, 0x2C, 0x3C): Increment r (8-bit register). */ @@ -1280,6 +1397,7 @@ static uint8_t z80_prefix_bits(Z80 *z80, uint8_t opcode) */ static uint8_t z80_prefix_index(Z80 *z80, uint8_t opcode) { + z80->last_index = (opcode == 0xDD) ? &z80->regfile.ix : &z80->regfile.iy; opcode = mmu_read_byte(z80->mmu, ++z80->regfile.pc); return (*instruction_table_index[opcode])(z80, opcode); } diff --git a/src/z80_tables.inc.c b/src/z80_tables.inc.c index 737b322..9bc7515 100644 --- a/src/z80_tables.inc.c +++ b/src/z80_tables.inc.c @@ -192,7 +192,7 @@ static DispatchTable instruction_table = { [0xBB] = z80_inst_cp_r, [0xBC] = z80_inst_cp_r, [0xBD] = z80_inst_cp_r, - [0xBE] = z80_inst_unimplemented, // TODO + [0xBE] = z80_inst_cp_hl, [0xBF] = z80_inst_cp_r, [0xC0] = z80_inst_ret_cc, [0xC1] = z80_inst_pop_qq, @@ -240,7 +240,7 @@ static DispatchTable instruction_table = { [0xEB] = z80_inst_ex_de_hl, [0xEC] = z80_inst_call_cc_nn, [0xED] = z80_prefix_extended, - [0xEE] = z80_inst_unimplemented, // TODO + [0xEE] = z80_inst_xor_n, [0xEF] = z80_inst_rst_p, [0xF0] = z80_inst_ret_cc, [0xF1] = z80_inst_pop_qq, @@ -812,7 +812,7 @@ static DispatchTable instruction_table_index = { [0x1E] = z80_inst_nop2, [0x1F] = z80_inst_nop2, [0x20] = z80_inst_nop2, - [0x21] = z80_inst_unimplemented, // TODO + [0x21] = z80_inst_ld_ixy_nn, [0x22] = z80_inst_unimplemented, // TODO [0x23] = z80_inst_unimplemented, // TODO [0x24] = z80_inst_unimplemented, // TODO @@ -833,7 +833,7 @@ static DispatchTable instruction_table_index = { [0x33] = z80_inst_nop2, [0x34] = z80_inst_unimplemented, // TODO [0x35] = z80_inst_unimplemented, // TODO - [0x36] = z80_inst_unimplemented, // TODO + [0x36] = z80_inst_ld_ixy_n, [0x37] = z80_inst_nop2, [0x38] = z80_inst_nop2, [0x39] = z80_inst_unimplemented, // TODO @@ -849,7 +849,7 @@ static DispatchTable instruction_table_index = { [0x43] = z80_inst_nop2, [0x44] = z80_inst_unimplemented, // TODO [0x45] = z80_inst_unimplemented, // TODO - [0x46] = z80_inst_unimplemented, // TODO + [0x46] = z80_inst_ld_r_ixy, [0x47] = z80_inst_nop2, [0x48] = z80_inst_nop2, [0x49] = z80_inst_nop2, @@ -857,7 +857,7 @@ static DispatchTable instruction_table_index = { [0x4B] = z80_inst_nop2, [0x4C] = z80_inst_unimplemented, // TODO [0x4D] = z80_inst_unimplemented, // TODO - [0x4E] = z80_inst_unimplemented, // TODO + [0x4E] = z80_inst_ld_r_ixy, [0x4F] = z80_inst_nop2, [0x50] = z80_inst_nop2, [0x51] = z80_inst_nop2, @@ -865,7 +865,7 @@ static DispatchTable instruction_table_index = { [0x53] = z80_inst_nop2, [0x54] = z80_inst_unimplemented, // TODO [0x55] = z80_inst_unimplemented, // TODO - [0x56] = z80_inst_unimplemented, // TODO + [0x56] = z80_inst_ld_r_ixy, [0x57] = z80_inst_nop2, [0x58] = z80_inst_nop2, [0x59] = z80_inst_nop2, @@ -873,7 +873,7 @@ static DispatchTable instruction_table_index = { [0x5B] = z80_inst_nop2, [0x5C] = z80_inst_unimplemented, // TODO [0x5D] = z80_inst_unimplemented, // TODO - [0x5E] = z80_inst_unimplemented, // TODO + [0x5E] = z80_inst_ld_r_ixy, [0x5F] = z80_inst_nop2, [0x60] = z80_inst_unimplemented, // TODO [0x61] = z80_inst_unimplemented, // TODO @@ -881,7 +881,7 @@ static DispatchTable instruction_table_index = { [0x63] = z80_inst_unimplemented, // TODO [0x64] = z80_inst_unimplemented, // TODO [0x65] = z80_inst_unimplemented, // TODO - [0x66] = z80_inst_unimplemented, // TODO + [0x66] = z80_inst_ld_r_ixy, [0x67] = z80_inst_unimplemented, // TODO [0x68] = z80_inst_unimplemented, // TODO [0x69] = z80_inst_unimplemented, // TODO @@ -889,23 +889,23 @@ static DispatchTable instruction_table_index = { [0x6B] = z80_inst_unimplemented, // TODO [0x6C] = z80_inst_unimplemented, // TODO [0x6D] = z80_inst_unimplemented, // TODO - [0x6E] = z80_inst_unimplemented, // TODO + [0x6E] = z80_inst_ld_r_ixy, [0x6F] = z80_inst_unimplemented, // TODO - [0x70] = z80_inst_unimplemented, // TODO - [0x71] = z80_inst_unimplemented, // TODO - [0x72] = z80_inst_unimplemented, // TODO - [0x73] = z80_inst_unimplemented, // TODO - [0x74] = z80_inst_unimplemented, // TODO - [0x75] = z80_inst_unimplemented, // TODO + [0x70] = z80_inst_ld_ixy_r, + [0x71] = z80_inst_ld_ixy_r, + [0x72] = z80_inst_ld_ixy_r, + [0x73] = z80_inst_ld_ixy_r, + [0x74] = z80_inst_ld_ixy_r, + [0x75] = z80_inst_ld_ixy_r, [0x76] = z80_inst_nop2, - [0x77] = z80_inst_unimplemented, // TODO + [0x77] = z80_inst_ld_ixy_r, [0x78] = z80_inst_nop2, [0x79] = z80_inst_nop2, [0x7A] = z80_inst_nop2, [0x7B] = z80_inst_nop2, [0x7C] = z80_inst_unimplemented, // TODO [0x7D] = z80_inst_unimplemented, // TODO - [0x7E] = z80_inst_unimplemented, // TODO + [0x7E] = z80_inst_ld_r_ixy, [0x7F] = z80_inst_nop2, [0x80] = z80_inst_nop2, [0x81] = z80_inst_nop2, @@ -961,7 +961,7 @@ static DispatchTable instruction_table_index = { [0xB3] = z80_inst_nop2, [0xB4] = z80_inst_unimplemented, // TODO [0xB5] = z80_inst_unimplemented, // TODO - [0xB6] = z80_inst_unimplemented, // TODO + [0xB6] = z80_inst_or_ixy, [0xB7] = z80_inst_nop2, [0xB8] = z80_inst_nop2, [0xB9] = z80_inst_nop2,