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