mirror of
https://github.com/MoleskiCoder/EightBit.git
synced 2025-04-07 19:37:08 +00:00
A whole bunch of consistency changes. No functional changes.
Signed-off-by: Adrian Conlon <Adrian.conlon@gmail.com>
This commit is contained in:
parent
ff2f44bbd2
commit
c292fb552e
@ -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();
|
||||
};
|
||||
}
|
@ -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;
|
||||
|
@ -27,7 +27,7 @@ namespace EightBit {
|
||||
Signal<LR35902> ExecutedInstruction;
|
||||
|
||||
int clockCycles() const {
|
||||
return cycles * 4;
|
||||
return cycles() * 4;
|
||||
}
|
||||
|
||||
virtual register16_t& AF() override {
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,8 +4,10 @@
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <bitset>
|
||||
#include <iostream>
|
||||
|
||||
#include <Memory.h>
|
||||
|
||||
#include "Memory.h"
|
||||
#include "Z80.h"
|
||||
|
||||
EightBit::Disassembler::Disassembler() {
|
||||
|
188
Z80/src/Z80.cpp
188
Z80/src/Z80.cpp
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "Board.h"
|
||||
#include "Disassembler.h"
|
||||
|
||||
#include <Disassembler.h>
|
||||
|
||||
Board::Board(const Configuration& configuration)
|
||||
: m_configuration(configuration),
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -19,7 +19,7 @@ namespace EightBit {
|
||||
}
|
||||
|
||||
uint8_t& reference(uint16_t address) {
|
||||
return m_bytes[address];
|
||||
return BYTES()[address];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ namespace EightBit {
|
||||
}
|
||||
|
||||
uint8_t& reference(uint16_t address) {
|
||||
return m_bytes[address];
|
||||
return BYTES()[address];
|
||||
}
|
||||
};
|
||||
}
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user