From 8f18a128cd991a759c897cab5e28ada5f3efc2cd Mon Sep 17 00:00:00 2001 From: "Adrian.Conlon" Date: Sat, 22 Jul 2017 23:52:58 +0100 Subject: [PATCH 01/10] First step of moving to an instruction decoder, rather than a lookup table. Signed-off-by: Adrian.Conlon --- Intel8080/inc/Intel8080.h | 230 ++++++------------------- Intel8080/src/Intel8080.cpp | 329 ++++++++++++++++++++++++++++++++++++ 2 files changed, 383 insertions(+), 176 deletions(-) diff --git a/Intel8080/inc/Intel8080.h b/Intel8080/inc/Intel8080.h index 5a78849..81aaa4c 100644 --- a/Intel8080/inc/Intel8080.h +++ b/Intel8080/inc/Intel8080.h @@ -43,17 +43,9 @@ namespace EightBit { virtual register16_t& DE() override { return de; } virtual register16_t& HL() override { return hl; } - bool isInterruptable() const { - return m_interrupt; - } + bool isInterruptable() const; - int interrupt(uint8_t value) { - if (isInterruptable()) { - di(); - return execute(value); - } - return 0; - } + int interrupt(uint8_t value); virtual void initialise(); int step(); @@ -72,11 +64,7 @@ namespace EightBit { int execute(uint8_t opcode); - int execute(const Instruction& instruction) { - cycles = 0; - instruction.vector(); - return cycles + instruction.count; - } + int execute(const Instruction& instruction); void adjustReservedFlags() { F() = (F() | Bit1) & ~(Bit5 | Bit3); @@ -90,15 +78,9 @@ namespace EightBit { clearFlag(f, AC, calculateHalfCarrySub(before, value, calculation)); } - static void increment(uint8_t& f, uint8_t& operand) { - adjustSZP(f, ++operand); - clearFlag(f, AC, lowNibble(operand)); - } + static void increment(uint8_t& f, uint8_t& operand); - static void decrement(uint8_t& f, uint8_t& operand) { - adjustSZP(f, --operand); - setFlag(f, AC, lowNibble(operand) != Mask4); - } + static void decrement(uint8_t& f, uint8_t& operand); static Instruction INS(instruction_t method, AddressingMode mode, std::string disassembly, int cycles); Instruction UNKNOWN(); @@ -107,68 +89,18 @@ namespace EightBit { // - void compare(uint8_t& f, uint8_t check, uint8_t value) { - subtract(f, check, value); - } + void compare(uint8_t& f, uint8_t check, uint8_t value); + void anda(uint8_t value); + void ora(uint8_t value); + void xra(uint8_t value); - void anda(uint8_t value) { - auto& a = A(); - auto& f = F(); - setFlag(f, AC, (a | value) & Bit3); - clearFlag(f, CF); - adjustSZP(f, a &= value); - } + void add(uint8_t value, int carry = 0); + void adc(uint8_t value); - void ora(uint8_t value) { - auto& f = F(); - clearFlag(f, AC | CF); - adjustSZP(f, A() |= value); - } + void dad(uint16_t value); - void xra(uint8_t value) { - auto& f = F(); - clearFlag(f, AC | CF); - adjustSZP(f, A() ^= value); - } - - void add(uint8_t value, int carry = 0) { - auto& a = A(); - auto& f = F(); - register16_t sum; - sum.word = a + value + carry; - adjustAuxiliaryCarryAdd(f, a, value, sum.word); - a = sum.low; - setFlag(f, CF, sum.word & Bit8); - adjustSZP(f, a); - } - - void adc(uint8_t value) { - add(value, F() & CF); - } - - void dad(uint16_t value) { - auto& f = F(); - auto sum = HL().word + value; - setFlag(f, CF, sum & Bit16); - HL().word = sum; - } - - void subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0) { - - register16_t result; - result.word = operand - value - carry; - - adjustAuxiliaryCarrySub(f, operand, value, result.word); - - operand = result.low; - - setFlag(f, CF, result.word & Bit8); - adjustSZP(f, operand); - } - - void sbb(uint8_t value) { - subtract(F(), A(), value, F() & CF); - } + void subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0); + void sbb(uint8_t value); void mov_m_r(uint8_t value) { m_memory.ADDRESS() = HL(); @@ -332,16 +264,7 @@ namespace EightBit { adjustReservedFlags(); } - void xhtl() { - m_memory.ADDRESS() = SP(); - MEMPTR().low = m_memory.reference(); - m_memory.reference() = L(); - L() = MEMPTR().low; - m_memory.ADDRESS().word++; - MEMPTR().high = m_memory.reference(); - m_memory.reference() = H(); - H() = MEMPTR().high; - } + void xhtl(); void sphl() { SP() = HL(); @@ -356,56 +279,51 @@ namespace EightBit { // jump - void jmp() { jumpConditional(true); } + void jmp(); - void jc() { jumpConditional(F() & CF); } - void jnc() { jumpConditional(!(F() & CF)); } + void jc(); + void jnc(); - void jz() { jumpConditional(F() & ZF); } - void jnz() { jumpConditional(!(F() & ZF)); } + void jz(); + void jnz(); - void jpe() { jumpConditional(F() & PF); } - void jpo() { jumpConditional(!(F() & PF)); } + void jpe(); + void jpo(); - void jm() { jumpConditional(F() & SF); } - void jp() { jumpConditional(!(F() & SF)); } + void jm(); + void jp(); - void pchl() { - PC() = HL(); - } + void pchl(); // call - void callDirect() { - fetchWord(); - call(); - } + void callDirect(); - void cc() { if (callConditional(F() & CF)) cycles += 6; } - void cnc() { if (callConditional(!(F() & CF))) cycles += 6; } + void cc(); + void cnc(); - void cpe() { if (callConditional(F() & PF)) cycles += 6; } - void cpo() { if (callConditional(!(F() & PF))) cycles += 6; } + void cpe(); + void cpo(); - void cz() { if (callConditional(F() & ZF)) cycles += 6; } - void cnz() { if (callConditional(!(F() & ZF))) cycles += 6; } + void cz(); + void cnz(); - void cm() { if (callConditional(F() & SF)) cycles += 6; } - void cp() { if (callConditional(!(F() & SF))) cycles += 6; } + void cm(); + void cp(); // return - void rc() { if (returnConditional(F() & CF)) cycles += 6; } - void rnc() { if (returnConditional(!(F() & CF))) cycles += 6; } + void rc(); + void rnc(); - void rz() { if (returnConditional(F() & ZF)) cycles += 6; } - void rnz() { if (returnConditional(!(F() & ZF))) cycles += 6; } + void rz(); + void rnz(); - void rpe() { if (returnConditional(F() & PF)) cycles += 6; } - void rpo() { if (returnConditional(!(F() & PF))) cycles += 6; } + void rpe(); + void rpo(); - void rm() { if (returnConditional(F() & SF)) cycles += 6; } - void rp() { if (returnConditional(!(F() & SF))) cycles += 6; } + void rm(); + void rp(); // restart @@ -591,67 +509,27 @@ namespace EightBit { // rotate - void rlc() { - auto& a = A(); - auto carry = a & Bit7; - a = (a << 1) | (carry >> 7); - setFlag(F(), CF, carry); - } - - void rrc() { - auto& a = A(); - auto carry = a & Bit0; - a = (a >> 1) | (carry << 7); - setFlag(F(), CF, carry); - } - - void ral() { - auto& a = A(); - auto& f = F(); - const auto carry = f & CF; - setFlag(f, CF, a & Bit7); - a = (a << 1) | carry; - } - - void rar() { - auto& a = A(); - auto& f = F(); - const auto carry = f & CF; - setFlag(f, CF, a & Bit0); - a = (a >> 1) | (carry << 7); - } + void rlc(); + void rrc(); + void ral(); + void rar(); // specials - void cma() { A() ^= Mask8; } - void stc() { setFlag(F(), CF); } - void cmc() { clearFlag(F(), CF, F() & CF); } - - void daa() { - const auto& a = A(); - auto& f = F(); - auto carry = f & CF; - uint8_t addition = 0; - if ((f & AC) || lowNibble(a) > 9) { - addition = 0x6; - } - if ((f & CF) || highNibble(a) > 9 || (highNibble(a) >= 9 && lowNibble(a) > 9)) { - addition |= 0x60; - carry = true; - } - add(addition); - setFlag(f, CF, carry); - } + void cma(); + void stc(); + void cmc(); + void daa(); // input/output - void out() { m_ports.write(fetchByte(), A()); } - void in() { A() = m_ports.read(fetchByte()); } + void out(); + void in(); // control - void ei() { m_interrupt = true; } - void di() { m_interrupt = false; } + void ei(); + void di(); void nop() {} diff --git a/Intel8080/src/Intel8080.cpp b/Intel8080/src/Intel8080.cpp index 41be661..2850369 100644 --- a/Intel8080/src/Intel8080.cpp +++ b/Intel8080/src/Intel8080.cpp @@ -62,6 +62,329 @@ void EightBit::Intel8080::initialise() { AF().word = BC().word = DE().word = HL().word = 0; } +#pragma region Interrupt routines + +void EightBit::Intel8080::di() { + m_interrupt = false; +} + +void EightBit::Intel8080::ei() { + m_interrupt = true; +} + +int EightBit::Intel8080::interrupt(uint8_t value) { + if (isInterruptable()) { + di(); + return execute(value); + } + return 0; +} + +bool EightBit::Intel8080::isInterruptable() const { + return m_interrupt; +} + +#pragma endregion Interrupt routines + +#pragma region Flag manipulation helpers + +void EightBit::Intel8080::increment(uint8_t& f, uint8_t& operand) { + adjustSZP(f, ++operand); + clearFlag(f, AC, lowNibble(operand)); +} + +void EightBit::Intel8080::decrement(uint8_t& f, uint8_t& operand) { + adjustSZP(f, --operand); + setFlag(f, AC, lowNibble(operand) != Mask4); +} + +#pragma endregion Flag manipulation helpers + +#pragma region PC manipulation: call/ret/jp/jr + +void EightBit::Intel8080::jmp() { + jumpConditional(true); +} + +void EightBit::Intel8080::jc() { + jumpConditional(F() & CF); +} + +void EightBit::Intel8080::jnc() { + jumpConditional(!(F() & CF)); +} + +void EightBit::Intel8080::jz() { + jumpConditional(F() & ZF); +} + +void EightBit::Intel8080::jnz() { + jumpConditional(!(F() & ZF)); +} + +void EightBit::Intel8080::jpe() { + jumpConditional(F() & PF); +} + +void EightBit::Intel8080::jpo() { + jumpConditional(!(F() & PF)); +} + +void EightBit::Intel8080::jm() { + jumpConditional(F() & SF); +} + +void EightBit::Intel8080::jp() { + jumpConditional(!(F() & SF)); +} + +void EightBit::Intel8080::pchl() { + PC() = HL(); +} + +void EightBit::Intel8080::rc() { + if (returnConditional(F() & CF)) + cycles += 6; +} + +void EightBit::Intel8080::rnc() { + if (returnConditional(!(F() & CF))) + cycles += 6; +} + +void EightBit::Intel8080::rz() { + if (returnConditional(F() & ZF)) + cycles += 6; +} + +void EightBit::Intel8080::rnz() { + if (returnConditional(!(F() & ZF))) + cycles += 6; +} + +void EightBit::Intel8080::rpe() { + if (returnConditional(F() & PF)) + cycles += 6; +} + +void EightBit::Intel8080::rpo() { + if (returnConditional(!(F() & PF))) + cycles += 6; +} + +void EightBit::Intel8080::rm() { + if (returnConditional(F() & SF)) + cycles += 6; +} + +void EightBit::Intel8080::rp() { + if (returnConditional(!(F() & SF))) + cycles += 6; +} + +void EightBit::Intel8080::callDirect() { + fetchWord(); + call(); +} + +void EightBit::Intel8080::cc() { + if (callConditional(F() & CF)) + cycles += 6; +} + +void EightBit::Intel8080::cnc() { + if (callConditional(!(F() & CF))) + cycles += 6; +} + +void EightBit::Intel8080::cpe() { + if (callConditional(F() & PF)) + cycles += 6; +} + +void EightBit::Intel8080::cpo() { + if (callConditional(!(F() & PF))) + cycles += 6; +} + +void EightBit::Intel8080::cz() { + if (callConditional(F() & ZF)) + cycles += 6; +} + +void EightBit::Intel8080::cnz() { + if (callConditional(!(F() & ZF))) + cycles += 6; +} + +void EightBit::Intel8080::cm() { + if (callConditional(F() & SF)) + cycles += 6; +} + +void EightBit::Intel8080::cp() { + if (callConditional(!(F() & SF))) + cycles += 6; +} + +#pragma endregion PC manipulation: call/ret/jp/jr + +#pragma region 16-bit arithmetic + +void EightBit::Intel8080::dad(uint16_t value) { + auto& f = F(); + auto sum = HL().word + value; + setFlag(f, CF, sum & Bit16); + HL().word = sum; +} + +#pragma endregion 16-bit arithmetic + +#pragma region ALU + +void EightBit::Intel8080::add(uint8_t value, int carry) { + auto& a = A(); + auto& f = F(); + register16_t sum; + sum.word = a + value + carry; + adjustAuxiliaryCarryAdd(f, a, value, sum.word); + a = sum.low; + setFlag(f, CF, sum.word & Bit8); + adjustSZP(f, a); +} + +void EightBit::Intel8080::adc(uint8_t value) { + add(value, F() & CF); +} + +void EightBit::Intel8080::subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry) { + + register16_t result; + result.word = operand - value - carry; + + adjustAuxiliaryCarrySub(f, operand, value, result.word); + + operand = result.low; + + setFlag(f, CF, result.word & Bit8); + adjustSZP(f, operand); +} + +void EightBit::Intel8080::sbb(uint8_t value) { + subtract(F(), A(), value, F() & CF); +} + +void EightBit::Intel8080::anda(uint8_t value) { + auto& a = A(); + auto& f = F(); + setFlag(f, AC, (a | value) & Bit3); + clearFlag(f, CF); + adjustSZP(f, a &= value); +} + +void EightBit::Intel8080::xra(uint8_t value) { + auto& f = F(); + clearFlag(f, AC | CF); + adjustSZP(f, A() ^= value); +} + +void EightBit::Intel8080::ora(uint8_t value) { + auto& f = F(); + clearFlag(f, AC | CF); + adjustSZP(f, A() |= value); +} + +void EightBit::Intel8080::compare(uint8_t& f, uint8_t check, uint8_t value) { + subtract(f, check, value); +} + +#pragma endregion ALU + +#pragma region Shift and rotate + +void EightBit::Intel8080::rlc() { + auto& a = A(); + auto carry = a & Bit7; + a = (a << 1) | (carry >> 7); + setFlag(F(), CF, carry); +} + +void EightBit::Intel8080::rrc() { + auto& a = A(); + auto carry = a & Bit0; + a = (a >> 1) | (carry << 7); + setFlag(F(), CF, carry); +} + +void EightBit::Intel8080::ral() { + auto& a = A(); + auto& f = F(); + const auto carry = f & CF; + setFlag(f, CF, a & Bit7); + a = (a << 1) | carry; +} + +void EightBit::Intel8080::rar() { + auto& a = A(); + auto& f = F(); + const auto carry = f & CF; + setFlag(f, CF, a & Bit0); + a = (a >> 1) | (carry << 7); +} + +#pragma endregion Shift and rotate + +#pragma region Miscellaneous instructions + +void EightBit::Intel8080::daa() { + const auto& a = A(); + auto& f = F(); + auto carry = f & CF; + uint8_t addition = 0; + if ((f & AC) || lowNibble(a) > 9) { + addition = 0x6; + } + if ((f & CF) || highNibble(a) > 9 || (highNibble(a) >= 9 && lowNibble(a) > 9)) { + addition |= 0x60; + carry = true; + } + add(addition); + setFlag(f, CF, carry); +} + +void EightBit::Intel8080::cma() { + A() ^= Mask8; +} + +void EightBit::Intel8080::stc() { + setFlag(F(), CF); +} + +void EightBit::Intel8080::cmc() { + clearFlag(F(), CF, F() & CF); +} + +void EightBit::Intel8080::xhtl() { + m_memory.ADDRESS() = SP(); + MEMPTR().low = m_memory.reference(); + m_memory.reference() = L(); + L() = MEMPTR().low; + m_memory.ADDRESS().word++; + MEMPTR().high = m_memory.reference(); + m_memory.reference() = H(); + H() = MEMPTR().high; +} + +#pragma endregion Miscellaneous instructions + +void EightBit::Intel8080::out() { + m_ports.write(fetchByte(), A()); +} + +void EightBit::Intel8080::in() { + A() = m_ports.read(fetchByte()); +} + int EightBit::Intel8080::step() { ExecutingInstruction.fire(*this); return execute(fetchByte()); @@ -72,6 +395,12 @@ int EightBit::Intel8080::execute(uint8_t opcode) { return execute(instruction); } +int EightBit::Intel8080::execute(const Instruction& instruction) { + cycles = 0; + instruction.vector(); + return cycles + instruction.count; +} + // void EightBit::Intel8080::___() { From ad9d37237ff059aff6913e1c2f5603ababb12367 Mon Sep 17 00:00:00 2001 From: "Adrian.Conlon" Date: Sun, 23 Jul 2017 10:26:53 +0100 Subject: [PATCH 02/10] Put i8080 instructions into their own region Signed-off-by: Adrian.Conlon --- Intel8080/src/Intel8080.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Intel8080/src/Intel8080.cpp b/Intel8080/src/Intel8080.cpp index 2850369..a11ad78 100644 --- a/Intel8080/src/Intel8080.cpp +++ b/Intel8080/src/Intel8080.cpp @@ -377,6 +377,8 @@ void EightBit::Intel8080::xhtl() { #pragma endregion Miscellaneous instructions +#pragma region I/O instructions + void EightBit::Intel8080::out() { m_ports.write(fetchByte(), A()); } @@ -385,6 +387,8 @@ void EightBit::Intel8080::in() { A() = m_ports.read(fetchByte()); } +#pragma endregion I/O instructions + int EightBit::Intel8080::step() { ExecutingInstruction.fire(*this); return execute(fetchByte()); From c0c969c560584508a50f0cbebba8a4d109cdae0e Mon Sep 17 00:00:00 2001 From: "Adrian.Conlon" Date: Mon, 24 Jul 2017 22:00:49 +0100 Subject: [PATCH 03/10] Use a z80 style instruction decoder for the i8080 emulator. --- Intel8080/inc/Intel8080.h | 533 ++++++----------------------- Intel8080/src/Intel8080.cpp | 660 ++++++++++++++++++++++++++---------- 2 files changed, 587 insertions(+), 606 deletions(-) diff --git a/Intel8080/inc/Intel8080.h b/Intel8080/inc/Intel8080.h index 81aaa4c..bb92a26 100644 --- a/Intel8080/inc/Intel8080.h +++ b/Intel8080/inc/Intel8080.h @@ -38,18 +38,30 @@ namespace EightBit { const std::array& getInstructions() const { return instructions; } - virtual register16_t& AF() override { return af; } - virtual register16_t& BC() override { return bc; } - virtual register16_t& DE() override { return de; } - virtual register16_t& HL() override { return hl; } - bool isInterruptable() const; int interrupt(uint8_t value); - virtual void initialise(); int step(); + virtual register16_t& AF() override { + return af; + } + + virtual register16_t& BC() override { + return bc; + } + + virtual register16_t& DE() override { + return de; + } + + virtual register16_t& HL() override { + return hl; + } + + virtual void initialise(); + private: InputOutput& m_ports; @@ -62,9 +74,66 @@ namespace EightBit { bool m_interrupt; - int execute(uint8_t opcode); + uint8_t& R(int r) { + __assume(r < 8); + __assume(r >= 0); + switch (r) { + case 0b000: + return B(); + case 0b001: + return C(); + case 0b010: + return D(); + case 0b011: + return E(); + case 0b100: + return H(); + case 0b101: + return L(); + case 0b110: + m_memory.ADDRESS() = HL(); + return m_memory.reference(); + case 0b111: + return A(); + default: + __assume(0); + } + throw std::logic_error("Unhandled registry mechanism"); + } - int execute(const Instruction& instruction); + register16_t& RP(int rp) { + __assume(rp < 4); + __assume(rp >= 0); + switch (rp) { + case 0b00: + return BC(); + case 0b01: + return DE(); + case 0b10: + return HL(); + case 0b11: + return SP(); + default: + __assume(0); + } + } + + register16_t& RP2(int rp) { + __assume(rp < 4); + __assume(rp >= 0); + switch (rp) { + case 0b00: + return BC(); + case 0b01: + return DE(); + case 0b10: + return HL(); + case 0b11: + return AF(); + default: + __assume(0); + } + } void adjustReservedFlags() { F() = (F() | Bit1) & ~(Bit5 | Bit3); @@ -78,448 +147,41 @@ namespace EightBit { clearFlag(f, AC, calculateHalfCarrySub(before, value, calculation)); } + static void subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0); + + int execute(uint8_t opcode); + void execute(int x, int y, int z, int p, int q); + static void increment(uint8_t& f, uint8_t& operand); static void decrement(uint8_t& f, uint8_t& operand); - static Instruction INS(instruction_t method, AddressingMode mode, std::string disassembly, int cycles); - Instruction UNKNOWN(); - - void installInstructions(); - - // - - void compare(uint8_t& f, uint8_t check, uint8_t value); - void anda(uint8_t value); - void ora(uint8_t value); - void xra(uint8_t value); - - void add(uint8_t value, int carry = 0); - void adc(uint8_t value); + bool returnConditionalFlag(uint8_t& f, int flag); + bool jumpConditionalFlag(uint8_t& f, int flag); + bool callConditionalFlag(uint8_t& f, int flag); void dad(uint16_t value); - void subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0); + void add(uint8_t value, int carry = 0); + void adc(uint8_t value); void sbb(uint8_t value); - - void mov_m_r(uint8_t value) { - m_memory.ADDRESS() = HL(); - m_memory.reference() = value; - } - - uint8_t mov_r_m() { - m_memory.ADDRESS() = HL(); - return m_memory.reference(); - } - - // - - void ___(); - - // Move, load, and store - - void mov_a_a() { } - void mov_a_b() { A() = B(); } - void mov_a_c() { A() = C(); } - void mov_a_d() { A() = D(); } - void mov_a_e() { A() = E(); } - void mov_a_h() { A() = H(); } - void mov_a_l() { A() = L(); } - - void mov_b_a() { B() = A(); } - void mov_b_b() { } - void mov_b_c() { B() = C(); } - void mov_b_d() { B() = D(); } - void mov_b_e() { B() = E(); } - void mov_b_h() { B() = H(); } - void mov_b_l() { B() = L(); } - - void mov_c_a() { C() = A(); } - void mov_c_b() { C() = B(); } - void mov_c_c() { } - void mov_c_d() { C() = D(); } - void mov_c_e() { C() = E(); } - void mov_c_h() { C() = H(); } - void mov_c_l() { C() = L(); } - - void mov_d_a() { D() = A(); } - void mov_d_b() { D() = B(); } - void mov_d_c() { D() = C(); } - void mov_d_d() { } - void mov_d_e() { D() = E(); } - void mov_d_h() { D() = H(); } - void mov_d_l() { D() = L(); } - - void mov_e_a() { E() = A(); } - void mov_e_b() { E() = B(); } - void mov_e_c() { E() = C(); } - void mov_e_d() { E() = D(); } - void mov_e_e() { } - void mov_e_h() { E() = H(); } - void mov_e_l() { E() = L(); } - - void mov_h_a() { H() = A(); } - void mov_h_b() { H() = B(); } - void mov_h_c() { H() = C(); } - void mov_h_d() { H() = D(); } - void mov_h_e() { H() = E(); } - void mov_h_h() { } - void mov_h_l() { H() = L(); } - - void mov_l_a() { L() = A(); } - void mov_l_b() { L() = B(); } - void mov_l_c() { L() = C(); } - void mov_l_d() { L() = D(); } - void mov_l_e() { L() = E(); } - void mov_l_h() { L() = H(); } - void mov_l_l() { } - - void mov_m_a() { mov_m_r(A()); } - void mov_m_b() { mov_m_r(B()); } - void mov_m_c() { mov_m_r(C()); } - void mov_m_d() { mov_m_r(D()); } - void mov_m_e() { mov_m_r(E()); } - void mov_m_h() { mov_m_r(H()); } - void mov_m_l() { mov_m_r(L()); } - - void mov_a_m() { A() = mov_r_m(); } - void mov_b_m() { B() = mov_r_m(); } - void mov_c_m() { C() = mov_r_m(); } - void mov_d_m() { D() = mov_r_m(); } - void mov_e_m() { E() = mov_r_m(); } - void mov_h_m() { H() = mov_r_m(); } - void mov_l_m() { L() = mov_r_m(); } - - void mvi_a() { A() = fetchByte(); } - void mvi_b() { B() = fetchByte(); } - void mvi_c() { C() = fetchByte(); } - void mvi_d() { D() = fetchByte(); } - void mvi_e() { E() = fetchByte(); } - void mvi_h() { H() = fetchByte(); } - void mvi_l() { L() = fetchByte(); } - - void mvi_m() { - auto data = fetchByte(); - m_memory.ADDRESS() = HL(); - m_memory.reference() = data; - } - - void lxi_b() { fetchWord(BC()); } - void lxi_d() { fetchWord(DE()); } - void lxi_h() { fetchWord(HL()); } - - void stax_r(register16_t& destination) { - m_memory.ADDRESS() = destination; - m_memory.reference() = A(); - } - - void stax_b() { stax_r(BC()); } - void stax_d() { stax_r(DE()); } - - void ldax_r(register16_t& source) { - m_memory.ADDRESS() = source; - A() = m_memory.reference(); - } - - void ldax_b() { ldax_r(BC()); } - void ldax_d() { ldax_r(DE()); } - - void sta() { - fetchWord(); - memptrReference() = A(); - } - - void lda() { - fetchWord(); - A() = memptrReference(); - } - - void shld() { - fetchWord(); - setWordViaMemptr(HL()); - } - - void lhld() { - fetchWord(); - getWordViaMemptr(HL()); - } - - void xchg() { - std::swap(DE(), HL()); - } - - // stack ops - - void push_b() { pushWord(BC()); } - void push_d() { pushWord(DE()); } - void push_h() { pushWord(HL()); } - void push_psw() { pushWord(AF()); } - - void pop_b() { popWord(BC()); } - void pop_d() { popWord(DE()); } - void pop_h() { popWord(HL()); } - - void pop_psw() { - popWord(AF()); - adjustReservedFlags(); - } - - void xhtl(); - - void sphl() { - SP() = HL(); - } - - void lxi_sp() { - fetchWord(SP()); - } - - void inx_sp() { ++SP().word; } - void dcx_sp() { --SP().word; } - - // jump - - void jmp(); - - void jc(); - void jnc(); - - void jz(); - void jnz(); - - void jpe(); - void jpo(); - - void jm(); - void jp(); - - void pchl(); - - // call - - void callDirect(); - - void cc(); - void cnc(); - - void cpe(); - void cpo(); - - void cz(); - void cnz(); - - void cm(); - void cp(); - - // return - - void rc(); - void rnc(); - - void rz(); - void rnz(); - - void rpe(); - void rpo(); - - void rm(); - void rp(); - - // restart - - void rst_0() { restart(0 << 3); } - void rst_1() { restart(1 << 3); } - void rst_2() { restart(2 << 3); } - void rst_3() { restart(3 << 3); } - void rst_4() { restart(4 << 3); } - void rst_5() { restart(5 << 3); } - void rst_6() { restart(6 << 3); } - void rst_7() { restart(7 << 3); } - - // increment and decrement - - void inr_a() { increment(F(), A()); } - void inr_b() { increment(F(), B()); } - void inr_c() { increment(F(), C()); } - void inr_d() { increment(F(), D()); } - void inr_e() { increment(F(), E()); } - void inr_h() { increment(F(), H()); } - void inr_l() { increment(F(), L()); } - - void inr_m() { - m_memory.ADDRESS() = HL(); - increment(F(), m_memory.reference()); - } - - void dcr_a() { decrement(F(), A()); } - void dcr_b() { decrement(F(), B()); } - void dcr_c() { decrement(F(), C()); } - void dcr_d() { decrement(F(), D()); } - void dcr_e() { decrement(F(), E()); } - void dcr_h() { decrement(F(), H()); } - void dcr_l() { decrement(F(), L()); } - - void dcr_m() { - m_memory.ADDRESS() = HL(); - decrement(F(), m_memory.reference()); - } - - void inx_b() { ++BC().word; } - void inx_d() { ++DE().word; } - void inx_h() { ++HL().word; } - - void dcx_b() { --BC().word; } - void dcx_d() { --DE().word; } - void dcx_h() { --HL().word; } - - // add - - void add_a() { add(A()); } - void add_b() { add(B()); } - void add_c() { add(C()); } - void add_d() { add(D()); } - void add_e() { add(E()); } - void add_h() { add(H()); } - void add_l() { add(L()); } - - void add_m() { - m_memory.ADDRESS() = HL(); - add(m_memory.reference()); - } - - void adi() { add(fetchByte()); } - - void adc_a() { adc(A()); } - void adc_b() { adc(B()); } - void adc_c() { adc(C()); } - void adc_d() { adc(D()); } - void adc_e() { adc(E()); } - void adc_h() { adc(H()); } - void adc_l() { adc(L()); } - - void adc_m() { - m_memory.ADDRESS() = HL(); - adc(m_memory.reference()); - } - - void aci() { adc(fetchByte()); } - - void dad_b() { dad(BC().word); } - void dad_d() { dad(DE().word); } - void dad_h() { dad(HL().word); } - void dad_sp() { dad(SP().word); } - - // subtract - - void sub_a() { subtract(F(), A(), A()); } - void sub_b() { subtract(F(), A(), B()); } - void sub_c() { subtract(F(), A(), C()); } - void sub_d() { subtract(F(), A(), D()); } - void sub_e() { subtract(F(), A(), E()); } - void sub_h() { subtract(F(), A(), H()); } - void sub_l() { subtract(F(), A(), L()); } - - void sub_m() { - m_memory.ADDRESS() = HL(); - subtract(F(), A(), m_memory.reference()); - } - - void sbb_a() { sbb(A()); } - void sbb_b() { sbb(B()); } - void sbb_c() { sbb(C()); } - void sbb_d() { sbb(D()); } - void sbb_e() { sbb(E()); } - void sbb_h() { sbb(H()); } - void sbb_l() { sbb(L()); } - - void sbb_m() { - m_memory.ADDRESS() = HL(); - sbb(m_memory.reference()); - } - - void sbi() { - sbb(fetchByte()); - } - - void sui() { - subtract(F(), A(), fetchByte()); - } - - // logical - - void ana_a() { anda(A()); } - void ana_b() { anda(B()); } - void ana_c() { anda(C()); } - void ana_d() { anda(D()); } - void ana_e() { anda(E()); } - void ana_h() { anda(H()); } - void ana_l() { anda(L()); } - - void ana_m() { - m_memory.ADDRESS() = HL(); - anda(m_memory.reference()); - } - - void ani() { anda(fetchByte()); } - - void xra_a() { xra(A()); } - void xra_b() { xra(B()); } - void xra_c() { xra(C()); } - void xra_d() { xra(D()); } - void xra_e() { xra(E()); } - void xra_h() { xra(H()); } - void xra_l() { xra(L()); } - - void xra_m() { - m_memory.ADDRESS() = HL(); - xra(m_memory.reference()); - } - - void xri() { xra(fetchByte()); } - - void ora_a() { ora(A()); } - void ora_b() { ora(B()); } - void ora_c() { ora(C()); } - void ora_d() { ora(D()); } - void ora_e() { ora(E()); } - void ora_h() { ora(H()); } - void ora_l() { ora(L()); } - - void ora_m() { - m_memory.ADDRESS() = HL(); - ora(m_memory.reference()); - } - - void ori() { ora(fetchByte()); } - - void cmp_a() { compare(F(), A(), A()); } - void cmp_b() { compare(F(), A(), B()); } - void cmp_c() { compare(F(), A(), C()); } - void cmp_d() { compare(F(), A(), D()); } - void cmp_e() { compare(F(), A(), E()); } - void cmp_h() { compare(F(), A(), H()); } - void cmp_l() { compare(F(), A(), L()); } - - void cmp_m() { - m_memory.ADDRESS() = HL(); - compare(F(), A(), m_memory.reference()); - } - - void cpi() { compare(F(), A(), fetchByte()); } - - // rotate + void anda(uint8_t value); + void xra(uint8_t value); + void ora(uint8_t value); + void compare(uint8_t& f, uint8_t check, uint8_t value); void rlc(); void rrc(); void ral(); void rar(); - // specials + void daa(); void cma(); void stc(); void cmc(); - void daa(); + + void xhtl(); // input/output @@ -531,8 +193,13 @@ namespace EightBit { void ei(); void di(); + // + + void ___(); void nop() {} - void hlt() { halt(); } + static Instruction INS(instruction_t method, AddressingMode mode, std::string disassembly, int cycles); + Instruction UNKNOWN(); + void installInstructions(); }; } \ No newline at end of file diff --git a/Intel8080/src/Intel8080.cpp b/Intel8080/src/Intel8080.cpp index a11ad78..f1aa668 100644 --- a/Intel8080/src/Intel8080.cpp +++ b/Intel8080/src/Intel8080.cpp @@ -12,53 +12,8 @@ EightBit::Intel8080::Intel8080(Memory& memory, InputOutput& ports) installInstructions(); } -EightBit::Intel8080::Instruction EightBit::Intel8080::INS(instruction_t method, AddressingMode mode, std::string disassembly, int cycles) { - Intel8080::Instruction returnValue; - returnValue.vector = method; - returnValue.mode = mode; - returnValue.disassembly = disassembly; - returnValue.count = cycles; - return returnValue; -} - -EightBit::Intel8080::Instruction EightBit::Intel8080::UNKNOWN() { - Intel8080::Instruction returnValue; - returnValue.vector = std::bind(&Intel8080::___, this); - returnValue.mode = Unknown; - returnValue.disassembly = ""; - returnValue.count = 0; - return returnValue; -} - -#define BIND(method) std::bind(&Intel8080:: method, this) - -void EightBit::Intel8080::installInstructions() { - instructions = { - //// 0 1 2 3 4 5 6 7 8 9 A B C D E F - /* 0 */ INS(BIND(nop), Implied, "NOP", 4), INS(BIND(lxi_b), Absolute, "LXI B,", 10), INS(BIND(stax_b), Implied, "STAX B", 7), INS(BIND(inx_b), Implied, "INX B", 5), INS(BIND(inr_b), Implied, "INR B", 5), INS(BIND(dcr_b), Implied, "DCR B", 5), INS(BIND(mvi_b), Immediate, "MVI B,", 7), INS(BIND(rlc), Implied, "RLC", 4), UNKNOWN(), INS(BIND(dad_b), Implied, "DAD B", 10), INS(BIND(ldax_b), Implied, "LDAX B", 7), INS(BIND(dcx_b), Implied, "DCX B", 5), INS(BIND(inr_c), Implied, "INR C", 5), INS(BIND(dcr_c), Implied, "DCR C", 5), INS(BIND(mvi_c), Immediate, "MVI C,", 7), INS(BIND(rrc), Implied, "RRC", 4), // 0 - /* 1 */ UNKNOWN(), INS(BIND(lxi_d), Absolute, "LXI D,", 10), INS(BIND(stax_d), Implied, "STAX D", 7), INS(BIND(inx_d), Implied, "INX D", 5), INS(BIND(inr_d), Implied, "INR D", 5), INS(BIND(dcr_d), Implied, "DCR D", 5), INS(BIND(mvi_d), Immediate, "MVI D,", 7), INS(BIND(ral), Implied, "RAL", 4), UNKNOWN(), INS(BIND(dad_d), Implied, "DAD D", 10), INS(BIND(ldax_d), Implied, "LDAX D", 7), INS(BIND(dcx_d), Implied, "DCX D", 5), INS(BIND(inr_e), Implied, "INR E", 5), INS(BIND(dcr_e), Implied, "DCR E", 5), INS(BIND(mvi_e), Immediate, "MVI E,", 7), INS(BIND(rar), Implied, "RAR", 4), // 1 - /* 2 */ UNKNOWN(), INS(BIND(lxi_h), Absolute, "LXI H,", 10), INS(BIND(shld), Absolute, "SHLD", 16), INS(BIND(inx_h), Implied, "INX H", 5), INS(BIND(inr_h), Implied, "INR H", 5), INS(BIND(dcr_h), Implied, "DCR H", 5), INS(BIND(mvi_h), Immediate, "MVI H,",7), INS(BIND(daa), Implied, "DAA", 4), UNKNOWN(), INS(BIND(dad_h), Implied, "DAD H", 10), INS(BIND(lhld), Absolute, "LHLD ", 16), INS(BIND(dcx_h), Implied, "DCX H", 5), INS(BIND(inr_l), Implied, "INR L", 5), INS(BIND(dcr_l), Implied, "DCR L", 5), INS(BIND(mvi_l), Immediate, "MVI L,", 7), INS(BIND(cma), Implied, "CMA", 4), // 2 - /* 3 */ UNKNOWN(), INS(BIND(lxi_sp), Absolute, "LXI SP,", 10), INS(BIND(sta), Absolute, "STA ", 13), INS(BIND(inx_sp), Implied, "INX SP", 5), INS(BIND(inr_m), Implied, "INR M", 10), INS(BIND(dcr_m), Implied, "DCR M", 10), INS(BIND(mvi_m), Immediate, "MVI M,", 10), INS(BIND(stc), Implied, "STC", 4), UNKNOWN(), INS(BIND(dad_sp), Implied, "DAD SP", 10), INS(BIND(lda), Absolute, "LDA ", 13), INS(BIND(dcx_sp), Implied, "DCX SP", 5), INS(BIND(inr_a), Implied, "INR A", 5), INS(BIND(dcr_a), Implied, "DCR A", 5), INS(BIND(mvi_a), Immediate, "MVI A,", 7), INS(BIND(cmc), Implied, "CMC", 4), // 3 - - /* 4 */ INS(BIND(mov_b_b), Implied, "MOV B,B", 5), INS(BIND(mov_b_c), Implied, "MOV B,C", 5), INS(BIND(mov_b_d), Implied, "MOV B,D", 5), INS(BIND(mov_b_e), Implied, "MOV B,E", 5), INS(BIND(mov_b_h), Implied, "MOV B,H", 5), INS(BIND(mov_b_l), Implied, "MOV B,L", 5), INS(BIND(mov_b_m), Implied, "MOV B,M", 7), INS(BIND(mov_b_a), Implied, "MOV B,A", 5), INS(BIND(mov_c_b), Implied, "MOV C,B", 5), INS(BIND(mov_c_c), Implied, "MOV C,C", 5), INS(BIND(mov_c_d), Implied, "MOV C,D", 5), INS(BIND(mov_c_e), Implied, "MOV C,E", 5), INS(BIND(mov_c_h), Implied, "MOV C,H", 5), INS(BIND(mov_c_l), Implied, "MOV C,L", 5), INS(BIND(mov_c_m), Implied, "MOV C,M", 7), INS(BIND(mov_c_a), Implied, "MOV C,A", 5), // 4 - /* 5 */ INS(BIND(mov_d_b), Implied, "MOV D,B", 5), INS(BIND(mov_d_c), Implied, "MOV D,C", 5), INS(BIND(mov_d_d), Implied, "MOV D,D", 5), INS(BIND(mov_d_e), Implied, "MOV D,E", 5), INS(BIND(mov_d_h), Implied, "MOV D,H", 5), INS(BIND(mov_d_l), Implied, "MOV D,L", 5), INS(BIND(mov_d_m), Implied, "MOV D,M", 7), INS(BIND(mov_d_a), Implied, "MOV D,A", 5), INS(BIND(mov_e_b), Implied, "MOV E,B", 5), INS(BIND(mov_e_c), Implied, "MOV E,C", 5), INS(BIND(mov_e_d), Implied, "MOV E,D", 5), INS(BIND(mov_e_e), Implied, "MOV E,E", 5), INS(BIND(mov_e_h), Implied, "MOV E,H", 5), INS(BIND(mov_e_l), Implied, "MOV E,L", 5), INS(BIND(mov_e_m), Implied, "MOV E,M", 7), INS(BIND(mov_e_a), Implied, "MOV E,A", 5), // 5 - /* 6 */ INS(BIND(mov_h_b), Implied, "MOV H,B", 5), INS(BIND(mov_h_c), Implied, "MOV H,C", 5), INS(BIND(mov_h_d), Implied, "MOV H,D", 5), INS(BIND(mov_h_e), Implied, "MOV H,E", 5), INS(BIND(mov_h_h), Implied, "MOV H,H", 5), INS(BIND(mov_h_l), Implied, "MOV H,L", 5), INS(BIND(mov_h_m), Implied, "MOV H,M", 7), INS(BIND(mov_h_a), Implied, "MOV H,A", 5), INS(BIND(mov_l_b), Implied, "MOV L,B", 5), INS(BIND(mov_l_c), Implied, "MOV L,C", 5), INS(BIND(mov_l_d), Implied, "MOV L,D", 5), INS(BIND(mov_l_e), Implied, "MOV L,E", 5), INS(BIND(mov_l_h), Implied, "MOV L,H", 5), INS(BIND(mov_l_l), Implied, "MOV L,L", 5), INS(BIND(mov_l_m), Implied, "MOV L,M", 7), INS(BIND(mov_l_a), Implied, "MOV L,A", 5), // 6 - /* 7 */ INS(BIND(mov_m_b), Implied, "MOV M,B", 7), INS(BIND(mov_m_c), Implied, "MOV M,C", 7), INS(BIND(mov_m_d), Implied, "MOV M,D", 7), INS(BIND(mov_m_e), Implied, "MOV M,E", 7), INS(BIND(mov_m_h), Implied, "MOV M,H", 7), INS(BIND(mov_m_l), Implied, "MOV M,L", 7), INS(BIND(hlt), Implied, "HLT", 7), INS(BIND(mov_m_a), Implied, "MOV M,A", 7), INS(BIND(mov_a_b), Implied, "MOV A,B", 5), INS(BIND(mov_a_c), Implied, "MOV A,C", 5), INS(BIND(mov_a_d), Implied, "MOV A,D", 5), INS(BIND(mov_a_e), Implied, "MOV A,E", 5), INS(BIND(mov_a_h), Implied, "MOV A,H", 5), INS(BIND(mov_a_l), Implied, "MOV A,L", 5), INS(BIND(mov_a_m), Implied, "MOV A,M", 7), INS(BIND(mov_a_a), Implied, "MOV A,A", 5), // 7 - - /* 8 */ INS(BIND(add_b), Implied, "ADD B", 4), INS(BIND(add_c), Implied, "ADD C", 4), INS(BIND(add_d), Implied, "ADD D", 4), INS(BIND(add_e), Implied, "ADD E", 4), INS(BIND(add_h), Implied, "ADD H", 4), INS(BIND(add_l), Implied, "ADD L", 4), INS(BIND(add_m), Implied, "ADD M", 7), INS(BIND(add_a), Implied, "ADD A", 4), INS(BIND(adc_b), Implied, "ADC B", 4), INS(BIND(adc_c), Implied, "ADC C", 4), INS(BIND(adc_d), Implied, "ADC D", 4), INS(BIND(adc_e), Implied, "ADC E", 4), INS(BIND(adc_h), Implied, "ADC H", 4), INS(BIND(adc_l), Implied, "ADC L", 4), INS(BIND(adc_m), Implied, "ADC M", 4), INS(BIND(adc_a), Implied, "ADC A", 4), // 8 - /* 9 */ INS(BIND(sub_b), Implied, "SUB B", 4), INS(BIND(sub_c), Implied, "SUB C", 4), INS(BIND(sub_d), Implied, "SUB D", 4), INS(BIND(sub_e), Implied, "SUB E", 4), INS(BIND(sub_h), Implied, "SUB H", 4), INS(BIND(sub_l), Implied, "SUB L", 4), INS(BIND(sub_m), Implied, "SUB M", 7), INS(BIND(sub_a), Implied, "SUB A", 4), INS(BIND(sbb_b), Implied, "SBB B", 4), INS(BIND(sbb_c), Implied, "SBB C", 4), INS(BIND(sbb_d), Implied, "SBB D", 4), INS(BIND(sbb_e), Implied, "SBB E", 4), INS(BIND(sbb_h), Implied, "SBB H", 4), INS(BIND(sbb_l), Implied, "SBB L", 4), INS(BIND(sbb_m), Implied, "SBB M", 4), INS(BIND(sbb_a), Implied, "SBB A", 4), // 9 - /* A */ INS(BIND(ana_b), Implied, "ANA B", 4), INS(BIND(ana_c), Implied, "ANA C", 4), INS(BIND(ana_d), Implied, "ANA D", 4), INS(BIND(ana_e), Implied, "ANA E", 4), INS(BIND(ana_h), Implied, "ANA H", 4), INS(BIND(ana_l), Implied, "ANA L", 4), INS(BIND(ana_m), Implied, "ANA M", 7), INS(BIND(ana_a), Implied, "ANA A", 4), INS(BIND(xra_b), Implied, "XRA B", 4), INS(BIND(xra_c), Implied, "XRA C", 4), INS(BIND(xra_d), Implied, "XRA D", 4), INS(BIND(xra_e), Implied, "XRA E", 4), INS(BIND(xra_h), Implied, "XRA H", 4), INS(BIND(xra_l), Implied, "XRA L", 4), INS(BIND(xra_m), Implied, "XRA M", 4), INS(BIND(xra_a), Implied, "XRA A", 4), // A - /* B */ INS(BIND(ora_b), Implied, "ORA B", 4), INS(BIND(ora_c), Implied, "ORA C", 4), INS(BIND(ora_d), Implied, "ORA D", 4), INS(BIND(ora_e), Implied, "ORA E", 4), INS(BIND(ora_h), Implied, "ORA H", 4), INS(BIND(ora_l), Implied, "ORA L", 4), INS(BIND(ora_m), Implied, "ORA M", 7), INS(BIND(ora_a), Implied, "ORA A", 4), INS(BIND(cmp_b), Implied, "CMP B", 4), INS(BIND(cmp_c), Implied, "CMP C", 4), INS(BIND(cmp_d), Implied, "CMP D", 4), INS(BIND(cmp_e), Implied, "CMP E", 4), INS(BIND(cmp_h), Implied, "CMP H", 4), INS(BIND(cmp_l), Implied, "CMP L", 4), INS(BIND(cmp_m), Implied, "CMP M", 4), INS(BIND(cmp_a), Implied, "CMP A", 4), // B - - /* C */ INS(BIND(rnz), Implied, "RNZ", 5), INS(BIND(pop_b), Implied, "POP B", 10), INS(BIND(jnz), Absolute, "JNZ ", 10), INS(BIND(jmp), Absolute, "JMP ", 10), INS(BIND(cnz), Absolute, "CNZ ", 11), INS(BIND(push_b), Implied, "PUSH B", 11), INS(BIND(adi), Immediate, "ADI ", 7), INS(BIND(rst_0), Implied, "RST 0", 11), INS(BIND(rz), Implied, "RZ", 11), INS(BIND(ret), Implied, "RET", 10), INS(BIND(jz), Absolute, "JZ ", 10), UNKNOWN(), INS(BIND(cz), Absolute, "CZ ", 11), INS(BIND(callDirect), Absolute, "CALL ", 17), INS(BIND(aci), Immediate, "ACI ", 7), INS(BIND(rst_1), Implied, "RST 1", 11), // C - /* D */ INS(BIND(rnc), Implied, "RNC", 5), INS(BIND(pop_d), Implied, "POP D", 10), INS(BIND(jnc), Absolute, "JNC ", 10), INS(BIND(out), Immediate, "OUT ", 10), INS(BIND(cnc), Absolute, "CNC ", 11), INS(BIND(push_d), Implied, "PUSH D", 11), INS(BIND(sui), Immediate, "SUI ", 7), INS(BIND(rst_2), Implied, "RST 2", 11), INS(BIND(rc), Implied, "RC", 11), UNKNOWN(), INS(BIND(jc), Absolute, "JC ", 10), INS(BIND(in), Immediate, "IN ", 10), INS(BIND(cc), Absolute, "CC ", 11), UNKNOWN(), INS(BIND(sbi), Immediate, "SBI ", 7), INS(BIND(rst_3), Implied, "RST 3", 11), // D - /* E */ INS(BIND(rpo), Implied, "RPO", 5), INS(BIND(pop_h), Implied, "POP H", 10), INS(BIND(jpo), Absolute, "JPO ", 10), INS(BIND(xhtl), Implied, "XHTL", 18), INS(BIND(cpo), Absolute, "CPO ", 11), INS(BIND(push_h), Implied, "PUSH H", 11), INS(BIND(ani), Immediate, "ANI ", 7), INS(BIND(rst_4), Implied, "RST 4", 11), INS(BIND(rpe), Implied, "RPE", 11), INS(BIND(pchl), Implied, "PCHL", 5), INS(BIND(jpe), Absolute, "JPE ", 10), INS(BIND(xchg), Implied, "XCHG", 4), INS(BIND(cpe), Absolute, "CPE ", 11), UNKNOWN(), INS(BIND(xri), Immediate, "XRI ", 7), INS(BIND(rst_5), Implied, "RST 5", 11), // E - /* F */ INS(BIND(rp), Implied, "RP", 5), INS(BIND(pop_psw), Implied, "POP PSW", 10), INS(BIND(jp), Absolute, "JP ", 10), INS(BIND(di), Implied, "DI ", 4), INS(BIND(cp), Absolute, "CP ", 11), INS(BIND(push_psw), Implied, "PUSH PSW", 11), INS(BIND(ori), Immediate, "ORI ", 7), INS(BIND(rst_6), Implied, "RST 6", 11), INS(BIND(rm), Implied, "RM", 11), INS(BIND(sphl), Implied, "SPHL", 5), INS(BIND(jm), Absolute, "JM ", 10), INS(BIND(ei), Implied, "EI", 4), INS(BIND(cm), Absolute, "CM ", 11), UNKNOWN(), INS(BIND(cpi), Immediate, "CPI ", 7), INS(BIND(rst_7), Implied, "RST 7", 11), // F - }; -} - void EightBit::Intel8080::initialise() { - Processor::initialise(); + IntelProcessor::initialise(); AF().word = BC().word = DE().word = HL().word = 0; } @@ -102,129 +57,76 @@ void EightBit::Intel8080::decrement(uint8_t& f, uint8_t& operand) { #pragma region PC manipulation: call/ret/jp/jr -void EightBit::Intel8080::jmp() { - jumpConditional(true); +bool EightBit::Intel8080::jumpConditionalFlag(uint8_t& f, int flag) { + switch (flag) { + case 0: // NZ + return jumpConditional(!(f & ZF)); + case 1: // Z + return jumpConditional(f & ZF); + case 2: // NC + return jumpConditional(!(f & CF)); + case 3: // C + return jumpConditional(f & CF); + case 4: // PO + return jumpConditional(!(f & PF)); + case 5: // PE + return jumpConditional(f & PF); + case 6: // P + return jumpConditional(!(f & SF)); + case 7: // M + return jumpConditional(f & SF); + default: + __assume(0); + } + throw std::logic_error("Unhandled JP conditional"); } -void EightBit::Intel8080::jc() { - jumpConditional(F() & CF); +bool EightBit::Intel8080::returnConditionalFlag(uint8_t& f, int flag) { + switch (flag) { + case 0: // NZ + return returnConditional(!(f & ZF)); + case 1: // Z + return returnConditional(f & ZF); + case 2: // NC + return returnConditional(!(f & CF)); + case 3: // C + return returnConditional(f & CF); + case 4: // PO + return returnConditional(!(f & PF)); + case 5: // PE + return returnConditional(f & PF); + case 6: // P + return returnConditional(!(f & SF)); + case 7: // M + return returnConditional(f & SF); + default: + __assume(0); + } + throw std::logic_error("Unhandled RET conditional"); } -void EightBit::Intel8080::jnc() { - jumpConditional(!(F() & CF)); -} - -void EightBit::Intel8080::jz() { - jumpConditional(F() & ZF); -} - -void EightBit::Intel8080::jnz() { - jumpConditional(!(F() & ZF)); -} - -void EightBit::Intel8080::jpe() { - jumpConditional(F() & PF); -} - -void EightBit::Intel8080::jpo() { - jumpConditional(!(F() & PF)); -} - -void EightBit::Intel8080::jm() { - jumpConditional(F() & SF); -} - -void EightBit::Intel8080::jp() { - jumpConditional(!(F() & SF)); -} - -void EightBit::Intel8080::pchl() { - PC() = HL(); -} - -void EightBit::Intel8080::rc() { - if (returnConditional(F() & CF)) - cycles += 6; -} - -void EightBit::Intel8080::rnc() { - if (returnConditional(!(F() & CF))) - cycles += 6; -} - -void EightBit::Intel8080::rz() { - if (returnConditional(F() & ZF)) - cycles += 6; -} - -void EightBit::Intel8080::rnz() { - if (returnConditional(!(F() & ZF))) - cycles += 6; -} - -void EightBit::Intel8080::rpe() { - if (returnConditional(F() & PF)) - cycles += 6; -} - -void EightBit::Intel8080::rpo() { - if (returnConditional(!(F() & PF))) - cycles += 6; -} - -void EightBit::Intel8080::rm() { - if (returnConditional(F() & SF)) - cycles += 6; -} - -void EightBit::Intel8080::rp() { - if (returnConditional(!(F() & SF))) - cycles += 6; -} - -void EightBit::Intel8080::callDirect() { - fetchWord(); - call(); -} - -void EightBit::Intel8080::cc() { - if (callConditional(F() & CF)) - cycles += 6; -} - -void EightBit::Intel8080::cnc() { - if (callConditional(!(F() & CF))) - cycles += 6; -} - -void EightBit::Intel8080::cpe() { - if (callConditional(F() & PF)) - cycles += 6; -} - -void EightBit::Intel8080::cpo() { - if (callConditional(!(F() & PF))) - cycles += 6; -} - -void EightBit::Intel8080::cz() { - if (callConditional(F() & ZF)) - cycles += 6; -} - -void EightBit::Intel8080::cnz() { - if (callConditional(!(F() & ZF))) - cycles += 6; -} - -void EightBit::Intel8080::cm() { - if (callConditional(F() & SF)) - cycles += 6; -} - -void EightBit::Intel8080::cp() { - if (callConditional(!(F() & SF))) - cycles += 6; +bool EightBit::Intel8080::callConditionalFlag(uint8_t& f, int flag) { + switch (flag) { + case 0: // NZ + return callConditional(!(f & ZF)); + case 1: // Z + return callConditional(f & ZF); + case 2: // NC + return callConditional(!(f & CF)); + case 3: // C + return callConditional(f & CF); + case 4: // PO + return callConditional(!(f & PF)); + case 5: // PE + return callConditional(f & PF); + case 6: // P + return callConditional(!(f & SF)); + case 7: // M + return callConditional(f & SF); + default: + __assume(0); + } + throw std::logic_error("Unhandled CALL conditional"); } #pragma endregion PC manipulation: call/ret/jp/jr @@ -353,7 +255,7 @@ void EightBit::Intel8080::daa() { } void EightBit::Intel8080::cma() { - A() ^= Mask8; + A() = ~A(); } void EightBit::Intel8080::stc() { @@ -391,25 +293,437 @@ void EightBit::Intel8080::in() { int EightBit::Intel8080::step() { ExecutingInstruction.fire(*this); + cycles = 0; return execute(fetchByte()); } int EightBit::Intel8080::execute(uint8_t opcode) { - const auto& instruction = instructions[opcode]; - return execute(instruction); + + const auto& decoded = getDecodedOpcode(opcode); + + auto x = decoded.x; + auto y = decoded.y; + auto z = decoded.z; + + auto p = decoded.p; + auto q = decoded.q; + + execute(x, y, z, p, q); + + if (cycles == 0) + throw std::logic_error("Unhandled opcode"); + + return cycles; } -int EightBit::Intel8080::execute(const Instruction& instruction) { - cycles = 0; - instruction.vector(); - return cycles + instruction.count; +void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) { + auto& a = A(); + auto& f = F(); + switch (x) { + case 0: + switch (z) { + case 0: // Relative jumps and assorted ops + switch (y) { + case 0: // NOP + cycles += 4; + break; + case 1: // EX AF AF' + break; + case 2: // DJNZ d + break; + case 3: // JR d + break; + case 4: // JR cc,d + case 5: + case 6: + case 7: + break; + default: + __assume(0); + } + break; + case 1: // 16-bit load immediate/add + switch (q) { + case 0: // LD rp,nn + fetchWord(RP(p)); + cycles += 10; + break; + case 1: // ADD HL,rp + dad(RP(p).word); + cycles += 11; + break; + } + break; + case 2: // Indirect loading + switch (q) { + case 0: + switch (p) { + case 0: // LD (BC),A + MEMPTR() = BC(); + MEMPTR().high = memptrReference() = a; + cycles += 7; + break; + case 1: // LD (DE),A + MEMPTR() = DE(); + MEMPTR().high = memptrReference() = a; + cycles += 7; + break; + case 2: // LD (nn),HL + fetchWord(); + setWordViaMemptr(HL()); + cycles += 16; + break; + case 3: // LD (nn),A + fetchWord(); + MEMPTR().high = memptrReference() = a; + cycles += 13; + break; + default: + __assume(0); + } + break; + case 1: + switch (p) { + case 0: // LD A,(BC) + MEMPTR() = BC(); + a = memptrReference(); + cycles += 7; + break; + case 1: // LD A,(DE) + MEMPTR() = DE(); + a = memptrReference(); + cycles += 7; + break; + case 2: // LD HL,(nn) + fetchWord(); + getWordViaMemptr(HL()); + cycles += 16; + break; + case 3: // LD A,(nn) + fetchWord(); + a = memptrReference(); + cycles += 13; + break; + default: + __assume(0); + } + break; + default: + __assume(0); + } + break; + case 3: // 16-bit INC/DEC + switch (q) { + case 0: // INC rp + ++RP(p).word; + break; + case 1: // DEC rp + --RP(p).word; + break; + default: + __assume(0); + } + cycles += 6; + break; + case 4: // 8-bit INC + increment(f, R(y)); // INC r + cycles += 4; + break; + case 5: // 8-bit DEC + decrement(f, R(y)); // DEC r + cycles += 4; + if (y == 6) + cycles += 7; + break; + case 6: { // 8-bit load immediate + auto& r = R(y); // LD r,n + r = fetchByte(); + cycles += 7; + if (y == 6) + cycles += 3; + break; + } + case 7: // Assorted operations on accumulator/flags + switch (y) { + case 0: + rlc(); + break; + case 1: + rrc(); + break; + case 2: + ral(); + break; + case 3: + rar(); + break; + case 4: + daa(); + break; + case 5: + cma(); + break; + case 6: + stc(); + break; + case 7: + cmc(); + break; + default: + __assume(0); + } + cycles += 4; + break; + default: + __assume(0); + } + break; + case 1: // 8-bit loading + if (z == 6 && y == 6) { // Exception (replaces LD (HL), (HL)) + halt(); + } else { + R(y) = R(z); + if ((y == 6) || (z == 6)) // M operations + cycles += 3; + } + cycles += 4; + break; + case 2: // Operate on accumulator and register/memory location + switch (y) { + case 0: // ADD A,r + add(R(z)); + break; + case 1: // ADC A,r + adc(R(z)); + break; + case 2: // SUB r + subtract(f, a, R(z)); + break; + case 3: // SBC A,r + sbb(R(z)); + break; + case 4: // AND r + anda(R(z)); + break; + case 5: // XOR r + xra(R(z)); + break; + case 6: // OR r + ora(R(z)); + break; + case 7: // CP r + compare(f, a, R(z)); + break; + default: + __assume(0); + } + cycles += 4; + if (z == 6) + cycles += 3; + break; + case 3: + switch (z) { + case 0: // Conditional return + if (returnConditionalFlag(f, y)) + cycles += 6; + cycles += 5; + break; + case 1: // POP & various ops + switch (q) { + case 0: // POP rp2[p] + popWord(RP2(p)); + adjustReservedFlags(); + cycles += 10; + break; + case 1: + switch (p) { + case 0: // RET + ret(); + cycles += 10; + break; + case 1: // EXX + break; + case 2: // JP HL + PC() = HL(); + cycles += 4; + break; + case 3: // LD SP,HL + SP() = HL(); + cycles += 4; + break; + default: + __assume(0); + } + break; + default: + __assume(0); + } + break; + case 2: // Conditional jump + jumpConditionalFlag(f, y); + cycles += 10; + break; + case 3: // Assorted operations + switch (y) { + case 0: // JP nn + fetchWord(); + jump(); + cycles += 10; + break; + case 1: // CB prefix + break; + case 2: // OUT (n),A + out(); + cycles += 11; + break; + case 3: // IN A,(n) + in(); + cycles += 11; + break; + case 4: // EX (SP),HL + xhtl(); + cycles += 19; + break; + case 5: // EX DE,HL + std::swap(DE(), HL()); + cycles += 4; + break; + case 6: // DI + di(); + cycles += 4; + break; + case 7: // EI + ei(); + cycles += 4; + break; + default: + __assume(0); + } + break; + case 4: // Conditional call: CALL cc[y], nn + if (callConditionalFlag(f, y)) + cycles += 7; + cycles += 10; + break; + case 5: // PUSH & various ops + switch (q) { + case 0: // PUSH rp2[p] + pushWord(RP2(p)); + cycles += 11; + break; + case 1: + switch (p) { + case 0: // CALL nn + fetchWord(); + call(); + cycles += 17; + break; + case 1: // DD prefix + break; + case 2: // ED prefix + break; + case 3: // FD prefix + break; + default: + __assume(0); + } + break; + default: + __assume(0); + } + break; + case 6: // Operate on accumulator and immediate operand: alu[y] n + switch (y) { + case 0: // ADD A,n + add(fetchByte()); + break; + case 1: // ADC A,n + adc(fetchByte()); + break; + case 2: // SUB n + subtract(f, a, fetchByte()); + break; + case 3: // SBC A,n + sbb(fetchByte()); + break; + case 4: // AND n + anda(fetchByte()); + break; + case 5: // XOR n + xra(fetchByte()); + break; + case 6: // OR n + ora(fetchByte()); + break; + case 7: // CP n + compare(f, a, fetchByte()); + break; + default: + __assume(0); + } + cycles += 7; + break; + case 7: // Restart: RST y * 8 + restart(y << 3); + cycles += 11; + break; + default: + __assume(0); + } + break; + } } // +EightBit::Intel8080::Instruction EightBit::Intel8080::INS(instruction_t method, AddressingMode mode, std::string disassembly, int cycles) { + Intel8080::Instruction returnValue; + returnValue.vector = method; + returnValue.mode = mode; + returnValue.disassembly = disassembly; + returnValue.count = cycles; + return returnValue; +} + +EightBit::Intel8080::Instruction EightBit::Intel8080::UNKNOWN() { + Intel8080::Instruction returnValue; + returnValue.vector = std::bind(&Intel8080::___, this); + returnValue.mode = Unknown; + returnValue.disassembly = ""; + returnValue.count = 0; + return returnValue; +} + +#define BIND(method) std::bind(&Intel8080:: method, this) + +void EightBit::Intel8080::installInstructions() { + instructions = { + //// 0 1 2 3 4 5 6 7 8 9 A B C D E F + /* 0 */ INS(BIND(nop), Implied, "NOP", 4), INS(BIND(nop), Absolute, "LXI B,", 10), INS(BIND(nop), Implied, "STAX B", 7), INS(BIND(nop), Implied, "INX B", 5), INS(BIND(nop), Implied, "INR B", 5), INS(BIND(nop), Implied, "DCR B", 5), INS(BIND(nop), Immediate, "MVI B,", 7), INS(BIND(nop), Implied, "RLC", 4), UNKNOWN(), INS(BIND(nop), Implied, "DAD B", 10), INS(BIND(nop), Implied, "LDAX B", 7), INS(BIND(nop), Implied, "DCX B", 5), INS(BIND(nop), Implied, "INR C", 5), INS(BIND(nop), Implied, "DCR C", 5), INS(BIND(nop), Immediate, "MVI C,", 7), INS(BIND(nop), Implied, "RRC", 4), // 0 + /* 1 */ UNKNOWN(), INS(BIND(nop), Absolute, "LXI D,", 10), INS(BIND(nop), Implied, "STAX D", 7), INS(BIND(nop), Implied, "INX D", 5), INS(BIND(nop), Implied, "INR D", 5), INS(BIND(nop), Implied, "DCR D", 5), INS(BIND(nop), Immediate, "MVI D,", 7), INS(BIND(nop), Implied, "RAL", 4), UNKNOWN(), INS(BIND(nop), Implied, "DAD D", 10), INS(BIND(nop), Implied, "LDAX D", 7), INS(BIND(nop), Implied, "DCX D", 5), INS(BIND(nop), Implied, "INR E", 5), INS(BIND(nop), Implied, "DCR E", 5), INS(BIND(nop), Immediate, "MVI E,", 7), INS(BIND(nop), Implied, "RAR", 4), // 1 + /* 2 */ UNKNOWN(), INS(BIND(nop), Absolute, "LXI H,", 10), INS(BIND(nop), Absolute, "SHLD", 16), INS(BIND(nop), Implied, "INX H", 5), INS(BIND(nop), Implied, "INR H", 5), INS(BIND(nop), Implied, "DCR H", 5), INS(BIND(nop), Immediate, "MVI H,",7), INS(BIND(nop), Implied, "DAA", 4), UNKNOWN(), INS(BIND(nop), Implied, "DAD H", 10), INS(BIND(nop), Absolute, "LHLD ", 16), INS(BIND(nop), Implied, "DCX H", 5), INS(BIND(nop), Implied, "INR L", 5), INS(BIND(nop), Implied, "DCR L", 5), INS(BIND(nop), Immediate, "MVI L,", 7), INS(BIND(nop), Implied, "CMA", 4), // 2 + /* 3 */ UNKNOWN(), INS(BIND(nop), Absolute, "LXI SP,", 10), INS(BIND(nop), Absolute, "STA ", 13), INS(BIND(nop), Implied, "INX SP", 5), INS(BIND(nop), Implied, "INR M", 10), INS(BIND(nop), Implied, "DCR M", 10), INS(BIND(nop), Immediate, "MVI M,", 10), INS(BIND(nop), Implied, "STC", 4), UNKNOWN(), INS(BIND(nop), Implied, "DAD SP", 10), INS(BIND(nop), Absolute, "LDA ", 13), INS(BIND(nop), Implied, "DCX SP", 5), INS(BIND(nop), Implied, "INR A", 5), INS(BIND(nop), Implied, "DCR A", 5), INS(BIND(nop), Immediate, "MVI A,", 7), INS(BIND(nop), Implied, "CMC", 4), // 3 + + /* 4 */ INS(BIND(nop), Implied, "MOV B,B", 5), INS(BIND(nop), Implied, "MOV B,C", 5), INS(BIND(nop), Implied, "MOV B,D", 5), INS(BIND(nop), Implied, "MOV B,E", 5), INS(BIND(nop), Implied, "MOV B,H", 5), INS(BIND(nop), Implied, "MOV B,L", 5), INS(BIND(nop), Implied, "MOV B,M", 7), INS(BIND(nop), Implied, "MOV B,A", 5), INS(BIND(nop), Implied, "MOV C,B", 5), INS(BIND(nop), Implied, "MOV C,C", 5), INS(BIND(nop), Implied, "MOV C,D", 5), INS(BIND(nop), Implied, "MOV C,E", 5), INS(BIND(nop), Implied, "MOV C,H", 5), INS(BIND(nop), Implied, "MOV C,L", 5), INS(BIND(nop), Implied, "MOV C,M", 7), INS(BIND(nop), Implied, "MOV C,A", 5), // 4 + /* 5 */ INS(BIND(nop), Implied, "MOV D,B", 5), INS(BIND(nop), Implied, "MOV D,C", 5), INS(BIND(nop), Implied, "MOV D,D", 5), INS(BIND(nop), Implied, "MOV D,E", 5), INS(BIND(nop), Implied, "MOV D,H", 5), INS(BIND(nop), Implied, "MOV D,L", 5), INS(BIND(nop), Implied, "MOV D,M", 7), INS(BIND(nop), Implied, "MOV D,A", 5), INS(BIND(nop), Implied, "MOV E,B", 5), INS(BIND(nop), Implied, "MOV E,C", 5), INS(BIND(nop), Implied, "MOV E,D", 5), INS(BIND(nop), Implied, "MOV E,E", 5), INS(BIND(nop), Implied, "MOV E,H", 5), INS(BIND(nop), Implied, "MOV E,L", 5), INS(BIND(nop), Implied, "MOV E,M", 7), INS(BIND(nop), Implied, "MOV E,A", 5), // 5 + /* 6 */ INS(BIND(nop), Implied, "MOV H,B", 5), INS(BIND(nop), Implied, "MOV H,C", 5), INS(BIND(nop), Implied, "MOV H,D", 5), INS(BIND(nop), Implied, "MOV H,E", 5), INS(BIND(nop), Implied, "MOV H,H", 5), INS(BIND(nop), Implied, "MOV H,L", 5), INS(BIND(nop), Implied, "MOV H,M", 7), INS(BIND(nop), Implied, "MOV H,A", 5), INS(BIND(nop), Implied, "MOV L,B", 5), INS(BIND(nop), Implied, "MOV L,C", 5), INS(BIND(nop), Implied, "MOV L,D", 5), INS(BIND(nop), Implied, "MOV L,E", 5), INS(BIND(nop), Implied, "MOV L,H", 5), INS(BIND(nop), Implied, "MOV L,L", 5), INS(BIND(nop), Implied, "MOV L,M", 7), INS(BIND(nop), Implied, "MOV L,A", 5), // 6 + /* 7 */ INS(BIND(nop), Implied, "MOV M,B", 7), INS(BIND(nop), Implied, "MOV M,C", 7), INS(BIND(nop), Implied, "MOV M,D", 7), INS(BIND(nop), Implied, "MOV M,E", 7), INS(BIND(nop), Implied, "MOV M,H", 7), INS(BIND(nop), Implied, "MOV M,L", 7), INS(BIND(nop), Implied, "HLT", 7), INS(BIND(nop), Implied, "MOV M,A", 7), INS(BIND(nop), Implied, "MOV A,B", 5), INS(BIND(nop), Implied, "MOV A,C", 5), INS(BIND(nop), Implied, "MOV A,D", 5), INS(BIND(nop), Implied, "MOV A,E", 5), INS(BIND(nop), Implied, "MOV A,H", 5), INS(BIND(nop), Implied, "MOV A,L", 5), INS(BIND(nop), Implied, "MOV A,M", 7), INS(BIND(nop), Implied, "MOV A,A", 5), // 7 + + /* 8 */ INS(BIND(nop), Implied, "ADD B", 4), INS(BIND(nop), Implied, "ADD C", 4), INS(BIND(nop), Implied, "ADD D", 4), INS(BIND(nop), Implied, "ADD E", 4), INS(BIND(nop), Implied, "ADD H", 4), INS(BIND(nop), Implied, "ADD L", 4), INS(BIND(nop), Implied, "ADD M", 7), INS(BIND(nop), Implied, "ADD A", 4), INS(BIND(nop), Implied, "ADC B", 4), INS(BIND(nop), Implied, "ADC C", 4), INS(BIND(nop), Implied, "ADC D", 4), INS(BIND(nop), Implied, "ADC E", 4), INS(BIND(nop), Implied, "ADC H", 4), INS(BIND(nop), Implied, "ADC L", 4), INS(BIND(nop), Implied, "ADC M", 4), INS(BIND(nop), Implied, "ADC A", 4), // 8 + /* 9 */ INS(BIND(nop), Implied, "SUB B", 4), INS(BIND(nop), Implied, "SUB C", 4), INS(BIND(nop), Implied, "SUB D", 4), INS(BIND(nop), Implied, "SUB E", 4), INS(BIND(nop), Implied, "SUB H", 4), INS(BIND(nop), Implied, "SUB L", 4), INS(BIND(nop), Implied, "SUB M", 7), INS(BIND(nop), Implied, "SUB A", 4), INS(BIND(nop), Implied, "SBB B", 4), INS(BIND(nop), Implied, "SBB C", 4), INS(BIND(nop), Implied, "SBB D", 4), INS(BIND(nop), Implied, "SBB E", 4), INS(BIND(nop), Implied, "SBB H", 4), INS(BIND(nop), Implied, "SBB L", 4), INS(BIND(nop), Implied, "SBB M", 4), INS(BIND(nop), Implied, "SBB A", 4), // 9 + /* A */ INS(BIND(nop), Implied, "ANA B", 4), INS(BIND(nop), Implied, "ANA C", 4), INS(BIND(nop), Implied, "ANA D", 4), INS(BIND(nop), Implied, "ANA E", 4), INS(BIND(nop), Implied, "ANA H", 4), INS(BIND(nop), Implied, "ANA L", 4), INS(BIND(nop), Implied, "ANA M", 7), INS(BIND(nop), Implied, "ANA A", 4), INS(BIND(nop), Implied, "XRA B", 4), INS(BIND(nop), Implied, "XRA C", 4), INS(BIND(nop), Implied, "XRA D", 4), INS(BIND(nop), Implied, "XRA E", 4), INS(BIND(nop), Implied, "XRA H", 4), INS(BIND(nop), Implied, "XRA L", 4), INS(BIND(nop), Implied, "XRA M", 4), INS(BIND(nop), Implied, "XRA A", 4), // A + /* B */ INS(BIND(nop), Implied, "ORA B", 4), INS(BIND(nop), Implied, "ORA C", 4), INS(BIND(nop), Implied, "ORA D", 4), INS(BIND(nop), Implied, "ORA E", 4), INS(BIND(nop), Implied, "ORA H", 4), INS(BIND(nop), Implied, "ORA L", 4), INS(BIND(nop), Implied, "ORA M", 7), INS(BIND(nop), Implied, "ORA A", 4), INS(BIND(nop), Implied, "CMP B", 4), INS(BIND(nop), Implied, "CMP C", 4), INS(BIND(nop), Implied, "CMP D", 4), INS(BIND(nop), Implied, "CMP E", 4), INS(BIND(nop), Implied, "CMP H", 4), INS(BIND(nop), Implied, "CMP L", 4), INS(BIND(nop), Implied, "CMP M", 4), INS(BIND(nop), Implied, "CMP A", 4), // B + + /* C */ INS(BIND(nop), Implied, "RNZ", 5), INS(BIND(nop), Implied, "POP B", 10), INS(BIND(nop), Absolute, "JNZ ", 10), INS(BIND(nop), Absolute, "JMP ", 10), INS(BIND(nop), Absolute, "CNZ ", 11), INS(BIND(nop), Implied, "PUSH B", 11), INS(BIND(nop), Immediate, "ADI ", 7), INS(BIND(nop), Implied, "RST 0", 11), INS(BIND(nop), Implied, "RZ", 11), INS(BIND(nop), Implied, "RET", 10), INS(BIND(nop), Absolute, "JZ ", 10), UNKNOWN(), INS(BIND(nop), Absolute, "CZ ", 11), INS(BIND(nop), Absolute, "CALL ", 17), INS(BIND(nop), Immediate, "ACI ", 7), INS(BIND(nop), Implied, "RST 1", 11), // C + /* D */ INS(BIND(nop), Implied, "RNC", 5), INS(BIND(nop), Implied, "POP D", 10), INS(BIND(nop), Absolute, "JNC ", 10), INS(BIND(nop), Immediate, "OUT ", 10), INS(BIND(nop), Absolute, "CNC ", 11), INS(BIND(nop), Implied, "PUSH D", 11), INS(BIND(nop), Immediate, "SUI ", 7), INS(BIND(nop), Implied, "RST 2", 11), INS(BIND(nop), Implied, "RC", 11), UNKNOWN(), INS(BIND(nop), Absolute, "JC ", 10), INS(BIND(nop), Immediate, "IN ", 10), INS(BIND(nop), Absolute, "CC ", 11), UNKNOWN(), INS(BIND(nop), Immediate, "SBI ", 7), INS(BIND(nop), Implied, "RST 3", 11), // D + /* E */ INS(BIND(nop), Implied, "RPO", 5), INS(BIND(nop), Implied, "POP H", 10), INS(BIND(nop), Absolute, "JPO ", 10), INS(BIND(nop), Implied, "XHTL", 18), INS(BIND(nop), Absolute, "CPO ", 11), INS(BIND(nop), Implied, "PUSH H", 11), INS(BIND(nop), Immediate, "ANI ", 7), INS(BIND(nop), Implied, "RST 4", 11), INS(BIND(nop), Implied, "RPE", 11), INS(BIND(nop), Implied, "PCHL", 5), INS(BIND(nop), Absolute, "JPE ", 10), INS(BIND(nop), Implied, "XCHG", 4), INS(BIND(nop), Absolute, "CPE ", 11), UNKNOWN(), INS(BIND(nop), Immediate, "XRI ", 7), INS(BIND(nop), Implied, "RST 5", 11), // E + /* F */ INS(BIND(nop), Implied, "RP", 5), INS(BIND(nop), Implied, "POP PSW", 10), INS(BIND(nop), Absolute, "JP ", 10), INS(BIND(nop), Implied, "DI ", 4), INS(BIND(nop), Absolute, "CP ", 11), INS(BIND(nop), Implied, "PUSH PSW", 11), INS(BIND(nop), Immediate, "ORI ", 7), INS(BIND(nop), Implied, "RST 6", 11), INS(BIND(nop), Implied, "RM", 11), INS(BIND(nop), Implied, "SPHL", 5), INS(BIND(nop), Absolute, "JM ", 10), INS(BIND(nop), Implied, "EI", 4), INS(BIND(nop), Absolute, "CM ", 11), UNKNOWN(), INS(BIND(nop), Immediate, "CPI ", 7), INS(BIND(nop), Implied, "RST 7", 11), // F + }; +} + void EightBit::Intel8080::___() { m_memory.ADDRESS().word = PC().word - 1; auto opcode = m_memory.reference(); auto message = Disassembler::invalid(opcode); throw std::domain_error(message); -} +} \ No newline at end of file From dfc02c7e542bbf072193d7018ab8410a7576b34d Mon Sep 17 00:00:00 2001 From: "Adrian.Conlon" Date: Mon, 24 Jul 2017 22:02:55 +0100 Subject: [PATCH 04/10] Remove pointless comment. Signed-off-by: Adrian.Conlon --- Z80/inc/Z80.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Z80/inc/Z80.h b/Z80/inc/Z80.h index 8147247..c104f49 100644 --- a/Z80/inc/Z80.h +++ b/Z80/inc/Z80.h @@ -57,8 +57,6 @@ namespace EightBit { int execute(uint8_t opcode); int step(); - // Mutable access to processor!! - virtual register16_t& AF() override { return m_accumulatorFlags[m_accumulatorFlagsSet]; } From 2ae4e8331e15850cc86a6dbf7ae40612c55770e8 Mon Sep 17 00:00:00 2001 From: "Adrian.Conlon" Date: Tue, 25 Jul 2017 14:12:34 +0100 Subject: [PATCH 05/10] Replace old i8080 disassembler with new (z80) style. Signed-off-by: Adrian.Conlon --- Intel8080/inc/Disassembler.h | 25 +- Intel8080/inc/Intel8080.h | 31 --- Intel8080/src/Disassembler.cpp | 421 +++++++++++++++++++++++++++++--- Intel8080/src/Intel8080.cpp | 55 ----- Intel8080/src/Intel8080.vcxproj | 8 +- Intel8080/src/stdafx.h | 2 + Intel8080/test/Board.cpp | 3 +- Intel8080/test/Board.h | 4 +- 8 files changed, 419 insertions(+), 130 deletions(-) diff --git a/Intel8080/inc/Disassembler.h b/Intel8080/inc/Disassembler.h index b3d4699..c9d4e9e 100644 --- a/Intel8080/inc/Disassembler.h +++ b/Intel8080/inc/Disassembler.h @@ -1,8 +1,10 @@ #pragma once #include +#include namespace EightBit { + class Intel8080; class Disassembler { @@ -10,7 +12,7 @@ namespace EightBit { Disassembler(); static std::string state(Intel8080& cpu); - static std::string disassemble(Intel8080& cpu); + std::string disassemble(Intel8080& cpu); static std::string flag(uint8_t value, int flag, const std::string& represents); static std::string flags(uint8_t value); @@ -19,5 +21,26 @@ namespace EightBit { static std::string binary(uint8_t value); static std::string invalid(uint8_t value); + + private: + mutable boost::format m_formatter; + + void disassemble(std::ostringstream& output, const Intel8080& cpu, uint16_t pc); + + void disassemble( + std::ostringstream& output, + const Intel8080& cpu, + uint16_t pc, + std::string& specification, + int& dumpCount, + int x, int y, int z, + int p, int q); + + std::string RP(int rp) const; + std::string RP2(int rp) const; + std::string R(int r) const; + static std::string cc(int flag); + static std::string alu(int which); + static std::string alu2(int which); }; } \ No newline at end of file diff --git a/Intel8080/inc/Intel8080.h b/Intel8080/inc/Intel8080.h index bb92a26..78b1138 100644 --- a/Intel8080/inc/Intel8080.h +++ b/Intel8080/inc/Intel8080.h @@ -18,26 +18,10 @@ namespace EightBit { CF = Bit0, }; - enum AddressingMode { - Unknown, - Implied, // zero bytes - Immediate, // single byte - Absolute // two bytes, little endian - }; - - struct Instruction { - instruction_t vector = nullptr; - AddressingMode mode = Unknown; - std::string disassembly; - int count = 0; - }; - Intel8080(Memory& memory, InputOutput& ports); Signal ExecutingInstruction; - const std::array& getInstructions() const { return instructions; } - bool isInterruptable() const; int interrupt(uint8_t value); @@ -65,8 +49,6 @@ namespace EightBit { private: InputOutput& m_ports; - std::array instructions; - register16_t af; register16_t bc; register16_t de; @@ -183,23 +165,10 @@ namespace EightBit { void xhtl(); - // input/output - void out(); void in(); - // control - void ei(); void di(); - - // - - void ___(); - void nop() {} - - static Instruction INS(instruction_t method, AddressingMode mode, std::string disassembly, int cycles); - Instruction UNKNOWN(); - void installInstructions(); }; } \ No newline at end of file diff --git a/Intel8080/src/Disassembler.cpp b/Intel8080/src/Disassembler.cpp index af04489..78a6ffa 100644 --- a/Intel8080/src/Disassembler.cpp +++ b/Intel8080/src/Disassembler.cpp @@ -9,6 +9,8 @@ #include "Intel8080.h" EightBit::Disassembler::Disassembler() { + // Disable exceptions where too many format arguments are available + m_formatter.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit); } std::string EightBit::Disassembler::state(Intel8080& cpu) { @@ -42,48 +44,397 @@ std::string EightBit::Disassembler::state(Intel8080& cpu) { return output.str(); } +std::string EightBit::Disassembler::RP(int rp) const { + switch (rp) { + case 0: + return "B"; + case 1: + return "D"; + case 2: + return "H"; + case 3: + return "SP"; + } + throw std::logic_error("Unhandled register pair"); +} + +std::string EightBit::Disassembler::RP2(int rp) const { + switch (rp) { + case 0: + return "B"; + case 1: + return "D"; + case 2: + return "H"; + case 3: + return "PSW"; + } + throw std::logic_error("Unhandled register pair"); +} + +std::string EightBit::Disassembler::R(int r) const { + switch (r) { + case 0: + return "B"; + case 1: + return "C"; + case 2: + return "D"; + case 3: + return "E"; + case 4: + return "H"; + case 5: + return "L"; + case 6: + return "M"; + case 7: + return "A"; + } + throw std::logic_error("Unhandled register"); +} + +std::string EightBit::Disassembler::cc(int flag) { + switch (flag) { + case 0: + return "NZ"; + case 1: + return "Z"; + case 2: + return "NC"; + case 3: + return "C"; + case 4: + return "PO"; + case 5: + return "PE"; + case 6: + return "P"; + case 7: + return "M"; + } + throw std::logic_error("Unhandled condition"); +} + +std::string EightBit::Disassembler::alu(int which) { + switch (which) { + case 0: // ADD A,n + return "ADD"; + case 1: // ADC + return "ADC"; + case 2: // SUB n + return "SUB"; + case 3: // SBC A,n + return "SBB"; + case 4: // AND n + return "ANA"; + case 5: // XOR n + return "XRA"; + case 6: // OR n + return "ORA"; + case 7: // CP n + return "CMP"; + } + throw std::logic_error("Unhandled alu operation"); +} + +std::string EightBit::Disassembler::alu2(int which) { + switch (which) { + case 0: // ADD A,n + return "ADI"; + case 1: // ADC + return "ACI"; + case 2: // SUB n + return "SUI"; + case 3: // SBC A,n + return "SBI"; + case 4: // AND n + return "ANI"; + case 5: // XOR n + return "XRI"; + case 6: // OR n + return "ORI"; + case 7: // CP n + return "CPI"; + } + throw std::logic_error("Unhandled alu operation"); +} + std::string EightBit::Disassembler::disassemble(Intel8080& cpu) { + std::ostringstream output; + disassemble(output, cpu, cpu.PC().word); + return output.str(); +} + +void EightBit::Disassembler::disassemble(std::ostringstream& output, const Intel8080& cpu, uint16_t pc) { const auto& memory = cpu.getMemory(); - auto pc = cpu.PC(); - auto opcode = memory.peek(pc.word); - const auto& instruction = cpu.getInstructions()[opcode]; + auto opcode = memory.peek(pc); - std::ostringstream output; - - // hex opcode output << hex(opcode); - // hex raw operand - switch (instruction.mode) { - case Intel8080::Immediate: - output << hex(memory.peek(pc.word + 1)); + auto x = (opcode & 0b11000000) >> 6; + auto y = (opcode & 0b111000) >> 3; + auto z = (opcode & 0b111); + + auto p = (y & 0b110) >> 1; + auto q = (y & 1); + + auto immediate = memory.peek(pc + 1); + auto absolute = memory.peekWord(pc + 1); + auto displacement = (int8_t)immediate; + auto relative = pc + displacement + 2; + auto indexedImmediate = memory.peek(pc + 1); + + auto dumpCount = 0; + + std::string specification = ""; + + disassemble( + output, cpu, pc, + specification, dumpCount, + x, y, z, p, q); + + for (int i = 0; i < dumpCount; ++i) + output << hex(memory.peek(pc + i + 1)); + + output << '\t'; + m_formatter.parse(specification); + output << m_formatter % (int)immediate % (int)absolute % relative % (int)displacement % indexedImmediate; +} + +void EightBit::Disassembler::disassemble( + std::ostringstream& output, + const Intel8080& cpu, + uint16_t pc, + std::string& specification, + int& dumpCount, + int x, int y, int z, + int p, int q) { + + switch (x) { + case 0: + switch (z) { + case 0: // Relative jumps and assorted ops + switch (y) { + case 0: // NOP + specification = "NOP"; + break; + case 1: // EX AF AF' + break; + case 2: // DJNZ d + break; + case 3: // JR d + break; + default: // JR cc,d + break; + } + break; + case 1: // 16-bit load immediate/add + switch (q) { + case 0: // LD rp,nn + specification = "LXI " + RP(p) + ",%2$04XH"; + dumpCount += 2; + break; + case 1: // ADD HL,rp + specification = "DAD " + RP(p); + break; + } + break; + case 2: // Indirect loading + switch (q) { + case 0: + switch (p) { + case 0: // LD (BC),A + specification = "STAX B"; + break; + case 1: // LD (DE),A + specification = "STAX D"; + break; + case 2: // LD (nn),HL + specification = "SHLD %2$04XH"; + dumpCount += 2; + break; + case 3: // LD (nn),A + specification = "STA %2$04XH"; + dumpCount += 2; + break; + } + break; + case 1: + switch (p) { + case 0: // LD A,(BC) + specification = "LDAX B"; + break; + case 1: // LD A,(DE) + specification = "LDAX D"; + break; + case 2: // LD HL,(nn) + specification = "LHLD %2$04XH"; + dumpCount += 2; + break; + case 3: // LD A,(nn) + specification = "LDA %2$04XH"; + dumpCount += 2; + break; + } + break; + } + break; + case 3: // 16-bit INC/DEC + switch (q) { + case 0: // INC rp + specification = "INX " + RP(p); + break; + case 1: // DEC rp + specification = "DCX " + RP(p); + break; + } + break; + case 4: // 8-bit INC + specification = "INR " + R(y); + break; + case 5: // 8-bit DEC + specification = "DCR " + R(y); + break; + case 6: // 8-bit load immediate + specification = "MVI " + R(y) + ",%1$02XH"; + dumpCount++; + break; + case 7: // Assorted operations on accumulator/flags + switch (y) { + case 0: + specification = "RLC"; + break; + case 1: + specification = "RRC"; + break; + case 2: + specification = "RAL"; + break; + case 3: + specification = "RAR"; + break; + case 4: + specification = "DAA"; + break; + case 5: + specification = "CMA"; + break; + case 6: + specification = "STC"; + break; + case 7: + specification = "CMC"; + break; + } + break; + } break; - case Intel8080::Absolute: - output << hex(memory.peek(pc.word + 1)); - output << hex(memory.peek(pc.word + 2)); + case 1: // 8-bit loading + if (z == 6 && y == 6) { // Exception (replaces LD (HL), (HL)) + specification = "HLT"; + } else { + specification = "MOV " + R(y) + "," + R(z); + } break; - default: + case 2: // Operate on accumulator and register/memory location + specification = alu(y) + " A," + R(z); + break; + case 3: + switch (z) { + case 0: // Conditional return + specification = "R" + cc(y); + break; + case 1: // POP & various ops + switch (q) { + case 0: // POP rp2[p] + specification = "POP " + RP2(p); + break; + case 1: + switch (p) { + case 0: // RET + specification = "RET"; + break; + case 1: // EXX + break; + case 2: // JP HL + specification = "PCHL"; + break; + case 3: // LD SP,HL + specification = "SPHL"; + break; + } + } + break; + case 2: // Conditional jump + specification = "J" + cc(y) + " %2$04XH"; + dumpCount += 2; + break; + case 3: // Assorted operations + switch (y) { + case 0: // JP nn + specification = "JMP %2$04XH"; + dumpCount += 2; + break; + case 1: // CB prefix + break; + case 2: // OUT (n),A + specification = "OUT %1$02XH"; + dumpCount++; + break; + case 3: // IN A,(n) + specification = "IN %1$02XH"; + dumpCount++; + break; + case 4: // EX (SP),HL + specification = "XHTL"; + break; + case 5: // EX DE,HL + specification = "XCHG"; + break; + case 6: // DI + specification = "DI"; + break; + case 7: // EI + specification = "EI"; + break; + } + break; + case 4: // Conditional call: CALL cc[y], nn + specification = "C" + cc(y) + " %2$04XH"; + dumpCount += 2; + break; + case 5: // PUSH & various ops + switch (q) { + case 0: // PUSH rp2[p] + specification = "PUSH " + RP2(p); + break; + case 1: + switch (p) { + case 0: // CALL nn + specification = "CALL %2$04XH"; + dumpCount += 2; + break; + case 1: // DD prefix + break; + case 2: // ED prefix + break; + case 3: // FD prefix + break; + } + } + break; + case 6: // Operate on accumulator and immediate operand: alu[y] n + specification = alu2(y) + " %1$02XH"; + dumpCount++; + break; + case 7: // Restart: RST y * 8 + specification = "RST " + hex((uint8_t)y); + break; + } break; } - output << "\t"; - - // base disassembly - output << instruction.disassembly; - - // disassembly operand - switch (instruction.mode) { - case Intel8080::Immediate: - output << hex(memory.peek(pc.word + 1)); - break; - case Intel8080::Absolute: - output << hex(memory.peekWord(pc.word + 1)); - break; - default: - break; - } - - return output.str(); } std::string EightBit::Disassembler::flag(uint8_t value, int flag, const std::string& represents) { @@ -97,11 +448,11 @@ std::string EightBit::Disassembler::flags(uint8_t value) { output << flag(value, Intel8080::SF, "S") << flag(value, Intel8080::ZF, "Z") - << "0" + << flag(value, Processor::Bit5, "5") << flag(value, Intel8080::AC, "A") - << "0" + << flag(value, Processor::Bit3, "3") << flag(value, Intel8080::PF, "P") - << "1" + << flag(value, Processor::Bit1, "1") << flag(value, Intel8080::CF, "C"); return output.str(); } diff --git a/Intel8080/src/Intel8080.cpp b/Intel8080/src/Intel8080.cpp index f1aa668..9c29a39 100644 --- a/Intel8080/src/Intel8080.cpp +++ b/Intel8080/src/Intel8080.cpp @@ -9,7 +9,6 @@ EightBit::Intel8080::Intel8080(Memory& memory, InputOutput& ports) m_interrupt(false), m_ports(ports) { bc.word = de.word = hl.word = 0; - installInstructions(); } void EightBit::Intel8080::initialise() { @@ -673,57 +672,3 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) { break; } } - -// - -EightBit::Intel8080::Instruction EightBit::Intel8080::INS(instruction_t method, AddressingMode mode, std::string disassembly, int cycles) { - Intel8080::Instruction returnValue; - returnValue.vector = method; - returnValue.mode = mode; - returnValue.disassembly = disassembly; - returnValue.count = cycles; - return returnValue; -} - -EightBit::Intel8080::Instruction EightBit::Intel8080::UNKNOWN() { - Intel8080::Instruction returnValue; - returnValue.vector = std::bind(&Intel8080::___, this); - returnValue.mode = Unknown; - returnValue.disassembly = ""; - returnValue.count = 0; - return returnValue; -} - -#define BIND(method) std::bind(&Intel8080:: method, this) - -void EightBit::Intel8080::installInstructions() { - instructions = { - //// 0 1 2 3 4 5 6 7 8 9 A B C D E F - /* 0 */ INS(BIND(nop), Implied, "NOP", 4), INS(BIND(nop), Absolute, "LXI B,", 10), INS(BIND(nop), Implied, "STAX B", 7), INS(BIND(nop), Implied, "INX B", 5), INS(BIND(nop), Implied, "INR B", 5), INS(BIND(nop), Implied, "DCR B", 5), INS(BIND(nop), Immediate, "MVI B,", 7), INS(BIND(nop), Implied, "RLC", 4), UNKNOWN(), INS(BIND(nop), Implied, "DAD B", 10), INS(BIND(nop), Implied, "LDAX B", 7), INS(BIND(nop), Implied, "DCX B", 5), INS(BIND(nop), Implied, "INR C", 5), INS(BIND(nop), Implied, "DCR C", 5), INS(BIND(nop), Immediate, "MVI C,", 7), INS(BIND(nop), Implied, "RRC", 4), // 0 - /* 1 */ UNKNOWN(), INS(BIND(nop), Absolute, "LXI D,", 10), INS(BIND(nop), Implied, "STAX D", 7), INS(BIND(nop), Implied, "INX D", 5), INS(BIND(nop), Implied, "INR D", 5), INS(BIND(nop), Implied, "DCR D", 5), INS(BIND(nop), Immediate, "MVI D,", 7), INS(BIND(nop), Implied, "RAL", 4), UNKNOWN(), INS(BIND(nop), Implied, "DAD D", 10), INS(BIND(nop), Implied, "LDAX D", 7), INS(BIND(nop), Implied, "DCX D", 5), INS(BIND(nop), Implied, "INR E", 5), INS(BIND(nop), Implied, "DCR E", 5), INS(BIND(nop), Immediate, "MVI E,", 7), INS(BIND(nop), Implied, "RAR", 4), // 1 - /* 2 */ UNKNOWN(), INS(BIND(nop), Absolute, "LXI H,", 10), INS(BIND(nop), Absolute, "SHLD", 16), INS(BIND(nop), Implied, "INX H", 5), INS(BIND(nop), Implied, "INR H", 5), INS(BIND(nop), Implied, "DCR H", 5), INS(BIND(nop), Immediate, "MVI H,",7), INS(BIND(nop), Implied, "DAA", 4), UNKNOWN(), INS(BIND(nop), Implied, "DAD H", 10), INS(BIND(nop), Absolute, "LHLD ", 16), INS(BIND(nop), Implied, "DCX H", 5), INS(BIND(nop), Implied, "INR L", 5), INS(BIND(nop), Implied, "DCR L", 5), INS(BIND(nop), Immediate, "MVI L,", 7), INS(BIND(nop), Implied, "CMA", 4), // 2 - /* 3 */ UNKNOWN(), INS(BIND(nop), Absolute, "LXI SP,", 10), INS(BIND(nop), Absolute, "STA ", 13), INS(BIND(nop), Implied, "INX SP", 5), INS(BIND(nop), Implied, "INR M", 10), INS(BIND(nop), Implied, "DCR M", 10), INS(BIND(nop), Immediate, "MVI M,", 10), INS(BIND(nop), Implied, "STC", 4), UNKNOWN(), INS(BIND(nop), Implied, "DAD SP", 10), INS(BIND(nop), Absolute, "LDA ", 13), INS(BIND(nop), Implied, "DCX SP", 5), INS(BIND(nop), Implied, "INR A", 5), INS(BIND(nop), Implied, "DCR A", 5), INS(BIND(nop), Immediate, "MVI A,", 7), INS(BIND(nop), Implied, "CMC", 4), // 3 - - /* 4 */ INS(BIND(nop), Implied, "MOV B,B", 5), INS(BIND(nop), Implied, "MOV B,C", 5), INS(BIND(nop), Implied, "MOV B,D", 5), INS(BIND(nop), Implied, "MOV B,E", 5), INS(BIND(nop), Implied, "MOV B,H", 5), INS(BIND(nop), Implied, "MOV B,L", 5), INS(BIND(nop), Implied, "MOV B,M", 7), INS(BIND(nop), Implied, "MOV B,A", 5), INS(BIND(nop), Implied, "MOV C,B", 5), INS(BIND(nop), Implied, "MOV C,C", 5), INS(BIND(nop), Implied, "MOV C,D", 5), INS(BIND(nop), Implied, "MOV C,E", 5), INS(BIND(nop), Implied, "MOV C,H", 5), INS(BIND(nop), Implied, "MOV C,L", 5), INS(BIND(nop), Implied, "MOV C,M", 7), INS(BIND(nop), Implied, "MOV C,A", 5), // 4 - /* 5 */ INS(BIND(nop), Implied, "MOV D,B", 5), INS(BIND(nop), Implied, "MOV D,C", 5), INS(BIND(nop), Implied, "MOV D,D", 5), INS(BIND(nop), Implied, "MOV D,E", 5), INS(BIND(nop), Implied, "MOV D,H", 5), INS(BIND(nop), Implied, "MOV D,L", 5), INS(BIND(nop), Implied, "MOV D,M", 7), INS(BIND(nop), Implied, "MOV D,A", 5), INS(BIND(nop), Implied, "MOV E,B", 5), INS(BIND(nop), Implied, "MOV E,C", 5), INS(BIND(nop), Implied, "MOV E,D", 5), INS(BIND(nop), Implied, "MOV E,E", 5), INS(BIND(nop), Implied, "MOV E,H", 5), INS(BIND(nop), Implied, "MOV E,L", 5), INS(BIND(nop), Implied, "MOV E,M", 7), INS(BIND(nop), Implied, "MOV E,A", 5), // 5 - /* 6 */ INS(BIND(nop), Implied, "MOV H,B", 5), INS(BIND(nop), Implied, "MOV H,C", 5), INS(BIND(nop), Implied, "MOV H,D", 5), INS(BIND(nop), Implied, "MOV H,E", 5), INS(BIND(nop), Implied, "MOV H,H", 5), INS(BIND(nop), Implied, "MOV H,L", 5), INS(BIND(nop), Implied, "MOV H,M", 7), INS(BIND(nop), Implied, "MOV H,A", 5), INS(BIND(nop), Implied, "MOV L,B", 5), INS(BIND(nop), Implied, "MOV L,C", 5), INS(BIND(nop), Implied, "MOV L,D", 5), INS(BIND(nop), Implied, "MOV L,E", 5), INS(BIND(nop), Implied, "MOV L,H", 5), INS(BIND(nop), Implied, "MOV L,L", 5), INS(BIND(nop), Implied, "MOV L,M", 7), INS(BIND(nop), Implied, "MOV L,A", 5), // 6 - /* 7 */ INS(BIND(nop), Implied, "MOV M,B", 7), INS(BIND(nop), Implied, "MOV M,C", 7), INS(BIND(nop), Implied, "MOV M,D", 7), INS(BIND(nop), Implied, "MOV M,E", 7), INS(BIND(nop), Implied, "MOV M,H", 7), INS(BIND(nop), Implied, "MOV M,L", 7), INS(BIND(nop), Implied, "HLT", 7), INS(BIND(nop), Implied, "MOV M,A", 7), INS(BIND(nop), Implied, "MOV A,B", 5), INS(BIND(nop), Implied, "MOV A,C", 5), INS(BIND(nop), Implied, "MOV A,D", 5), INS(BIND(nop), Implied, "MOV A,E", 5), INS(BIND(nop), Implied, "MOV A,H", 5), INS(BIND(nop), Implied, "MOV A,L", 5), INS(BIND(nop), Implied, "MOV A,M", 7), INS(BIND(nop), Implied, "MOV A,A", 5), // 7 - - /* 8 */ INS(BIND(nop), Implied, "ADD B", 4), INS(BIND(nop), Implied, "ADD C", 4), INS(BIND(nop), Implied, "ADD D", 4), INS(BIND(nop), Implied, "ADD E", 4), INS(BIND(nop), Implied, "ADD H", 4), INS(BIND(nop), Implied, "ADD L", 4), INS(BIND(nop), Implied, "ADD M", 7), INS(BIND(nop), Implied, "ADD A", 4), INS(BIND(nop), Implied, "ADC B", 4), INS(BIND(nop), Implied, "ADC C", 4), INS(BIND(nop), Implied, "ADC D", 4), INS(BIND(nop), Implied, "ADC E", 4), INS(BIND(nop), Implied, "ADC H", 4), INS(BIND(nop), Implied, "ADC L", 4), INS(BIND(nop), Implied, "ADC M", 4), INS(BIND(nop), Implied, "ADC A", 4), // 8 - /* 9 */ INS(BIND(nop), Implied, "SUB B", 4), INS(BIND(nop), Implied, "SUB C", 4), INS(BIND(nop), Implied, "SUB D", 4), INS(BIND(nop), Implied, "SUB E", 4), INS(BIND(nop), Implied, "SUB H", 4), INS(BIND(nop), Implied, "SUB L", 4), INS(BIND(nop), Implied, "SUB M", 7), INS(BIND(nop), Implied, "SUB A", 4), INS(BIND(nop), Implied, "SBB B", 4), INS(BIND(nop), Implied, "SBB C", 4), INS(BIND(nop), Implied, "SBB D", 4), INS(BIND(nop), Implied, "SBB E", 4), INS(BIND(nop), Implied, "SBB H", 4), INS(BIND(nop), Implied, "SBB L", 4), INS(BIND(nop), Implied, "SBB M", 4), INS(BIND(nop), Implied, "SBB A", 4), // 9 - /* A */ INS(BIND(nop), Implied, "ANA B", 4), INS(BIND(nop), Implied, "ANA C", 4), INS(BIND(nop), Implied, "ANA D", 4), INS(BIND(nop), Implied, "ANA E", 4), INS(BIND(nop), Implied, "ANA H", 4), INS(BIND(nop), Implied, "ANA L", 4), INS(BIND(nop), Implied, "ANA M", 7), INS(BIND(nop), Implied, "ANA A", 4), INS(BIND(nop), Implied, "XRA B", 4), INS(BIND(nop), Implied, "XRA C", 4), INS(BIND(nop), Implied, "XRA D", 4), INS(BIND(nop), Implied, "XRA E", 4), INS(BIND(nop), Implied, "XRA H", 4), INS(BIND(nop), Implied, "XRA L", 4), INS(BIND(nop), Implied, "XRA M", 4), INS(BIND(nop), Implied, "XRA A", 4), // A - /* B */ INS(BIND(nop), Implied, "ORA B", 4), INS(BIND(nop), Implied, "ORA C", 4), INS(BIND(nop), Implied, "ORA D", 4), INS(BIND(nop), Implied, "ORA E", 4), INS(BIND(nop), Implied, "ORA H", 4), INS(BIND(nop), Implied, "ORA L", 4), INS(BIND(nop), Implied, "ORA M", 7), INS(BIND(nop), Implied, "ORA A", 4), INS(BIND(nop), Implied, "CMP B", 4), INS(BIND(nop), Implied, "CMP C", 4), INS(BIND(nop), Implied, "CMP D", 4), INS(BIND(nop), Implied, "CMP E", 4), INS(BIND(nop), Implied, "CMP H", 4), INS(BIND(nop), Implied, "CMP L", 4), INS(BIND(nop), Implied, "CMP M", 4), INS(BIND(nop), Implied, "CMP A", 4), // B - - /* C */ INS(BIND(nop), Implied, "RNZ", 5), INS(BIND(nop), Implied, "POP B", 10), INS(BIND(nop), Absolute, "JNZ ", 10), INS(BIND(nop), Absolute, "JMP ", 10), INS(BIND(nop), Absolute, "CNZ ", 11), INS(BIND(nop), Implied, "PUSH B", 11), INS(BIND(nop), Immediate, "ADI ", 7), INS(BIND(nop), Implied, "RST 0", 11), INS(BIND(nop), Implied, "RZ", 11), INS(BIND(nop), Implied, "RET", 10), INS(BIND(nop), Absolute, "JZ ", 10), UNKNOWN(), INS(BIND(nop), Absolute, "CZ ", 11), INS(BIND(nop), Absolute, "CALL ", 17), INS(BIND(nop), Immediate, "ACI ", 7), INS(BIND(nop), Implied, "RST 1", 11), // C - /* D */ INS(BIND(nop), Implied, "RNC", 5), INS(BIND(nop), Implied, "POP D", 10), INS(BIND(nop), Absolute, "JNC ", 10), INS(BIND(nop), Immediate, "OUT ", 10), INS(BIND(nop), Absolute, "CNC ", 11), INS(BIND(nop), Implied, "PUSH D", 11), INS(BIND(nop), Immediate, "SUI ", 7), INS(BIND(nop), Implied, "RST 2", 11), INS(BIND(nop), Implied, "RC", 11), UNKNOWN(), INS(BIND(nop), Absolute, "JC ", 10), INS(BIND(nop), Immediate, "IN ", 10), INS(BIND(nop), Absolute, "CC ", 11), UNKNOWN(), INS(BIND(nop), Immediate, "SBI ", 7), INS(BIND(nop), Implied, "RST 3", 11), // D - /* E */ INS(BIND(nop), Implied, "RPO", 5), INS(BIND(nop), Implied, "POP H", 10), INS(BIND(nop), Absolute, "JPO ", 10), INS(BIND(nop), Implied, "XHTL", 18), INS(BIND(nop), Absolute, "CPO ", 11), INS(BIND(nop), Implied, "PUSH H", 11), INS(BIND(nop), Immediate, "ANI ", 7), INS(BIND(nop), Implied, "RST 4", 11), INS(BIND(nop), Implied, "RPE", 11), INS(BIND(nop), Implied, "PCHL", 5), INS(BIND(nop), Absolute, "JPE ", 10), INS(BIND(nop), Implied, "XCHG", 4), INS(BIND(nop), Absolute, "CPE ", 11), UNKNOWN(), INS(BIND(nop), Immediate, "XRI ", 7), INS(BIND(nop), Implied, "RST 5", 11), // E - /* F */ INS(BIND(nop), Implied, "RP", 5), INS(BIND(nop), Implied, "POP PSW", 10), INS(BIND(nop), Absolute, "JP ", 10), INS(BIND(nop), Implied, "DI ", 4), INS(BIND(nop), Absolute, "CP ", 11), INS(BIND(nop), Implied, "PUSH PSW", 11), INS(BIND(nop), Immediate, "ORI ", 7), INS(BIND(nop), Implied, "RST 6", 11), INS(BIND(nop), Implied, "RM", 11), INS(BIND(nop), Implied, "SPHL", 5), INS(BIND(nop), Absolute, "JM ", 10), INS(BIND(nop), Implied, "EI", 4), INS(BIND(nop), Absolute, "CM ", 11), UNKNOWN(), INS(BIND(nop), Immediate, "CPI ", 7), INS(BIND(nop), Implied, "RST 7", 11), // F - }; -} - -void EightBit::Intel8080::___() { - m_memory.ADDRESS().word = PC().word - 1; - auto opcode = m_memory.reference(); - auto message = Disassembler::invalid(opcode); - throw std::domain_error(message); -} \ No newline at end of file diff --git a/Intel8080/src/Intel8080.vcxproj b/Intel8080/src/Intel8080.vcxproj index 0c16d36..7c69427 100644 --- a/Intel8080/src/Intel8080.vcxproj +++ b/Intel8080/src/Intel8080.vcxproj @@ -71,16 +71,16 @@ - ../inc;../../inc;$(VC_IncludePath);$(WindowsSDK_IncludePath) + ..\inc;..\..\inc;C:\local\boost_1_64_0;$(IncludePath) - ../inc;../../inc;$(VC_IncludePath);$(WindowsSDK_IncludePath) + ..\inc;..\..\inc;C:\local\boost_1_64_0;$(IncludePath) - ../inc;../../inc;$(VC_IncludePath);$(WindowsSDK_IncludePath) + ..\inc;..\..\inc;C:\local\boost_1_64_0;$(IncludePath) - ../inc;../../inc;$(VC_IncludePath);$(WindowsSDK_IncludePath) + ..\inc;..\..\inc;C:\local\boost_1_64_0;$(IncludePath) diff --git a/Intel8080/src/stdafx.h b/Intel8080/src/stdafx.h index 20f89d9..b22af77 100644 --- a/Intel8080/src/stdafx.h +++ b/Intel8080/src/stdafx.h @@ -13,6 +13,8 @@ #include #include +#include + #if defined(_M_X64) || defined(_M_IX86 ) # define HOST_LITTLE_ENDIAN #else diff --git a/Intel8080/test/Board.cpp b/Intel8080/test/Board.cpp index ff81f8f..00fcc7d 100644 --- a/Intel8080/test/Board.cpp +++ b/Intel8080/test/Board.cpp @@ -1,6 +1,5 @@ #include "stdafx.h" #include "Board.h" -#include "Disassembler.h" #include "Configuration.h" #include @@ -83,6 +82,6 @@ void Board::Cpu_ExecutingInstruction_Debug(const EightBit::Intel8080&) { std::cerr << EightBit::Disassembler::state(m_cpu) << "\t" - << EightBit::Disassembler::disassemble(m_cpu) + << m_disassembler.disassemble(m_cpu) << '\n'; } diff --git a/Intel8080/test/Board.h b/Intel8080/test/Board.h index 85aea27..1d7f7f3 100644 --- a/Intel8080/test/Board.h +++ b/Intel8080/test/Board.h @@ -1,12 +1,11 @@ #pragma once -//#include - #include "Memory.h" #include "InputOutput.h" #include "Intel8080.h" #include "Profiler.h" #include "EventArgs.h" +#include "Disassembler.h" class Configuration; @@ -24,6 +23,7 @@ private: EightBit::Memory m_memory; EightBit::InputOutput m_ports; EightBit::Intel8080 m_cpu; + EightBit::Disassembler m_disassembler; EightBit::Profiler m_profiler; void Cpu_ExecutingInstruction_Cpm(const EightBit::Intel8080& cpu); From ff21263b9756ae7d80d543c35df91059fb0d7066 Mon Sep 17 00:00:00 2001 From: "Adrian.Conlon" Date: Tue, 25 Jul 2017 14:32:31 +0100 Subject: [PATCH 06/10] Correct a couple of small disassembly issues in the 8080 implementation Signed-off-by: Adrian.Conlon --- Intel8080/inc/Disassembler.h | 2 +- Intel8080/src/Disassembler.cpp | 14 +++++++------- Intel8080/src/Intel8080.cpp | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/Intel8080/inc/Disassembler.h b/Intel8080/inc/Disassembler.h index c9d4e9e..11d9cdc 100644 --- a/Intel8080/inc/Disassembler.h +++ b/Intel8080/inc/Disassembler.h @@ -14,7 +14,7 @@ namespace EightBit { static std::string state(Intel8080& cpu); std::string disassemble(Intel8080& cpu); - static std::string flag(uint8_t value, int flag, const std::string& represents); + static std::string flag(uint8_t value, int flag, std::string represents, std::string off = "-"); static std::string flags(uint8_t value); static std::string hex(uint8_t value); static std::string hex(uint16_t value); diff --git a/Intel8080/src/Disassembler.cpp b/Intel8080/src/Disassembler.cpp index 78a6ffa..87d421e 100644 --- a/Intel8080/src/Disassembler.cpp +++ b/Intel8080/src/Disassembler.cpp @@ -339,7 +339,7 @@ void EightBit::Disassembler::disassemble( } break; case 2: // Operate on accumulator and register/memory location - specification = alu(y) + " A," + R(z); + specification = alu(y) + " " + R(z); break; case 3: switch (z) { @@ -426,7 +426,7 @@ void EightBit::Disassembler::disassemble( } break; case 6: // Operate on accumulator and immediate operand: alu[y] n - specification = alu2(y) + " %1$02XH"; + specification = alu2(y) + " %1$02XH"; dumpCount++; break; case 7: // Restart: RST y * 8 @@ -437,9 +437,9 @@ void EightBit::Disassembler::disassemble( } } -std::string EightBit::Disassembler::flag(uint8_t value, int flag, const std::string& represents) { +std::string EightBit::Disassembler::flag(uint8_t value, int flag, std::string represents, std::string off) { std::ostringstream output; - output << (value & flag ? represents : "-"); + output << (value & flag ? represents : off); return output.str(); } @@ -448,11 +448,11 @@ std::string EightBit::Disassembler::flags(uint8_t value) { output << flag(value, Intel8080::SF, "S") << flag(value, Intel8080::ZF, "Z") - << flag(value, Processor::Bit5, "5") + << flag(value, Processor::Bit5, "1", "0") << flag(value, Intel8080::AC, "A") - << flag(value, Processor::Bit3, "3") + << flag(value, Processor::Bit3, "1", "0") << flag(value, Intel8080::PF, "P") - << flag(value, Processor::Bit1, "1") + << flag(value, Processor::Bit1, "1", "0") << flag(value, Intel8080::CF, "C"); return output.str(); } diff --git a/Intel8080/src/Intel8080.cpp b/Intel8080/src/Intel8080.cpp index 9c29a39..06068f0 100644 --- a/Intel8080/src/Intel8080.cpp +++ b/Intel8080/src/Intel8080.cpp @@ -14,6 +14,7 @@ EightBit::Intel8080::Intel8080(Memory& memory, InputOutput& ports) void EightBit::Intel8080::initialise() { IntelProcessor::initialise(); AF().word = BC().word = DE().word = HL().word = 0; + adjustReservedFlags(); } #pragma region Interrupt routines From b6dd48ca63e5a89fc9de6e8da087d00a9f8a69e6 Mon Sep 17 00:00:00 2001 From: "Adrian.Conlon" Date: Tue, 25 Jul 2017 18:56:43 +0100 Subject: [PATCH 07/10] Some more small clarifications of shared processor implementation. Signed-off-by: Adrian.Conlon --- Intel8080/inc/Intel8080.h | 10 ++----- Intel8080/src/Intel8080.cpp | 4 +-- Intel8080/test/test.cpp | 3 +- LR35902/inc/LR35902.h | 56 ++++++++++++++++++++++--------------- LR35902/src/LR35902.cpp | 2 +- M6502/inc/mos6502.h | 5 ++-- M6502/src/mos6502.cpp | 6 ---- Z80/inc/Z80.h | 6 ++-- Z80/src/Z80.cpp | 2 +- inc/IntelProcessor.h | 12 +------- inc/Processor.h | 16 +++++++++++ 11 files changed, 63 insertions(+), 59 deletions(-) diff --git a/Intel8080/inc/Intel8080.h b/Intel8080/inc/Intel8080.h index 78b1138..5f80d80 100644 --- a/Intel8080/inc/Intel8080.h +++ b/Intel8080/inc/Intel8080.h @@ -8,8 +8,6 @@ namespace EightBit { class Intel8080 : public IntelProcessor { public: - typedef std::function instruction_t; - enum StatusBits { SF = Bit7, ZF = Bit6, @@ -29,6 +27,8 @@ namespace EightBit { int step(); virtual register16_t& AF() override { + auto& f = af.low; + f = (f | Bit1) & ~(Bit5 | Bit3); return af; } @@ -117,10 +117,6 @@ namespace EightBit { } } - void adjustReservedFlags() { - F() = (F() | Bit1) & ~(Bit5 | Bit3); - } - static void adjustAuxiliaryCarryAdd(uint8_t& f, uint8_t before, uint8_t value, int calculation) { setFlag(f, AC, calculateHalfCarryAdd(before, value, calculation)); } @@ -131,7 +127,7 @@ namespace EightBit { static void subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0); - int execute(uint8_t opcode); + virtual int execute(uint8_t opcode); void execute(int x, int y, int z, int p, int q); static void increment(uint8_t& f, uint8_t& operand); diff --git a/Intel8080/src/Intel8080.cpp b/Intel8080/src/Intel8080.cpp index 06068f0..8bd07e7 100644 --- a/Intel8080/src/Intel8080.cpp +++ b/Intel8080/src/Intel8080.cpp @@ -14,7 +14,6 @@ EightBit::Intel8080::Intel8080(Memory& memory, InputOutput& ports) void EightBit::Intel8080::initialise() { IntelProcessor::initialise(); AF().word = BC().word = DE().word = HL().word = 0; - adjustReservedFlags(); } #pragma region Interrupt routines @@ -345,7 +344,7 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) { case 1: // 16-bit load immediate/add switch (q) { case 0: // LD rp,nn - fetchWord(RP(p)); + Processor::fetchWord(RP(p)); cycles += 10; break; case 1: // ADD HL,rp @@ -532,7 +531,6 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) { switch (q) { case 0: // POP rp2[p] popWord(RP2(p)); - adjustReservedFlags(); cycles += 10; break; case 1: diff --git a/Intel8080/test/test.cpp b/Intel8080/test/test.cpp index 378705e..7653e58 100644 --- a/Intel8080/test/test.cpp +++ b/Intel8080/test/test.cpp @@ -8,9 +8,10 @@ int main(int, char*[]) { Configuration configuration; #ifdef _DEBUG - configuration.setDebugMode(true); + //configuration.setDebugMode(true); configuration.setProfileMode(true); #endif + //configuration.setDebugMode(true); EightBit::TestHarness harness(configuration); harness.initialise(); diff --git a/LR35902/inc/LR35902.h b/LR35902/inc/LR35902.h index 9352131..24fcd87 100644 --- a/LR35902/inc/LR35902.h +++ b/LR35902/inc/LR35902.h @@ -31,44 +31,42 @@ namespace EightBit { int interrupt(uint8_t value); - int execute(uint8_t opcode); + virtual int execute(uint8_t opcode); int step(); - // Mutable access to processor!! - virtual register16_t& AF() override { - m_accumulatorFlag.low &= 0xf0; - return m_accumulatorFlag; + af.low &= 0xf0; + return af; } virtual register16_t& BC() override { - return m_registers[BC_IDX]; + return bc; } virtual register16_t& DE() override { - return m_registers[DE_IDX]; + return de; } virtual register16_t& HL() override { - return m_registers[HL_IDX]; + return hl; } virtual void reset(); virtual void initialise(); protected: - virtual uint8_t fetchByte() { + virtual uint8_t fetchByte() override { auto returned = IntelProcessor::fetchByte(); m_memory.fireReadBusEvent(); return returned; } - virtual void push(uint8_t value) { + virtual void push(uint8_t value) override { IntelProcessor::push(value); m_memory.fireWriteBusEvent(); } - virtual uint8_t pop() { + virtual uint8_t pop() override { auto returned = IntelProcessor::pop(); m_memory.fireReadBusEvent(); return returned; @@ -91,12 +89,12 @@ namespace EightBit { } private: - enum { BC_IDX, DE_IDX, HL_IDX }; - Bus& m_bus; - std::array m_registers; - register16_t m_accumulatorFlag; + register16_t af; + register16_t bc; + register16_t de; + register16_t hl; bool m_ime; @@ -104,10 +102,6 @@ namespace EightBit { bool m_stopped; - int fetchExecute() { - return execute(fetchByte()); - } - uint8_t& R(int r, uint8_t& a) { switch (r) { case 0: @@ -132,20 +126,36 @@ namespace EightBit { } register16_t& RP(int rp) { + __assume(rp < 4); + __assume(rp >= 0); switch (rp) { - case 3: + case 0b00: + return BC(); + case 0b01: + return DE(); + case 0b10: + return HL(); + case 0b11: return SP(); default: - return m_registers[rp]; + __assume(0); } } register16_t& RP2(int rp) { + __assume(rp < 4); + __assume(rp >= 0); switch (rp) { - case 3: + case 0b00: + return BC(); + case 0b01: + return DE(); + case 0b10: + return HL(); + case 0b11: return AF(); default: - return m_registers[rp]; + __assume(0); } } diff --git a/LR35902/src/LR35902.cpp b/LR35902/src/LR35902.cpp index c3fc23c..023a31e 100644 --- a/LR35902/src/LR35902.cpp +++ b/LR35902/src/LR35902.cpp @@ -500,7 +500,7 @@ void EightBit::LR35902::executeOther(int x, int y, int z, int p, int q) { case 1: // 16-bit load immediate/add switch (q) { case 0: // LD rp,nn - fetchWord(RP(p)); + Processor::fetchWord(RP(p)); cycles += 3; break; case 1: // ADD HL,rp diff --git a/M6502/inc/mos6502.h b/M6502/inc/mos6502.h index bfa056a..35a7ee2 100644 --- a/M6502/inc/mos6502.h +++ b/M6502/inc/mos6502.h @@ -78,7 +78,7 @@ namespace EightBit { protected: virtual void interrupt(uint16_t vector); - virtual int execute(uint8_t cell); + virtual int execute(uint8_t opcode); private: register16_t& MEMPTR() { return m_memptr; } @@ -96,8 +96,7 @@ namespace EightBit { void pushWord(register16_t value); void popWord(register16_t& output); - uint8_t fetchByte(); - void fetchWord(register16_t& output); + virtual uint8_t fetchByte() override; #pragma region 6502 addressing modes diff --git a/M6502/src/mos6502.cpp b/M6502/src/mos6502.cpp index 563cbc1..90742e5 100644 --- a/M6502/src/mos6502.cpp +++ b/M6502/src/mos6502.cpp @@ -385,12 +385,6 @@ uint8_t EightBit::MOS6502::fetchByte() { return getByte(); } -void EightBit::MOS6502::fetchWord(register16_t& output) { - m_memory.ADDRESS().word = PC().word++; - getWord(output); - PC().word++; -} - //// void EightBit::MOS6502::ROR(uint8_t& output) { diff --git a/Z80/inc/Z80.h b/Z80/inc/Z80.h index c104f49..27b3118 100644 --- a/Z80/inc/Z80.h +++ b/Z80/inc/Z80.h @@ -54,7 +54,7 @@ namespace EightBit { int interrupt(bool maskable, uint8_t value); - int execute(uint8_t opcode); + virtual int execute(uint8_t opcode); int step(); virtual register16_t& AF() override { @@ -131,9 +131,9 @@ namespace EightBit { int8_t m_displacement; bool m_displaced; - int fetchExecute() { + virtual int fetchExecute() override{ M1() = true; - return execute(fetchByte()); + return IntelProcessor::fetchExecute(); } uint8_t& DISPLACED() { diff --git a/Z80/src/Z80.cpp b/Z80/src/Z80.cpp index 0a10bc8..b685cfb 100644 --- a/Z80/src/Z80.cpp +++ b/Z80/src/Z80.cpp @@ -1152,7 +1152,7 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) { case 1: // 16-bit load immediate/add switch (q) { case 0: // LD rp,nn - fetchWord(RP(p)); + Processor::fetchWord(RP(p)); cycles += 10; break; case 1: // ADD HL,rp diff --git a/inc/IntelProcessor.h b/inc/IntelProcessor.h index 088c0b6..a26d735 100644 --- a/inc/IntelProcessor.h +++ b/inc/IntelProcessor.h @@ -119,16 +119,6 @@ namespace EightBit { return m_halfCarryTableSub[index & Mask3]; } - virtual uint8_t fetchByte() { - m_memory.ADDRESS().word = PC().word++; - return m_memory.reference(); - } - - void fetchWord(register16_t& output) { - output.low = fetchByte(); - output.high = fetchByte(); - } - virtual void push(uint8_t value) { m_memory.ADDRESS().word = --SP().word; m_memory.reference() = value; @@ -150,7 +140,7 @@ namespace EightBit { } void fetchWord() { - fetchWord(MEMPTR()); + Processor::fetchWord(MEMPTR()); } // diff --git a/inc/Processor.h b/inc/Processor.h index abd7641..0cf7151 100644 --- a/inc/Processor.h +++ b/inc/Processor.h @@ -55,6 +55,8 @@ namespace EightBit { void reset(); + virtual int execute(uint8_t opcode) = 0; + protected: static void clearFlag(uint8_t& f, int flag) { f &= ~flag; } static void setFlag(uint8_t& f, int flag) { f |= flag; } @@ -72,6 +74,20 @@ namespace EightBit { Memory& m_memory; int cycles; + virtual uint8_t fetchByte() { + m_memory.ADDRESS().word = PC().word++; + return m_memory.reference(); + } + + virtual void fetchWord(register16_t& output) { + output.low = fetchByte(); + output.high = fetchByte(); + } + + virtual int fetchExecute() { + return execute(fetchByte()); + } + private: register16_t pc; bool m_halted; From fbf797a6102a8fcbc9f9290ba61bde577c81a4bd Mon Sep 17 00:00:00 2001 From: "Adrian.Conlon" Date: Tue, 25 Jul 2017 19:26:21 +0100 Subject: [PATCH 08/10] More unification of "IntelProcessor" derived classes. This time the i8080. Signed-off-by: Adrian.Conlon --- Intel8080/inc/Intel8080.h | 16 +++---- Intel8080/src/Intel8080.cpp | 83 ++++++++++++++++++------------------- 2 files changed, 48 insertions(+), 51 deletions(-) diff --git a/Intel8080/inc/Intel8080.h b/Intel8080/inc/Intel8080.h index 5f80d80..f7a6ec6 100644 --- a/Intel8080/inc/Intel8080.h +++ b/Intel8080/inc/Intel8080.h @@ -138,15 +138,15 @@ namespace EightBit { bool jumpConditionalFlag(uint8_t& f, int flag); bool callConditionalFlag(uint8_t& f, int flag); - void dad(uint16_t value); + static void add(uint8_t& f, register16_t& operand, register16_t value); - void add(uint8_t value, int carry = 0); - void adc(uint8_t value); - void sbb(uint8_t value); - void anda(uint8_t value); - void xra(uint8_t value); - void ora(uint8_t value); - void compare(uint8_t& f, uint8_t check, uint8_t value); + static void add(uint8_t& f, uint8_t& operand, uint8_t value, int carry = 0); + static void adc(uint8_t& f, uint8_t& operand, uint8_t value); + static void sbb(uint8_t& f, uint8_t& operand, uint8_t value); + static void andr(uint8_t& f, uint8_t& operand, uint8_t value); + static void xorr(uint8_t& f, uint8_t& operand, uint8_t value); + static void orr(uint8_t& f, uint8_t& operand, uint8_t value); + static void compare(uint8_t& f, uint8_t check, uint8_t value); void rlc(); void rrc(); diff --git a/Intel8080/src/Intel8080.cpp b/Intel8080/src/Intel8080.cpp index 8bd07e7..7d9cb7d 100644 --- a/Intel8080/src/Intel8080.cpp +++ b/Intel8080/src/Intel8080.cpp @@ -132,30 +132,31 @@ bool EightBit::Intel8080::callConditionalFlag(uint8_t& f, int flag) { #pragma region 16-bit arithmetic -void EightBit::Intel8080::dad(uint16_t value) { - auto& f = F(); - auto sum = HL().word + value; - setFlag(f, CF, sum & Bit16); - HL().word = sum; +void EightBit::Intel8080::add(uint8_t& f, register16_t& operand, register16_t value) { + const auto result = operand.word + value.word; + setFlag(f, CF, result & Bit16); + operand.word = result; } #pragma endregion 16-bit arithmetic #pragma region ALU -void EightBit::Intel8080::add(uint8_t value, int carry) { - auto& a = A(); - auto& f = F(); - register16_t sum; - sum.word = a + value + carry; - adjustAuxiliaryCarryAdd(f, a, value, sum.word); - a = sum.low; - setFlag(f, CF, sum.word & Bit8); - adjustSZP(f, a); +void EightBit::Intel8080::add(uint8_t& f, uint8_t& operand, uint8_t value, int carry) { + + register16_t result; + result.word = operand + value + carry; + + adjustAuxiliaryCarryAdd(f, operand, value, result.word); + + operand = result.low; + + setFlag(f, CF, result.word & Bit8); + adjustSZP(f, operand); } -void EightBit::Intel8080::adc(uint8_t value) { - add(value, F() & CF); +void EightBit::Intel8080::adc(uint8_t& f, uint8_t& operand, uint8_t value) { + add(f, operand, value, f & CF); } void EightBit::Intel8080::subtract(uint8_t& f, uint8_t& operand, uint8_t value, int carry) { @@ -171,28 +172,24 @@ void EightBit::Intel8080::subtract(uint8_t& f, uint8_t& operand, uint8_t value, adjustSZP(f, operand); } -void EightBit::Intel8080::sbb(uint8_t value) { - subtract(F(), A(), value, F() & CF); +void EightBit::Intel8080::sbb(uint8_t& f, uint8_t& operand, uint8_t value) { + subtract(f, operand, value, f & CF); } -void EightBit::Intel8080::anda(uint8_t value) { - auto& a = A(); - auto& f = F(); - setFlag(f, AC, (a | value) & Bit3); +void EightBit::Intel8080::andr(uint8_t& f, uint8_t& operand, uint8_t value) { + setFlag(f, AC, (operand | value) & Bit3); clearFlag(f, CF); - adjustSZP(f, a &= value); + adjustSZP(f, operand &= value); } -void EightBit::Intel8080::xra(uint8_t value) { - auto& f = F(); +void EightBit::Intel8080::xorr(uint8_t& f, uint8_t& operand, uint8_t value) { clearFlag(f, AC | CF); - adjustSZP(f, A() ^= value); + adjustSZP(f, operand ^= value); } -void EightBit::Intel8080::ora(uint8_t value) { - auto& f = F(); +void EightBit::Intel8080::orr(uint8_t& f, uint8_t& operand, uint8_t value) { clearFlag(f, AC | CF); - adjustSZP(f, A() |= value); + adjustSZP(f, operand |= value); } void EightBit::Intel8080::compare(uint8_t& f, uint8_t check, uint8_t value) { @@ -249,7 +246,7 @@ void EightBit::Intel8080::daa() { addition |= 0x60; carry = true; } - add(addition); + add(f, A(), addition); setFlag(f, CF, carry); } @@ -348,7 +345,7 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) { cycles += 10; break; case 1: // ADD HL,rp - dad(RP(p).word); + add(f, HL(), RP(p)); cycles += 11; break; } @@ -490,25 +487,25 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) { case 2: // Operate on accumulator and register/memory location switch (y) { case 0: // ADD A,r - add(R(z)); + add(f, a, R(z)); break; case 1: // ADC A,r - adc(R(z)); + adc(f, a, R(z)); break; case 2: // SUB r subtract(f, a, R(z)); break; case 3: // SBC A,r - sbb(R(z)); + sbb(f, a, R(z)); break; case 4: // AND r - anda(R(z)); + andr(f, a, R(z)); break; case 5: // XOR r - xra(R(z)); + xorr(f, a, R(z)); break; case 6: // OR r - ora(R(z)); + orr(f, a, R(z)); break; case 7: // CP r compare(f, a, R(z)); @@ -633,25 +630,25 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) { case 6: // Operate on accumulator and immediate operand: alu[y] n switch (y) { case 0: // ADD A,n - add(fetchByte()); + add(f, a, fetchByte()); break; case 1: // ADC A,n - adc(fetchByte()); + adc(f, a, fetchByte()); break; case 2: // SUB n subtract(f, a, fetchByte()); break; case 3: // SBC A,n - sbb(fetchByte()); + sbb(f, a, fetchByte()); break; case 4: // AND n - anda(fetchByte()); + andr(f, a, fetchByte()); break; case 5: // XOR n - xra(fetchByte()); + xorr(f, a, fetchByte()); break; case 6: // OR n - ora(fetchByte()); + orr(f, a, fetchByte()); break; case 7: // CP n compare(f, a, fetchByte()); From 1b11e0750b87e1d491dd791d608bccbe340ad1f9 Mon Sep 17 00:00:00 2001 From: "Adrian.Conlon" Date: Tue, 25 Jul 2017 20:52:10 +0100 Subject: [PATCH 09/10] Try to make the 8080 emulator a little more like the LR35902 Signed-off-by: Adrian.Conlon --- Intel8080/src/Intel8080.cpp | 35 ++--------------------------------- 1 file changed, 2 insertions(+), 33 deletions(-) diff --git a/Intel8080/src/Intel8080.cpp b/Intel8080/src/Intel8080.cpp index 7d9cb7d..fa78946 100644 --- a/Intel8080/src/Intel8080.cpp +++ b/Intel8080/src/Intel8080.cpp @@ -323,19 +323,6 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) { case 0: // NOP cycles += 4; break; - case 1: // EX AF AF' - break; - case 2: // DJNZ d - break; - case 3: // JR d - break; - case 4: // JR cc,d - case 5: - case 6: - case 7: - break; - default: - __assume(0); } break; case 1: // 16-bit load immediate/add @@ -431,14 +418,12 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) { if (y == 6) cycles += 7; break; - case 6: { // 8-bit load immediate - auto& r = R(y); // LD r,n - r = fetchByte(); + case 6: // 8-bit load immediate + R(y) = fetchByte(); cycles += 7; if (y == 6) cycles += 3; break; - } case 7: // Assorted operations on accumulator/flags switch (y) { case 0: @@ -536,8 +521,6 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) { ret(); cycles += 10; break; - case 1: // EXX - break; case 2: // JP HL PC() = HL(); cycles += 4; @@ -546,8 +529,6 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) { SP() = HL(); cycles += 4; break; - default: - __assume(0); } break; default: @@ -565,8 +546,6 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) { jump(); cycles += 10; break; - case 1: // CB prefix - break; case 2: // OUT (n),A out(); cycles += 11; @@ -591,8 +570,6 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) { ei(); cycles += 4; break; - default: - __assume(0); } break; case 4: // Conditional call: CALL cc[y], nn @@ -613,14 +590,6 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) { call(); cycles += 17; break; - case 1: // DD prefix - break; - case 2: // ED prefix - break; - case 3: // FD prefix - break; - default: - __assume(0); } break; default: From 8535efb30d35e2514694f43ccdcd857892141d1a Mon Sep 17 00:00:00 2001 From: "Adrian.Conlon" Date: Tue, 25 Jul 2017 21:22:15 +0100 Subject: [PATCH 10/10] More i8080 and LR35902 consistency. Signed-off-by: Adrian.Conlon --- Intel8080/inc/Intel8080.h | 16 ++++---- Intel8080/src/Intel8080.cpp | 75 +++++++++++++++++-------------------- 2 files changed, 42 insertions(+), 49 deletions(-) diff --git a/Intel8080/inc/Intel8080.h b/Intel8080/inc/Intel8080.h index f7a6ec6..8c45e0f 100644 --- a/Intel8080/inc/Intel8080.h +++ b/Intel8080/inc/Intel8080.h @@ -148,16 +148,16 @@ namespace EightBit { static void orr(uint8_t& f, uint8_t& operand, uint8_t value); static void compare(uint8_t& f, uint8_t check, uint8_t value); - void rlc(); - void rrc(); - void ral(); - void rar(); + static void rlc(uint8_t& f, uint8_t& operand); + static void rrc(uint8_t& f, uint8_t& operand); + static void rl(uint8_t& f, uint8_t& operand); + static void rr(uint8_t& f, uint8_t& operand); - void daa(); + static void daa(uint8_t& a, uint8_t& f); - void cma(); - void stc(); - void cmc(); + static void cma(uint8_t& a, uint8_t& f); + static void stc(uint8_t& a, uint8_t& f); + static void cmc(uint8_t& a, uint8_t& f); void xhtl(); diff --git a/Intel8080/src/Intel8080.cpp b/Intel8080/src/Intel8080.cpp index fa78946..078ab0d 100644 --- a/Intel8080/src/Intel8080.cpp +++ b/Intel8080/src/Intel8080.cpp @@ -200,66 +200,59 @@ void EightBit::Intel8080::compare(uint8_t& f, uint8_t check, uint8_t value) { #pragma region Shift and rotate -void EightBit::Intel8080::rlc() { - auto& a = A(); - auto carry = a & Bit7; - a = (a << 1) | (carry >> 7); - setFlag(F(), CF, carry); +void EightBit::Intel8080::rlc(uint8_t& f, uint8_t& operand) { + auto carry = operand & Bit7; + operand = (operand << 1) | (carry >> 7); + setFlag(f, CF, carry); } -void EightBit::Intel8080::rrc() { - auto& a = A(); - auto carry = a & Bit0; - a = (a >> 1) | (carry << 7); - setFlag(F(), CF, carry); +void EightBit::Intel8080::rrc(uint8_t& f, uint8_t& operand) { + auto carry = operand & Bit0; + operand = (operand >> 1) | (carry << 7); + setFlag(f, CF, carry); } -void EightBit::Intel8080::ral() { - auto& a = A(); - auto& f = F(); +void EightBit::Intel8080::rl(uint8_t& f, uint8_t& operand) { const auto carry = f & CF; - setFlag(f, CF, a & Bit7); - a = (a << 1) | carry; + setFlag(f, CF, operand & Bit7); + operand = (operand << 1) | carry; } -void EightBit::Intel8080::rar() { - auto& a = A(); - auto& f = F(); +void EightBit::Intel8080::rr(uint8_t& f, uint8_t& operand) { const auto carry = f & CF; - setFlag(f, CF, a & Bit0); - a = (a >> 1) | (carry << 7); + setFlag(f, CF, operand & Bit0); + operand = (operand >> 1) | (carry << 7); } #pragma endregion Shift and rotate #pragma region Miscellaneous instructions -void EightBit::Intel8080::daa() { - const auto& a = A(); - auto& f = F(); +void EightBit::Intel8080::daa(uint8_t& a, uint8_t& f) { + const auto& before = a; auto carry = f & CF; uint8_t addition = 0; - if ((f & AC) || lowNibble(a) > 9) { + if ((f & AC) || lowNibble(before) > 9) { addition = 0x6; } - if ((f & CF) || highNibble(a) > 9 || (highNibble(a) >= 9 && lowNibble(a) > 9)) { + if ((f & CF) || highNibble(before) > 9 || (highNibble(before) >= 9 && lowNibble(before) > 9)) { addition |= 0x60; carry = true; } - add(f, A(), addition); + add(f, a, addition); setFlag(f, CF, carry); } -void EightBit::Intel8080::cma() { - A() = ~A(); +void EightBit::Intel8080::cma(uint8_t& a, uint8_t& f) { + a = ~a; } -void EightBit::Intel8080::stc() { - setFlag(F(), CF); +void EightBit::Intel8080::stc(uint8_t& a, uint8_t& f) { + setFlag(f, CF); } -void EightBit::Intel8080::cmc() { - clearFlag(F(), CF, F() & CF); +void EightBit::Intel8080::cmc(uint8_t& a, uint8_t& f) { + clearFlag(f, CF, f & CF); } void EightBit::Intel8080::xhtl() { @@ -290,7 +283,7 @@ void EightBit::Intel8080::in() { int EightBit::Intel8080::step() { ExecutingInstruction.fire(*this); cycles = 0; - return execute(fetchByte()); + return fetchExecute(); } int EightBit::Intel8080::execute(uint8_t opcode) { @@ -427,28 +420,28 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) { case 7: // Assorted operations on accumulator/flags switch (y) { case 0: - rlc(); + rlc(f, a); break; case 1: - rrc(); + rrc(f, a); break; case 2: - ral(); + rl(f, a); break; case 3: - rar(); + rr(f, a); break; case 4: - daa(); + daa(a, f); break; case 5: - cma(); + cma(a, f); break; case 6: - stc(); + stc(a, f); break; case 7: - cmc(); + cmc(a, f); break; default: __assume(0);