blob: 7023fd1a8c5ac0148c44708e6aedafa19833b078 [file]
// Copyright 2024 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.
#ifndef THIRD_PARTY_MPACT_RISCV_RISCV_GETTERS_H_
#define THIRD_PARTY_MPACT_RISCV_RISCV_GETTERS_H_
#include <cstdint>
#include <string>
#include "absl/strings/str_cat.h"
#include "mpact/sim/generic/immediate_operand.h"
#include "mpact/sim/generic/literal_operand.h"
#include "mpact/sim/generic/operand_interface.h"
#include "mpact/sim/generic/resource_operand_interface.h"
#include "mpact/sim/generic/simple_resource.h"
#include "riscv/riscv_encoding_common.h"
#include "riscv/riscv_getter_helpers.h"
#include "riscv/riscv_register_aliases.h"
#include "riscv/riscv_state.h"
// This file contains helper functions that are used to initialize "getter maps"
// with lambdas that create source, destination, and resource operands for the
// RiscV32G and RiscV32GZB instruction set decoders. The functions are templated
// so they can be used with different decoders with different sets of
// instruction enumerations and register types.
namespace mpact {
namespace sim {
namespace riscv {
using ::mpact::sim::generic::DestinationOperandInterface;
using ::mpact::sim::generic::ImmediateOperand;
using ::mpact::sim::generic::IntLiteralOperand;
using ::mpact::sim::generic::ResourceOperandInterface;
using ::mpact::sim::generic::SourceOperandInterface;
// The following function adds source operand getters to the given getter map.
// The function uses the template parameters to get the correct enum type
// for the instruction set being decoded. The Extractors parameter is used to
// get the correct instruction format extractor for the instruction set. The
// IntRegister and FpRegister parameters are used to get the correct register
// types for the instruction set.
template <typename Enum, typename Extractors, typename IntRegister,
typename FpRegister>
void AddRiscVSourceGetters(SourceOpGetterMap& getter_map,
RiscVEncodingCommon* common) {
// Source operand getters.
Insert(getter_map, *Enum::kAAq, [common]() -> SourceOperandInterface* {
if (Extractors::Inst32Format::ExtractAq(common->inst_word())) {
return new IntLiteralOperand<1>();
}
return new IntLiteralOperand<0>();
});
Insert(getter_map, *Enum::kARl, [common]() -> SourceOperandInterface* {
if (Extractors::Inst32Format::ExtractRl(common->inst_word())) {
return new generic::IntLiteralOperand<1>();
}
return new generic::IntLiteralOperand<0>();
});
Insert(getter_map, *Enum::kBImm12, [common]() {
return new ImmediateOperand<int32_t>(
Extractors::Inst32Format::ExtractBImm(common->inst_word()));
});
Insert(getter_map, *Enum::kC3drs2, [common]() {
auto num = Extractors::CS::ExtractCsRs2(common->inst_word());
return GetRegisterSourceOp<FpRegister>(
common->state(), absl::StrCat(RiscVState::kFregPrefix, num),
kFRegisterAliases[num]);
});
Insert(getter_map, *Enum::kC3rs1, [common]() {
auto num = Extractors::CS::ExtractCsRs1(common->inst_word());
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, num),
kXRegisterAliases[num]);
});
Insert(getter_map, *Enum::kC3rs2, [common]() {
auto num = Extractors::CS::ExtractCsRs2(common->inst_word());
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, num),
kXRegisterAliases[num]);
});
Insert(getter_map, *Enum::kCSRUimm5, [common]() {
return new ImmediateOperand<uint32_t>(
Extractors::Inst32Format::ExtractIUimm5(common->inst_word()));
});
Insert(getter_map, *Enum::kCdrs2, [common]() {
auto num = Extractors::CR::ExtractRs2(common->inst_word());
return GetRegisterSourceOp<FpRegister>(
common->state(), absl::StrCat(RiscVState::kFregPrefix, num),
kFRegisterAliases[num]);
});
Insert(getter_map, *Enum::kCrs1, [common]() {
auto num = Extractors::CR::ExtractRs1(common->inst_word());
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, num),
kXRegisterAliases[num]);
});
Insert(getter_map, *Enum::kCrs2, [common]() {
auto num = Extractors::CR::ExtractRs2(common->inst_word());
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, num),
kXRegisterAliases[num]);
});
Insert(getter_map, *Enum::kCsr, [common]() {
auto csr_indx = Extractors::IType::ExtractUImm12(common->inst_word());
auto res = common->state()->csr_set()->GetCsr(csr_indx);
if (!res.ok()) {
return new ImmediateOperand<uint32_t>(csr_indx);
}
auto* csr = res.value();
return new ImmediateOperand<uint32_t>(csr_indx, csr->name());
});
Insert(getter_map, *Enum::kDrs1, [common]() -> SourceOperandInterface* {
int num = Extractors::RType::ExtractRs1(common->inst_word());
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kFregPrefix, num),
kFRegisterAliases[num]);
});
Insert(getter_map, *Enum::kDrs2, [common]() -> SourceOperandInterface* {
int num = Extractors::RType::ExtractRs2(common->inst_word());
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kFregPrefix, num),
kFRegisterAliases[num]);
});
Insert(getter_map, *Enum::kDrs3, [common]() -> SourceOperandInterface* {
int num = Extractors::R4Type::ExtractRs3(common->inst_word());
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kFregPrefix, num),
kFRegisterAliases[num]);
});
Insert(getter_map, *Enum::kFrs1, [common]() -> SourceOperandInterface* {
int num = Extractors::RType::ExtractRs1(common->inst_word());
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kFregPrefix, num),
kFRegisterAliases[num]);
});
Insert(getter_map, *Enum::kFrs2, [common]() -> SourceOperandInterface* {
int num = Extractors::RType::ExtractRs2(common->inst_word());
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kFregPrefix, num),
kFRegisterAliases[num]);
});
Insert(getter_map, *Enum::kFrs3, [common]() -> SourceOperandInterface* {
int num = Extractors::R4Type::ExtractRs3(common->inst_word());
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kFregPrefix, num),
kFRegisterAliases[num]);
});
Insert(getter_map, *Enum::kICbImm8, [common]() {
return new ImmediateOperand<int32_t>(
Extractors::Inst16Format::ExtractBimm(common->inst_word()));
});
Insert(getter_map, *Enum::kICiImm6, [common]() {
return new ImmediateOperand<int32_t>(
Extractors::CI::ExtractImm6(common->inst_word()));
});
Insert(getter_map, *Enum::kICiImm612, [common]() {
return new ImmediateOperand<int32_t>(
Extractors::Inst16Format::ExtractImm18(common->inst_word()));
});
Insert(getter_map, *Enum::kICiImm6x16, [common]() {
return new generic::ImmediateOperand<int32_t>(
Extractors::Inst16Format::ExtractCiImm10(common->inst_word()));
});
Insert(getter_map, *Enum::kICiUimm6, [common]() {
return new ImmediateOperand<uint32_t>(
Extractors::Inst16Format::ExtractUimm6(common->inst_word()));
});
Insert(getter_map, *Enum::kICiUimm6x4, [common]() {
return new ImmediateOperand<uint32_t>(
Extractors::Inst16Format::ExtractCiImmW(common->inst_word()));
});
Insert(getter_map, *Enum::kICiUimm6x8, [common]() {
return new ImmediateOperand<uint32_t>(
Extractors::Inst16Format::ExtractCiImmD(common->inst_word()));
});
Insert(getter_map, *Enum::kICiwUimm8x4, [common]() {
return new ImmediateOperand<uint32_t>(
Extractors::Inst16Format::ExtractCiwImm10(common->inst_word()));
});
Insert(getter_map, *Enum::kICjImm11, [common]() {
return new ImmediateOperand<int32_t>(
Extractors::Inst16Format::ExtractJimm(common->inst_word()));
});
Insert(getter_map, *Enum::kIClUimm5x4, [common]() {
return new ImmediateOperand<uint32_t>(
Extractors::Inst16Format::ExtractClImmW(common->inst_word()));
});
Insert(getter_map, *Enum::kIClUimm5x8, [common]() {
return new ImmediateOperand<uint32_t>(
Extractors::Inst16Format::ExtractClImmD(common->inst_word()));
});
Insert(getter_map, *Enum::kICssUimm6x4, [common]() {
return new ImmediateOperand<uint32_t>(
Extractors::Inst16Format::ExtractCssImmW(common->inst_word()));
});
Insert(getter_map, *Enum::kICssUimm6x8, [common]() {
return new ImmediateOperand<uint32_t>(
Extractors::Inst16Format::ExtractCssImmD(common->inst_word()));
});
Insert(getter_map, *Enum::kIImm12, [common]() {
return new ImmediateOperand<int32_t>(
Extractors::Inst32Format::ExtractImm12(common->inst_word()));
});
Insert(getter_map, *Enum::kIUimm5, [common]() {
return new ImmediateOperand<uint32_t>(
Extractors::Inst32Format::ExtractRUimm5(common->inst_word()));
});
Insert(getter_map, *Enum::kJImm12, [common]() {
return new ImmediateOperand<int32_t>(
Extractors::Inst32Format::ExtractImm12(common->inst_word()));
});
Insert(getter_map, *Enum::kJImm20, [common]() {
return new ImmediateOperand<int32_t>(
Extractors::Inst32Format::ExtractJImm(common->inst_word()));
});
Insert(getter_map, *Enum::kPred, [common]() {
return new ImmediateOperand<uint32_t>(
Extractors::Fence::ExtractPred(common->inst_word()));
});
Insert(getter_map, *Enum::kRd, [common]() -> SourceOperandInterface* {
int num = Extractors::RType::ExtractRd(common->inst_word());
if (num == 0) return new generic::IntLiteralOperand<0>({1});
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, num),
kXRegisterAliases[num]);
});
Insert(getter_map, *Enum::kRm, [common]() -> SourceOperandInterface* {
int rm = Extractors::RType::ExtractFunc3(common->inst_word());
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;
}
});
Insert(getter_map, *Enum::kRs1, [common]() -> SourceOperandInterface* {
int num = Extractors::RType::ExtractRs1(common->inst_word());
if (num == 0) return new generic::IntLiteralOperand<0>({1});
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, num),
kXRegisterAliases[num]);
});
Insert(getter_map, *Enum::kRs2, [common]() -> SourceOperandInterface* {
int num = Extractors::RType::ExtractRs2(common->inst_word());
if (num == 0) return new generic::IntLiteralOperand<0>({1});
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, num),
kXRegisterAliases[num]);
});
Insert(getter_map, *Enum::kSImm12, [common]() {
return new ImmediateOperand<int32_t>(
Extractors::SType::ExtractSImm(common->inst_word()));
});
Insert(getter_map, *Enum::kSucc, [common]() {
return new ImmediateOperand<uint32_t>(
Extractors::Fence::ExtractSucc(common->inst_word()));
});
Insert(getter_map, *Enum::kUImm20, [common]() {
return new ImmediateOperand<int32_t>(
Extractors::Inst32Format::ExtractUImm(common->inst_word()));
});
Insert(getter_map, *Enum::kX0,
[]() { return new generic::IntLiteralOperand<0>({1}); });
Insert(getter_map, *Enum::kX2, [common]() {
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, 2),
kXRegisterAliases[2]);
});
}
// This function is used to add the destination operand getters to the given
// "getter map". The function is templated on the enum type that defines the
// destination operand types, the Extractors type that defines the bit
// extraction functions, and the IntRegister and FpRegister types that are used
// to construct the register operand.
template <typename Enum, typename Extractors, typename IntRegister,
typename FpRegister>
void AddRiscVDestGetters(DestOpGetterMap& getter_map,
RiscVEncodingCommon* common) {
// Destination operand getters.
Insert(getter_map, *Enum::kC3drd, [common](int latency) {
int num = Extractors::CL::ExtractClRd(common->inst_word());
return GetRegisterDestinationOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kFregPrefix, num), latency,
kFRegisterAliases[num]);
});
Insert(getter_map, *Enum::kC3rd, [common](int latency) {
int num = Extractors::CL::ExtractClRd(common->inst_word());
return GetRegisterDestinationOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, num), latency,
kXRegisterAliases[num]);
});
Insert(getter_map, *Enum::kC3rs1, [common](int latency) {
int num = Extractors::CL::ExtractClRs1(common->inst_word());
return GetRegisterDestinationOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, num), latency,
kXRegisterAliases[num]);
});
Insert(getter_map, *Enum::kCsr, [common](int latency) {
return GetRegisterDestinationOp<IntRegister>(common->state(),
RiscVState::kCsrName, latency);
});
Insert(getter_map, *Enum::kDrd,
[common](int latency) -> DestinationOperandInterface* {
int num = Extractors::RType::ExtractRd(common->inst_word());
return GetRegisterDestinationOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kFregPrefix, num),
latency, kFRegisterAliases[num]);
});
Insert(getter_map, *Enum::kFrd,
[common](int latency) -> DestinationOperandInterface* {
int num = Extractors::RType::ExtractRd(common->inst_word());
return GetRegisterDestinationOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kFregPrefix, num),
latency, kFRegisterAliases[num]);
});
Insert(getter_map, *Enum::kNextPc,
[common](int latency) -> DestinationOperandInterface* {
return GetRegisterDestinationOp<IntRegister>(
common->state(), RiscVState::kPcName, latency);
});
Insert(getter_map, *Enum::kRd,
[common](int latency) -> DestinationOperandInterface* {
int num = Extractors::RType::ExtractRd(common->inst_word());
if (num == 0) {
return GetRegisterDestinationOp<IntRegister>(common->state(),
"X0Dest", 0);
} else {
return GetRegisterDestinationOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, num),
latency, kXRegisterAliases[num]);
}
});
Insert(getter_map, *Enum::kX0,
[common](int latency) -> DestinationOperandInterface* {
return GetRegisterDestinationOp<IntRegister>(
common->state(), "X0Dest", 0, kXRegisterAliases[0]);
});
Insert(getter_map, *Enum::kX1, [common](int latency) {
return GetRegisterDestinationOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, 1), latency,
kXRegisterAliases[1]);
});
Insert(getter_map, *Enum::kX2, [common](int latency) {
return GetRegisterDestinationOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, 2), latency,
kXRegisterAliases[2]);
});
Insert(getter_map, *Enum::kFflags, [common](int latency) {
return GetCSRSetBitsDestinationOp<uint32_t>(common->state(), "fflags",
latency, "");
});
}
// This function is used to add the simple resource getters to the given
// "getter map". The function is templated on the enum type that defines the
// simple resource types, the Extractors type that defines the bit
// extraction functions, and the IntRegister and FpRegister types that are used
// to construct the register operand.
template <typename Enum, typename Extractors>
void AddRiscVSimpleResourceGetters(SimpleResourceGetterMap& getter_map,
RiscVEncodingCommon* common) {
Insert(getter_map, *Enum::kC3drd, [common]() -> generic::SimpleResource* {
int num = Extractors::CL::ExtractClRd(common->inst_word());
return common->resource_pool()->GetOrAddResource(absl::StrCat("d", num));
});
Insert(getter_map, *Enum::kC3drs2, [common]() -> generic::SimpleResource* {
int num = Extractors::CS::ExtractCsRs2(common->inst_word());
return common->resource_pool()->GetOrAddResource(absl::StrCat("d", num));
});
Insert(getter_map, *Enum::kC3rd, [common]() -> generic::SimpleResource* {
int num = Extractors::CL::ExtractClRd(common->inst_word());
return common->resource_pool()->GetOrAddResource(absl::StrCat("x", num));
});
Insert(getter_map, *Enum::kC3rs1, [common]() -> generic::SimpleResource* {
int num = Extractors::CS::ExtractCsRs1(common->inst_word());
return common->resource_pool()->GetOrAddResource(absl::StrCat("x", num));
});
Insert(getter_map, *Enum::kC3rs2, [common]() -> generic::SimpleResource* {
int num = Extractors::CS::ExtractCsRs2(common->inst_word());
return common->resource_pool()->GetOrAddResource(absl::StrCat("x", num));
});
Insert(getter_map, *Enum::kCdrs2, [common]() -> generic::SimpleResource* {
auto num = Extractors::CR::ExtractRs2(common->inst_word());
return common->resource_pool()->GetOrAddResource(absl::StrCat("d", num));
});
Insert(getter_map, *Enum::kCrs1, [common]() -> generic::SimpleResource* {
auto num = Extractors::CR::ExtractRs1(common->inst_word());
return common->resource_pool()->GetOrAddResource(absl::StrCat("x", num));
});
Insert(getter_map, *Enum::kCrs2, [common]() -> generic::SimpleResource* {
auto num = Extractors::CR::ExtractRs2(common->inst_word());
return common->resource_pool()->GetOrAddResource(absl::StrCat("x", num));
});
Insert(getter_map, *Enum::kCsr, [common]() -> generic::SimpleResource* {
return common->resource_pool()->GetOrAddResource("csr");
});
Insert(getter_map, *Enum::kDrd, [common]() -> generic::SimpleResource* {
int num = Extractors::RType::ExtractRd(common->inst_word());
return common->resource_pool()->GetOrAddResource(absl::StrCat("d", num));
});
Insert(getter_map, *Enum::kDrs1, [common]() -> generic::SimpleResource* {
int num = Extractors::RType::ExtractRs1(common->inst_word());
return common->resource_pool()->GetOrAddResource(absl::StrCat("d", num));
});
Insert(getter_map, *Enum::kDrs2, [common]() -> generic::SimpleResource* {
int num = Extractors::RType::ExtractRs2(common->inst_word());
return common->resource_pool()->GetOrAddResource(absl::StrCat("d", num));
});
Insert(getter_map, *Enum::kDrs3, [common]() -> generic::SimpleResource* {
int num = Extractors::R4Type::ExtractRs3(common->inst_word());
return common->resource_pool()->GetOrAddResource(absl::StrCat("d", num));
});
Insert(getter_map, *Enum::kFrd, [common]() -> generic::SimpleResource* {
int num = Extractors::RType::ExtractRd(common->inst_word());
return common->resource_pool()->GetOrAddResource(absl::StrCat("d", num));
});
Insert(getter_map, *Enum::kFrs1, [common]() -> generic::SimpleResource* {
int num = Extractors::RType::ExtractRs1(common->inst_word());
return common->resource_pool()->GetOrAddResource(absl::StrCat("d", num));
});
Insert(getter_map, *Enum::kFrs2, [common]() -> generic::SimpleResource* {
int num = Extractors::RType::ExtractRs2(common->inst_word());
return common->resource_pool()->GetOrAddResource(absl::StrCat("d", num));
});
Insert(getter_map, *Enum::kFrs3, [common]() -> generic::SimpleResource* {
int num = Extractors::R4Type::ExtractRs3(common->inst_word());
return common->resource_pool()->GetOrAddResource(absl::StrCat("d", num));
});
Insert(getter_map, *Enum::kNextPc, [common]() -> generic::SimpleResource* {
return common->resource_pool()->GetOrAddResource("next_pc");
});
Insert(getter_map, *Enum::kRd, [common]() -> generic::SimpleResource* {
auto num = Extractors::RType::ExtractRd(common->inst_word());
if (num == 0) return nullptr;
return common->resource_pool()->GetOrAddResource(absl::StrCat("x", num));
});
Insert(getter_map, *Enum::kRs1, [common]() -> generic::SimpleResource* {
auto num = Extractors::RType::ExtractRs1(common->inst_word());
if (num == 0) return nullptr;
return common->resource_pool()->GetOrAddResource(absl::StrCat("x", num));
});
Insert(getter_map, *Enum::kRs2, [common]() -> generic::SimpleResource* {
auto num = Extractors::RType::ExtractRs2(common->inst_word());
if (num == 0) return nullptr;
return common->resource_pool()->GetOrAddResource(absl::StrCat("x", num));
});
Insert(getter_map, *Enum::kX0,
[]() -> generic::SimpleResource* { return nullptr; });
Insert(getter_map, *Enum::kX1, [common]() -> generic::SimpleResource* {
return common->resource_pool()->GetOrAddResource("x1");
});
Insert(getter_map, *Enum::kX2, [common]() -> generic::SimpleResource* {
return common->resource_pool()->GetOrAddResource("x2");
});
}
} // namespace riscv
} // namespace sim
} // namespace mpact
#endif // THIRD_PARTY_MPACT_RISCV_RISCV_GETTERS_H_