1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 08:49:37 +00:00

Regularise data transfers.

This commit is contained in:
Thomas Harte 2024-02-28 21:23:57 -05:00
parent 3b320bcdef
commit 904462b881
2 changed files with 32 additions and 28 deletions

View File

@ -74,9 +74,12 @@ enum class BranchOperation {
BL, /// Copy PC and PSR to R14, then branch. Copied PC points to next instruction. BL, /// Copy PC and PSR to R14, then branch. Copied PC points to next instruction.
}; };
enum class Operation { enum class SingleDataTransferOperation {
LDR, /// Read single byte or word from [base + offset], possibly mutating the base. LDR, /// Read single byte or word from [base + offset], possibly mutating the base.
STR, /// Write a single byte or word to [base + offset], possibly mutating the base. STR, /// Write a single byte or word to [base + offset], possibly mutating the base.
};
enum class BlockDataTransferOperation {
LDM, /// Read 116 words from [base], possibly mutating it. LDM, /// Read 116 words from [base], possibly mutating it.
STM, /// Write 1-16 words to [base], possibly mutating it. STM, /// Write 1-16 words to [base], possibly mutating it.
}; };
@ -240,6 +243,10 @@ private:
struct SingleDataTransferFlags { struct SingleDataTransferFlags {
constexpr SingleDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {} constexpr SingleDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {}
constexpr SingleDataTransferOperation operation() const {
return flag_bit<20>(flags_) ? SingleDataTransferOperation::LDR : SingleDataTransferOperation::STR;
}
constexpr bool offset_is_immediate() const { return flag_bit<25>(flags_); } constexpr bool offset_is_immediate() const { return flag_bit<25>(flags_); }
constexpr bool pre_index() const { return flag_bit<24>(flags_); } constexpr bool pre_index() const { return flag_bit<24>(flags_); }
constexpr bool add_offset() const { return flag_bit<23>(flags_); } constexpr bool add_offset() const { return flag_bit<23>(flags_); }
@ -272,6 +279,10 @@ struct SingleDataTransfer: public WithShiftControlBits {
struct BlockDataTransferFlags { struct BlockDataTransferFlags {
constexpr BlockDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {} constexpr BlockDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {}
constexpr BlockDataTransferOperation operation() const {
return flag_bit<20>(flags_) ? BlockDataTransferOperation::LDM : BlockDataTransferOperation::STM;
}
constexpr bool pre_index() const { return flag_bit<24>(flags_); } constexpr bool pre_index() const { return flag_bit<24>(flags_); }
constexpr bool add_offset() const { return flag_bit<23>(flags_); } constexpr bool add_offset() const { return flag_bit<23>(flags_); }
constexpr bool load_psr() const { return flag_bit<22>(flags_); } constexpr bool load_psr() const { return flag_bit<22>(flags_); }
@ -418,21 +429,13 @@ struct OperationMapper {
// Single data transfer (LDR, STR); cf. p.25. // Single data transfer (LDR, STR); cf. p.25.
if constexpr (((partial >> 26) & 0b11) == 0b01) { if constexpr (((partial >> 26) & 0b11) == 0b01) {
constexpr bool is_ldr = partial & (1 << 20); scheduler.template perform<i>(SingleDataTransfer(instruction));
scheduler.template perform<is_ldr ? Operation::LDR : Operation::STR, i>(
condition,
SingleDataTransfer(instruction)
);
return; return;
} }
// Block data transfer (LDM, STM); cf. p.29. // Block data transfer (LDM, STM); cf. p.29.
if constexpr (((partial >> 25) & 0b111) == 0b100) { if constexpr (((partial >> 25) & 0b111) == 0b100) {
constexpr bool is_ldm = partial & (1 << 20); scheduler.template perform<i>(BlockDataTransfer(instruction));
scheduler.template perform<is_ldm ? Operation::LDM : Operation::STM, i>(
condition,
BlockDataTransfer(instruction)
);
return; return;
} }
@ -475,37 +478,38 @@ struct OperationMapper {
/// A brief documentation of the interface expected by @c dispatch below; will be a concept if/when this project adopts C++20. /// A brief documentation of the interface expected by @c dispatch below; will be a concept if/when this project adopts C++20.
struct SampleScheduler { struct SampleScheduler {
// General template arguments: /// @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);
// Template argument:
// //
// (1) Operation, telling the function which operation to perform. Will always be from the subset // Flags, an opaque type which can be converted into a DataProcessingFlags, MultiplyFlags, etc,
// implied by the operation category; and // by simple construction, to provide all flags that can be baked into the template parameters.
// (2) Flags, an opaque type which can be converted into a DataProcessingFlags, MultiplyFlags, etc,
// by simply construction, to provide all flags that can be baked into the template parameters.
// //
// Arguments are ommitted if not relevant. // Function argument:
// //
// Function arguments: // An operation-specific encapsulation of the operation code for decoding of fields that didn't
//
// (1) Condition, indicating the condition code associated with this operation; and
// (2) An operation-specific encapsulation of the operation code for decoding of fields that didn't
// fit into the template parameters. // fit into the template parameters.
//
// Either or both may be omitted if unnecessary.
template <Flags> void perform(DataProcessing); template <Flags> void perform(DataProcessing);
template <Flags> void perform(Multiply); template <Flags> void perform(Multiply);
template <Operation, Flags> void perform(Condition, SingleDataTransfer); template <Flags> void perform(SingleDataTransfer);
template <Operation, Flags> void perform(Condition, BlockDataTransfer); template <Flags> void perform(BlockDataTransfer);
template <Flags> void perform(Branch); template <Flags> void perform(Branch);
template <Flags> void perform(CoprocessorRegisterTransfer); template <Flags> void perform(CoprocessorRegisterTransfer);
template <Flags> void perform(CoprocessorDataOperation); template <Flags> void perform(CoprocessorDataOperation);
template<Flags> void perform(CoprocessorDataTransfer); template <Flags> void perform(CoprocessorDataTransfer);
// Irregular operations. // Irregular operations.
void software_interrupt(); void software_interrupt();
void unknown(uint32_t opcode); void unknown();
}; };
/// Decodes @c instruction, making an appropriate call into @c scheduler. /// Decodes @c instruction, making an appropriate call into @c scheduler.
/// ///
/// In lieue of C++20, see the sample definition of SampleScheduler above for the expected interface. /// In lieu of C++20, see the sample definition of SampleScheduler above for the expected interface.
template <typename SchedulerT> void dispatch(uint32_t instruction, SchedulerT &scheduler) { template <typename SchedulerT> void dispatch(uint32_t instruction, SchedulerT &scheduler) {
OperationMapper mapper; OperationMapper mapper;

View File

@ -223,8 +223,8 @@ struct Scheduler {
registers_.set_pc(registers_.pc(8) + branch.offset()); registers_.set_pc(registers_.pc(8) + branch.offset());
} }
template <Operation, Flags> void perform(Condition, SingleDataTransfer) {} template <Flags> void perform(SingleDataTransfer) {}
template <Operation, Flags> void perform(Condition, BlockDataTransfer) {} template <Flags> void perform(BlockDataTransfer) {}
void software_interrupt() { void software_interrupt() {
registers_.exception<Registers::Exception::SoftwareInterrupt>(); registers_.exception<Registers::Exception::SoftwareInterrupt>();