28e43b4f0b85162a353ce09fc4b0b3ac705ded7f
[microwatt.git] / scripts / mw_debug / mw_debug.c
1 #define _POSIX_C_SOURCE 200809L
2 #define _GNU_SOURCE
3
4 #include <stdint.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <stdint.h>
10 #include <stdbool.h>
11 #include <getopt.h>
12 #include <poll.h>
13 #include <signal.h>
14 #include <fcntl.h>
15 #include <netdb.h>
16 #include <ctype.h>
17 #include <sys/types.h>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <urjtag/urjtag.h>
21 #include <inttypes.h>
22
23 #define DBG_WB_ADDR 0x00
24 #define DBG_WB_DATA 0x01
25 #define DBG_WB_CTRL 0x02
26
27 #define DBG_CORE_CTRL 0x10
28 #define DBG_CORE_CTRL_STOP (1 << 0)
29 #define DBG_CORE_CTRL_RESET (1 << 1)
30 #define DBG_CORE_CTRL_ICRESET (1 << 2)
31 #define DBG_CORE_CTRL_STEP (1 << 3)
32 #define DBG_CORE_CTRL_START (1 << 4)
33
34 #define DBG_CORE_STAT 0x11
35 #define DBG_CORE_STAT_STOPPING (1 << 0)
36 #define DBG_CORE_STAT_STOPPED (1 << 1)
37 #define DBG_CORE_STAT_TERM (1 << 2)
38
39 #define DBG_CORE_NIA 0x12
40 #define DBG_CORE_MSR 0x13
41
42 #define DBG_CORE_GSPR_INDEX 0x14
43 #define DBG_CORE_GSPR_DATA 0x15
44
45 #define DBG_LOG_ADDR 0x16
46 #define DBG_LOG_DATA 0x17
47
48 static bool debug;
49
50 struct backend {
51 int (*init)(const char *target);
52 int (*reset)(void);
53 int (*command)(uint8_t op, uint8_t addr, uint64_t *data);
54 };
55 static struct backend *b;
56
57 static void check(int r, const char *failstr)
58 {
59 if (r >= 0)
60 return;
61 fprintf(stderr, "Error %s\n", failstr);
62 exit(1);
63 }
64
65 /* -------------- SIM backend -------------- */
66
67 static int sim_fd = -1;
68
69 static int sim_init(const char *target)
70 {
71 struct sockaddr_in saddr;
72 struct hostent *hp;
73 const char *p, *host;
74 int port, rc;
75
76 if (!target)
77 target = "localhost:13245";
78 p = strchr(target, ':');
79 host = strndup(target, p - target);
80 if (p && *p)
81 p++;
82 else
83 p = "13245";
84 port = strtoul(p, NULL, 10);
85 if (debug)
86 printf("Opening sim backend host '%s' port %d\n", host, port);
87
88 sim_fd = socket(PF_INET, SOCK_STREAM, 0);
89 if (sim_fd < 0) {
90 fprintf(stderr, "Error opening socket: %s\n",
91 strerror(errno));
92 return -1;
93 }
94 hp = gethostbyname(host);
95 if (!hp) {
96 fprintf(stderr,"Unknown host '%s'\n", host);
97 return -1;
98 }
99 memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length);
100 saddr.sin_port = htons(port);
101 saddr.sin_family = PF_INET;
102 rc = connect(sim_fd, (struct sockaddr *)&saddr, sizeof(saddr));
103 if (rc < 0) {
104 close(sim_fd);
105 fprintf(stderr,"Connection to '%s' failed: %s\n",
106 host, strerror(errno));
107 return -1;
108 }
109 return 0;
110 }
111
112 static int sim_reset(void)
113 {
114 return 0;
115 }
116
117 static void add_bits(uint8_t **p, int *b, uint64_t d, int c)
118 {
119 uint8_t md = 1 << *b;
120 uint64_t ms = 1;
121
122 while (c--) {
123 if (d & ms)
124 (**p) |= md;
125 ms <<= 1;
126 if (*b == 7) {
127 *b = 0;
128 (*p)++;
129 md = 1;
130 } else {
131 (*b)++;
132 md <<= 1;
133 }
134 }
135 }
136
137 static uint64_t read_bits(uint8_t **p, int *b, int c)
138 {
139 uint8_t ms = 1 << *b;
140 uint64_t md = 1;
141 uint64_t d = 0;
142
143 while (c--) {
144 if ((**p) & ms)
145 d |= md;
146 md <<= 1;
147 if (*b == 7) {
148 *b = 0;
149 (*p)++;
150 ms = 1;
151 } else {
152 (*b)++;
153 ms <<= 1;
154 }
155 }
156 return d;
157 }
158
159 static int sim_command(uint8_t op, uint8_t addr, uint64_t *data)
160 {
161 uint8_t buf[16], *p;
162 uint64_t d = data ? *data : 0;
163 int r, b = 0;
164
165 memset(buf, 0, 16);
166 p = buf+1;
167 add_bits(&p, &b, op, 2);
168 add_bits(&p, &b, d, 64);
169 add_bits(&p, &b, addr, 8);
170 if (b)
171 p++;
172 buf[0] = 74;
173 if (0)
174 {
175 int i;
176
177 for (i=0; i<(p-buf); i++)
178 printf("%02x ", buf[i]);
179 printf("\n");
180 }
181 r = write(sim_fd, buf, p - buf);
182 if (r < 0) {
183 fprintf(stderr, "failed to write sim command\n");
184 return -1;
185 }
186 r = read(sim_fd, buf, sizeof(buf));
187 if (0 && r > 0) {
188 int i;
189
190 for (i=0; i<r; i++)
191 printf("%02x ", buf[i]);
192 printf("\n");
193 }
194 p = buf+1;
195 b = 0;
196 r = read_bits(&p, &b, 2);
197 if (data)
198 *data = read_bits(&p, &b, 64);
199 return r;
200 }
201
202 static struct backend sim_backend = {
203 .init = sim_init,
204 .reset = sim_reset,
205 .command = sim_command,
206 };
207
208 /* -------------- JTAG backend -------------- */
209
210 static urj_chain_t *jc;
211
212 static int jtag_init(const char *target)
213 {
214 const char *sep;
215 const char *cable;
216 char *params[] = { NULL, };
217 urj_part_t *p;
218 uint32_t id;
219 int rc, part;
220
221 if (!target)
222 target = "DigilentHS1";
223 sep = strchr(target, ':');
224 cable = strndup(target, sep - target);
225 if (sep && *sep) {
226 fprintf(stderr, "jtag cable params not supported yet\n");
227 return -1;
228 }
229 if (debug)
230 printf("Opening jtag backend cable '%s'\n", cable);
231
232 jc = urj_tap_chain_alloc();
233 if (!jc) {
234 fprintf(stderr, "Failed to alloc JTAG\n");
235 return -1;
236 }
237 jc->main_part = 0;
238
239 rc = urj_tap_chain_connect(jc, cable, params);
240 if (rc != URJ_STATUS_OK) {
241 fprintf(stderr, "JTAG cable detect failed\n");
242 return -1;
243 }
244
245 /* XXX Hard wire part 0, that might need to change (use params and detect !) */
246 rc = urj_tap_manual_add(jc, 6);
247 if (rc < 0) {
248 fprintf(stderr, "JTAG failed to add part !\n");
249 return -1;
250 }
251 if (jc->parts == NULL || jc->parts->len == 0) {
252 fprintf(stderr, "JTAG Something's wrong after adding part !\n");
253 return -1;
254 }
255 urj_part_parts_set_instruction(jc->parts, "BYPASS");
256
257 jc->active_part = part = 0;
258
259 p = urj_tap_chain_active_part(jc);
260 if (!p) {
261 fprintf(stderr, "Failed to get active JTAG part\n");
262 return -1;
263 }
264 rc = urj_part_data_register_define(p, "IDCODE_REG", 32);
265 if (rc != URJ_STATUS_OK) {
266 fprintf(stderr, "JTAG failed to add IDCODE_REG register !\n");
267 return -1;
268 }
269 if (urj_part_instruction_define(p, "IDCODE", "001001", "IDCODE_REG") == NULL) {
270 fprintf(stderr, "JTAG failed to add IDCODE instruction !\n");
271 return -1;
272 }
273 rc = urj_part_data_register_define(p, "USER2_REG", 74);
274 if (rc != URJ_STATUS_OK) {
275 fprintf(stderr, "JTAG failed to add USER2_REG register !\n");
276 return -1;
277 }
278 if (urj_part_instruction_define(p, "USER2", "000011", "USER2_REG") == NULL) {
279 fprintf(stderr, "JTAG failed to add USER2 instruction !\n");
280 return -1;
281 }
282 urj_part_set_instruction(p, "IDCODE");
283 urj_tap_chain_shift_instructions(jc);
284 urj_tap_chain_shift_data_registers(jc, 1);
285 id = urj_tap_register_get_value(p->active_instruction->data_register->out);
286 printf("Found device ID: 0x%08x\n", id);
287 urj_part_set_instruction(p, "USER2");
288 urj_tap_chain_shift_instructions(jc);
289
290 return 0;
291 }
292
293 static int jtag_reset(void)
294 {
295 return 0;
296 }
297
298 static int jtag_command(uint8_t op, uint8_t addr, uint64_t *data)
299 {
300 urj_part_t *p = urj_tap_chain_active_part(jc);
301 urj_part_instruction_t *insn;
302 urj_data_register_t *dr;
303 uint64_t d = data ? *data : 0;
304 int rc;
305
306 if (!p)
307 return -1;
308 insn = p->active_instruction;
309 if (!insn)
310 return -1;
311 dr = insn->data_register;
312 if (!dr)
313 return -1;
314 rc = urj_tap_register_set_value_bit_range(dr->in, op, 1, 0);
315 if (rc != URJ_STATUS_OK)
316 return -1;
317 rc = urj_tap_register_set_value_bit_range(dr->in, d, 65, 2);
318 if (rc != URJ_STATUS_OK)
319 return -1;
320 rc = urj_tap_register_set_value_bit_range(dr->in, addr, 73, 66);
321 if (rc != URJ_STATUS_OK)
322 return -1;
323 rc = urj_tap_chain_shift_data_registers(jc, 1);
324 if (rc != URJ_STATUS_OK)
325 return -1;
326 rc = urj_tap_register_get_value_bit_range(dr->out, 1, 0);
327 if (data)
328 *data = urj_tap_register_get_value_bit_range(dr->out, 65, 2);
329 return rc;
330 }
331
332 static struct backend jtag_backend = {
333 .init = jtag_init,
334 .reset = jtag_reset,
335 .command = jtag_command,
336 };
337
338 static int dmi_read(uint8_t addr, uint64_t *data)
339 {
340 int rc;
341
342 rc = b->command(1, addr, data);
343 if (rc < 0)
344 return rc;
345 for (;;) {
346 rc = b->command(0, 0, data);
347 if (rc < 0)
348 return rc;
349 if (rc == 0)
350 return 0;
351 if (rc != 3)
352 fprintf(stderr, "Unknown status code %d !\n", rc);
353 }
354 }
355
356 static int dmi_write(uint8_t addr, uint64_t data)
357 {
358 int rc;
359
360 rc = b->command(2, addr, &data);
361 if (rc < 0)
362 return rc;
363 for (;;) {
364 rc = b->command(0, 0, NULL);
365 if (rc < 0)
366 return rc;
367 if (rc == 0)
368 return 0;
369 if (rc != 3)
370 fprintf(stderr, "Unknown status code %d !\n", rc);
371 }
372 }
373
374 static void core_status(void)
375 {
376 uint64_t stat, nia, msr;
377 const char *statstr, *statstr2;
378
379 check(dmi_read(DBG_CORE_STAT, &stat), "reading core status");
380 check(dmi_read(DBG_CORE_NIA, &nia), "reading core NIA");
381 check(dmi_read(DBG_CORE_MSR, &msr), "reading core MSR");
382
383 if (debug)
384 printf("Core status = 0x%llx\n", (unsigned long long)stat);
385 statstr = "running";
386 statstr2 = "";
387 if (stat & DBG_CORE_STAT_STOPPED) {
388 statstr = "stopped";
389 if (!(stat & DBG_CORE_STAT_STOPPING))
390 statstr2 = " (restarting?)";
391 else if (stat & DBG_CORE_STAT_TERM)
392 statstr2 = " (terminated)";
393 } else if (stat & DBG_CORE_STAT_STOPPING)
394 statstr = "stopping";
395 else if (stat & DBG_CORE_STAT_TERM)
396 statstr = "odd state (TERM but no STOP)";
397 printf("Core: %s%s\n", statstr, statstr2);
398 printf(" NIA: %016" PRIx64 "\n", nia);
399 printf(" MSR: %016" PRIx64 "\n", msr);
400 }
401
402 static void core_stop(void)
403 {
404 check(dmi_write(DBG_CORE_CTRL, DBG_CORE_CTRL_STOP), "stopping core");
405 }
406
407 static void core_start(void)
408 {
409 check(dmi_write(DBG_CORE_CTRL, DBG_CORE_CTRL_START), "starting core");
410 }
411
412 static void core_reset(void)
413 {
414 check(dmi_write(DBG_CORE_CTRL, DBG_CORE_CTRL_RESET), "resetting core");
415 }
416
417 static void core_step(void)
418 {
419 uint64_t stat;
420
421 check(dmi_read(DBG_CORE_STAT, &stat), "reading core status");
422
423 if (!(stat & DBG_CORE_STAT_STOPPED)) {
424 printf("Core not stopped !\n");
425 return;
426 }
427 check(dmi_write(DBG_CORE_CTRL, DBG_CORE_CTRL_STEP), "stepping core");
428 }
429
430 static void icache_reset(void)
431 {
432 check(dmi_write(DBG_CORE_CTRL, DBG_CORE_CTRL_ICRESET), "resetting icache");
433 }
434
435 static const char *fast_spr_names[] =
436 {
437 "lr", "ctr", "srr0", "srr1", "hsrr0", "hsrr1",
438 "sprg0", "sprg1", "sprg2", "sprg3",
439 "hsprg0", "hsprg1", "xer"
440 };
441
442 static void gpr_read(uint64_t reg, uint64_t count)
443 {
444 uint64_t data;
445
446 reg &= 0x3f;
447 if (reg + count > 64)
448 count = 64 - reg;
449 for (; count != 0; --count, ++reg) {
450 check(dmi_write(DBG_CORE_GSPR_INDEX, reg), "setting GPR index");
451 data = 0xdeadbeef;
452 check(dmi_read(DBG_CORE_GSPR_DATA, &data), "reading GPR data");
453 if (reg <= 31)
454 printf("r%"PRId64, reg);
455 else if ((reg - 32) < sizeof(fast_spr_names) / sizeof(fast_spr_names[0]))
456 printf("%s", fast_spr_names[reg - 32]);
457 else
458 printf("gspr%"PRId64, reg);
459 printf(":\t%016"PRIx64"\n", data);
460 }
461 }
462
463 static void mem_read(uint64_t addr, uint64_t count)
464 {
465 uint64_t data;
466 int i, rc;
467
468 rc = dmi_write(DBG_WB_CTRL, 0x7ff);
469 if (rc < 0)
470 return;
471 rc = dmi_write(DBG_WB_ADDR, addr);
472 if (rc < 0)
473 return;
474 for (i = 0; i < count; i++) {
475 rc = dmi_read(DBG_WB_DATA, &data);
476 if (rc < 0)
477 return;
478 printf("%016llx: %016llx\n",
479 (unsigned long long)addr,
480 (unsigned long long)data);
481 addr += 8;
482 }
483 }
484
485 static void mem_write(uint64_t addr, uint64_t data)
486 {
487 check(dmi_write(DBG_WB_CTRL, 0x7ff), "writing WB_CTRL");
488 check(dmi_write(DBG_WB_ADDR, addr), "writing WB_ADDR");
489 check(dmi_write(DBG_WB_DATA, data), "writing WB_DATA");
490 }
491
492 static void load(const char *filename, uint64_t addr)
493 {
494 uint64_t data;
495 int fd, rc, count;
496
497 fd = open(filename, O_RDONLY);
498 if (fd < 0) {
499 fprintf(stderr, "Failed to open '%s': %s\n", filename, strerror(errno));
500 exit(1);
501 }
502 check(dmi_write(DBG_WB_CTRL, 0x7ff), "writing WB_CTRL");
503 check(dmi_write(DBG_WB_ADDR, addr), "writing WB_ADDR");
504 count = 0;
505 for (;;) {
506 data = 0;
507 rc = read(fd, &data, 8);
508 if (rc <= 0)
509 break;
510 // if (rc < 8) XXX fixup endian ?
511 check(dmi_write(DBG_WB_DATA, data), "writing WB_DATA");
512 count += 8;
513 if (!(count % 1024)) {
514 printf("%x...\r", count);
515 fflush(stdout);
516 }
517 }
518 close(fd);
519 printf("%x done.\n", count);
520 }
521
522 static void save(const char *filename, uint64_t addr, uint64_t size)
523 {
524 uint64_t data;
525 int fd, rc, count;
526
527 fd = open(filename, O_WRONLY | O_CREAT, 00666);
528 if (fd < 0) {
529 fprintf(stderr, "Failed to open '%s': %s\n", filename, strerror(errno));
530 exit(1);
531 }
532 check(dmi_write(DBG_WB_CTRL, 0x7ff), "writing WB_CTRL");
533 check(dmi_write(DBG_WB_ADDR, addr), "writing WB_ADDR");
534 count = 0;
535 for (;;) {
536 check(dmi_read(DBG_WB_DATA, &data), "reading WB_DATA");
537 rc = write(fd, &data, 8);
538 if (rc <= 0) {
539 fprintf(stderr, "Failed to write: %s\n", strerror(errno));
540 break;
541 }
542 count += 8;
543 if (!(count % 1024)) {
544 printf("%x...\r", count);
545 fflush(stdout);
546 }
547 if (count >= size)
548 break;
549 }
550 close(fd);
551 printf("%x done.\n", count);
552 }
553
554 #define LOG_STOP 0x80000000ull
555
556 static void log_start(void)
557 {
558 check(dmi_write(DBG_LOG_ADDR, 0), "writing LOG_ADDR");
559 }
560
561 static void log_stop(void)
562 {
563 uint64_t lsize, laddr, waddr;
564
565 check(dmi_write(DBG_LOG_ADDR, LOG_STOP), "writing LOG_ADDR");
566 check(dmi_read(DBG_LOG_ADDR, &laddr), "reading LOG_ADDR");
567 waddr = laddr >> 32;
568 for (lsize = 1; lsize; lsize <<= 1)
569 if ((waddr >> 1) < lsize)
570 break;
571 waddr &= ~lsize;
572 printf("Log size = %" PRIu64 " entries, ", lsize);
573 printf("write ptr = %" PRIx64 "\n", waddr);
574 }
575
576 static void log_dump(const char *filename)
577 {
578 FILE *f;
579 uint64_t lsize, laddr, waddr;
580 uint64_t orig_laddr;
581 uint64_t i, ldata;
582
583 f = fopen(filename, "w");
584 if (f == NULL) {
585 fprintf(stderr, "Failed to create '%s': %s\n", filename,
586 strerror(errno));
587 exit(1);
588 }
589
590 check(dmi_read(DBG_LOG_ADDR, &orig_laddr), "reading LOG_ADDR");
591 if (!(orig_laddr & LOG_STOP))
592 check(dmi_write(DBG_LOG_ADDR, LOG_STOP), "writing LOG_ADDR");
593
594 waddr = orig_laddr >> 32;
595 for (lsize = 1; lsize; lsize <<= 1)
596 if ((waddr >> 1) < lsize)
597 break;
598 waddr &= ~lsize;
599 printf("Log size = %" PRIu64 " entries\n", lsize);
600
601 laddr = LOG_STOP | (waddr << 2);
602 check(dmi_write(DBG_LOG_ADDR, laddr), "writing LOG_ADDR");
603
604 for (i = 0; i < lsize * 4; ++i) {
605 check(dmi_read(DBG_LOG_DATA, &ldata), "reading LOG_DATA");
606 if (fwrite(&ldata, sizeof(ldata), 1, f) != 1) {
607 fprintf(stderr, "Write error on %s\n", filename);
608 exit(1);
609 }
610 if (!(i % 128)) {
611 printf("%" PRIu64 "...\r", i * 8);
612 fflush(stdout);
613 }
614 }
615 fclose(f);
616 printf("%" PRIu64 " done\n", lsize * 32);
617
618 check(dmi_write(DBG_LOG_ADDR, orig_laddr), "writing LOG_ADDR");
619 }
620
621 static void usage(const char *cmd)
622 {
623 fprintf(stderr, "Usage: %s -b <jtag|sim> <command> <args>\n", cmd);
624
625 fprintf(stderr, "\n");
626 fprintf(stderr, " CPU core:\n");
627 fprintf(stderr, " start\n");
628 fprintf(stderr, " stop\n");
629 fprintf(stderr, " step\n");
630 fprintf(stderr, " creset core reset\n");
631 fprintf(stderr, " icreset icache reset\n");
632
633 fprintf(stderr, "\n");
634 fprintf(stderr, " Memory:\n");
635 fprintf(stderr, " mr <hex addr> [count]\n");
636 fprintf(stderr, " mw <hex addr> <hex value>\n");
637 fprintf(stderr, " load <file> [addr] If omitted address is 0\n");
638 fprintf(stderr, " save <file> <addr> <size>\n");
639
640 fprintf(stderr, "\n");
641 fprintf(stderr, " Registers:\n");
642 fprintf(stderr, " gpr <reg> [count]\n");
643 fprintf(stderr, " status\n");
644
645 fprintf(stderr, "\n");
646 fprintf(stderr, " Core logging:\n");
647 fprintf(stderr, " lstart start logging\n");
648 fprintf(stderr, " lstop stop logging\n");
649 fprintf(stderr, " ldump <file> dump log to file\n");
650
651 fprintf(stderr, "\n");
652 fprintf(stderr, " JTAG:\n");
653 fprintf(stderr, " dmiread <hex addr>\n");
654 fprintf(stderr, " dmiwrite <hex addr> <hex value>\n");
655 fprintf(stderr, " quit\n");
656
657 exit(1);
658 }
659
660 int main(int argc, char *argv[])
661 {
662 const char *progname = argv[0];
663 const char *target = NULL;
664 int rc, i = 1;
665
666 b = NULL;
667
668 while(1) {
669 int c, oindex;
670 static struct option lopts[] = {
671 { "help", no_argument, 0, 'h' },
672 { "backend", required_argument, 0, 'b' },
673 { "target", required_argument, 0, 't' },
674 { "debug", no_argument, 0, 'd' },
675 { 0, 0, 0, 0 }
676 };
677 c = getopt_long(argc, argv, "dhb:t:", lopts, &oindex);
678 if (c < 0)
679 break;
680 switch(c) {
681 case 'h':
682 usage(progname);
683 break;
684 case 'b':
685 if (strcmp(optarg, "sim") == 0)
686 b = &sim_backend;
687 else if (strcmp(optarg, "jtag") == 0)
688 b = &jtag_backend;
689 else {
690 fprintf(stderr, "Unknown backend %s\n", optarg);
691 exit(1);
692 }
693 break;
694 case 't':
695 target = optarg;
696 break;
697 case 'd':
698 debug = true;
699 }
700 }
701
702 if (b == NULL) {
703 fprintf(stderr, "No backend selected\n");
704 exit(1);
705 }
706
707 rc = b->init(target);
708 if (rc < 0)
709 exit(1);
710 for (i = optind; i < argc; i++) {
711 if (strcmp(argv[i], "dmiread") == 0) {
712 uint8_t addr;
713 uint64_t data;
714
715 if ((i+1) >= argc)
716 usage(argv[0]);
717 addr = strtoul(argv[++i], NULL, 16);
718 dmi_read(addr, &data);
719 printf("%02x: %016llx\n", addr, (unsigned long long)data);
720 } else if (strcmp(argv[i], "dmiwrite") == 0) {
721 uint8_t addr;
722 uint64_t data;
723
724 if ((i+2) >= argc)
725 usage(argv[0]);
726 addr = strtoul(argv[++i], NULL, 16);
727 data = strtoul(argv[++i], NULL, 16);
728 dmi_write(addr, data);
729 } else if (strcmp(argv[i], "creset") == 0) {
730 core_reset();
731 } else if (strcmp(argv[i], "icreset") == 0) {
732 icache_reset();
733 } else if (strcmp(argv[i], "stop") == 0) {
734 core_stop();
735 } else if (strcmp(argv[i], "start") == 0) {
736 core_start();
737 } else if (strcmp(argv[i], "step") == 0) {
738 core_step();
739 } else if (strcmp(argv[i], "quit") == 0) {
740 dmi_write(0xff, 0);
741 } else if (strcmp(argv[i], "status") == 0) {
742 /* do nothing, always done below */
743 } else if (strcmp(argv[i], "mr") == 0) {
744 uint64_t addr, count = 1;
745
746 if ((i+1) >= argc)
747 usage(argv[0]);
748 addr = strtoul(argv[++i], NULL, 16);
749 if (((i+1) < argc) && isdigit(argv[i+1][0]))
750 count = strtoul(argv[++i], NULL, 16);
751 mem_read(addr, count);
752 } else if (strcmp(argv[i], "mw") == 0) {
753 uint64_t addr, data;
754
755 if ((i+2) >= argc)
756 usage(argv[0]);
757 addr = strtoul(argv[++i], NULL, 16);
758 data = strtoul(argv[++i], NULL, 16);
759 mem_write(addr, data);
760 } else if (strcmp(argv[i], "load") == 0) {
761 const char *filename;
762 uint64_t addr = 0;
763
764 if ((i+1) >= argc)
765 usage(argv[0]);
766 filename = argv[++i];
767 if (((i+1) < argc) && isdigit(argv[i+1][0]))
768 addr = strtoul(argv[++i], NULL, 16);
769 load(filename, addr);
770 } else if (strcmp(argv[i], "save") == 0) {
771 const char *filename;
772 uint64_t addr, size;
773
774 if ((i+3) >= argc)
775 usage(argv[0]);
776 filename = argv[++i];
777 addr = strtoul(argv[++i], NULL, 16);
778 size = strtoul(argv[++i], NULL, 16);
779 save(filename, addr, size);
780 } else if (strcmp(argv[i], "gpr") == 0) {
781 uint64_t reg, count = 1;
782
783 if ((i+1) >= argc)
784 usage(argv[0]);
785 reg = strtoul(argv[++i], NULL, 10);
786 if (((i+1) < argc) && isdigit(argv[i+1][0]))
787 count = strtoul(argv[++i], NULL, 10);
788 gpr_read(reg, count);
789 } else if (strcmp(argv[i], "lstart") == 0) {
790 log_start();
791 } else if (strcmp(argv[i], "lstop") == 0) {
792 log_stop();
793 } else if (strcmp(argv[i], "ldump") == 0) {
794 const char *filename;
795
796 if ((i+1) >= argc)
797 usage(argv[0]);
798 filename = argv[++i];
799 log_dump(filename);
800 } else {
801 fprintf(stderr, "Unknown command %s\n", argv[i]);
802 exit(1);
803 }
804 }
805 core_status();
806 return 0;
807 }