diff --git a/Intel8080/inc/Intel8080.h b/Intel8080/inc/Intel8080.h index cca4ed3..6080f34 100644 --- a/Intel8080/inc/Intel8080.h +++ b/Intel8080/inc/Intel8080.h @@ -25,6 +25,7 @@ namespace EightBit { Intel8080(Bus& bus, InputOutput& ports); Signal ExecutingInstruction; + Signal ExecutedInstruction; virtual int execute(uint8_t opcode) final; virtual int step() final; @@ -35,7 +36,8 @@ namespace EightBit { virtual register16_t& HL() final; protected: - virtual void reset() final; + virtual void handleRESET() final; + virtual void handleINT() final; private: bool m_interruptEnable = false; diff --git a/Intel8080/src/Intel8080.cpp b/Intel8080/src/Intel8080.cpp index 406e58c..a48ca12 100644 --- a/Intel8080/src/Intel8080.cpp +++ b/Intel8080/src/Intel8080.cpp @@ -23,9 +23,21 @@ EightBit::register16_t& EightBit::Intel8080::HL() { return hl; } -void EightBit::Intel8080::reset() { - IntelProcessor::reset(); +void EightBit::Intel8080::handleRESET() { + Processor::handleRESET(); di(); + addCycles(3); +} + + +void EightBit::Intel8080::handleINT() { + Processor::handleINT(); + raise(HALT()); + if (m_interruptEnable) { + di(); + execute(BUS().DATA()); + } + addCycles(3); } void EightBit::Intel8080::di() { @@ -258,18 +270,17 @@ int EightBit::Intel8080::step() { ExecutingInstruction.fire(*this); resetCycles(); if (LIKELY(powered())) { - if (UNLIKELY(lowered(INT()))) { - raise(HALT()); - raise(INT()); - if (m_interruptEnable) { - di(); - return execute(BUS().DATA()); - } + if (UNLIKELY(lowered(RESET()))) { + handleRESET(); + } else if (UNLIKELY(lowered(INT()))) { + handleINT(); + } else if (UNLIKELY(lowered(HALT()))) { + execute(0); // NOP + } else { + execute(fetchByte()); } - if (UNLIKELY(lowered(HALT()))) - return execute(0); // NOP - return execute(fetchByte()); } + ExecutedInstruction.fire(*this); return cycles(); } diff --git a/Intel8080/test/Board.cpp b/Intel8080/test/Board.cpp index b67e757..5383075 100644 --- a/Intel8080/test/Board.cpp +++ b/Intel8080/test/Board.cpp @@ -18,7 +18,6 @@ void Board::initialise() { m_ram.load(romDirectory + "/8080EX1.COM", 0x100); // Cringle/Bartholomew //m_ram.load(romDirectory + "/CPUTEST.COM", 0x100); // SuperSoft diagnostics - poke(5, 0xc9); // ret m_cpu.ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Cpm, this, std::placeholders::_1)); if (m_configuration.isProfileMode()) { @@ -30,15 +29,23 @@ void Board::initialise() { } CPU().powerOn(); - CPU().PC() = m_configuration.getStartAddress(); + CPU().reset(); + + poke(0, 0xc3); // JMP + poke(1, m_configuration.getStartAddress().low); + poke(2, m_configuration.getStartAddress().high); + + poke(5, 0xc9); // ret } void Board::Cpu_ExecutingInstruction_Cpm(EightBit::Intel8080& cpu) { switch (cpu.PC().word) { case 0x0: // CP/M warm start - CPU().powerOff(); - if (m_configuration.isProfileMode()) { - m_profiler.dump(); + if (++m_warmstartCount == 3) { + CPU().powerOff(); + if (m_configuration.isProfileMode()) { + m_profiler.dump(); + } } break; case 0x5: // BDOS diff --git a/Intel8080/test/Board.h b/Intel8080/test/Board.h index 1846b9c..bbdbd08 100644 --- a/Intel8080/test/Board.h +++ b/Intel8080/test/Board.h @@ -31,6 +31,7 @@ private: EightBit::Intel8080 m_cpu; EightBit::Disassembler m_disassembler; EightBit::Profiler m_profiler; + int m_warmstartCount = 0; void Cpu_ExecutingInstruction_Cpm(EightBit::Intel8080& cpu); diff --git a/LR35902/inc/LR35902.h b/LR35902/inc/LR35902.h index 08c8a57..376510d 100644 --- a/LR35902/inc/LR35902.h +++ b/LR35902/inc/LR35902.h @@ -39,8 +39,6 @@ namespace EightBit { virtual register16_t& DE() final { return de; } virtual register16_t& HL() final { return hl; } - int singleStep(); - protected: virtual void reset() final; virtual int execute(uint8_t opcode) final; diff --git a/LR35902/src/LR35902.cpp b/LR35902/src/LR35902.cpp index 8cadb8d..abe05ff 100644 --- a/LR35902/src/LR35902.cpp +++ b/LR35902/src/LR35902.cpp @@ -277,38 +277,30 @@ void EightBit::GameBoy::LR35902::ccf() { clearFlag(F(), CF, F() & CF); } -int EightBit::GameBoy::LR35902::singleStep() { - - const auto interruptEnable = BUS().peek(IoRegisters::BASE + IoRegisters::IE); - const auto interruptFlags = m_bus.IO().peek(IoRegisters::IF); - - auto masked = interruptEnable & interruptFlags; - if (masked) { - if (IME()) { - m_bus.IO().poke(IoRegisters::IF, 0); - lower(INT()); - const int index = EightBit::findFirstSet(masked); - BUS().DATA() = 0x38 + (index << 3); - } else { - if (halted()) - proceed(); - } - } - - const auto current = step(); - - m_bus.IO().checkTimers(current); - m_bus.IO().transferDma(); - - return current; -} - int EightBit::GameBoy::LR35902::step() { + ExecutingInstruction.fire(*this); m_prefixCB = false; resetCycles(); int ran = 0; if (LIKELY(powered())) { + + const auto interruptEnable = BUS().peek(IoRegisters::BASE + IoRegisters::IE); + const auto interruptFlags = m_bus.IO().peek(IoRegisters::IF); + + auto masked = interruptEnable & interruptFlags; + if (masked) { + if (IME()) { + m_bus.IO().poke(IoRegisters::IF, 0); + lower(INT()); + const int index = EightBit::findFirstSet(masked); + BUS().DATA() = 0x38 + (index << 3); + } else { + if (halted()) + proceed(); + } + } + if (UNLIKELY(lowered(INT()))) { raise(HALT()); raise(INT()); @@ -320,6 +312,10 @@ int EightBit::GameBoy::LR35902::step() { } else { ran = execute(fetchByte()); } + + m_bus.IO().checkTimers(ran); + m_bus.IO().transferDma(); + } ExecutedInstruction.fire(*this); return ran; diff --git a/M6502/src/mos6502.cpp b/M6502/src/mos6502.cpp index 0b0a008..a37ae6e 100644 --- a/M6502/src/mos6502.cpp +++ b/M6502/src/mos6502.cpp @@ -6,6 +6,8 @@ EightBit::MOS6502::MOS6502(Bus& bus) void EightBit::MOS6502::powerOn() { + Processor::powerOn(); + X() = Bit7; Y() = 0; A() = 0; @@ -13,8 +15,6 @@ void EightBit::MOS6502::powerOn() { S() = Mask8; raise(SO()); - - Processor::powerOn(); } int EightBit::MOS6502::step() { diff --git a/MC6809/inc/mc6809.h b/MC6809/inc/mc6809.h index ac41431..e6839f8 100644 --- a/MC6809/inc/mc6809.h +++ b/MC6809/inc/mc6809.h @@ -74,11 +74,17 @@ namespace EightBit { PinLevel& FIRQ() { return m_firq; } protected: - virtual void reset() final; + + // Default push/pop handlers virtual void push(uint8_t value) final { pushS(value); } virtual uint8_t pop() final { return popS(); } + // Interrupt (etc.) handlers + + virtual void handleRESET() final; + virtual void handleNMI() final; + private: const uint8_t RESETvector = 0xfe; // RESET vector const uint8_t NMIvector = 0xfc; // NMI vector @@ -113,8 +119,13 @@ namespace EightBit { return register16_t(low, high); } - register16_t popWordS() { popWord(S()); } - register16_t popWordU() { popWord(U()); } + register16_t popWordS() { return popWord(S()); } + register16_t popWordU() { return popWord(U()); } + + // Interrupt (etc.) handlers + + void handleIRQ(); + void handleFIRQ(); // Execution helpers @@ -122,12 +133,6 @@ namespace EightBit { void execute10(uint8_t opcode); void execute11(uint8_t opcode); - // Interrupt handlers - - void handleNMI(); - void handleIRQ(); - void handleFIRQ(); - // Register selection for "indexed" register16_t& RR(int which); diff --git a/MC6809/src/mc6809.cpp b/MC6809/src/mc6809.cpp index 0163f28..bba3e53 100644 --- a/MC6809/src/mc6809.cpp +++ b/MC6809/src/mc6809.cpp @@ -12,7 +12,9 @@ int EightBit::mc6809::step() { if (LIKELY(powered())) { m_prefix10 = m_prefix11 = false; ExecutingInstruction.fire(*this); - if (lowered(NMI())) + if (lowered(RESET())) + handleRESET(); + else if (lowered(NMI())) handleNMI(); else if (lowered(FIRQ()) && !(CC() & FF)) handleFIRQ(); @@ -27,36 +29,37 @@ int EightBit::mc6809::step() { // Interrupt (etc.) handlers -void EightBit::mc6809::reset() { - Processor::reset(); - DP() = 0; // Reestablish zero page - setFlag(CC(), IF | FF); // Disable IRQ and FIRQ +void EightBit::mc6809::handleRESET() { + Processor::handleRESET(); + raise(NMI()); + DP() = 0; + setFlag(CC(), IF | FF); jump(getWordPaged(0xff, RESETvector)); } void EightBit::mc6809::handleNMI() { - raise(NMI()); - addCycles(21); + Processor::handleNMI(); saveEntireRegisterState(); jump(getWordPaged(0xff, NMIvector)); + addCycles(21); } void EightBit::mc6809::handleIRQ() { - raise(IRQ()); - addCycles(21); + Processor::handleINT(); // Synonymous saveEntireRegisterState(); - setFlag(CC(), IF); // Disable IRQ + setFlag(CC(), IF); jump(getWordPaged(0xff, IRQvector)); + addCycles(21); } void EightBit::mc6809::handleFIRQ() { - addCycles(12); raise(FIRQ()); - clearFlag(CC(), EF); // Clear the EF flag. i.e. this only saves PC and CC + clearFlag(CC(), EF); pushWordS(PC()); pushS(CC()); - setFlag(CC(), IF | FF); // Disable IRQ and FIRQ + setFlag(CC(), IF | FF); jump(getWordPaged(0xff, FIRQvector)); + addCycles(12); } // diff --git a/Z80/inc/Z80.h b/Z80/inc/Z80.h index 440a3ba..b9e4a08 100644 --- a/Z80/inc/Z80.h +++ b/Z80/inc/Z80.h @@ -49,11 +49,13 @@ namespace EightBit { Z80(Bus& bus, InputOutput& ports); Signal ExecutingInstruction; + Signal ExecutedInstruction; PinLevel& M1() { return m_m1Line; } // Out virtual int execute(uint8_t opcode) final; virtual int step() final; + virtual void powerOn() final; virtual register16_t& AF() final; virtual register16_t& BC() final; @@ -83,7 +85,9 @@ namespace EightBit { } protected: - virtual void reset() final; + virtual void handleRESET() final; + virtual void handleNMI() final; + virtual void handleINT() final; private: PinLevel m_m1Line = Low; diff --git a/Z80/src/Z80.cpp b/Z80/src/Z80.cpp index 89e9914..7018cf6 100644 --- a/Z80/src/Z80.cpp +++ b/Z80/src/Z80.cpp @@ -24,9 +24,9 @@ EightBit::register16_t& EightBit::Z80::HL() { return m_registers[m_registerSet][HL_IDX]; } -void EightBit::Z80::reset() { +void EightBit::Z80::powerOn() { - IntelProcessor::reset(); + IntelProcessor::powerOn(); raise(M1()); @@ -34,23 +34,53 @@ void EightBit::Z80::reset() { IM() = 0; REFRESH() = 0; - IV() = 0xff; + IV() = Mask8; exxAF(); exx(); - AF() = 0xffff; - - BC() = 0xffff; - DE() = 0xffff; - HL() = 0xffff; - - IX() = 0xffff; - IY() = 0xffff; + IX() = IY() = AF() = BC() = DE() = HL() = Mask16; m_prefixCB = m_prefixDD = m_prefixED = m_prefixFD = false; } +void EightBit::Z80::handleRESET() { + Processor::handleRESET(); + di(); + addCycles(3); +} + +void EightBit::Z80::handleNMI() { + Processor::handleNMI(); + raise(HALT()); + IFF1() = false; + restart(0x66); + addCycles(13); +} + +void EightBit::Z80::handleINT() { + Processor::handleINT(); + raise(HALT()); + if (IFF1()) { + di(); + switch (IM()) { + case 0: // i8080 equivalent + execute(BUS().DATA()); + break; + case 1: + restart(7 << 3); + addCycles(13); + break; + case 2: + call(MEMPTR() = register16_t(BUS().DATA(), IV())); + addCycles(19); + break; + default: + UNREACHABLE; + } + } +} + void EightBit::Z80::di() { IFF1() = IFF2() = false; } @@ -614,39 +644,19 @@ int EightBit::Z80::step() { resetCycles(); if (LIKELY(powered())) { lower(M1()); - if (UNLIKELY(lowered(NMI()))) { - raise(HALT()); - raise(NMI()); - IFF1() = false; - restart(0x66); - addCycles(13); - return cycles(); + if (UNLIKELY(lowered(RESET()))) { + handleRESET(); + } else if (UNLIKELY(lowered(NMI()))) { + handleNMI(); + } else if (UNLIKELY(lowered(INT()))) { + handleINT(); + } else if (UNLIKELY(lowered(HALT()))) { + execute(0); // NOP + } else { + execute(fetchByte()); } - if (UNLIKELY(lowered(INT()))) { - raise(HALT()); - raise(INT()); - if (IFF1()) { - di(); - switch (IM()) { - case 0: // i8080 equivalent - return execute(BUS().DATA()); - case 1: - restart(7 << 3); - addCycles(13); - return cycles(); - case 2: - call(MEMPTR() = register16_t(BUS().DATA(), IV())); - addCycles(19); - return cycles(); - default: - UNREACHABLE; - } - } - } - if (UNLIKELY(lowered(HALT()))) - return execute(0); // NOP - return execute(fetchByte()); } + ExecutedInstruction.fire(*this); return cycles(); } diff --git a/Z80/test/Board.cpp b/Z80/test/Board.cpp index 52a0294..df05cbc 100644 --- a/Z80/test/Board.cpp +++ b/Z80/test/Board.cpp @@ -18,7 +18,6 @@ void Board::initialise() { m_ram.load(romDirectory + "/zexall.com", 0x100); // Cringle/Bartholomew //m_ram.load(romDirectory + "/CPUTEST.COM", 0x100); // SuperSoft diagnostics - poke(5, 0xc9); // ret m_cpu.ExecutingInstruction.connect(std::bind(&Board::Cpu_ExecutingInstruction_Cpm, this, std::placeholders::_1)); if (m_configuration.isProfileMode()) { @@ -30,7 +29,13 @@ void Board::initialise() { } CPU().powerOn(); - CPU().PC() = m_configuration.getStartAddress(); + CPU().reset(); + + poke(0, 0xc3); // JMP + poke(1, m_configuration.getStartAddress().low); + poke(2, m_configuration.getStartAddress().high); + + poke(5, 0xc9); // ret } void Board::Cpu_ExecutingInstruction_Cpm(EightBit::Z80& cpu) { @@ -38,9 +43,11 @@ void Board::Cpu_ExecutingInstruction_Cpm(EightBit::Z80& cpu) { CPU().powerOff(); switch (cpu.PC().word) { case 0x0: // CP/M warm start - CPU().powerOff(); - if (m_configuration.isProfileMode()) { - m_profiler.dump(); + if (++m_warmstartCount == 3) { + CPU().powerOff(); + if (m_configuration.isProfileMode()) { + m_profiler.dump(); + } } break; case 0x5: // BDOS diff --git a/Z80/test/Board.h b/Z80/test/Board.h index 0dde29c..7f6dd04 100644 --- a/Z80/test/Board.h +++ b/Z80/test/Board.h @@ -32,6 +32,7 @@ private: EightBit::Z80 m_cpu; EightBit::Disassembler m_disassembler; EightBit::Profiler m_profiler; + int m_warmstartCount = 0; void Cpu_ExecutingInstruction_Cpm(EightBit::Z80& cpu); diff --git a/inc/IntelProcessor.h b/inc/IntelProcessor.h index b9b246b..372f3d3 100644 --- a/inc/IntelProcessor.h +++ b/inc/IntelProcessor.h @@ -56,12 +56,12 @@ namespace EightBit { uint8_t& H() { return HL().high; } uint8_t& L() { return HL().low; } + virtual void powerOn() override; + protected: IntelProcessor(Bus& bus); virtual ~IntelProcessor() = default; - virtual void reset() override; - template static void adjustSign(uint8_t& f, const uint8_t value) { setFlag(f, T::SF, value & T::SF); } diff --git a/inc/Processor.h b/inc/Processor.h index 4d8ea21..1b6c941 100644 --- a/inc/Processor.h +++ b/inc/Processor.h @@ -78,11 +78,11 @@ namespace EightBit { PinLevel& POWER() { return m_powerLine; } bool powered() { return raised(POWER()); } - virtual void powerOn() { raise(POWER()); raise(HALT()); reset(); } + virtual void powerOn(); void powerOff() { lower(POWER()); } + void reset() { lower(RESET()); } int run(int limit); - virtual int singleStep(); virtual int step() = 0; virtual int execute(uint8_t opcode) = 0; @@ -102,12 +102,14 @@ namespace EightBit { Processor(Bus& memory); virtual ~Processor() = default; - virtual void reset(); - bool halted() { return lowered(HALT()); } void halt() { --PC(); lower(HALT()); } void proceed() { ++PC(); raise(HALT()); } + virtual void handleRESET(); + virtual void handleNMI(); + virtual void handleINT(); + uint8_t getBytePaged(uint8_t page, uint8_t offset) { return BUS().read(register16_t(offset, page)); } diff --git a/src/IntelProcessor.cpp b/src/IntelProcessor.cpp index a819603..69876af 100644 --- a/src/IntelProcessor.cpp +++ b/src/IntelProcessor.cpp @@ -7,8 +7,8 @@ EightBit::IntelProcessor::IntelProcessor(Bus& bus) m_decodedOpcodes[i] = i; } -void EightBit::IntelProcessor::reset() { - Processor::reset(); +void EightBit::IntelProcessor::powerOn() { + Processor::powerOn(); SP() = AF() = BC() = DE() = HL() = Mask16; } diff --git a/src/Processor.cpp b/src/Processor.cpp index 6916027..cb0af3a 100644 --- a/src/Processor.cpp +++ b/src/Processor.cpp @@ -5,24 +5,30 @@ EightBit::Processor::Processor(Bus& bus) : m_bus(bus) { } -void EightBit::Processor::reset() { - if (lowered(POWER())) - throw std::logic_error("POWER cannot be low"); +void EightBit::Processor::powerOn() { + raise(RESET()); + raise(HALT()); raise(INT()); raise(NMI()); + raise(POWER()); +} + +void EightBit::Processor::handleRESET() { raise(RESET()); PC() = 0; } +void EightBit::Processor::handleNMI() { + raise(NMI()); +} + +void EightBit::Processor::handleINT() { + raise(INT()); +} + int EightBit::Processor::run(const int limit) { int current = 0; while (LIKELY(powered()) && current < limit) - current += singleStep(); + current += step(); return current; } - -int EightBit::Processor::singleStep() { - if (UNLIKELY(lowered(RESET()))) - reset(); - return step(); -}