Source code for pynq.metadata.ip_dict_view

# Copyright (C) 2022 Xilinx, Inc
# SPDX-License-Identifier: BSD-3-Clause

import json
from typing import Dict, List

from pynqmetadata import Core, ManagerPort, Module, ProcSysCore, Signal, SubordinatePort
from pynqmetadata.errors import CoreNotFound

from .metadata_view import MetadataView

from .append_drivers_pass import DriverExtension


[docs]class IpDictView(MetadataView): """ Provides a view onto the Metadata object that displays all addressable IP from the Processing System. Models a dictionary, where the key is the IP name, and each entry contains: * physical address * address range * type * parameters dictionary * register dictionary * any associated state The produced view dictionary has the type: IP: {str: {‘phys_addr’ : int, ‘addr_range’ : int, ‘type’ : str, ‘parameters’ : dict, ‘registers’: dict, ‘state’ : str}} """ def __init__(self, module: Module, submodule: bool = False) -> None: super().__init__(module=module) self._is_submodule = submodule
[docs] def get_ps(self) -> ProcSysCore: """Gets a reference to the PS core for this design""" for core in self._md.blocks.values(): if isinstance(core, ProcSysCore): return core raise CoreNotFound( f"Could not find a processing system for the design when getting the ip_dict_view" )
def _search_for_interrupts(self, core: Core) -> List[Signal]: """For a given core return all it's signals that are interrupt pins""" itr_pins = [] for port in core.ports.values(): for sig in port.signals.values(): if "interrupt_index" in sig.ext: itr_pins.append(sig) return itr_pins @property def view(self) -> Dict: repr_dict = {} ps = self.get_ps() for port in ps.ports.values(): if isinstance(port, ManagerPort): for sp_ref in port.addrmap: target_port = port._addrmap_obj[sp_ref] dparent = target_port.parent() # check if we are traversing across a BDC and jump in to grab the block if we are dcore = None dst_port = None # This is an ordinary core if isinstance(dparent, Core): dcore = dparent dst_port = target_port # This is a module (BDC/Hierarchy) elif isinstance(dparent, Module): if len(dparent.blocks) == 0: # We require a BDC stub interface (used in the composable) dcore = dparent dst_port = target_port else: # We flatten the hierarchy as there are blocks within this module dcore = None for b in dparent.blocks.values(): for p in b.ports.values(): for d in p.destinations().values(): if target_port.ref == d.ref: dcore = b dcore.hierarchy_name = ( f"{dparent.hierarchy_name}/{b.name}" ) dst_port = p if dcore is not None: repr_dict[dcore.hierarchy_name] = {} # Special case the vlvn for empty BDC modules if hasattr(dcore, "vlnv"): repr_dict[dcore.hierarchy_name]["type"] = dcore.vlnv.str else: repr_dict[dcore.hierarchy_name][ "type" ] = "xilinx.com:bdc:bdc:1.0" repr_dict[dcore.hierarchy_name]["mem_id"] = dst_port.name repr_dict[dcore.hierarchy_name]["memtype"] = "REGISTER" repr_dict[dcore.hierarchy_name]["gpio"] = {} repr_dict[dcore.hierarchy_name]["interrupts"] = {} for itr_sig in self._search_for_interrupts(dcore): repr_dict[dcore.hierarchy_name]["interrupts"][ itr_sig.name ] = {} repr_dict[dcore.hierarchy_name]["interrupts"][itr_sig.name][ "controller" ] = itr_sig.ext["interrupt_index"].controller repr_dict[dcore.hierarchy_name]["interrupts"][itr_sig.name][ "index" ] = itr_sig.ext["interrupt_index"].index repr_dict[dcore.hierarchy_name]["interrupts"][itr_sig.name][ "fullpath" ] = f"{itr_sig.parent().parent().hierarchy_name}/{itr_sig.name}" repr_dict[dcore.hierarchy_name]["parameters"] = {} for param in dcore.parameters.values(): repr_dict[dcore.hierarchy_name]["parameters"][ param.name ] = param.value repr_dict[dcore.hierarchy_name]["registers"] = {} repr_dict[dcore.hierarchy_name]["driver"] = None repr_dict[dcore.hierarchy_name]["device"] = None if "driver" in dst_port.ext and isinstance( dst_port.ext["driver"], DriverExtension ): repr_dict[dcore.hierarchy_name]["driver"] = dst_port.ext[ "driver" ].driver repr_dict[dcore.hierarchy_name]["device"] = dst_port.ext[ "driver" ].device if not isinstance(dst_port.parent(), ProcSysCore): for reg in dst_port.registers.values(): repr_dict[dcore.hierarchy_name]["registers"][ reg.name ] = {} repr_dict[dcore.hierarchy_name]["registers"][reg.name][ "address_offset" ] = reg.offset repr_dict[dcore.hierarchy_name]["registers"][reg.name][ "size" ] = reg.width repr_dict[dcore.hierarchy_name]["registers"][reg.name][ "access" ] = reg.access repr_dict[dcore.hierarchy_name]["registers"][reg.name][ "description" ] = reg.description repr_dict[dcore.hierarchy_name]["registers"][reg.name][ "fields" ] = {} for f in reg.bitfields.values(): repr_dict[dcore.hierarchy_name]["registers"][ reg.name ]["fields"][f.name] = {} repr_dict[dcore.hierarchy_name]["registers"][ reg.name ]["fields"][f.name]["bit_offset"] = f.LSB repr_dict[dcore.hierarchy_name]["registers"][ reg.name ]["fields"][f.name]["bit_width"] = ( f.MSB - f.LSB ) + 1 repr_dict[dcore.hierarchy_name]["registers"][ reg.name ]["fields"][f.name]["access"] = f.access repr_dict[dcore.hierarchy_name]["registers"][ reg.name ]["fields"][f.name]["description"] = f.description repr_dict[dcore.hierarchy_name]["state"] = None repr_dict[dcore.hierarchy_name]["bdtype"] = None repr_dict[dcore.hierarchy_name][ "phys_addr" ] = dst_port.baseaddr repr_dict[dcore.hierarchy_name][ "addr_range" ] = dst_port.range repr_dict[dcore.hierarchy_name][ "fullpath" ] = dcore.hierarchy_name repr_dict[ps.hierarchy_name] = {} repr_dict[ps.hierarchy_name]["type"] = ps.vlnv.str repr_dict[ps.hierarchy_name]["gpio"] = {} repr_dict[ps.hierarchy_name]["interrupts"] = {} repr_dict[ps.hierarchy_name]["parameters"] = {} repr_dict[ps.hierarchy_name]["driver"] = None repr_dict[ps.hierarchy_name]["device"] = None if "driver" in ps.ext and isinstance(ps.ext["driver"], DriverExtension): repr_dict[ps.hierarchy_name]["driver"] = ps.ext["driver"].driver repr_dict[ps.hierarchy_name]["device"] = ps.ext["driver"].device for param in ps.parameters.values(): repr_dict[ps.hierarchy_name]["parameters"][param.name] = param.value return repr_dict