Behavioral Simulation
The FrontPanel Subsystem IP Core ships with a Bus Functional Model (BFM) that replaces the USB transport layer during simulation. Instead of a physical host connection, your testbench calls API tasks directly on the BFM, which drives the same AXI interfaces your logic sees in hardware.
This page covers behavioral simulation for both FrontPanel-AXI designs (SZG-HUB1450) and FrontPanel Classic designs (FX3-based boards).
FrontPanel-AXI (SZG-HUB1450)
This tutorial simulates an AXI-Stream loopback using two AMD IP cores: axis_data_fifo as a write-path buffer and axis_dwidth_converter to adapt the 32-bit write path to the 64-bit read path. You write 16 bytes from the host, read them back, and verify the values match.
The setup below (loopback concept, prerequisites, and IP settings) is shared. The tutorial then splits into a Block Design flow and an RTL flow that produce the same result.
The okHost BFM these steps drive is documented in the FrontPanel AXI HDL Simulation pages: the BFM behavioral contract it honors, and the Verilog (Vivado XSim) binding with its API tasks.
How the loopback works
The SZG-HUB1450 in Mode 3 (10G Up/2.5G Down) exposes asymmetric AXI-Stream ports. The m_axis and s_axis directions are documented under AXI-Stream, and the per-mode stream widths under Bandwidth Modes:
| Port | Direction | Width |
|---|---|---|
m_axis_tdata | okHost to your logic (host write) | 32-bit |
s_axis_tdata | your logic to okHost (host read) | 64-bit |
The chain bridges the width difference: axis_data_fifo (32-bit) buffers the write path, then axis_dwidth_converter packs pairs of 32-bit words into 64-bit beats for the read path:
okHost.m_axis (32) -> axis_data_fifo (32) -> axis_dwidth_converter (32->64) -> okHost.s_axis (64)Code language: CSS (css)Prerequisites
Complete both before starting:
IP cores and settings
Both flows use these three IP cores with identical settings.
| IP core | Settings |
|---|---|
| FrontPanel Subsystem | Board: SZG-HUB1450-AU10P-10G; Mode: Mode 3 (10G Up/2.5G Down) |
AXI4-Stream Data FIFO (axis_data_fifo) | TDATA Width: 4 bytes (32-bit); FIFO Depth: 16; Has TLAST: enabled |
AXI4-Stream Data Width Converter (axis_dwidth_converter) | Slave Interface TDATA: 4 bytes (32-bit); Master Interface TDATA: 8 bytes (64-bit) |
The test sequence
Both flows drive the same stimulus: reset the stream, write 16 bytes (0x10 through 0x1F), read them back, and compare byte-by-byte. Only the OKHOST macro differs, set to match each flow’s hierarchy. Each flow’s “Create the testbench” step adds these declarations and initial blocks:
integer error_code;
reg [63:0] transfer_byte_count;
integer i;
reg [7:0] byte_val;
integer fail_count;
initial begin
`OKHOST.axi_stream_reset(error_code);
repeat (10) @(posedge `OKHOST.aclk);
// Load write buffer: bytes 0x10 through 0x1F
for (i = 0; i < 16; i = i + 1)
`OKHOST.set_write_buffer(i, 8'h10 + i[7:0]);
// Write 16 bytes -> 4 x 32-bit beats via m_axis -> FIFO -> converter
`OKHOST.axi_stream_write(64'd16, 10.0, error_code, transfer_byte_count);
if (error_code != 0)
$display("FAIL: axi_stream_write error %0d", error_code);
// Read 16 bytes <- 2 x 64-bit beats via s_axis
`OKHOST.axi_stream_read(64'd16, 10.0, error_code, transfer_byte_count);
if (error_code != 0)
$display("FAIL: axi_stream_read error %0d", error_code);
// Compare write buffer to read buffer byte-by-byte
fail_count = 0;
for (i = 0; i < 16; i = i + 1) begin
`OKHOST.get_read_buffer(i, byte_val);
if (byte_val !== (8'h10 + i[7:0])) begin
$display("FAIL: byte[%0d] expected 0x%02h got 0x%02h",
i, 8'h10 + i[7:0], byte_val);
fail_count = fail_count + 1;
end
end
if (fail_count == 0)
$display("=== ALL 16 BYTES MATCH ===");
else
$display("=== %0d of 16 bytes failed ===", fail_count);
$finish;
end
initial begin
#10_000_000; // 10 ms watchdog
$display("ERROR: Testbench timeout");
$finish;
endCode language: PHP (php)The expected console output for both flows:
=== ALL 16 BYTES MATCH ===Choose your flow
| Block Design Flow | RTL Flow | |
|---|---|---|
| Design entry | IP Integrator canvas | Verilog instantiation |
| IP connections | Draw wires between blocks | Port-by-port in HDL |
| Testbench instantiates | Generated BD wrapper | Each IP individually |
| Choose if… | You are building your design in IP Integrator | You are writing all HDL by hand |
Block Design Flow
In this flow, the three IP cores are added to a Vivado IP Integrator block design and connected graphically. Vivado wraps the design in a generated Verilog module that the testbench instantiates.
Create a block design
Step 1: Open Create Block Design. In the Flow Navigator, under IP Integrator, click Create Block Design.
Step 2: Name the design. Enter a name (for example fp_loopback) and click OK. The block design canvas opens.
Add and configure the IP cores
Step 3: Open the IP Catalog search. In the block design canvas, click the + button (or right-click and select Add IP).
Step 4: Add the three IP cores. Add the FrontPanel Subsystem, AXI4-Stream Data FIFO, and AXI4-Stream Data Width Converter IPs to the canvas.
Step 5: Configure each IP. Double-click each block and apply the settings from IP cores and settings above.

Connect the AXI-Stream interfaces
Draw each connection by hovering over an interface port until the pencil cursor appears, then dragging to the target port.
Step 6: Connect the write path into the FIFO. Connect frontpanel_0 M_AXIS to axis_data_fifo_0 S_AXIS.
Step 7: Connect the FIFO to the width converter. Connect axis_data_fifo_0 M_AXIS to axis_dwidth_converter_0 S_AXIS.
Step 8: Connect the width converter back to okHost. Connect axis_dwidth_converter_0 M_AXIS to frontpanel_0 S_AXIS.
The M_AXIS and S_AXIS ports are AXI-Stream bus interfaces; Vivado connects all signals in the bundle (tdata, tvalid, tready, tlast) with a single wire.

Connect clock and reset
The axis_data_fifo and axis_dwidth_converter need clock and reset signals from the FrontPanel IP. These are individual scalar pins, not bus interfaces.
Step 9: Clock the FIFO. Hover over frontpanel_0‘s aclk output pin, then click and drag to axis_data_fifo_0‘s s_axis_aclk pin.
Step 10: Clock the width converter. Hold Ctrl (or repeat the drag) to also connect aclk to axis_dwidth_converter_0‘s aclk pin. Vivado creates a net with multiple fan-out connections.
Step 11: Reset the FIFO. Connect frontpanel_0‘s axis_aresetn output to axis_data_fifo_0‘s s_axis_aresetn pin.
Step 12: Reset the width converter. Connect axis_aresetn to axis_dwidth_converter_0‘s aresetn pin.

Make the host interface external
The FrontPanel IP’s host_interface carries the physical host-side signals. It plays no role in simulation, since the BFM drives the AXI side directly, but it must be exposed so the generated wrapper elaborates.
Step 13: Make the host interface external. In the canvas, right-click frontpanel_0‘s host_interface interface and choose Make External (or select it and press Ctrl+T). A single external host_interface port appears.

Do not run Validate Design on this loopback. The M_AXI and M_AXIL interfaces are unused here and left unconnected, so validation reports expected address warnings about them. They do not affect the generated wrapper or the simulation. Skip validation and generate the output products.
Generate output products and create HDL wrapper
Step 14: Generate output products. In the Sources panel, right-click fp_loopback.bd and select Generate Output Products. When prompted, click Generate.
Step 15: Create the HDL wrapper. After generation completes, right-click fp_loopback.bd again and select Create HDL Wrapper. Leave the default option selected (Let Vivado manage wrapper) and click OK.
Vivado generates fp_loopback_wrapper.v. Its only external ports are the FrontPanel host_interface you exposed, which the BFM does not use during simulation.
Create the testbench
The testbench instantiates the generated wrapper, which already contains the connected IP cores, and runs the test sequence.
Step 16: Create a simulation source file. In the Sources panel, click Add Sources, select Add or create simulation sources, and create a new Verilog file (for example bd_loopback_tb.v).
Step 17: Write the testbench shell. It instantiates the wrapper; the OKHOST macro is set in the next step and the test sequence goes where marked. The wrapper’s only external ports are the host-interface pins, which the BFM does not use in simulation, so it is instantiated with no connections:
`timescale 1ns/1ps
`default_nettype none
// OKHOST macro: set in the next step
module bd_loopback_tb;
// The BD wrapper contains frontpanel_0, axis_data_fifo_0, and
// axis_dwidth_converter_0 connected internally. Its only external ports are
// the host-interface pins, unused by the BFM, so it is left unconnected.
fp_loopback_wrapper u_dut ();
// Test sequence goes here
endmodule
`default_nettype wireCode language: JavaScript (javascript)Step 18: Set the OKHOST macro. Point it at the BFM instance inside the FrontPanel simulation model; the test sequence calls the BFM through this path. In the Block Design flow it is <testbench_module>.<wrapper_instance>.fp_loopback_i.frontpanel_0.inst. With testbench module bd_loopback_tb and wrapper instance u_dut:
`define OKHOST bd_loopback_tb.u_dut.fp_loopback_i.frontpanel_0.instCode language: CSS (css)Step 19: Add the test sequence. Add the variable declarations and initial blocks from The test sequence, in place of the marker comment in the shell above.
Step 20: Set the simulation top. In the Sources panel, right-click bd_loopback_tb and set it as the simulation top.
Run the simulation
Click Flow > Run Simulation > Run Behavioral Simulation. The Tcl Console shows the expected output.
RTL Flow
In this flow, the three IP cores are added from the IP Catalog and connected by hand in Verilog. The testbench instantiates each core directly.
Add and configure the IP cores
Step 1: Add the IP cores. In the Vivado IP Catalog, add the FrontPanel Subsystem, AXI4-Stream Data FIFO, and AXI4-Stream Data Width Converter IPs.
Step 2: Configure and generate each. Configure each with the settings from IP cores and settings above. When prompted after each IP, click Generate.
Create the testbench
The testbench instantiates the FrontPanel BFM and the two AMD IP cores, wires them into the loopback chain, and runs the test sequence.
Step 3: Create a simulation source file. In the Sources panel, click Add Sources, select Add or create simulation sources, and create a new Verilog file (for example rtl_loopback_tb.v).
Step 4: Open the test bench template. Open the IP Sources panel, expand the FrontPanel Subsystem IP, and open test_bench_template.v under the Test Bench folder. It contains the BFM instantiation wired to all three AXI interfaces, plus example API calls.
Step 5: Copy the template into your file. Copy the module declaration, wire declarations, and frontpanel_0 instance from test_bench_template.v into your new file. Rename the module to rtl_loopback_tb. Also delete the #(.SIM_BWMODE(3)) parameter override on the copied frontpanel_0 instance; the generated frontpanel_0 has no such top-level parameter, and leaving it elaborates with a warning.
Step 6: Set the OKHOST macro. Point it at the BFM instance inside the FrontPanel simulation model; the test sequence calls the BFM through this path. In the RTL flow it is <testbench_module>.<frontpanel_instance>.inst. With testbench module rtl_loopback_tb and FrontPanel instance u_okhost:
`define OKHOST rtl_loopback_tb.u_okhost.instCode language: CSS (css)Step 7: Add the inter-IP wires. Add wires for the signals that connect the two AMD IP instances to each other:
wire [31:0] fifo_tdata;
wire fifo_tvalid;
wire fifo_tready;Code language: CSS (css)Step 8: Instantiate the FIFO. Instantiate axis_data_fifo_0 in the DUT section, replacing the commented-out example instances there. The FIFO slave port connects to okHost’s m_axis outputs (the host write path); its master port drives the converter:
axis_data_fifo_0 u_fifo (
.s_axis_aresetn (axis_aresetn),
.s_axis_aclk (aclk),
.s_axis_tvalid (m_axis_tvalid),
.s_axis_tready (m_axis_tready),
.s_axis_tdata (m_axis_tdata),
.s_axis_tlast (m_axis_tlast),
.m_axis_tvalid (fifo_tvalid),
.m_axis_tready (fifo_tready),
.m_axis_tdata (fifo_tdata),
.m_axis_tlast ()
);Code language: CSS (css)Step 9: Instantiate the width converter. Instantiate axis_dwidth_converter_0 immediately after. Its slave port reads from the FIFO output; its master port drives okHost’s s_axis inputs (the host read path):
axis_dwidth_converter_0 u_dconv (
.aclk (aclk),
.aresetn (axis_aresetn),
.s_axis_tvalid (fifo_tvalid),
.s_axis_tready (fifo_tready),
.s_axis_tdata (fifo_tdata),
.m_axis_tvalid (s_axis_tvalid),
.m_axis_tready (s_axis_tready),
.m_axis_tdata (s_axis_tdata)
);Code language: CSS (css)Step 10: Add the test sequence. Add the variable declarations and initial blocks from The test sequence, replacing the template’s example initial block.
Step 11: Set the simulation top. In the Sources panel, right-click rtl_loopback_tb and set it as the simulation top.
Run the simulation
Click Flow > Run Simulation > Run Behavioral Simulation. The Tcl Console shows the expected output.
FrontPanel Classic (XEM8320)
This tutorial configures the FrontPanel Subsystem IP Core with a WireIn and a TriggerIn endpoint, then drives them from a testbench using the Host Simulation Library API. You set the WireIn to a known value and pulse a TriggerIn bit, then confirm both reach the endpoint nets.
This tutorial assumes familiarity with our Host Simulation HDL.
Prerequisites
Complete both before starting:
Target the XEM8320-AU25P (part xcau25p-ffvb676-2-e) when you create the project.
Configure the FrontPanel Subsystem IP Core
Step 1: Open the IP. In the Vivado IP Catalog, open the FrontPanel Subsystem IP.
Step 2: Set the board. On the Board page, set the board to XEM8320-AU25P.
Step 3: Define the endpoints. On the Endpoints page, enter a count of 1 for both the WireIn and TriggerIn endpoint types, then set the WireIn address to 0x13 and the TriggerIn address to 0x48.
Step 4: Generate. Click OK, then when prompted click Generate.

Create the testbench
The testbench instantiates the generated frontpanel_0 (which contains okHost and your endpoints), drives the endpoints with the Host Simulation Library tasks, and exposes the endpoint nets so you can observe them.
Step 5: Create a simulation source file. In the Sources panel, click Add Sources, select Add or create simulation sources, and create a new Verilog file (for example wire_trigger_tb.v).
Step 6: Copy the test bench template. Open test_bench_template.v under the Test Bench folder of the IP Sources panel. Copy its full contents into your new file and rename the module to wire_trigger_tb.
Step 7: Instantiate the IP and declare the endpoint nets. Replace the template’s USER_TOP_LEVEL_MODULE dut placeholder with the frontpanel_0 instance from the IP’s Instantiation Template, and declare the endpoint nets it exposes:
wire okClk;
wire [31:0] wi13_ep_dataout;
wire [31:0] ti48_ep_trigger;
wire ti48_ep_clk;
assign ti48_ep_clk = okClk;
frontpanel_0 dut (
.okUH (okUH),
.okHU (okHU),
.okUHU (okUHU),
.okAA (okAA),
.okClk (okClk),
.wi13_ep_dataout (wi13_ep_dataout),
.ti48_ep_trigger (ti48_ep_trigger),
.ti48_ep_clk (ti48_ep_clk)
);Step 8: Add the stimulus. Replace the template’s example initial block with the WireIn and TriggerIn stimulus. The example block drives pipe endpoints this design does not have, so it must be replaced:
initial begin
FrontPanelReset;
SetWireInValue(8'h13, 32'hdead_beef, NO_MASK);
UpdateWireIns;
ActivateTriggerIn(8'h48, 7);
endCode language: PHP (php)Step 9: Set the simulation top. In the Sources panel, right-click wire_trigger_tb and set it as the simulation top.
Run the simulation
Step 10: Run behavioral simulation. Click Flow > Run Simulation > Run Behavioral Simulation.
Step 11: Confirm the endpoint nets in the Waveform Viewer.
wi13_ep_dataout[31:0]settles to0xdeadbeefafterUpdateWireIns.ti48_ep_trigger[31:0]pulses bit 7 high for oneokClkcycle.
LFSR Simulation Example Design
For a complete example that exercises every endpoint type in a larger design, open the LFSR Simulation Example Design. See the Example Designs tutorial for instructions on opening it.