| // 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/riscv64g_encoding.h" |
| |
| #include <cstdint> |
| #include <string> |
| #include <utility> |
| |
| #include "absl/log/log.h" |
| #include "absl/strings/str_cat.h" |
| #include "mpact/sim/generic/immediate_operand.h" |
| #include "mpact/sim/generic/literal_operand.h" |
| #include "mpact/sim/generic/simple_resource.h" |
| #include "mpact/sim/generic/simple_resource_operand.h" |
| #include "riscv/riscv64g_bin_decoder.h" |
| #include "riscv/riscv64g_decoder.h" |
| #include "riscv/riscv64g_enums.h" |
| #include "riscv/riscv_register.h" |
| #include "riscv/riscv_state.h" |
| |
| namespace mpact { |
| namespace sim { |
| namespace riscv { |
| namespace isa64 { |
| |
| using generic::SimpleResourceOperand; |
| |
| // Generic helper functions to create register operands. |
| template <typename RegType> |
| inline DestinationOperandInterface *GetRegisterDestinationOp(RiscVState *state, |
| std::string name, |
| int latency) { |
| auto *reg = state->GetRegister<RegType>(name).first; |
| return reg->CreateDestinationOperand(latency); |
| } |
| |
| template <typename RegType> |
| inline DestinationOperandInterface *GetRegisterDestinationOp( |
| RiscVState *state, std::string name, int latency, std::string op_name) { |
| auto *reg = state->GetRegister<RegType>(name).first; |
| return reg->CreateDestinationOperand(latency, op_name); |
| } |
| |
| template <typename T> |
| inline DestinationOperandInterface *GetCSRSetBitsDestinationOp( |
| RiscVState *state, std::string name, int latency, std::string op_name) { |
| auto result = state->csr_set()->GetCsr(name); |
| if (!result.ok()) { |
| LOG(ERROR) << "No such CSR '" << name << "'"; |
| return nullptr; |
| } |
| auto *csr = result.value(); |
| auto *op = csr->CreateSetDestinationOperand(latency, op_name); |
| return op; |
| } |
| |
| template <typename RegType> |
| inline SourceOperandInterface *GetRegisterSourceOp(RiscVState *state, |
| std::string name) { |
| auto *reg = state->GetRegister<RegType>(name).first; |
| auto *op = reg->CreateSourceOperand(); |
| return op; |
| } |
| |
| template <typename RegType> |
| inline SourceOperandInterface *GetRegisterSourceOp(RiscVState *state, |
| std::string name, |
| std::string op_name) { |
| auto *reg = state->GetRegister<RegType>(name).first; |
| auto *op = reg->CreateSourceOperand(op_name); |
| return op; |
| } |
| |
| RiscV64GEncoding::RiscV64GEncoding(RiscVState *state) |
| : RiscV64GEncoding(state, true) {} |
| |
| RiscV64GEncoding::RiscV64GEncoding(RiscVState *state, bool use_abi_names) |
| : state_(state) { |
| if (use_abi_names) { |
| xreg_alias_ = xreg_abi_names_; |
| } else { |
| xreg_alias_ = xreg_names_; |
| } |
| InitializeSourceOperandGetters(); |
| InitializeDestinationOperandGetters(); |
| InitializeSimpleResourceGetters(); |
| resource_pool_ = new generic::SimpleResourcePool("RiscV64G", 128); |
| resource_delay_line_ = |
| state_->CreateAndAddDelayLine<generic::SimpleResourceDelayLine>(8); |
| } |
| |
| RiscV64GEncoding::~RiscV64GEncoding() { delete resource_pool_; } |
| |
| void RiscV64GEncoding::InitializeSourceOperandGetters() { |
| // Source operand getters. |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kAAq), |
| [this]() -> SourceOperandInterface * { |
| if (encoding64::inst32_format::ExtractAq(inst_word_)) { |
| return new generic::IntLiteralOperand<1>(); |
| } |
| return new generic::IntLiteralOperand<0>(); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kARl), |
| [this]() -> SourceOperandInterface * { |
| if (encoding64::inst32_format::ExtractRl(inst_word_)) { |
| return new generic::IntLiteralOperand<1>(); |
| } |
| return new generic::IntLiteralOperand<0>(); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kIUimm6), [this]() { |
| return new generic::ImmediateOperand<uint32_t>( |
| encoding64::r_s_type::ExtractRUimm6(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kBImm12), [this]() { |
| return new generic::ImmediateOperand<int32_t>( |
| encoding64::inst32_format::ExtractBImm(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kC3drs2), [this]() { |
| auto num = encoding64::inst16_format::ExtractCsRs2(inst_word_); |
| return GetRegisterSourceOp<RVFpRegister>( |
| state_, absl::StrCat(RiscVState::kFregPrefix, num)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kC3rs1), [this]() { |
| auto num = encoding64::inst16_format::ExtractCsRs1(inst_word_); |
| if (state_->xlen() == RiscVXlen::RV32) { |
| return GetRegisterSourceOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), |
| xreg_alias_[num]); |
| } |
| return GetRegisterSourceOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), |
| xreg_alias_[num]); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kC3rs2), [this]() { |
| auto num = encoding64::inst16_format::ExtractCsRs2(inst_word_); |
| if (state_->xlen() == RiscVXlen::RV32) { |
| return GetRegisterSourceOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), |
| xreg_alias_[num]); |
| } |
| return GetRegisterSourceOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), |
| xreg_alias_[num]); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kCSRUimm5), [this]() { |
| return new generic::ImmediateOperand<uint32_t>( |
| encoding64::inst32_format::ExtractIUimm5(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kCdrs2), [this]() { |
| auto num = encoding64::c_r::ExtractRs2(inst_word_); |
| return GetRegisterSourceOp<RVFpRegister>( |
| state_, absl::StrCat(RiscVState::kFregPrefix, num)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kCrs1), [this]() { |
| auto num = encoding64::c_r::ExtractRs1(inst_word_); |
| if (state_->xlen() == RiscVXlen::RV32) { |
| return GetRegisterSourceOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), |
| xreg_alias_[num]); |
| } |
| return GetRegisterSourceOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), |
| xreg_alias_[num]); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kCrs2), [this]() { |
| auto num = encoding64::c_r::ExtractRs2(inst_word_); |
| if (state_->xlen() == RiscVXlen::RV32) { |
| return GetRegisterSourceOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), |
| xreg_alias_[num]); |
| } |
| return GetRegisterSourceOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), |
| xreg_alias_[num]); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kCsr), [this]() { |
| auto csr_indx = encoding64::i_type::ExtractUImm12(inst_word_); |
| auto res = state_->csr_set()->GetCsr(csr_indx); |
| if (!res.ok()) { |
| return new generic::ImmediateOperand<uint32_t>(csr_indx); |
| } |
| auto *csr = res.value(); |
| return new generic::ImmediateOperand<uint32_t>(csr_indx, csr->name()); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kDrs1), [this]() { |
| int num = encoding64::r_type::ExtractRs1(inst_word_); |
| return GetRegisterSourceOp<RVFpRegister>( |
| state_, absl::StrCat(RiscVState::kFregPrefix, num)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kDrs2), [this]() { |
| int num = encoding64::r_type::ExtractRs2(inst_word_); |
| return GetRegisterSourceOp<RVFpRegister>( |
| state_, absl::StrCat(RiscVState::kFregPrefix, num)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kDrs3), [this]() { |
| int num = encoding64::r4_type::ExtractRs3(inst_word_); |
| return GetRegisterSourceOp<RVFpRegister>( |
| state_, absl::StrCat(RiscVState::kFregPrefix, num)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kFrs1), [this]() { |
| int num = encoding64::r_type::ExtractRs1(inst_word_); |
| return GetRegisterSourceOp<RVFpRegister>( |
| state_, absl::StrCat(RiscVState::kFregPrefix, num)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kFrs2), [this]() { |
| int num = encoding64::r_type::ExtractRs2(inst_word_); |
| return GetRegisterSourceOp<RVFpRegister>( |
| state_, absl::StrCat(RiscVState::kFregPrefix, num)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kFrs3), [this]() { |
| int num = encoding64::r4_type::ExtractRs3(inst_word_); |
| return GetRegisterSourceOp<RVFpRegister>( |
| state_, absl::StrCat(RiscVState::kFregPrefix, num)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kICbImm8), [this]() { |
| return new generic::ImmediateOperand<int32_t>( |
| encoding64::inst16_format::ExtractBimm(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kICiImm6), [this]() { |
| return new generic::ImmediateOperand<int32_t>( |
| encoding64::c_i::ExtractImm6(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kICiImm612), [this]() { |
| return new generic::ImmediateOperand<int32_t>( |
| encoding64::inst16_format::ExtractImm18(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kICiUimm6), [this]() { |
| return new generic::ImmediateOperand<uint32_t>( |
| encoding64::inst16_format::ExtractUimm6(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kICiUimm6x4), [this]() { |
| return new generic::ImmediateOperand<uint32_t>( |
| encoding64::inst16_format::ExtractCiImmW(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kICiUimm6x8), [this]() { |
| return new generic::ImmediateOperand<uint32_t>( |
| encoding64::inst16_format::ExtractCiImmD(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kICiImm6x16), [this]() { |
| return new generic::ImmediateOperand<int32_t>( |
| encoding64::inst16_format::ExtractCiImm10(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kICiwUimm8x4), [this]() { |
| return new generic::ImmediateOperand<uint32_t>( |
| encoding64::inst16_format::ExtractCiwImm10(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kICjImm11), [this]() { |
| return new generic::ImmediateOperand<int32_t>( |
| encoding64::inst16_format::ExtractJimm(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kIClUimm5x4), [this]() { |
| return new generic::ImmediateOperand<uint32_t>( |
| encoding64::inst16_format::ExtractClImmW(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kIClUimm5x8), [this]() { |
| return new generic::ImmediateOperand<uint32_t>( |
| encoding64::inst16_format::ExtractClImmD(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kICssUimm6x4), [this]() { |
| return new generic::ImmediateOperand<uint32_t>( |
| encoding64::inst16_format::ExtractCssImmW(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kICssUimm6x8), [this]() { |
| return new generic::ImmediateOperand<uint32_t>( |
| encoding64::inst16_format::ExtractCssImmD(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kIImm12), [this]() { |
| return new generic::ImmediateOperand<int32_t>( |
| encoding64::inst32_format::ExtractImm12(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kIUimm5), [this]() { |
| return new generic::ImmediateOperand<uint32_t>( |
| encoding64::inst32_format::ExtractRUimm5(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kJImm12), [this]() { |
| return new generic::ImmediateOperand<int32_t>( |
| encoding64::inst32_format::ExtractImm12(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kJImm20), [this]() { |
| return new generic::ImmediateOperand<int32_t>( |
| encoding64::inst32_format::ExtractJImm(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kPred), [this]() { |
| return new generic::ImmediateOperand<uint32_t>( |
| encoding64::fence::ExtractPred(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kRm), |
| [this]() -> SourceOperandInterface * { |
| uint32_t rm = (inst_word_ >> 12) & 0x7; |
| switch (rm) { |
| case 0: |
| return new generic::IntLiteralOperand<0>(); |
| case 1: |
| return new generic::IntLiteralOperand<1>(); |
| case 2: |
| return new generic::IntLiteralOperand<2>(); |
| case 3: |
| return new generic::IntLiteralOperand<3>(); |
| case 4: |
| return new generic::IntLiteralOperand<4>(); |
| case 5: |
| return new generic::IntLiteralOperand<5>(); |
| case 6: |
| return new generic::IntLiteralOperand<6>(); |
| case 7: |
| return new generic::IntLiteralOperand<7>(); |
| default: |
| return nullptr; |
| } |
| })); |
| source_op_getters_.insert(std::make_pair( |
| static_cast<int>(SourceOpEnum::kRd), |
| [this]() -> SourceOperandInterface * { |
| int num = encoding64::r_type::ExtractRd(inst_word_); |
| if (num == 0) |
| return new generic::IntLiteralOperand<0>({1}, xreg_alias_[0]); |
| if (state_->xlen() == RiscVXlen::RV32) { |
| return GetRegisterSourceOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), |
| xreg_alias_[num]); |
| } |
| return GetRegisterSourceOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), |
| xreg_alias_[num]); |
| })); |
| source_op_getters_.insert(std::make_pair( |
| static_cast<int>(SourceOpEnum::kRs1), |
| [this]() -> SourceOperandInterface * { |
| int num = encoding64::r_type::ExtractRs1(inst_word_); |
| if (num == 0) |
| return new generic::IntLiteralOperand<0>({1}, xreg_alias_[0]); |
| if (state_->xlen() == RiscVXlen::RV32) { |
| return GetRegisterSourceOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), |
| xreg_alias_[num]); |
| } |
| return GetRegisterSourceOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), |
| xreg_alias_[num]); |
| })); |
| source_op_getters_.insert(std::make_pair( |
| static_cast<int>(SourceOpEnum::kRs2), |
| [this]() -> SourceOperandInterface * { |
| int num = encoding64::r_type::ExtractRs2(inst_word_); |
| if (num == 0) |
| return new generic::IntLiteralOperand<0>({1}, xreg_alias_[0]); |
| if (state_->xlen() == RiscVXlen::RV32) { |
| return GetRegisterSourceOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), |
| xreg_alias_[num]); |
| } |
| return GetRegisterSourceOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), |
| xreg_alias_[num]); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kSImm12), [this]() { |
| return new generic::ImmediateOperand<int32_t>( |
| encoding64::s_type::ExtractSImm(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kSucc), [this]() { |
| return new generic::ImmediateOperand<uint32_t>( |
| encoding64::fence::ExtractSucc(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kUImm20), [this]() { |
| return new generic::ImmediateOperand<int32_t>( |
| encoding64::u_type::ExtractUImm(inst_word_)); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kX0), [this]() { |
| return new generic::IntLiteralOperand<0>({1}, xreg_alias_[0]); |
| })); |
| source_op_getters_.insert( |
| std::make_pair(static_cast<int>(SourceOpEnum::kX2), [this]() { |
| if (state_->xlen() == RiscVXlen::RV32) { |
| return GetRegisterSourceOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, 2), xreg_alias_[2]); |
| } |
| return GetRegisterSourceOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, 2), xreg_alias_[2]); |
| })); |
| source_op_getters_.insert(std::make_pair( |
| static_cast<int>(SourceOpEnum::kNone), []() { return nullptr; })); |
| } |
| |
| void RiscV64GEncoding::InitializeDestinationOperandGetters() { |
| // Destination operand getters. |
| dest_op_getters_.insert( |
| std::make_pair(static_cast<int>(DestOpEnum::kC3drd), [this](int latency) { |
| int num = encoding64::inst16_format::ExtractClRd(inst_word_); |
| if (state_->xlen() == RiscVXlen::RV32) { |
| return GetRegisterDestinationOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), latency, |
| xreg_alias_[num]); |
| } |
| return GetRegisterDestinationOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), latency, |
| xreg_alias_[num]); |
| })); |
| dest_op_getters_.insert( |
| std::make_pair(static_cast<int>(DestOpEnum::kC3rd), [this](int latency) { |
| int num = encoding64::inst16_format::ExtractClRd(inst_word_); |
| return GetRegisterDestinationOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), latency, |
| xreg_alias_[num]); |
| })); |
| dest_op_getters_.insert( |
| std::make_pair(static_cast<int>(DestOpEnum::kC3rs1), [this](int latency) { |
| int num = encoding64::inst16_format::ExtractClRs1(inst_word_); |
| if (state_->xlen() == RiscVXlen::RV32) { |
| return GetRegisterDestinationOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), latency, |
| xreg_alias_[num]); |
| } |
| return GetRegisterDestinationOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), latency, |
| xreg_alias_[num]); |
| })); |
| dest_op_getters_.insert(std::make_pair(static_cast<int>(DestOpEnum::kCsr), |
| [](int latency) { return nullptr; })); |
| dest_op_getters_.insert( |
| std::make_pair(static_cast<int>(DestOpEnum::kDrd), [this](int latency) { |
| int num = encoding64::r_type::ExtractRd(inst_word_); |
| return GetRegisterDestinationOp<RVFpRegister>( |
| state_, absl::StrCat(RiscVState::kFregPrefix, num), latency); |
| })); |
| dest_op_getters_.insert( |
| std::make_pair(static_cast<int>(DestOpEnum::kFrd), [this](int latency) { |
| int num = encoding64::r_type::ExtractRd(inst_word_); |
| return GetRegisterDestinationOp<RVFpRegister>( |
| state_, absl::StrCat(RiscVState::kFregPrefix, num), latency); |
| })); |
| dest_op_getters_.insert(std::make_pair( |
| static_cast<int>(DestOpEnum::kNextPc), [this](int latency) { |
| if (state_->xlen() == RiscVXlen::RV32) { |
| return GetRegisterDestinationOp<RV64Register>( |
| state_, RiscVState::kPcName, latency); |
| } |
| return GetRegisterDestinationOp<RV64Register>( |
| state_, RiscVState::kPcName, latency); |
| })); |
| dest_op_getters_.insert( |
| std::make_pair(static_cast<int>(DestOpEnum::kRd), |
| [this](int latency) -> DestinationOperandInterface * { |
| int num = encoding64::r_type::ExtractRd(inst_word_); |
| if (num == 0) { |
| return GetRegisterDestinationOp<RV64Register>( |
| state_, "X0Dest", 0, xreg_alias_[0]); |
| } else { |
| return GetRegisterDestinationOp<RVFpRegister>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, num), |
| latency, xreg_alias_[num]); |
| } |
| })); |
| dest_op_getters_.insert( |
| std::make_pair(static_cast<int>(DestOpEnum::kX0), [this](int) { |
| if (state_->xlen() == RiscVXlen::RV32) { |
| return GetRegisterDestinationOp<RV64Register>(state_, "X0Dest", 0, |
| xreg_alias_[0]); |
| } |
| return GetRegisterDestinationOp<RV64Register>(state_, "X0Dest", 0, |
| xreg_alias_[0]); |
| })); |
| dest_op_getters_.insert( |
| std::make_pair(static_cast<int>(DestOpEnum::kX1), [this](int latency) { |
| if (state_->xlen() == RiscVXlen::RV32) { |
| return GetRegisterDestinationOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, 1), latency, |
| xreg_alias_[1]); |
| } |
| return GetRegisterDestinationOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, 1), latency, |
| xreg_alias_[1]); |
| })); |
| dest_op_getters_.insert( |
| std::make_pair(static_cast<int>(DestOpEnum::kX2), [this](int latency) { |
| if (state_->xlen() == RiscVXlen::RV32) { |
| return GetRegisterDestinationOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, 2), latency, |
| xreg_alias_[2]); |
| } |
| return GetRegisterDestinationOp<RV64Register>( |
| state_, absl::StrCat(RiscVState::kXregPrefix, 2), latency, |
| xreg_alias_[2]); |
| })); |
| dest_op_getters_.insert(std::make_pair( |
| static_cast<int>(DestOpEnum::kFflags), [this](int latency) { |
| return GetCSRSetBitsDestinationOp<uint32_t>(state_, "fflags", latency, |
| ""); |
| })); |
| dest_op_getters_.insert(std::make_pair(static_cast<int>(DestOpEnum::kNone), |
| [](int latency) { return nullptr; })); |
| } |
| |
| // Parse the instruction word to determine the opcode. |
| void RiscV64GEncoding::ParseInstruction(uint32_t inst_word) { |
| inst_word_ = inst_word; |
| if ((inst_word_ & 0x3) == 3) { |
| opcode_ = mpact::sim::riscv::encoding64::DecodeRiscVGInst32(inst_word_); |
| return; |
| } |
| |
| opcode_ = mpact::sim::riscv::encoding64::DecodeRiscVCInst16( |
| static_cast<uint16_t>(inst_word_ & 0xffff)); |
| } |
| |
| void RiscV64GEncoding::InitializeComplexResourceOperandGetters() { |
| complex_resource_getters_.insert( |
| std::make_pair(static_cast<int>(ComplexResourceEnum::kNone), |
| [](int begin, int end) { return nullptr; })); |
| } |
| |
| ResourceOperandInterface *RiscV64GEncoding::GetComplexResourceOperand( |
| SlotEnum, int, OpcodeEnum, ComplexResourceEnum resource, int begin, |
| int end) { |
| int index = static_cast<int>(resource); |
| auto iter = complex_resource_getters_.find(index); |
| if (iter == complex_resource_getters_.end()) { |
| LOG(WARNING) << "No complex resource getter found for resource: " << index; |
| return nullptr; |
| } |
| return (iter->second)(begin, end); |
| } |
| |
| void RiscV64GEncoding::InitializeSimpleResourceGetters() { |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kNone), []() { return nullptr; })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kC3drd), |
| [this]() -> generic::SimpleResource * { |
| int num = encoding64::inst16_format::ExtractClRd(inst_word_); |
| return resource_pool_->GetOrAddResource(absl::StrCat("d", num)); |
| })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kC3drs2), |
| [this]() -> generic::SimpleResource * { |
| int num = encoding64::inst16_format::ExtractCsRs2(inst_word_); |
| return resource_pool_->GetOrAddResource(absl::StrCat("d", num)); |
| })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kC3rd), |
| [this]() -> generic::SimpleResource * { |
| int num = encoding64::inst16_format::ExtractClRd(inst_word_); |
| // If num is 0 it refers to the zero register. No resource. |
| if (num == 0) return nullptr; |
| return resource_pool_->GetOrAddResource(absl::StrCat("x", num)); |
| })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kC3rs1), |
| [this]() -> generic::SimpleResource * { |
| int num = encoding64::inst16_format::ExtractClRs1(inst_word_); |
| // If num is 0 it refers to the zero register. No resource. |
| if (num == 0) return nullptr; |
| return resource_pool_->GetOrAddResource(absl::StrCat("x", num)); |
| })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kC3rs2), |
| [this]() -> generic::SimpleResource * { |
| int num = encoding64::inst16_format::ExtractCsRs2(inst_word_); |
| // If num is 0 it refers to the zero register. No resource. |
| if (num == 0) return nullptr; |
| return resource_pool_->GetOrAddResource(absl::StrCat("x", num)); |
| })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kCdrs2), |
| [this]() -> generic::SimpleResource * { |
| auto num = encoding64::c_r::ExtractRs2(inst_word_); |
| return resource_pool_->GetOrAddResource(absl::StrCat("d", num)); |
| })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kCrs1), |
| [this]() -> generic::SimpleResource * { |
| auto num = encoding64::c_r::ExtractRs1(inst_word_); |
| // If num is 0 it refers to the zero register. No resource. |
| if (num == 0) return nullptr; |
| return resource_pool_->GetOrAddResource(absl::StrCat("x", num)); |
| })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kCrs2), |
| [this]() -> generic::SimpleResource * { |
| auto num = encoding64::c_r::ExtractRs2(inst_word_); |
| // If num is 0 it refers to the zero register. No resource. |
| if (num == 0) return nullptr; |
| return resource_pool_->GetOrAddResource(absl::StrCat("x", num)); |
| })); |
| simple_resource_getters_.insert( |
| std::make_pair(static_cast<int>(SimpleResourceEnum::kCsr), |
| [this]() -> generic::SimpleResource * { |
| return resource_pool_->GetOrAddResource("csr"); |
| })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kDrd), |
| [this]() -> generic::SimpleResource * { |
| auto num = encoding64::r4_type::ExtractRd(inst_word_); |
| return resource_pool_->GetOrAddResource(absl::StrCat("d", num)); |
| })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kDrs1), |
| [this]() -> generic::SimpleResource * { |
| auto num = encoding64::a_type::ExtractRs1(inst_word_); |
| return resource_pool_->GetOrAddResource(absl::StrCat("d", num)); |
| })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kDrs2), |
| [this]() -> generic::SimpleResource * { |
| auto num = encoding64::a_type::ExtractRs2(inst_word_); |
| return resource_pool_->GetOrAddResource(absl::StrCat("d", num)); |
| })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kDrs3), |
| [this]() -> generic::SimpleResource * { |
| auto num = encoding64::r4_type::ExtractRs3(inst_word_); |
| return resource_pool_->GetOrAddResource(absl::StrCat("d", num)); |
| })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kFrd), |
| [this]() -> generic::SimpleResource * { |
| auto num = encoding64::r4_type::ExtractRd(inst_word_); |
| return resource_pool_->GetOrAddResource(absl::StrCat("d", num)); |
| })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kFrs1), |
| [this]() -> generic::SimpleResource * { |
| auto num = encoding64::r4_type::ExtractRs1(inst_word_); |
| return resource_pool_->GetOrAddResource(absl::StrCat("d", num)); |
| })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kFrs2), |
| [this]() -> generic::SimpleResource * { |
| auto num = encoding64::r4_type::ExtractRs2(inst_word_); |
| return resource_pool_->GetOrAddResource(absl::StrCat("d", num)); |
| })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kFrs3), |
| [this]() -> generic::SimpleResource * { |
| auto num = encoding64::r4_type::ExtractRs3(inst_word_); |
| return resource_pool_->GetOrAddResource(absl::StrCat("d", num)); |
| })); |
| simple_resource_getters_.insert( |
| std::make_pair(static_cast<int>(SimpleResourceEnum::kNextPc), |
| [this]() -> generic::SimpleResource * { |
| return resource_pool_->GetOrAddResource("next_pc"); |
| })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kRd), |
| [this]() -> generic::SimpleResource * { |
| auto num = encoding64::a_type::ExtractRd(inst_word_); |
| // If num is 0 it refers to the zero register. No resource. |
| if (num == 0) return nullptr; |
| return resource_pool_->GetOrAddResource(absl::StrCat("x", num)); |
| })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kRs1), |
| [this]() -> generic::SimpleResource * { |
| auto num = encoding64::a_type::ExtractRs1(inst_word_); |
| // If num is 0 it refers to the zero register. No resource. |
| if (num == 0) return nullptr; |
| return resource_pool_->GetOrAddResource(absl::StrCat("x", num)); |
| })); |
| simple_resource_getters_.insert(std::make_pair( |
| static_cast<int>(SimpleResourceEnum::kRs2), |
| [this]() -> generic::SimpleResource * { |
| auto num = encoding64::a_type::ExtractRs2(inst_word_); |
| // If num is 0 it refers to the zero register. No resource. |
| if (num == 0) return nullptr; |
| return resource_pool_->GetOrAddResource(absl::StrCat("x", num)); |
| })); |
| // X0 is constant 0, so no resource issue. |
| simple_resource_getters_.insert( |
| std::make_pair(static_cast<int>(SimpleResourceEnum::kX0), |
| []() -> generic::SimpleResource * { return nullptr; })); |
| simple_resource_getters_.insert( |
| std::make_pair(static_cast<int>(SimpleResourceEnum::kX1), |
| [this]() -> generic::SimpleResource * { |
| return resource_pool_->GetOrAddResource("x1"); |
| })); |
| simple_resource_getters_.insert( |
| std::make_pair(static_cast<int>(SimpleResourceEnum::kX2), |
| [this]() -> generic::SimpleResource * { |
| return resource_pool_->GetOrAddResource("x2"); |
| })); |
| } |
| |
| ResourceOperandInterface *RiscV64GEncoding::GetSimpleResourceOperand( |
| SlotEnum, int, OpcodeEnum, SimpleResourceVector &resource_vec, int end) { |
| if (resource_vec.empty()) return nullptr; |
| auto *resource_set = resource_pool_->CreateResourceSet(); |
| for (auto resource_enum : resource_vec) { |
| int index = static_cast<int>(resource_enum); |
| auto iter = simple_resource_getters_.find(index); |
| if (iter == simple_resource_getters_.end()) { |
| LOG(WARNING) << "No getter for simple resource " << index; |
| continue; |
| } |
| auto *resource = (iter->second)(); |
| auto status = resource_set->AddResource(resource); |
| if (!status.ok()) { |
| LOG(ERROR) << "Unable to add resource to resource set (" |
| << static_cast<int>(resource_enum) << ")"; |
| } |
| } |
| auto *op = new SimpleResourceOperand(resource_set, end, resource_delay_line_); |
| return op; |
| } |
| |
| DestinationOperandInterface *RiscV64GEncoding::GetDestination( |
| SlotEnum, int, OpcodeEnum, DestOpEnum dest_op, int dest_no, int latency) { |
| int index = static_cast<int>(dest_op); |
| auto iter = dest_op_getters_.find(index); |
| if (iter == dest_op_getters_.end()) { |
| LOG(ERROR) << "No getter for destination op " << index; |
| return nullptr; |
| } |
| return (iter->second)(latency); |
| } |
| |
| SourceOperandInterface *RiscV64GEncoding::GetSource(SlotEnum, int, OpcodeEnum, |
| SourceOpEnum source_op, |
| int source_no) { |
| int index = static_cast<int>(source_op); |
| auto iter = source_op_getters_.find(index); |
| if (iter == source_op_getters_.end()) return nullptr; |
| return (iter->second)(); |
| } |
| |
| } // namespace isa64 |
| } // namespace riscv |
| } // namespace sim |
| } // namespace mpact |