Skip to content

Commit

Permalink
[util] Remove autogen functionality from make_new_dif
Browse files Browse the repository at this point in the history
This functionality has been move to autogen_dif so simplify
make_new_dif to actually... make NEW difs! The command line is
also changed: instead of requiring a top-level cfg file (which
makes little sense and pulls it topgen.lib), require to point to
the IP's hjson directly.

Signed-off-by: Amaury Pouly <[email protected]>
  • Loading branch information
pamaury committed Jan 6, 2025
1 parent 7fa3e55 commit abeb7fa
Showing 1 changed file with 41 additions and 129 deletions.
170 changes: 41 additions & 129 deletions util/make_new_dif.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,52 +7,40 @@
To instantiate the files for a new IP named ip_ctrl, run the command:
$ util/make_new_dif.py --ip-name-snake "ip_ctrl" --ip-name-long "IP Controller"
$ util/make_new_dif.py -i /path/to/ip.hjson --ip-name-snake "ip_ctrl" --ip-name-long "IP Controller"
where "IP Controller" is a documentation-friendly name for the IP.
For example, compare "pwrmgr" and "Power Manager".
It will instantiate:
- `util/make_new_dif/templates/dif_template.h.tpl` as the DIF Header boilerplate
into `dif_<ip>.h`, which should be manually edited/enhanced.
- `util/make_new_dif/templates/dif_autogen.h.tpl` as the autogenerated DIF
Header into `dif_<ip>_autogen.h`.
- `util/make_new_dif/templates/dif_autogen.c.tpl` as the autogenerated DIF
implementation into `dif_<ip>_autogen.c`.
- `util/make_new_dif/templates/dif_autogen_unittest.cc.tpl` as the
autogenerated DIF unit tests into `dif_<ip>_autogen_unittest.cc`.
- `doc/project_governance/checklist/sw_checklist.md.tpl` as the DIF Checklist
into dif_<ip>.md, which should be manually edited.
Each one of these templates has comments with more specific information.
You can also use the `--only=header`, `--only=autogen`, `--only=checklist` to
You can also use the `--only=header`, `--only=checklist` to
instantiate a subset of the templates. This can be passed multiple times, and
including `--only=all` will instantiate every template.
Note: the non-autogenerated files will still need some cleaning up before they
can be used.
Note: the files will still need some cleaning up before they can be used.
"""

import argparse
import glob
import logging
import subprocess
import sys
from pathlib import Path

import hjson
import topgen.lib as lib
from autogen_banner import get_autogen_banner
from autogen_testutils.gen import gen_testutils
from make_new_dif.ip import Ip
from mako.template import Template

# 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"]
ALL_PARTS = ["header", "checklist"]


def main():
Expand All @@ -62,20 +50,19 @@ def main():
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument(
"--mode",
"-m",
choices=["new", "regen"],
default="new",
required=True,
help="mode to generate DIF code. Use 'new' if no DIF code exists."
"Use 'regen' to regenerate all auto-generated DIFs for all IPs.")
parser.add_argument("--topcfg", "-t", help="path of the top hjson file.")
parser.add_argument("--ip-name-snake",

parser.add_argument("--ipcfg",
"-i",
type=Path,
required=True,
help="`<ip>.hjson` file.")
parser.add_argument("--ip-name-snake",
"-s",
required=True,
help="the short name of the IP, in snake_case.")
parser.add_argument("--ip-name-long",
"-l",
required=True,
help="the documentation-friendly name of the IP.")
parser.add_argument("--only",
choices=ALL_PARTS,
Expand All @@ -84,51 +71,7 @@ def main():
help="only create some files; defaults to all.")
args = parser.parse_args()

# Parse CMD line args.
ips = []

# Parse toplevel Hjson to get IPs that are generated with IPgen and those
# that are under <top>/ip.
if args.topcfg:
topcfg_path = args.topcfg
else:
topcfg_path = REPO_TOP / "hw/top_earlgrey/data/top_earlgrey.hjson"
try:
with open(topcfg_path, 'r') as ftop:
topcfg = hjson.load(ftop, use_decimal=True)
except FileNotFoundError:
print(f"hjson {topcfg_path} could not be found")
sys.exit(1)
ipgen_modules = lib.get_ipgen_modules(topcfg)
reggen_top_modules = lib.get_top_reggen_modules(topcfg)
all_modules = [m['type'] for m in topcfg['module']]

# Check for regeneration mode (used in CI check:
# ci/scripts/check-generated.sh)
if args.mode == "regen":
if len(args.only) != 1 or args.only[0] != "autogen":
raise RuntimeError(
"can only regenerate DIF code that is auto-generated.")
# Create list of IPs to re-generate DIF code for.
for autogen_src_filename in glob.iglob(
str(REPO_TOP / "sw/device/lib/dif/autogen/*.c")):
# NOTE: the line below takes as input a file path
# (/path/to/dif_uart_autogen.c) and returns the IP name in lower
# case snake mode (i.e., uart).
ip_name_snake = Path(autogen_src_filename).stem[4:-8]
# Only considers IPs for that particular top.
if ip_name_snake not in all_modules:
continue
# NOTE: ip.name_long_* not needed for auto-generated files which
# are the only files (re-)generated in regen mode.
ips.append(
Ip(ip_name_snake, "AUTOGEN", ipgen_modules, reggen_top_modules))
else:
assert args.ip_name_snake and args.ip_name_long, \
"ERROR: pass --ip-name-snake and --ip-name-long when --mode=new."
ips.append(
Ip(args.ip_name_snake, args.ip_name_long, ipgen_modules,
reggen_top_modules))
ip = Ip(args.ip_name_snake, args.ip_name_long, args.ipcfg)

# Default to generating all parts.
if len(args.only) == 0:
Expand All @@ -141,71 +84,40 @@ def main():

# Render DIF templates.
template_path = REPO_TOP / "util/make_new_dif/templates"
for ip in ips:
if "header" in args.only:
header_template_file = template_path / "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.")
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(
str(header_out_file)))

if "autogen" in args.only:
out_files = []
# Render all templates
for filetype in [".h", ".c", "_unittest.cc"]:
# Build input/output file names.
template_file = template_path / f"dif_autogen{filetype}.tpl"
out_file = (autogen_dif_dir /
f"dif_{ip.name_snake}_autogen{filetype}")

# Read in template.
template = Template(template_file.read_text(),
strict_undefined=True)

# Generate output file.
out_file.write_text(
template.render(
ip=ip,
autogen_banner=get_autogen_banner(
"util/make_new_dif.py --mode=regen --only=autogen",
"//")))

# Assemble a list of files to format all at once
out_files += [out_file]

if "header" in args.only:
header_template_file = template_path / "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.")
header_template = Template(header_template_file.read_text())
header_out_file.write_text(header_template.render(ip=ip))
logging.info("DIF header successfully written to {}.".format(
str(header_out_file)))

# Format autogenerated file with clang-format.
try:
subprocess.check_call(
["./bazelisk.sh", "run", "//quality:clang_format_fix", "--"] +
out_files)
["./bazelisk.sh", "run", "//quality:clang_format_fix", "--", header_out_file])
except subprocess.CalledProcessError:
logging.error(f"failed to format {out_file} with clang-format.")
logging.error(f"failed to format {header_out_file} with clang-format.")
sys.exit(1)

print(f"Autogenerated DIF successfully written to {out_files}.")

if "checklist" in args.only:
checklist_template_file = (
REPO_TOP /
"doc/project_governance/checklist/sw_checklist.md.tpl")
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.")
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(
str(checklist_out_file)))

# Render testutils templates.
if args.mode == "regen" or "autogen" in args.only:
gen_testutils(ips)
if "checklist" in args.only:
checklist_template_file = (
REPO_TOP /
"doc/project_governance/checklist/sw_checklist.md.tpl")
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.")
markdown_template = Template(checklist_template_file.read_text())
checklist_out_file.write_text(markdown_template.render(ip=ip))
logging.info("DIF Checklist successfully written to {}.".format(
str(checklist_out_file)))


if __name__ == "__main__":
Expand Down

0 comments on commit abeb7fa

Please sign in to comment.