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