s51: get start address from ihx file. re-enable breakpoints after reset.
[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 enum command_result
50 command_quit (int argc, char **argv)
51 {
52         exit(0);
53         return command_error;
54 }
55
56 static void
57 dump_bytes(uint8_t *memory, int length, uint16_t start)
58 {
59         int group, i;
60         
61         for (group = 0; group < length; group += 8) {
62                 s51_printf("0x%04x ", start + group);
63                 for (i = group; i < length && i < group + 8; i++)
64                         s51_printf("%02x ", memory[i]);
65                 for (; i < group + 8; i++)
66                         s51_printf("   ");
67                 for (i = group; i < length && i < group + 8; i++) {
68                         if (isascii(memory[i]) && isprint(memory[i]))
69                                 s51_printf("%c", memory[i]);
70                         else
71                                 s51_printf(".");
72                 }
73                 s51_printf("\n");
74         }
75 }
76
77 enum command_result
78 command_di (int argc, char **argv)
79 {
80         uint16_t start, end;
81         uint8_t memory[65536];
82         uint8_t status;
83         int length;
84         
85         if (argc != 3)
86                 return command_error;
87         if (parse_uint16(argv[1], &start) != command_success)
88                 return command_error;
89         if (parse_uint16(argv[2], &end) != command_success)
90                 return command_error;
91         length = (int) end - (int) start + 1;
92         status = ccdbg_read_memory(s51_dbg, start + 0xff00, memory, length);
93         dump_bytes(memory, length, start);
94         return command_success;
95 }
96
97 enum command_result
98 command_ds (int argc, char **argv)
99 {
100         uint16_t start, end;
101         uint8_t memory[65536];
102         uint8_t status;
103         int length;
104         
105         if (argc != 3)
106                 return command_error;
107         if (parse_uint16(argv[1], &start) != command_success)
108                 return command_error;
109         if (parse_uint16(argv[2], &end) != command_success)
110                 return command_error;
111         length = (int) end - (int) start + 1;
112         status = ccdbg_read_memory(s51_dbg, start + 0xdf00, memory, length);
113         dump_bytes(memory, length, start);
114         return command_success;
115 }
116
117 enum command_result
118 command_dx (int argc, char **argv)
119 {
120         uint16_t start, end;
121         uint8_t memory[65536];
122         uint8_t status;
123         int length;
124         
125         if (argc != 3)
126                 return command_error;
127         if (parse_uint16(argv[1], &start) != command_success)
128                 return command_error;
129         if (parse_uint16(argv[2], &end) != command_success)
130                 return command_error;
131         length = (int) end - (int) start + 1;
132         status = ccdbg_read_memory(s51_dbg, start, memory, length);
133         dump_bytes(memory, length, start);
134         return command_success;
135 }
136
137 enum command_result
138 command_set (int argc, char **argv)
139 {
140         return command_error;
141 }
142
143 enum command_result
144 command_dump (int argc, char **argv)
145 {
146         return command_error;
147 }
148
149 enum command_result
150 command_file (int argc, char **argv)
151 {
152         struct hex_file *hex;
153         FILE *file;
154         
155         if (argc != 2)
156                 return command_error;
157         file = fopen (argv[1], "r");
158         if (!file)
159                 return command_error;
160         hex = ccdbg_hex_file_read(file, argv[1]);
161         fclose(file);
162         if (!hex)
163                 return command_error;
164         if (hex->nrecord == 0) {
165                 ccdbg_hex_file_free(hex);
166                 return command_error;
167         }
168         start_address = hex->records[0]->address;
169         return command_success;
170 }
171
172 enum command_result
173 command_pc (int argc, char **argv)
174 {
175         uint16_t        pc;
176         if (argv[1]) {
177                 enum command_result result;
178                 result = parse_uint16(argv[1], &pc);
179                 if (result != command_success)
180                         return result;
181                 ccdbg_set_pc(s51_dbg, pc);
182         } else {
183                 pc = ccdbg_get_pc(s51_dbg);
184                 s51_printf("   0x%04x 00\n", pc);
185         }
186         return command_success;
187 }
188
189 struct cc_break {
190         int             enabled;
191         int             temporary;
192         uint16_t        address;
193 };
194
195 #define CC_NUM_BREAKPOINTS 4
196
197 static struct cc_break  breakpoints[CC_NUM_BREAKPOINTS];
198
199 static void
200 disable_breakpoint(int b)
201 {
202         uint8_t status;
203         
204         status = ccdbg_set_hw_brkpnt(s51_dbg, b, 0, breakpoints[b].address);
205         if (status != 0x00 && status != 0xff)
206                 s51_printf("disable_breakpoint status 0x%02x\n", status);
207 }
208
209 static void
210 enable_breakpoint(int b)
211 {
212         uint8_t status;
213         
214         status = ccdbg_set_hw_brkpnt(s51_dbg, b, 1, breakpoints[b].address);
215         if (status != 0xff)
216                 s51_printf("enable_breakpoint status 0x%02x\n", status);
217 }
218
219 static void
220 enable_breakpoints(void)
221 {
222         int b;
223         for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
224                 if (breakpoints[b].enabled)
225                         enable_breakpoint(b);
226 }
227
228 enum command_result
229 set_breakpoint(uint16_t address, int temporary)
230 {
231         int b;
232         uint8_t status;
233         for (b = 0; b < CC_NUM_BREAKPOINTS; b++) {
234                 if (breakpoints[b].enabled == 0)
235                         break;
236                 if (breakpoints[b].address == address)
237                         break;
238         }
239         if (b == CC_NUM_BREAKPOINTS) {
240                 s51_printf("Error: too many breakpoints requested\n");
241                 return command_success;
242         }
243         if (breakpoints[b].enabled == 0) {
244                 breakpoints[b].address = address;
245                 enable_breakpoint(b);
246         }
247         ++breakpoints[b].enabled;
248         s51_printf("Breakpoint %d at 0x%04x\n", b, address);
249         breakpoints[b].temporary += temporary;
250         return command_success;
251 }
252
253 enum command_result
254 clear_breakpoint(uint16_t address, int temporary)
255 {
256         int b;
257         uint8_t status;
258
259         for (b = 0; b < CC_NUM_BREAKPOINTS; b++) {
260                 if (breakpoints[b].enabled != 0 &&
261                     ((breakpoints[b].temporary != 0) == (temporary != 0)) &&
262                     breakpoints[b].address == address)
263                         break;
264         }
265         if (b == CC_NUM_BREAKPOINTS) {
266                 s51_printf("Error: no matching breakpoint found\n");
267                 return command_success;
268         }
269         --breakpoints[b].enabled;
270         breakpoints[b].temporary -= temporary;
271         if (breakpoints[b].enabled == 0) {
272                 disable_breakpoint(b);
273                 breakpoints[b].address = -1;
274         }
275         return command_success;
276 }
277
278
279 int
280 find_breakpoint(uint16_t address)
281 {
282         int b;
283
284         for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
285                 if (breakpoints[b].enabled && breakpoints[b].address == address)
286                         break;
287         if (b == CC_NUM_BREAKPOINTS)
288                 return -1;
289         return b;
290 }
291
292 enum command_result
293 command_break (int argc, char **argv)
294 {
295         int b;
296         uint16_t address;
297         enum command_result result;
298
299         if (argc == 1) {
300                 for (b = 0; b < CC_NUM_BREAKPOINTS; b++)
301                         if (breakpoints[b].enabled)
302                                 s51_printf("Breakpoint %d 0x%04x\n",
303                                         b, breakpoints[b].address);
304                 return command_success;
305         }
306         if (argc != 2)
307                 return command_error;
308         result = parse_uint16(argv[1], &address);
309         if (result != command_success)
310                 return result;
311
312         return set_breakpoint(address, 0);
313 }
314
315 enum command_result
316 command_clear (int argc, char **argv)
317 {
318         int b;
319         uint16_t address;
320         enum command_result result;
321
322         if (argc != 2)
323                 return command_error;
324         result = parse_uint16(argv[1], &address);
325         if (result != command_success)
326                 return result;
327         return clear_breakpoint(address, 0);
328 }
329
330 void
331 cc_stopped(uint8_t status)
332 {
333         uint16_t pc;
334         int b;
335         int code;
336         char *reason;
337
338         pc = ccdbg_get_pc(s51_dbg);
339         if (status & CC_STATUS_CPU_HALTED) {
340                 if ((status & CC_STATUS_HALT_STATUS) != 0) {
341                         pc = pc - 1;
342                         code = 104;
343                         reason = "Breakpoint";
344                         b = find_breakpoint(pc);
345                         if (b != -1 && breakpoints[b].temporary)
346                                 clear_breakpoint(pc, 1);
347                         ccdbg_set_pc(s51_dbg, pc);
348                 } else {
349                         code = 105;
350                         reason = "Interrupt";
351                 }
352                 s51_printf("Stop at 0x%04x: (%d) %s\n",
353                         pc, code, reason);
354         }
355 }
356
357 uint8_t
358 cc_step(uint16_t pc)
359 {
360         int b;
361         uint8_t status;
362
363         b = find_breakpoint(pc);
364         if (b != -1)
365                 disable_breakpoint(b);
366         status = ccdbg_step_instr(s51_dbg);
367         if (b != -1)
368                 enable_breakpoint(b);
369         return status;
370 }
371
372 enum command_result
373 command_run (int argc, char **argv)
374 {
375         uint16_t start, end;
376         enum command_result result;
377         uint16_t pc;
378         uint8_t status;
379         int b;
380         
381         if (argv[1]) {
382                 result = parse_uint16(argv[1], &start);
383                 if (result != command_success)
384                         return result;
385                 if (argv[2]) {
386                         result = parse_uint16(argv[2], &end);
387                         if (result != command_success)
388                                 return result;
389                 }
390                 if (start_address && start == 0) {
391                         start = start_address;
392                         s51_printf("Starting at 0x%04x\n", start);
393                 }
394                 ccdbg_set_pc(s51_dbg, start);
395         }
396         else
397                 start = ccdbg_get_pc(s51_dbg);
398         s51_printf("Resume at 0x%04x\n", start);
399         pc = start;
400         b = find_breakpoint(pc);
401         if (b != -1) {
402                 cc_step(pc);
403                 pc = ccdbg_get_pc(s51_dbg);
404                 if (find_breakpoint(pc) != -1) {
405                         status = ccdbg_read_status(s51_dbg);
406                         cc_stopped(status);
407                         return command_success;
408                 }
409         }
410         ccdbg_resume(s51_dbg);
411         result = cc_wait();
412         return result;
413 }
414
415 enum command_result
416 command_next (int argc, char **argv)
417 {
418         return command_step(argc, argv);
419 }
420
421 enum command_result
422 command_step (int argc, char **argv)
423 {
424         uint16_t pc;
425         uint8_t opcode;
426         uint8_t a;
427
428         a = cc_step(ccdbg_get_pc(s51_dbg));
429         s51_printf(" ACC= 0x%02x\n", a);
430         pc = ccdbg_get_pc(s51_dbg);
431         ccdbg_read_memory(s51_dbg, pc, &opcode, 1);
432         s51_printf(" ? 0x%04x %02x\n", pc, opcode);
433         return command_success;
434 }
435
436 enum command_result
437 command_load (int argc, char **argv)
438 {
439         return command_error;
440 }
441
442 enum command_result
443 command_halt (int argc, char **argv)
444 {
445         uint16_t        pc;
446         ccdbg_halt(s51_dbg);
447         pc = ccdbg_get_pc(s51_dbg);
448         s51_printf("Halted at 0x%04x\n", pc);
449         return command_success;
450 }
451
452 enum command_result
453 command_reset (int argc, char **argv)
454 {
455         ccdbg_debug_mode(s51_dbg);
456         ccdbg_halt(s51_dbg);
457         enable_breakpoints();
458         return command_success;
459 }
460
461 enum command_result
462 command_status(int argc, char **argv)
463 {
464         uint8_t status;
465
466         status = ccdbg_read_status(s51_dbg);
467         if ((status & CC_STATUS_CHIP_ERASE_DONE) == 0)
468                 s51_printf("\tChip erase in progress\n");
469         if (status & CC_STATUS_PCON_IDLE)
470                 s51_printf("\tCPU is idle (clock gated)\n");
471         if (status & CC_STATUS_CPU_HALTED)
472                 s51_printf("\tCPU halted\n");
473         else
474                 s51_printf("\tCPU running\n");
475         if ((status & CC_STATUS_POWER_MODE_0) == 0)
476                 s51_printf("\tPower Mode 1-3 selected\n");
477         if (status & CC_STATUS_HALT_STATUS)
478                 s51_printf("\tHalted by software or hw breakpoint\n");
479         else
480                 s51_printf("\tHalted by debug command\n");
481         if (status & CC_STATUS_DEBUG_LOCKED)
482                 s51_printf("\tDebug interface is locked\n");
483         if ((status & CC_STATUS_OSCILLATOR_STABLE) == 0)
484                 s51_printf("\tOscillators are not stable\n");
485         if (status & CC_STATUS_STACK_OVERFLOW)
486                 s51_printf("\tStack overflow\n");
487         return command_success;
488 }
489
490 enum command_result
491 cc_wait(void)
492 {
493         for(;;) {
494                 uint8_t status;
495                 status = ccdbg_read_status(s51_dbg);
496                 if (status & CC_STATUS_CPU_HALTED) {
497                         cc_stopped(status);
498                         return command_success;
499                 }
500                 if (s51_interrupted || s51_check_input()) {
501                         
502                         ccdbg_halt(s51_dbg);
503                         status = ccdbg_read_status(s51_dbg);
504                         cc_stopped(status);
505                         return command_interrupt;
506                 }
507         }
508 }
509