Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 41 additions & 14 deletions hls4ml/backends/symbolic/symbolic_backend.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import sys
from pathlib import Path

from hls4ml.backends import FPGABackend
from hls4ml.model.flow import register_flow
Expand Down Expand Up @@ -90,23 +91,49 @@ def create_initial_config(
return config

def build(self, model, reset=False, csim=True, synth=True, cosim=False, validation=False, export=False, vsynth=False):
if 'linux' in sys.platform:
found = os.system('command -v vivado_hls > /dev/null')
if found != 0:
raise Exception('Vivado HLS installation not found. Make sure "vivado_hls" is on PATH.')
compiler = model.config.get_config_value('Compiler')

curr_dir = os.getcwd()
os.chdir(model.config.get_output_dir())
vivado_cmd = (
f'vivado_hls -f build_prj.tcl "reset={reset} '
f'csim={csim} '
f'synth={synth} '
f'cosim={cosim} '
f'validation={validation} '
f'export={export} '
f'vsynth={vsynth}"'
)
os.system(vivado_cmd)

if compiler == 'vitis_hls':
if 'linux' in sys.platform:
found = os.system('command -v vitis-run > /dev/null') == 0
if not found:
raise Exception('Vitis HLS installation not found. Make sure "vitis-run" is on PATH.')

build_opts = (
'array set opt {\n'
f' reset {int(reset)}\n'
f' csim {int(csim)}\n'
f' synth {int(synth)}\n'
f' cosim {int(cosim)}\n'
f' validation {int(validation)}\n'
f' export {int(export)}\n'
f' vsynth {int(vsynth)}\n'
f' fifo_opt 0\n'
'}\n'
)
with open('build_opt.tcl', 'w') as f:
f.write(build_opts)
os.system('vitis-run --tcl build_prj.tcl --mode hls')
else:
if 'linux' in sys.platform:
found = os.system('command -v vivado_hls > /dev/null')
if found != 0:
raise Exception('Vivado HLS installation not found. Make sure "vivado_hls" is on PATH.')

vivado_cmd = (
f'vivado_hls -f build_prj.tcl "reset={reset} '
f'csim={csim} '
f'synth={synth} '
f'cosim={cosim} '
f'validation={validation} '
f'export={export} '
f'vsynth={vsynth}"'
)
os.system(vivado_cmd)

os.chdir(curr_dir)

return parse_vivado_report(model.config.get_output_dir())
18 changes: 13 additions & 5 deletions hls4ml/converters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ def convert_from_symbolic_expression(
input_data_tb=None,
output_data_tb=None,
precision='ap_fixed<16,6>',
hls_compiler='vivado_hls',
**kwargs,
):
"""Converts a given (SymPy or string) expression to hls4ml model.
Expand Down Expand Up @@ -438,17 +439,24 @@ def convert_from_symbolic_expression(
part (str, optional): The FPGA part. If set to `None` a default part of a backend will be used.
clock_period (int, optional): Clock period of the design.
Defaults to 5.
compiler (str, optional): Compiler to use, ``vivado_hls`` or ``vitis_hls``. Defaults to ``vivado_hls``.
hls_include_path (str, optional): Path to HLS inlcude files. If `None` the location will be inferred from the
location of the `compiler` used. If an empty string is passed the HLS math libraries won't be used during
hls_compiler (str, optional): HLS compiler to use. Must be ``'vivado_hls'`` or ``'vitis_hls'`. Defaults to ``'vivado_hls'``.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add support for vitisrun that is used in newer versions? And we could do a performance eval and if it works as well with Vitis as originally with Vivado, we can drop Vivado support altogether.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my mind vitisrun is/was the name of the executable. The compiler is still Vitis HLS. But yes, we can make it more consistent and just have vitisrun (since we don't support any versions of Vitis HLS for which vitisrun doesn't exist).

How would we know if it works as well? Do we have some baseline results? I personally wouldn't have access to a machine with Vivado HLS.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed it may make sense to just call them vivado and vitis instead of the actual executable.

regarding vivado hls, i see two options: if you have a licence at eth (check vlm with local license server if you still have a valid one) i can give you a containerized version that you can run without installation. other option is to use cvmfs if you have a cern account and can log in to lxplus.

hls_include_path (str, optional): Path to HLS include files. If `None` the location will be inferred from the
location of the compiler. If an empty string is passed the HLS math libraries won't be used during
compilation, meaning Python integration won't work unless all functions are LUT-based. Doesn't affect synthesis.
Defaults to None.
hls_libs_path (str, optional): Path to HLS libs files. If `None` the location will be inferred from the
location of the `compiler` used. Defaults to None.
location of the compiler. Defaults to None.

Returns:
ModelGraph: hls4ml model.
"""
_valid_compilers = ('vivado_hls', 'vitis_hls')
if hls_compiler not in _valid_compilers:
raise ValueError(f"hls_compiler must be one of {_valid_compilers}, got '{hls_compiler}'")

# Remove legacy 'compiler' kwarg if passed to avoid duplicate keyword argument
kwargs.pop('compiler', None)

import sympy

if not isinstance(expr, (list, set)):
Expand Down Expand Up @@ -490,7 +498,7 @@ def convert_from_symbolic_expression(
expr_layer['use_built_in_luts'] = use_built_in_lut_functions
layer_list.append(expr_layer)

config = create_config(output_dir=output_dir, project_name=project_name, backend='SymbolicExpression', **kwargs)
config = create_config(output_dir=output_dir, project_name=project_name, backend='SymbolicExpression', compiler=hls_compiler, **kwargs)

# config['Expression'] = str(expr)
config['NSymbols'] = n_symbols
Expand Down
17 changes: 16 additions & 1 deletion hls4ml/writer/symbolic_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def write_build_script(self, model):
"""

filedir = Path(__file__).parent
compiler = model.config.get_config_value('Compiler')

# project.tcl
prj_tcl_dst = Path(f'{model.config.get_output_dir()}/project.tcl')
Expand All @@ -77,16 +78,26 @@ def write_build_script(self, model):
f.write('set version "{}"\n'.format(model.config.get_config_value('Version', '1.0.0')))

# build_prj.tcl
srcpath = (filedir / '../templates/vivado/build_prj.tcl').resolve()
if compiler == 'vitis_hls':
srcpath = (filedir / '../templates/vitis/build_prj.tcl').resolve()
else:
srcpath = (filedir / '../templates/vivado/build_prj.tcl').resolve()
dstpath = f'{model.config.get_output_dir()}/build_prj.tcl'
copyfile(srcpath, dstpath)

# build_opt.tcl — required by the vitis build_prj.tcl, since vitis-run doesn't accept TCL arguments
if compiler == 'vitis_hls':
srcpath = (filedir / '../templates/vitis/build_opt.tcl').resolve()
dstpath = f'{model.config.get_output_dir()}/build_opt.tcl'
copyfile(str(srcpath), dstpath)

# vivado_synth.tcl
srcpath = (filedir / '../templates/vivado/vivado_synth.tcl').resolve()
dstpath = f'{model.config.get_output_dir()}/vivado_synth.tcl'
copyfile(srcpath, dstpath)

# build_lib.sh
# Vitis HLS 2022.2+ ships fpo_v7_1; Vivado HLS ships fpo_v7_0.
build_lib_src = (filedir / '../templates/symbolic/build_lib.sh').resolve()
build_lib_dst = Path(f'{model.config.get_output_dir()}/build_lib.sh').resolve()
with open(build_lib_src) as src, open(build_lib_dst, 'w') as dst:
Expand All @@ -95,6 +106,10 @@ def write_build_script(self, model):
line = line.replace('mystamp', model.config.get_config_value('Stamp'))
line = line.replace('mylibspath', model.config.get_config_value('HLSLibsPath'))

if compiler == 'vitis_hls':
line = line.replace('fpo_v7_0', 'fpo_v7_1')
line = line.replace('Ip_floating_point_v7_0', 'Ip_floating_point_v7_1')

if 'LDFLAGS=' in line and not os.path.exists(model.config.get_config_value('HLSLibsPath')):
line = 'LDFLAGS=\n'

Expand Down
Loading