From e19e6cda0cdc37769053b9fc2b01bc18333faea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Wed, 12 Mar 2025 13:17:00 +0100 Subject: [PATCH 1/7] added basic functionality for project files --- scripts/project_man.py | 63 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 scripts/project_man.py diff --git a/scripts/project_man.py b/scripts/project_man.py new file mode 100644 index 0000000..8283dee --- /dev/null +++ b/scripts/project_man.py @@ -0,0 +1,63 @@ +import os +from typing import Any +import toml +import datetime + +def findProjectFile() -> tuple[bool, str]: + cwd = os.getcwd().split("/") + for i in range(len(cwd) - 2): + searchPath = "/".join(cwd[0:len(cwd)-i]) + [exists, pathToProjectFile] = projectFileExists(searchPath) + if exists: + return (True, pathToProjectFile) + return (False, "") + +def projectFileExists(path: str) -> tuple[bool, str]: + files = os.listdir(path) + for file in files: + if "gantry.toml" in file: + return (True, os.path.join(path, file)) + return (False,"") + +def initProjectFile(projectName: str) -> tuple[bool, str]: + cwd = os.getcwd() + projectPath = os.path.join(cwd, "gantry.toml") + [exists, existingProjectPath] = projectFileExists(cwd) + if exists: + existingProjectName = existingProjectPath.split("/")[-1] + return (False, f"Project {existingProjectName} already exists, amend it to fit your intention or delete it to create a new project") + try: + with open(projectPath, "w") as f: + parsedTOML = toml.loads(createProjectFileTemplate(projectName)) + toml.dump(parsedTOML, f) + except: + return (False, "Creation of file failed, permissions may be set wrong") + + return (True, projectPath) + +def loadProjectFile() -> tuple[bool, str | dict[str, Any]] : + [exists, path] = findProjectFile() + if not exists: + return (False, "") + try: + with open(path, "r") as f: + toml.load + parsedTOML = toml.load(f) + print(parsedTOML) + return (True, parsedTOML) + except: + return (False, "Reading Project file failed, permissions may be set wrong") +def createProjectFileTemplate(projectName: str) -> str: + return f""" +title = "{projectName}" +createdAt = "{datetime.time()}" +maintainer = "" +email = "" +version = "0.0.1" +""" + + + +if __name__ == "__main__": + print(loadProjectFile()) + print(findProjectFile()) -- 2.43.0 From 060231ed259a5bb45ac7112f9074de2097dfdb9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Wed, 12 Mar 2025 14:20:10 +0100 Subject: [PATCH 2/7] added more helper functions --- scripts/project_man.py | 49 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/scripts/project_man.py b/scripts/project_man.py index 8283dee..bdd1484 100644 --- a/scripts/project_man.py +++ b/scripts/project_man.py @@ -1,8 +1,16 @@ import os +import re from typing import Any import toml import datetime + +def findProjectRoot() -> tuple[bool, str]: + [exists, projectFile] = findProjectFile() + if not exists: + return (False, "") + return (True, "/".join(projectFile.split("/")[0:-1])) + def findProjectFile() -> tuple[bool, str]: cwd = os.getcwd().split("/") for i in range(len(cwd) - 2): @@ -43,14 +51,48 @@ def loadProjectFile() -> tuple[bool, str | dict[str, Any]] : with open(path, "r") as f: toml.load parsedTOML = toml.load(f) - print(parsedTOML) return (True, parsedTOML) except: return (False, "Reading Project file failed, permissions may be set wrong") + +def writeProjectFile(projectDict: dict[str, Any]) -> tuple[bool, str]: + [exists, path] = findProjectFile() + if not exists: + return (False, "") + try: + with open(path, "w") as f: + toml.dump(projectDict, f) + return (True, "") + except: + return (False, "Reading Project file failed, permissions may be set wrong") + + +def addLibraryInProject(lib: str, std: str) -> tuple[bool, str]: + [exists, output] = loadProjectFile() + if not exists: + return (False, "Project doesn't exist.") + projectDict = {} + if isinstance(output, dict): + projectDict = output + else: + return (False, "Output wasn't a dictionary") + if "libraries" not in projectDict.keys(): + projectDict["libraries"] = {} + if lib not in projectDict["libraries"].keys(): + projectDict["libraries"][lib] = {} + projectDict["libraries"][lib]["vhdl-version"] = std + projectDict["libraries"][lib]["path"] = os.path.join(os.getcwd(), lib) + [wentWell, _] = writeProjectFile(projectDict) + return (wentWell, "") + return (False, "Library with this name is already declared") + + + + def createProjectFileTemplate(projectName: str) -> str: return f""" title = "{projectName}" -createdAt = "{datetime.time()}" +createdAt = "{datetime.date.today()}" maintainer = "" email = "" version = "0.0.1" @@ -59,5 +101,8 @@ version = "0.0.1" if __name__ == "__main__": + print(initProjectFile("test")) print(loadProjectFile()) print(findProjectFile()) + print(findProjectRoot()) + print(addLibraryInProject("ganimede", "93")) -- 2.43.0 From 812b92d352f8cae88b78cb5833503aacbbd27eeb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Wed, 12 Mar 2025 17:27:52 +0100 Subject: [PATCH 3/7] added remove functionality of libraries --- scripts/project_man.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/scripts/project_man.py b/scripts/project_man.py index bdd1484..425ad20 100644 --- a/scripts/project_man.py +++ b/scripts/project_man.py @@ -1,5 +1,4 @@ import os -import re from typing import Any import toml import datetime @@ -66,6 +65,23 @@ def writeProjectFile(projectDict: dict[str, Any]) -> tuple[bool, str]: except: return (False, "Reading Project file failed, permissions may be set wrong") +def removeLibraryInProject(lib: str) -> tuple[bool, str]: + [exists, output] = loadProjectFile() + if not exists: + return (False, "Project doesn't exist.") + projectDict = {} + if isinstance(output, dict): + projectDict = output + else: + return (False, "Output wasn't a dictionary") + if "libraries" not in projectDict.keys(): + return (False, "No libraries are declared in this project.") + if lib in projectDict["libraries"].keys(): + projectDict["libraries"].pop(lib) + [wentWell, _] = writeProjectFile(projectDict) + return (wentWell, "") + return (False, "Library with this name is not declared") + def addLibraryInProject(lib: str, std: str) -> tuple[bool, str]: [exists, output] = loadProjectFile() @@ -86,9 +102,6 @@ def addLibraryInProject(lib: str, std: str) -> tuple[bool, str]: return (wentWell, "") return (False, "Library with this name is already declared") - - - def createProjectFileTemplate(projectName: str) -> str: return f""" title = "{projectName}" @@ -106,3 +119,4 @@ if __name__ == "__main__": print(findProjectFile()) print(findProjectRoot()) print(addLibraryInProject("ganimede", "93")) + print(removeLibraryInProject("ganimede")) -- 2.43.0 From ef1c19604d136100a5365bfd4152e6a73745bccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Thu, 13 Mar 2025 13:46:29 +0100 Subject: [PATCH 4/7] made dockerized ghdl work with multiple directories --- scripts/ghdl | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/ghdl b/scripts/ghdl index cb3df0c..409d0f5 100755 --- a/scripts/ghdl +++ b/scripts/ghdl @@ -1,4 +1,6 @@ #!/bin/bash VARS="$@" COMMAND="ghdl $VARS" -docker run -it -v .:/src -w /src ghdl/ghdl:5.0.0-dev-gcc-ubuntu-24.04 bash -c "$COMMAND" +PROJ_HOME=/home/thesis1/repos/exjobb-public +RELPATH=$(realpath -m --relative-to="$PROJ_HOME" .) +docker run -it -v "$PROJ_HOME"/src:/src -w /"$RELPATH" ghdl/ghdl:5.0.0-dev-gcc-ubuntu-24.04 bash -c "$COMMAND" -- 2.43.0 From 6d0ff8e9325281d1acd55396281f5c32c082112a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Thu, 13 Mar 2025 15:14:27 +0100 Subject: [PATCH 5/7] Added project files to automate library imports --- scripts/build_env.py | 6 +-- scripts/elab.py | 11 +++++- scripts/gantry.py | 57 ++++++++++++++++++++++++---- scripts/project_man.py | 86 ++++++++++++++++++++++++++++-------------- 4 files changed, 119 insertions(+), 41 deletions(-) diff --git a/scripts/build_env.py b/scripts/build_env.py index b6fceff..e73d523 100644 --- a/scripts/build_env.py +++ b/scripts/build_env.py @@ -43,7 +43,7 @@ def addAllVHDLFiles(std: str, lib: str, init=False): return -1 vhdlFiles = [] currentlyAdded = [] - absWorkDir = os.path.join(os.getcwd(), "work") + absWorkDir = "work" cfFileId = getCfFileId(std) ## Find already present files if not init: @@ -53,10 +53,8 @@ def addAllVHDLFiles(std: str, lib: str, init=False): print(currentlyAdded) ## Add files not added for file in os.listdir(): - print(file) - print(currentlyAdded, file, file not in currentlyAdded) if ".vhd" in file and file not in currentlyAdded: - vhdlFiles.append(os.path.join(os.getcwd(), file)) + vhdlFiles.append(file) if len(vhdlFiles) > 0: print(f"Detected new files. Adding {vhdlFiles}") command = ["ghdl", "-i", "--workdir=work", f"--work={lib}", f"--std={std}"] + vhdlFiles diff --git a/scripts/elab.py b/scripts/elab.py index 1d5a040..793a89e 100644 --- a/scripts/elab.py +++ b/scripts/elab.py @@ -2,12 +2,19 @@ import os import subprocess import build_env from typing import List - +from project_man import getLibrariesPresent, getLibrariesInProject def generateIncludesForGHDL(includes: List[str]): cmd = [] + [exists, projectLibs] = getLibrariesInProject() + if not exists: + return [] + for lib in projectLibs.keys(): + includeString = f"{projectLibs[lib]['path']}/work" + cmd.append(f"-P{includeString}") for inc in includes: - cmd.append(f"-P{os.path.join(os.getcwd(), f"{inc}/work")}") + includeString = f"{inc}/work" + cmd.append(f"-P{includeString}") return cmd def elabDesign(topDef: str, arch: str, lib: str, std: str, includes: List[str]): diff --git a/scripts/gantry.py b/scripts/gantry.py index 55f64fb..24c4921 100644 --- a/scripts/gantry.py +++ b/scripts/gantry.py @@ -1,29 +1,61 @@ import typer +import os +from project_man import findProjectFile, initProjectFile, addLibraryInProject, projectFileExists, removeLibraryInProject, getLibrariesPresent import elab as elaborate import build_env from typing import List, Optional from typing_extensions import Annotated import subprocess -gantry_install_path = "/home/thesis2/exjobb-public/scripts" +gantry_install_path = "/home/thesis1/exjobb-public/scripts" app = typer.Typer() +project = typer.Typer() software = typer.Typer() hardware = typer.Typer() +app.add_typer(project, name="project", help="Project management to ease working with the tool") app.add_typer(software, name="sim", help="GHDL simulator command group") app.add_typer(hardware, name="syn", help="Synthesis and deployment command group") + def complete_vhdl_ver(): return ["87", "93", "93c", "00", "02", "08"] +@project.command(help="Creates a project file which allows for further project configuration") +def create( + name: Annotated[str, typer.Argument(help="Name of the project. Has no functional impact")] + ): + print(f"Creating a project at {os.getcwd()}/gantry.toml") + initProjectFile(name) + +@project.command(name="add-lib", help="Initializes a library in the project (non destructive)") +def addLib( + libname: Annotated[str, typer.Argument(help="Name of the library. This is what is used for imports in VHDL.")], + libpath: Annotated[str, typer.Argument(help="Relative path to the library. This tells simulators where to import form.")], + std: Annotated[str, typer.Option(help="Which VHDL standard to use. 87, 93, 93c, 00, 02 or 08", autocompletion=complete_vhdl_ver)] = "93c" + ): + print(f"Adding library {libname} to gantry.toml") + addLibraryInProject(libname, libpath, std) + +@project.command(name="remove-lib", help="Removes a library in the project (non destructive)") +def removeLib( + libname: Annotated[str, typer.Argument(help="Name of the library.")] + ): + print(f"Removing library {libname} from gantry.toml") + removeLibraryInProject(libname) + @software.command(help="Initializes the GHDL build environment in a library named \"work\". Adds all files ending in \".vhd\" to the project") def init( std: Annotated[str, typer.Option(help="Which VHDL standard to use. 87, 93, 93c, 00, 02 or 08", autocompletion=complete_vhdl_ver)] = "93c", - library: Annotated[str, typer.Option("--library", "-l", help="Library to compile from")] = "defaultLib", + library: Annotated[str, typer.Option("--library", "-l", help="Library to compile to. Defaults to \"work\"")] = "work", ): + (exists, _) = findProjectFile() + if exists: + addLibraryInProject(library, ".", std) + return build_env.createBuildEnv(std, library) @@ -31,10 +63,21 @@ def init( def elab( topdef: Annotated[str, typer.Argument(help="Top Definition entity to synthesize")] = "", 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 from")] = "defaultLib", + 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, std: Annotated[str, typer.Option(help="Which VHDL standard to use. 87, 93, 93c, 00, 02 or 08", autocompletion=complete_vhdl_ver)] = "93c" ): + if library == "": + [exists, presentLibs] = getLibrariesPresent() + if not exists: + print("No libs found.") + return + if len(presentLibs.keys()) == 1: + library = presentLibs.popitem()[0] + else: + libs = list(map(lambda x: "\"" + x[0] + "\"", presentLibs.items())) + print("More than one library present, please specify one by adding the flag -l with one of: " + " ".join(libs)) + return print(f"Elaborating {topdef} with arch {arch} in library {library}. VHDL {std}.") if includes is not None: print(f"Including libraries: {includes}") @@ -46,7 +89,7 @@ def elab( def run( topdef: Annotated[str, typer.Argument(help="Top Definition entity to synthesize")] = "", 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 from")] = "defaultLib", + 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, std: Annotated[str, typer.Option(help="Which VHDL standard to use. 87, 93, 93c, 00, 02 or 08", autocompletion=complete_vhdl_ver)] = "93c" ): @@ -60,14 +103,14 @@ 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 from, defaults to \"work\"")] = "defaultLib" + library: Annotated[str, typer.Option("--library", "-l", help="Library to compile todefaults to \"\"")] = "" ): proc = subprocess.run(["source_and_run.sh", f"{gantry_install_path}/nxp_script.py", "synthDesign", library, topdef]) @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 from, defaults to \"work\"")] = "defaultLib" + library: Annotated[str, typer.Option("--library", "-l", help="Library to compile to. If current directory contains libraries, it will be automatically detected")] = "" ): proc = subprocess.run(["source_and_run.sh", f"{gantry_install_path}/nxp_script.py", "placeDesign", library, topdef]) @@ -75,7 +118,7 @@ def place( @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 from, defaults to \"work\"")] = "defaultLib" + library: Annotated[str, typer.Option("--library", "-l", help="Library to compile to. If current directory contains libraries, it will be automatically detected")] = "" ): proc = subprocess.run(["source_and_run.sh", f"{gantry_install_path}/nxp_script.py", "routeDesign", library, topdef]) diff --git a/scripts/project_man.py b/scripts/project_man.py index 425ad20..c1890e5 100644 --- a/scripts/project_man.py +++ b/scripts/project_man.py @@ -4,13 +4,19 @@ import toml import datetime -def findProjectRoot() -> tuple[bool, str]: +def findProjectRoot() -> "tuple[bool, str]": [exists, projectFile] = findProjectFile() if not exists: return (False, "") return (True, "/".join(projectFile.split("/")[0:-1])) -def findProjectFile() -> tuple[bool, str]: +def getRelativePathToRoot(path: str) -> str: + (exists, projectRoot) = findProjectRoot() + if not exists: + return "" + return os.path.relpath(path, projectRoot) + +def findProjectFile() -> "tuple[bool, str]": cwd = os.getcwd().split("/") for i in range(len(cwd) - 2): searchPath = "/".join(cwd[0:len(cwd)-i]) @@ -19,14 +25,14 @@ def findProjectFile() -> tuple[bool, str]: return (True, pathToProjectFile) return (False, "") -def projectFileExists(path: str) -> tuple[bool, str]: +def projectFileExists(path: str) -> "tuple[bool, str]": files = os.listdir(path) for file in files: if "gantry.toml" in file: return (True, os.path.join(path, file)) return (False,"") -def initProjectFile(projectName: str) -> tuple[bool, str]: +def initProjectFile(projectName: str) -> "tuple[bool, str]": cwd = os.getcwd() projectPath = os.path.join(cwd, "gantry.toml") [exists, existingProjectPath] = projectFileExists(cwd) @@ -42,7 +48,7 @@ def initProjectFile(projectName: str) -> tuple[bool, str]: return (True, projectPath) -def loadProjectFile() -> tuple[bool, str | dict[str, Any]] : +def loadProjectFile() -> "tuple[bool, str | dict[str, Any]]" : [exists, path] = findProjectFile() if not exists: return (False, "") @@ -54,7 +60,9 @@ def loadProjectFile() -> tuple[bool, str | dict[str, Any]] : except: return (False, "Reading Project file failed, permissions may be set wrong") -def writeProjectFile(projectDict: dict[str, Any]) -> tuple[bool, str]: + + +def writeProjectFile(projectDict: "dict[str, Any]") -> "tuple[bool, str]": [exists, path] = findProjectFile() if not exists: return (False, "") @@ -65,15 +73,21 @@ def writeProjectFile(projectDict: dict[str, Any]) -> tuple[bool, str]: except: return (False, "Reading Project file failed, permissions may be set wrong") -def removeLibraryInProject(lib: str) -> tuple[bool, str]: +def getProjectDict() -> "tuple[bool, dict[str, Any]]": [exists, output] = loadProjectFile() if not exists: - return (False, "Project doesn't exist.") - projectDict = {} + print(output) + return (False, {}) if isinstance(output, dict): - projectDict = output + return (True, output) else: - return (False, "Output wasn't a dictionary") + print(output) + return (False, {}) + +def removeLibraryInProject(lib: str) -> "tuple[bool, str]": + [exists, projectDict] = getProjectDict() + if not exists: + return (False, "Found no project dictionary") if "libraries" not in projectDict.keys(): return (False, "No libraries are declared in this project.") if lib in projectDict["libraries"].keys(): @@ -83,25 +97,50 @@ def removeLibraryInProject(lib: str) -> tuple[bool, str]: return (False, "Library with this name is not declared") -def addLibraryInProject(lib: str, std: str) -> tuple[bool, str]: - [exists, output] = loadProjectFile() +def addLibraryInProject(lib: str, relPath: str, std: str) -> "tuple[bool, str]": + (exists, projectDict) = getProjectDict() if not exists: return (False, "Project doesn't exist.") - projectDict = {} - if isinstance(output, dict): - projectDict = output - else: - return (False, "Output wasn't a dictionary") if "libraries" not in projectDict.keys(): projectDict["libraries"] = {} if lib not in projectDict["libraries"].keys(): + libDir = getRelativePathToRoot(os.path.join(os.getcwd(), relPath)) projectDict["libraries"][lib] = {} projectDict["libraries"][lib]["vhdl-version"] = std - projectDict["libraries"][lib]["path"] = os.path.join(os.getcwd(), lib) + projectDict["libraries"][lib]["path"] = libDir + os.makedirs(name=relPath,exist_ok=True) + print(libDir) [wentWell, _] = writeProjectFile(projectDict) return (wentWell, "") return (False, "Library with this name is already declared") + +def getLibrariesInProject() -> "tuple[bool, dict[str, Any]]": + (exists, projectDict) = getProjectDict() + if not exists: + return (False, {}) + libs = {} + if "libraries" not in projectDict.keys(): + ## Successful read, no libs found -> empty return + return (True, {}) + (_, projectRoot) = findProjectRoot() + for lib in projectDict["libraries"].keys(): + libs[lib] = projectDict["libraries"][lib] + absPath = os.path.join(projectRoot, libs[lib]["path"]) + libs[lib]["path"] = os.path.relpath(absPath, os.getcwd()) + return (True, libs) + +def getLibrariesPresent() -> "tuple[bool, dict[str, Any]]": + cwd = os.getcwd() + (exists, libs) = getLibrariesInProject() + if not exists: + return (False, {}) + libsInCwd = {} + for lib in libs.keys(): + if os.path.samefile(libs[lib]["path"], cwd): + libsInCwd[lib] = libs[lib] + return (True, libsInCwd) + def createProjectFileTemplate(projectName: str) -> str: return f""" title = "{projectName}" @@ -111,12 +150,3 @@ email = "" version = "0.0.1" """ - - -if __name__ == "__main__": - print(initProjectFile("test")) - print(loadProjectFile()) - print(findProjectFile()) - print(findProjectRoot()) - print(addLibraryInProject("ganimede", "93")) - print(removeLibraryInProject("ganimede")) -- 2.43.0 From 8f44a2b06f83d7eecfde0a40545c70e915edec1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Thu, 13 Mar 2025 17:17:39 +0100 Subject: [PATCH 6/7] refined auto detection of library and std for commands --- scripts/build_env.py | 96 +++++++++++++++++++++++++++++------------- scripts/elab.py | 12 ++---- scripts/gantry.py | 81 ++++++++++++++++++++++++++--------- scripts/project_man.py | 15 +++++-- 4 files changed, 142 insertions(+), 62 deletions(-) diff --git a/scripts/build_env.py b/scripts/build_env.py index e73d523..de63805 100644 --- a/scripts/build_env.py +++ b/scripts/build_env.py @@ -1,6 +1,9 @@ import os from re import split import subprocess +from typing import List + +from project_man import addLibraryInProject, removeLibraryInProject def getCfFileId(std: str): return "08" if std == "08" else "93" ## Weird behaviour from GHDL, but all vhdl versions besides 08 have [...]93.cf @@ -26,45 +29,78 @@ def ghdlEnvExists(std, lib): ## Nothing bad, continue return True -def createBuildEnv(std: str, lib: str): +def addVHDLFiles(fileNames: List[str], std: str, lib: str): + os.makedirs("work", exist_ok=True) + vhdlFiles = [] if ghdlEnvExists(std=std, lib=lib): - print("Build environment already exists, exiting...") - return -1 - ## Create build env - print("Initializing GHDL project in current directory...") - os.makedirs("work",exist_ok=True) - addAllVHDLFiles(std=std, lib=lib, init=True) + cfFileId = getCfFileId(std) + cfFileName = list(filter(lambda x: ".cf" in x and lib in x and cfFileId in x, os.listdir("work")))[0] + cfFilePath = os.path.join("work",cfFileName) + currentlyAdded = getCurrentlyAddedFiles(cfFilePath) + for fileName in fileNames: + if fileName not in currentlyAdded: + vhdlFiles.append(fileName) + else: + addLibraryInProject(lib, ".", std) + vhdlFiles = fileNames + vhdlFiles = list(filter(lambda x: ".vhd" in x, vhdlFiles)) + if len(vhdlFiles) == 0: + print("no files to add.") + return 0 + print(f"adding {vhdlFiles} to library {lib}") + command = ["ghdl", "-i", "--workdir=work", f"--work={lib}", f"--std={std}"] + vhdlFiles + subprocess.run(command) return 0 -def addAllVHDLFiles(std: str, lib: str, init=False): - ## Ensure everything is ready for adding files - ## (init exception to avoid one if-case in ghdlEnvExists) - if not ghdlEnvExists(std=std, lib=lib) and not init: +def removeVHDLFiles(fileNames: List[str], std: str, lib: str): + if not ghdlEnvExists(std=std, lib=lib): return -1 - vhdlFiles = [] - currentlyAdded = [] - absWorkDir = "work" cfFileId = getCfFileId(std) - ## Find already present files - if not init: - cfFileName = list(filter(lambda x: ".cf" in x and lib in x and cfFileId in x, os.listdir(absWorkDir)))[0] - cfFilePath = os.path.join(absWorkDir,cfFileName) - currentlyAdded = getCurrentlyAddedFiles(cfFilePath) - print(currentlyAdded) - ## Add files not added - for file in os.listdir(): - if ".vhd" in file and file not in currentlyAdded: - vhdlFiles.append(file) - if len(vhdlFiles) > 0: - print(f"Detected new files. Adding {vhdlFiles}") - command = ["ghdl", "-i", "--workdir=work", f"--work={lib}", f"--std={std}"] + vhdlFiles - subprocess.run(command) - return 0 + cfFileName = list(filter(lambda x: ".cf" in x and lib in x and cfFileId in x, os.listdir("work")))[0] + cfFilePath = os.path.join("work",cfFileName) + currentlyAdded = getCurrentlyAddedFiles(cfFilePath) + + for fileName in fileNames: + if fileName not in currentlyAdded: + print(f"file {fileName} is not present in {cfFileName}.") + return 0 + currentlyAdded.remove(fileName) + removeCurrentlyAddedFile(fileName, cfFilePath) + if len(currentlyAdded) == 0: + print("Project is empty, removing GHDL project file and library reference in project") + removeLibraryInProject(lib) + os.remove(cfFilePath) + def getCurrentlyAddedFiles(cfFilePath:str): f = open(cfFilePath,"r") lines = f.readlines() f.close() fileLines = filter(lambda x: "file" in x, lines) - files = map(lambda x: split("\"",x)[1], fileLines) + files = map(lambda x: split("\" \"",x)[1], fileLines) return list(files) + +def removeCurrentlyAddedFile(fileName: str, cfFilePath: str): + f = open(cfFilePath,"r") + lines = f.readlines() + f.close() + try: + mappedLines = list(map(lambda x: fileName in x, lines)) + index = mappedLines.index(True) + endIndex = len(lines)-1 + for x in range(index+1,len(lines)): + if "file" in lines[x]: + endIndex = x + break + newLines = [] + for x in range(len(lines)): + if x < index or x >= endIndex: + newLines.append(lines[x]) + f = open(cfFilePath, "w") + f.writelines(newLines) + f.close() + except: + print(f"Something went wrong when trying to remove {fileName} from {cfFilePath}. Restoring to original configuration") + f = open(cfFilePath, "w") + f.writelines(lines) + f.close() diff --git a/scripts/elab.py b/scripts/elab.py index 793a89e..d5be319 100644 --- a/scripts/elab.py +++ b/scripts/elab.py @@ -18,20 +18,16 @@ def generateIncludesForGHDL(includes: List[str]): return cmd def elabDesign(topDef: str, arch: str, lib: str, std: str, includes: List[str]): - ## Add all source files present in pwd - if build_env.addAllVHDLFiles(std, lib) == -1: - print("Adding files failed. GHDL Build environment may be broken...") - return -1 + if not build_env.ghdlEnvExists(std, lib): + print("No GHDL environment present. Add all needed files before elaborating") incs = generateIncludesForGHDL(includes) command = [ "ghdl", "-m", "--workdir=work", f"--work={lib}", f"--std={std}"] + incs + ["-o", f"work/{topDef}-{arch}", f"work.{topDef}", f"{arch}"] subprocess.run(command) def runDesign(topDef: str, arch: str, lib: str, std: str, includes): - ## elaborate first, then run - if elabDesign(topDef, arch, lib, std, includes) == -1: - print("Elaboration failed...") - return -1 + if not build_env.ghdlEnvExists(std, lib): + print("No GHDL environment present. Add all needed files before elaborating") os.makedirs("wave",exist_ok=True) wavePath = os.path.join(os.getcwd(), "wave") incs = generateIncludesForGHDL(includes) diff --git a/scripts/gantry.py b/scripts/gantry.py index 24c4921..13362aa 100644 --- a/scripts/gantry.py +++ b/scripts/gantry.py @@ -1,6 +1,6 @@ import typer import os -from project_man import findProjectFile, initProjectFile, addLibraryInProject, projectFileExists, removeLibraryInProject, getLibrariesPresent +from project_man import findProjectFile, getLibraryInProject, initProjectFile, addLibraryInProject, removeLibraryInProject, getLibrariesPresent import elab as elaborate import build_env from typing import List, Optional @@ -19,6 +19,40 @@ app.add_typer(project, name="project", help="Project management to ease working app.add_typer(software, name="sim", help="GHDL simulator command group") app.add_typer(hardware, name="syn", help="Synthesis and deployment command group") +def autoDetectLibrary(lib: str) -> str: + if lib == "": + [exists, presentLibs] = getLibrariesPresent() + if not exists: + print("No libs found.") + return "work" + if len(presentLibs.keys()) == 1: + return presentLibs.popitem()[0] + else: + libs = list(map(lambda x: x[0], presentLibs.items())) + libsText = list(map(lambda i: f"{i}" + ": \"" + libs[i] + "\"", [x for x in range(len(libs))])) + selectionIndex = 0 + while True: + try: + selectionIndex = int(input("More than one library present, please choose: \n" + "\n".join(libsText) + "\n")) + if selectionIndex < 0 or selectionIndex >=len(libs): + raise ValueError + else: + break + except ValueError: + print("Invalid input!"), + return libs[selectionIndex] + else: + return lib + +def autoDetectStd(library: str, std: str) -> str: + if std == "" or std not in complete_vhdl_ver(): + (exists, libDict) = getLibraryInProject(library) + if not exists: + return "93" + else: + return libDict["vhdl-version"] + else: + return std def complete_vhdl_ver(): return ["87", "93", "93c", "00", "02", "08"] @@ -35,7 +69,7 @@ def create( def addLib( libname: Annotated[str, typer.Argument(help="Name of the library. This is what is used for imports in VHDL.")], libpath: Annotated[str, typer.Argument(help="Relative path to the library. This tells simulators where to import form.")], - std: Annotated[str, typer.Option(help="Which VHDL standard to use. 87, 93, 93c, 00, 02 or 08", autocompletion=complete_vhdl_ver)] = "93c" + std: Annotated[str, typer.Option(help="Which VHDL standard to use. 87, 93, 93c, 00, 02 or 08", autocompletion=complete_vhdl_ver)] = "93" ): print(f"Adding library {libname} to gantry.toml") addLibraryInProject(libname, libpath, std) @@ -47,16 +81,28 @@ def removeLib( print(f"Removing library {libname} from gantry.toml") removeLibraryInProject(libname) -@software.command(help="Initializes the GHDL build environment in a library named \"work\". Adds all files ending in \".vhd\" to the project") -def init( - std: Annotated[str, typer.Option(help="Which VHDL standard to use. 87, 93, 93c, 00, 02 or 08", autocompletion=complete_vhdl_ver)] = "93c", - library: Annotated[str, typer.Option("--library", "-l", help="Library to compile to. Defaults to \"work\"")] = "work", +@software.command(help="Adds files to a library. Automatically updates gantry project file and creates GHDL project files") +def add( + filenames: Annotated[List[str], typer.Argument(help="Which files to add to the library. May be more than one.")], + std: Annotated[str, typer.Option(help="Which VHDL standard to use. 87, 93, 93c, 00, 02 or 08", autocompletion=complete_vhdl_ver)] = "93", + library: Annotated[str, typer.Option("--library", "-l", help="Library to compile to.")] = "" ): + library = autoDetectLibrary(library) + std = autoDetectStd(library, std) (exists, _) = findProjectFile() if exists: addLibraryInProject(library, ".", std) - - return build_env.createBuildEnv(std, library) + return build_env.addVHDLFiles(filenames, std, library) + +@software.command(help="Removes files from a library. Automatically updates gantry project file and creates GHDL project files") +def remove( + filenames: Annotated[List[str], typer.Argument(help="Which files to add to the library. May be more than one.")], + std: Annotated[str, typer.Option(help="Which VHDL standard to use. 87, 93, 93c, 00, 02 or 08", autocompletion=complete_vhdl_ver)] = "93", + library: Annotated[str, typer.Option("--library", "-l", help="Library to compile to.")] = "" + ): + library = autoDetectLibrary(library) + std = autoDetectStd(library, std) + return build_env.removeVHDLFiles(filenames, std, library) @software.command(help="Runs analysis and elaboration on the provided top definition and architecture using GHDL. Automatically adds new files not present in the project") @@ -65,19 +111,10 @@ def elab( 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, - std: Annotated[str, typer.Option(help="Which VHDL standard to use. 87, 93, 93c, 00, 02 or 08", autocompletion=complete_vhdl_ver)] = "93c" + std: Annotated[str, typer.Option(help="Which VHDL standard to use. 87, 93, 93c, 00, 02 or 08", autocompletion=complete_vhdl_ver)] = "93" ): - if library == "": - [exists, presentLibs] = getLibrariesPresent() - if not exists: - print("No libs found.") - return - if len(presentLibs.keys()) == 1: - library = presentLibs.popitem()[0] - else: - libs = list(map(lambda x: "\"" + x[0] + "\"", presentLibs.items())) - print("More than one library present, please specify one by adding the flag -l with one of: " + " ".join(libs)) - return + library = autoDetectLibrary(library) + std = autoDetectStd(library, std) print(f"Elaborating {topdef} with arch {arch} in library {library}. VHDL {std}.") if includes is not None: print(f"Including libraries: {includes}") @@ -91,8 +128,10 @@ def run( 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, - std: Annotated[str, typer.Option(help="Which VHDL standard to use. 87, 93, 93c, 00, 02 or 08", autocompletion=complete_vhdl_ver)] = "93c" + std: Annotated[str, typer.Option(help="Which VHDL standard to use. 87, 93, 93c, 00, 02 or 08", autocompletion=complete_vhdl_ver)] = "93" ): + library = autoDetectLibrary(library) + std = autoDetectStd(library, std) print(f"Running (and synthesizing if needed) {topdef} with arch {arch} in library {library}. VHDL {std}") if includes is not None: print(f"Including libraries: {includes}") diff --git a/scripts/project_man.py b/scripts/project_man.py index c1890e5..55f062d 100644 --- a/scripts/project_man.py +++ b/scripts/project_man.py @@ -60,8 +60,6 @@ def loadProjectFile() -> "tuple[bool, str | dict[str, Any]]" : except: return (False, "Reading Project file failed, permissions may be set wrong") - - def writeProjectFile(projectDict: "dict[str, Any]") -> "tuple[bool, str]": [exists, path] = findProjectFile() if not exists: @@ -114,7 +112,18 @@ def addLibraryInProject(lib: str, relPath: str, std: str) -> "tuple[bool, str]": return (wentWell, "") return (False, "Library with this name is already declared") - +def getLibraryInProject(lib: str) -> "tuple[bool, dict[str, Any]]": + (exists, projectDict) = getProjectDict() + if not exists: + return (False, {}) + libs = {} + if "libraries" not in projectDict.keys(): + ## Successful read, no libs found -> empty return + return (False, {}) + (_, projectRoot) = findProjectRoot() + if lib in projectDict["libraries"].keys(): + return (True, projectDict["libraries"][lib]) + return (False, {}) def getLibrariesInProject() -> "tuple[bool, dict[str, Any]]": (exists, projectDict) = getProjectDict() if not exists: -- 2.43.0 From c3493e12262b4c05bc4f9af24ddf9bfd2eb502dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erik=20=C3=96rtenberg?= Date: Fri, 14 Mar 2025 11:07:55 +0100 Subject: [PATCH 7/7] removed Gantry from this repo and moved into https://git.kryddan.xyz/kryddan/gantry --- scripts/README.md | 6 -- scripts/build_env.py | 106 ------------------------ scripts/dependecies.md | 4 - scripts/elab.py | 42 ---------- scripts/gantry.py | 169 -------------------------------------- scripts/install_gantry.sh | 9 -- scripts/nxp_script.py | 81 ------------------ scripts/project_man.py | 161 ------------------------------------ scripts/requirements.txt | 14 ---- 9 files changed, 592 deletions(-) delete mode 100644 scripts/README.md delete mode 100644 scripts/build_env.py delete mode 100644 scripts/dependecies.md delete mode 100644 scripts/elab.py delete mode 100644 scripts/gantry.py delete mode 100755 scripts/install_gantry.sh delete mode 100644 scripts/nxp_script.py delete mode 100644 scripts/project_man.py delete mode 100644 scripts/requirements.txt diff --git a/scripts/README.md b/scripts/README.md deleted file mode 100644 index 53a3716..0000000 --- a/scripts/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Installation -* Run `python -m venv .` -* Run `./bin/pip install -r requirements.txt` - -# Running -* `./bin/python gantry.py --help` documents how it works diff --git a/scripts/build_env.py b/scripts/build_env.py deleted file mode 100644 index de63805..0000000 --- a/scripts/build_env.py +++ /dev/null @@ -1,106 +0,0 @@ -import os -from re import split -import subprocess -from typing import List - -from project_man import addLibraryInProject, removeLibraryInProject - -def getCfFileId(std: str): - return "08" if std == "08" else "93" ## Weird behaviour from GHDL, but all vhdl versions besides 08 have [...]93.cf - -def ghdlEnvExists(std, lib): - ## Check if work exists - try: - os.lstat("work") - except: - return False - ## Check that work is writable - if not os.access("work", os.W_OK): - print("work is write-protected, please acquire correct permissions") - return False - cfFileExists = False - filesInWork = os.listdir("work") - cfFileId = getCfFileId(std) - for file in filesInWork: - if ".cf" in file and lib in file and cfFileId in file: - cfFileExists = True - if not cfFileExists: - return False - ## Nothing bad, continue - return True - -def addVHDLFiles(fileNames: List[str], std: str, lib: str): - os.makedirs("work", exist_ok=True) - vhdlFiles = [] - if ghdlEnvExists(std=std, lib=lib): - cfFileId = getCfFileId(std) - cfFileName = list(filter(lambda x: ".cf" in x and lib in x and cfFileId in x, os.listdir("work")))[0] - cfFilePath = os.path.join("work",cfFileName) - currentlyAdded = getCurrentlyAddedFiles(cfFilePath) - for fileName in fileNames: - if fileName not in currentlyAdded: - vhdlFiles.append(fileName) - else: - addLibraryInProject(lib, ".", std) - vhdlFiles = fileNames - vhdlFiles = list(filter(lambda x: ".vhd" in x, vhdlFiles)) - if len(vhdlFiles) == 0: - print("no files to add.") - return 0 - print(f"adding {vhdlFiles} to library {lib}") - command = ["ghdl", "-i", "--workdir=work", f"--work={lib}", f"--std={std}"] + vhdlFiles - subprocess.run(command) - return 0 - -def removeVHDLFiles(fileNames: List[str], std: str, lib: str): - if not ghdlEnvExists(std=std, lib=lib): - return -1 - cfFileId = getCfFileId(std) - cfFileName = list(filter(lambda x: ".cf" in x and lib in x and cfFileId in x, os.listdir("work")))[0] - cfFilePath = os.path.join("work",cfFileName) - currentlyAdded = getCurrentlyAddedFiles(cfFilePath) - - for fileName in fileNames: - if fileName not in currentlyAdded: - print(f"file {fileName} is not present in {cfFileName}.") - return 0 - currentlyAdded.remove(fileName) - removeCurrentlyAddedFile(fileName, cfFilePath) - if len(currentlyAdded) == 0: - print("Project is empty, removing GHDL project file and library reference in project") - removeLibraryInProject(lib) - os.remove(cfFilePath) - - -def getCurrentlyAddedFiles(cfFilePath:str): - f = open(cfFilePath,"r") - lines = f.readlines() - f.close() - fileLines = filter(lambda x: "file" in x, lines) - files = map(lambda x: split("\" \"",x)[1], fileLines) - return list(files) - -def removeCurrentlyAddedFile(fileName: str, cfFilePath: str): - f = open(cfFilePath,"r") - lines = f.readlines() - f.close() - try: - mappedLines = list(map(lambda x: fileName in x, lines)) - index = mappedLines.index(True) - endIndex = len(lines)-1 - for x in range(index+1,len(lines)): - if "file" in lines[x]: - endIndex = x - break - newLines = [] - for x in range(len(lines)): - if x < index or x >= endIndex: - newLines.append(lines[x]) - f = open(cfFilePath, "w") - f.writelines(newLines) - f.close() - except: - print(f"Something went wrong when trying to remove {fileName} from {cfFilePath}. Restoring to original configuration") - f = open(cfFilePath, "w") - f.writelines(lines) - f.close() diff --git a/scripts/dependecies.md b/scripts/dependecies.md deleted file mode 100644 index 0feb6b1..0000000 --- a/scripts/dependecies.md +++ /dev/null @@ -1,4 +0,0 @@ -* GHDL = 4.1.0 -* Python >= 3.0.0 -* gtkwave >= v3.3.120 - diff --git a/scripts/elab.py b/scripts/elab.py deleted file mode 100644 index d5be319..0000000 --- a/scripts/elab.py +++ /dev/null @@ -1,42 +0,0 @@ -import os -import subprocess -import build_env -from typing import List -from project_man import getLibrariesPresent, getLibrariesInProject - -def generateIncludesForGHDL(includes: List[str]): - cmd = [] - [exists, projectLibs] = getLibrariesInProject() - if not exists: - return [] - for lib in projectLibs.keys(): - includeString = f"{projectLibs[lib]['path']}/work" - cmd.append(f"-P{includeString}") - for inc in includes: - includeString = f"{inc}/work" - cmd.append(f"-P{includeString}") - return cmd - -def elabDesign(topDef: str, arch: str, lib: str, std: str, includes: List[str]): - if not build_env.ghdlEnvExists(std, lib): - print("No GHDL environment present. Add all needed files before elaborating") - incs = generateIncludesForGHDL(includes) - command = [ - "ghdl", "-m", "--workdir=work", f"--work={lib}", f"--std={std}"] + incs + ["-o", f"work/{topDef}-{arch}", f"work.{topDef}", f"{arch}"] - subprocess.run(command) - -def runDesign(topDef: str, arch: str, lib: str, std: str, includes): - if not build_env.ghdlEnvExists(std, lib): - print("No GHDL environment present. Add all needed files before elaborating") - os.makedirs("wave",exist_ok=True) - wavePath = os.path.join(os.getcwd(), "wave") - incs = generateIncludesForGHDL(includes) - command = [ ## may add -v for verbose - "ghdl", "--elab-run", f"--workdir=work", f"--work={lib}", f"--std={std}"] + incs + ["-o", f"work/{topDef}-{arch}", f"{topDef}", f"{arch}", - f"--wave=wave/{topDef}-{arch}.ghw" ##, "--read-wave-opt= str: - if lib == "": - [exists, presentLibs] = getLibrariesPresent() - if not exists: - print("No libs found.") - return "work" - if len(presentLibs.keys()) == 1: - return presentLibs.popitem()[0] - else: - libs = list(map(lambda x: x[0], presentLibs.items())) - libsText = list(map(lambda i: f"{i}" + ": \"" + libs[i] + "\"", [x for x in range(len(libs))])) - selectionIndex = 0 - while True: - try: - selectionIndex = int(input("More than one library present, please choose: \n" + "\n".join(libsText) + "\n")) - if selectionIndex < 0 or selectionIndex >=len(libs): - raise ValueError - else: - break - except ValueError: - print("Invalid input!"), - return libs[selectionIndex] - else: - return lib - -def autoDetectStd(library: str, std: str) -> str: - if std == "" or std not in complete_vhdl_ver(): - (exists, libDict) = getLibraryInProject(library) - if not exists: - return "93" - else: - return libDict["vhdl-version"] - else: - return std - -def complete_vhdl_ver(): - return ["87", "93", "93c", "00", "02", "08"] - - -@project.command(help="Creates a project file which allows for further project configuration") -def create( - name: Annotated[str, typer.Argument(help="Name of the project. Has no functional impact")] - ): - print(f"Creating a project at {os.getcwd()}/gantry.toml") - initProjectFile(name) - -@project.command(name="add-lib", help="Initializes a library in the project (non destructive)") -def addLib( - libname: Annotated[str, typer.Argument(help="Name of the library. This is what is used for imports in VHDL.")], - libpath: Annotated[str, typer.Argument(help="Relative path to the library. This tells simulators where to import form.")], - std: Annotated[str, typer.Option(help="Which VHDL standard to use. 87, 93, 93c, 00, 02 or 08", autocompletion=complete_vhdl_ver)] = "93" - ): - print(f"Adding library {libname} to gantry.toml") - addLibraryInProject(libname, libpath, std) - -@project.command(name="remove-lib", help="Removes a library in the project (non destructive)") -def removeLib( - libname: Annotated[str, typer.Argument(help="Name of the library.")] - ): - print(f"Removing library {libname} from gantry.toml") - removeLibraryInProject(libname) - -@software.command(help="Adds files to a library. Automatically updates gantry project file and creates GHDL project files") -def add( - filenames: Annotated[List[str], typer.Argument(help="Which files to add to the library. May be more than one.")], - std: Annotated[str, typer.Option(help="Which VHDL standard to use. 87, 93, 93c, 00, 02 or 08", autocompletion=complete_vhdl_ver)] = "93", - library: Annotated[str, typer.Option("--library", "-l", help="Library to compile to.")] = "" - ): - library = autoDetectLibrary(library) - std = autoDetectStd(library, std) - (exists, _) = findProjectFile() - if exists: - addLibraryInProject(library, ".", std) - return build_env.addVHDLFiles(filenames, std, library) - -@software.command(help="Removes files from a library. Automatically updates gantry project file and creates GHDL project files") -def remove( - filenames: Annotated[List[str], typer.Argument(help="Which files to add to the library. May be more than one.")], - std: Annotated[str, typer.Option(help="Which VHDL standard to use. 87, 93, 93c, 00, 02 or 08", autocompletion=complete_vhdl_ver)] = "93", - library: Annotated[str, typer.Option("--library", "-l", help="Library to compile to.")] = "" - ): - library = autoDetectLibrary(library) - std = autoDetectStd(library, std) - return build_env.removeVHDLFiles(filenames, std, library) - - -@software.command(help="Runs analysis and elaboration on the provided top definition and architecture using GHDL. Automatically adds new files not present in the project") -def elab( - topdef: Annotated[str, typer.Argument(help="Top Definition entity to synthesize")] = "", - 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, - std: Annotated[str, typer.Option(help="Which VHDL standard to use. 87, 93, 93c, 00, 02 or 08", autocompletion=complete_vhdl_ver)] = "93" - ): - library = autoDetectLibrary(library) - std = autoDetectStd(library, std) - print(f"Elaborating {topdef} with arch {arch} in library {library}. VHDL {std}.") - if includes is not None: - print(f"Including libraries: {includes}") - else: - includes = [] - return elaborate.elabDesign(topdef, arch, library, std, includes) - -@software.command(help="Simulates elaborated design in GHDL and views waves in gtkwave. Automatically runs `gantry elab` on the same top def and arch.") -def run( - topdef: Annotated[str, typer.Argument(help="Top Definition entity to synthesize")] = "", - 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, - std: Annotated[str, typer.Option(help="Which VHDL standard to use. 87, 93, 93c, 00, 02 or 08", autocompletion=complete_vhdl_ver)] = "93" - ): - library = autoDetectLibrary(library) - std = autoDetectStd(library, std) - print(f"Running (and synthesizing if needed) {topdef} with arch {arch} in library {library}. VHDL {std}") - if includes is not None: - print(f"Including libraries: {includes}") - else: - includes = [] - return elaborate.runDesign(topdef, arch, library, std, includes) - -@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 \"\"")] = "" - ): - proc = subprocess.run(["source_and_run.sh", f"{gantry_install_path}/nxp_script.py", "synthDesign", library, topdef]) - -@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")] = "" - ): - 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")] = "" - ): - proc = subprocess.run(["source_and_run.sh", f"{gantry_install_path}/nxp_script.py", "routeDesign", library, topdef]) - -@hardware.command(help="") -def build(): - print("Build!") - -if __name__ == "__main__": - app() diff --git a/scripts/install_gantry.sh b/scripts/install_gantry.sh deleted file mode 100755 index f886ba3..0000000 --- a/scripts/install_gantry.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -PWD=$(pwd) -ESCAPED_PWD=$(printf '%s\n' "$PWD" | sed -e 's/[\/&]/\\&/g') -echo $ESCAPED_PWD -sed -i "0,/gantry_install_path =\"\"/s/gantry_install_path = \"\"/gantry_install_path = \"$ESCAPED_PWD\"/" gantry.py -printf "#!/bin/bash \n$PWD/bin/python3 $PWD/gantry.py \$@" > "$PWD/gantry" -chmod +x "$PWD/gantry" - diff --git a/scripts/nxp_script.py b/scripts/nxp_script.py deleted file mode 100644 index fc310b7..0000000 --- a/scripts/nxp_script.py +++ /dev/null @@ -1,81 +0,0 @@ -import os -import subprocess -import build_env -import sys -import traceback -from nxpython import * - -artifact_path = "" - -# Evaluate whether we want the user to provide a selection of files -def makeProject(library: str, project_name: 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") - 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") - 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): - # 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) - getProject().loadNative(os.path.join(artifact_path, project_name + ".nym")) - 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): - # 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) - getProject().load(os.path.join(artifact_path, project_name + "-synth.nym")) - getProject().progress("Place", 5) - getProject().save(os.path.join(artifact_path, project_name + "-place.nym")) - -def routeDesign(library: str, project_name: 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) - getProject().load(os.path.join(artifact_path, project_name + "-place.nym")) - getProject().progress("Route", 3) - getProject().save(os.path.join(artifact_path, project_name + "-route.nym")) - - -if __name__ == "__main__": - path = os.getcwd() - 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) - getProject().createAnalyzer() - getProject().getAnalyzer().launch(conditions="worstcase", maximumSlack=0, searchPathsLimit=10, synthesisMode=False) diff --git a/scripts/project_man.py b/scripts/project_man.py deleted file mode 100644 index 55f062d..0000000 --- a/scripts/project_man.py +++ /dev/null @@ -1,161 +0,0 @@ -import os -from typing import Any -import toml -import datetime - - -def findProjectRoot() -> "tuple[bool, str]": - [exists, projectFile] = findProjectFile() - if not exists: - return (False, "") - return (True, "/".join(projectFile.split("/")[0:-1])) - -def getRelativePathToRoot(path: str) -> str: - (exists, projectRoot) = findProjectRoot() - if not exists: - return "" - return os.path.relpath(path, projectRoot) - -def findProjectFile() -> "tuple[bool, str]": - cwd = os.getcwd().split("/") - for i in range(len(cwd) - 2): - searchPath = "/".join(cwd[0:len(cwd)-i]) - [exists, pathToProjectFile] = projectFileExists(searchPath) - if exists: - return (True, pathToProjectFile) - return (False, "") - -def projectFileExists(path: str) -> "tuple[bool, str]": - files = os.listdir(path) - for file in files: - if "gantry.toml" in file: - return (True, os.path.join(path, file)) - return (False,"") - -def initProjectFile(projectName: str) -> "tuple[bool, str]": - cwd = os.getcwd() - projectPath = os.path.join(cwd, "gantry.toml") - [exists, existingProjectPath] = projectFileExists(cwd) - if exists: - existingProjectName = existingProjectPath.split("/")[-1] - return (False, f"Project {existingProjectName} already exists, amend it to fit your intention or delete it to create a new project") - try: - with open(projectPath, "w") as f: - parsedTOML = toml.loads(createProjectFileTemplate(projectName)) - toml.dump(parsedTOML, f) - except: - return (False, "Creation of file failed, permissions may be set wrong") - - return (True, projectPath) - -def loadProjectFile() -> "tuple[bool, str | dict[str, Any]]" : - [exists, path] = findProjectFile() - if not exists: - return (False, "") - try: - with open(path, "r") as f: - toml.load - parsedTOML = toml.load(f) - return (True, parsedTOML) - except: - return (False, "Reading Project file failed, permissions may be set wrong") - -def writeProjectFile(projectDict: "dict[str, Any]") -> "tuple[bool, str]": - [exists, path] = findProjectFile() - if not exists: - return (False, "") - try: - with open(path, "w") as f: - toml.dump(projectDict, f) - return (True, "") - except: - return (False, "Reading Project file failed, permissions may be set wrong") - -def getProjectDict() -> "tuple[bool, dict[str, Any]]": - [exists, output] = loadProjectFile() - if not exists: - print(output) - return (False, {}) - if isinstance(output, dict): - return (True, output) - else: - print(output) - return (False, {}) - -def removeLibraryInProject(lib: str) -> "tuple[bool, str]": - [exists, projectDict] = getProjectDict() - if not exists: - return (False, "Found no project dictionary") - if "libraries" not in projectDict.keys(): - return (False, "No libraries are declared in this project.") - if lib in projectDict["libraries"].keys(): - projectDict["libraries"].pop(lib) - [wentWell, _] = writeProjectFile(projectDict) - return (wentWell, "") - return (False, "Library with this name is not declared") - - -def addLibraryInProject(lib: str, relPath: str, std: str) -> "tuple[bool, str]": - (exists, projectDict) = getProjectDict() - if not exists: - return (False, "Project doesn't exist.") - if "libraries" not in projectDict.keys(): - projectDict["libraries"] = {} - if lib not in projectDict["libraries"].keys(): - libDir = getRelativePathToRoot(os.path.join(os.getcwd(), relPath)) - projectDict["libraries"][lib] = {} - projectDict["libraries"][lib]["vhdl-version"] = std - projectDict["libraries"][lib]["path"] = libDir - os.makedirs(name=relPath,exist_ok=True) - print(libDir) - [wentWell, _] = writeProjectFile(projectDict) - return (wentWell, "") - return (False, "Library with this name is already declared") - -def getLibraryInProject(lib: str) -> "tuple[bool, dict[str, Any]]": - (exists, projectDict) = getProjectDict() - if not exists: - return (False, {}) - libs = {} - if "libraries" not in projectDict.keys(): - ## Successful read, no libs found -> empty return - return (False, {}) - (_, projectRoot) = findProjectRoot() - if lib in projectDict["libraries"].keys(): - return (True, projectDict["libraries"][lib]) - return (False, {}) -def getLibrariesInProject() -> "tuple[bool, dict[str, Any]]": - (exists, projectDict) = getProjectDict() - if not exists: - return (False, {}) - libs = {} - if "libraries" not in projectDict.keys(): - ## Successful read, no libs found -> empty return - return (True, {}) - (_, projectRoot) = findProjectRoot() - for lib in projectDict["libraries"].keys(): - libs[lib] = projectDict["libraries"][lib] - absPath = os.path.join(projectRoot, libs[lib]["path"]) - libs[lib]["path"] = os.path.relpath(absPath, os.getcwd()) - return (True, libs) - -def getLibrariesPresent() -> "tuple[bool, dict[str, Any]]": - cwd = os.getcwd() - (exists, libs) = getLibrariesInProject() - if not exists: - return (False, {}) - libsInCwd = {} - for lib in libs.keys(): - if os.path.samefile(libs[lib]["path"], cwd): - libsInCwd[lib] = libs[lib] - return (True, libsInCwd) - -def createProjectFileTemplate(projectName: str) -> str: - return f""" -title = "{projectName}" -createdAt = "{datetime.date.today()}" -maintainer = "" -email = "" -version = "0.0.1" -""" - diff --git a/scripts/requirements.txt b/scripts/requirements.txt deleted file mode 100644 index 5f05862..0000000 --- a/scripts/requirements.txt +++ /dev/null @@ -1,14 +0,0 @@ -attrs==21.4.0 -click==8.0.4 -commonmark==0.9.1 -dataclasses==0.8 -importlib-metadata==4.8.3 -markdown-it-py==2.0.1 -mdurl==0.1.0 -Pygments==2.14.0 -rich==12.6.0 -shellingham==1.4.0 -type-extensions==0.1.2 -typer==0.10.0 -typing_extensions==4.1.1 -zipp==3.6.0 -- 2.43.0