1
1
// ------------------------------------------------------------------------------
2
2
// fifo_single_clock_ram.sv
3
+ // published as part of https://github.com/pConst/basic_verilog
3
4
// Konstantin Pavlov, pavlovconst@gmail.com
4
5
// ------------------------------------------------------------------------------
5
6
15
16
// - configurable depth and data width
16
17
// - only "normal" mode is supported here, no FWFT mode
17
18
// - protected against overflow and underflow
19
+ // - simultaneous read and write operations supported BUT:
20
+ // only read will happen if simultaneous rw from full fifo
21
+ // only write will happen if simultaneous rw from empty fifo
22
+ // Always honor empty and full flags!
18
23
// - provides fifo contents initialization (!)
19
- //
24
+ // - CAUTION! block RAMs do NOT support fifo contents REinitialization after reset
20
25
21
26
22
27
/* --- INSTANTIATION TEMPLATE BEGIN ---
23
28
24
29
fifo_single_clock_ram #(
25
30
.DEPTH( 8 ),
26
- .DATA_W( 32 )
31
+ .DATA_W( 32 ),
32
+
33
+ // optional initialization
34
+ .INIT_FILE( "fifo_single_clock_ram_init.mem" ),
35
+ .INIT_CNT( 10 )
27
36
) FF1 (
28
37
.clk( clk ),
29
38
.nrst( 1'b1 ),
@@ -43,19 +52,23 @@ fifo_single_clock_ram #(
43
52
44
53
module fifo_single_clock_ram # ( parameter
45
54
46
- // FWFT_MODE = "TRUE", // "TRUE" - first word fall-trrough" mode
47
- // "FALSE" - normal fifo mode
55
+ FWFT_MODE = " TRUE" , // "TRUE" - first word fall-trrough" mode
56
+ // "FALSE" - normal fifo mode
57
+ DEPTH = 8 , // max elements count == DEPTH, DEPTH MUST be power of 2
58
+ DEPTH_W = clogb2(DEPTH )+ 1 , // elements counter width, extra bit to store
59
+ // "fifo full" state, see cnt[] variable comments
60
+
61
+ DATA_W = 32 , // data field width
48
62
49
- DEPTH = 8 , // max elements count == DEPTH, DEPTH MUST be power of 2
50
- DEPTH_W = $clog2(DEPTH )+ 1 , // elements counter width, extra bit to store
51
- // "fifo full" state, see cnt[] variable comments
63
+ RAM_STYLE = " " , // "block","register","M10K","logic",...
52
64
53
- DATA_W = 32 , // data field width
54
- INIT_FILE = " "
65
+ // optional initialization
66
+ INIT_FILE = " " , // .HEX or .MEM file to initialize fifo contents
67
+ INIT_CNT = '0 // sets desired initial cnt[]
55
68
)(
56
69
57
70
input clk,
58
- input nrst, // inverted reset
71
+ input nrst, // inverted reset
59
72
60
73
// input port
61
74
input w_req,
@@ -66,91 +79,107 @@ module fifo_single_clock_ram #( parameter
66
79
output [DATA_W - 1 : 0 ] r_data,
67
80
68
81
// helper ports
69
- output logic [DEPTH_W - 1 : 0 ] cnt = '0 ,
82
+ output logic [DEPTH_W - 1 : 0 ] cnt = INIT_CNT [ DEPTH_W - 1 : 0 ] ,
70
83
output logic empty,
71
84
output logic full,
72
85
73
86
output logic fail
74
87
);
75
88
76
89
77
- // read and write pointers
78
- logic [DEPTH_W - 1 : 0 ] w_ptr = '0 ;
79
- logic [DEPTH_W - 1 : 0 ] r_ptr = '0 ;
80
-
81
- // filtered requests
82
- logic w_req_f;
83
- assign w_req_f = w_req && ~ full;
84
-
85
- logic r_req_f;
86
- assign r_req_f = r_req && ~ empty;
87
-
88
-
89
- true_dual_port_write_first_2_clock_ram # (
90
- .RAM_WIDTH ( DATA_W ),
91
- .RAM_DEPTH ( DEPTH ),
92
- .INIT_FILE ( INIT_FILE )
93
- ) data_ram (
94
- .clka ( clk ),
95
- .addra ( w_ptr[DEPTH_W - 1 : 0 ] ),
96
- .ena ( w_req_f ),
97
- .wea ( 1'b1 ),
98
- .dina ( w_data[DATA_W - 1 : 0 ] ),
99
- .douta ( ),
100
-
101
- .clkb ( clk ),
102
- .addrb ( r_ptr[DEPTH_W - 1 : 0 ] ),
103
- .enb ( r_req_f ),
104
- .web ( 1'b0 ),
105
- .dinb ( '0 ),
106
- .doutb ( r_data[DATA_W - 1 : 0 ] )
107
- );
108
-
109
-
110
- function [DEPTH_W - 1 : 0 ] inc_ptr (
111
- input [DEPTH_W - 1 : 0 ] ptr
112
- );
113
-
114
- if ( ptr[DEPTH_W - 1 : 0 ] == DEPTH - 1 ) begin
115
- inc_ptr[DEPTH_W - 1 : 0 ] = '0 ;
116
- end else begin
117
- inc_ptr[DEPTH_W - 1 : 0 ] = ptr[DEPTH_W - 1 : 0 ] + 1'b1 ;
118
- end
119
- endfunction
120
-
121
-
122
- always_ff @ (posedge clk) begin
123
- if ( ~ nrst ) begin
124
- w_ptr[DEPTH_W - 1 : 0 ] <= '0 ;
125
- r_ptr[DEPTH_W - 1 : 0 ] <= '0 ;
126
-
127
- cnt[DEPTH_W - 1 : 0 ] <= '0 ;
128
- end else begin
129
-
130
- if ( w_req_f ) begin
131
- w_ptr[DEPTH_W - 1 : 0 ] <= inc_ptr (w_ptr[DEPTH_W - 1 : 0 ]);
132
- end
133
-
134
- if ( r_req_f ) begin
135
- r_ptr[DEPTH_W - 1 : 0 ] <= inc_ptr (r_ptr[DEPTH_W - 1 : 0 ]);
90
+ // read and write pointers
91
+ logic [DEPTH_W - 1 : 0 ] w_ptr = INIT_CNT [DEPTH_W - 1 : 0 ];
92
+ logic [DEPTH_W - 1 : 0 ] r_ptr = '0 ;
93
+
94
+ // filtered requests
95
+ logic w_req_f;
96
+ assign w_req_f = w_req && ~ full;
97
+
98
+ logic r_req_f;
99
+ assign r_req_f = r_req && ~ empty;
100
+
101
+
102
+ true_dual_port_write_first_2_clock_ram # (
103
+ .RAM_WIDTH ( DATA_W ),
104
+ .RAM_DEPTH ( DEPTH ),
105
+ .RAM_STYLE ( RAM_STYLE ), // "block","register","M10K","logic",...
106
+ .INIT_FILE ( INIT_FILE )
107
+ ) data_ram (
108
+ .clka ( clk ),
109
+ .addra ( w_ptr[DEPTH_W - 1 : 0 ] ),
110
+ .ena ( w_req_f ),
111
+ .wea ( 1'b1 ),
112
+ .dina ( w_data[DATA_W - 1 : 0 ] ),
113
+ .douta ( ),
114
+
115
+ .clkb ( clk ),
116
+ .addrb ( r_ptr[DEPTH_W - 1 : 0 ] ),
117
+ .enb ( r_req_f ),
118
+ .web ( 1'b0 ),
119
+ .dinb ( '0 ),
120
+ .doutb ( r_data[DATA_W - 1 : 0 ] )
121
+ );
122
+
123
+
124
+ always_ff @ (posedge clk) begin
125
+ if ( ~ nrst ) begin
126
+ w_ptr[DEPTH_W - 1 : 0 ] <= '0 ;
127
+ r_ptr[DEPTH_W - 1 : 0 ] <= '0 ;
128
+
129
+ cnt[DEPTH_W - 1 : 0 ] <= '0 ;
130
+ end else begin
131
+ unique case ({ w_req, r_req} )
132
+ 2'b00 : ; // nothing
133
+
134
+ 2'b01 : begin // reading out
135
+ if ( ~ empty ) begin
136
+ r_ptr[DEPTH_W - 1 : 0 ] <= inc_ptr (r_ptr[DEPTH_W - 1 : 0 ]);
137
+ cnt[DEPTH_W - 1 : 0 ] <= cnt[DEPTH_W - 1 : 0 ] - 1'b1 ;
138
+ end
139
+ end
140
+
141
+ 2'b10 : begin // writing in
142
+ if ( ~ full ) begin
143
+ w_ptr[DEPTH_W - 1 : 0 ] <= inc_ptr (w_ptr[DEPTH_W - 1 : 0 ]);
144
+ cnt[DEPTH_W - 1 : 0 ] <= cnt[DEPTH_W - 1 : 0 ] + 1'b1 ;
145
+ end
146
+ end
147
+
148
+ 2'b11 : begin // simultaneously reading and writing
149
+ if ( empty ) begin
150
+ w_ptr[DEPTH_W - 1 : 0 ] <= inc_ptr (w_ptr[DEPTH_W - 1 : 0 ]);
151
+ cnt[DEPTH_W - 1 : 0 ] <= cnt[DEPTH_W - 1 : 0 ] + 1'b1 ;
152
+ end else if ( full ) begin
153
+ r_ptr[DEPTH_W - 1 : 0 ] <= inc_ptr (r_ptr[DEPTH_W - 1 : 0 ]);
154
+ cnt[DEPTH_W - 1 : 0 ] <= cnt[DEPTH_W - 1 : 0 ] - 1'b1 ;
155
+ end else begin
156
+ w_ptr[DEPTH_W - 1 : 0 ] <= inc_ptr (w_ptr[DEPTH_W - 1 : 0 ]);
157
+ r_ptr[DEPTH_W - 1 : 0 ] <= inc_ptr (r_ptr[DEPTH_W - 1 : 0 ]);
158
+ // cnt[DEPTH_W-1:0] <= // data counter does not change here
159
+ end
160
+ end
161
+ endcase
136
162
end
163
+ end
137
164
138
- if ( w_req_f && ~ r_req_f ) begin
139
- cnt[DEPTH_W - 1 : 0 ] <= cnt[DEPTH_W - 1 : 0 ] + 1'b1 ;
140
- end else if ( ~ w_req_f && r_req_f ) begin
141
- cnt[DEPTH_W - 1 : 0 ] <= cnt[DEPTH_W - 1 : 0 ] - 1'b1 ;
142
- end
165
+ always_comb begin
166
+ empty = ( cnt[DEPTH_W - 1 : 0 ] == '0 );
167
+ full = ( cnt[DEPTH_W - 1 : 0 ] == DEPTH );
143
168
169
+ fail = ( empty && r_req ) ||
170
+ ( full && w_req );
144
171
end
145
- end
146
172
147
- always_comb begin
148
- empty = ( cnt[DEPTH_W - 1 : 0 ] == '0 );
149
- full = ( cnt[DEPTH_W - 1 : 0 ] == DEPTH );
173
+ function [DEPTH_W - 1 : 0 ] inc_ptr (
174
+ input [DEPTH_W - 1 : 0 ] ptr
175
+ );
176
+ if ( ptr[DEPTH_W - 1 : 0 ] == DEPTH - 1 ) begin
177
+ inc_ptr[DEPTH_W - 1 : 0 ] = '0 ;
178
+ end else begin
179
+ inc_ptr[DEPTH_W - 1 : 0 ] = ptr[DEPTH_W - 1 : 0 ] + 1'b1 ;
180
+ end
181
+ endfunction
150
182
151
- fail = ( empty && r_req ) ||
152
- ( full && w_req );
153
- end
183
+ `include " clogb2.svh"
154
184
155
185
endmodule
156
-
0 commit comments