xref: /netbsd-src/external/gpl3/binutils.old/dist/opcodes/cr16-dis.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
1 /* Disassembler code for CR16.
2    Copyright (C) 2007-2022 Free Software Foundation, Inc.
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 
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)
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 
21 #include "sysdep.h"
22 #include "disassemble.h"
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   (((a) >> (offs)) & ((1ul << ((n_bits) - 1) << 1) - 1))
34 
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)))
38 
39 /* Structure to map valid 'cinv' instruction options.  */
40 
41 typedef struct
42   {
43     /* Cinv printed string.  */
44     char *istr;
45     /* Value corresponding to the string.  */
46     char *ostr;
47   }
48 cinv_entry;
49 
50 /* CR16 'cinv' options mapping.  */
51 static const cinv_entry cr16_cinvs[] =
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.  */
62 static int NUMCINVS = ARRAY_SIZE (cr16_cinvs);
63 
64 /* Enum to distinguish different registers argument types.  */
65 typedef enum REG_ARG_TYPE
66   {
67     /* General purpose register (r<N>).  */
68     REG_ARG = 0,
69     /*Processor register   */
70     P_ARG,
71   }
72 REG_ARG_TYPE;
73 
74 /* Current opcode table entry we're disassembling.  */
75 static const inst *instruction;
76 /* Current instruction we're disassembling.  */
77 static ins cr16_currInsn;
78 /* The current instruction is read into 3 consecutive words.  */
79 static wordU cr16_words[3];
80 /* Contains all words in appropriate order.  */
81 static ULONGLONG cr16_allWords;
82 /* Holds the current processed argument number.  */
83 static int processing_argument_number;
84 /* Nonzero means a IMM4 instruction.  */
85 static int imm4flag;
86 /* Nonzero means the instruction's original size is
87    incremented (escape sequence is used).  */
88 static int size_changed;
89 
90 
91 /* Print the constant expression length.  */
92 
93 static char *
print_exp_len(int size)94 print_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 
119 static int
get_number_of_operands(void)120 get_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 
132 static int
getbits(operand_type op)133 getbits (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 
143 static argtype
getargtype(operand_type op)144 getargtype (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 
155 static char *
getccstring(unsigned cc_insn)156 getccstring (unsigned cc_insn)
157 {
158   return (char *) cr16_b_cond_tab[cc_insn];
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 
165 static char *
getcinvstring(const char * str)166 getcinvstring (const char *str)
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 
180 static char *
gettrapstring(unsigned int trap_index)181 gettrapstring (unsigned int trap_index)
182 {
183   const trap_entry *trap;
184 
185   for (trap = cr16_traps; trap < cr16_traps + NUMTRAPS; trap++)
186     if (trap->entry == trap_index)
187       return trap->name;
188 
189   return ILLEGAL;
190 }
191 
192 /* Given a register enum value, retrieve its name.  */
193 
194 static char *
getregname(reg r)195 getregname (reg r)
196 {
197   const reg_entry * regentry = cr16_regtab + r;
198 
199   if (regentry->type != CR16_R_REGTYPE)
200     return ILLEGAL;
201 
202   return regentry->name;
203 }
204 
205 /* Given a register pair enum value, retrieve its name.  */
206 
207 static char *
getregpname(reg r)208 getregpname (reg r)
209 {
210   const reg_entry * regentry = cr16_regptab + r;
211 
212   if (regentry->type != CR16_RP_REGTYPE)
213     return ILLEGAL;
214 
215   return regentry->name;
216 }
217 
218 /* Given a index register pair enum value, retrieve its name.  */
219 
220 static char *
getidxregpname(reg r)221 getidxregpname (reg r)
222 {
223   const reg_entry * regentry;
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 
239   regentry = cr16_regptab + r;
240 
241   if (regentry->type != CR16_RP_REGTYPE)
242     return ILLEGAL;
243 
244   return regentry->name;
245 }
246 
247 /* Getting a processor register name.  */
248 
249 static char *
getprocregname(int reg_index)250 getprocregname (int reg_index)
251 {
252   const reg_entry *r;
253 
254   for (r = cr16_pregtab; r < cr16_pregtab + NUMPREGS; r++)
255     if (r->image == reg_index)
256       return r->name;
257 
258   return "ILLEGAL REGISTER";
259 }
260 
261 /* Getting a processor register name - 32 bit size.  */
262 
263 static char *
getprocpregname(int reg_index)264 getprocpregname (int reg_index)
265 {
266   const reg_entry *r;
267 
268   for (r = cr16_pregptab; r < cr16_pregptab + NUMPREGPS; r++)
269     if (r->image == reg_index)
270       return r->name;
271 
272   return "ILLEGAL REGISTER";
273 }
274 
275 /* START and END are relating 'cr16_allWords' struct, which is 48 bits size.
276 
277                           START|--------|END
278              +---------+---------+---------+---------+
279              |         |   V    |     A    |   L     |
280              +---------+---------+---------+---------+
281                        0         16        32        48
282     words                  [0]       [1]       [2]      */
283 
284 static inline dwordU
makelongparameter(ULONGLONG val,int start,int end)285 makelongparameter (ULONGLONG val, int start, int end)
286 {
287   return EXTRACT (val, 48 - end, end - start);
288 }
289 
290 /* Build a mask of the instruction's 'constant' opcode,
291    based on the instruction's printing flags.  */
292 
293 static unsigned long
build_mask(void)294 build_mask (void)
295 {
296   unsigned long mask = SBM (instruction->match_bits);
297 
298   /* Adjust mask for bcond with 32-bit size instruction.  */
299   if ((IS_INSN_MNEMONIC("b") && instruction->size == 2))
300     mask = 0xff0f0000;
301 
302   return mask;
303 }
304 
305 /* Search for a matching opcode. Return 1 for success, 0 for failure.  */
306 
307 int
cr16_match_opcode(void)308 cr16_match_opcode (void)
309 {
310   unsigned long mask;
311   /* The instruction 'constant' opcode doesn't exceed 32 bits.  */
312   unsigned long doubleWord = cr16_words[1] + ((unsigned) cr16_words[0] << 16);
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 ();
321 
322       if ((doubleWord & mask) == BIN (instruction->match,
323 				      instruction->match_bits))
324 	return 1;
325       else
326 	instruction--;
327     }
328   return 0;
329 }
330 
331 /* Set the proper parameter value for different type of arguments.  */
332 
333 static void
make_argument(argument * a,int start_bits)334 make_argument (argument * a, int start_bits)
335 {
336   int inst_bit_size;
337   dwordU p;
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:
347       p = makelongparameter (cr16_allWords,
348 			     inst_bit_size - (start_bits + a->size),
349 			     inst_bit_size - start_bits);
350       a->r = p;
351       break;
352 
353     case arg_rp:
354       p = makelongparameter (cr16_allWords,
355 			     inst_bit_size - (start_bits + a->size),
356 			     inst_bit_size - start_bits);
357       a->rp = p;
358       break;
359 
360     case arg_pr:
361       p = makelongparameter (cr16_allWords,
362 			     inst_bit_size - (start_bits + a->size),
363 			     inst_bit_size - start_bits);
364       a->pr = p;
365       break;
366 
367     case arg_prp:
368       p = makelongparameter (cr16_allWords,
369 			     inst_bit_size - (start_bits + a->size),
370 			     inst_bit_size - start_bits);
371       a->prp = p;
372       break;
373 
374     case arg_ic:
375       p = makelongparameter (cr16_allWords,
376 			     inst_bit_size - (start_bits + a->size),
377 			     inst_bit_size - start_bits);
378       a->constant = p;
379       break;
380 
381     case arg_cc:
382       p = makelongparameter (cr16_allWords,
383 			     inst_bit_size - (start_bits + a->size),
384 			     inst_bit_size - start_bits);
385       a->cc = p;
386       break;
387 
388     case arg_idxr:
389       if (IS_INSN_TYPE (CSTBIT_INS) && instruction->mnemonic[4] == 'b')
390 	p = makelongparameter (cr16_allWords, 8, 9);
391       else
392 	p = makelongparameter (cr16_allWords, 9, 10);
393       a->i_r = p;
394       p = makelongparameter (cr16_allWords,
395 			     inst_bit_size - a->size, inst_bit_size);
396       a->constant = p;
397       break;
398 
399     case arg_idxrp:
400       p = makelongparameter (cr16_allWords, start_bits + 12, start_bits + 13);
401       a->i_r = p;
402       p = makelongparameter (cr16_allWords, start_bits + 13, start_bits + 16);
403       a->rp = p;
404       if (inst_bit_size > 32)
405 	{
406 	  p = makelongparameter (cr16_allWords, inst_bit_size - start_bits - 12,
407 				 inst_bit_size);
408 	  a->constant = (p & 0xffff) | (p >> 8 & 0xf0000);
409 	}
410       else if (instruction->size == 2)
411 	{
412 	  p = makelongparameter (cr16_allWords, inst_bit_size - 22,
413 				 inst_bit_size);
414 	  a->constant = ((p & 0xf) | (((p >> 20) & 0x3) << 4)
415 			 | ((p >> 14 & 0x3) << 6) | (((p >>7) & 0x1f) << 7));
416 	}
417       else if (instruction->size == 1 && a->size == 0)
418 	a->constant = 0;
419 
420       break;
421 
422     case arg_rbase:
423       p = makelongparameter (cr16_allWords, inst_bit_size, inst_bit_size);
424       a->constant = p;
425       p = makelongparameter (cr16_allWords, inst_bit_size - (start_bits + 4),
426 			     inst_bit_size - start_bits);
427       a->r = p;
428       break;
429 
430     case arg_cr:
431       p = makelongparameter (cr16_allWords, start_bits + 12, start_bits + 16);
432       a->r = p;
433       p = makelongparameter (cr16_allWords, inst_bit_size - 28, inst_bit_size);
434       a->constant = ((p >> 8) & 0xf0000) | (p & 0xffff);
435       break;
436 
437     case arg_crp:
438       if (instruction->size == 1)
439 	p = makelongparameter (cr16_allWords, 12, 16);
440       else
441 	p = makelongparameter (cr16_allWords, start_bits + 12, start_bits + 16);
442       a->rp = p;
443 
444       if (inst_bit_size > 32)
445 	{
446 	  p = makelongparameter (cr16_allWords, inst_bit_size - start_bits - 12,
447 				 inst_bit_size);
448 	  a->constant = ((p & 0xffff) | (p >> 8 & 0xf0000));
449 	}
450       else if (instruction->size == 2)
451 	{
452 	  p = makelongparameter (cr16_allWords, inst_bit_size - 16,
453 				 inst_bit_size);
454 	  a->constant = p;
455 	}
456       else if (instruction->size == 1 && a->size != 0)
457 	{
458 	  p = makelongparameter (cr16_allWords, 4, 8);
459 	  if (IS_INSN_MNEMONIC ("loadw")
460 	      || IS_INSN_MNEMONIC ("loadd")
461 	      || IS_INSN_MNEMONIC ("storw")
462 	      || IS_INSN_MNEMONIC ("stord"))
463 	    a->constant = p * 2;
464 	  else
465 	    a->constant = p;
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 :
482 	      p = makelongparameter (cr16_allWords, 0, start_bits);
483 	      a->constant = ((p & 0xf00) >> 4) | (p & 0xf);
484 	      break;
485 
486 	    case 24:
487 	      if (instruction->size == 3)
488 		{
489 		  p = makelongparameter (cr16_allWords, 16, inst_bit_size);
490 		  a->constant = ((((p >> 16) & 0xf) << 20)
491 				 | (((p >> 24) & 0xf) << 16)
492 				 | (p & 0xffff));
493 		}
494 	      else if (instruction->size == 2)
495 		{
496 		  p = makelongparameter (cr16_allWords, 8, inst_bit_size);
497 		  a->constant = p;
498 		}
499 	      break;
500 
501 	    default:
502 	      p = makelongparameter (cr16_allWords,
503 				     inst_bit_size - (start_bits + a->size),
504 				     inst_bit_size - start_bits);
505 	      a->constant = p;
506 	      break;
507 	    }
508 	}
509       else
510 	{
511 	  p = makelongparameter (cr16_allWords,
512 				 inst_bit_size - (start_bits + a->size),
513 				 inst_bit_size - start_bits);
514 	  a->constant = p;
515 	}
516       break;
517 
518     default:
519       break;
520     }
521 }
522 
523 /*  Print a single argument.  */
524 
525 static void
print_arg(argument * a,bfd_vma memaddr,struct disassemble_info * info)526 print_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   void *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 
672       /* PR 10173: Avoid printing the 0x prefix twice.  */
673       if (info->symtab_size > 0)
674 	func (stream, "%s", "0x");
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 
690 static void
print_arguments(ins * currentInsn,bfd_vma memaddr,struct disassemble_info * info)691 print_arguments (ins *currentInsn, bfd_vma memaddr, struct disassemble_info *info)
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"))))
699       && currentInsn->nargs == 1)
700     {
701       info->fprintf_func (info->stream, "RA");
702       return;
703     }
704 
705   for (i = 0; i < currentInsn->nargs; i++)
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)
711 	{
712 	  info->fprintf_func (info->stream, "(ra),");
713 	  continue;
714 	}
715 
716       if ((INST_HAS_REG_LIST) && (i == 2))
717 	info->fprintf_func (info->stream, "RA");
718       else
719 	print_arg (&currentInsn->arg[i], memaddr, info);
720 
721       if ((i != currentInsn->nargs - 1) && (!IS_INSN_MNEMONIC ("b")))
722 	info->fprintf_func (info->stream, ",");
723     }
724 }
725 
726 /* Build the instruction's arguments.  */
727 
728 void
cr16_make_instruction(void)729 cr16_make_instruction (void)
730 {
731   int i;
732   unsigned int shift;
733 
734   for (i = 0; i < cr16_currInsn.nargs; i++)
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);
744       cr16_currInsn.arg[i] = a;
745     }
746 
747   /* Calculate instruction size (in bytes).  */
748   cr16_currInsn.size = instruction->size + (size_changed ? 1 : 0);
749   /* Now in bits.  */
750   cr16_currInsn.size *= 2;
751 }
752 
753 /* Retrieve a single word from a given memory address.  */
754 
755 static wordU
get_word_at_PC(bfd_vma memaddr,struct disassemble_info * info)756 get_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 
772 static void
get_words_at_PC(bfd_vma memaddr,struct disassemble_info * info)773 get_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)
779     cr16_words[i] = get_word_at_PC (mem, info);
780 
781   cr16_allWords =  ((ULONGLONG) cr16_words[0] << 32)
782 		   + ((unsigned long) cr16_words[1] << 16) + cr16_words[2];
783 }
784 
785 /* Prints the instruction by calling print_arguments after proper matching.  */
786 
787 int
print_insn_cr16(bfd_vma memaddr,struct disassemble_info * info)788 print_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.  */
799   is_decoded = cr16_match_opcode ();
800   /* If found, print the instruction's mnemonic and arguments.  */
801   if (is_decoded > 0 && (cr16_words[0] != 0 || cr16_words[1] != 0))
802     {
803       if (startswith (instruction->mnemonic, "cinv"))
804 	info->fprintf_func (info->stream,"%s",
805 			    getcinvstring (instruction->mnemonic));
806       else
807 	info->fprintf_func (info->stream, "%s", instruction->mnemonic);
808 
809       if (((cr16_currInsn.nargs = get_number_of_operands ()) != 0)
810 	  && ! (IS_INSN_MNEMONIC ("b")))
811 	info->fprintf_func (info->stream, "\t");
812       cr16_make_instruction ();
813       /* For push/pop/pushrtn with RA instructions.  */
814       if ((INST_HAS_REG_LIST) && ((cr16_words[0] >> 7) & 0x1))
815 	cr16_currInsn.nargs +=1;
816       print_arguments (&cr16_currInsn, memaddr, info);
817       return cr16_currInsn.size;
818     }
819 
820   /* No match found.  */
821   info->fprintf_func (info->stream,"%s ",ILLEGAL);
822   return 2;
823 }
824