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