diff --git a/Intel8080/inc/Intel8080.h b/Intel8080/inc/Intel8080.h index 0115222..26fa6c5 100644 --- a/Intel8080/inc/Intel8080.h +++ b/Intel8080/inc/Intel8080.h @@ -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(); }; } \ No newline at end of file diff --git a/Intel8080/src/Intel8080.cpp b/Intel8080/src/Intel8080.cpp index 6a288fa..b62bac6 100644 --- a/Intel8080/src/Intel8080.cpp +++ b/Intel8080/src/Intel8080.cpp @@ -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; diff --git a/LR35902/inc/LR35902.h b/LR35902/inc/LR35902.h index 9bd015a..2742812 100644 --- a/LR35902/inc/LR35902.h +++ b/LR35902/inc/LR35902.h @@ -27,7 +27,7 @@ namespace EightBit { Signal<LR35902> ExecutedInstruction; int clockCycles() const { - return cycles * 4; + return cycles() * 4; } virtual register16_t& AF() override { diff --git a/LR35902/src/LR35902.cpp b/LR35902/src/LR35902.cpp index 32c4cd3..930f129 100644 --- a/LR35902/src/LR35902.cpp +++ b/LR35902/src/LR35902.cpp @@ -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; diff --git a/M6502/inc/mos6502.h b/M6502/inc/mos6502.h index b1980b5..b9885a1 100644 --- a/M6502/inc/mos6502.h +++ b/M6502/inc/mos6502.h @@ -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(); } diff --git a/M6502/src/mos6502.cpp b/M6502/src/mos6502.cpp index 6fb8529..f67e5a0 100644 --- a/M6502/src/mos6502.cpp +++ b/M6502/src/mos6502.cpp @@ -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) { diff --git a/Z80/inc/Signal.h b/Z80/inc/Signal.h deleted file mode 100644 index 96a2ad4..0000000 --- a/Z80/inc/Signal.h +++ /dev/null @@ -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); - } -}; diff --git a/Z80/inc/Z80.h b/Z80/inc/Z80.h index 1944085..bdbe2d2 100644 --- a/Z80/inc/Z80.h +++ b/Z80/inc/Z80.h @@ -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; } } diff --git a/Z80/src/Disassembler.cpp b/Z80/src/Disassembler.cpp index 7b9ca78..03d0381 100644 --- a/Z80/src/Disassembler.cpp +++ b/Z80/src/Disassembler.cpp @@ -4,8 +4,10 @@ #include <sstream> #include <iomanip> #include <bitset> +#include <iostream> + +#include <Memory.h> -#include "Memory.h" #include "Z80.h" EightBit::Disassembler::Disassembler() { diff --git a/Z80/src/Z80.cpp b/Z80/src/Z80.cpp index fa1365c..ca334f2 100644 --- a/Z80/src/Z80.cpp +++ b/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; diff --git a/Z80/src/stdafx.h b/Z80/src/stdafx.h index ef248a1..a8e08d0 100644 --- a/Z80/src/stdafx.h +++ b/Z80/src/stdafx.h @@ -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> diff --git a/Z80/test/Board.cpp b/Z80/test/Board.cpp index 3136d69..1ff6f7a 100644 --- a/Z80/test/Board.cpp +++ b/Z80/test/Board.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "Board.h" -#include "Disassembler.h" + +#include <Disassembler.h> Board::Board(const Configuration& configuration) : m_configuration(configuration), diff --git a/Z80/test/stdafx.h b/Z80/test/stdafx.h index 0c89d25..5ec6b1f 100644 --- a/Z80/test/stdafx.h +++ b/Z80/test/stdafx.h @@ -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> diff --git a/Z80/test/test.cpp b/Z80/test/test.cpp index 97cd46e..a44f12f 100644 --- a/Z80/test/test.cpp +++ b/Z80/test/test.cpp @@ -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; diff --git a/inc/InputOutput.h b/inc/InputOutput.h index be22bd3..6696d5f 100644 --- a/inc/InputOutput.h +++ b/inc/InputOutput.h @@ -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; }; } \ No newline at end of file diff --git a/inc/IntelProcessor.h b/inc/IntelProcessor.h index 5ecc6b0..73590a9 100644 --- a/inc/IntelProcessor.h +++ b/inc/IntelProcessor.h @@ -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; }; } \ No newline at end of file diff --git a/inc/Memory.h b/inc/Memory.h index 4a38a23..83921da 100644 --- a/inc/Memory.h +++ b/inc/Memory.h @@ -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, diff --git a/inc/Processor.h b/inc/Processor.h index c6e7713..f762918 100644 --- a/inc/Processor.h +++ b/inc/Processor.h @@ -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; diff --git a/inc/Ram.h b/inc/Ram.h index 45526a5..903c37d 100644 --- a/inc/Ram.h +++ b/inc/Ram.h @@ -19,7 +19,7 @@ namespace EightBit { } uint8_t& reference(uint16_t address) { - return m_bytes[address]; + return BYTES()[address]; } }; } diff --git a/inc/Rom.h b/inc/Rom.h index 5557de1..a33e8f5 100644 --- a/inc/Rom.h +++ b/inc/Rom.h @@ -15,7 +15,7 @@ namespace EightBit { } uint8_t& reference(uint16_t address) { - return m_bytes[address]; + return BYTES()[address]; } }; } \ No newline at end of file diff --git a/inc/Signal.h b/inc/Signal.h index 83445ef..08c596a 100644 --- a/inc/Signal.h +++ b/inc/Signal.h @@ -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); } }; diff --git a/inc/TestHarness.h b/inc/TestHarness.h index 1f4a388..fac13c0 100644 --- a/inc/TestHarness.h +++ b/inc/TestHarness.h @@ -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; } diff --git a/src/InputOutput.cpp b/src/InputOutput.cpp index 7ad30c7..7541b9a 100644 --- a/src/InputOutput.cpp +++ b/src/InputOutput.cpp @@ -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); } diff --git a/src/Processor.cpp b/src/Processor.cpp index b9ffdbb..9555eca 100644 --- a/src/Processor.cpp +++ b/src/Processor.cpp @@ -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;