+ throw trap_illegal_instruction();
+}
+
+insn_func_t processor_t::decode_insn(insn_t insn)
+{
+ // look up opcode in hash table
+ size_t idx = insn.bits() % OPCODE_CACHE_SIZE;
+ insn_desc_t desc = opcode_cache[idx];
+
+ if (unlikely(insn.bits() != desc.match)) {
+ // fall back to linear search
+ insn_desc_t* p = &instructions[0];
+ while ((insn.bits() & p->mask) != p->match)
+ p++;
+ desc = *p;
+
+ if (p->mask != 0 && p > &instructions[0]) {
+ if (p->match != (p-1)->match && p->match != (p+1)->match) {
+ // move to front of opcode list to reduce miss penalty
+ while (--p >= &instructions[0])
+ *(p+1) = *p;
+ instructions[0] = desc;
+ }
+ }
+
+ opcode_cache[idx] = desc;
+ opcode_cache[idx].match = insn.bits();
+ }
+
+ return xlen == 64 ? desc.rv64 : desc.rv32;
+}
+
+void processor_t::register_insn(insn_desc_t desc)
+{
+ instructions.push_back(desc);
+}
+
+void processor_t::build_opcode_map()
+{
+ struct cmp {
+ bool operator()(const insn_desc_t& lhs, const insn_desc_t& rhs) {
+ if (lhs.match == rhs.match)
+ return lhs.mask > rhs.mask;
+ return lhs.match > rhs.match;
+ }
+ };
+ std::sort(instructions.begin(), instructions.end(), cmp());
+
+ for (size_t i = 0; i < OPCODE_CACHE_SIZE; i++)
+ opcode_cache[i] = {1, 0, &illegal_instruction, &illegal_instruction};
+}
+
+void processor_t::register_extension(extension_t* x)
+{
+ for (auto insn : x->get_instructions())
+ register_insn(insn);
+ build_opcode_map();
+ for (auto disasm_insn : x->get_disasms())
+ disassembler->add_insn(disasm_insn);
+ if (ext != NULL)
+ throw std::logic_error("only one extension may be registered");
+ ext = x;
+ x->set_processor(this);
+}
+
+void processor_t::register_base_instructions()
+{
+ #define DECLARE_INSN(name, match, mask) \
+ insn_bits_t name##_match = (match), name##_mask = (mask);
+ #include "encoding.h"
+ #undef DECLARE_INSN
+
+ #define DEFINE_INSN(name) \
+ REGISTER_INSN(this, name, name##_match, name##_mask)
+ #include "insn_list.h"
+ #undef DEFINE_INSN
+
+ register_insn({0, 0, &illegal_instruction, &illegal_instruction});
+ build_opcode_map();
+}
+
+bool processor_t::load(reg_t addr, size_t len, uint8_t* bytes)
+{
+ return false;
+}
+
+bool processor_t::store(reg_t addr, size_t len, const uint8_t* bytes)
+{
+ switch (addr)