Adds a new CSR type RiscVShadowCsr that allows a CSR to provide a more restrictive view of another CSR. Adds cycle/cycleh and instret/instreth as shadow CSRs PiperOrigin-RevId: 705657616 Change-Id: I6c15b939de524f2d135dd429726da892807ec538
diff --git a/riscv/riscv_csr.h b/riscv/riscv_csr.h index b3b9480..6765b2c 100644 --- a/riscv/riscv_csr.h +++ b/riscv/riscv_csr.h
@@ -69,12 +69,12 @@ kTime = 0xc01, kInstret = 0xc02, + // Ignoring perf monitoring counters for now. + kCycleH = 0xc80, kTimeH = 0xc81, kInstretH = 0x82, - // Ignoring perf monitoring counters for now. - // Ignoring high bits of perf monitoring counters for now. // Supervisor trap setup. @@ -388,94 +388,6 @@ RiscVCsrClearBitsDb *clear_bits_target_; }; -// The shadow csr class is used to implement a more restricted view of another -// CSR, for instance, making a read-only view version of a CSR that may be -// accessible at lower privilege levels. -template <typename T> -class RiscVShadowCsr : public RiscVCsrInterface { - public: - RiscVShadowCsr(std::string name, RiscVCsrEnum index, T read_mask, - T write_mask, ArchState *state, RiscVCsrInterface *csr) - : RiscVCsrInterface(name, static_cast<uint64_t>(index), state), - csr_(csr), - read_mask_(read_mask), - write_mask_(write_mask), - write_target_(new RiscVCsrWriteDb(this)), - set_bits_target_(new RiscVCsrSetBitsDb(this)), - clear_bits_target_(new RiscVCsrClearBitsDb(this)) {} - RiscVShadowCsr() = delete; - RiscVShadowCsr(const RiscVShadowCsr &) = delete; - RiscVShadowCsr &operator=(const RiscVShadowCsr &) = delete; - - ~RiscVShadowCsr() override { - delete write_target_; - delete set_bits_target_; - delete clear_bits_target_; - } - - // Return the value, modified as per read mask. - uint32_t AsUint32() override { - return static_cast<uint32_t>(static_cast<T>(csr_->AsUint32()) & read_mask_); - } - uint64_t AsUint64() override { - return static_cast<uint64_t>(static_cast<T>(csr_->AsUint64()) & read_mask_); - } - // Write the value, modified as per write mask. - void Write(uint32_t value) override { - if (write_mask_ != 0) { - csr_->Write((static_cast<T>(csr_->GetUint32()) & ~write_mask_) | - (static_cast<T>(value) & write_mask_)); - } - } - void Write(uint64_t value) override { - if (write_mask_ != 0) { - csr_->Write((static_cast<T>(csr_->GetUint64()) & ~write_mask_) | - (static_cast<T>(value) & write_mask_)); - } - } - // Set the bits that are set in value, leave other bits unchanged. - // Set the bits specified in the value. Don't change the other bits. - void SetBits(uint32_t value) override { Write(GetUint32() | value); } - void SetBits(uint64_t value) override { Write(GetUint64() | value); } - // Clear the bits specified in the value. Don't change the other bits. - void ClearBits(uint32_t value) override { Write(GetUint32() & ~value); } - void ClearBits(uint64_t value) override { Write(GetUint64() & ~value); } - // Return the value, ignoring the read mask. - uint32_t GetUint32() override { return csr_->GetUint32(); } - uint64_t GetUint64() override { return csr_->GetUint64(); } - // Sets the value, ignoring the write mask. - void Set(uint32_t value) override { csr_->Set(static_cast<T>(value)); } - void Set(uint64_t value) override { csr_->Set(static_cast<T>(value)); } - // Size of value. - size_t size() const override { return sizeof(T); } - // Set to reset value. - void Reset() override { /* Empty. */ } - // Operand creation interface. - generic::SourceOperandInterface *CreateSourceOperand() override; - generic::DestinationOperandInterface *CreateSetDestinationOperand( - int latency, std::string op_name) override; - generic::DestinationOperandInterface *CreateClearDestinationOperand( - int latency, std::string op_name) override; - generic::DestinationOperandInterface *CreateWriteDestinationOperand( - int latency, std::string op_name) override; - - RiscVCsrWriteDb *write_target() const { return write_target_; } - RiscVCsrSetBitsDb *set_bits_target() const { return set_bits_target_; } - RiscVCsrClearBitsDb *clear_bits_target() const { return clear_bits_target_; } - - RiscVCsrInterface *csr() const { return csr_; } - T read_mask() const { return read_mask_; } - T write_mask() const { return write_mask_; } - - private: - RiscVCsrInterface *csr_; - T read_mask_; - T write_mask_; - RiscVCsrWriteDb *write_target_; - RiscVCsrSetBitsDb *set_bits_target_; - RiscVCsrClearBitsDb *clear_bits_target_; -}; - using RiscV32SimpleCsr = RiscVSimpleCsr<uint32_t>; using RiscV64SimpleCsr = RiscVSimpleCsr<uint64_t>; @@ -609,35 +521,6 @@ return new RiscVCsrSourceOperand(this); } -template <typename T> -generic::DestinationOperandInterface * -RiscVShadowCsr<T>::CreateSetDestinationOperand(int latency, - std::string op_name) { - return new RiscVCsrDestinationOperand(this, this->set_bits_target(), latency, - op_name); -} - -template <typename T> -generic::DestinationOperandInterface * -RiscVShadowCsr<T>::CreateClearDestinationOperand(int latency, - std::string op_name) { - return new RiscVCsrDestinationOperand(this, this->clear_bits_target(), - latency, op_name); -} - -template <typename T> -generic::DestinationOperandInterface * -RiscVShadowCsr<T>::CreateWriteDestinationOperand(int latency, - std::string op_name) { - return new RiscVCsrDestinationOperand(this, this->write_target(), latency, - op_name); -} - -template <typename T> -generic::SourceOperandInterface *RiscVShadowCsr<T>::CreateSourceOperand() { - return new RiscVCsrSourceOperand(this); -} - } // namespace riscv } // namespace sim } // namespace mpact
diff --git a/riscv/riscv_state.cc b/riscv/riscv_state.cc index 36e4fe9..8d71bad 100644 --- a/riscv/riscv_state.cc +++ b/riscv/riscv_state.cc
@@ -234,23 +234,23 @@ auto *minstret = CreateCsr<RiscVCounterCsr<T, RiscVState>>( state, csr_vec, "minstret", RiscVCsrEnum ::kMInstret, state); CHECK_NE(minstret, nullptr); - RiscVCsrInterface *minstreth = nullptr; if (sizeof(T) == sizeof(uint32_t)) { - minstreth = CreateCsr<RiscVCounterCsrHigh<RiscVState>>( - state, csr_vec, "minstreth", RiscVCsrEnum::kMInstretH, state, - reinterpret_cast<RiscVCounterCsr<uint32_t, RiscVState> *>(minstret)); - CHECK_NE(minstreth, nullptr); + CHECK_NE(CreateCsr<RiscVCounterCsrHigh<RiscVState>>( + state, csr_vec, "minstreth", RiscVCsrEnum::kMInstretH, state, + reinterpret_cast<RiscVCounterCsr<uint32_t, RiscVState> *>( + minstret)), + nullptr); } // mcycle/mcycleh auto *mcycle = CreateCsr<RiscVCounterCsr<T, RiscVState>>( state, csr_vec, "mcycle", RiscVCsrEnum::kMCycle, state); CHECK_NE(mcycle, nullptr); - RiscVCsrInterface *mcycleh = nullptr; if (sizeof(T) == sizeof(uint32_t)) { - mcycleh = CreateCsr<RiscVCounterCsrHigh<RiscVState>>( - state, csr_vec, "mcycleh", RiscVCsrEnum::kMCycleH, state, - reinterpret_cast<RiscVCounterCsr<uint32_t, RiscVState> *>(mcycle)); - CHECK_NE(mcycleh, nullptr); + CHECK_NE( + CreateCsr<RiscVCounterCsrHigh<RiscVState>>( + state, csr_vec, "mcycleh", RiscVCsrEnum::kMCycleH, state, + reinterpret_cast<RiscVCounterCsr<uint32_t, RiscVState> *>(mcycle)), + nullptr); } // Hypervisor level CSRs @@ -318,29 +318,6 @@ // User level CSRs - // instret/instreth - CHECK_NE(CreateCsr<RiscVShadowCsr<T>>( - state, csr_vec, "instret", RiscVCsrEnum ::kInstret, - std::numeric_limits<T>::max(), 0, state, minstret), - nullptr); - if (sizeof(T) == sizeof(uint32_t)) { - CHECK_NE(CreateCsr<RiscVShadowCsr<T>>( - state, csr_vec, "instreth", RiscVCsrEnum::kInstretH, - std::numeric_limits<T>::max(), 0, state, minstreth), - nullptr); - } - // cycle/cycleh - CHECK_NE(CreateCsr<RiscVShadowCsr<T>>( - state, csr_vec, "cycle", RiscVCsrEnum::kCycle, - std::numeric_limits<T>::max(), 0, state, mcycle), - nullptr); - if (sizeof(T) == sizeof(uint32_t)) { - CHECK_NE(CreateCsr<RiscVShadowCsr<T>>( - state, csr_vec, "cycleh", RiscVCsrEnum::kCycleH, - std::numeric_limits<T>::max(), 0, state, mcycleh), - nullptr); - } - // ustatus CHECK_NE(CreateCsr<RiscVSimpleCsr<T>>( state, csr_vec, "ustatus", RiscVCsrEnum::kUStatus, 0,
diff --git a/riscv/riscv_top.cc b/riscv/riscv_top.cc index ab18240..17885c7 100644 --- a/riscv/riscv_top.cc +++ b/riscv/riscv_top.cc
@@ -144,7 +144,7 @@ << "Failed to register opcode counter"; } - // Connect counters to minstret(h) and mcycle(h) CSRs. + // Connect counters to instret(h) and mcycle(h) CSRs. auto csr_res = state_->csr_set()->GetCsr("minstret"); CHECK_OK(csr_res.status()) << "Failed to get minstret CSR"; if (state_->xlen() == RiscVXlen::RV32) { @@ -169,13 +169,11 @@ reinterpret_cast<RiscVCounterCsrHigh<RiscVState> *>(csr_res.value()); mcycleh->set_counter(&counter_num_cycles_); } else { - // Minstret. - csr_res = state_->csr_set()->GetCsr("minstret"); + // Minstret/minstreth. auto *minstret = reinterpret_cast<RiscVCounterCsr<uint64_t, RiscVState> *>( csr_res.value()); minstret->set_counter(&counter_num_instructions_); - // Mcycle - csr_res = state_->csr_set()->GetCsr("mcycle"); + // Mcycle/mcycleh. auto *mcycle = reinterpret_cast<RiscVCounterCsr<uint64_t, RiscVState> *>( csr_res.value()); mcycle->set_counter(&counter_num_cycles_);
diff --git a/riscv/test/riscv_csr_test.cc b/riscv/test/riscv_csr_test.cc index 10801d3..1f6650a 100644 --- a/riscv/test/riscv_csr_test.cc +++ b/riscv/test/riscv_csr_test.cc
@@ -30,7 +30,6 @@ using ::mpact::sim::riscv::RiscV32SimpleCsr; using ::mpact::sim::riscv::RiscVCsrEnum; -using ::mpact::sim::riscv::RiscVShadowCsr; using ::mpact::sim::riscv::RiscVState; using ::mpact::sim::riscv::RiscVXlen; using ::mpact::sim::util::FlatDemandMemory; @@ -125,25 +124,4 @@ delete csr; } -// Test that the shadow csr constructs properly and with the expected values. -TEST_F(RiscV32CsrTest, ShadowCsrConstruction) { - auto *csr0 = new RiscV32SimpleCsr(kCsrName0, RiscVCsrEnum::kMScratch, - kDeadBeef, state_); - EXPECT_EQ(csr0->name(), kCsrName0); - EXPECT_EQ(csr0->index(), static_cast<int>(RiscVCsrEnum::kMScratch)); - - auto *csr1 = new RiscVShadowCsr<uint32_t>( - kCsrName1, RiscVCsrEnum::kUScratch, kReadMask, kWriteMask, state_, csr0); - EXPECT_EQ(csr1->name(), kCsrName1); - EXPECT_EQ(csr1->index(), static_cast<int>(RiscVCsrEnum::kUScratch)); - EXPECT_EQ(csr1->read_mask(), kReadMask); - EXPECT_EQ(csr1->write_mask(), kWriteMask); - - EXPECT_EQ(csr1->AsUint32(), csr0->AsUint32() & kReadMask); - csr1->Write(kAllOnes); - EXPECT_EQ(csr0->AsUint32(), kDeadBeef | (kAllOnes & kWriteMask)); - delete csr0; - delete csr1; -} - } // namespace