mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2025-01-21 21:30:31 +00:00
Switch to a memory read/write event driven model. All tests passing.
Signed-off-by: Adrian.Conlon <adrian.conlon@gmail.com>
This commit is contained in:
parent
261433bd6e
commit
016b3bca59
@ -56,7 +56,7 @@ namespace EightBit {
|
||||
|
||||
bool m_interrupt;
|
||||
|
||||
uint8_t& R(int r) {
|
||||
uint8_t R(int r) {
|
||||
__assume(r < 8);
|
||||
__assume(r >= 0);
|
||||
switch (r) {
|
||||
@ -73,8 +73,7 @@ namespace EightBit {
|
||||
case 0b101:
|
||||
return L();
|
||||
case 0b110:
|
||||
m_memory.ADDRESS() = HL();
|
||||
return m_memory.reference();
|
||||
return m_memory.read(HL());
|
||||
case 0b111:
|
||||
return A();
|
||||
default:
|
||||
@ -83,6 +82,39 @@ namespace EightBit {
|
||||
throw std::logic_error("Unhandled registry mechanism");
|
||||
}
|
||||
|
||||
void R(int r, uint8_t value) {
|
||||
__assume(r < 8);
|
||||
__assume(r >= 0);
|
||||
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:
|
||||
m_memory.write(HL(), value);
|
||||
break;
|
||||
case 0b111:
|
||||
A() = value;
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
}
|
||||
|
||||
register16_t& RP(int rp) {
|
||||
__assume(rp < 4);
|
||||
__assume(rp >= 0);
|
||||
|
@ -257,12 +257,12 @@ void EightBit::Intel8080::cmc(uint8_t& a, uint8_t& f) {
|
||||
|
||||
void EightBit::Intel8080::xhtl() {
|
||||
m_memory.ADDRESS() = SP();
|
||||
MEMPTR().low = m_memory.reference();
|
||||
m_memory.reference() = L();
|
||||
MEMPTR().low = m_memory.read(SP());
|
||||
m_memory.write(L());
|
||||
L() = MEMPTR().low;
|
||||
m_memory.ADDRESS().word++;
|
||||
MEMPTR().high = m_memory.reference();
|
||||
m_memory.reference() = H();
|
||||
MEMPTR().high = m_memory.read();
|
||||
m_memory.write(H());
|
||||
H() = MEMPTR().high;
|
||||
}
|
||||
|
||||
@ -336,12 +336,14 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) {
|
||||
switch (p) {
|
||||
case 0: // LD (BC),A
|
||||
MEMPTR() = BC();
|
||||
MEMPTR().high = memptrReference() = a;
|
||||
memptrReference();
|
||||
m_memory.write(MEMPTR().high = a);
|
||||
cycles += 7;
|
||||
break;
|
||||
case 1: // LD (DE),A
|
||||
MEMPTR() = DE();
|
||||
MEMPTR().high = memptrReference() = a;
|
||||
memptrReference();
|
||||
m_memory.write(MEMPTR().high = a);
|
||||
cycles += 7;
|
||||
break;
|
||||
case 2: // LD (nn),HL
|
||||
@ -351,7 +353,8 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) {
|
||||
break;
|
||||
case 3: // LD (nn),A
|
||||
fetchWord();
|
||||
MEMPTR().high = memptrReference() = a;
|
||||
memptrReference();
|
||||
m_memory.write(MEMPTR().high = a);
|
||||
cycles += 13;
|
||||
break;
|
||||
default:
|
||||
@ -362,12 +365,14 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) {
|
||||
switch (p) {
|
||||
case 0: // LD A,(BC)
|
||||
MEMPTR() = BC();
|
||||
a = memptrReference();
|
||||
memptrReference();
|
||||
a = m_memory.read();
|
||||
cycles += 7;
|
||||
break;
|
||||
case 1: // LD A,(DE)
|
||||
MEMPTR() = DE();
|
||||
a = memptrReference();
|
||||
memptrReference();
|
||||
a = m_memory.read();
|
||||
cycles += 7;
|
||||
break;
|
||||
case 2: // LD HL,(nn)
|
||||
@ -377,7 +382,8 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) {
|
||||
break;
|
||||
case 3: // LD A,(nn)
|
||||
fetchWord();
|
||||
a = memptrReference();
|
||||
memptrReference();
|
||||
a = m_memory.read();
|
||||
cycles += 13;
|
||||
break;
|
||||
default:
|
||||
@ -401,18 +407,22 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) {
|
||||
}
|
||||
cycles += 6;
|
||||
break;
|
||||
case 4: // 8-bit INC
|
||||
increment(f, R(y)); // INC r
|
||||
case 4: { // 8-bit INC
|
||||
auto operand = R(y);
|
||||
increment(f, operand);
|
||||
R(y, operand);
|
||||
cycles += 4;
|
||||
break;
|
||||
case 5: // 8-bit DEC
|
||||
decrement(f, R(y)); // DEC r
|
||||
} case 5: { // 8-bit DEC
|
||||
auto operand = R(y);
|
||||
decrement(f, operand);
|
||||
R(y, operand);
|
||||
cycles += 4;
|
||||
if (y == 6)
|
||||
cycles += 7;
|
||||
break;
|
||||
case 6: // 8-bit load immediate
|
||||
R(y) = fetchByte();
|
||||
} case 6: // 8-bit load immediate
|
||||
R(y, fetchByte());
|
||||
cycles += 7;
|
||||
if (y == 6)
|
||||
cycles += 3;
|
||||
@ -456,7 +466,7 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) {
|
||||
if (z == 6 && y == 6) { // Exception (replaces LD (HL), (HL))
|
||||
halt();
|
||||
} else {
|
||||
R(y) = R(z);
|
||||
R(y, R(z));
|
||||
if ((y == 6) || (z == 6)) // M operations
|
||||
cycles += 3;
|
||||
}
|
||||
|
@ -20,8 +20,7 @@ void Board::initialise() {
|
||||
m_memory.loadRam(romDirectory + "/8080EX1.COM", 0x100); // Cringle/Bartholomew
|
||||
//m_memory.loadRam(romDirectory + "/CPUTEST.COM", 0x100); // SuperSoft diagnostics
|
||||
|
||||
m_memory.ADDRESS().word = 5;
|
||||
m_memory.reference() = 0xc9; // ret
|
||||
m_memory.write(5, 0xc9); // ret
|
||||
m_cpu.ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Cpm, this, std::placeholders::_1));
|
||||
|
||||
if (m_configuration.isProfileMode()) {
|
||||
|
@ -54,40 +54,6 @@ namespace EightBit {
|
||||
virtual void reset();
|
||||
virtual void initialise();
|
||||
|
||||
protected:
|
||||
virtual uint8_t fetchByte() override {
|
||||
auto returned = IntelProcessor::fetchByte();
|
||||
m_memory.fireReadBusEvent();
|
||||
return returned;
|
||||
}
|
||||
|
||||
virtual void push(uint8_t value) override {
|
||||
IntelProcessor::push(value);
|
||||
m_memory.fireWriteBusEvent();
|
||||
}
|
||||
|
||||
virtual uint8_t pop() override {
|
||||
auto returned = IntelProcessor::pop();
|
||||
m_memory.fireReadBusEvent();
|
||||
return returned;
|
||||
}
|
||||
|
||||
virtual void getWordViaMemptr(register16_t& value) {
|
||||
value.low = memptrReference();
|
||||
m_memory.fireReadBusEvent();
|
||||
m_memory.ADDRESS().word++;
|
||||
value.high = m_memory.reference();
|
||||
m_memory.fireReadBusEvent();
|
||||
}
|
||||
|
||||
virtual void setWordViaMemptr(register16_t value) {
|
||||
memptrReference() = value.low;
|
||||
m_memory.fireWriteBusEvent();
|
||||
m_memory.ADDRESS().word++;
|
||||
m_memory.reference() = value.high;
|
||||
m_memory.fireWriteBusEvent();
|
||||
}
|
||||
|
||||
private:
|
||||
Bus& m_bus;
|
||||
|
||||
@ -102,7 +68,7 @@ namespace EightBit {
|
||||
|
||||
bool m_stopped;
|
||||
|
||||
uint8_t& R(int r, uint8_t& a) {
|
||||
uint8_t R(int r, uint8_t& a) {
|
||||
switch (r) {
|
||||
case 0:
|
||||
return B();
|
||||
@ -117,14 +83,42 @@ namespace EightBit {
|
||||
case 5:
|
||||
return L();
|
||||
case 6:
|
||||
m_memory.ADDRESS() = HL();
|
||||
return m_memory.reference();
|
||||
return m_memory.read(HL());
|
||||
case 7:
|
||||
return a;
|
||||
}
|
||||
throw std::logic_error("Unhandled registry mechanism");
|
||||
}
|
||||
|
||||
void R(int r, uint8_t& a, 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:
|
||||
m_memory.write(HL(), value);
|
||||
break;
|
||||
case 7:
|
||||
a = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
register16_t& RP(int rp) {
|
||||
__assume(rp < 4);
|
||||
__assume(rp >= 0);
|
||||
@ -192,17 +186,17 @@ namespace EightBit {
|
||||
static void orr(uint8_t& f, uint8_t& operand, uint8_t value);
|
||||
static void compare(uint8_t& f, uint8_t check, uint8_t value);
|
||||
|
||||
static void rlc(uint8_t& f, uint8_t& operand);
|
||||
static void rrc(uint8_t& f, uint8_t& operand);
|
||||
static void rl(uint8_t& f, uint8_t& operand);
|
||||
static void rr(uint8_t& f, uint8_t& operand);
|
||||
static void sla(uint8_t& f, uint8_t& operand);
|
||||
static void sra(uint8_t& f, uint8_t& operand);
|
||||
static void srl(uint8_t& f, uint8_t& operand);
|
||||
static uint8_t rlc(uint8_t& f, uint8_t operand);
|
||||
static uint8_t rrc(uint8_t& f, uint8_t operand);
|
||||
static uint8_t rl(uint8_t& f, uint8_t operand);
|
||||
static uint8_t rr(uint8_t& f, uint8_t operand);
|
||||
static uint8_t sla(uint8_t& f, uint8_t operand);
|
||||
static uint8_t sra(uint8_t& f, uint8_t operand);
|
||||
static uint8_t srl(uint8_t& f, uint8_t operand);
|
||||
|
||||
static void bit(uint8_t& f, int n, uint8_t& operand);
|
||||
static void res(int n, uint8_t& operand);
|
||||
static void set(int n, uint8_t& operand);
|
||||
static uint8_t bit(uint8_t& f, int n, uint8_t operand);
|
||||
static uint8_t res(int n, uint8_t operand);
|
||||
static uint8_t set(int n, uint8_t operand);
|
||||
|
||||
static void daa(uint8_t& a, uint8_t& f);
|
||||
|
||||
@ -210,6 +204,6 @@ namespace EightBit {
|
||||
static void ccf(uint8_t& a, uint8_t& f);
|
||||
static void cpl(uint8_t& a, uint8_t& f);
|
||||
|
||||
static void swap(uint8_t& f, uint8_t& operand);
|
||||
static uint8_t swap(uint8_t& f, uint8_t operand);
|
||||
};
|
||||
}
|
@ -212,76 +212,84 @@ void EightBit::LR35902::compare(uint8_t& f, uint8_t check, uint8_t value) {
|
||||
|
||||
#pragma region Shift and rotate
|
||||
|
||||
void EightBit::LR35902::rlc(uint8_t& f, uint8_t& operand) {
|
||||
uint8_t EightBit::LR35902::rlc(uint8_t& f, uint8_t operand) {
|
||||
clearFlag(f, NF | HC);
|
||||
setFlag(f, CF, operand & Bit7);
|
||||
operand = _rotl8(operand, 1);
|
||||
adjustZero<LR35902>(f, operand);
|
||||
return operand;
|
||||
}
|
||||
|
||||
void EightBit::LR35902::rrc(uint8_t& f, uint8_t& operand) {
|
||||
uint8_t EightBit::LR35902::rrc(uint8_t& f, uint8_t operand) {
|
||||
clearFlag(f, NF | HC);
|
||||
setFlag(f, CF, operand & Bit0);
|
||||
operand = _rotr8(operand, 1);
|
||||
adjustZero<LR35902>(f, operand);
|
||||
return operand;
|
||||
}
|
||||
|
||||
void EightBit::LR35902::rl(uint8_t& f, uint8_t& operand) {
|
||||
uint8_t EightBit::LR35902::rl(uint8_t& f, uint8_t operand) {
|
||||
clearFlag(f, NF | HC);
|
||||
const auto carry = (f & CF) >> 4;
|
||||
setFlag(f, CF, operand & Bit7);
|
||||
operand = (operand << 1) | carry;
|
||||
adjustZero<LR35902>(f, operand);
|
||||
return operand;
|
||||
}
|
||||
|
||||
void EightBit::LR35902::rr(uint8_t& f, uint8_t& operand) {
|
||||
uint8_t EightBit::LR35902::rr(uint8_t& f, uint8_t operand) {
|
||||
clearFlag(f, NF | HC);
|
||||
const auto carry = (f & CF) >> 4;
|
||||
setFlag(f, CF, operand & Bit0);
|
||||
operand = (operand >> 1) | (carry << 7);
|
||||
adjustZero<LR35902>(f, operand);
|
||||
return operand;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
void EightBit::LR35902::sla(uint8_t& f, uint8_t& operand) {
|
||||
uint8_t EightBit::LR35902::sla(uint8_t& f, uint8_t operand) {
|
||||
clearFlag(f, NF | HC);
|
||||
setFlag(f, CF, operand & Bit7);
|
||||
operand <<= 1;
|
||||
adjustZero<LR35902>(f, operand);
|
||||
return operand;
|
||||
}
|
||||
|
||||
void EightBit::LR35902::sra(uint8_t& f, uint8_t& operand) {
|
||||
uint8_t EightBit::LR35902::sra(uint8_t& f, uint8_t operand) {
|
||||
clearFlag(f, NF | HC);
|
||||
setFlag(f, CF, operand & Bit0);
|
||||
operand = (operand >> 1) | operand & Bit7;
|
||||
adjustZero<LR35902>(f, operand);
|
||||
return operand;
|
||||
}
|
||||
|
||||
void EightBit::LR35902::srl(uint8_t& f, uint8_t& operand) {
|
||||
uint8_t EightBit::LR35902::srl(uint8_t& f, uint8_t operand) {
|
||||
clearFlag(f, NF | HC);
|
||||
setFlag(f, CF, operand & Bit0);
|
||||
operand = (operand >> 1) & ~Bit7;
|
||||
adjustZero<LR35902>(f, operand);
|
||||
return operand;
|
||||
}
|
||||
|
||||
#pragma endregion Shift and rotate
|
||||
|
||||
#pragma region BIT/SET/RES
|
||||
|
||||
void EightBit::LR35902::bit(uint8_t& f, int n, uint8_t& operand) {
|
||||
uint8_t EightBit::LR35902::bit(uint8_t& f, int n, uint8_t operand) {
|
||||
auto carry = f & CF;
|
||||
uint8_t discarded = operand;
|
||||
andr(f, discarded, 1 << n);
|
||||
setFlag(f, CF, carry);
|
||||
return operand;
|
||||
}
|
||||
|
||||
void EightBit::LR35902::res(int n, uint8_t& operand) {
|
||||
operand &= ~(1 << n);
|
||||
uint8_t EightBit::LR35902::res(int n, uint8_t operand) {
|
||||
return operand & ~(1 << n);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::set(int n, uint8_t& operand) {
|
||||
operand |= (1 << n);
|
||||
uint8_t EightBit::LR35902::set(int n, uint8_t operand) {
|
||||
return operand | (1 << n);
|
||||
}
|
||||
|
||||
#pragma endregion BIT/SET/RES
|
||||
@ -326,12 +334,13 @@ void EightBit::LR35902::ccf(uint8_t& a, uint8_t& f) {
|
||||
clearFlag(f, CF, f & CF);
|
||||
}
|
||||
|
||||
void EightBit::LR35902::swap(uint8_t& f, uint8_t& operand) {
|
||||
uint8_t EightBit::LR35902::swap(uint8_t& f, uint8_t operand) {
|
||||
auto low = lowNibble(operand);
|
||||
auto high = highNibble(operand);
|
||||
operand = promoteNibble(low) | demoteNibble(high);
|
||||
adjustZero<LR35902>(f, operand);
|
||||
clearFlag(f, NF | HC | CF);
|
||||
return operand;
|
||||
}
|
||||
|
||||
#pragma endregion Miscellaneous instructions
|
||||
@ -369,64 +378,58 @@ void EightBit::LR35902::executeCB(int x, int y, int z, int p, int q) {
|
||||
auto& a = A();
|
||||
auto& f = F();
|
||||
switch (x) {
|
||||
case 0: // rot[y] r[z]
|
||||
case 0: { // rot[y] r[z]
|
||||
auto operand = R(z, a);
|
||||
switch (y) {
|
||||
case 0:
|
||||
rlc(f, R(z, a));
|
||||
operand = rlc(f, operand);
|
||||
break;
|
||||
case 1:
|
||||
rrc(f, R(z, a));
|
||||
operand = rrc(f, operand);
|
||||
break;
|
||||
case 2:
|
||||
rl(f, R(z, a));
|
||||
operand = rl(f, operand);
|
||||
break;
|
||||
case 3:
|
||||
rr(f, R(z, a));
|
||||
operand = rr(f, operand);
|
||||
break;
|
||||
case 4:
|
||||
sla(f, R(z, a));
|
||||
operand = sla(f, operand);
|
||||
break;
|
||||
case 5:
|
||||
sra(f, R(z, a));
|
||||
operand = sra(f, operand);
|
||||
break;
|
||||
case 6:
|
||||
swap(f, R(z, a));
|
||||
operand = swap(f, operand);
|
||||
break;
|
||||
case 7:
|
||||
srl(f, R(z, a));
|
||||
operand = srl(f, operand);
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
cycles += 2;
|
||||
if (z == 6) {
|
||||
m_bus.fireWriteBusEvent();
|
||||
R(z, a, operand);
|
||||
if (z == 6)
|
||||
cycles += 2;
|
||||
}
|
||||
break;
|
||||
case 1: // BIT y, r[z]
|
||||
} case 1: // BIT y, r[z]
|
||||
bit(f, y, R(z, a));
|
||||
cycles += 2;
|
||||
if (z == 6) {
|
||||
m_bus.fireReadBusEvent();
|
||||
if (z == 6)
|
||||
cycles += 2;
|
||||
}
|
||||
break;
|
||||
case 2: // RES y, r[z]
|
||||
res(y, R(z, a));
|
||||
R(z, a, res(y, R(z, a)));
|
||||
cycles += 2;
|
||||
if (z == 6) {
|
||||
m_bus.fireWriteBusEvent();
|
||||
if (z == 6)
|
||||
cycles += 2;
|
||||
}
|
||||
break;
|
||||
case 3: // SET y, r[z]
|
||||
set(y, R(z, a));
|
||||
R(z, a, set(y, R(z, a)));
|
||||
cycles += 2;
|
||||
if (z == 6) {
|
||||
m_bus.fireWriteBusEvent();
|
||||
if (z == 6)
|
||||
cycles += 2;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
@ -544,26 +547,24 @@ void EightBit::LR35902::executeOther(int x, int y, int z, int p, int q) {
|
||||
}
|
||||
cycles += 2;
|
||||
break;
|
||||
case 4: // 8-bit INC
|
||||
increment(f, R(y, a)); // INC r
|
||||
case 4: { // 8-bit INC
|
||||
auto operand = R(y, a);
|
||||
increment(f, operand);
|
||||
R(y, a, operand);
|
||||
cycles++;
|
||||
if (y == 6) {
|
||||
m_bus.fireWriteBusEvent();
|
||||
cycles += 2;
|
||||
}
|
||||
break;
|
||||
case 5: // 8-bit DEC
|
||||
decrement(f, R(y, a)); // DEC r
|
||||
cycles++;
|
||||
if (y == 6) {
|
||||
m_bus.fireWriteBusEvent();
|
||||
cycles += 2;
|
||||
}
|
||||
break;
|
||||
case 6: // 8-bit load immediate
|
||||
R(y, a) = fetchByte();
|
||||
if (y == 6)
|
||||
m_bus.fireWriteBusEvent();
|
||||
cycles += 2;
|
||||
break;
|
||||
} case 5: { // 8-bit DEC
|
||||
auto operand = R(y, a);
|
||||
decrement(f, operand);
|
||||
R(y, a, operand);
|
||||
cycles++;
|
||||
if (y == 6)
|
||||
cycles += 2;
|
||||
break;
|
||||
} case 6: // 8-bit load immediate
|
||||
R(y, a, fetchByte()); // LD r,n
|
||||
cycles += 2;
|
||||
break;
|
||||
case 7: // Assorted operations on accumulator/flags
|
||||
@ -603,14 +604,9 @@ void EightBit::LR35902::executeOther(int x, int y, int z, int p, int q) {
|
||||
if (z == 6 && y == 6) { // Exception (replaces LD (HL), (HL))
|
||||
halt();
|
||||
} else {
|
||||
R(y, a) = R(z, a);
|
||||
if ((y == 6) || (z == 6)) { // M operations
|
||||
if (y == 6)
|
||||
m_bus.fireWriteBusEvent();
|
||||
else
|
||||
m_bus.fireReadBusEvent();
|
||||
R(y, a, R(z, a));
|
||||
if ((y == 6) || (z == 6)) // M operations
|
||||
cycles++;
|
||||
}
|
||||
}
|
||||
cycles++;
|
||||
break;
|
||||
@ -644,10 +640,8 @@ void EightBit::LR35902::executeOther(int x, int y, int z, int p, int q) {
|
||||
__assume(0);
|
||||
}
|
||||
cycles++;
|
||||
if (z == 6) {
|
||||
m_bus.fireReadBusEvent();
|
||||
if (z == 6)
|
||||
cycles++;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch (z) {
|
||||
|
@ -40,11 +40,6 @@ namespace EightBit {
|
||||
CF = Bit0, // Carry
|
||||
};
|
||||
|
||||
enum BusDirection {
|
||||
Read,
|
||||
Write
|
||||
};
|
||||
|
||||
MOS6502(Memory& memory);
|
||||
virtual ~MOS6502();
|
||||
|
||||
@ -156,86 +151,118 @@ namespace EightBit {
|
||||
|
||||
#pragma endregion Addresses
|
||||
|
||||
#pragma region References
|
||||
#pragma region Addressing modes, read
|
||||
|
||||
uint8_t& AM_A() {
|
||||
m_busRW = false;
|
||||
uint8_t AM_A() {
|
||||
return A();
|
||||
}
|
||||
|
||||
uint8_t& AM_Immediate() {
|
||||
m_busRW = false;
|
||||
fetchByte();
|
||||
return m_memory.reference();
|
||||
uint8_t AM_Immediate() {
|
||||
return fetchByte();
|
||||
}
|
||||
|
||||
uint8_t& AM_Absolute() {
|
||||
m_busRW = true;
|
||||
uint8_t AM_Absolute() {
|
||||
Address_Absolute();
|
||||
m_memory.ADDRESS() = MEMPTR();
|
||||
return m_memory.reference();
|
||||
return m_memory.read(MEMPTR());
|
||||
}
|
||||
|
||||
uint8_t& AM_ZeroPage() {
|
||||
m_busRW = true;
|
||||
uint8_t AM_ZeroPage() {
|
||||
Address_ZeroPage();
|
||||
m_memory.ADDRESS() = MEMPTR();
|
||||
return m_memory.reference();
|
||||
return m_memory.read(MEMPTR());
|
||||
}
|
||||
|
||||
uint8_t& AM_AbsoluteX(BusDirection direction = BusDirection::Read) {
|
||||
m_busRW = true;
|
||||
uint8_t AM_AbsoluteX() {
|
||||
Address_AbsoluteX();
|
||||
m_memory.ADDRESS() = MEMPTR();
|
||||
if ((direction == BusDirection::Read) && (m_memory.ADDRESS().low == Mask8))
|
||||
if (m_memory.ADDRESS().low == Mask8)
|
||||
++cycles;
|
||||
return m_memory.reference();
|
||||
return m_memory.read();
|
||||
}
|
||||
|
||||
uint8_t& AM_AbsoluteY(BusDirection direction = BusDirection::Read) {
|
||||
m_busRW = true;
|
||||
uint8_t AM_AbsoluteY() {
|
||||
Address_AbsoluteY();
|
||||
m_memory.ADDRESS() = MEMPTR();
|
||||
if ((direction == BusDirection::Read) && (m_memory.ADDRESS().low == Mask8))
|
||||
if (m_memory.ADDRESS().low == Mask8)
|
||||
++cycles;
|
||||
return m_memory.reference();
|
||||
return m_memory.read();
|
||||
}
|
||||
|
||||
uint8_t& AM_ZeroPageX() {
|
||||
m_busRW = true;
|
||||
uint8_t AM_ZeroPageX() {
|
||||
Address_ZeroPageX();
|
||||
m_memory.ADDRESS() = MEMPTR();
|
||||
return m_memory.reference();
|
||||
return m_memory.read(MEMPTR());
|
||||
}
|
||||
|
||||
uint8_t& AM_ZeroPageY() {
|
||||
m_busRW = true;
|
||||
uint8_t AM_ZeroPageY() {
|
||||
Address_ZeroPageY();
|
||||
m_memory.ADDRESS() = MEMPTR();
|
||||
return m_memory.reference();
|
||||
return m_memory.read(MEMPTR());
|
||||
}
|
||||
|
||||
uint8_t& AM_IndexedIndirectX() {
|
||||
m_busRW = true;
|
||||
uint8_t AM_IndexedIndirectX() {
|
||||
Address_IndexedIndirectX();
|
||||
m_memory.ADDRESS() = MEMPTR();
|
||||
return m_memory.reference();
|
||||
return m_memory.read(MEMPTR());
|
||||
}
|
||||
|
||||
uint8_t& AM_IndirectIndexedY(BusDirection direction = BusDirection::Read) {
|
||||
m_busRW = true;
|
||||
uint8_t AM_IndirectIndexedY() {
|
||||
Address_IndirectIndexedY();
|
||||
m_memory.ADDRESS() = MEMPTR();
|
||||
if ((direction == BusDirection::Read) && (m_memory.ADDRESS().low == Mask8))
|
||||
if (m_memory.ADDRESS().low == Mask8)
|
||||
++cycles;
|
||||
return m_memory.reference();
|
||||
return m_memory.read();
|
||||
}
|
||||
|
||||
#pragma endregion References
|
||||
#pragma endregion Addressing modes, read
|
||||
|
||||
#pragma region Addressing modes, write
|
||||
|
||||
void AM_A(uint8_t value) {
|
||||
A() = value;
|
||||
}
|
||||
|
||||
void AM_Absolute(uint8_t value) {
|
||||
Address_Absolute();
|
||||
m_memory.write(MEMPTR(), value);
|
||||
}
|
||||
|
||||
void AM_ZeroPage(uint8_t value) {
|
||||
Address_ZeroPage();
|
||||
m_memory.write(MEMPTR(), value);
|
||||
}
|
||||
|
||||
void AM_AbsoluteX(uint8_t value) {
|
||||
Address_AbsoluteX();
|
||||
m_memory.write(MEMPTR(), value);
|
||||
}
|
||||
|
||||
void AM_AbsoluteY(uint8_t value) {
|
||||
Address_AbsoluteY();
|
||||
m_memory.write(MEMPTR(), value);
|
||||
}
|
||||
|
||||
void AM_ZeroPageX(uint8_t value) {
|
||||
Address_ZeroPageX();
|
||||
m_memory.write(MEMPTR(), value);
|
||||
}
|
||||
|
||||
void AM_ZeroPageY(uint8_t value) {
|
||||
Address_ZeroPageY();
|
||||
m_memory.write(MEMPTR(), value);
|
||||
}
|
||||
|
||||
void AM_IndexedIndirectX(uint8_t value) {
|
||||
Address_IndexedIndirectX();
|
||||
m_memory.write(MEMPTR(), value);
|
||||
}
|
||||
|
||||
void AM_IndirectIndexedY(uint8_t value) {
|
||||
Address_IndirectIndexedY();
|
||||
m_memory.write(MEMPTR(), value);
|
||||
}
|
||||
|
||||
#pragma endregion Addressing modes, write
|
||||
|
||||
#pragma region 6502 addressing mode switching
|
||||
|
||||
uint8_t& AM_00(int bbb, BusDirection direction = BusDirection::Read) {
|
||||
uint8_t AM_00(int bbb) {
|
||||
switch (bbb) {
|
||||
case 0b000:
|
||||
return AM_Immediate();
|
||||
@ -246,7 +273,7 @@ namespace EightBit {
|
||||
case 0b101:
|
||||
return AM_ZeroPageX();
|
||||
case 0b111:
|
||||
return AM_AbsoluteX(direction);
|
||||
return AM_AbsoluteX();
|
||||
case 0b010:
|
||||
case 0b100:
|
||||
case 0b110:
|
||||
@ -256,7 +283,33 @@ namespace EightBit {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t& AM_01(int bbb, BusDirection direction = BusDirection::Read) {
|
||||
void AM_00(int bbb, uint8_t value) {
|
||||
switch (bbb) {
|
||||
case 0b000:
|
||||
assert(false);
|
||||
break;
|
||||
case 0b001:
|
||||
AM_ZeroPage(value);
|
||||
break;
|
||||
case 0b011:
|
||||
AM_Absolute(value);
|
||||
break;
|
||||
case 0b101:
|
||||
AM_ZeroPageX(value);
|
||||
break;
|
||||
case 0b111:
|
||||
AM_AbsoluteX(value);
|
||||
break;
|
||||
case 0b010:
|
||||
case 0b100:
|
||||
case 0b110:
|
||||
throw std::domain_error("Illegal addressing mode");
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t AM_01(int bbb) {
|
||||
switch (bbb) {
|
||||
case 0b000:
|
||||
return AM_IndexedIndirectX();
|
||||
@ -267,19 +320,50 @@ namespace EightBit {
|
||||
case 0b011:
|
||||
return AM_Absolute();
|
||||
case 0b100:
|
||||
return AM_IndirectIndexedY(direction);
|
||||
return AM_IndirectIndexedY();
|
||||
case 0b101:
|
||||
return AM_ZeroPageX();
|
||||
case 0b110:
|
||||
return AM_AbsoluteY(direction);
|
||||
return AM_AbsoluteY();
|
||||
case 0b111:
|
||||
return AM_AbsoluteX(direction);
|
||||
return AM_AbsoluteX();
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t& AM_10(int bbb, BusDirection direction = BusDirection::Read) {
|
||||
uint8_t AM_01(int bbb, uint8_t value) {
|
||||
switch (bbb) {
|
||||
case 0b000:
|
||||
AM_IndexedIndirectX(value);
|
||||
break;
|
||||
case 0b001:
|
||||
AM_ZeroPage(value);
|
||||
break;
|
||||
case 0b010:
|
||||
assert(false);
|
||||
break;
|
||||
case 0b011:
|
||||
AM_Absolute(value);
|
||||
break;
|
||||
case 0b100:
|
||||
AM_IndirectIndexedY(value);
|
||||
break;
|
||||
case 0b101:
|
||||
AM_ZeroPageX(value);
|
||||
break;
|
||||
case 0b110:
|
||||
AM_AbsoluteY(value);
|
||||
break;
|
||||
case 0b111:
|
||||
AM_AbsoluteX(value);
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t AM_10(int bbb) {
|
||||
switch (bbb) {
|
||||
case 0b000:
|
||||
return AM_Immediate();
|
||||
@ -292,7 +376,36 @@ namespace EightBit {
|
||||
case 0b101:
|
||||
return AM_ZeroPageX();
|
||||
case 0b111:
|
||||
return AM_AbsoluteX(direction);
|
||||
return AM_AbsoluteX();
|
||||
case 0b100:
|
||||
case 0b110:
|
||||
throw std::domain_error("Illegal addressing mode");
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
void AM_10(int bbb, uint8_t value) {
|
||||
switch (bbb) {
|
||||
case 0b000:
|
||||
assert(false);
|
||||
break;
|
||||
case 0b001:
|
||||
AM_ZeroPage(value);
|
||||
break;
|
||||
case 0b010:
|
||||
AM_A(value);
|
||||
break;
|
||||
case 0b011:
|
||||
AM_Absolute(value);
|
||||
break;
|
||||
case 0b101:
|
||||
AM_ZeroPageX(value);
|
||||
break;
|
||||
case 0b111:
|
||||
AM_AbsoluteX(value);
|
||||
break;
|
||||
case 0b100:
|
||||
case 0b110:
|
||||
throw std::domain_error("Illegal addressing mode");
|
||||
@ -301,7 +414,7 @@ namespace EightBit {
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t& AM_10_x(int bbb, BusDirection direction = BusDirection::Read) {
|
||||
uint8_t AM_10_x(int bbb) {
|
||||
switch (bbb) {
|
||||
case 0b000:
|
||||
return AM_Immediate();
|
||||
@ -314,7 +427,35 @@ namespace EightBit {
|
||||
case 0b101:
|
||||
return AM_ZeroPageY();
|
||||
case 0b111:
|
||||
return AM_AbsoluteY(direction);
|
||||
return AM_AbsoluteY();
|
||||
case 0b100:
|
||||
case 0b110:
|
||||
throw std::domain_error("Illegal addressing mode");
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
}
|
||||
|
||||
void AM_10_x(int bbb, uint8_t value) {
|
||||
switch (bbb) {
|
||||
case 0b000:
|
||||
assert(false);
|
||||
break;
|
||||
case 0b001:
|
||||
AM_ZeroPage(value);
|
||||
break;
|
||||
case 0b010:
|
||||
AM_A(value);
|
||||
break;
|
||||
case 0b011:
|
||||
AM_Absolute(value);
|
||||
break;
|
||||
case 0b101:
|
||||
AM_ZeroPageY(value);
|
||||
break;
|
||||
case 0b111:
|
||||
AM_AbsoluteY(value);
|
||||
break;
|
||||
case 0b100:
|
||||
case 0b110:
|
||||
throw std::domain_error("Illegal addressing mode");
|
||||
@ -327,59 +468,40 @@ namespace EightBit {
|
||||
|
||||
#pragma endregion 6502 addressing modes
|
||||
|
||||
void firePendingBusEvents(BusDirection direction) {
|
||||
if (m_busRW) {
|
||||
switch (direction) {
|
||||
case BusDirection::Read:
|
||||
m_memory.fireReadBusEvent();
|
||||
break;
|
||||
case BusDirection::Write:
|
||||
m_memory.fireWriteBusEvent();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ASL(int bbb) {
|
||||
auto& reference = AM_10(bbb, BusDirection::Write);
|
||||
firePendingBusEvents(BusDirection::Read);
|
||||
ASL(reference);
|
||||
firePendingBusEvents(BusDirection::Write);
|
||||
auto operand = AM_10(bbb);
|
||||
ASL(operand);
|
||||
AM_10(bbb, operand);
|
||||
}
|
||||
|
||||
void ROL(int bbb) {
|
||||
auto& reference = AM_10(bbb, BusDirection::Write);
|
||||
firePendingBusEvents(BusDirection::Read);
|
||||
ROL(reference);
|
||||
firePendingBusEvents(BusDirection::Write);
|
||||
auto operand = AM_10(bbb);
|
||||
ROL(operand);
|
||||
AM_10(bbb, operand);
|
||||
}
|
||||
|
||||
void LSR(int bbb) {
|
||||
auto& reference = AM_10(bbb, BusDirection::Write);
|
||||
firePendingBusEvents(BusDirection::Read);
|
||||
LSR(reference);
|
||||
firePendingBusEvents(BusDirection::Write);
|
||||
auto operand = AM_10(bbb);
|
||||
LSR(operand);
|
||||
AM_10(bbb, operand);
|
||||
}
|
||||
|
||||
void ROR(int bbb) {
|
||||
auto& reference = AM_10(bbb, BusDirection::Write);
|
||||
firePendingBusEvents(BusDirection::Read);
|
||||
ROR(reference);
|
||||
firePendingBusEvents(BusDirection::Write);
|
||||
auto operand = AM_10(bbb);
|
||||
ROR(operand);
|
||||
AM_10(bbb, operand);
|
||||
}
|
||||
|
||||
void DEC(int bbb) {
|
||||
auto& reference = AM_10(bbb, BusDirection::Write);
|
||||
firePendingBusEvents(BusDirection::Read);
|
||||
adjustNZ(--reference);
|
||||
firePendingBusEvents(BusDirection::Write);
|
||||
auto operand = AM_10(bbb);
|
||||
adjustNZ(--operand);
|
||||
AM_10(bbb, operand);
|
||||
}
|
||||
|
||||
void INC(int bbb) {
|
||||
auto& reference = AM_10(bbb, BusDirection::Write);
|
||||
firePendingBusEvents(BusDirection::Read);
|
||||
adjustNZ(++reference);
|
||||
firePendingBusEvents(BusDirection::Write);
|
||||
auto operand = AM_10(bbb);
|
||||
adjustNZ(++operand);
|
||||
AM_10(bbb, operand);
|
||||
}
|
||||
|
||||
void ROR(uint8_t& output);
|
||||
@ -431,7 +553,5 @@ namespace EightBit {
|
||||
|
||||
std::array<int, 0x100> m_timings;
|
||||
std::array<opcode_decoded_t, 0x100> m_decodedOpcodes;
|
||||
|
||||
bool m_busRW;
|
||||
};
|
||||
}
|
@ -135,7 +135,6 @@ int EightBit::MOS6502::execute(uint8_t cell) {
|
||||
break;
|
||||
default: // BIT
|
||||
BIT(AM_00(decoded.bbb));
|
||||
firePendingBusEvents(BusDirection::Read);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -193,8 +192,7 @@ int EightBit::MOS6502::execute(uint8_t cell) {
|
||||
adjustNZ(A() = Y());
|
||||
break;
|
||||
default: // STY
|
||||
AM_00(decoded.bbb, BusDirection::Write) = Y();
|
||||
firePendingBusEvents(BusDirection::Write);
|
||||
AM_00(decoded.bbb, Y());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -211,7 +209,6 @@ int EightBit::MOS6502::execute(uint8_t cell) {
|
||||
break;
|
||||
default: // LDY
|
||||
adjustNZ(Y() = AM_00(decoded.bbb));
|
||||
firePendingBusEvents(BusDirection::Read);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -228,7 +225,6 @@ int EightBit::MOS6502::execute(uint8_t cell) {
|
||||
break;
|
||||
default: // CPY
|
||||
CMP(Y(), AM_00(decoded.bbb));
|
||||
firePendingBusEvents(BusDirection::Read);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -245,7 +241,6 @@ int EightBit::MOS6502::execute(uint8_t cell) {
|
||||
break;
|
||||
default: // CPX
|
||||
CMP(X(), AM_00(decoded.bbb));
|
||||
firePendingBusEvents(BusDirection::Read);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -255,35 +250,27 @@ int EightBit::MOS6502::execute(uint8_t cell) {
|
||||
switch (decoded.aaa) {
|
||||
case 0b000: // ORA
|
||||
adjustNZ(A() |= AM_01(decoded.bbb));
|
||||
firePendingBusEvents(BusDirection::Read);
|
||||
break;
|
||||
case 0b001: // AND
|
||||
adjustNZ(A() &= AM_01(decoded.bbb));
|
||||
firePendingBusEvents(BusDirection::Read);
|
||||
break;
|
||||
case 0b010: // EOR
|
||||
adjustNZ(A() ^= AM_01(decoded.bbb));
|
||||
firePendingBusEvents(BusDirection::Read);
|
||||
break;
|
||||
case 0b011: // ADC
|
||||
ADC(AM_01(decoded.bbb));
|
||||
firePendingBusEvents(BusDirection::Read);
|
||||
break;
|
||||
case 0b100: // STA
|
||||
AM_01(decoded.bbb, BusDirection::Write) = A();
|
||||
firePendingBusEvents(BusDirection::Write);
|
||||
AM_01(decoded.bbb, A());
|
||||
break;
|
||||
case 0b101: // LDA
|
||||
adjustNZ(A() = AM_01(decoded.bbb));
|
||||
firePendingBusEvents(BusDirection::Read);
|
||||
break;
|
||||
case 0b110: // CMP
|
||||
CMP(A(), AM_01(decoded.bbb));
|
||||
firePendingBusEvents(BusDirection::Read);
|
||||
break;
|
||||
case 0b111: // SBC
|
||||
SBC(AM_01(decoded.bbb));
|
||||
firePendingBusEvents(BusDirection::Read);
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
@ -312,8 +299,7 @@ int EightBit::MOS6502::execute(uint8_t cell) {
|
||||
S() = X();
|
||||
break;
|
||||
default: // STX
|
||||
AM_10_x(decoded.bbb, BusDirection::Write) = X();
|
||||
firePendingBusEvents(BusDirection::Write);
|
||||
AM_10_x(decoded.bbb, X());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -324,7 +310,6 @@ int EightBit::MOS6502::execute(uint8_t cell) {
|
||||
break;
|
||||
default: // LDX
|
||||
adjustNZ(X() = AM_10_x(decoded.bbb));
|
||||
firePendingBusEvents(BusDirection::Read);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -113,7 +113,7 @@ void Board::Memory_ReadByte_Input(const EightBit::AddressEventArgs& e) {
|
||||
auto cell = e.getCell();
|
||||
if (cell != 0) {
|
||||
assert(address == m_memory.ADDRESS().word);
|
||||
m_memory.reference() = 0;
|
||||
m_memory.write(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -132,8 +132,6 @@ void Board::Cpu_ExecutedInstruction_Poll(const EightBit::MOS6502& cpu) {
|
||||
}
|
||||
|
||||
void Board::pollKeyboard() {
|
||||
if (_kbhit()) {
|
||||
m_memory.ADDRESS().word = m_configuration.getInputAddress();
|
||||
m_memory.reference() = _getch();
|
||||
}
|
||||
if (_kbhit())
|
||||
m_memory.write(m_configuration.getInputAddress(), _getch());
|
||||
}
|
@ -55,10 +55,8 @@ void Fuse::TestRunner::initialiseMemory() {
|
||||
for (auto memoryDatum : m_test.memoryData) {
|
||||
auto address = memoryDatum.address;
|
||||
auto bytes = memoryDatum.bytes;
|
||||
for (int i = 0; i < bytes.size(); ++i) {
|
||||
m_memory.ADDRESS().word = address + i;
|
||||
m_memory.reference() = bytes[i];
|
||||
}
|
||||
for (int i = 0; i < bytes.size(); ++i)
|
||||
m_memory.write(address + i, bytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
109
Z80/inc/Z80.h
109
Z80/inc/Z80.h
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
#include "IntelProcessor.h"
|
||||
#include "InputOutput.h"
|
||||
@ -136,12 +137,16 @@ namespace EightBit {
|
||||
return IntelProcessor::fetchExecute();
|
||||
}
|
||||
|
||||
uint8_t& DISPLACED() {
|
||||
m_memory.ADDRESS().word = MEMPTR().word = (m_prefixDD ? IX() : IY()).word + m_displacement;
|
||||
return m_memory.reference();
|
||||
uint16_t displacedAddress() {
|
||||
assert(m_displaced);
|
||||
return MEMPTR().word = (m_prefixDD ? IX() : IY()).word + m_displacement;
|
||||
}
|
||||
|
||||
uint8_t& R(int r, uint8_t& a) {
|
||||
void fetchDisplacement() {
|
||||
m_displacement = fetchByte();
|
||||
}
|
||||
|
||||
uint8_t R(int r, uint8_t a) {
|
||||
switch (r) {
|
||||
case 0:
|
||||
return B();
|
||||
@ -156,12 +161,7 @@ namespace EightBit {
|
||||
case 5:
|
||||
return HL2().low;
|
||||
case 6:
|
||||
if (!m_displaced) {
|
||||
m_memory.ADDRESS() = HL();
|
||||
return m_memory.reference();
|
||||
}
|
||||
m_displacement = fetchByte();
|
||||
return DISPLACED();
|
||||
return m_memory.read(m_displaced ? displacedAddress() : HL().word);
|
||||
case 7:
|
||||
return a;
|
||||
default:
|
||||
@ -170,7 +170,38 @@ namespace EightBit {
|
||||
throw std::logic_error("Unhandled registry mechanism");
|
||||
}
|
||||
|
||||
uint8_t& R2(int r, uint8_t& a) {
|
||||
void R(int r, uint8_t& a, 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:
|
||||
m_memory.write(m_displaced ? displacedAddress() : HL().word, value);
|
||||
break;
|
||||
case 7:
|
||||
a = value;
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t R2(int r, const uint8_t& a) {
|
||||
switch (r) {
|
||||
case 0:
|
||||
return B();
|
||||
@ -185,8 +216,7 @@ namespace EightBit {
|
||||
case 5:
|
||||
return L();
|
||||
case 6:
|
||||
m_memory.ADDRESS() = HL();
|
||||
return m_memory.reference();
|
||||
return m_memory.read(HL());
|
||||
case 7:
|
||||
return a;
|
||||
default:
|
||||
@ -195,6 +225,37 @@ namespace EightBit {
|
||||
throw std::logic_error("Unhandled registry mechanism");
|
||||
}
|
||||
|
||||
void R2(int r, uint8_t& a, 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:
|
||||
m_memory.write(HL(), value);
|
||||
break;
|
||||
case 7:
|
||||
a = value;
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
}
|
||||
|
||||
register16_t& RP(int rp) {
|
||||
__assume(rp < 4);
|
||||
__assume(rp >= 0);
|
||||
@ -286,18 +347,18 @@ namespace EightBit {
|
||||
static void orr(uint8_t& f, uint8_t& operand, uint8_t value);
|
||||
static void compare(uint8_t& f, uint8_t check, uint8_t value);
|
||||
|
||||
static uint8_t& rlc(uint8_t& f, uint8_t& operand);
|
||||
static uint8_t& rrc(uint8_t& f, uint8_t& operand);
|
||||
static uint8_t& rl(uint8_t& f, uint8_t& operand);
|
||||
static uint8_t& rr(uint8_t& f, uint8_t& operand);
|
||||
static uint8_t& sla(uint8_t& f, uint8_t& operand);
|
||||
static uint8_t& sra(uint8_t& f, uint8_t& operand);
|
||||
static uint8_t& sll(uint8_t& f, uint8_t& operand);
|
||||
static uint8_t& srl(uint8_t& f, uint8_t& operand);
|
||||
static uint8_t rlc(uint8_t& f, uint8_t operand);
|
||||
static uint8_t rrc(uint8_t& f, uint8_t operand);
|
||||
static uint8_t rl(uint8_t& f, uint8_t operand);
|
||||
static uint8_t rr(uint8_t& f, uint8_t operand);
|
||||
static uint8_t sla(uint8_t& f, uint8_t operand);
|
||||
static uint8_t sra(uint8_t& f, uint8_t operand);
|
||||
static uint8_t sll(uint8_t& f, uint8_t operand);
|
||||
static uint8_t srl(uint8_t& f, uint8_t operand);
|
||||
|
||||
static uint8_t& bit(uint8_t& f, int n, uint8_t& operand);
|
||||
static uint8_t& res(int n, uint8_t& operand);
|
||||
static uint8_t& set(int n, uint8_t& operand);
|
||||
static uint8_t bit(uint8_t& f, int n, uint8_t operand);
|
||||
static uint8_t res(int n, uint8_t operand);
|
||||
static uint8_t set(int n, uint8_t operand);
|
||||
|
||||
static void daa(uint8_t& a, uint8_t& f);
|
||||
|
||||
|
@ -181,15 +181,14 @@ void EightBit::Disassembler::disassemble(std::ostringstream& output, const Z80&
|
||||
const auto& memory = cpu.getMemory();
|
||||
auto opcode = memory.peek(pc);
|
||||
|
||||
// hex opcode
|
||||
output << hex(opcode);
|
||||
const auto& decoded = cpu.getDecodedOpcode(opcode);
|
||||
|
||||
auto x = (opcode & 0b11000000) >> 6;
|
||||
auto y = (opcode & 0b111000) >> 3;
|
||||
auto z = (opcode & 0b111);
|
||||
auto x = decoded.x;
|
||||
auto y = decoded.y;
|
||||
auto z = decoded.z;
|
||||
|
||||
auto p = (y & 0b110) >> 1;
|
||||
auto q = (y & 1);
|
||||
auto p = decoded.p;
|
||||
auto q = decoded.q;
|
||||
|
||||
auto immediate = memory.peek(pc + 1);
|
||||
auto absolute = memory.peekWord(pc + 1);
|
||||
@ -199,6 +198,8 @@ void EightBit::Disassembler::disassemble(std::ostringstream& output, const Z80&
|
||||
|
||||
auto dumpCount = 0;
|
||||
|
||||
output << hex(opcode);
|
||||
|
||||
std::string specification = "";
|
||||
|
||||
if (m_prefixCB)
|
||||
|
182
Z80/src/Z80.cpp
182
Z80/src/Z80.cpp
@ -361,7 +361,7 @@ void EightBit::Z80::compare(uint8_t& f, uint8_t check, uint8_t value) {
|
||||
|
||||
#pragma region Shift and rotate
|
||||
|
||||
uint8_t& EightBit::Z80::rlc(uint8_t& f, uint8_t& operand) {
|
||||
uint8_t EightBit::Z80::rlc(uint8_t& f, uint8_t operand) {
|
||||
clearFlag(f, NF | HC);
|
||||
setFlag(f, CF, operand & Bit7);
|
||||
operand = _rotl8(operand, 1);
|
||||
@ -369,7 +369,7 @@ uint8_t& EightBit::Z80::rlc(uint8_t& f, uint8_t& operand) {
|
||||
return operand;
|
||||
}
|
||||
|
||||
uint8_t& EightBit::Z80::rrc(uint8_t& f, uint8_t& operand) {
|
||||
uint8_t EightBit::Z80::rrc(uint8_t& f, uint8_t operand) {
|
||||
clearFlag(f, NF | HC);
|
||||
setFlag(f, CF, operand & Bit0);
|
||||
operand = _rotr8(operand, 1);
|
||||
@ -377,7 +377,7 @@ uint8_t& EightBit::Z80::rrc(uint8_t& f, uint8_t& operand) {
|
||||
return operand;
|
||||
}
|
||||
|
||||
uint8_t& EightBit::Z80::rl(uint8_t& f, uint8_t& operand) {
|
||||
uint8_t EightBit::Z80::rl(uint8_t& f, uint8_t operand) {
|
||||
clearFlag(f, NF | HC);
|
||||
const auto carry = f & CF;
|
||||
setFlag(f, CF, operand & Bit7);
|
||||
@ -386,7 +386,7 @@ uint8_t& EightBit::Z80::rl(uint8_t& f, uint8_t& operand) {
|
||||
return operand;
|
||||
}
|
||||
|
||||
uint8_t& EightBit::Z80::rr(uint8_t& f, uint8_t& operand) {
|
||||
uint8_t EightBit::Z80::rr(uint8_t& f, uint8_t operand) {
|
||||
clearFlag(f, NF | HC);
|
||||
const auto carry = f & CF;
|
||||
setFlag(f, CF, operand & Bit0);
|
||||
@ -397,7 +397,7 @@ uint8_t& EightBit::Z80::rr(uint8_t& f, uint8_t& operand) {
|
||||
|
||||
//
|
||||
|
||||
uint8_t& EightBit::Z80::sla(uint8_t& f, uint8_t& operand) {
|
||||
uint8_t EightBit::Z80::sla(uint8_t& f, uint8_t operand) {
|
||||
clearFlag(f, NF | HC);
|
||||
setFlag(f, CF, operand & Bit7);
|
||||
operand <<= 1;
|
||||
@ -405,7 +405,7 @@ uint8_t& EightBit::Z80::sla(uint8_t& f, uint8_t& operand) {
|
||||
return operand;
|
||||
}
|
||||
|
||||
uint8_t& EightBit::Z80::sra(uint8_t& f, uint8_t& operand) {
|
||||
uint8_t EightBit::Z80::sra(uint8_t& f, uint8_t operand) {
|
||||
clearFlag(f, NF | HC);
|
||||
setFlag(f, CF, operand & Bit0);
|
||||
operand = (operand >> 1) | operand & Bit7;
|
||||
@ -413,7 +413,7 @@ uint8_t& EightBit::Z80::sra(uint8_t& f, uint8_t& operand) {
|
||||
return operand;
|
||||
}
|
||||
|
||||
uint8_t& EightBit::Z80::sll(uint8_t& f, uint8_t& operand) {
|
||||
uint8_t EightBit::Z80::sll(uint8_t& f, uint8_t operand) {
|
||||
clearFlag(f, NF | HC);
|
||||
setFlag(f, CF, operand & Bit7);
|
||||
operand = (operand << 1) | Bit0;
|
||||
@ -421,7 +421,7 @@ uint8_t& EightBit::Z80::sll(uint8_t& f, uint8_t& operand) {
|
||||
return operand;
|
||||
}
|
||||
|
||||
uint8_t& EightBit::Z80::srl(uint8_t& f, uint8_t& operand) {
|
||||
uint8_t EightBit::Z80::srl(uint8_t& f, uint8_t operand) {
|
||||
clearFlag(f, NF | HC);
|
||||
setFlag(f, CF, operand & Bit0);
|
||||
operand = (operand >> 1) & ~Bit7;
|
||||
@ -434,7 +434,7 @@ uint8_t& EightBit::Z80::srl(uint8_t& f, uint8_t& operand) {
|
||||
|
||||
#pragma region BIT/SET/RES
|
||||
|
||||
uint8_t& EightBit::Z80::bit(uint8_t& f, int n, uint8_t& operand) {
|
||||
uint8_t EightBit::Z80::bit(uint8_t& f, int n, uint8_t operand) {
|
||||
setFlag(f, HC);
|
||||
clearFlag(f, NF);
|
||||
const auto discarded = operand & (1 << n);
|
||||
@ -443,12 +443,12 @@ uint8_t& EightBit::Z80::bit(uint8_t& f, int n, uint8_t& operand) {
|
||||
return operand;
|
||||
}
|
||||
|
||||
uint8_t& EightBit::Z80::res(int n, uint8_t& operand) {
|
||||
return operand &= ~(1 << n);
|
||||
uint8_t EightBit::Z80::res(int n, uint8_t operand) {
|
||||
return operand & ~(1 << n);
|
||||
}
|
||||
|
||||
uint8_t& EightBit::Z80::set(int n, uint8_t& operand) {
|
||||
return operand |= (1 << n);
|
||||
uint8_t EightBit::Z80::set(int n, uint8_t operand) {
|
||||
return operand | (1 << n);
|
||||
}
|
||||
|
||||
#pragma endregion BIT/SET/RES
|
||||
@ -516,13 +516,12 @@ void EightBit::Z80::ccf(uint8_t a, uint8_t& f) {
|
||||
}
|
||||
|
||||
void EightBit::Z80::xhtl(register16_t& operand) {
|
||||
m_memory.ADDRESS() = SP();
|
||||
MEMPTR().low = m_memory.reference();
|
||||
m_memory.reference() = operand.low;
|
||||
MEMPTR().low = m_memory.read(SP());
|
||||
m_memory.write(operand.low);
|
||||
operand.low = MEMPTR().low;
|
||||
m_memory.ADDRESS().word++;
|
||||
MEMPTR().high = m_memory.reference();
|
||||
m_memory.reference() = operand.high;
|
||||
MEMPTR().high = m_memory.read();
|
||||
m_memory.write(operand.high);
|
||||
operand.high = MEMPTR().high;
|
||||
}
|
||||
|
||||
@ -534,9 +533,7 @@ void EightBit::Z80::xhtl(register16_t& operand) {
|
||||
|
||||
void EightBit::Z80::blockCompare(uint8_t a, uint8_t& f) {
|
||||
|
||||
m_memory.ADDRESS() = HL();
|
||||
|
||||
const auto value = m_memory.reference();
|
||||
const auto value = m_memory.read(HL());
|
||||
uint8_t result = a - value;
|
||||
|
||||
setFlag(f, PF, --BC().word);
|
||||
@ -586,11 +583,9 @@ bool EightBit::Z80::cpdr(uint8_t a, uint8_t& f) {
|
||||
#pragma region Block load instructions
|
||||
|
||||
void EightBit::Z80::blockLoad(uint8_t a, uint8_t& f, register16_t source, register16_t destination) {
|
||||
m_memory.ADDRESS() = source;
|
||||
auto value = m_memory.reference();
|
||||
m_memory.ADDRESS() = destination;
|
||||
m_memory.reference() = value;
|
||||
auto xy = a + value;
|
||||
const auto value = m_memory.read(source);
|
||||
m_memory.write(destination, value);
|
||||
const auto xy = a + value;
|
||||
setFlag(f, XF, xy & 8);
|
||||
setFlag(f, YF, xy & 2);
|
||||
clearFlag(f, NF | HC);
|
||||
@ -634,8 +629,7 @@ void EightBit::Z80::ini(uint8_t& f) {
|
||||
MEMPTR().word++;
|
||||
readPort();
|
||||
auto value = m_memory.DATA();
|
||||
m_memory.ADDRESS().word = HL().word++;
|
||||
m_memory.reference() = value;
|
||||
m_memory.write(HL().word++, value);
|
||||
decrement(f, B());
|
||||
setFlag(f, NF);
|
||||
}
|
||||
@ -645,8 +639,7 @@ void EightBit::Z80::ind(uint8_t& f) {
|
||||
MEMPTR().word--;
|
||||
readPort();
|
||||
auto value = m_memory.DATA();
|
||||
m_memory.ADDRESS().word = HL().word--;
|
||||
m_memory.reference() = value;
|
||||
m_memory.write(HL().word--, value);
|
||||
decrement(f, B());
|
||||
setFlag(f, NF);
|
||||
}
|
||||
@ -666,8 +659,8 @@ bool EightBit::Z80::indr(uint8_t& f) {
|
||||
#pragma region Block output instructions
|
||||
|
||||
void EightBit::Z80::blockOut(uint8_t& f) {
|
||||
auto value = m_memory.reference();
|
||||
m_memory.ADDRESS().word = BC().word;
|
||||
auto value = m_memory.read();
|
||||
m_memory.ADDRESS() = BC();
|
||||
writePort();
|
||||
decrement(f, B());
|
||||
setFlag(f, NF, value & Bit7);
|
||||
@ -705,8 +698,9 @@ bool EightBit::Z80::otdr(uint8_t& f) {
|
||||
|
||||
void EightBit::Z80::rrd(uint8_t& a, uint8_t& f) {
|
||||
MEMPTR() = HL();
|
||||
auto memory = memptrReference();
|
||||
m_memory.reference() = promoteNibble(a) | highNibble(memory);
|
||||
memptrReference();
|
||||
auto memory = m_memory.read();
|
||||
m_memory.write(promoteNibble(a) | highNibble(memory));
|
||||
a = (a & 0xf0) | lowNibble(memory);
|
||||
adjustSZPXY<Z80>(f, a);
|
||||
clearFlag(f, NF | HC);
|
||||
@ -714,8 +708,9 @@ void EightBit::Z80::rrd(uint8_t& a, uint8_t& f) {
|
||||
|
||||
void EightBit::Z80::rld(uint8_t& a, uint8_t& f) {
|
||||
MEMPTR() = HL();
|
||||
auto memory = memptrReference();
|
||||
m_memory.reference() = promoteNibble(memory) | lowNibble(a);
|
||||
memptrReference();
|
||||
auto memory = m_memory.read();
|
||||
m_memory.write(promoteNibble(memory) | lowNibble(a));
|
||||
a = (a & 0xf0) | highNibble(memory);
|
||||
adjustSZPXY<Z80>(f, a);
|
||||
clearFlag(f, NF | HC);
|
||||
@ -799,42 +794,48 @@ void EightBit::Z80::executeCB(int x, int y, int z) {
|
||||
auto& a = A();
|
||||
auto& f = F();
|
||||
switch (x) {
|
||||
case 0: // rot[y] r[z]
|
||||
case 0: { // rot[y] r[z]
|
||||
auto operand = m_displaced ? m_memory.read(displacedAddress()) : R(z, a);
|
||||
switch (y) {
|
||||
case 0:
|
||||
adjustSZP<Z80>(f, m_displaced ? R2(z, a) = rlc(f, DISPLACED()) : rlc(f, R(z, a)));
|
||||
operand = rlc(f, operand);
|
||||
break;
|
||||
case 1:
|
||||
adjustSZP<Z80>(f, m_displaced ? R2(z, a) = rrc(f, DISPLACED()) : rrc(f, R(z, a)));
|
||||
operand = rrc(f, operand);
|
||||
break;
|
||||
case 2:
|
||||
adjustSZP<Z80>(f, m_displaced ? R2(z, a) = rl(f, DISPLACED()) : rl(f, R(z, a)));
|
||||
operand = rl(f, operand);
|
||||
break;
|
||||
case 3:
|
||||
adjustSZP<Z80>(f, m_displaced ? R2(z, a) = rr(f, DISPLACED()) : rr(f, R(z, a)));
|
||||
operand = rr(f, operand);
|
||||
break;
|
||||
case 4:
|
||||
adjustSZP<Z80>(f, m_displaced ? R2(z, a) = sla(f, DISPLACED()) : sla(f, R(z, a)));
|
||||
operand = sla(f, operand);
|
||||
break;
|
||||
case 5:
|
||||
adjustSZP<Z80>(f, m_displaced ? R2(z, a) = sra(f, DISPLACED()) : sra(f, R(z, a)));
|
||||
operand = sra(f, operand);
|
||||
break;
|
||||
case 6:
|
||||
adjustSZP<Z80>(f, m_displaced ? R2(z, a) = sll(f, DISPLACED()) : sll(f, R(z, a)));
|
||||
operand = sll(f, operand);
|
||||
break;
|
||||
case 7:
|
||||
adjustSZP<Z80>(f, m_displaced ? R2(z, a) = srl(f, DISPLACED()) : srl(f, R(z, a)));
|
||||
operand = srl(f, operand);
|
||||
break;
|
||||
}
|
||||
cycles += 8;
|
||||
if (!m_displaced) {
|
||||
adjustSZP<Z80>(f, operand);
|
||||
if (m_displaced) {
|
||||
if (z != 6)
|
||||
R2(z, a, operand);
|
||||
m_memory.write(operand);
|
||||
cycles += 15;
|
||||
} else {
|
||||
R(z, a, operand);
|
||||
if (z == 6)
|
||||
cycles += 7;
|
||||
} else {
|
||||
cycles += 15;
|
||||
}
|
||||
cycles += 8;
|
||||
break;
|
||||
case 1: // BIT y, r[z]
|
||||
} case 1: // BIT y, r[z]
|
||||
cycles += 8;
|
||||
if (!m_displaced) {
|
||||
auto operand = bit(f, y, R(z, a));
|
||||
@ -845,7 +846,7 @@ void EightBit::Z80::executeCB(int x, int y, int z) {
|
||||
adjustXY<Z80>(f, operand);
|
||||
}
|
||||
} else {
|
||||
bit(f, y, DISPLACED());
|
||||
bit(f, y, m_memory.read(displacedAddress()));
|
||||
adjustXY<Z80>(f, MEMPTR().high);
|
||||
cycles += 12;
|
||||
}
|
||||
@ -853,22 +854,28 @@ void EightBit::Z80::executeCB(int x, int y, int z) {
|
||||
case 2: // RES y, r[z]
|
||||
cycles += 8;
|
||||
if (!m_displaced) {
|
||||
res(y, R(z, a));
|
||||
R(z, a, res(y, R(z, a)));
|
||||
if (z == 6)
|
||||
cycles += 7;
|
||||
} else {
|
||||
R2(z, a) = res(y, DISPLACED());
|
||||
auto operand = m_memory.read(displacedAddress());
|
||||
operand = res(y, operand);
|
||||
m_memory.write(operand);
|
||||
R2(z, a, operand);
|
||||
cycles += 15;
|
||||
}
|
||||
break;
|
||||
case 3: // SET y, r[z]
|
||||
cycles += 8;
|
||||
if (!m_displaced) {
|
||||
set(y, R(z, a));
|
||||
R(z, a, set(y, R(z, a)));
|
||||
if (z == 6)
|
||||
cycles += 7;
|
||||
} else {
|
||||
R2(z, a) = set(y, DISPLACED());
|
||||
auto operand = m_memory.read(displacedAddress());
|
||||
operand = set(y, operand);
|
||||
m_memory.write(operand);
|
||||
R2(z, a, operand);
|
||||
cycles += 15;
|
||||
}
|
||||
break;
|
||||
@ -892,7 +899,7 @@ void EightBit::Z80::executeED(int x, int y, int z, int p, int q) {
|
||||
MEMPTR().word++;
|
||||
readPort();
|
||||
if (y != 6) // IN r[y],(C)
|
||||
R(y, a) = m_memory.DATA();
|
||||
R(y, a, m_memory.DATA());
|
||||
adjustSZPXY<Z80>(f, m_memory.DATA());
|
||||
clearFlag(f, NF | HC);
|
||||
cycles += 12;
|
||||
@ -1169,12 +1176,14 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
|
||||
switch (p) {
|
||||
case 0: // LD (BC),A
|
||||
MEMPTR() = BC();
|
||||
MEMPTR().high = memptrReference() = a;
|
||||
memptrReference();
|
||||
m_memory.write(MEMPTR().high = a);
|
||||
cycles += 7;
|
||||
break;
|
||||
case 1: // LD (DE),A
|
||||
MEMPTR() = DE();
|
||||
MEMPTR().high = memptrReference() = a;
|
||||
memptrReference();
|
||||
m_memory.write(MEMPTR().high = a);
|
||||
cycles += 7;
|
||||
break;
|
||||
case 2: // LD (nn),HL
|
||||
@ -1184,7 +1193,8 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
|
||||
break;
|
||||
case 3: // LD (nn),A
|
||||
fetchWord();
|
||||
MEMPTR().high = memptrReference() = a;
|
||||
memptrReference();
|
||||
m_memory.write(MEMPTR().high = a);
|
||||
cycles += 13;
|
||||
break;
|
||||
default:
|
||||
@ -1195,12 +1205,14 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
|
||||
switch (p) {
|
||||
case 0: // LD A,(BC)
|
||||
MEMPTR() = BC();
|
||||
a = memptrReference();
|
||||
memptrReference();
|
||||
a = m_memory.read();
|
||||
cycles += 7;
|
||||
break;
|
||||
case 1: // LD A,(DE)
|
||||
MEMPTR() = DE();
|
||||
a = memptrReference();
|
||||
memptrReference();
|
||||
a = m_memory.read();
|
||||
cycles += 7;
|
||||
break;
|
||||
case 2: // LD HL,(nn)
|
||||
@ -1210,7 +1222,8 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
|
||||
break;
|
||||
case 3: // LD A,(nn)
|
||||
fetchWord();
|
||||
a = memptrReference();
|
||||
memptrReference();
|
||||
a = m_memory.read();
|
||||
cycles += 13;
|
||||
break;
|
||||
default:
|
||||
@ -1234,36 +1247,45 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
|
||||
}
|
||||
cycles += 6;
|
||||
break;
|
||||
case 4: // 8-bit INC
|
||||
increment(f, R(y, a)); // INC r
|
||||
case 4: { // 8-bit INC
|
||||
if (m_displaced && (y == 6))
|
||||
fetchDisplacement();
|
||||
auto operand = R(y, a);
|
||||
increment(f, operand);
|
||||
R(y, a, operand);
|
||||
cycles += 4;
|
||||
break;
|
||||
case 5: // 8-bit DEC
|
||||
decrement(f, R(y, a)); // DEC r
|
||||
} case 5: { // 8-bit DEC
|
||||
if (m_displaced && (y == 6))
|
||||
fetchDisplacement();
|
||||
auto operand = R(y, a);
|
||||
decrement(f, operand);
|
||||
R(y, a, operand);
|
||||
cycles += 4;
|
||||
if (y == 6)
|
||||
cycles += 7;
|
||||
break;
|
||||
case 6: { // 8-bit load immediate
|
||||
auto& r = R(y, a); // LD r,n
|
||||
r = fetchByte();
|
||||
} case 6: // 8-bit load immediate
|
||||
if (m_displaced && (y == 6))
|
||||
fetchDisplacement();
|
||||
R(y, a, fetchByte()); // LD r,n
|
||||
cycles += 7;
|
||||
if (y == 6)
|
||||
cycles += 3;
|
||||
break;
|
||||
} case 7: // Assorted operations on accumulator/flags
|
||||
case 7: // Assorted operations on accumulator/flags
|
||||
switch (y) {
|
||||
case 0:
|
||||
rlc(f, a);
|
||||
a = rlc(f, a);
|
||||
break;
|
||||
case 1:
|
||||
rrc(f, a);
|
||||
a = rrc(f, a);
|
||||
break;
|
||||
case 2:
|
||||
rl(f, a);
|
||||
a = rl(f, a);
|
||||
break;
|
||||
case 3:
|
||||
rr(f, a);
|
||||
a = rr(f, a);
|
||||
break;
|
||||
case 4:
|
||||
daa(a, f);
|
||||
@ -1293,6 +1315,7 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
|
||||
bool normal = true;
|
||||
if (m_displaced) {
|
||||
if (z == 6) {
|
||||
fetchDisplacement();
|
||||
switch (y) {
|
||||
case 4:
|
||||
H() = R(z, a);
|
||||
@ -1305,26 +1328,29 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
|
||||
}
|
||||
}
|
||||
if (y == 6) {
|
||||
fetchDisplacement();
|
||||
switch (z) {
|
||||
case 4:
|
||||
R(y, a) = H();
|
||||
R(y, a, H());
|
||||
normal = false;
|
||||
break;
|
||||
case 5:
|
||||
R(y, a) = L();
|
||||
R(y, a, L());
|
||||
normal = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (normal)
|
||||
R(y, a) = R(z, a);
|
||||
R(y, a, R(z, a));
|
||||
if ((y == 6) || (z == 6)) // M operations
|
||||
cycles += 3;
|
||||
}
|
||||
cycles += 4;
|
||||
break;
|
||||
case 2: // Operate on accumulator and register/memory location
|
||||
if (m_displaced && (z == 6))
|
||||
fetchDisplacement();
|
||||
switch (y) {
|
||||
case 0: // ADD A,r
|
||||
add(f, a, R(z, a));
|
||||
@ -1410,7 +1436,7 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
|
||||
case 1: // CB prefix
|
||||
m_prefixCB = true;
|
||||
if (m_displaced)
|
||||
m_displacement = fetchByte();
|
||||
fetchDisplacement();
|
||||
fetchExecute();
|
||||
break;
|
||||
case 2: // OUT (n),A
|
||||
|
@ -20,8 +20,7 @@ void Board::initialise() {
|
||||
//m_memory.loadRam(romDirectory + "/CPUTEST.COM", 0x100); // SuperSoft diagnostics
|
||||
//m_memory.loadRam(romDirectory + "/TEST.COM", 0x100); // Microcosm
|
||||
|
||||
m_memory.ADDRESS().word = 5;
|
||||
m_memory.reference() = 0xc9; // ret
|
||||
m_memory.write(5, 0xc9); // ret
|
||||
m_cpu.ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Cpm, this, std::placeholders::_1));
|
||||
|
||||
if (m_configuration.isProfileMode()) {
|
||||
|
@ -120,8 +120,7 @@ namespace EightBit {
|
||||
}
|
||||
|
||||
virtual void push(uint8_t value) {
|
||||
m_memory.ADDRESS().word = --SP().word;
|
||||
m_memory.reference() = value;
|
||||
m_memory.write(--SP().word, value);
|
||||
}
|
||||
|
||||
void pushWord(const register16_t& value) {
|
||||
@ -130,8 +129,7 @@ namespace EightBit {
|
||||
}
|
||||
|
||||
virtual uint8_t pop() {
|
||||
m_memory.ADDRESS().word = SP().word++;
|
||||
return m_memory.reference();
|
||||
return m_memory.read(SP().word++);
|
||||
}
|
||||
|
||||
void popWord(register16_t& output) {
|
||||
@ -145,22 +143,23 @@ namespace EightBit {
|
||||
|
||||
//
|
||||
|
||||
uint8_t& memptrReference() {
|
||||
void memptrReference() {
|
||||
m_memory.ADDRESS() = MEMPTR();
|
||||
MEMPTR().word++;
|
||||
return m_memory.reference();
|
||||
}
|
||||
|
||||
virtual void getWordViaMemptr(register16_t& value) {
|
||||
value.low = memptrReference();
|
||||
memptrReference();
|
||||
value.low = m_memory.read();
|
||||
m_memory.ADDRESS().word++;
|
||||
value.high = m_memory.reference();
|
||||
value.high = m_memory.read();
|
||||
}
|
||||
|
||||
virtual void setWordViaMemptr(register16_t value) {
|
||||
memptrReference() = value.low;
|
||||
memptrReference();
|
||||
m_memory.write(value.low);
|
||||
m_memory.ADDRESS().word++;
|
||||
m_memory.reference() = value.high;
|
||||
m_memory.write(value.high);
|
||||
}
|
||||
|
||||
//
|
||||
|
32
inc/Memory.h
32
inc/Memory.h
@ -56,19 +56,10 @@ namespace EightBit {
|
||||
virtual uint8_t peek(uint16_t address) const;
|
||||
virtual uint16_t peekWord(uint16_t address) const;
|
||||
|
||||
virtual uint8_t& reference() {
|
||||
auto effective = effectiveAddress(ADDRESS().word);
|
||||
return m_locked[effective] ? placeDATA(m_bus[effective]) : referenceDATA(m_bus[effective]);
|
||||
}
|
||||
|
||||
virtual int effectiveAddress(int address) const {
|
||||
return address & m_addressMask;
|
||||
}
|
||||
|
||||
void fireReadBusEvent() {
|
||||
ReadByte.fire(AddressEventArgs(ADDRESS().word, DATA()));
|
||||
}
|
||||
|
||||
uint8_t read() {
|
||||
auto content = reference();
|
||||
fireReadBusEvent();
|
||||
@ -80,8 +71,9 @@ namespace EightBit {
|
||||
return read();
|
||||
}
|
||||
|
||||
void fireWriteBusEvent() {
|
||||
WrittenByte.fire(AddressEventArgs(ADDRESS().word, DATA()));
|
||||
uint8_t read(register16_t address) {
|
||||
ADDRESS() = address;
|
||||
return read();
|
||||
}
|
||||
|
||||
void write(uint8_t value) {
|
||||
@ -94,6 +86,11 @@ namespace EightBit {
|
||||
write(value);
|
||||
}
|
||||
|
||||
void write(register16_t address, uint8_t value) {
|
||||
ADDRESS() = address;
|
||||
write(value);
|
||||
}
|
||||
|
||||
void clear();
|
||||
void loadRom(const std::string& path, uint16_t offset);
|
||||
void loadRam(const std::string& path, uint16_t offset);
|
||||
@ -111,6 +108,19 @@ namespace EightBit {
|
||||
register16_t m_address;
|
||||
uint8_t* m_data;
|
||||
|
||||
void fireReadBusEvent() {
|
||||
ReadByte.fire(AddressEventArgs(ADDRESS().word, DATA()));
|
||||
}
|
||||
|
||||
void fireWriteBusEvent() {
|
||||
WrittenByte.fire(AddressEventArgs(ADDRESS().word, DATA()));
|
||||
}
|
||||
|
||||
virtual uint8_t& reference() {
|
||||
auto effective = effectiveAddress(ADDRESS().word);
|
||||
return m_locked[effective] ? placeDATA(m_bus[effective]) : referenceDATA(m_bus[effective]);
|
||||
}
|
||||
|
||||
int loadMemory(const std::string& path, uint16_t offset);
|
||||
};
|
||||
}
|
@ -75,8 +75,7 @@ namespace EightBit {
|
||||
int cycles;
|
||||
|
||||
virtual uint8_t fetchByte() {
|
||||
m_memory.ADDRESS().word = PC().word++;
|
||||
return m_memory.reference();
|
||||
return m_memory.read(PC().word++);
|
||||
}
|
||||
|
||||
virtual void fetchWord(register16_t& output) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user