summaryrefslogtreecommitdiffhomepage
path: root/asm/arm/instruction.h
diff options
context:
space:
mode:
authorRoland Reichwein <mail@reichwein.it>2024-08-31 18:29:58 +0200
committerRoland Reichwein <mail@reichwein.it>2024-08-31 18:29:58 +0200
commit02153da4d5954261f6649e2980bc88f6d29e45a6 (patch)
tree4cc1ce6d1124edf791e48fcdb28b33a614d1a358 /asm/arm/instruction.h
parentf8c4fe1614cc79df9f97c8a7754cf2a5aaf5063d (diff)
ARM assembler (WIP)
Diffstat (limited to 'asm/arm/instruction.h')
-rw-r--r--asm/arm/instruction.h109
1 files changed, 109 insertions, 0 deletions
diff --git a/asm/arm/instruction.h b/asm/arm/instruction.h
new file mode 100644
index 0000000..224cc6e
--- /dev/null
+++ b/asm/arm/instruction.h
@@ -0,0 +1,109 @@
+#pragma once
+
+#include <memory>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+using namespace std::string_literals;
+
+using code_sequence = std::vector<uint8_t>;
+
+template<typename from_t>
+code_sequence to_code_sequence(from_t v);
+
+template<>
+code_sequence to_code_sequence<uint16_t>(uint16_t v) {
+ return code_sequence{static_cast<uint8_t>(v & 0xFF), static_cast<uint8_t>(v >> 8)};
+}
+
+template<>
+code_sequence to_code_sequence<uint32_t>(uint32_t v) {
+ return code_sequence{static_cast<uint8_t>(v & 0xFF), static_cast<uint8_t>(v >> 8), static_cast<uint8_t>(v >> 16),static_cast<uint8_t>(v >> 24) };
+}
+
+uint32_t high_bits(uint8_t number)
+{
+ return ~((static_cast<uint32_t>(1) << (32 - number)) - 1);
+}
+
+// Identify operator with leading bits
+class Pattern
+{
+public:
+ Pattern(uint32_t bits, uint32_t mask): _bits{bits}, _mask{mask} {}
+
+ template<typename T>
+ T encode()
+ {
+ return static_cast<T>(_bits);
+ }
+
+
+private:
+ uint32_t _bits;
+ uint32_t _mask;
+};
+
+class Operand
+{
+protected:
+ Operand(uint8_t pos): _pos(pos){}
+private:
+ uint8_t _pos;
+};
+
+class Register: public Operand
+{
+public:
+ Register(uint8_t pos): Operand{pos} {};
+};
+
+class Immediate: public Operand
+{
+public:
+ Immediate(uint8_t pos, uint8_t bits): Operand{pos}, _bits{bits} {}
+private:
+ uint8_t _bits;
+};
+
+using Operands = std::vector<std::shared_ptr<Operand>>;
+
+// Pattern [, Operand, ...]
+class Instruction
+{
+public:
+ Instruction(const std::string& mnemonic, uint8_t size, Pattern pattern, Operands operands): _mnemonic(mnemonic), _size(size), _pattern(pattern), _operands(operands) {}
+ code_sequence encode(const std::vector<std::string>& arguments)
+ {
+ if (_size == 2) { // 16 bit thumb insn
+ uint16_t result{ _pattern.encode<uint16_t>()};
+ return to_code_sequence(result);
+ } else if (_size == 4) { // 32 bit thumb insn
+ uint32_t result{ _pattern.encode<uint32_t>()};
+ return to_code_sequence(result);
+ } else {
+ throw std::runtime_error("Unsupported instruction size "s + std::to_string(_size));
+ }
+ }
+
+private:
+ std::string _mnemonic;
+ uint8_t _size;
+ Pattern _pattern;
+ Operands _operands;
+};
+
+namespace {
+ // factory functions
+ std::shared_ptr<Operand> imm(uint8_t pos, uint8_t size){ return std::make_shared<Immediate>(pos, size); };
+ std::shared_ptr<Operand> reg(uint8_t pos) { return std::make_shared<Register>(pos); };
+
+ std::vector<Instruction> insns{
+ {"adcs", 2, Pattern(0x4140, high_bits(10)), Operands{reg(0), reg(3)}},
+
+ {"lsls", 2, Pattern(0x0000, high_bits(5)), Operands{reg(0), reg(3), imm(6, 5)}}
+ };
+};
+
+