1214571Sdim/* Disassembler code for CR16.
2214571Sdim   Copyright 2007 Free Software Foundation, Inc.
3214571Sdim   Contributed by M R Swami Reddy (MR.Swami.Reddy@nsc.com).
4214571Sdim
5214571Sdim   This file is part of GAS, GDB and the GNU binutils.
6214571Sdim
7214571Sdim   This program is free software; you can redistribute it and/or modify it under
8214571Sdim   the terms of the GNU General Public License as published by the Free
9214571Sdim   Software Foundation; either version 2, or (at your option)
10214571Sdim   any later version.
11214571Sdim
12214571Sdim   This program is distributed in the hope that it will be useful, but WITHOUT
13214571Sdim   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14214571Sdim   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15214571Sdim   more details.
16214571Sdim
17214571Sdim   You should have received a copy of the GNU General Public License
18214571Sdim   along with this program; if not, write to the Free Software Foundation,
19214571Sdim   Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
20214571Sdim
21214571Sdim#include "dis-asm.h"
22214571Sdim#include "sysdep.h"
23214571Sdim#include "opcode/cr16.h"
24214571Sdim#include "libiberty.h"
25214571Sdim
26214571Sdim/* String to print when opcode was not matched.  */
27214571Sdim#define ILLEGAL  "illegal"
28214571Sdim  /* Escape to 16-bit immediate.  */
29214571Sdim#define ESCAPE_16_BIT  0xB
30214571Sdim
31214571Sdim/* Extract 'n_bits' from 'a' starting from offset 'offs'.  */
32214571Sdim#define EXTRACT(a, offs, n_bits)                    \
33214571Sdim  (n_bits == 32 ? (((a) >> (offs)) & 0xffffffffL)   \
34214571Sdim  : (((a) >> (offs)) & ((1 << (n_bits)) -1)))
35214571Sdim
36214571Sdim/* Set Bit Mask - a mask to set all bits starting from offset 'offs'.  */
37214571Sdim#define SBM(offs)  ((((1 << (32 - offs)) -1) << (offs)))
38214571Sdim
39214571Sdimtypedef unsigned long dwordU;
40214571Sdimtypedef unsigned short wordU;
41214571Sdim
42214571Sdimtypedef struct
43214571Sdim{
44214571Sdim  dwordU val;
45214571Sdim  int nbits;
46214571Sdim} parameter;
47214571Sdim
48214571Sdim/* Structure to map valid 'cinv' instruction options.  */
49214571Sdim
50214571Sdimtypedef struct
51214571Sdim  {
52214571Sdim    /* Cinv printed string.  */
53214571Sdim    char *istr;
54214571Sdim    /* Value corresponding to the string.  */
55214571Sdim    char *ostr;
56214571Sdim  }
57214571Sdimcinv_entry;
58214571Sdim
59214571Sdim/* CR16 'cinv' options mapping.  */
60214571Sdimconst cinv_entry cr16_cinvs[] =
61214571Sdim{
62214571Sdim  {"cinv[i]",     "cinv    [i]"},
63214571Sdim  {"cinv[i,u]",   "cinv    [i,u]"},
64214571Sdim  {"cinv[d]",     "cinv    [d]"},
65214571Sdim  {"cinv[d,u]",   "cinv    [d,u]"},
66214571Sdim  {"cinv[d,i]",   "cinv    [d,i]"},
67214571Sdim  {"cinv[d,i,u]", "cinv    [d,i,u]"}
68214571Sdim};
69214571Sdim
70214571Sdim/* Number of valid 'cinv' instruction options.  */
71214571Sdimstatic int NUMCINVS = ARRAY_SIZE (cr16_cinvs);
72214571Sdim
73214571Sdim/* Enum to distinguish different registers argument types.  */
74214571Sdimtypedef enum REG_ARG_TYPE
75214571Sdim  {
76214571Sdim    /* General purpose register (r<N>).  */
77214571Sdim    REG_ARG = 0,
78214571Sdim    /*Processor register   */
79214571Sdim    P_ARG,
80214571Sdim  }
81214571SdimREG_ARG_TYPE;
82214571Sdim
83214571Sdim/* Current opcode table entry we're disassembling.  */
84214571Sdimconst inst *instruction;
85214571Sdim/* Current instruction we're disassembling.  */
86214571Sdimins currInsn;
87214571Sdim/* The current instruction is read into 3 consecutive words.  */
88214571SdimwordU words[3];
89214571Sdim/* Contains all words in appropriate order.  */
90214571SdimULONGLONG allWords;
91214571Sdim/* Holds the current processed argument number.  */
92214571Sdimint processing_argument_number;
93214571Sdim/* Nonzero means a IMM4 instruction.  */
94214571Sdimint imm4flag;
95214571Sdim/* Nonzero means the instruction's original size is
96214571Sdim   incremented (escape sequence is used).  */
97214571Sdimint size_changed;
98214571Sdim
99214571Sdim
100214571Sdim/* Print the constant expression length.  */
101214571Sdim
102214571Sdimstatic char *
103214571Sdimprint_exp_len (int size)
104214571Sdim{
105214571Sdim  switch (size)
106214571Sdim    {
107214571Sdim    case 4:
108214571Sdim    case 5:
109214571Sdim    case 6:
110214571Sdim    case 8:
111214571Sdim    case 14:
112214571Sdim    case 16:
113214571Sdim      return ":s";
114214571Sdim    case 20:
115214571Sdim    case 24:
116214571Sdim    case 32:
117214571Sdim      return ":m";
118214571Sdim    case 48:
119214571Sdim      return ":l";
120214571Sdim    default:
121214571Sdim      return "";
122214571Sdim    }
123214571Sdim}
124214571Sdim
125214571Sdim
126214571Sdim/* Retrieve the number of operands for the current assembled instruction.  */
127214571Sdim
128214571Sdimstatic int
129214571Sdimget_number_of_operands (void)
130214571Sdim{
131214571Sdim  int i;
132214571Sdim
133214571Sdim  for (i = 0; instruction->operands[i].op_type && i < MAX_OPERANDS; i++)
134214571Sdim    ;
135214571Sdim
136214571Sdim  return i;
137214571Sdim}
138214571Sdim
139214571Sdim/* Return the bit size for a given operand.  */
140214571Sdim
141214571Sdimstatic int
142214571Sdimgetbits (operand_type op)
143214571Sdim{
144214571Sdim  if (op < MAX_OPRD)
145214571Sdim    return cr16_optab[op].bit_size;
146214571Sdim
147214571Sdim  return 0;
148214571Sdim}
149214571Sdim
150214571Sdim/* Return the argument type of a given operand.  */
151214571Sdim
152214571Sdimstatic argtype
153214571Sdimgetargtype (operand_type op)
154214571Sdim{
155214571Sdim  if (op < MAX_OPRD)
156214571Sdim    return cr16_optab[op].arg_type;
157214571Sdim
158214571Sdim  return nullargs;
159214571Sdim}
160214571Sdim
161214571Sdim/* Given a 'CC' instruction constant operand, return its corresponding
162214571Sdim   string. This routine is used when disassembling the 'CC' instruction.  */
163214571Sdim
164214571Sdimstatic char *
165214571Sdimgetccstring (unsigned cc)
166214571Sdim{
167214571Sdim  return (char *) cr16_b_cond_tab[cc];
168214571Sdim}
169214571Sdim
170214571Sdim
171214571Sdim/* Given a 'cinv' instruction constant operand, return its corresponding
172214571Sdim   string. This routine is used when disassembling the 'cinv' instruction. */
173214571Sdim
174214571Sdimstatic char *
175214571Sdimgetcinvstring (char *str)
176214571Sdim{
177214571Sdim  const cinv_entry *cinv;
178214571Sdim
179214571Sdim  for (cinv = cr16_cinvs; cinv < (cr16_cinvs + NUMCINVS); cinv++)
180214571Sdim    if (strcmp (cinv->istr, str) == 0)
181214571Sdim      return cinv->ostr;
182214571Sdim
183214571Sdim  return ILLEGAL;
184214571Sdim}
185214571Sdim
186214571Sdim/* Given the trap index in dispatch table, return its name.
187214571Sdim   This routine is used when disassembling the 'excp' instruction.  */
188214571Sdim
189214571Sdimstatic char *
190214571Sdimgettrapstring (unsigned int index)
191214571Sdim{
192214571Sdim  const trap_entry *trap;
193214571Sdim
194214571Sdim  for (trap = cr16_traps; trap < cr16_traps + NUMTRAPS; trap++)
195214571Sdim    if (trap->entry == index)
196214571Sdim      return trap->name;
197214571Sdim
198214571Sdim  return ILLEGAL;
199214571Sdim}
200214571Sdim
201214571Sdim/* Given a register enum value, retrieve its name.  */
202214571Sdim
203214571Sdimstatic char *
204214571Sdimgetregname (reg r)
205214571Sdim{
206214571Sdim  const reg_entry *reg = cr16_regtab + r;
207214571Sdim
208214571Sdim  if (reg->type != CR16_R_REGTYPE)
209214571Sdim    return ILLEGAL;
210214571Sdim
211214571Sdim  return reg->name;
212214571Sdim}
213214571Sdim
214214571Sdim/* Given a register pair enum value, retrieve its name.  */
215214571Sdim
216214571Sdimstatic char *
217214571Sdimgetregpname (reg r)
218214571Sdim{
219214571Sdim  const reg_entry *reg = cr16_regptab + r;
220214571Sdim
221214571Sdim  if (reg->type != CR16_RP_REGTYPE)
222214571Sdim    return ILLEGAL;
223214571Sdim
224214571Sdim  return reg->name;
225214571Sdim}
226214571Sdim
227214571Sdim/* Given a index register pair enum value, retrieve its name.  */
228214571Sdim
229214571Sdimstatic char *
230214571Sdimgetidxregpname (reg r)
231214571Sdim{
232214571Sdim  const reg_entry *reg;
233214571Sdim
234214571Sdim  switch (r)
235214571Sdim   {
236214571Sdim   case 0: r = 0; break;
237214571Sdim   case 1: r = 2; break;
238214571Sdim   case 2: r = 4; break;
239214571Sdim   case 3: r = 6; break;
240214571Sdim   case 4: r = 8; break;
241214571Sdim   case 5: r = 10; break;
242214571Sdim   case 6: r = 3; break;
243214571Sdim   case 7: r = 5; break;
244214571Sdim   default:
245214571Sdim     break;
246214571Sdim   }
247214571Sdim
248214571Sdim  reg = cr16_regptab + r;
249214571Sdim
250214571Sdim  if (reg->type != CR16_RP_REGTYPE)
251214571Sdim    return ILLEGAL;
252214571Sdim
253214571Sdim  return reg->name;
254214571Sdim}
255214571Sdim
256214571Sdim/* Getting a processor register name.  */
257214571Sdim
258214571Sdimstatic char *
259214571Sdimgetprocregname (int index)
260214571Sdim{
261214571Sdim  const reg_entry *r;
262214571Sdim
263214571Sdim  for (r = cr16_pregtab; r < cr16_pregtab + NUMPREGS; r++)
264214571Sdim    if (r->image == index)
265214571Sdim      return r->name;
266214571Sdim
267214571Sdim  return "ILLEGAL REGISTER";
268214571Sdim}
269214571Sdim
270214571Sdim/* Getting a processor register name - 32 bit size.  */
271214571Sdim
272214571Sdimstatic char *
273214571Sdimgetprocpregname (int index)
274214571Sdim{
275214571Sdim  const reg_entry *r;
276214571Sdim
277214571Sdim  for (r = cr16_pregptab; r < cr16_pregptab + NUMPREGPS; r++)
278214571Sdim    if (r->image == index)
279214571Sdim      return r->name;
280214571Sdim
281214571Sdim  return "ILLEGAL REGISTER";
282214571Sdim}
283214571Sdim
284214571Sdim/* START and END are relating 'allWords' struct, which is 48 bits size.
285214571Sdim
286214571Sdim                          START|--------|END
287214571Sdim             +---------+---------+---------+---------+
288214571Sdim             |         |   V    |     A    |   L     |
289214571Sdim             +---------+---------+---------+---------+
290214571Sdim                       0         16        32        48
291214571Sdim    words                  [0]       [1]       [2]      */
292214571Sdim
293214571Sdimstatic parameter
294214571Sdimmakelongparameter (ULONGLONG val, int start, int end)
295214571Sdim{
296214571Sdim  parameter p;
297214571Sdim
298214571Sdim  p.val = (dwordU) EXTRACT (val, 48 - end, end - start);
299214571Sdim  p.nbits = end - start;
300214571Sdim  return p;
301214571Sdim}
302214571Sdim
303214571Sdim/* Build a mask of the instruction's 'constant' opcode,
304214571Sdim   based on the instruction's printing flags.  */
305214571Sdim
306214571Sdimstatic unsigned long
307214571Sdimbuild_mask (void)
308214571Sdim{
309214571Sdim  unsigned long mask = SBM (instruction->match_bits);
310214571Sdim  return mask;
311214571Sdim}
312214571Sdim
313214571Sdim/* Search for a matching opcode. Return 1 for success, 0 for failure.  */
314214571Sdim
315214571Sdimstatic int
316214571Sdimmatch_opcode (void)
317214571Sdim{
318214571Sdim  unsigned long mask;
319214571Sdim  /* The instruction 'constant' opcode doewsn't exceed 32 bits.  */
320214571Sdim  unsigned long doubleWord = words[1] + (words[0] << 16);
321214571Sdim
322214571Sdim  /* Start searching from end of instruction table.  */
323214571Sdim  instruction = &cr16_instruction[NUMOPCODES - 2];
324214571Sdim
325214571Sdim  /* Loop over instruction table until a full match is found.  */
326214571Sdim  while (instruction >= cr16_instruction)
327214571Sdim    {
328214571Sdim      mask = build_mask ();
329214571Sdim      if ((doubleWord & mask) == BIN (instruction->match,
330214571Sdim                                      instruction->match_bits))
331214571Sdim        return 1;
332214571Sdim      else
333214571Sdim        instruction--;
334214571Sdim    }
335214571Sdim  return 0;
336214571Sdim}
337214571Sdim
338214571Sdim/* Set the proper parameter value for different type of arguments.  */
339214571Sdim
340214571Sdimstatic void
341214571Sdimmake_argument (argument * a, int start_bits)
342214571Sdim{
343214571Sdim  int inst_bit_size;
344214571Sdim  parameter p;
345214571Sdim
346214571Sdim  if ((instruction->size == 3) && a->size >= 16)
347214571Sdim    inst_bit_size = 48;
348214571Sdim  else
349214571Sdim    inst_bit_size = 32;
350214571Sdim
351214571Sdim  switch (a->type)
352214571Sdim    {
353214571Sdim    case arg_r:
354214571Sdim      p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
355214571Sdim                             inst_bit_size - start_bits);
356214571Sdim      a->r = p.val;
357214571Sdim      break;
358214571Sdim
359214571Sdim    case arg_rp:
360214571Sdim      p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
361214571Sdim                             inst_bit_size - start_bits);
362214571Sdim      a->rp = p.val;
363214571Sdim      break;
364214571Sdim
365214571Sdim    case arg_pr:
366214571Sdim      p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
367214571Sdim                             inst_bit_size - start_bits);
368214571Sdim      a->pr = p.val;
369214571Sdim      break;
370214571Sdim
371214571Sdim    case arg_prp:
372214571Sdim      p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
373214571Sdim                             inst_bit_size - start_bits);
374214571Sdim      a->prp = p.val;
375214571Sdim      break;
376214571Sdim
377214571Sdim    case arg_ic:
378214571Sdim      p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
379214571Sdim                             inst_bit_size - start_bits);
380214571Sdim      a->constant = p.val;
381214571Sdim      break;
382214571Sdim
383214571Sdim    case arg_cc:
384214571Sdim      p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
385214571Sdim                             inst_bit_size - start_bits);
386214571Sdim
387214571Sdim      a->cc = p.val;
388214571Sdim      break;
389214571Sdim
390214571Sdim    case arg_idxr:
391214571Sdim      if ((IS_INSN_MNEMONIC ("cbitb"))
392214571Sdim	  || (IS_INSN_MNEMONIC ("sbitb"))
393214571Sdim	  || (IS_INSN_MNEMONIC ("tbitb")))
394214571Sdim	p = makelongparameter (allWords, 8, 9);
395214571Sdim      else
396214571Sdim	p = makelongparameter (allWords, 9, 10);
397214571Sdim      a->i_r = p.val;
398214571Sdim      p = makelongparameter (allWords, inst_bit_size - a->size, inst_bit_size);
399214571Sdim      a->constant = p.val;
400214571Sdim      break;
401214571Sdim
402214571Sdim    case arg_idxrp:
403214571Sdim      p = makelongparameter (allWords, start_bits + 12, start_bits + 13);
404214571Sdim      a->i_r = p.val;
405214571Sdim      p = makelongparameter (allWords, start_bits + 13, start_bits + 16);
406214571Sdim      a->rp = p.val;
407214571Sdim      if (inst_bit_size > 32)
408214571Sdim	{
409214571Sdim	  p = makelongparameter (allWords, inst_bit_size - start_bits - 12,
410214571Sdim				 inst_bit_size);
411214571Sdim	  a->constant = ((p.val & 0xffff) | (p.val >> 8 & 0xf0000));
412214571Sdim	}
413214571Sdim      else if (instruction->size == 2)
414214571Sdim	{
415214571Sdim	  p = makelongparameter (allWords, inst_bit_size - 22, inst_bit_size);
416214571Sdim	  a->constant = (p.val & 0xf) | (((p.val >>20) & 0x3) << 4)
417214571Sdim	    | ((p.val >>14 & 0x3) << 6) | (((p.val >>7) & 0x1f) <<7);
418214571Sdim	}
419214571Sdim      else if (instruction->size == 1 && a->size == 0)
420214571Sdim	a->constant = 0;
421214571Sdim
422214571Sdim      break;
423214571Sdim
424214571Sdim    case arg_rbase:
425214571Sdim      p = makelongparameter (allWords, inst_bit_size, inst_bit_size);
426214571Sdim      a->constant = p.val;
427214571Sdim      p = makelongparameter (allWords, inst_bit_size - (start_bits + 4),
428214571Sdim                             inst_bit_size - start_bits);
429214571Sdim      a->r = p.val;
430214571Sdim      break;
431214571Sdim
432214571Sdim    case arg_cr:
433214571Sdim      p = makelongparameter (allWords, start_bits + 12, start_bits + 16);
434214571Sdim      a->r = p.val;
435214571Sdim      p = makelongparameter (allWords, inst_bit_size - 16, inst_bit_size);
436214571Sdim      a->constant = p.val;
437214571Sdim      break;
438214571Sdim
439214571Sdim    case arg_crp:
440214571Sdim      if (instruction->size == 1)
441214571Sdim	p = makelongparameter (allWords, 12, 16);
442214571Sdim      else
443214571Sdim	p = makelongparameter (allWords, start_bits + 12, start_bits + 16);
444214571Sdim      a->rp = p.val;
445214571Sdim
446214571Sdim      if (inst_bit_size > 32)
447214571Sdim	{
448214571Sdim	  p = makelongparameter (allWords, inst_bit_size - start_bits - 12,
449214571Sdim				 inst_bit_size);
450214571Sdim	  a->constant = ((p.val & 0xffff) | (p.val >> 8 & 0xf0000));
451214571Sdim	}
452214571Sdim      else if (instruction->size == 2)
453214571Sdim	{
454214571Sdim	  p = makelongparameter (allWords, inst_bit_size - 16, inst_bit_size);
455214571Sdim	  a->constant = p.val;
456214571Sdim	}
457214571Sdim      else if (instruction->size == 1 && a->size != 0)
458214571Sdim	{
459214571Sdim	  p = makelongparameter (allWords, 4, 8);
460214571Sdim	  if (IS_INSN_MNEMONIC ("loadw")
461214571Sdim	      || IS_INSN_MNEMONIC ("loadd")
462214571Sdim	      || IS_INSN_MNEMONIC ("storw")
463214571Sdim	      || IS_INSN_MNEMONIC ("stord"))
464214571Sdim	    a->constant = (p.val * 2);
465214571Sdim	  else
466214571Sdim	    a->constant = p.val;
467214571Sdim	}
468214571Sdim      else /* below case for 0x0(reg pair) */
469214571Sdim	a->constant = 0;
470214571Sdim
471214571Sdim      break;
472214571Sdim
473214571Sdim    case arg_c:
474214571Sdim
475214571Sdim      if ((IS_INSN_TYPE (BRANCH_INS))
476214571Sdim	  || (IS_INSN_MNEMONIC ("bal"))
477214571Sdim	  || (IS_INSN_TYPE (CSTBIT_INS))
478214571Sdim	  || (IS_INSN_TYPE (LD_STOR_INS)))
479214571Sdim	{
480214571Sdim	  switch (a->size)
481214571Sdim	    {
482214571Sdim	    case 8 :
483214571Sdim	      p = makelongparameter (allWords, 0, start_bits);
484214571Sdim	      a->constant = ((((p.val&0xf00)>>4)) | (p.val&0xf));
485214571Sdim	      break;
486214571Sdim
487214571Sdim	    case 24:
488214571Sdim	      if (instruction->size == 3)
489214571Sdim		{
490214571Sdim		  p = makelongparameter (allWords, 16, inst_bit_size);
491214571Sdim		  a->constant = ((((p.val>>16)&0xf) << 20)
492214571Sdim				 | (((p.val>>24)&0xf) << 16)
493214571Sdim				 | (p.val & 0xffff));
494214571Sdim		}
495214571Sdim	      else if (instruction->size == 2)
496214571Sdim		{
497214571Sdim		  p = makelongparameter (allWords, 8, inst_bit_size);
498214571Sdim		  a->constant = p.val;
499214571Sdim		}
500214571Sdim	      break;
501214571Sdim
502214571Sdim	    default:
503214571Sdim	      p = makelongparameter (allWords, inst_bit_size - (start_bits +
504214571Sdim								a->size), inst_bit_size - start_bits);
505214571Sdim	      a->constant = p.val;
506214571Sdim	      break;
507214571Sdim	    }
508214571Sdim	}
509214571Sdim      else
510214571Sdim	{
511214571Sdim	  p = makelongparameter (allWords, inst_bit_size -
512214571Sdim				 (start_bits + a->size),
513214571Sdim				 inst_bit_size - start_bits);
514214571Sdim	  a->constant = p.val;
515214571Sdim	}
516214571Sdim      break;
517214571Sdim
518214571Sdim    default:
519214571Sdim      break;
520214571Sdim    }
521214571Sdim}
522214571Sdim
523214571Sdim/*  Print a single argument.  */
524214571Sdim
525214571Sdimstatic void
526214571Sdimprint_arg (argument *a, bfd_vma memaddr, struct disassemble_info *info)
527214571Sdim{
528214571Sdim  LONGLONG longdisp, mask;
529214571Sdim  int sign_flag = 0;
530214571Sdim  int relative = 0;
531214571Sdim  bfd_vma number;
532214571Sdim  PTR stream = info->stream;
533214571Sdim  fprintf_ftype func = info->fprintf_func;
534214571Sdim
535214571Sdim  switch (a->type)
536214571Sdim    {
537214571Sdim    case arg_r:
538214571Sdim      func (stream, "%s", getregname (a->r));
539214571Sdim      break;
540214571Sdim
541214571Sdim    case arg_rp:
542214571Sdim      func (stream, "%s", getregpname (a->rp));
543214571Sdim      break;
544214571Sdim
545214571Sdim    case arg_pr:
546214571Sdim      func (stream, "%s", getprocregname (a->pr));
547214571Sdim      break;
548214571Sdim
549214571Sdim    case arg_prp:
550214571Sdim      func (stream, "%s", getprocpregname (a->prp));
551214571Sdim      break;
552214571Sdim
553214571Sdim    case arg_cc:
554214571Sdim      func (stream, "%s", getccstring (a->cc));
555214571Sdim      func (stream, "%s", "\t");
556214571Sdim      break;
557214571Sdim
558214571Sdim    case arg_ic:
559214571Sdim      if (IS_INSN_MNEMONIC ("excp"))
560214571Sdim	{
561214571Sdim	  func (stream, "%s", gettrapstring (a->constant));
562214571Sdim	  break;
563214571Sdim	}
564214571Sdim      else if ((IS_INSN_TYPE (ARITH_INS) || IS_INSN_TYPE (ARITH_BYTE_INS))
565214571Sdim	       && ((instruction->size == 1) && (a->constant == 9)))
566214571Sdim	func (stream, "$%d", -1);
567214571Sdim      else if (INST_HAS_REG_LIST)
568214571Sdim	func (stream, "$0x%lx", a->constant +1);
569214571Sdim      else if (IS_INSN_TYPE (SHIFT_INS))
570214571Sdim	{
571214571Sdim	  longdisp = a->constant;
572214571Sdim	  mask = ((LONGLONG)1 << a->size) - 1;
573214571Sdim	  if (longdisp & ((LONGLONG)1 << (a->size -1)))
574214571Sdim	    {
575214571Sdim	      sign_flag = 1;
576214571Sdim	      longdisp = ~(longdisp) + 1;
577214571Sdim	    }
578214571Sdim	  a->constant = (unsigned long int) (longdisp & mask);
579214571Sdim	  func (stream, "$%d", ((int)(sign_flag ? -a->constant :
580214571Sdim				      a->constant)));
581214571Sdim	}
582214571Sdim      else
583214571Sdim	func (stream, "$0x%lx", a->constant);
584214571Sdim      switch (a->size)
585214571Sdim	{
586214571Sdim	case 4  : case 5  : case 6  : case 8  :
587214571Sdim	  func (stream, "%s", ":s"); break;
588214571Sdim	case 16 : case 20 : func (stream, "%s", ":m"); break;
589214571Sdim	case 24 : case 32 : func (stream, "%s", ":l"); break;
590214571Sdim	default: break;
591214571Sdim	}
592214571Sdim      break;
593214571Sdim
594214571Sdim    case arg_idxr:
595214571Sdim      if (a->i_r == 0) func (stream, "[r12]");
596214571Sdim      if (a->i_r == 1) func (stream, "[r13]");
597214571Sdim      func (stream, "0x%lx", a->constant);
598214571Sdim      func (stream, "%s", print_exp_len (instruction->size * 16));
599214571Sdim      break;
600214571Sdim
601214571Sdim    case arg_idxrp:
602214571Sdim      if (a->i_r == 0) func (stream, "[r12]");
603214571Sdim      if (a->i_r == 1) func (stream, "[r13]");
604214571Sdim      func (stream, "0x%lx", a->constant);
605214571Sdim      func (stream, "%s", print_exp_len (instruction->size * 16));
606214571Sdim      func (stream, "%s", getidxregpname (a->rp));
607214571Sdim      break;
608214571Sdim
609214571Sdim    case arg_rbase:
610214571Sdim      func (stream, "(%s)", getregname (a->r));
611214571Sdim      break;
612214571Sdim
613214571Sdim    case arg_cr:
614214571Sdim      func (stream, "0x%lx", a->constant);
615214571Sdim      func (stream, "%s", print_exp_len (instruction->size * 16));
616214571Sdim      func (stream, "(%s)", getregname (a->r));
617214571Sdim      break;
618214571Sdim
619214571Sdim    case arg_crp:
620214571Sdim      func (stream, "0x%lx", a->constant);
621214571Sdim      func (stream, "%s", print_exp_len (instruction->size * 16));
622214571Sdim      func (stream, "%s", getregpname (a->rp));
623214571Sdim      break;
624214571Sdim
625214571Sdim    case arg_c:
626214571Sdim      /*Removed the *2 part as because implicit zeros are no more required.
627214571Sdim	Have to fix this as this needs a bit of extension in terms of branch
628214571Sdim	instructions. */
629214571Sdim      if (IS_INSN_TYPE (BRANCH_INS) || IS_INSN_MNEMONIC ("bal"))
630214571Sdim	{
631214571Sdim	  relative = 1;
632214571Sdim	  longdisp = a->constant;
633214571Sdim	  /* REVISIT: To sync with WinIDEA and CR16 4.1tools, the below
634214571Sdim	     line commented */
635214571Sdim	  /* longdisp <<= 1; */
636214571Sdim	  mask = ((LONGLONG)1 << a->size) - 1;
637214571Sdim	  switch (a->size)
638214571Sdim	    {
639214571Sdim	    case 8  :
640214571Sdim	      {
641214571Sdim		longdisp <<= 1;
642214571Sdim		if (longdisp & ((LONGLONG)1 << a->size))
643214571Sdim		  {
644214571Sdim		    sign_flag = 1;
645214571Sdim		    longdisp = ~(longdisp) + 1;
646214571Sdim		  }
647214571Sdim		break;
648214571Sdim	      }
649214571Sdim	    case 16 :
650214571Sdim	    case 24 :
651214571Sdim	      {
652214571Sdim		if (longdisp & 1)
653214571Sdim		  {
654214571Sdim		    sign_flag = 1;
655214571Sdim		    longdisp = ~(longdisp) + 1;
656214571Sdim		  }
657214571Sdim		break;
658214571Sdim	      }
659214571Sdim	    default:
660214571Sdim	      func (stream, "Wrong offset used in branch/bal instruction");
661214571Sdim	      break;
662214571Sdim	    }
663214571Sdim	  a->constant = (unsigned long int) (longdisp & mask);
664214571Sdim	}
665214571Sdim      /* For branch Neq instruction it is 2*offset + 2.  */
666214571Sdim      else if (IS_INSN_TYPE (BRANCH_NEQ_INS))
667214571Sdim	a->constant = 2 * a->constant + 2;
668214571Sdim
669214571Sdim      if ((!IS_INSN_TYPE (CSTBIT_INS)) && (!IS_INSN_TYPE (LD_STOR_INS)))
670214571Sdim	(sign_flag) ? func (stream, "%s", "*-"): func (stream, "%s","*+");
671214571Sdim
672214571Sdim      func (stream, "%s", "0x");
673214571Sdim      number = ((relative ? memaddr : 0) +
674214571Sdim		(sign_flag ? ((- a->constant) & 0xffffffe) : a->constant));
675214571Sdim
676214571Sdim      (*info->print_address_func) ((number & ((1 << 24) - 1)), info);
677214571Sdim
678214571Sdim      func (stream, "%s", print_exp_len (instruction->size * 16));
679214571Sdim      break;
680214571Sdim
681214571Sdim    default:
682214571Sdim      break;
683214571Sdim    }
684214571Sdim}
685214571Sdim
686214571Sdim/* Print all the arguments of CURRINSN instruction.  */
687214571Sdim
688214571Sdimstatic void
689214571Sdimprint_arguments (ins *currInsn, bfd_vma memaddr, struct disassemble_info *info)
690214571Sdim{
691214571Sdim  int i;
692214571Sdim
693214571Sdim  /* For "pop/push/popret RA instruction only.  */
694214571Sdim  if ((IS_INSN_MNEMONIC ("pop")
695214571Sdim       || (IS_INSN_MNEMONIC ("popret")
696214571Sdim	   || (IS_INSN_MNEMONIC ("push"))))
697214571Sdim      && currInsn->nargs == 1)
698214571Sdim    {
699214571Sdim      info->fprintf_func (info->stream, "RA");
700214571Sdim      return;
701214571Sdim    }
702214571Sdim
703214571Sdim  for (i = 0; i < currInsn->nargs; i++)
704214571Sdim    {
705214571Sdim      processing_argument_number = i;
706214571Sdim
707214571Sdim      /* For "bal (ra), disp17" instruction only.  */
708214571Sdim      if ((IS_INSN_MNEMONIC ("bal")) && (i == 0) && instruction->size == 2)
709214571Sdim        {
710214571Sdim          info->fprintf_func (info->stream, "(ra),");
711214571Sdim          continue;
712214571Sdim        }
713214571Sdim
714214571Sdim      if ((INST_HAS_REG_LIST) && (i == 2))
715214571Sdim        info->fprintf_func (info->stream, "RA");
716214571Sdim      else
717214571Sdim        print_arg (&currInsn->arg[i], memaddr, info);
718214571Sdim
719214571Sdim      if ((i != currInsn->nargs - 1) && (!IS_INSN_MNEMONIC ("b")))
720214571Sdim        info->fprintf_func (info->stream, ",");
721214571Sdim    }
722214571Sdim}
723214571Sdim
724214571Sdim/* Build the instruction's arguments.  */
725214571Sdim
726214571Sdimstatic void
727214571Sdimmake_instruction (void)
728214571Sdim{
729214571Sdim  int i;
730214571Sdim  unsigned int shift;
731214571Sdim
732214571Sdim  for (i = 0; i < currInsn.nargs; i++)
733214571Sdim    {
734214571Sdim      argument a;
735214571Sdim
736214571Sdim      memset (&a, 0, sizeof (a));
737214571Sdim      a.type = getargtype (instruction->operands[i].op_type);
738214571Sdim      a.size = getbits (instruction->operands[i].op_type);
739214571Sdim      shift = instruction->operands[i].shift;
740214571Sdim
741214571Sdim      make_argument (&a, shift);
742214571Sdim      currInsn.arg[i] = a;
743214571Sdim    }
744214571Sdim
745214571Sdim  /* Calculate instruction size (in bytes).  */
746214571Sdim  currInsn.size = instruction->size + (size_changed ? 1 : 0);
747214571Sdim  /* Now in bits.  */
748214571Sdim  currInsn.size *= 2;
749214571Sdim}
750214571Sdim
751214571Sdim/* Retrieve a single word from a given memory address.  */
752214571Sdim
753214571Sdimstatic wordU
754214571Sdimget_word_at_PC (bfd_vma memaddr, struct disassemble_info *info)
755214571Sdim{
756214571Sdim  bfd_byte buffer[4];
757214571Sdim  int status;
758214571Sdim  wordU insn = 0;
759214571Sdim
760214571Sdim  status = info->read_memory_func (memaddr, buffer, 2, info);
761214571Sdim
762214571Sdim  if (status == 0)
763214571Sdim    insn = (wordU) bfd_getl16 (buffer);
764214571Sdim
765214571Sdim  return insn;
766214571Sdim}
767214571Sdim
768214571Sdim/* Retrieve multiple words (3) from a given memory address.  */
769214571Sdim
770214571Sdimstatic void
771214571Sdimget_words_at_PC (bfd_vma memaddr, struct disassemble_info *info)
772214571Sdim{
773214571Sdim  int i;
774214571Sdim  bfd_vma mem;
775214571Sdim
776214571Sdim  for (i = 0, mem = memaddr; i < 3; i++, mem += 2)
777214571Sdim    words[i] = get_word_at_PC (mem, info);
778214571Sdim
779214571Sdim  allWords =
780214571Sdim    ((ULONGLONG) words[0] << 32) + ((unsigned long) words[1] << 16) + words[2];
781214571Sdim}
782214571Sdim
783214571Sdim/* Prints the instruction by calling print_arguments after proper matching.  */
784214571Sdim
785214571Sdimint
786214571Sdimprint_insn_cr16 (bfd_vma memaddr, struct disassemble_info *info)
787214571Sdim{
788214571Sdim  int is_decoded;     /* Nonzero means instruction has a match.  */
789214571Sdim
790214571Sdim  /* Initialize global variables.  */
791214571Sdim  imm4flag = 0;
792214571Sdim  size_changed = 0;
793214571Sdim
794214571Sdim  /* Retrieve the encoding from current memory location.  */
795214571Sdim  get_words_at_PC (memaddr, info);
796214571Sdim  /* Find a matching opcode in table.  */
797214571Sdim  is_decoded = match_opcode ();
798214571Sdim  /* If found, print the instruction's mnemonic and arguments.  */
799214571Sdim  if (is_decoded > 0 && (words[0] << 16 || words[1]) != 0)
800214571Sdim    {
801214571Sdim      if (strneq (instruction->mnemonic, "cinv", 4))
802214571Sdim        info->fprintf_func (info->stream,"%s", getcinvstring ((char *)instruction->mnemonic));
803214571Sdim      else
804214571Sdim        info->fprintf_func (info->stream, "%s", instruction->mnemonic);
805214571Sdim
806214571Sdim      if (((currInsn.nargs = get_number_of_operands ()) != 0)
807214571Sdim	  && ! (IS_INSN_MNEMONIC ("b")))
808214571Sdim        info->fprintf_func (info->stream, "\t");
809214571Sdim      make_instruction ();
810214571Sdim      /* For push/pop/pushrtn with RA instructions.  */
811214571Sdim      if ((INST_HAS_REG_LIST) && ((words[0] >> 7) & 0x1))
812214571Sdim        currInsn.nargs +=1;
813214571Sdim      print_arguments (&currInsn, memaddr, info);
814214571Sdim      return currInsn.size;
815214571Sdim    }
816214571Sdim
817214571Sdim  /* No match found.  */
818214571Sdim  info->fprintf_func (info->stream,"%s ",ILLEGAL);
819214571Sdim  return 2;
820214571Sdim}
821