// // Copyright 2018 Ettus Research, A National Instruments Company // // SPDX-License-Identifier: LGPL-3.0-or-later // // Module: chdr_traffic_sink_sim // Description: // A sink for CHDR traffic. Simulation only. // Accepts packets and computes the following metrics: // - Data integrity errors // - Packet latency // - Throughput counts // All metrics can optionally be written to a file to // generate load-latency graphs. `timescale 1ns/1ps `include "sim_cvita_lib.svh" module chdr_traffic_sink_sim #( parameter WIDTH = 64, parameter MTU = 5, parameter [15:0] NODE_ID = 'd0, parameter [15:0] NUM_NODES = 'd16, parameter FILE_PATH = ".", parameter FLUSH_N = 4 ) ( // Clocks and resets input clk, input rst, // Settings input [63:0] current_time, input start_stb, input [7:0] injection_rate, input [15:0] lines_per_pkt, input [7:0] traffic_patt, // CHDR master interface input [WIDTH-1:0] s_axis_tdata, input s_axis_tlast, input s_axis_tvalid, output s_axis_tready, // Metrics output session_active, output [31:0] xfer_count, output [31:0] pkt_count, output [31:0] data_err_count, output [31:0] route_err_count ); // Constants localparam integer ERR_BIT_PKT_SIZE_MISMATCH = 1; localparam integer ERR_BIT_PKT_DATA_MISMATCH = 2; localparam integer ERR_BIT_PKT_DEST_MISMATCH = 4; localparam integer ERR_BIT_PKT_SEQUENCE_ERR = 8; cvita_slave #(.DWIDTH(WIDTH)) s_chdr (.clk(clk)); cvita_pkt_t pkt; assign s_chdr.axis.tdata = s_axis_tdata; assign s_chdr.axis.tlast = s_axis_tlast; assign s_chdr.axis.tvalid = s_axis_tvalid; assign s_axis_tready = s_chdr.axis.tready; logic running = 0; integer num_data_errs = 0; integer num_route_errs = 0; logic [31:0] num_pkts_xferd = 0; logic [31:0] num_samps_xferd = 0; assign data_err_count = num_data_errs; assign route_err_count = num_route_errs; assign xfer_count = num_samps_xferd; assign pkt_count = num_pkts_xferd; assign session_active = running; integer session = 0; string filename; integer handle = 0; integer err = 0; integer bus_idle_cnt = 0; logic [WIDTH-1:0] i; // Egress buff in source is MTU + 4 localparam integer IDLE_TIMEOUT = (1 << (MTU + 4 + FLUSH_N)); initial begin: consume_blk // Consume infinitely s_chdr.reset(); while (1) begin // A session begins on the posedge of start_stb while (start_stb !== 1) @(posedge clk); session = session + 1; $sformat(filename, "%s/pkts_node%05d_inj%03d_lpp%05d_traffic%c_sess%04d.csv", FILE_PATH, NODE_ID, injection_rate, lines_per_pkt, traffic_patt, session); if (FILE_PATH != "") begin handle = $fopen(filename, "w"); if (handle == 0) begin $error("Could not open file: %s", filename); $finish(); end end if (handle != 0) $fdisplay(handle, "Src,Dst,Seqno,Error,Latency"); s_chdr.reset(); num_data_errs = 0; num_route_errs = 0; num_pkts_xferd = 0; num_samps_xferd = 0; bus_idle_cnt = 0; running = 1; while (1) begin // Pull packet from bus err = 0; if (~s_chdr.axis.tvalid[0]) begin @(posedge clk); bus_idle_cnt = bus_idle_cnt + 1; if (bus_idle_cnt <= IDLE_TIMEOUT) continue; else break; end s_chdr.pull_pkt(pkt, 0); bus_idle_cnt = 0; num_pkts_xferd = num_pkts_xferd + 1; num_samps_xferd = num_samps_xferd + lines_per_pkt; // Validate packet if (pkt.hdr.dst_sid != NODE_ID) begin err = err + ERR_BIT_PKT_DEST_MISMATCH; num_route_errs = num_route_errs + 1; end if (pkt.payload.size() != lines_per_pkt-2) begin err = err + ERR_BIT_PKT_SIZE_MISMATCH; num_data_errs = num_data_errs + 1; end else begin for (i = 'd0; i < (lines_per_pkt-2); i=i+1) begin if (pkt.payload[i] != i) begin err = err + ERR_BIT_PKT_DATA_MISMATCH; num_data_errs = num_data_errs + 1; break; end end end if (handle != 0) $fdisplay(handle, "%00d,%00d,%00d,%00d,%00d", pkt.hdr.src_sid, pkt.hdr.dst_sid, pkt.hdr.seqnum, err, (current_time - pkt.hdr.timestamp)); end running = 0; if (handle != 0) $fclose(handle); end end endmodule