Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 4 additions & 0 deletions hls4ml/backends/vitis/vitis_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def create_initial_config(
namespace=None,
write_weights_txt=True,
write_tar=False,
write_emulation_constants=False,
tb_output_stream='both',
**_,
):
Expand All @@ -79,6 +80,8 @@ def create_initial_config(
write_weights_txt (bool, optional): If True, writes weights to .txt files which speeds up compilation.
Defaults to True.
write_tar (bool, optional): If True, compresses the output directory into a .tar.gz file. Defaults to False.
write_emulation_constants (bool, optional): If True, write constants to define.h useful for emulation.
Defaults to False.
tb_output_stream (str, optional): Controls where to write the output. Options are 'stdout', 'file' and 'both'.
Defaults to 'both'.

Expand All @@ -97,6 +100,7 @@ def create_initial_config(
'WriteWeightsTxt': write_weights_txt,
'WriteTar': write_tar,
'TBOutputStream': tb_output_stream,
'WriteEmulationConstants': write_emulation_constants,
}

return config
Expand Down
4 changes: 4 additions & 0 deletions hls4ml/templates/vivado/firmware/defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
#include "ap_fixed.h"
#include "ap_int.h"
#include "nnet_utils/nnet_types.h"
#include <array>
#include <cstddef>
#include <cstdio>
#include <tuple>
// hls-fpga-machine-learning insert headers

// hls-fpga-machine-learning insert namespace-start
Expand All @@ -14,6 +16,8 @@

// hls-fpga-machine-learning insert layer-precision

// hls-fpga-machine-learning insert emulator-defines

// hls-fpga-machine-learning insert namespace-end

#endif
2 changes: 2 additions & 0 deletions hls4ml/templates/vivado/firmware/myproject.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ void myproject(
// hls-fpga-machine-learning insert header
);

// hls-fpga-machine-learning insert emulator-defines

// hls-fpga-machine-learning insert namespace-end

#endif
42 changes: 42 additions & 0 deletions hls4ml/writer/vivado_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,34 @@ def write_project_header(self, model):
if namespace is not None:
newline += '}\n'

elif '// hls-fpga-machine-learning insert emulator-defines' in line:
newline = line

if model.config.get_writer_config().get('WriteEmulationConstants', False):
brams_def_str = ', '.join([b.definition_cpp(as_reference=False) for b in model_brams])
brams_call_str = ', '.join([b.name for b in model_brams])

if model.config.get_config_value('IOType') == 'io_stream':
input_call_str = ', '.join([f'std::get<{n}>(inputs)' for n in range(len(model_inputs))])
output_call_str = ', '.join([f'std::get<{n}>(outputs)' for n in range(len(model_outputs))])
else:
input_call_str = ', '.join([f'std::get<{n}>(inputs).data()' for n in range(len(model_inputs))])
output_call_str = ', '.join([f'std::get<{n}>(outputs).data()' for n in range(len(model_outputs))])

newline += (
f'\ninline void {model.config.get_project_name()}_emulator('
'inputs_t& inputs, outputs_t& outputs' # the inputs_t should ideally be const
)
if len(model_brams) > 0:
newline += ',\n' + brams_def_str
newline += ') {\n'
newline += indent + model.config.get_project_name() + '(\n'
newline += indent + indent + input_call_str + ',\n'
newline += indent + indent + output_call_str
if len(model_brams) > 0:
newline += ',\n' + indent + indent + brams_call_str
newline += '\n' + indent + ');\n}\n'

else:
newline = line
fout.write(newline)
Expand Down Expand Up @@ -385,6 +413,20 @@ def write_defines(self, model):
if namespace is not None:
newline += '}\n'

elif '// hls-fpga-machine-learning insert emulator-defines' in line:
newline = line

if model.config.get_writer_config().get('WriteEmulationConstants', False):
if model.config.get_config_value('IOType') == 'io_stream':
input_types = [f'hls::stream<{v.type.name}>' for v in model.get_input_variables()]
output_types = [f'hls::stream<{v.type.name}>' for v in model.get_output_variables()]
else:
input_types = [f'std::array<{v.type.name}, {v.size_cpp()}>' for v in model.get_input_variables()]
output_types = [f'std::array<{v.type.name}, {v.size_cpp()}>' for v in model.get_output_variables()]
input_types_str = ', '.join(input_types)
output_types_str = ', '.join(output_types)
newline += '\n' + f'using inputs_t = std::tuple<{input_types_str}>;'
newline += '\n' + f'using outputs_t = std::tuple<{output_types_str}>;\n'
else:
newline = line
fout.write(newline)
Expand Down
12 changes: 12 additions & 0 deletions test/pytest/test_writer_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ def test_namespace(keras_model, namespace, io_type, backend):
hls_model.compile() # It's enough that the model compiles


@pytest.mark.parametrize('io_type', ['io_stream', 'io_parallel'])
@pytest.mark.parametrize('backend', ['Vitis']) # Only Vitis is supported
def test_emulator(keras_model, io_type, backend):

config = hls4ml.utils.config_from_keras_model(keras_model, granularity='name', backend=backend)
odir = str(test_root_path / f'hls4mlprj_emulation_{backend}_{io_type}')
hls_model = hls4ml.converters.convert_from_keras_model(
keras_model, hls_config=config, io_type=io_type, output_dir=odir, write_emulation_constants=True, backend=backend
)
hls_model.compile() # It's enough that the model compiles


@pytest.mark.parametrize('backend', ['Vivado', 'Vitis']) # No Quartus for now
@pytest.mark.parametrize('write_tar', [True, False])
def test_write_tar(keras_model, write_tar, backend):
Expand Down
Loading