1 |
2 |
kdv |
/*
|
2 |
|
|
* framestore_request.v
|
3 |
|
|
*
|
4 |
|
|
* Copyright (c) 2007 Koen De Vleeschauwer.
|
5 |
|
|
*
|
6 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
7 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
8 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
9 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
10 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
11 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
12 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
13 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
14 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
15 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
16 |
|
|
* SUCH DAMAGE.
|
17 |
|
|
*/
|
18 |
|
|
|
19 |
|
|
/*
|
20 |
|
|
* Frame Store Requests. Write requests to memory controller.
|
21 |
|
|
*
|
22 |
|
|
* Receives memory read and write requests from motion compensation and display;
|
23 |
|
|
* passes the read and write requests on to the memory controller.
|
24 |
|
|
*/
|
25 |
|
|
|
26 |
|
|
`include "timescale.v"
|
27 |
|
|
|
28 |
|
|
`undef DEBUG
|
29 |
|
|
//`define DEBUG 1
|
30 |
|
|
|
31 |
|
|
`undef DEBUG_2
|
32 |
|
|
//`define DEBUG_2
|
33 |
|
|
|
34 |
|
|
`undef CHECK
|
35 |
|
|
`ifdef __IVERILOG__
|
36 |
|
|
`define CHECK 1
|
37 |
|
|
`endif
|
38 |
|
|
|
39 |
|
|
//`define SIMULATION_ONLY
|
40 |
|
|
`ifdef __IVERILOG__
|
41 |
|
|
`define SIMULATION_ONLY 1
|
42 |
|
|
`endif
|
43 |
|
|
|
44 |
|
|
module framestore_request(rst, clk,
|
45 |
|
|
fwd_rd_addr_empty, fwd_rd_addr_en, fwd_rd_addr_valid, fwd_rd_addr, fwd_wr_dta_full, fwd_wr_dta_almost_full, fwd_rd_dta_almost_empty,
|
46 |
|
|
bwd_rd_addr_empty, bwd_rd_addr_en, bwd_rd_addr_valid, bwd_rd_addr, bwd_wr_dta_full, bwd_wr_dta_almost_full, bwd_rd_dta_almost_empty,
|
47 |
|
|
recon_rd_empty, recon_rd_almost_empty, recon_rd_en, recon_rd_valid, recon_rd_addr, recon_rd_dta, recon_wr_almost_full,
|
48 |
|
|
disp_rd_addr_empty, disp_rd_addr_en, disp_rd_addr_valid, disp_rd_addr, disp_wr_dta_full, disp_wr_dta_almost_full, disp_rd_dta_almost_empty,
|
49 |
|
|
osd_rd_empty, osd_rd_almost_empty, osd_rd_en, osd_rd_valid, osd_rd_addr, osd_rd_dta, osd_wr_almost_full,
|
50 |
|
|
vbw_rd_empty, vbw_rd_almost_empty, vbw_rd_en, vbw_rd_valid, vbw_rd_dta, vbw_wr_almost_full,
|
51 |
|
|
vbr_wr_full, vbr_wr_almost_full, vbr_rd_almost_empty,
|
52 |
|
|
vb_flush,
|
53 |
|
|
mem_req_wr_cmd, mem_req_wr_addr, mem_req_wr_dta, mem_req_wr_en, mem_req_wr_almost_full,
|
54 |
|
|
tag_wr_dta, tag_wr_en, tag_wr_almost_full
|
55 |
|
|
);
|
56 |
|
|
|
57 |
|
|
input rst;
|
58 |
|
|
input clk;
|
59 |
|
|
/* motion compensation: reading forward reference frame */
|
60 |
|
|
input fwd_rd_addr_empty;
|
61 |
|
|
output reg fwd_rd_addr_en;
|
62 |
|
|
input fwd_rd_addr_valid;
|
63 |
|
|
input [21:0]fwd_rd_addr;
|
64 |
|
|
input fwd_wr_dta_full;
|
65 |
|
|
input fwd_wr_dta_almost_full;
|
66 |
|
|
input fwd_rd_dta_almost_empty;
|
67 |
|
|
/* motion compensation: reading backward reference frame */
|
68 |
|
|
input bwd_rd_addr_empty;
|
69 |
|
|
output reg bwd_rd_addr_en;
|
70 |
|
|
input bwd_rd_addr_valid;
|
71 |
|
|
input [21:0]bwd_rd_addr;
|
72 |
|
|
input bwd_wr_dta_full;
|
73 |
|
|
input bwd_wr_dta_almost_full;
|
74 |
|
|
input bwd_rd_dta_almost_empty;
|
75 |
|
|
/* motion compensation: writing reconstructed frame */
|
76 |
|
|
input recon_rd_empty;
|
77 |
|
|
input recon_rd_almost_empty;
|
78 |
|
|
output reg recon_rd_en;
|
79 |
|
|
input recon_rd_valid;
|
80 |
|
|
input [21:0]recon_rd_addr;
|
81 |
|
|
input [63:0]recon_rd_dta;
|
82 |
|
|
input recon_wr_almost_full;
|
83 |
|
|
/* display: reading reconstructed frame */
|
84 |
|
|
input disp_rd_addr_empty;
|
85 |
|
|
output reg disp_rd_addr_en;
|
86 |
|
|
input disp_rd_addr_valid;
|
87 |
|
|
input [21:0]disp_rd_addr;
|
88 |
|
|
input disp_wr_dta_full;
|
89 |
|
|
input disp_wr_dta_almost_full;
|
90 |
|
|
input disp_rd_dta_almost_empty;
|
91 |
|
|
/* video buffer: writing to circular buffer */
|
92 |
|
|
input [63:0]vbw_rd_dta;
|
93 |
|
|
output reg vbw_rd_en;
|
94 |
|
|
input vbw_rd_valid;
|
95 |
|
|
input vbw_rd_empty;
|
96 |
|
|
input vbw_rd_almost_empty;
|
97 |
|
|
input vbw_wr_almost_full;
|
98 |
|
|
/* video buffer: reading from circular buffer */
|
99 |
|
|
input vbr_wr_full;
|
100 |
|
|
input vbr_wr_almost_full;
|
101 |
|
|
input vbr_rd_almost_empty;
|
102 |
|
|
/* video buffer: flushing circular buffer */
|
103 |
|
|
input vb_flush;
|
104 |
|
|
/* register file: writing on-screen display */
|
105 |
|
|
input osd_rd_empty;
|
106 |
|
|
input osd_rd_almost_empty;
|
107 |
|
|
output reg osd_rd_en;
|
108 |
|
|
input osd_rd_valid;
|
109 |
|
|
input [21:0]osd_rd_addr;
|
110 |
|
|
input [63:0]osd_rd_dta;
|
111 |
|
|
input osd_wr_almost_full;
|
112 |
|
|
/* memory request fifo */
|
113 |
|
|
output reg [1:0]mem_req_wr_cmd;
|
114 |
|
|
output reg [21:0]mem_req_wr_addr;
|
115 |
|
|
output reg [63:0]mem_req_wr_dta;
|
116 |
|
|
output reg mem_req_wr_en;
|
117 |
|
|
input mem_req_wr_almost_full;
|
118 |
|
|
/* memory tag fifo */
|
119 |
|
|
output reg [2:0]tag_wr_dta;
|
120 |
|
|
output reg tag_wr_en;
|
121 |
|
|
input tag_wr_almost_full;
|
122 |
|
|
|
123 |
|
|
parameter [15:0]
|
124 |
|
|
REFRESH_CYCLES = 16'd1024; /* number of mem_clk clock cycles between memory refreshes. */
|
125 |
|
|
|
126 |
|
|
parameter
|
127 |
|
|
REFRESH_EN = 1'b0; /* 1 if needs to issue REFRESH; 0 if no need to issue refresh commands, eg. sram */
|
128 |
|
|
|
129 |
|
|
/*
|
130 |
|
|
* memory controller commands.
|
131 |
|
|
*/
|
132 |
|
|
|
133 |
|
|
`include "mem_codes.v"
|
134 |
|
|
|
135 |
|
|
wire do_refresh;
|
136 |
|
|
wire do_disp;
|
137 |
|
|
wire do_vbr;
|
138 |
|
|
wire do_fwd;
|
139 |
|
|
wire do_bwd;
|
140 |
|
|
wire do_recon;
|
141 |
|
|
wire do_osd;
|
142 |
|
|
wire do_vbw;
|
143 |
|
|
|
144 |
|
|
/*
|
145 |
|
|
* memory clear address
|
146 |
|
|
*/
|
147 |
|
|
|
148 |
|
|
reg [21:0]mem_clr_addr;
|
149 |
|
|
reg [21:0]mem_clr_addr_0;
|
150 |
|
|
|
151 |
|
|
/*
|
152 |
|
|
* circular video buffer addresses
|
153 |
|
|
*/
|
154 |
|
|
|
155 |
|
|
reg [21:0]vbuf_wr_addr;
|
156 |
|
|
reg [21:0]vbuf_rd_addr;
|
157 |
|
|
|
158 |
|
|
reg vbuf_full;
|
159 |
|
|
reg vbuf_empty;
|
160 |
|
|
|
161 |
|
|
/*
|
162 |
|
|
* State machine
|
163 |
|
|
* Implements priority scheme.
|
164 |
|
|
* From highest to lowest priority:
|
165 |
|
|
* - disp display read
|
166 |
|
|
* - vbr video buffer read
|
167 |
|
|
* - fwd forward motion compensation read
|
168 |
|
|
* - bwd backward motion compensation read
|
169 |
|
|
* - vbw video buffer write
|
170 |
|
|
* - recon motion compensation write
|
171 |
|
|
* - osd on-screen display write
|
172 |
|
|
* Roughly modeled after the priority scheme in
|
173 |
|
|
* "Architecture and Bus-Arbitration Schemes for MPEG-2 Video Decoder",
|
174 |
|
|
* Jui-Hua Li and Nam Ling,
|
175 |
|
|
* IEEE Transactions on Circuits and Systems for Video Technology, Vol. 9, No. 5, August 1999, p.727-736.
|
176 |
|
|
*/
|
177 |
|
|
|
178 |
|
|
|
179 |
|
|
parameter [10:0]
|
180 |
|
|
STATE_INIT = 11'b00000000001,
|
181 |
|
|
STATE_CLEAR = 11'b00000000010,
|
182 |
|
|
STATE_IDLE = 11'b00000000100,
|
183 |
|
|
STATE_REFRESH = 11'b00000001000,
|
184 |
|
|
STATE_DISP = 11'b00000010000,
|
185 |
|
|
STATE_VBR = 11'b00000100000,
|
186 |
|
|
STATE_FWD = 11'b00001000000,
|
187 |
|
|
STATE_BWD = 11'b00010000000,
|
188 |
|
|
STATE_VBW = 11'b00100000000,
|
189 |
|
|
STATE_RECON = 11'b01000000000,
|
190 |
|
|
STATE_OSD = 11'b10000000000;
|
191 |
|
|
|
192 |
|
|
reg [10:0]state;
|
193 |
|
|
reg [10:0]next;
|
194 |
|
|
reg [10:0]previous;
|
195 |
|
|
|
196 |
|
|
/* next state logic */
|
197 |
|
|
always @*
|
198 |
|
|
case (state)
|
199 |
|
|
STATE_INIT: next = STATE_CLEAR;
|
200 |
|
|
STATE_CLEAR: if ((mem_clr_addr == VBUF_END) && ~mem_req_wr_almost_full) next = STATE_IDLE; // initialize memory
|
201 |
|
|
else next = STATE_CLEAR;
|
202 |
|
|
STATE_IDLE,
|
203 |
|
|
STATE_DISP,
|
204 |
|
|
STATE_VBR,
|
205 |
|
|
STATE_FWD,
|
206 |
|
|
STATE_BWD,
|
207 |
|
|
STATE_VBW,
|
208 |
|
|
STATE_RECON,
|
209 |
|
|
STATE_OSD: if (do_refresh) next = STATE_REFRESH; // schedule a dram refresh
|
210 |
|
|
else if (do_disp) next = STATE_DISP; // schedule a read for the display fifo
|
211 |
|
|
else if (do_vbr) next = STATE_VBR; // schedule a read from circular video buffer
|
212 |
|
|
else if (do_fwd) next = STATE_FWD; // schedule a read for forward motion compensation
|
213 |
|
|
else if (do_bwd) next = STATE_BWD; // schedule a read for backward motion compensation
|
214 |
|
|
else if (do_vbw) next = STATE_VBW; // schedule a write to circular video buffer
|
215 |
|
|
else if (do_recon) next = STATE_RECON; // schedule a write for motion compensation to write the reconstructed frame
|
216 |
|
|
else if (do_osd) next = STATE_OSD; // schedule a write for register file to write to the on-screen display
|
217 |
|
|
else next = STATE_IDLE; // nothing to do
|
218 |
|
|
|
219 |
|
|
STATE_REFRESH: if (do_disp) next = STATE_DISP;
|
220 |
|
|
else if (do_vbr) next = STATE_VBR;
|
221 |
|
|
else if (do_fwd) next = STATE_FWD;
|
222 |
|
|
else if (do_bwd) next = STATE_BWD;
|
223 |
|
|
else if (do_vbw) next = STATE_VBW;
|
224 |
|
|
else if (do_recon) next = STATE_RECON;
|
225 |
|
|
else if (do_osd) next = STATE_OSD;
|
226 |
|
|
else next = STATE_IDLE;
|
227 |
|
|
|
228 |
|
|
default next = STATE_IDLE;
|
229 |
|
|
|
230 |
|
|
endcase
|
231 |
|
|
|
232 |
|
|
always @(posedge clk)
|
233 |
|
|
if (~rst) state <= STATE_INIT;
|
234 |
|
|
else state <= next;
|
235 |
|
|
|
236 |
|
|
always @(posedge clk)
|
237 |
|
|
if (~rst) previous <= STATE_INIT;
|
238 |
|
|
else previous <= state;
|
239 |
|
|
|
240 |
|
|
/*
|
241 |
|
|
* Read data from fifo's
|
242 |
|
|
*/
|
243 |
|
|
|
244 |
|
|
always @(posedge clk)
|
245 |
|
|
if (~rst) disp_rd_addr_en <= 1'b0;
|
246 |
|
|
else disp_rd_addr_en <= (next == STATE_DISP);
|
247 |
|
|
|
248 |
|
|
always @(posedge clk)
|
249 |
|
|
if (~rst) fwd_rd_addr_en <= 1'b0;
|
250 |
|
|
else fwd_rd_addr_en <= (next == STATE_FWD);
|
251 |
|
|
|
252 |
|
|
always @(posedge clk)
|
253 |
|
|
if (~rst) bwd_rd_addr_en <= 1'b0;
|
254 |
|
|
else bwd_rd_addr_en <= (next == STATE_BWD);
|
255 |
|
|
|
256 |
|
|
always @(posedge clk)
|
257 |
|
|
if (~rst) recon_rd_en <= 1'b0;
|
258 |
|
|
else recon_rd_en <= (next == STATE_RECON);
|
259 |
|
|
|
260 |
|
|
always @(posedge clk)
|
261 |
|
|
if (~rst) vbw_rd_en <= 1'b0;
|
262 |
|
|
else vbw_rd_en <= (next == STATE_VBW);
|
263 |
|
|
|
264 |
|
|
always @(posedge clk)
|
265 |
|
|
if (~rst) osd_rd_en <= 1'b0;
|
266 |
|
|
else osd_rd_en <= (next == STATE_OSD);
|
267 |
|
|
|
268 |
|
|
/*
|
269 |
|
|
* Write address, data, command to memory request fifo.
|
270 |
|
|
* Write tag to tag fifo.
|
271 |
|
|
*/
|
272 |
|
|
|
273 |
|
|
always @(posedge clk)
|
274 |
|
|
if (~rst) tag_wr_dta <= TAG_CTRL;
|
275 |
|
|
else
|
276 |
|
|
case (previous)
|
277 |
|
|
STATE_INIT: tag_wr_dta <= TAG_CTRL;
|
278 |
|
|
STATE_CLEAR: tag_wr_dta <= TAG_CTRL;
|
279 |
|
|
STATE_IDLE: tag_wr_dta <= TAG_CTRL;
|
280 |
|
|
STATE_REFRESH: tag_wr_dta <= TAG_CTRL;
|
281 |
|
|
STATE_DISP: tag_wr_dta <= TAG_DISP;
|
282 |
|
|
STATE_VBR: tag_wr_dta <= TAG_VBUF;
|
283 |
|
|
STATE_FWD: tag_wr_dta <= TAG_FWD;
|
284 |
|
|
STATE_BWD: tag_wr_dta <= TAG_BWD;
|
285 |
|
|
STATE_RECON: tag_wr_dta <= TAG_RECON;
|
286 |
|
|
STATE_VBW: tag_wr_dta <= TAG_VBUF;
|
287 |
|
|
STATE_OSD: tag_wr_dta <= TAG_OSD;
|
288 |
|
|
default tag_wr_dta <= TAG_CTRL;
|
289 |
|
|
endcase
|
290 |
|
|
|
291 |
|
|
always @(posedge clk)
|
292 |
|
|
if (~rst) tag_wr_en <= 1'b0;
|
293 |
|
|
else
|
294 |
|
|
case (previous)
|
295 |
|
|
STATE_INIT: tag_wr_en <= 1'b0;
|
296 |
|
|
STATE_CLEAR: tag_wr_en <= 1'b0;
|
297 |
|
|
STATE_IDLE: tag_wr_en <= 1'b0;
|
298 |
|
|
STATE_REFRESH: tag_wr_en <= 1'b0;
|
299 |
|
|
STATE_DISP: tag_wr_en <= disp_rd_addr_valid;
|
300 |
|
|
STATE_VBR: tag_wr_en <= ~vbuf_empty;
|
301 |
|
|
STATE_FWD: tag_wr_en <= fwd_rd_addr_valid;
|
302 |
|
|
STATE_BWD: tag_wr_en <= bwd_rd_addr_valid;
|
303 |
|
|
STATE_RECON: tag_wr_en <= 1'b0;
|
304 |
|
|
STATE_VBW: tag_wr_en <= 1'b0;
|
305 |
|
|
STATE_OSD: tag_wr_en <= 1'b0;
|
306 |
|
|
default tag_wr_en <= 1'b0;
|
307 |
|
|
endcase
|
308 |
|
|
|
309 |
|
|
always @(posedge clk)
|
310 |
|
|
if (~rst) mem_req_wr_cmd <= CMD_NOOP;
|
311 |
|
|
else
|
312 |
|
|
case (previous)
|
313 |
|
|
STATE_INIT: mem_req_wr_cmd <= CMD_NOOP;
|
314 |
|
|
STATE_CLEAR: mem_req_wr_cmd <= CMD_WRITE;
|
315 |
|
|
STATE_IDLE: mem_req_wr_cmd <= CMD_NOOP;
|
316 |
|
|
STATE_REFRESH: mem_req_wr_cmd <= CMD_REFRESH;
|
317 |
|
|
STATE_DISP: mem_req_wr_cmd <= disp_rd_addr_valid ? CMD_READ : CMD_NOOP;
|
318 |
|
|
STATE_VBR: mem_req_wr_cmd <= ~vbuf_empty ? CMD_READ : CMD_NOOP;
|
319 |
|
|
STATE_FWD: mem_req_wr_cmd <= fwd_rd_addr_valid ? CMD_READ : CMD_NOOP;
|
320 |
|
|
STATE_BWD: mem_req_wr_cmd <= bwd_rd_addr_valid ? CMD_READ : CMD_NOOP;
|
321 |
|
|
STATE_RECON: mem_req_wr_cmd <= recon_rd_valid ? CMD_WRITE : CMD_NOOP;
|
322 |
|
|
STATE_VBW: mem_req_wr_cmd <= vbw_rd_valid ? CMD_WRITE : CMD_NOOP;
|
323 |
|
|
STATE_OSD: mem_req_wr_cmd <= osd_rd_valid ? CMD_WRITE : CMD_NOOP;
|
324 |
|
|
default mem_req_wr_cmd <= CMD_NOOP;
|
325 |
|
|
endcase
|
326 |
|
|
|
327 |
|
|
always @(posedge clk)
|
328 |
|
|
if (~rst) mem_req_wr_addr <= 22'b0;
|
329 |
|
|
else
|
330 |
|
|
case (previous)
|
331 |
|
|
STATE_INIT: mem_req_wr_addr <= 22'b0;
|
332 |
|
|
STATE_CLEAR: mem_req_wr_addr <= mem_clr_addr_0;
|
333 |
|
|
STATE_IDLE: mem_req_wr_addr <= 22'b0;
|
334 |
|
|
STATE_REFRESH: mem_req_wr_addr <= 22'b0;
|
335 |
|
|
STATE_DISP: mem_req_wr_addr <= disp_rd_addr_valid ? disp_rd_addr : 22'b0;
|
336 |
|
|
STATE_VBR: mem_req_wr_addr <= ~vbuf_empty ? vbuf_rd_addr : 22'b0;
|
337 |
|
|
STATE_FWD: mem_req_wr_addr <= fwd_rd_addr_valid ? fwd_rd_addr : 22'b0;
|
338 |
|
|
STATE_BWD: mem_req_wr_addr <= bwd_rd_addr_valid ? bwd_rd_addr : 22'b0;
|
339 |
|
|
STATE_RECON: mem_req_wr_addr <= recon_rd_valid ? recon_rd_addr : 22'b0;
|
340 |
|
|
STATE_VBW: mem_req_wr_addr <= vbw_rd_valid ? vbuf_wr_addr : 22'b0;
|
341 |
|
|
STATE_OSD: mem_req_wr_addr <= osd_rd_valid ? osd_rd_addr : 22'b0;
|
342 |
|
|
default mem_req_wr_addr <= 22'b0;
|
343 |
|
|
endcase
|
344 |
|
|
|
345 |
|
|
|
346 |
|
|
/*
|
347 |
|
|
* All y,u and v values are stored in memory with an offset of 128; hence every memory byte is initialized to 8'd128.
|
348 |
|
|
* This corresponds to y=u=v=0; a dull green.
|
349 |
|
|
*/
|
350 |
|
|
|
351 |
|
|
always @(posedge clk)
|
352 |
|
|
if (~rst) mem_req_wr_dta <= 64'b0;
|
353 |
|
|
else
|
354 |
|
|
case (previous)
|
355 |
|
|
STATE_INIT: mem_req_wr_dta <= 64'b0;
|
356 |
|
|
STATE_CLEAR: mem_req_wr_dta <= {8{8'd128}}; // initialize memory to all zeroes; all zeroes in yuv is a dull green
|
357 |
|
|
// STATE_CLEAR: mem_req_wr_dta <= {mem_clr_addr_0, 32'hdeadbeef}; // initialize memory so reads from addresses not written to can be easily detected
|
358 |
|
|
STATE_IDLE: mem_req_wr_dta <= 64'b0;
|
359 |
|
|
STATE_REFRESH: mem_req_wr_dta <= 64'b0;
|
360 |
|
|
STATE_DISP: mem_req_wr_dta <= 64'b0;
|
361 |
|
|
STATE_VBR: mem_req_wr_dta <= 64'b0;
|
362 |
|
|
STATE_FWD: mem_req_wr_dta <= 64'b0;
|
363 |
|
|
STATE_BWD: mem_req_wr_dta <= 64'b0;
|
364 |
|
|
STATE_RECON: mem_req_wr_dta <= recon_rd_valid ? recon_rd_dta : 64'b0;
|
365 |
|
|
STATE_VBW: mem_req_wr_dta <= vbw_rd_valid ? vbw_rd_dta : 64'b0;
|
366 |
|
|
STATE_OSD: mem_req_wr_dta <= osd_rd_valid ? osd_rd_dta : 64'b0;
|
367 |
|
|
default mem_req_wr_dta <= 64'b0;
|
368 |
|
|
endcase
|
369 |
|
|
|
370 |
|
|
always @(posedge clk)
|
371 |
|
|
if (~rst) mem_req_wr_en <= 1'b0;
|
372 |
|
|
else
|
373 |
|
|
case (previous)
|
374 |
|
|
STATE_INIT: mem_req_wr_en <= 1'b0;
|
375 |
|
|
STATE_CLEAR: mem_req_wr_en <= ~mem_req_wr_almost_full;
|
376 |
|
|
STATE_IDLE: mem_req_wr_en <= 1'b0;
|
377 |
|
|
STATE_REFRESH: mem_req_wr_en <= 1'b1;
|
378 |
|
|
STATE_DISP: mem_req_wr_en <= disp_rd_addr_valid;
|
379 |
|
|
STATE_VBR: mem_req_wr_en <= ~vbuf_empty;
|
380 |
|
|
STATE_FWD: mem_req_wr_en <= fwd_rd_addr_valid;
|
381 |
|
|
STATE_BWD: mem_req_wr_en <= bwd_rd_addr_valid;
|
382 |
|
|
STATE_RECON: mem_req_wr_en <= recon_rd_valid;
|
383 |
|
|
STATE_VBW: mem_req_wr_en <= vbw_rd_valid;
|
384 |
|
|
STATE_OSD: mem_req_wr_en <= osd_rd_valid;
|
385 |
|
|
default mem_req_wr_en <= 1'b0;
|
386 |
|
|
endcase
|
387 |
|
|
|
388 |
|
|
|
389 |
|
|
/*
|
390 |
|
|
* Clearing memory at start-up.
|
391 |
|
|
* When we're simulating, SIMULATION_ONLY is defined and we only clear 10 addresses at the end of memory, else simulation takes forever.
|
392 |
|
|
* When we're synthesizing, SIMULATION_ONLY is not defined, and we initialize all of memory.
|
393 |
|
|
*/
|
394 |
|
|
|
395 |
|
|
always @(posedge clk)
|
396 |
|
|
if (~rst) mem_clr_addr <= 22'd0;
|
397 |
|
|
`ifdef SIMULATION_ONLY
|
398 |
|
|
else if (state == STATE_INIT) mem_clr_addr <= VBUF_END - 22'd10; /* only clear ten last addresses */
|
399 |
|
|
`else
|
400 |
|
|
else if (state == STATE_INIT) mem_clr_addr <= FRAME_0_Y; /* lowest address used */
|
401 |
|
|
`endif
|
402 |
|
|
else if ((state == STATE_CLEAR) && ~mem_req_wr_almost_full) mem_clr_addr <= mem_clr_addr + 22'd1;
|
403 |
|
|
else mem_clr_addr <= mem_clr_addr;
|
404 |
|
|
|
405 |
|
|
always @(posedge clk)
|
406 |
|
|
if (~rst) mem_clr_addr_0 <= FRAME_0_Y;
|
407 |
|
|
else if ((state == STATE_CLEAR) && ~mem_req_wr_almost_full) mem_clr_addr_0 <= mem_clr_addr;
|
408 |
|
|
else mem_clr_addr_0 <= mem_clr_addr_0;
|
409 |
|
|
|
410 |
|
|
/*
|
411 |
|
|
* Refresh counter. Refresh at least every REFRESH_CYCLES cycles.
|
412 |
|
|
*/
|
413 |
|
|
|
414 |
|
|
reg [15:0]refresh_cnt;
|
415 |
|
|
|
416 |
|
|
always @(posedge clk)
|
417 |
|
|
if (~rst) refresh_cnt <= REFRESH_CYCLES;
|
418 |
|
|
else if (state == STATE_REFRESH) refresh_cnt <= REFRESH_CYCLES;
|
419 |
|
|
else if (refresh_cnt != 0) refresh_cnt <= refresh_cnt - 1;
|
420 |
|
|
else refresh_cnt <= refresh_cnt;
|
421 |
|
|
|
422 |
|
|
/*
|
423 |
|
|
* circular video buffer addresses
|
424 |
|
|
*/
|
425 |
|
|
|
426 |
|
|
reg [21:0]next_vbuf_wr_addr;
|
427 |
|
|
reg [21:0]next_vbuf_rd_addr;
|
428 |
|
|
reg next_vbuf_full;
|
429 |
|
|
reg next_vbuf_empty;
|
430 |
|
|
|
431 |
|
|
always @*
|
432 |
|
|
if ((previous == STATE_VBW) && vbw_rd_valid) next_vbuf_wr_addr = (vbuf_wr_addr == VBUF_END) ? VBUF : (vbuf_wr_addr + 22'd1);
|
433 |
|
|
else next_vbuf_wr_addr = vbuf_wr_addr;
|
434 |
|
|
|
435 |
|
|
always @*
|
436 |
|
|
if ((previous == STATE_VBR) && ~vbuf_empty) next_vbuf_rd_addr = (vbuf_rd_addr == VBUF_END) ? VBUF : (vbuf_rd_addr + 22'd1);
|
437 |
|
|
else next_vbuf_rd_addr = vbuf_rd_addr;
|
438 |
|
|
|
439 |
|
|
always @*
|
440 |
|
|
next_vbuf_full = ((next_vbuf_wr_addr + 22'd1) == next_vbuf_rd_addr) || ((next_vbuf_wr_addr == VBUF_END) && (next_vbuf_rd_addr == VBUF));
|
441 |
|
|
|
442 |
|
|
always @*
|
443 |
|
|
next_vbuf_empty = (next_vbuf_wr_addr == next_vbuf_rd_addr);
|
444 |
|
|
|
445 |
|
|
always @(posedge clk)
|
446 |
|
|
if (~rst) vbuf_wr_addr <= VBUF;
|
447 |
|
|
else if (vb_flush) vbuf_wr_addr <= VBUF;
|
448 |
|
|
else vbuf_wr_addr <= next_vbuf_wr_addr;
|
449 |
|
|
|
450 |
|
|
always @(posedge clk)
|
451 |
|
|
if (~rst) vbuf_rd_addr <= VBUF;
|
452 |
|
|
else if (vb_flush) vbuf_rd_addr <= VBUF;
|
453 |
|
|
else vbuf_rd_addr <= next_vbuf_rd_addr;
|
454 |
|
|
|
455 |
|
|
always @(posedge clk)
|
456 |
|
|
if (~rst) vbuf_full <= 1'b0;
|
457 |
|
|
else if (vb_flush) vbuf_full <= 1'b0;
|
458 |
|
|
else vbuf_full <= next_vbuf_full;
|
459 |
|
|
|
460 |
|
|
always @(posedge clk)
|
461 |
|
|
if (~rst) vbuf_empty <= 1'b1;
|
462 |
|
|
else if (vb_flush) vbuf_empty <= 1'b1;
|
463 |
|
|
else vbuf_empty <= next_vbuf_empty;
|
464 |
|
|
|
465 |
|
|
/*
|
466 |
|
|
* Priority scheme:
|
467 |
|
|
* refresh > display frame read > forward frame read > backward frame read > reconstructed frame write > osd write
|
468 |
|
|
*
|
469 |
|
|
* Note we do not treat requests for a 'reader' when the data fifo is "almost full".
|
470 |
|
|
* this way the data fifo never overflows (hopefully).
|
471 |
|
|
*
|
472 |
|
|
* Note we do not allow two consecutive vbuf writes.
|
473 |
|
|
* The first vbuf write might cause vbuf_full to assert, which would make the second vbuf write overflow the fifo.
|
474 |
|
|
* Not allowing two consecutive vbuf writes is not a problem, given program stream bitrates.
|
475 |
|
|
*/
|
476 |
|
|
|
477 |
|
|
wire vbuf_holdoff = (state == STATE_VBW) || (state == STATE_VBR) || (previous == STATE_VBW) || (previous == STATE_VBR);
|
478 |
|
|
|
479 |
|
|
assign do_refresh = (refresh_cnt == 0) && REFRESH_EN && ~mem_req_wr_almost_full;
|
480 |
|
|
assign do_disp = ~disp_rd_addr_empty && ~disp_wr_dta_almost_full && ~mem_req_wr_almost_full && ~tag_wr_almost_full;
|
481 |
|
|
assign do_vbr = ~vbuf_empty && ~vbuf_holdoff && vbr_rd_almost_empty && ~mem_req_wr_almost_full && ~tag_wr_almost_full;
|
482 |
|
|
assign do_fwd = ~fwd_rd_addr_empty && ~fwd_wr_dta_almost_full && ~mem_req_wr_almost_full && ~tag_wr_almost_full;
|
483 |
|
|
assign do_bwd = ~bwd_rd_addr_empty && ~bwd_wr_dta_almost_full && ~mem_req_wr_almost_full && ~tag_wr_almost_full;
|
484 |
|
|
assign do_recon = ~recon_rd_empty && ~mem_req_wr_almost_full;
|
485 |
|
|
assign do_vbw = ~vbuf_full && ~vbuf_holdoff && ~vbw_rd_empty && ~mem_req_wr_almost_full;
|
486 |
|
|
assign do_osd = ~osd_rd_empty && ~mem_req_wr_almost_full;
|
487 |
|
|
|
488 |
|
|
`ifdef DEBUG
|
489 |
|
|
always @(posedge clk)
|
490 |
|
|
case (state)
|
491 |
|
|
STATE_INIT: #0 $display("%m\tinit");
|
492 |
|
|
STATE_CLEAR: if (~mem_req_wr_almost_full) #0 $display("%m\tclear %h", mem_clr_addr);
|
493 |
|
|
STATE_IDLE: #0 $display("%m\tidle");
|
494 |
|
|
STATE_DISP: if (disp_rd_addr_valid) #0 $display("%m\tdisp read %h", disp_rd_addr);
|
495 |
|
|
STATE_VBW: if (vbw_rd_valid) #0 $display("%m\tvbw write %6h = %h", vbuf_wr_addr, vbw_rd_dta);
|
496 |
|
|
STATE_FWD: if (fwd_rd_addr_valid) #0 $display("%m\tfwd read %h", fwd_rd_addr);
|
497 |
|
|
STATE_BWD: if (bwd_rd_addr_valid) #0 $display("%m\tbwd read %h", bwd_rd_addr);
|
498 |
|
|
STATE_RECON: if (recon_rd_valid) #0 $display("%m\trecon write %6h = %h", recon_rd_addr, recon_rd_dta);
|
499 |
|
|
STATE_VBR: #0 $display("%m\tvbr read %h", vbuf_rd_addr);
|
500 |
|
|
STATE_OSD: if (osd_rd_valid) #0 $display("%m\tosd write %6h = %h", osd_rd_addr, osd_rd_dta);
|
501 |
|
|
default #0 $display("%m\t** Error: unknown state %d **", state);
|
502 |
|
|
endcase
|
503 |
|
|
|
504 |
|
|
`endif
|
505 |
|
|
|
506 |
|
|
`ifdef CHECK
|
507 |
|
|
always @(posedge clk)
|
508 |
|
|
if (vbw_rd_valid && vbr_wr_full)
|
509 |
|
|
begin
|
510 |
|
|
$display("%m\t***error*** vbw_rd_valid && vbr_wr_full");
|
511 |
|
|
$finish();
|
512 |
|
|
end
|
513 |
|
|
|
514 |
|
|
always @(posedge clk)
|
515 |
|
|
if ((state == STATE_VBW) && vbw_rd_valid && ((vbuf_wr_addr < VBUF) || (vbuf_wr_addr > VBUF_END)))
|
516 |
|
|
begin
|
517 |
|
|
$display("%m\t***error*** vbuf_wr_addr out of range: %h", vbuf_wr_addr);
|
518 |
|
|
$finish();
|
519 |
|
|
end
|
520 |
|
|
|
521 |
|
|
always @(posedge clk)
|
522 |
|
|
if ((state == STATE_VBR) && ~vbuf_empty && ((vbuf_rd_addr < VBUF) || (vbuf_rd_addr > VBUF_END)))
|
523 |
|
|
begin
|
524 |
|
|
$display("%m\t***error*** vbuf_rd_addr out of range: %h", vbuf_rd_addr);
|
525 |
|
|
$finish();
|
526 |
|
|
end
|
527 |
|
|
`endif
|
528 |
|
|
|
529 |
|
|
`ifdef DEBUG_2
|
530 |
|
|
always @(posedge clk)
|
531 |
|
|
case (state)
|
532 |
|
|
STATE_INIT: #0 $display("%m\tSTATE_INIT");
|
533 |
|
|
STATE_CLEAR: #0 $display("%m\tSTATE_CLEAR");
|
534 |
|
|
STATE_IDLE: #0 $display("%m\tSTATE_IDLE");
|
535 |
|
|
STATE_REFRESH: #0 $display("%m\tSTATE_REFRESH");
|
536 |
|
|
STATE_DISP: #0 $display("%m\tSTATE_DISP");
|
537 |
|
|
STATE_VBR: #0 $display("%m\tSTATE_VBR");
|
538 |
|
|
STATE_FWD: #0 $display("%m\tSTATE_FWD");
|
539 |
|
|
STATE_BWD: #0 $display("%m\tSTATE_BWD");
|
540 |
|
|
STATE_RECON: #0 $display("%m\tSTATE_RECON");
|
541 |
|
|
STATE_VBW: #0 $display("%m\tSTATE_VBW");
|
542 |
|
|
STATE_OSD: #0 $display("%m\tSTATE_OSD");
|
543 |
|
|
default #0 $display("%m\t** Error: unknown state %d **", state);
|
544 |
|
|
endcase
|
545 |
|
|
|
546 |
|
|
|
547 |
|
|
always @(posedge clk)
|
548 |
|
|
begin
|
549 |
|
|
$strobe("%m\tstate: %h fwd_rd_addr_empty: %h fwd_rd_addr_en: %h fwd_rd_addr_valid: %h fwd_rd_addr: %h fwd_wr_dta_full: %h",
|
550 |
|
|
state, fwd_rd_addr_empty, fwd_rd_addr_en, fwd_rd_addr_valid, fwd_rd_addr, fwd_wr_dta_full);
|
551 |
|
|
$strobe("%m\tbwd_rd_addr_empty: %h bwd_rd_addr_en: %h bwd_rd_addr_valid: %h bwd_rd_addr: %h bwd_wr_dta_full: %h",
|
552 |
|
|
bwd_rd_addr_empty, bwd_rd_addr_en, bwd_rd_addr_valid, bwd_rd_addr, bwd_wr_dta_full);
|
553 |
|
|
$strobe("%m\trecon_rd_empty: %h recon_rd_en: %h recon_rd_valid: %h recon_rd_addr: %h recon_rd_dta: %h",
|
554 |
|
|
recon_rd_empty, recon_rd_en, recon_rd_valid, recon_rd_addr, recon_rd_dta);
|
555 |
|
|
$strobe("%m\tdisp_rd_addr_empty: %h disp_rd_addr_en: %h disp_rd_addr_valid: %h disp_rd_addr: %h disp_wr_dta_full: %h",
|
556 |
|
|
disp_rd_addr_empty, disp_rd_addr_en, disp_rd_addr_valid, disp_rd_addr, disp_wr_dta_full);
|
557 |
|
|
$strobe("%m\tosd_rd_empty: %h osd_rd_en: %h osd_rd_valid: %h osd_rd_addr: %h osd_rd_dta: %h",
|
558 |
|
|
osd_rd_empty, osd_rd_en, osd_rd_valid, osd_rd_addr, osd_rd_dta);
|
559 |
|
|
$strobe("%m\tvbw_rd_empty: %h vbw_rd_en: %h vbw_rd_valid: %h vbw_rd_dta: %h vbr_wr_full: %h vbr_wr_almost_full: %h",
|
560 |
|
|
vbw_rd_empty, vbw_rd_en, vbw_rd_valid, vbw_rd_dta, vbr_wr_full, vbr_wr_almost_full);
|
561 |
|
|
$strobe("%m\tvbuf_wr_addr: %h vbuf_rd_addr: %h vbuf_full: %h vbuf_empty: %h next_vbuf_wr_addr: %h next_vbuf_rd_addr: %h",
|
562 |
|
|
vbuf_wr_addr, vbuf_rd_addr, vbuf_full, vbuf_empty, next_vbuf_wr_addr, next_vbuf_rd_addr);
|
563 |
|
|
$strobe("%m\tvbw_rd_empty: %h vbw_rd_en: %h vbw_rd_valid: %h vbw_rd_dta: %h vbuf_wr_addr: %h vbuf_rd_addr: %h vbuf_full: %h vbuf_empty: %h vbr_wr_full: %h vbr_wr_almost_full: %h",
|
564 |
|
|
vbw_rd_empty, vbw_rd_en, vbw_rd_valid, vbw_rd_dta, vbuf_wr_addr, vbuf_rd_addr, vbuf_full, vbuf_empty, vbr_wr_full, vbr_wr_almost_full);
|
565 |
|
|
$strobe("%m\tmem_req_wr_cmd: %h mem_req_wr_addr: %h mem_req_wr_dta: %h mem_req_wr_en: %h mem_req_wr_almost_full: %h",
|
566 |
|
|
mem_req_wr_cmd, mem_req_wr_addr, mem_req_wr_dta, mem_req_wr_en, mem_req_wr_almost_full);
|
567 |
|
|
$strobe("%m\ttag_wr_dta: %h tag_wr_en: %h tag_wr_almost_full: %h",
|
568 |
|
|
tag_wr_dta, tag_wr_en, tag_wr_almost_full);
|
569 |
|
|
end
|
570 |
|
|
`endif
|
571 |
|
|
endmodule
|
572 |
|
|
|
573 |
|
|
/* not truncated */
|