aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Waterman <andrew@sifive.com>2024-03-21 13:21:31 -0700
committerGitHub <noreply@github.com>2024-03-21 13:21:31 -0700
commit2e86ec4b83c2fe3eb19669244357d288be8b45fa (patch)
tree4c11369a500362d979a17a6538af402fcdcf3aa9
parentd527f1e4df711af07f3a20a478aa187d7146feb1 (diff)
parent677e030594aa51ea8d6304d24b7da2ecd7006fe8 (diff)
downloadspike-2e86ec4b83c2fe3eb19669244357d288be8b45fa.zip
spike-2e86ec4b83c2fe3eb19669244357d288be8b45fa.tar.gz
spike-2e86ec4b83c2fe3eb19669244357d288be8b45fa.tar.bz2
Merge pull request #1582 from mylai-mtk/zicfilp-upstream
Support Zicfilp
-rw-r--r--disasm/disasm.cc6
-rw-r--r--disasm/isa_parser.cc2
-rw-r--r--riscv/csrs.cc24
-rw-r--r--riscv/csrs.h9
-rw-r--r--riscv/decode_macros.h20
-rw-r--r--riscv/encoding.h8
-rw-r--r--riscv/execute.cc2
-rw-r--r--riscv/insns/c_jalr.h4
-rw-r--r--riscv/insns/c_jr.h4
-rw-r--r--riscv/insns/dret.h3
-rw-r--r--riscv/insns/jalr.h4
-rw-r--r--riscv/insns/lpad.h6
-rw-r--r--riscv/insns/mret.h4
-rw-r--r--riscv/insns/sret.h6
-rw-r--r--riscv/isa_parser.h1
-rw-r--r--riscv/overlap_list.h1
-rw-r--r--riscv/processor.cc39
-rw-r--r--riscv/processor.h4
-rw-r--r--riscv/riscv.mk.in4
-rw-r--r--riscv/trap.h1
20 files changed, 140 insertions, 12 deletions
diff --git a/disasm/disasm.cc b/disasm/disasm.cc
index 65c15f5..a33cb71 100644
--- a/disasm/disasm.cc
+++ b/disasm/disasm.cc
@@ -868,6 +868,12 @@ void disassembler_t::add_instructions(const isa_parser_t* isa)
DEFINE_XAMO(amocas_h)
}
+ if (isa->extension_enabled(EXT_ZICFILP)) {
+ // lpad encodes as `auipc x0, label`, so it needs to be added before auipc
+ // for higher disassembling priority
+ DISASM_INSN("lpad", lpad, 0, {&bigimm});
+ }
+
add_insn(new disasm_insn_t("j", match_jal, mask_jal | mask_rd, {&jump_target}));
add_insn(new disasm_insn_t("jal", match_jal | match_rd_ra, mask_jal | mask_rd, {&jump_target}));
add_insn(new disasm_insn_t("jal", match_jal, mask_jal, {&xrd, &jump_target}));
diff --git a/disasm/isa_parser.cc b/disasm/isa_parser.cc
index 7a133e4..3a99d0a 100644
--- a/disasm/isa_parser.cc
+++ b/disasm/isa_parser.cc
@@ -306,6 +306,8 @@ isa_parser_t::isa_parser_t(const char* str, const char *priv)
extension_table[EXT_ZALASR] = true;
} else if (ext_str == "ssqosid") {
extension_table[EXT_SSQOSID] = true;
+ } else if (ext_str == "zicfilp") {
+ extension_table[EXT_ZICFILP] = true;
} else if (ext_str[0] == 'x') {
extension_table['X'] = true;
if (ext_str.size() == 1) {
diff --git a/riscv/csrs.cc b/riscv/csrs.cc
index 0e8bf6d..b1f4b7d 100644
--- a/riscv/csrs.cc
+++ b/riscv/csrs.cc
@@ -285,7 +285,8 @@ mseccfg_csr_t::mseccfg_csr_t(processor_t* const proc, const reg_t addr):
void mseccfg_csr_t::verify_permissions(insn_t insn, bool write) const {
basic_csr_t::verify_permissions(insn, write);
- if (!proc->extension_enabled(EXT_SMEPMP))
+ if (!proc->extension_enabled(EXT_SMEPMP) &&
+ !proc->extension_enabled(EXT_ZICFILP))
throw trap_illegal_instruction(insn.bits());
}
@@ -322,6 +323,11 @@ bool mseccfg_csr_t::unlogged_write(const reg_t val) noexcept {
proc->get_mmu()->flush_tlb();
+ if (proc->extension_enabled(EXT_ZICFILP)) {
+ new_val &= ~MSECCFG_MLPE;
+ new_val |= (val & MSECCFG_MLPE);
+ }
+
return basic_csr_t::unlogged_write(new_val);
}
@@ -414,6 +420,7 @@ reg_t base_status_csr_t::compute_sstatus_write_mask() const noexcept {
| (has_fs ? SSTATUS_FS : 0)
| (proc->any_custom_extensions() ? SSTATUS_XS : 0)
| (has_vs ? SSTATUS_VS : 0)
+ | (proc->extension_enabled(EXT_ZICFILP) ? SSTATUS_SPELP : 0)
;
}
@@ -497,7 +504,9 @@ bool mstatus_csr_t::unlogged_write(const reg_t val) noexcept {
| (proc->extension_enabled('S') ? MSTATUS_TSR : 0)
| (has_page ? MSTATUS_TVM : 0)
| (has_gva ? MSTATUS_GVA : 0)
- | (has_mpv ? MSTATUS_MPV : 0);
+ | (has_mpv ? MSTATUS_MPV : 0)
+ | (proc->extension_enabled(EXT_ZICFILP) ? (MSTATUS_SPELP | MSTATUS_MPELP) : 0)
+ ;
const reg_t requested_mpp = proc->legalize_privilege(get_field(val, MSTATUS_MPP));
const reg_t adjusted_val = set_field(val, MSTATUS_MPP, requested_mpp);
@@ -897,6 +906,7 @@ bool medeleg_csr_t::unlogged_write(const reg_t val) noexcept {
| (1 << CAUSE_LOAD_PAGE_FAULT)
| (1 << CAUSE_STORE_PAGE_FAULT)
| (proc->extension_enabled('H') ? hypervisor_exceptions : 0)
+ | (proc->extension_enabled(EXT_ZICFILP) ? (1 << CAUSE_SOFTWARE_CHECK_FAULT) : 0)
;
return basic_csr_t::unlogged_write((read() & ~mask) | (val & mask));
}
@@ -1284,7 +1294,8 @@ dcsr_csr_t::dcsr_csr_t(processor_t* const proc, const reg_t addr):
ebreakvu(false),
halt(false),
v(false),
- cause(0) {
+ cause(0),
+ pelp(elp_t::NO_LP_EXPECTED) {
}
void dcsr_csr_t::verify_permissions(insn_t insn, bool write) const {
@@ -1307,6 +1318,7 @@ reg_t dcsr_csr_t::read() const noexcept {
result = set_field(result, DCSR_STEP, step);
result = set_field(result, DCSR_PRV, prv);
result = set_field(result, CSR_DCSR_V, v);
+ result = set_field(result, DCSR_PELP, pelp);
return result;
}
@@ -1321,13 +1333,17 @@ bool dcsr_csr_t::unlogged_write(const reg_t val) noexcept {
ebreakvu = proc->extension_enabled('H') ? get_field(val, CSR_DCSR_EBREAKVU) : false;
halt = get_field(val, DCSR_HALT);
v = proc->extension_enabled('H') ? get_field(val, CSR_DCSR_V) : false;
+ pelp = proc->extension_enabled(EXT_ZICFILP) ?
+ static_cast<elp_t>(get_field(val, DCSR_PELP)) : elp_t::NO_LP_EXPECTED;
return true;
}
-void dcsr_csr_t::write_cause_and_prv(uint8_t cause, reg_t prv, bool v) noexcept {
+void dcsr_csr_t::update_fields(const uint8_t cause, const reg_t prv,
+ const bool v, const elp_t pelp) noexcept {
this->cause = cause;
this->prv = prv;
this->v = v;
+ this->pelp = pelp;
log_write();
}
diff --git a/riscv/csrs.h b/riscv/csrs.h
index b3dfe1c..990c301 100644
--- a/riscv/csrs.h
+++ b/riscv/csrs.h
@@ -21,6 +21,11 @@
class processor_t;
struct state_t;
+enum struct elp_t {
+ NO_LP_EXPECTED = 0,
+ LP_EXPECTED = 1,
+};
+
// Parent, abstract class for all CSRs
class csr_t {
public:
@@ -676,7 +681,8 @@ class dcsr_csr_t: public csr_t {
dcsr_csr_t(processor_t* const proc, const reg_t addr);
virtual void verify_permissions(insn_t insn, bool write) const override;
virtual reg_t read() const noexcept override;
- void write_cause_and_prv(uint8_t cause, reg_t prv, bool v) noexcept;
+ void update_fields(const uint8_t cause, const reg_t prv,
+ const bool v, const elp_t pelp) noexcept;
protected:
virtual bool unlogged_write(const reg_t val) noexcept override;
public:
@@ -690,6 +696,7 @@ class dcsr_csr_t: public csr_t {
bool halt;
bool v;
uint8_t cause;
+ elp_t pelp;
};
typedef std::shared_ptr<dcsr_csr_t> dcsr_csr_t_p;
diff --git a/riscv/decode_macros.h b/riscv/decode_macros.h
index e31da5c..4050000 100644
--- a/riscv/decode_macros.h
+++ b/riscv/decode_macros.h
@@ -321,3 +321,23 @@ inline long double to_f(float128_t f) { long double r; memcpy(&r, &f, sizeof(r))
reg_t h##field = get_field(STATE.henvcfg->read(), HENVCFG_##field)
#endif
+
+#define software_check(x, tval) (unlikely(!(x)) ? throw trap_software_check(tval) : (void) 0)
+#define ZICFILP_xLPE(v, prv) \
+ ({ \
+ reg_t lpe = 0ULL; \
+ if (p->extension_enabled(EXT_ZICFILP)) { \
+ DECLARE_XENVCFG_VARS(LPE); \
+ const reg_t msecLPE = get_field(STATE.mseccfg->read(), MSECCFG_MLPE); \
+ switch (prv) { \
+ case PRV_U: lpe = p->extension_enabled('S') ? sLPE : mLPE; break; \
+ case PRV_S: lpe = (v) ? hLPE : mLPE; break; \
+ case PRV_M: lpe = msecLPE; break; \
+ default: abort(); \
+ } \
+ } \
+ lpe; \
+ })
+#define ZICFILP_IS_LP_EXPECTED(reg_num) \
+ (((reg_num) != 1 && (reg_num) != 5 && (reg_num) != 7) ? \
+ elp_t::LP_EXPECTED : elp_t::NO_LP_EXPECTED)
diff --git a/riscv/encoding.h b/riscv/encoding.h
index 249b3fa..ff3f743 100644
--- a/riscv/encoding.h
+++ b/riscv/encoding.h
@@ -4,7 +4,7 @@
/*
* This file is auto-generated by running 'make' in
- * https://github.com/riscv/riscv-opcodes (a014979)
+ * https://github.com/riscv/riscv-opcodes (4ad822d)
*/
#ifndef RISCV_CSR_ENCODING_H
@@ -346,6 +346,9 @@
#define SRMCFG_RCID 0x00000FFF
#define SRMCFG_MCID 0x0FFF0000
+/* software check exception xtval codes */
+#define LANDING_PAD_FAULT 2
+
#ifdef __riscv
#if __riscv_xlen == 64
@@ -1464,6 +1467,8 @@
#define MASK_LH_AQ 0xfdf0707f
#define MATCH_LHU 0x5003
#define MASK_LHU 0x707f
+#define MATCH_LPAD 0x17
+#define MASK_LPAD 0xfff
#define MATCH_LQ 0x300f
#define MASK_LQ 0x707f
#define MATCH_LR_D 0x1000302f
@@ -4245,6 +4250,7 @@ DECLARE_INSN(ldu, MATCH_LDU, MASK_LDU)
DECLARE_INSN(lh, MATCH_LH, MASK_LH)
DECLARE_INSN(lh_aq, MATCH_LH_AQ, MASK_LH_AQ)
DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU)
+DECLARE_INSN(lpad, MATCH_LPAD, MASK_LPAD)
DECLARE_INSN(lq, MATCH_LQ, MASK_LQ)
DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D)
DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W)
diff --git a/riscv/execute.cc b/riscv/execute.cc
index 4f5860b..b2532c9 100644
--- a/riscv/execute.cc
+++ b/riscv/execute.cc
@@ -280,6 +280,7 @@ void processor_t::step(size_t n)
in_wfi = false;
insn_fetch_t fetch = mmu->load_insn(pc);
+ execute_insn_prehook(fetch.insn);
if (debug && !state.serialized)
disasm(fetch.insn);
pc = execute_insn_logged(this, pc, fetch);
@@ -291,6 +292,7 @@ void processor_t::step(size_t n)
// Main simulation loop, fast path.
for (auto ic_entry = _mmu->access_icache(pc); ; ) {
auto fetch = ic_entry->data;
+ execute_insn_prehook(fetch.insn);
pc = execute_insn_fast(this, pc, fetch);
ic_entry = ic_entry->next;
if (unlikely(ic_entry->tag != pc))
diff --git a/riscv/insns/c_jalr.h b/riscv/insns/c_jalr.h
index 0a00f1c..12bc7f9 100644
--- a/riscv/insns/c_jalr.h
+++ b/riscv/insns/c_jalr.h
@@ -3,3 +3,7 @@ require(insn.rvc_rs1() != 0);
reg_t tmp = npc;
set_pc(RVC_RS1 & ~reg_t(1));
WRITE_REG(X_RA, tmp);
+
+if (ZICFILP_xLPE(STATE.v, STATE.prv)) {
+ STATE.elp = ZICFILP_IS_LP_EXPECTED(insn.rvc_rs1());
+}
diff --git a/riscv/insns/c_jr.h b/riscv/insns/c_jr.h
index 020cafd..c5162e9 100644
--- a/riscv/insns/c_jr.h
+++ b/riscv/insns/c_jr.h
@@ -1,3 +1,7 @@
require_extension(EXT_ZCA);
require(insn.rvc_rs1() != 0);
set_pc(RVC_RS1 & ~reg_t(1));
+
+if (ZICFILP_xLPE(STATE.v, STATE.prv)) {
+ STATE.elp = ZICFILP_IS_LP_EXPECTED(insn.rvc_rs1());
+}
diff --git a/riscv/insns/dret.h b/riscv/insns/dret.h
index 2abcc7d..bdcf3db 100644
--- a/riscv/insns/dret.h
+++ b/riscv/insns/dret.h
@@ -1,5 +1,8 @@
require(STATE.debug_mode);
set_pc_and_serialize(STATE.dpc->read());
+if (ZICFILP_xLPE(STATE.dcsr->v, STATE.dcsr->prv)) {
+ STATE.elp = STATE.dcsr->pelp;
+}
p->set_privilege(STATE.dcsr->prv, STATE.dcsr->v);
if (STATE.prv < PRV_M)
STATE.mstatus->write(STATE.mstatus->read() & ~MSTATUS_MPRV);
diff --git a/riscv/insns/jalr.h b/riscv/insns/jalr.h
index 386e8db..0622a22 100644
--- a/riscv/insns/jalr.h
+++ b/riscv/insns/jalr.h
@@ -1,3 +1,7 @@
reg_t tmp = npc;
set_pc((RS1 + insn.i_imm()) & ~reg_t(1));
WRITE_RD(tmp);
+
+if (ZICFILP_xLPE(STATE.v, STATE.prv)) {
+ STATE.elp = ZICFILP_IS_LP_EXPECTED(insn.rs1());
+}
diff --git a/riscv/insns/lpad.h b/riscv/insns/lpad.h
new file mode 100644
index 0000000..733e91d
--- /dev/null
+++ b/riscv/insns/lpad.h
@@ -0,0 +1,6 @@
+if (ZICFILP_xLPE(STATE.v, STATE.prv) && STATE.elp == elp_t::LP_EXPECTED) {
+ software_check(pc % 4 == 0 &&
+ ((READ_REG(7) & 0xFFFFF000ULL) == (static_cast<uint64_t>(insn.u_imm()) & 0xFFFFF000ULL) || insn.u_imm() == 0LL),
+ LANDING_PAD_FAULT);
+ STATE.elp = elp_t::NO_LP_EXPECTED;
+}
diff --git a/riscv/insns/mret.h b/riscv/insns/mret.h
index 7cb1f62..1133e86 100644
--- a/riscv/insns/mret.h
+++ b/riscv/insns/mret.h
@@ -9,6 +9,10 @@ s = set_field(s, MSTATUS_MIE, get_field(s, MSTATUS_MPIE));
s = set_field(s, MSTATUS_MPIE, 1);
s = set_field(s, MSTATUS_MPP, p->extension_enabled('U') ? PRV_U : PRV_M);
s = set_field(s, MSTATUS_MPV, 0);
+if (ZICFILP_xLPE(prev_virt, prev_prv)) {
+ STATE.elp = static_cast<elp_t>(get_field(s, MSTATUS_MPELP));
+ s = set_field(s, MSTATUS_MPELP, elp_t::NO_LP_EXPECTED);
+}
STATE.mstatus->write(s);
if (STATE.mstatush) STATE.mstatush->write(s >> 32); // log mstatush change
p->set_privilege(prev_prv, prev_virt);
diff --git a/riscv/insns/sret.h b/riscv/insns/sret.h
index 4c7305d..aeaf087 100644
--- a/riscv/insns/sret.h
+++ b/riscv/insns/sret.h
@@ -13,7 +13,6 @@ reg_t prev_prv = get_field(s, MSTATUS_SPP);
s = set_field(s, MSTATUS_SIE, get_field(s, MSTATUS_SPIE));
s = set_field(s, MSTATUS_SPIE, 1);
s = set_field(s, MSTATUS_SPP, PRV_U);
-STATE.sstatus->write(s);
bool prev_virt = STATE.v;
if (!STATE.v) {
if (p->extension_enabled('H')) {
@@ -24,4 +23,9 @@ if (!STATE.v) {
STATE.mstatus->write(set_field(STATE.mstatus->read(), MSTATUS_MPRV, 0));
}
+if (ZICFILP_xLPE(prev_virt, prev_prv)) {
+ STATE.elp = static_cast<elp_t>(get_field(s, SSTATUS_SPELP));
+ s = set_field(s, SSTATUS_SPELP, elp_t::NO_LP_EXPECTED);
+}
+STATE.sstatus->write(s);
p->set_privilege(prev_prv, prev_virt);
diff --git a/riscv/isa_parser.h b/riscv/isa_parser.h
index f310b97..f02b55d 100644
--- a/riscv/isa_parser.h
+++ b/riscv/isa_parser.h
@@ -87,6 +87,7 @@ typedef enum {
EXT_ZCMOP,
EXT_ZALASR,
EXT_SSQOSID,
+ EXT_ZICFILP,
NUM_ISA_EXTENSIONS
} isa_extension_t;
diff --git a/riscv/overlap_list.h b/riscv/overlap_list.h
index 2214be4..3084c36 100644
--- a/riscv/overlap_list.h
+++ b/riscv/overlap_list.h
@@ -21,3 +21,4 @@ DECLARE_OVERLAP_INSN(rstsa16, EXT_ZPN)
DECLARE_OVERLAP_INSN(rstsa32, EXT_ZPN)
DECLARE_OVERLAP_INSN(srli32_u, EXT_ZPN)
DECLARE_OVERLAP_INSN(umax32, EXT_ZPN)
+DECLARE_OVERLAP_INSN(lpad, EXT_ZICFILP)
diff --git a/riscv/processor.cc b/riscv/processor.cc
index 1c0486b..347fff3 100644
--- a/riscv/processor.cc
+++ b/riscv/processor.cc
@@ -94,6 +94,14 @@ processor_t::~processor_t()
delete disassembler;
}
+static void zicfilp_check_if_lpad_required(const elp_t elp, insn_t insn)
+{
+ if (unlikely(elp == elp_t::LP_EXPECTED)) {
+ // also see riscv/lpad.h for more checks performed
+ software_check((insn.bits() & MASK_LPAD) == MATCH_LPAD, LANDING_PAD_FAULT);
+ }
+}
+
static void bad_option_string(const char *option, const char *value,
const char *msg)
{
@@ -374,7 +382,8 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
(1 << CAUSE_USER_ECALL) |
(1 << CAUSE_FETCH_PAGE_FAULT) |
(1 << CAUSE_LOAD_PAGE_FAULT) |
- (1 << CAUSE_STORE_PAGE_FAULT);
+ (1 << CAUSE_STORE_PAGE_FAULT) |
+ (1 << CAUSE_SOFTWARE_CHECK_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);
@@ -443,7 +452,8 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
(proc->extension_enabled(EXT_ZICBOZ) ? MENVCFG_CBZE : 0) |
(proc->extension_enabled(EXT_SVADU) ? MENVCFG_ADUE: 0) |
(proc->extension_enabled(EXT_SVPBMT) ? MENVCFG_PBMTE : 0) |
- (proc->extension_enabled(EXT_SSTC) ? MENVCFG_STCE : 0);
+ (proc->extension_enabled(EXT_SSTC) ? MENVCFG_STCE : 0) |
+ (proc->extension_enabled(EXT_ZICFILP) ? MENVCFG_LPE : 0);
const reg_t menvcfg_init = (proc->extension_enabled(EXT_SVPBMT) ? MENVCFG_PBMTE : 0);
menvcfg = std::make_shared<envcfg_csr_t>(proc, CSR_MENVCFG, menvcfg_mask, menvcfg_init);
if (xlen == 32) {
@@ -453,13 +463,15 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
csrmap[CSR_MENVCFG] = menvcfg;
}
const reg_t senvcfg_mask = (proc->extension_enabled(EXT_ZICBOM) ? SENVCFG_CBCFE | SENVCFG_CBIE : 0) |
- (proc->extension_enabled(EXT_ZICBOZ) ? SENVCFG_CBZE : 0);
+ (proc->extension_enabled(EXT_ZICBOZ) ? SENVCFG_CBZE : 0) |
+ (proc->extension_enabled(EXT_ZICFILP) ? SENVCFG_LPE : 0);
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_SVADU) ? HENVCFG_ADUE: 0) |
(proc->extension_enabled(EXT_SVPBMT) ? HENVCFG_PBMTE : 0) |
- (proc->extension_enabled(EXT_SSTC) ? HENVCFG_STCE : 0);
+ (proc->extension_enabled(EXT_SSTC) ? HENVCFG_STCE : 0) |
+ (proc->extension_enabled(EXT_ZICFILP) ? HENVCFG_LPE : 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) {
@@ -590,6 +602,8 @@ void state_t::reset(processor_t* const proc, reg_t max_isa)
last_inst_priv = 0;
last_inst_xlen = 0;
last_inst_flen = 0;
+
+ elp = elp_t::NO_LP_EXPECTED;
}
void processor_t::set_debug(bool value)
@@ -810,8 +824,10 @@ const char* processor_t::get_privilege_string()
void processor_t::enter_debug_mode(uint8_t cause)
{
+ const bool has_zicfilp = extension_enabled(EXT_ZICFILP);
state.debug_mode = true;
- state.dcsr->write_cause_and_prv(cause, state.prv, state.v);
+ state.dcsr->update_fields(cause, state.prv, state.v, state.elp);
+ state.elp = elp_t::NO_LP_EXPECTED;
set_privilege(PRV_M, false);
state.dpc->write(state.pc);
state.pc = DEBUG_ROM_ENTRY;
@@ -880,6 +896,8 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
s = set_field(s, MSTATUS_SPIE, get_field(s, MSTATUS_SIE));
s = set_field(s, MSTATUS_SPP, state.prv);
s = set_field(s, MSTATUS_SIE, 0);
+ s = set_field(s, MSTATUS_SPELP, state.elp);
+ state.elp = elp_t::NO_LP_EXPECTED;
state.sstatus->write(s);
set_privilege(PRV_S, true);
} else if (state.prv <= PRV_S && bit < max_xlen && ((hsdeleg >> bit) & 1)) {
@@ -896,6 +914,8 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
s = set_field(s, MSTATUS_SPIE, get_field(s, MSTATUS_SIE));
s = set_field(s, MSTATUS_SPP, state.prv);
s = set_field(s, MSTATUS_SIE, 0);
+ s = set_field(s, MSTATUS_SPELP, state.elp);
+ state.elp = elp_t::NO_LP_EXPECTED;
state.nonvirtual_sstatus->write(s);
if (extension_enabled('H')) {
s = state.hstatus->read();
@@ -927,6 +947,8 @@ void processor_t::take_trap(trap_t& t, reg_t epc)
s = set_field(s, MSTATUS_MIE, 0);
s = set_field(s, MSTATUS_MPV, curr_virt);
s = set_field(s, MSTATUS_GVA, t.has_gva());
+ s = set_field(s, MSTATUS_MPELP, state.elp);
+ state.elp = elp_t::NO_LP_EXPECTED;
state.mstatus->write(s);
if (state.mstatush) state.mstatush->write(s >> 32); // log mstatush change
set_privilege(PRV_M, false);
@@ -961,6 +983,13 @@ const char* processor_t::get_symbol(uint64_t addr)
return sim->get_symbol(addr);
}
+void processor_t::execute_insn_prehook(insn_t insn)
+{
+ if (extension_enabled(EXT_ZICFILP)) {
+ zicfilp_check_if_lpad_required(state.elp, insn);
+ }
+}
+
void processor_t::disasm(insn_t insn)
{
uint64_t bits = insn.bits();
diff --git a/riscv/processor.h b/riscv/processor.h
index 8a80ff6..ec42418 100644
--- a/riscv/processor.h
+++ b/riscv/processor.h
@@ -189,6 +189,8 @@ struct state_t
reg_t last_inst_priv;
int last_inst_xlen;
int last_inst_flen;
+
+ elp_t elp;
};
// this class represents one processor in a RISC-V machine.
@@ -315,6 +317,8 @@ public:
void clear_waiting_for_interrupt() { in_wfi = false; };
bool is_waiting_for_interrupt() { return in_wfi; };
+ void execute_insn_prehook(insn_t insn);
+
private:
const isa_parser_t * const isa;
const cfg_t * const cfg;
diff --git a/riscv/riscv.mk.in b/riscv/riscv.mk.in
index df557f5..0c4a14b 100644
--- a/riscv/riscv.mk.in
+++ b/riscv/riscv.mk.in
@@ -1392,6 +1392,9 @@ riscv_insn_ext_zimop = \
mop_r_N \
mop_rr_N \
+riscv_insn_ext_zicfilp = \
+ lpad
+
riscv_insn_ext_zvk = \
$(riscv_insn_ext_zvbb) \
$(riscv_insn_ext_zvbc) \
@@ -1431,6 +1434,7 @@ riscv_insn_list = \
$(riscv_insn_smrnmi) \
$(riscv_insn_svinval) \
$(riscv_insn_ext_zimop) \
+ $(riscv_insn_ext_zicfilp) \
riscv_gen_srcs = $(addsuffix .cc,$(riscv_insn_list))
diff --git a/riscv/trap.h b/riscv/trap.h
index 54948fd..5eb62cf 100644
--- a/riscv/trap.h
+++ b/riscv/trap.h
@@ -119,5 +119,6 @@ DECLARE_MEM_GVA_TRAP(CAUSE_FETCH_GUEST_PAGE_FAULT, instruction_guest_page_fault)
DECLARE_MEM_GVA_TRAP(CAUSE_LOAD_GUEST_PAGE_FAULT, load_guest_page_fault)
DECLARE_INST_TRAP(CAUSE_VIRTUAL_INSTRUCTION, virtual_instruction)
DECLARE_MEM_GVA_TRAP(CAUSE_STORE_GUEST_PAGE_FAULT, store_guest_page_fault)
+DECLARE_INST_TRAP(CAUSE_SOFTWARE_CHECK_FAULT, software_check)
#endif