| 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 */
|