Subversion Repositories pentevo

Rev

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