source: trunk/src/binutils/opcodes/mips-dis.c@ 10

Last change on this file since 10 was 10, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 28.0 KB
Line 
1/* Print mips instructions for GDB, the GNU debugger, or for objdump.
2 Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
3 2000, 2001
4 Free Software Foundation, Inc.
5 Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp).
6
7This file is part of GDB, GAS, and the GNU binutils.
8
9This program is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation; either version 2 of the License, or
12(at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
22
23#include "sysdep.h"
24#include "dis-asm.h"
25#include "opcode/mips.h"
26#include "opintl.h"
27
28/* FIXME: These are needed to figure out if the code is mips16 or
29 not. The low bit of the address is often a good indicator. No
30 symbol table is available when this code runs out in an embedded
31 system as when it is used for disassembler support in a monitor. */
32
33#if !defined(EMBEDDED_ENV)
34#define SYMTAB_AVAILABLE 1
35#include "elf-bfd.h"
36#include "elf/mips.h"
37#endif
38
39/* Mips instructions are at maximum this many bytes long. */
40#define INSNLEN 4
41
42static int _print_insn_mips
43 PARAMS ((bfd_vma, struct disassemble_info *, enum bfd_endian));
44static int print_insn_mips
45 PARAMS ((bfd_vma, unsigned long int, struct disassemble_info *));
46static void print_insn_arg
47 PARAMS ((const char *, unsigned long, bfd_vma, struct disassemble_info *));
48static int print_insn_mips16
49 PARAMS ((bfd_vma, struct disassemble_info *));
50static void print_mips16_insn_arg
51 PARAMS ((int, const struct mips_opcode *, int, boolean, int, bfd_vma,
52 struct disassemble_info *));
53
54
55/* FIXME: These should be shared with gdb somehow. */
56
57/* The mips16 register names. */
58static const char * const mips16_reg_names[] =
59{
60 "s0", "s1", "v0", "v1", "a0", "a1", "a2", "a3"
61};
62
63static const char * const mips32_reg_names[] =
64{
65 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
66 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
67 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
68 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
69 "sr", "lo", "hi", "bad", "cause", "pc",
70 "fv0", "$f1", "fv1", "$f3", "ft0", "$f5", "ft1", "$f7",
71 "ft2", "$f9", "ft3", "$f11", "fa0", "$f13", "fa1", "$f15",
72 "ft4", "f17", "ft5", "f19", "fs0", "f21", "fs1", "f23",
73 "fs2", "$f25", "fs3", "$f27", "fs4", "$f29", "fs5", "$f31",
74 "fsr", "fir", "fp", "inx", "rand", "tlblo", "ctxt", "tlbhi",
75 "epc", "prid"
76};
77
78static const char * const mips64_reg_names[] =
79{
80 "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
81 "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
82 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
83 "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra",
84 "sr", "lo", "hi", "bad", "cause", "pc",
85 "fv0", "$f1", "fv1", "$f3", "ft0", "ft1", "ft2", "ft3",
86 "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3",
87 "fa4", "fa5", "fa6", "fa7", "ft8", "ft9", "ft10", "ft11",
88 "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7",
89 "fsr", "fir", "fp", "inx", "rand", "tlblo", "ctxt", "tlbhi",
90 "epc", "prid"
91};
92
93/* Scalar register names. _print_insn_mips() decides which register name
94 table to use. */
95static const char * const *reg_names = NULL;
96
97
98/* Print insn arguments for 32/64-bit code */
99
100static void
101print_insn_arg (d, l, pc, info)
102 const char *d;
103 register unsigned long int l;
104 bfd_vma pc;
105 struct disassemble_info *info;
106{
107 int delta;
108
109 switch (*d)
110 {
111 case ',':
112 case '(':
113 case ')':
114 (*info->fprintf_func) (info->stream, "%c", *d);
115 break;
116
117 case 's':
118 case 'b':
119 case 'r':
120 case 'v':
121 (*info->fprintf_func) (info->stream, "%s",
122 reg_names[(l >> OP_SH_RS) & OP_MASK_RS]);
123 break;
124
125 case 't':
126 case 'w':
127 (*info->fprintf_func) (info->stream, "%s",
128 reg_names[(l >> OP_SH_RT) & OP_MASK_RT]);
129 break;
130
131 case 'i':
132 case 'u':
133 (*info->fprintf_func) (info->stream, "0x%x",
134 (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE);
135 break;
136
137 case 'j': /* same as i, but sign-extended */
138 case 'o':
139 delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
140 if (delta & 0x8000)
141 delta |= ~0xffff;
142 (*info->fprintf_func) (info->stream, "%d",
143 delta);
144 break;
145
146 case 'h':
147 (*info->fprintf_func) (info->stream, "0x%x",
148 (unsigned int) ((l >> OP_SH_PREFX)
149 & OP_MASK_PREFX));
150 break;
151
152 case 'k':
153 (*info->fprintf_func) (info->stream, "0x%x",
154 (unsigned int) ((l >> OP_SH_CACHE)
155 & OP_MASK_CACHE));
156 break;
157
158 case 'a':
159 (*info->print_address_func)
160 ((((pc + 4) & ~ (bfd_vma) 0x0fffffff)
161 | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2)),
162 info);
163 break;
164
165 case 'p':
166 /* sign extend the displacement */
167 delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
168 if (delta & 0x8000)
169 delta |= ~0xffff;
170 (*info->print_address_func)
171 ((delta << 2) + pc + INSNLEN,
172 info);
173 break;
174
175 case 'd':
176 (*info->fprintf_func) (info->stream, "%s",
177 reg_names[(l >> OP_SH_RD) & OP_MASK_RD]);
178 break;
179
180 case 'U':
181 {
182 /* First check for both rd and rt being equal. */
183 unsigned int reg = (l >> OP_SH_RD) & OP_MASK_RD;
184 if (reg == ((l >> OP_SH_RT) & OP_MASK_RT))
185 (*info->fprintf_func) (info->stream, "%s",
186 reg_names[reg]);
187 else
188 {
189 /* If one is zero use the other. */
190 if (reg == 0)
191 (*info->fprintf_func) (info->stream, "%s",
192 reg_names[(l >> OP_SH_RT) & OP_MASK_RT]);
193 else if (((l >> OP_SH_RT) & OP_MASK_RT) == 0)
194 (*info->fprintf_func) (info->stream, "%s",
195 reg_names[reg]);
196 else /* Bogus, result depends on processor. */
197 (*info->fprintf_func) (info->stream, "%s or %s",
198 reg_names[reg],
199 reg_names[(l >> OP_SH_RT) & OP_MASK_RT]);
200 }
201 }
202 break;
203
204 case 'z':
205 (*info->fprintf_func) (info->stream, "%s", reg_names[0]);
206 break;
207
208 case '<':
209 (*info->fprintf_func) (info->stream, "0x%x",
210 (l >> OP_SH_SHAMT) & OP_MASK_SHAMT);
211 break;
212
213 case 'c':
214 (*info->fprintf_func) (info->stream, "0x%x",
215 (l >> OP_SH_CODE) & OP_MASK_CODE);
216 break;
217
218 case 'q':
219 (*info->fprintf_func) (info->stream, "0x%x",
220 (l >> OP_SH_CODE2) & OP_MASK_CODE2);
221 break;
222
223 case 'C':
224 (*info->fprintf_func) (info->stream, "0x%x",
225 (l >> OP_SH_COPZ) & OP_MASK_COPZ);
226 break;
227
228 case 'B':
229 (*info->fprintf_func) (info->stream, "0x%x",
230 (l >> OP_SH_CODE20) & OP_MASK_CODE20);
231 break;
232
233 case 'J':
234 (*info->fprintf_func) (info->stream, "0x%x",
235 (l >> OP_SH_CODE19) & OP_MASK_CODE19);
236 break;
237
238 case 'S':
239 case 'V':
240 (*info->fprintf_func) (info->stream, "$f%d",
241 (l >> OP_SH_FS) & OP_MASK_FS);
242 break;
243
244 case 'T':
245 case 'W':
246 (*info->fprintf_func) (info->stream, "$f%d",
247 (l >> OP_SH_FT) & OP_MASK_FT);
248 break;
249
250 case 'D':
251 (*info->fprintf_func) (info->stream, "$f%d",
252 (l >> OP_SH_FD) & OP_MASK_FD);
253 break;
254
255 case 'R':
256 (*info->fprintf_func) (info->stream, "$f%d",
257 (l >> OP_SH_FR) & OP_MASK_FR);
258 break;
259
260 case 'E':
261 (*info->fprintf_func) (info->stream, "%s",
262 reg_names[(l >> OP_SH_RT) & OP_MASK_RT]);
263 break;
264
265 case 'G':
266 (*info->fprintf_func) (info->stream, "%s",
267 reg_names[(l >> OP_SH_RD) & OP_MASK_RD]);
268 break;
269
270 case 'N':
271 (*info->fprintf_func) (info->stream, "$fcc%d",
272 (l >> OP_SH_BCC) & OP_MASK_BCC);
273 break;
274
275 case 'M':
276 (*info->fprintf_func) (info->stream, "$fcc%d",
277 (l >> OP_SH_CCC) & OP_MASK_CCC);
278 break;
279
280 case 'P':
281 (*info->fprintf_func) (info->stream, "%d",
282 (l >> OP_SH_PERFREG) & OP_MASK_PERFREG);
283 break;
284
285 case 'H':
286 (*info->fprintf_func) (info->stream, "%d",
287 (l >> OP_SH_SEL) & OP_MASK_SEL);
288 break;
289
290 default:
291 /* xgettext:c-format */
292 (*info->fprintf_func) (info->stream,
293 _("# internal error, undefined modifier(%c)"),
294 *d);
295 break;
296 }
297}
298
299
300/* Figure out the MIPS ISA and CPU based on the machine number. */
301
302static void
303mips_isa_type (mach, isa, cputype)
304 int mach;
305 int *isa;
306 int *cputype;
307{
308 switch (mach)
309 {
310 case bfd_mach_mips3000:
311 *cputype = CPU_R3000;
312 *isa = ISA_MIPS1;
313 break;
314 case bfd_mach_mips3900:
315 *cputype = CPU_R3900;
316 *isa = ISA_MIPS1;
317 break;
318 case bfd_mach_mips4000:
319 *cputype = CPU_R4000;
320 *isa = ISA_MIPS3;
321 break;
322 case bfd_mach_mips4010:
323 *cputype = CPU_R4010;
324 *isa = ISA_MIPS2;
325 break;
326 case bfd_mach_mips4100:
327 *cputype = CPU_VR4100;
328 *isa = ISA_MIPS3;
329 break;
330 case bfd_mach_mips4111:
331 *cputype = CPU_R4111;
332 *isa = ISA_MIPS3;
333 break;
334 case bfd_mach_mips4300:
335 *cputype = CPU_R4300;
336 *isa = ISA_MIPS3;
337 break;
338 case bfd_mach_mips4400:
339 *cputype = CPU_R4400;
340 *isa = ISA_MIPS3;
341 break;
342 case bfd_mach_mips4600:
343 *cputype = CPU_R4600;
344 *isa = ISA_MIPS3;
345 break;
346 case bfd_mach_mips4650:
347 *cputype = CPU_R4650;
348 *isa = ISA_MIPS3;
349 break;
350 case bfd_mach_mips5000:
351 *cputype = CPU_R5000;
352 *isa = ISA_MIPS4;
353 break;
354 case bfd_mach_mips6000:
355 *cputype = CPU_R6000;
356 *isa = ISA_MIPS2;
357 break;
358 case bfd_mach_mips8000:
359 *cputype = CPU_R8000;
360 *isa = ISA_MIPS4;
361 break;
362 case bfd_mach_mips10000:
363 *cputype = CPU_R10000;
364 *isa = ISA_MIPS4;
365 break;
366 case bfd_mach_mips12000:
367 *cputype = CPU_R12000;
368 *isa = ISA_MIPS4;
369 break;
370 case bfd_mach_mips16:
371 *cputype = CPU_MIPS16;
372 *isa = ISA_MIPS3;
373 break;
374 case bfd_mach_mips32:
375 *cputype = CPU_MIPS32;
376 *isa = ISA_MIPS32;
377 break;
378 case bfd_mach_mips32_4k:
379 *cputype = CPU_MIPS32_4K;
380 *isa = ISA_MIPS32;
381 break;
382 case bfd_mach_mips5:
383 *cputype = CPU_MIPS5;
384 *isa = ISA_MIPS5;
385 break;
386 case bfd_mach_mips64:
387 *cputype = CPU_MIPS64;
388 *isa = ISA_MIPS64;
389 break;
390 case bfd_mach_mips_sb1:
391 *cputype = CPU_SB1;
392 *isa = ISA_MIPS64;
393 break;
394 default:
395 *cputype = CPU_R3000;
396 *isa = ISA_MIPS3;
397 break;
398 }
399}
400
401/* Figure out ISA from disassemble_info data */
402
403static int
404get_mips_isa (info)
405 struct disassemble_info *info;
406{
407 int isa;
408 int cpu;
409
410 mips_isa_type (info->mach, &isa, &cpu);
411 return isa;
412}
413
414
415/* Print the mips instruction at address MEMADDR in debugged memory,
416 on using INFO. Returns length of the instruction, in bytes, which is
417 always INSNLEN. BIGENDIAN must be 1 if this is big-endian code, 0 if
418 this is little-endian code. */
419
420static int
421print_insn_mips (memaddr, word, info)
422 bfd_vma memaddr;
423 unsigned long int word;
424 struct disassemble_info *info;
425{
426 register const struct mips_opcode *op;
427 int target_processor, mips_isa;
428 static boolean init = 0;
429 static const struct mips_opcode *mips_hash[OP_MASK_OP + 1];
430
431 /* Build a hash table to shorten the search time. */
432 if (! init)
433 {
434 unsigned int i;
435
436 for (i = 0; i <= OP_MASK_OP; i++)
437 {
438 for (op = mips_opcodes; op < &mips_opcodes[NUMOPCODES]; op++)
439 {
440 if (op->pinfo == INSN_MACRO)
441 continue;
442 if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP))
443 {
444 mips_hash[i] = op;
445 break;
446 }
447 }
448 }
449
450 init = 1;
451 }
452
453#if ! SYMTAB_AVAILABLE
454 /* This is running out on a target machine, not in a host tool.
455 FIXME: Where does mips_target_info come from? */
456 target_processor = mips_target_info.processor;
457 mips_isa = mips_target_info.isa;
458#else
459 mips_isa_type (info->mach, &mips_isa, &target_processor);
460#endif
461
462 info->bytes_per_chunk = INSNLEN;
463 info->display_endian = info->endian;
464
465 op = mips_hash[(word >> OP_SH_OP) & OP_MASK_OP];
466 if (op != NULL)
467 {
468 for (; op < &mips_opcodes[NUMOPCODES]; op++)
469 {
470 if (op->pinfo != INSN_MACRO && (word & op->mask) == op->match)
471 {
472 register const char *d;
473
474 if (! OPCODE_IS_MEMBER (op, mips_isa, target_processor, 0))
475 continue;
476
477 (*info->fprintf_func) (info->stream, "%s", op->name);
478
479 d = op->args;
480 if (d != NULL && *d != '\0')
481 {
482 (*info->fprintf_func) (info->stream, "\t");
483 for (; *d != '\0'; d++)
484 print_insn_arg (d, word, memaddr, info);
485 }
486
487 return INSNLEN;
488 }
489 }
490 }
491
492 /* Handle undefined instructions. */
493 (*info->fprintf_func) (info->stream, "0x%x", word);
494 return INSNLEN;
495}
496
497
498/* In an environment where we do not know the symbol type of the
499 instruction we are forced to assume that the low order bit of the
500 instructions' address may mark it as a mips16 instruction. If we
501 are single stepping, or the pc is within the disassembled function,
502 this works. Otherwise, we need a clue. Sometimes. */
503
504static int
505_print_insn_mips (memaddr, info, endianness)
506 bfd_vma memaddr;
507 struct disassemble_info *info;
508 enum bfd_endian endianness;
509{
510 bfd_byte buffer[INSNLEN];
511 int status;
512
513#if 1
514 /* FIXME: If odd address, this is CLEARLY a mips 16 instruction. */
515 /* Only a few tools will work this way. */
516 if (memaddr & 0x01)
517 return print_insn_mips16 (memaddr, info);
518#endif
519
520#if SYMTAB_AVAILABLE
521 if (info->mach == 16
522 || (info->flavour == bfd_target_elf_flavour
523 && info->symbols != NULL
524 && ((*(elf_symbol_type **) info->symbols)->internal_elf_sym.st_other
525 == STO_MIPS16)))
526 return print_insn_mips16 (memaddr, info);
527#endif
528
529 /* Use mips64_reg_names for new ABI. */
530 if (info->flavour == bfd_target_elf_flavour
531 && info->symbols != NULL
532 && (((get_mips_isa(info) | INSN_ISA_MASK) & ISA_MIPS2) != 0)
533 && ((elf_elfheader (bfd_asymbol_bfd(*(info->symbols)))->e_flags
534 & EF_MIPS_ABI2) != 0))
535 reg_names = mips64_reg_names;
536 else
537 reg_names = mips32_reg_names;
538
539 status = (*info->read_memory_func) (memaddr, buffer, INSNLEN, info);
540 if (status == 0)
541 {
542 unsigned long insn;
543
544 if (endianness == BFD_ENDIAN_BIG)
545 insn = (unsigned long) bfd_getb32 (buffer);
546 else
547 insn = (unsigned long) bfd_getl32 (buffer);
548
549 return print_insn_mips (memaddr, insn, info);
550 }
551 else
552 {
553 (*info->memory_error_func) (status, memaddr, info);
554 return -1;
555 }
556}
557
558int
559print_insn_big_mips (memaddr, info)
560 bfd_vma memaddr;
561 struct disassemble_info *info;
562{
563 return _print_insn_mips (memaddr, info, BFD_ENDIAN_BIG);
564}
565
566int
567print_insn_little_mips (memaddr, info)
568 bfd_vma memaddr;
569 struct disassemble_info *info;
570{
571 return _print_insn_mips (memaddr, info, BFD_ENDIAN_LITTLE);
572}
573
574
575/* Disassemble mips16 instructions. */
576
577static int
578print_insn_mips16 (memaddr, info)
579 bfd_vma memaddr;
580 struct disassemble_info *info;
581{
582 int status;
583 bfd_byte buffer[2];
584 int length;
585 int insn;
586 boolean use_extend;
587 int extend = 0;
588 const struct mips_opcode *op, *opend;
589
590 info->bytes_per_chunk = 2;
591 info->display_endian = info->endian;
592 info->insn_info_valid = 1;
593 info->branch_delay_insns = 0;
594 info->data_size = 0;
595 info->insn_type = dis_nonbranch;
596 info->target = 0;
597 info->target2 = 0;
598
599 status = (*info->read_memory_func) (memaddr, buffer, 2, info);
600 if (status != 0)
601 {
602 (*info->memory_error_func) (status, memaddr, info);
603 return -1;
604 }
605
606 length = 2;
607
608 if (info->endian == BFD_ENDIAN_BIG)
609 insn = bfd_getb16 (buffer);
610 else
611 insn = bfd_getl16 (buffer);
612
613 /* Handle the extend opcode specially. */
614 use_extend = false;
615 if ((insn & 0xf800) == 0xf000)
616 {
617 use_extend = true;
618 extend = insn & 0x7ff;
619
620 memaddr += 2;
621
622 status = (*info->read_memory_func) (memaddr, buffer, 2, info);
623 if (status != 0)
624 {
625 (*info->fprintf_func) (info->stream, "extend 0x%x",
626 (unsigned int) extend);
627 (*info->memory_error_func) (status, memaddr, info);
628 return -1;
629 }
630
631 if (info->endian == BFD_ENDIAN_BIG)
632 insn = bfd_getb16 (buffer);
633 else
634 insn = bfd_getl16 (buffer);
635
636 /* Check for an extend opcode followed by an extend opcode. */
637 if ((insn & 0xf800) == 0xf000)
638 {
639 (*info->fprintf_func) (info->stream, "extend 0x%x",
640 (unsigned int) extend);
641 info->insn_type = dis_noninsn;
642 return length;
643 }
644
645 length += 2;
646 }
647
648 /* FIXME: Should probably use a hash table on the major opcode here. */
649
650 opend = mips16_opcodes + bfd_mips16_num_opcodes;
651 for (op = mips16_opcodes; op < opend; op++)
652 {
653 if (op->pinfo != INSN_MACRO && (insn & op->mask) == op->match)
654 {
655 const char *s;
656
657 if (strchr (op->args, 'a') != NULL)
658 {
659 if (use_extend)
660 {
661 (*info->fprintf_func) (info->stream, "extend 0x%x",
662 (unsigned int) extend);
663 info->insn_type = dis_noninsn;
664 return length - 2;
665 }
666
667 use_extend = false;
668
669 memaddr += 2;
670
671 status = (*info->read_memory_func) (memaddr, buffer, 2,
672 info);
673 if (status == 0)
674 {
675 use_extend = true;
676 if (info->endian == BFD_ENDIAN_BIG)
677 extend = bfd_getb16 (buffer);
678 else
679 extend = bfd_getl16 (buffer);
680 length += 2;
681 }
682 }
683
684 (*info->fprintf_func) (info->stream, "%s", op->name);
685 if (op->args[0] != '\0')
686 (*info->fprintf_func) (info->stream, "\t");
687
688 for (s = op->args; *s != '\0'; s++)
689 {
690 if (*s == ','
691 && s[1] == 'w'
692 && (((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX)
693 == ((insn >> MIPS16OP_SH_RY) & MIPS16OP_MASK_RY)))
694 {
695 /* Skip the register and the comma. */
696 ++s;
697 continue;
698 }
699 if (*s == ','
700 && s[1] == 'v'
701 && (((insn >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ)
702 == ((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX)))
703 {
704 /* Skip the register and the comma. */
705 ++s;
706 continue;
707 }
708 print_mips16_insn_arg (*s, op, insn, use_extend, extend, memaddr,
709 info);
710 }
711
712 if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
713 {
714 info->branch_delay_insns = 1;
715 if (info->insn_type != dis_jsr)
716 info->insn_type = dis_branch;
717 }
718
719 return length;
720 }
721 }
722
723 if (use_extend)
724 (*info->fprintf_func) (info->stream, "0x%x", extend | 0xf000);
725 (*info->fprintf_func) (info->stream, "0x%x", insn);
726 info->insn_type = dis_noninsn;
727
728 return length;
729}
730
731/* Disassemble an operand for a mips16 instruction. */
732
733static void
734print_mips16_insn_arg (type, op, l, use_extend, extend, memaddr, info)
735 char type;
736 const struct mips_opcode *op;
737 int l;
738 boolean use_extend;
739 int extend;
740 bfd_vma memaddr;
741 struct disassemble_info *info;
742{
743 switch (type)
744 {
745 case ',':
746 case '(':
747 case ')':
748 (*info->fprintf_func) (info->stream, "%c", type);
749 break;
750
751 case 'y':
752 case 'w':
753 (*info->fprintf_func) (info->stream, "%s",
754 mips16_reg_names[((l >> MIPS16OP_SH_RY)
755 & MIPS16OP_MASK_RY)]);
756 break;
757
758 case 'x':
759 case 'v':
760 (*info->fprintf_func) (info->stream, "%s",
761 mips16_reg_names[((l >> MIPS16OP_SH_RX)
762 & MIPS16OP_MASK_RX)]);
763 break;
764
765 case 'z':
766 (*info->fprintf_func) (info->stream, "%s",
767 mips16_reg_names[((l >> MIPS16OP_SH_RZ)
768 & MIPS16OP_MASK_RZ)]);
769 break;
770
771 case 'Z':
772 (*info->fprintf_func) (info->stream, "%s",
773 mips16_reg_names[((l >> MIPS16OP_SH_MOVE32Z)
774 & MIPS16OP_MASK_MOVE32Z)]);
775 break;
776
777 case '0':
778 (*info->fprintf_func) (info->stream, "%s", mips32_reg_names[0]);
779 break;
780
781 case 'S':
782 (*info->fprintf_func) (info->stream, "%s", mips32_reg_names[29]);
783 break;
784
785 case 'P':
786 (*info->fprintf_func) (info->stream, "$pc");
787 break;
788
789 case 'R':
790 (*info->fprintf_func) (info->stream, "%s", mips32_reg_names[31]);
791 break;
792
793 case 'X':
794 (*info->fprintf_func) (info->stream, "%s",
795 mips32_reg_names[((l >> MIPS16OP_SH_REGR32)
796 & MIPS16OP_MASK_REGR32)]);
797 break;
798
799 case 'Y':
800 (*info->fprintf_func) (info->stream, "%s",
801 mips32_reg_names[MIPS16OP_EXTRACT_REG32R (l)]);
802 break;
803
804 case '<':
805 case '>':
806 case '[':
807 case ']':
808 case '4':
809 case '5':
810 case 'H':
811 case 'W':
812 case 'D':
813 case 'j':
814 case '6':
815 case '8':
816 case 'V':
817 case 'C':
818 case 'U':
819 case 'k':
820 case 'K':
821 case 'p':
822 case 'q':
823 case 'A':
824 case 'B':
825 case 'E':
826 {
827 int immed, nbits, shift, signedp, extbits, pcrel, extu, branch;
828
829 shift = 0;
830 signedp = 0;
831 extbits = 16;
832 pcrel = 0;
833 extu = 0;
834 branch = 0;
835 switch (type)
836 {
837 case '<':
838 nbits = 3;
839 immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ;
840 extbits = 5;
841 extu = 1;
842 break;
843 case '>':
844 nbits = 3;
845 immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX;
846 extbits = 5;
847 extu = 1;
848 break;
849 case '[':
850 nbits = 3;
851 immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ;
852 extbits = 6;
853 extu = 1;
854 break;
855 case ']':
856 nbits = 3;
857 immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX;
858 extbits = 6;
859 extu = 1;
860 break;
861 case '4':
862 nbits = 4;
863 immed = (l >> MIPS16OP_SH_IMM4) & MIPS16OP_MASK_IMM4;
864 signedp = 1;
865 extbits = 15;
866 break;
867 case '5':
868 nbits = 5;
869 immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
870 info->insn_type = dis_dref;
871 info->data_size = 1;
872 break;
873 case 'H':
874 nbits = 5;
875 shift = 1;
876 immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
877 info->insn_type = dis_dref;
878 info->data_size = 2;
879 break;
880 case 'W':
881 nbits = 5;
882 shift = 2;
883 immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
884 if ((op->pinfo & MIPS16_INSN_READ_PC) == 0
885 && (op->pinfo & MIPS16_INSN_READ_SP) == 0)
886 {
887 info->insn_type = dis_dref;
888 info->data_size = 4;
889 }
890 break;
891 case 'D':
892 nbits = 5;
893 shift = 3;
894 immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
895 info->insn_type = dis_dref;
896 info->data_size = 8;
897 break;
898 case 'j':
899 nbits = 5;
900 immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
901 signedp = 1;
902 break;
903 case '6':
904 nbits = 6;
905 immed = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6;
906 break;
907 case '8':
908 nbits = 8;
909 immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
910 break;
911 case 'V':
912 nbits = 8;
913 shift = 2;
914 immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
915 /* FIXME: This might be lw, or it might be addiu to $sp or
916 $pc. We assume it's load. */
917 info->insn_type = dis_dref;
918 info->data_size = 4;
919 break;
920 case 'C':
921 nbits = 8;
922 shift = 3;
923 immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
924 info->insn_type = dis_dref;
925 info->data_size = 8;
926 break;
927 case 'U':
928 nbits = 8;
929 immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
930 extu = 1;
931 break;
932 case 'k':
933 nbits = 8;
934 immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
935 signedp = 1;
936 break;
937 case 'K':
938 nbits = 8;
939 shift = 3;
940 immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
941 signedp = 1;
942 break;
943 case 'p':
944 nbits = 8;
945 immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
946 signedp = 1;
947 pcrel = 1;
948 branch = 1;
949 info->insn_type = dis_condbranch;
950 break;
951 case 'q':
952 nbits = 11;
953 immed = (l >> MIPS16OP_SH_IMM11) & MIPS16OP_MASK_IMM11;
954 signedp = 1;
955 pcrel = 1;
956 branch = 1;
957 info->insn_type = dis_branch;
958 break;
959 case 'A':
960 nbits = 8;
961 shift = 2;
962 immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
963 pcrel = 1;
964 /* FIXME: This can be lw or la. We assume it is lw. */
965 info->insn_type = dis_dref;
966 info->data_size = 4;
967 break;
968 case 'B':
969 nbits = 5;
970 shift = 3;
971 immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
972 pcrel = 1;
973 info->insn_type = dis_dref;
974 info->data_size = 8;
975 break;
976 case 'E':
977 nbits = 5;
978 shift = 2;
979 immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
980 pcrel = 1;
981 break;
982 default:
983 abort ();
984 }
985
986 if (! use_extend)
987 {
988 if (signedp && immed >= (1 << (nbits - 1)))
989 immed -= 1 << nbits;
990 immed <<= shift;
991 if ((type == '<' || type == '>' || type == '[' || type == ']')
992 && immed == 0)
993 immed = 8;
994 }
995 else
996 {
997 if (extbits == 16)
998 immed |= ((extend & 0x1f) << 11) | (extend & 0x7e0);
999 else if (extbits == 15)
1000 immed |= ((extend & 0xf) << 11) | (extend & 0x7f0);
1001 else
1002 immed = ((extend >> 6) & 0x1f) | (extend & 0x20);
1003 immed &= (1 << extbits) - 1;
1004 if (! extu && immed >= (1 << (extbits - 1)))
1005 immed -= 1 << extbits;
1006 }
1007
1008 if (! pcrel)
1009 (*info->fprintf_func) (info->stream, "%d", immed);
1010 else
1011 {
1012 bfd_vma baseaddr;
1013 bfd_vma val;
1014
1015 if (branch)
1016 {
1017 immed *= 2;
1018 baseaddr = memaddr + 2;
1019 }
1020 else if (use_extend)
1021 baseaddr = memaddr - 2;
1022 else
1023 {
1024 int status;
1025 bfd_byte buffer[2];
1026
1027 baseaddr = memaddr;
1028
1029 /* If this instruction is in the delay slot of a jr
1030 instruction, the base address is the address of the
1031 jr instruction. If it is in the delay slot of jalr
1032 instruction, the base address is the address of the
1033 jalr instruction. This test is unreliable: we have
1034 no way of knowing whether the previous word is
1035 instruction or data. */
1036 status = (*info->read_memory_func) (memaddr - 4, buffer, 2,
1037 info);
1038 if (status == 0
1039 && (((info->endian == BFD_ENDIAN_BIG
1040 ? bfd_getb16 (buffer)
1041 : bfd_getl16 (buffer))
1042 & 0xf800) == 0x1800))
1043 baseaddr = memaddr - 4;
1044 else
1045 {
1046 status = (*info->read_memory_func) (memaddr - 2, buffer,
1047 2, info);
1048 if (status == 0
1049 && (((info->endian == BFD_ENDIAN_BIG
1050 ? bfd_getb16 (buffer)
1051 : bfd_getl16 (buffer))
1052 & 0xf81f) == 0xe800))
1053 baseaddr = memaddr - 2;
1054 }
1055 }
1056 val = (baseaddr & ~ ((1 << shift) - 1)) + immed;
1057 (*info->print_address_func) (val, info);
1058 info->target = val;
1059 }
1060 }
1061 break;
1062
1063 case 'a':
1064 if (! use_extend)
1065 extend = 0;
1066 l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2);
1067 (*info->print_address_func) (((memaddr + 4) & 0xf0000000) | l, info);
1068 info->insn_type = dis_jsr;
1069 info->target = ((memaddr + 4) & 0xf0000000) | l;
1070 info->branch_delay_insns = 1;
1071 break;
1072
1073 case 'l':
1074 case 'L':
1075 {
1076 int need_comma, amask, smask;
1077
1078 need_comma = 0;
1079
1080 l = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6;
1081
1082 amask = (l >> 3) & 7;
1083
1084 if (amask > 0 && amask < 5)
1085 {
1086 (*info->fprintf_func) (info->stream, "%s", mips32_reg_names[4]);
1087 if (amask > 1)
1088 (*info->fprintf_func) (info->stream, "-%s",
1089 mips32_reg_names[amask + 3]);
1090 need_comma = 1;
1091 }
1092
1093 smask = (l >> 1) & 3;
1094 if (smask == 3)
1095 {
1096 (*info->fprintf_func) (info->stream, "%s??",
1097 need_comma ? "," : "");
1098 need_comma = 1;
1099 }
1100 else if (smask > 0)
1101 {
1102 (*info->fprintf_func) (info->stream, "%s%s",
1103 need_comma ? "," : "",
1104 mips32_reg_names[16]);
1105 if (smask > 1)
1106 (*info->fprintf_func) (info->stream, "-%s",
1107 mips32_reg_names[smask + 15]);
1108 need_comma = 1;
1109 }
1110
1111 if (l & 1)
1112 {
1113 (*info->fprintf_func) (info->stream, "%s%s",
1114 need_comma ? "," : "",
1115 mips32_reg_names[31]);
1116 need_comma = 1;
1117 }
1118
1119 if (amask == 5 || amask == 6)
1120 {
1121 (*info->fprintf_func) (info->stream, "%s$f0",
1122 need_comma ? "," : "");
1123 if (amask == 6)
1124 (*info->fprintf_func) (info->stream, "-$f1");
1125 }
1126 }
1127 break;
1128
1129 default:
1130 /* xgettext:c-format */
1131 (*info->fprintf_func)
1132 (info->stream,
1133 _("# internal disassembler error, unrecognised modifier (%c)"),
1134 type);
1135 abort ();
1136 }
1137}
Note: See TracBrowser for help on using the repository browser.