From 53c075736286cf4523285e349d90469f4e5f8683 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Tue, 26 Apr 2016 03:21:16 -0500 Subject: [PATCH] Implement an assorted bunch of instructions. --- src/z80_ops.inc.c | 143 ++++++++++++++++++++++++++++++++-- src/z80_tables.inc.c | 212 +++++++++++++++++++++++++-------------------------- 2 files changed, 241 insertions(+), 114 deletions(-) diff --git a/src/z80_ops.inc.c b/src/z80_ops.inc.c index 40dae20..ab50992 100644 --- a/src/z80_ops.inc.c +++ b/src/z80_ops.inc.c @@ -192,9 +192,33 @@ static uint8_t z80_inst_ld_dd_nn(Z80 *z80, uint8_t opcode) // LD IXY, nn -// LD HL, (nn) +/* + LD HL, (nn) (0x2A): + Load memory at address nn into HL. +*/ +static uint8_t z80_inst_ld_hl_nn(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + uint16_t addr = mmu_read_double(z80->mmu, ++z80->regfile.pc); + uint16_t value = mmu_read_double(z80->mmu, addr); + set_pair(z80, REG_HL, value); + z80->regfile.pc += 2; + return 16; +} -// LD dd, (nn) +/* + LD dd, (nn) (0xED4B, 0xED5B, 0xED6B, 0xED7B): + Load memory at address nn into dd (16-bit register). +*/ +static uint8_t z80_inst_ld_dd_inn(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + uint16_t addr = mmu_read_double(z80->mmu, ++z80->regfile.pc); + uint16_t value = mmu_read_double(z80->mmu, addr); + set_pair(z80, extract_pair(opcode), value); + z80->regfile.pc += 2; + return 20; +} // LD IXY, (nn) @@ -281,7 +305,19 @@ static uint8_t z80_inst_ex_de_hl(Z80 *z80, uint8_t opcode) return 4; } -// EX AF, AF′ +/* + EX AF, AF' (0x08): + Exchange AF with AF'. +*/ +static uint8_t z80_inst_ex_af_af(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + uint16_t af = get_pair(z80, REG_AF); + set_pair(z80, REG_AF, get_pair(z80, REG_AF_)); + set_pair(z80, REG_AF_, af); + z80->regfile.pc++; + return 4; +} /* EXX (0xD9): @@ -306,7 +342,19 @@ static uint8_t z80_inst_exx(Z80 *z80, uint8_t opcode) return 4; } -// EX (SP), HL +/* + EX (SP), HL (0xE3): + Exchange the memory pointed to by SP with HL. +*/ +static uint8_t z80_inst_ex_sp_hl(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + uint16_t hl = get_pair(z80, REG_HL), sp = get_pair(z80, REG_SP); + set_pair(z80, REG_HL, mmu_read_double(z80->mmu, sp)); + mmu_write_double(z80->mmu, sp, hl); + z80->regfile.pc++; + return 19; +} // EX (SP), IXY @@ -425,6 +473,24 @@ static uint8_t z80_inst_sub_n(Z80 *z80, uint8_t opcode) // AND s +/* + AND n (0xE6): + Bitwise AND A with n (8-bit immediate). +*/ +static uint8_t z80_inst_and_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), 1, !!(a & 0x20), a == 0, + !!(a & 0x80), 0xFF); + + z80->regfile.pc++; + return 7; +} + // OR s /* @@ -538,7 +604,22 @@ static uint8_t z80_inst_inc_r(Z80 *z80, uint8_t opcode) return 4; } -// INC (HL) +/* + INC (HL) (0x34): + Increment the memory address pointed to by HL. +*/ +static uint8_t z80_inst_inc_hl(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + uint8_t byte = mmu_read_byte(z80->mmu, get_pair(z80, REG_HL)); + bool halfcarry = !!(((byte & 0x0F) + 1) & 0x10); + mmu_write_byte(z80->mmu, get_pair(z80, REG_HL), ++byte); + update_flags(z80, 0, 0, byte == 0x80, !!(byte & 0x08), halfcarry, + !!(byte & 0x20), byte == 0, !!(byte & 0x80), 0xFE); + + z80->regfile.pc++; + return 11; +} // INC (IXY+d) @@ -754,9 +835,46 @@ static uint8_t z80_inst_dec_ss(Z80 *z80, uint8_t opcode) // RRD -// BIT b, r +/* + BIT b, r (0xCB40, 0xCB41, 0xCB42, 0xCB43, 0xCB44, 0xCB45, 0xCB47, 0xCB48, + 0xCB49, 0xCB4A, 0xCB4B, 0xCB4C, 0xCB4D, 0xCB4F, 0xCB50, 0xCB51, 0xCB52, + 0xCB53, 0xCB54, 0xCB55, 0xCB57, 0xCB58, 0xCB59, 0xCB5A, 0xCB5B, 0xCB5C, + 0xCB5D, 0xCB5F, 0xCB60, 0xCB61, 0xCB62, 0xCB63, 0xCB64, 0xCB65, 0xCB67, + 0xCB68, 0xCB69, 0xCB6A, 0xCB6B, 0xCB6C, 0xCB6D, 0xCB6F, 0xCB70, 0xCB71, + 0xCB72, 0xCB73, 0xCB74, 0xCB75, 0xCB77, 0xCB78, 0xCB79, 0xCB7A, 0xCB7B, + 0xCB7C, 0xCB7D, 0xCB7F): + Test bit b of r (8-bit register). +*/ +static uint8_t z80_inst_bit_b_r(Z80 *z80, uint8_t opcode) +{ + uint8_t *reg = extract_reg(z80, opcode << 3); + uint8_t bit = opcode >> 3; + bool z = (((*reg) >> bit) & 1) == 0; + if (z) + update_flags(z80, 0, 0, 1, 0, 1, 0, 1, 0, 0xFE); + else + update_flags(z80, 0, 0, 0, bit == 3, 1, bit == 5, 0, bit == 7, 0xFE); + z80->regfile.pc++; + return 8; +} -// BIT b, (HL) +/* + BIT b, (HL) (0xCB46, 0xCB4E, 0xCB56, 0xCB5E, 0xCB66, 0xCB6E, 0xCB76, + 0xCB7E): + Test bit b of (HL). +*/ +static uint8_t z80_inst_bit_b_hl(Z80 *z80, uint8_t opcode) +{ + uint8_t val = mmu_read_byte(z80->mmu, get_pair(z80, REG_HL)); + uint8_t bit = opcode >> 3; + bool z = ((val >> bit) & 1) == 0; + if (z) + update_flags(z80, 0, 0, 1, 0, 1, 0, 1, 0, 0xFE); + else + update_flags(z80, 0, 0, 0, bit == 3, 1, bit == 5, 0, bit == 7, 0xFE); + z80->regfile.pc++; + return 8; +} // BIT b, (IXY+d) @@ -898,7 +1016,16 @@ static uint8_t z80_inst_ret_cc(Z80 *z80, uint8_t opcode) } } -// RETI +/* + RETI (0xED4D): + Pop PC from the stack. +*/ +static uint8_t z80_inst_reti(Z80 *z80, uint8_t opcode) +{ + (void) opcode; + z80->regfile.pc = stack_pop(z80); + return 14; +} /* RETN (0xED45, 0xED55, 0xED5D, 0xED65, 0xED6D, 0xED75, 0xED7D): diff --git a/src/z80_tables.inc.c b/src/z80_tables.inc.c index 3354a44..737b322 100644 --- a/src/z80_tables.inc.c +++ b/src/z80_tables.inc.c @@ -10,7 +10,7 @@ static DispatchTable instruction_table = { [0x05] = z80_inst_dec_r, [0x06] = z80_inst_ld_r_n, [0x07] = z80_inst_unimplemented, // TODO - [0x08] = z80_inst_unimplemented, // TODO + [0x08] = z80_inst_ex_af_af, [0x09] = z80_inst_add_hl_ss, [0x0A] = z80_inst_unimplemented, // TODO [0x0B] = z80_inst_dec_ss, @@ -44,7 +44,7 @@ static DispatchTable instruction_table = { [0x27] = z80_inst_unimplemented, // TODO [0x28] = z80_inst_jr_cc_e, [0x29] = z80_inst_add_hl_ss, - [0x2A] = z80_inst_unimplemented, // TODO + [0x2A] = z80_inst_ld_hl_nn, [0x2B] = z80_inst_dec_ss, [0x2C] = z80_inst_inc_r, [0x2D] = z80_inst_dec_r, @@ -54,7 +54,7 @@ static DispatchTable instruction_table = { [0x31] = z80_inst_ld_dd_nn, [0x32] = z80_inst_ld_nn_a, [0x33] = z80_inst_inc_ss, - [0x34] = z80_inst_unimplemented, // TODO + [0x34] = z80_inst_inc_hl, [0x35] = z80_inst_unimplemented, // TODO [0x36] = z80_inst_ld_hl_n, [0x37] = z80_inst_unimplemented, // TODO @@ -229,10 +229,10 @@ static DispatchTable instruction_table = { [0xE0] = z80_inst_ret_cc, [0xE1] = z80_inst_pop_qq, [0xE2] = z80_inst_jp_cc_nn, - [0xE3] = z80_inst_unimplemented, // TODO + [0xE3] = z80_inst_ex_sp_hl, [0xE4] = z80_inst_call_cc_nn, [0xE5] = z80_inst_push_qq, - [0xE6] = z80_inst_unimplemented, // TODO + [0xE6] = z80_inst_and_n, [0xE7] = z80_inst_rst_p, [0xE8] = z80_inst_ret_cc, [0xE9] = z80_inst_unimplemented, // TODO @@ -336,9 +336,9 @@ static DispatchTable instruction_table_extended = { [0x48] = z80_inst_in_r_c, [0x49] = z80_inst_out_c_r, [0x4A] = z80_inst_unimplemented, // TODO - [0x4B] = z80_inst_unimplemented, // TODO + [0x4B] = z80_inst_ld_dd_inn, [0x4C] = z80_inst_unimplemented, // TODO - [0x4D] = z80_inst_unimplemented, // TODO + [0x4D] = z80_inst_reti, [0x4E] = z80_inst_im, [0x4F] = z80_inst_unimplemented, // TODO [0x50] = z80_inst_in_r_c, @@ -352,7 +352,7 @@ static DispatchTable instruction_table_extended = { [0x58] = z80_inst_in_r_c, [0x59] = z80_inst_out_c_r, [0x5A] = z80_inst_unimplemented, // TODO - [0x5B] = z80_inst_unimplemented, // TODO + [0x5B] = z80_inst_ld_dd_inn, [0x5C] = z80_inst_unimplemented, // TODO [0x5D] = z80_inst_retn, [0x5E] = z80_inst_im, @@ -368,7 +368,7 @@ static DispatchTable instruction_table_extended = { [0x68] = z80_inst_in_r_c, [0x69] = z80_inst_out_c_r, [0x6A] = z80_inst_unimplemented, // TODO - [0x6B] = z80_inst_unimplemented, // TODO + [0x6B] = z80_inst_ld_dd_inn, [0x6C] = z80_inst_unimplemented, // TODO [0x6D] = z80_inst_retn, [0x6E] = z80_inst_im, @@ -384,43 +384,43 @@ static DispatchTable instruction_table_extended = { [0x78] = z80_inst_in_r_c, [0x79] = z80_inst_out_c_r, [0x7A] = z80_inst_unimplemented, // TODO - [0x7B] = z80_inst_unimplemented, // TODO + [0x7B] = z80_inst_ld_dd_inn, [0x7C] = z80_inst_unimplemented, // TODO [0x7D] = z80_inst_retn, [0x7E] = z80_inst_im, [0x7F] = z80_inst_nop2, - [0x80] = z80_inst_unimplemented, // TODO - [0x81] = z80_inst_unimplemented, // TODO - [0x82] = z80_inst_unimplemented, // TODO - [0x83] = z80_inst_unimplemented, // TODO - [0x84] = z80_inst_unimplemented, // TODO - [0x85] = z80_inst_unimplemented, // TODO - [0x86] = z80_inst_unimplemented, // TODO - [0x87] = z80_inst_unimplemented, // TODO - [0x88] = z80_inst_unimplemented, // TODO - [0x89] = z80_inst_unimplemented, // TODO - [0x8A] = z80_inst_unimplemented, // TODO - [0x8B] = z80_inst_unimplemented, // TODO - [0x8C] = z80_inst_unimplemented, // TODO - [0x8D] = z80_inst_unimplemented, // TODO - [0x8E] = z80_inst_unimplemented, // TODO - [0x8F] = z80_inst_unimplemented, // TODO - [0x90] = z80_inst_unimplemented, // TODO - [0x91] = z80_inst_unimplemented, // TODO - [0x92] = z80_inst_unimplemented, // TODO - [0x93] = z80_inst_unimplemented, // TODO - [0x94] = z80_inst_unimplemented, // TODO - [0x95] = z80_inst_unimplemented, // TODO - [0x96] = z80_inst_unimplemented, // TODO - [0x97] = z80_inst_unimplemented, // TODO - [0x98] = z80_inst_unimplemented, // TODO - [0x99] = z80_inst_unimplemented, // TODO - [0x9A] = z80_inst_unimplemented, // TODO - [0x9B] = z80_inst_unimplemented, // TODO - [0x9C] = z80_inst_unimplemented, // TODO - [0x9D] = z80_inst_unimplemented, // TODO - [0x9E] = z80_inst_unimplemented, // TODO - [0x9F] = z80_inst_unimplemented, // TODO + [0x80] = z80_inst_nop2, + [0x81] = z80_inst_nop2, + [0x82] = z80_inst_nop2, + [0x83] = z80_inst_nop2, + [0x84] = z80_inst_nop2, + [0x85] = z80_inst_nop2, + [0x86] = z80_inst_nop2, + [0x87] = z80_inst_nop2, + [0x88] = z80_inst_nop2, + [0x89] = z80_inst_nop2, + [0x8A] = z80_inst_nop2, + [0x8B] = z80_inst_nop2, + [0x8C] = z80_inst_nop2, + [0x8D] = z80_inst_nop2, + [0x8E] = z80_inst_nop2, + [0x8F] = z80_inst_nop2, + [0x90] = z80_inst_nop2, + [0x91] = z80_inst_nop2, + [0x92] = z80_inst_nop2, + [0x93] = z80_inst_nop2, + [0x94] = z80_inst_nop2, + [0x95] = z80_inst_nop2, + [0x96] = z80_inst_nop2, + [0x97] = z80_inst_nop2, + [0x98] = z80_inst_nop2, + [0x99] = z80_inst_nop2, + [0x9A] = z80_inst_nop2, + [0x9B] = z80_inst_nop2, + [0x9C] = z80_inst_nop2, + [0x9D] = z80_inst_nop2, + [0x9E] = z80_inst_nop2, + [0x9F] = z80_inst_nop2, [0xA0] = z80_inst_ldi, [0xA1] = z80_inst_unimplemented, // TODO [0xA2] = z80_inst_ini, @@ -584,70 +584,70 @@ static DispatchTable instruction_table_bits = { [0x3D] = z80_inst_unimplemented, // TODO [0x3E] = z80_inst_unimplemented, // TODO [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 - [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 - [0x76] = z80_inst_unimplemented, // TODO - [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 + [0x40] = z80_inst_bit_b_r, + [0x41] = z80_inst_bit_b_r, + [0x42] = z80_inst_bit_b_r, + [0x43] = z80_inst_bit_b_r, + [0x44] = z80_inst_bit_b_r, + [0x45] = z80_inst_bit_b_r, + [0x46] = z80_inst_bit_b_hl, + [0x47] = z80_inst_bit_b_r, + [0x48] = z80_inst_bit_b_r, + [0x49] = z80_inst_bit_b_r, + [0x4A] = z80_inst_bit_b_r, + [0x4B] = z80_inst_bit_b_r, + [0x4C] = z80_inst_bit_b_r, + [0x4D] = z80_inst_bit_b_r, + [0x4E] = z80_inst_bit_b_hl, + [0x4F] = z80_inst_bit_b_r, + [0x50] = z80_inst_bit_b_r, + [0x51] = z80_inst_bit_b_r, + [0x52] = z80_inst_bit_b_r, + [0x53] = z80_inst_bit_b_r, + [0x54] = z80_inst_bit_b_r, + [0x55] = z80_inst_bit_b_r, + [0x56] = z80_inst_bit_b_hl, + [0x57] = z80_inst_bit_b_r, + [0x58] = z80_inst_bit_b_r, + [0x59] = z80_inst_bit_b_r, + [0x5A] = z80_inst_bit_b_r, + [0x5B] = z80_inst_bit_b_r, + [0x5C] = z80_inst_bit_b_r, + [0x5D] = z80_inst_bit_b_r, + [0x5E] = z80_inst_bit_b_hl, + [0x5F] = z80_inst_bit_b_r, + [0x60] = z80_inst_bit_b_r, + [0x61] = z80_inst_bit_b_r, + [0x62] = z80_inst_bit_b_r, + [0x63] = z80_inst_bit_b_r, + [0x64] = z80_inst_bit_b_r, + [0x65] = z80_inst_bit_b_r, + [0x66] = z80_inst_bit_b_hl, + [0x67] = z80_inst_bit_b_r, + [0x68] = z80_inst_bit_b_r, + [0x69] = z80_inst_bit_b_r, + [0x6A] = z80_inst_bit_b_r, + [0x6B] = z80_inst_bit_b_r, + [0x6C] = z80_inst_bit_b_r, + [0x6D] = z80_inst_bit_b_r, + [0x6E] = z80_inst_bit_b_hl, + [0x6F] = z80_inst_bit_b_r, + [0x70] = z80_inst_bit_b_r, + [0x71] = z80_inst_bit_b_r, + [0x72] = z80_inst_bit_b_r, + [0x73] = z80_inst_bit_b_r, + [0x74] = z80_inst_bit_b_r, + [0x75] = z80_inst_bit_b_r, + [0x76] = z80_inst_bit_b_hl, + [0x77] = z80_inst_bit_b_r, + [0x78] = z80_inst_bit_b_r, + [0x79] = z80_inst_bit_b_r, + [0x7A] = z80_inst_bit_b_r, + [0x7B] = z80_inst_bit_b_r, + [0x7C] = z80_inst_bit_b_r, + [0x7D] = z80_inst_bit_b_r, + [0x7E] = z80_inst_bit_b_hl, + [0x7F] = z80_inst_bit_b_r, [0x80] = z80_inst_unimplemented, // TODO [0x81] = z80_inst_unimplemented, // TODO [0x82] = z80_inst_unimplemented, // TODO