Stream Port Resource Constraint (HLS 200-2199) - Stream Port Resource Constraint (HLS 200-2199) - 2026.1 English - UG1448

Vitis HLS Messaging (UG1448)

Document ID
UG1448
Release Date
2026-06-23
Version
2026.1 English

Description

The main message, HLS 200-2199, provides the main information about the cause of the II increase. The auxiliary message, HLS 200-2198, shows all the operations competing for the same resource (memory port or FIFO port implementing a streamed top array or a top hls::stream).

INFO: [HLS 200-2199] The II Violation in module 'pad_general_unsigned_short_16_Pipeline_VITIS_LOOP_23_2' (loop 'VITIS_LOOP_23_2'): Potential resource conflict between fifo read operation ('in_15_read', ./pad.h:48) on port 'in_15' (./pad.h:48) and fifo read operation ('in_15_read_15', ./pad.h:48) on port 'in_15' (./pad.h:48) on common resource 'in_15'.
INFO: [HLS 200-2198] Existing conflicting constraints include from fifo read operation ('in_15_read', ./pad.h:48) on port 'in_15' (./pad.h:48) to fifo read operation ('in_15_read_1', ./pad.h:48) on port 'in_15' (./pad.h:48) with distance of 1 (conflict 1 of 15)
...
INFO: [HLS 200-2198] Existing conflicting constraints include from fifo read operation ('in_15_read_14', ./pad.h:48) on port 'in_15' (./pad.h:48) to fifo read operation ('in_15_read_15', ./pad.h:48) on port 'in_15' (./pad.h:48) with distance of 1 (conflict 15 of 15)
INFO: [HLS 200-1470] Pipelining result : Target II = 1, Final II = 16, Depth = 72, loop 'VITIS_LOOP_23_2'

Explanation

The message is generated when an hls::stream or streamed array is accessed multiple times in a pipelined loop. All FIFOs have exactly one read port and one write port.

Recommendation

To resolve the issue, check the conditions under which the conflicting operations are executed (both control and observability-dependent mutual exclusion) and ensure that they are correct and easy to analyze. In the following example, the code looks like this (the pipeline pragma fully unrolls all the nested loops):

template <typename T>
void pad_general(hls::stream<T> in[16], hls::stream<T> out[16], PadConfig config) {
...
  for (int c = 0; c < iters; c++) {
#pragma HLS pipeline II=1
...
    for (int m = 0; m < 16; m++) {
...
        int ii = i-config.pad_start[0]; ...
        int idx_read = ii*config.input_dim_size[3]*...;
        tmp = in[idx_read%16].read();
        out[m].write(tmp);
    }
  }
}

It is important to note the following:

  • Top arrays of streams in and out are automatically fully partitioned into K streams.
  • In this case, the value of idx_read depends on the content of some input arrays, for example config.pad_start[0] and config.input_dim_size[3].
  • Vitis HLS is therefore unable to infer that different input streams are accessed by each iteration of the unrolled loop over m.
  • All K accesses can potentially read the same stream. in_15 is reported in the preceding example, and any one of the other 15 in_… streams could have been reported. A minimum II of 16 is required.
  • However, Vitis HLS can infer that all accesses to outare to one of the 16 streams.

In this case, a solution might be a single stream containing an array of 16 T, read into a local fully partitioned array and then used in the loop:

template <typename T>
void pad_general(hls::stream<hls::vector<T, 16>> &in, hls::stream<T> out[16], PadConfig config) {
...
  for (int c = 0; c < iters; c++) {
#pragma HLS pipeline II=1
    hls::vector<T,K> t = in.read();
#pragma HLS array_partition complete variable=t
...
    for (int m = 0; m < 16; m++) {
...
        int ii = i-config.pad_start[0]; ...
        int idx_read = ii*config.input_dim_size[3]*...;
        tmp = t[idx_read%16];
        out[m].write(tmp);
    }
  }
}

For more information and for a definition of terms, refer to Pipeline II Violations.