mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2024-11-12 17:04:46 +00:00
Tidy up some C++ code (concentrating on the Z80 at the moment).
Signed-off-by: Adrian Conlon <adrian.conlon@gmail.com>
This commit is contained in:
parent
26cc613c66
commit
4d2d1d214a
242
Z80/inc/Z80.h
242
Z80/inc/Z80.h
@ -1,14 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <array>
|
||||
#include <functional>
|
||||
|
||||
#include <IntelProcessor.h>
|
||||
#include <EventArgs.h>
|
||||
#include <Signal.h>
|
||||
#include <Register.h>
|
||||
#include <EightBitCompilerDefinitions.h>
|
||||
|
||||
namespace EightBit {
|
||||
|
||||
@ -99,19 +98,14 @@ namespace EightBit {
|
||||
[[nodiscard]] auto& IFF1() { return m_iff1; }
|
||||
[[nodiscard]] auto& IFF2() { return m_iff2; }
|
||||
|
||||
void exx() {
|
||||
m_registerSet ^= 1;
|
||||
}
|
||||
void exx() { m_registerSet ^= 1; }
|
||||
void exxAF() { m_accumulatorFlagsSet ^= 1; }
|
||||
|
||||
void exxAF() {
|
||||
m_accumulatorFlagsSet ^= 1;
|
||||
}
|
||||
[[nodiscard]] auto requestingIO() const { return lowered(IORQ()); }
|
||||
[[nodiscard]] auto requestingMemory() const { return lowered(MREQ()); }
|
||||
|
||||
[[nodiscard]] bool requestingIO() const { return lowered(IORQ()); }
|
||||
[[nodiscard]] bool requestingMemory() const { return lowered(MREQ()); }
|
||||
|
||||
[[nodiscard]] bool requestingRead() const { return lowered(RD()); }
|
||||
[[nodiscard]] bool requestingWrite() const { return lowered(WR()); }
|
||||
[[nodiscard]] auto requestingRead() const { return lowered(RD()); }
|
||||
[[nodiscard]] auto requestingWrite() const { return lowered(WR()); }
|
||||
|
||||
// ** From the Z80 CPU User Manual
|
||||
// RFSH.Refresh(output, active Low). RFSH, together with MREQ, indicates that the lower
|
||||
@ -150,11 +144,6 @@ namespace EightBit {
|
||||
DEFINE_PIN_ACTIVATOR_LOW(RD)
|
||||
DEFINE_PIN_ACTIVATOR_LOW(WR)
|
||||
|
||||
auto readBusDataM1() {
|
||||
_ActivateM1 m1(*this);
|
||||
return BUS().DATA();
|
||||
}
|
||||
|
||||
enum { BC_IDX, DE_IDX, HL_IDX };
|
||||
|
||||
std::array<std::array<register16_t, 3>, 2> m_registers;
|
||||
@ -179,194 +168,39 @@ namespace EightBit {
|
||||
bool m_prefixFD = false;
|
||||
|
||||
int8_t m_displacement = 0;
|
||||
bool m_displaced = false;
|
||||
|
||||
void handleNMI();
|
||||
|
||||
void resetPrefixes();
|
||||
|
||||
[[nodiscard]] auto displaced() const { return m_prefixDD || m_prefixFD; }
|
||||
[[nodiscard]] uint16_t displacedAddress();
|
||||
void fetchDisplacement();
|
||||
[[nodiscard]] uint8_t fetchOpCode();
|
||||
|
||||
uint8_t readBusDataM1();
|
||||
|
||||
typedef std::function<register16_t(void)> addresser_t;
|
||||
void loadAccumulatorIndirect(addresser_t addresser);
|
||||
void storeAccumulatorIndirect(addresser_t addresser);
|
||||
|
||||
typedef std::function<uint8_t(void)> reader_t;
|
||||
void readInternalRegister(reader_t reader);
|
||||
|
||||
void loadAccumulatorIndirect(addresser_t addresser) {
|
||||
(MEMPTR() = BUS().ADDRESS() = addresser())++;
|
||||
A() = memoryRead();
|
||||
}
|
||||
[[nodiscard]] register16_t& HL2();
|
||||
[[nodiscard]] register16_t& RP(int rp);
|
||||
[[nodiscard]] register16_t& RP2(int rp);
|
||||
|
||||
void storeAccumulatorIndirect(addresser_t addresser) {
|
||||
(MEMPTR() = BUS().ADDRESS() = addresser())++;
|
||||
MEMPTR().high = BUS().DATA() = A();
|
||||
memoryWrite();
|
||||
}
|
||||
[[nodiscard]] uint8_t R(int r);
|
||||
void R(int r, uint8_t value);
|
||||
void R2(int r, uint8_t value);
|
||||
|
||||
void readInternalRegister(reader_t reader) {
|
||||
F() = adjustSZXY<Z80>(F(), A() = reader());
|
||||
F() = clearBit(F(), NF | HC);
|
||||
F() = setBit(F(), PF, IFF2());
|
||||
tick();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto& HL2() {
|
||||
if (LIKELY(!m_displaced))
|
||||
return HL();
|
||||
if (m_prefixDD)
|
||||
return IX();
|
||||
// Must be FD prefix
|
||||
return IY();
|
||||
}
|
||||
|
||||
[[nodiscard]] auto& RP(const int rp) {
|
||||
ASSUME(rp >= 0);
|
||||
ASSUME(rp <= 3);
|
||||
switch (rp) {
|
||||
case 0b00:
|
||||
return BC();
|
||||
case 0b01:
|
||||
return DE();
|
||||
case 0b10:
|
||||
return HL2();
|
||||
case 0b11:
|
||||
return SP();
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] auto& RP2(const int rp) {
|
||||
ASSUME(rp >= 0);
|
||||
ASSUME(rp <= 3);
|
||||
switch (rp) {
|
||||
case 0b00:
|
||||
return BC();
|
||||
case 0b01:
|
||||
return DE();
|
||||
case 0b10:
|
||||
return HL2();
|
||||
case 0b11:
|
||||
return AF();
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] auto R(const int r) {
|
||||
ASSUME(r >= 0);
|
||||
ASSUME(r <= 7);
|
||||
switch (r) {
|
||||
case 0:
|
||||
return B();
|
||||
case 1:
|
||||
return C();
|
||||
case 2:
|
||||
return D();
|
||||
case 3:
|
||||
return E();
|
||||
case 4:
|
||||
return HL2().high;
|
||||
case 5:
|
||||
return HL2().low;
|
||||
case 6:
|
||||
return IntelProcessor::memoryRead(UNLIKELY(m_displaced) ? displacedAddress() : HL().word);
|
||||
case 7:
|
||||
return A();
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
void R(const int r, const uint8_t value) {
|
||||
ASSUME(r >= 0);
|
||||
ASSUME(r <= 7);
|
||||
switch (r) {
|
||||
case 0:
|
||||
B() = value;
|
||||
break;
|
||||
case 1:
|
||||
C() = value;
|
||||
break;
|
||||
case 2:
|
||||
D() = value;
|
||||
break;
|
||||
case 3:
|
||||
E() = value;
|
||||
break;
|
||||
case 4:
|
||||
HL2().high = value;
|
||||
break;
|
||||
case 5:
|
||||
HL2().low = value;
|
||||
break;
|
||||
case 6:
|
||||
IntelProcessor::memoryWrite(UNLIKELY(m_displaced) ? displacedAddress() : HL().word, value);
|
||||
break;
|
||||
case 7:
|
||||
A() = value;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
void R2(const int r, const uint8_t value) {
|
||||
ASSUME(r >= 0);
|
||||
ASSUME(r <= 7);
|
||||
switch (r) {
|
||||
case 0:
|
||||
B() = value;
|
||||
break;
|
||||
case 1:
|
||||
C() = value;
|
||||
break;
|
||||
case 2:
|
||||
D() = value;
|
||||
break;
|
||||
case 3:
|
||||
E() = value;
|
||||
break;
|
||||
case 4:
|
||||
H() = value;
|
||||
break;
|
||||
case 5:
|
||||
L() = value;
|
||||
break;
|
||||
case 6:
|
||||
IntelProcessor::memoryWrite(HL(), value);
|
||||
break;
|
||||
case 7:
|
||||
A() = value;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] static 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 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 uint8_t adjustOverflowAdd(uint8_t f, const uint8_t before, const uint8_t value, const uint8_t calculation) {
|
||||
return adjustOverflowAdd(f, before & SF, value & SF, calculation & SF);
|
||||
}
|
||||
|
||||
[[nodiscard]] static uint8_t adjustOverflowAdd(uint8_t f, const int beforeNegative, const int valueNegative, const int afterNegative) {
|
||||
const auto overflow = (beforeNegative == valueNegative) && (beforeNegative != afterNegative);
|
||||
return setBit(f, VF, overflow);
|
||||
}
|
||||
|
||||
[[nodiscard]] static uint8_t adjustOverflowSub(uint8_t f, const uint8_t before, const uint8_t value, const uint8_t calculation) {
|
||||
return adjustOverflowSub(f, before & SF, value & SF, calculation & SF);
|
||||
}
|
||||
|
||||
[[nodiscard]] static uint8_t adjustOverflowSub(uint8_t f, const int beforeNegative, const int valueNegative, const int afterNegative) {
|
||||
const auto overflow = (beforeNegative != valueNegative) && (beforeNegative != afterNegative);
|
||||
return setBit(f, VF, overflow);
|
||||
}
|
||||
[[nodiscard]] static uint8_t adjustHalfCarryAdd(uint8_t f, uint8_t before, uint8_t value, int calculation);
|
||||
[[nodiscard]] static uint8_t adjustHalfCarrySub(uint8_t f, uint8_t before, uint8_t value, int calculation);
|
||||
[[nodiscard]] static uint8_t adjustOverflowAdd(uint8_t f, uint8_t before, uint8_t value, uint8_t calculation);
|
||||
[[nodiscard]] static uint8_t adjustOverflowAdd(uint8_t f, int beforeNegative, int valueNegative, int afterNegative);
|
||||
[[nodiscard]] static uint8_t adjustOverflowSub(uint8_t f, uint8_t before, uint8_t value, uint8_t calculation);
|
||||
[[nodiscard]] static uint8_t adjustOverflowSub(uint8_t f, int beforeNegative, int valueNegative, int afterNegative);
|
||||
|
||||
[[nodiscard]] static bool convertCondition(uint8_t f, int flag);
|
||||
|
||||
@ -420,41 +254,41 @@ namespace EightBit {
|
||||
|
||||
static void scf(uint8_t& f, uint8_t operand);
|
||||
static void ccf(uint8_t& f, uint8_t operand);
|
||||
static uint8_t cpl(uint8_t& f, uint8_t operand);
|
||||
[[nodiscard]] static uint8_t cpl(uint8_t& f, uint8_t operand);
|
||||
|
||||
void xhtl(register16_t& exchange);
|
||||
|
||||
void blockCompare(uint8_t& f, uint8_t value, register16_t source, register16_t& counter);
|
||||
|
||||
void cpi(uint8_t& f, uint8_t value);
|
||||
bool cpir(uint8_t& f, uint8_t value);
|
||||
[[nodiscard]] bool cpir(uint8_t& f, uint8_t value);
|
||||
|
||||
void cpd(uint8_t& f, uint8_t value);
|
||||
bool cpdr(uint8_t& f, uint8_t value);
|
||||
[[nodiscard]] bool cpdr(uint8_t& f, uint8_t value);
|
||||
|
||||
void blockLoad(uint8_t& f, uint8_t a, register16_t source, register16_t destination, register16_t& counter);
|
||||
|
||||
void ldi(uint8_t& f, uint8_t a);
|
||||
bool ldir(uint8_t& f, uint8_t a);
|
||||
[[nodiscard]] bool ldir(uint8_t& f, uint8_t a);
|
||||
|
||||
void ldd(uint8_t& f, uint8_t a);
|
||||
bool lddr(uint8_t& f, uint8_t a);
|
||||
[[nodiscard]] bool lddr(uint8_t& f, uint8_t a);
|
||||
|
||||
void blockIn(register16_t& source, register16_t destination);
|
||||
|
||||
void ini();
|
||||
bool inir();
|
||||
[[nodiscard]] bool inir();
|
||||
|
||||
void ind();
|
||||
bool indr();
|
||||
[[nodiscard]] bool indr();
|
||||
|
||||
void blockOut(register16_t source, register16_t& destination);
|
||||
|
||||
void outi();
|
||||
bool otir();
|
||||
[[nodiscard]] bool otir();
|
||||
|
||||
void outd();
|
||||
bool otdr();
|
||||
[[nodiscard]] bool otdr();
|
||||
|
||||
[[nodiscard]] uint8_t neg(uint8_t& f, uint8_t operand);
|
||||
|
||||
|
229
Z80/src/Z80.cpp
229
Z80/src/Z80.cpp
@ -25,7 +25,7 @@ EightBit::Z80::Z80(Bus& bus)
|
||||
|
||||
AF() = IX() = IY() = BC() = DE() = HL() = Mask16;
|
||||
|
||||
m_prefixCB = m_prefixDD = m_prefixED = m_prefixFD = false;
|
||||
resetPrefixes();
|
||||
});
|
||||
|
||||
RaisedM1.connect([this](EventArgs) {
|
||||
@ -186,9 +186,33 @@ uint8_t EightBit::Z80::decrement(uint8_t& f, const uint8_t operand) {
|
||||
return result;
|
||||
}
|
||||
|
||||
uint8_t EightBit::Z80::adjustHalfCarryAdd(const uint8_t f, const uint8_t before, const uint8_t value, const int calculation) {
|
||||
return setBit(f, HC, calculateHalfCarryAdd(before, value, calculation));
|
||||
}
|
||||
|
||||
uint8_t EightBit::Z80::adjustHalfCarrySub(const uint8_t f, const uint8_t before, const uint8_t value, const int calculation) {
|
||||
return setBit(f, HC, calculateHalfCarrySub(before, value, calculation));
|
||||
}
|
||||
|
||||
uint8_t EightBit::Z80::adjustOverflowAdd(const uint8_t f, const uint8_t before, const uint8_t value, const uint8_t calculation) {
|
||||
return adjustOverflowAdd(f, before & SF, value & SF, calculation & SF);
|
||||
}
|
||||
|
||||
uint8_t EightBit::Z80::adjustOverflowAdd(const uint8_t f, const int beforeNegative, const int valueNegative, const int afterNegative) {
|
||||
const auto overflow = (beforeNegative == valueNegative) && (beforeNegative != afterNegative);
|
||||
return setBit(f, VF, overflow);
|
||||
}
|
||||
|
||||
uint8_t EightBit::Z80::adjustOverflowSub(const uint8_t f, const uint8_t before, const uint8_t value, const uint8_t calculation) {
|
||||
return adjustOverflowSub(f, before & SF, value & SF, calculation & SF);
|
||||
}
|
||||
|
||||
uint8_t EightBit::Z80::adjustOverflowSub(const uint8_t f, const int beforeNegative, const int valueNegative, const int afterNegative) {
|
||||
const auto overflow = (beforeNegative != valueNegative) && (beforeNegative != afterNegative);
|
||||
return setBit(f, VF, overflow);
|
||||
}
|
||||
|
||||
bool EightBit::Z80::convertCondition(const uint8_t f, int flag) {
|
||||
ASSUME(flag >= 0);
|
||||
ASSUME(flag <= 7);
|
||||
switch (flag) {
|
||||
case 0:
|
||||
return !(f & ZF);
|
||||
@ -447,8 +471,6 @@ uint8_t EightBit::Z80::srl(uint8_t& f, const uint8_t operand) {
|
||||
}
|
||||
|
||||
void EightBit::Z80::bit(uint8_t& f, const int n, const uint8_t operand) {
|
||||
ASSUME(n >= 0);
|
||||
ASSUME(n <= 7);
|
||||
f = setBit(f, HC);
|
||||
f = clearBit(f, NF);
|
||||
const auto discarded = operand & Chip::bit(n);
|
||||
@ -457,14 +479,10 @@ void EightBit::Z80::bit(uint8_t& f, const int n, const uint8_t operand) {
|
||||
}
|
||||
|
||||
uint8_t EightBit::Z80::res(const int n, const uint8_t operand) {
|
||||
ASSUME(n >= 0);
|
||||
ASSUME(n <= 7);
|
||||
return clearBit(operand, Chip::bit(n));
|
||||
}
|
||||
|
||||
uint8_t EightBit::Z80::set(const int n, const uint8_t operand) {
|
||||
ASSUME(n >= 0);
|
||||
ASSUME(n <= 7);
|
||||
return setBit(operand, Chip::bit(n));
|
||||
}
|
||||
|
||||
@ -584,7 +602,7 @@ bool EightBit::Z80::cpdr(uint8_t& f, uint8_t value) {
|
||||
|
||||
void EightBit::Z80::blockLoad(uint8_t& f, const uint8_t a, const register16_t source, const register16_t destination, register16_t& counter) {
|
||||
const auto value = IntelProcessor::memoryRead(source);
|
||||
IntelProcessor::memoryWrite(destination, value);
|
||||
IntelProcessor::memoryWrite(destination);
|
||||
const auto xy = a + value;
|
||||
f = setBit(f, XF, xy & Bit3);
|
||||
f = setBit(f, YF, xy & Bit1);
|
||||
@ -748,8 +766,13 @@ uint8_t EightBit::Z80::portRead() {
|
||||
|
||||
//
|
||||
|
||||
void EightBit::Z80::resetPrefixes() {
|
||||
m_prefixCB = m_prefixDD = m_prefixED = m_prefixFD = false;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
uint16_t EightBit::Z80::displacedAddress() {
|
||||
assert(m_displaced);
|
||||
return MEMPTR().word = (m_prefixDD ? IX() : IY()).word + m_displacement;
|
||||
}
|
||||
|
||||
@ -757,6 +780,13 @@ void EightBit::Z80::fetchDisplacement() {
|
||||
m_displacement = fetchByte();
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
uint8_t EightBit::Z80::readBusDataM1() {
|
||||
_ActivateM1 m1(*this);
|
||||
return BUS().DATA();
|
||||
}
|
||||
|
||||
// ** From the Z80 CPU User Manual
|
||||
|
||||
// Figure 5 depicts the timing during an M1 (op code fetch) cycle. The Program Counter is
|
||||
@ -803,11 +833,152 @@ uint8_t EightBit::Z80::fetchOpCode() {
|
||||
return returned;
|
||||
}
|
||||
|
||||
void EightBit::Z80::loadAccumulatorIndirect(addresser_t addresser) {
|
||||
(MEMPTR() = BUS().ADDRESS() = addresser())++;
|
||||
A() = memoryRead();
|
||||
}
|
||||
|
||||
void EightBit::Z80::storeAccumulatorIndirect(addresser_t addresser) {
|
||||
(MEMPTR() = BUS().ADDRESS() = addresser())++;
|
||||
MEMPTR().high = BUS().DATA() = A();
|
||||
memoryWrite();
|
||||
}
|
||||
|
||||
void EightBit::Z80::readInternalRegister(reader_t reader) {
|
||||
F() = adjustSZXY<Z80>(F(), A() = reader());
|
||||
F() = clearBit(F(), NF | HC);
|
||||
F() = setBit(F(), PF, IFF2());
|
||||
tick();
|
||||
}
|
||||
|
||||
EightBit::register16_t& EightBit::Z80::HL2() {
|
||||
if (UNLIKELY(m_prefixDD))
|
||||
return IX();
|
||||
if (UNLIKELY(m_prefixFD))
|
||||
return IY();
|
||||
return HL();
|
||||
}
|
||||
|
||||
EightBit::register16_t& EightBit::Z80::RP(const int rp) {
|
||||
switch (rp) {
|
||||
case 0b00:
|
||||
return BC();
|
||||
case 0b01:
|
||||
return DE();
|
||||
case 0b10:
|
||||
return HL2();
|
||||
case 0b11:
|
||||
return SP();
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
EightBit::register16_t& EightBit::Z80::RP2(const int rp) {
|
||||
switch (rp) {
|
||||
case 0b00:
|
||||
return BC();
|
||||
case 0b01:
|
||||
return DE();
|
||||
case 0b10:
|
||||
return HL2();
|
||||
case 0b11:
|
||||
return AF();
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t EightBit::Z80::R(const int r) {
|
||||
switch (r) {
|
||||
case 0:
|
||||
return B();
|
||||
case 1:
|
||||
return C();
|
||||
case 2:
|
||||
return D();
|
||||
case 3:
|
||||
return E();
|
||||
case 4:
|
||||
return HL2().high;
|
||||
case 5:
|
||||
return HL2().low;
|
||||
case 6:
|
||||
return IntelProcessor::memoryRead(UNLIKELY(displaced()) ? displacedAddress() : HL().word);
|
||||
case 7:
|
||||
return A();
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
void EightBit::Z80::R(const int r, const uint8_t value) {
|
||||
switch (r) {
|
||||
case 0:
|
||||
B() = value;
|
||||
break;
|
||||
case 1:
|
||||
C() = value;
|
||||
break;
|
||||
case 2:
|
||||
D() = value;
|
||||
break;
|
||||
case 3:
|
||||
E() = value;
|
||||
break;
|
||||
case 4:
|
||||
HL2().high = value;
|
||||
break;
|
||||
case 5:
|
||||
HL2().low = value;
|
||||
break;
|
||||
case 6:
|
||||
IntelProcessor::memoryWrite(UNLIKELY(displaced()) ? displacedAddress() : HL().word, value);
|
||||
break;
|
||||
case 7:
|
||||
A() = value;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
void EightBit::Z80::R2(const int r, const uint8_t value) {
|
||||
switch (r) {
|
||||
case 0:
|
||||
B() = value;
|
||||
break;
|
||||
case 1:
|
||||
C() = value;
|
||||
break;
|
||||
case 2:
|
||||
D() = value;
|
||||
break;
|
||||
case 3:
|
||||
E() = value;
|
||||
break;
|
||||
case 4:
|
||||
H() = value;
|
||||
break;
|
||||
case 5:
|
||||
L() = value;
|
||||
break;
|
||||
case 6:
|
||||
IntelProcessor::memoryWrite(HL(), value);
|
||||
break;
|
||||
case 7:
|
||||
A() = value;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
||||
int EightBit::Z80::step() {
|
||||
resetCycles();
|
||||
ExecutingInstruction.fire(*this);
|
||||
if (LIKELY(powered())) {
|
||||
m_displaced = m_prefixCB = m_prefixDD = m_prefixED = m_prefixFD = false;
|
||||
resetPrefixes();
|
||||
bool handled = false;
|
||||
if (lowered(RESET())) {
|
||||
handleRESET();
|
||||
@ -855,10 +1026,10 @@ int EightBit::Z80::execute() {
|
||||
void EightBit::Z80::executeCB(const int x, const int y, const int z) {
|
||||
|
||||
const bool memoryZ = z == 6;
|
||||
const bool indirect = (!m_displaced && memoryZ) || m_displaced;
|
||||
const bool indirect = (!displaced() && memoryZ) || displaced();
|
||||
|
||||
uint8_t operand;
|
||||
if (m_displaced) {
|
||||
if (displaced()) {
|
||||
tick(2);
|
||||
operand = IntelProcessor::memoryRead(displacedAddress());
|
||||
} else {
|
||||
@ -915,7 +1086,7 @@ void EightBit::Z80::executeCB(const int x, const int y, const int z) {
|
||||
}
|
||||
if (update) {
|
||||
tick();
|
||||
if (m_displaced) {
|
||||
if (displaced()) {
|
||||
IntelProcessor::memoryWrite(operand);
|
||||
if (!memoryZ)
|
||||
R2(z, operand);
|
||||
@ -1240,7 +1411,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
tick(2);
|
||||
break;
|
||||
case 4: { // 8-bit INC
|
||||
if (memoryY && m_displaced) {
|
||||
if (memoryY && displaced()) {
|
||||
fetchDisplacement();
|
||||
tick(5);
|
||||
}
|
||||
@ -1251,7 +1422,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
break;
|
||||
}
|
||||
case 5: { // 8-bit DEC
|
||||
if (memoryY && m_displaced) {
|
||||
if (memoryY && displaced()) {
|
||||
fetchDisplacement();
|
||||
tick(5);
|
||||
}
|
||||
@ -1262,10 +1433,10 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
break;
|
||||
}
|
||||
case 6: { // 8-bit load immediate
|
||||
if (memoryY && m_displaced)
|
||||
if (memoryY && displaced())
|
||||
fetchDisplacement();
|
||||
const auto value = fetchByte();
|
||||
if (m_displaced)
|
||||
if (displaced())
|
||||
tick(2);
|
||||
R(y, value); // LD r,n
|
||||
break;
|
||||
@ -1309,19 +1480,19 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
lowerHALT();
|
||||
} else {
|
||||
bool normal = true;
|
||||
if (m_displaced) {
|
||||
if (displaced()) {
|
||||
if (memoryZ || memoryY)
|
||||
fetchDisplacement();
|
||||
if (memoryZ) {
|
||||
switch (y) {
|
||||
case 4:
|
||||
if (m_displaced)
|
||||
if (displaced())
|
||||
tick(5);
|
||||
H() = R(z);
|
||||
normal = false;
|
||||
break;
|
||||
case 5:
|
||||
if (m_displaced)
|
||||
if (displaced())
|
||||
tick(5);
|
||||
L() = R(z);
|
||||
normal = false;
|
||||
@ -1331,13 +1502,13 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
if (memoryY) {
|
||||
switch (z) {
|
||||
case 4:
|
||||
if (m_displaced)
|
||||
if (displaced())
|
||||
tick(5);
|
||||
R(y, H());
|
||||
normal = false;
|
||||
break;
|
||||
case 5:
|
||||
if (m_displaced)
|
||||
if (displaced())
|
||||
tick(5);
|
||||
R(y, L());
|
||||
normal = false;
|
||||
@ -1346,14 +1517,14 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
}
|
||||
}
|
||||
if (normal) {
|
||||
if (m_displaced)
|
||||
if (displaced())
|
||||
tick(5);
|
||||
R(y, R(z));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2: { // Operate on accumulator and register/memory location
|
||||
if (memoryZ && m_displaced) {
|
||||
if (memoryZ && displaced()) {
|
||||
fetchDisplacement();
|
||||
tick(5);
|
||||
}
|
||||
@ -1431,7 +1602,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
break;
|
||||
case 1: // CB prefix
|
||||
m_prefixCB = true;
|
||||
if (m_displaced) {
|
||||
if (displaced()) {
|
||||
fetchDisplacement();
|
||||
IntelProcessor::execute(fetchByte());
|
||||
} else {
|
||||
@ -1474,7 +1645,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
call(MEMPTR() = fetchWord());
|
||||
break;
|
||||
case 1: // DD prefix
|
||||
m_displaced = m_prefixDD = true;
|
||||
m_prefixDD = true;
|
||||
IntelProcessor::execute(fetchOpCode());
|
||||
break;
|
||||
case 2: // ED prefix
|
||||
@ -1482,7 +1653,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in
|
||||
IntelProcessor::execute(fetchOpCode());
|
||||
break;
|
||||
case 3: // FD prefix
|
||||
m_displaced = m_prefixFD = true;
|
||||
m_prefixFD = true;
|
||||
IntelProcessor::execute(fetchOpCode());
|
||||
break;
|
||||
default:
|
||||
|
@ -11,12 +11,13 @@ namespace EightBit {
|
||||
|
||||
Signal<EventArgs> Ticked;
|
||||
|
||||
void tick(const int extra) { for (int i = 0; i < extra; ++i) tick(); }
|
||||
void tick() { ++m_cycles; Ticked.fire(); }
|
||||
[[nodiscard]] auto cycles() const noexcept { return m_cycles; }
|
||||
|
||||
void tick(int extra);
|
||||
void tick();
|
||||
|
||||
protected:
|
||||
void resetCycles() noexcept { m_cycles = 0; }
|
||||
void resetCycles() noexcept;
|
||||
|
||||
private:
|
||||
int m_cycles = 0;
|
||||
|
@ -40,6 +40,7 @@ namespace EightBit {
|
||||
virtual void handleINT();
|
||||
|
||||
void memoryWrite(register16_t address, uint8_t data);
|
||||
void memoryWrite(register16_t address);
|
||||
void memoryWrite(uint8_t data);
|
||||
virtual void memoryWrite();
|
||||
virtual void busWrite();
|
||||
@ -48,17 +49,10 @@ namespace EightBit {
|
||||
virtual uint8_t memoryRead();
|
||||
virtual uint8_t busRead();
|
||||
|
||||
auto getBytePaged(const uint8_t page, const uint8_t offset) {
|
||||
return memoryRead(register16_t(offset, page));
|
||||
}
|
||||
uint8_t getBytePaged(uint8_t page, uint8_t offset);
|
||||
void setBytePaged(uint8_t page, uint8_t offset, uint8_t value);
|
||||
|
||||
void setBytePaged(const uint8_t page, const uint8_t offset, const uint8_t value) {
|
||||
memoryWrite(register16_t(offset, page), value);
|
||||
}
|
||||
|
||||
auto fetchByte() {
|
||||
return memoryRead(PC()++);
|
||||
}
|
||||
uint8_t fetchByte();
|
||||
|
||||
[[nodiscard]] virtual register16_t getWord() = 0;
|
||||
virtual void setWord(register16_t value) = 0;
|
||||
@ -74,20 +68,10 @@ namespace EightBit {
|
||||
virtual void pushWord(register16_t value) = 0;
|
||||
[[nodiscard]] virtual register16_t popWord() = 0;
|
||||
|
||||
[[nodiscard]] auto getWord(const register16_t address) {
|
||||
BUS().ADDRESS() = address;
|
||||
return getWord();
|
||||
}
|
||||
|
||||
void setWord(const register16_t address, const register16_t value) {
|
||||
BUS().ADDRESS() = address;
|
||||
setWord(value);
|
||||
}
|
||||
|
||||
void jump(const register16_t destination) noexcept {
|
||||
PC() = destination;
|
||||
}
|
||||
register16_t getWord(register16_t address);
|
||||
void setWord(register16_t address, register16_t value);
|
||||
|
||||
void jump(const register16_t destination) noexcept;
|
||||
virtual void call(register16_t destination);
|
||||
virtual void ret();
|
||||
|
||||
|
16
src/ClockedChip.cpp
Normal file
16
src/ClockedChip.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
#include "stdafx.h"
|
||||
#include "ClockedChip.h"
|
||||
|
||||
void EightBit::ClockedChip::tick(const int extra) {
|
||||
for (int i = 0; i < extra; ++i)
|
||||
tick();
|
||||
}
|
||||
|
||||
void EightBit::ClockedChip::tick() {
|
||||
++m_cycles;
|
||||
Ticked.fire();
|
||||
}
|
||||
|
||||
void EightBit::ClockedChip::resetCycles() noexcept {
|
||||
m_cycles = 0;
|
||||
}
|
@ -178,6 +178,7 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="BigEndianProcessor.cpp" />
|
||||
<ClCompile Include="Bus.cpp" />
|
||||
<ClCompile Include="ClockedChip.cpp" />
|
||||
<ClCompile Include="Device.cpp" />
|
||||
<ClCompile Include="EventArgs.cpp" />
|
||||
<ClCompile Include="InputOutput.cpp" />
|
||||
|
@ -121,5 +121,8 @@
|
||||
<ClCompile Include="IntelHexFile.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ClockedChip.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -2,7 +2,7 @@ LIB = libeightbit.a
|
||||
|
||||
CXXFLAGS = -I ../inc
|
||||
|
||||
CXXFILES = BigEndianProcessor.cpp Bus.cpp Device.cpp EventArgs.cpp InputOutput.cpp IntelHexFile.cpp IntelProcessor.cpp LittleEndianProcessor.cpp Memory.cpp Processor.cpp Ram.cpp Rom.cpp UnusedMemory.cpp
|
||||
CXXFILES = BigEndianProcessor.cpp Bus.cpp ClockedChip.cpp Device.cpp EventArgs.cpp InputOutput.cpp IntelHexFile.cpp IntelProcessor.cpp LittleEndianProcessor.cpp Memory.cpp Processor.cpp Ram.cpp Rom.cpp UnusedMemory.cpp
|
||||
|
||||
include ../compile.mk
|
||||
include ../lib_build.mk
|
||||
|
@ -21,6 +21,11 @@ void EightBit::Processor::memoryWrite(const register16_t address, const uint8_t
|
||||
memoryWrite(data);
|
||||
}
|
||||
|
||||
void EightBit::Processor::memoryWrite(const register16_t address) {
|
||||
BUS().ADDRESS() = address;
|
||||
memoryWrite();
|
||||
}
|
||||
|
||||
void EightBit::Processor::memoryWrite(const uint8_t data) {
|
||||
BUS().DATA() = data;
|
||||
memoryWrite();
|
||||
@ -47,6 +52,28 @@ uint8_t EightBit::Processor::busRead() {
|
||||
return BUS().read();
|
||||
}
|
||||
|
||||
uint8_t EightBit::Processor::getBytePaged(const uint8_t page, const uint8_t offset) {
|
||||
return memoryRead(register16_t(offset, page));
|
||||
}
|
||||
|
||||
void EightBit::Processor::setBytePaged(const uint8_t page, const uint8_t offset, const uint8_t value) {
|
||||
memoryWrite(register16_t(offset, page), value);
|
||||
}
|
||||
|
||||
uint8_t EightBit::Processor::fetchByte() {
|
||||
return memoryRead(PC()++);
|
||||
}
|
||||
|
||||
EightBit::register16_t EightBit::Processor::getWord(const register16_t address) {
|
||||
BUS().ADDRESS() = address;
|
||||
return getWord();
|
||||
}
|
||||
|
||||
void EightBit::Processor::setWord(const register16_t address, const register16_t value) {
|
||||
BUS().ADDRESS() = address;
|
||||
setWord(value);
|
||||
}
|
||||
|
||||
int EightBit::Processor::run(const int limit) {
|
||||
int current = 0;
|
||||
while (LIKELY(powered() && (current < limit)))
|
||||
@ -67,6 +94,10 @@ int8_t EightBit::Processor::signExtend(const int b, uint8_t x) noexcept {
|
||||
return result;
|
||||
}
|
||||
|
||||
void EightBit::Processor::jump(const register16_t destination) noexcept {
|
||||
PC() = destination;
|
||||
}
|
||||
|
||||
void EightBit::Processor::call(const register16_t destination) {
|
||||
pushWord(PC());
|
||||
jump(destination);
|
||||
|
Loading…
Reference in New Issue
Block a user