mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2026-10-22 07:02:37 +00:00
Bring z80 implementation closer to .net
This commit is contained in:
1 parent
abcb245655
commit
c2890b6d00
7 files changed
+600
-518
No files matched your search
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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
@@ -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];
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user