From 904462b881a6ad387b169ee0607c96ec8383c8da Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 28 Feb 2024 21:23:57 -0500 Subject: [PATCH] Regularise data transfers. --- InstructionSets/ARM/OperationMapper.hpp | 56 ++++++++++--------- .../Mac/Clock SignalTests/ARMDecoderTests.mm | 4 +- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/InstructionSets/ARM/OperationMapper.hpp b/InstructionSets/ARM/OperationMapper.hpp index 9f4524849..884bac64f 100644 --- a/InstructionSets/ARM/OperationMapper.hpp +++ b/InstructionSets/ARM/OperationMapper.hpp @@ -74,9 +74,12 @@ enum class BranchOperation { 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. STR, /// Write a single byte or word to [base + offset], possibly mutating the base. +}; + +enum class BlockDataTransferOperation { LDM, /// Read 1–16 words from [base], possibly mutating it. STM, /// Write 1-16 words to [base], possibly mutating it. }; @@ -240,6 +243,10 @@ private: struct SingleDataTransferFlags { 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 pre_index() const { return flag_bit<24>(flags_); } constexpr bool add_offset() const { return flag_bit<23>(flags_); } @@ -272,6 +279,10 @@ struct SingleDataTransfer: public WithShiftControlBits { struct BlockDataTransferFlags { 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 add_offset() const { return flag_bit<23>(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. if constexpr (((partial >> 26) & 0b11) == 0b01) { - constexpr bool is_ldr = partial & (1 << 20); - scheduler.template perform( - condition, - SingleDataTransfer(instruction) - ); + scheduler.template perform(SingleDataTransfer(instruction)); return; } // Block data transfer (LDM, STM); cf. p.29. if constexpr (((partial >> 25) & 0b111) == 0b100) { - constexpr bool is_ldm = partial & (1 << 20); - scheduler.template perform( - condition, - BlockDataTransfer(instruction) - ); + scheduler.template perform(BlockDataTransfer(instruction)); 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. 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 - // implied by the operation category; and - // (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. + // Flags, an opaque type which can be converted into a DataProcessingFlags, MultiplyFlags, etc, + // by simple construction, to provide all flags that can be baked into the template parameters. // - // Arguments are ommitted if not relevant. + // Function argument: // - // Function arguments: - // - // (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 + // An operation-specific encapsulation of the operation code for decoding of fields that didn't // fit into the template parameters. + // + // Either or both may be omitted if unnecessary. template void perform(DataProcessing); template void perform(Multiply); - template void perform(Condition, SingleDataTransfer); - template void perform(Condition, BlockDataTransfer); + template void perform(SingleDataTransfer); + template void perform(BlockDataTransfer); template void perform(Branch); template void perform(CoprocessorRegisterTransfer); template void perform(CoprocessorDataOperation); - template void perform(CoprocessorDataTransfer); + template void perform(CoprocessorDataTransfer); // Irregular operations. void software_interrupt(); - void unknown(uint32_t opcode); + void unknown(); }; /// 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 void dispatch(uint32_t instruction, SchedulerT &scheduler) { OperationMapper mapper; diff --git a/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm b/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm index 0b925efa1..73f828966 100644 --- a/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm +++ b/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm @@ -223,8 +223,8 @@ struct Scheduler { registers_.set_pc(registers_.pc(8) + branch.offset()); } - template void perform(Condition, SingleDataTransfer) {} - template void perform(Condition, BlockDataTransfer) {} + template void perform(SingleDataTransfer) {} + template void perform(BlockDataTransfer) {} void software_interrupt() { registers_.exception();