| // 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 |