From bd0a15c054ede4d58b9394ad3f951c8cfe3a5094 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 16 Feb 2024 21:35:49 -0500 Subject: [PATCH] Start working on ARM2 decoding. --- InstructionSets/ARM/Decoder.hpp | 77 +++++++++++++++++++ InstructionSets/ARM/Instruction.hpp | 31 ++++++++ InstructionSets/ARM/Model.hpp | 17 ++++ InstructionSets/ARM/Operation.hpp | 39 ++++++++++ InstructionSets/PowerPC/Instruction.hpp | 6 +- .../Clock Signal.xcodeproj/project.pbxproj | 20 +++++ 6 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 InstructionSets/ARM/Decoder.hpp create mode 100644 InstructionSets/ARM/Instruction.hpp create mode 100644 InstructionSets/ARM/Model.hpp create mode 100644 InstructionSets/ARM/Operation.hpp diff --git a/InstructionSets/ARM/Decoder.hpp b/InstructionSets/ARM/Decoder.hpp new file mode 100644 index 000000000..f68be950f --- /dev/null +++ b/InstructionSets/ARM/Decoder.hpp @@ -0,0 +1,77 @@ +// +// Decoder.hpp +// Clock Signal +// +// Created by Thomas Harte on 16/02/2024. +// Copyright © 2024 Thomas Harte. All rights reserved. +// + +#pragma once + +#include "Model.hpp" +#include "Operation.hpp" + +#include + +namespace InstructionSet::ARM { + +template +constexpr std::array operation_table() { + std::array result{}; + for(int c = 0; c < 256; c++) { + const uint32_t opcode = c << 20; + + if(((opcode >> 26) & 0b11) == 0b00) { + result[c] = Operation((c >> 21) & 0xf); + continue; + } + + if(((opcode >> 25) & 0b111) == 0b101) { + result[c] = + ((opcode >> 24) & 1) ? Operation::BranchWithLink : Operation::Branch; + continue; + } + + if(((opcode >> 22) & 0b111'111) == 0b000'000) { + result[c] = + ((opcode >> 21) & 1) ? Operation::MultiplyWithAccumulate : Operation::Multiply; + continue; + } + + if(((opcode >> 26) & 0b11) == 0b01) { + result[c] = Operation::SingleDataTransfer; + continue; + } + + if(((opcode >> 25) & 0b111) == 0b100) { + result[c] = Operation::BlockDataTransfer; + continue; + } + + if(((opcode >> 24) & 0b1111) == 0b1111) { + result[c] = Operation::SoftwareInterrupt; + continue; + } + + if(((opcode >> 24) & 0b1111) == 0b1110) { + result[c] = Operation::CoprocessorDataOperationOrRegisterTransfer; + continue; + } + + if(((opcode >> 25) & 0b111) == 0b110) { + result[c] = Operation::CoprocessorDataTransfer; + continue; + } + + result[c] = Operation::Undefined; + } + return result; +} + +template +constexpr Operation operation(uint32_t opcode) { + constexpr std::array operations = operation_table(); + return operations[(opcode >> 20) & 0xff]; +} + +} diff --git a/InstructionSets/ARM/Instruction.hpp b/InstructionSets/ARM/Instruction.hpp new file mode 100644 index 000000000..300e00a50 --- /dev/null +++ b/InstructionSets/ARM/Instruction.hpp @@ -0,0 +1,31 @@ +// +// 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 { + +template +class Instruction { + public: + constexpr Instruction(uint32_t opcode) noexcept : opcode_(opcode) {} + + Condition condition() const { return Condition(opcode_ >> 28); } + Operation operation() const { + return InstructionSet::ARM::operation(opcode_); + } + + private: + uint32_t opcode_; +}; + +} diff --git a/InstructionSets/ARM/Model.hpp b/InstructionSets/ARM/Model.hpp new file mode 100644 index 000000000..ce6104137 --- /dev/null +++ b/InstructionSets/ARM/Model.hpp @@ -0,0 +1,17 @@ +// +// Model.hpp +// Clock Signal +// +// Created by Thomas Harte on 16/02/2024. +// Copyright © 2024 Thomas Harte. All rights reserved. +// + +#pragma once + +namespace InstructionSet::ARM { + +enum class Model { + ARM2, +}; + +} diff --git a/InstructionSets/ARM/Operation.hpp b/InstructionSets/ARM/Operation.hpp new file mode 100644 index 000000000..978441f68 --- /dev/null +++ b/InstructionSets/ARM/Operation.hpp @@ -0,0 +1,39 @@ +// +// Operation.hpp +// Clock Signal +// +// Created by Thomas Harte on 16/02/2024. +// Copyright © 2024 Thomas Harte. All rights reserved. +// + +#pragma once + +namespace InstructionSet::ARM { + +enum class Operation { + AND, EOR, SUB, RSB, + ADD, ADC, SBC, RSC, + TST, TEQ, CMP, CMN, + ORR, MOV, BIC, MVN, + + Branch, BranchWithLink, + Multiply, MultiplyWithAccumulate, + + SingleDataTransfer, + BlockDataTransfer, + SoftwareInterrupt, + + CoprocessorDataOperationOrRegisterTransfer, + CoprocessorDataTransfer, + + Undefined, +}; + +enum class Condition { + EQ, NE, CS, CC, + MI, PL, VS, VC, + HI, LS, GE, LT, + GT, LE, AL, NV, +}; + +} diff --git a/InstructionSets/PowerPC/Instruction.hpp b/InstructionSets/PowerPC/Instruction.hpp index 7116d3a0b..73895e4e1 100644 --- a/InstructionSets/PowerPC/Instruction.hpp +++ b/InstructionSets/PowerPC/Instruction.hpp @@ -1362,9 +1362,9 @@ struct Instruction { bool is_supervisor = false; uint32_t opcode = 0; - Instruction() noexcept {} - Instruction(uint32_t opcode) noexcept : opcode(opcode) {} - Instruction(Operation operation, uint32_t opcode, bool is_supervisor = false) noexcept : operation(operation), is_supervisor(is_supervisor), opcode(opcode) {} + constexpr Instruction() noexcept = default; + constexpr Instruction(uint32_t opcode) noexcept : opcode(opcode) {} + constexpr Instruction(Operation operation, uint32_t opcode, bool is_supervisor = false) noexcept : operation(operation), is_supervisor(is_supervisor), opcode(opcode) {} // Instruction fields are decoded below; naming is a compromise between // Motorola's documentation and IBM's. diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 069031998..eeabd41c1 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -213,6 +213,7 @@ 4B1EC716255398B000A1F44B /* Sound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1EC714255398B000A1F44B /* Sound.cpp */; }; 4B1EC717255398B000A1F44B /* Sound.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B1EC714255398B000A1F44B /* Sound.cpp */; }; 4B1EDB451E39A0AC009D6819 /* chip.png in Resources */ = {isa = PBXBuildFile; fileRef = 4B1EDB431E39A0AC009D6819 /* chip.png */; }; + 4B2005432B804D6400420C5C /* ARMDecoderTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B2005422B804D6400420C5C /* ARMDecoderTests.mm */; }; 4B2130E2273A7A0A008A77B4 /* Audio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2130E0273A7A0A008A77B4 /* Audio.cpp */; }; 4B2130E3273A7A0A008A77B4 /* Audio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2130E0273A7A0A008A77B4 /* Audio.cpp */; }; 4B228CD524D773B40077EF25 /* CSScanTarget.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B228CD424D773B30077EF25 /* CSScanTarget.mm */; }; @@ -1332,6 +1333,11 @@ 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 = ""; }; + 4B2005452B804DF600420C5C /* Operation.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Operation.hpp; sourceTree = ""; }; 4B2130E0273A7A0A008A77B4 /* Audio.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Audio.cpp; sourceTree = ""; }; 4B2130E1273A7A0A008A77B4 /* Audio.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Audio.hpp; sourceTree = ""; }; 4B228CD424D773B30077EF25 /* CSScanTarget.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CSScanTarget.mm; sourceTree = ""; }; @@ -2752,6 +2758,17 @@ path = Icons; sourceTree = ""; }; + 4B20053D2B804A4F00420C5C /* ARM */ = { + isa = PBXGroup; + children = ( + 4B2005402B804AA300420C5C /* Decoder.hpp */, + 4B20053E2B804A4F00420C5C /* Instruction.hpp */, + 4B2005442B804DC900420C5C /* Model.hpp */, + 4B2005452B804DF600420C5C /* Operation.hpp */, + ); + path = ARM; + sourceTree = ""; + }; 4B228CD324D773B30077EF25 /* ScanTarget */ = { isa = PBXGroup; children = ( @@ -4471,6 +4488,7 @@ 4B9D0C4E22C7E0CF00DE1AD3 /* 68000RollShiftTests.mm */, 4BD388872239E198002D14B5 /* 68000Tests.mm */, 4BF7019F26FFD32300996424 /* AmigaBlitterTests.mm */, + 4B2005422B804D6400420C5C /* ARMDecoderTests.mm */, 4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */, 4BE34437238389E10058E78F /* AtariSTVideoTests.mm */, 4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */, @@ -5082,6 +5100,7 @@ 4BE8EB5425C0E9D40040BC40 /* Disassembler.hpp */, 4BEDA3B625B25563000C2DBD /* README.md */, 4BDA7F7F29C4C179007A10A5 /* 6809 */, + 4B20053D2B804A4F00420C5C /* ARM */, 4B79629B2819681F008130F9 /* M68k */, 4BEDA40925B2844B000C2DBD /* M50740 */, 4BEDA3B325B25563000C2DBD /* PowerPC */, @@ -6334,6 +6353,7 @@ 4B778F2823A5EEF80000D260 /* Cartridge.cpp in Sources */, 4B7752B528217ED30073E2C5 /* SNA.cpp in Sources */, 4BEDA3C025B25563000C2DBD /* Decoder.cpp in Sources */, + 4B2005432B804D6400420C5C /* ARMDecoderTests.mm in Sources */, 4B778F4C23A5F2090000D260 /* StaticAnalyser.cpp in Sources */, 4B778F2623A5EE350000D260 /* Acorn.cpp in Sources */, 4B7752C128217F490073E2C5 /* FAT.cpp in Sources */,