ffd4b35c |
1 | /* |
2 | * This software is released into the public domain. |
3 | * See UNLICENSE file in top level directory. |
4 | */ |
5 | #include <stdlib.h> |
6 | #include <stdarg.h> |
7 | |
8 | #define u8 unsigned char |
9 | #define u16 unsigned short |
10 | #define u32 unsigned int |
11 | |
12 | #define noinline __attribute__((noinline)) |
13 | #define unused __attribute__((unused)) |
14 | #define _packed __attribute__((packed)) |
15 | |
16 | #define mem_barrier() \ |
17 | asm volatile("":::"memory") |
18 | |
19 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) |
20 | |
21 | #include "asmtools.h" |
22 | |
23 | #define VDP_DATA_PORT 0xC00000 |
24 | #define VDP_CTRL_PORT 0xC00004 |
25 | |
26 | #define TILE_MEM_END 0xB000 |
27 | |
28 | #define FONT_LEN 128 |
29 | #define TILE_FONT_BASE (TILE_MEM_END / 32 - FONT_LEN) |
30 | |
31 | /* note: using ED menu's layout here.. */ |
32 | #define WPLANE (TILE_MEM_END + 0x0000) |
33 | #define HSCRL (TILE_MEM_END + 0x0800) |
34 | #define SLIST (TILE_MEM_END + 0x0C00) |
35 | #define APLANE (TILE_MEM_END + 0x1000) |
36 | #define BPLANE (TILE_MEM_END + 0x3000) |
37 | |
38 | #define read8(a) \ |
39 | *((volatile u8 *) (a)) |
40 | #define read16(a) \ |
41 | *((volatile u16 *) (a)) |
42 | #define read32(a) \ |
43 | *((volatile u32 *) (a)) |
44 | #define write8(a, d) \ |
45 | *((volatile u8 *) (a)) = (d) |
46 | #define write16(a, d) \ |
47 | *((volatile u16 *) (a)) = (d) |
48 | #define write32(a, d) \ |
49 | *((volatile u32 *) (a)) = (d) |
50 | |
51 | #define write16_z80le(a, d) \ |
52 | ((volatile u8 *)(a))[0] = (u8)(d), \ |
53 | ((volatile u8 *)(a))[1] = ((d) >> 8) |
54 | |
55 | static inline u16 read16_z80le(const void *a_) |
56 | { |
57 | volatile const u8 *a = (volatile const u8 *)a_; |
58 | return a[0] | ((u16)a[1] << 8); |
59 | } |
60 | |
61 | #define CTL_WRITE_VRAM(adr) \ |
62 | (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x00) |
63 | #define CTL_WRITE_VSRAM(adr) \ |
64 | (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x10) |
65 | #define CTL_WRITE_CRAM(adr) \ |
66 | (((0xC000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x00) |
67 | #define CTL_READ_VRAM(adr) \ |
68 | (((0x0000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x00) |
69 | #define CTL_READ_VSRAM(adr) \ |
70 | (((0x0000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x10) |
71 | #define CTL_READ_CRAM(adr) \ |
72 | (((0x0000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x20) |
73 | |
74 | #define CTL_WRITE_DMA 0x80 |
75 | |
76 | #define VDP_setReg(r, v) \ |
77 | write16(VDP_CTRL_PORT, 0x8000 | ((r) << 8) | ((v) & 0xff)) |
78 | |
79 | enum { |
80 | VDP_MODE1 = 0x00, |
81 | VDP_MODE2 = 0x01, |
82 | VDP_NT_SCROLLA = 0x02, |
83 | VDP_NT_WIN = 0x03, |
84 | VDP_NT_SCROLLB = 0x04, |
85 | VDP_SAT_BASE = 0x05, |
86 | VDP_BACKDROP = 0x07, |
87 | VDP_MODE3 = 0x0b, |
88 | VDP_MODE4 = 0x0c, |
89 | VDP_HSCROLL = 0x0d, |
90 | VDP_AUTOINC = 0x0f, |
91 | VDP_SCROLLSZ = 0x10, |
92 | VDP_DMA_LEN0 = 0x13, |
93 | VDP_DMA_LEN1 = 0x14, |
94 | VDP_DMA_SRC0 = 0x15, |
95 | VDP_DMA_SRC1 = 0x16, |
96 | VDP_DMA_SRC2 = 0x17, |
97 | }; |
98 | |
99 | #define VDP_MODE1_PS 0x04 |
100 | #define VDP_MODE1_IE1 0x10 // h int |
101 | #define VDP_MODE2_MD 0x04 |
102 | #define VDP_MODE2_PAL 0x08 // 30 col |
103 | #define VDP_MODE2_DMA 0x10 |
104 | #define VDP_MODE2_IE0 0x20 // v int |
105 | #define VDP_MODE2_DISP 0x40 |
106 | |
107 | /* cell counts */ |
108 | #define LEFT_BORDER 1 /* lame TV */ |
109 | #define PLANE_W 64 |
110 | #define PLANE_H 32 |
111 | #define CSCREEN_H 28 |
112 | |
113 | /* data.s */ |
114 | extern const u32 font_base[]; |
115 | extern const u8 z80_test[]; |
116 | extern const u8 z80_test_end[]; |
117 | |
118 | static int text_pal; |
119 | |
120 | static noinline void VDP_drawTextML(const char *str, u16 plane_base, |
121 | u16 x, u16 y) |
122 | { |
123 | const u8 *src = (const u8 *)str; |
124 | u16 basetile = text_pal << 13; |
125 | int max_len = 40 - LEFT_BORDER; |
126 | int len; |
127 | u32 addr; |
128 | |
129 | x += LEFT_BORDER; |
130 | |
131 | for (len = 0; str[len] && len < max_len; len++) |
132 | ; |
133 | if (len > (PLANE_W - x)) |
134 | len = PLANE_W - x; |
135 | |
136 | addr = plane_base + ((x + (PLANE_W * y)) << 1); |
137 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(addr)); |
138 | |
139 | while (len-- > 0) { |
140 | write16(VDP_DATA_PORT, |
141 | basetile | ((*src++) - 32 + TILE_FONT_BASE / 32)); |
142 | } |
143 | } |
144 | |
145 | static int printf_ypos; |
146 | |
147 | static void printf_line(int x, const char *buf) |
148 | { |
149 | u32 addr; |
150 | int i; |
151 | |
152 | VDP_drawTextML(buf, APLANE, x, printf_ypos++ & (PLANE_H - 1)); |
153 | |
154 | if (printf_ypos >= CSCREEN_H) { |
155 | /* clear next line */ |
156 | addr = APLANE; |
157 | addr += (PLANE_W * (printf_ypos & (PLANE_H - 1))) << 1; |
158 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(addr)); |
159 | for (i = 0; i < 40 / 2; i++) |
160 | write32(VDP_DATA_PORT, 0); |
161 | |
162 | /* scroll plane */ |
163 | write32(VDP_CTRL_PORT, CTL_WRITE_VSRAM(0)); |
164 | write16(VDP_DATA_PORT, (printf_ypos - CSCREEN_H + 1) * 8); |
165 | } |
166 | } |
167 | |
168 | #define PRINTF_LEN 40 |
169 | |
170 | static int printf_xpos; |
171 | |
172 | static noinline int printf(const char *fmt, ...) |
173 | { |
174 | static const char hexchars[] = "0123456789abcdef"; |
175 | char c, buf[PRINTF_LEN + 11 + 1]; |
176 | const char *s; |
177 | va_list ap; |
178 | int ival; |
179 | u32 uval; |
180 | int d = 0; |
181 | int i, j; |
182 | |
183 | va_start(ap, fmt); |
184 | for (d = 0; *fmt; ) { |
185 | int prefix0 = 0; |
186 | int fwidth = 0; |
187 | |
188 | c = *fmt++; |
189 | if (d < PRINTF_LEN) |
190 | buf[d] = c; |
191 | |
192 | if (c != '%') { |
193 | if (c == '\n') { |
194 | buf[d] = 0; |
195 | printf_line(printf_xpos, buf); |
196 | d = 0; |
197 | printf_xpos = 0; |
198 | continue; |
199 | } |
200 | d++; |
201 | continue; |
202 | } |
203 | if (d >= PRINTF_LEN) |
204 | continue; |
205 | |
206 | if (*fmt == '0') { |
207 | prefix0 = 1; |
208 | fmt++; |
209 | } |
210 | |
211 | while ('1' <= *fmt && *fmt <= '9') { |
212 | fwidth = fwidth * 10 + *fmt - '0'; |
213 | fmt++; |
214 | } |
215 | |
216 | switch (*fmt++) { |
217 | case '%': |
218 | d++; |
219 | break; |
220 | case 'd': |
221 | case 'i': |
222 | ival = va_arg(ap, int); |
223 | if (ival < 0) { |
224 | buf[d++] = '-'; |
225 | ival = -ival; |
226 | } |
227 | for (i = 1000000000; i >= 10; i /= 10) |
228 | if (ival >= i) |
229 | break; |
230 | for (; i >= 10; i /= 10) { |
231 | buf[d++] = '0' + ival / i; |
232 | ival %= i; |
233 | } |
234 | buf[d++] = '0' + ival; |
235 | break; |
236 | case 'x': |
237 | uval = va_arg(ap, int); |
238 | while (fwidth > 1 && uval < (1 << (fwidth - 1) * 4)) { |
239 | buf[d++] = prefix0 ? '0' : ' '; |
240 | fwidth--; |
241 | } |
242 | for (j = 1; j < 8 && uval >= (1 << j * 4); j++) |
243 | ; |
244 | for (j--; j >= 0; j--) |
245 | buf[d++] = hexchars[(uval >> j * 4) & 0x0f]; |
246 | break; |
247 | case 's': |
248 | s = va_arg(ap, char *); |
249 | while (*s && d < PRINTF_LEN) |
250 | buf[d++] = *s++; |
251 | break; |
252 | default: |
253 | // don't handle, for now |
254 | d++; |
255 | va_arg(ap, void *); |
256 | break; |
257 | } |
258 | } |
259 | buf[d] = 0; |
260 | va_end(ap); |
261 | |
262 | if (d != 0) { |
263 | // line without \n |
264 | VDP_drawTextML(buf, APLANE, printf_xpos, |
265 | printf_ypos & (PLANE_H - 1)); |
266 | printf_xpos += d; |
267 | } |
268 | |
269 | return d; // wrong.. |
270 | } |
271 | |
272 | static const char *exc_names[] = { |
273 | NULL, |
274 | NULL, |
275 | "Bus Error", |
276 | "Address Error", |
277 | "Illegal Instruction", |
278 | "Zero Divide", |
279 | "CHK Instruction", |
280 | "TRAPV Instruction", |
281 | "Privilege Violation", /* 8 8 */ |
282 | "Trace", |
283 | "Line 1010 Emulator", |
284 | "Line 1111 Emulator", |
285 | NULL, |
286 | NULL, |
287 | NULL, |
288 | "Uninitialized Interrupt", |
289 | NULL, /* 10 16 */ |
290 | NULL, |
291 | NULL, |
292 | NULL, |
293 | NULL, |
294 | NULL, |
295 | NULL, |
296 | NULL, |
297 | "Spurious Interrupt", /* 18 24 */ |
298 | "l1 irq", |
299 | "l2 irq", |
300 | "l3 irq", |
301 | "l4 irq", |
302 | "l5 irq", |
303 | "l6 irq", |
304 | "l7 irq", |
305 | }; |
306 | |
307 | struct exc_frame { |
308 | u32 dr[8]; |
309 | u32 ar[8]; |
310 | u16 ecxnum; // from handler |
311 | union { |
312 | struct { |
313 | u16 sr; |
314 | u32 pc; |
315 | } g _packed; |
316 | struct { |
317 | u16 fc; |
318 | u32 addr; |
319 | u16 ir; |
320 | u16 sr; |
321 | u32 pc; |
322 | } bae _packed; // bus/address error frame |
323 | }; |
324 | } _packed; |
325 | |
326 | int xtttt(void) { return sizeof(struct exc_frame); } |
327 | |
328 | void exception(const struct exc_frame *f) |
329 | { |
330 | int i; |
331 | |
332 | while (read16(VDP_CTRL_PORT) & 2) |
333 | ; |
334 | VDP_setReg(VDP_MODE1, VDP_MODE1_PS); |
335 | VDP_setReg(VDP_MODE2, VDP_MODE2_MD | VDP_MODE2_DISP); |
336 | /* adjust scroll */ |
337 | write32(VDP_CTRL_PORT, CTL_WRITE_VSRAM(0)); |
338 | write16(VDP_DATA_PORT, |
339 | printf_ypos >= CSCREEN_H ? |
340 | (printf_ypos - CSCREEN_H + 1) * 8 : 0); |
341 | |
342 | printf("exception %i ", f->ecxnum); |
343 | if (f->ecxnum < ARRAY_SIZE(exc_names) && exc_names[f->ecxnum] != NULL) |
344 | printf("(%s)", exc_names[f->ecxnum]); |
345 | if (f->ecxnum < 4) |
346 | printf(" (%s)", (f->bae.fc & 0x10) ? "r" : "w"); |
347 | printf(" \n"); |
348 | |
349 | if (f->ecxnum < 4) { |
350 | printf(" PC: %08x SR: %04x \n", f->bae.pc, f->bae.sr); |
351 | printf("addr: %08x IR: %04x FC: %02x \n", |
352 | f->bae.addr, f->bae.ir, f->bae.fc); |
353 | } |
354 | else { |
355 | printf(" PC: %08x SR: %04x \n", f->g.pc, f->g.sr); |
356 | } |
357 | for (i = 0; i < 8; i++) |
358 | printf(" D%d: %08x A%d: %08x \n", i, f->dr[i], i, f->ar[i]); |
359 | printf(" \n"); |
360 | } |
361 | |
362 | // --- |
363 | |
364 | static void setup_default_palette(void) |
365 | { |
366 | write32(VDP_CTRL_PORT, CTL_WRITE_CRAM(0)); |
367 | write32(VDP_DATA_PORT, 0); |
368 | write32(VDP_CTRL_PORT, CTL_WRITE_CRAM(15 * 2)); // font normal |
369 | write16(VDP_DATA_PORT, 0xeee); |
370 | write32(VDP_CTRL_PORT, CTL_WRITE_CRAM(31 * 2)); // green |
371 | write16(VDP_DATA_PORT, 0x0e0); |
372 | write32(VDP_CTRL_PORT, CTL_WRITE_CRAM(47 * 2)); // red |
373 | write16(VDP_DATA_PORT, 0x00e); |
374 | } |
375 | |
376 | static void do_setup_dma(const void *src_, u16 words) |
377 | { |
378 | u32 src = (u32)src_; |
379 | // VDP_setReg(VDP_MODE2, VDP_MODE2_MD | VDP_MODE2_DMA); |
380 | VDP_setReg(VDP_DMA_LEN0, words); |
381 | VDP_setReg(VDP_DMA_LEN1, words >> 8); |
382 | VDP_setReg(VDP_DMA_SRC0, src >> 1); |
383 | VDP_setReg(VDP_DMA_SRC1, src >> 9); |
384 | VDP_setReg(VDP_DMA_SRC2, src >> 17); |
385 | // write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(addr) | CTL_WRITE_DMA); |
386 | } |
387 | |
388 | static void t_dma_zero_wrap_early(void) |
389 | { |
390 | const u32 *src = (const u32 *)0x3c0000; |
391 | u32 *ram = (u32 *)0xff0000; |
392 | |
393 | do_setup_dma(src + 4, 2); |
394 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0) | CTL_WRITE_DMA); |
395 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0) | CTL_WRITE_DMA); |
396 | |
397 | write32(VDP_CTRL_PORT, CTL_READ_VRAM(0)); |
398 | ram[0] = read32(VDP_DATA_PORT); |
399 | write32(VDP_CTRL_PORT, CTL_READ_VRAM(0xfffc)); |
400 | ram[1] = read32(VDP_DATA_PORT); |
401 | } |
402 | |
403 | static void t_dma_zero_fill_early(void) |
404 | { |
405 | u32 *ram = (u32 *)0xff0000; |
406 | |
407 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0)); |
408 | write32(VDP_DATA_PORT, 0); |
409 | write32(VDP_DATA_PORT, 0); |
410 | write32(VDP_DATA_PORT, 0); |
411 | write32(VDP_DATA_PORT, 0); |
412 | |
413 | VDP_setReg(VDP_AUTOINC, 1); |
414 | VDP_setReg(VDP_DMA_SRC2, 0x80); |
415 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(1) | CTL_WRITE_DMA); |
416 | write16(VDP_DATA_PORT, 0x1122); |
417 | ram[2] = read16(VDP_CTRL_PORT); |
418 | while (read16(VDP_CTRL_PORT) & 2) |
419 | ; |
420 | |
421 | VDP_setReg(VDP_AUTOINC, 2); |
422 | write32(VDP_CTRL_PORT, CTL_READ_VRAM(0)); |
423 | ram[3] = read32(VDP_DATA_PORT); |
424 | } |
425 | |
426 | #define expect(ok_, v0_, v1_) \ |
427 | if ((v0_) != (v1_)) { \ |
428 | printf("%s: %08x %08x\n", #v0_, v0_, v1_); \ |
429 | ok_ = 0; \ |
430 | } |
431 | |
432 | static int t_dma_zero_wrap(void) |
433 | { |
434 | const u32 *src = (const u32 *)0x3c0000; |
435 | const u32 *ram = (const u32 *)0xff0000; |
436 | int ok = 1; |
437 | |
438 | expect(ok, ram[0], src[5 + 0x10000/4]); |
439 | expect(ok, ram[1], src[4]); |
440 | return ok; |
441 | } |
442 | |
443 | static int t_dma_zero_fill(void) |
444 | { |
445 | const u32 *ram = (const u32 *)0xff0000; |
446 | u32 v0 = ram[2] & 2; |
447 | int ok = 1; |
448 | |
449 | expect(ok, v0, 2); |
450 | expect(ok, ram[3], 0x11111111); |
451 | return ok; |
452 | } |
453 | |
454 | static int t_dma_ram_wrap(void) |
455 | { |
456 | u32 *ram = (u32 *)0xff0000; |
457 | u32 saved, v0, v1; |
458 | int ok = 1; |
459 | |
460 | saved = read32(&ram[0x10000/4 - 1]); |
461 | ram[0x10000/4 - 1] = 0x01020304; |
462 | ram[0] = 0x05060708; |
463 | do_setup_dma(&ram[0x10000/4 - 1], 4); |
464 | mem_barrier(); |
465 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0x100) | CTL_WRITE_DMA); |
466 | |
467 | mem_barrier(); |
468 | write32(&ram[0x10000/4 - 1], saved); |
469 | |
470 | write32(VDP_CTRL_PORT, CTL_READ_VRAM(0x100)); |
471 | v0 = read32(VDP_DATA_PORT); |
472 | v1 = read32(VDP_DATA_PORT); |
473 | |
474 | expect(ok, v0, 0x01020304); |
475 | expect(ok, v1, 0x05060708); |
476 | return ok; |
477 | } |
478 | |
479 | // test no src reprogram, only len0 |
480 | static int t_dma_multi(void) |
481 | { |
482 | const u32 *src = (const u32 *)0x3c0000; |
483 | u32 v0, v1; |
484 | int ok = 1; |
485 | |
486 | do_setup_dma(src, 2); |
487 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0x100) | CTL_WRITE_DMA); |
488 | VDP_setReg(VDP_DMA_LEN0, 2); |
489 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0x104) | CTL_WRITE_DMA); |
490 | |
491 | write32(VDP_CTRL_PORT, CTL_READ_VRAM(0x100)); |
492 | v0 = read32(VDP_DATA_PORT); |
493 | v1 = read32(VDP_DATA_PORT); |
494 | |
495 | expect(ok, v0, src[0]); |
496 | expect(ok, v1, src[1]); |
497 | return ok; |
498 | } |
499 | |
500 | static int t_dma_cram_wrap(void) |
501 | { |
502 | u32 *ram = (u32 *)0xff0000; |
503 | u32 v0, v1; |
504 | int ok = 1; |
505 | |
506 | write32(VDP_CTRL_PORT, CTL_WRITE_CRAM(0)); |
507 | write32(VDP_DATA_PORT, 0); |
508 | |
509 | ram[0] = 0x0ec20ec4; |
510 | ram[1] = 0x0ec60ec8; |
511 | mem_barrier(); |
512 | do_setup_dma(ram, 4); |
513 | write32(VDP_CTRL_PORT, CTL_WRITE_CRAM(0x7c | 0xff81) | CTL_WRITE_DMA); |
514 | |
515 | write32(VDP_CTRL_PORT, CTL_READ_CRAM(0x7c)); |
516 | v0 = read32(VDP_DATA_PORT) & 0x0eee0eee; |
517 | write32(VDP_CTRL_PORT, CTL_READ_CRAM(0)); |
518 | v1 = read32(VDP_DATA_PORT) & 0x0eee0eee; |
519 | |
520 | setup_default_palette(); |
521 | |
522 | expect(ok, v0, ram[0]); |
523 | expect(ok, v1, ram[1]); |
524 | return ok; |
525 | } |
526 | |
527 | static int t_dma_vsram_wrap(void) |
528 | { |
529 | u32 *ram32 = (u32 *)0xff0000; |
530 | u16 *ram16 = (u16 *)0xff0000; |
531 | u32 v0, v1; |
532 | int ok = 1; |
533 | int i; |
534 | |
535 | write32(VDP_CTRL_PORT, CTL_WRITE_VSRAM(0)); |
536 | write32(VDP_DATA_PORT, 0); |
537 | |
538 | for (i = 0; i < 0x48/2; i++) |
539 | ram16[i] = i + 1; |
540 | mem_barrier(); |
541 | do_setup_dma(ram16, 0x48/2); |
542 | write32(VDP_CTRL_PORT, CTL_WRITE_VSRAM(0x3c | 0xff81) | CTL_WRITE_DMA); |
543 | |
544 | write32(VDP_CTRL_PORT, CTL_READ_VSRAM(0x3c)); |
545 | v0 = read32(VDP_DATA_PORT) & 0x03ff03ff; |
546 | write32(VDP_CTRL_PORT, CTL_READ_VSRAM(0)); |
547 | v1 = read32(VDP_DATA_PORT) & 0x03ff03ff; |
548 | |
549 | write32(VDP_CTRL_PORT, CTL_WRITE_VSRAM(0)); |
550 | write32(VDP_DATA_PORT, 0); |
551 | |
552 | expect(ok, v0, ram32[0]); |
553 | expect(ok, v1, ram32[0x48/4 - 1]); |
554 | return ok; |
555 | } |
556 | |
557 | static int t_dma_and_data(void) |
558 | { |
559 | const u32 *src = (const u32 *)0x3c0000; |
560 | u32 v0; |
561 | int ok = 1; |
562 | |
563 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0x100)); |
564 | write32(VDP_DATA_PORT, 0); |
565 | |
566 | do_setup_dma(src, 2); |
567 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0xfc) | CTL_WRITE_DMA); |
568 | write32(VDP_DATA_PORT, 0x5ec8a248); |
569 | |
570 | write32(VDP_CTRL_PORT, CTL_READ_VRAM(0x100)); |
571 | v0 = read32(VDP_DATA_PORT); |
572 | |
573 | expect(ok, v0, 0x5ec8a248); |
574 | return ok; |
575 | } |
576 | |
577 | static int t_dma_fill3_odd(void) |
578 | { |
579 | u32 v0, v1, v2; |
580 | int ok = 1; |
581 | |
582 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0x100)); |
583 | write32(VDP_DATA_PORT, 0); |
584 | write32(VDP_DATA_PORT, 0); |
585 | write32(VDP_DATA_PORT, 0); |
586 | |
587 | VDP_setReg(VDP_AUTOINC, 3); |
588 | VDP_setReg(VDP_DMA_LEN0, 3); |
589 | VDP_setReg(VDP_DMA_SRC2, 0x80); |
590 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0x101) | CTL_WRITE_DMA); |
591 | write16(VDP_DATA_PORT, 0x1122); |
592 | while (read16(VDP_CTRL_PORT) & 2) |
593 | ; |
594 | |
595 | VDP_setReg(VDP_AUTOINC, 2); |
596 | write32(VDP_CTRL_PORT, CTL_READ_VRAM(0x100)); |
597 | v0 = read32(VDP_DATA_PORT); |
598 | v1 = read32(VDP_DATA_PORT); |
599 | v2 = read32(VDP_DATA_PORT); |
600 | |
601 | expect(ok, v0, 0x22110000); |
602 | expect(ok, v1, 0x00111100); |
603 | expect(ok, v2, 0x00000011); |
604 | return ok; |
605 | } |
606 | |
607 | static int t_dma_fill3_even(void) |
608 | { |
609 | u32 v0, v1, v2; |
610 | int ok = 1; |
611 | |
612 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0x100)); |
613 | write32(VDP_DATA_PORT, 0); |
614 | write32(VDP_DATA_PORT, 0); |
615 | write32(VDP_DATA_PORT, 0); |
616 | |
617 | VDP_setReg(VDP_AUTOINC, 3); |
618 | VDP_setReg(VDP_DMA_LEN0, 3); |
619 | VDP_setReg(VDP_DMA_SRC2, 0x80); |
620 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0x100) | CTL_WRITE_DMA); |
621 | write16(VDP_DATA_PORT, 0x1122); |
622 | while (read16(VDP_CTRL_PORT) & 2) |
623 | ; |
624 | |
625 | VDP_setReg(VDP_AUTOINC, 2); |
626 | write32(VDP_CTRL_PORT, CTL_READ_VRAM(0x100)); |
627 | v0 = read32(VDP_DATA_PORT); |
628 | v1 = read32(VDP_DATA_PORT); |
629 | v2 = read32(VDP_DATA_PORT); |
630 | |
631 | expect(ok, v0, 0x11221100); |
632 | expect(ok, v1, 0x00000011); |
633 | expect(ok, v2, 0x11000000); |
634 | return ok; |
635 | } |
636 | |
637 | static unused int t_dma_fill3_vsram(void) |
638 | { |
639 | u32 v0, v1, v2; |
640 | int ok = 1; |
641 | |
642 | write32(VDP_CTRL_PORT, CTL_WRITE_VSRAM(0)); |
643 | write32(VDP_DATA_PORT, 0); |
644 | write32(VDP_DATA_PORT, 0); |
645 | write32(VDP_DATA_PORT, 0); |
646 | |
647 | write16(VDP_DATA_PORT, 0x0111); |
648 | write16(VDP_DATA_PORT, 0x0222); |
649 | write16(VDP_DATA_PORT, 0x0333); |
650 | |
651 | VDP_setReg(VDP_AUTOINC, 3); |
652 | VDP_setReg(VDP_DMA_LEN0, 3); |
653 | VDP_setReg(VDP_DMA_SRC2, 0x80); |
654 | write32(VDP_CTRL_PORT, CTL_WRITE_VSRAM(1) | CTL_WRITE_DMA); |
655 | write16(VDP_DATA_PORT, 0x0102); |
656 | while (read16(VDP_CTRL_PORT) & 2) |
657 | ; |
658 | |
659 | VDP_setReg(VDP_AUTOINC, 2); |
660 | write32(VDP_CTRL_PORT, CTL_READ_VSRAM(0)); |
661 | v0 = read32(VDP_DATA_PORT); |
662 | v1 = read32(VDP_DATA_PORT); |
663 | v2 = read32(VDP_DATA_PORT); |
664 | |
665 | write32(VDP_CTRL_PORT, CTL_WRITE_VSRAM(0)); |
666 | write32(VDP_DATA_PORT, 0); |
667 | |
668 | expect(ok, v0, 0x01020000); |
669 | expect(ok, v1, 0x01110111); |
670 | expect(ok, v2, 0x00000111); |
671 | return ok; |
672 | } |
673 | |
674 | static int t_dma_fill_dis(void) |
675 | { |
676 | u32 v0, v1; |
677 | int ok = 1; |
678 | |
679 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0x100)); |
680 | write32(VDP_DATA_PORT, 0); |
681 | write32(VDP_DATA_PORT, 0); |
682 | |
683 | VDP_setReg(VDP_DMA_LEN0, 1); |
684 | VDP_setReg(VDP_DMA_SRC2, 0x80); |
685 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0x100) | CTL_WRITE_DMA); |
686 | VDP_setReg(VDP_MODE2, VDP_MODE2_MD); |
687 | write16(VDP_DATA_PORT, 0x1122); |
688 | while (read16(VDP_CTRL_PORT) & 2) |
689 | ; |
690 | |
691 | VDP_setReg(VDP_MODE2, VDP_MODE2_MD | VDP_MODE2_DMA | VDP_MODE2_DISP); |
692 | write16(VDP_DATA_PORT, 0x3344); |
693 | while (read16(VDP_CTRL_PORT) & 2) |
694 | ; |
695 | |
696 | write32(VDP_CTRL_PORT, CTL_READ_VRAM(0x100)); |
697 | v0 = read32(VDP_DATA_PORT); |
698 | v1 = read32(VDP_DATA_PORT); |
699 | |
700 | expect(ok, v0, 0); |
701 | expect(ok, v1, 0); |
702 | return ok; |
703 | } |
704 | |
705 | static int t_dma_fill_src(void) |
706 | { |
707 | const u32 *src = (const u32 *)0x3c0000; |
708 | u32 v0, v1; |
709 | int ok = 1; |
710 | |
711 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0x100)); |
712 | write32(VDP_DATA_PORT, 0); |
713 | |
714 | // do_setup_dma(src, 2); // hang, can't write src2 twice |
715 | VDP_setReg(VDP_DMA_LEN0, 2); |
716 | VDP_setReg(VDP_DMA_SRC0, (u32)src >> 1); |
717 | VDP_setReg(VDP_DMA_SRC1, (u32)src >> 9); |
718 | VDP_setReg(VDP_DMA_SRC2, 0x80); |
719 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0x100) | CTL_WRITE_DMA); |
720 | write16(VDP_DATA_PORT, 0x1122); |
721 | while (read16(VDP_CTRL_PORT) & 2) |
722 | ; |
723 | |
724 | VDP_setReg(VDP_DMA_LEN0, 2); |
725 | VDP_setReg(VDP_DMA_SRC2, (u32)src >> 17); |
726 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0x104) | CTL_WRITE_DMA); |
727 | |
728 | write32(VDP_CTRL_PORT, CTL_READ_VRAM(0x100)); |
729 | v0 = read32(VDP_DATA_PORT); |
730 | v1 = read32(VDP_DATA_PORT); |
731 | |
732 | expect(ok, v0, 0x11220011); |
733 | expect(ok, v1, src[1]); |
734 | return ok; |
735 | } |
736 | |
737 | /* z80 tests assume busreq state */ |
738 | static int t_z80mem_long_mirror(void) |
739 | { |
740 | u8 *zram = (u8 *)0xa00000; |
741 | int ok = 1; |
742 | |
743 | write8(&zram[0x1100], 0x11); |
744 | write8(&zram[0x1101], 0x22); |
745 | write8(&zram[0x1102], 0x33); |
746 | write8(&zram[0x1103], 0x44); |
747 | mem_barrier(); |
748 | write32(&zram[0x3100], 0x55667788); |
749 | mem_barrier(); |
750 | |
751 | expect(ok, zram[0x1100], 0x55); |
752 | expect(ok, zram[0x1101], 0x22); |
753 | expect(ok, zram[0x1102], 0x77); |
754 | expect(ok, zram[0x1103], 0x44); |
755 | return ok; |
756 | } |
757 | |
758 | static int t_z80mem_vdp_r(void) |
759 | { |
760 | u8 *zram = (u8 *)0xa00000; |
761 | int ok = 1; |
762 | |
763 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0x100)); |
764 | write32(VDP_DATA_PORT, 0x11223344); |
765 | write32(VDP_CTRL_PORT, CTL_READ_VRAM(0x100)); |
766 | |
767 | zram[0x1000] = 1; // cp |
768 | zram[0x1001] = 2; // len |
769 | write16_z80le(&zram[0x1002], 0x7f00); // src |
770 | write16_z80le(&zram[0x1004], 0x1006); // dst |
771 | zram[0x1006] = zram[0x1007] = zram[0x1008] = 0x5a; |
772 | mem_barrier(); |
773 | write16(0xa11100, 0x000); |
774 | burn10((98 + 40*2 + 27) * 15 / 7 * 2 / 10); |
775 | |
776 | write16(0xa11100, 0x100); |
777 | while (read16(0xa11100) & 0x100) |
778 | ; |
779 | |
780 | expect(ok, zram[0x1000], 0); |
781 | expect(ok, zram[0x1006], 0x11); |
782 | expect(ok, zram[0x1007], 0x44); |
783 | expect(ok, zram[0x1008], 0x5a); |
784 | return ok; |
785 | } |
786 | |
787 | static unused int t_z80mem_vdp_w(void) |
788 | { |
789 | u8 *zram = (u8 *)0xa00000; |
790 | u32 v0; |
791 | int ok = 1; |
792 | |
793 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0x100)); |
794 | write32(VDP_DATA_PORT, 0x11223344); |
795 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0x100)); |
796 | |
797 | zram[0x1000] = 1; // cp |
798 | zram[0x1001] = 2; // len |
799 | write16_z80le(&zram[0x1002], 0x1006); // src |
800 | write16_z80le(&zram[0x1004], 0x7f00); // dst |
801 | zram[0x1006] = 0x55; |
802 | zram[0x1007] = 0x66; |
803 | mem_barrier(); |
804 | write16(0xa11100, 0x000); |
805 | burn10((98 + 40*2 + 27) * 15 / 7 * 2 / 10); |
806 | |
807 | write16(0xa11100, 0x100); |
808 | while (read16(0xa11100) & 0x100) |
809 | ; |
810 | |
811 | write32(VDP_CTRL_PORT, CTL_READ_VRAM(0x100)); |
812 | v0 = read32(VDP_DATA_PORT); |
813 | |
814 | expect(ok, zram[0x1000], 0); |
815 | expect(ok, v0, 0x55556666); |
816 | return ok; |
817 | } |
818 | |
819 | static const struct { |
820 | int (*test)(void); |
821 | const char *name; |
822 | } g_tests[] = { |
823 | { t_dma_zero_wrap, "dma zero len + wrap" }, |
824 | { t_dma_zero_fill, "dma zero len + fill" }, |
825 | { t_dma_ram_wrap, "dma ram wrap" }, |
826 | { t_dma_multi, "dma multi" }, |
827 | { t_dma_cram_wrap, "dma cram wrap" }, |
828 | { t_dma_vsram_wrap, "dma vsram wrap" }, |
829 | { t_dma_and_data, "dma and data" }, |
830 | { t_dma_fill3_odd, "dma fill3 odd" }, |
831 | { t_dma_fill3_even, "dma fill3 even" }, |
832 | // { t_dma_fill3_vsram, "dma fill3 vsram" }, // later |
833 | { t_dma_fill_dis, "dma fill disabled" }, |
834 | { t_dma_fill_src, "dma fill src incr" }, |
835 | { t_z80mem_long_mirror, "z80 ram long mirror" }, |
836 | { t_z80mem_vdp_r, "z80 vdp read" }, |
837 | // { t_z80mem_vdp_w, "z80 vdp write" }, // hang |
838 | }; |
839 | |
840 | static void setup_z80(void) |
841 | { |
842 | u8 *zram = (u8 *)0xa00000; |
843 | int i, len; |
844 | |
845 | /* z80 */ |
846 | write16(0xa11100, 0x100); |
847 | write16(0xa11200, 0x100); |
848 | |
849 | while (read16(0xa11100) & 0x100) |
850 | ; |
851 | |
852 | // load the default test program, clear it's data |
853 | len = z80_test_end - z80_test; |
854 | for (i = 0; i < len; i++) |
855 | write8(&zram[i], z80_test[i]); |
856 | for (i = 0x1000; i < 0x1007; i++) |
857 | write8(&zram[i], 0); |
858 | } |
859 | |
860 | int main() |
861 | { |
862 | int passed = 0; |
863 | int ret; |
864 | int i; |
865 | |
866 | setup_z80(); |
867 | |
868 | /* setup VDP */ |
869 | while (read16(VDP_CTRL_PORT) & 2) |
870 | ; |
871 | |
872 | VDP_setReg(VDP_MODE1, VDP_MODE1_PS); |
873 | VDP_setReg(VDP_MODE2, VDP_MODE2_MD | VDP_MODE2_DMA); |
874 | VDP_setReg(VDP_MODE3, 0x00); |
875 | VDP_setReg(VDP_MODE4, 0x81); |
876 | VDP_setReg(VDP_NT_SCROLLA, APLANE >> 10); |
877 | VDP_setReg(VDP_NT_SCROLLB, BPLANE >> 13); |
878 | VDP_setReg(VDP_SAT_BASE, SLIST >> 9); |
879 | VDP_setReg(VDP_HSCROLL, HSCRL >> 10); |
880 | VDP_setReg(VDP_AUTOINC, 2); |
881 | VDP_setReg(VDP_SCROLLSZ, 0x01); |
882 | VDP_setReg(VDP_BACKDROP, 0); |
883 | |
884 | // early tests |
885 | t_dma_zero_wrap_early(); |
886 | t_dma_zero_fill_early(); |
887 | |
888 | /* pattern 0 */ |
889 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(0)); |
890 | for (i = 0; i < 32 / 4; i++) |
891 | write32(VDP_DATA_PORT, 0); |
892 | |
893 | /* clear name tables */ |
894 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(APLANE)); |
895 | for (i = 0; i < PLANE_W * PLANE_H / 2; i++) |
896 | write32(VDP_DATA_PORT, 0); |
897 | |
898 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(BPLANE)); |
899 | for (i = 0; i < PLANE_W * PLANE_H / 2; i++) |
900 | write32(VDP_DATA_PORT, 0); |
901 | |
902 | /* SAT, h. scroll */ |
903 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(SLIST)); |
904 | write32(VDP_DATA_PORT, 0); |
905 | |
906 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(HSCRL)); |
907 | write32(VDP_DATA_PORT, 0); |
908 | |
909 | /* scroll plane vscroll */ |
910 | write32(VDP_CTRL_PORT, CTL_WRITE_VSRAM(0)); |
911 | write32(VDP_DATA_PORT, 0); |
912 | printf_ypos = 1; |
913 | |
914 | /* load font */ |
915 | write32(VDP_CTRL_PORT, CTL_WRITE_VRAM(TILE_FONT_BASE)); |
916 | for (i = 0; i < FONT_LEN * 32 / 4; i++) |
917 | write32(VDP_DATA_PORT, font_base[i]); |
918 | |
919 | /* set colors */ |
920 | setup_default_palette(); |
921 | |
922 | VDP_setReg(VDP_MODE2, VDP_MODE2_MD | VDP_MODE2_DMA | VDP_MODE2_DISP); |
923 | |
924 | printf("\n"); |
925 | printf("MD version: %02x\n", read8(0xa10001)); |
926 | |
927 | for (i = 0; i < ARRAY_SIZE(g_tests); i++) { |
928 | // print test number if we haven't scrolled away |
929 | if (printf_ypos < CSCREEN_H) { |
930 | int old_ypos = printf_ypos; |
931 | printf_ypos = 0; |
932 | text_pal = 0; |
933 | printf("%02d/%02d", i, ARRAY_SIZE(g_tests)); |
934 | printf_ypos = old_ypos; |
935 | printf_xpos = 0; |
936 | } |
937 | text_pal = 2; |
938 | ret = g_tests[i].test(); |
939 | if (ret != 1) |
940 | printf("failed %d: %s\n", i, g_tests[i].name); |
941 | else |
942 | passed++; |
943 | } |
944 | |
945 | text_pal = 0; |
946 | printf("%d/%d passed.\n", passed, ARRAY_SIZE(g_tests)); |
947 | |
948 | printf_ypos = 0; |
949 | printf(" "); |
950 | |
951 | for (;;) |
952 | ; |
953 | |
954 | return 0; |
955 | } |
956 | |
957 | // vim:ts=4:sw=4:expandtab |