mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2026-10-22 07:02:37 +00:00
First stage of syncing to .net implementation. Pretty shakey, but test_Z80 runs
This commit is contained in:
1 parent
43f1ec55a1
commit
6bec1d473d
59 files changed
+1049
-967
No files matched your search
@@ -12,7 +12,7 @@
|
||||
namespace EightBit {
|
||||
class Disassembler {
|
||||
public:
|
||||
Disassembler(Bus& bus) noexcept;
|
||||
Disassembler(Bus& bus);
|
||||
|
||||
static std::string state(Intel8080& cpu);
|
||||
std::string disassemble(Intel8080& cpu);
|
||||
|
||||
+92
-120
@@ -15,7 +15,7 @@
|
||||
namespace EightBit {
|
||||
class Intel8080 final : public IntelProcessor {
|
||||
public:
|
||||
DECLARE_PIN_OUTPUT(DBIN) // Active high
|
||||
DECLARE_PIN_OUTPUT(DBIN) // Active high
|
||||
DECLARE_PIN_OUTPUT(WR) // Active low
|
||||
|
||||
public:
|
||||
@@ -29,36 +29,30 @@ namespace EightBit {
|
||||
|
||||
Intel8080(Bus& bus);
|
||||
|
||||
Signal<Intel8080> ExecutingInstruction;
|
||||
Signal<Intel8080> ExecutedInstruction;
|
||||
|
||||
void execute() noexcept final;
|
||||
int step() 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]] bool requestingIO() noexcept { return m_requestIO; }
|
||||
[[nodiscard]] bool requestingMemory() noexcept { return m_requestMemory; }
|
||||
[[nodiscard]] constexpr bool requestingIO() const noexcept { return m_requestIO; }
|
||||
[[nodiscard]] constexpr bool requestingMemory() const noexcept { return m_requestMemory; }
|
||||
|
||||
[[nodiscard]] bool requestingRead() noexcept { return raised(DBIN()); }
|
||||
[[nodiscard]] bool requestingWrite() noexcept { return lowered(WR()); }
|
||||
[[nodiscard]] constexpr bool requestingRead() const noexcept { return raised(DBIN()); }
|
||||
[[nodiscard]] constexpr bool requestingWrite() const noexcept { return lowered(WR()); }
|
||||
|
||||
protected:
|
||||
void handleRESET() noexcept final;
|
||||
void handleINT() noexcept final;
|
||||
|
||||
void memoryUpdate(int ticks = 1) noexcept;
|
||||
void memoryWrite() noexcept final;
|
||||
uint8_t memoryRead() noexcept final;
|
||||
|
||||
void busWrite() noexcept final;
|
||||
uint8_t busRead() noexcept final;
|
||||
//void busWrite() noexcept final;
|
||||
//uint8_t busRead() noexcept final;
|
||||
|
||||
private:
|
||||
bool m_requestIO = false;
|
||||
@@ -66,122 +60,100 @@ namespace EightBit {
|
||||
|
||||
bool m_interruptEnable = false;
|
||||
|
||||
register16_t af;
|
||||
register16_t bc = Mask16;
|
||||
register16_t de = Mask16;
|
||||
register16_t hl = Mask16;
|
||||
register16_t m_af;
|
||||
register16_t m_bc = Mask16;
|
||||
register16_t m_de = Mask16;
|
||||
register16_t m_hl = Mask16;
|
||||
|
||||
auto R(const int r) {
|
||||
switch (r) {
|
||||
case 0b000:
|
||||
return B();
|
||||
case 0b001:
|
||||
return C();
|
||||
case 0b010:
|
||||
return D();
|
||||
case 0b011:
|
||||
return E();
|
||||
case 0b100:
|
||||
return H();
|
||||
case 0b101:
|
||||
return L();
|
||||
case 0b110:
|
||||
return IntelProcessor::memoryRead(HL());
|
||||
case 0b111:
|
||||
return A();
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
uint8_t R(int r);
|
||||
void R(int r, uint8_t value);
|
||||
register16_t& RP(int rp);
|
||||
register16_t& RP2(int rp);
|
||||
|
||||
[[nodiscard]] static constexpr auto zeroTest(uint8_t data) noexcept { return data & ZF; }
|
||||
[[nodiscard]] static constexpr auto carryTest(uint8_t data) noexcept { return data & CF; }
|
||||
[[nodiscard]] static constexpr auto parityTest(uint8_t data) noexcept { return data & PF; }
|
||||
[[nodiscard]] static constexpr auto signTest(uint8_t data) noexcept { return data & SF; }
|
||||
[[nodiscard]] static constexpr auto auxiliaryCarryTest(uint8_t data) noexcept { return data & AC; }
|
||||
|
||||
[[nodiscard]] constexpr auto zero() noexcept { return zeroTest(F()); }
|
||||
[[nodiscard]] constexpr auto carry() noexcept { return carryTest(F()); }
|
||||
[[nodiscard]] constexpr auto parity() noexcept { return parityTest(F()); }
|
||||
[[nodiscard]] constexpr auto sign() noexcept { return signTest(F()); }
|
||||
[[nodiscard]] constexpr auto auxiliaryCarry() noexcept { return auxiliaryCarryTest(F()); }
|
||||
|
||||
void adjustStatusFlags(uint8_t value) noexcept { F() = value; }
|
||||
|
||||
void setBit(StatusBits flag) noexcept { return adjustStatusFlags(setBit(F(), flag)); }
|
||||
void setBit(int flag) noexcept { return setBit((StatusBits)flag); }
|
||||
[[nodiscard]] static constexpr uint8_t setBit(uint8_t f, StatusBits flag) noexcept { return Chip::setBit(f, (uint8_t)flag); }
|
||||
void setBit(StatusBits flag, int condition) noexcept { adjustStatusFlags(Chip::setBit(F(), flag, condition)); }
|
||||
[[nodiscard]] static constexpr uint8_t setBit(uint8_t f, StatusBits flag, int condition) noexcept { return Chip::setBit(f, (uint8_t)flag, condition); }
|
||||
void setBit(StatusBits flag, bool condition) noexcept { adjustStatusFlags(setBit(F(), flag, condition)); }
|
||||
void setBit(int flag, bool condition) noexcept { setBit((StatusBits)flag, condition); }
|
||||
[[nodiscard]] static constexpr uint8_t setBit(uint8_t f, StatusBits flag, bool condition) noexcept { return Chip::setBit(f, (uint8_t)flag, condition); }
|
||||
|
||||
void clearBit(StatusBits flag) noexcept { adjustStatusFlags(clearBit(F(), flag)); }
|
||||
void clearBit(int flag) noexcept { clearBit((StatusBits)flag); }
|
||||
[[nodiscard]] static constexpr uint8_t clearBit(uint8_t f, StatusBits flag) noexcept { return Chip::clearBit(f, (uint8_t)flag); }
|
||||
void clearBit(StatusBits flag, int condition) noexcept { adjustStatusFlags(clearBit(F(), flag, condition)); }
|
||||
[[nodiscard]] static constexpr uint8_t clearBit(uint8_t f, StatusBits flag, int condition) noexcept { return Chip::clearBit(f, (uint8_t)flag, condition); }
|
||||
|
||||
void adjustSign(uint8_t value) noexcept { adjustStatusFlags(adjustSign(F(), value)); }
|
||||
[[nodiscard]] static constexpr uint8_t adjustSign(uint8_t input, uint8_t value) noexcept { return setBit(input, SF, signTest(value)); }
|
||||
|
||||
void adjustZero(uint8_t value) noexcept { adjustStatusFlags(adjustZero(F(), value)); }
|
||||
[[nodiscard]] static constexpr uint8_t adjustZero(uint8_t input, uint8_t value) noexcept { return clearBit(input, ZF, value); }
|
||||
|
||||
void adjustParity(uint8_t value) noexcept { adjustStatusFlags(adjustParity(F(), value)); }
|
||||
[[nodiscard]] static constexpr uint8_t adjustParity(uint8_t input, uint8_t value) noexcept { return setBit(input, PF, evenParity(value)); }
|
||||
|
||||
void adjustSZ(uint8_t value) noexcept { adjustStatusFlags(adjustSZ(F(), value)); }
|
||||
[[nodiscard]] static constexpr uint8_t adjustSZ(uint8_t input, uint8_t value) noexcept {
|
||||
input = adjustSign(input, value);
|
||||
return adjustZero(input, value);
|
||||
}
|
||||
|
||||
void R(int r, const uint8_t value) {
|
||||
switch (r) {
|
||||
case 0b000:
|
||||
B() = value;
|
||||
break;
|
||||
case 0b001:
|
||||
C() = value;
|
||||
break;
|
||||
case 0b010:
|
||||
D() = value;
|
||||
break;
|
||||
case 0b011:
|
||||
E() = value;
|
||||
break;
|
||||
case 0b100:
|
||||
H() = value;
|
||||
break;
|
||||
case 0b101:
|
||||
L() = value;
|
||||
break;
|
||||
case 0b110:
|
||||
IntelProcessor::memoryWrite(HL(), value);
|
||||
break;
|
||||
case 0b111:
|
||||
A() = value;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
void adjustSZP(uint8_t value) noexcept { adjustStatusFlags(adjustSZP(F(), value)); }
|
||||
[[nodiscard]] static constexpr uint8_t adjustSZP(uint8_t input, uint8_t value) noexcept {
|
||||
input = adjustSZ(input, value);
|
||||
return adjustParity(input, value);
|
||||
}
|
||||
|
||||
auto& RP(const int rp) {
|
||||
switch (rp) {
|
||||
case 0b00:
|
||||
return BC();
|
||||
case 0b01:
|
||||
return DE();
|
||||
case 0b10:
|
||||
return HL();
|
||||
case 0b11:
|
||||
return SP();
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
[[nodiscard]] static constexpr auto adjustAuxilliaryCarryAdd(uint8_t f, uint8_t before, uint8_t value, int calculation) noexcept {
|
||||
return setBit(f, AC, calculateHalfCarryAdd(before, value, calculation));
|
||||
}
|
||||
|
||||
auto& RP2(const int rp) {
|
||||
switch (rp) {
|
||||
case 0b00:
|
||||
return BC();
|
||||
case 0b01:
|
||||
return DE();
|
||||
case 0b10:
|
||||
return HL();
|
||||
case 0b11:
|
||||
return AF();
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
void adjustAuxiliaryCarryAdd(uint8_t before, uint8_t value, int calculation) noexcept {
|
||||
adjustStatusFlags(adjustAuxilliaryCarryAdd(F(), before, value, calculation));
|
||||
}
|
||||
|
||||
static void adjustAuxiliaryCarryAdd(uint8_t& f, uint8_t before, uint8_t value, int calculation) {
|
||||
f = setBit(f, AC, calculateHalfCarryAdd(before, value, calculation));
|
||||
[[nodiscard]] static constexpr auto adjustAuxiliaryCarrySub(uint8_t f, uint8_t before, uint8_t value, int calculation) noexcept {
|
||||
return setBit(f, AC, calculateHalfCarrySub(before, value, calculation));
|
||||
}
|
||||
|
||||
static void adjustAuxiliaryCarrySub(uint8_t& f, uint8_t before, uint8_t value, int calculation) {
|
||||
f = clearBit(f, AC, calculateHalfCarrySub(before, value, calculation));
|
||||
void adjustAuxiliaryCarrySub(uint8_t before, uint8_t value, int calculation) noexcept {
|
||||
adjustStatusFlags(adjustAuxiliaryCarrySub(F(), before, value, calculation));
|
||||
}
|
||||
|
||||
void subtract(uint8_t& operand, uint8_t value, int carry = 0);
|
||||
[[nodiscard]] bool convertCondition(int flag) noexcept final;
|
||||
|
||||
void execute(int x, int y, int z, int p, int q);
|
||||
|
||||
void increment(uint8_t& operand);
|
||||
void decrement(uint8_t& operand);
|
||||
[[nodiscard]] uint8_t increment(uint8_t operand);
|
||||
[[nodiscard]] uint8_t decrement(uint8_t operand);
|
||||
|
||||
void di();
|
||||
void ei();
|
||||
|
||||
int returnConditionalFlag(int flag);
|
||||
int jumpConditionalFlag(int flag);
|
||||
int callConditionalFlag(int flag);
|
||||
void disableInterrupts() noexcept final;
|
||||
void enableInterrupts() noexcept final;
|
||||
|
||||
void add(register16_t value);
|
||||
|
||||
void add(uint8_t value, int carry = 0);
|
||||
void adc(uint8_t value);
|
||||
void sub(uint8_t value, int carry = 0) noexcept;
|
||||
uint8_t subtract(uint8_t value, int carry = 0);
|
||||
void sbb(uint8_t value);
|
||||
|
||||
void andr(uint8_t value);
|
||||
void xorr(uint8_t value);
|
||||
void orr(uint8_t value);
|
||||
@@ -206,14 +178,14 @@ namespace EightBit {
|
||||
uint8_t portRead(uint8_t port);
|
||||
uint8_t portRead();
|
||||
|
||||
void requestIO() noexcept { assert(!requestingMemory()); m_requestIO = true; }
|
||||
void releaseIO() noexcept { m_requestIO = false; }
|
||||
void requestMemory() noexcept { assert(!requestingIO()); m_requestMemory = true; }
|
||||
void releaseMemory() noexcept { m_requestMemory = false; }
|
||||
constexpr void requestIO() noexcept { assert(!requestingMemory()); m_requestIO = true; }
|
||||
constexpr void releaseIO() noexcept { m_requestIO = false; }
|
||||
constexpr void requestMemory() noexcept { assert(!requestingIO()); m_requestMemory = true; }
|
||||
constexpr void releaseMemory() noexcept { m_requestMemory = false; }
|
||||
|
||||
void requestRead() { raise(DBIN()); }
|
||||
void releaseRead() { lower(DBIN()); }
|
||||
void requestWrite() { lower(WR()); }
|
||||
void releaseWrite() { raise(WR()); }
|
||||
constexpr void requestRead() noexcept { raise(DBIN()); }
|
||||
constexpr void releaseRead() noexcept { lower(DBIN()); }
|
||||
constexpr void requestWrite() noexcept { lower(WR()); }
|
||||
constexpr void releaseWrite() noexcept { raise(WR()); }
|
||||
};
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <iomanip>
|
||||
#include <bitset>
|
||||
|
||||
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);
|
||||
@@ -177,7 +177,7 @@ std::string EightBit::Disassembler::disassemble(Intel8080& cpu, uint16_t pc) {
|
||||
auto q = (y & 1);
|
||||
|
||||
auto immediate = BUS().peek(pc + 1);
|
||||
auto absolute = cpu.peekWord(pc + 1).word;
|
||||
auto absolute = cpu.peekShort(pc + 1).word;
|
||||
auto displacement = (int8_t)immediate;
|
||||
auto relative = pc + displacement + 2;
|
||||
auto indexedImmediate = BUS().peek(pc + 1);
|
||||
|
||||
+195
-169
@@ -12,29 +12,28 @@ EightBit::Intel8080::Intel8080(Bus& bus)
|
||||
releaseRead();
|
||||
releaseWrite();
|
||||
|
||||
di();
|
||||
disableInterrupts();
|
||||
});
|
||||
}
|
||||
|
||||
DEFINE_PIN_LEVEL_CHANGERS(DBIN, Intel8080);
|
||||
DEFINE_PIN_LEVEL_CHANGERS(WR, Intel8080);
|
||||
|
||||
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::AF() noexcept {
|
||||
m_af.low = (m_af.low | Bit1) & ~(Bit5 | Bit3);
|
||||
return m_af;
|
||||
}
|
||||
|
||||
const EightBit::register16_t& EightBit::Intel8080::BC() const noexcept {
|
||||
return bc;
|
||||
EightBit::register16_t& EightBit::Intel8080::BC() noexcept {
|
||||
return m_bc;
|
||||
}
|
||||
|
||||
const EightBit::register16_t& EightBit::Intel8080::DE() const noexcept {
|
||||
return de;
|
||||
EightBit::register16_t& EightBit::Intel8080::DE() noexcept {
|
||||
return m_de;
|
||||
}
|
||||
|
||||
const EightBit::register16_t& EightBit::Intel8080::HL() const noexcept {
|
||||
return hl;
|
||||
EightBit::register16_t& EightBit::Intel8080::HL() noexcept {
|
||||
return m_hl;
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::memoryWrite() noexcept {
|
||||
@@ -65,101 +64,138 @@ uint8_t EightBit::Intel8080::busRead() noexcept {
|
||||
|
||||
void EightBit::Intel8080::handleRESET() noexcept {
|
||||
IntelProcessor::handleRESET();
|
||||
di();
|
||||
tick(3);
|
||||
disableInterrupts();
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::handleINT() noexcept {
|
||||
IntelProcessor::handleINT();
|
||||
raiseHALT();
|
||||
if (m_interruptEnable) {
|
||||
di();
|
||||
Processor::execute(BUS().DATA());
|
||||
}
|
||||
Processor::execute(BUS().DATA());
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::di() {
|
||||
void EightBit::Intel8080::disableInterrupts() noexcept {
|
||||
m_interruptEnable = false;
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::ei() {
|
||||
void EightBit::Intel8080::enableInterrupts() noexcept {
|
||||
m_interruptEnable = true;
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::increment(uint8_t& operand) {
|
||||
F() = adjustSZP<Intel8080>(F(), ++operand);
|
||||
F() = clearBit(F(), AC, lowNibble(operand));
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::decrement(uint8_t& operand) {
|
||||
F() = adjustSZP<Intel8080>(F(), --operand);
|
||||
F() = setBit(F(), AC, lowNibble(operand) != Mask4);
|
||||
}
|
||||
|
||||
int EightBit::Intel8080::jumpConditionalFlag(const int flag) {
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
return jumpConditional(!(F() & ZF));
|
||||
case 1: // Z
|
||||
return jumpConditional(F() & ZF);
|
||||
case 2: // NC
|
||||
return jumpConditional(!(F() & CF));
|
||||
case 3: // C
|
||||
return jumpConditional(F() & CF);
|
||||
case 4: // PO
|
||||
return jumpConditional(!(F() & PF));
|
||||
case 5: // PE
|
||||
return jumpConditional(F() & PF);
|
||||
case 6: // P
|
||||
return jumpConditional(!(F() & SF));
|
||||
case 7: // M
|
||||
return jumpConditional(F() & SF);
|
||||
uint8_t EightBit::Intel8080::R(const int r) {
|
||||
switch (r) {
|
||||
case 0b000:
|
||||
return B();
|
||||
case 0b001:
|
||||
return C();
|
||||
case 0b010:
|
||||
return D();
|
||||
case 0b011:
|
||||
return E();
|
||||
case 0b100:
|
||||
return H();
|
||||
case 0b101:
|
||||
return L();
|
||||
case 0b110:
|
||||
return IntelProcessor::memoryRead(HL());
|
||||
case 0b111:
|
||||
return A();
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
int EightBit::Intel8080::returnConditionalFlag(const int flag) {
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
return returnConditional(!(F() & ZF));
|
||||
case 1: // Z
|
||||
return returnConditional(F() & ZF);
|
||||
case 2: // NC
|
||||
return returnConditional(!(F() & CF));
|
||||
case 3: // C
|
||||
return returnConditional(F() & CF);
|
||||
case 4: // PO
|
||||
return returnConditional(!(F() & PF));
|
||||
case 5: // PE
|
||||
return returnConditional(F() & PF);
|
||||
case 6: // P
|
||||
return returnConditional(!(F() & SF));
|
||||
case 7: // M
|
||||
return returnConditional(F() & SF);
|
||||
void EightBit::Intel8080::R(int r, const uint8_t value) {
|
||||
switch (r) {
|
||||
case 0b000:
|
||||
B() = value;
|
||||
break;
|
||||
case 0b001:
|
||||
C() = value;
|
||||
break;
|
||||
case 0b010:
|
||||
D() = value;
|
||||
break;
|
||||
case 0b011:
|
||||
E() = value;
|
||||
break;
|
||||
case 0b100:
|
||||
H() = value;
|
||||
break;
|
||||
case 0b101:
|
||||
L() = value;
|
||||
break;
|
||||
case 0b110:
|
||||
IntelProcessor::memoryWrite(HL(), value);
|
||||
break;
|
||||
case 0b111:
|
||||
A() = value;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
int EightBit::Intel8080::callConditionalFlag(const int flag) {
|
||||
EightBit::register16_t& EightBit::Intel8080::RP(const int rp) {
|
||||
switch (rp) {
|
||||
case 0b00:
|
||||
return BC();
|
||||
case 0b01:
|
||||
return DE();
|
||||
case 0b10:
|
||||
return HL();
|
||||
case 0b11:
|
||||
return SP();
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
EightBit::register16_t& EightBit::Intel8080::RP2(const int rp) {
|
||||
switch (rp) {
|
||||
case 0b00:
|
||||
return BC();
|
||||
case 0b01:
|
||||
return DE();
|
||||
case 0b10:
|
||||
return HL();
|
||||
case 0b11:
|
||||
return AF();
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t EightBit::Intel8080::increment(uint8_t operand) {
|
||||
const uint8_t result = operand + 1;
|
||||
adjustSZP(result);
|
||||
clearBit(AC, lowNibble(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t EightBit::Intel8080::decrement(uint8_t operand) {
|
||||
const uint8_t result = operand - 1;
|
||||
adjustSZP(result);
|
||||
setBit(AC, lowNibble(result) != Mask4);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool EightBit::Intel8080::convertCondition(int flag) noexcept {
|
||||
switch (flag) {
|
||||
case 0: // NZ
|
||||
return callConditional(!(F() & ZF));
|
||||
case 1: // Z
|
||||
return callConditional(F() & ZF);
|
||||
case 2: // NC
|
||||
return callConditional(!(F() & CF));
|
||||
case 3: // C
|
||||
return callConditional(F() & CF);
|
||||
case 4: // PO
|
||||
return callConditional(!(F() & PF));
|
||||
case 5: // PE
|
||||
return callConditional(F() & PF);
|
||||
case 6: // P
|
||||
return callConditional(!(F() & SF));
|
||||
case 7: // M
|
||||
return callConditional(F() & SF);
|
||||
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;
|
||||
}
|
||||
@@ -175,53 +211,59 @@ void EightBit::Intel8080::add(const uint8_t value, const int carry) {
|
||||
|
||||
const register16_t result = A() + value + carry;
|
||||
|
||||
adjustAuxiliaryCarryAdd(F(), A(), value, result.word);
|
||||
adjustAuxiliaryCarryAdd(A(), value, result.word);
|
||||
|
||||
A() = result.low;
|
||||
|
||||
F() = setBit(F(), CF, result.word & Bit8);
|
||||
F() = adjustSZP<Intel8080>(F(), A());
|
||||
setBit(CF, result.word & Bit8);
|
||||
adjustSZP(A());
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::adc(const uint8_t value) {
|
||||
add(value, F() & CF);
|
||||
add(value, carry());
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::subtract(uint8_t& operand, const uint8_t value, const int carry) {
|
||||
uint8_t EightBit::Intel8080::subtract(const uint8_t value, const int carry) {
|
||||
|
||||
const register16_t result = operand - value - carry;
|
||||
const auto operand = A();
|
||||
|
||||
adjustAuxiliaryCarrySub(F(), operand, value, result.word);
|
||||
const register16_t subtraction = operand - value - carry;
|
||||
const auto result = subtraction.low;
|
||||
|
||||
operand = result.low;
|
||||
adjustAuxiliaryCarrySub(operand, value, subtraction.word);
|
||||
|
||||
F() = setBit(F(), CF, result.word & Bit8);
|
||||
F() = adjustSZP<Intel8080>(F(), operand);
|
||||
setBit(CF, subtraction.word & Bit8);
|
||||
adjustSZP(operand);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::sub(uint8_t value, int carry) noexcept {
|
||||
A() = subtract(value, carry);
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::sbb(const uint8_t value) {
|
||||
subtract(A(), value, F() & CF);
|
||||
sub(value, carry());
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::andr(const uint8_t value) {
|
||||
F() = setBit(F(), AC, (A() | value) & Bit3);
|
||||
F() = clearBit(F(), CF);
|
||||
F() = adjustSZP<Intel8080>(F(), A() &= value);
|
||||
setBit(AC, (A() | value) & Bit3);
|
||||
clearBit(CF);
|
||||
adjustSZP(A() &= value);
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::xorr(const uint8_t value) {
|
||||
F() = clearBit(F(), AC | CF);
|
||||
F() = adjustSZP<Intel8080>(F(), A() ^= value);
|
||||
clearBit(AC | CF);
|
||||
adjustSZP(A() ^= value);
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::orr(const uint8_t value) {
|
||||
F() = clearBit(F(), AC | CF);
|
||||
F() = adjustSZP<Intel8080>(F(), A() |= value);
|
||||
clearBit(AC | CF);
|
||||
adjustSZP(A() |= value);
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::compare(const uint8_t value) {
|
||||
auto original = A();
|
||||
subtract(original, value);
|
||||
subtract(value);
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::rlc() {
|
||||
@@ -237,22 +279,22 @@ void EightBit::Intel8080::rrc() {
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::rl() {
|
||||
const auto carry = F() & CF;
|
||||
const auto carrying = carry();
|
||||
F() = setBit(F(), CF, A() & Bit7);
|
||||
A() = (A() << 1) | carry;
|
||||
A() = (A() << 1) | carrying;
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::rr() {
|
||||
const auto carry = F() & CF;
|
||||
const auto carrying = carry();
|
||||
F() = setBit(F(), CF, A() & Bit0);
|
||||
A() = (A() >> 1) | (carry << 7);
|
||||
A() = (A() >> 1) | (carrying << 7);
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::daa() {
|
||||
const auto& before = A();
|
||||
auto carry = F() & CF;
|
||||
uint8_t addition = 0;
|
||||
if ((F() & AC) || lowNibble(before) > 9) {
|
||||
if (auxiliaryCarry() || lowNibble(before) > 9) {
|
||||
addition = 0x6;
|
||||
}
|
||||
if ((F() & CF) || highNibble(before) > 9 || (highNibble(before) >= 9 && lowNibble(before) > 9)) {
|
||||
@@ -279,11 +321,14 @@ void EightBit::Intel8080::xhtl(register16_t& exchange) {
|
||||
MEMPTR().low = IntelProcessor::memoryRead(SP());
|
||||
++BUS().ADDRESS();
|
||||
MEMPTR().high = memoryRead();
|
||||
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();
|
||||
tick(2);
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::portWrite(const uint8_t port) {
|
||||
@@ -310,23 +355,18 @@ uint8_t EightBit::Intel8080::portRead() {
|
||||
return returned;
|
||||
}
|
||||
|
||||
int EightBit::Intel8080::step() noexcept {
|
||||
ExecutingInstruction.fire(*this);
|
||||
resetCycles();
|
||||
if (LIKELY(powered())) {
|
||||
if (UNLIKELY(lowered(RESET()))) {
|
||||
handleRESET();
|
||||
} else if (UNLIKELY(lowered(INT()))) {
|
||||
void EightBit::Intel8080::poweredStep() noexcept {
|
||||
if (UNLIKELY(lowered(RESET()))) {
|
||||
handleRESET();
|
||||
} else if (UNLIKELY(lowered(INT()))) {
|
||||
if (m_interruptEnable) {
|
||||
handleINT();
|
||||
} else if (UNLIKELY(lowered(HALT()))) {
|
||||
Processor::execute(0); // NOP
|
||||
} else {
|
||||
Processor::execute(fetchByte());
|
||||
}
|
||||
} else if (UNLIKELY(lowered(HALT()))) {
|
||||
Processor::execute(0); // NOP
|
||||
} else {
|
||||
Processor::execute(fetchByte());
|
||||
}
|
||||
ExecutedInstruction.fire(*this);
|
||||
ASSUME(cycles() > 0);
|
||||
return cycles();
|
||||
}
|
||||
|
||||
void EightBit::Intel8080::execute() noexcept {
|
||||
@@ -406,7 +446,7 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i
|
||||
break;
|
||||
case 2: // LD HL,(nn)
|
||||
BUS().ADDRESS() = fetchWord();
|
||||
HL() = getWord();
|
||||
HL() = getShort();
|
||||
tick(16);
|
||||
break;
|
||||
case 3: // LD A,(nn)
|
||||
@@ -437,14 +477,12 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i
|
||||
break;
|
||||
case 4: { // 8-bit INC
|
||||
auto operand = R(y);
|
||||
increment(operand);
|
||||
R(y, operand);
|
||||
R(y, increment(operand));
|
||||
tick(4);
|
||||
break;
|
||||
} case 5: { // 8-bit DEC
|
||||
auto operand = R(y);
|
||||
decrement(operand);
|
||||
R(y, operand);
|
||||
R(y, decrement(operand));
|
||||
tick(4);
|
||||
if (UNLIKELY(y == 6))
|
||||
tick(7);
|
||||
@@ -500,45 +538,42 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i
|
||||
}
|
||||
tick(4);
|
||||
break;
|
||||
case 2: // Operate on accumulator and register/memory location
|
||||
case 2: { // Operate on accumulator and register/memory location
|
||||
const auto value = R(z);
|
||||
switch (y) {
|
||||
case 0: // ADD A,r
|
||||
add(R(z));
|
||||
add(value);
|
||||
break;
|
||||
case 1: // ADC A,r
|
||||
adc(R(z));
|
||||
adc(value);
|
||||
break;
|
||||
case 2: // SUB r
|
||||
subtract(A(), R(z));
|
||||
sub(value);
|
||||
break;
|
||||
case 3: // SBC A,r
|
||||
sbb(R(z));
|
||||
sbb(value);
|
||||
break;
|
||||
case 4: // AND r
|
||||
andr(R(z));
|
||||
andr(value);
|
||||
break;
|
||||
case 5: // XOR r
|
||||
xorr(R(z));
|
||||
xorr(value);
|
||||
break;
|
||||
case 6: // OR r
|
||||
orr(R(z));
|
||||
orr(value);
|
||||
break;
|
||||
case 7: // CP r
|
||||
compare(R(z));
|
||||
compare(value);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
tick(4);
|
||||
if (UNLIKELY(z == 6))
|
||||
tick(3);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
switch (z) {
|
||||
case 0: // Conditional return
|
||||
if (returnConditionalFlag(y))
|
||||
tick(6);
|
||||
tick(5);
|
||||
returnConditionalFlag(y);
|
||||
break;
|
||||
case 1: // POP & various ops
|
||||
switch (q) {
|
||||
@@ -553,8 +588,7 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i
|
||||
tick(10);
|
||||
break;
|
||||
case 2: // JP HL
|
||||
jump(HL());
|
||||
tick(4);
|
||||
Processor::jump(HL());
|
||||
break;
|
||||
case 3: // LD SP,HL
|
||||
SP() = HL();
|
||||
@@ -568,17 +602,14 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i
|
||||
break;
|
||||
case 2: // Conditional jump
|
||||
jumpConditionalFlag(y);
|
||||
tick(10);
|
||||
break;
|
||||
case 3: // Assorted operations
|
||||
switch (y) {
|
||||
case 0: // JP nn
|
||||
jump(fetchWord());
|
||||
tick(10);
|
||||
Processor::jump(fetchWord());
|
||||
break;
|
||||
case 2: // OUT (n),A
|
||||
portWrite(fetchByte());
|
||||
tick(11);
|
||||
break;
|
||||
case 3: // IN A,(n)
|
||||
A() = portRead(fetchByte());
|
||||
@@ -586,26 +617,20 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i
|
||||
break;
|
||||
case 4: // EX (SP),HL
|
||||
xhtl(HL());
|
||||
tick(19);
|
||||
break;
|
||||
case 5: // EX DE,HL
|
||||
std::swap(DE(), HL());
|
||||
tick(4);
|
||||
break;
|
||||
case 6: // DI
|
||||
di();
|
||||
tick(4);
|
||||
disableInterrupts();
|
||||
break;
|
||||
case 7: // EI
|
||||
ei();
|
||||
tick(4);
|
||||
enableInterrupts();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 4: // Conditional call: CALL cc[y], nn
|
||||
if (callConditionalFlag(y))
|
||||
tick(7);
|
||||
tick(10);
|
||||
callConditionalFlag(y);
|
||||
break;
|
||||
case 5: // PUSH & various ops
|
||||
switch (q) {
|
||||
@@ -625,37 +650,38 @@ void EightBit::Intel8080::execute(const int x, const int y, const int z, const i
|
||||
UNREACHABLE;
|
||||
}
|
||||
break;
|
||||
case 6: // Operate on accumulator and immediate operand: alu[y] n
|
||||
case 6: { // Operate on accumulator and immediate operand: alu[y] n
|
||||
const auto operand = fetchByte();
|
||||
switch (y) {
|
||||
case 0: // ADD A,n
|
||||
add(fetchByte());
|
||||
add(operand);
|
||||
break;
|
||||
case 1: // ADC A,n
|
||||
adc(fetchByte());
|
||||
adc(operand);
|
||||
break;
|
||||
case 2: // SUB n
|
||||
subtract(A(), fetchByte());
|
||||
sub(operand);
|
||||
break;
|
||||
case 3: // SBC A,n
|
||||
sbb(fetchByte());
|
||||
sbb(operand);
|
||||
break;
|
||||
case 4: // AND n
|
||||
andr(fetchByte());
|
||||
andr(operand);
|
||||
break;
|
||||
case 5: // XOR n
|
||||
xorr(fetchByte());
|
||||
xorr(operand);
|
||||
break;
|
||||
case 6: // OR n
|
||||
orr(fetchByte());
|
||||
orr(operand);
|
||||
break;
|
||||
case 7: // CP n
|
||||
compare(fetchByte());
|
||||
compare(operand);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
tick(7);
|
||||
break;
|
||||
}
|
||||
case 7: // Restart: RST y * 8
|
||||
restart(y << 3);
|
||||
tick(11);
|
||||
|
||||
@@ -22,7 +22,7 @@ void Board::lowerPOWER() noexcept {
|
||||
EightBit::Bus::lowerPOWER();
|
||||
}
|
||||
|
||||
void Board::initialise() {
|
||||
void Board::initialise() noexcept {
|
||||
|
||||
auto romDirectory = m_configuration.getRomDirectory();
|
||||
|
||||
@@ -46,13 +46,13 @@ void Board::initialise() {
|
||||
}
|
||||
|
||||
poke(0, 0xc3); // JMP
|
||||
CPU().pokeWord(1, m_configuration.getStartAddress());
|
||||
CPU().pokeShort(1, m_configuration.getStartAddress());
|
||||
|
||||
poke(5, 0xc9); // ret
|
||||
}
|
||||
|
||||
void Board::Cpu_ExecutingInstruction_Cpm(EightBit::Intel8080& cpu) {
|
||||
switch (cpu.PC().word) {
|
||||
void Board::Cpu_ExecutingInstruction_Cpm(EightBit::EventArgs&) {
|
||||
switch (CPU().PC().word) {
|
||||
case 0x0: // CP/M warm start
|
||||
if (++m_warmstartCount == 2) {
|
||||
lowerPOWER();
|
||||
@@ -84,15 +84,15 @@ void Board::bdos() {
|
||||
}
|
||||
}
|
||||
|
||||
void Board::Cpu_ExecutingInstruction_Profile(EightBit::Intel8080& cpu) {
|
||||
void Board::Cpu_ExecutingInstruction_Profile(EightBit::EventArgs&) {
|
||||
|
||||
const auto pc = cpu.PC();
|
||||
const auto pc = CPU().PC();
|
||||
|
||||
m_profiler.addAddress(pc.word);
|
||||
m_profiler.addInstruction(peek(pc.word));
|
||||
}
|
||||
|
||||
void Board::Cpu_ExecutingInstruction_Debug(const EightBit::Intel8080& cpu) {
|
||||
void Board::Cpu_ExecutingInstruction_Debug(const EightBit::EventArgs&) {
|
||||
const std::string disassembled =
|
||||
EightBit::Disassembler::state(CPU()) + '\t' + m_disassembler.disassemble(CPU()) + '\n';
|
||||
std::cerr << disassembled;
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
void raisePOWER() noexcept final;
|
||||
void lowerPOWER() noexcept final;
|
||||
|
||||
virtual void initialise() final;
|
||||
virtual void initialise() noexcept final;
|
||||
|
||||
protected:
|
||||
virtual EightBit::MemoryMapping mapping(uint16_t address) noexcept final {
|
||||
@@ -36,10 +36,10 @@ private:
|
||||
EightBit::Profiler m_profiler;
|
||||
int m_warmstartCount = 0;
|
||||
|
||||
void Cpu_ExecutingInstruction_Cpm(EightBit::Intel8080& cpu);
|
||||
void Cpu_ExecutingInstruction_Cpm(EightBit::EventArgs&);
|
||||
|
||||
void Cpu_ExecutingInstruction_Debug(const EightBit::Intel8080& cpu);
|
||||
void Cpu_ExecutingInstruction_Profile(EightBit::Intel8080& cpu);
|
||||
void Cpu_ExecutingInstruction_Debug(const EightBit::EventArgs&);
|
||||
void Cpu_ExecutingInstruction_Profile(EightBit::EventArgs&);
|
||||
|
||||
void bdos();
|
||||
};
|
||||
@@ -23,7 +23,7 @@ void Fuse::TestRunner::lowerPOWER() noexcept {
|
||||
EightBit::Bus::lowerPOWER();
|
||||
}
|
||||
|
||||
void Fuse::TestRunner::initialise() {
|
||||
void Fuse::TestRunner::initialise() noexcept {
|
||||
disableGameRom();
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,6 @@ namespace Fuse {
|
||||
void raisePOWER() noexcept final;
|
||||
void lowerPOWER() noexcept final;
|
||||
|
||||
void initialise();
|
||||
void initialise() noexcept;
|
||||
};
|
||||
}
|
||||
@@ -17,7 +17,7 @@ namespace EightBit {
|
||||
|
||||
AbstractColourPalette() = default;
|
||||
|
||||
[[nodiscard]] auto colour(size_t index) const noexcept {
|
||||
[[nodiscard]] auto colour(size_t index) const {
|
||||
assert(index < m_colours.size());
|
||||
return m_colours[index];
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@ namespace EightBit {
|
||||
namespace GameBoy {
|
||||
class CharacterDefinition final {
|
||||
public:
|
||||
CharacterDefinition(Ram& vram, uint16_t address) noexcept;
|
||||
CharacterDefinition(Ram& vram, uint16_t address);
|
||||
|
||||
[[nodiscard]] std::array<int, 8> get(int row) const noexcept;
|
||||
[[nodiscard]] std::array<int, 8> get(int row) const;
|
||||
|
||||
private:
|
||||
Ram& m_vram;
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace EightBit {
|
||||
|
||||
class Disassembler {
|
||||
public:
|
||||
Disassembler(Bus& bus) noexcept;
|
||||
Disassembler(Bus& bus);
|
||||
|
||||
static std::string state(LR35902& cpu);
|
||||
std::string disassemble(LR35902& cpu);
|
||||
@@ -71,7 +71,7 @@ namespace EightBit {
|
||||
static std::string cc(int flag);
|
||||
static std::string alu(int which);
|
||||
|
||||
Bus& BUS() noexcept { return m_bus; }
|
||||
Bus& BUS() { return m_bus; }
|
||||
};
|
||||
}
|
||||
}
|
||||
+12
-12
@@ -27,12 +27,12 @@ namespace EightBit {
|
||||
PixelCount = RasterWidth * RasterHeight,
|
||||
};
|
||||
|
||||
Display(const AbstractColourPalette* colours, Bus& bus, Ram& oam, Ram& vram) noexcept;
|
||||
Display(const AbstractColourPalette* colours, Bus& bus, Ram& oam, Ram& vram);
|
||||
|
||||
[[nodiscard]] const auto& pixels() const noexcept { return m_pixels; }
|
||||
[[nodiscard]] const auto& pixels() const { return m_pixels; }
|
||||
|
||||
void renderCurrentScanline() noexcept;
|
||||
void loadObjectAttributes() noexcept;
|
||||
void renderCurrentScanline();
|
||||
void loadObjectAttributes();
|
||||
|
||||
private:
|
||||
enum class tile_offset_t {
|
||||
@@ -48,42 +48,42 @@ namespace EightBit {
|
||||
uint8_t m_control = 0;
|
||||
uint8_t m_scanLine = 0;
|
||||
|
||||
[[nodiscard]] std::array<int, 4> createPalette(int address) noexcept;
|
||||
[[nodiscard]] std::array<int, 4> createPalette(int address);
|
||||
|
||||
void renderBackground() noexcept;
|
||||
void renderBackground();
|
||||
void renderBackground(
|
||||
int bgArea, int bgCharacters,
|
||||
tile_offset_t offsetType,
|
||||
int offsetX, int offsetY,
|
||||
const std::array<int, 4>& palette) noexcept;
|
||||
const std::array<int, 4>& palette);
|
||||
|
||||
void renderBackgroundTile(
|
||||
int definitionOffset,
|
||||
int row, int column,
|
||||
int bgCharacters, tile_offset_t offsetType,
|
||||
int offsetX, int offsetY,
|
||||
const std::array<int, 4>& palette) noexcept;
|
||||
const std::array<int, 4>& palette);
|
||||
|
||||
void renderObjects() noexcept;
|
||||
void renderObjects();
|
||||
|
||||
void renderSpriteTile(
|
||||
int height,
|
||||
int drawX, int drawY,
|
||||
bool flipX, bool flipY,
|
||||
const std::array<int, 4>& palette,
|
||||
const CharacterDefinition& definition) noexcept;
|
||||
const CharacterDefinition& definition);
|
||||
|
||||
void renderBackgroundTile(
|
||||
int drawX, int drawY,
|
||||
const std::array<int, 4>& palette,
|
||||
const CharacterDefinition& definition) noexcept;
|
||||
const CharacterDefinition& definition);
|
||||
|
||||
void renderTile(
|
||||
int height,
|
||||
int drawX, int drawY,
|
||||
bool flipX, bool flipY, bool allowTransparencies,
|
||||
const std::array<int, 4>& palette,
|
||||
const CharacterDefinition& definition) noexcept;
|
||||
const CharacterDefinition& definition);
|
||||
};
|
||||
}
|
||||
}
|
||||
+10
-10
@@ -34,23 +34,23 @@ namespace EightBit {
|
||||
RomPageSize = 0x4000
|
||||
};
|
||||
|
||||
Bus() noexcept;
|
||||
Bus();
|
||||
|
||||
void raisePOWER() noexcept override;
|
||||
void lowerPOWER() noexcept override;
|
||||
|
||||
[[nodiscard]] auto& CPU() noexcept { return m_cpu; }
|
||||
[[nodiscard]] auto& VRAM() noexcept { return m_videoRam; }
|
||||
[[nodiscard]] auto& OAMRAM() noexcept { return m_oamRam; }
|
||||
[[nodiscard]] auto& IO() noexcept { return m_ioPorts; }
|
||||
[[nodiscard]] auto& CPU() { return m_cpu; }
|
||||
[[nodiscard]] auto& VRAM() { return m_videoRam; }
|
||||
[[nodiscard]] auto& OAMRAM() { return m_oamRam; }
|
||||
[[nodiscard]] auto& IO() { return m_ioPorts; }
|
||||
|
||||
void reset();
|
||||
|
||||
void disableGameRom() noexcept { m_disableGameRom = true; }
|
||||
void enableGameRom() noexcept { m_disableGameRom = false; }
|
||||
void disableGameRom() { m_disableGameRom = true; }
|
||||
void enableGameRom() { m_disableGameRom = false; }
|
||||
|
||||
[[nodiscard]] bool gameRomDisabled() const noexcept { return m_disableGameRom; }
|
||||
[[nodiscard]] bool gameRomEnabled() const noexcept { return !gameRomDisabled(); }
|
||||
[[nodiscard]] bool gameRomDisabled() const { return m_disableGameRom; }
|
||||
[[nodiscard]] bool gameRomEnabled() const { return !gameRomDisabled(); }
|
||||
|
||||
void loadBootRom(std::string path);
|
||||
void loadGameRom(std::string path);
|
||||
@@ -94,7 +94,7 @@ namespace EightBit {
|
||||
|
||||
void validateCartridgeType();
|
||||
|
||||
void Bus_WrittenByte(EightBit::EventArgs) noexcept;
|
||||
void Bus_WrittenByte(EightBit::EventArgs);
|
||||
|
||||
void runRasterLines(int lines);
|
||||
void runVerticalBlankLines(int lines);
|
||||
|
||||
+12
-12
@@ -133,35 +133,35 @@ namespace EightBit {
|
||||
|
||||
void updateLcdStatusMode(int mode);
|
||||
|
||||
void disableBootRom() noexcept { m_disableBootRom = true; }
|
||||
void enableBootRom() noexcept { m_disableBootRom = false; }
|
||||
void disableBootRom() { m_disableBootRom = true; }
|
||||
void enableBootRom() { m_disableBootRom = false; }
|
||||
|
||||
auto bootRomDisabled() const noexcept { return m_disableBootRom; }
|
||||
auto bootRomEnabled() const noexcept { return !bootRomDisabled(); }
|
||||
auto bootRomDisabled() const { return m_disableBootRom; }
|
||||
auto bootRomEnabled() const { return !bootRomDisabled(); }
|
||||
|
||||
void pressRight() { m_p14 = m_p10 = false; triggerKeypadInterrupt(); }
|
||||
void releaseRight() noexcept { m_p14 = m_p10 = true; }
|
||||
void releaseRight() { m_p14 = m_p10 = true; }
|
||||
|
||||
void pressLeft() { m_p14 = m_p11 = false, triggerKeypadInterrupt(); }
|
||||
void releaseLeft() noexcept { m_p14 = m_p11 = true; }
|
||||
void releaseLeft() { m_p14 = m_p11 = true; }
|
||||
|
||||
void pressUp() { m_p14 = m_p12 = false, triggerKeypadInterrupt(); }
|
||||
void releaseUp() noexcept { m_p14 = m_p12 = true; }
|
||||
void releaseUp() { m_p14 = m_p12 = true; }
|
||||
|
||||
void pressDown() { m_p14 = m_p13 = false, triggerKeypadInterrupt(); }
|
||||
void releaseDown() noexcept { m_p14 = m_p13 = true; }
|
||||
void releaseDown() { m_p14 = m_p13 = true; }
|
||||
|
||||
void pressA() { m_p15 = m_p10 = false, triggerKeypadInterrupt(); }
|
||||
void releaseA() noexcept { m_p15 = m_p10 = true; }
|
||||
void releaseA() { m_p15 = m_p10 = true; }
|
||||
|
||||
void pressB() { m_p15 = m_p11 = false, triggerKeypadInterrupt(); }
|
||||
void releaseB() noexcept { m_p15 = m_p11 = true; }
|
||||
void releaseB() { m_p15 = m_p11 = true; }
|
||||
|
||||
void pressSelect() { m_p15 = m_p12 = false, triggerKeypadInterrupt(); }
|
||||
void releaseSelect() noexcept { m_p15 = m_p12 = true; }
|
||||
void releaseSelect() { m_p15 = m_p12 = true; }
|
||||
|
||||
void pressStart() { m_p15 = m_p13 = false, triggerKeypadInterrupt(); }
|
||||
void releaseStart() noexcept { m_p15 = m_p13 = true; }
|
||||
void releaseStart() { m_p15 = m_p13 = true; }
|
||||
|
||||
private:
|
||||
Bus& m_bus;
|
||||
|
||||
+61
-61
@@ -13,6 +13,11 @@ namespace EightBit {
|
||||
class Bus;
|
||||
|
||||
class LR35902 final : public IntelProcessor {
|
||||
public:
|
||||
DECLARE_PIN_OUTPUT(MWR)
|
||||
DECLARE_PIN_OUTPUT(RD)
|
||||
DECLARE_PIN_OUTPUT(WR)
|
||||
|
||||
public:
|
||||
enum StatusBits {
|
||||
ZF = Bit7,
|
||||
@@ -26,20 +31,16 @@ namespace EightBit {
|
||||
Signal<LR35902> ExecutingInstruction;
|
||||
Signal<LR35902> ExecutedInstruction;
|
||||
|
||||
[[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;
|
||||
|
||||
bool& IME() noexcept { return m_ime; }
|
||||
bool& IME() { return m_ime; }
|
||||
|
||||
[[nodiscard]] uint8_t enabledInterrupts() noexcept;
|
||||
[[nodiscard]] uint8_t flaggedInterrupts() noexcept;
|
||||
[[nodiscard]] uint8_t maskedInterrupts() noexcept;
|
||||
[[nodiscard]] uint8_t enabledInterrupts();
|
||||
[[nodiscard]] uint8_t flaggedInterrupts();
|
||||
[[nodiscard]] uint8_t maskedInterrupts();
|
||||
|
||||
Signal<EventArgs> MachineTicked;
|
||||
|
||||
@@ -48,102 +49,101 @@ namespace EightBit {
|
||||
|
||||
protected:
|
||||
void execute() noexcept final;
|
||||
int step() noexcept final;
|
||||
void poweredStep() noexcept final;
|
||||
|
||||
void handleRESET() noexcept final;
|
||||
void handleINT() noexcept final;
|
||||
|
||||
void memoryUpdate(int ticks) noexcept;
|
||||
void memoryWrite() noexcept final;
|
||||
uint8_t memoryRead() noexcept final;
|
||||
|
||||
void pushWord(register16_t value) noexcept final;
|
||||
|
||||
void jr(int8_t offset) noexcept final;
|
||||
int jumpConditional(int condition) noexcept final;
|
||||
int returnConditional(int condition) noexcept final;
|
||||
int jrConditional(int condition) noexcept final;
|
||||
void jumpRelative(int8_t offset) noexcept final;
|
||||
void jumpConditional(bool condition) noexcept final;
|
||||
void returnConditional(bool condition) noexcept final;
|
||||
void ret() noexcept final;
|
||||
void jumpIndirect() noexcept final;
|
||||
|
||||
private:
|
||||
Bus& m_bus;
|
||||
|
||||
register16_t af = 0xffff;
|
||||
register16_t bc = 0xffff;
|
||||
register16_t de = 0xffff;
|
||||
register16_t hl = 0xffff;
|
||||
register16_t m_af = 0xffff;
|
||||
register16_t m_bc = 0xffff;
|
||||
register16_t m_de = 0xffff;
|
||||
register16_t m_hl = 0xffff;
|
||||
|
||||
bool m_ime = false;
|
||||
bool m_stopped = false;
|
||||
bool m_ei = false;
|
||||
|
||||
bool m_prefixCB = false;
|
||||
|
||||
[[nodiscard]] uint8_t R(int r);
|
||||
void R(int r, uint8_t value);
|
||||
|
||||
[[nodiscard]] register16_t& RP(int rp) noexcept;
|
||||
[[nodiscard]] register16_t& RP2(int rp) noexcept;
|
||||
[[nodiscard]] register16_t& RP(int rp);
|
||||
[[nodiscard]] register16_t& RP2(int rp);
|
||||
|
||||
[[nodiscard]] static constexpr auto adjustHalfCarryAdd(uint8_t f, const uint8_t before, const uint8_t value, const int calculation) noexcept {
|
||||
[[nodiscard]] static constexpr auto adjustHalfCarryAdd(uint8_t f, const uint8_t before, const uint8_t value, const int calculation) {
|
||||
return setBit(f, HC, calculateHalfCarryAdd(before, value, calculation));
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr auto adjustHalfCarrySub(uint8_t f, const uint8_t before, const uint8_t value, const int calculation) noexcept {
|
||||
[[nodiscard]] static constexpr auto adjustHalfCarrySub(uint8_t f, const uint8_t before, const uint8_t value, const int calculation) {
|
||||
return setBit(f, HC, calculateHalfCarrySub(before, value, calculation));
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool convertCondition(uint8_t f, int flag) noexcept;
|
||||
[[nodiscard]] bool convertCondition(int flag) noexcept final;
|
||||
|
||||
static uint8_t subtract(uint8_t& f, uint8_t operand, uint8_t value, int carry = 0) noexcept;
|
||||
static uint8_t subtract(uint8_t& f, uint8_t operand, uint8_t value, int carry = 0);
|
||||
|
||||
void executeCB(int x, int y, int z, int p, int q);
|
||||
void executeOther(int x, int y, int z, int p, int q);
|
||||
|
||||
[[nodiscard]] static uint8_t increment(uint8_t& f, uint8_t operand) noexcept;
|
||||
[[nodiscard]] static uint8_t decrement(uint8_t& f, uint8_t operand) noexcept;
|
||||
[[nodiscard]] static uint8_t increment(uint8_t& f, uint8_t operand);
|
||||
[[nodiscard]] static uint8_t decrement(uint8_t& f, uint8_t operand);
|
||||
|
||||
void stop(bool value = true) noexcept { m_stopped = value; }
|
||||
void start() noexcept { stop(false); }
|
||||
[[nodiscard]] bool stopped() const noexcept { return m_stopped; }
|
||||
void stop(bool value = true) { m_stopped = value; }
|
||||
void start() { stop(false); }
|
||||
[[nodiscard]] bool stopped() const { return m_stopped; }
|
||||
|
||||
void di() noexcept;
|
||||
void ei() noexcept;
|
||||
[[nodiscard]] constexpr bool& EI() noexcept { return m_ei; }
|
||||
|
||||
virtual void disableInterrupts() noexcept final;
|
||||
virtual void enableInterrupts() noexcept final;
|
||||
|
||||
void reti();
|
||||
|
||||
void jrConditionalFlag(uint8_t f, int flag);
|
||||
void returnConditionalFlag(uint8_t f, int flag);
|
||||
void jumpConditionalFlag(uint8_t f, int flag);
|
||||
void callConditionalFlag(uint8_t f, int flag);
|
||||
|
||||
[[nodiscard]] register16_t add(uint8_t& f, register16_t operand, register16_t value);
|
||||
|
||||
[[nodiscard]] static uint8_t add(uint8_t& f, uint8_t operand, uint8_t value, int carry = 0) noexcept;
|
||||
[[nodiscard]] static uint8_t adc(uint8_t& f, uint8_t operand, uint8_t value) noexcept;
|
||||
[[nodiscard]] static uint8_t sbc(uint8_t& f, uint8_t operand, uint8_t value) noexcept;
|
||||
static uint8_t andr(uint8_t& f, uint8_t operand, uint8_t value) noexcept;
|
||||
[[nodiscard]] static uint8_t xorr(uint8_t& f, uint8_t operand, uint8_t value) noexcept;
|
||||
[[nodiscard]] static uint8_t orr(uint8_t& f, uint8_t operand, uint8_t value) noexcept;
|
||||
[[nodiscard]] static void compare(uint8_t& f, uint8_t operand, uint8_t value) noexcept;
|
||||
[[nodiscard]] static uint8_t add(uint8_t& f, uint8_t operand, uint8_t value, int carry = 0);
|
||||
[[nodiscard]] static uint8_t adc(uint8_t& f, uint8_t operand, uint8_t value);
|
||||
[[nodiscard]] static uint8_t sbc(uint8_t& f, uint8_t operand, uint8_t value);
|
||||
static uint8_t andr(uint8_t& f, uint8_t operand, uint8_t value);
|
||||
[[nodiscard]] static uint8_t xorr(uint8_t& f, uint8_t operand, uint8_t value);
|
||||
[[nodiscard]] static uint8_t orr(uint8_t& f, uint8_t operand, uint8_t value);
|
||||
[[nodiscard]] static void compare(uint8_t& f, uint8_t operand, uint8_t value);
|
||||
|
||||
[[nodiscard]] static uint8_t rlc(uint8_t& f, uint8_t operand) noexcept;
|
||||
[[nodiscard]] static uint8_t rrc(uint8_t& f, uint8_t operand) noexcept;
|
||||
[[nodiscard]] static uint8_t rl(uint8_t& f, uint8_t operand) noexcept;
|
||||
[[nodiscard]] static uint8_t rr(uint8_t& f, uint8_t operand) noexcept;
|
||||
[[nodiscard]] static uint8_t sla(uint8_t& f, uint8_t operand) noexcept;
|
||||
[[nodiscard]] static uint8_t sra(uint8_t& f, uint8_t operand) noexcept;
|
||||
[[nodiscard]] static uint8_t srl(uint8_t& f, uint8_t operand) noexcept;
|
||||
[[nodiscard]] static uint8_t rlc(uint8_t& f, uint8_t operand);
|
||||
[[nodiscard]] static uint8_t rrc(uint8_t& f, uint8_t operand);
|
||||
[[nodiscard]] static uint8_t rl(uint8_t& f, uint8_t operand);
|
||||
[[nodiscard]] static uint8_t rr(uint8_t& f, uint8_t operand);
|
||||
[[nodiscard]] static uint8_t sla(uint8_t& f, uint8_t operand);
|
||||
[[nodiscard]] static uint8_t sra(uint8_t& f, uint8_t operand);
|
||||
[[nodiscard]] static uint8_t srl(uint8_t& f, uint8_t operand);
|
||||
|
||||
static void bit(uint8_t& f, int n, uint8_t operand) noexcept;
|
||||
[[nodiscard]] static uint8_t res(int n, uint8_t operand) noexcept;
|
||||
[[nodiscard]] static uint8_t set(int n, uint8_t operand) noexcept;
|
||||
static void bit(uint8_t& f, int n, uint8_t operand);
|
||||
[[nodiscard]] static uint8_t res(int n, uint8_t operand);
|
||||
[[nodiscard]] static uint8_t set(int n, uint8_t operand);
|
||||
|
||||
[[nodiscard]] static uint8_t daa(uint8_t& f, uint8_t operand) noexcept;
|
||||
[[nodiscard]] static uint8_t daa(uint8_t& f, uint8_t operand);
|
||||
|
||||
static void scf(uint8_t& f, uint8_t operand) noexcept;
|
||||
static void ccf(uint8_t& f, uint8_t operand) noexcept;
|
||||
[[nodiscard]] static uint8_t cpl(uint8_t& f, uint8_t operand) noexcept;
|
||||
static void scf(uint8_t& f, uint8_t operand);
|
||||
static void ccf(uint8_t& f, uint8_t operand);
|
||||
[[nodiscard]] static uint8_t cpl(uint8_t& f, uint8_t operand);
|
||||
|
||||
[[nodiscard]] static uint8_t swap(uint8_t& f, uint8_t operand) noexcept;
|
||||
[[nodiscard]] static uint8_t swap(uint8_t& f, uint8_t operand);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -14,18 +14,18 @@ namespace EightBit {
|
||||
ObjectAttribute() = default;
|
||||
ObjectAttribute(Ram& ram, uint16_t address);
|
||||
|
||||
[[nodiscard]] auto positionY() const noexcept { return m_positionY; }
|
||||
[[nodiscard]] auto positionX() const noexcept { return m_positionX; }
|
||||
[[nodiscard]] auto pattern() const noexcept { return m_pattern; }
|
||||
[[nodiscard]] auto flags() const noexcept { return m_flags; }
|
||||
[[nodiscard]] auto positionY() const { return m_positionY; }
|
||||
[[nodiscard]] auto positionX() const { return m_positionX; }
|
||||
[[nodiscard]] auto pattern() const { return m_pattern; }
|
||||
[[nodiscard]] auto flags() const { return m_flags; }
|
||||
|
||||
[[nodiscard]] auto priority() const noexcept { return flags() & Chip::Bit7; }
|
||||
[[nodiscard]] auto priority() const { return flags() & Chip::Bit7; }
|
||||
|
||||
[[nodiscard]] auto highPriority() const noexcept { return !!priority(); }
|
||||
[[nodiscard]] auto lowPriority() const noexcept { return !priority(); }
|
||||
[[nodiscard]] auto flipY() const noexcept { return !!(flags() & Chip::Bit6); }
|
||||
[[nodiscard]] auto flipX() const noexcept { return !!(flags() & Chip::Bit5); }
|
||||
[[nodiscard]] auto palette() const noexcept { return (flags() & Chip::Bit4) >> 4; }
|
||||
[[nodiscard]] auto highPriority() const { return !!priority(); }
|
||||
[[nodiscard]] auto lowPriority() const { return !priority(); }
|
||||
[[nodiscard]] auto flipY() const { return !!(flags() & Chip::Bit6); }
|
||||
[[nodiscard]] auto flipX() const { return !!(flags() & Chip::Bit5); }
|
||||
[[nodiscard]] auto palette() const { return (flags() & Chip::Bit4) >> 4; }
|
||||
|
||||
private:
|
||||
uint8_t m_positionY;
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
|
||||
#include <Ram.h>
|
||||
|
||||
EightBit::GameBoy::CharacterDefinition::CharacterDefinition(Ram& vram, const uint16_t address) noexcept
|
||||
EightBit::GameBoy::CharacterDefinition::CharacterDefinition(Ram& vram, const uint16_t address)
|
||||
: m_vram(vram),
|
||||
m_address(address) {
|
||||
}
|
||||
|
||||
std::array<int, 8> EightBit::GameBoy::CharacterDefinition::get(int row) const noexcept {
|
||||
std::array<int, 8> EightBit::GameBoy::CharacterDefinition::get(int row) const {
|
||||
|
||||
std::array<int, 8> returned {};
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "../inc/LR35902.h"
|
||||
#include "../inc/IoRegisters.h"
|
||||
|
||||
EightBit::GameBoy::Disassembler::Disassembler(Bus& bus) noexcept
|
||||
EightBit::GameBoy::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);
|
||||
@@ -170,7 +170,7 @@ void EightBit::GameBoy::Disassembler::disassemble(std::ostringstream& output, LR
|
||||
auto q = (y & 1);
|
||||
|
||||
auto immediate = BUS().peek(pc + 1);
|
||||
auto absolute = cpu.peekWord(pc + 1).word;
|
||||
auto absolute = cpu.peekShort(pc + 1).word;
|
||||
auto displacement = (int8_t)immediate;
|
||||
auto relative = pc + displacement + 2;
|
||||
auto indexedImmediate = BUS().peek(pc + 1);
|
||||
|
||||
+11
-11
@@ -7,7 +7,7 @@
|
||||
|
||||
#include <Processor.h>
|
||||
|
||||
EightBit::GameBoy::Display::Display(const AbstractColourPalette* colours, Bus& bus, Ram& oam, Ram& vram) noexcept
|
||||
EightBit::GameBoy::Display::Display(const AbstractColourPalette* colours, Bus& bus, Ram& oam, Ram& vram)
|
||||
: m_bus(bus),
|
||||
m_oam(oam),
|
||||
m_vram(vram),
|
||||
@@ -15,7 +15,7 @@ EightBit::GameBoy::Display::Display(const AbstractColourPalette* colours, Bus& b
|
||||
}
|
||||
|
||||
#pragma optimize ("t", off)
|
||||
void EightBit::GameBoy::Display::renderCurrentScanline() noexcept {
|
||||
void EightBit::GameBoy::Display::renderCurrentScanline() {
|
||||
m_scanLine = m_bus.IO().peek(IoRegisters::LY);
|
||||
if (m_scanLine < RasterHeight) {
|
||||
m_control = m_bus.IO().peek(IoRegisters::LCDC);
|
||||
@@ -28,7 +28,7 @@ void EightBit::GameBoy::Display::renderCurrentScanline() noexcept {
|
||||
}
|
||||
#pragma optimize ("t", on)
|
||||
|
||||
std::array<int, 4> EightBit::GameBoy::Display::createPalette(const int address) noexcept {
|
||||
std::array<int, 4> EightBit::GameBoy::Display::createPalette(const int address) {
|
||||
const auto raw = m_bus.IO().peek(address);
|
||||
const std::array<int, 4> palette = {
|
||||
raw & 0b11,
|
||||
@@ -39,12 +39,12 @@ std::array<int, 4> EightBit::GameBoy::Display::createPalette(const int address)
|
||||
return palette;
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::Display::loadObjectAttributes() noexcept {
|
||||
void EightBit::GameBoy::Display::loadObjectAttributes() {
|
||||
for (int i = 0; i < 40; ++i)
|
||||
m_objectAttributes[i] = ObjectAttribute(m_oam, 4 * i);
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::Display::renderObjects() noexcept {
|
||||
void EightBit::GameBoy::Display::renderObjects() {
|
||||
|
||||
const auto objBlockHeight = (m_control & IoRegisters::OBJ_SIZE) ? 16 : 8;
|
||||
|
||||
@@ -84,7 +84,7 @@ void EightBit::GameBoy::Display::renderObjects() noexcept {
|
||||
}
|
||||
|
||||
#pragma optimize ("t", off)
|
||||
void EightBit::GameBoy::Display::renderBackground() noexcept {
|
||||
void EightBit::GameBoy::Display::renderBackground() {
|
||||
|
||||
const auto palette = createPalette(IoRegisters::BGP);
|
||||
|
||||
@@ -109,7 +109,7 @@ void EightBit::GameBoy::Display::renderBackground() noexcept {
|
||||
void EightBit::GameBoy::Display::renderBackground(
|
||||
int bgArea, int bgCharacters, tile_offset_t offsetType,
|
||||
int offsetX, int offsetY,
|
||||
const std::array<int, 4>& palette) noexcept {
|
||||
const std::array<int, 4>& palette) {
|
||||
|
||||
const int row = (m_scanLine - offsetY) / 8;
|
||||
const auto address = bgArea + (row * BufferCharacterWidth);
|
||||
@@ -131,7 +131,7 @@ void EightBit::GameBoy::Display::renderSpriteTile(
|
||||
const int drawX, const int drawY,
|
||||
const bool flipX, const bool flipY,
|
||||
const std::array<int, 4>& palette,
|
||||
const CharacterDefinition& definition) noexcept {
|
||||
const CharacterDefinition& definition) {
|
||||
renderTile(
|
||||
height,
|
||||
drawX, drawY,
|
||||
@@ -145,7 +145,7 @@ void EightBit::GameBoy::Display::renderBackgroundTile(
|
||||
int row, int column,
|
||||
int bgCharacters, tile_offset_t offsetType,
|
||||
int offsetX, int offsetY,
|
||||
const std::array<int, 4>& palette) noexcept {
|
||||
const std::array<int, 4>& palette) {
|
||||
|
||||
const auto definition = CharacterDefinition(m_vram, bgCharacters + definitionOffset);
|
||||
const auto drawX = (column * 8) + offsetX;
|
||||
@@ -160,7 +160,7 @@ void EightBit::GameBoy::Display::renderBackgroundTile(
|
||||
void EightBit::GameBoy::Display::renderBackgroundTile(
|
||||
const int drawX, const int drawY,
|
||||
const std::array<int, 4>& palette,
|
||||
const CharacterDefinition& definition) noexcept {
|
||||
const CharacterDefinition& definition) {
|
||||
renderTile(
|
||||
8,
|
||||
drawX, drawY,
|
||||
@@ -174,7 +174,7 @@ void EightBit::GameBoy::Display::renderTile(
|
||||
const int drawX, const int drawY,
|
||||
const bool flipX, const bool flipY, const bool allowTransparencies,
|
||||
const std::array<int, 4>& palette,
|
||||
const CharacterDefinition& definition) noexcept {
|
||||
const CharacterDefinition& definition) {
|
||||
|
||||
const auto width = 8;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include "../inc/GameBoyBus.h"
|
||||
#include "../inc/Display.h"
|
||||
|
||||
EightBit::GameBoy::Bus::Bus() noexcept
|
||||
EightBit::GameBoy::Bus::Bus()
|
||||
: m_cpu(*this),
|
||||
m_ioPorts(*this) {
|
||||
WrittenByte.connect(std::bind(&GameBoy::Bus::Bus_WrittenByte, this, std::placeholders::_1));
|
||||
@@ -40,7 +40,7 @@ void EightBit::GameBoy::Bus::loadGameRom(const std::string path) {
|
||||
validateCartridgeType();
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::Bus::Bus_WrittenByte(EightBit::EventArgs) noexcept {
|
||||
void EightBit::GameBoy::Bus::Bus_WrittenByte(EightBit::EventArgs) {
|
||||
|
||||
const auto address = ADDRESS().word;
|
||||
const auto value = DATA();
|
||||
|
||||
+124
-122
@@ -4,55 +4,80 @@
|
||||
|
||||
// based on http://www.z80.info/decoding.htm
|
||||
|
||||
DEFINE_PIN_LEVEL_CHANGERS(MWR, GameBoy::LR35902);
|
||||
DEFINE_PIN_LEVEL_CHANGERS(RD, GameBoy::LR35902);
|
||||
DEFINE_PIN_LEVEL_CHANGERS(WR, GameBoy::LR35902);
|
||||
|
||||
EightBit::GameBoy::LR35902::LR35902(Bus& memory)
|
||||
: IntelProcessor(memory),
|
||||
m_bus(memory) {
|
||||
|
||||
RaisedPOWER.connect([this](EventArgs) {
|
||||
raiseWR();
|
||||
raiseRD();
|
||||
raiseMWR();
|
||||
EI() = false;
|
||||
});
|
||||
|
||||
RaisingHALT.connect([this](EventArgs) {
|
||||
++PC();
|
||||
});
|
||||
|
||||
MachineTicked.connect([this](EventArgs) {
|
||||
m_bus.IO().incrementTimers();
|
||||
m_bus.IO().transferDma();
|
||||
});
|
||||
}
|
||||
|
||||
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::AF() noexcept {
|
||||
m_af.low = higherNibble(m_af.low);
|
||||
return m_af;
|
||||
}
|
||||
|
||||
const EightBit::register16_t& EightBit::GameBoy::LR35902::BC() const noexcept {
|
||||
return bc;
|
||||
EightBit::register16_t& EightBit::GameBoy::LR35902::BC() noexcept {
|
||||
return m_bc;
|
||||
}
|
||||
|
||||
const EightBit::register16_t& EightBit::GameBoy::LR35902::DE() const noexcept {
|
||||
return de;
|
||||
EightBit::register16_t& EightBit::GameBoy::LR35902::DE() noexcept {
|
||||
return m_de;
|
||||
}
|
||||
|
||||
const EightBit::register16_t& EightBit::GameBoy::LR35902::HL() const noexcept {
|
||||
return hl;
|
||||
EightBit::register16_t& EightBit::GameBoy::LR35902::HL() noexcept {
|
||||
return m_hl;
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::handleRESET() noexcept {
|
||||
IntelProcessor::handleRESET();
|
||||
di();
|
||||
SP() = Mask16 - 1;
|
||||
tickMachine(4);
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::handleINT() noexcept {
|
||||
IntelProcessor::handleINT();
|
||||
raiseHALT();
|
||||
di();
|
||||
restart(BUS().DATA());
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::memoryUpdate(int ticks) noexcept {
|
||||
lowerMWR();
|
||||
lowerWR();
|
||||
IntelProcessor::memoryWrite();
|
||||
tickMachine(ticks);
|
||||
raiseWR();
|
||||
raiseMWR();
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::memoryWrite() noexcept {
|
||||
tickMachine();
|
||||
IntelProcessor::memoryWrite();
|
||||
memoryUpdate(1);
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::memoryRead() noexcept {
|
||||
tickMachine();
|
||||
return IntelProcessor::memoryRead();
|
||||
lowerMWR();
|
||||
lowerRD();
|
||||
IntelProcessor::memoryRead();
|
||||
tickMachine();
|
||||
raiseRD();
|
||||
raiseMWR();
|
||||
return BUS().DATA();
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::pushWord(register16_t value) noexcept {
|
||||
@@ -60,43 +85,42 @@ void EightBit::GameBoy::LR35902::pushWord(register16_t value) noexcept {
|
||||
IntelProcessor::pushWord(value);
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::jr(int8_t offset) noexcept {
|
||||
IntelProcessor::jr(offset);
|
||||
void EightBit::GameBoy::LR35902::jumpRelative(int8_t offset) noexcept {
|
||||
IntelProcessor::jumpRelative(offset);
|
||||
tickMachine();
|
||||
}
|
||||
|
||||
int EightBit::GameBoy::LR35902::jumpConditional(const int condition) noexcept {
|
||||
if (IntelProcessor::jumpConditional(condition))
|
||||
void EightBit::GameBoy::LR35902::jumpConditional(bool condition) noexcept {
|
||||
IntelProcessor::jumpConditional(condition);
|
||||
if (condition)
|
||||
tickMachine();
|
||||
return condition;
|
||||
}
|
||||
|
||||
int EightBit::GameBoy::LR35902::returnConditional(const int condition) noexcept {
|
||||
void EightBit::GameBoy::LR35902::returnConditional(bool condition) noexcept {
|
||||
tickMachine();
|
||||
IntelProcessor::returnConditional(condition);
|
||||
tickMachine();
|
||||
return condition;
|
||||
}
|
||||
|
||||
int EightBit::GameBoy::LR35902::jrConditional(const int condition) noexcept {
|
||||
if (!IntelProcessor::jrConditional(condition))
|
||||
tickMachine();
|
||||
return condition;
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::ret() noexcept {
|
||||
IntelProcessor::ret();
|
||||
tickMachine();
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::di() noexcept {
|
||||
void EightBit::GameBoy::LR35902::jumpIndirect() noexcept {
|
||||
IntelProcessor::jumpIndirect();
|
||||
tickMachine();
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::disableInterrupts() noexcept {
|
||||
IME() = false;
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::ei() noexcept {
|
||||
void EightBit::GameBoy::LR35902::enableInterrupts() noexcept {
|
||||
IME() = true;
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::increment(uint8_t& f, const uint8_t operand) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::increment(uint8_t& f, const uint8_t operand) {
|
||||
f = clearBit(f, NF);
|
||||
const uint8_t result = operand + 1;
|
||||
f = adjustZero<LR35902>(f, result);
|
||||
@@ -104,7 +128,7 @@ uint8_t EightBit::GameBoy::LR35902::increment(uint8_t& f, const uint8_t operand)
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::decrement(uint8_t& f, const uint8_t operand) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::decrement(uint8_t& f, const uint8_t operand) {
|
||||
f = setBit(f, NF);
|
||||
f = clearBit(f, HC, lowNibble(operand));
|
||||
const uint8_t result = operand - 1;
|
||||
@@ -166,7 +190,7 @@ void EightBit::GameBoy::LR35902::R(const int r, const uint8_t value) {
|
||||
}
|
||||
}
|
||||
|
||||
EightBit::register16_t& EightBit::GameBoy::LR35902::RP(const int rp) noexcept {
|
||||
EightBit::register16_t& EightBit::GameBoy::LR35902::RP(const int rp) {
|
||||
switch (rp) {
|
||||
case 0b00:
|
||||
return BC();
|
||||
@@ -181,7 +205,7 @@ EightBit::register16_t& EightBit::GameBoy::LR35902::RP(const int rp) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
EightBit::register16_t& EightBit::GameBoy::LR35902::RP2(const int rp) noexcept {
|
||||
EightBit::register16_t& EightBit::GameBoy::LR35902::RP2(const int rp) {
|
||||
switch (rp) {
|
||||
case 0b00:
|
||||
return BC();
|
||||
@@ -196,42 +220,26 @@ EightBit::register16_t& EightBit::GameBoy::LR35902::RP2(const int rp) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
bool EightBit::GameBoy::LR35902::convertCondition(const uint8_t f, int flag) noexcept {
|
||||
bool EightBit::GameBoy::LR35902::convertCondition(int flag) noexcept {
|
||||
ASSUME(flag >= 0);
|
||||
ASSUME(flag <= 7);
|
||||
switch (flag) {
|
||||
case 0:
|
||||
return !(f & ZF);
|
||||
return !(F() & ZF);
|
||||
case 1:
|
||||
return f & ZF;
|
||||
return F() & ZF;
|
||||
case 2:
|
||||
return !(f & CF);
|
||||
return !(F() & CF);
|
||||
case 3:
|
||||
return f & CF;
|
||||
return F() & CF;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::returnConditionalFlag(const uint8_t f, const int flag) {
|
||||
returnConditional(convertCondition(f, flag));
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::jrConditionalFlag(const uint8_t f, const int flag) {
|
||||
jrConditional(convertCondition(f, flag));
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::jumpConditionalFlag(uint8_t f, const int flag) {
|
||||
jumpConditional(convertCondition(f, flag));
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::callConditionalFlag(uint8_t f, const int flag) {
|
||||
callConditional(convertCondition(f, flag));
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::reti() {
|
||||
ret();
|
||||
ei();
|
||||
enableInterrupts();
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::GameBoy::LR35902::add(uint8_t& f, const register16_t operand, const register16_t value) {
|
||||
@@ -250,7 +258,7 @@ EightBit::register16_t EightBit::GameBoy::LR35902::add(uint8_t& f, const registe
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::add(uint8_t& f, const uint8_t operand, const uint8_t value, const int carry) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::add(uint8_t& f, const uint8_t operand, const uint8_t value, const int carry) {
|
||||
|
||||
const register16_t addition = operand + value + carry;
|
||||
const auto result = addition.low;
|
||||
@@ -264,11 +272,11 @@ uint8_t EightBit::GameBoy::LR35902::add(uint8_t& f, const uint8_t operand, const
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::adc(uint8_t& f, const uint8_t operand, const uint8_t value) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::adc(uint8_t& f, const uint8_t operand, const uint8_t value) {
|
||||
return add(f, operand, value, (f & CF) >> 4);
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::subtract(uint8_t& f, const uint8_t operand, const uint8_t value, const int carry) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::subtract(uint8_t& f, const uint8_t operand, const uint8_t value, const int carry) {
|
||||
|
||||
const register16_t subtraction = operand - value - carry;
|
||||
const auto result = subtraction.low;
|
||||
@@ -282,11 +290,11 @@ uint8_t EightBit::GameBoy::LR35902::subtract(uint8_t& f, const uint8_t operand,
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::sbc(uint8_t& f, const uint8_t operand, const uint8_t value) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::sbc(uint8_t& f, const uint8_t operand, const uint8_t value) {
|
||||
return subtract(f, operand, value, (f & CF) >> 4);
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::andr(uint8_t& f, const uint8_t operand, const uint8_t value) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::andr(uint8_t& f, const uint8_t operand, const uint8_t value) {
|
||||
f = setBit(f, HC);
|
||||
f = clearBit(f, CF | NF);
|
||||
const uint8_t result = operand & value;
|
||||
@@ -294,76 +302,76 @@ uint8_t EightBit::GameBoy::LR35902::andr(uint8_t& f, const uint8_t operand, cons
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::xorr(uint8_t& f, const uint8_t operand, const uint8_t value) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::xorr(uint8_t& f, const uint8_t operand, const uint8_t value) {
|
||||
f = clearBit(f, HC | CF | NF);
|
||||
const uint8_t result = operand ^ value;
|
||||
f = adjustZero<LR35902>(f, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::orr(uint8_t& f, const uint8_t operand, const uint8_t value) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::orr(uint8_t& f, const uint8_t operand, const uint8_t value) {
|
||||
f = clearBit(f, HC | CF | NF);
|
||||
const uint8_t result = operand | value;
|
||||
f = adjustZero<LR35902>(f, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::compare(uint8_t& f, uint8_t operand, const uint8_t value) noexcept {
|
||||
void EightBit::GameBoy::LR35902::compare(uint8_t& f, uint8_t operand, const uint8_t value) {
|
||||
subtract(f, operand, value);
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::rlc(uint8_t& f, const uint8_t operand) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::rlc(uint8_t& f, const uint8_t operand) {
|
||||
f = clearBit(f, NF | HC | ZF);
|
||||
const auto carry = operand & Bit7;
|
||||
f = setBit(f, CF, carry);
|
||||
return (operand << 1) | (carry >> 7);
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::rrc(uint8_t& f, const uint8_t operand) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::rrc(uint8_t& f, const uint8_t operand) {
|
||||
f = clearBit(f, NF | HC | ZF);
|
||||
const auto carry = operand & Bit0;
|
||||
f = setBit(f, CF, carry);
|
||||
return (operand >> 1) | (carry << 7);
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::rl(uint8_t& f, const uint8_t operand) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::rl(uint8_t& f, const uint8_t operand) {
|
||||
f = clearBit(f, NF | HC | ZF);
|
||||
const auto carry = f & CF;
|
||||
f = setBit(f, CF, operand & Bit7);
|
||||
return (operand << 1) | (carry >> 4); // CF at Bit4
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::rr(uint8_t& f, const uint8_t operand) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::rr(uint8_t& f, const uint8_t operand) {
|
||||
f = clearBit(f, NF | HC | ZF);
|
||||
const auto carry = f & CF;
|
||||
f = setBit(f, CF, operand & Bit0);
|
||||
return (operand >> 1) | (carry << 3); // CF at Bit4
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::sla(uint8_t& f, const uint8_t operand) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::sla(uint8_t& f, const uint8_t operand) {
|
||||
f = clearBit(f, NF | HC | ZF);
|
||||
f = setBit(f, CF, operand & Bit7);
|
||||
return operand << 1;
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::sra(uint8_t& f, const uint8_t operand) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::sra(uint8_t& f, const uint8_t operand) {
|
||||
f = clearBit(f, NF | HC | ZF);
|
||||
f = setBit(f, CF, operand & Bit0);
|
||||
return (operand >> 1) | (operand & Bit7);
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::swap(uint8_t& f, const uint8_t operand) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::swap(uint8_t& f, const uint8_t operand) {
|
||||
f = clearBit(f, NF | HC | CF);
|
||||
return promoteNibble(operand) | demoteNibble(operand);
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::srl(uint8_t& f, const uint8_t operand) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::srl(uint8_t& f, const uint8_t operand) {
|
||||
f = clearBit(f, NF | HC | ZF);
|
||||
f = setBit(f, CF, operand & Bit0);
|
||||
return (operand >> 1) & ~Bit7;
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::bit(uint8_t& f, const int n, const uint8_t operand) noexcept {
|
||||
void EightBit::GameBoy::LR35902::bit(uint8_t& f, const int n, const uint8_t operand) {
|
||||
ASSUME(n >= 0);
|
||||
ASSUME(n <= 7);
|
||||
const auto carry = f & CF;
|
||||
@@ -371,19 +379,19 @@ void EightBit::GameBoy::LR35902::bit(uint8_t& f, const int n, const uint8_t oper
|
||||
f = setBit(f, CF, carry);
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::res(const int n, const uint8_t operand) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::res(const int n, const uint8_t operand) {
|
||||
ASSUME(n >= 0);
|
||||
ASSUME(n <= 7);
|
||||
return clearBit(operand, Chip::bit(n));
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::set(const int n, const uint8_t operand) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::set(const int n, const uint8_t operand) {
|
||||
ASSUME(n >= 0);
|
||||
ASSUME(n <= 7);
|
||||
return setBit(operand, Chip::bit(n));
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::daa(uint8_t& f, uint8_t operand) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::daa(uint8_t& f, uint8_t operand) {
|
||||
|
||||
int updated = operand;
|
||||
|
||||
@@ -408,67 +416,61 @@ uint8_t EightBit::GameBoy::LR35902::daa(uint8_t& f, uint8_t operand) noexcept {
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::cpl(uint8_t& f, const uint8_t operand) noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::cpl(uint8_t& f, const uint8_t operand) {
|
||||
f = setBit(f, HC | NF);
|
||||
return ~operand;
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::scf(uint8_t& f, const uint8_t operand) noexcept {
|
||||
void EightBit::GameBoy::LR35902::scf(uint8_t& f, const uint8_t operand) {
|
||||
f = setBit(f, CF);
|
||||
f = clearBit(f, HC | NF);
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::ccf(uint8_t& f, const uint8_t operand) noexcept {
|
||||
void EightBit::GameBoy::LR35902::ccf(uint8_t& f, const uint8_t operand) {
|
||||
f = clearBit(f, NF | HC);
|
||||
f = clearBit(f, CF, f & CF);
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::enabledInterrupts() noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::enabledInterrupts() {
|
||||
return BUS().peek(IoRegisters::BASE + IoRegisters::IE);
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::flaggedInterrupts() noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::flaggedInterrupts() {
|
||||
return m_bus.IO().peek(IoRegisters::IF);
|
||||
}
|
||||
|
||||
uint8_t EightBit::GameBoy::LR35902::maskedInterrupts() noexcept {
|
||||
uint8_t EightBit::GameBoy::LR35902::maskedInterrupts() {
|
||||
return enabledInterrupts() & flaggedInterrupts();
|
||||
}
|
||||
|
||||
int EightBit::GameBoy::LR35902::step() noexcept {
|
||||
void EightBit::GameBoy::LR35902::poweredStep() noexcept {
|
||||
|
||||
ExecutingInstruction.fire(*this);
|
||||
m_prefixCB = false;
|
||||
resetCycles();
|
||||
if (LIKELY(powered())) {
|
||||
|
||||
const auto masked = maskedInterrupts();
|
||||
if (masked) {
|
||||
if (IME()) {
|
||||
m_bus.IO().poke(IoRegisters::IF, 0);
|
||||
lowerINT();
|
||||
const int index = findFirstSet(masked);
|
||||
BUS().DATA() = 0x38 + (index << 3);
|
||||
} else {
|
||||
raiseHALT();
|
||||
}
|
||||
}
|
||||
|
||||
if (UNLIKELY(lowered(RESET()))) {
|
||||
handleRESET();
|
||||
} else if (UNLIKELY(lowered(INT()))) {
|
||||
handleINT();
|
||||
} else if (UNLIKELY(lowered(HALT()))) {
|
||||
IntelProcessor::memoryRead(PC());
|
||||
//Processor::execute(0); // NOP
|
||||
if (EI()) {
|
||||
enableInterrupts();
|
||||
EI() = false;
|
||||
}
|
||||
|
||||
const auto masked = maskedInterrupts();
|
||||
if (masked) {
|
||||
if (IME()) {
|
||||
m_bus.IO().poke(IoRegisters::IF, 0);
|
||||
lowerINT();
|
||||
const int index = findFirstSet(masked);
|
||||
BUS().DATA() = 0x38 + (index << 3);
|
||||
} else {
|
||||
Processor::execute(fetchByte());
|
||||
raiseHALT();
|
||||
}
|
||||
}
|
||||
ExecutedInstruction.fire(*this);
|
||||
assert(cycles() > 0);
|
||||
assert(cycles() % 4 == 0);
|
||||
return cycles();
|
||||
|
||||
if (UNLIKELY(lowered(RESET()))) {
|
||||
handleRESET();
|
||||
} else if (UNLIKELY(lowered(INT()))) {
|
||||
handleINT();
|
||||
} else {
|
||||
Processor::execute(fetchByte());
|
||||
}
|
||||
}
|
||||
|
||||
void EightBit::GameBoy::LR35902::execute() noexcept {
|
||||
@@ -551,15 +553,16 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in
|
||||
break;
|
||||
case 2: // GB: STOP
|
||||
stop();
|
||||
tickMachine(2);
|
||||
break;
|
||||
case 3: // JR d
|
||||
jr(fetchByte());
|
||||
jumpRelative(fetchByte());
|
||||
break;
|
||||
case 4: // JR cc,d
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
jrConditionalFlag(F(), y - 4);
|
||||
jumpRelativeConditionalFlag(y - 4);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
@@ -722,7 +725,7 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
returnConditionalFlag(F(), y);
|
||||
returnConditionalFlag(y);
|
||||
break;
|
||||
case 4: // GB: LD (FF00 + n),A
|
||||
IntelProcessor::memoryWrite(IoRegisters::BASE + fetchByte(), A());
|
||||
@@ -772,7 +775,7 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in
|
||||
reti();
|
||||
break;
|
||||
case 2: // JP HL
|
||||
jump(HL());
|
||||
Processor::jump(HL());
|
||||
break;
|
||||
case 3: // LD SP,HL
|
||||
SP() = HL();
|
||||
@@ -792,7 +795,7 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
jumpConditionalFlag(F(), y);
|
||||
jumpConditionalFlag(y);
|
||||
break;
|
||||
case 4: // GB: LD (FF00 + C),A
|
||||
IntelProcessor::memoryWrite(IoRegisters::BASE + C(), A());
|
||||
@@ -815,23 +818,22 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in
|
||||
case 3: // Assorted operations
|
||||
switch (y) {
|
||||
case 0: // JP nn
|
||||
jump(MEMPTR() = fetchWord());
|
||||
tickMachine();
|
||||
jumpIndirect();
|
||||
break;
|
||||
case 1: // CB prefix
|
||||
m_prefixCB = true;
|
||||
Processor::execute(fetchByte());
|
||||
break;
|
||||
case 6: // DI
|
||||
di();
|
||||
disableInterrupts();
|
||||
break;
|
||||
case 7: // EI
|
||||
ei();
|
||||
EI() = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 4: // Conditional call: CALL cc[y], nn
|
||||
callConditionalFlag(F(), y);
|
||||
callConditionalFlag(y);
|
||||
break;
|
||||
case 5: // PUSH & various ops
|
||||
switch (q) {
|
||||
|
||||
@@ -22,4 +22,4 @@ void TestRunner::lowerPOWER() noexcept {
|
||||
EightBit::Bus::lowerPOWER();
|
||||
}
|
||||
|
||||
void TestRunner::initialise() {}
|
||||
void TestRunner::initialise() noexcept {}
|
||||
@@ -18,7 +18,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& CPU() noexcept { return m_cpu; }
|
||||
|
||||
@@ -415,7 +415,7 @@ namespace EightBit {
|
||||
static void dump(std::ostream& out, int value, int width);
|
||||
|
||||
uint8_t getByte(uint16_t address);
|
||||
uint16_t getWord(uint16_t address);
|
||||
uint16_t getShort(uint16_t address);
|
||||
|
||||
std::string dump_Byte(uint16_t address);
|
||||
std::string dump_DByte(uint16_t address);
|
||||
|
||||
+6
-4
@@ -35,11 +35,11 @@ namespace EightBit {
|
||||
|
||||
MOS6502(Bus& bus) noexcept;
|
||||
|
||||
Signal<MOS6502> ExecutingInstruction;
|
||||
Signal<MOS6502> ExecutedInstruction;
|
||||
//Signal<MOS6502> ExecutingInstruction;
|
||||
//Signal<MOS6502> ExecutedInstruction;
|
||||
|
||||
void execute() noexcept final;
|
||||
[[nodiscard]] int step() noexcept final;
|
||||
void poweredStep() noexcept final;
|
||||
|
||||
[[nodiscard]] constexpr auto& X() noexcept { return m_x; }
|
||||
[[nodiscard]] constexpr auto& Y() noexcept { return m_y; }
|
||||
@@ -106,7 +106,7 @@ namespace EightBit {
|
||||
}
|
||||
|
||||
// Read the opcode within the existing cycle
|
||||
void fetchInstruction() noexcept {
|
||||
uint8_t fetchInstruction() noexcept final {
|
||||
|
||||
// Instruction fetch beginning
|
||||
lowerSYNC();
|
||||
@@ -121,6 +121,8 @@ namespace EightBit {
|
||||
|
||||
// Instruction fetch has now completed
|
||||
raiseSYNC();
|
||||
|
||||
return opcode();
|
||||
}
|
||||
|
||||
// Addressing modes
|
||||
|
||||
@@ -474,8 +474,8 @@ uint8_t EightBit::Disassembly::getByte(uint16_t address) {
|
||||
return BUS().peek(address);
|
||||
}
|
||||
|
||||
uint16_t EightBit::Disassembly::getWord(uint16_t address) {
|
||||
return processor.peekWord(address).word;
|
||||
uint16_t EightBit::Disassembly::getShort(uint16_t address) {
|
||||
return processor.peekShort(address).word;
|
||||
}
|
||||
|
||||
////
|
||||
@@ -489,7 +489,7 @@ std::string EightBit::Disassembly::dump_DByte(uint16_t address) {
|
||||
}
|
||||
|
||||
std::string EightBit::Disassembly::dump_Word(uint16_t address) {
|
||||
return dump_WordValue(getWord(address));
|
||||
return dump_WordValue(getShort(address));
|
||||
}
|
||||
|
||||
////
|
||||
|
||||
+15
-25
@@ -20,37 +20,27 @@ DEFINE_PIN_LEVEL_CHANGERS(SYNC, MOS6502)
|
||||
DEFINE_PIN_LEVEL_CHANGERS(RDY, MOS6502)
|
||||
DEFINE_PIN_LEVEL_CHANGERS(RW, MOS6502)
|
||||
|
||||
int EightBit::MOS6502::step() noexcept {
|
||||
void EightBit::MOS6502::poweredStep() noexcept {
|
||||
|
||||
resetCycles();
|
||||
tick(); // A cycle is used, whether RDY is high or not
|
||||
|
||||
ExecutingInstruction.fire(*this);
|
||||
if (LIKELY(powered())) {
|
||||
if (UNLIKELY(lowered(SO())))
|
||||
handleSO();
|
||||
|
||||
tick(); // A cycle is used, whether RDY is high or not
|
||||
if (LIKELY(raised(RDY()))) {
|
||||
|
||||
if (UNLIKELY(lowered(SO())))
|
||||
handleSO();
|
||||
fetchInstruction();
|
||||
|
||||
if (LIKELY(raised(RDY()))) {
|
||||
|
||||
fetchInstruction();
|
||||
|
||||
// Priority: RESET > NMI > INT
|
||||
if (UNLIKELY(lowered(RESET())))
|
||||
handleRESET();
|
||||
else if (UNLIKELY(lowered(NMI())))
|
||||
handleNMI();
|
||||
else if (UNLIKELY(lowered(INT()) && !interruptMasked()))
|
||||
handleINT();
|
||||
else
|
||||
execute();
|
||||
}
|
||||
// Priority: RESET > NMI > INT
|
||||
if (UNLIKELY(lowered(RESET())))
|
||||
handleRESET();
|
||||
else if (UNLIKELY(lowered(NMI())))
|
||||
handleNMI();
|
||||
else if (UNLIKELY(lowered(INT()) && !interruptMasked()))
|
||||
handleINT();
|
||||
else
|
||||
execute();
|
||||
}
|
||||
ExecutedInstruction.fire(*this);
|
||||
|
||||
ASSUME(cycles() > 0);
|
||||
return cycles();
|
||||
}
|
||||
|
||||
// Interrupt (etc.) handlers
|
||||
|
||||
@@ -34,8 +34,8 @@ void Board::initialise() noexcept {
|
||||
|
||||
// Disassembly output
|
||||
if (m_configuration.isDebugMode())
|
||||
CPU().ExecutingInstruction.connect([this] (EightBit::MOS6502& cpu) {
|
||||
const auto address = cpu.PC();
|
||||
CPU().ExecutingInstruction.connect([this] (EightBit::EventArgs&) {
|
||||
const auto address = CPU().PC();
|
||||
const auto cell = peek(address);
|
||||
|
||||
std::cout << std::hex;
|
||||
@@ -53,8 +53,8 @@ void Board::initialise() noexcept {
|
||||
});
|
||||
|
||||
// Loop detected stop condition
|
||||
CPU().ExecutedInstruction.connect([this] (EightBit::MOS6502& cpu) {
|
||||
const auto pc = cpu.PC();
|
||||
CPU().ExecutedInstruction.connect([this] (EightBit::EventArgs&) {
|
||||
const auto pc = CPU().PC();
|
||||
if (m_oldPC != pc) {
|
||||
m_oldPC = pc;
|
||||
} else {
|
||||
@@ -65,5 +65,5 @@ void Board::initialise() noexcept {
|
||||
});
|
||||
|
||||
poke(0x00, 0x4c);
|
||||
CPU().pokeWord(1, m_configuration.getStartAddress());
|
||||
CPU().pokeShort(1, m_configuration.getStartAddress());
|
||||
}
|
||||
+1
-1
@@ -181,7 +181,7 @@
|
||||
namespace EightBit {
|
||||
class M6532 final : public ClockedChip {
|
||||
public:
|
||||
M6532() noexcept;
|
||||
M6532();
|
||||
virtual ~M6532() = default;
|
||||
|
||||
/* ___
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <cassert>
|
||||
|
||||
EightBit::M6532::M6532() noexcept {
|
||||
EightBit::M6532::M6532() {
|
||||
Ticked.connect([this](EightBit::EventArgs&) {
|
||||
step();
|
||||
});
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace EightBit {
|
||||
[[nodiscard]] Bus& BUS() { return m_bus; }
|
||||
|
||||
[[nodiscard]] uint8_t getByte(uint16_t address);
|
||||
[[nodiscard]] uint16_t getWord(uint16_t address);
|
||||
[[nodiscard]] uint16_t getShort(uint16_t address);
|
||||
|
||||
[[nodiscard]] std::string disassembleUnprefixed();
|
||||
[[nodiscard]] std::string disassemble10();
|
||||
|
||||
+66
-66
@@ -67,31 +67,31 @@ namespace EightBit {
|
||||
Signal<mc6809> ExecutedInstruction;
|
||||
|
||||
void execute() noexcept final;
|
||||
[[nodiscard]] int step() noexcept final;
|
||||
void poweredStep() noexcept final;
|
||||
|
||||
[[nodiscard]] constexpr auto& D() noexcept { return m_d; }
|
||||
[[nodiscard]] constexpr auto& A() noexcept { return D().high; }
|
||||
[[nodiscard]] constexpr auto& B() noexcept { return D().low; }
|
||||
[[nodiscard]] constexpr auto& D() { return m_d; }
|
||||
[[nodiscard]] constexpr auto& A() { return D().high; }
|
||||
[[nodiscard]] constexpr auto& B() { return D().low; }
|
||||
|
||||
[[nodiscard]] constexpr auto& X() noexcept { return m_x; }
|
||||
[[nodiscard]] constexpr auto& Y() noexcept { return m_y; }
|
||||
[[nodiscard]] constexpr auto& U() noexcept { return m_u; }
|
||||
[[nodiscard]] constexpr auto& S() noexcept { return m_s; }
|
||||
[[nodiscard]] constexpr auto& X() { return m_x; }
|
||||
[[nodiscard]] constexpr auto& Y() { return m_y; }
|
||||
[[nodiscard]] constexpr auto& U() { return m_u; }
|
||||
[[nodiscard]] constexpr auto& S() { return m_s; }
|
||||
|
||||
[[nodiscard]] constexpr auto& DP() noexcept { return m_dp; }
|
||||
[[nodiscard]] constexpr auto& CC() noexcept { return m_cc; }
|
||||
[[nodiscard]] constexpr const auto& CC() const noexcept { return m_cc; }
|
||||
[[nodiscard]] constexpr auto& DP() { return m_dp; }
|
||||
[[nodiscard]] constexpr auto& CC() { return m_cc; }
|
||||
[[nodiscard]] constexpr const auto& CC() const { return m_cc; }
|
||||
|
||||
// Flag checking
|
||||
|
||||
[[nodiscard]] constexpr auto fastInterruptMasked() const noexcept { return CC() & FF; }
|
||||
[[nodiscard]] constexpr auto interruptMasked() const noexcept { return CC() & IF; }
|
||||
[[nodiscard]] constexpr auto fastInterruptMasked() const { return CC() & FF; }
|
||||
[[nodiscard]] constexpr auto interruptMasked() const { return CC() & IF; }
|
||||
|
||||
[[nodiscard]] constexpr auto negative() const noexcept { return CC() & NF; }
|
||||
[[nodiscard]] constexpr auto zero() const noexcept { return CC() & ZF; }
|
||||
[[nodiscard]] constexpr auto overflow() const noexcept { return CC() & VF; }
|
||||
[[nodiscard]] constexpr auto carry() const noexcept { return CC() & CF; }
|
||||
[[nodiscard]] constexpr auto halfCarry() const noexcept { return CC() & HF; }
|
||||
[[nodiscard]] constexpr auto negative() const { return CC() & NF; }
|
||||
[[nodiscard]] constexpr auto zero() const { return CC() & ZF; }
|
||||
[[nodiscard]] constexpr auto overflow() const { return CC() & VF; }
|
||||
[[nodiscard]] constexpr auto carry() const { return CC() & CF; }
|
||||
[[nodiscard]] constexpr auto halfCarry() const { return CC() & HF; }
|
||||
|
||||
// |---------------|-----------------------------------|
|
||||
// | MPU State | |
|
||||
@@ -104,9 +104,9 @@ namespace EightBit {
|
||||
// | 1 | 1 | HALT Acknowledge |
|
||||
// |-------|-------|-----------------------------------|
|
||||
|
||||
[[nodiscard]] auto halted() noexcept { return lowered(HALT()); }
|
||||
void halt() noexcept { --PC(); lowerHALT(); }
|
||||
void proceed() noexcept { ++PC(); raiseHALT(); }
|
||||
[[nodiscard]] auto halted() { return lowered(HALT()); }
|
||||
void halt() { --PC(); lowerHALT(); }
|
||||
void proceed() { ++PC(); raiseHALT(); }
|
||||
|
||||
protected:
|
||||
// Default push/pop handlers
|
||||
@@ -163,21 +163,21 @@ namespace EightBit {
|
||||
|
||||
// Stack manipulation
|
||||
|
||||
void push(register16_t& stack, uint8_t value);
|
||||
void pushS(const uint8_t value) { push(S(), value); }
|
||||
void pushU(const uint8_t value) { push(U(), value); }
|
||||
void push(register16_t& stack, uint8_t value) noexcept;
|
||||
void pushS(const uint8_t value) noexcept { push(S(), value); }
|
||||
void pushU(const uint8_t value) noexcept { push(U(), value); }
|
||||
|
||||
void pushWord(register16_t& stack, const register16_t value) {
|
||||
void pushWord(register16_t& stack, const register16_t value) noexcept {
|
||||
push(stack, value.low);
|
||||
push(stack, value.high);
|
||||
}
|
||||
|
||||
void pushWordS(const register16_t value) { pushWord(S(), value); }
|
||||
void pushWordU(const register16_t value) { pushWord(U(), value); }
|
||||
void pushWordS(const register16_t value) noexcept { pushWord(S(), value); }
|
||||
void pushWordU(const register16_t value) noexcept { pushWord(U(), value); }
|
||||
|
||||
[[nodiscard]] uint8_t pop(register16_t& stack);
|
||||
[[nodiscard]] uint8_t popS() { return pop(S()); }
|
||||
[[nodiscard]] uint8_t popU() { return pop(U()); }
|
||||
[[nodiscard]] uint8_t pop(register16_t& stack) noexcept;
|
||||
[[nodiscard]] uint8_t popS() noexcept { return pop(S()); }
|
||||
[[nodiscard]] uint8_t popU() noexcept { return pop(U()); }
|
||||
|
||||
[[nodiscard]] register16_t popWord(register16_t& stack) {
|
||||
const auto high = pop(stack);
|
||||
@@ -190,9 +190,9 @@ namespace EightBit {
|
||||
|
||||
// Interrupt (etc.) handlers
|
||||
|
||||
void handleHALT();
|
||||
void handleNMI();
|
||||
void handleFIRQ();
|
||||
void handleHALT() noexcept;
|
||||
void handleNMI() noexcept;
|
||||
void handleFIRQ() noexcept;
|
||||
|
||||
// Execution helpers
|
||||
|
||||
@@ -204,7 +204,7 @@ namespace EightBit {
|
||||
[[nodiscard]] register16_t& RR(int which);
|
||||
|
||||
// Register selection for 8-bit transfer/exchange
|
||||
[[nodiscard]] uint8_t& referenceTransfer8(int specifier) noexcept;
|
||||
[[nodiscard]] uint8_t& referenceTransfer8(int specifier);
|
||||
|
||||
// Register selection for 16-bit transfer/exchange
|
||||
[[nodiscard]] register16_t& referenceTransfer16(int specifier);
|
||||
@@ -235,46 +235,46 @@ namespace EightBit {
|
||||
|
||||
// Flag adjustment
|
||||
|
||||
template<class T> constexpr void adjustZero(const T datum) noexcept { CC() = clearBit(CC(), ZF, datum); }
|
||||
constexpr void adjustZero(const register16_t datum) noexcept { CC() = clearBit(CC(), ZF, datum.word); }
|
||||
constexpr void adjustNegative(const uint8_t datum) noexcept { CC() = setBit(CC(), NF, datum & Bit7); }
|
||||
constexpr void adjustNegative(const register16_t datum) noexcept { adjustNegative(datum.high); }
|
||||
constexpr void adjustNegative(const uint16_t datum) noexcept { adjustNegative(register16_t(datum)); }
|
||||
template<class T> constexpr void adjustZero(const T datum) { CC() = clearBit(CC(), ZF, datum); }
|
||||
constexpr void adjustZero(const register16_t datum) { CC() = clearBit(CC(), ZF, datum.word); }
|
||||
constexpr void adjustNegative(const uint8_t datum) { CC() = setBit(CC(), NF, datum & Bit7); }
|
||||
constexpr void adjustNegative(const register16_t datum) { adjustNegative(datum.high); }
|
||||
constexpr void adjustNegative(const uint16_t datum) { adjustNegative(register16_t(datum)); }
|
||||
|
||||
template<class T> constexpr void adjustNZ(const T datum) noexcept {
|
||||
template<class T> constexpr void adjustNZ(const T datum) {
|
||||
adjustZero(datum);
|
||||
adjustNegative(datum);
|
||||
}
|
||||
|
||||
constexpr void adjustCarry(const uint16_t datum) noexcept { CC() = setBit(CC(), CF, datum & Bit8); } // 8-bit addition
|
||||
constexpr void adjustCarry(const uint32_t datum) noexcept { CC() = setBit(CC(), CF, datum & Bit16); } // 16-bit addition
|
||||
constexpr void adjustCarry(const register16_t datum) noexcept { adjustCarry(datum.word); }
|
||||
constexpr void adjustCarry(const uint16_t datum) { CC() = setBit(CC(), CF, datum & Bit8); } // 8-bit addition
|
||||
constexpr void adjustCarry(const uint32_t datum) { CC() = setBit(CC(), CF, datum & Bit16); } // 16-bit addition
|
||||
constexpr void adjustCarry(const register16_t datum) { adjustCarry(datum.word); }
|
||||
|
||||
constexpr void adjustBorrow(const uint16_t datum) noexcept { CC() = clearBit(CC(), CF, datum & Bit8); } // 8-bit subtraction
|
||||
constexpr void adjustBorrow(const uint32_t datum) noexcept { CC() = clearBit(CC(), CF, datum & Bit16); } // 16-bit subtraction
|
||||
constexpr void adjustBorrow(const register16_t datum) noexcept { adjustBorrow(datum.word); }
|
||||
constexpr void adjustBorrow(const uint16_t datum) { CC() = clearBit(CC(), CF, datum & Bit8); } // 8-bit subtraction
|
||||
constexpr void adjustBorrow(const uint32_t datum) { CC() = clearBit(CC(), CF, datum & Bit16); } // 16-bit subtraction
|
||||
constexpr void adjustBorrow(const register16_t datum) { adjustBorrow(datum.word); }
|
||||
|
||||
constexpr void adjustOverflow(const uint8_t before, const uint8_t data, const register16_t after) noexcept {
|
||||
constexpr void adjustOverflow(const uint8_t before, const uint8_t data, const register16_t after) {
|
||||
const uint8_t lowAfter = after.low;
|
||||
const uint8_t highAfter = after.high;
|
||||
CC() = setBit(CC(), VF, (before ^ data ^ lowAfter ^ (highAfter << 7)) & Bit7);
|
||||
}
|
||||
|
||||
constexpr void adjustOverflow(const uint16_t before, const uint16_t data, const uint32_t after) noexcept {
|
||||
constexpr void adjustOverflow(const uint16_t before, const uint16_t data, const uint32_t after) {
|
||||
const uint16_t lowAfter = after & Mask16;
|
||||
const uint16_t highAfter = after >> 16;
|
||||
CC() = setBit(CC(), VF, (before ^ data ^ lowAfter ^ (highAfter << 15)) & Bit15);
|
||||
}
|
||||
|
||||
constexpr void adjustOverflow(const register16_t before, const register16_t data, const register16_t after) noexcept {
|
||||
constexpr void adjustOverflow(const register16_t before, const register16_t data, const register16_t after) {
|
||||
adjustOverflow(before.word, data.word, after.word);
|
||||
}
|
||||
|
||||
constexpr void adjustHalfCarry(const uint8_t before, const uint8_t data, const uint8_t after) noexcept {
|
||||
constexpr void adjustHalfCarry(const uint8_t before, const uint8_t data, const uint8_t after) {
|
||||
CC() = setBit(CC(), HF, (before ^ data ^ after) & Bit4);
|
||||
}
|
||||
|
||||
constexpr void adjustAddition(const uint8_t before, const uint8_t data, const register16_t after) noexcept {
|
||||
constexpr void adjustAddition(const uint8_t before, const uint8_t data, const register16_t after) {
|
||||
const auto result = after.low;
|
||||
adjustNZ(result);
|
||||
adjustCarry(after);
|
||||
@@ -282,52 +282,52 @@ namespace EightBit {
|
||||
adjustHalfCarry(before, data, result);
|
||||
}
|
||||
|
||||
constexpr void adjustAddition(const uint16_t before, const uint16_t data, const uint32_t after) noexcept {
|
||||
constexpr void adjustAddition(const uint16_t before, const uint16_t data, const uint32_t after) {
|
||||
const register16_t result = after & Mask16;
|
||||
adjustNZ(result);
|
||||
adjustCarry(after);
|
||||
adjustOverflow(before, data, after);
|
||||
}
|
||||
|
||||
constexpr void adjustAddition(const register16_t before, const register16_t data, const uint32_t after) noexcept {
|
||||
constexpr void adjustAddition(const register16_t before, const register16_t data, const uint32_t after) {
|
||||
adjustAddition(before.word, data.word, after);
|
||||
}
|
||||
|
||||
constexpr void adjustSubtraction(const uint8_t before, const uint8_t data, const register16_t after) noexcept {
|
||||
constexpr void adjustSubtraction(const uint8_t before, const uint8_t data, const register16_t after) {
|
||||
const auto result = after.low;
|
||||
adjustNZ(result);
|
||||
adjustCarry(after);
|
||||
adjustOverflow(before, data, after);
|
||||
}
|
||||
|
||||
constexpr void adjustSubtraction(const uint16_t before, const uint16_t data, const uint32_t after) noexcept {
|
||||
constexpr void adjustSubtraction(const uint16_t before, const uint16_t data, const uint32_t after) {
|
||||
const register16_t result = after & Mask16;
|
||||
adjustNZ(result);
|
||||
adjustCarry(after);
|
||||
adjustOverflow(before, data, after);
|
||||
}
|
||||
|
||||
constexpr void adjustSubtraction(const register16_t before, const register16_t data, const uint32_t after) noexcept {
|
||||
constexpr void adjustSubtraction(const register16_t before, const register16_t data, const uint32_t after) {
|
||||
adjustSubtraction(before.word, data.word, after);
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] constexpr auto LS() const noexcept { return carry() || zero(); } // (C OR Z)
|
||||
[[nodiscard]] constexpr auto HI() const noexcept { return !LS(); } // !(C OR Z)
|
||||
[[nodiscard]] constexpr auto LT() const noexcept { return (negative() >> 3) ^ (overflow() >> 1); } // (N XOR V)
|
||||
[[nodiscard]] constexpr auto GE() const noexcept { return !LT(); } // !(N XOR V)
|
||||
[[nodiscard]] constexpr auto LE() const noexcept { return zero() || LT(); } // (Z OR (N XOR V))
|
||||
[[nodiscard]] constexpr auto GT() const noexcept { return !LE(); } // !(Z OR (N XOR V))
|
||||
[[nodiscard]] constexpr auto LS() const { return carry() || zero(); } // (C OR Z)
|
||||
[[nodiscard]] constexpr auto HI() const { return !LS(); } // !(C OR Z)
|
||||
[[nodiscard]] constexpr auto LT() const { return (negative() >> 3) ^ (overflow() >> 1); } // (N XOR V)
|
||||
[[nodiscard]] constexpr auto GE() const { return !LT(); } // !(N XOR V)
|
||||
[[nodiscard]] constexpr auto LE() const { return zero() || LT(); } // (Z OR (N XOR V))
|
||||
[[nodiscard]] constexpr auto GT() const { return !LE(); } // !(Z OR (N XOR V))
|
||||
|
||||
// Branching
|
||||
|
||||
auto branch(const register16_t destination, const bool condition) noexcept {
|
||||
auto branch(const register16_t destination, const bool condition) {
|
||||
if (condition)
|
||||
jump(destination);
|
||||
return condition;
|
||||
}
|
||||
|
||||
void branchShort(const bool condition) noexcept {
|
||||
void branchShort(const bool condition) {
|
||||
branch(Address_relative_byte(), condition);
|
||||
}
|
||||
|
||||
@@ -343,7 +343,7 @@ namespace EightBit {
|
||||
void saveRegisterState();
|
||||
void restoreRegisterState();
|
||||
|
||||
template <class T> constexpr T through(const T data) noexcept {
|
||||
template <class T> constexpr T through(const T data) {
|
||||
CC() = clearBit(CC(), VF);
|
||||
adjustNZ(data);
|
||||
return data;
|
||||
@@ -365,7 +365,7 @@ namespace EightBit {
|
||||
void cwai(uint8_t data);
|
||||
uint8_t da(uint8_t operand);
|
||||
uint8_t dec(uint8_t operand);
|
||||
[[nodiscard]] uint8_t eorr(uint8_t operand, uint8_t data) noexcept;
|
||||
[[nodiscard]] uint8_t eorr(uint8_t operand, uint8_t data);
|
||||
void exg(uint8_t data);
|
||||
uint8_t inc(uint8_t operand);
|
||||
void jsr(register16_t address);
|
||||
|
||||
@@ -710,7 +710,7 @@ std::string EightBit::Disassembly::Address_indexed(std::string mnemomic) {
|
||||
<< wrapIndirect(dump_ByteValue(byte) + "," + r, indirect);
|
||||
break;
|
||||
case 0b1001: // n,R (sixteen-bit)
|
||||
word = getWord(++m_address);
|
||||
word = getShort(++m_address);
|
||||
output
|
||||
<< dump_WordValue(word)
|
||||
<< "\t" << mnemomic << "\t"
|
||||
@@ -729,7 +729,7 @@ std::string EightBit::Disassembly::Address_indexed(std::string mnemomic) {
|
||||
<< wrapIndirect(dump_RelativeValue((int8_t)byte) + ",PCR", indirect);
|
||||
break;
|
||||
case 0b1101: // n,PCR (sixteen-bit)
|
||||
word = getWord(++m_address);
|
||||
word = getShort(++m_address);
|
||||
output
|
||||
<< dump_WordValue(word)
|
||||
<< "\t" << mnemomic << "\t"
|
||||
@@ -737,7 +737,7 @@ std::string EightBit::Disassembly::Address_indexed(std::string mnemomic) {
|
||||
break;
|
||||
case 0b1111: // [n]
|
||||
assert(indirect);
|
||||
word = getWord(++m_address);
|
||||
word = getShort(++m_address);
|
||||
output
|
||||
<< dump_WordValue(word)
|
||||
<< "\t" << mnemomic << "\t"
|
||||
@@ -759,7 +759,7 @@ std::string EightBit::Disassembly::Address_indexed(std::string mnemomic) {
|
||||
|
||||
std::string EightBit::Disassembly::Address_extended(std::string mnemomic) {
|
||||
std::ostringstream output;
|
||||
const auto word = getWord(++m_address);
|
||||
const auto word = getShort(++m_address);
|
||||
output
|
||||
<< dump_WordValue(word)
|
||||
<< "\t" << mnemomic << "\t"
|
||||
@@ -779,7 +779,7 @@ std::string EightBit::Disassembly::Address_relative_byte(std::string mnemomic) {
|
||||
|
||||
std::string EightBit::Disassembly::Address_relative_word(std::string mnemomic) {
|
||||
std::ostringstream output;
|
||||
const auto word = getWord(++m_address);
|
||||
const auto word = getShort(++m_address);
|
||||
output
|
||||
<< dump_WordValue(word)
|
||||
<< "\t" << mnemomic << "\t"
|
||||
@@ -801,7 +801,7 @@ std::string EightBit::Disassembly::AM_immediate_byte(std::string mnemomic) {
|
||||
|
||||
std::string EightBit::Disassembly::AM_immediate_word(std::string mnemomic) {
|
||||
std::ostringstream output;
|
||||
const auto word = getWord(++m_address);
|
||||
const auto word = getShort(++m_address);
|
||||
output
|
||||
<< dump_WordValue(word)
|
||||
<< "\t" << mnemomic << "\t"
|
||||
@@ -882,8 +882,8 @@ uint8_t EightBit::Disassembly::getByte(uint16_t address) {
|
||||
return BUS().peek(address);
|
||||
}
|
||||
|
||||
uint16_t EightBit::Disassembly::getWord(uint16_t address) {
|
||||
return CPU().peekWord(address).word;
|
||||
uint16_t EightBit::Disassembly::getShort(uint16_t address) {
|
||||
return CPU().peekShort(address).word;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
+20
-20
@@ -20,10 +20,10 @@ DEFINE_PIN_LEVEL_CHANGERS(BA, mc6809);
|
||||
DEFINE_PIN_LEVEL_CHANGERS(BS, mc6809);
|
||||
DEFINE_PIN_LEVEL_CHANGERS(RW, mc6809);
|
||||
|
||||
int EightBit::mc6809::step() noexcept {
|
||||
resetCycles();
|
||||
ExecutingInstruction.fire(*this);
|
||||
if (LIKELY(powered())) {
|
||||
void EightBit::mc6809::poweredStep() noexcept {
|
||||
//resetCycles();
|
||||
//ExecutingInstruction.fire(*this);
|
||||
//if (LIKELY(powered())) {
|
||||
m_prefix10 = m_prefix11 = false;
|
||||
if (UNLIKELY(halted()))
|
||||
handleHALT();
|
||||
@@ -37,15 +37,15 @@ int EightBit::mc6809::step() noexcept {
|
||||
handleINT();
|
||||
else
|
||||
BigEndianProcessor::execute(fetchByte());
|
||||
}
|
||||
ExecutedInstruction.fire(*this);
|
||||
assert(cycles() > 0);
|
||||
return cycles();
|
||||
//}
|
||||
//ExecutedInstruction.fire(*this);
|
||||
//assert(cycles() > 0);
|
||||
//return cycles();
|
||||
}
|
||||
|
||||
// Interrupt (etc.) handlers
|
||||
|
||||
void EightBit::mc6809::handleHALT() {
|
||||
void EightBit::mc6809::handleHALT() noexcept {
|
||||
raiseBA();
|
||||
raiseBS();
|
||||
}
|
||||
@@ -62,11 +62,11 @@ void EightBit::mc6809::handleRESET() noexcept {
|
||||
memoryRead();
|
||||
memoryRead();
|
||||
memoryRead();
|
||||
jump(getWord());
|
||||
jump(getShort());
|
||||
eat();
|
||||
}
|
||||
|
||||
void EightBit::mc6809::handleNMI() {
|
||||
void EightBit::mc6809::handleNMI() noexcept {
|
||||
raiseNMI();
|
||||
lowerBA();
|
||||
raiseBS();
|
||||
@@ -95,7 +95,7 @@ void EightBit::mc6809::handleINT() noexcept {
|
||||
eat();
|
||||
}
|
||||
|
||||
void EightBit::mc6809::handleFIRQ() {
|
||||
void EightBit::mc6809::handleFIRQ() noexcept {
|
||||
raiseFIRQ();
|
||||
lowerBA();
|
||||
raiseBS();
|
||||
@@ -635,11 +635,11 @@ uint8_t EightBit::mc6809::pop() noexcept {
|
||||
return popS();
|
||||
}
|
||||
|
||||
void EightBit::mc6809::push(register16_t& stack, const uint8_t value) {
|
||||
void EightBit::mc6809::push(register16_t& stack, const uint8_t value) noexcept {
|
||||
memoryWrite(--stack, value);
|
||||
}
|
||||
|
||||
uint8_t EightBit::mc6809::pop(register16_t& stack) {
|
||||
uint8_t EightBit::mc6809::pop(register16_t& stack) noexcept {
|
||||
return memoryRead(stack++);
|
||||
}
|
||||
|
||||
@@ -757,7 +757,7 @@ EightBit::register16_t EightBit::mc6809::Address_indexed() {
|
||||
UNREACHABLE;
|
||||
}
|
||||
if (indirect) {
|
||||
address = Processor::getWord(address);
|
||||
address = Processor::getShort(address);
|
||||
eat();
|
||||
}
|
||||
} else {
|
||||
@@ -800,15 +800,15 @@ EightBit::register16_t EightBit::mc6809::AM_immediate_word() {
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::mc6809::AM_direct_word() {
|
||||
return Processor::getWord(Address_direct());
|
||||
return Processor::getShort(Address_direct());
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::mc6809::AM_indexed_word() {
|
||||
return Processor::getWord(Address_indexed());
|
||||
return Processor::getShort(Address_indexed());
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::mc6809::AM_extended_word() {
|
||||
return Processor::getWord(Address_extended());
|
||||
return Processor::getShort(Address_extended());
|
||||
}
|
||||
|
||||
//
|
||||
@@ -922,11 +922,11 @@ uint8_t EightBit::mc6809::dec(const uint8_t operand) {
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t EightBit::mc6809::eorr(const uint8_t operand, const uint8_t data) noexcept {
|
||||
uint8_t EightBit::mc6809::eorr(const uint8_t operand, const uint8_t data) {
|
||||
return through((uint8_t)(operand ^ data));
|
||||
}
|
||||
|
||||
uint8_t& EightBit::mc6809::referenceTransfer8(const int specifier) noexcept {
|
||||
uint8_t& EightBit::mc6809::referenceTransfer8(const int specifier) {
|
||||
switch (specifier) {
|
||||
case 0b1000:
|
||||
return A();
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
Board::Board(const Configuration& configuration)
|
||||
: m_configuration(configuration) {}
|
||||
|
||||
void Board::raisePOWER() noexcept {
|
||||
void Board::raisePOWER() {
|
||||
|
||||
EightBit::Bus::raisePOWER();
|
||||
|
||||
@@ -26,7 +26,7 @@ void Board::raisePOWER() noexcept {
|
||||
accessAcia();
|
||||
}
|
||||
|
||||
void Board::lowerPOWER() noexcept {
|
||||
void Board::lowerPOWER() {
|
||||
|
||||
if (m_configuration.isProfileMode()) {
|
||||
m_profiler.EmitLine.connect([this](EightBit::ProfileLineEventArgs line) {
|
||||
@@ -111,7 +111,7 @@ void Board::initialise() {
|
||||
}
|
||||
}
|
||||
|
||||
EightBit::MemoryMapping Board::mapping(uint16_t address) noexcept {
|
||||
EightBit::MemoryMapping Board::mapping(uint16_t address) {
|
||||
|
||||
if (address < 0x8000)
|
||||
return { m_ram, 0x0000, EightBit::Chip::Mask16, EightBit::MemoryMapping::AccessLevel::ReadWrite };
|
||||
|
||||
+3
-3
@@ -20,13 +20,13 @@ public:
|
||||
auto& CPU() { return m_cpu; }
|
||||
auto& ACIA() { return m_acia; }
|
||||
|
||||
void raisePOWER() noexcept final;
|
||||
void lowerPOWER() noexcept final;
|
||||
void raisePOWER() final;
|
||||
void lowerPOWER() final;
|
||||
|
||||
virtual void initialise() final;
|
||||
|
||||
protected:
|
||||
EightBit::MemoryMapping mapping(uint16_t address) noexcept final;
|
||||
EightBit::MemoryMapping mapping(uint16_t address) final;
|
||||
|
||||
private:
|
||||
const Configuration& m_configuration;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
Board::Board() {}
|
||||
|
||||
void Board::raisePOWER() noexcept {
|
||||
void Board::raisePOWER() {
|
||||
EightBit::Bus::raisePOWER();
|
||||
|
||||
CPU().raisePOWER();
|
||||
@@ -16,7 +16,7 @@ void Board::raisePOWER() noexcept {
|
||||
CPU().raiseHALT();
|
||||
}
|
||||
|
||||
void Board::lowerPOWER() noexcept {
|
||||
void Board::lowerPOWER() {
|
||||
CPU().lowerPOWER();
|
||||
EightBit::Bus::lowerPOWER();
|
||||
}
|
||||
@@ -33,6 +33,6 @@ void Board::initialise() {
|
||||
});
|
||||
}
|
||||
|
||||
EightBit::MemoryMapping Board::mapping(uint16_t) noexcept {
|
||||
EightBit::MemoryMapping Board::mapping(uint16_t) {
|
||||
return { m_ram, 0x0000, 0xffff, EightBit::MemoryMapping::AccessLevel::ReadWrite };
|
||||
}
|
||||
@@ -9,15 +9,15 @@ class Board final : public EightBit::Bus {
|
||||
public:
|
||||
Board();
|
||||
|
||||
constexpr EightBit::mc6809& CPU() noexcept { return m_cpu; }
|
||||
constexpr EightBit::mc6809& CPU() { return m_cpu; }
|
||||
|
||||
void raisePOWER() noexcept final;
|
||||
void lowerPOWER() noexcept final;
|
||||
void raisePOWER() final;
|
||||
void lowerPOWER() final;
|
||||
|
||||
protected:
|
||||
void initialise() final;
|
||||
|
||||
EightBit::MemoryMapping mapping(uint16_t address) noexcept final;
|
||||
EightBit::MemoryMapping mapping(uint16_t address) final;
|
||||
|
||||
private:
|
||||
EightBit::Ram m_ram = 0x10000; // 0000 - FFFF, 64K RAM
|
||||
|
||||
@@ -998,7 +998,7 @@ TEST_CASE("Subroutines", "[JSR][RTS]") {
|
||||
SECTION("JSR") {
|
||||
|
||||
// Set up a word to test at address 0x205
|
||||
cpu.pokeWord(0x205, 0x03ff);
|
||||
cpu.pokeShort(0x205, 0x03ff);
|
||||
|
||||
// Set register D
|
||||
cpu.D() = 0x105;
|
||||
@@ -1044,7 +1044,7 @@ TEST_CASE("Subroutines", "[JSR][RTS]") {
|
||||
|
||||
cpu.S().word = 0x300;
|
||||
|
||||
cpu.pokeWord(0x300, 0x102C); // Write return address
|
||||
cpu.pokeShort(0x300, 0x102C); // Write return address
|
||||
board.poke(0xB00, 0x39); // RTS
|
||||
|
||||
cpu.PC().word = 0xB00;
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace EightBit {
|
||||
virtual ~Ricoh2A03() = default;
|
||||
|
||||
protected:
|
||||
uint8_t sub(uint8_t operand, int borrow) noexcept final;
|
||||
void adc() noexcept final;
|
||||
uint8_t sub(uint8_t operand, int borrow) final;
|
||||
void adc() final;
|
||||
};
|
||||
}
|
||||
@@ -5,10 +5,10 @@ EightBit::Ricoh2A03::Ricoh2A03(Bus& bus)
|
||||
: MOS6502(bus) {
|
||||
}
|
||||
|
||||
uint8_t EightBit::Ricoh2A03::sub(uint8_t operand, int borrow) noexcept {
|
||||
uint8_t EightBit::Ricoh2A03::sub(uint8_t operand, int borrow) {
|
||||
return MOS6502::sub_b(operand, borrow);
|
||||
}
|
||||
|
||||
void EightBit::Ricoh2A03::adc() noexcept {
|
||||
void EightBit::Ricoh2A03::adc() {
|
||||
MOS6502::adc_b();
|
||||
}
|
||||
@@ -49,7 +49,7 @@ void Fuse::TestRunner::addActualEvent(const std::string& specifier) {
|
||||
|
||||
//
|
||||
|
||||
void Fuse::TestRunner::raisePOWER() noexcept {
|
||||
void Fuse::TestRunner::raisePOWER() {
|
||||
EightBit::Bus::raisePOWER();
|
||||
m_cpu.raisePOWER();
|
||||
m_cpu.raiseRESET();
|
||||
@@ -58,12 +58,12 @@ void Fuse::TestRunner::raisePOWER() noexcept {
|
||||
m_test.transferRegisters(m_cpu);
|
||||
}
|
||||
|
||||
void Fuse::TestRunner::lowerPOWER() noexcept {
|
||||
void Fuse::TestRunner::lowerPOWER() {
|
||||
m_cpu.lowerPOWER();
|
||||
EightBit::Bus::lowerPOWER();
|
||||
}
|
||||
|
||||
EightBit::MemoryMapping Fuse::TestRunner::mapping(uint16_t address) noexcept {
|
||||
EightBit::MemoryMapping Fuse::TestRunner::mapping(uint16_t address) {
|
||||
return {
|
||||
m_ram,
|
||||
0x0000,
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Fuse {
|
||||
void dumpActualEvents() const;
|
||||
|
||||
protected:
|
||||
virtual EightBit::MemoryMapping mapping(uint16_t address) noexcept final;
|
||||
virtual EightBit::MemoryMapping mapping(uint16_t address) final;
|
||||
|
||||
public:
|
||||
TestRunner(const Test& test, const ExpectedTestResult& expected);
|
||||
@@ -51,8 +51,8 @@ namespace Fuse {
|
||||
bool failed() const { return m_failed; }
|
||||
bool unimplemented() const { return m_unimplemented; }
|
||||
|
||||
void raisePOWER() noexcept final;
|
||||
void lowerPOWER() noexcept final;
|
||||
void raisePOWER() final;
|
||||
void lowerPOWER() final;
|
||||
|
||||
void initialise() final;
|
||||
};
|
||||
|
||||
+9
-3
@@ -168,7 +168,7 @@ namespace EightBit {
|
||||
|
||||
[[nodiscard]] constexpr void displaceAddress() noexcept {
|
||||
const auto& index_register = m_prefixDD ? IX() : IY();
|
||||
BUS().ADDRESS() = MEMPTR() = index_register.word + m_displacement;
|
||||
BUS().ADDRESS() = MEMPTR() = index_register.joined + m_displacement;
|
||||
}
|
||||
|
||||
void fetchDisplacement() noexcept;
|
||||
@@ -177,8 +177,8 @@ namespace EightBit {
|
||||
uint8_t readDataUnderInterrupt() noexcept;
|
||||
|
||||
typedef std::function<register16_t(void)> addresser_t;
|
||||
void loadAccumulatorIndirect(addresser_t addresser) noexcept;
|
||||
void storeAccumulatorIndirect(addresser_t addresser) noexcept;
|
||||
//void loadAccumulatorIndirect(addresser_t addresser) noexcept;
|
||||
//void storeAccumulatorIndirect(addresser_t addresser) noexcept;
|
||||
|
||||
typedef std::function<uint8_t(void)> reader_t;
|
||||
void readInternalRegister(reader_t reader) noexcept;
|
||||
@@ -420,5 +420,11 @@ namespace EightBit {
|
||||
void readPort(register16_t port) noexcept;
|
||||
void readPort(uint8_t port) noexcept;
|
||||
void readPort() noexcept;
|
||||
|
||||
void loadImmediate(int y);
|
||||
void popRegisterPair(int p);
|
||||
void pushRegisterPair(int p);
|
||||
|
||||
void prefixCB();
|
||||
};
|
||||
}
|
||||
@@ -165,7 +165,7 @@ std::string EightBit::Disassembler::alu(int which) {
|
||||
}
|
||||
|
||||
std::string EightBit::Disassembler::disassemble(Z80& cpu) {
|
||||
return disassemble(cpu, cpu.PC().word);
|
||||
return disassemble(cpu, cpu.PC().joined);
|
||||
}
|
||||
|
||||
std::string EightBit::Disassembler::disassemble(Z80& cpu, uint16_t address) {
|
||||
@@ -189,7 +189,7 @@ void EightBit::Disassembler::disassemble(std::ostringstream& output, Z80& cpu, u
|
||||
auto q = decoded.q;
|
||||
|
||||
auto immediate = BUS().peek(pc + 1);
|
||||
auto absolute = cpu.peekWord(pc + 1).word;
|
||||
auto absolute = cpu.peekShort(pc + 1).joined;
|
||||
auto displacement = (int8_t)immediate;
|
||||
auto relative = pc + displacement + 2;
|
||||
auto indexedImmediate = BUS().peek(pc + 1);
|
||||
|
||||
@@ -43,7 +43,7 @@ void EightBit::Profiler::dumpAddressProfiles() const {
|
||||
for (int i = 0; i < 0x10000; ++i) {
|
||||
auto count = m_addresses[i];
|
||||
|
||||
m_cpu.PC().word = i;
|
||||
m_cpu.PC().joined = i;
|
||||
|
||||
if (count > 0)
|
||||
std::cout
|
||||
|
||||
+90
-58
@@ -25,7 +25,7 @@ EightBit::Z80::Z80(Bus& bus, InputOutput& ports) noexcept
|
||||
exx();
|
||||
|
||||
IX() = IY() = Mask16;
|
||||
resetWorkingRegisters();
|
||||
resetRegisterSet();
|
||||
});
|
||||
|
||||
RaisedM1.connect([this](EventArgs) {
|
||||
@@ -186,7 +186,7 @@ void EightBit::Z80::handleRESET() noexcept {
|
||||
IM() = 0;
|
||||
IV() = 0;
|
||||
REFRESH() = 0;
|
||||
SP().word = AF().word = Mask16;
|
||||
SP().joined = AF().joined = Mask16;
|
||||
}
|
||||
|
||||
void EightBit::Z80::handleNMI() noexcept {
|
||||
@@ -218,9 +218,8 @@ void EightBit::Z80::handleINT() noexcept {
|
||||
|
||||
IntelProcessor::handleINT();
|
||||
|
||||
tick();
|
||||
|
||||
const auto data = readDataUnderInterrupt();
|
||||
tick();
|
||||
assert(cycles() == 6);
|
||||
|
||||
switch (IM()) {
|
||||
@@ -232,8 +231,8 @@ void EightBit::Z80::handleINT() noexcept {
|
||||
assert(cycles() == 13);
|
||||
break;
|
||||
case 2:
|
||||
MEMPTR() = Processor::getWordPaged(IV(), data);
|
||||
call(MEMPTR());
|
||||
Processor::getPagedInto(IV(), data, MEMPTR());
|
||||
IntelProcessor::call();
|
||||
assert(cycles() == 19);
|
||||
break;
|
||||
default:
|
||||
@@ -366,7 +365,7 @@ void EightBit::Z80::sbc(const register16_t value) noexcept {
|
||||
|
||||
const auto operand = HL2();
|
||||
|
||||
const auto subtraction = operand.word - value.word - carry();
|
||||
const auto subtraction = operand.joined - value.joined - carry();
|
||||
intermediate() = subtraction;
|
||||
|
||||
setBit(NF);
|
||||
@@ -406,7 +405,7 @@ void EightBit::Z80::add(const register16_t value, int carry) noexcept {
|
||||
|
||||
const auto operand = HL2();
|
||||
|
||||
const auto addition = operand.word + value.word + carry;
|
||||
const auto addition = operand.joined + value.joined + carry;
|
||||
intermediate() = addition;
|
||||
|
||||
clearBit(NF);
|
||||
@@ -597,7 +596,7 @@ void EightBit::Z80::blockCompare() noexcept {
|
||||
IntelProcessor::memoryRead(HL());
|
||||
uint8_t result = A() - BUS().DATA();
|
||||
|
||||
setBit(PF, --BC().word);
|
||||
setBit(PF, --BC().joined);
|
||||
|
||||
adjustSZ(result);
|
||||
adjustHalfCarrySub(A(), BUS().DATA(), result);
|
||||
@@ -637,7 +636,7 @@ void EightBit::Z80::cpdr() noexcept {
|
||||
repeatBlockInstruction();
|
||||
tick(5);
|
||||
} else {
|
||||
MEMPTR() = PC().word - 2;
|
||||
MEMPTR() = PC().joined - 2;
|
||||
tick(2);
|
||||
}
|
||||
}
|
||||
@@ -649,7 +648,7 @@ void EightBit::Z80::blockLoad() noexcept {
|
||||
setBit(XF, xy & Bit3);
|
||||
setBit(YF, xy & Bit1);
|
||||
clearBit(NF | HC);
|
||||
setBit(PF, --BC().word);
|
||||
setBit(PF, --BC().joined);
|
||||
tick(2);
|
||||
}
|
||||
|
||||
@@ -867,7 +866,8 @@ void EightBit::Z80::readPort() noexcept {
|
||||
//
|
||||
|
||||
void EightBit::Z80::fetchDisplacement() noexcept {
|
||||
m_displacement = fetchByte();
|
||||
fetchByte();
|
||||
m_displacement = BUS().DATA();
|
||||
}
|
||||
|
||||
//
|
||||
@@ -906,18 +906,18 @@ uint8_t EightBit::Z80::fetchInstruction() noexcept {
|
||||
return data;
|
||||
}
|
||||
|
||||
void EightBit::Z80::loadAccumulatorIndirect(addresser_t addresser) noexcept {
|
||||
MEMPTR() = BUS().ADDRESS() = addresser();
|
||||
++MEMPTR();
|
||||
A() = memoryRead();
|
||||
}
|
||||
|
||||
void EightBit::Z80::storeAccumulatorIndirect(addresser_t addresser) noexcept {
|
||||
MEMPTR() = BUS().ADDRESS() = addresser();
|
||||
++MEMPTR();
|
||||
MEMPTR().high = BUS().DATA() = A();
|
||||
memoryWrite();
|
||||
}
|
||||
//void EightBit::Z80::loadAccumulatorIndirect(addresser_t addresser) noexcept {
|
||||
// MEMPTR() = BUS().ADDRESS() = addresser();
|
||||
// ++MEMPTR();
|
||||
// A() = memoryRead();
|
||||
//}
|
||||
//
|
||||
//void EightBit::Z80::storeAccumulatorIndirect(addresser_t addresser) noexcept {
|
||||
// MEMPTR() = BUS().ADDRESS() = addresser();
|
||||
// ++MEMPTR();
|
||||
// MEMPTR().high = BUS().DATA() = A();
|
||||
// memoryWrite();
|
||||
//}
|
||||
|
||||
void EightBit::Z80::readInternalRegister(reader_t reader) noexcept {
|
||||
adjustSZXY(A() = reader());
|
||||
@@ -1192,13 +1192,14 @@ void EightBit::Z80::executeED(const int x, const int y, const int z, const int p
|
||||
}
|
||||
break;
|
||||
case 3: // Retrieve/store register pair from/to immediate address
|
||||
BUS().ADDRESS() = fetchWord();
|
||||
fetchShortAddress();
|
||||
switch (q) {
|
||||
case 0: // LD (nn), rp[p]
|
||||
setWord(RP(p));
|
||||
setShort(RP(p));
|
||||
break;
|
||||
case 1: // LD rp[p], (nn)
|
||||
RP(p) = getWord();
|
||||
getShort();
|
||||
RP(p) = intermediate();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
@@ -1359,7 +1360,8 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
jumpRelativeConditional(--B());
|
||||
break;
|
||||
case 3: // JR d
|
||||
jumpRelative(fetchByte());
|
||||
fetchByte();
|
||||
jumpRelative(BUS().DATA());
|
||||
break;
|
||||
case 4: // JR cc,d
|
||||
case 5:
|
||||
@@ -1374,7 +1376,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
case 1: // 16-bit load immediate/add
|
||||
switch (q) {
|
||||
case 0: // LD rp,nn
|
||||
RP(p) = fetchWord();
|
||||
fetchInto(RP(p));
|
||||
break;
|
||||
case 1: // ADD HL,rp
|
||||
add(RP(p));
|
||||
@@ -1388,17 +1390,18 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
case 0:
|
||||
switch (p) {
|
||||
case 0: // LD (BC),A
|
||||
storeAccumulatorIndirect([this]() { return BC(); });
|
||||
writeMemoryIndirect(BC(), A());
|
||||
break;
|
||||
case 1: // LD (DE),A
|
||||
storeAccumulatorIndirect([this]() { return DE(); });
|
||||
writeMemoryIndirect(DE(), A());
|
||||
break;
|
||||
case 2: // LD (nn),HL
|
||||
BUS().ADDRESS() = fetchWord();
|
||||
setWord(HL2());
|
||||
fetchShortAddress();
|
||||
setShort(HL2());
|
||||
break;
|
||||
case 3: // LD (nn),A
|
||||
storeAccumulatorIndirect([this]() { return fetchWord(); });
|
||||
fetchInto(MEMPTR());
|
||||
writeMemoryIndirect(A());
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
@@ -1407,17 +1410,23 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
case 1:
|
||||
switch (p) {
|
||||
case 0: // LD A,(BC)
|
||||
loadAccumulatorIndirect([this]() { return BC(); });
|
||||
readMemoryIndirect(BC());
|
||||
A() = BUS().DATA();
|
||||
break;
|
||||
case 1: // LD A,(DE)
|
||||
loadAccumulatorIndirect([this]() { return DE(); });
|
||||
readMemoryIndirect(DE());
|
||||
A() = BUS().DATA();
|
||||
break;
|
||||
case 2: // LD HL,(nn)
|
||||
BUS().ADDRESS() = fetchWord();
|
||||
HL2() = getWord();
|
||||
|
||||
fetchShortAddress();
|
||||
getShort();
|
||||
HL2() = intermediate();
|
||||
break;
|
||||
case 3: // LD A,(nn)
|
||||
loadAccumulatorIndirect([this]() { return fetchWord(); });
|
||||
fetchInto(MEMPTR());
|
||||
readMemoryIndirect();
|
||||
A() = BUS().DATA();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
@@ -1459,12 +1468,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
break;
|
||||
}
|
||||
case 6: { // 8-bit load immediate
|
||||
if (memoryY && displaced())
|
||||
fetchDisplacement();
|
||||
const auto value = fetchByte();
|
||||
if (memoryY)
|
||||
tick(2);
|
||||
R(y, value); // LD r,n
|
||||
loadImmediate(y);
|
||||
break;
|
||||
}
|
||||
case 7: // Assorted operations on accumulator/flags
|
||||
@@ -1584,7 +1588,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
case 1: // POP & various ops
|
||||
switch (q) {
|
||||
case 0: // POP rp2[p]
|
||||
RP2(p) = popWord();
|
||||
popRegisterPair(p);
|
||||
break;
|
||||
case 1:
|
||||
switch (p) {
|
||||
@@ -1618,19 +1622,15 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
jumpIndirect();
|
||||
break;
|
||||
case 1: // CB prefix
|
||||
m_prefixCB = true;
|
||||
if (displaced()) {
|
||||
fetchDisplacement();
|
||||
IntelProcessor::execute(fetchByte());
|
||||
} else {
|
||||
IntelProcessor::execute(fetchInstruction());
|
||||
}
|
||||
prefixCB();
|
||||
break;
|
||||
case 2: // OUT (n),A
|
||||
writePort(fetchByte());
|
||||
fetchByte();
|
||||
writePort(BUS().DATA());
|
||||
break;
|
||||
case 3: // IN A,(n)
|
||||
readPort(fetchByte());
|
||||
fetchByte();
|
||||
readPort(BUS().DATA());
|
||||
A() = BUS().DATA();
|
||||
break;
|
||||
case 4: // EX (SP),HL
|
||||
@@ -1655,8 +1655,9 @@ 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));
|
||||
//tick();
|
||||
//pushWord(RP2(p));
|
||||
pushRegisterPair(p);
|
||||
break;
|
||||
case 1:
|
||||
switch (p) {
|
||||
@@ -1684,7 +1685,8 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
}
|
||||
break;
|
||||
case 6: { // Operate on accumulator and immediate operand: alu[y] n
|
||||
const auto operand = fetchByte();
|
||||
fetchByte();
|
||||
auto operand = BUS().DATA();
|
||||
switch (y) {
|
||||
case 0: // ADD A,n
|
||||
add(operand);
|
||||
@@ -1724,3 +1726,33 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void EightBit::Z80::loadImmediate(int y) {
|
||||
auto memoryY = y == 6;
|
||||
if (memoryY && displaced())
|
||||
fetchDisplacement();
|
||||
fetchByte(); // LD r,n
|
||||
if (memoryY)
|
||||
tick(2);
|
||||
R(y, BUS().DATA());
|
||||
}
|
||||
|
||||
void EightBit::Z80::popRegisterPair(int p) {
|
||||
popInto(RP2(p));
|
||||
}
|
||||
|
||||
void EightBit::Z80::pushRegisterPair(int p) {
|
||||
tick();
|
||||
pushShort(RP2(p));
|
||||
}
|
||||
|
||||
void EightBit::Z80::prefixCB() {
|
||||
m_prefixCB = true;
|
||||
if (displaced()) {
|
||||
fetchDisplacement();
|
||||
fetchByte();
|
||||
Processor::execute(BUS().DATA());
|
||||
} else {
|
||||
Processor::execute(fetchInstruction());
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -27,7 +27,7 @@ void Board::initialise() noexcept {
|
||||
});
|
||||
|
||||
m_cpu.ExecutingInstruction.connect([this] (EightBit::EventArgs) {
|
||||
switch (m_cpu.PC().word) {
|
||||
switch (m_cpu.PC().joined) {
|
||||
case 0x0: // CP/M warm start
|
||||
if (++m_warmstartCount == 2) {
|
||||
lowerPOWER();
|
||||
@@ -46,7 +46,7 @@ void Board::initialise() noexcept {
|
||||
if (m_configuration.isProfileMode())
|
||||
m_cpu.ExecutingInstruction.connect([this] (EightBit::EventArgs) {
|
||||
const auto pc = m_cpu.PC();
|
||||
m_profiler.addAddress(pc.word);
|
||||
m_profiler.addAddress(pc.joined);
|
||||
m_profiler.addInstruction(peek(pc));
|
||||
});
|
||||
|
||||
@@ -60,7 +60,7 @@ void Board::initialise() noexcept {
|
||||
});
|
||||
|
||||
poke(0, 0xc3); // JMP
|
||||
CPU().pokeWord(1, m_configuration.getStartAddress());
|
||||
CPU().pokeShort(1, m_configuration.getStartAddress());
|
||||
poke(5, 0xc9); // ret
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ void Board::bdos() {
|
||||
std::cout << CPU().E();
|
||||
break;
|
||||
case 0x9:
|
||||
for (uint16_t i = CPU().DE().word; peek(i) != '$'; ++i)
|
||||
for (uint16_t i = CPU().DE().joined; peek(i) != '$'; ++i)
|
||||
std::cout << peek(i);
|
||||
break;
|
||||
}
|
||||
|
||||
+10
-10
@@ -11,21 +11,21 @@ namespace EightBit {
|
||||
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;
|
||||
[[nodiscard]] register16_t peekShort(uint16_t address) noexcept final;
|
||||
void pokeShort(uint16_t address, register16_t value) noexcept final;
|
||||
|
||||
protected:
|
||||
BigEndianProcessor(Bus& memory) noexcept;
|
||||
|
||||
[[nodiscard]] register16_t getWord() noexcept override;
|
||||
void setWord(register16_t value) noexcept override;
|
||||
void getInto(register16_t& into) noexcept override;
|
||||
void setShort(register16_t value) noexcept override;
|
||||
|
||||
void getPagedInto(register16_t& into) noexcept override;
|
||||
void setPaged(register16_t value) noexcept override;
|
||||
|
||||
[[nodiscard]] register16_t getWordPaged() noexcept override;
|
||||
void setWordPaged(register16_t value) noexcept override;
|
||||
void fetchInto(register16_t& into) noexcept override;
|
||||
|
||||
[[nodiscard]] register16_t fetchWord() noexcept override;
|
||||
|
||||
void pushWord(register16_t value) noexcept override;
|
||||
[[nodiscard]] register16_t popWord() noexcept override;
|
||||
void pushShort(register16_t value) noexcept override;
|
||||
void popInto(register16_t& into) noexcept override;
|
||||
};
|
||||
}
|
||||
@@ -27,11 +27,11 @@ namespace EightBit {
|
||||
[[nodiscard]] constexpr auto& DATA() noexcept { return m_data; }
|
||||
|
||||
[[nodiscard]] uint8_t peek(const uint16_t address) noexcept { return reference(address); }
|
||||
[[nodiscard]] auto peek(const register16_t address) noexcept { return peek(address.word); }
|
||||
[[nodiscard]] auto peek(const register16_t address) noexcept { return peek(address.joined); }
|
||||
|
||||
void poke(const uint8_t value) noexcept { reference() = 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); }
|
||||
void poke(const register16_t address, const uint8_t value) noexcept { poke(address.joined, value); }
|
||||
|
||||
[[nodiscard]] uint8_t read() noexcept;
|
||||
void write() noexcept;
|
||||
@@ -43,7 +43,7 @@ namespace EightBit {
|
||||
|
||||
protected:
|
||||
[[nodiscard]] uint8_t& reference(uint16_t address) noexcept;
|
||||
[[nodiscard]] uint8_t& reference() noexcept { return reference(ADDRESS().word); }
|
||||
[[nodiscard]] uint8_t& reference() noexcept { return reference(ADDRESS().joined); }
|
||||
|
||||
void loadHexFile(const std::string& path);
|
||||
|
||||
|
||||
+17
-7
@@ -132,7 +132,7 @@ namespace EightBit {
|
||||
void handleINT() noexcept override;
|
||||
|
||||
void push(uint8_t value) noexcept final;
|
||||
[[nodiscard]] uint8_t pop() noexcept final;
|
||||
void pop() noexcept final;
|
||||
|
||||
//
|
||||
|
||||
@@ -141,26 +141,25 @@ namespace EightBit {
|
||||
|
||||
//
|
||||
|
||||
[[nodiscard]] register16_t getWord() noexcept final;
|
||||
void setWord(register16_t value) noexcept final;
|
||||
void getShort() noexcept final;
|
||||
void setShort(register16_t value) noexcept final;
|
||||
|
||||
//
|
||||
|
||||
void restart(uint8_t address) noexcept;
|
||||
void callConditional(bool condition) noexcept;
|
||||
virtual void jumpConditional(bool condition) noexcept;
|
||||
void jumpRelativeConditional(bool condition) noexcept;
|
||||
virtual void jumpRelativeConditional(bool condition) noexcept;
|
||||
virtual void returnConditional(bool condition) noexcept;
|
||||
void jumpIndirect() noexcept;
|
||||
virtual 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(static_cast<int8_t>(offset)); }
|
||||
void ret() noexcept override;
|
||||
|
||||
void resetWorkingRegisters() noexcept;
|
||||
void resetRegisterSet() noexcept;
|
||||
|
||||
[[nodiscard]] virtual bool convertCondition(int flag) noexcept = 0;
|
||||
|
||||
@@ -171,6 +170,17 @@ namespace EightBit {
|
||||
|
||||
virtual void cpl() noexcept;
|
||||
|
||||
void readMemoryIndirect(register16_t via) noexcept;
|
||||
void readMemoryIndirect() noexcept;
|
||||
|
||||
void writeMemoryIndirect(register16_t via, uint8_t data) noexcept;
|
||||
void writeMemoryIndirect(uint8_t data) noexcept;
|
||||
|
||||
virtual void memoryUpdate(int ticks) noexcept = 0;
|
||||
|
||||
virtual uint8_t& R(int r, MemoryMapping::AccessLevel access) noexcept = 0;
|
||||
void R(int r, uint8_t value, int ticks = 1) noexcept;
|
||||
|
||||
private:
|
||||
static std::array<int, 8> m_halfCarryTableAdd;
|
||||
static std::array<int, 8> m_halfCarryTableSub;
|
||||
|
||||
@@ -11,21 +11,21 @@ namespace EightBit {
|
||||
virtual ~LittleEndianProcessor() noexcept = default;
|
||||
LittleEndianProcessor(const LittleEndianProcessor& rhs) noexcept;
|
||||
|
||||
[[nodiscard]] register16_t peekWord(register16_t address) noexcept final;
|
||||
void pokeWord(register16_t address, register16_t value) noexcept final;
|
||||
[[nodiscard]] register16_t peekShort(uint16_t address) noexcept final;
|
||||
void pokeShort(uint16_t address, register16_t value) noexcept final;
|
||||
|
||||
protected:
|
||||
LittleEndianProcessor(Bus& memory) noexcept;
|
||||
|
||||
[[nodiscard]] register16_t getWord() noexcept override;
|
||||
void setWord(register16_t value) noexcept override;
|
||||
void getInto(register16_t& into) noexcept override;
|
||||
void setShort(register16_t value) noexcept override;
|
||||
|
||||
[[nodiscard]] register16_t getWordPaged() noexcept override;
|
||||
void setWordPaged(register16_t value) noexcept override;
|
||||
void getPagedInto(register16_t& into) noexcept override;
|
||||
void setPaged(register16_t value) noexcept override;
|
||||
|
||||
[[nodiscard]] register16_t fetchWord() noexcept override;
|
||||
void fetchInto(register16_t& into) noexcept override;
|
||||
|
||||
void pushWord(register16_t value) noexcept override;
|
||||
[[nodiscard]] register16_t popWord() noexcept override;
|
||||
void pushShort(register16_t value) noexcept override;
|
||||
void popInto(register16_t& into) noexcept override;
|
||||
};
|
||||
}
|
||||
+22
-18
@@ -45,8 +45,8 @@ namespace EightBit {
|
||||
virtual void execute() noexcept = 0;
|
||||
void execute(uint8_t value) noexcept;
|
||||
|
||||
[[nodiscard]] virtual register16_t peekWord(register16_t address) noexcept = 0;
|
||||
virtual void pokeWord(register16_t address, register16_t value) noexcept = 0;
|
||||
[[nodiscard]] virtual register16_t peekShort(uint16_t address) noexcept = 0;
|
||||
virtual void pokeShort(uint16_t address, register16_t value) noexcept = 0;
|
||||
|
||||
DECLARE_PIN_INPUT(RESET)
|
||||
DECLARE_PIN_INPUT(INT)
|
||||
@@ -71,33 +71,37 @@ namespace EightBit {
|
||||
virtual uint8_t busRead() noexcept;
|
||||
|
||||
virtual register16_t& incrementPC() noexcept;
|
||||
virtual register16_t& decrementPC() noexcept;
|
||||
|
||||
virtual void immediateAddress() noexcept;
|
||||
|
||||
uint8_t fetchByte() noexcept;
|
||||
void fetchByte() noexcept;
|
||||
virtual uint8_t fetchInstruction() noexcept;
|
||||
|
||||
[[nodiscard]] virtual register16_t getWord() noexcept = 0;
|
||||
virtual void setWord(register16_t value) noexcept = 0;
|
||||
virtual void getInto(register16_t& into) noexcept = 0;
|
||||
virtual void getShort() noexcept { getInto(m_intermediate); }
|
||||
virtual void setShort(register16_t value) noexcept = 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;
|
||||
void getShortPaged(register16_t address) noexcept;
|
||||
void getShortPaged(uint8_t page, uint8_t offset) noexcept;
|
||||
void getPagedInto(uint8_t page, uint8_t offset, register16_t& into);
|
||||
void getShortPaged() noexcept { getPagedInto(m_intermediate); }
|
||||
virtual void getPagedInto(register16_t& into) noexcept = 0;
|
||||
void setPaged(register16_t address, register16_t value) noexcept;
|
||||
void setPaged(uint8_t page, uint8_t offset, register16_t value) noexcept;
|
||||
virtual void setPaged(register16_t value) noexcept = 0;
|
||||
|
||||
[[nodiscard]] virtual register16_t fetchWord() noexcept = 0;
|
||||
virtual void fetchInto(register16_t& into) noexcept = 0;
|
||||
void fetchShort() noexcept { fetchInto(m_intermediate); }
|
||||
void fetchShortAddress() noexcept;
|
||||
|
||||
virtual void push(uint8_t value) noexcept = 0;
|
||||
[[nodiscard]] virtual uint8_t pop() noexcept = 0;
|
||||
virtual void pop() noexcept = 0;
|
||||
|
||||
virtual void pushWord(register16_t value) noexcept = 0;
|
||||
[[nodiscard]] virtual register16_t popWord() noexcept = 0;
|
||||
virtual void pushShort(register16_t value) noexcept = 0;
|
||||
virtual void popInto(register16_t& into) noexcept = 0;
|
||||
|
||||
[[nodiscard]] register16_t getWord(register16_t address) noexcept;
|
||||
void setWord(register16_t address, register16_t value) noexcept;
|
||||
void getShort(register16_t address) noexcept;
|
||||
void setShort(register16_t address, register16_t value) noexcept;
|
||||
|
||||
void jump(const register16_t destination) noexcept;
|
||||
void jump(uint16_t destination) noexcept;
|
||||
|
||||
+16
-16
@@ -31,19 +31,19 @@ namespace EightBit {
|
||||
uint8_t low;
|
||||
#endif
|
||||
};
|
||||
uint16_t word;
|
||||
uint16_t joined;
|
||||
|
||||
constexpr register16_t() noexcept : word(0) {}
|
||||
constexpr register16_t(const uint16_t w) noexcept : word(w) {}
|
||||
constexpr register16_t() noexcept : joined(0) {}
|
||||
constexpr register16_t(const uint16_t w) noexcept : joined(w) {}
|
||||
constexpr register16_t(const uint8_t l, const uint8_t h) noexcept : low(l), high(h) {}
|
||||
|
||||
constexpr auto& operator++() noexcept {
|
||||
++word;
|
||||
++joined;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr auto& operator--() noexcept {
|
||||
--word;
|
||||
--joined;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -60,24 +60,24 @@ namespace EightBit {
|
||||
}
|
||||
|
||||
constexpr auto& operator+=(const register16_t rhs) noexcept {
|
||||
this->word += rhs.word;
|
||||
this->joined += rhs.joined;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr auto& operator-=(const register16_t rhs) noexcept {
|
||||
this->word -= rhs.word;
|
||||
this->joined -= rhs.joined;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto operator==(const register16_t& rhs) const noexcept { return word == rhs.word; }
|
||||
[[nodiscard]] constexpr auto operator!=(const register16_t& rhs) const noexcept { return word != rhs.word; }
|
||||
[[nodiscard]] constexpr auto operator<(const register16_t& rhs) const noexcept { return word < rhs.word; }
|
||||
[[nodiscard]] constexpr auto operator<=(const register16_t& rhs) const noexcept { return word <= rhs.word; }
|
||||
[[nodiscard]] constexpr auto operator>(const register16_t& rhs) const noexcept { return word > rhs.word; }
|
||||
[[nodiscard]] constexpr auto operator>=(const register16_t& rhs) const noexcept { return word >= rhs.word; }
|
||||
[[nodiscard]] constexpr auto operator==(const register16_t& rhs) const noexcept { return joined == rhs.joined; }
|
||||
[[nodiscard]] constexpr auto operator!=(const register16_t& rhs) const noexcept { return joined != rhs.joined; }
|
||||
[[nodiscard]] constexpr auto operator<(const register16_t& rhs) const noexcept { return joined < rhs.joined; }
|
||||
[[nodiscard]] constexpr auto operator<=(const register16_t& rhs) const noexcept { return joined <= rhs.joined; }
|
||||
[[nodiscard]] constexpr auto operator>(const register16_t& rhs) const noexcept { return joined > rhs.joined; }
|
||||
[[nodiscard]] constexpr auto operator>=(const register16_t& rhs) const noexcept { return joined >= rhs.joined; }
|
||||
|
||||
[[nodiscard]] constexpr auto zero() const noexcept { return word == 0; }
|
||||
[[nodiscard]] constexpr auto nonzero() const noexcept { return word != 0; }
|
||||
[[nodiscard]] constexpr auto zero() const noexcept { return joined == 0; }
|
||||
[[nodiscard]] constexpr auto nonzero() const noexcept { return joined != 0; }
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr inline auto operator+(register16_t lhs, const register16_t rhs) noexcept {
|
||||
@@ -91,6 +91,6 @@ namespace EightBit {
|
||||
}
|
||||
|
||||
inline auto& operator<<(std::ostream& output, const register16_t value) {
|
||||
return output << std::hex << std::setw(4) << std::setfill('0') << value.word;
|
||||
return output << std::hex << std::setw(4) << std::setfill('0') << value.joined;
|
||||
}
|
||||
}
|
||||
+39
-35
@@ -7,56 +7,60 @@ EightBit::BigEndianProcessor::BigEndianProcessor(Bus& memory) noexcept
|
||||
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();
|
||||
EightBit::register16_t EightBit::BigEndianProcessor::peekShort(uint16_t address) noexcept {
|
||||
const auto high = BUS().peek(address);
|
||||
const auto low = BUS().peek(++address);
|
||||
return { low, high };
|
||||
}
|
||||
|
||||
void EightBit::BigEndianProcessor::setWord(const register16_t value) noexcept {
|
||||
memoryWrite(value.high);
|
||||
void EightBit::BigEndianProcessor::pokeShort(uint16_t address, const register16_t value) noexcept {
|
||||
BUS().poke(address, value.high);
|
||||
BUS().poke(++address, value.low);
|
||||
}
|
||||
|
||||
void EightBit::BigEndianProcessor::fetchInto(register16_t& into) noexcept {
|
||||
fetchByte();
|
||||
into.high = BUS().DATA();
|
||||
fetchByte();
|
||||
into.low = BUS().DATA();
|
||||
}
|
||||
|
||||
void EightBit::BigEndianProcessor::getInto(register16_t& into) noexcept {
|
||||
memoryRead();
|
||||
into.high = BUS().DATA();
|
||||
++BUS().ADDRESS();
|
||||
memoryWrite(value.low);
|
||||
memoryRead();
|
||||
into.low = BUS().DATA();
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::BigEndianProcessor::getWordPaged() noexcept {
|
||||
const auto high = memoryRead();
|
||||
void EightBit::BigEndianProcessor::getPagedInto(register16_t& into) noexcept {
|
||||
memoryRead();
|
||||
into.high = BUS().DATA();
|
||||
++BUS().ADDRESS().low;
|
||||
const auto low = memoryRead();
|
||||
return { low, high };
|
||||
memoryRead();
|
||||
into.low = BUS().DATA();
|
||||
}
|
||||
|
||||
void EightBit::BigEndianProcessor::setWordPaged(const register16_t value) noexcept {
|
||||
memoryWrite(value.high);
|
||||
++BUS().ADDRESS().low;
|
||||
memoryWrite(value.low);
|
||||
void EightBit::BigEndianProcessor::popInto(register16_t& into) noexcept {
|
||||
pop();
|
||||
into.high = BUS().DATA();
|
||||
pop();
|
||||
into.low = BUS().DATA();
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::BigEndianProcessor::fetchWord() noexcept {
|
||||
intermediate().high = fetchByte();
|
||||
intermediate().low = fetchByte();
|
||||
return intermediate();
|
||||
}
|
||||
|
||||
void EightBit::BigEndianProcessor::pushWord(const register16_t value) noexcept {
|
||||
void EightBit::BigEndianProcessor::pushShort(register16_t value) noexcept {
|
||||
push(value.low);
|
||||
push(value.high);
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::BigEndianProcessor::popWord() noexcept {
|
||||
const auto high = pop();
|
||||
const auto low = pop();
|
||||
return { low, high };
|
||||
void EightBit::BigEndianProcessor::setShort(register16_t value) noexcept {
|
||||
memoryWrite(value.high);
|
||||
++BUS().ADDRESS();
|
||||
memoryWrite(value.low);
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::BigEndianProcessor::peekWord(const register16_t address) noexcept {
|
||||
const auto high = BUS().peek(address);
|
||||
const auto low = BUS().peek(address + 1);
|
||||
return { low, high };
|
||||
}
|
||||
|
||||
void EightBit::BigEndianProcessor::pokeWord(const register16_t address, const register16_t value) noexcept {
|
||||
BUS().poke(address, value.high);
|
||||
BUS().poke(address + 1, value.low);
|
||||
void EightBit::BigEndianProcessor::setPaged(register16_t value) noexcept {
|
||||
memoryWrite(value.high);
|
||||
++BUS().ADDRESS().low;
|
||||
memoryWrite(value.low);
|
||||
}
|
||||
+4
-4
@@ -11,13 +11,13 @@ uint8_t InputOutput::read(register16_t port) {
|
||||
|
||||
uint8_t InputOutput::readInputPort(register16_t port) {
|
||||
ReadingPort.fire(port);
|
||||
const auto value = _input[port.word];
|
||||
const auto value = _input[port.joined];
|
||||
ReadPort.fire(port);
|
||||
return value;
|
||||
}
|
||||
|
||||
void InputOutput::writeInputPort(register16_t port, uint8_t value) {
|
||||
_input[port.word] = value;
|
||||
_input[port.joined] = value;
|
||||
}
|
||||
|
||||
// Output port actions
|
||||
@@ -28,12 +28,12 @@ void InputOutput::write(register16_t port, uint8_t value) {
|
||||
|
||||
void InputOutput::writeOutputPort(register16_t port, uint8_t value) {
|
||||
WritingPort.fire(port);
|
||||
_output[port.word] = value;
|
||||
_output[port.joined] = value;
|
||||
WrittenPort.fire(port);
|
||||
}
|
||||
|
||||
uint8_t InputOutput::readOutputPort(register16_t port) {
|
||||
return _output[port.word];
|
||||
return _output[port.joined];
|
||||
}
|
||||
|
||||
}
|
||||
+46
-22
@@ -11,7 +11,7 @@ EightBit::IntelProcessor::IntelProcessor(Bus& bus) noexcept
|
||||
|
||||
RaisedPOWER.connect([this](EventArgs) {
|
||||
PC() = SP() = Mask16;
|
||||
resetWorkingRegisters();
|
||||
resetRegisterSet();
|
||||
raiseHALT();
|
||||
});
|
||||
}
|
||||
@@ -23,7 +23,7 @@ EightBit::IntelProcessor::IntelProcessor(const IntelProcessor& rhs) noexcept
|
||||
HALT() = rhs.HALT();
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::resetWorkingRegisters() noexcept {
|
||||
void EightBit::IntelProcessor::resetRegisterSet() noexcept {
|
||||
AF() = BC() = DE() = HL() = Mask16;
|
||||
}
|
||||
|
||||
@@ -45,8 +45,8 @@ void EightBit::IntelProcessor::push(const uint8_t value) noexcept {
|
||||
memoryWrite(--SP(), value);
|
||||
}
|
||||
|
||||
uint8_t EightBit::IntelProcessor::pop() noexcept {
|
||||
return memoryRead(SP()++);
|
||||
void EightBit::IntelProcessor::pop() noexcept {
|
||||
memoryRead(SP()++);
|
||||
}
|
||||
|
||||
EightBit::register16_t& EightBit::IntelProcessor::incrementPC() noexcept {
|
||||
@@ -56,18 +56,17 @@ EightBit::register16_t& EightBit::IntelProcessor::incrementPC() noexcept {
|
||||
}
|
||||
|
||||
uint8_t EightBit::IntelProcessor::fetchInstruction() noexcept {
|
||||
const auto data = fetchByte();
|
||||
return proceeding() ? data : (uint8_t)0;
|
||||
fetchByte();
|
||||
return proceeding() ? BUS().DATA() : (uint8_t)0;
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::IntelProcessor::getWord() noexcept {
|
||||
const auto returned = LittleEndianProcessor::getWord();
|
||||
void EightBit::IntelProcessor::getShort() noexcept {
|
||||
LittleEndianProcessor::getShort();
|
||||
MEMPTR() = BUS().ADDRESS();
|
||||
return returned;
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::setWord(const register16_t value) noexcept {
|
||||
LittleEndianProcessor::setWord(value);
|
||||
void EightBit::IntelProcessor::setShort(const register16_t value) noexcept {
|
||||
LittleEndianProcessor::setShort(value);
|
||||
MEMPTR() = BUS().ADDRESS();
|
||||
}
|
||||
|
||||
@@ -77,21 +76,21 @@ void EightBit::IntelProcessor::restart(const uint8_t address) noexcept {
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::callConditional(bool condition) noexcept {
|
||||
MEMPTR() = fetchWord();
|
||||
fetchInto(MEMPTR());
|
||||
if (condition)
|
||||
call();
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::jumpConditional(bool condition) noexcept {
|
||||
MEMPTR() = fetchWord();
|
||||
fetchInto(MEMPTR());
|
||||
if (condition)
|
||||
jump();
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::jumpRelativeConditional(bool condition) noexcept {
|
||||
const auto offset = fetchByte();
|
||||
fetchByte();
|
||||
if (condition)
|
||||
jumpRelative(offset);
|
||||
jumpRelative(BUS().DATA());
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::returnConditional(bool condition) noexcept {
|
||||
@@ -110,7 +109,7 @@ void EightBit::IntelProcessor::ret() noexcept {
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::jumpIndirect() noexcept {
|
||||
MEMPTR() = fetchWord();
|
||||
fetchInto(MEMPTR());
|
||||
jump();
|
||||
}
|
||||
|
||||
@@ -119,16 +118,12 @@ void EightBit::IntelProcessor::jump() noexcept {
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::callIndirect() noexcept {
|
||||
MEMPTR() = fetchWord();
|
||||
fetchInto(MEMPTR());
|
||||
call();
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::call() noexcept {
|
||||
call(MEMPTR());
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::call(register16_t destination) noexcept {
|
||||
Processor::call(destination);
|
||||
LittleEndianProcessor::call(MEMPTR());
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::jumpConditionalFlag(int flag) noexcept {
|
||||
@@ -164,3 +159,32 @@ bool EightBit::IntelProcessor::operator==(const EightBit::IntelProcessor& rhs) c
|
||||
&& left.DE() == right.DE()
|
||||
&& left.HL() == right.HL();
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::readMemoryIndirect(register16_t via) noexcept {
|
||||
MEMPTR() = via;
|
||||
readMemoryIndirect();
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::readMemoryIndirect() noexcept {
|
||||
BUS().ADDRESS() = MEMPTR();
|
||||
++MEMPTR();
|
||||
memoryRead();
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::writeMemoryIndirect(register16_t via, uint8_t data) noexcept {
|
||||
MEMPTR() = via;
|
||||
writeMemoryIndirect(data);
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::writeMemoryIndirect(uint8_t data) noexcept {
|
||||
BUS().ADDRESS() = MEMPTR();
|
||||
++MEMPTR();
|
||||
MEMPTR().high = BUS().DATA() = data;
|
||||
memoryWrite();
|
||||
}
|
||||
|
||||
void EightBit::IntelProcessor::R(int r, uint8_t value, int ticks) noexcept {
|
||||
R(r, MemoryMapping::AccessLevel::WriteOnly) = value;
|
||||
if (r == 6)
|
||||
memoryUpdate(ticks);
|
||||
}
|
||||
@@ -7,56 +7,60 @@ EightBit::LittleEndianProcessor::LittleEndianProcessor(Bus& memory) noexcept
|
||||
EightBit::LittleEndianProcessor::LittleEndianProcessor(const LittleEndianProcessor& rhs) noexcept
|
||||
: Processor(rhs) {}
|
||||
|
||||
EightBit::register16_t EightBit::LittleEndianProcessor::getWord() noexcept {
|
||||
const auto low = memoryRead();
|
||||
++BUS().ADDRESS();
|
||||
const auto high = memoryRead();
|
||||
EightBit::register16_t EightBit::LittleEndianProcessor::peekShort(uint16_t address) noexcept {
|
||||
const auto low = BUS().peek(address);
|
||||
const auto high = BUS().peek(++address);
|
||||
return { low, high };
|
||||
}
|
||||
|
||||
void EightBit::LittleEndianProcessor::setWord(const register16_t value) noexcept {
|
||||
memoryWrite(value.low);
|
||||
void EightBit::LittleEndianProcessor::pokeShort(uint16_t address, const register16_t value) noexcept {
|
||||
BUS().poke(address, value.low);
|
||||
BUS().poke(++address, value.high);
|
||||
}
|
||||
|
||||
void EightBit::LittleEndianProcessor::fetchInto(register16_t& into) noexcept {
|
||||
fetchByte();
|
||||
into.low = BUS().DATA();
|
||||
fetchByte();
|
||||
into.high = BUS().DATA();
|
||||
}
|
||||
|
||||
void EightBit::LittleEndianProcessor::getInto(register16_t& into) noexcept {
|
||||
memoryRead();
|
||||
into.low = BUS().DATA();
|
||||
++BUS().ADDRESS();
|
||||
memoryWrite(value.high);
|
||||
memoryRead();
|
||||
into.high = BUS().DATA();
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::LittleEndianProcessor::getWordPaged() noexcept {
|
||||
const auto low = memoryRead();
|
||||
void EightBit::LittleEndianProcessor::getPagedInto(register16_t& into) noexcept {
|
||||
memoryRead();
|
||||
into.low = BUS().DATA();
|
||||
++BUS().ADDRESS().low;
|
||||
const auto high = memoryRead();
|
||||
return { low, high };
|
||||
memoryRead();
|
||||
into.high = BUS().DATA();
|
||||
}
|
||||
|
||||
void EightBit::LittleEndianProcessor::setWordPaged(register16_t value) noexcept {
|
||||
memoryWrite(value.low);
|
||||
++BUS().ADDRESS().low;
|
||||
memoryWrite(value.high);
|
||||
void EightBit::LittleEndianProcessor::popInto(register16_t& into) noexcept {
|
||||
pop();
|
||||
into.low = BUS().DATA();
|
||||
pop();
|
||||
into.high = BUS().DATA();
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::LittleEndianProcessor::fetchWord() noexcept {
|
||||
intermediate().low = fetchByte();
|
||||
intermediate().high = fetchByte();
|
||||
return intermediate();
|
||||
}
|
||||
|
||||
void EightBit::LittleEndianProcessor::pushWord(const register16_t value) noexcept {
|
||||
void EightBit::LittleEndianProcessor::pushShort(register16_t value) noexcept {
|
||||
push(value.high);
|
||||
push(value.low);
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::LittleEndianProcessor::popWord() noexcept {
|
||||
const auto low = pop();
|
||||
const auto high = pop();
|
||||
return { low, high };
|
||||
void EightBit::LittleEndianProcessor::setShort(register16_t value) noexcept {
|
||||
memoryWrite(value.low);
|
||||
++BUS().ADDRESS();
|
||||
memoryWrite(value.high);
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::LittleEndianProcessor::peekWord(const register16_t address) noexcept {
|
||||
const auto low = BUS().peek(address);
|
||||
const auto high = BUS().peek(address + 1);
|
||||
return { low, high };
|
||||
}
|
||||
|
||||
void EightBit::LittleEndianProcessor::pokeWord(const register16_t address, const register16_t value) noexcept {
|
||||
BUS().poke(address, value.low);
|
||||
BUS().poke(address + 1, value.high);
|
||||
void EightBit::LittleEndianProcessor::setPaged(register16_t value) noexcept {
|
||||
memoryWrite(value.low);
|
||||
++BUS().ADDRESS().low;
|
||||
memoryWrite(value.high);
|
||||
}
|
||||
+30
-24
@@ -62,65 +62,71 @@ uint8_t EightBit::Processor::busRead() noexcept {
|
||||
return BUS().read();
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::Processor::getWordPaged(register16_t address) noexcept {
|
||||
void EightBit::Processor::getShortPaged(register16_t address) noexcept {
|
||||
BUS().ADDRESS() = address;
|
||||
return getWordPaged();
|
||||
getShortPaged();
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::Processor::getWordPaged(const uint8_t page, const uint8_t offset) noexcept {
|
||||
void EightBit::Processor::getShortPaged(const uint8_t page, const uint8_t offset) noexcept {
|
||||
BUS().ADDRESS() = { offset, page };
|
||||
return getWordPaged();
|
||||
getShortPaged();
|
||||
}
|
||||
|
||||
void EightBit::Processor::setWordPaged(register16_t address, const register16_t value) noexcept {
|
||||
void EightBit::Processor::getPagedInto(uint8_t page, uint8_t offset, register16_t& into) {
|
||||
BUS().ADDRESS() = { offset, page };
|
||||
getPagedInto(into);
|
||||
}
|
||||
|
||||
void EightBit::Processor::setPaged(register16_t address, const register16_t value) noexcept {
|
||||
BUS().ADDRESS() = address;
|
||||
setWordPaged(value);
|
||||
setPaged(value);
|
||||
}
|
||||
|
||||
void EightBit::Processor::setWordPaged(const uint8_t page, const uint8_t offset, const register16_t value) noexcept {
|
||||
void EightBit::Processor::setPaged(const uint8_t page, const uint8_t offset, const register16_t value) noexcept {
|
||||
BUS().ADDRESS() = { offset, page };
|
||||
setWordPaged(value);
|
||||
setPaged(value);
|
||||
}
|
||||
|
||||
EightBit::register16_t& EightBit::Processor::incrementPC() noexcept {
|
||||
return ++PC();
|
||||
}
|
||||
|
||||
EightBit::register16_t& EightBit::Processor::decrementPC() noexcept {
|
||||
return --PC();
|
||||
}
|
||||
|
||||
void EightBit::Processor::immediateAddress() noexcept {
|
||||
BUS().ADDRESS() = PC();
|
||||
incrementPC();
|
||||
}
|
||||
|
||||
uint8_t EightBit::Processor::fetchByte() noexcept {
|
||||
void EightBit::Processor::fetchByte() noexcept {
|
||||
immediateAddress();
|
||||
return memoryRead();
|
||||
memoryRead();
|
||||
}
|
||||
|
||||
uint8_t EightBit::Processor::fetchInstruction() noexcept {
|
||||
return fetchByte();
|
||||
fetchByte();
|
||||
return BUS().DATA();
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::Processor::getWord(const register16_t address) noexcept {
|
||||
BUS().ADDRESS() = address;
|
||||
return getWord();
|
||||
void EightBit::Processor::fetchShortAddress() noexcept {
|
||||
fetchShort();
|
||||
BUS().ADDRESS() = m_intermediate;
|
||||
}
|
||||
|
||||
void EightBit::Processor::setWord(const register16_t address, const register16_t value) noexcept {
|
||||
void EightBit::Processor::getShort(const register16_t address) noexcept {
|
||||
BUS().ADDRESS() = address;
|
||||
setWord(value);
|
||||
getShort();
|
||||
}
|
||||
|
||||
void EightBit::Processor::setShort(const register16_t address, const register16_t value) noexcept {
|
||||
BUS().ADDRESS() = address;
|
||||
setShort(value);
|
||||
}
|
||||
|
||||
int EightBit::Processor::step() noexcept {
|
||||
resetCycles();
|
||||
ExecutingInstruction.fire();
|
||||
if (LIKELY(powered()))
|
||||
if (powered())
|
||||
poweredStep();
|
||||
ExecutedInstruction.fire();
|
||||
// ASSUME(cycles() > 0); Not if unpowered!!
|
||||
return cycles();
|
||||
}
|
||||
|
||||
@@ -145,12 +151,12 @@ void EightBit::Processor::jump(const uint16_t destination) noexcept {
|
||||
}
|
||||
|
||||
void EightBit::Processor::call(const register16_t destination) noexcept {
|
||||
pushWord(PC());
|
||||
pushShort(PC());
|
||||
jump(destination);
|
||||
}
|
||||
|
||||
void EightBit::Processor::ret() noexcept {
|
||||
jump(popWord());
|
||||
popInto(PC());
|
||||
}
|
||||
|
||||
bool EightBit::Processor::operator==(const EightBit::Processor& rhs) const noexcept {
|
||||
|
||||
Reference in new issue
Block a user