forked from SJTU-YONGFU-RESEARCH-GRP/core
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfigurable_param_fifo.v
More file actions
executable file
·162 lines (148 loc) · 6.4 KB
/
configurable_param_fifo.v
File metadata and controls
executable file
·162 lines (148 loc) · 6.4 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
/**
* Configurable Parameter FIFO
*
* This module implements a highly configurable FIFO with optional almost-full
* and almost-empty flags. The almost flags can be enabled or disabled via
* parameter, and include hysteresis to prevent oscillation.
*
* Key Features:
* - Configurable depth: Any FIFO depth (not limited to power of 2)
* - Optional almost flags: Can enable/disable almost-full/empty flags
* - Hysteresis: Almost flags include hysteresis to prevent oscillation
* - Registered output: Read data is registered
* - Valid output: Read valid signal indicates valid data
*
* Almost Flags (when enabled):
* - Almost empty: Asserted when count <= threshold
* - Almost full: Asserted when count >= threshold
* - Hysteresis: Prevents oscillation by requiring different thresholds for assert/deassert
*
* Hysteresis Logic:
* - Almost empty: Assert at threshold, deassert at threshold+1
* - Almost full: Assert at threshold, deassert at threshold-1
*
* Use Cases:
* - Flow control with configurable thresholds
* - Systems requiring optional status flags
* - Applications needing hysteresis
*
* @param DATA_WIDTH Width of data bus (default: 8 bits)
* @param FIFO_DEPTH Depth of FIFO (default: 16)
* @param ADDR_WIDTH Address width = $clog2(FIFO_DEPTH)
* @param ALMOST_FULL_THRESHOLD Almost full threshold (default: FIFO_DEPTH - 2)
* @param ALMOST_EMPTY_THRESHOLD Almost empty threshold (default: 2)
* @param ENABLE_ALMOST_FLAGS Enable almost flags: 1=enabled, 0=disabled (default: 1)
*
* @input clk Clock signal
* @input rst_n Active-low reset signal
* @input wr_en Write enable
* @input rd_en Read enable
* @input wr_data[DATA_WIDTH-1:0] Write data
*
* @output rd_data[DATA_WIDTH-1:0] Read data (registered)
* @output empty Empty flag
* @output full Full flag
* @output almost_empty Almost empty flag (optional)
* @output almost_full Almost full flag (optional)
*/
module configurable_param_fifo #(
parameter DATA_WIDTH = 8, // Width of data bus
parameter FIFO_DEPTH = 16, // Depth of FIFO
parameter ADDR_WIDTH = $clog2(FIFO_DEPTH), // Address width derived from depth
parameter ALMOST_FULL_THRESHOLD = FIFO_DEPTH - 2, // Threshold for almost full flag
parameter ALMOST_EMPTY_THRESHOLD = 2, // Threshold for almost empty flag
parameter ENABLE_ALMOST_FLAGS = 1 // Enable/disable almost full/empty flags
)(
input wire clk, // Clock input
input wire rst_n, // Active low reset
input wire wr_en, // Write enable
input wire rd_en, // Read enable
input wire [DATA_WIDTH-1:0] wr_data, // Write data
output wire [DATA_WIDTH-1:0] rd_data, // Read data
output wire empty, // FIFO empty flag
output wire full, // FIFO full flag
output wire almost_empty, // Almost empty flag (optional)
output wire almost_full // Almost full flag (optional)
);
// Internal registers for FIFO storage
reg [DATA_WIDTH-1:0] mem [0:FIFO_DEPTH-1];
reg [ADDR_WIDTH:0] wr_ptr; // Extra bit for full/empty detection
reg [ADDR_WIDTH:0] rd_ptr; // Extra bit for full/empty detection
reg [DATA_WIDTH-1:0] rd_data_reg; // Register for read data
reg rd_valid; // Register to track if read data is valid
// Calculate pointers for internal memory access
wire [ADDR_WIDTH-1:0] wr_addr = wr_ptr[ADDR_WIDTH-1:0];
wire [ADDR_WIDTH-1:0] rd_addr = rd_ptr[ADDR_WIDTH-1:0];
// Calculate current fill level
wire [ADDR_WIDTH:0] fifo_count = wr_ptr - rd_ptr;
// Empty and full flags using combinational logic
assign empty = (wr_ptr == rd_ptr);
assign full = (wr_ptr[ADDR_WIDTH-1:0] == rd_ptr[ADDR_WIDTH-1:0]) &&
(wr_ptr[ADDR_WIDTH] != rd_ptr[ADDR_WIDTH]);
// Almost empty and full flags with hysteresis
reg almost_empty_reg, almost_full_reg;
generate
if (ENABLE_ALMOST_FLAGS) begin : gen_almost_flags
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
almost_empty_reg <= 1'b1;
almost_full_reg <= 1'b0;
end else begin
// Almost empty with hysteresis
if (empty) begin
almost_empty_reg <= 1'b1;
end else if (fifo_count <= ALMOST_EMPTY_THRESHOLD) begin
almost_empty_reg <= 1'b1;
end else if (fifo_count > ALMOST_EMPTY_THRESHOLD + 1) begin
almost_empty_reg <= 1'b0;
end
// Almost full with hysteresis
if (full) begin
almost_full_reg <= 1'b1;
end else if (fifo_count >= ALMOST_FULL_THRESHOLD) begin
almost_full_reg <= 1'b1;
end else if (fifo_count < ALMOST_FULL_THRESHOLD - 1) begin
almost_full_reg <= 1'b0;
end
end
end
assign almost_empty = almost_empty_reg;
assign almost_full = almost_full_reg;
end else begin : gen_no_almost_flags
assign almost_empty = 1'b0;
assign almost_full = 1'b0;
end
endgenerate
// Write operation
always @(posedge clk) begin
if (wr_en && !full) begin
mem[wr_addr] <= wr_data;
end
end
// Write pointer update
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
wr_ptr <= {(ADDR_WIDTH+1){1'b0}};
end else if (wr_en && !full) begin
wr_ptr <= wr_ptr + 1'b1;
end
end
// Read operation and pointer update
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rd_data_reg <= {DATA_WIDTH{1'b0}};
rd_ptr <= {(ADDR_WIDTH+1){1'b0}};
rd_valid <= 1'b0;
end else begin
if (rd_en && !empty) begin
rd_data_reg <= mem[rd_addr];
rd_ptr <= rd_ptr + 1'b1;
rd_valid <= 1'b1;
end else begin
rd_valid <= 1'b0;
end
end
end
// Output read data only when valid
assign rd_data = rd_valid ? rd_data_reg : {DATA_WIDTH{1'b0}};
endmodule