ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/mon/src/disass/m68k-dis.c
Revision: 1.4
Committed: 2003-04-13T09:54:26Z (21 years, 1 month ago) by gbeauche
Content type: text/plain
Branch: MAIN
CVS Tags: release_3-1
Changes since 1.3: +3 -1 lines
Log Message:
Fix printing of m68k addresses, we assume they are always 32-bit values
even in real addressing mode.

File Contents

# User Rev Content
1 cebix 1.1 /* Print Motorola 68k instructions.
2     Copyright 1986, 87, 89, 91, 92, 93, 94, 95, 96, 97, 1998
3     Free Software Foundation, Inc.
4    
5     This file is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9    
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13     GNU General Public License for more details.
14    
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18    
19 gbeauche 1.3 #include <stdlib.h>
20 cebix 1.1 #include "dis-asm.h"
21     #include "floatformat.h"
22     #include "opintl.h"
23    
24     #include "m68k.h"
25    
26     /* Local function prototypes */
27    
28     static int
29     fetch_data PARAMS ((struct disassemble_info *, bfd_byte *));
30    
31     static void
32     dummy_print_address PARAMS ((bfd_vma, struct disassemble_info *));
33    
34     static int
35     fetch_arg PARAMS ((unsigned char *, int, int, disassemble_info *));
36    
37     static void
38     print_base PARAMS ((int, bfd_vma, disassemble_info*));
39    
40     static unsigned char *
41     print_indexed PARAMS ((int, unsigned char *, bfd_vma, disassemble_info *));
42    
43     static int
44     print_insn_arg PARAMS ((const char *, unsigned char *, unsigned char *,
45     bfd_vma, disassemble_info *));
46    
47     CONST char * CONST fpcr_names[] = {
48     "", "fpiar", "fpsr", "fpiar/fpsr", "fpcr",
49     "fpiar/fpcr", "fpsr/fpcr", "fpiar/fpsr/fpcr"};
50    
51     static char *const reg_names[] = {
52     "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
53     "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
54     "sr", "pc"};
55    
56     /* Sign-extend an (unsigned char). */
57     #if __STDC__ == 1
58     #define COERCE_SIGNED_CHAR(ch) ((signed char)(ch))
59     #else
60     #define COERCE_SIGNED_CHAR(ch) ((int)(((ch) ^ 0x80) & 0xFF) - 128)
61     #endif
62    
63     /* Get a 1 byte signed integer. */
64     #define NEXTBYTE(p) (p += 2, FETCH_DATA (info, p), COERCE_SIGNED_CHAR(p[-1]))
65    
66     /* Get a 2 byte signed integer. */
67     #define COERCE16(x) ((int) (((x) ^ 0x8000) - 0x8000))
68     #define NEXTWORD(p) \
69     (p += 2, FETCH_DATA (info, p), \
70     COERCE16 ((p[-2] << 8) + p[-1]))
71    
72     /* Get a 4 byte signed integer. */
73     #define COERCE32(x) ((bfd_signed_vma) ((x) ^ 0x80000000) - 0x80000000)
74     #define NEXTLONG(p) \
75     (p += 4, FETCH_DATA (info, p), \
76     (COERCE32 ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])))
77    
78     /* Get a 4 byte unsigned integer. */
79     #define NEXTULONG(p) \
80     (p += 4, FETCH_DATA (info, p), \
81     (unsigned int) ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]))
82    
83     /* Get a single precision float. */
84     #define NEXTSINGLE(val, p) \
85     (p += 4, FETCH_DATA (info, p), \
86     floatformat_to_double (&floatformat_ieee_single_big, (char *) p - 4, &val))
87    
88     /* Get a double precision float. */
89     #define NEXTDOUBLE(val, p) \
90     (p += 8, FETCH_DATA (info, p), \
91     floatformat_to_double (&floatformat_ieee_double_big, (char *) p - 8, &val))
92    
93     /* Get an extended precision float. */
94     #define NEXTEXTEND(val, p) \
95     (p += 12, FETCH_DATA (info, p), \
96     floatformat_to_double (&floatformat_m68881_ext, (char *) p - 12, &val))
97    
98     /* Need a function to convert from packed to double
99     precision. Actually, it's easier to print a
100     packed number than a double anyway, so maybe
101     there should be a special case to handle this... */
102     #define NEXTPACKED(p) \
103     (p += 12, FETCH_DATA (info, p), 0.0)
104    
105    
106     /* Maximum length of an instruction. */
107     #define MAXLEN 22
108    
109     #include <setjmp.h>
110    
111     struct private
112     {
113     /* Points to first byte not fetched. */
114     bfd_byte *max_fetched;
115     bfd_byte the_buffer[MAXLEN];
116     bfd_vma insn_start;
117     jmp_buf bailout;
118     };
119    
120     /* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
121     to ADDR (exclusive) are valid. Returns 1 for success, longjmps
122     on error. */
123     #define FETCH_DATA(info, addr) \
124     ((addr) <= ((struct private *)(info->private_data))->max_fetched \
125     ? 1 : fetch_data ((info), (addr)))
126    
127     static int
128     fetch_data (info, addr)
129     struct disassemble_info *info;
130     bfd_byte *addr;
131     {
132     int status;
133     struct private *priv = (struct private *)info->private_data;
134     bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
135    
136     status = (*info->read_memory_func) (start,
137     priv->max_fetched,
138     addr - priv->max_fetched,
139     info);
140     if (status != 0)
141     {
142     (*info->memory_error_func) (status, start, info);
143     longjmp (priv->bailout, 1);
144     }
145     else
146     priv->max_fetched = addr;
147     return 1;
148     }
149    
150     /* This function is used to print to the bit-bucket. */
151     static int
152     #ifdef __STDC__
153     dummy_printer (FILE * file, const char * format, ...)
154     #else
155     dummy_printer (file) FILE *file;
156     #endif
157     { return 0; }
158    
159     static void
160     dummy_print_address (vma, info)
161     bfd_vma vma;
162     struct disassemble_info *info;
163     {
164     }
165    
166     /* Print the m68k instruction at address MEMADDR in debugged memory,
167     on INFO->STREAM. Returns length of the instruction, in bytes. */
168    
169     int
170     print_insn_m68k (memaddr, info)
171     bfd_vma memaddr;
172     disassemble_info *info;
173     {
174     register int i;
175     register unsigned char *p;
176     unsigned char *save_p;
177     register const char *d;
178     register unsigned long bestmask;
179     const struct m68k_opcode *best = 0;
180     unsigned int arch_mask;
181     struct private priv;
182     bfd_byte *buffer = priv.the_buffer;
183     fprintf_ftype save_printer = info->fprintf_func;
184     void (*save_print_address) PARAMS((bfd_vma, struct disassemble_info*))
185     = info->print_address_func;
186     int major_opcode;
187     static int numopcodes[16];
188     static const struct m68k_opcode **opcodes[16];
189    
190     if (!opcodes[0])
191     {
192     /* Speed up the matching by sorting the opcode table on the upper
193     four bits of the opcode. */
194     const struct m68k_opcode **opc_pointer[16];
195    
196     /* First count how many opcodes are in each of the sixteen buckets. */
197     for (i = 0; i < m68k_numopcodes; i++)
198     numopcodes[(m68k_opcodes[i].opcode >> 28) & 15]++;
199    
200     /* Then create a sorted table of pointers that point into the
201     unsorted table. */
202     opc_pointer[0] = ((const struct m68k_opcode **)
203 cebix 1.2 malloc (sizeof (struct m68k_opcode *)
204 cebix 1.1 * m68k_numopcodes));
205     opcodes[0] = opc_pointer[0];
206     for (i = 1; i < 16; i++)
207     {
208     opc_pointer[i] = opc_pointer[i - 1] + numopcodes[i - 1];
209     opcodes[i] = opc_pointer[i];
210     }
211    
212     for (i = 0; i < m68k_numopcodes; i++)
213     *opc_pointer[(m68k_opcodes[i].opcode >> 28) & 15]++ = &m68k_opcodes[i];
214    
215     }
216    
217     info->private_data = (PTR) &priv;
218     /* Tell objdump to use two bytes per chunk and six bytes per line for
219     displaying raw data. */
220     info->bytes_per_chunk = 2;
221     info->bytes_per_line = 6;
222     info->display_endian = BFD_ENDIAN_BIG;
223     priv.max_fetched = priv.the_buffer;
224     priv.insn_start = memaddr;
225     if (setjmp (priv.bailout) != 0)
226     /* Error return. */
227     return -1;
228    
229     switch (info->mach)
230     {
231     default:
232     case 0:
233     arch_mask = (unsigned int) -1;
234     break;
235     case bfd_mach_m68000:
236     arch_mask = m68000;
237     break;
238     case bfd_mach_m68008:
239     arch_mask = m68008;
240     break;
241     case bfd_mach_m68010:
242     arch_mask = m68010;
243     break;
244     case bfd_mach_m68020:
245     arch_mask = m68020;
246     break;
247     case bfd_mach_m68030:
248     arch_mask = m68030;
249     break;
250     case bfd_mach_m68040:
251     arch_mask = m68040;
252     break;
253     case bfd_mach_m68060:
254     arch_mask = m68060;
255     break;
256     }
257    
258     arch_mask |= m68881 | m68851;
259    
260     bestmask = 0;
261     FETCH_DATA (info, buffer + 2);
262     major_opcode = (buffer[0] >> 4) & 15;
263     for (i = 0; i < numopcodes[major_opcode]; i++)
264     {
265     const struct m68k_opcode *opc = opcodes[major_opcode][i];
266     unsigned long opcode = opc->opcode;
267     unsigned long match = opc->match;
268    
269     if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))
270     && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))
271     /* Only fetch the next two bytes if we need to. */
272     && (((0xffff & match) == 0)
273     ||
274     (FETCH_DATA (info, buffer + 4)
275     && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))
276     && ((0xff & buffer[3] & match) == (0xff & opcode)))
277     )
278     && (opc->arch & arch_mask) != 0)
279     {
280     /* Don't use for printout the variants of divul and divsl
281     that have the same register number in two places.
282     The more general variants will match instead. */
283     for (d = opc->args; *d; d += 2)
284     if (d[1] == 'D')
285     break;
286    
287     /* Don't use for printout the variants of most floating
288     point coprocessor instructions which use the same
289     register number in two places, as above. */
290     if (*d == '\0')
291     for (d = opc->args; *d; d += 2)
292     if (d[1] == 't')
293     break;
294    
295     /* Don't match fmovel with more than one register; wait for
296     fmoveml. */
297     if (*d == '\0')
298     {
299     for (d = opc->args; *d; d += 2)
300     {
301     if (d[0] == 's' && d[1] == '8')
302     {
303     int val;
304    
305     val = fetch_arg (buffer, d[1], 3, info);
306     if ((val & (val - 1)) != 0)
307     break;
308     }
309     }
310     }
311    
312     if (*d == '\0' && match > bestmask)
313     {
314     best = opc;
315     bestmask = match;
316     }
317     }
318     }
319    
320     if (best == 0)
321     goto invalid;
322    
323     /* Point at first word of argument data,
324     and at descriptor for first argument. */
325     p = buffer + 2;
326    
327     /* Figure out how long the fixed-size portion of the instruction is.
328     The only place this is stored in the opcode table is
329     in the arguments--look for arguments which specify fields in the 2nd
330     or 3rd words of the instruction. */
331     for (d = best->args; *d; d += 2)
332     {
333     /* I don't think it is necessary to be checking d[0] here; I suspect
334     all this could be moved to the case statement below. */
335     if (d[0] == '#')
336     {
337     if (d[1] == 'l' && p - buffer < 6)
338     p = buffer + 6;
339     else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' )
340     p = buffer + 4;
341     }
342     if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4)
343     p = buffer + 4;
344     switch (d[1])
345     {
346     case '1':
347     case '2':
348     case '3':
349     case '7':
350     case '8':
351     case '9':
352     case 'i':
353     if (p - buffer < 4)
354     p = buffer + 4;
355     break;
356     case '4':
357     case '5':
358     case '6':
359     if (p - buffer < 6)
360     p = buffer + 6;
361     break;
362     default:
363     break;
364     }
365     }
366    
367     /* pflusha is an exceptions. It takes no arguments but is two words
368     long. Recognize it by looking at the lower 16 bits of the mask. */
369     if (p - buffer < 4 && (best->match & 0xFFFF) != 0)
370     p = buffer + 4;
371    
372     /* lpstop is another exception. It takes a one word argument but is
373     three words long. */
374     if (p - buffer < 6
375     && (best->match & 0xffff) == 0xffff
376     && best->args[0] == '#'
377     && best->args[1] == 'w')
378     {
379     /* Copy the one word argument into the usual location for a one
380     word argument, to simplify printing it. We can get away with
381     this because we know exactly what the second word is, and we
382     aren't going to print anything based on it. */
383     p = buffer + 6;
384     FETCH_DATA (info, p);
385     buffer[2] = buffer[4];
386     buffer[3] = buffer[5];
387     }
388    
389     FETCH_DATA (info, p);
390    
391     d = best->args;
392    
393     /* We can the operands twice. The first time we don't print anything,
394     but look for errors. */
395    
396     save_p = p;
397     info->print_address_func = dummy_print_address;
398     info->fprintf_func = (fprintf_ftype)dummy_printer;
399     for ( ; *d; d += 2)
400     {
401     int eaten = print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
402     if (eaten >= 0)
403     p += eaten;
404     else if (eaten == -1)
405     goto invalid;
406     else
407     {
408     (*info->fprintf_func)(info->stream,
409     /* xgettext:c-format */
410     _("<internal error in opcode table: %s %s>\n"),
411     best->name,
412     best->args);
413     goto invalid;
414     }
415    
416     }
417     p = save_p;
418     info->fprintf_func = save_printer;
419     info->print_address_func = save_print_address;
420    
421     d = best->args;
422    
423     (*info->fprintf_func) (info->stream, "%s", best->name);
424    
425     if (*d)
426     (*info->fprintf_func) (info->stream, "\t");
427    
428     while (*d)
429     {
430     p += print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
431     d += 2;
432     if (*d && *(d - 2) != 'I' && *d != 'k')
433     (*info->fprintf_func) (info->stream, ",");
434     }
435     return p - buffer;
436    
437     invalid: {
438 cebix 1.2 extern void print_68k_invalid_opcode(unsigned long, struct disassemble_info *);
439 cebix 1.1
440     /* Handle undefined instructions. */
441     info->fprintf_func = save_printer;
442     info->print_address_func = save_print_address;
443 cebix 1.2 print_68k_invalid_opcode((buffer[0] << 8) | buffer[1], info);
444 cebix 1.1 return 2;
445     }
446     }
447    
448     /* Returns number of bytes "eaten" by the operand, or
449     return -1 if an invalid operand was found, or -2 if
450     an opcode tabe error was found. */
451    
452     static int
453     print_insn_arg (d, buffer, p0, addr, info)
454     const char *d;
455     unsigned char *buffer;
456     unsigned char *p0;
457     bfd_vma addr; /* PC for this arg to be relative to */
458     disassemble_info *info;
459     {
460     register int val = 0;
461     register int place = d[1];
462     register unsigned char *p = p0;
463     int regno;
464     register CONST char *regname;
465     register unsigned char *p1;
466     double flval;
467     int flt_p;
468     bfd_signed_vma disp;
469     unsigned int uval;
470    
471     switch (*d)
472     {
473     case 'c': /* cache identifier */
474     {
475     static char *const cacheFieldName[] = { "nc", "dc", "ic", "bc" };
476     val = fetch_arg (buffer, place, 2, info);
477     (*info->fprintf_func) (info->stream, cacheFieldName[val]);
478     break;
479     }
480    
481     case 'a': /* address register indirect only. Cf. case '+'. */
482     {
483     (*info->fprintf_func)
484     (info->stream,
485     "(%s)",
486     reg_names [fetch_arg (buffer, place, 3, info) + 8]);
487     break;
488     }
489    
490     case '_': /* 32-bit absolute address for move16. */
491     {
492     uval = NEXTULONG (p);
493     (*info->print_address_func) (uval, info);
494     break;
495     }
496    
497     case 'C':
498     (*info->fprintf_func) (info->stream, "ccr");
499     break;
500    
501     case 'S':
502     (*info->fprintf_func) (info->stream, "sr");
503     break;
504    
505     case 'U':
506     (*info->fprintf_func) (info->stream, "usp");
507     break;
508    
509     case 'J':
510     {
511     static const struct { char *name; int value; } names[]
512     = {{"sfc", 0x000}, {"dfc", 0x001}, {"cacr", 0x002},
513     {"tc", 0x003}, {"itt0",0x004}, {"itt1", 0x005},
514     {"dtt0",0x006}, {"dtt1",0x007}, {"buscr",0x008},
515     {"usp", 0x800}, {"vbr", 0x801}, {"caar", 0x802},
516     {"msp", 0x803}, {"isp", 0x804},
517    
518     /* Should we be calling this psr like we do in case 'Y'? */
519     {"mmusr",0x805},
520    
521     {"urp", 0x806}, {"srp", 0x807}, {"pcr", 0x808}};
522    
523     val = fetch_arg (buffer, place, 12, info);
524     for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--)
525     if (names[regno].value == val)
526     {
527     (*info->fprintf_func) (info->stream, "%s", names[regno].name);
528     break;
529     }
530     if (regno < 0)
531     (*info->fprintf_func) (info->stream, "$%04x", val);
532     }
533     break;
534    
535     case 'Q':
536     val = fetch_arg (buffer, place, 3, info);
537     /* 0 means 8, except for the bkpt instruction... */
538     if (val == 0 && d[1] != 's')
539     val = 8;
540     (*info->fprintf_func) (info->stream, "#%d", val);
541     break;
542    
543     case 'M':
544     val = fetch_arg (buffer, place, 8, info);
545     if (val & 0x80)
546     val = val - 0x100;
547     (*info->fprintf_func) (info->stream, "#$%02x", val);
548     break;
549    
550     case 'T':
551     val = fetch_arg (buffer, place, 4, info);
552     (*info->fprintf_func) (info->stream, "#$%08x", val);
553     break;
554    
555     case 'D':
556     (*info->fprintf_func) (info->stream, "%s",
557     reg_names[fetch_arg (buffer, place, 3, info)]);
558     break;
559    
560     case 'A':
561     (*info->fprintf_func)
562     (info->stream, "%s",
563     reg_names[fetch_arg (buffer, place, 3, info) + 010]);
564     break;
565    
566     case 'R':
567     (*info->fprintf_func)
568     (info->stream, "%s",
569     reg_names[fetch_arg (buffer, place, 4, info)]);
570     break;
571    
572     case 'r':
573     regno = fetch_arg (buffer, place, 4, info);
574     (*info->fprintf_func) (info->stream, "(%s)", reg_names[regno]);
575     break;
576    
577     case 'F':
578     (*info->fprintf_func)
579     (info->stream, "fp%d",
580     fetch_arg (buffer, place, 3, info));
581     break;
582    
583     case 'O':
584     val = fetch_arg (buffer, place, 6, info);
585     if (val & 0x20)
586     (*info->fprintf_func) (info->stream, "%s", reg_names [val & 7]);
587     else
588     (*info->fprintf_func) (info->stream, "%d", val);
589     break;
590    
591     case '+':
592     (*info->fprintf_func)
593     (info->stream, "(%s)+",
594     reg_names[fetch_arg (buffer, place, 3, info) + 8]);
595     break;
596    
597     case '-':
598     (*info->fprintf_func)
599     (info->stream, "-(%s)",
600     reg_names[fetch_arg (buffer, place, 3, info) + 8]);
601     break;
602    
603     case 'k':
604     if (place == 'k')
605     (*info->fprintf_func)
606     (info->stream, "{%s}",
607     reg_names[fetch_arg (buffer, place, 3, info)]);
608     else if (place == 'C')
609     {
610     val = fetch_arg (buffer, place, 7, info);
611     if ( val > 63 ) /* This is a signed constant. */
612     val -= 128;
613     (*info->fprintf_func) (info->stream, "{#%d}", val);
614     }
615     else
616     return -2;
617     break;
618    
619     case '#':
620     case '^':
621     p1 = buffer + (*d == '#' ? 2 : 4);
622     if (place == 's')
623     val = fetch_arg (buffer, place, 4, info);
624     else if (place == 'C')
625     val = fetch_arg (buffer, place, 7, info);
626     else if (place == '8')
627     val = fetch_arg (buffer, place, 3, info);
628     else if (place == '3')
629     val = fetch_arg (buffer, place, 8, info);
630     else if (place == 'b') {
631     val = NEXTBYTE (p1);
632     (*info->fprintf_func) (info->stream, "#$%02x", val & 0xff);
633     break;
634     }
635     else if (place == 'w' || place == 'W') {
636     val = NEXTWORD (p1);
637     (*info->fprintf_func) (info->stream, "#$%04x", val & 0xffff);
638     break;
639     }
640     else if (place == 'l') {
641     val = NEXTLONG (p1);
642     (*info->fprintf_func) (info->stream, "#$%08x", val);
643     break;
644     }
645     else
646     return -2;
647     (*info->fprintf_func) (info->stream, "#%d", val);
648     break;
649    
650     case 'B':
651     if (place == 'b')
652     disp = NEXTBYTE (p);
653     else if (place == 'B')
654     disp = COERCE_SIGNED_CHAR(buffer[1]);
655     else if (place == 'w' || place == 'W')
656     disp = NEXTWORD (p);
657     else if (place == 'l' || place == 'L' || place == 'C')
658     disp = NEXTLONG (p);
659     else if (place == 'g')
660     {
661     disp = NEXTBYTE (buffer);
662     if (disp == 0)
663     disp = NEXTWORD (p);
664     else if (disp == -1)
665     disp = NEXTLONG (p);
666     }
667     else if (place == 'c')
668     {
669     if (buffer[1] & 0x40) /* If bit six is one, long offset */
670     disp = NEXTLONG (p);
671     else
672     disp = NEXTWORD (p);
673     }
674     else
675     return -2;
676    
677 cebix 1.2 #if 1
678 gbeauche 1.4 /* FIXME: We are bound to have 32-bit addresses even if cxmon is
679     requested to run in real mode, because m68k is 32-bit. */
680     (*info->fprintf_func) (info->stream, "$%08x", (uint32)(addr + disp));
681 cebix 1.2 #else
682 cebix 1.1 (*info->print_address_func) (addr + disp, info);
683 cebix 1.2 #endif
684 cebix 1.1 break;
685    
686     case 'd':
687     val = NEXTWORD (p);
688     (*info->fprintf_func)
689     (info->stream, "($%04x,%s)",
690     val, reg_names[fetch_arg (buffer, place, 3, info) + 8]);
691     break;
692    
693     case 's':
694     (*info->fprintf_func) (info->stream, "%s",
695     fpcr_names[fetch_arg (buffer, place, 3, info)]);
696     break;
697    
698     case 'I':
699     /* Get coprocessor ID... */
700     val = fetch_arg (buffer, 'd', 3, info);
701    
702     if (val != 1) /* Unusual coprocessor ID? */
703     (*info->fprintf_func) (info->stream, "(cpid=%d) ", val);
704     break;
705    
706     case '*':
707     case '~':
708     case '%':
709     case ';':
710     case '@':
711     case '!':
712     case '$':
713     case '?':
714     case '/':
715     case '&':
716     case '|':
717     case '<':
718     case '>':
719     case 'm':
720     case 'n':
721     case 'o':
722     case 'p':
723     case 'q':
724     case 'v':
725    
726     if (place == 'd')
727     {
728     val = fetch_arg (buffer, 'x', 6, info);
729     val = ((val & 7) << 3) + ((val >> 3) & 7);
730     }
731     else
732     val = fetch_arg (buffer, 's', 6, info);
733    
734     /* Get register number assuming address register. */
735     regno = (val & 7) + 8;
736     regname = reg_names[regno];
737     switch (val >> 3)
738     {
739     case 0:
740     (*info->fprintf_func) (info->stream, "%s", reg_names[val]);
741     break;
742    
743     case 1:
744     (*info->fprintf_func) (info->stream, "%s", regname);
745     break;
746    
747     case 2:
748     (*info->fprintf_func) (info->stream, "(%s)", regname);
749     break;
750    
751     case 3:
752     (*info->fprintf_func) (info->stream, "(%s)+", regname);
753     break;
754    
755     case 4:
756     (*info->fprintf_func) (info->stream, "-(%s)", regname);
757     break;
758    
759     case 5:
760     val = NEXTWORD (p);
761     (*info->fprintf_func) (info->stream, "($%04x,%s)", val, regname);
762     break;
763    
764     case 6:
765     p = print_indexed (regno, p, addr, info);
766     break;
767    
768     case 7:
769     switch (val & 7)
770     {
771     case 0:
772     val = NEXTWORD (p);
773     (*info->print_address_func) (val, info);
774     break;
775    
776     case 1:
777     uval = NEXTULONG (p);
778     (*info->print_address_func) (uval, info);
779     break;
780    
781     case 2:
782     val = NEXTWORD (p);
783 cebix 1.2 (*info->fprintf_func) (info->stream, "($%08x,pc)", addr + val);
784 cebix 1.1 break;
785    
786     case 3:
787     p = print_indexed (-1, p, addr, info);
788     break;
789    
790     case 4:
791     switch( place )
792     {
793     case 'b':
794     val = NEXTBYTE (p);
795     (*info->fprintf_func) (info->stream, "#$%02x", val & 0xff);
796     goto imm_printed;
797    
798     case 'w':
799     val = NEXTWORD (p);
800     (*info->fprintf_func) (info->stream, "#$%04x", val & 0xffff);
801     goto imm_printed;
802    
803     case 'l':
804     val = NEXTLONG (p);
805     (*info->fprintf_func) (info->stream, "#$%08x", val);
806     goto imm_printed;
807    
808     case 'f':
809     NEXTSINGLE(flval, p);
810     break;
811    
812     case 'F':
813     NEXTDOUBLE(flval, p);
814     break;
815    
816     case 'x':
817     NEXTEXTEND(flval, p);
818     break;
819    
820     case 'p':
821     flval = NEXTPACKED(p);
822     break;
823    
824     default:
825     return -1;
826     }
827     (*info->fprintf_func) (info->stream, "#%g", flval);
828     imm_printed:
829     break;
830    
831     default:
832     return -1;
833     }
834     }
835     break;
836    
837     case 'L':
838     case 'l':
839     if (place == 'w')
840     {
841     char doneany;
842     p1 = buffer + 2;
843     val = NEXTWORD (p1);
844     /* Move the pointer ahead if this point is farther ahead
845     than the last. */
846     p = p1 > p ? p1 : p;
847     if (val == 0)
848     {
849     (*info->fprintf_func) (info->stream, "#0");
850     break;
851     }
852     if (*d == 'l')
853     {
854     register int newval = 0;
855     for (regno = 0; regno < 16; ++regno)
856     if (val & (0x8000 >> regno))
857     newval |= 1 << regno;
858     val = newval;
859     }
860     val &= 0xffff;
861     doneany = 0;
862     for (regno = 0; regno < 16; ++regno)
863     if (val & (1 << regno))
864     {
865     int first_regno;
866     if (doneany)
867     (*info->fprintf_func) (info->stream, "/");
868     doneany = 1;
869     (*info->fprintf_func) (info->stream, "%s", reg_names[regno]);
870     first_regno = regno;
871     while (val & (1 << (regno + 1)))
872     ++regno;
873     if (regno > first_regno)
874     (*info->fprintf_func) (info->stream, "-%s",
875     reg_names[regno]);
876     }
877     }
878     else if (place == '3')
879     {
880     /* `fmovem' insn. */
881     char doneany;
882     val = fetch_arg (buffer, place, 8, info);
883     if (val == 0)
884     {
885     (*info->fprintf_func) (info->stream, "#0");
886     break;
887     }
888     if (*d == 'l')
889     {
890     register int newval = 0;
891     for (regno = 0; regno < 8; ++regno)
892     if (val & (0x80 >> regno))
893     newval |= 1 << regno;
894     val = newval;
895     }
896     val &= 0xff;
897     doneany = 0;
898     for (regno = 0; regno < 8; ++regno)
899     if (val & (1 << regno))
900     {
901     int first_regno;
902     if (doneany)
903     (*info->fprintf_func) (info->stream, "/");
904     doneany = 1;
905     (*info->fprintf_func) (info->stream, "fp%d", regno);
906     first_regno = regno;
907     while (val & (1 << (regno + 1)))
908     ++regno;
909     if (regno > first_regno)
910     (*info->fprintf_func) (info->stream, "-fp%d", regno);
911     }
912     }
913     else if (place == '8')
914     {
915     /* fmoveml for FP status registers */
916     (*info->fprintf_func) (info->stream, "%s",
917     fpcr_names[fetch_arg (buffer, place, 3,
918     info)]);
919     }
920     else
921     return -2;
922     break;
923    
924     case 'X':
925     place = '8';
926     case 'Y':
927     case 'Z':
928     case 'W':
929     case '0':
930     case '1':
931     case '2':
932     case '3':
933     {
934     int val = fetch_arg (buffer, place, 5, info);
935     char *name = 0;
936     switch (val)
937     {
938     case 2: name = "tt0"; break;
939     case 3: name = "tt1"; break;
940     case 0x10: name = "tc"; break;
941     case 0x11: name = "drp"; break;
942     case 0x12: name = "srp"; break;
943     case 0x13: name = "crp"; break;
944     case 0x14: name = "cal"; break;
945     case 0x15: name = "val"; break;
946     case 0x16: name = "scc"; break;
947     case 0x17: name = "ac"; break;
948     case 0x18: name = "psr"; break;
949     case 0x19: name = "pcsr"; break;
950     case 0x1c:
951     case 0x1d:
952     {
953     int break_reg = ((buffer[3] >> 2) & 7);
954     (*info->fprintf_func)
955     (info->stream, val == 0x1c ? "bad%d" : "bac%d",
956     break_reg);
957     }
958     break;
959     default:
960     (*info->fprintf_func) (info->stream, "<mmu register %d>", val);
961     }
962     if (name)
963     (*info->fprintf_func) (info->stream, "%s", name);
964     }
965     break;
966    
967     case 'f':
968     {
969     int fc = fetch_arg (buffer, place, 5, info);
970     if (fc == 1)
971     (*info->fprintf_func) (info->stream, "dfc");
972     else if (fc == 0)
973     (*info->fprintf_func) (info->stream, "sfc");
974     else
975     /* xgettext:c-format */
976     (*info->fprintf_func) (info->stream, _("<function code %d>"), fc);
977     }
978     break;
979    
980     case 'V':
981     (*info->fprintf_func) (info->stream, "val");
982     break;
983    
984     case 't':
985     {
986     int level = fetch_arg (buffer, place, 3, info);
987     (*info->fprintf_func) (info->stream, "%d", level);
988     }
989     break;
990    
991     default:
992     return -2;
993     }
994    
995     return p - p0;
996     }
997    
998     /* Fetch BITS bits from a position in the instruction specified by CODE.
999     CODE is a "place to put an argument", or 'x' for a destination
1000     that is a general address (mode and register).
1001     BUFFER contains the instruction. */
1002    
1003     static int
1004     fetch_arg (buffer, code, bits, info)
1005     unsigned char *buffer;
1006     int code;
1007     int bits;
1008     disassemble_info *info;
1009     {
1010     register int val = 0;
1011     switch (code)
1012     {
1013     case 's':
1014     val = buffer[1];
1015     break;
1016    
1017     case 'd': /* Destination, for register or quick. */
1018     val = (buffer[0] << 8) + buffer[1];
1019     val >>= 9;
1020     break;
1021    
1022     case 'x': /* Destination, for general arg */
1023     val = (buffer[0] << 8) + buffer[1];
1024     val >>= 6;
1025     break;
1026    
1027     case 'k':
1028     FETCH_DATA (info, buffer + 3);
1029     val = (buffer[3] >> 4);
1030     break;
1031    
1032     case 'C':
1033     FETCH_DATA (info, buffer + 3);
1034     val = buffer[3];
1035     break;
1036    
1037     case '1':
1038     FETCH_DATA (info, buffer + 3);
1039     val = (buffer[2] << 8) + buffer[3];
1040     val >>= 12;
1041     break;
1042    
1043     case '2':
1044     FETCH_DATA (info, buffer + 3);
1045     val = (buffer[2] << 8) + buffer[3];
1046     val >>= 6;
1047     break;
1048    
1049     case '3':
1050     case 'j':
1051     FETCH_DATA (info, buffer + 3);
1052     val = (buffer[2] << 8) + buffer[3];
1053     break;
1054    
1055     case '4':
1056     FETCH_DATA (info, buffer + 5);
1057     val = (buffer[4] << 8) + buffer[5];
1058     val >>= 12;
1059     break;
1060    
1061     case '5':
1062     FETCH_DATA (info, buffer + 5);
1063     val = (buffer[4] << 8) + buffer[5];
1064     val >>= 6;
1065     break;
1066    
1067     case '6':
1068     FETCH_DATA (info, buffer + 5);
1069     val = (buffer[4] << 8) + buffer[5];
1070     break;
1071    
1072     case '7':
1073     FETCH_DATA (info, buffer + 3);
1074     val = (buffer[2] << 8) + buffer[3];
1075     val >>= 7;
1076     break;
1077    
1078     case '8':
1079     FETCH_DATA (info, buffer + 3);
1080     val = (buffer[2] << 8) + buffer[3];
1081     val >>= 10;
1082     break;
1083    
1084     case '9':
1085     FETCH_DATA (info, buffer + 3);
1086     val = (buffer[2] << 8) + buffer[3];
1087     val >>= 5;
1088     break;
1089    
1090     case 'e':
1091     val = (buffer[1] >> 6);
1092     break;
1093    
1094     default:
1095     abort ();
1096     }
1097    
1098     switch (bits)
1099     {
1100     case 2:
1101     return val & 3;
1102     case 3:
1103     return val & 7;
1104     case 4:
1105     return val & 017;
1106     case 5:
1107     return val & 037;
1108     case 6:
1109     return val & 077;
1110     case 7:
1111     return val & 0177;
1112     case 8:
1113     return val & 0377;
1114     case 12:
1115     return val & 07777;
1116     default:
1117     abort ();
1118     }
1119     }
1120    
1121     /* Print an indexed argument. The base register is BASEREG (-1 for pc).
1122     P points to extension word, in buffer.
1123     ADDR is the nominal core address of that extension word. */
1124    
1125     static unsigned char *
1126     print_indexed (basereg, p, addr, info)
1127     int basereg;
1128     unsigned char *p;
1129     bfd_vma addr;
1130     disassemble_info *info;
1131     {
1132     register int word;
1133     static char *const scales[] = {"", "*2", "*4", "*8"};
1134     bfd_vma base_disp;
1135     bfd_vma outer_disp;
1136     char buf[40];
1137     char vmabuf[50];
1138    
1139     word = NEXTWORD (p);
1140    
1141     /* Generate the text for the index register.
1142     Where this will be output is not yet determined. */
1143     sprintf (buf, "%s.%c%s",
1144     reg_names[(word >> 12) & 0xf],
1145     (word & 0x800) ? 'l' : 'w',
1146     scales[(word >> 9) & 3]);
1147    
1148     /* Handle the 68000 style of indexing. */
1149    
1150     if ((word & 0x100) == 0)
1151     {
1152     base_disp = word & 0xff;
1153     if ((base_disp & 0x80) != 0)
1154     base_disp -= 0x100;
1155     if (basereg == -1)
1156     base_disp += addr;
1157     (*info->fprintf_func) (info->stream, "(", buf);
1158     print_base (basereg, base_disp, info);
1159     (*info->fprintf_func) (info->stream, ",%s)", buf);
1160     return p;
1161     }
1162    
1163     /* Handle the generalized kind. */
1164     /* First, compute the displacement to add to the base register. */
1165    
1166     if (word & 0200)
1167     {
1168     if (basereg == -1)
1169     basereg = -3;
1170     else
1171     basereg = -2;
1172     }
1173     if (word & 0100)
1174     buf[0] = '\0';
1175     base_disp = 0;
1176     switch ((word >> 4) & 3)
1177     {
1178     case 2:
1179     base_disp = NEXTWORD (p);
1180     break;
1181     case 3:
1182     base_disp = NEXTLONG (p);
1183     }
1184     if (basereg == -1)
1185     base_disp += addr;
1186    
1187     /* Handle single-level case (not indirect) */
1188    
1189     if ((word & 7) == 0)
1190     {
1191     (*info->fprintf_func) (info->stream, "(");
1192     print_base (basereg, base_disp, info);
1193     if (buf[0] != '\0')
1194     (*info->fprintf_func) (info->stream, ",%s", buf);
1195     (*info->fprintf_func) (info->stream, ")");
1196     return p;
1197     }
1198    
1199     /* Two level. Compute displacement to add after indirection. */
1200    
1201     outer_disp = 0;
1202     switch (word & 3)
1203     {
1204     case 2:
1205     outer_disp = NEXTWORD (p);
1206     break;
1207     case 3:
1208     outer_disp = NEXTLONG (p);
1209     }
1210    
1211     (*info->fprintf_func) (info->stream, "([");
1212     print_base (basereg, base_disp, info);
1213     if ((word & 4) == 0 && buf[0] != '\0')
1214     {
1215     (*info->fprintf_func) (info->stream, ",%s", buf);
1216     buf[0] = '\0';
1217     }
1218     if (outer_disp)
1219     (*info->fprintf_func) (info->stream, "],$%08x", outer_disp);
1220     else
1221     (*info->fprintf_func) (info->stream, "]", outer_disp);
1222     if (buf[0] != '\0')
1223     (*info->fprintf_func) (info->stream, ",%s", buf);
1224     (*info->fprintf_func) (info->stream, ")");
1225    
1226     return p;
1227     }
1228    
1229     /* Print a base register REGNO and displacement DISP, on INFO->STREAM.
1230     REGNO = -1 for pc, -2 for none (suppressed). */
1231    
1232     static void
1233     print_base (regno, disp, info)
1234     int regno;
1235     bfd_vma disp;
1236     disassemble_info *info;
1237     {
1238 cebix 1.2 if (regno == -1)
1239     (*info->fprintf_func) (info->stream, "$%08x,pc", disp);
1240     else {
1241     if (regno == -3)
1242     (*info->fprintf_func) (info->stream, "$%08x,zpc", disp);
1243     else if (regno == -2)
1244     (*info->print_address_func) (disp, info);
1245     else
1246     (*info->fprintf_func) (info->stream, "$%08x,%s", disp, reg_names[regno]);
1247     }
1248 cebix 1.1 }