1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-08-08 14:25:05 +00:00

Improve formatting, constness in 68k and ARM instruction set implementations.

This commit is contained in:
Thomas Harte
2024-12-01 08:20:24 -05:00
parent 9d87296316
commit 394fe0f1f1
13 changed files with 508 additions and 495 deletions

View File

@@ -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);

View File

@@ -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_;
};
}

View File

@@ -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);
}

View File

@@ -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 116 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.

View File

@@ -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 &reg(bool force_user_mode, uint32_t offset) {
uint32_t &reg(const bool force_user_mode, const uint32_t offset) {
switch(mode_) {
default:
case Mode::User: return active_[offset];

View File

@@ -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));

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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:

View File

@@ -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++) {

View File

@@ -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 &);
}