Add support for decoding new write operations defined in chip data files

Change-Id: I83f2f72073fe05e1f0d9bde85e3aabe4c9df1a33
Signed-off-by: Caleb Palmer <cnpalmer@us.ibm.com>
diff --git a/README.md b/README.md
index 8b406dd..5ae5bc2 100644
--- a/README.md
+++ b/README.md
@@ -21,14 +21,14 @@
 ## User Application Requirements and APIs
 
 - The process to access hardware register data will vary per user application.
-  Therefore, this library will declare the hardware access [user APIs][], but
-  each user application must implement the APIs for their own environment.
+  Therefore, this library will declare the hardware access [user APIs][], but each
+  user application must implement the APIs for their own environment.
 - This library will not contain data regarding hardware specific information.
   Instead, that information will be provided by the user application in the form
   of the [Chip Data Files][].
 - Tracing, or logging, methods will vary per user application. Therefore, this
-  library will declare the tracing/logging [user APIs][], but each user
-  application must implement the APIs for their own environment.
+  library will declare the tracing/logging [user APIs][], but each user application
+  must implement the APIs for their own environment.
 
 ## Environment configuration
 
diff --git a/src/chip_data/hei_chip_data.cpp b/src/chip_data/hei_chip_data.cpp
index c5506aa..b37eb58 100644
--- a/src/chip_data/hei_chip_data.cpp
+++ b/src/chip_data/hei_chip_data.cpp
@@ -18,6 +18,7 @@
 
 constexpr Version_t VERSION_1 = 0x01;
 constexpr Version_t VERSION_2 = 0x02;
+constexpr Version_t VERSION_3 = 0x03;
 
 //------------------------------------------------------------------------------
 
@@ -251,6 +252,25 @@
     Instance_t numInsts;
     io_stream >> nodeId >> regType >> numInsts;
 
+    // Version 3 and above: Read any write operations that exist.
+    std::map<OpRuleName_t, std::pair<OpRuleType_t, RegisterId_t>> opRules;
+    if (VERSION_3 <= i_version)
+    {
+        uint8_t numOpRules;
+        io_stream >> numOpRules;
+        for (unsigned int i = 0; i < numOpRules; i++)
+        {
+            OpRuleName_t opName;
+            OpRuleType_t opType;
+            RegisterId_t regId;
+            io_stream >> opName >> opType >> regId;
+
+            std::pair<OpRuleType_t, RegisterId_t> tmpPair = {opType, regId};
+            auto ret = opRules.emplace(opName, tmpPair);
+            HEI_ASSERT(ret.second || ret.first->second == tmpPair);
+        }
+    }
+
     for (unsigned int i = 0; i < numInsts; i++)
     {
         // Read the node instance metadata.
@@ -325,6 +345,16 @@
             HEI_ASSERT(ret.second); // Should not have duplicate entries
         }
 
+        // Version 3 and above: Add any write operations to the isoNode.
+        if (VERSION_3 <= i_version)
+        {
+            for (const auto& rule : opRules)
+            {
+                isoNode->addOpRule(rule.first, rule.second.first,
+                                   rule.second.second);
+            }
+        }
+
         // Add this isolation node with the temporary child node map to the
         // returned map of nodes.
         auto ret = io_tmpNodeMap.emplace(IsolationNode::Key{nodeId, nodeInst},
@@ -397,7 +427,7 @@
     HEI_ASSERT(io_isoChips.end() == io_isoChips.find(chipType));
 
     // Check supported versions.
-    HEI_ASSERT(VERSION_1 <= version && version <= VERSION_2);
+    HEI_ASSERT(VERSION_1 <= version && version <= VERSION_3);
 
     // Allocate memory for the new isolation chip.
     auto isoChip = std::make_shared<IsolationChip>(chipType);
diff --git a/src/hei_types.hpp b/src/hei_types.hpp
index 80f5ef8..dc88351 100644
--- a/src/hei_types.hpp
+++ b/src/hei_types.hpp
@@ -134,6 +134,32 @@
 using RegisterAddress_t = uint64_t;
 
 /**
+ * This is used to define the name of a write operation rule for a FIR,
+ * defined in the Chip Data Files.
+ *
+ * Values:
+ *   This is a hashed value of one of the following string names:
+ *   "FIR_SET", "FIR_CLEAR", "MASK_SET", "MASK_CLEAR".
+ *
+ * Range:
+ *   This is defined as a 1-byte field in the Chip Data Files.
+ */
+using OpRuleName_t = uint8_t;
+
+/**
+ * This is used to define the type of a write operation rule for a FIR,
+ * defined in the Chip Data Files.
+ *
+ * Values:
+ *   This is a hashed value of one of the following string names:
+ *   "atomic_or", "atomic_and", "read_set_write", "read_clear_write".
+ *
+ * Range:
+ *   This is defined as a 1-byte field in the Chip Data Files.
+ */
+using OpRuleType_t = uint8_t;
+
+/**
  * The hardware register attribute flags.
  *
  * Values:
diff --git a/src/isolator/hei_isolation_node.cpp b/src/isolator/hei_isolation_node.cpp
index 78c5b65..d156015 100644
--- a/src/isolator/hei_isolation_node.cpp
+++ b/src/isolator/hei_isolation_node.cpp
@@ -145,6 +145,17 @@
 
 //------------------------------------------------------------------------------
 
+void IsolationNode::addOpRule(OpRuleName_t i_opName, OpRuleType_t i_opType,
+                              RegisterId_t i_regId)
+{
+    std::pair<OpRuleType_t, RegisterId_t> tmpPair = {i_opType, i_regId};
+    auto ret = iv_op_rules.emplace(i_opName, tmpPair);
+
+    HEI_ASSERT(ret.second || ret.first->second == tmpPair);
+}
+
+//------------------------------------------------------------------------------
+
 std::vector<const IsolationNode*> IsolationNode::cv_isolationStack{};
 
 //------------------------------------------------------------------------------
diff --git a/src/isolator/hei_isolation_node.hpp b/src/isolator/hei_isolation_node.hpp
index d88ad02..9043f1d 100644
--- a/src/isolator/hei_isolation_node.hpp
+++ b/src/isolator/hei_isolation_node.hpp
@@ -110,6 +110,12 @@
      */
     std::map<BitPosition_t, const ConstPtr> iv_children;
 
+    /**
+     * This map is used to store the write operation rules for the isolation
+     * node as defined in the Chip Data Files.
+     */
+    std::map<OpRuleName_t, std::pair<OpRuleType_t, RegisterId_t>> iv_op_rules;
+
   public: // Member functions
     /**
      * @brief  Finds all active attentions on this node. If an active bit is a
@@ -151,8 +157,8 @@
      * This is only intended to be used during initialization of the isolator.
      * Will assert that a rule has not already been defined for this type.
      *
-     * @param The target attention type.
-     * @param The rule for this attention type.
+     * @param i_attnType The target attention type.
+     * @param i_rule The rule for this attention type.
      */
     void addRule(AttentionType_t i_attnType, Register::ConstPtr i_rule);
 
@@ -163,11 +169,24 @@
      * This is only intended to be used during initialization of the isolator.
      * Will assert that nothing has already been defined for this bit.
      *
-     * @param The target bit on this node.
-     * @param The child node to analyze for the given bit.
+     * @param i_bit The target bit on this node.
+     * @param i_child The child node to analyze for the given bit.
      */
     void addChild(BitPosition_t i_bit, ConstPtr i_child);
 
+    /**
+     * @brief Adds a new write operation for the isolation node.
+     *
+     * This is only intended to be used during initialization of the isolator.
+     * Will assert that nothing has already been defined for this type.
+     *
+     * @param i_opName The name of the operation.
+     * @param i_opType The type of the operation.
+     * @param i_regId The ID of the register to be written.
+     */
+    void addOpRule(OpRuleName_t i_opName, OpRuleType_t i_opType,
+                   RegisterId_t i_regId);
+
     /** @return The node ID. */
     NodeId_t getId() const
     {