aboutsummaryrefslogtreecommitdiff
path: root/riscv/processor.cc
diff options
context:
space:
mode:
Diffstat (limited to 'riscv/processor.cc')
-rw-r--r--riscv/processor.cc76
1 files changed, 57 insertions, 19 deletions
diff --git a/riscv/processor.cc b/riscv/processor.cc
index 59fa062..9b8050c 100644
--- a/riscv/processor.cc
+++ b/riscv/processor.cc
@@ -20,14 +20,15 @@
#undef STATE
#define STATE state
-processor_t::processor_t(const char* isa, const char* varch, simif_t* sim,
- uint32_t id, bool halt_on_reset)
+processor_t::processor_t(const char* isa, const char* priv, const char* varch,
+ simif_t* sim, uint32_t id, bool halt_on_reset)
: debug(false), halt_request(false), sim(sim), ext(NULL), id(id),
histogram_enabled(false), log_commits_enabled(false),
halt_on_reset(halt_on_reset), last_pc(1), executions(1)
{
VU.p = this;
parse_isa_string(isa);
+ parse_priv_string(priv);
parse_varch_string(varch);
register_base_instructions();
mmu = new mmu_t(sim, this);
@@ -61,6 +62,12 @@ static void bad_isa_string(const char* isa)
abort();
}
+static void bad_priv_string(const char* priv)
+{
+ fprintf(stderr, "error: bad --priv option %s\n", priv);
+ abort();
+}
+
static void bad_varch_string(const char* varch)
{
fprintf(stderr, "error: bad --varch option %s\n", varch);
@@ -121,11 +128,35 @@ void processor_t::parse_varch_string(const char* s)
VU.SLEN = slen;
}
-void processor_t::parse_isa_string(const char* str)
+static std::string strtolower(const char* str)
{
- std::string lowercase, tmp;
+ std::string res;
for (const char *r = str; *r; r++)
- lowercase += std::tolower(*r);
+ res += std::tolower(*r);
+ return res;
+}
+
+void processor_t::parse_priv_string(const char* str)
+{
+ std::string lowercase = strtolower(str);
+ bool user = false, supervisor = false;
+
+ if (lowercase == "m")
+ ;
+ else if (lowercase == "mu")
+ user = true;
+ else if (lowercase == "msu")
+ user = supervisor = true;
+ else
+ bad_priv_string(str);
+
+ max_isa |= reg_t(user) << ('u' - 'a');
+ max_isa |= reg_t(supervisor) << ('s' - 'a');
+}
+
+void processor_t::parse_isa_string(const char* str)
+{
+ std::string lowercase = strtolower(str), tmp;
const char* p = lowercase.c_str();
const char* all_subsets = "imafdqc"
@@ -135,10 +166,10 @@ void processor_t::parse_isa_string(const char* str)
"";
max_xlen = 64;
- state.misa = reg_t(2) << 62;
+ max_isa = reg_t(2) << 62;
if (strncmp(p, "rv32", 4) == 0)
- max_xlen = 32, state.misa = reg_t(1) << 30, p += 4;
+ max_xlen = 32, max_isa = reg_t(1) << 30, p += 4;
else if (strncmp(p, "rv64", 4) == 0)
p += 4;
else if (strncmp(p, "rv", 2) == 0)
@@ -154,11 +185,9 @@ void processor_t::parse_isa_string(const char* str)
}
isa_string = "rv" + std::to_string(max_xlen) + p;
- state.misa |= 1L << ('s' - 'a'); // advertise support for supervisor mode
- state.misa |= 1L << ('u' - 'a'); // advertise support for user mode
while (*p) {
- state.misa |= 1L << (*p - 'a');
+ max_isa |= 1L << (*p - 'a');
if (auto next = strchr(all_subsets, *p)) {
all_subsets = next + 1;
@@ -179,8 +208,6 @@ void processor_t::parse_isa_string(const char* str)
if (supports_extension('Q') && !supports_extension('D'))
bad_isa_string(str);
-
- max_isa = state.misa;
}
void state_t::reset(reg_t max_isa)
@@ -349,7 +376,7 @@ reg_t processor_t::legalize_privilege(reg_t prv)
if (!supports_extension('U'))
return PRV_M;
- if (prv == PRV_H || !supports_extension('S'))
+ if (prv == PRV_H || (prv == PRV_S && !supports_extension('S')))
return PRV_U;
return prv;
@@ -461,8 +488,9 @@ int processor_t::paddr_bits()
void processor_t::set_csr(int which, reg_t val)
{
val = zext_xlen(val);
- reg_t delegable_ints = MIP_SSIP | MIP_STIP | MIP_SEIP
- | ((ext != NULL) << IRQ_COP);
+ reg_t supervisor_ints = supports_extension('S') ? MIP_SSIP | MIP_STIP | MIP_SEIP : 0;
+ reg_t coprocessor_ints = (ext != NULL) << IRQ_COP;
+ reg_t delegable_ints = supervisor_ints | coprocessor_ints;
reg_t all_ints = delegable_ints | MIP_MSIP | MIP_MTIP;
if (which >= CSR_PMPADDR0 && which < CSR_PMPADDR0 + state.n_pmp) {
@@ -507,10 +535,14 @@ void processor_t::set_csr(int which, reg_t val)
(MSTATUS_MPP | MSTATUS_MPRV | MSTATUS_SUM | MSTATUS_MXR))
mmu->flush_tlb();
+ bool has_fs = supports_extension('S') || supports_extension('F')
+ || supports_extension('V');
+
reg_t mask = MSTATUS_SIE | MSTATUS_SPIE | MSTATUS_MIE | MSTATUS_MPIE
- | MSTATUS_FS | MSTATUS_MPRV | MSTATUS_SUM
+ | MSTATUS_MPRV | MSTATUS_SUM
| MSTATUS_MXR | MSTATUS_TW | MSTATUS_TVM
| MSTATUS_TSR | MSTATUS_UXL | MSTATUS_SXL |
+ (has_fs ? MSTATUS_FS : 0) |
(ext ? MSTATUS_XS : 0);
reg_t requested_mpp = legalize_privilege(get_field(val, MSTATUS_MPP));
@@ -534,7 +566,7 @@ void processor_t::set_csr(int which, reg_t val)
break;
}
case CSR_MIP: {
- reg_t mask = MIP_SSIP | MIP_STIP;
+ reg_t mask = supervisor_ints & (MIP_SSIP | MIP_STIP);
state.mip = (state.mip & ~mask) | (val & mask);
break;
}
@@ -809,8 +841,14 @@ reg_t processor_t::get_csr(int which)
case CSR_MVENDORID: return 0;
case CSR_MHARTID: return id;
case CSR_MTVEC: return state.mtvec;
- case CSR_MEDELEG: return state.medeleg;
- case CSR_MIDELEG: return state.mideleg;
+ case CSR_MEDELEG:
+ if (!supports_extension('S'))
+ break;
+ return state.medeleg;
+ case CSR_MIDELEG:
+ if (!supports_extension('S'))
+ break;
+ return state.mideleg;
case CSR_TSELECT: return state.tselect;
case CSR_TDATA1:
if (state.tselect < state.num_triggers) {