Serialize counters without throwing C++ exceptions
authorAndrew Waterman <waterman@cs.berkeley.edu>
Thu, 26 Mar 2015 07:28:10 +0000 (00:28 -0700)
committerAndrew Waterman <waterman@cs.berkeley.edu>
Fri, 27 Mar 2015 02:26:32 +0000 (19:26 -0700)
Ideally, a similar mechanism will apply to target machine exceptions.

riscv/decode.h
riscv/processor.cc
riscv/processor.h

index 4ad45490b95447074bc8082e4c37086bd8f3ee4c..72efcd9e9464ffef1d92ec4e9270c504e9f32515 100644 (file)
@@ -159,7 +159,11 @@ private:
        npc = sext_xlen(x); \
      } while(0)
 
+#define PC_SERIALIZE 3 /* sentinel value indicating simulator pipeline flush */
+
 #define validate_csr(which, write) ({ \
+  if (!STATE.serialized) return PC_SERIALIZE; \
+  STATE.serialized = false; \
   unsigned my_priv = get_field(STATE.mstatus, MSTATUS_PRV); \
   unsigned csr_priv = get_field((which), 0x300); \
   unsigned csr_read_only = get_field((which), 0xC00) == 3; \
index 0ff55789a449b2939a4ddea935420fcddfc44581..afae1ce348913b5e7f8dd0affc0ad6707ca3cc6c 100644 (file)
@@ -21,7 +21,7 @@
 
 processor_t::processor_t(sim_t* _sim, mmu_t* _mmu, uint32_t _id)
   : sim(_sim), mmu(_mmu), ext(NULL), disassembler(new disassembler_t),
-    id(_id), run(false), debug(false), serialized(false)
+    id(_id), run(false), debug(false)
 {
   reset(true);
   mmu->set_processor(this);
@@ -86,16 +86,6 @@ void processor_t::reset(bool value)
     ext->reset(); // reset the extension
 }
 
-struct serialize_t {};
-
-void processor_t::serialize()
-{
-  if (serialized)
-    serialized = false;
-  else
-    serialized = true, throw serialize_t();
-}
-
 void processor_t::raise_interrupt(reg_t which)
 {
   throw trap_t(((reg_t)1 << 63) | which);
@@ -183,17 +173,28 @@ void processor_t::step(size_t n)
     return;
   n = std::min(n, next_timer(&state) | 1U);
 
+  #define maybe_serialize() \
+   if (unlikely(pc == PC_SERIALIZE)) { \
+     pc = state.pc; \
+     state.serialized = true; \
+     continue; \
+   }
+
   try
   {
     take_interrupt();
 
     if (unlikely(debug))
     {
-      while (instret++ < n)
+      while (instret < n)
       {
         insn_fetch_t fetch = mmu->load_insn(pc);
-        disasm(fetch.insn);
-        state.pc = pc = execute_insn(this, pc, fetch);
+        if (!state.serialized)
+          disasm(fetch.insn);
+        pc = execute_insn(this, pc, fetch);
+        maybe_serialize();
+        instret++;
+        state.pc = pc;
       }
     }
     else while (instret < n)
@@ -204,22 +205,26 @@ void processor_t::step(size_t n)
       #define ICACHE_ACCESS(idx) { \
         insn_fetch_t fetch = ic_entry->data; \
         ic_entry++; \
-        state.pc = pc = execute_insn(this, pc, fetch); \
-        instret++; \
+        pc = execute_insn(this, pc, fetch); \
         if (idx == mmu_t::ICACHE_ENTRIES-1) break; \
         if (unlikely(ic_entry->tag != pc)) break; \
+        instret++; \
+        state.pc = pc; \
       }
 
       switch (idx) {
         #include "icache.h"
       }
+
+      maybe_serialize();
+      instret++;
+      state.pc = pc;
     }
   }
   catch(trap_t& t)
   {
     state.pc = take_trap(t, pc);
   }
-  catch(serialize_t& s) {}
 
   update_timer(&state, instret);
 }
@@ -388,7 +393,6 @@ void processor_t::set_csr(int which, reg_t val)
     case CSR_SEPC: state.sepc = val; break;
     case CSR_STVEC: state.stvec = val & ~3; break;
     case CSR_STIMECMP:
-      serialize();
       state.stip = false;
       state.stimecmp = val;
       break;
@@ -426,7 +430,6 @@ reg_t processor_t::get_csr(int which)
     case CSR_SCYCLE:
     case CSR_STIME:
     case CSR_SINSTRET:
-      serialize();
       return state.scount;
     case CSR_CYCLEH:
     case CSR_TIMEH:
@@ -436,7 +439,6 @@ reg_t processor_t::get_csr(int which)
     case CSR_SINSTRETH:
       if (xlen == 64)
         break;
-      serialize();
       return state.scount >> 32;
     case CSR_SSTATUS:
     {
index 4189fea8615f68271ff120b6c2b15791a79f002a..e9d9c4fd0ae6675aa2b53ce9933d5465ad4d42db 100644 (file)
@@ -55,6 +55,7 @@ struct state_t
   reg_t fromhost;
   reg_t scount;
   bool stip;
+  bool serialized; // whether timer CSRs are in a well-defined state
   uint32_t stimecmp;
   uint32_t fflags;
   uint32_t frm;
@@ -104,7 +105,6 @@ private:
   bool run; // !reset
   bool debug;
   bool histogram_enabled;
-  bool serialized;
 
   std::vector<insn_desc_t> instructions;
   std::vector<insn_desc_t*> opcode_map;
@@ -112,7 +112,6 @@ private:
   std::map<size_t,size_t> pc_histogram;
 
   void take_interrupt(); // take a trap if any interrupts are pending
-  void serialize(); // collapse into defined architectural state
   reg_t take_trap(trap_t& t, reg_t epc); // take an exception
   void disasm(insn_t insn); // disassemble and print an instruction