1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-04 18:29:40 +00:00

Adds enough logic to start serialising instructions to somewhere.

Possibly extraneous for now, but it means I can start stepping and testing.
This commit is contained in:
Thomas Harte 2020-09-25 17:18:25 -04:00
parent 95af1815c8
commit 22c792dc46
2 changed files with 102 additions and 58 deletions

View File

@ -7,10 +7,83 @@
//
#include "../65816.hpp"
#include <map>
using namespace CPU::WDC65816;
struct CPU::WDC65816::ProcessorStorageConstructor {
// Establish that a storage constructor needs access to ProcessorStorage.
ProcessorStorage &storage_;
ProcessorStorageConstructor(ProcessorStorage &storage) : storage_(storage) {}
enum class AccessType {
Read, Write
};
constexpr AccessType access_type_for_operation(Operation operation) {
switch(operation) {
case ADC: case AND: case BIT: case CMP:
case CPX: case CPY: case EOR: case ORA:
case SBC:
case LDA: case LDX: case LDY:
case JMP: case JSR:
return AccessType::Read;
case STA: case STX: case STY: case STZ:
return AccessType::Write;
}
}
typedef void (* Generator)(AccessType, bool, const std::function<void(MicroOp)>&);
using GeneratorKey = std::tuple<AccessType, Generator>;
std::map<GeneratorKey, std::pair<size_t, size_t>> installed_patterns;
uint8_t opcode = 0;
void install(Generator generator, Operation operation) {
// Determine the access type implied by this operation.
const AccessType access_type = access_type_for_operation(operation);
// Check whether this access type + addressing mode generator has already been generated.
const auto key = std::make_pair(access_type, generator);
const auto map_entry = installed_patterns.find(key);
size_t micro_op_location_8, micro_op_location_16;
// If it wasn't found, generate it now in both 8- and 16-bit variants.
// Otherwise, get the location of the existing entries.
if(map_entry == installed_patterns.end()) {
// Generate 8-bit steps.
micro_op_location_8 = storage_.micro_ops_.size();
(*generator)(access_type, true, [this] (MicroOp op) {
this->storage_.micro_ops_.push_back(op);
});
storage_.micro_ops_.push_back(OperationMoveToNextProgram);
// Generate 16-bit steps.
micro_op_location_16 = storage_.micro_ops_.size();
(*generator)(access_type, false, [this] (MicroOp op) {
this->storage_.micro_ops_.push_back(op);
});
storage_.micro_ops_.push_back(OperationMoveToNextProgram);
// Insert into the map.
installed_patterns[key] = std::make_pair(micro_op_location_8, micro_op_location_16);
} else {
micro_op_location_8 = map_entry->second.first;
micro_op_location_16 = map_entry->second.second;
}
// Fill in the proper table entries and increment the opcode pointer.
storage_.instructions[opcode].program_offset = micro_op_location_8;
storage_.instructions[opcode].operation = operation;
storage_.instructions[opcode + 256].program_offset = micro_op_location_16;
storage_.instructions[opcode + 256].operation = operation;
++opcode;
}
/*
Code below is structured to ease translation from Table 5-7 of the 2018
edition of the WDC 65816 datasheet.
@ -112,41 +185,12 @@ struct CPU::WDC65816::ProcessorStorageConstructor {
}
};
AccessType ProcessorStorage::access_type_for_operation(Operation operation) {
switch(operation) {
case ADC: case AND: case BIT: case CMP:
case CPX: case CPY: case EOR: case ORA:
case SBC:
case LDA: case LDX: case LDY:
case JMP: case JSR:
return AccessType::Read;
case STA: case STX: case STY: case STZ:
return AccessType::Write;
}
}
void ProcessorStorage::install(void (* generator)(AccessType, bool, const std::function<void(MicroOp)>&), Operation operation, ProcessorStorageConstructor &) {
const AccessType access_type = access_type_for_operation(operation);
(*generator)(access_type, true, [] (MicroOp) {});
// TODO:
// (1) use [hash of] pointer to generator to determine whether operation tables have already been built;
// (2) if not, build them in both 8- and 16-bit variations;
// (3) insert appropriate entries into an instruction table for the current instruction; and
// (4) increment the instruction counter.
//
// Additional observation: temporary storage would be helpful, so load that into ProcessorStorageConstructor.
}
ProcessorStorage::ProcessorStorage() {
ProcessorStorageConstructor constructor;
ProcessorStorageConstructor constructor(*this);
// Install the instructions.
#define op(x, y) install(&ProcessorStorageConstructor::x, y, constructor)
#define op(x, y) constructor.install(&ProcessorStorageConstructor::x, y)
/* 0x00 BRK s */
/* 0x01 ORA (d, x) */

View File

@ -45,8 +45,25 @@ enum MicroOp: uint8_t {
OperationMoveToNextProgram
};
enum class AccessType {
Read, Write
enum Operation: uint8_t {
// These perform the named operation using the value in the data buffer;
// they are implicitly AccessType::Read.
ADC, AND, BIT, CMP, CPX, CPY, EOR, ORA, SBC,
// These load the respective register from the data buffer;
// they are implicitly AccessType::Read.
LDA, LDX, LDY,
// These move the respective register (or value) to the data buffer;
// they are implicitly AccessType::Write.
STA, STX, STY, STZ,
/// Loads the PC with the operand from the data buffer.
JMP,
/// Loads the PC with the operand from the daa buffer, replacing
/// it with the old PC.
JSR,
};
class ProcessorStorageConstructor;
@ -55,38 +72,21 @@ class ProcessorStorage {
public:
ProcessorStorage();
enum Operation: uint8_t {
// These perform the named operation using the value in the data buffer;
// they are implicitly AccessType::Read.
ADC, AND, BIT, CMP, CPX, CPY, EOR, ORA, SBC,
// These load the respective register from the data buffer;
// they are implicitly AccessType::Read.
LDA, LDX, LDY,
// These move the respective register (or value) to the data buffer;
// they are implicitly AccessType::Write.
STA, STX, STY, STZ,
/// Loads the PC with the operand from the data buffer.
JMP,
/// Loads the PC with the operand from the daa buffer, replacing
/// it with the old PC.
JSR,
};
struct Instruction {
size_t program_offset;
Operation operation;
};
Instruction instructions[256];
Instruction instructions[512 + 3]; // Arranged as:
// 256 entries: emulation-mode instructions;
// 256 entries: 16-bit instructions;
// reset
// NMI
// IRQ
private:
std::vector<MicroOp> micro_ops_;
friend ProcessorStorageConstructor;
AccessType access_type_for_operation(Operation);
void install(void (* generator)(AccessType, bool, const std::function<void(MicroOp)>&), Operation, ProcessorStorageConstructor &);
std::vector<MicroOp> micro_ops_;
};
#endif /* WDC65816Implementation_h */