From e986ae2878ed53d7c90b3aa0b1ef54650486c3d4 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 21 Feb 2024 15:25:57 -0500 Subject: [PATCH] Add coprocessor data operations and register transfers. --- InstructionSets/ARM/Decoder.hpp | 145 ++++++++++++++---- InstructionSets/ARM/Instruction.hpp | 40 ----- InstructionSets/ARM/Operation.hpp | 5 +- .../Clock Signal.xcodeproj/project.pbxproj | 2 - 4 files changed, 117 insertions(+), 75 deletions(-) delete mode 100644 InstructionSets/ARM/Instruction.hpp diff --git a/InstructionSets/ARM/Decoder.hpp b/InstructionSets/ARM/Decoder.hpp index 257fba017..e2dd01866 100644 --- a/InstructionSets/ARM/Decoder.hpp +++ b/InstructionSets/ARM/Decoder.hpp @@ -47,7 +47,6 @@ struct WithShiftControlBits { /// The amount to shift by if @c shift_count_is_register() is @c false; meaningless otherwise. int shift_amount() const { return (opcode_ >> 7) & 0x1f; } - protected: uint32_t opcode_; }; @@ -150,10 +149,69 @@ struct SingleDataTransfer: public WithShiftControlBits { int immediate() const { return opcode_ & 0xfff; } }; +// +// Block data transfer (LDR, STR). +// +struct BlockDataTransferFlags { + constexpr BlockDataTransferFlags(uint8_t flags) noexcept : flags_(flags) {} + + constexpr bool pre_index() { return flag_bit<24>(flags_); } + constexpr bool add_offset() { return flag_bit<23>(flags_); } + constexpr bool load_psr() { return flag_bit<22>(flags_); } + constexpr bool write_back_address() { return flag_bit<21>(flags_); } + +private: + uint8_t flags_; +}; + +struct BlockDataTransfer: public WithShiftControlBits { + using WithShiftControlBits::WithShiftControlBits; + + /// The base register index. i.e. 'Rn'. + int base() const { return (opcode_ >> 16) & 0xf; } + + /// A bitfield indicating which registers to load or store. + int register_list() const { return opcode_ & 0xffff; } +}; + +// +// Coprocessor data operation and register transfer. +// +struct CoprocessorDataOperationFlags { + constexpr CoprocessorDataOperationFlags(uint8_t flags) noexcept : flags_(flags) {} + + constexpr int operation() const { return (flags_ >> (FlagsStartBit - 20)) & 0xf; } + +private: + uint8_t flags_; +}; + +struct CoprocessorRegisterTransferFlags { + constexpr CoprocessorRegisterTransferFlags(uint8_t flags) noexcept : flags_(flags) {} + + constexpr int operation() const { return (flags_ >> (FlagsStartBit - 20)) & 0x7; } + +private: + uint8_t flags_; +}; + +struct CoprocessorOperationOrRegisterTransfer { + constexpr CoprocessorOperationOrRegisterTransfer(uint32_t opcode) noexcept : opcode_(opcode) {} + + int operand1() { return (opcode_ >> 16) & 0xf; } + int operand2() { return opcode_ & 0xf; } + int destination() { return (opcode_ >> 12) & 0xf; } + int coprocessor() { return (opcode_ >> 8) & 0xf; } + int information() { return (opcode_ >> 5) & 0x7; } + +protected: + uint32_t opcode_; +}; struct OperationMapper { template void dispatch(uint32_t instruction, SchedulerT &scheduler) { - constexpr auto partial = static_cast(i << 20); + constexpr auto partial = uint32_t(i << 20); + const auto condition = Condition(instruction >> 28); // Cf. the ARM2 datasheet, p.45. Tests below match its ordering // other than that 'undefined' is the fallthrough case. More specific @@ -165,6 +223,7 @@ struct OperationMapper { constexpr auto operation = Operation(int(Operation::AND) + ((partial >> 21) & 0xf)); constexpr auto flags = DataProcessingFlags(i); scheduler.template data_processing( + condition, DataProcessing(instruction) ); } @@ -179,6 +238,7 @@ struct OperationMapper { constexpr bool is_mla = partial & (1 << 21); constexpr auto flags = MultiplyFlags(i); scheduler.template multiply( + condition, Multiply(instruction) ); } @@ -189,9 +249,61 @@ struct OperationMapper { constexpr bool is_ldr = partial & (1 << 20); constexpr auto flags = SingleDataTransferFlags(i); scheduler.template single_data_transfer( + condition, SingleDataTransfer(instruction) ); } + + // Block data transfer (LDM, STM); cf. p.29. + if constexpr (((partial >> 25) & 0b111) == 0b100) { + constexpr bool is_ldm = partial & (1 << 20); + constexpr auto flags = BlockDataTransferFlags(i); + scheduler.template block_data_transfer( + condition, + BlockDataTransfer(instruction) + ); + } + + // 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 branch( + condition, + (instruction & 0xf'ffff) << 2 + ); + } + + // Software interreupt; cf. p.35. + if constexpr (((partial >> 24) & 0b1111) == 0b1111) { + scheduler.software_interrupt(condition); + } + + + // Both: + // Coprocessor data operation; cf. p. 37; and + // Coprocessor register transfers; cf. p. 42. + if constexpr (((partial >> 24) & 0b1111) == 0b1110) { + const auto parameters = CoprocessorOperationOrRegisterTransfer(instruction); + + // TODO: parameters should probably vary. + + if(instruction & (1 << 4)) { + // Register transfer. + constexpr auto flags = CoprocessorRegisterTransferFlags(i); + constexpr bool is_mrc = partial & (1 << 20); + scheduler.template coprocessor_register_transfer( + condition, + parameters + ); + } else { + // Data operation. + constexpr auto flags = CoprocessorDataOperationFlags(i); + scheduler.template coprocessor_data_operation( + condition, + parameters + ); + } + } } }; @@ -202,40 +314,11 @@ template void dispatch(uint32_t instruction, SchedulerT &s } /* - - - - // Block data transfer (LDM, STM); cf. p.29. - if(((opcode >> 25) & 0b111) == 0b100) { - result[c] = - ((opcode >> 20) & 1) ? Operation::LDM : Operation::STM; - continue; - } - - // Branch and branch with link (B, BL); cf. p.15. - if(((opcode >> 25) & 0b111) == 0b101) { - result[c] = - ((opcode >> 24) & 1) ? Operation::BL : Operation::B; - continue; - } - if(((opcode >> 25) & 0b111) == 0b110) { result[c] = Operation::CoprocessorDataTransfer; continue; } - if(((opcode >> 24) & 0b1111) == 0b1110) { - result[c] = Operation::CoprocessorDataOperationOrRegisterTransfer; - continue; - } - - if(((opcode >> 24) & 0b1111) == 0b1111) { - result[c] = Operation::SoftwareInterrupt; - continue; - } - - result[c] = Operation::Undefined; - */ } diff --git a/InstructionSets/ARM/Instruction.hpp b/InstructionSets/ARM/Instruction.hpp deleted file mode 100644 index 5bcefa5a0..000000000 --- a/InstructionSets/ARM/Instruction.hpp +++ /dev/null @@ -1,40 +0,0 @@ -// -// Instruction.hpp -// Clock Signal -// -// Created by Thomas Harte on 16/02/2024. -// Copyright © 2024 Thomas Harte. All rights reserved. -// - -#pragma once - -#include "Decoder.hpp" -#include "Model.hpp" -#include "Operation.hpp" - -namespace InstructionSet::ARM { - -/* - - // - // LDR and STR. - // - struct SingleDataTransfer { - constexpr SingleDataTransfer(uint32_t opcode) noexcept : opcode_(opcode) {} - - /// The destination register index. i.e. 'Rd' for LDR. - int destination() const { return (opcode_ >> 12) & 0xf; } - - /// The destination register index. i.e. 'Rd' for STR. - int source() const { return (opcode_ >> 12) & 0xf; } - - /// The base register index. i.e. 'Rn'. - int base() const { return (opcode_ >> 16) & 0xf; } - - /// - int offset() const { return opcode_ & 0xfff; } - - // TODO: P, U, B, W, L, I. -*/ - -} diff --git a/InstructionSets/ARM/Operation.hpp b/InstructionSets/ARM/Operation.hpp index e9adcf2a2..218881845 100644 --- a/InstructionSets/ARM/Operation.hpp +++ b/InstructionSets/ARM/Operation.hpp @@ -49,9 +49,10 @@ enum class Operation { LDR, STR, LDM, STM, - SoftwareInterrupt, + SWI, - CoprocessorDataOperationOrRegisterTransfer, + CDP, + MRC, MCR, CoprocessorDataTransfer, Undefined, diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index eeabd41c1..752aab031 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -1333,7 +1333,6 @@ 4B1EC714255398B000A1F44B /* Sound.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Sound.cpp; sourceTree = ""; }; 4B1EC715255398B000A1F44B /* Sound.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Sound.hpp; sourceTree = ""; }; 4B1EDB431E39A0AC009D6819 /* chip.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = chip.png; sourceTree = ""; }; - 4B20053E2B804A4F00420C5C /* Instruction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Instruction.hpp; sourceTree = ""; }; 4B2005402B804AA300420C5C /* Decoder.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Decoder.hpp; sourceTree = ""; }; 4B2005422B804D6400420C5C /* ARMDecoderTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ARMDecoderTests.mm; sourceTree = ""; }; 4B2005442B804DC900420C5C /* Model.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Model.hpp; sourceTree = ""; }; @@ -2762,7 +2761,6 @@ isa = PBXGroup; children = ( 4B2005402B804AA300420C5C /* Decoder.hpp */, - 4B20053E2B804A4F00420C5C /* Instruction.hpp */, 4B2005442B804DC900420C5C /* Model.hpp */, 4B2005452B804DF600420C5C /* Operation.hpp */, );