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