Use single, shared real-time counter
authorAndrew Waterman <waterman@cs.berkeley.edu>
Mon, 1 Jun 2015 01:28:53 +0000 (18:28 -0700)
committerAndrew Waterman <waterman@cs.berkeley.edu>
Mon, 1 Jun 2015 01:29:45 +0000 (18:29 -0700)
This required disentangling INSTRET/CYCLE from TIME.

riscv/processor.cc
riscv/processor.h
riscv/sim.cc
riscv/sim.h

index 6368c8f18cc5ad3f3423894927c06043626cb6af..cf6790a86f9eabbaa1ac92b3336aded873ccfc98 100644 (file)
@@ -202,18 +202,13 @@ static reg_t execute_insn(processor_t* p, reg_t pc, insn_fetch_t fetch)
   return npc;
 }
 
-static void update_timer(state_t* state, size_t instret)
+void processor_t::check_timer()
 {
-  uint64_t count0 = (uint64_t)(uint32_t)state->mtime;
-  state->mtime += instret;
-  uint64_t before = count0 - state->stimecmp;
-  if (int64_t(before ^ (before + instret)) < 0)
-    state->mip |= MIP_STIP;
-}
-
-static size_t next_timer(state_t* state)
-{
-  return state->stimecmp - (uint32_t)state->mtime;
+  // this assumes the rtc doesn't change asynchronously during step(),
+  if (state.stimecmp >= (uint32_t)state.prev_rtc
+      && state.stimecmp < (uint32_t)sim->rtc)
+    state.mip |= MIP_STIP;
+  state.prev_rtc = sim->rtc;
 }
 
 void processor_t::step(size_t n)
@@ -224,7 +219,6 @@ void processor_t::step(size_t n)
 
   if (unlikely(!run || !n))
     return;
-  n = std::min(n, next_timer(&state) | 1U);
 
   #define maybe_serialize() \
    if (unlikely(pc == PC_SERIALIZE)) { \
@@ -235,6 +229,7 @@ void processor_t::step(size_t n)
 
   try
   {
+    check_timer();
     take_interrupt();
 
     if (unlikely(debug))
@@ -280,7 +275,7 @@ void processor_t::step(size_t n)
     take_trap(t, pc);
   }
 
-  update_timer(&state, instret);
+  state.minstret += instret;
 
   // tail-recurse if we didn't execute as many instructions as we'd hoped
   if (instret < n)
@@ -371,29 +366,35 @@ void processor_t::set_csr(int which, reg_t val)
       break;
     case CSR_MTIME:
     case CSR_STIMEW:
-      state.mtime = val;
+      // this implementation ignores writes to MTIME
       break;
     case CSR_MTIMEH:
     case CSR_STIMEHW:
+      // this implementation ignores writes to MTIME
+      break;
+    case CSR_TIMEW:
+      val -= sim->rtc;
       if (xlen == 32)
-        state.mtime = (uint32_t)val | (state.mtime >> 32 << 32);
+        state.sutime_delta = (uint32_t)val | (state.sutime_delta >> 32 << 32);
       else
-        state.mtime = val;
+        state.sutime_delta = val;
+      break;
+    case CSR_TIMEHW:
+      val = ((val << 32) - sim->rtc) >> 32;
+      state.sutime_delta = (val << 32) | (uint32_t)state.sutime_delta;
       break;
     case CSR_CYCLEW:
-    case CSR_TIMEW:
     case CSR_INSTRETW:
-      val -= state.mtime;
+      val -= state.minstret;
       if (xlen == 32)
-        state.sutime_delta = (uint32_t)val | (state.sutime_delta >> 32 << 32);
+        state.suinstret_delta = (uint32_t)val | (state.suinstret_delta >> 32 << 32);
       else
-        state.sutime_delta = val;
+        state.suinstret_delta = val;
       break;
     case CSR_CYCLEHW:
-    case CSR_TIMEHW:
     case CSR_INSTRETHW:
-      val -= state.mtime;
-      state.sutime_delta = (val << 32) | (uint32_t)state.sutime_delta;
+      val = ((val << 32) - state.minstret) >> 32;
+      state.suinstret_delta = (val << 32) | (uint32_t)state.suinstret_delta;
       break;
     case CSR_MSTATUS: {
       if ((val ^ state.mstatus) & (MSTATUS_VM | MSTATUS_PRV | MSTATUS_PRV1 | MSTATUS_MPRV))
@@ -496,29 +497,33 @@ reg_t processor_t::get_csr(int which)
         break;
       return (state.fflags << FSR_AEXC_SHIFT) | (state.frm << FSR_RD_SHIFT);
     case CSR_MTIME:
+    case CSR_STIME:
     case CSR_STIMEW:
-      return state.mtime;
+      return sim->rtc;
     case CSR_MTIMEH:
+    case CSR_STIMEH:
     case CSR_STIMEHW:
-      return state.mtime >> 32;
-    case CSR_CYCLE:
+      return sim->rtc >> 32;
     case CSR_TIME:
-    case CSR_INSTRET:
-    case CSR_STIME:
-    case CSR_CYCLEW:
     case CSR_TIMEW:
+      return sim->rtc + state.sutime_delta;
+    case CSR_CYCLE:
+    case CSR_CYCLEW:
+    case CSR_INSTRET:
     case CSR_INSTRETW:
-      return state.mtime + state.sutime_delta;
-    case CSR_CYCLEH:
+      return state.minstret + state.suinstret_delta;
     case CSR_TIMEH:
+    case CSR_TIMEHW:
+      if (xlen == 64)
+        break;
+      return (sim->rtc + state.sutime_delta) >> 32;
+    case CSR_CYCLEH:
     case CSR_INSTRETH:
-    case CSR_STIMEH:
     case CSR_CYCLEHW:
-    case CSR_TIMEHW:
     case CSR_INSTRETHW:
       if (xlen == 64)
         break;
-      return (state.mtime + state.sutime_delta) >> 32;
+      return (state.minstret + state.suinstret_delta) >> 32;
     case CSR_SSTATUS: {
       reg_t ss = 0;
       ss = set_field(ss, SSTATUS_IE, get_field(state.mstatus, MSTATUS_IE));
index 1d497d0c8ef5f5678d2bc90e7f5405d3eee0075b..134c0a1696648a923a5bdce4c90d124bee79b554 100644 (file)
@@ -45,7 +45,7 @@ struct state_t
   reg_t mbadaddr;
   reg_t mscratch;
   reg_t mcause;
-  reg_t mtime;
+  reg_t minstret;
   reg_t mie;
   reg_t mip;
   reg_t sepc;
@@ -55,12 +55,14 @@ struct state_t
   reg_t sptbr;
   reg_t scause;
   reg_t sutime_delta;
+  reg_t suinstret_delta;
   reg_t tohost;
   reg_t fromhost;
-  bool serialized; // whether timer CSRs are in a well-defined state
+  reg_t prev_rtc;
   uint32_t stimecmp;
   uint32_t fflags;
   uint32_t frm;
+  bool serialized; // whether timer CSRs are in a well-defined state
 
   reg_t load_reservation;
 
@@ -118,6 +120,7 @@ private:
   std::vector<insn_desc_t> opcode_store;
   std::map<size_t,size_t> pc_histogram;
 
+  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
   void disasm(insn_t insn); // disassemble and print an instruction
index 0fdd8297f421f03220ed75d2c4fce1b4dd0a85e5..eb31f12d3b3a288c2311987959fecc1f550132aa 100644 (file)
@@ -21,7 +21,7 @@ static void handle_signal(int sig)
 sim_t::sim_t(const char* isa, size_t nprocs, size_t mem_mb,
              const std::vector<std::string>& args)
   : htif(new htif_isasim_t(this, args)), procs(std::max(nprocs, size_t(1))),
-    current_step(0), current_proc(0), debug(false)
+    rtc(0), current_step(0), current_proc(0), debug(false)
 {
   signal(SIGINT, &handle_signal);
   // allocate target machine's memory, shrinking it as necessary
@@ -93,8 +93,10 @@ void sim_t::step(size_t n)
     {
       current_step = 0;
       procs[current_proc]->yield_load_reservation();
-      if (++current_proc == procs.size())
+      if (++current_proc == procs.size()) {
         current_proc = 0;
+        rtc += INTERLEAVE / INSNS_PER_RTC_TICK;
+      }
 
       htif->tick();
     }
index ca1ad6f544b9fb100f741f8340ad2d234574625c..6615ab007b131874c54981bed70ca21729130f9b 100644 (file)
@@ -47,6 +47,8 @@ private:
 
   void step(size_t n); // step through simulation
   static const size_t INTERLEAVE = 5000;
+  static const size_t INSNS_PER_RTC_TICK = 100; // 10 MHz clock for 1 BIPS core
+  reg_t rtc;
   size_t current_step;
   size_t current_proc;
   bool debug;