blob: 8525582b99fb43b6ecf2c7a497bc46da4140af05 [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.
// This file adds operand getters for the Zc* extensions.
#ifndef THIRD_PARTY_MPACT_RISCV_RISCV_ZC_GETTERS_H_
#define THIRD_PARTY_MPACT_RISCV_RISCV_ZC_GETTERS_H_
#include <cstdint>
#include <vector>
#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 "riscv/riscv_encoding_common.h"
#include "riscv/riscv_getter_helpers.h"
#include "riscv/riscv_register_aliases.h"
#include "riscv/riscv_state.h"
namespace mpact::sim::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;
using SourceOpIf = 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.
// Getters for Zca source operands.
template <typename Enum, typename Extractors, typename IntRegister,
typename FpRegister>
void AddRiscVZcaSourceGetters(SourceOpGetterMap &getter_map,
RiscVEncodingCommon *common) {
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::kCrd, [common]() {
auto num = Extractors::CR::ExtractRd(common->inst_word());
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, num),
kXRegisterAliases[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::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::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]() -> SourceOperandInterface * {
return new ImmediateOperand<uint32_t>(
Extractors::Inst16Format::ExtractCiImmW(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::kICssUimm6x4,
[common]() -> SourceOperandInterface * {
return new ImmediateOperand<uint32_t>(
Extractors::Inst16Format::ExtractCssImmW(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]);
});
}
// Getters for Zca destination operands.
template <typename Enum, typename Extractors, typename IntRegister,
typename FpRegister>
void AddRiscVZcaDestGetters(SourceOpGetterMap &getter_map,
RiscVEncodingCommon *common) {
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);
});
}
// Getters for Zcb source operands (not covered in Zca).
template <typename Enum, typename Extractors, typename IntRegister,
typename FpRegister>
void AddRiscVZcbSourceGetters(SourceOpGetterMap &getter_map,
RiscVEncodingCommon *common) {
Insert(getter_map, *Enum::kUimm2b, [common]() {
auto num = Extractors::CLB::ExtractUimm2(common->inst_word());
return new ImmediateOperand<uint32_t>(num);
});
Insert(getter_map, *Enum::kUimm2h, [common](int latency) {
auto num = Extractors::CLH::ExtractUimm2(common->inst_word());
return new ImmediateOperand<uint32_t>(num);
});
}
// Getters for Zcb destination operands (not covered in Zca).
template <typename Enum, typename Extractors, typename IntRegister,
typename FpRegister>
void AddRiscVZcbDestGetters(DestOpGetterMap &getter_map,
RiscVEncodingCommon *common) {
Insert(getter_map, *Enum::kC3rs2, [common](int latency) {
int num = Extractors::CLB::ExtractClRd(common->inst_word());
return GetRegisterDestinationOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, num), latency);
});
}
// Getters for Zcf source operands.
template <typename Enum, typename Extractors, typename IntRegister,
typename FpRegister>
void AddRiscVZcfSourceGetters(SourceOpGetterMap &getter_map,
RiscVEncodingCommon *common) {
Insert(getter_map, *Enum::kC3frs2, [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::kCfrs2, [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::kICiUimm6x4,
[common]() -> SourceOperandInterface * {
return new ImmediateOperand<uint32_t>(
Extractors::Inst16Format::ExtractCiImmW(common->inst_word()));
});
Insert(getter_map, *Enum::kIClUimm5x4, [common]() {
return new ImmediateOperand<uint32_t>(
Extractors::Inst16Format::ExtractClImmW(common->inst_word()));
});
Insert(getter_map, *Enum::kICssUimm6x4, [common]() {
return new ImmediateOperand<uint32_t>(
Extractors::Inst16Format::ExtractCssImmW(common->inst_word()));
});
Insert(getter_map, *Enum::kX2, [common]() {
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, 2),
kXRegisterAliases[2]);
});
}
// Getters for Zcf destination operands.
template <typename Enum, typename Extractors, typename IntRegister,
typename FpRegister>
void AddRiscVZcfDestGetters(DestOpGetterMap &getter_map,
RiscVEncodingCommon *common) {
Insert(getter_map, *Enum::kC3frd, [common](int latency) {
int num = Extractors::CL::ExtractClRd(common->inst_word());
return GetRegisterDestinationOp<FpRegister>(
common->state(), absl::StrCat(RiscVState::kFregPrefix, num), latency);
});
}
// Getters for Zcd source operands.
template <typename Enum, typename Extractors, typename IntRegister,
typename FpRegister>
void AddRiscVZcdSourceGetters(SourceOpGetterMap &getter_map,
RiscVEncodingCommon *common) {
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::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::kICiUimm6x8,
[common]() -> SourceOperandInterface * {
return new ImmediateOperand<uint32_t>(
Extractors::Inst16Format::ExtractCiImmW(common->inst_word()));
});
Insert(getter_map, *Enum::kIClUimm5x8, [common]() {
return new ImmediateOperand<uint32_t>(
Extractors::Inst16Format::ExtractClImmW(common->inst_word()));
});
Insert(getter_map, *Enum::kICssUimm6x8, [common]() {
return new ImmediateOperand<uint32_t>(
Extractors::Inst16Format::ExtractCssImmW(common->inst_word()));
});
Insert(getter_map, *Enum::kX2, [common]() {
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, 2),
kXRegisterAliases[2]);
});
}
// Getters for Zcd destination operands.
template <typename Enum, typename Extractors, typename IntRegister,
typename FpRegister>
void AddRiscVZcdDestGetters(DestOpGetterMap &getter_map,
RiscVEncodingCommon *common) {
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);
});
}
// The following table maps Zcmp Sreg alias register numbers to Xreg numbers.
constexpr int kSRegToXRegMap[8] = {8, 9, 18, 19, 20, 21, 22, 23};
// Getters for Zcmp source operands.
template <typename Enum, typename Extractors, typename IntRegister,
typename FpRegister>
void AddRiscVZcmpSourceGetters(SourceOpGetterMap &getter_map,
RiscVEncodingCommon *common) {
Insert(getter_map, *Enum::kRlist, [common]() {
return new ImmediateOperand<uint32_t>(
Extractors::CMMP::ExtractRlist(common->inst_word()));
});
Insert(getter_map, *Enum::kSpimm, [common]() {
return new ImmediateOperand<uint32_t>(
Extractors::CMMP::ExtractSpimm(common->inst_word()));
});
Insert(getter_map, *Enum::kSreg1, [common]() {
int num =
kSRegToXRegMap[Extractors::CMMV::ExtractRs1p(common->inst_word())];
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, num),
kXRegisterAliases[num]);
});
Insert(getter_map, *Enum::kSreg2, [common]() {
int num =
kSRegToXRegMap[Extractors::CMMV::ExtractRs2p(common->inst_word())];
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, num),
kXRegisterAliases[num]);
});
Insert(getter_map, *Enum::kX2, [common]() {
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, 2),
kXRegisterAliases[2]);
});
Insert(getter_map, *Enum::kX10, [common]() {
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, 10),
kXRegisterAliases[10]);
});
Insert(getter_map, *Enum::kX11, [common]() {
return GetRegisterSourceOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, 11),
kXRegisterAliases[11]);
});
}
// Getters for Zcmp destination operands.
template <typename Enum, typename Extractors, typename IntRegister,
typename FpRegister>
void AddRiscVZcmpDestGetters(DestOpGetterMap &getter_map,
RiscVEncodingCommon *common) {
Insert(getter_map, *Enum::kSreg1, [common](int latency) {
int num =
kSRegToXRegMap[Extractors::CMMV::ExtractRs1p(common->inst_word())];
return GetRegisterDestinationOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, num), latency);
});
Insert(getter_map, *Enum::kSreg2, [common](int latency) {
int num =
kSRegToXRegMap[Extractors::CMMV::ExtractRs2p(common->inst_word())];
return GetRegisterDestinationOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, num), latency);
});
Insert(getter_map, *Enum::kX2, [common](int latency) {
return GetRegisterDestinationOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, 2), latency);
});
Insert(getter_map, *Enum::kX10, [common](int latency) {
return GetRegisterDestinationOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, 10), latency);
});
Insert(getter_map, *Enum::kX11, [common](int latency) {
return GetRegisterDestinationOp<IntRegister>(
common->state(), absl::StrCat(RiscVState::kXregPrefix, 11), latency);
});
}
// Getters for Zcmp list source operands.
template <typename Enum, typename Extractors, typename IntRegister,
typename FpRegister>
void AddRiscVZcmpListSourceGetters(ListSourceOpGetterMap &getter_map,
RiscVEncodingCommon *common) {
Insert(getter_map, *Enum::kRlist, [common]() {
std::vector<SourceOperandInterface *> result;
int rlist = Extractors::CMMP::ExtractRlist(common->inst_word());
// Get the value of 'rlist', and add source operands accordingly.
if (rlist < 4) return result;
result.push_back(GetRegisterSourceOp<IntRegister>(common->state(), "x1"));
if (rlist == 4) return result;
result.push_back(GetRegisterSourceOp<IntRegister>(common->state(), "x8"));
if (rlist == 5) return result;
result.push_back(GetRegisterSourceOp<IntRegister>(common->state(), "x9"));
if (rlist == 6) return result;
result.push_back(GetRegisterSourceOp<IntRegister>(common->state(), "x18"));
if (rlist == 7) return result;
result.push_back(GetRegisterSourceOp<IntRegister>(common->state(), "x19"));
if (rlist == 8) return result;
result.push_back(GetRegisterSourceOp<IntRegister>(common->state(), "x20"));
if (rlist == 9) return result;
result.push_back(GetRegisterSourceOp<IntRegister>(common->state(), "x21"));
if (rlist == 10) return result;
result.push_back(GetRegisterSourceOp<IntRegister>(common->state(), "x22"));
if (rlist == 11) return result;
result.push_back(GetRegisterSourceOp<IntRegister>(common->state(), "x23"));
if (rlist == 12) return result;
result.push_back(GetRegisterSourceOp<IntRegister>(common->state(), "x24"));
if (rlist == 13) return result;
result.push_back(GetRegisterSourceOp<IntRegister>(common->state(), "x25"));
if (rlist == 14) return result;
result.push_back(GetRegisterSourceOp<IntRegister>(common->state(), "x26"));
result.push_back(GetRegisterSourceOp<IntRegister>(common->state(), "x27"));
return result;
});
}
// Getters for Zcmp list destination operands.
template <typename Enum, typename Extractors, typename IntRegister,
typename FpRegister>
void AddRiscVZcmpListDestGetters(ListDestOpGetterMap &getter_map,
RiscVEncodingCommon *common) {
Insert(getter_map, *Enum::kRlist, [common](std::vector<int> latency) {
std::vector<DestinationOperandInterface *> result;
int rlist = Extractors::CMMP::ExtractRlist(common->inst_word());
// Get the value of 'rlist', and add destination operands accordingly.
int size = latency.size();
if (rlist < 4) return result;
result.push_back(GetRegisterDestinationOp<IntRegister>(
common->state(), "x1", latency[result.size() % size]));
if (rlist == 4) return result;
result.push_back(GetRegisterDestinationOp<IntRegister>(
common->state(), "x8", latency[result.size() % size]));
if (rlist == 5) return result;
result.push_back(GetRegisterDestinationOp<IntRegister>(
common->state(), "x9", latency[result.size() % size]));
if (rlist == 6) return result;
result.push_back(GetRegisterDestinationOp<IntRegister>(
common->state(), "x18", latency[result.size() % size]));
if (rlist == 7) return result;
result.push_back(GetRegisterDestinationOp<IntRegister>(
common->state(), "x19", latency[result.size() % size]));
if (rlist == 8) return result;
result.push_back(GetRegisterDestinationOp<IntRegister>(
common->state(), "x20", latency[result.size() % size]));
if (rlist == 9) return result;
result.push_back(GetRegisterDestinationOp<IntRegister>(
common->state(), "x21", latency[result.size() % size]));
if (rlist == 10) return result;
result.push_back(GetRegisterDestinationOp<IntRegister>(
common->state(), "x22", latency[result.size() % size]));
if (rlist == 11) return result;
result.push_back(GetRegisterDestinationOp<IntRegister>(
common->state(), "x23", latency[result.size() % size]));
if (rlist == 12) return result;
result.push_back(GetRegisterDestinationOp<IntRegister>(
common->state(), "x24", latency[result.size() % size]));
if (rlist == 13) return result;
result.push_back(GetRegisterDestinationOp<IntRegister>(
common->state(), "x25", latency[result.size() % size]));
if (rlist == 14) return result;
result.push_back(GetRegisterDestinationOp<IntRegister>(
common->state(), "x26", latency[result.size() % size]));
result.push_back(GetRegisterDestinationOp<IntRegister>(
common->state(), "x27", latency[result.size() % size]));
return result;
});
}
template <typename Enum, typename Extractors, typename IntRegister,
typename FpRegister>
void AddRiscVZcmtSourceGetters(SourceOpGetterMap &getter_map,
RiscVEncodingCommon *common) {
Insert(getter_map, *Enum::kJtIndex, [common](int latency) {
int num = Extractors::CMJT::ExtractIndex(common->inst_word());
return new ImmediateOperand<uint32_t>(num);
});
}
} // namespace mpact::sim::riscv
#endif // THIRD_PARTY_MPACT_RISCV_RISCV_ZC_GETTERS_H_