Source code for pynq.metadata.runtime_metadata_parser

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

import copy
from typing import Dict

import pynqutils
from pynqmetadata import Module

from .clock_dict_view import ClockDictView
from .gpio_dict_view import GpioDictView
from .hierarchy_dict_view import HierarchyDictView
from .interrupt_controllers_view import InterruptControllersView
from .interrupt_pins_view import InterruptPinsView
from .ip_dict_view import IpDictView
from .mem_dict_view import MemDictView


[docs]class RuntimeMetadataParser: """ A class that produces a runtime metadata object. This is a collections of different views onto the metadata object. Each view presents a different interpretation of the underlying metadata. Views: * ip_dict: a dictionary of all IP that is addressable from the processing system. * hierarchy_dict : a dictionary containing the hierarchies of IP in the design. * gpio_dict: all the GPIO pins controlled by the PS. * interrupt_controllers : a dictionary of al AXI interrupt controllers in the system that are attached to the PS. * interrupt_pins : all pins attached to an interrupt controller in the interrupt_controllers view * mem_dict: a dictionary of all the memory regions in the design. * clock_dict : a dictionary of all the configurable clocks in the design. Views are dynamically updated as the underlying metadata is changed. However, this is not currently fully supported in the latest release of PYNQ, so one time deep copies of these dictionaries are made. """ def __init__(self, md: Module) -> None: self.md = md # Check to see if there is an XSA parser associated with the metadata if "xsa" in self.md.ext: self.xsa = self.md.ext["xsa"].xsa else: self.xsa = None self.partial = True self.bin_data = None self.xclbin_data = None self.dtbo_data = None self.systemgraph = self.md self.ps_name = list(md.get_processing_systems().keys())[0] self.ps = md.get_processing_systems()[self.ps_name] self.family_ps = self.ps.ps_name self.interrupt_controllers_view = InterruptControllersView(self.md) self.interrupt_controllers = copy.deepcopy(self.interrupt_controllers_view.view) self.interrupt_pins_view = InterruptPinsView(self.md, self.interrupt_controllers) self.interrupt_pins = copy.deepcopy(self.interrupt_pins_view.view) self.ip_dict_view = IpDictView(self.md) self.ip_dict = copy.deepcopy(self.ip_dict_view.view) self.gpio_dict_view = GpioDictView(self.md) self.gpio_dict = copy.deepcopy(self.gpio_dict_view.view) self.clock_dict_view = ClockDictView(self.md) self.clock_dict = copy.deepcopy(self.clock_dict_view.clock_dict) self.mem_dict_view = MemDictView(self.md) self.mem_dict = copy.deepcopy(self.mem_dict_view.view) self.hierarchy_dict_view = HierarchyDictView( module=self.md, ip_view=self.ip_dict, mem_view=self.mem_dict, overlay=None, hierarchy_drivers={}, default_hierarchy=None, device=None, ) self.refresh_hierarchy_dict() # Remove any duplicates in ip_dict and mem_dict for item in self.mem_dict: if item in self.ip_dict: del self.ip_dict[item]
[docs] def refresh_hierarchy_dict(self) -> None: self.hierarchy_dict = copy.deepcopy(self.hierarchy_dict_view.view) self.assign_gpio_to_ip() self.assign_interrupts_to_ip()
[docs] def assign_gpio_to_ip(self)->None: """ Assigns the GPIO and Interrupts to the IP Dict """ for gpio in self.gpio_dict.values(): for connection in gpio["pins"]: ip, _, pin = connection.rpartition("/") if ip in self.ip_dict: self.ip_dict[ip]["gpio"][pin] = gpio elif ip in self.hierarchy_dict: self.hierarchy_dict[ip]["gpio"][pin] = gpio
[docs] def assign_interrupts_to_ip(self)->None: """ Assigns interrupts to the dictionaries """ for interrupt, val in self.interrupt_pins.items(): block, _, pin = interrupt.rpartition("/") if block in self.ip_dict: self.ip_dict[block]["interrupts"][pin] = val elif block in self.hierarchy_dict: self.hierarchy_dict[block]["interrupts"][pin]= val