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