blob: eb58b2c510031de39619620cba2fbcf3e64908c9 [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.
#include "mpact/sim/decoder/test/push_pop_encoding.h"
#include <cstdint>
#include <string>
#include <utility>
#include <vector>
#include "mpact/sim/decoder/test/push_pop_inst_bin_decoder.h"
#include "mpact/sim/decoder/test/push_pop_inst_enums.h"
#include "mpact/sim/generic/arch_state.h"
#include "mpact/sim/generic/immediate_operand.h"
#include "mpact/sim/generic/operand_interface.h"
#include "mpact/sim/generic/register.h"
#include "mpact/sim/generic/type_helpers.h"
namespace mpact::sim::decoder::test {
using ::mpact::sim::generic::operator*; // NOLINT
using ::mpact::sim::generic::ArchState;
using ::mpact::sim::generic::ImmediateOperand;
using ::mpact::sim::generic::SourceOperandInterface;
using TestRegister = ::mpact::sim::generic::Register<uint32_t>;
template <typename RegType>
inline RegType* GetRegister(ArchState* state, std::string name) {
auto iter = state->registers()->find(name);
if (iter == state->registers()->end()) {
return nullptr;
}
return static_cast<RegType*>(iter->second);
}
// Generic helper functions to create register operands.
template <typename RegType>
inline DestinationOperandInterface* GetRegisterDestinationOp(ArchState* state,
std::string name,
int latency) {
auto* reg = GetRegister<RegType>(state, name);
return reg->CreateDestinationOperand(latency);
}
template <typename RegType>
inline DestinationOperandInterface* GetRegisterDestinationOp(
ArchState* state, std::string name, int latency, std::string op_name) {
auto* reg = GetRegister<RegType>(state, name);
return reg->CreateDestinationOperand(latency, op_name);
}
template <typename RegType>
inline SourceOperandInterface* GetRegisterSourceOp(ArchState* state,
std::string name) {
auto* reg = GetRegister<RegType>(state, name);
auto* op = reg->CreateSourceOperand();
return op;
}
template <typename RegType>
inline SourceOperandInterface* GetRegisterSourceOp(ArchState* state,
std::string name,
std::string op_name) {
auto* reg = GetRegister<RegType>(state, name);
auto* op = reg->CreateSourceOperand(op_name);
return op;
}
PushPopEncoding::PushPopEncoding(ArchState* state) : state_(state) {
source_op_getters_.insert(std::make_pair(
*SourceOpEnum::kRlist, [this]() -> SourceOperandInterface* {
return new generic::ImmediateOperand<uint32_t>(
p_type::ExtractRlist(inst_word_));
}));
source_op_getters_.insert(std::make_pair(
*SourceOpEnum::kSpimm6, [this]() -> SourceOperandInterface* {
return new generic::ImmediateOperand<uint32_t>(
p_type::ExtractSpimm6(inst_word_));
}));
source_op_getters_.insert(
std::make_pair(*SourceOpEnum::kX2, [this]() -> SourceOperandInterface* {
return GetRegisterSourceOp<TestRegister>(state_, "x2");
}));
list_source_op_getters_.insert(std::make_pair(
*ListSourceOpEnum::kRlist,
[this]() -> std::vector<SourceOperandInterface*> {
std::vector<SourceOperandInterface*> result;
auto rlist = p_type::ExtractRlist(inst_word_);
// Get the value of 'rlist', and add source operands accordingly.
if (rlist < 4) return result;
result.push_back(GetRegisterSourceOp<TestRegister>(state_, "x1"));
if (rlist == 4) return result;
result.push_back(GetRegisterSourceOp<TestRegister>(state_, "x8"));
if (rlist == 5) return result;
result.push_back(GetRegisterSourceOp<TestRegister>(state_, "x9"));
if (rlist == 6) return result;
result.push_back(GetRegisterSourceOp<TestRegister>(state_, "x18"));
if (rlist == 7) return result;
result.push_back(GetRegisterSourceOp<TestRegister>(state_, "x19"));
if (rlist == 8) return result;
result.push_back(GetRegisterSourceOp<TestRegister>(state_, "x20"));
if (rlist == 9) return result;
result.push_back(GetRegisterSourceOp<TestRegister>(state_, "x21"));
if (rlist == 10) return result;
result.push_back(GetRegisterSourceOp<TestRegister>(state_, "x22"));
if (rlist == 11) return result;
result.push_back(GetRegisterSourceOp<TestRegister>(state_, "x23"));
if (rlist == 12) return result;
result.push_back(GetRegisterSourceOp<TestRegister>(state_, "x24"));
if (rlist == 13) return result;
result.push_back(GetRegisterSourceOp<TestRegister>(state_, "x25"));
if (rlist == 14) return result;
result.push_back(GetRegisterSourceOp<TestRegister>(state_, "x26"));
result.push_back(GetRegisterSourceOp<TestRegister>(state_, "x27"));
return result;
}));
dest_op_getters_.insert(std::make_pair(
*DestOpEnum::kX2, [this](int latency) -> DestinationOperandInterface* {
return GetRegisterDestinationOp<TestRegister>(state_, "x2", latency);
}));
list_dest_op_getters_.insert(
std::make_pair(*ListDestOpEnum::kRlist,
[this](const std::vector<int>& latency)
-> std::vector<DestinationOperandInterface*> {
std::vector<DestinationOperandInterface*> result;
// Get the value of 'rlist', and add destination operands
// accordingly.
auto rlist = p_type::ExtractRlist(inst_word_);
int size = latency.size();
if (rlist < 4) return result;
result.push_back(GetRegisterDestinationOp<TestRegister>(
state_, "x1", latency[result.size() % size]));
if (rlist == 4) return result;
result.push_back(GetRegisterDestinationOp<TestRegister>(
state_, "x8", latency[result.size() % size]));
if (rlist == 5) return result;
result.push_back(GetRegisterDestinationOp<TestRegister>(
state_, "x9", latency[result.size() % size]));
if (rlist == 6) return result;
result.push_back(GetRegisterDestinationOp<TestRegister>(
state_, "x18", latency[result.size() % size]));
if (rlist == 7) return result;
result.push_back(GetRegisterDestinationOp<TestRegister>(
state_, "x19", latency[result.size() % size]));
if (rlist == 8) return result;
result.push_back(GetRegisterDestinationOp<TestRegister>(
state_, "x20", latency[result.size() % size]));
if (rlist == 9) return result;
result.push_back(GetRegisterDestinationOp<TestRegister>(
state_, "x21", latency[result.size() % size]));
if (rlist == 10) return result;
result.push_back(GetRegisterDestinationOp<TestRegister>(
state_, "x22", latency[result.size() % size]));
if (rlist == 11) return result;
result.push_back(GetRegisterDestinationOp<TestRegister>(
state_, "x23", latency[result.size() % size]));
if (rlist == 12) return result;
result.push_back(GetRegisterDestinationOp<TestRegister>(
state_, "x24", latency[result.size() % size]));
if (rlist == 13) return result;
result.push_back(GetRegisterDestinationOp<TestRegister>(
state_, "x25", latency[result.size() % size]));
if (rlist == 14) return result;
result.push_back(GetRegisterDestinationOp<TestRegister>(
state_, "x26", latency[result.size() % size]));
result.push_back(GetRegisterDestinationOp<TestRegister>(
state_, "x27", latency[result.size() % size]));
return result;
}));
}
void PushPopEncoding::ParseInstruction(uint16_t inst_word) {
inst_word_ = inst_word;
opcode_ = DecodePushPop(inst_word_);
}
SourceOperandInterface* PushPopEncoding::GetSource(SlotEnum, int, OpcodeEnum,
SourceOpEnum op,
int source_no) {
auto iter = source_op_getters_.find(*op);
if (iter == source_op_getters_.end()) {
return nullptr;
}
return iter->second();
}
std::vector<SourceOperandInterface*> PushPopEncoding::GetSources(
SlotEnum, int, OpcodeEnum, ListSourceOpEnum op, int source_no) {
auto iter = list_source_op_getters_.find(*op);
if (iter == list_source_op_getters_.end()) {
return {};
}
return iter->second();
}
DestinationOperandInterface* PushPopEncoding::GetDestination(
SlotEnum, int, OpcodeEnum, DestOpEnum op, int dest_no, int latency) {
auto iter = dest_op_getters_.find(*op);
if (iter == dest_op_getters_.end()) {
return nullptr;
}
return iter->second(latency);
}
std::vector<DestinationOperandInterface*> PushPopEncoding::GetDestinations(
SlotEnum, int, OpcodeEnum, ListDestOpEnum op, int dest_no,
const std::vector<int>& latency) {
auto iter = list_dest_op_getters_.find(*op);
if (iter == list_dest_op_getters_.end()) {
return {};
}
return iter->second(latency);
}
} // namespace mpact::sim::decoder::test