Hierarchy
The testbench is the AXI-Stream master. Packet checks live in one wrapper,
pkt_snoop (u_snoop). That wrapper does not drive
tready. With NIC=1, u_nic_rx is the
slave: it produces s_tready on the same wires the snoops sample.
Without the flag, the bench drives tready from BP only.
u_snoop is not a packet FIFO: children snoop the same AXIS.
After instantiation
What exists after make NIC=1 instantiates.
Instance tree (GTKWave SST)
Same AXIS after the port map (not a chain)
u_nic_rx and u_snoop are siblings.
Beats do not go NIC then parser. Swap only u_nic_rx if you attach another RX.
AXIS pin template
Your NIC is a slave. The testbench is the master. Observers tap the bus;
they must not drive tready.
ready_mask is the bench BP bit. AND it
inside the slave so a stalled BP cycle is not
counted as a beat. Tie ready_mask to 1 only if your core is
the sole ready source.
tstart; this bench uses it as SOP.
Sample only when s_tvalid && s_tready.
What nic_rx does
The in-tree template is ingress credits, not a 400GbE MAC.
Occupancy rises on an accepted beat and falls one beat per cycle
(host drain). s_tready drops when almost full, when
pause_en toggles (NIC_PAUSE=1), or when
ready_mask is 0. On s_tlast it pulses
rx_pkt_valid with a byte count from tkeep.
The testbench compares that length to pkt_size_filter.
occ_max=1 on a line-rate drain is expected: the FIFO does not back up.
NIC_PAUSE=1
NIC_PAUSE=1 is a slave-side stall inside
nic_rx. It only exists when you also
make NIC=1.
Each clock, pause_en toggles bubble.
s_tready is 0 whenever bubble is 1, so the NIC
accepts a beat only every other cycle (50% ready), even if the FIFO is not full.
s_tready = rst_n && ready_mask && !bubble && !almost_full
| Knob | Who stalls | Typical use |
|---|---|---|
| BP=1 / BP=2 | Bench ready_mask ANDed into the slave | Extra backpressure from the testbench |
| NIC_PAUSE=1 | nic_rx itself (bubble) | Prove the DUT is the one driving tready |
Default is NIC_PAUSE=0: bubble stays 0, no extra toggle.
make NIC=1 NIC_PAUSE=1
Packet counts and [NIC] … mis=0 should still match
NIC_PAUSE=0 if the slave only advances on
s_tvalid && s_tready. Your own RX can tie
pause_en off.
Build and gate
make # [NIC] off — nic_rx.sv not compiled make NIC=1 # u_nic_rx on the bus make NIC=1 BP=2 make NIC=1 NIC_PAUSE=1
Changing NIC rebuilds. End of a NIC=1 run:
[NIC] rx=100 drop=0 byte_mis=0 csum_side=0 occ_max=1 mis=0
rx must equal streamed packets. byte_mis=0 means
the same length as pkt_size_filter on each tlast.
Per-packet lines stay [DUT] Classified; there is no per-packet
[NIC] print.
Swap your RX
- Keep
make NIC=1(or add your file in the Makefileifeq ($(NIC),1)block). - Replace
u_nic_rxinsideifdef EN_NICinhdl/tb_pcap_dpi.sv. - Ports:
s_tdata,s_tkeep,s_tvalid,s_tready(out),s_tstart,s_tlast,s_tuser,s_tuser_err,ready_mask. - Do not open the pcap in HDL. Use
PCAP=. - Leave
u_snoopunless you are replacing the scoreboards too.