fix mu_p platform features and CSRs

This commit is contained in:
Eyck Jentzsch 2021-05-17 09:20:09 +02:00
parent 4b3f5a6b0c
commit aaceecd5dc
4 changed files with 55 additions and 38 deletions

View File

@ -147,8 +147,6 @@ protected:
inline void leave(unsigned lvl){ inline void leave(unsigned lvl){
this->core.leave_trap(lvl); this->core.leave_trap(lvl);
auto pc_val = super::template read_mem<reg_t>(traits::CSR, (lvl << 8) + 0x41);
this->template get_reg<reg_t>(traits::NEXT_PC) = pc_val;
} }
inline void wait(unsigned type){ inline void wait(unsigned type){

View File

@ -66,7 +66,9 @@
namespace iss { namespace iss {
namespace arch { namespace arch {
template <typename BASE, bool PMP=false> class riscv_hart_mu_p : public BASE { enum features_e{FEAT_NONE, FEAT_PMP, FEAT_EXT_N};
template <typename BASE, features_e FEAT=FEAT_NONE> class riscv_hart_mu_p : public BASE {
protected: protected:
const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}}; const std::array<const char, 4> lvl = {{'U', 'S', 'H', 'M'}};
const std::array<const char *, 16> trap_str = {{"" const std::array<const char *, 16> trap_str = {{""
@ -92,7 +94,7 @@ protected:
"User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt"}}; "User external interrupt", "Supervisor external interrupt", "Reserved", "Machine external interrupt"}};
public: public:
using super = BASE; using super = BASE;
using this_class = riscv_hart_mu_p<BASE, PMP>; using this_class = riscv_hart_mu_p<BASE, FEAT>;
using phys_addr_t = typename super::phys_addr_t; using phys_addr_t = typename super::phys_addr_t;
using reg_t = typename super::reg_t; using reg_t = typename super::reg_t;
using addr_t = typename super::addr_t; using addr_t = typename super::addr_t;
@ -218,7 +220,7 @@ public:
protected: protected:
struct riscv_instrumentation_if : public iss::instrumentation_if { struct riscv_instrumentation_if : public iss::instrumentation_if {
riscv_instrumentation_if(riscv_hart_mu_p<BASE, PMP> &arch) riscv_instrumentation_if(riscv_hart_mu_p<BASE, FEAT> &arch)
: arch(arch) {} : arch(arch) {}
/** /**
* get the name of this architecture * get the name of this architecture
@ -233,7 +235,7 @@ protected:
virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; }; virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; };
riscv_hart_mu_p<BASE, PMP> &arch; riscv_hart_mu_p<BASE, FEAT> &arch;
}; };
friend struct riscv_instrumentation_if; friend struct riscv_instrumentation_if;
@ -286,8 +288,8 @@ protected:
void check_interrupt(); void check_interrupt();
}; };
template <typename BASE, bool PMP> template <typename BASE, features_e FEAT>
riscv_hart_mu_p<BASE, PMP>::riscv_hart_mu_p() riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p()
: state() : state()
, cycle_offset(0) , cycle_offset(0)
, instr_if(*this) { , instr_if(*this) {
@ -326,9 +328,26 @@ riscv_hart_mu_p<BASE, PMP>::riscv_hart_mu_p()
// read-only registers // read-only registers
csr_rd_cb[misa] = &this_class::read_reg; csr_rd_cb[misa] = &this_class::read_reg;
csr_wr_cb[misa] = nullptr; csr_wr_cb[misa] = nullptr;
if(FEAT & FEAT_PMP){
for(size_t i=pmpaddr0; i<=pmpaddr15; ++i){
csr_rd_cb[i] = &this_class::read_reg;
csr_wr_cb[i] = &this_class::write_reg;
}
for(size_t i=pmpcfg0; i<=pmpcfg3; ++i){
csr_rd_cb[i] = &this_class::read_reg;
csr_wr_cb[i] = &this_class::write_reg;
}
}
if(FEAT & FEAT_EXT_N){
csr_rd_cb[mideleg] = &this_class::read_reg;
csr_wr_cb[mideleg] = &this_class::write_reg;
csr_rd_cb[medeleg] = &this_class::read_reg;
csr_wr_cb[medeleg] = &this_class::write_reg;
}
} }
template <typename BASE, bool PMP> std::pair<uint64_t, bool> riscv_hart_mu_p<BASE, PMP>::load_file(std::string name, int type) { template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_mu_p<BASE, FEAT>::load_file(std::string name, int type) {
FILE *fp = fopen(name.c_str(), "r"); FILE *fp = fopen(name.c_str(), "r");
if (fp) { if (fp) {
std::array<char, 5> buf; std::array<char, 5> buf;
@ -372,8 +391,8 @@ template <typename BASE, bool PMP> std::pair<uint64_t, bool> riscv_hart_mu_p<BAS
throw std::runtime_error("memory load file not found"); throw std::runtime_error("memory load file not found");
} }
template <typename BASE, bool PMP> template <typename BASE, features_e FEAT>
iss::status riscv_hart_mu_p<BASE, PMP>::read(const address_type type, const access_type access, const uint32_t space, iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const access_type access, const uint32_t space,
const uint64_t addr, const unsigned length, uint8_t *const data) { const uint64_t addr, const unsigned length, uint8_t *const data) {
#ifndef NDEBUG #ifndef NDEBUG
if (access && iss::access_type::DEBUG) { if (access && iss::access_type::DEBUG) {
@ -430,8 +449,8 @@ iss::status riscv_hart_mu_p<BASE, PMP>::read(const address_type type, const acce
} }
} }
template <typename BASE, bool PMP> template <typename BASE, features_e FEAT>
iss::status riscv_hart_mu_p<BASE, PMP>::write(const address_type type, const access_type access, const uint32_t space, iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const access_type access, const uint32_t space,
const uint64_t addr, const unsigned length, const uint8_t *const data) { const uint64_t addr, const unsigned length, const uint8_t *const data) {
#ifndef NDEBUG #ifndef NDEBUG
const char *prefix = (access && iss::access_type::DEBUG) ? "debug " : ""; const char *prefix = (access && iss::access_type::DEBUG) ? "debug " : "";
@ -537,7 +556,7 @@ iss::status riscv_hart_mu_p<BASE, PMP>::write(const address_type type, const acc
} }
} }
template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_csr(unsigned addr, reg_t &val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_csr(unsigned addr, reg_t &val) {
if (addr >= csr.size()) return iss::Err; if (addr >= csr.size()) return iss::Err;
auto req_priv_lvl = (addr >> 8) & 0x3; auto req_priv_lvl = (addr >> 8) & 0x3;
if (this->reg.PRIV < req_priv_lvl) // not having required privileges if (this->reg.PRIV < req_priv_lvl) // not having required privileges
@ -548,7 +567,7 @@ template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_
return (this->*(it->second))(addr, val); return (this->*(it->second))(addr, val);
} }
template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::write_csr(unsigned addr, reg_t val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_csr(unsigned addr, reg_t val) {
if (addr >= csr.size()) return iss::Err; if (addr >= csr.size()) return iss::Err;
auto req_priv_lvl = (addr >> 8) & 0x3; auto req_priv_lvl = (addr >> 8) & 0x3;
if (this->reg.PRIV < req_priv_lvl) // not having required privileges if (this->reg.PRIV < req_priv_lvl) // not having required privileges
@ -561,17 +580,17 @@ template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::write
return (this->*(it->second))(addr, val); return (this->*(it->second))(addr, val);
} }
template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_reg(unsigned addr, reg_t &val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_reg(unsigned addr, reg_t &val) {
val = csr[addr]; val = csr[addr];
return iss::Ok; return iss::Ok;
} }
template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::write_reg(unsigned addr, reg_t val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_reg(unsigned addr, reg_t val) {
csr[addr] = val; csr[addr] = val;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_cycle(unsigned addr, reg_t &val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_cycle(unsigned addr, reg_t &val) {
auto cycle_val = this->reg.icount + cycle_offset; auto cycle_val = this->reg.icount + cycle_offset;
if (addr == mcycle) { if (addr == mcycle) {
val = static_cast<reg_t>(cycle_val); val = static_cast<reg_t>(cycle_val);
@ -582,7 +601,7 @@ template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_
return iss::Ok; return iss::Ok;
} }
template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_time(unsigned addr, reg_t &val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_time(unsigned addr, reg_t &val) {
uint64_t time_val = (this->reg.icount + cycle_offset) / (100000000 / 32768 - 1); //-> ~3052; uint64_t time_val = (this->reg.icount + cycle_offset) / (100000000 / 32768 - 1); //-> ~3052;
if (addr == time) { if (addr == time) {
val = static_cast<reg_t>(time_val); val = static_cast<reg_t>(time_val);
@ -593,31 +612,31 @@ template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_
return iss::Ok; return iss::Ok;
} }
template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_status(unsigned addr, reg_t &val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_status(unsigned addr, reg_t &val) {
auto req_priv_lvl = (addr >> 8) & 0x3; auto req_priv_lvl = (addr >> 8) & 0x3;
val = state.mstatus & hart_state_type::get_mask(req_priv_lvl); val = state.mstatus & hart_state_type::get_mask(req_priv_lvl);
return iss::Ok; return iss::Ok;
} }
template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::write_status(unsigned addr, reg_t val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_status(unsigned addr, reg_t val) {
auto req_priv_lvl = (addr >> 8) & 0x3; auto req_priv_lvl = (addr >> 8) & 0x3;
state.write_mstatus(val, req_priv_lvl); state.write_mstatus(val, req_priv_lvl);
check_interrupt(); check_interrupt();
return iss::Ok; return iss::Ok;
} }
template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_ie(unsigned addr, reg_t &val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_ie(unsigned addr, reg_t &val) {
val = csr[mie]; val = csr[mie];
val &= csr[mideleg]; val &= csr[mideleg];
return iss::Ok; return iss::Ok;
} }
template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_hartid(unsigned addr, reg_t &val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_hartid(unsigned addr, reg_t &val) {
val = mhartid_reg; val = mhartid_reg;
return iss::Ok; return iss::Ok;
} }
template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::write_ie(unsigned addr, reg_t val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_ie(unsigned addr, reg_t val) {
auto req_priv_lvl = (addr >> 8) & 0x3; auto req_priv_lvl = (addr >> 8) & 0x3;
auto mask = get_irq_mask(req_priv_lvl); auto mask = get_irq_mask(req_priv_lvl);
csr[mie] = (csr[mie] & ~mask) | (val & mask); csr[mie] = (csr[mie] & ~mask) | (val & mask);
@ -625,13 +644,13 @@ template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::write
return iss::Ok; return iss::Ok;
} }
template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::read_ip(unsigned addr, reg_t &val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::read_ip(unsigned addr, reg_t &val) {
val = csr[mip]; val = csr[mip];
val &= csr[mideleg]; val &= csr[mideleg];
return iss::Ok; return iss::Ok;
} }
template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::write_ip(unsigned addr, reg_t val) { template <typename BASE, features_e FEAT> iss::status riscv_hart_mu_p<BASE, FEAT>::write_ip(unsigned addr, reg_t val) {
auto req_priv_lvl = (addr >> 8) & 0x3; auto req_priv_lvl = (addr >> 8) & 0x3;
auto mask = get_irq_mask(req_priv_lvl); auto mask = get_irq_mask(req_priv_lvl);
mask &= ~(1 << 7); // MTIP is read only mask &= ~(1 << 7); // MTIP is read only
@ -640,8 +659,8 @@ template <typename BASE, bool PMP> iss::status riscv_hart_mu_p<BASE, PMP>::write
return iss::Ok; return iss::Ok;
} }
template <typename BASE, bool PMP> template <typename BASE, features_e FEAT>
iss::status riscv_hart_mu_p<BASE, PMP>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) { iss::status riscv_hart_mu_p<BASE, FEAT>::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
if ((paddr.val + length) > mem.size()) return iss::Err; if ((paddr.val + length) > mem.size()) return iss::Err;
if(mem_read_cb) return mem_read_cb(paddr, length, data); if(mem_read_cb) return mem_read_cb(paddr, length, data);
switch (paddr.val) { switch (paddr.val) {
@ -666,8 +685,8 @@ iss::status riscv_hart_mu_p<BASE, PMP>::read_mem(phys_addr_t paddr, unsigned len
return iss::Ok; return iss::Ok;
} }
template <typename BASE, bool PMP> template <typename BASE, features_e FEAT>
iss::status riscv_hart_mu_p<BASE, PMP>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) { iss::status riscv_hart_mu_p<BASE, FEAT>::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
if ((paddr.val + length) > mem.size()) return iss::Err; if ((paddr.val + length) > mem.size()) return iss::Err;
if(mem_write_cb) return mem_write_cb(paddr, length, data); if(mem_write_cb) return mem_write_cb(paddr, length, data);
switch (paddr.val) { switch (paddr.val) {
@ -743,12 +762,12 @@ iss::status riscv_hart_mu_p<BASE, PMP>::write_mem(phys_addr_t paddr, unsigned le
return iss::Ok; return iss::Ok;
} }
template <typename BASE, bool PMP> inline void riscv_hart_mu_p<BASE, PMP>::reset(uint64_t address) { template <typename BASE, features_e FEAT> inline void riscv_hart_mu_p<BASE, FEAT>::reset(uint64_t address) {
BASE::reset(address); BASE::reset(address);
state.mstatus = hart_state_type::mstatus_reset_val; state.mstatus = hart_state_type::mstatus_reset_val;
} }
template <typename BASE, bool PMP> void riscv_hart_mu_p<BASE, PMP>::check_interrupt() { template <typename BASE, features_e FEAT> void riscv_hart_mu_p<BASE, FEAT>::check_interrupt() {
auto ideleg = csr[mideleg]; auto ideleg = csr[mideleg];
// Multiple simultaneous interrupts and traps at the same privilege level are // Multiple simultaneous interrupts and traps at the same privilege level are
// handled in the following decreasing priority order: // handled in the following decreasing priority order:
@ -770,7 +789,7 @@ template <typename BASE, bool PMP> void riscv_hart_mu_p<BASE, PMP>::check_interr
} }
} }
template <typename BASE, bool PMP> uint64_t riscv_hart_mu_p<BASE, PMP>::enter_trap(uint64_t flags, uint64_t addr) { template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::enter_trap(uint64_t flags, uint64_t addr) {
// flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0] // flags are ACTIVE[31:31], CAUSE[30:16], TRAPID[15:0]
// calculate and write mcause val // calculate and write mcause val
auto trap_id = bit_sub<0, 16>(flags); auto trap_id = bit_sub<0, 16>(flags);
@ -840,10 +859,10 @@ template <typename BASE, bool PMP> uint64_t riscv_hart_mu_p<BASE, PMP>::enter_tr
return this->reg.NEXT_PC; return this->reg.NEXT_PC;
} }
template <typename BASE, bool PMP> uint64_t riscv_hart_mu_p<BASE, PMP>::leave_trap(uint64_t flags) { template <typename BASE, features_e FEAT> uint64_t riscv_hart_mu_p<BASE, FEAT>::leave_trap(uint64_t flags) {
auto cur_priv = this->reg.PRIV;
auto inst_priv = (flags & 0x3)? 3:0; auto inst_priv = (flags & 0x3)? 3:0;
auto status = state.mstatus; auto status = state.mstatus;
// pop the relevant lower-privilege interrupt enable and privilege mode stack // pop the relevant lower-privilege interrupt enable and privilege mode stack
// clear respective yIE // clear respective yIE
switch (inst_priv) { switch (inst_priv) {
@ -859,7 +878,7 @@ template <typename BASE, bool PMP> uint64_t riscv_hart_mu_p<BASE, PMP>::leave_tr
} }
// sets the pc to the value stored in the x epc register. // sets the pc to the value stored in the x epc register.
this->reg.NEXT_PC = csr[uepc | inst_priv << 8]; this->reg.NEXT_PC = csr[uepc | inst_priv << 8];
CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << lvl[this->reg.PRIV] << " to " CLOG(INFO, disass) << "Executing xRET , changing privilege level from " << lvl[cur_priv] << " to "
<< lvl[this->reg.PRIV]; << lvl[this->reg.PRIV];
return this->reg.NEXT_PC; return this->reg.NEXT_PC;
} }

View File

@ -47,7 +47,7 @@ using tgc_b_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_b>;
#ifdef CORE_TGC_D #ifdef CORE_TGC_D
#include "iss/arch/riscv_hart_mu_p.h" #include "iss/arch/riscv_hart_mu_p.h"
#include "iss/arch/tgc_d.h" #include "iss/arch/tgc_d.h"
using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d>; using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, iss::arch::FEAT_PMP>;
#endif #endif
#ifdef WITH_LLVM #ifdef WITH_LLVM
#include <iss/llvm/jit_helper.h> #include <iss/llvm/jit_helper.h>

View File

@ -44,7 +44,7 @@ using tgc_c_plat_type = iss::arch::riscv_hart_m_p<iss::arch::tgc_c>;
#ifdef CORE_TGC_D #ifdef CORE_TGC_D
#include "iss/arch/riscv_hart_mu_p.h" #include "iss/arch/riscv_hart_mu_p.h"
#include "iss/arch/tgc_d.h" #include "iss/arch/tgc_d.h"
using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d>; using tgc_d_plat_type = iss::arch::riscv_hart_mu_p<iss::arch::tgc_d, iss::arch::FEAT_PMP>;
#endif #endif
#include "iss/debugger/encoderdecoder.h" #include "iss/debugger/encoderdecoder.h"
#include "iss/debugger/gdb_session.h" #include "iss/debugger/gdb_session.h"