Start adding comparison operations to EightBit classes

This commit is contained in:
Adrian Conlon 2021-12-27 14:24:38 +00:00
parent af7679505c
commit 945fcefb36
16 changed files with 154 additions and 34 deletions

View File

@ -35,10 +35,14 @@ namespace EightBit {
virtual int execute() final;
virtual int step() final;
[[nodiscard]] virtual register16_t& AF() noexcept final;
[[nodiscard]] virtual register16_t& BC() noexcept final;
[[nodiscard]] virtual register16_t& DE() noexcept final;
[[nodiscard]] virtual register16_t& HL() 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]] bool requestingIO() noexcept { return m_requestIO; }
[[nodiscard]] bool requestingMemory() noexcept { return m_requestMemory; }

View File

@ -19,20 +19,21 @@ EightBit::Intel8080::Intel8080(Bus& bus)
DEFINE_PIN_LEVEL_CHANGERS(DBIN, Intel8080);
DEFINE_PIN_LEVEL_CHANGERS(WR, Intel8080);
EightBit::register16_t& EightBit::Intel8080::AF() noexcept {
af.low = (af.low | Bit1) & ~(Bit5 | Bit3);
const EightBit::register16_t& EightBit::Intel8080::AF() const noexcept {
auto* processor = const_cast<Intel8080*>(this);
processor->af.low = (af.low | Bit1) & ~(Bit5 | Bit3);
return af;
}
EightBit::register16_t& EightBit::Intel8080::BC() noexcept {
const EightBit::register16_t& EightBit::Intel8080::BC() const noexcept {
return bc;
}
EightBit::register16_t& EightBit::Intel8080::DE() noexcept {
const EightBit::register16_t& EightBit::Intel8080::DE() const noexcept {
return de;
}
EightBit::register16_t& EightBit::Intel8080::HL() noexcept {
const EightBit::register16_t& EightBit::Intel8080::HL() const noexcept {
return hl;
}

View File

@ -26,10 +26,14 @@ namespace EightBit {
Signal<LR35902> ExecutingInstruction;
Signal<LR35902> ExecutedInstruction;
[[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]] 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(); }
bool& IME() noexcept { return m_ime; }

View File

@ -13,20 +13,21 @@ EightBit::GameBoy::LR35902::LR35902(Bus& memory)
});
}
EightBit::register16_t& EightBit::GameBoy::LR35902::AF() noexcept {
af.low = higherNibble(af.low);
const EightBit::register16_t& EightBit::GameBoy::LR35902::AF() const noexcept {
auto* gb = const_cast<LR35902*>(this);
gb->af.low = higherNibble(af.low);
return af;
}
EightBit::register16_t& EightBit::GameBoy::LR35902::BC() noexcept {
const EightBit::register16_t& EightBit::GameBoy::LR35902::BC() const noexcept {
return bc;
}
EightBit::register16_t& EightBit::GameBoy::LR35902::DE() noexcept {
const EightBit::register16_t& EightBit::GameBoy::LR35902::DE() const noexcept {
return de;
}
EightBit::register16_t& EightBit::GameBoy::LR35902::HL() noexcept {
const EightBit::register16_t& EightBit::GameBoy::LR35902::HL() const noexcept {
return hl;
}

View File

@ -71,6 +71,8 @@ namespace EightBit {
Z80(Bus& bus);
bool operator==(const Z80& rhs) const;
Signal<Z80> ExecutingInstruction;
Signal<Z80> ExecutedInstruction;
@ -89,16 +91,22 @@ namespace EightBit {
int execute() final;
int step() final;
[[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]] 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]] auto& IX() noexcept { return m_ix; }
[[nodiscard]] const auto& IX() const noexcept { return m_ix; }
NON_CONST_REGISTOR_ACCESSOR(IX);
[[nodiscard]] auto& IXH() noexcept { return IX().high; }
[[nodiscard]] auto& IXL() noexcept { return IX().low; }
[[nodiscard]] auto& IY() noexcept { return m_iy; }
[[nodiscard]] const auto& IY() const noexcept { return m_iy; }
NON_CONST_REGISTOR_ACCESSOR(IY);
[[nodiscard]] auto& IYH() noexcept { return IY().high; }
[[nodiscard]] auto& IYL() noexcept { return IY().low; }
@ -114,11 +122,16 @@ 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; }
constexpr void exx() noexcept { m_registerSet ^= 1; }
constexpr void exxAF() noexcept { m_accumulatorFlagsSet ^= 1; }

View File

@ -23,7 +23,8 @@ EightBit::Z80::Z80(Bus& bus)
exxAF();
exx();
AF() = IX() = IY() = BC() = DE() = HL() = Mask16;
IX() = IY() = Mask16;
resetWorkingRegisters();
resetPrefixes();
});
@ -33,6 +34,35 @@ EightBit::Z80::Z80(Bus& bus)
});
}
bool EightBit::Z80::operator==(const EightBit::Z80& rhs) const {
const auto base = IntelProcessor::operator==(rhs);
auto* z80 = const_cast<Z80*>(this);
z80->exxAF();
z80->exx();
return base
&& RFSH() == rhs.RFSH()
&& NMI() == rhs.NMI()
&& M1() == rhs.M1()
&& MREQ() == rhs.MREQ()
&& IORQ() == rhs.IORQ()
&& RD() == rhs.RD()
&& WR() == rhs.WR()
&& AF() == rhs.AF()
&& BC() == rhs.BC()
&& DE() == rhs.DE()
&& HL() == rhs.HL()
&& IX() == rhs.IX()
&& IY() == rhs.IY()
&& REFRESH() == rhs.REFRESH()
&& IV() == rhs.IV()
&& IM() == rhs.IM()
&& IFF1() == rhs.IFF1()
&& IFF2() == rhs.IFF2();
}
DEFINE_PIN_LEVEL_CHANGERS(NMI, Z80);
DEFINE_PIN_LEVEL_CHANGERS(M1, Z80);
DEFINE_PIN_LEVEL_CHANGERS(RFSH, Z80);
@ -41,19 +71,19 @@ DEFINE_PIN_LEVEL_CHANGERS(IORQ, Z80);
DEFINE_PIN_LEVEL_CHANGERS(RD, Z80);
DEFINE_PIN_LEVEL_CHANGERS(WR, Z80);
EightBit::register16_t& EightBit::Z80::AF() noexcept {
const EightBit::register16_t& EightBit::Z80::AF() const noexcept {
return m_accumulatorFlags[m_accumulatorFlagsSet];
}
EightBit::register16_t& EightBit::Z80::BC() noexcept {
const EightBit::register16_t& EightBit::Z80::BC() const noexcept {
return m_registers[m_registerSet][BC_IDX];
}
EightBit::register16_t& EightBit::Z80::DE() noexcept {
const EightBit::register16_t& EightBit::Z80::DE() const noexcept {
return m_registers[m_registerSet][DE_IDX];
}
EightBit::register16_t& EightBit::Z80::HL() noexcept {
const EightBit::register16_t& EightBit::Z80::HL() const noexcept {
return m_registers[m_registerSet][HL_IDX];
}

View File

@ -9,6 +9,8 @@ namespace EightBit {
public:
virtual ~ClockedChip() noexcept {};
bool operator==(const ClockedChip& rhs) const;
Signal<EventArgs> Ticked;
[[nodiscard]] constexpr auto cycles() const noexcept { return m_cycles; }

View File

@ -108,6 +108,8 @@ namespace EightBit {
virtual ~Device() noexcept {};
bool operator==(const Device& rhs) const;
[[nodiscard]] constexpr bool powered() const noexcept { return raised(POWER()); }
protected:

View File

@ -9,6 +9,16 @@
#include "Signal.h"
#include "EightBitCompilerDefinitions.h"
#define NON_CONST_ACCESSOR(accessor, type) \
[[nodiscard]] 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;
@ -36,27 +46,35 @@ namespace EightBit {
virtual ~IntelProcessor() {};
bool operator==(const IntelProcessor& rhs) const;
[[nodiscard]] constexpr const auto& getDecodedOpcode(const size_t i) const noexcept {
return m_decodedOpcodes[i];
}
[[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 register16_t& AF() noexcept = 0;
[[nodiscard]] virtual const register16_t& AF() const noexcept = 0;
NON_CONST_REGISTOR_ACCESSOR(AF);
[[nodiscard]] auto& A() noexcept { return AF().high; }
[[nodiscard]] auto& F() noexcept { return AF().low; }
[[nodiscard]] virtual register16_t& BC() noexcept = 0;
[[nodiscard]] virtual const register16_t& BC() const noexcept = 0;
NON_CONST_REGISTOR_ACCESSOR(BC);
[[nodiscard]] auto& B() noexcept { return BC().high; }
[[nodiscard]] auto& C() noexcept { return BC().low; }
[[nodiscard]] virtual register16_t& DE() noexcept = 0;
[[nodiscard]] virtual const register16_t& DE() const noexcept = 0;
NON_CONST_REGISTOR_ACCESSOR(DE);
[[nodiscard]] auto& D() noexcept { return DE().high; }
[[nodiscard]] auto& E() noexcept { return DE().low; }
[[nodiscard]] virtual register16_t& HL() noexcept = 0;
[[nodiscard]] virtual const register16_t& HL() const noexcept = 0;
NON_CONST_REGISTOR_ACCESSOR(HL);
[[nodiscard]] auto& H() noexcept { return HL().high; }
[[nodiscard]] auto& L() noexcept { return HL().low; }
@ -141,6 +159,8 @@ namespace EightBit {
virtual int jrConditional(int condition);
void ret() override;
void resetWorkingRegisters();
private:
static std::array<int, 8> m_halfCarryTableAdd;
static std::array<int, 8> m_halfCarryTableSub;

View File

@ -23,7 +23,10 @@ namespace EightBit {
virtual ~Processor() noexcept {}
bool operator==(const Processor& rhs) const;
[[nodiscard]] constexpr auto& PC() noexcept { return m_pc; }
[[nodiscard]] constexpr const auto& PC() const noexcept { return m_pc; }
int run(int limit);
virtual int step() = 0;

View File

@ -28,6 +28,7 @@ namespace EightBit {
Rom(size_t size = 0) noexcept;
Rom(const Rom& rhs);
Rom& operator=(const Rom& rhs);
bool operator==(const Rom& rhs) const;
[[nodiscard]] size_t size() const noexcept final;

View File

@ -14,3 +14,9 @@ void EightBit::ClockedChip::tick() {
void EightBit::ClockedChip::resetCycles() noexcept {
m_cycles = 0;
}
bool EightBit::ClockedChip::operator==(const EightBit::ClockedChip& rhs) const {
return
Device::operator==(rhs)
&& cycles() == rhs.cycles();
}

View File

@ -2,3 +2,7 @@
#include "../inc/Device.h"
DEFINE_PIN_LEVEL_CHANGERS(POWER, Device);
bool EightBit::Device::operator==(const EightBit::Device& rhs) const {
return POWER() == rhs.POWER();
}

View File

@ -13,11 +13,16 @@ EightBit::IntelProcessor::IntelProcessor(Bus& bus)
RaisedHALT.connect([this](EventArgs) noexcept { ++PC(); });
RaisedPOWER.connect([this](EventArgs) {
PC() = SP() = AF() = BC() = DE() = HL() = Mask16;
PC() = SP() = Mask16;
resetWorkingRegisters();
raiseHALT();
});
}
void EightBit::IntelProcessor::resetWorkingRegisters() {
AF() = BC() = DE() = HL() = Mask16;
}
DEFINE_PIN_LEVEL_CHANGERS(HALT, IntelProcessor);
void EightBit::IntelProcessor::handleRESET() {
@ -85,3 +90,15 @@ void EightBit::IntelProcessor::ret() {
Processor::ret();
MEMPTR() = PC();
}
bool EightBit::IntelProcessor::operator==(const EightBit::IntelProcessor& rhs) const {
return
Processor::operator==(rhs)
&& HALT() == rhs.HALT()
&& MEMPTR() == rhs.MEMPTR()
&& SP() == rhs.SP()
&& AF() == rhs.AF()
&& BC() == rhs.BC()
&& DE() == rhs.DE()
&& HL() == rhs.HL();
}

View File

@ -98,3 +98,11 @@ void EightBit::Processor::call(const register16_t destination) {
void EightBit::Processor::ret() {
jump(popWord());
}
bool EightBit::Processor::operator==(const EightBit::Processor& rhs) const {
return
ClockedChip::operator==(rhs)
&& RESET() == rhs.RESET()
&& INT() == rhs.INT()
&& PC() == rhs.PC();
}

View File

@ -3,6 +3,10 @@
#include <iostream>
bool EightBit::Rom::operator==(const Rom& rhs) const {
return BYTES() == rhs.BYTES();
}
int EightBit::Rom::load(std::ifstream& file, std::vector<uint8_t>& output, const int writeOffset, const int readOffset, int limit, const int maximumSize) {
file.seekg(0, std::ios::end);