megaed-sv: input latency test
[megadrive.git] / megaed-sv / main.c
CommitLineData
ab6ed3c4 1#include <stdarg.h>
2
3#define u8 unsigned char
4#define u16 unsigned short
5#define u32 unsigned int
6
7#define noinline __attribute__((noinline))
8
9#include "edos.h"
51f3a685 10#include "asmtools.h"
ab6ed3c4 11
12#define GFX_DATA_PORT 0xC00000
13#define GFX_CTRL_PORT 0xC00004
14
15#define TILE_MEM_END 0xB000
16
17#define FONT_LEN 128
18#define TILE_FONT_BASE (TILE_MEM_END / 32 - FONT_LEN)
19
20/* note: using ED menu's layout here.. */
21#define WPLAN (TILE_MEM_END + 0x0000)
22#define HSCRL (TILE_MEM_END + 0x0800)
23#define SLIST (TILE_MEM_END + 0x0C00)
24#define APLANE (TILE_MEM_END + 0x1000)
25#define BPLANE (TILE_MEM_END + 0x3000)
26
27#define write16(a, d) \
28 *((volatile u16 *) (a)) = (d)
29#define write32(a, d) \
30 *((volatile u32 *) (a)) = (d)
31
32#define GFX_WRITE_VRAM_ADDR(adr) \
33 (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x00)
34#define GFX_WRITE_VSRAM_ADDR(adr) \
35 (((0x4000 | ((adr) & 0x3FFF)) << 16) | ((adr) >> 14) | 0x10)
36
37enum {
38 VDP_MODE1 = 0x00,
39 VDP_MODE2 = 0x01,
40 VDP_BACKDROP = 0x07,
41 VDP_MODE3 = 0x0b,
42 VDP_MODE4 = 0x0c,
43 VDP_AUTOINC = 0x0f,
44 VDP_SCROLLSZ = 0x10,
45};
46
47/* cell counts */
48#define LEFT_BORDER 1 /* lame TV */
49#define PLANE_W 64
50#define PLANE_H 32
51#define CSCREEN_H 28
52
53static noinline void VDP_drawTextML(const char *str, u16 plane_base,
54 u16 x, u16 y)
55{
56 const u8 *src = (const u8 *)str;
57 u16 basetile = 0;
58 int max_len = 40 - LEFT_BORDER;
59 int len;
60 u32 addr;
61
62 x += LEFT_BORDER;
63
64 for (len = 0; str[len] && len < max_len; len++)
65 ;
66 if (len > (PLANE_W - x))
67 len = PLANE_W - x;
68
69 addr = plane_base + ((x + (PLANE_W * y)) << 1);
70 write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(addr));
71
72 while (len-- > 0) {
73 write16(GFX_DATA_PORT,
74 basetile | ((*src++) - 32 + TILE_FONT_BASE));
75 }
76}
77
78static int printf_ypos;
79
80static void printf_line(int x, const char *buf)
81{
82 u32 addr;
83 int i;
84
ab6ed3c4 85 VDP_drawTextML(buf, APLANE, x, printf_ypos++ & (PLANE_H - 1));
86
87 if (printf_ypos >= CSCREEN_H) {
88 /* clear next line */
89 addr = APLANE;
90 addr += (PLANE_W * (printf_ypos & (PLANE_H - 1))) << 1;
91 write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(addr));
92 for (i = 0; i < 40 / 2; i++)
93 write32(GFX_DATA_PORT, 0);
94
95 /* scroll plane */
96 write32(GFX_CTRL_PORT, GFX_WRITE_VSRAM_ADDR(0));
97 write16(GFX_DATA_PORT, (printf_ypos - 27) * 8);
98 }
99}
100
51f3a685 101#define PRINTF_LEN 40
102
ab6ed3c4 103static noinline int printf(const char *fmt, ...)
104{
51f3a685 105 static const char hexchars[] = "0123456789abcdef";
ab6ed3c4 106 static int printf_xpos;
51f3a685 107 char c, buf[PRINTF_LEN + 11 + 1];
108 const char *s;
ab6ed3c4 109 va_list ap;
110 int ival;
51f3a685 111 u32 uval;
ab6ed3c4 112 int d = 0;
51f3a685 113 int i, j;
ab6ed3c4 114
115 va_start(ap, fmt);
116 for (d = 0; *fmt; ) {
51f3a685 117 int prefix0 = 0;
118 int fwidth = 0;
119
120 c = *fmt++;
121 if (d < PRINTF_LEN)
122 buf[d] = c;
123
124 if (c != '%') {
125 if (c == '\n') {
ab6ed3c4 126 buf[d] = 0;
51f3a685 127 printf_line(printf_xpos, buf);
ab6ed3c4 128 d = 0;
129 printf_xpos = 0;
130 continue;
131 }
132 d++;
133 continue;
134 }
51f3a685 135 if (d >= PRINTF_LEN)
136 continue;
137
138 if (*fmt == '0') {
139 prefix0 = 1;
140 fmt++;
141 }
142
143 while ('1' <= *fmt && *fmt <= '9') {
144 fwidth = fwidth * 10 + *fmt - '0';
145 fmt++;
146 }
ab6ed3c4 147
148 switch (*fmt++) {
149 case '%':
150 d++;
151 break;
152 case 'd':
153 case 'i':
154 ival = va_arg(ap, int);
155 if (ival < 0) {
156 buf[d++] = '-';
157 ival = -ival;
158 }
159 for (i = 1000000000; i >= 10; i /= 10)
160 if (ival >= i)
161 break;
162 for (; i >= 10; i /= 10) {
163 buf[d++] = '0' + ival / i;
164 ival %= i;
165 }
166 buf[d++] = '0' + ival;
167 break;
51f3a685 168 case 'x':
169 uval = va_arg(ap, int);
170 while (fwidth > 0 && uval < (1 << (fwidth - 1) * 4)) {
171 buf[d++] = prefix0 ? '0' : ' ';
172 fwidth--;
173 }
174 for (j = 1; j < 8 && uval >= (1 << j * 4); j++)
175 ;
176 for (j--; j >= 0; j--)
177 buf[d++] = hexchars[(uval >> j * 4) & 0x0f];
178 break;
ab6ed3c4 179 case 's':
51f3a685 180 s = va_arg(ap, char *);
181 while (*s && d < PRINTF_LEN)
182 buf[d++] = *s++;
183 break;
ab6ed3c4 184 default:
185 // don't handle, for now
186 d++;
ab6ed3c4 187 va_arg(ap, void *);
188 break;
189 }
190 }
191 buf[d] = 0;
192 va_end(ap);
193
194 if (d != 0) {
195 // line without \n
196 VDP_drawTextML(buf, APLANE, printf_xpos,
197 printf_ypos & (PLANE_H - 1));
198 printf_xpos += d;
199 }
200
201 return d; // wrong..
202}
203
204void exception(void)
205{
206 VDP_drawTextML("============", APLANE, 0, 0);
207 VDP_drawTextML(" exception! ", APLANE, 0, 1);
208 VDP_drawTextML("============", APLANE, 0, 2);
209 while (1)
210 ;
211}
212
213void vbl(void)
214{
215}
216
51f3a685 217static int usb_read_while_ready(OsRoutine *ed,
218 void *buf_, int maxlen)
219{
220 u8 *buf = buf_;
221 int r = 0;
222
223 while (ed->usbRdReady() && r < maxlen)
224 buf[r++] = ed->usbReadByte();
225
226 return r;
227}
228
229/*
230 * TH = 1 : ?1CBRLDU 3-button pad return value (not read)
231 * TH = 0 : ?0SA00DU 3-button pad return value
232 * TH = 1 : ?1CBRLDU 3-button pad return value
233 * TH = 0 : ?0SA0000 D3-0 are forced to '0'
234 * TH = 1 : ?1CBMXYZ Extra buttons returned in D3-0
235 * TH = 0 : ?0SA1111 D3-0 are forced to '1'
236 */
237static void test_joy_latency(int *min_out, int *max_out)
238{
239 u8 rbuf[8 * 6];
240 int min = 8;
241 int max = 0;
242 int i, v, b, e;
243
244 for (i = 0; i < 64; i++) {
245 read_joy_responses(rbuf);
246
247 for (b = 0; b < 8 * 4; b++) {
248 v = b & 7;
249 e = (b & 0x08) ? 0x0c : 0;
250 if ((rbuf[b] & 0x0c) == e) {
251 if (v < min)
252 min = v;
253 }
254 else if (v > max)
255 max = v;
256 }
257 }
258
259 /* print out the last test */
260 for (b = 0; b < 8 * 5; b++) {
261 printf(" %02x", rbuf[b]);
262 if ((b & 7) == 7)
263 printf("\n");
264 }
265 printf("\n");
266
267 *min_out = min;
268 *max_out = max;
269}
270
271static int do_test(OsRoutine *ed, u8 b3)
272{
273 int min = 0, max = 0;
274
275 switch (b3)
276 {
277 case 'j':
278 test_joy_latency(&min, &max);
279 printf("latency: %d - %d\n\n", min, max);
280 return 0;
281 default:
282 break;
283 }
284
285 return -1;
286}
287
ab6ed3c4 288int main()
289{
290 OsRoutine *ed;
51f3a685 291 u8 buf[16];
292 int i, d, ret;
ab6ed3c4 293
294 ed = (OsRoutine *) *(u32 *)0x1A0;
295 ed->memInitDmaCode();
296
297 ed->VDP_setReg(VDP_MODE1, 0x04);
298 ed->VDP_setReg(VDP_MODE2, 0x64);
299 ed->VDP_setReg(VDP_AUTOINC, 2);
300 ed->VDP_setReg(VDP_SCROLLSZ, 0x01);
301
302 /* clear name tables */
303 write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(APLANE));
304 for (i = 0; i < PLANE_W * PLANE_H / 2; i++)
305 write32(GFX_DATA_PORT, 0);
306
307 write32(GFX_CTRL_PORT, GFX_WRITE_VRAM_ADDR(BPLANE));
308 for (i = 0; i < PLANE_W * PLANE_H / 2; i++)
309 write32(GFX_DATA_PORT, 0);
310
311 /* note: relying on ED menu's font setup here.. */
312
ab6ed3c4 313 for (;;) {
51f3a685 314 if (!ed->usbRdReady()) {
ab6ed3c4 315 asm volatile("stop #0x2000");
51f3a685 316 continue;
317 }
318
319 buf[0] = ed->usbReadByte();
320 if (buf[0] == ' ')
321 continue;
322 if (buf[0] != '*') {
323 d = 1;
324 goto bad_input;
325 }
326
327 /* note: OS uses Twofgsr */
328 buf[1] = ed->usbReadByte();
329 switch (buf[1]) {
330 case 'T':
331 ed->usbWriteByte('k');
332 break;
333 /* custom */
334 case 't':
335 buf[2] = ed->usbReadByte();
336 ret = do_test(ed, buf[2]);
337 if (ret != 0) {
338 d = 3;
339 goto bad_input;
340 }
341 ed->usbWriteByte('k');
342 break;
343 default:
344 d = 2;
345 goto bad_input;
346 }
347
348 continue;
349
350bad_input:
351 ret = usb_read_while_ready(ed, buf + d, sizeof(buf) - d);
352 buf[d + ret] = 0;
353 printf("bad cmd: %s\n", buf);
354 /* consume all remaining data */
355 while (ed->usbRdReady())
356 usb_read_while_ready(ed, buf, sizeof(buf));
ab6ed3c4 357
51f3a685 358 ed->usbWriteByte('b');
ab6ed3c4 359 }
360
361 return 0;
362}
363
364// vim:ts=4:sw=4:expandtab