Bring z80 implementation closer to .net

This commit is contained in:
Adrian Conlon committed 2026-02-24 11:39:33 +00:00
1 parent abcb245655
commit c2890b6d00
7 files changed
+600 -518

No files matched your search

+11 -35
View File
@@ -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() {
+277 -191
View File
@@ -75,21 +75,6 @@ namespace EightBit {
Z80(const Z80& rhs);
bool operator==(const Z80& rhs) const;
Signal<Z80> ExecutingInstruction;
Signal<Z80> ExecutedInstruction;
Signal<EventArgs> ReadingMemory;
Signal<EventArgs> ReadMemory;
Signal<EventArgs> WritingMemory;
Signal<EventArgs> WrittenMemory;
Signal<EventArgs> ReadingIO;
Signal<EventArgs> ReadIO;
Signal<EventArgs> WritingIO;
Signal<EventArgs> 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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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;
};
}
+288 -257
View File
@@ -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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(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<Z80>(F(), operand);
adjustSZP(operand);
break;
} case 1: // BIT y, r[z]
bit(F(), y, operand);
F() = adjustXY<Z80>(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<Z80>(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;
+7 -7
View File
@@ -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;
});
+4 -8
View File
@@ -14,22 +14,18 @@ namespace EightBit {
std::array<uint8_t, 0x10000> _output = {};
public:
Signal<uint16_t> ReadingPort;
Signal<uint16_t> ReadPort;
Signal<register16_t> ReadingPort;
Signal<register16_t> ReadPort;
Signal<uint16_t> WritingPort;
Signal<uint16_t> WrittenPort;
Signal<register16_t> WritingPort;
Signal<register16_t> 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);
};
}
+9
View File
@@ -11,6 +11,15 @@
namespace EightBit {
class Processor : public ClockedChip {
public:
Signal<EventArgs> ExecutingInstruction;
Signal<EventArgs> ExecutedInstruction;
Signal<EventArgs> ReadingMemory;
Signal<EventArgs> ReadMemory;
Signal<EventArgs> WritingMemory;
Signal<EventArgs> 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
+4 -20
View File
@@ -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];
}
}