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>>;