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