Add minstret to perf_counters
Change-Id: I3945606d8f082fdbd6bb2ecf68c7c35b3cfc03de
diff --git a/tests/kelvin_isa/perf_counters.cc b/tests/kelvin_isa/perf_counters.cc
index 937f820..5c79d92 100644
--- a/tests/kelvin_isa/perf_counters.cc
+++ b/tests/kelvin_isa/perf_counters.cc
@@ -22,22 +22,43 @@
inline uint64_t mcycle_read(void) {
uint32_t cycle_low = 0;
uint32_t cycle_high = 0;
+ uint32_t cycle_high_2 = 0;
asm volatile(
"1:"
" csrr %0, mcycleh;" // Read `mcycleh`.
" csrr %1, mcycle;" // Read `mcycle`.
- : "=r"(cycle_high), "=r"(cycle_low)
+ " csrr %2, mcycleh;" // Read `mcycleh` again.
+ " bne %0, %2, 1b;"
+ : "=r"(cycle_high), "=r"(cycle_low), "=r"(cycle_high_2)
:);
return static_cast<uint64_t>(cycle_high) << 32 | cycle_low;
}
+inline uint64_t minstret_read(void) {
+ uint32_t instret_low = 0;
+ uint32_t instret_high = 0;
+ uint32_t instret_high_2 = 0;
+ asm volatile(
+ "1:"
+ " csrr %0, minstreth;" // Read `minstreth`.
+ " csrr %1, minstret;" // Read `minstret`.
+ " csrr %2, minstreth;"
+ "bne %0, %2, 1b;"
+ : "=r"(instret_high), "=r"(instret_low), "=r"(instret_high_2)
+ :);
+ return static_cast<uint64_t>(instret_high) << 32 | instret_low;
+}
+
int main(void) {
- // Set the cycle counter to 0x1ffffffff.
+ // Set the cycle counter to 0x1fffffff0.
asm volatile (" \
csrwi mcycleh, 1; \
- li a0, 0xfffffffd; \
+ li a0, 0xfffffff0; \
csrrw a0, mcycle, a0;" : /* no outputs*/ : /* no inputs */ : /* clobbers */"a0");
uint64_t cycle = mcycle_read();
+ for (int i = 0; i < 16; ++i) {
+ asm volatile("nop");
+ }
uint64_t cycle2 = mcycle_read();
uint32_t cycle_lo, cycle_hi, cycle2_lo, cycle2_hi;
cycle_lo = cycle & 0xFFFFFFFF;
@@ -49,8 +70,33 @@
exit(-1);
}
if (cycle2_lo > cycle_lo) {
- printf("mcycle did not wrap");
+ printf("mcycle did not wrap\r\n");
exit(-1);
}
+
+ asm volatile (" \
+ csrwi minstreth, 1; \
+ li a0, 0xfffffff0; \
+ csrrw a0, minstret, a0; " : : : "a0");
+ uint64_t instret = minstret_read();
+#pragma GCC unroll 16
+ for (int i = 0; i < 16; ++i) {
+ asm volatile("nop");
+ }
+ uint64_t instret2 = minstret_read();
+ uint32_t instret_lo, instret_hi, instret2_lo, instret2_hi;
+ instret_lo = instret & 0xFFFFFFFF;
+ instret2_lo = instret2 & 0xFFFFFFFF;
+ instret_hi = instret >> 32;
+ instret2_hi = instret2 >> 32;
+ if (instret2_hi == instret_hi) {
+ printf("minstreth did not increment\r\n");
+ exit(-1);
+ }
+ if (instret2_lo > instret_lo) {
+ printf("minstret did not wrap\r\n");
+ exit(-1);
+ }
+
return 0;
}