Use SFR access funcs. Support 'dump' command. Add -m (monitor) flag.
[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)
73 {
74         int group, i;
75         
76         for (group = 0; group < length; group += 8) {
77                 s51_printf("0x%04x ", 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);
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);
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);
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         FILE *file;
178         
179         if (argc != 2)
180                 return command_error;
181         file = fopen (argv[1], "r");
182         if (!file)
183                 return command_error;
184         hex = ccdbg_hex_file_read(file, argv[1]);
185         fclose(file);
186         if (!hex)
187                 return command_error;
188         if (hex->nrecord == 0) {
189                 ccdbg_hex_file_free(hex);
190                 return command_error;
191         }
192         start_address = hex->records[0]->address;
193         return command_success;
194 }
195
196 enum command_result
197 command_pc (int argc, char **argv)
198 {
199         uint16_t        pc;
200         if (argv[1]) {
201                 enum command_result result;
202                 result = parse_uint16(argv[1], &pc);
203                 if (result != command_success)
204                         return result;
205                 ccdbg_set_pc(s51_dbg, pc);
206         } else {
207                 pc = ccdbg_get_pc(s51_dbg);
208                 s51_printf("   0x%04x 00\n", pc);
209         }
210         return command_success;
211 }
212
213 struct cc_break {
214         int             enabled;
215         int             temporary;
216         uint16_t        address;
217 };
218
219 #define CC_NUM_BREAKPOINTS 4
220
221 static struct cc_break  breakpoints[CC_NUM_BREAKPOINTS];
222
223 static void
224 disable_breakpoint(int b)
225 {
226         uint8_t status;
227         
228         status = ccdbg_set_hw_brkpnt(s51_dbg, b, 0, breakpoints[b].address);
229         if (status != 0x00 && status != 0xff)
230                 s51_printf("disable_breakpoint status 0x%02x\n", status);
231 }
232
233 static void
234 enable_breakpoint(int b)
235 {
236         uint8_t status;
237         
238         status = ccdbg_set_hw_brkpnt(s51_dbg, b, 1, breakpoints[b].address);
239         if (status != 0xff)
240                 s51_printf("enable_breakpoint status 0x%02x\n", status);
241 }
242
243 static void
244 enable_breakpoints(void)
245 {
246         int b;
247         for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
248                 if (breakpoints[b].enabled)
249                         enable_breakpoint(b);
250 }
251
252 enum command_result
253 set_breakpoint(uint16_t address, int temporary)
254 {
255         int b;
256         uint8_t status;
257         for (b = 0; b < CC_NUM_BREAKPOINTS; b++) {
258                 if (breakpoints[b].enabled == 0)
259                         break;
260                 if (breakpoints[b].address == address)
261                         break;
262         }
263         if (b == CC_NUM_BREAKPOINTS) {
264                 s51_printf("Error: too many breakpoints requested\n");
265                 return command_success;
266         }
267         if (breakpoints[b].enabled == 0) {
268                 breakpoints[b].address = address;
269                 enable_breakpoint(b);
270         }
271         ++breakpoints[b].enabled;
272         s51_printf("Breakpoint %d at 0x%04x\n", b, address);
273         breakpoints[b].temporary += temporary;
274         return command_success;
275 }
276
277 enum command_result
278 clear_breakpoint(uint16_t address, int temporary)
279 {
280         int b;
281         uint8_t status;
282
283         for (b = 0; b < CC_NUM_BREAKPOINTS; b++) {
284                 if (breakpoints[b].enabled != 0 &&
285                     ((breakpoints[b].temporary != 0) == (temporary != 0)) &&
286                     breakpoints[b].address == address)
287                         break;
288         }
289         if (b == CC_NUM_BREAKPOINTS) {
290                 s51_printf("Error: no matching breakpoint found\n");
291                 return command_success;
292         }
293         --breakpoints[b].enabled;
294         breakpoints[b].temporary -= temporary;
295         if (breakpoints[b].enabled == 0) {
296                 disable_breakpoint(b);
297                 breakpoints[b].address = -1;
298         }
299         return command_success;
300 }
301
302
303 int
304 find_breakpoint(uint16_t address)
305 {
306         int b;
307
308         for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
309                 if (breakpoints[b].enabled && breakpoints[b].address == address)
310                         break;
311         if (b == CC_NUM_BREAKPOINTS)
312                 return -1;
313         return b;
314 }
315
316 enum command_result
317 command_break (int argc, char **argv)
318 {
319         int b;
320         uint16_t address;
321         enum command_result result;
322
323         if (argc == 1) {
324                 for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
325                         if (breakpoints[b].enabled)
326                                 s51_printf("Breakpoint %d 0x%04x\n",
327                                         b, breakpoints[b].address);
328                 return command_success;
329         }
330         if (argc != 2)
331                 return command_error;
332         result = parse_uint16(argv[1], &address);
333         if (result != command_success)
334                 return result;
335
336         return set_breakpoint(address, 0);
337 }
338
339 enum command_result
340 command_clear (int argc, char **argv)
341 {
342         int b;
343         uint16_t address;
344         enum command_result result;
345
346         if (argc != 2)
347                 return command_error;
348         result = parse_uint16(argv[1], &address);
349         if (result != command_success)
350                 return result;
351         return clear_breakpoint(address, 0);
352 }
353
354 void
355 cc_stopped(uint8_t status)
356 {
357         uint16_t pc;
358         int b;
359         int code;
360         char *reason;
361
362         pc = ccdbg_get_pc(s51_dbg);
363         if (status & CC_STATUS_CPU_HALTED) {
364                 if ((status & CC_STATUS_HALT_STATUS) != 0) {
365                         pc = pc - 1;
366                         code = 104;
367                         reason = "Breakpoint";
368                         b = find_breakpoint(pc);
369                         if (b != -1 && breakpoints[b].temporary)
370                                 clear_breakpoint(pc, 1);
371                         ccdbg_set_pc(s51_dbg, pc);
372                 } else {
373                         code = 105;
374                         reason = "Interrupt";
375                 }
376                 s51_printf("Stop at 0x%04x: (%d) %s\n",
377                         pc, code, reason);
378         }
379 }
380
381 uint8_t
382 cc_step(uint16_t pc)
383 {
384         int b;
385         uint8_t status;
386
387         b = find_breakpoint(pc);
388         if (b != -1)
389                 disable_breakpoint(b);
390         status = ccdbg_step_instr(s51_dbg);
391         if (b != -1)
392                 enable_breakpoint(b);
393         return status;
394 }
395
396 enum command_result
397 command_run (int argc, char **argv)
398 {
399         uint16_t start, end;
400         enum command_result result;
401         uint16_t pc;
402         uint8_t status;
403         int b;
404         
405         if (argv[1]) {
406                 result = parse_uint16(argv[1], &start);
407                 if (result != command_success)
408                         return result;
409                 if (argv[2]) {
410                         result = parse_uint16(argv[2], &end);
411                         if (result != command_success)
412                                 return result;
413                 }
414                 if (start_address && start == 0) {
415                         start = start_address;
416                         s51_printf("Starting at 0x%04x\n", start);
417                 }
418                 ccdbg_set_pc(s51_dbg, start);
419         }
420         else
421                 start = ccdbg_get_pc(s51_dbg);
422         s51_printf("Resume at 0x%04x\n", start);
423         pc = start;
424         b = find_breakpoint(pc);
425         if (b != -1) {
426                 cc_step(pc);
427                 pc = ccdbg_get_pc(s51_dbg);
428                 if (find_breakpoint(pc) != -1) {
429                         status = ccdbg_read_status(s51_dbg);
430                         cc_stopped(status);
431                         return command_success;
432                 }
433         }
434         ccdbg_resume(s51_dbg);
435         result = cc_wait();
436         return result;
437 }
438
439 enum command_result
440 command_next (int argc, char **argv)
441 {
442         return command_step(argc, argv);
443 }
444
445 enum command_result
446 command_step (int argc, char **argv)
447 {
448         uint16_t pc;
449         uint8_t opcode;
450         uint8_t a;
451
452         a = cc_step(ccdbg_get_pc(s51_dbg));
453         s51_printf(" ACC= 0x%02x\n", a);
454         pc = ccdbg_get_pc(s51_dbg);
455         ccdbg_read_memory(s51_dbg, pc, &opcode, 1);
456         s51_printf(" ? 0x%04x %02x\n", pc, opcode);
457         return command_success;
458 }
459
460 enum command_result
461 command_load (int argc, char **argv)
462 {
463         return command_error;
464 }
465
466 enum command_result
467 command_halt (int argc, char **argv)
468 {
469         uint16_t        pc;
470         ccdbg_halt(s51_dbg);
471         pc = ccdbg_get_pc(s51_dbg);
472         s51_printf("Halted at 0x%04x\n", pc);
473         return command_success;
474 }
475
476 enum command_result
477 command_reset (int argc, char **argv)
478 {
479         ccdbg_debug_mode(s51_dbg);
480         ccdbg_halt(s51_dbg);
481         enable_breakpoints();
482         return command_success;
483 }
484
485 enum command_result
486 command_status(int argc, char **argv)
487 {
488         uint8_t status;
489
490         status = ccdbg_read_status(s51_dbg);
491         if ((status & CC_STATUS_CHIP_ERASE_DONE) == 0)
492                 s51_printf("\tChip erase in progress\n");
493         if (status & CC_STATUS_PCON_IDLE)
494                 s51_printf("\tCPU is idle (clock gated)\n");
495         if (status & CC_STATUS_CPU_HALTED)
496                 s51_printf("\tCPU halted\n");
497         else
498                 s51_printf("\tCPU running\n");
499         if ((status & CC_STATUS_POWER_MODE_0) == 0)
500                 s51_printf("\tPower Mode 1-3 selected\n");
501         if (status & CC_STATUS_HALT_STATUS)
502                 s51_printf("\tHalted by software or hw breakpoint\n");
503         else
504                 s51_printf("\tHalted by debug command\n");
505         if (status & CC_STATUS_DEBUG_LOCKED)
506                 s51_printf("\tDebug interface is locked\n");
507         if ((status & CC_STATUS_OSCILLATOR_STABLE) == 0)
508                 s51_printf("\tOscillators are not stable\n");
509         if (status & CC_STATUS_STACK_OVERFLOW)
510                 s51_printf("\tStack overflow\n");
511         return command_success;
512 }
513
514 enum command_result
515 cc_wait(void)
516 {
517         for(;;) {
518                 uint8_t status;
519                 status = ccdbg_read_status(s51_dbg);
520                 if (status & CC_STATUS_CPU_HALTED) {
521                         cc_stopped(status);
522                         return command_success;
523                 }
524                 if (s51_interrupted || s51_check_input()) {
525                         
526                         ccdbg_halt(s51_dbg);
527                         status = ccdbg_read_status(s51_dbg);
528                         cc_stopped(status);
529                         return command_interrupt;
530                 }
531         }
532 }
533