[util] Organize and package `make_new_dif.py` classes.

IP HJSON file are parsed by the `util/make_new_dif.py` tool to load
IP metadata needed for auto-generating DIFs. This python code was
originally all contained in the `util/make_new_dif.py` script. By
repackaging it, we can reuse this code in the
`util/check_dif_statuses.py` script.

Signed-off-by: Timothy Trippel <ttrippel@google.com>
diff --git a/util/make_new_dif.py b/util/make_new_dif.py
index 295c7f1..d626c85 100755
--- a/util/make_new_dif.py
+++ b/util/make_new_dif.py
@@ -32,156 +32,18 @@
 import shutil
 import subprocess
 import sys
-from collections import OrderedDict
 from pathlib import Path
 
-import hjson
 from mako.template import Template
 
+from make_new_dif.ip import Ip
+
 # This file is $REPO_TOP/util/make_new_dif.py, so it takes two parent()
 # calls to get back to the top.
 REPO_TOP = Path(__file__).resolve().parent.parent
 
 ALL_PARTS = ["header", "checklist", "autogen"]
 
-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
-
 
 def main():
     dif_dir = REPO_TOP / "sw/device/lib/dif"
@@ -244,13 +106,13 @@
 
     for ip in ips:
         if "header" in args.only:
-            header_template_file = (REPO_TOP /
-                                    "util/make_new_dif/dif_template.h.tpl")
+            header_template_file = (
+                REPO_TOP / "util/make_new_dif/templates/dif_template.h.tpl")
             header_out_file = dif_dir / "dif_{}.h".format(ip.name_snake)
             if header_out_file.is_file():
                 raise FileExistsError(
-                    """DIF header already exists for the IP. To overwrite, """
-                    """delete existing header and try again.""")
+                    "DIF header already exists for the IP. To overwrite, "
+                    "delete existing header and try again.")
             header_template = Template(header_template_file.read_text())
             header_out_file.write_text(header_template.render(ip=ip))
             print("DIF header successfully written to {}.".format(
@@ -261,7 +123,8 @@
             for filetype in [".h", ".c", "_unittest.cc"]:
                 # Build input/output file names.
                 template_file = (
-                    REPO_TOP / f"util/make_new_dif/dif_autogen{filetype}.tpl")
+                    REPO_TOP /
+                    f"util/make_new_dif/templates/dif_autogen{filetype}.tpl")
                 out_file = (autogen_dif_dir /
                             f"dif_{ip.name_snake}_autogen{filetype}")
 
@@ -291,8 +154,8 @@
             checklist_out_file = dif_dir / "dif_{}.md".format(ip.name_snake)
             if checklist_out_file.is_file():
                 raise FileExistsError(
-                    """DIF checklist already exists for the IP. To """
-                    """overwrite, delete existing checklist and try again.""")
+                    "DIF checklist already exists for the IP. To "
+                    "overwrite, delete existing checklist and try again.")
             markdown_template = Template(checklist_template_file.read_text())
             checklist_out_file.write_text(markdown_template.render(ip=ip))
             print("DIF Checklist successfully written to {}.".format(