[sim, opcodes] made sim more decoupled from opcodes
[riscv-isa-sim.git] / riscv / processor.cc
index 0bab83ac643dac0e635a5a86249bcc8ba5ab2da2..cb2188b1c694a3614ce94e1056fc0cff240b3ce3 100644 (file)
@@ -8,43 +8,11 @@
 #include "config.h"
 #include "sim.h"
 #include "icsim.h"
-#include "softfloat.h"
-#include "platform.h" // softfloat isNaNF32UI, etc.
-#include "internals.h" // ditto
 
 processor_t::processor_t(sim_t* _sim, char* _mem, size_t _memsz)
   : sim(_sim), mmu(_mem,_memsz)
 {
-  memset(XPR,0,sizeof(XPR));
-  memset(FPR,0,sizeof(FPR));
-  pc = 0;
-  evec = 0;
-  epc = 0;
-  badvaddr = 0;
-  cause = 0;
-  pcr_k0 = 0;
-  pcr_k1 = 0;
-  tohost = 0;
-  fromhost = 0;
-  count = 0;
-  compare = 0;
-  set_sr(SR_S | SR_SX);  // SX ignored if 64b mode not supported
-  set_fsr(0);
-
-  memset(counters,0,sizeof(counters));
-
-  // vector stuff
-  vecbanks = 0xff;
-  vecbanks_count = 8;
-  utidx = -1;
-  vlmax = 32;
-  vl = 0;
-  nxfpr_bank = 256;
-  nxpr_use = 32;
-  nfpr_use = 32;
-  for (int i=0; i<MAX_UTS; i++)
-    uts[i] = NULL;
-
+  initialize_dispatch_table();
   // a few assumptions about endianness, including freg_t union
   static_assert(BYTE_ORDER == LITTLE_ENDIAN);
   static_assert(sizeof(freg_t) == 8);
@@ -57,6 +25,8 @@ processor_t::processor_t(sim_t* _sim, char* _mem, size_t _memsz)
   dcsim = NULL;
   itlbsim = NULL;
   dtlbsim = NULL;
+
+  reset();
 }
 
 processor_t::~processor_t()
@@ -106,6 +76,41 @@ void processor_t::init(uint32_t _id, icsim_t* default_icache,
   #endif
 }
 
+void processor_t::reset()
+{
+  run = false;
+
+  memset(XPR,0,sizeof(XPR));
+  memset(FPR,0,sizeof(FPR));
+
+  pc = 0;
+  evec = 0;
+  epc = 0;
+  badvaddr = 0;
+  cause = 0;
+  pcr_k0 = 0;
+  pcr_k1 = 0;
+  tohost = 0;
+  fromhost = 0;
+  count = 0;
+  compare = 0;
+  cycle = 0;
+  set_sr(SR_S | SR_SX);  // SX ignored if 64b mode not supported
+  set_fsr(0);
+
+  // vector stuff
+  vecbanks = 0xff;
+  vecbanks_count = 8;
+  utidx = -1;
+  vlmax = 32;
+  vl = 0;
+  nxfpr_bank = 256;
+  nxpr_use = 32;
+  nfpr_use = 32;
+  for (int i=0; i<MAX_UTS; i++)
+    uts[i] = NULL;
+}
+
 void processor_t::set_sr(uint32_t val)
 {
   sr = val & ~SR_ZERO;
@@ -149,34 +154,47 @@ void processor_t::setvl(int vlapp)
   vl = std::min(vlmax, vlapp);
 }
 
+void processor_t::take_interrupt()
+{
+  uint32_t interrupts = (cause & CAUSE_IP) >> CAUSE_IP_SHIFT;
+  interrupts &= (sr & SR_IM) >> SR_IM_SHIFT;
+
+  if(interrupts && (sr & SR_ET))
+    throw trap_interrupt;
+}
+
 void processor_t::step(size_t n, bool noisy)
 {
+  if(!run)
+    return;
+
   size_t i = 0;
   while(1) try
   {
-    for( ; i < n; i++)
-    {
-      uint32_t interrupts = (cause & CAUSE_IP) >> CAUSE_IP_SHIFT;
-      interrupts &= (sr & SR_IM) >> SR_IM_SHIFT;
-      if(interrupts && (sr & SR_ET))
-        take_trap(trap_interrupt,noisy);
-
-      insn_t insn = mmu.load_insn(pc, sr & SR_EC);
-  
-      reg_t npc = pc + insn_length(insn);
-
-      if(noisy)
-        disasm(insn,pc);
+    take_interrupt();
 
-      #include "execute.h"
-  
-      pc = npc;
-      XPR[0] = 0;
+    #define execute_insn(noisy) \
+      do { insn_t insn = mmu.load_insn(pc, sr & SR_EC); \
+      if(noisy) disasm(insn,pc); \
+      pc = dispatch_table[insn.bits % DISPATCH_TABLE_SIZE](this, insn, pc); \
+      XPR[0] = 0; } while(0)
 
-      if(count++ == compare)
-        cause |= 1 << (TIMER_IRQ+CAUSE_IP_SHIFT);
+    if(noisy) for( ; i < n; i++)
+      execute_insn(true);
+    else 
+    {
+      for( ; n > 3 && i < n-3; i+=4)
+      {
+        execute_insn(false);
+        execute_insn(false);
+        execute_insn(false);
+        execute_insn(false);
+      }
+      for( ; i < n; i++)
+        execute_insn(false);
     }
-    return;
+
+    break;
   }
   catch(trap_t t)
   {
@@ -185,9 +203,23 @@ void processor_t::step(size_t n, bool noisy)
   }
   catch(vt_command_t cmd)
   {
+    i++;
     if (cmd == vt_command_stop)
-      return;
+      break;
   }
+  catch(halt_t t)
+  {
+    reset();
+    return;
+  }
+
+  cycle += i;
+
+  typeof(count) old_count = count;
+  typeof(count) max_count = -1;
+  count += i;
+  if(old_count < compare && (count >= compare || old_count > max_count-i))
+    cause |= 1 << (TIMER_IRQ+CAUSE_IP_SHIFT);
 }
 
 void processor_t::take_trap(trap_t t, bool noisy)
@@ -206,6 +238,12 @@ void processor_t::take_trap(trap_t t, bool noisy)
   badvaddr = mmu.get_badvaddr();
 }
 
+void processor_t::deliver_ipi()
+{
+  cause |= 1 << (IPI_IRQ+CAUSE_IP_SHIFT);
+  run = true;
+}
+
 void processor_t::disasm(insn_t insn, reg_t pc)
 {
   printf("core %3d: 0x%016llx (0x%08x) ",id,(unsigned long long)pc,insn.bits);
@@ -222,9 +260,60 @@ void processor_t::disasm(insn_t insn, reg_t pc)
   info.buffer_vma = pc;
 
   int ret = print_insn_little_mips(pc, &info);
-  demand(ret == (INSN_IS_RVC(insn.bits) ? 2 : 4), "disasm bug!");
+  demand(ret == insn_length(insn.bits), "disasm bug!");
   #else
   printf("unknown");
   #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;
+  }
+}