Source code for hlsfactory.flow_vitis_modern

import os
import time

from hlsfactory.design_config import FlowName
from hlsfactory.flow_vitis import (
    DesignHLSSynthData,
    VitisHLSDesign,
    auto_find_synth_report,
    check_build_files_exist,
)
from hlsfactory.framework import Design, ToolFlow
from hlsfactory.utils import (
    CallToolResult,
    ExecutionDataStatus,
    call_tool,
    find_bin_path,
    flow_already_completed,
    update_execution_data_with_flow_results,
)

# Both the synth flow and the csim flow below operate on the same HLS
# component directory, since the modern flow's csim/cosim/impl/package steps
# all run against a component that was already created (typically by a prior
# C-synthesis run). Using a fixed, well-known name lets the csim/cosim flows
# find the component created by VitisHLSModernSynthFlow without needing extra
# design-config plumbing.
HLS_COMPONENT_DIR_NAME = "hls_component"

# Starting with the Vitis Unified IDE (any release after 2024.2), Vitis HLS is
# no longer a standalone tool with its own `vitis_hls` TCL entry point.
# Instead HLS becomes an "HLS component" driven by the common `v++`/`vitis-run`
# command line tools and a plain INI-style HLS config file (`.cfg`), rather
# than a `.tcl` script. See:
#   https://docs.amd.com/r/en-US/ug1399-vitis-hls/Vitis-HLS-Migration-Guide
#   https://docs.amd.com/r/en-US/ug1399-vitis-hls/Vitis-HLS-Flow-Steps
#
# C-synthesis (and packaging of the resulting RTL as a Vivado IP/Vitis kernel)
# is run via:
#   v++ -c --mode hls --config <hls_config.cfg> --work_dir <work_dir>
#
# This produces a component directory (marked by a `vitis-comp.json` file)
# with the synthesis report at `<work_dir>/hls/syn/report/csynth.xml`, which
# uses the same XML schema as the classic Vitis HLS `csynth.xml` report, so
# the existing parsers in `hlsfactory.flow_vitis` are reused as-is.


[docs] class VitisHLSModernSynthFlow(ToolFlow): name = "VitisHLSModernSynthFlow" def __init__( self, vpp_bin: str | None = None, log_output: bool = False, log_execution_time: bool = True, env_var_xilinx_hls: str | None = None, env_var_xilinx_vitis: str | None = None, env_var_xilinx_vivado: str | None = None, ) -> None: if vpp_bin is None: self.vpp_bin = find_bin_path("v++") else: self.vpp_bin = vpp_bin self.log_output = log_output self.log_execution_time = log_execution_time self.env_var_xilinx_hls = env_var_xilinx_hls self.env_var_xilinx_vitis = env_var_xilinx_vitis self.env_var_xilinx_vivado = env_var_xilinx_vivado
[docs] def execute(self, design: Design, timeout: float | None = None) -> list[Design]: design_dir = design.dir if flow_already_completed(design_dir, self.name): print(f"[{design_dir}] Skipping {self.name}, already completed") return [design] t_0 = time.perf_counter() # Get the HLS config file path from the design config config = design.require_config() hls_config_name = config.require_flow_setting( FlowName.VITIS_HLS_MODERN_SYNTH, "hls_config" ) fp_hls_config = design_dir / hls_config_name check_build_files_exist([fp_hls_config]) if self.env_var_xilinx_hls: os.environ["XILINX_HLS"] = self.env_var_xilinx_hls if self.env_var_xilinx_vitis: os.environ["XILINX_VITIS"] = self.env_var_xilinx_vitis if self.env_var_xilinx_vivado: os.environ["XILINX_VIVADO"] = self.env_var_xilinx_vivado cmd = ( f"{self.vpp_bin} -c --mode hls " f"--config {hls_config_name} --work_dir {HLS_COMPONENT_DIR_NAME}" ) return_result = call_tool( cmd, cwd=design_dir, log_output=self.log_output, timeout=timeout, raise_on_error=False, ) if return_result == CallToolResult.TIMEOUT: (design_dir / f"timeout__{self.name}.txt").touch() print(f"[{design_dir}] Timeout of {timeout} seconds reached") t_1 = time.perf_counter() if self.log_execution_time: update_execution_data_with_flow_results( design_dir, self.name, ExecutionDataStatus.TIMEOUT, t_0, t_1, error_message=f"Timeout of {timeout}s reached", ) return [] if return_result == CallToolResult.ERROR: (design_dir / f"error__{self.name}.txt").touch() print(f"[{design_dir}] Error occurred during execution") t_1 = time.perf_counter() if self.log_execution_time: update_execution_data_with_flow_results( design_dir, self.name, ExecutionDataStatus.ERROR, t_0, t_1, error_message="Synthesis execution error", ) return [] work_dir = design_dir / HLS_COMPONENT_DIR_NAME csynth_report_fp = auto_find_synth_report(work_dir) hls_data = DesignHLSSynthData.parse_from_synth_report_file(csynth_report_fp) hls_data.to_json(design_dir / "data_hls.json") # type: ignore design_data = VitisHLSDesign.parse_from_synth_report_file(csynth_report_fp) design_data.to_json(design_dir / "data_design.json") # type: ignore t_1 = time.perf_counter() if self.log_execution_time: update_execution_data_with_flow_results( design_dir, self.name, ExecutionDataStatus.SUCCESS, t_0, t_1 ) return [design]
[docs] class VitisHLSModernCsimFlow(ToolFlow): name = "VitisHLSModernCsimFlow" def __init__( self, vitis_run_bin: str | None = None, log_output: bool = False, log_execution_time: bool = True, env_var_xilinx_hls: str | None = None, env_var_xilinx_vitis: str | None = None, env_var_xilinx_vivado: str | None = None, ) -> None: if vitis_run_bin is None: self.vitis_run_bin = find_bin_path("vitis-run") else: self.vitis_run_bin = vitis_run_bin self.log_output = log_output self.log_execution_time = log_execution_time self.env_var_xilinx_hls = env_var_xilinx_hls self.env_var_xilinx_vitis = env_var_xilinx_vitis self.env_var_xilinx_vivado = env_var_xilinx_vivado
[docs] def execute(self, design: Design, timeout: float | None = None) -> list[Design]: design_dir = design.dir t_0 = time.perf_counter() # Get the HLS config file path from the design config. The same # config file used for VitisHLSModernSynthFlow is reused here; it # must also declare a `tb.file` for csim to have a test bench to run. config = design.require_config() hls_config_name = config.require_flow_setting( FlowName.VITIS_HLS_MODERN_CSIM, "hls_config" ) fp_hls_config = design_dir / hls_config_name check_build_files_exist([fp_hls_config]) if self.env_var_xilinx_hls: os.environ["XILINX_HLS"] = self.env_var_xilinx_hls if self.env_var_xilinx_vitis: os.environ["XILINX_VITIS"] = self.env_var_xilinx_vitis if self.env_var_xilinx_vivado: os.environ["XILINX_VIVADO"] = self.env_var_xilinx_vivado cmd = ( f"{self.vitis_run_bin} --mode hls --config {hls_config_name} " f"--csim --work_dir {HLS_COMPONENT_DIR_NAME}" ) return_result = call_tool( cmd, cwd=design_dir, log_output=self.log_output, timeout=timeout, raise_on_error=False, ) t_1 = time.perf_counter() if self.log_execution_time: if return_result == CallToolResult.TIMEOUT: update_execution_data_with_flow_results( design_dir, self.name, ExecutionDataStatus.TIMEOUT, t_0, t_1, error_message=f"Timeout of {timeout}s reached", ) elif return_result == CallToolResult.ERROR: update_execution_data_with_flow_results( design_dir, self.name, ExecutionDataStatus.ERROR, t_0, t_1, error_message="C simulation execution error", ) else: update_execution_data_with_flow_results( design_dir, self.name, ExecutionDataStatus.SUCCESS, t_0, t_1, ) if return_result == CallToolResult.TIMEOUT: (design_dir / f"timeout__{self.name}.txt").touch() print(f"[{design_dir}] Timeout of {timeout} seconds reached") return [] if return_result == CallToolResult.ERROR: (design_dir / f"error__{self.name}.txt").touch() print(f"[{design_dir}] Error occurred during execution") return [] return [design]