Skip to content

Commit d1b286a

Browse files
authored
Merge pull request Xilinx#1248 from Xilinx/infra/hlsvector
Infrastructure to incorporate components with hls::vector interface
2 parents a054165 + 95bc8a6 commit d1b286a

File tree

2 files changed

+129
-29
lines changed

2 files changed

+129
-29
lines changed

src/finn/custom_op/fpgadataflow/hlsbackend.py

Lines changed: 83 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ def get_nodeattr_types(self):
5454
"code_gen_dir_cppsim": ("s", False, ""),
5555
"executable_path": ("s", False, ""),
5656
"res_hls": ("s", False, ""),
57+
# temporary node attribute to keep track of interface style of hls ops
58+
"cpp_interface": ("s", False, "packed", {"packed", "hls_vector"}),
5759
}
5860

5961
def get_all_verilog_paths(self):
@@ -206,7 +208,13 @@ def code_generation_cppsim(self, model):
206208
self.dataoutstrm()
207209
self.save_as_npy()
208210

209-
template = templates.docompute_template
211+
if self.get_nodeattr("cpp_interface") == "hls_vector":
212+
self.timeout_value()
213+
self.timeout_condition()
214+
self.timeout_read_stream()
215+
template = templates.docompute_template_timeout
216+
else:
217+
template = templates.docompute_template
210218

211219
for key in self.code_gen_dict:
212220
# transform list into long string separated by '\n'
@@ -371,24 +379,40 @@ def read_npy_data(self):
371379
if dtype == DataType["BIPOLAR"]:
372380
# use binary for bipolar storage
373381
dtype = DataType["BINARY"]
374-
elem_bits = dtype.bitwidth()
375-
packed_bits = self.get_instream_width()
376-
packed_hls_type = "ap_uint<%d>" % packed_bits
377382
elem_hls_type = dtype.get_hls_datatype_str()
378383
npy_type = "float"
379384
npy_in = "%s/input_0.npy" % code_gen_dir
380385
self.code_gen_dict["$READNPYDATA$"] = []
381-
self.code_gen_dict["$READNPYDATA$"].append(
382-
'npy2apintstream<%s, %s, %d, %s>("%s", in0_%s);'
383-
% (
384-
packed_hls_type,
385-
elem_hls_type,
386-
elem_bits,
387-
npy_type,
388-
npy_in,
389-
self.hls_sname(),
386+
387+
cpp_interface = self.get_nodeattr("cpp_interface")
388+
389+
if cpp_interface == "packed":
390+
elem_bits = dtype.bitwidth()
391+
packed_bits = self.get_instream_width()
392+
packed_hls_type = "ap_uint<%d>" % packed_bits
393+
self.code_gen_dict["$READNPYDATA$"].append(
394+
'npy2apintstream<%s, %s, %d, %s>("%s", in0_%s);'
395+
% (
396+
packed_hls_type,
397+
elem_hls_type,
398+
elem_bits,
399+
npy_type,
400+
npy_in,
401+
self.hls_sname(),
402+
)
403+
)
404+
else:
405+
folded_shape = self.get_folded_input_shape()
406+
self.code_gen_dict["$READNPYDATA$"].append(
407+
'npy2vectorstream<%s, %s, %d>("%s", in0_%s, false);'
408+
% (
409+
elem_hls_type,
410+
npy_type,
411+
folded_shape[-1],
412+
npy_in,
413+
self.hls_sname(),
414+
)
390415
)
391-
)
392416

393417
def strm_decl(self):
394418
"""Function to generate the commands for the stream declaration in c++,
@@ -422,27 +446,43 @@ def dataoutstrm(self):
422446
if dtype == DataType["BIPOLAR"]:
423447
# use binary for bipolar storage
424448
dtype = DataType["BINARY"]
425-
elem_bits = dtype.bitwidth()
426-
packed_bits = self.get_outstream_width()
427-
packed_hls_type = "ap_uint<%d>" % packed_bits
428449
elem_hls_type = dtype.get_hls_datatype_str()
429450
npy_type = "float"
430451
npy_out = "%s/output.npy" % code_gen_dir
431452
oshape = self.get_folded_output_shape()
432453
oshape_cpp_str = str(oshape).replace("(", "{").replace(")", "}")
433454

434-
self.code_gen_dict["$DATAOUTSTREAM$"] = [
435-
'apintstream2npy<%s, %s, %d, %s>(out_%s, %s, "%s");'
436-
% (
437-
packed_hls_type,
438-
elem_hls_type,
439-
elem_bits,
440-
npy_type,
441-
self.hls_sname(),
442-
oshape_cpp_str,
443-
npy_out,
444-
)
445-
]
455+
cpp_interface = self.get_nodeattr("cpp_interface")
456+
457+
if cpp_interface == "packed":
458+
elem_bits = dtype.bitwidth()
459+
packed_bits = self.get_outstream_width()
460+
packed_hls_type = "ap_uint<%d>" % packed_bits
461+
462+
self.code_gen_dict["$DATAOUTSTREAM$"] = [
463+
'apintstream2npy<%s, %s, %d, %s>(out_%s, %s, "%s");'
464+
% (
465+
packed_hls_type,
466+
elem_hls_type,
467+
elem_bits,
468+
npy_type,
469+
self.hls_sname(),
470+
oshape_cpp_str,
471+
npy_out,
472+
)
473+
]
474+
else:
475+
folded_shape = self.get_folded_output_shape()
476+
self.code_gen_dict["$DATAOUTSTREAM$"] = [
477+
'vectorstream2npy<%s, %s, %d>(strm, %s, "%s");'
478+
% (
479+
elem_hls_type,
480+
npy_type,
481+
folded_shape[-1],
482+
oshape_cpp_str,
483+
npy_out,
484+
)
485+
]
446486

447487
def save_as_npy(self):
448488
"""Function to generate the commands for saving data in .npy file in c++"""
@@ -474,3 +514,17 @@ def get_ap_int_max_w(self):
474514
ret = max([instream, outstream])
475515
assert ret <= 8191, "AP_INT_MAX_W=%d is larger than allowed maximum of 8191" % ret
476516
return ret
517+
518+
def timeout_value(self):
519+
"""Set timeout value for HLS functions defined for one clock cycle"""
520+
self.code_gen_dict["$TIMEOUT_VALUE$"] = ["1000"]
521+
522+
def timeout_condition(self):
523+
"""Set timeout condition for HLS functions defined for one clock cycle"""
524+
self.code_gen_dict["$TIMEOUT_CONDITION$"] = ["out_{}.empty()".format(self.hls_sname())]
525+
526+
def timeout_read_stream(self):
527+
"""Set reading output stream procedure for HLS functions defined for one clock cycle"""
528+
self.code_gen_dict["$TIMEOUT_READ_STREAM$"] = [
529+
"strm << out_{}.read();".format(self.hls_sname())
530+
]

src/finn/custom_op/fpgadataflow/templates.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#define AP_INT_MAX_W $AP_INT_MAX_W$
3333
#include "cnpy.h"
3434
#include "npy2apintstream.hpp"
35+
#include "npy2vectorstream.hpp"
3536
#include <vector>
3637
#include "bnn-library.h"
3738
@@ -58,6 +59,51 @@
5859
5960
"""
6061

62+
# template for single node execution with timeout (for single clock hls operations)
63+
docompute_template_timeout = """
64+
#define AP_INT_MAX_W $AP_INT_MAX_W$
65+
#include "cnpy.h"
66+
#include "npy2apintstream.hpp"
67+
#include "npy2vectorstream.hpp"
68+
#include <vector>
69+
#include "bnn-library.h"
70+
71+
// includes for network parameters
72+
$GLOBALS$
73+
74+
// defines for network parameters
75+
$DEFINES$
76+
77+
int main(){
78+
$PRAGMAS$
79+
80+
$STREAMDECLARATIONS$
81+
82+
$READNPYDATA$
83+
84+
unsigned timeout = 0;
85+
while(timeout < $TIMEOUT_VALUE$){
86+
87+
$DOCOMPUTE$
88+
89+
if($TIMEOUT_CONDITION$){
90+
timeout++;
91+
}
92+
93+
else{
94+
$TIMEOUT_READ_STREAM$
95+
timeout = 0;
96+
}
97+
}
98+
99+
$DATAOUTSTREAM$
100+
101+
$SAVEASCNPY$
102+
103+
}
104+
105+
"""
106+
61107
# templates for single node ip generation
62108

63109
# cpp file

0 commit comments

Comments
 (0)