| /* Disassembler code for CRX. | 
 |    Copyright (C) 2004-2024 Free Software Foundation, Inc. | 
 |    Contributed by Tomer Levi, NSC, Israel. | 
 |    Written by Tomer Levi. | 
 |  | 
 |    This file is part of the GNU opcodes library. | 
 |  | 
 |    This library is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3, or (at your option) | 
 |    any later version. | 
 |  | 
 |    It is distributed in the hope that it will be useful, but WITHOUT | 
 |    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | 
 |    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public | 
 |    License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program; if not, write to the Free Software | 
 |    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, | 
 |    MA 02110-1301, USA.  */ | 
 |  | 
 | #include "sysdep.h" | 
 | #include "disassemble.h" | 
 | #include "opcode/crx.h" | 
 |  | 
 | /* String to print when opcode was not matched.  */ | 
 | #define ILLEGAL	"illegal" | 
 |   /* Escape to 16-bit immediate.  */ | 
 | #define ESCAPE_16_BIT  0xE | 
 |  | 
 | /* Extract 'n_bits' from 'a' starting from offset 'offs'.  */ | 
 | #define EXTRACT(a, offs, n_bits)	    \ | 
 |   (((a) >> (offs)) & ((2ull << (n_bits - 1)) - 1)) | 
 |  | 
 | /* Set Bit Mask - a mask to set all bits starting from offset 'offs'.  */ | 
 | #define SBM(offs)  ((-1u << (offs)) & 0xffffffff) | 
 |  | 
 | typedef unsigned long dwordU; | 
 | typedef unsigned short wordU; | 
 |  | 
 | typedef struct | 
 | { | 
 |   dwordU val; | 
 |   int nbits; | 
 | } parameter; | 
 |  | 
 | /* Structure to hold valid 'cinv' instruction options.  */ | 
 |  | 
 | typedef struct | 
 |   { | 
 |     /* Cinv printed string.  */ | 
 |     char *str; | 
 |     /* Value corresponding to the string.  */ | 
 |     unsigned int value; | 
 |   } | 
 | cinv_entry; | 
 |  | 
 | /* CRX 'cinv' options.  */ | 
 | static const cinv_entry crx_cinvs[] = | 
 | { | 
 |   {"[i]", 2}, {"[i,u]", 3}, {"[d]", 4}, {"[d,u]", 5}, | 
 |   {"[d,i]", 6}, {"[d,i,u]", 7}, {"[b]", 8}, | 
 |   {"[b,i]", 10}, {"[b,i,u]", 11}, {"[b,d]", 12}, | 
 |   {"[b,d,u]", 13}, {"[b,d,i]", 14}, {"[b,d,i,u]", 15} | 
 | }; | 
 |  | 
 | /* Enum to distinguish different registers argument types.  */ | 
 | typedef enum REG_ARG_TYPE | 
 |   { | 
 |     /* General purpose register (r<N>).  */ | 
 |     REG_ARG = 0, | 
 |     /* User register (u<N>).  */ | 
 |     USER_REG_ARG, | 
 |     /* CO-Processor register (c<N>).  */ | 
 |     COP_ARG, | 
 |     /* CO-Processor special register (cs<N>).  */ | 
 |     COPS_ARG | 
 |   } | 
 | REG_ARG_TYPE; | 
 |  | 
 | /* Number of valid 'cinv' instruction options.  */ | 
 | static int NUMCINVS = ((sizeof crx_cinvs)/(sizeof crx_cinvs[0])); | 
 | /* Current opcode table entry we're disassembling.  */ | 
 | static const inst *instruction; | 
 | /* Current instruction we're disassembling.  */ | 
 | static ins currInsn; | 
 | /* The current instruction is read into 3 consecutive words.  */ | 
 | static wordU words[3]; | 
 | /* Contains all words in appropriate order.  */ | 
 | static ULONGLONG allWords; | 
 | /* Holds the current processed argument number.  */ | 
 | static int processing_argument_number; | 
 | /* Nonzero means a CST4 instruction.  */ | 
 | static int cst4flag; | 
 | /* Nonzero means the instruction's original size is | 
 |    incremented (escape sequence is used).  */ | 
 | static int size_changed; | 
 |  | 
 |  | 
 | /* Retrieve the number of operands for the current assembled instruction.  */ | 
 |  | 
 | static int | 
 | get_number_of_operands (void) | 
 | { | 
 |   int i; | 
 |  | 
 |   for (i = 0; i < MAX_OPERANDS && instruction->operands[i].op_type; i++) | 
 |     ; | 
 |  | 
 |   return i; | 
 | } | 
 |  | 
 | /* Return the bit size for a given operand.  */ | 
 |  | 
 | static int | 
 | getbits (operand_type op) | 
 | { | 
 |   if (op < MAX_OPRD) | 
 |     return crx_optab[op].bit_size; | 
 |   else | 
 |     return 0; | 
 | } | 
 |  | 
 | /* Return the argument type of a given operand.  */ | 
 |  | 
 | static argtype | 
 | getargtype (operand_type op) | 
 | { | 
 |   if (op < MAX_OPRD) | 
 |     return crx_optab[op].arg_type; | 
 |   else | 
 |     return nullargs; | 
 | } | 
 |  | 
 | /* Given the trap index in dispatch table, return its name. | 
 |    This routine is used when disassembling the 'excp' instruction.  */ | 
 |  | 
 | static char * | 
 | gettrapstring (unsigned int trap_index) | 
 | { | 
 |   const trap_entry *trap; | 
 |  | 
 |   for (trap = crx_traps; trap < crx_traps + NUMTRAPS; trap++) | 
 |     if (trap->entry == trap_index) | 
 |       return trap->name; | 
 |  | 
 |   return ILLEGAL; | 
 | } | 
 |  | 
 | /* Given a 'cinv' instruction constant operand, return its corresponding string. | 
 |    This routine is used when disassembling the 'cinv' instruction.  */ | 
 |  | 
 | static char * | 
 | getcinvstring (unsigned int num) | 
 | { | 
 |   const cinv_entry *cinv; | 
 |  | 
 |   for (cinv = crx_cinvs; cinv < (crx_cinvs + NUMCINVS); cinv++) | 
 |     if (cinv->value == num) | 
 |       return cinv->str; | 
 |  | 
 |   return ILLEGAL; | 
 | } | 
 |  | 
 | /* Given a register enum value, retrieve its name.  */ | 
 |  | 
 | static char * | 
 | getregname (reg r) | 
 | { | 
 |   const reg_entry * regentry = &crx_regtab[r]; | 
 |  | 
 |   if (regentry->type != CRX_R_REGTYPE) | 
 |     return ILLEGAL; | 
 |   else | 
 |     return regentry->name; | 
 | } | 
 |  | 
 | /* Given a coprocessor register enum value, retrieve its name.  */ | 
 |  | 
 | static char * | 
 | getcopregname (copreg r, reg_type type) | 
 | { | 
 |   const reg_entry * regentry; | 
 |  | 
 |   if (type == CRX_C_REGTYPE) | 
 |     regentry = &crx_copregtab[r]; | 
 |   else if (type == CRX_CS_REGTYPE) | 
 |     regentry = &crx_copregtab[r+(cs0-c0)]; | 
 |   else | 
 |     return ILLEGAL; | 
 |  | 
 |   return regentry->name; | 
 | } | 
 |  | 
 |  | 
 | /* Getting a processor register name.  */ | 
 |  | 
 | static char * | 
 | getprocregname (int reg_index) | 
 | { | 
 |   const reg_entry *r; | 
 |  | 
 |   for (r = crx_regtab; r < crx_regtab + NUMREGS; r++) | 
 |     if (r->image == reg_index) | 
 |       return r->name; | 
 |  | 
 |   return "ILLEGAL REGISTER"; | 
 | } | 
 |  | 
 | /* Get the power of two for a given integer.  */ | 
 |  | 
 | static int | 
 | powerof2 (int x) | 
 | { | 
 |   int product, i; | 
 |  | 
 |   for (i = 0, product = 1; i < x; i++) | 
 |     product *= 2; | 
 |  | 
 |   return product; | 
 | } | 
 |  | 
 | /* Transform a register bit mask to a register list.  */ | 
 |  | 
 | static void | 
 | getregliststring (int mask, char *string, enum REG_ARG_TYPE core_cop) | 
 | { | 
 |   char temp_string[16]; | 
 |   int i; | 
 |  | 
 |   string[0] = '{'; | 
 |   string[1] = '\0'; | 
 |  | 
 |  | 
 |   /* A zero mask means HI/LO registers.  */ | 
 |   if (mask == 0) | 
 |     { | 
 |       if (core_cop == USER_REG_ARG) | 
 | 	strcat (string, "ulo,uhi"); | 
 |       else | 
 | 	strcat (string, "lo,hi"); | 
 |     } | 
 |   else | 
 |     { | 
 |       for (i = 0; i < 16; i++) | 
 | 	{ | 
 | 	  if (mask & 0x1) | 
 | 	    { | 
 | 	      switch (core_cop) | 
 | 	      { | 
 | 	      case REG_ARG: | 
 | 		sprintf (temp_string, "r%d", i); | 
 | 		break; | 
 | 	      case USER_REG_ARG: | 
 | 		sprintf (temp_string, "u%d", i); | 
 | 		break; | 
 | 	      case COP_ARG: | 
 | 		sprintf (temp_string, "c%d", i); | 
 | 		break; | 
 | 	      case COPS_ARG: | 
 | 		sprintf (temp_string, "cs%d", i); | 
 | 		break; | 
 | 	      default: | 
 | 		break; | 
 | 	      } | 
 | 	      strcat (string, temp_string); | 
 | 	      if (mask & 0xfffe) | 
 | 		strcat (string, ","); | 
 | 	    } | 
 | 	  mask >>= 1; | 
 | 	} | 
 |     } | 
 |  | 
 |   strcat (string, "}"); | 
 | } | 
 |  | 
 | /* START and END are relating 'allWords' struct, which is 48 bits size. | 
 |  | 
 | 			  START|--------|END | 
 | 	    +---------+---------+---------+---------+ | 
 | 	    |	      |	   V    |     A	  |   L	    | | 
 | 	    +---------+---------+---------+---------+ | 
 | 	    	      0		16	  32	    48 | 
 |     words		  [0]	    [1]	      [2]	*/ | 
 |  | 
 | static parameter | 
 | makelongparameter (ULONGLONG val, int start, int end) | 
 | { | 
 |   parameter p; | 
 |  | 
 |   p.val = (dwordU) EXTRACT(val, 48 - end, end - start); | 
 |   p.nbits = end - start; | 
 |   return p; | 
 | } | 
 |  | 
 | /* Build a mask of the instruction's 'constant' opcode, | 
 |    based on the instruction's printing flags.  */ | 
 |  | 
 | static unsigned int | 
 | build_mask (void) | 
 | { | 
 |   unsigned int print_flags; | 
 |   unsigned int mask; | 
 |  | 
 |   print_flags = instruction->flags & FMT_CRX; | 
 |   switch (print_flags) | 
 |     { | 
 |       case FMT_1: | 
 | 	mask = 0xF0F00000; | 
 | 	break; | 
 |       case FMT_2: | 
 | 	mask = 0xFFF0FF00; | 
 | 	break; | 
 |       case FMT_3: | 
 | 	mask = 0xFFF00F00; | 
 | 	break; | 
 |       case FMT_4: | 
 | 	mask = 0xFFF0F000; | 
 | 	break; | 
 |       case FMT_5: | 
 | 	mask = 0xFFF0FFF0; | 
 | 	break; | 
 |       default: | 
 | 	mask = SBM(instruction->match_bits); | 
 | 	break; | 
 |     } | 
 |  | 
 |   return mask; | 
 | } | 
 |  | 
 | /* Search for a matching opcode. Return 1 for success, 0 for failure.  */ | 
 |  | 
 | static int | 
 | match_opcode (void) | 
 | { | 
 |   unsigned int mask; | 
 |  | 
 |   /* The instruction 'constant' opcode doewsn't exceed 32 bits.  */ | 
 |   unsigned int doubleWord = words[1] + ((unsigned) words[0] << 16); | 
 |  | 
 |   /* Start searching from end of instruction table.  */ | 
 |   instruction = &crx_instruction[NUMOPCODES - 2]; | 
 |  | 
 |   /* Loop over instruction table until a full match is found.  */ | 
 |   while (instruction >= crx_instruction) | 
 |     { | 
 |       mask = build_mask (); | 
 |       if ((doubleWord & mask) == BIN(instruction->match, instruction->match_bits)) | 
 | 	return 1; | 
 |       else | 
 | 	instruction--; | 
 |     } | 
 |   return 0; | 
 | } | 
 |  | 
 | /* Set the proper parameter value for different type of arguments.  */ | 
 |  | 
 | static void | 
 | make_argument (argument * a, int start_bits) | 
 | { | 
 |   int inst_bit_size, total_size; | 
 |   parameter p; | 
 |  | 
 |   if ((instruction->size == 3) && a->size >= 16) | 
 |     inst_bit_size = 48; | 
 |   else | 
 |     inst_bit_size = 32; | 
 |  | 
 |   switch (a->type) | 
 |     { | 
 |     case arg_copr: | 
 |     case arg_copsr: | 
 |       p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size), | 
 | 			     inst_bit_size - start_bits); | 
 |       a->cr = p.val; | 
 |       break; | 
 |  | 
 |     case arg_r: | 
 |       p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size), | 
 | 			     inst_bit_size - start_bits); | 
 |       a->r = p.val; | 
 |       break; | 
 |  | 
 |     case arg_ic: | 
 |       p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size), | 
 | 			     inst_bit_size - start_bits); | 
 |  | 
 |       if ((p.nbits == 4) && cst4flag) | 
 | 	{ | 
 | 	  if (IS_INSN_TYPE (CMPBR_INS) && (p.val == ESCAPE_16_BIT)) | 
 | 	    { | 
 | 	      /* A special case, where the value is actually stored | 
 | 		 in the last 4 bits.  */ | 
 | 	      p = makelongparameter (allWords, 44, 48); | 
 | 	      /* The size of the instruction should be incremented.  */ | 
 | 	      size_changed = 1; | 
 | 	    } | 
 |  | 
 | 	  if (p.val == 6) | 
 | 	    p.val = -1; | 
 | 	  else if (p.val == 13) | 
 | 	    p.val = 48; | 
 | 	  else if (p.val == 5) | 
 | 	    p.val = -4; | 
 | 	  else if (p.val == 10) | 
 | 	    p.val = 32; | 
 | 	  else if (p.val == 11) | 
 | 	    p.val = 20; | 
 | 	  else if (p.val == 9) | 
 | 	    p.val = 16; | 
 | 	} | 
 |  | 
 |       a->constant = p.val; | 
 |       break; | 
 |  | 
 |     case arg_idxr: | 
 |       a->scale = 0; | 
 |       total_size = a->size + 10;  /* sizeof(rbase + ridx + scl2) = 10.  */ | 
 |       p = makelongparameter (allWords, inst_bit_size - total_size, | 
 | 			     inst_bit_size - (total_size - 4)); | 
 |       a->r = p.val; | 
 |       p = makelongparameter (allWords, inst_bit_size - (total_size - 4), | 
 | 			     inst_bit_size - (total_size - 8)); | 
 |       a->i_r = p.val; | 
 |       p = makelongparameter (allWords, inst_bit_size - (total_size - 8), | 
 | 			     inst_bit_size - (total_size - 10)); | 
 |       a->scale = p.val; | 
 |       p = makelongparameter (allWords, inst_bit_size - (total_size - 10), | 
 | 			     inst_bit_size); | 
 |       a->constant = p.val; | 
 |       break; | 
 |  | 
 |     case arg_rbase: | 
 |       p = makelongparameter (allWords, inst_bit_size - (start_bits + 4), | 
 | 			     inst_bit_size - start_bits); | 
 |       a->r = p.val; | 
 |       break; | 
 |  | 
 |     case arg_cr: | 
 |       if (a->size <= 8) | 
 | 	{ | 
 | 	  p = makelongparameter (allWords, inst_bit_size - (start_bits + 4), | 
 | 				 inst_bit_size - start_bits); | 
 | 	  a->r = p.val; | 
 | 	  /* Case for opc4 r dispu rbase.  */ | 
 | 	  p = makelongparameter (allWords, inst_bit_size - (start_bits + 8), | 
 | 				 inst_bit_size - (start_bits + 4)); | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* The 'rbase' start_bits is always relative to a 32-bit data type.  */ | 
 | 	  p = makelongparameter (allWords, 32 - (start_bits + 4), | 
 | 				 32 - start_bits); | 
 | 	  a->r = p.val; | 
 | 	  p = makelongparameter (allWords, 32 - start_bits, | 
 | 				 inst_bit_size); | 
 | 	} | 
 |       if ((p.nbits == 4) && cst4flag) | 
 | 	{ | 
 | 	  if (instruction->flags & DISPUW4) | 
 | 	    p.val *= 2; | 
 | 	  else if (instruction->flags & DISPUD4) | 
 | 	    p.val *= 4; | 
 | 	} | 
 |       a->constant = p.val; | 
 |       break; | 
 |  | 
 |     case arg_c: | 
 |       p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size), | 
 | 			     inst_bit_size - start_bits); | 
 |       a->constant = p.val; | 
 |       break; | 
 |     default: | 
 |       break; | 
 |     } | 
 | } | 
 |  | 
 | /*  Print a single argument.  */ | 
 |  | 
 | static void | 
 | print_arg (argument *a, bfd_vma memaddr, struct disassemble_info *info) | 
 | { | 
 |   ULONGLONG longdisp, mask; | 
 |   int sign_flag = 0; | 
 |   int relative = 0; | 
 |   bfd_vma number; | 
 |   int op_index = 0; | 
 |   char string[200]; | 
 |   void *stream = info->stream; | 
 |   fprintf_ftype func = info->fprintf_func; | 
 |  | 
 |   switch (a->type) | 
 |     { | 
 |     case arg_copr: | 
 |       func (stream, "%s", getcopregname (a->cr, CRX_C_REGTYPE)); | 
 |       break; | 
 |  | 
 |     case arg_copsr: | 
 |       func (stream, "%s", getcopregname (a->cr, CRX_CS_REGTYPE)); | 
 |       break; | 
 |  | 
 |     case arg_r: | 
 |       if (IS_INSN_MNEMONIC ("mtpr") || IS_INSN_MNEMONIC ("mfpr")) | 
 | 	func (stream, "%s", getprocregname (a->r)); | 
 |       else | 
 | 	func (stream, "%s", getregname (a->r)); | 
 |       break; | 
 |  | 
 |     case arg_ic: | 
 |       if (IS_INSN_MNEMONIC ("excp")) | 
 | 	func (stream, "%s", gettrapstring (a->constant)); | 
 |  | 
 |       else if (IS_INSN_MNEMONIC ("cinv")) | 
 | 	func (stream, "%s", getcinvstring (a->constant)); | 
 |  | 
 |       else if (INST_HAS_REG_LIST) | 
 | 	{ | 
 | 	  REG_ARG_TYPE reg_arg_type = IS_INSN_TYPE (COP_REG_INS) ? | 
 | 	    COP_ARG : IS_INSN_TYPE (COPS_REG_INS) ? | 
 | 	    COPS_ARG : (instruction->flags & USER_REG) ? | 
 | 	    USER_REG_ARG : REG_ARG; | 
 |  | 
 | 	  if ((reg_arg_type == COP_ARG) || (reg_arg_type == COPS_ARG)) | 
 | 	    { | 
 | 	      /*  Check for proper argument number.  */ | 
 | 	      if (processing_argument_number == 2) | 
 | 		{ | 
 | 		  getregliststring (a->constant, string, reg_arg_type); | 
 | 		  func (stream, "%s", string); | 
 | 		} | 
 | 	      else | 
 | 		func (stream, "$0x%lx", a->constant & 0xffffffff); | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      getregliststring (a->constant, string, reg_arg_type); | 
 | 	      func (stream, "%s", string); | 
 | 	    } | 
 | 	} | 
 |       else | 
 | 	func (stream, "$0x%lx", a->constant & 0xffffffff); | 
 |       break; | 
 |  | 
 |     case arg_idxr: | 
 |       func (stream, "0x%lx(%s,%s,%d)", a->constant & 0xffffffff, | 
 | 	    getregname (a->r), getregname (a->i_r), powerof2 (a->scale)); | 
 |       break; | 
 |  | 
 |     case arg_rbase: | 
 |       func (stream, "(%s)", getregname (a->r)); | 
 |       break; | 
 |  | 
 |     case arg_cr: | 
 |       func (stream, "0x%lx(%s)", a->constant & 0xffffffff, getregname (a->r)); | 
 |  | 
 |       if (IS_INSN_TYPE (LD_STOR_INS_INC)) | 
 | 	func (stream, "+"); | 
 |       break; | 
 |  | 
 |     case arg_c: | 
 |       /* Removed the *2 part as because implicit zeros are no more required. | 
 | 	 Have to fix this as this needs a bit of extension in terms of branchins. | 
 | 	 Have to add support for cmp and branch instructions.  */ | 
 |       if (IS_INSN_TYPE (BRANCH_INS) || IS_INSN_MNEMONIC ("bal") | 
 | 	  || IS_INSN_TYPE (CMPBR_INS) || IS_INSN_TYPE (DCR_BRANCH_INS) | 
 | 	  || IS_INSN_TYPE (COP_BRANCH_INS)) | 
 | 	{ | 
 | 	  relative = 1; | 
 | 	  longdisp = a->constant; | 
 | 	  longdisp <<= 1; | 
 |  | 
 | 	  switch (a->size) | 
 | 	    { | 
 | 	    case 8: | 
 | 	    case 16: | 
 | 	    case 24: | 
 | 	    case 32: | 
 | 	      mask = ((LONGLONG) 1 << a->size) - 1; | 
 | 	      if (longdisp & ((ULONGLONG) 1 << a->size)) | 
 | 		{ | 
 | 		  sign_flag = 1; | 
 | 		  longdisp = ~(longdisp) + 1; | 
 | 		} | 
 | 	      a->constant = (unsigned long int) (longdisp & mask); | 
 | 	      break; | 
 | 	    default: | 
 | 	      func (stream, | 
 | 		    "Wrong offset used in branch/bal instruction"); | 
 | 	      break; | 
 | 	    } | 
 |  | 
 | 	} | 
 |       /* For branch Neq instruction it is 2*offset + 2.  */ | 
 |       else if (IS_INSN_TYPE (BRANCH_NEQ_INS)) | 
 | 	a->constant = 2 * a->constant + 2; | 
 |       else if (IS_INSN_TYPE (LD_STOR_INS_INC) | 
 | 	       || IS_INSN_TYPE (LD_STOR_INS) | 
 | 	       || IS_INSN_TYPE (STOR_IMM_INS) | 
 | 	       || IS_INSN_TYPE (CSTBIT_INS)) | 
 | 	{ | 
 | 	  op_index = instruction->flags & REVERSE_MATCH ? 0 : 1; | 
 | 	  if (instruction->operands[op_index].op_type == abs16) | 
 | 	    a->constant |= 0xFFFF0000; | 
 | 	} | 
 |       func (stream, "%s", "0x"); | 
 |       number = (relative ? memaddr : 0) | 
 | 	+ (sign_flag ? -a->constant : a->constant); | 
 |       (*info->print_address_func) (number, info); | 
 |       break; | 
 |     default: | 
 |       break; | 
 |     } | 
 | } | 
 |  | 
 | /* Print all the arguments of CURRINSN instruction.  */ | 
 |  | 
 | static void | 
 | print_arguments (ins *currentInsn, bfd_vma memaddr, struct disassemble_info *info) | 
 | { | 
 |   int i; | 
 |  | 
 |   for (i = 0; i < currentInsn->nargs; i++) | 
 |     { | 
 |       processing_argument_number = i; | 
 |  | 
 |       print_arg (¤tInsn->arg[i], memaddr, info); | 
 |  | 
 |       if (i != currentInsn->nargs - 1) | 
 | 	info->fprintf_func (info->stream, ", "); | 
 |     } | 
 | } | 
 |  | 
 | /* Build the instruction's arguments.  */ | 
 |  | 
 | static void | 
 | make_instruction (void) | 
 | { | 
 |   int i; | 
 |   unsigned int shift; | 
 |  | 
 |   for (i = 0; i < currInsn.nargs; i++) | 
 |     { | 
 |       argument a; | 
 |  | 
 |       memset (&a, 0, sizeof (a)); | 
 |       a.type = getargtype (instruction->operands[i].op_type); | 
 |       if (instruction->operands[i].op_type == cst4 | 
 | 	  || instruction->operands[i].op_type == rbase_dispu4) | 
 | 	cst4flag = 1; | 
 |       a.size = getbits (instruction->operands[i].op_type); | 
 |       shift = instruction->operands[i].shift; | 
 |  | 
 |       make_argument (&a, shift); | 
 |       currInsn.arg[i] = a; | 
 |     } | 
 |  | 
 |   /* Calculate instruction size (in bytes).  */ | 
 |   currInsn.size = instruction->size + (size_changed ? 1 : 0); | 
 |   /* Now in bits.  */ | 
 |   currInsn.size *= 2; | 
 | } | 
 |  | 
 | /* Retrieve a single word from a given memory address.  */ | 
 |  | 
 | static wordU | 
 | get_word_at_PC (bfd_vma memaddr, struct disassemble_info *info) | 
 | { | 
 |   bfd_byte buffer[4]; | 
 |   int status; | 
 |   wordU insn = 0; | 
 |  | 
 |   status = info->read_memory_func (memaddr, buffer, 2, info); | 
 |  | 
 |   if (status == 0) | 
 |     insn = (wordU) bfd_getl16 (buffer); | 
 |  | 
 |   return insn; | 
 | } | 
 |  | 
 | /* Retrieve multiple words (3) from a given memory address.  */ | 
 |  | 
 | static void | 
 | get_words_at_PC (bfd_vma memaddr, struct disassemble_info *info) | 
 | { | 
 |   int i; | 
 |   bfd_vma mem; | 
 |  | 
 |   for (i = 0, mem = memaddr; i < 3; i++, mem += 2) | 
 |     words[i] = get_word_at_PC (mem, info); | 
 |  | 
 |   allWords = | 
 |     ((ULONGLONG) words[0] << 32) + ((unsigned long) words[1] << 16) + words[2]; | 
 | } | 
 |  | 
 | /* Prints the instruction by calling print_arguments after proper matching.  */ | 
 |  | 
 | int | 
 | print_insn_crx (bfd_vma memaddr, struct disassemble_info *info) | 
 | { | 
 |   int is_decoded;     /* Nonzero means instruction has a match.  */ | 
 |  | 
 |   /* Initialize global variables.  */ | 
 |   cst4flag = 0; | 
 |   size_changed = 0; | 
 |  | 
 |   /* Retrieve the encoding from current memory location.  */ | 
 |   get_words_at_PC (memaddr, info); | 
 |   /* Find a matching opcode in table.  */ | 
 |   is_decoded = match_opcode (); | 
 |   /* If found, print the instruction's mnemonic and arguments.  */ | 
 |   if (is_decoded > 0 && (words[0] != 0 || words[1] != 0)) | 
 |     { | 
 |       info->fprintf_func (info->stream, "%s", instruction->mnemonic); | 
 |       if ((currInsn.nargs = get_number_of_operands ()) != 0) | 
 | 	info->fprintf_func (info->stream, "\t"); | 
 |       make_instruction (); | 
 |       print_arguments (&currInsn, memaddr, info); | 
 |       return currInsn.size; | 
 |     } | 
 |  | 
 |   /* No match found.  */ | 
 |   info->fprintf_func (info->stream,"%s ",ILLEGAL); | 
 |   return 2; | 
 | } |