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/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/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" -""" -