diff --git a/InstructionSets/CachingExecutor.hpp b/InstructionSets/CachingExecutor.hpp index c5fc80753..ec1d58722 100644 --- a/InstructionSets/CachingExecutor.hpp +++ b/InstructionSets/CachingExecutor.hpp @@ -94,7 +94,7 @@ template < // work for executors to fill this array, but subsequently performers can be // indexed by array position, which is a lot more compact than a generic pointer. std::array performers_; - + ProgramCounterType program_counter_; /*! Moves the current point of execution to @c address, updating necessary performer caches @@ -104,6 +104,7 @@ template < // Set flag to terminate any inner loop currently running through // previously-parsed content. has_branched_ = true; + program_counter_ = address; // Temporary implementation: just interpret. program_.clear(); @@ -137,11 +138,36 @@ template < } } - private: - bool has_branched_ = false; + /*! + Runs for @c duration; the intention is that subclasses provide a method + that is clear about units, and call this to count down in whatever units they + count down in. + */ + void run_for(int duration) { + remaining_duration_ += duration; + + while(remaining_duration_ > 0) { + has_branched_ = false; + while(remaining_duration_ > 0 && !has_branched_) { + (static_cast(this)->*performers_[program_index_])(); + ++program_index_; + } + } + } + + /*! + Should be called by a specific executor to subtract from the remaining + running duration. + */ + inline void subtract_duration(int duration) { + remaining_duration_ -= duration; + } private: + bool has_branched_ = false; + int remaining_duration_ = 0; std::vector program_; + size_t program_index_ = 0; /* TODO: almost below here can be shoved off into an LRUCache object, or similar. */ diff --git a/InstructionSets/M50740/Executor.cpp b/InstructionSets/M50740/Executor.cpp index def6927e6..6469e76e0 100644 --- a/InstructionSets/M50740/Executor.cpp +++ b/InstructionSets/M50740/Executor.cpp @@ -37,9 +37,11 @@ void Executor::set_rom(const std::vector &rom) { reset(); // TEMPORARY: just to test initial wiring. - for(int c = 0; c < 1300; c++) { - run_to_branch(); - } + run_for(Cycles(13000)); +} + +void Executor::run_for(Cycles cycles) { + CachingExecutor::run_for(cycles.as()); } void Executor::reset() { @@ -126,6 +128,12 @@ template inline void Executor::perform_interrupt() { } template void Executor::perform() { + printf("%04x\t%02x\t%d %d\t[x:%02x s:%02x]\n", program_counter_ & 0x1fff, memory_[program_counter_ & 0x1fff], int(operation), int(addressing_mode), x_, s_); + + // Post cycle cost; this emulation _does not provide accurate timing_. + // TODO: post actual cycle counts. For now count instructions only. + subtract_duration(1); + // Deal with all modes that don't access memory up here; // those that access memory will go through a slightly longer // sequence below that wraps the address and checks whether @@ -135,8 +143,6 @@ template void Executor::pe #define next8() memory_[(program_counter_ + 1) & 0x1fff] #define next16() (memory_[(program_counter_ + 1) & 0x1fff] | (memory_[(program_counter_ + 2) & 0x1fff] << 8)) - printf("%04x\t%02x\t%d %d\t[x:%02x s:%02x]\n", program_counter_ & 0x1fff, memory_[program_counter_ & 0x1fff], int(operation), int(addressing_mode), x_, s_); - // Underlying assumption below: the instruction stream will never // overlap with IO ports. switch(addressing_mode) { @@ -204,7 +210,7 @@ template void Executor::pe case AddressingMode::AbsoluteY: address = next16() + y_; break; case AddressingMode::ZeroPage: address = next8(); break; case AddressingMode::ZeroPageX: address = (next8() + x_) & 0xff; break; - case AddressingMode::ZeroPageY: address = (next8() + x_) & 0xff; break; + case AddressingMode::ZeroPageY: address = (next8() + y_) & 0xff; break; case AddressingMode::ZeroPageIndirect: address = next8(); @@ -398,6 +404,10 @@ template void Executor::perform(uint8_t *operand [[maybe_u overflow_result_ = uint8_t(*operand << 1); break; + case Operation::TST: + set_nz(*operand); + break; + /* Operations affected by the index mode flag: ADC, AND, CMP, EOR, LDA, ORA, and SBC. */ @@ -514,9 +524,3 @@ template void Executor::perform(uint8_t *operand [[maybe_u } #undef set_nz } - -void Executor::set_program_counter(uint16_t address) { - printf("--- %04x ---\n", (address & 0x1fff) - 0x1000); - program_counter_ = address; - CachingExecutor::set_program_counter(address); -} diff --git a/InstructionSets/M50740/Executor.hpp b/InstructionSets/M50740/Executor.hpp index 744c4da43..7e2617c5c 100644 --- a/InstructionSets/M50740/Executor.hpp +++ b/InstructionSets/M50740/Executor.hpp @@ -12,6 +12,7 @@ #include "Instruction.hpp" #include "Parser.hpp" #include "../CachingExecutor.hpp" +#include "../../ClockReceiver/ClockReceiver.hpp" #include #include @@ -34,6 +35,11 @@ class Executor: public CachingExecutor { void set_rom(const std::vector &rom); void reset(); + /*! + Runs, in discrete steps, the minimum number of instructions as it takes to complete at least @c cycles. + */ + void run_for(Cycles cycles); + private: // MARK: - CachingExecutor-facing interface. @@ -106,8 +112,6 @@ class Executor: public CachingExecutor { */ template void perform(); - void set_program_counter(uint16_t address); - private: // MARK: - Instruction set state. @@ -115,7 +119,6 @@ class Executor: public CachingExecutor { uint8_t memory_[0x2000]; // Registers. - uint16_t program_counter_; uint8_t a_, x_, y_, s_; uint8_t negative_result_ = 0;