mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2026-04-26 21:18:36 +00:00
Lots of miscellaneous cycle accurate updates
This commit is contained in:
1 parent
81c1703ea9
commit
d533593a14
25 files changed
+601
-613
No files matched your search
@@ -20,4 +20,4 @@ void TestRunner::lowerPOWER() noexcept {
|
||||
EightBit::Bus::lowerPOWER();
|
||||
}
|
||||
|
||||
void TestRunner::initialise() {}
|
||||
void TestRunner::initialise() noexcept {}
|
||||
@@ -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; }
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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,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
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
+3
-1
@@ -17,7 +17,9 @@ namespace EightBit {
|
||||
m_delegates.push_back(functor);
|
||||
}
|
||||
|
||||
void fire(T& e = EventArgs::empty()) const {
|
||||
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
@@ -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
@@ -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
@@ -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,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
@@ -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
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user