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