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_