1/* Instruction printing code for Score 2 Copyright 2006 Free Software Foundation, Inc. 3 Contributed by: 4 Mei Ligang (ligang@sunnorth.com.cn) 5 Pei-Lin Tsai (pltsai@sunplus.com) 6 7 This file is part of libopcodes. 8 9 This program is free software; you can redistribute it and/or modify it under 10 the terms of the GNU General Public License as published by the Free 11 Software Foundation; either version 2 of the License, or (at your option) 12 any later version. 13 14 This program is distributed in the hope that it will be useful, but WITHOUT 15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 17 more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 22 02110-1301, USA. */ 23 24#include "sysdep.h" 25#include "dis-asm.h" 26#define DEFINE_TABLE 27#include "score-opc.h" 28#include "opintl.h" 29#include "bfd.h" 30 31/* FIXME: This shouldn't be done here. */ 32#include "elf-bfd.h" 33#include "elf/internal.h" 34#include "elf/score.h" 35 36#ifndef streq 37#define streq(a,b) (strcmp ((a), (b)) == 0) 38#endif 39 40#ifndef strneq 41#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0) 42#endif 43 44#ifndef NUM_ELEM 45#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0]) 46#endif 47 48typedef struct 49{ 50 const char *name; 51 const char *description; 52 const char *reg_names[32]; 53} score_regname; 54 55static score_regname regnames[] = 56{ 57 {"gcc", "Select register names used by GCC", 58 {"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", 59 "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", 60 "r21", "r22", "r23", "r24", "r25", "r26", "r27", "gp", "r29", "r30", "r31"}}, 61}; 62 63static unsigned int regname_selected = 0; 64 65#define NUM_SCORE_REGNAMES NUM_ELEM (regnames) 66#define score_regnames regnames[regname_selected].reg_names 67 68/* Print one instruction from PC on INFO->STREAM. 69 Return the size of the instruction. */ 70static int 71print_insn_score32 (bfd_vma pc, struct disassemble_info *info, long given) 72{ 73 struct score_opcode *insn; 74 void *stream = info->stream; 75 fprintf_ftype func = info->fprintf_func; 76 77 for (insn = score_opcodes; insn->assembler; insn++) 78 { 79 if ((insn->mask & 0xffff0000) && (given & insn->mask) == insn->value) 80 { 81 char *c; 82 83 for (c = insn->assembler; *c; c++) 84 { 85 if (*c == '%') 86 { 87 switch (*++c) 88 { 89 case 'j': 90 { 91 int target; 92 93 if (info->flags & INSN_HAS_RELOC) 94 pc = 0; 95 target = (pc & 0xfe000000) | (given & 0x01fffffe); 96 (*info->print_address_func) (target, info); 97 } 98 break; 99 case 'b': 100 { 101 /* Sign-extend a 20-bit number. */ 102#define SEXT20(x) ((((x) & 0xfffff) ^ (~ 0x7ffff)) + 0x80000) 103 int disp = ((given & 0x01ff8000) >> 5) | (given & 0x3fe); 104 int target = (pc + SEXT20 (disp)); 105 106 (*info->print_address_func) (target, info); 107 } 108 break; 109 case '0': 110 case '1': 111 case '2': 112 case '3': 113 case '4': 114 case '5': 115 case '6': 116 case '7': 117 case '8': 118 case '9': 119 { 120 int bitstart = *c++ - '0'; 121 int bitend = 0; 122 123 while (*c >= '0' && *c <= '9') 124 bitstart = (bitstart * 10) + *c++ - '0'; 125 126 switch (*c) 127 { 128 case '-': 129 c++; 130 while (*c >= '0' && *c <= '9') 131 bitend = (bitend * 10) + *c++ - '0'; 132 133 if (!bitend) 134 abort (); 135 136 switch (*c) 137 { 138 case 'r': 139 { 140 long reg; 141 142 reg = given >> bitstart; 143 reg &= (2 << (bitend - bitstart)) - 1; 144 145 func (stream, "%s", score_regnames[reg]); 146 } 147 break; 148 case 'd': 149 { 150 long reg; 151 152 reg = given >> bitstart; 153 reg &= (2 << (bitend - bitstart)) - 1; 154 155 func (stream, "%ld", reg); 156 } 157 break; 158 case 'i': 159 { 160 long reg; 161 162 reg = given >> bitstart; 163 reg &= (2 << (bitend - bitstart)) - 1; 164 reg = ((reg ^ (1 << (bitend - bitstart))) - 165 (1 << (bitend - bitstart))); 166 167 if (((given & insn->mask) == 0x0c00000a) /* ldc1 */ 168 || ((given & insn->mask) == 0x0c000012) /* ldc2 */ 169 || ((given & insn->mask) == 0x0c00001c) /* ldc3 */ 170 || ((given & insn->mask) == 0x0c00000b) /* stc1 */ 171 || ((given & insn->mask) == 0x0c000013) /* stc2 */ 172 || ((given & insn->mask) == 0x0c00001b)) /* stc3 */ 173 reg <<= 2; 174 175 func (stream, "%ld", reg); 176 } 177 break; 178 case 'x': 179 { 180 long reg; 181 182 reg = given >> bitstart; 183 reg &= (2 << (bitend - bitstart)) - 1; 184 185 func (stream, "%lx", reg); 186 } 187 break; 188 default: 189 abort (); 190 } 191 break; 192 case '`': 193 c++; 194 if ((given & (1 << bitstart)) == 0) 195 func (stream, "%c", *c); 196 break; 197 case '\'': 198 c++; 199 if ((given & (1 << bitstart)) != 0) 200 func (stream, "%c", *c); 201 break; 202 default: 203 abort (); 204 } 205 break; 206 207 default: 208 abort (); 209 } 210 } 211 } 212 else 213 func (stream, "%c", *c); 214 } 215 return 4; 216 } 217 } 218 219#if (SCORE_SIMULATOR_ACTIVE) 220 func (stream, _("<illegal instruction>")); 221 return 4; 222#endif 223 224 abort (); 225} 226 227static void 228print_insn_parallel_sym (struct disassemble_info *info) 229{ 230 void *stream = info->stream; 231 fprintf_ftype func = info->fprintf_func; 232 233 /* 10: 0000 nop! 234 4 space + 1 colon + 1 space + 1 tab + 8 opcode + 2 space + 1 tab. 235 FIXME: the space number is not accurate. */ 236 func (stream, "%s", " ||\n \t \t"); 237} 238 239/* Print one instruction from PC on INFO->STREAM. 240 Return the size of the instruction. */ 241static int 242print_insn_score16 (bfd_vma pc, struct disassemble_info *info, long given) 243{ 244 struct score_opcode *insn; 245 void *stream = info->stream; 246 fprintf_ftype func = info->fprintf_func; 247 248 given &= 0xffff; 249 for (insn = score_opcodes; insn->assembler; insn++) 250 { 251 if (!(insn->mask & 0xffff0000) && (given & insn->mask) == insn->value) 252 { 253 char *c = insn->assembler; 254 255 info->bytes_per_chunk = 2; 256 info->bytes_per_line = 4; 257 given &= 0xffff; 258 259 for (; *c; c++) 260 { 261 if (*c == '%') 262 { 263 switch (*++c) 264 { 265 266 case 'j': 267 { 268 int target; 269 270 if (info->flags & INSN_HAS_RELOC) 271 pc = 0; 272 273 target = (pc & 0xfffff000) | (given & 0x00000ffe); 274 (*info->print_address_func) (target, info); 275 } 276 break; 277 case 'b': 278 { 279 /* Sign-extend a 9-bit number. */ 280#define SEXT9(x) ((((x) & 0x1ff) ^ (~ 0xff)) + 0x100) 281 int disp = (given & 0xff) << 1; 282 int target = (pc + SEXT9 (disp)); 283 284 (*info->print_address_func) (target, info); 285 } 286 break; 287 288 case '0': 289 case '1': 290 case '2': 291 case '3': 292 case '4': 293 case '5': 294 case '6': 295 case '7': 296 case '8': 297 case '9': 298 { 299 int bitstart = *c++ - '0'; 300 int bitend = 0; 301 302 while (*c >= '0' && *c <= '9') 303 bitstart = (bitstart * 10) + *c++ - '0'; 304 305 switch (*c) 306 { 307 case '-': 308 { 309 long reg; 310 311 c++; 312 while (*c >= '0' && *c <= '9') 313 bitend = (bitend * 10) + *c++ - '0'; 314 if (!bitend) 315 abort (); 316 reg = given >> bitstart; 317 reg &= (2 << (bitend - bitstart)) - 1; 318 switch (*c) 319 { 320 case 'R': 321 func (stream, "%s", score_regnames[reg + 16]); 322 break; 323 case 'r': 324 func (stream, "%s", score_regnames[reg]); 325 break; 326 case 'd': 327 if (*(c + 1) == '\0') 328 func (stream, "%ld", reg); 329 else 330 { 331 c++; 332 if (*c == '1') 333 func (stream, "%ld", reg << 1); 334 else if (*c == '2') 335 func (stream, "%ld", reg << 2); 336 } 337 break; 338 339 case 'x': 340 if (*(c + 1) == '\0') 341 func (stream, "%lx", reg); 342 else 343 { 344 c++; 345 if (*c == '1') 346 func (stream, "%lx", reg << 1); 347 else if (*c == '2') 348 func (stream, "%lx", reg << 2); 349 } 350 break; 351 case 'i': 352 reg = ((reg ^ (1 << bitend)) - (1 << bitend)); 353 func (stream, "%ld", reg); 354 break; 355 default: 356 abort (); 357 } 358 } 359 break; 360 361 case '\'': 362 c++; 363 if ((given & (1 << bitstart)) != 0) 364 func (stream, "%c", *c); 365 break; 366 default: 367 abort (); 368 } 369 } 370 break; 371 default: 372 abort (); 373 } 374 } 375 else 376 func (stream, "%c", *c); 377 } 378 379 return 2; 380 } 381 } 382#if (SCORE_SIMULATOR_ACTIVE) 383 func (stream, _("<illegal instruction>")); 384 return 2; 385#endif 386 /* No match. */ 387 abort (); 388} 389 390/* NOTE: There are no checks in these routines that 391 the relevant number of data bytes exist. */ 392static int 393print_insn (bfd_vma pc, struct disassemble_info *info, bfd_boolean little) 394{ 395 unsigned char b[4]; 396 long given; 397 long ridparity; 398 int status; 399 bfd_boolean insn_pce_p = FALSE; 400 bfd_boolean insn_16_p = FALSE; 401 402 info->display_endian = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG; 403 404 if (pc & 0x2) 405 { 406 info->bytes_per_chunk = 2; 407 status = info->read_memory_func (pc, (bfd_byte *) b, 2, info); 408 b[3] = b[2] = 0; 409 insn_16_p = TRUE; 410 } 411 else 412 { 413 info->bytes_per_chunk = 4; 414 status = info->read_memory_func (pc, (bfd_byte *) & b[0], 4, info); 415 if (status != 0) 416 { 417 info->bytes_per_chunk = 2; 418 status = info->read_memory_func (pc, (bfd_byte *) b, 2, info); 419 b[3] = b[2] = 0; 420 insn_16_p = TRUE; 421 } 422 } 423 424 if (status != 0) 425 { 426 info->memory_error_func (status, pc, info); 427 return -1; 428 } 429 430 if (little) 431 { 432 given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24); 433 } 434 else 435 { 436 given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]); 437 } 438 439 if ((given & 0x80008000) == 0x80008000) 440 { 441 insn_pce_p = FALSE; 442 insn_16_p = FALSE; 443 } 444 else if ((given & 0x8000) == 0x8000) 445 { 446 insn_pce_p = TRUE; 447 } 448 else 449 { 450 insn_16_p = TRUE; 451 } 452 453 /* 16 bit instruction. */ 454 if (insn_16_p) 455 { 456 if (little) 457 { 458 given = b[0] | (b[1] << 8); 459 } 460 else 461 { 462 given = (b[0] << 8) | b[1]; 463 } 464 465 status = print_insn_score16 (pc, info, given); 466 } 467 /* pce instruction. */ 468 else if (insn_pce_p) 469 { 470 long other; 471 472 other = given & 0xFFFF; 473 given = (given & 0xFFFF0000) >> 16; 474 475 status = print_insn_score16 (pc, info, given); 476 print_insn_parallel_sym (info); 477 status += print_insn_score16 (pc, info, other); 478 /* disassemble_bytes() will output 4 byte per chunk for pce instructio. */ 479 info->bytes_per_chunk = 4; 480 } 481 /* 32 bit instruction. */ 482 else 483 { 484 /* Get rid of parity. */ 485 ridparity = (given & 0x7FFF); 486 ridparity |= (given & 0x7FFF0000) >> 1; 487 given = ridparity; 488 status = print_insn_score32 (pc, info, given); 489 } 490 491 return status; 492} 493 494int 495print_insn_big_score (bfd_vma pc, struct disassemble_info *info) 496{ 497 return print_insn (pc, info, FALSE); 498} 499 500int 501print_insn_little_score (bfd_vma pc, struct disassemble_info *info) 502{ 503 return print_insn (pc, info, TRUE); 504} 505