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