Skip to content

Commit

Permalink
Add Sstc extension
Browse files Browse the repository at this point in the history
This adds the stimecmp[h] CSRs. It is enabled by default.

The code is slightly unfortunately structured to handle CSRs that don't fit the standard permission checks. I added a TODO to improve it.

Co-authored-by: Tim Hutt <[email protected]>
  • Loading branch information
ved-rivos and Timmmm committed Oct 2, 2024
1 parent 47380fa commit 25ebc9e
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 44 deletions.
5 changes: 5 additions & 0 deletions c_emulator/riscv_platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions c_emulator/riscv_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions c_emulator/riscv_platform_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions c_emulator/riscv_platform_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions c_emulator/riscv_sim.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ enum {
OPT_ENABLE_ZCB,
OPT_ENABLE_ZICBOM,
OPT_ENABLE_ZICBOZ,
OPT_ENABLE_SSTC,
OPT_CACHE_BLOCK_SIZE,
};

Expand Down Expand Up @@ -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));

Expand Down
4 changes: 4 additions & 0 deletions model/riscv_csr_begin.sail
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions model/riscv_insts_zicsr.sail
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */
Expand Down
13 changes: 11 additions & 2 deletions model/riscv_platform.sail
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
17 changes: 17 additions & 0 deletions model/riscv_sys_control.sail
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
*/
Expand All @@ -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.
Expand Down
103 changes: 61 additions & 42 deletions model/riscv_sys_regs.sail
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)

0 comments on commit 25ebc9e

Please sign in to comment.