Add capture regs from Chip Data File to IsolationNode

Change-Id: Ia91821f2b14e12ed917c97b622789710ffb8bdb4
Signed-off-by: Zane Shelley <zshelle@us.ibm.com>
diff --git a/src/chip_data/hei_chip_data.cpp b/src/chip_data/hei_chip_data.cpp
index 87044db..752014b 100644
--- a/src/chip_data/hei_chip_data.cpp
+++ b/src/chip_data/hei_chip_data.cpp
@@ -75,7 +75,8 @@
 
 //------------------------------------------------------------------------------
 
-void __readExpr(ChipDataStream& io_stream, RegisterType_t i_regType)
+void __readExpr(ChipDataStream& io_stream, const IsolationChip::Ptr& i_isoChip,
+                IsolationNode::Ptr& io_isoNode)
 {
     uint8_t exprType;
     io_stream >> exprType;
@@ -86,11 +87,23 @@
             RegisterId_t regId;
             Instance_t regInst;
             io_stream >> regId >> regInst;
+
+            // Find the hardware register that is stored in this isolation chip
+            // and add it to the list of capture registers. This ensures all
+            // registers referenced in the rules are are captured by default.
+            // Note that this will assert that the target register must exist in
+            // the isolation chip.
+            auto hwReg = i_isoChip->getHardwareRegister({regId, regInst});
+
+            // Add the register to the isolation node.
+            io_isoNode->addCaptureRegister(hwReg);
+
             break;
         }
         case 0x02: // integer constant
         {
-            if (REG_TYPE_SCOM == i_regType || REG_TYPE_ID_SCOM == i_regType)
+            if (REG_TYPE_SCOM == io_isoNode->getRegisterType() ||
+                REG_TYPE_ID_SCOM == io_isoNode->getRegisterType())
             {
                 uint64_t constant; // 8-byte value
                 io_stream >> constant;
@@ -107,7 +120,7 @@
             io_stream >> numSubExpr;
             for (uint8_t i = 0; i < numSubExpr; i++)
             {
-                __readExpr(io_stream, i_regType);
+                __readExpr(io_stream, i_isoChip, io_isoNode);
             }
             break;
         }
@@ -117,27 +130,27 @@
             io_stream >> numSubExpr;
             for (uint8_t i = 0; i < numSubExpr; i++)
             {
-                __readExpr(io_stream, i_regType);
+                __readExpr(io_stream, i_isoChip, io_isoNode);
             }
             break;
         }
         case 0x12: // NOT operation
         {
-            __readExpr(io_stream, i_regType);
+            __readExpr(io_stream, i_isoChip, io_isoNode);
             break;
         }
         case 0x13: // left shift operation
         {
             uint8_t shiftValue;
             io_stream >> shiftValue;
-            __readExpr(io_stream, i_regType);
+            __readExpr(io_stream, i_isoChip, io_isoNode);
             break;
         }
         case 0x14: // right shift operation
         {
             uint8_t shiftValue;
             io_stream >> shiftValue;
-            __readExpr(io_stream, i_regType);
+            __readExpr(io_stream, i_isoChip, io_isoNode);
             break;
         }
         default:
@@ -162,30 +175,51 @@
         uint8_t numCapRegs, numIsoRules, numChildNodes;
         io_stream >> nodeInst >> numCapRegs >> numIsoRules >> numChildNodes;
 
+        // There must be at least one isolation rule defined.
+        HEI_ASSERT(0 != numIsoRules);
+
+        // Allocate memory for this isolation node.
+        auto isoNode =
+            std::make_shared<IsolationNode>(nodeId, nodeInst, regType);
+
         // Add capture registers.
         for (unsigned int j = 0; j < numCapRegs; j++)
         {
+            // Read the capture register metadata.
             RegisterId_t regId;
             Instance_t regInst;
             io_stream >> regId >> regInst;
+
+            // Find the hardware register that is stored in this isolation chip
+            // and add it to the list of capture registers. Note that this will
+            // assert that the target register must exist in the isolation chip.
+            auto hwReg = io_isoChip->getHardwareRegister({regId, regInst});
+
+            // Add the register to the isolation node.
+            isoNode->addCaptureRegister(hwReg);
         }
 
         // Add isolation rules.
         for (unsigned int j = 0; j < numIsoRules; j++)
         {
+            // Read the rule metadata.
             AttentionType_t attnType;
             io_stream >> attnType;
-            __readExpr(io_stream, regType);
+            __readExpr(io_stream, io_isoChip, isoNode);
         }
 
         // Add child nodes.
         for (unsigned int j = 0; j < numChildNodes; j++)
         {
+            // Read the child node metadata.
             BitPosition_t bit;
             NodeId_t childId;
             Instance_t childInst;
             io_stream >> bit >> childId >> childInst;
         }
+
+        // Add this node to the isolation chip.
+        io_isoChip->addIsolationNode(isoNode);
     }
 }
 
diff --git a/src/isolator/hei_isolation_node.hpp b/src/isolator/hei_isolation_node.hpp
index 2546a93..33df441 100644
--- a/src/isolator/hei_isolation_node.hpp
+++ b/src/isolator/hei_isolation_node.hpp
@@ -51,8 +51,10 @@
      * @param i_id       Unique ID for all instances of this node.
      * @param i_instance Instance of this node.
      */
-    IsolationNode(NodeId_t i_id, Instance_t i_instance) :
-        iv_id(i_id), iv_instance(i_instance)
+    IsolationNode(NodeId_t i_id, Instance_t i_instance,
+                  RegisterType_t i_regType) :
+        iv_id(i_id),
+        iv_instance(i_instance), iv_regType(i_regType)
     {}
 
     /** @brief Destructor. */
@@ -75,6 +77,14 @@
     const Instance_t iv_instance;
 
     /**
+     * A registers referenced by this node's rules must be of this type. No
+     * mixing of register types is allowed because comparing different sized
+     * registers is undefined behavior. Note that it is possible to have capture
+     * registers of mixed types.
+     */
+    const RegisterType_t iv_regType;
+
+    /**
      * The list of register to capture and add to the log for additional
      * debugging.
      */
@@ -85,7 +95,8 @@
      * register 'rule' (value) to find any active attentions for each attention
      * type (key). A 'rule', like "register & ~mask", is a combination of
      * HardwareRegister objects and virtual operator registers (all children
-     * of the Register class).
+     * of the Register class). Note that all registers referenced by these rules
+     * must be the same type as iv_regType.
      */
     std::map<AttentionType_t, const Register::ConstPtr> iv_rules;
 
@@ -166,6 +177,12 @@
         return {iv_id, iv_instance};
     }
 
+    /** @return This node's register type.. */
+    RegisterType_t getRegisterType() const
+    {
+        return iv_regType;
+    }
+
   private: // Isolation stack and supporting functions.
     /** When analyze() is called at the tree root, all recursive calls to
      *  analyze() will target the same chip and attention type. So we only need
diff --git a/src/register/hei_operator_register.hpp b/src/register/hei_operator_register.hpp
index 6bfaca9..5c225b1 100644
--- a/src/register/hei_operator_register.hpp
+++ b/src/register/hei_operator_register.hpp
@@ -72,18 +72,18 @@
      * @brief Constructor from components.
      * @param i_arg Target register for operation.
      */
-    explicit NotRegister(Register& i_arg) :
-        OperatorRegister(i_arg.getSize()), iv_child(&i_arg)
+    explicit NotRegister(Register::ConstPtr i_arg) :
+        OperatorRegister(i_arg->getSize()), iv_child(i_arg)
     {}
 
-    /** @brief Default destructor. */
+    /** @brief Destructor. */
     ~NotRegister() = default;
 
-    /** @brief Default copy constructor. */
-    NotRegister(const NotRegister&) = default;
+    /** @brief Copy constructor. */
+    NotRegister(const NotRegister&) = delete;
 
-    /** @brief Default assignment operator. */
-    NotRegister& operator=(const NotRegister& r) = default;
+    /** @brief Assignment operator. */
+    NotRegister& operator=(const NotRegister& r) = delete;
 
     /** @brief Overloaded from parent class. */
     const BitString* getBitString(const Chip& i_chip) const override
@@ -108,7 +108,7 @@
     }
 
   private:
-    Register* iv_child;
+    const Register::ConstPtr iv_child;
 };
 
 /**
@@ -126,18 +126,18 @@
      * @param i_arg    Target register for operation.
      * @param i_amount The shift value.
      */
-    LeftShiftRegister(Register& i_arg, uint16_t i_amount) :
-        OperatorRegister(i_arg.getSize()), iv_child(&i_arg), iv_amount(i_amount)
+    LeftShiftRegister(Register::ConstPtr i_arg, size_t i_amount) :
+        OperatorRegister(i_arg->getSize()), iv_child(i_arg), iv_amount(i_amount)
     {}
 
-    /** @brief Default destructor. */
+    /** @brief Destructor. */
     ~LeftShiftRegister() = default;
 
-    /** @brief Default copy constructor. */
-    LeftShiftRegister(const LeftShiftRegister&) = default;
+    /** @brief Copy constructor. */
+    LeftShiftRegister(const LeftShiftRegister&) = delete;
 
-    /** @brief Default assignment operator. */
-    LeftShiftRegister& operator=(const LeftShiftRegister& r) = default;
+    /** @brief Assignment operator. */
+    LeftShiftRegister& operator=(const LeftShiftRegister& r) = delete;
 
     /** @brief Overloaded from parent class. */
     const BitString* getBitString(const Chip& i_chip) const override
@@ -164,8 +164,8 @@
     }
 
   private:
-    Register* iv_child;
-    uint16_t iv_amount;
+    const Register::ConstPtr iv_child;
+    const size_t iv_amount;
 };
 
 /**
@@ -183,18 +183,18 @@
      * @param i_arg    Target register for operation.
      * @param i_amount The shift value.
      */
-    RightShiftRegister(Register& i_arg, uint16_t i_amount) :
-        OperatorRegister(i_arg.getSize()), iv_child(&i_arg), iv_amount(i_amount)
+    RightShiftRegister(Register::ConstPtr i_arg, size_t i_amount) :
+        OperatorRegister(i_arg->getSize()), iv_child(i_arg), iv_amount(i_amount)
     {}
 
-    /** @brief Default destructor. */
+    /** @brief Destructor. */
     ~RightShiftRegister() = default;
 
-    /** @brief Default copy constructor. */
-    RightShiftRegister(const RightShiftRegister&) = default;
+    /** @brief Copy constructor. */
+    RightShiftRegister(const RightShiftRegister&) = delete;
 
-    /** @brief Default assignment operator. */
-    RightShiftRegister& operator=(const RightShiftRegister& r) = default;
+    /** @brief Assignment operator. */
+    RightShiftRegister& operator=(const RightShiftRegister& r) = delete;
 
     /** @brief Overloaded from parent class. */
     const BitString* getBitString(const Chip& i_chip) const override
@@ -221,8 +221,8 @@
     }
 
   private:
-    Register* iv_child;
-    uint16_t iv_amount;
+    const Register::ConstPtr iv_child;
+    const size_t iv_amount;
 };
 
 /**
@@ -241,19 +241,22 @@
      * @param i_left  Target register for operation.
      * @param i_right Target register for operation.
      */
-    AndRegister(Register& i_left, Register& i_right) :
-        OperatorRegister(std::min(i_left.getSize(), i_right.getSize())),
-        iv_left(&i_left), iv_right(&i_right)
-    {}
+    AndRegister(Register::ConstPtr i_left, Register::ConstPtr i_right) :
+        OperatorRegister(i_left->getSize()), iv_left(i_left), iv_right(i_right)
+    {
+        // The two registers must be the same sizes or it makes for some weird
+        // results.
+        HEI_ASSERT(iv_left->getSize() == iv_right->getSize());
+    }
 
-    /** @brief Default destructor. */
+    /** @brief Destructor. */
     ~AndRegister() = default;
 
-    /** @brief Default copy constructor. */
-    AndRegister(const AndRegister&) = default;
+    /** @brief Copy constructor. */
+    AndRegister(const AndRegister&) = delete;
 
-    /** @brief Default assignment operator. */
-    AndRegister& operator=(const AndRegister& r) = default;
+    /** @brief Assignment operator. */
+    AndRegister& operator=(const AndRegister& r) = delete;
 
     /** @brief Overloaded from parent class. */
     const BitString* getBitString(const Chip& i_chip) const override
@@ -281,8 +284,8 @@
     }
 
   private:
-    Register* iv_left;
-    Register* iv_right;
+    const Register::ConstPtr iv_left;
+    const Register::ConstPtr iv_right;
 };
 
 /**
@@ -301,19 +304,22 @@
      * @param i_left  Target register for operation.
      * @param i_right Target register for operation.
      */
-    OrRegister(Register& i_left, Register& i_right) :
-        OperatorRegister(std::min(i_left.getSize(), i_right.getSize())),
-        iv_left(&i_left), iv_right(&i_right)
-    {}
+    OrRegister(Register::ConstPtr i_left, Register::ConstPtr i_right) :
+        OperatorRegister(i_left->getSize()), iv_left(i_left), iv_right(i_right)
+    {
+        // The two registers must be the same sizes or it makes for some weird
+        // results.
+        HEI_ASSERT(iv_left->getSize() == iv_right->getSize());
+    }
 
-    /** @brief Default destructor. */
+    /** @brief Destructor. */
     ~OrRegister() = default;
 
-    /** @brief Default copy constructor. */
-    OrRegister(const OrRegister&) = default;
+    /** @brief Copy constructor. */
+    OrRegister(const OrRegister&) = delete;
 
-    /** @brief Default assignment operator. */
-    OrRegister& operator=(const OrRegister& r) = default;
+    /** @brief Assignment operator. */
+    OrRegister& operator=(const OrRegister& r) = delete;
 
     /** @brief Overloaded from parent class. */
     const BitString* getBitString(const Chip& i_chip) const override
@@ -341,36 +347,38 @@
     }
 
   private:
-    Register* iv_left;
-    Register* iv_right;
+    const Register::ConstPtr iv_left;
+    const Register::ConstPtr iv_right;
 };
 
 /**
  * @brief Contains a constant value that can be used within any of the other
  *        register operators. The value can be retrieved using the
  *        getBitString() function.
- **/
+ */
 class ConstantRegister : public OperatorRegister
 {
   public:
     /**
      * @brief Constructor from components.
-     * @param i_arg A BitStringBuffer containing the constant value.
+     * @param i_val An unsigned integer value. iv_result will be initialized to
+     *              the size of type T and this value will be copied into that
+     *              buffer.
      */
-    explicit ConstantRegister(const BitStringBuffer& i_arg) :
-        OperatorRegister(BitString::getMinBytes(i_arg.getBitLen()))
+    template <class T>
+    explicit ConstantRegister(T i_val) : OperatorRegister(sizeof(i_val))
     {
-        iv_result = i_arg;
+        iv_result.setFieldRight(0, iv_result.getBitLen(), i_val);
     }
 
-    /** @brief Default destructor. */
+    /** @brief Destructor. */
     ~ConstantRegister() = default;
 
-    /** @brief Default copy constructor. */
-    ConstantRegister(const ConstantRegister&) = default;
+    /** @brief Copy constructor. */
+    ConstantRegister(const ConstantRegister&) = delete;
 
-    /** @brief Default assignment operator. */
-    ConstantRegister& operator=(const ConstantRegister& r) = default;
+    /** @brief Assignment operator. */
+    ConstantRegister& operator=(const ConstantRegister& r) = delete;
 
     /** @brief Overloaded from parent class. */
     const BitString* getBitString(const Chip& i_chip) const override
diff --git a/src/util/hei_bit_string.cpp b/src/util/hei_bit_string.cpp
index 9cc2613..a04fb43 100644
--- a/src/util/hei_bit_string.cpp
+++ b/src/util/hei_bit_string.cpp
@@ -286,25 +286,29 @@
 
 bool BitString::operator<(const BitString& i_str) const
 {
-    // The two bit strings must be the same length. Otherwise, the comparison
-    // undefined (i.e. compare from the left vs. right).
-    HEI_ASSERT(getBitLen() == i_str.getBitLen());
-
-    for (uint64_t pos = 0; pos < getBitLen(); pos += UINT64_BIT_LEN)
+    if (getBitLen() < i_str.getBitLen())
     {
-        uint64_t len = std::min(getBitLen() - pos, UINT64_BIT_LEN);
-
-        auto l_str = getFieldRight(pos, len);
-        auto r_str = i_str.getFieldRight(pos, len);
-
-        if (l_str < r_str)
+        return true;
+    }
+    else if (getBitLen() == i_str.getBitLen())
+    {
+        // Can only compare the bit strings if the length is the same.
+        for (uint64_t pos = 0; pos < getBitLen(); pos += UINT64_BIT_LEN)
         {
-            return true;
-        }
-        // The loop can only continue if the values are equal.
-        else if (l_str > r_str)
-        {
-            return false;
+            uint64_t len = std::min(getBitLen() - pos, UINT64_BIT_LEN);
+
+            auto l_str = getFieldRight(pos, len);
+            auto r_str = i_str.getFieldRight(pos, len);
+
+            if (l_str < r_str)
+            {
+                return true;
+            }
+            // The loop can only continue if the values are equal.
+            else if (l_str > r_str)
+            {
+                return false;
+            }
         }
     }
 
diff --git a/src/util/hei_bit_string.hpp b/src/util/hei_bit_string.hpp
index 669e755..59369b7 100644
--- a/src/util/hei_bit_string.hpp
+++ b/src/util/hei_bit_string.hpp
@@ -333,7 +333,15 @@
         return isEqual(i_str);
     }
 
-    /** @brief Less-than operator */
+    /**
+     * @brief Less-than operator.
+     *
+     * IMPORTANT:
+     * The purpose of this function is primarily for sorting these objects in
+     * data structures like map and vector. It does not guarantee a less than
+     * comparison of the bit strings because bit strings can vary in length and
+     * it is difficult to define that kind of comparison.
+     */
     bool operator<(const BitString& i_str) const;
 
     /** @brief Bitwise NOT operator. */