]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - opcodes/cr16-dis.c
* MAINTAINERS: Update my email.
[thirdparty/binutils-gdb.git] / opcodes / cr16-dis.c
CommitLineData
3d3d428f 1/* Disassembler code for CR16.
e20cc039 2 Copyright 2007, 2008, 2009, 2012 Free Software Foundation, Inc.
3d3d428f
NC
3 Contributed by M R Swami Reddy (MR.Swami.Reddy@nsc.com).
4
5 This file is part of GAS, GDB and the GNU binutils.
6
9b201bb5
NC
7 This program is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3, or (at your option)
3d3d428f
NC
10 any later version.
11
12 This program is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
20
3d3d428f 21#include "sysdep.h"
df7b86aa 22#include "dis-asm.h"
3d3d428f
NC
23#include "opcode/cr16.h"
24#include "libiberty.h"
25
26/* String to print when opcode was not matched. */
27#define ILLEGAL "illegal"
28 /* Escape to 16-bit immediate. */
29#define ESCAPE_16_BIT 0xB
30
31/* Extract 'n_bits' from 'a' starting from offset 'offs'. */
32#define EXTRACT(a, offs, n_bits) \
33 (n_bits == 32 ? (((a) >> (offs)) & 0xffffffffL) \
34 : (((a) >> (offs)) & ((1 << (n_bits)) -1)))
35
36/* Set Bit Mask - a mask to set all bits starting from offset 'offs'. */
37#define SBM(offs) ((((1 << (32 - offs)) -1) << (offs)))
38
39typedef unsigned long dwordU;
40typedef unsigned short wordU;
41
42typedef struct
43{
44 dwordU val;
45 int nbits;
46} parameter;
47
48/* Structure to map valid 'cinv' instruction options. */
49
50typedef struct
51 {
52 /* Cinv printed string. */
53 char *istr;
54 /* Value corresponding to the string. */
55 char *ostr;
56 }
57cinv_entry;
58
59/* CR16 'cinv' options mapping. */
60const cinv_entry cr16_cinvs[] =
61{
62 {"cinv[i]", "cinv [i]"},
63 {"cinv[i,u]", "cinv [i,u]"},
64 {"cinv[d]", "cinv [d]"},
65 {"cinv[d,u]", "cinv [d,u]"},
66 {"cinv[d,i]", "cinv [d,i]"},
67 {"cinv[d,i,u]", "cinv [d,i,u]"}
68};
69
70/* Number of valid 'cinv' instruction options. */
71static int NUMCINVS = ARRAY_SIZE (cr16_cinvs);
72
73/* Enum to distinguish different registers argument types. */
74typedef enum REG_ARG_TYPE
75 {
76 /* General purpose register (r<N>). */
77 REG_ARG = 0,
78 /*Processor register */
79 P_ARG,
80 }
81REG_ARG_TYPE;
82
83/* Current opcode table entry we're disassembling. */
84const inst *instruction;
85/* Current instruction we're disassembling. */
86ins currInsn;
87/* The current instruction is read into 3 consecutive words. */
88wordU words[3];
89/* Contains all words in appropriate order. */
90ULONGLONG allWords;
91/* Holds the current processed argument number. */
92int processing_argument_number;
93/* Nonzero means a IMM4 instruction. */
94int imm4flag;
95/* Nonzero means the instruction's original size is
96 incremented (escape sequence is used). */
97int size_changed;
98
99
100/* Print the constant expression length. */
101
102static char *
103print_exp_len (int size)
104{
105 switch (size)
106 {
107 case 4:
108 case 5:
109 case 6:
110 case 8:
111 case 14:
112 case 16:
113 return ":s";
114 case 20:
115 case 24:
116 case 32:
117 return ":m";
118 case 48:
119 return ":l";
120 default:
121 return "";
122 }
123}
124
125
126/* Retrieve the number of operands for the current assembled instruction. */
127
128static int
129get_number_of_operands (void)
130{
131 int i;
132
133 for (i = 0; instruction->operands[i].op_type && i < MAX_OPERANDS; i++)
134 ;
135
136 return i;
137}
138
139/* Return the bit size for a given operand. */
140
141static int
142getbits (operand_type op)
143{
144 if (op < MAX_OPRD)
145 return cr16_optab[op].bit_size;
146
147 return 0;
148}
149
150/* Return the argument type of a given operand. */
151
152static argtype
153getargtype (operand_type op)
154{
155 if (op < MAX_OPRD)
156 return cr16_optab[op].arg_type;
157
158 return nullargs;
159}
160
161/* Given a 'CC' instruction constant operand, return its corresponding
162 string. This routine is used when disassembling the 'CC' instruction. */
163
164static char *
91d6fa6a 165getccstring (unsigned cc_insn)
3d3d428f 166{
91d6fa6a 167 return (char *) cr16_b_cond_tab[cc_insn];
3d3d428f
NC
168}
169
170
171/* Given a 'cinv' instruction constant operand, return its corresponding
172 string. This routine is used when disassembling the 'cinv' instruction. */
173
174static char *
ddb341a7 175getcinvstring (const char *str)
3d3d428f
NC
176{
177 const cinv_entry *cinv;
178
179 for (cinv = cr16_cinvs; cinv < (cr16_cinvs + NUMCINVS); cinv++)
180 if (strcmp (cinv->istr, str) == 0)
181 return cinv->ostr;
182
183 return ILLEGAL;
184}
185
186/* Given the trap index in dispatch table, return its name.
187 This routine is used when disassembling the 'excp' instruction. */
188
189static char *
91d6fa6a 190gettrapstring (unsigned int trap_index)
3d3d428f
NC
191{
192 const trap_entry *trap;
193
194 for (trap = cr16_traps; trap < cr16_traps + NUMTRAPS; trap++)
91d6fa6a 195 if (trap->entry == trap_index)
3d3d428f
NC
196 return trap->name;
197
198 return ILLEGAL;
199}
200
201/* Given a register enum value, retrieve its name. */
202
203static char *
204getregname (reg r)
205{
91d6fa6a 206 const reg_entry * regentry = cr16_regtab + r;
3d3d428f 207
91d6fa6a 208 if (regentry->type != CR16_R_REGTYPE)
3d3d428f
NC
209 return ILLEGAL;
210
91d6fa6a 211 return regentry->name;
3d3d428f
NC
212}
213
214/* Given a register pair enum value, retrieve its name. */
215
216static char *
217getregpname (reg r)
218{
91d6fa6a 219 const reg_entry * regentry = cr16_regptab + r;
3d3d428f 220
91d6fa6a 221 if (regentry->type != CR16_RP_REGTYPE)
3d3d428f
NC
222 return ILLEGAL;
223
91d6fa6a 224 return regentry->name;
3d3d428f
NC
225}
226
227/* Given a index register pair enum value, retrieve its name. */
228
229static char *
230getidxregpname (reg r)
231{
91d6fa6a 232 const reg_entry * regentry;
3d3d428f
NC
233
234 switch (r)
235 {
236 case 0: r = 0; break;
237 case 1: r = 2; break;
238 case 2: r = 4; break;
239 case 3: r = 6; break;
240 case 4: r = 8; break;
241 case 5: r = 10; break;
242 case 6: r = 3; break;
243 case 7: r = 5; break;
244 default:
245 break;
246 }
247
91d6fa6a 248 regentry = cr16_regptab + r;
3d3d428f 249
91d6fa6a 250 if (regentry->type != CR16_RP_REGTYPE)
3d3d428f
NC
251 return ILLEGAL;
252
91d6fa6a 253 return regentry->name;
3d3d428f
NC
254}
255
256/* Getting a processor register name. */
257
258static char *
91d6fa6a 259getprocregname (int reg_index)
3d3d428f
NC
260{
261 const reg_entry *r;
262
263 for (r = cr16_pregtab; r < cr16_pregtab + NUMPREGS; r++)
91d6fa6a 264 if (r->image == reg_index)
3d3d428f
NC
265 return r->name;
266
267 return "ILLEGAL REGISTER";
268}
269
270/* Getting a processor register name - 32 bit size. */
271
272static char *
91d6fa6a 273getprocpregname (int reg_index)
3d3d428f
NC
274{
275 const reg_entry *r;
276
277 for (r = cr16_pregptab; r < cr16_pregptab + NUMPREGPS; r++)
91d6fa6a 278 if (r->image == reg_index)
3d3d428f
NC
279 return r->name;
280
281 return "ILLEGAL REGISTER";
282}
283
284/* START and END are relating 'allWords' struct, which is 48 bits size.
285
286 START|--------|END
287 +---------+---------+---------+---------+
288 | | V | A | L |
289 +---------+---------+---------+---------+
290 0 16 32 48
291 words [0] [1] [2] */
292
293static parameter
294makelongparameter (ULONGLONG val, int start, int end)
295{
296 parameter p;
297
298 p.val = (dwordU) EXTRACT (val, 48 - end, end - start);
299 p.nbits = end - start;
300 return p;
301}
302
303/* Build a mask of the instruction's 'constant' opcode,
304 based on the instruction's printing flags. */
305
306static unsigned long
307build_mask (void)
308{
309 unsigned long mask = SBM (instruction->match_bits);
3ce6fddb
NC
310
311 /* Adjust mask for bcond with 32-bit size instruction. */
312 if ((IS_INSN_MNEMONIC("b") && instruction->size == 2))
313 mask = 0xff0f0000;
314
3d3d428f
NC
315 return mask;
316}
317
318/* Search for a matching opcode. Return 1 for success, 0 for failure. */
319
320static int
321match_opcode (void)
322{
323 unsigned long mask;
324 /* The instruction 'constant' opcode doewsn't exceed 32 bits. */
59b098c9 325 unsigned long doubleWord = (words[1] + (words[0] << 16)) & 0xffffffff;
3d3d428f
NC
326
327 /* Start searching from end of instruction table. */
328 instruction = &cr16_instruction[NUMOPCODES - 2];
329
330 /* Loop over instruction table until a full match is found. */
331 while (instruction >= cr16_instruction)
332 {
333 mask = build_mask ();
59b098c9
SR
334 /* Adjust mask for bcond with 32-bit size instruction */
335 if ((IS_INSN_MNEMONIC("b") && instruction->size == 2))
336 mask = 0xff0f0000;
337
3d3d428f
NC
338 if ((doubleWord & mask) == BIN (instruction->match,
339 instruction->match_bits))
340 return 1;
341 else
342 instruction--;
343 }
344 return 0;
345}
346
347/* Set the proper parameter value for different type of arguments. */
348
349static void
350make_argument (argument * a, int start_bits)
351{
352 int inst_bit_size;
353 parameter p;
354
355 if ((instruction->size == 3) && a->size >= 16)
356 inst_bit_size = 48;
357 else
358 inst_bit_size = 32;
359
360 switch (a->type)
361 {
362 case arg_r:
363 p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
364 inst_bit_size - start_bits);
365 a->r = p.val;
366 break;
367
368 case arg_rp:
369 p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
370 inst_bit_size - start_bits);
371 a->rp = p.val;
372 break;
373
374 case arg_pr:
375 p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
376 inst_bit_size - start_bits);
377 a->pr = p.val;
378 break;
379
380 case arg_prp:
381 p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
382 inst_bit_size - start_bits);
383 a->prp = p.val;
384 break;
385
386 case arg_ic:
387 p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
388 inst_bit_size - start_bits);
389 a->constant = p.val;
390 break;
391
392 case arg_cc:
393 p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
394 inst_bit_size - start_bits);
395
396 a->cc = p.val;
397 break;
398
399 case arg_idxr:
400 if ((IS_INSN_MNEMONIC ("cbitb"))
401 || (IS_INSN_MNEMONIC ("sbitb"))
402 || (IS_INSN_MNEMONIC ("tbitb")))
403 p = makelongparameter (allWords, 8, 9);
404 else
405 p = makelongparameter (allWords, 9, 10);
406 a->i_r = p.val;
407 p = makelongparameter (allWords, inst_bit_size - a->size, inst_bit_size);
408 a->constant = p.val;
409 break;
410
411 case arg_idxrp:
412 p = makelongparameter (allWords, start_bits + 12, start_bits + 13);
413 a->i_r = p.val;
414 p = makelongparameter (allWords, start_bits + 13, start_bits + 16);
415 a->rp = p.val;
416 if (inst_bit_size > 32)
417 {
418 p = makelongparameter (allWords, inst_bit_size - start_bits - 12,
419 inst_bit_size);
420 a->constant = ((p.val & 0xffff) | (p.val >> 8 & 0xf0000));
421 }
422 else if (instruction->size == 2)
423 {
424 p = makelongparameter (allWords, inst_bit_size - 22, inst_bit_size);
425 a->constant = (p.val & 0xf) | (((p.val >>20) & 0x3) << 4)
426 | ((p.val >>14 & 0x3) << 6) | (((p.val >>7) & 0x1f) <<7);
427 }
428 else if (instruction->size == 1 && a->size == 0)
429 a->constant = 0;
430
431 break;
432
433 case arg_rbase:
434 p = makelongparameter (allWords, inst_bit_size, inst_bit_size);
435 a->constant = p.val;
436 p = makelongparameter (allWords, inst_bit_size - (start_bits + 4),
437 inst_bit_size - start_bits);
438 a->r = p.val;
439 break;
440
441 case arg_cr:
442 p = makelongparameter (allWords, start_bits + 12, start_bits + 16);
443 a->r = p.val;
444 p = makelongparameter (allWords, inst_bit_size - 16, inst_bit_size);
445 a->constant = p.val;
446 break;
447
448 case arg_crp:
449 if (instruction->size == 1)
450 p = makelongparameter (allWords, 12, 16);
451 else
452 p = makelongparameter (allWords, start_bits + 12, start_bits + 16);
453 a->rp = p.val;
454
455 if (inst_bit_size > 32)
456 {
457 p = makelongparameter (allWords, inst_bit_size - start_bits - 12,
458 inst_bit_size);
459 a->constant = ((p.val & 0xffff) | (p.val >> 8 & 0xf0000));
460 }
461 else if (instruction->size == 2)
462 {
463 p = makelongparameter (allWords, inst_bit_size - 16, inst_bit_size);
464 a->constant = p.val;
465 }
466 else if (instruction->size == 1 && a->size != 0)
467 {
468 p = makelongparameter (allWords, 4, 8);
469 if (IS_INSN_MNEMONIC ("loadw")
470 || IS_INSN_MNEMONIC ("loadd")
471 || IS_INSN_MNEMONIC ("storw")
472 || IS_INSN_MNEMONIC ("stord"))
473 a->constant = (p.val * 2);
474 else
475 a->constant = p.val;
476 }
477 else /* below case for 0x0(reg pair) */
478 a->constant = 0;
479
480 break;
481
482 case arg_c:
483
484 if ((IS_INSN_TYPE (BRANCH_INS))
485 || (IS_INSN_MNEMONIC ("bal"))
486 || (IS_INSN_TYPE (CSTBIT_INS))
487 || (IS_INSN_TYPE (LD_STOR_INS)))
488 {
489 switch (a->size)
490 {
491 case 8 :
492 p = makelongparameter (allWords, 0, start_bits);
493 a->constant = ((((p.val&0xf00)>>4)) | (p.val&0xf));
494 break;
495
496 case 24:
497 if (instruction->size == 3)
498 {
499 p = makelongparameter (allWords, 16, inst_bit_size);
500 a->constant = ((((p.val>>16)&0xf) << 20)
501 | (((p.val>>24)&0xf) << 16)
502 | (p.val & 0xffff));
503 }
504 else if (instruction->size == 2)
505 {
506 p = makelongparameter (allWords, 8, inst_bit_size);
507 a->constant = p.val;
508 }
509 break;
510
511 default:
512 p = makelongparameter (allWords, inst_bit_size - (start_bits +
513 a->size), inst_bit_size - start_bits);
514 a->constant = p.val;
515 break;
516 }
517 }
518 else
519 {
520 p = makelongparameter (allWords, inst_bit_size -
521 (start_bits + a->size),
522 inst_bit_size - start_bits);
523 a->constant = p.val;
524 }
525 break;
526
527 default:
528 break;
529 }
530}
531
532/* Print a single argument. */
533
534static void
535print_arg (argument *a, bfd_vma memaddr, struct disassemble_info *info)
536{
537 LONGLONG longdisp, mask;
538 int sign_flag = 0;
539 int relative = 0;
540 bfd_vma number;
541 PTR stream = info->stream;
542 fprintf_ftype func = info->fprintf_func;
543
544 switch (a->type)
545 {
546 case arg_r:
547 func (stream, "%s", getregname (a->r));
548 break;
549
550 case arg_rp:
551 func (stream, "%s", getregpname (a->rp));
552 break;
553
554 case arg_pr:
555 func (stream, "%s", getprocregname (a->pr));
556 break;
557
558 case arg_prp:
559 func (stream, "%s", getprocpregname (a->prp));
560 break;
561
562 case arg_cc:
563 func (stream, "%s", getccstring (a->cc));
564 func (stream, "%s", "\t");
565 break;
566
567 case arg_ic:
568 if (IS_INSN_MNEMONIC ("excp"))
569 {
570 func (stream, "%s", gettrapstring (a->constant));
571 break;
572 }
573 else if ((IS_INSN_TYPE (ARITH_INS) || IS_INSN_TYPE (ARITH_BYTE_INS))
574 && ((instruction->size == 1) && (a->constant == 9)))
575 func (stream, "$%d", -1);
576 else if (INST_HAS_REG_LIST)
577 func (stream, "$0x%lx", a->constant +1);
578 else if (IS_INSN_TYPE (SHIFT_INS))
579 {
580 longdisp = a->constant;
581 mask = ((LONGLONG)1 << a->size) - 1;
582 if (longdisp & ((LONGLONG)1 << (a->size -1)))
583 {
584 sign_flag = 1;
585 longdisp = ~(longdisp) + 1;
586 }
587 a->constant = (unsigned long int) (longdisp & mask);
588 func (stream, "$%d", ((int)(sign_flag ? -a->constant :
589 a->constant)));
590 }
591 else
592 func (stream, "$0x%lx", a->constant);
593 switch (a->size)
594 {
595 case 4 : case 5 : case 6 : case 8 :
596 func (stream, "%s", ":s"); break;
597 case 16 : case 20 : func (stream, "%s", ":m"); break;
598 case 24 : case 32 : func (stream, "%s", ":l"); break;
599 default: break;
600 }
601 break;
602
603 case arg_idxr:
604 if (a->i_r == 0) func (stream, "[r12]");
605 if (a->i_r == 1) func (stream, "[r13]");
606 func (stream, "0x%lx", a->constant);
607 func (stream, "%s", print_exp_len (instruction->size * 16));
608 break;
609
610 case arg_idxrp:
611 if (a->i_r == 0) func (stream, "[r12]");
612 if (a->i_r == 1) func (stream, "[r13]");
613 func (stream, "0x%lx", a->constant);
614 func (stream, "%s", print_exp_len (instruction->size * 16));
615 func (stream, "%s", getidxregpname (a->rp));
616 break;
617
618 case arg_rbase:
619 func (stream, "(%s)", getregname (a->r));
620 break;
621
622 case arg_cr:
623 func (stream, "0x%lx", a->constant);
624 func (stream, "%s", print_exp_len (instruction->size * 16));
625 func (stream, "(%s)", getregname (a->r));
626 break;
627
628 case arg_crp:
629 func (stream, "0x%lx", a->constant);
630 func (stream, "%s", print_exp_len (instruction->size * 16));
631 func (stream, "%s", getregpname (a->rp));
632 break;
633
634 case arg_c:
635 /*Removed the *2 part as because implicit zeros are no more required.
636 Have to fix this as this needs a bit of extension in terms of branch
637 instructions. */
638 if (IS_INSN_TYPE (BRANCH_INS) || IS_INSN_MNEMONIC ("bal"))
639 {
640 relative = 1;
641 longdisp = a->constant;
642 /* REVISIT: To sync with WinIDEA and CR16 4.1tools, the below
643 line commented */
644 /* longdisp <<= 1; */
645 mask = ((LONGLONG)1 << a->size) - 1;
646 switch (a->size)
647 {
648 case 8 :
649 {
650 longdisp <<= 1;
651 if (longdisp & ((LONGLONG)1 << a->size))
652 {
653 sign_flag = 1;
654 longdisp = ~(longdisp) + 1;
655 }
656 break;
657 }
658 case 16 :
659 case 24 :
660 {
661 if (longdisp & 1)
662 {
663 sign_flag = 1;
664 longdisp = ~(longdisp) + 1;
665 }
666 break;
667 }
668 default:
669 func (stream, "Wrong offset used in branch/bal instruction");
670 break;
671 }
672 a->constant = (unsigned long int) (longdisp & mask);
673 }
674 /* For branch Neq instruction it is 2*offset + 2. */
675 else if (IS_INSN_TYPE (BRANCH_NEQ_INS))
676 a->constant = 2 * a->constant + 2;
677
678 if ((!IS_INSN_TYPE (CSTBIT_INS)) && (!IS_INSN_TYPE (LD_STOR_INS)))
679 (sign_flag) ? func (stream, "%s", "*-"): func (stream, "%s","*+");
680
522fe561 681 /* PR 10173: Avoid printing the 0x prefix twice. */
e20cc039 682 if (info->symtab_size > 0)
522fe561 683 func (stream, "%s", "0x");
3d3d428f
NC
684 number = ((relative ? memaddr : 0) +
685 (sign_flag ? ((- a->constant) & 0xffffffe) : a->constant));
686
687 (*info->print_address_func) ((number & ((1 << 24) - 1)), info);
688
689 func (stream, "%s", print_exp_len (instruction->size * 16));
690 break;
691
692 default:
693 break;
694 }
695}
696
697/* Print all the arguments of CURRINSN instruction. */
698
699static void
91d6fa6a 700print_arguments (ins *currentInsn, bfd_vma memaddr, struct disassemble_info *info)
3d3d428f
NC
701{
702 int i;
703
704 /* For "pop/push/popret RA instruction only. */
705 if ((IS_INSN_MNEMONIC ("pop")
706 || (IS_INSN_MNEMONIC ("popret")
707 || (IS_INSN_MNEMONIC ("push"))))
91d6fa6a 708 && currentInsn->nargs == 1)
3d3d428f
NC
709 {
710 info->fprintf_func (info->stream, "RA");
711 return;
712 }
713
91d6fa6a 714 for (i = 0; i < currentInsn->nargs; i++)
3d3d428f
NC
715 {
716 processing_argument_number = i;
717
718 /* For "bal (ra), disp17" instruction only. */
719 if ((IS_INSN_MNEMONIC ("bal")) && (i == 0) && instruction->size == 2)
720 {
721 info->fprintf_func (info->stream, "(ra),");
722 continue;
723 }
724
725 if ((INST_HAS_REG_LIST) && (i == 2))
726 info->fprintf_func (info->stream, "RA");
727 else
91d6fa6a 728 print_arg (&currentInsn->arg[i], memaddr, info);
3d3d428f 729
91d6fa6a 730 if ((i != currentInsn->nargs - 1) && (!IS_INSN_MNEMONIC ("b")))
3d3d428f
NC
731 info->fprintf_func (info->stream, ",");
732 }
733}
734
735/* Build the instruction's arguments. */
736
737static void
738make_instruction (void)
739{
740 int i;
741 unsigned int shift;
742
743 for (i = 0; i < currInsn.nargs; i++)
744 {
745 argument a;
746
747 memset (&a, 0, sizeof (a));
748 a.type = getargtype (instruction->operands[i].op_type);
749 a.size = getbits (instruction->operands[i].op_type);
750 shift = instruction->operands[i].shift;
751
752 make_argument (&a, shift);
753 currInsn.arg[i] = a;
754 }
755
756 /* Calculate instruction size (in bytes). */
757 currInsn.size = instruction->size + (size_changed ? 1 : 0);
758 /* Now in bits. */
759 currInsn.size *= 2;
760}
761
762/* Retrieve a single word from a given memory address. */
763
764static wordU
765get_word_at_PC (bfd_vma memaddr, struct disassemble_info *info)
766{
767 bfd_byte buffer[4];
768 int status;
769 wordU insn = 0;
770
771 status = info->read_memory_func (memaddr, buffer, 2, info);
772
773 if (status == 0)
774 insn = (wordU) bfd_getl16 (buffer);
775
776 return insn;
777}
778
779/* Retrieve multiple words (3) from a given memory address. */
780
781static void
782get_words_at_PC (bfd_vma memaddr, struct disassemble_info *info)
783{
784 int i;
785 bfd_vma mem;
786
787 for (i = 0, mem = memaddr; i < 3; i++, mem += 2)
788 words[i] = get_word_at_PC (mem, info);
789
790 allWords =
791 ((ULONGLONG) words[0] << 32) + ((unsigned long) words[1] << 16) + words[2];
792}
793
794/* Prints the instruction by calling print_arguments after proper matching. */
795
796int
797print_insn_cr16 (bfd_vma memaddr, struct disassemble_info *info)
798{
799 int is_decoded; /* Nonzero means instruction has a match. */
800
801 /* Initialize global variables. */
802 imm4flag = 0;
803 size_changed = 0;
804
805 /* Retrieve the encoding from current memory location. */
806 get_words_at_PC (memaddr, info);
807 /* Find a matching opcode in table. */
808 is_decoded = match_opcode ();
809 /* If found, print the instruction's mnemonic and arguments. */
810 if (is_decoded > 0 && (words[0] << 16 || words[1]) != 0)
811 {
812 if (strneq (instruction->mnemonic, "cinv", 4))
ddb341a7 813 info->fprintf_func (info->stream,"%s", getcinvstring (instruction->mnemonic));
3d3d428f
NC
814 else
815 info->fprintf_func (info->stream, "%s", instruction->mnemonic);
816
817 if (((currInsn.nargs = get_number_of_operands ()) != 0)
818 && ! (IS_INSN_MNEMONIC ("b")))
819 info->fprintf_func (info->stream, "\t");
820 make_instruction ();
821 /* For push/pop/pushrtn with RA instructions. */
822 if ((INST_HAS_REG_LIST) && ((words[0] >> 7) & 0x1))
823 currInsn.nargs +=1;
824 print_arguments (&currInsn, memaddr, info);
825 return currInsn.size;
826 }
827
828 /* No match found. */
829 info->fprintf_func (info->stream,"%s ",ILLEGAL);
830 return 2;
831}