| // 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/bin_encoding_info.h" |
| |
| #include <string> |
| #include <utility> |
| |
| #include "absl/status/status.h" |
| #include "absl/strings/string_view.h" |
| #include "mpact/sim/decoder/bin_decoder.h" |
| #include "mpact/sim/decoder/decoder_error_listener.h" |
| #include "mpact/sim/decoder/format.h" |
| #include "mpact/sim/decoder/instruction_group.h" |
| |
| namespace mpact { |
| namespace sim { |
| namespace decoder { |
| namespace bin_format { |
| |
| BinEncodingInfo::BinEncodingInfo(std::string opcode_enum, |
| DecoderErrorListener *error_listener) |
| : opcode_enum_(opcode_enum), error_listener_(error_listener) {} |
| |
| BinEncodingInfo::~BinEncodingInfo() { delete decoder_; } |
| |
| // Add name of an include file to be included in the generated code. |
| void BinEncodingInfo::AddIncludeFile(std::string include_file) { |
| include_files_.insert(std::move(include_file)); |
| } |
| |
| // Adding a format that does not have a parent (to inherit from ). |
| absl::StatusOr<Format *> BinEncodingInfo::AddFormat(std::string name, |
| int width) { |
| // Verify that the format name hasn't been used. |
| if (format_map_.contains(name)) { |
| return absl::InternalError( |
| absl::StrCat("Error: format '", name, "' already defined")); |
| } |
| auto format = new Format(name, width, this); |
| format_map_.emplace(name, format); |
| return format; |
| } |
| |
| // Adding a format that does have a parent. |
| absl::StatusOr<Format *> BinEncodingInfo::AddFormat(std::string name, int width, |
| std::string parent_name) { |
| // Verify that the format name hasn't been used. |
| if (format_map_.contains(name)) { |
| return absl::InternalError( |
| absl::StrCat("Error: format '", name, "' already defined")); |
| } |
| auto format = new Format(name, width, parent_name, this); |
| format_map_.emplace(name, format); |
| return format; |
| } |
| |
| // Lookup a format by name. Return nullptr if it isn't found. |
| Format *BinEncodingInfo::GetFormat(absl::string_view name) const { |
| auto iter = format_map_.find(name); |
| if (iter == format_map_.end()) return nullptr; |
| return iter->second; |
| } |
| |
| // Add the named instruction group. Instruction encodings are added directly |
| // to the group using the returned pointer. |
| absl::StatusOr<InstructionGroup *> BinEncodingInfo::AddInstructionGroup( |
| std::string name, int width, std::string format_name) { |
| if (instruction_group_map_.contains(name)) { |
| return absl::InternalError( |
| absl::StrCat("Error: instruction group '", name, "' already defined")); |
| } |
| auto group = |
| new InstructionGroup(name, width, format_name, opcode_enum_, this); |
| instruction_group_map_.emplace(name, group); |
| return group; |
| } |
| |
| // Top level method that calls the checking method of each format. This is |
| // called after all the formats have been added. |
| absl::Status BinEncodingInfo::CheckFormats() { |
| for (auto &[unused, format] : format_map_) { |
| // For the base formats (those who do not inherit from another format). |
| if (format->base_format() == nullptr) { |
| format->PropagateExtractorsUp(); |
| } |
| } |
| |
| for (auto &[unused, format] : format_map_) { |
| if (format->base_format() == nullptr) { |
| format->PropagateExtractorsDown(); |
| } |
| } |
| return absl::OkStatus(); |
| } |
| |
| BinDecoder *BinEncodingInfo::AddBinDecoder(std::string name) { |
| if (decoder_ != nullptr) { |
| error_listener_->semanticError(nullptr, "Can only select one decoder"); |
| return nullptr; |
| } |
| auto *bin_decoder = new BinDecoder(name, this, error_listener()); |
| decoder_ = bin_decoder; |
| return bin_decoder; |
| } |
| |
| } // namespace bin_format |
| } // namespace decoder |
| } // namespace sim |
| } // namespace mpact |