aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/axi/axi_embed_tlast.v
blob: bc14043e9afc965e150157a2bce393d5e6f6d34a (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
//
// 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_embed_tlast #(
  parameter WIDTH=64,
  parameter ADD_CHECKSUM=0
) (
   input clk,
   input reset,
   input clear,
   //
   input [WIDTH-1:0] i_tdata,
   input i_tlast,
   input i_tvalid,
   output i_tready,
   //
   output reg [WIDTH-1:0] o_tdata,
   output o_tvalid,
   input o_tready
);

   localparam PASS = 0;
   localparam ZERO = 1;
   localparam ONE = 2;
   localparam ESCAPE = 3;

   localparam IDLE = 0;
   localparam LAST = 1;
   localparam ESC = 2;
   localparam FINISH = 3;
   
   reg [1:0]  state, next_state;

   reg [1:0]  select;

   wire [31:0] checksum;
   generate if (ADD_CHECKSUM == 1) begin
      reg [31:0] checksum_reg;
      always @(posedge clk) begin
         if (reset | clear) begin
            checksum_reg <= 0;
         end else if (i_tready && i_tvalid && i_tlast) begin
            checksum_reg <= 0;
         end else if (i_tready && i_tvalid) begin
            checksum_reg <= checksum_reg ^ i_tdata[31:0] ^ i_tdata[63:32];
         end
      end
      assign checksum = checksum_reg;
   end else begin
      assign checksum = 32'h0;
   end endgenerate

   always @(posedge clk) 
      if (reset | clear) begin
         state <= IDLE;
      end else begin if (o_tready)
         state <= next_state;
      end 

   always @(*) begin
      case(state)
         IDLE: begin
            if (i_tlast && i_tvalid) begin
               next_state = LAST;
               select = ESCAPE;
            end else if ((i_tdata == 64'hDEADBEEFFEEDCAFE) && i_tvalid) begin
               next_state = ESC;
               select = ESCAPE;
            end else begin
               next_state = IDLE;
               select = PASS;
            end
         end // case: IDLE

         LAST: begin
            select = ONE;
            next_state = FINISH;
         end

         ESC: begin
            select = ZERO;
            next_state = FINISH;
         end

         FINISH: begin
            select = PASS;
            if (i_tvalid)
               next_state = IDLE;
            else
               next_state = FINISH;
         end
      endcase // case(state)
   end // always @ (*)

   //
   // Muxes
   //
   always @*
      begin
         case(select)
            PASS:   o_tdata = i_tdata;
            ZERO:   o_tdata = 0;
            ONE:    o_tdata = {checksum[31:0],32'h1};
            ESCAPE: o_tdata = 64'hDEADBEEFFEEDCAFE;
         endcase // case(select)
      end

   assign o_tvalid = (select == PASS) ? i_tvalid : 1'b1;
   assign i_tready = (select == PASS) ? o_tready : 1'b0;

endmodule // axi_embed_tlast