| # 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 | |
| from typing import List | |
| 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 | |
| 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 | |
| self.type = irq["type"] if "type" in irq else "event" | |
| assert self.type == "event" or self.type == "status" | |
| 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, | |
| templated_modules: List[str], ipgen_modules: List[str], | |
| reggen_top_modules: List[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). | |
| templated_modules: Templated modules where hjson is under top_* | |
| ipgen_modules: Ipgen modules where hjson is under ip_autogen | |
| reggen_top_modules: Top Reggen modules where hjson is under top_* | |
| """ | |
| # 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 ipgen_modules: | |
| data_dir = REPO_TOP / "hw/top_earlgrey/ip_autogen/{0}/data".format( | |
| self.name_snake) | |
| elif self.name_snake in templated_modules: | |
| data_dir = REPO_TOP / "hw/top_earlgrey/ip/{0}/data/autogen".format( | |
| self.name_snake) | |
| elif self.name_snake in reggen_top_modules: | |
| data_dir = REPO_TOP / "hw/top_earlgrey/ip/{0}/data/".format( | |
| self.name_snake) | |
| else: | |
| data_dir = REPO_TOP / "hw/ip/{0}/data".format(self.name_snake) | |
| _hjson_file = data_dir / "{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 |