Moving towards Z80 cycle accuracy

This commit is contained in:
Adrian Conlon
2026-03-03 10:30:08 +00:00
parent 199232dd53
commit a1afe7f78c
7 changed files with 239 additions and 225 deletions

View File

@@ -168,9 +168,6 @@
<ClCompile Include="tests.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\M6502\src\M6502.vcxproj">
<Project>{d8726a1b-bbfe-47ef-9860-26b90140ba66}</Project>
</ProjectReference>
<ProjectReference Include="..\..\src\EightBit.vcxproj">
<Project>{a9c24bd9-0cb4-4c84-b09b-46b815f9da47}</Project>
</ProjectReference>

View File

@@ -135,16 +135,14 @@ namespace EightBit {
void handleRESET() noexcept final;
void handleINT() noexcept final;
void pushWord(register16_t destination) noexcept final;
void memoryUpdate(int ticks) noexcept;
void memoryWrite() noexcept final;
uint8_t memoryRead() noexcept final;
void refreshMemory() noexcept;
void busWrite() noexcept final;
uint8_t busRead() noexcept final;
void jumpRelative(int8_t offset) noexcept final;
void jr(int8_t offset) noexcept final;
int jrConditional(int condition) noexcept final;
void call(register16_t destination) override;
private:
bool m_interruptPending = false;
@@ -189,17 +187,17 @@ namespace EightBit {
[[nodiscard]] constexpr auto displaced() const noexcept { return m_prefixDD || m_prefixFD; }
[[nodiscard]] constexpr const register16_t& displacedAddress() noexcept {
[[nodiscard]] constexpr void displaceAddress() noexcept {
const auto& index_register = m_prefixDD ? IX() : IY();
const auto address = index_register.word + m_displacement;
MEMPTR().word = address;
return MEMPTR();
BUS().ADDRESS() = MEMPTR();
}
void fetchDisplacement() noexcept;
[[nodiscard]] uint8_t fetchInstruction() noexcept;
[[nodiscard]] uint8_t fetchInstruction() noexcept final;
uint8_t readBusDataM1() noexcept;
uint8_t readDataUnderInterrupt();
typedef std::function<register16_t(void)> addresser_t;
void loadAccumulatorIndirect(addresser_t addresser) noexcept;
@@ -212,8 +210,8 @@ namespace EightBit {
[[nodiscard]] register16_t& RP(int rp) noexcept;
[[nodiscard]] register16_t& RP2(int rp) noexcept;
[[nodiscard]] uint8_t R(int r) noexcept;
void R(int r, uint8_t value) noexcept;
[[nodiscard]] uint8_t& R(int r, MemoryMapping::AccessLevel access = MemoryMapping::AccessLevel::ReadOnly) noexcept;
void R(int r, uint8_t value, int ticks = 1) noexcept;
void R2(int r, uint8_t value) noexcept;
[[nodiscard]] static constexpr auto zeroTest(uint8_t data) noexcept { return data & ZF; }
@@ -341,7 +339,7 @@ namespace EightBit {
return adjustOverflowSub(input, signTest(before), signTest(value), signTest(calculation));
}
[[nodiscard]] constexpr bool convertCondition(int flag) noexcept {
[[nodiscard]] bool convertCondition(int flag) noexcept override {
switch (flag) {
case 0:
return zero() == 0;
@@ -407,10 +405,7 @@ namespace EightBit {
void retn() noexcept;
void reti() noexcept;
void returnConditionalFlag(int flag) noexcept;
void jrConditionalFlag(int flag) noexcept;
void callConditionalFlag(int flag) noexcept;
void jumpConditionalFlag(int flag) noexcept;
void returnConditionalFlag(int flag) noexcept final;
[[nodiscard]] register16_t sbc(register16_t operand, register16_t value) noexcept;
[[nodiscard]] register16_t adc(register16_t operand, register16_t value) noexcept;
@@ -583,9 +578,10 @@ namespace EightBit {
adjustXY(((Q() ^ F()) | A()));
}
void cpl() noexcept {
void cpl() noexcept final {
setBit(HC | NF);
adjustXY(A() = ~A());
IntelProcessor::cpl();
adjustXY(A());
}
void xhtl(register16_t& exchange) noexcept;

View File

@@ -141,76 +141,57 @@ const EightBit::register16_t& EightBit::Z80::HL() const noexcept {
return m_registers[m_registerSet][HL_IDX];
}
void EightBit::Z80::pushWord(const register16_t destination) noexcept {
void EightBit::Z80::memoryUpdate(int ticks) noexcept {
assert(ticks > 0 && "Ticks must be greater than zero");
WritingMemory.fire();
tick(ticks);
lowerMREQ();
lowerWR();
tick();
IntelProcessor::memoryWrite();
raiseWR();
raiseMREQ();
tick();
IntelProcessor::pushWord(destination);
WrittenMemory.fire();
}
void EightBit::Z80::memoryWrite() noexcept {
memoryUpdate(1);
}
class _Writer final {
Z80& m_parent;
public:
_Writer(Z80& parent) noexcept
: m_parent(parent) {
m_parent.WritingMemory.fire();
m_parent.tick(2);
m_parent.lowerMREQ();
}
~_Writer() noexcept {
m_parent.raiseMREQ();
m_parent.WrittenMemory.fire();
}
};
_Writer writer(*this);
IntelProcessor::memoryWrite();
void EightBit::Z80::refreshMemory() noexcept {
assert(lowered(M1()) && "M1 must be lowered to refresh memory");
BUS().ADDRESS() = { REFRESH(), IV() };
lowerRFSH();
tick();
lowerMREQ();
raiseMREQ();
raiseRFSH();
}
uint8_t EightBit::Z80::memoryRead() noexcept {
class _Reader final {
Z80& m_parent;
public:
_Reader(Z80& parent) noexcept
: m_parent(parent) {
m_parent.ReadingMemory.fire();
if (lowered(m_parent.M1()))
m_parent.tick();
m_parent.tick(2);
m_parent.lowerMREQ();
}
~_Reader() noexcept {
m_parent.raiseMREQ();
m_parent.ReadMemory.fire();
}
};
_Reader reader(*this);
return IntelProcessor::memoryRead();
}
void EightBit::Z80::busWrite() noexcept {
ReadingMemory.fire();
tick();
_ActivateWR writer(*this);
IntelProcessor::busWrite();
}
uint8_t EightBit::Z80::busRead() noexcept {
lowerMREQ();
lowerRD();
tick();
IntelProcessor::memoryRead();
raiseRD();
raiseMREQ();
if (lowered(M1()))
refreshMemory();
tick();
_ActivateRD reader(*this);
return IntelProcessor::busRead();
ReadMemory.fire();
return BUS().DATA();
}
void EightBit::Z80::handleRESET() noexcept {
IntelProcessor::handleRESET();
disableInterrupts();
IM() = 0;
IV() = 0;
REFRESH() = 0;
SP().word = AF().word = Mask16;
tick(3);
}
void EightBit::Z80::handleNMI() noexcept {
@@ -218,18 +199,32 @@ void EightBit::Z80::handleNMI() noexcept {
raiseHALT();
IFF2() = IFF1();
IFF1() = false;
readBusDataM1();
lowerM1();
raiseM1();
restart(0x66);
}
uint8_t EightBit::Z80::readDataUnderInterrupt() {
lowerM1();
tick(3);
lowerIORQ();
tick();
const auto data = BUS().DATA();
raiseIORQ();
assert(cycles() == 4);
refreshMemory();
assert(cycles() == 5);
raiseM1();
return data;
}
void EightBit::Z80::handleINT() noexcept {
IntelProcessor::handleINT();
tick(2); // 2 extra clock cycles introduced to allow the bus to settle
uint8_t data;
{
_ActivateIORQ iorq(*this);
data = readBusDataM1();
}
const auto data = readDataUnderInterrupt();
tick();
assert(cycles() == 6);
switch (IM()) {
case 0: // i8080 equivalent
@@ -237,11 +232,13 @@ void EightBit::Z80::handleINT() noexcept {
break;
case 1:
restart(7 << 3);
assert(cycles() == 13);
break;
case 2:
tick(7); // How long to allow fetching data from the device...
tick();
MEMPTR() = Processor::getWordPaged(IV(), data);
call(MEMPTR());
assert(cycles() == 13);
break;
default:
UNREACHABLE;
@@ -257,23 +254,12 @@ void EightBit::Z80::enableInterrupts() {
}
void EightBit::Z80::returnConditionalFlag(const int flag) noexcept {
const auto condition = convertCondition(flag);
tick();
if (convertCondition(flag))
if (condition)
ret();
}
void EightBit::Z80::jrConditionalFlag(const int flag) noexcept {
jrConditional(convertCondition(flag));
}
void EightBit::Z80::jumpConditionalFlag(const int flag) noexcept {
jumpConditional(convertCondition(flag));
}
void EightBit::Z80::callConditionalFlag(const int flag) noexcept {
callConditional(convertCondition(flag));
}
void EightBit::Z80::retn() noexcept {
ret();
IFF1() = IFF2();
@@ -283,15 +269,15 @@ void EightBit::Z80::reti() noexcept {
retn();
}
void EightBit::Z80::jr(int8_t offset) noexcept {
IntelProcessor::jr(offset);
tick(5);
void EightBit::Z80::call(register16_t destination) {
tick();
Processor::call(destination);
}
int EightBit::Z80::jrConditional(const int condition) noexcept {
if (!IntelProcessor::jrConditional(condition))
tick(3);
return condition;
void EightBit::Z80::jumpRelative(int8_t offset) noexcept {
IntelProcessor::jumpRelative(offset);
tick(5);
}
EightBit::register16_t EightBit::Z80::sbc(const register16_t operand, const register16_t value) noexcept {
@@ -345,7 +331,6 @@ EightBit::register16_t EightBit::Z80::add(const register16_t operand, const regi
MEMPTR() = operand + 1;
tick(7);
return intermediate();
}
@@ -353,12 +338,13 @@ void EightBit::Z80::xhtl(register16_t& exchange) noexcept {
MEMPTR().low = IntelProcessor::memoryRead(SP());
++BUS().ADDRESS();
MEMPTR().high = memoryRead();
tick();
IntelProcessor::memoryWrite(exchange.high);
BUS().DATA() = exchange.high;
exchange.high = MEMPTR().high;
memoryUpdate(2);
--BUS().ADDRESS();
IntelProcessor::memoryWrite(exchange.low);
BUS().DATA() = exchange.low;
exchange.low = MEMPTR().low;
memoryUpdate(1);
tick(2);
}
@@ -597,7 +583,7 @@ void EightBit::Z80::writePort(const uint8_t port) noexcept {
void EightBit::Z80::writePort() noexcept {
MEMPTR() = BUS().ADDRESS();
//tick(2);
tick(2);
lowerIORQ();
lowerWR();
tick();
@@ -620,11 +606,12 @@ void EightBit::Z80::readPort(const uint8_t port) noexcept {
void EightBit::Z80::readPort() noexcept {
MEMPTR() = BUS().ADDRESS();
//tick(2);
tick(2);
tick();
lowerIORQ();
lowerRD();
BUS().DATA() = m_ports.read(BUS().ADDRESS());
tick();
raiseRD();
raiseIORQ();
tick();
@@ -638,11 +625,6 @@ void EightBit::Z80::fetchDisplacement() noexcept {
//
uint8_t EightBit::Z80::readBusDataM1() noexcept {
_ActivateM1 m1(*this);
return BUS().DATA();
}
// ** From the Z80 CPU User Manual
// Figure 5 depicts the timing during an M1 (op code fetch) cycle. The Program Counter is
@@ -671,22 +653,10 @@ uint8_t EightBit::Z80::readBusDataM1() noexcept {
// CPU.The HALT acknowledge signal is active during this time indicating that the processor
// is in the HALT state
uint8_t EightBit::Z80::fetchInstruction() noexcept {
uint8_t returned;
{
_ActivateM1 m1(*this);
const auto halted = lowered(HALT());
returned = IntelProcessor::memoryRead(PC());
if (UNLIKELY(halted))
returned = 0; // NOP
else
PC()++;
}
BUS().ADDRESS() = { REFRESH(), IV() };
{
_ActivateRFSH rfsh(*this);
_ActivateMREQ mreq(*this);
}
return returned;
lowerM1();
IntelProcessor::fetchInstruction();
raiseM1();
return BUS().DATA();
}
void EightBit::Z80::loadAccumulatorIndirect(addresser_t addresser) noexcept {
@@ -745,7 +715,7 @@ EightBit::register16_t& EightBit::Z80::RP2(const int rp) noexcept {
}
}
uint8_t EightBit::Z80::R(const int r) noexcept {
uint8_t& EightBit::Z80::R(const int r, MemoryMapping::AccessLevel access) noexcept {
switch (r) {
case 0:
return B();
@@ -760,7 +730,21 @@ uint8_t EightBit::Z80::R(const int r) noexcept {
case 5:
return HL2().low;
case 6:
return IntelProcessor::memoryRead(UNLIKELY(displaced()) ? displacedAddress() : HL());
if (displaced())
displaceAddress();
else
BUS().ADDRESS() = HL();
switch (access) {
case MemoryMapping::AccessLevel::ReadOnly:
memoryRead();
break;
case MemoryMapping::AccessLevel::WriteOnly:
break;
default:
UNREACHABLE;
break;
}
return BUS().DATA();
case 7:
return A();
default:
@@ -768,35 +752,11 @@ uint8_t EightBit::Z80::R(const int r) noexcept {
}
}
void EightBit::Z80::R(const int r, const uint8_t value) noexcept {
switch (r) {
case 0:
B() = value;
break;
case 1:
C() = value;
break;
case 2:
D() = value;
break;
case 3:
E() = value;
break;
case 4:
HL2().high = value;
break;
case 5:
HL2().low = value;
break;
case 6:
IntelProcessor::memoryWrite(UNLIKELY(displaced()) ? displacedAddress() : HL(), value);
break;
case 7:
A() = value;
break;
default:
UNREACHABLE;
}
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);
}
void EightBit::Z80::R2(const int r, const uint8_t value) noexcept {
@@ -879,11 +839,13 @@ void EightBit::Z80::executeCB(const int x, const int y, const int z) noexcept {
const bool memoryZ = z == 6;
const bool indirect = (!displaced() && memoryZ) || displaced();
const auto direct = !indirect;
uint8_t operand;
if (displaced()) {
tick(2);
operand = IntelProcessor::memoryRead(displacedAddress());
displaceAddress();
operand = memoryRead();
} else {
operand = R(z);
}
@@ -923,8 +885,8 @@ void EightBit::Z80::executeCB(const int x, const int y, const int z) noexcept {
break;
} case 1: // BIT y, r[z]
bit(y, operand);
adjustXY(indirect ? MEMPTR().high : operand);
if (memoryZ)
adjustXY(direct ? operand : MEMPTR().high);
if (indirect)
tick();
break;
case 2: // RES y, r[z]
@@ -937,8 +899,8 @@ void EightBit::Z80::executeCB(const int x, const int y, const int z) noexcept {
UNREACHABLE;
}
if (update) {
tick();
if (displaced()) {
tick();
IntelProcessor::memoryWrite(operand);
if (!memoryZ)
R2(z, operand);
@@ -980,6 +942,7 @@ 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();
@@ -1147,16 +1110,16 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
break;
case 2: // DJNZ d
tick();
jrConditional(--B());
jumpRelativeConditional(--B());
break;
case 3: // JR d
jr(fetchByte());
jumpRelative(fetchByte());
break;
case 4: // JR cc,d
case 5:
case 6:
case 7:
jrConditionalFlag(y - 4);
jumpRelativeConditionalFlag(y - 4);
break;
default:
UNREACHABLE;
@@ -1169,6 +1132,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
break;
case 1: // ADD HL,rp
HL2() = add(HL2(), RP(p));
tick(7);
break;
default:
UNREACHABLE;
@@ -1237,9 +1201,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
tick(5);
}
const auto original = R(y);
if (memoryY)
tick();
R(y, increment(original));
R(y, increment(original), 2);
break;
}
case 5: { // 8-bit DEC
@@ -1248,16 +1210,14 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
tick(5);
}
const auto original = R(y);
if (memoryY)
tick();
R(y, decrement(original));
R(y, decrement(original), 2);
break;
}
case 6: { // 8-bit load immediate
if (memoryY && displaced())
fetchDisplacement();
const auto value = fetchByte();
if (displaced())
if (memoryY)
tick(2);
R(y, value); // LD r,n
break;
@@ -1297,24 +1257,20 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
}
break;
case 1: // 8-bit loading
if ((memoryZ && memoryY)) { // Exception (replaces LD (HL), (HL))
lowerHALT();
} else {
if (!(memoryZ && memoryY)) {
bool normal = true;
if (displaced()) {
if (memoryZ || memoryY)
if (memoryZ || memoryY) {
fetchDisplacement();
tick(5);
}
if (memoryZ) {
switch (y) {
case 4:
if (displaced())
tick(5);
H() = R(z);
normal = false;
break;
case 5:
if (displaced())
tick(5);
L() = R(z);
normal = false;
break;
@@ -1323,25 +1279,20 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
if (memoryY) {
switch (z) {
case 4:
if (displaced())
tick(5);
R(y, H());
normal = false;
break;
case 5:
if (displaced())
tick(5);
R(y, L());
normal = false;
break;
}
}
}
if (normal) {
if (displaced())
tick(5);
if (normal)
R(y, R(z));
}
} else {
lowerHALT(); // Exception (replaces LD (HL), (HL))
}
break;
case 2: { // Operate on accumulator and register/memory location
@@ -1399,7 +1350,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
exx();
break;
case 2: // JP (HL)
jump(HL2());
Processor::jump(HL2());
break;
case 3: // LD SP,HL
SP() = HL2();
@@ -1459,6 +1410,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
case 5: // PUSH & various ops
switch (q) {
case 0: // PUSH rp2[p]
tick();
pushWord(RP2(p));
break;
case 1:

View File

@@ -150,26 +150,55 @@ namespace EightBit {
//
register16_t& incrementPC() override;
uint8_t fetchInstruction() override;
//
[[nodiscard]] register16_t getWord() final;
void setWord(register16_t value) final;
//
virtual void restart(uint8_t address);
virtual int callConditional(int condition);
virtual int jumpConditional(int condition);
virtual int returnConditional(int condition);
virtual void jr(int8_t offset) noexcept;
virtual int jrConditional(int condition);
virtual void callConditional(bool condition);
virtual void jumpConditional(bool condition);
virtual void jumpRelativeConditional(bool condition);
virtual void returnConditional(bool condition);
virtual void jumpIndirect();
virtual void jump();
void callIndirect();
void call();
virtual void jumpRelative(int8_t offset) noexcept;
void jumpRelative(uint8_t offset) noexcept { jumpRelative((int8_t)offset); }
void ret() override;
virtual void fetchWordMEMPTR();
void jumpIndirect();
void callIndirect();
void resetWorkingRegisters() noexcept;
[[nodiscard]] virtual bool convertCondition(int flag) noexcept = 0;
virtual void jumpConditionalFlag(int flag) {
jumpConditional(convertCondition(flag));
}
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();
}
private:
static std::array<int, 8> m_halfCarryTableAdd;
static std::array<int, 8> m_halfCarryTableSub;

View File

@@ -70,7 +70,13 @@ namespace EightBit {
virtual uint8_t memoryRead();
virtual uint8_t busRead();
virtual register16_t& incrementPC();
virtual register16_t& decrementPC();
virtual void immediateAddress();
uint8_t fetchByte();
virtual uint8_t fetchInstruction();
[[nodiscard]] virtual register16_t getWord() = 0;
virtual void setWord(register16_t value) = 0;

View File

@@ -9,9 +9,6 @@ EightBit::IntelProcessor::IntelProcessor(Bus& bus)
for (int i = 0; i < 0x100; ++i)
m_decodedOpcodes.at(i) = i;
LoweredHALT.connect([this](EventArgs) noexcept { --PC(); });
RaisedHALT.connect([this](EventArgs) noexcept { ++PC(); });
RaisedPOWER.connect([this](EventArgs) {
PC() = SP() = Mask16;
resetWorkingRegisters();
@@ -37,7 +34,7 @@ DEFINE_PIN_LEVEL_CHANGERS(HALT, IntelProcessor);
void EightBit::IntelProcessor::handleRESET() {
Processor::handleRESET();
disableInterrupts();
jump(0);
Processor::jump(0);
}
void EightBit::IntelProcessor::handleINT() {
@@ -54,6 +51,18 @@ uint8_t EightBit::IntelProcessor::pop() {
return memoryRead(SP()++);
}
EightBit::register16_t& EightBit::IntelProcessor::incrementPC() {
if (raised(HALT()))
Processor::incrementPC();
return PC();
}
uint8_t EightBit::IntelProcessor::fetchInstruction() {
fetchByte();
return lowered(HALT()) ? (uint8_t)0 : BUS().DATA();
}
EightBit::register16_t EightBit::IntelProcessor::getWord() {
const auto returned = LittleEndianProcessor::getWord();
MEMPTR() = BUS().ADDRESS();
@@ -66,41 +75,38 @@ void EightBit::IntelProcessor::setWord(const register16_t value) {
}
void EightBit::IntelProcessor::restart(const uint8_t address) {
call(MEMPTR() = { address, 0 });
MEMPTR() = { address, 0 };
call();
}
int EightBit::IntelProcessor::callConditional(const int condition) {
void EightBit::IntelProcessor::callConditional(bool condition) {
fetchWordMEMPTR();
if (condition)
call(MEMPTR());
return condition;
call();
}
int EightBit::IntelProcessor::jumpConditional(const int condition) {
void EightBit::IntelProcessor::jumpConditional(bool condition) {
fetchWordMEMPTR();
if (condition)
jump(MEMPTR());
return condition;
jump();
}
int EightBit::IntelProcessor::returnConditional(const int condition) {
void EightBit::IntelProcessor::jumpRelativeConditional(bool condition) {
const auto offset = fetchByte();
if (condition)
jumpRelative(offset);
}
void EightBit::IntelProcessor::returnConditional(bool condition) {
if (condition)
ret();
return condition;
}
void EightBit::IntelProcessor::jr(const int8_t offset) noexcept {
jump(MEMPTR() = PC() + offset);
void EightBit::IntelProcessor::jumpRelative(const int8_t offset) noexcept {
MEMPTR() = PC() + offset;
jump();
}
int EightBit::IntelProcessor::jrConditional(const int condition) {
const auto offsetAddress = PC()++;
if (condition) {
const auto offset = memoryRead(offsetAddress);
jr(offset);
}
return condition;
}
void EightBit::IntelProcessor::ret() {
LittleEndianProcessor::ret();
@@ -114,12 +120,20 @@ void EightBit::IntelProcessor::fetchWordMEMPTR() {
void EightBit::IntelProcessor::jumpIndirect() {
fetchWordMEMPTR();
jump(MEMPTR());
jump();
}
void EightBit::IntelProcessor::jump() {
Processor::jump(MEMPTR());
}
void EightBit::IntelProcessor::callIndirect() {
fetchWordMEMPTR();
call(MEMPTR());
call();
}
void EightBit::IntelProcessor::call() {
Processor::call(MEMPTR());
}
bool EightBit::IntelProcessor::operator==(const EightBit::IntelProcessor& rhs) const noexcept {

View File

@@ -80,8 +80,28 @@ void EightBit::Processor::setWordPaged(const uint8_t page, const uint8_t offset,
setWordPaged(value);
}
EightBit::register16_t& EightBit::Processor::incrementPC() {
PC()++;
return PC();
}
EightBit::register16_t& EightBit::Processor::decrementPC() {
PC()--;
return PC();
}
void EightBit::Processor::immediateAddress() {
BUS().ADDRESS() = PC();
incrementPC();
}
uint8_t EightBit::Processor::fetchByte() {
return memoryRead(PC()++);
immediateAddress();
return memoryRead();
}
uint8_t EightBit::Processor::fetchInstruction() {
return fetchByte();
}
EightBit::register16_t EightBit::Processor::getWord(const register16_t address) {