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