Array arguments are implemented by default as an ap_memory
interface using word-addressing. This is a standard block RAM interface
with data, address, chip-enable, and write-enable ports.
An ap_memory
interface can be implemented as a
single-port of dual-port interface. If Vitis HLS can
determine that using a dual-port interface will reduce the initial interval, it will
automatically implement a dual-port interface. The BIND_STORAGE pragma or directive can be
used to specify the memory resource and if this directive is specified on the array with a
single-port block RAM, a single-port interface will be implemented. Conversely, if a dual-port
interface is specified using the BIND_STORAGE pragma and Vitis HLS determines this interface provides no benefit it will automatically
implement a single-port interface.
If the array is accessed in a sequential manner an ap_fifo
interface can be used. As with the ap_hs
interface, Vitis HLS will halt if it determines the data access is not sequential, report a
warning if it cannot determine if the access is sequential or issue no message if it
determines the access is sequential. The ap_fifo
interface can only be used
for reading or writing, not both.
ap_memory, bram
The ap_memory
and
bram
interface port-level I/O protocols are used to implement array
arguments. This type of port-level I/O protocol can communicate with memory elements (for
example, RAMs and ROMs) when the implementation requires random accesses to the memory
address locations.
ap_fifo
interface instead. The ap_fifo
interface reduces the hardware overhead,
because address generation is not performed.The ap_memory
and bram
interface port-level I/O
protocols are similar, though not the same. The ap_memory
interface uses word-based addressing, and generates an additional chip enable control
signal, while the bram
interface uses byte-addressing. The
following table summarizes the differences:
ap_memory | bram | |
---|---|---|
Address of the nth word | n*1 | n*(word-size in bytes) |
Address bit-width | ceil(log2(depth)) | 32 bit |
Supported word size | arbitrary | 8*power-of-two bits |
Byte-enable support | Yes, if word size is multiple of bytes | Yes |
IP integrator Support | Not-available | Supported by Block Memory Generator and/or Embedded Memory Generator |
In the Vivado tool, the way the interfaces are represented is also different:
- The
ap_memory
interface appears as discrete ports. - The
bram
interface appears as a single, grouped port. In IP integrator, you can use a single connection to create connections to all ports.
When using a memory interface, specify the implementation using the BIND_STORAGE pragma. If no target is specified for the arrays, Vitis HLS determines whether to use a single or dual-port RAM interface.
The following figure shows an array named
d
specified as a single-port block RAM. The port names are based on the
C/C++ function argument. For example, if the C/C++ argument is d
, the
chip-enable is d_ce
, and the input data is d_q0
based on
the output/q
port of the BRAM.
After reset, the following occurs:
- After start is applied, the block begins normal operation.
- Reads are performed by applying
an address on the output address ports while asserting the output signal
d_ce
.Note: For a default block RAM, the design expects the input datad_q0
to be available in the next clock cycle. You can use the BIND_STORAGE pragma to indicate the RAM has a longer read latency. - Write operations are performed
by asserting output ports
d_ce
andd_we
while simultaneously applying the address and output datad_d0
.
ap_fifo
When an output port is written to, its
associated output valid
signal interface is the most
hardware-efficient approach when the design requires access to a memory element and the
access is always performed in a sequential manner, that is, no random access is required.
The ap_fifo
port-level I/O protocol supports the following:
- Allows the port to be connected to a FIFO
- Enables complete, two-way
empty-full
communication - Works for arrays, pointers, and pass-by-reference argument types
ap_fifo
interface often use pointers and might
access the same variable multiple times. To understand the importance of the volatile
qualifier when using this coding style, see Multi-Access Pointers on the Interface.In the following example, in1
is a pointer that
accesses the current address, then two addresses
above the current address, and finally one address
below.
void foo(int* in1, ...) {
int data1, data2, data3;
...
data1= *in1;
data2= *(in1+2);
data3= *(in1-1);
...
}
If in1
is
specified as an ap_fifo
interface, Vitis HLS checks the accesses, determines the accesses are not in sequential
order, issues an error, and halts. To read from non-sequential address locations, use an
ap_memory
or bram
interface.
You cannot specify an
ap_fifo
interface on an argument that is both read from and written to.
You can only specify an ap_fifo
interface on an input or an output
argument. A design with input argument in
and output argument
out
specified as ap_fifo
interfaces behaves as shown in
the following figure.
For inputs, the following occurs:
- After ap_start is applied, the block begins normal operation.
- If the input port is ready to
be read but the FIFO is empty as indicated by input port
in_empty_n
Low, the design stalls and waits for data to become available. - When the FIFO contains data as
indicated by input port
in_empty_n
High, an output acknowledgein_read
is asserted High to indicate the data was read in this cycle.
For outputs, the following occurs:
- After start is applied, the block begins normal operation.
- If an output port is ready to
be written to but the FIFO is full as indicated by
out_full_n
Low, the data is placed on the output port but the design stalls and waits for the space to become available in the FIFO. - When space becomes available in
the FIFO as indicated by
out_full_n
High, the output acknowledge signalout_write
is asserted to indicate the output data isvalid
. - If the top-level function or
the top-level loop is pipelined using the
-rewind
option, Vitis HLS creates an additional output port with the suffix_lwr
. When the last write to the FIFO interface completes, the_lwr
port goes active-High.