Description
Explanation
The II violation message is issued when the tool cannot satisfy the user-specified hard constraint. II violation conceptually occurs because of the hardware dependencies generated by the HLS from user code when the function/loop is pipelined with II=1. These dependencies are the same as the processor dependencies as explained in this wiki: https://en.wikipedia.org/wiki/Data_dependency
These dependencies can be categorized into three sections:
- Memory dependencies
-
Memory dependencies arise when there is memory port contention. This contention only occurs if the loop is pipelined with II=1 and the number of access per loop iteration > 2. This limitation of memory ports is a hardware limit of a storage resource - BRAM/URAM.
So if the user tries to perform >2 access per loop iteration the tool won't be able to schedule the operations in one cycle. This can be visualized in Vitis High-Level Synthesis User Guide (UG1399)
Solution: Partition the array with regards to the user code or refactor the array to multiple dimensions.
- Data dependencies
-
A data dependence is a property of the program, where the current instruction uses the value produced by an earlier instruction. There are 3 main scenarios where these dependencies can arise.
- The current loop iteration uses the value
generated by an earlier loop iteration. and this value takes N
cycles to be generated by the earlier iteration. This prevents
the current iteration starting at the next cycle.
- The following snippet displays the behavior.
- In the below example because of the multiplication of a float variable the loop cannot schedule at II=1.
float a; float b; for(...) { #pragma HLS pipeline II=1 val *= a*b; }
- The current loop iteration uses the value generated by an earlier loop iteration but in infrequent terms. and this value takes N cycles to be generated by the earlier iteration. This prevents the current iteration starting at the next cycle.
-
The current loop iteration exit condition uses the value generated by an earlier loop iteration. and this value takes N cycles to be generated by the earlier iteration. This prevents the current iteration starting at the next cycle.
The following code snippet shows the behavior.
float a; float b; for(...) { #pragma HLS pipeline II=1 if(val==3.69) break; val *= a*b; }
Solution: These dependencies are visualized in the schedule viewer l to help the user understand. Break up these dependencies in the user code.
- The current loop iteration uses the value
generated by an earlier loop iteration. and this value takes N
cycles to be generated by the earlier iteration. This prevents
the current iteration starting at the next cycle.
- False dependencies
-
void histogram(int in[INPUT SIZE], int hist[VALUE SIZE]) { int acc = 0; int i, val; int old = in[0]; #pragma HLS DEPENDENCE variable=hist intra RAW false for(i = 0; i < INPUT SIZE; i++) { #pragma HLS PIPELINE II=1 val = in[i]; if(old == val) { acc = acc + 1; } else { hist[old] = acc; acc = hist[val] + 1; } old = val; } hist[old] = acc;