mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-14 13:33:42 +00:00
Switches performers to member functions. Very slightly starts work on M50740 performers.
This commit is contained in:
parent
54b26c7991
commit
ad03858c6e
@ -63,7 +63,7 @@ template <
|
||||
public:
|
||||
|
||||
protected:
|
||||
using Performer = void (*)(Executor *);
|
||||
using Performer = void (Executor::*)();
|
||||
using PerformerIndex = typename MinIntTypeValue<max_performer_count>::type;
|
||||
|
||||
std::array<Performer, max_performer_count> performers_;
|
||||
|
@ -20,8 +20,75 @@ Executor::Executor() {
|
||||
}
|
||||
}
|
||||
|
||||
template <Operation operation> void Executor::perform(uint8_t *operand [[maybe_unused]]) {
|
||||
template <Operation operation, AddressingMode addressing_mode> void Executor::perform() {
|
||||
// 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
|
||||
// a write is valid [if required].
|
||||
|
||||
int address;
|
||||
#define next8() memory_[(program_counter_ + 1) & 0x1fff]
|
||||
#define next16() memory_[(program_counter_ + 1) & 0x1fff] | (memory_[(program_counter_ + 2) & 0x1fff] << 8)
|
||||
|
||||
switch(addressing_mode) {
|
||||
|
||||
// Addressing modes with no further memory access.
|
||||
|
||||
case AddressingMode::Implied:
|
||||
perform<operation>(nullptr);
|
||||
++program_counter_;
|
||||
return;
|
||||
|
||||
case AddressingMode::Accumulator:
|
||||
perform<operation>(&a_);
|
||||
++program_counter_;
|
||||
return;
|
||||
|
||||
case AddressingMode::Immediate:
|
||||
perform<operation>(&next8());
|
||||
program_counter_ += 2;
|
||||
return;
|
||||
|
||||
// Addressing modes with a memory access.
|
||||
|
||||
case AddressingMode::Absolute:
|
||||
address = next16();
|
||||
program_counter_ += 3;
|
||||
break;
|
||||
|
||||
case AddressingMode::AbsoluteX:
|
||||
address = next16() + x_;
|
||||
program_counter_ += 3;
|
||||
break;
|
||||
|
||||
case AddressingMode::AbsoluteY:
|
||||
address = next16() + y_;
|
||||
program_counter_ += 3;
|
||||
break;
|
||||
|
||||
/* TODO: the rest. */
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
|
||||
#undef next16
|
||||
#undef next8
|
||||
|
||||
assert(access_type(operation) != AccessType::None);
|
||||
|
||||
if constexpr(access_type(operation) == AccessType::Read) {
|
||||
perform<operation>(&memory_[address & 0x1fff]);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t value = memory_[address & 0x1fff];
|
||||
perform<operation>(&value);
|
||||
|
||||
// TODO: full writing logic here; only the first 96 bytes are RAM,
|
||||
// there are also timers and IO ports to handle.
|
||||
memory_[address & 0x1fff] = value;
|
||||
}
|
||||
|
||||
template <Operation operation, AddressingMode addressing_mode> void Executor::perform(Executor *) {
|
||||
template <Operation operation> void Executor::perform(uint8_t *operand [[maybe_unused]]) {
|
||||
}
|
||||
|
@ -18,17 +18,6 @@ namespace M50740 {
|
||||
|
||||
class Executor;
|
||||
|
||||
/*!
|
||||
M50740 actions require no further context; the addressing mode and operation is baked in,
|
||||
so using the Executor to enquire of memory and the program counter is sufficient.
|
||||
*/
|
||||
struct Action {
|
||||
using Performer = void (*)(Executor *);
|
||||
Performer perform = nullptr;
|
||||
|
||||
inline Action(Performer performer) noexcept : perform(performer) {}
|
||||
};
|
||||
|
||||
class Executor: public CachingExecutor<Executor, 0x2000, 256, false> {
|
||||
public:
|
||||
Executor();
|
||||
@ -58,21 +47,21 @@ class Executor: public CachingExecutor<Executor, 0x2000, 256, false> {
|
||||
fill<int(MinOperation), int(MinAddressingMode)>(performers);
|
||||
}
|
||||
|
||||
Action::Performer performer(Operation operation, AddressingMode addressing_mode) {
|
||||
Performer performer(Operation operation, AddressingMode addressing_mode) {
|
||||
return performers[int(addressing_mode) * (MaxOperation - MinOperation) + int(operation) - MinOperation];
|
||||
}
|
||||
|
||||
private:
|
||||
Action::Performer performers[(MaxAddressingMode - MinAddressingMode) * (MaxOperation - MinOperation)];
|
||||
Performer performers[(MaxAddressingMode - MinAddressingMode) * (MaxOperation - MinOperation)];
|
||||
|
||||
template<int operation, int addressing_mode> void fill_operation(Action::Performer *target) {
|
||||
template<int operation, int addressing_mode> void fill_operation(Performer *target) {
|
||||
*target = &Executor::perform<Operation(operation), AddressingMode(addressing_mode)>;
|
||||
if constexpr (addressing_mode+1 < MaxAddressingMode) {
|
||||
fill_operation<operation, addressing_mode+1>(target + 1);
|
||||
}
|
||||
}
|
||||
|
||||
template<int operation, int addressing_mode> void fill(Action::Performer *target) {
|
||||
template<int operation, int addressing_mode> void fill(Performer *target) {
|
||||
fill_operation<operation, addressing_mode>(target);
|
||||
target += MaxOperation - MinOperation;
|
||||
if constexpr (operation+1 < MaxOperation) {
|
||||
@ -85,16 +74,21 @@ class Executor: public CachingExecutor<Executor, 0x2000, 256, false> {
|
||||
/*!
|
||||
Performs @c operation using @c operand as the value fetched from memory, if any.
|
||||
*/
|
||||
template <Operation operation> static void perform(uint8_t *operand);
|
||||
template <Operation operation> void perform(uint8_t *operand);
|
||||
|
||||
/*!
|
||||
Performs @c operation in @c addressing_mode.
|
||||
*/
|
||||
template <Operation operation, AddressingMode addressing_mode> static void perform(Executor *);
|
||||
template <Operation operation, AddressingMode addressing_mode> void perform();
|
||||
|
||||
private:
|
||||
// MARK: - Instruction set state.
|
||||
|
||||
// Memory.
|
||||
uint8_t memory_[0x2000];
|
||||
|
||||
// Registers.
|
||||
uint8_t a_, x_, y_;
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user