add comment
[riscv-isa-sim.git] / riscv / processor.cc
index f24784bec779b0cf8e35bff0b77251832db5073b..3b0d3956ff8b8dc3fedb8387db8661b9c642a2ca 100644 (file)
@@ -138,6 +138,21 @@ void state_t::reset(reg_t max_isa)
   tselect = 0;
   for (unsigned int i = 0; i < num_triggers; i++)
     mcontrol[i].type = 2;
+#ifdef SPIKE_SIMPLEV
+  // set SV CSR banks to default (full) sizes
+  msv.state_size = 1;
+  ssv.state_size = 1;
+  usv.state_size = 3;
+  // VL and MVL all 0
+  msv.vl = msv.mvl = 0;
+  ssv.vl = ssv.mvl = 0;
+  usv.vl = usv.mvl = 0;
+  // SUBVL all 1, including in xesvstate
+  msv.subvl = 1;
+  ssv.subvl = 1;
+  usv.subvl = 1;
+  mesvstate = sesvstate = 0;
+#endif
 }
 
 void sv_shape_t::setup_map()
@@ -153,6 +168,7 @@ void sv_shape_t::setup_map()
         case SV_SHAPE_PERM_YZX: order[0] = 1; order[1] = 2; order[2] = 0; break;
         case SV_SHAPE_PERM_ZXY: order[0] = 2; order[1] = 0; order[2] = 1; break;
         case SV_SHAPE_PERM_ZYX: order[0] = 2; order[1] = 1; order[2] = 0; break;
+        default: throw trap_illegal_instruction(0);
     }
     for (int i = 0; i < 128; i++)
     {
@@ -164,7 +180,7 @@ void sv_shape_t::setup_map()
             if (idxs[order[j]] != lims[order[j]]) {
                 break;
             }
-            idxs[order[i]] = 0;
+            idxs[order[j]] = 0;
         }
     }
 }
@@ -186,13 +202,13 @@ sv_csr_t &state_t::sv()
     return get_usv();
 }
 
-sv_shape_t* state_t::get_shape(reg_t reg)
+sv_shape_t* state_t::get_shape(reg_t reg, bool pred)
 {
     if (prv == PRV_M || prv == PRV_S || reg == 0) {
         return NULL;
     }
     for (int i = 0; i < 3; i++) {
-        if (remap[i].regidx == reg) {
+        if (remap[i].regidx == reg && remap[i].pred == pred) {
             return &shape[i];
         }
     }
@@ -340,6 +356,7 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
   // by default, trap to M-mode, unless delegated to S-mode
   reg_t bit = t.cause();
   reg_t deleg = state.medeleg;
+  reg_t svstate = get_csr(CSR_SV_STATE);
   bool interrupt = (bit & ((reg_t)1 << (max_xlen-1))) != 0;
   if (interrupt)
     deleg = state.mideleg, bit &= ~((reg_t)1 << (max_xlen-1));
@@ -348,6 +365,7 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
     state.pc = state.stvec;
     state.scause = t.cause();
     state.sepc = epc;
+    state.sesvstate = svstate;
     state.stval = t.get_tval();
 
     reg_t s = state.mstatus;
@@ -360,6 +378,7 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
     reg_t vector = (state.mtvec & 1) && interrupt ? 4*bit : 0;
     state.pc = (state.mtvec & ~(reg_t)1) + vector;
     state.mepc = epc;
+    state.mesvstate = svstate;
     state.mcause = t.cause();
     state.mtval = t.get_tval();
 
@@ -396,72 +415,29 @@ int processor_t::paddr_bits()
   return max_xlen == 64 ? 50 : 34;
 }
 
-void processor_t::set_csr(int which, reg_t val)
+void state_t::get_csr_start_end(int &start, int &end)
 {
-  val = _zext_xlen(val);
-  reg_t delegable_ints = MIP_SSIP | MIP_STIP | MIP_SEIP
-                       | ((ext != NULL) << IRQ_COP);
-  reg_t all_ints = delegable_ints | MIP_MSIP | MIP_MTIP;
-  fprintf(stderr, "set CSR %x %lx\n", which, val);
-  switch (which)
-  {
-#ifdef SPIKE_SIMPLEV
-    case CSR_USVMVL:
-      state.sv().mvl = std::min(val, (uint64_t)64); // limited to XLEN width
-      // TODO XXX throw exception if val == 0
-      fprintf(stderr, "set MVL %lx\n", state.sv().mvl);
-      break;
-    case CSR_USVSTATE:
-      // bits 0-5: mvl - 6-11: vl - 12-17: srcoffs - 18-23: destoffs
-      set_csr(CSR_USVMVL, get_field(val, 0x1f   )+1);
-      set_csr(CSR_USVVL , get_field(val, 0x1f<<6)+1);
-      state.sv().srcoffs  = std::min(get_field(val, 0x1f<<12), state.sv().vl-1);
-      state.sv().destoffs = std::min(get_field(val, 0x1f<<18), state.sv().vl-1);
-      break;
-    case CSR_USVVL:
-      state.sv().vl = std::min(state.sv().mvl, val);
-      // TODO XXX throw exception if val == 0
-      fprintf(stderr, "set VL %lx\n", state.sv().vl);
-      break;
-    case CSR_SVREGCFG0:
-    case CSR_SVREGCFG1:
-    case CSR_SVREGCFG2:
-    case CSR_SVREGCFG3:
-    case CSR_SVREGCFG4:
-    case CSR_SVREGCFG5:
-    case CSR_SVREGCFG6:
-    case CSR_SVREGCFG7:
+    start = sv().state_bank * 4;
+    end = start + (1 << (sv().state_size+1));
+    start = std::min(sv_csr_sz(), start);
+    end = std::min(sv_csr_sz(), end);
+    fprintf(stderr, "sv state csr start/end: %d %d\n", start, end);
+}
+
+void state_t::sv_csr_reg_unpack()
+{
+    // okaaay and now "unpack" the CAM to make it easier to use.  this
+    // approach is not designed to be efficient right now.  optimise later
+    // first clear the old tables
+    memset(sv().sv_int_tb, 0, sizeof(sv().sv_int_tb));
+    memset(sv().sv_fp_tb, 0, sizeof(sv().sv_fp_tb));
+    // now walk the CAM and unpack it
+    int start = 0;
+    int end = 0;
+    get_csr_start_end(start, end);
+    for (int i = start; i < end; i++)
     {
-      uint64_t v = (uint64_t)val;
-      // identify which (pair) of SV config CAM registers are being set
-      int tbidx = (which - CSR_SVREGCFG0) * 2;
-      fprintf(stderr, "set REGCFG %d %lx\n", tbidx, v);
-      // lower 16 bits go into even, upper into odd...
-      state.sv().sv_csrs[tbidx].u = get_field(v, 0xffffUL);
-      state.sv().sv_csrs[tbidx+1].u = get_field(v, 0xffffUL<<16);
-      int clroffset = 2;
-      if (xlen == 64)
-      {
-          state.sv().sv_csrs[tbidx+2].u = get_field(v, 0xffffUL<<32);
-          state.sv().sv_csrs[tbidx+3].u = get_field(v, 0xffffUL<<48);
-        clroffset = 4;
-      }
-      // clear out all CSRs above the one(s) being set: this ensures that
-      // when it comes to context-switching, it's clear what needs to be saved
-      for (int i = tbidx+clroffset; i < 16; i++)
-      {
-          fprintf(stderr, "clr REGCFG %d\n", i);
-          state.sv().sv_csrs[i].u = 0;
-      }
-      // okaaay and now "unpack" the CAM to make it easier to use.  this
-      // approach is not designed to be efficient right now.  optimise later
-      // first clear the old tables
-      memset(state.sv().sv_int_tb, 0, sizeof(state.sv().sv_int_tb));
-      memset(state.sv().sv_fp_tb, 0, sizeof(state.sv().sv_fp_tb));
-      // now walk the CAM and unpack it
-      for (int i = 0; i < state.sv_csr_sz(); i++)
-      {
-        union sv_reg_csr_entry *c = &state.sv().sv_csrs[i];
+        union sv_reg_csr_entry *c = &sv().sv_csrs[i];
         uint64_t idx = c->b.regkey;
         sv_reg_entry *r;
         if (c->u == 0)
@@ -471,11 +447,11 @@ void processor_t::set_csr(int which, reg_t val)
         // XXX damn.  this basically duplicates sv_insn_t::get_regentry.
         if (c->b.type == 1)
         {
-            r = &state.sv().sv_int_tb[idx];
+            r = &sv().sv_int_tb[idx];
         }
         else
         {
-            r = &state.sv().sv_fp_tb[idx];
+            r = &sv().sv_fp_tb[idx];
         }
         r->elwidth = c->b.elwidth;
         r->regidx = c->b.regidx;
@@ -483,7 +459,147 @@ void processor_t::set_csr(int which, reg_t val)
         r->active = true;
         fprintf(stderr, "setting REGCFG type:%d isvec:%d %d %d\n",
                         c->b.type, r->isvec, (int)idx, (int)r->regidx);
+    }
+}
+
+void state_t::sv_csr_pred_unpack()
+{
+    memset(sv().sv_pred_int_tb, 0, sizeof(sv().sv_pred_int_tb));
+    memset(sv().sv_pred_fp_tb, 0, sizeof(sv().sv_pred_fp_tb));
+    int start = 0;
+    int end = 0;
+    get_csr_start_end(start, end);
+    for (int i = start; i < end; i++)
+    {
+        union sv_pred_csr_entry *c = &sv().sv_pred_csrs[i];
+        uint64_t idx = c->b.regkey;
+        if (c->u == 0)
+        {
+            break;
+        }
+        sv_pred_entry *r;
+        // XXX damn.  this basically duplicates sv_insn_t::get_predentry.
+        if (c->b.type == 1)
+        {
+            r = &sv().sv_pred_int_tb[idx];
+        }
+        else
+        {
+            r = &sv().sv_pred_fp_tb[idx];
+        }
+        r->regidx = c->b.regidx;
+        r->zero   = c->b.zero;
+        r->inv    = c->b.inv;
+        r->ffirst = c->b.ffirst;
+        r->active = true;
+        fprintf(stderr, "setting PREDCFG %d type:%d zero:%d %d %d\n",
+                        i, c->b.type, r->zero, (int)idx, (int)r->regidx);
+    }
+}
+
+reg_t processor_t::set_csr(int which, reg_t val, bool imm_mode)
+{
+  reg_t old_val = get_csr(which);
+  val = _zext_xlen(val);
+  reg_t delegable_ints = MIP_SSIP | MIP_STIP | MIP_SEIP
+                       | ((ext != NULL) << IRQ_COP);
+  reg_t all_ints = delegable_ints | MIP_MSIP | MIP_MTIP;
+  fprintf(stderr, "set CSR %x %lx\n", which, val);
+  switch (which)
+  {
+#ifdef SPIKE_SIMPLEV
+    case CSR_SV_MVL:
+      state.sv().mvl = std::min(val+1, (uint64_t)64); // limited to XLEN width
+      old_val = state.sv().mvl - 1;
+      // TODO XXX throw exception if val == 0
+      fprintf(stderr, "set MVL %lx\n", state.sv().mvl);
+      break;
+    case CSR_SV_STATE:
+    {
+      // bits 0-5: mvl - 6-11: vl - 12-17: srcoffs - 18-23: destoffs
+      set_csr(CSR_SV_MVL, get_field(val, SV_STATE_VL ));
+      set_csr(CSR_SV_VL , get_field(val, SV_STATE_MVL));
+      set_csr(CSR_SV_SUBVL , get_field(val, SV_STATE_SUBVL)+1);
+      // decode (and limit) src/dest VL offsets
+      reg_t srcoffs = get_field(val, SV_STATE_SRCOFFS);
+      reg_t destoffs = get_field(val, SV_STATE_DESTOFFS);
+      state.sv().srcoffs  = std::min(srcoffs , state.sv().vl-1);
+      state.sv().destoffs = std::min(destoffs, state.sv().vl-1);
+      // decode (and limit) src/dest SUBVL offsets
+      reg_t subdestoffs = get_field(val, SV_STATE_DSVOFFS);
+      state.sv().dsvoffs = std::min(subdestoffs, state.sv().subvl-1);
+      //int state_bank = get_field(val, SV_STATE_BANK);
+      //int state_size = get_field(val, SV_STATE_SIZE);
+      //set_csr(CSR_USVCFG, state_bank | (state_size << 3));
+      break;
+    }
+    case CSR_SV_CFG:
+    {
+      int old_bank = state.sv().state_bank;
+      int old_size = state.sv().state_size;
+      state.sv().state_bank = get_field(val, SV_CFG_BANK);
+      state.sv().state_size = get_field(val, SV_CFG_SIZE);
+      if (old_bank != state.sv().state_bank ||
+          old_size != state.sv().state_size)
+      {
+        // if the bank or size is changed, the csrs that are enabled
+        // also changes.  easiest thing in software: recalculate them all
+        state.sv_csr_pred_unpack();
+        state.sv_csr_reg_unpack();
+      }
+      break;
+    }
+    case CSR_SV_SUBVL:
+      state.sv().subvl = std::max(1, std::min(4, (int)val));
+      old_val = state.sv().subvl;
+      // TODO XXX throw exception if val attempted to be set == 0
+      fprintf(stderr, "set SUBVL %lx\n", state.sv().subvl);
+      break;
+    case CSR_SV_VL:
+      state.sv().vl = std::min(state.sv().mvl, val + 1);
+      old_val = state.sv().mvl - 1;
+      // TODO XXX throw exception if val == 0
+      fprintf(stderr, "set VL %lx\n", state.sv().vl);
+      break;
+    case CSR_SVREGTOP:
+    case CSR_SVREGBOT:
+    {
+      bool top = (which == CSR_SVREGTOP);
+      uint64_t v = (uint64_t)val;
+      fprintf(stderr, "set SVREG %d %lx\n", top, v);
+      int start = 0;
+      int end = 0;
+      state.get_csr_start_end(start, end);
+      uint64_t res_old = 0;
+      int num_entries = val & 0xf;
+      int max_xlen_entries = (xlen == 64) ? 4 : 2;
+      if (!imm_mode) {
+          num_entries = max_xlen_entries;
       }
+      // read 2 16-bit entries for RV32, 4 16-bit entries for RV64
+      int popidx = 0;
+      for (int i = 0; i < num_entries; i++) {
+          uint64_t svcfg = 0;
+          if (!imm_mode) {
+              uint64_t mask = 0xffffUL << (i*16UL);
+              svcfg = get_field(v, mask);
+              fprintf(stderr, "SVREG mask %lx cfg %lx\n", mask, svcfg);
+              if (!svcfg && i > 0) {
+                break;
+              }
+          }
+          // see regpush on how this works.
+          uint64_t res = state.sv().regpush(svcfg, end, top);
+          if (res != 0) {
+              res_old |= res << (popidx * 16UL);
+              popidx += 1;
+              if (popidx == max_xlen_entries) {
+                break;
+              }
+          }
+      }
+      old_val = res_old;
+      state.sv_csr_reg_unpack();
       break;
     }
     case CSR_SVPREDCFG0:
@@ -513,34 +629,7 @@ void processor_t::set_csr(int which, reg_t val)
       {
           state.sv().sv_pred_csrs[i].u = 0;
       }
-      memset(state.sv().sv_pred_int_tb, 0, sizeof(state.sv().sv_pred_int_tb));
-      memset(state.sv().sv_pred_fp_tb, 0, sizeof(state.sv().sv_pred_fp_tb));
-      for (int i = 0; i < state.sv_csr_sz(); i++)
-      {
-        union sv_pred_csr_entry *c = &state.sv().sv_pred_csrs[i];
-        uint64_t idx = c->b.regkey;
-        if (c->u == 0)
-        {
-            break;
-        }
-        sv_pred_entry *r;
-        // XXX damn.  this basically duplicates sv_insn_t::get_predentry.
-        if (c->b.type == 1)
-        {
-            r = &state.sv().sv_pred_int_tb[idx];
-        }
-        else
-        {
-            r = &state.sv().sv_pred_fp_tb[idx];
-        }
-        r->regidx = c->b.regidx;
-        r->zero   = c->b.zero;
-        r->inv    = c->b.inv;
-        r->packed = c->b.packed;
-        r->active = true;
-        fprintf(stderr, "setting PREDCFG %d type:%d zero:%d %d %d\n",
-                        i, c->b.type, r->zero, (int)idx, (int)r->regidx);
-      }
+      state.sv_csr_pred_unpack();
       break;
     }
     case CSR_UREMAP:
@@ -548,6 +637,9 @@ void processor_t::set_csr(int which, reg_t val)
       state.remap[0].regidx = get_field(val, SV_REMAP_REGIDX0);
       state.remap[1].regidx = get_field(val, SV_REMAP_REGIDX1);
       state.remap[2].regidx = get_field(val, SV_REMAP_REGIDX2);
+      state.remap[0].pred = get_field(val, SV_REMAP_PRED0);
+      state.remap[1].pred = get_field(val, SV_REMAP_PRED1);
+      state.remap[2].pred = get_field(val, SV_REMAP_PRED2);
       state.remap[0].shape = get_field(val, SV_REMAP_SHAPE0);
       state.remap[1].shape = get_field(val, SV_REMAP_SHAPE1);
       state.remap[2].shape = get_field(val, SV_REMAP_SHAPE2);
@@ -558,14 +650,21 @@ void processor_t::set_csr(int which, reg_t val)
     case CSR_USHAPE2:
     {
       int shapeidx = which - CSR_USHAPE0;
-      state.shape[shapeidx].xsz = get_field(val, SV_SHAPE_XDIM);
-      state.shape[shapeidx].ysz = get_field(val, SV_SHAPE_YDIM);
-      state.shape[shapeidx].zsz = get_field(val, SV_SHAPE_ZDIM);
+      state.shape[shapeidx].xsz = get_field(val, SV_SHAPE_XDIM) + 1;
+      state.shape[shapeidx].ysz = get_field(val, SV_SHAPE_YDIM) + 1;
+      state.shape[shapeidx].zsz = get_field(val, SV_SHAPE_ZDIM) + 1;
       state.shape[shapeidx].offs = (get_field(val, (1<<7 )) ? 0x1 : 0) |
                                    (get_field(val, (1<<15)) ? 0x2 : 0) |
                                    (get_field(val, (1<<23)) ? 0x4 : 0);
       state.shape[shapeidx].permute = get_field(val, SV_SHAPE_PERM);
       state.shape[shapeidx].setup_map();
+      fprintf(stderr, "sv shape %d x %d y %d z %d offs %d perm %d\n",
+              shapeidx,
+              state.shape[shapeidx].xsz,
+              state.shape[shapeidx].ysz,
+              state.shape[shapeidx].zsz,
+              state.shape[shapeidx].offs,
+              state.shape[shapeidx].permute);
       break;
     }
 #endif
@@ -682,11 +781,13 @@ void processor_t::set_csr(int which, reg_t val)
       break;
     }
     case CSR_SEPC: state.sepc = val & ~(reg_t)1; break;
+    case CSR_SESVSTATE: state.sesvstate = val; break;
     case CSR_STVEC: state.stvec = val >> 2 << 2; break;
     case CSR_SSCRATCH: state.sscratch = val; break;
     case CSR_SCAUSE: state.scause = val; break;
     case CSR_STVAL: state.stval = val; break;
     case CSR_MEPC: state.mepc = val & ~(reg_t)1; break;
+    case CSR_MESVSTATE: state.mesvstate = val; break;
     case CSR_MTVEC: state.mtvec = val & ~(reg_t)2; break;
     case CSR_MSCRATCH: state.mscratch = val; break;
     case CSR_MCAUSE: state.mcause = val; break;
@@ -766,6 +867,7 @@ void processor_t::set_csr(int which, reg_t val)
       state.dscratch = val;
       break;
   }
+  return old_val;
 }
 
 reg_t processor_t::get_csr(int which)
@@ -793,21 +895,27 @@ reg_t processor_t::get_csr(int which)
   switch (which)
   {
 #ifdef SPIKE_SIMPLEV
-    case CSR_USVVL:
+    case CSR_SV_VL:
       return state.sv().vl;
-    case CSR_USVSTATE:
-      return (state.sv().vl-1)            | ((state.sv().mvl-1)<<6) |
-             (state.sv().srcoffs<<12)     | (state.sv().destoffs<<18) ;
-    case CSR_USVMVL:
+    case CSR_SV_CFG:
+      return (state.sv().state_bank)      | (state.sv().state_size<<3);
+    case CSR_SV_STATE:
+      fprintf(stderr, "get CSR_SV_STATE vl %ld mvl %ld subvl %ld\n",
+                            state.sv().vl,
+                            state.sv().mvl,
+                            state.sv().subvl);
+      return ((std::max((int)state.sv().vl, 1))-1)     |
+             ((std::max((int)state.sv().mvl, 1)-1)<<6) |
+             (state.sv().srcoffs<<12)     |
+             (state.sv().destoffs<<18) |
+             ((std::max((int)state.sv().subvl, 1)-1)<<24)   |
+             (state.sv().dsvoffs<<26);
+    case CSR_SV_MVL:
       return state.sv().mvl;
-    case CSR_SVREGCFG0:
-    case CSR_SVREGCFG1:
-    case CSR_SVREGCFG2:
-    case CSR_SVREGCFG3:
-    case CSR_SVREGCFG4:
-    case CSR_SVREGCFG5:
-    case CSR_SVREGCFG6:
-    case CSR_SVREGCFG7:
+    case CSR_SV_SUBVL:
+      return state.sv().subvl;
+    case CSR_SVREGTOP:
+    case CSR_SVREGBOT:
       return 0;// XXX TODO: return correct entry
     case CSR_SVPREDCFG0:
     case CSR_SVPREDCFG1:
@@ -872,6 +980,7 @@ reg_t processor_t::get_csr(int which)
     case CSR_SIP: return state.mip & state.mideleg;
     case CSR_SIE: return state.mie & state.mideleg;
     case CSR_SEPC: return state.sepc & pc_alignment_mask();
+    case CSR_SESVSTATE: return state.sesvstate;
     case CSR_STVAL: return state.stval;
     case CSR_STVEC: return state.stvec;
     case CSR_SCAUSE:
@@ -887,6 +996,7 @@ reg_t processor_t::get_csr(int which)
     case CSR_MIP: return state.mip;
     case CSR_MIE: return state.mie;
     case CSR_MEPC: return state.mepc & pc_alignment_mask();
+    case CSR_MESVSTATE: return state.mesvstate;
     case CSR_MSCRATCH: return state.mscratch;
     case CSR_MCAUSE: return state.mcause;
     case CSR_MTVAL: return state.mtval;