add comment
[riscv-isa-sim.git] / riscv / processor.cc
index 6f0d3a7b9008bef422a8769ec4b881e2edc81fb7..3b0d3956ff8b8dc3fedb8387db8661b9c642a2ca 100644 (file)
@@ -4,7 +4,7 @@
 #include "extension.h"
 #include "common.h"
 #include "config.h"
-#include "sim.h"
+#include "simif.h"
 #include "mmu.h"
 #include "disasm.h"
 #include <cinttypes>
 #include <limits.h>
 #include <stdexcept>
 #include <algorithm>
+#ifdef SPIKE_SIMPLEV
+#include "sv_insn_redirect.h"
+#endif
 
 #undef STATE
 #define STATE state
 
-processor_t::processor_t(const char* isa, sim_t* sim, uint32_t id,
+processor_t::processor_t(const char* isa, simif_t* sim, uint32_t id,
         bool halt_on_reset)
   : debug(false), halt_request(false), sim(sim), ext(NULL), id(id),
-  halt_on_reset(halt_on_reset)
+  halt_on_reset(halt_on_reset), last_pc(1), executions(1)
+#ifdef SPIKE_SIMPLEV
+    , s(this)
+#endif
 {
   parse_isa_string(isa);
   register_base_instructions();
 
+#ifdef SPIKE_SIMPLEV
+  mmu = new sv_mmu_t(sim, this);
+#else
   mmu = new mmu_t(sim, this);
+#endif
+
   disassembler = new disassembler_t(max_xlen);
+  if (ext)
+    for (auto disasm_insn : ext->get_disasms())
+      disassembler->add_insn(disasm_insn);
 
   reset();
 }
@@ -61,20 +75,20 @@ void processor_t::parse_isa_string(const char* str)
     lowercase += std::tolower(*r);
 
   const char* p = lowercase.c_str();
-  const char* all_subsets = "imafdc";
+  const char* all_subsets = "imafdqc";
 
   max_xlen = 64;
-  isa = reg_t(2) << 62;
+  state.misa = reg_t(2) << 62;
 
   if (strncmp(p, "rv32", 4) == 0)
-    max_xlen = 32, isa = reg_t(1) << 30, p += 4;
+    max_xlen = 32, state.misa = reg_t(1) << 30, p += 4;
   else if (strncmp(p, "rv64", 4) == 0)
     p += 4;
   else if (strncmp(p, "rv", 2) == 0)
     p += 2;
 
   if (!*p) {
-    p = all_subsets;
+    p = "imafdc";
   } else if (*p == 'g') { // treat "G" as "IMAFD"
     tmp = std::string("imafd") + (p+1);
     p = &tmp[0];
@@ -83,11 +97,11 @@ void processor_t::parse_isa_string(const char* str)
   }
 
   isa_string = "rv" + std::to_string(max_xlen) + p;
-  isa |= 1L << ('s' - 'a'); // advertise support for supervisor mode
-  isa |= 1L << ('u' - 'a'); // advertise support for user mode
+  state.misa |= 1L << ('s' - 'a'); // advertise support for supervisor mode
+  state.misa |= 1L << ('u' - 'a'); // advertise support for user mode
 
   while (*p) {
-    isa |= 1L << (*p - 'a');
+    state.misa |= 1L << (*p - 'a');
 
     if (auto next = strchr(all_subsets, *p)) {
       all_subsets = next + 1;
@@ -106,22 +120,99 @@ void processor_t::parse_isa_string(const char* str)
   if (supports_extension('D') && !supports_extension('F'))
     bad_isa_string(str);
 
-  // advertise support for supervisor and user modes
-  isa |= 1L << ('s' - 'a');
-  isa |= 1L << ('u' - 'a');
+  if (supports_extension('Q') && !supports_extension('D'))
+    bad_isa_string(str);
+
+  if (supports_extension('Q') && max_xlen < 64)
+    bad_isa_string(str);
 
-  max_isa = isa;
+  max_isa = state.misa;
 }
 
-void state_t::reset()
+void state_t::reset(reg_t max_isa)
 {
   memset(this, 0, sizeof(*this));
+  misa = max_isa;
   prv = PRV_M;
   pc = DEFAULT_RSTVEC;
-  load_reservation = -1;
   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()
+{
+    int order[3] = {};
+    int lims[3] = {xsz, ysz, zsz};
+    int idxs[3] = {0,0,0};
+
+    switch (permute) {
+        case SV_SHAPE_PERM_XYZ: order[0] = 0; order[1] = 1; order[2] = 2; break;
+        case SV_SHAPE_PERM_XZY: order[0] = 0; order[1] = 2; order[2] = 1; break;
+        case SV_SHAPE_PERM_YXZ: order[0] = 1; order[1] = 0; order[2] = 2; break;
+        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++)
+    {
+        uint8_t new_idx = idxs[0] + idxs[1] * xsz + idxs[2] * xsz * ysz;
+        map[i] = new_idx;
+        for (int j = 0; j < 3; j++)
+        {
+            idxs[order[j]] = idxs[order[j]] + 1;
+            if (idxs[order[j]] != lims[order[j]]) {
+                break;
+            }
+            idxs[order[j]] = 0;
+        }
+    }
+}
+
+int state_t::sv_csr_sz()
+{
+    if (prv == PRV_M)
+        return SV_MCSR_SZ;
+    if (prv == PRV_S)
+        return SV_SCSR_SZ;
+    return SV_UCSR_SZ;
+}
+sv_csr_t &state_t::sv()
+{
+    if (prv == PRV_M)
+        return get_msv();
+    if (prv == PRV_S)
+        return get_ssv();
+    return get_usv();
+}
+
+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 && remap[i].pred == pred) {
+            return &shape[i];
+        }
+    }
+    return NULL;
 }
 
 void processor_t::set_debug(bool value)
@@ -144,13 +235,16 @@ void processor_t::set_histogram(bool value)
 
 void processor_t::reset()
 {
-  state.reset();
+  state.reset(max_isa);
   state.dcsr.halt = halt_on_reset;
   halt_on_reset = false;
   set_csr(CSR_MSTATUS, state.mstatus);
 
   if (ext)
     ext->reset(); // reset the extension
+
+  if (sim)
+    sim->proc_reset(id);
 }
 
 // Count number of contiguous 0 bits starting from the LSB.
@@ -171,20 +265,56 @@ void processor_t::take_interrupt(reg_t pending_interrupts)
 
   reg_t sie = get_field(state.mstatus, MSTATUS_SIE);
   reg_t s_enabled = state.prv < PRV_S || (state.prv == PRV_S && sie);
+  // M-ints have highest priority; consider S-ints only if no M-ints pending
   if (enabled_interrupts == 0)
     enabled_interrupts = pending_interrupts & state.mideleg & -s_enabled;
 
-  if (enabled_interrupts)
+  if (state.dcsr.cause == 0 && enabled_interrupts) {
+    // nonstandard interrupts have highest priority
+    if (enabled_interrupts >> IRQ_M_EXT)
+      enabled_interrupts = enabled_interrupts >> IRQ_M_EXT << IRQ_M_EXT;
+    // external interrupts have next-highest priority
+    else if (enabled_interrupts & (MIP_MEIP | MIP_SEIP))
+      enabled_interrupts = enabled_interrupts & (MIP_MEIP | MIP_SEIP);
+    // software interrupts have next-highest priority
+    else if (enabled_interrupts & (MIP_MSIP | MIP_SSIP))
+      enabled_interrupts = enabled_interrupts & (MIP_MSIP | MIP_SSIP);
+    // timer interrupts have next-highest priority
+    else if (enabled_interrupts & (MIP_MTIP | MIP_STIP))
+      enabled_interrupts = enabled_interrupts & (MIP_MTIP | MIP_STIP);
+    else
+      abort();
+
     throw trap_t(((reg_t)1 << (max_xlen-1)) | ctz(enabled_interrupts));
+  }
 }
 
-void processor_t::set_privilege(reg_t prv)
+static int xlen_to_uxl(int xlen)
+{
+  if (xlen == 32)
+    return 1;
+  if (xlen == 64)
+    return 2;
+  abort();
+}
+
+reg_t processor_t::legalize_privilege(reg_t prv)
 {
   assert(prv <= PRV_M);
-  if (prv == PRV_H)
-    prv = PRV_U;
+
+  if (!supports_extension('U'))
+    return PRV_M;
+
+  if (prv == PRV_H || !supports_extension('S'))
+    return PRV_U;
+
+  return prv;
+}
+
+void processor_t::set_privilege(reg_t prv)
+{
   mmu->flush_tlb();
-  state.prv = prv;
+  state.prv = legalize_privilege(prv);
 }
 
 void processor_t::enter_debug_mode(uint8_t cause)
@@ -193,7 +323,7 @@ void processor_t::enter_debug_mode(uint8_t cause)
   state.dcsr.prv = state.prv;
   set_privilege(PRV_M);
   state.dpc = state.pc;
-  state.pc = debug_rom_entry();
+  state.pc = DEBUG_ROM_ENTRY;
 }
 
 void processor_t::take_trap(trap_t& t, reg_t epc)
@@ -201,14 +331,14 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
   if (debug) {
     fprintf(stderr, "core %3d: exception %s, epc 0x%016" PRIx64 "\n",
             id, t.name(), epc);
-    if (t.has_badaddr())
-      fprintf(stderr, "core %3d:           badaddr 0x%016" PRIx64 "\n", id,
-          t.get_badaddr());
+    if (t.has_tval())
+      fprintf(stderr, "core %3d:           tval 0x%016" PRIx64 "\n", id,
+          t.get_tval());
   }
 
   if (state.dcsr.cause) {
     if (t.cause() == CAUSE_BREAKPOINT) {
-      state.pc = debug_rom_entry();
+      state.pc = DEBUG_ROM_ENTRY;
     } else {
       state.pc = DEBUG_ROM_TVEC;
     }
@@ -217,7 +347,6 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
 
   if (t.cause() == CAUSE_BREAKPOINT && (
               (state.prv == PRV_M && state.dcsr.ebreakm) ||
-              (state.prv == PRV_H && state.dcsr.ebreakh) ||
               (state.prv == PRV_S && state.dcsr.ebreaks) ||
               (state.prv == PRV_U && state.dcsr.ebreaku))) {
     enter_debug_mode(DCSR_CAUSE_SWBP);
@@ -227,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));
@@ -235,8 +365,8 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
     state.pc = state.stvec;
     state.scause = t.cause();
     state.sepc = epc;
-    if (t.has_badaddr())
-      state.sbadaddr = t.get_badaddr();
+    state.sesvstate = svstate;
+    state.stval = t.get_tval();
 
     reg_t s = state.mstatus;
     s = set_field(s, MSTATUS_SPIE, get_field(s, MSTATUS_SIE));
@@ -248,9 +378,9 @@ 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();
-    if (t.has_badaddr())
-      state.mbadaddr = t.get_badaddr();
+    state.mtval = t.get_tval();
 
     reg_t s = state.mstatus;
     s = set_field(s, MSTATUS_MPIE, get_field(s, MSTATUS_MIE));
@@ -259,15 +389,10 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
     set_csr(CSR_MSTATUS, s);
     set_privilege(PRV_M);
   }
-
-  yield_load_reservation();
 }
 
 void processor_t::disasm(insn_t insn)
 {
-  static uint64_t last_pc = 1, last_bits;
-  static uint64_t executions = 1;
-
   uint64_t bits = insn.bits() & ((1ULL << (8 * insn_length(insn.bits()))) - 1);
   if (last_pc != state.pc || last_bits != bits) {
     if (executions != 1) {
@@ -290,13 +415,259 @@ 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)
+{
+    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()
 {
-  val = zext_xlen(val);
-  reg_t delegable_ints = MIP_SSIP | MIP_STIP | MIP_SEIP | (1 << IRQ_COP);
+    // 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++)
+    {
+        union sv_reg_csr_entry *c = &sv().sv_csrs[i];
+        uint64_t idx = c->b.regkey;
+        sv_reg_entry *r;
+        if (c->u == 0)
+        {
+            break;
+        }
+        // XXX damn.  this basically duplicates sv_insn_t::get_regentry.
+        if (c->b.type == 1)
+        {
+            r = &sv().sv_int_tb[idx];
+        }
+        else
+        {
+            r = &sv().sv_fp_tb[idx];
+        }
+        r->elwidth = c->b.elwidth;
+        r->regidx = c->b.regidx;
+        r->isvec = c->b.isvec;
+        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:
+    case CSR_SVPREDCFG1:
+    case CSR_SVPREDCFG2:
+    case CSR_SVPREDCFG3:
+    case CSR_SVPREDCFG4:
+    case CSR_SVPREDCFG5:
+    case CSR_SVPREDCFG6:
+    case CSR_SVPREDCFG7:
+    {
+      // comments removed as it's near-identical to the regs version
+      // TODO: macro-ify
+      uint64_t v = (uint64_t)val;
+      int tbidx = (which - CSR_SVPREDCFG0) * 2;
+      fprintf(stderr, "set PREDCFG %d %lx\n", tbidx, v);
+      state.sv().sv_pred_csrs[tbidx].u = get_field(v, 0xffff);
+      state.sv().sv_pred_csrs[tbidx+1].u = get_field(v, 0xffff0000);
+      int clroffset = 2;
+      if (xlen == 64)
+      {
+          state.sv().sv_pred_csrs[tbidx+2].u = get_field(v, 0xffffUL<<32);
+          state.sv().sv_pred_csrs[tbidx+3].u = get_field(v, 0xffffUL<<48);
+          clroffset = 4;
+      }
+      for (int i = tbidx+clroffset; i < 16; i++)
+      {
+          state.sv().sv_pred_csrs[i].u = 0;
+      }
+      state.sv_csr_pred_unpack();
+      break;
+    }
+    case CSR_UREMAP:
+    {
+      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);
+      break;
+    }
+    case CSR_USHAPE0:
+    case CSR_USHAPE1:
+    case CSR_USHAPE2:
+    {
+      int shapeidx = which - CSR_USHAPE0;
+      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
     case CSR_FFLAGS:
       dirty_fp_state;
       state.fflags = val & (FSR_AEXC >> FSR_AEXC_SHIFT);
@@ -316,9 +687,15 @@ void processor_t::set_csr(int which, reg_t val)
         mmu->flush_tlb();
 
       reg_t mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE
-                 | MSTATUS_SPP | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM
-                 | MSTATUS_MPP | MSTATUS_MXR | MSTATUS_TW | MSTATUS_TVM
-                 | MSTATUS_TSR | (ext ? MSTATUS_XS : 0);
+                 | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM
+                 | MSTATUS_MXR | MSTATUS_TW | MSTATUS_TVM
+                 | MSTATUS_TSR | MSTATUS_UXL | MSTATUS_SXL |
+                 (ext ? MSTATUS_XS : 0);
+
+      reg_t requested_mpp = legalize_privilege(get_field(val, MSTATUS_MPP));
+      state.mstatus = set_field(state.mstatus, MSTATUS_MPP, requested_mpp);
+      if (supports_extension('S'))
+        mask |= MSTATUS_SPP;
 
       state.mstatus = (state.mstatus & ~mask) | (val & mask);
 
@@ -329,8 +706,10 @@ void processor_t::set_csr(int which, reg_t val)
       else
         state.mstatus = set_field(state.mstatus, MSTATUS64_SD, dirty);
 
-      // spike supports the notion of xlen < max_xlen, but current priv spec
-      // doesn't provide a mechanism to run RV32 software on an RV64 machine
+      state.mstatus = set_field(state.mstatus, MSTATUS_UXL, xlen_to_uxl(max_xlen));
+      state.mstatus = set_field(state.mstatus, MSTATUS_UXL, xlen_to_uxl(max_xlen));
+      state.mstatus = set_field(state.mstatus, MSTATUS_SXL, xlen_to_uxl(max_xlen));
+      // U-XLEN == S-XLEN == M-XLEN
       xlen = max_xlen;
       break;
     }
@@ -346,10 +725,13 @@ void processor_t::set_csr(int which, reg_t val)
       state.mideleg = (state.mideleg & ~delegable_ints) | (val & delegable_ints);
       break;
     case CSR_MEDELEG: {
-      reg_t mask = 0;
-#define DECLARE_CAUSE(name, value) mask |= 1ULL << (value);
-#include "encoding.h"
-#undef DECLARE_CAUSE
+      reg_t mask =
+        (1 << CAUSE_MISALIGNED_FETCH) |
+        (1 << CAUSE_BREAKPOINT) |
+        (1 << CAUSE_USER_ECALL) |
+        (1 << CAUSE_FETCH_PAGE_FAULT) |
+        (1 << CAUSE_LOAD_PAGE_FAULT) |
+        (1 << CAUSE_STORE_PAGE_FAULT);
       state.medeleg = (state.medeleg & ~mask) | (val & mask);
       break;
     }
@@ -359,10 +741,16 @@ void processor_t::set_csr(int which, reg_t val)
         state.minstret = (state.minstret >> 32 << 32) | (val & 0xffffffffU);
       else
         state.minstret = val;
+      // The ISA mandates that if an instruction writes instret, the write
+      // takes precedence over the increment to instret.  However, Spike
+      // unconditionally increments instret after executing an instruction.
+      // Correct for this artifact by decrementing instret here.
+      state.minstret--;
       break;
     case CSR_MINSTRETH:
     case CSR_MCYCLEH:
       state.minstret = (val << 32) | (state.minstret << 32 >> 32);
+      state.minstret--; // See comment above.
       break;
     case CSR_SCOUNTEREN:
       state.scounteren = val;
@@ -382,27 +770,33 @@ void processor_t::set_csr(int which, reg_t val)
     case CSR_SIE:
       return set_csr(CSR_MIE,
                      (state.mie & ~state.mideleg) | (val & state.mideleg));
-    case CSR_SPTBR: {
+    case CSR_SATP: {
       mmu->flush_tlb();
       if (max_xlen == 32)
-        state.sptbr = val & (SPTBR32_PPN | SPTBR32_MODE);
-      if (max_xlen == 64 && (get_field(val, SPTBR64_MODE) == SPTBR_MODE_OFF ||
-                             get_field(val, SPTBR64_MODE) == SPTBR_MODE_SV39 ||
-                             get_field(val, SPTBR64_MODE) == SPTBR_MODE_SV48))
-        state.sptbr = val & (SPTBR64_PPN | SPTBR64_MODE);
+        state.satp = val & (SATP32_PPN | SATP32_MODE);
+      if (max_xlen == 64 && (get_field(val, SATP64_MODE) == SATP_MODE_OFF ||
+                             get_field(val, SATP64_MODE) == SATP_MODE_SV39 ||
+                             get_field(val, SATP64_MODE) == SATP_MODE_SV48))
+        state.satp = val & (SATP64_PPN | SATP64_MODE);
       break;
     }
-    case CSR_SEPC: state.sepc = 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_SBADADDR: state.sbadaddr = val; break;
-    case CSR_MEPC: state.mepc = 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;
-    case CSR_MBADADDR: state.mbadaddr = val; break;
+    case CSR_MTVAL: state.mtval = val; break;
     case CSR_MISA: {
+      // the write is ignored if increasing IALIGN would misalign the PC
+      if (!(val & (1L << ('C' - 'A'))) && (state.pc & 2))
+        break;
+
       if (!(val & (1L << ('F' - 'A'))))
         val &= ~(1L << ('D' - 'A'));
 
@@ -415,7 +809,7 @@ void processor_t::set_csr(int which, reg_t val)
       mask |= 1L << ('C' - 'A');
       mask &= max_isa;
 
-      isa = (val & mask) | (isa & ~mask);
+      state.misa = (val & mask) | (state.misa & ~mask);
       break;
     }
     case CSR_TSELECT:
@@ -467,12 +861,13 @@ void processor_t::set_csr(int which, reg_t val)
       state.dcsr.halt = get_field(val, DCSR_HALT);
       break;
     case CSR_DPC:
-      state.dpc = val;
+      state.dpc = val & ~(reg_t)1;
       break;
     case CSR_DSCRATCH:
       state.dscratch = val;
       break;
   }
+  return old_val;
 }
 
 reg_t processor_t::get_csr(int which)
@@ -499,6 +894,45 @@ reg_t processor_t::get_csr(int which)
 
   switch (which)
   {
+#ifdef SPIKE_SIMPLEV
+    case CSR_SV_VL:
+      return state.sv().vl;
+    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_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:
+    case CSR_SVPREDCFG2:
+    case CSR_SVPREDCFG3:
+    case CSR_SVPREDCFG4:
+    case CSR_SVPREDCFG5:
+    case CSR_SVPREDCFG6:
+    case CSR_SVPREDCFG7:
+      return 0;// XXX TODO: return correct entry
+    case CSR_UREMAP:
+      return 0;// XXX TODO: return correct entry
+    case CSR_USHAPE0:
+    case CSR_USHAPE1:
+    case CSR_USHAPE2:
+      return 0;// XXX TODO: return correct entry
+#endif
     case CSR_FFLAGS:
       require_fp;
       if (!supports_extension('F'))
@@ -522,6 +956,11 @@ reg_t processor_t::get_csr(int which)
     case CSR_MINSTRET:
     case CSR_MCYCLE:
       return state.minstret;
+    case CSR_INSTRETH:
+    case CSR_CYCLEH:
+      if (ctr_ok && xlen == 32)
+        return state.minstret >> 32;
+      break;
     case CSR_MINSTRETH:
     case CSR_MCYCLEH:
       if (xlen == 32)
@@ -531,7 +970,7 @@ reg_t processor_t::get_csr(int which)
     case CSR_MCOUNTEREN: return state.mcounteren;
     case CSR_SSTATUS: {
       reg_t mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_SPP | SSTATUS_FS
-                 | SSTATUS_XS | SSTATUS_SUM;
+                 | SSTATUS_XS | SSTATUS_SUM | SSTATUS_MXR | SSTATUS_UXL;
       reg_t sstatus = state.mstatus & mask;
       if ((sstatus & SSTATUS_FS) == SSTATUS_FS ||
           (sstatus & SSTATUS_XS) == SSTATUS_XS)
@@ -540,26 +979,28 @@ 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;
-    case CSR_SBADADDR: return state.sbadaddr;
+    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:
       if (max_xlen > xlen)
         return state.scause | ((state.scause >> (max_xlen-1)) << (xlen-1));
       return state.scause;
-    case CSR_SPTBR:
+    case CSR_SATP:
       if (get_field(state.mstatus, MSTATUS_TVM))
         require_privilege(PRV_M);
-      return state.sptbr;
+      return state.satp;
     case CSR_SSCRATCH: return state.sscratch;
     case CSR_MSTATUS: return state.mstatus;
     case CSR_MIP: return state.mip;
     case CSR_MIE: return state.mie;
-    case CSR_MEPC: return state.mepc;
+    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_MBADADDR: return state.mbadaddr;
-    case CSR_MISA: return isa;
+    case CSR_MTVAL: return state.mtval;
+    case CSR_MISA: return state.misa;
     case CSR_MARCHID: return 0;
     case CSR_MIMPID: return 0;
     case CSR_MVENDORID: return 0;
@@ -616,7 +1057,7 @@ reg_t processor_t::get_csr(int which)
         return v;
       }
     case CSR_DPC:
-      return state.dpc;
+      return state.dpc & pc_alignment_mask();
     case CSR_DSCRATCH:
       return state.dscratch;
   }
@@ -756,3 +1197,4 @@ void processor_t::trigger_updated()
     }
   }
 }
+