1 /* Morpho Technologies mRISC opcode support, for GNU Binutils. -*- C -*- 2 Copyright 2001, 2007, 2008, 2009, 2012 Free Software Foundation, Inc. 3 4 Contributed by Red Hat Inc; developed under contract from 5 Morpho Technologies. 6 7 This file is part of the GNU Binutils. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for 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, 22 MA 02110-1301, USA. */ 23 24 25 /* Each section is delimited with start and end markers. 26 27 <arch>-opc.h additions use: "-- opc.h" 28 <arch>-opc.c additions use: "-- opc.c" 29 <arch>-asm.c additions use: "-- asm.c" 30 <arch>-dis.c additions use: "-- dis.c" 31 <arch>-ibd.h additions use: "-- ibd.h" */ 32 33 /* -- opc.h */ 35 36 /* Check applicability of instructions against machines. */ 37 #define CGEN_VALIDATE_INSN_SUPPORTED 38 39 /* Allows reason codes to be output when assembler errors occur. */ 40 #define CGEN_VERBOSE_ASSEMBLER_ERRORS 41 42 /* Override disassembly hashing - there are variable bits in the top 43 byte of these instructions. */ 44 #define CGEN_DIS_HASH_SIZE 8 45 #define CGEN_DIS_HASH(buf, value) (((* (unsigned char *) (buf)) >> 5) % CGEN_DIS_HASH_SIZE) 46 47 #define CGEN_ASM_HASH_SIZE 127 48 #define CGEN_ASM_HASH(insn) mt_asm_hash (insn) 49 50 extern unsigned int mt_asm_hash (const char *); 51 52 extern int mt_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *); 53 54 55 /* -- opc.c */ 57 #include "safe-ctype.h" 58 59 /* Special check to ensure that instruction exists for given machine. */ 60 61 int 62 mt_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn) 63 { 64 int machs = CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH); 65 66 /* No mach attribute? Assume it's supported for all machs. */ 67 if (machs == 0) 68 return 1; 69 70 return ((machs & cd->machs) != 0); 71 } 72 73 /* A better hash function for instruction mnemonics. */ 74 75 unsigned int 76 mt_asm_hash (const char* insn) 77 { 78 unsigned int hash; 79 const char* m = insn; 80 81 for (hash = 0; *m && ! ISSPACE (*m); m++) 82 hash = (hash * 23) ^ (0x1F & TOLOWER (*m)); 83 84 /* printf ("%s %d\n", insn, (hash % CGEN_ASM_HASH_SIZE)); */ 85 86 return hash % CGEN_ASM_HASH_SIZE; 87 } 88 89 90 /* -- asm.c */ 92 /* Range checking for signed numbers. Returns 0 if acceptable 93 and 1 if the value is out of bounds for a signed quantity. */ 94 95 static int 96 signed_out_of_bounds (long val) 97 { 98 if ((val < -32768) || (val > 32767)) 99 return 1; 100 return 0; 101 } 102 103 static const char * 104 parse_loopsize (CGEN_CPU_DESC cd, 105 const char **strp, 106 int opindex, 107 void *arg) 108 { 109 signed long * valuep = (signed long *) arg; 110 const char *errmsg; 111 bfd_reloc_code_real_type code = BFD_RELOC_NONE; 112 enum cgen_parse_operand_result result_type; 113 bfd_vma value; 114 115 /* Is it a control transfer instructions? */ 116 if (opindex == (CGEN_OPERAND_TYPE) MT_OPERAND_LOOPSIZE) 117 { 118 code = BFD_RELOC_MT_PCINSN8; 119 errmsg = cgen_parse_address (cd, strp, opindex, code, 120 & result_type, & value); 121 *valuep = value; 122 return errmsg; 123 } 124 125 abort (); 126 } 127 128 static const char * 129 parse_imm16 (CGEN_CPU_DESC cd, 130 const char **strp, 131 int opindex, 132 void *arg) 133 { 134 signed long * valuep = (signed long *) arg; 135 const char *errmsg; 136 enum cgen_parse_operand_result result_type; 137 bfd_reloc_code_real_type code = BFD_RELOC_NONE; 138 bfd_vma value; 139 140 /* Is it a control transfer instructions? */ 141 if (opindex == (CGEN_OPERAND_TYPE) MT_OPERAND_IMM16O) 142 { 143 code = BFD_RELOC_16_PCREL; 144 errmsg = cgen_parse_address (cd, strp, opindex, code, 145 & result_type, & value); 146 if (errmsg == NULL) 147 { 148 if (signed_out_of_bounds (value)) 149 errmsg = _("Operand out of range. Must be between -32768 and 32767."); 150 } 151 *valuep = value; 152 return errmsg; 153 } 154 155 /* If it's not a control transfer instruction, then 156 we have to check for %OP relocating operators. */ 157 if (opindex == (CGEN_OPERAND_TYPE) MT_OPERAND_IMM16L) 158 ; 159 else if (strncmp (*strp, "%hi16", 5) == 0) 160 { 161 *strp += 5; 162 code = BFD_RELOC_HI16; 163 } 164 else if (strncmp (*strp, "%lo16", 5) == 0) 165 { 166 *strp += 5; 167 code = BFD_RELOC_LO16; 168 } 169 170 /* If we found a %OP relocating operator, then parse it as an address. 171 If not, we need to parse it as an integer, either signed or unsigned 172 depending on which operand type we have. */ 173 if (code != BFD_RELOC_NONE) 174 { 175 /* %OP relocating operator found. */ 176 errmsg = cgen_parse_address (cd, strp, opindex, code, 177 & result_type, & value); 178 if (errmsg == NULL) 179 { 180 switch (result_type) 181 { 182 case (CGEN_PARSE_OPERAND_RESULT_NUMBER): 183 if (code == BFD_RELOC_HI16) 184 value = (value >> 16) & 0xFFFF; 185 else if (code == BFD_RELOC_LO16) 186 value = value & 0xFFFF; 187 else 188 errmsg = _("Biiiig Trouble in parse_imm16!"); 189 break; 190 191 case (CGEN_PARSE_OPERAND_RESULT_QUEUED): 192 /* No special processing for this case. */ 193 break; 194 195 default: 196 errmsg = _("The percent-operator's operand is not a symbol"); 197 break; 198 } 199 } 200 *valuep = value; 201 } 202 else 203 { 204 /* Parse hex values like 0xffff as unsigned, and sign extend 205 them manually. */ 206 int parse_signed = (opindex == (CGEN_OPERAND_TYPE)MT_OPERAND_IMM16); 207 208 if ((*strp)[0] == '0' 209 && ((*strp)[1] == 'x' || (*strp)[1] == 'X')) 210 parse_signed = 0; 211 212 /* No relocating operator. Parse as an number. */ 213 if (parse_signed) 214 { 215 /* Parse as as signed integer. */ 216 217 errmsg = cgen_parse_signed_integer (cd, strp, opindex, valuep); 218 219 if (errmsg == NULL) 220 { 221 #if 0 222 /* Manual range checking is needed for the signed case. */ 223 if (*valuep & 0x8000) 224 value = 0xffff0000 | *valuep; 225 else 226 value = *valuep; 227 228 if (signed_out_of_bounds (value)) 229 errmsg = _("Operand out of range. Must be between -32768 and 32767."); 230 /* Truncate to 16 bits. This is necessary 231 because cgen will have sign extended *valuep. */ 232 *valuep &= 0xFFFF; 233 #endif 234 } 235 } 236 else 237 { 238 /* MT_OPERAND_IMM16Z. Parse as an unsigned integer. */ 239 errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, (unsigned long *) valuep); 240 241 if (opindex == (CGEN_OPERAND_TYPE) MT_OPERAND_IMM16 242 && *valuep >= 0x8000 243 && *valuep <= 0xffff) 244 *valuep -= 0x10000; 245 } 246 } 247 248 return errmsg; 249 } 250 251 252 static const char * 253 parse_dup (CGEN_CPU_DESC cd, 254 const char **strp, 255 int opindex, 256 unsigned long *valuep) 257 { 258 const char *errmsg = NULL; 259 260 if (strncmp (*strp, "dup", 3) == 0 || strncmp (*strp, "DUP", 3) == 0) 261 { 262 *strp += 3; 263 *valuep = 1; 264 } 265 else if (strncmp (*strp, "xx", 2) == 0 || strncmp (*strp, "XX", 2) == 0) 266 { 267 *strp += 2; 268 *valuep = 0; 269 } 270 else 271 errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep); 272 273 return errmsg; 274 } 275 276 277 static const char * 278 parse_ball (CGEN_CPU_DESC cd, 279 const char **strp, 280 int opindex, 281 unsigned long *valuep) 282 { 283 const char *errmsg = NULL; 284 285 if (strncmp (*strp, "all", 3) == 0 || strncmp (*strp, "ALL", 3) == 0) 286 { 287 *strp += 3; 288 *valuep = 1; 289 } 290 else if (strncmp (*strp, "one", 3) == 0 || strncmp (*strp, "ONE", 3) == 0) 291 { 292 *strp += 3; 293 *valuep = 0; 294 } 295 else 296 errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep); 297 298 return errmsg; 299 } 300 301 static const char * 302 parse_xmode (CGEN_CPU_DESC cd, 303 const char **strp, 304 int opindex, 305 unsigned long *valuep) 306 { 307 const char *errmsg = NULL; 308 309 if (strncmp (*strp, "pm", 2) == 0 || strncmp (*strp, "PM", 2) == 0) 310 { 311 *strp += 2; 312 *valuep = 1; 313 } 314 else if (strncmp (*strp, "xm", 2) == 0 || strncmp (*strp, "XM", 2) == 0) 315 { 316 *strp += 2; 317 *valuep = 0; 318 } 319 else 320 errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep); 321 322 return errmsg; 323 } 324 325 static const char * 326 parse_rc (CGEN_CPU_DESC cd, 327 const char **strp, 328 int opindex, 329 unsigned long *valuep) 330 { 331 const char *errmsg = NULL; 332 333 if (strncmp (*strp, "r", 1) == 0 || strncmp (*strp, "R", 1) == 0) 334 { 335 *strp += 1; 336 *valuep = 1; 337 } 338 else if (strncmp (*strp, "c", 1) == 0 || strncmp (*strp, "C", 1) == 0) 339 { 340 *strp += 1; 341 *valuep = 0; 342 } 343 else 344 errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep); 345 346 return errmsg; 347 } 348 349 static const char * 350 parse_cbrb (CGEN_CPU_DESC cd, 351 const char **strp, 352 int opindex, 353 unsigned long *valuep) 354 { 355 const char *errmsg = NULL; 356 357 if (strncmp (*strp, "rb", 2) == 0 || strncmp (*strp, "RB", 2) == 0) 358 { 359 *strp += 2; 360 *valuep = 1; 361 } 362 else if (strncmp (*strp, "cb", 2) == 0 || strncmp (*strp, "CB", 2) == 0) 363 { 364 *strp += 2; 365 *valuep = 0; 366 } 367 else 368 errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep); 369 370 return errmsg; 371 } 372 373 static const char * 374 parse_rbbc (CGEN_CPU_DESC cd, 375 const char **strp, 376 int opindex, 377 unsigned long *valuep) 378 { 379 const char *errmsg = NULL; 380 381 if (strncmp (*strp, "rt", 2) == 0 || strncmp (*strp, "RT", 2) == 0) 382 { 383 *strp += 2; 384 *valuep = 0; 385 } 386 else if (strncmp (*strp, "br1", 3) == 0 || strncmp (*strp, "BR1", 3) == 0) 387 { 388 *strp += 3; 389 *valuep = 1; 390 } 391 else if (strncmp (*strp, "br2", 3) == 0 || strncmp (*strp, "BR2", 3) == 0) 392 { 393 *strp += 3; 394 *valuep = 2; 395 } 396 else if (strncmp (*strp, "cs", 2) == 0 || strncmp (*strp, "CS", 2) == 0) 397 { 398 *strp += 2; 399 *valuep = 3; 400 } 401 else 402 errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep); 403 404 return errmsg; 405 } 406 407 static const char * 408 parse_type (CGEN_CPU_DESC cd, 409 const char **strp, 410 int opindex, 411 unsigned long *valuep) 412 { 413 const char *errmsg = NULL; 414 415 if (strncmp (*strp, "odd", 3) == 0 || strncmp (*strp, "ODD", 3) == 0) 416 { 417 *strp += 3; 418 *valuep = 0; 419 } 420 else if (strncmp (*strp, "even", 4) == 0 || strncmp (*strp, "EVEN", 4) == 0) 421 { 422 *strp += 4; 423 *valuep = 1; 424 } 425 else if (strncmp (*strp, "oe", 2) == 0 || strncmp (*strp, "OE", 2) == 0) 426 { 427 *strp += 2; 428 *valuep = 2; 429 } 430 else 431 errmsg = cgen_parse_unsigned_integer (cd, strp, opindex, valuep); 432 433 if ((errmsg == NULL) && (*valuep == 3)) 434 errmsg = _("invalid operand. type may have values 0,1,2 only."); 435 436 return errmsg; 437 } 438 439 /* -- dis.c */ 440 static void print_dollarhex (CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int); 441 static void print_pcrel (CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int); 442 443 static void 444 print_dollarhex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 445 void * dis_info, 446 long value, 447 unsigned int attrs ATTRIBUTE_UNUSED, 448 bfd_vma pc ATTRIBUTE_UNUSED, 449 int length ATTRIBUTE_UNUSED) 450 { 451 disassemble_info *info = (disassemble_info *) dis_info; 452 453 info->fprintf_func (info->stream, "$%lx", value & 0xffffffff); 454 455 if (0) 456 print_normal (cd, dis_info, value, attrs, pc, length); 457 } 458 459 static void 460 print_pcrel (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 461 void * dis_info, 462 long value, 463 unsigned int attrs ATTRIBUTE_UNUSED, 464 bfd_vma pc ATTRIBUTE_UNUSED, 465 int length ATTRIBUTE_UNUSED) 466 { 467 print_address (cd, dis_info, value + pc, attrs, pc, length); 468 } 469 470 /* -- */ 471 472 473 474 475 476