From f38d326ca76cb01ef04dc5597721cb7ba35ba23c Mon Sep 17 00:00:00 2001 From: Adrian Conlon Date: Sat, 29 Dec 2018 19:17:36 +0000 Subject: [PATCH] Improve the flexibility of the BUS mapping/read/write architecture. Signed-off-by: Adrian Conlon --- Intel8080/inc/Intel8080.h | 2 +- Intel8080/src/Intel8080.cpp | 10 +++++----- LR35902/inc/LR35902.h | 2 +- LR35902/src/LR35902.cpp | 10 +++++----- MC6809/inc/mc6809.h | 8 ++++---- MC6809/src/mc6809.cpp | 26 +++++++++++++------------- Z80/inc/Z80.h | 2 +- Z80/src/Z80.cpp | 18 +++++++++--------- inc/Bus.h | 5 ++--- inc/Mapper.h | 14 ++++++++++++++ inc/MemoryMapping.h | 2 +- inc/Processor.h | 18 ++++++++++++++---- src/BigEndianProcessor.cpp | 12 ++++++------ src/EightBit.vcxproj | 1 + src/EightBit.vcxproj.filters | 3 +++ src/LittleEndianProcessor.cpp | 12 ++++++------ src/Processor.cpp | 28 ++++++++++++++++++++++++++++ 17 files changed, 114 insertions(+), 59 deletions(-) create mode 100644 inc/Mapper.h diff --git a/Intel8080/inc/Intel8080.h b/Intel8080/inc/Intel8080.h index a2b9018..797ba31 100644 --- a/Intel8080/inc/Intel8080.h +++ b/Intel8080/inc/Intel8080.h @@ -27,7 +27,7 @@ namespace EightBit { Signal ExecutingInstruction; Signal ExecutedInstruction; - virtual int execute(uint8_t opcode) final; + virtual int execute() final; virtual int step() final; virtual register16_t& AF() final; diff --git a/Intel8080/src/Intel8080.cpp b/Intel8080/src/Intel8080.cpp index ba92b92..2bc1c10 100644 --- a/Intel8080/src/Intel8080.cpp +++ b/Intel8080/src/Intel8080.cpp @@ -35,7 +35,7 @@ void EightBit::Intel8080::handleINT() { raise(HALT()); if (m_interruptEnable) { di(); - execute(BUS().DATA()); + Processor::execute(BUS().DATA()); } addCycles(3); } @@ -275,18 +275,18 @@ int EightBit::Intel8080::step() { } else if (UNLIKELY(lowered(INT()))) { handleINT(); } else if (UNLIKELY(lowered(HALT()))) { - execute(0); // NOP + Processor::execute(0); // NOP } else { - execute(fetchByte()); + Processor::execute(fetchByte()); } } ExecutedInstruction.fire(*this); return cycles(); } -int EightBit::Intel8080::execute(const uint8_t opcode) { +int EightBit::Intel8080::execute() { - const auto& decoded = getDecodedOpcode(opcode); + const auto& decoded = getDecodedOpcode(opcode()); const auto x = decoded.x; const auto y = decoded.y; diff --git a/LR35902/inc/LR35902.h b/LR35902/inc/LR35902.h index f48f17c..963ef76 100644 --- a/LR35902/inc/LR35902.h +++ b/LR35902/inc/LR35902.h @@ -36,7 +36,7 @@ namespace EightBit { virtual register16_t& HL() final; protected: - virtual int execute(uint8_t opcode) final; + virtual int execute() final; virtual int step() final; virtual void handleRESET() final; diff --git a/LR35902/src/LR35902.cpp b/LR35902/src/LR35902.cpp index 2c6745f..9de1fae 100644 --- a/LR35902/src/LR35902.cpp +++ b/LR35902/src/LR35902.cpp @@ -326,9 +326,9 @@ int EightBit::GameBoy::LR35902::step() { } else if (UNLIKELY(lowered(INT()))) { handleINT(); } else if (UNLIKELY(lowered(HALT()))) { - execute(0); // NOP + Processor::execute(0); // NOP } else { - execute(fetchByte()); + Processor::execute(fetchByte()); } m_bus.IO().checkTimers(clockCycles()); @@ -339,9 +339,9 @@ int EightBit::GameBoy::LR35902::step() { return clockCycles(); } -int EightBit::GameBoy::LR35902::execute(const uint8_t opcode) { +int EightBit::GameBoy::LR35902::execute() { - const auto& decoded = getDecodedOpcode(opcode); + const auto& decoded = getDecodedOpcode(opcode()); const auto x = decoded.x; const auto y = decoded.y; @@ -750,7 +750,7 @@ void EightBit::GameBoy::LR35902::executeOther(const int x, const int y, const in break; case 1: // CB prefix m_prefixCB = true; - execute(fetchByte()); + Processor::execute(fetchByte()); break; case 6: // DI di(); diff --git a/MC6809/inc/mc6809.h b/MC6809/inc/mc6809.h index 51ece65..fabe759 100644 --- a/MC6809/inc/mc6809.h +++ b/MC6809/inc/mc6809.h @@ -57,7 +57,7 @@ namespace EightBit { Signal ExecutingInstruction; Signal ExecutedInstruction; - virtual int execute(uint8_t opcode) final; + virtual int execute() final; virtual int step() final; virtual void powerOn() final; @@ -148,9 +148,9 @@ namespace EightBit { // Execution helpers - void executeUnprefixed(uint8_t opcode); - void execute10(uint8_t opcode); - void execute11(uint8_t opcode); + void executeUnprefixed(); + void execute10(); + void execute11(); // Register selection for "indexed" register16_t& RR(int which); diff --git a/MC6809/src/mc6809.cpp b/MC6809/src/mc6809.cpp index 6bb741b..0cf6e37 100644 --- a/MC6809/src/mc6809.cpp +++ b/MC6809/src/mc6809.cpp @@ -29,7 +29,7 @@ int EightBit::mc6809::step() { else if (UNLIKELY(lowered(IRQ()) && !interruptMasked())) handleIRQ(); else - execute(fetchByte()); + Processor::execute(fetchByte()); } ExecutedInstruction.fire(*this); return cycles(); @@ -88,32 +88,32 @@ void EightBit::mc6809::handleFIRQ() { // -int EightBit::mc6809::execute(const uint8_t opcode) { +int EightBit::mc6809::execute() { lower(BA()); lower(BS()); const bool prefixed = m_prefix10 || m_prefix11; const bool unprefixed = !prefixed; if (unprefixed) { - executeUnprefixed(opcode); + executeUnprefixed(); } else { if (m_prefix10) - execute10(opcode); + execute10(); else - execute11(opcode); + execute11(); } assert(cycles() > 0); return cycles(); } -void EightBit::mc6809::executeUnprefixed(const uint8_t opcode) { +void EightBit::mc6809::executeUnprefixed() { assert(!(m_prefix10 || m_prefix11)); assert(cycles() == 0); - switch (opcode) { + switch (opcode()) { - case 0x10: m_prefix10 = true; execute(fetchByte()); break; - case 0x11: m_prefix11 = true; execute(fetchByte()); break; + case 0x10: m_prefix10 = true; Processor::execute(fetchByte()); break; + case 0x11: m_prefix11 = true; Processor::execute(fetchByte()); break; // ABX case 0x3a: addCycles(3); X() += B(); break; // ABX (inherent) @@ -475,12 +475,12 @@ void EightBit::mc6809::executeUnprefixed(const uint8_t opcode) { } } -void EightBit::mc6809::execute10(const uint8_t opcode) { +void EightBit::mc6809::execute10() { assert(m_prefix10 && !m_prefix11); assert(cycles() == 0); - switch (opcode) { + switch (opcode()) { // CMP @@ -546,12 +546,12 @@ void EightBit::mc6809::execute10(const uint8_t opcode) { } } -void EightBit::mc6809::execute11(const uint8_t opcode) { +void EightBit::mc6809::execute11() { assert(!m_prefix10 && m_prefix11); assert(cycles() == 0); - switch (opcode) { + switch (opcode()) { // CMP diff --git a/Z80/inc/Z80.h b/Z80/inc/Z80.h index 4574c29..d02a81e 100644 --- a/Z80/inc/Z80.h +++ b/Z80/inc/Z80.h @@ -54,7 +54,7 @@ namespace EightBit { [[nodiscard]] auto& NMI() { return m_nmiLine; } // In [[nodiscard]] auto& M1() { return m_m1Line; } // Out - int execute(uint8_t opcode) final; + int execute() final; int step() final; void powerOn() final; diff --git a/Z80/src/Z80.cpp b/Z80/src/Z80.cpp index b7da64a..6dcb553 100644 --- a/Z80/src/Z80.cpp +++ b/Z80/src/Z80.cpp @@ -67,7 +67,7 @@ void EightBit::Z80::handleINT() { di(); switch (IM()) { case 0: // i8080 equivalent - execute(BUS().DATA()); + Processor::execute(BUS().DATA()); break; case 1: restart(7 << 3); @@ -671,16 +671,16 @@ int EightBit::Z80::step() { } else if (UNLIKELY(lowered(INT()))) { handleINT(); } else if (UNLIKELY(lowered(HALT()))) { - execute(0); // NOP + Processor::execute(0); // NOP } else { - execute(fetchByte()); + Processor::execute(fetchByte()); } } ExecutedInstruction.fire(*this); return cycles(); } -int EightBit::Z80::execute(const uint8_t opcode) { +int EightBit::Z80::execute() { ASSUME(lowered(M1())); @@ -689,7 +689,7 @@ int EightBit::Z80::execute(const uint8_t opcode) { raise(M1()); } - const auto& decoded = getDecodedOpcode(opcode); + const auto& decoded = getDecodedOpcode(opcode()); const auto x = decoded.x; const auto y = decoded.y; @@ -1364,7 +1364,7 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in if (UNLIKELY(m_displaced)) fetchDisplacement(); lower(M1()); - execute(fetchByte()); + Processor::execute(fetchByte()); break; case 2: // OUT (n),A writePort(fetchByte()); @@ -1414,17 +1414,17 @@ void EightBit::Z80::executeOther(const int x, const int y, const int z, const in case 1: // DD prefix m_displaced = m_prefixDD = true; lower(M1()); - execute(fetchByte()); + Processor::execute(fetchByte()); break; case 2: // ED prefix m_prefixED = true; lower(M1()); - execute(fetchByte()); + Processor::execute(fetchByte()); break; case 3: // FD prefix m_displaced = m_prefixFD = true; lower(M1()); - execute(fetchByte()); + Processor::execute(fetchByte()); break; default: UNREACHABLE; diff --git a/inc/Bus.h b/inc/Bus.h index b66142c..3c28d02 100644 --- a/inc/Bus.h +++ b/inc/Bus.h @@ -9,10 +9,10 @@ #include "Signal.h" #include "Register.h" #include "EventArgs.h" -#include "MemoryMapping.h" +#include "Mapper.h" namespace EightBit { - class Bus { + class Bus : public Mapper { public: virtual ~Bus() = default; @@ -54,7 +54,6 @@ namespace EightBit { protected: virtual void initialise() = 0; - [[nodiscard]] virtual MemoryMapping mapping(uint16_t address) = 0; [[nodiscard]] uint8_t& reference(uint16_t address); [[nodiscard]] auto& reference(const register16_t address) { return reference(address.word); } [[nodiscard]] uint8_t& reference() { return reference(ADDRESS()); } diff --git a/inc/Mapper.h b/inc/Mapper.h new file mode 100644 index 0000000..e6d9d43 --- /dev/null +++ b/inc/Mapper.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +#include "MemoryMapping.h" + +namespace EightBit { + class Mapper { + public: + virtual ~Mapper() = default; + + [[nodiscard]] virtual MemoryMapping mapping(uint16_t address) = 0; + }; +} diff --git a/inc/MemoryMapping.h b/inc/MemoryMapping.h index b918dad..59f727b 100644 --- a/inc/MemoryMapping.h +++ b/inc/MemoryMapping.h @@ -9,7 +9,7 @@ namespace EightBit { struct MemoryMapping { - enum class AccessLevel { Unknown, ReadOnly, ReadWrite, }; + enum class AccessLevel { Unknown, ReadOnly, WriteOnly, ReadWrite }; Memory& memory; uint16_t begin = Chip::Mask16; diff --git a/inc/Processor.h b/inc/Processor.h index 0d82159..c27a990 100644 --- a/inc/Processor.h +++ b/inc/Processor.h @@ -29,7 +29,8 @@ namespace EightBit { int run(int limit); virtual int step() = 0; - virtual int execute(uint8_t opcode) = 0; + virtual int execute() = 0; + int execute(uint8_t value); [[nodiscard]] auto cycles() const noexcept { return m_cycles; } @@ -39,6 +40,7 @@ namespace EightBit { protected: Processor(Bus& memory); + [[nodiscard]] auto& opcode() noexcept { return m_opcode; } [[nodiscard]] auto& BUS() noexcept { return m_bus; } [[nodiscard]] auto halted() noexcept { return lowered(HALT()); } @@ -49,16 +51,23 @@ namespace EightBit { virtual void handleINT(); virtual void handleIRQ(); + void busWrite(register16_t address, uint8_t data); + void busWrite(uint8_t data); + virtual void busWrite(); + + [[nodiscard]] uint8_t busRead(register16_t address); + [[nodiscard]] virtual uint8_t busRead(); + [[nodiscard]] auto getBytePaged(const uint8_t page, const uint8_t offset) { - return BUS().read(register16_t(offset, page)); + return busRead(register16_t(offset, page)); } void setBytePaged(const uint8_t page, const uint8_t offset, const uint8_t value) { - BUS().write(register16_t(offset, page), value); + busWrite(register16_t(offset, page), value); } [[nodiscard]] auto fetchByte() { - return BUS().read(PC()++); + return busRead(PC()++); } [[nodiscard]] virtual register16_t getWord() = 0; @@ -102,6 +111,7 @@ namespace EightBit { private: Bus& m_bus; + uint8_t m_opcode = Mask8; int m_cycles = 0; register16_t m_pc; diff --git a/src/BigEndianProcessor.cpp b/src/BigEndianProcessor.cpp index 119919c..b972b89 100644 --- a/src/BigEndianProcessor.cpp +++ b/src/BigEndianProcessor.cpp @@ -5,29 +5,29 @@ EightBit::BigEndianProcessor::BigEndianProcessor(Bus& memory) : Processor(memory) {} EightBit::register16_t EightBit::BigEndianProcessor::getWord() { - const auto high = BUS().read(); + const auto high = busRead(); ++BUS().ADDRESS(); - const auto low = BUS().read(); + const auto low = busRead(); return { low, high }; } void EightBit::BigEndianProcessor::setWord(const register16_t value) { - BUS().write(value.high); + busWrite(value.high); ++BUS().ADDRESS(); - BUS().write(value.low); + busWrite(value.low); } EightBit::register16_t EightBit::BigEndianProcessor::getWordPaged(const uint8_t page, const uint8_t offset) { const auto high = getBytePaged(page, offset); ++BUS().ADDRESS().low; - const auto low = BUS().read(); + const auto low = busRead(); return { low, high }; } void EightBit::BigEndianProcessor::setWordPaged(const uint8_t page, const uint8_t offset, const register16_t value) { setBytePaged(page, offset, value.high); ++BUS().ADDRESS().low; - BUS().write(value.low); + busWrite(value.low); } EightBit::register16_t EightBit::BigEndianProcessor::fetchWord() { diff --git a/src/EightBit.vcxproj b/src/EightBit.vcxproj index 6d89dab..55c8adf 100644 --- a/src/EightBit.vcxproj +++ b/src/EightBit.vcxproj @@ -150,6 +150,7 @@ + diff --git a/src/EightBit.vcxproj.filters b/src/EightBit.vcxproj.filters index b92d1c1..10fdae7 100644 --- a/src/EightBit.vcxproj.filters +++ b/src/EightBit.vcxproj.filters @@ -65,6 +65,9 @@ Header Files + + Header Files + diff --git a/src/LittleEndianProcessor.cpp b/src/LittleEndianProcessor.cpp index 0d99ab4..3b78fa5 100644 --- a/src/LittleEndianProcessor.cpp +++ b/src/LittleEndianProcessor.cpp @@ -5,29 +5,29 @@ EightBit::LittleEndianProcessor::LittleEndianProcessor(Bus& memory) : Processor(memory) {} EightBit::register16_t EightBit::LittleEndianProcessor::getWord() { - const auto low = BUS().read(); + const auto low = busRead(); ++BUS().ADDRESS(); - const auto high = BUS().read(); + const auto high = busRead(); return { low, high }; } void EightBit::LittleEndianProcessor::setWord(const register16_t value) { - BUS().write(value.low); + busWrite(value.low); ++BUS().ADDRESS(); - BUS().write(value.high); + busWrite(value.high); } EightBit::register16_t EightBit::LittleEndianProcessor::getWordPaged(const uint8_t page, const uint8_t offset) { const auto low = getBytePaged(page, offset); ++BUS().ADDRESS().low; - const auto high = BUS().read(); + const auto high = busRead(); return { low, high }; } void EightBit::LittleEndianProcessor::setWordPaged(const uint8_t page, const uint8_t offset, const register16_t value) { setBytePaged(page, offset, value.low); ++BUS().ADDRESS().low; - BUS().write(value.high); + busWrite(value.high); } EightBit::register16_t EightBit::LittleEndianProcessor::fetchWord() { diff --git a/src/Processor.cpp b/src/Processor.cpp index 342f4e6..b11cbae 100644 --- a/src/Processor.cpp +++ b/src/Processor.cpp @@ -25,6 +25,29 @@ void EightBit::Processor::handleIRQ() { raise(IRQ()); } +void EightBit::Processor::busWrite(const register16_t address, const uint8_t data) { + BUS().ADDRESS() = address; + busWrite(data); +} + +void EightBit::Processor::busWrite(const uint8_t data) { + BUS().DATA() = data; + busWrite(); +} + +void EightBit::Processor::busWrite() { + BUS().write(); +} + +uint8_t EightBit::Processor::busRead(const register16_t address) { + BUS().ADDRESS() = address; + return busRead(); +} + +uint8_t EightBit::Processor::busRead() { + return BUS().read(); +} + int EightBit::Processor::run(const int limit) { int current = 0; while (LIKELY(powered() && (current < limit))) @@ -32,6 +55,11 @@ int EightBit::Processor::run(const int limit) { return current; } +int EightBit::Processor::execute(const uint8_t value) { + opcode() = value; + return execute(); +} + // http://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend int8_t EightBit::Processor::signExtend(const int b, uint8_t x) { const uint8_t m = 1 << (b - 1); // mask can be pre-computed if b is fixed