|  | # Copyright lowRISC contributors. | 
|  | # Licensed under the Apache License, Version 2.0, see LICENSE for details. | 
|  | # SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | from collections import OrderedDict | 
|  | from pathlib import Path | 
|  |  | 
|  | import hjson | 
|  |  | 
|  | # This file is $REPO_TOP/util/make_new_dif/ip.py, so it takes three parent() | 
|  | # calls to get back to the top. | 
|  | REPO_TOP = Path(__file__).resolve().parent.parent.parent | 
|  |  | 
|  | IPS_USING_IPGEN = [ | 
|  | 'rv_plic', | 
|  | 'alert_handler', | 
|  | ] | 
|  |  | 
|  |  | 
|  | class Alert: | 
|  | """Holds alert information for populating DIF code templates. | 
|  |  | 
|  | Attributes: | 
|  | name_snake (str): Alert short name in lower snake case. | 
|  | name_upper (str): Alert short name in upper snake case. | 
|  | name_camel (str): Alert short name in camel case. | 
|  | description (str): Full description of the alert. | 
|  |  | 
|  | """ | 
|  | def __init__(self, alert: OrderedDict) -> None: | 
|  | self.name_snake = alert["name"] | 
|  | self.name_upper = self.name_snake.upper() | 
|  | self.name_camel = "".join( | 
|  | [word.capitalize() for word in self.name_snake.split("_")]) | 
|  | _multiline_description = alert["desc"][0].upper() + alert["desc"][1:] | 
|  | self.description = _multiline_description.replace("\n", " ") | 
|  |  | 
|  |  | 
|  | class Irq: | 
|  | """Holds IRQ information for populating DIF code templates. | 
|  |  | 
|  | Attributes: | 
|  | name_snake (str): IRQ short name in lower snake case. | 
|  | name_upper (str): IRQ short name in upper snake case. | 
|  | name_camel (str): IRQ short name in camel case. | 
|  | description (str): full description of the IRQ. | 
|  |  | 
|  | """ | 
|  | def __init__(self, irq: OrderedDict) -> None: | 
|  | self.name_snake = irq["name"] | 
|  | self.name_upper = self.name_snake.upper() | 
|  | self.name_camel = "".join( | 
|  | [word.capitalize() for word in self.name_snake.split("_")]) | 
|  | _multiline_description = irq["desc"][0].upper() + irq["desc"][1:] | 
|  | self.description = _multiline_description.replace("\n", " ") | 
|  | self.width = irq["width"] if "width" in irq else 1 | 
|  |  | 
|  |  | 
|  | class Parameter: | 
|  | """Holds IP Parameter information for populating DIF code templates. | 
|  |  | 
|  | Attributes: | 
|  | name (str): Parameter name. | 
|  | description (str): Parameter description. | 
|  | default (int): Default parameter value. | 
|  |  | 
|  | """ | 
|  | def __init__(self, parameter: OrderedDict) -> None: | 
|  | self.name = parameter["name"] | 
|  | self.description = parameter["desc"] | 
|  | self.default = None | 
|  | if "default" in parameter: | 
|  | self.default = parameter["default"] | 
|  |  | 
|  |  | 
|  | class Ip: | 
|  | """Holds all IP metadata mined from an IP's name and HJSON file. | 
|  |  | 
|  | Attributes: | 
|  | name_snake (str): IP short name in lower snake case. | 
|  | name_upper (str): IP short name in upper snake case. | 
|  | name_camel (str): IP short name in camel case. | 
|  | name_long_lower (str): IP full name in lower case. | 
|  | name_long_upper (str): IP full name with first letter capitalized. | 
|  | alerts (List[alerts]): List of Alert objs constructed from HSJON data. | 
|  | irqs (List[Irq]): List of Irq objs constructed from HJSON data. | 
|  |  | 
|  | """ | 
|  | def __init__(self, name_snake: str, name_long_lower: str) -> None: | 
|  | """Mines metadata to populate this Ip object. | 
|  |  | 
|  | Args: | 
|  | name_snake: IP short name in lower snake case (e.g., pwrmgr). | 
|  | name_long_lower: IP full name in lower case (e.g., power manager). | 
|  | """ | 
|  | # Generate various IP name formats. | 
|  | self.name_snake = name_snake | 
|  | self.name_upper = self.name_snake.upper() | 
|  | self.name_camel = "".join( | 
|  | [word.capitalize() for word in self.name_snake.split("_")]) | 
|  | self.name_long_lower = name_long_lower | 
|  | # We just want to set the first character to title case. In particular, | 
|  | # .capitalize() does not do the right thing, since it would convert | 
|  | # UART to Uart. | 
|  | self.name_long_upper = (self.name_long_lower[0].upper() + | 
|  | self.name_long_lower[1:]) | 
|  | # Load HJSON data. | 
|  | if self.name_snake in IPS_USING_IPGEN: | 
|  | ip_dir = REPO_TOP / "hw/top_earlgrey/ip_autogen/{0}".format( | 
|  | self.name_snake) | 
|  | else: | 
|  | ip_dir = REPO_TOP / "hw/ip/{0}".format(self.name_snake) | 
|  | _hjson_file = ip_dir / "data" / "{0}.hjson".format(self.name_snake) | 
|  | with _hjson_file.open("r") as f: | 
|  | _hjson_str = f.read() | 
|  | self._hjson_data = hjson.loads(_hjson_str) | 
|  | # Load Alert data from HJSON. | 
|  | self.alerts = self._load_alerts() | 
|  | # Load IRQ data from HJSON. | 
|  | self.irqs = self._load_irqs() | 
|  | # Load Parameters from HJSON | 
|  | self.parameters = self._load_parameters() | 
|  |  | 
|  | def _load_alerts(self): | 
|  | assert (self._hjson_data and | 
|  | "ERROR: must load IP HJSON before loading Alerts") | 
|  | alerts = [] | 
|  | if "alert_list" in self._hjson_data: | 
|  | for alert in self._hjson_data["alert_list"]: | 
|  | alerts.append(Alert(alert)) | 
|  | return alerts | 
|  |  | 
|  | def _load_irqs(self): | 
|  | assert (self._hjson_data and | 
|  | "ERROR: must load IP HJSON before loading IRQs") | 
|  | irqs = [] | 
|  | if "interrupt_list" in self._hjson_data: | 
|  | for irq in self._hjson_data["interrupt_list"]: | 
|  | irqs.append(Irq(irq)) | 
|  | return irqs | 
|  |  | 
|  | def _load_parameters(self): | 
|  | assert (self._hjson_data and | 
|  | "ERROR: must load IP HJSON before loarding Parameters") | 
|  | parameters = {} | 
|  | if "param_list" in self._hjson_data: | 
|  | for parameter in self._hjson_data["param_list"]: | 
|  | p = Parameter(parameter) | 
|  | parameters[p.name] = p | 
|  | return parameters |