12159047fSniklas /* Print Motorola 68k instructions.
2b55d4692Sfgsch Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
3*007c2a45Smiod 1998, 1999, 2000, 2001, 2002, 2003
4fddef416Sniklas Free Software Foundation, Inc.
52159047fSniklas
62159047fSniklas This file is free software; you can redistribute it and/or modify
72159047fSniklas it under the terms of the GNU General Public License as published by
82159047fSniklas the Free Software Foundation; either version 2 of the License, or
92159047fSniklas (at your option) any later version.
102159047fSniklas
112159047fSniklas This program is distributed in the hope that it will be useful,
122159047fSniklas but WITHOUT ANY WARRANTY; without even the implied warranty of
132159047fSniklas MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
142159047fSniklas GNU General Public License for more details.
152159047fSniklas
162159047fSniklas You should have received a copy of the GNU General Public License
172159047fSniklas along with this program; if not, write to the Free Software
182159047fSniklas Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
192159047fSniklas
20f7cc78ecSespie #include "sysdep.h"
212159047fSniklas #include "dis-asm.h"
222159047fSniklas #include "floatformat.h"
23c074d1c9Sdrahn #include "libiberty.h"
24f7cc78ecSespie #include "opintl.h"
252159047fSniklas
262159047fSniklas #include "opcode/m68k.h"
272159047fSniklas
282159047fSniklas /* Local function prototypes */
292159047fSniklas
302159047fSniklas static int
31fddef416Sniklas fetch_data PARAMS ((struct disassemble_info *, bfd_byte *));
32fddef416Sniklas
33fddef416Sniklas static void
34fddef416Sniklas dummy_print_address PARAMS ((bfd_vma, struct disassemble_info *));
35fddef416Sniklas
36fddef416Sniklas static int
372159047fSniklas fetch_arg PARAMS ((unsigned char *, int, int, disassemble_info *));
382159047fSniklas
392159047fSniklas static void
402159047fSniklas print_base PARAMS ((int, bfd_vma, disassemble_info *));
412159047fSniklas
422159047fSniklas static unsigned char *
432159047fSniklas print_indexed PARAMS ((int, unsigned char *, bfd_vma, disassemble_info *));
442159047fSniklas
452159047fSniklas static int
462159047fSniklas print_insn_arg PARAMS ((const char *, unsigned char *, unsigned char *,
472159047fSniklas bfd_vma, disassemble_info *));
482159047fSniklas
49c074d1c9Sdrahn const char * const fpcr_names[] = {
502159047fSniklas "", "%fpiar", "%fpsr", "%fpiar/%fpsr", "%fpcr",
51b55d4692Sfgsch "%fpiar/%fpcr", "%fpsr/%fpcr", "%fpiar/%fpsr/%fpcr"
52b55d4692Sfgsch };
532159047fSniklas
54c074d1c9Sdrahn static char *const reg_names[] = {
552159047fSniklas "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
562159047fSniklas "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp",
57b55d4692Sfgsch "%ps", "%pc"
58b55d4692Sfgsch };
592159047fSniklas
602159047fSniklas /* Sign-extend an (unsigned char). */
612159047fSniklas #if __STDC__ == 1
622159047fSniklas #define COERCE_SIGNED_CHAR(ch) ((signed char) (ch))
632159047fSniklas #else
642159047fSniklas #define COERCE_SIGNED_CHAR(ch) ((int) (((ch) ^ 0x80) & 0xFF) - 128)
652159047fSniklas #endif
662159047fSniklas
672159047fSniklas /* Get a 1 byte signed integer. */
682159047fSniklas #define NEXTBYTE(p) (p += 2, FETCH_DATA (info, p), COERCE_SIGNED_CHAR(p[-1]))
692159047fSniklas
702159047fSniklas /* Get a 2 byte signed integer. */
712159047fSniklas #define COERCE16(x) ((int) (((x) ^ 0x8000) - 0x8000))
722159047fSniklas #define NEXTWORD(p) \
732159047fSniklas (p += 2, FETCH_DATA (info, p), \
742159047fSniklas COERCE16 ((p[-2] << 8) + p[-1]))
752159047fSniklas
762159047fSniklas /* Get a 4 byte signed integer. */
77f7cc78ecSespie #define COERCE32(x) ((bfd_signed_vma) ((x) ^ 0x80000000) - 0x80000000)
782159047fSniklas #define NEXTLONG(p) \
792159047fSniklas (p += 4, FETCH_DATA (info, p), \
802159047fSniklas (COERCE32 ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])))
812159047fSniklas
82f7cc78ecSespie /* Get a 4 byte unsigned integer. */
83f7cc78ecSespie #define NEXTULONG(p) \
84f7cc78ecSespie (p += 4, FETCH_DATA (info, p), \
85f7cc78ecSespie (unsigned int) ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]))
86f7cc78ecSespie
87fddef416Sniklas /* Get a single precision float. */
882159047fSniklas #define NEXTSINGLE(val, p) \
89fddef416Sniklas (p += 4, FETCH_DATA (info, p), \
90fddef416Sniklas floatformat_to_double (&floatformat_ieee_single_big, (char *) p - 4, &val))
912159047fSniklas
92fddef416Sniklas /* Get a double precision float. */
932159047fSniklas #define NEXTDOUBLE(val, p) \
94fddef416Sniklas (p += 8, FETCH_DATA (info, p), \
95fddef416Sniklas floatformat_to_double (&floatformat_ieee_double_big, (char *) p - 8, &val))
962159047fSniklas
97fddef416Sniklas /* Get an extended precision float. */
98fddef416Sniklas #define NEXTEXTEND(val, p) \
99fddef416Sniklas (p += 12, FETCH_DATA (info, p), \
100fddef416Sniklas floatformat_to_double (&floatformat_m68881_ext, (char *) p - 12, &val))
1012159047fSniklas
1022159047fSniklas /* Need a function to convert from packed to double
1032159047fSniklas precision. Actually, it's easier to print a
1042159047fSniklas packed number than a double anyway, so maybe
1052159047fSniklas there should be a special case to handle this... */
1062159047fSniklas #define NEXTPACKED(p) \
1072159047fSniklas (p += 12, FETCH_DATA (info, p), 0.0)
1082159047fSniklas
1092159047fSniklas /* Maximum length of an instruction. */
1102159047fSniklas #define MAXLEN 22
1112159047fSniklas
1122159047fSniklas #include <setjmp.h>
1132159047fSniklas
114c074d1c9Sdrahn struct private {
1152159047fSniklas /* Points to first byte not fetched. */
1162159047fSniklas bfd_byte *max_fetched;
1172159047fSniklas bfd_byte the_buffer[MAXLEN];
1182159047fSniklas bfd_vma insn_start;
1192159047fSniklas jmp_buf bailout;
1202159047fSniklas };
1212159047fSniklas
1222159047fSniklas /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
1232159047fSniklas to ADDR (exclusive) are valid. Returns 1 for success, longjmps
1242159047fSniklas on error. */
1252159047fSniklas #define FETCH_DATA(info, addr) \
1262159047fSniklas ((addr) <= ((struct private *) (info->private_data))->max_fetched \
1272159047fSniklas ? 1 : fetch_data ((info), (addr)))
1282159047fSniklas
1292159047fSniklas static int
fetch_data(info,addr)1302159047fSniklas fetch_data (info, addr)
1312159047fSniklas struct disassemble_info *info;
1322159047fSniklas bfd_byte *addr;
1332159047fSniklas {
1342159047fSniklas int status;
1352159047fSniklas struct private *priv = (struct private *)info->private_data;
1362159047fSniklas bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
1372159047fSniklas
1382159047fSniklas status = (*info->read_memory_func) (start,
1392159047fSniklas priv->max_fetched,
1402159047fSniklas addr - priv->max_fetched,
1412159047fSniklas info);
1422159047fSniklas if (status != 0)
1432159047fSniklas {
1442159047fSniklas (*info->memory_error_func) (status, start, info);
1452159047fSniklas longjmp (priv->bailout, 1);
1462159047fSniklas }
1472159047fSniklas else
1482159047fSniklas priv->max_fetched = addr;
1492159047fSniklas return 1;
1502159047fSniklas }
1512159047fSniklas
1522159047fSniklas /* This function is used to print to the bit-bucket. */
1532159047fSniklas static int
1542159047fSniklas #ifdef __STDC__
dummy_printer(FILE * file ATTRIBUTE_UNUSED,const char * format ATTRIBUTE_UNUSED,...)155b55d4692Sfgsch dummy_printer (FILE *file ATTRIBUTE_UNUSED,
156b55d4692Sfgsch const char *format ATTRIBUTE_UNUSED, ...)
1572159047fSniklas #else
158c074d1c9Sdrahn dummy_printer (file)
159c074d1c9Sdrahn FILE *file ATTRIBUTE_UNUSED;
1602159047fSniklas #endif
161c074d1c9Sdrahn {
162c074d1c9Sdrahn return 0;
163c074d1c9Sdrahn }
1642159047fSniklas
165fddef416Sniklas static void
dummy_print_address(vma,info)1662159047fSniklas dummy_print_address (vma, info)
167b55d4692Sfgsch bfd_vma vma ATTRIBUTE_UNUSED;
168b55d4692Sfgsch struct disassemble_info *info ATTRIBUTE_UNUSED;
1692159047fSniklas {
1702159047fSniklas }
1712159047fSniklas
1722159047fSniklas /* Print the m68k instruction at address MEMADDR in debugged memory,
1732159047fSniklas on INFO->STREAM. Returns length of the instruction, in bytes. */
1742159047fSniklas
1752159047fSniklas int
print_insn_m68k(memaddr,info)1762159047fSniklas print_insn_m68k (memaddr, info)
1772159047fSniklas bfd_vma memaddr;
1782159047fSniklas disassemble_info *info;
1792159047fSniklas {
1802159047fSniklas register int i;
1812159047fSniklas register unsigned char *p;
1822159047fSniklas unsigned char *save_p;
1832159047fSniklas register const char *d;
1842159047fSniklas register unsigned long bestmask;
185b55d4692Sfgsch const struct m68k_opcode *best;
186f7cc78ecSespie unsigned int arch_mask;
1872159047fSniklas struct private priv;
1882159047fSniklas bfd_byte *buffer = priv.the_buffer;
1892159047fSniklas fprintf_ftype save_printer = info->fprintf_func;
1902159047fSniklas void (*save_print_address) PARAMS ((bfd_vma, struct disassemble_info *))
1912159047fSniklas = info->print_address_func;
192fddef416Sniklas int major_opcode;
193fddef416Sniklas static int numopcodes[16];
194fddef416Sniklas static const struct m68k_opcode **opcodes[16];
195fddef416Sniklas
196fddef416Sniklas if (!opcodes[0])
197fddef416Sniklas {
198fddef416Sniklas /* Speed up the matching by sorting the opcode table on the upper
199fddef416Sniklas four bits of the opcode. */
200fddef416Sniklas const struct m68k_opcode **opc_pointer[16];
201fddef416Sniklas
202fddef416Sniklas /* First count how many opcodes are in each of the sixteen buckets. */
203fddef416Sniklas for (i = 0; i < m68k_numopcodes; i++)
204fddef416Sniklas numopcodes[(m68k_opcodes[i].opcode >> 28) & 15]++;
205fddef416Sniklas
206fddef416Sniklas /* Then create a sorted table of pointers that point into the
207fddef416Sniklas unsorted table. */
208fddef416Sniklas opc_pointer[0] = ((const struct m68k_opcode **)
209fddef416Sniklas xmalloc (sizeof (struct m68k_opcode *)
210fddef416Sniklas * m68k_numopcodes));
211fddef416Sniklas opcodes[0] = opc_pointer[0];
212fddef416Sniklas for (i = 1; i < 16; i++)
213fddef416Sniklas {
214fddef416Sniklas opc_pointer[i] = opc_pointer[i - 1] + numopcodes[i - 1];
215fddef416Sniklas opcodes[i] = opc_pointer[i];
216fddef416Sniklas }
217fddef416Sniklas
218fddef416Sniklas for (i = 0; i < m68k_numopcodes; i++)
219fddef416Sniklas *opc_pointer[(m68k_opcodes[i].opcode >> 28) & 15]++ = &m68k_opcodes[i];
220fddef416Sniklas
221fddef416Sniklas }
2222159047fSniklas
2232159047fSniklas info->private_data = (PTR) &priv;
224fddef416Sniklas /* Tell objdump to use two bytes per chunk and six bytes per line for
225fddef416Sniklas displaying raw data. */
226fddef416Sniklas info->bytes_per_chunk = 2;
227fddef416Sniklas info->bytes_per_line = 6;
228fddef416Sniklas info->display_endian = BFD_ENDIAN_BIG;
2292159047fSniklas priv.max_fetched = priv.the_buffer;
2302159047fSniklas priv.insn_start = memaddr;
2312159047fSniklas if (setjmp (priv.bailout) != 0)
2322159047fSniklas /* Error return. */
2332159047fSniklas return -1;
2342159047fSniklas
235b55d4692Sfgsch best = NULL;
236f7cc78ecSespie switch (info->mach)
237f7cc78ecSespie {
238f7cc78ecSespie default:
239f7cc78ecSespie case 0:
240f7cc78ecSespie arch_mask = (unsigned int) -1;
241f7cc78ecSespie break;
242f7cc78ecSespie case bfd_mach_m68000:
243f7cc78ecSespie arch_mask = m68000;
244f7cc78ecSespie break;
245f7cc78ecSespie case bfd_mach_m68008:
246f7cc78ecSespie arch_mask = m68008;
247f7cc78ecSespie break;
248f7cc78ecSespie case bfd_mach_m68010:
249f7cc78ecSespie arch_mask = m68010;
250f7cc78ecSespie break;
251f7cc78ecSespie case bfd_mach_m68020:
252f7cc78ecSespie arch_mask = m68020;
253f7cc78ecSespie break;
254f7cc78ecSespie case bfd_mach_m68030:
255f7cc78ecSespie arch_mask = m68030;
256f7cc78ecSespie break;
257f7cc78ecSespie case bfd_mach_m68040:
258f7cc78ecSespie arch_mask = m68040;
259f7cc78ecSespie break;
260f7cc78ecSespie case bfd_mach_m68060:
261f7cc78ecSespie arch_mask = m68060;
262f7cc78ecSespie break;
263b55d4692Sfgsch case bfd_mach_mcf5200:
264b55d4692Sfgsch arch_mask = mcf5200;
265b55d4692Sfgsch break;
266*007c2a45Smiod case bfd_mach_mcf528x:
267*007c2a45Smiod arch_mask = mcf528x;
268*007c2a45Smiod break;
269b55d4692Sfgsch case bfd_mach_mcf5206e:
270b55d4692Sfgsch arch_mask = mcf5206e;
271b55d4692Sfgsch break;
272b55d4692Sfgsch case bfd_mach_mcf5307:
273b55d4692Sfgsch arch_mask = mcf5307;
274b55d4692Sfgsch break;
275b55d4692Sfgsch case bfd_mach_mcf5407:
276b55d4692Sfgsch arch_mask = mcf5407;
277b55d4692Sfgsch break;
278f7cc78ecSespie }
279f7cc78ecSespie
280f7cc78ecSespie arch_mask |= m68881 | m68851;
281f7cc78ecSespie
2822159047fSniklas bestmask = 0;
2832159047fSniklas FETCH_DATA (info, buffer + 2);
284fddef416Sniklas major_opcode = (buffer[0] >> 4) & 15;
285fddef416Sniklas for (i = 0; i < numopcodes[major_opcode]; i++)
2862159047fSniklas {
287fddef416Sniklas const struct m68k_opcode *opc = opcodes[major_opcode][i];
2882159047fSniklas unsigned long opcode = opc->opcode;
2892159047fSniklas unsigned long match = opc->match;
2902159047fSniklas
2912159047fSniklas if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))
2922159047fSniklas && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))
2932159047fSniklas /* Only fetch the next two bytes if we need to. */
2942159047fSniklas && (((0xffff & match) == 0)
2952159047fSniklas ||
2962159047fSniklas (FETCH_DATA (info, buffer + 4)
2972159047fSniklas && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))
2982159047fSniklas && ((0xff & buffer[3] & match) == (0xff & opcode)))
299f7cc78ecSespie )
300f7cc78ecSespie && (opc->arch & arch_mask) != 0)
3012159047fSniklas {
3022159047fSniklas /* Don't use for printout the variants of divul and divsl
3032159047fSniklas that have the same register number in two places.
3042159047fSniklas The more general variants will match instead. */
3052159047fSniklas for (d = opc->args; *d; d += 2)
3062159047fSniklas if (d[1] == 'D')
3072159047fSniklas break;
3082159047fSniklas
3092159047fSniklas /* Don't use for printout the variants of most floating
3102159047fSniklas point coprocessor instructions which use the same
3112159047fSniklas register number in two places, as above. */
3122159047fSniklas if (*d == '\0')
3132159047fSniklas for (d = opc->args; *d; d += 2)
3142159047fSniklas if (d[1] == 't')
3152159047fSniklas break;
3162159047fSniklas
3172159047fSniklas /* Don't match fmovel with more than one register; wait for
3182159047fSniklas fmoveml. */
3192159047fSniklas if (*d == '\0')
3202159047fSniklas {
3212159047fSniklas for (d = opc->args; *d; d += 2)
3222159047fSniklas {
3232159047fSniklas if (d[0] == 's' && d[1] == '8')
3242159047fSniklas {
3252159047fSniklas int val;
3262159047fSniklas
3272159047fSniklas val = fetch_arg (buffer, d[1], 3, info);
3282159047fSniklas if ((val & (val - 1)) != 0)
3292159047fSniklas break;
3302159047fSniklas }
3312159047fSniklas }
3322159047fSniklas }
3332159047fSniklas
3342159047fSniklas if (*d == '\0' && match > bestmask)
3352159047fSniklas {
3362159047fSniklas best = opc;
3372159047fSniklas bestmask = match;
3382159047fSniklas }
3392159047fSniklas }
3402159047fSniklas }
3412159047fSniklas
342b55d4692Sfgsch if (best == NULL)
3432159047fSniklas goto invalid;
3442159047fSniklas
3452159047fSniklas /* Point at first word of argument data,
3462159047fSniklas and at descriptor for first argument. */
3472159047fSniklas p = buffer + 2;
3482159047fSniklas
3492159047fSniklas /* Figure out how long the fixed-size portion of the instruction is.
3502159047fSniklas The only place this is stored in the opcode table is
3512159047fSniklas in the arguments--look for arguments which specify fields in the 2nd
3522159047fSniklas or 3rd words of the instruction. */
3532159047fSniklas for (d = best->args; *d; d += 2)
3542159047fSniklas {
3552159047fSniklas /* I don't think it is necessary to be checking d[0] here; I suspect
3562159047fSniklas all this could be moved to the case statement below. */
3572159047fSniklas if (d[0] == '#')
3582159047fSniklas {
3592159047fSniklas if (d[1] == 'l' && p - buffer < 6)
3602159047fSniklas p = buffer + 6;
3612159047fSniklas else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8')
3622159047fSniklas p = buffer + 4;
3632159047fSniklas }
3642159047fSniklas if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4)
3652159047fSniklas p = buffer + 4;
3662159047fSniklas switch (d[1])
3672159047fSniklas {
3682159047fSniklas case '1':
3692159047fSniklas case '2':
3702159047fSniklas case '3':
3712159047fSniklas case '7':
3722159047fSniklas case '8':
3732159047fSniklas case '9':
3742159047fSniklas case 'i':
3752159047fSniklas if (p - buffer < 4)
3762159047fSniklas p = buffer + 4;
3772159047fSniklas break;
3782159047fSniklas case '4':
3792159047fSniklas case '5':
3802159047fSniklas case '6':
3812159047fSniklas if (p - buffer < 6)
3822159047fSniklas p = buffer + 6;
3832159047fSniklas break;
3842159047fSniklas default:
3852159047fSniklas break;
3862159047fSniklas }
3872159047fSniklas }
388f7cc78ecSespie
389f7cc78ecSespie /* pflusha is an exceptions. It takes no arguments but is two words
390f7cc78ecSespie long. Recognize it by looking at the lower 16 bits of the mask. */
3912159047fSniklas if (p - buffer < 4 && (best->match & 0xFFFF) != 0)
3922159047fSniklas p = buffer + 4;
3932159047fSniklas
394f7cc78ecSespie /* lpstop is another exception. It takes a one word argument but is
395f7cc78ecSespie three words long. */
396f7cc78ecSespie if (p - buffer < 6
397f7cc78ecSespie && (best->match & 0xffff) == 0xffff
398f7cc78ecSespie && best->args[0] == '#'
399f7cc78ecSespie && best->args[1] == 'w')
400f7cc78ecSespie {
401f7cc78ecSespie /* Copy the one word argument into the usual location for a one
402f7cc78ecSespie word argument, to simplify printing it. We can get away with
403f7cc78ecSespie this because we know exactly what the second word is, and we
404f7cc78ecSespie aren't going to print anything based on it. */
405f7cc78ecSespie p = buffer + 6;
406f7cc78ecSespie FETCH_DATA (info, p);
407f7cc78ecSespie buffer[2] = buffer[4];
408f7cc78ecSespie buffer[3] = buffer[5];
409f7cc78ecSespie }
410f7cc78ecSespie
4112159047fSniklas FETCH_DATA (info, p);
4122159047fSniklas
4132159047fSniklas d = best->args;
4142159047fSniklas
415*007c2a45Smiod /* We scan the operands twice. The first time we don't print anything,
4162159047fSniklas but look for errors. */
4172159047fSniklas
4182159047fSniklas save_p = p;
4192159047fSniklas info->print_address_func = dummy_print_address;
4202159047fSniklas info->fprintf_func = (fprintf_ftype) dummy_printer;
4212159047fSniklas for (; *d; d += 2)
4222159047fSniklas {
423f7cc78ecSespie int eaten = print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
4242159047fSniklas if (eaten >= 0)
4252159047fSniklas p += eaten;
4262159047fSniklas else if (eaten == -1)
4272159047fSniklas goto invalid;
4282159047fSniklas else
4292159047fSniklas {
4302159047fSniklas (*info->fprintf_func) (info->stream,
431f7cc78ecSespie /* xgettext:c-format */
432f7cc78ecSespie _("<internal error in opcode table: %s %s>\n"),
4332159047fSniklas best->name,
4342159047fSniklas best->args);
4352159047fSniklas goto invalid;
4362159047fSniklas }
4372159047fSniklas
4382159047fSniklas }
4392159047fSniklas p = save_p;
4402159047fSniklas info->fprintf_func = save_printer;
4412159047fSniklas info->print_address_func = save_print_address;
4422159047fSniklas
4432159047fSniklas d = best->args;
4442159047fSniklas
4452159047fSniklas (*info->fprintf_func) (info->stream, "%s", best->name);
4462159047fSniklas
4472159047fSniklas if (*d)
4482159047fSniklas (*info->fprintf_func) (info->stream, " ");
4492159047fSniklas
4502159047fSniklas while (*d)
4512159047fSniklas {
452f7cc78ecSespie p += print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
4532159047fSniklas d += 2;
4542159047fSniklas if (*d && *(d - 2) != 'I' && *d != 'k')
4552159047fSniklas (*info->fprintf_func) (info->stream, ",");
4562159047fSniklas }
4572159047fSniklas return p - buffer;
4582159047fSniklas
4592159047fSniklas invalid:
4602159047fSniklas /* Handle undefined instructions. */
4612159047fSniklas info->fprintf_func = save_printer;
4622159047fSniklas info->print_address_func = save_print_address;
4632159047fSniklas (*info->fprintf_func) (info->stream, "0%o",
4642159047fSniklas (buffer[0] << 8) + buffer[1]);
4652159047fSniklas return 2;
4662159047fSniklas }
4672159047fSniklas
4682159047fSniklas /* Returns number of bytes "eaten" by the operand, or
4692159047fSniklas return -1 if an invalid operand was found, or -2 if
4702159047fSniklas an opcode tabe error was found. */
4712159047fSniklas
4722159047fSniklas static int
print_insn_arg(d,buffer,p0,addr,info)4732159047fSniklas print_insn_arg (d, buffer, p0, addr, info)
4742159047fSniklas const char *d;
4752159047fSniklas unsigned char *buffer;
4762159047fSniklas unsigned char *p0;
4772159047fSniklas bfd_vma addr; /* PC for this arg to be relative to */
4782159047fSniklas disassemble_info *info;
4792159047fSniklas {
4802159047fSniklas register int val = 0;
4812159047fSniklas register int place = d[1];
4822159047fSniklas register unsigned char *p = p0;
4832159047fSniklas int regno;
484c074d1c9Sdrahn register const char *regname;
4852159047fSniklas register unsigned char *p1;
4862159047fSniklas double flval;
4872159047fSniklas int flt_p;
488f7cc78ecSespie bfd_signed_vma disp;
489f7cc78ecSespie unsigned int uval;
4902159047fSniklas
4912159047fSniklas switch (*d)
4922159047fSniklas {
4932159047fSniklas case 'c': /* cache identifier */
4942159047fSniklas {
4952159047fSniklas static char *const cacheFieldName[] = { "nc", "dc", "ic", "bc" };
4962159047fSniklas val = fetch_arg (buffer, place, 2, info);
4972159047fSniklas (*info->fprintf_func) (info->stream, cacheFieldName[val]);
4982159047fSniklas break;
4992159047fSniklas }
5002159047fSniklas
5012159047fSniklas case 'a': /* address register indirect only. Cf. case '+'. */
5022159047fSniklas {
5032159047fSniklas (*info->fprintf_func)
5042159047fSniklas (info->stream,
5052159047fSniklas "%s@",
5062159047fSniklas reg_names[fetch_arg (buffer, place, 3, info) + 8]);
5072159047fSniklas break;
5082159047fSniklas }
5092159047fSniklas
5102159047fSniklas case '_': /* 32-bit absolute address for move16. */
5112159047fSniklas {
512f7cc78ecSespie uval = NEXTULONG (p);
513f7cc78ecSespie (*info->print_address_func) (uval, info);
5142159047fSniklas break;
5152159047fSniklas }
5162159047fSniklas
5172159047fSniklas case 'C':
5182159047fSniklas (*info->fprintf_func) (info->stream, "%%ccr");
5192159047fSniklas break;
5202159047fSniklas
5212159047fSniklas case 'S':
5222159047fSniklas (*info->fprintf_func) (info->stream, "%%sr");
5232159047fSniklas break;
5242159047fSniklas
5252159047fSniklas case 'U':
5262159047fSniklas (*info->fprintf_func) (info->stream, "%%usp");
5272159047fSniklas break;
5282159047fSniklas
529f7cc78ecSespie case 'E':
530f7cc78ecSespie (*info->fprintf_func) (info->stream, "%%acc");
531f7cc78ecSespie break;
532f7cc78ecSespie
533f7cc78ecSespie case 'G':
534f7cc78ecSespie (*info->fprintf_func) (info->stream, "%%macsr");
535f7cc78ecSespie break;
536f7cc78ecSespie
537f7cc78ecSespie case 'H':
538f7cc78ecSespie (*info->fprintf_func) (info->stream, "%%mask");
539f7cc78ecSespie break;
540f7cc78ecSespie
5412159047fSniklas case 'J':
5422159047fSniklas {
543*007c2a45Smiod /* FIXME: There's a problem here, different m68k processors call the
544*007c2a45Smiod same address different names. This table can't get it right
545*007c2a45Smiod because it doesn't know which processor it's disassembling for. */
5462159047fSniklas static const struct { char *name; int value; } names[]
5472159047fSniklas = {{"%sfc", 0x000}, {"%dfc", 0x001}, {"%cacr", 0x002},
5482159047fSniklas {"%tc", 0x003}, {"%itt0",0x004}, {"%itt1", 0x005},
5492159047fSniklas {"%dtt0",0x006}, {"%dtt1",0x007}, {"%buscr",0x008},
5502159047fSniklas {"%usp", 0x800}, {"%vbr", 0x801}, {"%caar", 0x802},
551fddef416Sniklas {"%msp", 0x803}, {"%isp", 0x804},
552*007c2a45Smiod {"%flashbar", 0xc04}, {"%rambar", 0xc05}, /* mcf528x added these. */
5532159047fSniklas
5542159047fSniklas /* Should we be calling this psr like we do in case 'Y'? */
5552159047fSniklas {"%mmusr",0x805},
5562159047fSniklas
5572159047fSniklas {"%urp", 0x806}, {"%srp", 0x807}, {"%pcr", 0x808}};
5582159047fSniklas
5592159047fSniklas val = fetch_arg (buffer, place, 12, info);
5602159047fSniklas for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--)
5612159047fSniklas if (names[regno].value == val)
5622159047fSniklas {
5632159047fSniklas (*info->fprintf_func) (info->stream, "%s", names[regno].name);
5642159047fSniklas break;
5652159047fSniklas }
5662159047fSniklas if (regno < 0)
5672159047fSniklas (*info->fprintf_func) (info->stream, "%d", val);
5682159047fSniklas }
5692159047fSniklas break;
5702159047fSniklas
5712159047fSniklas case 'Q':
5722159047fSniklas val = fetch_arg (buffer, place, 3, info);
5732159047fSniklas /* 0 means 8, except for the bkpt instruction... */
5742159047fSniklas if (val == 0 && d[1] != 's')
5752159047fSniklas val = 8;
5762159047fSniklas (*info->fprintf_func) (info->stream, "#%d", val);
5772159047fSniklas break;
5782159047fSniklas
579*007c2a45Smiod case 'x':
580*007c2a45Smiod val = fetch_arg (buffer, place, 3, info);
581*007c2a45Smiod /* 0 means -1. */
582*007c2a45Smiod if (val == 0)
583*007c2a45Smiod val = -1;
584*007c2a45Smiod (*info->fprintf_func) (info->stream, "#%d", val);
585*007c2a45Smiod break;
586*007c2a45Smiod
5872159047fSniklas case 'M':
588f7cc78ecSespie if (place == 'h')
589f7cc78ecSespie {
590f7cc78ecSespie static char *const scalefactor_name[] = { "<<", ">>" };
591f7cc78ecSespie val = fetch_arg (buffer, place, 1, info);
592f7cc78ecSespie (*info->fprintf_func) (info->stream, scalefactor_name[val]);
593f7cc78ecSespie }
594f7cc78ecSespie else
595f7cc78ecSespie {
5962159047fSniklas val = fetch_arg (buffer, place, 8, info);
5972159047fSniklas if (val & 0x80)
5982159047fSniklas val = val - 0x100;
5992159047fSniklas (*info->fprintf_func) (info->stream, "#%d", val);
600f7cc78ecSespie }
6012159047fSniklas break;
6022159047fSniklas
6032159047fSniklas case 'T':
6042159047fSniklas val = fetch_arg (buffer, place, 4, info);
6052159047fSniklas (*info->fprintf_func) (info->stream, "#%d", val);
6062159047fSniklas break;
6072159047fSniklas
6082159047fSniklas case 'D':
6092159047fSniklas (*info->fprintf_func) (info->stream, "%s",
6102159047fSniklas reg_names[fetch_arg (buffer, place, 3, info)]);
6112159047fSniklas break;
6122159047fSniklas
6132159047fSniklas case 'A':
6142159047fSniklas (*info->fprintf_func)
6152159047fSniklas (info->stream, "%s",
6162159047fSniklas reg_names[fetch_arg (buffer, place, 3, info) + 010]);
6172159047fSniklas break;
6182159047fSniklas
6192159047fSniklas case 'R':
6202159047fSniklas (*info->fprintf_func)
6212159047fSniklas (info->stream, "%s",
6222159047fSniklas reg_names[fetch_arg (buffer, place, 4, info)]);
6232159047fSniklas break;
6242159047fSniklas
6252159047fSniklas case 'r':
6262159047fSniklas regno = fetch_arg (buffer, place, 4, info);
6272159047fSniklas if (regno > 7)
6282159047fSniklas (*info->fprintf_func) (info->stream, "%s@", reg_names[regno]);
6292159047fSniklas else
6302159047fSniklas (*info->fprintf_func) (info->stream, "@(%s)", reg_names[regno]);
6312159047fSniklas break;
6322159047fSniklas
6332159047fSniklas case 'F':
6342159047fSniklas (*info->fprintf_func)
6352159047fSniklas (info->stream, "%%fp%d",
6362159047fSniklas fetch_arg (buffer, place, 3, info));
6372159047fSniklas break;
6382159047fSniklas
6392159047fSniklas case 'O':
6402159047fSniklas val = fetch_arg (buffer, place, 6, info);
6412159047fSniklas if (val & 0x20)
6422159047fSniklas (*info->fprintf_func) (info->stream, "%s", reg_names[val & 7]);
6432159047fSniklas else
6442159047fSniklas (*info->fprintf_func) (info->stream, "%d", val);
6452159047fSniklas break;
6462159047fSniklas
6472159047fSniklas case '+':
6482159047fSniklas (*info->fprintf_func)
6492159047fSniklas (info->stream, "%s@+",
6502159047fSniklas reg_names[fetch_arg (buffer, place, 3, info) + 8]);
6512159047fSniklas break;
6522159047fSniklas
6532159047fSniklas case '-':
6542159047fSniklas (*info->fprintf_func)
6552159047fSniklas (info->stream, "%s@-",
6562159047fSniklas reg_names[fetch_arg (buffer, place, 3, info) + 8]);
6572159047fSniklas break;
6582159047fSniklas
6592159047fSniklas case 'k':
6602159047fSniklas if (place == 'k')
6612159047fSniklas (*info->fprintf_func)
6622159047fSniklas (info->stream, "{%s}",
6632159047fSniklas reg_names[fetch_arg (buffer, place, 3, info)]);
6642159047fSniklas else if (place == 'C')
6652159047fSniklas {
6662159047fSniklas val = fetch_arg (buffer, place, 7, info);
6672159047fSniklas if (val > 63) /* This is a signed constant. */
6682159047fSniklas val -= 128;
6692159047fSniklas (*info->fprintf_func) (info->stream, "{#%d}", val);
6702159047fSniklas }
6712159047fSniklas else
6722159047fSniklas return -2;
6732159047fSniklas break;
6742159047fSniklas
6752159047fSniklas case '#':
6762159047fSniklas case '^':
6772159047fSniklas p1 = buffer + (*d == '#' ? 2 : 4);
6782159047fSniklas if (place == 's')
6792159047fSniklas val = fetch_arg (buffer, place, 4, info);
6802159047fSniklas else if (place == 'C')
6812159047fSniklas val = fetch_arg (buffer, place, 7, info);
6822159047fSniklas else if (place == '8')
6832159047fSniklas val = fetch_arg (buffer, place, 3, info);
6842159047fSniklas else if (place == '3')
6852159047fSniklas val = fetch_arg (buffer, place, 8, info);
6862159047fSniklas else if (place == 'b')
6872159047fSniklas val = NEXTBYTE (p1);
6882159047fSniklas else if (place == 'w' || place == 'W')
6892159047fSniklas val = NEXTWORD (p1);
6902159047fSniklas else if (place == 'l')
6912159047fSniklas val = NEXTLONG (p1);
6922159047fSniklas else
6932159047fSniklas return -2;
6942159047fSniklas (*info->fprintf_func) (info->stream, "#%d", val);
6952159047fSniklas break;
6962159047fSniklas
6972159047fSniklas case 'B':
6982159047fSniklas if (place == 'b')
699f7cc78ecSespie disp = NEXTBYTE (p);
7002159047fSniklas else if (place == 'B')
701f7cc78ecSespie disp = COERCE_SIGNED_CHAR (buffer[1]);
7022159047fSniklas else if (place == 'w' || place == 'W')
703f7cc78ecSespie disp = NEXTWORD (p);
7042159047fSniklas else if (place == 'l' || place == 'L' || place == 'C')
705f7cc78ecSespie disp = NEXTLONG (p);
7062159047fSniklas else if (place == 'g')
7072159047fSniklas {
708f7cc78ecSespie disp = NEXTBYTE (buffer);
709f7cc78ecSespie if (disp == 0)
710f7cc78ecSespie disp = NEXTWORD (p);
711f7cc78ecSespie else if (disp == -1)
712f7cc78ecSespie disp = NEXTLONG (p);
7132159047fSniklas }
7142159047fSniklas else if (place == 'c')
7152159047fSniklas {
7162159047fSniklas if (buffer[1] & 0x40) /* If bit six is one, long offset */
717f7cc78ecSespie disp = NEXTLONG (p);
7182159047fSniklas else
719f7cc78ecSespie disp = NEXTWORD (p);
7202159047fSniklas }
7212159047fSniklas else
7222159047fSniklas return -2;
7232159047fSniklas
724f7cc78ecSespie (*info->print_address_func) (addr + disp, info);
7252159047fSniklas break;
7262159047fSniklas
7272159047fSniklas case 'd':
7282159047fSniklas val = NEXTWORD (p);
7292159047fSniklas (*info->fprintf_func)
7302159047fSniklas (info->stream, "%s@(%d)",
731fddef416Sniklas reg_names[fetch_arg (buffer, place, 3, info) + 8], val);
7322159047fSniklas break;
7332159047fSniklas
7342159047fSniklas case 's':
7352159047fSniklas (*info->fprintf_func) (info->stream, "%s",
7362159047fSniklas fpcr_names[fetch_arg (buffer, place, 3, info)]);
7372159047fSniklas break;
7382159047fSniklas
7392159047fSniklas case 'I':
7402159047fSniklas /* Get coprocessor ID... */
7412159047fSniklas val = fetch_arg (buffer, 'd', 3, info);
7422159047fSniklas
7432159047fSniklas if (val != 1) /* Unusual coprocessor ID? */
7442159047fSniklas (*info->fprintf_func) (info->stream, "(cpid=%d) ", val);
7452159047fSniklas break;
7462159047fSniklas
7472159047fSniklas case '*':
7482159047fSniklas case '~':
7492159047fSniklas case '%':
7502159047fSniklas case ';':
7512159047fSniklas case '@':
7522159047fSniklas case '!':
7532159047fSniklas case '$':
7542159047fSniklas case '?':
7552159047fSniklas case '/':
7562159047fSniklas case '&':
7572159047fSniklas case '|':
758fddef416Sniklas case '<':
759fddef416Sniklas case '>':
760f7cc78ecSespie case 'm':
761f7cc78ecSespie case 'n':
762f7cc78ecSespie case 'o':
763f7cc78ecSespie case 'p':
764f7cc78ecSespie case 'q':
765f7cc78ecSespie case 'v':
766*007c2a45Smiod case 'b':
767*007c2a45Smiod case 'w':
768*007c2a45Smiod case 'y':
769*007c2a45Smiod case 'z':
7702159047fSniklas if (place == 'd')
7712159047fSniklas {
7722159047fSniklas val = fetch_arg (buffer, 'x', 6, info);
7732159047fSniklas val = ((val & 7) << 3) + ((val >> 3) & 7);
7742159047fSniklas }
7752159047fSniklas else
7762159047fSniklas val = fetch_arg (buffer, 's', 6, info);
7772159047fSniklas
7782159047fSniklas /* Get register number assuming address register. */
7792159047fSniklas regno = (val & 7) + 8;
7802159047fSniklas regname = reg_names[regno];
7812159047fSniklas switch (val >> 3)
7822159047fSniklas {
7832159047fSniklas case 0:
7842159047fSniklas (*info->fprintf_func) (info->stream, "%s", reg_names[val]);
7852159047fSniklas break;
7862159047fSniklas
7872159047fSniklas case 1:
7882159047fSniklas (*info->fprintf_func) (info->stream, "%s", regname);
7892159047fSniklas break;
7902159047fSniklas
7912159047fSniklas case 2:
7922159047fSniklas (*info->fprintf_func) (info->stream, "%s@", regname);
7932159047fSniklas break;
7942159047fSniklas
7952159047fSniklas case 3:
7962159047fSniklas (*info->fprintf_func) (info->stream, "%s@+", regname);
7972159047fSniklas break;
7982159047fSniklas
7992159047fSniklas case 4:
8002159047fSniklas (*info->fprintf_func) (info->stream, "%s@-", regname);
8012159047fSniklas break;
8022159047fSniklas
8032159047fSniklas case 5:
8042159047fSniklas val = NEXTWORD (p);
8052159047fSniklas (*info->fprintf_func) (info->stream, "%s@(%d)", regname, val);
8062159047fSniklas break;
8072159047fSniklas
8082159047fSniklas case 6:
8092159047fSniklas p = print_indexed (regno, p, addr, info);
8102159047fSniklas break;
8112159047fSniklas
8122159047fSniklas case 7:
8132159047fSniklas switch (val & 7)
8142159047fSniklas {
8152159047fSniklas case 0:
8162159047fSniklas val = NEXTWORD (p);
8172159047fSniklas (*info->print_address_func) (val, info);
8182159047fSniklas break;
8192159047fSniklas
8202159047fSniklas case 1:
821f7cc78ecSespie uval = NEXTULONG (p);
822f7cc78ecSespie (*info->print_address_func) (uval, info);
8232159047fSniklas break;
8242159047fSniklas
8252159047fSniklas case 2:
8262159047fSniklas val = NEXTWORD (p);
827f7cc78ecSespie (*info->fprintf_func) (info->stream, "%%pc@(");
8282159047fSniklas (*info->print_address_func) (addr + val, info);
829f7cc78ecSespie (*info->fprintf_func) (info->stream, ")");
8302159047fSniklas break;
8312159047fSniklas
8322159047fSniklas case 3:
8332159047fSniklas p = print_indexed (-1, p, addr, info);
8342159047fSniklas break;
8352159047fSniklas
8362159047fSniklas case 4:
8372159047fSniklas flt_p = 1; /* Assume it's a float... */
8382159047fSniklas switch (place)
8392159047fSniklas {
8402159047fSniklas case 'b':
8412159047fSniklas val = NEXTBYTE (p);
8422159047fSniklas flt_p = 0;
8432159047fSniklas break;
8442159047fSniklas
8452159047fSniklas case 'w':
8462159047fSniklas val = NEXTWORD (p);
8472159047fSniklas flt_p = 0;
8482159047fSniklas break;
8492159047fSniklas
8502159047fSniklas case 'l':
8512159047fSniklas val = NEXTLONG (p);
8522159047fSniklas flt_p = 0;
8532159047fSniklas break;
8542159047fSniklas
8552159047fSniklas case 'f':
8562159047fSniklas NEXTSINGLE (flval, p);
8572159047fSniklas break;
8582159047fSniklas
8592159047fSniklas case 'F':
8602159047fSniklas NEXTDOUBLE (flval, p);
8612159047fSniklas break;
8622159047fSniklas
8632159047fSniklas case 'x':
864fddef416Sniklas NEXTEXTEND (flval, p);
8652159047fSniklas break;
8662159047fSniklas
8672159047fSniklas case 'p':
8682159047fSniklas flval = NEXTPACKED (p);
8692159047fSniklas break;
8702159047fSniklas
8712159047fSniklas default:
8722159047fSniklas return -1;
8732159047fSniklas }
8742159047fSniklas if (flt_p) /* Print a float? */
8752159047fSniklas (*info->fprintf_func) (info->stream, "#%g", flval);
8762159047fSniklas else
8772159047fSniklas (*info->fprintf_func) (info->stream, "#%d", val);
8782159047fSniklas break;
8792159047fSniklas
8802159047fSniklas default:
8812159047fSniklas return -1;
8822159047fSniklas }
8832159047fSniklas }
8842159047fSniklas break;
8852159047fSniklas
8862159047fSniklas case 'L':
8872159047fSniklas case 'l':
8882159047fSniklas if (place == 'w')
8892159047fSniklas {
8902159047fSniklas char doneany;
8912159047fSniklas p1 = buffer + 2;
8922159047fSniklas val = NEXTWORD (p1);
8932159047fSniklas /* Move the pointer ahead if this point is farther ahead
8942159047fSniklas than the last. */
8952159047fSniklas p = p1 > p ? p1 : p;
8962159047fSniklas if (val == 0)
8972159047fSniklas {
8982159047fSniklas (*info->fprintf_func) (info->stream, "#0");
8992159047fSniklas break;
9002159047fSniklas }
9012159047fSniklas if (*d == 'l')
9022159047fSniklas {
9032159047fSniklas register int newval = 0;
9042159047fSniklas for (regno = 0; regno < 16; ++regno)
9052159047fSniklas if (val & (0x8000 >> regno))
9062159047fSniklas newval |= 1 << regno;
9072159047fSniklas val = newval;
9082159047fSniklas }
9092159047fSniklas val &= 0xffff;
9102159047fSniklas doneany = 0;
9112159047fSniklas for (regno = 0; regno < 16; ++regno)
9122159047fSniklas if (val & (1 << regno))
9132159047fSniklas {
9142159047fSniklas int first_regno;
9152159047fSniklas if (doneany)
9162159047fSniklas (*info->fprintf_func) (info->stream, "/");
9172159047fSniklas doneany = 1;
9182159047fSniklas (*info->fprintf_func) (info->stream, "%s", reg_names[regno]);
9192159047fSniklas first_regno = regno;
9202159047fSniklas while (val & (1 << (regno + 1)))
9212159047fSniklas ++regno;
9222159047fSniklas if (regno > first_regno)
9232159047fSniklas (*info->fprintf_func) (info->stream, "-%s",
9242159047fSniklas reg_names[regno]);
9252159047fSniklas }
9262159047fSniklas }
9272159047fSniklas else if (place == '3')
9282159047fSniklas {
9292159047fSniklas /* `fmovem' insn. */
9302159047fSniklas char doneany;
9312159047fSniklas val = fetch_arg (buffer, place, 8, info);
9322159047fSniklas if (val == 0)
9332159047fSniklas {
9342159047fSniklas (*info->fprintf_func) (info->stream, "#0");
9352159047fSniklas break;
9362159047fSniklas }
9372159047fSniklas if (*d == 'l')
9382159047fSniklas {
9392159047fSniklas register int newval = 0;
9402159047fSniklas for (regno = 0; regno < 8; ++regno)
9412159047fSniklas if (val & (0x80 >> regno))
9422159047fSniklas newval |= 1 << regno;
9432159047fSniklas val = newval;
9442159047fSniklas }
9452159047fSniklas val &= 0xff;
9462159047fSniklas doneany = 0;
9472159047fSniklas for (regno = 0; regno < 8; ++regno)
9482159047fSniklas if (val & (1 << regno))
9492159047fSniklas {
9502159047fSniklas int first_regno;
9512159047fSniklas if (doneany)
9522159047fSniklas (*info->fprintf_func) (info->stream, "/");
9532159047fSniklas doneany = 1;
9542159047fSniklas (*info->fprintf_func) (info->stream, "%%fp%d", regno);
9552159047fSniklas first_regno = regno;
9562159047fSniklas while (val & (1 << (regno + 1)))
9572159047fSniklas ++regno;
9582159047fSniklas if (regno > first_regno)
9592159047fSniklas (*info->fprintf_func) (info->stream, "-%%fp%d", regno);
9602159047fSniklas }
9612159047fSniklas }
9622159047fSniklas else if (place == '8')
9632159047fSniklas {
9642159047fSniklas /* fmoveml for FP status registers */
9652159047fSniklas (*info->fprintf_func) (info->stream, "%s",
9662159047fSniklas fpcr_names[fetch_arg (buffer, place, 3,
9672159047fSniklas info)]);
9682159047fSniklas }
9692159047fSniklas else
9702159047fSniklas return -2;
9712159047fSniklas break;
9722159047fSniklas
9732159047fSniklas case 'X':
9742159047fSniklas place = '8';
9752159047fSniklas case 'Y':
9762159047fSniklas case 'Z':
9772159047fSniklas case 'W':
9782159047fSniklas case '0':
9792159047fSniklas case '1':
9802159047fSniklas case '2':
9812159047fSniklas case '3':
9822159047fSniklas {
9832159047fSniklas int val = fetch_arg (buffer, place, 5, info);
9842159047fSniklas char *name = 0;
9852159047fSniklas switch (val)
9862159047fSniklas {
9872159047fSniklas case 2: name = "%tt0"; break;
9882159047fSniklas case 3: name = "%tt1"; break;
9892159047fSniklas case 0x10: name = "%tc"; break;
9902159047fSniklas case 0x11: name = "%drp"; break;
9912159047fSniklas case 0x12: name = "%srp"; break;
9922159047fSniklas case 0x13: name = "%crp"; break;
9932159047fSniklas case 0x14: name = "%cal"; break;
9942159047fSniklas case 0x15: name = "%val"; break;
9952159047fSniklas case 0x16: name = "%scc"; break;
9962159047fSniklas case 0x17: name = "%ac"; break;
9972159047fSniklas case 0x18: name = "%psr"; break;
9982159047fSniklas case 0x19: name = "%pcsr"; break;
9992159047fSniklas case 0x1c:
10002159047fSniklas case 0x1d:
10012159047fSniklas {
10022159047fSniklas int break_reg = ((buffer[3] >> 2) & 7);
10032159047fSniklas (*info->fprintf_func)
10042159047fSniklas (info->stream, val == 0x1c ? "%%bad%d" : "%%bac%d",
10052159047fSniklas break_reg);
10062159047fSniklas }
10072159047fSniklas break;
10082159047fSniklas default:
10092159047fSniklas (*info->fprintf_func) (info->stream, "<mmu register %d>", val);
10102159047fSniklas }
10112159047fSniklas if (name)
10122159047fSniklas (*info->fprintf_func) (info->stream, "%s", name);
10132159047fSniklas }
10142159047fSniklas break;
10152159047fSniklas
10162159047fSniklas case 'f':
10172159047fSniklas {
10182159047fSniklas int fc = fetch_arg (buffer, place, 5, info);
10192159047fSniklas if (fc == 1)
10202159047fSniklas (*info->fprintf_func) (info->stream, "%%dfc");
10212159047fSniklas else if (fc == 0)
10222159047fSniklas (*info->fprintf_func) (info->stream, "%%sfc");
10232159047fSniklas else
1024f7cc78ecSespie /* xgettext:c-format */
1025f7cc78ecSespie (*info->fprintf_func) (info->stream, _("<function code %d>"), fc);
10262159047fSniklas }
10272159047fSniklas break;
10282159047fSniklas
10292159047fSniklas case 'V':
10302159047fSniklas (*info->fprintf_func) (info->stream, "%%val");
10312159047fSniklas break;
10322159047fSniklas
10332159047fSniklas case 't':
10342159047fSniklas {
10352159047fSniklas int level = fetch_arg (buffer, place, 3, info);
10362159047fSniklas (*info->fprintf_func) (info->stream, "%d", level);
10372159047fSniklas }
10382159047fSniklas break;
10392159047fSniklas
1040f7cc78ecSespie case 'u':
1041f7cc78ecSespie {
1042f7cc78ecSespie short is_upper = 0;
1043f7cc78ecSespie int reg = fetch_arg (buffer, place, 5, info);
1044f7cc78ecSespie
1045f7cc78ecSespie if (reg & 0x10)
1046f7cc78ecSespie {
1047f7cc78ecSespie is_upper = 1;
1048f7cc78ecSespie reg &= 0xf;
1049f7cc78ecSespie }
1050f7cc78ecSespie (*info->fprintf_func) (info->stream, "%s%s",
1051f7cc78ecSespie reg_names[reg],
1052f7cc78ecSespie is_upper ? "u" : "l");
1053f7cc78ecSespie }
1054f7cc78ecSespie break;
1055f7cc78ecSespie
10562159047fSniklas default:
10572159047fSniklas return -2;
10582159047fSniklas }
10592159047fSniklas
10602159047fSniklas return p - p0;
10612159047fSniklas }
10622159047fSniklas
10632159047fSniklas /* Fetch BITS bits from a position in the instruction specified by CODE.
10642159047fSniklas CODE is a "place to put an argument", or 'x' for a destination
10652159047fSniklas that is a general address (mode and register).
10662159047fSniklas BUFFER contains the instruction. */
10672159047fSniklas
10682159047fSniklas static int
fetch_arg(buffer,code,bits,info)10692159047fSniklas fetch_arg (buffer, code, bits, info)
10702159047fSniklas unsigned char *buffer;
10712159047fSniklas int code;
10722159047fSniklas int bits;
10732159047fSniklas disassemble_info *info;
10742159047fSniklas {
10752159047fSniklas register int val = 0;
10762159047fSniklas switch (code)
10772159047fSniklas {
10782159047fSniklas case 's':
10792159047fSniklas val = buffer[1];
10802159047fSniklas break;
10812159047fSniklas
10822159047fSniklas case 'd': /* Destination, for register or quick. */
10832159047fSniklas val = (buffer[0] << 8) + buffer[1];
10842159047fSniklas val >>= 9;
10852159047fSniklas break;
10862159047fSniklas
10872159047fSniklas case 'x': /* Destination, for general arg */
10882159047fSniklas val = (buffer[0] << 8) + buffer[1];
10892159047fSniklas val >>= 6;
10902159047fSniklas break;
10912159047fSniklas
10922159047fSniklas case 'k':
10932159047fSniklas FETCH_DATA (info, buffer + 3);
10942159047fSniklas val = (buffer[3] >> 4);
10952159047fSniklas break;
10962159047fSniklas
10972159047fSniklas case 'C':
10982159047fSniklas FETCH_DATA (info, buffer + 3);
10992159047fSniklas val = buffer[3];
11002159047fSniklas break;
11012159047fSniklas
11022159047fSniklas case '1':
11032159047fSniklas FETCH_DATA (info, buffer + 3);
11042159047fSniklas val = (buffer[2] << 8) + buffer[3];
11052159047fSniklas val >>= 12;
11062159047fSniklas break;
11072159047fSniklas
11082159047fSniklas case '2':
11092159047fSniklas FETCH_DATA (info, buffer + 3);
11102159047fSniklas val = (buffer[2] << 8) + buffer[3];
11112159047fSniklas val >>= 6;
11122159047fSniklas break;
11132159047fSniklas
11142159047fSniklas case '3':
11152159047fSniklas case 'j':
11162159047fSniklas FETCH_DATA (info, buffer + 3);
11172159047fSniklas val = (buffer[2] << 8) + buffer[3];
11182159047fSniklas break;
11192159047fSniklas
11202159047fSniklas case '4':
11212159047fSniklas FETCH_DATA (info, buffer + 5);
11222159047fSniklas val = (buffer[4] << 8) + buffer[5];
11232159047fSniklas val >>= 12;
11242159047fSniklas break;
11252159047fSniklas
11262159047fSniklas case '5':
11272159047fSniklas FETCH_DATA (info, buffer + 5);
11282159047fSniklas val = (buffer[4] << 8) + buffer[5];
11292159047fSniklas val >>= 6;
11302159047fSniklas break;
11312159047fSniklas
11322159047fSniklas case '6':
11332159047fSniklas FETCH_DATA (info, buffer + 5);
11342159047fSniklas val = (buffer[4] << 8) + buffer[5];
11352159047fSniklas break;
11362159047fSniklas
11372159047fSniklas case '7':
11382159047fSniklas FETCH_DATA (info, buffer + 3);
11392159047fSniklas val = (buffer[2] << 8) + buffer[3];
11402159047fSniklas val >>= 7;
11412159047fSniklas break;
11422159047fSniklas
11432159047fSniklas case '8':
11442159047fSniklas FETCH_DATA (info, buffer + 3);
11452159047fSniklas val = (buffer[2] << 8) + buffer[3];
11462159047fSniklas val >>= 10;
11472159047fSniklas break;
11482159047fSniklas
11492159047fSniklas case '9':
11502159047fSniklas FETCH_DATA (info, buffer + 3);
11512159047fSniklas val = (buffer[2] << 8) + buffer[3];
11522159047fSniklas val >>= 5;
11532159047fSniklas break;
11542159047fSniklas
11552159047fSniklas case 'e':
11562159047fSniklas val = (buffer[1] >> 6);
11572159047fSniklas break;
11582159047fSniklas
1159f7cc78ecSespie case 'm':
1160f7cc78ecSespie val = (buffer[1] & 0x40 ? 0x8 : 0)
1161f7cc78ecSespie | ((buffer[0] >> 1) & 0x7)
1162f7cc78ecSespie | (buffer[3] & 0x80 ? 0x10 : 0);
1163f7cc78ecSespie break;
1164f7cc78ecSespie
1165f7cc78ecSespie case 'n':
1166f7cc78ecSespie val = (buffer[1] & 0x40 ? 0x8 : 0) | ((buffer[0] >> 1) & 0x7);
1167f7cc78ecSespie break;
1168f7cc78ecSespie
1169f7cc78ecSespie case 'o':
1170f7cc78ecSespie val = (buffer[2] >> 4) | (buffer[3] & 0x80 ? 0x10 : 0);
1171f7cc78ecSespie break;
1172f7cc78ecSespie
1173f7cc78ecSespie case 'M':
1174f7cc78ecSespie val = buffer[1] | (buffer[3] & 0x40 ? 0x10 : 0);
1175f7cc78ecSespie break;
1176f7cc78ecSespie
1177f7cc78ecSespie case 'N':
1178f7cc78ecSespie val = buffer[3] | (buffer[3] & 0x40 ? 0x10 : 0);
1179f7cc78ecSespie break;
1180f7cc78ecSespie
1181f7cc78ecSespie case 'h':
1182f7cc78ecSespie val = buffer[2] >> 2;
1183f7cc78ecSespie break;
1184f7cc78ecSespie
11852159047fSniklas default:
11862159047fSniklas abort ();
11872159047fSniklas }
11882159047fSniklas
11892159047fSniklas switch (bits)
11902159047fSniklas {
1191f7cc78ecSespie case 1:
1192f7cc78ecSespie return val & 1;
11932159047fSniklas case 2:
11942159047fSniklas return val & 3;
11952159047fSniklas case 3:
11962159047fSniklas return val & 7;
11972159047fSniklas case 4:
11982159047fSniklas return val & 017;
11992159047fSniklas case 5:
12002159047fSniklas return val & 037;
12012159047fSniklas case 6:
12022159047fSniklas return val & 077;
12032159047fSniklas case 7:
12042159047fSniklas return val & 0177;
12052159047fSniklas case 8:
12062159047fSniklas return val & 0377;
12072159047fSniklas case 12:
12082159047fSniklas return val & 07777;
12092159047fSniklas default:
12102159047fSniklas abort ();
12112159047fSniklas }
12122159047fSniklas }
12132159047fSniklas
12142159047fSniklas /* Print an indexed argument. The base register is BASEREG (-1 for pc).
12152159047fSniklas P points to extension word, in buffer.
12162159047fSniklas ADDR is the nominal core address of that extension word. */
12172159047fSniklas
12182159047fSniklas static unsigned char *
print_indexed(basereg,p,addr,info)12192159047fSniklas print_indexed (basereg, p, addr, info)
12202159047fSniklas int basereg;
12212159047fSniklas unsigned char *p;
12222159047fSniklas bfd_vma addr;
12232159047fSniklas disassemble_info *info;
12242159047fSniklas {
12252159047fSniklas register int word;
12262159047fSniklas static char *const scales[] = { "", ":2", ":4", ":8" };
12272159047fSniklas bfd_vma base_disp;
12282159047fSniklas bfd_vma outer_disp;
12292159047fSniklas char buf[40];
12302159047fSniklas char vmabuf[50];
12312159047fSniklas
12322159047fSniklas word = NEXTWORD (p);
12332159047fSniklas
12342159047fSniklas /* Generate the text for the index register.
12352159047fSniklas Where this will be output is not yet determined. */
12362159047fSniklas sprintf (buf, "%s:%c%s",
12372159047fSniklas reg_names[(word >> 12) & 0xf],
12382159047fSniklas (word & 0x800) ? 'l' : 'w',
12392159047fSniklas scales[(word >> 9) & 3]);
12402159047fSniklas
12412159047fSniklas /* Handle the 68000 style of indexing. */
12422159047fSniklas
12432159047fSniklas if ((word & 0x100) == 0)
12442159047fSniklas {
1245f7cc78ecSespie base_disp = word & 0xff;
1246f7cc78ecSespie if ((base_disp & 0x80) != 0)
1247f7cc78ecSespie base_disp -= 0x100;
12482159047fSniklas if (basereg == -1)
1249f7cc78ecSespie base_disp += addr;
1250f7cc78ecSespie print_base (basereg, base_disp, info);
12512159047fSniklas (*info->fprintf_func) (info->stream, ",%s)", buf);
12522159047fSniklas return p;
12532159047fSniklas }
12542159047fSniklas
12552159047fSniklas /* Handle the generalized kind. */
12562159047fSniklas /* First, compute the displacement to add to the base register. */
12572159047fSniklas
12582159047fSniklas if (word & 0200)
12592159047fSniklas {
12602159047fSniklas if (basereg == -1)
12612159047fSniklas basereg = -3;
12622159047fSniklas else
12632159047fSniklas basereg = -2;
12642159047fSniklas }
12652159047fSniklas if (word & 0100)
12662159047fSniklas buf[0] = '\0';
12672159047fSniklas base_disp = 0;
12682159047fSniklas switch ((word >> 4) & 3)
12692159047fSniklas {
12702159047fSniklas case 2:
12712159047fSniklas base_disp = NEXTWORD (p);
12722159047fSniklas break;
12732159047fSniklas case 3:
12742159047fSniklas base_disp = NEXTLONG (p);
12752159047fSniklas }
12762159047fSniklas if (basereg == -1)
12772159047fSniklas base_disp += addr;
12782159047fSniklas
12792159047fSniklas /* Handle single-level case (not indirect) */
12802159047fSniklas
12812159047fSniklas if ((word & 7) == 0)
12822159047fSniklas {
12832159047fSniklas print_base (basereg, base_disp, info);
12842159047fSniklas if (buf[0] != '\0')
12852159047fSniklas (*info->fprintf_func) (info->stream, ",%s", buf);
12862159047fSniklas (*info->fprintf_func) (info->stream, ")");
12872159047fSniklas return p;
12882159047fSniklas }
12892159047fSniklas
12902159047fSniklas /* Two level. Compute displacement to add after indirection. */
12912159047fSniklas
12922159047fSniklas outer_disp = 0;
12932159047fSniklas switch (word & 3)
12942159047fSniklas {
12952159047fSniklas case 2:
12962159047fSniklas outer_disp = NEXTWORD (p);
12972159047fSniklas break;
12982159047fSniklas case 3:
12992159047fSniklas outer_disp = NEXTLONG (p);
13002159047fSniklas }
13012159047fSniklas
13022159047fSniklas print_base (basereg, base_disp, info);
13032159047fSniklas if ((word & 4) == 0 && buf[0] != '\0')
13042159047fSniklas {
13052159047fSniklas (*info->fprintf_func) (info->stream, ",%s", buf);
13062159047fSniklas buf[0] = '\0';
13072159047fSniklas }
13082159047fSniklas sprintf_vma (vmabuf, outer_disp);
13092159047fSniklas (*info->fprintf_func) (info->stream, ")@(%s", vmabuf);
13102159047fSniklas if (buf[0] != '\0')
13112159047fSniklas (*info->fprintf_func) (info->stream, ",%s", buf);
13122159047fSniklas (*info->fprintf_func) (info->stream, ")");
13132159047fSniklas
13142159047fSniklas return p;
13152159047fSniklas }
13162159047fSniklas
13172159047fSniklas /* Print a base register REGNO and displacement DISP, on INFO->STREAM.
13182159047fSniklas REGNO = -1 for pc, -2 for none (suppressed). */
13192159047fSniklas
13202159047fSniklas static void
print_base(regno,disp,info)13212159047fSniklas print_base (regno, disp, info)
13222159047fSniklas int regno;
13232159047fSniklas bfd_vma disp;
13242159047fSniklas disassemble_info *info;
13252159047fSniklas {
13262159047fSniklas if (regno == -1)
13272159047fSniklas {
13282159047fSniklas (*info->fprintf_func) (info->stream, "%%pc@(");
13292159047fSniklas (*info->print_address_func) (disp, info);
13302159047fSniklas }
13312159047fSniklas else
13322159047fSniklas {
13332159047fSniklas char buf[50];
13342159047fSniklas
13352159047fSniklas if (regno == -2)
13362159047fSniklas (*info->fprintf_func) (info->stream, "@(");
13372159047fSniklas else if (regno == -3)
13382159047fSniklas (*info->fprintf_func) (info->stream, "%%zpc@(");
13392159047fSniklas else
13402159047fSniklas (*info->fprintf_func) (info->stream, "%s@(", reg_names[regno]);
13412159047fSniklas
13422159047fSniklas sprintf_vma (buf, disp);
13432159047fSniklas (*info->fprintf_func) (info->stream, "%s", buf);
13442159047fSniklas }
13452159047fSniklas }
1346