Rev 467 | Details | Compare with Previous | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 668 | lvd | 1 | // ZX-Evo Base Configuration (c) NedoPC 2008,2009,2010,2011,2012,2013,2014 |
| 4 | lvd | 2 | // |
| 3 | // DRAM arbiter. Shares DRAM between processor and video data fetcher |
||
| 467 | lvd | 4 | |
| 668 | lvd | 5 | /* |
| 6 | This file is part of ZX-Evo Base Configuration firmware. |
||
| 467 | lvd | 7 | |
| 668 | lvd | 8 | ZX-Evo Base Configuration firmware is free software: |
| 9 | you can redistribute it and/or modify it under the terms of |
||
| 10 | the GNU General Public License as published by |
||
| 11 | the Free Software Foundation, either version 3 of the License, or |
||
| 12 | (at your option) any later version. |
||
| 467 | lvd | 13 | |
| 668 | lvd | 14 | ZX-Evo Base Configuration firmware is distributed in the hope that |
| 15 | it will be useful, but WITHOUT ANY WARRANTY; without even |
||
| 16 | the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
||
| 17 | See the GNU General Public License for more details. |
||
| 467 | lvd | 18 | |
| 668 | lvd | 19 | You should have received a copy of the GNU General Public License |
| 20 | along with ZX-Evo Base Configuration firmware. |
||
| 21 | If not, see <http://www.gnu.org/licenses/>. |
||
| 22 | */ |
||
| 467 | lvd | 23 | |
| 668 | lvd | 24 | |
| 467 | lvd | 25 | // 14.06.2011: |
| 26 | // removed cpu_stall and cpu_waitcyc. |
||
| 27 | // changed cpu_strobe behavior (only strobes read data arrival now). |
||
| 28 | // added cpu_next signal (shows whether next DRAM cycle CAN be grabbed by CPU) |
||
| 29 | // |
||
| 30 | // Now it is a REQUIREMENT for 'go' signal only starting and ending on |
||
| 31 | // beginning of DRAM cycle (i.e. right after 'cend' strobe). |
||
| 32 | |||
| 33 | |||
| 34 | // 13.06.2011: |
||
| 668 | lvd | 35 | // Придётся потребовать, чтоб go устанавливался сразу после cend (у меня [lvd] это так). |
| 36 | // это для того, чтобы процессор на 14мгц мог заранее и в любой момент знать, на |
||
| 37 | // сколько завейтиться. Вместо cpu_ack введем другой сигнал, который в течение всего |
||
| 38 | // драм-цикла будет показывать, чей может быть следующий цикл - процессора или только |
||
| 39 | // видео. По сути это и будет также cpu_ack, но валидный в момент cpu_req (т.е. |
||
| 40 | // в момент cend) и ранее. |
||
| 467 | lvd | 41 | |
| 42 | // 12.06.2011: |
||
| 668 | lvd | 43 | // проблема: если цпу просит цикл чтения, а его дать не могут, |
| 44 | // то он должен держать cpu_req. однако, снять он его может |
||
| 45 | // только по cpu_strobe, при этом также отправится еще один |
||
| 46 | // запрос чтения!!! |
||
| 47 | // решение: добавить сигнал cpu_ack, по которому узнаётся, что |
||
| 48 | // арбитр зохавал запрос (записи или чтения), который будет |
||
| 49 | // совпадать с нынешним cpu_strobe на записи (cbeg), а будущий |
||
| 50 | // cpu_strobe сделать только как строб данных на зохаванном |
||
| 51 | // запросе чтеня. |
||
| 52 | // это, возможно, позволит удалить всякие cpu_waitcyc... |
||
| 467 | lvd | 53 | |
| 54 | |||
| 4 | lvd | 55 | // Arbitration is made on full 8-cycle access blocks. Each cycle is defined by dram.v and consists of 4 fpga clocks. |
| 56 | // During each access block, there can be either no videodata access, 1 videodata access, 2, 4 or full 8 accesses. |
||
| 57 | // All spare cycles can be used by processor. If nobody uses memory in the given cycle, refresh cycle is performed |
||
| 58 | // |
||
| 59 | // In each access block, videodata accesses are spreaded all over the block so that processor receives cycle |
||
| 60 | // as fast as possible, until there is absolute need to fetch remaining video data |
||
| 61 | // |
||
| 62 | // Examples: |
||
| 63 | // |
||
| 64 | // | access block | 4 video accesses during block, no processor accesses. video accesses are done |
||
| 65 | // | vid | vid | vid | vid | ref | ref | ref | ref | as soon as possible, spare cycles are refresh ones |
||
| 66 | // |
||
| 67 | // | access block | 4 video accesses during block, processor requests access every other cycle |
||
| 68 | // | vid | prc | vid | prc | vid | prc | vid | prc | |
||
| 69 | // |
||
| 70 | // | access block | 4 video accesses, processor begins requesting cycles continously from second one |
||
| 71 | // | vid | prc | prc | prc | prc | vid | vid | vid | so it is given cycles while there is such possibility. after that processor |
||
| 72 | // can't access mem until the end of access block and stalls |
||
| 73 | // |
||
| 74 | // | access block | 8 video accesses, processor stalls, if it is requesting cycles |
||
| 75 | // | vid | vid | vid | vid | vid | vid | vid | vid | |
||
| 76 | // |
||
| 77 | // | access block | 2 video accesses, single processor request, other cycles are refresh ones |
||
| 78 | // | vid | vid | ref | ref | cpu | ref | ref | ref | |
||
| 79 | // |
||
| 80 | // | access block | 4 video accesses, single processor request, other cycles are refresh ones |
||
| 81 | // | vid | vid | cpu | vid | vid | ref | ref | ref | |
||
| 82 | // |
||
| 83 | // access block begins at any dram cycle, then blocks go back-to-back |
||
| 84 | // |
||
| 85 | // key signals are go and cpu_req, sampled at the end of each dram cycle. Must be set to the module |
||
| 86 | // one clock cycle earlier the clock of the beginning current dram cycle |
||
| 87 | |||
| 668 | lvd | 88 | `include "../include/tune.v" |
| 89 | |||
| 4 | lvd | 90 | module arbiter( |
| 91 | |||
| 92 | input clk, |
||
| 93 | input rst_n, |
||
| 94 | |||
| 95 | // dram.v interface |
||
| 467 | lvd | 96 | output [20:0] dram_addr, // address for dram access |
| 97 | output reg dram_req, // dram request |
||
| 98 | output reg dram_rnw, // Read-NotWrite |
||
| 4 | lvd | 99 | input dram_cbeg, // cycle begin |
| 100 | input dram_rrdy, // read data ready (coincides with cend) |
||
| 101 | output [1:0] dram_bsel, // positive bytes select: bsel[1] for wrdata[15:8], bsel[0] for wrdata[7:0] |
||
| 102 | input [15:0] dram_rddata, // data just read |
||
| 103 | output [15:0] dram_wrdata, // data to be written |
||
| 104 | |||
| 105 | |||
| 106 | output reg cend, // regenerates this signal: end of DRAM cycle. cend is one-cycle positive pulse just before cbeg pulse |
||
| 107 | output reg pre_cend, // one clock earlier cend |
||
| 108 | output reg post_cbeg, // one more earlier |
||
| 109 | |||
| 110 | |||
| 111 | input go, // start video access blocks |
||
| 112 | |||
| 113 | input [1:0] bw, // required bandwidth: 3'b00 - 1 video cycle per block |
||
| 114 | // 3'b01 - 2 video accesses |
||
| 115 | // 3'b10 - 4 video accesses |
||
| 116 | // 3'b11 - 8 video accesses (stall of CPU) |
||
| 117 | |||
| 118 | input [20:0] video_addr, // during access block, only when video_strobe==1 |
||
| 119 | output [15:0] video_data, // read video data which is valid only during video_strobe==1 because video_data |
||
| 120 | // is just wires to the dram.v's rddata signals |
||
| 121 | output reg video_strobe, // positive one-cycle strobe as soon as there is next video_data available. |
||
| 122 | // if there is video_strobe, it coincides with cend signal |
||
| 123 | output reg video_next, // on this signal you can change video_addr; it is one clock leading the video_strobe |
||
| 124 | |||
| 125 | |||
| 126 | |||
| 467 | lvd | 127 | input wire cpu_req, |
| 128 | input wire cpu_rnw, |
||
| 129 | input wire [20:0] cpu_addr, |
||
| 130 | input wire [ 7:0] cpu_wrdata, |
||
| 131 | input wire cpu_wrbsel, |
||
| 4 | lvd | 132 | |
| 467 | lvd | 133 | output wire [15:0] cpu_rddata, |
| 134 | output reg cpu_next, |
||
| 135 | output reg cpu_strobe |
||
| 4 | lvd | 136 | ); |
| 137 | |||
| 138 | wire cbeg; |
||
| 139 | |||
| 140 | reg [1:0] cctr; // DRAM cycle counter: 0 when cbeg is 1, then 1,2,3,0, etc... |
||
| 141 | |||
| 142 | |||
| 467 | lvd | 143 | reg stall; |
| 144 | reg cpu_rnw_r; |
||
| 4 | lvd | 145 | |
| 146 | reg [2:0] blk_rem; // remaining accesses in a block (7..0) |
||
| 147 | reg [2:0] blk_nrem; // remaining for the next dram cycle |
||
| 148 | |||
| 149 | reg [2:0] vid_rem; // remaining video accesses in block (4..0) |
||
| 150 | reg [2:0] vid_nrem; // for rhe next cycle |
||
| 151 | |||
| 152 | |||
| 153 | wire [2:0] vidmax; // max number of video cycles in a block, depends on bw input |
||
| 154 | |||
| 155 | |||
| 156 | |||
| 157 | localparam CYC_VIDEO = 2'b00; // do there |
||
| 158 | localparam CYC_CPU = 2'b01; // not since are dependencies |
||
| 159 | localparam CYC_FREE = 2'b10; // alter bit |
||
| 160 | |||
| 161 | reg [1:0] curr_cycle; // type of the cycle in progress |
||
| 162 | reg [1:0] next_cycle; // type of the next cycle |
||
| 163 | |||
| 164 | |||
| 165 | |||
| 166 | |||
| 167 | |||
| 168 | initial // simulation only! |
||
| 169 | begin |
||
| 170 | curr_cycle = CYC_FREE; |
||
| 171 | blk_rem = 0; |
||
| 172 | vid_rem = 0; |
||
| 173 | end |
||
| 174 | |||
| 175 | |||
| 176 | |||
| 177 | |||
| 178 | assign cbeg = dram_cbeg; // just alias |
||
| 179 | |||
| 180 | // make cycle strobe signals |
||
| 181 | always @(posedge clk) |
||
| 182 | begin |
||
| 183 | post_cbeg <= cbeg; |
||
| 467 | lvd | 184 | pre_cend <= post_cbeg; |
| 185 | cend <= pre_cend; |
||
| 4 | lvd | 186 | end |
| 187 | |||
| 188 | |||
| 189 | // track blk_rem counter: how many cycles left to the end of block (7..0) |
||
| 190 | always @(posedge clk) if( cend ) |
||
| 191 | begin |
||
| 192 | blk_rem <= blk_nrem; |
||
| 193 | |||
| 194 | if( (blk_rem==3'd0) ) |
||
| 467 | lvd | 195 | stall <= (bw==2'd3) & go; |
| 4 | lvd | 196 | end |
| 197 | |||
| 198 | always @* |
||
| 199 | begin |
||
| 200 | if( (blk_rem==3'd0) && go ) |
||
| 201 | blk_nrem = 7; |
||
| 202 | else |
||
| 203 | blk_nrem = (blk_rem==0) ? 3'd0 : (blk_rem-3'd1); |
||
| 204 | end |
||
| 205 | |||
| 206 | |||
| 207 | |||
| 208 | // track vid_rem counter |
||
| 209 | assign vidmax = (3'b001) << bw; // 1,2,4 or 8 - just to know how many cycles to perform |
||
| 210 | |||
| 211 | always @(posedge clk) if( cend ) |
||
| 212 | begin |
||
| 213 | vid_rem <= vid_nrem; |
||
| 214 | end |
||
| 215 | |||
| 216 | always @* |
||
| 217 | begin |
||
| 218 | if( go && (blk_rem==3'd0) ) |
||
| 219 | vid_nrem = cpu_req ? vidmax : (vidmax-3'd1); |
||
| 220 | else |
||
| 221 | if( next_cycle==CYC_VIDEO ) |
||
| 222 | vid_nrem = (vid_rem==3'd0) ? 3'd0 : (vid_rem-3'd1); |
||
| 223 | else |
||
| 224 | vid_nrem = vid_rem; |
||
| 225 | end |
||
| 226 | |||
| 227 | |||
| 228 | |||
| 229 | |||
| 230 | // next cycle decision |
||
| 231 | always @* |
||
| 232 | begin |
||
| 233 | if( blk_rem==3'd0 ) |
||
| 234 | begin |
||
| 235 | if( go ) |
||
| 236 | begin |
||
| 237 | if( bw==2'b11 ) |
||
| 467 | lvd | 238 | begin |
| 239 | cpu_next = 1'b0; |
||
| 240 | |||
| 4 | lvd | 241 | next_cycle = CYC_VIDEO; |
| 467 | lvd | 242 | end |
| 4 | lvd | 243 | else |
| 467 | lvd | 244 | begin |
| 245 | cpu_next = 1'b1; |
||
| 246 | |||
| 4 | lvd | 247 | if( cpu_req ) |
| 248 | next_cycle = CYC_CPU; |
||
| 249 | else |
||
| 250 | next_cycle = CYC_VIDEO; |
||
| 467 | lvd | 251 | end |
| 4 | lvd | 252 | end |
| 253 | else // !go |
||
| 254 | begin |
||
| 467 | lvd | 255 | cpu_next = 1'b1; |
| 256 | |||
| 4 | lvd | 257 | if( cpu_req ) |
| 258 | next_cycle = CYC_CPU; |
||
| 259 | else |
||
| 260 | next_cycle = CYC_FREE; |
||
| 261 | end |
||
| 262 | end |
||
| 263 | else // blk_rem!=3'd0 |
||
| 264 | begin |
||
| 467 | lvd | 265 | if( stall ) |
| 266 | begin |
||
| 267 | cpu_next = 1'b0; |
||
| 268 | |||
| 4 | lvd | 269 | next_cycle = CYC_VIDEO; |
| 467 | lvd | 270 | end |
| 4 | lvd | 271 | else |
| 272 | begin |
||
| 273 | if( vid_rem==blk_rem ) |
||
| 467 | lvd | 274 | begin |
| 275 | cpu_next = 1'b0; |
||
| 276 | |||
| 4 | lvd | 277 | next_cycle = CYC_VIDEO; |
| 467 | lvd | 278 | end |
| 4 | lvd | 279 | else |
| 467 | lvd | 280 | begin |
| 281 | cpu_next = 1'b1; |
||
| 282 | |||
| 4 | lvd | 283 | if( cpu_req ) |
| 284 | next_cycle = CYC_CPU; |
||
| 285 | else |
||
| 286 | if( vid_rem==3'd0 ) |
||
| 287 | next_cycle = CYC_FREE; |
||
| 288 | else |
||
| 289 | next_cycle = CYC_VIDEO; |
||
| 467 | lvd | 290 | end |
| 4 | lvd | 291 | end |
| 292 | end |
||
| 293 | end |
||
| 294 | |||
| 295 | |||
| 296 | |||
| 467 | lvd | 297 | |
| 4 | lvd | 298 | // just current cycle register |
| 299 | always @(posedge clk) if( cend ) |
||
| 300 | begin |
||
| 301 | curr_cycle <= next_cycle; |
||
| 302 | end |
||
| 303 | |||
| 304 | |||
| 305 | |||
| 306 | |||
| 307 | // route required data/etc. to and from the dram.v |
||
| 308 | |||
| 309 | assign dram_wrdata[15:0] = { cpu_wrdata[7:0], cpu_wrdata[7:0] }; |
||
| 310 | assign dram_bsel[1:0] = { ~cpu_wrbsel, cpu_wrbsel }; |
||
| 311 | |||
| 312 | assign dram_addr = next_cycle[0] ? cpu_addr : video_addr; |
||
| 313 | |||
| 314 | assign cpu_rddata = dram_rddata; |
||
| 315 | assign video_data = dram_rddata; |
||
| 316 | |||
| 317 | always @* |
||
| 318 | begin |
||
| 319 | if( next_cycle[1] ) // CYC_FREE |
||
| 320 | begin |
||
| 321 | dram_req = 1'b0; |
||
| 322 | dram_rnw = 1'b1; |
||
| 323 | end |
||
| 324 | else // CYC_CPU or CYC_VIDEO |
||
| 325 | begin |
||
| 326 | dram_req = 1'b1; |
||
| 327 | if( next_cycle[0] ) // CYC_CPU |
||
| 328 | dram_rnw = cpu_rnw; |
||
| 329 | else // CYC_VIDEO |
||
| 330 | dram_rnw = 1'b1; |
||
| 331 | end |
||
| 332 | end |
||
| 333 | |||
| 334 | |||
| 335 | |||
| 467 | lvd | 336 | // generation of read strobes: for video and cpu |
| 4 | lvd | 337 | |
| 338 | |||
| 339 | always @(posedge clk) |
||
| 467 | lvd | 340 | if( cend ) |
| 341 | cpu_rnw_r <= cpu_rnw; |
||
| 342 | |||
| 343 | |||
| 344 | always @(posedge clk) |
||
| 4 | lvd | 345 | begin |
| 467 | lvd | 346 | if( (curr_cycle==CYC_CPU) && cpu_rnw_r && pre_cend ) |
| 4 | lvd | 347 | cpu_strobe <= 1'b1; |
| 348 | else |
||
| 349 | cpu_strobe <= 1'b0; |
||
| 467 | lvd | 350 | end |
| 4 | lvd | 351 | |
| 352 | |||
| 467 | lvd | 353 | always @(posedge clk) |
| 354 | begin |
||
| 4 | lvd | 355 | if( (curr_cycle==CYC_VIDEO) && pre_cend ) |
| 356 | video_strobe <= 1'b1; |
||
| 357 | else |
||
| 358 | video_strobe <= 1'b0; |
||
| 359 | |||
| 360 | if( (curr_cycle==CYC_VIDEO) && post_cbeg ) |
||
| 361 | video_next <= 1'b1; |
||
| 362 | else |
||
| 363 | video_next <= 1'b0; |
||
| 364 | end |
||
| 365 | |||
| 366 | |||
| 367 | |||
| 368 | endmodule |
||
| 369 |