Build HardwareRegister objects from Chip Data Files

Change-Id: I4fbcdd5ba012008000b8d1f324dd47d95ef2d932
Signed-off-by: Zane Shelley <zshelle@us.ibm.com>
diff --git a/src/chip_data/CHIP_DATA.md b/src/chip_data/CHIP_DATA.md
index c7ad234..24fe1a8 100644
--- a/src/chip_data/CHIP_DATA.md
+++ b/src/chip_data/CHIP_DATA.md
@@ -41,7 +41,7 @@
 
 | Bytes | Desc             | Value/Example                 |
 |:-----:|:-----------------|:------------------------------|
-|     4 | register keyword | 0x43484950 (ascii for "REGS") |
+|     4 | register keyword | 0x52454753 (ascii for "REGS") |
 |     3 | # of registers   | 0 is invalid                  |
 
 Then, each register will start with:
diff --git a/src/chip_data/hei_chip_data.cpp b/src/chip_data/hei_chip_data.cpp
index f10589d..a6f1c10 100644
--- a/src/chip_data/hei_chip_data.cpp
+++ b/src/chip_data/hei_chip_data.cpp
@@ -1,5 +1,6 @@
 #include <chip_data/hei_chip_data.hpp>
 #include <chip_data/hei_chip_data_stream.hpp>
+#include <register/hei_scom_register.hpp>
 
 namespace libhei
 {
@@ -12,7 +13,7 @@
 
 using SectionKeyword_t = uint32_t;
 
-constexpr SectionKeyword_t KW_REGS = 0x43484950; // "REGS" ASCII
+constexpr SectionKeyword_t KW_REGS = 0x52454753; // "REGS" ASCII
 constexpr SectionKeyword_t KW_NODE = 0x4e4f4445; // "NODE" ASCII
 constexpr SectionKeyword_t KW_ROOT = 0x524f4f54; // "ROOT" ASCII
 
@@ -22,27 +23,96 @@
 
 //------------------------------------------------------------------------------
 
+void __readRegister(ChipDataStream& io_stream, IsolationChipPtr& io_isoChip)
+{
+    // Read the register metadata.
+    RegisterId_t id;
+    RegisterType_t type;
+    RegisterAttributeFlags_t attr;
+    Instance_t numInsts;
+    io_stream >> id >> type >> attr >> numInsts;
+
+    // Must have at least one instance.
+    HEI_ASSERT(0 != numInsts);
+
+    for (Instance_t i = 0; i < numInsts; i++)
+    {
+        // Read the register instance metadata.
+        Instance_t inst;
+        io_stream >> inst;
+
+        // The address size is dependent on the register type.
+        if (REG_TYPE_SCOM == type)
+        {
+            uint32_t addr; // 4-byte address.
+            io_stream >> addr;
+
+            // Get this register from the flyweight factory.
+            auto& factory = Flyweight<const ScomRegister>::getSingleton();
+            HardwareRegisterPtr hwReg = factory.get(id, inst, attr, addr);
+
+            // Add this register to the isolation chip.
+            io_isoChip->addHardwareRegister(hwReg);
+        }
+        else if (REG_TYPE_ID_SCOM == type)
+        {
+            uint64_t addr; // 8-byte address.
+            io_stream >> addr;
+
+            // Get this register from the flyweight factory.
+            auto& factory = Flyweight<const IdScomRegister>::getSingleton();
+            HardwareRegisterPtr hwReg = factory.get(id, inst, attr, addr);
+
+            // Add this register to the isolation chip.
+            io_isoChip->addHardwareRegister(hwReg);
+        }
+        else
+        {
+            HEI_ASSERT(false); // Register type unsupported.
+        }
+    }
+}
+
+//------------------------------------------------------------------------------
+
 void parseChipDataFile(void* i_buffer, size_t i_bufferSize,
                        IsolationChipMap& io_isoChips)
 {
     ChipDataStream stream{i_buffer, i_bufferSize};
 
     // Read the file metadata.
-    FileKeyword_t file_kw = 0;
-    ChipType_t chipType   = 0;
-    Version_t version     = 0;
-    stream >> file_kw >> chipType >> version;
+    FileKeyword_t fileKeyword;
+    ChipType_t chipType;
+    Version_t version;
+    stream >> fileKeyword >> chipType >> version;
 
-    // Check the file ID.
-    HEI_ASSERT(KW_CHIPDATA == file_kw);
+    // Check the file keyword.
+    HEI_ASSERT(KW_CHIPDATA == fileKeyword);
 
     // This chip type should not already exist.
     HEI_ASSERT(io_isoChips.end() == io_isoChips.find(chipType));
 
+    // So far there is only one supported version type so check it here.
+    HEI_ASSERT(VERSION_1 == version);
+
     // Allocate memory for the new isolation chip.
     auto isoChip = std::make_unique<IsolationChip>(chipType);
 
-    // TODO
+    // Read the register list metadata.
+    SectionKeyword_t regsKeyword;
+    RegisterId_t numRegs;
+    stream >> regsKeyword >> numRegs;
+
+    // Check the register keyword.
+    HEI_ASSERT(KW_REGS == regsKeyword);
+
+    // There must be at least one register defined.
+    HEI_ASSERT(0 != numRegs);
+
+    for (uint32_t i = 0; i < numRegs; i++)
+    {
+        __readRegister(stream, isoChip);
+    }
 
     // Add this isolation chip to the collective list of isolation chips.
     auto ret = io_isoChips.emplace(chipType, std::move(isoChip));
diff --git a/src/chip_data/hei_chip_data_stream.hpp b/src/chip_data/hei_chip_data_stream.hpp
index c9cbde7..122e425 100644
--- a/src/chip_data/hei_chip_data_stream.hpp
+++ b/src/chip_data/hei_chip_data_stream.hpp
@@ -126,4 +126,16 @@
     return *this;
 }
 
+/** @brief Template specialization for RegisterId_t. */
+template <>
+inline ChipDataStream& ChipDataStream::operator>>(RegisterId_t& o_right)
+{
+    // A register ID is only 3 bytes, but there isn't a 24-bit integer type. So
+    // extract 3 bytes to a uint32_t and drop the unused byte.
+    uint32_t tmp = 0;
+    read(&tmp, 3);
+    o_right = static_cast<RegisterId_t>(be32toh(tmp) >> 8);
+    return *this;
+}
+
 } // namespace libhei
diff --git a/src/hei_types.hpp b/src/hei_types.hpp
index 3f88a4d..e70edd4 100644
--- a/src/hei_types.hpp
+++ b/src/hei_types.hpp
@@ -81,7 +81,10 @@
  *   This is defined as a 3-byte field in the Chip Data Files, which should be
  *   sufficient to support all the registers on a typical chip.
  */
-using RegisterId_t = uint32_t; // IMPORTANT: see range note above.
+// IMPORTANT: typedef or using only creates an alias which is not a new type.
+// Need to defined this as an enum so that template specialization will detect a
+// new variable type. See note aboved for details.
+enum RegisterId_t : uint32_t;
 
 /**
  * A chip could contain more than one instance of a register or node. For
diff --git a/src/isolator/hei_isolation_chip.hpp b/src/isolator/hei_isolation_chip.hpp
index cb41353..b02d328 100644
--- a/src/isolator/hei_isolation_chip.hpp
+++ b/src/isolator/hei_isolation_chip.hpp
@@ -119,6 +119,9 @@
                                       Instance_t i_nodeInst) const;
 };
 
+/** Pointer management for isolation chips. */
+using IsolationChipPtr = std::unique_ptr<IsolationChip>;
+
 /** A simple map to ensure only one IsolationChip exists per chip type. */
 using IsolationChipMap =
     std::map<ChipType_t, const std::unique_ptr<const IsolationChip>>;