mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-27 01:31:42 +00:00
Starts formalising end conditions.
This commit is contained in:
parent
0fafbf5092
commit
adef2e9b4e
@ -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<Performer, max_performer_count> 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<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:
|
||||
bool has_branched_ = false;
|
||||
int remaining_duration_ = 0;
|
||||
std::vector<PerformerIndex> program_;
|
||||
size_t program_index_ = 0;
|
||||
|
||||
/* TODO: almost below here can be shoved off into an LRUCache object, or similar. */
|
||||
|
||||
|
@ -37,9 +37,11 @@ void Executor::set_rom(const std::vector<uint8_t> &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<int>());
|
||||
}
|
||||
|
||||
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() {
|
||||
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 <Operation operation, AddressingMode addressing_mode> 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 <Operation operation, AddressingMode addressing_mode> 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 <Operation operation> 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 <Operation operation> 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);
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "Instruction.hpp"
|
||||
#include "Parser.hpp"
|
||||
#include "../CachingExecutor.hpp"
|
||||
#include "../../ClockReceiver/ClockReceiver.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
@ -34,6 +35,11 @@ class Executor: public CachingExecutor {
|
||||
void set_rom(const std::vector<uint8_t> &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 <Operation operation, AddressingMode addressing_mode> 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;
|
||||
|
Loading…
Reference in New Issue
Block a user