blob: f264b79de042425273af3e6ed98e275943070b0f [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
//
// 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_full_decoder/solution/riscv32i_encoding.h"
#include <string>
#include "mpact/sim/generic/devnull_operand.h"
#include "mpact/sim/generic/immediate_operand.h"
#include "mpact/sim/generic/literal_operand.h"
#include "mpact/sim/generic/operand_interface.h"
#include "other/riscv_register.h"
#include "other/riscv_simple_state.h"
#include "riscv_bin_decoder/solution/riscv32i_bin_decoder.h"
namespace mpact {
namespace sim {
namespace codelab {
using riscv::RiscVState;
using riscv::RV32Register;
using generic::DevNullOperand;
using generic::ImmediateOperand;
using generic::IntLiteralOperand;
// Generic helper functions to create register operands.
template <typename RegType>
inline DestinationOperandInterface *GetRegisterDestinationOp(
RiscVState *state, const std::string &name, int latency) {
auto *reg = state->GetRegister<RegType>(name).first;
return reg->CreateDestinationOperand(latency);
}
template <typename RegType>
inline DestinationOperandInterface *GetRegisterDestinationOp(
RiscVState *state, const std::string &name, int latency,
const std::string &op_name) {
auto *reg = state->GetRegister<RegType>(name).first;
return reg->CreateDestinationOperand(latency, op_name);
}
template <typename RegType>
inline SourceOperandInterface *GetRegisterSourceOp(RiscVState *state,
const std::string &name) {
auto [reg_ptr, unused] = state->GetRegister<RegType>(name);
auto *op = reg_ptr->CreateSourceOperand();
return op;
}
template <typename RegType>
inline SourceOperandInterface *GetRegisterSourceOp(RiscVState *state,
const std::string &name,
const std::string &op_name) {
auto [reg_ptr, unused] = state->GetRegister<RegType>(name);
auto *op = reg_ptr->CreateSourceOperand(op_name);
return op;
}
RiscV32IEncoding::RiscV32IEncoding(RiscVState *state) : state_(state) {
InitializeSourceOperandGetters();
InitializeDestinationOperandGetters();
}
// Parse the instruction word to determine the opcode.
void RiscV32IEncoding::ParseInstruction(uint32_t inst_word) {
inst_word_ = inst_word;
opcode_ = mpact::sim::codelab::DecodeRiscVInst32(inst_word_);
}
DestinationOperandInterface *RiscV32IEncoding::GetDestination(
SlotEnum, int, OpcodeEnum, DestOpEnum dest_op, int, int latency) {
return dest_op_getters_[static_cast<int>(dest_op)](latency);
}
SourceOperandInterface *RiscV32IEncoding::GetSource(SlotEnum, int, OpcodeEnum,
SourceOpEnum source_op,
int) {
return source_op_getters_[static_cast<int>(source_op)]();
}
void RiscV32IEncoding::InitializeDestinationOperandGetters() {
// Destination operand getters.
dest_op_getters_[static_cast<int>(DestOpEnum::kNone)] = [](int latency) {
return nullptr;
};
dest_op_getters_[static_cast<int>(DestOpEnum::kCsr)] = [this](int latency) {
return GetRegisterDestinationOp<RV32Register>(state_, "CSR", latency);
};
dest_op_getters_[static_cast<int>(DestOpEnum::kNextPc)] =
[this](int latency) {
return GetRegisterDestinationOp<RV32Register>(
state_, RiscVState::kPcName, latency);
};
dest_op_getters_[static_cast<int>(DestOpEnum::kRd)] =
[this](int latency) -> DestinationOperandInterface * {
int num = inst32_format::ExtractRd(inst_word_);
if (num == 0) return new DevNullOperand<uint32_t>(state_, {1});
return GetRegisterDestinationOp<RV32Register>(
state_, absl::StrCat(RiscVState::kXregPrefix, num), latency,
xreg_alias_[num]);
};
}
void RiscV32IEncoding::InitializeSourceOperandGetters() {
// Source operand getters.
source_op_getters_[static_cast<int>(SourceOpEnum::kNone)] = []() {
return nullptr;
};
// Register operands.
source_op_getters_[static_cast<int>(SourceOpEnum::kCsr)] = [this]() {
return GetRegisterSourceOp<RV32Register>(state_, "CSR");
};
source_op_getters_[static_cast<int>(SourceOpEnum::kRs1)] =
[this]() -> SourceOperandInterface * {
int num = inst32_format::ExtractRs1(inst_word_);
if (num == 0) return new IntLiteralOperand<0>({1}, xreg_alias_[0]);
return GetRegisterSourceOp<RV32Register>(
state_, absl::StrCat(RiscVState::kXregPrefix, num), xreg_alias_[num]);
};
source_op_getters_[static_cast<int>(SourceOpEnum::kRs2)] =
[this]() -> SourceOperandInterface * {
int num = inst32_format::ExtractRs2(inst_word_);
if (num == 0) return new IntLiteralOperand<0>({1}, xreg_alias_[0]);
return GetRegisterSourceOp<RV32Register>(
state_, absl::StrCat(RiscVState::kXregPrefix, num), xreg_alias_[num]);
};
// Immediates.
source_op_getters_[static_cast<int>(SourceOpEnum::kBimm12)] = [this]() {
return new ImmediateOperand<int32_t>(
inst32_format::ExtractBImm(inst_word_));
};
source_op_getters_[static_cast<int>(SourceOpEnum::kImm12)] = [this]() {
return new ImmediateOperand<int32_t>(
inst32_format::ExtractImm12(inst_word_));
};
source_op_getters_[static_cast<int>(SourceOpEnum::kUimm5)] = [this]() {
return new ImmediateOperand<uint32_t>(
inst32_format::ExtractUimm5(inst_word_));
};
source_op_getters_[static_cast<int>(SourceOpEnum::kJimm20)] = [this]() {
return new ImmediateOperand<int32_t>(
inst32_format::ExtractJImm(inst_word_));
};
source_op_getters_[static_cast<int>(SourceOpEnum::kSimm12)] = [this]() {
return new ImmediateOperand<int32_t>(
inst32_format::ExtractSImm(inst_word_));
};
source_op_getters_[static_cast<int>(SourceOpEnum::kUimm20)] = [this]() {
return new ImmediateOperand<int32_t>(
inst32_format::ExtractUimm32(inst_word_));
};
}
} // namespace codelab
} // namespace sim
} // namespace mpact