Skip to content

Commit

Permalink
Add support for HPM counters
Browse files Browse the repository at this point in the history
Implements Hardware Performance Monitoring counters, but only by making the registers available. Their values only change if explicitly written to and all values are legal.

All 32 HPM counters are always implemented (the spec says this "should" be the case), and a platform callback `sys_writable_hpm_counters` is added to allow making any of them read-only. I haven't hooked `sys_writable_hpm_counters` up to CLI flags because Codasip does not use the CLI flags and it is quite tedious, and hopefully going to change when riscv-config is used.

Finally this adds `menvcfg` and `senvcfg` to the CSR name map which I forgot to do previously.
  • Loading branch information
Timmmm committed May 15, 2024
1 parent e1242d8 commit 008577f
Show file tree
Hide file tree
Showing 9 changed files with 260 additions and 22 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_writable_misa(unit u)
return rv_enable_writable_misa;
}

mach_bits sys_writable_hpm_counters(unit u)
{
return rv_writable_hpm_counters;
}

bool plat_enable_dirty_update(unit u)
{
return rv_enable_dirty_update;
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 @@ -10,6 +10,7 @@ bool sys_enable_zfinx(unit);
bool sys_enable_writable_misa(unit);
bool sys_enable_writable_fiom(unit);
bool sys_enable_vext(unit);
mach_bits sys_writable_hpm_counters(unit u);

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 @@ -14,6 +14,7 @@ bool rv_enable_next = false;
bool rv_enable_writable_misa = true;
bool rv_enable_fdext = true;
bool rv_enable_vext = true;
uint64_t rv_writable_hpm_counters = 0xFFFFFFFF;

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 @@ -18,6 +18,7 @@ extern bool rv_enable_rvc;
extern bool rv_enable_next;
extern bool rv_enable_fdext;
extern bool rv_enable_vext;
extern uint64_t rv_writable_hpm_counters;
extern bool rv_enable_writable_misa;
extern bool rv_enable_dirty_update;
extern bool rv_enable_misaligned;
Expand Down
150 changes: 148 additions & 2 deletions model/riscv_csr_map.sail
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,69 @@ mapping clause csr_name_map = 0x015 <-> "seed"
mapping clause csr_name_map = 0xC00 <-> "cycle"
mapping clause csr_name_map = 0xC01 <-> "time"
mapping clause csr_name_map = 0xC02 <-> "instret"
mapping clause csr_name_map = 0xC03 <-> "hpmcounter3"
mapping clause csr_name_map = 0xC04 <-> "hpmcounter4"
mapping clause csr_name_map = 0xC05 <-> "hpmcounter5"
mapping clause csr_name_map = 0xC06 <-> "hpmcounter6"
mapping clause csr_name_map = 0xC07 <-> "hpmcounter7"
mapping clause csr_name_map = 0xC08 <-> "hpmcounter8"
mapping clause csr_name_map = 0xC09 <-> "hpmcounter9"
mapping clause csr_name_map = 0xC0A <-> "hpmcounter10"
mapping clause csr_name_map = 0xC0B <-> "hpmcounter11"
mapping clause csr_name_map = 0xC0C <-> "hpmcounter12"
mapping clause csr_name_map = 0xC0D <-> "hpmcounter13"
mapping clause csr_name_map = 0xC0E <-> "hpmcounter14"
mapping clause csr_name_map = 0xC0F <-> "hpmcounter15"
mapping clause csr_name_map = 0xC10 <-> "hpmcounter16"
mapping clause csr_name_map = 0xC11 <-> "hpmcounter17"
mapping clause csr_name_map = 0xC12 <-> "hpmcounter18"
mapping clause csr_name_map = 0xC13 <-> "hpmcounter19"
mapping clause csr_name_map = 0xC14 <-> "hpmcounter20"
mapping clause csr_name_map = 0xC15 <-> "hpmcounter21"
mapping clause csr_name_map = 0xC16 <-> "hpmcounter22"
mapping clause csr_name_map = 0xC17 <-> "hpmcounter23"
mapping clause csr_name_map = 0xC18 <-> "hpmcounter24"
mapping clause csr_name_map = 0xC19 <-> "hpmcounter25"
mapping clause csr_name_map = 0xC1A <-> "hpmcounter26"
mapping clause csr_name_map = 0xC1B <-> "hpmcounter27"
mapping clause csr_name_map = 0xC1C <-> "hpmcounter28"
mapping clause csr_name_map = 0xC1D <-> "hpmcounter29"
mapping clause csr_name_map = 0xC1E <-> "hpmcounter30"
mapping clause csr_name_map = 0xC1F <-> "hpmcounter31"

mapping clause csr_name_map = 0xC80 <-> "cycleh"
mapping clause csr_name_map = 0xC81 <-> "timeh"
mapping clause csr_name_map = 0xC82 <-> "instreth"
/* TODO: other hpm counters */
mapping clause csr_name_map = 0xC83 <-> "hpmcounter3h"
mapping clause csr_name_map = 0xC84 <-> "hpmcounter4h"
mapping clause csr_name_map = 0xC85 <-> "hpmcounter5h"
mapping clause csr_name_map = 0xC86 <-> "hpmcounter6h"
mapping clause csr_name_map = 0xC87 <-> "hpmcounter7h"
mapping clause csr_name_map = 0xC88 <-> "hpmcounter8h"
mapping clause csr_name_map = 0xC89 <-> "hpmcounter9h"
mapping clause csr_name_map = 0xC8A <-> "hpmcounter10h"
mapping clause csr_name_map = 0xC8B <-> "hpmcounter11h"
mapping clause csr_name_map = 0xC8C <-> "hpmcounter12h"
mapping clause csr_name_map = 0xC8D <-> "hpmcounter13h"
mapping clause csr_name_map = 0xC8E <-> "hpmcounter14h"
mapping clause csr_name_map = 0xC8F <-> "hpmcounter15h"
mapping clause csr_name_map = 0xC90 <-> "hpmcounter16h"
mapping clause csr_name_map = 0xC91 <-> "hpmcounter17h"
mapping clause csr_name_map = 0xC92 <-> "hpmcounter18h"
mapping clause csr_name_map = 0xC93 <-> "hpmcounter19h"
mapping clause csr_name_map = 0xC94 <-> "hpmcounter20h"
mapping clause csr_name_map = 0xC95 <-> "hpmcounter21h"
mapping clause csr_name_map = 0xC96 <-> "hpmcounter22h"
mapping clause csr_name_map = 0xC97 <-> "hpmcounter23h"
mapping clause csr_name_map = 0xC98 <-> "hpmcounter24h"
mapping clause csr_name_map = 0xC99 <-> "hpmcounter25h"
mapping clause csr_name_map = 0xC9A <-> "hpmcounter26h"
mapping clause csr_name_map = 0xC9B <-> "hpmcounter27h"
mapping clause csr_name_map = 0xC9C <-> "hpmcounter28h"
mapping clause csr_name_map = 0xC9D <-> "hpmcounter29h"
mapping clause csr_name_map = 0xC9E <-> "hpmcounter30h"
mapping clause csr_name_map = 0xC9F <-> "hpmcounter31h"

/* supervisor trap setup */
mapping clause csr_name_map = 0x100 <-> "sstatus"
mapping clause csr_name_map = 0x102 <-> "sedeleg"
Expand Down Expand Up @@ -70,6 +129,36 @@ mapping clause csr_name_map = 0x306 <-> "mcounteren"
mapping clause csr_name_map = 0x320 <-> "mcountinhibit"
/* machine envcfg */
mapping clause csr_name_map = 0x30A <-> "menvcfg"
/* hardware performance counter event selection */
mapping clause csr_name_map = 0x323 <-> "mhpmevent3"
mapping clause csr_name_map = 0x324 <-> "mhpmevent4"
mapping clause csr_name_map = 0x325 <-> "mhpmevent5"
mapping clause csr_name_map = 0x326 <-> "mhpmevent6"
mapping clause csr_name_map = 0x327 <-> "mhpmevent7"
mapping clause csr_name_map = 0x328 <-> "mhpmevent8"
mapping clause csr_name_map = 0x329 <-> "mhpmevent9"
mapping clause csr_name_map = 0x32A <-> "mhpmevent10"
mapping clause csr_name_map = 0x32B <-> "mhpmevent11"
mapping clause csr_name_map = 0x32C <-> "mhpmevent12"
mapping clause csr_name_map = 0x32D <-> "mhpmevent13"
mapping clause csr_name_map = 0x32E <-> "mhpmevent14"
mapping clause csr_name_map = 0x32F <-> "mhpmevent15"
mapping clause csr_name_map = 0x330 <-> "mhpmevent16"
mapping clause csr_name_map = 0x331 <-> "mhpmevent17"
mapping clause csr_name_map = 0x332 <-> "mhpmevent18"
mapping clause csr_name_map = 0x333 <-> "mhpmevent19"
mapping clause csr_name_map = 0x334 <-> "mhpmevent20"
mapping clause csr_name_map = 0x335 <-> "mhpmevent21"
mapping clause csr_name_map = 0x336 <-> "mhpmevent22"
mapping clause csr_name_map = 0x337 <-> "mhpmevent23"
mapping clause csr_name_map = 0x338 <-> "mhpmevent24"
mapping clause csr_name_map = 0x339 <-> "mhpmevent25"
mapping clause csr_name_map = 0x33A <-> "mhpmevent26"
mapping clause csr_name_map = 0x33B <-> "mhpmevent27"
mapping clause csr_name_map = 0x33C <-> "mhpmevent28"
mapping clause csr_name_map = 0x33D <-> "mhpmevent29"
mapping clause csr_name_map = 0x33E <-> "mhpmevent30"
mapping clause csr_name_map = 0x33F <-> "mhpmevent31"
/* machine trap handling */
mapping clause csr_name_map = 0x340 <-> "mscratch"
mapping clause csr_name_map = 0x341 <-> "mepc"
Expand Down Expand Up @@ -160,9 +249,66 @@ mapping clause csr_name_map = 0x3EF <-> "pmpaddr63"
/* machine counters/timers */
mapping clause csr_name_map = 0xB00 <-> "mcycle"
mapping clause csr_name_map = 0xB02 <-> "minstret"
mapping clause csr_name_map = 0xB03 <-> "mhpmcounter3"
mapping clause csr_name_map = 0xB04 <-> "mhpmcounter4"
mapping clause csr_name_map = 0xB05 <-> "mhpmcounter5"
mapping clause csr_name_map = 0xB06 <-> "mhpmcounter6"
mapping clause csr_name_map = 0xB07 <-> "mhpmcounter7"
mapping clause csr_name_map = 0xB08 <-> "mhpmcounter8"
mapping clause csr_name_map = 0xB09 <-> "mhpmcounter9"
mapping clause csr_name_map = 0xB0A <-> "mhpmcounter10"
mapping clause csr_name_map = 0xB0B <-> "mhpmcounter11"
mapping clause csr_name_map = 0xB0C <-> "mhpmcounter12"
mapping clause csr_name_map = 0xB0D <-> "mhpmcounter13"
mapping clause csr_name_map = 0xB0E <-> "mhpmcounter14"
mapping clause csr_name_map = 0xB0F <-> "mhpmcounter15"
mapping clause csr_name_map = 0xB10 <-> "mhpmcounter16"
mapping clause csr_name_map = 0xB11 <-> "mhpmcounter17"
mapping clause csr_name_map = 0xB12 <-> "mhpmcounter18"
mapping clause csr_name_map = 0xB13 <-> "mhpmcounter19"
mapping clause csr_name_map = 0xB14 <-> "mhpmcounter20"
mapping clause csr_name_map = 0xB15 <-> "mhpmcounter21"
mapping clause csr_name_map = 0xB16 <-> "mhpmcounter22"
mapping clause csr_name_map = 0xB17 <-> "mhpmcounter23"
mapping clause csr_name_map = 0xB18 <-> "mhpmcounter24"
mapping clause csr_name_map = 0xB19 <-> "mhpmcounter25"
mapping clause csr_name_map = 0xB1A <-> "mhpmcounter26"
mapping clause csr_name_map = 0xB1B <-> "mhpmcounter27"
mapping clause csr_name_map = 0xB1C <-> "mhpmcounter28"
mapping clause csr_name_map = 0xB1D <-> "mhpmcounter29"
mapping clause csr_name_map = 0xB1E <-> "mhpmcounter30"
mapping clause csr_name_map = 0xB1F <-> "mhpmcounter31"
mapping clause csr_name_map = 0xB80 <-> "mcycleh"
mapping clause csr_name_map = 0xB82 <-> "minstreth"
/* TODO: other hpm counters and events */
mapping clause csr_name_map = 0xB83 <-> "mhpmcounter3h"
mapping clause csr_name_map = 0xB84 <-> "mhpmcounter4h"
mapping clause csr_name_map = 0xB85 <-> "mhpmcounter5h"
mapping clause csr_name_map = 0xB86 <-> "mhpmcounter6h"
mapping clause csr_name_map = 0xB87 <-> "mhpmcounter7h"
mapping clause csr_name_map = 0xB88 <-> "mhpmcounter8h"
mapping clause csr_name_map = 0xB89 <-> "mhpmcounter9h"
mapping clause csr_name_map = 0xB8A <-> "mhpmcounter10h"
mapping clause csr_name_map = 0xB8B <-> "mhpmcounter11h"
mapping clause csr_name_map = 0xB8C <-> "mhpmcounter12h"
mapping clause csr_name_map = 0xB8D <-> "mhpmcounter13h"
mapping clause csr_name_map = 0xB8E <-> "mhpmcounter14h"
mapping clause csr_name_map = 0xB8F <-> "mhpmcounter15h"
mapping clause csr_name_map = 0xB90 <-> "mhpmcounter16h"
mapping clause csr_name_map = 0xB91 <-> "mhpmcounter17h"
mapping clause csr_name_map = 0xB92 <-> "mhpmcounter18h"
mapping clause csr_name_map = 0xB93 <-> "mhpmcounter19h"
mapping clause csr_name_map = 0xB94 <-> "mhpmcounter20h"
mapping clause csr_name_map = 0xB95 <-> "mhpmcounter21h"
mapping clause csr_name_map = 0xB96 <-> "mhpmcounter22h"
mapping clause csr_name_map = 0xB97 <-> "mhpmcounter23h"
mapping clause csr_name_map = 0xB98 <-> "mhpmcounter24h"
mapping clause csr_name_map = 0xB99 <-> "mhpmcounter25h"
mapping clause csr_name_map = 0xB9A <-> "mhpmcounter26h"
mapping clause csr_name_map = 0xB9B <-> "mhpmcounter27h"
mapping clause csr_name_map = 0xB9C <-> "mhpmcounter28h"
mapping clause csr_name_map = 0xB9D <-> "mhpmcounter29h"
mapping clause csr_name_map = 0xB9E <-> "mhpmcounter30h"
mapping clause csr_name_map = 0xB9F <-> "mhpmcounter31h"
/* trigger/debug */
mapping clause csr_name_map = 0x7a0 <-> "tselect"
mapping clause csr_name_map = 0x7a1 <-> "tdata1"
Expand Down
28 changes: 28 additions & 0 deletions model/riscv_insts_zicsr.sail
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ function readCSR csr : csreg -> xlenbits = {
(0x31A, 32) => menvcfg.bits[63 .. 32],
(0x320, _) => zero_extend(mcountinhibit.bits),

/* Hardware Performance Monitoring event selection */
(0b0011001 /* 0x320 */ @ index : bits(5), _) if unsigned(index) >= 3 => read_mhpmevent(hpmidx_from_bits(index)),

(0x340, _) => mscratch,
(0x341, _) => get_xret_target(Machine) & pc_alignment_mask(),
(0x342, _) => mcause.bits,
Expand All @@ -62,6 +65,10 @@ function readCSR csr : csreg -> xlenbits = {
(0xB80, 32) => mcycle[63 .. 32],
(0xB82, 32) => minstret[63 .. 32],

/* Hardware Performance Monitoring machine mode counters */
(0b1011000 /* 0xB00 */ @ index : bits(5), _) if unsigned(index) >= 3 => read_mhpmcounter(hpmidx_from_bits(index)),
(0b1011100 /* 0xB80 */ @ index : bits(5), 32) if unsigned(index) >= 3 => read_mhpmcounterh(hpmidx_from_bits(index)),

/* vector */
(0x008, _) => zero_extend(vstart),
(0x009, _) => zero_extend(vxsat),
Expand Down Expand Up @@ -97,6 +104,10 @@ function readCSR csr : csreg -> xlenbits = {
(0xC81, 32) => mtime[63 .. 32],
(0xC82, 32) => minstret[63 .. 32],

/* Hardware Performance Monitoring user mode counters */
(0b1100000 /* 0xC00 */ @ index : bits(5), _) if unsigned(index) >= 3 => read_mhpmcounter(hpmidx_from_bits(index)),
(0b1100100 /* 0xC80 */ @ index : bits(5), 32) if unsigned(index) >= 3 => read_mhpmcounterh(hpmidx_from_bits(index)),

/* user mode: Zkr */
(0x015, _) => read_seed_csr(),

Expand Down Expand Up @@ -152,6 +163,23 @@ function writeCSR (csr : csreg, value : xlenbits) -> unit = {
(0xB80, 32) => { mcycle[63 .. 32] = value; Some(value) },
(0xB82, 32) => { minstret[63 .. 32] = value; minstret_increment = false; Some(value) },

/* Hardware Performance Monitoring machine mode counters */
(0b0011001 /* 0x320 */ @ index : bits(5), _) if unsigned(index) >= 3 => {
let index = hpmidx_from_bits(index);
write_mhpmevent(index, value);
Some(read_mhpmevent(index))
},
(0b1011000 /* 0xB00 */ @ index : bits(5), _) if unsigned(index) >= 3 => {
let index = hpmidx_from_bits(index);
write_mhpmcounter(index, value);
Some(read_mhpmcounter(index))
},
(0b1011100 /* 0xB80 */ @ index : bits(5), 32) if unsigned(index) >= 3 => {
let index = hpmidx_from_bits(index);
write_mhpmcounterh(index, value);
Some(read_mhpmcounterh(index))
},

/* trigger/debug */
(0x7a0, _) => { tselect = value; Some(tselect) },

Expand Down
42 changes: 28 additions & 14 deletions model/riscv_sys_control.sail
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,20 @@ function is_CSR_defined (csr : csreg, p : Privilege) -> bool =
0x3C @ idx : bits(4) => p == Machine & sys_pmp_count() > unsigned(0b01 @ idx),
0x3D @ idx : bits(4) => p == Machine & sys_pmp_count() > unsigned(0b10 @ idx),
0x3E @ idx : bits(4) => p == Machine & sys_pmp_count() > unsigned(0b11 @ idx),

/* counters */
0b0011001 /* 0x320 */ @ index : bits(5) if unsigned(index) >= 3 => haveZihpm() & p == Machine, // mhpmevent3..31

0xB00 => p == Machine, // mcycle
0xB02 => p == Machine, // minstret

0b1011000 /* 0xB00 */ @ index : bits(5) if unsigned(index) >= 3 => haveZihpm() & p == Machine, // mhpmcounter3..31

0xB80 => p == Machine & (sizeof(xlen) == 32), // mcycleh
0xB82 => p == Machine & (sizeof(xlen) == 32), // minstreth

0b1011100 /* 0xB80 */ @ index : bits(5) if unsigned(index) >= 3 => haveZihpm() & p == Machine & (sizeof(xlen) == 32), // mhpmcounterh3..31

/* disabled trigger/debug module */
0x7a0 => p == Machine,

Expand Down Expand Up @@ -82,10 +90,14 @@ function is_CSR_defined (csr : csreg, p : Privilege) -> bool =
0xC01 => haveUsrMode(), // time
0xC02 => haveUsrMode(), // instret

0b1100000 /* 0xC00 */ @ index : bits(5) if unsigned(index) >= 3 => haveZihpm() & haveUsrMode(), // hpmcounter3..31

0xC80 => haveUsrMode() & (sizeof(xlen) == 32), // cycleh
0xC81 => haveUsrMode() & (sizeof(xlen) == 32), // timeh
0xC82 => haveUsrMode() & (sizeof(xlen) == 32), // instreth

0b1100100 /* 0xC80 */ @ index : bits(5) if unsigned(index) >= 3 => haveZihpm() & haveUsrMode() & (sizeof(xlen) == 32), // hpmcounterh3..31

/* user mode: Zkr */
0x015 => haveZkr(),

Expand All @@ -101,22 +113,24 @@ function check_CSR_access(csrrw, csrpr, p, isWrite) =
function check_TVM_SATP(csr : csreg, p : Privilege) -> bool =
not(csr == 0x180 & p == Supervisor & mstatus[TVM] == 0b1)

function check_Counteren(csr : csreg, p : Privilege) -> bool =
match(csr, p) {
(0xC00, Supervisor) => mcounteren[CY] == 0b1,
(0xC01, Supervisor) => mcounteren[TM] == 0b1,
(0xC02, Supervisor) => mcounteren[IR] == 0b1,
// There are several features that are controlled by machine/supervisor enable
// bits (m/senvcfg, m/scounteren, etc.). This abstracts that logic.
function feature_enabled_for_priv(p : Privilege, machine_enable_bit : bit, supervisor_enable_bit : bit) -> bool = match p {
Machine => true,
Supervisor => machine_enable_bit == bitone,
User => machine_enable_bit == bitone & (not(haveSupMode()) | supervisor_enable_bit == bitone),
}

(0xC00, User) => mcounteren[CY] == 0b1 & (not(haveSupMode()) | scounteren[CY] == 0b1),
(0xC01, User) => mcounteren[TM] == 0b1 & (not(haveSupMode()) | scounteren[TM] == 0b1),
(0xC02, User) => mcounteren[IR] == 0b1 & (not(haveSupMode()) | scounteren[IR] == 0b1),

(_, _) => /* no HPM counters for now */
if 0xC03 <=_u csr & csr <=_u 0xC1F
then false
else true
}
// Return true if the counter is enabled OR the CSR is not a counter.
function check_Counteren(csr : csreg, p : Privilege) -> bool = {
// Check if it is not a counter.
if csr <_u 0xC00 | 0xC1F <_u csr
then return true;

// Check the relevant bit in m/scounteren.
let index = unsigned(csr[4 .. 0]);
feature_enabled_for_priv(p, mcounteren.bits()[index], scounteren.bits()[index])
}

/* Seed may only be accessed if we are doing a write, and access has been
* allowed in the current priv mode
Expand Down
Loading

0 comments on commit 008577f

Please sign in to comment.