aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/axi/axi_extract_tlast.v
blob: 16d6d17c2cc58b5f78916512dabbc7e617689d7f (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
148
149
//
// 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)
  (
   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
   
   );

   reg [1:0] state, next_state;
   
   localparam IDLE = 0;
   localparam EXTRACT1 = 1;
   localparam EXTRACT2 = 2;
   localparam EXTRACT3 = 3;
   
   assign     o_tdata = i_tdata;

   reg [31:0] checksum, old_checksum;
   reg       checksum_error;
   
   
   always @(posedge clk) 
     if (reset | clear) begin
	checksum <= 0;
	old_checksum <= 0;
     end else if (o_tready && i_tvalid && o_tlast) begin
	checksum <= 0;
	old_checksum <= 0;
     end else if (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_reg <= checksum_error;

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

   always @(*) begin
      checksum_error = 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 (old_checksum != i_tdata[63:32]) 
		     checksum_error = 1'b1;
		   next_state = EXTRACT2;
		end
	      else // We assume emulation and don't look for illegal codes.
		begin
		   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