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