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