1 /*
2  * test_6280.c
3  *
4  * test the "cpu6280" core.
5  */
6 
7 /* $Id: test_6280.c,v 1.4 2000/09/09 16:01:37 nyef Exp $ */
8 
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <ctype.h>
12 #include <string.h>
13 #include <stdarg.h>
14 #include "types.h"
15 #include "ui.h"
16 #include "cal.h"
17 #include "cpu6280int.h"
18 #include "tool.h"
19 
20 #define MAX_MEMLOCS 32
21 
22 cal_cpu test_cpu;
23 struct cpu6280_context *context;
24 
25 u8 page_0[0x200];
26 
27 u32 system_flags;
28 
29 int did_test_fail;
30 int num_passed;
31 int num_failed;
32 int in_test;
33 
34 char cur_test[256];
35 
36 int cur_line;
37 
38 typedef void (*testfunc)(void);
39 
40 struct memloc {
41     u32 address;
42     u8 data;
43 };
44 
45 struct memloc memlocs[MAX_MEMLOCS];
46 int memlocs_used;
47 
48 #define SET_MEMORY(addr, data8) do { memlocs[memlocs_used].data = data8; memlocs[memlocs_used].address = addr; memlocs_used++; if (addr < 0x200) page_0[addr] = data8; } while (0)
49 
test_read8(cal_cpu cpu,u32 address)50 u8 test_read8(cal_cpu cpu, u32 address)
51 {
52     int i;
53     u32 addr;
54 
55     addr = address & 0xffffff;
56 
57     if (addr < 0x0200) {
58 	return page_0[addr];
59     }
60 
61     for (i = 0; i < memlocs_used; i++) {
62 	if (memlocs[i].address == addr) {
63 	    return memlocs[i].data;
64 	}
65     }
66 
67     printf("read8 access to unknown location 0x%06lx.\n", addr);
68 
69     did_test_fail = 1;
70 
71     return 0;
72 }
73 
test_write8(cal_cpu cpu,u32 address,u8 data)74 void test_write8(cal_cpu cpu, u32 address, u8 data)
75 {
76     int i;
77     u32 addr;
78 
79     addr = address & 0xffffff;
80 
81     if (addr < 0x0200) {
82 	page_0[addr] = data;
83     }
84 
85     for (i = 0; i < memlocs_used; i++) {
86 	if (memlocs[i].address == addr) {
87 	    memlocs[i].data = data;
88 	    return;
89 	}
90     }
91 
92     printf("write8 access 0x%02x to unknown location 0x%06lx.\n", data, addr);
93 
94     did_test_fail = 1;
95 }
96 
97 memread8_t read8table[1] = {test_read8};
98 memwrite8_t write8table[1] = {test_write8};
99 
pce_st0_hack(u8 data)100 void pce_st0_hack(u8 data) { } /* required to link */
pce_st1_hack(u8 data)101 void pce_st1_hack(u8 data) { } /* required to link */
pce_st2_hack(u8 data)102 void pce_st2_hack(u8 data) { } /* required to link */
103 
clear_cpu(void)104 void clear_cpu(void)
105 {
106     bzero(page_0, sizeof(page_0));
107 
108     context->reg_a = 0x00;
109     context->reg_x = 0x00;
110     context->reg_y = 0x00;
111     context->reg_s = 0xff;
112 
113     context->pc = 0;
114     context->flags = 0;
115 
116     context->cycles_left = 0;
117 
118     memlocs_used = 0;
119 }
120 
deb_printf(const char * fmt,...)121 void deb_printf(const char *fmt, ...)
122 {
123     va_list args;
124 
125     va_start(args, fmt);
126     vprintf(fmt, args);
127     va_end(args);
128 
129     did_test_fail = 1;
130 }
131 
strip_blanks(char * buf)132 char *strip_blanks(char *buf)
133 {
134     char *bufptr;
135 
136     bufptr = buf;
137 
138     while (isblank(*bufptr)) {
139 	bufptr++;
140     }
141 
142     return bufptr;
143 }
144 
145 typedef int (*line_handler)(char *);
146 
147 struct parse_table {
148     char *match;
149     line_handler handler;
150 };
151 
do_start(char * buf)152 int do_start(char *buf)
153 {
154     if (in_test) {
155 	printf("start found while already in test.\n");
156 	return 1;
157     }
158 
159     if (!*buf) {
160 	printf("test has no name.\n");
161 	return 1;
162     }
163 
164     strcpy(cur_test, buf);
165 
166     did_test_fail = 0;
167     clear_cpu();
168     in_test = 1;
169     return 0;
170 }
171 
do_set_reg(char * buf)172 int do_set_reg(char *buf)
173 {
174     u8 *reg;
175     char *bufptr;
176 
177     if (buf[0] == 'a') {
178 	reg = &context->reg_a;
179     } else if (buf[0] == 'x') {
180 	reg = &context->reg_x;
181     } else if (buf[0] == 'y') {
182 	reg = &context->reg_y;
183     } else if (buf[0] == 's') {
184 	reg = &context->reg_s;
185     } else {
186 	printf("unknown reg.\n");
187 	return 1;
188     }
189 
190     bufptr = buf + 1;
191 
192     bufptr = strip_blanks(bufptr);
193 
194     if (*bufptr != '=') {
195 	printf("expected '='.\n");
196 	return 1;
197     }
198 
199     bufptr++;
200 
201     bufptr = strip_blanks(bufptr);
202 
203     *reg = strtoul(bufptr, &bufptr, 0);
204 
205     return 0;
206 }
207 
do_set_mem(char * buf)208 int do_set_mem(char *buf)
209 {
210     char *bufptr;
211     unsigned long addr;
212     unsigned short data;
213 
214     addr = strtoul(buf, &bufptr, 0);
215 
216     bufptr = strip_blanks(bufptr);
217 
218     if (*bufptr != '=') {
219 	printf("expected '='.\n");
220 	return 1;
221     }
222 
223     bufptr++;
224 
225     bufptr = strip_blanks(bufptr);
226 
227     data = strtoul(bufptr, &bufptr, 0);
228 
229     SET_MEMORY(addr, data);
230 
231     return 0;
232 }
233 
do_set_flags(char * buf)234 int do_set_flags(char *buf)
235 {
236     u8 flags;
237 
238     flags = strtoul(buf, NULL, 0);
239 
240     SET_FLAGS(context, flags);
241 
242     return 0;
243 }
244 
do_set_cycles(char * buf)245 int do_set_cycles(char *buf)
246 {
247     if (!isdigit(*buf)) {
248 	printf("expected number.\n");
249 	return 1;
250     }
251 
252     context->cycles_left = strtol(buf, NULL, 0);
253 
254     return 0;
255 }
256 
do_set_pc(char * buf)257 int do_set_pc(char *buf)
258 {
259     context->pc = strtoul(buf, NULL, 0);
260 
261     return 0;
262 }
263 
264 struct parse_table set_line_types[] = {
265     {"reg",      do_set_reg},
266     {"register", do_set_reg},
267     {"mem",      do_set_mem},
268     {"memory",   do_set_mem},
269     {"pc",       do_set_pc},
270     {"cycles",   do_set_cycles},
271     {"flags",    do_set_flags},
272     {NULL, NULL}, /* must be last entry */
273 };
274 
do_set(char * buf)275 int do_set(char *buf)
276 {
277     struct parse_table *cur_match;
278     char *bufptr;
279     int match_len;
280 
281     if (!in_test) {
282 	printf("set found while not in test.\n");
283 	return 1;
284     }
285 
286     bufptr = buf;
287 
288     for (cur_match = set_line_types; cur_match->match; cur_match++) {
289 	match_len = strlen(cur_match->match);
290 	if (!strncmp(bufptr, cur_match->match, match_len)) {
291 	    if (bufptr[match_len] && (!isblank(bufptr[match_len]))) {
292 		continue;
293 	    }
294 
295 	    bufptr += match_len;
296 	    bufptr = strip_blanks(bufptr);
297 
298 	    return cur_match->handler(bufptr);
299 	}
300     }
301 
302     return 1;
303 }
304 
do_run(char * buf)305 int do_run(char *buf)
306 {
307     if (!in_test) {
308 	printf("run found while not in test.\n");
309 	return 1;
310     }
311 
312     cpu6280_step(context);
313     return 0;
314 }
315 
do_check_reg(char * buf)316 int do_check_reg(char *buf)
317 {
318     u8 *reg;
319     u8 data;
320     char *bufptr;
321 
322     if (buf[0] == 'a') {
323 	reg = &context->reg_a;
324     } else if (buf[0] == 'x') {
325 	reg = &context->reg_x;
326     } else if (buf[0] == 'y') {
327 	reg = &context->reg_y;
328     } else if (buf[0] == 's') {
329 	reg = &context->reg_s;
330     } else {
331 	printf("unknown reg.\n");
332 	return 1;
333     }
334 
335     bufptr = buf + 1;
336 
337     bufptr = strip_blanks(bufptr);
338 
339     if (*bufptr != '=') {
340 	printf("expected '='.\n");
341 	return 1;
342     }
343 
344     bufptr++;
345 
346     bufptr = strip_blanks(bufptr);
347 
348     data = strtoul(bufptr, &bufptr, 0);
349 
350     if (*reg != data) {
351 	printf("check reg: expected 0x%02x, found 0x%02x.\n", data, *reg);
352 	did_test_fail = 1;
353     }
354 
355     return 0;
356 }
357 
do_check_mem(char * buf)358 int do_check_mem(char *buf)
359 {
360     char *bufptr;
361     unsigned long addr;
362     u8 data;
363     u8 data2;
364 
365     addr = strtoul(buf, &bufptr, 0);
366 
367     bufptr = strip_blanks(bufptr);
368 
369     if (*bufptr != '=') {
370 	printf("expected '='.\n");
371 	return 1;
372     }
373 
374     bufptr++;
375 
376     bufptr = strip_blanks(bufptr);
377 
378     data = strtoul(bufptr, &bufptr, 0);
379     data2 = test_read8(NULL, addr);
380 
381     if (data != data2) {
382 	printf("check mem: expected 0x%02x, found 0x%02x.\n", data, data2);
383 	did_test_fail = 1;
384     }
385 
386     return 0;
387 }
388 
do_check_flags(char * buf)389 int do_check_flags(char *buf)
390 {
391     u8 data;
392     u8 flags;
393 
394     if (!isdigit(*buf)) {
395 	printf("expected number.\n");
396 	return 1;
397     }
398 
399     data = strtoul(buf, NULL, 0);
400     flags = GET_FLAGS(context);
401 
402     if (data != flags) {
403 	printf("check flags: expected 0x%02x, found 0x%02x.\n", data, flags);
404 	did_test_fail = 1;
405     }
406 
407     return 0;
408 }
409 
do_check_cycles(char * buf)410 int do_check_cycles(char *buf)
411 {
412     int data;
413 
414     data = strtol(buf, NULL, 0);
415 
416     if (data != context->cycles_left) {
417 	printf("check cycles: expected 0x%04x, found 0x%04x.\n", data, context->cycles_left);
418 	did_test_fail = 1;
419     }
420 
421     return 0;
422 }
423 
do_check_pc(char * buf)424 int do_check_pc(char *buf)
425 {
426     u16 data;
427 
428     data = strtoul(buf, NULL, 0);
429 
430     if (data != context->pc) {
431 	printf("check pc: expected 0x%04hx, found 0x%04hx.\n", data, context->pc);
432 	did_test_fail = 1;
433     }
434 
435     return 0;
436 }
437 
438 struct parse_table check_line_types[] = {
439     {"reg",      do_check_reg},
440     {"register", do_check_reg},
441     {"mem",      do_check_mem},
442     {"memory",   do_check_mem},
443     {"pc",       do_check_pc},
444     {"cycles",   do_check_cycles},
445     {"flags",    do_check_flags},
446     {NULL, NULL}, /* must be last entry */
447 };
448 
do_check(char * buf)449 int do_check(char *buf)
450 {
451     struct parse_table *cur_match;
452     char *bufptr;
453     int match_len;
454 
455     if (!in_test) {
456 	printf("check found while not in test.\n");
457 	return 1;
458     }
459 
460     bufptr = buf;
461 
462     for (cur_match = check_line_types; cur_match->match; cur_match++) {
463 	match_len = strlen(cur_match->match);
464 	if (!strncmp(bufptr, cur_match->match, match_len)) {
465 	    if (bufptr[match_len] && (!isblank(bufptr[match_len]))) {
466 		continue;
467 	    }
468 
469 	    bufptr += match_len;
470 	    bufptr = strip_blanks(bufptr);
471 
472 	    return cur_match->handler(bufptr);
473 	}
474     }
475 
476     return 1;
477 }
478 
do_done(char * buf)479 int do_done(char *buf)
480 {
481     if (!in_test) {
482 	printf("done found while not in test.\n");
483 	return 1;
484     }
485 
486     if (did_test_fail) {
487 	printf("test \"%s\" failed.\n", cur_test);
488 	num_failed++;
489     } else {
490 	num_passed++;
491     }
492 
493     in_test = 0;
494 
495     return 0;
496 }
497 
498 struct parse_table line_types[] = {
499     {"start", do_start},
500     {"set",   do_set},
501     {"run",   do_run},
502     {"check", do_check},
503     {"done",  do_done}, /* Do Done is a song by Kudo Shizuka */
504     {NULL, NULL}, /* must be last entry */
505 };
506 
parse_test_file_line(char * buf)507 int parse_test_file_line(char *buf)
508 {
509     struct parse_table *cur_match;
510     char *bufptr;
511     int match_len;
512 
513     bufptr = buf;
514 
515     bufptr = strip_blanks(bufptr);
516 
517     if (!*bufptr) {
518 	/* blank line, no action */
519 	return 0;
520     }
521 
522     if (*bufptr == '#') {
523 	/* comment, no action */
524 	return 0;
525     }
526 
527     for (cur_match = line_types; cur_match->match; cur_match++) {
528 	match_len = strlen(cur_match->match);
529 	if (!strncmp(bufptr, cur_match->match, match_len)) {
530 	    if (bufptr[match_len] && (!isblank(bufptr[match_len]))) {
531 		continue;
532 	    }
533 
534 	    bufptr += match_len;
535 	    bufptr = strip_blanks(bufptr);
536 
537 	    return cur_match->handler(bufptr);
538 	}
539     }
540 
541     return 1;
542 }
543 
parse_test_file(FILE * testfile)544 void parse_test_file(FILE *testfile)
545 {
546     char buf[256];
547 
548     in_test = 0;
549 
550     while (!feof(testfile)) {
551 	cur_line++;
552 	if (!fgets(buf, 256, testfile)) {
553 	    return;
554 	}
555 	if (buf[strlen(buf) - 1] == '\n') {
556 	    buf[strlen(buf) - 1] = '\0';
557 	}
558 	if (parse_test_file_line(buf)) {
559 	    printf("Syntax error, line %d.\n", cur_line);
560 	    did_test_fail = 1;
561 	}
562     }
563 }
564 
create_cpu(void)565 void create_cpu(void)
566 {
567     test_cpu = calloc(sizeof(struct cal_cpu), 1);
568 
569     cal_cpu6280_init(&test_cpu);
570     context = test_cpu->data.d_cpu6280;
571 
572     test_cpu->setmmu8(test_cpu, 0, 0, read8table, write8table);
573     test_cpu->setzpage(test_cpu, page_0);
574 }
575 
main(int argc,char * argv[])576 int main(int argc, char *argv[])
577 {
578     num_passed = 0;
579     num_failed = 0;
580 
581     create_cpu();
582 
583     printf("Running tests...\n");
584 
585     parse_test_file(stdin);
586 
587     if (in_test) {
588 	printf("Still in test at EOF.\n");
589 	printf("Syntax error, line %d.\n", cur_line + 1);
590 	num_failed++;
591     }
592 
593     printf("Summary: %d passed, %d failed, %d total.\n", num_passed, num_failed, num_passed + num_failed);
594 
595     return 0;
596 }
597 
598 /*
599  * $Log: test_6280.c,v $
600  * Revision 1.4  2000/09/09 16:01:37  nyef
601  * converted to use lazy flag evaluation
602  *
603  * Revision 1.3  2000/01/24 05:05:31  nyef
604  * added pce_st[012]_hack() to quash linker errors
605  *
606  * Revision 1.2  2000/01/21 03:20:55  nyef
607  * fixed zpage access and flag mismatch debug output
608  *
609  * Revision 1.1  2000/01/17 01:07:33  nyef
610  * Initial revision
611  *
612  */
613