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