aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/axi/axi_extract_tlast.v
diff options
context:
space:
mode:
Diffstat (limited to 'fpga/usrp3/lib/axi/axi_extract_tlast.v')
-rw-r--r--fpga/usrp3/lib/axi/axi_extract_tlast.v147
1 files changed, 147 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/axi/axi_extract_tlast.v b/fpga/usrp3/lib/axi/axi_extract_tlast.v
new file mode 100644
index 000000000..9afef3c35
--- /dev/null
+++ b/fpga/usrp3/lib/axi/axi_extract_tlast.v
@@ -0,0 +1,147 @@
+//
+// Copyright 2014 Ettus Research LLC
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: LGPL-3.0-or-later
+//
+//
+// AXI stream neds N+1 bits to transmit packets of N bits so that the LAST bit can be represented.
+// LAST occurs relatively infrequently and can be synthesized by using an in-band ESC code to generate
+// a multi-word sequence to encode it (and the escape character when it appears as data input).
+//
+// 0x1234567887654321 with last becomes
+// 0xDEADBEEFFEEDCAFE 0x0000000000000001 0x1234567887654321
+//
+// 0xDEADBEEFFEEDCAFE with last becomes
+// 0xDEADBEEFFEEDCAFE 0x0000000000000001 0xDEADBEEFFEEDCAFE
+//
+// 0xDEADBEEFFEEDCAFE without last becomes
+// 0xDEADBEEFFEEDCAFE 0x0000000000000000 0xDEADBEEFFEEDCAFE
+//
+
+module axi_extract_tlast #(
+ parameter WIDTH=64,
+ parameter VALIDATE_CHECKSUM=0
+) (
+ input clk,
+ input reset,
+ input clear,
+ //
+ input [WIDTH-1:0] i_tdata,
+ input i_tvalid,
+ output reg i_tready,
+ //
+ output [WIDTH-1:0] o_tdata,
+ output reg o_tlast,
+ output reg o_tvalid,
+ input o_tready,
+ //
+ output reg checksum_error
+);
+
+ reg [1:0] state, next_state;
+
+ localparam IDLE = 0;
+ localparam EXTRACT1 = 1;
+ localparam EXTRACT2 = 2;
+ localparam EXTRACT3 = 3;
+
+ assign o_tdata = i_tdata;
+
+ reg checksum_error_pre;
+ reg [31:0] checksum, old_checksum;
+
+ always @(posedge clk)
+ if (reset | clear) begin
+ checksum <= 0;
+ old_checksum <= 0;
+ end else if (VALIDATE_CHECKSUM && o_tready && i_tvalid && o_tlast) begin
+ checksum <= 0;
+ old_checksum <= 0;
+ end else if (VALIDATE_CHECKSUM && i_tready && i_tvalid && (state == IDLE)) begin
+ checksum <= checksum ^ i_tdata[31:0] ^ i_tdata[63:32];
+ old_checksum <= checksum;
+ end
+
+ always @(posedge clk)
+ checksum_error <= checksum_error_pre;
+
+ always @(posedge clk)
+ if (reset | clear) begin
+ state <= IDLE;
+ end else begin
+ state <= next_state;
+ end
+
+ always @(*) begin
+ checksum_error_pre = 0;
+ case(state)
+ //
+ // Search for Escape sequence "0xDEADBEEFFEEDCAFE"
+ // If ESC found don't pass data downstream but transition to next state.
+ // else pass data downstream.
+ //
+ IDLE: begin
+ o_tlast = 1'b0;
+ if ((i_tdata == 64'hDEADBEEFFEEDCAFE) && i_tvalid) begin
+ next_state = EXTRACT1;
+ o_tvalid = 1'b0;
+ i_tready = 1'b1;
+ end else begin
+ next_state = IDLE;
+ o_tvalid = i_tvalid;
+ i_tready = o_tready;
+ end // else: !if((i_tdata == 'hDEADBEEFFEEDCAFE) && i_tvalid)
+ end // case: IDLE
+ //
+ // Look at next data. If it's a 0x1 then o_tlast should be asserted with next data word.
+ // if it's 0x0 then it signals emulation of the Escape code in the original data stream
+ // and we should just pass the next data word through unchanged with no o_tlast indication.
+ //
+ EXTRACT1: begin
+ o_tvalid = 1'b0;
+ i_tready = 1'b1;
+ o_tlast = 1'b0;
+ if (i_tvalid) begin
+ if (i_tdata[31:0] == 'h1) begin
+ if (VALIDATE_CHECKSUM && (old_checksum != i_tdata[63:32]))
+ checksum_error_pre = 1'b1;
+ next_state = EXTRACT2;
+ end else begin
+ // We assume emulation and don't look for illegal codes.
+ next_state = EXTRACT3;
+ end // else: !if(i_tdata == 'h1)
+ end else begin // if (i_tvalid)
+ next_state = EXTRACT1;
+ end // else: !if(i_tvalid)
+ end // case: EXTRACT1
+ //
+ // Assert o_tlast with data word.
+ //
+ EXTRACT2: begin
+ o_tvalid = i_tvalid;
+ i_tready = o_tready;
+ o_tlast = 1'b1;
+ if (i_tvalid & o_tready)
+ next_state = IDLE;
+ else
+ next_state = EXTRACT2;
+ end
+ //
+ // Emulation, don't assert o_tlast with dataword.
+ //
+ EXTRACT3: begin
+ o_tvalid = i_tvalid;
+ i_tready = o_tready;
+ o_tlast = 1'b0;
+ if (i_tvalid & o_tready)
+ next_state = IDLE;
+ else
+ next_state = EXTRACT2;
+ end
+ endcase // case(state)
+ end
+
+endmodule // axi_extract_tlast
+
+ \ No newline at end of file