Browse Source

Merge pull request #593 from chihminchao/selective-mmu-mode

Selective mmu mode
pull/594/head
Andrew Waterman 6 years ago
committed by GitHub
parent
commit
9380375e22
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      riscv/decode.h
  2. 38
      riscv/dts.cc
  3. 5
      riscv/dts.h
  4. 1
      riscv/insns/sfence_vma.h
  5. 117
      riscv/processor.cc
  6. 15
      riscv/processor.h
  7. 48
      riscv/sim.cc

1
riscv/decode.h

@ -236,6 +236,7 @@ private:
#define require_rv64 require(xlen == 64)
#define require_rv32 require(xlen == 32)
#define require_extension(s) require(p->supports_extension(s))
#define require_impl(s) require(p->supports_impl(s))
#define require_fp require((STATE.mstatus & MSTATUS_FS) != 0)
#define require_accelerator require((STATE.mstatus & MSTATUS_XS) != 0)

38
riscv/dts.cc

@ -225,6 +225,21 @@ static int fdt_get_node_addr_size(void *fdt, int node, reg_t *addr,
return 0;
}
int fdt_get_offset(void *fdt, const char *field)
{
return fdt_path_offset(fdt, field);
}
int fdt_get_first_subnode(void *fdt, int node)
{
return fdt_first_subnode(fdt, node);
}
int fdt_get_next_subnode(void *fdt, int node)
{
return fdt_next_subnode(fdt, node);
}
int fdt_parse_clint(void *fdt, reg_t *clint_addr,
const char *compatible)
{
@ -273,3 +288,26 @@ int fdt_parse_pmp_alignment(void *fdt, reg_t *pmp_align,
return 0;
}
int fdt_parse_mmu_type(void *fdt, int cpu_offset, char *mmu_type)
{
int len;
const void *prop;
if (!fdt || cpu_offset < 0)
return -EINVAL;
prop = fdt_getprop(fdt, cpu_offset, "device_type", &len);
if (!prop || !len)
return -EINVAL;
if (strncmp ((char *)prop, "cpu", strlen ("cpu")))
return -EINVAL;
prop = fdt_getprop(fdt, cpu_offset, "mmu-type", &len);
if (!prop || !len)
return -EINVAL;
strcpy(mmu_type, (char *)prop);
return 0;
}

5
riscv/dts.h

@ -14,10 +14,15 @@ std::string make_dts(size_t insns_per_rtc_tick, size_t cpu_hz,
std::string dts_compile(const std::string& dts);
int fdt_get_offset(void *fdt, const char *field);
int fdt_get_first_subnode(void *fdt, int node);
int fdt_get_next_subnode(void *fdt, int node);
int fdt_parse_clint(void *fdt, reg_t *clint_addr,
const char *compatible);
int fdt_parse_pmp_num(void *fdt, reg_t *pmp_num,
const char *compatible);
int fdt_parse_pmp_alignment(void *fdt, reg_t *pmp_align,
const char *compatible);
int fdt_parse_mmu_type(void *fdt, int cpu_offset, char *mmu_type);
#endif

1
riscv/insns/sfence_vma.h

@ -1,4 +1,5 @@
require_extension('S');
require_impl(IMPL_MMU);
if (STATE.v) {
if (STATE.prv == PRV_U || get_field(STATE.hstatus, HSTATUS_VTVM))
require_novirt();

117
riscv/processor.cc

@ -27,7 +27,7 @@ processor_t::processor_t(const char* isa, const char* priv, const char* varch,
: debug(false), halt_request(HR_NONE), sim(sim), ext(NULL), id(id), xlen(0),
histogram_enabled(false), log_commits_enabled(false),
log_file(log_file), halt_on_reset(halt_on_reset),
extension_table(256, false), last_pc(1), executions(1)
extension_table(256, false), impl_table(256, false), last_pc(1), executions(1)
{
VU.p = this;
@ -45,6 +45,12 @@ processor_t::processor_t(const char* isa, const char* priv, const char* varch,
set_pmp_granularity(1 << PMP_SHIFT);
set_pmp_num(state.max_pmp);
if (max_xlen == 32)
set_mmu_capability(IMPL_MMU_SV32);
else if (max_xlen == 64)
set_mmu_capability(IMPL_MMU_SV48);
reset();
}
@ -502,6 +508,31 @@ void processor_t::set_pmp_granularity(reg_t gran) {
lg_pmp_granularity = ctz(gran);
}
void processor_t::set_mmu_capability(int cap)
{
switch (cap) {
case IMPL_MMU_SV32:
set_impl(cap, true);
set_impl(IMPL_MMU, true);
break;
case IMPL_MMU_SV39:
set_impl(cap, true);
set_impl(IMPL_MMU, true);
break;
case IMPL_MMU_SV48:
set_impl(cap, true);
set_impl(IMPL_MMU_SV39, true);
set_impl(IMPL_MMU, true);
break;
default:
set_impl(IMPL_MMU_SV32, false);
set_impl(IMPL_MMU_SV39, false);
set_impl(IMPL_MMU_SV48, false);
set_impl(IMPL_MMU, false);
break;
}
}
void processor_t::take_interrupt(reg_t pending_interrupts)
{
reg_t enabled_interrupts, deleg, status, mie, m_enabled;
@ -774,6 +805,39 @@ int processor_t::paddr_bits()
return max_xlen == 64 ? 50 : 34;
}
reg_t processor_t::cal_satp(reg_t val) const
{
reg_t reg_val = 0;
reg_t rv64_ppn_mask = (reg_t(1) << (MAX_PADDR_BITS - PGSHIFT)) - 1;
mmu->flush_tlb();
if (max_xlen == 32) {
reg_val = val & (SATP32_PPN |
(supports_impl(IMPL_MMU_SV32) ? SATP32_MODE : 0));
}
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)) {
reg_val = val & (SATP64_PPN | rv64_ppn_mask);
reg_t mode = get_field(val, SATP64_MODE);
switch(mode) {
case SATP_MODE_OFF:
default:
mode = SATP_MODE_OFF;
break;
case SATP_MODE_SV39:
mode = supports_impl(IMPL_MMU_SV39) ? SATP_MODE_SV39 : SATP_MODE_OFF;
break;
case SATP_MODE_SV48:
mode = supports_impl(IMPL_MMU_SV48) ? SATP_MODE_SV48 : SATP_MODE_OFF;
break;
}
reg_val = set_field(reg_val, SATP64_MODE, mode);
}
return reg_val;
}
void processor_t::set_csr(int which, reg_t val)
{
#if defined(RISCV_ENABLE_COMMITLOG)
@ -847,8 +911,11 @@ void processor_t::set_csr(int which, reg_t val)
VU.vxrm = (val & VCSR_VXRM) >> VCSR_VXRM_SHIFT;
break;
case CSR_MSTATUS: {
bool has_page = supports_extension('S') && supports_impl(IMPL_MMU);
if ((val ^ state.mstatus) &
(MSTATUS_MPP | MSTATUS_MPRV | MSTATUS_SUM | MSTATUS_MXR))
(MSTATUS_MPP | MSTATUS_MPRV
| (has_page ? (MSTATUS_MXR | MSTATUS_SUM) : 0)
| MSTATUS_MXR))
mmu->flush_tlb();
bool has_fs = supports_extension('S') || supports_extension('F')
@ -858,8 +925,9 @@ void processor_t::set_csr(int which, reg_t val)
bool has_gva = has_mpv;
reg_t mask = MSTATUS_MIE | MSTATUS_MPIE | MSTATUS_MPRV
| (supports_extension('S') ? (MSTATUS_SUM | MSTATUS_SIE | MSTATUS_SPIE) : 0)
| MSTATUS_MXR | MSTATUS_TW | MSTATUS_TVM | MSTATUS_TSR
| (supports_extension('S') ? (MSTATUS_SIE | MSTATUS_SPIE) : 0)
| MSTATUS_TW | MSTATUS_TSR
| (has_page ? (MSTATUS_MXR | MSTATUS_SUM | MSTATUS_TVM) : 0)
| (has_fs ? MSTATUS_FS : 0)
| (has_vs ? MSTATUS_VS : 0)
| (ext ? MSTATUS_XS : 0)
@ -970,22 +1038,15 @@ void processor_t::set_csr(int which, reg_t val)
state.mie = (state.mie & ~mask) | (val & mask);
break;
}
case CSR_SATP: {
reg_t reg_val = 0;
reg_t rv64_ppn_mask = (reg_t(1) << (MAX_PADDR_BITS - PGSHIFT)) - 1;
mmu->flush_tlb();
if (max_xlen == 32)
reg_val = 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))
reg_val = val & (SATP64_MODE | (SATP64_PPN & rv64_ppn_mask));
case CSR_SATP:
if (!supports_impl(IMPL_MMU))
val = 0;
if (state.v)
state.vsatp = reg_val;
state.vsatp = cal_satp(val);
else
state.satp = reg_val;
state.satp = cal_satp(val);
break;
}
case CSR_SEPC:
if (state.v)
state.vsepc = val & ~(reg_t)1;
@ -1052,8 +1113,9 @@ void processor_t::set_csr(int which, reg_t val)
break;
}
case CSR_HSTATUS: {
reg_t mask = HSTATUS_VTSR | HSTATUS_VTW | HSTATUS_VTVM |
HSTATUS_HU | HSTATUS_SPVP | HSTATUS_SPV | HSTATUS_GVA;
reg_t mask = HSTATUS_VTSR | HSTATUS_VTW
| (supports_impl(IMPL_MMU) ? HSTATUS_VTVM : 0)
| HSTATUS_HU | HSTATUS_SPVP | HSTATUS_SPV | HSTATUS_GVA;
state.hstatus = (state.hstatus & ~mask) | (val & mask);
break;
}
@ -1140,19 +1202,12 @@ void processor_t::set_csr(int which, reg_t val)
state.mip = (state.mip & ~mask) | ((val << 1) & mask);
break;
}
case CSR_VSATP: {
reg_t reg_val = 0;
reg_t rv64_ppn_mask = (reg_t(1) << (MAX_PADDR_BITS - PGSHIFT)) - 1;
mmu->flush_tlb();
if (max_xlen == 32)
reg_val = 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))
reg_val = val & (SATP64_MODE | (SATP64_PPN & rv64_ppn_mask));
state.vsatp = reg_val;
case CSR_VSATP:
if (!supports_impl(IMPL_MMU))
val = 0;
state.vsatp = cal_satp(val);
break;
}
case CSR_TSELECT:
if (val < state.num_triggers) {
state.tselect = val;

15
riscv/processor.h

@ -245,6 +245,14 @@ typedef enum {
EXT_ZVEDIV,
} isa_extension_t;
typedef enum {
IMPL_MMU_SV32,
IMPL_MMU_SV39,
IMPL_MMU_SV48,
IMPL_MMU_BARE,
IMPL_MMU,
} impl_extension_t;
// Count number of contiguous 1 bits starting from the LSB.
static int cto(reg_t val)
{
@ -292,6 +300,10 @@ public:
else
return extension_table[ext];
}
void set_impl(uint8_t impl, bool val) { impl_table[impl] = val; }
bool supports_impl(uint8_t impl) const {
return impl_table[impl];
}
reg_t pc_alignment_mask() {
return ~(reg_t)(supports_extension('C') ? 0 : 2);
}
@ -409,6 +421,7 @@ public:
void set_pmp_num(reg_t pmp_num);
void set_pmp_granularity(reg_t pmp_granularity);
void set_mmu_capability(int cap);
const char* get_symbol(uint64_t addr);
@ -428,6 +441,7 @@ private:
FILE *log_file;
bool halt_on_reset;
std::vector<bool> extension_table;
std::vector<bool> impl_table;
std::vector<insn_desc_t> instructions;
@ -456,6 +470,7 @@ private:
void build_opcode_map();
void register_base_instructions();
insn_func_t decode_insn(insn_t insn);
reg_t cal_satp(reg_t val) const;
// Track repeated executions for processor_t::disasm()
uint64_t last_pc, last_bits, executions;

48
riscv/sim.cc

@ -83,6 +83,7 @@ sim_t::sim_t(const char* isa, const char* priv, const char* varch,
make_dtb();
//handle clic
clint.reset(new clint_t(procs, CPU_HZ / INSNS_PER_RTC_TICK, real_time_clint));
reg_t clint_base;
if (fdt_parse_clint((void *)dtb.c_str(), &clint_base, "riscv,clint0")) {
@ -91,6 +92,7 @@ sim_t::sim_t(const char* isa, const char* priv, const char* varch,
bus.add_device(clint_base, clint.get());
}
//handle pmp
for (size_t i = 0; i < nprocs; i++) {
reg_t pmp_num = 0, pmp_granularity = 0;
fdt_parse_pmp_num((void *)dtb.c_str(), &pmp_num, "riscv");
@ -99,6 +101,52 @@ sim_t::sim_t(const char* isa, const char* priv, const char* varch,
procs[i]->set_pmp_num(pmp_num);
procs[i]->set_pmp_granularity(pmp_granularity);
}
void *fdt = (void *)dtb.c_str();
int cpu_offset = 0, rc;
size_t cpu_idx = 0;
cpu_offset = fdt_get_offset(fdt, "/cpus");
if (cpu_offset < 0)
return;
for (cpu_offset = fdt_get_first_subnode(fdt, cpu_offset); cpu_offset >= 0;
cpu_offset = fdt_get_next_subnode(fdt, cpu_offset)) {
if (cpu_idx >= nprocs)
break;
//handle mmu-type
char mmu_type[256] = "";
rc = fdt_parse_mmu_type(fdt, cpu_offset, mmu_type);
if (rc == 0) {
procs[cpu_idx]->set_mmu_capability(IMPL_MMU_BARE);
if (strncmp(mmu_type, "riscv,sv32", strlen("riscv,sv32")) == 0) {
procs[cpu_idx]->set_mmu_capability(IMPL_MMU_SV32);
} else if (strncmp(mmu_type, "riscv,sv39", strlen("riscv,sv39")) == 0) {
procs[cpu_idx]->set_mmu_capability(IMPL_MMU_SV39);
} else if (strncmp(mmu_type, "riscv,sv48", strlen("riscv,sv48")) == 0) {
procs[cpu_idx]->set_mmu_capability(IMPL_MMU_SV48);
} else if (strncmp(mmu_type, "riscv,bare", strlen("riscv,bare")) == 0) {
//has been set in the beginning
} else {
std::cerr << "core ("
<< hartids.size()
<< ") doesn't have valid 'mmu-type'"
<< mmu_type << ").\n";
exit(1);
}
}
cpu_idx++;
}
if (cpu_idx != nprocs) {
std::cerr << "core number in dts ("
<< cpu_idx
<< ") doesn't match it in command line ("
<< nprocs << ").\n";
exit(1);
}
}
sim_t::~sim_t()

Loading…
Cancel
Save