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; }