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 |