blob: e4ff1b47eeb2b4f7d2f87c93d7a5c3d7014c5d65 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
"""
Script to patch the OpenTitan tree for building english-breakfast-friendly
software.
This script and its associated mechanism will eventually be transitioned to
a pure-Bazel solution.
"""
import argparse
import shutil
import subprocess
from pathlib import Path
# This file is in /hw/top_.../util
REPO_TOP = Path(__file__).resolve().parents[3]
BINARIES = [
'sw/device/lib/testing/test_rom/test_rom_export_fpga_cw305',
'sw/device/sca/aes_serial_export_fpga_cw305',
'sw/device/lib/testing/test_rom/test_rom_export_sim_verilator',
'sw/device/tests/aes_smoketest_export_sim_verilator',
'sw/device/examples/hello_world/hello_world_export_sim_verilator',
]
BAZEL_BINARIES = [
'//sw/device/lib/testing/test_rom',
'//sw/device/sca:aes_serial',
'//sw/device/tests:aes_smoketest_prog',
'//sw/device/examples/hello_world',
]
def find_dirs(root, names):
"""
Finds all directories under `root` with the given name and
yields them.
"""
for p in root.iterdir():
if not p.is_dir():
continue
if p.name in names:
yield p
else:
find_dirs(p, names)
def delete_path(path):
"""
Deletes a path; will delete directories recursively.
"""
print(f'* Deleting: {path}')
if not path.exists():
return
if path.is_dir():
shutil.rmtree(str(path))
else:
path.unlink()
def shell_out(cmd):
print(f"Running {cmd}")
# Let the resulting exception from `check` propagate out.
subprocess.run(cmd, check=True)
def main():
parser = argparse.ArgumentParser(
prog="prepare_sw",
description="Script to prepare SW sources for English Breakfast",
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('--build',
'-b',
default=False,
action='store_true',
help='Build ROM based on reduced design')
parser.add_argument(
'--delete-only',
'-d',
default=False,
action='store_true',
help='Delete previously generated auto-gen files without running topgen'
)
parser.add_argument('--top',
'-t',
default='englishbreakfast',
type=str,
help='The alternative top to use')
args = parser.parse_args()
name = args.top
topname = f'top_{name}'
# We start by removing any previously generated auto-gen files for the
# selected non-earlgrey top. These might be stale and confuse topgen.
print('Purging previously generated auto-gen files')
for d in find_dirs(REPO_TOP / 'hw' / topname, ['autogen', 'ip_autogen']):
delete_path(d)
delete_path(REPO_TOP / 'build' / str(topname + '-autogen'))
delete_path(REPO_TOP / 'hw' / topname / 'data/autogen')
delete_path(REPO_TOP / 'hw' / topname / 'dv/autogen')
delete_path(REPO_TOP / 'hw' / topname / 'dv/env/autogen')
delete_path(REPO_TOP / 'hw' / topname / 'ip/ast/rtl')
delete_path(REPO_TOP / 'hw' / topname / 'ip/clkmgr')
delete_path(REPO_TOP / 'hw' / topname / 'ip/flash_ctrl')
delete_path(REPO_TOP / 'hw' / topname / 'ip/pinmux')
delete_path(REPO_TOP / 'hw' / topname / 'ip/pwrmgr')
delete_path(REPO_TOP / 'hw' / topname / 'ip/rstmgr')
delete_path(REPO_TOP / 'hw' / topname / 'ip/sensor_ctrl/rtl')
delete_path(REPO_TOP / 'hw' / topname / 'ip/xbar_main')
delete_path(REPO_TOP / 'hw' / topname / 'ip/xbar_peri')
delete_path(REPO_TOP / 'hw' / topname / 'rtl/autogen')
delete_path(REPO_TOP / 'hw' / topname / 'sw/autogen')
if args.delete_only:
return
# Next, we need to re-run topgen in order to create all auto-generated files.
shell_out([
REPO_TOP / 'util/topgen.py',
'-t',
REPO_TOP / 'hw' / topname / 'data' / f"{topname}.hjson",
'-o',
REPO_TOP / 'hw' / topname,
])
# We need to patch some files:
# 1. Build system files need to be pointed to the proper auto-gen files.
# Specifically, we overwrite the earlgrey autogen-ed files with the
# englishbreakfast equivalents where they differ (i.e. any needed ip in
# `hw/topname/{ip, ip_autogen}`).
# 2. SW sources currently contain
# hardcoded references to top_earlgrey. We
# need to change some file and variable names in auto-generated files.
# 3. The build system still uses some sources from the original top level.
# We thus need to replace those with the new sources patched in 2.
# Patch hjson files for Bazel
print("Transplanting autogen-ed hjson files")
REG_FILES = [
'ip_autogen/alert_handler/data/alert_handler.hjson',
'ip/clkmgr/data/autogen/clkmgr.hjson',
'ip/flash_ctrl/data/autogen/flash_ctrl.hjson',
'ip/pwrmgr/data/autogen/pwrmgr.hjson',
'ip/rstmgr/data/autogen/rstmgr.hjson',
'ip/pinmux/data/autogen/pinmux.hjson',
'ip_autogen/rv_plic/data/rv_plic.hjson',
'ip/ast/data/ast.hjson',
'ip/sensor_ctrl/data/sensor_ctrl.hjson',
]
for reg_file in REG_FILES:
src = REPO_TOP / 'hw' / topname / reg_file
dst = REPO_TOP / 'hw' / 'top_earlgrey' / reg_file
print(f"* Copying {src} -> {dst}")
dst.write_text(src.read_text())
for suffix in ['.c', '.h', '_memory.h', '_memory.ld']:
old = REPO_TOP / 'hw' / topname / 'sw/autogen' / (topname + suffix)
new = REPO_TOP / 'hw/top_earlgrey/sw/autogen' / ('top_earlgrey' +
suffix)
print(f"* {old} -> {new}")
text = old.read_text()
text = text.replace(name, 'earlgrey')
text = text.replace(name.capitalize(), 'Earlgrey')
text = text.replace(name.upper(), 'EARLGREY')
# The SW build expects to find this file both in the top_earlgrey dir AND
# in the top_englishbreakfast dir.
new.write_text(text)
(old.parent / new.name).write_text(text)
if not args.build:
return
# Build the software including test_rom to enable the FPGA build.
shell_out([
REPO_TOP / 'bazelisk.sh',
'build',
'--copt=-DOT_IS_ENGLISH_BREAKFAST_REDUCED_SUPPORT_FOR_INTERNAL_USE_ONLY_',
] + BAZEL_BINARIES)
if __name__ == "__main__":
main()