From 16b8021401242ed1eceb90feee21fe574c87eea4 Mon Sep 17 00:00:00 2001 From: Thomas Harte <thomas.harte@gmail.com> Date: Sat, 27 May 2017 15:39:22 -0400 Subject: [PATCH] Made a stab at the CB pages. --- Processors/Z80/Z80.hpp | 163 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 156 insertions(+), 7 deletions(-) diff --git a/Processors/Z80/Z80.hpp b/Processors/Z80/Z80.hpp index 7525cde8b..9220b2b38 100644 --- a/Processors/Z80/Z80.hpp +++ b/Processors/Z80/Z80.hpp @@ -131,6 +131,10 @@ struct MicroOp { SCF, CCF, + RES, + BIT, + SET, + CalculateRSTDestination, IndexedPlaceHolder, @@ -192,6 +196,10 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> { InstructionPage fd_page_; InstructionPage dd_page_; + InstructionPage cb_page_; + InstructionPage fdcb_page_; + InstructionPage ddcb_page_; + #define XX {MicroOp::None, 0} #define INDEX() {MicroOp::IndexedPlaceHolder}, FETCH(temp8_, pc_), WAIT(5), {MicroOp::CalculateIndexAddress, &index} @@ -346,7 +354,46 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> { #undef NOP_ROW } - void assemble_base_page(InstructionPage &target, RegisterPair &index, bool add_offsets) { + void assembled_cd_page(InstructionPage &target, RegisterPair &index, bool add_offsets) { +#define OCTO_OP_GROUP(x) OP_GROUP(x), OP_GROUP(x), OP_GROUP(x), OP_GROUP(x), OP_GROUP(x), OP_GROUP(x), OP_GROUP(x), OP_GROUP(x) + InstructionTable cb_program_table = { + /* 0x00 RLC B; 0x01 RLC C; 0x02 RLC D; 0x03 RLC E; 0x04 RLC H; 0x05 RLC L; 0x06 RLC (HL); 0x07 RLC A */ + OP_GROUP(RLC), + + /* 0x08 RRC B; 0x09 RRC C; 0x0a RRC D; 0x0b RRC E; 0x0c RRC H; 0x0d RRC L; 0x0e RRC (HL); 0x0f RRC A */ + OP_GROUP(RRC), + + /* 0x10 RL B; 0x11 RL C; 0x12 RL D; 0x13 RL E; 0x14 RL H; 0x15 RL L; 0x16 RL (HL); 0x17 RL A */ + OP_GROUP(RL), + + /* 0x18 RR B; 0x99 RR C; 0x1a RR D; 0x1b RR E; 0x1c RR H; 0x1d RR L; 0x1e RR (HL); 0x1f RR A */ + OP_GROUP(RR), + + /* 0x20 SLA B; 0x21 SLA C; 0x22 SLA D; 0x23 SLA E; 0x24 SLA H; 0x25 SLA L; 0x26 SLA (HL); 0x27 SLA A */ + OP_GROUP(SLA), + + /* 0x28 SRA B; 0x29 SRA C; 0x2a SRA D; 0x2b SRA E; 0x2c SRA H; 0x2d SRA L; 0x2e SRA (HL); 0x2f SRA A */ + OP_GROUP(SRA), + + /* 0x30 SLL B; 0x31 SLL C; 0x32 SLL D; 0x33 SLL E; 0x34 SLL H; 0x35 SLL L; 0x36 SLL (HL); 0x37 SLL A */ + OP_GROUP(SLL), + + /* 0x38 SRL B; 0x39 SRL C; 0x3a SRL D; 0x3b SRL E; 0x3c SRL H; 0x3d SRL L; 0x3e SRL (HL); 0x3f SRL A */ + OP_GROUP(SRL), + + /* 0x40 – 0x7f: BIT */ + OCTO_OP_GROUP(BIT), + + /* 0x80 – 0xcf: RES */ + OCTO_OP_GROUP(RES), + + /* 0xd0 – 0xdf: SET */ + OCTO_OP_GROUP(SET) + }; + assemble_page(target, cb_program_table, add_offsets); + } + + void assemble_base_page(InstructionPage &target, RegisterPair &index, bool add_offsets, InstructionPage &cb_page) { #define INC_DEC_LD(r) \ Program({MicroOp::Increment8, &r}), \ Program({MicroOp::Decrement8, &r}), \ @@ -480,7 +527,7 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> { /* 0xc6 ADD A, n */ Program(FETCH(temp8_, pc_), {MicroOp::ADD8, &temp8_}), /* 0xc7 RST 00h */ RST(), /* 0xc8 RET Z */ RET(TestZ), /* 0xc9 RET */ Program(POP(pc_)), - /* 0xca JP Z */ JP(TestZ), /* 0xcb [CB page] */XX, + /* 0xca JP Z */ JP(TestZ), /* 0xcb [CB page] */Program({MicroOp::SetInstructionPage, &cb_page}), /* 0xcc CALL Z */ CALL(TestZ), /* 0xcd CALL */ Program(FETCH16(temp16_, pc_), WAIT(1), PUSH(pc_), {MicroOp::Move16, &temp16_.full, &pc_.full}), /* 0xce ADC A, n */ Program(FETCH(temp8_, pc_), {MicroOp::ADC8, &temp8_}), /* 0xcf RST 08h */ RST(), @@ -515,6 +562,7 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> { /* 0xfe CP n */ Program(FETCH(temp8_, pc_), {MicroOp::CP8, &temp8_}), /* 0xff RST 38h */ RST(), }; + assemble_cb_page(cb_page, index, add_offsets); assemble_page(target, base_program_table, add_offsets); } @@ -543,9 +591,9 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> { public: Processor() : MicroOpScheduler() { - assemble_base_page(base_page_, hl_, false); - assemble_base_page(dd_page_, ix_, true); - assemble_base_page(fd_page_, iy_, true); + assemble_base_page(base_page_, hl_, false, cb_page_); + assemble_base_page(dd_page_, ix_, true, ddcb_page_); + assemble_base_page(fd_page_, iy_, true, fdcb_page_); assemble_ed_page(ed_page_); assemble_fetch_decode_execute(); } @@ -946,7 +994,7 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> { afDash_.bytes.low = f; } break; -#pragma mark - Repetition group +#pragma mark - Repetition case MicroOp::LDIR: { bc_.full--; @@ -967,7 +1015,26 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> { } } break; -#pragma mark - Rotation +#pragma mark - Bit Manipulation + + case MicroOp::BIT: { + uint8_t result = *(uint8_t *)operation->source & (1 << ((operation_ >> 3)&7)); + + sign_result_ = zero_result_ = bit3_result_ = bit5_result_ = result; + half_carry_flag_ = Flag::HalfCarry; + subtract_flag_ = 0; + parity_overflow_flag_ = result ? 0 : Flag::Parity; + } break; + + case MicroOp::RES: + *(uint8_t *)operation->source &= ~(1 << ((operation_ >> 3)&7)); + break; + + case MicroOp::SET: + *(uint8_t *)operation->source |= (1 << ((operation_ >> 3)&7)); + break; + +#pragma mark - Rotation and shifting case MicroOp::RLA: { uint8_t new_carry = a_ >> 7; @@ -1001,6 +1068,88 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> { subtract_flag_ = half_carry_flag_ = 0; } break; + case MicroOp::RLC: { + carry_flag_ = *(uint8_t *)operation->source >> 7; + *(uint8_t *)operation->source = (uint8_t)((*(uint8_t *)operation->source << 1) | carry_flag_); + + sign_result_ = zero_result_ = bit5_result_ = bit3_result_ = *(uint8_t *)operation->source; + set_parity(sign_result_); + half_carry_flag_ = 0; + subtract_flag_ = 0; + } break; + + case MicroOp::RRC: { + carry_flag_ = *(uint8_t *)operation->source & 1; + *(uint8_t *)operation->source = (uint8_t)((*(uint8_t *)operation->source >> 1) | (carry_flag_ << 7)); + + sign_result_ = zero_result_ = bit5_result_ = bit3_result_ = *(uint8_t *)operation->source; + set_parity(sign_result_); + half_carry_flag_ = 0; + subtract_flag_ = 0; + } break; + + case MicroOp::RL: { + uint8_t next_carry = *(uint8_t *)operation->source >> 7; + *(uint8_t *)operation->source = (uint8_t)((*(uint8_t *)operation->source << 1) | carry_flag_); + carry_flag_ = next_carry; + + sign_result_ = zero_result_ = bit5_result_ = bit3_result_ = *(uint8_t *)operation->source; + set_parity(sign_result_); + half_carry_flag_ = 0; + subtract_flag_ = 0; + } break; + + case MicroOp::RR: { + uint8_t next_carry = *(uint8_t *)operation->source & 1; + *(uint8_t *)operation->source = (uint8_t)((*(uint8_t *)operation->source >> 1) | (carry_flag_ << 7)); + carry_flag_ = next_carry; + + sign_result_ = zero_result_ = bit5_result_ = bit3_result_ = *(uint8_t *)operation->source; + set_parity(sign_result_); + half_carry_flag_ = 0; + subtract_flag_ = 0; + } break; + + case MicroOp::SLA: { + carry_flag_ = *(uint8_t *)operation->source >> 7; + *(uint8_t *)operation->source = (uint8_t)(*(uint8_t *)operation->source << 1); + + sign_result_ = zero_result_ = bit5_result_ = bit3_result_ = *(uint8_t *)operation->source; + set_parity(sign_result_); + half_carry_flag_ = 0; + subtract_flag_ = 0; + } break; + + case MicroOp::SRA: { + carry_flag_ = *(uint8_t *)operation->source & 1; + *(uint8_t *)operation->source = (uint8_t)((*(uint8_t *)operation->source >> 1) | (*(uint8_t *)operation->source & 0x80)); + + sign_result_ = zero_result_ = bit5_result_ = bit3_result_ = *(uint8_t *)operation->source; + set_parity(sign_result_); + half_carry_flag_ = 0; + subtract_flag_ = 0; + } break; + + case MicroOp::SLL: { + carry_flag_ = *(uint8_t *)operation->source >> 7; + *(uint8_t *)operation->source = (uint8_t)(*(uint8_t *)operation->source << 1) | 1; + + sign_result_ = zero_result_ = bit5_result_ = bit3_result_ = *(uint8_t *)operation->source; + set_parity(sign_result_); + half_carry_flag_ = 0; + subtract_flag_ = 0; + } break; + + case MicroOp::SRL: { + carry_flag_ = *(uint8_t *)operation->source & 1; + *(uint8_t *)operation->source = (uint8_t)((*(uint8_t *)operation->source >> 1)); + + sign_result_ = zero_result_ = bit5_result_ = bit3_result_ = *(uint8_t *)operation->source; + set_parity(sign_result_); + half_carry_flag_ = 0; + subtract_flag_ = 0; + } break; + #pragma mark - Interrupt state case MicroOp::EI: