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