blob: 08a3e0ee3c798a953d3ed44ef72c20064f0186ab [file] [log] [blame]
# Copyright 2023 Google LLC
# Copyright lowRISC contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
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], top_name: 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 / f"hw/{top_name}/ip_autogen/{self.name_snake}/data"
elif self.name_snake in templated_modules:
data_dir = REPO_TOP / f"hw/{top_name}/ip/{self.name_snake}/data/autogen"
elif self.name_snake in reggen_top_modules:
data_dir = REPO_TOP / f"hw/{top_name}/ip/{self.name_snake}/data/"
else:
data_dir = REPO_TOP / f"hw/ip/{self.name_snake}/data"
_hjson_file = data_dir / f"{self.name_snake}.hjson"
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