[top_englishbreakfast] Clean up the tree-bodging script

Signed-off-by: Miguel Young de la Sota <mcyoung@google.com>
diff --git a/hw/top_englishbreakfast/util/prepare_sw.py b/hw/top_englishbreakfast/util/prepare_sw.py
index c2891a0..67ad72d 100755
--- a/hw/top_englishbreakfast/util/prepare_sw.py
+++ b/hw/top_englishbreakfast/util/prepare_sw.py
@@ -2,74 +2,99 @@
 # Copyright lowRISC contributors.
 # Licensed under the Apache License, Version 2.0, see LICENSE for details.
 # SPDX-License-Identifier: Apache-2.0
-r"""Script to prepare SW for non-earlgrey tops
+
+"""
+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 sys
+import shutil
 import subprocess
-import re
+
 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_nexysvideo',
+    'sw/device/sca/aes_serial_export_fpga_nexysvideo',
+    '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',
+]
+
+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(
+        '--top',
+        '-t',
+        default='englishbreakfast',
+        type=str,
+        help='The alternative top to use')
     args = parser.parse_args()
-
-    # Config
-    name_old = 'earlgrey'
-    name = 'englishbreakfast'
-
-    topname = 'top_' + name
-
-    path_root = str(Path(__file__).resolve().parents[3])
+    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.
-    cmd = [path_root + '/hw/' + topname + '/util/remove_autogen_files.sh']
+    print('Purging earlgrey autogen files')
+    for d in find_dirs(REPO_TOP / 'hw', ['autogen', 'ip_autogen']):
+        delete_path(d)
 
-    try:
-        print("Removing auto-generated files...")
-        subprocess.run(cmd,
-                       check=True,
-                       stdout=subprocess.PIPE,
-                       stderr=subprocess.STDOUT,
-                       universal_newlines=True)
+    delete_path(REPO_TOP / 'hw/ip/ast/rtl')
+    delete_path(REPO_TOP / 'hw/ip/sensor_ctrl/rtl')
+    delete_path(REPO_TOP / 'hw/ip/xbar_main/xbar_main.core')
+    delete_path(REPO_TOP / 'hw/ip/xbar_peri/xbar_peri.core')
 
-    except subprocess.CalledProcessError as e:
-        print("Removing auto-generated files failed: " + str(e))
-        sys.exit(1)
-
-    # Next, we need to run topgen in order to create all auto-generated files.
-    path_in = path_root + '/hw/' + topname + '/data/'
-    path_out = path_root + '/hw/' + topname
-    cmd = [path_root + '/util/topgen.py',  # "--verbose",
-           "-t", path_in + topname + '.hjson',
-           "-o", path_out]
-
-    try:
-        print("Running topgen...")
-        subprocess.run(cmd,
-                       check=True,
-                       stdout=subprocess.PIPE,
-                       stderr=subprocess.STDOUT,
-                       universal_newlines=True)
-
-    except subprocess.CalledProcessError as e:
-        print("topgen failed: " + str(e))
-        sys.exit(1)
+    # 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. meson.build needs to be pointed to the proper auto-gen files.
@@ -78,76 +103,31 @@
     # 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.
 
-    # 1.
-    cmd = ['sed', '-i', "s/TOPNAME='top_{}'/TOPNAME='top_{}'/g".format(name_old, name),
-           path_root + '/meson.build']
-    try:
-        print("Adjusting meson.build...")
-        subprocess.run(cmd,
-                       check=True,
-                       stdout=subprocess.PIPE,
-                       stderr=subprocess.STDOUT,
-                       universal_newlines=True)
+    print("Rewriting $REPO_TOP/meson.build's TOPNAME")
+    meson_build = (REPO_TOP / 'meson.build').read_text()
+    meson_build = meson_build.replace("TOPNAME='top_earlgrey'", f"TOPNAME='{topname}'")
+    (REPO_TOP / 'meson.build').write_text(meson_build)
 
-    except subprocess.CalledProcessError as e:
-        print("Adjustment of meson.build failed: " + str(e))
-        sys.exit(1)
+    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}")
 
-    # 2. and 3.
-    print("Adjusting SW files generated by topgen...")
-    files = ['top_' + name + '.c',
-             'top_' + name + '.h',
-             'top_' + name + '_memory.h',
-             'top_' + name + '_memory.ld']
-    path_in = path_root + '/hw/top_' + name + '/sw/autogen/'
-    path_out = path_root + '/hw/top_' + name_old + '/sw/autogen/'
+        text = old.read_text()
+        text = text.replace(name, 'earlgrey')
+        text = text.replace(name.capitalize(), 'Earlgrey')
+        text = text.replace(name.upper(), 'EARLGREY')
 
-    for file_name in files:
+        # 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)
 
-        # Read file produced by topgen.
-        with open(path_in + file_name, "r") as file_in:
-            text = file_in.read()
+    if not args.build:
+        return;
 
-        text = re.sub(name, name_old, text)
-        text = re.sub(name.capitalize(), name_old.capitalize(), text)
-        text = re.sub(name.upper(), name_old.upper(), text)
-
-        # Write file that SW build can deal with.
-        file_name_new = re.sub(name, name_old, file_name)
-        with open(path_in + file_name_new, "w") as file_out:
-            file_out.write(text)
-
-        # Overwrite the files in the tree of the original top level. They are still used by the
-        # SW build.
-        with open(path_out + file_name_new, "w") as file_out:
-            file_out.write(text)
-
-    if (args.build):
-        # Build the software including test_rom to enable the FPGA build.
-        binaries = [
-            'sw/device/lib/testing/test_rom/test_rom_export_fpga_nexysvideo',
-            'sw/device/sca/aes_serial_export_fpga_nexysvideo',
-            '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',
-        ]
-        for binary in binaries:
-            print("Building " + binary + "...")
-            cmd = ['ninja', '-C', path_root + '/build-out',
-                   binary]
-            try:
-                subprocess.run(cmd,
-                               check=True,
-                               stdout=subprocess.PIPE,
-                               stderr=subprocess.STDOUT,
-                               universal_newlines=True)
-
-            except subprocess.CalledProcessError as e:
-                print("Failed to generate boot ROM: " + str(e))
-                sys.exit(1)
-
-        return 0
-
+    # Build the software including test_rom to enable the FPGA build.
+    shell_out(['ninja', '-C', REPO_TOP / 'build-out'] + BINARIES)
 
 if __name__ == "__main__":
     main()
diff --git a/hw/top_englishbreakfast/util/remove_autogen_files.sh b/hw/top_englishbreakfast/util/remove_autogen_files.sh
deleted file mode 100755
index 599a9ce..0000000
--- a/hw/top_englishbreakfast/util/remove_autogen_files.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/bash
-# Copyright lowRISC contributors.
-# Licensed under the Apache License, Version 2.0, see LICENSE for details.
-# SPDX-License-Identifier: Apache-2.0
-
-# The purpose of this simple script is to remove all auto-generated files for
-# the current top-level design. Except for top_earlgrey, we anyway don't check
-# these files into the repo. This is also useful for debugging topgen by
-# letting it run on a clean directory.
-
-# Get the path to the top-specific directory.
-top_path=$(dirname $(realpath $0))/../
-
-# Find and delete autogen directories.
-find ${top_path} -depth -type d -name "autogen" -exec rm -rf {} \;
-find ${top_path} -depth -type d -name "ip_autogen" -exec rm -rf {} \;
-
-# Some autogen files are not in autogen folders.
-rm -rf ${top_path}/ip/ast/rtl/*
-rm -rf ${top_path}/ip/sensor_ctrl/rtl/*
-rm -rf ${top_path}/ip/xbar_main/xbar_main.core
-rm -rf ${top_path}/ip/xbar_peri/xbar_peri.core
-
-# Remove topgen files for secondary top levels.
-rm -rf build/top_*-autogen/