diff mbox series

[v2,06/20] tests: Import P10 SCOM HWP for address translation tests

Message ID 20201001070814.102735-7-amitay@ozlabs.org
State New
Headers show
Series Add p10 support to libpdbg | expand

Commit Message

Amitay Isaacs Oct. 1, 2020, 7:08 a.m. UTC
Signed-off-by: Amitay Isaacs <amitay@ozlabs.org>
---
 src/tests/p10_cu.H        | 102 +++++
 src/tests/p10_scom_addr.C | 916 ++++++++++++++++++++++++++++++++++++++
 src/tests/p10_scom_addr.H | 700 +++++++++++++++++++++++++++++
 src/tests/p10_scominfo.C  | 838 ++++++++++++++++++++++++++++++++++
 src/tests/p10_scominfo.H  |  89 ++++
 5 files changed, 2645 insertions(+)
 create mode 100644 src/tests/p10_cu.H
 create mode 100644 src/tests/p10_scom_addr.C
 create mode 100644 src/tests/p10_scom_addr.H
 create mode 100644 src/tests/p10_scominfo.C
 create mode 100644 src/tests/p10_scominfo.H

Comments

Joel Stanley Oct. 7, 2020, 11:45 a.m. UTC | #1
On Thu, 1 Oct 2020 at 07:11, Amitay Isaacs <amitay@ozlabs.org> wrote:
>
> Signed-off-by: Amitay Isaacs <amitay@ozlabs.org>
> ---
>  src/tests/p10_cu.H        | 102 +++++
>  src/tests/p10_scom_addr.C | 916 ++++++++++++++++++++++++++++++++++++++
>  src/tests/p10_scom_addr.H | 700 +++++++++++++++++++++++++++++
>  src/tests/p10_scominfo.C  | 838 ++++++++++++++++++++++++++++++++++
>  src/tests/p10_scominfo.H  |  89 ++++
>  5 files changed, 2645 insertions(+)
>  create mode 100644 src/tests/p10_cu.H
>  create mode 100644 src/tests/p10_scom_addr.C
>  create mode 100644 src/tests/p10_scom_addr.H
>  create mode 100644 src/tests/p10_scominfo.C
>  create mode 100644 src/tests/p10_scominfo.H
>

Good to see the confidential notices are gone. I noticed they don't
contain licence info any more either, is this ok?

Reviewed-by: Joel Stanley <joel@jms.id.au>

Cheers,

Joel
Amitay Isaacs Oct. 8, 2020, 7:38 a.m. UTC | #2
On Wed, 2020-10-07 at 11:45 +0000, Joel Stanley wrote:
> On Thu, 1 Oct 2020 at 07:11, Amitay Isaacs <amitay@ozlabs.org> wrote:
> > Signed-off-by: Amitay Isaacs <amitay@ozlabs.org>
> > ---
> >  src/tests/p10_cu.H        | 102 +++++
> >  src/tests/p10_scom_addr.C | 916
> > ++++++++++++++++++++++++++++++++++++++
> >  src/tests/p10_scom_addr.H | 700 +++++++++++++++++++++++++++++
> >  src/tests/p10_scominfo.C  | 838 ++++++++++++++++++++++++++++++++++
> >  src/tests/p10_scominfo.H  |  89 ++++
> >  5 files changed, 2645 insertions(+)
> >  create mode 100644 src/tests/p10_cu.H
> >  create mode 100644 src/tests/p10_scom_addr.C
> >  create mode 100644 src/tests/p10_scom_addr.H
> >  create mode 100644 src/tests/p10_scominfo.C
> >  create mode 100644 src/tests/p10_scominfo.H
> > 
> 
> Good to see the confidential notices are gone. I noticed they don't
> contain licence info any more either, is this ok?

Hmm... that's not good.  I will include the standard license blob.

> 
> Reviewed-by: Joel Stanley <joel@jms.id.au>
> 
> Cheers,
> 
> Joel

Amitay.
diff mbox series

Patch

diff --git a/src/tests/p10_cu.H b/src/tests/p10_cu.H
new file mode 100644
index 0000000..3577f41
--- /dev/null
+++ b/src/tests/p10_cu.H
@@ -0,0 +1,102 @@ 
+///
+/// @file p10_cu.H
+/// @brief P10 chip unit definitions
+///
+/// HWP Owner: thi@us.ibm.com
+/// HWP Team: NEST
+/// HWP Level: 1
+/// HWP Consumed by: FSP/HB
+///
+
+#ifndef P10_CU_H
+#define P10_CU_H
+
+// includes
+#include <stdint.h>
+
+extern "C"
+{
+
+    /// P10 chip unit type enumeration
+    typedef enum
+    {
+        P10_NO_CU           =  0,           ///< P10 chip
+        PU_PERV_CHIPUNIT    =  1,           ///< Pervasive
+        PU_EQ_CHIPUNIT      =  2,           ///< Quad
+        PU_C_CHIPUNIT       =  3,           ///< Core
+        PU_PEC_CHIPUNIT     =  4,           ///< PCIe (PEC)
+        PU_PHB_CHIPUNIT     =  5,           ///< PCIe (PHB)
+        PU_NMMU_CHIPUNIT    =  6,           ///< NMMU
+        PU_IOHS_CHIPUNIT    =  7,           ///< IOHS (High speed IO)
+        PU_MC_CHIPUNIT      =  8,           ///< MC
+        PU_MI_CHIPUNIT      =  9,           ///< MI
+        PU_MCC_CHIPUNIT     = 10,           ///< MCC
+        PU_OMI_CHIPUNIT     = 11,           ///< OMI
+        PU_OMIC_CHIPUNIT    = 12,           ///< OMIC
+        PU_PAU_CHIPUNIT     = 13,           ///< PAU
+        PU_PAUC_CHIPUNIT    = 14,           ///< PAUC
+        NONE                = 0xFF,         ///< None/Invalid
+    } p10ChipUnits_t;
+
+    /// P10 chip unit pairing struct
+    struct p10_chipUnitPairing_t
+    {
+        /// @brief Default constructor
+        p10_chipUnitPairing_t()
+            : chipUnitType(NONE), chipUnitNum(0) {}
+        /// @brief Construct from type/instance number
+        p10_chipUnitPairing_t (p10ChipUnits_t type, uint32_t num)
+            : chipUnitType(type), chipUnitNum(num) {}
+
+        p10ChipUnits_t chipUnitType;  ///< chip unit type
+        uint32_t chipUnitNum;         ///< chip unit instance number
+    };
+
+    struct p10_chipUnitDescription_t
+    {
+        const char*          strVal;          // Chip unit string
+        const p10ChipUnits_t enumVal;         // Chip unit enum value
+        const uint8_t        maxChipUnitNum;  // Max Chip unit num value
+    };
+
+
+    // Max chip unit positions
+    const uint8_t MAX_PU_CHIPUNIT_NUM      =  0;  // P10_NO_CU
+    const uint8_t MAX_PU_EQ_CHIPUNIT_NUM   =  7;
+    const uint8_t MAX_PU_C_CHIPUNIT_NUM    = 31;
+    const uint8_t MAX_PU_PEC_CHIPUNIT_NUM  =  1;
+    const uint8_t MAX_PU_PHB_CHIPUNIT_NUM  =  5;
+    const uint8_t MAX_PU_NMMU_CHIPUNIT_NUM =  1;
+    const uint8_t MAX_PU_PERV_CHIPUNIT_NUM = 39; // Special case, with gaps
+    const uint8_t MAX_PU_IOHS_CHIPUNIT_NUM =  7;
+    const uint8_t MAX_PU_PAU_CHIPUNIT_NUM  =  7;
+    const uint8_t MAX_PU_MC_CHIPUNIT_NUM   =  3;
+    const uint8_t MAX_PU_MI_CHIPUNIT_NUM   =  3;
+    const uint8_t MAX_PU_MCC_CHIPUNIT_NUM  =  7;
+    const uint8_t MAX_PU_OMIC_CHIPUNIT_NUM =  7;
+    const uint8_t MAX_PU_OMI_CHIPUNIT_NUM  = 15;
+    const uint8_t MAX_PU_PAUC_CHIPUNIT_NUM =  3;
+
+    // Chip unit string/enum/max targes table
+    const p10_chipUnitDescription_t ChipUnitDescriptionTable[] =
+    {
+        { "pu"    , P10_NO_CU,         MAX_PU_CHIPUNIT_NUM       },
+        { "eq"    , PU_EQ_CHIPUNIT,    MAX_PU_EQ_CHIPUNIT_NUM    },
+        { "c"     , PU_C_CHIPUNIT,     MAX_PU_C_CHIPUNIT_NUM     },
+        { "pec"   , PU_PEC_CHIPUNIT,   MAX_PU_PEC_CHIPUNIT_NUM   },
+        { "phb"   , PU_PHB_CHIPUNIT,   MAX_PU_PHB_CHIPUNIT_NUM   },
+        { "nmmu"  , PU_NMMU_CHIPUNIT,  MAX_PU_NMMU_CHIPUNIT_NUM  },
+        { "perv"  , PU_PERV_CHIPUNIT,  MAX_PU_PERV_CHIPUNIT_NUM  },  // Special case, with gaps
+        { "iohs"  , PU_IOHS_CHIPUNIT,  MAX_PU_IOHS_CHIPUNIT_NUM  },
+        { "mc"    , PU_MC_CHIPUNIT,    MAX_PU_MC_CHIPUNIT_NUM    },
+        { "mi"    , PU_MI_CHIPUNIT,    MAX_PU_MI_CHIPUNIT_NUM    },
+        { "mcc"   , PU_MCC_CHIPUNIT,   MAX_PU_MCC_CHIPUNIT_NUM   },
+        { "omi"   , PU_OMI_CHIPUNIT,   MAX_PU_OMI_CHIPUNIT_NUM   },
+        { "omic"  , PU_OMIC_CHIPUNIT,  MAX_PU_OMIC_CHIPUNIT_NUM  },
+        { "pau"   , PU_PAU_CHIPUNIT,   MAX_PU_PAU_CHIPUNIT_NUM   },
+        { "pauc"  , PU_PAUC_CHIPUNIT,  MAX_PU_PAUC_CHIPUNIT_NUM  },
+    };
+
+} // extern "C"
+
+#endif /* P10_CU_H */
diff --git a/src/tests/p10_scom_addr.C b/src/tests/p10_scom_addr.C
new file mode 100644
index 0000000..507c5a0
--- /dev/null
+++ b/src/tests/p10_scom_addr.C
@@ -0,0 +1,916 @@ 
+///
+/// @file p10_scom_addr.C
+/// @brief P10 chip unit SCOM address platform translation code
+///
+/// HWP HW Maintainer: Thi Tran <thi@us.ibm.com>
+/// HWP FW Maintainer:
+/// HWP Consumed by: Cronus, HB, HWSV
+///
+
+// includes
+#include "p10_scom_addr.H"
+
+#define P10_SCOM_ADDR_C
+
+extern "C"
+{
+    /// See function description in header file
+
+    // #####################################
+    bool p10_scom_addr::isEqTarget()
+    {
+        bool l_eqTarget = false;
+
+        // Must have EQ chiplet ID
+        if ( (getChipletId() >= EQ0_CHIPLET_ID) &&
+             (getChipletId() <= EQ7_CHIPLET_ID) )
+        {
+            // If endpoint is QME (0xE):
+            // QME per core (bit 20) must be 0
+            // region select (bits 16:19) must be 0
+            if ( (getEndpoint() == QME_ENDPOINT) && (!getQMEPerCore()) &&
+                 (getRegionSelect() == EQ_REGION_SEL) )
+            {
+                l_eqTarget = true;
+            }
+            // associate perv target resources with EQ
+            else if (isPervTarget())
+            {
+                l_eqTarget = true;
+            }
+        }
+
+        return l_eqTarget;
+    }
+
+    // ########################################
+    uint8_t p10_scom_addr::getEqTargetInstance()
+    {
+        uint8_t l_instance = 0;
+        l_instance = (getChipletId() - EQ0_CHIPLET_ID);
+        return l_instance;
+    }
+
+    // #####################################
+    bool p10_scom_addr::isCoreTarget()
+    {
+        bool l_coreTarget = false;
+
+        // Must have EQ chiplet ID
+        if ( (getChipletId() >= EQ0_CHIPLET_ID) &&
+             (getChipletId() <= EQ7_CHIPLET_ID) )
+        {
+            // Region select must be...
+            if ( (getRegionSelect() == MULTI_HOT_SELECT_C0) ||  // 0x8
+                 (getRegionSelect() == MULTI_HOT_SELECT_C1) ||  // 0x4
+                 (getRegionSelect() == MULTI_HOT_SELECT_C2) ||  // 0x2
+                 (getRegionSelect() == MULTI_HOT_SELECT_C3) ||  // 0x1
+                 (getRegionSelect() == EQ_REGION_SEL) )         // 0x0
+            {
+                // If QME endpoint (0xE), QME per core (bit 20) must be 1
+                if ( (getEndpoint() == QME_ENDPOINT) && getQMEPerCore() )
+                {
+                    l_coreTarget = true;
+                }
+                // or must be PSCOM endpoints -- ensure that ring ID is
+                // associated with a core resource on the first PSCOM
+                // endpoint (0x1), all are core rings on the second
+                // PSCOM endpoint (0x2)
+                else if ( ((getEndpoint() == PSCOM_ENDPOINT) &&   // 0x1
+                           ((getEQRingId() != PERV_RING_ID) &&    // 0x1
+                            (getEQRingId() != QME_RING_ID))) ||   // 0x2
+                          (getEndpoint() == PSCOM_2_ENDPOINT) )   // 0x2
+                {
+                    l_coreTarget = true;
+                }
+            }
+        }
+
+        return l_coreTarget;
+    }
+
+    // #####################################
+    uint8_t p10_scom_addr::getCoreTargetInstance()
+    {
+        uint8_t l_instance = 0;
+
+        // First core instance of the quad
+        l_instance = (getChipletId() - EQ0_CHIPLET_ID) * NUM_CORES_PER_EQ;
+
+        // Get core instance based on region select
+        if (getRegionSelect() == MULTI_HOT_SELECT_C3)
+        {
+            l_instance += 3;
+        }
+        else if (getRegionSelect() == MULTI_HOT_SELECT_C2)
+        {
+            l_instance += 2;
+        }
+        else if (getRegionSelect() == MULTI_HOT_SELECT_C1)
+        {
+            l_instance += 1;
+        }
+
+        return l_instance;
+    }
+
+    // #####################################
+    bool p10_scom_addr::isPecTarget()
+    {
+        bool l_pecTarget = false;
+
+        // associate perv target resources with PCIE
+        if ( (getChipletId() >= PCI0_CHIPLET_ID) &&      // 0x8
+             (getChipletId() <= PCI1_CHIPLET_ID) )       // 0x9
+        {
+            l_pecTarget = isPervTarget();
+        }
+
+        // Endpoint must be PSCOM (0x1)
+        if (getEndpoint() == PSCOM_ENDPOINT)  // 0x1
+        {
+            // For PEC addresses via NEST regions:
+            // Ring ID must be 0x6, sat ID must be 0
+            if ( (getChipletId() >= N0_CHIPLET_ID) &&  // 0x2
+                 (getChipletId() <= N1_CHIPLET_ID) &&  // 0x3
+                 (getRingId() == N0_PE1_RING_ID) &&    // 0x6
+                 (getSatId() == PEC_SAT_ID) )          // 0x0
+
+            {
+                l_pecTarget = true;
+            }
+            // For PEC addresses via PCIE:
+            else if ( (getChipletId() >= PCI0_CHIPLET_ID) &&  // 0x8
+                      (getChipletId() <= PCI1_CHIPLET_ID) )   // 0x9
+            {
+                // Ring IDs must be 0x4-0x5 (iopci rings) or
+                // Ring ID is 0x2 (pci ring) and sat Id = 0x0
+                if ( (getRingId() == IO_PCI0_RING_ID) ||   // 0x4
+                     (getRingId() == IO_PCI1_RING_ID) ||   // 0x5
+                     ((getRingId() == PCI_RING_ID) &&      // 0x2
+                      (getSatId() == PEC_SAT_ID)) )        // 0x0
+                {
+                    l_pecTarget = true;
+                }
+            }
+        }
+
+        return l_pecTarget;
+    }
+
+    // #####################################
+    uint8_t p10_scom_addr::getPecTargetInstance()
+    {
+        uint8_t l_instance = 0;
+
+        // PEC addresses via NEST regions
+        l_instance = N1_CHIPLET_ID - getChipletId();
+
+        // PEC addresses via PCIE
+        if ( (getChipletId() == PCI0_CHIPLET_ID) ||
+             (getChipletId() == PCI1_CHIPLET_ID) )
+        {
+            l_instance = getChipletId() - PCI0_CHIPLET_ID;
+        }
+
+        return l_instance;
+    }
+
+    // #####################################
+    bool p10_scom_addr::isPhbTarget()
+    {
+        bool l_phbTarget = false;
+
+        // Endpoint must be PSCOM (0x1)
+        if ( (getEndpoint() == PSCOM_ENDPOINT) )  // 0x1
+        {
+            // PCIE chiplet ID
+            if ( (getChipletId() >= PCI0_CHIPLET_ID) && // 0x8
+                 (getChipletId() <= PCI1_CHIPLET_ID) )  // 0x9
+            {
+                // Ring ID of 0x2, Sat ID 1-6
+                if ( (getRingId() == PCI_RING_ID) && // 0x2
+                     (getSatId() >= PHB0_AIB_SAT_ID) &&  // 0x1
+                     (getSatId() <= PHB2_PHB_SAT_ID) )   // 0x6
+                {
+                    l_phbTarget = true;
+                }
+            }
+
+            // N0/N1 chiplet ID
+            if ( (getChipletId() >= N0_CHIPLET_ID) &&  // 0x2
+                 (getChipletId() <= N1_CHIPLET_ID) &&  // 0x3
+                 (getRingId() == N0_PE1_RING_ID)  &&   // 0x6
+                 (getSatId() >= PHB0_AIB_SAT_ID) &&    // 0x1
+                 (getSatId() <= PHB2_AIB_SAT_ID) )     // 0x3
+            {
+                l_phbTarget = true;
+            }
+        }
+
+        return l_phbTarget;
+    }
+
+    // #####################################
+    uint8_t p10_scom_addr::getPhbTargetInstance()
+    {
+        uint8_t l_instance = 0;
+
+        if ( (getChipletId() == N0_CHIPLET_ID) ||
+             (getChipletId() == PCI1_CHIPLET_ID) )
+        {
+            l_instance += 3;
+        }
+
+        if ( (getRingId() == N0_PE1_RING_ID) )
+        {
+            l_instance += (getSatId() - 1);
+        }
+        else if ( (getRingId() == PCI_RING_ID ) )
+        {
+            l_instance += ((getSatId() - 1) % 3);
+        }
+        else
+        {
+            l_instance += (getRingId() - 3);
+        }
+
+        return l_instance;
+    }
+
+    // #####################################
+    bool p10_scom_addr::isNmmuTarget()
+    {
+        bool l_nmmuTarget = false;
+
+        // Must have NEST chiplet ID
+        if ( (getChipletId() == N0_CHIPLET_ID) ||
+             (getChipletId() == N1_CHIPLET_ID) )
+        {
+            // Endpoint must be PSCOM, ring ID must be 0x3, Sat ID must be 0/1
+            if ( (getEndpoint() == PSCOM_ENDPOINT) &&    // 0x1
+                 (getRingId() == N0_MM0_RING_ID)  &&     // 0x3
+                 (getSatId() >= NMMU_SAT_ID0) &&         // 0x0
+                 (getSatId() <= NMMU_SAT_ID1) )          // 0x1
+            {
+                l_nmmuTarget = true;
+            }
+        }
+
+        return l_nmmuTarget;
+    }
+
+    // #####################################
+    uint8_t p10_scom_addr::getNmmuTargetInstance()
+    {
+        return (getChipletId() - N0_CHIPLET_ID);
+    }
+
+    // #####################################
+    bool p10_scom_addr::isPervTarget()
+    {
+        bool l_pervTarget = false;
+        uint8_t l_index = 0;
+
+        // Check chiplet ID by looping through PERV chiplet ID table
+        for (l_index = 0;
+             l_index < sizeof(PervTargetChipletIdTable) / sizeof(p10ChipletId_t);
+             l_index++)
+        {
+            // See if Chiplet ID is a perv chiplet ID from table
+            if (getChipletId() == PervTargetChipletIdTable[l_index])
+            {
+                if (getEndpoint() == PSCOM_ENDPOINT)            // 0x1
+                {
+                    // EQ specific PSCOM endpoint logic
+                    // ensure ring being accessed is EQ scoped (non-core)
+                    if ( (getChipletId() >= EQ0_CHIPLET_ID) &&
+                         (getChipletId() <= EQ7_CHIPLET_ID) )
+                    {
+                        if ( (getEQRingId() == PERV_RING_ID) || // 0x1
+                             (getEQRingId() == QME_RING_ID) )   // 0x2
+                        {
+                            l_pervTarget = true;
+                        }
+                    }
+
+                    // non-EQ chiplet, just match for ring ID = 0 / 1
+                    else
+                    {
+                        if ( (getRingId() == PSCOM_RING_ID) ||  // 0x0
+                             (getRingId() == PERV_RING_ID) )    // 0x1
+                        {
+                            l_pervTarget = true;
+                        }
+                    }
+                }
+                else if (getEndpoint() == CLOCK_CTRL_ENDPOINT)  // 0x3
+                {
+                    l_pervTarget = true;
+                }
+                // Check if Endpoint is a PERV endpoint
+                else if ( (getEndpoint() == CHIPLET_CTRL_ENDPOINT) ||     // 0x0
+                          (getEndpoint() == FIR_ENDPOINT)          ||     // 0x4
+                          (getEndpoint() == THERMAL_ENDPOINT)      ||     // 0x5
+                          (getEndpoint() == PCBSLV_ENDPOINT) )            // 0xF
+                {
+                    if ( getRingId() == PSCOM_RING_ID)                    // 0x0
+                    {
+                        l_pervTarget = true;
+                    }
+                }
+
+                break;
+            }
+        }
+
+        return l_pervTarget;
+    }
+
+    // #####################################
+    uint8_t p10_scom_addr::getPervTargetInstance()
+    {
+        return getChipletId();
+    }
+
+    // #####################################
+    bool p10_scom_addr::isIoHsTarget()
+    {
+        bool l_iohsTarget = false;
+
+        // IOHS can be targeted by AXON or PAU chiplets (indirect scom),
+
+        // Associate perv target resources with AXON
+        if ( (getChipletId() >= AXON0_CHIPLET_ID) &&       // 0x18
+             (getChipletId() <= AXON7_CHIPLET_ID) )        // 0x1F
+        {
+            l_iohsTarget = isPervTarget();
+
+            // If not a PERV target check for IOHS target that uses AXON chiplet
+            if (l_iohsTarget == false)
+            {
+                if ( (getEndpoint() == PSCOM_ENDPOINT)  &&
+                     (getRingId() == AXONE_PDL_RING_ID) &&  // 0x4
+                     (getSatId() == DLP_SAT_ID) )           // 0x0
+                {
+                    l_iohsTarget = true;
+                }
+            }
+        }
+
+        // Target via PAU chiplets
+        else if ( isIndirect()                        &&
+                  (getChipletId() >= PAU0_CHIPLET_ID) &&   // 0x10
+                  (getChipletId() <= PAU3_CHIPLET_ID) )   // 0x13
+        {
+            // Endpoint must be PSCOM and RingID is IOPPE
+            if ( (getEndpoint() == PSCOM_ENDPOINT) &&
+                 (getRingId() == PAU_IOPPE_RING_ID) )     // 0xB
+            {
+                // Group address (bits 22:26 of upper address) must be 0b00000 or 0b00001,
+                // and indirect register address should be per-group or per-lane
+                // Group 0: IOHS[0]
+                // Group 1: IOHS[1]
+                if ( ( (getIoGroupAddr() == 0x0) ||
+                       (getIoGroupAddr() == 0x1) ) &&
+                     ((getIoRegAddr() & 0x1E0) != 0x1E0) )
+                {
+                    l_iohsTarget = true;
+                }
+            }
+        }
+
+        return l_iohsTarget;
+    }
+
+    // #####################################
+    uint8_t p10_scom_addr::getIoHsTargetInstance()
+    {
+        uint8_t l_instance = 0;
+
+        // Chiplet ID is AXON
+        if ( (getChipletId() >= AXON0_CHIPLET_ID) &&
+             (getChipletId() <= AXON7_CHIPLET_ID) )
+        {
+            l_instance = getChipletId() - AXON0_CHIPLET_ID;
+        }
+        // Chiplet ID is PAU
+        else
+        {
+            // If chiplet ID is PAU then this is indirect address.
+            // Use PAU and Group address (bits 22:26) to calculate instance.
+            //   PAU0 (lower right) -> IOHS0 + IOHS1
+            //   PAU1 (upper right) -> IOHS2 + IOHS3
+            //   PAU2 (lower left)  -> IOHS4 + IOHS5
+            //   PAU3 (upper left)  -> IOHS6 + IOHS7
+            //
+            // Group address bits (22:26) of upper 32-bit
+            //   Group 0: IOHS[0]
+            //   Group 1: IOHS[1]
+            if ( (getChipletId() >= PAU0_CHIPLET_ID) &&      // 0x10
+                 (getChipletId() <= PAU3_CHIPLET_ID) )       // 0x13
+            {
+                l_instance = (getChipletId() - PAU0_CHIPLET_ID) * 2;
+
+                if (getIoGroupAddr() == 0x1)
+                {
+                    l_instance += 1;
+                }
+            }
+        }
+
+        return l_instance;
+    }
+
+    // #####################################
+    bool p10_scom_addr::isPauTarget()
+    {
+        bool l_pauTarget = false;
+
+        // Endpoint must be PSCOM
+        if ( getEndpoint() == PSCOM_ENDPOINT)
+        {
+            // Check chiplet ID
+            if ( (getChipletId() >= PAU0_CHIPLET_ID) &&
+                 (getChipletId() <= PAU3_CHIPLET_ID) )
+            {
+                if ( (getRingId() == PAU0346_0_RING_ID) || // 0x02
+                     (getRingId() == PAU0346_1_RING_ID) )  // 0x03
+
+                {
+                    l_pauTarget = true;
+                }
+                else if ( (getChipletId() == PAU2_CHIPLET_ID) ||
+                          (getChipletId() == PAU3_CHIPLET_ID) )
+                {
+                    if ( (getRingId() == PAU57_0_RING_ID) || // 0x04
+                         (getRingId() == PAU57_1_RING_ID) )  // 0x05
+                    {
+                        l_pauTarget = true;
+                    }
+                }
+            }
+        }
+
+        return l_pauTarget;
+    }
+
+    // #####################################
+    uint8_t p10_scom_addr::getPauTargetInstance()
+    {
+        uint8_t l_instance = 0;
+
+        if ( (getRingId() == PAU0346_0_RING_ID) || // 0x02
+             (getRingId() == PAU0346_1_RING_ID) )  // 0x03
+        {
+            if (getChipletId() == PAU0_CHIPLET_ID)
+            {
+                l_instance = 0;
+            }
+            else if (getChipletId() == PAU1_CHIPLET_ID)
+            {
+                l_instance = 3;
+            }
+            else if (getChipletId() == PAU2_CHIPLET_ID)
+            {
+                l_instance = 4;
+            }
+            else if (getChipletId() == PAU3_CHIPLET_ID)
+            {
+                l_instance = 6;
+            }
+        }
+
+        else if ( (getRingId() == PAU57_0_RING_ID) || // 0x04
+                  (getRingId() == PAU57_1_RING_ID) )  // 0x05
+        {
+            if (getChipletId() == PAU2_CHIPLET_ID)
+            {
+                l_instance = 5;
+            }
+            else if (getChipletId() == PAU3_CHIPLET_ID)
+            {
+                l_instance = 7;
+            }
+        }
+
+        return l_instance;
+    }
+
+    // #####################################
+    bool p10_scom_addr::isMcTarget()
+    {
+        // Same as MI
+        return isMiTarget();
+    }
+
+    // #####################################
+    uint8_t p10_scom_addr::getMcTargetInstance()
+    {
+        // Same as MI
+        return getMiTargetInstance();
+    }
+
+    // #####################################
+    bool p10_scom_addr::isMiTarget()
+    {
+        bool l_miTarget = false;
+
+        // Chiplet ID must belong to MCs
+        if ( (getChipletId() >= MC0_CHIPLET_ID)   &&    // 0x0C
+             (getChipletId() <= MC3_CHIPLET_ID) )       // 0x0F
+        {
+            // allow access to perv endpoints on MC chiplets
+            if (isPervTarget())
+            {
+                l_miTarget = true;
+            }
+            // Endpoint = PSCOM_ENDPOINT, and ringID = MC_0_RING_ID
+            else if ( (getEndpoint() == PSCOM_ENDPOINT) &&     // 0x1
+                      (getRingId() == MC_0_RING_ID) )          // 0x3
+            {
+                // PBI satellite
+                if (getSatId() == MC_SAT_ID0)  // 0x0 (PBI)
+                {
+                    // avoid match on MCC register space
+                    if (!(((getSatOffset() >= 0x22) &&
+                           (getSatOffset() <= 0x2B)) ||
+                          ((getSatOffset() >= 0x32) &&
+                           (getSatOffset() <= 0x3B))))
+                    {
+                        l_miTarget = true;
+                    }
+                }
+
+                // MCBIST satellite ID space
+                // avoid match on MCC register space in 0xD
+                if ( (getSatId() == MC_SAT_ID12) || // 0xC,0xE,0xF (MCBIST)
+                     (getSatId() == MC_SAT_ID14) ||
+                     (getSatId() == MC_SAT_ID15) )
+                {
+                    l_miTarget = true;
+                }
+            }
+        }
+
+        return l_miTarget;
+    }
+
+    // #####################################
+    uint8_t p10_scom_addr::getMiTargetInstance()
+    {
+        return getChipletId() - MC0_CHIPLET_ID;
+    }
+
+    // #####################################
+    bool p10_scom_addr::isMccTarget()
+    {
+        bool l_mccTarget = false;
+
+        // Chiplet ID must belong to MCs, Endpoint = PSCOM_ENDPOINT,
+        // and ringID = MC_0_RING_ID
+        if ( (getChipletId() >= MC0_CHIPLET_ID) &&    // 0x0C
+             (getChipletId() <= MC3_CHIPLET_ID) &&    // 0x0F
+             (getEndpoint() == PSCOM_ENDPOINT) &&     // 0x1
+             (getRingId() == MC_0_RING_ID) )          // 0x3
+        {
+            // MCC Sat ID
+            if ( (getSatId() == MC_SAT_ID4) ||  // 0x4
+                 (getSatId() == MC_SAT_ID8) ||  // 0x8
+                 (getSatId() == MC_SAT_ID5) ||  // 0x5
+                 (getSatId() == MC_SAT_ID9) )   // 0x9
+            {
+                l_mccTarget = true;
+            }
+
+            // MCC register space in PBI
+            if (getSatId() == MC_SAT_ID0)
+            {
+                if (((getSatOffset() >= 0x22) &&
+                     (getSatOffset() <= 0x2B)) ||
+                    ((getSatOffset() >= 0x32) &&
+                     (getSatOffset() <= 0x3B)))
+                {
+                    l_mccTarget = true;
+                }
+            }
+
+            // MCC register space in MCBIST
+            if (getSatId() == MC_SAT_ID13)
+            {
+                l_mccTarget = true;
+            }
+        }
+
+        return l_mccTarget;
+    }
+
+    // #####################################
+    uint8_t p10_scom_addr::getMccTargetInstance()
+    {
+        uint8_t l_instance = (getChipletId() - MC0_CHIPLET_ID) * 2;
+
+        // MCC Sat ID
+        if ( (getSatId() == MC_SAT_ID5) ||  // 5
+             (getSatId() == MC_SAT_ID9) )   // 9
+        {
+            l_instance += 1;
+        }
+
+        // MCC register space in PBI
+        if ( getSatId() == MC_SAT_ID0 )     // 0
+        {
+            if ((getSatOffset() >= 0x32) &&
+                (getSatOffset() <= 0x3B))
+            {
+                l_instance += 1;
+            }
+        }
+
+        // MCC register space in MCBIST
+        if ( getSatId() == MC_SAT_ID13)    // 13
+        {
+            // MSB of SatOffset denotes channel
+            if (getSatOffset() >= 0x20)
+            {
+                l_instance += 1;
+            }
+        }
+
+        return l_instance;
+    }
+
+    // #####################################
+    bool p10_scom_addr::isOmiTarget()
+    {
+        bool l_omiTarget = false;
+
+        // PAU chiplet, IOPPE ringId (indirect scom)
+        if ( isIndirect()                          &&   // indirect
+             ( getChipletId() >= PAU0_CHIPLET_ID ) &&   // 0x10
+             ( getChipletId() <= PAU3_CHIPLET_ID ) &&   // 0x13
+             ( getEndpoint() == PSCOM_ENDPOINT )   &&   // 0x1
+             ( getRingId() == PAU_IOPPE_RING_ID)   &&   // 0xB
+             ( getSatId() == PPE_SAT_ID0) )             // 0x0
+        {
+            // Group address (bits 22:26 of upper address)
+            // must be 0b00010 or 0b00011 (for OMI)
+            if ( (getIoGroupAddr() == 0x2 ) ||
+                 (getIoGroupAddr() == 0x3 ) )
+            {
+                // Reg address must start with 0xxx (per lane)
+                uint32_t regAddr = getIoRegAddr();
+
+                if ( ( regAddr & 0x100 ) == 0x000 )
+                {
+                    l_omiTarget = true;
+                }
+            }
+        }
+
+        // MC chiplet direct SCOM
+        if ( ( getChipletId() >= MC0_CHIPLET_ID ) &&   // 0x0C
+             ( getChipletId() <= MC3_CHIPLET_ID ) &&   // 0x0F
+             ( getEndpoint() == PSCOM_ENDPOINT )  &&   // 0x1
+             ( getRingId() >= OMI0_RING_ID )      &&   // 0x5
+             ( getRingId() <= OMI1_RING_ID )      &&   // 0x6
+             ( getSatId()  == MC_SAT_ID0 ) )           // 0x0 (DL)
+        {
+            if (((getSatOffset() >= 16) &&             // 16:31 (subchannel 0)
+                 (getSatOffset() <= 47)) ||            // 32:47 (subchannel 1)
+                ((getSatOffset() >= 48) &&             // 48:51 (subchannel 0, pm regs)
+                 (getSatOffset() <= 51)) ||
+                ((getSatOffset() >= 56) &&             // 48:51 (subchannel 1, pm regs)
+                 (getSatOffset() <= 59)))
+            {
+                l_omiTarget = true;
+            }
+        }
+
+        return l_omiTarget;
+    }
+
+    // #####################################
+    uint8_t p10_scom_addr::getOmiTargetInstance()
+    {
+        uint8_t l_instance = 0;
+
+        // PAU chiplet indirect SCOM
+        if ( (getChipletId() >= PAU0_CHIPLET_ID) &&      // 0x10
+             (getChipletId() <= PAU3_CHIPLET_ID) )       // 0x13
+        {
+            // PAU0 --> OMI 0/1/2/3
+            // PAU1 --> OMI 8/9/10/11
+            // PAU2 --> OMI 4/5/6/7
+            // PAU3 --> OMI 12/13/14/15
+            // set basis based on direct chiplet ID
+            if (getChipletId() == PAU0_CHIPLET_ID)
+            {
+                l_instance = 0;
+            }
+            else if (getChipletId() == PAU1_CHIPLET_ID)
+            {
+                l_instance = 8;
+            }
+            else if (getChipletId() == PAU2_CHIPLET_ID)
+            {
+                l_instance = 4;
+            }
+            else
+            {
+                l_instance = 12;
+            }
+
+            // account for IO group address
+            if (getIoGroupAddr() == 0x3)
+            {
+                l_instance += 2;
+            }
+
+            // account for IO lane selection
+            if ( ( getIoLane() >= 8 ) &&
+                 ( getIoLane() <= 15) )
+            {
+                l_instance += 1;
+            }
+        }
+
+        // MC direct
+        if ( (getChipletId() >= MC0_CHIPLET_ID) &&
+             (getChipletId() <= MC3_CHIPLET_ID) )
+        {
+            // Instances 0, 4, 8, 12
+            l_instance = (getChipletId() - MC0_CHIPLET_ID) * 4;
+
+            // Instances 2, 6, 10, 14
+            if ( getRingId() == OMI1_RING_ID )     // 0x6
+            {
+                l_instance += 2;
+            }
+
+            // Instances 1, 3, 5, 7, 9, 11, 13, 15
+            if ( ((getSatOffset() >= 32) &&
+                  (getSatOffset() <= 47)) ||
+                 ((getSatOffset() >= 56) &&
+                  (getSatOffset() <= 59)) )
+            {
+                l_instance += 1;
+            }
+        }
+
+        return l_instance;
+    }
+
+    // #####################################
+    bool p10_scom_addr::isOmicTarget()
+    {
+        bool l_omicTarget = false;
+
+        // PAU chiplet, IOPPE ringId (indirect scom)
+        if ( isIndirect()                          &&   // indirect
+             ( getChipletId() >= PAU0_CHIPLET_ID ) &&   // 0x10
+             ( getChipletId() <= PAU3_CHIPLET_ID ) &&   // 0x13
+             ( getEndpoint() == PSCOM_ENDPOINT )   &&   // 0x1
+             ( getRingId() == PAU_IOPPE_RING_ID)   &&   // 0xB
+             ( getSatId() == PPE_SAT_ID0) )             // 0x0
+        {
+            // Group address (bits 22:26 of upper address)
+            // must be 0b00010 or 0b00011 (for OMI)
+            if ( (getIoGroupAddr() == 0x2 ) ||
+                 (getIoGroupAddr() == 0x3 ) )
+            {
+                // Reg address must start with 1xxx (per group),
+                // excluding 1111 (per bus)
+                uint32_t regAddr = getIoRegAddr();
+
+                if ( ( ( regAddr & 0x1E0 ) != 0x1E0 ) &&
+                     ( ( regAddr & 0x100 ) == 0x100 ) )
+                {
+                    l_omicTarget = true;
+                }
+            }
+        }
+
+        // MC chiplet direct SCOM
+        if ( ( getChipletId() >= MC0_CHIPLET_ID ) &&   // 0x0C
+             ( getChipletId() <= MC3_CHIPLET_ID ) &&   // 0x0F
+             ( getEndpoint() == PSCOM_ENDPOINT )  &&   // 0x1
+             ( getRingId() >= OMI0_RING_ID )      &&   // 0x5
+             ( getRingId() <= OMI1_RING_ID )      &&   // 0x6
+             ( getSatId()  == MC_SAT_ID0 )        &&   // 0x0 (DL)
+             ( getSatOffset() >= 0 )              &&   // shared regs 0-15
+             ( getSatOffset() <= 15 ) )
+        {
+            l_omicTarget = true;
+        }
+
+        return l_omicTarget;
+    }
+
+    // #####################################
+    uint8_t p10_scom_addr::getOmicTargetInstance()
+    {
+        uint8_t l_instance = 0;
+
+        // PAU indirect
+        if ( ( getChipletId() >= PAU0_CHIPLET_ID ) &&   // 0x10
+             ( getChipletId() <= PAU3_CHIPLET_ID ) )    // 0x13
+        {
+            // PAU0 --> OMIC 0/1
+            // PAU1 --> OMIC 4/5
+            // PAU2 --> OMIC 2/3
+            // PAU3 --> OMIC 6/7
+            if (getChipletId() == PAU0_CHIPLET_ID)
+            {
+                l_instance = 0;
+            }
+            else if (getChipletId() == PAU1_CHIPLET_ID)
+            {
+                l_instance = 4;
+            }
+            else if (getChipletId() == PAU2_CHIPLET_ID)
+            {
+                l_instance = 2;
+            }
+            else // PAU3_CHIPLET_ID
+            {
+                l_instance = 6;
+            }
+
+            if (getIoGroupAddr() == 0x3)
+            {
+                l_instance += 1;
+            }
+        }
+
+        // MC direct
+        if ( ( getChipletId() >= MC0_CHIPLET_ID ) &&   // 0x0C
+             ( getChipletId() <= MC3_CHIPLET_ID ) )    // 0x0F
+        {
+            l_instance = (getChipletId() - MC0_CHIPLET_ID) * 2;
+
+            if (getRingId() == 0x6)
+            {
+                l_instance += 1;
+            }
+        }
+
+        return l_instance;
+    }
+
+    // #####################################
+    bool p10_scom_addr::isPaucTarget()
+    {
+        bool l_paucTarget = false;
+
+        if ( (getChipletId() >= PAU0_CHIPLET_ID) &&    // 0x10
+             (getChipletId() <= PAU3_CHIPLET_ID) )     // 0x13
+        {
+            // allow access to perv endpoints on MC chiplets
+            if (isPervTarget())
+            {
+                l_paucTarget = true;
+            }
+            else if ( getEndpoint() == PSCOM_ENDPOINT )  // 0x1
+            {
+                // IO PPE access
+                if ( isDirect()                         && // direct
+                     (getRingId() == PAU_IOPPE_RING_ID) && // 0xB
+                     ( (getSatId() == PPE_SAT_ID0) ||      // 0x0
+                       (getSatId() == PPE_SAT_ID1) ) )     // 0x1
+                {
+                    l_paucTarget = true;
+                }
+
+                // TL access
+                if ( (getRingId() == PAU_TL_RING_ID) &&    // 0x6
+                     ( (getSatId() == TL_SAT_ID) ) )       // 0x0
+                {
+                    l_paucTarget = true;
+                }
+
+                // per-bus IO super wrapper registers
+                if ( isIndirect()                        && // indirect
+                     ((getIoRegAddr() & 0x1E0) == 0x1E0) && // register(0:3) = 0b1111
+                     (getRingId() == PAU_IOPPE_RING_ID)  && // 0xB
+                     (getSatId() == PPE_SAT_ID0) )          // 0x0
+                {
+                    l_paucTarget = true;
+                }
+            }
+        }
+
+        return l_paucTarget;
+    }
+
+    // #####################################
+    uint8_t p10_scom_addr::getPaucTargetInstance()
+    {
+        uint8_t l_instance = (getChipletId() - PAU0_CHIPLET_ID);
+
+        return l_instance;
+    }
+
+} // extern "C"
+
+#undef P10_SCOM_ADDR_C
diff --git a/src/tests/p10_scom_addr.H b/src/tests/p10_scom_addr.H
new file mode 100644
index 0000000..a764f2a
--- /dev/null
+++ b/src/tests/p10_scom_addr.H
@@ -0,0 +1,700 @@ 
+///
+/// @file p10_scom_addr.H
+/// @brief P10 SCOM address class
+///
+/// HWP HW Maintainer: Thi Tran <thi@us.ibm.com>
+/// HWP FW Maintainer:
+/// HWP Consumed by: Cronus, HB, HWSV
+///
+
+#ifndef P10_SCOM_ADDR_H
+#define P10_SCOM_ADDR_H
+
+// includes
+#include <stdint.h>
+
+extern "C"
+{
+    /// Constants
+    const uint32_t NUM_CORES_PER_EQ = 4;  // Num of cores in an EQ chiplet
+
+    /// P10 Chiplet ID enumeration
+    typedef enum
+    {
+        PIB_CHIPLET_ID   = 0x00,    ///< PIB chiplet (FSI)
+        PERV_CHIPLET_ID  = 0x01,    ///< TP chiplet
+
+        N0_CHIPLET_ID    = 0x02,    ///< Nest0 (North) chiplet
+        N1_CHIPLET_ID    = 0x03,    ///< Nest1 (South) chiplet
+
+        PCI0_CHIPLET_ID  = 0x08,    ///< PCIe0 chiplet
+        PCI1_CHIPLET_ID  = 0x09,    ///< PCIe1 chiplet
+
+        MC0_CHIPLET_ID   = 0x0C,    ///< MC0 chiplet
+        MC1_CHIPLET_ID   = 0x0D,    ///< MC1 chiplet
+        MC2_CHIPLET_ID   = 0x0E,    ///< MC2 chiplet
+        MC3_CHIPLET_ID   = 0x0F,    ///< MC3 chiplet
+
+        PAU0_CHIPLET_ID  = 0x10,    ///< PAU0 chiplet
+        PAU1_CHIPLET_ID  = 0x11,    ///< PAU1 chiplet
+        PAU2_CHIPLET_ID  = 0x12,    ///< PAU2 chiplet
+        PAU3_CHIPLET_ID  = 0x13,    ///< PAU3 chiplet
+
+        AXON0_CHIPLET_ID = 0x18,    ///< AXON0 chiplet (high speed io)
+        AXON1_CHIPLET_ID = 0x19,    ///< AXON1 chiplet (high speed io)
+        AXON2_CHIPLET_ID = 0x1A,    ///< AXON2 chiplet (high speed io)
+        AXON3_CHIPLET_ID = 0x1B,    ///< AXON3 chiplet (high speed io)
+        AXON4_CHIPLET_ID = 0x1C,    ///< AXON4 chiplet (high speed io)
+        AXON5_CHIPLET_ID = 0x1D,    ///< AXON5 chiplet (high speed io)
+        AXON6_CHIPLET_ID = 0x1E,    ///< AXON6 chiplet (high speed io)
+        AXON7_CHIPLET_ID = 0x1F,    ///< AXON7 chiplet (high speed io)
+
+        EQ0_CHIPLET_ID   = 0x20,    ///< Quad0 chiplet (super chiplet)
+        EQ1_CHIPLET_ID   = 0x21,    ///< Quad1 chiplet (super chiplet)
+        EQ2_CHIPLET_ID   = 0x22,    ///< Quad2 chiplet (super chiplet)
+        EQ3_CHIPLET_ID   = 0x23,    ///< Quad3 chiplet (super chiplet)
+        EQ4_CHIPLET_ID   = 0x24,    ///< Quad4 chiplet (super chiplet)
+        EQ5_CHIPLET_ID   = 0x25,    ///< Quad5 chiplet (super chiplet)
+        EQ6_CHIPLET_ID   = 0x26,    ///< Quad6 chiplet (super chiplet)
+        EQ7_CHIPLET_ID   = 0x27,    ///< Quad7 chiplet (super chiplet)
+    } p10ChipletId_t;
+
+    /// P10 SCOM Endpoint ID enumeration
+    typedef enum
+    {
+        CHIPLET_CTRL_ENDPOINT   = 0x0,    ///< Chiplet Control
+        PSCOM_ENDPOINT          = 0x1,    ///< EQ:PSCOM (L3), others: PSCOM
+        PSCOM_2_ENDPOINT        = 0x2,    ///< EQ:PSCOM (Core/L2), TP:ITR, Nest:TOD (Time Of Day)
+        CLOCK_CTRL_ENDPOINT     = 0x3,    ///< Clock controller
+        FIR_ENDPOINT            = 0x4,    ///< FIR
+        THERMAL_ENDPOINT        = 0x5,    ///< Thermal
+        DPLL_ENDPOINT           = 0x6,    ///< TP (only): DPLL
+        QME_ENDPOINT            = 0xE,    ///< EQ (only): QME
+        PCBSLV_ENDPOINT         = 0xF,    ///< PCB Slave registers
+    } p10EndpointID_t;
+
+    /// P10 region select (CoreId/One-hot)
+    typedef enum
+    {
+        EQ_REGION_SEL       = 0x0,
+        MULTI_HOT_SELECT_C0 = 0x8,
+        MULTI_HOT_SELECT_C1 = 0x4,
+        MULTI_HOT_SELECT_C2 = 0x2,
+        MULTI_HOT_SELECT_C3 = 0x1,
+    } p10RegionSelect_t;
+
+    /// *************************************
+    ///          Ring ID enums
+    /// *************************************
+
+    /// P10 N0 chiplet ring ID enumeration
+    typedef enum
+    {
+        N0_MM0_RING_ID  = 0x3,
+        N0_PE1_RING_ID   = 0x6,
+    } p10_N0_RingId_t;
+
+    /// P10 N1 chiplet ring ID enumeration
+    /// source: tpc_p10_n1_top.vhdl
+    typedef enum
+    {
+        N1_MM1_RING_ID  = 0x3,
+        N1_PE0_RING_ID  = 0x6,
+    } p10_N1_RingId_t;
+
+    /// P10 PCIe chiplet SCOM ring ID enumeration
+    typedef enum
+    {
+        PCI_RING_ID      = 0x2,
+        IO_PCI0_RING_ID  = 0x4,
+        IO_PCI1_RING_ID  = 0x5,
+    } p10_PCI_RingId_t;
+
+    /// P10 PERV chiplet and PSCOM ring ID enumeration
+    typedef enum
+    {
+        PSCOM_RING_ID = 0x0,
+        PERV_RING_ID  = 0x1,
+    } p10_PSCOM_PERV_RingId_t;
+
+    /// P10 AXONE chiplet ring ID enumeration
+    typedef enum
+    {
+        AXONE_PDL_RING_ID = 0x4,
+    } p10_AXONE_RingId_t;
+
+    /// P10 PAU chiplet ring ID enumeration
+    typedef enum
+    {
+        PAU0346_0_RING_ID = 0x2,
+        PAU0346_1_RING_ID = 0x3,
+        PAU57_0_RING_ID   = 0x4,
+        PAU57_1_RING_ID   = 0x5,
+        PAU_TL_RING_ID    = 0x6,
+        PAU_IOPPE_RING_ID = 0xB,
+    } p10_PAU_RingId_t;
+
+    /// P10 MC chiplet ring ID enumeration
+    typedef enum
+    {
+        MC_0_RING_ID = 0x3,
+        MC_1_RING_ID = 0x4,
+        OMI0_RING_ID = 0x5,
+        OMI1_RING_ID = 0x6,
+    } p10_MC_RingId_t;
+
+    /// P10 EQ chiplet ring ID enumeration
+    typedef enum
+    {
+        QME_RING_ID = 0x2,
+        L3_RING_ID = 0x3,
+    } p10_EQ_PSCOM_RingId_t;
+
+    typedef enum
+    {
+        L2_RING_ID = 0x0,
+        C_0_RING_ID = 0x2,
+        C_1_RING_ID = 0x3,
+        C_3_RING_ID = 0x5,
+    } p10_EQ_PSCOM2_RingId_t;
+
+    /// -----------------------
+    /// Satellite ID defintions
+    /// -----------------------
+    typedef enum
+    {
+        NMMU_SAT_ID0 = 0x0,
+        NMMU_SAT_ID1 = 0x1,
+    } p10_NMMU_SatId_t;
+
+    typedef enum
+    {
+        PEC_SAT_ID   = 0x0,
+        PHB0_AIB_SAT_ID = 0x1,
+        PHB1_AIB_SAT_ID = 0x2,
+        PHB2_AIB_SAT_ID = 0x3,
+        PHB0_PHB_SAT_ID = 0x4,
+        PHB1_PHB_SAT_ID = 0x5,
+        PHB2_PHB_SAT_ID = 0x6,
+    } p10_PCI_SatId_t;
+
+    typedef enum
+    {
+        MC_SAT_ID0  = 0x0,
+        MC_SAT_ID4  = 0x4,
+        MC_SAT_ID5  = 0x5,
+        MC_SAT_ID8  = 0x8,
+        MC_SAT_ID9  = 0x9,
+        MC_SAT_ID12 = 0xC,
+        MC_SAT_ID13 = 0xD,
+        MC_SAT_ID14 = 0xE,
+        MC_SAT_ID15 = 0xF,
+    } p10_MC_SatId_t;
+
+    typedef enum
+    {
+        PPE_SAT_ID0 = 0x0,
+        TL_SAT_ID   = 0x0,
+        PPE_SAT_ID1 = 0x1,
+    } p10_PAU_SatId_t;
+
+    typedef enum
+    {
+        DLP_SAT_ID = 0x0,
+    } p10_AXONE_SatId_t;
+
+    /// *************************************
+    ///          Perv target table
+    /// *************************************
+    const p10ChipletId_t PervTargetChipletIdTable[] =
+    {
+        PIB_CHIPLET_ID,
+        PERV_CHIPLET_ID,
+        N0_CHIPLET_ID,
+        N1_CHIPLET_ID,
+        PCI0_CHIPLET_ID,
+        PCI1_CHIPLET_ID,
+        MC0_CHIPLET_ID,
+        MC1_CHIPLET_ID,
+        MC2_CHIPLET_ID,
+        MC3_CHIPLET_ID,
+        PAU0_CHIPLET_ID,
+        PAU1_CHIPLET_ID,
+        PAU2_CHIPLET_ID,
+        PAU3_CHIPLET_ID,
+        AXON0_CHIPLET_ID,
+        AXON1_CHIPLET_ID,
+        AXON2_CHIPLET_ID,
+        AXON3_CHIPLET_ID,
+        AXON4_CHIPLET_ID,
+        AXON5_CHIPLET_ID,
+        AXON6_CHIPLET_ID,
+        AXON7_CHIPLET_ID,
+        EQ0_CHIPLET_ID,
+        EQ1_CHIPLET_ID,
+        EQ2_CHIPLET_ID,
+        EQ3_CHIPLET_ID,
+        EQ4_CHIPLET_ID,
+        EQ5_CHIPLET_ID,
+        EQ6_CHIPLET_ID,
+        EQ7_CHIPLET_ID,
+    };
+
+// ----------------------
+// For non-EQ chiplets
+// ----------------------
+//        8             7             6             5             4             3          2         1
+//
+//  |0 1 2 3| |4 5 6 7| |8 9 10 11| |12 13 14 15| |16 17 18 19| |20 21 22 23| |24 25 26 27| |28 29 30 31|
+//    {A}{     B     }               {     C   }   0  0  {      D    } {     E     } {        F        }
+//
+// A - Is multiCast if bit 1 = 0x1
+// B - Chiplet ID (6 bits) [2:7]
+// C - Endpoint ID (4 bits) [12:15]
+// D - Ring (4 bits) [18:21]
+// E - Sat ID (4 bits) [22:25]
+// F - Sat Offset (6 bits) [26:31]
+
+// ----------------------
+// For EQ/Core chiplets
+// ----------------------
+//        8             7             6             5             4             3          2         1
+//
+//  |0 1 2 3| |4 5 6 7| |8 9 10 11| |12 13 14 15| |16 17 18 19| |20 21 22 23| |24 25 26 27| |28 29 30 31|
+//    {A}{     B      }             {     C     }  {    D    }   E   F { G  }  {         H             }
+//
+// A - Is multiCast if bit 1 = 0x1
+// B - Chiplet ID (6 bits) [2:7]
+// C - Endpoint ID (4 bits) [12:15]
+// D - Region select (4 bits) [16:19]
+// E - QME per core (1 bit) [20]
+// F - QME Sat Enable (1 bit) [21]
+// G - QME Sat sel (2 bits) [22:23]
+// H - QME reg (8 bits) [24:31]
+
+    /// P10 SCOM address class
+    class p10_scom_addr
+    {
+        public:
+
+            /// @brief Construct a SCOM address object
+            /// @param[in] i_addr 64-bit raw SCOM address
+            p10_scom_addr(const uint64_t i_addr)
+                : iv_addr(i_addr)
+            {
+            }
+
+            /// @brief Set full/raw SCOM address
+            /// @param[in] i_addr 64-bit SCOM address
+            /// @retval none
+            inline void setAddr(const uint64_t i_addr)
+            {
+                iv_addr = i_addr;
+                return;
+            }
+
+            /// @brief Retrieve full/raw SCOM address
+            /// @retval uint64_t 64-bit SCOM address
+            inline uint64_t getAddr() const
+            {
+                return (iv_addr);
+            }
+
+            /// @brief Determine if SCOM address is direct-form (bit 0)
+            /// @retval bool True if SCOM address is direct-form, false otherwise
+            inline bool isDirect() const
+            {
+                return (((iv_addr >> 63) & 0x1) == 0x0);
+            }
+
+            /// @brief Determine if SCOM address is indirect-form
+            /// @retval bool True if SCOM address is indirect-form, false otherwise
+            inline bool isIndirect() const
+            {
+                return (!isDirect());
+            }
+
+            /// @brief Determine if SCOM address is multicast (bit 1)
+            /// @retval bool True if SCOM address is multicast, false otherwise
+            inline bool isMulticast() const
+            {
+                return (((iv_addr >> 30) & 0x1) == 0x1);
+            }
+
+            /// @brief Determine if SCOM address is unicast
+            /// @retval bool True if SCOM address is unicast, false otherwise
+            inline bool isUnicast() const
+            {
+                return (!(isMulticast()));
+            }
+
+            /// @brief Extract pervasive chiplet ID from SCOM address (bits 2:7)
+            /// @retval uint8_t Pervasive chiplet ID value
+            inline uint8_t getChipletId() const
+            {
+                return ((iv_addr >> 24) & 0x3F);
+            }
+
+            /// @brief Modify SCOM address, update pervasive chiplet ID
+            /// @param[in] i_chiplet_id Chiplet ID value to write
+            /// @retval none
+            inline void setChipletId(const uint8_t i_chiplet_id)
+            {
+                iv_addr &= 0xFFFFFFFFC0FFFFFFULL;
+                iv_addr |= ((i_chiplet_id & 0x3F) << 24);
+                return;
+            }
+
+            /// @brief Extract Endpoint field from SCOM address (bits 12:15)
+            /// @retval uint8_t Endpoint field value
+            inline uint8_t getEndpoint() const
+            {
+                return ((iv_addr >> 16) & 0xF);
+            }
+
+            /// @brief Modify the Endpoint field from SCOM address
+            /// @retval none
+            inline void setEndpoint(const uint8_t i_port)
+            {
+                iv_addr &= 0xFFFFFFFFFFF0FFFFULL;
+                iv_addr |= ((i_port & 0xF) << 16);
+                return;
+            }
+
+            /// @brief Extract region select field (core id) from SCOM address (bits 16:19)
+            /// @retval uint8_t Region select value
+            inline uint8_t getRegionSelect() const
+            {
+                return ((iv_addr >> 12) & 0xF);
+            }
+
+            /// @brief Modify the region select field (core id) from SCOM address
+            /// @retval none
+            inline void setRegionSelect(const uint8_t i_regionSelect)
+            {
+                iv_addr &= 0xFFFFFFFFFFFF0FFFULL;
+                iv_addr |= ((i_regionSelect & 0xF) << 12);
+                return;
+            }
+
+            /// @brief Extract ring field from SCOM address (bits 18:21)
+            /// @retval uint8_t Ring id value
+            inline uint8_t getRingId() const
+            {
+                return ((iv_addr >> 10) & 0xF);
+            }
+
+            /// @brief Extract EQ ring field from SCOM address (bits 20:22)
+            /// @retval uint8_t Ring id value
+            inline uint8_t getEQRingId() const
+            {
+                return ((iv_addr >> 9) & 0x7);
+            }
+
+            /// @brief Modify SCOM address, update ring field value
+            /// @param[in] i_ring Ring field value to write
+            /// @retval none
+            inline void setRingId(const uint8_t i_ring)
+            {
+                iv_addr &= 0xFFFFFFFFFFFF03FFULL;
+                iv_addr |= ((i_ring & 0x3F) << 10);
+                return;
+            }
+
+            /// @brief Extract satellite ID field from SCOM address (bits 22:25)
+            /// @retval uint8_t Satellite ID field value
+            inline uint8_t getSatId() const
+            {
+                return ((iv_addr >> 6) & 0xF);
+            }
+
+            /// @brief Extract EQ satellite ID field from SCOM address (bits 23:25)
+            /// @retval uint8_t Ring id value
+            inline uint8_t getEQSatId() const
+            {
+                return ((iv_addr >> 6) & 0x7);
+            }
+
+            /// @brief Modify SCOM address, update satellite ID field
+            /// @param[in] i_sat_id Satellite ID value to write
+            /// @retval none
+            inline void setSatId(const uint8_t i_satId)
+            {
+                iv_addr &= 0xFFFFFFFFFFFFFC3FULL;
+                iv_addr |= ((i_satId & 0xF) << 6);
+                return;
+            }
+
+            /// @brief Extract satellite register offset field from SCOM address (bits 26:31)
+            /// @retval uint8_t Satellite register offset field value
+            inline uint8_t getSatOffset() const
+            {
+                return (iv_addr & 0x3F);
+            }
+
+            /// @brief Modify SCOM address, update satellite offset field
+            /// @param[in] i_sat_offset Satellite offset value to write
+            /// @retval none
+            inline void setSatOffset(const uint8_t i_sat_offset)
+            {
+                iv_addr &= 0xFFFFFFFFFFFFFFC0ULL;
+                iv_addr |= (i_sat_offset & 0x3F);
+                return;
+            }
+
+            /// @brief Get the OBUS Super Wrapper Group address (bits 22:26) of
+            ///        an indirect scom address
+            /// @retval uint8_t Group address
+            inline uint8_t getIoGroupAddr() const
+            {
+                return ((iv_addr >> 37) & 0x1F);
+            }
+
+            /// @brief Set the OBUS Super Wrapper Group address (bits 22:26) of
+            ///        an indirect scom address
+            /// @param[in] i_group_addr Group address value to write
+            /// @retval none
+            inline void setIoGroupAddr(const uint8_t i_group_addr)
+            {
+                iv_addr &= 0xFFFFFC1FFFFFFFFFULL;
+                iv_addr |= ( ((uint64_t)i_group_addr & 0x1F) << 37 );
+                return;
+            }
+
+            /// @brief Get Super Wrapper Register address (bits 12:20)
+            ///        of an indirect scom address
+            /// @retval uint32_t Register address
+            inline uint32_t getIoRegAddr() const
+            {
+                return ((iv_addr >> 43) & 0x1FF);
+            }
+
+            /// @brief Get the OBUS Super Wrapper TX/RX bit (bit 21)
+            ///        of an indirect scom address
+            /// @retval uint8_t TX/RX bit
+            inline uint32_t getIoTxRxBit() const
+            {
+                return ((iv_addr >> 42) & 0x1);
+            }
+
+            /// @brief Get the OBUS Super Wrapper Lane (bits 27:31)
+            ///        of an indirect scom address
+            /// @retval uint8_t Lane
+            inline uint32_t getIoLane() const
+            {
+                return ((iv_addr >> 32) & 0x1F);
+            }
+
+            /// @brief Set the OBUS Super Wrapper Lane (bits 27:31)
+            ///        of an indirect scom address
+            /// @retval uint8_t Lane
+            inline void setIoLane(const uint8_t i_lane)
+            {
+                iv_addr &= 0xFFFFFFE0FFFFFFFFULL;
+                iv_addr |= ( ((uint64_t)i_lane & 0x1F) <<  32);
+            }
+
+            /// IOP indirect SCOMs
+            /// IOP0.top0.pma0 (PMA0) -> 0x8000xxxx0801113f
+            /// IOP0.top0.pma1 (PMA1) -> 0x8001xxxx0801113f
+            /// IOP0.top1.pma0 (PMA2) -> 0x8000xxxx0801153f
+            /// IOP0.top1.pma1 (PMA3) -> 0x8001xxxx0801153f
+            /// IOP1.top0.pma0 (PMA0) -> 0x8000xxxx0901113f
+            /// IOP1.top0.pma1 (PMA1) -> 0x8001xxxx0901113f
+            /// IOP1.top1.pma0 (PMA2) -> 0x8000xxxx0901153f
+            /// IOP1.top1.pma1 (PMA3) -> 0x8001xxxx0901153f
+
+            /// @brief Get PEC IOP Control Register value (bits 12:31) from
+            ///        an indirect scom address
+            /// @retval uint32_t CR register
+            inline uint32_t getIopIndCRreg() const
+            {
+                return ((iv_addr >> 32) & 0xFFFFF);
+            }
+
+            /// @brief Get IOP TOP value (bit 53) from an indirect scom address
+            /// @retval uint8_t Top value (0 or 1)
+            inline uint8_t getIopTop() const
+            {
+                return ((iv_addr >> 10) & 0x1);
+            }
+
+            /// @brief Get PMA value (bit 15) from an indirect scom address
+            /// @retval uint8_t Top value (0 or 1)
+            inline uint8_t getPMA() const
+            {
+                return ( ((iv_addr >> 48) & 0x1) + (getIopTop() * 2) );
+            }
+
+            /// @brief Determine if SCOM address is valid/well-formed
+            /// @retval bool True if SCOM address is valid, false otherwise
+            inline bool isValid() const
+            {
+                return true;
+            }
+
+            /// @brief Determine if this address belongs to EQ target type
+            /// @retval true or false.
+            bool isEqTarget();
+
+            /// @brief Determine the EQ instance for this address
+            /// Function prereq: Address must belong to EQ target type
+            /// @retval uint8_t EQ target instance
+            uint8_t getEqTargetInstance();
+
+            /// @brief  Determine if this address belongs to core target type
+            /// @retval true or false.
+            bool isCoreTarget();
+
+            /// @brief  Determine the core instance for this address.
+            /// Function prereq: Address must belong to core target type
+            /// @retval uint8_t Core target instance
+            uint8_t getCoreTargetInstance();
+
+            /// @brief Determine if this address belongs to PEC target type
+            /// @retval true or false.
+            bool isPecTarget();
+
+            /// @brief Determine the pec instance for this address
+            /// Function prereq: Address must belong to PEC target type
+            /// @retval uint8_t PEC target instance
+            uint8_t getPecTargetInstance();
+
+            /// @brief Determine if this address belongs to PHB target type
+            /// @retval true or false.
+            bool isPhbTarget();
+
+            /// @brief Determine the PHB instance for this address
+            /// Function prereq: Address must belong to PHB target type
+            /// @retval uint8_t PHB target instance
+            uint8_t getPhbTargetInstance();
+
+            /// @brief Determine if this address belongs to NMMU target type
+            /// @retval true or false.
+            bool isNmmuTarget();
+
+            /// @brief Determine the NMMU instance for this address
+            /// Function prereq: Address must belong to NMMU target type
+            /// @retval uint8_t NMMU target instance
+            uint8_t getNmmuTargetInstance();
+
+            /// @brief Get the QME Per Core value (bit 20, EQ/Core only)
+            /// Function prereq: Address must belong to EQ or Core target type
+            /// @retval uint8_t QME Per Core value
+            inline uint8_t getQMEPerCore()
+            {
+                return (iv_addr >> 11) & 0x1;
+            }
+
+            /// @brief Get the QME Sat Enable value (bit 21, EQ/Core only)
+            /// Function prereq: Address must belong to EQ or Core target type
+            /// @retval uint8_t QME Sat Enable value
+            inline uint8_t getQMESatEn()
+            {
+                return (iv_addr >> 10) & 0x1;
+            }
+
+            /// @brief Get the QME Sat Select value (bit 22:23, EQ/Core only)
+            /// Function prereq: Address must belong to EQ or Core target type
+            /// @retval uint8_t QME Sat Sel value
+            inline uint8_t getQMESatSel()
+            {
+                return (iv_addr >> 8) & 0x3;
+            }
+
+            /// @brief Get the QME reg value (bit 24:31, EQ/Core only)
+            /// Function prereq: Address must belong to EQ or Core target type
+            /// @retval uint8_t QME reg value
+            inline uint8_t getQMEReg()
+            {
+                return (iv_addr & 0xFF);
+            }
+
+            /// @brief Determine if this address belongs to PERV target type
+            /// @retval true or false.
+            bool isPervTarget();
+
+            /// @brief Determine the PERV instance for this address
+            /// Function prereq: Address must belong to PERV target type
+            /// @retval uint8_t PERV target instance.
+            uint8_t getPervTargetInstance();
+
+            /// @brief Determine if this address belongs to IOHS target type
+            /// @retval true or false.
+            bool isIoHsTarget();
+
+            /// @brief Determine the IOHS instance for this address
+            /// Function prereq: Address must belong to IOHS target type
+            /// @retval uint8_t IOHS target instance.
+            uint8_t getIoHsTargetInstance();
+
+            /// @brief Determine if this address belongs to PAU target type
+            /// @retval true or false.
+            bool isPauTarget();
+
+            /// @brief Determine the PAU instance for this address
+            /// Function prereq: Address must belong to PAU target type
+            /// @retval uint8_t PAU target instance.
+            uint8_t getPauTargetInstance();
+
+            /// @brief Determine if this address belongs to MC target type
+            /// @retval true or false.
+            bool isMcTarget();
+
+            /// @brief Determine the MC instance for this address
+            /// Function prereq: Address must belong to MI target type
+            /// @retval uint8_t MC target instance.
+            uint8_t getMcTargetInstance();
+
+            /// @brief Determine if this address belongs to MI target type
+            /// @retval true or false.
+            bool isMiTarget();
+
+            /// @brief Determine the MI instance for this address
+            /// Function prereq: Address must belong to MI target type
+            /// @retval uint8_t MI target instance.
+            uint8_t getMiTargetInstance();
+
+            /// @brief Determine if this address belongs to MCC target type
+            /// @retval true or false.
+            bool isMccTarget();
+
+            /// @brief Determine the MCC instance for this address
+            /// Function prereq: Address must belong to MCC target type
+            /// @retval uint8_t MCC target instance.
+            uint8_t getMccTargetInstance();
+
+            /// @brief Determine if this address belongs to OMI target type
+            /// @retval true or false.
+            bool isOmiTarget();
+
+            /// @brief Determine the OMI instance for this address
+            /// Function prereq: Address must belong to OMI target type
+            /// @retval uint8_t OMI target instance.
+            uint8_t getOmiTargetInstance();
+
+            /// @brief Determine if this address belongs to OMIC target type
+            /// @retval true or false.
+            bool isOmicTarget();
+
+            /// @brief Determine the OMIC instance for this address
+            /// Function prereq: Address must belong to OMIC target type
+            /// @retval uint8_t OMIC target instance.
+            uint8_t getOmicTargetInstance();
+
+            /// @brief Determine if this address belongs to PAUC target type
+            /// @retval true or false.
+            bool isPaucTarget();
+
+            /// @brief Determine the PAUC instance for this address
+            /// Function prereq: Address must belong to PAUC target type
+            /// @retval uint8_t PAUC target instance.
+            uint8_t getPaucTargetInstance();
+
+        private:
+            uint64_t iv_addr;   ///< 64-bit raw SCOM address
+    };
+
+} // extern "C"
+
+#endif /* P10_SCOM_ADDR_H */
diff --git a/src/tests/p10_scominfo.C b/src/tests/p10_scominfo.C
new file mode 100644
index 0000000..0294a50
--- /dev/null
+++ b/src/tests/p10_scominfo.C
@@ -0,0 +1,838 @@ 
+///
+/// @file p10_scominfo.C
+/// @brief P10 chip unit SCOM address platform translation code
+///
+/// HWP HW Maintainer: Thi Tran <thi@us.ibm.com>
+/// HWP FW Maintainer:
+/// HWP Consumed by: Cronus, HB, HWSV
+///
+
+// includes
+#include "p10_scominfo.H"
+#include "p10_scom_addr.H"
+
+#define P10_SCOMINFO_C
+
+extern "C"
+{
+
+    // ---------------------------
+    // Internal functions
+    // ---------------------------
+
+    //################################################################################
+    /// @brief Calculate the region select (core ID) value for given core
+    ///        instance
+    /// @param[in] i_coreInstance   Core instance number (0-31)
+    /// @retval uint8_t Region select value
+    uint8_t calcRegionSelect(uint8_t i_coreInstanceNum)
+    {
+        uint8_t l_regionSel = 0;
+
+        if (i_coreInstanceNum % NUM_CORES_PER_EQ == 0)
+        {
+            l_regionSel = 8;
+        }
+        else if (i_coreInstanceNum % NUM_CORES_PER_EQ == 1)
+        {
+            l_regionSel = 4;
+        }
+        else if (i_coreInstanceNum % NUM_CORES_PER_EQ == 2)
+        {
+            l_regionSel = 2;
+        }
+        else
+        {
+            l_regionSel = 1;
+        }
+
+        return l_regionSel;
+    }
+
+    //################################################################################
+    /// @brief Get the chiplet ID for a chip unit instance based on given
+    ///        address and chip unit type
+    /// @param[in]  i_addr          SCOM address
+    /// @param[in]  i_chipUnitNum   Instance number
+    /// @param[in]  i_chipUnitType  Chip unit type
+    /// @param[out] o_chipletId     Output chiplet id
+    /// @retval Non-zero if error
+    uint8_t getChipletId(const uint64_t i_addr,
+                         const uint8_t i_chipUnitNum,
+                         const p10ChipUnits_t i_chipUnitType,
+                         uint8_t& o_chipletId)
+    {
+        uint8_t l_rc = 0;
+
+        do
+        {
+            p10_scom_addr l_scom(i_addr);
+
+            switch (i_chipUnitType)
+            {
+                case PU_EQ_CHIPUNIT:
+                    o_chipletId = EQ0_CHIPLET_ID + i_chipUnitNum;
+                    break;
+
+                case PU_C_CHIPUNIT:
+                    o_chipletId = EQ0_CHIPLET_ID + (i_chipUnitNum / NUM_CORES_PER_EQ);
+                    break;
+
+                case PU_PEC_CHIPUNIT:
+
+                    // If input address is of Nest chiplets
+                    if ( (l_scom.getChipletId() >= N0_CHIPLET_ID) &&
+                         (l_scom.getChipletId() <= N1_CHIPLET_ID) )
+                    {
+                        o_chipletId = ((i_chipUnitNum) ? (N0_CHIPLET_ID) : (N1_CHIPLET_ID));
+                    }
+                    // If input address is of PCI chiplets
+                    else
+                    {
+                        o_chipletId = PCI0_CHIPLET_ID + i_chipUnitNum;
+                    }
+
+                    break;
+
+                case PU_PHB_CHIPUNIT:
+
+                    // If input address is of Nest chiplets
+                    if ( (l_scom.getChipletId() >= N0_CHIPLET_ID) &&
+                         (l_scom.getChipletId() <= N1_CHIPLET_ID) )
+                    {
+                        o_chipletId = ((i_chipUnitNum / 3) ? (N0_CHIPLET_ID) : (N1_CHIPLET_ID));
+                    }
+                    // If input address is of PCI chiplets
+                    else
+                    {
+                        o_chipletId = (i_chipUnitNum / 3) + PCI0_CHIPLET_ID;
+                    }
+
+                    break;
+
+                case PU_NMMU_CHIPUNIT:
+                    o_chipletId = i_chipUnitNum + N0_CHIPLET_ID;
+                    break;
+
+                case PU_PERV_CHIPUNIT:
+                    o_chipletId = i_chipUnitNum;
+                    break;
+
+                case PU_IOHS_CHIPUNIT:
+
+                    // If input address is of AXON chiplets
+                    if ( (l_scom.getChipletId() >= AXON0_CHIPLET_ID) &&      // 0x18
+                         (l_scom.getChipletId() <= AXON7_CHIPLET_ID) )       // 0x1F
+                    {
+                        o_chipletId = AXON0_CHIPLET_ID + i_chipUnitNum;
+                    }
+                    else if ( (l_scom.getChipletId() >= PAU0_CHIPLET_ID) &&
+                              (l_scom.getChipletId() <= PAU3_CHIPLET_ID) )
+                    {
+                        // PAU0 --> IOHS0, IOHS1
+                        // PAU1 --> IOHS2, IOHS3
+                        // PAU2 --> IOHS4, IOHS5
+                        // PAU3 --> IOHS6, IOHS7
+                        o_chipletId = (i_chipUnitNum / 2) + PAU0_CHIPLET_ID;
+                    }
+                    else
+                    {
+                        l_rc = 1;
+                    }
+
+                    break;
+
+                case PU_MI_CHIPUNIT:
+                case PU_MC_CHIPUNIT:
+                    o_chipletId = i_chipUnitNum + MC0_CHIPLET_ID;
+                    break;
+
+                case PU_MCC_CHIPUNIT:
+                    o_chipletId = (i_chipUnitNum / 2) + MC0_CHIPLET_ID;
+                    break;
+
+                case PU_OMIC_CHIPUNIT:
+
+                    // PAU indirect
+                    if ( (l_scom.getChipletId() >= PAU0_CHIPLET_ID) &&   // 0x10
+                         (l_scom.getChipletId() <= PAU3_CHIPLET_ID) )    // 0x13
+                    {
+                        // PAU0 --> OMIC 0/1
+                        // PAU1 --> OMIC 4/5
+                        // PAU2 --> OMIC 2/3
+                        // PAU3 --> OMIC 6/7
+                        if (i_chipUnitNum >= 0 && i_chipUnitNum <= 1)
+                        {
+                            o_chipletId = PAU0_CHIPLET_ID;
+                        }
+                        else if (i_chipUnitNum >= 2 && i_chipUnitNum <= 3)
+                        {
+                            o_chipletId = PAU2_CHIPLET_ID;
+                        }
+                        else if (i_chipUnitNum >= 4 && i_chipUnitNum <= 5)
+                        {
+                            o_chipletId = PAU1_CHIPLET_ID;
+                        }
+                        else if (i_chipUnitNum >= 6 && i_chipUnitNum <= 7)
+                        {
+                            o_chipletId = PAU3_CHIPLET_ID;
+                        }
+                        else
+                        {
+                            l_rc = 1;
+                        }
+                    }
+                    // MC direct
+                    else
+                    {
+                        o_chipletId = (i_chipUnitNum / 2) + MC0_CHIPLET_ID;
+                    }
+
+                    break;
+
+                case PU_OMI_CHIPUNIT:
+
+                    // PAU indirect
+                    if ( (l_scom.getChipletId() >= PAU0_CHIPLET_ID) &&   // 0x10
+                         (l_scom.getChipletId() <= PAU3_CHIPLET_ID) )    // 0x13
+                    {
+                        // PAU0 --> OMI 0/1/2/3
+                        // PAU1 --> OMI 8/9/10/11
+                        // PAU2 --> OMI 4/5/6/7
+                        // PAU3 --> OMI 12/13/14/15
+                        if (i_chipUnitNum >= 0 && i_chipUnitNum <= 3)
+                        {
+                            o_chipletId = PAU0_CHIPLET_ID;
+                        }
+                        else if (i_chipUnitNum >= 4 && i_chipUnitNum <= 7)
+                        {
+                            o_chipletId = PAU2_CHIPLET_ID;
+                        }
+                        else if (i_chipUnitNum >= 8 && i_chipUnitNum <= 11)
+                        {
+                            o_chipletId = PAU1_CHIPLET_ID;
+                        }
+                        else if (i_chipUnitNum >= 12 && i_chipUnitNum <= 15)
+                        {
+                            o_chipletId = PAU3_CHIPLET_ID;
+                        }
+                        else
+                        {
+                            l_rc = 1;
+                        }
+                    }
+                    // MC direct
+                    else
+                    {
+                        o_chipletId = (i_chipUnitNum / 4) + MC0_CHIPLET_ID;
+                    }
+
+                    break;
+
+                case PU_PAUC_CHIPUNIT:
+                    o_chipletId = i_chipUnitNum + PAU0_CHIPLET_ID;
+                    break;
+
+                case PU_PAU_CHIPUNIT:
+                    o_chipletId = (i_chipUnitNum / 2) + PAU0_CHIPLET_ID;
+                    break;
+
+                default:
+                    l_rc = 1;
+                    break;
+            };
+
+        }
+        while (0);
+
+        return (l_rc);
+    }
+
+    // See header file for function description
+    uint64_t p10_scominfo_createChipUnitScomAddr(
+        const p10ChipUnits_t i_p10CU,
+        const uint8_t i_ecLevel,
+        const uint8_t i_chipUnitNum,
+        const uint64_t i_scomAddr,
+        const uint32_t i_mode)
+    {
+        uint8_t l_rc = 0;
+        p10_scom_addr l_scom(i_scomAddr);
+        uint8_t l_chipletId = 0;
+
+        do
+        {
+            // Make sure i_chipUnitNum is within range
+            l_rc = validateChipUnitNum(i_chipUnitNum, i_p10CU);
+
+            if (l_rc)
+            {
+                break;
+            }
+
+            // If chip unit type is a chip, return input address
+            if (i_p10CU == P10_NO_CU)
+            {
+                l_scom.setAddr(i_scomAddr);
+                break;
+            }
+
+            // Set the chiplet ID
+            l_rc = getChipletId(i_scomAddr, i_chipUnitNum, i_p10CU, l_chipletId);
+
+            if (l_rc)
+            {
+                break;
+            }
+
+            l_scom.setChipletId(l_chipletId);
+
+            // Set other address fields (ringId, satId, etc...)
+            // for Chip unit types that are needed.
+            switch (i_p10CU)
+            {
+                case PU_C_CHIPUNIT:
+                    // Set the core's region select (core ID)
+                    l_scom.setRegionSelect(calcRegionSelect(i_chipUnitNum));
+                    break;
+
+                case PU_PHB_CHIPUNIT:
+
+                    // If input address is of Nest chiplets
+                    if ( (l_scom.getChipletId() >= N0_CHIPLET_ID) &&
+                         (l_scom.getChipletId() <= N1_CHIPLET_ID) )
+                    {
+                        l_scom.setSatId(1 + (i_chipUnitNum % 3));
+                    }
+                    // If input address is of PCI chiplets
+                    else
+                    {
+                        if (l_scom.getRingId() == 2)
+                        {
+                            if ((l_scom.getSatId() >= 1) &&
+                                (l_scom.getSatId() <= 3))
+                            {
+                                l_scom.setSatId(1 + (i_chipUnitNum % 3));
+                            }
+                            else
+                            {
+                                l_scom.setSatId(4 + (i_chipUnitNum % 3));
+                            }
+                        }
+                    }
+
+                    break;
+
+                case PU_MCC_CHIPUNIT:
+
+                    // Set Sat ID
+                    if (i_chipUnitNum % 2)
+                    {
+                        uint8_t l_offset = l_scom.getSatOffset();
+
+                        // MCC Sat ID
+                        // For odd MCC instance, Sat Id is to be set to 5, or 9
+                        // If input address is an even instance that has:
+                        //   SatId = 0x4 --> set translated SatId to 0x5
+                        //         = 0x8 --> set translated SatId to 0x9
+                        // If input address is an odd instance, leave the SatId
+                        // as input address.
+                        if (l_scom.getSatId() == 0x4)
+                        {
+                            l_scom.setSatId(0x5);
+                        }
+                        else if (l_scom.getSatId() == 0x8)
+                        {
+                            l_scom.setSatId(0x9);
+                        }
+                        // PBI Sat ID
+                        else if (l_scom.getSatId() == 0x0)
+                        {
+                            if ((l_offset >= 0x22) &&
+                                (l_offset <= 0x2B))
+                            {
+                                l_scom.setSatOffset(l_offset + 0x10);
+                            }
+                        }
+                        // MCBIST Sat ID
+                        else if (l_scom.getSatId() == 0xD)
+                        {
+                            if ((l_offset >= 0x00) &&
+                                (l_offset <= 0x1F))
+                            {
+                                l_scom.setSatOffset(l_offset + 0x20);
+                            }
+                        }
+                    }
+                    else
+                    {
+                        uint8_t l_offset = l_scom.getSatOffset();
+
+                        // For even MCC instance, Sat Id is to be set to 4, or 8
+                        // If input address is an odd instance that has:
+                        //   SatId = 0x5 --> set translated SatId to 0x4
+                        //         = 0x9 --> set translated SatId to 0x8
+                        // If input address is an even instance, leave the SatId
+                        // as input address.
+                        if (l_scom.getSatId() == 0x5)
+                        {
+                            l_scom.setSatId(0x4);
+                        }
+                        else if (l_scom.getSatId() == 0x9)
+                        {
+                            l_scom.setSatId(0x8);
+                        }
+                        // PBI Sat ID
+                        else if (l_scom.getSatId() == 0x0)
+                        {
+                            if ((l_offset >= 0x32) &&
+                                (l_offset <= 0x3B))
+                            {
+                                l_scom.setSatOffset(l_offset - 0x10);
+                            }
+                        }
+                        // MCBIST Sat ID
+                        else if (l_scom.getSatId() == 0xD)
+                        {
+                            if ((l_offset >= 0x20) &&
+                                (l_offset <= 0x3F))
+                            {
+                                l_scom.setSatOffset(l_offset - 0x20);
+                            }
+                        }
+                    }
+
+                    break;
+
+
+                case PU_IOHS_CHIPUNIT:
+
+                    // PAU indirect
+                    if ( (l_scom.getChipletId() >= PAU0_CHIPLET_ID) &&   // 0x10
+                         (l_scom.getChipletId() <= PAU3_CHIPLET_ID) )    // 0x13
+                    {
+                        // for odd IOHS instances, set IO group = 1
+                        if ( i_chipUnitNum % 2 )
+                        {
+                            l_scom.setIoGroupAddr(0x1);
+                        }
+                        // for even IOHS instances, set IO group = 0
+                        else
+                        {
+                            l_scom.setIoGroupAddr(0x0);
+                        }
+                    }
+
+                    break;
+
+                case PU_OMI_CHIPUNIT:
+
+                    // PAU indirect
+                    if ( (l_scom.getChipletId() >= PAU0_CHIPLET_ID) &&   // 0x10
+                         (l_scom.getChipletId() <= PAU3_CHIPLET_ID) )    // 0x13
+                    {
+                        // for odd OMI instances, set IO lane between 8-15
+                        if ( i_chipUnitNum % 2 )
+                        {
+                            l_scom.setIoLane(8 + (l_scom.getIoLane() % 8));
+                        }
+                        // for even OMI instances, set IO lane between 0-7
+                        else
+                        {
+                            l_scom.setIoLane(0 + (l_scom.getIoLane() % 8));
+                        }
+
+                        // for odd OMI instances after dividing by 2, set IO group = 3
+                        if ( (i_chipUnitNum / 2) % 2 )
+                        {
+                            l_scom.setIoGroupAddr(0x3);
+                        }
+                        // for even OMI instances after dividing by 2, set IO group = 2
+                        else
+                        {
+                            l_scom.setIoGroupAddr(0x2);
+                        }
+                    }
+                    // MC direct
+                    else
+                    {
+                        // non-PM regs
+                        if ((l_scom.getSatOffset() >= 16) && (l_scom.getSatOffset() <= 47))
+                        {
+                            // for odd OMI instances, set sat reg ID between 32-47
+                            if ( i_chipUnitNum % 2 )
+                            {
+                                l_scom.setSatOffset(32 + (l_scom.getSatOffset() % 16));
+                            }
+                            // for even OMI instances, set sat reg ID between 16-31
+                            else
+                            {
+                                l_scom.setSatOffset(16 + (l_scom.getSatOffset() % 16));
+                            }
+                        }
+                        // PM regs
+                        else
+                        {
+                            // for odd OMI instances, set sat reg ID between 56-59
+                            if ( i_chipUnitNum % 2 )
+                            {
+                                l_scom.setSatOffset(56 + (l_scom.getSatOffset() % 4));
+                            }
+                            // for even OMI instances, set sat reg ID between 48-51
+                            else
+                            {
+                                l_scom.setSatOffset(48 + (l_scom.getSatOffset() % 4));
+                            }
+
+                        }
+
+                        // for odd OMI instances after dividing by 2, set ring ID = 6
+                        if ( (i_chipUnitNum / 2) % 2 )
+                        {
+                            l_scom.setRingId(0x6);
+                        }
+                        // for even OMI instances after dividing by 2, set ring ID = 5
+                        else
+                        {
+                            l_scom.setRingId(0x5);
+                        }
+                    }
+
+                    break;
+
+                case PU_OMIC_CHIPUNIT:
+
+                    // PAU indirect
+                    if ( (l_scom.getChipletId() >= PAU0_CHIPLET_ID) &&   // 0x10
+                         (l_scom.getChipletId() <= PAU3_CHIPLET_ID) )    // 0x13
+                    {
+                        if (i_chipUnitNum % 2)
+                        {
+                            // For odd OMIC instance, set IO group ID=3
+                            l_scom.setIoGroupAddr(0x3);
+                        }
+                        else
+                        {
+                            // For even OMIC instance, set IO group ID=2
+                            l_scom.setIoGroupAddr(0x2);
+                        }
+                    }
+                    // MC direct
+                    else
+                    {
+                        if (i_chipUnitNum % 2)
+                        {
+                            // For odd OMIC instance, set ring ID=6
+                            l_scom.setRingId(0x6);
+                        }
+                        else
+                        {
+                            // For even OMIC instance, set ring ID=5
+                            l_scom.setRingId(0x5);
+                        }
+                    }
+
+                    break;
+
+                case PU_PAU_CHIPUNIT:
+
+                    // Setting RingId for instances 0, 3, 4, and 6
+                    // If input address has:
+                    //   RingId = 0x4 --> set translated RingId to 0x2
+                    //            0x5 --> set translated RingId to 0x3
+                    // Leave RingId as is otherwise
+                    if ( (i_chipUnitNum == 0) ||
+                         (i_chipUnitNum == 3) ||
+                         (i_chipUnitNum == 4) ||
+                         (i_chipUnitNum == 6) )
+                    {
+                        if (l_scom.getRingId() == 0x4)
+                        {
+                            l_scom.setRingId(0x2);
+                        }
+                        else if (l_scom.getRingId() == 0x5)
+                        {
+                            l_scom.setRingId(0x3);
+                        }
+                    }
+
+                    // Setting RingId for instances 1, 2, 5, and 7
+                    // If input address has:
+                    //   RingId = 0x2 --> set translated RingId to 0x4
+                    //            0x3 --> set translated RingId to 0x5
+                    // Leave RingId as is otherwise
+                    else if ( (i_chipUnitNum == 1) ||
+                              (i_chipUnitNum == 2) ||
+                              (i_chipUnitNum == 5) ||
+                              (i_chipUnitNum == 7) )
+                    {
+                        if (l_scom.getRingId() == 0x2)
+                        {
+                            l_scom.setRingId(0x4);
+                        }
+                        else if (l_scom.getRingId() == 0x3)
+                        {
+                            l_scom.setRingId(0x5);
+                        }
+                    }
+
+                    break;
+
+                default:
+                    break;
+            }
+
+            // Break out if error
+            if (l_rc)
+            {
+                break;
+            }
+
+        }
+        while(0);
+
+        if (l_rc)
+        {
+            l_scom.setAddr(FAILED_TRANSLATION);
+        }
+
+        return l_scom.getAddr();
+    }
+
+    // See header file for function description
+    uint32_t p10_scominfo_isChipUnitScom(const p10ChipUnits_t i_p10CU,
+                                         const uint8_t i_ecLevel,
+                                         const uint64_t i_scomAddr,
+                                         bool& o_chipUnitRelated,
+                                         std::vector<p10_chipUnitPairing_t>& o_chipUnitPairing,
+                                         const p10TranslationMode_t i_mode)
+    {
+        p10_scom_addr l_scom(i_scomAddr);
+        o_chipUnitRelated = false;
+        o_chipUnitPairing.clear();
+
+        // Quad registers which can be addressed by EQ target type
+        // eq: 0..7
+        if (l_scom.isEqTarget())
+        {
+            o_chipUnitRelated = true;
+            // PU_EQ_CHIPUNIT
+            o_chipUnitPairing.push_back(p10_chipUnitPairing_t(PU_EQ_CHIPUNIT,
+                                        l_scom.getEqTargetInstance()));
+        }
+
+        // Core, L2, L3 registers which can be addressed by core target type
+        // c: 0..31
+        if (l_scom.isCoreTarget())
+        {
+            o_chipUnitRelated = true;
+            // PU_C_CHIPUNIT
+            o_chipUnitPairing.push_back(p10_chipUnitPairing_t(PU_C_CHIPUNIT,
+                                        l_scom.getCoreTargetInstance()));
+        }
+
+        // PEC registers which can be addressed by pec target type
+        // pec: 0..1
+        if (l_scom.isPecTarget())
+        {
+            o_chipUnitRelated = true;
+            // PU_PEC_CHIPUNIT
+            o_chipUnitPairing.push_back(p10_chipUnitPairing_t(PU_PEC_CHIPUNIT,
+                                        l_scom.getPecTargetInstance()));
+        }
+
+        // PHB registers
+        // phb: 0..5
+        if (l_scom.isPhbTarget())
+        {
+            o_chipUnitRelated = true;
+            // PU_PHB_CHIPUNIT
+            o_chipUnitPairing.push_back(p10_chipUnitPairing_t(PU_PHB_CHIPUNIT,
+                                        l_scom.getPhbTargetInstance()));
+        }
+
+        // NMMU registers
+        // nmmu: 0..1
+        if (l_scom.isNmmuTarget())
+        {
+            o_chipUnitRelated = true;
+            // PU_NMMU_CHIPUNIT
+            o_chipUnitPairing.push_back(p10_chipUnitPairing_t(PU_NMMU_CHIPUNIT,
+                                        l_scom.getNmmuTargetInstance()));
+        }
+
+        // IOHS registers
+        if (l_scom.isIoHsTarget() &&
+            // prevent matching on IOHS SCOMs in ENGD build mode
+            (i_mode != P10_ENGD_BUILD_MODE))
+        {
+            o_chipUnitRelated = true;
+            // PU_IOHS_CHIPUNIT
+            o_chipUnitPairing.push_back(p10_chipUnitPairing_t(PU_IOHS_CHIPUNIT,
+                                        l_scom.getIoHsTargetInstance()));
+        }
+
+        // PAU registers
+        if (l_scom.isPauTarget())
+        {
+            o_chipUnitRelated = true;
+            // PU_PAU_CHIPUNIT
+            o_chipUnitPairing.push_back(p10_chipUnitPairing_t(PU_PAU_CHIPUNIT,
+                                        l_scom.getPauTargetInstance()));
+        }
+
+        // MC registers
+        if (l_scom.isMcTarget())
+        {
+            o_chipUnitRelated = true;
+            // PU_MC_CHIPUNIT
+            o_chipUnitPairing.push_back(p10_chipUnitPairing_t(PU_MC_CHIPUNIT,
+                                        l_scom.getMcTargetInstance()));
+        }
+
+        // MI registers
+        if (l_scom.isMiTarget())
+        {
+            o_chipUnitRelated = true;
+            // PU_MI_CHIPUNIT
+            o_chipUnitPairing.push_back(p10_chipUnitPairing_t(PU_MI_CHIPUNIT,
+                                        l_scom.getMiTargetInstance()));
+        }
+
+        // MCC registers
+        if (l_scom.isMccTarget())
+        {
+            o_chipUnitRelated = true;
+            // PU_MCC_CHIPUNIT
+            o_chipUnitPairing.push_back(p10_chipUnitPairing_t(PU_MCC_CHIPUNIT,
+                                        l_scom.getMccTargetInstance()));
+        }
+
+        // OMI registers
+        if (l_scom.isOmiTarget())
+        {
+            o_chipUnitRelated = true;
+            // PU_OMI_CHIPUNIT
+            o_chipUnitPairing.push_back(p10_chipUnitPairing_t(PU_OMI_CHIPUNIT,
+                                        l_scom.getOmiTargetInstance()));
+        }
+
+        // OMIC registers
+        if (l_scom.isOmicTarget())
+        {
+            o_chipUnitRelated = true;
+            // PU_OMIC_CHIPUNIT
+            o_chipUnitPairing.push_back(p10_chipUnitPairing_t(PU_OMIC_CHIPUNIT,
+                                        l_scom.getOmicTargetInstance()));
+        }
+
+        // PAUC registers
+        if (l_scom.isPaucTarget() &&
+            // prevent matching on indirect SCOMs (physically targeting IOHS
+            // scan latches) in ENGD build mode
+            ((i_mode != P10_ENGD_BUILD_MODE) ||
+             (l_scom.isDirect())))
+        {
+            o_chipUnitRelated = true;
+            // PU_PAUC_CHIPUNIT
+            o_chipUnitPairing.push_back(p10_chipUnitPairing_t(PU_PAUC_CHIPUNIT,
+                                        l_scom.getPaucTargetInstance()));
+        }
+
+        // PERV registers
+        if (l_scom.isPervTarget())
+        {
+            // if running in engineering data build flow context, do not
+            // emit associations for registers which would have only
+            // a single association of type PERV
+            if (!((o_chipUnitPairing.size() == 0) &&
+                  (i_mode == P10_ENGD_BUILD_MODE)))
+            {
+                o_chipUnitRelated = true;
+                // PU_PERV_CHIPUNIT
+                o_chipUnitPairing.push_back(p10_chipUnitPairing_t(PU_PERV_CHIPUNIT,
+                                            l_scom.getPervTargetInstance()));
+            }
+        }
+
+        /// Address may be of a chip, let it pass through
+        return (!l_scom.isValid());
+    }
+
+    uint32_t p10_scominfo_fixChipUnitScomAddrOrTarget(const p10ChipUnits_t i_p10CU,
+            const uint8_t i_ecLevel,
+            const uint32_t i_targetChipUnitNum,
+            const uint64_t i_scomaddr,
+            uint64_t& o_modifiedScomAddr,
+            p10ChipUnits_t& o_p10CU,
+            uint32_t& o_modifiedChipUnitNum,
+            const uint32_t i_mode)
+    {
+        uint32_t rc = 0;
+
+        o_modifiedScomAddr = i_scomaddr;
+        o_p10CU = i_p10CU;
+        o_modifiedChipUnitNum = i_targetChipUnitNum;
+
+        return rc;
+    }
+
+    //################################################################################
+    uint8_t validateChipUnitNum(const uint8_t i_chipUnitNum,
+                                const p10ChipUnits_t i_chipUnitType)
+    {
+        uint8_t l_rc = 0;
+        uint8_t l_index;
+
+        for (l_index = 0;
+             l_index < (sizeof(ChipUnitDescriptionTable) / sizeof(p10_chipUnitDescription_t));
+             l_index++)
+        {
+            // Looking for input chip unit type in table
+            if (i_chipUnitType == ChipUnitDescriptionTable[l_index].enumVal)
+            {
+                // Found a match, check input i_chipUnitNum to be <= max chip unit num
+                // for this unit type
+                if (i_chipUnitNum > ChipUnitDescriptionTable[l_index].maxChipUnitNum)
+                {
+                    l_rc = 1;
+                }
+
+                // Additional check for PERV targets, where there are gaps between instances
+                else if (i_chipUnitType == PU_PERV_CHIPUNIT)
+                {
+                    // Note: We allow content in chiplet ID = 0x00 to be referenced with a perv target instance,
+                    //       so do not check for instance = 0 here.
+                    if ( ((i_chipUnitNum > 3) && (i_chipUnitNum < 8)) ||
+                         ((i_chipUnitNum > 9) && (i_chipUnitNum < 12)) ||
+                         ((i_chipUnitNum > 19) && (i_chipUnitNum < 24)) )
+                    {
+                        l_rc = 1;
+                    }
+                }
+
+                // Additional check for PAU targets, where instance 1 and 2 are not valid
+                else if (i_chipUnitType == PU_PAU_CHIPUNIT)
+                {
+                    if ( (i_chipUnitNum == 1) || (i_chipUnitNum == 2) )
+                    {
+                        l_rc = 1;
+                    }
+                }
+
+                break;
+            }
+        }
+
+        // Can't find i_chipUnitType in table
+        if ( l_index >= (sizeof(ChipUnitDescriptionTable) / sizeof(p10_chipUnitDescription_t)) )
+        {
+            l_rc = 1;
+        }
+
+        return (l_rc);
+    }
+
+} // extern "C"
+
+#undef P10_SCOMINFO_C
diff --git a/src/tests/p10_scominfo.H b/src/tests/p10_scominfo.H
new file mode 100644
index 0000000..2075d08
--- /dev/null
+++ b/src/tests/p10_scominfo.H
@@ -0,0 +1,89 @@ 
+///
+/// @file p10_scominfo.H
+/// @brief P10 chip unit SCOM address platform translation code
+///
+/// HWP HW Maintainer: Thi Tran <thi@us.ibm.com>
+/// HWP FW Maintainer:
+/// HWP Consumed by: Cronus, HB, HWSV
+///
+
+#ifndef P10_SCOMINFO_H
+#define P10_SCOMINFO_H
+
+// includes
+#include <stdint.h>
+#include <vector>
+#include "p10_cu.H"
+
+extern "C"
+{
+    // Modes of translation
+    typedef enum
+    {
+        P10_DEFAULT_MODE = 0,       // Default platform behavior
+        P10_ENGD_BUILD_MODE = 1,    // Apply customization for ENGD build
+    } p10TranslationMode_t;
+
+    typedef enum
+    {
+        FAILED_TRANSLATION = 0xFFFFFFFFFFFFFFF1ull
+    } p10TranslationResult_t;
+
+    /// @brief Creates the actual SCOM address based on the chip unit type, instance, and the input SCOM address (relative to chip unit instance 0)
+    /// @param[in] i_p10CU        Enumeration of the chip unit type
+    /// @param[in] i_ecLevel      Chip EC level represented in HEX digit value.  Example: i_ecLevel = 0x12 --> EC level 1.2
+    /// @param[in] i_chipUnitNum  Instance number of the chip unit
+    /// @param[in] i_scomAddr     The input SCOM address associated with the chip unit type
+    /// @param[in] i_mode         Translation mode, specifying different addr translation methods.
+    /// @retval uint64_t Actual SCOM address for the chip unit instance passed in
+    uint64_t p10_scominfo_createChipUnitScomAddr(const p10ChipUnits_t i_p10CU,
+            const uint8_t i_ecLevel,
+            const uint8_t i_chipUnitNum,
+            const uint64_t i_scomAddr,
+            const uint32_t i_mode = 0);
+
+    /// @brief Determine if the provided SCOM address correlates to any chip units (if so creates a list of chipUnitPairing structures which correspond)
+    /// @param[in] i_p10CU              Enumeration of the chip unit type
+    /// @param[in] i_ecLevel            Chip EC level represented in HEX digit value.  Example: i_ecLevel = 0x12 --> EC level 1.2
+    /// @param[in] i_scomAddr SCOM address to be tested
+    /// @param[out] o_chipUnitRelated   Returns true if SCOM address is associated with any chip units
+    /// @param[out] o_chipUnitPairing   Collection of chipUnitPairing enums
+    /// @param[in] i_mode               Translation mode, specifying different addr translation methods.
+    /// @retval uint32_t Return non-zero for error
+    uint32_t p10_scominfo_isChipUnitScom(const p10ChipUnits_t i_p10CU,
+                                         const uint8_t i_ecLevel,
+                                         const uint64_t i_scomAddr,
+                                         bool& o_chipUnitRelated,
+                                         std::vector<p10_chipUnitPairing_t>& o_chipUnitPairing,
+                                         const p10TranslationMode_t i_mode = P10_DEFAULT_MODE);
+
+    /// @brief Alter the unit/unitnum of a target for spys where the clocks-on vs clocks-off targets are different.
+    /// @param[in] i_p10CU                Target used for the spy request
+    /// @param[in] i_ecLevel              Chip EC level represented in HEX digit value.  Example: i_ecLevel = 0x12 --> EC level 1.2
+    /// @param[in] i_targetChipUnitNum    The instance number of the target used for the spy request
+    /// @param[in] i_scomaddr             The scom from the clocks-on portion of the spy
+    /// @param[out] o_modifiedScomAddr    The translated scom address (none may be needed)
+    /// @param[out] o_p10CU               The translated target type
+    /// @param[out] o_modifiedChipUnitNum The translated target instance number
+    /// @param[in] i_mode                 Translation mode, specifying different addr translation methods.
+    /// @retval uint32_t Return non-zero for error
+    uint32_t p10_scominfo_fixChipUnitScomAddrOrTarget(const p10ChipUnits_t i_p10CU,
+            const uint8_t i_ecLevel,
+            const uint32_t i_targetChipUnitNum,
+            const uint64_t i_scomaddr,
+            uint64_t& o_modifiedScomAddr,
+            p10ChipUnits_t& o_p10CU,
+            uint32_t& o_modifiedChipUnitNum,
+            const uint32_t i_mode = 0);
+
+    /// @brief Validate the chip unit number to be within range
+    ///        of a chip unit type.
+    /// @param[in] i_chipUnitNum   Value of chip unit number (instance)
+    /// @param[in] i_chipUnitType  Chip unit type
+    /// @retval Non-zero if error
+    uint8_t validateChipUnitNum(const uint8_t i_chipUnitNum,
+                                const p10ChipUnits_t i_chipUnitType);
+
+} // extern "C"
+
+#endif /* P10_SCOMINFO_H */