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:
Adrian.Conlon 2017-08-06 17:06:48 +01:00
parent 261433bd6e
commit 016b3bca59
16 changed files with 615 additions and 390 deletions

View File

@ -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);

View File

@ -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;
}

View File

@ -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()) {

View File

@ -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);
};
}

View File

@ -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) {

View File

@ -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;
};
}

View File

@ -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;

View File

@ -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());
}

View File

@ -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]);
}
}

View File

@ -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);

View File

@ -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)

View File

@ -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

View File

@ -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()) {

View File

@ -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);
}
//

View File

@ -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);
};
}

View File

@ -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) {