aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/rfnoc/axi_drop_partial_packet.v
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/lib/rfnoc/axi_drop_partial_packet.v')
-rw-r--r--fpga/usrp3/lib/rfnoc/axi_drop_partial_packet.v140
1 files changed, 140 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/rfnoc/axi_drop_partial_packet.v b/fpga/usrp3/lib/rfnoc/axi_drop_partial_packet.v
new file mode 100644
index 000000000..a4dbae654
--- /dev/null
+++ b/fpga/usrp3/lib/rfnoc/axi_drop_partial_packet.v
@@ -0,0 +1,140 @@
+//
+// Copyright 2016 Ettus Research
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+// Drop packets that are larger or smaller than the allowed packet size.
+//
+
+module axi_drop_partial_packet #(
+ parameter WIDTH = 32,
+ parameter MAX_PKT_SIZE = 1024,
+ parameter HOLD_LAST_WORD = 0, // Hold off sending last word until next full packet arrives
+ parameter SR_PKT_SIZE_ADDR = 1
+)(
+ input clk, input reset, input clear,
+ input flush, // If using HOLD_LAST_WORD, will forcibly release all words in FIFO
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+ input [WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
+ output [WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready
+);
+
+ generate
+ // Packet size of 1 means it is impossible to form a partial packet, so this module does nothing...
+ if (MAX_PKT_SIZE == 1) begin
+ assign o_tdata = i_tdata;
+ assign o_tlast = i_tlast;
+ assign o_tvalid = i_tvalid;
+ assign i_tready = o_tready;
+ // All other packet sizes
+ end else begin
+ // Settings register
+ wire [$clog2(MAX_PKT_SIZE+1)-1:0] sr_pkt_size;
+ setting_reg #(.my_addr(SR_PKT_SIZE_ADDR), .width($clog2(MAX_PKT_SIZE+1)), .at_reset(1)) set_pkt_size (
+ .clk(clk), .rst(reset), .strobe(set_stb), .addr(set_addr), .in(set_data),
+ .out(sr_pkt_size), .changed());
+
+ // Do not change n unless block is not active
+ reg active;
+ reg [$clog2(MAX_PKT_SIZE+1)-1:0] pkt_size = 1;
+ always @(posedge clk) begin
+ if (reset | clear) begin
+ active <= 1'b0;
+ end else begin
+ if (i_tready & i_tvalid) begin
+ active <= 1'b1;
+ end
+ end
+ if (clear | ~active) begin
+ pkt_size <= (sr_pkt_size == 0) ? 1 : sr_pkt_size;
+ end
+ end
+
+ wire [WIDTH-1:0] int_tdata;
+ wire int_tlast, int_tvalid, int_tready;
+ wire i_tlast_int, i_terror;
+
+ reg small_pkt, large_pkt;
+ wire hold_last_sample;
+ reg release_last;
+ reg [$clog2(MAX_PKT_SIZE+1)-1:0] in_cnt;
+ reg [15:0] in_pkt_cnt, in_pkt_cnt_hold, out_pkt_cnt;
+ always @(posedge clk) begin
+ if (reset | clear) begin
+ small_pkt <= 1'b0;
+ large_pkt <= 1'b0;
+ release_last <= 1'b0;
+ in_cnt <= 1;
+ in_pkt_cnt <= 0;
+ in_pkt_cnt_hold <= 0;
+ out_pkt_cnt <= 0;
+ end else begin
+ if (i_tvalid & i_tready) begin
+ if (in_cnt == pkt_size | i_tlast_int) begin
+ in_cnt <= 1;
+ end else begin
+ in_cnt <= in_cnt + 1;
+ end
+ end
+ if (pkt_size == 1) begin
+ small_pkt <= 1'b0;
+ large_pkt <= 1'b0;
+ end else begin
+ if (i_tvalid & i_tready) begin
+ if ((in_cnt == pkt_size-1'b1) & ~i_tlast) begin
+ small_pkt <= 1'b0;
+ end else begin
+ small_pkt <= 1'b1;
+ end
+ if ((in_cnt == pkt_size) & ~i_tlast) begin
+ large_pkt <= 1'b1;
+ end
+ if (large_pkt) begin
+ large_pkt <= 1'b0;
+ end
+ end
+ end
+ if (i_tvalid & i_tready & i_tlast & ~i_terror) begin
+ in_pkt_cnt <= in_pkt_cnt + 1'b1;
+ end
+ if (int_tvalid & int_tready & int_tlast & ~hold_last_sample) begin
+ out_pkt_cnt <= out_pkt_cnt + 1'b1;
+ end
+ if ((i_tvalid & i_tready & i_terror) | flush) begin
+ release_last <= 1'b1;
+ in_pkt_cnt_hold <= in_pkt_cnt;
+ end else if (in_pkt_cnt_hold == out_pkt_cnt) begin
+ release_last <= 1'b0;
+ end
+ end
+ end
+
+ assign hold_last_sample = ((in_pkt_cnt == out_pkt_cnt) | ((in_pkt_cnt == out_pkt_cnt+1) & ~release_last)) & (pkt_size != 1);
+
+ assign i_tlast_int = i_tlast | large_pkt;
+ assign i_terror = i_tlast & i_tvalid & (small_pkt | large_pkt);
+
+ // FIFO with ability to rewind write pointer back if input packet is flagged as bad
+ axi_packet_gate #(.WIDTH(WIDTH+1), .SIZE($clog2(MAX_PKT_SIZE+1)), .USE_AS_BUFF(1)) pkt_gate_i (
+ .clk(clk), .reset(reset), .clear(clear),
+ .i_tdata({i_tlast,i_tdata}), .i_tvalid(i_tvalid), .i_tlast(i_tlast_int), .i_terror(i_terror), .i_tready(i_tready),
+ .o_tdata({int_tlast,int_tdata}), .o_tvalid(int_tvalid), .o_tlast(), .o_tready(int_tready & ~(hold_last_sample & int_tlast)));
+
+ // Generate output register to hold on to last word
+ if (HOLD_LAST_WORD) begin
+ axi_fifo_flop2 #(.WIDTH(WIDTH+1)) axi_fifo_flop2 (
+ .clk(clk), .reset(reset), .clear(clear),
+ .i_tdata({int_tlast,int_tdata}), .i_tvalid(int_tvalid & ~(hold_last_sample & int_tlast)), .i_tready(int_tready),
+ .o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
+ .space(), .occupied());
+ end else begin
+ assign o_tdata = int_tdata;
+ assign o_tlast = int_tlast;
+ assign o_tvalid = int_tvalid;
+ assign int_tready = o_tready;
+ end
+ end
+ endgenerate
+
+endmodule