hls::task objects in your code include the header file
hls_task.h.The hls::task library provides a simpler
way of modeling purely streaming kernels, allowing static instantiation of tasks with
only streaming I/O (hls::stream or hls::stream_of_blocks). This reduces the need for checks
for empty stream needed to model concurrent processes in C++.
The following is a simple example that can be found at simple_data_driven on GitHub:
void odds_and_evens(hls::stream<int> &in, hls::stream<int> &out1, hls::stream<int> &out2) {
hls_thread_local hls::stream<int> s1; // channel connecting t1 and t2
hls_thread_local hls::stream<int> s2; // channel connecting t1 and t3
// t1 infinitely runs splitter, with input in and outputs s1 and s2
hls_thread_local hls::task t1(splitter, in, s1, s2);
// t2 infinitely runs function odds, with input s1 and output out1
hls_thread_local hls::task t2(odds, s1, out1);
// t3 infinitely runs function evens, with input s2 and output
hls_thread_local hls::task t3(evens, s2, out2);
}
Notice the top-level function, odds_and_evens uses streaming input and output interfaces. This is a
purely streaming kernel. The top-level function includes the following:
- s1 and s2 are thread-local streams (
hls_thread_local) and are used to connect the task-channel tasks t1 and t2. These streams need to be thread-local so that they can be kept alive across top-level calls. - t1, t2, and t3 are the thread-local
hls::taskthat execute the functions (splitter,odds, andevensrespectively). The tasks run infinitely and just process data on their input streams. No synchronization is needed.
However, this type of model does have some restrictions such as:
- You cannot access non-local memory
- Non-stream data, such as scalar and array variables, must all be local to the processes and cannot be passed as arguments
- A task cannot be nested inside a sequential region
- You must explicitly describe the parallelism in the design by the specification of parallel tasks
The hls::task objects can be mixed
freely with standard dataflow-style function calls, which can move data in and out of
memories (DRAM and BRAM). Tasks also support splitting channels (hls::split) to support one-to-many data distributions to build pools of
workers that process streams of data, and merging channels (hls::merge) to support many-to-one data aggregation.