1883529b6Schristos/* Adapteva epiphany opcode support. -*- C -*- 2883529b6Schristos 3883529b6Schristos Copyright 2009, 2011 Free Software Foundation, Inc. 4883529b6Schristos 5883529b6Schristos Contributed by Embecosm on behalf of Adapteva, Inc. 6883529b6Schristos 7883529b6Schristos This file is part of the GNU Binutils and of GDB. 8883529b6Schristos 9883529b6Schristos This program is free software; you can redistribute it and/or modify 10883529b6Schristos it under the terms of the GNU General Public License as published by 11883529b6Schristos the Free Software Foundation; either version 3 of the License, or 12883529b6Schristos (at your option) any later version. 13883529b6Schristos 14883529b6Schristos This program is distributed in the hope that it will be useful, 15883529b6Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 16883529b6Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17883529b6Schristos GNU General Public License for more details. 18883529b6Schristos 19883529b6Schristos You should have received a copy of the GNU General Public License 20883529b6Schristos along with this program; if not, write to the Free Software 21883529b6Schristos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 22883529b6Schristos MA 02110-1301, USA. */ 23883529b6Schristos 24883529b6Schristos/* 25883529b6Schristos Each section is delimited with start and end markers. 26883529b6Schristos 27883529b6Schristos <arch>-opc.h additions use: "-- opc.h" 28883529b6Schristos <arch>-opc.c additions use: "-- opc.c" 29883529b6Schristos <arch>-asm.c additions use: "-- asm.c" 30883529b6Schristos <arch>-dis.c additions use: "-- dis.c" 31883529b6Schristos <arch>-ibd.h additions use: "-- ibd.h". */ 32883529b6Schristos 33883529b6Schristos/* -- opc.h */ 34883529b6Schristos 35883529b6Schristos/* enumerate relaxation types for gas. */ 36883529b6Schristostypedef enum epiphany_relax_types 37883529b6Schristos{ 38883529b6Schristos EPIPHANY_RELAX_NONE=0, 39883529b6Schristos EPIPHANY_RELAX_NEED_RELAXING, 40883529b6Schristos 41883529b6Schristos EPIPHANY_RELAX_BRANCH_SHORT, /* Fits into +127..-128 */ 42883529b6Schristos EPIPHANY_RELAX_BRANCH_LONG, /* b/bl/b<cond> +-2*16 */ 43883529b6Schristos 44883529b6Schristos EPIPHANY_RELAX_ARITH_SIMM3, /* add/sub -7..3 */ 45883529b6Schristos EPIPHANY_RELAX_ARITH_SIMM11, /* add/sub -2**11-1 .. 2**10-1 */ 46883529b6Schristos 47883529b6Schristos EPIPHANY_RELAX_MOV_IMM8, /* mov r,imm8 */ 48883529b6Schristos EPIPHANY_RELAX_MOV_IMM16, /* mov r,imm16 */ 49883529b6Schristos 50883529b6Schristos EPIPHANY_RELAX_LDST_IMM3, /* (ldr|str)* r,[r,disp3] */ 51883529b6Schristos EPIPHANY_RELAX_LDST_IMM11 /* (ldr|str)* r,[r,disp11] */ 52883529b6Schristos 53883529b6Schristos} EPIPHANY_RELAX_TYPES; 54883529b6Schristos 55883529b6Schristos/* Override disassembly hashing... */ 56883529b6Schristos 57883529b6Schristos/* Can only depend on instruction having 4 decode bits which gets us to the 58883529b6Schristos major groups of 16/32 instructions. */ 59883529b6Schristos#undef CGEN_DIS_HASH_SIZE 60883529b6Schristos#if 1 61883529b6Schristos 62883529b6Schristos/* hash code on the 4 LSBs */ 63883529b6Schristos#define CGEN_DIS_HASH_SIZE 16 64883529b6Schristos 65883529b6Schristos#define CGEN_DIS_HASH(buf, value) ((*buf) & 0xf) 66883529b6Schristos#else 67883529b6Schristos#define CGEN_DIS_HASH_SIZE 1 68883529b6Schristos#define CGEN_DIS_HASH(buf, value) 0 69883529b6Schristos#endif 70883529b6Schristos 71883529b6Schristosextern const char * parse_shortregs (CGEN_CPU_DESC cd, 72883529b6Schristos const char ** strp, 73883529b6Schristos CGEN_KEYWORD * keywords, 74883529b6Schristos long * valuep); 75883529b6Schristos 76883529b6Schristosextern const char * parse_branch_addr (CGEN_CPU_DESC cd, 77883529b6Schristos const char ** strp, 78883529b6Schristos int opindex, 79883529b6Schristos int opinfo, 80883529b6Schristos enum cgen_parse_operand_result * resultp, 81883529b6Schristos bfd_vma *valuep); 82883529b6Schristos 83883529b6Schristos/* Allows reason codes to be output when assembler errors occur. */ 84883529b6Schristos#define CGEN_VERBOSE_ASSEMBLER_ERRORS 85883529b6Schristos 86883529b6Schristos 87883529b6Schristos/* -- opc.c */ 88883529b6Schristos 89883529b6Schristos 90883529b6Schristos 91883529b6Schristos/* -- asm.c */ 92883529b6Schristosconst char * 93883529b6Schristosparse_shortregs (CGEN_CPU_DESC cd, 94883529b6Schristos const char ** strp, 95883529b6Schristos CGEN_KEYWORD * keywords, 96883529b6Schristos long * regno) 97883529b6Schristos{ 98883529b6Schristos const char * errmsg; 99883529b6Schristos 100883529b6Schristos /* Parse register. */ 101883529b6Schristos errmsg = cgen_parse_keyword (cd, strp, keywords, regno); 102883529b6Schristos 103883529b6Schristos if (errmsg) 104883529b6Schristos return errmsg; 105883529b6Schristos 106883529b6Schristos if (*regno > 7) 107883529b6Schristos errmsg = _("register unavailable for short instructions"); 108883529b6Schristos 109883529b6Schristos return errmsg; 110883529b6Schristos} 111883529b6Schristos 112883529b6Schristosstatic const char * parse_simm_not_reg (CGEN_CPU_DESC, const char **, int, 113883529b6Schristos long *); 114883529b6Schristos 115883529b6Schristosstatic const char * 116883529b6Schristosparse_uimm_not_reg (CGEN_CPU_DESC cd, 117883529b6Schristos const char ** strp, 118883529b6Schristos int opindex, 119883529b6Schristos unsigned long * valuep) 120883529b6Schristos{ 121883529b6Schristos long * svalp = (void *) valuep; 122883529b6Schristos return parse_simm_not_reg (cd, strp, opindex, svalp); 123883529b6Schristos} 124883529b6Schristos 125883529b6Schristos/* Handle simm3/simm11/imm3/imm12. */ 126883529b6Schristos 127883529b6Schristosstatic const char * 128883529b6Schristosparse_simm_not_reg (CGEN_CPU_DESC cd, 129883529b6Schristos const char ** strp, 130883529b6Schristos int opindex, 131883529b6Schristos long * valuep) 132883529b6Schristos{ 133883529b6Schristos const char * errmsg; 134883529b6Schristos 135883529b6Schristos int sign = 0; 136883529b6Schristos int bits = 0; 137883529b6Schristos 138883529b6Schristos switch (opindex) 139883529b6Schristos { 140883529b6Schristos case EPIPHANY_OPERAND_SIMM3: 141883529b6Schristos sign = 1; bits = 3; break; 142883529b6Schristos case EPIPHANY_OPERAND_SIMM11: 143883529b6Schristos sign = 1; bits = 11; break; 144883529b6Schristos case EPIPHANY_OPERAND_DISP3: 145883529b6Schristos sign = 0; bits = 3; break; 146883529b6Schristos case EPIPHANY_OPERAND_DISP11: 147883529b6Schristos /* Load/store displacement is a sign-magnitude 12 bit value. */ 148883529b6Schristos sign = 0; bits = 11; break; 149883529b6Schristos } 150883529b6Schristos 151883529b6Schristos /* First try to parse as a register name and reject the operand. */ 152883529b6Schristos errmsg = cgen_parse_keyword (cd, strp, & epiphany_cgen_opval_gr_names,valuep); 153883529b6Schristos if (!errmsg) 154883529b6Schristos return _("register name used as immediate value"); 155883529b6Schristos 156883529b6Schristos errmsg = (sign ? cgen_parse_signed_integer (cd, strp, opindex, valuep) 157883529b6Schristos : cgen_parse_unsigned_integer (cd, strp, opindex, 158883529b6Schristos (unsigned long *) valuep)); 159883529b6Schristos if (errmsg) 160883529b6Schristos return errmsg; 161883529b6Schristos 162883529b6Schristos if (sign) 163883529b6Schristos errmsg = cgen_validate_signed_integer (*valuep, 164883529b6Schristos -((1L << bits) - 1), (1 << (bits - 1)) - 1); 165883529b6Schristos else 166883529b6Schristos errmsg = cgen_validate_unsigned_integer (*valuep, 0, (1L << bits) - 1); 167883529b6Schristos 168883529b6Schristos return errmsg; 169883529b6Schristos} 170883529b6Schristos 171883529b6Schristosstatic const char * 172883529b6Schristosparse_postindex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 173883529b6Schristos const char ** strp, 174883529b6Schristos int opindex ATTRIBUTE_UNUSED, 175883529b6Schristos unsigned long *valuep) 176883529b6Schristos{ 177883529b6Schristos if (**strp == '#') 178883529b6Schristos ++*strp; /* Skip leading hashes. */ 179883529b6Schristos 180883529b6Schristos if (**strp == '-') 181883529b6Schristos { 182883529b6Schristos *valuep = 1; 183883529b6Schristos ++*strp; 184883529b6Schristos } 185883529b6Schristos else if (**strp == '+') 186883529b6Schristos { 187883529b6Schristos *valuep = 0; 188883529b6Schristos ++*strp; 189883529b6Schristos } 190883529b6Schristos else 191883529b6Schristos *valuep = 0; 192883529b6Schristos 193883529b6Schristos return NULL; 194883529b6Schristos} 195883529b6Schristos 196883529b6Schristosstatic const char * 197883529b6Schristosparse_imm8 (CGEN_CPU_DESC cd, 198883529b6Schristos const char ** strp, 199883529b6Schristos int opindex, 200883529b6Schristos bfd_reloc_code_real_type code, 201883529b6Schristos enum cgen_parse_operand_result * result_type, 202883529b6Schristos bfd_vma * valuep) 203883529b6Schristos{ 204883529b6Schristos const char * errmsg; 205883529b6Schristos enum cgen_parse_operand_result rt; 206883529b6Schristos long dummyval; 207883529b6Schristos 208883529b6Schristos if (!result_type) 209883529b6Schristos result_type = &rt; 210883529b6Schristos 211883529b6Schristos code = BFD_RELOC_NONE; 212883529b6Schristos 213883529b6Schristos if (!cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_gr_names, &dummyval) 214883529b6Schristos || !cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_cr_names, 215883529b6Schristos &dummyval)) 216883529b6Schristos /* Don't treat "mov ip,ip" as a move-immediate. */ 217883529b6Schristos return _("register source in immediate move"); 218883529b6Schristos 219883529b6Schristos errmsg = cgen_parse_address (cd, strp, opindex, code, result_type, valuep); 220883529b6Schristos if (errmsg) 221883529b6Schristos return errmsg; 222883529b6Schristos 223883529b6Schristos if (*result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 224883529b6Schristos errmsg = cgen_validate_unsigned_integer (*valuep, 0, 0xff); 225883529b6Schristos else 226883529b6Schristos errmsg = _("byte relocation unsupported"); 227883529b6Schristos 228883529b6Schristos *valuep &= 0xff; 229883529b6Schristos return errmsg; 230883529b6Schristos} 231883529b6Schristos 232883529b6Schristosstatic const char * MISSING_CLOSE_PARENTHESIS = N_("missing `)'"); 233883529b6Schristos 234883529b6Schristosstatic const char * 235883529b6Schristosparse_imm16 (CGEN_CPU_DESC cd, 236883529b6Schristos const char ** strp, 237883529b6Schristos int opindex, 238883529b6Schristos bfd_reloc_code_real_type code ATTRIBUTE_UNUSED, 239883529b6Schristos enum cgen_parse_operand_result * result_type, 240883529b6Schristos bfd_vma * valuep) 241883529b6Schristos{ 242883529b6Schristos const char * errmsg; 243883529b6Schristos enum cgen_parse_operand_result rt; 244883529b6Schristos long dummyval; 245883529b6Schristos 246883529b6Schristos if (!result_type) 247883529b6Schristos result_type = &rt; 248883529b6Schristos 249883529b6Schristos if (strncasecmp (*strp, "%high(", 6) == 0) 250883529b6Schristos { 251883529b6Schristos *strp += 6; 252883529b6Schristos errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_EPIPHANY_HIGH, 253883529b6Schristos result_type, valuep); 254883529b6Schristos if (**strp != ')') 255883529b6Schristos return MISSING_CLOSE_PARENTHESIS; 256883529b6Schristos ++*strp; 257883529b6Schristos *valuep >>= 16; 258883529b6Schristos } 259883529b6Schristos else if (strncasecmp (*strp, "%low(", 5) == 0) 260883529b6Schristos { 261883529b6Schristos *strp += 5; 262883529b6Schristos errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_EPIPHANY_LOW, 263883529b6Schristos result_type, valuep); 264883529b6Schristos if (**strp != ')') 265883529b6Schristos return MISSING_CLOSE_PARENTHESIS; 266883529b6Schristos ++*strp; 267883529b6Schristos } 268883529b6Schristos else if (!cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_gr_names, 269883529b6Schristos &dummyval) 270883529b6Schristos || !cgen_parse_keyword (cd, strp, &epiphany_cgen_opval_cr_names, 271883529b6Schristos &dummyval)) 272883529b6Schristos /* Don't treat "mov ip,ip" as a move-immediate. */ 273883529b6Schristos return _("register source in immediate move"); 274883529b6Schristos else 275883529b6Schristos errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_16, 276883529b6Schristos result_type, valuep); 277883529b6Schristos 278883529b6Schristos if (!errmsg && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 279883529b6Schristos errmsg = cgen_validate_unsigned_integer (*valuep, 0, 0xffff); 280883529b6Schristos 281883529b6Schristos *valuep &= 0xffff; 282883529b6Schristos return errmsg; 283883529b6Schristos} 284883529b6Schristos 285883529b6Schristosconst char * 286883529b6Schristosparse_branch_addr (CGEN_CPU_DESC cd, 287883529b6Schristos const char ** strp, 288883529b6Schristos int opindex, 289883529b6Schristos int opinfo ATTRIBUTE_UNUSED, 290883529b6Schristos enum cgen_parse_operand_result * resultp ATTRIBUTE_UNUSED, 291883529b6Schristos bfd_vma *valuep ATTRIBUTE_UNUSED) 292883529b6Schristos{ 293883529b6Schristos const char * errmsg; 294883529b6Schristos enum cgen_parse_operand_result result_type; 295883529b6Schristos bfd_reloc_code_real_type code = BFD_RELOC_NONE; 296883529b6Schristos bfd_vma value; 297883529b6Schristos 298883529b6Schristos switch (opindex) 299883529b6Schristos { 300883529b6Schristos case EPIPHANY_OPERAND_SIMM24: 301883529b6Schristos code = BFD_RELOC_EPIPHANY_SIMM24; 302883529b6Schristos break; 303883529b6Schristos 304883529b6Schristos case EPIPHANY_OPERAND_SIMM8: 305883529b6Schristos code = BFD_RELOC_EPIPHANY_SIMM8; 306883529b6Schristos break; 307883529b6Schristos 308883529b6Schristos default: 309883529b6Schristos errmsg = _("ABORT: unknown operand"); 310883529b6Schristos return errmsg; 311883529b6Schristos } 312883529b6Schristos 313883529b6Schristos errmsg = cgen_parse_address (cd, strp, opindex, code, 314883529b6Schristos &result_type, &value); 315883529b6Schristos if (errmsg == NULL) 316883529b6Schristos { 317883529b6Schristos if (result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) 318883529b6Schristos { 319883529b6Schristos /* Act as if we had done a PC-relative branch, ala .+num. */ 320883529b6Schristos char buf[20]; 321883529b6Schristos const char * bufp = (const char *) buf; 322883529b6Schristos 323883529b6Schristos sprintf (buf, ".+%ld", (long) value); 324883529b6Schristos errmsg = cgen_parse_address (cd, &bufp, opindex, code, &result_type, 325883529b6Schristos &value); 326883529b6Schristos } 327883529b6Schristos 328883529b6Schristos if (result_type == CGEN_PARSE_OPERAND_RESULT_QUEUED) 329883529b6Schristos { 330883529b6Schristos /* This will happen for things like (s2-s1) where s2 and s1 331883529b6Schristos are labels. */ 332883529b6Schristos /* Nothing further to be done. */ 333883529b6Schristos } 334883529b6Schristos else 335883529b6Schristos errmsg = _("Not a pc-relative address."); 336883529b6Schristos } 337883529b6Schristos return errmsg; 338883529b6Schristos} 339883529b6Schristos 340883529b6Schristos/* -- dis.c */ 341883529b6Schristos 342883529b6Schristos#define CGEN_PRINT_INSN epiphany_print_insn 343883529b6Schristos 344883529b6Schristosstatic int 345883529b6Schristosepiphany_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info) 346883529b6Schristos{ 347883529b6Schristos bfd_byte buf[CGEN_MAX_INSN_SIZE]; 348883529b6Schristos int buflen; 349883529b6Schristos int status; 350883529b6Schristos 351883529b6Schristos info->bytes_per_chunk = 2; 352*8cbf5cb7Schristos info->bytes_per_line = 4; 353883529b6Schristos 354883529b6Schristos /* Attempt to read the base part of the insn. */ 355*8cbf5cb7Schristos buflen = cd->base_insn_bitsize / 8; 356883529b6Schristos status = (*info->read_memory_func) (pc, buf, buflen, info); 357883529b6Schristos 358883529b6Schristos /* Try again with the minimum part, if min < base. */ 359883529b6Schristos if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize)) 360883529b6Schristos { 361*8cbf5cb7Schristos buflen = cd->min_insn_bitsize / 8; 362883529b6Schristos status = (*info->read_memory_func) (pc, buf, buflen, info); 363883529b6Schristos } 364883529b6Schristos 365883529b6Schristos if (status != 0) 366883529b6Schristos { 367883529b6Schristos (*info->memory_error_func) (status, pc, info); 368883529b6Schristos return -1; 369883529b6Schristos } 370883529b6Schristos 371883529b6Schristos return print_insn (cd, pc, info, buf, buflen); 372883529b6Schristos} 373883529b6Schristos 374883529b6Schristos 375883529b6Schristosstatic void 376883529b6Schristosprint_postindex (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 377883529b6Schristos void * dis_info, 378883529b6Schristos long value, 379883529b6Schristos unsigned int attrs ATTRIBUTE_UNUSED, 380883529b6Schristos bfd_vma pc ATTRIBUTE_UNUSED, 381883529b6Schristos int length ATTRIBUTE_UNUSED) 382883529b6Schristos{ 383883529b6Schristos disassemble_info *info = (disassemble_info *) dis_info; 384883529b6Schristos (*info->fprintf_func) (info->stream, value ? "-" : "+"); 385883529b6Schristos} 386883529b6Schristos 387883529b6Schristosstatic void 388883529b6Schristosprint_simm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 389883529b6Schristos void * dis_info, 390883529b6Schristos long value, 391883529b6Schristos unsigned int attrs ATTRIBUTE_UNUSED, 392883529b6Schristos bfd_vma pc ATTRIBUTE_UNUSED, 393883529b6Schristos int length ATTRIBUTE_UNUSED) 394883529b6Schristos{ 395883529b6Schristos print_address (cd, dis_info, value, attrs, pc, length); 396883529b6Schristos} 397883529b6Schristos 398883529b6Schristosstatic void 399883529b6Schristosprint_uimm_not_reg (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED, 400883529b6Schristos void * dis_info, 401883529b6Schristos unsigned long value, 402883529b6Schristos unsigned int attrs ATTRIBUTE_UNUSED, 403883529b6Schristos bfd_vma pc ATTRIBUTE_UNUSED, 404883529b6Schristos int length ATTRIBUTE_UNUSED) 405883529b6Schristos{ 406883529b6Schristos disassemble_info *info = (disassemble_info *)dis_info; 407883529b6Schristos 408883529b6Schristos if (value & 0x800) 409883529b6Schristos (*info->fprintf_func) (info->stream, "-"); 410883529b6Schristos 411883529b6Schristos value &= 0x7ff; 412883529b6Schristos print_address (cd, dis_info, value, attrs, pc, length); 413883529b6Schristos} 414883529b6Schristos 415883529b6Schristos 416883529b6Schristos/* -- */ 417883529b6Schristos 418