Kernel transfer reference
A hook moves typed data between a port and lane buffers, then runs the datapath. This page is
the lookup for those in-kernel calls — the block, stream, and
complex pages each introduce the ones they need; this collects them in one place. The
element-keyed methods come from the generated <element>_array_utils:: namespace (aliased au
below); the geometry (pf, lane_capacity, get_nwords) and the lane loop in depth are in
raw arrays, and the single-schema model is in
Serialization.
Over a memory (m_axi) port
The port is an ap_uint<WORD_BW>*. Two access shapes:
A resident range — read_array_slice / write_array_slice (the block shape). Move
an arbitrary element range [i0, i1) in element coordinates (the kernel never computes i0/PF):
au::read_array_slice<WORD_BW>(mem, x); // whole array → x[0..N) (static-size overload)
au::read_array_slice<WORD_BW>(mem, i0, i1, x); // elements [i0, i1) → x[0 .. i1-i0)
au::write_array_slice<WORD_BW>(x, mem, i0, i1); // x → words [i0, i1) (unaligned ends RMW)
The lane loop — read_array_lane / write_array_lane (the complex shape). For
throughput: each call moves the next LW = lane_capacity<WORD_BW>() elements at a running word
pointer (you advance it by get_nwords<WORD_BW>(LW) words):
au::read_array_lane<WORD_BW>(src, lane, n); // LW elements in, n valid
au::write_array_lane<WORD_BW>(lane, dst, n); // LW elements out
Over a stream port
For an AXI-Stream the shape is the stream lane loop, but you drop the running
pointers (the stream sequences itself) and use the stream lane variants, which also carry TLAST:
streamutils::tlast_status tl;
au::read_axi4_stream_lane<WORD_BW>(s_in, lane, n, tl); // LW elements off the stream
au::write_axi4_stream_lane<WORD_BW>(s_out, lane, /*tlast=*/last, n);
A plain FIFO (no TLAST) uses read_stream_lane<WORD_BW>(s, dst, n) /
write_stream_lane<WORD_BW>(src, s, n).
The common loop shapes
- Load-to-array (block) — pull a whole operand resident, then compute at leisure:
read_array_slice<WORD_BW>(mem, x)into a local array. Use when you need random access (a coefficient table, a strided row) and don’t need cycle-level scheduling. - Lane loop (throughput) (complex) — step by
LW, read a lane buffer,UNROLLthe compute across lanes, write back; advance the word pointer byWPU. One shape covers both regimes (vectorized and wide-elementpf = 0). The full annotated loop with its three pragmas (ARRAY_PARTITION complete/UNROLL/PIPELINE II=1) is in raw arrays — the lane loop. - Pipelined stream loop (stream) — the same lane loop over a stream port (drop the
pointers, use the stream lane variants above); the stream self-sequences, so it streams in at one
beat per
LW.
Mapping the Python transfer interfaces to the kernel
A hook is the C++ realization of a Python transfer interface. The
ArrayTransferIF calls map to the generated array-utils methods:
| Python (transactional model) | C++ (in the hook) |
|---|---|
ArrayTransferIFMaster(element_type=Float32).write(elements) |
float32_array_utils::write_axi4_stream_lane<W>(src, s, tlast, n) (looped over the burst) |
ArrayTransferIFSlave(element_type=Float32).get(count=n) |
float32_array_utils::read_axi4_stream_lane<W>(s, dst, n, tl) (looped) |
| an array resident in memory | float32_array_utils::read_array_slice<W>(mem, out) |
ArrayUtilsStep generates these for any DataSchema element type, so a transfer parameterized on a
composite DataList gets analogous helpers.
API note: earlier drafts mapped these to the bulk
write_array(stream, …)/read_array(stream, …)names. Those were the memory bulk methods (read_array<W>(words, dst, len)) misapplied to streams; the current per-port API is the lane/slice family above. The old bulkread_array/write_array(and the per-element*_elemwrappers) have been retired from the generator — resident arrays useread_array_slice/write_array_slice(element coordinates) or theread_array_laneloop, and all live examples read in this one idiom.
(The component-method self.m_mem.read_array(...) / write_array(...) in run_proc are a different,
auto-generated path — they lower to read_array_slice / write_array_slice bursts, see
block — not hand-written hook calls.)
See also
- Raw arrays — the lane loop in depth (pragmas,
pf = 0) andread_array_slice. - Serialization — the single-schema methods and the
word_bwmodel. - Interfaces — the Python transactional model these kernel calls realize.
- Block / Stream / Complex — the patterns these calls live inside.