testpico: more on timer reload
[megadrive.git] / megaed-stop / main.c
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 #include "edos.h"
13
14 #define GFX_DATA_PORT    0xC00000
15 #define GFX_CTRL_PORT    0xC00004
16
17 #define TILE_MEM_END     0xB000
18
19 #define FONT_LEN         128
20 #define TILE_FONT_BASE   (TILE_MEM_END / 32  - FONT_LEN)
21
22 /* note: using ED menu's layout here.. */
23 #define WPLANE           (TILE_MEM_END + 0x0000)
24 #define HSCRL            (TILE_MEM_END + 0x0800)
25 #define SLIST            (TILE_MEM_END + 0x0C00)
26 #define APLANE           (TILE_MEM_END + 0x1000)
27 #define BPLANE           (TILE_MEM_END + 0x3000)
28
29 #define read8(a) \
30     *((volatile u8 *) (a))
31 #define read16(a) \
32     *((volatile u16 *) (a))
33 #define read32(a) \
34     *((volatile u32 *) (a))
35 #define write16(a, d) \
36     *((volatile u16 *) (a)) = (d)
37 #define write32(a, d) \
38     *((volatile u32 *) (a)) = (d)
39
40 #define GFX_WRITE_VRAM_ADDR(adr) \
41     (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x00)
42 #define GFX_WRITE_VSRAM_ADDR(adr) \
43     (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x10)
44
45 enum {
46     VDP_MODE1 = 0x00,
47     VDP_MODE2 = 0x01,
48     VDP_BACKDROP = 0x07,
49     VDP_MODE3 = 0x0b,
50     VDP_MODE4 = 0x0c,
51     VDP_AUTOINC = 0x0f,
52     VDP_SCROLLSZ = 0x10,
53 };
54
55 /* cell counts */
56 #define LEFT_BORDER 1   /* lame TV */
57 #define PLANE_W 64
58 #define PLANE_H 32
59 #define CSCREEN_H 28
60
61 static void VDP_drawTextML(const char *str, u16 plane_base,
62     u16 x, u16 y)
63 {
64     const u8 *src = (const u8 *)str;
65     u16 basetile = 0;
66     int max_len = 40 - LEFT_BORDER;
67     int len;
68     u32 addr;
69
70     x += LEFT_BORDER;
71
72     for (len = 0; str[len] && len < max_len; len++)
73         ;
74     if (len > (PLANE_W - x))
75         len = PLANE_W - x;
76
77     addr = plane_base + ((x + (PLANE_W * y)) << 1);
78     write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(addr));
79
80     while (len-- > 0) {
81         write16(GFX_DATA_PORT,
82             basetile | ((*src++) - 32 + TILE_FONT_BASE / 32));
83     }
84 }
85
86 static int printf_ypos;
87
88 static void printf_line(int x, const char *buf)
89 {
90     u32 addr;
91     int i;
92
93     VDP_drawTextML(buf, APLANE, x, printf_ypos++ & (PLANE_H - 1));
94
95     if (printf_ypos >= CSCREEN_H) {
96         /* clear next line */
97         addr = APLANE;
98         addr += (PLANE_W * (printf_ypos & (PLANE_H - 1))) << 1;
99         write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(addr));
100         for (i = 0; i < 40 / 2; i++)
101             write32(GFX_DATA_PORT, 0);
102
103         /* scroll plane */
104         write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0));
105         write16(GFX_DATA_PORT, (printf_ypos - CSCREEN_H + 1) * 8);
106     }
107 }
108
109 #define PRINTF_LEN 40
110
111 static int printf(const char *fmt, ...)
112 {
113     static const char hexchars[] = "0123456789abcdef";
114     static int printf_xpos;
115     char c, buf[PRINTF_LEN + 11 + 1];
116     const char *s;
117     va_list ap;
118     int ival;
119     u32 uval;
120     int d = 0;
121     int i, j;
122
123     va_start(ap, fmt);
124     for (d = 0; *fmt; ) {
125         int prefix0 = 0;
126         int fwidth = 0;
127
128         c = *fmt++;
129         if (d < PRINTF_LEN)
130             buf[d] = c;
131
132         if (c != '%') {
133             if (c == '\n') {
134                 buf[d] = 0;
135                 printf_line(printf_xpos, buf);
136                 d = 0;
137                 printf_xpos = 0;
138                 continue;
139             }
140             d++;
141             continue;
142         }
143         if (d >= PRINTF_LEN)
144             continue;
145
146         if (*fmt == '0') {
147             prefix0 = 1;
148             fmt++;
149         }
150
151         while ('1' <= *fmt && *fmt <= '9') {
152             fwidth = fwidth * 10 + *fmt - '0';
153             fmt++;
154         }
155
156         switch (*fmt++) {
157         case '%':
158             d++;
159             break;
160         case 'd':
161         case 'i':
162             ival = va_arg(ap, int);
163             if (ival < 0) {
164                 buf[d++] = '-';
165                 ival = -ival;
166             }
167             for (i = 1000000000; i >= 10; i /= 10)
168                 if (ival >= i)
169                     break;
170             for (; i >= 10; i /= 10) {
171                 buf[d++] = '0' + ival / i;
172                 ival %= i;
173             }
174             buf[d++] = '0' + ival;
175             break;
176         case 'x':
177             uval = va_arg(ap, int);
178             while (fwidth > 1 && uval < (1 << (fwidth - 1) * 4)) {
179                 buf[d++] = prefix0 ? '0' : ' ';
180                 fwidth--;
181             }
182             for (j = 1; j < 8 && uval >= (1 << j * 4); j++)
183                 ;
184             for (j--; j >= 0; j--)
185                 buf[d++] = hexchars[(uval >> j * 4) & 0x0f];
186             break;
187         case 's':
188             s = va_arg(ap, char *);
189             while (*s && d < PRINTF_LEN)
190                 buf[d++] = *s++;
191             break;
192         default:
193             // don't handle, for now
194             d++;
195             va_arg(ap, void *);
196             break;
197         }
198     }
199     buf[d] = 0;
200     va_end(ap);
201
202     if (d != 0) {
203         // line without \n
204         VDP_drawTextML(buf, APLANE, printf_xpos,
205             printf_ypos & (PLANE_H - 1));
206         printf_xpos += d;
207     }
208
209     return d; // wrong..
210 }
211
212 int main()
213 {
214     OsRoutine *ed;
215     u8 seed, bad = 0;
216     u8 *p, val;
217     int i, t, len;
218
219     ed = (OsRoutine *) *(u32 *)0x1A0;
220     ed->memInitDmaCode(); 
221
222     ed->VDP_setReg(VDP_MODE1, 0x04); 
223     ed->VDP_setReg(VDP_MODE2, 0x64); 
224     ed->VDP_setReg(VDP_AUTOINC, 2); 
225     ed->VDP_setReg(VDP_SCROLLSZ, 0x01); 
226
227     /* clear name tables */
228     write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(APLANE));
229     for (i = 0; i < PLANE_W * PLANE_H / 2; i++)
230         write32(GFX_DATA_PORT, 0);
231
232     write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(BPLANE));
233     for (i = 0; i < PLANE_W * PLANE_H / 2; i++)
234         write32(GFX_DATA_PORT, 0);
235
236     /* scroll planes */
237     write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0));
238     write32(GFX_DATA_PORT, 0);
239
240     /* note: relying on ED menu's font setup here.. */
241
242     printf("\n");
243     printf("MD version: %02x\n", read8(0xa10001));
244     printf("ED os/fw: %d/%d\n\n", ed->osGetOsVersion(),
245            ed->osGetFirmVersion());
246
247     seed = read8(0xC00009);
248     p = (void *)0x200000;
249     len = 0x200000;
250     printf("filling SDRAM, seed=%02x.. ", seed);
251
252     val = seed;
253     for (i = 0; i < len; i++)
254         p[i] = val++;
255
256     printf("done.\n");
257
258     for (t = 1; ; t++) {
259         printf("executing stop.. ");
260         for (i = 0; i < 5 * 60; i++)
261             asm volatile("stop #0x2000");
262         printf("done\n");
263
264         printf("checking memory..\n");
265
266         val = seed;
267         for (i = 0; i < len; i++) {
268             if (p[i] != val) {
269                 printf("bad: %06x: got %02x, expected %02x\n",
270                        &p[i], p[i], val);
271                 bad = 1;
272             }
273             val++;
274         }
275
276         printf("done. Try %d: test ", t);
277         if (bad) {
278             printf("FAILED\n");
279             break;
280         }
281         printf("PASSED\n");
282     }
283
284     /* there are not enough STOP opcodes in this world :D */
285     while (1)
286         asm volatile("stop #0x2000");
287
288     return 0;
289 }
290
291 // vim:ts=4:sw=4:expandtab