@@ -111,8 +111,10 @@ def write_project_cpp(self, model):
111111 newline = line
112112 if io_type == 'io_stream' :
113113 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 )
116118 newline += ') {\n '
117119 if io_type == 'io_parallel' :
118120 newline = 'output_data myproject(\n '
@@ -124,8 +126,10 @@ def write_project_cpp(self, model):
124126 newline = line
125127 if io_type == 'io_stream' :
126128 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 )
129133 newline += ') {\n '
130134 if io_type == 'io_parallel' :
131135 newline += 'component output_data myproject(\n '
@@ -148,10 +152,11 @@ def write_project_cpp(self, model):
148152 elif '//hls-fpga-machine-learning initialize input/output' in line :
149153 if io_type == 'io_stream' :
150154 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 '
155160 else :
156161 newline = line
157162 newline += indent + 'hls_register output_data outputs;\n '
@@ -195,11 +200,12 @@ def write_project_cpp(self, model):
195200 elif '//hls-fpga-machine-learning return' in line :
196201 if io_type == 'io_stream' :
197202 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 '
203209 else :
204210 newline = line
205211 newline += indent + 'return outputs;\n '
@@ -242,8 +248,10 @@ def write_project_header(self, model):
242248 # For io_stream, input and output are passed by reference; see myproject.h & myproject.cpp for more details
243249 if io_type == 'io_stream' :
244250 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 )
247255 newline += ');\n '
248256 # In io_parallel, a struct is returned; see myproject.h & myproject.cpp for more details
249257 else :
@@ -256,8 +264,10 @@ def write_project_header(self, model):
256264 newline = line
257265 if io_type == 'io_stream' :
258266 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 )
261271 newline += ');\n '
262272 else :
263273 newline += 'component output_data myproject(\n '
@@ -452,7 +462,9 @@ def write_testbench_stream(self, model):
452462 return
453463
454464 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 ()
456468
457469 filedir = os .path .dirname (os .path .abspath (__file__ ))
458470
@@ -479,10 +491,7 @@ def write_testbench_stream(self, model):
479491
480492 f = open (os .path .join (filedir , '../templates/quartus/myproject_test_stream.cpp' ), 'r' )
481493 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+
486495 for line in f .readlines ():
487496 indent = ' ' * (len (line ) - len (line .lstrip (' ' )))
488497
@@ -491,29 +500,39 @@ def write_testbench_stream(self, model):
491500
492501 elif '//hls-fpga-machine learning instantiate inputs and outputs' in line :
493502 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+
497508 # TODO - This is one-input specific (are multiple model inputs needed at all?)
498509 elif '//hls-fpga-machine-learning insert data' in line :
499510 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+
506520 elif '//hls-fpga-machine-learning insert zero' in line :
507521 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
513530
514531 elif '//hls-fpga-machine-learning insert top-level-function' in line :
515532 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 '
517536
518537 elif 'hls-fpga-machine-learning insert run' in line :
519538 newline = line
@@ -522,8 +541,9 @@ def write_testbench_stream(self, model):
522541 elif '//hls-fpga-machine-learning convert output' in line :
523542 newline = line
524543 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 )
527547
528548 elif '//hls-fpga-machine-learning insert tb-output' in line :
529549 newline += indent + 'for(int i = 0; i < {}; i++) {{\n ' .format (outvar .size_cpp ())
@@ -617,32 +637,36 @@ def write_bridge(self, model):
617637 elif '//hls-fpga-machine-learning insert wrapper' in line :
618638 dtype = line .split ('#' , 1 )[1 ].strip ()
619639 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+
633651 # 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+
637656 # 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 )
639661 newline += top_level
640662 newline += '\n '
641663
642664 # 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 ,
644667 dtype ,
645668 o .size_cpp (),
669+ o .name ,
646670 o .name
647671 )
648672
0 commit comments