blob: 7c38d535bdff64cb46e2bd28bc1bc2b1c3af60f0 [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
//
// 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/bundle.h"
#include <memory>
#include <string>
#include <vector>
#include "mpact/sim/decoder/format_name.h"
#include "mpact/sim/decoder/instruction_set.h"
namespace mpact {
namespace sim {
namespace machine_description {
namespace instruction_set {
Bundle::Bundle(absl::string_view name, InstructionSet *instruction_set)
: instruction_set_(instruction_set),
name_(name),
pascal_name_(ToPascalCase(name)) {}
void Bundle::AppendBundleName(absl::string_view name) {
// emplace_back accepts a string_view, push_back does not.
bundle_names_.emplace_back(name);
}
void Bundle::AppendSlot(absl::string_view name,
const std::vector<int> &instance_vec) {
slot_uses_.push_back({std::string(name), instance_vec});
}
// Returns a string containing the bundle class declaration (.h file).
std::string Bundle::GenerateClassDeclaration(
absl::string_view encoding_type) const {
std::string output;
absl::StrAppend(&output, "class ", pascal_name(),
"Decoder {\n"
" public:\n"
" explicit ",
pascal_name(),
"Decoder(ArchState *arch_state);\n"
" virtual ~",
pascal_name(),
"Decoder() = default;\n"
" virtual Instruction *Decode(uint64_t address, ",
encoding_type,
" *encoding);\n"
" virtual SemFunc GetSemanticFunction() = 0;\n"
"\n");
for (const auto &bundle_name : bundle_names()) {
absl::StrAppend(&output, " ", ToPascalCase(bundle_name), "Decoder *",
bundle_name, "_decoder() { return ", bundle_name,
"_decoder_.get(); }\n");
}
for (const auto &[slot_name, unused] : slot_uses()) {
absl::StrAppend(&output, " ", ToPascalCase(slot_name), "Slot *", slot_name,
"_decoder() { return ", slot_name, "_decoder_.get(); }\n");
}
absl::StrAppend(&output, " private:\n");
for (const auto &bundle_name : bundle_names()) {
absl::StrAppend(&output, " std::unique_ptr<", ToPascalCase(bundle_name),
"Decoder> ", bundle_name, "_decoder_;\n");
}
for (const auto &[slot_name, unused] : slot_uses()) {
absl::StrAppend(&output, " std::unique_ptr<", ToPascalCase(slot_name),
"Slot> ", slot_name, "_decoder_;\n");
}
absl::StrAppend(&output,
" ArchState *arch_state_;\n"
"};\n"
"\n");
return output;
}
// Returns a string containing the bundle class definition (.cc file).
std::string Bundle::GenerateClassDefinition(
absl::string_view encoding_type) const {
std::string output;
std::string class_name = pascal_name() + "Bundle";
// Constructor.
absl::StrAppend(&output, class_name, "::", class_name,
"(ArchState *arch_state) :\n"
" arch_state_(arch_state)\n"
"{\n");
for (const auto &bundle_name : bundle_names()) {
absl::StrAppend(&output, " ", bundle_name, "_decoder = std::make_unique<",
ToPascalCase(bundle_name), "Decoder>(arch_state_);\n");
}
for (const auto &[slot_name, unused] : slot_uses()) {
absl::StrAppend(&output, " ", slot_name, "_decoder = std::make_unique<",
ToPascalCase(slot_name), "Slot>(arch_state_);\n");
}
absl::StrAppend(&output, "}\n");
// Decode.
absl::StrAppend(
&output, "Instruction *", class_name, "::Decode(uint64_t address, ",
encoding_type,
" *encoding) {\n"
" Instruction *inst = new Instruction(address, arch_state_);\n"
" Instruction *tmp_inst;\n");
// Decoded bundles are added to the child list.
for (const auto &bundle_name : bundle_names()) {
absl::StrAppend(&output, " tmp_inst = ", bundle_name,
"_decoder_->Decode(address, encoding);\n"
" inst->AppendChild(tmp_inst);\n");
}
// Instructions for decoded slots are added to the "next" list.
for (const auto &[slot_name, instance_vec] : slot_uses()) {
if (instance_vec.empty()) {
absl::StrAppend(&output, " tmp_inst = ", slot_name,
"_decoder_->Decode(address, encoding, 0);\n"
" inst->Append(tmp_inst);\n");
} else {
for (auto index : instance_vec) {
absl::StrAppend(&output, " tmp_inst = ", slot_name,
"_decoder_->Decode(address, encoding, ", index,
");\n"
" inst->Append(tmp_inst);\n");
}
}
}
// Set semantic function for this bundle.
absl::StrAppend(
&output,
" inst->set_semantic_function(this->GetSemanticFunction());\n"
"}\n");
return output;
}
} // namespace instruction_set
} // namespace machine_description
} // namespace sim
} // namespace mpact