# ippcli Devices and Nodes

There are two primary objects for interacting with the devices in the silicon:

> - Devices - The devices primarily hold information about the silicon or portion of silicon it is representing.

> - Nodes - Hold functions to apply to its corresponding device.

For each Device there is exactly one Node, and for each Node, there is exactly one device. Often it may be useful to apply a function to multiple nodes/devices at the same time, and for that you would use a NodeGroup.

> - Node Groups - Holds multiple nodes for indexing or running a function on

The most common node group used is “ipc.threads”, which exists to be backwards compatible with the DAL/itpii.

## Devices

The devices primarily hold information about the silicon or portion of silicon it is representing. A list of the known TAP devices can be found via:

    >>> ipc.devicelist
    Indx DID         Alias                Type                Step Idcode      P/D/ C/T  Enabled
    ---------------------------------------------------------------------------------------------------
    0    0x00003000  ANN_CLTAPC0          ANN_CLTAPC          A0   0x10A84013  0/-/ -/-  Yes
    1    0x00004000  ANN_SC0              ANN_SC              A0   0x0202100B  0/-/ -/-  Yes
    2    0x00001000  ANN_ARC0             ARC                 A0   0x200424B1  0/-/ -/0  Yes
    3    0x00001001  ANN_AUDIO0           AUDIO               A0   0x0B284013  0/-/ -/0  Yes
    4    0x00001002  ANN_PSH0             LMT                 A0   0x18289013  0/-/ -/0  Yes
    ...
    73   0x00005001  SLM_MODULE1          SLM_MODULE          E0   0x4A68E013  0/-/ -/-  Yes
    74   0x00002002  SLM_C2               SLM_C               E0   0x4A68E013  0/-/ 0/-  Yes
    75   0x00001008  SLM_C2_T0            SLM                 E0   0x4A68E013  0/-/ 0/0  Yes
    76   0x00002003  SLM_C3               SLM_C               E0   0x4A68E013  0/-/ 1/-  Yes
    77   0x00001009  SLM_C3_T0            SLM                 E0   0x4A68E013  0/-/ 1/0  Yes
    78   0x00014000  MIPI-PTI             InterfacePort                        0/-/ -/-  Yes

You can also print the device to see some of the known information about that device:

    >>> print ipc.devicelist[0]
    alias         = ANN_CLTAPC0
    devicetype    = ANN_CLTAPC
    stepping      = A0                   packageid  =  0
    did           = 0x00003000           dieid      =
    idcode        = 0x10a84013           coreid     =
    irlength      = 8                    threadid   =
    isenabled     = True                 instanceid =  0
    bustype       =

In some cases there may be additional information about the device that is available. To see all that is available on a device, use the built-in python dir command:

    >>> print dir(ipc.devicelist[0])

The Device, the Device’s DID, and the Device’s alias are the primary methods of specifying a device when calling in to the IPC CLI functions. However, if the Node is being used (more on that in a bit), then the device does not need to be specified.

You can see from the example above that the Device’s DID does not begin with 0. However, the itpii/DAL started with 0. For backwards compatibility the “Indx” can also be specified when calling in to a function but it is not recommended. It is preferable to use the DID, or even better, the Alias.

The Device List behaves as a list and can be indexed in to (see example above). There are two additional functions that may be useful to many users:

DeviceList.findByDID(did)

  Return the device object matching this did.

  Parameters

    did – the id of the device to return.

  Returns

    The device instance, if found.

  Raises

    ValueError – if no matching did is found.

DeviceList.search(values=None, bywhat=None, **kwargs)

  Searches through all the known devices and looks for an attribute specified in the ‘bywhat’ variable. Returns a DeviceList with a list of all the devices that matched the search criteria.

  Parameters

    - values – this can be either a list of values or a regular expression that we will match each devices ‘bywhat’ against.

    - bywhat – any device attribute to match against.

    - kwargs – bywhat can be express via kwargs like so: devicetype=value; only one kwarg is currently supported.

    - ignore_case – (optional) special kwarg that will be looked for (default=True).

  Returns

    A devicelist object.

  Example

      >>> # Search for aliases that match exactly with what is in the specified list
      >>> ipc.devicelist.search( ["SLM_C0_T0","SLM_C1_T0"] )

      >>> # Search for aliases that match the given regular expression
      >>> ipc.devicelist.search( "SLM_C._T." )

      >>> # search for all device types that match the given regular expression
      >>> ipc.devicelist.search( "SLM", "devicetype" )
      >>> ipc.devicelist.search( devicetype = "SLM" )

  Raises

    - ValueError – if values is None and kwargs is empty

    - ValueError – if more than 1 kwarg is passed in (not including ignore_case)

    - ValueError – if no devices with the given attributes were found

Device.search_children(**kwargs)

  Search for children and return a list of devices that match the specified criteria.

  Parameters

    - kwargs – key=value of what to search for. If value is a string, then it is treated like a regular expression.

    - ignore_case – optional kwarg to specify ignoring case (defaults to True).

  Returns

    a devicelist object.

  Raises

    - ValueError – if kwargs is empty

    - ValueError – if more than 1 kwarg is passed in (not counting ignore_case)

Device.search_parents(**kwargs)

  Search parents and return a list of devices that match the specified criteria.

  Parameters

    - kwargs – key=value of what to search for. If value is a string, then it is treated like a regular expression.

    - ignore_case – optional kwarg to specify ignoring case (defaults to True).

  Returns

    a devicelist object.

  Raises

    - ValueError – if kwargs is empty

    - ValueError – if more than 1 kwarg is passed in (not counting ignore_case)

## Nodes

Nodes are objects that help map the devices to the functions that those devices support. Currently there is a NodeContainer object that holds all the nodes and it is found here in the ipccli:

    >>> ipc.devs.<tab>
    ipc.devs.ann_arc0            ipc.devs.ann_iopti0          ipc.devs.ann_pnd0            ipc.devs.ann_usb2phy0
    ipc.devs.ann_atpg0           ipc.devs.ann_iosdio0         ipc.devs.ann_pnd_dft0        ipc.devs.ann_usb2pll0
    ipc.devs.ann_audio0          ipc.devs.ann_iossp0          ipc.devs.ann_pnd_mbist0      ipc.devs.ann_usb3phy0
    ipc.devs.ann_cck0            ipc.devs.ann_iosspa0         ipc.devs.ann_pnd_tap2iosf0   ipc.devs.ann_vsp0

Each Node will have the functions that are supported by that device:

    >>> ipc.devs.slm_c0_t0.<tab>
    ipc.devs.slm_c0_t0.arch_register()
    ipc.devs.slm_c0_t0.asm()             ipc.devs.slm_c0_t0.cv                ipc.devs.slm_c0_t0.mem()
    ipc.devs.slm_c0_t0.asmmode()         ipc.devs.slm_c0_t0.device            ipc.devs.slm_c0_t0.memblock()
    ipc.devs.slm_c0_t0.br()              ipc.devs.slm_c0_t0.did               ipc.devs.slm_c0_t0.memdump()
    ipc.devs.slm_c0_t0.brchange()        ipc.devs.slm_c0_t0.dport()           ipc.devs.slm_c0_t0.msr()
    ipc.devs.slm_c0_t0.breaks            ipc.devs.slm_c0_t0.drscan()          ipc.devs.slm_c0_t0.name
    ipc.devs.slm_c0_t0.brget()           ipc.devs.slm_c0_t0.go()              ipc.devs.slm_c0_t0.nodetype
    ipc.devs.slm_c0_t0.brnew()           ipc.devs.slm_c0_t0.halt()            ipc.devs.slm_c0_t0.port()
    ipc.devs.slm_c0_t0.brremove()        ipc.devs.slm_c0_t0.idcode()          ipc.devs.slm_c0_t0.state
    ipc.devs.slm_c0_t0.cpuid()           ipc.devs.slm_c0_t0.invd()            ipc.devs.slm_c0_t0.step()
    ipc.devs.slm_c0_t0.cpuid_eax()       ipc.devs.slm_c0_t0.irdrscan()        ipc.devs.slm_c0_t0.thread_status()
    ipc.devs.slm_c0_t0.cpuid_ebx()       ipc.devs.slm_c0_t0.irdrscanreplace()

### NodeContainer

The various nodes are attributes off of something called a NodeContainer, but really you most likely just care that it is located here:

    >>> ipc.devs
    <ipccli.ipc_env.ipc_node_container.NodeContainer object at 0x0000000002C7ECC0>

The node container currently has the following functions for use by users:

class NodeContainer(base)
  group_by(values=None, bywhat=None, **kwargs)

    Searches through all the known devices and looks for an attribute specified in the ‘bywhat’ variable. Returns a Node Group with a list of all the nodes whose devices matched the search criteria.

    Parameters

      - values – this can be either a list of values or a regular expression that we will match each devices ‘bywhat’ against.

      - bywhat – any device attribute to match against.

      - kwargs – bywhat can be expressed via kwargs like so: devicetype=value.

      - ignore_case – (optional) special kwarg that will be looked for (default=True).

    Returns

      A node group containing all the nodes whose devices matched the search criteria.

    See also

    Node Groups

    Example:

        >>> # Search for aliases that match exactly with what is in the specified list
        >>> threads = ipc.devs.group_by( ["SLM_C0_T0","SLM_C1_T0"] )

        >>> # Search for aliases that match the given regular expression
        >>> threads = ipc.devs.group_by( "SLM_C._T." )

        >>> # search for all device types that match the given regular expression
        >>> threads = ipc.devs.group_by( devicetype="SLM" )

    Raises

      - ValueError – if values is None and kwargs is empty

      - ValueError – if no nodes with the given attributes were found

## Node Groups

A node group is a derivative of a list that will allow you to perform operations across all the nodes in that list. ipc.threads is an example of one such node group and here is an example of reading from all the MSRs on that node group:

    >>> ipc.threads.msr(0x400)
    GLM_C0_T0.msr - [64b] 0x0000000000000000
    GLM_C1_T0.msr - [64b] 0x0000000000000000
    GLM_C2_T0.msr - [64b] 0x0000000000000000
    GLM_C3_T0.msr - [64b] 0x0000000000000000

The display is showing each node and the value that was received for each node. This is actually a list of values being returned though, so you can index in to that return data if you need to:

    >>> data = ipc.threads.msr(0x400)
    >>> data[0]
    [64b] 0x0000000000000000
    >>> data[1]
    [64b] 0x0000000000000000
    >>> len(data)
    0x4

Now, suppose you need to check the value of an MSR across all the threads. The Node group helps shortcut that check by letting you do this:

    >>> ipc.threads.msr(0x400) == 0
    True

Keep in mind, ALL the nodes must have the same value for that to be true. So if a single thread reports non-zero, then the expression evaluates to False.

## StatePort Object

The IPC API has a notion of building up multiple operations to build a higher level function called a stateport. The IPC API provides functions for dynamically discovering and creating those functions. Those functions will be under the stateport object under each node.

## Device Actions

Some nodes support device specific actions. You can find those actions via show actions:

    >>> ipc.device_actions.show_actions()
    debugport0 - LogInput - ScanEngine procedure that writes the specified input
                             to the OpenIPC log file (iff ScanEngine logger is
                             enabled to level Debug) and also returns the input
    root       - LogInput - ScanEngine procedure that writes the specified input
                             to the OpenIPC log file (iff ScanEngine logger is
                             enabled to level Debug) and also returns the input

You can execute those actions off the same device_actions object:

    >>> ipc.device_actions.root.LogInput("message for log file")

Or if you have the device-node already, the actions are there as well:

    >>> ipc.devs.root.device_actions.LogInput("message for log file")