blob: fa356f315fac06731e703763be91f1d64fcc24b3 [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
//
// http://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/riscv64gzb_encoding.h"
#include <cstdint>
#include "absl/log/log.h"
#include "absl/strings/str_cat.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/riscv64gzb_bin_decoder.h"
#include "riscv/riscv64gzb_decoder.h"
#include "riscv/riscv64gzb_enums.h"
#include "riscv/riscv_encoding_common.h"
#include "riscv/riscv_getters.h"
#include "riscv/riscv_getters_rv64.h"
#include "riscv/riscv_getters_zba.h"
#include "riscv/riscv_getters_zbb64.h"
#include "riscv/riscv_register.h"
#include "riscv/riscv_state.h"
namespace mpact::sim::riscv::isa64gzb {
using ::mpact::sim::generic::operator*; // NOLINT: clang-tidy false positive.
RiscV64GZBEncoding::RiscV64GZBEncoding(RiscVState* state)
: state_(state),
inst_word_(0),
opcode_(OpcodeEnum::kNone),
format_(FormatEnum::kNone) {
resource_pool_ = new generic::SimpleResourcePool("RiscV64GZB", 128);
resource_delay_line_ =
state_->CreateAndAddDelayLine<generic::SimpleResourceDelayLine>(8);
// Initialize getters.
source_op_getters_.emplace(*SourceOpEnum::kNone, []() { return nullptr; });
dest_op_getters_.emplace(*DestOpEnum::kNone,
[](int latency) { return nullptr; });
simple_resource_getters_.emplace(*SimpleResourceEnum::kNone,
[]() { return nullptr; });
complex_resource_getters_.emplace(
*ComplexResourceEnum::kNone,
[](int latency, int end) { return nullptr; });
AddRiscVSourceGetters<SourceOpEnum, Extractors, RV64Register, RVFpRegister>(
source_op_getters_, this);
AddRiscV64SourceGetters<SourceOpEnum, Extractors, RV64Register, RVFpRegister>(
source_op_getters_, this);
AddRiscVZbaSourceGetters<SourceOpEnum, Extractors, RV64Register,
RVFpRegister>(source_op_getters_, this);
AddRiscVZbb64SourceGetters<SourceOpEnum, Extractors, RV64Register,
RVFpRegister>(source_op_getters_, this);
AddRiscVDestGetters<DestOpEnum, Extractors, RV64Register, RVFpRegister>(
dest_op_getters_, this);
AddRiscVZbaDestGetters<DestOpEnum, Extractors, RV64Register, RVFpRegister>(
dest_op_getters_, this);
AddRiscVSimpleResourceGetters<SimpleResourceEnum, Extractors>(
simple_resource_getters_, this);
// Verify that there are getters for each enum value.
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;
}
}
for (int i = *SimpleResourceEnum::kNone;
i < *SimpleResourceEnum::kPastMaxValue; ++i) {
if (simple_resource_getters_.find(i) == simple_resource_getters_.end()) {
LOG(ERROR) << "No getter for simple resource enum value " << i;
}
}
}
RiscV64GZBEncoding::~RiscV64GZBEncoding() { delete resource_pool_; }
void RiscV64GZBEncoding::ParseInstruction(uint32_t inst_word) {
inst_word_ = inst_word;
if ((inst_word_ & 0x3) == 3) {
auto [opcode, format] = DecodeRiscV64GZBInst32WithFormat(inst_word_);
opcode_ = opcode;
format_ = format;
return;
}
auto [opcode, format] = DecodeRiscV64GZBInst16WithFormat(
static_cast<uint16_t>(inst_word & 0xffff));
opcode_ = opcode;
format_ = format;
}
ResourceOperandInterface* RiscV64GZBEncoding::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);
}
ResourceOperandInterface* RiscV64GZBEncoding::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* RiscV64GZBEncoding::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* RiscV64GZBEncoding::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 mpact::sim::riscv::isa64gzb