diff --git a/InstructionSets/ARM/OperationMapper.hpp b/InstructionSets/ARM/OperationMapper.hpp index 088d81dd1..d8b1f34ca 100644 --- a/InstructionSets/ARM/OperationMapper.hpp +++ b/InstructionSets/ARM/OperationMapper.hpp @@ -68,10 +68,12 @@ enum class MultiplyOperation { MLA, /// Rd = Rm * Rs + Rn }; -enum class Operation { +enum class BranchOperation { B, /// Add offset to PC; programmer allows for PC being two words ahead. BL, /// Copy PC and PSR to R14, then branch. Copied PC points to next instruction. +}; +enum class Operation { 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. LDM, /// Read 1–16 words from [base], possibly mutating it. @@ -137,6 +139,18 @@ protected: // // Branch (i.e. B and BL). // +struct BranchFlags { + constexpr BranchFlags(uint8_t flags) noexcept : flags_(flags) {} + + /// @returns The operation to apply. + constexpr BranchOperation operation() const { + return flag_bit<24>(flags_) ? BranchOperation::BL : BranchOperation::B; + } + +private: + uint8_t flags_; +}; + struct Branch { constexpr Branch(uint32_t opcode) noexcept : opcode_(opcode) {} @@ -423,11 +437,7 @@ struct OperationMapper { // Branch and branch with link (B, BL); cf. p.15. if constexpr (((partial >> 25) & 0b111) == 0b101) { - constexpr bool is_bl = partial & (1 << 24); - scheduler.template perform( - condition, - Branch(instruction) - ); + scheduler.template perform(Branch(instruction)); return; } diff --git a/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm b/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm index e8adfd528..59684b901 100644 --- a/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm +++ b/OSBindings/Mac/Clock SignalTests/ARMDecoderTests.mm @@ -114,7 +114,7 @@ struct Scheduler { const bool shift_by_register = !flags.operand2_is_immediate() && fields.shift_count_is_register(); // Write a raw result into the PC proxy if the target is R15; it'll be stored properly later. - uint32_t pc_proxy; + uint32_t pc_proxy = 0; auto &destination = fields.destination() == 15 ? pc_proxy : registers_.active[fields.destination()]; // "When R15 appears in either of the Rn or Rs positions it will give the value @@ -301,12 +301,18 @@ struct Scheduler { } } + template void perform(Branch branch) { + constexpr BranchFlags flags(f); + + if constexpr (flags.operation() == BranchOperation::BL) { + registers_.active[14] = registers_.pc(4); + } + registers_.set_pc(registers_.pc(8) + branch.offset()); + } + template void perform(Condition, SingleDataTransfer) {} template void perform(Condition, BlockDataTransfer) {} - template void perform(Condition condition, Branch branch) { - printf("Branch %sif %d; add %08x\n", op == Operation::BL ? "with link " : "", int(condition), branch.offset()); - } template void perform(Condition, CoprocessorRegisterTransfer) {} template void perform(Condition, CoprocessorDataOperation) {} template void perform(Condition, CoprocessorDataTransfer) {}