diff --git a/incl/iss/arch/riscv_hart_m_p.h b/incl/iss/arch/riscv_hart_m_p.h
index 699f341..b02f999 100644
--- a/incl/iss/arch/riscv_hart_m_p.h
+++ b/incl/iss/arch/riscv_hart_m_p.h
@@ -176,6 +176,10 @@ public:
return 0b100010001000; // only machine mode is supported
}
+ constexpr reg_t get_pc_mask() {
+ return traits::MISA_VAL&0b0100?~1:~3;
+ }
+
riscv_hart_m_p();
virtual ~riscv_hart_m_p() = default;
@@ -285,6 +289,7 @@ private:
iss::status read_ip(unsigned addr, reg_t &val);
iss::status write_ip(unsigned addr, reg_t val);
iss::status read_hartid(unsigned addr, reg_t &val);
+ iss::status write_mepc(unsigned addr, reg_t val);
reg_t mhartid_reg{0x0};
std::functionmem_read_cb;
@@ -317,13 +322,12 @@ riscv_hart_m_p::riscv_hart_m_p()
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
- for (unsigned addr = cycle; addr <= hpmcounter31; ++addr){
+ for (unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
- csr_wr_cb[addr] = &this_class::write_reg;
}
- for (unsigned addr = cycleh; addr <= hpmcounter31h; ++addr){
+ for (unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
- csr_wr_cb[addr] = &this_class::write_reg;
+ //csr_wr_cb[addr] = &this_class::write_reg;
}
// common regs
const std::array addrs{{misa, mvendorid, marchid, mimpid, mepc, mtvec, mscratch, mcause, mtval, mscratch}};
@@ -333,9 +337,12 @@ riscv_hart_m_p::riscv_hart_m_p()
}
// special handling & overrides
csr_rd_cb[time] = &this_class::read_time;
- csr_wr_cb[time] = nullptr;
csr_rd_cb[timeh] = &this_class::read_time;
- csr_wr_cb[timeh] = nullptr;
+ csr_rd_cb[cycle] = &this_class::read_cycle;
+ csr_rd_cb[cycleh] = &this_class::read_cycle;
+ csr_rd_cb[instret] = &this_class::read_instret;
+ csr_rd_cb[instreth] = &this_class::read_instret;
+
csr_rd_cb[mcycle] = &this_class::read_cycle;
csr_wr_cb[mcycle] = &this_class::write_cycle;
csr_rd_cb[mcycleh] = &this_class::read_cycle;
@@ -354,6 +361,7 @@ riscv_hart_m_p::riscv_hart_m_p()
csr_rd_cb[mcounteren] = &this_class::read_null;
csr_wr_cb[mcounteren] = &this_class::write_null;
csr_rd_cb[mtvec] = &this_class::read_mtvec;
+ csr_wr_cb[mepc] = &this_class::write_mepc;
csr_wr_cb[misa] = &this_class::write_null;
csr_wr_cb[mvendorid] = &this_class::write_null;
csr_wr_cb[marchid] = &this_class::write_null;
@@ -656,9 +664,9 @@ template iss::status riscv_hart_m_p::write_cycle(unsigned
}
template iss::status riscv_hart_m_p::read_instret(unsigned addr, reg_t &val) {
- if (addr == minstret) {
+ if ((addr&0xff) == (minstret&0xff)) {
val = static_cast(this->reg.instret);
- } else if (addr == minstreth) {
+ } else if ((addr&0xff) == (minstreth&0xff)) {
if (sizeof(typename traits::reg_t) != 4) return iss::Err;
val = static_cast(this->reg.instret >> 32);
}
@@ -667,11 +675,11 @@ template iss::status riscv_hart_m_p::read_instret(unsigned
template iss::status riscv_hart_m_p::write_instret(unsigned addr, reg_t val) {
if (sizeof(typename traits::reg_t) != 4) {
- if (addr == minstreth)
+ if ((addr&0xff) == (minstreth&0xff))
return iss::Err;
this->reg.instret = static_cast(val);
} else {
- if (addr == minstret) {
+ if ((addr&0xff) == (minstret&0xff)) {
this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val;
} else {
this->reg.instret = (static_cast(val)<<32) + (this->reg.instret & 0xffffffff);
@@ -710,7 +718,6 @@ template iss::status riscv_hart_m_p::write_status(unsigned
template iss::status riscv_hart_m_p::read_ie(unsigned addr, reg_t &val) {
val = csr[mie];
- //val &= csr[mideleg];
return iss::Ok;
}
@@ -728,7 +735,6 @@ template iss::status riscv_hart_m_p::write_ie(unsigned add
template iss::status riscv_hart_m_p::read_ip(unsigned addr, reg_t &val) {
val = csr[mip];
- //val &= csr[mideleg];
return iss::Ok;
}
@@ -740,6 +746,12 @@ template iss::status riscv_hart_m_p::write_ip(unsigned add
return iss::Ok;
}
+template iss::status riscv_hart_m_p::write_mepc(unsigned addr, reg_t val) {
+ auto mask = get_pc_mask();
+ csr[addr] = val;//(csr[addr] & ~mask) | (val & mask);
+ return iss::Ok;
+}
+
template
iss::status riscv_hart_m_p::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
if(mem_read_cb) return mem_read_cb(paddr, length, data);
@@ -798,9 +810,10 @@ iss::status riscv_hart_m_p::write_mem(phys_addr_t paddr, unsigned length,
std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask));
// tohost handling in case of riscv-test
if (paddr.access && iss::access_type::FUNC) {
- auto tohost_upper = (traits::XLEN == 32 && paddr.val == (tohost + 4));
+ auto tohost_upper = (traits::XLEN == 32 && paddr.val == (tohost + 4)) ||
+ (traits::XLEN == 64 && paddr.val == tohost);
auto tohost_lower =
- (traits::XLEN == 32 && paddr.val == tohost);
+ (traits::XLEN == 32 && paddr.val == tohost) || (traits::XLEN == 64 && paddr.val == tohost);
if (tohost_lower || tohost_upper) {
uint64_t hostvar = *reinterpret_cast(p.data() + (tohost & mem.page_addr_mask));
if (tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) {
@@ -831,7 +844,8 @@ iss::status riscv_hart_m_p::write_mem(phys_addr_t paddr, unsigned length,
}
} else if (tohost_lower)
to_host_wr_cnt++;
- } else if (traits::XLEN == 32 && paddr.val == fromhost + 4) {
+ } else if ((traits::XLEN == 32 && paddr.val == fromhost + 4) ||
+ (traits::XLEN == 64 && paddr.val == fromhost)) {
uint64_t fhostvar = *reinterpret_cast(p.data() + (fromhost & mem.page_addr_mask));
*reinterpret_cast(p.data() + (tohost & mem.page_addr_mask)) = fhostvar;
}
@@ -856,7 +870,7 @@ template void riscv_hart_m_p::check_interrupt() {
bool mie = state.mstatus.MIE;
auto m_enabled = this->reg.PRIV < PRIV_M || (this->reg.PRIV == PRIV_M && mie);
- auto enabled_interrupts = m_enabled ? ena_irq /*& ~ideleg*/ : 0;
+ auto enabled_interrupts = m_enabled ? ena_irq : 0;
if (enabled_interrupts != 0) {
int res = 0;
@@ -918,7 +932,7 @@ template uint64_t riscv_hart_m_p::leave_trap(uint64_t flag
state.mstatus.MIE = state.mstatus.MPIE;
state.mstatus.MPIE = 1;
// sets the pc to the value stored in the x epc register.
- this->reg.NEXT_PC = csr[mepc];
+ this->reg.NEXT_PC = csr[mepc] & get_pc_mask();
CLOG(INFO, disass) << "Executing xRET";
check_interrupt();
return this->reg.NEXT_PC;
diff --git a/incl/iss/arch/riscv_hart_msu_vp.h b/incl/iss/arch/riscv_hart_msu_vp.h
index d9cb528..f43d0e0 100644
--- a/incl/iss/arch/riscv_hart_msu_vp.h
+++ b/incl/iss/arch/riscv_hart_msu_vp.h
@@ -356,7 +356,10 @@ protected:
virtual iss::status write_csr(unsigned addr, reg_t val);
hart_state_type state;
- uint64_t cycle_offset;
+ int64_t cycle_offset{0};
+ uint64_t mcycle_csr{0};
+ int64_t instret_offset{0};
+ uint64_t minstret_csr{0};
reg_t fault_data;
std::array vm;
uint64_t tohost = tohost_dflt;
@@ -377,10 +380,15 @@ protected:
std::unordered_map csr_wr_cb;
private:
- iss::status read_null(unsigned addr, reg_t &val);
iss::status read_reg(unsigned addr, reg_t &val);
iss::status write_reg(unsigned addr, reg_t val);
+ iss::status read_null(unsigned addr, reg_t &val);
+ iss::status write_null(unsigned addr, reg_t val){return iss::status::Ok;}
iss::status read_cycle(unsigned addr, reg_t &val);
+ iss::status write_cycle(unsigned addr, reg_t val);
+ iss::status read_instret(unsigned addr, reg_t &val);
+ iss::status write_instret(unsigned addr, reg_t val);
+ iss::status read_mtvec(unsigned addr, reg_t &val);
iss::status read_time(unsigned addr, reg_t &val);
iss::status read_status(unsigned addr, reg_t &val);
iss::status write_status(unsigned addr, reg_t val);
@@ -389,6 +397,7 @@ private:
iss::status read_ip(unsigned addr, reg_t &val);
iss::status write_ip(unsigned addr, reg_t val);
iss::status read_hartid(unsigned addr, reg_t &val);
+ iss::status write_mepc(unsigned addr, reg_t val);
iss::status read_satp(unsigned addr, reg_t &val);
iss::status write_satp(unsigned addr, reg_t val);
iss::status read_fcsr(unsigned addr, reg_t &val);
@@ -405,15 +414,19 @@ protected:
template
riscv_hart_msu_vp::riscv_hart_msu_vp()
: state()
-, cycle_offset(0)
, instr_if(*this) {
- csr[misa] = hart_state_type::get_misa();
+ // reset values
+ csr[misa] = traits::MISA_VAL;
+ csr[mvendorid] = 0x669;
+ csr[marchid] = 0x80000003;
+ csr[mimpid] = 1;
+
uart_buf.str("");
- for (unsigned addr = mcycle; addr <= mhpmcounter31; ++addr){
+ for (unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
- for (unsigned addr = mcycleh; addr <= mhpmcounter31h; ++addr){
+ for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
@@ -421,23 +434,35 @@ riscv_hart_msu_vp::riscv_hart_msu_vp()
csr_rd_cb[addr] = &this_class::read_null;
csr_wr_cb[addr] = &this_class::write_reg;
}
- for (unsigned addr = cycle; addr <= hpmcounter31; ++addr){
+ for (unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
- csr_wr_cb[addr] = &this_class::write_reg;
}
for (unsigned addr = cycleh; addr <= hpmcounter31h; ++addr){
csr_rd_cb[addr] = &this_class::read_null;
+ //csr_wr_cb[addr] = &this_class::write_reg;
+ }
+ // common regs
+ const std::array addrs{{misa, mvendorid, marchid, mimpid, mepc, mtvec, mscratch, mcause, mtval, mscratch}};
+ for(auto addr: addrs) {
+ csr_rd_cb[addr] = &this_class::read_reg;
csr_wr_cb[addr] = &this_class::write_reg;
}
- // special handling
+ // special handling & overrides
csr_rd_cb[time] = &this_class::read_time;
- csr_wr_cb[time] = nullptr;
csr_rd_cb[timeh] = &this_class::read_time;
- csr_wr_cb[timeh] = nullptr;
+ csr_rd_cb[cycle] = &this_class::read_cycle;
+ csr_rd_cb[cycleh] = &this_class::read_cycle;
+ csr_rd_cb[instret] = &this_class::read_instret;
+ csr_rd_cb[instreth] = &this_class::read_instret;
+
csr_rd_cb[mcycle] = &this_class::read_cycle;
+ csr_wr_cb[mcycle] = &this_class::write_cycle;
csr_rd_cb[mcycleh] = &this_class::read_cycle;
- csr_rd_cb[minstret] = &this_class::read_cycle;
- csr_rd_cb[minstreth] = &this_class::read_cycle;
+ csr_wr_cb[mcycleh] = &this_class::write_cycle;
+ csr_rd_cb[minstret] = &this_class::read_instret;
+ csr_wr_cb[minstret] = &this_class::write_instret;
+ csr_rd_cb[minstreth] = &this_class::read_instret;
+ csr_wr_cb[minstreth] = &this_class::write_instret;
csr_rd_cb[mstatus] = &this_class::read_status;
csr_wr_cb[mstatus] = &this_class::write_status;
csr_rd_cb[sstatus] = &this_class::read_status;
@@ -457,16 +482,14 @@ riscv_hart_msu_vp::riscv_hart_msu_vp()
csr_rd_cb[uie] = &this_class::read_ie;
csr_wr_cb[uie] = &this_class::write_ie;
csr_rd_cb[mhartid] = &this_class::read_hartid;
- // common regs
- const std::array addrs{{mepc, mtvec, mscratch, mcause, mtval, mscratch}};
- for(auto addr: addrs) {
- csr_rd_cb[addr] = &this_class::read_reg;
- csr_wr_cb[addr] = &this_class::write_reg;
- }
- // read-only registers
- csr_rd_cb[misa] = &this_class::read_reg;
- csr_wr_cb[misa] = nullptr;
-
+ csr_rd_cb[mcounteren] = &this_class::read_null;
+ csr_wr_cb[mcounteren] = &this_class::write_null;
+ csr_rd_cb[mtvec] = &this_class::read_mtvec;
+ csr_wr_cb[mepc] = &this_class::write_mepc;
+ csr_wr_cb[misa] = &this_class::write_null;
+ csr_wr_cb[mvendorid] = &this_class::write_null;
+ csr_wr_cb[marchid] = &this_class::write_null;
+ csr_wr_cb[mimpid] = &this_class::write_null;
csr_rd_cb[satp] = &this_class::read_satp;
csr_wr_cb[satp] = &this_class::write_satp;
csr_rd_cb[fcsr] = &this_class::read_fcsr;
@@ -557,10 +580,14 @@ iss::status riscv_hart_msu_vp::read(const address_type type, const access_
auto res = type==iss::address_type::PHYSICAL?
read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data):
read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
- if (unlikely(res != iss::Ok)) this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
+ if (unlikely(res != iss::Ok)){
+ this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
+ fault_data=addr;
+ }
return res;
} catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id;
+ fault_data=ta.addr;
return iss::Err;
}
} break;
@@ -597,6 +624,7 @@ iss::status riscv_hart_msu_vp::read(const address_type type, const access_
return iss::Ok;
} catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id;
+ fault_data=ta.addr;
return iss::Err;
}
}
@@ -651,11 +679,14 @@ iss::status riscv_hart_msu_vp::write(const address_type type, const access
auto res = type==iss::address_type::PHYSICAL?
write_mem(phys_addr_t{access, space, addr}, length, data):
write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
- if (unlikely(res != iss::Ok))
- this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 7 (Store/AMO access fault)
+ if (unlikely(res != iss::Ok)) {
+ this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
+ fault_data=addr;
+ }
return res;
} catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id;
+ fault_data=ta.addr;
return iss::Err;
}
@@ -720,6 +751,7 @@ iss::status riscv_hart_msu_vp::write(const address_type type, const access
return iss::Ok;
} catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id;
+ fault_data=ta.addr;
return iss::Err;
}
}
@@ -774,8 +806,50 @@ template iss::status riscv_hart_m_p::read_cycle(unsigned a
return iss::Ok;
}
-template iss::status riscv_hart_msu_vp::read_time(unsigned addr, reg_t &val) {
- uint64_t time_val = (this->reg.icount + cycle_offset) / (100000000 / 32768 - 1); //-> ~3052;
+template iss::status riscv_hart_m_p::write_cycle(unsigned addr, reg_t val) {
+ if (sizeof(typename traits::reg_t) != 4) {
+ if (addr == mcycleh)
+ return iss::Err;
+ mcycle_csr = static_cast(val);
+ } else {
+ if (addr == mcycle) {
+ mcycle_csr = (mcycle_csr & 0xffffffff00000000) + val;
+ } else {
+ mcycle_csr = (static_cast(val)<<32) + (mcycle_csr & 0xffffffff);
+ }
+ }
+ cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around
+ return iss::Ok;
+}
+
+template iss::status riscv_hart_m_p::read_instret(unsigned addr, reg_t &val) {
+ if ((addr&0xff) == (minstret&0xff)) {
+ val = static_cast(this->reg.instret);
+ } else if ((addr&0xff) == (minstreth&0xff)) {
+ if (sizeof(typename traits::reg_t) != 4) return iss::Err;
+ val = static_cast(this->reg.instret >> 32);
+ }
+ return iss::Ok;
+}
+
+template iss::status riscv_hart_m_p::write_instret(unsigned addr, reg_t val) {
+ if (sizeof(typename traits::reg_t) != 4) {
+ if ((addr&0xff) == (minstreth&0xff))
+ return iss::Err;
+ this->reg.instret = static_cast(val);
+ } else {
+ if ((addr&0xff) == (minstret&0xff)) {
+ this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val;
+ } else {
+ this->reg.instret = (static_cast(val)<<32) + (this->reg.instret & 0xffffffff);
+ }
+ }
+ this->reg.instret--;
+ return iss::Ok;
+}
+
+template iss::status riscv_hart_m_p::read_time(unsigned addr, reg_t &val) {
+ uint64_t time_val = this->reg.icount / (100000000 / 32768 - 1); //-> ~3052;
if (addr == time) {
val = static_cast(time_val);
} else if (addr == timeh) {
@@ -785,6 +859,11 @@ template iss::status riscv_hart_msu_vp::read_time(unsigned
return iss::Ok;
}
+template iss::status riscv_hart_m_p::read_mtvec(unsigned addr, reg_t &val) {
+ val = csr[mtvec] & ~2;
+ return iss::Ok;
+}
+
template iss::status riscv_hart_msu_vp::read_status(unsigned addr, reg_t &val) {
auto req_priv_lvl = (addr >> 8) & 0x3;
val = state.mstatus & hart_state_type::get_mask(req_priv_lvl);
@@ -835,6 +914,12 @@ template iss::status riscv_hart_msu_vp::write_ip(unsigned
return iss::Ok;
}
+template iss::status riscv_hart_m_p::write_mepc(unsigned addr, reg_t val) {
+ auto mask = get_pc_mask();
+ csr[addr] = val;//(csr[addr] & ~mask) | (val & mask);
+ return iss::Ok;
+}
+
template iss::status riscv_hart_msu_vp::read_satp(unsigned addr, reg_t &val) {
reg_t tvm = state.mstatus.TVM;
if (this->reg.PRIV == PRIV_S & tvm != 0) {
@@ -918,7 +1003,6 @@ iss::status riscv_hart_msu_vp::read_mem(phys_addr_t paddr, unsigned length
template
iss::status riscv_hart_msu_vp::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
- if ((paddr.val + length) > mem.size()) return iss::Err;
if(mem_write_cb) return mem_write_cb(paddr, length, data);
switch (paddr.val) {
case 0x10013000: // UART0 base, TXFIFO reg
@@ -1153,7 +1237,7 @@ template uint64_t riscv_hart_msu_vp::enter_trap(uint64_t f
* access, or page-fault exception occurs, mtval is written with the
* faulting effective address.
*/
- csr[utval | (new_priv << 8)] = cause==2?instr : fault_data;
+ csr[utval | (new_priv << 8)] = cause==2?((instr & 0x3)==3?instr:instr&0xffff):fault_data;
fault_data = 0;
} else {
if (cur_priv != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)
@@ -1193,7 +1277,7 @@ template uint64_t riscv_hart_msu_vp::enter_trap(uint64_t f
auto ivec = csr[utvec | (new_priv << 8)];
// calculate addr// set NEXT_PC to trap addressess to jump to based on MODE
// bits in mtvec
- this->reg.NEXT_PC = ivec & ~0x1UL;
+ this->reg.NEXT_PC = ivec & ~0x3UL;
if ((ivec & 0x1) == 1 && trap_id != 0) this->reg.NEXT_PC += 4 * cause;
// reset trap state
this->reg.PRIV = new_priv;
diff --git a/incl/iss/arch/riscv_hart_mu_p.h b/incl/iss/arch/riscv_hart_mu_p.h
index 50f4d5e..c7f5b2f 100644
--- a/incl/iss/arch/riscv_hart_mu_p.h
+++ b/incl/iss/arch/riscv_hart_mu_p.h
@@ -154,15 +154,29 @@ public:
mstatus = new_val;
}
- T satp;
-
static constexpr uint32_t get_mask(unsigned priv_lvl) {
#if __cplusplus < 201402L
return priv_lvl == PRIV_U ? 0x80000011UL : priv_lvl == PRIV_S ? 0x800de133UL : 0x807ff9ddUL;
#else
switch (priv_lvl) {
- case PRIV_U: return 0x80000011UL; // 0b1000 0000 0000 0000 0000 0000 0001 0001
- default: return 0x807ff9ddUL; // 0b1000 0000 0111 1111 1111 1001 1011 1011
+ case PRIV_U: return 0x00000011UL; // 0b1000 0000 0000 0000 0000 0000 0001 0001
+ default:
+ // +-SD
+ // | +-TSR
+ // | |+-TW
+ // | ||+-TVM
+ // | |||+-MXR
+ // | ||||+-SUM
+ // | |||||+-MPRV
+ // | |||||| +-XS
+ // | |||||| | +-FS
+ // | |||||| | | +-MPP
+ // | |||||| | | | +-SPP
+ // | |||||| | | | |+-MPIE
+ // | |||||| | | | || +-UPIE
+ // | ||||||/|/|/| || |+-MIE
+ // | ||||||/|/|/| || || +-UIE
+ return 0b00000000000000000001100010011001;
}
#endif
}
@@ -172,13 +186,17 @@ public:
constexpr reg_t get_irq_mask(size_t mode) {
std::array m = {{
0b000100010001, // U mode
- 0b001100110011, // S mode
+ 0, // S mode
0,
- 0b101110111011 // M mode
+ 0b100110011001 // M mode
}};
return m[mode];
}
+ constexpr reg_t get_pc_mask() {
+ return traits::MISA_VAL&0b0100?~1:~3;
+ }
+
riscv_hart_mu_p();
virtual ~riscv_hart_mu_p() = default;
@@ -200,7 +218,7 @@ public:
void disass_output(uint64_t pc, const std::string instr) override {
CLOG(INFO, disass) << fmt::format("0x{:016x} {:40} [p:{};s:0x{:x};c:{}]",
- pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.ccount);
+ pc, instr, lvl[this->reg.PRIV], (reg_t)state.mstatus, this->reg.icount);
};
iss::instrumentation_if *get_instrumentation_if() override { return &instr_if; }
@@ -249,7 +267,10 @@ protected:
virtual iss::status write_csr(unsigned addr, reg_t val);
hart_state_type state;
- uint64_t cycle_offset;
+ int64_t cycle_offset{0};
+ uint64_t mcycle_csr{0};
+ int64_t instret_offset{0};
+ uint64_t minstret_csr{0};
reg_t fault_data;
uint64_t tohost = tohost_dflt;
uint64_t fromhost = fromhost_dflt;
@@ -270,7 +291,13 @@ protected:
private:
iss::status read_reg(unsigned addr, reg_t &val);
iss::status write_reg(unsigned addr, reg_t val);
+ iss::status read_null(unsigned addr, reg_t &val);
+ iss::status write_null(unsigned addr, reg_t val){return iss::status::Ok;}
iss::status read_cycle(unsigned addr, reg_t &val);
+ iss::status write_cycle(unsigned addr, reg_t val);
+ iss::status read_instret(unsigned addr, reg_t &val);
+ iss::status write_instret(unsigned addr, reg_t val);
+ iss::status read_mtvec(unsigned addr, reg_t &val);
iss::status read_time(unsigned addr, reg_t &val);
iss::status read_status(unsigned addr, reg_t &val);
iss::status write_status(unsigned addr, reg_t val);
@@ -279,6 +306,7 @@ private:
iss::status read_ip(unsigned addr, reg_t &val);
iss::status write_ip(unsigned addr, reg_t val);
iss::status read_hartid(unsigned addr, reg_t &val);
+ iss::status write_mepc(unsigned addr, reg_t val);
reg_t mhartid_reg{0x0};
std::functionmem_read_cb;
@@ -291,21 +319,55 @@ protected:
template
riscv_hart_mu_p::riscv_hart_mu_p()
: state()
-, cycle_offset(0)
, instr_if(*this) {
+ // reset values
csr[misa] = traits::MISA_VAL;
+ csr[mvendorid] = 0x669;
+ csr[marchid] = 0x80000003;
+ csr[mimpid] = 1;
+
uart_buf.str("");
- for (unsigned addr = mcycle; addr <= hpmcounter31; ++addr) csr_wr_cb[addr] = nullptr;
- for (unsigned addr = mcycleh; addr <= hpmcounter31h; ++addr) csr_wr_cb[addr] = nullptr;
- // special handling
+ for (unsigned addr = mhpmcounter3; addr <= mhpmcounter31; ++addr){
+ csr_rd_cb[addr] = &this_class::read_null;
+ csr_wr_cb[addr] = &this_class::write_reg;
+ }
+ for (unsigned addr = mhpmcounter3h; addr <= mhpmcounter31h; ++addr){
+ csr_rd_cb[addr] = &this_class::read_null;
+ csr_wr_cb[addr] = &this_class::write_reg;
+ }
+ for (unsigned addr = mhpmevent3; addr <= mhpmevent31; ++addr){
+ csr_rd_cb[addr] = &this_class::read_null;
+ csr_wr_cb[addr] = &this_class::write_reg;
+ }
+ for (unsigned addr = hpmcounter3; addr <= hpmcounter31; ++addr){
+ csr_rd_cb[addr] = &this_class::read_null;
+ }
+ for (unsigned addr = hpmcounter3h; addr <= hpmcounter31h; ++addr){
+ csr_rd_cb[addr] = &this_class::read_null;
+ //csr_wr_cb[addr] = &this_class::write_reg;
+ }
+ // common regs
+ const std::array addrs{{misa, mvendorid, marchid, mimpid, mepc, mtvec, mscratch, mcause, mtval, mscratch}};
+ for(auto addr: addrs) {
+ csr_rd_cb[addr] = &this_class::read_reg;
+ csr_wr_cb[addr] = &this_class::write_reg;
+ }
+ // special handling & overrides
csr_rd_cb[time] = &this_class::read_time;
- csr_wr_cb[time] = nullptr;
csr_rd_cb[timeh] = &this_class::read_time;
- csr_wr_cb[timeh] = nullptr;
+ csr_rd_cb[cycle] = &this_class::read_cycle;
+ csr_rd_cb[cycleh] = &this_class::read_cycle;
+ csr_rd_cb[instret] = &this_class::read_instret;
+ csr_rd_cb[instreth] = &this_class::read_instret;
+
csr_rd_cb[mcycle] = &this_class::read_cycle;
+ csr_wr_cb[mcycle] = &this_class::write_cycle;
csr_rd_cb[mcycleh] = &this_class::read_cycle;
- csr_rd_cb[minstret] = &this_class::read_cycle;
- csr_rd_cb[minstreth] = &this_class::read_cycle;
+ csr_wr_cb[mcycleh] = &this_class::write_cycle;
+ csr_rd_cb[minstret] = &this_class::read_instret;
+ csr_wr_cb[minstret] = &this_class::write_instret;
+ csr_rd_cb[minstreth] = &this_class::read_instret;
+ csr_wr_cb[minstreth] = &this_class::write_instret;
csr_rd_cb[mstatus] = &this_class::read_status;
csr_wr_cb[mstatus] = &this_class::write_status;
csr_rd_cb[ustatus] = &this_class::read_status;
@@ -319,15 +381,14 @@ riscv_hart_mu_p::riscv_hart_mu_p()
csr_rd_cb[uie] = &this_class::read_ie;
csr_wr_cb[uie] = &this_class::write_ie;
csr_rd_cb[mhartid] = &this_class::read_hartid;
- // common regs
- const std::array addrs{{mepc, mtvec, mscratch, mcause, mtval, mscratch}};
- for(auto addr: addrs) {
- csr_rd_cb[addr] = &this_class::read_reg;
- csr_wr_cb[addr] = &this_class::write_reg;
- }
- // read-only registers
- csr_rd_cb[misa] = &this_class::read_reg;
- csr_wr_cb[misa] = nullptr;
+ csr_rd_cb[mcounteren] = &this_class::read_null;
+ csr_wr_cb[mcounteren] = &this_class::write_null;
+ csr_rd_cb[mtvec] = &this_class::read_mtvec;
+ csr_wr_cb[mepc] = &this_class::write_mepc;
+ csr_wr_cb[misa] = &this_class::write_null;
+ csr_wr_cb[mvendorid] = &this_class::write_null;
+ csr_wr_cb[marchid] = &this_class::write_null;
+ csr_wr_cb[mimpid] = &this_class::write_null;
if(FEAT & FEAT_PMP){
for(size_t i=pmpaddr0; i<=pmpaddr15; ++i){
@@ -413,13 +474,23 @@ iss::status riscv_hart_mu_p::read(const address_type type, const acc
return iss::Err;
}
try {
+ auto alignment = access == iss::access_type::FETCH? (traits::MISA_VAL&0x100? 2 : 4) : length;
+ if(alignment>1 && (addr&(alignment-1))){
+ this->reg.trap_state = 1<<31 | 4<<16;
+ fault_data=addr;
+ return iss::Err;
+ }
auto res = type==iss::address_type::PHYSICAL?
read_mem( BASE::v2p(phys_addr_t{access, space, addr}), length, data):
read_mem( BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
- if (unlikely(res != iss::Ok)) this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
+ if (unlikely(res != iss::Ok)){
+ this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 5 (load access fault
+ fault_data=addr;
+ }
return res;
} catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id;
+ fault_data=ta.addr;
return iss::Err;
}
} break;
@@ -445,6 +516,7 @@ iss::status riscv_hart_mu_p::read(const address_type type, const acc
return iss::Ok;
} catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id;
+ fault_data=ta.addr;
return iss::Err;
}
}
@@ -485,14 +557,22 @@ iss::status riscv_hart_mu_p::write(const address_type type, const ac
return iss::Err;
}
try {
+ if(length>1 && (addr&(length-1))){
+ this->reg.trap_state = 1<<31 | 6<<16;
+ fault_data=addr;
+ return iss::Err;
+ }
auto res = type==iss::address_type::PHYSICAL?
write_mem(phys_addr_t{access, space, addr}, length, data):
write_mem(BASE::v2p(iss::addr_t{access, type, space, addr}), length, data);
- if (unlikely(res != iss::Ok))
- this->reg.trap_state = (1 << 31) | (5 << 16); // issue trap 7 (Store/AMO access fault)
+ if (unlikely(res != iss::Ok)) {
+ this->reg.trap_state = (1 << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
+ fault_data=addr;
+ }
return res;
} catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id;
+ fault_data=ta.addr;
return iss::Err;
}
@@ -552,6 +632,7 @@ iss::status riscv_hart_mu_p::write(const address_type type, const ac
return iss::Ok;
} catch (trap_access &ta) {
this->reg.trap_state = (1 << 31) | ta.id;
+ fault_data=ta.addr;
return iss::Err;
}
}
@@ -585,6 +666,11 @@ template iss::status riscv_hart_mu_p iss::status riscv_hart_m_p::read_null(unsigned addr, reg_t &val) {
+ val = 0;
+ return iss::Ok;
+}
+
template iss::status riscv_hart_mu_p::write_reg(unsigned addr, reg_t val) {
csr[addr] = val;
return iss::Ok;
@@ -601,8 +687,50 @@ template iss::status riscv_hart_mu_p iss::status riscv_hart_m_p::write_cycle(unsigned addr, reg_t val) {
+ if (sizeof(typename traits::reg_t) != 4) {
+ if (addr == mcycleh)
+ return iss::Err;
+ mcycle_csr = static_cast(val);
+ } else {
+ if (addr == mcycle) {
+ mcycle_csr = (mcycle_csr & 0xffffffff00000000) + val;
+ } else {
+ mcycle_csr = (static_cast(val)<<32) + (mcycle_csr & 0xffffffff);
+ }
+ }
+ cycle_offset = mcycle_csr-this->reg.icount; // TODO: relying on wrap-around
+ return iss::Ok;
+}
+
+template iss::status riscv_hart_m_p::read_instret(unsigned addr, reg_t &val) {
+ if ((addr&0xff) == (minstret&0xff)) {
+ val = static_cast(this->reg.instret);
+ } else if ((addr&0xff) == (minstreth&0xff)) {
+ if (sizeof(typename traits::reg_t) != 4) return iss::Err;
+ val = static_cast(this->reg.instret >> 32);
+ }
+ return iss::Ok;
+}
+
+template iss::status riscv_hart_m_p::write_instret(unsigned addr, reg_t val) {
+ if (sizeof(typename traits::reg_t) != 4) {
+ if ((addr&0xff) == (minstreth&0xff))
+ return iss::Err;
+ this->reg.instret = static_cast(val);
+ } else {
+ if ((addr&0xff) == (minstret&0xff)) {
+ this->reg.instret = (this->reg.instret & 0xffffffff00000000) + val;
+ } else {
+ this->reg.instret = (static_cast(val)<<32) + (this->reg.instret & 0xffffffff);
+ }
+ }
+ this->reg.instret--;
+ return iss::Ok;
+}
+
template iss::status riscv_hart_mu_p::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 / (100000000 / 32768 - 1); //-> ~3052;
if (addr == time) {
val = static_cast(time_val);
} else if (addr == timeh) {
@@ -612,6 +740,10 @@ template iss::status riscv_hart_mu_p iss::status riscv_hart_m_p::read_mtvec(unsigned addr, reg_t &val) {
+ val = csr[mtvec] & ~2;
+ return iss::Ok;
+}
template iss::status riscv_hart_mu_p::read_status(unsigned addr, reg_t &val) {
auto req_priv_lvl = (addr >> 8) & 0x3;
val = state.mstatus & hart_state_type::get_mask(req_priv_lvl);
@@ -659,9 +791,14 @@ template iss::status riscv_hart_mu_p iss::status riscv_hart_m_p::write_mepc(unsigned addr, reg_t val) {
+ auto mask = get_pc_mask();
+ csr[addr] = val;//(csr[addr] & ~mask) | (val & mask);
+ return iss::Ok;
+}
+
template
iss::status riscv_hart_mu_p::read_mem(phys_addr_t paddr, unsigned length, uint8_t *const data) {
- if ((paddr.val + length) > mem.size()) return iss::Err;
if(mem_read_cb) return mem_read_cb(paddr, length, data);
switch (paddr.val) {
case 0x0200BFF8: { // CLINT base, mtime reg
@@ -677,9 +814,9 @@ iss::status riscv_hart_mu_p::read_mem(phys_addr_t paddr, unsigned le
if (this->reg.icount > 30000) data[3] |= 0x80;
} break;
default: {
- const auto &p = mem(paddr.val / mem.page_size);
- auto offs = paddr.val & mem.page_addr_mask;
- std::copy(p.data() + offs, p.data() + offs + length, data);
+ for(auto offs=0U; offs::read_mem(phys_addr_t paddr, unsigned le
template
iss::status riscv_hart_mu_p::write_mem(phys_addr_t paddr, unsigned length, const uint8_t *const data) {
- if ((paddr.val + length) > mem.size()) return iss::Err;
if(mem_write_cb) return mem_write_cb(paddr, length, data);
switch (paddr.val) {
case 0x10013000: // UART0 base, TXFIFO reg
@@ -719,9 +855,10 @@ iss::status riscv_hart_mu_p::write_mem(phys_addr_t paddr, unsigned l
std::copy(data, data + length, p.data() + (paddr.val & mem.page_addr_mask));
// tohost handling in case of riscv-test
if (paddr.access && iss::access_type::FUNC) {
- auto tohost_upper = (traits::XLEN == 32 && paddr.val == (tohost + 4));
+ auto tohost_upper = (traits::XLEN == 32 && paddr.val == (tohost + 4)) ||
+ (traits::XLEN == 64 && paddr.val == tohost);
auto tohost_lower =
- (traits::XLEN == 32 && paddr.val == tohost);
+ (traits::XLEN == 32 && paddr.val == tohost) || (traits::XLEN == 64 && paddr.val == tohost);
if (tohost_lower || tohost_upper) {
uint64_t hostvar = *reinterpret_cast(p.data() + (tohost & mem.page_addr_mask));
if (tohost_upper || (tohost_lower && to_host_wr_cnt > 0)) {
@@ -752,7 +889,8 @@ iss::status riscv_hart_mu_p::write_mem(phys_addr_t paddr, unsigned l
}
} else if (tohost_lower)
to_host_wr_cnt++;
- } else if (traits::XLEN == 32 && paddr.val == fromhost + 4) {
+ } else if ((traits::XLEN == 32 && paddr.val == fromhost + 4) ||
+ (traits::XLEN == 64 && paddr.val == fromhost)) {
uint64_t fhostvar = *reinterpret_cast(p.data() + (fromhost & mem.page_addr_mask));
*reinterpret_cast(p.data() + (tohost & mem.page_addr_mask)) = fhostvar;
}
@@ -809,7 +947,7 @@ template uint64_t riscv_hart_mu_p::
* access, or page-fault exception occurs, mtval is written with the
* faulting effective address.
*/
- csr[utval | (new_priv << 8)] = cause==2?instr:fault_data;
+ csr[utval | (new_priv << 8)] = cause==2?((instr & 0x3)==3?instr:instr&0xffff):fault_data;
fault_data = 0;
} else {
if (this->reg.PRIV != PRIV_M && ((csr[mideleg] >> cause) & 0x1) != 0)