## Intel® High Level Synthesis Compiler Pro Edition: Reference Manual

ID 683349
Date 12/13/2021
Public

The Intel® HLS Compiler Pro Edition implements task functions in way similar to HLS component functions, but with some additional constraints.

You can get data in and out of task functions in the following ways:
Task function interfaces are subject to the following restrictions:
• You cannot use Avalon® MM Host interfaces (ihc::mm_host) defined at global or file scope in a component or its tasks.
• Pointer or reference data types cannot be passed to task functions as arguments unless they are a pointer or reference to an explicit Avalon® MM Host interface.
For more details and example of task function interfaces, refer to the following tutorial:

You can invoke a function as a task with the ihc::launch<>() and ihc::collect<>() API.

An ihc::launch<task_function>() call in your code produces a call interface for the specified task with the top-level component as the source and the task as the sink. The top-level component invokes the call interface of a task by asserting the start signal to start a new execution of the task.

An ihc::collect<task_function>() call in your code produces a return interface for the specified task with the task as the source and the top-level component as the sink. This return interface has a done signal that is asserted by the task when it has completed a single execution. When the top-level component invokes the return interface it consumes this donesignal and retrieves any returned values.

In the High Level Design Reports (report.html), the ihc::launch and ihc::collect calls appear as blocking streaming write and streaming read operations.

### Scalar Parameters and Return Values

Like HLS components, the scalar parameters and return value for an HLS task are implemented as conduits and the hand-shaking is implemented as a simple stall/valid handshake. The ihc::launch and ihc::collect calls connect directly to the HLS task function do and return streams.

In the High Level Design Report (report.html), the ihc::launch and ihc::collect calls appear as blocking streaming write and streaming read operations.

### Interaction with External Systems

Task functions can use a global instance of the ihc::stream_in class to take an input from the external system, or a global instance of the ihc::stream_out class to provide output to the external system.

The global ihc::stream_in and ihc::stream_out streams must be declared outside of any struct variables, and they cannot be declared in arrays.

### Communication Between HLS Task Functions

For two task functions to communicate with each other, connect them with a global ihc::stream object (instead of the ihc::stream_in and ihc::stream_out objects).

The global ihc::stream object must be declared outside of any struct variables, and it cannot be declared in an array.

The ihc::stream object has an API very similar to the ihc::stream_in and ihc::stream_out classes. However, since these streams always require handshaking, the API does not support the parameters ihc::usesReady or ihc::usesValid. They do support tryRead and tryWrite API functions.

The ihc::stream objects can have both of their endpoints within the system of tasks. This includes within the same function as well. For an example of using an ihc::stream within a single function as a FIFO, see the following tutorial:
<quartus_installdir>/hls/examples/tutorials/system_of_tasks/internal_stream
If an instance of the ihc::stream class has only one endpoint within the system of tasks, it is treated as if it were a ihc::stream_in or ihc::stream_out class based on its usage within the system, so it can be used interchangeably with ihc::stream_in or ihc::stream_out (provided that the limitations do not affect the design). An ihc::stream object can be used for multiple tasks to communicate with one another. See the following tutorial:
<quartus_installdir>/hls/examples/tutorials/system_of_tasks/parallel_loops
The following diagram shows how you might use the ihc::stream object to communicate between task functions:
Figure 13. Example of a Systems of Tasks using Internal Streams

HLS task functions are subject to the following restrictions:
• Task functions cannot be shared between multiple components.
• All read sites and write sites for a stream must be within the same function (component or task).
• If you implement a class member function as a task function, the member function must be static. If you want to parameterize the function behavior, use function parameters or template parameters. You cannot use instance variables of an object.
• A task function can be launched (with ihc::launch) only from one component function or task function. The launching function and the collecting function can be different functions but they must part of the same component system of tasks.
• A task function can be collected (with ihc::collect) only from one component or task function. The collecting function and the launching function can be different functions but they must part of the same component system of tasks.
• No guarantee of execution order is provided between independent I/O instructions, even at the task level.

The ihc::launch and ihc::collect calls to a particular task function are executed in order.

Any stream accesses to that task from the current function are executed in instruction order only with respect to ihc::launch and ihc::collect calls to the corresponding function.

Figure 14. Example 1 of a Valid ihc::launch/ihc::collect Sequence
Figure 15. Example 2 of a Valid ihc::launch/ihc::collect Sequence
Figure 16. Example 3 of a Valid ihc::launch/ihc::collect Sequence
Figure 17. Example of an Invalid ihc::launch/ihc::collect Sequence

You can use the following function-level attributes on an HLS task function:
• hls_max_concurrency
• hls_component_ii
• hls_scheduler_target_fmax_mhz
• hls_disable_component_pipelining

In addition to these function attributes, you can use any HLS attributes and pragmas within your HLS task functions. For example, you can use attributes and pragmas like #pragma ii, #pragma ivdep, hls_memory, and hls_register.

You cannot use component macros or component invocation interface control attributes when you define HLS task functions. For example, you cannot use hls_avalon_agent_register_argument, hls_conduit_argument, hls_stall_free_return, or hls_avalon_streaming_component

The compiler schedules launches and collects in the top-level component or caller datapath.

If you schedule multiple tasks with different latencies, you might need to add capacity to ihc::launch and ihc::collect calls.

Similarly, setting the capacity parameter in an ihc::launch call inserts a buffer that allows the caller to push work onto the task function which is then free to pull work off that queue when it can.

Setting the capacity parameter in an ihc::collect call inserts a buffer that can hold the return values as they are computed by the task function. The caller function is free to pull the return values from the buffer at a convenient later time without causing backpressure on the task function.

For more information on how and when to use the capacity parameter with your ihc::launch and ihc::collect calls, refer to "Explicitly Add Buffer Capacity to Your Design When Needed" in the Intel HLS Compiler Best Practices Guide

You can also review the following tutorial:
<quartus_installdir>/hls/examples/tutorials/system_of_tasks/launch_and_collect_capacity