aboutsummaryrefslogtreecommitdiff
path: root/riscv/processor.cc
diff options
context:
space:
mode:
Diffstat (limited to 'riscv/processor.cc')
-rw-r--r--riscv/processor.cc56
1 files changed, 53 insertions, 3 deletions
diff --git a/riscv/processor.cc b/riscv/processor.cc
index eea2ce2..cb2188b 100644
--- a/riscv/processor.cc
+++ b/riscv/processor.cc
@@ -12,6 +12,7 @@
processor_t::processor_t(sim_t* _sim, char* _mem, size_t _memsz)
: sim(_sim), mmu(_mem,_memsz)
{
+ initialize_dispatch_table();
// a few assumptions about endianness, including freg_t union
static_assert(BYTE_ORDER == LITTLE_ENDIAN);
static_assert(sizeof(freg_t) == 8);
@@ -172,12 +173,10 @@ void processor_t::step(size_t n, bool noisy)
{
take_interrupt();
- #include "dispatch.h"
-
#define execute_insn(noisy) \
do { insn_t insn = mmu.load_insn(pc, sr & SR_EC); \
if(noisy) disasm(insn,pc); \
- pc = dispatch_table[dispatch_index(insn)](this, insn, pc); \
+ pc = dispatch_table[insn.bits % DISPATCH_TABLE_SIZE](this, insn, pc); \
XPR[0] = 0; } while(0)
if(noisy) for( ; i < n; i++)
@@ -267,3 +266,54 @@ void processor_t::disasm(insn_t insn, reg_t pc)
#endif
printf("\n");
}
+
+// if the lower log2(DISPATCH_TABLE_SIZE) bits of an instruction
+// uniquely identify that instruction, the dispatch table points
+// directly to that insn_func. otherwise, we search the short
+// list of instructions that match.
+
+insn_func_t processor_t::dispatch_table[DISPATCH_TABLE_SIZE];
+
+struct insn_chain_t
+{
+ insn_func_t func;
+ uint32_t opcode;
+ uint32_t mask;
+};
+static std::vector<insn_chain_t> dispatch_chain[DISPATCH_TABLE_SIZE];
+
+reg_t processor_t::dispatch(insn_t insn, reg_t pc)
+{
+ size_t idx = insn.bits % DISPATCH_TABLE_SIZE;
+ for(size_t i = 0; i < dispatch_chain[idx].size(); i++)
+ {
+ insn_chain_t& c = dispatch_chain[idx][i];
+ if((insn.bits & c.mask) == c.opcode)
+ return c.func(this, insn, pc);
+ }
+ throw trap_illegal_instruction;
+}
+
+void processor_t::initialize_dispatch_table()
+{
+ if(dispatch_table[0] != NULL)
+ return;
+
+ for(size_t i = 0; i < DISPATCH_TABLE_SIZE; i++)
+ {
+ #define DECLARE_INSN(name, opcode, mask) \
+ if((i & (mask)) == ((opcode) & (mask) & (DISPATCH_TABLE_SIZE-1))) \
+ dispatch_chain[i].push_back( \
+ (insn_chain_t){&processor_t::insn_func_ ## name, opcode, mask});
+ #include "opcodes.h"
+ #undef DECLARE_INSN
+ }
+
+ for(size_t i = 0; i < DISPATCH_TABLE_SIZE; i++)
+ {
+ if(dispatch_chain[i].size() == 1)
+ dispatch_table[i] = dispatch_chain[i][0].func;
+ else
+ dispatch_table[i] = &processor_t::dispatch;
+ }
+}