added support for auto analyzing dependencies (something GHDL really should do by itself, but doesn't for some reason

This commit is contained in:
Erik Örtenberg 2025-03-14 14:46:54 +01:00
parent 3a2151e037
commit 319e3e25c0

View File

@ -1,8 +1,66 @@
import os
import subprocess
import build_env
from re import split, sub
from typing import List
from project_man import getLibrariesPresent, getLibrariesInProject
from project_man import getLibrariesPresent, getLibrariesInProject, getLibraryInProject
## returns list of dicts containing {lib: ..., file: ...} in correct compile order
def getNeededDependencies(topDef: str, arch: str, lib: str, std: str, includes: List[str]):
incs = generateIncludesForGHDL(includes)
disableWarnings = [
"-Wno-library", "-Wno-deprecated-option", "-Wno-unexpected-option",
"-Wno-binding", "-Wno-port", "-Wno-pragma", "-Wno-specs", "-Wno-runtime-error",
"-Wno-missing-wait", "-Wno-shared", "-Wno-hide", "-Wno-nowrite",
"-Wno-logic-loop", "-Wno-pure", "-Wno-analyze-assert", "-Wno-attribute",
"-Wno-useless", "-Wno-open-assoc", "-Wno-conformance", "-Wno-unkept-attribute",
"-Wno-unhandled-attribute", "-Wno-elaboration"
]
command = [
"ghdl", "--elab-order", "--workdir=work", f"--work={lib}", f"--std={std}"
] + incs + disableWarnings + [
"--libraries", f"{topDef}", f"{arch}"
]
res = subprocess.run(command,capture_output=True)
if res.returncode != 0:
print(res.stdout, res.stderr)
res = split("\r\n", res.stdout.decode())
res = res[0:-1]
res = list(map(lambda x: {"lib": split(" ",x)[0], "file": split(" ", x)[1]}, res))
res = list(filter(lambda x: x["lib"] != lib, res))
outputDict = {}
for x in res:
if x["lib"] not in outputDict.keys():
outputDict[x["lib"]] = []
## For some reason, GHDL doesn't play nice with relative include paths, so
## many unnecessary "cd thing/.." occurs in a row. This regex fixes that.
fixed = sub(r"\w*/../","", x["file"])
outputDict[x["lib"]].append(fixed)
print(outputDict)
return outputDict
## anylyzes the needed dependecies such that elaboration using libraries is nice :)
def analyzeNeededDependencies(topDef: str, arch: str, lib: str, std: str, includes: List[str]):
deps = getNeededDependencies(topDef, arch, lib, std, includes)
incs = generateIncludesForGHDL(includes)
print(incs)
[exists, libDict] = getLibrariesInProject()
if not exists:
print("project doesn't exist")
return
for currLib in deps.keys():
currLibPath = libDict[currLib]["path"]
filesNames = list(map(lambda x: split("/",x)[-1],deps[currLib]))
vhdlFiles = list(map(lambda x: os.path.join(currLibPath, x),deps[currLib]))
if len(vhdlFiles) == 0:
continue
print(f"Analyzing dependecies in {currLib}: {filesNames}")
command = [
"ghdl", "-a", f"--workdir={os.path.join(currLibPath, 'work')}", f"--work={currLib}", f"--std={std}"
] + incs + vhdlFiles
subprocess.run(command)
def generateIncludesForGHDL(includes: List[str]):
cmd = []
@ -20,9 +78,12 @@ def generateIncludesForGHDL(includes: List[str]):
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")
analyzeNeededDependencies(topDef, arch, lib, std, includes)
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}"]
"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):
@ -32,11 +93,13 @@ def runDesign(topDef: str, arch: str, lib: str, std: str, includes):
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=<See"
"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=<See"
]
subprocess.run(command)
command = [
"gtkwave", f"{topDef}-{arch}.ghw", "--rcvar",
"do_initial_zoom_fit yes"]
subprocess.run(command, cwd=wavePath)