blob: d235d5a00f44c6efbfea3dc35079fab83a93f9a7 [file]
// 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_vec_encoding.h"
#include <cstdint>
#include <string>
#include <utility>
#include <vector>
#include "absl/base/casts.h"
#include "absl/log/log.h"
#include "absl/strings/str_cat.h"
#include "absl/types/span.h"
#include "mpact/sim/generic/immediate_operand.h"
#include "mpact/sim/generic/literal_operand.h"
#include "mpact/sim/generic/register.h"
#include "mpact/sim/generic/simple_resource.h"
#include "mpact/sim/generic/simple_resource_operand.h"
#include "mpact/sim/generic/type_helpers.h"
#include "riscv/riscv64gv_bin_decoder.h"
#include "riscv/riscv64gv_decoder.h"
#include "riscv/riscv64gv_enums.h"
#include "riscv/riscv_register.h"
#include "riscv/riscv_state.h"
namespace mpact {
namespace sim {
namespace riscv {
namespace isa64v {
namespace {
using generic::SimpleResourceOperand;
using ::mpact::sim::generic::operator*; // NOLINT: is used below.
constexpr int kNumRegTable[8] = {8, 1, 2, 1, 4, 1, 2, 1};
template <typename M, typename E, typename G>
inline void Insert(M& map, E entry, G getter) {
map.insert(std::make_pair(static_cast<int>(entry), getter));
}
template <typename RegType>
inline void GetVRegGroup(RiscVState* state, int reg_num,
std::vector<generic::RegisterBase*>* vreg_group) {
// The number of registers in a vector register group depends on the register
// index: 0, 8, 16, 24 each have 8 registers, 4, 12, 20, 28 each have 4,
// 2, 6, 10, 14, 18, 22, 26, 30 each have two, and all odd numbered register
// groups have only 1.
int num_regs = kNumRegTable[reg_num % 8];
for (int i = 0; i < num_regs; i++) {
auto vreg_name = absl::StrCat(RiscVState::kVregPrefix, reg_num + i);
vreg_group->push_back(state->GetRegister<RegType>(vreg_name).first);
}
}
template <typename RegType>
inline SourceOperandInterface* GetVectorRegisterSourceOp(RiscVState* state,
int reg_num) {
std::vector<generic::RegisterBase*> vreg_group;
GetVRegGroup<RegType>(state, reg_num, &vreg_group);
auto* v_src_op = new RV32VectorSourceOperand(
absl::Span<generic::RegisterBase*>(vreg_group),
absl::StrCat(RiscVState::kVregPrefix, reg_num));
return v_src_op;
}
template <typename RegType>
inline DestinationOperandInterface* GetVectorRegisterDestinationOp(
RiscVState* state, int latency, int reg_num) {
std::vector<generic::RegisterBase*> vreg_group;
GetVRegGroup<RegType>(state, reg_num, &vreg_group);
auto* v_dst_op = new RV32VectorDestinationOperand(
absl::Span<generic::RegisterBase*>(vreg_group), latency,
absl::StrCat(RiscVState::kVregPrefix, reg_num));
return v_dst_op;
}
template <typename RegType>
inline SourceOperandInterface* GetVectorMaskRegisterSourceOp(RiscVState* state,
int reg_num) {
// Mask register groups only have a single register.
std::vector<generic::RegisterBase*> vreg_group;
vreg_group.push_back(
state
->GetRegister<RegType>(absl::StrCat(RiscVState::kVregPrefix, reg_num))
.first);
auto* v_src_op = new RV32VectorSourceOperand(
absl::Span<generic::RegisterBase*>(vreg_group),
absl::StrCat(RiscVState::kVregPrefix, reg_num));
return v_src_op;
}
template <typename RegType>
inline DestinationOperandInterface* GetVectorMaskRegisterDestinationOp(
RiscVState* state, int latency, int reg_num) {
// Mask register groups only have a single register.
std::vector<generic::RegisterBase*> vreg_group;
vreg_group.push_back(
state
->GetRegister<RegType>(absl::StrCat(RiscVState::kVregPrefix, reg_num))
.first);
auto* v_dst_op = new RV32VectorDestinationOperand(
absl::Span<generic::RegisterBase*>(vreg_group), latency,
absl::StrCat(RiscVState::kVregPrefix, reg_num));
return v_dst_op;
}
// 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;
}
} // namespace
RiscV64GVecEncoding::RiscV64GVecEncoding(RiscVState* state)
: RiscV64GVecEncoding(state, true) {}
RiscV64GVecEncoding::RiscV64GVecEncoding(RiscVState* state, bool use_abi_names)
: state_(state) {
if (use_abi_names) {
xreg_alias_ = xreg_abi_names_;
} else {
xreg_alias_ = xreg_names_;
}
InitializeSourceOperandGetters();
InitializeDestinationOperandGetters();
InitializeVectorSourceOperandGetters();
InitializeVectorDestinationOperandGetters();
InitializeSimpleResourceGetters();
resource_pool_ = new generic::SimpleResourcePool("RiscV64GV", 128);
resource_delay_line_ =
state_->CreateAndAddDelayLine<generic::SimpleResourceDelayLine>(8);
for (int i = *SourceOpEnum::kNone; i < *SourceOpEnum::kPastMaxValue; ++i) {
if (source_op_getters_.find(i) == source_op_getters_.end()) {
LOG(ERROR) << "No getter for source op enum value " << i;
}
}
for (int i = *DestOpEnum::kNone; i < *DestOpEnum::kPastMaxValue; ++i) {
if (dest_op_getters_.find(i) == dest_op_getters_.end()) {
LOG(ERROR) << "No getter for destination op enum value " << i;
}
}
}
RiscV64GVecEncoding::~RiscV64GVecEncoding() { delete resource_pool_; }
void RiscV64GVecEncoding::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]() {
uint32_t uimm = encoding64::u_type::ExtractUImm(inst_word_);
return new generic::ImmediateOperand<int32_t>(
absl::bit_cast<int32_t>(uimm));
}));
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::kFs1), [this]() {
const int num = encoding64::v_arith::ExtractRs1(inst_word_);
return GetRegisterSourceOp<RV64Register>(state_, freg_names_[num],
freg_abi_names_[num]);
}));
source_op_getters_.insert(std::make_pair(
static_cast<int>(SourceOpEnum::kNone), []() { return nullptr; }));
}
void RiscV64GVecEncoding::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::kFd), [this](int latency) {
const int num = encoding64::v_arith::ExtractRd(inst_word_);
return GetRegisterDestinationOp<RV64Register>(
state_, freg_names_[num], latency, freg_abi_names_[num]);
}));
dest_op_getters_.insert(std::make_pair(static_cast<int>(DestOpEnum::kNone),
[](int latency) { return nullptr; }));
}
void RiscV64GVecEncoding::InitializeVectorSourceOperandGetters() {
Insert(source_op_getters_, SourceOpEnum::kVd,
[this]() -> SourceOperandInterface* {
auto num = encoding64::v_arith::ExtractVd(inst_word_);
return GetVectorRegisterSourceOp<RVVectorRegister>(state_, num);
});
Insert(source_op_getters_, SourceOpEnum::kVmask,
[this]() -> SourceOperandInterface* {
auto vm = encoding64::v_arith::ExtractVm(inst_word_);
if (vm == 1) {
// Unmasked, return the True mask.
return new RV32VectorTrueOperand(state_);
}
// Masked. Return the mask register.
return GetVectorMaskRegisterSourceOp<RVVectorRegister>(state_, 0);
});
Insert(source_op_getters_, SourceOpEnum::kVmaskTrue,
[this]() -> SourceOperandInterface* {
return new RV32VectorTrueOperand(state_);
});
Insert(source_op_getters_, SourceOpEnum::kVm,
[this]() -> SourceOperandInterface* {
auto vm = encoding64::v_arith::ExtractVm(inst_word_);
return new generic::ImmediateOperand<bool>(
vm, absl::StrCat("vm.", vm ? "t" : "f"));
});
Insert(source_op_getters_, SourceOpEnum::kVs1,
[this]() -> SourceOperandInterface* {
auto num = encoding64::v_arith::ExtractVs1(inst_word_);
return GetVectorRegisterSourceOp<RVVectorRegister>(state_, num);
});
Insert(source_op_getters_, SourceOpEnum::kVs2,
[this]() -> SourceOperandInterface* {
auto num = encoding64::v_arith::ExtractVs2(inst_word_);
return GetVectorRegisterSourceOp<RVVectorRegister>(state_, num);
});
Insert(source_op_getters_, SourceOpEnum::kVs3,
[this]() -> SourceOperandInterface* {
auto num = encoding64::v_mem::ExtractVs3(inst_word_);
return GetVectorRegisterSourceOp<RVVectorRegister>(state_, num);
});
Insert(source_op_getters_, SourceOpEnum::kSimm5,
[this]() -> SourceOperandInterface* {
const auto num = encoding64::inst32_format::ExtractSimm5(inst_word_);
return new generic::ImmediateOperand<int32_t>(num);
});
Insert(source_op_getters_, SourceOpEnum::kUimm5,
[this]() -> SourceOperandInterface* {
const auto num = encoding64::inst32_format::ExtractUimm5(inst_word_);
return new generic::ImmediateOperand<int32_t>(num);
});
Insert(source_op_getters_, SourceOpEnum::kZimm10,
[this]() -> SourceOperandInterface* {
const auto num =
encoding64::inst32_format::ExtractZimm10(inst_word_);
return new generic::ImmediateOperand<int32_t>(num);
});
Insert(source_op_getters_, SourceOpEnum::kZimm11,
[this]() -> SourceOperandInterface* {
const auto num =
encoding64::inst32_format::ExtractZimm11(inst_word_);
return new generic::ImmediateOperand<int32_t>(num);
});
Insert(source_op_getters_, SourceOpEnum::kConst1,
[]() -> SourceOperandInterface* {
return new generic::ImmediateOperand<int32_t>(1);
});
Insert(source_op_getters_, SourceOpEnum::kConst2,
[]() -> SourceOperandInterface* {
return new generic::ImmediateOperand<int32_t>(2);
});
Insert(source_op_getters_, SourceOpEnum::kConst4,
[]() -> SourceOperandInterface* {
return new generic::ImmediateOperand<int32_t>(4);
});
Insert(source_op_getters_, SourceOpEnum::kConst8,
[]() -> SourceOperandInterface* {
return new generic::ImmediateOperand<int32_t>(8);
});
Insert(source_op_getters_, SourceOpEnum::kNf,
[this]() -> SourceOperandInterface* {
auto num_fields = encoding64::v_mem::ExtractNf(inst_word_);
return new generic::ImmediateOperand<uint8_t>(
num_fields, absl::StrCat(num_fields + 1));
});
}
void RiscV64GVecEncoding::InitializeVectorDestinationOperandGetters() {
Insert(dest_op_getters_, DestOpEnum::kVd,
[this](int latency) -> DestinationOperandInterface* {
auto num = encoding64::v_arith::ExtractVd(inst_word_);
return GetVectorRegisterDestinationOp<RVVectorRegister>(
state_, latency, num);
});
}
// Parse the instruction word to determine the opcode.
void RiscV64GVecEncoding::ParseInstruction(uint32_t inst_word) {
inst_word_ = inst_word;
if ((inst_word_ & 0x3) == 3) {
opcode_ = mpact::sim::riscv::encoding64::DecodeRiscV64GVInst32(inst_word_);
return;
}
opcode_ = mpact::sim::riscv::encoding64::DecodeRiscVCInst16(
static_cast<uint16_t>(inst_word_ & 0xffff));
}
void RiscV64GVecEncoding::InitializeComplexResourceOperandGetters() {
complex_resource_getters_.insert(
std::make_pair(static_cast<int>(ComplexResourceEnum::kNone),
[](int begin, int end) { return nullptr; }));
}
ResourceOperandInterface* RiscV64GVecEncoding::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 RiscV64GVecEncoding::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* RiscV64GVecEncoding::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* RiscV64GVecEncoding::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* RiscV64GVecEncoding::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()) {
LOG(ERROR) << "No getter for source op " << index;
return nullptr;
}
return (iter->second)();
}
} // namespace isa64v
} // namespace riscv
} // namespace sim
} // namespace mpact