1 /* Disassemble Imagination Technologies Meta instructions.
2    Copyright (C) 2013-2016 Free Software Foundation, Inc.
3    Contributed by Imagination Technologies Ltd.
4 
5    This library 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 3 of the License, or
8    (at your option) any later version.
9 
10    It is distributed in the hope that it will be useful, but WITHOUT
11    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
13    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., 51 Franklin Street - Fifth Floor, Boston,
18    MA 02110-1301, USA.  */
19 
20 #include "sysdep.h"
21 #include "dis-asm.h"
22 #include "opintl.h"
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "opcode/metag.h"
29 
30 /* Column widths for printing.  */
31 #define PREFIX_WIDTH    "10"
32 #define INSN_NAME_WIDTH "10"
33 
34 #define OPERAND_WIDTH   92
35 #define ADDR_WIDTH      20
36 #define REG_WIDTH       64
37 #define DSP_PREFIX_WIDTH 17
38 
39 /* Value to print if we fail to parse a register name.  */
40 const char unknown_reg[] = "?";
41 
42 /* Return the size of a GET or SET instruction.  */
43 unsigned int
metag_get_set_size_bytes(unsigned int opcode)44 metag_get_set_size_bytes (unsigned int opcode)
45 {
46   switch (((opcode) >> 24) & 0x5)
47     {
48     case 0x5:
49       return 8;
50     case 0x4:
51       return 4;
52     case 0x1:
53       return 2;
54     case 0x0:
55       return 1;
56     }
57   return 1;
58 }
59 
60 /* Return the size of an extended GET or SET instruction.  */
61 unsigned int
metag_get_set_ext_size_bytes(unsigned int opcode)62 metag_get_set_ext_size_bytes (unsigned int opcode)
63 {
64   switch (((opcode) >> 1) & 0x3)
65     {
66     case 0x3:
67       return 8;
68     case 0x2:
69       return 4;
70     case 0x1:
71       return 2;
72     case 0x0:
73       return 1;
74     }
75   return 1;
76 }
77 
78 /* Return the size of a conditional SET instruction.  */
79 unsigned int
metag_cond_set_size_bytes(unsigned int opcode)80 metag_cond_set_size_bytes (unsigned int opcode)
81 {
82   switch (opcode & 0x201)
83     {
84     case 0x201:
85       return 8;
86     case 0x200:
87       return 4;
88     case 0x001:
89       return 2;
90     case 0x000:
91       return 1;
92     }
93   return 1;
94 }
95 
96 /* Return a value sign-extended.  */
97 static int
sign_extend(int n,unsigned int bits)98 sign_extend (int n, unsigned int bits)
99 {
100   int mask = 1 << (bits - 1);
101   return -(n & mask) | n;
102 }
103 
104 /* Return the short interpretation of UNIT.  */
105 static unsigned int
short_unit(unsigned int unit)106 short_unit (unsigned int unit)
107 {
108   if (unit == UNIT_CT)
109     return UNIT_A1;
110   else
111     return unit;
112 }
113 
114 /* Return the register corresponding to UNIT and NUMBER or NULL.  */
115 static const metag_reg *
lookup_reg(unsigned int unit,unsigned int number)116 lookup_reg (unsigned int unit, unsigned int number)
117 {
118   size_t i;
119 
120   for (i = 0; i < sizeof(metag_regtab)/sizeof(metag_regtab[0]); i++)
121     {
122       const metag_reg *reg = &metag_regtab[i];
123 
124       if (reg->unit == unit && reg->no == number)
125 	return reg;
126     }
127   return NULL;
128 }
129 
130 
131 /* Return the register name corresponding to UNIT and NUMBER or NULL.  */
132 static const char *
lookup_reg_name(unsigned int unit,unsigned int number)133 lookup_reg_name (unsigned int unit, unsigned int number)
134 {
135   const metag_reg *reg;
136 
137   reg = lookup_reg (unit, number);
138 
139   if (reg)
140     return reg->name;
141   else
142     return unknown_reg;
143 }
144 
145 /* Return the unit that is the pair of UNIT.  */
146 static unsigned int
get_pair_unit(unsigned int unit)147 get_pair_unit (unsigned int unit)
148 {
149   switch (unit)
150     {
151     case UNIT_D0:
152       return UNIT_D1;
153     case UNIT_D1:
154       return UNIT_D0;
155     case UNIT_A0:
156       return UNIT_A1;
157     case UNIT_A1:
158       return UNIT_A0;
159     default:
160       return unit;
161     }
162 }
163 
164 /* Return the name of the pair register for UNIT and NUMBER or NULL.  */
165 static const char *
lookup_pair_reg_name(unsigned int unit,unsigned int number)166 lookup_pair_reg_name (unsigned int unit, unsigned int number)
167 {
168   if (unit == UNIT_FX)
169     return lookup_reg_name (unit, number + 1);
170   else
171     return lookup_reg_name (get_pair_unit (unit), number);
172 }
173 
174 /* Return the name of the accumulator register for PART.  */
175 static const char *
lookup_acf_name(unsigned int part)176 lookup_acf_name (unsigned int part)
177 {
178   size_t i;
179 
180   for (i = 0; i < sizeof(metag_acftab)/sizeof(metag_acftab[0]); i++)
181     {
182       const metag_acf *acf = &metag_acftab[i];
183 
184       if (acf->part == part)
185 	return acf->name;
186     }
187   return "ACF.?";
188 }
189 
190 /* Return the register name for the O2R register for UNIT and NUMBER.  */
191 static const char *
lookup_o2r(enum metag_unit unit,unsigned int number)192 lookup_o2r (enum metag_unit unit, unsigned int number)
193 {
194   unsigned int o2r_unit;
195   enum metag_unit actual_unit = UNIT_A0;
196   const metag_reg *reg;
197 
198   o2r_unit = (number & ~O2R_REG_MASK) >> 3;
199   number = number & O2R_REG_MASK;
200 
201   if (unit == UNIT_A0)
202     {
203       switch (o2r_unit)
204 	{
205 	case 0:
206 	  actual_unit = UNIT_A1;
207 	  break;
208 	case 1:
209 	  actual_unit = UNIT_D0;
210 	  break;
211 	case 2:
212 	  actual_unit = UNIT_RD;
213 	  break;
214 	case 3:
215 	  actual_unit = UNIT_D1;
216 	  break;
217 	}
218     }
219   else if (unit == UNIT_A1)
220     {
221       switch (o2r_unit)
222 	{
223 	case 0:
224 	  actual_unit = UNIT_D1;
225 	  break;
226 	case 1:
227 	  actual_unit = UNIT_D0;
228 	  break;
229 	case 2:
230 	  actual_unit = UNIT_RD;
231 	  break;
232 	case 3:
233 	  actual_unit = UNIT_A0;
234 	  break;
235 	}
236     }
237   else if (unit == UNIT_D0)
238     {
239       switch (o2r_unit)
240 	{
241 	case 0:
242 	  actual_unit = UNIT_A1;
243 	  break;
244 	case 1:
245 	  actual_unit = UNIT_D1;
246 	  break;
247 	case 2:
248 	  actual_unit = UNIT_RD;
249 	  break;
250 	case 3:
251 	  actual_unit = UNIT_A0;
252 	  break;
253 	}
254     }
255   else if (unit == UNIT_D1)
256     {
257       switch (o2r_unit)
258 	{
259 	case 0:
260 	  actual_unit = UNIT_A1;
261 	  break;
262 	case 1:
263 	  actual_unit = UNIT_D0;
264 	  break;
265 	case 2:
266 	  actual_unit = UNIT_RD;
267 	  break;
268 	case 3:
269 	  actual_unit = UNIT_A0;
270 	  break;
271 	}
272     }
273 
274   reg = lookup_reg (actual_unit, number);
275 
276   if (reg)
277     return reg->name;
278   else
279     return unknown_reg;
280 }
281 
282 /* Return the string for split condition code CODE. */
283 static const char *
lookup_scc_flags(unsigned int code)284 lookup_scc_flags (unsigned int code)
285 {
286   size_t i;
287 
288   for (i = 0; i < sizeof (metag_dsp_scondtab) / sizeof (metag_dsp_scondtab[0]); i++)
289     {
290       if (metag_dsp_scondtab[i].code == code)
291 	{
292 	  return metag_dsp_scondtab[i].name;
293 	}
294     }
295   return NULL;
296 }
297 
298 /* Return the string for FPU split condition code CODE. */
299 static const char *
lookup_fpu_scc_flags(unsigned int code)300 lookup_fpu_scc_flags (unsigned int code)
301 {
302   size_t i;
303 
304   for (i = 0; i < sizeof (metag_fpu_scondtab) / sizeof (metag_fpu_scondtab[0]); i++)
305     {
306       if (metag_fpu_scondtab[i].code == code)
307 	{
308 	  return metag_fpu_scondtab[i].name;
309 	}
310     }
311   return NULL;
312 }
313 
314 /* Print an instruction with PREFIX, NAME and OPERANDS.  */
315 static void
print_insn(disassemble_info * outf,const char * prefix,const char * name,const char * operands)316 print_insn (disassemble_info *outf, const char *prefix, const char *name,
317 	    const char *operands)
318 {
319   outf->fprintf_func (outf->stream, "%-" PREFIX_WIDTH "s%-" INSN_NAME_WIDTH "s%s", prefix, name, operands);
320 }
321 
322 /* Print an instruction with no operands.  */
323 static void
print_none(unsigned int insn_word ATTRIBUTE_UNUSED,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)324 print_none (unsigned int insn_word ATTRIBUTE_UNUSED,
325 	    bfd_vma pc ATTRIBUTE_UNUSED,
326 	    const insn_template *template,
327 	    disassemble_info *outf)
328 {
329   outf->fprintf_func (outf->stream, "%-" PREFIX_WIDTH "s%s", "",
330 		      template->name);
331 }
332 
333 /* Print a unit to unit MOV instruction.  */
334 static void
print_mov_u2u(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)335 print_mov_u2u (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
336 	       const insn_template *template,
337 	       disassemble_info *outf)
338 {
339   unsigned int dest_unit, dest_no, src_unit, src_no;
340   unsigned int is_kick = (insn_word & 0x1) && !((insn_word >> 9) & 0x1);
341   unsigned int major = MAJOR_OPCODE (insn_word);
342   unsigned int minor = MINOR_OPCODE (insn_word);
343   char buf[OPERAND_WIDTH];
344   const char *dest_reg;
345   const char *src_reg;
346 
347   dest_unit = (insn_word >> 5) & UNIT_MASK;
348   dest_no = (insn_word >> 14) & REG_MASK;
349 
350   dest_reg = lookup_reg_name (dest_unit, dest_no);
351 
352   if (is_kick)
353     src_unit = UNIT_TR;
354   else
355     src_unit = (insn_word >> 10) & UNIT_MASK;
356 
357   /* This is really an RTI/RTH. No, really.  */
358   if (major == OPC_MISC &&
359       minor == 0x3 &&
360       src_unit == 0xf)
361     {
362       if (insn_word & 0x800000)
363 	outf->fprintf_func (outf->stream, "%-" PREFIX_WIDTH "s%s", "",
364 			    "RTI");
365       else
366 	outf->fprintf_func (outf->stream, "%-" PREFIX_WIDTH "s%s", "",
367 			    "RTH");
368 
369       return;
370     }
371 
372   src_no = (insn_word >> 19) & REG_MASK;
373 
374   src_reg = lookup_reg_name (src_unit, src_no);
375 
376   snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg);
377 
378   if (dest_unit == UNIT_FX || src_unit == UNIT_FX)
379     print_insn (outf, "F", template->name, buf);
380   else
381     print_insn (outf, "", template->name, buf);
382 }
383 
384 /* Print a MOV to port instruction.  */
385 static void
print_mov_port(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)386 print_mov_port (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
387 		const insn_template *template,
388 		disassemble_info *outf)
389 {
390   unsigned int dest_unit, dest1_no, dest2_no, src_unit, src_no;
391   unsigned int is_movl = MINOR_OPCODE (insn_word) == MOVL_MINOR;
392   char buf[OPERAND_WIDTH];
393   const char *dest_reg;
394   const char *pair_reg;
395   const char *src_reg;
396 
397   if (is_movl)
398     dest_unit = short_unit ((insn_word >> 5) & SHORT_UNIT_MASK);
399   else
400     dest_unit = (insn_word >> 5) & UNIT_MASK;
401 
402   dest1_no = (insn_word >> 14) & REG_MASK;
403   dest2_no = (insn_word >> 9) & REG_MASK;
404 
405   dest_reg = lookup_reg_name (dest_unit, dest1_no);
406   pair_reg = lookup_pair_reg_name (dest_unit, dest2_no);
407 
408   src_unit = UNIT_RD;
409   src_no = 0;
410 
411   src_reg = lookup_reg_name (src_unit, src_no);
412 
413   if (is_movl)
414     snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, pair_reg, src_reg);
415   else
416     snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg);
417 
418   if (dest_unit == UNIT_FX)
419     print_insn (outf, "F", template->name, buf);
420   else
421     print_insn (outf, "", template->name, buf);
422 }
423 
424 /* Return the number of bits set in rmask.  */
hweight(unsigned int rmask)425 static unsigned int hweight (unsigned int rmask)
426 {
427   unsigned int count;
428 
429   for (count = 0; rmask; count++)
430     {
431       rmask &= rmask - 1;
432     }
433 
434   return count;
435 }
436 
437 /* Print a MOVL to TTREC instruction.  */
438 static void
print_movl_ttrec(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)439 print_movl_ttrec (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
440 		  const insn_template *template,
441 		  disassemble_info *outf)
442 {
443   unsigned int dest_unit, dest_no, src1_no, src2_no, src_unit;
444   char buf[OPERAND_WIDTH];
445   const char *dest_reg;
446   const char *src_reg;
447   const char *pair_reg;
448 
449   dest_unit = UNIT_TT;
450   dest_no = 3;
451 
452   dest_reg = lookup_reg_name (dest_unit, dest_no);
453 
454   src1_no = (insn_word >> 19) & REG_MASK;
455   src2_no = (insn_word >> 14) & REG_MASK;
456 
457   src_unit = short_unit ((insn_word >> 7) & SHORT_UNIT_MASK);
458 
459   src_reg = lookup_reg_name (src_unit, src1_no);
460   pair_reg = lookup_pair_reg_name (src_unit, src2_no);
461 
462   snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src_reg, pair_reg);
463 
464   print_insn (outf, "", template->name, buf);
465 }
466 
467 /* Format a GET or SET address mode string from INSN_WORD into BUF.  */
468 static void
get_set_addr_str(char * buf,unsigned int buf_size,unsigned int size,unsigned int insn_word)469 get_set_addr_str (char *buf, unsigned int buf_size, unsigned int size,
470 		  unsigned int insn_word)
471 {
472   const char *base_reg;
473   unsigned int base_unit, base_no;
474   unsigned int imm = (insn_word >> 25) & 1;
475   unsigned int ua = (insn_word >> 7) & 1;
476   unsigned int pp = insn_word & 1;
477 
478   base_unit = short_unit ((insn_word >> 5) & SHORT_UNIT_MASK);
479   base_no = (insn_word >> 14) & REG_MASK;
480 
481   base_reg = lookup_reg_name (base_unit, base_no);
482 
483   if (imm)
484     {
485       int offset = (insn_word >> 8) & GET_SET_IMM_MASK;
486 
487       offset = sign_extend (offset, GET_SET_IMM_BITS);
488 
489       if (offset == 0)
490 	{
491 	  snprintf (buf, buf_size, "[%s]", base_reg);
492 	  return;
493 	}
494 
495       if (offset == 1 && ua)
496 	{
497 	  if (pp)
498 	    snprintf (buf, buf_size, "[%s++]", base_reg);
499 	  else
500 	    snprintf (buf, buf_size, "[++%s]", base_reg);
501 
502 	  return;
503 	}
504       else if (offset == -1 && ua)
505 	{
506 	  if (pp)
507 	    snprintf (buf, buf_size, "[%s--]", base_reg);
508 	  else
509 	    snprintf (buf, buf_size, "[--%s]", base_reg);
510 
511 	  return;
512 	}
513 
514       offset = offset * size;
515 
516       if (ua)
517 	{
518 	  if (pp)
519 	    snprintf (buf, buf_size, "[%s+#%d++]", base_reg, offset);
520 	  else
521 	    snprintf (buf, buf_size, "[%s++#%d]", base_reg, offset);
522 	}
523       else
524 	snprintf (buf, buf_size, "[%s+#%d]", base_reg, offset);
525     }
526   else
527     {
528       const char *offset_reg;
529       unsigned int offset_no;
530 
531       offset_no = (insn_word >> 9) & REG_MASK;
532 
533       offset_reg = lookup_reg_name (base_unit, offset_no);
534 
535       if (ua)
536 	{
537 	  if (pp)
538 	    snprintf (buf, buf_size, "[%s+%s++]", base_reg, offset_reg);
539 	  else
540 	    snprintf (buf, buf_size, "[%s++%s]", base_reg, offset_reg);
541 	}
542       else
543 	snprintf (buf, buf_size, "[%s+%s]", base_reg, offset_reg);
544     }
545 }
546 
547 /* Format an extended GET or SET address mode string from INSN_WORD into BUF. */
548 static void
get_set_ext_addr_str(char * buf,unsigned int buf_size,unsigned int size,unsigned int insn_word)549 get_set_ext_addr_str (char *buf, unsigned int buf_size, unsigned int size,
550 		      unsigned int insn_word)
551 {
552   const char *base_reg;
553   unsigned int base_unit, base_no;
554   int offset;
555 
556   base_unit = short_unit ((insn_word >> 5) & SHORT_UNIT_MASK);
557   base_no = insn_word & EXT_BASE_REG_MASK;
558 
559   base_reg = lookup_reg_name (base_unit, base_no);
560 
561   offset = (insn_word >> 7) & GET_SET_EXT_IMM_MASK;
562 
563   offset = sign_extend (offset, GET_SET_EXT_IMM_BITS);
564 
565   offset = offset * size;
566 
567   if (offset == 0)
568     {
569       snprintf (buf, buf_size, "[%s]", base_reg);
570     }
571   else
572     {
573       snprintf (buf, buf_size, "[%s+#%d]", base_reg, offset);
574     }
575 }
576 
577 /* Format an MGET or MSET address mode string from INSN_WORD into BUF.  */
578 static void
mget_mset_addr_str(char * buf,unsigned int buf_size,unsigned int insn_word)579 mget_mset_addr_str (char *buf, unsigned int buf_size,
580 		    unsigned int insn_word)
581 {
582   const char *base_reg;
583   unsigned int base_unit, base_no;
584 
585   base_unit = short_unit ((insn_word >> 5) & SHORT_UNIT_MASK);
586   base_no = (insn_word >> 14) & REG_MASK;
587 
588   base_reg = lookup_reg_name (base_unit, base_no);
589 
590   snprintf (buf, buf_size, "[%s++]", base_reg);
591 }
592 
593 /* Format a conditional SET address mode string from INSN_WORD into BUF.  */
594 static void
cond_set_addr_str(char * buf,unsigned int buf_size,unsigned int insn_word)595 cond_set_addr_str (char *buf, unsigned int buf_size,
596 		   unsigned int insn_word)
597 {
598   const char *base_reg;
599   unsigned int base_unit, base_no;
600 
601   base_unit = short_unit ((insn_word >> 5) & SHORT_UNIT_MASK);
602   base_no = (insn_word >> 14) & REG_MASK;
603 
604   base_reg = lookup_reg_name (base_unit, base_no);
605 
606   snprintf (buf, buf_size, "[%s]", base_reg);
607 }
608 
609 /* Format a cache instruction address mode string from INSN_WORD into BUF.  */
610 static void
cache_addr_str(char * buf,unsigned int buf_size,unsigned int insn_word,int width)611 cache_addr_str (char *buf, unsigned int buf_size, unsigned int insn_word,
612 		int width)
613 {
614   const char *base_reg;
615   unsigned int base_unit, base_no;
616   int offset;
617 
618   base_unit = short_unit ((insn_word >> 5) & SHORT_UNIT_MASK);
619   base_no = (insn_word >> 14) & REG_MASK;
620 
621   base_reg = lookup_reg_name (base_unit, base_no);
622 
623   offset = (insn_word >> 8) & GET_SET_IMM_MASK;
624 
625   offset = sign_extend (offset, GET_SET_IMM_BITS);
626 
627   offset = offset * width;
628 
629   if (offset == 0)
630     {
631       snprintf (buf, buf_size, "[%s]", base_reg);
632     }
633   else
634     {
635       snprintf (buf, buf_size, "[%s+#%d]", base_reg, offset);
636     }
637 }
638 
639 /* Format a list of registers starting at REG_UNIT and REG_NO and conforming
640    to RMASK into BUF.  */
641 static void
lookup_reg_list(char * reg_buf,size_t buf_len,unsigned int reg_unit,unsigned int reg_no,unsigned int rmask,bfd_boolean is_fpu_64bit)642 lookup_reg_list (char *reg_buf, size_t buf_len, unsigned int reg_unit,
643 		 unsigned int reg_no, unsigned int rmask,
644 		 bfd_boolean is_fpu_64bit)
645 {
646   const char *regs[MGET_MSET_MAX_REGS];
647   size_t used_regs = 1, i, remaining;
648 
649   regs[0] = lookup_reg_name (reg_unit, reg_no);
650 
651   for (i = 1; i < MGET_MSET_MAX_REGS; i++)
652     {
653       if (rmask & 1)
654 	{
655 	  if (is_fpu_64bit)
656 	    regs[used_regs] = lookup_reg_name (reg_unit, reg_no + (i * 2));
657 	  else
658 	    regs[used_regs] = lookup_reg_name (reg_unit, reg_no + i);
659 	  used_regs++;
660 	}
661       rmask = rmask >> 1;
662     }
663 
664   remaining = buf_len;
665 
666   for (i = 0; i < used_regs; i++)
667     {
668       size_t len;
669       if (i == 0)
670 	len = snprintf(reg_buf, remaining, "%s", regs[i]);
671       else
672 	len = snprintf(reg_buf, remaining, ",%s", regs[i]);
673 
674       reg_buf += len;
675       remaining -= len;
676     }
677 }
678 
679 /* Print a GET instruction.  */
680 static void
print_get(char * buf,char * addr_buf,unsigned int size,const char * dest_reg,const char * pair_reg,unsigned int reg_unit,const insn_template * template,disassemble_info * outf)681 print_get (char *buf, char *addr_buf, unsigned int size,
682 	   const char *dest_reg, const char *pair_reg, unsigned int reg_unit,
683 	   const insn_template *template,
684 	   disassemble_info *outf)
685 {
686   if (size == 8)
687     {
688       snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, pair_reg,
689 		addr_buf);
690     }
691   else
692     {
693       snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, addr_buf);
694     }
695 
696   if (reg_unit == UNIT_FX)
697     print_insn (outf, "F", template->name, buf);
698   else
699     print_insn (outf, "", template->name, buf);
700 }
701 
702 /* Print a SET instruction.  */
703 static void
print_set(char * buf,char * addr_buf,unsigned int size,const char * src_reg,const char * pair_reg,unsigned int reg_unit,const insn_template * template,disassemble_info * outf)704 print_set (char *buf, char *addr_buf, unsigned int size,
705 	   const char *src_reg, const char *pair_reg, unsigned int reg_unit,
706 	   const insn_template *template,
707 	   disassemble_info *outf)
708 {
709   if (size == 8)
710     {
711       snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", addr_buf, src_reg, pair_reg);
712     }
713   else
714     {
715       snprintf (buf, OPERAND_WIDTH, "%s,%s", addr_buf, src_reg);
716     }
717 
718   if (reg_unit == UNIT_FX)
719     print_insn (outf, "F", template->name, buf);
720   else
721     print_insn (outf, "", template->name, buf);
722 }
723 
724 /* Print a GET or SET instruction.  */
725 static void
print_get_set(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)726 print_get_set (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
727 	       const insn_template *template,
728 	       disassemble_info *outf)
729 {
730   bfd_boolean is_get = MAJOR_OPCODE (template->meta_opcode) == OPC_GET;
731   char buf[OPERAND_WIDTH];
732   char addr_buf[ADDR_WIDTH];
733   unsigned int reg_unit, reg_no;
734   unsigned int size = metag_get_set_size_bytes (insn_word);
735   const char *reg_name;
736   const char *pair_reg;
737 
738   reg_unit = (insn_word >> 1) & UNIT_MASK;
739   reg_no = (insn_word >> 19) & REG_MASK;
740 
741   /* SETs should always print RD. */
742   if (!is_get && reg_unit == UNIT_RD)
743     reg_no = 0;
744 
745   reg_name = lookup_reg_name (reg_unit, reg_no);
746 
747   pair_reg = lookup_pair_reg_name (reg_unit, reg_no);
748 
749   get_set_addr_str (addr_buf, ADDR_WIDTH, size, insn_word);
750 
751   if (is_get)
752     {
753       /* RD regs are 64 bits wide so don't use the pair syntax.  */
754       if (reg_unit == UNIT_RD)
755 	print_get (buf, addr_buf, 4, reg_name, pair_reg, reg_unit,
756 		   template, outf);
757       else
758 	print_get (buf, addr_buf, size, reg_name, pair_reg, reg_unit,
759 		   template, outf);
760     }
761   else
762     {
763       /* RD regs are 64 bits wide so don't use the pair syntax.  */
764       if (reg_unit == UNIT_RD)
765 	print_set (buf, addr_buf, 4, reg_name, pair_reg, reg_unit,
766 		   template, outf);
767       else
768 	print_set (buf, addr_buf, size, reg_name, pair_reg, reg_unit,
769 		   template, outf);
770     }
771 }
772 
773 /* Print an extended GET or SET instruction.  */
774 static void
print_get_set_ext(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)775 print_get_set_ext (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
776 		   const insn_template *template,
777 		   disassemble_info *outf)
778 {
779   bfd_boolean is_get = MINOR_OPCODE (template->meta_opcode) == GET_EXT_MINOR;
780   bfd_boolean is_mov = MINOR_OPCODE (template->meta_opcode) == MOV_EXT_MINOR;
781   char buf[OPERAND_WIDTH];
782   char addr_buf[ADDR_WIDTH];
783   unsigned int reg_unit, reg_no;
784   unsigned int size = metag_get_set_ext_size_bytes (insn_word);
785   const char *reg_name;
786   const char *pair_reg;
787 
788   if (is_mov)
789     reg_unit = UNIT_RD;
790   else
791     reg_unit = short_unit ((insn_word >> 3) & SHORT_UNIT_MASK);
792 
793   reg_no = (insn_word >> 19) & REG_MASK;
794 
795   reg_name = lookup_reg_name (reg_unit, reg_no);
796 
797   pair_reg = lookup_pair_reg_name (reg_unit, reg_no);
798 
799   get_set_ext_addr_str (addr_buf, ADDR_WIDTH, size, insn_word);
800 
801   if (is_get)
802     print_get (buf, addr_buf, size, reg_name, pair_reg, reg_unit,
803 	       template, outf);
804   else if (is_mov)
805     print_get (buf, addr_buf, 4, reg_name, pair_reg, reg_unit,
806 	       template, outf);
807   else
808     print_set (buf, addr_buf, size, reg_name, pair_reg, reg_unit,
809 	       template, outf);
810 }
811 
812 /* Print an MGET or MSET instruction.  */
813 static void
print_mget_mset(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)814 print_mget_mset (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
815 		 const insn_template *template,
816 		 disassemble_info *outf)
817 {
818   bfd_boolean is_get = MAJOR_OPCODE (template->meta_opcode) == OPC_GET;
819   bfd_boolean is_fpu = (MINOR_OPCODE (template->meta_opcode) & 0x6) == 0x6;
820   bfd_boolean is_64bit = (MINOR_OPCODE (template->meta_opcode) & 0x1) == 0x1;
821   char buf[OPERAND_WIDTH];
822   char addr_buf[ADDR_WIDTH];
823   char reg_buf[REG_WIDTH];
824   unsigned int reg_unit, reg_no, rmask;
825 
826   if (is_fpu)
827     reg_unit = UNIT_FX;
828   else
829     reg_unit = short_unit ((insn_word >> 3) & SHORT_UNIT_MASK);
830 
831   reg_no = (insn_word >> 19) & REG_MASK;
832   rmask = (insn_word >> 7) & RMASK_MASK;
833 
834   lookup_reg_list (reg_buf, REG_WIDTH, reg_unit, reg_no, rmask,
835 		   is_fpu && is_64bit);
836 
837   mget_mset_addr_str (addr_buf, ADDR_WIDTH, insn_word);
838 
839   if (is_get)
840     snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_buf, addr_buf);
841   else
842     snprintf (buf, OPERAND_WIDTH, "%s,%s", addr_buf, reg_buf);
843 
844   if (is_fpu)
845     print_insn (outf, "F", template->name, buf);
846   else
847     print_insn (outf, "", template->name, buf);
848 }
849 
850 /* Print a conditional SET instruction.  */
851 static void
print_cond_set(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)852 print_cond_set (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
853 		const insn_template *template,
854 		disassemble_info *outf)
855 {
856   char buf[OPERAND_WIDTH];
857   char addr_buf[ADDR_WIDTH];
858   unsigned int src_unit, src_no;
859   unsigned int size = metag_cond_set_size_bytes (insn_word);
860   const char *src_reg;
861   const char *pair_reg;
862 
863   src_unit = (insn_word >> 10) & UNIT_MASK;
864   src_no = (insn_word >> 19) & REG_MASK;
865 
866   if (src_unit == UNIT_RD)
867     src_no = 0;
868 
869   src_reg = lookup_reg_name (src_unit, src_no);
870 
871   pair_reg = lookup_pair_reg_name (src_unit, src_no);
872 
873   cond_set_addr_str (addr_buf, ADDR_WIDTH, insn_word);
874 
875   if (src_unit == UNIT_RD)
876     print_set (buf, addr_buf, 4, src_reg, pair_reg, src_unit,
877 	       template, outf);
878   else
879     print_set (buf, addr_buf, size, src_reg, pair_reg, src_unit,
880 	       template, outf);
881 }
882 
883 /* Print a MMOV instruction.  */
884 static void
print_mmov(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)885 print_mmov (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
886 	    const insn_template *template,
887 	    disassemble_info *outf)
888 {
889   unsigned int is_fpu = template->insn_type == INSN_FPU;
890   unsigned int is_prime = ((MINOR_OPCODE (template->meta_opcode) & 0x2) &&
891 			   !is_fpu);
892   unsigned int is_64bit = MINOR_OPCODE (template->meta_opcode) & 0x1;
893   unsigned int is_dsp = template->meta_opcode & 0x1;
894   unsigned int dest_unit, dest_no, rmask;
895   char buf[OPERAND_WIDTH];
896   char reg_buf[REG_WIDTH];
897   char addr_buf[ADDR_WIDTH];
898 
899   if (is_fpu)
900     dest_no = (insn_word >> 14) & REG_MASK;
901   else
902     dest_no = (insn_word >> 19) & REG_MASK;
903 
904   rmask = (insn_word >> 7) & RMASK_MASK;
905 
906   if (is_prime)
907     {
908       const char *dest_reg;
909       const char *base_reg;
910       unsigned int base_unit, base_no;
911       int i, count = hweight (rmask);
912 
913       dest_reg = lookup_reg_name (UNIT_RD, dest_no);
914 
915       strcpy (reg_buf, dest_reg);
916 
917       for (i = 0; i < count; i++)
918 	{
919 	  strcat (reg_buf, ",");
920 	  strcat (reg_buf, dest_reg);
921 	}
922 
923       base_unit = short_unit ((insn_word >> 5) & SHORT_UNIT_MASK);
924       base_no = (insn_word >> 14) & REG_MASK;
925 
926       base_reg = lookup_reg_name (base_unit, base_no);
927 
928       snprintf (addr_buf, ADDR_WIDTH, "[%s++]", base_reg);
929 
930       snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_buf, addr_buf);
931     }
932   else
933     {
934       if (is_fpu)
935 	dest_unit = UNIT_FX;
936       else
937 	dest_unit = short_unit ((insn_word >> 3) & SHORT_UNIT_MASK);
938 
939       lookup_reg_list (reg_buf, REG_WIDTH, dest_unit, dest_no, rmask,
940 		       is_fpu && is_64bit);
941 
942       snprintf (buf, OPERAND_WIDTH, "%s,RD", reg_buf);
943     }
944 
945   if (is_dsp)
946     {
947       char prefix_buf[10] = {0};
948       if (is_prime)
949 	{
950 	  if (dest_no == 22 || dest_no == 23)
951 	    strcpy (prefix_buf, "DB");
952 	  else if (dest_no == 24)
953 	    strcpy (prefix_buf, "DBH");
954 	  else if (dest_no == 25)
955 	    strcpy (prefix_buf, "DWH");
956 	  else if (dest_no == 31)
957 	    strcpy (prefix_buf, "DW");
958 	}
959       else
960 	strcpy (prefix_buf, "DW");
961       print_insn (outf, prefix_buf, template->name, buf);
962     }
963   else if (is_fpu)
964     print_insn (outf, "F", template->name, buf);
965   else
966     print_insn (outf, "", template->name, buf);
967 }
968 
969 /* Print an MDRD instruction.  */
970 static void
print_mdrd(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)971 print_mdrd (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
972 	    const insn_template *template,
973 	    disassemble_info *outf)
974 {
975   unsigned int rmask, count;
976   char buf[OPERAND_WIDTH];
977 
978   rmask = (insn_word >> 7) & RMASK_MASK;
979 
980   count = hweight (rmask);
981 
982   snprintf (buf, OPERAND_WIDTH, "#%#x", count + 1);
983 
984   print_insn (outf, "", template->name, buf);
985 }
986 
987 /* Print an XFR instruction.  */
988 static void
print_xfr(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)989 print_xfr (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
990 	   const insn_template *template,
991 	   disassemble_info *outf)
992 {
993   char buf[OPERAND_WIDTH];
994   char dest_buf[ADDR_WIDTH];
995   char src_buf[ADDR_WIDTH];
996   unsigned int dest_unit, src_unit;
997   unsigned int dest_no, src_no;
998   unsigned int us, ud, pp;
999   const char *dest_base_reg;
1000   const char *dest_offset_reg;
1001   const char *src_base_reg;
1002   const char *src_offset_reg;
1003 
1004   src_unit = short_unit ((insn_word >> 2) & SHORT_UNIT_MASK);
1005   src_no = (insn_word >> 19) & REG_MASK;
1006 
1007   src_base_reg = lookup_reg_name (src_unit, src_no);
1008 
1009   src_no = (insn_word >> 14) & REG_MASK;
1010 
1011   src_offset_reg = lookup_reg_name (src_unit, src_no);
1012 
1013   dest_unit = short_unit (insn_word & SHORT_UNIT_MASK);
1014   dest_no = (insn_word >> 9) & REG_MASK;
1015 
1016   dest_base_reg = lookup_reg_name (dest_unit, dest_no);
1017 
1018   dest_no = (insn_word >> 4) & REG_MASK;
1019 
1020   dest_offset_reg = lookup_reg_name (dest_unit, dest_no);
1021 
1022   us = (insn_word >> 27) & 0x1;
1023   ud = (insn_word >> 26) & 0x1;
1024   pp = (insn_word >> 24) & 0x1;
1025 
1026   if (us)
1027     if (pp)
1028       snprintf (src_buf, ADDR_WIDTH, "[%s+%s++]", src_base_reg,
1029 		src_offset_reg);
1030     else
1031       snprintf (src_buf, ADDR_WIDTH, "[%s++%s]", src_base_reg,
1032 		src_offset_reg);
1033   else
1034     snprintf (src_buf, ADDR_WIDTH, "[%s+%s]", src_base_reg,
1035 	      src_offset_reg);
1036 
1037   if (ud)
1038     if (pp)
1039       snprintf (dest_buf, ADDR_WIDTH, "[%s+%s++]", dest_base_reg,
1040 		dest_offset_reg);
1041     else
1042       snprintf (dest_buf, ADDR_WIDTH, "[%s++%s]", dest_base_reg,
1043 		dest_offset_reg);
1044   else
1045     snprintf (dest_buf, ADDR_WIDTH, "[%s+%s]", dest_base_reg,
1046 	      dest_offset_reg);
1047 
1048   snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_buf, src_buf);
1049 
1050   print_insn (outf, "", template->name, buf);
1051 }
1052 
1053 /* Print a MOV to control unit instruction.  */
1054 static void
print_mov_ct(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1055 print_mov_ct (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1056 	      const insn_template *template,
1057 	      disassemble_info *outf)
1058 {
1059   char buf[OPERAND_WIDTH];
1060   unsigned int reg_no;
1061   unsigned int se = (insn_word >> 1) & 0x1;
1062   unsigned int is_trace = (insn_word >> 2) & 0x1;
1063   int value;
1064   const char *dest_reg;
1065 
1066   reg_no = (insn_word >> 19) & REG_MASK;
1067 
1068   if (is_trace)
1069     dest_reg = lookup_reg_name (UNIT_TT, reg_no);
1070   else
1071     dest_reg = lookup_reg_name (UNIT_CT, reg_no);
1072 
1073   value = (insn_word >> 3) & IMM16_MASK;
1074 
1075   if (se)
1076     {
1077       value = sign_extend (value, IMM16_BITS);
1078       snprintf (buf, OPERAND_WIDTH, "%s,#%d", dest_reg, value);
1079     }
1080   else
1081     {
1082       snprintf (buf, OPERAND_WIDTH, "%s,#%#x", dest_reg, value);
1083     }
1084 
1085   print_insn (outf, "", template->name, buf);
1086 }
1087 
1088 /* Print a SWAP instruction.  */
1089 static void
print_swap(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1090 print_swap (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1091 	    const insn_template *template,
1092 	    disassemble_info *outf)
1093 {
1094   char buf[OPERAND_WIDTH];
1095   unsigned int dest_no, src_no;
1096   unsigned int dest_unit, src_unit;
1097   const char *dest_reg;
1098   const char *src_reg;
1099 
1100   src_unit = (insn_word >> 10) & UNIT_MASK;
1101   src_no = (insn_word >> 19) & REG_MASK;
1102 
1103   src_reg = lookup_reg_name (src_unit, src_no);
1104 
1105   dest_unit = (insn_word >> 5) & UNIT_MASK;
1106   dest_no = (insn_word >> 14) & REG_MASK;
1107 
1108   dest_reg = lookup_reg_name (dest_unit, dest_no);
1109 
1110   snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg);
1111 
1112   if (dest_unit == UNIT_FX || src_unit == UNIT_FX)
1113     print_insn (outf, "F", template->name, buf);
1114   else
1115     print_insn (outf, "", template->name, buf);
1116 }
1117 
1118 /* Print a SWAP instruction.  */
1119 static void
print_jump(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1120 print_jump (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1121 	    const insn_template *template,
1122 	    disassemble_info *outf)
1123 {
1124   char buf[OPERAND_WIDTH];
1125   unsigned int reg_no, reg_unit;
1126   const char *reg_name;
1127   int value;
1128 
1129   reg_unit = short_unit (insn_word & SHORT_UNIT_MASK);
1130   reg_no = (insn_word >> 19) & REG_MASK;
1131 
1132   reg_name = lookup_reg_name (reg_unit, reg_no);
1133 
1134   value = (insn_word >> 3) & IMM16_MASK;
1135 
1136   snprintf (buf, OPERAND_WIDTH, "%s,#%#x", reg_name, value);
1137 
1138   print_insn (outf, "", template->name, buf);
1139 }
1140 
1141 /* Print a CALLR instruction.  */
1142 static void
print_callr(unsigned int insn_word,bfd_vma pc,const insn_template * template,disassemble_info * outf)1143 print_callr (unsigned int insn_word, bfd_vma pc, const insn_template *template,
1144 	     disassemble_info *outf)
1145 {
1146   char buf[OPERAND_WIDTH];
1147   unsigned int reg_no, reg_unit;
1148   const char *reg_name;
1149   int value;
1150 
1151   reg_unit = short_unit ((insn_word >> 3) & SHORT_UNIT_MASK);
1152   reg_no = insn_word & CALLR_REG_MASK;
1153 
1154   reg_name = lookup_reg_name (reg_unit, reg_no);
1155 
1156   value = (insn_word >> 5) & IMM19_MASK;
1157 
1158   value = sign_extend (value, IMM19_BITS);
1159 
1160   value = value * 4;
1161 
1162   value += pc;
1163 
1164   snprintf (buf, OPERAND_WIDTH, "%s,", reg_name);
1165 
1166   print_insn (outf, "", template->name, buf);
1167 
1168   outf->print_address_func (value, outf);
1169 }
1170 
1171 /* Print a GP ALU instruction.  */
1172 static void
print_alu(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1173 print_alu (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1174 	   const insn_template *template,
1175 	   disassemble_info *outf)
1176 {
1177   char buf[OPERAND_WIDTH];
1178   unsigned int is_addr_op = MAJOR_OPCODE (template->meta_opcode) == OPC_ADDR;
1179   unsigned int is_mul = MAJOR_OPCODE (template->meta_opcode) == OPC_MUL;
1180   unsigned int dest_no, src1_no, src2_no;
1181   unsigned int imm = (insn_word >> 25) & 0x1;
1182   unsigned int cond = (insn_word >> 26) & 0x1;
1183   unsigned int o1z = 0;
1184   unsigned int o2r = insn_word & 0x1;
1185   unsigned int unit_bit = (insn_word >> 24) & 0x1;
1186   unsigned int ca = (insn_word >> 5) & 0x1;
1187   unsigned int se = (insn_word >> 1) & 0x1;
1188   bfd_boolean is_quickrot = template->arg_type & GP_ARGS_QR;
1189   enum metag_unit base_unit;
1190   enum metag_unit dest_unit;
1191   const char *dest_reg;
1192   const char *src1_reg;
1193   const char *src2_reg;
1194   int value;
1195 
1196   if ((MAJOR_OPCODE (template->meta_opcode) == OPC_ADDR ||
1197       MAJOR_OPCODE (template->meta_opcode) == OPC_ADD ||
1198        MAJOR_OPCODE (template->meta_opcode) == OPC_SUB) &&
1199       ((insn_word >> 2) & 0x1))
1200     o1z = 1;
1201 
1202   if (is_addr_op)
1203     {
1204       if (unit_bit)
1205 	base_unit = UNIT_A1;
1206       else
1207 	base_unit = UNIT_A0;
1208     }
1209   else
1210     {
1211       if (unit_bit)
1212 	base_unit = UNIT_D1;
1213       else
1214 	base_unit = UNIT_D0;
1215     }
1216 
1217   dest_no = (insn_word >> 19) & REG_MASK;
1218   src1_no = (insn_word >> 14) & REG_MASK;
1219   src2_no = (insn_word >> 9) & REG_MASK;
1220 
1221   dest_unit = base_unit;
1222 
1223   if (imm)
1224     {
1225       if (cond)
1226 	{
1227 	  if (ca)
1228 	    {
1229 	      dest_unit = (insn_word >> 1) & UNIT_MASK;
1230 	      dest_reg = lookup_reg_name (dest_unit, dest_no);
1231 	    }
1232 	  else
1233 	      dest_reg = lookup_reg_name (dest_unit, dest_no);
1234 
1235 	  src1_reg = lookup_reg_name (base_unit, src1_no);
1236 
1237 	  value = (insn_word >> 6) & IMM8_MASK;
1238 
1239 	  if (is_quickrot)
1240 	    {
1241 	      unsigned int qr_unit = unit_bit ? UNIT_A1 : UNIT_A0;
1242 	      unsigned int qr_no = 2;
1243 	      const char *qr_reg = lookup_reg_name (qr_unit, qr_no);
1244 
1245 	      snprintf (buf, OPERAND_WIDTH, "%s,%s,#%#x,%s", dest_reg,
1246 			src1_reg, value, qr_reg);
1247 	    }
1248 	  else
1249 	    snprintf (buf, OPERAND_WIDTH, "%s,%s,#%#x", dest_reg,
1250 		      src1_reg, value);
1251 	}
1252       else
1253 	{
1254 	  if (is_addr_op && (dest_no & ~CPC_REG_MASK))
1255 	    {
1256 	      dest_reg = lookup_reg_name (dest_unit, dest_no & CPC_REG_MASK);
1257 	      src1_reg = lookup_reg_name (base_unit, 0x10);
1258 	    }
1259 	  else
1260 	    {
1261 	      dest_reg = lookup_reg_name (dest_unit, dest_no);
1262 	      src1_reg = lookup_reg_name (base_unit, dest_no);
1263 	    }
1264 
1265 	  value = (insn_word >> 3) & IMM16_MASK;
1266 
1267 	  if (se)
1268 	    {
1269 	      value = sign_extend (value, IMM16_BITS);
1270 	      if (o1z)
1271 		{
1272 		  snprintf (buf, OPERAND_WIDTH, "%s,#%d", dest_reg, value);
1273 		}
1274 	      else
1275 		{
1276 		  snprintf (buf, OPERAND_WIDTH, "%s,%s,#%d", dest_reg,
1277 			    src1_reg, value);
1278 		}
1279 	    }
1280 	  else
1281 	    {
1282 	      if (o1z)
1283 		{
1284 		  snprintf (buf, OPERAND_WIDTH, "%s,#%#x", dest_reg, value);
1285 		}
1286 	      else
1287 		{
1288 		  snprintf (buf, OPERAND_WIDTH, "%s,%s,#%#x", dest_reg,
1289 			    src1_reg, value);
1290 		}
1291 	    }
1292 	}
1293     }
1294   else
1295     {
1296       src1_reg = lookup_reg_name (base_unit, src1_no);
1297 
1298       if (o2r)
1299 	src2_reg = lookup_o2r (base_unit, src2_no);
1300       else
1301 	src2_reg = lookup_reg_name (base_unit, src2_no);
1302 
1303       if (cond)
1304 	{
1305 	  dest_unit = (insn_word >> 5) & UNIT_MASK;
1306 
1307 	  if (is_mul)
1308 	    {
1309 	      if (ca)
1310 		dest_unit = (insn_word >> 1) & UNIT_MASK;
1311 	      else
1312 		dest_unit = base_unit;
1313 	    }
1314 
1315 	  dest_reg = lookup_reg_name (dest_unit, dest_no);
1316 
1317 	  snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg,
1318 		    src1_reg, src2_reg);
1319 	}
1320       else
1321 	{
1322 	  dest_reg = lookup_reg_name (dest_unit, dest_no);
1323 
1324 	  if (is_quickrot)
1325 	    {
1326 	      unsigned int qr_unit = unit_bit ? UNIT_A1 : UNIT_A0;
1327 	      unsigned int qr_no = 2 + ((insn_word >> 7) & 0x1);
1328 	      const char *qr_reg = lookup_reg_name (qr_unit, qr_no);
1329 
1330 	      snprintf (buf, OPERAND_WIDTH, "%s,%s,%s,%s", dest_reg,
1331 			src1_reg, src2_reg, qr_reg);
1332 	    }
1333 	  else if (o1z)
1334 	    {
1335 	      snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src2_reg);
1336 	    }
1337 	  else
1338 	    {
1339 	      snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg,
1340 			src1_reg, src2_reg);
1341 	    }
1342 	}
1343     }
1344 
1345   if (dest_unit == UNIT_FX)
1346     print_insn (outf, "F", template->name, buf);
1347   else
1348     print_insn (outf, "", template->name, buf);
1349 }
1350 
1351 /* Print a B instruction.  */
1352 static void
print_branch(unsigned int insn_word,bfd_vma pc,const insn_template * template,disassemble_info * outf)1353 print_branch (unsigned int insn_word, bfd_vma pc,
1354 	      const insn_template *template,
1355 	      disassemble_info *outf)
1356 {
1357   int value;
1358 
1359   value = (insn_word >> 5) & IMM19_MASK;
1360 
1361   value = sign_extend (value, IMM19_BITS);
1362 
1363   value = value * 4;
1364 
1365   value += pc;
1366 
1367   print_insn (outf, "", template->name, "");
1368 
1369   outf->print_address_func (value, outf);
1370 }
1371 
1372 /* Print a SWITCH instruction.  */
1373 static void
print_switch(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1374 print_switch (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1375 	      const insn_template *template,
1376 	      disassemble_info *outf)
1377 {
1378   char buf[OPERAND_WIDTH];
1379   unsigned int value;
1380 
1381   value = insn_word & IMM24_MASK;
1382 
1383   snprintf (buf, OPERAND_WIDTH, "#%#x", value);
1384 
1385   print_insn (outf, "", template->name, buf);
1386 }
1387 
1388 /* Print a shift instruction.  */
1389 static void
print_shift(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1390 print_shift (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1391 	     const insn_template *template,
1392 	     disassemble_info *outf)
1393 {
1394   char buf[OPERAND_WIDTH];
1395   unsigned int dest_no, src1_no, src2_no;
1396   unsigned int imm = (insn_word >> 25) & 0x1;
1397   unsigned int cond = (insn_word >> 26) & 0x1;
1398   unsigned int unit_bit = (insn_word >> 24) & 0x1;
1399   unsigned int ca = (insn_word >> 5) & 0x1;
1400   enum metag_unit base_unit;
1401   unsigned int dest_unit;
1402   const char *dest_reg;
1403   const char *src1_reg;
1404   const char *src2_reg;
1405   int value;
1406 
1407   if (unit_bit)
1408     base_unit = UNIT_D1;
1409   else
1410     base_unit = UNIT_D0;
1411 
1412   dest_no = (insn_word >> 19) & REG_MASK;
1413   src1_no = (insn_word >> 14) & REG_MASK;
1414   src2_no = (insn_word >> 9) & REG_MASK;
1415 
1416   dest_unit = base_unit;
1417 
1418   if (imm)
1419     {
1420       if (cond && ca)
1421 	dest_unit = (insn_word >> 1) & UNIT_MASK;
1422 
1423       dest_reg = lookup_reg_name (dest_unit, dest_no);
1424 
1425       src1_reg = lookup_reg_name (base_unit, src1_no);
1426 
1427       value = (insn_word >> 9) & IMM5_MASK;
1428 
1429       snprintf (buf, OPERAND_WIDTH, "%s,%s,#%#x", dest_reg,
1430 		src1_reg, value);
1431     }
1432   else
1433     {
1434       if (cond && ca)
1435 	dest_unit = (insn_word >> 1) & UNIT_MASK;
1436 
1437       dest_reg = lookup_reg_name (dest_unit, dest_no);
1438 
1439       src1_reg = lookup_reg_name (base_unit, src1_no);
1440       src2_reg = lookup_reg_name (base_unit, src2_no);
1441 
1442       snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg,
1443 		src1_reg, src2_reg);
1444     }
1445 
1446   if (dest_unit == UNIT_FX)
1447     print_insn (outf, "F", template->name, buf);
1448   else
1449     print_insn (outf, "", template->name, buf);
1450 }
1451 
1452 /* Print a MIN or MAX instruction.  */
1453 static void
print_min_max(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1454 print_min_max (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1455 	       const insn_template *template,
1456 	       disassemble_info *outf)
1457 {
1458   unsigned int base_unit, dest_no, src1_no, src2_no;
1459   char buf[OPERAND_WIDTH];
1460   const char *dest_reg;
1461   const char *src1_reg;
1462   const char *src2_reg;
1463 
1464   if ((insn_word >> 24) & UNIT_MASK)
1465     base_unit = UNIT_D1;
1466   else
1467     base_unit = UNIT_D0;
1468 
1469   dest_no = (insn_word >> 19) & REG_MASK;
1470   src1_no = (insn_word >> 14) & REG_MASK;
1471   src2_no = (insn_word >> 9) & REG_MASK;
1472 
1473   dest_reg = lookup_reg_name (base_unit, dest_no);
1474 
1475   src1_reg = lookup_reg_name (base_unit, src1_no);
1476   src2_reg = lookup_reg_name (base_unit, src2_no);
1477 
1478   snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg);
1479 
1480   print_insn (outf, "", template->name, buf);
1481 }
1482 
1483 /* Print a bit operation instruction.  */
1484 static void
print_bitop(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1485 print_bitop (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1486 	     const insn_template *template,
1487 	     disassemble_info *outf)
1488 {
1489   unsigned int swap_inst = MAJOR_OPCODE (template->meta_opcode) == OPC_MISC;
1490   unsigned int base_unit, src_unit, dest_no, src_no;
1491   unsigned int is_bexl = 0;
1492   char buf[OPERAND_WIDTH];
1493   const char *dest_reg;
1494   const char *src_reg;
1495 
1496   if (swap_inst &&
1497       ((insn_word >> 1) & 0xb) == 0xa)
1498     is_bexl = 1;
1499 
1500   if (swap_inst)
1501     {
1502       if (insn_word & 0x1)
1503 	base_unit = UNIT_D1;
1504       else
1505 	base_unit = UNIT_D0;
1506     }
1507   else
1508     {
1509       if ((insn_word >> 24) & 0x1)
1510 	base_unit = UNIT_D1;
1511       else
1512 	base_unit = UNIT_D0;
1513     }
1514 
1515   src_unit = base_unit;
1516 
1517   if (is_bexl)
1518     base_unit = get_pair_unit (base_unit);
1519 
1520   dest_no = (insn_word >> 19) & REG_MASK;
1521 
1522   dest_reg = lookup_reg_name (base_unit, dest_no);
1523 
1524   src_no = (insn_word >> 14) & REG_MASK;
1525 
1526   src_reg = lookup_reg_name (src_unit, src_no);
1527 
1528   snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg);
1529 
1530   print_insn (outf, "", template->name, buf);
1531 }
1532 
1533 /* Print a CMP or TST instruction.  */
1534 static void
print_cmp(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1535 print_cmp (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1536 	   const insn_template *template,
1537 	   disassemble_info *outf)
1538 {
1539   char buf[OPERAND_WIDTH];
1540   unsigned int dest_no, src_no;
1541   unsigned int imm = (insn_word >> 25) & 0x1;
1542   unsigned int cond = (insn_word >> 26) & 0x1;
1543   unsigned int o2r = insn_word & 0x1;
1544   unsigned int unit_bit = (insn_word >> 24) & 0x1;
1545   unsigned int se = (insn_word >> 1) & 0x1;
1546   enum metag_unit base_unit;
1547   const char *dest_reg;
1548   const char *src_reg;
1549   int value;
1550 
1551   if (unit_bit)
1552     base_unit = UNIT_D1;
1553   else
1554     base_unit = UNIT_D0;
1555 
1556   dest_no = (insn_word >> 14) & REG_MASK;
1557   src_no = (insn_word >> 9) & REG_MASK;
1558 
1559   dest_reg = lookup_reg_name (base_unit, dest_no);
1560 
1561   if (imm)
1562     {
1563       if (cond)
1564 	{
1565 	  value = (insn_word >> 6) & IMM8_MASK;
1566 
1567 	  snprintf (buf, OPERAND_WIDTH, "%s,#%#x", dest_reg, value);
1568 	}
1569       else
1570 	{
1571 	  dest_no = (insn_word >> 19) & REG_MASK;
1572 
1573 	  dest_reg = lookup_reg_name (base_unit, dest_no);
1574 
1575 	  value = (insn_word >> 3) & IMM16_MASK;
1576 
1577 	  if (se)
1578 	    {
1579 	      value = sign_extend (value, IMM16_BITS);
1580 	      snprintf (buf, OPERAND_WIDTH, "%s,#%d", dest_reg, value);
1581 	    }
1582 	  else
1583 	    {
1584 	      snprintf (buf, OPERAND_WIDTH, "%s,#%#x", dest_reg, value);
1585 	    }
1586 	}
1587     }
1588   else
1589     {
1590       if (o2r)
1591 	src_reg = lookup_o2r (base_unit, src_no);
1592       else
1593 	src_reg = lookup_reg_name (base_unit, src_no);
1594 
1595       snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg);
1596     }
1597 
1598   print_insn (outf, "", template->name, buf);
1599 }
1600 
1601 /* Print a CACHER instruction.  */
1602 static void
print_cacher(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1603 print_cacher (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1604 	      const insn_template *template,
1605 	      disassemble_info *outf)
1606 {
1607   char buf[OPERAND_WIDTH];
1608   char addr_buf[ADDR_WIDTH];
1609   unsigned int reg_unit, reg_no;
1610   unsigned int size = ((insn_word >> 1) & 0x1) ? 8 : 4;
1611   const char *reg_name;
1612   const char *pair_name;
1613 
1614   reg_unit = short_unit ((insn_word >> 3) & SHORT_UNIT_MASK);
1615   reg_no = (insn_word >> 19) & REG_MASK;
1616 
1617   reg_name = lookup_reg_name (reg_unit, reg_no);
1618   pair_name = lookup_pair_reg_name (reg_unit, reg_no);
1619 
1620   cache_addr_str (addr_buf, ADDR_WIDTH, insn_word, size);
1621 
1622   if (size == 8)
1623     snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", reg_name, pair_name, addr_buf);
1624   else
1625     snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_name, addr_buf);
1626 
1627   print_insn (outf, "", template->name, buf);
1628 }
1629 
1630 /* Print a CACHEW instruction.  */
1631 static void
print_cachew(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1632 print_cachew (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1633 	      const insn_template *template,
1634 	      disassemble_info *outf)
1635 {
1636   char buf[OPERAND_WIDTH];
1637   char addr_buf[ADDR_WIDTH];
1638   unsigned int reg_unit, reg_no;
1639   unsigned int size = ((insn_word >> 1) & 0x1) ? 8 : 4;
1640   const char *reg_name;
1641   const char *pair_name;
1642 
1643   reg_unit = short_unit ((insn_word >> 3) & SHORT_UNIT_MASK);
1644   reg_no = (insn_word >> 19) & REG_MASK;
1645 
1646   reg_name = lookup_reg_name (reg_unit, reg_no);
1647   pair_name = lookup_pair_reg_name (reg_unit, reg_no);
1648 
1649   cache_addr_str (addr_buf, ADDR_WIDTH, insn_word, 64);
1650 
1651   if (size == 8)
1652     snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", addr_buf, reg_name, pair_name);
1653   else
1654     snprintf (buf, OPERAND_WIDTH, "%s,%s", addr_buf, reg_name);
1655 
1656   print_insn (outf, "", template->name, buf);
1657 }
1658 
1659 /* Print an ICACHE instruction.  */
1660 static void
print_icache(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1661 print_icache (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1662 	      const insn_template *template,
1663 	      disassemble_info *outf)
1664 {
1665   char buf[OPERAND_WIDTH];
1666   int offset;
1667   int pfcount;
1668 
1669   offset = ((insn_word >> 9) & IMM15_MASK);
1670   pfcount = ((insn_word >> 1) & IMM4_MASK);
1671 
1672   offset = sign_extend (offset, IMM15_BITS);
1673 
1674   if (pfcount)
1675     snprintf (buf, OPERAND_WIDTH, "#%d,#0x%x", offset, pfcount);
1676   else
1677     snprintf (buf, OPERAND_WIDTH, "#%d,#0", offset);
1678   print_insn (outf, "", template->name, buf);
1679 }
1680 
1681 /* Print a LNKGET instruction.  */
1682 static void
print_lnkget(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1683 print_lnkget (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1684 	      const insn_template *template,
1685 	      disassemble_info *outf)
1686 {
1687   char buf[OPERAND_WIDTH];
1688   char addr_buf[ADDR_WIDTH];
1689   unsigned int reg_unit, reg_no;
1690   unsigned int size = metag_get_set_ext_size_bytes (insn_word);
1691   const char *reg_name;
1692   const char *pair_name;
1693 
1694   reg_unit = short_unit ((insn_word >> 3) & SHORT_UNIT_MASK);
1695   reg_no = (insn_word >> 19) & REG_MASK;
1696 
1697   reg_name = lookup_reg_name (reg_unit, reg_no);
1698   pair_name = lookup_pair_reg_name (reg_unit, reg_no);
1699 
1700   cache_addr_str (addr_buf, ADDR_WIDTH, insn_word, size);
1701 
1702   if (size == 8)
1703     snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", reg_name, pair_name, addr_buf);
1704   else
1705     snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_name, addr_buf);
1706 
1707   print_insn (outf, "", template->name, buf);
1708 }
1709 
1710 /* Print an FPU MOV instruction.  */
1711 static void
print_fmov(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1712 print_fmov (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1713 	    const insn_template *template,
1714 	    disassemble_info *outf)
1715 {
1716   char buf[OPERAND_WIDTH];
1717   char prefix_buf[10];
1718   unsigned int src_no, dest_no;
1719   unsigned int p = (insn_word >> 6) & 0x1;
1720   unsigned int d = (insn_word >> 5) & 0x1;
1721   unsigned int cc = (insn_word >> 1) & CC_MASK;
1722   bfd_boolean show_cond = cc != COND_A && cc != COND_NV;
1723   const char *dest_reg;
1724   const char *src_reg;
1725   const char *cc_flags;
1726 
1727   dest_no = (insn_word >> 19) & REG_MASK;
1728   src_no = (insn_word >> 14) & REG_MASK;
1729 
1730   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
1731   src_reg = lookup_reg_name (UNIT_FX, src_no);
1732 
1733   cc_flags = lookup_fpu_scc_flags (cc);
1734 
1735   snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg);
1736 
1737   snprintf (prefix_buf, 10, "F%s%s%s", p ? "L" : "",
1738 	    d ? "D" : "", show_cond ? cc_flags : "");
1739 
1740   print_insn (outf, prefix_buf, template->name, buf);
1741 }
1742 
1743 /* Convert an FPU rmask into a compatible form. */
1744 static unsigned int
convert_fx_rmask(unsigned int rmask)1745 convert_fx_rmask (unsigned int rmask)
1746 {
1747   int num_bits = hweight (rmask), i;
1748   unsigned int ret = 0;
1749 
1750   for (i = 0; i < num_bits; i++)
1751     {
1752       ret <<= 1;
1753       ret |= 0x1;
1754     }
1755 
1756   return ret;
1757 }
1758 
1759 /* Print an FPU MMOV instruction.  */
1760 static void
print_fmmov(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1761 print_fmmov (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1762 	    const insn_template *template,
1763 	    disassemble_info *outf)
1764 {
1765   char buf[OPERAND_WIDTH];
1766   char data_buf[REG_WIDTH];
1767   char fpu_buf[REG_WIDTH];
1768   bfd_boolean to_fpu = MAJOR_OPCODE (insn_word) == OPC_GET;
1769   bfd_boolean is_mmovl = MINOR_OPCODE (insn_word) & 0x1;
1770   unsigned int rmask = (insn_word >> 7) & RMASK_MASK;
1771   unsigned int fpu_no, data_no, data_unit;
1772 
1773   data_no = (insn_word >> 19) & REG_MASK;
1774   fpu_no = (insn_word >> 14) & REG_MASK;
1775 
1776   if (insn_word & 0x1)
1777     data_unit = UNIT_D1;
1778   else
1779     data_unit = UNIT_D0;
1780 
1781   lookup_reg_list (data_buf, REG_WIDTH, data_unit, data_no, rmask, FALSE);
1782   lookup_reg_list (fpu_buf, REG_WIDTH, UNIT_FX, fpu_no,
1783 		   convert_fx_rmask (rmask), is_mmovl);
1784 
1785   if (to_fpu)
1786     snprintf (buf, OPERAND_WIDTH, "%s,%s", fpu_buf, data_buf);
1787   else
1788     snprintf (buf, OPERAND_WIDTH, "%s,%s", data_buf, fpu_buf);
1789 
1790   print_insn (outf, "F", template->name, buf);
1791 }
1792 
1793 /* Print an FPU data unit MOV instruction.  */
1794 static void
print_fmov_data(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1795 print_fmov_data (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1796 		 const insn_template *template,
1797 		 disassemble_info *outf)
1798 {
1799   char buf[OPERAND_WIDTH];
1800   unsigned int src_no, dest_no;
1801   unsigned int to_fpu = ((insn_word >> 7) & 0x1);
1802   unsigned int unit_bit = (insn_word >> 24) & 0x1;
1803   enum metag_unit base_unit;
1804   const char *dest_reg;
1805   const char *src_reg;
1806 
1807   dest_no = (insn_word >> 19) & REG_MASK;
1808   src_no = (insn_word >> 9) & REG_MASK;
1809 
1810   if (unit_bit)
1811     base_unit = UNIT_D1;
1812   else
1813     base_unit = UNIT_D0;
1814 
1815   if (to_fpu)
1816     {
1817       dest_reg = lookup_reg_name (UNIT_FX, dest_no);
1818       src_reg = lookup_reg_name (base_unit, src_no);
1819     }
1820   else
1821     {
1822       dest_reg = lookup_reg_name (base_unit, dest_no);
1823       src_reg = lookup_reg_name (UNIT_FX, src_no);
1824     }
1825 
1826   snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg);
1827 
1828   print_insn (outf, "F", template->name, buf);
1829 }
1830 
1831 /* Print an FPU MOV immediate instruction.  */
1832 static void
print_fmov_i(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1833 print_fmov_i (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1834 	      const insn_template *template,
1835 	      disassemble_info *outf)
1836 {
1837   char buf[OPERAND_WIDTH];
1838   unsigned int dest_no;
1839   unsigned int p = (insn_word >> 2) & 0x1;
1840   unsigned int d = (insn_word >> 1) & 0x1;
1841   const char *dest_reg;
1842   unsigned int value = (insn_word >> 3) & IMM16_MASK;
1843 
1844   dest_no = (insn_word >> 19) & REG_MASK;
1845 
1846   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
1847 
1848   snprintf (buf, OPERAND_WIDTH, "%s,#%#x", dest_reg, value);
1849 
1850   if (p)
1851     print_insn (outf, "FL", template->name, buf);
1852   else if (d)
1853     print_insn (outf, "FD", template->name, buf);
1854   else
1855     print_insn (outf, "F", template->name, buf);
1856 }
1857 
1858 /* Print an FPU PACK instruction.  */
1859 static void
print_fpack(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1860 print_fpack (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1861 	     const insn_template *template,
1862 	     disassemble_info *outf)
1863 {
1864   char buf[OPERAND_WIDTH];
1865   unsigned int src1_no, src2_no, dest_no;
1866   const char *dest_reg;
1867   const char *src1_reg;
1868   const char *src2_reg;
1869 
1870   dest_no = (insn_word >> 19) & REG_MASK;
1871   src1_no = (insn_word >> 14) & REG_MASK;
1872   src2_no = (insn_word >> 9) & REG_MASK;
1873 
1874   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
1875   src1_reg = lookup_reg_name (UNIT_FX, src1_no);
1876   src2_reg = lookup_reg_name (UNIT_FX, src2_no);
1877 
1878   snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg);
1879 
1880   print_insn (outf, "F", template->name, buf);
1881 }
1882 
1883 /* Print an FPU SWAP instruction.  */
1884 static void
print_fswap(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1885 print_fswap (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1886 	     const insn_template *template,
1887 	     disassemble_info *outf)
1888 {
1889   char buf[OPERAND_WIDTH];
1890   unsigned int src_no, dest_no;
1891   const char *dest_reg;
1892   const char *src_reg;
1893 
1894   dest_no = (insn_word >> 19) & REG_MASK;
1895   src_no = (insn_word >> 14) & REG_MASK;
1896 
1897   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
1898   src_reg = lookup_reg_name (UNIT_FX, src_no);
1899 
1900   snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg);
1901 
1902   print_insn (outf, "FL", template->name, buf);
1903 }
1904 
1905 /* Print an FPU CMP instruction.  */
1906 static void
print_fcmp(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1907 print_fcmp (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1908 	    const insn_template *template,
1909 	    disassemble_info *outf)
1910 {
1911   char buf[OPERAND_WIDTH];
1912   char prefix_buf[10];
1913   unsigned int src_no, dest_no;
1914   unsigned int a = (insn_word >> 19) & 0x1;
1915   unsigned int z = (insn_word >> 8) & 0x1;
1916   unsigned int p = (insn_word >> 6) & 0x1;
1917   unsigned int d = (insn_word >> 5) & 0x1;
1918   unsigned int q = (insn_word >> 7) & 0x1;
1919   unsigned int cc = (insn_word >> 1) & CC_MASK;
1920   bfd_boolean show_cond = cc != COND_A && cc != COND_NV;
1921   const char *dest_reg;
1922   const char *src_reg;
1923   const char *cc_flags;
1924 
1925   dest_no = (insn_word >> 14) & REG_MASK;
1926   src_no = (insn_word >> 9) & REG_MASK;
1927 
1928   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
1929   src_reg = lookup_reg_name (UNIT_FX, src_no);
1930 
1931   cc_flags = lookup_fpu_scc_flags (cc);
1932 
1933   if (z)
1934     snprintf (buf, OPERAND_WIDTH, "%s,#0", dest_reg);
1935   else
1936     snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg);
1937 
1938   snprintf (prefix_buf, 10, "F%s%s%s%s%s", p ? "L" : "",
1939 	    d ? "D" : "", a ? "A" : "", q ? "Q" : "",
1940 	    show_cond ? cc_flags : "");
1941 
1942   print_insn (outf, prefix_buf, template->name, buf);
1943 }
1944 
1945 /* Print an FPU MIN or MAX instruction.  */
1946 static void
print_fminmax(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1947 print_fminmax (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1948 	       const insn_template *template,
1949 	       disassemble_info *outf)
1950 {
1951   char buf[OPERAND_WIDTH];
1952   char prefix_buf[10];
1953   unsigned int p = (insn_word >> 6) & 0x1;
1954   unsigned int d = (insn_word >> 5) & 0x1;
1955   unsigned int src1_no, src2_no, dest_no;
1956   unsigned int cc = (insn_word >> 1) & CC_MASK;
1957   bfd_boolean show_cond = cc != COND_A && cc != COND_NV;
1958   const char *dest_reg;
1959   const char *src1_reg;
1960   const char *src2_reg;
1961   const char *cc_flags;
1962 
1963   dest_no = (insn_word >> 19) & REG_MASK;
1964   src1_no = (insn_word >> 14) & REG_MASK;
1965   src2_no = (insn_word >> 9) & REG_MASK;
1966 
1967   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
1968   src1_reg = lookup_reg_name (UNIT_FX, src1_no);
1969   src2_reg = lookup_reg_name (UNIT_FX, src2_no);
1970 
1971   cc_flags = lookup_fpu_scc_flags (cc);
1972 
1973   snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg);
1974 
1975   snprintf (prefix_buf, 10, "F%s%s%s", p ? "L" : "",
1976 	    d ? "D" : "", show_cond ? cc_flags : "");
1977 
1978   print_insn (outf, prefix_buf, template->name, buf);
1979 }
1980 
1981 /* Print an FPU data conversion instruction.  */
1982 static void
print_fconv(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1983 print_fconv (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1984 	     const insn_template *template,
1985 	     disassemble_info *outf)
1986 {
1987   char buf[OPERAND_WIDTH];
1988   char prefix_buf[10];
1989   unsigned int p = (insn_word >> 6) & 0x1;
1990   unsigned int z = (insn_word >> 12) & 0x1;
1991   unsigned int src_no, dest_no;
1992   unsigned int cc = (insn_word >> 1) & CC_MASK;
1993   bfd_boolean show_cond = cc != COND_A && cc != COND_NV;
1994   const char *dest_reg;
1995   const char *src_reg;
1996   const char *cc_flags;
1997 
1998   dest_no = (insn_word >> 19) & REG_MASK;
1999   src_no = (insn_word >> 14) & REG_MASK;
2000 
2001   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
2002   src_reg = lookup_reg_name (UNIT_FX, src_no);
2003 
2004   cc_flags = lookup_fpu_scc_flags (cc);
2005 
2006   snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg);
2007 
2008   snprintf (prefix_buf, 10, "F%s%s%s", p ? "L" : "",
2009 	    z ? "Z" : "", show_cond ? cc_flags : "");
2010 
2011   print_insn (outf, prefix_buf, template->name, buf);
2012 }
2013 
2014 /* Print an FPU extended data conversion instruction.  */
2015 static void
print_fconvx(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)2016 print_fconvx (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2017 	      const insn_template *template,
2018 	      disassemble_info *outf)
2019 {
2020   char buf[OPERAND_WIDTH];
2021   char prefix_buf[10];
2022   unsigned int p = (insn_word >> 6) & 0x1;
2023   unsigned int xl = (insn_word >> 7) & 0x1;
2024   unsigned int src_no, dest_no, fraction_bits;
2025   unsigned int cc = (insn_word >> 1) & CC_MASK;
2026   bfd_boolean show_cond = cc != COND_A && cc != COND_NV;
2027   const char *dest_reg;
2028   const char *src_reg;
2029   const char *cc_flags;
2030 
2031   dest_no = (insn_word >> 19) & REG_MASK;
2032   src_no = (insn_word >> 14) & REG_MASK;
2033 
2034   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
2035   src_reg = lookup_reg_name (UNIT_FX, src_no);
2036 
2037   cc_flags = lookup_fpu_scc_flags (cc);
2038 
2039   if (xl)
2040     fraction_bits = (insn_word >> 8) & IMM6_MASK;
2041   else
2042     fraction_bits = (insn_word >> 9) & IMM5_MASK;
2043 
2044   snprintf (buf, OPERAND_WIDTH, "%s,%s,#%#x", dest_reg, src_reg,
2045 	    fraction_bits);
2046 
2047   snprintf (prefix_buf, 10, "F%s%s", p ? "L" : "",
2048 	    show_cond ? cc_flags : "");
2049 
2050   print_insn (outf, prefix_buf, template->name, buf);
2051 }
2052 
2053 /* Print an FPU basic arithmetic instruction.  */
2054 static void
print_fbarith(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)2055 print_fbarith (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2056 	       const insn_template *template,
2057 	       disassemble_info *outf)
2058 {
2059   char buf[OPERAND_WIDTH];
2060   char prefix_buf[10];
2061   unsigned int n = (insn_word >> 7) & 0x1;
2062   unsigned int p = (insn_word >> 6) & 0x1;
2063   unsigned int d = (insn_word >> 5) & 0x1;
2064   unsigned int src1_no, src2_no, dest_no;
2065   unsigned int cc = (insn_word >> 1) & CC_MASK;
2066   bfd_boolean show_cond = cc != COND_A && cc != COND_NV;
2067   const char *dest_reg;
2068   const char *src1_reg;
2069   const char *src2_reg;
2070   const char *cc_flags;
2071 
2072   dest_no = (insn_word >> 19) & REG_MASK;
2073   src1_no = (insn_word >> 14) & REG_MASK;
2074   src2_no = (insn_word >> 9) & REG_MASK;
2075 
2076   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
2077   src1_reg = lookup_reg_name (UNIT_FX, src1_no);
2078   src2_reg = lookup_reg_name (UNIT_FX, src2_no);
2079 
2080   cc_flags = lookup_fpu_scc_flags (cc);
2081 
2082   snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg);
2083 
2084   snprintf (prefix_buf, 10, "F%s%s%s%s", p ? "L" : "",
2085 	    d ? "D" : "", n ? "I" : "", show_cond ? cc_flags : "");
2086 
2087   print_insn (outf, prefix_buf, template->name, buf);
2088 }
2089 
2090 /* Print an FPU extended arithmetic instruction.  */
2091 static void
print_fearith(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)2092 print_fearith (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2093 	       const insn_template *template,
2094 	       disassemble_info *outf)
2095 {
2096   char buf[OPERAND_WIDTH];
2097   char prefix_buf[10];
2098   bfd_boolean is_muz = (MINOR_OPCODE (insn_word) == 0x6 &&
2099 			((insn_word >> 4) & 0x1));
2100   bfd_boolean is_mac = (MINOR_OPCODE (insn_word) == 0x6 &&
2101 			(insn_word & 0x1f) == 0);
2102   bfd_boolean is_maw = (MINOR_OPCODE (insn_word) == 0x6 &&
2103 			((insn_word >> 3) & 0x1));
2104   unsigned int o3o = insn_word & 0x1;
2105   unsigned int q = is_muz && ((insn_word >> 1) & 0x1);
2106   unsigned int n = (insn_word >> 7) & 0x1;
2107   unsigned int p = (insn_word >> 6) & 0x1;
2108   unsigned int d = (insn_word >> 5) & 0x1;
2109   unsigned int cc = (insn_word >> 1) & CC_MASK;
2110   bfd_boolean show_cond = (MINOR_OPCODE (insn_word) == 0x5 && cc != COND_A &&
2111 			   cc != COND_NV);
2112   unsigned int src1_no, src2_no, dest_no;
2113   const char *dest_reg;
2114   const char *src1_reg;
2115   const char *src2_reg;
2116   const char *cc_flags;
2117 
2118   dest_no = (insn_word >> 19) & REG_MASK;
2119   src1_no = (insn_word >> 14) & REG_MASK;
2120   src2_no = (insn_word >> 9) & REG_MASK;
2121 
2122   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
2123   src1_reg = lookup_reg_name (UNIT_FX, src1_no);
2124   src2_reg = lookup_reg_name (UNIT_FX, src2_no);
2125 
2126   cc_flags = lookup_fpu_scc_flags (cc);
2127 
2128   if (is_mac)
2129     snprintf (buf, OPERAND_WIDTH, "ACF.0,%s,%s", src1_reg, src2_reg);
2130   else if (o3o && is_maw)
2131     snprintf (buf, OPERAND_WIDTH, "%s,%s", src1_reg, src2_reg);
2132   else
2133     snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg);
2134 
2135   snprintf (prefix_buf, 10, "F%s%s%s%s%s", p ? "L" : "",
2136 	    d ? "D" : "", n ? "I" : "", q ? "Q" : "",
2137 	    show_cond ? cc_flags : "");
2138 
2139   print_insn (outf, prefix_buf, template->name, buf);
2140 }
2141 
2142 /* Print an FPU RCP or RSQ instruction.  */
2143 static void
print_frec(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)2144 print_frec (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2145 	    const insn_template *template,
2146 	    disassemble_info *outf)
2147 {
2148   char buf[OPERAND_WIDTH];
2149   char prefix_buf[10];
2150   unsigned int z = (insn_word >> 10) & 0x1;
2151   unsigned int q = (insn_word >> 9) & 0x1;
2152   unsigned int n = (insn_word >> 7) & 0x1;
2153   unsigned int p = (insn_word >> 6) & 0x1;
2154   unsigned int d = (insn_word >> 5) & 0x1;
2155   unsigned int src_no, dest_no;
2156   const char *dest_reg;
2157   const char *src_reg;
2158 
2159   dest_no = (insn_word >> 19) & REG_MASK;
2160   src_no = (insn_word >> 14) & REG_MASK;
2161 
2162   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
2163   src_reg = lookup_reg_name (UNIT_FX, src_no);
2164 
2165   snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg);
2166 
2167   snprintf (prefix_buf, 10, "F%s%s%s%s%s", p ? "L" : "",
2168 	    d ? "D" : "", n ? "I" : "", q ? "Q" : "", z ? "Z" : "");
2169 
2170   print_insn (outf, prefix_buf, template->name, buf);
2171 }
2172 
2173 static void
print_fsimd(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)2174 print_fsimd (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2175 	     const insn_template *template,
2176 	     disassemble_info *outf)
2177 {
2178   char buf[OPERAND_WIDTH];
2179   unsigned int n = (insn_word >> 7) & 0x1;
2180   unsigned int src1_no, src2_no, dest_no;
2181   const char *dest_reg;
2182   const char *src1_reg;
2183   const char *src2_reg;
2184 
2185   dest_no = (insn_word >> 19) & REG_MASK;
2186   src1_no = (insn_word >> 14) & REG_MASK;
2187   src2_no = (insn_word >> 9) & REG_MASK;
2188 
2189   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
2190   src1_reg = lookup_reg_name (UNIT_FX, src1_no);
2191   src2_reg = lookup_reg_name (UNIT_FX, src2_no);
2192 
2193   snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg);
2194 
2195   if (n)
2196     print_insn (outf, "FLI", template->name, buf);
2197   else
2198     print_insn (outf, "FL", template->name, buf);
2199 }
2200 
2201 /* Print an FPU accumulator GET or SET instruction.  */
2202 static void
print_fget_set_acf(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)2203 print_fget_set_acf (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2204 		    const insn_template *template,
2205 		    disassemble_info *outf)
2206 {
2207   bfd_boolean is_get = MAJOR_OPCODE (template->meta_opcode) == OPC_GET;
2208   char buf[OPERAND_WIDTH];
2209   char addr_buf[ADDR_WIDTH];
2210   unsigned int part;
2211   const char *reg_name;
2212 
2213   part = (insn_word >> 19) & ACF_PART_MASK;
2214 
2215   reg_name = lookup_acf_name (part);
2216 
2217   mget_mset_addr_str (addr_buf, ADDR_WIDTH, insn_word);
2218 
2219   if (is_get)
2220     {
2221       snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_name, addr_buf);
2222     }
2223   else
2224     {
2225       snprintf (buf, OPERAND_WIDTH, "%s,%s", addr_buf, reg_name);
2226     }
2227   print_insn (outf, "F", template->name, buf);
2228 }
2229 
2230 /* Return the name of the DSP register or accumulator for NUM and UNIT.  */
2231 static const char *
__lookup_dsp_name(unsigned int num,unsigned int unit)2232 __lookup_dsp_name (unsigned int num, unsigned int unit)
2233 {
2234   size_t i;
2235 
2236   for (i = 0; i < sizeof(metag_dsp_regtab)/sizeof(metag_dsp_regtab[0]); i++)
2237     {
2238       const metag_reg *reg = &metag_dsp_regtab[i];
2239 
2240       if (reg->no == num)
2241 	{
2242 	  if ((reg->unit == UNIT_RAM_D0 || reg->unit == UNIT_ACC_D0) &&
2243 	      unit == UNIT_D0)
2244 	    return reg->name;
2245 
2246 	  if ((reg->unit == UNIT_RAM_D1 || reg->unit == UNIT_ACC_D1) &&
2247 	      unit == UNIT_D1)
2248 	    return reg->name;
2249 	}
2250     }
2251   return "?.?";
2252 }
2253 
2254 /* Return the name of the DSP register for NUM and UNIT.  */
2255 static const char *
lookup_dsp_name(unsigned int num,unsigned int unit)2256 lookup_dsp_name (unsigned int num, unsigned int unit)
2257 {
2258   size_t i;
2259 
2260   for (i = 0; i < sizeof(metag_dsp_regtab)/sizeof(metag_dsp_regtab[0]); i++)
2261     {
2262       const metag_reg *reg = &metag_dsp_regtab[i];
2263 
2264       if (reg->no == num && reg->unit == unit)
2265 	return reg->name;
2266     }
2267   return "?.?";
2268 }
2269 
2270 /* Return the name of the DSP RAM register for NUM and UNIT.  */
2271 static const char *
lookup_dspram_name(unsigned int num,unsigned int unit,bfd_boolean load)2272 lookup_dspram_name (unsigned int num, unsigned int unit, bfd_boolean load)
2273 {
2274   size_t i, nentries;
2275 
2276   nentries = sizeof(metag_dsp_tmpl_regtab[load])/sizeof(metag_dsp_tmpl_regtab[load][0]);
2277 
2278   for (i = 0; i < nentries; i++)
2279     {
2280       const metag_reg *reg = &metag_dsp_tmpl_regtab[load][i];
2281 
2282       if (reg->no == num && reg->unit == unit)
2283 	return reg->name;
2284     }
2285   return "?.?";
2286 }
2287 
2288 /* This lookup function looks up the corresponding name for a register
2289    number in a DSP instruction. SOURCE indicates whether this
2290    register is a source or destination operand.  */
2291 static const char *
lookup_any_reg_name(unsigned int unit,unsigned int num,bfd_boolean source)2292 lookup_any_reg_name (unsigned int unit, unsigned int num, bfd_boolean source)
2293 {
2294   /* A register with the top bit set (5th bit) indicates a DSPRAM
2295      register.  */
2296   if (num > 15)
2297     {
2298       unsigned int dunit = (unit == UNIT_D0) ? UNIT_RAM_D0 : UNIT_RAM_D1;
2299       return lookup_dspram_name (num, dunit, source);
2300     }
2301   else
2302     return lookup_reg_name (unit, num);
2303 }
2304 
2305 /* Return the DSP data unit for UNIT.  */
2306 static inline enum metag_unit
dsp_data_unit_to_sym(unsigned int unit)2307 dsp_data_unit_to_sym (unsigned int unit)
2308 {
2309   if (unit == 0)
2310     return UNIT_D0;
2311   else
2312     return UNIT_D1;
2313 }
2314 
2315 /* Print a DSP GET or SET instruction.  */
2316 static void
print_dget_set(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)2317 print_dget_set (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2318 		const insn_template *template,
2319 		disassemble_info *outf)
2320 {
2321   bfd_boolean is_get = (template->meta_opcode & 0x100);
2322   char buf[OPERAND_WIDTH];
2323   char addr_buf[ADDR_WIDTH];
2324   char prefix[DSP_PREFIX_WIDTH];
2325   unsigned int part;
2326   const char *reg_name[2];
2327   bfd_boolean is_high = FALSE;
2328   bfd_boolean is_dual = (insn_word & 0x4);
2329   bfd_boolean is_template = (insn_word & 0x2);
2330   const char *base_reg = "?";
2331   unsigned int addr_unit, base_no, unit;
2332 
2333   unit = dsp_data_unit_to_sym (insn_word & 0x1);
2334 
2335   /* Is this a load/store to a template table?  */
2336   if (is_template)
2337     {
2338       part = (insn_word >> 19) & 0x1f;
2339       reg_name[0] = lookup_dsp_name (part, UNIT_DT);
2340     }
2341   else
2342     {
2343       part = (insn_word >> 19) & REG_MASK;
2344       is_high = ((part & 0x18) == 0x18);
2345 
2346       /* Strip bit high indicator.  */
2347       if (is_high)
2348 	part &= 0x17;
2349 
2350       reg_name[0] = __lookup_dsp_name (part, unit);
2351 
2352     }
2353 
2354   /* Is this a dual unit DSP operation?  The modulo operator below
2355      makes sure that we print the Rd register in the correct order,
2356      e.g. because there's only one bit in the instruction for the Data
2357      Unit we have to work out what the other data unit number is.
2358      (there's only 2).  */
2359   if (is_dual)
2360     {
2361       unsigned int _unit = insn_word & 0x1;
2362 
2363       _unit = ((_unit + 1) % 2);
2364       reg_name[1] = __lookup_dsp_name(part, dsp_data_unit_to_sym (_unit));
2365     }
2366   else
2367     reg_name[1] = NULL;
2368 
2369   addr_unit = ((insn_word >> 18) & 0x1);
2370   if (addr_unit == 0)
2371 	  addr_unit = UNIT_A0;
2372   else
2373 	  addr_unit = UNIT_A1;
2374 
2375   base_no = (insn_word >> 14) & DSP_REG_MASK;
2376 
2377   base_reg = lookup_reg_name (addr_unit, base_no);
2378 
2379   /* Check if it's a post-increment/post-decrement.  */
2380   if (insn_word & 0x2000)
2381   {
2382 	  unsigned int imm = (insn_word >> 9) & DGET_SET_IMM_MASK;
2383 	  const char *post_op;
2384 
2385 	  switch (imm)
2386 	    {
2387 	    case 0x1:
2388 	      post_op = "++";
2389 	      break;
2390 	    case 0x3:
2391 	      post_op = "--";
2392 	      break;
2393 	    default:
2394 	      post_op = "";
2395 	    }
2396 
2397 	  snprintf (addr_buf, ADDR_WIDTH, "[%s%s]", base_reg, post_op);
2398   }
2399   else
2400   {
2401 	  unsigned int offset_part = (insn_word >> 9) & DSP_REG_MASK;
2402 	  const char *offset_reg = lookup_reg_name (addr_unit, offset_part);
2403 
2404 	  snprintf (addr_buf, ADDR_WIDTH, "[%s+%s++]", base_reg, offset_reg);
2405   }
2406 
2407   if (is_get)
2408     {
2409       if (is_dual && !is_template)
2410 	snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", reg_name[0],
2411 		  reg_name[1], addr_buf);
2412       else
2413 	snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_name[0], addr_buf);
2414     }
2415   else
2416     {
2417       if (is_dual && !is_template)
2418 	snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", addr_buf,
2419 		  reg_name[0], reg_name[1]);
2420       else
2421 	snprintf (buf, OPERAND_WIDTH, "%s,%s", addr_buf, reg_name[0]);
2422     }
2423 
2424   snprintf (prefix, DSP_PREFIX_WIDTH, "D%s", is_high ? "H" : "");
2425   print_insn (outf, prefix, template->name, buf);
2426 }
2427 
2428 /* Print a DSP template instruction.  */
2429 static void
print_dtemplate(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)2430 print_dtemplate (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2431 		 const insn_template *template,
2432 		 disassemble_info *outf)
2433 {
2434   char buf[OPERAND_WIDTH];
2435   char prefix[DSP_PREFIX_WIDTH];
2436   unsigned int offset[4];
2437   bfd_boolean is_half = (MINOR_OPCODE (insn_word) == 0x5);
2438   bfd_boolean daop_only = (MINOR_OPCODE (insn_word) == 0x3);
2439 
2440   offset[0] = ((insn_word >> 19) & REG_MASK);
2441   offset[1] = ((insn_word >> 14) & REG_MASK);
2442   offset[2] = ((insn_word >> 9) & REG_MASK);
2443   offset[3] = ((insn_word >> 4) & REG_MASK);
2444 
2445   if (daop_only)
2446 	  snprintf (buf, OPERAND_WIDTH, "#0x%x,#0x%x,#0x%x", offset[0],
2447 		    offset[1], offset[2]);
2448   else
2449     {
2450       snprintf (buf, OPERAND_WIDTH, "#0x%x,#0x%x,#0x%x,#0x%x", offset[0],
2451 		offset[1], offset[2], offset[3]);
2452     }
2453 
2454   snprintf (prefix, DSP_PREFIX_WIDTH, "D%s", is_half ? "H" : "");
2455   print_insn (outf, prefix, template->name, buf);
2456 }
2457 
2458 /* Format template definition from INSN_WORD into BUF.  */
2459 static void
decode_template_definition(unsigned int insn_word,char * buf,size_t len)2460 decode_template_definition(unsigned int insn_word, char *buf, size_t len)
2461 {
2462   bfd_boolean load = ((insn_word >> 13) & 0x1);
2463   bfd_boolean dspram = (((insn_word >> 17) & 0x3) == 0x3);
2464   const char *template[1];
2465   unsigned int tidx = ((insn_word >> 9) & TEMPLATE_REGS_MASK);
2466   enum metag_unit au, ram_unit;
2467   unsigned int addr_reg_nums[2];
2468   const char *addr_reg_names[2];
2469   const char *post_op = "";
2470   const char *join_op = "";
2471   enum metag_unit data_unit = ((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0;
2472 
2473   template[0] = lookup_dsp_name (tidx, UNIT_DT);
2474 
2475   addr_reg_names[1] = "";
2476 
2477   if (dspram)
2478     {
2479       ram_unit = (data_unit == UNIT_D0) ? UNIT_RAM_D0 : UNIT_RAM_D1;
2480       addr_reg_nums[0] = ((insn_word >> 19) & REG_MASK);
2481       addr_reg_names[0] = lookup_dspram_name (addr_reg_nums[0],
2482 					      ram_unit, load);
2483     }
2484   else
2485     {
2486       bfd_boolean im = (((insn_word >> 18) & 0x1) != 0);
2487 
2488       au = (((insn_word >> 23) & 0x1) == 0) ? UNIT_A0 : UNIT_A1;
2489       addr_reg_nums[0] = ((insn_word >> 19) & DSP_REG_MASK);
2490 
2491       addr_reg_names[0] = lookup_reg_name (au, addr_reg_nums[0]);
2492 
2493       if (im)
2494 	{
2495 	  unsigned int im_value = ((insn_word >> 14) & 0x3);
2496 
2497 	  switch (im_value)
2498 	    {
2499 	    case 0x1:
2500 	      post_op = "++";
2501 	      break;
2502 	    case 0x3:
2503 	      post_op = "--";
2504 	      break;
2505 	    }
2506 	}
2507       else
2508 	{
2509 	  addr_reg_nums[1] = ((insn_word >> 14) & DSP_REG_MASK);
2510 	  addr_reg_names[1] = lookup_reg_name (au, addr_reg_nums[1]);
2511 	  join_op = "+";
2512 	  post_op = "++";
2513 	}
2514     }
2515 
2516   if (load)
2517     {
2518       len = snprintf (buf, len, " %s,[%s%s%s%s]", template[0], addr_reg_names[0],
2519 		      join_op, addr_reg_names[1], post_op);
2520     }
2521   else
2522     {
2523       len = snprintf (buf, len, " [%s%s%s%s],%s", addr_reg_names[0], join_op,
2524 		      addr_reg_names[1], post_op, template[0]);
2525     }
2526 }
2527 
2528 /* Print a DSP ALU instruction.  */
2529 static void
print_dalu(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)2530 print_dalu (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2531 	    const insn_template *template,
2532 	    disassemble_info *outf)
2533 {
2534   bfd_boolean is_dual = FALSE;
2535   unsigned int data_unit = (((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0);
2536   const char *reg_names[3];
2537   unsigned int reg_nums[3];
2538   bfd_boolean ac = ((insn_word >> 7) & 0x1);
2539   char buf[OPERAND_WIDTH];
2540   char prefix[DSP_PREFIX_WIDTH];
2541   size_t len;
2542   bfd_boolean is_mod = FALSE;
2543   bfd_boolean is_overflow = FALSE;
2544   unsigned int reg_brackets[3];
2545   bfd_boolean is_w_mx = FALSE;
2546   bfd_boolean is_b_mx = FALSE;
2547   bfd_boolean imm = FALSE;
2548   bfd_boolean is_quickrot64 = FALSE;
2549   bfd_boolean conditional = FALSE;
2550   const char *cc_flags = NULL;
2551   bfd_boolean is_unsigned = FALSE;
2552 
2553   memset (reg_brackets, 0, sizeof (reg_brackets));
2554 
2555   if (template->arg_type & DSP_ARGS_1)
2556     {
2557       bfd_boolean is_template = FALSE;
2558       const char *addr_reg = NULL;
2559       bfd_boolean qr = FALSE;
2560       bfd_boolean is_acc_add = FALSE;
2561       bfd_boolean is_acc_sub = FALSE;
2562       bfd_boolean is_acc_zero = FALSE;
2563       bfd_boolean is_split8 = (template->arg_type & DSP_ARGS_SPLIT8);
2564 
2565       /* Read DU bit.  */
2566       data_unit = ((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0;
2567 
2568       conditional = ((insn_word >> 24) & 0x4);
2569 
2570       /* Templates can't be conditional.  */
2571       is_template = (((insn_word & 0x02000002) == 0x2) && !conditional);
2572 
2573       if (is_split8)
2574 	is_mod = (insn_word & 0x80);
2575 
2576       if (template->arg_type & DSP_ARGS_QR)
2577 	{
2578 	  if (!conditional)
2579 	    is_quickrot64 = ((insn_word >> 5) & 0x1);
2580 	}
2581 
2582       if (template->arg_type & DSP_ARGS_DACC)
2583 	{
2584 	  is_mod = (insn_word & 0x8);
2585 	  is_unsigned = (insn_word & 0x40);
2586 	}
2587 
2588       if (is_template)
2589 	{
2590 	  is_w_mx = (insn_word & 0x1);
2591 	  is_dual = ((insn_word >> 0x4) & 0x1);
2592 
2593 	  /* De.r,Dx.r,De.r|ACe.r */
2594 	  if (template->arg_type & DSP_ARGS_ACC2)
2595 	    {
2596 	      is_mod = (insn_word & 0x8);
2597 	      is_overflow = (insn_word & 0x20);
2598 	    }
2599 
2600 	  /* ACe.e,ACx.r,ACo.e? */
2601 	  if ((template->arg_type & DSP_ARGS_XACC) &&
2602 	      (((insn_word >> 6) & 0x5) == 0x5))
2603 	    {
2604 	      enum metag_unit ac_unit, ao_unit;
2605 
2606 	      ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1;
2607 
2608 	      if (ac_unit == UNIT_ACC_D0)
2609 		ao_unit = UNIT_ACC_D1;
2610 	      else
2611 		ao_unit = UNIT_ACC_D0;
2612 
2613 	      reg_nums[1] = ((insn_word >> 19) & REG_MASK);
2614 
2615 	      /* These are dummy arguments anyway so the register
2616 		 number does not matter.  */
2617 	      reg_names[0] = lookup_dsp_name (16, ac_unit); /* ACe.0 */
2618 	      reg_names[1] = lookup_dsp_name (16, ac_unit); /* ACx.0 */
2619 	      reg_names[2] = lookup_dsp_name (16, ao_unit); /* ACo.0 */
2620 	    }
2621 	  else
2622 	    {
2623 	      /* De.r|ACe.r,Dx.r,De.r */
2624 	      if (template->arg_type & DSP_ARGS_DACC &&
2625 		  ((insn_word & 0x84) != 0))
2626 		{
2627 		  enum metag_unit ac_unit;
2628 
2629 		  ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1;
2630 		  reg_names[0] = lookup_dsp_name (16, ac_unit);
2631 
2632 		  is_acc_zero = ((insn_word & 0x84) == 0x04);
2633 		  is_acc_add = ((insn_word & 0x84) == 0x80);
2634 		  is_acc_sub = ((insn_word & 0x84) == 0x84);
2635 		}
2636 	      else
2637 		reg_names[0] = lookup_any_reg_name (data_unit, 0, FALSE);
2638 
2639 	      /* These are dummy arguments anyway so the register
2640 		 number does not matter.  */
2641 	      reg_names[1] = lookup_any_reg_name (data_unit, 0, TRUE);
2642 
2643 	      /* De.r,Dx.r,De.r|ACe.r */
2644 	      if ((template->arg_type & DSP_ARGS_ACC2) &&
2645 		  ((insn_word & 0x80) == 0x80))
2646 		{
2647 		  enum metag_unit ac_unit;
2648 
2649 		  ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1;
2650 		  reg_names[2] = lookup_dsp_name (16, ac_unit);
2651 		}
2652 	      /* Detection of QUICKRoT and accumulator usage uses the
2653 		 same bits. They are mutually exclusive.  */
2654 	      else if (ac && (template->arg_type & DSP_ARGS_ACC2))
2655 		{
2656 		  reg_nums[2] = ((insn_word >> 9) & REG_MASK);
2657 
2658 		  if (data_unit == UNIT_D0)
2659 		    reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D0);
2660 		  else
2661 		    reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D1);
2662 		}
2663 	      else
2664 		{
2665 		  if ((template->arg_type & DSP_ARGS_QR) &&
2666 		      ((insn_word & 0x40) == 0x40))
2667 		    {
2668 		      enum metag_unit aunit;
2669 		      int reg_no;
2670 
2671 		      if (conditional)
2672 			reg_no = ((insn_word >> 5) & 0x1);
2673 		      else
2674 			reg_no = ((insn_word >> 7) & 0x1);
2675 
2676 		      aunit = (data_unit == UNIT_D0) ? UNIT_A0 : UNIT_A1;
2677 		      addr_reg = lookup_reg_name (aunit, reg_no + 2);
2678 
2679 		      qr = TRUE;
2680 		    }
2681 
2682 		  reg_names[2] = lookup_any_reg_name (data_unit, 0, TRUE);
2683 		}
2684 	    }
2685 
2686 	  if (qr)
2687 	    {
2688 	      len = snprintf (buf, OPERAND_WIDTH, "%s,%s,%s,%s",
2689 			      reg_names[0], reg_names[1], reg_names[2],
2690 			      addr_reg);
2691 	    }
2692 	  else
2693 	    {
2694 	      len = snprintf (buf, OPERAND_WIDTH, "%s,%s,%s%s%s",
2695 			      reg_names[0], reg_names[1],
2696 			      reg_brackets[2] ? "[" : "",
2697 			      reg_names[2], reg_brackets[2] ? "]" : "");
2698 	    }
2699 
2700 	  decode_template_definition (insn_word, buf + len,
2701 				      OPERAND_WIDTH - len);
2702 	}
2703       else			/* Not a template definiton.  */
2704 	{
2705 	  reg_nums[0] = ((insn_word >> 19) & REG_MASK);
2706 	  reg_nums[1] = ((insn_word >> 14) & REG_MASK);
2707 	  reg_nums[2] = ((insn_word >> 9) & REG_MASK);
2708 
2709 	  imm = (((insn_word >> 24) & 0x2) && (template->arg_type & DSP_ARGS_IMM));
2710 
2711 	  if (imm)
2712 	    is_dual = (insn_word & 0x4);
2713 	  else if (!conditional)
2714 	    is_dual = (insn_word & 0x10);
2715 	  else
2716 	    cc_flags = lookup_scc_flags ((insn_word >> 1) & CC_MASK);
2717 
2718 	  /* De.r,Dx.r,De.r|ACe.r */
2719 	  if (template->arg_type & DSP_ARGS_ACC2)
2720 	    {
2721 	      is_mod = (insn_word & 0x8);
2722 	      is_overflow = (insn_word & 0x20);
2723 	    }
2724 
2725 	  if (template->arg_type & DSP_ARGS_SPLIT8)
2726 	    {
2727 	      is_overflow = (insn_word & 0x20);
2728 	    }
2729 
2730 	  /* ACe.e,ACx.r,ACo.e? */
2731 	  if ((template->arg_type & DSP_ARGS_XACC) &&
2732 	      (((insn_word >> 6) & 0x5) == 0x5))
2733 	    {
2734 	      enum metag_unit ac_unit, ao_unit;
2735 
2736 	      ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1;
2737 
2738 	      if (ac_unit == UNIT_ACC_D0)
2739 		ao_unit = UNIT_ACC_D1;
2740 	      else
2741 		ao_unit = UNIT_ACC_D0;
2742 
2743 	      reg_nums[1] = ((insn_word >> 19) & REG_MASK);
2744 	      reg_names[0] = lookup_dsp_name (reg_nums[1], ac_unit);
2745 	      reg_names[1] = lookup_dsp_name (reg_nums[1], ac_unit);
2746 	      reg_names[2] = lookup_dsp_name (reg_nums[1], ao_unit);
2747 	    }
2748 	  else
2749 	    {
2750 	      bfd_boolean o2r = (insn_word & 0x1);
2751 
2752 	      /* De.r|ACe.r,Dx.r,De.r */
2753 	      if ((template->arg_type & DSP_ARGS_DACC) &&
2754 		  ((insn_word & 0x84) != 0))
2755 		{
2756 		  enum metag_unit ac_unit;
2757 
2758 		  ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1;
2759 		  reg_names[0] = lookup_dsp_name (reg_nums[0], ac_unit);
2760 
2761 		  is_acc_zero = ((insn_word & 0x84) == 0x04);
2762 		  is_acc_add = ((insn_word & 0x84) == 0x80);
2763 		  is_acc_sub = ((insn_word & 0x84) == 0x84);
2764 		}
2765 	      else if (conditional)
2766 		{
2767 		  reg_names[0] = lookup_reg_name (data_unit, reg_nums[0]);
2768 		}
2769 	      else
2770 		{
2771 		  reg_names[0] = lookup_any_reg_name (data_unit,
2772 						      reg_nums[0], FALSE);
2773 		  if (reg_nums[0] > 15)
2774 		    reg_brackets[0] = 1;
2775 		}
2776 
2777 	      if (imm)
2778 		{
2779 		  reg_names[1] = lookup_any_reg_name (data_unit, reg_nums[0], TRUE);
2780 
2781 		  if (reg_brackets[0])
2782 		    reg_brackets[1] = 1;
2783 		  }
2784 	      else
2785 		{
2786 		  if (is_split8 && is_mod)
2787 		    {
2788 		      reg_names[1] = lookup_reg_name (data_unit, reg_nums[1]);
2789 		    }
2790 		  else
2791 		  {
2792 		    reg_names[1] = lookup_any_reg_name (data_unit, reg_nums[1], TRUE);
2793 
2794 		    if (reg_nums[1] > 15)
2795 		      reg_brackets[1] = 1;
2796 		  }
2797 		}
2798 
2799 	      /* Detection of QUICKRoT and accumulator usage uses the
2800 		 same bits. They are mutually exclusive.  */
2801 	      if (ac && (template->arg_type & DSP_ARGS_ACC2))
2802 		{
2803 		  if (data_unit == UNIT_D0)
2804 		    reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D0);
2805 		  else
2806 		    reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D1);
2807 		}
2808 
2809 	      else
2810 		{
2811 		  if ((template->arg_type & DSP_ARGS_QR) &&
2812 		      ((insn_word & 0x40) == 0x40))
2813 		    {
2814 		      enum metag_unit aunit;
2815 		      int reg_no;
2816 
2817 		      if (conditional)
2818 			reg_no = ((insn_word >> 5) & 0x1);
2819 		      else
2820 			reg_no = ((insn_word >> 7) & 0x1);
2821 
2822 		      aunit = (data_unit == UNIT_D0) ? UNIT_A0 : UNIT_A1;
2823 		      addr_reg = lookup_reg_name (aunit, reg_no + 2);
2824 
2825 		      qr = TRUE;
2826 		    }
2827 
2828 		  if (o2r)
2829 		    reg_names[2] = lookup_o2r (data_unit, reg_nums[2]);
2830 		  else
2831 		    {
2832 		      /* Can't use a DSPRAM reg if both QD and L1 are
2833 			 set on a QUICKRoT instruction or if we're a
2834 			 split 8.  */
2835 		      if (((template->arg_type & DSP_ARGS_QR)
2836 			   && ((insn_word & 0x30) == 0x30 && !conditional)) ||
2837 			  (is_split8 && is_mod))
2838 			reg_names[2] = lookup_reg_name (data_unit, reg_nums[2]);
2839 		      else
2840 			{
2841 			  reg_names[2] = lookup_any_reg_name (data_unit,
2842 							      reg_nums[2], TRUE);
2843 			  if (reg_nums[2] > 15)
2844 			    reg_brackets[2] = 1;
2845 			}
2846 		    }
2847 		}
2848 	    }
2849 
2850 	  if (qr)
2851 	    {
2852 	      len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,%s%s%s,%s",
2853 			      reg_brackets[0] ? "[" : "",
2854 			      reg_names[0], reg_brackets[0] ? "]" : "",
2855 			      reg_brackets[1] ? "[" : "",
2856 			      reg_names[1], reg_brackets[1] ? "]" : "",
2857 			      reg_brackets[2] ? "[" : "",
2858 			      reg_names[2], reg_brackets[2] ? "]" : "",
2859 			      addr_reg);
2860 	    }
2861 	  else
2862 	    {
2863 	      if (imm)
2864 		{
2865 		  /* Conform to the embedded assembler's policy of
2866 		     printing negative numbers as decimal and positive
2867 		     as hex.  */
2868 		  int value = ((insn_word >> 3) & IMM16_MASK);
2869 
2870 		  if ((value & 0x8000) || value == 0)
2871 		    {
2872 		      value = sign_extend (value, IMM16_BITS);
2873 		      len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,#%d",
2874 				      reg_brackets[0] ? "[" : "",
2875 				      reg_names[0], reg_brackets[0] ? "]" : "",
2876 				      reg_brackets[1] ? "[" : "",
2877 				      reg_names[1], reg_brackets[1] ? "]" : "",
2878 				      value);
2879 		    }
2880 		  else
2881 		    {
2882 		      len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,#%#x",
2883 				      reg_brackets[0] ? "[" : "",
2884 				      reg_names[0], reg_brackets[0] ? "]" : "",
2885 				      reg_brackets[1] ? "[" : "",
2886 				      reg_names[1], reg_brackets[1] ? "]" : "",
2887 				      value);
2888 		    }
2889 		}
2890 	      else
2891 		{
2892 		  len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,%s%s%s",
2893 				  reg_brackets[0] ? "[" : "",
2894 				  reg_names[0], reg_brackets[0] ? "]" : "",
2895 				  reg_brackets[1] ? "[" : "", reg_names[1],
2896 				  reg_brackets[1] ? "]" : "",
2897 				  reg_brackets[2] ? "[" : "",
2898 				  reg_names[2], reg_brackets[2] ? "]" : "");
2899 		}
2900 	    }
2901 	}
2902 
2903       snprintf (prefix, DSP_PREFIX_WIDTH, "D%s%s%s%s%s%s%s%s%s%s%s%s",
2904 		cc_flags ? cc_flags : "",
2905 		is_dual ? "L" : "",
2906 		is_quickrot64 ? "Q" : "",
2907 		is_unsigned ? "U" : "",
2908 		is_mod ? "M" : "",
2909 		is_acc_zero ? "Z" : "",
2910 		is_acc_add ? "P" : "", is_acc_sub ? "N" : "",
2911 		is_overflow ? "O" : "",
2912 		is_w_mx ? "W" : "",
2913 		is_b_mx ? "B" : "",
2914 		is_template ? "T" : "");
2915     }
2916   else if (template->arg_type & DSP_ARGS_2) /* Group 2.  */
2917     {
2918       bfd_boolean is_template;
2919       bfd_boolean o2r = FALSE;
2920       int major = MAJOR_OPCODE (template->meta_opcode);
2921       bfd_boolean is_neg_or_mov = (major == OPC_ADD || major == OPC_SUB);
2922       bfd_boolean is_cmp_tst = ((major == OPC_CMP) &&
2923 				((insn_word & 0x0000002c) == 0));
2924       bfd_boolean is_fpu_mov = template->insn_type == INSN_DSP_FPU;
2925       bfd_boolean to_fpu = (template->meta_opcode >> 7) & 0x1;
2926 
2927       if (major == OPC_9)
2928 	imm = (insn_word & 0x2);
2929       else if (template->arg_type & DSP_ARGS_IMM)
2930 	imm = ((insn_word >> 25) & 0x1);
2931 
2932       is_template = (((insn_word & 0x02000002) == 0x2) &&
2933 		     major != OPC_9);
2934 
2935       if (imm)
2936 	is_dual = ((insn_word >> 0x2) & 0x1);
2937       else
2938 	is_dual = ((insn_word >> 0x4) & 0x1);
2939 
2940       /* MOV and XSD[BW] do not have o2r.  */
2941       if (major != OPC_9 && major != OPC_MISC)
2942 	o2r = (insn_word & 0x1);
2943 
2944       if (is_neg_or_mov)
2945 	{
2946 	  is_mod = (insn_word & 0x8);
2947 	  is_overflow = (insn_word & 0x20);
2948 	}
2949 
2950       /* XSD */
2951       if (major == OPC_MISC)
2952 	data_unit = (insn_word & 0x1) ? UNIT_D1 : UNIT_D0;
2953       else
2954 	data_unit = ((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0;
2955 
2956       /* Check for NEG,MOV,ABS,FFB, etc.  */
2957       if (is_neg_or_mov || !is_cmp_tst || imm ||
2958 	  MAJOR_OPCODE (insn_word) == OPC_9 ||
2959 	  MAJOR_OPCODE (insn_word) == OPC_MISC)
2960 	reg_nums[0] = ((insn_word >> 19) & REG_MASK);
2961       else
2962 	reg_nums[0] = ((insn_word >> 14) & REG_MASK);
2963 
2964       if (is_template)
2965 	{
2966 	  is_w_mx = (insn_word & 0x1);
2967 
2968 	  /* These are dummy arguments anyway so the register number
2969 	     does not matter.  */
2970 	  if (is_fpu_mov)
2971 	    {
2972 	      if (to_fpu)
2973 		{
2974 		  reg_names[0] = lookup_reg_name (UNIT_FX, 0);
2975 		  reg_names[1] = lookup_reg_name (data_unit, 0);
2976 		}
2977 	      else
2978 		{
2979 		  reg_names[0] = lookup_reg_name (data_unit, 0);
2980 		  reg_names[1] = lookup_reg_name (UNIT_FX, 0);
2981 		}
2982 	    }
2983 	  else
2984 	    {
2985 	      reg_names[0] = lookup_reg_name (data_unit, 0);
2986 	      reg_names[1] = lookup_reg_name (data_unit, 0);
2987 	    }
2988 
2989 	  len = snprintf (buf, OPERAND_WIDTH, "%s,%s",
2990 			  reg_names[0], reg_names[1]);
2991 
2992 	  decode_template_definition (insn_word, buf + len,
2993 				      OPERAND_WIDTH - len);
2994 	}
2995       else
2996 	{
2997 	  if (imm)
2998 	    {
2999 	      /* Conform to the embedded assembler's policy of
3000 		 printing negative numbers as decimal and positive as
3001 		 hex.  */
3002 	      unsigned int value = ((insn_word >> 3) & IMM16_MASK);
3003 
3004 	      if (major == OPC_9)
3005 		{
3006 		  data_unit = (insn_word & 0x1) ? UNIT_D1 : UNIT_D0;
3007 		  is_dual = (insn_word & 0x4);
3008 
3009 		  reg_names[0] = __lookup_dsp_name (reg_nums[0], data_unit);
3010 		}
3011 	      else
3012 		{
3013 		  reg_names[0] = lookup_any_reg_name (data_unit, reg_nums[0], TRUE);
3014 		  if (reg_nums[0] > 15)
3015 		    reg_brackets[0] = 1;
3016 		}
3017 
3018 	      if ((value & 0x8000) || value == 0)
3019 		{
3020 		  value = sign_extend (value, IMM16_BITS);
3021 		  snprintf (buf, OPERAND_WIDTH, "%s%s%s,#%d",
3022 			    reg_brackets[0] ? "[" : "",
3023 			    reg_names[0], reg_brackets[0] ? "]" : "",
3024 			    value);
3025 		}
3026 	      else
3027 		{
3028 		  snprintf (buf, OPERAND_WIDTH, "%s%s%s,#0x%x",
3029 			    reg_brackets[0] ? "[" : "",
3030 			    reg_names[0], reg_brackets[0] ? "]" : "",
3031 			    value);
3032 		}
3033 	    }
3034 	  else
3035 	    {
3036 	      if (is_neg_or_mov || is_cmp_tst)
3037 		reg_nums[1] = ((insn_word >> 9) & REG_MASK);
3038 	      else
3039 		reg_nums[1] = ((insn_word >> 14) & REG_MASK);
3040 
3041 	      if (major == OPC_9)
3042 		{
3043 		  is_dual = (insn_word & 0x4);
3044 		  data_unit = (insn_word & 0x1) ? UNIT_D1 : UNIT_D0;
3045 
3046 		  if (MINOR_OPCODE (template->meta_opcode) == 0x1)
3047 		    reg_names[0] = __lookup_dsp_name (reg_nums[0], data_unit);
3048 		  else
3049 		    reg_names[0] = lookup_reg_name (data_unit, reg_nums[0]);
3050 		}
3051 	      else
3052 		{
3053 		  unsigned int reg0_unit = data_unit;
3054 
3055 		  if (is_fpu_mov && to_fpu)
3056 		    reg0_unit = UNIT_FX;
3057 
3058 		  reg_names[0] = lookup_any_reg_name (reg0_unit, reg_nums[0],
3059 						      (!is_neg_or_mov && is_cmp_tst));
3060 		  if (reg_nums[0] > 15)
3061 		    reg_brackets[0] = 1;
3062 		}
3063 
3064 	      if (o2r)
3065 		reg_names[1] = lookup_o2r (data_unit, reg_nums[1]);
3066 	      else
3067 		{
3068 		  /* Check for accumulator argument.  */
3069 		  if (is_neg_or_mov && ((insn_word & 0x80) == 0x80))
3070 		    {
3071 		      if (data_unit == UNIT_D0)
3072 			reg_names[1] = lookup_dsp_name (reg_nums[1], UNIT_ACC_D0);
3073 		      else
3074 			reg_names[1] = lookup_dsp_name (reg_nums[1], UNIT_ACC_D1);
3075 		    }
3076 		  else
3077 		    {
3078 		      if (major == OPC_9)
3079 			{
3080 			  if (MINOR_OPCODE (template->meta_opcode) == 0x1)
3081 			    {
3082 			      reg_names[1] = lookup_reg_name (data_unit, reg_nums[1]);
3083 			    }
3084 			  else
3085 			    {
3086 			      enum metag_unit u;
3087 
3088 			      u = (insn_word & 0x1) ? UNIT_RAM_D1 : UNIT_RAM_D0;
3089 			      reg_names[1] = lookup_dsp_name (reg_nums[1], u);
3090 			    }
3091 			}
3092 		      else
3093 			{
3094 			  reg_names[1] = lookup_any_reg_name (data_unit,
3095 							      reg_nums[1], TRUE);
3096 			  if (reg_nums[1] > 15)
3097 			    reg_brackets[1] = 1;
3098 			}
3099 		    }
3100 		}
3101 
3102 	      snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s",
3103 			reg_brackets[0] ? "[" : "", reg_names[0],
3104 			reg_brackets[0] ? "]" : "",
3105 			reg_brackets[1] ? "[" : "", reg_names[1],
3106 			reg_brackets[1] ? "]" : "");
3107 	    }
3108 	}
3109 
3110       snprintf (prefix, DSP_PREFIX_WIDTH, "D%s%s%s%s%s%s",
3111 		is_fpu_mov ? "F" : "",
3112 		is_dual ? "L" : "",
3113 		is_mod ? "M" : "", is_overflow ? "O" : "",
3114 		is_w_mx ? "W" : "",
3115 		is_template ? "T" : "");
3116     }
3117   else				/* Group 3. */
3118     {
3119       /* If both the C and CA bits are set, then the Rd register can
3120 	 be in any unit. Figure out which unit from the Ud field.  */
3121       bfd_boolean all_units = (((insn_word) & 0x04000020) == 0x04000020);
3122       enum metag_unit ud_unit = ((insn_word >> 1) & UNIT_MASK);
3123       enum metag_unit ram_unit, acc_unit;
3124       bfd_boolean round = FALSE;
3125       bfd_boolean clamp9 = FALSE;
3126       bfd_boolean clamp8 = FALSE;
3127       bfd_boolean is_template = ((insn_word & 0x04000002) == 0x2);
3128 
3129       imm = ((insn_word >> 25) & 0x1);
3130       ac = (insn_word & 0x1);
3131 
3132       conditional = (MINOR_OPCODE (insn_word) & 0x4);
3133 
3134       /* Check for conditional and not Condition Always.  */
3135       if (conditional && !(insn_word & 0x20))
3136 	cc_flags = lookup_scc_flags ((insn_word >> 1) & CC_MASK);
3137       else if (!(conditional && (insn_word & 0x20)))
3138 	is_dual = ((insn_word >> 0x4) & 0x1);
3139 
3140       /* Conditional instructions don't have the L1 or RSPP fields.  */
3141       if ((insn_word & 0x04000000) == 0)
3142 	{
3143 	  round = (((insn_word >> 2) & 0x3) == 0x1);
3144 	  clamp9 = (((insn_word >> 2) & 0x3) == 0x2);
3145 	  clamp8 = (((insn_word >> 2) & 0x3) == 0x3);
3146 	}
3147 
3148       /* Read DU bit.  */
3149       data_unit = ((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0;
3150       reg_nums[0] = ((insn_word >> 19) & REG_MASK);
3151       reg_nums[1] = ((insn_word >> 14) & REG_MASK);
3152 
3153       ram_unit = (data_unit == UNIT_D0) ? UNIT_RAM_D0 : UNIT_RAM_D1;
3154       acc_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1;
3155 
3156       if (all_units)
3157 	reg_names[0] = lookup_reg_name (ud_unit, reg_nums[0]);
3158       else
3159 	{
3160 	  if (conditional)
3161 	    reg_names[0] = lookup_reg_name (data_unit, reg_nums[0]);
3162 	  else
3163 	    {
3164 	      reg_names[0] = lookup_any_reg_name (data_unit, reg_nums[0], FALSE);
3165 	      if (reg_nums[0] > 15)
3166 		reg_brackets[0] = 1;
3167 	    }
3168 	}
3169 
3170       if (ac)
3171 	{
3172 	  reg_names[1] = lookup_dsp_name (reg_nums[1], acc_unit);
3173 	}
3174       else
3175 	{
3176 	  reg_names[1] = lookup_any_reg_name (data_unit, reg_nums[1], TRUE);
3177 	  if (reg_nums[1] > 15)
3178 	    reg_brackets[1] = 1;
3179 	}
3180 
3181       if (imm)
3182 	{
3183 	  snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,#%#x",
3184 		    reg_brackets[0] ? "[" : "",
3185 		    reg_names[0], reg_brackets[0] ? "]" : "",
3186 		    reg_brackets[1] ? "[" : "",
3187 		    reg_names[1], reg_brackets[1] ? "]" : "",
3188 		    ((insn_word >> 9) & IMM5_MASK));
3189 	}
3190       else
3191 	{
3192 	  reg_nums[2] = ((insn_word >> 9) & REG_MASK);
3193 
3194 	  reg_names[2] = lookup_any_reg_name (data_unit, reg_nums[2], TRUE);
3195 
3196 	  if (reg_nums[2] > 15)
3197 		  reg_brackets[2] = 1;
3198 
3199 	  if (is_template)
3200 	    {
3201 	      bfd_boolean load = ((insn_word >> 13) & 0x1);
3202 	      bfd_boolean dspram = (((insn_word >> 17) & 0x3) == 0x3);
3203 	      const char *tname[1];
3204 	      unsigned int tidx = ((insn_word >> 9) & TEMPLATE_REGS_MASK);
3205 	      enum metag_unit au;
3206 	      unsigned int addr_reg_nums[2];
3207 	      const char *addr_reg_names[2];
3208 	      const char *post_op = "";
3209 	      const char *join_op = "";
3210 
3211 	      is_w_mx = ((insn_word >> 5) & 0x1);
3212 
3213 	      tname[0] = lookup_dsp_name (tidx, UNIT_DT);
3214 
3215 	      /* These are dummy arguments anyway */
3216 	      reg_names[0] = lookup_reg_name (data_unit, 0);
3217 	      if (ac)
3218 		reg_names[1] = lookup_dsp_name (16, acc_unit);
3219 	      else
3220 		reg_names[1] = lookup_reg_name (data_unit, 0);
3221 	      reg_names[2] = lookup_reg_name (data_unit, 0);
3222 
3223 	      addr_reg_names[1] = "";
3224 
3225 	      if (dspram)
3226 		{
3227 		  ram_unit = (data_unit == UNIT_D0) ? UNIT_RAM_D0 : UNIT_RAM_D1;
3228 		  addr_reg_nums[0] = ((insn_word >> 19) & REG_MASK);
3229 		  addr_reg_names[0] = lookup_dspram_name (addr_reg_nums[0],
3230 							  ram_unit, load);
3231 		}
3232 	      else
3233 		{
3234 		  bfd_boolean im = (((insn_word >> 18) & 0x1) != 0);
3235 
3236 		  au = (((insn_word >> 23) & 0x1) == 0) ? UNIT_A0 : UNIT_A1;
3237 		  addr_reg_nums[0] = ((insn_word >> 19) & DSP_REG_MASK);
3238 
3239 		  addr_reg_names[0] = lookup_reg_name (au, addr_reg_nums[0]);
3240 
3241 		  if (im)
3242 		    {
3243 		      unsigned int im_value = ((insn_word >> 14) & 0x3);
3244 
3245 		      switch (im_value)
3246 			{
3247 			case 0x1:
3248 			  post_op = "++";
3249 			  break;
3250 			case 0x3:
3251 			  post_op = "--";
3252 			  break;
3253 			}
3254 		    }
3255 		  else
3256 		    {
3257 		      addr_reg_nums[1] = ((insn_word >> 14) & DSP_REG_MASK);
3258 		      addr_reg_names[1] = lookup_reg_name (au, addr_reg_nums[1]);
3259 		      join_op = "+";
3260 		      post_op = "++";
3261 		    }
3262 		}
3263 
3264 	      if (load)
3265 		{
3266 		  snprintf (buf, OPERAND_WIDTH, "%s,%s,%s %s,[%s%s%s%s]",
3267 			    reg_names[0], reg_names[1], reg_names[2],
3268 			    tname[0], addr_reg_names[0], join_op,
3269 			    addr_reg_names[1], post_op);
3270 		}
3271 	      else
3272 		{
3273 		  snprintf (buf, OPERAND_WIDTH, "%s,%s,%s [%s%s%s%s],%s",
3274 			    reg_names[0], reg_names[1], reg_names[2],
3275 			    addr_reg_names[0], join_op, addr_reg_names[1],
3276 			    post_op, tname[0]);
3277 		}
3278 	    }
3279 	  else
3280 	    {
3281 	      snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,%s%s%s",
3282 			reg_brackets[0] ? "[" : "",
3283 			reg_names[0], reg_brackets[0] ? "]" : "",
3284 			reg_brackets[1] ? "[" : "",
3285 			reg_names[1], reg_brackets[1] ? "]" : "",
3286 			reg_brackets[2] ? "[" : "",
3287 			reg_names[2], reg_brackets[2] ? "]" : "");
3288 	    }
3289 	}
3290 
3291       snprintf (prefix, DSP_PREFIX_WIDTH, "D%s%s%s%s%s%s%s",
3292 		cc_flags ? cc_flags : "",
3293 		is_dual ? "L" : "", clamp9 ? "G" : "",
3294 		clamp8 ? "B" : "", round ? "R" : "",
3295 		is_w_mx ? "W" : "",
3296 		is_template ? "T" : "");
3297     }
3298 
3299   print_insn (outf, prefix, template->name, buf);
3300 
3301 }
3302 
3303 typedef void (*insn_printer)(unsigned int, bfd_vma, const insn_template *,
3304 			     disassemble_info *);
3305 
3306 /* Printer table.  */
3307 static const insn_printer insn_printers[ENC_MAX] =
3308   {
3309     [ENC_NONE] = print_none,
3310     [ENC_MOV_U2U] = print_mov_u2u,
3311     [ENC_MOV_PORT] = print_mov_port,
3312     [ENC_MMOV] = print_mmov,
3313     [ENC_MDRD] = print_mdrd,
3314     [ENC_MOVL_TTREC] = print_movl_ttrec,
3315     [ENC_GET_SET] = print_get_set,
3316     [ENC_GET_SET_EXT] = print_get_set_ext,
3317     [ENC_MGET_MSET] = print_mget_mset,
3318     [ENC_COND_SET] = print_cond_set,
3319     [ENC_XFR] = print_xfr,
3320     [ENC_MOV_CT] = print_mov_ct,
3321     [ENC_SWAP] = print_swap,
3322     [ENC_JUMP] = print_jump,
3323     [ENC_CALLR] = print_callr,
3324     [ENC_ALU] = print_alu,
3325     [ENC_SHIFT] = print_shift,
3326     [ENC_MIN_MAX] = print_min_max,
3327     [ENC_BITOP] = print_bitop,
3328     [ENC_CMP] = print_cmp,
3329     [ENC_BRANCH] = print_branch,
3330     [ENC_KICK] = print_mov_u2u,
3331     [ENC_SWITCH] = print_switch,
3332     [ENC_CACHER] = print_cacher,
3333     [ENC_CACHEW] = print_cachew,
3334     [ENC_ICACHE] = print_icache,
3335     [ENC_LNKGET] = print_lnkget,
3336     [ENC_FMOV] = print_fmov,
3337     [ENC_FMMOV] = print_fmmov,
3338     [ENC_FMOV_DATA] = print_fmov_data,
3339     [ENC_FMOV_I] = print_fmov_i,
3340     [ENC_FPACK] = print_fpack,
3341     [ENC_FSWAP] = print_fswap,
3342     [ENC_FCMP] = print_fcmp,
3343     [ENC_FMINMAX] = print_fminmax,
3344     [ENC_FCONV] = print_fconv,
3345     [ENC_FCONVX] = print_fconvx,
3346     [ENC_FBARITH] = print_fbarith,
3347     [ENC_FEARITH] = print_fearith,
3348     [ENC_FREC] = print_frec,
3349     [ENC_FSIMD] = print_fsimd,
3350     [ENC_FGET_SET_ACF] = print_fget_set_acf,
3351     [ENC_DGET_SET] = print_dget_set,
3352     [ENC_DTEMPLATE] = print_dtemplate,
3353     [ENC_DALU] = print_dalu,
3354   };
3355 
3356 /* Entry point for instruction printing.  */
3357 int
print_insn_metag(bfd_vma pc,disassemble_info * outf)3358 print_insn_metag (bfd_vma pc, disassemble_info *outf)
3359 {
3360   bfd_byte buf[4];
3361   unsigned int insn_word;
3362   size_t i;
3363   outf->bytes_per_chunk = 4;
3364 
3365   (*outf->read_memory_func) (pc & ~0x03, buf, 4, outf);
3366   insn_word = bfd_getl32 (buf);
3367 
3368   for (i = 0; i < sizeof(metag_optab)/sizeof(metag_optab[0]); i++)
3369     {
3370       const insn_template *template = &metag_optab[i];
3371 
3372       if ((insn_word & template->meta_mask) == template->meta_opcode)
3373 	{
3374 	  enum insn_encoding encoding = template->encoding;
3375 	  insn_printer printer = insn_printers[encoding];
3376 
3377 	  if (printer)
3378 	    printer (insn_word, pc, template, outf);
3379 
3380 	  return 4;
3381 	}
3382     }
3383 
3384   return 4;
3385 }
3386