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)}}
};
};
|