Make serial test simpler
[fw/altos] / s51 / s51-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 "s51.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         exit(0);
68         return command_error;
69 }
70
71 static void
72 dump_bytes(uint8_t *memory, int length, uint16_t start, char *format)
73 {
74         int group, i;
75         
76         for (group = 0; group < length; group += 8) {
77                 s51_printf(format, start + group);
78                 for (i = group; i < length && i < group + 8; i++)
79                         s51_printf("%02x ", memory[i]);
80                 for (; i < group + 8; i++)
81                         s51_printf("   ");
82                 for (i = group; i < length && i < group + 8; i++) {
83                         if (isascii(memory[i]) && isprint(memory[i]))
84                                 s51_printf("%c", memory[i]);
85                         else
86                                 s51_printf(".");
87                 }
88                 s51_printf("\n");
89         }
90 }
91
92 enum command_result
93 command_di (int argc, char **argv)
94 {
95         uint16_t start, end;
96         uint8_t memory[65536];
97         uint8_t status;
98         int length;
99         
100         if (argc != 3)
101                 return command_error;
102         if (parse_uint16(argv[1], &start) != command_success)
103                 return command_error;
104         if (parse_uint16(argv[2], &end) != command_success)
105                 return command_error;
106         length = (int) end - (int) start + 1;
107         status = ccdbg_read_memory(s51_dbg, start + 0xff00, memory, length);
108         dump_bytes(memory, length, start, "0x%02x ");
109         return command_success;
110 }
111
112 enum command_result
113 command_ds (int argc, char **argv)
114 {
115         uint8_t start, end;
116         uint8_t memory[0x100];
117         uint8_t status;
118         int length;
119         
120         if (argc != 3)
121                 return command_error;
122         if (parse_uint8(argv[1], &start) != command_success)
123                 return command_error;
124         if (parse_uint8(argv[2], &end) != command_success)
125                 return command_error;
126         length = (int) end - (int) start + 1;
127         status = ccdbg_read_sfr(s51_dbg, start, memory, length);
128         dump_bytes(memory, length, start, "0x%02x ");
129         return command_success;
130 }
131
132 enum command_result
133 command_dx (int argc, char **argv)
134 {
135         uint16_t start, end;
136         uint8_t memory[65536];
137         uint8_t status;
138         int length;
139         
140         if (argc != 3)
141                 return command_error;
142         if (parse_uint16(argv[1], &start) != command_success)
143                 return command_error;
144         if (parse_uint16(argv[2], &end) != command_success)
145                 return command_error;
146         length = (int) end - (int) start + 1;
147         status = ccdbg_read_memory(s51_dbg, start, memory, length);
148         dump_bytes(memory, length, start, "0x%04x ");
149         return command_success;
150 }
151
152 enum command_result
153 command_set (int argc, char **argv)
154 {
155         uint16_t address;
156         uint8_t *data;
157         int len = argc - 3;
158         int i;
159         enum command_result ret = command_success;
160
161         if (len < 0)
162                 return command_error;
163         if (parse_uint16(argv[2], &address) != command_success)
164                 return command_error;
165         if (len == 0)
166                 return command_success;
167         data = malloc(len);
168         if (!data)
169                 return command_error;
170         for (i = 0; i < len; i++)
171                 if (parse_uint8(argv[i+3], &data[i]) != command_success)
172                         return command_error;
173         
174         if (strcmp(argv[1], "xram") == 0) {
175                 ccdbg_write_memory(s51_dbg, address, data, len);
176         } else if (strcmp(argv[1], "iram") == 0) {
177                 ccdbg_write_memory(s51_dbg, address + 0xff00, data, len);
178         } else if (strcmp(argv[1], "sfr") == 0) {
179                 ccdbg_write_sfr(s51_dbg, (uint8_t) address, data, len);
180         } else
181                 ret = command_error;
182         free(data);
183         return ret;
184 }
185
186 enum command_result
187 command_dump (int argc, char **argv)
188 {
189         if (argv[1]) {
190                 if (strcmp(argv[1], "rom") == 0 ||
191                     strcmp(argv[1], "xram") == 0)
192                         return command_dx(argc-1, argv+1);
193                 if (strcmp(argv[1], "iram") == 0)
194                         return command_di(argc-1, argv+1);
195                 if (strcmp(argv[1], "sfr") == 0)
196                         return command_ds(argc-1, argv+1);
197         }
198         return command_error;
199 }
200
201 enum command_result
202 command_file (int argc, char **argv)
203 {
204         struct hex_file *hex;
205         struct hex_image *image;
206         FILE *file;
207         
208         if (argc != 2)
209                 return command_error;
210         file = fopen (argv[1], "r");
211         if (!file)
212                 return command_error;
213         hex = ccdbg_hex_file_read(file, argv[1]);
214         fclose(file);
215         if (!hex)
216                 return command_error;
217         if (hex->nrecord == 0) {
218                 ccdbg_hex_file_free(hex);
219                 return command_error;
220         }
221         image = ccdbg_hex_image_create(hex);
222         ccdbg_hex_file_free(hex);
223         start_address = image->address;
224         ccdbg_set_rom(s51_dbg, image);
225         return command_success;
226 }
227
228 enum command_result
229 command_pc (int argc, char **argv)
230 {
231         uint16_t        pc;
232         if (argv[1]) {
233                 enum command_result result;
234                 result = parse_uint16(argv[1], &pc);
235                 if (result != command_success)
236                         return result;
237                 ccdbg_set_pc(s51_dbg, pc);
238         } else {
239                 pc = ccdbg_get_pc(s51_dbg);
240                 s51_printf("   0x%04x 00\n", pc);
241         }
242         return command_success;
243 }
244
245 struct cc_break {
246         int             enabled;
247         int             temporary;
248         uint16_t        address;
249 };
250
251 #define CC_NUM_BREAKPOINTS 4
252
253 static struct cc_break  breakpoints[CC_NUM_BREAKPOINTS];
254
255 static void
256 disable_breakpoint(int b)
257 {
258         uint8_t status;
259         
260         status = ccdbg_set_hw_brkpnt(s51_dbg, b, 0, breakpoints[b].address);
261         if (status != 0x00 && status != 0xff)
262                 s51_printf("disable_breakpoint status 0x%02x\n", status);
263 }
264
265 static void
266 enable_breakpoint(int b)
267 {
268         uint8_t status;
269         
270         status = ccdbg_set_hw_brkpnt(s51_dbg, b, 1, breakpoints[b].address);
271         if (status != 0xff)
272                 s51_printf("enable_breakpoint status 0x%02x\n", status);
273 }
274
275 static void
276 enable_breakpoints(void)
277 {
278         int b;
279         for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
280                 if (breakpoints[b].enabled)
281                         enable_breakpoint(b);
282 }
283
284 enum command_result
285 set_breakpoint(uint16_t address, int temporary)
286 {
287         int b;
288         uint8_t status;
289         for (b = 0; b < CC_NUM_BREAKPOINTS; b++) {
290                 if (breakpoints[b].enabled == 0)
291                         break;
292                 if (breakpoints[b].address == address)
293                         break;
294         }
295         if (b == CC_NUM_BREAKPOINTS) {
296                 s51_printf("Error: too many breakpoints requested\n");
297                 return command_success;
298         }
299         if (breakpoints[b].enabled == 0) {
300                 breakpoints[b].address = address;
301                 enable_breakpoint(b);
302         }
303         ++breakpoints[b].enabled;
304         s51_printf("Breakpoint %d at 0x%04x\n", b, address);
305         breakpoints[b].temporary += temporary;
306         return command_success;
307 }
308
309 enum command_result
310 clear_breakpoint(uint16_t address, int temporary)
311 {
312         int b;
313         uint8_t status;
314
315         for (b = 0; b < CC_NUM_BREAKPOINTS; b++) {
316                 if (breakpoints[b].enabled != 0 &&
317                     ((breakpoints[b].temporary != 0) == (temporary != 0)) &&
318                     breakpoints[b].address == address)
319                         break;
320         }
321         if (b == CC_NUM_BREAKPOINTS) {
322                 s51_printf("Error: no matching breakpoint found\n");
323                 return command_success;
324         }
325         --breakpoints[b].enabled;
326         breakpoints[b].temporary -= temporary;
327         if (breakpoints[b].enabled == 0) {
328                 disable_breakpoint(b);
329                 breakpoints[b].address = -1;
330         }
331         return command_success;
332 }
333
334
335 int
336 find_breakpoint(uint16_t address)
337 {
338         int b;
339
340         for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
341                 if (breakpoints[b].enabled && breakpoints[b].address == address)
342                         break;
343         if (b == CC_NUM_BREAKPOINTS)
344                 return -1;
345         return b;
346 }
347
348 enum command_result
349 command_break (int argc, char **argv)
350 {
351         int b;
352         uint16_t address;
353         enum command_result result;
354
355         if (argc == 1) {
356                 for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
357                         if (breakpoints[b].enabled)
358                                 s51_printf("Breakpoint %d 0x%04x\n",
359                                         b, breakpoints[b].address);
360                 return command_success;
361         }
362         if (argc != 2)
363                 return command_error;
364         result = parse_uint16(argv[1], &address);
365         if (result != command_success)
366                 return result;
367
368         return set_breakpoint(address, 0);
369 }
370
371 enum command_result
372 command_clear (int argc, char **argv)
373 {
374         int b;
375         uint16_t address;
376         enum command_result result;
377
378         if (argc != 2)
379                 return command_error;
380         result = parse_uint16(argv[1], &address);
381         if (result != command_success)
382                 return result;
383         return clear_breakpoint(address, 0);
384 }
385
386 void
387 cc_stopped(uint8_t status)
388 {
389         uint16_t pc;
390         int b;
391         int code;
392         char *reason;
393
394         pc = ccdbg_get_pc(s51_dbg);
395         if (status & CC_STATUS_CPU_HALTED) {
396                 if ((status & CC_STATUS_HALT_STATUS) != 0) {
397                         pc = pc - 1;
398                         code = 104;
399                         reason = "Breakpoint";
400                         b = find_breakpoint(pc);
401                         if (b != -1 && breakpoints[b].temporary)
402                                 clear_breakpoint(pc, 1);
403                         ccdbg_set_pc(s51_dbg, pc);
404                 } else {
405                         code = 105;
406                         reason = "Interrupt";
407                 }
408                 s51_printf("Stop at 0x%04x: (%d) %s\n",
409                         pc, code, reason);
410         }
411 }
412
413 uint8_t
414 cc_step(uint16_t pc)
415 {
416         int b;
417         uint8_t status;
418
419         b = find_breakpoint(pc);
420         if (b != -1)
421                 disable_breakpoint(b);
422         status = ccdbg_step_instr(s51_dbg);
423         if (b != -1)
424                 enable_breakpoint(b);
425         return status;
426 }
427
428 enum command_result
429 command_run (int argc, char **argv)
430 {
431         uint16_t start, end;
432         enum command_result result;
433         uint16_t pc;
434         uint8_t status;
435         int b;
436         
437         if (argv[1]) {
438                 result = parse_uint16(argv[1], &start);
439                 if (result != command_success)
440                         return result;
441                 if (argv[2]) {
442                         result = parse_uint16(argv[2], &end);
443                         if (result != command_success)
444                                 return result;
445                 }
446                 if (start_address && start == 0) {
447                         start = start_address;
448                         s51_printf("Starting at 0x%04x\n", start);
449                 }
450                 ccdbg_set_pc(s51_dbg, start);
451         }
452         else
453                 start = ccdbg_get_pc(s51_dbg);
454         s51_printf("Resume at 0x%04x\n", start);
455         pc = start;
456         b = find_breakpoint(pc);
457         if (b != -1) {
458                 cc_step(pc);
459                 pc = ccdbg_get_pc(s51_dbg);
460                 if (find_breakpoint(pc) != -1) {
461                         status = ccdbg_read_status(s51_dbg);
462                         cc_stopped(status);
463                         return command_success;
464                 }
465         }
466         ccdbg_resume(s51_dbg);
467         result = cc_wait();
468         return result;
469 }
470
471 enum command_result
472 command_next (int argc, char **argv)
473 {
474         return command_step(argc, argv);
475 }
476
477 enum command_result
478 command_step (int argc, char **argv)
479 {
480         uint16_t pc;
481         uint8_t opcode;
482         uint8_t a;
483
484         a = cc_step(ccdbg_get_pc(s51_dbg));
485         s51_printf(" ACC= 0x%02x\n", a);
486         pc = ccdbg_get_pc(s51_dbg);
487         ccdbg_read_memory(s51_dbg, pc, &opcode, 1);
488         s51_printf(" ? 0x%04x %02x\n", pc, opcode);
489         return command_success;
490 }
491
492 enum command_result
493 command_load (int argc, char **argv)
494 {
495         return command_error;
496 }
497
498 enum command_result
499 command_halt (int argc, char **argv)
500 {
501         uint16_t        pc;
502         ccdbg_halt(s51_dbg);
503         pc = ccdbg_get_pc(s51_dbg);
504         s51_printf("Halted at 0x%04x\n", pc);
505         return command_success;
506 }
507
508 enum command_result
509 command_stop (int argc, char **argv)
510 {
511         return command_success;
512 }
513
514 enum command_result
515 command_reset (int argc, char **argv)
516 {
517         ccdbg_debug_mode(s51_dbg);
518         ccdbg_halt(s51_dbg);
519         enable_breakpoints();
520         return command_success;
521 }
522
523 enum command_result
524 command_status(int argc, char **argv)
525 {
526         uint8_t status;
527
528         status = ccdbg_read_status(s51_dbg);
529         if ((status & CC_STATUS_CHIP_ERASE_DONE) == 0)
530                 s51_printf("\tChip erase in progress\n");
531         if (status & CC_STATUS_PCON_IDLE)
532                 s51_printf("\tCPU is idle (clock gated)\n");
533         if (status & CC_STATUS_CPU_HALTED)
534                 s51_printf("\tCPU halted\n");
535         else
536                 s51_printf("\tCPU running\n");
537         if ((status & CC_STATUS_POWER_MODE_0) == 0)
538                 s51_printf("\tPower Mode 1-3 selected\n");
539         if (status & CC_STATUS_HALT_STATUS)
540                 s51_printf("\tHalted by software or hw breakpoint\n");
541         else
542                 s51_printf("\tHalted by debug command\n");
543         if (status & CC_STATUS_DEBUG_LOCKED)
544                 s51_printf("\tDebug interface is locked\n");
545         if ((status & CC_STATUS_OSCILLATOR_STABLE) == 0)
546                 s51_printf("\tOscillators are not stable\n");
547         if (status & CC_STATUS_STACK_OVERFLOW)
548                 s51_printf("\tStack overflow\n");
549         return command_success;
550 }
551
552 static enum command_result
553 info_breakpoints(int argc, char **argv)
554 {
555         int b;
556         uint16_t address;
557         enum command_result result;
558
559         if (argc == 1) {
560                 s51_printf("Num Type       Disp Hit   Cnt   Address  What\n");
561                 for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
562                         if (breakpoints[b].enabled) {
563                                 s51_printf("%-3d fetch      %s 1     1     0x%04x   uc::disass() unimplemented\n",
564                                            b,
565                                            breakpoints[b].temporary ? "del " : "keep",
566                                            breakpoints[b].address);
567                         }
568                 return command_success;
569         }
570         
571 }
572
573 static enum command_result
574 info_help(int argc, char **argv);
575
576 static struct command_function infos[] = {
577         { "breakpoints", "b", info_breakpoints, "[b]reakpoints",
578                 "List current breakpoints\n" },
579         { "help",   "?",  info_help,    "help",
580                 "Print this list\n" },
581         
582         { NULL, NULL, NULL, NULL, NULL },
583 };
584
585 static enum command_result
586 info_help(int argc, char **argv)
587 {
588         return command_function_help(infos, argc, argv);
589 }
590
591 enum command_result
592 command_info(int argc, char **argv)
593 {
594         struct command_function *func;
595         
596         if (argc < 2)
597                 return command_error;
598         func = command_string_to_function(infos, argv[1]);
599         if (!func)
600                 return command_syntax;
601         return (*func->func)(argc-1, argv+1);
602 }
603
604 enum command_result
605 cc_wait(void)
606 {
607         for(;;) {
608                 uint8_t status;
609                 status = ccdbg_read_status(s51_dbg);
610                 if (status & CC_STATUS_CPU_HALTED) {
611                         cc_stopped(status);
612                         return command_success;
613                 }
614                 if (s51_interrupted || s51_check_input()) {
615                         
616                         ccdbg_halt(s51_dbg);
617                         status = ccdbg_read_status(s51_dbg);
618                         cc_stopped(status);
619                         return command_interrupt;
620                 }
621         }
622 }
623