No public description PiperOrigin-RevId: 748351895 Change-Id: I13e5aad8d4a7dd5e40716e99d75cc785f13546a5
diff --git a/mpact/sim/decoder/BinFormat.g4 b/mpact/sim/decoder/BinFormat.g4 index c09440f..890ebc8 100644 --- a/mpact/sim/decoder/BinFormat.g4 +++ b/mpact/sim/decoder/BinFormat.g4
@@ -37,13 +37,23 @@ // "inheritance" in this context only refers to the width, and helps group // formats in a hierarchy. format_def - : FORMAT name=IDENT width=index? inherits_from? '{' format_field_defs'}' ';'? + : FORMAT name=IDENT width=index? inherits_from? + '{' layout_spec? format_field_defs'}' ';'? ; inherits_from : ':' IDENT ; +layout_spec + : LAYOUT ':' layout_type ';' + ; + +layout_type + : DEFAULT + | PACKED_STRUCT + ; + // Each format consists of a number of entries whose widths sum up to the // format widths. Each entry is either a field, or a sub-format (creating // a hierarchy), with the width specified with array notation. Fields and/or @@ -259,6 +269,9 @@ GROUP : 'group'; DECODER : 'decoder'; SPECIALIZES : 'specializes'; +LAYOUT : 'layout'; +DEFAULT : 'default'; +PACKED_STRUCT : 'packed_struct'; // Other tokens. STRING_LITERAL : UNTERMINATED_STRING_LITERAL '"';
diff --git a/mpact/sim/decoder/bin_format_visitor.cc b/mpact/sim/decoder/bin_format_visitor.cc index 97351f3..702e004 100644 --- a/mpact/sim/decoder/bin_format_visitor.cc +++ b/mpact/sim/decoder/bin_format_visitor.cc
@@ -203,32 +203,40 @@ std::string enc_dot_h_name = absl::StrCat(prefix, "_bin_encoder.h"); std::string enc_dot_cc_name = absl::StrCat(prefix, "_bin_encoder.cc"); std::string enum_dot_h_name = absl::StrCat(prefix, "_enums.h"); + std::string types_dot_h_name = absl::StrCat(prefix, "_bin_types.h"); std::ofstream dec_dot_h_file(absl::StrCat(directory, "/", dec_dot_h_name)); std::ofstream dec_dot_cc_file(absl::StrCat(directory, "/", dec_dot_cc_name)); std::ofstream enc_dot_h_file(absl::StrCat(directory, "/", enc_dot_h_name)); std::ofstream enc_dot_cc_file(absl::StrCat(directory, "/", enc_dot_cc_name)); + std::ofstream types_dot_h_file( + absl::StrCat(directory, "/", types_dot_h_name)); - auto [dec_h_output, dec_cc_output] = - EmitDecoderFilePrefix(dec_dot_h_name, encoding_info.get()); + auto [dec_h_output, dec_cc_output, types_h_output] = EmitDecoderFilePrefix( + dec_dot_h_name, types_dot_h_name, encoding_info.get()); dec_dot_h_file << dec_h_output; dec_dot_cc_file << dec_cc_output; + types_dot_h_file << types_h_output; auto [enc_h_output, enc_cc_output] = EmitEncoderFilePrefix( - enc_dot_h_name, enum_dot_h_name, encoding_info.get()); + enc_dot_h_name, enum_dot_h_name, types_dot_h_name, encoding_info.get()); enc_dot_h_file << enc_h_output; enc_dot_cc_file << enc_cc_output; // Output file prefix is the input file name. - auto [dec_h_output2, dec_cc_output2] = EmitDecoderCode(encoding_info.get()); + auto [dec_h_output2, dec_cc_output2, types_h_output2] = + EmitDecoderCode(encoding_info.get()); dec_dot_h_file << dec_h_output2; dec_dot_cc_file << dec_cc_output2; - auto [dec_h_output3, dec_cc_output3] = - EmitFileSuffix(dec_dot_h_name, encoding_info.get()); + types_dot_h_file << types_h_output2; + auto [dec_h_output3, dec_cc_output3, types_h_output3] = + EmitFileSuffix(dec_dot_h_name, types_dot_h_name, encoding_info.get()); dec_dot_h_file << dec_h_output3; dec_dot_cc_file << dec_cc_output3; + types_dot_h_file << types_h_output3; auto [enc_h_output2, enc_cc_output2] = EmitEncoderCode(encoding_info.get()); enc_dot_h_file << enc_h_output2; enc_dot_cc_file << enc_cc_output2; - auto [enc_h_output3, enc_cc_output3] = - EmitFileSuffix(enc_dot_h_name, encoding_info.get()); + std::string empty; + auto [enc_h_output3, enc_cc_output3, not_used] = + EmitFileSuffix(enc_dot_h_name, empty, encoding_info.get()); enc_dot_h_file << enc_h_output3; enc_dot_cc_file << enc_cc_output3; @@ -243,10 +251,12 @@ encoding->decoder()->CheckEncodings(); } -BinFormatVisitor::StringPair BinFormatVisitor::EmitDecoderFilePrefix( - const std::string &dot_h_name, BinEncodingInfo *encoding_info) const { +BinFormatVisitor::StringTriple BinFormatVisitor::EmitDecoderFilePrefix( + const std::string &dot_h_name, const std::string &types_dot_h_name, + BinEncodingInfo *encoding_info) const { std::string h_string; std::string cc_string; + std::string types_string; std::string guard_name = ToHeaderGuard(dot_h_name); absl::StrAppend(&h_string, "#ifndef ", guard_name, @@ -260,16 +270,33 @@ "\n" "#include \"absl/functional/any_invocable.h\"\n" "#include \"absl/log/log.h\"\n" + "#include \"", + types_dot_h_name, + "\"\n" "\n\n"); + std::string types_guard_name = ToHeaderGuard(types_dot_h_name); + absl::StrAppend(&types_string, "#ifndef ", types_guard_name, + "\n" + "#define ", + types_guard_name, + "\n" + "\n" + "#include <iostream>\n" + "#include <cstdint>\n" + "\n"); for (auto const &include_file : encoding_info->include_files()) { absl::StrAppend(&h_string, "#include ", include_file, "\n"); } absl::StrAppend(&h_string, "\n"); - absl::StrAppend(&cc_string, "#include \"", dot_h_name, "\"\n\n"); + absl::StrAppend(&cc_string, "#include \"", dot_h_name, + "\"\n" + "#include \"", + types_dot_h_name, "\"\n\n"); for (auto &name_space : encoding_info->decoder()->namespaces()) { auto name_space_str = absl::StrCat("namespace ", name_space, " {\n"); absl::StrAppend(&h_string, name_space_str); absl::StrAppend(&cc_string, name_space_str); + absl::StrAppend(&types_string, name_space_str); } absl::StrAppend(&h_string, "\n"); absl::StrAppend(&cc_string, "\n"); @@ -285,39 +312,49 @@ absl::StrAppend(&h_string, " k", ToPascalCase(name), " = ", i++, ",\n"); } absl::StrAppend(&h_string, "};\n\n"); - return {h_string, cc_string}; + return {h_string, cc_string, types_string}; } -BinFormatVisitor::StringPair BinFormatVisitor::EmitFileSuffix( - const std::string &dot_h_name, BinEncodingInfo *encoding_info) { +BinFormatVisitor::StringTriple BinFormatVisitor::EmitFileSuffix( + const std::string &dot_h_name, const std::string &types_dot_h_name, + BinEncodingInfo *encoding_info) { std::string h_string; std::string cc_string; + std::string types_string; absl::StrAppend(&h_string, "\n"); absl::StrAppend(&cc_string, "\n"); + if (!types_dot_h_name.empty()) absl::StrAppend(&types_string, "\n"); auto &namespaces = encoding_info->decoder()->namespaces(); for (auto rptr = namespaces.rbegin(); rptr != namespaces.rend(); rptr++) { std::string name_space = absl::StrCat("} // namespace ", *rptr, "\n"); absl::StrAppend(&h_string, name_space); absl::StrAppend(&cc_string, name_space); + if (!types_dot_h_name.empty()) absl::StrAppend(&types_string, name_space); } std::string guard_name = ToHeaderGuard(dot_h_name); absl::StrAppend(&h_string, "\n#endif // ", guard_name); - return {h_string, cc_string}; + if (!types_dot_h_name.empty()) { + std::string types_guard_name = ToHeaderGuard(types_dot_h_name); + absl::StrAppend(&types_string, "\n#endif // ", types_guard_name); + } + return {h_string, cc_string, types_string}; } -BinFormatVisitor::StringPair BinFormatVisitor::EmitDecoderCode( +BinFormatVisitor::StringTriple BinFormatVisitor::EmitDecoderCode( BinEncodingInfo *encoding) { std::string h_string; std::string cc_string; std::string group_string; + std::string extractor_types; std::string extractor_class = absl::StrCat("class Extractors {\n", "public: \n"); // Write out the inline functions for bitfield and overlay extractions. for (auto &[unused, format_ptr] : encoding->format_map()) { - auto [functions, classes] = format_ptr->GenerateExtractors(); - absl::StrAppend(&h_string, functions); - absl::StrAppend(&extractor_class, classes); + auto extractors = format_ptr->GenerateExtractors(); + absl::StrAppend(&h_string, extractors.h_output); + absl::StrAppend(&extractor_class, extractors.class_output); + absl::StrAppend(&extractor_types, extractors.types_output); } absl::StrAppend(&h_string, extractor_class, "};\n\n"); auto *decoder = encoding->decoder(); @@ -331,12 +368,12 @@ absl::StrAppend(&group_string, group->WriteGroup()); } absl::StrAppend(&h_string, group_string); - return {h_string, cc_string}; + return {h_string, cc_string, extractor_types}; } std::tuple<std::string, std::string> BinFormatVisitor::EmitEncoderFilePrefix( const std::string &dot_h_name, const std::string &enum_h_name, - BinEncodingInfo *encoding_info) const { + const std::string &types_dot_h_name, BinEncodingInfo *encoding_info) const { std::string h_string; std::string cc_string; @@ -351,16 +388,22 @@ "#include <cstdint>\n\n" "#include \"absl/base/no_destructor.h\"\n" "#include \"absl/container/flat_hash_map.h\"\n" - "#include \"absl/log/log.h\"\n\n" + "#include \"absl/log/log.h\"\n" "#include \"", - enum_h_name, "\"\n"); + enum_h_name, + "\"\n" + "#include \"", + types_dot_h_name, "\"\n\n"); absl::StrAppend(&cc_string, "#include \"", dot_h_name, "\"\n\n" "#include <cstdint>\n\n" "#include \"absl/base/no_destructor.h\"\n" "#include \"absl/container/flat_hash_map.h\"\n" "#include \"", - enum_h_name, "\"\n"); + enum_h_name, + "\"\n" + "#include \"", + types_dot_h_name, "\"\n\n"); for (auto &name_space : encoding_info->decoder()->namespaces()) { auto name_space_str = absl::StrCat("namespace ", name_space, " {\n"); absl::StrAppend(&cc_string, name_space_str); @@ -689,8 +732,14 @@ ctx->start, format_res.status().message()); return; } - // Parse the fields in the format. + // Parse the layout. auto format = format_res.value(); + if (ctx->layout_spec() != nullptr) { + if (ctx->layout_spec()->layout_type()->getText() == "packed_struct") { + format->set_layout(Format::Layout::kPackedStruct); + } + } + // Parse the fields in the format. auto file_index = context_file_map_.at(ctx); for (auto field : ctx->format_field_defs()->field_def()) { context_file_map_.insert({field, file_index}); @@ -717,6 +766,12 @@ // If it's a field definition, add the field. bool is_signed = ctx->sign_spec()->SIGNED() != nullptr; int width = ConvertToInt(ctx->index()->number()); + if ((format->layout() == Format::Layout::kPackedStruct) && (width > 64)) { + error_listener_->semanticError( + file_names_[context_file_map_.at(ctx)], ctx->index()->number()->start, + "Fields in packed struct layouts can not be > 64 bits"); + return; + } auto status = format->AddField(field_name, is_signed, width); if (!status.ok()) { error_listener_->semanticError(file_names_[context_file_map_.at(ctx)], @@ -730,6 +785,12 @@ int size = 1; if (ctx->index() != nullptr) { size = ConvertToInt(ctx->index()->number()); + if ((format->layout() == Format::Layout::kPackedStruct) && (size > 1)) { + error_listener_->semanticError( + file_names_[context_file_map_.at(ctx)], ctx->index()->number()->start, + "Formats in packed struct layouts can not be replicated"); + return; + } } std::string format_ref_name = ctx->format_name->getText(); // Make sure that the referred to format is fully parsed. @@ -741,6 +802,13 @@ } format_ref = encoding_info->GetFormat(format_ref_name); } + int width = format_ref->declared_width(); + if ((format->layout() == Format::Layout::kPackedStruct) && (width > 64)) { + error_listener_->semanticError( + file_names_[context_file_map_.at(ctx)], ctx->index()->number()->start, + "Formats used in packed struct layouts can not be > 64 bits"); + return; + } format->AddFormatReferenceField(field_name, format_ref_name, size, ctx->start); }
diff --git a/mpact/sim/decoder/bin_format_visitor.h b/mpact/sim/decoder/bin_format_visitor.h index a5f15fc..82b49ab 100644 --- a/mpact/sim/decoder/bin_format_visitor.h +++ b/mpact/sim/decoder/bin_format_visitor.h
@@ -77,6 +77,11 @@ std::string h_output; std::string cc_output; }; + struct StringTriple { + std::string h_output; + std::string cc_output; + std::string types_output; + }; BinFormatVisitor(); ~BinFormatVisitor(); @@ -94,19 +99,22 @@ void PerformEncodingChecks(BinEncodingInfo *encoding); // Called to generate and emit code for the decoder according to the parsed // input file. - StringPair EmitDecoderCode(BinEncodingInfo *encoding); - StringPair EmitDecoderFilePrefix(const std::string &dot_h_name, - BinEncodingInfo *encoding_info) const; + StringTriple EmitDecoderCode(BinEncodingInfo *encoding); + StringTriple EmitDecoderFilePrefix(const std::string &dot_h_name, + const std::string &types_dot_h_name, + BinEncodingInfo *encoding_info) const; // Called to generate and emit code for the decoder according to the parsed // input file. std::tuple<std::string, std::string> EmitEncoderCode( BinEncodingInfo *encoding); std::tuple<std::string, std::string> EmitEncoderFilePrefix( const std::string &dot_h_name, const std::string &enum_h_name, + const std::string &types_dot_h_name, BinEncodingInfo *encoding_info) const; // Generate the file suffixes (namespace closing etc.) - StringPair EmitFileSuffix(const std::string &dot_h_name, - BinEncodingInfo *encoding_info); + StringTriple EmitFileSuffix(const std::string &dot_h_name, + const std::string &types_dot_h_name, + BinEncodingInfo *encoding_info); // Utility methods to parse certain nodes. BinaryNum ParseBinaryNum(TerminalNode *node); BitRange GetBitIndexRange(BitIndexRangeCtx *ctx);
diff --git a/mpact/sim/decoder/format.cc b/mpact/sim/decoder/format.cc index 0ea3491..59f2164 100644 --- a/mpact/sim/decoder/format.cc +++ b/mpact/sim/decoder/format.cc
@@ -17,7 +17,6 @@ #include <algorithm> #include <cstdint> #include <string> -#include <tuple> #include <utility> #include "absl/numeric/bits.h" @@ -353,6 +352,32 @@ return false; } +std::string Format::GeneratePackedStructFieldExtractor( + const Field *field) const { + std::string h_output; + int width = field->width; + std::string return_type = GetUIntType(width); + std::string signature = absl::StrCat("inline ", return_type, " Extract", + ToPascalCase(field->name), "("); + if (declared_width_ < 64) { + absl::StrAppend(&signature, GetUIntType(declared_width_), " value) {\n"); + } else { + absl::StrAppend(&signature, "const uint8_t *value) {\n"); + } + absl::StrAppend(&h_output, signature); + // Now start the body. + std::string union_type = absl::StrCat("const ", ToSnakeCase(name()), + "::Union", ToPascalCase(name())); + absl::StrAppend(&h_output, " ", union_type, + " *packed_union;\n" + " packed_union = reinterpret_cast<", + union_type, "*>(", + declared_width_ > 64 ? "value);\n" : "&value);\n", + " return packed_union->", ToSnakeCase(name()), ".", + field->name, ";\n}\n\n"); + return h_output; +} + // This method generates the C++ code for the field extractors for the current // format. std::string Format::GenerateFieldExtractor(const Field *field) const { @@ -426,9 +451,41 @@ return h_output; } +std::string Format::GeneratePackedStructFieldInserter( + const Field *field) const { + std::string h_output; + std::string field_type_name; + std::string inst_word_type_name; + if (computed_width_ <= 64) { + inst_word_type_name = GetUIntType(computed_width_); + } else { + inst_word_type_name = "uint8_t *"; + } + field_type_name = GetUIntType(field->width); + std::string union_type = + absl::StrCat(ToSnakeCase(name()), "::Union", ToPascalCase(name())); + absl::StrAppend(&h_output, "static inline ", inst_word_type_name, " Insert", + ToPascalCase(field->name), "(", field_type_name, " value, ", + inst_word_type_name, + " inst_word) {\n" + " ", + union_type, + " *packed_union;\n" + " packed_union = reinterpret_cast<", + union_type, "*>(", + (computed_width_ <= 64 ? "&inst_word" : "inst_word"), + ");\n" + " packed_union->", + ToSnakeCase(name()), ".", field->name, + " = value;\n" + " return inst_word;\n" + "}\n\n"); + return h_output; +} + // This method generates the C++ code for field inserters for the current -// format. That is, the generated code will take the value of a field and insert -// it into the right place in the instruction word. +// format. That is, the generated code will take the value of a field and +// insert it into the right place in the instruction word. std::string Format::GenerateFieldInserter(const Field *field) const { std::string h_output; std::string field_type_name; @@ -473,11 +530,11 @@ " return inst_word;\n" "}\n"); } else { - absl::StrAppend( - &h_output, - " LOG(FATAL) << \" Support for fields > 128 bits not implemented - " - "yet.\";\n" - " return 0;\n}\n"); + absl::StrAppend(&h_output, + " LOG(FATAL) << \" Support for fields > 128 bits not " + "implemented - " + "yet.\";\n" + " return 0;\n}\n"); } return h_output; } @@ -499,11 +556,11 @@ " value, ", result_type_name, " inst_word) {\n"); // Mark error if either the overlay or the format is > 64 bits. if (overlay->declared_width() > 128) { - absl::StrAppend( - &h_output, - " LOG(FATAL) << \" Support for overlays > 128 bits not implemented - " - "yet.\";\n" - " return 0;\n}\n"); + absl::StrAppend(&h_output, + " LOG(FATAL) << \" Support for overlays > 128 bits " + "not implemented - " + "yet.\";\n" + " return 0;\n}\n"); return h_output; } bool use_mask_variable = false; @@ -564,6 +621,38 @@ return h_output; } +std::string Format::GeneratePackedStructFormatInserter( + std::string_view format_alias, const Format *format, int high, + int size) const { + std::string h_output; + std::string inst_word_type_name; + if (computed_width_ <= 64) { + inst_word_type_name = GetUIntType(computed_width_); + } else { + inst_word_type_name = "uint8_t *"; + } + std::string format_type_name = GetUIntType(format->declared_width()); + std::string union_type = + absl::StrCat(ToSnakeCase(name()), "::Union", ToPascalCase(name())); + absl::StrAppend(&h_output, "static inline ", inst_word_type_name, "Insert", + ToPascalCase(format_alias), "(", format_type_name, " value, ", + inst_word_type_name, + " inst_word) {\n" + " ", + union_type, + " *packed_union;\n" + " packed_union = reinterpret_cast<", + union_type, "*>(", + (computed_width_ <= 64 ? "&inst_word" : "inst_word"), + ");\n" + " packed_union->", + ToSnakeCase(name()), ".", format_alias, + " = value;\n" + " return inst_word;\n" + "}\n\n"); + return h_output; +} + // This method generates the C++ code for format inserters for the current // format. That is, the generated code will take the value of a format and // insert it into the right place in the instruction word. @@ -593,11 +682,11 @@ format_type_name, " value, ", target_type_name, " inst_word) {\n"); if (format->declared_width() > 128) { - absl::StrAppend( - &h_output, - " LOG(FATAL) << \" Support for formats > 128 bits not implemented - " - "yet.\";\n" - " return 0;\n}\n"); + absl::StrAppend(&h_output, + " LOG(FATAL) << \" Support for formats > 128 bits not " + "implemented - " + "yet.\";\n" + " return 0;\n}\n"); return h_output; } int width = format->declared_width(); @@ -645,11 +734,11 @@ ToPascalCase(format_alias), "(", format_type_name, " value, ", target_type_name, " inst_word) {\n"); if (format->declared_width() > 128) { - absl::StrAppend( - &h_output, - " LOG(FATAL) << \" Support for formats > 128 bits not implemented - " - "yet.\";\n" - " return 0;\n}\n"); + absl::StrAppend(&h_output, + " LOG(FATAL) << \" Support for formats > 128 bits not " + "implemented - " + "yet.\";\n" + " return 0;\n}\n"); return h_output; } int width = format->declared_width(); @@ -683,14 +772,41 @@ return h_output; } -// This method generates the format extractors for the current format (for when -// a format contains other formats). +std::string Format::GeneratePackedStructFormatExtractor( + absl::string_view format_alias, const Format *format, int high, + int size) const { + std::string h_output; + int width = format->declared_width(); + std::string return_type = GetUIntType(width); + std::string signature = absl::StrCat("inline ", return_type, " Extract", + ToPascalCase(format_alias), "("); + if (declared_width_ < 64) { + absl::StrAppend(&signature, GetUIntType(declared_width_), " value) {\n"); + } else { + absl::StrAppend(&signature, "const uint8_t *value) {\n"); + } + absl::StrAppend(&h_output, signature); + // Now start the body. + std::string union_type = absl::StrCat("const ", ToSnakeCase(name()), + "::Union", ToPascalCase(name())); + absl::StrAppend(&h_output, " ", union_type, + " *packed_union;\n" + " packed_union = reinterpret_cast<", + union_type, " *>(", + declared_width_ > 64 ? "value);\n" : "&value);\n", + " return packed_union->", ToSnakeCase(name()), ".", + format_alias, ";\n}\n\n"); + return h_output; +} + +// This method generates the format extractors for the current format (for +// when a format contains other formats). std::string Format::GenerateFormatExtractor(absl::string_view format_alias, const Format *format, int high, int size) const { - std::string h_output; // For each format generate am extractor. + std::string h_output; // For each format generate an extractor. int width = format->declared_width(); - // An extraction can only be for 64 bits or less. + // An extraction can only be for 128 bits or less. if (width > 128) { encoding_info_->error_listener()->semanticError( nullptr, @@ -755,8 +871,8 @@ absl::StrAppend(&expr, ", ", width, ")"); absl::StrAppend(&h_output, " return ", expr, ";\n}\n\n"); } - // If the parent format size is not a power of two, also create an extractor - // that takes a uint8_t * parameter. + // If the parent format size is not a power of two, also create an + // extractor that takes a uint8_t * parameter. if ((declared_width_ <= 128) && (absl::popcount(static_cast<unsigned>(declared_width_)) > 1)) { absl::StrAppend(&h_output, "inline ", return_type, " Extract", @@ -773,6 +889,37 @@ return h_output; } +std::string Format::GeneratePackedStructOverlayExtractor( + Overlay *overlay) const { + std::string h_output; + std::string arg_type; + if (declared_width_ > 128) { + arg_type = "const uint8_t *"; + } else { + std::string arg_type = GetUIntType(declared_width_); + } + std::string return_type = overlay->is_signed() + ? GetIntType(overlay->declared_width()) + : GetUIntType(overlay->declared_width()); + std::string signature = + absl::StrCat("inline ", return_type, " Extract", + ToPascalCase(overlay->name()), "(", arg_type, " value)"); + absl::StrAppend(&h_output, signature, " {\n ", return_type, " result;\n", + overlay->WritePackedStructValueExtractor("value", "result")); + if (overlay->is_signed()) { + int shift = GetIntTypeBitWidth(overlay->declared_width()) - + overlay->declared_width(); + absl::StrAppend(&h_output, " result = result << ", shift, + ";\n" + " result = result >> ", + shift, ";\n"); + } + absl::StrAppend(&h_output, + " return result;\n" + "}\n\n"); + return h_output; +} + // Generates the C++ code for the overlay extractors in the current format. std::string Format::GenerateOverlayExtractor(Overlay *overlay) const { std::string h_output; @@ -827,14 +974,26 @@ } absl::StrAppend(&h_output, "struct ", ToPascalCase(name()), " {\n\n"); // First fields and formats. + std::string inserter; for (auto &[unused, field_or_format_ptr] : extractors_) { if (field_or_format_ptr->is_field()) { - auto inserter = GenerateFieldInserter(field_or_format_ptr->field()); + if (layout() == Layout::kPackedStruct) { + inserter = + GeneratePackedStructFieldInserter(field_or_format_ptr->field()); + } else { + inserter = GenerateFieldInserter(field_or_format_ptr->field()); + } absl::StrAppend(&h_output, inserter); } else { - auto inserter = GenerateFormatInserter( - field_or_format_ptr->format_alias(), field_or_format_ptr->format(), - field_or_format_ptr->high(), field_or_format_ptr->size()); + if (layout() == Layout::kPackedStruct) { + inserter = GeneratePackedStructFormatInserter( + field_or_format_ptr->format_alias(), field_or_format_ptr->format(), + field_or_format_ptr->high(), field_or_format_ptr->size()); + } else { + inserter = GenerateFormatInserter( + field_or_format_ptr->format_alias(), field_or_format_ptr->format(), + field_or_format_ptr->high(), field_or_format_ptr->size()); + } absl::StrAppend(&h_output, inserter); } } @@ -847,50 +1006,118 @@ return h_output; } -// Top level function called to generate all the extractors for this format. -std::tuple<std::string, std::string> Format::GenerateExtractors() const { - std::string class_output; +std::string Format::GeneratePackedStructTypes() const { std::string h_output; + // First the struct. + absl::StrAppend(&h_output, "struct Packed", ToPascalCase(name()), " {\n"); + for (auto it = field_vec_.rbegin(); it != field_vec_.rend(); ++it) { + auto *component = *it; + if (component->is_field()) { + int width = component->field()->width; + std::string field_type = component->field()->is_signed + ? GetIntType(width) + : GetUIntType(width); + absl::StrAppend(&h_output, " ", field_type, " ", + component->field()->name, " : ", + component->field()->width, ";\n"); + } else { + absl::StrAppend(&h_output, " ", + GetUIntType(component->format()->declared_width()), " ", + component->format_alias(), " : ", + component->format()->declared_width(), ";\n"); + } + } + absl::StrAppend(&h_output, "} ABSL_ATTRIBUTE_PACKED;\n\n"); + // Next the union. + int num_bytes = (declared_width_ + 7) / 8; + absl::StrAppend(&h_output, "union Union", ToPascalCase(name()), + " {\n" + " Packed", + ToPascalCase(name()), " ", ToSnakeCase(name()), + ";\n" + " uint8_t bytes[", + num_bytes, "];\n"); + // If it is 64 bits or less, add an unsigned integer value type. + if (declared_width_ <= 64) { + absl::StrAppend(&h_output, " ", GetUIntType(declared_width_), " value;\n"); + } + absl::StrAppend(&h_output, "};\n\n"); + return h_output; +} + +// Top level function called to generate all the extractors for this format. +Extractors Format::GenerateExtractors() const { + Extractors extractors; if (extractors_.empty() && overlay_extractors_.empty()) { - return std::tie(h_output, class_output); + return extractors; } - class_output = absl::StrCat("class ", ToPascalCase(name()), " {\n public:\n", - " ", ToPascalCase(name()), "() = default;\n\n"); + extractors.class_output = + absl::StrCat("class ", ToPascalCase(name()), " {\n public:\n", " ", + ToPascalCase(name()), "() = default;\n\n"); // Use a separate namespace for each format. - h_output = absl::StrCat("namespace ", ToSnakeCase(name()), " {\n\n"); + extractors.h_output = + absl::StrCat("namespace ", ToSnakeCase(name()), " {\n\n"); + extractors.types_output = + absl::StrCat("namespace ", ToSnakeCase(name()), " {\n\n"); std::string get_size = absl::StrCat("constexpr int k", ToPascalCase(name()), "Size = ", declared_width(), ";\n\n"); - absl::StrAppend(&h_output, get_size); - absl::StrAppend(&class_output, "static ", get_size); + absl::StrAppend(&extractors.h_output, get_size); + absl::StrAppend(&extractors.class_output, "static ", get_size); + + // If this format has a packed struct layout, generate the types required. + if (layout() == Layout::kPackedStruct) { + absl::StrAppend(&extractors.types_output, GeneratePackedStructTypes()); + } // First fields and formats. for (auto &[unused, field_or_format_ptr] : extractors_) { if (field_or_format_ptr->is_field()) { - auto extractor = GenerateFieldExtractor(field_or_format_ptr->field()); - absl::StrAppend(&h_output, extractor); - absl::StrAppend(&class_output, "static ", extractor); + std::string extractor; + if (layout() == Layout::kPackedStruct) { + extractor = + GeneratePackedStructFieldExtractor(field_or_format_ptr->field()); + } else { + extractor = GenerateFieldExtractor(field_or_format_ptr->field()); + } + absl::StrAppend(&extractors.h_output, extractor); + absl::StrAppend(&extractors.class_output, "static ", extractor); } else { - auto extractor = GenerateFormatExtractor( - field_or_format_ptr->format_alias(), field_or_format_ptr->format(), - field_or_format_ptr->high(), field_or_format_ptr->size()); - absl::StrAppend(&h_output, extractor); - absl::StrAppend(&class_output, "static ", extractor); + std::string extractor; + if (layout() == Layout::kPackedStruct) { + extractor = GeneratePackedStructFormatExtractor( + field_or_format_ptr->format_alias(), field_or_format_ptr->format(), + field_or_format_ptr->high(), field_or_format_ptr->size()); + } else { + extractor = GenerateFormatExtractor( + field_or_format_ptr->format_alias(), field_or_format_ptr->format(), + field_or_format_ptr->high(), field_or_format_ptr->size()); + } + absl::StrAppend(&extractors.h_output, extractor); + absl::StrAppend(&extractors.class_output, "static ", extractor); } } // Then the overlays. for (auto &[unused, overlay_ptr] : overlay_extractors_) { - auto extractor = GenerateOverlayExtractor(overlay_ptr); - absl::StrAppend(&h_output, extractor); - absl::StrAppend(&class_output, "static ", extractor); + std::string extractor; + if (layout() == Layout::kPackedStruct) { + extractor = GeneratePackedStructOverlayExtractor(overlay_ptr); + } else { + extractor = GenerateOverlayExtractor(overlay_ptr); + } + absl::StrAppend(&extractors.h_output, extractor); + absl::StrAppend(&extractors.class_output, "static ", extractor); } - absl::StrAppend(&h_output, "} // namespace ", ToSnakeCase(name()), "\n\n"); - absl::StrAppend(&class_output, "};\n\n"); - return std::tie(h_output, class_output); + absl::StrAppend(&extractors.h_output, "} // namespace ", ToSnakeCase(name()), + "\n\n"); + absl::StrAppend(&extractors.types_output, "} // namespace ", + ToSnakeCase(name()), "\n\n"); + absl::StrAppend(&extractors.class_output, "};\n\n"); + return extractors; } bool Format::IsDerivedFrom(const Format *format) {
diff --git a/mpact/sim/decoder/format.h b/mpact/sim/decoder/format.h index c986510..deb4a55 100644 --- a/mpact/sim/decoder/format.h +++ b/mpact/sim/decoder/format.h
@@ -17,7 +17,6 @@ #include <map> #include <string> -#include <tuple> #include <vector> #include "absl/container/btree_map.h" @@ -106,8 +105,20 @@ Format *format_ = nullptr; }; +struct Extractors { + std::string h_output; + std::string class_output; + std::string types_output; +}; + class Format { public: + // Layout type of the format. + enum class Layout { + kDefault, + kPackedStruct, + }; + Format() = delete; Format(std::string name, int width, BinEncodingInfo *encoding_info); Format(std::string name, int width, std::string base_format_name, @@ -140,7 +151,7 @@ void PropagateExtractorsUp(); void PropagateExtractorsDown(); // Generates definitions of the field and overlay extractors in the format. - std::tuple<std::string, std::string> GenerateExtractors() const; + Extractors GenerateExtractors() const; // Generates definitions of the field and overlay inserters in the format. std::string GenerateInserters() const; @@ -157,11 +168,21 @@ Format *base_format() const { return base_format_; } // Return pointer to the parent encoding info class. BinEncodingInfo *encoding_info() const { return encoding_info_; } + // Field layout. + Layout layout() const { return layout_; } + void set_layout(Layout layout) { layout_ = layout; } private: bool HasExtract(const std::string &name) const; bool HasOverlayExtract(const std::string &name) const; + // Extractor generators. + std::string GeneratePackedStructTypes() const; + std::string GeneratePackedStructFieldExtractor(const Field *field) const; + std::string GeneratePackedStructFormatExtractor(std::string_view format_alias, + const Format *format, + int high, int size) const; + std::string GeneratePackedStructOverlayExtractor(Overlay *overlay) const; std::string GenerateFieldExtractor(const Field *field) const; std::string GenerateFormatExtractor(std::string_view format_alias, const Format *format, int high, @@ -169,9 +190,13 @@ std::string GenerateOverlayExtractor(Overlay *overlay) const; // Inserters. std::string GenerateFieldInserter(const Field *field) const; + std::string GeneratePackedStructFieldInserter(const Field *field) const; std::string GenerateFormatInserter(std::string_view format_alias, const Format *format, int high, int size) const; + std::string GeneratePackedStructFormatInserter(std::string_view format_alias, + const Format *format, int high, + int size) const; std::string GenerateReplicatedFormatInserter(std::string_view format_alias, const Format *format, int high, int size) const; @@ -190,6 +215,7 @@ std::string int_type_name_; int declared_width_; int computed_width_ = 0; + Layout layout_ = Layout::kDefault; Format *base_format_ = nullptr; std::vector<Format *> derived_formats_; BinEncodingInfo *encoding_info_;
diff --git a/mpact/sim/decoder/instruction_set_visitor.cc b/mpact/sim/decoder/instruction_set_visitor.cc index 406c6dd..0ce2e00 100644 --- a/mpact/sim/decoder/instruction_set_visitor.cc +++ b/mpact/sim/decoder/instruction_set_visitor.cc
@@ -1992,6 +1992,12 @@ pos++; if (pos >= format.size()) { pos = std::string::npos; + } else if (format[pos] == '?') { + format_info->is_optional = true; + pos++; + if (pos >= format.size()) { + pos = std::string::npos; + } } format_info->is_formatted = true; disasm_fmt->format_info_vec.push_back(format_info); @@ -2012,6 +2018,13 @@ auto *format_info = new FormatInfo(); format_info->op_name = op_name; format_info->is_formatted = false; + if ((pos != std::string::npos) && (format[pos] == '?')) { + format_info->is_optional = true; + pos++; + if (pos >= format.size()) { + pos = std::string::npos; + } + } disasm_fmt->format_info_vec.push_back(format_info); }
diff --git a/mpact/sim/decoder/mpact_sim_isa.bzl b/mpact/sim/decoder/mpact_sim_isa.bzl index db01738..efcb6f0 100644 --- a/mpact/sim/decoder/mpact_sim_isa.bzl +++ b/mpact/sim/decoder/mpact_sim_isa.bzl
@@ -170,6 +170,7 @@ "%s_bin_decoder.cc" % base_file_prefix, "%s_bin_encoder.h" % base_file_prefix, "%s_bin_encoder.cc" % base_file_prefix, + "%s_bin_types.h" % base_file_prefix, ] # The command to generate the files.
diff --git a/mpact/sim/decoder/opcode.h b/mpact/sim/decoder/opcode.h index 1cacd87..4921df6 100644 --- a/mpact/sim/decoder/opcode.h +++ b/mpact/sim/decoder/opcode.h
@@ -147,6 +147,7 @@ FormatInfo(const FormatInfo &) = default; std::string op_name; bool is_formatted = true; + bool is_optional = false; std::string number_format; bool use_address = false; std::string operation;
diff --git a/mpact/sim/decoder/overlay.cc b/mpact/sim/decoder/overlay.cc index b742651..7842bec 100644 --- a/mpact/sim/decoder/overlay.cc +++ b/mpact/sim/decoder/overlay.cc
@@ -14,22 +14,28 @@ #include "mpact/sim/decoder/overlay.h" +#include <algorithm> #include <cstdint> #include <string> #include <vector> +#include "absl/numeric/bits.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "mpact/sim/decoder/bin_format_visitor.h" #include "mpact/sim/decoder/format.h" +#include "mpact/sim/decoder/format_name.h" namespace mpact { namespace sim { namespace decoder { namespace bin_format { +using ::mpact::sim::machine_description::instruction_set::ToPascalCase; +using ::mpact::sim::machine_description::instruction_set::ToSnakeCase; + BitsOrField::BitsOrField(Field *field, int high, int low, int width) : field_(field), high_(high), low_(low), width_(width), position_(-1) {} @@ -250,6 +256,64 @@ return output; } +namespace { + +// Return the int type byte width (1, 2, 4, 8, 16) or (-1 if it's bigger), of +// the integer type that would fit this format. +int GetIntTypeBitWidth(int bitwidth) { + auto shift = absl::bit_width(static_cast<unsigned>(bitwidth)) - 1; + if (absl::popcount(static_cast<unsigned>(bitwidth)) > 1) shift++; + shift = std::max(shift, 3); + if (shift > 7) return -1; + return 1 << shift; +} + +std::string GetUIntType(int bitwidth) { + if (bitwidth > 128) return "uint8_t *"; + if (bitwidth > 64) return "absl::uint128"; + return absl::StrCat("uint", GetIntTypeBitWidth(bitwidth), "_t"); +} + +} // namespace + +std::string Overlay::WritePackedStructValueExtractor( + absl::string_view value, absl::string_view result) const { + std::string output; + std::string assign = " = "; + std::string union_type = + absl::StrCat("const ", ToSnakeCase(format_->name()), "::Union", + ToPascalCase(format_->name())); + absl::StrAppend(&output, " ", union_type, + " packed_union;\n" + " packed_union = reinterpret_cast<", + union_type, "*>(", + format_->declared_width() > 64 ? "value);\n" : "&value);\n"); + std::string result_type = GetUIntType(declared_width_); + for (auto *component : component_vec_) { + if (component->high() < 0) { + // Binary literals are added. + BinaryNum bin_num = component->bin_num(); + // If the value is 0, no need to 'or' it in. + if (bin_num.value == 0) continue; + + int shift = component->position() - bin_num.width + 1; + absl::StrAppend(&output, " ", result, assign, bin_num.value); + if (shift > 0) { + absl::StrAppend(&output, " << ", shift); + } + absl::StrAppend(&output, ";\n"); + } else { + // Field or format references are added. + absl::StrAppend( + &output, " ", result, assign, "static_cast<", result_type, + ">(packed_union->", ToSnakeCase(format_->name()), ".", + component->field()->name, ") << ", component->position(), ";\n"); + } + assign = " |= "; + } + return output; +} + // Return a string with the code (not counting function definition, variable // definition or return statement) for extracting the value of the overlay from // a variable 'value' and storing it into the variable 'result'. This extractor
diff --git a/mpact/sim/decoder/overlay.h b/mpact/sim/decoder/overlay.h index 7917988..cd05ed7 100644 --- a/mpact/sim/decoder/overlay.h +++ b/mpact/sim/decoder/overlay.h
@@ -107,6 +107,8 @@ absl::StatusOr<uint64_t> GetValue(uint64_t input) const; std::string WriteSimpleValueExtractor(absl::string_view value, absl::string_view result) const; + std::string WritePackedStructValueExtractor(absl::string_view value, + absl::string_view result) const; absl::StatusOr<uint64_t> GetValue(uint8_t *input); std::string WriteComplexValueExtractor(absl::string_view value, absl::string_view result,
diff --git a/mpact/sim/decoder/slot.cc b/mpact/sim/decoder/slot.cc index 06b48a8..c4c54f8 100644 --- a/mpact/sim/decoder/slot.cc +++ b/mpact/sim/decoder/slot.cc
@@ -308,7 +308,7 @@ } std::string input(str.substr(pos)); bool in_space = false; - char p; + char p = '\0'; for (auto c : str) { if (isspace(c)) { if (!in_space) { @@ -399,6 +399,7 @@ auto format_end = disasm_fmt->format_info_vec.end(); char prev = '\0'; // Iterate over the format fragments. + bool optional = false; while (fragment_iter != fragment_end) { auto fragment = *fragment_iter; if (!fragment.empty()) { @@ -408,6 +409,10 @@ } else { prev = '\0'; } + if (optional) { + absl::StrAppend(&output, ")?"); + } + optional = false; fragment_iter++; if (format_iter != format_end) { // If the trailling part of output is not '\\s*', and prev is @@ -419,6 +424,10 @@ absl::StrAppend(&output, "\\s*"); } } + if ((*format_iter)->is_optional) { + optional = true; + absl::StrAppend(&output, "(?:"); + } std::string op_name = (*format_iter)->op_name; absl::StrAppend(&output, "(\\S*?)"); opnd_locators.push_back(inst->opcode()->op_locator_map().at(op_name)); @@ -433,6 +442,9 @@ format_iter++; } } + if (optional) { + absl::StrAppend(&output, ")?"); + } } absl::StrAppend(&output, "\\s*$)\""); return {output, opnd_locators};
diff --git a/mpact/sim/generic/BUILD b/mpact/sim/generic/BUILD index e198eeb..5e6e266 100644 --- a/mpact/sim/generic/BUILD +++ b/mpact/sim/generic/BUILD
@@ -127,6 +127,8 @@ "core_debug_interface.h", ], deps = [ + ":core", + ":instruction", "@com_google_absl//absl/status", "@com_google_absl//absl/status:statusor", ],
diff --git a/mpact/sim/generic/core_debug_interface.h b/mpact/sim/generic/core_debug_interface.h index 75fd5f6..6402696 100644 --- a/mpact/sim/generic/core_debug_interface.h +++ b/mpact/sim/generic/core_debug_interface.h
@@ -22,14 +22,13 @@ #include "absl/status/status.h" #include "absl/status/statusor.h" +#include "mpact/sim/generic/data_buffer.h" +#include "mpact/sim/generic/instruction.h" namespace mpact { namespace sim { namespace generic { -class DataBuffer; -class Instruction; - enum class AccessType { kLoad = 1, kStore = 2,