altos/test: Adjust CRC error rate after FEC fix
[fw/altos] / ao-tools / ao-dbg / ao-dbg-command.c
1 /*
2  * Copyright © 2008 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include "ao-dbg.h"
20
21 static uint16_t start_address;
22
23 static enum command_result
24 parse_int(char *value, int *result)
25 {
26         char *endptr;
27
28         *result = strtol(value, &endptr, 0);
29         if (endptr == value)
30                 return command_syntax;
31         return command_success;
32 }
33
34 static enum command_result
35 parse_uint16(char *value, uint16_t *uint16)
36 {
37         int     v;
38         enum command_result result;
39
40         result = parse_int(value, &v);
41         if (result != command_success)
42                 return command_error;
43         if (v < 0 || v > 0xffff)
44                 return command_error;
45         *uint16 = v;
46         return command_success;
47 }
48
49 static enum command_result
50 parse_uint8(char *value, uint8_t *uint8)
51 {
52         int     v;
53         enum command_result result;
54
55         result = parse_int(value, &v);
56         if (result != command_success)
57                 return command_error;
58         if (v < 0 || v > 0xff)
59                 return command_error;
60         *uint8 = v;
61         return command_success;
62 }
63
64 enum command_result
65 command_quit (int argc, char **argv)
66 {
67         ccdbg_reset(s51_dbg);
68         exit(0);
69         return command_error;
70 }
71
72 static void
73 dump_bytes(uint8_t *memory, int length, uint16_t start, char *format)
74 {
75         int group, i;
76
77         for (group = 0; group < length; group += 8) {
78                 s51_printf(format, start + group);
79                 for (i = group; i < length && i < group + 8; i++)
80                         s51_printf("%02x ", memory[i]);
81                 for (; i < group + 8; i++)
82                         s51_printf("   ");
83                 for (i = group; i < length && i < group + 8; i++) {
84                         if (isascii(memory[i]) && isprint(memory[i]))
85                                 s51_printf("%c", memory[i]);
86                         else
87                                 s51_printf(".");
88                 }
89                 s51_printf("\n");
90         }
91 }
92
93 enum command_result
94 command_di (int argc, char **argv)
95 {
96         uint16_t start, end;
97         uint8_t memory[65536];
98         uint8_t status;
99         int length;
100
101         if (argc != 3)
102                 return command_error;
103         if (parse_uint16(argv[1], &start) != command_success)
104                 return command_error;
105         if (parse_uint16(argv[2], &end) != command_success)
106                 return command_error;
107         length = (int) end - (int) start + 1;
108         status = ccdbg_read_memory(s51_dbg, start + 0xff00, memory, length);
109         (void) status;
110         dump_bytes(memory, length, start, "0x%02x ");
111         return command_success;
112 }
113
114 enum command_result
115 command_ds (int argc, char **argv)
116 {
117         uint8_t start, end;
118         uint8_t memory[0x100];
119         uint8_t status;
120         int length;
121
122         if (argc != 3)
123                 return command_error;
124         if (parse_uint8(argv[1], &start) != command_success)
125                 return command_error;
126         if (parse_uint8(argv[2], &end) != command_success)
127                 return command_error;
128         length = (int) end - (int) start + 1;
129         status = ccdbg_read_sfr(s51_dbg, start, memory, length);
130         (void) status;
131         dump_bytes(memory, length, start, "0x%02x ");
132         return command_success;
133 }
134
135 enum command_result
136 command_dx (int argc, char **argv)
137 {
138         uint16_t start, end;
139         uint8_t memory[65536];
140         uint8_t status;
141         int length;
142
143         if (argc != 3)
144                 return command_error;
145         if (parse_uint16(argv[1], &start) != command_success)
146                 return command_error;
147         if (parse_uint16(argv[2], &end) != command_success)
148                 return command_error;
149         length = (int) end - (int) start + 1;
150         status = ccdbg_read_memory(s51_dbg, start, memory, length);
151         (void) status;
152         dump_bytes(memory, length, start, "0x%04x ");
153         return command_success;
154 }
155
156 enum command_result
157 command_set (int argc, char **argv)
158 {
159         uint16_t address;
160         uint8_t *data;
161         int len = argc - 3;
162         int i;
163         enum command_result ret = command_success;
164
165         if (len < 0)
166                 return command_error;
167         if (parse_uint16(argv[2], &address) != command_success)
168                 return command_error;
169         if (len == 0)
170                 return command_success;
171         data = malloc(len);
172         if (!data)
173                 return command_error;
174         for (i = 0; i < len; i++)
175                 if (parse_uint8(argv[i+3], &data[i]) != command_success)
176                         return command_error;
177
178         if (strcmp(argv[1], "xram") == 0) {
179                 ccdbg_write_memory(s51_dbg, address, data, len);
180         } else if (strcmp(argv[1], "iram") == 0) {
181                 ccdbg_write_memory(s51_dbg, address + 0xff00, data, len);
182         } else if (strcmp(argv[1], "sfr") == 0) {
183                 ccdbg_write_sfr(s51_dbg, (uint8_t) address, data, len);
184         } else
185                 ret = command_error;
186         free(data);
187         return ret;
188 }
189
190 enum command_result
191 command_dump (int argc, char **argv)
192 {
193         if (argv[1]) {
194                 if (strcmp(argv[1], "rom") == 0 ||
195                     strcmp(argv[1], "xram") == 0)
196                         return command_dx(argc-1, argv+1);
197                 if (strcmp(argv[1], "iram") == 0)
198                         return command_di(argc-1, argv+1);
199                 if (strcmp(argv[1], "sfr") == 0)
200                         return command_ds(argc-1, argv+1);
201         }
202         return command_error;
203 }
204
205 enum command_result
206 command_file (int argc, char **argv)
207 {
208         struct ao_hex_file *hex;
209         struct ao_hex_image *image;
210         FILE *file;
211
212         if (argc != 2)
213                 return command_error;
214         file = fopen (argv[1], "r");
215         if (!file)
216                 return command_error;
217         hex = ao_hex_file_read(file, argv[1]);
218         fclose(file);
219         if (!hex)
220                 return command_error;
221         if (hex->nrecord == 0) {
222                 ao_hex_file_free(hex);
223                 return command_error;
224         }
225         image = ao_hex_image_create(hex);
226         ao_hex_file_free(hex);
227         start_address = image->address;
228         ccdbg_set_rom(s51_dbg, image);
229         return command_success;
230 }
231
232 enum command_result
233 command_pc (int argc, char **argv)
234 {
235         uint16_t        pc;
236         if (argv[1]) {
237                 enum command_result result;
238                 result = parse_uint16(argv[1], &pc);
239                 if (result != command_success)
240                         return result;
241                 ccdbg_set_pc(s51_dbg, pc);
242         } else {
243                 pc = ccdbg_get_pc(s51_dbg);
244                 s51_printf("   0x%04x 00\n", pc);
245         }
246         return command_success;
247 }
248
249 struct cc_break {
250         int             enabled;
251         int             temporary;
252         uint16_t        address;
253 };
254
255 #define CC_NUM_BREAKPOINTS 4
256
257 static struct cc_break  breakpoints[CC_NUM_BREAKPOINTS];
258
259 static void
260 disable_breakpoint(int b)
261 {
262         uint8_t status;
263
264         status = ccdbg_set_hw_brkpnt(s51_dbg, b, 0, breakpoints[b].address);
265         if (status != 0x00 && status != 0xff)
266                 s51_printf("disable_breakpoint status 0x%02x\n", status);
267 }
268
269 static void
270 enable_breakpoint(int b)
271 {
272         uint8_t status;
273
274         status = ccdbg_set_hw_brkpnt(s51_dbg, b, 1, breakpoints[b].address);
275         if (status != 0xff)
276                 s51_printf("enable_breakpoint status 0x%02x\n", status);
277 }
278
279 static void
280 enable_breakpoints(void)
281 {
282         int b;
283         for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
284                 if (breakpoints[b].enabled)
285                         enable_breakpoint(b);
286 }
287
288 static enum command_result
289 set_breakpoint(uint16_t address, int temporary)
290 {
291         int b;
292         for (b = 0; b < CC_NUM_BREAKPOINTS; b++) {
293                 if (breakpoints[b].enabled == 0)
294                         break;
295                 if (breakpoints[b].address == address)
296                         break;
297         }
298         if (b == CC_NUM_BREAKPOINTS) {
299                 s51_printf("Error: too many breakpoints requested\n");
300                 return command_success;
301         }
302         if (breakpoints[b].enabled == 0) {
303                 breakpoints[b].address = address;
304                 enable_breakpoint(b);
305         }
306         ++breakpoints[b].enabled;
307         s51_printf("Breakpoint %d at 0x%04x\n", b, address);
308         breakpoints[b].temporary += temporary;
309         return command_success;
310 }
311
312 static enum command_result
313 clear_breakpoint(uint16_t address, int temporary)
314 {
315         int b;
316
317         for (b = 0; b < CC_NUM_BREAKPOINTS; b++) {
318                 if (breakpoints[b].enabled != 0 &&
319                     ((breakpoints[b].temporary != 0) == (temporary != 0)) &&
320                     breakpoints[b].address == address)
321                         break;
322         }
323         if (b == CC_NUM_BREAKPOINTS) {
324                 s51_printf("Error: no matching breakpoint found\n");
325                 return command_success;
326         }
327         --breakpoints[b].enabled;
328         breakpoints[b].temporary -= temporary;
329         if (breakpoints[b].enabled == 0) {
330                 disable_breakpoint(b);
331                 breakpoints[b].address = -1;
332         }
333         return command_success;
334 }
335
336
337 static int
338 find_breakpoint(uint16_t address)
339 {
340         int b;
341
342         for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
343                 if (breakpoints[b].enabled && breakpoints[b].address == address)
344                         break;
345         if (b == CC_NUM_BREAKPOINTS)
346                 return -1;
347         return b;
348 }
349
350 enum command_result
351 command_break (int argc, char **argv)
352 {
353         int b;
354         uint16_t address;
355         enum command_result result;
356
357         if (argc == 1) {
358                 for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
359                         if (breakpoints[b].enabled)
360                                 s51_printf("Breakpoint %d 0x%04x\n",
361                                         b, breakpoints[b].address);
362                 return command_success;
363         }
364         if (argc != 2)
365                 return command_error;
366         result = parse_uint16(argv[1], &address);
367         if (result != command_success)
368                 return result;
369
370         return set_breakpoint(address, 0);
371 }
372
373 enum command_result
374 command_clear (int argc, char **argv)
375 {
376         uint16_t address;
377         enum command_result result;
378
379         if (argc != 2)
380                 return command_error;
381         result = parse_uint16(argv[1], &address);
382         if (result != command_success)
383                 return result;
384         return clear_breakpoint(address, 0);
385 }
386
387 static void
388 cc_stopped(uint8_t status)
389 {
390         uint16_t pc;
391         int b;
392         int code;
393         char *reason;
394
395         pc = ccdbg_get_pc(s51_dbg);
396         if (status & CC_STATUS_CPU_HALTED) {
397                 if ((status & CC_STATUS_HALT_STATUS) != 0) {
398                         pc = pc - 1;
399                         code = 104;
400                         reason = "Breakpoint";
401                         b = find_breakpoint(pc);
402                         if (b != -1 && breakpoints[b].temporary)
403                                 clear_breakpoint(pc, 1);
404                         ccdbg_set_pc(s51_dbg, pc);
405                 } else {
406                         code = 105;
407                         reason = "Interrupt";
408                 }
409                 s51_printf("Stop at 0x%04x: (%d) %s\n",
410                         pc, code, reason);
411         }
412 }
413
414 static uint8_t
415 cc_step(uint16_t pc)
416 {
417         int b;
418         uint8_t status;
419
420         b = find_breakpoint(pc);
421         if (b != -1)
422                 disable_breakpoint(b);
423         status = ccdbg_step_instr(s51_dbg);
424         if (b != -1)
425                 enable_breakpoint(b);
426         return status;
427 }
428
429 enum command_result
430 command_run (int argc, char **argv)
431 {
432         uint16_t start, end;
433         enum command_result result;
434         uint16_t pc;
435         uint8_t status;
436         int b;
437
438         if (argv[1]) {
439                 result = parse_uint16(argv[1], &start);
440                 if (result != command_success)
441                         return result;
442                 if (argv[2]) {
443                         result = parse_uint16(argv[2], &end);
444                         if (result != command_success)
445                                 return result;
446                 }
447                 if (start_address && start == 0) {
448                         start = start_address;
449                         s51_printf("Starting at 0x%04x\n", start);
450                 }
451                 ccdbg_set_pc(s51_dbg, start);
452         }
453         else
454                 start = ccdbg_get_pc(s51_dbg);
455         s51_printf("Resume at 0x%04x\n", start);
456         pc = start;
457         b = find_breakpoint(pc);
458         if (b != -1) {
459                 cc_step(pc);
460                 pc = ccdbg_get_pc(s51_dbg);
461                 if (find_breakpoint(pc) != -1) {
462                         status = ccdbg_read_status(s51_dbg);
463                         cc_stopped(status);
464                         return command_success;
465                 }
466         }
467         ccdbg_resume(s51_dbg);
468         result = cc_wait();
469         return result;
470 }
471
472 enum command_result
473 command_next (int argc, char **argv)
474 {
475         return command_step(argc, argv);
476 }
477
478 enum command_result
479 command_step (int argc, char **argv)
480 {
481         uint16_t pc;
482         uint8_t opcode;
483         uint8_t a;
484
485         a = cc_step(ccdbg_get_pc(s51_dbg));
486         s51_printf(" ACC= 0x%02x\n", a);
487         pc = ccdbg_get_pc(s51_dbg);
488         ccdbg_read_memory(s51_dbg, pc, &opcode, 1);
489         s51_printf(" ? 0x%04x %02x\n", pc, opcode);
490         return command_success;
491 }
492
493 enum command_result
494 command_load (int argc, char **argv)
495 {
496         char *filename = argv[1];
497         FILE *file;
498         struct ao_hex_file      *hex;
499         struct ao_hex_image *image;
500
501         if (!filename)
502                 return command_error;
503         file = fopen(filename, "r");
504         if (!file) {
505                 perror(filename);
506                 return command_error;
507         }
508         hex = ao_hex_file_read(file, filename);
509         fclose(file);
510         if (!hex) {
511                 return command_error;
512         }
513         image = ao_hex_image_create(hex);
514         ao_hex_file_free(hex);
515         if (!image) {
516                 fprintf(stderr, "image create failed\n");
517                 return command_error;
518         }
519         if (image->address >= 0xf000) {
520                 printf("Loading %d bytes to RAM at 0x%04x\n",
521                        image->length, image->address);
522                 ccdbg_write_hex_image(s51_dbg, image, 0);
523         } else {
524                 fprintf(stderr, "Can only load to RAM\n");
525         }
526         ao_hex_image_free(image);
527         return command_success;
528 }
529
530 enum command_result
531 command_halt (int argc, char **argv)
532 {
533         uint16_t        pc;
534         ccdbg_halt(s51_dbg);
535         pc = ccdbg_get_pc(s51_dbg);
536         s51_printf("Halted at 0x%04x\n", pc);
537         return command_success;
538 }
539
540 enum command_result
541 command_stop (int argc, char **argv)
542 {
543         return command_success;
544 }
545
546 enum command_result
547 command_reset (int argc, char **argv)
548 {
549         ccdbg_debug_mode(s51_dbg);
550         ccdbg_halt(s51_dbg);
551         enable_breakpoints();
552         return command_success;
553 }
554
555 enum command_result
556 command_status(int argc, char **argv)
557 {
558         uint8_t status;
559
560         status = ccdbg_read_status(s51_dbg);
561         if ((status & CC_STATUS_CHIP_ERASE_DONE) == 0)
562                 s51_printf("\tChip erase in progress\n");
563         if (status & CC_STATUS_PCON_IDLE)
564                 s51_printf("\tCPU is idle (clock gated)\n");
565         if (status & CC_STATUS_CPU_HALTED)
566                 s51_printf("\tCPU halted\n");
567         else
568                 s51_printf("\tCPU running\n");
569         if ((status & CC_STATUS_POWER_MODE_0) == 0)
570                 s51_printf("\tPower Mode 1-3 selected\n");
571         if (status & CC_STATUS_HALT_STATUS)
572                 s51_printf("\tHalted by software or hw breakpoint\n");
573         else
574                 s51_printf("\tHalted by debug command\n");
575         if (status & CC_STATUS_DEBUG_LOCKED)
576                 s51_printf("\tDebug interface is locked\n");
577         if ((status & CC_STATUS_OSCILLATOR_STABLE) == 0)
578                 s51_printf("\tOscillators are not stable\n");
579         if (status & CC_STATUS_STACK_OVERFLOW)
580                 s51_printf("\tStack overflow\n");
581         return command_success;
582 }
583
584 static enum command_result
585 info_breakpoints(int argc, char **argv)
586 {
587         int b;
588
589         if (argc == 1) {
590                 s51_printf("Num Type       Disp Hit   Cnt   Address  What\n");
591                 for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
592                         if (breakpoints[b].enabled) {
593                                 s51_printf("%-3d fetch      %s 1     1     0x%04x   uc::disass() unimplemented\n",
594                                            b,
595                                            breakpoints[b].temporary ? "del " : "keep",
596                                            breakpoints[b].address);
597                         }
598                 return command_success;
599         }
600         return command_syntax;
601 }
602
603 static enum command_result
604 info_help(int argc, char **argv);
605
606 static struct command_function infos[] = {
607         { "breakpoints", "b", info_breakpoints, "[b]reakpoints",
608                 "List current breakpoints\n" },
609         { "help",   "?",  info_help,    "help",
610                 "Print this list\n" },
611
612         { NULL, NULL, NULL, NULL, NULL },
613 };
614
615 static enum command_result
616 info_help(int argc, char **argv)
617 {
618         return command_function_help(infos, argc, argv);
619 }
620
621 enum command_result
622 command_info(int argc, char **argv)
623 {
624         struct command_function *func;
625
626         if (argc < 2)
627                 return command_error;
628         func = command_string_to_function(infos, argv[1]);
629         if (!func)
630                 return command_syntax;
631         return (*func->func)(argc-1, argv+1);
632 }
633
634 enum command_result
635 cc_wait(void)
636 {
637         for(;;) {
638                 uint8_t status;
639                 status = ccdbg_read_status(s51_dbg);
640                 if (status & CC_STATUS_CPU_HALTED) {
641                         cc_stopped(status);
642                         return command_success;
643                 }
644                 if (s51_interrupted || s51_check_input()) {
645
646                         ccdbg_halt(s51_dbg);
647                         status = ccdbg_read_status(s51_dbg);
648                         cc_stopped(status);
649                         return command_interrupt;
650                 }
651         }
652 }