1 /* Adapteva epiphany opcode support. -*- C -*- 2 3 Copyright 2009, 2011 Free Software Foundation, Inc. 4 5 Contributed by Embecosm on behalf of Adapteva, Inc. 6 7 This file is part of the GNU Binutils and of GDB. 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 /* enumerate relaxation types for gas. */ 37 typedef enum epiphany_relax_types 38 { 39 EPIPHANY_RELAX_NONE=0, 40 EPIPHANY_RELAX_NEED_RELAXING, 41 42 EPIPHANY_RELAX_BRANCH_SHORT, /* Fits into +127..-128 */ 43 EPIPHANY_RELAX_BRANCH_LONG, /* b/bl/b<cond> +-2*16 */ 44 45 EPIPHANY_RELAX_ARITH_SIMM3, /* add/sub -7..3 */ 46 EPIPHANY_RELAX_ARITH_SIMM11, /* add/sub -2**11-1 .. 2**10-1 */ 47 48 EPIPHANY_RELAX_MOV_IMM8, /* mov r,imm8 */ 49 EPIPHANY_RELAX_MOV_IMM16, /* mov r,imm16 */ 50 51 EPIPHANY_RELAX_LDST_IMM3, /* (ldr|str)* r,[r,disp3] */ 52 EPIPHANY_RELAX_LDST_IMM11 /* (ldr|str)* r,[r,disp11] */ 53 54 } EPIPHANY_RELAX_TYPES; 55 56 /* Override disassembly hashing... */ 57 58 /* Can only depend on instruction having 4 decode bits which gets us to the 59 major groups of 16/32 instructions. */ 60 #undef CGEN_DIS_HASH_SIZE 61 #if 1 62 63 /* hash code on the 4 LSBs */ 64 #define CGEN_DIS_HASH_SIZE 16 65 66 #define CGEN_DIS_HASH(buf, value) ((*buf) & 0xf) 67 #else 68 #define CGEN_DIS_HASH_SIZE 1 69 #define CGEN_DIS_HASH(buf, value) 0 70 #endif 71 72 extern const char * parse_shortregs (CGEN_CPU_DESC cd, 73 const char ** strp, 74 CGEN_KEYWORD * keywords, 75 long * valuep); 76 77 extern const char * parse_branch_addr (CGEN_CPU_DESC cd, 78 const char ** strp, 79 int opindex, 80 int opinfo, 81 enum cgen_parse_operand_result * resultp, 82 bfd_vma *valuep); 83 84 /* Allows reason codes to be output when assembler errors occur. */ 85 #define CGEN_VERBOSE_ASSEMBLER_ERRORS 86 87 88 /* -- opc.c */ 90 91 92 93 /* -- asm.c */ 95 const char * 96 parse_shortregs (CGEN_CPU_DESC cd, 97 const char ** strp, 98 CGEN_KEYWORD * keywords, 99 long * regno) 100 { 101 const char * errmsg; 102 103 /* Parse register. */ 104 errmsg = cgen_parse_keyword (cd, strp, keywords, regno); 105 106 if (errmsg) 107 return errmsg; 108 109 if (*regno > 7) 110 errmsg = _("register unavailable for short instructions"); 111 112 return errmsg; 113 } 114 115 static const char * parse_simm_not_reg (CGEN_CPU_DESC, const char **, int, 116 long *); 117 118 static const char * 119 parse_uimm_not_reg (CGEN_CPU_DESC cd, 120 const char ** strp, 121 int opindex, 122 unsigned long * valuep) 123 { 124 long * svalp = (void *) valuep; 125 return parse_simm_not_reg (cd, strp, opindex, svalp); 126 } 127 128 /* Handle simm3/simm11/imm3/imm12. */ 129 130 static const char * 131 parse_simm_not_reg (CGEN_CPU_DESC cd, 132 const char ** strp, 133 int opindex, 134 long * valuep) 135 { 136 const char * errmsg; 137 138 int sign = 0; 139 int bits = 0; 140 141 switch (opindex) 142 { 143 case EPIPHANY_OPERAND_SIMM3: 144 sign = 1; bits = 3; break; 145 case EPIPHANY_OPERAND_SIMM11: 146 sign = 1; bits = 11; break; 147 case EPIPHANY_OPERAND_DISP3: 148 sign = 0; bits = 3; break; 149 case EPIPHANY_OPERAND_DISP11: 150 /* Load/store displacement is a sign-magnitude 12 bit value. */ 151 sign = 0; bits = 11; break; 152 } 153 154 /* First try to parse as a register name and reject the operand. */ 155 errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names,valuep); 156 if (!errmsg) 157 return _("register name used as immediate value"); 158 159 errmsg = (sign ? cgen_parse_signed_integer (cd, strp, opindex, valuep) 160 : cgen_parse_unsigned_integer (cd, strp, opindex, 161 (unsigned long *) valuep)); 162 if (errmsg) 163 return errmsg; 164 165 if (sign) 166 errmsg = cgen_validate_signed_integer (*valuep, 167 -((1L << bits) - 1), (1 << (bits - 1)) - 1); 168 else 169 errmsg = cgen_validate_unsigned_integer (*valuep, 0, (1L << bits) - 1); 170 171 return errmsg; 172 } 173 174 static const char * 175 parse_postindex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 176 const char ** strp, 177 int opindex ATTRIBUTE_UNUSED, 178 unsigned long *valuep) 179 { 180 if (**strp == '#') 181 ++*strp; /* Skip leading hashes. */ 182 183 if (**strp == '-') 184 { 185 *valuep = 1; 186 ++*strp; 187 } 188 else if (**strp == '+') 189 { 190 *valuep = 0; 191 ++*strp; 192 } 193 else 194 *valuep = 0; 195 196 return NULL; 197 } 198 199 static const char * 200 parse_imm8 (CGEN_CPU_DESC cd, 201 const char ** strp, 202 int opindex, 203 bfd_reloc_code_real_type code, 204 enum cgen_parse_operand_result * result_type, 205 bfd_vma * valuep) 206 { 207 const char * errmsg; 208 enum cgen_parse_operand_result rt; 209 long dummyval; 210 211 if (!result_type) 212 result_type = &rt; 213 214 code = BFD_RELOC_NONE; 215 216 if (!cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_gr_names, &dummyval) 217 || !cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_cr_names, 218 &dummyval)) 219 /* Don't treat "mov ip,ip" as a move-immediate. */ 220 return _("register source in immediate move"); 221 222 errmsg = cgen_parse_address (cd, strp, opindex, code, result_type, valuep); 223 if (errmsg) 224 return errmsg; 225 226 if (*result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 227 errmsg = cgen_validate_unsigned_integer (*valuep, 0, 0xff); 228 else 229 errmsg = _("byte relocation unsupported"); 230 231 *valuep &= 0xff; 232 return errmsg; 233 } 234 235 static const char * MISSING_CLOSE_PARENTHESIS = N_("missing `)'"); 236 237 static const char * 238 parse_imm16 (CGEN_CPU_DESC cd, 239 const char ** strp, 240 int opindex, 241 bfd_reloc_code_real_type code ATTRIBUTE_UNUSED, 242 enum cgen_parse_operand_result * result_type, 243 bfd_vma * valuep) 244 { 245 const char * errmsg; 246 enum cgen_parse_operand_result rt; 247 long dummyval; 248 249 if (!result_type) 250 result_type = &rt; 251 252 if (strncasecmp (*strp, "%high(", 6) == 0) 253 { 254 *strp += 6; 255 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_EPIPHANY_HIGH, 256 result_type, valuep); 257 if (**strp != ')') 258 return MISSING_CLOSE_PARENTHESIS; 259 ++*strp; 260 *valuep >>= 16; 261 } 262 else if (strncasecmp (*strp, "%low(", 5) == 0) 263 { 264 *strp += 5; 265 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_EPIPHANY_LOW, 266 result_type, valuep); 267 if (**strp != ')') 268 return MISSING_CLOSE_PARENTHESIS; 269 ++*strp; 270 } 271 else if (!cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_gr_names, 272 &dummyval) 273 || !cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_cr_names, 274 &dummyval)) 275 /* Don't treat "mov ip,ip" as a move-immediate. */ 276 return _("register source in immediate move"); 277 else 278 errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_16, 279 result_type, valuep); 280 281 if (!errmsg && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 282 errmsg = cgen_validate_unsigned_integer (*valuep, 0, 0xffff); 283 284 *valuep &= 0xffff; 285 return errmsg; 286 } 287 288 const char * 289 parse_branch_addr (CGEN_CPU_DESC cd, 290 const char ** strp, 291 int opindex, 292 int opinfo ATTRIBUTE_UNUSED, 293 enum cgen_parse_operand_result * resultp ATTRIBUTE_UNUSED, 294 bfd_vma *valuep ATTRIBUTE_UNUSED) 295 { 296 const char * errmsg; 297 enum cgen_parse_operand_result result_type; 298 bfd_reloc_code_real_type code = BFD_RELOC_NONE; 299 bfd_vma value; 300 301 switch (opindex) 302 { 303 case EPIPHANY_OPERAND_SIMM24: 304 code = BFD_RELOC_EPIPHANY_SIMM24; 305 break; 306 307 case EPIPHANY_OPERAND_SIMM8: 308 code = BFD_RELOC_EPIPHANY_SIMM8; 309 break; 310 311 default: 312 errmsg = _("ABORT: unknown operand"); 313 return errmsg; 314 } 315 316 errmsg = cgen_parse_address (cd, strp, opindex, code, 317 &result_type, &value); 318 if (errmsg == NULL) 319 { 320 if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 321 { 322 /* Act as if we had done a PC-relative branch, ala .+num. */ 323 char buf[20]; 324 const char * bufp = (const char *) buf; 325 326 sprintf (buf, ".+%ld", (long) value); 327 errmsg = cgen_parse_address (cd, &bufp, opindex, code, &result_type, 328 &value); 329 } 330 331 if (result_type == CGEN_PARSE_OPERAND_RESULT_QUEUED) 332 { 333 /* This will happen for things like (s2-s1) where s2 and s1 334 are labels. */ 335 /* Nothing further to be done. */ 336 } 337 else 338 errmsg = _("Not a pc-relative address."); 339 } 340 return errmsg; 341 } 342 343 /* -- dis.c */ 345 346 #define CGEN_PRINT_INSN epiphany_print_insn 347 348 static int 349 epiphany_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info) 350 { 351 bfd_byte buf[CGEN_MAX_INSN_SIZE]; 352 int buflen; 353 int status; 354 355 info->bytes_per_chunk = 2; 356 357 /* Attempt to read the base part of the insn. */ 358 info->bytes_per_line = buflen = cd->base_insn_bitsize / 8; 359 status = (*info->read_memory_func) (pc, buf, buflen, info); 360 361 /* Try again with the minimum part, if min < base. */ 362 if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize)) 363 { 364 info->bytes_per_line = buflen = cd->min_insn_bitsize / 8; 365 status = (*info->read_memory_func) (pc, buf, buflen, info); 366 } 367 368 if (status != 0) 369 { 370 (*info->memory_error_func) (status, pc, info); 371 return -1; 372 } 373 374 return print_insn (cd, pc, info, buf, buflen); 375 } 376 377 378 static void 379 print_postindex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 380 void * dis_info, 381 long value, 382 unsigned int attrs ATTRIBUTE_UNUSED, 383 bfd_vma pc ATTRIBUTE_UNUSED, 384 int length ATTRIBUTE_UNUSED) 385 { 386 disassemble_info *info = (disassemble_info *) dis_info; 387 (*info->fprintf_func) (info->stream, value ? "-" : "+"); 388 } 389 390 static void 391 print_simm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 392 void * dis_info, 393 long value, 394 unsigned int attrs ATTRIBUTE_UNUSED, 395 bfd_vma pc ATTRIBUTE_UNUSED, 396 int length ATTRIBUTE_UNUSED) 397 { 398 print_address (cd, dis_info, value, attrs, pc, length); 399 } 400 401 static void 402 print_uimm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 403 void * dis_info, 404 unsigned long value, 405 unsigned int attrs ATTRIBUTE_UNUSED, 406 bfd_vma pc ATTRIBUTE_UNUSED, 407 int length ATTRIBUTE_UNUSED) 408 { 409 disassemble_info *info = (disassemble_info *)dis_info; 410 411 if (value & 0x800) 412 (*info->fprintf_func) (info->stream, "-"); 413 414 value &= 0x7ff; 415 print_address (cd, dis_info, value, attrs, pc, length); 416 } 417 418 419 /* -- */ 421 422