Improve instruction fetch
authorAndrew Waterman <waterman@cs.berkeley.edu>
Tue, 8 Sep 2015 22:09:23 +0000 (15:09 -0700)
committerAndrew Waterman <waterman@cs.berkeley.edu>
Wed, 9 Sep 2015 00:00:02 +0000 (17:00 -0700)
- Performance for variable-length instructions is much better
- Refill is simpler and faster
- Support for instructions with overlapping opcodes (e.g. C.ADD + C.JALR)

15 files changed:
riscv/decode.h
riscv/encoding.h
riscv/execute.cc [new file with mode: 0644]
riscv/insns/c_add.h
riscv/insns/c_addi16sp.h [new file with mode: 0644]
riscv/insns/c_addiw.h
riscv/insns/c_ebreak.h [new file with mode: 0644]
riscv/insns/c_jalr.h [new file with mode: 0644]
riscv/insns/c_jr.h [new file with mode: 0644]
riscv/insns/c_lui.h
riscv/insns/c_mv.h
riscv/mmu.h
riscv/processor.cc
riscv/processor.h
riscv/riscv.mk.in

index 16e57d72353a1c7657491c4e887acff5e1e29b19..8462da2c2a4cdac430991b244022f5bbb4ec593f 100644 (file)
@@ -53,6 +53,8 @@ const int NFPR = 32;
    ((x) & 0x1f) < 0x1f ? 4 : \
    ((x) & 0x3f) < 0x3f ? 6 : \
    8)
+#define MAX_INSN_LENGTH 8
+#define PC_ALIGN 2
 
 typedef uint64_t insn_bits_t;
 class insn_t
index 039ffdfcb82e5ec0e5180f65c6ccc3069328b549..16a7792d7baaa788505074dc895d4f62eb574dcd 100644 (file)
 #define MASK_C_ADD  0xf003
 #define MATCH_C_ADDI 0xc002
 #define MASK_C_ADDI  0xe003
+#define MATCH_C_ADDI16SP 0xa002
+#define MASK_C_ADDI16SP  0xef83
 #define MATCH_C_ADDI4SPN 0x8000
 #define MASK_C_ADDI4SPN  0xe003
 #define MATCH_C_ADDIW 0xe002
 #define MASK_C_BEQZ  0xe003
 #define MATCH_C_BNEZ 0x6002
 #define MASK_C_BNEZ  0xe003
+#define MATCH_C_EBREAK 0x1000
+#define MASK_C_EBREAK  0xffff
 #define MATCH_C_FLD 0xa000
 #define MASK_C_FLD  0xe003
 #define MATCH_C_FLDSP 0xa001
 #define MASK_C_J  0xe003
 #define MATCH_C_JAL 0x2002
 #define MASK_C_JAL  0xe003
+#define MATCH_C_JALR 0x1000
+#define MASK_C_JALR  0xf07f
+#define MATCH_C_JR 0x0
+#define MASK_C_JR  0xf07f
+#define MATCH_C_LD 0xe000
+#define MASK_C_LD  0xe003
+#define MATCH_C_LDSP 0xe001
+#define MASK_C_LDSP  0xe003
 #define MATCH_C_LI 0x8002
 #define MASK_C_LI  0xe003
 #define MATCH_C_LUI 0xa002
 #define MASK_C_LWSP  0xe003
 #define MATCH_C_MV 0x0
 #define MASK_C_MV  0xf003
+#define MATCH_C_NOP 0xc002
+#define MASK_C_NOP  0xffff
+#define MATCH_C_SD 0x6000
+#define MASK_C_SD  0xe003
+#define MATCH_C_SDSP 0x6001
+#define MASK_C_SDSP  0xe003
 #define MATCH_C_SLLI 0x1
 #define MASK_C_SLLI  0xe003
 #define MATCH_C_SW 0x4000
@@ -646,11 +664,13 @@ DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU)
 DECLARE_INSN(bne, MATCH_BNE, MASK_BNE)
 DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD)
 DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI)
+DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP)
 DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN)
 DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW)
 DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW)
 DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ)
 DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ)
+DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK)
 DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD)
 DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP)
 DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW)
@@ -661,11 +681,18 @@ DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW)
 DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP)
 DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J)
 DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL)
+DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR)
+DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR)
+DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD)
+DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP)
 DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI)
 DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI)
 DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW)
 DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP)
 DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV)
+DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP)
+DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD)
+DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP)
 DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI)
 DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW)
 DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP)
diff --git a/riscv/execute.cc b/riscv/execute.cc
new file mode 100644 (file)
index 0000000..bb7ed34
--- /dev/null
@@ -0,0 +1,117 @@
+// See LICENSE for license details.
+
+#include "processor.h"
+#include "mmu.h"
+#include <cassert>
+
+static void commit_log(state_t* state, reg_t pc, insn_t insn)
+{
+#ifdef RISCV_ENABLE_COMMITLOG
+  if (get_field(state->mstatus, MSTATUS_IE)) {
+    uint64_t mask = (insn.length() == 8 ? uint64_t(0) : (uint64_t(1) << (insn.length() * 8))) - 1;
+    if (state->log_reg_write.addr) {
+      fprintf(stderr, "0x%016" PRIx64 " (0x%08" PRIx64 ") %c%2" PRIu64 " 0x%016" PRIx64 "\n",
+              pc,
+              insn.bits() & mask,
+              state->log_reg_write.addr & 1 ? 'f' : 'x',
+              state->log_reg_write.addr >> 1,
+              state->log_reg_write.data);
+    } else {
+      fprintf(stderr, "0x%016" PRIx64 " (0x%08" PRIx64 ")\n", pc, insn.bits() & mask);
+    }
+  }
+  state->log_reg_write.addr = 0;
+#endif
+}
+
+inline void processor_t::update_histogram(size_t pc)
+{
+#ifdef RISCV_ENABLE_HISTOGRAM
+  size_t idx = pc >> 2;
+  pc_histogram[idx]++;
+#endif
+}
+
+static reg_t execute_insn(processor_t* p, reg_t pc, insn_fetch_t fetch)
+{
+  reg_t npc = fetch.func(p, fetch.insn, pc);
+  if (npc != PC_SERIALIZE) {
+    commit_log(p->get_state(), pc, fetch.insn);
+    p->update_histogram(pc);
+  }
+  return npc;
+}
+
+// fetch/decode/execute loop
+void processor_t::step(size_t n)
+{
+  while (run && n > 0) {
+    size_t instret = 0;
+    reg_t pc = state.pc;
+    mmu_t* _mmu = mmu;
+
+    #define advance_pc() \
+     if (unlikely(pc == PC_SERIALIZE)) { \
+       pc = state.pc; \
+       state.serialized = true; \
+       break; \
+     } else { \
+       state.pc = pc; \
+       instret++; \
+     }
+
+    try
+    {
+      check_timer();
+      take_interrupt();
+
+      if (unlikely(debug))
+      {
+        while (instret < n)
+        {
+          insn_fetch_t fetch = mmu->load_insn(pc);
+          if (!state.serialized)
+            disasm(fetch.insn);
+          pc = execute_insn(this, pc, fetch);
+          advance_pc();
+        }
+      }
+      else while (instret < n)
+      {
+        size_t idx = _mmu->icache_index(pc);
+        auto ic_entry = _mmu->access_icache(pc);
+
+        #define ICACHE_ACCESS(i) { \
+          insn_fetch_t fetch = ic_entry->data; \
+          ic_entry++; \
+          pc = execute_insn(this, pc, fetch); \
+          if (i == mmu_t::ICACHE_ENTRIES-1) break; \
+          if (unlikely(ic_entry->tag != pc)) goto miss; \
+          if (unlikely(instret+1 == n)) break; \
+          instret++; \
+          state.pc = pc; \
+        }
+
+        switch (idx) {
+          #include "icache.h"
+        }
+
+        advance_pc();
+        continue;
+
+miss:
+        advance_pc();
+        // refill I$ if it looks like there wasn't a taken branch
+        if (pc > (ic_entry-1)->tag && pc <= (ic_entry-1)->tag + MAX_INSN_LENGTH)
+          _mmu->refill_icache(pc, ic_entry);
+      }
+    }
+    catch(trap_t& t)
+    {
+      take_trap(t, pc);
+    }
+
+    state.minstret += instret;
+    n -= instret;
+  }
+}
index c13385ec4dec0bf471daaeb64f6bdb15b07bfcbf..ab7d4d4c8e643f252c80f6df73077d34a46f0d66 100644 (file)
@@ -1,12 +1,3 @@
 require_extension('C');
-if (insn.rvc_rs2() == 0) {
-  if (insn.rvc_rs1() == 0) { // c.ebreak
-    throw trap_breakpoint();
-  } else { // c.jalr
-    reg_t tmp = npc;
-    set_pc(RVC_RS1 & ~reg_t(1));
-    WRITE_REG(X_RA, tmp);
-  }
-} else {
-  WRITE_RD(sext_xlen(RVC_RS1 + RVC_RS2));
-}
+require(insn.rvc_rs2() != 0);
+WRITE_RD(sext_xlen(RVC_RS1 + RVC_RS2));
diff --git a/riscv/insns/c_addi16sp.h b/riscv/insns/c_addi16sp.h
new file mode 100644 (file)
index 0000000..3bc88a4
--- /dev/null
@@ -0,0 +1,3 @@
+require_extension('C');
+require(insn.rvc_addi16sp_imm() != 0);
+WRITE_REG(X_SP, sext_xlen(RVC_SP + insn.rvc_addi16sp_imm()));
index fe87872b42251964fec846cdf52f46ae9c627edf..05d349713fed39ddd5c4b2356944d8b92f7624e5 100644 (file)
@@ -1,2 +1,3 @@
 require_extension('C');
+require_rv64;
 WRITE_RD(sext32(RVC_RS1 + insn.rvc_imm()));
diff --git a/riscv/insns/c_ebreak.h b/riscv/insns/c_ebreak.h
new file mode 100644 (file)
index 0000000..a17200f
--- /dev/null
@@ -0,0 +1,2 @@
+require_extension('C');
+throw trap_breakpoint();
diff --git a/riscv/insns/c_jalr.h b/riscv/insns/c_jalr.h
new file mode 100644 (file)
index 0000000..cb1e422
--- /dev/null
@@ -0,0 +1,5 @@
+require_extension('C');
+require(insn.rvc_rs1() != 0);
+reg_t tmp = npc;
+set_pc(RVC_RS1 & ~reg_t(1));
+WRITE_REG(X_RA, tmp);
diff --git a/riscv/insns/c_jr.h b/riscv/insns/c_jr.h
new file mode 100644 (file)
index 0000000..9c4a8ea
--- /dev/null
@@ -0,0 +1,3 @@
+require_extension('C');
+require(insn.rvc_rs1() != 0);
+set_pc(RVC_RS1 & ~reg_t(1));
index cb76c61a52020b03e572b9c3fec9ffc9d94542f3..e5060a37892ab6fbb184de2819d25d9b48fb2a98 100644 (file)
@@ -1,6 +1,3 @@
 require_extension('C');
-if (insn.rvc_rd() == 0) { // c.addi16sp
-  WRITE_REG(X_SP, sext_xlen(RVC_SP + insn.rvc_addi16sp_imm()));
-} else {
-  WRITE_RD(insn.rvc_imm() << 12);
-}
+require(insn.rvc_rd() != 0);
+WRITE_RD(insn.rvc_imm() << 12);
index 4a23063741c03e119a49916713102d27249dd387..a03d0d0763f26a62f3503c4552af308d1671598b 100644 (file)
@@ -1,7 +1,3 @@
 require_extension('C');
-if (insn.rvc_rs2() == 0) {
-  require(insn.rvc_rd() != 0);
-  set_pc(RVC_RS1 & ~reg_t(1));
-} else {
-  WRITE_RD(RVC_RS2);
-}
+require(insn.rvc_rs2() != 0);
+WRITE_RD(RVC_RS2);
index ddb1d51e1fa8b4d23ff40e2a96aa2102c89aa16f..ce8685dcf278d0ae37e6295537ffba1b7b14becb 100644 (file)
@@ -72,18 +72,11 @@ public:
 
   inline size_t icache_index(reg_t addr)
   {
-    // for instruction sizes != 4, this hash still works but is suboptimal
-    return (addr / 4) % ICACHE_ENTRIES;
+    return (addr / PC_ALIGN) % ICACHE_ENTRIES;
   }
 
-  // load instruction from memory at aligned address.
-  icache_entry_t* access_icache(reg_t addr) __attribute__((always_inline))
+  inline icache_entry_t* refill_icache(reg_t addr, icache_entry_t* entry)
   {
-    reg_t idx = icache_index(addr);
-    icache_entry_t* entry = &icache[idx];
-    if (likely(entry->tag == addr))
-      return entry;
-
     char* iaddr = (char*)translate(addr, 1, false, true);
     insn_bits_t insn = *(uint16_t*)iaddr;
     int length = insn_length(insn);
@@ -106,16 +99,23 @@ public:
     }
 
     insn_fetch_t fetch = {proc->decode_insn(insn), insn};
-    icache[idx].tag = addr;
-    icache[idx].data = fetch;
+    entry->tag = addr;
+    entry->data = fetch;
 
     reg_t paddr = iaddr - mem;
-    if (!tracer.empty() && tracer.interested_in_range(paddr, paddr + 1, false, true))
-    {
-      icache[idx].tag = -1;
+    if (tracer.interested_in_range(paddr, paddr + 1, false, true)) {
+      entry->tag = -1;
       tracer.trace(paddr, length, false, true);
     }
-    return &icache[idx];
+    return entry;
+  }
+
+  inline icache_entry_t* access_icache(reg_t addr)
+  {
+    icache_entry_t* entry = &icache[icache_index(addr)];
+    if (likely(entry->tag == addr))
+      return entry;
+    return refill_icache(addr, entry);
   }
 
   inline insn_fetch_t load_insn(reg_t addr)
index 5b533910ac0c368e3555b0551a04c18ba653639a..d1e7ce3f97d5a69337006c75bae317701d8ed166 100644 (file)
@@ -30,10 +30,7 @@ processor_t::processor_t(const char* isa, sim_t* sim, uint32_t id)
 
   reset(true);
 
-  #define DECLARE_INSN(name, match, mask) REGISTER_INSN(this, name, match, mask)
-  #include "encoding.h"
-  #undef DECLARE_INSN
-  build_opcode_map();
+  register_base_instructions();
 }
 
 processor_t::~processor_t()
@@ -173,121 +170,12 @@ void processor_t::take_interrupt()
   }
 }
 
-static void commit_log(state_t* state, reg_t pc, insn_t insn)
-{
-#ifdef RISCV_ENABLE_COMMITLOG
-  if (get_field(state->mstatus, MSTATUS_IE)) {
-    uint64_t mask = (insn.length() == 8 ? uint64_t(0) : (uint64_t(1) << (insn.length() * 8))) - 1;
-    if (state->log_reg_write.addr) {
-      fprintf(stderr, "0x%016" PRIx64 " (0x%08" PRIx64 ") %c%2" PRIu64 " 0x%016" PRIx64 "\n",
-              pc,
-              insn.bits() & mask,
-              state->log_reg_write.addr & 1 ? 'f' : 'x',
-              state->log_reg_write.addr >> 1,
-              state->log_reg_write.data);
-    } else {
-      fprintf(stderr, "0x%016" PRIx64 " (0x%08" PRIx64 ")\n", pc, insn.bits() & mask);
-    }
-  }
-  state->log_reg_write.addr = 0;
-#endif
-}
-
-inline void processor_t::update_histogram(size_t pc)
-{
-#ifdef RISCV_ENABLE_HISTOGRAM
-  size_t idx = pc >> 2;
-  pc_histogram[idx]++;
-#endif
-}
-
-static reg_t execute_insn(processor_t* p, reg_t pc, insn_fetch_t fetch)
-{
-  reg_t npc = fetch.func(p, fetch.insn, pc);
-  if (npc != PC_SERIALIZE) {
-    commit_log(p->get_state(), pc, fetch.insn);
-    p->update_histogram(pc);
-  }
-  return npc;
-}
-
 void processor_t::check_timer()
 {
   if (sim->rtc >= state.mtimecmp)
     state.mip |= MIP_MTIP;
 }
 
-void processor_t::step(size_t n)
-{
-  size_t instret = 0;
-  reg_t pc = state.pc;
-  mmu_t* _mmu = mmu;
-
-  if (unlikely(!run || !n))
-    return;
-
-  #define maybe_serialize() \
-   if (unlikely(pc == PC_SERIALIZE)) { \
-     pc = state.pc; \
-     state.serialized = true; \
-     break; \
-   }
-
-  try
-  {
-    check_timer();
-    take_interrupt();
-
-    if (unlikely(debug))
-    {
-      while (instret < n)
-      {
-        insn_fetch_t fetch = mmu->load_insn(pc);
-        if (!state.serialized)
-          disasm(fetch.insn);
-        pc = execute_insn(this, pc, fetch);
-        maybe_serialize();
-        instret++;
-        state.pc = pc;
-      }
-    }
-    else while (instret < n)
-    {
-      size_t idx = _mmu->icache_index(pc);
-      auto ic_entry = _mmu->access_icache(pc);
-
-      #define ICACHE_ACCESS(idx) { \
-        insn_fetch_t fetch = ic_entry->data; \
-        ic_entry++; \
-        pc = execute_insn(this, pc, fetch); \
-        if (idx == mmu_t::ICACHE_ENTRIES-1) break; \
-        if (unlikely(ic_entry->tag != pc)) break; \
-        if (unlikely(instret+1 == n)) break; \
-        instret++; \
-        state.pc = pc; \
-      }
-
-      switch (idx) {
-        #include "icache.h"
-      }
-
-      maybe_serialize();
-      instret++;
-      state.pc = pc;
-    }
-  }
-  catch(trap_t& t)
-  {
-    take_trap(t, pc);
-  }
-
-  state.minstret += instret;
-
-  // tail-recurse if we didn't execute as many instructions as we'd hoped
-  if (instret < n)
-    step(n - instret);
-}
-
 void processor_t::push_privilege_stack()
 {
   reg_t s = state.mstatus;
@@ -463,7 +351,7 @@ void processor_t::set_csr(int which, reg_t val)
       break;
     }
     case CSR_SEPC: state.sepc = val; break;
-    case CSR_STVEC: state.stvec = val & ~3; break;
+    case CSR_STVEC: state.stvec = val >> 2 << 2; break;
     case CSR_SPTBR: state.sptbr = zext_xlen(val & -PGSIZE); break;
     case CSR_SSCRATCH: state.sscratch = val; break;
     case CSR_MEPC: state.mepc = val; break;
@@ -602,55 +490,51 @@ reg_t illegal_instruction(processor_t* p, insn_t insn, reg_t pc)
 
 insn_func_t processor_t::decode_insn(insn_t insn)
 {
-  size_t mask = opcode_map.size()-1;
-  insn_desc_t* desc = opcode_map[insn.bits() & mask]; 
+  // 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;
+      }
+    }
 
-  while ((insn.bits() & desc->mask) != desc->match)
-    desc++;
+    opcode_cache[idx] = desc;
+    opcode_cache[idx].match = insn.bits();
+  }
 
-  return xlen == 64 ? desc->rv64 : desc->rv32;
+  return xlen == 64 ? desc.rv64 : desc.rv32;
 }
 
 void processor_t::register_insn(insn_desc_t desc)
 {
-  assert(desc.mask & 1);
   instructions.push_back(desc);
 }
 
 void processor_t::build_opcode_map()
 {
-  size_t buckets = -1;
-  for (auto& inst : instructions)
-    while ((inst.mask & buckets) != buckets)
-      buckets /= 2;
-  buckets++;
-
   struct cmp {
-    decltype(insn_desc_t::match) mask;
-    cmp(decltype(mask) mask) : mask(mask) {}
     bool operator()(const insn_desc_t& lhs, const insn_desc_t& rhs) {
-      if ((lhs.match & mask) != (rhs.match & mask))
-        return (lhs.match & mask) < (rhs.match & mask);
-      return lhs.match < rhs.match;
+      if (lhs.match == rhs.match)
+        return lhs.mask > rhs.mask;
+      return lhs.match > rhs.match;
     }
   };
-  std::sort(instructions.begin(), instructions.end(), cmp(buckets-1));
-
-  opcode_map.resize(buckets);
-  opcode_store.resize(instructions.size() + 1);
+  std::sort(instructions.begin(), instructions.end(), cmp());
 
-  size_t j = 0;
-  for (size_t b = 0, i = 0; b < buckets; b++)
-  {
-    opcode_map[b] = &opcode_store[j];
-    while (i < instructions.size() && b == (instructions[i].match & (buckets-1)))
-      opcode_store[j++] = instructions[i++];
-  }
-
-  assert(j == opcode_store.size()-1);
-  opcode_store[j].match = opcode_store[j].mask = 0;
-  opcode_store[j].rv32 = &illegal_instruction;
-  opcode_store[j].rv64 = &illegal_instruction;
+  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)
@@ -665,3 +549,23 @@ void processor_t::register_extension(extension_t* x)
   ext = x;
   x->set_processor(this);
 }
+
+void processor_t::register_base_instructions()
+{
+  std::map<std::string, std::pair<insn_bits_t, insn_bits_t>> opcodes;
+
+  #define DECLARE_INSN(name, match, mask) \
+    opcodes[#name] = std::make_pair(match, mask);
+  #include "encoding.h"
+  #undef DECLARE_INSN
+
+  #define DEFINE_INSN(name) \
+    if (!opcodes.count(#name)) \
+      throw std::logic_error("opcode for " #name " not found"); \
+    REGISTER_INSN(this, name, opcodes[#name].first, opcodes[#name].second)
+  #include "insn_list.h"
+  #undef DEFINE_INSN
+
+  register_insn({0, 0, &illegal_instruction, &illegal_instruction});
+  build_opcode_map();
+}
index 6af78877f785785bc009aa9d6269ccf86e3a0c62..d117ff1acbcc1d8988b68e412b373739efdbf6c4 100644 (file)
@@ -18,8 +18,8 @@ class disassembler_t;
 
 struct insn_desc_t
 {
-  uint32_t match;
-  uint32_t mask;
+  insn_bits_t match;
+  insn_bits_t mask;
   insn_func_t rv32;
   insn_func_t rv64;
 };
@@ -115,10 +115,11 @@ private:
   bool histogram_enabled;
 
   std::vector<insn_desc_t> instructions;
-  std::vector<insn_desc_t*> opcode_map;
-  std::vector<insn_desc_t> opcode_store;
   std::map<size_t,size_t> pc_histogram;
 
+  static const size_t OPCODE_CACHE_SIZE = 8191;
+  insn_desc_t opcode_cache[OPCODE_CACHE_SIZE];
+
   void check_timer();
   void take_interrupt(); // take a trap if any interrupts are pending
   void take_trap(trap_t& t, reg_t epc); // take an exception
@@ -130,6 +131,7 @@ private:
 
   void parse_isa_string(const char* isa);
   void build_opcode_map();
+  void register_base_instructions();
   insn_func_t decode_insn(insn_t insn);
 };
 
index 7ce2cb94385ca3b7a4461f28c1a79176a9185932..f35f200c18ae41ccee84cbea6b6199645d86464b 100644 (file)
@@ -29,6 +29,7 @@ riscv_precompiled_hdrs = \
 riscv_srcs = \
        htif.cc \
        processor.cc \
+       execute.cc \
        sim.cc \
        interactive.cc \
        trap.cc \
@@ -45,9 +46,203 @@ riscv_test_srcs =
 
 riscv_gen_hdrs = \
        icache.h \
+       insn_list.h \
+
+riscv_insn_list = \
+       add \
+       addi \
+       addiw \
+       addw \
+       amoadd_d \
+       amoadd_w \
+       amoand_d \
+       amoand_w \
+       amomax_d \
+       amomaxu_d \
+       amomaxu_w \
+       amomax_w \
+       amomin_d \
+       amominu_d \
+       amominu_w \
+       amomin_w \
+       amoor_d \
+       amoor_w \
+       amoswap_d \
+       amoswap_w \
+       amoxor_d \
+       amoxor_w \
+       and \
+       andi \
+       auipc \
+       beq \
+       bge \
+       bgeu \
+       blt \
+       bltu \
+       bne \
+       c_add \
+       c_addi16sp \
+       c_addi4spn \
+       c_addi \
+       c_addiw \
+       c_addw \
+       c_beqz \
+       c_bnez \
+       c_ebreak \
+       c_fld \
+       c_fldsp \
+       c_flw \
+       c_flwsp \
+       c_fsd \
+       c_fsdsp \
+       c_fsw \
+       c_fswsp \
+       c_jal \
+       c_jalr \
+       c_j \
+       c_jr \
+       c_li \
+       c_lui \
+       c_lw \
+       c_lwsp \
+       c_mv \
+       c_slli \
+       csrrc \
+       csrrci \
+       csrrs \
+       csrrsi \
+       csrrw \
+       csrrwi \
+       c_sw \
+       c_swsp \
+       div \
+       divu \
+       divuw \
+       divw \
+       fadd_d \
+       fadd_s \
+       fclass_d \
+       fclass_s \
+       fcvt_d_l \
+       fcvt_d_lu \
+       fcvt_d_s \
+       fcvt_d_w \
+       fcvt_d_wu \
+       fcvt_l_d \
+       fcvt_l_s \
+       fcvt_lu_d \
+       fcvt_lu_s \
+       fcvt_s_d \
+       fcvt_s_l \
+       fcvt_s_lu \
+       fcvt_s_w \
+       fcvt_s_wu \
+       fcvt_w_d \
+       fcvt_w_s \
+       fcvt_wu_d \
+       fcvt_wu_s \
+       fdiv_d \
+       fdiv_s \
+       fence \
+       fence_i \
+       feq_d \
+       feq_s \
+       fld \
+       fle_d \
+       fle_s \
+       flt_d \
+       flt_s \
+       flw \
+       fmadd_d \
+       fmadd_s \
+       fmax_d \
+       fmax_s \
+       fmin_d \
+       fmin_s \
+       fmsub_d \
+       fmsub_s \
+       fmul_d \
+       fmul_s \
+       fmv_d_x \
+       fmv_s_x \
+       fmv_x_d \
+       fmv_x_s \
+       fnmadd_d \
+       fnmadd_s \
+       fnmsub_d \
+       fnmsub_s \
+       fsd \
+       fsgnj_d \
+       fsgnjn_d \
+       fsgnjn_s \
+       fsgnj_s \
+       fsgnjx_d \
+       fsgnjx_s \
+       fsqrt_d \
+       fsqrt_s \
+       fsub_d \
+       fsub_s \
+       fsw \
+       hrts \
+       jal \
+       jalr \
+       lb \
+       lbu \
+       ld \
+       lh \
+       lhu \
+       lr_d \
+       lr_w \
+       lui \
+       lw \
+       lwu \
+       mrth \
+       mrts \
+       mul \
+       mulh \
+       mulhsu \
+       mulhu \
+       mulw \
+       or \
+       ori \
+       rem \
+       remu \
+       remuw \
+       remw \
+       sb \
+       sbreak \
+       scall \
+       sc_d \
+       sc_w \
+       sd \
+       sfence_vm \
+       sh \
+       sll \
+       slli \
+       slliw \
+       sllw \
+       slt \
+       slti \
+       sltiu \
+       sltu \
+       sra \
+       srai \
+       sraiw \
+       sraw \
+       sret \
+       srl \
+       srli \
+       srliw \
+       srlw \
+       sub \
+       subw \
+       sw \
+       wfi \
+       xor \
+       xori \
 
 riscv_gen_srcs = \
-       $(addsuffix .cc, $(call get_insn_list,$(src_dir)/riscv/encoding.h))
+       $(addsuffix .cc,$(riscv_insn_list))
 
 icache_entries := `grep "ICACHE_ENTRIES =" $(src_dir)/riscv/mmu.h | sed 's/.* = \(.*\);/\1/'`
 
@@ -55,6 +250,10 @@ icache.h: mmu.h
        $(src_dir)/riscv/gen_icache $(icache_entries) > $@.tmp
        mv $@.tmp $@
 
+insn_list.h: $(src_dir)/riscv/riscv.mk.in
+       echo $(riscv_insn_list) | sed 's/\s\+\|$$/\n/g' | sed '/^$$/d' | sed 's/\./_/g' | sed 's/\(.*\)/DEFINE_INSN(\1)/' > $@.tmp
+       mv $@.tmp $@
+
 $(riscv_gen_srcs): %.cc: insns/%.h insn_template.cc
        sed 's/NAME/$(subst .cc,,$@)/' $(src_dir)/riscv/insn_template.cc | sed 's/OPCODE/$(call get_opcode,$(src_dir)/riscv/encoding.h,$(subst .cc,,$@))/' > $@