1 /* Disassemble Imagination Technologies Meta instructions.
2    Copyright (C) 2013-2021 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 "disassemble.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,bool 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 		 bool 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   bool 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   bool is_get = MINOR_OPCODE (template->meta_opcode) == GET_EXT_MINOR;
780   bool 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   bool is_get = MAJOR_OPCODE (template->meta_opcode) == OPC_GET;
819   bool is_fpu = (MINOR_OPCODE (template->meta_opcode) & 0x6) == 0x6;
820   bool 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   bool 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   bool 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   /* We used to have buf[OPERAND_WIDTH] here, but gcc v8 complains
1766      about the snprintf()s below possibly truncating the output.
1767      (There is no way to tell gcc that this truncation is intentional).
1768      So now we use an extra wide buffer.  */
1769   char buf[OPERAND_WIDTH * 2];
1770   char data_buf[REG_WIDTH];
1771   char fpu_buf[REG_WIDTH];
1772   bool to_fpu = MAJOR_OPCODE (insn_word) == OPC_GET;
1773   bool is_mmovl = MINOR_OPCODE (insn_word) & 0x1;
1774   unsigned int rmask = (insn_word >> 7) & RMASK_MASK;
1775   unsigned int fpu_no, data_no, data_unit;
1776 
1777   data_no = (insn_word >> 19) & REG_MASK;
1778   fpu_no = (insn_word >> 14) & REG_MASK;
1779 
1780   if (insn_word & 0x1)
1781     data_unit = UNIT_D1;
1782   else
1783     data_unit = UNIT_D0;
1784 
1785   lookup_reg_list (data_buf, REG_WIDTH, data_unit, data_no, rmask, false);
1786   lookup_reg_list (fpu_buf, REG_WIDTH, UNIT_FX, fpu_no,
1787 		   convert_fx_rmask (rmask), is_mmovl);
1788 
1789   if (to_fpu)
1790     snprintf (buf, sizeof buf, "%s,%s", fpu_buf, data_buf);
1791   else
1792     snprintf (buf, sizeof buf, "%s,%s", data_buf, fpu_buf);
1793 
1794   print_insn (outf, "F", template->name, buf);
1795 }
1796 
1797 /* Print an FPU data unit MOV instruction.  */
1798 static void
print_fmov_data(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1799 print_fmov_data (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1800 		 const insn_template *template,
1801 		 disassemble_info *outf)
1802 {
1803   char buf[OPERAND_WIDTH];
1804   unsigned int src_no, dest_no;
1805   unsigned int to_fpu = ((insn_word >> 7) & 0x1);
1806   unsigned int unit_bit = (insn_word >> 24) & 0x1;
1807   enum metag_unit base_unit;
1808   const char *dest_reg;
1809   const char *src_reg;
1810 
1811   dest_no = (insn_word >> 19) & REG_MASK;
1812   src_no = (insn_word >> 9) & REG_MASK;
1813 
1814   if (unit_bit)
1815     base_unit = UNIT_D1;
1816   else
1817     base_unit = UNIT_D0;
1818 
1819   if (to_fpu)
1820     {
1821       dest_reg = lookup_reg_name (UNIT_FX, dest_no);
1822       src_reg = lookup_reg_name (base_unit, src_no);
1823     }
1824   else
1825     {
1826       dest_reg = lookup_reg_name (base_unit, dest_no);
1827       src_reg = lookup_reg_name (UNIT_FX, src_no);
1828     }
1829 
1830   snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg);
1831 
1832   print_insn (outf, "F", template->name, buf);
1833 }
1834 
1835 /* Print an FPU MOV immediate instruction.  */
1836 static void
print_fmov_i(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1837 print_fmov_i (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1838 	      const insn_template *template,
1839 	      disassemble_info *outf)
1840 {
1841   char buf[OPERAND_WIDTH];
1842   unsigned int dest_no;
1843   unsigned int p = (insn_word >> 2) & 0x1;
1844   unsigned int d = (insn_word >> 1) & 0x1;
1845   const char *dest_reg;
1846   unsigned int value = (insn_word >> 3) & IMM16_MASK;
1847 
1848   dest_no = (insn_word >> 19) & REG_MASK;
1849 
1850   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
1851 
1852   snprintf (buf, OPERAND_WIDTH, "%s,#%#x", dest_reg, value);
1853 
1854   if (p)
1855     print_insn (outf, "FL", template->name, buf);
1856   else if (d)
1857     print_insn (outf, "FD", template->name, buf);
1858   else
1859     print_insn (outf, "F", template->name, buf);
1860 }
1861 
1862 /* Print an FPU PACK instruction.  */
1863 static void
print_fpack(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1864 print_fpack (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1865 	     const insn_template *template,
1866 	     disassemble_info *outf)
1867 {
1868   char buf[OPERAND_WIDTH];
1869   unsigned int src1_no, src2_no, dest_no;
1870   const char *dest_reg;
1871   const char *src1_reg;
1872   const char *src2_reg;
1873 
1874   dest_no = (insn_word >> 19) & REG_MASK;
1875   src1_no = (insn_word >> 14) & REG_MASK;
1876   src2_no = (insn_word >> 9) & REG_MASK;
1877 
1878   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
1879   src1_reg = lookup_reg_name (UNIT_FX, src1_no);
1880   src2_reg = lookup_reg_name (UNIT_FX, src2_no);
1881 
1882   snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg);
1883 
1884   print_insn (outf, "F", template->name, buf);
1885 }
1886 
1887 /* Print an FPU SWAP instruction.  */
1888 static void
print_fswap(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1889 print_fswap (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1890 	     const insn_template *template,
1891 	     disassemble_info *outf)
1892 {
1893   char buf[OPERAND_WIDTH];
1894   unsigned int src_no, dest_no;
1895   const char *dest_reg;
1896   const char *src_reg;
1897 
1898   dest_no = (insn_word >> 19) & REG_MASK;
1899   src_no = (insn_word >> 14) & REG_MASK;
1900 
1901   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
1902   src_reg = lookup_reg_name (UNIT_FX, src_no);
1903 
1904   snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg);
1905 
1906   print_insn (outf, "FL", template->name, buf);
1907 }
1908 
1909 /* Print an FPU CMP instruction.  */
1910 static void
print_fcmp(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1911 print_fcmp (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1912 	    const insn_template *template,
1913 	    disassemble_info *outf)
1914 {
1915   char buf[OPERAND_WIDTH];
1916   char prefix_buf[10];
1917   unsigned int src_no, dest_no;
1918   unsigned int a = (insn_word >> 19) & 0x1;
1919   unsigned int z = (insn_word >> 8) & 0x1;
1920   unsigned int p = (insn_word >> 6) & 0x1;
1921   unsigned int d = (insn_word >> 5) & 0x1;
1922   unsigned int q = (insn_word >> 7) & 0x1;
1923   unsigned int cc = (insn_word >> 1) & CC_MASK;
1924   bool show_cond = cc != COND_A && cc != COND_NV;
1925   const char *dest_reg;
1926   const char *src_reg;
1927   const char *cc_flags;
1928 
1929   dest_no = (insn_word >> 14) & REG_MASK;
1930   src_no = (insn_word >> 9) & REG_MASK;
1931 
1932   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
1933   src_reg = lookup_reg_name (UNIT_FX, src_no);
1934 
1935   cc_flags = lookup_fpu_scc_flags (cc);
1936 
1937   if (z)
1938     snprintf (buf, OPERAND_WIDTH, "%s,#0", dest_reg);
1939   else
1940     snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg);
1941 
1942   snprintf (prefix_buf, 10, "F%s%s%s%s%s", p ? "L" : "",
1943 	    d ? "D" : "", a ? "A" : "", q ? "Q" : "",
1944 	    show_cond ? cc_flags : "");
1945 
1946   print_insn (outf, prefix_buf, template->name, buf);
1947 }
1948 
1949 /* Print an FPU MIN or MAX instruction.  */
1950 static void
print_fminmax(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1951 print_fminmax (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1952 	       const insn_template *template,
1953 	       disassemble_info *outf)
1954 {
1955   char buf[OPERAND_WIDTH];
1956   char prefix_buf[10];
1957   unsigned int p = (insn_word >> 6) & 0x1;
1958   unsigned int d = (insn_word >> 5) & 0x1;
1959   unsigned int src1_no, src2_no, dest_no;
1960   unsigned int cc = (insn_word >> 1) & CC_MASK;
1961   bool show_cond = cc != COND_A && cc != COND_NV;
1962   const char *dest_reg;
1963   const char *src1_reg;
1964   const char *src2_reg;
1965   const char *cc_flags;
1966 
1967   dest_no = (insn_word >> 19) & REG_MASK;
1968   src1_no = (insn_word >> 14) & REG_MASK;
1969   src2_no = (insn_word >> 9) & REG_MASK;
1970 
1971   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
1972   src1_reg = lookup_reg_name (UNIT_FX, src1_no);
1973   src2_reg = lookup_reg_name (UNIT_FX, src2_no);
1974 
1975   cc_flags = lookup_fpu_scc_flags (cc);
1976 
1977   snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg);
1978 
1979   snprintf (prefix_buf, 10, "F%s%s%s", p ? "L" : "",
1980 	    d ? "D" : "", show_cond ? cc_flags : "");
1981 
1982   print_insn (outf, prefix_buf, template->name, buf);
1983 }
1984 
1985 /* Print an FPU data conversion instruction.  */
1986 static void
print_fconv(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)1987 print_fconv (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1988 	     const insn_template *template,
1989 	     disassemble_info *outf)
1990 {
1991   char buf[OPERAND_WIDTH];
1992   char prefix_buf[10];
1993   unsigned int p = (insn_word >> 6) & 0x1;
1994   unsigned int z = (insn_word >> 12) & 0x1;
1995   unsigned int src_no, dest_no;
1996   unsigned int cc = (insn_word >> 1) & CC_MASK;
1997   bool show_cond = cc != COND_A && cc != COND_NV;
1998   const char *dest_reg;
1999   const char *src_reg;
2000   const char *cc_flags;
2001 
2002   dest_no = (insn_word >> 19) & REG_MASK;
2003   src_no = (insn_word >> 14) & REG_MASK;
2004 
2005   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
2006   src_reg = lookup_reg_name (UNIT_FX, src_no);
2007 
2008   cc_flags = lookup_fpu_scc_flags (cc);
2009 
2010   snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg);
2011 
2012   snprintf (prefix_buf, 10, "F%s%s%s", p ? "L" : "",
2013 	    z ? "Z" : "", show_cond ? cc_flags : "");
2014 
2015   print_insn (outf, prefix_buf, template->name, buf);
2016 }
2017 
2018 /* Print an FPU extended data conversion instruction.  */
2019 static void
print_fconvx(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)2020 print_fconvx (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2021 	      const insn_template *template,
2022 	      disassemble_info *outf)
2023 {
2024   char buf[OPERAND_WIDTH];
2025   char prefix_buf[10];
2026   unsigned int p = (insn_word >> 6) & 0x1;
2027   unsigned int xl = (insn_word >> 7) & 0x1;
2028   unsigned int src_no, dest_no, fraction_bits;
2029   unsigned int cc = (insn_word >> 1) & CC_MASK;
2030   bool show_cond = cc != COND_A && cc != COND_NV;
2031   const char *dest_reg;
2032   const char *src_reg;
2033   const char *cc_flags;
2034 
2035   dest_no = (insn_word >> 19) & REG_MASK;
2036   src_no = (insn_word >> 14) & REG_MASK;
2037 
2038   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
2039   src_reg = lookup_reg_name (UNIT_FX, src_no);
2040 
2041   cc_flags = lookup_fpu_scc_flags (cc);
2042 
2043   if (xl)
2044     fraction_bits = (insn_word >> 8) & IMM6_MASK;
2045   else
2046     fraction_bits = (insn_word >> 9) & IMM5_MASK;
2047 
2048   snprintf (buf, OPERAND_WIDTH, "%s,%s,#%#x", dest_reg, src_reg,
2049 	    fraction_bits);
2050 
2051   snprintf (prefix_buf, 10, "F%s%s", p ? "L" : "",
2052 	    show_cond ? cc_flags : "");
2053 
2054   print_insn (outf, prefix_buf, template->name, buf);
2055 }
2056 
2057 /* Print an FPU basic arithmetic instruction.  */
2058 static void
print_fbarith(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)2059 print_fbarith (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2060 	       const insn_template *template,
2061 	       disassemble_info *outf)
2062 {
2063   char buf[OPERAND_WIDTH];
2064   char prefix_buf[10];
2065   unsigned int n = (insn_word >> 7) & 0x1;
2066   unsigned int p = (insn_word >> 6) & 0x1;
2067   unsigned int d = (insn_word >> 5) & 0x1;
2068   unsigned int src1_no, src2_no, dest_no;
2069   unsigned int cc = (insn_word >> 1) & CC_MASK;
2070   bool show_cond = cc != COND_A && cc != COND_NV;
2071   const char *dest_reg;
2072   const char *src1_reg;
2073   const char *src2_reg;
2074   const char *cc_flags;
2075 
2076   dest_no = (insn_word >> 19) & REG_MASK;
2077   src1_no = (insn_word >> 14) & REG_MASK;
2078   src2_no = (insn_word >> 9) & REG_MASK;
2079 
2080   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
2081   src1_reg = lookup_reg_name (UNIT_FX, src1_no);
2082   src2_reg = lookup_reg_name (UNIT_FX, src2_no);
2083 
2084   cc_flags = lookup_fpu_scc_flags (cc);
2085 
2086   snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg);
2087 
2088   snprintf (prefix_buf, 10, "F%s%s%s%s", p ? "L" : "",
2089 	    d ? "D" : "", n ? "I" : "", show_cond ? cc_flags : "");
2090 
2091   print_insn (outf, prefix_buf, template->name, buf);
2092 }
2093 
2094 /* Print an FPU extended arithmetic instruction.  */
2095 static void
print_fearith(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)2096 print_fearith (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2097 	       const insn_template *template,
2098 	       disassemble_info *outf)
2099 {
2100   char buf[OPERAND_WIDTH];
2101   char prefix_buf[10];
2102   bool is_muz = MINOR_OPCODE (insn_word) == 0x6 && ((insn_word >> 4) & 0x1);
2103   bool is_mac = MINOR_OPCODE (insn_word) == 0x6 && (insn_word & 0x1f) == 0;
2104   bool is_maw = MINOR_OPCODE (insn_word) == 0x6 && ((insn_word >> 3) & 0x1);
2105   unsigned int o3o = insn_word & 0x1;
2106   unsigned int q = is_muz && ((insn_word >> 1) & 0x1);
2107   unsigned int n = (insn_word >> 7) & 0x1;
2108   unsigned int p = (insn_word >> 6) & 0x1;
2109   unsigned int d = (insn_word >> 5) & 0x1;
2110   unsigned int cc = (insn_word >> 1) & CC_MASK;
2111   bool show_cond = (MINOR_OPCODE (insn_word) == 0x5 && cc != COND_A
2112 		    && cc != COND_NV);
2113   unsigned int src1_no, src2_no, dest_no;
2114   const char *dest_reg;
2115   const char *src1_reg;
2116   const char *src2_reg;
2117   const char *cc_flags;
2118 
2119   dest_no = (insn_word >> 19) & REG_MASK;
2120   src1_no = (insn_word >> 14) & REG_MASK;
2121   src2_no = (insn_word >> 9) & REG_MASK;
2122 
2123   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
2124   src1_reg = lookup_reg_name (UNIT_FX, src1_no);
2125   src2_reg = lookup_reg_name (UNIT_FX, src2_no);
2126 
2127   cc_flags = lookup_fpu_scc_flags (cc);
2128 
2129   if (is_mac)
2130     snprintf (buf, OPERAND_WIDTH, "ACF.0,%s,%s", src1_reg, src2_reg);
2131   else if (o3o && is_maw)
2132     snprintf (buf, OPERAND_WIDTH, "%s,%s", src1_reg, src2_reg);
2133   else
2134     snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg);
2135 
2136   snprintf (prefix_buf, 10, "F%s%s%s%s%s", p ? "L" : "",
2137 	    d ? "D" : "", n ? "I" : "", q ? "Q" : "",
2138 	    show_cond ? cc_flags : "");
2139 
2140   print_insn (outf, prefix_buf, template->name, buf);
2141 }
2142 
2143 /* Print an FPU RCP or RSQ instruction.  */
2144 static void
print_frec(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)2145 print_frec (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2146 	    const insn_template *template,
2147 	    disassemble_info *outf)
2148 {
2149   char buf[OPERAND_WIDTH];
2150   char prefix_buf[10];
2151   unsigned int z = (insn_word >> 10) & 0x1;
2152   unsigned int q = (insn_word >> 9) & 0x1;
2153   unsigned int n = (insn_word >> 7) & 0x1;
2154   unsigned int p = (insn_word >> 6) & 0x1;
2155   unsigned int d = (insn_word >> 5) & 0x1;
2156   unsigned int src_no, dest_no;
2157   const char *dest_reg;
2158   const char *src_reg;
2159 
2160   dest_no = (insn_word >> 19) & REG_MASK;
2161   src_no = (insn_word >> 14) & REG_MASK;
2162 
2163   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
2164   src_reg = lookup_reg_name (UNIT_FX, src_no);
2165 
2166   snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg);
2167 
2168   snprintf (prefix_buf, 10, "F%s%s%s%s%s", p ? "L" : "",
2169 	    d ? "D" : "", n ? "I" : "", q ? "Q" : "", z ? "Z" : "");
2170 
2171   print_insn (outf, prefix_buf, template->name, buf);
2172 }
2173 
2174 static void
print_fsimd(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)2175 print_fsimd (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2176 	     const insn_template *template,
2177 	     disassemble_info *outf)
2178 {
2179   char buf[OPERAND_WIDTH];
2180   unsigned int n = (insn_word >> 7) & 0x1;
2181   unsigned int src1_no, src2_no, dest_no;
2182   const char *dest_reg;
2183   const char *src1_reg;
2184   const char *src2_reg;
2185 
2186   dest_no = (insn_word >> 19) & REG_MASK;
2187   src1_no = (insn_word >> 14) & REG_MASK;
2188   src2_no = (insn_word >> 9) & REG_MASK;
2189 
2190   dest_reg = lookup_reg_name (UNIT_FX, dest_no);
2191   src1_reg = lookup_reg_name (UNIT_FX, src1_no);
2192   src2_reg = lookup_reg_name (UNIT_FX, src2_no);
2193 
2194   snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg);
2195 
2196   if (n)
2197     print_insn (outf, "FLI", template->name, buf);
2198   else
2199     print_insn (outf, "FL", template->name, buf);
2200 }
2201 
2202 /* Print an FPU accumulator GET or SET instruction.  */
2203 static void
print_fget_set_acf(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)2204 print_fget_set_acf (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2205 		    const insn_template *template,
2206 		    disassemble_info *outf)
2207 {
2208   bool is_get = MAJOR_OPCODE (template->meta_opcode) == OPC_GET;
2209   char buf[OPERAND_WIDTH];
2210   char addr_buf[ADDR_WIDTH];
2211   unsigned int part;
2212   const char *reg_name;
2213 
2214   part = (insn_word >> 19) & ACF_PART_MASK;
2215 
2216   reg_name = lookup_acf_name (part);
2217 
2218   mget_mset_addr_str (addr_buf, ADDR_WIDTH, insn_word);
2219 
2220   if (is_get)
2221     {
2222       snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_name, addr_buf);
2223     }
2224   else
2225     {
2226       snprintf (buf, OPERAND_WIDTH, "%s,%s", addr_buf, reg_name);
2227     }
2228   print_insn (outf, "F", template->name, buf);
2229 }
2230 
2231 /* Return the name of the DSP register or accumulator for NUM and UNIT.  */
2232 static const char *
__lookup_dsp_name(unsigned int num,unsigned int unit)2233 __lookup_dsp_name (unsigned int num, unsigned int unit)
2234 {
2235   size_t i;
2236 
2237   for (i = 0; i < sizeof(metag_dsp_regtab)/sizeof(metag_dsp_regtab[0]); i++)
2238     {
2239       const metag_reg *reg = &metag_dsp_regtab[i];
2240 
2241       if (reg->no == num)
2242 	{
2243 	  if ((reg->unit == UNIT_RAM_D0 || reg->unit == UNIT_ACC_D0) &&
2244 	      unit == UNIT_D0)
2245 	    return reg->name;
2246 
2247 	  if ((reg->unit == UNIT_RAM_D1 || reg->unit == UNIT_ACC_D1) &&
2248 	      unit == UNIT_D1)
2249 	    return reg->name;
2250 	}
2251     }
2252   return "?.?";
2253 }
2254 
2255 /* Return the name of the DSP register for NUM and UNIT.  */
2256 static const char *
lookup_dsp_name(unsigned int num,unsigned int unit)2257 lookup_dsp_name (unsigned int num, unsigned int unit)
2258 {
2259   size_t i;
2260 
2261   for (i = 0; i < sizeof(metag_dsp_regtab)/sizeof(metag_dsp_regtab[0]); i++)
2262     {
2263       const metag_reg *reg = &metag_dsp_regtab[i];
2264 
2265       if (reg->no == num && reg->unit == unit)
2266 	return reg->name;
2267     }
2268   return "?.?";
2269 }
2270 
2271 /* Return the name of the DSP RAM register for NUM and UNIT.  */
2272 static const char *
lookup_dspram_name(unsigned int num,unsigned int unit,bool load)2273 lookup_dspram_name (unsigned int num, unsigned int unit, bool load)
2274 {
2275   size_t i, nentries;
2276 
2277   nentries = sizeof(metag_dsp_tmpl_regtab[load])/sizeof(metag_dsp_tmpl_regtab[load][0]);
2278 
2279   for (i = 0; i < nentries; i++)
2280     {
2281       const metag_reg *reg = &metag_dsp_tmpl_regtab[load][i];
2282 
2283       if (reg->no == num && reg->unit == unit)
2284 	return reg->name;
2285     }
2286   return "?.?";
2287 }
2288 
2289 /* This lookup function looks up the corresponding name for a register
2290    number in a DSP instruction. SOURCE indicates whether this
2291    register is a source or destination operand.  */
2292 static const char *
lookup_any_reg_name(unsigned int unit,unsigned int num,bool source)2293 lookup_any_reg_name (unsigned int unit, unsigned int num, bool source)
2294 {
2295   /* A register with the top bit set (5th bit) indicates a DSPRAM
2296      register.  */
2297   if (num > 15)
2298     {
2299       unsigned int dunit = (unit == UNIT_D0) ? UNIT_RAM_D0 : UNIT_RAM_D1;
2300       return lookup_dspram_name (num, dunit, source);
2301     }
2302   else
2303     return lookup_reg_name (unit, num);
2304 }
2305 
2306 /* Return the DSP data unit for UNIT.  */
2307 static inline enum metag_unit
dsp_data_unit_to_sym(unsigned int unit)2308 dsp_data_unit_to_sym (unsigned int unit)
2309 {
2310   if (unit == 0)
2311     return UNIT_D0;
2312   else
2313     return UNIT_D1;
2314 }
2315 
2316 /* Print a DSP GET or SET instruction.  */
2317 static void
print_dget_set(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)2318 print_dget_set (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2319 		const insn_template *template,
2320 		disassemble_info *outf)
2321 {
2322   bool is_get = (template->meta_opcode & 0x100);
2323   char buf[OPERAND_WIDTH];
2324   char addr_buf[ADDR_WIDTH];
2325   char prefix[DSP_PREFIX_WIDTH];
2326   unsigned int part;
2327   const char *reg_name[2];
2328   bool is_high = false;
2329   bool is_dual = (insn_word & 0x4);
2330   bool is_template = (insn_word & 0x2);
2331   const char *base_reg = "?";
2332   unsigned int addr_unit, base_no, unit;
2333 
2334   unit = dsp_data_unit_to_sym (insn_word & 0x1);
2335 
2336   /* Is this a load/store to a template table?  */
2337   if (is_template)
2338     {
2339       part = (insn_word >> 19) & 0x1f;
2340       reg_name[0] = lookup_dsp_name (part, UNIT_DT);
2341     }
2342   else
2343     {
2344       part = (insn_word >> 19) & REG_MASK;
2345       is_high = ((part & 0x18) == 0x18);
2346 
2347       /* Strip bit high indicator.  */
2348       if (is_high)
2349 	part &= 0x17;
2350 
2351       reg_name[0] = __lookup_dsp_name (part, unit);
2352 
2353     }
2354 
2355   /* Is this a dual unit DSP operation?  The modulo operator below
2356      makes sure that we print the Rd register in the correct order,
2357      e.g. because there's only one bit in the instruction for the Data
2358      Unit we have to work out what the other data unit number is.
2359      (there's only 2).  */
2360   if (is_dual)
2361     {
2362       unsigned int _unit = insn_word & 0x1;
2363 
2364       _unit = ((_unit + 1) % 2);
2365       reg_name[1] = __lookup_dsp_name(part, dsp_data_unit_to_sym (_unit));
2366     }
2367   else
2368     reg_name[1] = NULL;
2369 
2370   addr_unit = ((insn_word >> 18) & 0x1);
2371   if (addr_unit == 0)
2372 	  addr_unit = UNIT_A0;
2373   else
2374 	  addr_unit = UNIT_A1;
2375 
2376   base_no = (insn_word >> 14) & DSP_REG_MASK;
2377 
2378   base_reg = lookup_reg_name (addr_unit, base_no);
2379 
2380   /* Check if it's a post-increment/post-decrement.  */
2381   if (insn_word & 0x2000)
2382   {
2383 	  unsigned int imm = (insn_word >> 9) & DGET_SET_IMM_MASK;
2384 	  const char *post_op;
2385 
2386 	  switch (imm)
2387 	    {
2388 	    case 0x1:
2389 	      post_op = "++";
2390 	      break;
2391 	    case 0x3:
2392 	      post_op = "--";
2393 	      break;
2394 	    default:
2395 	      post_op = "";
2396 	    }
2397 
2398 	  snprintf (addr_buf, ADDR_WIDTH, "[%s%s]", base_reg, post_op);
2399   }
2400   else
2401   {
2402 	  unsigned int offset_part = (insn_word >> 9) & DSP_REG_MASK;
2403 	  const char *offset_reg = lookup_reg_name (addr_unit, offset_part);
2404 
2405 	  snprintf (addr_buf, ADDR_WIDTH, "[%s+%s++]", base_reg, offset_reg);
2406   }
2407 
2408   if (is_get)
2409     {
2410       if (is_dual && !is_template)
2411 	snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", reg_name[0],
2412 		  reg_name[1], addr_buf);
2413       else
2414 	snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_name[0], addr_buf);
2415     }
2416   else
2417     {
2418       if (is_dual && !is_template)
2419 	snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", addr_buf,
2420 		  reg_name[0], reg_name[1]);
2421       else
2422 	snprintf (buf, OPERAND_WIDTH, "%s,%s", addr_buf, reg_name[0]);
2423     }
2424 
2425   snprintf (prefix, DSP_PREFIX_WIDTH, "D%s", is_high ? "H" : "");
2426   print_insn (outf, prefix, template->name, buf);
2427 }
2428 
2429 /* Print a DSP template instruction.  */
2430 static void
print_dtemplate(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)2431 print_dtemplate (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2432 		 const insn_template *template,
2433 		 disassemble_info *outf)
2434 {
2435   char buf[OPERAND_WIDTH];
2436   char prefix[DSP_PREFIX_WIDTH];
2437   unsigned int offset[4];
2438   bool is_half = (MINOR_OPCODE (insn_word) == 0x5);
2439   bool daop_only = (MINOR_OPCODE (insn_word) == 0x3);
2440 
2441   offset[0] = ((insn_word >> 19) & REG_MASK);
2442   offset[1] = ((insn_word >> 14) & REG_MASK);
2443   offset[2] = ((insn_word >> 9) & REG_MASK);
2444   offset[3] = ((insn_word >> 4) & REG_MASK);
2445 
2446   if (daop_only)
2447 	  snprintf (buf, OPERAND_WIDTH, "#0x%x,#0x%x,#0x%x", offset[0],
2448 		    offset[1], offset[2]);
2449   else
2450     {
2451       snprintf (buf, OPERAND_WIDTH, "#0x%x,#0x%x,#0x%x,#0x%x", offset[0],
2452 		offset[1], offset[2], offset[3]);
2453     }
2454 
2455   snprintf (prefix, DSP_PREFIX_WIDTH, "D%s", is_half ? "H" : "");
2456   print_insn (outf, prefix, template->name, buf);
2457 }
2458 
2459 /* Format template definition from INSN_WORD into BUF.  */
2460 static void
decode_template_definition(unsigned int insn_word,char * buf,size_t len)2461 decode_template_definition(unsigned int insn_word, char *buf, size_t len)
2462 {
2463   bool load = ((insn_word >> 13) & 0x1);
2464   bool dspram = (((insn_word >> 17) & 0x3) == 0x3);
2465   const char *template[1];
2466   unsigned int tidx = ((insn_word >> 9) & TEMPLATE_REGS_MASK);
2467   enum metag_unit au, ram_unit;
2468   unsigned int addr_reg_nums[2];
2469   const char *addr_reg_names[2];
2470   const char *post_op = "";
2471   const char *join_op = "";
2472   enum metag_unit data_unit = ((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0;
2473 
2474   template[0] = lookup_dsp_name (tidx, UNIT_DT);
2475 
2476   addr_reg_names[1] = "";
2477 
2478   if (dspram)
2479     {
2480       ram_unit = (data_unit == UNIT_D0) ? UNIT_RAM_D0 : UNIT_RAM_D1;
2481       addr_reg_nums[0] = ((insn_word >> 19) & REG_MASK);
2482       addr_reg_names[0] = lookup_dspram_name (addr_reg_nums[0],
2483 					      ram_unit, load);
2484     }
2485   else
2486     {
2487       bool im = (((insn_word >> 18) & 0x1) != 0);
2488 
2489       au = (((insn_word >> 23) & 0x1) == 0) ? UNIT_A0 : UNIT_A1;
2490       addr_reg_nums[0] = ((insn_word >> 19) & DSP_REG_MASK);
2491 
2492       addr_reg_names[0] = lookup_reg_name (au, addr_reg_nums[0]);
2493 
2494       if (im)
2495 	{
2496 	  unsigned int im_value = ((insn_word >> 14) & 0x3);
2497 
2498 	  switch (im_value)
2499 	    {
2500 	    case 0x1:
2501 	      post_op = "++";
2502 	      break;
2503 	    case 0x3:
2504 	      post_op = "--";
2505 	      break;
2506 	    }
2507 	}
2508       else
2509 	{
2510 	  addr_reg_nums[1] = ((insn_word >> 14) & DSP_REG_MASK);
2511 	  addr_reg_names[1] = lookup_reg_name (au, addr_reg_nums[1]);
2512 	  join_op = "+";
2513 	  post_op = "++";
2514 	}
2515     }
2516 
2517   if (load)
2518     {
2519       len = snprintf (buf, len, " %s,[%s%s%s%s]", template[0], addr_reg_names[0],
2520 		      join_op, addr_reg_names[1], post_op);
2521     }
2522   else
2523     {
2524       len = snprintf (buf, len, " [%s%s%s%s],%s", addr_reg_names[0], join_op,
2525 		      addr_reg_names[1], post_op, template[0]);
2526     }
2527 }
2528 
2529 /* Print a DSP ALU instruction.  */
2530 static void
print_dalu(unsigned int insn_word,bfd_vma pc ATTRIBUTE_UNUSED,const insn_template * template,disassemble_info * outf)2531 print_dalu (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2532 	    const insn_template *template,
2533 	    disassemble_info *outf)
2534 {
2535   bool is_dual = false;
2536   unsigned int data_unit = (((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0);
2537   const char *reg_names[3];
2538   unsigned int reg_nums[3];
2539   bool ac = ((insn_word >> 7) & 0x1);
2540   char buf[OPERAND_WIDTH];
2541   char prefix[DSP_PREFIX_WIDTH];
2542   size_t len;
2543   bool is_mod = false;
2544   bool is_overflow = false;
2545   unsigned int reg_brackets[3];
2546   bool is_w_mx = false;
2547   bool is_b_mx = false;
2548   bool imm = false;
2549   bool is_quickrot64 = false;
2550   bool conditional = false;
2551   const char *cc_flags = NULL;
2552   bool is_unsigned = false;
2553 
2554   memset (reg_brackets, 0, sizeof (reg_brackets));
2555 
2556   if (template->arg_type & DSP_ARGS_1)
2557     {
2558       bool is_template = false;
2559       const char *addr_reg = NULL;
2560       bool qr = false;
2561       bool is_acc_add = false;
2562       bool is_acc_sub = false;
2563       bool is_acc_zero = false;
2564       bool is_split8 = (template->arg_type & DSP_ARGS_SPLIT8);
2565 
2566       /* Read DU bit.  */
2567       data_unit = ((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0;
2568 
2569       conditional = ((insn_word >> 24) & 0x4);
2570 
2571       /* Templates can't be conditional.  */
2572       is_template = (((insn_word & 0x02000002) == 0x2) && !conditional);
2573 
2574       if (is_split8)
2575 	is_mod = (insn_word & 0x80);
2576 
2577       if (template->arg_type & DSP_ARGS_QR)
2578 	{
2579 	  if (!conditional)
2580 	    is_quickrot64 = ((insn_word >> 5) & 0x1);
2581 	}
2582 
2583       if (template->arg_type & DSP_ARGS_DACC)
2584 	{
2585 	  is_mod = (insn_word & 0x8);
2586 	  is_unsigned = (insn_word & 0x40);
2587 	}
2588 
2589       if (is_template)
2590 	{
2591 	  is_w_mx = (insn_word & 0x1);
2592 	  is_dual = ((insn_word >> 0x4) & 0x1);
2593 
2594 	  /* De.r,Dx.r,De.r|ACe.r */
2595 	  if (template->arg_type & DSP_ARGS_ACC2)
2596 	    {
2597 	      is_mod = (insn_word & 0x8);
2598 	      is_overflow = (insn_word & 0x20);
2599 	    }
2600 
2601 	  /* ACe.e,ACx.r,ACo.e? */
2602 	  if ((template->arg_type & DSP_ARGS_XACC) &&
2603 	      (((insn_word >> 6) & 0x5) == 0x5))
2604 	    {
2605 	      enum metag_unit ac_unit, ao_unit;
2606 
2607 	      ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1;
2608 
2609 	      if (ac_unit == UNIT_ACC_D0)
2610 		ao_unit = UNIT_ACC_D1;
2611 	      else
2612 		ao_unit = UNIT_ACC_D0;
2613 
2614 	      reg_nums[1] = ((insn_word >> 19) & REG_MASK);
2615 
2616 	      /* These are dummy arguments anyway so the register
2617 		 number does not matter.  */
2618 	      reg_names[0] = lookup_dsp_name (16, ac_unit); /* ACe.0 */
2619 	      reg_names[1] = lookup_dsp_name (16, ac_unit); /* ACx.0 */
2620 	      reg_names[2] = lookup_dsp_name (16, ao_unit); /* ACo.0 */
2621 	    }
2622 	  else
2623 	    {
2624 	      /* De.r|ACe.r,Dx.r,De.r */
2625 	      if (template->arg_type & DSP_ARGS_DACC &&
2626 		  ((insn_word & 0x84) != 0))
2627 		{
2628 		  enum metag_unit ac_unit;
2629 
2630 		  ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1;
2631 		  reg_names[0] = lookup_dsp_name (16, ac_unit);
2632 
2633 		  is_acc_zero = ((insn_word & 0x84) == 0x04);
2634 		  is_acc_add = ((insn_word & 0x84) == 0x80);
2635 		  is_acc_sub = ((insn_word & 0x84) == 0x84);
2636 		}
2637 	      else
2638 		reg_names[0] = lookup_any_reg_name (data_unit, 0, false);
2639 
2640 	      /* These are dummy arguments anyway so the register
2641 		 number does not matter.  */
2642 	      reg_names[1] = lookup_any_reg_name (data_unit, 0, true);
2643 
2644 	      /* De.r,Dx.r,De.r|ACe.r */
2645 	      if ((template->arg_type & DSP_ARGS_ACC2) &&
2646 		  ((insn_word & 0x80) == 0x80))
2647 		{
2648 		  enum metag_unit ac_unit;
2649 
2650 		  ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1;
2651 		  reg_names[2] = lookup_dsp_name (16, ac_unit);
2652 		}
2653 	      /* Detection of QUICKRoT and accumulator usage uses the
2654 		 same bits. They are mutually exclusive.  */
2655 	      else if (ac && (template->arg_type & DSP_ARGS_ACC2))
2656 		{
2657 		  reg_nums[2] = ((insn_word >> 9) & REG_MASK);
2658 
2659 		  if (data_unit == UNIT_D0)
2660 		    reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D0);
2661 		  else
2662 		    reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D1);
2663 		}
2664 	      else
2665 		{
2666 		  if ((template->arg_type & DSP_ARGS_QR) &&
2667 		      ((insn_word & 0x40) == 0x40))
2668 		    {
2669 		      enum metag_unit aunit;
2670 		      int reg_no;
2671 
2672 		      if (conditional)
2673 			reg_no = ((insn_word >> 5) & 0x1);
2674 		      else
2675 			reg_no = ((insn_word >> 7) & 0x1);
2676 
2677 		      aunit = (data_unit == UNIT_D0) ? UNIT_A0 : UNIT_A1;
2678 		      addr_reg = lookup_reg_name (aunit, reg_no + 2);
2679 
2680 		      qr = true;
2681 		    }
2682 
2683 		  reg_names[2] = lookup_any_reg_name (data_unit, 0, true);
2684 		}
2685 	    }
2686 
2687 	  if (qr)
2688 	    {
2689 	      len = snprintf (buf, OPERAND_WIDTH, "%s,%s,%s,%s",
2690 			      reg_names[0], reg_names[1], reg_names[2],
2691 			      addr_reg);
2692 	    }
2693 	  else
2694 	    {
2695 	      len = snprintf (buf, OPERAND_WIDTH, "%s,%s,%s%s%s",
2696 			      reg_names[0], reg_names[1],
2697 			      reg_brackets[2] ? "[" : "",
2698 			      reg_names[2], reg_brackets[2] ? "]" : "");
2699 	    }
2700 
2701 	  decode_template_definition (insn_word, buf + len,
2702 				      OPERAND_WIDTH - len);
2703 	}
2704       else			/* Not a template definiton.  */
2705 	{
2706 	  reg_nums[0] = ((insn_word >> 19) & REG_MASK);
2707 	  reg_nums[1] = ((insn_word >> 14) & REG_MASK);
2708 	  reg_nums[2] = ((insn_word >> 9) & REG_MASK);
2709 
2710 	  imm = (((insn_word >> 24) & 0x2) && (template->arg_type & DSP_ARGS_IMM));
2711 
2712 	  if (imm)
2713 	    is_dual = (insn_word & 0x4);
2714 	  else if (!conditional)
2715 	    is_dual = (insn_word & 0x10);
2716 	  else
2717 	    cc_flags = lookup_scc_flags ((insn_word >> 1) & CC_MASK);
2718 
2719 	  /* De.r,Dx.r,De.r|ACe.r */
2720 	  if (template->arg_type & DSP_ARGS_ACC2)
2721 	    {
2722 	      is_mod = (insn_word & 0x8);
2723 	      is_overflow = (insn_word & 0x20);
2724 	    }
2725 
2726 	  if (template->arg_type & DSP_ARGS_SPLIT8)
2727 	    {
2728 	      is_overflow = (insn_word & 0x20);
2729 	    }
2730 
2731 	  /* ACe.e,ACx.r,ACo.e? */
2732 	  if ((template->arg_type & DSP_ARGS_XACC) &&
2733 	      (((insn_word >> 6) & 0x5) == 0x5))
2734 	    {
2735 	      enum metag_unit ac_unit, ao_unit;
2736 
2737 	      ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1;
2738 
2739 	      if (ac_unit == UNIT_ACC_D0)
2740 		ao_unit = UNIT_ACC_D1;
2741 	      else
2742 		ao_unit = UNIT_ACC_D0;
2743 
2744 	      reg_nums[1] = ((insn_word >> 19) & REG_MASK);
2745 	      reg_names[0] = lookup_dsp_name (reg_nums[1], ac_unit);
2746 	      reg_names[1] = lookup_dsp_name (reg_nums[1], ac_unit);
2747 	      reg_names[2] = lookup_dsp_name (reg_nums[1], ao_unit);
2748 	    }
2749 	  else
2750 	    {
2751 	      bool o2r = (insn_word & 0x1);
2752 
2753 	      /* De.r|ACe.r,Dx.r,De.r */
2754 	      if ((template->arg_type & DSP_ARGS_DACC) &&
2755 		  ((insn_word & 0x84) != 0))
2756 		{
2757 		  enum metag_unit ac_unit;
2758 
2759 		  ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1;
2760 		  reg_names[0] = lookup_dsp_name (reg_nums[0], ac_unit);
2761 
2762 		  is_acc_zero = ((insn_word & 0x84) == 0x04);
2763 		  is_acc_add = ((insn_word & 0x84) == 0x80);
2764 		  is_acc_sub = ((insn_word & 0x84) == 0x84);
2765 		}
2766 	      else if (conditional)
2767 		{
2768 		  reg_names[0] = lookup_reg_name (data_unit, reg_nums[0]);
2769 		}
2770 	      else
2771 		{
2772 		  reg_names[0] = lookup_any_reg_name (data_unit,
2773 						      reg_nums[0], false);
2774 		  if (reg_nums[0] > 15)
2775 		    reg_brackets[0] = 1;
2776 		}
2777 
2778 	      if (imm)
2779 		{
2780 		  reg_names[1] = lookup_any_reg_name (data_unit, reg_nums[0], true);
2781 
2782 		  if (reg_brackets[0])
2783 		    reg_brackets[1] = 1;
2784 		  }
2785 	      else
2786 		{
2787 		  if (is_split8 && is_mod)
2788 		    {
2789 		      reg_names[1] = lookup_reg_name (data_unit, reg_nums[1]);
2790 		    }
2791 		  else
2792 		  {
2793 		    reg_names[1] = lookup_any_reg_name (data_unit, reg_nums[1], true);
2794 
2795 		    if (reg_nums[1] > 15)
2796 		      reg_brackets[1] = 1;
2797 		  }
2798 		}
2799 
2800 	      /* Detection of QUICKRoT and accumulator usage uses the
2801 		 same bits. They are mutually exclusive.  */
2802 	      if (ac && (template->arg_type & DSP_ARGS_ACC2))
2803 		{
2804 		  if (data_unit == UNIT_D0)
2805 		    reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D0);
2806 		  else
2807 		    reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D1);
2808 		}
2809 
2810 	      else
2811 		{
2812 		  if ((template->arg_type & DSP_ARGS_QR) &&
2813 		      ((insn_word & 0x40) == 0x40))
2814 		    {
2815 		      enum metag_unit aunit;
2816 		      int reg_no;
2817 
2818 		      if (conditional)
2819 			reg_no = ((insn_word >> 5) & 0x1);
2820 		      else
2821 			reg_no = ((insn_word >> 7) & 0x1);
2822 
2823 		      aunit = (data_unit == UNIT_D0) ? UNIT_A0 : UNIT_A1;
2824 		      addr_reg = lookup_reg_name (aunit, reg_no + 2);
2825 
2826 		      qr = true;
2827 		    }
2828 
2829 		  if (o2r)
2830 		    reg_names[2] = lookup_o2r (data_unit, reg_nums[2]);
2831 		  else
2832 		    {
2833 		      /* Can't use a DSPRAM reg if both QD and L1 are
2834 			 set on a QUICKRoT instruction or if we're a
2835 			 split 8.  */
2836 		      if (((template->arg_type & DSP_ARGS_QR)
2837 			   && ((insn_word & 0x30) == 0x30 && !conditional)) ||
2838 			  (is_split8 && is_mod))
2839 			reg_names[2] = lookup_reg_name (data_unit, reg_nums[2]);
2840 		      else
2841 			{
2842 			  reg_names[2] = lookup_any_reg_name (data_unit,
2843 							      reg_nums[2], true);
2844 			  if (reg_nums[2] > 15)
2845 			    reg_brackets[2] = 1;
2846 			}
2847 		    }
2848 		}
2849 	    }
2850 
2851 	  if (qr)
2852 	    {
2853 	      len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,%s%s%s,%s",
2854 			      reg_brackets[0] ? "[" : "",
2855 			      reg_names[0], reg_brackets[0] ? "]" : "",
2856 			      reg_brackets[1] ? "[" : "",
2857 			      reg_names[1], reg_brackets[1] ? "]" : "",
2858 			      reg_brackets[2] ? "[" : "",
2859 			      reg_names[2], reg_brackets[2] ? "]" : "",
2860 			      addr_reg);
2861 	    }
2862 	  else
2863 	    {
2864 	      if (imm)
2865 		{
2866 		  /* Conform to the embedded assembler's policy of
2867 		     printing negative numbers as decimal and positive
2868 		     as hex.  */
2869 		  int value = ((insn_word >> 3) & IMM16_MASK);
2870 
2871 		  if ((value & 0x8000) || value == 0)
2872 		    {
2873 		      value = sign_extend (value, IMM16_BITS);
2874 		      len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,#%d",
2875 				      reg_brackets[0] ? "[" : "",
2876 				      reg_names[0], reg_brackets[0] ? "]" : "",
2877 				      reg_brackets[1] ? "[" : "",
2878 				      reg_names[1], reg_brackets[1] ? "]" : "",
2879 				      value);
2880 		    }
2881 		  else
2882 		    {
2883 		      len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,#%#x",
2884 				      reg_brackets[0] ? "[" : "",
2885 				      reg_names[0], reg_brackets[0] ? "]" : "",
2886 				      reg_brackets[1] ? "[" : "",
2887 				      reg_names[1], reg_brackets[1] ? "]" : "",
2888 				      value);
2889 		    }
2890 		}
2891 	      else
2892 		{
2893 		  len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,%s%s%s",
2894 				  reg_brackets[0] ? "[" : "",
2895 				  reg_names[0], reg_brackets[0] ? "]" : "",
2896 				  reg_brackets[1] ? "[" : "", reg_names[1],
2897 				  reg_brackets[1] ? "]" : "",
2898 				  reg_brackets[2] ? "[" : "",
2899 				  reg_names[2], reg_brackets[2] ? "]" : "");
2900 		}
2901 	    }
2902 	}
2903 
2904       snprintf (prefix, DSP_PREFIX_WIDTH, "D%s%s%s%s%s%s%s%s%s%s%s%s",
2905 		cc_flags ? cc_flags : "",
2906 		is_dual ? "L" : "",
2907 		is_quickrot64 ? "Q" : "",
2908 		is_unsigned ? "U" : "",
2909 		is_mod ? "M" : "",
2910 		is_acc_zero ? "Z" : "",
2911 		is_acc_add ? "P" : "", is_acc_sub ? "N" : "",
2912 		is_overflow ? "O" : "",
2913 		is_w_mx ? "W" : "",
2914 		is_b_mx ? "B" : "",
2915 		is_template ? "T" : "");
2916     }
2917   else if (template->arg_type & DSP_ARGS_2) /* Group 2.  */
2918     {
2919       bool is_template;
2920       bool o2r = false;
2921       int major = MAJOR_OPCODE (template->meta_opcode);
2922       bool is_neg_or_mov = (major == OPC_ADD || major == OPC_SUB);
2923       bool is_cmp_tst = major == OPC_CMP && (insn_word & 0x0000002c) == 0;
2924       bool is_fpu_mov = template->insn_type == INSN_DSP_FPU;
2925       bool 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       bool 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       bool round = false;
3125       bool clamp9 = false;
3126       bool clamp8 = false;
3127       bool 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 	      bool load = ((insn_word >> 13) & 0x1);
3202 	      bool 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 		  bool 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   int status;
3364 
3365   outf->bytes_per_chunk = 4;
3366   status = (*outf->read_memory_func) (pc & ~0x03, buf, 4, outf);
3367   if (status)
3368     {
3369       (*outf->memory_error_func) (status, pc, outf);
3370       return -1;
3371     }
3372   insn_word = bfd_getl32 (buf);
3373 
3374   for (i = 0; i < sizeof(metag_optab)/sizeof(metag_optab[0]); i++)
3375     {
3376       const insn_template *template = &metag_optab[i];
3377 
3378       if ((insn_word & template->meta_mask) == template->meta_opcode)
3379 	{
3380 	  enum insn_encoding encoding = template->encoding;
3381 	  insn_printer printer = insn_printers[encoding];
3382 
3383 	  if (printer)
3384 	    printer (insn_word, pc, template, outf);
3385 
3386 	  return 4;
3387 	}
3388     }
3389 
3390   return 4;
3391 }
3392