mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-08 14:25:05 +00:00
Improve formatting, const
ness in 68k and ARM instruction set implementations.
This commit is contained in:
@@ -31,7 +31,7 @@ template <> struct Carry<false> {
|
||||
///
|
||||
/// Shift amounts of 0 are given the meaning attributed to them for immediate shift counts.
|
||||
template <ShiftType type, bool set_carry, bool is_immediate_shift>
|
||||
void shift(uint32_t &source, uint32_t amount, typename Carry<set_carry>::type carry) {
|
||||
void shift(uint32_t &source, uint32_t amount, const typename Carry<set_carry>::type carry) {
|
||||
switch(type) {
|
||||
case ShiftType::LogicalLeft:
|
||||
if(amount > 32) {
|
||||
@@ -113,7 +113,7 @@ void shift(uint32_t &source, uint32_t amount, typename Carry<set_carry>::type ca
|
||||
|
||||
/// Acts as per @c shift above, but applies runtime shift-type selection.
|
||||
template <bool set_carry, bool is_immediate_shift>
|
||||
void shift(ShiftType type, uint32_t &source, uint32_t amount, typename Carry<set_carry>::type carry) {
|
||||
void shift(const ShiftType type, uint32_t &source, const uint32_t amount, const typename Carry<set_carry>::type carry) {
|
||||
switch(type) {
|
||||
case ShiftType::LogicalLeft:
|
||||
shift<ShiftType::LogicalLeft, set_carry, is_immediate_shift>(source, amount, carry);
|
||||
|
@@ -74,7 +74,7 @@ struct Instruction {
|
||||
bool sets_flags = false;
|
||||
bool is_byte = false;
|
||||
|
||||
std::string to_string(uint32_t address) const {
|
||||
std::string to_string(const uint32_t address) const {
|
||||
std::ostringstream result;
|
||||
|
||||
// Treat all nevers as nops.
|
||||
@@ -161,17 +161,17 @@ struct Instruction {
|
||||
/// able to vend it later via @c last().
|
||||
template <Model model>
|
||||
struct Disassembler {
|
||||
Instruction last() {
|
||||
Instruction last() const {
|
||||
return instruction_;
|
||||
}
|
||||
|
||||
bool should_schedule(Condition condition) {
|
||||
bool should_schedule(const Condition condition) {
|
||||
instruction_ = Instruction();
|
||||
instruction_.condition = condition;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <Flags f> void perform(DataProcessing fields) {
|
||||
template <Flags f> void perform(const DataProcessing fields) {
|
||||
constexpr DataProcessingFlags flags(f);
|
||||
|
||||
instruction_.operand1.type = Operand::Type::Register;
|
||||
@@ -214,7 +214,7 @@ struct Disassembler {
|
||||
}
|
||||
|
||||
template <Flags> void perform(Multiply) {}
|
||||
template <Flags f> void perform(SingleDataTransfer fields) {
|
||||
template <Flags f> void perform(const SingleDataTransfer fields) {
|
||||
constexpr SingleDataTransferFlags flags(f);
|
||||
instruction_.operation =
|
||||
(flags.operation() == SingleDataTransferFlags::Operation::STR) ?
|
||||
@@ -226,7 +226,7 @@ struct Disassembler {
|
||||
instruction_.operand1.type = Operand::Type::Register;
|
||||
instruction_.operand1.value = fields.base();
|
||||
}
|
||||
template <Flags f> void perform(BlockDataTransfer fields) {
|
||||
template <Flags f> void perform(const BlockDataTransfer fields) {
|
||||
constexpr BlockDataTransferFlags flags(f);
|
||||
instruction_.operation =
|
||||
(flags.operation() == BlockDataTransferFlags::Operation::STM) ?
|
||||
@@ -238,7 +238,7 @@ struct Disassembler {
|
||||
instruction_.operand1.type = Operand::Type::RegisterList;
|
||||
instruction_.operand1.value = fields.register_list();
|
||||
}
|
||||
template <Flags f> void perform(Branch fields) {
|
||||
template <Flags f> void perform(const Branch fields) {
|
||||
constexpr BranchFlags flags(f);
|
||||
instruction_.operation =
|
||||
(flags.operation() == BranchFlags::Operation::BL) ?
|
||||
@@ -264,7 +264,6 @@ struct Disassembler {
|
||||
|
||||
private:
|
||||
Instruction instruction_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@ namespace InstructionSet::ARM {
|
||||
/// Maps from a semantic ARM read of type @c SourceT to either the 8- or 32-bit value observed
|
||||
/// by watching the low 8 bits or all 32 bits of the data bus.
|
||||
template <typename DestinationT, typename SourceT>
|
||||
DestinationT read_bus(SourceT value) {
|
||||
DestinationT read_bus(const SourceT value) {
|
||||
if constexpr (std::is_same_v<DestinationT, SourceT>) {
|
||||
return value;
|
||||
}
|
||||
@@ -57,14 +57,14 @@ struct Executor {
|
||||
|
||||
/// @returns @c true if @c condition implies an appropriate perform call should be made for this instruction,
|
||||
/// @c false otherwise.
|
||||
bool should_schedule(Condition condition) {
|
||||
bool should_schedule(const Condition condition) {
|
||||
// This short-circuit of registers_.test provides the necessary compiler clue that
|
||||
// Condition::AL is not only [[likely]] but [[exceedingly likely]].
|
||||
return condition == Condition::AL ? true : registers_.test(condition);
|
||||
}
|
||||
|
||||
template <bool allow_register, bool set_carry, typename FieldsT>
|
||||
uint32_t decode_shift(FieldsT fields, uint32_t &rotate_carry, uint32_t pc_offset) {
|
||||
uint32_t decode_shift(const FieldsT fields, uint32_t &rotate_carry, const uint32_t pc_offset) {
|
||||
// "When R15 appears in the Rm position it will give the value of the PC together
|
||||
// with the PSR flags to the barrel shifter. ...
|
||||
//
|
||||
@@ -105,7 +105,7 @@ struct Executor {
|
||||
return operand2;
|
||||
}
|
||||
|
||||
template <Flags f> void perform(DataProcessing fields) {
|
||||
template <Flags f> void perform(const DataProcessing fields) {
|
||||
constexpr DataProcessingFlags flags(f);
|
||||
const bool shift_by_register = !flags.operand2_is_immediate() && fields.shift_count_is_register();
|
||||
|
||||
@@ -142,7 +142,10 @@ struct Executor {
|
||||
const auto sub = [&](uint32_t lhs, uint32_t rhs) {
|
||||
conditions = lhs - rhs;
|
||||
|
||||
if constexpr (flags.operation() == DataProcessingOperation::SBC || flags.operation() == DataProcessingOperation::RSC) {
|
||||
if constexpr (
|
||||
flags.operation() == DataProcessingOperation::SBC ||
|
||||
flags.operation() == DataProcessingOperation::RSC
|
||||
) {
|
||||
conditions += registers_.c() - 1;
|
||||
}
|
||||
|
||||
@@ -225,7 +228,7 @@ struct Executor {
|
||||
}
|
||||
}
|
||||
|
||||
template <Flags f> void perform(Multiply fields) {
|
||||
template <Flags f> void perform(const Multiply fields) {
|
||||
constexpr MultiplyFlags flags(f);
|
||||
|
||||
// R15 rules:
|
||||
@@ -252,7 +255,7 @@ struct Executor {
|
||||
}
|
||||
}
|
||||
|
||||
template <Flags f> void perform(Branch branch) {
|
||||
template <Flags f> void perform(const Branch branch) {
|
||||
constexpr BranchFlags flags(f);
|
||||
|
||||
if constexpr (flags.operation() == BranchFlags::Operation::BL) {
|
||||
@@ -261,7 +264,7 @@ struct Executor {
|
||||
set_pc<true>(registers_.pc(4) + branch.offset());
|
||||
}
|
||||
|
||||
template <Flags f> void perform(SingleDataTransfer transfer) {
|
||||
template <Flags f> void perform(const SingleDataTransfer transfer) {
|
||||
constexpr SingleDataTransferFlags flags(f);
|
||||
|
||||
// Calculate offset.
|
||||
@@ -386,7 +389,7 @@ struct Executor {
|
||||
}
|
||||
}
|
||||
}
|
||||
template <Flags f> void perform(BlockDataTransfer transfer) {
|
||||
template <Flags f> void perform(const BlockDataTransfer transfer) {
|
||||
constexpr BlockDataTransferFlags flags(f);
|
||||
constexpr bool is_ldm = flags.operation() == BlockDataTransferFlags::Operation::LDM;
|
||||
|
||||
@@ -573,7 +576,7 @@ struct Executor {
|
||||
}
|
||||
}
|
||||
|
||||
void software_interrupt(SoftwareInterrupt swi) {
|
||||
void software_interrupt(const SoftwareInterrupt swi) {
|
||||
if(control_flow_handler_.should_swi(swi.comment())) {
|
||||
exception<Registers::Exception::SoftwareInterrupt>();
|
||||
}
|
||||
@@ -614,7 +617,7 @@ struct Executor {
|
||||
///
|
||||
/// By default this is not forwarded to the control-flow handler.
|
||||
template <bool notify = false>
|
||||
void set_pc(uint32_t pc) {
|
||||
void set_pc(const uint32_t pc) {
|
||||
registers_.set_pc(pc);
|
||||
if constexpr (notify) {
|
||||
control_flow_handler_.did_set_pc();
|
||||
@@ -637,7 +640,7 @@ private:
|
||||
control_flow_handler_.did_set_pc();
|
||||
}
|
||||
|
||||
void set_status(uint32_t status) {
|
||||
void set_status(const uint32_t status) {
|
||||
registers_.set_status(status);
|
||||
control_flow_handler_.did_set_status();
|
||||
}
|
||||
@@ -650,7 +653,7 @@ private:
|
||||
ControlFlowHandlerTStorage control_flow_handler_;
|
||||
Registers registers_;
|
||||
|
||||
static bool is_invalid_address(uint32_t address) {
|
||||
static bool is_invalid_address(const uint32_t address) {
|
||||
if constexpr (model == Model::ARMv2with32bitAddressing) {
|
||||
return false;
|
||||
}
|
||||
@@ -661,7 +664,7 @@ private:
|
||||
/// Executes the instruction @c instruction which should have been fetched from @c executor.pc(),
|
||||
/// modifying @c executor.
|
||||
template <Model model, typename MemoryT, typename StatusObserverT>
|
||||
void execute(uint32_t instruction, Executor<model, MemoryT, StatusObserverT> &executor) {
|
||||
void execute(const uint32_t instruction, Executor<model, MemoryT, StatusObserverT> &executor) {
|
||||
executor.set_pc(executor.pc() + 4);
|
||||
dispatch<model>(instruction, executor);
|
||||
}
|
||||
|
@@ -35,7 +35,7 @@ static constexpr int FlagsStartBit = 20;
|
||||
using Flags = uint8_t;
|
||||
|
||||
template <int position>
|
||||
constexpr bool flag_bit(uint8_t flags) {
|
||||
constexpr bool flag_bit(const uint8_t flags) {
|
||||
static_assert(position >= 20 && position < 28);
|
||||
return flags & (1 << (position - FlagsStartBit));
|
||||
}
|
||||
@@ -44,7 +44,7 @@ constexpr bool flag_bit(uint8_t flags) {
|
||||
// Methods common to data processing and data transfer.
|
||||
//
|
||||
struct WithShiftControlBits {
|
||||
constexpr WithShiftControlBits(uint32_t opcode) noexcept : opcode_(opcode) {}
|
||||
constexpr WithShiftControlBits(const uint32_t opcode) noexcept : opcode_(opcode) {}
|
||||
|
||||
/// The operand 2 register index if @c operand2_is_immediate() is @c false; meaningless otherwise.
|
||||
uint32_t operand2() const { return opcode_ & 0xf; }
|
||||
@@ -65,7 +65,7 @@ protected:
|
||||
// Branch (i.e. B and BL).
|
||||
//
|
||||
struct BranchFlags {
|
||||
constexpr BranchFlags(uint8_t flags) noexcept : flags_(flags) {}
|
||||
constexpr BranchFlags(const uint8_t flags) noexcept : flags_(flags) {}
|
||||
|
||||
enum class Operation {
|
||||
B, /// Add offset to PC; programmer allows for PC being two words ahead.
|
||||
@@ -82,7 +82,7 @@ private:
|
||||
};
|
||||
|
||||
struct Branch {
|
||||
constexpr Branch(uint32_t opcode) noexcept : opcode_(opcode) {}
|
||||
constexpr Branch(const uint32_t opcode) noexcept : opcode_(opcode) {}
|
||||
|
||||
/// The 26-bit offset to add to the PC.
|
||||
uint32_t offset() const { return (opcode_ & 0xff'ffff) << 2; }
|
||||
@@ -113,7 +113,7 @@ enum class DataProcessingOperation {
|
||||
MVN, /// Rd = NOT Op2.
|
||||
};
|
||||
|
||||
constexpr bool is_logical(DataProcessingOperation operation) {
|
||||
constexpr bool is_logical(const DataProcessingOperation operation) {
|
||||
switch(operation) {
|
||||
case DataProcessingOperation::AND:
|
||||
case DataProcessingOperation::EOR:
|
||||
@@ -129,7 +129,7 @@ constexpr bool is_logical(DataProcessingOperation operation) {
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool is_comparison(DataProcessingOperation operation) {
|
||||
constexpr bool is_comparison(const DataProcessingOperation operation) {
|
||||
switch(operation) {
|
||||
case DataProcessingOperation::TST:
|
||||
case DataProcessingOperation::TEQ:
|
||||
@@ -142,7 +142,7 @@ constexpr bool is_comparison(DataProcessingOperation operation) {
|
||||
}
|
||||
|
||||
struct DataProcessingFlags {
|
||||
constexpr DataProcessingFlags(uint8_t flags) noexcept : flags_(flags) {}
|
||||
constexpr DataProcessingFlags(const uint8_t flags) noexcept : flags_(flags) {}
|
||||
|
||||
/// @returns The operation to apply.
|
||||
constexpr DataProcessingOperation operation() const {
|
||||
@@ -183,7 +183,7 @@ struct DataProcessing: public WithShiftControlBits {
|
||||
// MUL and MLA.
|
||||
//
|
||||
struct MultiplyFlags {
|
||||
constexpr MultiplyFlags(uint8_t flags) noexcept : flags_(flags) {}
|
||||
constexpr MultiplyFlags(const uint8_t flags) noexcept : flags_(flags) {}
|
||||
|
||||
/// @c true if the status register should be updated; @c false otherwise.
|
||||
constexpr bool set_condition_codes() const { return flag_bit<20>(flags_); }
|
||||
@@ -203,7 +203,7 @@ private:
|
||||
};
|
||||
|
||||
struct Multiply {
|
||||
constexpr Multiply(uint32_t opcode) noexcept : opcode_(opcode) {}
|
||||
constexpr Multiply(const uint32_t opcode) noexcept : opcode_(opcode) {}
|
||||
|
||||
/// The destination register index. i.e. 'Rd'.
|
||||
uint32_t destination() const { return (opcode_ >> 16) & 0xf; }
|
||||
@@ -225,7 +225,7 @@ private:
|
||||
// Single data transfer (LDR, STR).
|
||||
//
|
||||
struct SingleDataTransferFlags {
|
||||
constexpr SingleDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {}
|
||||
constexpr SingleDataTransferFlags(const uint8_t flags) noexcept : flags_(flags) {}
|
||||
|
||||
enum class Operation {
|
||||
LDR, /// Read single byte or word from [base + offset], possibly mutating the base.
|
||||
@@ -266,7 +266,7 @@ struct SingleDataTransfer: public WithShiftControlBits {
|
||||
// Block data transfer (LDR, STR).
|
||||
//
|
||||
struct BlockDataTransferFlags {
|
||||
constexpr BlockDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {}
|
||||
constexpr BlockDataTransferFlags(const uint8_t flags) noexcept : flags_(flags) {}
|
||||
|
||||
enum class Operation {
|
||||
LDM, /// Read 1–16 words from [base], possibly mutating it.
|
||||
@@ -311,7 +311,7 @@ struct BlockDataTransfer: public WithShiftControlBits {
|
||||
// Coprocessor data operation.
|
||||
//
|
||||
struct CoprocessorDataOperationFlags {
|
||||
constexpr CoprocessorDataOperationFlags(uint8_t flags) noexcept : flags_(flags) {}
|
||||
constexpr CoprocessorDataOperationFlags(const uint8_t flags) noexcept : flags_(flags) {}
|
||||
|
||||
constexpr int coprocessor_operation() const { return (flags_ >> (FlagsStartBit - 20)) & 0xf; }
|
||||
|
||||
@@ -320,7 +320,7 @@ private:
|
||||
};
|
||||
|
||||
struct CoprocessorDataOperation {
|
||||
constexpr CoprocessorDataOperation(uint32_t opcode) noexcept : opcode_(opcode) {}
|
||||
constexpr CoprocessorDataOperation(const uint32_t opcode) noexcept : opcode_(opcode) {}
|
||||
|
||||
uint32_t operand1() const { return (opcode_ >> 16) & 0xf; }
|
||||
uint32_t operand2() const { return opcode_ & 0xf; }
|
||||
@@ -336,7 +336,7 @@ private:
|
||||
// Coprocessor register transfer.
|
||||
//
|
||||
struct CoprocessorRegisterTransferFlags {
|
||||
constexpr CoprocessorRegisterTransferFlags(uint8_t flags) noexcept : flags_(flags) {}
|
||||
constexpr CoprocessorRegisterTransferFlags(const uint8_t flags) noexcept : flags_(flags) {}
|
||||
|
||||
enum class Operation {
|
||||
MRC, /// Move from coprocessor register to ARM register.
|
||||
@@ -353,7 +353,7 @@ private:
|
||||
};
|
||||
|
||||
struct CoprocessorRegisterTransfer {
|
||||
constexpr CoprocessorRegisterTransfer(uint32_t opcode) noexcept : opcode_(opcode) {}
|
||||
constexpr CoprocessorRegisterTransfer(const uint32_t opcode) noexcept : opcode_(opcode) {}
|
||||
|
||||
uint32_t operand1() const { return (opcode_ >> 16) & 0xf; }
|
||||
uint32_t operand2() const { return opcode_ & 0xf; }
|
||||
@@ -369,7 +369,7 @@ private:
|
||||
// Coprocessor data transfer.
|
||||
//
|
||||
struct CoprocessorDataTransferFlags {
|
||||
constexpr CoprocessorDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {}
|
||||
constexpr CoprocessorDataTransferFlags(const uint8_t flags) noexcept : flags_(flags) {}
|
||||
|
||||
enum class Operation {
|
||||
LDC, /// Coprocessor data transfer load.
|
||||
@@ -392,7 +392,7 @@ private:
|
||||
// Software interrupt.
|
||||
//
|
||||
struct SoftwareInterrupt {
|
||||
constexpr SoftwareInterrupt(uint32_t opcode) noexcept : opcode_(opcode) {}
|
||||
constexpr SoftwareInterrupt(const uint32_t opcode) noexcept : opcode_(opcode) {}
|
||||
|
||||
/// The 24-bit comment field, often decoded by the receiver of an SWI.
|
||||
uint32_t comment() const { return opcode_ & 0xff'ffff; }
|
||||
@@ -402,7 +402,7 @@ private:
|
||||
};
|
||||
|
||||
struct CoprocessorDataTransfer {
|
||||
constexpr CoprocessorDataTransfer(uint32_t opcode) noexcept : opcode_(opcode) {}
|
||||
constexpr CoprocessorDataTransfer(const uint32_t opcode) noexcept : opcode_(opcode) {}
|
||||
|
||||
int base() const { return (opcode_ >> 16) & 0xf; }
|
||||
|
||||
@@ -419,12 +419,12 @@ private:
|
||||
/// Operation mapper; use the free function @c dispatch as defined below.
|
||||
template <Model>
|
||||
struct OperationMapper {
|
||||
static Condition condition(uint32_t instruction) {
|
||||
static Condition condition(const uint32_t instruction) {
|
||||
return Condition(instruction >> 28);
|
||||
}
|
||||
|
||||
template <int i, typename SchedulerT>
|
||||
static void dispatch(uint32_t instruction, SchedulerT &scheduler) {
|
||||
static void dispatch(const uint32_t instruction, SchedulerT &scheduler) {
|
||||
// Put the 8-bit segment of instruction back into its proper place;
|
||||
// this allows all the tests below to be written so as to coordinate
|
||||
// properly with the data sheet, and since it's all compile-time work
|
||||
@@ -507,7 +507,7 @@ struct OperationMapper {
|
||||
struct SampleScheduler {
|
||||
/// @returns @c true if the rest of the instruction should be decoded and supplied
|
||||
/// to the scheduler as defined below; @c false otherwise.
|
||||
bool should_schedule(Condition condition);
|
||||
bool should_schedule(Condition);
|
||||
|
||||
// Template argument:
|
||||
//
|
||||
@@ -537,7 +537,7 @@ struct SampleScheduler {
|
||||
/// Decodes @c instruction, making an appropriate call into @c scheduler.
|
||||
///
|
||||
/// In lieu of C++20, see the sample definition of SampleScheduler above for the expected interface.
|
||||
template <Model model, typename SchedulerT> void dispatch(uint32_t instruction, SchedulerT &scheduler) {
|
||||
template <Model model, typename SchedulerT> void dispatch(const uint32_t instruction, SchedulerT &scheduler) {
|
||||
OperationMapper<model> mapper;
|
||||
|
||||
// Test condition.
|
||||
|
@@ -52,12 +52,12 @@ struct Registers {
|
||||
Registers() = default;
|
||||
|
||||
/// Sets the N and Z flags according to the value of @c result.
|
||||
void set_nz(uint32_t value) {
|
||||
void set_nz(const uint32_t value) {
|
||||
zero_result_ = negative_flag_ = value;
|
||||
}
|
||||
|
||||
/// Sets C if @c value is non-zero; resets it otherwise.
|
||||
void set_c(uint32_t value) {
|
||||
void set_c(const uint32_t value) {
|
||||
carry_flag_ = value;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ struct Registers {
|
||||
}
|
||||
|
||||
/// Sets V if the highest bit of @c value is set; resets it otherwise.
|
||||
void set_v(uint32_t value) {
|
||||
void set_v(const uint32_t value) {
|
||||
overflow_flag_ = value;
|
||||
}
|
||||
|
||||
@@ -83,14 +83,14 @@ struct Registers {
|
||||
}
|
||||
|
||||
/// @returns The full PC + status bits.
|
||||
uint32_t pc_status(uint32_t offset) const {
|
||||
uint32_t pc_status(const uint32_t offset) const {
|
||||
return
|
||||
((active_[15] + offset) & ConditionCode::Address) |
|
||||
status();
|
||||
}
|
||||
|
||||
/// Sets status bits only, subject to mode.
|
||||
void set_status(uint32_t status) {
|
||||
void set_status(const uint32_t status) {
|
||||
// ... in user mode the other flags (I, F, M1, M0) are protected from direct change
|
||||
// but in non-user modes these will also be affected, accepting copies of bits 27, 26,
|
||||
// 1 and 0 of the result respectively.
|
||||
@@ -112,12 +112,12 @@ struct Registers {
|
||||
}
|
||||
|
||||
/// Sets a new PC.
|
||||
void set_pc(uint32_t value) {
|
||||
void set_pc(const uint32_t value) {
|
||||
active_[15] = value & ConditionCode::Address;
|
||||
}
|
||||
|
||||
/// @returns The stored PC plus @c offset limited to 26 bits.
|
||||
uint32_t pc(uint32_t offset) const {
|
||||
uint32_t pc(const uint32_t offset) const {
|
||||
return (active_[15] + offset) & ConditionCode::Address;
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ struct Registers {
|
||||
/// The FIQ went low at least one cycle ago and ConditionCode::FIQDisable was not set.
|
||||
FIQ = 0x1c,
|
||||
};
|
||||
static constexpr uint32_t pc_offset_during(Exception exception) {
|
||||
static constexpr uint32_t pc_offset_during(const Exception exception) {
|
||||
// The below is somewhat convoluted by the assumed execution model:
|
||||
//
|
||||
// * exceptions occuring during execution of an instruction are taken
|
||||
@@ -231,7 +231,7 @@ struct Registers {
|
||||
// MARK: - Condition tests.
|
||||
|
||||
/// @returns @c true if @c condition tests as true; @c false otherwise.
|
||||
bool test(Condition condition) const {
|
||||
bool test(const Condition condition) const {
|
||||
const auto ne = [&]() -> bool {
|
||||
return zero_result_;
|
||||
};
|
||||
@@ -279,7 +279,7 @@ struct Registers {
|
||||
}
|
||||
|
||||
/// Sets current execution mode.
|
||||
void set_mode(Mode target_mode) {
|
||||
void set_mode(const Mode target_mode) {
|
||||
if(mode_ == target_mode) {
|
||||
return;
|
||||
}
|
||||
@@ -335,18 +335,18 @@ struct Registers {
|
||||
mode_ = target_mode;
|
||||
}
|
||||
|
||||
uint32_t &operator[](uint32_t offset) {
|
||||
uint32_t &operator[](const uint32_t offset) {
|
||||
return active_[static_cast<size_t>(offset)];
|
||||
}
|
||||
|
||||
uint32_t operator[](uint32_t offset) const {
|
||||
uint32_t operator[](const uint32_t offset) const {
|
||||
return active_[static_cast<size_t>(offset)];
|
||||
}
|
||||
|
||||
/// @returns A reference to the register at @c offset. If @c force_user_mode is true,
|
||||
/// this will the the user-mode register. Otherwise it'll be that for the current mode. These references
|
||||
/// are guaranteed to remain valid only until the next mode change.
|
||||
uint32_t ®(bool force_user_mode, uint32_t offset) {
|
||||
uint32_t ®(const bool force_user_mode, const uint32_t offset) {
|
||||
switch(mode_) {
|
||||
default:
|
||||
case Mode::User: return active_[offset];
|
||||
|
@@ -57,7 +57,7 @@ template <
|
||||
when page caching.
|
||||
*/
|
||||
}
|
||||
void announce_instruction(ProgramCounterType, InstructionType instruction) {
|
||||
void announce_instruction(ProgramCounterType, const InstructionType instruction) {
|
||||
// Dutifully map the instruction to a performer and keep it.
|
||||
program_.push_back(static_cast<Executor *>(this)->action_for(instruction));
|
||||
|
||||
|
@@ -35,7 +35,12 @@ template <
|
||||
Adds the result of disassembling @c memory which is @c length @c MemoryWords long from @c start_address
|
||||
to the current net total of instructions and recorded memory accesses.
|
||||
*/
|
||||
void disassemble(const MemoryWord *memory, ProgramCounterType location, ProgramCounterType length, ProgramCounterType start_address) {
|
||||
void disassemble(
|
||||
const MemoryWord *const memory,
|
||||
const ProgramCounterType location,
|
||||
const ProgramCounterType length,
|
||||
const ProgramCounterType start_address
|
||||
) {
|
||||
// TODO: possibly, move some of this stuff to instruction-set specific disassemblers, analogous to
|
||||
// the Executor's ownership of the Parser. That would allow handling of stateful parsing.
|
||||
ParserType<decltype(*this), true> parser;
|
||||
@@ -61,16 +66,16 @@ template <
|
||||
}
|
||||
|
||||
void announce_overflow(ProgramCounterType) {}
|
||||
void announce_instruction(ProgramCounterType address, InstructionType instruction) {
|
||||
void announce_instruction(const ProgramCounterType address, const InstructionType instruction) {
|
||||
instructions_[address] = instruction;
|
||||
}
|
||||
void add_entry(ProgramCounterType address) {
|
||||
void add_entry(const ProgramCounterType address) {
|
||||
if(entry_points_.find(address) == entry_points_.end()) {
|
||||
pending_entry_points_.push_back(address);
|
||||
entry_points_.insert(address);
|
||||
}
|
||||
}
|
||||
void add_access(AddressType address, AccessType access_type) {
|
||||
void add_access(const AddressType address, const AccessType access_type) {
|
||||
// TODO.
|
||||
(void)address;
|
||||
(void)access_type;
|
||||
|
@@ -140,7 +140,8 @@ constexpr Operation Predecoder<model>::operation(const OpT op) {
|
||||
}
|
||||
|
||||
template <Model model>
|
||||
template <typename Predecoder<model>::OpT op> uint32_t Predecoder<model>::invalid_operands() {
|
||||
template <typename Predecoder<model>::OpT op>
|
||||
constexpr uint32_t Predecoder<model>::invalid_operands() {
|
||||
constexpr auto Dn = Mask< AddressingMode::DataRegisterDirect >::value;
|
||||
constexpr auto An = Mask< AddressingMode::AddressRegisterDirect >::value;
|
||||
constexpr auto Ind = Mask< AddressingMode::AddressRegisterIndirect >::value;
|
||||
@@ -162,24 +163,25 @@ template <typename Predecoder<model>::OpT op> uint32_t Predecoder<model>::invali
|
||||
//
|
||||
// All modes: the complete set (other than Quick).
|
||||
//
|
||||
static constexpr auto AllModes = Dn | An | Ind | PostInc | PreDec | d16An | d8AnXn | XXXw | XXXl | Imm | d16PC | d8PCXn;
|
||||
static constexpr auto AllModesNoAn = AllModes & ~An;
|
||||
constexpr auto AllModes = Dn | An | Ind | PostInc | PreDec | d16An |
|
||||
d8AnXn | XXXw | XXXl | Imm | d16PC | d8PCXn;
|
||||
constexpr auto AllModesNoAn = AllModes & ~An;
|
||||
|
||||
//
|
||||
// Alterable addressing modes (with and without AddressRegisterDirect).
|
||||
//
|
||||
static constexpr auto AlterableAddressingModes = Dn | An | Ind | PostInc | PreDec | d16An | d8AnXn | XXXw | XXXl;
|
||||
static constexpr auto AlterableAddressingModesNoAn = AlterableAddressingModes & ~An;
|
||||
constexpr auto AlterableAddressingModes = Dn | An | Ind | PostInc | PreDec | d16An | d8AnXn | XXXw | XXXl;
|
||||
constexpr auto AlterableAddressingModesNoAn = AlterableAddressingModes & ~An;
|
||||
|
||||
//
|
||||
// Control [flow] addressing modes.
|
||||
//
|
||||
static constexpr auto ControlAddressingModes = Ind | d16An | d8AnXn | XXXw | XXXl | d16PC | d8PCXn;
|
||||
constexpr auto ControlAddressingModes = Ind | d16An | d8AnXn | XXXw | XXXl | d16PC | d8PCXn;
|
||||
|
||||
//
|
||||
// An invalid response, used as the default case.
|
||||
//
|
||||
static constexpr auto InvalidOperands = uint32_t(~0);
|
||||
constexpr auto InvalidOperands = uint32_t(~0);
|
||||
|
||||
switch(op) {
|
||||
default: break;
|
||||
@@ -620,7 +622,8 @@ template <typename Predecoder<model>::OpT op> uint32_t Predecoder<model>::invali
|
||||
|
||||
/// Provides a post-decoding validation step — primarily ensures that the prima facie addressing modes are supported by the operation.
|
||||
template <Model model>
|
||||
template <typename Predecoder<model>::OpT op, bool validate> Preinstruction Predecoder<model>::validated(
|
||||
template <typename Predecoder<model>::OpT op, bool validate>
|
||||
constexpr Preinstruction Predecoder<model>::validated(
|
||||
const AddressingMode op1_mode, const int op1_reg,
|
||||
const AddressingMode op2_mode, const int op2_reg,
|
||||
const Condition condition,
|
||||
@@ -656,7 +659,10 @@ template <typename Predecoder<model>::OpT op, bool validate> Preinstruction Pred
|
||||
/// Decodes the fields within an instruction and constructs a `Preinstruction`, given that the operation has already been
|
||||
/// decoded. Optionally applies validation
|
||||
template <Model model>
|
||||
template <typename Predecoder<model>::OpT op, bool validate> Preinstruction Predecoder<model>::decode(const uint16_t instruction) {
|
||||
template <typename Predecoder<model>::OpT op, bool validate>
|
||||
constexpr Preinstruction Predecoder<model>::decode(
|
||||
const uint16_t instruction
|
||||
) {
|
||||
// Fields used pervasively below.
|
||||
//
|
||||
// Underlying assumption: the compiler will discard whatever of these
|
||||
@@ -1273,7 +1279,7 @@ template <typename Predecoder<model>::OpT op, bool validate> Preinstruction Pred
|
||||
#define DecodeReq(x, y) if constexpr (x) Decode(y); break;
|
||||
|
||||
template <Model model>
|
||||
Preinstruction Predecoder<model>::decode0(const uint16_t instruction) {
|
||||
constexpr Preinstruction Predecoder<model>::decode0(const uint16_t instruction) {
|
||||
using Op = Operation;
|
||||
|
||||
switch(instruction & 0xfff) {
|
||||
@@ -1386,7 +1392,7 @@ Preinstruction Predecoder<model>::decode0(const uint16_t instruction) {
|
||||
}
|
||||
|
||||
template <Model model>
|
||||
Preinstruction Predecoder<model>::decode1(const uint16_t instruction) {
|
||||
constexpr Preinstruction Predecoder<model>::decode1(const uint16_t instruction) {
|
||||
using Op = Operation;
|
||||
|
||||
// 4-116 (p220)
|
||||
@@ -1394,7 +1400,7 @@ Preinstruction Predecoder<model>::decode1(const uint16_t instruction) {
|
||||
}
|
||||
|
||||
template <Model model>
|
||||
Preinstruction Predecoder<model>::decode2(const uint16_t instruction) {
|
||||
constexpr Preinstruction Predecoder<model>::decode2(const uint16_t instruction) {
|
||||
using Op = Operation;
|
||||
|
||||
// 4-116 (p220)
|
||||
@@ -1405,7 +1411,7 @@ Preinstruction Predecoder<model>::decode2(const uint16_t instruction) {
|
||||
}
|
||||
|
||||
template <Model model>
|
||||
Preinstruction Predecoder<model>::decode3(const uint16_t instruction) {
|
||||
constexpr Preinstruction Predecoder<model>::decode3(const uint16_t instruction) {
|
||||
using Op = Operation;
|
||||
|
||||
// 4-116 (p220)
|
||||
@@ -1416,7 +1422,7 @@ Preinstruction Predecoder<model>::decode3(const uint16_t instruction) {
|
||||
}
|
||||
|
||||
template <Model model>
|
||||
Preinstruction Predecoder<model>::decode4(const uint16_t instruction) {
|
||||
constexpr Preinstruction Predecoder<model>::decode4(const uint16_t instruction) {
|
||||
using Op = Operation;
|
||||
|
||||
switch(instruction & 0xfff) {
|
||||
@@ -1539,7 +1545,7 @@ Preinstruction Predecoder<model>::decode4(const uint16_t instruction) {
|
||||
}
|
||||
|
||||
template <Model model>
|
||||
Preinstruction Predecoder<model>::decode5(const uint16_t instruction) {
|
||||
constexpr Preinstruction Predecoder<model>::decode5(const uint16_t instruction) {
|
||||
using Op = Operation;
|
||||
|
||||
switch(instruction & 0x1f8) {
|
||||
@@ -1617,7 +1623,7 @@ Preinstruction Predecoder<model>::decode5(const uint16_t instruction) {
|
||||
}
|
||||
|
||||
template <Model model>
|
||||
Preinstruction Predecoder<model>::decode6(const uint16_t instruction) {
|
||||
constexpr Preinstruction Predecoder<model>::decode6(const uint16_t instruction) {
|
||||
using Op = Operation;
|
||||
|
||||
switch(instruction & 0xf00) {
|
||||
@@ -1649,7 +1655,7 @@ Preinstruction Predecoder<model>::decode6(const uint16_t instruction) {
|
||||
}
|
||||
|
||||
template <Model model>
|
||||
Preinstruction Predecoder<model>::decode7(const uint16_t instruction) {
|
||||
constexpr Preinstruction Predecoder<model>::decode7(const uint16_t instruction) {
|
||||
// 4-134 (p238)
|
||||
if(!(instruction & 0x100)) {
|
||||
Decode(MOVEQ);
|
||||
@@ -1659,7 +1665,7 @@ Preinstruction Predecoder<model>::decode7(const uint16_t instruction) {
|
||||
}
|
||||
|
||||
template <Model model>
|
||||
Preinstruction Predecoder<model>::decode8(const uint16_t instruction) {
|
||||
constexpr Preinstruction Predecoder<model>::decode8(const uint16_t instruction) {
|
||||
using Op = Operation;
|
||||
|
||||
switch(instruction & 0x1f0) {
|
||||
@@ -1689,7 +1695,7 @@ Preinstruction Predecoder<model>::decode8(const uint16_t instruction) {
|
||||
}
|
||||
|
||||
template <Model model>
|
||||
Preinstruction Predecoder<model>::decode9(const uint16_t instruction) {
|
||||
constexpr Preinstruction Predecoder<model>::decode9(const uint16_t instruction) {
|
||||
using Op = Operation;
|
||||
|
||||
switch(instruction & 0x1f0) {
|
||||
@@ -1721,12 +1727,12 @@ Preinstruction Predecoder<model>::decode9(const uint16_t instruction) {
|
||||
}
|
||||
|
||||
template <Model model>
|
||||
Preinstruction Predecoder<model>::decodeA(const uint16_t) {
|
||||
constexpr Preinstruction Predecoder<model>::decodeA(const uint16_t) {
|
||||
return Preinstruction();
|
||||
}
|
||||
|
||||
template <Model model>
|
||||
Preinstruction Predecoder<model>::decodeB(const uint16_t instruction) {
|
||||
constexpr Preinstruction Predecoder<model>::decodeB(const uint16_t instruction) {
|
||||
using Op = Operation;
|
||||
|
||||
switch(instruction & 0x1f8) {
|
||||
@@ -1760,7 +1766,7 @@ Preinstruction Predecoder<model>::decodeB(const uint16_t instruction) {
|
||||
}
|
||||
|
||||
template <Model model>
|
||||
Preinstruction Predecoder<model>::decodeC(const uint16_t instruction) {
|
||||
constexpr Preinstruction Predecoder<model>::decodeC(const uint16_t instruction) {
|
||||
using Op = Operation;
|
||||
|
||||
// 4-105 (p209)
|
||||
@@ -1795,7 +1801,7 @@ Preinstruction Predecoder<model>::decodeC(const uint16_t instruction) {
|
||||
}
|
||||
|
||||
template <Model model>
|
||||
Preinstruction Predecoder<model>::decodeD(const uint16_t instruction) {
|
||||
constexpr Preinstruction Predecoder<model>::decodeD(const uint16_t instruction) {
|
||||
using Op = Operation;
|
||||
|
||||
switch(instruction & 0x1f0) {
|
||||
@@ -1827,7 +1833,7 @@ Preinstruction Predecoder<model>::decodeD(const uint16_t instruction) {
|
||||
}
|
||||
|
||||
template <Model model>
|
||||
Preinstruction Predecoder<model>::decodeE(const uint16_t instruction) {
|
||||
constexpr Preinstruction Predecoder<model>::decodeE(const uint16_t instruction) {
|
||||
using Op = Operation;
|
||||
|
||||
switch(instruction & 0xfc0) {
|
||||
@@ -1900,7 +1906,7 @@ Preinstruction Predecoder<model>::decodeE(const uint16_t instruction) {
|
||||
}
|
||||
|
||||
template <Model model>
|
||||
Preinstruction Predecoder<model>::decodeF(const uint16_t) {
|
||||
constexpr Preinstruction Predecoder<model>::decodeF(const uint16_t) {
|
||||
return Preinstruction();
|
||||
}
|
||||
|
||||
|
@@ -27,27 +27,27 @@ namespace InstructionSet::M68k {
|
||||
*/
|
||||
template <Model model> class Predecoder {
|
||||
public:
|
||||
Preinstruction decode(uint16_t instruction);
|
||||
static Preinstruction decode(uint16_t);
|
||||
|
||||
private:
|
||||
// Page by page decoders; each gets a bit ad hoc so
|
||||
// it is neater to separate them.
|
||||
Preinstruction decode0(uint16_t instruction);
|
||||
Preinstruction decode1(uint16_t instruction);
|
||||
Preinstruction decode2(uint16_t instruction);
|
||||
Preinstruction decode3(uint16_t instruction);
|
||||
Preinstruction decode4(uint16_t instruction);
|
||||
Preinstruction decode5(uint16_t instruction);
|
||||
Preinstruction decode6(uint16_t instruction);
|
||||
Preinstruction decode7(uint16_t instruction);
|
||||
Preinstruction decode8(uint16_t instruction);
|
||||
Preinstruction decode9(uint16_t instruction);
|
||||
Preinstruction decodeA(uint16_t instruction);
|
||||
Preinstruction decodeB(uint16_t instruction);
|
||||
Preinstruction decodeC(uint16_t instruction);
|
||||
Preinstruction decodeD(uint16_t instruction);
|
||||
Preinstruction decodeE(uint16_t instruction);
|
||||
Preinstruction decodeF(uint16_t instruction);
|
||||
static constexpr Preinstruction decode0(uint16_t);
|
||||
static constexpr Preinstruction decode1(uint16_t);
|
||||
static constexpr Preinstruction decode2(uint16_t);
|
||||
static constexpr Preinstruction decode3(uint16_t);
|
||||
static constexpr Preinstruction decode4(uint16_t);
|
||||
static constexpr Preinstruction decode5(uint16_t);
|
||||
static constexpr Preinstruction decode6(uint16_t);
|
||||
static constexpr Preinstruction decode7(uint16_t);
|
||||
static constexpr Preinstruction decode8(uint16_t);
|
||||
static constexpr Preinstruction decode9(uint16_t);
|
||||
static constexpr Preinstruction decodeA(uint16_t);
|
||||
static constexpr Preinstruction decodeB(uint16_t);
|
||||
static constexpr Preinstruction decodeC(uint16_t);
|
||||
static constexpr Preinstruction decodeD(uint16_t);
|
||||
static constexpr Preinstruction decodeE(uint16_t);
|
||||
static constexpr Preinstruction decodeF(uint16_t);
|
||||
|
||||
// Yuckiness here: 67 is a count of the number of things contained below in
|
||||
// ExtendedOperation; this acts to ensure ExtendedOperation is the minimum
|
||||
@@ -60,14 +60,14 @@ template <Model model> class Predecoder {
|
||||
static constexpr auto OpMax = OpT(OperationMax<model>::value);
|
||||
|
||||
// Specific instruction decoders.
|
||||
template <OpT operation, bool validate = true> Preinstruction decode(uint16_t instruction);
|
||||
template <OpT operation, bool validate> Preinstruction validated(
|
||||
template <OpT operation, bool validate = true> static constexpr Preinstruction decode(uint16_t instruction);
|
||||
template <OpT operation, bool validate> static constexpr Preinstruction validated(
|
||||
AddressingMode op1_mode = AddressingMode::None, int op1_reg = 0,
|
||||
AddressingMode op2_mode = AddressingMode::None, int op2_reg = 0,
|
||||
Condition condition = Condition::True,
|
||||
int further_extension_words = 0
|
||||
);
|
||||
template <OpT operation> uint32_t invalid_operands();
|
||||
template <OpT operation> static constexpr uint32_t invalid_operands();
|
||||
|
||||
// Extended operation list; collapses into a single byte enough information to
|
||||
// know both the type of operation and how to decode the operands. Most of the
|
||||
|
@@ -37,12 +37,12 @@ struct BusHandler {
|
||||
/// Write @c value of type/size @c IntT to @c address with the processor signalling
|
||||
/// a FunctionCode of @c function. @c IntT will be one of @c uint8_t, @c uint16_t
|
||||
/// or @c uint32_t.
|
||||
template <typename IntT> void write(uint32_t address, IntT value, FunctionCode function);
|
||||
template <typename IntT> void write(uint32_t address, IntT value, FunctionCode);
|
||||
|
||||
/// Read and return a value of type/size @c IntT from @c address with the processor signalling
|
||||
/// a FunctionCode of @c function. @c IntT will be one of @c uint8_t, @c uint16_t
|
||||
/// or @c uint32_t.
|
||||
template <typename IntT> IntT read(uint32_t address, FunctionCode function);
|
||||
template <typename IntT> IntT read(uint32_t address, FunctionCode);
|
||||
|
||||
/// React to the processor programmatically strobing its RESET output.
|
||||
void reset();
|
||||
@@ -80,7 +80,7 @@ template <Model model, typename BusHandler> class Executor {
|
||||
void set_interrupt_level(int);
|
||||
|
||||
// State for the executor is just the register set.
|
||||
RegisterSet get_state();
|
||||
RegisterSet get_state() const;
|
||||
void set_state(const RegisterSet &);
|
||||
|
||||
private:
|
||||
|
@@ -101,7 +101,7 @@ void Executor<model, BusHandler>::run_for_instructions(int count) {
|
||||
}
|
||||
|
||||
template <Model model, typename BusHandler>
|
||||
RegisterSet Executor<model, BusHandler>::get_state() {
|
||||
RegisterSet Executor<model, BusHandler>::get_state() const {
|
||||
RegisterSet result;
|
||||
|
||||
for(int c = 0; c < 8; c++) {
|
||||
|
@@ -163,7 +163,7 @@ template <
|
||||
Model model,
|
||||
typename FlowController,
|
||||
Operation operation = Operation::Undefined
|
||||
> void perform(Preinstruction instruction, CPU::RegisterPair32 &source, CPU::RegisterPair32 &dest, Status &status, FlowController &flow_controller);
|
||||
> void perform(Preinstruction, CPU::RegisterPair32 &source, CPU::RegisterPair32 &dest, Status &, FlowController &);
|
||||
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user