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()
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];
}
}
// 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));
state.pc = state.stvec;
state.scause = t.cause();
state.sepc = epc;
+ state.sesvstate = svstate;
state.stval = t.get_tval();
reg_t s = state.mstatus;
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();
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)
// 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;
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:
{
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:
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_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;
state.dscratch = val;
break;
}
+ return old_val;
}
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:
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:
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;