This fixes the rfnoc_null_src_sink, chdr_crossbar_nxn, and chdr_stream_endpoint blocks so that wider CHDR widths are properly supported. It also updates PkgChdrBfm to able to properly test these blocks. The testbenches have been updated to test both 64 and 512-bit widths. Original-commit: 3af8dcaacfa4bf36dcae3bdbf0b353385b7063c6
206 lines
7.5 KiB
Systemverilog
206 lines
7.5 KiB
Systemverilog
//
|
|
// Copyright 2018 Ettus Research, A National Instruments Company
|
|
//
|
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
//
|
|
// Module: chdr_traffic_source_sim
|
|
// Description:
|
|
// A traffic generator for CHDR traffic. Simulation only.
|
|
// Supports multiple traffic pattern and injection rates.
|
|
//
|
|
|
|
`timescale 1ns/1ps
|
|
|
|
`include "sim_cvita_lib.svh"
|
|
|
|
module chdr_traffic_source_sim #(
|
|
parameter WIDTH = 64, // Width of the AXI-Stream data bus
|
|
parameter MTU = 5, // log2 of the max number of lines in a packet
|
|
parameter [15:0] NODE_ID = 'd0, // Node ID for this generator
|
|
parameter [15:0] NUM_NODES = 'd16 // Total number of generators in the application
|
|
) (
|
|
// Clocks and resets
|
|
input clk, // AXI-Stream clock
|
|
input rst, // AXI-Stream reset
|
|
// Settings
|
|
input [63:0] current_time, // The current value of the global timebase (synch to clk)
|
|
input start_stb, // A strobe that indicates the start of a generation session
|
|
input [7:0] injection_rate, // The inject rate (in percent) to simulate
|
|
input [15:0] lines_per_pkt, // Number of lines per packet to generate
|
|
input [7:0] traffic_patt, // The traffic pattern (see localparams below for values)
|
|
input [31:0] num_pkts_to_send, // Number of packets to send
|
|
// CHDR master interface
|
|
output [WIDTH-1:0] m_axis_tdata, // AXI-Stream master tdata
|
|
output m_axis_tlast, // AXI-Stream master tlast
|
|
output m_axis_tvalid, // AXI-Stream master tvalid
|
|
input m_axis_tready, // AXI-Stream master tready
|
|
// Metrics
|
|
output session_active, // Signal indicating if generation session is active
|
|
output [63:0] session_duration, // Session duration (only valid after session ends)
|
|
output [31:0] xfer_count, // Number of lines transferred (only valid after session ends)
|
|
output [31:0] pkt_count // Number of packets transferred (only valid after session ends)
|
|
);
|
|
// **** Supported Traffic Patters ****
|
|
localparam [7:0] TRAFFIC_PATT_LOOPBACK = 8'd76; //L
|
|
localparam [7:0] TRAFFIC_PATT_NEIGHBOR = 8'd78; //N
|
|
localparam [7:0] TRAFFIC_PATT_BIT_COMPLEMENT = 8'd67; //C
|
|
localparam [7:0] TRAFFIC_PATT_SEQUENTIAL = 8'd83; //S
|
|
localparam [7:0] TRAFFIC_PATT_UNIFORM = 8'd85; //U
|
|
localparam [7:0] TRAFFIC_PATT_UNIFORM_OTHERS = 8'd79; //O
|
|
localparam [7:0] TRAFFIC_PATT_RANDOM_PERM = 8'd82; //R
|
|
|
|
cvita_master #(.DWIDTH(WIDTH)) m_chdr (.clk(clk));
|
|
axis_t #(.DWIDTH(WIDTH)) post_fifo (.clk(clk));
|
|
axis_t #(.DWIDTH(WIDTH)) pre_gate (.clk(clk));
|
|
cvita_hdr_t header;
|
|
reg throttle = 1'b1;
|
|
|
|
logic running = 0;
|
|
logic [31:0] curr_pkt_num = 'd0;
|
|
logic [31:0] num_samps_xferd = 'd0;
|
|
logic [63:0] start_time = 0;
|
|
logic [63:0] stop_time = 0;
|
|
logic [15:0] last_gen_sid = (NODE_ID - 16'd1);
|
|
|
|
assign xfer_count = num_samps_xferd;
|
|
assign pkt_count = curr_pkt_num;
|
|
assign session_duration = (stop_time - start_time);
|
|
assign session_active = running;
|
|
|
|
// Utility function to assign SIDs based on traffic pattern
|
|
function [15:0] gen_dst_sid;
|
|
input [7:0] traffic_patt;
|
|
input [15:0] last_sid;
|
|
|
|
logic [31:0] rnum;
|
|
|
|
if (traffic_patt == TRAFFIC_PATT_UNIFORM) begin
|
|
gen_dst_sid = $urandom_range('d0, NUM_NODES-'d1);
|
|
end else if (traffic_patt == TRAFFIC_PATT_UNIFORM_OTHERS) begin
|
|
rnum = $urandom_range('d0, NUM_NODES-'d2);
|
|
if (rnum < NODE_ID)
|
|
gen_dst_sid = rnum[15:0];
|
|
else
|
|
gen_dst_sid = rnum[15:0] + 16'd1;
|
|
end else if (traffic_patt == TRAFFIC_PATT_SEQUENTIAL) begin
|
|
gen_dst_sid = (last_sid + 16'd1) % NUM_NODES;
|
|
end else if (traffic_patt == TRAFFIC_PATT_NEIGHBOR) begin
|
|
gen_dst_sid = (NODE_ID + 16'd1) % NUM_NODES;
|
|
end else if (traffic_patt == TRAFFIC_PATT_LOOPBACK) begin
|
|
gen_dst_sid = NODE_ID;
|
|
end else if (traffic_patt == TRAFFIC_PATT_BIT_COMPLEMENT) begin
|
|
gen_dst_sid = (NUM_NODES - NODE_ID - 1) % NUM_NODES;
|
|
end else if (traffic_patt == TRAFFIC_PATT_RANDOM_PERM) begin
|
|
//TODO: Implement me
|
|
gen_dst_sid = 0;
|
|
end else begin
|
|
gen_dst_sid = 'd0;
|
|
end
|
|
endfunction
|
|
|
|
// Generation loop. Push to m_chdr infinitely fast
|
|
initial begin: gen_blk
|
|
// Generate infinitely
|
|
std::process p;
|
|
p = process::self();
|
|
p.srandom(NODE_ID + NUM_NODES);
|
|
m_chdr.reset();
|
|
while (1) begin
|
|
// A generation session begins on the posedge of start_stb
|
|
while (start_stb !== 1) @(posedge clk);
|
|
curr_pkt_num = 'd0;
|
|
m_chdr.reset();
|
|
num_samps_xferd = 'd0;
|
|
start_time = current_time;
|
|
running = 1;
|
|
while (curr_pkt_num < num_pkts_to_send) begin
|
|
header = '{
|
|
pkt_type:DATA, has_time:1, eob:0,
|
|
seqnum:curr_pkt_num[11:0], length:(lines_per_pkt*8),
|
|
src_sid:NODE_ID, dst_sid:gen_dst_sid(traffic_patt, last_gen_sid),
|
|
timestamp:0 //TS attached later
|
|
};
|
|
last_gen_sid = header.dst_sid;
|
|
curr_pkt_num = curr_pkt_num + 'd1;
|
|
m_chdr.push_ramp_pkt(lines_per_pkt-2, 'h0, 'h1, header);
|
|
num_samps_xferd = num_samps_xferd + lines_per_pkt;
|
|
end
|
|
running = 0;
|
|
stop_time = current_time;
|
|
end
|
|
end
|
|
|
|
// Capture packets in a really short FIFO (for backpressure)
|
|
axi_fifo #(
|
|
.WIDTH(WIDTH+1), .SIZE(MTU + 1)
|
|
) fifo_i (
|
|
.clk (clk),
|
|
.reset (rst),
|
|
.clear (1'b0),
|
|
.i_tdata ({m_chdr.axis.tlast, m_chdr.axis.tdata}),
|
|
.i_tvalid (m_chdr.axis.tvalid),
|
|
.i_tready (m_chdr.axis.tready),
|
|
.o_tdata ({post_fifo.tlast, post_fifo.tdata}),
|
|
.o_tvalid (post_fifo.tvalid),
|
|
.o_tready (post_fifo.tready),
|
|
.space (),
|
|
.occupied ()
|
|
);
|
|
|
|
// Attach timestamp after the packet leaves the FIFO after
|
|
// throttling.
|
|
|
|
localparam [1:0] ST_HDR = 2'd0;
|
|
localparam [1:0] ST_TS = 2'd1;
|
|
localparam [1:0] ST_BODY = 2'd2;
|
|
|
|
reg [1:0] pkt_state = ST_HDR;
|
|
always_ff @(posedge clk) begin
|
|
if (rst) begin
|
|
pkt_state <= ST_HDR;
|
|
end else if (pre_gate.tvalid & pre_gate.tready) begin
|
|
case (pkt_state)
|
|
ST_HDR:
|
|
if (~pre_gate.tlast)
|
|
pkt_state <= pre_gate.tdata[61] ? ST_TS : ST_BODY;
|
|
ST_TS:
|
|
pkt_state <= pre_gate.tlast ? ST_HDR : ST_BODY;
|
|
ST_BODY:
|
|
pkt_state <= pre_gate.tlast ? ST_HDR : ST_BODY;
|
|
default:
|
|
pkt_state <= ST_HDR;
|
|
endcase
|
|
end
|
|
end
|
|
|
|
// Enforce injection rate by pulling from FIFO with a certain time probability
|
|
always_ff @(posedge clk) begin
|
|
throttle <= ($urandom_range(32'd99, 32'd0) > {24'h0, injection_rate});
|
|
end
|
|
|
|
// Insert timestamp + throttle logic
|
|
assign pre_gate.tdata = (pkt_state == ST_TS) ? current_time : post_fifo.tdata;
|
|
assign pre_gate.tlast = post_fifo.tlast;
|
|
assign pre_gate.tvalid = post_fifo.tvalid & ~throttle;
|
|
assign post_fifo.tready = pre_gate.tready & ~throttle;
|
|
|
|
// Gate the packet to smooth out throttle-related noise.
|
|
// This also serves as a buffer for the packet in case things are backed up
|
|
axi_packet_gate #(
|
|
.WIDTH(WIDTH), .SIZE(MTU + 4), .USE_AS_BUFF(1)
|
|
) pkt_gate_i (
|
|
.clk (clk),
|
|
.reset (rst),
|
|
.clear (1'b0),
|
|
.i_tdata (pre_gate.tdata),
|
|
.i_tlast (pre_gate.tlast),
|
|
.i_terror (1'b0),
|
|
.i_tvalid (pre_gate.tvalid),
|
|
.i_tready (pre_gate.tready),
|
|
.o_tdata (m_axis_tdata),
|
|
.o_tlast (m_axis_tlast),
|
|
.o_tvalid (m_axis_tvalid),
|
|
.o_tready (m_axis_tready)
|
|
);
|
|
|
|
endmodule |