pdbg util to get chip/unit target from unit/chip

Signed-off-by: Zane Shelley <zshelle@us.ibm.com>
Change-Id: Ia5c72c5667b7f6eb1ecb02c044dca5208a211c70
diff --git a/util/pdbg.cpp b/util/pdbg.cpp
index a69d079..c798240 100644
--- a/util/pdbg.cpp
+++ b/util/pdbg.cpp
@@ -66,6 +66,15 @@
 
 //------------------------------------------------------------------------------
 
+uint8_t getUnitPos(pdbg_target* i_trgt)
+{
+    uint8_t attr = 0;
+    pdbg_target_get_attribute(i_trgt, "ATTR_CHIP_UNIT_POS", 1, 1, &attr);
+    return attr;
+}
+
+//------------------------------------------------------------------------------
+
 uint8_t getTrgtType(pdbg_target* i_trgt)
 {
     uint8_t attr = 0;
@@ -80,6 +89,112 @@
 
 //------------------------------------------------------------------------------
 
+pdbg_target* getParentChip(pdbg_target* i_unitTarget)
+{
+    assert(nullptr != i_unitTarget);
+
+    // Check if the given target is already a chip.
+    auto targetType = getTrgtType(i_unitTarget);
+    if (TYPE_PROC == targetType || TYPE_OCMB == targetType)
+    {
+        return i_unitTarget; // simply return the given target
+    }
+
+    // Check if this unit is on an OCMB.
+    pdbg_target* parentChip = pdbg_target_parent("ocmb", i_unitTarget);
+
+    // If not on the OCMB, check if this unit is on a PROC.
+    if (nullptr == parentChip)
+    {
+        parentChip = pdbg_target_parent("proc", i_unitTarget);
+    }
+
+    // There should always be a parent chip. Throw an error if not found.
+    if (nullptr == parentChip)
+    {
+        throw std::logic_error("No parent chip found: i_unitTarget=" +
+                               std::string{getPath(i_unitTarget)});
+    }
+
+    return parentChip;
+}
+
+//------------------------------------------------------------------------------
+
+pdbg_target* getChipUnit(pdbg_target* i_parentChip, TargetType_t i_unitType,
+                         uint8_t i_unitPos)
+{
+    assert(nullptr != i_parentChip);
+
+    auto parentType = getTrgtType(i_parentChip);
+
+    std::string devTreeType{};
+
+    if (TYPE_PROC == parentType)
+    {
+        // clang-format off
+        static const std::map<TargetType_t, std::string> m =
+        {
+            {TYPE_MC,     "mc"      },
+            {TYPE_MCC,    "mcc"     },
+            {TYPE_OMI,    "omi"     },
+            {TYPE_OMIC,   "omic"    },
+            {TYPE_PAUC,   "pauc"    },
+            {TYPE_PAU,    "pau"     },
+            {TYPE_NMMU,   "nmmu"    },
+            {TYPE_IOHS,   "iohs"    },
+            {TYPE_IOLINK, "smpgroup"},
+            {TYPE_EQ,     "eq"      },
+            {TYPE_CORE,   "core"    },
+            {TYPE_PEC,    "pec"     },
+            {TYPE_PHB,    "phb"     },
+            {TYPE_NX,     "nx"      },
+        };
+        // clang-format on
+
+        devTreeType = m.at(i_unitType);
+    }
+    else if (TYPE_OCMB == parentType)
+    {
+        // clang-format off
+        static const std::map<TargetType_t, std::string> m =
+        {
+            {TYPE_MEM_PORT, "mem_port"},
+        };
+        // clang-format on
+
+        devTreeType = m.at(i_unitType);
+    }
+    else
+    {
+        throw std::logic_error("Unexpected parent chip: " +
+                               std::string{getPath(i_parentChip)});
+    }
+
+    // Iterate all children of the parent and match the unit position.
+    pdbg_target* unitTarget = nullptr;
+    pdbg_for_each_target(devTreeType.c_str(), i_parentChip, unitTarget)
+    {
+        if (nullptr != unitTarget && i_unitPos == getUnitPos(unitTarget))
+        {
+            break; // found it
+        }
+    }
+
+    // Print a warning if the target unit is not found, but don't throw an
+    // error.  Instead let the calling code deal with the it.
+    if (nullptr == unitTarget)
+    {
+        trace::err("No unit target found: i_parentChip=%s i_unitType=0x%02x "
+                   "i_unitPos=%u",
+                   getPath(i_parentChip), i_unitType, i_unitPos);
+    }
+
+    return unitTarget;
+}
+
+//------------------------------------------------------------------------------
+
 pdbg_target* getConnectedTarget(pdbg_target* i_rxTarget,
                                 const callout::BusType& i_busType)
 {
diff --git a/util/pdbg.hpp b/util/pdbg.hpp
index 10a4694..e9cdad8 100644
--- a/util/pdbg.hpp
+++ b/util/pdbg.hpp
@@ -61,12 +61,23 @@
 /** @return The absolute position of the given chip. */
 uint32_t getChipPos(const libhei::Chip& i_chip);
 
+/** @return The unit position of a target within a chip. */
+uint8_t getUnitPos(pdbg_target* i_trgt);
+
 /** @return The target type of the given target. */
 uint8_t getTrgtType(pdbg_target* i_trgt);
 
 /** @return The target type of the given chip. */
 uint8_t getTrgtType(const libhei::Chip& i_chip);
 
+/** @return The parent chip target of the given unit target. */
+pdbg_target* getParentChip(pdbg_target* i_unitTarget);
+
+/** @return The unit target within chip of the given unit type and position
+ *          relative to the chip. */
+pdbg_target* getChipUnit(pdbg_target* i_parentChip, TargetType_t i_unitType,
+                         uint8_t i_unitPos);
+
 /**
  * @return The connected target on the other side of the given bus.
  * @param  i_rxTarget The target on the receiving side (RX) of the bus.