Add mcycle / mcycleh to Kelvin sim
PiperOrigin-RevId: 597650959
diff --git a/WORKSPACE b/WORKSPACE
index 3e2833e..54b618f 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -6,9 +6,9 @@
# MPACT-RiscV repo
http_archive(
name = "com_google_mpact-riscv",
- sha256 = "2f51e0d90f6adf639fe6b23bee6dd86283326d86f8952e60cb26abeccc1e939b",
- strip_prefix = "mpact-riscv-641f0748c6b17aa8789d455e82fb8f1296f79d26",
- url = "https://github.com/google/mpact-riscv/archive/641f0748c6b17aa8789d455e82fb8f1296f79d26.tar.gz",
+ sha256 = "68c65bae71654ce59f3bd047af9083840b4b463aee7a17ba7d75c84322534347",
+ strip_prefix = "mpact-riscv-a4c534a97b107f3734e04c8e32d182e49d400ac3",
+ url = "https://github.com/google/mpact-riscv/archive/a4c534a97b107f3734e04c8e32d182e49d400ac3.tar.gz",
)
# MPACT-Sim repo
diff --git a/sim/kelvin_state.cc b/sim/kelvin_state.cc
index 62b92f2..0c82a23 100644
--- a/sim/kelvin_state.cc
+++ b/sim/kelvin_state.cc
@@ -47,7 +47,9 @@
mpact::sim::util::MemoryInterface *memory,
mpact::sim::util::AtomicMemoryOpInterface *atomic_memory)
: mpact::sim::riscv::RiscVState(id, xlen, memory, atomic_memory),
- kisa_("kisa", static_cast<RiscVCsrEnum>(KelvinCsrEnum::kKIsa), this) {
+ kisa_("kisa", static_cast<RiscVCsrEnum>(KelvinCsrEnum::kKIsa), this),
+ mcycle_("mcycle", RiscVCsrEnum::kMCycle, this),
+ mcycleh_("mcycleh", RiscVCsrEnum::kMCycleH, this) {
set_vector_register_width(kVectorRegisterWidth);
for (int i = 0; i < acc_register_.size(); ++i) {
acc_register_[i].fill(0);
@@ -62,6 +64,13 @@
}
auto *misa = *result;
misa->Set(kKelvinMisaVal);
+
+ if (!csr_set()->AddCsr(&mcycle_).ok()) {
+ LOG(FATAL) << "Failed to register mcycle";
+ }
+ if (!csr_set()->AddCsr(&mcycleh_).ok()) {
+ LOG(FATAL) << "Failed to register mcycleh";
+ }
}
KelvinState::KelvinState(absl::string_view id,
@@ -129,4 +138,11 @@
log_args_.clear();
}
+void KelvinState::IncrementMCycle(uint64_t value) {
+ uint64_t new_cycle =
+ (mcycle_.GetUint64() | (mcycleh_.GetUint64() << 32)) + value;
+ mcycle_.Set(new_cycle & 0xFFFFFFFF);
+ mcycleh_.Set(new_cycle >> 32);
+}
+
} // namespace kelvin::sim
diff --git a/sim/kelvin_state.h b/sim/kelvin_state.h
index 5c66649..ffcfd84 100644
--- a/sim/kelvin_state.h
+++ b/sim/kelvin_state.h
@@ -97,6 +97,8 @@
on_mpause_.emplace_back(std::move(handler));
}
+ void IncrementMCycle(uint64_t value);
+
private:
uint32_t vector_length_{kVectorLengthInBits};
@@ -114,6 +116,10 @@
// Kelvin-specific CSR, contains information about the Kelvin ISA version.
mpact::sim::riscv::RiscV32SimpleCsr kisa_;
+
+ // mcycle/mcycleh CSR.
+ mpact::sim::riscv::RiscV32SimpleCsr mcycle_;
+ mpact::sim::riscv::RiscV32SimpleCsr mcycleh_;
};
} // namespace kelvin::sim
diff --git a/sim/kelvin_top.cc b/sim/kelvin_top.cc
index 26e2391..3b49bd2 100644
--- a/sim/kelvin_top.cc
+++ b/sim/kelvin_top.cc
@@ -252,7 +252,7 @@
bool executed = false;
do {
executed = ExecuteInstruction(real_inst);
- counter_num_cycles_.Increment(1);
+ IncrementCycleCount(1);
state_->AdvanceDelayLines();
} while (!executed);
// Increment counter.
@@ -309,7 +309,7 @@
bool executed = false;
do {
executed = ExecuteInstruction(inst);
- counter_num_cycles_.Increment(1);
+ IncrementCycleCount(1);
state_->AdvanceDelayLines();
} while (!executed);
count++;
@@ -406,7 +406,7 @@
trace_entry->set_disasm(inst->AsString());
}
}
- counter_num_cycles_.Increment(1);
+ IncrementCycleCount(1);
state_->AdvanceDelayLines();
} while (!executed);
// Update counters.
@@ -725,4 +725,9 @@
}
}
+void KelvinTop::IncrementCycleCount(uint64_t value) {
+ counter_num_cycles_.Increment(value);
+ state_->IncrementMCycle(value);
+}
+
} // namespace kelvin::sim
diff --git a/sim/kelvin_top.h b/sim/kelvin_top.h
index 1aa0637..5bab3d1 100644
--- a/sim/kelvin_top.h
+++ b/sim/kelvin_top.h
@@ -121,6 +121,8 @@
absl::Status StepPastBreakpoint();
// Set the pc value.
void SetPc(uint64_t value);
+ // Increment the cycle count.
+ void IncrementCycleCount(uint64_t value);
// The DB factory is used to manage data buffers for memory read/writes.
mpact::sim::generic::DataBufferFactory db_factory_;
diff --git a/sim/test/BUILD b/sim/test/BUILD
index a965726..b634ef2 100644
--- a/sim/test/BUILD
+++ b/sim/test/BUILD
@@ -20,6 +20,7 @@
"testfiles/hello_world_mpause.elf",
"testfiles/hello_world_rv32imf.elf",
"testfiles/kelvin_ebreak.elf",
+ "testfiles/kelvin_perf_counters.elf",
"testfiles/kelvin_vldvst.elf",
"testfiles/rv32i.elf",
"testfiles/rv32m.elf",
@@ -80,6 +81,7 @@
"testfiles/hello_world_mpause.elf",
"testfiles/hello_world_rv32imf.elf",
"testfiles/kelvin_ebreak.elf",
+ "testfiles/kelvin_perf_counters.elf",
"testfiles/kelvin_vldvst.elf",
"testfiles/rv32i.elf",
"testfiles/rv32m.elf",
diff --git a/sim/test/kelvin_top_test.cc b/sim/test/kelvin_top_test.cc
index b4883d7..3d9a956 100644
--- a/sim/test/kelvin_top_test.cc
+++ b/sim/test/kelvin_top_test.cc
@@ -51,6 +51,7 @@
constexpr char kRV32SoftFloatElfFileName[] = "rv32soft_fp.elf";
constexpr char kRV32fElfFileName[] = "rv32uf_fadd.elf";
constexpr char kKelvinVldVstFileName[] = "kelvin_vldvst.elf";
+constexpr char kKelvinPerfCountersFileName[] = "kelvin_perf_counters.elf";
// The depot path to the test directory.
constexpr char kDepotPath[] = "sim/test/";
@@ -474,6 +475,17 @@
EXPECT_THAT(stdout_str, testing::HasSubstr("vld_vst test passed!"));
}
+TEST_F(KelvinTopTest, RunKelvinPerfCountersProgram) {
+ LoadFile(kKelvinPerfCountersFileName);
+ EXPECT_OK(kelvin_top_->WriteRegister("pc", entry_point_));
+ EXPECT_OK(kelvin_top_->Run());
+ EXPECT_OK(kelvin_top_->Wait());
+ auto halt_result = kelvin_top_->GetLastHaltReason();
+ CHECK_OK(halt_result);
+ EXPECT_EQ(static_cast<int>(halt_result.value()),
+ static_cast<int>(HaltReason::kUserRequest));
+}
+
constexpr int kMemoryBlockSize = 256 * 1024; // 256KB
// Default max memory address is 4MB - 1. Round up to find the number of memory
// blocks.
diff --git a/sim/test/testfiles/kelvin_perf_counters.elf b/sim/test/testfiles/kelvin_perf_counters.elf
new file mode 100755
index 0000000..6037860
--- /dev/null
+++ b/sim/test/testfiles/kelvin_perf_counters.elf
Binary files differ