blob: 679fa5b08a054007deaf3b0185684babeded2f09 [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/riscv32g_vec_encoding.h"
#include <cstdint>
#include <string>
#include <utility>
#include <vector>
#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 "riscv/riscv32gv_bin_decoder.h"
#include "riscv/riscv32gv_decoder.h"
#include "riscv/riscv32gv_enums.h"
#include "riscv/riscv_register.h"
#include "riscv/riscv_state.h"
namespace mpact {
namespace sim {
namespace riscv {
namespace isa32v {
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));
}
constexpr int kNumRegTable[8] = {8, 1, 2, 1, 4, 1, 2, 1};
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;
}
RiscV32GVecEncoding::RiscV32GVecEncoding(RiscVState* state) : state_(state) {
InitializeSourceOperandGetters();
InitializeDestinationOperandGetters();
InitializeSimpleResourceGetters();
InitializeVectorSourceOperandGetters();
InitializeVectorDestinationOperandGetters();
resource_pool_ = new generic::SimpleResourcePool("RiscV32GV", 128);
resource_delay_line_ =
state_->CreateAndAddDelayLine<generic::SimpleResourceDelayLine>(8);
}
RiscV32GVecEncoding::~RiscV32GVecEncoding() { delete resource_pool_; }
void RiscV32GVecEncoding::InitializeVectorSourceOperandGetters() {
Insert(source_op_getters_, SourceOpEnum::kVd,
[this]() -> SourceOperandInterface* {
auto num = encoding::v_arith::ExtractVd(inst_word_);
return GetVectorRegisterSourceOp<RVVectorRegister>(state_, num);
});
Insert(source_op_getters_, SourceOpEnum::kVmask,
[this]() -> SourceOperandInterface* {
auto vm = encoding::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::kVs1,
[this]() -> SourceOperandInterface* {
auto num = encoding::v_arith::ExtractVs1(inst_word_);
return GetVectorRegisterSourceOp<RVVectorRegister>(state_, num);
});
Insert(source_op_getters_, SourceOpEnum::kVs2,
[this]() -> SourceOperandInterface* {
auto num = encoding::v_arith::ExtractVs2(inst_word_);
return GetVectorRegisterSourceOp<RVVectorRegister>(state_, num);
});
Insert(source_op_getters_, SourceOpEnum::kVs3,
[this]() -> SourceOperandInterface* {
auto num = encoding::v_mem::ExtractVs3(inst_word_);
return GetVectorRegisterSourceOp<RVVectorRegister>(state_, num);
});
Insert(source_op_getters_, SourceOpEnum::kSimm5,
[this]() -> SourceOperandInterface* {
const auto num = encoding::inst32_format::ExtractSimm5(inst_word_);
return new generic::ImmediateOperand<int32_t>(num);
});
Insert(source_op_getters_, SourceOpEnum::kUimm5,
[this]() -> SourceOperandInterface* {
const auto num = encoding::inst32_format::ExtractUimm5(inst_word_);
return new generic::ImmediateOperand<int32_t>(num);
});
Insert(source_op_getters_, SourceOpEnum::kZimm10,
[this]() -> SourceOperandInterface* {
const auto num = encoding::inst32_format::ExtractZimm10(inst_word_);
return new generic::ImmediateOperand<int32_t>(num);
});
Insert(source_op_getters_, SourceOpEnum::kZimm11,
[this]() -> SourceOperandInterface* {
const auto num = encoding::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 = encoding::v_mem::ExtractNf(inst_word_);
return new generic::ImmediateOperand<uint8_t>(
num_fields, absl::StrCat(num_fields + 1));
});
}
void RiscV32GVecEncoding::InitializeVectorDestinationOperandGetters() {
Insert(dest_op_getters_, DestOpEnum::kVd,
[this](int latency) -> DestinationOperandInterface* {
auto num = encoding::v_arith::ExtractVd(inst_word_);
return GetVectorRegisterDestinationOp<RVVectorRegister>(
state_, latency, num);
});
}
void RiscV32GVecEncoding::InitializeSourceOperandGetters() {
// Source operand getters.
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kAAq),
[this]() -> SourceOperandInterface* {
if (encoding::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 (encoding::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::kBImm12), [this]() {
return new generic::ImmediateOperand<int32_t>(
encoding::inst32_format::ExtractBImm(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kC3drs2), [this]() {
auto num = encoding::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::kC3frs2), [this]() {
auto num = encoding::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 = encoding::inst16_format::ExtractCsRs1(inst_word_);
return GetRegisterSourceOp<RV32Register>(
state_, absl::StrCat(RiscVState::kXregPrefix, num),
xreg_alias_[num]);
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kC3rs2), [this]() {
auto num = encoding::inst16_format::ExtractCsRs2(inst_word_);
return GetRegisterSourceOp<RV32Register>(
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>(
encoding::inst32_format::ExtractIUimm5(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kCdrs2), [this]() {
auto num = encoding::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::kCfrs2), [this]() {
auto num = encoding::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 = encoding::c_r::ExtractRs1(inst_word_);
return GetRegisterSourceOp<RV32Register>(
state_, absl::StrCat(RiscVState::kXregPrefix, num),
xreg_alias_[num]);
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kCrs2), [this]() {
auto num = encoding::c_r::ExtractRs2(inst_word_);
return GetRegisterSourceOp<RV32Register>(
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 = encoding::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 = encoding::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 = encoding::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 = encoding::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 = encoding::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 = encoding::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 = encoding::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::kFs1), [this]() {
const int num = encoding::v_arith::ExtractRs1(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>(
encoding::inst16_format::ExtractBimm(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kICiImm6), [this]() {
return new generic::ImmediateOperand<int32_t>(
encoding::c_i::ExtractImm6(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kICiImm612), [this]() {
return new generic::ImmediateOperand<int32_t>(
encoding::inst16_format::ExtractImm18(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kICiUimm6), [this]() {
return new generic::ImmediateOperand<uint32_t>(
encoding::inst16_format::ExtractUimm6(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kICiUimm6x4), [this]() {
return new generic::ImmediateOperand<uint32_t>(
encoding::inst16_format::ExtractCiImmW(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kICiUimm6x8), [this]() {
return new generic::ImmediateOperand<uint32_t>(
encoding::inst16_format::ExtractCiImmD(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kICiImm6x16), [this]() {
return new generic::ImmediateOperand<int32_t>(
encoding::inst16_format::ExtractCiImm10(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kICiwUimm8x4), [this]() {
return new generic::ImmediateOperand<uint32_t>(
encoding::inst16_format::ExtractCiwImm10(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kICjImm11), [this]() {
return new generic::ImmediateOperand<int32_t>(
encoding::inst16_format::ExtractJimm(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kIClUimm5x4), [this]() {
return new generic::ImmediateOperand<uint32_t>(
encoding::inst16_format::ExtractClImmW(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kIClUimm5x8), [this]() {
return new generic::ImmediateOperand<uint32_t>(
encoding::inst16_format::ExtractClImmD(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kICssUimm6x4), [this]() {
return new generic::ImmediateOperand<uint32_t>(
encoding::inst16_format::ExtractCssImmW(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kICssUimm6x8), [this]() {
return new generic::ImmediateOperand<uint32_t>(
encoding::inst16_format::ExtractCssImmD(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kIImm12), [this]() {
return new generic::ImmediateOperand<int32_t>(
encoding::inst32_format::ExtractImm12(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kIUimm5), [this]() {
return new generic::ImmediateOperand<uint32_t>(
encoding::inst32_format::ExtractRUimm5(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kJImm12), [this]() {
return new generic::ImmediateOperand<int32_t>(
encoding::inst32_format::ExtractImm12(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kJImm20), [this]() {
return new generic::ImmediateOperand<int32_t>(
encoding::inst32_format::ExtractJImm(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kPred), [this]() {
return new generic::ImmediateOperand<uint32_t>(
encoding::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 = encoding::r_type::ExtractRd(inst_word_);
if (num == 0)
return new generic::IntLiteralOperand<0>({1}, xreg_alias_[0]);
return GetRegisterSourceOp<RV32Register>(
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 = encoding::r_type::ExtractRs1(inst_word_);
if (num == 0)
return new generic::IntLiteralOperand<0>({1}, xreg_alias_[0]);
return GetRegisterSourceOp<RV32Register>(
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 = encoding::r_type::ExtractRs2(inst_word_);
if (num == 0)
return new generic::IntLiteralOperand<0>({1}, xreg_alias_[0]);
return GetRegisterSourceOp<RV32Register>(
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>(
encoding::inst32_format::ExtractSImm(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kSucc), [this]() {
return new generic::ImmediateOperand<uint32_t>(
encoding::fence::ExtractSucc(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(static_cast<int>(SourceOpEnum::kUImm20), [this]() {
return new generic::ImmediateOperand<int32_t>(
encoding::inst32_format::ExtractUImm(inst_word_));
}));
Insert(source_op_getters_, SourceOpEnum::kVm,
[this]() -> SourceOperandInterface* {
auto vm = encoding::v_arith::ExtractVm(inst_word_);
return new generic::ImmediateOperand<bool>(
vm, absl::StrCat("vm.", vm ? "t" : "f"));
});
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]() {
return GetRegisterSourceOp<RV32Register>(
state_, absl::StrCat(RiscVState::kXregPrefix, 2), xreg_alias_[2]);
}));
source_op_getters_.insert(std::make_pair(
static_cast<int>(SourceOpEnum::kNone), []() { return nullptr; }));
}
void RiscV32GVecEncoding::InitializeDestinationOperandGetters() {
// Destination operand getters.
dest_op_getters_.insert(
std::make_pair(static_cast<int>(DestOpEnum::kC3drd), [this](int latency) {
int num = encoding::inst16_format::ExtractClRd(inst_word_);
return GetRegisterDestinationOp<RV32Register>(
state_, absl::StrCat(RiscVState::kXregPrefix, num), latency,
xreg_alias_[num]);
}));
dest_op_getters_.insert(
std::make_pair(static_cast<int>(DestOpEnum::kC3frd), [this](int latency) {
int num = encoding::inst16_format::ExtractClRd(inst_word_);
return GetRegisterDestinationOp<RVFpRegister>(
state_, absl::StrCat(RiscVState::kXregPrefix, num), latency);
}));
dest_op_getters_.insert(
std::make_pair(static_cast<int>(DestOpEnum::kC3rd), [this](int latency) {
int num = encoding::inst16_format::ExtractClRd(inst_word_);
return GetRegisterDestinationOp<RVFpRegister>(
state_, absl::StrCat(RiscVState::kXregPrefix, num), latency);
}));
dest_op_getters_.insert(
std::make_pair(static_cast<int>(DestOpEnum::kC3rs1), [this](int latency) {
int num = encoding::inst16_format::ExtractClRs1(inst_word_);
return GetRegisterDestinationOp<RV32Register>(
state_, absl::StrCat(RiscVState::kXregPrefix, num), latency,
xreg_alias_[num]);
}));
dest_op_getters_.insert(
std::make_pair(static_cast<int>(DestOpEnum::kCsr), [this](int latency) {
return GetRegisterDestinationOp<RV32Register>(
state_, RiscVState::kCsrName, latency);
}));
dest_op_getters_.insert(
std::make_pair(static_cast<int>(DestOpEnum::kDrd), [this](int latency) {
int num = encoding::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::kFd), [this](int latency) {
int num = encoding::v_arith::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 = encoding::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) {
return GetRegisterDestinationOp<RV32Register>(
state_, RiscVState::kPcName, latency);
}));
dest_op_getters_.insert(
std::make_pair(static_cast<int>(DestOpEnum::kRd),
[this](int latency) -> DestinationOperandInterface* {
int num = encoding::r_type::ExtractRd(inst_word_);
if (num == 0) {
return GetRegisterDestinationOp<RV32Register>(
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) {
return GetRegisterDestinationOp<RV32Register>(state_, "X0Dest", 0,
xreg_alias_[0]);
}));
dest_op_getters_.insert(
std::make_pair(static_cast<int>(DestOpEnum::kX1), [this](int latency) {
return GetRegisterDestinationOp<RV32Register>(
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) {
return GetRegisterDestinationOp<RV32Register>(
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 RiscV32GVecEncoding::ParseInstruction(uint32_t inst_word) {
inst_word_ = inst_word;
if ((inst_word_ & 0x3) == 3) {
opcode_ = mpact::sim::riscv::encoding::DecodeRiscV32GV(inst_word_);
return;
}
opcode_ = mpact::sim::riscv::encoding::DecodeRiscVCInst16(
static_cast<uint16_t>(inst_word_ & 0xffff));
}
void RiscV32GVecEncoding::InitializeComplexResourceOperandGetters() {
complex_resource_getters_.insert(
std::make_pair(static_cast<int>(ComplexResourceEnum::kNone),
[](int begin, int end) { return nullptr; }));
}
ResourceOperandInterface* RiscV32GVecEncoding::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 RiscV32GVecEncoding::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 = encoding::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 = encoding::inst16_format::ExtractCsRs2(inst_word_);
return resource_pool_->GetOrAddResource(absl::StrCat("d", num));
}));
simple_resource_getters_.insert(std::make_pair(
static_cast<int>(SimpleResourceEnum::kC3frd),
[this]() -> generic::SimpleResource* {
int num = encoding::inst16_format::ExtractClRd(inst_word_);
return resource_pool_->GetOrAddResource(absl::StrCat("d", num));
}));
simple_resource_getters_.insert(std::make_pair(
static_cast<int>(SimpleResourceEnum::kC3frs2),
[this]() -> generic::SimpleResource* {
int num = encoding::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 = encoding::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 = encoding::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 = encoding::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 = encoding::c_r::ExtractRs2(inst_word_);
return resource_pool_->GetOrAddResource(absl::StrCat("d", num));
}));
simple_resource_getters_.insert(std::make_pair(
static_cast<int>(SimpleResourceEnum::kCfrs2),
[this]() -> generic::SimpleResource* {
auto num = encoding::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 = encoding::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 = encoding::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 = encoding::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 = encoding::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 = encoding::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 = encoding::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 = encoding::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 = encoding::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 = encoding::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 = encoding::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 = encoding::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 = encoding::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 = encoding::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* RiscV32GVecEncoding::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 generic::SimpleResourceOperand(resource_set, end,
resource_delay_line_);
return op;
}
DestinationOperandInterface* RiscV32GVecEncoding::GetDestination(
SlotEnum, int, OpcodeEnum opcode, 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) << absl::StrCat("No getter for destination op enum value ",
index, "for instruction ",
kOpcodeNames[static_cast<int>(opcode)]);
return nullptr;
}
return (iter->second)(latency);
}
SourceOperandInterface* RiscV32GVecEncoding::GetSource(SlotEnum, int,
OpcodeEnum opcode,
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) << absl::StrCat("No getter for source op enum value ", index,
" for instruction ",
kOpcodeNames[static_cast<int>(opcode)]);
return nullptr;
}
return (iter->second)();
}
} // namespace isa32v
} // namespace riscv
} // namespace sim
} // namespace mpact