Deterministic Behavior - 2023.2 English

Vitis High-Level Synthesis User Guide (UG1399)

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 English

As discussed in Blocking API, the blocking API can have both deterministic and non-deterministic behavior as shown in the following code example:

func1()
{
   while(!s.empty()) {
   s.read();
   }
}

During C-simulation the data to the stream is always available so the while loop runs through to completion. However, if the data stream has a single bubble when running in hardware the while loop will exit, and func1 will return prematurely. This will lead to non-deterministic behavior between C-simulation and RTL execution.

The proper way to implement this loop is to use the side-channel signal tlast, as shown in the following example. Refer to AXI4-Stream Interfaces with Side-Channels for more information.

func1()
{
   while(!tlast) { 
      s1.read() 
   }
}
The blocking API can be deterministic when used in one of the following ways.
Case 1 - Simple read/write to the FIFO
int data = in.read();
  if (data >= 10)
    out1.write(data);
  else
    out2.write(data);
Case 2 - FULL and EMPTY check using blocking API

This case does not perform any computation with side effects, i.e. read or write a stream, memory, or static variable is still considered to use only blocking stream accesses.

void df(hls::stream<...> &s1, hls::stream<...> &s2, ...) {
#pragma HLS dataflow
 
  p1(s1, ...);
  p2(s2, ...);
...
}
void p1(hls::stream<...> &s1, ...) {
  if (s1.empty())
    return;
  ... = s1.read();
  ...
}
void p2(hls::stream<...> &s2, ...) {
  if (s2.full())
    return;
  ...
  s2.write(...);
}