Inside the canonical region, the canonical body should follow these guidelines:
- Use a local, non-static scalar or an array variable. A local variable is declared inside the function body (for dataflow in a function) or loop body (for dataflow inside a loop). Refer to Limitations of Control-Driven Task-Level Parallelism for additional limitations on arrays.
- A sequence of function calls that pass data forward (with no feedback unless using
hls::stream/hls::stream_of_blocks
), from a function to one that is lexically later, under the following conditions:- Variables (except scalar) can have only one reading process and one writing process.
- Use write before read (producer before consumer) if you are using local non-scalar variables, which then become channels. For scalar variables, both write before read and read before write are allowed.
- Use read before write (consumer before producer) if you are using function arguments. Any intra-body anti-dependencies must be preserved by the design.
- Function return type must be void.
- No loop-carried dependencies are allowed among different processes via
variables except when FIFOs are used. Forward loop-carried dependencies are
supported for arrays transformed to streams and both forward and backward
dependencies are supported for
hls::streams
.- Except when these dependencies exist across successive calls to the top function (i.e., inout argument written by one iteration and read by the following iteration).
- No control whatsoever is supported inside a dataflow region, except inside
function calls (that define processes).
- For canonical dataflow, there should be no conditionals, no loops, no return or goto statements, and no C++ exceptions such as throw.