diff --git a/c_emulator/riscv_platform.c b/c_emulator/riscv_platform.c index 691b1efb3..916452a25 100644 --- a/c_emulator/riscv_platform.c +++ b/c_emulator/riscv_platform.c @@ -72,6 +72,11 @@ bool sys_enable_zicboz(unit u) return rv_enable_zicboz; } +bool sys_enable_sstc(unit u) +{ + return rv_enable_sstc; +} + uint64_t sys_pmp_count(unit u) { return rv_pmp_count; diff --git a/c_emulator/riscv_platform.h b/c_emulator/riscv_platform.h index 5f145b778..7e2482092 100644 --- a/c_emulator/riscv_platform.h +++ b/c_emulator/riscv_platform.h @@ -13,6 +13,7 @@ bool sys_enable_vext(unit); bool sys_enable_bext(unit); bool sys_enable_zicbom(unit); bool sys_enable_zicboz(unit); +bool sys_enable_sstc(unit); uint64_t sys_pmp_count(unit); uint64_t sys_pmp_grain(unit); diff --git a/c_emulator/riscv_platform_impl.c b/c_emulator/riscv_platform_impl.c index 4ae06c03e..e9e239ee2 100644 --- a/c_emulator/riscv_platform_impl.c +++ b/c_emulator/riscv_platform_impl.c @@ -17,6 +17,7 @@ bool rv_enable_vext = true; bool rv_enable_bext = false; bool rv_enable_zicbom = false; bool rv_enable_zicboz = false; +bool rv_enable_sstc = false; bool rv_enable_dirty_update = false; bool rv_enable_misaligned = false; diff --git a/c_emulator/riscv_platform_impl.h b/c_emulator/riscv_platform_impl.h index 367806be9..196d51dcb 100644 --- a/c_emulator/riscv_platform_impl.h +++ b/c_emulator/riscv_platform_impl.h @@ -21,6 +21,7 @@ extern bool rv_enable_vext; extern bool rv_enable_bext; extern bool rv_enable_zicbom; extern bool rv_enable_zicboz; +extern bool rv_enable_sstc; extern bool rv_enable_writable_misa; extern bool rv_enable_dirty_update; extern bool rv_enable_misaligned; diff --git a/c_emulator/riscv_sim.c b/c_emulator/riscv_sim.c index 3f812c5ec..4eb279df6 100644 --- a/c_emulator/riscv_sim.c +++ b/c_emulator/riscv_sim.c @@ -58,6 +58,7 @@ enum { OPT_ENABLE_ZCB, OPT_ENABLE_ZICBOM, OPT_ENABLE_ZICBOZ, + OPT_ENABLE_SSTC, OPT_CACHE_BLOCK_SIZE, }; @@ -434,6 +435,10 @@ static int process_args(int argc, char **argv) fprintf(stderr, "enabling Zicboz extension.\n"); rv_enable_zicboz = true; break; + case OPT_ENABLE_SSTC: + fprintf(stderr, "enabling Sstc extension.\n"); + rv_enable_sstc = true; + break; case OPT_CACHE_BLOCK_SIZE: block_size_exp = ilog2(atol(optarg)); diff --git a/model/riscv_csr_begin.sail b/model/riscv_csr_begin.sail index 29ff4eed8..d45e94ddc 100644 --- a/model/riscv_csr_begin.sail +++ b/model/riscv_csr_begin.sail @@ -111,6 +111,9 @@ mapping clause csr_name_map = 0x141 <-> "sepc" mapping clause csr_name_map = 0x142 <-> "scause" mapping clause csr_name_map = 0x143 <-> "stval" mapping clause csr_name_map = 0x144 <-> "sip" +/* Sstc - supervisor timer register */ +mapping clause csr_name_map = 0x14D <-> "stimecmp" +mapping clause csr_name_map = 0x15D <-> "stimecmph" /* supervisor protection and translation */ mapping clause csr_name_map = 0x180 <-> "satp" /* supervisor envcfg */ @@ -132,6 +135,7 @@ mapping clause csr_name_map = 0x306 <-> "mcounteren" mapping clause csr_name_map = 0x320 <-> "mcountinhibit" /* machine envcfg */ mapping clause csr_name_map = 0x30A <-> "menvcfg" +mapping clause csr_name_map = 0x31A <-> "menvcfgh" /* hardware performance counter event selection */ mapping clause csr_name_map = 0x323 <-> "mhpmevent3" mapping clause csr_name_map = 0x324 <-> "mhpmevent4" diff --git a/model/riscv_insts_zicsr.sail b/model/riscv_insts_zicsr.sail index 8e8c0dce2..f76080d3b 100644 --- a/model/riscv_insts_zicsr.sail +++ b/model/riscv_insts_zicsr.sail @@ -85,6 +85,8 @@ function clause read_CSR(0x141) = get_xret_target(Supervisor) & pc_alignment_mas function clause read_CSR(0x142) = scause.bits function clause read_CSR(0x143) = stval function clause read_CSR(0x144) = lower_mip(mip, mideleg).bits +function clause read_CSR(0x14D) = stimecmp[sizeof(xlen) - 1 .. 0] +function clause read_CSR(0x15D if xlen == 32) = stimecmp[63 .. 32] function clause read_CSR(0x180) = satp /* user mode counters */ @@ -173,6 +175,8 @@ function clause write_CSR(0x141, value) = { set_xret_target(Supervisor, value) } function clause write_CSR(0x142, value) = { scause.bits = value; scause.bits } function clause write_CSR(0x143, value) = { stval = value; stval } function clause write_CSR(0x144, value) = { mip = legalize_sip(mip, mideleg, value); mip.bits } +function clause write_CSR(0x14D, value) = { stimecmp[(sizeof(xlen) - 1) .. 0] = value; stimecmp[sizeof(xlen) - 1 ..0] } +function clause write_CSR((0x15D, value) if xlen == 32) = { stimecmp[63 ..32] = value; stimecmp[63 .. 32] } function clause write_CSR(0x180, value) = { satp = legalize_satp(cur_Architecture(), satp, value); satp } /* user mode: seed (entropy source). writes are ignored */ diff --git a/model/riscv_platform.sail b/model/riscv_platform.sail index e407d8aae..a0748ac9e 100644 --- a/model/riscv_platform.sail +++ b/model/riscv_platform.sail @@ -211,8 +211,17 @@ function clint_dispatch() -> unit = { if mtimecmp <=_u mtime then { if get_config_print_platform() then print_platform(" clint timer pending at mtime " ^ BitStr(mtime)); - mip[MTI] = 0b1 - } + mip[MTI] = 0b1; + }; + /* Sstc - supervisor timer register */ + if extensionEnabled(Ext_Sstc) then { + mip[STI] = 0b0; + if stimecmp <=_u mtime then { + if get_config_print_platform() + then print_platform(" supervisor timer pending at mtime " ^ BitStr(mtime)); + mip[STI] = 0b1; + } + }; } /* The rreg effect is due to checking mtime. */ diff --git a/model/riscv_sys_control.sail b/model/riscv_sys_control.sail index 80e6ea5c7..cd7a5aa1f 100644 --- a/model/riscv_sys_control.sail +++ b/model/riscv_sys_control.sail @@ -87,6 +87,10 @@ function clause is_CSR_defined(0x142) = extensionEnabled(Ext_S) // scause function clause is_CSR_defined(0x143) = extensionEnabled(Ext_S) // stval function clause is_CSR_defined(0x144) = extensionEnabled(Ext_S) // sip +/* Sstc : supervisor timer register */ +function clause is_CSR_defined(0x14D) = extensionEnabled(Ext_S) & extensionEnabled(Ext_Sstc) // stimecmp +function clause is_CSR_defined(0x15D) = extensionEnabled(Ext_S) & extensionEnabled(Ext_Sstc) // stimecmph + /* supervisor mode: address translation */ function clause is_CSR_defined(0x180) = extensionEnabled(Ext_S) // satp @@ -134,6 +138,15 @@ function check_Counteren(csr : csreg, p : Privilege) -> bool = { feature_enabled_for_priv(p, mcounteren.bits[index], scounteren.bits[index]) } +// Return true if the stimecmp[h] CSR is accessible OR the CSR is not stimecmp[h]. +function check_Stimecmp(csr : csreg, p : Privilege) -> bool = { + // Check if it is not stimecmp. + if csr != 0x14D & csr != 0x15D + then return true; + + p == Machine | (p == Supervisor & mcounteren[TM] == 0b1 & menvcfg[STCE] == 0b1) +} + /* Seed may only be accessed if we are doing a write, and access has been * allowed in the current priv mode */ @@ -155,8 +168,12 @@ function check_seed_CSR (csr : csreg, p : Privilege, isWrite : bool) -> bool = { function check_CSR(csr : csreg, p : Privilege, isWrite : bool) -> bool = is_CSR_defined(csr) & check_CSR_access(csrAccess(csr), csrPriv(csr), p, isWrite) + // TODO: If we add `p` back to is_CSR_defined() we could move these three + // check_ functions back there. We should also rename is_CSR_defined() + // to is_CSR_accessible() or similar. & check_TVM_SATP(csr, p) & check_Counteren(csr, p) + & check_Stimecmp(csr, p) & check_seed_CSR(csr, p, isWrite) /* Reservation handling for LR/SC. diff --git a/model/riscv_sys_regs.sail b/model/riscv_sys_regs.sail index edecc4ddf..0468aa206 100644 --- a/model/riscv_sys_regs.sail +++ b/model/riscv_sys_regs.sail @@ -116,6 +116,9 @@ val sys_enable_bext = pure "sys_enable_bext" : unit -> bool val sys_enable_zicbom = pure "sys_enable_zicbom" : unit -> bool val sys_enable_zicboz = pure "sys_enable_zicboz" : unit -> bool +// Is the Sstc stimecmp extension supported. +val sys_enable_sstc = pure "sys_enable_sstc" : unit -> bool + /* This function allows an extension to veto a write to Misa if it would violate an alignment restriction on unsetting C. If it returns true the write will have no effect. */ @@ -328,11 +331,56 @@ register mip : Minterrupts /* Pending */ register mie : Minterrupts /* Enabled */ register mideleg : Minterrupts /* Delegation to S-mode */ +bitfield MEnvcfg : bits(64) = { + // Supervisor TimeCmp Extension + STCE : 63, + // Page Based Memory Types Extension + PBMTE : 62, + // Reserved WPRI bits. + wpri_1 : 61 .. 8, + // Cache Block Zero instruction Enable + CBZE : 7, + // Cache Block Clean and Flush instruction Enable + CBCFE : 6, + // Cache Block Invalidate instruction Enable + CBIE : 5 .. 4, + // Reserved WPRI bits. + wpri_0 : 3 .. 1, + // Fence of I/O implies Memory + FIOM : 0, +} + +bitfield SEnvcfg : xlenbits = { + // Cache Block Zero instruction Enable + CBZE : 7, + // Cache Block Clean and Flush instruction Enable + CBCFE : 6, + // Cache Block Invalidate instruction Enable + CBIE : 5 .. 4, + // Reserved WPRI bits. + wpri_0 : 3 .. 1, + // Fence of I/O implies Memory + FIOM : 0, +} + +register menvcfg : MEnvcfg +register senvcfg : SEnvcfg + +/* Supervisor timecmp */ +enum clause extension = Ext_Sstc +function clause extensionEnabled(Ext_Sstc) = sys_enable_sstc() + function legalize_mip(o : Minterrupts, v : xlenbits) -> Minterrupts = { /* The only writable bits are the S-mode bits, and with the 'N' * extension, the U-mode bits. */ let v = Mk_Minterrupts(v); - let m = [o with SEI = v[SEI], STI = v[STI], SSI = v[SSI]]; + let m = [o with + SEI = v[SEI], + SSI = v[SSI], + // STI is read only if Sstc is enabled and STCE is set (it is equal to stimecmp <= mtime). + STI = if extensionEnabled(Ext_Sstc) & menvcfg[STCE] == 0b1 then o[STI] else v[STI], + ]; + if extensionEnabled(Ext_U) & extensionEnabled(Ext_N) then { [m with UEI = v[UEI], UTI = v[UTI], USI = v[USI]] } else m @@ -795,53 +843,21 @@ function read_seed_csr() -> xlenbits = { /* Writes to the seed CSR are ignored */ function write_seed_csr () -> xlenbits = zeros() -bitfield MEnvcfg : bits(64) = { - // Supervisor TimeCmp Extension - STCE : 63, - // Page Based Memory Types Extension - PBMTE : 62, - // Reserved WPRI bits. - wpri_1 : 61 .. 8, - // Cache Block Zero instruction Enable - CBZE : 7, - // Cache Block Clean and Flush instruction Enable - CBCFE : 6, - // Cache Block Invalidate instruction Enable - CBIE : 5 .. 4, - // Reserved WPRI bits. - wpri_0 : 3 .. 1, - // Fence of I/O implies Memory - FIOM : 0, -} - -bitfield SEnvcfg : xlenbits = { - // Cache Block Zero instruction Enable - CBZE : 7, - // Cache Block Clean and Flush instruction Enable - CBCFE : 6, - // Cache Block Invalidate instruction Enable - CBIE : 5 .. 4, - // Reserved WPRI bits. - wpri_0 : 3 .. 1, - // Fence of I/O implies Memory - FIOM : 0, -} - -register menvcfg : MEnvcfg -register senvcfg : SEnvcfg - function legalize_menvcfg(o : MEnvcfg, v : bits(64)) -> MEnvcfg = { let v = Mk_MEnvcfg(v); - let o = [o with FIOM = if sys_enable_writable_fiom() then v[FIOM] else 0b0]; - // Other extensions are not implemented yet so all other fields are read only zero. - o + [o with + FIOM = if sys_enable_writable_fiom() then v[FIOM] else 0b0, + STCE = if extensionEnabled(Ext_Sstc) then v[STCE] else 0b0, + // Other extensions are not implemented yet so all other fields are read only zero. + ] } function legalize_senvcfg(o : SEnvcfg, v : xlenbits) -> SEnvcfg = { let v = Mk_SEnvcfg(v); - let o = [o with FIOM = if sys_enable_writable_fiom() then v[FIOM] else 0b0]; - // Other extensions are not implemented yet so all other fields are read only zero. - o + [o with + FIOM = if sys_enable_writable_fiom() then v[FIOM] else 0b0, + // Other extensions are not implemented yet so all other fields are read only zero. + ]; } // Return whether or not FIOM is currently active, based on the current @@ -936,3 +952,6 @@ function get_vtype_vma() = decode_agtype(vtype[vma]) val get_vtype_vta : unit -> agtype function get_vtype_vta() = decode_agtype(vtype[vta]) + +/* Sstc : Supervisor Timer Register */ +register stimecmp : bits(64)