1 /* Print m68k instructions for GDB, the GNU debugger.
2 Copyright (C) 1986, 1987 Free Software Foundation, Inc.
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.
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.
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!
26 #include "m68k-opcode.h"
28 /* 68k instructions are never longer than this many bytes. */
31 /* Number of elements in the opcode table. */
32 #define NOPCODES (sizeof m68k_opcodes / sizeof m68k_opcodes[0])
34 extern char *reg_names[];
35 char *fpcr_names[] = { "", "fpiar", "fpsr", "fpiar/fpsr", "fpcr",
36 "fpiar/fpcr", "fpsr/fpcr", "fpiar-fpcr"};
38 static unsigned char *print_insn_arg ();
39 static unsigned char *print_indexed ();
40 static void print_base ();
41 static int fetch_arg ();
43 #define NEXTBYTE(p) (p += 2, ((char *)p)[-1])
46 (p += 2, ((((char *)p)[-2]) << 8) + p[-1])
49 (p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])
51 #define NEXTSINGLE(p) \
52 (p += 4, *((float *)(p - 4)))
54 #define NEXTDOUBLE(p) \
55 (p += 8, *((double *)(p - 8)))
57 #define NEXTEXTEND(p) \
58 (p += 12, 0.0) /* Need a function to convert from extended to double
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... */
67 /* Print the m68k instruction at address MEMADDR in debugged memory,
68 on STREAM. Returns length of the instruction, in bytes. */
71 print_insn (memaddr, stream)
75 unsigned char buffer[MAXLEN];
77 register unsigned char *p;
79 register int bestmask;
82 read_memory (memaddr, buffer, MAXLEN);
86 for (i = 0; i < NOPCODES; i++)
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)))
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)
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. */
106 for (d = m68k_opcodes[i].args; *d; d += 2)
110 if (*d == 0 && match > bestmask)
118 /* Handle undefined instructions. */
121 fprintf (stream, "0%o", (buffer[0] << 8) + buffer[1]);
125 fprintf (stream, "%s", m68k_opcodes[best].name);
127 /* Point at first word of argument data,
128 and at descriptor for first argument. */
131 /* Why do this this way? -MelloN */
132 for (d = m68k_opcodes[best].args; *d; d += 2)
136 if (d[1] == 'l' && p - buffer < 6)
138 else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' )
141 if (d[1] >= '1' && d[1] <= '3' && p - buffer < 4)
143 if (d[1] >= '4' && d[1] <= '6' && p - buffer < 6)
147 d = m68k_opcodes[best].args;
154 p = print_insn_arg (d, buffer, p, memaddr + p - buffer, stream);
156 if (*d && *(d - 2) != 'I' && *d != 'k')
157 fprintf (stream, ",");
162 static unsigned char *
163 print_insn_arg (d, buffer, p, addr, stream)
165 unsigned char *buffer;
166 register unsigned char *p;
167 CORE_ADDR addr; /* PC for this arg to be relative to */
171 register int place = d[1];
173 register char *regname;
174 register unsigned char *p1;
175 register double flval;
181 fprintf (stream, "ccr");
185 fprintf (stream, "sr");
189 fprintf (stream, "usp");
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}};
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)
203 fprintf (stream, names[regno].name);
207 fprintf (stream, "%d", val);
212 val = fetch_arg (buffer, place, 3);
213 if (val == 0) val = 8;
214 fprintf (stream, "#%d", val);
218 val = fetch_arg (buffer, place, 8);
221 fprintf (stream, "#%d", val);
225 val = fetch_arg (buffer, place, 4);
226 fprintf (stream, "#%d", val);
230 fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3)]);
234 fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 3) + 010]);
238 fprintf (stream, "%s", reg_names[fetch_arg (buffer, place, 4)]);
242 fprintf (stream, "fp%d", fetch_arg (buffer, place, 3));
246 val = fetch_arg (buffer, place, 6);
248 fprintf (stream, "%s", reg_names [val & 7]);
250 fprintf (stream, "%d", val);
254 fprintf (stream, "(%s)+", reg_names[fetch_arg (buffer, place, 3) + 8]);
258 fprintf (stream, "-(%s)", reg_names[fetch_arg (buffer, place, 3) + 8]);
263 fprintf (stream, "{%s}", reg_names[fetch_arg (buffer, place, 3)]);
264 else if (place == 'C')
266 val = fetch_arg (buffer, place, 7);
267 if ( val > 63 ) /* This is a signed constant. */
269 fprintf (stream, "{#%d}", val);
272 error ("Invalid arg format in opcode table: \"%c%c\".",
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')
288 else if (place == 'w')
290 else if (place == 'l')
293 error ("Invalid arg format in opcode table: \"%c%c\".",
295 fprintf (stream, "#%d", val);
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')
307 else if (place == 'w')
309 else if (place == 'l')
312 error ("Invalid arg format in opcode table: \"%c%c\".",
314 fprintf (stream, "#%d", val);
320 else if (place == 'w')
322 else if (place == 'l')
324 else if (place == 'g')
326 val = ((char *)buffer)[1];
332 else if (place == 'c')
334 if (buffer[1] & 0x40) /* If bit six is one, long offset */
340 error ("Invalid arg format in opcode table: \"%c%c\".",
343 print_address (addr + val, stream);
348 fprintf (stream, "%d(%s)", val, fetch_arg (buffer, place, 3));
352 fprintf (stream, "%s", fpcr_names[fetch_arg (buffer, place, 3)]);
356 val = fetch_arg (buffer, 'd', 3); /* Get coprocessor ID... */
357 if (val != 1) /* Unusual coprocessor ID? */
358 fprintf (stream, "(cpid=%d) ", val);
360 p += 2; /* Skip coprocessor extended operands */
376 val = fetch_arg (buffer, 'x', 6);
377 val = ((val & 7) << 3) + ((val >> 3) & 7);
380 val = fetch_arg (buffer, 's', 6);
382 /* Get register number assuming address register. */
383 regno = (val & 7) + 8;
384 regname = reg_names[regno];
388 fprintf (stream, "%s", reg_names[val]);
392 fprintf (stream, "%s", regname);
396 fprintf (stream, "(%s)", regname);
400 fprintf (stream, "(%s)+", regname);
404 fprintf (stream, "-(%s)", regname);
409 fprintf (stream, "%d(%s)", val, regname);
413 p = print_indexed (regno, p, addr, stream);
421 fprintf (stream, "@#");
422 print_address (val, stream);
427 fprintf (stream, "@#");
428 print_address (val, stream);
433 print_address (addr + val, stream);
437 p = print_indexed (-1, p, addr, stream);
441 flt_p = 1; /* Assume it's a float... */
460 flval = NEXTSINGLE(p);
464 flval = NEXTDOUBLE(p);
468 flval = NEXTEXTEND(p);
472 flval = NEXTPACKED(p);
476 error ("Invalid arg format in opcode table: \"%c%c\".",
479 if ( flt_p ) /* Print a float? */
480 fprintf (stream, "#%g", flval);
482 fprintf (stream, "#%d", val);
486 fprintf (stream, "<invalid address mode 0%o>", val);
492 error ("Invalid arg format in opcode table: \"%c\".", *d);
495 return (unsigned char *) p;
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. */
504 fetch_arg (buffer, code, bits)
505 unsigned char *buffer;
516 case 'd': /* Destination, for register or quick. */
517 val = (buffer[0] << 8) + buffer[1];
521 case 'x': /* Destination, for general arg */
522 val = (buffer[0] << 8) + buffer[1];
527 val = (buffer[3] >> 4);
535 val = (buffer[2] << 8) + buffer[3];
540 val = (buffer[2] << 8) + buffer[3];
546 val = (buffer[2] << 8) + buffer[3];
550 val = (buffer[4] << 8) + buffer[5];
555 val = (buffer[4] << 8) + buffer[5];
560 val = (buffer[4] << 8) + buffer[5];
564 val = (buffer[2] << 8) + buffer[3];
569 val = (buffer[2] << 8) + buffer[3];
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. */
602 static unsigned char *
603 print_indexed (basereg, p, addr, stream)
610 static char *scales[] = {"", "*2", "*4", "*8"};
611 register int base_disp;
612 register int outer_disp;
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]);
624 /* Handle the 68000 style of indexing. */
626 if ((word & 0x100) == 0)
629 ((word & 0x80) ? word | 0xff00 : word & 0xff)
630 + ((basereg == -1) ? addr : 0),
632 fprintf (stream, "%s", buf);
636 /* Handle the generalized kind. */
637 /* First, compute the displacement to add to the base register. */
644 switch ((word >> 4) & 3)
647 base_disp = NEXTWORD (p);
650 base_disp = NEXTLONG (p);
655 /* Handle single-level case (not indirect) */
659 print_base (basereg, base_disp, stream);
660 fprintf (stream, "%s", buf);
664 /* Two level. Compute displacement to add after indirection. */
670 outer_disp = NEXTWORD (p);
673 outer_disp = NEXTLONG (p);
676 fprintf (stream, "%d(", outer_disp);
677 print_base (basereg, base_disp, stream);
679 /* If postindexed, print the closeparen before the index. */
681 fprintf (stream, ")%s", buf);
682 /* If preindexed, print the closeparen after the index. */
684 fprintf (stream, "%s)", buf);
689 /* Print a base register REGNO and displacement DISP, on STREAM.
690 REGNO = -1 for pc, -2 for none (suppressed). */
693 print_base (regno, disp, stream)
699 fprintf (stream, "%d", disp);
700 else if (regno == -1)
701 fprintf (stream, "0x%x", disp);
703 fprintf (stream, "%d(%s)", disp, reg_names[regno]);
706 /* This is not part of insn printing, but it is machine-specific,
707 so this is a convenient place to put it.
709 Convert a 68881 extended float to a double.
710 FROM is the address of the extended float.
711 Store the double in *TO. */
715 #define asm16(str) asm ("short " str#)
717 #define asm16(str) asm ("short str")
721 #define asm16(str) asm (".word " str#)
723 #define asm16(str) asm (".word str")
727 convert_from_68881 (from, to)
732 asm ("movl a6@(8),a0");
733 asm ("movl a6@(12),a1");
734 asm ("fmovex a0@,fp0");
735 asm ("fmoved fp0,a1@");
737 /* Hand-assemble those insns since some assemblers lose
738 and some have different syntax. */
750 /* The converse: convert the double *FROM to an extended float
751 and store where TO points. */
753 convert_to_68881 (from, to)
758 asm ("movl a6@(8),a0");
759 asm ("movl a6@(12),a1");
760 asm ("fmoved a0@,fp0");
761 asm ("fmovex fp0,a1@");
763 /* Hand-assemble those insns since some assemblers lose. */