aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/axi/axi_extract_tlast.v
blob: 9afef3c35515554049442b3c8fe199902352e025 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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