-
Notifications
You must be signed in to change notification settings - Fork 384
/
fifo_single_clock_ram.sv
executable file
·185 lines (148 loc) · 5.02 KB
/
fifo_single_clock_ram.sv
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
//------------------------------------------------------------------------------
// fifo_single_clock_ram.sv
// published as part of https://github.com/pConst/basic_verilog
// Konstantin Pavlov, [email protected]
//------------------------------------------------------------------------------
// INFO ------------------------------------------------------------------------
// Single-clock FIFO buffer implementation, also known as "queue"
//
// This fifo variant should synthesize into block RAM seamlessly, both for
// Altera and for Xilinx chips. Simulation is also consistent.
// Use this fifo when you need cross-vendor and sim/synth compatibility.
//
// Features:
// - single clock operation
// - configurable depth and data width
// - only "normal" mode is supported here, no FWFT mode
// - protected against overflow and underflow
// - simultaneous read and write operations supported BUT:
// only read will happen if simultaneous rw from full fifo
// only write will happen if simultaneous rw from empty fifo
// Always honor empty and full flags!
// - provides fifo contents initialization (!)
// - CAUTION! block RAMs do NOT support fifo contents REinitialization after reset
/* --- INSTANTIATION TEMPLATE BEGIN ---
fifo_single_clock_ram #(
.DEPTH( 8 ),
.DATA_W( 32 ),
// optional initialization
.INIT_FILE( "fifo_single_clock_ram_init.mem" ),
.INIT_CNT( 10 )
) FF1 (
.clk( clk ),
.nrst( 1'b1 ),
.w_req( ),
.w_data( ),
.r_req( ),
.r_data( ),
.cnt( ),
.empty( ),
.full( )
);
--- INSTANTIATION TEMPLATE END ---*/
module fifo_single_clock_ram #( parameter
FWFT_MODE = "TRUE", // "TRUE" - first word fall-trrough" mode
// "FALSE" - normal fifo mode
DEPTH = 8, // max elements count == DEPTH, DEPTH MUST be power of 2
DEPTH_W = clogb2(DEPTH)+1, // elements counter width, extra bit to store
// "fifo full" state, see cnt[] variable comments
DATA_W = 32, // data field width
RAM_STYLE = "", // "block","register","M10K","logic",...
// optional initialization
INIT_FILE = "", // .HEX or .MEM file to initialize fifo contents
INIT_CNT = '0 // sets desired initial cnt[]
)(
input clk,
input nrst, // inverted reset
// input port
input w_req,
input [DATA_W-1:0] w_data,
// output port
input r_req,
output [DATA_W-1:0] r_data,
// helper ports
output logic [DEPTH_W-1:0] cnt = INIT_CNT[DEPTH_W-1:0],
output logic empty,
output logic full,
output logic fail
);
// read and write pointers
logic [DEPTH_W-1:0] w_ptr = INIT_CNT[DEPTH_W-1:0];
logic [DEPTH_W-1:0] r_ptr = '0;
// filtered requests
logic w_req_f;
assign w_req_f = w_req && ~full;
logic r_req_f;
assign r_req_f = r_req && ~empty;
true_dual_port_write_first_2_clock_ram #(
.RAM_WIDTH( DATA_W ),
.RAM_DEPTH( DEPTH ),
.RAM_STYLE( RAM_STYLE ), // "block","register","M10K","logic",...
.INIT_FILE( INIT_FILE )
) data_ram (
.clka( clk ),
.addra( w_ptr[DEPTH_W-1:0] ),
.ena( w_req_f ),
.wea( 1'b1 ),
.dina( w_data[DATA_W-1:0] ),
.douta( ),
.clkb( clk ),
.addrb( r_ptr[DEPTH_W-1:0] ),
.enb( r_req_f ),
.web( 1'b0 ),
.dinb( '0 ),
.doutb( r_data[DATA_W-1:0] )
);
always_ff @(posedge clk) begin
if ( ~nrst ) begin
w_ptr[DEPTH_W-1:0] <= '0;
r_ptr[DEPTH_W-1:0] <= '0;
cnt[DEPTH_W-1:0] <= '0;
end else begin
unique case ({w_req, r_req})
2'b00: ; // nothing
2'b01: begin // reading out
if( ~empty ) begin
r_ptr[DEPTH_W-1:0] <= inc_ptr(r_ptr[DEPTH_W-1:0]);
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] - 1'b1;
end
end
2'b10: begin // writing in
if( ~full ) begin
w_ptr[DEPTH_W-1:0] <= inc_ptr(w_ptr[DEPTH_W-1:0]);
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] + 1'b1;
end
end
2'b11: begin // simultaneously reading and writing
if( empty ) begin
w_ptr[DEPTH_W-1:0] <= inc_ptr(w_ptr[DEPTH_W-1:0]);
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] + 1'b1;
end else if( full ) begin
r_ptr[DEPTH_W-1:0] <= inc_ptr(r_ptr[DEPTH_W-1:0]);
cnt[DEPTH_W-1:0] <= cnt[DEPTH_W-1:0] - 1'b1;
end else begin
w_ptr[DEPTH_W-1:0] <= inc_ptr(w_ptr[DEPTH_W-1:0]);
r_ptr[DEPTH_W-1:0] <= inc_ptr(r_ptr[DEPTH_W-1:0]);
//cnt[DEPTH_W-1:0] <= // data counter does not change here
end
end
endcase
end
end
always_comb begin
empty = ( cnt[DEPTH_W-1:0] == '0 );
full = ( cnt[DEPTH_W-1:0] == DEPTH );
fail = ( empty && r_req ) ||
( full && w_req );
end
function [DEPTH_W-1:0] inc_ptr (
input [DEPTH_W-1:0] ptr
);
if( ptr[DEPTH_W-1:0] == DEPTH-1 ) begin
inc_ptr[DEPTH_W-1:0] = '0;
end else begin
inc_ptr[DEPTH_W-1:0] = ptr[DEPTH_W-1:0] + 1'b1;
end
endfunction
`include "clogb2.svh"
endmodule