Communication between two hardware modules is one of the main tasks in digital system design. When two tasks exchange signals or data, they should know when to send and receive the active data. In other words, there should be a synchronisation mechanism between them for a successful data transaction. In the low-level RTL design approach, handshaking signals usually address this issue, and in high-level design flows, interfaces and protocols define and orchestrate the communication among modules.
High-level synthesis tools such as Vitis-HLS provide mechanisms for implementing low-level handshaking signals as well as high-level interfaces and protocols. HLS tools usually infer the actual implementation automatically if designers follow a proper coding style describing their hardware systems.
There are three main approaches to synchronise two hardware modules or logic circuits:
- Using the design clock
- Using handshaking interfaces
- Using stream data transfer
Design Clock
If two modules can generate and receive data in each clock cycle, then synchronisation between them is trivial, and the active edge of the clock can be used for this purpose. The UART transmitter circuit explained in this post is an excellent example of this case.

To be able to use this simple synchronisation mechanism, the SCII design approach should be followed for implementing hardware modules. The following figure shows a pulse_generator and up_counter modules designed in Vitis-HLS following the SCII design approach. The up_counter module counts wherever the user presses the up_count pushbutton input.

If the modules do not follow the SCII design approach, the up-counter may lose the signal pulse indicating the activation of the pushbutton switch or may count multiple times.
Handshaking Interfaces
Handshaking signals can be used to synchronise two hardware modules in HLS. The handshaking in HLS also known as Port-Level I/O Interfaces&Protocols.
The port-level I/O can use simple wires such as valid and acknowledge signals to implement the desired handshaking, or it can implement complex protocols for specific modules such as memory and CPUs.
Simple port-level I/O interfaces include ap_ack, ap_hs, ap_ovld, ap_stable, and ap_vld. And specific complex I/O interfaces include ap_memory, ap_fifo, m_axi, s_axilite, and axis.

The following figure shows how we can use a valid/acknowledge handshaking mechanism for the up_couter example which is not designed using the SCII approach.

Streaming Data Transfer
In this synchronisation mechanism, the sender and receiver modules use a shared FIFO memory for communication. The sender module writes its data into the FIFO whenever the data is valid, and the receiver reads data from the FIFO whenever it is ready for processing the data. The Vitis-HLS provides two port-level interfaces for data streaming: ap_fifo and axis. The following figure shows how to connect two data_source and accumulator modules together via a FIFO memory.

If you are interested in logic design in HLS, please refer to here.