A whole bunch of consistency changes. No functional changes.

Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
Adrian Conlon 2017-11-03 22:05:01 +00:00
parent ff2f44bbd2
commit c292fb552e
24 changed files with 349 additions and 328 deletions

View File

@ -53,7 +53,7 @@ namespace EightBit {
register16_t de;
register16_t hl;
uint8_t R(int r) {
uint8_t R(int r, uint8_t a) {
switch (r) {
case 0b000:
return B();
@ -70,14 +70,14 @@ namespace EightBit {
case 0b110:
return getByte(HL());
case 0b111:
return A();
return a;
default:
UNREACHABLE;
}
throw std::logic_error("Unhandled registry mechanism");
}
void R(int r, uint8_t value) {
void R(int r, uint8_t& a, uint8_t value) {
switch (r) {
case 0b000:
B() = value;
@ -101,7 +101,7 @@ namespace EightBit {
setByte(HL(), value);
break;
case 0b111:
A() = value;
a = value;
break;
default:
UNREACHABLE;
@ -153,6 +153,9 @@ namespace EightBit {
static void increment(uint8_t& f, uint8_t& operand);
static void decrement(uint8_t& f, uint8_t& operand);
void di();
void ei();
bool returnConditionalFlag(uint8_t& f, int flag);
bool jumpConditionalFlag(uint8_t& f, int flag);
bool callConditionalFlag(uint8_t& f, int flag);
@ -178,12 +181,12 @@ namespace EightBit {
static void stc(uint8_t& a, uint8_t& f);
static void cmc(uint8_t& a, uint8_t& f);
void xhtl();
void xhtl(register16_t& operand);
void out();
void in();
void writePort(uint8_t port, uint8_t a);
void writePort();
void ei();
void di();
void readPort(uint8_t port, uint8_t& a);
void readPort();
};
}

View File

@ -112,8 +112,8 @@ bool EightBit::Intel8080::callConditionalFlag(uint8_t& f, int flag) {
void EightBit::Intel8080::add(uint8_t& f, register16_t& operand, register16_t value) {
const auto result = operand.word + value.word;
setFlag(f, CF, result & Bit16);
operand.word = result;
setFlag(f, CF, result & Bit16);
}
void EightBit::Intel8080::add(uint8_t& f, uint8_t& operand, uint8_t value, int carry) {
@ -221,27 +221,45 @@ void EightBit::Intel8080::cmc(uint8_t& a, uint8_t& f) {
clearFlag(f, CF, f & CF);
}
void EightBit::Intel8080::xhtl() {
void EightBit::Intel8080::xhtl(register16_t& operand) {
MEMPTR().low = getByte(SP());
setByte(L());
L() = MEMPTR().low;
setByte(operand.low);
operand.low = MEMPTR().low;
BUS().ADDRESS().word++;
MEMPTR().high = getByte();
setByte(H());
H() = MEMPTR().high;
setByte(operand.high);
operand.high = MEMPTR().high;
}
void EightBit::Intel8080::out() {
m_ports.write(fetchByte(), A());
void EightBit::Intel8080::writePort(uint8_t port, uint8_t data) {
BUS().ADDRESS().low = port;
BUS().ADDRESS().high = data;
MEMPTR() = BUS().ADDRESS();
BUS().placeDATA(data);
writePort();
MEMPTR().low++;
}
void EightBit::Intel8080::in() {
A() = m_ports.read(fetchByte());
void EightBit::Intel8080::writePort() {
m_ports.write(BUS().ADDRESS().low, BUS().DATA());
}
void EightBit::Intel8080::readPort(uint8_t port, uint8_t& a) {
BUS().ADDRESS().low = port;
BUS().ADDRESS().high = a;
MEMPTR() = BUS().ADDRESS();
readPort();
a = BUS().DATA();
MEMPTR().low++;
}
void EightBit::Intel8080::readPort() {
BUS().placeDATA(m_ports.read(BUS().ADDRESS().low));
}
int EightBit::Intel8080::step() {
ExecutingInstruction.fire(*this);
cycles = 0;
resetCycles();
return fetchExecute();
}
@ -249,19 +267,19 @@ int EightBit::Intel8080::execute(uint8_t opcode) {
const auto& decoded = getDecodedOpcode(opcode);
auto x = decoded.x;
auto y = decoded.y;
auto z = decoded.z;
const auto x = decoded.x;
const auto y = decoded.y;
const auto z = decoded.z;
auto p = decoded.p;
auto q = decoded.q;
const auto p = decoded.p;
const auto q = decoded.q;
execute(x, y, z, p, q);
if (cycles == 0)
if (cycles() == 0)
throw std::logic_error("Unhandled opcode");
return cycles;
return cycles();
}
void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) {
@ -273,19 +291,19 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) {
case 0: // Relative jumps and assorted ops
switch (y) {
case 0: // NOP
cycles += 4;
addCycles(4);
break;
}
break;
case 1: // 16-bit load immediate/add
switch (q) {
case 0: // LD rp,nn
Processor::fetchWord(RP(p));
cycles += 10;
fetchWord(RP(p));
addCycles(10);
break;
case 1: // ADD HL,rp
add(f, HL(), RP(p));
cycles += 11;
addCycles(11);
break;
}
break;
@ -297,24 +315,24 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) {
MEMPTR() = BC();
memptrReference();
setByte(MEMPTR().high = a);
cycles += 7;
addCycles(7);
break;
case 1: // LD (DE),A
MEMPTR() = DE();
memptrReference();
setByte(MEMPTR().high = a);
cycles += 7;
addCycles(7);
break;
case 2: // LD (nn),HL
fetchWord();
setWordViaMemptr(HL());
cycles += 16;
addCycles(16);
break;
case 3: // LD (nn),A
fetchWord();
memptrReference();
setByte(MEMPTR().high = a);
cycles += 13;
addCycles(13);
break;
default:
UNREACHABLE;
@ -326,24 +344,24 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) {
MEMPTR() = BC();
memptrReference();
a = getByte();
cycles += 7;
addCycles(7);
break;
case 1: // LD A,(DE)
MEMPTR() = DE();
memptrReference();
a = getByte();
cycles += 7;
addCycles(7);
break;
case 2: // LD HL,(nn)
fetchWord();
getWordViaMemptr(HL());
cycles += 16;
addCycles(16);
break;
case 3: // LD A,(nn)
fetchWord();
memptrReference();
a = getByte();
cycles += 13;
addCycles(13);
break;
default:
UNREACHABLE;
@ -364,27 +382,27 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) {
default:
UNREACHABLE;
}
cycles += 6;
addCycles(6);
break;
case 4: { // 8-bit INC
auto operand = R(y);
auto operand = R(y, a);
increment(f, operand);
R(y, operand);
cycles += 4;
R(y, a, operand);
addCycles(4);
break;
} case 5: { // 8-bit DEC
auto operand = R(y);
auto operand = R(y, a);
decrement(f, operand);
R(y, operand);
cycles += 4;
R(y, a, operand);
addCycles(4);
if (y == 6)
cycles += 7;
addCycles(7);
break;
} case 6: // 8-bit load immediate
R(y, fetchByte());
cycles += 7;
R(y, a, fetchByte());
addCycles(7);
if (y == 6)
cycles += 3;
addCycles(3);
break;
case 7: // Assorted operations on accumulator/flags
switch (y) {
@ -415,7 +433,7 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) {
default:
UNREACHABLE;
}
cycles += 4;
addCycles(4);
break;
default:
UNREACHABLE;
@ -425,71 +443,71 @@ 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, a, R(z, a));
if ((y == 6) || (z == 6)) // M operations
cycles += 3;
addCycles(3);
}
cycles += 4;
addCycles(4);
break;
case 2: // Operate on accumulator and register/memory location
switch (y) {
case 0: // ADD A,r
add(f, a, R(z));
add(f, a, R(z, a));
break;
case 1: // ADC A,r
adc(f, a, R(z));
adc(f, a, R(z, a));
break;
case 2: // SUB r
subtract(f, a, R(z));
subtract(f, a, R(z, a));
break;
case 3: // SBC A,r
sbb(f, a, R(z));
sbb(f, a, R(z, a));
break;
case 4: // AND r
andr(f, a, R(z));
andr(f, a, R(z, a));
break;
case 5: // XOR r
xorr(f, a, R(z));
xorr(f, a, R(z, a));
break;
case 6: // OR r
orr(f, a, R(z));
orr(f, a, R(z, a));
break;
case 7: // CP r
compare(f, a, R(z));
compare(f, a, R(z, a));
break;
default:
UNREACHABLE;
}
cycles += 4;
addCycles(4);
if (z == 6)
cycles += 3;
addCycles(3);
break;
case 3:
switch (z) {
case 0: // Conditional return
if (returnConditionalFlag(f, y))
cycles += 6;
cycles += 5;
addCycles(6);
addCycles(5);
break;
case 1: // POP & various ops
switch (q) {
case 0: // POP rp2[p]
popWord(RP2(p));
cycles += 10;
addCycles(10);
break;
case 1:
switch (p) {
case 0: // RET
ret();
cycles += 10;
addCycles(10);
break;
case 2: // JP HL
PC() = HL();
cycles += 4;
addCycles(4);
break;
case 3: // LD SP,HL
SP() = HL();
cycles += 4;
addCycles(4);
break;
}
break;
@ -499,58 +517,58 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) {
break;
case 2: // Conditional jump
jumpConditionalFlag(f, y);
cycles += 10;
addCycles(10);
break;
case 3: // Assorted operations
switch (y) {
case 0: // JP nn
fetchWord();
jump();
cycles += 10;
addCycles(10);
break;
case 2: // OUT (n),A
out();
cycles += 11;
writePort(fetchByte(), a);
addCycles(11);
break;
case 3: // IN A,(n)
in();
cycles += 11;
readPort(fetchByte(), a);
addCycles(11);
break;
case 4: // EX (SP),HL
xhtl();
cycles += 19;
xhtl(HL());
addCycles(19);
break;
case 5: // EX DE,HL
std::swap(DE(), HL());
cycles += 4;
addCycles(4);
break;
case 6: // DI
di();
cycles += 4;
addCycles(4);
break;
case 7: // EI
ei();
cycles += 4;
addCycles(4);
break;
}
break;
case 4: // Conditional call: CALL cc[y], nn
if (callConditionalFlag(f, y))
cycles += 7;
cycles += 10;
addCycles(7);
addCycles(10);
break;
case 5: // PUSH & various ops
switch (q) {
case 0: // PUSH rp2[p]
pushWord(RP2(p));
cycles += 11;
addCycles(11);
break;
case 1:
switch (p) {
case 0: // CALL nn
fetchWord();
call();
cycles += 17;
addCycles(17);
break;
}
break;
@ -587,11 +605,11 @@ void EightBit::Intel8080::execute(int x, int y, int z, int p, int q) {
default:
UNREACHABLE;
}
cycles += 7;
addCycles(7);
break;
case 7: // Restart: RST y * 8
restart(y << 3);
cycles += 11;
addCycles(11);
break;
default:
UNREACHABLE;

View File

@ -27,7 +27,7 @@ namespace EightBit {
Signal<LR35902> ExecutedInstruction;
int clockCycles() const {
return cycles * 4;
return cycles() * 4;
}
virtual register16_t& AF() override {

View File

@ -301,7 +301,7 @@ int EightBit::GameBoy::LR35902::singleStep() {
if (ime) {
m_bus.IO().poke(IoRegisters::IF, 0);
} else {
if (isHalted())
if (halted())
proceed();
}
}
@ -317,7 +317,7 @@ int EightBit::GameBoy::LR35902::singleStep() {
} else if (ime && (masked & IoRegisters::Interrupts::KeypadPressed)) {
current += interrupt(0x60);
} else {
current += isHalted() ? 1 : step();
current += halted() ? 1 : step();
}
m_bus.IO().checkTimers(current);
@ -329,7 +329,7 @@ int EightBit::GameBoy::LR35902::singleStep() {
int EightBit::GameBoy::LR35902::step() {
ExecutingInstruction.fire(*this);
m_prefixCB = false;
cycles = 0;
resetCycles();
const auto ran = fetchExecute();
ExecutedInstruction.fire(*this);
return ran;
@ -351,7 +351,7 @@ int EightBit::GameBoy::LR35902::execute(uint8_t opcode) {
else
executeOther(x, y, z, p, q);
if (cycles == 0)
if (cycles() == 0)
throw std::logic_error("Unhandled opcode");
return clockCycles();
@ -391,29 +391,29 @@ void EightBit::GameBoy::LR35902::executeCB(int x, int y, int z, int p, int q) {
default:
UNREACHABLE;
}
cycles += 2;
addCycles(2);
R(z, a, operand);
adjustZero<LR35902>(f, operand);
if (z == 6)
cycles += 2;
addCycles(2);
break;
} case 1: // BIT y, r[z]
bit(f, y, R(z, a));
cycles += 2;
addCycles(2);
if (z == 6)
cycles += 2;
addCycles(2);
break;
case 2: // RES y, r[z]
R(z, a, res(y, R(z, a)));
cycles += 2;
addCycles(2);
if (z == 6)
cycles += 2;
addCycles(2);
break;
case 3: // SET y, r[z]
R(z, a, set(y, R(z, a)));
cycles += 2;
addCycles(2);
if (z == 6)
cycles += 2;
addCycles(2);
break;
default:
UNREACHABLE;
@ -429,28 +429,28 @@ void EightBit::GameBoy::LR35902::executeOther(int x, int y, int z, int p, int q)
case 0: // Relative jumps and assorted ops
switch (y) {
case 0: // NOP
cycles++;
addCycle();
break;
case 1: // GB: LD (nn),SP
fetchWord();
setWordViaMemptr(SP());
cycles += 5;
addCycles(5);
break;
case 2: // GB: STOP
stop();
cycles++;
addCycle();
break;
case 3: // JR d
jr(fetchByte());
cycles += 4;
addCycles(4);
break;
case 4: // JR cc,d
case 5:
case 6:
case 7:
if (jrConditionalFlag(f, y - 4))
cycles++;
cycles += 2;
addCycle();
addCycles(2);
break;
default:
UNREACHABLE;
@ -460,11 +460,11 @@ void EightBit::GameBoy::LR35902::executeOther(int x, int y, int z, int p, int q)
switch (q) {
case 0: // LD rp,nn
fetchWord(RP(p));
cycles += 3;
addCycles(3);
break;
case 1: // ADD HL,rp
add(f, HL(), RP(p));
cycles += 2;
addCycles(2);
break;
default:
UNREACHABLE;
@ -476,19 +476,19 @@ void EightBit::GameBoy::LR35902::executeOther(int x, int y, int z, int p, int q)
switch (p) {
case 0: // LD (BC),A
setByte(BC(), a);
cycles += 2;
addCycles(2);
break;
case 1: // LD (DE),A
setByte(DE(), a);
cycles += 2;
addCycles(2);
break;
case 2: // GB: LDI (HL),A
setByte(HL().word++, a);
cycles += 2;
addCycles(2);
break;
case 3: // GB: LDD (HL),A
setByte(HL().word--, a);
cycles += 2;
addCycles(2);
break;
default:
UNREACHABLE;
@ -498,19 +498,19 @@ void EightBit::GameBoy::LR35902::executeOther(int x, int y, int z, int p, int q)
switch (p) {
case 0: // LD A,(BC)
a = getByte(BC());
cycles += 2;
addCycles(2);
break;
case 1: // LD A,(DE)
a = getByte(DE());
cycles += 2;
addCycles(2);
break;
case 2: // GB: LDI A,(HL)
a = getByte(HL().word++);
cycles += 2;
addCycles(2);
break;
case 3: // GB: LDD A,(HL)
a = getByte(HL().word--);
cycles += 2;
addCycles(2);
break;
default:
UNREACHABLE;
@ -531,27 +531,27 @@ void EightBit::GameBoy::LR35902::executeOther(int x, int y, int z, int p, int q)
default:
UNREACHABLE;
}
cycles += 2;
addCycles(2);
break;
case 4: { // 8-bit INC
auto operand = R(y, a);
increment(f, operand);
R(y, a, operand);
cycles++;
addCycle();
if (y == 6)
cycles += 2;
addCycles(2);
break;
} case 5: { // 8-bit DEC
auto operand = R(y, a);
decrement(f, operand);
R(y, a, operand);
cycles++;
addCycle();
if (y == 6)
cycles += 2;
addCycles(2);
break;
} case 6: // 8-bit load immediate
R(y, a, fetchByte()); // LD r,n
cycles += 2;
addCycles(2);
break;
case 7: // Assorted operations on accumulator/flags
switch (y) {
@ -582,7 +582,7 @@ void EightBit::GameBoy::LR35902::executeOther(int x, int y, int z, int p, int q)
default:
UNREACHABLE;
}
cycles++;
addCycle();
break;
default:
UNREACHABLE;
@ -594,9 +594,9 @@ void EightBit::GameBoy::LR35902::executeOther(int x, int y, int z, int p, int q)
} else {
R(y, a, R(z, a));
if ((y == 6) || (z == 6)) // M operations
cycles++;
addCycle();
}
cycles++;
addCycle();
break;
case 2: // Operate on accumulator and register/memory location
switch (y) {
@ -627,9 +627,9 @@ void EightBit::GameBoy::LR35902::executeOther(int x, int y, int z, int p, int q)
default:
UNREACHABLE;
}
cycles++;
addCycle();
if (z == 6)
cycles++;
addCycle();
break;
case 3:
switch (z) {
@ -640,12 +640,12 @@ void EightBit::GameBoy::LR35902::executeOther(int x, int y, int z, int p, int q)
case 2:
case 3:
if (returnConditionalFlag(f, y))
cycles += 3;
cycles += 2;
addCycles(3);
addCycles(2);
break;
case 4: // GB: LD (FF00 + n),A
m_bus.write(IoRegisters::BASE + fetchByte(), a);
cycles += 3;
addCycles(3);
break;
case 5: { // GB: ADD SP,dd
const auto before = SP().word;
@ -657,11 +657,11 @@ void EightBit::GameBoy::LR35902::executeOther(int x, int y, int z, int p, int q)
setFlag(f, CF, carried & Bit8);
setFlag(f, HC, carried & Bit4);
}
cycles += 4;
addCycles(4);
break;
case 6: // GB: LD A,(FF00 + n)
a = m_bus.read(IoRegisters::BASE + fetchByte());
cycles += 3;
addCycles(3);
break;
case 7: { // GB: LD HL,SP + dd
const auto before = SP().word;
@ -673,7 +673,7 @@ void EightBit::GameBoy::LR35902::executeOther(int x, int y, int z, int p, int q)
setFlag(f, CF, carried & Bit8);
setFlag(f, HC, carried & Bit4);
}
cycles += 3;
addCycles(3);
break;
default:
UNREACHABLE;
@ -683,25 +683,25 @@ void EightBit::GameBoy::LR35902::executeOther(int x, int y, int z, int p, int q)
switch (q) {
case 0: // POP rp2[p]
popWord(RP2(p));
cycles += 3;
addCycles(3);
break;
case 1:
switch (p) {
case 0: // RET
ret();
cycles += 4;
addCycles(4);
break;
case 1: // GB: RETI
reti();
cycles += 4;
addCycles(4);
break;
case 2: // JP HL
PC() = HL();
cycles++;
addCycle();
break;
case 3: // LD SP,HL
SP() = HL();
cycles += 2;
addCycles(2);
break;
default:
UNREACHABLE;
@ -718,25 +718,25 @@ void EightBit::GameBoy::LR35902::executeOther(int x, int y, int z, int p, int q)
case 2:
case 3:
jumpConditionalFlag(f, y);
cycles += 3;
addCycles(3);
break;
case 4: // GB: LD (FF00 + C),A
m_bus.write(IoRegisters::BASE + C(), a);
cycles += 2;
addCycles(2);
break;
case 5: // GB: LD (nn),A
fetchWord();
setByte(MEMPTR(), a);
cycles += 4;
addCycles(4);
break;
case 6: // GB: LD A,(FF00 + C)
a = m_bus.read(IoRegisters::BASE + C());
cycles += 2;
addCycles(2);
break;
case 7: // GB: LD A,(nn)
fetchWord();
a = getByte(MEMPTR());
cycles += 4;
addCycles(4);
break;
default:
UNREACHABLE;
@ -747,7 +747,7 @@ void EightBit::GameBoy::LR35902::executeOther(int x, int y, int z, int p, int q)
case 0: // JP nn
fetchWord();
jump();
cycles += 4;
addCycles(4);
break;
case 1: // CB prefix
m_prefixCB = true;
@ -755,31 +755,31 @@ void EightBit::GameBoy::LR35902::executeOther(int x, int y, int z, int p, int q)
break;
case 6: // DI
di();
cycles++;
addCycle();
break;
case 7: // EI
ei();
cycles++;
addCycle();
break;
}
break;
case 4: // Conditional call: CALL cc[y], nn
if (callConditionalFlag(f, y))
cycles += 3;
cycles += 3;
addCycles(3);
addCycles(3);
break;
case 5: // PUSH & various ops
switch (q) {
case 0: // PUSH rp2[p]
pushWord(RP2(p));
cycles += 4;
addCycles(4);
break;
case 1:
switch (p) {
case 0: // CALL nn
fetchWord();
call();
cycles += 6;
addCycles(6);
break;
}
break;
@ -816,11 +816,11 @@ void EightBit::GameBoy::LR35902::executeOther(int x, int y, int z, int p, int q)
default:
UNREACHABLE;
}
cycles += 2;
addCycles(2);
break;
case 7: // Restart: RST y * 8
restart(y << 3);
cycles += 4;
addCycles(4);
break;
default:
UNREACHABLE;

View File

@ -158,7 +158,7 @@ namespace EightBit {
Address_AbsoluteX();
BUS().ADDRESS() = MEMPTR();
if (BUS().ADDRESS().low == Mask8)
++cycles;
addCycle();
return getByte();
}
@ -166,7 +166,7 @@ namespace EightBit {
Address_AbsoluteY();
BUS().ADDRESS() = MEMPTR();
if (BUS().ADDRESS().low == Mask8)
++cycles;
addCycle();
return getByte();
}
@ -189,7 +189,7 @@ namespace EightBit {
Address_IndirectIndexedY();
BUS().ADDRESS() = MEMPTR();
if (BUS().ADDRESS().low == Mask8)
++cycles;
addCycle();
return getByte();
}

View File

@ -40,7 +40,7 @@ void EightBit::MOS6502::initialise() {
int EightBit::MOS6502::step() {
ExecutingInstruction.fire(*this);
cycles = 0;
resetCycles();
auto returned = fetchExecute();
ExecutedInstruction.fire(*this);
return returned;
@ -83,7 +83,7 @@ void EightBit::MOS6502::interrupt(uint16_t vector) {
int EightBit::MOS6502::execute(uint8_t cell) {
cycles = m_timings[cell];
addCycles(m_timings[cell]);
// http://www.llx.com/~nparker/a2/opcodes.html
@ -338,10 +338,10 @@ int EightBit::MOS6502::execute(uint8_t cell) {
__assume(0);
}
if (cycles == 0)
if (cycles() == 0)
throw std::logic_error("Unhandled opcode");
return cycles;
return cycles();
}
////
@ -483,8 +483,8 @@ void EightBit::MOS6502::Branch(int8_t displacement) {
const auto page = PC().high;
PC().word += displacement;
if (PC().high != page)
cycles++;
cycles++;
addCycle();
addCycle();
}
void EightBit::MOS6502::Branch(bool flag) {

View File

@ -1,23 +0,0 @@
#pragma once
#include <vector>
#include <functional>
template<class T> class Signal {
private:
typedef std::function<void(T&)> delegate_t;
typedef std::vector<delegate_t> delegates_t;
delegates_t delegates;
public:
void connect(delegate_t functor) {
delegates.push_back(functor);
}
void fire(T& e) const {
if (!delegates.empty())
for (auto& delegate : delegates)
delegate(e);
}
};

View File

@ -2,12 +2,17 @@
#include <cstdint>
#include <cassert>
#include <stdexcept>
#include "IntelProcessor.h"
#include "InputOutput.h"
#include "Signal.h"
#include <IntelProcessor.h>
#include <Signal.h>
#include <Register.h>
namespace EightBit {
class InputOutput;
class Bus;
class Z80 : public IntelProcessor {
public:
struct refresh_t {
@ -255,12 +260,16 @@ namespace EightBit {
register16_t& RP(int rp) {
switch (rp) {
case 0:
return BC();
case 1:
return DE();
case 2:
return HL2();
case 3:
return SP();
case HL_IDX:
return HL2();
default:
return m_registers[m_registerSet][rp];
UNREACHABLE;
}
}
@ -275,12 +284,16 @@ namespace EightBit {
register16_t& RP2(int rp) {
switch (rp) {
case 0:
return BC();
case 1:
return DE();
case 2:
return HL2();
case 3:
return AF();
case HL_IDX:
return HL2();
default:
return m_registers[m_registerSet][rp];
UNREACHABLE;
}
}

View File

@ -4,8 +4,10 @@
#include <sstream>
#include <iomanip>
#include <bitset>
#include <iostream>
#include <Memory.h>
#include "Memory.h"
#include "Z80.h"
EightBit::Disassembler::Disassembler() {

View File

@ -58,34 +58,34 @@ void EightBit::Z80::ei() {
}
int EightBit::Z80::interrupt(bool maskable, uint8_t value) {
cycles = 0;
resetCycles();
if (!maskable || (maskable && IFF1())) {
if (maskable) {
di();
switch (IM()) {
case 0:
M1() = true;
cycles += execute(value);
addCycles(execute(value));
break;
case 1:
restart(7 << 3);
cycles += 13;
addCycles(13);
break;
case 2:
pushWord(PC());
PC().low = value;
PC().high = IV();
cycles += 19;
addCycles(19);
break;
}
} else {
IFF1() = false;
restart(0x66);
cycles += 13;
addCycles(13);
}
}
// Could be zero for a masked interrupt...
return cycles;
return cycles();
}
void EightBit::Z80::increment(uint8_t& f, uint8_t& operand) {
@ -679,7 +679,7 @@ void EightBit::Z80::readPort() {
int EightBit::Z80::step() {
ExecutingInstruction.fire(*this);
m_displaced = m_prefixCB = m_prefixDD = m_prefixED = m_prefixFD = false;
cycles = 0;
resetCycles();
return fetchExecute();
}
@ -712,10 +712,10 @@ int EightBit::Z80::execute(uint8_t opcode) {
executeED(x, y, z, p, q);
}
if (cycles == 0)
if (cycles() == 0)
throw std::logic_error("Unhandled opcode");
return cycles;
return cycles();
}
void EightBit::Z80::executeCB(int x, int y, int z) {
@ -757,56 +757,56 @@ void EightBit::Z80::executeCB(int x, int y, int z) {
if (z != 6)
R2(z, a, operand);
setByte(operand);
cycles += 15;
addCycles(15);
} else {
R(z, a, operand);
if (z == 6)
cycles += 7;
addCycles(7);
}
cycles += 8;
addCycles(8);
break;
} case 1: // BIT y, r[z]
cycles += 8;
addCycles(8);
if (!m_displaced) {
auto operand = bit(f, y, R(z, a));
if (z == 6) {
adjustXY<Z80>(f, MEMPTR().high);
cycles += 4;
addCycles(4);
} else {
adjustXY<Z80>(f, operand);
}
} else {
bit(f, y, getByte(displacedAddress()));
adjustXY<Z80>(f, MEMPTR().high);
cycles += 12;
addCycles(12);
}
break;
case 2: // RES y, r[z]
cycles += 8;
addCycles(8);
if (!m_displaced) {
R(z, a, res(y, R(z, a)));
if (z == 6)
cycles += 7;
addCycles(7);
} else {
auto operand = getByte(displacedAddress());
operand = res(y, operand);
setByte(operand);
R2(z, a, operand);
cycles += 15;
addCycles(15);
}
break;
case 3: // SET y, r[z]
cycles += 8;
addCycles(8);
if (!m_displaced) {
R(z, a, set(y, R(z, a)));
if (z == 6)
cycles += 7;
addCycles(7);
} else {
auto operand = getByte(displacedAddress());
operand = set(y, operand);
setByte(operand);
R2(z, a, operand);
cycles += 15;
addCycles(15);
}
break;
default:
@ -820,7 +820,7 @@ void EightBit::Z80::executeED(int x, int y, int z, int p, int q) {
switch (x) {
case 0:
case 3: // Invalid instruction, equivalent to NONI followed by NOP
cycles += 8;
addCycles(8);
break;
case 1:
switch (z) {
@ -832,7 +832,7 @@ void EightBit::Z80::executeED(int x, int y, int z, int p, int q) {
R(y, a, BUS().DATA());
adjustSZPXY<Z80>(f, BUS().DATA());
clearFlag(f, NF | HC);
cycles += 12;
addCycles(12);
break;
case 1: // Output to port with 16-bit address
MEMPTR() = BUS().ADDRESS() = BC();
@ -842,7 +842,7 @@ void EightBit::Z80::executeED(int x, int y, int z, int p, int q) {
else // OUT (C),r[y]
BUS().placeDATA(R(y, a));
writePort();
cycles += 12;
addCycles(12);
break;
case 2: // 16-bit add/subtract with carry
switch (q) {
@ -855,7 +855,7 @@ void EightBit::Z80::executeED(int x, int y, int z, int p, int q) {
default:
UNREACHABLE;
}
cycles += 15;
addCycles(15);
break;
case 3: // Retrieve/store register pair from/to immediate address
switch (q) {
@ -870,11 +870,11 @@ void EightBit::Z80::executeED(int x, int y, int z, int p, int q) {
default:
UNREACHABLE;
}
cycles += 20;
addCycles(20);
break;
case 4: // Negate accumulator
neg(a, f);
cycles += 8;
addCycles(8);
break;
case 5: // Return from interrupt
switch (y) {
@ -885,7 +885,7 @@ void EightBit::Z80::executeED(int x, int y, int z, int p, int q) {
retn(); // RETN
break;
}
cycles += 14;
addCycles(14);
break;
case 6: // Set interrupt mode
switch (y) {
@ -908,43 +908,43 @@ void EightBit::Z80::executeED(int x, int y, int z, int p, int q) {
default:
UNREACHABLE;
}
cycles += 8;
addCycles(8);
break;
case 7: // Assorted ops
switch (y) {
case 0: // LD I,A
IV() = a;
cycles += 9;
addCycles(9);
break;
case 1: // LD R,A
REFRESH() = a;
cycles += 9;
addCycles(9);
break;
case 2: // LD A,I
a = IV();
adjustSZXY<Z80>(f, a);
clearFlag(f, NF | HC);
setFlag(f, PF, IFF2());
cycles += 9;
addCycles(9);
break;
case 3: // LD A,R
a = REFRESH();
adjustSZXY<Z80>(f, a);
clearFlag(f, NF | HC);
setFlag(f, PF, IFF2());
cycles += 9;
addCycles(9);
break;
case 4: // RRD
rrd(a, f);
cycles += 18;
addCycles(18);
break;
case 5: // RLD
rld(a, f);
cycles += 18;
addCycles(18);
break;
case 6: // NOP
case 7: // NOP
cycles += 4;
addCycles(4);
break;
default:
UNREACHABLE;
@ -967,13 +967,13 @@ void EightBit::Z80::executeED(int x, int y, int z, int p, int q) {
case 6: // LDIR
if (ldir(a, f)) {
PC().word -= 2;
cycles += 5;
addCycles(5);
}
break;
case 7: // LDDR
if (lddr(a, f)) {
PC().word -= 2;
cycles += 5;
addCycles(5);
}
break;
}
@ -989,13 +989,13 @@ void EightBit::Z80::executeED(int x, int y, int z, int p, int q) {
case 6: // CPIR
if (cpir(a, f)) {
PC().word -= 2;
cycles += 5;
addCycles(5);
}
break;
case 7: // CPDR
if (cpdr(a, f)) {
PC().word -= 2;
cycles += 5;
addCycles(5);
}
break;
}
@ -1011,13 +1011,13 @@ void EightBit::Z80::executeED(int x, int y, int z, int p, int q) {
case 6: // INIR
if (inir(f)) {
PC().word -= 2;
cycles += 5;
addCycles(5);
}
break;
case 7: // INDR
if (indr(f)) {
PC().word -= 2;
cycles += 5;
addCycles(5);
}
break;
}
@ -1033,19 +1033,19 @@ void EightBit::Z80::executeED(int x, int y, int z, int p, int q) {
case 6: // OTIR
if (otir(f)) {
PC().word -= 2;
cycles += 5;
addCycles(5);
}
break;
case 7: // OTDR
if (otdr(f)) {
PC().word -= 2;
cycles += 5;
addCycles(5);
}
break;
}
break;
}
cycles += 16;
addCycles(16);
break;
}
}
@ -1059,28 +1059,28 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
case 0: // Relative jumps and assorted ops
switch (y) {
case 0: // NOP
cycles += 4;
addCycles(4);
break;
case 1: // EX AF AF'
exxAF();
cycles += 4;
addCycles(4);
break;
case 2: // DJNZ d
if (jrConditional(--B()))
cycles += 5;
cycles += 8;
addCycles(5);
addCycles(8);
break;
case 3: // JR d
jr(fetchByte());
cycles += 12;
addCycles(12);
break;
case 4: // JR cc,d
case 5:
case 6:
case 7:
if (jrConditionalFlag(f, y - 4))
cycles += 5;
cycles += 5;
addCycles(5);
addCycles(5);
break;
default:
UNREACHABLE;
@ -1090,11 +1090,11 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
switch (q) {
case 0: // LD rp,nn
fetchWord(RP(p));
cycles += 10;
addCycles(10);
break;
case 1: // ADD HL,rp
add(f, HL2(), RP(p));
cycles += 11;
addCycles(11);
break;
default:
UNREACHABLE;
@ -1108,24 +1108,24 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
MEMPTR() = BC();
memptrReference();
setByte(MEMPTR().high = a);
cycles += 7;
addCycles(7);
break;
case 1: // LD (DE),A
MEMPTR() = DE();
memptrReference();
setByte(MEMPTR().high = a);
cycles += 7;
addCycles(7);
break;
case 2: // LD (nn),HL
fetchWord();
setWordViaMemptr(HL2());
cycles += 16;
addCycles(16);
break;
case 3: // LD (nn),A
fetchWord();
memptrReference();
setByte(MEMPTR().high = a);
cycles += 13;
addCycles(13);
break;
default:
UNREACHABLE;
@ -1137,24 +1137,24 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
MEMPTR() = BC();
memptrReference();
a = getByte();
cycles += 7;
addCycles(7);
break;
case 1: // LD A,(DE)
MEMPTR() = DE();
memptrReference();
a = getByte();
cycles += 7;
addCycles(7);
break;
case 2: // LD HL,(nn)
fetchWord();
getWordViaMemptr(HL2());
cycles += 16;
addCycles(16);
break;
case 3: // LD A,(nn)
fetchWord();
memptrReference();
a = getByte();
cycles += 13;
addCycles(13);
break;
default:
UNREACHABLE;
@ -1175,7 +1175,7 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
default:
UNREACHABLE;
}
cycles += 6;
addCycles(6);
break;
case 4: { // 8-bit INC
if (m_displaced && (y == 6))
@ -1183,7 +1183,7 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
auto operand = R(y, a);
increment(f, operand);
R(y, a, operand);
cycles += 4;
addCycles(4);
break;
} case 5: { // 8-bit DEC
if (m_displaced && (y == 6))
@ -1191,17 +1191,17 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
auto operand = R(y, a);
decrement(f, operand);
R(y, a, operand);
cycles += 4;
addCycles(4);
if (y == 6)
cycles += 7;
addCycles(7);
break;
} case 6: // 8-bit load immediate
if (m_displaced && (y == 6))
fetchDisplacement();
R(y, a, fetchByte()); // LD r,n
cycles += 7;
addCycles(7);
if (y == 6)
cycles += 3;
addCycles(3);
break;
case 7: // Assorted operations on accumulator/flags
switch (y) {
@ -1232,7 +1232,7 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
default:
UNREACHABLE;
}
cycles += 4;
addCycles(4);
break;
default:
UNREACHABLE;
@ -1274,9 +1274,9 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
if (normal)
R(y, a, R(z, a));
if ((y == 6) || (z == 6)) // M operations
cycles += 3;
addCycles(3);
}
cycles += 4;
addCycles(4);
break;
case 2: // Operate on accumulator and register/memory location
if (m_displaced && (z == 6))
@ -1309,40 +1309,40 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
default:
UNREACHABLE;
}
cycles += 4;
addCycles(4);
if (z == 6)
cycles += 3;
addCycles(3);
break;
case 3:
switch (z) {
case 0: // Conditional return
if (returnConditionalFlag(f, y))
cycles += 6;
cycles += 5;
addCycles(6);
addCycles(5);
break;
case 1: // POP & various ops
switch (q) {
case 0: // POP rp2[p]
popWord(RP2(p));
cycles += 10;
addCycles(10);
break;
case 1:
switch (p) {
case 0: // RET
ret();
cycles += 10;
addCycles(10);
break;
case 1: // EXX
exx();
cycles += 4;
addCycles(4);
break;
case 2: // JP HL
PC() = HL2();
cycles += 4;
addCycles(4);
break;
case 3: // LD SP,HL
SP() = HL2();
cycles += 4;
addCycles(4);
break;
default:
UNREACHABLE;
@ -1354,14 +1354,14 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
break;
case 2: // Conditional jump
jumpConditionalFlag(f, y);
cycles += 10;
addCycles(10);
break;
case 3: // Assorted operations
switch (y) {
case 0: // JP nn
fetchWord();
jump();
cycles += 10;
addCycles(10);
break;
case 1: // CB prefix
m_prefixCB = true;
@ -1371,27 +1371,27 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
break;
case 2: // OUT (n),A
writePort(fetchByte(), a);
cycles += 11;
addCycles(11);
break;
case 3: // IN A,(n)
readPort(fetchByte(), a);
cycles += 11;
addCycles(11);
break;
case 4: // EX (SP),HL
xhtl(HL2());
cycles += 19;
addCycles(19);
break;
case 5: // EX DE,HL
std::swap(DE(), HL());
cycles += 4;
addCycles(4);
break;
case 6: // DI
di();
cycles += 4;
addCycles(4);
break;
case 7: // EI
ei();
cycles += 4;
addCycles(4);
break;
default:
UNREACHABLE;
@ -1399,21 +1399,21 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
break;
case 4: // Conditional call: CALL cc[y], nn
if (callConditionalFlag(f, y))
cycles += 7;
cycles += 10;
addCycles(7);
addCycles(10);
break;
case 5: // PUSH & various ops
switch (q) {
case 0: // PUSH rp2[p]
pushWord(RP2(p));
cycles += 11;
addCycles(11);
break;
case 1:
switch (p) {
case 0: // CALL nn
fetchWord();
call();
cycles += 17;
addCycles(17);
break;
case 1: // DD prefix
m_displaced = m_prefixDD = true;
@ -1464,11 +1464,11 @@ void EightBit::Z80::executeOther(int x, int y, int z, int p, int q) {
default:
UNREACHABLE;
}
cycles += 7;
addCycles(7);
break;
case 7: // Restart: RST y * 8
restart(y << 3);
cycles += 11;
addCycles(11);
break;
default:
UNREACHABLE;

View File

@ -5,17 +5,18 @@
#include <string>
#include <cstdint>
#include <stdexcept>
#include <functional>
#include <algorithm>
#include <memory>
#include <cassert>
#include <sstream>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <array>
#include <vector>
#include <bitset>
#include <boost/format.hpp>
#include <Memory.h>
#include <IntelProcessor.h>
#include <InputOutput.h>
#include <Signal.h>

View File

@ -1,6 +1,7 @@
#include "stdafx.h"
#include "Board.h"
#include "Disassembler.h"
#include <Disassembler.h>
Board::Board(const Configuration& configuration)
: m_configuration(configuration),

View File

@ -3,14 +3,13 @@
#endif
#include <string>
#include <cstdint>
#include <stdexcept>
#include <algorithm>
#include <memory>
#include <iostream>
#include <chrono>
#include <array>
#include <vector>
#include <map>
#include <TestHarness.h>
#include <Disassembler.h>
#include <Register.h>
#include <Ram.h>
#include <Bus.h>
#include <InputOutput.h>
#include <Profiler.h>
#include <EventArgs.h>
#include <Z80.h>

View File

@ -1,8 +1,9 @@
#include "stdafx.h"
#include "TestHarness.h"
#include "Configuration.h"
#include "Board.h"
#include <TestHarness.h>
int main(int, char*[]) {
Configuration configuration;

View File

@ -12,9 +12,9 @@ namespace EightBit {
void write(uint8_t port, uint8_t value) { return writeOutputPort(port, value); }
uint8_t readInputPort(uint8_t port);
void writeInputPort(uint8_t port, uint8_t value) { input[port] = value; }
void writeInputPort(uint8_t port, uint8_t value) { m_input[port] = value; }
uint8_t readOutputPort(uint8_t port) { return output[port]; }
uint8_t readOutputPort(uint8_t port) { return m_output[port]; }
void writeOutputPort(uint8_t port, uint8_t value);
Signal<uint8_t> ReadingPort;
@ -31,7 +31,7 @@ namespace EightBit {
void OnWrittenPort(uint8_t port);
private:
std::array<uint8_t, 0x100> input;
std::array<uint8_t, 0x100> output;
std::array<uint8_t, 0x100> m_input;
std::array<uint8_t, 0x100> m_output;
};
}

View File

@ -41,7 +41,7 @@ namespace EightBit {
virtual void initialise() override;
virtual void reset() override;
register16_t& SP() { return sp; }
register16_t& SP() { return m_sp; }
virtual register16_t& AF() = 0;
uint8_t& A() { return AF().high; }
@ -188,6 +188,6 @@ namespace EightBit {
private:
std::array<opcode_decoded_t, 0x100> m_decodedOpcodes;
register16_t sp;
register16_t m_sp;
};
}

View File

@ -19,7 +19,7 @@ namespace EightBit {
}
protected:
std::vector<uint8_t> m_bytes;
std::vector<uint8_t>& BYTES() { return m_bytes; }
uint8_t read(uint16_t address) const {
return m_bytes[address];
@ -30,6 +30,8 @@ namespace EightBit {
}
private:
std::vector<uint8_t> m_bytes;
static int loadBinary(
const std::string& path,
std::vector<uint8_t>& output,

View File

@ -64,10 +64,10 @@ namespace EightBit {
Bus& BUS() { return m_bus; }
register16_t& PC() { return pc; }
register16_t& PC() { return m_pc; }
register16_t& MEMPTR() { return m_memptr; }
bool isHalted() const { return m_halted; }
bool halted() const { return m_halted; }
void halt() { --PC().word; m_halted = true; }
void proceed() { ++PC().word; m_halted = false; }
@ -98,9 +98,6 @@ namespace EightBit {
Processor(Bus& memory);
Bus& m_bus;
int cycles;
virtual uint8_t fetchByte() {
return getByte(PC().word++);
}
@ -153,8 +150,15 @@ namespace EightBit {
jump();
}
int cycles() const { return m_cycles; }
void resetCycles() { m_cycles = 0; }
void addCycles(int extra) { m_cycles += extra; }
void addCycle() { ++m_cycles; }
private:
register16_t pc;
Bus& m_bus;
int m_cycles;
register16_t m_pc;
register16_t m_memptr;
bool m_halted;
bool m_power;

View File

@ -19,7 +19,7 @@ namespace EightBit {
}
uint8_t& reference(uint16_t address) {
return m_bytes[address];
return BYTES()[address];
}
};
}

View File

@ -15,7 +15,7 @@ namespace EightBit {
}
uint8_t& reference(uint16_t address) {
return m_bytes[address];
return BYTES()[address];
}
};
}

View File

@ -9,16 +9,16 @@ namespace EightBit {
typedef std::function<void(const T&)> delegate_t;
typedef std::vector<delegate_t> delegates_t;
delegates_t delegates;
delegates_t m_delegates;
public:
void connect(delegate_t functor) {
delegates.push_back(functor);
m_delegates.push_back(functor);
}
void fire(const T& e) const {
if (!delegates.empty())
for (auto& delegate : delegates)
if (!m_delegates.empty())
for (auto& delegate : m_delegates)
delegate(e);
}
};

View File

@ -63,7 +63,7 @@ namespace EightBit {
auto& cpu = m_board.CPU();
cpu.powerOn();
while (!cpu.isHalted()) {
while (!cpu.halted()) {
m_totalCycles += cpu.step();
++m_instructions;
}

View File

@ -3,14 +3,14 @@
uint8_t EightBit::InputOutput::readInputPort(uint8_t port) {
OnReadingPort(port);
const auto value = input[port];
const auto value = m_input[port];
OnReadPort(port);
return value;
}
void EightBit::InputOutput::writeOutputPort(uint8_t port, uint8_t value) {
OnWritingPort(port);
output[port] = value;
m_output[port] = value;
OnWrittenPort(port);
}

View File

@ -3,7 +3,7 @@
EightBit::Processor::Processor(Bus& bus)
: m_bus(bus),
cycles(0),
m_cycles(0),
m_halted(false),
m_power(false) {
PC().word = MEMPTR().word = 0;