1
+ // ------------------------------------------------------------------------------
2
+ // preview_fifo.sv
3
+ // Konstantin Pavlov, [email protected]
4
+ // ------------------------------------------------------------------------------
5
+
6
+ // INFO ------------------------------------------------------------------------
7
+ // module performs just like an ordinany FIFO in show-ahead mode
8
+ // the diffenence is that 0,1 or 2 words may be requested at once
9
+ // reader can also "preview" future fifo elements without actually fetching it
10
+
11
+
12
+ /* --- INSTANTIATION TEMPLATE BEGIN ---
13
+
14
+ preview_fifo #( parameter
15
+ .WIDTH( 16 ),
16
+ .DEPTH( 16 ),
17
+ ) pf (
18
+ .clk( clk ),
19
+ .nrst( nrst ),
20
+
21
+ // input port
22
+ .wrreq( ),
23
+ .ena( ),
24
+ .id0( ),
25
+ .id1( ),
26
+
27
+ // output port
28
+ .valid( ),
29
+ .shift_req_oh( ),
30
+ .od( ),
31
+ .od( )
32
+ );
33
+
34
+ --- INSTANTIATION TEMPLATE END ---*/
35
+
36
+
37
+ module preview_fifo # ( parameter
38
+ WIDTH = 32 ,
39
+ DEPTH = 16 , // should be power of 2
40
+
41
+ USED_W = $clog2(DEPTH )
42
+ )(
43
+ input clk,
44
+ input nrst,
45
+
46
+ // input port
47
+ output wrreq, // request to make a write
48
+ input ena, // write data to fifo command
49
+ input [WIDTH - 1 : 0 ] id0, // preceding data word
50
+ input [WIDTH - 1 : 0 ] id1, // subsequent data word
51
+ // both data words are written simultaneously
52
+
53
+ // output port
54
+ output valid, // data outputs have valid data
55
+ input [2 : 0 ] shift_req_oh, // 3'b001 - no shift
56
+ // 3'b010 - shift one word
57
+ // 3'b100 - shift two words at once
58
+ output logic [WIDTH - 1 : 0 ] od0, // first data word (preceding)
59
+ output logic [WIDTH - 1 : 0 ] od1, // seconfd dadta word (subsequent)
60
+
61
+
62
+ // debug ports
63
+ output logic fail = 1'b0
64
+ );
65
+
66
+
67
+ // pointer to the first data word
68
+ logic ptr = 1'b0 ;
69
+
70
+ logic [WIDTH - 1 : 0 ] fifo_d0;
71
+ logic [WIDTH - 1 : 0 ] fifo_d1;
72
+
73
+ logic rdreq0 = 1'b0 ;
74
+ logic rdreq1 = 1'b0 ;
75
+
76
+ logic empty0;
77
+ logic empty1;
78
+
79
+ logic full0;
80
+ logic full1;
81
+
82
+ // usedw0[] == usedw1[] OR usedw0[] == (usedw1[]-1) combinations are possible
83
+ logic [USED_W - 1 : 0 ] usedw0;
84
+ logic [USED_W - 1 : 0 ] usedw1;
85
+
86
+ scfifo # (
87
+ .LPM_WIDTH ( WIDTH ),
88
+ .LPM_NUMWORDS ( DEPTH ),
89
+ .LPM_WIDTHU ( USED_W ),
90
+ .LPM_SHOWAHEAD ( " ON" ),
91
+ .UNDERFLOW_CHECKING ( " ON" ),
92
+ .OVERFLOW_CHECKING ( " ON" ),
93
+ .ALMOST_FULL_VALUE ( DEPTH - 4 ),
94
+ .ALMOST_EMPTY_VALUE ( 0 + 4 ),
95
+ .ENABLE_ECC ( " FALSE" ),
96
+ .ALLOW_RWCYCLE_WHEN_FULL ( " ON" ),
97
+ .USE_EAB ( " ON" ),
98
+ .MAXIMIZE_SPEED ( 5 ),
99
+ .DEVICE_FAMILY ( " Cyclone V" )
100
+ ) internal_fifo0 (
101
+ .clock ( clk ),
102
+ .aclr ( 1'b0 ),
103
+ .sclr ( ~ nrst ),
104
+
105
+ .data ( id0[WIDTH - 1 : 0 ] ),
106
+ .wrreq ( ena ),
107
+ .rdreq ( rdreq0 ),
108
+
109
+ .q ( fifo_d0[WIDTH - 1 : 0 ] ),
110
+ .empty ( empty0 ),
111
+ .full ( full0 ),
112
+ .almost_full ( ),
113
+ .almost_empty ( ),
114
+ .usedw ( usedw0[USED_W - 1 : 0 ] ),
115
+ .eccstatus ( ) // [1:0]
116
+ );
117
+
118
+ scfifo # (
119
+ .LPM_WIDTH ( WIDTH ),
120
+ .LPM_NUMWORDS ( DEPTH ),
121
+ .LPM_WIDTHU ( USED_W ),
122
+ .LPM_SHOWAHEAD ( " ON" ),
123
+ .UNDERFLOW_CHECKING ( " ON" ),
124
+ .OVERFLOW_CHECKING ( " ON" ),
125
+ .ALMOST_FULL_VALUE ( DEPTH - 4 ),
126
+ .ALMOST_EMPTY_VALUE ( 0 + 4 ),
127
+ .ENABLE_ECC ( " FALSE" ),
128
+ .ALLOW_RWCYCLE_WHEN_FULL ( " ON" ),
129
+ .USE_EAB ( " ON" ),
130
+ .MAXIMIZE_SPEED ( 5 ),
131
+ .DEVICE_FAMILY ( " Cyclone V" )
132
+ ) internal_fifo1 (
133
+ .clock ( clk ),
134
+ .aclr ( 1'b0 ),
135
+ .sclr ( ~ nrst ),
136
+
137
+ .data ( id1[WIDTH - 1 : 0 ] ),
138
+ .wrreq ( ena ),
139
+ .rdreq ( rdreq1 ),
140
+
141
+ .q ( fifo_d1[WIDTH - 1 : 0 ] ),
142
+ .empty ( empty1 ),
143
+ .full ( full1 ),
144
+ .almost_full ( ),
145
+ .almost_empty ( ),
146
+ .usedw ( usedw1[USED_W - 1 : 0 ] ),
147
+ .eccstatus ( ) // [1:0]
148
+ );
149
+
150
+
151
+ always_ff @ (posedge clk) begin
152
+ if ( ~ nrst ) begin
153
+ ptr <= 1'b0 ;
154
+ fail <= 1'b0 ;
155
+ end else begin
156
+ if ( ptr ) begin // d1 fifo has one extra unaligned word
157
+ case ( shift_req_oh[2 : 0 ] )
158
+ 3'b010 : begin
159
+ ptr <= ~ ptr;
160
+ od0[WIDTH - 1 : 0 ] <= od1[WIDTH - 1 : 0 ];
161
+ od1[WIDTH - 1 : 0 ] <= fifo_d1[WIDTH - 1 : 0 ];
162
+ rdreq0 = 1'b0 ;
163
+ rdreq1 = 1'b1 ;
164
+ end
165
+ 3'b100 : begin
166
+ // ptr <= ptr;
167
+ od0[WIDTH - 1 : 0 ] <= fifo_d0[WIDTH - 1 : 0 ];
168
+ od1[WIDTH - 1 : 0 ] <= fifo_d1[WIDTH - 1 : 0 ];
169
+ rdreq0 = 1'b1 ;
170
+ rdreq1 = 1'b1 ;
171
+ end
172
+ default : ; // do nothing
173
+ endcase
174
+ end else begin // aligned data
175
+ unique case ( shift_req_oh[2 : 0 ] )
176
+ 3'b010 : begin
177
+ ptr <= ~ ptr;
178
+ od0[WIDTH - 1 : 0 ] <= od1[WIDTH - 1 : 0 ];
179
+ od1[WIDTH - 1 : 0 ] <= fifo_d0[WIDTH - 1 : 0 ];
180
+ rdreq0 = 1'b1 ;
181
+ rdreq1 = 1'b0 ;
182
+ end
183
+ 3'b100 : begin
184
+ // ptr <= ptr;
185
+ od0[WIDTH - 1 : 0 ] <= fifo_d1[WIDTH - 1 : 0 ];
186
+ od1[WIDTH - 1 : 0 ] <= fifo_d0[WIDTH - 1 : 0 ];
187
+ rdreq0 = 1'b1 ;
188
+ rdreq1 = 1'b1 ;
189
+ end
190
+ default : ; // do nothing
191
+ endcase
192
+ end // if
193
+
194
+ if ( | shift_req_oh[2 : 1 ] && empty0 ) begin
195
+ fail <= 1'b1 ;
196
+ end
197
+
198
+ end // ~nrst
199
+ end
200
+
201
+ // valid is when both output ports show valid data
202
+ assign valid = ~ empty1;
203
+
204
+ // extra cycles for request and data propagation
205
+ assign wrreq = (usedw0[USED_W - 1 : 0 ] < (DEPTH - 4 ));
206
+
207
+ endmodule
0 commit comments