Files
b210-k7-fpga/lib/rfnoc/crossbar/crossbar_tb/chdr_traffic_source_sim.sv
T
Andrew Moch 55881469ac fpga: rfnoc: Add support for 512-bit CHDR widths
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
2020-06-18 09:09:34 -05:00

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