blob: bad52f7f492d5e2cc9391b9c4a799724df69209b [file] [log] [blame]
Miguel Young de la Sotaff15b052020-09-09 11:26:17 -04001#!/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 Trippelce9232e2021-09-13 22:48:18 +00005"""make_new_dif.py is a script for instantiating templates needed to begin
6development on a new DIF.
Miguel Young de la Sotaff15b052020-09-09 11:26:17 -04007
Timothy Trippeled24b152021-11-03 03:05:04 +00008To 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
12where "IP Controller" is a documentation-friendly name for the IP.
13For example, compare "pwrmgr" and "Power Manager".
Timothy Trippelce9232e2021-09-13 22:48:18 +000014
15It will instantiate:
Timothy Trippeled24b152021-11-03 03:05:04 +000016- `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 Trippelce9232e2021-09-13 22:48:18 +000018- `sw/device/lib/dif/templates/dif_autogen.h.tpl` as the autogenerated DIF
Timothy Trippeled24b152021-11-03 03:05:04 +000019 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 Trippelce9232e2021-09-13 22:48:18 +000026
27See both templates for more information.
28
29You can also use the `--only=header`, `--only=autogen`, `--only=checklist` to
30instantiate a subset of the templates. This can be passed multiple times, and
31including `--only=all` will instantiate every template.
32
33Note: the non-autogenerated files will still need some cleaning up before they
34can be used.
35"""
Miguel Young de la Sotaff15b052020-09-09 11:26:17 -040036
37import argparse
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +000038import glob
Timothy Trippelce9232e2021-09-13 22:48:18 +000039import logging
Timothy Trippelce9232e2021-09-13 22:48:18 +000040import subprocess
41import sys
Miguel Young de la Sotaff15b052020-09-09 11:26:17 -040042from pathlib import Path
43
Timothy Trippel48a9fb72022-02-10 22:36:40 -080044import hjson
Miguel Young de la Sotaff15b052020-09-09 11:26:17 -040045from mako.template import Template
46
Timothy Trippel48a9fb72022-02-10 22:36:40 -080047import topgen.lib as lib
Timothy Trippel2f945982021-11-03 22:31:07 +000048from autogen_banner import get_autogen_banner
Timothy Trippel553475e2022-02-22 18:05:28 -080049from autogen_testutils.gen import gen_testutils
Timothy Trippel1c4f7c22021-10-27 21:46:38 +000050from make_new_dif.ip import Ip
51
Miguel Young de la Sotaff15b052020-09-09 11:26:17 -040052# This file is $REPO_TOP/util/make_new_dif.py, so it takes two parent()
53# calls to get back to the top.
54REPO_TOP = Path(__file__).resolve().parent.parent
55
Timothy Trippelce9232e2021-09-13 22:48:18 +000056ALL_PARTS = ["header", "checklist", "autogen"]
57
Miguel Young de la Sotaff15b052020-09-09 11:26:17 -040058
59def main():
Timothy Trippelce9232e2021-09-13 22:48:18 +000060 dif_dir = REPO_TOP / "sw/device/lib/dif"
61 autogen_dif_dir = dif_dir / "autogen"
Miguel Young de la Sotaff15b052020-09-09 11:26:17 -040062
63 parser = argparse.ArgumentParser()
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +000064 parser.add_argument(
65 "--mode",
66 "-m",
Timothy Trippeled24b152021-11-03 03:05:04 +000067 choices=["new", "regen"],
68 default="new",
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +000069 required=True,
Timothy Trippeled24b152021-11-03 03:05:04 +000070 help="mode to generate DIF code. Use 'new' if no DIF code exists."
Timothy Trippel553475e2022-02-22 18:05:28 -080071 "Use 'regen' to regenerate all auto-generated DIFs for all IPs.")
Timothy Trippel48a9fb72022-02-10 22:36:40 -080072 parser.add_argument("--topcfg", "-t", help="path of the top hjson file.")
Timothy Trippeled24b152021-11-03 03:05:04 +000073 parser.add_argument("--ip-name-snake",
Timothy Trippelce9232e2021-09-13 22:48:18 +000074 "-i",
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +000075 help="the short name of the IP, in snake_case.")
Timothy Trippeled24b152021-11-03 03:05:04 +000076 parser.add_argument("--ip-name-long",
77 "-l",
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +000078 help="the documentation-friendly name of the IP.")
Timothy Trippelce9232e2021-09-13 22:48:18 +000079 parser.add_argument("--only",
80 choices=ALL_PARTS,
Sam Elliottf18219f2020-09-23 17:46:10 +010081 default=[],
Timothy Trippelce9232e2021-09-13 22:48:18 +000082 action="append",
83 help="only create some files; defaults to all.")
Miguel Young de la Sotaff15b052020-09-09 11:26:17 -040084 args = parser.parse_args()
85
Timothy Trippelce9232e2021-09-13 22:48:18 +000086 # Parse CMD line args.
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +000087 ips = []
88
Timothy Trippel553475e2022-02-22 18:05:28 -080089 # Parse toplevel Hjson to get IPs that are templated / generated with IPgen.
Timothy Chen65ff5102022-01-20 18:42:09 -080090 topcfg_path = REPO_TOP / "hw/top_earlgrey/data/top_earlgrey.hjson"
91 if args.topcfg:
92 topcfg_path = args.topcfg
Timothy Chen65ff5102022-01-20 18:42:09 -080093 try:
94 with open(topcfg_path, 'r') as ftop:
Timothy Trippel48a9fb72022-02-10 22:36:40 -080095 topcfg = hjson.load(ftop, use_decimal=True)
Timothy Chen65ff5102022-01-20 18:42:09 -080096 except FileNotFoundError:
97 print(f"hjson {topcfg_path} could not be found")
98 sys.exit(1)
Timothy Chen65ff5102022-01-20 18:42:09 -080099 templated_modules = lib.get_templated_modules(topcfg)
100 ipgen_modules = lib.get_ipgen_modules(topcfg)
Timothy Trippela2298252022-04-12 10:59:39 -0700101 reggen_top_modules = lib.get_top_reggen_modules(topcfg)
Timothy Chen65ff5102022-01-20 18:42:09 -0800102
Timothy Trippeled24b152021-11-03 03:05:04 +0000103 # Check for regeneration mode (used in CI check:
104 # ci/scripts/check-generated.sh)
105 if args.mode == "regen":
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +0000106 if len(args.only) != 1 or args.only[0] != "autogen":
107 raise RuntimeError(
Timothy Trippeled24b152021-11-03 03:05:04 +0000108 "can only regenerate DIF code that is auto-generated.")
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +0000109 # Create list of IPs to re-generate DIF code for.
110 for autogen_src_filename in glob.iglob(
111 str(REPO_TOP / "sw/device/lib/dif/autogen/*.c")):
112 # NOTE: the line below takes as input a file path
113 # (/path/to/dif_uart_autogen.c) and returns the IP name in lower
114 # case snake mode (i.e., uart).
115 ip_name_snake = Path(autogen_src_filename).stem[4:-8]
116 # NOTE: ip.name_long_* not needed for auto-generated files which
Timothy Trippeled24b152021-11-03 03:05:04 +0000117 # are the only files (re-)generated in regen mode.
Timothy Trippel48a9fb72022-02-10 22:36:40 -0800118 ips.append(
Timothy Trippela2298252022-04-12 10:59:39 -0700119 Ip(ip_name_snake, "AUTOGEN", templated_modules, ipgen_modules,
120 reggen_top_modules))
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +0000121 else:
Timothy Trippeled24b152021-11-03 03:05:04 +0000122 assert args.ip_name_snake and args.ip_name_long, \
123 "ERROR: pass --ip-name-snake and --ip-name-long when --mode=new."
Timothy Trippel48a9fb72022-02-10 22:36:40 -0800124 ips.append(
125 Ip(args.ip_name_snake, args.ip_name_long, templated_modules,
Timothy Trippela2298252022-04-12 10:59:39 -0700126 ipgen_modules, reggen_top_modules))
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +0000127
Timothy Trippelce9232e2021-09-13 22:48:18 +0000128 # Default to generating all parts.
Sam Elliottf18219f2020-09-23 17:46:10 +0100129 if len(args.only) == 0:
Sam Elliottf18219f2020-09-23 17:46:10 +0100130 args.only += ALL_PARTS
131
Timothy Trippelce9232e2021-09-13 22:48:18 +0000132 # Create output directories if needed.
Sam Elliottf18219f2020-09-23 17:46:10 +0100133 if len(args.only) > 0:
Timothy Trippelce9232e2021-09-13 22:48:18 +0000134 dif_dir.mkdir(exist_ok=True)
135 autogen_dif_dir.mkdir(exist_ok=True)
Miguel Young de la Sotaff15b052020-09-09 11:26:17 -0400136
Timothy Trippel553475e2022-02-22 18:05:28 -0800137 # Render DIF templates.
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +0000138 for ip in ips:
139 if "header" in args.only:
Timothy Trippel1c4f7c22021-10-27 21:46:38 +0000140 header_template_file = (
141 REPO_TOP / "util/make_new_dif/templates/dif_template.h.tpl")
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +0000142 header_out_file = dif_dir / "dif_{}.h".format(ip.name_snake)
Timothy Trippeled0abd22021-10-26 03:24:23 +0000143 if header_out_file.is_file():
144 raise FileExistsError(
Timothy Trippel1c4f7c22021-10-27 21:46:38 +0000145 "DIF header already exists for the IP. To overwrite, "
146 "delete existing header and try again.")
Timothy Trippeled0abd22021-10-26 03:24:23 +0000147 header_template = Template(header_template_file.read_text())
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +0000148 header_out_file.write_text(header_template.render(ip=ip))
149 print("DIF header successfully written to {}.".format(
150 str(header_out_file)))
Miguel Young de la Sotaff15b052020-09-09 11:26:17 -0400151
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +0000152 if "autogen" in args.only:
Drew Macraef2396eb2022-06-30 14:28:08 -0400153 out_files = []
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +0000154 # Render all templates
Timothy Trippel440f9602021-09-22 00:34:29 +0000155 for filetype in [".h", ".c", "_unittest.cc"]:
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +0000156 # Build input/output file names.
Timothy Trippel7b6113d2021-09-15 21:51:11 +0000157 template_file = (
Timothy Trippel1c4f7c22021-10-27 21:46:38 +0000158 REPO_TOP /
159 f"util/make_new_dif/templates/dif_autogen{filetype}.tpl")
Timothy Trippel7b6113d2021-09-15 21:51:11 +0000160 out_file = (autogen_dif_dir /
161 f"dif_{ip.name_snake}_autogen{filetype}")
Sam Elliottf18219f2020-09-23 17:46:10 +0100162
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +0000163 # Read in template.
Timothy Trippel67137492021-09-24 22:54:13 +0000164 template = Template(template_file.read_text(),
165 strict_undefined=True)
Sam Elliottf18219f2020-09-23 17:46:10 +0100166
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +0000167 # Generate output file.
Timothy Trippel2f945982021-11-03 22:31:07 +0000168 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 Elliottf18219f2020-09-23 17:46:10 +0100174
Drew Macraef2396eb2022-06-30 14:28:08 -0400175 # Assemble a list of files to format all at once
176 out_files += [out_file]
Sam Elliottf18219f2020-09-23 17:46:10 +0100177
Drew Macraef2396eb2022-06-30 14:28:08 -0400178 # Format autogenerated file with clang-format.
179 try:
180 subprocess.check_call(
Chris Frantza0bceb22022-09-20 15:35:10 -0700181 ["./ci/bazelisk.sh", "run", "//quality:clang_format_fix", "--"] + out_files
Drew Macraef2396eb2022-06-30 14:28:08 -0400182 )
183 except subprocess.CalledProcessError:
184 logging.error(
185 f"failed to format {out_file} with clang-format.")
186 sys.exit(1)
187
188 print("Autogenerated DIF successfully written to {}.".format(
189 out_files))
Sam Elliottf18219f2020-09-23 17:46:10 +0100190
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +0000191 if "checklist" in args.only:
192 checklist_template_file = REPO_TOP / "doc/project/sw_checklist.md.tpl"
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +0000193 checklist_out_file = dif_dir / "dif_{}.md".format(ip.name_snake)
Timothy Trippeled0abd22021-10-26 03:24:23 +0000194 if checklist_out_file.is_file():
195 raise FileExistsError(
Timothy Trippel1c4f7c22021-10-27 21:46:38 +0000196 "DIF checklist already exists for the IP. To "
197 "overwrite, delete existing checklist and try again.")
Timothy Trippeled0abd22021-10-26 03:24:23 +0000198 markdown_template = Template(checklist_template_file.read_text())
Timothy Trippeld7cb3ae2021-09-20 21:28:38 +0000199 checklist_out_file.write_text(markdown_template.render(ip=ip))
200 print("DIF Checklist successfully written to {}.".format(
201 str(checklist_out_file)))
Miguel Young de la Sotaff15b052020-09-09 11:26:17 -0400202
Timothy Trippel553475e2022-02-22 18:05:28 -0800203 # Render testutils templates.
204 if args.mode == "regen" or "autogen" in args.only:
205 gen_testutils(ips)
206
Miguel Young de la Sotaff15b052020-09-09 11:26:17 -0400207
Timothy Trippelce9232e2021-09-13 22:48:18 +0000208if __name__ == "__main__":
Miguel Young de la Sotaff15b052020-09-09 11:26:17 -0400209 main()