Introduces support for Xilinx ISE build flow
Adds scripts and utilities for synthesis, mapping, placement, and bitstream generation using Xilinx ISE tools. Refactors configuration management into a dedicated module. Updates project model to support tool-specific options. Adjusts `.gitignore` and Python version compatibility. Simplifies directory handling and ensures modularity by reorganizing configuration and tool logic.
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -183,4 +183,5 @@ output/
|
||||
vhdl/
|
||||
poetry.lock
|
||||
project.yml
|
||||
.project/
|
||||
.project/
|
||||
.devcontainer/
|
@@ -7,7 +7,7 @@ license = "MIT"
|
||||
readme = "README.md"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.12"
|
||||
python = "^3.10"
|
||||
pyyaml = "^6.0.2"
|
||||
doit = "^0.36.0"
|
||||
pydantic = "^2.11.3"
|
||||
|
@@ -1,14 +0,0 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
class DirectoryConfig(BaseModel):
|
||||
dependency: str = ".hdlbuild_deps"
|
||||
build: str = ".working"
|
||||
report: str = "reports"
|
||||
copy_target: str = "output"
|
||||
|
||||
DIRECTORIES = DirectoryConfig()
|
||||
|
||||
class GitConfig(BaseModel):
|
||||
timeout: int = 10
|
||||
|
||||
GIT = GitConfig()
|
@@ -1,3 +1,9 @@
|
||||
from models.config import DIRECTORIES
|
||||
from tools.xilinx_ise.bitgen import copy_bitstream_file, run_bitgen
|
||||
from tools.xilinx_ise.map import copy_map_report, run_map
|
||||
from tools.xilinx_ise.ngdbuild import run_ngdbuild
|
||||
from tools.xilinx_ise.par import copy_par_report, copy_pinout_report, run_par
|
||||
from tools.xilinx_ise.xst import copy_synthesis_report, generate_xst_project_file, generate_xst_script_file, run_xst
|
||||
from utils.directory_manager import clear_directories, ensure_directories_exist
|
||||
from utils.project_loader import load_project_config
|
||||
from utils.source_resolver import expand_sources
|
||||
@@ -7,11 +13,40 @@ project = load_project_config()
|
||||
print(project.name)
|
||||
print(project.sources.vhdl)
|
||||
|
||||
clear_directories()
|
||||
|
||||
ensure_directories_exist()
|
||||
|
||||
clear_directories()
|
||||
|
||||
|
||||
expanded_vhdl = expand_sources(project.sources.vhdl)
|
||||
|
||||
for library, filepath in expanded_vhdl:
|
||||
print(f"vhdl {library} \"{filepath}\"")
|
||||
|
||||
generate_xst_project_file(project, f"{DIRECTORIES.build}/{project.name}.prj")
|
||||
generate_xst_script_file(project, f"{DIRECTORIES.build}/{project.name}.scr")
|
||||
print(f"XST project file generated at {DIRECTORIES.build}/{project.name}.prj")
|
||||
print(f"XST script file generated at {DIRECTORIES.build}/{project.name}.scr")
|
||||
|
||||
run_xst(project)
|
||||
print("Run XST")
|
||||
|
||||
copy_synthesis_report(project)
|
||||
print("Copy synthesis report")
|
||||
|
||||
run_ngdbuild(project)
|
||||
print("Run ngdbuild")
|
||||
|
||||
run_map(project)
|
||||
print("Run map")
|
||||
copy_map_report(project)
|
||||
print("Copy map report")
|
||||
|
||||
run_par(project)
|
||||
print("Run par")
|
||||
copy_par_report(project)
|
||||
copy_pinout_report(project)
|
||||
|
||||
run_bitgen(project)
|
||||
copy_bitstream_file(project)
|
26
src/models/config.py
Normal file
26
src/models/config.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import os
|
||||
from pydantic import BaseModel
|
||||
|
||||
class DirectoryConfig(BaseModel):
|
||||
dependency: str = ".hdlbuild_deps"
|
||||
build: str = ".working"
|
||||
report: str = "reports"
|
||||
copy_target: str = "output"
|
||||
|
||||
def get_relative_prefix(self) -> str:
|
||||
"""
|
||||
Gibt den relativen Pfad von build-Verzeichnis zurück zum Hauptverzeichnis.
|
||||
|
||||
Beispiel:
|
||||
".working" -> "../"
|
||||
".build/deep" -> "../../"
|
||||
"""
|
||||
depth = len(os.path.normpath(self.build).split(os.sep))
|
||||
return "../" * depth
|
||||
|
||||
DIRECTORIES = DirectoryConfig()
|
||||
|
||||
class GitConfig(BaseModel):
|
||||
timeout: int = 10
|
||||
|
||||
GIT = GitConfig()
|
@@ -5,6 +5,16 @@ class SourceFile(BaseModel):
|
||||
path: str
|
||||
library: str = "work" # Default auf 'work'
|
||||
|
||||
class ToolOptions(BaseModel):
|
||||
common: List[str] = Field(default_factory=list)
|
||||
xst: List[str] = Field(default_factory=list)
|
||||
ngdbuild: List[str] = Field(default_factory=list)
|
||||
map: List[str] = Field(default_factory=list)
|
||||
par: List[str] = Field(default_factory=list)
|
||||
bitgen: List[str] = Field(default_factory=list)
|
||||
trace: List[str] = Field(default_factory=list)
|
||||
fuse: List[str] = Field(default_factory=list)
|
||||
|
||||
class Dependency(BaseModel):
|
||||
name: str
|
||||
git: str
|
||||
@@ -34,3 +44,4 @@ class ProjectConfig(BaseModel):
|
||||
constraints: Optional[str] = None
|
||||
build: Optional[BuildOptions] = None
|
||||
dependencies: Optional[List[Dependency]] = Field(default_factory=list)
|
||||
tool_options: Optional[ToolOptions] = ToolOptions()
|
||||
|
63
src/tools/xilinx_ise/bitgen.py
Normal file
63
src/tools/xilinx_ise/bitgen.py
Normal file
@@ -0,0 +1,63 @@
|
||||
import subprocess
|
||||
import os
|
||||
import shutil
|
||||
from typing import Optional
|
||||
from models.project import ProjectConfig
|
||||
from models.config import DIRECTORIES
|
||||
|
||||
def run_bitgen(project: ProjectConfig, working_dir: Optional[str] = None):
|
||||
"""
|
||||
Führt Xilinx BitGen aus, um den finalen Bitstream zu erzeugen.
|
||||
|
||||
Args:
|
||||
project (ProjectConfig): Geladene Projektkonfiguration.
|
||||
working_dir (str, optional): Arbeitsverzeichnis; Standard: build-Verzeichnis.
|
||||
"""
|
||||
if working_dir is None:
|
||||
working_dir = DIRECTORIES.build
|
||||
|
||||
xilinx_bin_dir = os.path.join(project.xilinx_path, "bin", "lin64") # oder "nt64" für Windows
|
||||
bitgen_executable = os.path.join(xilinx_bin_dir, "bitgen")
|
||||
|
||||
if not os.path.exists(bitgen_executable):
|
||||
raise FileNotFoundError(f"BitGen-Executable nicht gefunden unter: {bitgen_executable}")
|
||||
|
||||
print(f"[hdlbuild] Starte BitGen über {bitgen_executable}")
|
||||
print(f"[hdlbuild] Arbeitsverzeichnis: {working_dir}")
|
||||
|
||||
cmd = [bitgen_executable]
|
||||
|
||||
# Füge zuerst die "common" Optionen ein (falls vorhanden)
|
||||
if project.tool_options and project.tool_options.common:
|
||||
cmd.extend(project.tool_options.common)
|
||||
|
||||
# Dann die BitGen-spezifischen Optionen
|
||||
if project.tool_options and project.tool_options.bitgen:
|
||||
cmd.extend(project.tool_options.bitgen)
|
||||
|
||||
# Dann die Pflicht-Argumente
|
||||
cmd.extend([
|
||||
"-w",
|
||||
f"{project.name}.ncd",
|
||||
f"{project.name}.bit"
|
||||
])
|
||||
|
||||
subprocess.run(cmd, cwd=working_dir, check=True)
|
||||
|
||||
def copy_bitstream_file(project: ProjectConfig):
|
||||
"""
|
||||
Kopiert die Bitstream-Datei (.bit) vom Build-Verzeichnis ins Output-Verzeichnis.
|
||||
|
||||
Args:
|
||||
project (ProjectConfig): Geladene Projektkonfiguration.
|
||||
"""
|
||||
src_path = os.path.join(DIRECTORIES.build, f"{project.name}.bit")
|
||||
dst_path = os.path.join(DIRECTORIES.copy_target, f"{project.name}.bit")
|
||||
|
||||
if not os.path.exists(src_path):
|
||||
raise FileNotFoundError(f"Bitstream-Datei nicht gefunden: {src_path}")
|
||||
|
||||
os.makedirs(DIRECTORIES.copy_target, exist_ok=True)
|
||||
|
||||
shutil.copyfile(src_path, dst_path)
|
||||
print(f"[hdlbuild] Bitstream-Datei kopiert nach {dst_path}")
|
54
src/tools/xilinx_ise/common.py
Normal file
54
src/tools/xilinx_ise/common.py
Normal file
@@ -0,0 +1,54 @@
|
||||
import subprocess
|
||||
import os
|
||||
from typing import Optional, List
|
||||
from models.project import ProjectConfig
|
||||
from models.config import DIRECTORIES
|
||||
|
||||
def run_tool(
|
||||
project: ProjectConfig,
|
||||
tool_executable_name: str,
|
||||
tool_option_attr: str,
|
||||
mandatory_arguments: List[str],
|
||||
working_dir: Optional[str] = None
|
||||
):
|
||||
"""
|
||||
Führt ein beliebiges Xilinx ISE Tool aus (XST, NGDBuild, MAP, PAR, BitGen),
|
||||
mit Common- und Toolspezifischen Optionen + festen Pflichtargumenten.
|
||||
|
||||
Args:
|
||||
project (ProjectConfig): Das Projekt-Objekt
|
||||
tool_executable_name (str): z.B. "xst", "map", "par", "bitgen"
|
||||
tool_option_attr (str): Attribut-Name in tool_options, z.B. "xst", "map"
|
||||
mandatory_arguments (List[str]): Liste mit Pflicht-Argumenten
|
||||
working_dir (str, optional): Arbeitsverzeichnis
|
||||
"""
|
||||
if working_dir is None:
|
||||
working_dir = DIRECTORIES.build
|
||||
|
||||
xilinx_bin_dir = os.path.join(project.xilinx_path, "bin", "lin64") # oder "nt64"
|
||||
tool_executable = os.path.join(xilinx_bin_dir, tool_executable_name)
|
||||
|
||||
if not os.path.exists(tool_executable):
|
||||
raise FileNotFoundError(f"Executable nicht gefunden: {tool_executable}")
|
||||
|
||||
print(f"[hdlbuild] Starte {tool_executable_name.upper()} über {tool_executable}")
|
||||
print(f"[hdlbuild] Arbeitsverzeichnis: {working_dir}")
|
||||
|
||||
cmd = [tool_executable]
|
||||
|
||||
# Füge zuerst "common" Optionen ein
|
||||
if project.tool_options and project.tool_options.common:
|
||||
cmd.extend(project.tool_options.common)
|
||||
|
||||
# Füge dann Toolspezifische Optionen ein
|
||||
if project.tool_options:
|
||||
tool_opts = getattr(project.tool_options, tool_option_attr, [])
|
||||
if tool_opts:
|
||||
cmd.extend(tool_opts)
|
||||
|
||||
# Füge die Pflicht-Argumente an
|
||||
cmd.extend(mandatory_arguments)
|
||||
|
||||
print(f"[hdlbuild] Befehl: {' '.join(cmd)}")
|
||||
|
||||
subprocess.run(cmd, cwd=working_dir, check=True)
|
67
src/tools/xilinx_ise/map.py
Normal file
67
src/tools/xilinx_ise/map.py
Normal file
@@ -0,0 +1,67 @@
|
||||
import subprocess
|
||||
import os
|
||||
import shutil
|
||||
from typing import Optional
|
||||
from models.project import ProjectConfig
|
||||
from models.config import DIRECTORIES
|
||||
|
||||
def run_map(project: ProjectConfig, working_dir: Optional[str] = None):
|
||||
"""
|
||||
Führt Xilinx MAP aus, basierend auf dem gegebenen Projekt.
|
||||
|
||||
Args:
|
||||
project (ProjectConfig): Geladene Projektkonfiguration.
|
||||
working_dir (str, optional): Arbeitsverzeichnis; Standard: build-Verzeichnis.
|
||||
"""
|
||||
if working_dir is None:
|
||||
working_dir = DIRECTORIES.build
|
||||
|
||||
xilinx_bin_dir = os.path.join(project.xilinx_path, "bin", "lin64") # oder "nt64" für Windows
|
||||
map_executable = os.path.join(xilinx_bin_dir, "map")
|
||||
|
||||
if not os.path.exists(map_executable):
|
||||
raise FileNotFoundError(f"MAP-Executable nicht gefunden unter: {map_executable}")
|
||||
|
||||
print(f"[hdlbuild] Starte MAP über {map_executable}")
|
||||
print(f"[hdlbuild] Arbeitsverzeichnis: {working_dir}")
|
||||
|
||||
cmd = [map_executable]
|
||||
|
||||
# Füge zuerst die "common" Optionen ein (falls vorhanden)
|
||||
if project.tool_options and project.tool_options.common:
|
||||
cmd.extend(project.tool_options.common)
|
||||
|
||||
# Dann die MAP-spezifischen Optionen
|
||||
if project.tool_options and project.tool_options.map:
|
||||
cmd.extend(project.tool_options.map)
|
||||
|
||||
# Dann die Pflicht-Argumente
|
||||
cmd.extend([
|
||||
"-p", project.target_device,
|
||||
"-w",
|
||||
f"{project.name}.ngd",
|
||||
"-o", f"{project.name}.map.ncd",
|
||||
f"{project.name}.pcf"
|
||||
])
|
||||
|
||||
|
||||
subprocess.run(cmd, cwd=working_dir, check=True)
|
||||
|
||||
def copy_map_report(project: ProjectConfig):
|
||||
"""
|
||||
Kopiert den Map-Report (.map.mrp) vom Build-Verzeichnis ins Report-Verzeichnis
|
||||
und benennt ihn sinnvoll um.
|
||||
|
||||
Args:
|
||||
project (ProjectConfig): Geladene Projektkonfiguration.
|
||||
"""
|
||||
src_path = os.path.join(DIRECTORIES.build, f"{project.name}.map.mrp")
|
||||
dst_path = os.path.join(DIRECTORIES.report, f"{project.name}.MapReport")
|
||||
|
||||
if not os.path.exists(src_path):
|
||||
raise FileNotFoundError(f"Map-Report nicht gefunden: {src_path}")
|
||||
|
||||
os.makedirs(DIRECTORIES.report, exist_ok=True)
|
||||
|
||||
shutil.copyfile(src_path, dst_path)
|
||||
print(f"[hdlbuild] Map-Report kopiert nach {dst_path}")
|
46
src/tools/xilinx_ise/ngdbuild.py
Normal file
46
src/tools/xilinx_ise/ngdbuild.py
Normal file
@@ -0,0 +1,46 @@
|
||||
import subprocess
|
||||
import os
|
||||
from typing import Optional
|
||||
from models.project import ProjectConfig
|
||||
from models.config import DIRECTORIES
|
||||
|
||||
def run_ngdbuild(project: ProjectConfig, working_dir: Optional[str] = None):
|
||||
"""
|
||||
Führt Xilinx NGDBuild aus, basierend auf dem gegebenen Projekt.
|
||||
|
||||
Args:
|
||||
project (ProjectConfig): Geladene Projektkonfiguration.
|
||||
working_dir (str, optional): Arbeitsverzeichnis; Standard: build-Verzeichnis.
|
||||
"""
|
||||
if working_dir is None:
|
||||
working_dir = DIRECTORIES.build
|
||||
|
||||
xilinx_bin_dir = os.path.join(project.xilinx_path, "bin", "lin64") # oder "nt64" für Windows
|
||||
ngdbuild_executable = os.path.join(xilinx_bin_dir, "ngdbuild")
|
||||
|
||||
if not os.path.exists(ngdbuild_executable):
|
||||
raise FileNotFoundError(f"NGDBuild-Executable nicht gefunden unter: {ngdbuild_executable}")
|
||||
|
||||
print(f"[hdlbuild] Starte NGDBuild über {ngdbuild_executable}")
|
||||
print(f"[hdlbuild] Arbeitsverzeichnis: {working_dir}")
|
||||
|
||||
cmd = [ngdbuild_executable]
|
||||
|
||||
# Füge zuerst die "common" Optionen ein (falls vorhanden)
|
||||
if project.tool_options and project.tool_options.common:
|
||||
cmd.extend(project.tool_options.common)
|
||||
|
||||
# Dann die NGDBuild-spezifischen Optionen
|
||||
if project.tool_options and project.tool_options.ngdbuild:
|
||||
cmd.extend(project.tool_options.ngdbuild)
|
||||
|
||||
# Dann die Pflicht-Argumente
|
||||
cmd.extend([
|
||||
"-p", project.target_device,
|
||||
"-uc", f"{DIRECTORIES.get_relative_prefix()}{project.constraints}",
|
||||
f"{project.name}.ngc",
|
||||
f"{project.name}.ngd"
|
||||
])
|
||||
|
||||
|
||||
subprocess.run(cmd, cwd=working_dir, check=True)
|
85
src/tools/xilinx_ise/par.py
Normal file
85
src/tools/xilinx_ise/par.py
Normal file
@@ -0,0 +1,85 @@
|
||||
import subprocess
|
||||
import shutil
|
||||
import os
|
||||
from typing import Optional
|
||||
from models.project import ProjectConfig
|
||||
from models.config import DIRECTORIES
|
||||
|
||||
def run_par(project: ProjectConfig, working_dir: Optional[str] = None):
|
||||
"""
|
||||
Führt Xilinx PAR (Place & Route) aus, basierend auf dem gegebenen Projekt.
|
||||
|
||||
Args:
|
||||
project (ProjectConfig): Geladene Projektkonfiguration.
|
||||
working_dir (str, optional): Arbeitsverzeichnis; Standard: build-Verzeichnis.
|
||||
"""
|
||||
if working_dir is None:
|
||||
working_dir = DIRECTORIES.build
|
||||
|
||||
xilinx_bin_dir = os.path.join(project.xilinx_path, "bin", "lin64") # oder "nt64" für Windows
|
||||
par_executable = os.path.join(xilinx_bin_dir, "par")
|
||||
|
||||
if not os.path.exists(par_executable):
|
||||
raise FileNotFoundError(f"PAR-Executable nicht gefunden unter: {par_executable}")
|
||||
|
||||
print(f"[hdlbuild] Starte PAR über {par_executable}")
|
||||
print(f"[hdlbuild] Arbeitsverzeichnis: {working_dir}")
|
||||
|
||||
cmd = [par_executable]
|
||||
|
||||
# Füge zuerst die "common" Optionen ein (falls vorhanden)
|
||||
if project.tool_options and project.tool_options.common:
|
||||
cmd.extend(project.tool_options.common)
|
||||
|
||||
# Dann die PAR-spezifischen Optionen
|
||||
if project.tool_options and project.tool_options.par:
|
||||
cmd.extend(project.tool_options.par)
|
||||
|
||||
# Dann die Pflicht-Argumente
|
||||
cmd.extend([
|
||||
"-w",
|
||||
f"{project.name}.map.ncd",
|
||||
f"{project.name}.ncd",
|
||||
f"{project.name}.pcf"
|
||||
])
|
||||
|
||||
|
||||
subprocess.run(cmd, cwd=working_dir, check=True)
|
||||
|
||||
def copy_par_report(project: ProjectConfig):
|
||||
"""
|
||||
Kopiert den Place & Route Report (.par) vom Build-Verzeichnis ins Report-Verzeichnis
|
||||
und benennt ihn sinnvoll um.
|
||||
|
||||
Args:
|
||||
project (ProjectConfig): Geladene Projektkonfiguration.
|
||||
"""
|
||||
src_path = os.path.join(DIRECTORIES.build, f"{project.name}.par")
|
||||
dst_path = os.path.join(DIRECTORIES.report, f"{project.name}.PlaceRouteReport")
|
||||
|
||||
if not os.path.exists(src_path):
|
||||
raise FileNotFoundError(f"PAR-Report nicht gefunden: {src_path}")
|
||||
|
||||
os.makedirs(DIRECTORIES.report, exist_ok=True)
|
||||
|
||||
shutil.copyfile(src_path, dst_path)
|
||||
print(f"[hdlbuild] PAR-Report kopiert nach {dst_path}")
|
||||
|
||||
def copy_pinout_report(project: ProjectConfig):
|
||||
"""
|
||||
Kopiert den Pinout Summary Report (_pad.txt) vom Build-Verzeichnis ins Report-Verzeichnis
|
||||
und benennt ihn sinnvoll um.
|
||||
|
||||
Args:
|
||||
project (ProjectConfig): Geladene Projektkonfiguration.
|
||||
"""
|
||||
src_path = os.path.join(DIRECTORIES.build, f"{project.name}_pad.txt")
|
||||
dst_path = os.path.join(DIRECTORIES.report, f"{project.name}.PinoutReport")
|
||||
|
||||
if not os.path.exists(src_path):
|
||||
raise FileNotFoundError(f"Pinout-Report nicht gefunden: {src_path}")
|
||||
|
||||
os.makedirs(DIRECTORIES.report, exist_ok=True)
|
||||
|
||||
shutil.copyfile(src_path, dst_path)
|
||||
print(f"[hdlbuild] Pinout-Report kopiert nach {dst_path}")
|
101
src/tools/xilinx_ise/xst.py
Normal file
101
src/tools/xilinx_ise/xst.py
Normal file
@@ -0,0 +1,101 @@
|
||||
from typing import Optional
|
||||
from models.config import DIRECTORIES
|
||||
from utils.source_resolver import expand_sources
|
||||
from models.project import ProjectConfig
|
||||
import subprocess
|
||||
import os
|
||||
import shutil
|
||||
|
||||
def generate_xst_project_file(project: ProjectConfig, output_path: str):
|
||||
"""
|
||||
Generiert die XST .prj-Datei mit allen Quellcodes.
|
||||
"""
|
||||
with open(output_path, "w") as f:
|
||||
# VHDL-Sources
|
||||
for lib, src in expand_sources(project.sources.vhdl):
|
||||
f.write(f"vhdl {lib} \"{DIRECTORIES.get_relative_prefix()}/{src}\"\n")
|
||||
# Verilog-Sources
|
||||
for lib, src in expand_sources(project.sources.verilog):
|
||||
f.write(f"verilog {lib} \"{DIRECTORIES.get_relative_prefix()}/{src}\"\n")
|
||||
|
||||
# Optionale Dependencies
|
||||
if project.dependencies:
|
||||
for dep in project.dependencies:
|
||||
# Hier könnte man noch spezielle Sources aus dep.path expandieren
|
||||
pass
|
||||
|
||||
def generate_xst_script_file(project: ProjectConfig, output_path: str):
|
||||
"""
|
||||
Generiert die XST .scr-Datei mit den Synthese-Optionen.
|
||||
"""
|
||||
with open(output_path, "w") as f:
|
||||
f.write(f"run ")
|
||||
f.write(f"-ifn {project.name}.prj ")
|
||||
f.write(f"-ofn {project.name}.ngc ")
|
||||
f.write(f"-ifmt mixed ")
|
||||
|
||||
if project.tool_options and project.tool_options.xst:
|
||||
for opt in project.tool_options.xst:
|
||||
f.write(f"{opt} ")
|
||||
|
||||
f.write(f"-top {project.topmodule} ")
|
||||
f.write(f"-ofmt NGC ")
|
||||
f.write(f"-p {project.target_device} ")
|
||||
|
||||
|
||||
|
||||
def run_xst(project: ProjectConfig, working_dir: Optional[str] = None):
|
||||
"""
|
||||
Führt Xilinx XST Synthese aus, basierend auf dem gegebenen Projekt.
|
||||
|
||||
Args:
|
||||
project (ProjectConfig): Geladene Projektkonfiguration.
|
||||
working_dir (str, optional): Pfad, wo .prj/.scr liegen und gebaut werden soll.
|
||||
Wenn None, wird das aktuelle Arbeitsverzeichnis verwendet.
|
||||
"""
|
||||
if working_dir is None:
|
||||
working_dir = DIRECTORIES.build
|
||||
|
||||
xilinx_bin_dir = os.path.join(project.xilinx_path, "bin", "lin64") # oder "nt64" für Windows
|
||||
xst_executable = os.path.join(xilinx_bin_dir, "xst")
|
||||
|
||||
if not os.path.exists(xst_executable):
|
||||
raise FileNotFoundError(f"XST-Executable nicht gefunden unter: {xst_executable}")
|
||||
|
||||
print(f"[hdlbuild] Starte XST Synthese über {xst_executable}")
|
||||
print(f"[hdlbuild] Arbeitsverzeichnis: {working_dir}")
|
||||
|
||||
cmd = [xst_executable]
|
||||
|
||||
# Füge die "common" Optionen ein, wenn sie existieren
|
||||
if project.tool_options and project.tool_options.common:
|
||||
cmd.extend(project.tool_options.common)
|
||||
|
||||
# Jetzt die XST-spezifischen Aufrufe
|
||||
cmd.extend([
|
||||
"-ifn", f"{project.name}.scr"
|
||||
])
|
||||
|
||||
print(f"[hdlbuild] XST-Befehl: {' '.join(cmd)}")
|
||||
|
||||
subprocess.run(cmd, cwd=working_dir, check=True)
|
||||
|
||||
def copy_synthesis_report(project: ProjectConfig):
|
||||
"""
|
||||
Kopiert den Synthesebericht (.srp) vom Build-Verzeichnis ins Report-Verzeichnis
|
||||
und benennt ihn sinnvoll um.
|
||||
|
||||
Args:
|
||||
project (ProjectConfig): Geladene Projektkonfiguration.
|
||||
"""
|
||||
src_path = os.path.join(DIRECTORIES.build, f"{project.name}.srp")
|
||||
dst_path = os.path.join(DIRECTORIES.report, f"{project.name}.SynthesisReport")
|
||||
|
||||
if not os.path.exists(src_path):
|
||||
raise FileNotFoundError(f"Synthesebericht nicht gefunden: {src_path}")
|
||||
|
||||
# Stelle sicher, dass das Zielverzeichnis existiert
|
||||
os.makedirs(DIRECTORIES.report, exist_ok=True)
|
||||
|
||||
shutil.copyfile(src_path, dst_path)
|
||||
print(f"[hdlbuild] Synthesebericht kopiert nach {dst_path}")
|
@@ -1,6 +1,6 @@
|
||||
import os
|
||||
import shutil
|
||||
from config import DIRECTORIES
|
||||
from models.config import DIRECTORIES
|
||||
|
||||
def ensure_directories_exist():
|
||||
"""
|
||||
|
Reference in New Issue
Block a user