|  | /* Disassembler code for CRX. | 
|  | Copyright (C) 2004-2023 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; | 
|  | } |