forked from SJTU-YONGFU-RESEARCH-GRP/core
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmemory_mapped_fifo.v
More file actions
executable file
·193 lines (177 loc) · 6.97 KB
/
memory_mapped_fifo.v
File metadata and controls
executable file
·193 lines (177 loc) · 6.97 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
188
189
190
191
192
193
/**
* Memory-Mapped FIFO
*
* This module implements a FIFO that can be accessed via a memory-mapped
* interface, making it accessible from processors or other memory-mapped
* systems. It also provides an optional external interface for direct access.
*
* Key Features:
* - Memory-mapped interface: Accessible via standard memory-mapped bus
* - Register map: Defined register addresses for FIFO operations
* - Control operations: Reset and flush via control register
* - Status register: Provides FIFO status flags
* - External interface: Optional direct FIFO access
*
* Register Map:
* - 0x0 (FIFO_DATA_REG): Read=pop data, Write=push data
* - 0x4 (FIFO_STATUS_REG): Read FIFO status flags
* - 0x8 (FIFO_CONTROL_REG): Write control operations (reset, flush)
* - 0xC (FIFO_COUNT_REG): Read number of entries
*
* Control Register Bits:
* - Bit 0 (CTRL_RESET_BIT): Reset FIFO
* - Bit 1 (CTRL_FLUSH_BIT): Flush FIFO
*
* Status Register Bits:
* - Bit 0: Empty flag
* - Bit 1: Full flag
* - Bit 2: Almost empty flag
* - Bit 3: Almost full flag
*
* Use Cases:
* - Processor-accessible FIFOs
* - Memory-mapped I/O
* - System-on-Chip (SoC) integration
* - Register-based control
*
* @param DATA_WIDTH Width of data bus (default: 32 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
*
* Memory-Mapped Interface:
* @input mem_valid Memory access valid
* @input mem_write Memory write (1=write, 0=read)
* @input mem_addr[3:0] Memory address (register select)
* @input mem_wdata[DATA_WIDTH-1:0] Memory write data
* @output mem_ready Memory ready signal
* @output mem_rdata[DATA_WIDTH-1:0] Memory read data
*
* External Interface:
* @output ext_empty External empty flag
* @output ext_full External full flag
* @input ext_rd_en External read enable
* @output ext_rd_data[DATA_WIDTH-1:0] External read data
* @input ext_wr_en External write enable
* @input ext_wr_data[DATA_WIDTH-1:0] External write data
*/
module memory_mapped_fifo #(
parameter DATA_WIDTH = 32,
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,
// Memory-mapped interface
input wire mem_valid,
input wire mem_write,
input wire [3:0] mem_addr,
input wire [DATA_WIDTH-1:0] mem_wdata,
output reg mem_ready,
output reg [DATA_WIDTH-1:0] mem_rdata,
// Optional external interface
output wire ext_empty,
output wire ext_full,
input wire ext_rd_en,
output wire [DATA_WIDTH-1:0] ext_rd_data,
input wire ext_wr_en,
input wire [DATA_WIDTH-1:0] ext_wr_data
);
// Register map
localparam FIFO_DATA_REG = 4'h0; // Read: pop data, Write: push data
localparam FIFO_STATUS_REG = 4'h4; // Read: FIFO status
localparam FIFO_CONTROL_REG = 4'h8; // Write: control operations
localparam FIFO_COUNT_REG = 4'hC; // Read: number of entries
// Control register bits
localparam CTRL_RESET_BIT = 0; // Reset FIFO
localparam CTRL_FLUSH_BIT = 1; // Flush FIFO
// Status register bits
localparam STATUS_EMPTY_BIT = 0;
localparam STATUS_FULL_BIT = 1;
localparam STATUS_ALMOST_EMPTY_BIT = 2;
localparam STATUS_ALMOST_FULL_BIT = 3;
// Memory array for data storage
reg [DATA_WIDTH-1:0] mem [(1<<ADDR_WIDTH)-1:0];
// FIFO pointers
reg [ADDR_WIDTH:0] wr_ptr;
reg [ADDR_WIDTH:0] rd_ptr;
// Register to hold data for external read interface
reg [DATA_WIDTH-1:0] ext_data_reg;
// Internal control signals
wire fifo_wr_en = (mem_valid && mem_write && mem_addr == FIFO_DATA_REG) || ext_wr_en;
wire fifo_rd_en = (mem_valid && !mem_write && mem_addr == FIFO_DATA_REG) || ext_rd_en;
wire fifo_flush = mem_valid && mem_write && mem_addr == FIFO_CONTROL_REG && mem_wdata[CTRL_FLUSH_BIT];
wire fifo_reset = mem_valid && mem_write && mem_addr == FIFO_CONTROL_REG && mem_wdata[CTRL_RESET_BIT];
// FIFO count and status
wire [ADDR_WIDTH:0] fifo_count = wr_ptr - rd_ptr;
wire fifo_empty = (fifo_count == 0);
wire fifo_full = (fifo_count == (1<<ADDR_WIDTH));
wire fifo_almost_empty = (fifo_count <= ALMOST_EMPTY_THRESHOLD) && !fifo_empty;
wire fifo_almost_full = (fifo_count >= ((1<<ADDR_WIDTH) - ALMOST_FULL_THRESHOLD));
// Status register
wire [DATA_WIDTH-1:0] status_reg = {
{(DATA_WIDTH-4){1'b0}},
fifo_almost_full,
fifo_almost_empty,
fifo_full,
fifo_empty
};
// Write pointer logic
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
wr_ptr <= 0;
end else if (fifo_reset || fifo_flush) begin
wr_ptr <= 0;
end else if (fifo_wr_en && !fifo_full) begin
wr_ptr <= wr_ptr + 1'b1;
mem[wr_ptr[ADDR_WIDTH-1:0]] <= mem_valid ? mem_wdata : ext_wr_data;
end
end
// Read pointer logic
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
rd_ptr <= 0;
ext_data_reg <= {DATA_WIDTH{1'b0}};
end else if (fifo_reset || fifo_flush) begin
rd_ptr <= 0;
ext_data_reg <= {DATA_WIDTH{1'b0}};
end else if (fifo_rd_en && !fifo_empty) begin
// Capture the data at current read pointer, then increment pointer
ext_data_reg <= mem[rd_ptr[ADDR_WIDTH-1:0]];
rd_ptr <= rd_ptr + 1'b1;
end
end
// Memory-mapped read logic
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
mem_rdata <= 0;
mem_ready <= 0;
end else begin
mem_ready <= mem_valid; // Respond in the next cycle
if (mem_valid && !mem_write) begin
case (mem_addr)
FIFO_DATA_REG: begin
mem_rdata <= fifo_empty ? {DATA_WIDTH{1'b0}} : mem[rd_ptr[ADDR_WIDTH-1:0]];
end
FIFO_STATUS_REG: begin
mem_rdata <= status_reg;
end
FIFO_COUNT_REG: begin
mem_rdata <= {{(DATA_WIDTH-ADDR_WIDTH-1){1'b0}}, fifo_count};
end
default: begin
mem_rdata <= {DATA_WIDTH{1'b0}};
end
endcase
end
end
end
// External interface signals
assign ext_empty = fifo_empty;
assign ext_full = fifo_full;
assign ext_rd_data = ext_data_reg;
endmodule