Implement Hauser misa.C misalignment proposal (#187)
[riscv-isa-sim.git] / riscv / processor.h
index ab3af22930ab64e321d78d3e83a995f62a250be8..3e67215b46df9e29493b050c2d59e5cd586507cf 100644 (file)
@@ -5,14 +5,16 @@
 #include "decode.h"
 #include "config.h"
 #include "devices.h"
+#include "trap.h"
 #include <string>
 #include <vector>
 #include <map>
+#include "debug_rom_defines.h"
 
 class processor_t;
 class mmu_t;
 typedef reg_t (*insn_func_t)(processor_t*, insn_t, reg_t);
-class sim_t;
+class simif_t;
 class trap_t;
 class extension_t;
 class disassembler_t;
@@ -28,7 +30,7 @@ struct insn_desc_t
 struct commit_log_reg_t
 {
   reg_t addr;
-  reg_t data;
+  freg_t data;
 };
 
 typedef struct
@@ -45,7 +47,6 @@ typedef struct
 
 typedef enum
 {
-  ACTION_NONE = MCONTROL_ACTION_NONE,
   ACTION_DEBUG_EXCEPTION = MCONTROL_ACTION_DEBUG_EXCEPTION,
   ACTION_DEBUG_MODE = MCONTROL_ACTION_DEBUG_MODE,
   ACTION_TRACE_START = MCONTROL_ACTION_TRACE_START,
@@ -66,8 +67,10 @@ typedef enum
 typedef struct
 {
   uint8_t type;
+  bool dmode;
   uint8_t maskmax;
   bool select;
+  bool timing;
   mcontrol_action_t action;
   bool chain;
   mcontrol_match_t match;
@@ -83,7 +86,7 @@ typedef struct
 // architectural state of a RISC-V hart
 struct state_t
 {
-  void reset();
+  void reset(reg_t max_isa);
 
   static const int num_triggers = 4;
 
@@ -93,9 +96,10 @@ struct state_t
 
   // control and status registers
   reg_t prv;    // TODO: Can this be an enum instead?
+  reg_t misa;
   reg_t mstatus;
   reg_t mepc;
-  reg_t mbadaddr;
+  reg_t mtval;
   reg_t mscratch;
   reg_t mtvec;
   reg_t mcause;
@@ -104,20 +108,20 @@ struct state_t
   reg_t mip;
   reg_t medeleg;
   reg_t mideleg;
-  reg_t mucounteren;
-  reg_t mscounteren;
+  uint32_t mcounteren;
+  uint32_t scounteren;
   reg_t sepc;
-  reg_t sbadaddr;
+  reg_t stval;
   reg_t sscratch;
   reg_t stvec;
-  reg_t sptbr;
+  reg_t satp;
   reg_t scause;
   reg_t dpc;
   reg_t dscratch;
   dcsr_t dcsr;
   reg_t tselect;
   mcontrol_t mcontrol[num_triggers];
-  reg_t tdata1[num_triggers];
+  reg_t tdata2[num_triggers];
 
   uint32_t fflags;
   uint32_t frm;
@@ -136,6 +140,8 @@ struct state_t
 #ifdef RISCV_ENABLE_COMMITLOG
   commit_log_reg_t log_reg_write;
   reg_t last_inst_priv;
+  int last_inst_xlen;
+  int last_inst_flen;
 #endif
 };
 
@@ -158,7 +164,7 @@ static int cto(reg_t val)
 class processor_t : public abstract_device_t
 {
 public:
-  processor_t(const char* isa, sim_t* sim, uint32_t id, bool halt_on_reset=false);
+  processor_t(const char* isa, simif_t* sim, uint32_t id, bool halt_on_reset=false);
   ~processor_t();
 
   void set_debug(bool value);
@@ -166,15 +172,30 @@ public:
   void reset();
   void step(size_t n); // run for n cycles
   void set_csr(int which, reg_t val);
-  void raise_interrupt(reg_t which);
   reg_t get_csr(int which);
   mmu_t* get_mmu() { return mmu; }
   state_t* get_state() { return &state; }
+  unsigned get_xlen() { return xlen; }
+  unsigned get_max_xlen() { return max_xlen; }
+  std::string get_isa_string() { return isa_string; }
+  unsigned get_flen() {
+    return supports_extension('Q') ? 128 :
+           supports_extension('D') ? 64 :
+           supports_extension('F') ? 32 : 0;
+  }
   extension_t* get_extension() { return ext; }
   bool supports_extension(unsigned char ext) {
     if (ext >= 'a' && ext <= 'z') ext += 'A' - 'a';
-    return ext >= 'A' && ext <= 'Z' && ((isa >> (ext - 'A')) & 1);
+    return ext >= 'A' && ext <= 'Z' && ((state.misa >> (ext - 'A')) & 1);
+  }
+  reg_t pc_alignment_mask() {
+    return ~(reg_t)(supports_extension('C') ? 0 : 2);
+  }
+  void check_pc_alignment(reg_t pc) {
+    if (unlikely(pc & ~pc_alignment_mask()))
+      throw trap_instruction_address_misaligned(pc);
   }
+  reg_t legalize_privilege(reg_t);
   void set_privilege(reg_t);
   void yield_load_reservation() { state.load_reservation = (reg_t)-1; }
   void update_histogram(reg_t pc);
@@ -189,7 +210,10 @@ public:
 
   // When true, display disassembly of each instruction that's executed.
   bool debug;
-  void update_slow_path();
+  // When true, take the slow simulation path.
+  bool slow_path();
+  bool halted() { return state.dcsr.cause ? true : false; }
+  bool halt_request;
 
   // Return the index of a trigger that matched, or -1.
   inline int trigger_match(trigger_operation_t operation, reg_t address, reg_t data)
@@ -197,18 +221,21 @@ public:
     if (state.dcsr.cause)
       return -1;
 
-    bool chain_ok = false;
+    bool chain_ok = true;
 
     for (unsigned int i = 0; i < state.num_triggers; i++) {
-      if (state.mcontrol[i].action == ACTION_NONE ||
-          (operation == OPERATION_EXECUTE && !state.mcontrol[i].execute) ||
+      if (!chain_ok) {
+        chain_ok |= !state.mcontrol[i].chain;
+        continue;
+      }
+
+      if ((operation == OPERATION_EXECUTE && !state.mcontrol[i].execute) ||
           (operation == OPERATION_STORE && !state.mcontrol[i].store) ||
           (operation == OPERATION_LOAD && !state.mcontrol[i].load) ||
           (state.prv == PRV_M && !state.mcontrol[i].m) ||
-          (state.prv == PRV_H && !state.mcontrol[i].h) ||
           (state.prv == PRV_S && !state.mcontrol[i].s) ||
           (state.prv == PRV_U && !state.mcontrol[i].u)) {
-        goto next;
+        continue;
       }
 
       reg_t value;
@@ -226,55 +253,44 @@ public:
 
       switch (state.mcontrol[i].match) {
         case MATCH_EQUAL:
-          if (value != state.tdata1[i])
-            goto next;
+          if (value != state.tdata2[i])
+            continue;
           break;
         case MATCH_NAPOT:
           {
-            reg_t mask = ~((1 << cto(state.tdata1[i])) - 1);
-            if ((value & mask) != (state.tdata1[i] & mask))
-              goto next;
+            reg_t mask = ~((1 << cto(state.tdata2[i])) - 1);
+            if ((value & mask) != (state.tdata2[i] & mask))
+              continue;
           }
           break;
         case MATCH_GE:
-          if (value < state.tdata1[i])
-            goto next;
+          if (value < state.tdata2[i])
+            continue;
           break;
         case MATCH_LT:
-          if (value >= state.tdata1[i])
-            goto next;
+          if (value >= state.tdata2[i])
+            continue;
           break;
         case MATCH_MASK_LOW:
           {
-            reg_t mask = state.tdata1[i] >> (xlen/2);
-            if ((value & mask) != (state.tdata1[i] & mask))
-              goto next;
+            reg_t mask = state.tdata2[i] >> (xlen/2);
+            if ((value & mask) != (state.tdata2[i] & mask))
+              continue;
           }
           break;
         case MATCH_MASK_HIGH:
           {
-            reg_t mask = state.tdata1[i] >> (xlen/2);
-            if (((value >> (xlen/2)) & mask) != (state.tdata1[i] & mask))
-              goto next;
+            reg_t mask = state.tdata2[i] >> (xlen/2);
+            if (((value >> (xlen/2)) & mask) != (state.tdata2[i] & mask))
+              continue;
           }
           break;
       }
 
-      if (state.mcontrol[i].chain && !chain_ok) {
-        goto next;
-      }
-
-      // We got here, so this trigger matches. But if the next trigger has
-      // chain set, then we can't perform the action.
-      if (i+1 < state.num_triggers && state.mcontrol[i+1].chain) {
-        chain_ok = true;
-        continue;
-      } else {
+      if (!state.mcontrol[i].chain) {
         return i;
       }
-
-next:
-      chain_ok = false;
+      chain_ok = true;
     }
     return -1;
   }
@@ -282,7 +298,7 @@ next:
   void trigger_updated();
 
 private:
-  sim_t* sim;
+  simif_t* sim;
   mmu_t* mmu; // main memory is always accessed via the mmu
   extension_t* ext;
   disassembler_t* disassembler;
@@ -290,12 +306,10 @@ private:
   uint32_t id;
   unsigned max_xlen;
   unsigned xlen;
-  reg_t isa;
+  reg_t max_isa;
   std::string isa_string;
   bool histogram_enabled;
   bool halt_on_reset;
-  // When true, take the slow simulation path.
-  bool slow_path;
 
   std::vector<insn_desc_t> instructions;
   std::map<reg_t,uint64_t> pc_histogram;
@@ -303,23 +317,25 @@ private:
   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_pending_interrupt() { take_interrupt(state.mip & state.mie); }
+  void take_interrupt(reg_t mask); // take first enabled interrupt in mask
   void take_trap(trap_t& t, reg_t epc); // take an exception
   void disasm(insn_t insn); // disassemble and print an instruction
   int paddr_bits();
 
   void enter_debug_mode(uint8_t cause);
 
-  friend class sim_t;
   friend class mmu_t;
-  friend class rtc_t;
+  friend class clint_t;
   friend class extension_t;
 
   void parse_isa_string(const char* isa);
   void build_opcode_map();
   void register_base_instructions();
   insn_func_t decode_insn(insn_t insn);
+
+  // Track repeated executions for processor_t::disasm()
+  uint64_t last_pc, last_bits, executions;
 };
 
 reg_t illegal_instruction(processor_t* p, insn_t insn, reg_t pc);