Adds RiscV Zicond instruction semantic functions and isa/bin_fmt defs.

Adds capability to combine instruction groups other than in decoders
in .bin_fmt files.

PiperOrigin-RevId: 689844873
Change-Id: Ide0a427228fd32906597eeeca8c86a0b039584ce
diff --git a/mpact/sim/decoder/BinFormat.g4 b/mpact/sim/decoder/BinFormat.g4
index 1a4ba6a..57872d4 100644
--- a/mpact/sim/decoder/BinFormat.g4
+++ b/mpact/sim/decoder/BinFormat.g4
@@ -117,6 +117,7 @@
 instruction_group_def
   : INSTRUCTION GROUP name=IDENT '[' number ']' ':' format=IDENT
     '{' instruction_def_list '}' ';'?
+  | INSTRUCTION GROUP name=IDENT '=' '{' group_name_list '}' ';'?
   ;
 
 instruction_def_list
diff --git a/mpact/sim/decoder/bin_format_contexts.h b/mpact/sim/decoder/bin_format_contexts.h
index 5a97a47..8457626 100644
--- a/mpact/sim/decoder/bin_format_contexts.h
+++ b/mpact/sim/decoder/bin_format_contexts.h
@@ -34,6 +34,7 @@
 using FieldConstraintCtx = BinFormatParser::Field_constraintContext;
 using FieldDefCtx = BinFormatParser::Field_defContext;
 using FormatDefCtx = BinFormatParser::Format_defContext;
+using GroupNameListCtx = BinFormatParser::Group_name_listContext;
 using IncludeFileCtx = BinFormatParser::Include_fileContext;
 using InstructionGroupDefCtx = BinFormatParser::Instruction_group_defContext;
 using InstructionDefCtx = BinFormatParser::Instruction_defContext;
diff --git a/mpact/sim/decoder/bin_format_visitor.cc b/mpact/sim/decoder/bin_format_visitor.cc
index c969fbd..04d944e 100644
--- a/mpact/sim/decoder/bin_format_visitor.cc
+++ b/mpact/sim/decoder/bin_format_visitor.cc
@@ -21,7 +21,6 @@
 #include <istream>
 #include <list>
 #include <memory>
-#include <new>
 #include <string>
 #include <utility>
 #include <vector>
@@ -709,53 +708,63 @@
         file_names_[context_file_map_.at(ctx)], ctx->start,
         absl::StrCat(group_name, ": illegal use of format name"));
   }
-  int width = ConvertToInt(ctx->number());
-  std::string format_name = ctx->format->getText();
-  auto iter = format_decl_map_.find(format_name);
-  if (iter == format_decl_map_.end()) {
-    error_listener_->semanticError(
-        file_names_[context_file_map_.at(ctx)], ctx->start,
-        absl::StrCat("Undefined format '", format_name,
-                     "' used by instruction group '", group_name, "'"));
-    return nullptr;
-  } else {
-    VisitFormatDef(iter->second, encoding_info);
-    auto *format = encoding_info->GetFormat(format_name);
-    // Verify that the format width = declared width and also <= 64 bits wide.
-    if (format->declared_width() != width) {
+  // If the width is specified, this is a single instruction group with
+  // format definitions.
+  if (ctx->number() != nullptr) {
+    int width = ConvertToInt(ctx->number());
+    std::string format_name = ctx->format->getText();
+    auto iter = format_decl_map_.find(format_name);
+    if (iter == format_decl_map_.end()) {
       error_listener_->semanticError(
-          file_names_[context_file_map_.at(format_decl_map_.at(format_name))],
-          ctx->start,
-          absl::StrCat("Width of format '", format_name, "' (",
-                       format->declared_width(),
-                       ") differs from the declared width of instruction "
-                       "group '",
-                       group_name, "' (", width, ")"));
+          file_names_[context_file_map_.at(ctx)], ctx->start,
+          absl::StrCat("Undefined format '", format_name,
+                       "' used by instruction group '", group_name, "'"));
+      return nullptr;
+    } else {
+      VisitFormatDef(iter->second, encoding_info);
+      auto *format = encoding_info->GetFormat(format_name);
+      // Verify that the format width = declared width and also <= 64 bits wide.
+      if (format->declared_width() != width) {
+        error_listener_->semanticError(
+            file_names_[context_file_map_.at(format_decl_map_.at(format_name))],
+            ctx->start,
+            absl::StrCat("Width of format '", format_name, "' (",
+                         format->declared_width(),
+                         ") differs from the declared width of instruction "
+                         "group '",
+                         group_name, "' (", width, ")"));
+      }
+      if (format->declared_width() > 64) {
+        error_listener_->semanticError(
+            file_names_[context_file_map_.at(format_decl_map_.at(format_name))],
+            ctx->start,
+            absl::StrCat("Instruction group '", group_name,
+                         "': width must be <= 64 bits"));
+      }
     }
-    if (format->declared_width() > 64) {
-      error_listener_->semanticError(
-          file_names_[context_file_map_.at(format_decl_map_.at(format_name))],
-          ctx->start,
-          absl::StrCat("Instruction group '", group_name,
-                       "': width must be <= 64 bits"));
+    auto inst_group_res =
+        encoding_info->AddInstructionGroup(group_name, width, format_name);
+    if (!inst_group_res.ok()) {
+      error_listener_->semanticError(file_names_[context_file_map_.at(ctx)],
+                                     ctx->start,
+                                     inst_group_res.status().message());
+      return nullptr;
     }
+    // Parse the instruction encoding definitions in the instruction group.
+    auto *inst_group = inst_group_res.value();
+    int file_index = context_file_map_.at(ctx);
+    for (auto *inst_def : ctx->instruction_def_list()->instruction_def()) {
+      context_file_map_.insert({inst_def, file_index});
+      VisitInstructionDef(inst_def, inst_group);
+    }
+    return inst_group_res.value();
   }
-  auto inst_group_res =
-      encoding_info->AddInstructionGroup(group_name, width, format_name);
-  if (!inst_group_res.ok()) {
-    error_listener_->semanticError(file_names_[context_file_map_.at(ctx)],
-                                   ctx->start,
-                                   inst_group_res.status().message());
-    return nullptr;
-  }
-  // Parse the instruction encoding definitions in the instruction group.
-  auto *inst_group = inst_group_res.value();
-  int file_index = context_file_map_.at(ctx);
-  for (auto *inst_def : ctx->instruction_def_list()->instruction_def()) {
-    context_file_map_.insert({inst_def, file_index});
-    VisitInstructionDef(inst_def, inst_group);
-  }
-  return inst_group_res.value();
+  // This is a group that combines multiple other instruction groups.
+  absl::flat_hash_set<std::string> group_name_set;
+  auto file_index = context_file_map_.at(ctx);
+  context_file_map_.insert({ctx->group_name_list(), file_index});
+  return VisitInstructionGroupNameList(group_name, ctx->group_name_list(),
+                                       group_name_set, encoding_info);
 }
 
 void BinFormatVisitor::VisitInstructionDef(InstructionDefCtx *ctx,
@@ -1078,6 +1087,12 @@
     if ((attr_ctx->group_name() != nullptr) &&
         (attr_ctx->group_name()->group_name_list() == nullptr)) {
       std::string group_name = attr_ctx->group_name()->IDENT()->getText();
+      if (group_name_set.contains(group_name)) {
+        error_listener_->semanticError(
+            file_names_[context_file_map_.at(ctx)], attr_ctx->start,
+            absl::StrCat("Instruction group '", group_name, "' listed twice"));
+        continue;
+      }
 
       auto map_iter = encoding_info->instruction_group_map().find(group_name);
       InstructionGroup *inst_group = nullptr;
@@ -1097,12 +1112,6 @@
           continue;
         }
       }
-      if (group_name_set.contains(group_name)) {
-        error_listener_->semanticError(
-            file_names_[context_file_map_.at(ctx)], attr_ctx->start,
-            absl::StrCat("Instruction group '", group_name, "' listed twice"));
-        continue;
-      }
       group_name_set.insert(group_name);
       decoder->AddInstructionGroup(inst_group);
       continue;
@@ -1110,98 +1119,26 @@
     // If it is a parent group, process it here.
     if ((attr_ctx->group_name() != nullptr) &&
         (attr_ctx->group_name()->group_name_list() != nullptr)) {
-      // Check each of the child groups. Visit any that haven't been visited
-      // yet, and make sure they all specify the same format.
       std::string group_name = attr_ctx->group_name()->IDENT()->getText();
       if (group_name_set.contains(group_name)) {
         error_listener_->semanticError(
             file_names_[context_file_map_.at(ctx)], attr_ctx->start,
-            absl::StrCat("Instruction group '", group_name,
-                         "' listed twice - ignored"));
+            absl::StrCat("Instruction group '", group_name, "' listed twice"));
         continue;
       }
-      std::vector<InstructionGroup *> child_groups;
-      std::string group_format_name;
-      // Iterate through the list of named "child" groups to combine.
-      for (auto *ident : attr_ctx->group_name()->group_name_list()->IDENT()) {
-        auto child_name = ident->getText();
-        if (group_name_set.contains(child_name)) {
-          error_listener_->semanticError(
-              file_names_[context_file_map_.at(ctx)], attr_ctx->start,
-              absl::StrCat("Instruction group listed twice: '", child_name,
-                           "' - ignored"));
-          continue;
-        }
-        InstructionGroup *child_group = nullptr;
-        auto map_iter = encoding_info->instruction_group_map().find(child_name);
-        if (map_iter != encoding_info->instruction_group_map().end()) {
-          child_group = map_iter->second;
-          bool exists = false;
-          for (auto const *group : child_groups) {
-            if (child_name == group->name()) {
-              exists = true;
-              break;
-            }
-          }
-          if (exists) {
-            error_listener_->semanticError(
-                file_names_[context_file_map_.at(ctx)], attr_ctx->start,
-                absl::StrCat("Instruction group '", child_name,
-                             "' listed twice"));
-            continue;
-          }
-        } else {
-          // The instruction group hasn't been visited yet, so look up the
-          // declaration and visit it now.
-          auto iter = group_decl_map_.find(child_name);
-          if (iter != group_decl_map_.end()) {
-            child_group =
-                VisitInstructionGroupDef(iter->second, encoding_info.get());
-          }
-          if (child_group == nullptr) {
-            error_listener_->semanticError(
-                file_names_[context_file_map_.at(ctx)], attr_ctx->start,
-                absl::StrCat("Instruction group '", child_name, "' not found"));
-            continue;
-          }
-        }
-        if (child_groups.empty()) {
-          group_format_name = child_group->format_name();
-        }
-        // Check that the child groups all use the same instruction format.
-        if (group_format_name != child_group->format_name()) {
-          error_listener_->semanticError(
-              file_names_[context_file_map_.at(ctx)], attr_ctx->start,
-              absl::StrCat("Instruction group '", child_name,
-                           "' must use format '", group_format_name,
-                           ", to be merged into group '", group_name, "'"));
-          continue;
-        }
-        child_groups.push_back(child_group);
+      auto file_index = context_file_map_.at(ctx);
+      context_file_map_.insert(
+          {attr_ctx->group_name()->group_name_list(), file_index});
+      auto *parent_group = VisitInstructionGroupNameList(
+          group_name, attr_ctx->group_name()->group_name_list(), group_name_set,
+          encoding_info.get());
+      if (parent_group == nullptr) {
+        continue;
       }
 
-      if (child_groups.empty()) {
-        error_listener_->semanticError(attr_ctx->start, "No child groups");
-        continue;
-      }
-      // Create the "parent" group and add all of the instructions from the
-      // child groups to it.
-      auto width = child_groups.front()->width();
-      auto res = encoding_info->AddInstructionGroup(group_name, width,
-                                                    group_format_name);
-      if (!res.ok()) {
-        error_listener_->semanticError(attr_ctx->start, res.status().message());
-        continue;
-      }
-      auto parent_group = res.value();
-      for (auto *child_group : child_groups) {
-        for (auto *encoding : child_group->encoding_vec()) {
-          parent_group->AddInstructionEncoding(
-              new InstructionEncoding(*encoding));
-        }
-      }
-      group_name_set.insert(parent_group->name());
+      group_name_set.insert(group_name);
       decoder->AddInstructionGroup(parent_group);
+      continue;
     }
   }
   if (group_name_set.empty()) {
@@ -1210,6 +1147,78 @@
   return encoding_info;
 }
 
+InstructionGroup *BinFormatVisitor::VisitInstructionGroupNameList(
+    const std::string &group_name, GroupNameListCtx *ctx,
+    absl::flat_hash_set<std::string> &group_name_set,
+    BinEncodingInfo *encoding_info) {
+  std::vector<InstructionGroup *> child_groups;
+  std::string group_format_name;
+  // Iterate through the list of named "child" groups to combine.
+  for (auto *ident : ctx->IDENT()) {
+    auto child_name = ident->getText();
+    if (group_name_set.contains(child_name)) {
+      error_listener_->semanticError(
+          file_names_[context_file_map_.at(ctx)], ctx->start,
+          absl::StrCat("Instruction group added twice: '", child_name,
+                       "' - ignored"));
+      continue;
+    }
+    InstructionGroup *child_group = nullptr;
+    auto map_iter = encoding_info->instruction_group_map().find(child_name);
+    if (map_iter != encoding_info->instruction_group_map().end()) {
+      child_group = map_iter->second;
+    } else {
+      // The instruction group hasn't been visited yet, so look up the
+      // declaration and visit it now.
+      auto iter = group_decl_map_.find(child_name);
+      if (iter != group_decl_map_.end()) {
+        child_group = VisitInstructionGroupDef(iter->second, encoding_info);
+      }
+      if (child_group == nullptr) {
+        error_listener_->semanticError(
+            file_names_[context_file_map_.at(ctx)], ctx->start,
+            absl::StrCat("Instruction group '", child_name, "' not found"));
+        continue;
+      }
+    }
+    // If this is the first child group, then set the format name.
+    if (child_groups.empty()) {
+      group_format_name = child_group->format_name();
+    } else if (group_format_name != child_group->format_name()) {
+      // Check that the child groups all use the same instruction format.
+      error_listener_->semanticError(
+          file_names_[context_file_map_.at(ctx)], ctx->start,
+          absl::StrCat("Instruction group '", child_name, "' must use format '",
+                       group_format_name, ", to be merged into group '",
+                       group_name, "'"));
+      continue;
+    }
+    group_name_set.insert(child_name);
+    child_groups.push_back(child_group);
+  }
+
+  if (child_groups.empty()) {
+    error_listener_->semanticError(ctx->start, "No child groups");
+    return nullptr;
+  }
+  // Create the "parent" group and add all of the instructions from the
+  // child groups to it.
+  auto width = child_groups.front()->width();
+  auto res =
+      encoding_info->AddInstructionGroup(group_name, width, group_format_name);
+  if (!res.ok()) {
+    error_listener_->semanticError(ctx->start, res.status().message());
+    return nullptr;
+  }
+  auto parent_group = res.value();
+  for (auto *child_group : child_groups) {
+    for (auto *encoding : child_group->encoding_vec()) {
+      parent_group->AddInstructionEncoding(new InstructionEncoding(*encoding));
+    }
+  }
+  return parent_group;
+}
+
 }  // namespace bin_format
 }  // namespace decoder
 }  // namespace sim
diff --git a/mpact/sim/decoder/bin_format_visitor.h b/mpact/sim/decoder/bin_format_visitor.h
index 25a99bb..cd5ae1a 100644
--- a/mpact/sim/decoder/bin_format_visitor.h
+++ b/mpact/sim/decoder/bin_format_visitor.h
@@ -24,6 +24,7 @@
 #include <vector>
 
 #include "absl/container/flat_hash_map.h"
+#include "absl/container/flat_hash_set.h"
 #include "absl/status/status.h"
 #include "absl/strings/string_view.h"
 #include "antlr4-runtime/ParserRuleContext.h"
@@ -126,6 +127,10 @@
       const std::string &template_str_in) const;
   void VisitConstraint(Format *format, FieldConstraintCtx *ctx,
                        InstructionEncoding *inst_encoding);
+  InstructionGroup *VisitInstructionGroupNameList(
+      const std::string &group_name, GroupNameListCtx *ctx,
+      absl::flat_hash_set<std::string> &group_name_set,
+      BinEncodingInfo *encoding_info);
 
   // Accessors.
   decoder::DecoderErrorListener *error_listener() const {
diff --git a/mpact/sim/decoder/test/bin_format_visitor_test.cc b/mpact/sim/decoder/test/bin_format_visitor_test.cc
index 217b66a..4080b13 100644
--- a/mpact/sim/decoder/test/bin_format_visitor_test.cc
+++ b/mpact/sim/decoder/test/bin_format_visitor_test.cc
@@ -618,13 +618,13 @@
       "Error: No such instruction group: 'InstGroup'");
   EXPECT_TRUE(ptr != std::string::npos);
   ptr = log_sink.error_log().find(
-      "Error: Instruction group 'inst32a' listed twice - ignored");
+      "Error: Instruction group added twice: 'inst32a' - ignored");
   EXPECT_TRUE(ptr != std::string::npos);
   ptr = log_sink.error_log().find(
-      "Error: Instruction group 'InstGroup2' listed twice - ignored");
+      "Error: Instruction group 'InstGroup2' listed twice");
   EXPECT_TRUE(ptr != std::string::npos);
   ptr = log_sink.error_log().find(
-      "Error: Instruction group 'inst32c' listed twice");
+      "Error: Instruction group added twice: 'inst32c' - ignored");
   EXPECT_TRUE(ptr != std::string::npos);
   ptr =
       log_sink.error_log().find("Error: Instruction group 'inst32d' not found");
diff --git a/mpact/sim/generic/register.h b/mpact/sim/generic/register.h
index 91479c4..b25861b 100644
--- a/mpact/sim/generic/register.h
+++ b/mpact/sim/generic/register.h
@@ -23,7 +23,6 @@
 #include <any>
 #include <cstdint>
 #include <functional>
-#include <map>
 #include <string>
 #include <vector>
 
@@ -49,7 +48,7 @@
 class RegisterSourceOperand : public SourceOperandInterface {
  public:
   // Constructor. Note, default constructor deleted.
-  RegisterSourceOperand(RegisterBase *reg, const std::string op_name);
+  RegisterSourceOperand(RegisterBase *reg, std::string op_name);
   explicit RegisterSourceOperand(RegisterBase *reg);
 
   RegisterSourceOperand() = delete;
diff --git a/mpact/sim/generic/state_item.h b/mpact/sim/generic/state_item.h
index 17116cc..1df112c 100644
--- a/mpact/sim/generic/state_item.h
+++ b/mpact/sim/generic/state_item.h
@@ -15,6 +15,7 @@
 #ifndef MPACT_SIM_GENERIC_STATE_ITEM_H_
 #define MPACT_SIM_GENERIC_STATE_ITEM_H_
 
+#include <cstdint>
 #include <string>
 #include <type_traits>