Understanding Volatile Data - 2024.1 English

Vitis High-Level Synthesis User Guide (UG1399)

Document ID
Release Date
2024.1 English

The code in Multi-Access Pointers on the Interface is written with intent that input pointer d_i and output pointer d_o are implemented in RTL as FIFO (or handshake) interfaces to ensure that:

  • Upstream producer modules supply new data each time a read is performed on RTL port d_i.
  • Downstream consumer modules accept new data each time there is a write to RTL port d_o.

When this code is compiled by standard C/C++ compilers, the multiple accesses to each pointer is reduced to a single access. As far as the compiler is concerned, there is no indication that the data on d_i changes during the execution of the function and only the final write to d_o is relevant. The other writes are overwritten by the time the function completes.

Vitis HLS matches the behavior of the gcc compiler and optimizes these reads and writes into a single read operation and a single write operation. When the RTL is examined, there is only a single read and write operation on each port.

The fundamental issue with this design is that the test bench and design do not adequately model how you expect the RTL ports to be implemented:

  • You expect RTL ports that read and write multiple times during a transaction (and can stream the data in and out).
  • The test bench supplies only a single input value and returns only a single output value. A C/C++ simulation of Multi-Access Pointers on the Interface shows the following results, which demonstrates that each input is being accumulated four times. The same value is being read once and accumulated each time. It is not four separate reads.
    Din Dout
    0   0
    1   4
    2   8
    3   12

To make this design read and write to the RTL ports multiple times, use a volatile qualifier as shown in Multi-Access Pointers on the Interface. The volatile qualifier tells the C/C++ compiler and Vitis HLS to make no assumptions about the pointer accesses, and to not optimize them away. That is, the data is volatile and might change.

The volatile qualifier:
  • Prevents pointer access optimizations.
  • Results in an RTL design that performs the expected four reads on input port d_i and two writes to output port d_o.

Even if the volatile keyword is used, the coding style of accessing a pointer multiple times still has an issue in that the function and test bench do not adequately model multiple distinct reads and writes. In this case, four reads are performed, but the same data is read four times. There are two separate writes, each with the correct data, but the test bench captures data only for the final write.

Tip: In order to see the intermediate accesses, use cosim_design -trace_level to create a trace file during RTL simulation and view the trace file in the appropriate viewer.

The Multi-Access volatile pointer interface can be implemented with wire interfaces. If a FIFO interface is specified, Vitis HLS creates an RTL test bench to stream new data on each read. Because no new data is available from the test bench, the RTL fails to verify. The test bench does not correctly model the reads and writes.