1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 08:49:37 +00:00

Starts formalising end conditions.

This commit is contained in:
Thomas Harte 2021-01-21 22:36:44 -05:00
parent 0fafbf5092
commit adef2e9b4e
3 changed files with 51 additions and 18 deletions

View File

@ -94,7 +94,7 @@ template <
// work for executors to fill this array, but subsequently performers can be // 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. // indexed by array position, which is a lot more compact than a generic pointer.
std::array<Performer, max_performer_count> performers_; std::array<Performer, max_performer_count> performers_;
ProgramCounterType program_counter_;
/*! /*!
Moves the current point of execution to @c address, updating necessary performer caches 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 // Set flag to terminate any inner loop currently running through
// previously-parsed content. // previously-parsed content.
has_branched_ = true; has_branched_ = true;
program_counter_ = address;
// Temporary implementation: just interpret. // Temporary implementation: just interpret.
program_.clear(); 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<Executor *>(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: private:
bool has_branched_ = false;
int remaining_duration_ = 0;
std::vector<PerformerIndex> program_; std::vector<PerformerIndex> program_;
size_t program_index_ = 0;
/* TODO: almost below here can be shoved off into an LRUCache object, or similar. */ /* TODO: almost below here can be shoved off into an LRUCache object, or similar. */

View File

@ -37,9 +37,11 @@ void Executor::set_rom(const std::vector<uint8_t> &rom) {
reset(); reset();
// TEMPORARY: just to test initial wiring. // TEMPORARY: just to test initial wiring.
for(int c = 0; c < 1300; c++) { run_for(Cycles(13000));
run_to_branch();
} }
void Executor::run_for(Cycles cycles) {
CachingExecutor::run_for(cycles.as<int>());
} }
void Executor::reset() { void Executor::reset() {
@ -126,6 +128,12 @@ template<bool is_brk> inline void Executor::perform_interrupt() {
} }
template <Operation operation, AddressingMode addressing_mode> void Executor::perform() { template <Operation operation, AddressingMode addressing_mode> 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; // Deal with all modes that don't access memory up here;
// those that access memory will go through a slightly longer // those that access memory will go through a slightly longer
// sequence below that wraps the address and checks whether // sequence below that wraps the address and checks whether
@ -135,8 +143,6 @@ template <Operation operation, AddressingMode addressing_mode> void Executor::pe
#define next8() memory_[(program_counter_ + 1) & 0x1fff] #define next8() memory_[(program_counter_ + 1) & 0x1fff]
#define next16() (memory_[(program_counter_ + 1) & 0x1fff] | (memory_[(program_counter_ + 2) & 0x1fff] << 8)) #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 // Underlying assumption below: the instruction stream will never
// overlap with IO ports. // overlap with IO ports.
switch(addressing_mode) { switch(addressing_mode) {
@ -204,7 +210,7 @@ template <Operation operation, AddressingMode addressing_mode> void Executor::pe
case AddressingMode::AbsoluteY: address = next16() + y_; break; case AddressingMode::AbsoluteY: address = next16() + y_; break;
case AddressingMode::ZeroPage: address = next8(); break; case AddressingMode::ZeroPage: address = next8(); break;
case AddressingMode::ZeroPageX: address = (next8() + x_) & 0xff; 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: case AddressingMode::ZeroPageIndirect:
address = next8(); address = next8();
@ -398,6 +404,10 @@ template <Operation operation> void Executor::perform(uint8_t *operand [[maybe_u
overflow_result_ = uint8_t(*operand << 1); overflow_result_ = uint8_t(*operand << 1);
break; break;
case Operation::TST:
set_nz(*operand);
break;
/* /*
Operations affected by the index mode flag: ADC, AND, CMP, EOR, LDA, ORA, and SBC. Operations affected by the index mode flag: ADC, AND, CMP, EOR, LDA, ORA, and SBC.
*/ */
@ -514,9 +524,3 @@ template <Operation operation> void Executor::perform(uint8_t *operand [[maybe_u
} }
#undef set_nz #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);
}

View File

@ -12,6 +12,7 @@
#include "Instruction.hpp" #include "Instruction.hpp"
#include "Parser.hpp" #include "Parser.hpp"
#include "../CachingExecutor.hpp" #include "../CachingExecutor.hpp"
#include "../../ClockReceiver/ClockReceiver.hpp"
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
@ -34,6 +35,11 @@ class Executor: public CachingExecutor {
void set_rom(const std::vector<uint8_t> &rom); void set_rom(const std::vector<uint8_t> &rom);
void reset(); 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: private:
// MARK: - CachingExecutor-facing interface. // MARK: - CachingExecutor-facing interface.
@ -106,8 +112,6 @@ class Executor: public CachingExecutor {
*/ */
template <Operation operation, AddressingMode addressing_mode> void perform(); template <Operation operation, AddressingMode addressing_mode> void perform();
void set_program_counter(uint16_t address);
private: private:
// MARK: - Instruction set state. // MARK: - Instruction set state.
@ -115,7 +119,6 @@ class Executor: public CachingExecutor {
uint8_t memory_[0x2000]; uint8_t memory_[0x2000];
// Registers. // Registers.
uint16_t program_counter_;
uint8_t a_, x_, y_, s_; uint8_t a_, x_, y_, s_;
uint8_t negative_result_ = 0; uint8_t negative_result_ = 0;