#pragma once #include #include #include #include using namespace std::string_literals; using code_sequence = std::vector; template code_sequence to_code_sequence(from_t v); template<> code_sequence to_code_sequence(uint16_t v) { return code_sequence{static_cast(v & 0xFF), static_cast(v >> 8)}; } template<> code_sequence to_code_sequence(uint32_t v) { return code_sequence{static_cast(v & 0xFF), static_cast(v >> 8), static_cast(v >> 16),static_cast(v >> 24) }; } uint32_t high_bits(uint8_t number) { return ~((static_cast(1) << (32 - number)) - 1); } // Identify operator with leading bits class Pattern { public: Pattern(uint32_t bits, uint32_t mask): _bits{bits}, _mask{mask} {} template T encode() { return static_cast(_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>; // 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& arguments) { if (_size == 2) { // 16 bit thumb insn uint16_t result{ _pattern.encode()}; return to_code_sequence(result); } else if (_size == 4) { // 32 bit thumb insn uint32_t result{ _pattern.encode()}; 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 imm(uint8_t pos, uint8_t size){ return std::make_shared(pos, size); }; std::shared_ptr reg(uint8_t pos) { return std::make_shared(pos); }; std::vector 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)}} }; };