forked from SJTU-YONGFU-RESEARCH-GRP/core
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfwft_fifo.v
More file actions
executable file
·187 lines (171 loc) · 7.56 KB
/
fwft_fifo.v
File metadata and controls
executable file
·187 lines (171 loc) · 7.56 KB
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/**
* First-Word Fall-Through (FWFT) FIFO
*
* This module implements a First-Word Fall-Through FIFO, also known as a
* show-ahead FIFO. Unlike standard FIFOs, the first word appears at the output
* immediately when data is available, without requiring a read enable pulse first.
*
* Key Features:
* - First-word fall-through: Data appears immediately when available
* - Output register: Pre-fetches data for immediate availability
* - Lower latency: No read enable needed to see data
* - Standard FIFO: Full/empty flags and status indicators
*
* FWFT vs Standard FIFO:
* - Standard FIFO: Read enable must be asserted before data appears
* - FWFT FIFO: Data is always visible when FIFO is not empty
* - Advantage: Lower latency, data ready immediately
* - Use case: When consumer needs to see data before deciding to read
*
* Operation:
* - When FIFO receives data: Automatically pre-fetches to output register
* - When consumer reads: Output register is consumed, next data pre-fetched
* - Output register: Always contains next data to be read (if available)
*
* Output Register:
* - Pre-fetches data from FIFO memory
* - Makes data available immediately
* - Advances read pointer when data is consumed
*
* Use Cases:
* - Low-latency data pipelines
* - Protocols requiring data inspection before consumption
* - Systems where data visibility is more important than explicit dequeue
* - Interfaces requiring immediate data availability
*
* @param DATA_WIDTH Width of data words (default: 8 bits)
* @param ADDR_WIDTH Address width - FIFO depth = 2^ADDR_WIDTH (default: 4, depth=16)
* @param ALMOST_FULL_THRESHOLD Almost full threshold (default: 2)
* @param ALMOST_EMPTY_THRESHOLD Almost empty threshold (default: 2)
*
* @input clk Clock signal
* @input rst_n Active-low reset signal
* @input wr_en Write enable
* @input wr_data[DATA_WIDTH-1:0] Write data
* @output full Full flag
* @output almost_full Almost full flag
*
* @input rd_en Read enable (removes data from FIFO)
* @output rd_data[DATA_WIDTH-1:0] Read data (from output register)
* @output empty Empty flag (true when output register is invalid)
* @output almost_empty Almost empty flag
* @output data_count[ADDR_WIDTH:0] Current number of entries in FIFO
*/
module fwft_fifo #(
parameter DATA_WIDTH = 8,
parameter ADDR_WIDTH = 4, // FIFO depth = 2^ADDR_WIDTH
parameter ALMOST_FULL_THRESHOLD = 2,
parameter ALMOST_EMPTY_THRESHOLD = 2
) (
input wire clk,
input wire rst_n,
// Write interface
input wire wr_en,
input wire [DATA_WIDTH-1:0] wr_data,
output wire full,
output wire almost_full,
// Read interface (FWFT style)
input wire rd_en,
output wire [DATA_WIDTH-1:0] rd_data,
output wire empty,
output wire almost_empty,
// Status
output wire [ADDR_WIDTH:0] data_count
);
// Memory array for data storage
reg [DATA_WIDTH-1:0] mem [(1<<ADDR_WIDTH)-1:0];
// Pointers
reg [ADDR_WIDTH:0] wr_ptr; // Write pointer
reg [ADDR_WIDTH:0] rd_ptr; // Read pointer
// FWFT output registers
reg [DATA_WIDTH-1:0] output_reg; // First word register
reg output_valid; // First word valid flag
// Status signals
wire fifo_empty = (wr_ptr == rd_ptr);
wire next_empty = (wr_ptr == rd_ptr + 1'b1) && rd_en && !fifo_empty;
wire raw_empty; // Standard FIFO empty flag
// FIFO count
assign data_count = wr_ptr - rd_ptr;
// Status flags
assign raw_empty = (data_count == 0);
assign full = (data_count == (1<<ADDR_WIDTH));
assign almost_full = (data_count >= ((1<<ADDR_WIDTH) - ALMOST_FULL_THRESHOLD));
assign almost_empty = (data_count <= ALMOST_EMPTY_THRESHOLD) && !raw_empty;
// FWFT empty signal - empty only when output register is invalid
assign empty = !output_valid;
// Write pointer logic
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
wr_ptr <= 0;
end else if (wr_en && !full) begin
wr_ptr <= wr_ptr + 1'b1;
end
end
// Read pointer logic
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rd_ptr <= 0;
end else if (rd_en && !raw_empty) begin
rd_ptr <= rd_ptr + 1'b1;
end
end
// Memory write operation
always @(posedge clk) begin
if (wr_en && !full) begin
mem[wr_ptr[ADDR_WIDTH-1:0]] <= wr_data;
end
end
// ============================================================================
// FWFT Output Register Logic
// ============================================================================
// Manages the output register that provides first-word fall-through behavior
// The output register pre-fetches data to make it immediately available
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
// ====================================================================
// Reset State
// ====================================================================
output_valid <= 1'b0;
output_reg <= {DATA_WIDTH{1'b0}};
end else begin
// ====================================================================
// Case 1: Data Consumed, Fetch Next
// ====================================================================
// When reading and output register is valid, need to fetch next data
if (rd_en && output_valid) begin
if (!raw_empty) begin
// ============================================================
// FIFO Not Empty: Fetch Next Data
// ============================================================
// Pre-fetch next data from FIFO memory
// This keeps data ready for immediate consumption
output_reg <= mem[rd_ptr[ADDR_WIDTH-1:0]];
output_valid <= 1'b1;
end else begin
// ============================================================
// FIFO Empty: Invalidate Output
// ============================================================
// No more data available: invalidate output register
output_valid <= 1'b0;
end
end
// ====================================================================
// Case 2: Output Invalid, FIFO Has Data
// ====================================================================
// When output register is invalid and FIFO is not empty
// Automatically pre-fetch data (this is the "fall-through" behavior)
else if (!output_valid && !raw_empty) begin
// ================================================================
// Pre-Fetch Data
// ================================================================
// Fetch data from FIFO and make it immediately available
output_reg <= mem[rd_ptr[ADDR_WIDTH-1:0]];
output_valid <= 1'b1;
// Advance read pointer since we've consumed this entry
rd_ptr <= rd_ptr + 1'b1;
end
end
end
// Read data output
assign rd_data = output_reg;
endmodule