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

View File

@ -28,7 +28,7 @@ namespace EightBit {
return (high << 7) | variable;
}
refresh_t& operator++() {
auto& operator++() {
++variable;
return *this;
}
@ -51,8 +51,8 @@ namespace EightBit {
Signal<Z80> ExecutingInstruction;
Signal<Z80> ExecutedInstruction;
PinLevel& NMI() { return m_nmiLine; } // In
PinLevel& M1() { return m_m1Line; } // Out
auto& NMI() { return m_nmiLine; } // In
auto& M1() { return m_m1Line; } // Out
virtual int execute(uint8_t opcode) final;
virtual int step() final;
@ -63,19 +63,19 @@ namespace EightBit {
virtual register16_t& DE() final;
virtual register16_t& HL() final;
register16_t& IX() { return m_ix; }
uint8_t& IXH() { return IX().high; }
uint8_t& IXL() { return IX().low; }
auto& IX() { return m_ix; }
auto& IXH() { return IX().high; }
auto& IXL() { return IX().low; }
register16_t& IY() { return m_iy; }
uint8_t& IYH() { return IY().high; }
uint8_t& IYL() { return IY().low; }
auto& IY() { return m_iy; }
auto& IYH() { return IY().high; }
auto& IYL() { return IY().low; }
refresh_t& REFRESH() { return m_refresh; }
uint8_t& IV() { return iv; }
int& IM() { return m_interruptMode; }
bool& IFF1() { return m_iff1; }
bool& IFF2() { return m_iff2; }
auto& REFRESH() { return m_refresh; }
auto& IV() { return iv; }
auto& IM() { return m_interruptMode; }
auto& IFF1() { return m_iff1; }
auto& IFF2() { return m_iff2; }
void exx() {
m_registerSet ^= 1;
@ -132,7 +132,50 @@ namespace EightBit {
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 <= 7);
switch (r) {
@ -190,7 +233,7 @@ namespace EightBit {
}
}
uint8_t R2(const int r) {
auto R2(const int r) {
ASSUME(r >= 0);
ASSUME(r <= 7);
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) {
setFlag(f, HC, calculateHalfCarryAdd(before, value, calculation));
}
@ -395,7 +395,7 @@ namespace EightBit {
void ind();
bool indr();
void blockOut(const register16_t source, register16_t& destination);
void blockOut(register16_t source, register16_t& destination);
void outi();
bool otir();

View File

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