Files
tt-support-tools/shuttle.py
T
2024-03-13 23:03:07 +02:00

234 lines
8.8 KiB
Python

import glob
import json
import logging
import os
import shutil
from typing import Dict, List
import git
import yaml
from config import Config
from project import Project
from shuttle_index import ShuttleIndex, ShuttleIndexMuxEntry
def copy_print(src: str, dest: str):
os.makedirs(os.path.dirname(dest), exist_ok=True)
logging.info(f" -> {dest}")
shutil.copy2(src, dest)
def copy_print_glob(pattern: str, dest_dir: str):
for file in glob.glob(pattern):
copy_print(file, os.path.join(dest_dir, os.path.basename(file)))
class ShuttleConfig:
def __init__(self, config: Config, projects: List[Project], modules_yaml_name: str):
self.config = config
self.projects = projects
self.script_dir = os.path.dirname(os.path.realpath(__file__))
self.modules_yaml_name = modules_yaml_name
if config.get("openframe", False):
self.tt_top_macro = "openframe_project_wrapper"
else:
self.tt_top_macro = "user_project_wrapper"
def configure_mux(self):
with open(self.modules_yaml_name, "r") as modules_file:
module_config = yaml.safe_load(modules_file)
configured_macros = set(
map(lambda mod: mod["name"], module_config["modules"])
)
logging.info(
f"found {len(configured_macros)} preconfigured macros: {configured_macros}"
)
for project in self.projects:
tiles = project.info.tiles
width, height = map(int, tiles.split("x"))
if project.unprefixed_name not in configured_macros:
module_config["modules"].append(
{
"name": project.unprefixed_name,
"width": width,
"height": height,
}
)
with open("tt-multiplexer/cfg/modules.yaml", "w") as mux_modules_file:
yaml.dump(module_config, mux_modules_file)
res = os.system("make -C tt-multiplexer clean gensrc")
if res != 0:
logging.error("Failed to generate multiplexer placement configuration")
exit(1)
mux_index: Dict[str, ShuttleIndexMuxEntry] = {}
mux_index_reverse = {}
with open("tt-multiplexer/cfg/modules_placed.yaml") as placed_modules_file:
placed_modules = yaml.safe_load(placed_modules_file)
for module in placed_modules["modules"]:
mux_address = (module["mux_id"] << 5) | module["blk_id"]
module_name = "tt_um_" + module["name"]
project = next(
p for p in self.projects if p.info.top_module == module_name
)
project.mux_address = mux_address
mux_index[mux_address] = {
"macro": module_name,
"x": module["x"],
"y": module["y"],
"tiles": f"{module['width']}x{module['height']}",
"repo": project.git_url,
"commit": project.commit_id,
"features": {
"analog": module["analog"],
},
}
mux_index_reverse[module_name] = mux_address
for project in self.projects:
if project.info.top_module not in mux_index_reverse:
logging.error(f"no placement found for {project}!")
exit(1)
project.mux_address = mux_index_reverse[project.info.top_module]
repo = git.Repo(".")
shuttle_index_data: ShuttleIndex = {
"shuttle": self.config["name"],
"repo": list(repo.remotes[0].urls)[0],
"commit": repo.commit().hexsha,
"commit_date": repo.commit().committed_date,
"version": 2,
"mux": mux_index,
}
with open("shuttle_index.json", "w") as shuttle_index_file:
json.dump(shuttle_index_data, shuttle_index_file, indent=2)
with open("verilog/includes/includes.gl.user_projects", "w") as includes_file:
for project in self.projects:
if project.is_chip_rom():
continue
includes_file.write(
f"$(USER_PROJECT_VERILOG)/../projects/{project.info.top_module}/{project.info.top_module}.v\n"
)
def list(self):
for project in self.projects:
logging.info(project)
def find_last_run(self, macro: str):
runs = f"tt-multiplexer/ol2/{macro}/runs/"
if macro == "tt_um_chip_rom":
runs = "tt/rom/runs/"
runlist = sorted(
[
r
for r in os.listdir(runs)
if r.startswith("RUN_") and os.path.isdir(os.path.join(runs, r))
]
)
if len(runlist) == 0:
print(f"Error: no runs found for {macro}")
exit(1)
return os.path.join(runs, runlist[-1])
def copy_macros(self):
logging.info("copying macros to tt_top:")
copy_print_glob("projects/*/*.gds", "tt-multiplexer/ol2/tt_top/gds")
copy_print_glob("projects/*/*.lef", "tt-multiplexer/ol2/tt_top/lef")
copy_print_glob("projects/*/*.v", "tt-multiplexer/ol2/tt_top/verilog")
macros = ["tt_um_chip_rom", "tt_ctrl", "tt_mux"]
for macro in macros:
lastrun = self.find_last_run(macro)
copy_print(
f"{lastrun}/final/gds/{macro}.gds",
f"tt-multiplexer/ol2/tt_top/gds/{macro}.gds",
)
copy_print(
f"{lastrun}/final/lef/{macro}.lef",
f"tt-multiplexer/ol2/tt_top/lef/{macro}.lef",
)
copy_print(
f"{lastrun}/final/pnl/{macro}.pnl.v",
f"tt-multiplexer/ol2/tt_top/verilog/{macro}.v",
)
copy_print_glob(
f"{lastrun}/final/spef/*/*.spef", "tt-multiplexer/ol2/tt_top/spef"
)
# Copy power gate macros:
for macro in ["tt_pg_vdd_1", "tt_pg_vdd_2"]:
copy_print(
f"tt-multiplexer/pg/{macro}/{macro}.gds",
f"tt-multiplexer/ol2/tt_top/gds/{macro}.gds",
)
copy_print(
f"tt-multiplexer/pg/{macro}/{macro}.lef",
f"tt-multiplexer/ol2/tt_top/lef/{macro}.lef",
)
copy_print(
f"tt-multiplexer/pg/{macro}/{macro}.v",
f"tt-multiplexer/ol2/tt_top/verilog/{macro}.v",
)
def copy_final_results(self):
macros = ["tt_um_chip_rom", "tt_ctrl", "tt_mux", "tt_top"]
logging.info("copying final results:")
for macro in macros:
lastrun = self.find_last_run(macro)
macro_name = macro if macro != "tt_top" else self.tt_top_macro
logging.info(f"** {macro_name} **")
logging.info(f" FROM {lastrun}")
copy_print(f"{lastrun}/final/gds/{macro_name}.gds", f"gds/{macro_name}.gds")
copy_print(f"{lastrun}/final/lef/{macro_name}.lef", f"lef/{macro_name}.lef")
copy_print(
f"{lastrun}/final/pnl/{macro_name}.pnl.v", f"verilog/gl/{macro_name}.v"
)
copy_print(
f"{lastrun}/final/nl/{macro_name}.nl.v", f"verilog/gl/{macro_name}.nl.v"
)
shutil.copytree(
f"{lastrun}/final/spef",
f"spef/",
copy_function=copy_print,
dirs_exist_ok=True,
)
# Copy power gate macros:
for macro in ["tt_pg_vdd_1", "tt_pg_vdd_2"]:
copy_print(
f"tt-multiplexer/pg/{macro}/{macro}.gds",
f"gds/{macro}.gds",
)
copy_print(
f"tt-multiplexer/pg/{macro}/{macro}.lef",
f"lef/{macro}.lef",
)
copy_print(
f"tt-multiplexer/pg/{macro}/{macro}.v",
f"verilog/gl/{macro}.v",
)
def create_efabless_submission(self):
logging.info("creating efabless submission directory:")
lastrun = self.find_last_run("tt_top")
copy_print("shuttle_index.md", "efabless/README.md")
copy_print("shuttle_index.json", "efabless/shuttle_index.json")
copy_print("verilog/rtl/user_defines.v", "efabless/verilog/rtl/user_defines.v")
copy_print(
f"{lastrun}/final/pnl/{self.tt_top_macro}.pnl.v",
f"efabless/verilog/gl/{self.tt_top_macro}.v",
)
copy_print(
f"{lastrun}/final/gds/{self.tt_top_macro}.gds",
f"efabless/gds/{self.tt_top_macro}.gds",
)
copy_print(
f"{lastrun}/final/lef/{self.tt_top_macro}.lef",
f"efabless/lef/{self.tt_top_macro}.lef",
)