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