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