Rev 951 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
29 | lvd | 1 | // simulate fpga top-level with external dram, rom, z80 |
722 | lvd | 2 | // (c) 2010-2016 NedoPC |
29 | lvd | 3 | |
4 | `include "../include/tune.v" |
||
5 | |||
31 | lvd | 6 | |
467 | lvd | 7 | |
8 | //`define ZLOG 1 |
||
9 | |||
10 | |||
11 | |||
29 | lvd | 12 | `define HALF_CLK_PERIOD (17.8) |
13 | |||
37 | lvd | 14 | `define ZCLK_DELAY (9.5) |
34 | lvd | 15 | |
16 | // toshibo |
||
37 | lvd | 17 | //`define Z80_DELAY_DOWN (17.0) |
18 | //`define Z80_DELAY_UP (22.0) |
||
33 | lvd | 19 | |
34 | lvd | 20 | // z0840008 |
37 | lvd | 21 | `define Z80_DELAY_DOWN 34 |
22 | `define Z80_DELAY_UP 30 |
||
33 | lvd | 23 | |
29 | lvd | 24 | module tb; |
25 | |||
26 | reg fclk; |
||
27 | |||
28 | wire clkz_out,clkz_in; |
||
29 | |||
30 | reg iorq_n,mreq_n,rd_n,wr_n; // has some delays relative to z*_n (below) |
||
31 | reg m1_n,rfsh_n; // |
||
32 | |||
425 | lvd | 33 | wire res; // |
29 | lvd | 34 | tri1 ziorq_n,zmreq_n,zrd_n,zwr_n,zm1_n,zrfsh_n; // connected to Z80 |
35 | |||
425 | lvd | 36 | tri1 int_n,wait_n,nmi_n; |
37 | wire zint_n,zwait_n,znmi_n; |
||
200 | lvd | 38 | |
467 | lvd | 39 | wire [15:0] #((`Z80_DELAY_DOWN+`Z80_DELAY_UP)/2) za; |
40 | wire [ 7:0] #((`Z80_DELAY_DOWN+`Z80_DELAY_UP)/2) zd; |
||
29 | lvd | 41 | |
684 | lvd | 42 | tri1 [ 7:0] zd_dut_to_z80; |
29 | lvd | 43 | |
467 | lvd | 44 | |
684 | lvd | 45 | reg [15:0] reset_pc = 16'h0000; |
46 | reg [15:0] reset_sp = 16'hFFFF; |
||
47 | |||
48 | |||
49 | |||
29 | lvd | 50 | wire csrom, romoe_n, romwe_n; |
200 | lvd | 51 | wire rompg0_n, dos_n; |
425 | lvd | 52 | wire rompg2,rompg3,rompg4; |
29 | lvd | 53 | |
54 | wire [15:0] rd; |
||
55 | wire [9:0] ra; |
||
56 | wire rwe_n,rucas_n,rlcas_n,rras0_n,rras1_n; |
||
57 | |||
58 | |||
941 | lvd | 59 | tri1 [15:0] ide_d; |
29 | lvd | 60 | |
61 | |||
425 | lvd | 62 | wire hsync,vsync; |
63 | wire [1:0] red,grn,blu; |
||
29 | lvd | 64 | |
425 | lvd | 65 | |
66 | |||
543 | lvd | 67 | // sdcard |
68 | wire sdcs_n, sddo, sddi, sdclk; |
||
425 | lvd | 69 | |
543 | lvd | 70 | // avr |
71 | wire spick, spidi, spido, spics_n; |
||
72 | |||
73 | |||
74 | |||
75 | |||
280 | lvd | 76 | assign zwait_n = (wait_n==1'b0) ? 1'b0 : 1'b1; |
77 | assign znmi_n = (nmi_n==1'b0) ? 1'b0 : 1'b1; |
||
425 | lvd | 78 | assign zint_n = (int_n==1'b0) ? 1'b0 : 1'b1; |
280 | lvd | 79 | |
80 | |||
81 | |||
425 | lvd | 82 | |
83 | |||
84 | |||
29 | lvd | 85 | initial |
86 | begin |
||
87 | |||
88 | fclk = 1'b0; |
||
89 | |||
90 | forever #`HALF_CLK_PERIOD fclk = ~fclk; |
||
91 | end |
||
92 | |||
93 | |||
200 | lvd | 94 | assign #`ZCLK_DELAY clkz_in = ~clkz_out; |
29 | lvd | 95 | |
96 | |||
97 | |||
98 | |||
99 | |||
100 | |||
101 | |||
102 | top DUT( .fclk(fclk), |
||
103 | .clkz_out(clkz_out), |
||
104 | .clkz_in(clkz_in), |
||
105 | |||
106 | // z80 |
||
107 | .iorq_n(iorq_n), |
||
108 | .mreq_n(mreq_n), |
||
109 | .rd_n(rd_n), |
||
110 | .wr_n(wr_n), |
||
111 | .m1_n(m1_n), |
||
112 | .rfsh_n(rfsh_n), |
||
113 | .int_n(int_n), |
||
114 | .nmi_n(nmi_n), |
||
115 | .wait_n(wait_n), |
||
116 | .res(res), |
||
117 | // |
||
118 | .d(zd), |
||
119 | .a(za), |
||
120 | |||
121 | // ROM |
||
122 | .csrom(csrom), |
||
123 | .romoe_n(romoe_n), |
||
124 | .romwe_n(romwe_n), |
||
200 | lvd | 125 | .rompg0_n(rompg0_n), |
126 | .dos_n(dos_n), |
||
425 | lvd | 127 | .rompg2(rompg2), |
128 | .rompg3(rompg3), |
||
129 | .rompg4(rompg4), |
||
29 | lvd | 130 | |
131 | // DRAM |
||
132 | .rd(rd), |
||
133 | .ra(ra), |
||
134 | .rwe_n(rwe_n), |
||
135 | .rucas_n(rucas_n), |
||
136 | .rlcas_n(rlcas_n), |
||
137 | .rras0_n(rras0_n), |
||
138 | .rras1_n(rras1_n), |
||
139 | |||
140 | // ZX-bus |
||
141 | .iorqge1(1'b0), |
||
142 | .iorqge2(1'b0), |
||
143 | |||
144 | // IDE |
||
145 | .ide_d(ide_d), |
||
146 | .ide_rdy(1'b1), |
||
147 | |||
148 | // VG93 |
||
149 | .step(1'b0), |
||
150 | .vg_sl(1'b0), |
||
151 | .vg_sr(1'b0), |
||
152 | .vg_tr43(1'b0), |
||
153 | .rdat_b_n(1'b1), |
||
154 | .vg_wf_de(1'b0), |
||
155 | .vg_drq(1'b1), |
||
156 | .vg_irq(1'b1), |
||
157 | .vg_wd(1'b0), |
||
158 | |||
159 | // SDcard SPI |
||
543 | lvd | 160 | .sddi(sddi), |
161 | .sddo(sddo), |
||
162 | .sdcs_n(sdcs_n), |
||
163 | .sdclk(sdclk), |
||
29 | lvd | 164 | |
165 | // ATmega SPI |
||
543 | lvd | 166 | .spics_n(spics_n), |
167 | .spick(spick), |
||
168 | .spido(spido), |
||
169 | .spidi(spidi), |
||
29 | lvd | 170 | |
425 | lvd | 171 | .vhsync(hsync), |
172 | .vvsync(vsync), |
||
173 | .vred(red), |
||
174 | .vgrn(grn), |
||
175 | .vblu(blu) |
||
176 | |||
29 | lvd | 177 | ); |
178 | |||
179 | |||
467 | lvd | 180 | |
181 | |||
722 | lvd | 182 | // assign zd_dut_to_z80 = tb.DUT.ena_ram ? tb.DUT.dout_ram : ( tb.DUT.ena_ports ? tb.DUT.dout_ports : ( tb.DUT.drive_ff ? 8'hFF : 8'bZZZZZZZZ ) ); |
183 | assign zd_dut_to_z80 = tb.DUT.d_ena ? tb.DUT.d_pre_out : 8'bZZZZ_ZZZZ; |
||
467 | lvd | 184 | |
185 | |||
186 | |||
187 | |||
29 | lvd | 188 | wire zrst_n = ~res; |
189 | |||
190 | T80a z80( .RESET_n(zrst_n), |
||
191 | .CLK_n(clkz_in), |
||
280 | lvd | 192 | .WAIT_n(zwait_n), |
425 | lvd | 193 | .INT_n(zint_n), |
280 | lvd | 194 | .NMI_n(znmi_n), |
29 | lvd | 195 | .M1_n(zm1_n), |
196 | .RFSH_n(zrfsh_n), |
||
197 | .MREQ_n(zmreq_n), |
||
198 | .IORQ_n(ziorq_n), |
||
199 | .RD_n(zrd_n), |
||
200 | .WR_n(zwr_n), |
||
201 | .BUSRQ_n(1'b1), |
||
202 | .A(za), |
||
467 | lvd | 203 | .D_I(zd_dut_to_z80), |
684 | lvd | 204 | .D_O(zd), |
205 | .ResetPC(reset_pc), |
||
206 | .ResetSP(reset_sp) |
||
29 | lvd | 207 | ); |
208 | |||
209 | // now make delayed versions of signals |
||
210 | // |
||
280 | lvd | 211 | reg mreq_wr_n; |
212 | wire iorq_wr_n, full_wr_n; |
||
213 | // |
||
214 | // first, assure there is no X's at the start |
||
215 | // |
||
216 | initial |
||
217 | begin |
||
218 | m1_n = 1'b1; |
||
219 | rfsh_n = 1'b1; |
||
220 | mreq_n = 1'b1; |
||
221 | iorq_n = 1'b1; |
||
222 | rd_n = 1'b1; |
||
223 | wr_n = 1'b1; |
||
224 | mreq_wr_n = 1'b1; |
||
225 | end |
||
226 | // |
||
29 | lvd | 227 | always @(zm1_n) |
228 | if( zm1_n ) |
||
229 | m1_n <= #`Z80_DELAY_UP zm1_n; |
||
230 | else |
||
231 | m1_n <= #`Z80_DELAY_DOWN zm1_n; |
||
232 | // |
||
233 | always @(zrfsh_n) |
||
234 | if( zrfsh_n ) |
||
235 | rfsh_n <= #`Z80_DELAY_UP zrfsh_n; |
||
236 | else |
||
237 | rfsh_n <= #`Z80_DELAY_DOWN zrfsh_n; |
||
238 | // |
||
239 | always @(zmreq_n) |
||
240 | if( zmreq_n ) |
||
241 | mreq_n <= #`Z80_DELAY_UP zmreq_n; |
||
242 | else |
||
243 | mreq_n <= #`Z80_DELAY_DOWN zmreq_n; |
||
244 | // |
||
245 | always @(ziorq_n) |
||
246 | if( ziorq_n ) |
||
247 | iorq_n <= #`Z80_DELAY_UP ziorq_n; |
||
248 | else |
||
249 | iorq_n <= #`Z80_DELAY_DOWN ziorq_n; |
||
250 | // |
||
251 | always @(zrd_n) |
||
252 | if( zrd_n ) |
||
253 | rd_n <= #`Z80_DELAY_UP zrd_n; |
||
254 | else |
||
255 | rd_n <= #`Z80_DELAY_DOWN zrd_n; |
||
256 | // |
||
280 | lvd | 257 | // |
258 | // special handling for broken T80 WR_n |
||
511 | lvd | 259 | // |
29 | lvd | 260 | always @(negedge clkz_in) |
280 | lvd | 261 | mreq_wr_n <= zwr_n; |
262 | // |
||
263 | assign iorq_wr_n = ziorq_n | (~zrd_n) | (~zm1_n); |
||
264 | // |
||
265 | assign full_wr_n = mreq_wr_n & iorq_wr_n; |
||
266 | // |
||
267 | // this way glitches won't affect state of wr_n |
||
268 | always @(full_wr_n) |
||
269 | if( !full_wr_n ) |
||
270 | #`Z80_DELAY_DOWN wr_n <= full_wr_n; |
||
29 | lvd | 271 | else |
280 | lvd | 272 | #`Z80_DELAY_UP wr_n <= full_wr_n; |
29 | lvd | 273 | |
274 | |||
280 | lvd | 275 | |
276 | |||
277 | |||
29 | lvd | 278 | // ROM model |
279 | rom romko( |
||
425 | lvd | 280 | .addr( {rompg4,rompg3,rompg2,dos_n, (~rompg0_n), za[13:0]} ), |
467 | lvd | 281 | .data(zd_dut_to_z80), |
29 | lvd | 282 | .ce_n( romoe_n | (~csrom) ) |
283 | ); |
||
284 | |||
285 | // DRAM model |
||
286 | drammem dramko1( |
||
287 | .ma(ra), |
||
288 | .d(rd), |
||
289 | .ras_n(rras0_n), |
||
290 | .ucas_n(rucas_n), |
||
291 | .lcas_n(rlcas_n), |
||
292 | .we_n(rwe_n) |
||
293 | ); |
||
294 | // |
||
295 | drammem dramko2( |
||
296 | .ma(ra), |
||
297 | .d(rd), |
||
298 | .ras_n(rras1_n), |
||
299 | .ucas_n(rucas_n), |
||
300 | .lcas_n(rlcas_n), |
||
301 | .we_n(rwe_n) |
||
302 | ); |
||
303 | defparam dramko1._verbose_ = 0; |
||
304 | defparam dramko2._verbose_ = 0; |
||
305 | |||
510 | lvd | 306 | defparam dramko1._init_ = 0; |
307 | defparam dramko2._init_ = 0; |
||
29 | lvd | 308 | |
309 | |||
510 | lvd | 310 | |
280 | lvd | 311 | `ifndef GATE |
200 | lvd | 312 | |
313 | // trace rom page |
||
314 | wire rma14,rma15; |
||
315 | |||
316 | assign rma14 = DUT.page[0][0]; |
||
317 | assign rma15 = DUT.page[0][1]; |
||
318 | |||
319 | |||
320 | always @(rma14 or rma15) |
||
321 | begin |
||
467 | lvd | 322 | // $display("at time %t us",$time/1000000); |
200 | lvd | 323 | |
467 | lvd | 324 | // case( {rma15, rma14} ) |
200 | lvd | 325 | |
467 | lvd | 326 | // 2'b00: $display("BASIC 48"); |
327 | // 2'b01: $display("TR-DOS"); |
||
328 | // 2'b10: $display("BASIC 128"); |
||
329 | // 2'b11: $display("GLUKROM"); |
||
330 | // default: $display("unknown"); |
||
200 | lvd | 331 | |
467 | lvd | 332 | // endcase |
200 | lvd | 333 | |
467 | lvd | 334 | // $display(""); |
200 | lvd | 335 | end |
336 | |||
337 | |||
338 | // trace ram page |
||
339 | wire [5:0] rpag; |
||
340 | |||
341 | assign rpag=DUT.page[3][5:0]; |
||
342 | |||
343 | always @(rpag) |
||
344 | begin |
||
467 | lvd | 345 | // $display("at time %t us",$time/1000000); |
200 | lvd | 346 | |
467 | lvd | 347 | // $display("RAM page is %d",rpag); |
200 | lvd | 348 | |
467 | lvd | 349 | // $display(""); |
200 | lvd | 350 | end |
351 | |||
352 | |||
353 | |||
425 | lvd | 354 | // key presses/nmi/whatsoever |
200 | lvd | 355 | initial |
356 | begin |
||
425 | lvd | 357 | #1; |
200 | lvd | 358 | tb.DUT.zkbdmus.kbd = 40'd0; |
425 | lvd | 359 | tb.DUT.zkbdmus.kbd[36] = 1'b1; |
360 | @(negedge int_n); |
||
469 | lvd | 361 | @(negedge int_n); |
425 | lvd | 362 | tb.DUT.zkbdmus.kbd[36] = 1'b0; |
363 | end |
||
364 | |||
467 | lvd | 365 | `endif |
366 | |||
367 | |||
368 | |||
369 | |||
370 | |||
371 | |||
372 | |||
373 | |||
374 | `ifdef ZLOG |
||
375 | reg [ 7:0] old_opcode; |
||
376 | reg [15:0] old_opcode_addr; |
||
377 | |||
378 | wire [7:0] zdd = zd_dut_to_z80; |
||
379 | |||
380 | reg was_m1; |
||
381 | |||
382 | always @(zm1_n) |
||
383 | if( zm1_n ) |
||
384 | was_m1 <= 1'b0; |
||
511 | lvd | 385 | else |
467 | lvd | 386 | was_m1 = 1'b1; |
387 | |||
388 | always @(posedge (zmreq_n | zrd_n | zm1_n | (~zrfsh_n)) ) |
||
389 | if( was_m1 ) |
||
390 | begin |
||
391 | if( (zdd!==old_opcode) || (za!==old_opcode_addr) ) |
||
511 | lvd | 392 | begin |
467 | lvd | 393 | if( tb.DUT.z80mem.romnram ) |
394 | // $display("Z80OPROM: addr %x, opcode %x, time %t",za,zdd,$time); |
||
395 | $display("Z80OPROM: addr %x, opcode %x",za,zdd); |
||
396 | else |
||
397 | // $display("Z80OPRAM: addr %x, opcode %x, time %t",za,zdd,$time); |
||
398 | $display("Z80OPRAM: addr %x, opcode %x",za,zdd); |
||
399 | end |
||
400 | |||
401 | old_opcode = zdd; |
||
402 | old_opcode_addr = za; |
||
200 | lvd | 403 | end |
467 | lvd | 404 | |
405 | always @(posedge (zmreq_n | zrd_n | (~zm1_n) | (~zrfsh_n)) ) |
||
406 | if( !was_m1 ) |
||
407 | begin |
||
408 | if( tb.DUT.z80mem.romnram ) |
||
409 | // $display("Z80RDROM: addr %x, rddata %x, time %t",za,zdd,$time); |
||
410 | $display("Z80RDROM: addr %x, rddata %x",za,zdd); |
||
411 | else |
||
412 | // $display("Z80RDRAM: addr %x, rddata %x, time %t",za,zdd,$time); |
||
413 | $display("Z80RDRAM: addr %x, rddata %x",za,zdd); |
||
414 | end |
||
415 | |||
416 | always @(posedge (zmreq_n | zwr_n | (~zm1_n) | (~zrfsh_n)) ) |
||
417 | begin |
||
418 | if( tb.DUT.z80mem.romnram ) |
||
419 | // $display("Z80WRROM: addr %x, wrdata %x, time %t",za,zd,$time); |
||
420 | $display("Z80WRROM: addr %x, wrdata %x",za,zd); |
||
421 | else |
||
422 | // $display("Z80WRRAM: addr %x, wrdata %x, time %t",za,zd,$time); |
||
423 | $display("Z80WRRAM: addr %x, wrdata %x",za,zd); |
||
424 | end |
||
425 | lvd | 425 | `endif |
200 | lvd | 426 | |
427 | |||
428 | |||
429 | |||
467 | lvd | 430 | // turbo |
431 | `ifdef C7MHZ |
||
432 | initial |
||
433 | force tb.DUT.zclock.turbo = 2'b01; |
||
434 | `else |
||
435 | `ifdef C35MHZ |
||
200 | lvd | 436 | |
467 | lvd | 437 | initial |
438 | force tb.DUT.zclock.turbo = 2'b00; |
||
425 | lvd | 439 | |
467 | lvd | 440 | `endif |
441 | `endif |
||
425 | lvd | 442 | |
443 | |||
684 | lvd | 444 | // raster type |
445 | `ifdef CCONTEND |
||
446 | initial |
||
447 | force tb.DUT.modes_raster = 2'b10; |
||
448 | `endif |
||
425 | lvd | 449 | |
467 | lvd | 450 | |
451 | |||
684 | lvd | 452 | |
721 | lvd | 453 | `ifdef NMITEST2 |
454 | `define M48K |
||
455 | |||
456 | initial |
||
457 | begin |
||
458 | int i,fd; |
||
459 | logic [7:0] ldbyte; |
||
460 | |||
727 | lvd | 461 | reset_pc=16'h8000; |
721 | lvd | 462 | reset_sp=16'h8000; |
463 | |||
464 | fd = $fopen("dimkanmi.bin","rb"); |
||
465 | if( !fd ) |
||
466 | begin |
||
467 | $display("Can't open 'dimkanmi.bin'!"); |
||
468 | $stop; |
||
469 | end |
||
470 | |||
727 | lvd | 471 | i='h8000; |
721 | lvd | 472 | |
473 | begin : load_loop |
||
474 | while(1) |
||
475 | begin |
||
476 | if( 1!=$fread(ldbyte,fd) ) disable load_loop; |
||
477 | put_byte_48k(i,ldbyte); |
||
478 | i=i+1; |
||
479 | end |
||
480 | end |
||
481 | $fclose(fd); |
||
722 | lvd | 482 | |
737 | lvd | 483 | |
484 | wait(res===1'b0); |
||
485 | #(0.2); |
||
738 | lvd | 486 | tb.DUT.zports.atm_turbo = 1'b1; |
737 | lvd | 487 | tb.DUT.zports.peff7_int[4] = 1'b0; |
488 | |||
489 | |||
722 | lvd | 490 | #(100000); // 100 us |
491 | |||
492 | //force nmi_n = 1'b0; |
||
493 | @(posedge fclk); |
||
494 | force tb.DUT.imm_nmi = 1'b1; |
||
495 | @(posedge fclk); |
||
496 | release tb.DUT.imm_nmi; |
||
721 | lvd | 497 | end |
738 | lvd | 498 | `endif |
721 | lvd | 499 | |
738 | lvd | 500 | |
501 | |||
502 | `ifdef NMITEST3 |
||
503 | `define M48K |
||
504 | |||
505 | initial |
||
506 | begin |
||
507 | int i,fd; |
||
508 | logic [7:0] ldbyte; |
||
509 | |||
510 | reset_pc=16'h0068; |
||
511 | reset_sp=16'h8000; |
||
512 | |||
513 | |||
514 | #(0.1); // let M48K rom load execute |
||
515 | |||
516 | fd = $fopen("dimkarom.bin","rb"); |
||
517 | if( !fd ) |
||
518 | begin |
||
519 | $display("Can't open 'dimkarom.bin'!"); |
||
520 | $stop; |
||
521 | end |
||
522 | |||
523 | i='h0066; |
||
524 | begin : load_loop |
||
525 | while(1) |
||
526 | begin |
||
527 | if( 1!=$fread(ldbyte,fd) ) disable load_loop; |
||
528 | tb.romko.zxevo_rom.mem[i]=ldbyte; |
||
529 | i=i+1; |
||
530 | end |
||
531 | end |
||
532 | $fclose(fd); |
||
533 | |||
534 | |||
535 | wait(res===1'b0); |
||
536 | #(0.2); |
||
537 | tb.DUT.zports.atm_turbo = 1'b1; |
||
538 | tb.DUT.zports.peff7_int[4] = 1'b0; |
||
539 | |||
540 | |||
541 | #(1000000); // 1 ms |
||
542 | |||
543 | //force nmi_n = 1'b0; |
||
544 | @(posedge fclk); |
||
545 | force tb.DUT.imm_nmi = 1'b1; |
||
546 | @(posedge fclk); |
||
547 | release tb.DUT.imm_nmi; |
||
548 | end |
||
549 | `endif |
||
550 | |||
551 | |||
727 | lvd | 552 | // port #FE monitor |
553 | wire fe_write; |
||
554 | assign fe_write = (za[7:0]==8'hFE) && !wr_n && !iorq_n; |
||
555 | always @(negedge fe_write) |
||
737 | lvd | 556 | $display("port #FE monitor: border is %d at %t",zd[2:0],$time()); |
557 | always @(negedge nmi_n) |
||
558 | $display("nmi monitor: negative edge at %t",$time()); |
||
721 | lvd | 559 | |
560 | |||
737 | lvd | 561 | |
721 | lvd | 562 | |
684 | lvd | 563 | // start in 48k mode |
564 | `ifdef M48K |
||
565 | initial |
||
566 | begin : force_48k_mode |
||
567 | |||
568 | int i; |
||
569 | int fd; |
||
715 | lvd | 570 | |
738 | lvd | 571 | fd = $fopen("48.rom","rb"); |
572 | if( 16384!=$fread(tb.romko.zxevo_rom.mem,fd) ) |
||
573 | begin |
||
574 | $display("Couldn't load 48k ROM!\n"); |
||
575 | $stop; |
||
576 | end |
||
577 | $fclose(fd); |
||
578 | |||
579 | |||
715 | lvd | 580 | wait(res===1'b0); |
581 | #(0.1); |
||
684 | lvd | 582 | |
715 | lvd | 583 | tb.DUT.zports.atm_turbo = 1'b0; |
584 | tb.DUT.zports.atm_pen = 1'b0; |
||
585 | tb.DUT.zports.atm_cpm_n = 1'b1; |
||
586 | tb.DUT.zports.atm_pen2 = 1'b0; |
||
587 | |||
588 | tb.DUT.zdos.dos = 1'b0; |
||
589 | |||
590 | |||
720 | lvd | 591 | tb.DUT.instantiate_atm_pagers[0].atm_pager.pages[0] = 'd0; |
592 | tb.DUT.instantiate_atm_pagers[1].atm_pager.pages[0] = 'd5; |
||
593 | tb.DUT.instantiate_atm_pagers[2].atm_pager.pages[0] = 'd2; |
||
594 | tb.DUT.instantiate_atm_pagers[3].atm_pager.pages[0] = 'd0; |
||
595 | tb.DUT.instantiate_atm_pagers[0].atm_pager.pages[1] = 'd0; |
||
596 | tb.DUT.instantiate_atm_pagers[1].atm_pager.pages[1] = 'd5; |
||
597 | tb.DUT.instantiate_atm_pagers[2].atm_pager.pages[1] = 'd2; |
||
598 | tb.DUT.instantiate_atm_pagers[3].atm_pager.pages[1] = 'd0; |
||
599 | |||
600 | tb.DUT.instantiate_atm_pagers[0].atm_pager.ramnrom[0] = 'd0; |
||
601 | tb.DUT.instantiate_atm_pagers[1].atm_pager.ramnrom[0] = 'd1; |
||
602 | tb.DUT.instantiate_atm_pagers[2].atm_pager.ramnrom[0] = 'd1; |
||
603 | tb.DUT.instantiate_atm_pagers[3].atm_pager.ramnrom[0] = 'd1; |
||
604 | tb.DUT.instantiate_atm_pagers[0].atm_pager.ramnrom[1] = 'd0; |
||
605 | tb.DUT.instantiate_atm_pagers[1].atm_pager.ramnrom[1] = 'd1; |
||
606 | tb.DUT.instantiate_atm_pagers[2].atm_pager.ramnrom[1] = 'd1; |
||
607 | tb.DUT.instantiate_atm_pagers[3].atm_pager.ramnrom[1] = 'd1; |
||
608 | |||
715 | lvd | 609 | tb.DUT.zports.atm_scr_mode = 3'b011; |
684 | lvd | 610 | |
720 | lvd | 611 | tb.DUT.zports.peff7_int = 8'h14; |
612 | tb.DUT.zports.p7ffd_int = 8'h30; |
||
715 | lvd | 613 | |
720 | lvd | 614 | |
615 | |||
684 | lvd | 616 | for(i=0;i<512;i=i+1) |
617 | begin : set_palette // R G B |
||
618 | tb.DUT.video_top.video_palframe.palette[i] = { (i[1]?{1'b1,i[3]}:2'b00), 1'b0, (i[2]?{1'b1,i[3]}:2'b00), 1'b0, (i[0]?{1'b1,i[3]}:2'b00) }; |
||
619 | end |
||
620 | |||
621 | end |
||
622 | `endif |
||
623 | |||
624 | |||
625 | // load and start some code after we've reached "1982 Sinclair research ltd" |
||
626 | `ifdef START_LOAD |
||
627 | initial |
||
628 | begin |
||
629 | int i,fd; |
||
630 | logic [7:0] ldbyte; |
||
631 | |||
632 | wait( za==16'h15e0 && zmreq_n==1'b0 && zrd_n == 1'b0 ); |
||
633 | |||
634 | $display("loading and starting..."); |
||
635 | |||
636 | fd = $fopen(`START_NAME,"rb"); |
||
637 | for(i=`START_ADDR;i<`START_ADDR+`START_LEN;i=i+1) |
||
638 | begin |
||
639 | if( 1!=$fread(ldbyte,fd) ) |
||
640 | begin |
||
641 | $display("can't read byte from input file!"); |
||
642 | $stop; |
||
643 | end |
||
644 | |||
645 | put_byte_48k(i,ldbyte); |
||
646 | end |
||
647 | $fclose(fd); |
||
648 | |||
649 | $display("load ok!"); |
||
650 | |||
651 | reset_pc = 16'h9718; |
||
652 | reset_sp = 16'h6000; |
||
653 | @(posedge clkz_in); |
||
654 | force tb.zrst_n = 1'b0; |
||
655 | repeat(3) @(posedge clkz_in); |
||
656 | release tb.zrst_n; |
||
657 | @(posedge clkz_in); |
||
658 | reset_pc = 16'h0000; |
||
659 | reset_sp = 16'hFFFF; |
||
660 | end |
||
661 | `endif |
||
662 | |||
663 | |||
664 | |||
665 | |||
666 | |||
667 | |||
668 | |||
669 | |||
670 | |||
671 | |||
467 | lvd | 672 | |
673 | |||
674 | |||
511 | lvd | 675 | `ifndef NO_PIXER |
425 | lvd | 676 | // picture out |
677 | pixer pixer |
||
678 | ( |
||
679 | .clk(fclk), |
||
680 | |||
681 | .vsync(vsync), |
||
682 | .hsync(hsync), |
||
683 | .red(red), |
||
684 | .grn(grn), |
||
685 | .blu(blu) |
||
686 | ); |
||
511 | lvd | 687 | `endif |
425 | lvd | 688 | |
689 | |||
510 | lvd | 690 | /* |
280 | lvd | 691 | // time ticks |
692 | always |
||
693 | begin : timemark |
||
200 | lvd | 694 | |
280 | lvd | 695 | integer ms; |
696 | |||
697 | ms = ($time/1000000); |
||
698 | |||
467 | lvd | 699 | // $display("timemark %d ms",ms); |
280 | lvd | 700 | |
701 | #10000000.0; // 1 ms |
||
702 | end |
||
510 | lvd | 703 | */ |
280 | lvd | 704 | |
705 | |||
510 | lvd | 706 | // init dram |
721 | lvd | 707 | `ifndef NMITEST2 |
510 | lvd | 708 | initial |
511 | lvd | 709 | begin : init_dram |
510 | lvd | 710 | integer i; |
941 | lvd | 711 | |
712 | integer page; |
||
713 | integer offset; |
||
714 | |||
715 | reg [7:0] trd [0:655359]; |
||
280 | lvd | 716 | |
941 | lvd | 717 | integer fd; |
942 | lvd | 718 | integer size; |
941 | lvd | 719 | |
720 | |||
721 | |||
722 | |||
510 | lvd | 723 | for(i=0;i<4*1024*1024;i=i+1) |
724 | begin |
||
725 | put_byte(i,(i%257)); |
||
726 | end |
||
941 | lvd | 727 | |
728 | // load TRD |
||
729 | fd = $fopen("boot.trd","rb"); |
||
942 | lvd | 730 | size=$fread(trd,fd); |
941 | lvd | 731 | |
942 | lvd | 732 | if( size>655360 || size<=0 ) |
941 | lvd | 733 | begin |
942 | lvd | 734 | $display("Couldn't load or wrong boot.trd!\n"); |
941 | lvd | 735 | $stop; |
736 | end |
||
942 | lvd | 737 | $fclose(fd); |
941 | lvd | 738 | |
942 | lvd | 739 | |
941 | lvd | 740 | // copy TRD to RAM |
942 | lvd | 741 | page = 32'h0F4; |
941 | lvd | 742 | offset = 0; |
743 | |||
942 | lvd | 744 | for(i=0;i<size;i=i+1) |
941 | lvd | 745 | begin |
746 | put_byte( .addr(page*16384+offset), .data(trd[i]) ); |
||
747 | |||
748 | offset = offset + 1; |
||
749 | if( offset>=16384 ) |
||
750 | begin |
||
751 | offset = 0; |
||
752 | page = page - 1; |
||
753 | end |
||
754 | end |
||
942 | lvd | 755 | |
941 | lvd | 756 | |
942 | lvd | 757 | $display("boot.trd loaded!\n"); |
510 | lvd | 758 | end |
721 | lvd | 759 | `endif |
280 | lvd | 760 | |
761 | |||
762 | |||
763 | |||
425 | lvd | 764 | |
684 | lvd | 765 | // cmos simulation |
766 | wire [7:0] cmos_addr; |
||
767 | wire [7:0] cmos_read; |
||
768 | wire [7:0] cmos_write; |
||
769 | wire cmos_rnw; |
||
770 | wire cmos_req; |
||
771 | |||
772 | cmosemu cmosemu |
||
773 | ( |
||
774 | .zclk(clkz_in), |
||
775 | |||
776 | .cmos_req (cmos_req ), |
||
777 | .cmos_addr (cmos_addr ), |
||
778 | .cmos_rnw (cmos_rnw ), |
||
779 | .cmos_read (cmos_read ), |
||
780 | .cmos_write(cmos_write) |
||
781 | ); |
||
782 | |||
783 | assign cmos_req = tb.DUT.wait_start_gluclock; |
||
784 | assign cmos_rnw = tb.DUT.wait_rnw; |
||
785 | assign cmos_addr = tb.DUT.gluclock_addr; |
||
786 | assign cmos_write = tb.DUT.wait_write; |
||
787 | |||
788 | always @* |
||
789 | force tb.DUT.wait_read = cmos_read; |
||
790 | |||
791 | |||
792 | |||
793 | |||
543 | lvd | 794 | `ifdef SPITEST |
795 | // spitest printing module |
||
796 | // does not hurt at any time (yet), so attached forever |
||
510 | lvd | 797 | |
543 | lvd | 798 | spitest_print spitest_print( |
799 | .sdclk (sdclk ), |
||
800 | .sddi (sddi ), |
||
801 | .sddo (sddo ), |
||
802 | .sdcs_n(sdcs_n) |
||
803 | ); |
||
510 | lvd | 804 | |
543 | lvd | 805 | // spitest AVR imitator |
510 | lvd | 806 | |
543 | lvd | 807 | spitest_avr spitest_avr( |
808 | .spick (spick ), |
||
809 | .spics_n(spics_n), |
||
810 | .spido (spido ), |
||
811 | .spidi (spidi ) |
||
812 | ); |
||
813 | `else |
||
814 | assign sddi = 1'b1; |
||
510 | lvd | 815 | |
543 | lvd | 816 | assign spics_n = 1'b1; |
817 | assign spick = 1'b0; |
||
818 | assign spido = 1'b1; |
||
819 | `endif |
||
820 | |||
821 | |||
822 | |||
823 | |||
824 | |||
943 | lvd | 825 | // set up breakpoint |
826 | /* |
||
827 | wire bpt = za===16'h3FEC && zmreq_n===1'b0 && zrd_n===1'b0 && zm1_n===1'b0; |
||
828 | initial |
||
829 | begin |
||
830 | #(1_800_000_000); |
||
831 | @(posedge fclk); |
||
832 | forever |
||
833 | begin |
||
834 | @(posedge bpt); |
||
835 | $display("Stop at breakpoint"); |
||
836 | $stop; |
||
837 | end |
||
838 | end |
||
839 | */ |
||
576 | lvd | 840 | |
943 | lvd | 841 | // log INI command |
842 | wire [15:0] #(0.1) dza; |
||
843 | wire [ 7:0] #(0.1) dzw; |
||
844 | wire [ 7:0] #(0.1) dzr; |
||
576 | lvd | 845 | |
943 | lvd | 846 | typedef enum {FETCH,MRD,MWR,IORD,IOWR,IACK} cycle_t; |
576 | lvd | 847 | |
943 | lvd | 848 | cycle_t curr_cycle; |
849 | cycle_t cycles[0:3]; |
||
850 | logic [15:0] addrs[0:3]; |
||
851 | logic [ 7:0] wdata[0:3]; |
||
852 | logic [ 7:0] rdata[0:3]; |
||
576 | lvd | 853 | |
943 | lvd | 854 | wire is_fetch, is_mrd, is_mwr, is_iord, is_iowr, is_iack; |
576 | lvd | 855 | |
943 | lvd | 856 | wire is_any; |
576 | lvd | 857 | |
858 | |||
859 | |||
860 | |||
943 | lvd | 861 | assign dza = za; |
862 | assign dzw = zd; |
||
863 | assign dzr = zd_dut_to_z80; |
||
576 | lvd | 864 | |
943 | lvd | 865 | assign is_fetch = zm1_n===1'b0 && zmreq_n===1'b0 && zrd_n===1'b0; |
866 | assign is_mrd = zm1_n===1'b1 && zmreq_n===1'b0 && zrd_n===1'b0; |
||
867 | assign is_mwr = zmreq_n===1'b0 && zwr_n===1'b0; |
||
868 | assign is_iord = ziorq_n===1'b0 && zrd_n===1'b0; |
||
869 | assign is_iowr = ziorq_n===1'b0 && zwr_n===1'b0; |
||
870 | assign is_iack = zm1_n===1'b0 && ziorq_n===1'b0; |
||
576 | lvd | 871 | |
943 | lvd | 872 | assign is_any = is_fetch || is_mrd || is_mwr || is_iord || is_iowr || is_iack; |
873 | |||
874 | |||
875 | always @(negedge is_any) |
||
876 | begin : remember |
||
877 | int i; |
||
878 | |||
879 | for(i=1;i<4;i++) |
||
880 | begin |
||
881 | addrs [i] <= addrs [i-1]; |
||
882 | cycles[i] <= cycles[i-1]; |
||
883 | |||
884 | wdata [i] <= wdata [i-1]; |
||
885 | rdata [i] <= rdata [i-1]; |
||
886 | end |
||
887 | |||
888 | addrs[0] <= dza; |
||
889 | cycles[0] <= curr_cycle; |
||
890 | |||
891 | wdata[0] <= dzw; |
||
892 | rdata[0] <= dzr; |
||
893 | end |
||
894 | |||
895 | always @(posedge is_any) |
||
896 | if( is_fetch ) curr_cycle <= FETCH; |
||
897 | else if( is_mrd ) curr_cycle <= MRD; |
||
898 | else if( is_mwr ) curr_cycle <= MWR; |
||
899 | else if( is_iord ) curr_cycle <= IORD; |
||
900 | else if( is_iowr ) curr_cycle <= IOWR; |
||
901 | else if( is_iack ) curr_cycle <= IACK; |
||
902 | else |
||
903 | begin |
||
904 | $display("Spurious cycle detect!"); |
||
905 | $stop; |
||
906 | end |
||
907 | |||
908 | |||
909 | // actual break |
||
910 | always @(negedge is_any) |
||
911 | begin |
||
912 | if( cycles[3]==FETCH && addrs[3][15:0 ]==16'h3FEC && rdata[3]==8'hED && |
||
913 | cycles[2]==FETCH && rdata[2]==8'hA2 && |
||
914 | cycles[1]==IORD && |
||
915 | cycles[0]==MWR && addrs[0][15:14]== 2'd0 |
||
916 | ) |
||
917 | begin |
||
945 | lvd | 918 | $display("trd INI caught! port=%04x, wraddr=%04x, time=%t",addrs[1],addrs[0],$time()); |
943 | lvd | 919 | end |
920 | end |
||
921 | |||
922 | |||
923 | |||
924 | |||
925 | |||
926 | |||
927 | |||
928 | |||
929 | |||
930 | |||
951 | lvd | 931 | // timestamps |
932 | always |
||
933 | begin |
||
934 | $display("Running for %t ms",$time()/1000000000.0); |
||
935 | #1000000.0; |
||
936 | end |
||
943 | lvd | 937 | |
938 | |||
939 | |||
940 | |||
941 | |||
968 | lvd | 942 | // generate nmi after 2s |
943 | initial |
||
944 | begin |
||
945 | #2000000000.0; |
||
943 | lvd | 946 | |
968 | lvd | 947 | force DUT.set_nmi[0] = 1'b1; |
948 | #1000000.0; |
||
949 | release DUT.set_nmi[0]; |
||
950 | end |
||
943 | lvd | 951 | |
952 | |||
953 | |||
951 | lvd | 954 | |
955 | |||
956 | |||
957 | |||
958 | |||
959 | |||
960 | |||
425 | lvd | 961 | task put_byte; |
962 | |||
963 | input [21:0] addr; |
||
964 | input [ 7:0] data; |
||
965 | |||
966 | |||
511 | lvd | 967 | |
425 | lvd | 968 | reg [19:0] arraddr; |
969 | |||
970 | begin |
||
971 | |||
972 | arraddr = { addr[21:12], addr[11:2] }; |
||
973 | |||
974 | case( addr[1:0] ) // chipsel, bytesel |
||
975 | |||
976 | 2'b00: tb.dramko1.array[arraddr][15:8] = data; |
||
977 | 2'b01: tb.dramko1.array[arraddr][ 7:0] = data; |
||
978 | 2'b10: tb.dramko2.array[arraddr][15:8] = data; |
||
979 | 2'b11: tb.dramko2.array[arraddr][ 7:0] = data; |
||
980 | |||
981 | endcase |
||
982 | end |
||
983 | |||
984 | endtask |
||
985 | |||
684 | lvd | 986 | task put_byte_48k |
987 | ( |
||
988 | input [15:0] addr, |
||
989 | input [ 7:0] data |
||
990 | ); |
||
425 | lvd | 991 | |
684 | lvd | 992 | case( addr[15:14] ) |
993 | 2'b01: put_byte(addr-16'h4000 + 22'h14000,data); |
||
994 | 2'b10: put_byte(addr-16'h8000 + 22'h08000,data); |
||
995 | 2'b11: put_byte(addr-16'hc000 + 22'h00000,data); |
||
996 | endcase |
||
997 | endtask |
||
425 | lvd | 998 | |
999 | |||
1000 | |||
684 | lvd | 1001 | |
29 | lvd | 1002 | endmodule |
1003 | |||
1004 |