some tests
[megadrive.git] / testsram / main.c
CommitLineData
3ee911dc 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 ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
17
18#include "asmtools.h"
19
20#define GFX_DATA_PORT 0xC00000
21#define GFX_CTRL_PORT 0xC00004
22
23#define TILE_MEM_END 0xB000
24
25#define FONT_LEN 128
26#define TILE_FONT_BASE (TILE_MEM_END / 32 - FONT_LEN)
27
28/* note: using ED menu's layout here.. */
29#define WPLANE (TILE_MEM_END + 0x0000)
30#define HSCRL (TILE_MEM_END + 0x0800)
31#define SLIST (TILE_MEM_END + 0x0C00)
32#define APLANE (TILE_MEM_END + 0x1000)
33#define BPLANE (TILE_MEM_END + 0x3000)
34
35#define read8(a) \
36 *((volatile u8 *) (a))
37#define read16(a) \
38 *((volatile u16 *) (a))
39#define read32(a) \
40 *((volatile u32 *) (a))
41#define write8(a, d) \
42 *((volatile u8 *) (a)) = (d)
43#define write16(a, d) \
44 *((volatile u16 *) (a)) = (d)
45#define write32(a, d) \
46 *((volatile u32 *) (a)) = (d)
47
48#define GFX_WRITE_VRAM_ADDR(adr) \
49 (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x00)
50#define GFX_WRITE_VSRAM_ADDR(adr) \
51 (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x10)
52#define GFX_WRITE_CRAM_ADDR(adr) \
53 (((0xC000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x00)
54
55#define VDP_setReg(r, v) \
56 write16(GFX_CTRL_PORT, 0x8000 | ((r) << 8) | (v))
57
58enum {
59 VDP_MODE1 = 0x00,
60 VDP_MODE2 = 0x01,
61 VDP_NT_SCROLLA = 0x02,
62 VDP_NT_WIN = 0x03,
63 VDP_NT_SCROLLB = 0x04,
64 VDP_SAT_BASE = 0x05,
65 VDP_BACKDROP = 0x07,
66 VDP_MODE3 = 0x0b,
67 VDP_MODE4 = 0x0c,
68 VDP_HSCROLL = 0x0d,
69 VDP_AUTOINC = 0x0f,
70 VDP_SCROLLSZ = 0x10,
71};
72
73/* cell counts */
74#define LEFT_BORDER 1 /* lame TV */
75#define PLANE_W 64
76#define PLANE_H 32
77#define CSCREEN_H 28
78
79static int text_pal;
80
81static noinline void VDP_drawTextML(const char *str, u16 plane_base,
82 u16 x, u16 y)
83{
84 const u8 *src = (const u8 *)str;
85 u16 basetile = text_pal << 13;
86 int max_len = 40 - LEFT_BORDER;
87 int len;
88 u32 addr;
89
90 x += LEFT_BORDER;
91
92 for (len = 0; str[len] && len < max_len; len++)
93 ;
94 if (len > (PLANE_W - x))
95 len = PLANE_W - x;
96
97 addr = plane_base + ((x + (PLANE_W * y)) << 1);
98 write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(addr));
99
100 while (len-- > 0) {
101 write16(GFX_DATA_PORT,
102 basetile | ((*src++) - 32 + TILE_FONT_BASE / 32));
103 }
104}
105
106static int printf_ypos;
107
108static void printf_line(int x, const char *buf)
109{
110 u32 addr;
111 int i;
112
113 VDP_drawTextML(buf, APLANE, x, printf_ypos++ & (PLANE_H - 1));
114
115 if (printf_ypos >= CSCREEN_H) {
116 /* clear next line */
117 addr = APLANE;
118 addr += (PLANE_W * (printf_ypos & (PLANE_H - 1))) << 1;
119 write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(addr));
120 for (i = 0; i < 40 / 2; i++)
121 write32(GFX_DATA_PORT, 0);
122
123 /* scroll plane */
124 write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0));
125 write16(GFX_DATA_PORT, (printf_ypos - CSCREEN_H + 1) * 8);
126 }
127}
128
129#define PRINTF_LEN 40
130
131static int printf_xpos;
132
133static noinline int printf(const char *fmt, ...)
134{
135 static const char hexchars[] = "0123456789abcdef";
136 char c, buf[PRINTF_LEN + 11 + 1];
137 const char *s;
138 va_list ap;
139 int ival;
140 u32 uval;
141 int d = 0;
142 int i, j;
143
144 va_start(ap, fmt);
145 for (d = 0; *fmt; ) {
146 int prefix0 = 0;
147 int fwidth = 0;
148
149 c = *fmt++;
150 if (d < PRINTF_LEN)
151 buf[d] = c;
152
153 if (c != '%') {
154 if (c == '\n') {
155 buf[d] = 0;
156 printf_line(printf_xpos, buf);
157 d = 0;
158 printf_xpos = 0;
159 continue;
160 }
161 d++;
162 continue;
163 }
164 if (d >= PRINTF_LEN)
165 continue;
166
167 if (*fmt == '0') {
168 prefix0 = 1;
169 fmt++;
170 }
171
172 while ('1' <= *fmt && *fmt <= '9') {
173 fwidth = fwidth * 10 + *fmt - '0';
174 fmt++;
175 }
176
177 switch (*fmt++) {
178 case '%':
179 d++;
180 break;
181 case 'd':
182 case 'i':
183 ival = va_arg(ap, int);
184 if (ival < 0) {
185 buf[d++] = '-';
186 ival = -ival;
187 }
188 for (i = 1000000000; i >= 10; i /= 10)
189 if (ival >= i)
190 break;
191 for (; i >= 10; i /= 10) {
192 buf[d++] = '0' + ival / i;
193 ival %= i;
194 }
195 buf[d++] = '0' + ival;
196 break;
197 case 'x':
198 uval = va_arg(ap, int);
199 while (fwidth > 1 && uval < (1 << (fwidth - 1) * 4)) {
200 buf[d++] = prefix0 ? '0' : ' ';
201 fwidth--;
202 }
203 for (j = 1; j < 8 && uval >= (1 << j * 4); j++)
204 ;
205 for (j--; j >= 0; j--)
206 buf[d++] = hexchars[(uval >> j * 4) & 0x0f];
207 break;
208 case 's':
209 s = va_arg(ap, char *);
210 while (*s && d < PRINTF_LEN)
211 buf[d++] = *s++;
212 break;
213 default:
214 // don't handle, for now
215 d++;
216 va_arg(ap, void *);
217 break;
218 }
219 }
220 buf[d] = 0;
221 va_end(ap);
222
223 if (d != 0) {
224 // line without \n
225 VDP_drawTextML(buf, APLANE, printf_xpos,
226 printf_ypos & (PLANE_H - 1));
227 printf_xpos += d;
228 }
229
230 return d; // wrong..
231}
232
233static const char *exc_names[] = {
234 NULL,
235 NULL,
236 "Bus Error",
237 "Address Error",
238 "Illegal Instruction",
239 "Zero Divide",
240 "CHK Instruction",
241 "TRAPV Instruction",
242 "Privilege Violation", /* 8 8 */
243 "Trace",
244 "Line 1010 Emulator",
245 "Line 1111 Emulator",
246 NULL,
247 NULL,
248 NULL,
249 "Uninitialized Interrupt",
250 NULL, /* 10 16 */
251 NULL,
252 NULL,
253 NULL,
254 NULL,
255 NULL,
256 NULL,
257 NULL,
258 "Spurious Interrupt", /* 18 24 */
259 "l1 irq",
260 "l2 irq",
261 "l3 irq",
262 "l4 irq",
263 "l5 irq",
264 "l6 irq",
265 "l7 irq",
266};
267
268struct exc_frame {
269 u32 dr[8];
270 u32 ar[8];
271 u16 ecxnum; // from handler
272 union {
273 struct {
274 u16 sr;
275 u32 pc;
276 } g _packed;
277 struct {
278 u16 fc;
279 u32 addr;
280 u16 ir;
281 u16 sr;
282 u32 pc;
283 } bae _packed; // bus/address error frame
284 };
285} _packed;
286
287int xtttt(void) { return sizeof(struct exc_frame); }
288
289void exception(const struct exc_frame *f)
290{
291 int i;
292
293 while (read16(GFX_CTRL_PORT) & 2)
294 ;
295 write16(GFX_CTRL_PORT, 0x8000 | (VDP_MODE1 << 8) | 0x04);
296 write16(GFX_CTRL_PORT, 0x8000 | (VDP_MODE2 << 8) | 0x44);
297 /* adjust scroll */
298 write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0));
299 write16(GFX_DATA_PORT,
300 printf_ypos >= CSCREEN_H ?
301 (printf_ypos - CSCREEN_H + 1) * 8 : 0);
302
303 printf("exception %i ", f->ecxnum);
304 if (f->ecxnum < ARRAY_SIZE(exc_names) && exc_names[f->ecxnum] != NULL)
305 printf("(%s)", exc_names[f->ecxnum]);
306 if (f->ecxnum < 4)
307 printf(" (%s)", (f->bae.fc & 0x10) ? "r" : "w");
308 printf(" \n");
309
310 if (f->ecxnum < 4) {
311 printf(" PC: %08x SR: %04x \n", f->bae.pc, f->bae.sr);
312 printf("addr: %08x IR: %04x FC: %02x \n",
313 f->bae.addr, f->bae.ir, f->bae.fc);
314 }
315 else {
316 printf(" PC: %08x SR: %04x \n", f->g.pc, f->g.sr);
317 }
318 for (i = 0; i < 8; i++)
319 printf(" D%d: %08x A%d: %08x \n", i, f->dr[i], i, f->ar[i]);
320 printf(" \n");
321}
322
323extern u32 font_base[];
324extern u8 test_data[];
325extern u8 test_data_end[];
326
327static void simple_test(int *odd, int *even, int *rom)
328{
329 u32 old, new, v0, v1;
330
331 *odd = *even = *rom = 0;
332 old = read16(0x200000);
333 new = old ^ 0xa55a;
334 write16(0x200000, new);
335 v0 = read16(0x200000);
336 write8(0x200000, ~new >> 8);
337 write8(0x200001, ~new);
338 //write16(0x200000, ~new);
339 v1 = read16(0x200000);
340 if (((v0 ^ new) & 0xff00) == 0 && ((v1 ^ ~new) & 0xff00) == 0) {
341 printf(" even");
342 *even = 1;
343 }
344 if (((v0 ^ new) & 0x00ff) == 0 && ((v1 ^ ~new) & 0x00ff) == 0) {
345 printf(" odd");
346 *odd = 1;
347 }
348 if (v0 == old && v1 == old) {
349 printf(" ROM");
350 *rom = 1;
351 }
352 else if (!(*odd | *even)) {
353 text_pal = 2;
354 printf(" bad value");
355 text_pal = 0;
356 }
357}
358
359static int detect_size(u8 *a)
360{
361 int i, v;
362
363 write8(a, 0);
364 for (i = 2, v = 1; i < 0x200000; i <<= 1, v++) {
365 write8(a + i, v);
366 if (read8(a) || read8(a + i) != v)
367 break;
368 }
369 return i > 2 ? i / 2 : 0;
370}
371
372static unused void fill(u8 *d, unsigned int size, u8 val)
373{
374 unsigned int i;
375
376 for (i = 0; i < size * 2; i += 2)
377 d[i] = val;
378}
379
380static int check(u8 *d, unsigned int size, u8 val)
381{
382 unsigned int i;
383
384 for (i = 0; i < size * 2; i += 2)
385 if (d[i] != val)
386 break;
387
388 if (i == size * 2)
389 return 1;
390
391 text_pal = 2;
392 printf("\nfailed at byte %x, val %02x vs %02x\n",
393 i / 2, d[i], val);
394 text_pal = 0;
395 return 0;
396}
397
398static void do_test(u8 *d, unsigned int size)
399{
400 int spos = printf_xpos;
401 int i;
402
403 for (i = 0; i < 0x100; i++) {
404 printf_xpos = spos;
405 printf("%02x", i);
406 //fill(d, size, i);
407 fillpx16(d, size / 16, i);
408 if (!checkpx4(d, size / 4, i)) {
409 check(d, size, i); // for log
410 break;
411 }
412 }
413}
414
415int main()
416{
417 volatile u32 *vptr32;
418 int odd, even, rom;
419 u32 old;
420 int i;
421
422 /* z80 */
423 write16(0xa11100, 0x100);
424 write16(0xa11200, 0);
425
426 /* setup VDP */
427 while (read16(GFX_CTRL_PORT) & 2)
428 ;
429
430 VDP_setReg(VDP_MODE1, 0x04);
431 VDP_setReg(VDP_MODE2, 0x44);
432 VDP_setReg(VDP_MODE3, 0x00);
433 VDP_setReg(VDP_MODE4, 0x81);
434 VDP_setReg(VDP_NT_SCROLLA, APLANE >> 10);
435 VDP_setReg(VDP_NT_SCROLLB, BPLANE >> 13);
436 VDP_setReg(VDP_SAT_BASE, SLIST >> 9);
437 VDP_setReg(VDP_HSCROLL, HSCRL >> 10);
438 VDP_setReg(VDP_AUTOINC, 2);
439 VDP_setReg(VDP_SCROLLSZ, 0x01);
440 VDP_setReg(VDP_BACKDROP, 0);
441
442 /* clear name tables */
443 write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(APLANE));
444 for (i = 0; i < PLANE_W * PLANE_H / 2; i++)
445 write32(GFX_DATA_PORT, 0);
446
447 write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(BPLANE));
448 for (i = 0; i < PLANE_W * PLANE_H / 2; i++)
449 write32(GFX_DATA_PORT, 0);
450
451 /* SAT, h. scroll */
452 write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(SLIST));
453 write32(GFX_DATA_PORT, 0);
454
455 write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(HSCRL));
456 write32(GFX_DATA_PORT, 0);
457
458 /* scroll plane vscroll */
459 write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0));
460 write32(GFX_DATA_PORT, 0);
461 printf_xpos = printf_ypos = 0;
462
463 /* load font */
464 write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(TILE_FONT_BASE));
465 for (i = 0; i < FONT_LEN * 32 / 4; i++)
466 write32(GFX_DATA_PORT, font_base[i]);
467
468 /* set colors */
469 write32(GFX_CTRL_PORT, GFX_WRITE_CRAM_ADDR(0));
470 write32(GFX_DATA_PORT, 0);
471 write32(GFX_CTRL_PORT, GFX_WRITE_CRAM_ADDR(15 * 2)); // font normal
472 write16(GFX_DATA_PORT, 0xeee);
473 write32(GFX_CTRL_PORT, GFX_WRITE_CRAM_ADDR(31 * 2)); // green
474 write16(GFX_DATA_PORT, 0x0e0);
475 write32(GFX_CTRL_PORT, GFX_WRITE_CRAM_ADDR(47 * 2)); // red
476 write16(GFX_DATA_PORT, 0x00e);
477 text_pal = 0;
478
479 printf("\n");
480 printf("MD version: %02x\n", read8(0xa10001));
481 printf("ROM writable? ");
482
483 vptr32 = (void *)0x120;
484 old = *vptr32;
485 *vptr32 ^= ~0;
486 printf("%s\n", *vptr32 == old ? "no" : "yes");
487
488 printf("200000 initial state:");
489 simple_test(&odd, &even, &rom);
490
491 printf("\nenable with i0: ");
492 write_rreg_i0(1);
493 simple_test(&odd, &even, &rom);
494
495 printf("\ndisable with i0:");
496 write_rreg_i0(0);
497 simple_test(&odd, &even, &rom);
498
499 printf("\nenable with i1: ");
500 write_rreg_i1(1);
501 simple_test(&odd, &even, &rom);
502
503 printf("\ndisable with i1:");
504 write_rreg_i1(0);
505 simple_test(&odd, &even, &rom);
506
507 printf("\nenable with 16: ");
508 write16(0xa130f0, 1);
509 simple_test(&odd, &even, &rom);
510 printf("\n");
511
512 if (even) {
513 even = detect_size((void *)0x200000);
514 printf("detected even size: %d\n", even);
515 }
516 if (odd) {
517 odd = detect_size((void *)0x200001);
518 printf("detected odd size: %d\n", odd);
519 }
520 if (even) {
521 printf("testing even: ", even);
522 do_test((void *)0x200000, even);
523 printf("\n");
524 }
525 if (odd) {
526 printf("testing odd: ", odd);
527 do_test((void *)0x200001, odd);
528 printf("\n");
529 }
530
531 if (!odd && !even) {
532 text_pal = 2;
533 printf("no RAM\n");
534 text_pal = 0;
535 }
536
537 printf("done.\n");
538
539 for (;;)
540 ;
541
542 return 0;
543}
544
545// vim:ts=4:sw=4:expandtab