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:
parent
0fafbf5092
commit
adef2e9b4e
@ -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. */
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user