diff options
Diffstat (limited to 'fpga/usrp3/lib/packet_proc_200')
4 files changed, 471 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/packet_proc_200/Makefile.srcs b/fpga/usrp3/lib/packet_proc_200/Makefile.srcs new file mode 100644 index 000000000..3f0834df9 --- /dev/null +++ b/fpga/usrp3/lib/packet_proc_200/Makefile.srcs @@ -0,0 +1,14 @@ +# +# Copyright 2013 Ettus Research LLC +# Copyright 2016 Ettus Research, a National Instruments Company +# +# SPDX-License-Identifier: LGPL-3.0-or-later +# + +################################################## +# Packet Processing Sources +################################################## +PACKET_PROC_200_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/packet_proc_200/, \ +cvita_dest_lookup_legacy.v \ +source_flow_control_legacy.v \ +)) diff --git a/fpga/usrp3/lib/packet_proc_200/cvita_dest_lookup_legacy.v b/fpga/usrp3/lib/packet_proc_200/cvita_dest_lookup_legacy.v new file mode 100644 index 000000000..17954baaa --- /dev/null +++ b/fpga/usrp3/lib/packet_proc_200/cvita_dest_lookup_legacy.v @@ -0,0 +1,53 @@ +// +// Copyright 2014 Ettus Research LLC +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// Map the endpoint dest part of the SID in the CVITA header to a destination +// This destination (o_tdest) signal will be valid with o_tdata +// This only works with VALID CVITA frames + +module cvita_dest_lookup_legacy +#( + parameter DEST_WIDTH = 4 +) +( + input clk, input rst, + input set_stb, input [7:0] set_addr, input [DEST_WIDTH-1:0] set_data, + input [63:0] i_tdata, input i_tlast, input i_tvalid, output i_tready, + output [63:0] o_tdata, output o_tlast, output o_tvalid, input o_tready, + output [DEST_WIDTH-1:0] o_tdest +); + + reg [7:0] endpoint; + ram_2port #(.DWIDTH(DEST_WIDTH), .AWIDTH(8)) dest_lut + ( + .clka(clk), .ena(1'b1), .wea(set_stb), .addra(set_addr), .dia(set_data), .doa(), + .clkb(clk), .enb(1'b1), .web(1'b0), .addrb(endpoint), .dib(8'hff), .dob(o_tdest) + ); + + reg forward; + reg [1:0] count; + always @(posedge clk) begin + if (rst) begin + forward <= 1'b0; + count <= 2'b0; + end + else if (forward == 1'b0 && i_tvalid) begin + if (count == 2'b11) forward <= 1'b1; + endpoint <= i_tdata[23:16]; + count <= count + 1'b1; + end + else if (forward == 1'b1 && i_tvalid && i_tready && i_tlast) begin + forward <= 1'b0; + count <= 2'b0; + end + end + + assign o_tdata = i_tdata; + assign o_tlast = i_tlast; + assign o_tvalid = i_tvalid && forward; + assign i_tready = o_tready && forward; + +endmodule // cvita_dest_lookup_legacy diff --git a/fpga/usrp3/lib/packet_proc_200/source_flow_control_legacy.v b/fpga/usrp3/lib/packet_proc_200/source_flow_control_legacy.v new file mode 100644 index 000000000..46906f97d --- /dev/null +++ b/fpga/usrp3/lib/packet_proc_200/source_flow_control_legacy.v @@ -0,0 +1,150 @@ +// +// Copyright 2014-2016 Ettus Research +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +// This block passes the in_* AXI port to the out_* AXI port only when it has +// enough flow control credits. Data is held when there are not enough credits. +// Credits are replenished with extension context packets which update the +// last_consumed packet register. Max credits are controlled by settings regs. +// The 2nd line of the packet contains the sequence number in the low 12 bits. +// These packets should not have a time value, but if they do it will be ignored. + +module source_flow_control_legacy #( + parameter BASE=0 +) ( + input clk, input reset, input clear, + input set_stb, input [7:0] set_addr, input [31:0] set_data, + input [63:0] fc_tdata, input fc_tlast, input fc_tvalid, output fc_tready, + input [63:0] in_tdata, input in_tlast, input in_tvalid, output in_tready, + output [63:0] out_tdata, output out_tlast, output out_tvalid, input out_tready, + output busy +); + reg [31:0] last_seqnum_consumed; + wire [31:0] window_size; + wire [31:0] go_until_seqnum = last_seqnum_consumed + window_size + 1; + reg [31:0] current_seqnum; + wire window_reset; + wire window_enable; + + //Sets the size of the flow control window + setting_reg #(.my_addr(BASE)) sr_window_size + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data), + .out(window_size),.changed()); + + //Setting to enable/disable the flow control window + //When this register is hit, the window will reset. + //As a part of the reset process, all FC blocked data upstream will be + //dropped by this module and it will reset to the SFC_HEAD head state. + //The reset sequence can take more than one cycle during which this + //module will hold off all flow control data. + setting_reg #(.my_addr(BASE+1), .width(1)) sr_window_enable + (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data), + .out(window_enable),.changed(window_reset)); + + reg go; + reg window_reseting; + reg [11:0] window_reset_cnt; //Counter to make reset tolerant to bubble cycles + reg [1:0] sfc_state; + + always @(posedge clk) begin + if (reset | clear) begin + window_reseting <= 1'b0; + end else if (window_reset) begin //Reset start + window_reseting <= 1'b1; + window_reset_cnt <= 12'd0; + end else if (window_reseting & ~in_tvalid) begin //Reset end + window_reset_cnt <= window_reset_cnt + 12'd1; + window_reseting <= (window_reset_cnt == 12'hFFF); + end + end + + localparam SFC_HEAD = 2'd0; + localparam SFC_TIME = 2'd1; + localparam SFC_BODY = 2'd2; + localparam SFC_DUMP = 2'd3; + + always @(posedge clk) + if (reset | clear | window_reset) begin + last_seqnum_consumed <= 32'hFFFFFFFF; + sfc_state <= SFC_HEAD; + end else if (fc_tvalid & fc_tready) + case(sfc_state) + SFC_HEAD : + if(fc_tlast) + sfc_state <= SFC_HEAD; // Error. CHDR packet with only a header is an error. + else if(~fc_tdata[63]) // Is this NOT an extension context packet? + sfc_state <= SFC_DUMP; // Error. Only extension context packets should come in on this interface. + else if(fc_tdata[61]) // Does this packet have time? + sfc_state <= SFC_TIME; + else + sfc_state <= SFC_BODY; + + SFC_TIME : + if(fc_tlast) + sfc_state <= SFC_HEAD; // Error, CHDR packet with only header and time is an error. + else + sfc_state <= SFC_BODY; + + SFC_BODY : + begin + last_seqnum_consumed <= fc_tdata[31:0]; // Sequence number is in lower 32bits. + if(fc_tlast) + sfc_state <= SFC_HEAD; + else + sfc_state <= SFC_DUMP; // Error. Not expecting any more data in a CHDR packet. + end + + SFC_DUMP : // shouldn't ever need to be here, this is an error condition + if(fc_tlast) + sfc_state <= SFC_HEAD; + + endcase // case (sfc_state) + + assign busy = window_reseting; + assign fc_tready = ~window_reseting; // Consume FC if not in reset + assign out_tdata = in_tdata; // CHDR data flows through combinatorially. + assign out_tlast = in_tlast; + assign in_tready = (go ? out_tready : 1'b0) | window_reseting; + assign out_tvalid = (go & ~window_reseting) ? in_tvalid : 1'b0; + + // + // Each time we receive the end of an IF data packet increment the current_seqnum. + // We bravely assume that no packets go missing...or at least that they will be detected elsewhere + // and then handled appropriately. + // The SEQNUM needs to be initialized every time we start a new stream. In new_rx_framer this is done + // as a side effect of writing a new SID value to the setting reg. + // + // By incrementing current_seqnum on the last signal we get the nice effect that packet flow is + // always suspended between packets rather than within a packet. + // + always @(posedge clk) + if(reset | clear | window_reseting) + current_seqnum <= 32'd0; + else if (in_tvalid && in_tready && in_tlast) + current_seqnum <= current_seqnum + 32'd1; + + always @(posedge clk) + if(reset | clear) begin + go <= 1'b0; + end else begin + if(~window_enable) + go <= 1'b1; + else + case(go) + 1'b0: + // This test assumes the host is well behaved in sending good numbers for packets consumed + // and that current_seqnum increments always by 1 only. + // This way wraps are dealt with without a large logic penalty. + if (in_tvalid & (go_until_seqnum - current_seqnum != 0)) + go <= 1'b1; + //if(in_tvalid & (go_until_seqnum > current_seqnum)) // FIXME will need to handle wrap of 32-bit seqnum + + 1'b1: + if(in_tvalid & in_tready & in_tlast) + go <= 1'b0; + endcase // case (go) + end + +endmodule // source_flow_control_legacy diff --git a/fpga/usrp3/lib/packet_proc_200/source_flow_control_legacy_tb.v b/fpga/usrp3/lib/packet_proc_200/source_flow_control_legacy_tb.v new file mode 100644 index 000000000..e8f7cccdf --- /dev/null +++ b/fpga/usrp3/lib/packet_proc_200/source_flow_control_legacy_tb.v @@ -0,0 +1,254 @@ +// +// Copyright 2016 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// +`timescale 1ns/1ps + +module source_flow_control_legacy_tb(); + + reg clk = 0; + reg reset = 1; + + always #10 clk = ~clk; + + initial $dumpfile("source_flow_control_legacy_tb.vcd"); + initial $dumpvars(0,source_flow_control_legacy_tb); + + initial + begin + #1000 reset = 0; + #20000; + $finish; + end + + reg [63:0] tdata; + wire [63:0] tdata_int; + reg tlast; + wire tlast_int; + reg tvalid = 1'b0; + wire tvalid_int; + wire tready, tready_int; + + reg [63:0] fc_tdata; + reg fc_tlast, fc_tvalid; + wire fc_tready; + + wire [63:0] out_tdata; + wire out_tlast, out_tready, out_tvalid; + + wire [15:0] occ_in, occ_out; + reg set_stb = 0; + reg [7:0] set_addr; + reg [31:0] set_data; + + + task send_fc_packet; + input [31:0] seqnum; + input [31:0] sid; + input always_go; + + begin + @(posedge clk); + fc_tlast <= 1'b0; + fc_tdata <= { 1'b1, 1'b0, 1'b0, 1'b0, 12'hABC, 16'd4, sid }; + fc_tvalid <= 1; + @(posedge clk); + fc_tlast <= 1'b1; + //fc_tdata <= { 52'h0,seqnum }; + fc_tdata <= { 31'h0,always_go, seqnum }; + @(posedge clk); + fc_tvalid <= 0; + @(posedge clk); + end + endtask // send_packet + + task send_packet; + input ec; + input timed; + input [11:0] seqnum; + input [31:0] sid; + input [63:0] vtime; + input [15:0] addr; + input [31:0] data; + + begin + // Send a packet + @(posedge clk); + tlast <= 1'b0; + tdata <= { ec, 1'b0, timed, 1'b0, seqnum, timed ? 16'd6 : 16'd4, sid }; + tvalid <= 1; + @(posedge clk); + if(timed) + begin + tdata <= vtime; + @(posedge clk); + end + tlast <= 1'b1; + tdata <= { 16'h0, addr, data }; + @(posedge clk); + tlast <= 1'b0; + tvalid <= 0; + @(posedge clk); + end + endtask // send_packet + + initial + begin + tvalid <= 1'b0; + while(reset) + @(posedge clk); + @(posedge clk); + // Set flow control window to be 2 + set_stb <= 1; + set_addr <= 0; + set_data <= 2; + @(posedge clk); + set_stb <= 0; + // ExtContext. Time. Seq=0, SID=DEAD_6789, Time=10 + send_packet(1'b1,1'b1,12'h0,32'hDEAD_6789,64'h10,16'hB,32'hF00D_1234); + send_packet(1'b1,1'b1,12'h1,32'hDEAD_6789,64'h20,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'h2,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'h3,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'h4,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'h5,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'h6,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'h7,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'h8,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321); + #500; + // Consumed 2 packets + send_fc_packet(32'd1,32'h3,1'b0); + #300; + // Consumed 1 packet + send_fc_packet(32'd2,32'h3,1'b0); + #500; + // Consumed 2 packets + send_fc_packet(32'd4,32'h3,1'b0); + #400; + // Send same SEQ ID again to test it causes no changes. + send_fc_packet(32'd4,32'h3,1'b0); + #300; + // Consumed 1 packet + send_fc_packet(32'd5,32'h3,1'b0); + #500; + // Consumed 2 packets + send_fc_packet(32'd7,32'h3,1'b0); + #500; + send_packet(1'b1,1'b1,12'h9,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'hA,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321); + #300; + // Consumed 1 packet + send_fc_packet(32'd8,32'h3,1'b0); + // + // Now force internal sequence count to close to wrap value to test corner case + // + #100; + source_flow_control_legacy.current_seqnum <= 32'hFFFF_FFFC; + #100; + send_fc_packet(32'hFFFF_FFFA,32'h3,1'b0); + #100; + send_packet(1'b1,1'b1,12'hFFC,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321); + #200; + send_packet(1'b1,1'b1,12'hFFD,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'hFFE,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'hFFF,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'h000,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'h001,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'h002,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321); + #200; + // Consumed 2 packets + send_fc_packet(32'hFFFF_FFFC,32'h3,1'b0); + #200; + // Consumed 2 packets + send_fc_packet(32'hFFFF_FFFE,32'h3,1'b0); + send_packet(1'b1,1'b1,12'h003,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'h004,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321); + #200; + // Consumed 2 packets + send_fc_packet(32'h0,32'h3,1'b0); + #200; + // Consumed 2 packets + send_fc_packet(32'h2,32'h3,1'b0); + #500; + // + // Again force internal sequence count to close to wrap value to test new corner case + // + #100; + source_flow_control_legacy.current_seqnum <= 32'hFFFF_FFFC; + #100; + send_fc_packet(32'hFFFF_FFFA,32'h3,1'b0); + #100; + send_packet(1'b1,1'b1,12'hFFC,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321); + #200; + send_packet(1'b1,1'b1,12'hFFD,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'hFFE,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'hFFF,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'h000,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'h001,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'h002,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321); + #200; + // Consumed 1 packets + send_fc_packet(32'hFFFF_FFFB,32'h3,1'b0); + #200; + // Consumed 1 packets + send_fc_packet(32'hFFFF_FFFC,32'h3,1'b0); + send_packet(1'b1,1'b1,12'h003,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321); + send_packet(1'b1,1'b1,12'h004,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321); + #200; + // Consumed 1 packets + send_fc_packet(32'hFFFF_FFFD,32'h3,1'b0); + #200; + // Consumed 1 packets + send_fc_packet(32'hFFFF_FFFE,32'h3,1'b0); + #200; + // Consumed 1 packets + send_fc_packet(32'hFFFF_FFFF,32'h3,1'b0); + #200; + // Consumed 1 packets + send_fc_packet(32'h0,32'h3,1'b0); + #200; + // Consumed 1 packets + send_fc_packet(32'h1,32'h3,1'b0); + #200; + // Consumed 1 packets + send_fc_packet(32'h2,32'h3,1'b0); + #500; + + + + + end + + axi_fifo #(.WIDTH(65), .SIZE(10)) fifo_in + (.clk(clk), .reset(reset), .clear(1'b0), + .i_tdata({tlast,tdata}), .i_tvalid(tvalid), .i_tready(tready), + .o_tdata({tlast_int,tdata_int}), .o_tvalid(tvalid_int), .o_tready(tready_int), + .occupied(occ_in)); + + source_flow_control_legacy source_flow_control_legacy + (.clk(clk), .reset(reset), .clear(1'b0), + .set_stb(set_stb), .set_addr(set_addr), .set_data(set_data), + .fc_tdata(fc_tdata), .fc_tlast(fc_tlast), .fc_tvalid(fc_tvalid), .fc_tready(fc_tready), + .in_tdata(tdata_int), .in_tlast(tlast_int), .in_tvalid(tvalid_int), .in_tready(tready_int), + .out_tdata(out_tdata), .out_tlast(out_tlast), .out_tvalid(out_tvalid), .out_tready(out_tready) + ); + + wire [63:0] dump_tdata; + wire dump_tlast, dump_tvalid, dump_tready; + + axi_fifo #(.WIDTH(65), .SIZE(10)) fifo_out + (.clk(clk), .reset(reset), .clear(1'b0), + .i_tdata({out_tlast,out_tdata}), .i_tvalid(out_tvalid), .i_tready(out_tready), + .o_tdata({dump_tlast,dump_tdata}), .o_tvalid(dump_tvalid), .o_tready(dump_tready), + .occupied(occ_out)); + + assign dump_tready = 0; + + always @(posedge clk) + if(out_tvalid & out_tready) + begin + $display("%x",out_tdata); + if(out_tlast) + $display("TLAST"); + end +endmodule // source_flow_control_legacy_tb |