Source code for pynq.metadata.interrupt_controllers_view

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

import json
import re
from typing import Dict, List

from pydantic import Field
from pynqmetadata import Core, MetadataExtension, Module, Signal

from .metadata_view import MetadataView

[docs]class InterruptControllerIndex(MetadataExtension): index: int = Field( ..., description="The index for an interrupt controller in the PYNQ runtime" )
[docs]class InterruptControllersView(MetadataView): """ Provides a view onto the Metadata object that displays all the AXI interrupt controllers that are accessible from the processing system. Models a dictionary where the key is the name of the interrupt controller and each entry contains: * parent: either another controller or the PS * index: the index of this interrupt. The PS is the root of this hierarchy and is unnamed. """ def __init__(self, module: Module) -> None: super().__init__(module=module) self._state = {} self._base_idx: int = 0 def _walk_for_irq_controllers(self, sig: Signal) -> List[Core]: """From a PS IRQ pin, walk out from it and the concat blocks collecting all the interrupt controller blocks""" ret: List[Core] = [] # Get the index number from the port name (stf: I don't like this) if sig.parent().parent().vlnv.name == "xlconcat": idx_re = re.search("In([0-9]+)", sig.name) if len(idx_re.groups()) == 1: # idx = int(idx_re.group(1)) + base_idx idx = self._base_idx else: raise ValueError( f"Trying to infer an interrupt index from the port name for {sig.ref} but it does not match the expected format signame={sig.name} groups={idx_re.groups()}" ) else: idx = self._base_idx for dst in sig._connections.values(): if dst.parent().parent().vlnv.name == "axi_intc": dst.parent().parent().ext[ "interrupt_controller_index" ] = InterruptControllerIndex(index=idx) self._base_idx = self._base_idx + 1 ret.append(dst.parent().parent()) if dst.parent().parent().vlnv.name == "xlconcat": concat = dst.parent().parent() for port in concat.ports.values(): if port.name != "dout": sig = port.sig() ret = ret + self._walk_for_irq_controllers(sig) return ret @property def view(self) -> Dict: repr_dict = {} self._base_idx ps_list = self._md.get_processing_systems() if len(ps_list) > 1: raise RuntimeError( f"There is more than one processing system in the design, not sure how to proceed." ) ps = ps_list[list(ps_list.keys())[0]] ps_irq_signals = ps.get_irqs # Find all the directly connected controllers to the ps controller_list = [] for ps_irq in ps_irq_signals.values(): controller_list = controller_list + self._walk_for_irq_controllers(ps_irq) for controller in controller_list: repr_dict[controller.name] = {} repr_dict[controller.name]["parent"] = "" if "interrupt_controller_index" in controller.ext: repr_dict[controller.name]["index"] = controller.ext[ "interrupt_controller_index" ].index else: raise RuntimeError( f"Cannot determine the index for interrupt controller {controller.ref}" ) repr_dict[controller.name]["raw_irq"] = ps.irq_map[ controller.ext["interrupt_controller_index"].index ] return repr_dict def __setitem__(self, key: str, value: object) -> None: """Set the state of an item in the interrupt_controllers""" self._state[key] = value