diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index ee46d66e1..1ba9d7732 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -1342,6 +1342,7 @@ 4BAB62AE1D32730D00DF5BA0 /* Storage.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Storage.hpp; sourceTree = ""; }; 4BAF2B4C2004580C00480230 /* DMK.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DMK.cpp; sourceTree = ""; }; 4BAF2B4D2004580C00480230 /* DMK.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = DMK.hpp; sourceTree = ""; }; + 4BB023FF25212888009F8D90 /* 65816Implementation.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = 65816Implementation.hpp; path = ../../Processors/65816/Implementation/65816Implementation.hpp; sourceTree = ""; }; 4BB06B211F316A3F00600C7A /* ForceInline.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ForceInline.hpp; sourceTree = ""; }; 4BB0A6592044FD3000FB3688 /* SN76489.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SN76489.cpp; sourceTree = ""; }; 4BB0A65A2044FD3000FB3688 /* SN76489.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = SN76489.hpp; sourceTree = ""; }; @@ -3330,6 +3331,7 @@ 4BB73E951B587A5100552FC2 = { isa = PBXGroup; children = ( + 4BB023FF25212888009F8D90 /* 65816Implementation.hpp */, 4B51F70820A521D700AFA2C1 /* Activity */, 4B8944E2201967B4007DE474 /* Analyser */, 4BB73EA01B587A5100552FC2 /* Clock Signal */, diff --git a/Processors/65816/65816.hpp b/Processors/65816/65816.hpp index 25837e6db..24b4344e2 100644 --- a/Processors/65816/65816.hpp +++ b/Processors/65816/65816.hpp @@ -13,21 +13,25 @@ #include #include "../RegisterSizes.hpp" +#include "../../ClockReceiver/ClockReceiver.hpp" namespace CPU { namespace WDC65816 { -enum class Personality { - WDC65816, - WDC65802 -}; - #include "Implementation/65816Storage.hpp" -template class Processor: public ProcessorStorage { +template class Processor: private ProcessorStorage { + public: + Processor(BusHandler &bus_handler) : bus_handler_(bus_handler) {} + void run_for(const Cycles cycles); + + private: + BusHandler &bus_handler_; }; +#include "Implementation/65816Implementation.hpp" + } } diff --git a/Processors/65816/Implementation/65816Implementation.hpp b/Processors/65816/Implementation/65816Implementation.hpp new file mode 100644 index 000000000..3555ca4eb --- /dev/null +++ b/Processors/65816/Implementation/65816Implementation.hpp @@ -0,0 +1,27 @@ +// +// 65816Implementation.hpp +// Clock Signal +// +// Created by Thomas Harte on 27/09/2020. +// Copyright © 2020 Thomas Harte. All rights reserved. +// + +template void Processor::run_for(const Cycles cycles) { + auto int_cycles = cycles.as_integral(); + while(int_cycles--) { + const MicroOp operation = *next_op_; + ++next_op_; + + switch(operation) { + case OperationMoveToNextProgram: + // The exception program will determine the appropriate way to respond + // based on the pending exception if one exists; otherwise just do a + // standard fetch-decode-execute. + next_op_ = &instructions[pending_exceptions_ ? size_t(OperationSlot::Exception) : size_t(OperationSlot::FetchDecodeExecute)]; + continue; + + default: + assert(false); + } + } +} diff --git a/Processors/65816/Implementation/65816Storage.cpp b/Processors/65816/Implementation/65816Storage.cpp index 82fd8b112..31e5642ad 100644 --- a/Processors/65816/Implementation/65816Storage.cpp +++ b/Processors/65816/Implementation/65816Storage.cpp @@ -108,8 +108,15 @@ struct CPU::WDC65816::ProcessorStorageConstructor { void set_exception_generator(Generator generator) { const auto key = std::make_pair(AccessType::Read, generator); const auto map_entry = installed_patterns.find(key); - storage_.instructions[512].program_offset = uint16_t(map_entry->second.first); - storage_.instructions[512].operation = BRK; + storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].program_offset = uint16_t(map_entry->second.first); + storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].operation = BRK; + } + + void install_fetch_decode_execute() { + storage_.instructions[size_t(ProcessorStorage::OperationSlot::FetchDecodeExecute)].program_offset = uint16_t(storage_.micro_ops_.size()); + storage_.instructions[size_t(ProcessorStorage::OperationSlot::FetchDecodeExecute)].operation = NOP; + storage_.micro_ops_.push_back(CycleFetchIncrementPC); + storage_.micro_ops_.push_back(OperationDecode); } /* @@ -979,6 +986,7 @@ ProcessorStorage::ProcessorStorage() { #undef op constructor.set_exception_generator(&ProcessorStorageConstructor::stack_exception); + constructor.install_fetch_decode_execute(); #ifndef NDEBUG assert(micro_ops_.size() < 65536); diff --git a/Processors/65816/Implementation/65816Storage.hpp b/Processors/65816/Implementation/65816Storage.hpp index d3f430a5a..cad67ee3b 100644 --- a/Processors/65816/Implementation/65816Storage.hpp +++ b/Processors/65816/Implementation/65816Storage.hpp @@ -103,7 +103,10 @@ enum MicroOp: uint8_t { OperationPrepareException, /// Complete this set of micr-ops. - OperationMoveToNextProgram + OperationMoveToNextProgram, + + /// Inspects the instruction buffer and thereby selects the next set of micro-ops to schedule. + OperationDecode, }; enum Operation: uint8_t { @@ -165,40 +168,59 @@ enum Operation: uint8_t { class ProcessorStorageConstructor; -class ProcessorStorage { - public: - ProcessorStorage(); +struct ProcessorStorage { + ProcessorStorage(); - // Frustratingly, there is not quite enough space in 16 bits to store both - // the program offset and the operation as currently defined. - struct Instruction { - uint16_t program_offset; - Operation operation; - }; - Instruction instructions[513]; // Arranged as: - // 256 entries: emulation-mode instructions; - // 256 entries: 16-bit instructions; and - // the entry for 'exceptions' (i.e. reset, irq, nmi). + // Frustratingly, there is not quite enough space in 16 bits to store both + // the program offset and the operation as currently defined. + struct Instruction { + uint16_t program_offset; + Operation operation; + }; + Instruction instructions[514]; // Arranged as: + // 256 entries: emulation-mode instructions; + // 256 entries: 16-bit instructions; + // the entry for 'exceptions' (i.e. reset, irq, nmi); and + // the entry for fetch-decode-execute. + enum class OperationSlot { + Exception = 512, + FetchDecodeExecute + }; - private: - friend ProcessorStorageConstructor; + void set_power_on_state() { + // Set next_op_ to any instance of OperationMoveToNextProgram. + for(size_t c = 0; c < micro_ops_.size(); ++c) { + if(micro_ops_[c] == OperationMoveToNextProgram) { + next_op_ = µ_ops_[c]; + break; + } + } - // Registers. - RegisterPair16 a_; - RegisterPair16 x_, y_; - uint16_t pc_, s_; + pending_exceptions_ = PowerOn; + } - // I.e. the offset for direct addressing (outside of emulation mode). - uint16_t direct_; + // Registers. + RegisterPair16 a_; + RegisterPair16 x_, y_; + uint16_t pc_, s_; - // Banking registers are all stored with the relevant byte - // shifted up bits 16–23. - uint32_t data_bank_; // i.e. DBR. - uint32_t program_bank_; // i.e. PBR. + // I.e. the offset for direct addressing (outside of emulation mode). + uint16_t direct_; + // Banking registers are all stored with the relevant byte + // shifted up bits 16–23. + uint32_t data_bank_; // i.e. DBR. + uint32_t program_bank_; // i.e. PBR. - std::vector micro_ops_; + static constexpr int PowerOn = 1 << 0; + static constexpr int Reset = 1 << 1; + static constexpr int IRQ = 1 << 2; + static constexpr int NMI = 1 << 3; + int pending_exceptions_ = 0; + + std::vector micro_ops_; + MicroOp *next_op_ = nullptr; }; #endif /* WDC65816Implementation_h */