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