| // Copyright 2023 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 |
| // |
| // https://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 "riscv/riscv_csr.h" |
| |
| #include <cstdint> |
| #include <string> |
| #include <utility> |
| |
| #include "absl/log/log.h" |
| #include "absl/status/status.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/strings/string_view.h" |
| #include "mpact/sim/generic/data_buffer.h" |
| |
| namespace mpact { |
| namespace sim { |
| namespace riscv { |
| |
| void RiscVCsrWriteDb::SetDataBuffer(generic::DataBuffer* db) { |
| auto db_size = db->size<uint8_t>(); |
| if (db_size == 4) { |
| csr_->Write(db->Get<uint32_t>(0)); |
| return; |
| } |
| if (db_size == 8) { |
| csr_->Write(db->Get<uint64_t>(0)); |
| return; |
| } |
| LOG(ERROR) << "Attempted to write CSR with width != 32 or 64"; |
| } |
| |
| void RiscVCsrClearBitsDb::SetDataBuffer(generic::DataBuffer* db) { |
| auto db_size = db->size<uint8_t>(); |
| if (db_size == 4) { |
| csr_->ClearBits(db->Get<uint32_t>(0)); |
| return; |
| } |
| if (db_size == 8) { |
| csr_->ClearBits(db->Get<uint64_t>(0)); |
| return; |
| } |
| LOG(ERROR) << "Attempted to clear CSR with width != 32 or 64"; |
| } |
| |
| void RiscVCsrSetBitsDb::SetDataBuffer(generic::DataBuffer* db) { |
| auto db_size = db->size<uint8_t>(); |
| if (db_size == 4) { |
| csr_->SetBits(db->Get<uint32_t>(0)); |
| return; |
| } |
| if (db_size == 8) { |
| csr_->SetBits(db->Get<uint64_t>(0)); |
| return; |
| } |
| LOG(ERROR) << "Attempted to set CSR with width != 32 or 64"; |
| } |
| |
| absl::Status RiscVCsrSet::AddCsr(RiscVCsrInterface* csr) { |
| if (csr == nullptr) { |
| return absl::InvalidArgumentError("csr is nullptr"); |
| } |
| auto index_ptr = csr_index_map_.find(csr->index()); |
| auto name_ptr = csr_name_map_.find(csr->name()); |
| if (index_ptr != csr_index_map_.end()) { |
| return absl::AlreadyExistsError(absl::StrCat( |
| "CSR 0x", absl::Hex(csr->index()), " already added to CSR set")); |
| } |
| if (name_ptr != csr_name_map_.end()) { |
| return absl::AlreadyExistsError( |
| absl::StrCat("'", csr->name(), "'", " already added to CSR set")); |
| } |
| |
| csr_index_map_.insert(std::make_pair(csr->index(), csr)); |
| csr_name_map_.insert(std::make_pair(csr->name(), csr)); |
| return absl::OkStatus(); |
| } |
| |
| absl::StatusOr<RiscVCsrInterface*> RiscVCsrSet::GetCsr(absl::string_view name) { |
| auto name_ptr = csr_name_map_.find(name); |
| if (name_ptr == csr_name_map_.end()) { |
| return absl::NotFoundError(absl::StrCat("No such CSR: '", name, "'")); |
| } |
| return name_ptr->second; |
| } |
| |
| absl::StatusOr<RiscVCsrInterface*> RiscVCsrSet::GetCsr(uint64_t index) { |
| auto index_ptr = csr_index_map_.find(index); |
| if (index_ptr == csr_index_map_.end()) { |
| return absl::NotFoundError(absl::StrCat("No such CSR index: ", index)); |
| } |
| return index_ptr->second; |
| } |
| |
| absl::Status RiscVCsrSet::RemoveCsr(uint64_t csr_index) { |
| auto index_ptr = csr_index_map_.find(csr_index); |
| if (index_ptr == csr_index_map_.end()) { |
| return absl::NotFoundError( |
| absl::StrCat("CSR 0x", absl::Hex(csr_index), " not found")); |
| } |
| auto name_ptr = csr_name_map_.find(index_ptr->second->name()); |
| csr_index_map_.erase(index_ptr); |
| csr_name_map_.erase(name_ptr); |
| return absl::OkStatus(); |
| } |
| |
| RiscVCsrSourceOperand::RiscVCsrSourceOperand(RiscVCsrInterface* csr, |
| std::string op_name) |
| : csr_(csr), op_name_(op_name) {} |
| |
| RiscVCsrSourceOperand::RiscVCsrSourceOperand(RiscVCsrInterface* csr) |
| : RiscVCsrSourceOperand(csr, csr->name()) {} |
| |
| bool RiscVCsrSourceOperand::AsBool(int i) { |
| return static_cast<bool>(csr_->AsUint32()); |
| } |
| int8_t RiscVCsrSourceOperand::AsInt8(int i) { |
| return static_cast<int8_t>(csr_->AsUint32()); |
| } |
| uint8_t RiscVCsrSourceOperand::AsUint8(int i) { |
| return static_cast<uint8_t>(csr_->AsUint32()); |
| } |
| int16_t RiscVCsrSourceOperand::AsInt16(int i) { |
| return static_cast<int16_t>(csr_->AsUint32()); |
| } |
| uint16_t RiscVCsrSourceOperand::AsUint16(int i) { |
| return static_cast<uint16_t>(csr_->AsUint32()); |
| } |
| int32_t RiscVCsrSourceOperand::AsInt32(int i) { |
| return static_cast<int32_t>(csr_->AsUint32()); |
| } |
| uint32_t RiscVCsrSourceOperand::AsUint32(int i) { |
| return static_cast<uint32_t>(csr_->AsUint32()); |
| } |
| int64_t RiscVCsrSourceOperand::AsInt64(int i) { |
| return static_cast<int64_t>(csr_->AsUint64()); |
| } |
| uint64_t RiscVCsrSourceOperand::AsUint64(int i) { |
| return static_cast<uint64_t>(csr_->AsUint64()); |
| } |
| |
| // Implementation of the destination op templated class methods. |
| RiscVCsrDestinationOperand::RiscVCsrDestinationOperand( |
| RiscVCsrInterface* csr, generic::DataBufferDestination* db_dest, |
| int latency, std::string op_name) |
| : csr_(csr), |
| db_dest_(db_dest), |
| db_factory_(csr_->state()->db_factory()), |
| latency_(latency), |
| delay_line_(csr_->state()->data_buffer_delay_line()), |
| op_name_(op_name) {} |
| |
| RiscVCsrDestinationOperand::RiscVCsrDestinationOperand( |
| RiscVCsrInterface* csr, generic::DataBufferDestination* db_dest, |
| int latency) |
| : RiscVCsrDestinationOperand(csr, db_dest, latency, csr->name()) {} |
| |
| void RiscVCsrDestinationOperand::InitializeDataBuffer(generic::DataBuffer* db) { |
| db->set_destination(db_dest_); |
| db->set_latency(latency_); |
| db->set_delay_line(delay_line_); |
| } |
| |
| generic::DataBuffer* RiscVCsrDestinationOperand::CopyDataBuffer() { |
| generic::DataBuffer* db = db_factory_->Allocate(csr_->size()); |
| if (csr_->size() == 4) { |
| db->Set<uint32_t>(0, csr_->AsUint32()); |
| } else if (csr_->size() == 8) { |
| db->Set<uint64_t>(0, csr_->AsUint64()); |
| } |
| InitializeDataBuffer(db); |
| return db; |
| } |
| |
| generic::DataBuffer* RiscVCsrDestinationOperand::AllocateDataBuffer() { |
| generic::DataBuffer* db = db_factory_->Allocate(csr_->size()); |
| InitializeDataBuffer(db); |
| return db; |
| } |
| |
| } // namespace riscv |
| } // namespace sim |
| } // namespace mpact |