1143880Spjd/* Disassemble Imagination Technologies Meta instructions.
2143880Spjd   Copyright (C) 2013-2020 Free Software Foundation, Inc.
3143880Spjd   Contributed by Imagination Technologies Ltd.
4143880Spjd
5143880Spjd   This library is free software; you can redistribute it and/or modify
6143880Spjd   it under the terms of the GNU General Public License as published by
7143880Spjd   the Free Software Foundation; either version 3 of the License, or
8143880Spjd   (at your option) any later version.
9143880Spjd
10263351Sjmmv   It is distributed in the hope that it will be useful, but WITHOUT
11143880Spjd   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12143880Spjd   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
13143880Spjd   License for more details.
14143880Spjd
15143880Spjd   You should have received a copy of the GNU General Public License
16143880Spjd   along with this program; if not, write to the Free Software
17143880Spjd   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
18143880Spjd   MA 02110-1301, USA.  */
19143880Spjd
20143880Spjd#include "sysdep.h"
21143880Spjd#include "disassemble.h"
22143880Spjd#include "opintl.h"
23143880Spjd
24143880Spjd#include <stdio.h>
25143880Spjd#include <stdlib.h>
26143880Spjd#include <string.h>
27143880Spjd
28263351Sjmmv#include "opcode/metag.h"
29143880Spjd
30143880Spjd/* Column widths for printing.  */
31143880Spjd#define PREFIX_WIDTH    "10"
32143880Spjd#define INSN_NAME_WIDTH "10"
33143880Spjd
34143880Spjd#define OPERAND_WIDTH   92
35143880Spjd#define ADDR_WIDTH      20
36143880Spjd#define REG_WIDTH       64
37143880Spjd#define DSP_PREFIX_WIDTH 17
38143880Spjd
39143880Spjd/* Value to print if we fail to parse a register name.  */
40143880Spjdconst char unknown_reg[] = "?";
41143880Spjd
42143880Spjd/* Return the size of a GET or SET instruction.  */
43unsigned int
44metag_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.  */
61unsigned int
62metag_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.  */
79unsigned int
80metag_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.  */
97static int
98sign_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.  */
105static unsigned int
106short_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.  */
115static const metag_reg *
116lookup_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.  */
132static const char *
133lookup_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.  */
146static unsigned int
147get_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.  */
165static const char *
166lookup_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.  */
175static const char *
176lookup_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.  */
191static const char *
192lookup_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. */
283static const char *
284lookup_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. */
299static const char *
300lookup_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.  */
315static void
316print_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.  */
323static void
324print_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.  */
334static void
335print_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.  */
385static void
386print_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.  */
425static 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.  */
438static void
439print_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.  */
468static void
469get_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. */
548static void
549get_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.  */
578static void
579mget_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.  */
594static void
595cond_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.  */
610static void
611cache_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.  */
641static void
642lookup_reg_list (char *reg_buf, size_t buf_len, unsigned int reg_unit,
643		 unsigned int reg_no, unsigned int rmask,
644		 bfd_boolean is_fpu_64bit)
645{
646  const char *regs[MGET_MSET_MAX_REGS];
647  size_t used_regs = 1, i, remaining;
648
649  regs[0] = lookup_reg_name (reg_unit, reg_no);
650
651  for (i = 1; i < MGET_MSET_MAX_REGS; i++)
652    {
653      if (rmask & 1)
654	{
655	  if (is_fpu_64bit)
656	    regs[used_regs] = lookup_reg_name (reg_unit, reg_no + (i * 2));
657	  else
658	    regs[used_regs] = lookup_reg_name (reg_unit, reg_no + i);
659	  used_regs++;
660	}
661      rmask = rmask >> 1;
662    }
663
664  remaining = buf_len;
665
666  for (i = 0; i < used_regs; i++)
667    {
668      size_t len;
669      if (i == 0)
670	len = snprintf(reg_buf, remaining, "%s", regs[i]);
671      else
672	len = snprintf(reg_buf, remaining, ",%s", regs[i]);
673
674      reg_buf += len;
675      remaining -= len;
676    }
677}
678
679/* Print a GET instruction.  */
680static void
681print_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.  */
703static void
704print_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.  */
725static void
726print_get_set (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
727	       const insn_template *template,
728	       disassemble_info *outf)
729{
730  bfd_boolean is_get = MAJOR_OPCODE (template->meta_opcode) == OPC_GET;
731  char buf[OPERAND_WIDTH];
732  char addr_buf[ADDR_WIDTH];
733  unsigned int reg_unit, reg_no;
734  unsigned int size = metag_get_set_size_bytes (insn_word);
735  const char *reg_name;
736  const char *pair_reg;
737
738  reg_unit = (insn_word >> 1) & UNIT_MASK;
739  reg_no = (insn_word >> 19) & REG_MASK;
740
741  /* SETs should always print RD. */
742  if (!is_get && reg_unit == UNIT_RD)
743    reg_no = 0;
744
745  reg_name = lookup_reg_name (reg_unit, reg_no);
746
747  pair_reg = lookup_pair_reg_name (reg_unit, reg_no);
748
749  get_set_addr_str (addr_buf, ADDR_WIDTH, size, insn_word);
750
751  if (is_get)
752    {
753      /* RD regs are 64 bits wide so don't use the pair syntax.  */
754      if (reg_unit == UNIT_RD)
755	print_get (buf, addr_buf, 4, reg_name, pair_reg, reg_unit,
756		   template, outf);
757      else
758	print_get (buf, addr_buf, size, reg_name, pair_reg, reg_unit,
759		   template, outf);
760    }
761  else
762    {
763      /* RD regs are 64 bits wide so don't use the pair syntax.  */
764      if (reg_unit == UNIT_RD)
765	print_set (buf, addr_buf, 4, reg_name, pair_reg, reg_unit,
766		   template, outf);
767      else
768	print_set (buf, addr_buf, size, reg_name, pair_reg, reg_unit,
769		   template, outf);
770    }
771}
772
773/* Print an extended GET or SET instruction.  */
774static void
775print_get_set_ext (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
776		   const insn_template *template,
777		   disassemble_info *outf)
778{
779  bfd_boolean is_get = MINOR_OPCODE (template->meta_opcode) == GET_EXT_MINOR;
780  bfd_boolean is_mov = MINOR_OPCODE (template->meta_opcode) == MOV_EXT_MINOR;
781  char buf[OPERAND_WIDTH];
782  char addr_buf[ADDR_WIDTH];
783  unsigned int reg_unit, reg_no;
784  unsigned int size = metag_get_set_ext_size_bytes (insn_word);
785  const char *reg_name;
786  const char *pair_reg;
787
788  if (is_mov)
789    reg_unit = UNIT_RD;
790  else
791    reg_unit = short_unit ((insn_word >> 3) & SHORT_UNIT_MASK);
792
793  reg_no = (insn_word >> 19) & REG_MASK;
794
795  reg_name = lookup_reg_name (reg_unit, reg_no);
796
797  pair_reg = lookup_pair_reg_name (reg_unit, reg_no);
798
799  get_set_ext_addr_str (addr_buf, ADDR_WIDTH, size, insn_word);
800
801  if (is_get)
802    print_get (buf, addr_buf, size, reg_name, pair_reg, reg_unit,
803	       template, outf);
804  else if (is_mov)
805    print_get (buf, addr_buf, 4, reg_name, pair_reg, reg_unit,
806	       template, outf);
807  else
808    print_set (buf, addr_buf, size, reg_name, pair_reg, reg_unit,
809	       template, outf);
810}
811
812/* Print an MGET or MSET instruction.  */
813static void
814print_mget_mset (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
815		 const insn_template *template,
816		 disassemble_info *outf)
817{
818  bfd_boolean is_get = MAJOR_OPCODE (template->meta_opcode) == OPC_GET;
819  bfd_boolean is_fpu = (MINOR_OPCODE (template->meta_opcode) & 0x6) == 0x6;
820  bfd_boolean is_64bit = (MINOR_OPCODE (template->meta_opcode) & 0x1) == 0x1;
821  char buf[OPERAND_WIDTH];
822  char addr_buf[ADDR_WIDTH];
823  char reg_buf[REG_WIDTH];
824  unsigned int reg_unit, reg_no, rmask;
825
826  if (is_fpu)
827    reg_unit = UNIT_FX;
828  else
829    reg_unit = short_unit ((insn_word >> 3) & SHORT_UNIT_MASK);
830
831  reg_no = (insn_word >> 19) & REG_MASK;
832  rmask = (insn_word >> 7) & RMASK_MASK;
833
834  lookup_reg_list (reg_buf, REG_WIDTH, reg_unit, reg_no, rmask,
835		   is_fpu && is_64bit);
836
837  mget_mset_addr_str (addr_buf, ADDR_WIDTH, insn_word);
838
839  if (is_get)
840    snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_buf, addr_buf);
841  else
842    snprintf (buf, OPERAND_WIDTH, "%s,%s", addr_buf, reg_buf);
843
844  if (is_fpu)
845    print_insn (outf, "F", template->name, buf);
846  else
847    print_insn (outf, "", template->name, buf);
848}
849
850/* Print a conditional SET instruction.  */
851static void
852print_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.  */
884static void
885print_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.  */
970static void
971print_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.  */
988static void
989print_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.  */
1054static void
1055print_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.  */
1089static void
1090print_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.  */
1119static void
1120print_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.  */
1142static void
1143print_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.  */
1172static void
1173print_alu (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1174	   const insn_template *template,
1175	   disassemble_info *outf)
1176{
1177  char buf[OPERAND_WIDTH];
1178  unsigned int is_addr_op = MAJOR_OPCODE (template->meta_opcode) == OPC_ADDR;
1179  unsigned int is_mul = MAJOR_OPCODE (template->meta_opcode) == OPC_MUL;
1180  unsigned int dest_no, src1_no, src2_no;
1181  unsigned int imm = (insn_word >> 25) & 0x1;
1182  unsigned int cond = (insn_word >> 26) & 0x1;
1183  unsigned int o1z = 0;
1184  unsigned int o2r = insn_word & 0x1;
1185  unsigned int unit_bit = (insn_word >> 24) & 0x1;
1186  unsigned int ca = (insn_word >> 5) & 0x1;
1187  unsigned int se = (insn_word >> 1) & 0x1;
1188  bfd_boolean is_quickrot = template->arg_type & GP_ARGS_QR;
1189  enum metag_unit base_unit;
1190  enum metag_unit dest_unit;
1191  const char *dest_reg;
1192  const char *src1_reg;
1193  const char *src2_reg;
1194  int value;
1195
1196  if ((MAJOR_OPCODE (template->meta_opcode) == OPC_ADDR ||
1197      MAJOR_OPCODE (template->meta_opcode) == OPC_ADD ||
1198       MAJOR_OPCODE (template->meta_opcode) == OPC_SUB) &&
1199      ((insn_word >> 2) & 0x1))
1200    o1z = 1;
1201
1202  if (is_addr_op)
1203    {
1204      if (unit_bit)
1205	base_unit = UNIT_A1;
1206      else
1207	base_unit = UNIT_A0;
1208    }
1209  else
1210    {
1211      if (unit_bit)
1212	base_unit = UNIT_D1;
1213      else
1214	base_unit = UNIT_D0;
1215    }
1216
1217  dest_no = (insn_word >> 19) & REG_MASK;
1218  src1_no = (insn_word >> 14) & REG_MASK;
1219  src2_no = (insn_word >> 9) & REG_MASK;
1220
1221  dest_unit = base_unit;
1222
1223  if (imm)
1224    {
1225      if (cond)
1226	{
1227	  if (ca)
1228	    {
1229	      dest_unit = (insn_word >> 1) & UNIT_MASK;
1230	      dest_reg = lookup_reg_name (dest_unit, dest_no);
1231	    }
1232	  else
1233	      dest_reg = lookup_reg_name (dest_unit, dest_no);
1234
1235	  src1_reg = lookup_reg_name (base_unit, src1_no);
1236
1237	  value = (insn_word >> 6) & IMM8_MASK;
1238
1239	  if (is_quickrot)
1240	    {
1241	      unsigned int qr_unit = unit_bit ? UNIT_A1 : UNIT_A0;
1242	      unsigned int qr_no = 2;
1243	      const char *qr_reg = lookup_reg_name (qr_unit, qr_no);
1244
1245	      snprintf (buf, OPERAND_WIDTH, "%s,%s,#%#x,%s", dest_reg,
1246			src1_reg, value, qr_reg);
1247	    }
1248	  else
1249	    snprintf (buf, OPERAND_WIDTH, "%s,%s,#%#x", dest_reg,
1250		      src1_reg, value);
1251	}
1252      else
1253	{
1254	  if (is_addr_op && (dest_no & ~CPC_REG_MASK))
1255	    {
1256	      dest_reg = lookup_reg_name (dest_unit, dest_no & CPC_REG_MASK);
1257	      src1_reg = lookup_reg_name (base_unit, 0x10);
1258	    }
1259	  else
1260	    {
1261	      dest_reg = lookup_reg_name (dest_unit, dest_no);
1262	      src1_reg = lookup_reg_name (base_unit, dest_no);
1263	    }
1264
1265	  value = (insn_word >> 3) & IMM16_MASK;
1266
1267	  if (se)
1268	    {
1269	      value = sign_extend (value, IMM16_BITS);
1270	      if (o1z)
1271		{
1272		  snprintf (buf, OPERAND_WIDTH, "%s,#%d", dest_reg, value);
1273		}
1274	      else
1275		{
1276		  snprintf (buf, OPERAND_WIDTH, "%s,%s,#%d", dest_reg,
1277			    src1_reg, value);
1278		}
1279	    }
1280	  else
1281	    {
1282	      if (o1z)
1283		{
1284		  snprintf (buf, OPERAND_WIDTH, "%s,#%#x", dest_reg, value);
1285		}
1286	      else
1287		{
1288		  snprintf (buf, OPERAND_WIDTH, "%s,%s,#%#x", dest_reg,
1289			    src1_reg, value);
1290		}
1291	    }
1292	}
1293    }
1294  else
1295    {
1296      src1_reg = lookup_reg_name (base_unit, src1_no);
1297
1298      if (o2r)
1299	src2_reg = lookup_o2r (base_unit, src2_no);
1300      else
1301	src2_reg = lookup_reg_name (base_unit, src2_no);
1302
1303      if (cond)
1304	{
1305	  dest_unit = (insn_word >> 5) & UNIT_MASK;
1306
1307	  if (is_mul)
1308	    {
1309	      if (ca)
1310		dest_unit = (insn_word >> 1) & UNIT_MASK;
1311	      else
1312		dest_unit = base_unit;
1313	    }
1314
1315	  dest_reg = lookup_reg_name (dest_unit, dest_no);
1316
1317	  snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg,
1318		    src1_reg, src2_reg);
1319	}
1320      else
1321	{
1322	  dest_reg = lookup_reg_name (dest_unit, dest_no);
1323
1324	  if (is_quickrot)
1325	    {
1326	      unsigned int qr_unit = unit_bit ? UNIT_A1 : UNIT_A0;
1327	      unsigned int qr_no = 2 + ((insn_word >> 7) & 0x1);
1328	      const char *qr_reg = lookup_reg_name (qr_unit, qr_no);
1329
1330	      snprintf (buf, OPERAND_WIDTH, "%s,%s,%s,%s", dest_reg,
1331			src1_reg, src2_reg, qr_reg);
1332	    }
1333	  else if (o1z)
1334	    {
1335	      snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src2_reg);
1336	    }
1337	  else
1338	    {
1339	      snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg,
1340			src1_reg, src2_reg);
1341	    }
1342	}
1343    }
1344
1345  if (dest_unit == UNIT_FX)
1346    print_insn (outf, "F", template->name, buf);
1347  else
1348    print_insn (outf, "", template->name, buf);
1349}
1350
1351/* Print a B instruction.  */
1352static void
1353print_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.  */
1373static void
1374print_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.  */
1389static void
1390print_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.  */
1453static void
1454print_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.  */
1484static void
1485print_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.  */
1534static void
1535print_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.  */
1602static void
1603print_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.  */
1631static void
1632print_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.  */
1660static void
1661print_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.  */
1682static void
1683print_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.  */
1711static void
1712print_fmov (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
1713	    const insn_template *template,
1714	    disassemble_info *outf)
1715{
1716  char buf[OPERAND_WIDTH];
1717  char prefix_buf[10];
1718  unsigned int src_no, dest_no;
1719  unsigned int p = (insn_word >> 6) & 0x1;
1720  unsigned int d = (insn_word >> 5) & 0x1;
1721  unsigned int cc = (insn_word >> 1) & CC_MASK;
1722  bfd_boolean show_cond = cc != COND_A && cc != COND_NV;
1723  const char *dest_reg;
1724  const char *src_reg;
1725  const char *cc_flags;
1726
1727  dest_no = (insn_word >> 19) & REG_MASK;
1728  src_no = (insn_word >> 14) & REG_MASK;
1729
1730  dest_reg = lookup_reg_name (UNIT_FX, dest_no);
1731  src_reg = lookup_reg_name (UNIT_FX, src_no);
1732
1733  cc_flags = lookup_fpu_scc_flags (cc);
1734
1735  snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg);
1736
1737  snprintf (prefix_buf, 10, "F%s%s%s", p ? "L" : "",
1738	    d ? "D" : "", show_cond ? cc_flags : "");
1739
1740  print_insn (outf, prefix_buf, template->name, buf);
1741}
1742
1743/* Convert an FPU rmask into a compatible form. */
1744static unsigned int
1745convert_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.  */
1760static void
1761print_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  bfd_boolean to_fpu = MAJOR_OPCODE (insn_word) == OPC_GET;
1773  bfd_boolean 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.  */
1798static void
1799print_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.  */
1836static void
1837print_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.  */
1863static void
1864print_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.  */
1888static void
1889print_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.  */
1910static void
1911print_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  bfd_boolean 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.  */
1950static void
1951print_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  bfd_boolean 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.  */
1986static void
1987print_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  bfd_boolean 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.  */
2019static void
2020print_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  bfd_boolean 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.  */
2058static void
2059print_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  bfd_boolean 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.  */
2095static void
2096print_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  bfd_boolean is_muz = (MINOR_OPCODE (insn_word) == 0x6 &&
2103			((insn_word >> 4) & 0x1));
2104  bfd_boolean is_mac = (MINOR_OPCODE (insn_word) == 0x6 &&
2105			(insn_word & 0x1f) == 0);
2106  bfd_boolean is_maw = (MINOR_OPCODE (insn_word) == 0x6 &&
2107			((insn_word >> 3) & 0x1));
2108  unsigned int o3o = insn_word & 0x1;
2109  unsigned int q = is_muz && ((insn_word >> 1) & 0x1);
2110  unsigned int n = (insn_word >> 7) & 0x1;
2111  unsigned int p = (insn_word >> 6) & 0x1;
2112  unsigned int d = (insn_word >> 5) & 0x1;
2113  unsigned int cc = (insn_word >> 1) & CC_MASK;
2114  bfd_boolean show_cond = (MINOR_OPCODE (insn_word) == 0x5 && cc != COND_A &&
2115			   cc != COND_NV);
2116  unsigned int src1_no, src2_no, dest_no;
2117  const char *dest_reg;
2118  const char *src1_reg;
2119  const char *src2_reg;
2120  const char *cc_flags;
2121
2122  dest_no = (insn_word >> 19) & REG_MASK;
2123  src1_no = (insn_word >> 14) & REG_MASK;
2124  src2_no = (insn_word >> 9) & REG_MASK;
2125
2126  dest_reg = lookup_reg_name (UNIT_FX, dest_no);
2127  src1_reg = lookup_reg_name (UNIT_FX, src1_no);
2128  src2_reg = lookup_reg_name (UNIT_FX, src2_no);
2129
2130  cc_flags = lookup_fpu_scc_flags (cc);
2131
2132  if (is_mac)
2133    snprintf (buf, OPERAND_WIDTH, "ACF.0,%s,%s", src1_reg, src2_reg);
2134  else if (o3o && is_maw)
2135    snprintf (buf, OPERAND_WIDTH, "%s,%s", src1_reg, src2_reg);
2136  else
2137    snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg);
2138
2139  snprintf (prefix_buf, 10, "F%s%s%s%s%s", p ? "L" : "",
2140	    d ? "D" : "", n ? "I" : "", q ? "Q" : "",
2141	    show_cond ? cc_flags : "");
2142
2143  print_insn (outf, prefix_buf, template->name, buf);
2144}
2145
2146/* Print an FPU RCP or RSQ instruction.  */
2147static void
2148print_frec (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2149	    const insn_template *template,
2150	    disassemble_info *outf)
2151{
2152  char buf[OPERAND_WIDTH];
2153  char prefix_buf[10];
2154  unsigned int z = (insn_word >> 10) & 0x1;
2155  unsigned int q = (insn_word >> 9) & 0x1;
2156  unsigned int n = (insn_word >> 7) & 0x1;
2157  unsigned int p = (insn_word >> 6) & 0x1;
2158  unsigned int d = (insn_word >> 5) & 0x1;
2159  unsigned int src_no, dest_no;
2160  const char *dest_reg;
2161  const char *src_reg;
2162
2163  dest_no = (insn_word >> 19) & REG_MASK;
2164  src_no = (insn_word >> 14) & REG_MASK;
2165
2166  dest_reg = lookup_reg_name (UNIT_FX, dest_no);
2167  src_reg = lookup_reg_name (UNIT_FX, src_no);
2168
2169  snprintf (buf, OPERAND_WIDTH, "%s,%s", dest_reg, src_reg);
2170
2171  snprintf (prefix_buf, 10, "F%s%s%s%s%s", p ? "L" : "",
2172	    d ? "D" : "", n ? "I" : "", q ? "Q" : "", z ? "Z" : "");
2173
2174  print_insn (outf, prefix_buf, template->name, buf);
2175}
2176
2177static void
2178print_fsimd (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2179	     const insn_template *template,
2180	     disassemble_info *outf)
2181{
2182  char buf[OPERAND_WIDTH];
2183  unsigned int n = (insn_word >> 7) & 0x1;
2184  unsigned int src1_no, src2_no, dest_no;
2185  const char *dest_reg;
2186  const char *src1_reg;
2187  const char *src2_reg;
2188
2189  dest_no = (insn_word >> 19) & REG_MASK;
2190  src1_no = (insn_word >> 14) & REG_MASK;
2191  src2_no = (insn_word >> 9) & REG_MASK;
2192
2193  dest_reg = lookup_reg_name (UNIT_FX, dest_no);
2194  src1_reg = lookup_reg_name (UNIT_FX, src1_no);
2195  src2_reg = lookup_reg_name (UNIT_FX, src2_no);
2196
2197  snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", dest_reg, src1_reg, src2_reg);
2198
2199  if (n)
2200    print_insn (outf, "FLI", template->name, buf);
2201  else
2202    print_insn (outf, "FL", template->name, buf);
2203}
2204
2205/* Print an FPU accumulator GET or SET instruction.  */
2206static void
2207print_fget_set_acf (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2208		    const insn_template *template,
2209		    disassemble_info *outf)
2210{
2211  bfd_boolean is_get = MAJOR_OPCODE (template->meta_opcode) == OPC_GET;
2212  char buf[OPERAND_WIDTH];
2213  char addr_buf[ADDR_WIDTH];
2214  unsigned int part;
2215  const char *reg_name;
2216
2217  part = (insn_word >> 19) & ACF_PART_MASK;
2218
2219  reg_name = lookup_acf_name (part);
2220
2221  mget_mset_addr_str (addr_buf, ADDR_WIDTH, insn_word);
2222
2223  if (is_get)
2224    {
2225      snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_name, addr_buf);
2226    }
2227  else
2228    {
2229      snprintf (buf, OPERAND_WIDTH, "%s,%s", addr_buf, reg_name);
2230    }
2231  print_insn (outf, "F", template->name, buf);
2232}
2233
2234/* Return the name of the DSP register or accumulator for NUM and UNIT.  */
2235static const char *
2236__lookup_dsp_name (unsigned int num, unsigned int unit)
2237{
2238  size_t i;
2239
2240  for (i = 0; i < sizeof(metag_dsp_regtab)/sizeof(metag_dsp_regtab[0]); i++)
2241    {
2242      const metag_reg *reg = &metag_dsp_regtab[i];
2243
2244      if (reg->no == num)
2245	{
2246	  if ((reg->unit == UNIT_RAM_D0 || reg->unit == UNIT_ACC_D0) &&
2247	      unit == UNIT_D0)
2248	    return reg->name;
2249
2250	  if ((reg->unit == UNIT_RAM_D1 || reg->unit == UNIT_ACC_D1) &&
2251	      unit == UNIT_D1)
2252	    return reg->name;
2253	}
2254    }
2255  return "?.?";
2256}
2257
2258/* Return the name of the DSP register for NUM and UNIT.  */
2259static const char *
2260lookup_dsp_name (unsigned int num, unsigned int unit)
2261{
2262  size_t i;
2263
2264  for (i = 0; i < sizeof(metag_dsp_regtab)/sizeof(metag_dsp_regtab[0]); i++)
2265    {
2266      const metag_reg *reg = &metag_dsp_regtab[i];
2267
2268      if (reg->no == num && reg->unit == unit)
2269	return reg->name;
2270    }
2271  return "?.?";
2272}
2273
2274/* Return the name of the DSP RAM register for NUM and UNIT.  */
2275static const char *
2276lookup_dspram_name (unsigned int num, unsigned int unit, bfd_boolean load)
2277{
2278  size_t i, nentries;
2279
2280  nentries = sizeof(metag_dsp_tmpl_regtab[load])/sizeof(metag_dsp_tmpl_regtab[load][0]);
2281
2282  for (i = 0; i < nentries; i++)
2283    {
2284      const metag_reg *reg = &metag_dsp_tmpl_regtab[load][i];
2285
2286      if (reg->no == num && reg->unit == unit)
2287	return reg->name;
2288    }
2289  return "?.?";
2290}
2291
2292/* This lookup function looks up the corresponding name for a register
2293   number in a DSP instruction. SOURCE indicates whether this
2294   register is a source or destination operand.  */
2295static const char *
2296lookup_any_reg_name (unsigned int unit, unsigned int num, bfd_boolean source)
2297{
2298  /* A register with the top bit set (5th bit) indicates a DSPRAM
2299     register.  */
2300  if (num > 15)
2301    {
2302      unsigned int dunit = (unit == UNIT_D0) ? UNIT_RAM_D0 : UNIT_RAM_D1;
2303      return lookup_dspram_name (num, dunit, source);
2304    }
2305  else
2306    return lookup_reg_name (unit, num);
2307}
2308
2309/* Return the DSP data unit for UNIT.  */
2310static inline enum metag_unit
2311dsp_data_unit_to_sym (unsigned int unit)
2312{
2313  if (unit == 0)
2314    return UNIT_D0;
2315  else
2316    return UNIT_D1;
2317}
2318
2319/* Print a DSP GET or SET instruction.  */
2320static void
2321print_dget_set (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2322		const insn_template *template,
2323		disassemble_info *outf)
2324{
2325  bfd_boolean is_get = (template->meta_opcode & 0x100);
2326  char buf[OPERAND_WIDTH];
2327  char addr_buf[ADDR_WIDTH];
2328  char prefix[DSP_PREFIX_WIDTH];
2329  unsigned int part;
2330  const char *reg_name[2];
2331  bfd_boolean is_high = FALSE;
2332  bfd_boolean is_dual = (insn_word & 0x4);
2333  bfd_boolean is_template = (insn_word & 0x2);
2334  const char *base_reg = "?";
2335  unsigned int addr_unit, base_no, unit;
2336
2337  unit = dsp_data_unit_to_sym (insn_word & 0x1);
2338
2339  /* Is this a load/store to a template table?  */
2340  if (is_template)
2341    {
2342      part = (insn_word >> 19) & 0x1f;
2343      reg_name[0] = lookup_dsp_name (part, UNIT_DT);
2344    }
2345  else
2346    {
2347      part = (insn_word >> 19) & REG_MASK;
2348      is_high = ((part & 0x18) == 0x18);
2349
2350      /* Strip bit high indicator.  */
2351      if (is_high)
2352	part &= 0x17;
2353
2354      reg_name[0] = __lookup_dsp_name (part, unit);
2355
2356    }
2357
2358  /* Is this a dual unit DSP operation?  The modulo operator below
2359     makes sure that we print the Rd register in the correct order,
2360     e.g. because there's only one bit in the instruction for the Data
2361     Unit we have to work out what the other data unit number is.
2362     (there's only 2).  */
2363  if (is_dual)
2364    {
2365      unsigned int _unit = insn_word & 0x1;
2366
2367      _unit = ((_unit + 1) % 2);
2368      reg_name[1] = __lookup_dsp_name(part, dsp_data_unit_to_sym (_unit));
2369    }
2370  else
2371    reg_name[1] = NULL;
2372
2373  addr_unit = ((insn_word >> 18) & 0x1);
2374  if (addr_unit == 0)
2375	  addr_unit = UNIT_A0;
2376  else
2377	  addr_unit = UNIT_A1;
2378
2379  base_no = (insn_word >> 14) & DSP_REG_MASK;
2380
2381  base_reg = lookup_reg_name (addr_unit, base_no);
2382
2383  /* Check if it's a post-increment/post-decrement.  */
2384  if (insn_word & 0x2000)
2385  {
2386	  unsigned int imm = (insn_word >> 9) & DGET_SET_IMM_MASK;
2387	  const char *post_op;
2388
2389	  switch (imm)
2390	    {
2391	    case 0x1:
2392	      post_op = "++";
2393	      break;
2394	    case 0x3:
2395	      post_op = "--";
2396	      break;
2397	    default:
2398	      post_op = "";
2399	    }
2400
2401	  snprintf (addr_buf, ADDR_WIDTH, "[%s%s]", base_reg, post_op);
2402  }
2403  else
2404  {
2405	  unsigned int offset_part = (insn_word >> 9) & DSP_REG_MASK;
2406	  const char *offset_reg = lookup_reg_name (addr_unit, offset_part);
2407
2408	  snprintf (addr_buf, ADDR_WIDTH, "[%s+%s++]", base_reg, offset_reg);
2409  }
2410
2411  if (is_get)
2412    {
2413      if (is_dual && !is_template)
2414	snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", reg_name[0],
2415		  reg_name[1], addr_buf);
2416      else
2417	snprintf (buf, OPERAND_WIDTH, "%s,%s", reg_name[0], addr_buf);
2418    }
2419  else
2420    {
2421      if (is_dual && !is_template)
2422	snprintf (buf, OPERAND_WIDTH, "%s,%s,%s", addr_buf,
2423		  reg_name[0], reg_name[1]);
2424      else
2425	snprintf (buf, OPERAND_WIDTH, "%s,%s", addr_buf, reg_name[0]);
2426    }
2427
2428  snprintf (prefix, DSP_PREFIX_WIDTH, "D%s", is_high ? "H" : "");
2429  print_insn (outf, prefix, template->name, buf);
2430}
2431
2432/* Print a DSP template instruction.  */
2433static void
2434print_dtemplate (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2435		 const insn_template *template,
2436		 disassemble_info *outf)
2437{
2438  char buf[OPERAND_WIDTH];
2439  char prefix[DSP_PREFIX_WIDTH];
2440  unsigned int offset[4];
2441  bfd_boolean is_half = (MINOR_OPCODE (insn_word) == 0x5);
2442  bfd_boolean daop_only = (MINOR_OPCODE (insn_word) == 0x3);
2443
2444  offset[0] = ((insn_word >> 19) & REG_MASK);
2445  offset[1] = ((insn_word >> 14) & REG_MASK);
2446  offset[2] = ((insn_word >> 9) & REG_MASK);
2447  offset[3] = ((insn_word >> 4) & REG_MASK);
2448
2449  if (daop_only)
2450	  snprintf (buf, OPERAND_WIDTH, "#0x%x,#0x%x,#0x%x", offset[0],
2451		    offset[1], offset[2]);
2452  else
2453    {
2454      snprintf (buf, OPERAND_WIDTH, "#0x%x,#0x%x,#0x%x,#0x%x", offset[0],
2455		offset[1], offset[2], offset[3]);
2456    }
2457
2458  snprintf (prefix, DSP_PREFIX_WIDTH, "D%s", is_half ? "H" : "");
2459  print_insn (outf, prefix, template->name, buf);
2460}
2461
2462/* Format template definition from INSN_WORD into BUF.  */
2463static void
2464decode_template_definition(unsigned int insn_word, char *buf, size_t len)
2465{
2466  bfd_boolean load = ((insn_word >> 13) & 0x1);
2467  bfd_boolean dspram = (((insn_word >> 17) & 0x3) == 0x3);
2468  const char *template[1];
2469  unsigned int tidx = ((insn_word >> 9) & TEMPLATE_REGS_MASK);
2470  enum metag_unit au, ram_unit;
2471  unsigned int addr_reg_nums[2];
2472  const char *addr_reg_names[2];
2473  const char *post_op = "";
2474  const char *join_op = "";
2475  enum metag_unit data_unit = ((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0;
2476
2477  template[0] = lookup_dsp_name (tidx, UNIT_DT);
2478
2479  addr_reg_names[1] = "";
2480
2481  if (dspram)
2482    {
2483      ram_unit = (data_unit == UNIT_D0) ? UNIT_RAM_D0 : UNIT_RAM_D1;
2484      addr_reg_nums[0] = ((insn_word >> 19) & REG_MASK);
2485      addr_reg_names[0] = lookup_dspram_name (addr_reg_nums[0],
2486					      ram_unit, load);
2487    }
2488  else
2489    {
2490      bfd_boolean im = (((insn_word >> 18) & 0x1) != 0);
2491
2492      au = (((insn_word >> 23) & 0x1) == 0) ? UNIT_A0 : UNIT_A1;
2493      addr_reg_nums[0] = ((insn_word >> 19) & DSP_REG_MASK);
2494
2495      addr_reg_names[0] = lookup_reg_name (au, addr_reg_nums[0]);
2496
2497      if (im)
2498	{
2499	  unsigned int im_value = ((insn_word >> 14) & 0x3);
2500
2501	  switch (im_value)
2502	    {
2503	    case 0x1:
2504	      post_op = "++";
2505	      break;
2506	    case 0x3:
2507	      post_op = "--";
2508	      break;
2509	    }
2510	}
2511      else
2512	{
2513	  addr_reg_nums[1] = ((insn_word >> 14) & DSP_REG_MASK);
2514	  addr_reg_names[1] = lookup_reg_name (au, addr_reg_nums[1]);
2515	  join_op = "+";
2516	  post_op = "++";
2517	}
2518    }
2519
2520  if (load)
2521    {
2522      len = snprintf (buf, len, " %s,[%s%s%s%s]", template[0], addr_reg_names[0],
2523		      join_op, addr_reg_names[1], post_op);
2524    }
2525  else
2526    {
2527      len = snprintf (buf, len, " [%s%s%s%s],%s", addr_reg_names[0], join_op,
2528		      addr_reg_names[1], post_op, template[0]);
2529    }
2530}
2531
2532/* Print a DSP ALU instruction.  */
2533static void
2534print_dalu (unsigned int insn_word, bfd_vma pc ATTRIBUTE_UNUSED,
2535	    const insn_template *template,
2536	    disassemble_info *outf)
2537{
2538  bfd_boolean is_dual = FALSE;
2539  unsigned int data_unit = (((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0);
2540  const char *reg_names[3];
2541  unsigned int reg_nums[3];
2542  bfd_boolean ac = ((insn_word >> 7) & 0x1);
2543  char buf[OPERAND_WIDTH];
2544  char prefix[DSP_PREFIX_WIDTH];
2545  size_t len;
2546  bfd_boolean is_mod = FALSE;
2547  bfd_boolean is_overflow = FALSE;
2548  unsigned int reg_brackets[3];
2549  bfd_boolean is_w_mx = FALSE;
2550  bfd_boolean is_b_mx = FALSE;
2551  bfd_boolean imm = FALSE;
2552  bfd_boolean is_quickrot64 = FALSE;
2553  bfd_boolean conditional = FALSE;
2554  const char *cc_flags = NULL;
2555  bfd_boolean is_unsigned = FALSE;
2556
2557  memset (reg_brackets, 0, sizeof (reg_brackets));
2558
2559  if (template->arg_type & DSP_ARGS_1)
2560    {
2561      bfd_boolean is_template = FALSE;
2562      const char *addr_reg = NULL;
2563      bfd_boolean qr = FALSE;
2564      bfd_boolean is_acc_add = FALSE;
2565      bfd_boolean is_acc_sub = FALSE;
2566      bfd_boolean is_acc_zero = FALSE;
2567      bfd_boolean is_split8 = (template->arg_type & DSP_ARGS_SPLIT8);
2568
2569      /* Read DU bit.  */
2570      data_unit = ((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0;
2571
2572      conditional = ((insn_word >> 24) & 0x4);
2573
2574      /* Templates can't be conditional.  */
2575      is_template = (((insn_word & 0x02000002) == 0x2) && !conditional);
2576
2577      if (is_split8)
2578	is_mod = (insn_word & 0x80);
2579
2580      if (template->arg_type & DSP_ARGS_QR)
2581	{
2582	  if (!conditional)
2583	    is_quickrot64 = ((insn_word >> 5) & 0x1);
2584	}
2585
2586      if (template->arg_type & DSP_ARGS_DACC)
2587	{
2588	  is_mod = (insn_word & 0x8);
2589	  is_unsigned = (insn_word & 0x40);
2590	}
2591
2592      if (is_template)
2593	{
2594	  is_w_mx = (insn_word & 0x1);
2595	  is_dual = ((insn_word >> 0x4) & 0x1);
2596
2597	  /* De.r,Dx.r,De.r|ACe.r */
2598	  if (template->arg_type & DSP_ARGS_ACC2)
2599	    {
2600	      is_mod = (insn_word & 0x8);
2601	      is_overflow = (insn_word & 0x20);
2602	    }
2603
2604	  /* ACe.e,ACx.r,ACo.e? */
2605	  if ((template->arg_type & DSP_ARGS_XACC) &&
2606	      (((insn_word >> 6) & 0x5) == 0x5))
2607	    {
2608	      enum metag_unit ac_unit, ao_unit;
2609
2610	      ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1;
2611
2612	      if (ac_unit == UNIT_ACC_D0)
2613		ao_unit = UNIT_ACC_D1;
2614	      else
2615		ao_unit = UNIT_ACC_D0;
2616
2617	      reg_nums[1] = ((insn_word >> 19) & REG_MASK);
2618
2619	      /* These are dummy arguments anyway so the register
2620		 number does not matter.  */
2621	      reg_names[0] = lookup_dsp_name (16, ac_unit); /* ACe.0 */
2622	      reg_names[1] = lookup_dsp_name (16, ac_unit); /* ACx.0 */
2623	      reg_names[2] = lookup_dsp_name (16, ao_unit); /* ACo.0 */
2624	    }
2625	  else
2626	    {
2627	      /* De.r|ACe.r,Dx.r,De.r */
2628	      if (template->arg_type & DSP_ARGS_DACC &&
2629		  ((insn_word & 0x84) != 0))
2630		{
2631		  enum metag_unit ac_unit;
2632
2633		  ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1;
2634		  reg_names[0] = lookup_dsp_name (16, ac_unit);
2635
2636		  is_acc_zero = ((insn_word & 0x84) == 0x04);
2637		  is_acc_add = ((insn_word & 0x84) == 0x80);
2638		  is_acc_sub = ((insn_word & 0x84) == 0x84);
2639		}
2640	      else
2641		reg_names[0] = lookup_any_reg_name (data_unit, 0, FALSE);
2642
2643	      /* These are dummy arguments anyway so the register
2644		 number does not matter.  */
2645	      reg_names[1] = lookup_any_reg_name (data_unit, 0, TRUE);
2646
2647	      /* De.r,Dx.r,De.r|ACe.r */
2648	      if ((template->arg_type & DSP_ARGS_ACC2) &&
2649		  ((insn_word & 0x80) == 0x80))
2650		{
2651		  enum metag_unit ac_unit;
2652
2653		  ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1;
2654		  reg_names[2] = lookup_dsp_name (16, ac_unit);
2655		}
2656	      /* Detection of QUICKRoT and accumulator usage uses the
2657		 same bits. They are mutually exclusive.  */
2658	      else if (ac && (template->arg_type & DSP_ARGS_ACC2))
2659		{
2660		  reg_nums[2] = ((insn_word >> 9) & REG_MASK);
2661
2662		  if (data_unit == UNIT_D0)
2663		    reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D0);
2664		  else
2665		    reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D1);
2666		}
2667	      else
2668		{
2669		  if ((template->arg_type & DSP_ARGS_QR) &&
2670		      ((insn_word & 0x40) == 0x40))
2671		    {
2672		      enum metag_unit aunit;
2673		      int reg_no;
2674
2675		      if (conditional)
2676			reg_no = ((insn_word >> 5) & 0x1);
2677		      else
2678			reg_no = ((insn_word >> 7) & 0x1);
2679
2680		      aunit = (data_unit == UNIT_D0) ? UNIT_A0 : UNIT_A1;
2681		      addr_reg = lookup_reg_name (aunit, reg_no + 2);
2682
2683		      qr = TRUE;
2684		    }
2685
2686		  reg_names[2] = lookup_any_reg_name (data_unit, 0, TRUE);
2687		}
2688	    }
2689
2690	  if (qr)
2691	    {
2692	      len = snprintf (buf, OPERAND_WIDTH, "%s,%s,%s,%s",
2693			      reg_names[0], reg_names[1], reg_names[2],
2694			      addr_reg);
2695	    }
2696	  else
2697	    {
2698	      len = snprintf (buf, OPERAND_WIDTH, "%s,%s,%s%s%s",
2699			      reg_names[0], reg_names[1],
2700			      reg_brackets[2] ? "[" : "",
2701			      reg_names[2], reg_brackets[2] ? "]" : "");
2702	    }
2703
2704	  decode_template_definition (insn_word, buf + len,
2705				      OPERAND_WIDTH - len);
2706	}
2707      else			/* Not a template definiton.  */
2708	{
2709	  reg_nums[0] = ((insn_word >> 19) & REG_MASK);
2710	  reg_nums[1] = ((insn_word >> 14) & REG_MASK);
2711	  reg_nums[2] = ((insn_word >> 9) & REG_MASK);
2712
2713	  imm = (((insn_word >> 24) & 0x2) && (template->arg_type & DSP_ARGS_IMM));
2714
2715	  if (imm)
2716	    is_dual = (insn_word & 0x4);
2717	  else if (!conditional)
2718	    is_dual = (insn_word & 0x10);
2719	  else
2720	    cc_flags = lookup_scc_flags ((insn_word >> 1) & CC_MASK);
2721
2722	  /* De.r,Dx.r,De.r|ACe.r */
2723	  if (template->arg_type & DSP_ARGS_ACC2)
2724	    {
2725	      is_mod = (insn_word & 0x8);
2726	      is_overflow = (insn_word & 0x20);
2727	    }
2728
2729	  if (template->arg_type & DSP_ARGS_SPLIT8)
2730	    {
2731	      is_overflow = (insn_word & 0x20);
2732	    }
2733
2734	  /* ACe.e,ACx.r,ACo.e? */
2735	  if ((template->arg_type & DSP_ARGS_XACC) &&
2736	      (((insn_word >> 6) & 0x5) == 0x5))
2737	    {
2738	      enum metag_unit ac_unit, ao_unit;
2739
2740	      ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1;
2741
2742	      if (ac_unit == UNIT_ACC_D0)
2743		ao_unit = UNIT_ACC_D1;
2744	      else
2745		ao_unit = UNIT_ACC_D0;
2746
2747	      reg_nums[1] = ((insn_word >> 19) & REG_MASK);
2748	      reg_names[0] = lookup_dsp_name (reg_nums[1], ac_unit);
2749	      reg_names[1] = lookup_dsp_name (reg_nums[1], ac_unit);
2750	      reg_names[2] = lookup_dsp_name (reg_nums[1], ao_unit);
2751	    }
2752	  else
2753	    {
2754	      bfd_boolean o2r = (insn_word & 0x1);
2755
2756	      /* De.r|ACe.r,Dx.r,De.r */
2757	      if ((template->arg_type & DSP_ARGS_DACC) &&
2758		  ((insn_word & 0x84) != 0))
2759		{
2760		  enum metag_unit ac_unit;
2761
2762		  ac_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1;
2763		  reg_names[0] = lookup_dsp_name (reg_nums[0], ac_unit);
2764
2765		  is_acc_zero = ((insn_word & 0x84) == 0x04);
2766		  is_acc_add = ((insn_word & 0x84) == 0x80);
2767		  is_acc_sub = ((insn_word & 0x84) == 0x84);
2768		}
2769	      else if (conditional)
2770		{
2771		  reg_names[0] = lookup_reg_name (data_unit, reg_nums[0]);
2772		}
2773	      else
2774		{
2775		  reg_names[0] = lookup_any_reg_name (data_unit,
2776						      reg_nums[0], FALSE);
2777		  if (reg_nums[0] > 15)
2778		    reg_brackets[0] = 1;
2779		}
2780
2781	      if (imm)
2782		{
2783		  reg_names[1] = lookup_any_reg_name (data_unit, reg_nums[0], TRUE);
2784
2785		  if (reg_brackets[0])
2786		    reg_brackets[1] = 1;
2787		  }
2788	      else
2789		{
2790		  if (is_split8 && is_mod)
2791		    {
2792		      reg_names[1] = lookup_reg_name (data_unit, reg_nums[1]);
2793		    }
2794		  else
2795		  {
2796		    reg_names[1] = lookup_any_reg_name (data_unit, reg_nums[1], TRUE);
2797
2798		    if (reg_nums[1] > 15)
2799		      reg_brackets[1] = 1;
2800		  }
2801		}
2802
2803	      /* Detection of QUICKRoT and accumulator usage uses the
2804		 same bits. They are mutually exclusive.  */
2805	      if (ac && (template->arg_type & DSP_ARGS_ACC2))
2806		{
2807		  if (data_unit == UNIT_D0)
2808		    reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D0);
2809		  else
2810		    reg_names[2] = lookup_dsp_name (reg_nums[2], UNIT_ACC_D1);
2811		}
2812
2813	      else
2814		{
2815		  if ((template->arg_type & DSP_ARGS_QR) &&
2816		      ((insn_word & 0x40) == 0x40))
2817		    {
2818		      enum metag_unit aunit;
2819		      int reg_no;
2820
2821		      if (conditional)
2822			reg_no = ((insn_word >> 5) & 0x1);
2823		      else
2824			reg_no = ((insn_word >> 7) & 0x1);
2825
2826		      aunit = (data_unit == UNIT_D0) ? UNIT_A0 : UNIT_A1;
2827		      addr_reg = lookup_reg_name (aunit, reg_no + 2);
2828
2829		      qr = TRUE;
2830		    }
2831
2832		  if (o2r)
2833		    reg_names[2] = lookup_o2r (data_unit, reg_nums[2]);
2834		  else
2835		    {
2836		      /* Can't use a DSPRAM reg if both QD and L1 are
2837			 set on a QUICKRoT instruction or if we're a
2838			 split 8.  */
2839		      if (((template->arg_type & DSP_ARGS_QR)
2840			   && ((insn_word & 0x30) == 0x30 && !conditional)) ||
2841			  (is_split8 && is_mod))
2842			reg_names[2] = lookup_reg_name (data_unit, reg_nums[2]);
2843		      else
2844			{
2845			  reg_names[2] = lookup_any_reg_name (data_unit,
2846							      reg_nums[2], TRUE);
2847			  if (reg_nums[2] > 15)
2848			    reg_brackets[2] = 1;
2849			}
2850		    }
2851		}
2852	    }
2853
2854	  if (qr)
2855	    {
2856	      len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,%s%s%s,%s",
2857			      reg_brackets[0] ? "[" : "",
2858			      reg_names[0], reg_brackets[0] ? "]" : "",
2859			      reg_brackets[1] ? "[" : "",
2860			      reg_names[1], reg_brackets[1] ? "]" : "",
2861			      reg_brackets[2] ? "[" : "",
2862			      reg_names[2], reg_brackets[2] ? "]" : "",
2863			      addr_reg);
2864	    }
2865	  else
2866	    {
2867	      if (imm)
2868		{
2869		  /* Conform to the embedded assembler's policy of
2870		     printing negative numbers as decimal and positive
2871		     as hex.  */
2872		  int value = ((insn_word >> 3) & IMM16_MASK);
2873
2874		  if ((value & 0x8000) || value == 0)
2875		    {
2876		      value = sign_extend (value, IMM16_BITS);
2877		      len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,#%d",
2878				      reg_brackets[0] ? "[" : "",
2879				      reg_names[0], reg_brackets[0] ? "]" : "",
2880				      reg_brackets[1] ? "[" : "",
2881				      reg_names[1], reg_brackets[1] ? "]" : "",
2882				      value);
2883		    }
2884		  else
2885		    {
2886		      len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,#%#x",
2887				      reg_brackets[0] ? "[" : "",
2888				      reg_names[0], reg_brackets[0] ? "]" : "",
2889				      reg_brackets[1] ? "[" : "",
2890				      reg_names[1], reg_brackets[1] ? "]" : "",
2891				      value);
2892		    }
2893		}
2894	      else
2895		{
2896		  len = snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,%s%s%s",
2897				  reg_brackets[0] ? "[" : "",
2898				  reg_names[0], reg_brackets[0] ? "]" : "",
2899				  reg_brackets[1] ? "[" : "", reg_names[1],
2900				  reg_brackets[1] ? "]" : "",
2901				  reg_brackets[2] ? "[" : "",
2902				  reg_names[2], reg_brackets[2] ? "]" : "");
2903		}
2904	    }
2905	}
2906
2907      snprintf (prefix, DSP_PREFIX_WIDTH, "D%s%s%s%s%s%s%s%s%s%s%s%s",
2908		cc_flags ? cc_flags : "",
2909		is_dual ? "L" : "",
2910		is_quickrot64 ? "Q" : "",
2911		is_unsigned ? "U" : "",
2912		is_mod ? "M" : "",
2913		is_acc_zero ? "Z" : "",
2914		is_acc_add ? "P" : "", is_acc_sub ? "N" : "",
2915		is_overflow ? "O" : "",
2916		is_w_mx ? "W" : "",
2917		is_b_mx ? "B" : "",
2918		is_template ? "T" : "");
2919    }
2920  else if (template->arg_type & DSP_ARGS_2) /* Group 2.  */
2921    {
2922      bfd_boolean is_template;
2923      bfd_boolean o2r = FALSE;
2924      int major = MAJOR_OPCODE (template->meta_opcode);
2925      bfd_boolean is_neg_or_mov = (major == OPC_ADD || major == OPC_SUB);
2926      bfd_boolean is_cmp_tst = ((major == OPC_CMP) &&
2927				((insn_word & 0x0000002c) == 0));
2928      bfd_boolean is_fpu_mov = template->insn_type == INSN_DSP_FPU;
2929      bfd_boolean to_fpu = (template->meta_opcode >> 7) & 0x1;
2930
2931      if (major == OPC_9)
2932	imm = (insn_word & 0x2);
2933      else if (template->arg_type & DSP_ARGS_IMM)
2934	imm = ((insn_word >> 25) & 0x1);
2935
2936      is_template = (((insn_word & 0x02000002) == 0x2) &&
2937		     major != OPC_9);
2938
2939      if (imm)
2940	is_dual = ((insn_word >> 0x2) & 0x1);
2941      else
2942	is_dual = ((insn_word >> 0x4) & 0x1);
2943
2944      /* MOV and XSD[BW] do not have o2r.  */
2945      if (major != OPC_9 && major != OPC_MISC)
2946	o2r = (insn_word & 0x1);
2947
2948      if (is_neg_or_mov)
2949	{
2950	  is_mod = (insn_word & 0x8);
2951	  is_overflow = (insn_word & 0x20);
2952	}
2953
2954      /* XSD */
2955      if (major == OPC_MISC)
2956	data_unit = (insn_word & 0x1) ? UNIT_D1 : UNIT_D0;
2957      else
2958	data_unit = ((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0;
2959
2960      /* Check for NEG,MOV,ABS,FFB, etc.  */
2961      if (is_neg_or_mov || !is_cmp_tst || imm ||
2962	  MAJOR_OPCODE (insn_word) == OPC_9 ||
2963	  MAJOR_OPCODE (insn_word) == OPC_MISC)
2964	reg_nums[0] = ((insn_word >> 19) & REG_MASK);
2965      else
2966	reg_nums[0] = ((insn_word >> 14) & REG_MASK);
2967
2968      if (is_template)
2969	{
2970	  is_w_mx = (insn_word & 0x1);
2971
2972	  /* These are dummy arguments anyway so the register number
2973	     does not matter.  */
2974	  if (is_fpu_mov)
2975	    {
2976	      if (to_fpu)
2977		{
2978		  reg_names[0] = lookup_reg_name (UNIT_FX, 0);
2979		  reg_names[1] = lookup_reg_name (data_unit, 0);
2980		}
2981	      else
2982		{
2983		  reg_names[0] = lookup_reg_name (data_unit, 0);
2984		  reg_names[1] = lookup_reg_name (UNIT_FX, 0);
2985		}
2986	    }
2987	  else
2988	    {
2989	      reg_names[0] = lookup_reg_name (data_unit, 0);
2990	      reg_names[1] = lookup_reg_name (data_unit, 0);
2991	    }
2992
2993	  len = snprintf (buf, OPERAND_WIDTH, "%s,%s",
2994			  reg_names[0], reg_names[1]);
2995
2996	  decode_template_definition (insn_word, buf + len,
2997				      OPERAND_WIDTH - len);
2998	}
2999      else
3000	{
3001	  if (imm)
3002	    {
3003	      /* Conform to the embedded assembler's policy of
3004		 printing negative numbers as decimal and positive as
3005		 hex.  */
3006	      unsigned int value = ((insn_word >> 3) & IMM16_MASK);
3007
3008	      if (major == OPC_9)
3009		{
3010		  data_unit = (insn_word & 0x1) ? UNIT_D1 : UNIT_D0;
3011		  is_dual = (insn_word & 0x4);
3012
3013		  reg_names[0] = __lookup_dsp_name (reg_nums[0], data_unit);
3014		}
3015	      else
3016		{
3017		  reg_names[0] = lookup_any_reg_name (data_unit, reg_nums[0], TRUE);
3018		  if (reg_nums[0] > 15)
3019		    reg_brackets[0] = 1;
3020		}
3021
3022	      if ((value & 0x8000) || value == 0)
3023		{
3024		  value = sign_extend (value, IMM16_BITS);
3025		  snprintf (buf, OPERAND_WIDTH, "%s%s%s,#%d",
3026			    reg_brackets[0] ? "[" : "",
3027			    reg_names[0], reg_brackets[0] ? "]" : "",
3028			    value);
3029		}
3030	      else
3031		{
3032		  snprintf (buf, OPERAND_WIDTH, "%s%s%s,#0x%x",
3033			    reg_brackets[0] ? "[" : "",
3034			    reg_names[0], reg_brackets[0] ? "]" : "",
3035			    value);
3036		}
3037	    }
3038	  else
3039	    {
3040	      if (is_neg_or_mov || is_cmp_tst)
3041		reg_nums[1] = ((insn_word >> 9) & REG_MASK);
3042	      else
3043		reg_nums[1] = ((insn_word >> 14) & REG_MASK);
3044
3045	      if (major == OPC_9)
3046		{
3047		  is_dual = (insn_word & 0x4);
3048		  data_unit = (insn_word & 0x1) ? UNIT_D1 : UNIT_D0;
3049
3050		  if (MINOR_OPCODE (template->meta_opcode) == 0x1)
3051		    reg_names[0] = __lookup_dsp_name (reg_nums[0], data_unit);
3052		  else
3053		    reg_names[0] = lookup_reg_name (data_unit, reg_nums[0]);
3054		}
3055	      else
3056		{
3057		  unsigned int reg0_unit = data_unit;
3058
3059		  if (is_fpu_mov && to_fpu)
3060		    reg0_unit = UNIT_FX;
3061
3062		  reg_names[0] = lookup_any_reg_name (reg0_unit, reg_nums[0],
3063						      (!is_neg_or_mov && is_cmp_tst));
3064		  if (reg_nums[0] > 15)
3065		    reg_brackets[0] = 1;
3066		}
3067
3068	      if (o2r)
3069		reg_names[1] = lookup_o2r (data_unit, reg_nums[1]);
3070	      else
3071		{
3072		  /* Check for accumulator argument.  */
3073		  if (is_neg_or_mov && ((insn_word & 0x80) == 0x80))
3074		    {
3075		      if (data_unit == UNIT_D0)
3076			reg_names[1] = lookup_dsp_name (reg_nums[1], UNIT_ACC_D0);
3077		      else
3078			reg_names[1] = lookup_dsp_name (reg_nums[1], UNIT_ACC_D1);
3079		    }
3080		  else
3081		    {
3082		      if (major == OPC_9)
3083			{
3084			  if (MINOR_OPCODE (template->meta_opcode) == 0x1)
3085			    {
3086			      reg_names[1] = lookup_reg_name (data_unit, reg_nums[1]);
3087			    }
3088			  else
3089			    {
3090			      enum metag_unit u;
3091
3092			      u = (insn_word & 0x1) ? UNIT_RAM_D1 : UNIT_RAM_D0;
3093			      reg_names[1] = lookup_dsp_name (reg_nums[1], u);
3094			    }
3095			}
3096		      else
3097			{
3098			  reg_names[1] = lookup_any_reg_name (data_unit,
3099							      reg_nums[1], TRUE);
3100			  if (reg_nums[1] > 15)
3101			    reg_brackets[1] = 1;
3102			}
3103		    }
3104		}
3105
3106	      snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s",
3107			reg_brackets[0] ? "[" : "", reg_names[0],
3108			reg_brackets[0] ? "]" : "",
3109			reg_brackets[1] ? "[" : "", reg_names[1],
3110			reg_brackets[1] ? "]" : "");
3111	    }
3112	}
3113
3114      snprintf (prefix, DSP_PREFIX_WIDTH, "D%s%s%s%s%s%s",
3115		is_fpu_mov ? "F" : "",
3116		is_dual ? "L" : "",
3117		is_mod ? "M" : "", is_overflow ? "O" : "",
3118		is_w_mx ? "W" : "",
3119		is_template ? "T" : "");
3120    }
3121  else				/* Group 3. */
3122    {
3123      /* If both the C and CA bits are set, then the Rd register can
3124	 be in any unit. Figure out which unit from the Ud field.  */
3125      bfd_boolean all_units = (((insn_word) & 0x04000020) == 0x04000020);
3126      enum metag_unit ud_unit = ((insn_word >> 1) & UNIT_MASK);
3127      enum metag_unit ram_unit, acc_unit;
3128      bfd_boolean round = FALSE;
3129      bfd_boolean clamp9 = FALSE;
3130      bfd_boolean clamp8 = FALSE;
3131      bfd_boolean is_template = ((insn_word & 0x04000002) == 0x2);
3132
3133      imm = ((insn_word >> 25) & 0x1);
3134      ac = (insn_word & 0x1);
3135
3136      conditional = (MINOR_OPCODE (insn_word) & 0x4);
3137
3138      /* Check for conditional and not Condition Always.  */
3139      if (conditional && !(insn_word & 0x20))
3140	cc_flags = lookup_scc_flags ((insn_word >> 1) & CC_MASK);
3141      else if (!(conditional && (insn_word & 0x20)))
3142	is_dual = ((insn_word >> 0x4) & 0x1);
3143
3144      /* Conditional instructions don't have the L1 or RSPP fields.  */
3145      if ((insn_word & 0x04000000) == 0)
3146	{
3147	  round = (((insn_word >> 2) & 0x3) == 0x1);
3148	  clamp9 = (((insn_word >> 2) & 0x3) == 0x2);
3149	  clamp8 = (((insn_word >> 2) & 0x3) == 0x3);
3150	}
3151
3152      /* Read DU bit.  */
3153      data_unit = ((insn_word >> 24) & 0x1) ? UNIT_D1 : UNIT_D0;
3154      reg_nums[0] = ((insn_word >> 19) & REG_MASK);
3155      reg_nums[1] = ((insn_word >> 14) & REG_MASK);
3156
3157      ram_unit = (data_unit == UNIT_D0) ? UNIT_RAM_D0 : UNIT_RAM_D1;
3158      acc_unit = (data_unit == UNIT_D0) ? UNIT_ACC_D0 : UNIT_ACC_D1;
3159
3160      if (all_units)
3161	reg_names[0] = lookup_reg_name (ud_unit, reg_nums[0]);
3162      else
3163	{
3164	  if (conditional)
3165	    reg_names[0] = lookup_reg_name (data_unit, reg_nums[0]);
3166	  else
3167	    {
3168	      reg_names[0] = lookup_any_reg_name (data_unit, reg_nums[0], FALSE);
3169	      if (reg_nums[0] > 15)
3170		reg_brackets[0] = 1;
3171	    }
3172	}
3173
3174      if (ac)
3175	{
3176	  reg_names[1] = lookup_dsp_name (reg_nums[1], acc_unit);
3177	}
3178      else
3179	{
3180	  reg_names[1] = lookup_any_reg_name (data_unit, reg_nums[1], TRUE);
3181	  if (reg_nums[1] > 15)
3182	    reg_brackets[1] = 1;
3183	}
3184
3185      if (imm)
3186	{
3187	  snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,#%#x",
3188		    reg_brackets[0] ? "[" : "",
3189		    reg_names[0], reg_brackets[0] ? "]" : "",
3190		    reg_brackets[1] ? "[" : "",
3191		    reg_names[1], reg_brackets[1] ? "]" : "",
3192		    ((insn_word >> 9) & IMM5_MASK));
3193	}
3194      else
3195	{
3196	  reg_nums[2] = ((insn_word >> 9) & REG_MASK);
3197
3198	  reg_names[2] = lookup_any_reg_name (data_unit, reg_nums[2], TRUE);
3199
3200	  if (reg_nums[2] > 15)
3201		  reg_brackets[2] = 1;
3202
3203	  if (is_template)
3204	    {
3205	      bfd_boolean load = ((insn_word >> 13) & 0x1);
3206	      bfd_boolean dspram = (((insn_word >> 17) & 0x3) == 0x3);
3207	      const char *tname[1];
3208	      unsigned int tidx = ((insn_word >> 9) & TEMPLATE_REGS_MASK);
3209	      enum metag_unit au;
3210	      unsigned int addr_reg_nums[2];
3211	      const char *addr_reg_names[2];
3212	      const char *post_op = "";
3213	      const char *join_op = "";
3214
3215	      is_w_mx = ((insn_word >> 5) & 0x1);
3216
3217	      tname[0] = lookup_dsp_name (tidx, UNIT_DT);
3218
3219	      /* These are dummy arguments anyway */
3220	      reg_names[0] = lookup_reg_name (data_unit, 0);
3221	      if (ac)
3222		reg_names[1] = lookup_dsp_name (16, acc_unit);
3223	      else
3224		reg_names[1] = lookup_reg_name (data_unit, 0);
3225	      reg_names[2] = lookup_reg_name (data_unit, 0);
3226
3227	      addr_reg_names[1] = "";
3228
3229	      if (dspram)
3230		{
3231		  ram_unit = (data_unit == UNIT_D0) ? UNIT_RAM_D0 : UNIT_RAM_D1;
3232		  addr_reg_nums[0] = ((insn_word >> 19) & REG_MASK);
3233		  addr_reg_names[0] = lookup_dspram_name (addr_reg_nums[0],
3234							  ram_unit, load);
3235		}
3236	      else
3237		{
3238		  bfd_boolean im = (((insn_word >> 18) & 0x1) != 0);
3239
3240		  au = (((insn_word >> 23) & 0x1) == 0) ? UNIT_A0 : UNIT_A1;
3241		  addr_reg_nums[0] = ((insn_word >> 19) & DSP_REG_MASK);
3242
3243		  addr_reg_names[0] = lookup_reg_name (au, addr_reg_nums[0]);
3244
3245		  if (im)
3246		    {
3247		      unsigned int im_value = ((insn_word >> 14) & 0x3);
3248
3249		      switch (im_value)
3250			{
3251			case 0x1:
3252			  post_op = "++";
3253			  break;
3254			case 0x3:
3255			  post_op = "--";
3256			  break;
3257			}
3258		    }
3259		  else
3260		    {
3261		      addr_reg_nums[1] = ((insn_word >> 14) & DSP_REG_MASK);
3262		      addr_reg_names[1] = lookup_reg_name (au, addr_reg_nums[1]);
3263		      join_op = "+";
3264		      post_op = "++";
3265		    }
3266		}
3267
3268	      if (load)
3269		{
3270		  snprintf (buf, OPERAND_WIDTH, "%s,%s,%s %s,[%s%s%s%s]",
3271			    reg_names[0], reg_names[1], reg_names[2],
3272			    tname[0], addr_reg_names[0], join_op,
3273			    addr_reg_names[1], post_op);
3274		}
3275	      else
3276		{
3277		  snprintf (buf, OPERAND_WIDTH, "%s,%s,%s [%s%s%s%s],%s",
3278			    reg_names[0], reg_names[1], reg_names[2],
3279			    addr_reg_names[0], join_op, addr_reg_names[1],
3280			    post_op, tname[0]);
3281		}
3282	    }
3283	  else
3284	    {
3285	      snprintf (buf, OPERAND_WIDTH, "%s%s%s,%s%s%s,%s%s%s",
3286			reg_brackets[0] ? "[" : "",
3287			reg_names[0], reg_brackets[0] ? "]" : "",
3288			reg_brackets[1] ? "[" : "",
3289			reg_names[1], reg_brackets[1] ? "]" : "",
3290			reg_brackets[2] ? "[" : "",
3291			reg_names[2], reg_brackets[2] ? "]" : "");
3292	    }
3293	}
3294
3295      snprintf (prefix, DSP_PREFIX_WIDTH, "D%s%s%s%s%s%s%s",
3296		cc_flags ? cc_flags : "",
3297		is_dual ? "L" : "", clamp9 ? "G" : "",
3298		clamp8 ? "B" : "", round ? "R" : "",
3299		is_w_mx ? "W" : "",
3300		is_template ? "T" : "");
3301    }
3302
3303  print_insn (outf, prefix, template->name, buf);
3304
3305}
3306
3307typedef void (*insn_printer)(unsigned int, bfd_vma, const insn_template *,
3308			     disassemble_info *);
3309
3310/* Printer table.  */
3311static const insn_printer insn_printers[ENC_MAX] =
3312  {
3313    [ENC_NONE] = print_none,
3314    [ENC_MOV_U2U] = print_mov_u2u,
3315    [ENC_MOV_PORT] = print_mov_port,
3316    [ENC_MMOV] = print_mmov,
3317    [ENC_MDRD] = print_mdrd,
3318    [ENC_MOVL_TTREC] = print_movl_ttrec,
3319    [ENC_GET_SET] = print_get_set,
3320    [ENC_GET_SET_EXT] = print_get_set_ext,
3321    [ENC_MGET_MSET] = print_mget_mset,
3322    [ENC_COND_SET] = print_cond_set,
3323    [ENC_XFR] = print_xfr,
3324    [ENC_MOV_CT] = print_mov_ct,
3325    [ENC_SWAP] = print_swap,
3326    [ENC_JUMP] = print_jump,
3327    [ENC_CALLR] = print_callr,
3328    [ENC_ALU] = print_alu,
3329    [ENC_SHIFT] = print_shift,
3330    [ENC_MIN_MAX] = print_min_max,
3331    [ENC_BITOP] = print_bitop,
3332    [ENC_CMP] = print_cmp,
3333    [ENC_BRANCH] = print_branch,
3334    [ENC_KICK] = print_mov_u2u,
3335    [ENC_SWITCH] = print_switch,
3336    [ENC_CACHER] = print_cacher,
3337    [ENC_CACHEW] = print_cachew,
3338    [ENC_ICACHE] = print_icache,
3339    [ENC_LNKGET] = print_lnkget,
3340    [ENC_FMOV] = print_fmov,
3341    [ENC_FMMOV] = print_fmmov,
3342    [ENC_FMOV_DATA] = print_fmov_data,
3343    [ENC_FMOV_I] = print_fmov_i,
3344    [ENC_FPACK] = print_fpack,
3345    [ENC_FSWAP] = print_fswap,
3346    [ENC_FCMP] = print_fcmp,
3347    [ENC_FMINMAX] = print_fminmax,
3348    [ENC_FCONV] = print_fconv,
3349    [ENC_FCONVX] = print_fconvx,
3350    [ENC_FBARITH] = print_fbarith,
3351    [ENC_FEARITH] = print_fearith,
3352    [ENC_FREC] = print_frec,
3353    [ENC_FSIMD] = print_fsimd,
3354    [ENC_FGET_SET_ACF] = print_fget_set_acf,
3355    [ENC_DGET_SET] = print_dget_set,
3356    [ENC_DTEMPLATE] = print_dtemplate,
3357    [ENC_DALU] = print_dalu,
3358  };
3359
3360/* Entry point for instruction printing.  */
3361int
3362print_insn_metag (bfd_vma pc, disassemble_info *outf)
3363{
3364  bfd_byte buf[4];
3365  unsigned int insn_word;
3366  size_t i;
3367  int status;
3368
3369  outf->bytes_per_chunk = 4;
3370  status = (*outf->read_memory_func) (pc & ~0x03, buf, 4, outf);
3371  if (status)
3372    {
3373      (*outf->memory_error_func) (status, pc, outf);
3374      return -1;
3375    }
3376  insn_word = bfd_getl32 (buf);
3377
3378  for (i = 0; i < sizeof(metag_optab)/sizeof(metag_optab[0]); i++)
3379    {
3380      const insn_template *template = &metag_optab[i];
3381
3382      if ((insn_word & template->meta_mask) == template->meta_opcode)
3383	{
3384	  enum insn_encoding encoding = template->encoding;
3385	  insn_printer printer = insn_printers[encoding];
3386
3387	  if (printer)
3388	    printer (insn_word, pc, template, outf);
3389
3390	  return 4;
3391	}
3392    }
3393
3394  return 4;
3395}
3396