summaryrefslogtreecommitdiffhomepage
path: root/asm/arm/instruction.h
blob: 224cc6e37c685703fd15396b7ac33a4f29cdf65e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
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)}}
 };
};