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.
  • Loading branch information
Timmmm committed Sep 4, 2024
1 parent a58c58c commit 947a20d
Show file tree
Hide file tree
Showing 9 changed files with 254 additions and 23 deletions.
5 changes: 5 additions & 0 deletions c_emulator/riscv_platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,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 @@ -20,6 +20,7 @@ uint64_t sys_pmp_grain(unit);
bool plat_enable_dirty_update(unit);
bool plat_enable_misaligned_access(unit);
bool plat_mtval_has_illegal_inst_bits(unit);
mach_bits sys_writable_hpm_counters(unit u);

mach_bits plat_ram_base(unit);
mach_bits plat_ram_size(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 @@ -22,6 +22,7 @@ bool rv_enable_dirty_update = false;
bool rv_enable_misaligned = false;
bool rv_mtval_has_illegal_inst_bits = false;
bool rv_enable_writable_fiom = true;
uint64_t rv_writable_hpm_counters = 0xFFFFFFFF;

uint64_t rv_ram_base = UINT64_C(0x80000000);
uint64_t rv_ram_size = UINT64_C(0x4000000);
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 @@ -26,6 +26,7 @@ extern bool rv_enable_dirty_update;
extern bool rv_enable_misaligned;
extern bool rv_mtval_has_illegal_inst_bits;
extern bool rv_enable_writable_fiom;
extern uint64_t rv_writable_hpm_counters;

extern uint64_t rv_ram_base;
extern uint64_t rv_ram_size;
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
36 changes: 21 additions & 15 deletions model/riscv_sys_control.sail
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,20 @@ function is_CSR_defined (csr : csreg) -> bool =
0x3C @ idx : bits(4) => sys_pmp_count() > unsigned(0b01 @ idx),
0x3D @ idx : bits(4) => sys_pmp_count() > unsigned(0b10 @ idx),
0x3E @ idx : bits(4) => sys_pmp_count() > unsigned(0b11 @ idx),

/* counters */
0b0011001 /* 0x320 */ @ index : bits(5) if unsigned(index) >= 3 => extensionEnabled(Ext_Zihpm), // mhpmevent3..31

0xB00 => true, // mcycle
0xB02 => true, // minstret

0b1011000 /* 0xB00 */ @ index : bits(5) if unsigned(index) >= 3 => extensionEnabled(Ext_Zihpm), // mhpmcounter3..31

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

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

/* disabled trigger/debug module */
0x7a0 => true,

Expand Down Expand Up @@ -84,10 +92,14 @@ function is_CSR_defined (csr : csreg) -> bool =
0xC01 => extensionEnabled(Ext_U), // time
0xC02 => extensionEnabled(Ext_U), // instret

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

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

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

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

Expand All @@ -111,22 +123,16 @@ function feature_enabled_for_priv(p : Privilege, machine_enable_bit : bit, super
User => machine_enable_bit == bitone & (not(extensionEnabled(Ext_S)) | supervisor_enable_bit == bitone),
}

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,

(0xC00, User) => mcounteren[CY] == 0b1 & (not(extensionEnabled(Ext_S)) | scounteren[CY] == 0b1),
(0xC01, User) => mcounteren[TM] == 0b1 & (not(extensionEnabled(Ext_S)) | scounteren[TM] == 0b1),
(0xC02, User) => mcounteren[IR] == 0b1 & (not(extensionEnabled(Ext_S)) | 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 947a20d

Please sign in to comment.