Support RV32 RDTIMEH/RDCYCLEH/RDINSTRETH
[riscv-isa-sim.git] / riscv / processor.cc
index ed19509496f6960411f0f1d1ee8ec330ea72db19..f47c8e50d03620f712c3e8ec922b9d1f3e147ba3 100644 (file)
@@ -32,6 +32,7 @@ processor_t::processor_t(sim_t* _sim, mmu_t* _mmu, uint32_t _id)
 
 processor_t::~processor_t()
 {
+  delete disassembler;
 }
 
 void state_t::reset()
@@ -95,6 +96,14 @@ void processor_t::take_interrupt()
         throw trap_t((1ULL << ((state.sr & SR_S64) ? 63 : 31)) + i);
 }
 
+static void commit_log(state_t* state, insn_t insn)
+{
+#ifdef RISCV_ENABLE_COMMITLOG
+  if (!(state->sr & SR_S))
+    fprintf(stderr, "\n0x%016" PRIx64 " (0x%08" PRIx32 ") ", state->pc, insn.bits());
+#endif
+}
+
 void processor_t::step(size_t n)
 {
   if(!run)
@@ -109,62 +118,40 @@ void processor_t::step(size_t n)
   {
     take_interrupt();
 
-    // execute_insn fetches and executes one instruction
-    #define execute_insn(noisy) \
-      do { \
-        insn_fetch_t fetch = mmu->load_insn(state.pc); \
-        if(noisy) disasm(fetch.insn.insn); \
-        state.pc = fetch.func(this, fetch.insn.insn, state.pc); \
-      } while(0)
-
-    
-    // special execute_insn  for commit log dumping
-#ifdef RISCV_ENABLE_COMMITLOG
-    //static disassembler disasmblr; 
-    #undef execute_insn 
-    #define execute_insn(noisy) \
-      do { \
-        insn_fetch_t fetch = _mmu->load_insn(state.pc); \
-        if(noisy) disasm(fetch.insn.insn); \
-        bool in_spvr = state.sr & SR_S; \
-        if (!in_spvr) fprintf(stderr, "\n0x%016" PRIx64 " (0x%08" PRIx32 ") ", state.pc, fetch.insn.insn.bits()); \
-        /*if (!in_spvr) fprintf(stderr, "\n0x%016" PRIx64 " (0x%08" PRIx32 ") %s  ", state.pc, fetch.insn.insn.bits(), disasmblr.disassemble(fetch.insn.insn).c_str());*/ \
-        state.pc = fetch.func(this, fetch.insn.insn, state.pc); \
-      } while(0)
-#endif
-
     if (debug) // print out instructions as we go
     {
       for (size_t i = 0; i < n; state.count++, i++)
-        execute_insn(true);
+      {
+        insn_fetch_t fetch = mmu->load_insn(state.pc);
+        disasm(fetch.insn.insn);
+        commit_log(&state, fetch.insn.insn);
+        state.pc = fetch.func(this, fetch.insn.insn, state.pc);
+      }
     }
     else while (n > 0)
     {
       size_t idx = (state.pc / sizeof(insn_t)) % ICACHE_SIZE;
-      auto ic_entry_init = &_mmu->icache[idx], ic_entry = ic_entry_init;
-
-      #define update_count() { \
-        size_t i = ic_entry - ic_entry_init; \
-        state.count += i; \
-        if (i >= n) break; \
-        n -= i; }
+      auto ic_entry = _mmu->access_icache(state.pc), ic_entry_init = ic_entry;
 
       #define ICACHE_ACCESS(idx) { \
         insn_t insn = ic_entry->data.insn.insn; \
         insn_func_t func = ic_entry->data.func; \
-        if (unlikely(ic_entry->tag != state.pc)) break; \
+        commit_log(&state, insn); \
         ic_entry++; \
-        state.pc = func(this, insn, state.pc); }
+        state.pc = func(this, insn, state.pc); \
+        if (idx < ICACHE_SIZE-1 && unlikely(ic_entry->tag != state.pc)) break; \
+      }
 
-      switch (idx) while (true)
+      switch (idx)
       {
-        ICACHE_SWITCH;
-        update_count();
-        ic_entry_init = ic_entry = &_mmu->icache[0];
+        ICACHE_SWITCH; // auto-generated into icache.h
       }
 
-      _mmu->access_icache(state.pc);
-      update_count();
+      size_t i = ic_entry - ic_entry_init;
+      state.count += i;
+      if (i >= n)
+        break;
+      n -= i;
     }
   }
   catch(trap_t& t)
@@ -246,12 +233,12 @@ reg_t processor_t::set_pcr(int which, reg_t val)
     case CSR_EVEC:
       state.evec = val & ~3;
       break;
-    case CSR_CYCLE:
-    case CSR_TIME:
-    case CSR_INSTRET:
     case CSR_COUNT:
       state.count = val;
       break;
+    case CSR_COUNTH:
+      state.count = (val << 32) | (uint32_t)state.count;
+      break;
     case CSR_COMPARE:
       set_interrupt(IRQ_TIMER, false);
       state.compare = val;
@@ -312,6 +299,13 @@ reg_t processor_t::get_pcr(int which)
     case CSR_INSTRET:
     case CSR_COUNT:
       return state.count;
+    case CSR_CYCLEH:
+    case CSR_TIMEH:
+    case CSR_INSTRETH:
+    case CSR_COUNTH:
+      if (rv64)
+        break;
+      return state.count >> 32;
     case CSR_COMPARE:
       return state.compare;
     case CSR_CAUSE:
@@ -340,9 +334,8 @@ reg_t processor_t::get_pcr(int which)
     case CSR_FROMHOST:
       sim->get_htif()->tick(); // not necessary, but faster
       return state.fromhost;
-    default:
-      throw trap_illegal_instruction();
   }
+  throw trap_illegal_instruction();
 }
 
 void processor_t::set_interrupt(int which, bool on)