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