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