From 4ea39b4333d6424b35033c1bf956558f57581027 Mon Sep 17 00:00:00 2001 From: Adam Date: Fri, 28 Mar 2025 17:07:38 +0100 Subject: [PATCH] Added library support for nxp_script --- src/gantry.py | 40 +++++++++++++++++++++++++----- src/nxp_script.py | 62 +++++++++++++++++++++++++++------------------- src/project_man.py | 23 +++++++++++++++++ 3 files changed, 94 insertions(+), 31 deletions(-) diff --git a/src/gantry.py b/src/gantry.py index 06bdefd..3e8a526 100644 --- a/src/gantry.py +++ b/src/gantry.py @@ -1,14 +1,22 @@ import typer import os +<<<<<<< HEAD from re import split from project_man import findProjectFile, getLibraryInProject, initProjectFile, addLibraryInProject, removeLibraryInProject, getLibrariesPresent +======= +from project_man import findProjectRoot, getProjectDict, getLibrariesInProject, findProjectFile, getLibraryInProject, getSourceFilesWithLib, initProjectFile, addLibraryInProject, removeLibraryInProject, getLibrariesPresent +>>>>>>> 8bf7864 (Added library support for nxp_script) import elab as elaborate import build_env from typing import List, Optional from typing_extensions import Annotated import subprocess +<<<<<<< HEAD gantry_install_path = "/home/thesis1/repos/gantry/src" +======= +gantry_install_path = "/home/thesis2/gantry/src" +>>>>>>> 8bf7864 (Added library support for nxp_script) app = typer.Typer() @@ -145,22 +153,42 @@ def run( @hardware.command(help="Synthesizes the provided top level design using NXPython. Make sure you run this with NXPython.") def synth( topdef: Annotated[str, typer.Argument(help="Top Definition entity to synthesize")] = "", - library: Annotated[str, typer.Option("--library", "-l", help="Library to compile todefaults to \"\"")] = "" + arch: Annotated[str, typer.Argument(help="Architecture to synthesize within the top definition provided")] = "", + library: Annotated[str, typer.Option("--library", "-l", help="Library to compile to")] = "", + includes: Annotated[Optional[List[str]], typer.Option("--include", "-i", help="Which libraries to include in compile")] = None, ): - proc = subprocess.run(["source_and_run.sh", f"{gantry_install_path}/nxp_script.py", "synthDesign", library, topdef]) + library = autoDetectLibrary(library) + print(f"Synthesizing {topdef} with arch {arch} in library {library}.") + if includes is not None: + print(f"Including libraries: {includes}") + else: + _, includes = getSourceFilesWithLib() # TODO: Error handling + _, proj_root = findProjectRoot() + proc = subprocess.run(["source_and_run.sh", # Source NXPython + f"{gantry_install_path}/nxp_script.py", # Run script + "synthDesign", # Function call + library, # Function arguments + topdef, + proj_root] + + includes + ) @hardware.command(help="Places the provided top level design using NXPython. Make sure you run this with NXPython.") def place( - topdef: Annotated[str, typer.Argument(help="Top Definition entity to synthesize")] = "", - library: Annotated[str, typer.Option("--library", "-l", help="Library to compile to. If current directory contains libraries, it will be automatically detected")] = "" + topdef: Annotated[str, typer.Argument(help="Top Definition entity to place")] = "", + arch: Annotated[str, typer.Argument(help="Architecture to place within the top definition provided")] = "", + library: Annotated[str, typer.Option("--library", "-l", help="Library to compile to. If current directory contains libraries, it will be automatically detected")] = "", + includes: Annotated[Optional[List[str]], typer.Option("--include", "-i", help="Which libraries to include in compile")] = None, ): proc = subprocess.run(["source_and_run.sh", f"{gantry_install_path}/nxp_script.py", "placeDesign", library, topdef]) @hardware.command(help="Routes the provided top level design using NXPython. Make sure you run this with NXPython.") def route( - topdef: Annotated[str, typer.Argument(help="Top Definition entity to synthesize")] = "", - library: Annotated[str, typer.Option("--library", "-l", help="Library to compile to. If current directory contains libraries, it will be automatically detected")] = "" + topdef: Annotated[str, typer.Argument(help="Top Definition entity to route")] = "", + arch: Annotated[str, typer.Argument(help="Architecture to route within the top definition provided")] = "", + library: Annotated[str, typer.Option("--library", "-l", help="Library to compile to. If current directory contains libraries, it will be automatically detected")] = "", + includes: Annotated[Optional[List[str]], typer.Option("--include", "-i", help="Which libraries to include in compile")] = None, ): proc = subprocess.run(["source_and_run.sh", f"{gantry_install_path}/nxp_script.py", "routeDesign", library, topdef]) diff --git a/src/nxp_script.py b/src/nxp_script.py index fc310b7..21e032c 100644 --- a/src/nxp_script.py +++ b/src/nxp_script.py @@ -1,72 +1,79 @@ import os import subprocess -import build_env import sys import traceback from nxpython import * artifact_path = "" + +def getNXFormatedIncludes(path, libs) -> "tuple[bool, list[tuple[str, str]]]": + printRemark("These libraries exst in the project: " + str(libs)) + includes = [] + for lib in libs: + listed = list(os.listdir(os.path.join(path, lib))) + files = list(filter(lambda x: ".vhdl" in x or ".vhd" in x or ".v\0" in x, listed)) # Find VHDL and Verilog files + lib_name = str.split(lib, "/")[-1] + includes = includes + list(map(lambda x: (lib_name, os.path.join(lib, x)), files)) + return (True, includes) + # Evaluate whether we want the user to provide a selection of files -def makeProject(library: str, project_name: str, path): +def makeProject(library: str, project_name: str, includes: "list[str]", path): # Create an Impulse project and add all VHDL files to it - print(path) - #Createproject enters the implicitly created directory - print(f"Creating project \'{project_name}\'\n") + # Createproject enters the implicitly created directory + printRemark(f"Creating project \'{project_name}\'\n") + printRemark(f"Setting topcell name to {project_name} in library {library}") getProject().setTopCellName(library, project_name) getProject().setVariantName("NG-MEDIUM", "LGA-625") getProject().addParameters({}) - print(path) - listed = list(os.listdir(path)) - files = list(filter(lambda x: ".vhdl" in x or ".vhd" in x or ".v\0" in x, listed)) # Find VHDL and Verilog files - files = list(map(lambda x: os.path.join(path, x), files)) - print(f"Adding the following files to project: {files}\n") - getProject().addFiles(files) - print("Saving project") + for lib, file in includes: + printRemark(f"Adding file {os.path.join(path, file)} from lib {lib}") + getProject().addFile(lib, os.path.join(path, file)) + printRemark("Saving project") getProject().save(os.path.join(artifact_path, project_name + ".nym")) return 0 # Do we want the user to specify how far they want to progress wach step? What does the number mean? -def synthDesign(library: str, project_name: str, path): +def synthDesign(library: str, project_name: str, includes: "list[str]", path): # Synthesize the design of the project of the provided `project_name` - print("Starting synthesis\n") try: nymFile = os.path.join(artifact_path, project_name + ".nym") os.lstat(nymFile) getProject().loadNative(nymFile) except: - print("No existing project found, creating new project\n") - makeProject(library, project_name, path) + printRemark("No existing project found, creating new project\n") + makeProject(library, project_name, includes, path) getProject().loadNative(os.path.join(artifact_path, project_name + ".nym")) + printRemark("Starting synthesis\n") getProject().progress("Synthesize", 3) getProject().save(os.path.join(artifact_path, project_name + "-synth.nym")) return 0 -def placeDesign(library: str, project_name: str, path): +def placeDesign(library: str, project_name: str, includes: "list[str]", path): # Place the given design. Will use a previously synthesized project if available, otherwise one will be created. - print("Starting place\n") try: nymFile = os.path.join(artifact_path, project_name + "-synth.nym") os.lstat(nymFile) getProject().load(nymFile) except: - print("No existing synthesis found, entering synthesis stage\n") - synthDesign(library, project_name, path) + printRemark("No existing synthesis found, entering synthesis stage\n") + synthDesign(library, project_name, includes, path) getProject().load(os.path.join(artifact_path, project_name + "-synth.nym")) + printRemark("Starting place\n") getProject().progress("Place", 5) getProject().save(os.path.join(artifact_path, project_name + "-place.nym")) -def routeDesign(library: str, project_name: str, path): +def routeDesign(library: str, project_name: str, includes: "list[str]", path): # Route the given design. Will use a previously placed project if available, otherwise one will be created. - print("Starting route\n") try: nymFile = os.path.join(artifact_path, project_name + "-place.nym") os.lstat(nymFile) getProject().load(nymFile) except: - print("No existing place found, entering place stage\n") - placeDesign(library, project_name, path) + printRemark("No existing place found, entering place stage\n") + placeDesign(library, project_name, includes, path) getProject().load(os.path.join(artifact_path, project_name + "-place.nym")) + printRemark("Starting route\n") getProject().progress("Route", 3) getProject().save(os.path.join(artifact_path, project_name + "-route.nym")) @@ -76,6 +83,11 @@ if __name__ == "__main__": artifact_path = os.path.join(path, "syn") print(f"Calling {sys.argv[1]}() with arguments {sys.argv[2]}, {sys.argv[3]}") createProject(artifact_path) - globals()[sys.argv[1]](sys.argv[2], sys.argv[3], path) + nx_includes = [] + for i in range(5, len(sys.argv[5:]), 2): + nx_includes.append((sys.argv[i], sys.argv[i + 1])) + printRemark("\nNX_INCLUDES ARE: " + str(nx_includes) + "\n") + # (Library, Topdef, Includes, Working_dir) + globals()[sys.argv[1]](sys.argv[2], sys.argv[3], nx_includes, path) getProject().createAnalyzer() getProject().getAnalyzer().launch(conditions="worstcase", maximumSlack=0, searchPathsLimit=10, synthesisMode=False) diff --git a/src/project_man.py b/src/project_man.py index 14c66d0..1584c03 100644 --- a/src/project_man.py +++ b/src/project_man.py @@ -127,6 +127,7 @@ def getLibraryInProject(lib: str, cwd=os.getcwd()) -> "tuple[bool, dict[str, Any libs[lib]["path"] = os.path.relpath(absPath, cwd) return (True, libs) return (False, {}) + def getLibrariesInProject(cwd=os.getcwd()) -> "tuple[bool, dict[str, Any]]": (exists, projectDict) = getProjectDict() if not exists: @@ -152,6 +153,28 @@ def getLibrariesPresent(cwd=os.getcwd()) -> "tuple[bool, dict[str, Any]]": libsInCwd[lib] = libs[lib] return (True, libsInCwd) +# TODO: Make this function recursively look in folders in the library directory +# Returns a list in the format [, , , ...] +# This is used for sending the files to NXPython +def getSourceFilesWithLib() -> "tuple[bool, list[str]]": + exists, proj_dict = getProjectDict() + if not exists: + return (False, []) + if "libraries" not in proj_dict.keys(): + ## Successful read, no libs found -> empty return + return (True, []) + _, proj_root = findProjectRoot() + result = [] + cwd = os.getcwd() + for lib in proj_dict["libraries"].keys(): + listed = list(os.listdir(os.path.join(proj_root, lib))) + files = list(filter(lambda x: ".vhdl" in x or ".vhd" in x or ".v\0" in x, listed)) # Find VHDL and Verilog files + for file in files: + result.append(lib) + rel_file_path = os.path.relpath(os.path.join(proj_root, lib, file), cwd) + result.append(rel_file_path) + return (True, result) + def createProjectFileTemplate(projectName: str) -> str: return f""" title = "{projectName}"