Start refactoring CPU cores to use C++17/14 features. (This commit covers the 6502 and Z80)

Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
Adrian Conlon 2018-10-27 18:41:55 +01:00
parent 62f3cd717b
commit fac2da9ac4
4 changed files with 142 additions and 148 deletions

View File

@ -63,10 +63,10 @@ namespace EightBit {
void interrupt(uint8_t vector); void interrupt(uint8_t vector);
void adjustZero(uint8_t datum) { clearFlag(P(), ZF, datum); } void adjustZero(const uint8_t datum) { clearFlag(P(), ZF, datum); }
void adjustNegative(uint8_t datum) { setFlag(P(), NF, datum & NF); } void adjustNegative(const uint8_t datum) { setFlag(P(), NF, datum & NF); }
void adjustNZ(uint8_t datum) { void adjustNZ(const uint8_t datum) {
adjustZero(datum); adjustZero(datum);
adjustNegative(datum); adjustNegative(datum);
} }
@ -76,19 +76,19 @@ namespace EightBit {
// Address resolution // Address resolution
register16_t Address_Absolute() { auto Address_Absolute() {
return fetchWord(); return fetchWord();
} }
uint8_t Address_ZeroPage() { auto Address_ZeroPage() {
return fetchByte(); return fetchByte();
} }
register16_t Address_ZeroPageIndirect() { auto Address_ZeroPageIndirect() {
return getWordPaged(0, Address_ZeroPage()); return getWordPaged(0, Address_ZeroPage());
} }
register16_t Address_Indirect() { auto Address_Indirect() {
const auto address = Address_Absolute(); const auto address = Address_Absolute();
return getWordPaged(address.high, address.low); return getWordPaged(address.high, address.low);
} }
@ -101,110 +101,113 @@ namespace EightBit {
return Address_ZeroPage() + Y(); return Address_ZeroPage() + Y();
} }
std::tuple<register16_t, bool> Address_AbsoluteX() { auto Address_AbsoluteX() {
auto address = Address_Absolute(); auto address = Address_Absolute();
const auto page = address.high; const auto page = address.high;
address += X(); address += X();
return std::tuple<register16_t, bool>(address, address.high != page); return std::make_pair(address, address.high != page);
} }
std::tuple<register16_t, bool> Address_AbsoluteY() { auto Address_AbsoluteY() {
auto address = Address_Absolute(); auto address = Address_Absolute();
const auto page = address.high; const auto page = address.high;
address += Y(); address += Y();
return std::tuple<register16_t, bool>(address, address.high != page); return std::make_pair(address, address.high != page);
} }
register16_t Address_IndexedIndirectX() { auto Address_IndexedIndirectX() {
return getWordPaged(0, Address_ZeroPageX()); return getWordPaged(0, Address_ZeroPageX());
} }
std::tuple<register16_t, bool> Address_IndirectIndexedY() { auto Address_IndirectIndexedY() {
auto address = Address_ZeroPageIndirect(); auto address = Address_ZeroPageIndirect();
const auto page = address.high; const auto page = address.high;
address += Y(); address += Y();
return std::tuple<register16_t, bool>(address, address.high != page); return std::make_pair(address, address.high != page);
} }
// Addressing modes, read // Addressing modes, read
uint8_t AM_Immediate() { auto AM_Immediate() {
return fetchByte(); return fetchByte();
} }
uint8_t AM_Absolute() { auto AM_Absolute() {
return BUS().read(Address_Absolute()); return BUS().read(Address_Absolute());
} }
uint8_t AM_ZeroPage() { auto AM_ZeroPage() {
return BUS().read(Address_ZeroPage()); return BUS().read(Address_ZeroPage());
} }
uint8_t AM_AbsoluteX() { auto AM_AbsoluteX() {
const auto ap = Address_AbsoluteX(); const auto [address, paged] = Address_AbsoluteX();
if (UNLIKELY(std::get<1>(ap))) if (UNLIKELY(paged))
addCycle(); addCycle();
return BUS().read(std::get<0>(ap)); return BUS().read(address);
} }
uint8_t AM_AbsoluteY() { auto AM_AbsoluteY() {
const auto ap = Address_AbsoluteY(); const auto [address, paged] = Address_AbsoluteY();
if (UNLIKELY(std::get<1>(ap))) if (UNLIKELY(paged))
addCycle(); addCycle();
return BUS().read(std::get<0>(ap)); return BUS().read(address);
} }
uint8_t AM_ZeroPageX() { auto AM_ZeroPageX() {
return BUS().read(Address_ZeroPageX()); return BUS().read(Address_ZeroPageX());
} }
uint8_t AM_ZeroPageY() { auto AM_ZeroPageY() {
return BUS().read(Address_ZeroPageY()); return BUS().read(Address_ZeroPageY());
} }
uint8_t AM_IndexedIndirectX() { auto AM_IndexedIndirectX() {
return BUS().read(Address_IndexedIndirectX()); return BUS().read(Address_IndexedIndirectX());
} }
uint8_t AM_IndirectIndexedY() { auto AM_IndirectIndexedY() {
const auto ap = Address_IndirectIndexedY(); const auto [address, paged] = Address_IndirectIndexedY();
if (UNLIKELY(std::get<1>(ap))) if (UNLIKELY(paged))
addCycle(); addCycle();
return BUS().read(std::get<0>(ap)); return BUS().read(address);
} }
// Addressing modes, write // Addressing modes, write
void AM_Absolute(uint8_t value) { void AM_Absolute(const uint8_t value) {
BUS().write(Address_Absolute(), value); BUS().write(Address_Absolute(), value);
} }
void AM_ZeroPage(uint8_t value) { void AM_ZeroPage(const uint8_t value) {
BUS().write(Address_ZeroPage(), value); BUS().write(Address_ZeroPage(), value);
} }
void AM_AbsoluteX(uint8_t value) { void AM_AbsoluteX(const uint8_t value) {
BUS().write(std::get<0>(Address_AbsoluteX()), value); const auto [address, paged] = Address_AbsoluteX();
BUS().write(address, value);
} }
void AM_AbsoluteY(uint8_t value) { void AM_AbsoluteY(const uint8_t value) {
BUS().write(std::get<0>(Address_AbsoluteY()), value); const auto [address, paged] = Address_AbsoluteY();
BUS().write(address, value);
} }
void AM_ZeroPageX(uint8_t value) { void AM_ZeroPageX(const uint8_t value) {
BUS().write(Address_ZeroPageX(), value); BUS().write(Address_ZeroPageX(), value);
} }
void AM_ZeroPageY(uint8_t value) { void AM_ZeroPageY(const uint8_t value) {
BUS().write(Address_ZeroPageY(), value); BUS().write(Address_ZeroPageY(), value);
} }
void AM_IndexedIndirectX(uint8_t value) { void AM_IndexedIndirectX(const uint8_t value) {
BUS().write(Address_IndexedIndirectX(), value); BUS().write(Address_IndexedIndirectX(), value);
} }
void AM_IndirectIndexedY(uint8_t value) { void AM_IndirectIndexedY(const uint8_t value) {
BUS().write(std::get<0>(Address_IndirectIndexedY()), value); const auto [address, paged] = Address_IndirectIndexedY();
BUS().write(address, value);
} }
// Operations // Operations
@ -219,77 +222,77 @@ namespace EightBit {
A() = SBC(A(), value); A() = SBC(A(), value);
} }
void SLO(uint8_t value) { void SLO(const uint8_t value) {
const auto result = ASL(value); const auto result = ASL(value);
BUS().write(result); BUS().write(result);
ORA(result); ORA(result);
} }
void SRE(uint8_t value) { void SRE(const uint8_t value) {
const auto result = LSR(value); const auto result = LSR(value);
BUS().write(result); BUS().write(result);
EORA(result); EORA(result);
} }
void RLA(uint8_t value) { void RLA(const uint8_t value) {
const auto result = ROL(value); const auto result = ROL(value);
BUS().write(result); BUS().write(result);
ANDA(result); ANDA(result);
} }
void RRA(uint8_t value) { void RRA(const uint8_t value) {
const auto result = ROR(value); const auto result = ROR(value);
BUS().write(result); BUS().write(result);
A() = ADC(A(), result); A() = ADC(A(), result);
} }
void LAX(uint8_t value) { void LAX(const uint8_t value) {
adjustNZ(X() = A() = value); adjustNZ(X() = A() = value);
} }
void AAC(uint8_t value) { void AAC(const uint8_t value) {
ANDA(value); ANDA(value);
setFlag(P(), CF, A() & Bit7); setFlag(P(), CF, A() & Bit7);
} }
void ASR(uint8_t value) { void ASR(const uint8_t value) {
A() = LSR(A() & value); A() = LSR(A() & value);
} }
void ARR(uint8_t value) { void ARR(const uint8_t value) {
} }
void ATX(uint8_t value) { void ATX(const uint8_t value) {
ANDA(value); ANDA(value);
X() = A(); X() = A();
} }
void AXS(uint8_t value) { void AXS(const uint8_t value) {
} }
// //
uint8_t DEC(uint8_t value) { auto DEC(uint8_t value) {
const auto result = --value; const auto result = --value;
adjustNZ(result); adjustNZ(result);
return result; return result;
} }
uint8_t INC(uint8_t value) { auto INC(uint8_t value) {
const auto result = ++value; const auto result = ++value;
adjustNZ(result); adjustNZ(result);
return result; return result;
} }
void ORA(uint8_t value) { void ORA(const uint8_t value) {
adjustNZ(A() |= value); adjustNZ(A() |= value);
} }
void ANDA(uint8_t value) { void ANDA(const uint8_t value) {
adjustNZ(A() &= value); adjustNZ(A() &= value);
} }
void EORA(uint8_t value) { void EORA(const uint8_t value) {
adjustNZ(A() ^= value); adjustNZ(A() ^= value);
} }

View File

@ -441,7 +441,7 @@ uint8_t EightBit::MOS6502::SUB_d(const uint8_t operand, const uint8_t data, cons
return promoteNibble(high) | lowNibble(low); return promoteNibble(high) | lowNibble(low);
} }
void EightBit::MOS6502::CMP(uint8_t first, uint8_t second) { void EightBit::MOS6502::CMP(const uint8_t first, const uint8_t second) {
const register16_t result = first - second; const register16_t result = first - second;
adjustNZ(result.low); adjustNZ(result.low);
clearFlag(P(), CF, result.high); clearFlag(P(), CF, result.high);
@ -487,7 +487,7 @@ uint8_t EightBit::MOS6502::ADD_d(uint8_t operand, uint8_t data, int carry) {
//// ////
void EightBit::MOS6502::Branch(int8_t displacement) { void EightBit::MOS6502::Branch(const int8_t displacement) {
const auto page = PC().high; const auto page = PC().high;
PC() += displacement; PC() += displacement;
if (UNLIKELY(PC().high != page)) if (UNLIKELY(PC().high != page))
@ -495,7 +495,7 @@ void EightBit::MOS6502::Branch(int8_t displacement) {
addCycle(); addCycle();
} }
void EightBit::MOS6502::Branch(bool flag) { void EightBit::MOS6502::Branch(const bool flag) {
const int8_t displacement = AM_Immediate(); const int8_t displacement = AM_Immediate();
if (UNLIKELY(flag)) if (UNLIKELY(flag))
Branch(displacement); Branch(displacement);

View File

@ -28,7 +28,7 @@ namespace EightBit {
return (high << 7) | variable; return (high << 7) | variable;
} }
refresh_t& operator++() { auto& operator++() {
++variable; ++variable;
return *this; return *this;
} }
@ -51,8 +51,8 @@ namespace EightBit {
Signal<Z80> ExecutingInstruction; Signal<Z80> ExecutingInstruction;
Signal<Z80> ExecutedInstruction; Signal<Z80> ExecutedInstruction;
PinLevel& NMI() { return m_nmiLine; } // In auto& NMI() { return m_nmiLine; } // In
PinLevel& M1() { return m_m1Line; } // Out auto& M1() { return m_m1Line; } // Out
virtual int execute(uint8_t opcode) final; virtual int execute(uint8_t opcode) final;
virtual int step() final; virtual int step() final;
@ -63,19 +63,19 @@ namespace EightBit {
virtual register16_t& DE() final; virtual register16_t& DE() final;
virtual register16_t& HL() final; virtual register16_t& HL() final;
register16_t& IX() { return m_ix; } auto& IX() { return m_ix; }
uint8_t& IXH() { return IX().high; } auto& IXH() { return IX().high; }
uint8_t& IXL() { return IX().low; } auto& IXL() { return IX().low; }
register16_t& IY() { return m_iy; } auto& IY() { return m_iy; }
uint8_t& IYH() { return IY().high; } auto& IYH() { return IY().high; }
uint8_t& IYL() { return IY().low; } auto& IYL() { return IY().low; }
refresh_t& REFRESH() { return m_refresh; } auto& REFRESH() { return m_refresh; }
uint8_t& IV() { return iv; } auto& IV() { return iv; }
int& IM() { return m_interruptMode; } auto& IM() { return m_interruptMode; }
bool& IFF1() { return m_iff1; } auto& IFF1() { return m_iff1; }
bool& IFF2() { return m_iff2; } auto& IFF2() { return m_iff2; }
void exx() { void exx() {
m_registerSet ^= 1; m_registerSet ^= 1;
@ -132,7 +132,50 @@ namespace EightBit {
m_displacement = fetchByte(); m_displacement = fetchByte();
} }
uint8_t R(const int r) { auto& HL2() {
if (LIKELY(!m_displaced))
return HL();
if (m_prefixDD)
return IX();
// Must be FD prefix
return IY();
}
auto& RP(const int rp) {
ASSUME(rp >= 0);
ASSUME(rp <= 3);
switch (rp) {
case 0:
return BC();
case 1:
return DE();
case 2:
return HL2();
case 3:
return SP();
default:
UNREACHABLE;
}
}
auto& RP2(const int rp) {
ASSUME(rp >= 0);
ASSUME(rp <= 3);
switch (rp) {
case 0:
return BC();
case 1:
return DE();
case 2:
return HL2();
case 3:
return AF();
default:
UNREACHABLE;
}
}
auto R(const int r) {
ASSUME(r >= 0); ASSUME(r >= 0);
ASSUME(r <= 7); ASSUME(r <= 7);
switch (r) { switch (r) {
@ -190,7 +233,7 @@ namespace EightBit {
} }
} }
uint8_t R2(const int r) { auto R2(const int r) {
ASSUME(r >= 0); ASSUME(r >= 0);
ASSUME(r <= 7); ASSUME(r <= 7);
switch (r) { switch (r) {
@ -248,49 +291,6 @@ namespace EightBit {
} }
} }
register16_t& RP(const int rp) {
ASSUME(rp >= 0);
ASSUME(rp <= 3);
switch (rp) {
case 0:
return BC();
case 1:
return DE();
case 2:
return HL2();
case 3:
return SP();
default:
UNREACHABLE;
}
}
register16_t& HL2() {
if (LIKELY(!m_displaced))
return HL();
if (m_prefixDD)
return IX();
// Must be FD prefix
return IY();
}
register16_t& RP2(const int rp) {
ASSUME(rp >= 0);
ASSUME(rp <= 3);
switch (rp) {
case 0:
return BC();
case 1:
return DE();
case 2:
return HL2();
case 3:
return AF();
default:
UNREACHABLE;
}
}
static void adjustHalfCarryAdd(uint8_t& f, const uint8_t before, const uint8_t value, const int calculation) { static void adjustHalfCarryAdd(uint8_t& f, const uint8_t before, const uint8_t value, const int calculation) {
setFlag(f, HC, calculateHalfCarryAdd(before, value, calculation)); setFlag(f, HC, calculateHalfCarryAdd(before, value, calculation));
} }
@ -395,7 +395,7 @@ namespace EightBit {
void ind(); void ind();
bool indr(); bool indr();
void blockOut(const register16_t source, register16_t& destination); void blockOut(register16_t source, register16_t& destination);
void outi(); void outi();
bool otir(); bool otir();

View File

@ -38,15 +38,16 @@ void EightBit::Z80::powerOn() {
IV() = Mask8; IV() = Mask8;
exxAF(); exxAF();
exx(); AF() = Mask16;
IX() = IY() = AF() = BC() = DE() = HL() = Mask16; exx();
IX() = IY() = BC() = DE() = HL() = Mask16;
m_prefixCB = m_prefixDD = m_prefixED = m_prefixFD = false; m_prefixCB = m_prefixDD = m_prefixED = m_prefixFD = false;
} }
void EightBit::Z80::handleRESET() { void EightBit::Z80::handleRESET() {
Processor::handleRESET(); IntelProcessor::handleRESET();
di(); di();
addCycles(3); addCycles(3);
} }
@ -60,7 +61,7 @@ void EightBit::Z80::handleNMI() {
} }
void EightBit::Z80::handleINT() { void EightBit::Z80::handleINT() {
Processor::handleINT(); IntelProcessor::handleINT();
raise(HALT()); raise(HALT());
if (IFF1()) { if (IFF1()) {
di(); di();
@ -73,7 +74,7 @@ void EightBit::Z80::handleINT() {
addCycles(13); addCycles(13);
break; break;
case 2: case 2:
call(MEMPTR() = register16_t(BUS().DATA(), IV())); call(MEMPTR() = { BUS().DATA(), IV() });
addCycles(19); addCycles(19);
break; break;
default: default:
@ -599,8 +600,7 @@ bool EightBit::Z80::otdr() {
} }
void EightBit::Z80::rrd() { void EightBit::Z80::rrd() {
MEMPTR() = BUS().ADDRESS() = HL(); MEMPTR()++ = BUS().ADDRESS() = HL();
++MEMPTR();
const auto memory = BUS().read(); const auto memory = BUS().read();
BUS().write(promoteNibble(A()) | highNibble(memory)); BUS().write(promoteNibble(A()) | highNibble(memory));
A() = higherNibble(A()) | lowerNibble(memory); A() = higherNibble(A()) | lowerNibble(memory);
@ -609,8 +609,7 @@ void EightBit::Z80::rrd() {
} }
void EightBit::Z80::rld() { void EightBit::Z80::rld() {
MEMPTR() = BUS().ADDRESS() = HL(); MEMPTR()++ = BUS().ADDRESS() = HL();
++MEMPTR();
const auto memory = BUS().read(); const auto memory = BUS().read();
BUS().write(promoteNibble(memory) | lowNibble(A())); BUS().write(promoteNibble(memory) | lowNibble(A()));
A() = higherNibble(A()) | highNibble(memory); A() = higherNibble(A()) | highNibble(memory);
@ -619,7 +618,7 @@ void EightBit::Z80::rld() {
} }
void EightBit::Z80::writePort(const uint8_t port) { void EightBit::Z80::writePort(const uint8_t port) {
MEMPTR() = BUS().ADDRESS() = register16_t(port, A()); MEMPTR() = BUS().ADDRESS() = { port, A() };
BUS().DATA() = A(); BUS().DATA() = A();
writePort(); writePort();
++MEMPTR().low; ++MEMPTR().low;
@ -630,7 +629,7 @@ void EightBit::Z80::writePort() {
} }
uint8_t EightBit::Z80::readPort(const uint8_t port) { uint8_t EightBit::Z80::readPort(const uint8_t port) {
MEMPTR() = BUS().ADDRESS() = register16_t(port, A()); MEMPTR() = BUS().ADDRESS() = { port, A() };
++MEMPTR().low; ++MEMPTR().low;
return readPort(); return readPort();
} }
@ -814,8 +813,7 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p
case 1: case 1:
switch (z) { switch (z) {
case 0: // Input from port with 16-bit address case 0: // Input from port with 16-bit address
MEMPTR() = BUS().ADDRESS() = BC(); MEMPTR()++ = BUS().ADDRESS() = BC();
++MEMPTR();
readPort(); readPort();
if (LIKELY(y != 6)) // IN r[y],(C) if (LIKELY(y != 6)) // IN r[y],(C)
R(y, BUS().DATA()); R(y, BUS().DATA());
@ -824,8 +822,7 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p
addCycles(12); addCycles(12);
break; break;
case 1: // Output to port with 16-bit address case 1: // Output to port with 16-bit address
MEMPTR() = BUS().ADDRESS() = BC(); MEMPTR()++ = BUS().ADDRESS() = BC();
++MEMPTR();
if (UNLIKELY(y == 6)) // OUT (C),0 if (UNLIKELY(y == 6)) // OUT (C),0
BUS().DATA() = 0; BUS().DATA() = 0;
else // OUT (C),r[y] else // OUT (C),r[y]
@ -1105,15 +1102,13 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
case 0: case 0:
switch (p) { switch (p) {
case 0: // LD (BC),A case 0: // LD (BC),A
MEMPTR() = BUS().ADDRESS() = BC(); MEMPTR()++ = BUS().ADDRESS() = BC();
++MEMPTR();
MEMPTR().high = BUS().DATA() = A(); MEMPTR().high = BUS().DATA() = A();
BUS().write(); BUS().write();
addCycles(7); addCycles(7);
break; break;
case 1: // LD (DE),A case 1: // LD (DE),A
MEMPTR() = BUS().ADDRESS() = DE(); MEMPTR()++ = BUS().ADDRESS() = DE();
++MEMPTR();
MEMPTR().high = BUS().DATA() = A(); MEMPTR().high = BUS().DATA() = A();
BUS().write(); BUS().write();
addCycles(7); addCycles(7);
@ -1124,8 +1119,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
addCycles(16); addCycles(16);
break; break;
case 3: // LD (nn),A case 3: // LD (nn),A
MEMPTR() = BUS().ADDRESS() = fetchWord(); MEMPTR()++ = BUS().ADDRESS() = fetchWord();
++MEMPTR();
MEMPTR().high = BUS().DATA() = A(); MEMPTR().high = BUS().DATA() = A();
BUS().write(); BUS().write();
addCycles(13); addCycles(13);
@ -1137,14 +1131,12 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
case 1: case 1:
switch (p) { switch (p) {
case 0: // LD A,(BC) case 0: // LD A,(BC)
MEMPTR() = BUS().ADDRESS() = BC(); MEMPTR()++ = BUS().ADDRESS() = BC();
++MEMPTR();
A() = BUS().read(); A() = BUS().read();
addCycles(7); addCycles(7);
break; break;
case 1: // LD A,(DE) case 1: // LD A,(DE)
MEMPTR() = BUS().ADDRESS() = DE(); MEMPTR()++ = BUS().ADDRESS() = DE();
++MEMPTR();
A() = BUS().read(); A() = BUS().read();
addCycles(7); addCycles(7);
break; break;
@ -1154,8 +1146,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
addCycles(16); addCycles(16);
break; break;
case 3: // LD A,(nn) case 3: // LD A,(nn)
MEMPTR() = BUS().ADDRESS() = fetchWord(); MEMPTR()++ = BUS().ADDRESS() = fetchWord();
++MEMPTR();
A() = BUS().read(); A() = BUS().read();
addCycles(13); addCycles(13);
break; break;