Adding mcycle/mcycleh CSRs, and refactoring how CRSs with counters work.
PiperOrigin-RevId: 670687615
Change-Id: I018468528f28cd48eaf7a08f6dbdd9f1aac471eb
diff --git a/cheriot/BUILD b/cheriot/BUILD
index 3e2156a..4085f38 100644
--- a/cheriot/BUILD
+++ b/cheriot/BUILD
@@ -175,14 +175,12 @@
"cheriot_register.cc",
"cheriot_state.cc",
"cheriot_vector_true_operand.cc",
- "riscv_cheriot_minstret.cc",
],
hdrs = [
"cheriot_register.h",
"cheriot_state.h",
"cheriot_vector_true_operand.h",
"riscv_cheriot_csr_enum.h",
- "riscv_cheriot_minstret.h",
"riscv_cheriot_register_aliases.h",
],
tags = ["not_run:arm"],
@@ -587,6 +585,7 @@
"@com_google_absl//absl/time",
"@com_google_mpact-riscv//riscv:riscv_arm_semihost",
"@com_google_mpact-riscv//riscv:riscv_clint",
+ "@com_google_mpact-riscv//riscv:riscv_state",
"@com_google_mpact-riscv//riscv:stoull_wrapper",
"@com_google_mpact-sim//mpact/sim/generic:core",
"@com_google_mpact-sim//mpact/sim/generic:core_debug_interface",
diff --git a/cheriot/cheriot_renode.cc b/cheriot/cheriot_renode.cc
index 88d2ea1..30ea54a 100644
--- a/cheriot/cheriot_renode.cc
+++ b/cheriot/cheriot_renode.cc
@@ -23,6 +23,7 @@
#include <ios>
#include <iostream>
#include <memory>
+#include <new>
#include <string>
#include <string_view>
@@ -44,7 +45,6 @@
#include "cheriot/cheriot_state.h"
#include "cheriot/cheriot_top.h"
#include "cheriot/debug_command_shell.h"
-#include "cheriot/riscv_cheriot_minstret.h"
#include "mpact/sim/generic/core_debug_interface.h"
#include "mpact/sim/generic/type_helpers.h"
#include "mpact/sim/proto/component_data.pb.h"
@@ -57,6 +57,7 @@
#include "mpact/sim/util/renode/renode_debug_interface.h"
#include "riscv//riscv_arm_semihost.h"
#include "riscv//riscv_clint.h"
+#include "riscv//riscv_counter_csr.h"
#include "riscv//riscv_state.h"
#include "riscv//stoull_wrapper.h"
#include "src/google/protobuf/text_format.h"
@@ -77,10 +78,10 @@
namespace sim {
namespace cheriot {
-using ::mpact::sim::cheriot::RiscVCheriotMInstret;
-using ::mpact::sim::cheriot::RiscVCheriotMInstreth;
using ::mpact::sim::proto::ComponentData;
using ::mpact::sim::riscv::RiscVClint;
+using ::mpact::sim::riscv::RiscVCounterCsr;
+using ::mpact::sim::riscv::RiscVCounterCsrHigh;
using ::mpact::sim::util::AtomicMemoryOpInterface;
using ::mpact::sim::util::TaggedMemoryWatcher;
using ::mpact::sim::util::TaggedToUntaggedMemoryTransactor;
@@ -500,11 +501,26 @@
return absl::InternalError(
absl::StrCat(name_, ": Error while initializing minstret/minstreth\n"));
}
- auto *minstret = static_cast<RiscVCheriotMInstret *>(minstret_res.value());
- auto *minstreth = static_cast<RiscVCheriotMInstreth *>(minstreth_res.value());
+ auto *minstret = static_cast<RiscVCounterCsr<uint32_t, CheriotState> *>(
+ minstret_res.value());
+ auto *minstreth =
+ static_cast<RiscVCounterCsrHigh<CheriotState> *>(minstreth_res.value());
minstret->set_counter(cheriot_top_->counter_num_instructions());
minstreth->set_counter(cheriot_top_->counter_num_instructions());
-
+ // Initialize mcycle/mcycleh. Bind the instruction counter to those
+ // registers.
+ auto mcycle_res = cheriot_top_->state()->csr_set()->GetCsr("mcycle");
+ auto mcycleh_res = cheriot_top_->state()->csr_set()->GetCsr("mcycleh");
+ if (!mcycle_res.ok() || !mcycleh_res.ok()) {
+ return absl::InternalError(
+ absl::StrCat(name_, ": Error while initializing mcycle/mcycleh\n"));
+ }
+ auto *mcycle = static_cast<RiscVCounterCsr<uint32_t, CheriotState> *>(
+ mcycle_res.value());
+ auto *mcycleh =
+ static_cast<RiscVCounterCsrHigh<CheriotState> *>(mcycleh_res.value());
+ mcycle->set_counter(cheriot_top_->counter_num_cycles());
+ mcycleh->set_counter(cheriot_top_->counter_num_cycles());
// Set up the memory router with the system bus. Other devices are added once
// config info has been received. Add a tagged default memory transactor, so
// that any tagged loads/stores are forward to the sysbus without tags.
diff --git a/cheriot/cheriot_state.cc b/cheriot/cheriot_state.cc
index 685e6d0..39ac0bf 100644
--- a/cheriot/cheriot_state.cc
+++ b/cheriot/cheriot_state.cc
@@ -17,6 +17,7 @@
#include <algorithm>
#include <cstdint>
#include <limits>
+#include <new>
#include <string>
#include <string_view>
#include <utility>
@@ -28,12 +29,12 @@
#include "absl/strings/str_cat.h"
#include "cheriot/cheriot_register.h"
#include "cheriot/riscv_cheriot_csr_enum.h"
-#include "cheriot/riscv_cheriot_minstret.h"
#include "mpact/sim/generic/arch_state.h"
#include "mpact/sim/generic/type_helpers.h"
#include "mpact/sim/util/memory/memory_interface.h"
#include "mpact/sim/util/memory/tagged_flat_demand_memory.h"
#include "mpact/sim/util/memory/tagged_memory_interface.h"
+#include "riscv//riscv_counter_csr.h"
#include "riscv//riscv_csr.h"
#include "riscv//riscv_misa.h"
#include "riscv//riscv_pmp.h"
@@ -51,6 +52,8 @@
using EC = ::mpact::sim::riscv::ExceptionCode;
using ::mpact::sim::generic::operator*; // NOLINT: used below (clang error).
using ::mpact::sim::riscv::IsaExtension;
+using ::mpact::sim::riscv::RiscVCounterCsr;
+using ::mpact::sim::riscv::RiscVCounterCsrHigh;
using ::mpact::sim::riscv::RiscVCsrEnum;
using ::mpact::sim::riscv::RiscVCsrInterface;
using ::mpact::sim::riscv::RiscVPmp;
@@ -191,10 +194,23 @@
CHECK_NE(mtval, nullptr);
// minstret/minstreth
- CHECK_NE(CreateCsr<RiscVCheriotMInstret>(state, csr_vec, "minstret", state),
- nullptr);
- CHECK_NE(CreateCsr<RiscVCheriotMInstreth>(state, csr_vec, "minstreth", state),
- nullptr);
+ auto *minstret = CreateCsr<RiscVCounterCsr<T, CheriotState>>(
+ state, csr_vec, "minstret", RiscVCsrEnum ::kMInstret, state);
+ CHECK_NE(minstret, nullptr);
+ if (sizeof(T) == sizeof(uint32_t)) {
+ CHECK_NE(CreateCsr<RiscVCounterCsrHigh<CheriotState>>(
+ state, csr_vec, "minstreth", RiscVCsrEnum::kMInstretH, state),
+ nullptr);
+ }
+ // mcycle/mcycleh
+ auto *mcycle = CreateCsr<RiscVCounterCsr<T, CheriotState>>(
+ state, csr_vec, "mcycle", RiscVCsrEnum::kMCycle, state);
+ CHECK_NE(mcycle, nullptr);
+ if (sizeof(T) == sizeof(uint32_t)) {
+ CHECK_NE(CreateCsr<RiscVCounterCsrHigh<CheriotState>>(
+ state, csr_vec, "mcycleh", RiscVCsrEnum::kMCycleH, state),
+ nullptr);
+ }
// Stack high water mark CSRs. Mshwm gets updated automatically during
// execution. mshwm
diff --git a/cheriot/cheriot_test_rig.cc b/cheriot/cheriot_test_rig.cc
index c794a9c..91e17ec 100644
--- a/cheriot/cheriot_test_rig.cc
+++ b/cheriot/cheriot_test_rig.cc
@@ -16,6 +16,7 @@
#include <cstdint>
#include <cstring>
+#include <new>
#include <string>
#include "absl/functional/bind_front.h"
@@ -26,12 +27,12 @@
#include "cheriot/cheriot_register.h"
#include "cheriot/cheriot_state.h"
#include "cheriot/cheriot_test_rig_decoder.h"
-#include "cheriot/riscv_cheriot_minstret.h"
#include "cheriot/riscv_cheriot_register_aliases.h"
#include "cheriot/test_rig_packets.h"
#include "mpact/sim/generic/component.h"
#include "mpact/sim/util/memory/tagged_flat_demand_memory.h"
#include "mpact/sim/util/memory/tagged_memory_watcher.h"
+#include "riscv//riscv_counter_csr.h"
#include "riscv//riscv_register.h"
#include "riscv//riscv_state.h"
@@ -40,6 +41,8 @@
using EC = ::mpact::sim::riscv::ExceptionCode;
using PB = ::mpact::sim::cheriot::CheriotRegister::PermissionBits;
using CheriotEC = ::mpact::sim::cheriot::ExceptionCode;
+using ::mpact::sim::riscv::RiscVCounterCsr;
+using ::mpact::sim::riscv::RiscVCounterCsrHigh;
using ::mpact::sim::util::TaggedFlatDemandMemory;
using ::mpact::sim::util::TaggedMemoryWatcher;
@@ -105,13 +108,27 @@
// registers.
auto minstret_res = state_->csr_set()->GetCsr("minstret");
auto minstreth_res = state_->csr_set()->GetCsr("minstreth");
- if (!minstret_res.ok() || !minstreth_res.ok()) {
- LOG(ERROR) << "Error while initializing minstret/minstreth";
- }
- auto *minstret = static_cast<RiscVCheriotMInstret *>(minstret_res.value());
- auto *minstreth = static_cast<RiscVCheriotMInstreth *>(minstreth_res.value());
+ CHECK_OK(minstret_res.status());
+ CHECK_OK(minstreth_res.status());
+ auto *minstret = static_cast<RiscVCounterCsr<uint32_t, CheriotState> *>(
+ minstret_res.value());
+ auto *minstreth =
+ static_cast<RiscVCounterCsrHigh<CheriotState> *>(minstreth_res.value());
minstret->set_counter(&counter_num_instructions_);
minstreth->set_counter(&counter_num_instructions_);
+
+ // Initialize mcycle/mcycleh. Bind the instruction counter to those
+ // registers.
+ auto mcycle_res = state_->csr_set()->GetCsr("mcycle");
+ auto mcycleh_res = state_->csr_set()->GetCsr("mcycleh");
+ CHECK_OK(mcycle_res.status());
+ CHECK_OK(mcycleh_res.status());
+ auto *mcycle = static_cast<RiscVCounterCsr<uint32_t, CheriotState> *>(
+ mcycle_res.value());
+ auto *mcycleh =
+ static_cast<RiscVCounterCsrHigh<CheriotState> *>(mcycleh_res.value());
+ mcycle->set_counter(&counter_num_instructions_);
+ mcycleh->set_counter(&counter_num_instructions_);
// Set memory limits according to the memory space for TestRIG.
state_->set_max_physical_address(0x8000'0000ULL + 64 * 1024);
state_->set_min_physical_address(0x8000'0000ULL);
diff --git a/cheriot/mpact_cheriot.cc b/cheriot/mpact_cheriot.cc
index a24abce..c8a5b0e 100644
--- a/cheriot/mpact_cheriot.cc
+++ b/cheriot/mpact_cheriot.cc
@@ -20,6 +20,7 @@
#include <ios>
#include <iostream>
#include <memory>
+#include <new>
#include <optional>
#include <ostream>
#include <string>
@@ -43,9 +44,9 @@
#include "cheriot/cheriot_instrumentation_control.h"
#include "cheriot/cheriot_rvv_decoder.h"
#include "cheriot/cheriot_rvv_fp_decoder.h"
+#include "cheriot/cheriot_state.h"
#include "cheriot/cheriot_top.h"
#include "cheriot/debug_command_shell.h"
-#include "cheriot/riscv_cheriot_minstret.h"
#include "mpact/sim/generic/core_debug_interface.h"
#include "mpact/sim/generic/counters.h"
#include "mpact/sim/generic/decoder_interface.h"
@@ -65,6 +66,7 @@
#include "re2/re2.h"
#include "riscv//riscv_arm_semihost.h"
#include "riscv//riscv_clint.h"
+#include "riscv//riscv_counter_csr.h"
#include "src/google/protobuf/text_format.h"
using AddressRange = mpact::sim::util::MemoryWatcher::AddressRange;
@@ -75,6 +77,8 @@
using ::mpact::sim::cheriot::CheriotState;
using ::mpact::sim::generic::DecoderInterface;
using ::mpact::sim::proto::ComponentData;
+using ::mpact::sim::riscv::RiscVCounterCsr;
+using ::mpact::sim::riscv::RiscVCounterCsrHigh;
using ::mpact::sim::util::InstructionProfiler;
using ::mpact::sim::util::TaggedMemoryUseProfiler;
@@ -156,8 +160,6 @@
using HaltReason = ::mpact::sim::generic::CoreDebugInterface::HaltReason;
using ::mpact::sim::cheriot::CheriotTop;
-using ::mpact::sim::cheriot::RiscVCheriotMInstret;
-using ::mpact::sim::cheriot::RiscVCheriotMInstreth;
using ::mpact::sim::generic::Instruction;
using ::mpact::sim::riscv::RiscVArmSemihost;
using ::mpact::sim::riscv::RiscVClint;
@@ -334,11 +336,28 @@
std::cerr << "Error while initializing minstret/minstreth";
return -1;
}
- auto *minstret = static_cast<RiscVCheriotMInstret *>(minstret_res.value());
- auto *minstreth = static_cast<RiscVCheriotMInstreth *>(minstreth_res.value());
+ auto *minstret = static_cast<RiscVCounterCsr<uint32_t, CheriotState> *>(
+ minstret_res.value());
+ auto *minstreth =
+ static_cast<RiscVCounterCsrHigh<CheriotState> *>(minstreth_res.value());
minstret->set_counter(cheriot_top.counter_num_instructions());
minstreth->set_counter(cheriot_top.counter_num_instructions());
+ // Initialize mcycle/mcycleh. Bind the instruction counter to those
+ // registers.
+ auto mcycle_res = cheriot_top.state()->csr_set()->GetCsr("mcycle");
+ auto mcycleh_res = cheriot_top.state()->csr_set()->GetCsr("mcycleh");
+ if (!mcycle_res.ok() || !mcycleh_res.ok()) {
+ std::cerr << "Error while initializing mcycle/mcycleh";
+ return -1;
+ }
+ auto *mcycle = static_cast<RiscVCounterCsr<uint32_t, CheriotState> *>(
+ mcycle_res.value());
+ auto *mcycleh =
+ static_cast<RiscVCounterCsrHigh<CheriotState> *>(mcycleh_res.value());
+ mcycle->set_counter(cheriot_top.counter_num_cycles());
+ mcycleh->set_counter(cheriot_top.counter_num_cycles());
+
// Set up the memory router with the appropriate targets.
::mpact::sim::util::AtomicMemory *atomic_memory = nullptr;
atomic_memory = new mpact::sim::util::AtomicMemory(tagged_memory);
diff --git a/cheriot/riscv_cheriot_minstret.cc b/cheriot/riscv_cheriot_minstret.cc
deleted file mode 100644
index 6eae2dd..0000000
--- a/cheriot/riscv_cheriot_minstret.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2024 Google LLC
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "cheriot/riscv_cheriot_minstret.h"
-
-#include <cstdint>
-#include <string>
-
-#include "cheriot/cheriot_state.h"
-#include "riscv//riscv_csr.h"
-
-namespace mpact::sim::cheriot {
-
-using ::mpact::sim::riscv::RiscVCsrEnum;
-
-RiscVCheriotMInstret::RiscVCheriotMInstret(std::string name,
- CheriotState *state)
- : RiscVSimpleCsr<uint32_t>(name, RiscVCsrEnum::kMInstret, state) {}
-
-// Read the current value of the counter and apply the offset.
-uint32_t RiscVCheriotMInstret::GetUint32() {
- if (counter_ == nullptr) return offset_;
- uint32_t value = GetCounterValue() + offset_;
- return value;
-}
-
-uint64_t RiscVCheriotMInstret::GetUint64() {
- return static_cast<uint64_t>(GetUint32());
-}
-
-void RiscVCheriotMInstret::Set(uint32_t value) {
- offset_ = value - GetCounterValue();
-}
-
-void RiscVCheriotMInstret::Set(uint64_t value) {
- Set(static_cast<uint32_t>(value));
-}
-
-RiscVCheriotMInstreth::RiscVCheriotMInstreth(std::string name,
- CheriotState *state)
- : RiscVSimpleCsr<uint32_t>(name, RiscVCsrEnum::kMInstretH, state) {}
-
-// Read the current value of the counter and apply the offset.
-uint32_t RiscVCheriotMInstreth::GetUint32() {
- if (counter_ == nullptr) return offset_;
- uint32_t value = GetCounterValue() + offset_;
- return value;
-}
-
-uint64_t RiscVCheriotMInstreth::GetUint64() {
- return static_cast<uint64_t>(GetUint32());
-}
-
-void RiscVCheriotMInstreth::Set(uint32_t value) {
- offset_ = value - GetCounterValue();
-}
-
-void RiscVCheriotMInstreth::Set(uint64_t value) {
- Set(static_cast<uint32_t>(value));
-}
-
-} // namespace mpact::sim::cheriot
diff --git a/cheriot/riscv_cheriot_minstret.h b/cheriot/riscv_cheriot_minstret.h
deleted file mode 100644
index 1df90b0..0000000
--- a/cheriot/riscv_cheriot_minstret.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2024 Google LLC
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MPACT_CHERIOT__RISCV_CHERIOT_MINSTRET_H_
-#define MPACT_CHERIOT__RISCV_CHERIOT_MINSTRET_H_
-
-#include <cstdint>
-#include <string>
-
-#include "cheriot/riscv_cheriot_csr_enum.h"
-#include "mpact/sim/generic/counters.h"
-#include "riscv//riscv_csr.h"
-
-// This file provides the declarations for the CherIoT minstret/minstreth
-// CSRs. They are tied to the instruction counter of the top level of the
-// simulator. That binding is done when the simulator is instantiated. Until
-// that is done, the CSR just works like a scratch CSR.
-
-// Since this CSR is both readable and writable, but the counter value cannot
-// be changed, every time the register is written, a relative offset is computed
-// from the counter, so that the values read are relative to the most recent
-// write of the CSR.
-
-namespace mpact::sim::cheriot {
-
-using ::mpact::sim::generic::SimpleCounter;
-using ::mpact::sim::riscv::RiscVSimpleCsr;
-
-class CheriotState;
-
-class RiscVCheriotMInstret : public RiscVSimpleCsr<uint32_t> {
- public:
- RiscVCheriotMInstret(std::string name, CheriotState* state);
- RiscVCheriotMInstret(const RiscVCheriotMInstret&) = delete;
- RiscVCheriotMInstret& operator=(const RiscVCheriotMInstret&) = delete;
- ~RiscVCheriotMInstret() override = default;
-
- // RiscVSimpleCsr method overrides.
- uint32_t GetUint32() override;
- uint64_t GetUint64() override;
-
- void Set(uint32_t) override;
- void Set(uint64_t) override;
-
- void set_counter(SimpleCounter<uint64_t>* counter) { counter_ = counter; }
-
- private:
- inline uint32_t GetCounterValue() const {
- return static_cast<uint32_t>(counter_->GetValue() & 0xffff'ffffULL);
- };
-
- SimpleCounter<uint64_t>* counter_ = nullptr;
- uint32_t offset_ = 0;
-};
-
-class RiscVCheriotMInstreth : public RiscVSimpleCsr<uint32_t> {
- public:
- RiscVCheriotMInstreth(std::string name, CheriotState* state);
- RiscVCheriotMInstreth(const RiscVCheriotMInstret&) = delete;
- RiscVCheriotMInstreth& operator=(const RiscVCheriotMInstret&) = delete;
- ~RiscVCheriotMInstreth() override = default;
-
- // RiscVSimpleCsr method overrides.
- uint32_t GetUint32() override;
- uint64_t GetUint64() override;
-
- void Set(uint32_t) override;
- void Set(uint64_t) override;
-
- void set_counter(SimpleCounter<uint64_t>* counter) { counter_ = counter; }
-
- private:
- inline uint32_t GetCounterValue() const {
- return static_cast<uint32_t>(counter_->GetValue() >> 32);
- };
-
- SimpleCounter<uint64_t>* counter_ = nullptr;
- uint32_t offset_ = 0;
-};
-
-} // namespace mpact::sim::cheriot
-
-#endif // MPACT_CHERIOT__RISCV_CHERIOT_MINSTRET_H_