diff --git a/Z80/fusetest_Z80/FuseTestRunner.cpp b/Z80/fusetest_Z80/FuseTestRunner.cpp index c141844..1570eb7 100644 --- a/Z80/fusetest_Z80/FuseTestRunner.cpp +++ b/Z80/fusetest_Z80/FuseTestRunner.cpp @@ -14,9 +14,9 @@ Fuse::TestRunner::TestRunner(const Test& test, const ExpectedTestResult& result) m_expectedEvents.events.push_back(event); } - m_cpu.ExecutedInstruction.connect([this](EightBit::Z80& cpu) { - m_totalCycles += cpu.cycles(); - std::cout << "**** Cycle count: " << cpu.cycles() << std::endl; + m_cpu.ExecutedInstruction.connect([this](EightBit::EventArgs) { + m_totalCycles += m_cpu.cycles(); + std::cout << "**** Cycle count: " << m_cpu.cycles() << std::endl; }); m_cpu.ReadMemory.connect([this](EightBit::EventArgs&) { @@ -27,11 +27,11 @@ Fuse::TestRunner::TestRunner(const Test& test, const ExpectedTestResult& result) addActualEvent("MW"); }); - m_cpu.ReadIO.connect([this](EightBit::EventArgs&) { + m_ports.ReadPort.connect([this](EightBit::register16_t) { addActualEvent("PR"); }); - m_cpu.WrittenIO.connect([this](EightBit::EventArgs&) { + m_ports.WrittenPort.connect([this](EightBit::register16_t) { addActualEvent("PW"); }); } @@ -64,36 +64,12 @@ void Fuse::TestRunner::lowerPOWER() noexcept { } EightBit::MemoryMapping Fuse::TestRunner::mapping(uint16_t address) noexcept { - - const bool memory = m_cpu.requestingMemory(); - if (memory) - return { - m_ram, - 0x0000, - 0xffff, - EightBit::MemoryMapping::AccessLevel::ReadWrite - }; - - const bool io = m_cpu.requestingIO(); - if (io) { - - m_ports.accessType() = EightBit::InputOutput::AccessType::Unknown; - - const bool reading = m_cpu.requestingRead(); - if (reading) - m_ports.accessType() = EightBit::InputOutput::AccessType::Reading; - - const bool writing = m_cpu.requestingWrite(); - if (writing) - m_ports.accessType() = EightBit::InputOutput::AccessType::Writing; - - return { - m_ports, - 0x0000, - 0xff, - EightBit::MemoryMapping::AccessLevel::ReadWrite - }; - } + return { + m_ram, + 0x0000, + 0xffff, + EightBit::MemoryMapping::AccessLevel::ReadWrite + }; } void Fuse::TestRunner::initialise() { diff --git a/Z80/inc/Z80.h b/Z80/inc/Z80.h index f777000..c0b7dae 100644 --- a/Z80/inc/Z80.h +++ b/Z80/inc/Z80.h @@ -75,21 +75,6 @@ namespace EightBit { Z80(const Z80& rhs); bool operator==(const Z80& rhs) const; - Signal ExecutingInstruction; - Signal ExecutedInstruction; - - Signal ReadingMemory; - Signal ReadMemory; - - Signal WritingMemory; - Signal WrittenMemory; - - Signal ReadingIO; - Signal ReadIO; - - Signal WritingIO; - Signal WrittenIO; - void execute() noexcept final; int step() noexcept final; @@ -135,6 +120,8 @@ namespace EightBit { [[nodiscard]] constexpr auto& IFF2() noexcept { return m_iff2; } [[nodiscard]] constexpr auto IFF2() const noexcept { return m_iff2; } + [[nodiscard]] constexpr auto& Q() noexcept { return m_q; } + constexpr void exx() noexcept { m_registerSet ^= 1; } constexpr void exxAF() noexcept { m_accumulatorFlagsSet ^= 1; } @@ -180,6 +167,9 @@ namespace EightBit { bool m_iff1 = false; bool m_iff2 = false; + uint8_t m_q = 0; // Previously modified instruction status register + uint8_t m_modifiedF = 0; // In-flight status register. Used to build "Q" + bool m_prefixCB = false; bool m_prefixDD = false; bool m_prefixED = false; @@ -222,65 +212,159 @@ namespace EightBit { void R(int r, uint8_t value) noexcept; void R2(int r, uint8_t value) noexcept; + static [[nodiscard]] constexpr auto zeroTest(uint8_t data) noexcept { return data & ZF; } + static [[nodiscard]] constexpr auto carryTest(uint8_t data) noexcept { return data & CF; } + static [[nodiscard]] constexpr auto parityTest(uint8_t data) noexcept { return data & PF; } + static [[nodiscard]] constexpr auto signTest(uint8_t data) noexcept { return data & SF; } + static [[nodiscard]] constexpr auto halfCarryTest(uint8_t data) noexcept { return data & HC; } + static [[nodiscard]] constexpr auto subtractingTest(uint8_t data) noexcept { return data & NF; } + static [[nodiscard]] constexpr auto xTest(uint8_t data) noexcept { return data & XF; } + static [[nodiscard]] constexpr auto yTest(uint8_t data) noexcept { return data & YF; } + + [[nodiscard]] constexpr auto zero() noexcept { return zeroTest(F()); } + [[nodiscard]] constexpr auto carry() noexcept { return carryTest(F()); } + [[nodiscard]] constexpr auto parity() noexcept { return parityTest(F()); } + [[nodiscard]] constexpr auto sign() noexcept { return signTest(F()); } + [[nodiscard]] constexpr auto halfCarry() noexcept { return halfCarryTest(F()); } + [[nodiscard]] constexpr auto subtracting() noexcept { return subtractingTest(F()); } + + void adjustStatusFlags(uint8_t value) noexcept { m_modifiedF = F() = value; } + + void setBit(StatusBits flag) { return adjustStatusFlags(setBit(F(), flag)); } + static [[nodiscard]] constexpr uint8_t setBit(uint8_t f, StatusBits flag) noexcept { return Chip::setBit(f, (uint8_t)flag); } + void setBit(StatusBits flag, int condition) noexcept { adjustStatusFlags(Chip::setBit(F(), flag, condition)); } + static [[nodiscard]] constexpr uint8_t setBit(uint8_t f, StatusBits flag, int condition) noexcept { return Chip::setBit(f, (uint8_t)flag, condition); } + void setBit(StatusBits flag, bool condition) noexcept { adjustStatusFlags(setBit(F(), flag, condition)); } + static [[nodiscard]] constexpr uint8_t setBit(uint8_t f, StatusBits flag, bool condition) noexcept { return Chip::setBit(f, (uint8_t)flag, condition); } + + void clearBit(StatusBits flag) noexcept { adjustStatusFlags(clearBit(F(), flag)); } + static [[nodiscard]] constexpr uint8_t clearBit(uint8_t f, StatusBits flag) noexcept { return Chip::clearBit(f, (uint8_t)flag); } + void clearBit(StatusBits flag, int condition) noexcept { adjustStatusFlags(clearBit(F(), flag, condition)); } + static [[nodiscard]] constexpr uint8_t clearBit(uint8_t f, StatusBits flag, int condition) noexcept { return Chip::clearBit(f, (uint8_t)flag, condition); } + + void adjustSign(uint8_t value) noexcept { adjustStatusFlags(adjustSign(F(), value)); } + static [[nodiscard]] uint8_t adjustSign(uint8_t input, uint8_t value) noexcept { return setBit(input, SF, signTest(value)); } + + void adjustZero(uint8_t value) noexcept { adjustStatusFlags(adjustZero(F(), value)); } + static [[nodiscard]] constexpr uint8_t adjustZero(uint8_t input, uint8_t value) noexcept { return clearBit(input, ZF, value); } + + void adjustParity(uint8_t value) noexcept { adjustStatusFlags(adjustParity(F(), value)); } + static [[nodiscard]] constexpr uint8_t adjustParity(uint8_t input, uint8_t value) noexcept { return setBit(input, PF, evenParity(value)); } + + void adjustSZ(uint8_t value) noexcept { adjustStatusFlags(adjustSZ(F(), value)); } + static [[nodiscard]] uint8_t adjustSZ(uint8_t input, uint8_t value) noexcept { + input = adjustSign(input, value); + return adjustZero(input, value); + } + + void adjustSZP(uint8_t value) noexcept { adjustStatusFlags(adjustSZP(F(), value)); } + static [[nodiscard]] uint8_t adjustSZP(uint8_t input, uint8_t value) noexcept { + input = adjustSZ(input, value); + return adjustParity(input, value); + } + + void adjustXY(uint8_t value) noexcept { adjustStatusFlags(adjustXY(F(), value)); } + static [[nodiscard]] constexpr uint8_t adjustXY(uint8_t input, uint8_t value) noexcept { + input = setBit(input, XF, xTest(value)); + return setBit(input, YF, yTest(value)); + } + + void adjustSZPXY(uint8_t value) noexcept { adjustStatusFlags(adjustSZPXY(F(), value)); } + static [[nodiscard]] uint8_t adjustSZPXY(uint8_t input, uint8_t value) noexcept { + input = adjustSZP(input, value); + return adjustXY(input, value); + } + + void adjustSZXY(uint8_t value) noexcept { adjustStatusFlags(adjustSZXY(F(), value)); } + static [[nodiscard]] uint8_t adjustSZXY(uint8_t input, uint8_t value) noexcept { + input = adjustSZ(input, value); + return adjustXY(input, value); + } + [[nodiscard]] static constexpr auto adjustHalfCarryAdd(uint8_t f, uint8_t before, uint8_t value, int calculation) noexcept { return setBit(f, HC, calculateHalfCarryAdd(before, value, calculation)); } + void adjustHalfCarryAdd(uint8_t before, uint8_t value, int calculation) noexcept { + adjustStatusFlags(adjustHalfCarryAdd(F(), before, value, calculation)); + } + [[nodiscard]] static constexpr auto adjustHalfCarrySub(uint8_t f, uint8_t before, uint8_t value, int calculation) noexcept { return setBit(f, HC, calculateHalfCarrySub(before, value, calculation)); } - [[nodiscard]] static constexpr auto adjustOverflowAdd(uint8_t f, int beforeNegative, int valueNegative, int afterNegative) noexcept { - const auto overflow = (beforeNegative == valueNegative) && (beforeNegative != afterNegative); - return setBit(f, VF, overflow); + void adjustHalfCarrySub(uint8_t before, uint8_t value, int calculation) noexcept { + adjustStatusFlags(adjustHalfCarrySub(F(), before, value, calculation)); } - [[nodiscard]] static constexpr auto adjustOverflowAdd(uint8_t f, uint8_t before, uint8_t value, uint8_t calculation) noexcept { - return adjustOverflowAdd(f, before & SF, value & SF, calculation & SF); + void adjustOverflowAdd(int beforeNegative, int valueNegative, int afterNegative) { + adjustStatusFlags(adjustOverflowAdd(F(), beforeNegative, valueNegative, afterNegative)); } - [[nodiscard]] static constexpr auto adjustOverflowSub(uint8_t f, int beforeNegative, int valueNegative, int afterNegative) noexcept { - const auto overflow = (beforeNegative != valueNegative) && (beforeNegative != afterNegative); - return setBit(f, VF, overflow); + [[nodiscard]] static uint8_t adjustOverflowAdd(uint8_t input, int beforeNegative, int valueNegative, int afterNegative) { + const auto overflow = beforeNegative == valueNegative && beforeNegative != afterNegative; + return setBit(input, VF, overflow); } - [[nodiscard]] static constexpr auto adjustOverflowSub(uint8_t f, uint8_t before, uint8_t value, uint8_t calculation) noexcept { - return adjustOverflowSub(f, before & SF, value & SF, calculation & SF); + void adjustOverflowAdd(uint8_t before, uint8_t value, uint8_t calculation) { + adjustStatusFlags(adjustOverflowAdd(F(), before, value, calculation)); } - [[nodiscard]] static constexpr bool convertCondition(uint8_t f, int flag) noexcept { + [[nodiscard]] static uint8_t adjustOverflowAdd(uint8_t input, uint8_t before, uint8_t value, uint8_t calculation) { + return adjustOverflowAdd(input, signTest(before), signTest(value), signTest(calculation)); + } + + void adjustOverflowSub(int beforeNegative, int valueNegative, int afterNegative) { + adjustStatusFlags(adjustOverflowSub(F(), beforeNegative, valueNegative, afterNegative)); + } + + [[nodiscard]] static uint8_t adjustOverflowSub(uint8_t input, int beforeNegative, int valueNegative, int afterNegative) { + const auto overflow = beforeNegative != valueNegative && beforeNegative != afterNegative; + return setBit(input, VF, overflow); + } + + void adjustOverflowSub(uint8_t before, uint8_t value, uint8_t calculation) { + adjustStatusFlags(adjustOverflowSub(F(), before, value, calculation)); + } + + [[nodiscard]] static uint8_t adjustOverflowSub(uint8_t input, uint8_t before, uint8_t value, uint8_t calculation) { + return adjustOverflowSub(input, signTest(before), signTest(value), signTest(calculation)); + } + + [[nodiscard]] constexpr bool convertCondition(int flag) noexcept { switch (flag) { case 0: - return !(f & ZF); + return zero() == 0; case 1: - return f & ZF; + return zero() != 0; case 2: - return !(f & CF); + return carry() == 0; case 3: - return f & CF; + return carry() != 0; case 4: - return !(f & PF); + return parity() == 0; case 5: - return f & PF; + return parity() != 0; case 6: - return !(f & SF); + return sign() == 0; case 7: - return f & SF; + return sign() != 0; default: UNREACHABLE; } } - static constexpr auto subtract(uint8_t& f, uint8_t operand, uint8_t value, int carry = 0) noexcept { + auto subtract(uint8_t operand, uint8_t value, int carry = 0) noexcept { + const register16_t subtraction = operand - value - carry; const auto result = subtraction.low; - f = adjustHalfCarrySub(f, operand, value, result); - f = adjustOverflowSub(f, operand, value, result); + adjustHalfCarrySub(operand, value, result); + adjustOverflowSub(operand, value, result); - f = setBit(f, NF); - f = setBit(f, CF, subtraction.high & CF); - f = adjustSZ(f, result); + setBit(NF); + setBit(CF, carryTest(subtraction.high)); + adjustSZ(result); return result; } @@ -289,21 +373,21 @@ namespace EightBit { void executeED(int x, int y, int z, int p, int q) noexcept; void executeOther(int x, int y, int z, int p, int q) noexcept; - [[nodiscard]] static constexpr auto increment(uint8_t& f, uint8_t operand) noexcept { - f = clearBit(f, NF); + [[nodiscard]] auto increment(uint8_t operand) noexcept { + clearBit(NF); const uint8_t result = operand + 1; - f = adjustSZXY(f, result); - f = setBit(f, VF, result == Bit7); - f = clearBit(f, HC, lowNibble(result)); + adjustSZXY(result); + setBit(VF, result == Bit7); + clearBit(HC, lowNibble(result)); return result; } - [[nodiscard]] static constexpr auto decrement(uint8_t& f, uint8_t operand) noexcept { - f = setBit(f, NF); - f = clearBit(f, HC, lowNibble(operand)); + [[nodiscard]] auto decrement(uint8_t operand) noexcept { + setBit(NF); + clearBit(HC, lowNibble(operand)); const uint8_t result = operand - 1; - f = adjustSZXY(f, result); - f = setBit(f, VF, result == Mask7); + adjustSZXY(result); + setBit(VF, result == Mask7); return result; } @@ -313,156 +397,153 @@ namespace EightBit { void retn() noexcept; void reti() noexcept; - void returnConditionalFlag(uint8_t f, int flag) noexcept; - void jrConditionalFlag(uint8_t f, int flag) noexcept; - void callConditionalFlag(uint8_t f, int flag) noexcept; - void jumpConditionalFlag(uint8_t f, int flag) noexcept; + void returnConditionalFlag(int flag) noexcept; + void jrConditionalFlag(int flag) noexcept; + void callConditionalFlag(int flag) noexcept; + void jumpConditionalFlag(int flag) noexcept; - [[nodiscard]] register16_t sbc(uint8_t& f, register16_t operand, register16_t value) noexcept; - [[nodiscard]] register16_t adc(uint8_t& f, register16_t operand, register16_t value) noexcept; - [[nodiscard]] register16_t add(uint8_t& f, register16_t operand, register16_t value, int carry = 0) noexcept; + [[nodiscard]] register16_t sbc(register16_t operand, register16_t value) noexcept; + [[nodiscard]] register16_t adc(register16_t operand, register16_t value) noexcept; + [[nodiscard]] register16_t add(register16_t operand, register16_t value, int carry = 0) noexcept; - [[nodiscard]] static constexpr auto add(uint8_t& f, uint8_t operand, uint8_t value, int carry = 0) noexcept { - const register16_t addition = operand + value + carry; - const auto result = addition.low; + [[nodiscard]] auto add(uint8_t operand, uint8_t value, int carry = 0) noexcept { - f = adjustHalfCarryAdd(f, operand, value, result); - f = adjustOverflowAdd(f, operand, value, result); + intermediate() = operand + value + carry; + const auto result = intermediate().low; - f = clearBit(f, NF); - f = setBit(f, CF, addition.high & CF); - f = adjustSZXY(f, result); + adjustHalfCarryAdd(operand, value, result); + adjustOverflowAdd(operand, value, result); + + clearBit(NF); + setBit(CF, carryTest(intermediate().high)); + adjustSZXY(result); return result; } - [[nodiscard]] static constexpr auto adc(uint8_t& f, uint8_t operand, uint8_t value) noexcept { - return add(f, operand, value, f & CF); + [[nodiscard]] auto adc(uint8_t operand, uint8_t value) noexcept { + return add(operand, value, carry()); } - [[nodiscard]] static constexpr auto sub(uint8_t& f, uint8_t operand, uint8_t value, int carry = 0) noexcept { - const auto subtraction = subtract(f, operand, value, carry); - f = adjustSZXY(f, subtraction); + [[nodiscard]] auto sub(uint8_t operand, uint8_t value, int carry = 0) noexcept { + const auto subtraction = subtract(operand, value, carry); + adjustSZXY(subtraction); return subtraction; } - [[nodiscard]] static constexpr auto sbc(uint8_t& f, uint8_t operand, uint8_t value) noexcept { - return sub(f, operand, value, f & CF); + [[nodiscard]] auto sbc(uint8_t operand, uint8_t value) noexcept { + return sub(operand, value, carry()); } - [[nodiscard]] static constexpr auto andr(uint8_t& f, uint8_t operand, uint8_t value) noexcept { - f = setBit(f, HC); - f = clearBit(f, CF | NF); - const uint8_t result = operand & value; - f = adjustSZPXY(f, result); - return result; + [[nodiscard]] void andr(uint8_t value) noexcept { + setBit(HC); + clearBit((StatusBits)(CF | NF)); + adjustSZPXY(A() &= value); } - [[nodiscard]] static constexpr auto xorr(uint8_t& f, uint8_t operand, uint8_t value) noexcept { - f = clearBit(f, HC | CF | NF); - const uint8_t result = operand ^ value; - f = adjustSZPXY(f, result); - return result; + [[nodiscard]] void xorr(uint8_t value) noexcept { + clearBit((StatusBits)(HC | CF | NF)); + adjustSZPXY(A() ^= value); } - [[nodiscard]] static constexpr auto orr(uint8_t& f, uint8_t operand, uint8_t value) noexcept { - f = clearBit(f, HC | CF | NF); - const uint8_t result = operand | value; - f = adjustSZPXY(f, result); - return result; + [[nodiscard]] void orr(uint8_t value) noexcept { + clearBit((StatusBits)(HC | CF | NF)); + adjustSZPXY(A() |= value); } - static void compare(uint8_t& f, uint8_t operand, uint8_t value) noexcept { - subtract(f, operand, value); - f = adjustXY(f, value); + void compare(uint8_t value) noexcept { + subtract(A(), value); + adjustXY(value); } - [[nodiscard]] static constexpr auto rlc(uint8_t& f, uint8_t operand) noexcept { - f = clearBit(f, NF | HC); + [[nodiscard]] auto rlc(uint8_t operand) noexcept { + clearBit((StatusBits)(NF | HC)); const auto carry = operand & Bit7; - f = setBit(f, CF, carry); + setBit(CF, carry); const uint8_t result = (operand << 1) | (carry >> 7); - f = adjustXY(f, result); + adjustXY(result); return result; } - [[nodiscard]] static constexpr auto rrc(uint8_t& f, uint8_t operand) noexcept { - f = clearBit(f, NF | HC); + [[nodiscard]] auto rrc(uint8_t operand) noexcept { + clearBit((StatusBits)(NF | HC)); const auto carry = operand & Bit0; - f = setBit(f, CF, carry); + setBit(CF, carry); const uint8_t result = (operand >> 1) | (carry << 7); - f = adjustXY(f, result); + adjustXY(result); return result; } - [[nodiscard]] static constexpr auto rl(uint8_t& f, uint8_t operand) noexcept { - f = clearBit(f, NF | HC); - const auto carry = f & CF; - f = setBit(f, CF, operand & Bit7); - const uint8_t result = (operand << 1) | carry; - f = adjustXY(f, result); + [[nodiscard]] auto rl(uint8_t operand) noexcept { + clearBit((StatusBits)(NF | HC)); + const auto carrying = carry(); + setBit(CF, operand & Bit7); + const uint8_t result = (operand << 1) | carrying; + adjustXY(result); return result; } - [[nodiscard]] static constexpr auto rr(uint8_t& f, uint8_t operand) noexcept { - f = clearBit(f, NF | HC); - const auto carry = f & CF; - f = setBit(f, CF, operand & Bit0); - const uint8_t result = (operand >> 1) | (carry << 7); - f = adjustXY(f, result); + [[nodiscard]] auto rr(uint8_t operand) noexcept { + clearBit((StatusBits)(NF | HC)); + const auto carrying = carry(); + setBit(CF, operand & Bit0); + const uint8_t result = (operand >> 1) | (carrying << 7); + adjustXY(result); return result; } - [[nodiscard]] static constexpr auto sla(uint8_t& f, uint8_t operand) noexcept { - f = clearBit(f, NF | HC); - f = setBit(f, CF, operand & Bit7); + [[nodiscard]] auto sla(uint8_t operand) noexcept { + clearBit((StatusBits)(NF | HC)); + setBit(CF, operand & Bit7); const uint8_t result = operand << 1; - f = adjustXY(f, result); + adjustXY(result); return result; } - [[nodiscard]] static constexpr auto sra(uint8_t& f, uint8_t operand) noexcept { - f = clearBit(f, NF | HC); - f = setBit(f, CF, operand & Bit0); + [[nodiscard]] auto sra(uint8_t operand) noexcept { + clearBit((StatusBits)(NF | HC)); + setBit(CF, operand & Bit0); const uint8_t result = (operand >> 1) | (operand & Bit7); - f = adjustXY(f, result); + adjustXY(result); return result; } - [[nodiscard]] static constexpr auto sll(uint8_t& f, uint8_t operand) noexcept { - f = clearBit(f, NF | HC); - f = setBit(f, CF, operand & Bit7); + [[nodiscard]] auto sll(uint8_t operand) noexcept { + clearBit((StatusBits)(NF | HC)); + setBit(CF, operand & Bit7); const uint8_t result = (operand << 1) | Bit0; - f = adjustXY(f, result); + adjustXY(result); return result; } - [[nodiscard]] static constexpr auto srl(uint8_t& f, uint8_t operand) noexcept { - f = clearBit(f, NF | HC); - f = setBit(f, CF, operand & Bit0); + [[nodiscard]] auto srl(uint8_t operand) noexcept { + clearBit((StatusBits)(NF | HC)); + setBit(CF, operand & Bit0); const uint8_t result = (operand >> 1) & ~Bit7; - f = adjustXY(f, result); - f = setBit(f, ZF, result); + adjustXY(result); + setBit(ZF, result); return result; } - static constexpr void bit(uint8_t& f, int n, uint8_t operand) noexcept { - f = setBit(f, HC); - f = clearBit(f, NF); + void bit(int n, uint8_t operand) noexcept { + setBit(HC); + clearBit(NF); const auto discarded = operand & Chip::bit(n); - f = adjustSZ(f, discarded); - f = clearBit(f, PF, discarded); + adjustSZ(discarded); + clearBit(PF, discarded); } - [[nodiscard]] static constexpr auto res(int n, uint8_t operand) noexcept { return clearBit(operand, Chip::bit(n)); } - [[nodiscard]] static constexpr auto set(int n, uint8_t operand) noexcept { return setBit(operand, Chip::bit(n)); } + [[nodiscard]] static constexpr auto res(int n, uint8_t operand) noexcept { return Chip::clearBit(operand, Chip::bit(n)); } + [[nodiscard]] static constexpr auto set(int n, uint8_t operand) noexcept { return Chip::setBit(operand, Chip::bit(n)); } - [[nodiscard]] static constexpr auto daa(uint8_t& f, uint8_t operand) noexcept { - const auto lowAdjust = (f & HC) || (lowNibble(operand) > 9); - const auto highAdjust = (f & CF) || (operand > 0x99); + [[nodiscard]] void daa() noexcept { - auto updated = operand; - if (f & NF) { + auto updated = A(); + + const auto lowAdjust = halfCarry() || (lowNibble(A()) > 9); + const auto highAdjust = carry() || (A() > 0x99); + + if (subtracting()) { if (lowAdjust) updated -= 6; if (highAdjust) @@ -474,90 +555,95 @@ namespace EightBit { updated += 0x60; } - f = (f & (CF | NF)) | (operand > 0x99 ? CF : 0) | ((operand ^ updated) & HC); - - f = adjustSZPXY(f, updated); - - return updated; + adjustStatusFlags((F() & (CF | NF) | (A() > 0x99 ? CF : 0) | halfCarryTest(A() ^ updated))); + adjustSZPXY(A() = updated); } - static constexpr void scf(uint8_t& f, uint8_t operand) noexcept { - f = setBit(f, CF); - f = clearBit(f, HC | NF); - f = adjustXY(f, operand); + void scf(uint8_t operand) noexcept { + setBit(CF); + clearBit((StatusBits)(HC | NF)); + adjustXY((Q() ^ F()) | A()); } - static constexpr void ccf(uint8_t& f, uint8_t operand) noexcept { - f = clearBit(f, NF); - const auto carry = f & CF; - f = setBit(f, HC, carry); - f = clearBit(f, CF, carry); - f = adjustXY(f, operand); + void ccf(uint8_t operand) noexcept { + clearBit(NF); + const auto carrying = carry(); + setBit(HC, carrying); + clearBit(CF, carrying); + adjustXY(((Q() ^ F()) | A())); } - [[nodiscard]] static constexpr auto cpl(uint8_t& f, uint8_t operand) noexcept { - f = setBit(f, HC | NF); - const uint8_t result = ~operand; - f = adjustXY(f, result); - return result; + void cpl() noexcept { + setBit((StatusBits)(HC | NF)); + adjustXY(A() = ~A()); } void xhtl(register16_t& exchange) noexcept; - void blockCompare(uint8_t& f, uint8_t value, register16_t source, register16_t& counter) noexcept; + void blockCompare() noexcept; - void cpi(uint8_t& f, uint8_t value) noexcept; - [[nodiscard]] bool cpir(uint8_t& f, uint8_t value) noexcept; + void cpi() noexcept; + void cpir() noexcept; - void cpd(uint8_t& f, uint8_t value) noexcept; - [[nodiscard]] bool cpdr(uint8_t& f, uint8_t value) noexcept; + void cpd() noexcept; + void cpdr() noexcept; - void blockLoad(uint8_t& f, uint8_t a, register16_t source, register16_t destination, register16_t& counter) noexcept; + void blockLoad() noexcept; - void ldi(uint8_t& f, uint8_t a) noexcept; - [[nodiscard]] bool ldir(uint8_t& f, uint8_t a) noexcept; + void ldi() noexcept; + void ldir() noexcept; - void ldd(uint8_t& f, uint8_t a) noexcept; - [[nodiscard]] bool lddr(uint8_t& f, uint8_t a) noexcept; + void ldd() noexcept; + void lddr() noexcept; - void blockIn(register16_t& source, register16_t destination) noexcept; + void repeatBlockInstruction(); + void adjustBlockRepeatFlagsIO(); + void adjustBlockInputOutputFlags(int basis); + void adjustBlockInFlagsIncrement(); + void adjustBlockInFlagsDecrement(); + void adjustBlockOutFlags(); + + void blockIn() noexcept; void ini() noexcept; - [[nodiscard]] bool inir() noexcept; + void inir() noexcept; void ind() noexcept; - [[nodiscard]] bool indr() noexcept; + void indr() noexcept; - void blockOut(register16_t source, register16_t& destination) noexcept; + void blockOut() noexcept; void outi() noexcept; - [[nodiscard]] bool otir() noexcept; + void otir() noexcept; void outd() noexcept; - [[nodiscard]] bool otdr() noexcept; + void otdr() noexcept; - [[nodiscard]] static constexpr auto neg(uint8_t& f, uint8_t operand) noexcept { - f = setBit(f, PF, operand == Bit7); - f = setBit(f, CF, operand); - f = setBit(f, NF); + void neg() noexcept { - const uint8_t result = (~operand + 1); // two's complement + setBit(PF, A() == Bit7); + setBit(CF, A()); + setBit(NF); - f = adjustHalfCarrySub(f, 0U, operand, result); - f = adjustOverflowSub(f, 0U, operand, result); + auto original = A(); - f = adjustSZXY(f, result); + A() = (~A() + 1); // two's complement - return result; + adjustHalfCarrySub(0U, original, A()); + adjustOverflowSub(0U, original, A()); + + adjustSZXY(A()); } - void rrd(uint8_t& f, register16_t address, uint8_t& update) noexcept; - void rld(uint8_t& f, register16_t address, uint8_t& update) noexcept; + void rrd(register16_t address, uint8_t& update) noexcept; + void rld(register16_t address, uint8_t& update) noexcept; - void portWrite(uint8_t port) noexcept; - void portWrite() noexcept; + void writePort(register16_t port) noexcept; + void writePort(uint8_t port) noexcept; + void writePort() noexcept; - void portRead(uint8_t port) noexcept; - void portRead() noexcept; + void readPort(register16_t port) noexcept; + void readPort(uint8_t port) noexcept; + void readPort() noexcept; }; } \ No newline at end of file diff --git a/Z80/src/Z80.cpp b/Z80/src/Z80.cpp index 8ee43b3..32da279 100644 --- a/Z80/src/Z80.cpp +++ b/Z80/src/Z80.cpp @@ -246,22 +246,22 @@ void EightBit::Z80::enableInterrupts() { IFF1() = IFF2() = true; } -void EightBit::Z80::returnConditionalFlag(const uint8_t f, const int flag) noexcept { +void EightBit::Z80::returnConditionalFlag(const int flag) noexcept { tick(); - if (convertCondition(f, flag)) + if (convertCondition(flag)) ret(); } -void EightBit::Z80::jrConditionalFlag(const uint8_t f, const int flag) noexcept { - jrConditional(convertCondition(f, flag)); +void EightBit::Z80::jrConditionalFlag(const int flag) noexcept { + jrConditional(convertCondition(flag)); } -void EightBit::Z80::jumpConditionalFlag(const uint8_t f, const int flag) noexcept { - jumpConditional(convertCondition(f, flag)); +void EightBit::Z80::jumpConditionalFlag(const int flag) noexcept { + jumpConditional(convertCondition(flag)); } -void EightBit::Z80::callConditionalFlag(const uint8_t f, const int flag) noexcept { - callConditional(convertCondition(f, flag)); +void EightBit::Z80::callConditionalFlag(const int flag) noexcept { + callConditional(convertCondition(flag)); } void EightBit::Z80::retn() noexcept { @@ -284,59 +284,59 @@ int EightBit::Z80::jrConditional(const int condition) noexcept { return condition; } -EightBit::register16_t EightBit::Z80::sbc(uint8_t& f, const register16_t operand, const register16_t value) noexcept { +EightBit::register16_t EightBit::Z80::sbc(const register16_t operand, const register16_t value) noexcept { - const auto subtraction = operand.word - value.word - (f & CF); - const register16_t result = subtraction; + const auto subtraction = operand.word - value.word - carry(); + intermediate() = subtraction; - f = setBit(f, NF); - f = setBit(f, ZF, result.zero()); - f = setBit(f, CF, subtraction & Bit16); - f = adjustHalfCarrySub(f, operand.high, value.high, result.high); - f = adjustXY(f, result.high); + setBit(NF); + setBit(ZF, intermediate().zero()); + setBit(CF, subtraction & Bit16); + adjustHalfCarrySub(operand.high, value.high, intermediate().high); + adjustXY(intermediate().high); - const auto beforeNegative = operand.high & SF; - const auto valueNegative = value.high & SF; - const auto afterNegative = result.high & SF; + const auto beforeNegative = signTest(operand.high); + const auto valueNegative = signTest(value.high); + const auto afterNegative = signTest(intermediate().high); - f = setBit(f, SF, afterNegative); - f = adjustOverflowSub(f, beforeNegative, valueNegative, afterNegative); + setBit(SF, afterNegative); + adjustOverflowSub(beforeNegative, valueNegative, afterNegative); MEMPTR() = operand + 1; tick(7); - return result; + return intermediate(); } -EightBit::register16_t EightBit::Z80::adc(uint8_t& f, const register16_t operand, const register16_t value) noexcept { +EightBit::register16_t EightBit::Z80::adc(const register16_t operand, const register16_t value) noexcept { - const auto result = add(f, operand, value, f & CF); - f = setBit(f, ZF, result.zero()); + auto _ = add(operand, value, carry()); + setBit(ZF, intermediate().zero()); - const auto beforeNegative = operand.high & SF; - const auto valueNegative = value.high & SF; - const auto afterNegative = result.high & SF; + const auto beforeNegative = signTest(operand.high); + const auto valueNegative = signTest(value.high); + const auto afterNegative = signTest(intermediate().high); - f = setBit(f, SF, afterNegative); - f = adjustOverflowAdd(f, beforeNegative, valueNegative, afterNegative); + setBit(SF, afterNegative); + adjustOverflowAdd(beforeNegative, valueNegative, afterNegative); - return result; + return intermediate(); } -EightBit::register16_t EightBit::Z80::add(uint8_t& f, const register16_t operand, const register16_t value, int carry) noexcept { +EightBit::register16_t EightBit::Z80::add(const register16_t operand, const register16_t value, int carry) noexcept { - const int addition = operand.word + value.word + carry; - const register16_t result = addition; + const auto addition = operand.word + value.word + carry; + intermediate().word = addition; - f = clearBit(f, NF); - f = setBit(f, CF, addition & Bit16); - f = adjustHalfCarryAdd(f, operand.high, value.high, result.high); - f = adjustXY(f, result.high); + clearBit(NF); + setBit(CF, addition & Bit16); + adjustHalfCarryAdd(operand.high, value.high, intermediate().high); + adjustXY(intermediate().high); MEMPTR() = operand + 1; tick(7); - return result; + return intermediate(); } void EightBit::Z80::xhtl(register16_t& exchange) noexcept { @@ -352,211 +352,273 @@ void EightBit::Z80::xhtl(register16_t& exchange) noexcept { tick(2); } -void EightBit::Z80::blockCompare(uint8_t& f, const uint8_t value, const register16_t source, register16_t& counter) noexcept { +void EightBit::Z80::blockCompare() noexcept { - const auto contents = IntelProcessor::memoryRead(source); - uint8_t result = value - contents; + IntelProcessor::memoryRead(HL()); + uint8_t result = A() - BUS().DATA(); - f = setBit(f, PF, --counter.word); + setBit(PF, --BC().word); - f = adjustSZ(f, result); - f = adjustHalfCarrySub(f, value, contents, result); - f = setBit(f, NF); + adjustSZ(result); + adjustHalfCarrySub(A(), BUS().DATA(), result); + setBit(NF); - result -= ((f & HC) >> 4); + result -= (halfCarry() >> 4); - f = setBit(f, YF, result & Bit1); - f = setBit(f, XF, result & Bit3); + setBit(YF, result & Bit1); + setBit(XF, result & Bit3); tick(5); } -void EightBit::Z80::cpi(uint8_t& f, uint8_t value) noexcept { - blockCompare(f, value, HL()++, BC()); +void EightBit::Z80::cpi() noexcept { + blockCompare(); + ++HL(); ++MEMPTR(); } -void EightBit::Z80::cpd(uint8_t& f, uint8_t value) noexcept { - blockCompare(f, value, HL()--, BC()); +void EightBit::Z80::cpd() noexcept { + blockCompare(); + --HL(); --MEMPTR(); } -bool EightBit::Z80::cpir(uint8_t& f, uint8_t value) noexcept { - cpi(f, value); - return (f & PF) && !(f & ZF); // See CPI +void EightBit::Z80::cpir() noexcept { + cpi(); + if (parity() != 0 && zero() == 0) { + repeatBlockInstruction(); + tick(5); + } } -bool EightBit::Z80::cpdr(uint8_t& f, uint8_t value) noexcept { - cpd(f, value); - return (f & PF) && !(f & ZF); // See CPD +void EightBit::Z80::cpdr() noexcept { + cpd(); + if (parity() != 0 && zero() == 0) { + repeatBlockInstruction(); + tick(5); + } else { + MEMPTR().word = PC().word - 2; + tick(2); + } } -void EightBit::Z80::blockLoad(uint8_t& f, const uint8_t a, const register16_t source, const register16_t destination, register16_t& counter) noexcept { - const auto value = IntelProcessor::memoryRead(source); - IntelProcessor::memoryWrite(destination); - const auto xy = a + value; - f = setBit(f, XF, xy & Bit3); - f = setBit(f, YF, xy & Bit1); - f = clearBit(f, NF | HC); - f = setBit(f, PF, --counter.word); +void EightBit::Z80::blockLoad() noexcept { + IntelProcessor::memoryRead(HL()); + IntelProcessor::memoryWrite(DE()); + const auto xy = A() + BUS().DATA(); + setBit(XF, xy & Bit3); + setBit(YF, xy & Bit1); + clearBit((StatusBits)(NF | HC)); + setBit(PF, --BC().word); tick(2); } -void EightBit::Z80::ldd(uint8_t& f, const uint8_t a) noexcept { - blockLoad(f, a, HL()--, DE()--, BC()); +void EightBit::Z80::ldd() noexcept { + blockLoad(); + --HL(); + --DE(); } -void EightBit::Z80::ldi(uint8_t& f, const uint8_t a) noexcept { - blockLoad(f, a, HL()++, DE()++, BC()); +void EightBit::Z80::ldi() noexcept { + blockLoad(); + ++HL(); + ++DE(); } -bool EightBit::Z80::ldir(uint8_t& f, const uint8_t a) noexcept { - ldi(f, a); - return !!(f & PF); // See LDI +void EightBit::Z80::ldir() noexcept { + ldi(); + if (parity() != 0) + repeatBlockInstruction(); + tick(5); } -bool EightBit::Z80::lddr(uint8_t& f, const uint8_t a) noexcept { - ldd(f, a); - return !!(f & PF); // See LDD +void EightBit::Z80::lddr() noexcept { + ldd(); + if (parity() != 0) + repeatBlockInstruction(); + tick(5); } -void EightBit::Z80::blockIn(register16_t& source, const register16_t destination) noexcept { - MEMPTR() = BUS().ADDRESS() = source; +void EightBit::Z80::repeatBlockInstruction() +{ + MEMPTR() = --PC(); + --PC(); + adjustXY(PC().high); +} + +void EightBit::Z80::adjustBlockRepeatFlagsIO() { + if (carry() != 0) { + const auto negative = signTest(BUS().DATA()) != 0; + const uint8_t direction = B() + (negative ? -1 : +1); + const auto calculatedParity = (parity() >> 2) ^ (evenParity(direction & Mask::Mask3) ? 1 : 0) ^ 1; + setBit(PF, calculatedParity != 0); + setBit(HC, (B() & Mask::Mask4) == (negative ? 0 : Mask::Mask4)); + } else { + adjustParity((B() & Mask::Mask3)); + } +} + +void EightBit::Z80::adjustBlockInputOutputFlags(int basis) { + setBit((StatusBits)(HC | CF), basis > 0xff); + adjustParity(((basis & (int)Mask::Mask3) ^ B())); +} + +void EightBit::Z80::adjustBlockInFlagsIncrement() { + adjustBlockInputOutputFlags((C() + 1) + BUS().DATA()); +} + +void EightBit::Z80::adjustBlockInFlagsDecrement() { + adjustBlockInputOutputFlags((C() - 1) + BUS().DATA()); +} + +void EightBit::Z80::adjustBlockOutFlags() { + // HL needs to have been incremented or decremented prior to this call + setBit(NF, signTest(BUS().DATA())); + adjustBlockInputOutputFlags(L() + BUS().DATA()); +} + +void EightBit::Z80::blockIn() noexcept { tick(); - portRead(); - BUS().ADDRESS() = destination; + readPort(BC()); + BUS().ADDRESS() = HL(); memoryWrite(); - source.high = decrement(F(), source.high); + adjustSZXY(--B()); F() = setBit(F(), NF); } void EightBit::Z80::ini() noexcept { - blockIn(BC(), HL()++); + blockIn(); + ++HL(); ++MEMPTR(); } void EightBit::Z80::ind() noexcept { - blockIn(BC(), HL()--); + blockIn(); + --HL(); --MEMPTR(); } -bool EightBit::Z80::inir() noexcept { +void EightBit::Z80::inir() noexcept { ini(); - return !(F() & ZF); // See INI + if (zero() == 0) { + repeatBlockInstruction(); + adjustBlockRepeatFlagsIO(); + tick(5); + } } -bool EightBit::Z80::indr() noexcept { +void EightBit::Z80::indr() noexcept { ind(); - return !(F() & ZF); // See IND + if (zero() == 0) { + repeatBlockInstruction(); + adjustBlockRepeatFlagsIO(); + tick(5); + } } -void EightBit::Z80::blockOut(const register16_t source, register16_t& destination) noexcept { +void EightBit::Z80::blockOut() noexcept { tick(); - const auto value = IntelProcessor::memoryRead(source); - destination.high = decrement(F(), destination.high); - BUS().ADDRESS() = destination; - portWrite(); - MEMPTR() = destination; - F() = setBit(F(), NF, value & Bit7); - F() = setBit(F(), HC | CF, (L() + value) > 0xff); - F() = adjustParity(F(), ((value + L()) & Mask3) ^ B()); + Processor::memoryRead(HL()); + B() = decrement(B()); + writePort(BC()); } void EightBit::Z80::outi() noexcept { - blockOut(HL()++, BC()); + blockOut(); + ++HL(); + adjustBlockOutFlags(); ++MEMPTR(); } void EightBit::Z80::outd() noexcept { - blockOut(HL()--, BC()); + blockOut(); + --HL(); + adjustBlockOutFlags(); --MEMPTR(); } -bool EightBit::Z80::otir() noexcept { +void EightBit::Z80::otir() noexcept { outi(); - return !(F() & ZF); // See OUTI + if (zero() == 0) { + repeatBlockInstruction(); + adjustBlockRepeatFlagsIO(); + tick(5); + } } -bool EightBit::Z80::otdr() noexcept { +void EightBit::Z80::otdr() noexcept { outd(); - return !(F() & ZF); // See OUTD + if (zero() == 0) { + repeatBlockInstruction(); + adjustBlockRepeatFlagsIO(); + tick(5); + } } -void EightBit::Z80::rrd(uint8_t& f, register16_t address, uint8_t& update) noexcept { +void EightBit::Z80::rrd(register16_t address, uint8_t& update) noexcept { (MEMPTR() = BUS().ADDRESS() = address)++; const auto memory = memoryRead(); tick(4); IntelProcessor::memoryWrite(promoteNibble(update) | highNibble(memory)); update = higherNibble(update) | lowerNibble(memory); - f = adjustSZPXY(f, update); - f = clearBit(f, NF | HC); + adjustSZPXY(update); + clearBit((StatusBits)(NF | HC)); } -void EightBit::Z80::rld(uint8_t& f, register16_t address, uint8_t& update) noexcept { +void EightBit::Z80::rld(register16_t address, uint8_t& update) noexcept { (MEMPTR() = BUS().ADDRESS() = address)++; const auto memory = memoryRead(); tick(4); IntelProcessor::memoryWrite(promoteNibble(memory) | lowNibble(update)); update = higherNibble(update) | highNibble(memory); - f = adjustSZPXY(f, update); - f = clearBit(f, NF | HC); + adjustSZPXY(update); + clearBit((StatusBits)(NF | HC)); } -void EightBit::Z80::portWrite(const uint8_t port) noexcept { - MEMPTR() = BUS().ADDRESS() = { port, A() }; - BUS().DATA() = A(); - portWrite(); +void EightBit::Z80::writePort(const register16_t port) noexcept { + BUS().ADDRESS() = port; + writePort(); +} + +void EightBit::Z80::writePort(const uint8_t port) noexcept { + BUS().ADDRESS() = { port, BUS().DATA() = A() }; + writePort(); ++MEMPTR().low; } -void EightBit::Z80::portWrite() noexcept { - - class _Writer final { - Z80& m_parent; - public: - _Writer(Z80& parent) noexcept - : m_parent(parent) { - m_parent.WritingIO.fire(); - } - - ~_Writer() noexcept { - m_parent.WrittenIO.fire(); - m_parent.tick(3); - } - }; - - _Writer writer(*this); - _ActivateIORQ iorq(*this); +void EightBit::Z80::writePort() noexcept { + MEMPTR() = BUS().ADDRESS(); + //tick(2); + lowerIORQ(); + lowerWR(); + tick(); + m_ports.write(BUS().ADDRESS(), BUS().DATA()); + raiseWR(); + raiseIORQ(); tick(); - m_ports.writeOutputPort(BUS().ADDRESS().low, BUS().DATA()); } -void EightBit::Z80::portRead(const uint8_t port) noexcept { - MEMPTR() = BUS().ADDRESS() = { port, A() }; - ++MEMPTR().low; - portRead(); +void EightBit::Z80::readPort(register16_t port) noexcept { + BUS().ADDRESS() = port; + readPort(); } -void EightBit::Z80::portRead() noexcept { +void EightBit::Z80::readPort(const uint8_t port) noexcept { + BUS().ADDRESS() = { port, A() }; + readPort(); + ++MEMPTR(); +} - class _Reader final { - Z80& m_parent; - public: - _Reader(Z80& parent) noexcept - : m_parent(parent) { - m_parent.ReadingIO.fire(); - } - - ~_Reader() noexcept { - m_parent.ReadIO.fire(); - m_parent.tick(3); - } - }; - - _Reader reader(*this); - _ActivateIORQ iorq(*this); +void EightBit::Z80::readPort() noexcept { + MEMPTR() = BUS().ADDRESS(); + //tick(2); + tick(); + lowerIORQ(); + lowerRD(); + BUS().DATA() = m_ports.read(BUS().ADDRESS()); + raiseRD(); + raiseIORQ(); tick(); - BUS().DATA() = m_ports.readInputPort(BUS().ADDRESS().low); } // @@ -630,9 +692,9 @@ void EightBit::Z80::storeAccumulatorIndirect(addresser_t addresser) noexcept { } void EightBit::Z80::readInternalRegister(reader_t reader) noexcept { - F() = adjustSZXY(F(), A() = reader()); - F() = clearBit(F(), NF | HC); - F() = setBit(F(), PF, IFF2()); + adjustSZXY(A() = reader()); + clearBit((StatusBits)(NF | HC)); + setBit(PF, IFF2()); tick(); } @@ -761,7 +823,7 @@ void EightBit::Z80::R2(const int r, const uint8_t value) noexcept { int EightBit::Z80::step() noexcept { resetCycles(); - ExecutingInstruction.fire(*this); + ExecutingInstruction.fire(); if (LIKELY(powered())) { resetPrefixes(); bool handled = false; @@ -782,7 +844,7 @@ int EightBit::Z80::step() noexcept { if (!handled) IntelProcessor::execute(fetchOpCode()); } - ExecutedInstruction.fire(*this); + ExecutedInstruction.fire(); ASSUME(cycles() > 0); return cycles(); } @@ -824,37 +886,37 @@ void EightBit::Z80::executeCB(const int x, const int y, const int z) noexcept { case 0: { // rot[y] r[z] switch (y) { case 0: - operand = rlc(F(), operand); + operand = rlc(operand); break; case 1: - operand = rrc(F(), operand); + operand = rrc(operand); break; case 2: - operand = rl(F(), operand); + operand = rl(operand); break; case 3: - operand = rr(F(), operand); + operand = rr(operand); break; case 4: - operand = sla(F(), operand); + operand = sla(operand); break; case 5: - operand = sra(F(), operand); + operand = sra(operand); break; case 6: - operand = sll(F(), operand); + operand = sll(operand); break; case 7: - operand = srl(F(), operand); + operand = srl(operand); break; default: UNREACHABLE; } - F() = adjustSZP(F(), operand); + adjustSZP(operand); break; } case 1: // BIT y, r[z] - bit(F(), y, operand); - F() = adjustXY(F(), indirect ? MEMPTR().high : operand); + bit(y, operand); + adjustXY(indirect ? MEMPTR().high : operand); if (memoryZ) tick(); break; @@ -888,25 +950,25 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p case 1: switch (z) { case 0: // Input from port with 16-bit address - (MEMPTR() = BUS().ADDRESS() = BC())++; - portRead(); + readPort(BC()); + ++MEMPTR(); if (y != 6) // IN r[y],(C) R(y, BUS().DATA()); - F() = adjustSZPXY(F(), BUS().DATA()); - F() = clearBit(F(), NF | HC); + adjustSZPXY(BUS().DATA()); + clearBit((StatusBits)(NF | HC)); break; case 1: // Output to port with 16-bit address - (MEMPTR() = BUS().ADDRESS() = BC())++; BUS().DATA() = y == 6 ? 0 : R(y); - portWrite(); + writePort(BC()); + ++MEMPTR(); break; case 2: // 16-bit add/subtract with carry switch (q) { case 0: // SBC HL, rp[p] - HL2() = sbc(F(), HL2(), RP(p)); + HL2() = sbc(HL2(), RP(p)); break; case 1: // ADC HL, rp[p] - HL2() = adc(F(), HL2(), RP(p)); + HL2() = adc(HL2(), RP(p)); break; default: UNREACHABLE; @@ -926,7 +988,7 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p } break; case 4: // Negate accumulator - A() = neg(F(), A()); + neg(); break; case 5: // Return from interrupt switch (y) { @@ -976,10 +1038,10 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p tick(); break; case 4: // RRD - rrd(F(), HL(), A()); + rrd(HL(), A()); break; case 5: // RLD - rld(F(), HL(), A()); + rld(HL(), A()); break; case 6: // NOP case 7: // NOP @@ -997,51 +1059,32 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p case 0: // LD switch (y) { case 4: // LDI - ldi(F(), A()); + ldi(); break; case 5: // LDD - ldd(F(), A()); + ldd(); break; case 6: // LDIR - if (ldir(F(), A())) { - MEMPTR() = --PC(); - --PC(); - tick(5); - } + ldir(); break; case 7: // LDDR - if (lddr(F(), A())) { - MEMPTR() = --PC(); - --PC(); - tick(5); - } + lddr(); break; } break; case 1: // CP switch (y) { case 4: // CPI - cpi(F(), A()); + cpi(); break; case 5: // CPD - cpd(F(), A()); + cpd(); break; case 6: // CPIR - if (cpir(F(), A())) { - MEMPTR() = --PC(); - --PC(); - tick(5); - } + cpir(); break; case 7: // CPDR - if (cpdr(F(), A())) { - MEMPTR() = --PC(); - --PC(); - tick(5); - } else { - MEMPTR() = PC() - 2; - tick(2); - } + cpdr(); break; } break; @@ -1054,16 +1097,10 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p ind(); break; case 6: // INIR - if (inir()) { - PC() -= 2; - tick(5); - } + inir(); break; case 7: // INDR - if (indr()) { - PC() -= 2; - tick(5); - } + indr(); break; } break; @@ -1076,16 +1113,10 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p outd(); break; case 6: // OTIR - if (otir()) { - PC() -= 2; - tick(5); - } + otir(); break; case 7: // OTDR - if (otdr()) { - PC() -= 2; - tick(5); - } + otdr(); break; } break; @@ -1118,7 +1149,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in case 5: case 6: case 7: - jrConditionalFlag(F(), y - 4); + jrConditionalFlag(y - 4); break; default: UNREACHABLE; @@ -1130,7 +1161,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in RP(p) = fetchWord(); break; case 1: // ADD HL,rp - HL2() = add(F(), HL2(), RP(p)); + HL2() = add(HL2(), RP(p)); break; default: UNREACHABLE; @@ -1201,7 +1232,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in const auto original = R(y); if (memoryY) tick(); - R(y, increment(F(), original)); + R(y, increment(original)); break; } case 5: { // 8-bit DEC @@ -1212,7 +1243,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in const auto original = R(y); if (memoryY) tick(); - R(y, decrement(F(), original)); + R(y, decrement(original)); break; } case 6: { // 8-bit load immediate @@ -1227,28 +1258,28 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in case 7: // Assorted operations on accumulator/flags switch (y) { case 0: - A() = rlc(F(), A()); + A() = rlc(A()); break; case 1: - A() = rrc(F(), A()); + A() = rrc(A()); break; case 2: - A() = rl(F(), A()); + A() = rl(A()); break; case 3: - A() = rr(F(), A()); + A() = rr(A()); break; case 4: - A() = daa(F(), A()); + daa(); break; case 5: - A() = cpl(F(), A()); + cpl(); break; case 6: - scf(F(), A()); + scf(A()); break; case 7: - ccf(F(), A()); + ccf(A()); break; default: UNREACHABLE; @@ -1314,28 +1345,28 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in const auto value = R(z); switch (y) { case 0: // ADD A,r - A() = add(F(), A(), value); + A() = add(A(), value); break; case 1: // ADC A,r - A() = adc(F(), A(), value); + A() = adc(A(), value); break; case 2: // SUB r - A() = sub(F(), A(), value); + A() = sub(A(), value); break; case 3: // SBC A,r - A() = sbc(F(), A(), value); + A() = sbc(A(), value); break; case 4: // AND r - A() = andr(F(), A(), value); + andr(value); break; case 5: // XOR r - A() = xorr(F(), A(), value); + xorr(value); break; case 6: // OR r - A() = orr(F(), A(), value); + orr(value); break; case 7: // CP r - compare(F(), A(), value); + compare(value); break; default: UNREACHABLE; @@ -1345,7 +1376,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in case 3: switch (z) { case 0: // Conditional return - returnConditionalFlag(F(), y); + returnConditionalFlag(y); break; case 1: // POP & various ops switch (q) { @@ -1376,7 +1407,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in } break; case 2: // Conditional jump - jumpConditionalFlag(F(), y); + jumpConditionalFlag(y); break; case 3: // Assorted operations switch (y) { @@ -1393,10 +1424,10 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in } break; case 2: // OUT (n),A - portWrite(fetchByte()); + writePort(fetchByte()); break; case 3: // IN A,(n) - portRead(fetchByte()); + readPort(fetchByte()); A() = BUS().DATA(); break; case 4: // EX (SP),HL @@ -1416,7 +1447,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in } break; case 4: // Conditional call: CALL cc[y], nn - callConditionalFlag(F(), y); + callConditionalFlag(y); break; case 5: // PUSH & various ops switch (q) { @@ -1452,28 +1483,28 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in const auto operand = fetchByte(); switch (y) { case 0: // ADD A,n - A() = add(F(), A(), operand); + A() = add(A(), operand); break; case 1: // ADC A,n - A() = adc(F(), A(), operand); + A() = adc(A(), operand); break; case 2: // SUB n - A() = sub(F(), A(), operand); + A() = sub(A(), operand); break; case 3: // SBC A,n - A() = sbc(F(), A(), operand); + A() = sbc(A(), operand); break; case 4: // AND n - A() = andr(F(), A(), operand); + andr(operand); break; case 5: // XOR n - A() = xorr(F(), A(), operand); + xorr(operand); break; case 6: // OR n - A() = orr(F(), A(), operand); + orr(operand); break; case 7: // CP n - compare(F(), A(), operand); + compare(operand); break; default: UNREACHABLE; diff --git a/Z80/test/Board.cpp b/Z80/test/Board.cpp index fe4c845..6caa002 100644 --- a/Z80/test/Board.cpp +++ b/Z80/test/Board.cpp @@ -26,8 +26,8 @@ void Board::initialise() { lowerPOWER(); }); - m_cpu.ExecutingInstruction.connect([this] (EightBit::Z80& cpu) { - switch (cpu.PC().word) { + m_cpu.ExecutingInstruction.connect([this] (EightBit::EventArgs) { + switch (m_cpu.PC().word) { case 0x0: // CP/M warm start if (++m_warmstartCount == 2) { lowerPOWER(); @@ -44,18 +44,18 @@ void Board::initialise() { }); if (m_configuration.isProfileMode()) - m_cpu.ExecutingInstruction.connect([this] (EightBit::Z80& cpu) { - const auto pc = cpu.PC(); + m_cpu.ExecutingInstruction.connect([this] (EightBit::EventArgs) { + const auto pc = m_cpu.PC(); m_profiler.addAddress(pc.word); m_profiler.addInstruction(peek(pc)); }); if (m_configuration.isDebugMode()) - m_cpu.ExecutingInstruction.connect([this] (EightBit::Z80& cpu) { + m_cpu.ExecutingInstruction.connect([this] (EightBit::EventArgs) { std::cerr - << EightBit::Disassembler::state(cpu) + << EightBit::Disassembler::state(m_cpu) << "\t" - << m_disassembler.disassemble(cpu) + << m_disassembler.disassemble(m_cpu) << std::endl; }); diff --git a/inc/InputOutput.h b/inc/InputOutput.h index 1e6ef44..9393375 100644 --- a/inc/InputOutput.h +++ b/inc/InputOutput.h @@ -14,22 +14,18 @@ namespace EightBit { std::array _output = {}; public: - Signal ReadingPort; - Signal ReadPort; + Signal ReadingPort; + Signal ReadPort; - Signal WritingPort; - Signal WrittenPort; + Signal WritingPort; + Signal WrittenPort; [[nodiscard]] uint8_t read(register16_t port); [[nodiscard]] uint8_t readInputPort(register16_t port); - [[nodiscard]] uint8_t readInputPort(uint16_t port); - void writeInputPort(uint16_t port, uint8_t value) noexcept; void writeInputPort(register16_t port, uint8_t value); void write(register16_t port, uint8_t value); void writeOutputPort(register16_t port, uint8_t value); - void writeOutputPort(uint16_t port, uint8_t value); - [[nodiscard]] uint8_t readOutputPort(uint16_t port) noexcept; [[nodiscard]] uint8_t readOutputPort(register16_t port); }; } diff --git a/inc/Processor.h b/inc/Processor.h index 556b3c3..e03c635 100644 --- a/inc/Processor.h +++ b/inc/Processor.h @@ -11,6 +11,15 @@ namespace EightBit { class Processor : public ClockedChip { public: + Signal ExecutingInstruction; + Signal ExecutedInstruction; + + Signal ReadingMemory; + Signal ReadMemory; + + Signal WritingMemory; + Signal WrittenMemory; + // http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend // b: number of bits representing the number in x // x: sign extend this b-bit number to r diff --git a/src/InputOutput.cpp b/src/InputOutput.cpp index d0e6c6f..975be24 100644 --- a/src/InputOutput.cpp +++ b/src/InputOutput.cpp @@ -10,22 +10,14 @@ uint8_t InputOutput::read(register16_t port) { } uint8_t InputOutput::readInputPort(register16_t port) { - return readInputPort(port.word); -} - -uint8_t InputOutput::readInputPort(uint16_t port) { ReadingPort.fire(port); - const auto value = _input[port]; + const auto value = _input[port.word]; ReadPort.fire(port); return value; } -void InputOutput::writeInputPort(uint16_t port, uint8_t value) noexcept { - _input[port] = value; -} - void InputOutput::writeInputPort(register16_t port, uint8_t value) { - writeInputPort(port.word, value); + _input[port.word] = value; } // Output port actions @@ -35,21 +27,13 @@ void InputOutput::write(register16_t port, uint8_t value) { } void InputOutput::writeOutputPort(register16_t port, uint8_t value) { - writeOutputPort(port.word ,value); -} - -void InputOutput::writeOutputPort(uint16_t port, uint8_t value) { WritingPort.fire(port); - _output[port] = value; + _output[port.word] = value; WrittenPort.fire(port); } -uint8_t InputOutput::readOutputPort(uint16_t port) noexcept { - return _output[port]; -} - uint8_t InputOutput::readOutputPort(register16_t port) { - return readOutputPort(port.word); + return _output[port.word]; } }