@@ -111,8 +111,10 @@ def write_project_cpp(self, model):
111
111
newline = line
112
112
if io_type == 'io_stream' :
113
113
newline += 'void myproject(\n '
114
- newline += indent + 'stream_in<{}> &input_stream,\n ' .format (model_inputs [0 ].type .name )
115
- newline += indent + 'stream_out<{}> &output_stream\n ' .format (model_outputs [0 ].type .name )
114
+ for inp in model_inputs :
115
+ newline += indent + 'stream_in<{}> &{}_stream,\n ' .format (inp .type .name , inp .name )
116
+ for out in model_outputs :
117
+ newline += indent + 'stream_out<{}> &{}_stream\n ' .format (out .type .name , out .name )
116
118
newline += ') {\n '
117
119
if io_type == 'io_parallel' :
118
120
newline = 'output_data myproject(\n '
@@ -124,8 +126,10 @@ def write_project_cpp(self, model):
124
126
newline = line
125
127
if io_type == 'io_stream' :
126
128
newline += 'component void myproject(\n '
127
- newline += indent + 'stream_in<{}> &input_stream,\n ' .format (model_inputs [0 ].type .name )
128
- newline += indent + 'stream_out<{}> &output_stream\n ' .format (model_outputs [0 ].type .name )
129
+ for inp in model_inputs :
130
+ newline += indent + 'stream_in<{}> &{}_stream,\n ' .format (inp .type .name , inp .name )
131
+ for out in model_outputs :
132
+ newline += indent + 'stream_out<{}> &{}_stream\n ' .format (out .type .name , out .name )
129
133
newline += ') {\n '
130
134
if io_type == 'io_parallel' :
131
135
newline += 'component output_data myproject(\n '
@@ -148,10 +152,11 @@ def write_project_cpp(self, model):
148
152
elif '//hls-fpga-machine-learning initialize input/output' in line :
149
153
if io_type == 'io_stream' :
150
154
newline = line
151
- newline += indent + f'for (size_t i = 0; i < { model_inputs [0 ].size_cpp ()} / { model_inputs [0 ].type .name } ::size; i++) {{\n '
152
- newline += indent + f' { model_inputs [0 ].type .name } tmp = input_stream.read();\n '
153
- newline += indent + f' { model_inputs [0 ].name } .write(tmp);\n '
154
- newline += indent + f'}}\n '
155
+ for inp in model_inputs :
156
+ newline += indent + f'for (size_t i = 0; i < { inp .size_cpp ()} / { inp .type .name } ::size; i++) {{\n '
157
+ newline += indent + f' { inp .type .name } tmp = { inp .name } _stream.read();\n '
158
+ newline += indent + f' { inp .name } .write(tmp);\n '
159
+ newline += indent + f'}}\n '
155
160
else :
156
161
newline = line
157
162
newline += indent + 'hls_register output_data outputs;\n '
@@ -195,11 +200,12 @@ def write_project_cpp(self, model):
195
200
elif '//hls-fpga-machine-learning return' in line :
196
201
if io_type == 'io_stream' :
197
202
newline = line
198
- newline += indent + f'for (size_t i = 0; i < { model_outputs [0 ].size_cpp ()} / { model_outputs [0 ].type .name } ::size; i++) {{\n '
199
- newline += indent + f' { model_outputs [0 ].type .name } tmp = { model_outputs [0 ].name } .read();\n '
200
- newline += indent + f' output_stream.write(tmp);\n '
201
- newline += indent + f'}}\n '
202
- newline += '}\n '
203
+ for out in model_outputs :
204
+ newline += indent + f'for (size_t i = 0; i < { out .size_cpp ()} / { out .type .name } ::size; i++) {{\n '
205
+ newline += indent + f' { out .type .name } tmp = { out .name } .read();\n '
206
+ newline += indent + f' { out .name } _stream.write(tmp);\n '
207
+ newline += indent + f'}}\n '
208
+ newline += '}\n '
203
209
else :
204
210
newline = line
205
211
newline += indent + 'return outputs;\n '
@@ -242,8 +248,10 @@ def write_project_header(self, model):
242
248
# For io_stream, input and output are passed by reference; see myproject.h & myproject.cpp for more details
243
249
if io_type == 'io_stream' :
244
250
newline += 'void myproject(\n '
245
- newline += indent + 'stream_in<{}> &input_stream,\n ' .format (model_inputs [0 ].type .name )
246
- newline += indent + 'stream_out<{}> &output_stream\n ' .format (model_outputs [0 ].type .name )
251
+ for inp in model_inputs :
252
+ newline += indent + 'stream_in<{}> &{}_stream,\n ' .format (inp .type .name , inp .name )
253
+ for out in model_outputs :
254
+ newline += indent + 'stream_out<{}> &{}_stream\n ' .format (out .type .name , out .name )
247
255
newline += ');\n '
248
256
# In io_parallel, a struct is returned; see myproject.h & myproject.cpp for more details
249
257
else :
@@ -256,8 +264,10 @@ def write_project_header(self, model):
256
264
newline = line
257
265
if io_type == 'io_stream' :
258
266
newline += 'component void myproject(\n '
259
- newline += indent + 'stream_in<{}> &input_stream,\n ' .format (model_inputs [0 ].type .name )
260
- newline += indent + 'stream_out<{}> &output_stream\n ' .format (model_outputs [0 ].type .name )
267
+ for inp in model_inputs :
268
+ newline += indent + 'stream_in<{}> &{}_stream,\n ' .format (inp .type .name , inp .name )
269
+ for out in model_outputs :
270
+ newline += indent + 'stream_out<{}> &{}_stream\n ' .format (out .type .name , out .name )
261
271
newline += ');\n '
262
272
else :
263
273
newline += 'component output_data myproject(\n '
@@ -452,7 +462,9 @@ def write_testbench_stream(self, model):
452
462
return
453
463
454
464
outvar = model .get_output_variables ()[0 ]
455
- invar = model .get_input_variables ()[0 ]
465
+
466
+ model_inputs = model .get_input_variables ()
467
+ model_outputs = model .get_output_variables ()
456
468
457
469
filedir = os .path .dirname (os .path .abspath (__file__ ))
458
470
@@ -479,10 +491,7 @@ def write_testbench_stream(self, model):
479
491
480
492
f = open (os .path .join (filedir , '../templates/quartus/myproject_test_stream.cpp' ), 'r' )
481
493
fout = open ('{}/{}_test.cpp' .format (model .config .get_output_dir (), model .config .get_project_name ()), 'w' )
482
-
483
- if len (model .get_input_variables ()) > 1 or len (model .get_output_variables ()) > 1 :
484
- raise Exception ('Quartus io_stream supports exactly one input/output per model' )
485
-
494
+
486
495
for line in f .readlines ():
487
496
indent = ' ' * (len (line ) - len (line .lstrip (' ' )))
488
497
@@ -491,29 +500,39 @@ def write_testbench_stream(self, model):
491
500
492
501
elif '//hls-fpga-machine learning instantiate inputs and outputs' in line :
493
502
newline = line
494
- newline += indent + 'stream_in<{}> inputs;\n ' .format (invar .type .name )
495
- newline += indent + 'stream_out<{}> outputs;\n ' .format (outvar .type .name )
496
-
503
+ for inp in model_inputs :
504
+ newline += indent + 'stream_in<{}> {}_input;\n ' .format (inp .type .name , inp .name )
505
+ for out in model_outputs :
506
+ newline += indent + 'stream_out<{}> {}_output;\n ' .format (out .type .name , out .name )
507
+
497
508
# TODO - This is one-input specific (are multiple model inputs needed at all?)
498
509
elif '//hls-fpga-machine-learning insert data' in line :
499
510
newline = line
500
- newline += indent + f'float vals[{ invar .size_cpp ()} ]; \n '
501
- newline += indent + f'for (int j = 0 ; j < { invar .size_cpp ()} ; j++) {{\n '
502
- newline += indent + f' vals[j] = in[j]; \n '
503
- newline += indent + f'}}'
504
- newline += indent + f'nnet::convert_data<float, { invar .type .name } , { invar .size_cpp ()} >(vals, inputs);\n '
505
-
511
+ c = 0
512
+ for inp in model_inputs :
513
+ newline += indent + f'float vals_{ c } [{ inp .size_cpp ()} ]; \n '
514
+ newline += indent + f'for (int j = 0 ; j < { inp .size_cpp ()} ; j++) {{\n '
515
+ newline += indent + indent + f'vals_{ c } [j] = in[j]; \n '
516
+ newline += indent + f'}}\n '
517
+ newline += indent + f'nnet::convert_data<float, { inp .type .name } , { inp .size_cpp ()} >(vals_{ c } , { inp .name } _input);\n '
518
+ c += 1
519
+
506
520
elif '//hls-fpga-machine-learning insert zero' in line :
507
521
newline = line
508
- newline += indent + f'float vals[{ invar .size_cpp ()} ]; \n '
509
- newline += indent + f'for (int j = 0 ; j < { invar .size_cpp ()} ; j++) {{'
510
- newline += indent + f' vals[j] = 0.0; \n '
511
- newline += indent + f'}}'
512
- newline += indent + f'nnet::convert_data<float, { invar .type .name } , { invar .size_cpp ()} >(vals, inputs);\n '
522
+ c = 0
523
+ for inp in model_inputs :
524
+ newline += indent + f'float vals_{ c } [{ inp .size_cpp ()} ]; \n '
525
+ newline += indent + f'for (int j = 0 ; j < { inp .size_cpp ()} ; j++) {{\n '
526
+ newline += indent + indent + f'vals_{ c } [j] = 0.0; \n '
527
+ newline += indent + f'}}\n '
528
+ newline += indent + f'nnet::convert_data<float, { inp .type .name } , { inp .size_cpp ()} >(vals_{ c } , { inp .name } _input);\n '
529
+ c += 1
513
530
514
531
elif '//hls-fpga-machine-learning insert top-level-function' in line :
515
532
newline = line
516
- newline += indent + f'ihc_hls_enqueue_noret(&{ model .config .get_project_name ()} , inputs, outputs); \n '
533
+ input_params = ', ' .join ([f'{ i .name } _input' for i in model_inputs ])
534
+ output_params = ', ' .join ([f'{ o .name } _output' for o in model_outputs ])
535
+ newline += indent + f'ihc_hls_enqueue_noret(&{ model .config .get_project_name ()} , { input_params } , { output_params } ); \n '
517
536
518
537
elif 'hls-fpga-machine-learning insert run' in line :
519
538
newline = line
@@ -522,8 +541,9 @@ def write_testbench_stream(self, model):
522
541
elif '//hls-fpga-machine-learning convert output' in line :
523
542
newline = line
524
543
newline += indent + 'float res[{}];\n ' .format (outvar .size_cpp ())
525
- newline += indent + 'nnet::convert_data_back<{}, float, {}>(outputs, res);\n ' .format (outvar .type .name ,
526
- outvar .size_cpp ())
544
+ newline += indent + 'nnet::convert_data_back<{}, float, {}>({}_output, res);\n ' .format (outvar .type .name ,
545
+ outvar .size_cpp (),
546
+ outvar .name )
527
547
528
548
elif '//hls-fpga-machine-learning insert tb-output' in line :
529
549
newline += indent + 'for(int i = 0; i < {}; i++) {{\n ' .format (outvar .size_cpp ())
@@ -617,32 +637,36 @@ def write_bridge(self, model):
617
637
elif '//hls-fpga-machine-learning insert wrapper' in line :
618
638
dtype = line .split ('#' , 1 )[1 ].strip ()
619
639
if io_type == 'io_stream' :
620
- if len (model_inputs ) > 1 or len (model_outputs ) > 1 :
621
- raise Exception ('io_stream Quartus supports exactly one input/output' )
622
- i = model_inputs [0 ]
623
- o = model_outputs [0 ]
624
-
625
- # Initialise stream object and store input data (C-array) to a 'stream' object
626
- newline = indent + 'stream_in<{}> inputs;\n ' .format (model_inputs [0 ].type .name )
627
- newline += indent + 'nnet::convert_data<{}, {}, {}>({}, inputs);\n ' .format (dtype ,
628
- i .type .name ,
629
- i .size_cpp (),
630
- i .name ,
631
- )
632
-
640
+ newline = ''
641
+ for i in model_inputs :
642
+ # Initialise stream object and store input data (C-array) to a 'stream' object
643
+ newline += indent + 'stream_in<{}> {}_input;\n ' .format (i .type .name , i .name )
644
+ newline += indent + 'nnet::convert_data<{}, {}, {}>({}, {}_input);\n ' .format (dtype ,
645
+ i .type .name ,
646
+ i .size_cpp (),
647
+ i .name ,
648
+ i .name
649
+ )
650
+
633
651
# Initialise stream output
634
- newline += '\n '
635
- newline += indent + 'stream_out<{}> outputs;\n ' .format (model_outputs [0 ].type .name )
636
-
652
+ for o in model_outputs :
653
+ newline += '\n '
654
+ newline += indent + 'stream_out<{}> {}_output;\n ' .format (o .type .name , o .name )
655
+
637
656
# Execute top-level function
638
- top_level = indent + '{}(inputs, outputs);\n ' .format (model .config .get_project_name ())
657
+ input_params = ', ' .join ([f'{ i .name } _input' for i in model_inputs ])
658
+ output_params = ', ' .join ([f'{ o .name } _output' for o in model_outputs ])
659
+
660
+ top_level = indent + '{}({}, {});\n ' .format (model .config .get_project_name (), input_params , output_params )
639
661
newline += top_level
640
662
newline += '\n '
641
663
642
664
# Store data from 'stream' output to C-array, to be then returned and handled in Python
643
- newline += indent + 'nnet::convert_data_back<{}, {}, {}>(outputs, {});\n ' .format (o .type .name ,
665
+ for o in model_outputs :
666
+ newline += indent + 'nnet::convert_data_back<{}, {}, {}>({}_output, {});\n ' .format (o .type .name ,
644
667
dtype ,
645
668
o .size_cpp (),
669
+ o .name ,
646
670
o .name
647
671
)
648
672
0 commit comments