1*3d8817e4Smiod /* Disassembler code for CRX.
2*3d8817e4Smiod    Copyright 2004, 2005 Free Software Foundation, Inc.
3*3d8817e4Smiod    Contributed by Tomer Levi, NSC, Israel.
4*3d8817e4Smiod    Written by Tomer Levi.
5*3d8817e4Smiod 
6*3d8817e4Smiod    This file is part of the GNU binutils and GDB, the GNU debugger.
7*3d8817e4Smiod 
8*3d8817e4Smiod    This program is free software; you can redistribute it and/or modify it under
9*3d8817e4Smiod    the terms of the GNU General Public License as published by the Free
10*3d8817e4Smiod    Software Foundation; either version 2, or (at your option)
11*3d8817e4Smiod    any later version.
12*3d8817e4Smiod 
13*3d8817e4Smiod    This program is distributed in the hope that it will be useful, but WITHOUT
14*3d8817e4Smiod    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15*3d8817e4Smiod    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16*3d8817e4Smiod    more details.
17*3d8817e4Smiod 
18*3d8817e4Smiod    You should have received a copy of the GNU General Public License
19*3d8817e4Smiod    along with this program; if not, write to the Free Software
20*3d8817e4Smiod    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
21*3d8817e4Smiod 
22*3d8817e4Smiod #include "dis-asm.h"
23*3d8817e4Smiod #include "sysdep.h"
24*3d8817e4Smiod #include "opcode/crx.h"
25*3d8817e4Smiod 
26*3d8817e4Smiod /* String to print when opcode was not matched.  */
27*3d8817e4Smiod #define ILLEGAL	"illegal"
28*3d8817e4Smiod   /* Escape to 16-bit immediate.  */
29*3d8817e4Smiod #define ESCAPE_16_BIT  0xE
30*3d8817e4Smiod 
31*3d8817e4Smiod /* Extract 'n_bits' from 'a' starting from offset 'offs'.  */
32*3d8817e4Smiod #define EXTRACT(a, offs, n_bits)	    \
33*3d8817e4Smiod   (n_bits == 32 ? (((a) >> (offs)) & 0xffffffffL)   \
34*3d8817e4Smiod   : (((a) >> (offs)) & ((1 << (n_bits)) -1)))
35*3d8817e4Smiod 
36*3d8817e4Smiod /* Set Bit Mask - a mask to set all bits starting from offset 'offs'.  */
37*3d8817e4Smiod #define SBM(offs)  ((((1 << (32 - offs)) -1) << (offs)))
38*3d8817e4Smiod 
39*3d8817e4Smiod typedef unsigned long dwordU;
40*3d8817e4Smiod typedef unsigned short wordU;
41*3d8817e4Smiod 
42*3d8817e4Smiod typedef struct
43*3d8817e4Smiod {
44*3d8817e4Smiod   dwordU val;
45*3d8817e4Smiod   int nbits;
46*3d8817e4Smiod } parameter;
47*3d8817e4Smiod 
48*3d8817e4Smiod /* Structure to hold valid 'cinv' instruction options.  */
49*3d8817e4Smiod 
50*3d8817e4Smiod typedef struct
51*3d8817e4Smiod   {
52*3d8817e4Smiod     /* Cinv printed string.  */
53*3d8817e4Smiod     char *str;
54*3d8817e4Smiod     /* Value corresponding to the string.  */
55*3d8817e4Smiod     unsigned int value;
56*3d8817e4Smiod   }
57*3d8817e4Smiod cinv_entry;
58*3d8817e4Smiod 
59*3d8817e4Smiod /* CRX 'cinv' options.  */
60*3d8817e4Smiod const cinv_entry crx_cinvs[] =
61*3d8817e4Smiod {
62*3d8817e4Smiod   {"[i]", 2}, {"[i,u]", 3}, {"[d]", 4}, {"[d,u]", 5},
63*3d8817e4Smiod   {"[d,i]", 6}, {"[d,i,u]", 7}, {"[b]", 8},
64*3d8817e4Smiod   {"[b,i]", 10}, {"[b,i,u]", 11}, {"[b,d]", 12},
65*3d8817e4Smiod   {"[b,d,u]", 13}, {"[b,d,i]", 14}, {"[b,d,i,u]", 15}
66*3d8817e4Smiod };
67*3d8817e4Smiod 
68*3d8817e4Smiod /* Enum to distinguish different registers argument types.  */
69*3d8817e4Smiod typedef enum REG_ARG_TYPE
70*3d8817e4Smiod   {
71*3d8817e4Smiod     /* General purpose register (r<N>).  */
72*3d8817e4Smiod     REG_ARG = 0,
73*3d8817e4Smiod     /* User register (u<N>).  */
74*3d8817e4Smiod     USER_REG_ARG,
75*3d8817e4Smiod     /* CO-Processor register (c<N>).  */
76*3d8817e4Smiod     COP_ARG,
77*3d8817e4Smiod     /* CO-Processor special register (cs<N>).  */
78*3d8817e4Smiod     COPS_ARG
79*3d8817e4Smiod   }
80*3d8817e4Smiod REG_ARG_TYPE;
81*3d8817e4Smiod 
82*3d8817e4Smiod /* Number of valid 'cinv' instruction options.  */
83*3d8817e4Smiod int NUMCINVS = ((sizeof crx_cinvs)/(sizeof crx_cinvs[0]));
84*3d8817e4Smiod /* Current opcode table entry we're disassembling.  */
85*3d8817e4Smiod const inst *instruction;
86*3d8817e4Smiod /* Current instruction we're disassembling.  */
87*3d8817e4Smiod ins currInsn;
88*3d8817e4Smiod /* The current instruction is read into 3 consecutive words.  */
89*3d8817e4Smiod wordU words[3];
90*3d8817e4Smiod /* Contains all words in appropriate order.  */
91*3d8817e4Smiod ULONGLONG allWords;
92*3d8817e4Smiod /* Holds the current processed argument number.  */
93*3d8817e4Smiod int processing_argument_number;
94*3d8817e4Smiod /* Nonzero means a CST4 instruction.  */
95*3d8817e4Smiod int cst4flag;
96*3d8817e4Smiod /* Nonzero means the instruction's original size is
97*3d8817e4Smiod    incremented (escape sequence is used).  */
98*3d8817e4Smiod int size_changed;
99*3d8817e4Smiod 
100*3d8817e4Smiod static int get_number_of_operands (void);
101*3d8817e4Smiod static argtype getargtype     (operand_type);
102*3d8817e4Smiod static int getbits	      (operand_type);
103*3d8817e4Smiod static char *getregname	      (reg);
104*3d8817e4Smiod static char *getcopregname    (copreg, reg_type);
105*3d8817e4Smiod static char * getprocregname  (int);
106*3d8817e4Smiod static char *gettrapstring    (unsigned);
107*3d8817e4Smiod static char *getcinvstring    (unsigned);
108*3d8817e4Smiod static void getregliststring  (int, char *, enum REG_ARG_TYPE);
109*3d8817e4Smiod static wordU get_word_at_PC   (bfd_vma, struct disassemble_info *);
110*3d8817e4Smiod static void get_words_at_PC   (bfd_vma, struct disassemble_info *);
111*3d8817e4Smiod static unsigned long build_mask (void);
112*3d8817e4Smiod static int powerof2	      (int);
113*3d8817e4Smiod static int match_opcode	      (void);
114*3d8817e4Smiod static void make_instruction  (void);
115*3d8817e4Smiod static void print_arguments   (ins *, bfd_vma, struct disassemble_info *);
116*3d8817e4Smiod static void print_arg	      (argument *, bfd_vma, struct disassemble_info *);
117*3d8817e4Smiod 
118*3d8817e4Smiod /* Retrieve the number of operands for the current assembled instruction.  */
119*3d8817e4Smiod 
120*3d8817e4Smiod static int
get_number_of_operands(void)121*3d8817e4Smiod get_number_of_operands (void)
122*3d8817e4Smiod {
123*3d8817e4Smiod   int i;
124*3d8817e4Smiod 
125*3d8817e4Smiod   for (i = 0; instruction->operands[i].op_type && i < MAX_OPERANDS; i++)
126*3d8817e4Smiod     ;
127*3d8817e4Smiod 
128*3d8817e4Smiod   return i;
129*3d8817e4Smiod }
130*3d8817e4Smiod 
131*3d8817e4Smiod /* Return the bit size for a given operand.  */
132*3d8817e4Smiod 
133*3d8817e4Smiod static int
getbits(operand_type op)134*3d8817e4Smiod getbits (operand_type op)
135*3d8817e4Smiod {
136*3d8817e4Smiod   if (op < MAX_OPRD)
137*3d8817e4Smiod     return crx_optab[op].bit_size;
138*3d8817e4Smiod   else
139*3d8817e4Smiod     return 0;
140*3d8817e4Smiod }
141*3d8817e4Smiod 
142*3d8817e4Smiod /* Return the argument type of a given operand.  */
143*3d8817e4Smiod 
144*3d8817e4Smiod static argtype
getargtype(operand_type op)145*3d8817e4Smiod getargtype (operand_type op)
146*3d8817e4Smiod {
147*3d8817e4Smiod   if (op < MAX_OPRD)
148*3d8817e4Smiod     return crx_optab[op].arg_type;
149*3d8817e4Smiod   else
150*3d8817e4Smiod     return nullargs;
151*3d8817e4Smiod }
152*3d8817e4Smiod 
153*3d8817e4Smiod /* Given the trap index in dispatch table, return its name.
154*3d8817e4Smiod    This routine is used when disassembling the 'excp' instruction.  */
155*3d8817e4Smiod 
156*3d8817e4Smiod static char *
gettrapstring(unsigned int index)157*3d8817e4Smiod gettrapstring (unsigned int index)
158*3d8817e4Smiod {
159*3d8817e4Smiod   const trap_entry *trap;
160*3d8817e4Smiod 
161*3d8817e4Smiod   for (trap = crx_traps; trap < crx_traps + NUMTRAPS; trap++)
162*3d8817e4Smiod     if (trap->entry == index)
163*3d8817e4Smiod       return trap->name;
164*3d8817e4Smiod 
165*3d8817e4Smiod   return ILLEGAL;
166*3d8817e4Smiod }
167*3d8817e4Smiod 
168*3d8817e4Smiod /* Given a 'cinv' instruction constant operand, return its corresponding string.
169*3d8817e4Smiod    This routine is used when disassembling the 'cinv' instruction.  */
170*3d8817e4Smiod 
171*3d8817e4Smiod static char *
getcinvstring(unsigned int num)172*3d8817e4Smiod getcinvstring (unsigned int num)
173*3d8817e4Smiod {
174*3d8817e4Smiod   const cinv_entry *cinv;
175*3d8817e4Smiod 
176*3d8817e4Smiod   for (cinv = crx_cinvs; cinv < (crx_cinvs + NUMCINVS); cinv++)
177*3d8817e4Smiod     if (cinv->value == num)
178*3d8817e4Smiod       return cinv->str;
179*3d8817e4Smiod 
180*3d8817e4Smiod   return ILLEGAL;
181*3d8817e4Smiod }
182*3d8817e4Smiod 
183*3d8817e4Smiod /* Given a register enum value, retrieve its name.  */
184*3d8817e4Smiod 
185*3d8817e4Smiod char *
getregname(reg r)186*3d8817e4Smiod getregname (reg r)
187*3d8817e4Smiod {
188*3d8817e4Smiod   const reg_entry *reg = &crx_regtab[r];
189*3d8817e4Smiod 
190*3d8817e4Smiod   if (reg->type != CRX_R_REGTYPE)
191*3d8817e4Smiod     return ILLEGAL;
192*3d8817e4Smiod   else
193*3d8817e4Smiod     return reg->name;
194*3d8817e4Smiod }
195*3d8817e4Smiod 
196*3d8817e4Smiod /* Given a coprocessor register enum value, retrieve its name.  */
197*3d8817e4Smiod 
198*3d8817e4Smiod char *
getcopregname(copreg r,reg_type type)199*3d8817e4Smiod getcopregname (copreg r, reg_type type)
200*3d8817e4Smiod {
201*3d8817e4Smiod   const reg_entry *reg;
202*3d8817e4Smiod 
203*3d8817e4Smiod   if (type == CRX_C_REGTYPE)
204*3d8817e4Smiod     reg = &crx_copregtab[r];
205*3d8817e4Smiod   else if (type == CRX_CS_REGTYPE)
206*3d8817e4Smiod     reg = &crx_copregtab[r+(cs0-c0)];
207*3d8817e4Smiod   else
208*3d8817e4Smiod     return ILLEGAL;
209*3d8817e4Smiod 
210*3d8817e4Smiod   return reg->name;
211*3d8817e4Smiod }
212*3d8817e4Smiod 
213*3d8817e4Smiod 
214*3d8817e4Smiod /* Getting a processor register name.  */
215*3d8817e4Smiod 
216*3d8817e4Smiod static char *
getprocregname(int index)217*3d8817e4Smiod getprocregname (int index)
218*3d8817e4Smiod {
219*3d8817e4Smiod   const reg_entry *r;
220*3d8817e4Smiod 
221*3d8817e4Smiod   for (r = crx_regtab; r < crx_regtab + NUMREGS; r++)
222*3d8817e4Smiod     if (r->image == index)
223*3d8817e4Smiod       return r->name;
224*3d8817e4Smiod 
225*3d8817e4Smiod   return "ILLEGAL REGISTER";
226*3d8817e4Smiod }
227*3d8817e4Smiod 
228*3d8817e4Smiod /* Get the power of two for a given integer.  */
229*3d8817e4Smiod 
230*3d8817e4Smiod static int
powerof2(int x)231*3d8817e4Smiod powerof2 (int x)
232*3d8817e4Smiod {
233*3d8817e4Smiod   int product, i;
234*3d8817e4Smiod 
235*3d8817e4Smiod   for (i = 0, product = 1; i < x; i++)
236*3d8817e4Smiod     product *= 2;
237*3d8817e4Smiod 
238*3d8817e4Smiod   return product;
239*3d8817e4Smiod }
240*3d8817e4Smiod 
241*3d8817e4Smiod /* Transform a register bit mask to a register list.  */
242*3d8817e4Smiod 
243*3d8817e4Smiod void
getregliststring(int mask,char * string,enum REG_ARG_TYPE core_cop)244*3d8817e4Smiod getregliststring (int mask, char *string, enum REG_ARG_TYPE core_cop)
245*3d8817e4Smiod {
246*3d8817e4Smiod   char temp_string[5];
247*3d8817e4Smiod   int i;
248*3d8817e4Smiod 
249*3d8817e4Smiod   string[0] = '{';
250*3d8817e4Smiod   string[1] = '\0';
251*3d8817e4Smiod 
252*3d8817e4Smiod 
253*3d8817e4Smiod   /* A zero mask means HI/LO registers.  */
254*3d8817e4Smiod   if (mask == 0)
255*3d8817e4Smiod     {
256*3d8817e4Smiod       if (core_cop == USER_REG_ARG)
257*3d8817e4Smiod 	strcat (string, "ulo,uhi");
258*3d8817e4Smiod       else
259*3d8817e4Smiod 	strcat (string, "lo,hi");
260*3d8817e4Smiod     }
261*3d8817e4Smiod   else
262*3d8817e4Smiod     {
263*3d8817e4Smiod       for (i = 0; i < 16; i++)
264*3d8817e4Smiod 	{
265*3d8817e4Smiod 	  if (mask & 0x1)
266*3d8817e4Smiod 	    {
267*3d8817e4Smiod 	      switch (core_cop)
268*3d8817e4Smiod 	      {
269*3d8817e4Smiod 	      case REG_ARG:
270*3d8817e4Smiod 		sprintf (temp_string, "r%d", i);
271*3d8817e4Smiod 		break;
272*3d8817e4Smiod 	      case USER_REG_ARG:
273*3d8817e4Smiod 		sprintf (temp_string, "u%d", i);
274*3d8817e4Smiod 		break;
275*3d8817e4Smiod 	      case COP_ARG:
276*3d8817e4Smiod 		sprintf (temp_string, "c%d", i);
277*3d8817e4Smiod 		break;
278*3d8817e4Smiod 	      case COPS_ARG:
279*3d8817e4Smiod 		sprintf (temp_string, "cs%d", i);
280*3d8817e4Smiod 		break;
281*3d8817e4Smiod 	      default:
282*3d8817e4Smiod 		break;
283*3d8817e4Smiod 	      }
284*3d8817e4Smiod 	      strcat (string, temp_string);
285*3d8817e4Smiod 	      if (mask & 0xfffe)
286*3d8817e4Smiod 		strcat (string, ",");
287*3d8817e4Smiod 	    }
288*3d8817e4Smiod 	  mask >>= 1;
289*3d8817e4Smiod 	}
290*3d8817e4Smiod     }
291*3d8817e4Smiod 
292*3d8817e4Smiod   strcat (string, "}");
293*3d8817e4Smiod }
294*3d8817e4Smiod 
295*3d8817e4Smiod /* START and END are relating 'allWords' struct, which is 48 bits size.
296*3d8817e4Smiod 
297*3d8817e4Smiod 			  START|--------|END
298*3d8817e4Smiod 	    +---------+---------+---------+---------+
299*3d8817e4Smiod 	    |	      |	   V    |     A	  |   L	    |
300*3d8817e4Smiod 	    +---------+---------+---------+---------+
301*3d8817e4Smiod 	    	      0		16	  32	    48
302*3d8817e4Smiod     words		  [0]	    [1]	      [2]	*/
303*3d8817e4Smiod 
304*3d8817e4Smiod static parameter
makelongparameter(ULONGLONG val,int start,int end)305*3d8817e4Smiod makelongparameter (ULONGLONG val, int start, int end)
306*3d8817e4Smiod {
307*3d8817e4Smiod   parameter p;
308*3d8817e4Smiod 
309*3d8817e4Smiod   p.val = (dwordU) EXTRACT(val, 48 - end, end - start);
310*3d8817e4Smiod   p.nbits = end - start;
311*3d8817e4Smiod   return p;
312*3d8817e4Smiod }
313*3d8817e4Smiod 
314*3d8817e4Smiod /* Build a mask of the instruction's 'constant' opcode,
315*3d8817e4Smiod    based on the instruction's printing flags.  */
316*3d8817e4Smiod 
317*3d8817e4Smiod static unsigned long
build_mask(void)318*3d8817e4Smiod build_mask (void)
319*3d8817e4Smiod {
320*3d8817e4Smiod   unsigned int print_flags;
321*3d8817e4Smiod   unsigned long mask;
322*3d8817e4Smiod 
323*3d8817e4Smiod   print_flags = instruction->flags & FMT_CRX;
324*3d8817e4Smiod   switch (print_flags)
325*3d8817e4Smiod     {
326*3d8817e4Smiod       case FMT_1:
327*3d8817e4Smiod 	mask = 0xF0F00000;
328*3d8817e4Smiod 	break;
329*3d8817e4Smiod       case FMT_2:
330*3d8817e4Smiod 	mask = 0xFFF0FF00;
331*3d8817e4Smiod 	break;
332*3d8817e4Smiod       case FMT_3:
333*3d8817e4Smiod 	mask = 0xFFF00F00;
334*3d8817e4Smiod 	break;
335*3d8817e4Smiod       case FMT_4:
336*3d8817e4Smiod 	mask = 0xFFF0F000;
337*3d8817e4Smiod 	break;
338*3d8817e4Smiod       case FMT_5:
339*3d8817e4Smiod 	mask = 0xFFF0FFF0;
340*3d8817e4Smiod 	break;
341*3d8817e4Smiod       default:
342*3d8817e4Smiod 	mask = SBM(instruction->match_bits);
343*3d8817e4Smiod 	break;
344*3d8817e4Smiod     }
345*3d8817e4Smiod 
346*3d8817e4Smiod   return mask;
347*3d8817e4Smiod }
348*3d8817e4Smiod 
349*3d8817e4Smiod /* Search for a matching opcode. Return 1 for success, 0 for failure.  */
350*3d8817e4Smiod 
351*3d8817e4Smiod static int
match_opcode(void)352*3d8817e4Smiod match_opcode (void)
353*3d8817e4Smiod {
354*3d8817e4Smiod   unsigned long mask;
355*3d8817e4Smiod 
356*3d8817e4Smiod   /* The instruction 'constant' opcode doewsn't exceed 32 bits.  */
357*3d8817e4Smiod   unsigned long doubleWord = words[1] + (words[0] << 16);
358*3d8817e4Smiod 
359*3d8817e4Smiod   /* Start searching from end of instruction table.  */
360*3d8817e4Smiod   instruction = &crx_instruction[NUMOPCODES - 2];
361*3d8817e4Smiod 
362*3d8817e4Smiod   /* Loop over instruction table until a full match is found.  */
363*3d8817e4Smiod   while (instruction >= crx_instruction)
364*3d8817e4Smiod     {
365*3d8817e4Smiod       mask = build_mask ();
366*3d8817e4Smiod       if ((doubleWord & mask) == BIN(instruction->match, instruction->match_bits))
367*3d8817e4Smiod 	return 1;
368*3d8817e4Smiod       else
369*3d8817e4Smiod 	instruction--;
370*3d8817e4Smiod     }
371*3d8817e4Smiod   return 0;
372*3d8817e4Smiod }
373*3d8817e4Smiod 
374*3d8817e4Smiod /* Set the proper parameter value for different type of arguments.  */
375*3d8817e4Smiod 
376*3d8817e4Smiod static void
make_argument(argument * a,int start_bits)377*3d8817e4Smiod make_argument (argument * a, int start_bits)
378*3d8817e4Smiod {
379*3d8817e4Smiod   int inst_bit_size, total_size;
380*3d8817e4Smiod   parameter p;
381*3d8817e4Smiod 
382*3d8817e4Smiod   if ((instruction->size == 3) && a->size >= 16)
383*3d8817e4Smiod     inst_bit_size = 48;
384*3d8817e4Smiod   else
385*3d8817e4Smiod     inst_bit_size = 32;
386*3d8817e4Smiod 
387*3d8817e4Smiod   switch (a->type)
388*3d8817e4Smiod     {
389*3d8817e4Smiod     case arg_copr:
390*3d8817e4Smiod     case arg_copsr:
391*3d8817e4Smiod       p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
392*3d8817e4Smiod 			     inst_bit_size - start_bits);
393*3d8817e4Smiod       a->cr = p.val;
394*3d8817e4Smiod       break;
395*3d8817e4Smiod 
396*3d8817e4Smiod     case arg_r:
397*3d8817e4Smiod       p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
398*3d8817e4Smiod 			     inst_bit_size - start_bits);
399*3d8817e4Smiod       a->r = p.val;
400*3d8817e4Smiod       break;
401*3d8817e4Smiod 
402*3d8817e4Smiod     case arg_ic:
403*3d8817e4Smiod       p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
404*3d8817e4Smiod 			     inst_bit_size - start_bits);
405*3d8817e4Smiod 
406*3d8817e4Smiod       if ((p.nbits == 4) && cst4flag)
407*3d8817e4Smiod         {
408*3d8817e4Smiod 	  if (IS_INSN_TYPE (CMPBR_INS) && (p.val == ESCAPE_16_BIT))
409*3d8817e4Smiod 	    {
410*3d8817e4Smiod 	      /* A special case, where the value is actually stored
411*3d8817e4Smiod 		 in the last 4 bits.  */
412*3d8817e4Smiod 	      p = makelongparameter (allWords, 44, 48);
413*3d8817e4Smiod 	      /* The size of the instruction should be incremented.  */
414*3d8817e4Smiod 	      size_changed = 1;
415*3d8817e4Smiod 	    }
416*3d8817e4Smiod 
417*3d8817e4Smiod           if (p.val == 6)
418*3d8817e4Smiod             p.val = -1;
419*3d8817e4Smiod           else if (p.val == 13)
420*3d8817e4Smiod             p.val = 48;
421*3d8817e4Smiod           else if (p.val == 5)
422*3d8817e4Smiod             p.val = -4;
423*3d8817e4Smiod           else if (p.val == 10)
424*3d8817e4Smiod             p.val = 32;
425*3d8817e4Smiod           else if (p.val == 11)
426*3d8817e4Smiod             p.val = 20;
427*3d8817e4Smiod           else if (p.val == 9)
428*3d8817e4Smiod             p.val = 16;
429*3d8817e4Smiod         }
430*3d8817e4Smiod 
431*3d8817e4Smiod       a->constant = p.val;
432*3d8817e4Smiod       break;
433*3d8817e4Smiod 
434*3d8817e4Smiod     case arg_idxr:
435*3d8817e4Smiod       a->scale = 0;
436*3d8817e4Smiod       total_size = a->size + 10;  /* sizeof(rbase + ridx + scl2) = 10.  */
437*3d8817e4Smiod       p = makelongparameter (allWords, inst_bit_size - total_size,
438*3d8817e4Smiod 			     inst_bit_size - (total_size - 4));
439*3d8817e4Smiod       a->r = p.val;
440*3d8817e4Smiod       p = makelongparameter (allWords, inst_bit_size - (total_size - 4),
441*3d8817e4Smiod 			     inst_bit_size - (total_size - 8));
442*3d8817e4Smiod       a->i_r = p.val;
443*3d8817e4Smiod       p = makelongparameter (allWords, inst_bit_size - (total_size - 8),
444*3d8817e4Smiod 			     inst_bit_size - (total_size - 10));
445*3d8817e4Smiod       a->scale = p.val;
446*3d8817e4Smiod       p = makelongparameter (allWords, inst_bit_size - (total_size - 10),
447*3d8817e4Smiod 			     inst_bit_size);
448*3d8817e4Smiod       a->constant = p.val;
449*3d8817e4Smiod       break;
450*3d8817e4Smiod 
451*3d8817e4Smiod     case arg_rbase:
452*3d8817e4Smiod       p = makelongparameter (allWords, inst_bit_size - (start_bits + 4),
453*3d8817e4Smiod 			     inst_bit_size - start_bits);
454*3d8817e4Smiod       a->r = p.val;
455*3d8817e4Smiod       break;
456*3d8817e4Smiod 
457*3d8817e4Smiod     case arg_cr:
458*3d8817e4Smiod       if (a->size <= 8)
459*3d8817e4Smiod         {
460*3d8817e4Smiod           p = makelongparameter (allWords, inst_bit_size - (start_bits + 4),
461*3d8817e4Smiod 				 inst_bit_size - start_bits);
462*3d8817e4Smiod           a->r = p.val;
463*3d8817e4Smiod           /* Case for opc4 r dispu rbase.  */
464*3d8817e4Smiod           p = makelongparameter (allWords, inst_bit_size - (start_bits + 8),
465*3d8817e4Smiod 				 inst_bit_size - (start_bits + 4));
466*3d8817e4Smiod         }
467*3d8817e4Smiod       else
468*3d8817e4Smiod         {
469*3d8817e4Smiod 	  /* The 'rbase' start_bits is always relative to a 32-bit data type.  */
470*3d8817e4Smiod           p = makelongparameter (allWords, 32 - (start_bits + 4),
471*3d8817e4Smiod 				 32 - start_bits);
472*3d8817e4Smiod           a->r = p.val;
473*3d8817e4Smiod           p = makelongparameter (allWords, 32 - start_bits,
474*3d8817e4Smiod 				 inst_bit_size);
475*3d8817e4Smiod         }
476*3d8817e4Smiod       if ((p.nbits == 4) && cst4flag)
477*3d8817e4Smiod         {
478*3d8817e4Smiod           if (instruction->flags & DISPUW4)
479*3d8817e4Smiod 	    p.val *= 2;
480*3d8817e4Smiod           else if (instruction->flags & DISPUD4)
481*3d8817e4Smiod 	    p.val *= 4;
482*3d8817e4Smiod         }
483*3d8817e4Smiod       a->constant = p.val;
484*3d8817e4Smiod       break;
485*3d8817e4Smiod 
486*3d8817e4Smiod     case arg_c:
487*3d8817e4Smiod       p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size),
488*3d8817e4Smiod 			     inst_bit_size - start_bits);
489*3d8817e4Smiod       a->constant = p.val;
490*3d8817e4Smiod       break;
491*3d8817e4Smiod     default:
492*3d8817e4Smiod       break;
493*3d8817e4Smiod     }
494*3d8817e4Smiod }
495*3d8817e4Smiod 
496*3d8817e4Smiod /*  Print a single argument.  */
497*3d8817e4Smiod 
498*3d8817e4Smiod static void
print_arg(argument * a,bfd_vma memaddr,struct disassemble_info * info)499*3d8817e4Smiod print_arg (argument *a, bfd_vma memaddr, struct disassemble_info *info)
500*3d8817e4Smiod {
501*3d8817e4Smiod   LONGLONG longdisp, mask;
502*3d8817e4Smiod   int sign_flag = 0;
503*3d8817e4Smiod   int relative = 0;
504*3d8817e4Smiod   bfd_vma number;
505*3d8817e4Smiod   int op_index = 0;
506*3d8817e4Smiod   char string[200];
507*3d8817e4Smiod   PTR stream = info->stream;
508*3d8817e4Smiod   fprintf_ftype func = info->fprintf_func;
509*3d8817e4Smiod 
510*3d8817e4Smiod   switch (a->type)
511*3d8817e4Smiod     {
512*3d8817e4Smiod     case arg_copr:
513*3d8817e4Smiod       func (stream, "%s", getcopregname (a->cr, CRX_C_REGTYPE));
514*3d8817e4Smiod       break;
515*3d8817e4Smiod 
516*3d8817e4Smiod     case arg_copsr:
517*3d8817e4Smiod       func (stream, "%s", getcopregname (a->cr, CRX_CS_REGTYPE));
518*3d8817e4Smiod       break;
519*3d8817e4Smiod 
520*3d8817e4Smiod     case arg_r:
521*3d8817e4Smiod       if (IS_INSN_MNEMONIC ("mtpr") || IS_INSN_MNEMONIC ("mfpr"))
522*3d8817e4Smiod 	func (stream, "%s", getprocregname (a->r));
523*3d8817e4Smiod       else
524*3d8817e4Smiod 	func (stream, "%s", getregname (a->r));
525*3d8817e4Smiod       break;
526*3d8817e4Smiod 
527*3d8817e4Smiod     case arg_ic:
528*3d8817e4Smiod       if (IS_INSN_MNEMONIC ("excp"))
529*3d8817e4Smiod 	func (stream, "%s", gettrapstring (a->constant));
530*3d8817e4Smiod 
531*3d8817e4Smiod       else if (IS_INSN_MNEMONIC ("cinv"))
532*3d8817e4Smiod 	func (stream, "%s", getcinvstring (a->constant));
533*3d8817e4Smiod 
534*3d8817e4Smiod       else if (INST_HAS_REG_LIST)
535*3d8817e4Smiod         {
536*3d8817e4Smiod 	  REG_ARG_TYPE reg_arg_type = IS_INSN_TYPE (COP_REG_INS) ?
537*3d8817e4Smiod 				 COP_ARG : IS_INSN_TYPE (COPS_REG_INS) ?
538*3d8817e4Smiod 				 COPS_ARG : (instruction->flags & USER_REG) ?
539*3d8817e4Smiod 				 USER_REG_ARG : REG_ARG;
540*3d8817e4Smiod 
541*3d8817e4Smiod           if ((reg_arg_type == COP_ARG) || (reg_arg_type == COPS_ARG))
542*3d8817e4Smiod 	    {
543*3d8817e4Smiod 		/*  Check for proper argument number.  */
544*3d8817e4Smiod 		if (processing_argument_number == 2)
545*3d8817e4Smiod 		  {
546*3d8817e4Smiod 		    getregliststring (a->constant, string, reg_arg_type);
547*3d8817e4Smiod 		    func (stream, "%s", string);
548*3d8817e4Smiod 		  }
549*3d8817e4Smiod 		else
550*3d8817e4Smiod 		  func (stream, "$0x%lx", a->constant);
551*3d8817e4Smiod 	    }
552*3d8817e4Smiod 	  else
553*3d8817e4Smiod             {
554*3d8817e4Smiod               getregliststring (a->constant, string, reg_arg_type);
555*3d8817e4Smiod               func (stream, "%s", string);
556*3d8817e4Smiod             }
557*3d8817e4Smiod         }
558*3d8817e4Smiod       else
559*3d8817e4Smiod 	func (stream, "$0x%lx", a->constant);
560*3d8817e4Smiod       break;
561*3d8817e4Smiod 
562*3d8817e4Smiod     case arg_idxr:
563*3d8817e4Smiod       func (stream, "0x%lx(%s,%s,%d)", a->constant, getregname (a->r),
564*3d8817e4Smiod 	    getregname (a->i_r), powerof2 (a->scale));
565*3d8817e4Smiod       break;
566*3d8817e4Smiod 
567*3d8817e4Smiod     case arg_rbase:
568*3d8817e4Smiod       func (stream, "(%s)", getregname (a->r));
569*3d8817e4Smiod       break;
570*3d8817e4Smiod 
571*3d8817e4Smiod     case arg_cr:
572*3d8817e4Smiod       func (stream, "0x%lx(%s)", a->constant, getregname (a->r));
573*3d8817e4Smiod 
574*3d8817e4Smiod       if (IS_INSN_TYPE (LD_STOR_INS_INC))
575*3d8817e4Smiod 	func (stream, "+");
576*3d8817e4Smiod       break;
577*3d8817e4Smiod 
578*3d8817e4Smiod     case arg_c:
579*3d8817e4Smiod       /* Removed the *2 part as because implicit zeros are no more required.
580*3d8817e4Smiod 	 Have to fix this as this needs a bit of extension in terms of branchins.
581*3d8817e4Smiod 	 Have to add support for cmp and branch instructions.  */
582*3d8817e4Smiod       if (IS_INSN_TYPE (BRANCH_INS) || IS_INSN_MNEMONIC ("bal")
583*3d8817e4Smiod 	  || IS_INSN_TYPE (CMPBR_INS) || IS_INSN_TYPE (DCR_BRANCH_INS)
584*3d8817e4Smiod 	  || IS_INSN_TYPE (COP_BRANCH_INS))
585*3d8817e4Smiod         {
586*3d8817e4Smiod 	  relative = 1;
587*3d8817e4Smiod           longdisp = a->constant;
588*3d8817e4Smiod           longdisp <<= 1;
589*3d8817e4Smiod 
590*3d8817e4Smiod           switch (a->size)
591*3d8817e4Smiod             {
592*3d8817e4Smiod             case 8:
593*3d8817e4Smiod 	    case 16:
594*3d8817e4Smiod 	    case 24:
595*3d8817e4Smiod 	    case 32:
596*3d8817e4Smiod 	      mask = ((LONGLONG)1 << a->size) - 1;
597*3d8817e4Smiod               if (longdisp & ((LONGLONG)1 << a->size))
598*3d8817e4Smiod                 {
599*3d8817e4Smiod                   sign_flag = 1;
600*3d8817e4Smiod                   longdisp = ~(longdisp) + 1;
601*3d8817e4Smiod                 }
602*3d8817e4Smiod               a->constant = (unsigned long int) (longdisp & mask);
603*3d8817e4Smiod               break;
604*3d8817e4Smiod             default:
605*3d8817e4Smiod 	      func (stream,
606*3d8817e4Smiod 		    "Wrong offset used in branch/bal instruction");
607*3d8817e4Smiod               break;
608*3d8817e4Smiod             }
609*3d8817e4Smiod 
610*3d8817e4Smiod         }
611*3d8817e4Smiod       /* For branch Neq instruction it is 2*offset + 2.  */
612*3d8817e4Smiod       else if (IS_INSN_TYPE (BRANCH_NEQ_INS))
613*3d8817e4Smiod 	a->constant = 2 * a->constant + 2;
614*3d8817e4Smiod       else if (IS_INSN_TYPE (LD_STOR_INS_INC)
615*3d8817e4Smiod 	  || IS_INSN_TYPE (LD_STOR_INS)
616*3d8817e4Smiod 	  || IS_INSN_TYPE (STOR_IMM_INS)
617*3d8817e4Smiod 	  || IS_INSN_TYPE (CSTBIT_INS))
618*3d8817e4Smiod         {
619*3d8817e4Smiod           op_index = instruction->flags & REVERSE_MATCH ? 0 : 1;
620*3d8817e4Smiod           if (instruction->operands[op_index].op_type == abs16)
621*3d8817e4Smiod 	    a->constant |= 0xFFFF0000;
622*3d8817e4Smiod         }
623*3d8817e4Smiod       func (stream, "%s", "0x");
624*3d8817e4Smiod       number = (relative ? memaddr : 0)
625*3d8817e4Smiod 	       + (sign_flag ? -a->constant : a->constant);
626*3d8817e4Smiod       (*info->print_address_func) (number, info);
627*3d8817e4Smiod       break;
628*3d8817e4Smiod     default:
629*3d8817e4Smiod       break;
630*3d8817e4Smiod     }
631*3d8817e4Smiod }
632*3d8817e4Smiod 
633*3d8817e4Smiod /* Print all the arguments of CURRINSN instruction.  */
634*3d8817e4Smiod 
635*3d8817e4Smiod static void
print_arguments(ins * currInsn,bfd_vma memaddr,struct disassemble_info * info)636*3d8817e4Smiod print_arguments (ins *currInsn, bfd_vma memaddr, struct disassemble_info *info)
637*3d8817e4Smiod {
638*3d8817e4Smiod   int i;
639*3d8817e4Smiod 
640*3d8817e4Smiod   for (i = 0; i < currInsn->nargs; i++)
641*3d8817e4Smiod     {
642*3d8817e4Smiod       processing_argument_number = i;
643*3d8817e4Smiod 
644*3d8817e4Smiod       print_arg (&currInsn->arg[i], memaddr, info);
645*3d8817e4Smiod 
646*3d8817e4Smiod       if (i != currInsn->nargs - 1)
647*3d8817e4Smiod 	info->fprintf_func (info->stream, ", ");
648*3d8817e4Smiod     }
649*3d8817e4Smiod }
650*3d8817e4Smiod 
651*3d8817e4Smiod /* Build the instruction's arguments.  */
652*3d8817e4Smiod 
653*3d8817e4Smiod static void
make_instruction(void)654*3d8817e4Smiod make_instruction (void)
655*3d8817e4Smiod {
656*3d8817e4Smiod   int i;
657*3d8817e4Smiod   unsigned int shift;
658*3d8817e4Smiod 
659*3d8817e4Smiod   for (i = 0; i < currInsn.nargs; i++)
660*3d8817e4Smiod     {
661*3d8817e4Smiod       argument a;
662*3d8817e4Smiod 
663*3d8817e4Smiod       memset (&a, 0, sizeof (a));
664*3d8817e4Smiod       a.type = getargtype (instruction->operands[i].op_type);
665*3d8817e4Smiod       if (instruction->operands[i].op_type == cst4
666*3d8817e4Smiod 	  || instruction->operands[i].op_type == rbase_dispu4)
667*3d8817e4Smiod 	cst4flag = 1;
668*3d8817e4Smiod       a.size = getbits (instruction->operands[i].op_type);
669*3d8817e4Smiod       shift = instruction->operands[i].shift;
670*3d8817e4Smiod 
671*3d8817e4Smiod       make_argument (&a, shift);
672*3d8817e4Smiod       currInsn.arg[i] = a;
673*3d8817e4Smiod     }
674*3d8817e4Smiod 
675*3d8817e4Smiod   /* Calculate instruction size (in bytes).  */
676*3d8817e4Smiod   currInsn.size = instruction->size + (size_changed ? 1 : 0);
677*3d8817e4Smiod   /* Now in bits.  */
678*3d8817e4Smiod   currInsn.size *= 2;
679*3d8817e4Smiod }
680*3d8817e4Smiod 
681*3d8817e4Smiod /* Retrieve a single word from a given memory address.  */
682*3d8817e4Smiod 
683*3d8817e4Smiod static wordU
get_word_at_PC(bfd_vma memaddr,struct disassemble_info * info)684*3d8817e4Smiod get_word_at_PC (bfd_vma memaddr, struct disassemble_info *info)
685*3d8817e4Smiod {
686*3d8817e4Smiod   bfd_byte buffer[4];
687*3d8817e4Smiod   int status;
688*3d8817e4Smiod   wordU insn = 0;
689*3d8817e4Smiod 
690*3d8817e4Smiod   status = info->read_memory_func (memaddr, buffer, 2, info);
691*3d8817e4Smiod 
692*3d8817e4Smiod   if (status == 0)
693*3d8817e4Smiod     insn = (wordU) bfd_getl16 (buffer);
694*3d8817e4Smiod 
695*3d8817e4Smiod   return insn;
696*3d8817e4Smiod }
697*3d8817e4Smiod 
698*3d8817e4Smiod /* Retrieve multiple words (3) from a given memory address.  */
699*3d8817e4Smiod 
700*3d8817e4Smiod static void
get_words_at_PC(bfd_vma memaddr,struct disassemble_info * info)701*3d8817e4Smiod get_words_at_PC (bfd_vma memaddr, struct disassemble_info *info)
702*3d8817e4Smiod {
703*3d8817e4Smiod   int i;
704*3d8817e4Smiod   bfd_vma mem;
705*3d8817e4Smiod 
706*3d8817e4Smiod   for (i = 0, mem = memaddr; i < 3; i++, mem += 2)
707*3d8817e4Smiod     words[i] = get_word_at_PC (mem, info);
708*3d8817e4Smiod 
709*3d8817e4Smiod   allWords =
710*3d8817e4Smiod     ((ULONGLONG) words[0] << 32) + ((unsigned long) words[1] << 16) + words[2];
711*3d8817e4Smiod }
712*3d8817e4Smiod 
713*3d8817e4Smiod /* Prints the instruction by calling print_arguments after proper matching.  */
714*3d8817e4Smiod 
715*3d8817e4Smiod int
print_insn_crx(memaddr,info)716*3d8817e4Smiod print_insn_crx (memaddr, info)
717*3d8817e4Smiod      bfd_vma memaddr;
718*3d8817e4Smiod      struct disassemble_info *info;
719*3d8817e4Smiod {
720*3d8817e4Smiod   int is_decoded;     /* Nonzero means instruction has a match.  */
721*3d8817e4Smiod 
722*3d8817e4Smiod   /* Initialize global variables.  */
723*3d8817e4Smiod   cst4flag = 0;
724*3d8817e4Smiod   size_changed = 0;
725*3d8817e4Smiod 
726*3d8817e4Smiod   /* Retrieve the encoding from current memory location.  */
727*3d8817e4Smiod   get_words_at_PC (memaddr, info);
728*3d8817e4Smiod   /* Find a matching opcode in table.  */
729*3d8817e4Smiod   is_decoded = match_opcode ();
730*3d8817e4Smiod   /* If found, print the instruction's mnemonic and arguments.  */
731*3d8817e4Smiod   if (is_decoded > 0 && (words[0] << 16 || words[1]) != 0)
732*3d8817e4Smiod     {
733*3d8817e4Smiod       info->fprintf_func (info->stream, "%s", instruction->mnemonic);
734*3d8817e4Smiod       if ((currInsn.nargs = get_number_of_operands ()) != 0)
735*3d8817e4Smiod 	info->fprintf_func (info->stream, "\t");
736*3d8817e4Smiod       make_instruction ();
737*3d8817e4Smiod       print_arguments (&currInsn, memaddr, info);
738*3d8817e4Smiod       return currInsn.size;
739*3d8817e4Smiod     }
740*3d8817e4Smiod 
741*3d8817e4Smiod   /* No match found.  */
742*3d8817e4Smiod   info->fprintf_func (info->stream,"%s ",ILLEGAL);
743*3d8817e4Smiod   return 2;
744*3d8817e4Smiod }
745