fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/arch/simarm/cmd_arm.c *
7 * Created: 2004-11-04 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2004-2013 Hampa Hug <hampa@hampa.ch> *
9 * Copyright: (C) 2004-2006 Lukas Ruf <ruf@lpr.ch> *
10 *****************************************************************************/
11
12/*****************************************************************************
13 * This program is free software. You can redistribute it and / or modify it *
14 * under the terms of the GNU General Public License version 2 as published *
15 * by the Free Software Foundation. *
16 * *
17 * This program is distributed in the hope that it will be useful, but *
18 * WITHOUT ANY WARRANTY, without even the implied warranty of *
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
20 * Public License for more details. *
21 *****************************************************************************/
22
23/*****************************************************************************
24 * This software was developed at the Computer Engineering and Networks *
25 * Laboratory (TIK), Swiss Federal Institute of Technology (ETH) Zurich. *
26 *****************************************************************************/
27
28
29#include "main.h"
30#include "cmd_arm.h"
31#include "simarm.h"
32
33#include <cpu/arm/arm.h>
34
35#include <lib/console.h>
36#include <lib/log.h>
37#include <lib/monitor.h>
38#include <lib/sysdep.h>
39
40
41static mon_cmd_t par_cmd[] = {
42 { "c", "[cnt]", "clock" },
43 { "gb", "[addr...]", "run with breakpoints" },
44 { "g", "", "run" },
45 { "key", "[val...]", "send keycodes to the serial console" },
46 { "p", "[cnt]", "execute cnt instructions, skip calls [1]" },
47 { "r", "reg [val]", "get or set a register" },
48 { "s", "[what]", "print status (cpu|intc|mem|mmu|timer)" },
49 { "t", "[cnt]", "execute cnt instructions [1]" },
50 { "u", "[addr [cnt]]", "disassemble" },
51 { "x", "[c|r|v]", "set the translation mode (cpu, real, virtual)" },
52 { "xx", "[addr...]", "translate a virtual address" }
53};
54
55
56static const char *arm_modes[32] = {
57 "0x00", "0x01", "0x02", "0x03",
58 "0x04", "0x05", "0x06", "0x07",
59 "0x08", "0x09", "0x0a", "0x0b",
60 "0x0c", "0x0d", "0x0e", "0x0f",
61 "usr", "fiq", "irq", "svc",
62 "0x14", "0x15", "0x16", "abt",
63 "0x18", "0x19", "und", "0x1b",
64 "0x1c", "0x1d", "0x1e", "sys"
65};
66
67void sarm_dasm_str (char *dst, arm_dasm_t *op)
68{
69 unsigned i, j;
70
71 if (op->argn == 0) {
72 sprintf (dst, "%08lX %s", (unsigned long) op->ir, op->op);
73 }
74 else {
75 j = sprintf (dst, "%08lX %-8s %s", (unsigned long) op->ir, op->op, op->arg[0]);
76
77 for (i = 1; i < op->argn; i++) {
78 j += sprintf (dst + j, ", %s", op->arg[i]);
79 }
80 }
81}
82
83void sarm_prt_state_cpu (arm_t *c, FILE *fp)
84{
85 unsigned long long opcnt, clkcnt;
86 unsigned long delay;
87 arm_dasm_t op;
88 char str[256];
89
90 pce_prt_sep ("ARM");
91
92 opcnt = arm_get_opcnt (c);
93 clkcnt = arm_get_clkcnt (c);
94 delay = arm_get_delay (c);
95
96 fprintf (fp, "CLK=%llx OP=%llx DLY=%lx CPI=%.4f\n",
97 clkcnt, opcnt, delay,
98 (opcnt > 0) ? ((double) (clkcnt + delay) / (double) opcnt) : 1.0
99 );
100
101 fprintf (fp, "r00=%08lX r04=%08lX r08=%08lX r12=%08lX CPSR=%08lX\n",
102 (unsigned long) arm_get_gpr (c, 0),
103 (unsigned long) arm_get_gpr (c, 4),
104 (unsigned long) arm_get_gpr (c, 8),
105 (unsigned long) arm_get_gpr (c, 12),
106 (unsigned long) arm_get_cpsr (c)
107 );
108
109 fprintf (fp, "r01=%08lX r05=%08lX r09=%08lX r13=%08lX SPSR=%08lX\n",
110 (unsigned long) arm_get_gpr (c, 1),
111 (unsigned long) arm_get_gpr (c, 5),
112 (unsigned long) arm_get_gpr (c, 9),
113 (unsigned long) arm_get_gpr (c, 13),
114 (unsigned long) arm_get_spsr (c)
115 );
116
117 fprintf (fp, "r02=%08lX r06=%08lX r10=%08lX r14=%08lX CC=[%c%c%c%c]\n",
118 (unsigned long) arm_get_gpr (c, 2),
119 (unsigned long) arm_get_gpr (c, 6),
120 (unsigned long) arm_get_gpr (c, 10),
121 (unsigned long) arm_get_gpr (c, 14),
122 (arm_get_cc_n (c)) ? 'N' : '-',
123 (arm_get_cc_z (c)) ? 'Z' : '-',
124 (arm_get_cc_c (c)) ? 'C' : '-',
125 (arm_get_cc_v (c)) ? 'V' : '-'
126 );
127
128 fprintf (fp, "r03=%08lX r07=%08lX r11=%08lX r15=%08lX M=%02X (%s)\n",
129 (unsigned long) arm_get_gpr (c, 3),
130 (unsigned long) arm_get_gpr (c, 7),
131 (unsigned long) arm_get_gpr (c, 11),
132 (unsigned long) arm_get_gpr (c, 15),
133 (unsigned) arm_get_cpsr_m (c),
134 arm_modes[arm_get_cpsr_m (c) & 0x1f]
135 );
136
137 arm_dasm_mem (c, &op, arm_get_pc (c), par_xlat);
138 sarm_dasm_str (str, &op);
139
140 fprintf (fp, "%08lX %s\n", (unsigned long) arm_get_pc (c), str);
141}
142
143void sarm_prt_state_mmu (arm_t *c, FILE *fp)
144{
145 arm_copr15_t *p;
146
147 pce_prt_sep ("ARM MMU");
148
149 p = c->copr[15]->ext;
150
151 fprintf (fp, "CR=[%c%c%c%c%c%c%c%c%c%c%c%c%c]\n",
152 (p->reg[1] & ARM_C15_CR_V) ? 'V' : 'v',
153 (p->reg[1] & ARM_C15_CR_I) ? 'I' : 'i',
154 (p->reg[1] & ARM_C15_CR_Z) ? 'Z' : 'z',
155 (p->reg[1] & ARM_C15_CR_R) ? 'R' : 'r',
156 (p->reg[1] & ARM_C15_CR_S) ? 'S' : 's',
157 (p->reg[1] & ARM_C15_CR_B) ? 'B' : 'b',
158 (p->reg[1] & ARM_C15_CR_L) ? 'L' : 'l',
159 (p->reg[1] & ARM_C15_CR_D) ? 'D' : 'd',
160 (p->reg[1] & ARM_C15_CR_P) ? 'P' : 'p',
161 (p->reg[1] & ARM_C15_CR_W) ? 'W' : 'w',
162 (p->reg[1] & ARM_C15_CR_C) ? 'C' : 'c',
163 (p->reg[1] & ARM_C15_CR_A) ? 'A' : 'a',
164 (p->reg[1] & ARM_C15_CR_M) ? 'M' : 'm'
165 );
166
167 fprintf (fp, "c00=%08lX c04=%08lX c08=%08lX c12=%08lX\n",
168 (unsigned long) p->reg[0],
169 (unsigned long) p->reg[4],
170 (unsigned long) p->reg[8],
171 (unsigned long) p->reg[12]
172 );
173
174 fprintf (fp, "c01=%08lX c05=%08lX c09=%08lX c13=%08lX\n",
175 (unsigned long) p->reg[1],
176 (unsigned long) p->reg[5],
177 (unsigned long) p->reg[9],
178 (unsigned long) p->reg[13]
179 );
180
181 fprintf (fp, "c02=%08lX c06=%08lX c10=%08lX c14=%08lX\n",
182 (unsigned long) p->reg[2],
183 (unsigned long) p->reg[6],
184 (unsigned long) p->reg[10],
185 (unsigned long) p->reg[14]
186 );
187
188 fprintf (fp, "c03=%08lX c07=%08lX c11=%08lX c15=%08lX\n",
189 (unsigned long) p->reg[3],
190 (unsigned long) p->reg[7],
191 (unsigned long) p->reg[11],
192 (unsigned long) p->reg[15]
193 );
194}
195
196void sarm_prt_state_timer (ixp_timer_t *tmr, FILE *fp)
197{
198 unsigned i;
199 ixp_timer_counter_t *cnt;
200
201 pce_prt_sep ("IXP TIMER");
202
203 fprintf (fp, "ADDR=%08lX\n", tmr->base);
204
205 for (i = 0; i < 4; i++) {
206 cnt = &tmr->cntr[i];
207
208 fprintf (fp, "T%u: %c VAL=%08lX LOAD=%08lX CTL=%08lX IRQ=%d\n",
209 i,
210 tmr_get_active (tmr, i) ? 'R' : 'S',
211 (unsigned long) cnt->status,
212 (unsigned long) cnt->load,
213 (unsigned long) cnt->ctrl,
214 cnt->irq_val != 0
215 );
216 }
217}
218
219void sarm_prt_state_intc (simarm_t *sim, FILE *fp)
220{
221 ixp_intc_t *ic;
222
223 pce_prt_sep ("IXP INTC");
224
225 ic = sim->intc;
226
227 fprintf (fp, "inp raw: %08lx\n", ic->status_raw);
228 fprintf (fp, "ena irq: %08lx\n", ic->enable_irq);
229 fprintf (fp, "out irq: %08lx (%d)\n", ic->status_irq, (int) ic->irq_val);
230 fprintf (fp, "\n");
231 fprintf (fp, "inp raw: %08lx\n", ic->status_raw);
232 fprintf (fp, "ena fiq: %08lx\n", ic->enable_fiq);
233 fprintf (fp, "out fiq: %08lx (%d)\n", ic->status_fiq, (int) ic->fiq_val);
234}
235
236void sarm_prt_state_mem (simarm_t *sim, FILE *fp)
237{
238 pce_prt_sep ("ARM MEM");
239 mem_prt_state (sim->mem, fp);
240}
241
242void prt_state (simarm_t *sim, FILE *fp, const char *str)
243{
244 cmd_t cmd;
245
246 cmd_set_str (&cmd, str);
247
248 if (cmd_match_eol (&cmd)) {
249 return;
250 }
251
252 while (!cmd_match_eol (&cmd)) {
253 if (cmd_match (&cmd, "cpu")) {
254 sarm_prt_state_cpu (sim->cpu, fp);
255 }
256 else if (cmd_match (&cmd, "mmu")) {
257 sarm_prt_state_mmu (sim->cpu, fp);
258 }
259 else if (cmd_match (&cmd, "timer")) {
260 sarm_prt_state_timer (sim->timer, fp);
261 }
262 else if (cmd_match (&cmd, "intc")) {
263 sarm_prt_state_intc (sim, fp);
264 }
265 else if (cmd_match (&cmd, "mem")) {
266 sarm_prt_state_mem (sim, fp);
267 }
268 else {
269 printf ("unknown component (%s)\n", cmd_get_str (&cmd));
270 return;
271 }
272 }
273}
274
275
276static
277void sarm_exec (simarm_t *sim)
278{
279 unsigned long long old;
280
281 old = arm_get_opcnt (sim->cpu);
282
283 while (arm_get_opcnt (sim->cpu) == old) {
284 sarm_clock (sim, 1);
285 }
286}
287
288static
289int sarm_check_break (simarm_t *sim)
290{
291 if (bps_check (&sim->bps, 0, arm_get_pc (sim->cpu), stdout)) {
292 return (1);
293 }
294
295 if (sim->brk) {
296 return (1);
297 }
298
299 return (0);
300}
301
302static
303int sarm_exec_to (simarm_t *sim, unsigned long addr)
304{
305 while (arm_get_pc (sim->cpu) != addr) {
306 sarm_clock (sim, 1);
307
308 if (sim->brk) {
309 return (1);
310 }
311 }
312
313 return (0);
314}
315
316static
317int sarm_exec_off (simarm_t *sim, unsigned long addr)
318{
319 while (arm_get_pc (sim->cpu) == addr) {
320 sarm_clock (sim, 1);
321
322 if (sim->brk) {
323 return (1);
324 }
325 }
326
327 return (0);
328}
329
330void sarm_run (simarm_t *sim)
331{
332 pce_start (&sim->brk);
333
334 sarm_clock_discontinuity (sim);
335
336 while (1) {
337 sarm_clock (sim, 16);
338
339 if (sim->brk) {
340 break;
341 }
342 }
343
344 pce_stop();
345}
346
347
348#if 0
349static
350int sarm_log_opcode (void *ext, unsigned long ir)
351{
352 simarm_t *sim = ext;
353
354 return (0);
355}
356#endif
357
358static
359void sarm_log_undef (void *ext, unsigned long ir)
360{
361 simarm_t *sim = ext;
362
363 if ((ir & 0x0f000000UL) == 0x0c000000UL) {
364 return;
365 }
366
367 if ((ir & 0x0f000000UL) == 0x0d000000UL) {
368 return;
369 }
370
371 pce_log (MSG_DEB,
372 "%08lX: undefined operation [%08lX]\n",
373 (unsigned long) arm_get_pc (sim->cpu), ir
374 );
375}
376
377static
378void sarm_log_trap (void *ext, unsigned long addr)
379{
380 simarm_t *sim = ext;
381 char *name;
382
383 switch (addr & 0xff) {
384 case 0x04:
385 name = "undefined operation";
386 name = NULL;
387 break;
388
389 case 0x08:
390 name = "swi";
391 name = NULL;
392 break;
393
394 case 0x0c:
395 name = "prefetch abort";
396 name = NULL;
397 break;
398
399 case 0x10:
400 name = "data abort";
401 name = NULL;
402 break;
403
404 case 0x18:
405 name = "irq";
406 name = NULL;
407 break;
408
409 case 0x1c:
410 name = "fiq";
411 break;
412
413 default:
414 name = "unknown";
415 break;
416 }
417
418 if (name != NULL) {
419 pce_log (MSG_DEB, "%08lX (%08lX): exception %lx (%s)\n",
420 (unsigned long) arm_get_pc (sim->cpu),
421 (unsigned long) arm_get_last_pc (sim->cpu),
422 addr, name
423 );
424 }
425}
426
427static
428void do_c (cmd_t *cmd, simarm_t *sim)
429{
430 unsigned long cnt;
431
432 cnt = 1;
433
434 cmd_match_uint32 (cmd, &cnt);
435
436 if (!cmd_match_end (cmd)) {
437 return;
438 }
439
440 sarm_clock_discontinuity (sim);
441
442 while (cnt > 0) {
443 sarm_clock (sim, 1);
444 cnt -= 1;
445 }
446
447 sarm_prt_state_cpu (sim->cpu, stdout);
448}
449
450static
451void do_g_b (cmd_t *cmd, simarm_t *sim)
452{
453 unsigned long addr;
454 breakpoint_t *bp;
455
456 while (cmd_match_uint32 (cmd, &addr)) {
457 bp = bp_addr_new (addr);
458 bps_bp_add (&sim->bps, bp);
459 }
460
461 if (!cmd_match_end (cmd)) {
462 return;
463 }
464
465 pce_start (&sim->brk);
466
467 sarm_clock_discontinuity (sim);
468
469 while (1) {
470 sarm_exec (sim);
471
472 if (sarm_check_break (sim)) {
473 break;
474 }
475 }
476
477 pce_stop();
478}
479
480static
481void do_g (cmd_t *cmd, simarm_t *sim)
482{
483 if (cmd_match (cmd, "b")) {
484 do_g_b (cmd, sim);
485 return;
486 }
487
488 if (!cmd_match_end (cmd)) {
489 return;
490 }
491
492 sarm_run (sim);
493}
494
495static
496void do_key (cmd_t *cmd, simarm_t *sim)
497{
498 unsigned short c;
499
500 while (cmd_match_uint16 (cmd, &c)) {
501 sarm_set_keycode (sim, c);
502 }
503
504 if (!cmd_match_end (cmd)) {
505 return;
506 }
507}
508
509static
510void do_p (cmd_t *cmd, simarm_t *sim)
511{
512 unsigned long cnt;
513 arm_dasm_t da;
514
515 cnt = 1;
516
517 cmd_match_uint32 (cmd, &cnt);
518
519 if (!cmd_match_end (cmd)) {
520 return;
521 }
522
523 pce_start (&sim->brk);
524
525 sarm_clock_discontinuity (sim);
526
527 while (cnt > 0) {
528 arm_dasm_mem (sim->cpu, &da, arm_get_pc (sim->cpu), ARM_XLAT_CPU);
529
530 if (da.flags & ARM_DFLAG_CALL) {
531 if (sarm_exec_to (sim, arm_get_pc (sim->cpu) + 4)) {
532 break;
533 }
534 }
535 else {
536 uint32_t cpsr;
537
538 cpsr = arm_get_cpsr (sim->cpu);
539
540 if (sarm_exec_off (sim, arm_get_pc (sim->cpu))) {
541 break;
542 }
543
544 if ((cpsr & ARM_PSR_M) == ARM_MODE_USR) {
545 /* check if exception occured */
546 while (arm_get_cpsr_m (sim->cpu) != ARM_MODE_USR) {
547 sarm_clock (sim, 1);
548
549 if (sim->brk) {
550 break;
551 }
552 }
553 }
554 }
555
556 cnt -= 1;
557 }
558
559 pce_stop();
560
561 sarm_prt_state_cpu (sim->cpu, stdout);
562}
563
564static
565void do_r (cmd_t *cmd, simarm_t *sim)
566{
567 unsigned long val;
568 char sym[256];
569
570 if (cmd_match_eol (cmd)) {
571 sarm_prt_state_cpu (sim->cpu, stdout);
572 return;
573 }
574
575 if (!cmd_match_ident (cmd, sym, 256)) {
576 printf ("missing register\n");
577 return;
578 }
579
580 if (arm_get_reg (sim->cpu, sym, &val)) {
581 printf ("bad register (%s)\n", sym);
582 return;
583 }
584
585 if (cmd_match_eol (cmd)) {
586 printf ("%08lX\n", val);
587 return;
588 }
589
590 if (!cmd_match_uint32 (cmd, &val)) {
591 printf ("missing value\n");
592 return;
593 }
594
595 if (!cmd_match_end (cmd)) {
596 return;
597 }
598
599 arm_set_reg (sim->cpu, sym, val);
600
601 sarm_prt_state_cpu (sim->cpu, stdout);
602}
603
604static
605void do_s (cmd_t *cmd, simarm_t *sim)
606{
607 if (cmd_match_eol (cmd)) {
608 sarm_prt_state_cpu (sim->cpu, stdout);
609 return;
610 }
611
612 prt_state (sim, stdout, cmd_get_str (cmd));
613}
614
615static
616void do_t (cmd_t *cmd, simarm_t *sim)
617{
618 unsigned long i, n;
619
620 n = 1;
621
622 cmd_match_uint32 (cmd, &n);
623
624 if (!cmd_match_end (cmd)) {
625 return;
626 }
627
628 pce_start (&sim->brk);
629
630 sarm_clock_discontinuity (sim);
631
632 for (i = 0; i < n; i++) {
633 sarm_exec (sim);
634 }
635
636 pce_stop();
637
638 sarm_prt_state_cpu (sim->cpu, stdout);
639}
640
641static
642void do_u (cmd_t *cmd, simarm_t *sim)
643{
644 unsigned i;
645 int to;
646 unsigned long addr, cnt;
647 static unsigned int first = 1;
648 static unsigned long saddr = 0;
649 arm_dasm_t op;
650 char str[256];
651
652 if (first) {
653 first = 0;
654 saddr = arm_get_pc (sim->cpu);
655 }
656
657 to = 0;
658 addr = saddr;
659 cnt = 16;
660
661 if (cmd_match (cmd, "-")) {
662 to = 1;
663 }
664
665 if (cmd_match_uint32 (cmd, &addr)) {
666 cmd_match_uint32 (cmd, &cnt);
667 }
668
669 if (!cmd_match_end (cmd)) {
670 return;
671 }
672
673 if (to) {
674 addr -= 4 * (cnt - 1);
675 }
676
677 for (i = 0; i < cnt; i++) {
678 arm_dasm_mem (sim->cpu, &op, addr, par_xlat);
679 sarm_dasm_str (str, &op);
680
681 fprintf (stdout, "%08lX %s\n", addr, str);
682
683 addr += 4;
684 }
685
686 saddr = addr;
687}
688
689static
690void do_xx (cmd_t *cmd, simarm_t *sim)
691{
692 unsigned long addr1;
693 uint32_t addr2;
694 unsigned domn, perm;
695
696 while (cmd_match_uint32 (cmd, &addr1)) {
697 addr2 = addr1;
698 if (arm_translate_extern (sim->cpu, &addr2, par_xlat, &domn, &perm)) {
699 printf ("%08lX translation abort\n", addr1);
700 }
701 else {
702 printf ("%08lX -> %08lX D=%02X P=%02X\n",
703 addr1, (unsigned long) addr2, domn, perm
704 );
705 }
706 }
707}
708
709static
710void do_x (cmd_t *cmd, simarm_t *sim)
711{
712 if (cmd_match_eol (cmd)) {
713 switch (par_xlat) {
714 case ARM_XLAT_CPU:
715 printf ("xlat cpu\n");
716 break;
717
718 case ARM_XLAT_REAL:
719 printf ("xlat real\n");
720 break;
721
722 case ARM_XLAT_VIRTUAL:
723 printf ("xlat virtual\n");
724 break;
725
726 default:
727 printf ("xlat unknown\n");
728 break;
729 }
730
731 return;
732 }
733
734 if (cmd_match (cmd, "c")) {
735 par_xlat = ARM_XLAT_CPU;
736 }
737 else if (cmd_match (cmd, "r")) {
738 par_xlat = ARM_XLAT_REAL;
739 }
740 else if (cmd_match (cmd, "v")) {
741 par_xlat = ARM_XLAT_VIRTUAL;
742 }
743 else if (cmd_match (cmd, "x")) {
744 do_xx (cmd, sim);
745 }
746 else {
747 cmd_error (cmd, "unknown translation type");
748 return;
749 }
750
751 if (!cmd_match_end (cmd)) {
752 return;
753 }
754}
755
756int sarm_do_cmd (simarm_t *sim, cmd_t *cmd)
757{
758 if (cmd_match (cmd, "b")) {
759 cmd_do_b (cmd, &sim->bps);
760 }
761 else if (cmd_match (cmd, "c")) {
762 do_c (cmd, sim);
763 }
764 else if (cmd_match (cmd, "g")) {
765 do_g (cmd, sim);
766 }
767 else if (cmd_match (cmd, "key")) {
768 do_key (cmd, sim);
769 }
770 else if (cmd_match (cmd, "p")) {
771 do_p (cmd, sim);
772 }
773 else if (cmd_match (cmd, "r")) {
774 do_r (cmd, sim);
775 }
776 else if (cmd_match (cmd, "s")) {
777 do_s (cmd, sim);
778 }
779 else if (cmd_match (cmd, "t")) {
780 do_t (cmd, sim);
781 }
782 else if (cmd_match (cmd, "u")) {
783 do_u (cmd, sim);
784 }
785 else if (cmd_match (cmd, "x")) {
786 do_x (cmd, sim);
787 }
788 else {
789 return (1);
790 }
791
792 return (0);
793}
794
795void sarm_cmd_init (simarm_t *sim, monitor_t *mon)
796{
797 mon_cmd_add (mon, par_cmd, sizeof (par_cmd) / sizeof (par_cmd[0]));
798 mon_cmd_add_bp (mon);
799
800 sim->cpu->log_ext = sim;
801 sim->cpu->log_opcode = NULL;
802 sim->cpu->log_undef = sarm_log_undef;
803 sim->cpu->log_exception = sarm_log_trap;
804}