Initial revision
[deliverable/binutils-gdb.git] / binutils / m68k-pinsn.c
1 /* Print m68k instructions for objdump
2 Copyright (C) 1986, 1987, 1989 Free Software Foundation, Inc.
3
4
5 This file is part of the binutils.
6
7 The binutils are free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 1, or (at your option)
10 any later version.
11
12 The binutils are distributed in the hope that they will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with the binutils; see the file COPYING. If not, write to
19 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21 /* $Id$
22 $Log$
23 Revision 1.1 1991/03/21 21:26:45 gumby
24 Initial revision
25
26 * Revision 1.1 1991/03/13 00:34:06 chrisb
27 * Initial revision
28 *
29 * Revision 1.4 1991/03/09 04:36:34 rich
30 * Modified Files:
31 * sparc-pinsn.c ostrip.c objdump.c m68k-pinsn.c i960-pinsn.c
32 * binutils.h
33 *
34 * Pulled sysdep.h out of bfd.h.
35 *
36 * Revision 1.3 1991/03/08 21:54:45 rich
37 * Modified Files:
38 * Makefile ar.c binutils.h bucomm.c copy.c cplus-dem.c getopt.c
39 * i960-pinsn.c m68k-pinsn.c nm.c objdump.c sparc-opcode.h
40 * sparc-pinsn.c strip.c
41 *
42 * Verifying Portland tree with steve's last changes. Also, some partial
43 * porting.
44 *
45 * Revision 1.2 1991/03/08 07:46:24 sac
46 * Added -l option to disassembly - prints line numbers too.
47 *
48 * Revision 1.1 1991/02/22 16:48:02 sac
49 * Initial revision
50 *
51 */
52
53 #include <stdio.h>
54 #include "sysdep.h"
55 #include "bfd.h"
56 #include "m68k-opcode.h"
57
58 extern int fputs();
59 extern void print_address();
60
61 /* 68k instructions are never longer than this many bytes. */
62 #define MAXLEN 22
63
64 /* Number of elements in the opcode table. */
65 #define NOPCODES (sizeof m68k_opcodes / sizeof m68k_opcodes[0])
66
67 extern char *reg_names[];
68 char *fpcr_names[] = { "", "fpiar", "fpsr", "fpiar/fpsr", "fpcr",
69 "fpiar/fpcr", "fpsr/fpcr", "fpiar-fpcr"};
70
71 char *reg_names[] = {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", "ps", "pc"};
72 static unsigned char *print_insn_arg ();
73 static unsigned char *print_indexed ();
74 static void print_base ();
75 static int fetch_arg ();
76
77 #define NEXTBYTE(p) (p += 2, ((char *)p)[-1])
78
79 #define NEXTWORD(p) \
80 (p += 2, ((((char *)p)[-2]) << 8) + p[-1])
81
82 #define NEXTLONG(p) \
83 (p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])
84
85 #define NEXTSINGLE(p) \
86 (p += 4, *((float *)(p - 4)))
87
88 #define NEXTDOUBLE(p) \
89 (p += 8, *((double *)(p - 8)))
90
91 #define NEXTEXTEND(p) \
92 (p += 12, 0.0) /* Need a function to convert from extended to double
93 precision... */
94
95 #define NEXTPACKED(p) \
96 (p += 12, 0.0) /* Need a function to convert from packed to double
97 precision. Actually, it's easier to print a
98 packed number than a double anyway, so maybe
99 there should be a special case to handle this... */
100 \f
101 /* Print the m68k instruction at address MEMADDR in debugged memory,
102 on STREAM. Returns length of the instruction, in bytes. */
103
104 int
105 print_insn_m68k(addr, buffer, stream)
106 bfd_vma addr;
107 unsigned char *buffer;
108 FILE *stream;
109 {
110 register unsigned int i;
111 register unsigned char *p;
112 register char *d;
113 register unsigned int bestmask;
114 int best;
115
116
117
118 bestmask = 0;
119 best = -1;
120 for (i = 0; i < NOPCODES; i++)
121 {
122 register unsigned int opcode = m68k_opcodes[i].opcode;
123 register unsigned int match = m68k_opcodes[i].match;
124 if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))
125 && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))
126 && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))
127 && ((0xff & buffer[3] & match) == (0xff & opcode)))
128 {
129 /* Don't use for printout the variants of divul and divsl
130 that have the same register number in two places.
131 The more general variants will match instead. */
132 for (d = m68k_opcodes[i].args; *d; d += 2)
133 if (d[1] == 'D')
134 break;
135
136 /* Don't use for printout the variants of most floating
137 point coprocessor instructions which use the same
138 register number in two places, as above. */
139 if (*d == 0)
140 for (d = m68k_opcodes[i].args; *d; d += 2)
141 if (d[1] == 't')
142 break;
143
144 if (*d == 0 && match > bestmask)
145 {
146 best = i;
147 bestmask = match;
148 }
149 }
150 }
151
152 /* Handle undefined instructions. */
153 if (best < 0)
154 {
155 fprintf (stream, "0%o", (unsigned) (buffer[0] << 8) + buffer[1]);
156 return 2;
157 }
158
159 fprintf (stream, "%s", m68k_opcodes[best].name);
160
161 /* Point at first word of argument data,
162 and at descriptor for first argument. */
163 p = buffer + 2;
164
165 /* Why do this this way? -MelloN */
166 for (d = m68k_opcodes[best].args; *d; d += 2)
167 {
168 if (d[0] == '#')
169 {
170 if (d[1] == 'l' && p - buffer < 6)
171 p = buffer + 6;
172 else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' )
173 p = buffer + 4;
174 }
175 if (d[1] >= '1' && d[1] <= '3' && p - buffer < 4)
176 p = buffer + 4;
177 if (d[1] >= '4' && d[1] <= '6' && p - buffer < 6)
178 p = buffer + 6;
179 if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4)
180 p = buffer + 4;
181 }
182
183 d = m68k_opcodes[best].args;
184
185 if (*d)
186 fputs (" ", stream);
187
188 while (*d)
189 {
190 p = print_insn_arg (d, buffer, p, addr + p - buffer, stream);
191 d += 2;
192 if (*d && *(d - 2) != 'I' && *d != 'k')
193 fputs (",", stream);
194 }
195 return p - buffer;
196 }
197
198 static unsigned char *
199 print_insn_arg (d, buffer, p, addr, stream)
200 char *d;
201 unsigned char *buffer;
202 register unsigned char *p;
203 bfd_vma addr; /* PC for this arg to be relative to */
204 FILE *stream;
205 {
206 register int val;
207 register int place = d[1];
208 int regno;
209 register char *regname;
210 register unsigned char *p1;
211 register double flval;
212 int flt_p;
213
214 switch (*d)
215 {
216 case 'C':
217 fprintf (stream, "ccr");
218 break;
219
220 case 'S':
221 fprintf (stream, "sr");
222 break;
223
224 case 'U':
225 fprintf (stream, "usp");
226 break;
227
228 case 'J':
229 {
230 static struct { char *name; int value; } names[]
231 = {{"sfc", 0x000}, {"dfc", 0x001}, {"cacr", 0x002},
232 {"usp", 0x800}, {"vbr", 0x801}, {"caar", 0x802},
233 {"msp", 0x803}, {"isp", 0x804}};
234
235 val = fetch_arg (buffer, place, 12);
236 for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--)
237 if (names[regno].value == val)
238 {
239 fprintf (stream, names[regno].name);
240 break;
241 }
242 if (regno < 0)
243 fprintf (stream, "%d", val);
244 }
245 break;
246
247 case 'Q':
248 val = fetch_arg (buffer, place, 3);
249 if (val == 0) val = 8;
250 fprintf (stream, "#%d", val);
251 break;
252
253 case 'M':
254 val = fetch_arg (buffer, place, 8);
255 if (val & 0x80)
256 val = val - 0x100;
257 fprintf (stream, "#%d", val);
258 break;
259
260 case 'T':
261 val = fetch_arg (buffer, place, 4);
262 fprintf (stream, "#%d", val);
263 break;
264
265 case 'D':
266 fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3)]);
267 break;
268
269 case 'A':
270 fprintf (stream, "%s",
271 reg_names[fetch_arg (buffer, place, 3) + 010]);
272 break;
273
274 case 'R':
275 fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 4)]);
276 break;
277
278 case 'F':
279 fprintf (stream, "fp%d", fetch_arg (buffer, place, 3));
280 break;
281
282 case 'O':
283 val = fetch_arg (buffer, place, 6);
284 if (val & 0x20)
285 fprintf (stream, "%s", reg_names [val & 7]);
286 else
287 fprintf (stream, "%d", val);
288 break;
289
290 case '+':
291 fprintf (stream, "%s@+",
292 reg_names[fetch_arg (buffer, place, 3) + 8]);
293 break;
294
295 case '-':
296 fprintf (stream, "%s@-",
297 reg_names[fetch_arg (buffer, place, 3) + 8]);
298 break;
299
300 case 'k':
301 if (place == 'k')
302 fprintf (stream, "{%s}", reg_names[fetch_arg (buffer, place, 3)]);
303 else if (place == 'C')
304 {
305 val = fetch_arg (buffer, place, 7);
306 if ( val > 63 ) /* This is a signed constant. */
307 val -= 128;
308 fprintf (stream, "{#%d}", val);
309 }
310 else
311 fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".",
312 *d, place);
313 break;
314
315 case '#':
316 case '^':
317 p1 = buffer + (*d == '#' ? 2 : 4);
318 if (place == 's')
319 val = fetch_arg (buffer, place, 4);
320 else if (place == 'C')
321 val = fetch_arg (buffer, place, 7);
322 else if (place == '8')
323 val = fetch_arg (buffer, place, 3);
324 else if (place == '3')
325 val = fetch_arg (buffer, place, 8);
326 else if (place == 'b')
327 val = NEXTBYTE (p1);
328 else if (place == 'w')
329 val = NEXTWORD (p1);
330 else if (place == 'l')
331 val = NEXTLONG (p1);
332 else
333 fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".",
334 *d, place);
335 fprintf (stream, "#%d", val);
336 break;
337
338 case 'B':
339 if (place == 'b')
340 val = NEXTBYTE (p);
341 else if (place == 'w')
342 val = NEXTWORD (p);
343 else if (place == 'l')
344 val = NEXTLONG (p);
345 else if (place == 'g')
346 {
347 val = ((char *)buffer)[1];
348 if (val == 0)
349 val = NEXTWORD (p);
350 else if (val == -1)
351 val = NEXTLONG (p);
352 }
353 else if (place == 'c')
354 {
355 if (buffer[1] & 0x40) /* If bit six is one, long offset */
356 val = NEXTLONG (p);
357 else
358 val = NEXTWORD (p);
359 }
360 else
361 fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".",
362 *d, place);
363 print_address (addr + val, stream);
364 break;
365
366 case 'd':
367 val = NEXTWORD (p);
368 fprintf (stream, "%s@(%d)",
369 reg_names[fetch_arg (buffer, place, 3)], val);
370 break;
371
372 case 's':
373 fprintf (stream, "%s",
374 fpcr_names[fetch_arg (buffer, place, 3)]);
375 break;
376
377 case 'I':
378 val = fetch_arg (buffer, 'd', 3); /* Get coprocessor ID... */
379 if (val != 1) /* Unusual coprocessor ID? */
380 fprintf (stream, "(cpid=%d) ", val);
381 if (place == 'i')
382 p += 2; /* Skip coprocessor extended operands */
383 break;
384
385 case '*':
386 case '~':
387 case '%':
388 case ';':
389 case '@':
390 case '!':
391 case '$':
392 case '?':
393 case '/':
394 case '&':
395
396 if (place == 'd')
397 {
398 val = fetch_arg (buffer, 'x', 6);
399 val = ((val & 7) << 3) + ((val >> 3) & 7);
400 }
401 else
402 val = fetch_arg (buffer, 's', 6);
403
404 /* Get register number assuming address register. */
405 regno = (val & 7) + 8;
406 regname = reg_names[regno];
407 switch (val >> 3)
408 {
409 case 0:
410 fprintf (stream, "%s", reg_names[val]);
411 break;
412
413 case 1:
414 fprintf (stream, "%s", regname);
415 break;
416
417 case 2:
418 fprintf (stream, "%s@", regname);
419 break;
420
421 case 3:
422 fprintf (stream, "%s@+", regname);
423 break;
424
425 case 4:
426 fprintf (stream, "%s@-", regname);
427 break;
428
429 case 5:
430 val = NEXTWORD (p);
431 fprintf (stream, "%s@(%d)", regname, val);
432 break;
433
434 case 6:
435 p = print_indexed (regno, p, addr, stream);
436 break;
437
438 case 7:
439 switch (val & 7)
440 {
441 case 0:
442 val = NEXTWORD (p);
443 fprintf (stream, "@#");
444 print_address (val, stream);
445 break;
446
447 case 1:
448 val = NEXTLONG (p);
449 fprintf (stream, "@#");
450 print_address (val, stream);
451 break;
452
453 case 2:
454 val = NEXTWORD (p);
455 print_address (addr + val, stream);
456 break;
457
458 case 3:
459 p = print_indexed (-1, p, addr, stream);
460 break;
461
462 case 4:
463 flt_p = 1; /* Assume it's a float... */
464 switch( place )
465 {
466 case 'b':
467 val = NEXTBYTE (p);
468 flt_p = 0;
469 break;
470
471 case 'w':
472 val = NEXTWORD (p);
473 flt_p = 0;
474 break;
475
476 case 'l':
477 val = NEXTLONG (p);
478 flt_p = 0;
479 break;
480
481 case 'f':
482 flval = NEXTSINGLE(p);
483 break;
484
485 case 'F':
486 flval = NEXTDOUBLE(p);
487 break;
488
489 case 'x':
490 flval = NEXTEXTEND(p);
491 break;
492
493 case 'p':
494 flval = NEXTPACKED(p);
495 break;
496
497 default:
498 fprintf(stderr, "Invalid arg format in opcode table: \"%c%c\".",
499 *d, place);
500 }
501 if ( flt_p ) /* Print a float? */
502 fprintf (stream, "#%g", flval);
503 else
504 fprintf (stream, "#%d", val);
505 break;
506
507 default:
508 fprintf (stream, "<invalid address mode 0%o>", (unsigned) val);
509 }
510 }
511 break;
512
513 case 'L':
514 case 'l':
515 if (place == 'w')
516 {
517 char doneany;
518 p1 = buffer + 2;
519 val = NEXTWORD (p1);
520 /* Move the pointer ahead if this point is farther ahead
521 than the last. */
522 p = p1 > p ? p1 : p;
523 if (val == 0)
524 {
525 fputs ("#0", stream);
526 break;
527 }
528 if (*d == 'l')
529 {
530 register int newval = 0;
531 for (regno = 0; regno < 16; ++regno)
532 if (val & (0x8000 >> regno))
533 newval |= 1 << regno;
534 val = newval;
535 }
536 val &= 0xffff;
537 doneany = 0;
538 for (regno = 0; regno < 16; ++regno)
539 if (val & (1 << regno))
540 {
541 int first_regno;
542 if (doneany)
543 fputs ("/", stream);
544 doneany = 1;
545 fprintf (stream, "%s", reg_names[regno]);
546 first_regno = regno;
547 while (val & (1 << (regno + 1)))
548 ++regno;
549 if (regno > first_regno)
550 fprintf (stream, "-%s", reg_names[regno]);
551 }
552 }
553 else if (place == '3')
554 {
555 /* `fmovem' insn. */
556 char doneany;
557 val = fetch_arg (buffer, place, 8);
558 if (val == 0)
559 {
560 fputs ("#0", stream);
561 break;
562 }
563 if (*d == 'l')
564 {
565 register int newval = 0;
566 for (regno = 0; regno < 8; ++regno)
567 if (val & (0x80 >> regno))
568 newval |= 1 << regno;
569 val = newval;
570 }
571 val &= 0xff;
572 doneany = 0;
573 for (regno = 0; regno < 8; ++regno)
574 if (val & (1 << regno))
575 {
576 int first_regno;
577 if (doneany)
578 fputs ("/", stream);
579 doneany = 1;
580 fprintf (stream, "fp%d", regno);
581 first_regno = regno;
582 while (val & (1 << (regno + 1)))
583 ++regno;
584 if (regno > first_regno)
585 fprintf (stream, "-fp%d", regno);
586 }
587 }
588 else
589 abort ();
590 break;
591
592 default:
593 fprintf(stderr, "Invalid arg format in opcode table: \"%c\".", *d);
594 }
595
596 return (unsigned char *) p;
597 }
598
599 /* Fetch BITS bits from a position in the instruction specified by CODE.
600 CODE is a "place to put an argument", or 'x' for a destination
601 that is a general address (mode and register).
602 BUFFER contains the instruction. */
603
604 static int
605 fetch_arg (buffer, code, bits)
606 unsigned char *buffer;
607 char code;
608 int bits;
609 {
610 register int val;
611 switch (code)
612 {
613 case 's':
614 val = buffer[1];
615 break;
616
617 case 'd': /* Destination, for register or quick. */
618 val = (buffer[0] << 8) + buffer[1];
619 val >>= 9;
620 break;
621
622 case 'x': /* Destination, for general arg */
623 val = (buffer[0] << 8) + buffer[1];
624 val >>= 6;
625 break;
626
627 case 'k':
628 val = (buffer[3] >> 4);
629 break;
630
631 case 'C':
632 val = buffer[3];
633 break;
634
635 case '1':
636 val = (buffer[2] << 8) + buffer[3];
637 val >>= 12;
638 break;
639
640 case '2':
641 val = (buffer[2] << 8) + buffer[3];
642 val >>= 6;
643 break;
644
645 case '3':
646 case 'j':
647 val = (buffer[2] << 8) + buffer[3];
648 break;
649
650 case '4':
651 val = (buffer[4] << 8) + buffer[5];
652 val >>= 12;
653 break;
654
655 case '5':
656 val = (buffer[4] << 8) + buffer[5];
657 val >>= 6;
658 break;
659
660 case '6':
661 val = (buffer[4] << 8) + buffer[5];
662 break;
663
664 case '7':
665 val = (buffer[2] << 8) + buffer[3];
666 val >>= 7;
667 break;
668
669 case '8':
670 val = (buffer[2] << 8) + buffer[3];
671 val >>= 10;
672 break;
673
674 default:
675 abort ();
676 }
677
678 switch (bits)
679 {
680 case 3:
681 return val & 7;
682 case 4:
683 return val & 017;
684 case 5:
685 return val & 037;
686 case 6:
687 return val & 077;
688 case 7:
689 return val & 0177;
690 case 8:
691 return val & 0377;
692 case 12:
693 return val & 07777;
694 default:
695 abort ();
696 return(0);
697 }
698 } /* fetch_arg() */
699
700 /* Print an indexed argument. The base register is BASEREG (-1 for pc).
701 P points to extension word, in buffer.
702 ADDR is the nominal core address of that extension word. */
703
704 static unsigned char *
705 print_indexed (basereg, p, addr, stream)
706 int basereg;
707 unsigned char *p;
708 FILE *stream;
709 bfd_vma addr;
710 {
711 register int word;
712 static char *scales[] = {"", "*2", "*4", "*8"};
713 register int base_disp;
714 register int outer_disp;
715 char buf[40];
716
717 word = NEXTWORD (p);
718
719 /* Generate the text for the index register.
720 Where this will be output is not yet determined. */
721 sprintf (buf, "[%s.%c%s]",
722 reg_names[(word >> 12) & 0xf],
723 (word & 0x800) ? 'l' : 'w',
724 scales[(word >> 9) & 3]);
725
726 /* Handle the 68000 style of indexing. */
727
728 if ((word & 0x100) == 0)
729 {
730 print_base (basereg,
731 ((word & 0x80) ? word | 0xff00 : word & 0xff)
732 + ((basereg == -1) ? addr : 0),
733 stream);
734 fputs (buf, stream);
735 return p;
736 }
737
738 /* Handle the generalized kind. */
739 /* First, compute the displacement to add to the base register. */
740
741 if (word & 0200)
742 basereg = -2;
743 if (word & 0100)
744 buf[0] = 0;
745 base_disp = 0;
746 switch ((word >> 4) & 3)
747 {
748 case 2:
749 base_disp = NEXTWORD (p);
750 break;
751 case 3:
752 base_disp = NEXTLONG (p);
753 }
754 if (basereg == -1)
755 base_disp += addr;
756
757 /* Handle single-level case (not indirect) */
758
759 if ((word & 7) == 0)
760 {
761 print_base (basereg, base_disp, stream);
762 fputs (buf, stream);
763 return p;
764 }
765
766 /* Two level. Compute displacement to add after indirection. */
767
768 outer_disp = 0;
769 switch (word & 3)
770 {
771 case 2:
772 outer_disp = NEXTWORD (p);
773 break;
774 case 3:
775 outer_disp = NEXTLONG (p);
776 }
777
778 fprintf (stream, "%d(", outer_disp);
779 print_base (basereg, base_disp, stream);
780
781 /* If postindexed, print the closeparen before the index. */
782 if (word & 4)
783 fprintf (stream, ")%s", buf);
784 /* If preindexed, print the closeparen after the index. */
785 else
786 fprintf (stream, "%s)", buf);
787
788 return p;
789 }
790
791 /* Print a base register REGNO and displacement DISP, on STREAM.
792 REGNO = -1 for pc, -2 for none (suppressed). */
793
794 static void
795 print_base (regno, disp, stream)
796 int regno;
797 int disp;
798 FILE *stream;
799 {
800 if (regno == -2)
801 fprintf (stream, "%d", disp);
802 else if (regno == -1)
803 fprintf (stream, "0x%x", (unsigned) disp);
804 else
805 fprintf (stream, "%d(%s)", disp, reg_names[regno]);
806 }
This page took 0.046405 seconds and 4 git commands to generate.