1//
2// Copyright 2014 Ettus Research LLC
3// Copyright 2018 Ettus Research, a National Instruments Company
4//
5// SPDX-License-Identifier: LGPL-3.0-or-later
6//
7//
8// Ultra fast critical path FIFO.
9// Only 2 entrys but no combinatorial feed through paths
10//
11
12
13module axi_fast_extract_tlast
14  #(parameter WIDTH=64)
15  (
16   input clk,
17   input reset,
18   input clear,
19   //
20   input [WIDTH-1:0] i_tdata,
21   input i_tvalid,
22   output reg i_tready,
23   //
24   output [WIDTH-1:0] o_tdata,
25   output o_tlast,
26   output reg o_tvalid,
27   input  o_tready
28   );
29
30   reg [WIDTH:0] data_reg1, data_reg2;
31
32   reg [1:0] 	   fifo_state;
33
34   localparam EMPTY = 0;
35   localparam HALF = 1;
36   localparam FULL = 2;
37
38   reg [1:0]  extract_state;
39
40   localparam IDLE = 0;
41   localparam EXTRACT1 = 1;
42   localparam EXTRACT2 = 2;
43   localparam EXTRACT3 = 3;
44
45
46   always @(posedge clk)
47     if (reset | clear) begin
48	fifo_state <= EMPTY;
49     end else begin
50	case (fifo_state)
51	  // Nothing in either register.
52	  // Upstream can always push data to us.
53	  // Downstream has nothing to take from us.
54	  EMPTY: begin
55	     if ((extract_state == IDLE) && (i_tdata == 64'hDEADBEEFFEEDCAFE) && i_tvalid) begin
56		// Embeded escpae code received.
57		extract_state <= EXTRACT1;
58		i_tready <= 1'b1;
59		o_tvalid <= 1'b0;
60		fifo_state <= EMPTY;
61	     end else if ((extract_state == EXTRACT1) && i_tvalid) begin
62		// Now work out if its a genuine embeded tlast or emulation.
63		i_tready <= 1'b1;
64		o_tvalid <= 1'b0;
65		fifo_state <= EMPTY;
66		if (i_tdata[31:0] == 'h1) begin
67		   extract_state <= EXTRACT2;
68		end else begin
69		   extract_state <= EXTRACT3;
70		end
71	     end else if ((extract_state == EXTRACT2) && i_tvalid) begin
72		// Extract tlast.
73		data_reg1 <= {1'b1,i_tdata};
74		i_tready <= 1'b1;
75		o_tvalid <= 1'b1;
76		fifo_state <= HALF;
77		extract_state <= IDLE;
78	     end else if (i_tvalid) begin
79		// Get here both for normal data and for EXTRACT3 emulation data.
80		data_reg1 <= {1'b0,i_tdata};
81		fifo_state <= HALF;
82		extract_state <= IDLE;
83		i_tready <= 1'b1;
84		o_tvalid <= 1'b1;
85	     end else begin
86		// Nothing to do.
87		fifo_state <= EMPTY;
88		i_tready <= 1'b1;
89		o_tvalid <= 1'b0;
90	     end
91	  end
92	  // First Register Full.
93	  // Upstream can always push data to us.
94	  // Downstream can always read from us.
95	  HALF: begin
96	     if ((extract_state == IDLE) && (i_tdata == 64'hDEADBEEFFEEDCAFE) && i_tvalid) begin
97		// Embeded escpae code received.
98		extract_state <= EXTRACT1;
99		if (o_tready) begin
100		   // If meanwhile we get read then go empty...
101		   i_tready <= 1'b1;
102		   o_tvalid <= 1'b0;
103		   fifo_state <= EMPTY;
104		end else begin
105		   // ...else stay half full.
106		   fifo_state <= HALF;
107		   i_tready <= 1'b1;
108		   o_tvalid <= 1'b1;
109		end
110	     end else if ((extract_state == EXTRACT1) && i_tvalid) begin
111		// Now work out if its a genuine embeded tlast or emulation.
112		if (i_tdata[31:0] == 'h1) begin
113		   extract_state <= EXTRACT2;
114		end else begin
115		   extract_state <= EXTRACT3;
116		end
117		if (o_tready) begin
118		   // If meanwhile we get read then go empty...
119		   i_tready <= 1'b1;
120		   o_tvalid <= 1'b0;
121		   fifo_state <= EMPTY;
122		end else begin
123		   // ...else stay half full.
124		   fifo_state <= HALF;
125		   i_tready <= 1'b1;
126		   o_tvalid <= 1'b1;
127		end
128	     end else if ((extract_state == EXTRACT2) && i_tvalid) begin
129		// Extract tlast.
130		data_reg1 <= {1'b1,i_tdata};
131		extract_state <= IDLE;
132		if (o_tready) begin
133		   // We get read and writen same cycle...
134		   i_tready <= 1'b1;
135		   o_tvalid <= 1'b1;
136		   fifo_state <= HALF;
137		end else begin
138		   // ...or we get written and go full.
139		   data_reg2 <= data_reg1;
140		   i_tready <= 1'b0;
141		   o_tvalid <= 1'b1;
142		   fifo_state <= FULL;
143		end
144	     end else if (i_tvalid) begin
145		// Get here both for normal data and for EXTRACT3 emulation data.
146		data_reg1 <= {1'b0,i_tdata};
147		extract_state <= IDLE;
148		if (o_tready) begin
149		   // We get read and writen same cycle...
150		   fifo_state <= HALF;
151		   i_tready <= 1'b1;
152		   o_tvalid <= 1'b1;
153		end else begin
154		   // ...or we get written and go full.
155		   data_reg2 <= data_reg1;
156		   i_tready <= 1'b0;
157		   o_tvalid <= 1'b1;
158		   fifo_state <= FULL;
159		end
160	     end else if (o_tready) begin // if (i_tvalid)
161		// Only getting read this cycle so go empty
162		fifo_state <= EMPTY;
163		i_tready <= 1'b1;
164		o_tvalid <= 1'b0;
165	     end else begin
166		// Absolutley nothing happens, everything stays the same.
167		fifo_state <= HALF;
168		i_tready <= 1'b1;
169		o_tvalid <= 1'b1;
170	     end
171	  end // case: HALF
172	  // Both Registers Full.
173	  // Upstream can not push to us in this fifo_state.
174	  // Downstream can always read from us.
175	  FULL: begin
176	     if (o_tready) begin
177		fifo_state <= HALF;
178		i_tready <= 1'b1;
179		o_tvalid <= 1'b1;
180	     end
181	     else begin
182		fifo_state <= FULL;
183		i_tready <= 1'b0;
184		o_tvalid <= 1'b1;
185	     end
186	  end
187	endcase // case(fifo_state)
188     end // else: !if(reset | clear)
189
190   assign {o_tlast,o_tdata} = (fifo_state == FULL) ? data_reg2 : data_reg1;
191
192
193endmodule // axi_fast_extract_tlast
194