Miguel Young de la Sota | ff15b05 | 2020-09-09 11:26:17 -0400 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # Copyright lowRISC contributors. |
| 3 | # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| 4 | # SPDX-License-Identifier: Apache-2.0 |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 5 | """make_new_dif.py is a script for instantiating templates needed to begin |
| 6 | development on a new DIF. |
Miguel Young de la Sota | ff15b05 | 2020-09-09 11:26:17 -0400 | [diff] [blame] | 7 | |
Timothy Trippel | ed24b15 | 2021-11-03 03:05:04 +0000 | [diff] [blame] | 8 | To instantiate the files for a new IP named ip_ctrl, run the command: |
| 9 | |
| 10 | $ util/make_new_dif.py --ip-name-snake "ip_ctrl" --ip-name-long "IP Controller" |
| 11 | |
| 12 | where "IP Controller" is a documentation-friendly name for the IP. |
| 13 | For example, compare "pwrmgr" and "Power Manager". |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 14 | |
| 15 | It will instantiate: |
Timothy Trippel | ed24b15 | 2021-11-03 03:05:04 +0000 | [diff] [blame] | 16 | - `sw/device/lib/dif/dif_template.h.tpl` as the DIF Header boilerplate |
| 17 | (into `dif_<ip>.h`), which should be manually edited/enhanced. |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 18 | - `sw/device/lib/dif/templates/dif_autogen.h.tpl` as the autogenerated DIF |
Timothy Trippel | ed24b15 | 2021-11-03 03:05:04 +0000 | [diff] [blame] | 19 | Header (into `dif_<ip>_autogen.h`). |
| 20 | - `sw/device/lib/dif/templates/dif_autogen.c.tpl` as the autogenerated DIF |
| 21 | implementation (into `dif_<ip>_autogen.c`). |
| 22 | - `sw/device/lib/dif/templates/dif_autogen_unittest.cc.tpl` as the |
| 23 | autogenerated DIF unit tests (into `dif_<ip>_autogen_unittest.cc`). |
| 24 | - `doc/project/sw_checklist.md.tpl` as the DIF Checklist (into dif_<ip>.md), |
| 25 | which should be manually edited. |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 26 | |
| 27 | See both templates for more information. |
| 28 | |
| 29 | You can also use the `--only=header`, `--only=autogen`, `--only=checklist` to |
| 30 | instantiate a subset of the templates. This can be passed multiple times, and |
| 31 | including `--only=all` will instantiate every template. |
| 32 | |
| 33 | Note: the non-autogenerated files will still need some cleaning up before they |
| 34 | can be used. |
| 35 | """ |
Miguel Young de la Sota | ff15b05 | 2020-09-09 11:26:17 -0400 | [diff] [blame] | 36 | |
| 37 | import argparse |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 38 | import glob |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 39 | import logging |
| 40 | import shutil |
| 41 | import subprocess |
| 42 | import sys |
Miguel Young de la Sota | ff15b05 | 2020-09-09 11:26:17 -0400 | [diff] [blame] | 43 | from pathlib import Path |
| 44 | |
Timothy Trippel | 48a9fb7 | 2022-02-10 22:36:40 -0800 | [diff] [blame] | 45 | import hjson |
Miguel Young de la Sota | ff15b05 | 2020-09-09 11:26:17 -0400 | [diff] [blame] | 46 | from mako.template import Template |
| 47 | |
Timothy Trippel | 48a9fb7 | 2022-02-10 22:36:40 -0800 | [diff] [blame] | 48 | import topgen.lib as lib |
Timothy Trippel | 2f94598 | 2021-11-03 22:31:07 +0000 | [diff] [blame] | 49 | from autogen_banner import get_autogen_banner |
Timothy Trippel | 553475e | 2022-02-22 18:05:28 -0800 | [diff] [blame] | 50 | from autogen_testutils.gen import gen_testutils |
Timothy Trippel | 1c4f7c2 | 2021-10-27 21:46:38 +0000 | [diff] [blame] | 51 | from make_new_dif.ip import Ip |
| 52 | |
Miguel Young de la Sota | ff15b05 | 2020-09-09 11:26:17 -0400 | [diff] [blame] | 53 | # This file is $REPO_TOP/util/make_new_dif.py, so it takes two parent() |
| 54 | # calls to get back to the top. |
| 55 | REPO_TOP = Path(__file__).resolve().parent.parent |
| 56 | |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 57 | ALL_PARTS = ["header", "checklist", "autogen"] |
| 58 | |
Miguel Young de la Sota | ff15b05 | 2020-09-09 11:26:17 -0400 | [diff] [blame] | 59 | |
| 60 | def main(): |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 61 | dif_dir = REPO_TOP / "sw/device/lib/dif" |
| 62 | autogen_dif_dir = dif_dir / "autogen" |
Miguel Young de la Sota | ff15b05 | 2020-09-09 11:26:17 -0400 | [diff] [blame] | 63 | |
| 64 | parser = argparse.ArgumentParser() |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 65 | parser.add_argument( |
| 66 | "--mode", |
| 67 | "-m", |
Timothy Trippel | ed24b15 | 2021-11-03 03:05:04 +0000 | [diff] [blame] | 68 | choices=["new", "regen"], |
| 69 | default="new", |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 70 | required=True, |
Timothy Trippel | ed24b15 | 2021-11-03 03:05:04 +0000 | [diff] [blame] | 71 | help="mode to generate DIF code. Use 'new' if no DIF code exists." |
Timothy Trippel | 553475e | 2022-02-22 18:05:28 -0800 | [diff] [blame] | 72 | "Use 'regen' to regenerate all auto-generated DIFs for all IPs.") |
Timothy Trippel | 48a9fb7 | 2022-02-10 22:36:40 -0800 | [diff] [blame] | 73 | parser.add_argument("--topcfg", "-t", help="path of the top hjson file.") |
Timothy Trippel | ed24b15 | 2021-11-03 03:05:04 +0000 | [diff] [blame] | 74 | parser.add_argument("--ip-name-snake", |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 75 | "-i", |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 76 | help="the short name of the IP, in snake_case.") |
Timothy Trippel | ed24b15 | 2021-11-03 03:05:04 +0000 | [diff] [blame] | 77 | parser.add_argument("--ip-name-long", |
| 78 | "-l", |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 79 | help="the documentation-friendly name of the IP.") |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 80 | parser.add_argument("--only", |
| 81 | choices=ALL_PARTS, |
Sam Elliott | f18219f | 2020-09-23 17:46:10 +0100 | [diff] [blame] | 82 | default=[], |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 83 | action="append", |
| 84 | help="only create some files; defaults to all.") |
Miguel Young de la Sota | ff15b05 | 2020-09-09 11:26:17 -0400 | [diff] [blame] | 85 | args = parser.parse_args() |
| 86 | |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 87 | # Parse CMD line args. |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 88 | ips = [] |
| 89 | |
Timothy Trippel | 553475e | 2022-02-22 18:05:28 -0800 | [diff] [blame] | 90 | # Parse toplevel Hjson to get IPs that are templated / generated with IPgen. |
Timothy Chen | 65ff510 | 2022-01-20 18:42:09 -0800 | [diff] [blame] | 91 | topcfg_path = REPO_TOP / "hw/top_earlgrey/data/top_earlgrey.hjson" |
| 92 | if args.topcfg: |
| 93 | topcfg_path = args.topcfg |
Timothy Chen | 65ff510 | 2022-01-20 18:42:09 -0800 | [diff] [blame] | 94 | try: |
| 95 | with open(topcfg_path, 'r') as ftop: |
Timothy Trippel | 48a9fb7 | 2022-02-10 22:36:40 -0800 | [diff] [blame] | 96 | topcfg = hjson.load(ftop, use_decimal=True) |
Timothy Chen | 65ff510 | 2022-01-20 18:42:09 -0800 | [diff] [blame] | 97 | except FileNotFoundError: |
| 98 | print(f"hjson {topcfg_path} could not be found") |
| 99 | sys.exit(1) |
Timothy Chen | 65ff510 | 2022-01-20 18:42:09 -0800 | [diff] [blame] | 100 | templated_modules = lib.get_templated_modules(topcfg) |
| 101 | ipgen_modules = lib.get_ipgen_modules(topcfg) |
Timothy Trippel | a229825 | 2022-04-12 10:59:39 -0700 | [diff] [blame] | 102 | reggen_top_modules = lib.get_top_reggen_modules(topcfg) |
Timothy Chen | 65ff510 | 2022-01-20 18:42:09 -0800 | [diff] [blame] | 103 | |
Timothy Trippel | ed24b15 | 2021-11-03 03:05:04 +0000 | [diff] [blame] | 104 | # Check for regeneration mode (used in CI check: |
| 105 | # ci/scripts/check-generated.sh) |
| 106 | if args.mode == "regen": |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 107 | if len(args.only) != 1 or args.only[0] != "autogen": |
| 108 | raise RuntimeError( |
Timothy Trippel | ed24b15 | 2021-11-03 03:05:04 +0000 | [diff] [blame] | 109 | "can only regenerate DIF code that is auto-generated.") |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 110 | # Create list of IPs to re-generate DIF code for. |
| 111 | for autogen_src_filename in glob.iglob( |
| 112 | str(REPO_TOP / "sw/device/lib/dif/autogen/*.c")): |
| 113 | # NOTE: the line below takes as input a file path |
| 114 | # (/path/to/dif_uart_autogen.c) and returns the IP name in lower |
| 115 | # case snake mode (i.e., uart). |
| 116 | ip_name_snake = Path(autogen_src_filename).stem[4:-8] |
| 117 | # NOTE: ip.name_long_* not needed for auto-generated files which |
Timothy Trippel | ed24b15 | 2021-11-03 03:05:04 +0000 | [diff] [blame] | 118 | # are the only files (re-)generated in regen mode. |
Timothy Trippel | 48a9fb7 | 2022-02-10 22:36:40 -0800 | [diff] [blame] | 119 | ips.append( |
Timothy Trippel | a229825 | 2022-04-12 10:59:39 -0700 | [diff] [blame] | 120 | Ip(ip_name_snake, "AUTOGEN", templated_modules, ipgen_modules, |
| 121 | reggen_top_modules)) |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 122 | else: |
Timothy Trippel | ed24b15 | 2021-11-03 03:05:04 +0000 | [diff] [blame] | 123 | assert args.ip_name_snake and args.ip_name_long, \ |
| 124 | "ERROR: pass --ip-name-snake and --ip-name-long when --mode=new." |
Timothy Trippel | 48a9fb7 | 2022-02-10 22:36:40 -0800 | [diff] [blame] | 125 | ips.append( |
| 126 | Ip(args.ip_name_snake, args.ip_name_long, templated_modules, |
Timothy Trippel | a229825 | 2022-04-12 10:59:39 -0700 | [diff] [blame] | 127 | ipgen_modules, reggen_top_modules)) |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 128 | |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 129 | # Default to generating all parts. |
Sam Elliott | f18219f | 2020-09-23 17:46:10 +0100 | [diff] [blame] | 130 | if len(args.only) == 0: |
Sam Elliott | f18219f | 2020-09-23 17:46:10 +0100 | [diff] [blame] | 131 | args.only += ALL_PARTS |
| 132 | |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 133 | # Create output directories if needed. |
Sam Elliott | f18219f | 2020-09-23 17:46:10 +0100 | [diff] [blame] | 134 | if len(args.only) > 0: |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 135 | dif_dir.mkdir(exist_ok=True) |
| 136 | autogen_dif_dir.mkdir(exist_ok=True) |
Miguel Young de la Sota | ff15b05 | 2020-09-09 11:26:17 -0400 | [diff] [blame] | 137 | |
Timothy Trippel | 553475e | 2022-02-22 18:05:28 -0800 | [diff] [blame] | 138 | # Render DIF templates. |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 139 | for ip in ips: |
| 140 | if "header" in args.only: |
Timothy Trippel | 1c4f7c2 | 2021-10-27 21:46:38 +0000 | [diff] [blame] | 141 | header_template_file = ( |
| 142 | REPO_TOP / "util/make_new_dif/templates/dif_template.h.tpl") |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 143 | header_out_file = dif_dir / "dif_{}.h".format(ip.name_snake) |
Timothy Trippel | ed0abd2 | 2021-10-26 03:24:23 +0000 | [diff] [blame] | 144 | if header_out_file.is_file(): |
| 145 | raise FileExistsError( |
Timothy Trippel | 1c4f7c2 | 2021-10-27 21:46:38 +0000 | [diff] [blame] | 146 | "DIF header already exists for the IP. To overwrite, " |
| 147 | "delete existing header and try again.") |
Timothy Trippel | ed0abd2 | 2021-10-26 03:24:23 +0000 | [diff] [blame] | 148 | header_template = Template(header_template_file.read_text()) |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 149 | header_out_file.write_text(header_template.render(ip=ip)) |
| 150 | print("DIF header successfully written to {}.".format( |
| 151 | str(header_out_file))) |
Miguel Young de la Sota | ff15b05 | 2020-09-09 11:26:17 -0400 | [diff] [blame] | 152 | |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 153 | if "autogen" in args.only: |
| 154 | # Render all templates |
Timothy Trippel | 440f960 | 2021-09-22 00:34:29 +0000 | [diff] [blame] | 155 | for filetype in [".h", ".c", "_unittest.cc"]: |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 156 | # Build input/output file names. |
Timothy Trippel | 7b6113d | 2021-09-15 21:51:11 +0000 | [diff] [blame] | 157 | template_file = ( |
Timothy Trippel | 1c4f7c2 | 2021-10-27 21:46:38 +0000 | [diff] [blame] | 158 | REPO_TOP / |
| 159 | f"util/make_new_dif/templates/dif_autogen{filetype}.tpl") |
Timothy Trippel | 7b6113d | 2021-09-15 21:51:11 +0000 | [diff] [blame] | 160 | out_file = (autogen_dif_dir / |
| 161 | f"dif_{ip.name_snake}_autogen{filetype}") |
Sam Elliott | f18219f | 2020-09-23 17:46:10 +0100 | [diff] [blame] | 162 | |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 163 | # Read in template. |
Timothy Trippel | 6713749 | 2021-09-24 22:54:13 +0000 | [diff] [blame] | 164 | template = Template(template_file.read_text(), |
| 165 | strict_undefined=True) |
Sam Elliott | f18219f | 2020-09-23 17:46:10 +0100 | [diff] [blame] | 166 | |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 167 | # Generate output file. |
Timothy Trippel | 2f94598 | 2021-11-03 22:31:07 +0000 | [diff] [blame] | 168 | out_file.write_text( |
| 169 | template.render( |
| 170 | ip=ip, |
| 171 | autogen_banner=get_autogen_banner( |
| 172 | "util/make_new_dif.py --mode=regen --only=autogen", |
| 173 | "//"))) |
Sam Elliott | f18219f | 2020-09-23 17:46:10 +0100 | [diff] [blame] | 174 | |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 175 | # Format autogenerated file with clang-format. |
| 176 | assert (shutil.which("clang-format") and |
| 177 | "ERROR: clang-format must be installed to format " |
| 178 | " autogenerated code to pass OpenTitan CI checks.") |
| 179 | try: |
| 180 | subprocess.check_call(["clang-format", "-i", out_file]) |
| 181 | except subprocess.CalledProcessError: |
| 182 | logging.error( |
| 183 | f"failed to format {out_file} with clang-format.") |
| 184 | sys.exit(1) |
Sam Elliott | f18219f | 2020-09-23 17:46:10 +0100 | [diff] [blame] | 185 | |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 186 | print("Autogenerated DIF successfully written to {}.".format( |
| 187 | out_file)) |
Sam Elliott | f18219f | 2020-09-23 17:46:10 +0100 | [diff] [blame] | 188 | |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 189 | if "checklist" in args.only: |
| 190 | checklist_template_file = REPO_TOP / "doc/project/sw_checklist.md.tpl" |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 191 | checklist_out_file = dif_dir / "dif_{}.md".format(ip.name_snake) |
Timothy Trippel | ed0abd2 | 2021-10-26 03:24:23 +0000 | [diff] [blame] | 192 | if checklist_out_file.is_file(): |
| 193 | raise FileExistsError( |
Timothy Trippel | 1c4f7c2 | 2021-10-27 21:46:38 +0000 | [diff] [blame] | 194 | "DIF checklist already exists for the IP. To " |
| 195 | "overwrite, delete existing checklist and try again.") |
Timothy Trippel | ed0abd2 | 2021-10-26 03:24:23 +0000 | [diff] [blame] | 196 | markdown_template = Template(checklist_template_file.read_text()) |
Timothy Trippel | d7cb3ae | 2021-09-20 21:28:38 +0000 | [diff] [blame] | 197 | checklist_out_file.write_text(markdown_template.render(ip=ip)) |
| 198 | print("DIF Checklist successfully written to {}.".format( |
| 199 | str(checklist_out_file))) |
Miguel Young de la Sota | ff15b05 | 2020-09-09 11:26:17 -0400 | [diff] [blame] | 200 | |
Timothy Trippel | 553475e | 2022-02-22 18:05:28 -0800 | [diff] [blame] | 201 | # Render testutils templates. |
| 202 | if args.mode == "regen" or "autogen" in args.only: |
| 203 | gen_testutils(ips) |
| 204 | |
Miguel Young de la Sota | ff15b05 | 2020-09-09 11:26:17 -0400 | [diff] [blame] | 205 | |
Timothy Trippel | ce9232e | 2021-09-13 22:48:18 +0000 | [diff] [blame] | 206 | if __name__ == "__main__": |
Miguel Young de la Sota | ff15b05 | 2020-09-09 11:26:17 -0400 | [diff] [blame] | 207 | main() |