Lots of miscellaneous cycle accurate updates

This commit is contained in:
Adrian Conlon committed 2026-03-21 16:18:39 +00:00
1 parent 81c1703ea9
commit d533593a14
25 files changed
+603 -615

No files matched your search

+1 -1
View File
@@ -20,4 +20,4 @@ void TestRunner::lowerPOWER() noexcept {
EightBit::Bus::lowerPOWER();
}
void TestRunner::initialise() {}
void TestRunner::initialise() noexcept {}
+1 -1
View File
@@ -19,7 +19,7 @@ public:
void raisePOWER() noexcept final;
void lowerPOWER() noexcept final;
void initialise() final;
void initialise() noexcept final;
[[nodiscard]] constexpr auto& RAM() noexcept { return m_ram; }
[[nodiscard]] constexpr auto& ports() noexcept { return m_ports; }
+1 -1
View File
@@ -10,7 +10,7 @@ namespace EightBit {
class Disassembler final {
public:
Disassembler(Bus& bus) noexcept;
Disassembler(Bus& bus);
static std::string state(Z80& cpu);
std::string disassemble(Z80& cpu);
+3 -3
View File
@@ -27,21 +27,21 @@ namespace EightBit {
[[nodiscard]] constexpr const auto& instructions() const { return m_instructions; }
[[nodiscard]] constexpr const auto& addresses() const { return m_addresses; }
[[nodiscard]] constexpr auto instructions_available() const noexcept {
[[nodiscard]] constexpr auto instructions_available() const {
const auto found = std::find_if(
instructions().begin(), instructions().end(),
[](const auto& value) { return value != 0; });
return found != instructions().end();
}
[[nodiscard]] constexpr auto addresses_available() const noexcept {
[[nodiscard]] constexpr auto addresses_available() const {
const auto found = std::find_if(
addresses().begin(), addresses().end(),
[](const auto& value) { return value != 0; });
return found != addresses().end();
}
[[nodiscard]] constexpr auto available() const noexcept {
[[nodiscard]] constexpr auto available() const {
return instructions_available() || addresses_available();
}
+44 -277
View File
@@ -29,14 +29,6 @@ namespace EightBit {
DECLARE_PIN_OUTPUT(RD)
DECLARE_PIN_OUTPUT(WR)
private:
DEFINE_PIN_ACTIVATOR_LOW(RFSH)
DEFINE_PIN_ACTIVATOR_LOW(M1)
DEFINE_PIN_ACTIVATOR_LOW(MREQ)
DEFINE_PIN_ACTIVATOR_LOW(IORQ)
DEFINE_PIN_ACTIVATOR_LOW(RD)
DEFINE_PIN_ACTIVATOR_LOW(WR)
public:
struct refresh_t {
@@ -70,30 +62,24 @@ namespace EightBit {
CF = Bit0,
};
Z80(Bus& bus, InputOutput& ports);
Z80(Bus& bus, InputOutput& ports) noexcept;
Z80(const Z80& rhs);
bool operator==(const Z80& rhs) const;
Z80(const Z80& rhs) noexcept;
bool operator==(const Z80& rhs) const noexcept;
void execute() noexcept final;
void poweredStep() noexcept final;
[[nodiscard]] const register16_t& AF() const noexcept final;
[[nodiscard]] auto& AF() noexcept { return IntelProcessor::AF(); }
[[nodiscard]] const register16_t& BC() const noexcept final;
[[nodiscard]] auto& BC() noexcept { return IntelProcessor::BC(); }
[[nodiscard]] const register16_t& DE() const noexcept final;
[[nodiscard]] auto& DE() noexcept { return IntelProcessor::DE(); }
[[nodiscard]] const register16_t& HL() const noexcept final;
[[nodiscard]] auto& HL() noexcept { return IntelProcessor::HL(); }
[[nodiscard]] register16_t& AF() noexcept final;
[[nodiscard]] register16_t& BC() noexcept final;
[[nodiscard]] register16_t& DE() noexcept final;
[[nodiscard]] register16_t& HL() noexcept final;
[[nodiscard]] constexpr const auto& IX() const noexcept { return m_ix; }
NON_CONST_REGISTOR_ACCESSOR(IX);
[[nodiscard]] constexpr auto& IX() noexcept { return m_ix; }
[[nodiscard]] constexpr auto& IXH() noexcept { return IX().high; }
[[nodiscard]] constexpr auto& IXL() noexcept { return IX().low; }
[[nodiscard]] constexpr const auto& IY() const noexcept { return m_iy; }
NON_CONST_REGISTOR_ACCESSOR(IY);
[[nodiscard]] constexpr auto& IY() noexcept { return m_iy; }
[[nodiscard]] constexpr auto& IYH() noexcept { return IY().high; }
[[nodiscard]] constexpr auto& IYL() noexcept { return IY().low; }
@@ -109,16 +95,11 @@ namespace EightBit {
// programmer. During refresh, the contents of the I Register are placed on the upper eight
// bits of the address bus.
[[nodiscard]] constexpr auto& REFRESH() noexcept { return m_refresh; }
[[nodiscard]] constexpr auto REFRESH() const noexcept { return m_refresh; }
[[nodiscard]] constexpr auto& IV() noexcept { return iv; }
[[nodiscard]] constexpr auto IV() const noexcept { return iv; }
[[nodiscard]] constexpr auto& IM() noexcept { return m_interruptMode; }
[[nodiscard]] constexpr auto IM() const noexcept { return m_interruptMode; }
[[nodiscard]] constexpr auto& IFF1() noexcept { return m_iff1; }
[[nodiscard]] constexpr auto IFF1() const noexcept { return m_iff1; }
[[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; }
@@ -131,18 +112,20 @@ namespace EightBit {
[[nodiscard]] constexpr auto requestingRead() const noexcept { return lowered(RD()); }
[[nodiscard]] constexpr auto requestingWrite() const noexcept { return lowered(WR()); }
[[nodiscard]] constexpr auto fetchingOpCode() const noexcept { return lowered(M1()); }
protected:
void handleRESET() noexcept final;
void handleINT() noexcept final;
void memoryUpdate(int ticks) noexcept;
void memoryUpdate(int ticks = 1) noexcept;
void memoryWrite() noexcept final;
uint8_t memoryRead() noexcept final;
void refreshMemory() noexcept;
void jumpRelative(int8_t offset) noexcept final;
void call(register16_t destination) final;
void call(register16_t destination) noexcept final;
private:
bool m_interruptPending = false;
@@ -181,23 +164,17 @@ namespace EightBit {
void handleNMI() noexcept;
constexpr void resetPrefixes() noexcept {
m_prefixCB = m_prefixDD = m_prefixED = m_prefixFD = false;
}
[[nodiscard]] constexpr auto displaced() const noexcept { return m_prefixDD || m_prefixFD; }
[[nodiscard]] constexpr void displaceAddress() noexcept {
const auto& index_register = m_prefixDD ? IX() : IY();
const auto address = index_register.word + m_displacement;
MEMPTR().word = address;
BUS().ADDRESS() = MEMPTR();
BUS().ADDRESS() = MEMPTR() = index_register.word + m_displacement;
}
void fetchDisplacement() noexcept;
[[nodiscard]] uint8_t fetchInstruction() noexcept final;
uint8_t readDataUnderInterrupt();
uint8_t readDataUnderInterrupt() noexcept;
typedef std::function<register16_t(void)> addresser_t;
void loadAccumulatorIndirect(addresser_t addresser) noexcept;
@@ -339,70 +316,17 @@ namespace EightBit {
return adjustOverflowSub(input, signTest(before), signTest(value), signTest(calculation));
}
[[nodiscard]] bool convertCondition(int flag) noexcept override {
switch (flag) {
case 0:
return zero() == 0;
case 1:
return zero() != 0;
case 2:
return carry() == 0;
case 3:
return carry() != 0;
case 4:
return parity() == 0;
case 5:
return parity() != 0;
case 6:
return sign() == 0;
case 7:
return sign() != 0;
default:
UNREACHABLE;
}
}
auto subtract(uint8_t value, int carry = 0) noexcept {
const auto operand = A();
const register16_t subtraction = operand - value - carry;
const auto result = subtraction.low;
adjustHalfCarrySub(operand, value, result);
adjustOverflowSub(operand, value, result);
setBit(NF);
setBit(CF, carryTest(subtraction.high));
adjustSZ(result);
return result;
}
[[nodiscard]] bool convertCondition(int flag) noexcept final;
void executeCB(int x, int y, int z) noexcept;
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]] auto increment(uint8_t operand) noexcept {
clearBit(NF);
const uint8_t result = operand + 1;
adjustSZXY(result);
setBit(VF, result == Bit7);
clearBit(HC, lowNibble(result));
return result;
}
[[nodiscard]] uint8_t increment(uint8_t operand) noexcept;
[[nodiscard]] uint8_t decrement(uint8_t operand) noexcept;
[[nodiscard]] auto decrement(uint8_t operand) noexcept {
setBit(NF);
clearBit(HC, lowNibble(operand));
const uint8_t result = operand - 1;
adjustSZXY(result);
setBit(VF, result == Mask7);
return result;
}
void disableInterrupts() override;
void enableInterrupts() override;
void disableInterrupts() noexcept final;
void enableInterrupts() noexcept final;
void retn() noexcept;
void reti() noexcept;
@@ -413,178 +337,35 @@ namespace EightBit {
void adc(register16_t value) noexcept;
void add(register16_t value, int carry = 0) noexcept;
void add(uint8_t value, int carry = 0) noexcept {
void add(uint8_t value, int carry = 0) noexcept;
void adc(uint8_t value) noexcept;
void sub(uint8_t value, int carry = 0) noexcept;
uint8_t subtract(uint8_t value, int carry = 0) noexcept;
void sbc(uint8_t value) noexcept;
const auto operand = A();
void andr(uint8_t value) noexcept;
void xorr(uint8_t value) noexcept;
void orr(uint8_t value) noexcept;
void compare(uint8_t value) noexcept;
intermediate() = operand + value + carry;
const auto result = intermediate().low;
[[nodiscard]] uint8_t rlc(uint8_t operand) noexcept;
[[nodiscard]] uint8_t rrc(uint8_t operand) noexcept;
[[nodiscard]] uint8_t rl(uint8_t operand) noexcept;
[[nodiscard]] uint8_t rr(uint8_t operand) noexcept;
[[nodiscard]] uint8_t sla(uint8_t operand) noexcept;
[[nodiscard]] uint8_t sra(uint8_t operand) noexcept;
[[nodiscard]] uint8_t sll(uint8_t operand) noexcept;
[[nodiscard]] uint8_t srl(uint8_t operand) noexcept;
adjustHalfCarryAdd(operand, value, result);
adjustOverflowAdd(operand, value, result);
clearBit(NF);
setBit(CF, carryTest(intermediate().high));
adjustSZXY(result);
A() = result;
}
void adc(uint8_t value) noexcept {
add(value, carry());
}
void sub(uint8_t value, int carry = 0) noexcept {
adjustSZXY(A() = subtract(value, carry));
}
void sbc(uint8_t value) noexcept {
sub(value, carry());
}
[[nodiscard]] void andr(uint8_t value) noexcept {
setBit(HC);
clearBit(CF | NF);
adjustSZPXY(A() &= value);
}
[[nodiscard]] void xorr(uint8_t value) noexcept {
clearBit(HC | CF | NF);
adjustSZPXY(A() ^= value);
}
[[nodiscard]] void orr(uint8_t value) noexcept {
clearBit(HC | CF | NF);
adjustSZPXY(A() |= value);
}
void compare(uint8_t value) noexcept {
subtract(value);
adjustXY(value);
}
[[nodiscard]] auto rlc(uint8_t operand) noexcept {
clearBit(NF | HC);
const auto carry = operand & Bit7;
setBit(CF, carry);
const uint8_t result = (operand << 1) | (carry >> 7);
adjustXY(result);
return result;
}
[[nodiscard]] auto rrc(uint8_t operand) noexcept {
clearBit(NF | HC);
const auto carry = operand & Bit0;
setBit(CF, carry);
const uint8_t result = (operand >> 1) | (carry << 7);
adjustXY(result);
return result;
}
[[nodiscard]] auto rl(uint8_t operand) noexcept {
clearBit(NF | HC);
const auto carrying = carry();
setBit(CF, operand & Bit7);
const uint8_t result = (operand << 1) | carrying;
adjustXY(result);
return result;
}
[[nodiscard]] auto rr(uint8_t operand) noexcept {
clearBit(NF | HC);
const auto carrying = carry();
setBit(CF, operand & Bit0);
const uint8_t result = (operand >> 1) | (carrying << 7);
adjustXY(result);
return result;
}
[[nodiscard]] auto sla(uint8_t operand) noexcept {
clearBit(NF | HC);
setBit(CF, operand & Bit7);
const uint8_t result = operand << 1;
adjustXY(result);
return result;
}
[[nodiscard]] auto sra(uint8_t operand) noexcept {
clearBit(NF | HC);
setBit(CF, operand & Bit0);
const uint8_t result = (operand >> 1) | (operand & Bit7);
adjustXY(result);
return result;
}
[[nodiscard]] auto sll(uint8_t operand) noexcept {
clearBit(NF | HC);
setBit(CF, operand & Bit7);
const uint8_t result = (operand << 1) | Bit0;
adjustXY(result);
return result;
}
[[nodiscard]] auto srl(uint8_t operand) noexcept {
clearBit(NF | HC);
setBit(CF, operand & Bit0);
const uint8_t result = (operand >> 1) & ~Bit7;
adjustXY(result);
setBit(ZF, result);
return result;
}
void bit(int n, uint8_t operand) noexcept {
setBit(HC);
clearBit(NF);
const auto discarded = operand & Chip::bit(n);
adjustSZ(discarded);
clearBit(PF, discarded);
}
void bit(int n, uint8_t operand) noexcept;
[[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]] void daa() noexcept {
auto updated = A();
const auto lowAdjust = halfCarry() || (lowNibble(A()) > 9);
const auto highAdjust = carry() || (A() > 0x99);
if (subtracting()) {
if (lowAdjust)
updated -= 6;
if (highAdjust)
updated -= 0x60;
} else {
if (lowAdjust)
updated += 6;
if (highAdjust)
updated += 0x60;
}
adjustStatusFlags((F() & (CF | NF) | (A() > 0x99 ? CF : 0) | halfCarryTest(A() ^ updated)));
adjustSZPXY(A() = updated);
}
void scf() noexcept {
setBit(CF);
clearBit(HC | NF);
adjustXY((Q() ^ F()) | A());
}
void ccf() noexcept {
clearBit(NF);
const auto carrying = carry();
setBit(HC, carrying);
clearBit(CF, carrying);
adjustXY(((Q() ^ F()) | A()));
}
void cpl() noexcept final {
setBit(HC | NF);
IntelProcessor::cpl();
adjustXY(A());
}
void daa() noexcept;
void scf() noexcept;
void ccf() noexcept;
void cpl() noexcept final;
void xhtl(register16_t& exchange) noexcept;
@@ -605,7 +386,7 @@ namespace EightBit {
void lddr() noexcept;
void repeatBlockInstruction() noexcept;
void adjustBlockRepeatFlagsIO();
void adjustBlockRepeatFlagsIO() noexcept;
void adjustBlockInputOutputFlags(int basis) noexcept;
void adjustBlockInFlagsIncrement() noexcept;
void adjustBlockInFlagsDecrement() noexcept;
@@ -627,21 +408,7 @@ namespace EightBit {
void outd() noexcept;
void otdr() noexcept;
void neg() noexcept {
setBit(PF, A() == Bit7);
setBit(CF, A());
setBit(NF);
auto original = A();
A() = (~A() + 1); // two's complement
adjustHalfCarrySub(0U, original, A());
adjustOverflowSub(0U, original, A());
adjustSZXY(A());
}
void neg() noexcept;
void rrd(register16_t address, uint8_t& update) noexcept;
void rld(register16_t address, uint8_t& update) noexcept;
+1 -1
View File
@@ -8,7 +8,7 @@
#include "../inc/Z80.h"
EightBit::Disassembler::Disassembler(Bus& bus) noexcept
EightBit::Disassembler::Disassembler(Bus& bus)
: m_bus(bus) {
// Disable exceptions where too many format arguments are available
m_formatter.exceptions(boost::io::all_error_bits ^ boost::io::too_many_args_bit);
+331 -89
View File
@@ -3,7 +3,7 @@
// based on http://www.z80.info/decoding.htm
EightBit::Z80::Z80(Bus& bus, InputOutput& ports)
EightBit::Z80::Z80(Bus& bus, InputOutput& ports) noexcept
: IntelProcessor(bus),
m_ports(ports) {
RaisedPOWER.connect([this](EventArgs) {
@@ -45,24 +45,19 @@ EightBit::Z80::Z80(Bus& bus, InputOutput& ports)
});
}
EightBit::Z80::Z80(const Z80& rhs)
EightBit::Z80::Z80(const Z80& rhs) noexcept
: IntelProcessor(rhs),
m_ports(rhs.m_ports) {
m_registers = rhs.m_registers;
m_registerSet = rhs.m_registerSet;
m_accumulatorFlags = rhs.m_accumulatorFlags;
m_accumulatorFlagsSet = rhs.m_accumulatorFlagsSet;
m_ix = rhs.m_ix;
m_iy = rhs.m_iy;
iv = rhs.iv;
m_interruptMode = rhs.m_interruptMode;
m_iff1 = rhs.m_iff1;
m_iff2 = rhs.m_iff2;
m_ports(rhs.m_ports),
m_registers(rhs.m_registers),
m_registerSet(rhs.m_registerSet),
m_accumulatorFlags(rhs.m_accumulatorFlags),
m_accumulatorFlagsSet(rhs.m_accumulatorFlagsSet),
m_ix(rhs.m_ix),
m_iy(rhs.m_iy),
iv(rhs.iv),
m_interruptMode(rhs.m_interruptMode),
m_iff1(rhs.m_iff1),
m_iff2(rhs.m_iff2) {
RFSH() = rhs.RFSH();
NMI() = rhs.NMI();
M1() = rhs.M1();
@@ -72,47 +67,47 @@ EightBit::Z80::Z80(const Z80& rhs)
WR() = rhs.WR();
}
bool EightBit::Z80::operator==(const EightBit::Z80& rhs) const {
bool EightBit::Z80::operator==(const EightBit::Z80& rhs) const noexcept {
const auto base = IntelProcessor::operator==(rhs);
auto& left = const_cast<Z80&>(*this);
auto& right = const_cast<Z80&>(rhs);
const auto pins =
RFSH() == rhs.RFSH()
&& NMI() == rhs.NMI()
&& M1() == rhs.M1()
&& MREQ() == rhs.MREQ()
&& IORQ() == rhs.IORQ()
&& RD() == rhs.RD()
&& WR() == rhs.WR();
left.RFSH() == right.RFSH()
&& left.NMI() == right.NMI()
&& left.M1() == right.M1()
&& left.MREQ() == right.MREQ()
&& left.IORQ() == right.IORQ()
&& left.RD() == right.RD()
&& left.WR() == right.WR();
auto* z80 = const_cast<Z80*>(this);
auto& z80_rhs = const_cast<Z80&>(rhs);
left.exxAF();
right.exxAF();
const auto af = left.AF() == right.AF();
left.exxAF();
right.exxAF();
z80->exxAF();
z80_rhs.exxAF();
const auto af = AF() == rhs.AF();
z80->exxAF();
z80_rhs.exxAF();
z80->exx();
z80_rhs.exx();
left.exx();
right.exx();
const auto pairs =
BC() == rhs.BC()
&& DE() == rhs.DE()
&& HL() == rhs.HL();
z80->exx();
z80_rhs.exx();
left.BC() == right.BC()
&& left.DE() == right.DE()
&& left.HL() == right.HL();
left.exx();
right.exx();
const auto indices =
IX() == rhs.IX()
&& IY() == rhs.IY();
left.IX() == right.IX()
&& left.IY() == right.IY();
const auto miscellaneous =
REFRESH() == rhs.REFRESH()
&& IV() == rhs.IV()
&& IM() == rhs.IM()
&& IFF1() == rhs.IFF1()
&& IFF2() == rhs.IFF2();
left.REFRESH() == right.REFRESH()
&& left.IV() == right.IV()
&& left.IM() == right.IM()
&& left.IFF1() == right.IFF1()
&& left.IFF2() == right.IFF2();
return base && pins && af && pairs && indices && miscellaneous;
}
@@ -125,19 +120,19 @@ DEFINE_PIN_LEVEL_CHANGERS(IORQ, Z80);
DEFINE_PIN_LEVEL_CHANGERS(RD, Z80);
DEFINE_PIN_LEVEL_CHANGERS(WR, Z80);
const EightBit::register16_t& EightBit::Z80::AF() const noexcept {
EightBit::register16_t& EightBit::Z80::AF() noexcept {
return m_accumulatorFlags[m_accumulatorFlagsSet];
}
const EightBit::register16_t& EightBit::Z80::BC() const noexcept {
EightBit::register16_t& EightBit::Z80::BC() noexcept {
return m_registers[m_registerSet][BC_IDX];
}
const EightBit::register16_t& EightBit::Z80::DE() const noexcept {
EightBit::register16_t& EightBit::Z80::DE() noexcept {
return m_registers[m_registerSet][DE_IDX];
}
const EightBit::register16_t& EightBit::Z80::HL() const noexcept {
EightBit::register16_t& EightBit::Z80::HL() noexcept {
return m_registers[m_registerSet][HL_IDX];
}
@@ -156,11 +151,11 @@ void EightBit::Z80::memoryUpdate(int ticks) noexcept {
}
void EightBit::Z80::memoryWrite() noexcept {
memoryUpdate(1);
memoryUpdate();
}
void EightBit::Z80::refreshMemory() noexcept {
assert(lowered(M1()) && "M1 must be lowered to refresh memory");
assert(fetchingOpCode() && "M1 must be lowered to refresh memory");
BUS().ADDRESS() = { REFRESH(), IV() };
lowerRFSH();
tick();
@@ -175,14 +170,14 @@ uint8_t EightBit::Z80::memoryRead() noexcept {
lowerMREQ();
lowerRD();
tick();
const auto data = IntelProcessor::memoryRead();
IntelProcessor::memoryRead();
raiseRD();
raiseMREQ();
if (lowered(M1()))
if (fetchingOpCode())
refreshMemory();
tick();
ReadMemory.fire();
return data;
return BUS().DATA();
}
void EightBit::Z80::handleRESET() noexcept {
@@ -204,9 +199,9 @@ void EightBit::Z80::handleNMI() noexcept {
restart(0x66);
}
uint8_t EightBit::Z80::readDataUnderInterrupt() {
uint8_t EightBit::Z80::readDataUnderInterrupt() noexcept {
lowerM1();
tick(3);
tick(2);
lowerIORQ();
tick();
const auto data = BUS().DATA();
@@ -215,6 +210,7 @@ uint8_t EightBit::Z80::readDataUnderInterrupt() {
refreshMemory();
assert(cycles() == 5);
raiseM1();
tick();
return data;
}
@@ -222,8 +218,9 @@ void EightBit::Z80::handleINT() noexcept {
IntelProcessor::handleINT();
const auto data = readDataUnderInterrupt();
tick();
const auto data = readDataUnderInterrupt();
assert(cycles() == 6);
switch (IM()) {
@@ -235,24 +232,46 @@ void EightBit::Z80::handleINT() noexcept {
assert(cycles() == 13);
break;
case 2:
tick();
MEMPTR() = Processor::getWordPaged(IV(), data);
call(MEMPTR());
assert(cycles() == 13);
assert(cycles() == 19);
break;
default:
UNREACHABLE;
}
}
void EightBit::Z80::disableInterrupts() {
void EightBit::Z80::disableInterrupts() noexcept {
IFF1() = IFF2() = false;
}
void EightBit::Z80::enableInterrupts() {
void EightBit::Z80::enableInterrupts() noexcept {
IFF1() = IFF2() = true;
}
bool EightBit::Z80::convertCondition(int flag) noexcept {
switch (flag) {
case 0:
return zero() == 0;
case 1:
return zero() != 0;
case 2:
return carry() == 0;
case 3:
return carry() != 0;
case 4:
return parity() == 0;
case 5:
return parity() != 0;
case 6:
return sign() == 0;
case 7:
return sign() != 0;
default:
UNREACHABLE;
}
}
void EightBit::Z80::returnConditionalFlag(const int flag) noexcept {
const auto condition = convertCondition(flag);
tick();
@@ -269,8 +288,7 @@ void EightBit::Z80::reti() noexcept {
retn();
}
void EightBit::Z80::call(register16_t destination) {
void EightBit::Z80::call(register16_t destination) noexcept {
tick();
Processor::call(destination);
}
@@ -280,6 +298,70 @@ void EightBit::Z80::jumpRelative(int8_t offset) noexcept {
tick(5);
}
uint8_t EightBit::Z80::increment(uint8_t operand) noexcept {
clearBit(NF);
const uint8_t result = operand + 1;
adjustSZXY(result);
setBit(VF, result == Bit7);
clearBit(HC, lowNibble(result));
return result;
}
uint8_t EightBit::Z80::decrement(uint8_t operand) noexcept {
setBit(NF);
clearBit(HC, lowNibble(operand));
const uint8_t result = operand - 1;
adjustSZXY(result);
setBit(VF, result == Mask7);
return result;
}
void EightBit::Z80::add(uint8_t value, int carry) noexcept {
const auto operand = A();
intermediate() = operand + value + carry;
const auto result = intermediate().low;
adjustHalfCarryAdd(operand, value, result);
adjustOverflowAdd(operand, value, result);
clearBit(NF);
setBit(CF, carryTest(intermediate().high));
adjustSZXY(result);
A() = result;
}
void EightBit::Z80::adc(uint8_t value) noexcept {
add(value, carry());
}
void EightBit::Z80::sub(uint8_t value, int carry) noexcept {
adjustSZXY(A() = subtract(value, carry));
}
void EightBit::Z80::sbc(uint8_t value) noexcept {
sub(value, carry());
}
uint8_t EightBit::Z80::subtract(uint8_t value, int carry) noexcept {
const auto operand = A();
const register16_t subtraction = operand - value - carry;
const auto result = subtraction.low;
adjustHalfCarrySub(operand, value, result);
adjustOverflowSub(operand, value, result);
setBit(NF);
setBit(CF, carryTest(subtraction.high));
adjustSZ(result);
return result;
}
void EightBit::Z80::sbc(const register16_t value) noexcept {
const auto operand = HL2();
@@ -303,6 +385,7 @@ void EightBit::Z80::sbc(const register16_t value) noexcept {
MEMPTR() = operand + 1;
HL2() = intermediate();
tick(7);
}
void EightBit::Z80::adc(const register16_t value) noexcept {
@@ -324,7 +407,7 @@ void EightBit::Z80::add(const register16_t value, int carry) noexcept {
const auto operand = HL2();
const auto addition = operand.word + value.word + carry;
intermediate().word = addition;
intermediate() = addition;
clearBit(NF);
setBit(CF, addition & Bit16);
@@ -334,6 +417,7 @@ void EightBit::Z80::add(const register16_t value, int carry) noexcept {
MEMPTR() = operand + 1;
HL2() = intermediate();
tick(7);
}
void EightBit::Z80::xhtl(register16_t& exchange) noexcept {
@@ -346,19 +430,177 @@ void EightBit::Z80::xhtl(register16_t& exchange) noexcept {
--BUS().ADDRESS();
BUS().DATA() = exchange.low;
exchange.low = MEMPTR().low;
memoryUpdate(1);
memoryUpdate();
tick(2);
}
void EightBit::Z80::andr(uint8_t value) noexcept {
setBit(HC);
clearBit(CF | NF);
adjustSZPXY(A() &= value);
}
void EightBit::Z80::xorr(uint8_t value) noexcept {
clearBit(HC | CF | NF);
adjustSZPXY(A() ^= value);
}
void EightBit::Z80::orr(uint8_t value) noexcept {
clearBit(HC | CF | NF);
adjustSZPXY(A() |= value);
}
void EightBit::Z80::compare(uint8_t value) noexcept {
subtract(value);
adjustXY(value);
}
uint8_t EightBit::Z80::rlc(uint8_t operand) noexcept {
clearBit(NF | HC);
const auto carry = operand & Bit7;
setBit(CF, carry);
const uint8_t result = (operand << 1) | (carry >> 7);
adjustXY(result);
return result;
}
uint8_t EightBit::Z80::rrc(uint8_t operand) noexcept {
clearBit(NF | HC);
const auto carry = operand & Bit0;
setBit(CF, carry);
const uint8_t result = (operand >> 1) | (carry << 7);
adjustXY(result);
return result;
}
uint8_t EightBit::Z80::rl(uint8_t operand) noexcept {
clearBit(NF | HC);
const auto carrying = carry();
setBit(CF, operand & Bit7);
const uint8_t result = (operand << 1) | carrying;
adjustXY(result);
return result;
}
uint8_t EightBit::Z80::rr(uint8_t operand) noexcept {
clearBit(NF | HC);
const auto carrying = carry();
setBit(CF, operand & Bit0);
const uint8_t result = (operand >> 1) | (carrying << 7);
adjustXY(result);
return result;
}
uint8_t EightBit::Z80::sla(uint8_t operand) noexcept {
clearBit(NF | HC);
setBit(CF, operand & Bit7);
const uint8_t result = operand << 1;
adjustXY(result);
return result;
}
uint8_t EightBit::Z80::sra(uint8_t operand) noexcept {
clearBit(NF | HC);
setBit(CF, operand & Bit0);
const uint8_t result = (operand >> 1) | (operand & Bit7);
adjustXY(result);
return result;
}
uint8_t EightBit::Z80::sll(uint8_t operand) noexcept {
clearBit(NF | HC);
setBit(CF, operand & Bit7);
const uint8_t result = (operand << 1) | Bit0;
adjustXY(result);
return result;
}
uint8_t EightBit::Z80::srl(uint8_t operand) noexcept {
clearBit(NF | HC);
setBit(CF, operand & Bit0);
const uint8_t result = (operand >> 1) & ~Bit7;
adjustXY(result);
setBit(ZF, result);
return result;
}
void EightBit::Z80::bit(int n, uint8_t operand) noexcept {
setBit(HC);
clearBit(NF);
const auto discarded = operand & Chip::bit(n);
adjustSZ(discarded);
clearBit(PF, discarded);
}
void EightBit::Z80::daa() noexcept {
auto updated = A();
const auto lowAdjust = halfCarry() || (lowNibble(A()) > 9);
const auto highAdjust = carry() || (A() > 0x99);
if (subtracting()) {
if (lowAdjust)
updated -= 6;
if (highAdjust)
updated -= 0x60;
} else {
if (lowAdjust)
updated += 6;
if (highAdjust)
updated += 0x60;
}
adjustStatusFlags((F() & (CF | NF) | (A() > 0x99 ? CF : 0) | halfCarryTest(A() ^ updated)));
adjustSZPXY(A() = updated);
}
void EightBit::Z80::scf() noexcept {
setBit(CF);
clearBit(HC | NF);
adjustXY((Q() ^ F()) | A());
}
void EightBit::Z80::ccf() noexcept {
clearBit(NF);
const auto carrying = carry();
setBit(HC, carrying);
clearBit(CF, carrying);
adjustXY(((Q() ^ F()) | A()));
}
void EightBit::Z80::cpl() noexcept {
setBit(HC | NF);
IntelProcessor::cpl();
adjustXY(A());
}
void EightBit::Z80::neg() noexcept {
setBit(PF, A() == Bit7);
setBit(CF, A());
setBit(NF);
auto original = A();
A() = (~A() + 1); // two's complement
adjustHalfCarrySub(0U, original, A());
adjustOverflowSub(0U, original, A());
adjustSZXY(A());
}
void EightBit::Z80::blockCompare() noexcept {
const auto data = IntelProcessor::memoryRead(HL());
uint8_t result = A() - data;
IntelProcessor::memoryRead(HL());
uint8_t result = A() - BUS().DATA();
setBit(PF, --BC().word);
adjustSZ(result);
adjustHalfCarrySub(A(), data, result);
adjustHalfCarrySub(A(), BUS().DATA(), result);
setBit(NF);
result -= (halfCarry() >> 4);
@@ -395,15 +637,15 @@ void EightBit::Z80::cpdr() noexcept {
repeatBlockInstruction();
tick(5);
} else {
MEMPTR().word = PC().word - 2;
MEMPTR() = PC().word - 2;
tick(2);
}
}
void EightBit::Z80::blockLoad() noexcept {
const auto data = IntelProcessor::memoryRead(HL());
IntelProcessor::memoryRead(HL());
IntelProcessor::memoryWrite(DE());
const auto xy = A() + data;
const auto xy = A() + BUS().DATA();
setBit(XF, xy & Bit3);
setBit(YF, xy & Bit1);
clearBit(NF | HC);
@@ -443,7 +685,7 @@ void EightBit::Z80::repeatBlockInstruction() noexcept {
adjustXY(PC().high);
}
void EightBit::Z80::adjustBlockRepeatFlagsIO() {
void EightBit::Z80::adjustBlockRepeatFlagsIO() noexcept {
if (carry() != 0) {
const auto negative = signTest(BUS().DATA()) != 0;
const uint8_t direction = B() + (negative ? -1 : +1);
@@ -461,11 +703,11 @@ void EightBit::Z80::adjustBlockInputOutputFlags(int basis) noexcept {
}
void EightBit::Z80::adjustBlockInFlagsIncrement() noexcept {
adjustBlockInputOutputFlags((C() + 1) + BUS().DATA());
adjustBlockInputOutputFlags((uint8_t)(C() + 1) + BUS().DATA());
}
void EightBit::Z80::adjustBlockInFlagsDecrement() noexcept {
adjustBlockInputOutputFlags((C() - 1) + BUS().DATA());
adjustBlockInputOutputFlags((uint8_t)(C() - 1) + BUS().DATA());
}
void EightBit::Z80::adjustBlockOutFlags() noexcept {
@@ -478,7 +720,7 @@ void EightBit::Z80::blockIn() noexcept {
tick();
readPort(BC());
BUS().ADDRESS() = HL();
memoryUpdate(1);
memoryUpdate();
adjustSZXY(--B());
setBit(NF, BUS().DATA() & SF);
}
@@ -555,7 +797,8 @@ void EightBit::Z80::otdr() noexcept {
}
void EightBit::Z80::rrd(register16_t address, uint8_t& update) noexcept {
(MEMPTR() = BUS().ADDRESS() = address)++;
MEMPTR() = BUS().ADDRESS() = address;
++MEMPTR();
const auto memory = memoryRead();
tick(4);
IntelProcessor::memoryWrite(promoteNibble(update) | highNibble(memory));
@@ -565,7 +808,8 @@ void EightBit::Z80::rrd(register16_t address, uint8_t& update) noexcept {
}
void EightBit::Z80::rld(register16_t address, uint8_t& update) noexcept {
(MEMPTR() = BUS().ADDRESS() = address)++;
MEMPTR() = BUS().ADDRESS() = address;
++MEMPTR();
const auto memory = memoryRead();
tick(4);
IntelProcessor::memoryWrite(promoteNibble(memory) | lowNibble(update));
@@ -663,12 +907,14 @@ uint8_t EightBit::Z80::fetchInstruction() noexcept {
}
void EightBit::Z80::loadAccumulatorIndirect(addresser_t addresser) noexcept {
(MEMPTR() = BUS().ADDRESS() = addresser())++;
MEMPTR() = BUS().ADDRESS() = addresser();
++MEMPTR();
A() = memoryRead();
}
void EightBit::Z80::storeAccumulatorIndirect(addresser_t addresser) noexcept {
(MEMPTR() = BUS().ADDRESS() = addresser())++;
MEMPTR() = BUS().ADDRESS() = addresser();
++MEMPTR();
MEMPTR().high = BUS().DATA() = A();
memoryWrite();
}
@@ -677,12 +923,13 @@ void EightBit::Z80::readInternalRegister(reader_t reader) noexcept {
adjustSZXY(A() = reader());
clearBit(NF | HC);
setBit(PF, IFF2());
tick();
}
EightBit::register16_t& EightBit::Z80::HL2() noexcept {
if (UNLIKELY(m_prefixDD))
if (m_prefixDD)
return IX();
if (UNLIKELY(m_prefixFD))
if (m_prefixFD)
return IY();
return HL();
}
@@ -755,7 +1002,6 @@ uint8_t& EightBit::Z80::R(const int r, MemoryMapping::AccessLevel access) noexce
}
void EightBit::Z80::R(const int r, const uint8_t value, const int ticks) noexcept {
R(r, MemoryMapping::AccessLevel::WriteOnly) = value;
if (r == 6)
memoryUpdate(ticks);
@@ -944,7 +1190,6 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p
default:
UNREACHABLE;
}
tick(7);
break;
case 3: // Retrieve/store register pair from/to immediate address
BUS().ADDRESS() = fetchWord();
@@ -1004,11 +1249,9 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p
break;
case 2: // LD A,I
readInternalRegister([this]() { return IV(); });
tick();
break;
case 3: // LD A,R
readInternalRegister([this]() { return REFRESH(); });
tick();
break;
case 4: // RRD
rrd(HL(), A());
@@ -1135,7 +1378,6 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
break;
case 1: // ADD HL,rp
add(RP(p));
tick(7);
break;
default:
UNREACHABLE;
+1 -1
View File
@@ -17,7 +17,7 @@ void Board::lowerPOWER() noexcept {
EightBit::Bus::lowerPOWER();
}
void Board::initialise() {
void Board::initialise() noexcept {
auto romDirectory = m_configuration.getRomDirectory();
m_ram.load(romDirectory + "/zexall.com", 0x100); // Cringle/Bartholomew
+2 -2
View File
@@ -16,12 +16,12 @@ class Board : public EightBit::Bus {
public:
Board(const Configuration& configuration);
EightBit::Z80& CPU() noexcept { return m_cpu; }
EightBit::Z80& CPU() { return m_cpu; }
void raisePOWER() noexcept final;
void lowerPOWER() noexcept final;
void initialise() final;
void initialise() noexcept final;
protected:
EightBit::MemoryMapping mapping(uint16_t address) noexcept final {
+9 -8
View File
@@ -8,7 +8,8 @@ namespace EightBit {
class BigEndianProcessor : public Processor {
public:
virtual ~BigEndianProcessor() noexcept {};
virtual ~BigEndianProcessor() noexcept = default;
BigEndianProcessor(const BigEndianProcessor& rhs) noexcept;
[[nodiscard]] register16_t peekWord(register16_t address) noexcept final;
void pokeWord(register16_t address, register16_t value) noexcept final;
@@ -16,15 +17,15 @@ namespace EightBit {
protected:
BigEndianProcessor(Bus& memory) noexcept;
[[nodiscard]] register16_t getWord() override;
void setWord(register16_t value) override;
[[nodiscard]] register16_t getWord() noexcept override;
void setWord(register16_t value) noexcept override;
[[nodiscard]] register16_t getWordPaged() override;
void setWordPaged(register16_t value) override;
[[nodiscard]] register16_t getWordPaged() noexcept override;
void setWordPaged(register16_t value) noexcept override;
[[nodiscard]] register16_t fetchWord() final;
[[nodiscard]] register16_t fetchWord() noexcept override;
void pushWord(register16_t value) final;
[[nodiscard]] register16_t popWord() final;
void pushWord(register16_t value) noexcept override;
[[nodiscard]] register16_t popWord() noexcept override;
};
}
+5 -5
View File
@@ -26,20 +26,20 @@ namespace EightBit {
[[nodiscard]] constexpr auto DATA() const noexcept { return m_data; }
[[nodiscard]] constexpr auto& DATA() noexcept { return m_data; }
[[nodiscard]] virtual uint8_t peek(const uint16_t address) noexcept { return reference(address); }
[[nodiscard]] uint8_t peek(const uint16_t address) noexcept { return reference(address); }
[[nodiscard]] auto peek(const register16_t address) noexcept { return peek(address.word); }
void poke(const uint8_t value) noexcept { reference() = value; }
virtual void poke(const uint16_t address, const uint8_t value) noexcept { reference(address) = value; }
void poke(const uint16_t address, const uint8_t value) noexcept { reference(address) = value; }
void poke(const register16_t address, const uint8_t value) noexcept { poke(address.word, value); }
[[nodiscard]] uint8_t read();
void write();
[[nodiscard]] uint8_t read() noexcept;
void write() noexcept;
virtual void raisePOWER() noexcept;
virtual void lowerPOWER() noexcept;
virtual void initialise() = 0;
virtual void initialise() noexcept = 0;
protected:
[[nodiscard]] uint8_t& reference(uint16_t address) noexcept;
+2 -2
View File
@@ -14,12 +14,12 @@ namespace EightBit {
[[nodiscard]] constexpr auto cycles() const noexcept { return m_cycles; }
void tick() {
void tick() noexcept {
++m_cycles;
Ticked.fire();
}
void tick(int extra) {
void tick(int extra) noexcept {
for (int i = 0; i < extra; ++i)
tick();
}
+5 -24
View File
@@ -10,17 +10,17 @@
Signal<EventArgs> Lowered ## name;
#define DECLARE_PIN_LEVEL_RAISE(name) \
virtual void raise ## name();
virtual void raise ## name() noexcept;
#define DECLARE_PIN_LEVEL_LOWER(name) \
virtual void lower ## name();
virtual void lower ## name() noexcept;
#define DECLARE_PIN_LEVEL_CHANGERS(name) \
DECLARE_PIN_LEVEL_RAISE(name) \
DECLARE_PIN_LEVEL_LOWER(name)
#define DEFINE_PIN_LEVEL_RAISE(name, within) \
void EightBit:: within ::raise ## name() { \
void EightBit:: within ::raise ## name() noexcept { \
if (lowered( name ())) { \
Raising ## name.fire(); \
raise( name ()); \
@@ -29,7 +29,7 @@
}
#define DEFINE_PIN_LEVEL_LOWER(name, within) \
void EightBit:: within ::lower ## name() { \
void EightBit:: within ::lower ## name() noexcept { \
if (raised( name ())) { \
Lowering ## name.fire(); \
lower( name ()); \
@@ -44,25 +44,6 @@
#define DECLARE_PIN_MEMBER(name) \
PinLevel m_## name ## _Line = PinLevel::Low;
#define DEFINE_PIN_ACTIVATOR(name, on, off) \
template <class T> class _Activate ## name final { \
T& m_parent; \
public: \
_Activate ## name(T& parent) noexcept \
: m_parent(parent) { \
m_parent. on ## name(); \
} \
~_Activate ## name() noexcept { \
m_parent. off ## name(); \
} \
};
#define DEFINE_PIN_ACTIVATOR_LOW(name) \
DEFINE_PIN_ACTIVATOR(name, lower, raise)
#define DEFINE_PIN_ACTIVATOR_HIGH(name) \
DEFINE_PIN_ACTIVATOR(name, raise, lower)
#define DECLARE_PIN(name, visibility) \
public: \
DECLARE_PIN_SIGNALS(name) \
@@ -114,6 +95,6 @@ namespace EightBit {
[[nodiscard]] constexpr bool powered() const noexcept { return raised(POWER()); }
protected:
Device() noexcept {};
Device() noexcept = default;
};
}
+36 -63
View File
@@ -9,16 +9,6 @@
#include "Signal.h"
#include "EightBitCompilerDefinitions.h"
#define NON_CONST_ACCESSOR(accessor, type) \
[[nodiscard]] constexpr auto& accessor() noexcept { \
const auto& consted = *this; \
const auto& reference = consted.accessor(); \
return const_cast<type&>(reference); \
}
#define NON_CONST_REGISTOR_ACCESSOR(accessor) \
NON_CONST_ACCESSOR(accessor, register16_t)
namespace EightBit {
class Bus;
@@ -52,35 +42,32 @@ namespace EightBit {
}
[[nodiscard]] constexpr auto& MEMPTR() noexcept { return m_memptr; }
[[nodiscard]] constexpr auto MEMPTR() const noexcept { return m_memptr; }
[[nodiscard]] constexpr auto& SP() noexcept { return m_sp; }
[[nodiscard]] register16_t SP() const noexcept { return m_sp; }
[[nodiscard]] virtual const register16_t& AF() const noexcept = 0;
NON_CONST_REGISTOR_ACCESSOR(AF);
[[nodiscard]] virtual register16_t& AF() noexcept = 0;
[[nodiscard]] auto& A() noexcept { return AF().high; }
[[nodiscard]] auto& F() noexcept { return AF().low; }
[[nodiscard]] virtual const register16_t& BC() const noexcept = 0;
NON_CONST_REGISTOR_ACCESSOR(BC);
[[nodiscard]] virtual register16_t& BC() noexcept = 0;
[[nodiscard]] auto& B() noexcept { return BC().high; }
[[nodiscard]] auto& C() noexcept { return BC().low; }
[[nodiscard]] virtual const register16_t& DE() const noexcept = 0;
NON_CONST_REGISTOR_ACCESSOR(DE);
[[nodiscard]] virtual register16_t& DE() noexcept = 0;
[[nodiscard]] auto& D() noexcept { return DE().high; }
[[nodiscard]] auto& E() noexcept { return DE().low; }
[[nodiscard]] virtual const register16_t& HL() const noexcept = 0;
NON_CONST_REGISTOR_ACCESSOR(HL);
[[nodiscard]] virtual register16_t& HL() noexcept = 0;
[[nodiscard]] auto& H() noexcept { return HL().high; }
[[nodiscard]] auto& L() noexcept { return HL().low; }
DECLARE_PIN_OUTPUT(HALT)
public:
[[nodiscard]] constexpr bool halted() const noexcept { return lowered(HALT()); }
[[nodiscard]] constexpr bool proceeding() const noexcept { return !halted(); }
protected:
IntelProcessor(Bus& bus);
IntelProcessor(Bus& bus) noexcept;
template<class T> [[nodiscard]] static constexpr uint8_t adjustSign(uint8_t f, const uint8_t value) noexcept {
return setBit(f, T::SF, value & T::SF);
@@ -138,65 +125,51 @@ namespace EightBit {
return calculateHalfCarry(m_halfCarryTableSub, before, value, calculation);
}
virtual void disableInterrupts() = 0;
virtual void disableInterrupts() noexcept = 0;
virtual void enableInterrupts() noexcept = 0;
virtual void enableInterrupts() = 0;
void handleRESET() noexcept override;
void handleINT() noexcept override;
void handleRESET() override;
void handleINT() override;
void push(uint8_t value) final;
[[nodiscard]] uint8_t pop() final;
void push(uint8_t value) noexcept final;
[[nodiscard]] uint8_t pop() noexcept final;
//
register16_t& incrementPC() override;
uint8_t fetchInstruction() override;
register16_t& incrementPC() noexcept override;
uint8_t fetchInstruction() noexcept override;
//
[[nodiscard]] register16_t getWord() final;
void setWord(register16_t value) final;
[[nodiscard]] register16_t getWord() noexcept final;
void setWord(register16_t value) noexcept final;
//
void restart(uint8_t address);
void callConditional(bool condition);
virtual void jumpConditional(bool condition);
void jumpRelativeConditional(bool condition);
virtual void returnConditional(bool condition);
void jumpIndirect();
void jump();
void callIndirect();
void call();
virtual void call(register16_t destination);
void restart(uint8_t address) noexcept;
void callConditional(bool condition) noexcept;
virtual void jumpConditional(bool condition) noexcept;
void jumpRelativeConditional(bool condition) noexcept;
virtual void returnConditional(bool condition) noexcept;
void jumpIndirect() noexcept;
void jump() noexcept;
void callIndirect() noexcept;
void call() noexcept;
virtual void call(register16_t destination) noexcept;
virtual void jumpRelative(int8_t offset) noexcept;
void jumpRelative(uint8_t offset) noexcept { jumpRelative((int8_t)offset); }
void ret() override;
void jumpRelative(uint8_t offset) noexcept { jumpRelative(static_cast<int8_t>(offset)); }
void ret() noexcept override;
void resetWorkingRegisters() noexcept;
[[nodiscard]] virtual bool convertCondition(int flag) noexcept = 0;
virtual void jumpConditionalFlag(int flag) {
jumpConditional(convertCondition(flag));
}
virtual void jumpConditionalFlag(int flag) noexcept;
virtual void jumpRelativeConditionalFlag(int flag) noexcept;
virtual void returnConditionalFlag(int flag) noexcept;
virtual void callConditionalFlag(int flag) noexcept;
virtual void jumpRelativeConditionalFlag(int flag) {
jumpRelativeConditional(convertCondition(flag));
}
virtual void returnConditionalFlag(int flag) {
returnConditional(convertCondition(flag));
}
virtual void callConditionalFlag(int flag) {
callConditional(convertCondition(flag));
}
virtual void cpl() noexcept {
A() = ~A();
}
virtual void cpl() noexcept;
private:
static std::array<int, 8> m_halfCarryTableAdd;
+8 -7
View File
@@ -8,6 +8,7 @@ namespace EightBit {
class LittleEndianProcessor : public Processor {
public:
virtual ~LittleEndianProcessor() noexcept = default;
LittleEndianProcessor(const LittleEndianProcessor& rhs) noexcept;
[[nodiscard]] register16_t peekWord(register16_t address) noexcept final;
@@ -16,15 +17,15 @@ namespace EightBit {
protected:
LittleEndianProcessor(Bus& memory) noexcept;
[[nodiscard]] register16_t getWord() override;
void setWord(register16_t value) override;
[[nodiscard]] register16_t getWord() noexcept override;
void setWord(register16_t value) noexcept override;
[[nodiscard]] register16_t getWordPaged() override;
void setWordPaged(register16_t value) override;
[[nodiscard]] register16_t getWordPaged() noexcept override;
void setWordPaged(register16_t value) noexcept override;
[[nodiscard]] register16_t fetchWord() final;
[[nodiscard]] register16_t fetchWord() noexcept override;
void pushWord(register16_t value) override;
[[nodiscard]] register16_t popWord() override;
void pushWord(register16_t value) noexcept override;
[[nodiscard]] register16_t popWord() noexcept override;
};
}
+32 -32
View File
@@ -57,53 +57,53 @@ namespace EightBit {
[[nodiscard]] constexpr auto& opcode() noexcept { return m_opcode; }
[[nodiscard]] constexpr auto& BUS() noexcept { return m_bus; }
virtual void handleRESET();
virtual void handleINT();
virtual void handleRESET() noexcept;
virtual void handleINT() noexcept;
void memoryWrite(register16_t address, uint8_t data);
void memoryWrite(register16_t address);
void memoryWrite(uint8_t data);
virtual void memoryWrite();
virtual void busWrite();
void memoryWrite(register16_t address, uint8_t data) noexcept;
void memoryWrite(register16_t address) noexcept;
void memoryWrite(uint8_t data) noexcept;
virtual void memoryWrite() noexcept;
virtual void busWrite() noexcept;
uint8_t memoryRead(register16_t address);
virtual uint8_t memoryRead();
virtual uint8_t busRead();
uint8_t memoryRead(register16_t address) noexcept;
virtual uint8_t memoryRead() noexcept;
virtual uint8_t busRead() noexcept;
virtual register16_t& incrementPC();
virtual register16_t& decrementPC();
virtual register16_t& incrementPC() noexcept;
virtual register16_t& decrementPC() noexcept;
virtual void immediateAddress();
virtual void immediateAddress() noexcept;
uint8_t fetchByte();
virtual uint8_t fetchInstruction();
uint8_t fetchByte() noexcept;
virtual uint8_t fetchInstruction() noexcept;
[[nodiscard]] virtual register16_t getWord() = 0;
virtual void setWord(register16_t value) = 0;
[[nodiscard]] virtual register16_t getWord() noexcept = 0;
virtual void setWord(register16_t value) noexcept = 0;
[[nodiscard]] register16_t getWordPaged(register16_t address);
[[nodiscard]] register16_t getWordPaged(uint8_t page, uint8_t offset);
[[nodiscard]] virtual register16_t getWordPaged() = 0;
void setWordPaged(register16_t address, register16_t value);
void setWordPaged(uint8_t page, uint8_t offset, register16_t value);
virtual void setWordPaged(register16_t value) = 0;
[[nodiscard]] register16_t getWordPaged(register16_t address) noexcept;
[[nodiscard]] register16_t getWordPaged(uint8_t page, uint8_t offset) noexcept;
[[nodiscard]] virtual register16_t getWordPaged() noexcept = 0;
void setWordPaged(register16_t address, register16_t value) noexcept;
void setWordPaged(uint8_t page, uint8_t offset, register16_t value) noexcept;
virtual void setWordPaged(register16_t value) noexcept = 0;
[[nodiscard]] virtual register16_t fetchWord() = 0;
[[nodiscard]] virtual register16_t fetchWord() noexcept = 0;
virtual void push(uint8_t value) = 0;
[[nodiscard]] virtual uint8_t pop() = 0;
virtual void push(uint8_t value) noexcept = 0;
[[nodiscard]] virtual uint8_t pop() noexcept = 0;
virtual void pushWord(register16_t value) = 0;
[[nodiscard]] virtual register16_t popWord() = 0;
virtual void pushWord(register16_t value) noexcept = 0;
[[nodiscard]] virtual register16_t popWord() noexcept = 0;
[[nodiscard]] register16_t getWord(register16_t address);
void setWord(register16_t address, register16_t value);
[[nodiscard]] register16_t getWord(register16_t address) noexcept;
void setWord(register16_t address, register16_t value) noexcept;
void jump(const register16_t destination) noexcept;
void jump(uint16_t destination) noexcept;
virtual void call(register16_t destination);
virtual void ret();
virtual void call(register16_t destination) noexcept;
virtual void ret() noexcept;
private:
Bus& m_bus;
+1 -1
View File
@@ -8,7 +8,7 @@ namespace EightBit {
class Ram : public Rom {
public:
Ram(size_t size = 0) noexcept;
virtual ~Ram() = default;
virtual ~Ram() noexcept = default;
[[nodiscard]] uint8_t& reference(uint16_t address) noexcept final;
void poke(uint16_t address, uint8_t value) noexcept final;
+4 -4
View File
@@ -26,10 +26,10 @@ namespace EightBit {
static int load(std::string path, std::vector<uint8_t>& output, int writeOffset = 0, int readOffset = 0, int limit = -1, int maximumSize = -1);
Rom(size_t size = 0) noexcept;
Rom(const Rom& rhs);
virtual ~Rom() = default;
Rom& operator=(const Rom& rhs);
bool operator==(const Rom& rhs) const;
Rom(const Rom& rhs) noexcept;
virtual ~Rom() noexcept = default;
Rom& operator=(const Rom& rhs) noexcept;
bool operator==(const Rom& rhs) const noexcept;
[[nodiscard]] uint16_t size() const noexcept final;
+5 -3
View File
@@ -17,9 +17,11 @@ namespace EightBit {
m_delegates.push_back(functor);
}
void fire(T& e = EventArgs::empty()) const {
for (auto& delegate : m_delegates)
delegate(e);
void fire(T& e = EventArgs::empty()) const noexcept {
const auto firing = !m_delegates.empty();
if (firing)
for (auto& delegate : m_delegates)
delegate(e);
}
};
}
+13 -10
View File
@@ -4,44 +4,47 @@
EightBit::BigEndianProcessor::BigEndianProcessor(Bus& memory) noexcept
: Processor(memory) {}
EightBit::register16_t EightBit::BigEndianProcessor::getWord() {
EightBit::BigEndianProcessor::BigEndianProcessor(const BigEndianProcessor& rhs) noexcept
: Processor(rhs) {}
EightBit::register16_t EightBit::BigEndianProcessor::getWord() noexcept {
const auto high = memoryRead();
++BUS().ADDRESS();
const auto low = memoryRead();
return { low, high };
}
void EightBit::BigEndianProcessor::setWord(const register16_t value) {
void EightBit::BigEndianProcessor::setWord(const register16_t value) noexcept {
memoryWrite(value.high);
++BUS().ADDRESS();
memoryWrite(value.low);
}
EightBit::register16_t EightBit::BigEndianProcessor::getWordPaged() {
EightBit::register16_t EightBit::BigEndianProcessor::getWordPaged() noexcept {
const auto high = memoryRead();
++BUS().ADDRESS().low;
const auto low = memoryRead();
return { low, high };
}
void EightBit::BigEndianProcessor::setWordPaged(const register16_t value) {
void EightBit::BigEndianProcessor::setWordPaged(const register16_t value) noexcept {
memoryWrite(value.high);
++BUS().ADDRESS().low;
memoryWrite(value.low);
}
EightBit::register16_t EightBit::BigEndianProcessor::fetchWord() {
const auto high = fetchByte();
const auto low = fetchByte();
return { low, high };
EightBit::register16_t EightBit::BigEndianProcessor::fetchWord() noexcept {
intermediate().high = fetchByte();
intermediate().low = fetchByte();
return intermediate();
}
void EightBit::BigEndianProcessor::pushWord(const register16_t value) {
void EightBit::BigEndianProcessor::pushWord(const register16_t value) noexcept {
push(value.low);
push(value.high);
}
EightBit::register16_t EightBit::BigEndianProcessor::popWord() {
EightBit::register16_t EightBit::BigEndianProcessor::popWord() noexcept {
const auto high = pop();
const auto low = pop();
return { low, high };
+2 -2
View File
@@ -8,14 +8,14 @@ void EightBit::Bus::raisePOWER() noexcept {}
void EightBit::Bus::lowerPOWER() noexcept {}
uint8_t EightBit::Bus::read() {
uint8_t EightBit::Bus::read() noexcept {
ReadingByte.fire();
const auto returned = DATA() = reference();
ReadByte.fire();
return returned;
}
void EightBit::Bus::write() {
void EightBit::Bus::write() noexcept {
WritingByte.fire();
reference() = DATA();
WrittenByte.fire();
+55 -37
View File
@@ -4,7 +4,7 @@
std::array<int, 8> EightBit::IntelProcessor::m_halfCarryTableAdd = { { 0, 0, 1, 0, 1, 0, 1, 1 } };
std::array<int, 8> EightBit::IntelProcessor::m_halfCarryTableSub = { { 0, 1, 1, 1, 0, 0, 0, 1 } };
EightBit::IntelProcessor::IntelProcessor(Bus& bus)
EightBit::IntelProcessor::IntelProcessor(Bus& bus) noexcept
: LittleEndianProcessor(bus) {
for (int i = 0; i < 0x100; ++i)
m_decodedOpcodes.at(i) = i;
@@ -17,11 +17,9 @@ EightBit::IntelProcessor::IntelProcessor(Bus& bus)
}
EightBit::IntelProcessor::IntelProcessor(const IntelProcessor& rhs) noexcept
: LittleEndianProcessor(rhs) {
m_sp = rhs.m_sp;
m_memptr = rhs.m_memptr;
: LittleEndianProcessor(rhs),
m_sp(rhs.m_sp),
m_memptr(rhs.m_memptr) {
HALT() = rhs.HALT();
}
@@ -31,73 +29,72 @@ void EightBit::IntelProcessor::resetWorkingRegisters() noexcept {
DEFINE_PIN_LEVEL_CHANGERS(HALT, IntelProcessor);
void EightBit::IntelProcessor::handleRESET() {
void EightBit::IntelProcessor::handleRESET() noexcept {
Processor::handleRESET();
disableInterrupts();
Processor::jump(0);
}
void EightBit::IntelProcessor::handleINT() {
void EightBit::IntelProcessor::handleINT() noexcept {
Processor::handleINT();
disableInterrupts();
raiseHALT();
disableInterrupts();
}
void EightBit::IntelProcessor::push(const uint8_t value) {
void EightBit::IntelProcessor::push(const uint8_t value) noexcept {
memoryWrite(--SP(), value);
}
uint8_t EightBit::IntelProcessor::pop() {
uint8_t EightBit::IntelProcessor::pop() noexcept {
return memoryRead(SP()++);
}
EightBit::register16_t& EightBit::IntelProcessor::incrementPC() {
if (raised(HALT()))
EightBit::register16_t& EightBit::IntelProcessor::incrementPC() noexcept {
if (proceeding())
Processor::incrementPC();
return PC();
}
uint8_t EightBit::IntelProcessor::fetchInstruction() {
uint8_t EightBit::IntelProcessor::fetchInstruction() noexcept {
const auto data = fetchByte();
return lowered(HALT()) ? (uint8_t)0 : data;
return proceeding() ? data : (uint8_t)0;
}
EightBit::register16_t EightBit::IntelProcessor::getWord() {
EightBit::register16_t EightBit::IntelProcessor::getWord() noexcept {
const auto returned = LittleEndianProcessor::getWord();
MEMPTR() = BUS().ADDRESS();
return returned;
}
void EightBit::IntelProcessor::setWord(const register16_t value) {
void EightBit::IntelProcessor::setWord(const register16_t value) noexcept {
LittleEndianProcessor::setWord(value);
MEMPTR() = BUS().ADDRESS();
}
void EightBit::IntelProcessor::restart(const uint8_t address) {
void EightBit::IntelProcessor::restart(const uint8_t address) noexcept {
MEMPTR() = { address, 0 };
call();
}
void EightBit::IntelProcessor::callConditional(bool condition) {
void EightBit::IntelProcessor::callConditional(bool condition) noexcept {
MEMPTR() = fetchWord();
if (condition)
call();
}
void EightBit::IntelProcessor::jumpConditional(bool condition) {
void EightBit::IntelProcessor::jumpConditional(bool condition) noexcept {
MEMPTR() = fetchWord();
if (condition)
jump();
}
void EightBit::IntelProcessor::jumpRelativeConditional(bool condition) {
void EightBit::IntelProcessor::jumpRelativeConditional(bool condition) noexcept {
const auto offset = fetchByte();
if (condition)
jumpRelative(offset);
}
void EightBit::IntelProcessor::returnConditional(bool condition) {
void EightBit::IntelProcessor::returnConditional(bool condition) noexcept {
if (condition)
ret();
}
@@ -107,42 +104,63 @@ void EightBit::IntelProcessor::jumpRelative(const int8_t offset) noexcept {
jump();
}
void EightBit::IntelProcessor::ret() {
void EightBit::IntelProcessor::ret() noexcept {
LittleEndianProcessor::ret();
MEMPTR() = PC();
}
void EightBit::IntelProcessor::jumpIndirect() {
void EightBit::IntelProcessor::jumpIndirect() noexcept {
MEMPTR() = fetchWord();
jump();
}
void EightBit::IntelProcessor::jump() {
void EightBit::IntelProcessor::jump() noexcept {
Processor::jump(MEMPTR());
}
void EightBit::IntelProcessor::callIndirect() {
void EightBit::IntelProcessor::callIndirect() noexcept {
MEMPTR() = fetchWord();
call();
}
void EightBit::IntelProcessor::call() {
void EightBit::IntelProcessor::call() noexcept {
call(MEMPTR());
}
void EightBit::IntelProcessor::call(register16_t destination) {
void EightBit::IntelProcessor::call(register16_t destination) noexcept {
Processor::call(destination);
}
void EightBit::IntelProcessor::jumpConditionalFlag(int flag) noexcept {
jumpConditional(convertCondition(flag));
}
void EightBit::IntelProcessor::jumpRelativeConditionalFlag(int flag) noexcept {
jumpRelativeConditional(convertCondition(flag));
}
void EightBit::IntelProcessor::returnConditionalFlag(int flag) noexcept {
returnConditional(convertCondition(flag));
}
void EightBit::IntelProcessor::callConditionalFlag(int flag) noexcept {
callConditional(convertCondition(flag));
}
void EightBit::IntelProcessor::cpl() noexcept {
A() = ~A();
}
bool EightBit::IntelProcessor::operator==(const EightBit::IntelProcessor& rhs) const noexcept {
auto& left = const_cast<IntelProcessor&>(*this);
auto& right = const_cast<IntelProcessor&>(rhs);
return
LittleEndianProcessor::operator==(rhs)
&& HALT() == rhs.HALT()
&& MEMPTR() == rhs.MEMPTR()
&& SP() == rhs.SP()
&& AF() == rhs.AF()
&& BC() == rhs.BC()
&& DE() == rhs.DE()
&& HL() == rhs.HL();
&& left.HALT() == right.HALT()
&& left.MEMPTR() == right.MEMPTR()
&& left.SP() == right.SP()
&& left.AF() == right.AF()
&& left.BC() == right.BC()
&& left.DE() == right.DE()
&& left.HL() == right.HL();
}
+7 -7
View File
@@ -7,44 +7,44 @@ EightBit::LittleEndianProcessor::LittleEndianProcessor(Bus& memory) noexcept
EightBit::LittleEndianProcessor::LittleEndianProcessor(const LittleEndianProcessor& rhs) noexcept
: Processor(rhs) {}
EightBit::register16_t EightBit::LittleEndianProcessor::getWord() {
EightBit::register16_t EightBit::LittleEndianProcessor::getWord() noexcept {
const auto low = memoryRead();
++BUS().ADDRESS();
const auto high = memoryRead();
return { low, high };
}
void EightBit::LittleEndianProcessor::setWord(const register16_t value) {
void EightBit::LittleEndianProcessor::setWord(const register16_t value) noexcept {
memoryWrite(value.low);
++BUS().ADDRESS();
memoryWrite(value.high);
}
EightBit::register16_t EightBit::LittleEndianProcessor::getWordPaged() {
EightBit::register16_t EightBit::LittleEndianProcessor::getWordPaged() noexcept {
const auto low = memoryRead();
++BUS().ADDRESS().low;
const auto high = memoryRead();
return { low, high };
}
void EightBit::LittleEndianProcessor::setWordPaged(register16_t value) {
void EightBit::LittleEndianProcessor::setWordPaged(register16_t value) noexcept {
memoryWrite(value.low);
++BUS().ADDRESS().low;
memoryWrite(value.high);
}
EightBit::register16_t EightBit::LittleEndianProcessor::fetchWord() {
EightBit::register16_t EightBit::LittleEndianProcessor::fetchWord() noexcept {
intermediate().low = fetchByte();
intermediate().high = fetchByte();
return intermediate();
}
void EightBit::LittleEndianProcessor::pushWord(const register16_t value) {
void EightBit::LittleEndianProcessor::pushWord(const register16_t value) noexcept {
push(value.high);
push(value.low);
}
EightBit::register16_t EightBit::LittleEndianProcessor::popWord() {
EightBit::register16_t EightBit::LittleEndianProcessor::popWord() noexcept {
const auto low = pop();
const auto high = pop();
return { low, high };
+31 -31
View File
@@ -7,109 +7,109 @@ EightBit::Processor::Processor(Bus& bus) noexcept
EightBit::Processor::Processor(const Processor& rhs) noexcept
: ClockedChip(rhs),
m_bus(rhs.m_bus) {
m_bus(rhs.m_bus),
m_opcode(rhs.m_opcode),
m_pc(rhs.m_pc),
m_intermediate(rhs.m_intermediate) {
RESET() = rhs.RESET();
INT() = rhs.INT();
PC() = rhs.PC();
}
DEFINE_PIN_LEVEL_CHANGERS(RESET, Processor)
DEFINE_PIN_LEVEL_CHANGERS(INT, Processor)
void EightBit::Processor::handleRESET() {
void EightBit::Processor::handleRESET() noexcept {
raiseRESET();
}
void EightBit::Processor::handleINT() {
void EightBit::Processor::handleINT() noexcept {
raiseINT();
}
void EightBit::Processor::memoryWrite(const register16_t address, const uint8_t data) {
void EightBit::Processor::memoryWrite(const register16_t address, const uint8_t data) noexcept {
BUS().ADDRESS() = address;
memoryWrite(data);
}
void EightBit::Processor::memoryWrite(const register16_t address) {
void EightBit::Processor::memoryWrite(const register16_t address) noexcept {
BUS().ADDRESS() = address;
memoryWrite();
}
void EightBit::Processor::memoryWrite(const uint8_t data) {
void EightBit::Processor::memoryWrite(const uint8_t data) noexcept {
BUS().DATA() = data;
memoryWrite();
}
void EightBit::Processor::memoryWrite() {
void EightBit::Processor::memoryWrite() noexcept {
busWrite();
}
void EightBit::Processor::busWrite() {
void EightBit::Processor::busWrite() noexcept {
BUS().write();
}
uint8_t EightBit::Processor::memoryRead(const register16_t address) {
uint8_t EightBit::Processor::memoryRead(const register16_t address) noexcept {
BUS().ADDRESS() = address;
return memoryRead();
}
uint8_t EightBit::Processor::memoryRead() {
uint8_t EightBit::Processor::memoryRead() noexcept {
return busRead();
}
uint8_t EightBit::Processor::busRead() {
uint8_t EightBit::Processor::busRead() noexcept {
return BUS().read();
}
EightBit::register16_t EightBit::Processor::getWordPaged(register16_t address) {
EightBit::register16_t EightBit::Processor::getWordPaged(register16_t address) noexcept {
BUS().ADDRESS() = address;
return getWordPaged();
}
EightBit::register16_t EightBit::Processor::getWordPaged(const uint8_t page, const uint8_t offset) {
EightBit::register16_t EightBit::Processor::getWordPaged(const uint8_t page, const uint8_t offset) noexcept {
BUS().ADDRESS() = { offset, page };
return getWordPaged();
}
void EightBit::Processor::setWordPaged(register16_t address, const register16_t value) {
void EightBit::Processor::setWordPaged(register16_t address, const register16_t value) noexcept {
BUS().ADDRESS() = address;
setWordPaged(value);
}
void EightBit::Processor::setWordPaged(const uint8_t page, const uint8_t offset, const register16_t value) {
void EightBit::Processor::setWordPaged(const uint8_t page, const uint8_t offset, const register16_t value) noexcept {
BUS().ADDRESS() = { offset, page };
setWordPaged(value);
}
EightBit::register16_t& EightBit::Processor::incrementPC() {
PC()++;
return PC();
EightBit::register16_t& EightBit::Processor::incrementPC() noexcept {
return ++PC();
}
EightBit::register16_t& EightBit::Processor::decrementPC() {
PC()--;
return PC();
EightBit::register16_t& EightBit::Processor::decrementPC() noexcept {
return --PC();
}
void EightBit::Processor::immediateAddress() {
void EightBit::Processor::immediateAddress() noexcept {
BUS().ADDRESS() = PC();
incrementPC();
}
uint8_t EightBit::Processor::fetchByte() {
uint8_t EightBit::Processor::fetchByte() noexcept {
immediateAddress();
return memoryRead();
}
uint8_t EightBit::Processor::fetchInstruction() {
uint8_t EightBit::Processor::fetchInstruction() noexcept {
return fetchByte();
}
EightBit::register16_t EightBit::Processor::getWord(const register16_t address) {
EightBit::register16_t EightBit::Processor::getWord(const register16_t address) noexcept {
BUS().ADDRESS() = address;
return getWord();
}
void EightBit::Processor::setWord(const register16_t address, const register16_t value) {
void EightBit::Processor::setWord(const register16_t address, const register16_t value) noexcept {
BUS().ADDRESS() = address;
setWord(value);
}
@@ -120,7 +120,7 @@ int EightBit::Processor::step() noexcept {
if (LIKELY(powered()))
poweredStep();
ExecutedInstruction.fire();
ASSUME(cycles() > 0);
// ASSUME(cycles() > 0); Not if unpowered!!
return cycles();
}
@@ -141,15 +141,15 @@ void EightBit::Processor::jump(const register16_t destination) noexcept {
}
void EightBit::Processor::jump(const uint16_t destination) noexcept {
PC().word = destination;
PC() = destination;
}
void EightBit::Processor::call(const register16_t destination) {
void EightBit::Processor::call(const register16_t destination) noexcept {
pushWord(PC());
jump(destination);
}
void EightBit::Processor::ret() {
void EightBit::Processor::ret() noexcept {
jump(popWord());
}
+3 -3
View File
@@ -3,7 +3,7 @@
#include <iostream>
bool EightBit::Rom::operator==(const Rom& rhs) const {
bool EightBit::Rom::operator==(const Rom& rhs) const noexcept {
return BYTES() == rhs.BYTES();
}
@@ -48,10 +48,10 @@ void EightBit::Rom::poke(const uint16_t address, const uint8_t value) noexcept {
EightBit::Rom::Rom(const size_t size) noexcept
: m_bytes(size) {}
EightBit::Rom::Rom(const Rom& rhs)
EightBit::Rom::Rom(const Rom& rhs) noexcept
: m_bytes(rhs.m_bytes) {}
EightBit::Rom& EightBit::Rom::operator=(const Rom& rhs) {
EightBit::Rom& EightBit::Rom::operator=(const Rom& rhs) noexcept {
if (this != &rhs)
m_bytes = rhs.m_bytes;
return *this;