Browse Source

Merge pull request #1040 from plctlab/plct-priv-dev

Update for counter related CSR
pull/1049/head
Andrew Waterman 4 years ago
committed by GitHub
parent
commit
3ea7494620
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      riscv/clint.cc
  2. 43
      riscv/csrs.cc
  3. 17
      riscv/csrs.h
  4. 26
      riscv/processor.cc
  5. 3
      riscv/processor.h

1
riscv/clint.cc

@ -82,6 +82,7 @@ void clint_t::increment(reg_t inc)
mtime += inc;
}
for (size_t i = 0; i < procs.size(); i++) {
procs[i]->state.time->sync(mtime);
procs[i]->state.mip->backdoor_write_with_mask(MIP_MTIP, 0);
if (mtime >= mtimecmp[i])
procs[i]->state.mip->backdoor_write_with_mask(MIP_MTIP, MIP_MTIP);

43
riscv/csrs.cc

@ -525,6 +525,10 @@ bool rv32_low_csr_t::unlogged_write(const reg_t val) noexcept {
return orig->unlogged_write((orig->written_value() >> 32 << 32) | (val & 0xffffffffU));
}
reg_t rv32_low_csr_t::written_value() const noexcept {
return orig->written_value() & 0xffffffffU;
}
// implement class rv32_high_csr_t
rv32_high_csr_t::rv32_high_csr_t(processor_t* const proc, const reg_t addr, csr_t_p orig):
csr_t(proc, addr),
@ -543,6 +547,10 @@ bool rv32_high_csr_t::unlogged_write(const reg_t val) noexcept {
return orig->unlogged_write((orig->written_value() << 32 >> 32) | ((val & 0xffffffffU) << 32));
}
reg_t rv32_high_csr_t::written_value() const noexcept {
return (orig->written_value() >> 32) & 0xffffffffU;
}
// implement class sstatus_csr_t
sstatus_csr_t::sstatus_csr_t(processor_t* const proc, sstatus_proxy_csr_t_p orig, vsstatus_csr_t_p virt):
virtualized_csr_t(proc, orig, virt),
@ -934,10 +942,7 @@ void wide_counter_csr_t::bump(const reg_t howmuch) noexcept {
}
bool wide_counter_csr_t::unlogged_write(const reg_t val) noexcept {
if (proc->get_xlen() == 32)
this->val = (this->val >> 32 << 32) | (val & 0xffffffffU);
else
this->val = val;
this->val = val;
// The ISA mandates that if an instruction writes instret, the write
// takes precedence over the increment to instret. However, Spike
// unconditionally increments instret after executing an instruction.
@ -951,25 +956,23 @@ reg_t wide_counter_csr_t::written_value() const noexcept {
return this->val + 1;
}
void wide_counter_csr_t::write_upper_half(const reg_t val) noexcept {
this->val = (val << 32) | (this->val << 32 >> 32);
this->val--; // See comment above.
// Log upper half only.
log_special_write(address + (CSR_MINSTRETH - CSR_MINSTRET), written_value() >> 32);
}
counter_top_csr_t::counter_top_csr_t(processor_t* const proc, const reg_t addr, wide_counter_csr_t_p parent):
// implement class time_counter_csr_t
time_counter_csr_t::time_counter_csr_t(processor_t* const proc, const reg_t addr):
csr_t(proc, addr),
parent(parent) {
shadow_val(0) {
}
reg_t counter_top_csr_t::read() const noexcept {
return parent->read() >> 32;
reg_t time_counter_csr_t::read() const noexcept {
// reading the time CSR in VS or VU mode returns the sum of the contents of
// htimedelta and the actual value of time.
if (state->v)
return shadow_val + state->htimedelta->read();
else
return shadow_val;
}
bool counter_top_csr_t::unlogged_write(const reg_t val) noexcept {
parent->write_upper_half(val);
return true;
void time_counter_csr_t::sync(const reg_t val) noexcept {
shadow_val = val;
}
proxy_csr_t::proxy_csr_t(processor_t* const proc, const reg_t addr, csr_t_p delegate):
@ -1008,11 +1011,13 @@ bool counter_proxy_csr_t::myenable(csr_t_p counteren) const noexcept {
}
void counter_proxy_csr_t::verify_permissions(insn_t insn, bool write) const {
proxy_csr_t::verify_permissions(insn, write);
const bool mctr_ok = (state->prv < PRV_M) ? myenable(state->mcounteren) : true;
const bool hctr_ok = state->v ? myenable(state->hcounteren) : true;
const bool sctr_ok = (proc->extension_enabled('S') && state->prv < PRV_S) ? myenable(state->scounteren) : true;
if (write || !mctr_ok)
if (!mctr_ok)
throw trap_illegal_instruction(insn.bits());
if (!hctr_ok)
throw trap_virtual_instruction(insn.bits());

17
riscv/csrs.h

@ -262,6 +262,7 @@ class rv32_low_csr_t: public csr_t {
virtual void verify_permissions(insn_t insn, bool write) const override;
protected:
virtual bool unlogged_write(const reg_t val) noexcept override;
virtual reg_t written_value() const noexcept override;
private:
csr_t_p orig;
};
@ -273,6 +274,7 @@ class rv32_high_csr_t: public csr_t {
virtual void verify_permissions(insn_t insn, bool write) const override;
protected:
virtual bool unlogged_write(const reg_t val) noexcept override;
virtual reg_t written_value() const noexcept override;
private:
csr_t_p orig;
};
@ -500,7 +502,6 @@ class wide_counter_csr_t: public csr_t {
// Always returns full 64-bit value
virtual reg_t read() const noexcept override;
void bump(const reg_t howmuch) noexcept;
void write_upper_half(const reg_t val) noexcept;
protected:
virtual bool unlogged_write(const reg_t val) noexcept override;
virtual reg_t written_value() const noexcept override;
@ -510,18 +511,20 @@ class wide_counter_csr_t: public csr_t {
typedef std::shared_ptr<wide_counter_csr_t> wide_counter_csr_t_p;
// A simple proxy to read/write the upper half of minstret/mcycle
class counter_top_csr_t: public csr_t {
class time_counter_csr_t: public csr_t {
public:
counter_top_csr_t(processor_t* const proc, const reg_t addr, wide_counter_csr_t_p parent);
time_counter_csr_t(processor_t* const proc, const reg_t addr);
virtual reg_t read() const noexcept override;
void sync(const reg_t val) noexcept;
protected:
virtual bool unlogged_write(const reg_t val) noexcept override;
virtual bool unlogged_write(const reg_t val) noexcept override { return false; };
private:
wide_counter_csr_t_p parent;
reg_t shadow_val;
};
typedef std::shared_ptr<counter_top_csr_t> counter_top_csr_t_p;
typedef std::shared_ptr<time_counter_csr_t> time_counter_csr_t_p;
// For a CSR that is an alias of another
class proxy_csr_t: public csr_t {

26
riscv/processor.cc

@ -202,20 +202,29 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
csrmap[CSR_MSCRATCH] = std::make_shared<basic_csr_t>(proc, CSR_MSCRATCH, 0);
csrmap[CSR_MTVEC] = mtvec = std::make_shared<tvec_csr_t>(proc, CSR_MTVEC);
csrmap[CSR_MCAUSE] = mcause = std::make_shared<cause_csr_t>(proc, CSR_MCAUSE);
csrmap[CSR_MINSTRET] = minstret = std::make_shared<wide_counter_csr_t>(proc, CSR_MINSTRET);
csrmap[CSR_MCYCLE] = mcycle = std::make_shared<wide_counter_csr_t>(proc, CSR_MCYCLE);
minstret = std::make_shared<wide_counter_csr_t>(proc, CSR_MINSTRET);
mcycle = std::make_shared<wide_counter_csr_t>(proc, CSR_MCYCLE);
time = std::make_shared<time_counter_csr_t>(proc, CSR_TIME);
if (proc->extension_enabled_const(EXT_ZICNTR)) {
csrmap[CSR_INSTRET] = std::make_shared<counter_proxy_csr_t>(proc, CSR_INSTRET, minstret);
csrmap[CSR_CYCLE] = std::make_shared<counter_proxy_csr_t>(proc, CSR_CYCLE, mcycle);
csrmap[CSR_TIME] = std::make_shared<counter_proxy_csr_t>(proc, CSR_TIME, time);
}
if (xlen == 32) {
counter_top_csr_t_p minstreth, mcycleh;
csrmap[CSR_MINSTRETH] = minstreth = std::make_shared<counter_top_csr_t>(proc, CSR_MINSTRETH, minstret);
csrmap[CSR_MCYCLEH] = mcycleh = std::make_shared<counter_top_csr_t>(proc, CSR_MCYCLEH, mcycle);
csr_t_p minstreth, mcycleh;
csrmap[CSR_MINSTRET] = std::make_shared<rv32_low_csr_t>(proc, CSR_MINSTRET, minstret);
csrmap[CSR_MINSTRETH] = minstreth = std::make_shared<rv32_high_csr_t>(proc, CSR_MINSTRETH, minstret);
csrmap[CSR_MCYCLE] = std::make_shared<rv32_low_csr_t>(proc, CSR_MCYCLE, mcycle);
csrmap[CSR_MCYCLEH] = mcycleh = std::make_shared<rv32_high_csr_t>(proc, CSR_MCYCLEH, mcycle);
if (proc->extension_enabled_const(EXT_ZICNTR)) {
auto timeh = std::make_shared<rv32_high_csr_t>(proc, CSR_TIMEH, time);
csrmap[CSR_INSTRETH] = std::make_shared<counter_proxy_csr_t>(proc, CSR_INSTRETH, minstreth);
csrmap[CSR_CYCLEH] = std::make_shared<counter_proxy_csr_t>(proc, CSR_CYCLEH, mcycleh);
csrmap[CSR_TIMEH] = std::make_shared<counter_proxy_csr_t>(proc, CSR_TIMEH, timeh);
}
} else {
csrmap[CSR_MINSTRET] = minstret;
csrmap[CSR_MCYCLE] = mcycle;
}
for (reg_t i = 3; i <= 31; ++i) {
const reg_t which_mevent = CSR_MHPMEVENT3 + i - 3;
@ -344,6 +353,13 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
(1 << CAUSE_STORE_PAGE_FAULT);
csrmap[CSR_HEDELEG] = hedeleg = std::make_shared<masked_csr_t>(proc, CSR_HEDELEG, hedeleg_mask, 0);
csrmap[CSR_HCOUNTEREN] = hcounteren = std::make_shared<masked_csr_t>(proc, CSR_HCOUNTEREN, counteren_mask, 0);
htimedelta = std::make_shared<basic_csr_t>(proc, CSR_HTIMEDELTA, 0);
if (xlen == 32) {
csrmap[CSR_HTIMEDELTA] = std::make_shared<rv32_low_csr_t>(proc, CSR_HTIMEDELTA, htimedelta);
csrmap[CSR_HTIMEDELTAH] = std::make_shared<rv32_high_csr_t>(proc, CSR_HTIMEDELTAH, htimedelta);
} else {
csrmap[CSR_HTIMEDELTA] = htimedelta;
}
csrmap[CSR_HTVAL] = htval = std::make_shared<basic_csr_t>(proc, CSR_HTVAL, 0);
csrmap[CSR_HTINST] = htinst = std::make_shared<basic_csr_t>(proc, CSR_HTINST, 0);
csrmap[CSR_HGATP] = hgatp = std::make_shared<hgatp_csr_t>(proc, CSR_HGATP);

3
riscv/processor.h

@ -191,6 +191,9 @@ struct state_t
csr_t_p sstateen[4];
csr_t_p hstateen[4];
csr_t_p htimedelta;
time_counter_csr_t_p time;
bool serialized; // whether timer CSRs are in a well-defined state
// When true, execute a single instruction and then enter debug mode. This

Loading…
Cancel
Save