Vitis HLS Testbench
The generated schema classes also make the C++ testbench much simpler. Instead of manually decoding binary files and packing AXI4-Stream words by hand, the testbench can operate directly on typed protocol objects.
In this example, the testbench performs five basic tasks:
- read the coefficients, DATA command header, sample payload, and END command header from binary files generated by Python
- write the DATA command header + samples + END command header into the AXI4-Stream input ahead of the kernel call (C-sim runs the kernel as a synchronous function, so all inputs must be queued first)
- invoke the
polykernel with the coefficients passed as ans_axiliteargument and the status fields (halted,error_code,tx_id_status) passed ass_axilitereferences - deserialize the output stream back into a typed response header and sample buffer, then write them to binary files
- write
regmap_status.jsonwith the final values ofhalted,error_code, andtx_id_statussoValidateCSimStepcan cross-check them against the Python regmap status
The kernel returns after it consumes the END header (or halts on a TLAST error). In synthesized RTL the return asserts ap_done; in C-simulation it is just “the call completed.”
Testbench responsibilities
The HLS testbench is implemented in examples/poly/poly_tb.cpp.
- Load
coeffs.bininto afloat[4]array (used as thes_axilitecoefficient argument). - Load
data_cmd_hdr.bininto aPolyCmdHdrandsamp_in_data.bininto afloat[]sample buffer. - Load
end_cmd_hdr.bininto a secondPolyCmdHdr. - Push the DATA header, packed samples (with TLAST on the final word), and END header into the input stream.
- Declare AXI-Lite output scalars (
ap_uint<1> halted,ap_uint<8> error_code,ap_uint<16> tx_id_status) and callpoly(in_stream, out_stream, coeffs, halted, error_code, tx_id_status). - Drain
resp_hdrandsamp_outfrom the output stream into binary files (resp_hdr_data.bin,samp_out_data.bin). - Write
regmap_status.jsoncontaining the three AXI-Lite output values.
Because the kernel halts (rather than emitting a per-transaction footer) on framing errors, neither a streamed footer nor any extra TLAST-sync file is produced — ValidateCSimStep instead compares regmap_status.json between the Python and Vitis runs and asserts halted == 0 and error == NO_ERROR for both.
Why this matters
In a conventional HLS testbench, a significant amount of code is often spent on:
- manually reading packed binary data
- converting that data into stream words
- reconstructing typed responses from the output stream
- keeping the testbench protocol consistent with both the software model and the kernel interface
In this example, those concerns are handled by schema-generated helpers.
As a result, the testbench mostly expresses the transaction flow itself:
- load inputs
- stream them into the kernel
- collect outputs
- write results for comparison
This reduces boilerplate and makes it easier to keep the Python model, generated headers, kernel, and testbench synchronized.