Browse Source

Add Sstc support. (#1057)

pull/1063/head
i2h2 4 years ago
committed by GitHub
parent
commit
5672c4a41a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 37
      riscv/csrs.cc
  2. 17
      riscv/csrs.h
  3. 2
      riscv/isa_parser.cc
  4. 1
      riscv/isa_parser.h
  5. 23
      riscv/processor.cc
  6. 4
      riscv/processor.h

37
riscv/csrs.cc

@ -679,7 +679,8 @@ void mip_csr_t::backdoor_write_with_mask(const reg_t mask, const reg_t val) noex
}
reg_t mip_csr_t::write_mask() const noexcept {
const reg_t supervisor_ints = proc->extension_enabled('S') ? MIP_SSIP | MIP_STIP | MIP_SEIP : 0;
// MIP_STIP is writable unless SSTC exists and STCE is set in MENVCFG
const reg_t supervisor_ints = proc->extension_enabled('S') ? MIP_SSIP | ((state->menvcfg->read() & MENVCFG_STCE) ? 0 : MIP_STIP) | MIP_SEIP : 0;
const reg_t vssip_int = proc->extension_enabled('H') ? MIP_VSSIP : 0;
const reg_t hypervisor_ints = proc->extension_enabled('H') ? MIP_HS_MASK : 0;
// We must mask off sgeip, vstip, and vseip. All three of these
@ -979,6 +980,11 @@ reg_t time_counter_csr_t::read() const noexcept {
void time_counter_csr_t::sync(const reg_t val) noexcept {
shadow_val = val;
if (proc->extension_enabled(EXT_SSTC)) {
const reg_t mip_val = (shadow_val >= state->stimecmp->read() ? MIP_STIP : 0) |
(shadow_val + state->htimedelta->read() >= state->vstimecmp->read() ? MIP_VSTIP : 0);
state->mip->backdoor_write_with_mask(MIP_STIP | MIP_VSTIP, mip_val);
}
}
proxy_csr_t::proxy_csr_t(processor_t* const proc, const reg_t addr, csr_t_p delegate):
@ -1400,3 +1406,32 @@ void henvcfg_csr_t::verify_permissions(insn_t insn, bool write) const {
throw trap_illegal_instruction(insn.bits());
}
}
stimecmp_csr_t::stimecmp_csr_t(processor_t* const proc, const reg_t addr, const reg_t imask):
basic_csr_t(proc, addr, 0), intr_mask(imask) {
}
bool stimecmp_csr_t::unlogged_write(const reg_t val) noexcept {
state->mip->backdoor_write_with_mask(intr_mask, state->time->read() >= val ? intr_mask : 0);
return basic_csr_t::unlogged_write(val);
}
virtualized_stimecmp_csr_t::virtualized_stimecmp_csr_t(processor_t* const proc, csr_t_p orig, csr_t_p virt):
virtualized_csr_t(proc, orig, virt) {
}
void virtualized_stimecmp_csr_t::verify_permissions(insn_t insn, bool write) const {
virtualized_csr_t::verify_permissions(insn, write);
// check for read permission to time as enabled by xcounteren
state->time_proxy->verify_permissions(insn, false);
if (!(state->menvcfg->read() & MENVCFG_STCE)) {
// access to (v)stimecmp with MENVCFG.STCE = 0
if (state->prv < PRV_M)
throw trap_illegal_instruction(insn.bits());
} else if (state->v && !(state->henvcfg->read() & HENVCFG_STCE)) {
// access to vstimecmp with MENVCFG.STCE = 1 and HENVCFG.STCE = 0 when V = 1
throw trap_virtual_instruction(insn.bits());
}
}

17
riscv/csrs.h

@ -449,12 +449,13 @@ class masked_csr_t: public basic_csr_t {
};
// henvcfg.pbmte is read_only 0 when menvcfg.pbmte = 0
// henvcfg.stce is read_only 0 when menvcfg.stce = 0
class henvcfg_csr_t final: public masked_csr_t {
public:
henvcfg_csr_t(processor_t* const proc, const reg_t addr, const reg_t mask, const reg_t init, csr_t_p menvcfg);
reg_t read() const noexcept override {
return (menvcfg->read() | ~MENVCFG_PBMTE) & masked_csr_t::read();
return (menvcfg->read() | ~(MENVCFG_PBMTE | MENVCFG_STCE)) & masked_csr_t::read();
}
virtual void verify_permissions(insn_t insn, bool write) const override;
@ -729,4 +730,18 @@ class senvcfg_csr_t final: public masked_csr_t {
virtual void verify_permissions(insn_t insn, bool write) const override;
};
class stimecmp_csr_t: public basic_csr_t {
public:
stimecmp_csr_t(processor_t* const proc, const reg_t addr, const reg_t imask);
protected:
virtual bool unlogged_write(const reg_t val) noexcept override;
private:
reg_t intr_mask;
};
class virtualized_stimecmp_csr_t: public virtualized_csr_t {
public:
virtualized_stimecmp_csr_t(processor_t* const proc, csr_t_p orig, csr_t_p virt);
virtual void verify_permissions(insn_t insn, bool write) const override;
};
#endif

2
riscv/isa_parser.cc

@ -181,6 +181,8 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv)
} else if (ext_str == "zicbop") {
} else if (ext_str == "zicntr") {
} else if (ext_str == "zihpm") {
} else if (ext_str == "sstc") {
extension_table[EXT_SSTC] = true;
} else if (ext_str[0] == 'x') {
max_isa |= 1L << ('x' - 'a');
extension_table[toupper('x')] = true;

1
riscv/isa_parser.h

@ -52,6 +52,7 @@ typedef enum {
EXT_XZBM,
EXT_XZBR,
EXT_XZBT,
EXT_SSTC,
} isa_extension_t;
typedef enum {

23
riscv/processor.cc

@ -208,7 +208,7 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
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);
csrmap[CSR_TIME] = time_proxy = std::make_shared<counter_proxy_csr_t>(proc, CSR_TIME, time);
}
if (xlen == 32) {
csr_t_p minstreth, mcycleh;
@ -405,7 +405,8 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
if (proc->extension_enabled_const('U')) {
const reg_t menvcfg_mask = (proc->extension_enabled(EXT_ZICBOM) ? MENVCFG_CBCFE | MENVCFG_CBIE : 0) |
(proc->extension_enabled(EXT_ZICBOZ) ? MENVCFG_CBZE : 0) |
(proc->extension_enabled(EXT_SVPBMT) ? MENVCFG_PBMTE : 0);
(proc->extension_enabled(EXT_SVPBMT) ? MENVCFG_PBMTE : 0) |
(proc->extension_enabled(EXT_SSTC) ? MENVCFG_STCE : 0);
const reg_t menvcfg_init = (proc->extension_enabled(EXT_SVPBMT) ? MENVCFG_PBMTE : 0);
menvcfg = std::make_shared<masked_csr_t>(proc, CSR_MENVCFG, menvcfg_mask, menvcfg_init);
if (xlen == 32) {
@ -419,7 +420,8 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
csrmap[CSR_SENVCFG] = senvcfg = std::make_shared<senvcfg_csr_t>(proc, CSR_SENVCFG, senvcfg_mask, 0);
const reg_t henvcfg_mask = (proc->extension_enabled(EXT_ZICBOM) ? HENVCFG_CBCFE | HENVCFG_CBIE : 0) |
(proc->extension_enabled(EXT_ZICBOZ) ? HENVCFG_CBZE : 0) |
(proc->extension_enabled(EXT_SVPBMT) ? HENVCFG_PBMTE : 0);
(proc->extension_enabled(EXT_SVPBMT) ? HENVCFG_PBMTE : 0) |
(proc->extension_enabled(EXT_SSTC) ? HENVCFG_STCE : 0);
const reg_t henvcfg_init = (proc->extension_enabled(EXT_SVPBMT) ? HENVCFG_PBMTE : 0);
henvcfg = std::make_shared<henvcfg_csr_t>(proc, CSR_HENVCFG, henvcfg_mask, henvcfg_init, menvcfg);
if (xlen == 32) {
@ -457,6 +459,21 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
}
}
if (proc->extension_enabled_const(EXT_SSTC)) {
stimecmp = std::make_shared<stimecmp_csr_t>(proc, CSR_STIMECMP, MIP_STIP);
vstimecmp = std::make_shared<stimecmp_csr_t>(proc, CSR_VSTIMECMP, MIP_VSTIP);
auto virtualized_stimecmp = std::make_shared<virtualized_stimecmp_csr_t>(proc, stimecmp, vstimecmp);
if (xlen == 32) {
csrmap[CSR_STIMECMP] = std::make_shared<rv32_low_csr_t>(proc, CSR_STIMECMP, virtualized_stimecmp);
csrmap[CSR_STIMECMPH] = std::make_shared<rv32_high_csr_t>(proc, CSR_STIMECMPH, virtualized_stimecmp);
csrmap[CSR_VSTIMECMP] = std::make_shared<rv32_low_csr_t>(proc, CSR_VSTIMECMP, vstimecmp);
csrmap[CSR_VSTIMECMPH] = std::make_shared<rv32_high_csr_t>(proc, CSR_VSTIMECMPH, vstimecmp);
} else {
csrmap[CSR_STIMECMP] = virtualized_stimecmp;
csrmap[CSR_VSTIMECMP] = vstimecmp;
}
}
serialized = false;
#ifdef RISCV_ENABLE_COMMITLOG

4
riscv/processor.h

@ -193,6 +193,10 @@ struct state_t
csr_t_p htimedelta;
time_counter_csr_t_p time;
csr_t_p time_proxy;
csr_t_p stimecmp;
csr_t_p vstimecmp;
bool serialized; // whether timer CSRs are in a well-defined state

Loading…
Cancel
Save