138889Sjdp/* Opcode table for the ARC. 2218822Sdim Copyright 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2004, 2005 385815Sobrien Free Software Foundation, Inc. 438889Sjdp Contributed by Doug Evans (dje@cygnus.com). 585815Sobrien 638889Sjdp This program is free software; you can redistribute it and/or modify 738889Sjdp it under the terms of the GNU General Public License as published by 838889Sjdp the Free Software Foundation; either version 2, or (at your option) 938889Sjdp any later version. 1038889Sjdp 1138889Sjdp This program is distributed in the hope that it will be useful, 1238889Sjdp but WITHOUT ANY WARRANTY; without even the implied warranty of 1338889Sjdp MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1438889Sjdp GNU General Public License for more details. 1538889Sjdp 1638889Sjdp You should have received a copy of the GNU General Public License 1785815Sobrien along with this program; if not, write to the Free Software Foundation, 18218822Sdim Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 1938889Sjdp 2089857Sobrien#include "sysdep.h" 2138889Sjdp#include <stdio.h> 2285815Sobrien#include "ansidecl.h" 23130561Sobrien#include "bfd.h" 2438889Sjdp#include "opcode/arc.h" 25218822Sdim#include "opintl.h" 2638889Sjdp 27218822Sdimenum operand {OP_NONE,OP_REG,OP_SHIMM,OP_LIMM}; 28218822Sdim 29218822Sdim#define OPERANDS 3 30218822Sdim 31218822Sdimenum operand ls_operand[OPERANDS]; 32218822Sdim 33218822Sdimstruct arc_opcode *arc_ext_opcodes; 34218822Sdimstruct arc_ext_operand_value *arc_ext_operands; 35218822Sdim 36218822Sdim#define LS_VALUE 0 37218822Sdim#define LS_DEST 0 38218822Sdim#define LS_BASE 1 39218822Sdim#define LS_OFFSET 2 40218822Sdim 41218822Sdim/* Given a format letter, yields the index into `arc_operands'. 42218822Sdim eg: arc_operand_map['a'] = REGA. */ 43218822Sdimunsigned char arc_operand_map[256]; 44218822Sdim 45218822Sdim/* Nonzero if we've seen an 'f' suffix (in certain insns). */ 46218822Sdimstatic int flag_p; 47218822Sdim 48218822Sdim/* Nonzero if we've finished processing the 'f' suffix. */ 49218822Sdimstatic int flagshimm_handled_p; 50218822Sdim 51218822Sdim/* Nonzero if we've seen a 'a' suffix (address writeback). */ 52218822Sdimstatic int addrwb_p; 53218822Sdim 54218822Sdim/* Nonzero if we've seen a 'q' suffix (condition code). */ 55218822Sdimstatic int cond_p; 56218822Sdim 57218822Sdim/* Nonzero if we've inserted a nullify condition. */ 58218822Sdimstatic int nullify_p; 59218822Sdim 60218822Sdim/* The value of the a nullify condition we inserted. */ 61218822Sdimstatic int nullify; 62218822Sdim 63218822Sdim/* Nonzero if we've inserted jumpflags. */ 64218822Sdimstatic int jumpflags_p; 65218822Sdim 66218822Sdim/* Nonzero if we've inserted a shimm. */ 67218822Sdimstatic int shimm_p; 68218822Sdim 69218822Sdim/* The value of the shimm we inserted (each insn only gets one but it can 70218822Sdim appear multiple times). */ 71218822Sdimstatic int shimm; 72218822Sdim 73218822Sdim/* Nonzero if we've inserted a limm (during assembly) or seen a limm 74218822Sdim (during disassembly). */ 75218822Sdimstatic int limm_p; 76218822Sdim 77218822Sdim/* The value of the limm we inserted. Each insn only gets one but it can 78218822Sdim appear multiple times. */ 79218822Sdimstatic long limm; 80218822Sdim 8138889Sjdp#define INSERT_FN(fn) \ 82218822Sdimstatic arc_insn fn (arc_insn, const struct arc_operand *, \ 83218822Sdim int, const struct arc_operand_value *, long, \ 84218822Sdim const char **) 85218822Sdim 8638889Sjdp#define EXTRACT_FN(fn) \ 87218822Sdimstatic long fn (arc_insn *, const struct arc_operand *, \ 88218822Sdim int, const struct arc_operand_value **, int *) 8938889Sjdp 9038889SjdpINSERT_FN (insert_reg); 9138889SjdpINSERT_FN (insert_shimmfinish); 9238889SjdpINSERT_FN (insert_limmfinish); 9385815SobrienINSERT_FN (insert_offset); 9485815SobrienINSERT_FN (insert_base); 9585815SobrienINSERT_FN (insert_st_syntax); 9685815SobrienINSERT_FN (insert_ld_syntax); 9785815SobrienINSERT_FN (insert_addr_wb); 9838889SjdpINSERT_FN (insert_flag); 9985815SobrienINSERT_FN (insert_nullify); 10038889SjdpINSERT_FN (insert_flagfinish); 10138889SjdpINSERT_FN (insert_cond); 10238889SjdpINSERT_FN (insert_forcelimm); 10338889SjdpINSERT_FN (insert_reladdr); 10438889SjdpINSERT_FN (insert_absaddr); 10585815SobrienINSERT_FN (insert_jumpflags); 10638889SjdpINSERT_FN (insert_unopmacro); 10738889Sjdp 10838889SjdpEXTRACT_FN (extract_reg); 10985815SobrienEXTRACT_FN (extract_ld_offset); 11085815SobrienEXTRACT_FN (extract_ld_syntax); 11185815SobrienEXTRACT_FN (extract_st_offset); 11285815SobrienEXTRACT_FN (extract_st_syntax); 11338889SjdpEXTRACT_FN (extract_flag); 11438889SjdpEXTRACT_FN (extract_cond); 11538889SjdpEXTRACT_FN (extract_reladdr); 11685815SobrienEXTRACT_FN (extract_jumpflags); 11738889SjdpEXTRACT_FN (extract_unopmacro); 11838889Sjdp 11938889Sjdp/* Various types of ARC operands, including insn suffixes. */ 12038889Sjdp 12138889Sjdp/* Insn format values: 12238889Sjdp 12338889Sjdp 'a' REGA register A field 12438889Sjdp 'b' REGB register B field 12538889Sjdp 'c' REGC register C field 12638889Sjdp 'S' SHIMMFINISH finish inserting a shimm value 12738889Sjdp 'L' LIMMFINISH finish inserting a limm value 12885815Sobrien 'o' OFFSET offset in st insns 12985815Sobrien 'O' OFFSET offset in ld insns 13085815Sobrien '0' SYNTAX_ST_NE enforce store insn syntax, no errors 13185815Sobrien '1' SYNTAX_LD_NE enforce load insn syntax, no errors 13285815Sobrien '2' SYNTAX_ST enforce store insn syntax, errors, last pattern only 13385815Sobrien '3' SYNTAX_LD enforce load insn syntax, errors, last pattern only 13485815Sobrien 's' BASE base in st insn 13538889Sjdp 'f' FLAG F flag 13638889Sjdp 'F' FLAGFINISH finish inserting the F flag 13738889Sjdp 'G' FLAGINSN insert F flag in "flag" insn 13838889Sjdp 'n' DELAY N field (nullify field) 13938889Sjdp 'q' COND condition code field 14038889Sjdp 'Q' FORCELIMM set `cond_p' to 1 to ensure a constant is a limm 14138889Sjdp 'B' BRANCH branch address (22 bit pc relative) 14238889Sjdp 'J' JUMP jump address (26 bit absolute) 14385815Sobrien 'j' JUMPFLAGS optional high order bits of 'J' 14438889Sjdp 'z' SIZE1 size field in ld a,[b,c] 14538889Sjdp 'Z' SIZE10 size field in ld a,[b,shimm] 14638889Sjdp 'y' SIZE22 size field in st c,[b,shimm] 14738889Sjdp 'x' SIGN0 sign extend field ld a,[b,c] 14838889Sjdp 'X' SIGN9 sign extend field ld a,[b,shimm] 14938889Sjdp 'w' ADDRESS3 write-back field in ld a,[b,c] 15038889Sjdp 'W' ADDRESS12 write-back field in ld a,[b,shimm] 15138889Sjdp 'v' ADDRESS24 write-back field in st c,[b,shimm] 15238889Sjdp 'e' CACHEBYPASS5 cache bypass in ld a,[b,c] 15338889Sjdp 'E' CACHEBYPASS14 cache bypass in ld a,[b,shimm] 15438889Sjdp 'D' CACHEBYPASS26 cache bypass in st c,[b,shimm] 15538889Sjdp 'U' UNOPMACRO fake operand to copy REGB to REGC for unop macros 15638889Sjdp 15738889Sjdp The following modifiers may appear between the % and char (eg: %.f): 15838889Sjdp 15938889Sjdp '.' MODDOT '.' prefix must be present 16038889Sjdp 'r' REG generic register value, for register table 16138889Sjdp 'A' AUXREG auxiliary register in lr a,[b], sr c,[b] 16238889Sjdp 16338889Sjdp Fields are: 16438889Sjdp 16585815Sobrien CHAR BITS SHIFT FLAGS INSERT_FN EXTRACT_FN */ 16638889Sjdp 16738889Sjdpconst struct arc_operand arc_operands[] = 16838889Sjdp{ 169218822Sdim/* Place holder (??? not sure if needed). */ 17038889Sjdp#define UNUSED 0 17185815Sobrien { 0, 0, 0, 0, 0, 0 }, 17238889Sjdp 173218822Sdim/* Register A or shimm/limm indicator. */ 17438889Sjdp#define REGA (UNUSED + 1) 17585815Sobrien { 'a', 6, ARC_SHIFT_REGA, ARC_OPERAND_SIGNED | ARC_OPERAND_ERROR, insert_reg, extract_reg }, 17638889Sjdp 177218822Sdim/* Register B or shimm/limm indicator. */ 17838889Sjdp#define REGB (REGA + 1) 17985815Sobrien { 'b', 6, ARC_SHIFT_REGB, ARC_OPERAND_SIGNED | ARC_OPERAND_ERROR, insert_reg, extract_reg }, 18038889Sjdp 181218822Sdim/* Register C or shimm/limm indicator. */ 18238889Sjdp#define REGC (REGB + 1) 18385815Sobrien { 'c', 6, ARC_SHIFT_REGC, ARC_OPERAND_SIGNED | ARC_OPERAND_ERROR, insert_reg, extract_reg }, 18438889Sjdp 185218822Sdim/* Fake operand used to insert shimm value into most instructions. */ 18638889Sjdp#define SHIMMFINISH (REGC + 1) 18738889Sjdp { 'S', 9, 0, ARC_OPERAND_SIGNED + ARC_OPERAND_FAKE, insert_shimmfinish, 0 }, 18838889Sjdp 189218822Sdim/* Fake operand used to insert limm value into most instructions. */ 19038889Sjdp#define LIMMFINISH (SHIMMFINISH + 1) 19138889Sjdp { 'L', 32, 32, ARC_OPERAND_ADDRESS + ARC_OPERAND_LIMM + ARC_OPERAND_FAKE, insert_limmfinish, 0 }, 19238889Sjdp 193218822Sdim/* Shimm operand when there is no reg indicator (st). */ 19485815Sobrien#define ST_OFFSET (LIMMFINISH + 1) 19585815Sobrien { 'o', 9, 0, ARC_OPERAND_LIMM | ARC_OPERAND_SIGNED | ARC_OPERAND_STORE, insert_offset, extract_st_offset }, 19638889Sjdp 197218822Sdim/* Shimm operand when there is no reg indicator (ld). */ 19885815Sobrien#define LD_OFFSET (ST_OFFSET + 1) 19985815Sobrien { 'O', 9, 0,ARC_OPERAND_LIMM | ARC_OPERAND_SIGNED | ARC_OPERAND_LOAD, insert_offset, extract_ld_offset }, 20038889Sjdp 201218822Sdim/* Operand for base. */ 20285815Sobrien#define BASE (LD_OFFSET + 1) 20385815Sobrien { 's', 6, ARC_SHIFT_REGB, ARC_OPERAND_LIMM | ARC_OPERAND_SIGNED, insert_base, extract_reg}, 20485815Sobrien 20585815Sobrien/* 0 enforce syntax for st insns. */ 20685815Sobrien#define SYNTAX_ST_NE (BASE + 1) 20785815Sobrien { '0', 9, 0, ARC_OPERAND_FAKE, insert_st_syntax, extract_st_syntax }, 20885815Sobrien 20985815Sobrien/* 1 enforce syntax for ld insns. */ 21085815Sobrien#define SYNTAX_LD_NE (SYNTAX_ST_NE + 1) 21185815Sobrien { '1', 9, 0, ARC_OPERAND_FAKE, insert_ld_syntax, extract_ld_syntax }, 21285815Sobrien 21385815Sobrien/* 0 enforce syntax for st insns. */ 21485815Sobrien#define SYNTAX_ST (SYNTAX_LD_NE + 1) 21585815Sobrien { '2', 9, 0, ARC_OPERAND_FAKE | ARC_OPERAND_ERROR, insert_st_syntax, extract_st_syntax }, 21685815Sobrien 21785815Sobrien/* 0 enforce syntax for ld insns. */ 21885815Sobrien#define SYNTAX_LD (SYNTAX_ST + 1) 21985815Sobrien { '3', 9, 0, ARC_OPERAND_FAKE | ARC_OPERAND_ERROR, insert_ld_syntax, extract_ld_syntax }, 22085815Sobrien 221218822Sdim/* Flag update bit (insertion is defered until we know how). */ 22285815Sobrien#define FLAG (SYNTAX_LD + 1) 22338889Sjdp { 'f', 1, 8, ARC_OPERAND_SUFFIX, insert_flag, extract_flag }, 22438889Sjdp 225218822Sdim/* Fake utility operand to finish 'f' suffix handling. */ 22638889Sjdp#define FLAGFINISH (FLAG + 1) 22738889Sjdp { 'F', 1, 8, ARC_OPERAND_FAKE, insert_flagfinish, 0 }, 22838889Sjdp 229218822Sdim/* Fake utility operand to set the 'f' flag for the "flag" insn. */ 23038889Sjdp#define FLAGINSN (FLAGFINISH + 1) 23138889Sjdp { 'G', 1, 8, ARC_OPERAND_FAKE, insert_flag, 0 }, 23238889Sjdp 233218822Sdim/* Branch delay types. */ 23438889Sjdp#define DELAY (FLAGINSN + 1) 23585815Sobrien { 'n', 2, 5, ARC_OPERAND_SUFFIX , insert_nullify, 0 }, 23638889Sjdp 237218822Sdim/* Conditions. */ 23838889Sjdp#define COND (DELAY + 1) 23938889Sjdp { 'q', 5, 0, ARC_OPERAND_SUFFIX, insert_cond, extract_cond }, 24038889Sjdp 241218822Sdim/* Set `cond_p' to 1 to ensure a constant is treated as a limm. */ 24238889Sjdp#define FORCELIMM (COND + 1) 24385815Sobrien { 'Q', 0, 0, ARC_OPERAND_FAKE, insert_forcelimm, 0 }, 24438889Sjdp 245218822Sdim/* Branch address; b, bl, and lp insns. */ 24638889Sjdp#define BRANCH (FORCELIMM + 1) 24785815Sobrien { 'B', 20, 7, (ARC_OPERAND_RELATIVE_BRANCH + ARC_OPERAND_SIGNED) | ARC_OPERAND_ERROR, insert_reladdr, extract_reladdr }, 24838889Sjdp 249218822Sdim/* Jump address; j insn (this is basically the same as 'L' except that the 25085815Sobrien value is right shifted by 2). */ 25138889Sjdp#define JUMP (BRANCH + 1) 25285815Sobrien { 'J', 24, 32, ARC_OPERAND_ERROR | (ARC_OPERAND_ABSOLUTE_BRANCH + ARC_OPERAND_LIMM + ARC_OPERAND_FAKE), insert_absaddr, 0 }, 25338889Sjdp 254218822Sdim/* Jump flags; j{,l} insn value or'ed into 'J' addr for flag values. */ 25585815Sobrien#define JUMPFLAGS (JUMP + 1) 25685815Sobrien { 'j', 6, 26, ARC_OPERAND_JUMPFLAGS | ARC_OPERAND_ERROR, insert_jumpflags, extract_jumpflags }, 25738889Sjdp 258218822Sdim/* Size field, stored in bit 1,2. */ 25985815Sobrien#define SIZE1 (JUMPFLAGS + 1) 26085815Sobrien { 'z', 2, 1, ARC_OPERAND_SUFFIX, 0, 0 }, 26185815Sobrien 262218822Sdim/* Size field, stored in bit 10,11. */ 26338889Sjdp#define SIZE10 (SIZE1 + 1) 26485815Sobrien { 'Z', 2, 10, ARC_OPERAND_SUFFIX, 0, 0 }, 26538889Sjdp 266218822Sdim/* Size field, stored in bit 22,23. */ 26738889Sjdp#define SIZE22 (SIZE10 + 1) 26885815Sobrien { 'y', 2, 22, ARC_OPERAND_SUFFIX, 0, 0 }, 26938889Sjdp 270218822Sdim/* Sign extend field, stored in bit 0. */ 27138889Sjdp#define SIGN0 (SIZE22 + 1) 27285815Sobrien { 'x', 1, 0, ARC_OPERAND_SUFFIX, 0, 0 }, 27338889Sjdp 274218822Sdim/* Sign extend field, stored in bit 9. */ 27538889Sjdp#define SIGN9 (SIGN0 + 1) 27685815Sobrien { 'X', 1, 9, ARC_OPERAND_SUFFIX, 0, 0 }, 27738889Sjdp 278218822Sdim/* Address write back, stored in bit 3. */ 27938889Sjdp#define ADDRESS3 (SIGN9 + 1) 28085815Sobrien { 'w', 1, 3, ARC_OPERAND_SUFFIX, insert_addr_wb, 0}, 28138889Sjdp 282218822Sdim/* Address write back, stored in bit 12. */ 28338889Sjdp#define ADDRESS12 (ADDRESS3 + 1) 28485815Sobrien { 'W', 1, 12, ARC_OPERAND_SUFFIX, insert_addr_wb, 0}, 28538889Sjdp 286218822Sdim/* Address write back, stored in bit 24. */ 28738889Sjdp#define ADDRESS24 (ADDRESS12 + 1) 28885815Sobrien { 'v', 1, 24, ARC_OPERAND_SUFFIX, insert_addr_wb, 0}, 28938889Sjdp 290218822Sdim/* Cache bypass, stored in bit 5. */ 29138889Sjdp#define CACHEBYPASS5 (ADDRESS24 + 1) 29285815Sobrien { 'e', 1, 5, ARC_OPERAND_SUFFIX, 0, 0 }, 29338889Sjdp 294218822Sdim/* Cache bypass, stored in bit 14. */ 29538889Sjdp#define CACHEBYPASS14 (CACHEBYPASS5 + 1) 29685815Sobrien { 'E', 1, 14, ARC_OPERAND_SUFFIX, 0, 0 }, 29738889Sjdp 298218822Sdim/* Cache bypass, stored in bit 26. */ 29938889Sjdp#define CACHEBYPASS26 (CACHEBYPASS14 + 1) 30085815Sobrien { 'D', 1, 26, ARC_OPERAND_SUFFIX, 0, 0 }, 30138889Sjdp 302218822Sdim/* Unop macro, used to copy REGB to REGC. */ 30338889Sjdp#define UNOPMACRO (CACHEBYPASS26 + 1) 30438889Sjdp { 'U', 6, ARC_SHIFT_REGC, ARC_OPERAND_FAKE, insert_unopmacro, extract_unopmacro }, 30538889Sjdp 30638889Sjdp/* '.' modifier ('.' required). */ 30738889Sjdp#define MODDOT (UNOPMACRO + 1) 30885815Sobrien { '.', 1, 0, ARC_MOD_DOT, 0, 0 }, 30938889Sjdp 31038889Sjdp/* Dummy 'r' modifier for the register table. 31138889Sjdp It's called a "dummy" because there's no point in inserting an 'r' into all 31238889Sjdp the %a/%b/%c occurrences in the insn table. */ 31338889Sjdp#define REG (MODDOT + 1) 31485815Sobrien { 'r', 6, 0, ARC_MOD_REG, 0, 0 }, 31538889Sjdp 31638889Sjdp/* Known auxiliary register modifier (stored in shimm field). */ 31738889Sjdp#define AUXREG (REG + 1) 31885815Sobrien { 'A', 9, 0, ARC_MOD_AUXREG, 0, 0 }, 31938889Sjdp 320218822Sdim/* End of list place holder. */ 32185815Sobrien { 0, 0, 0, 0, 0, 0 } 32238889Sjdp}; 32338889Sjdp 32438889Sjdp/* Insert a value into a register field. 32538889Sjdp If REG is NULL, then this is actually a constant. 32638889Sjdp 32738889Sjdp We must also handle auxiliary registers for lr/sr insns. */ 32838889Sjdp 32938889Sjdpstatic arc_insn 330218822Sdiminsert_reg (arc_insn insn, 331218822Sdim const struct arc_operand *operand, 332218822Sdim int mods, 333218822Sdim const struct arc_operand_value *reg, 334218822Sdim long value, 335218822Sdim const char **errmsg) 33638889Sjdp{ 33738889Sjdp static char buf[100]; 33885815Sobrien enum operand op_type = OP_NONE; 33938889Sjdp 34038889Sjdp if (reg == NULL) 34138889Sjdp { 34238889Sjdp /* We have a constant that also requires a value stored in a register 34338889Sjdp field. Handle these by updating the register field and saving the 34438889Sjdp value for later handling by either %S (shimm) or %L (limm). */ 34538889Sjdp 34638889Sjdp /* Try to use a shimm value before a limm one. */ 34738889Sjdp if (ARC_SHIMM_CONST_P (value) 34838889Sjdp /* If we've seen a conditional suffix we have to use a limm. */ 34938889Sjdp && !cond_p 35038889Sjdp /* If we already have a shimm value that is different than ours 35138889Sjdp we have to use a limm. */ 35238889Sjdp && (!shimm_p || shimm == value)) 35338889Sjdp { 35485815Sobrien int marker; 35585815Sobrien 35685815Sobrien op_type = OP_SHIMM; 357218822Sdim /* Forget about shimm as dest mlm. */ 35885815Sobrien 35985815Sobrien if ('a' != operand->fmt) 36085815Sobrien { 36185815Sobrien shimm_p = 1; 36285815Sobrien shimm = value; 36385815Sobrien flagshimm_handled_p = 1; 36485815Sobrien marker = flag_p ? ARC_REG_SHIMM_UPDATE : ARC_REG_SHIMM; 36585815Sobrien } 36685815Sobrien else 36785815Sobrien { 368218822Sdim /* Don't request flag setting on shimm as dest. */ 36985815Sobrien marker = ARC_REG_SHIMM; 37085815Sobrien } 37138889Sjdp insn |= marker << operand->shift; 37285815Sobrien /* insn |= value & 511; - done later. */ 37338889Sjdp } 37438889Sjdp /* We have to use a limm. If we've already seen one they must match. */ 37538889Sjdp else if (!limm_p || limm == value) 37638889Sjdp { 37785815Sobrien op_type = OP_LIMM; 37838889Sjdp limm_p = 1; 37938889Sjdp limm = value; 38038889Sjdp insn |= ARC_REG_LIMM << operand->shift; 38138889Sjdp /* The constant is stored later. */ 38238889Sjdp } 38338889Sjdp else 384218822Sdim *errmsg = _("unable to fit different valued constants into instruction"); 38538889Sjdp } 38638889Sjdp else 38738889Sjdp { 38838889Sjdp /* We have to handle both normal and auxiliary registers. */ 38938889Sjdp 39038889Sjdp if (reg->type == AUXREG) 39138889Sjdp { 39238889Sjdp if (!(mods & ARC_MOD_AUXREG)) 393218822Sdim *errmsg = _("auxiliary register not allowed here"); 39438889Sjdp else 39538889Sjdp { 396218822Sdim if ((insn & I(-1)) == I(2)) /* Check for use validity. */ 39785815Sobrien { 39885815Sobrien if (reg->flags & ARC_REGISTER_READONLY) 399218822Sdim *errmsg = _("attempt to set readonly register"); 40085815Sobrien } 40185815Sobrien else 40285815Sobrien { 40385815Sobrien if (reg->flags & ARC_REGISTER_WRITEONLY) 404218822Sdim *errmsg = _("attempt to read writeonly register"); 40585815Sobrien } 40638889Sjdp insn |= ARC_REG_SHIMM << operand->shift; 40738889Sjdp insn |= reg->value << arc_operands[reg->type].shift; 40838889Sjdp } 40938889Sjdp } 41038889Sjdp else 41138889Sjdp { 41285815Sobrien /* check for use validity. */ 41385815Sobrien if ('a' == operand->fmt || ((insn & I(-1)) < I(2))) 41485815Sobrien { 41585815Sobrien if (reg->flags & ARC_REGISTER_READONLY) 416218822Sdim *errmsg = _("attempt to set readonly register"); 41785815Sobrien } 41885815Sobrien if ('a' != operand->fmt) 41985815Sobrien { 42085815Sobrien if (reg->flags & ARC_REGISTER_WRITEONLY) 421218822Sdim *errmsg = _("attempt to read writeonly register"); 42285815Sobrien } 42338889Sjdp /* We should never get an invalid register number here. */ 42438889Sjdp if ((unsigned int) reg->value > 60) 42538889Sjdp { 426218822Sdim sprintf (buf, _("invalid register number `%d'"), reg->value); 42738889Sjdp *errmsg = buf; 42838889Sjdp } 42985815Sobrien insn |= reg->value << operand->shift; 43085815Sobrien op_type = OP_REG; 43138889Sjdp } 43238889Sjdp } 43338889Sjdp 43485815Sobrien switch (operand->fmt) 43585815Sobrien { 43685815Sobrien case 'a': 43785815Sobrien ls_operand[LS_DEST] = op_type; 43885815Sobrien break; 43985815Sobrien case 's': 44085815Sobrien ls_operand[LS_BASE] = op_type; 44185815Sobrien break; 44285815Sobrien case 'c': 44385815Sobrien if ((insn & I(-1)) == I(2)) 44485815Sobrien ls_operand[LS_VALUE] = op_type; 44585815Sobrien else 44685815Sobrien ls_operand[LS_OFFSET] = op_type; 44785815Sobrien break; 44885815Sobrien case 'o': case 'O': 44985815Sobrien ls_operand[LS_OFFSET] = op_type; 45085815Sobrien break; 45185815Sobrien } 45285815Sobrien 45338889Sjdp return insn; 45438889Sjdp} 45538889Sjdp 45638889Sjdp/* Called when we see an 'f' flag. */ 45738889Sjdp 45838889Sjdpstatic arc_insn 459218822Sdiminsert_flag (arc_insn insn, 460218822Sdim const struct arc_operand *operand ATTRIBUTE_UNUSED, 461218822Sdim int mods ATTRIBUTE_UNUSED, 462218822Sdim const struct arc_operand_value *reg ATTRIBUTE_UNUSED, 463218822Sdim long value ATTRIBUTE_UNUSED, 464218822Sdim const char **errmsg ATTRIBUTE_UNUSED) 46538889Sjdp{ 46638889Sjdp /* We can't store anything in the insn until we've parsed the registers. 46738889Sjdp Just record the fact that we've got this flag. `insert_reg' will use it 46838889Sjdp to store the correct value (ARC_REG_SHIMM_UPDATE or bit 0x100). */ 46938889Sjdp flag_p = 1; 47085815Sobrien return insn; 47185815Sobrien} 47238889Sjdp 47385815Sobrien/* Called when we see an nullify condition. */ 47485815Sobrien 47585815Sobrienstatic arc_insn 476218822Sdiminsert_nullify (arc_insn insn, 477218822Sdim const struct arc_operand *operand, 478218822Sdim int mods ATTRIBUTE_UNUSED, 479218822Sdim const struct arc_operand_value *reg ATTRIBUTE_UNUSED, 480218822Sdim long value, 481218822Sdim const char **errmsg ATTRIBUTE_UNUSED) 48285815Sobrien{ 48385815Sobrien nullify_p = 1; 48485815Sobrien insn |= (value & ((1 << operand->bits) - 1)) << operand->shift; 48585815Sobrien nullify = value; 48638889Sjdp return insn; 48738889Sjdp} 48838889Sjdp 48938889Sjdp/* Called after completely building an insn to ensure the 'f' flag gets set 49038889Sjdp properly. This is needed because we don't know how to set this flag until 49138889Sjdp we've parsed the registers. */ 49238889Sjdp 49338889Sjdpstatic arc_insn 494218822Sdiminsert_flagfinish (arc_insn insn, 495218822Sdim const struct arc_operand *operand, 496218822Sdim int mods ATTRIBUTE_UNUSED, 497218822Sdim const struct arc_operand_value *reg ATTRIBUTE_UNUSED, 498218822Sdim long value ATTRIBUTE_UNUSED, 499218822Sdim const char **errmsg ATTRIBUTE_UNUSED) 50038889Sjdp{ 50138889Sjdp if (flag_p && !flagshimm_handled_p) 50238889Sjdp { 50338889Sjdp if (shimm_p) 50438889Sjdp abort (); 50538889Sjdp flagshimm_handled_p = 1; 50638889Sjdp insn |= (1 << operand->shift); 50738889Sjdp } 50838889Sjdp return insn; 50938889Sjdp} 51038889Sjdp 51138889Sjdp/* Called when we see a conditional flag (eg: .eq). */ 51238889Sjdp 51338889Sjdpstatic arc_insn 514218822Sdiminsert_cond (arc_insn insn, 515218822Sdim const struct arc_operand *operand, 516218822Sdim int mods ATTRIBUTE_UNUSED, 517218822Sdim const struct arc_operand_value *reg ATTRIBUTE_UNUSED, 518218822Sdim long value, 519218822Sdim const char **errmsg ATTRIBUTE_UNUSED) 52038889Sjdp{ 52138889Sjdp cond_p = 1; 52238889Sjdp insn |= (value & ((1 << operand->bits) - 1)) << operand->shift; 52338889Sjdp return insn; 52438889Sjdp} 52538889Sjdp 52638889Sjdp/* Used in the "j" instruction to prevent constants from being interpreted as 52738889Sjdp shimm values (which the jump insn doesn't accept). This can also be used 52838889Sjdp to force the use of limm values in other situations (eg: ld r0,[foo] uses 52938889Sjdp this). 53038889Sjdp ??? The mechanism is sound. Access to it is a bit klunky right now. */ 53138889Sjdp 53238889Sjdpstatic arc_insn 533218822Sdiminsert_forcelimm (arc_insn insn, 534218822Sdim const struct arc_operand *operand ATTRIBUTE_UNUSED, 535218822Sdim int mods ATTRIBUTE_UNUSED, 536218822Sdim const struct arc_operand_value *reg ATTRIBUTE_UNUSED, 537218822Sdim long value ATTRIBUTE_UNUSED, 538218822Sdim const char **errmsg ATTRIBUTE_UNUSED) 53985815Sobrien{ 54085815Sobrien cond_p = 1; 54185815Sobrien return insn; 54285815Sobrien} 54385815Sobrien 54485815Sobrienstatic arc_insn 545218822Sdiminsert_addr_wb (arc_insn insn, 546218822Sdim const struct arc_operand *operand, 547218822Sdim int mods ATTRIBUTE_UNUSED, 548218822Sdim const struct arc_operand_value *reg ATTRIBUTE_UNUSED, 549218822Sdim long value ATTRIBUTE_UNUSED, 550218822Sdim const char **errmsg ATTRIBUTE_UNUSED) 55185815Sobrien{ 55285815Sobrien addrwb_p = 1 << operand->shift; 55385815Sobrien return insn; 55485815Sobrien} 55585815Sobrien 55685815Sobrienstatic arc_insn 557218822Sdiminsert_base (arc_insn insn, 558218822Sdim const struct arc_operand *operand, 559218822Sdim int mods, 560218822Sdim const struct arc_operand_value *reg, 561218822Sdim long value, 562218822Sdim const char **errmsg) 56338889Sjdp{ 56485815Sobrien if (reg != NULL) 56585815Sobrien { 56685815Sobrien arc_insn myinsn; 56785815Sobrien myinsn = insert_reg (0, operand,mods, reg, value, errmsg) >> operand->shift; 56885815Sobrien insn |= B(myinsn); 56985815Sobrien ls_operand[LS_BASE] = OP_REG; 57085815Sobrien } 57185815Sobrien else if (ARC_SHIMM_CONST_P (value) && !cond_p) 57285815Sobrien { 57385815Sobrien if (shimm_p && value != shimm) 57485815Sobrien { 575218822Sdim /* Convert the previous shimm operand to a limm. */ 57685815Sobrien limm_p = 1; 57785815Sobrien limm = shimm; 578218822Sdim insn &= ~C(-1); /* We know where the value is in insn. */ 57985815Sobrien insn |= C(ARC_REG_LIMM); 58085815Sobrien ls_operand[LS_VALUE] = OP_LIMM; 58185815Sobrien } 58285815Sobrien insn |= ARC_REG_SHIMM << operand->shift; 58385815Sobrien shimm_p = 1; 58485815Sobrien shimm = value; 58585815Sobrien ls_operand[LS_BASE] = OP_SHIMM; 586218822Sdim ls_operand[LS_OFFSET] = OP_SHIMM; 58785815Sobrien } 58885815Sobrien else 58985815Sobrien { 59085815Sobrien if (limm_p && value != limm) 59185815Sobrien { 592218822Sdim *errmsg = _("too many long constants"); 59385815Sobrien return insn; 59485815Sobrien } 59585815Sobrien limm_p = 1; 59685815Sobrien limm = value; 59785815Sobrien insn |= B(ARC_REG_LIMM); 59885815Sobrien ls_operand[LS_BASE] = OP_LIMM; 59985815Sobrien } 60085815Sobrien 60138889Sjdp return insn; 60238889Sjdp} 60338889Sjdp 60485815Sobrien/* Used in ld/st insns to handle the offset field. We don't try to 60585815Sobrien match operand syntax here. we catch bad combinations later. */ 60638889Sjdp 60738889Sjdpstatic arc_insn 608218822Sdiminsert_offset (arc_insn insn, 609218822Sdim const struct arc_operand *operand, 610218822Sdim int mods, 611218822Sdim const struct arc_operand_value *reg, 612218822Sdim long value, 613218822Sdim const char **errmsg) 61438889Sjdp{ 61538889Sjdp long minval, maxval; 61638889Sjdp 61738889Sjdp if (reg != NULL) 61838889Sjdp { 61985815Sobrien arc_insn myinsn; 62085815Sobrien myinsn = insert_reg (0,operand,mods,reg,value,errmsg) >> operand->shift; 62185815Sobrien ls_operand[LS_OFFSET] = OP_REG; 622218822Sdim if (operand->flags & ARC_OPERAND_LOAD) /* Not if store, catch it later. */ 623218822Sdim if ((insn & I(-1)) != I(1)) /* Not if opcode == 1, catch it later. */ 624218822Sdim insn |= C (myinsn); 62538889Sjdp } 62638889Sjdp else 62738889Sjdp { 62838889Sjdp /* This is *way* more general than necessary, but maybe some day it'll 62938889Sjdp be useful. */ 63038889Sjdp if (operand->flags & ARC_OPERAND_SIGNED) 63138889Sjdp { 63238889Sjdp minval = -(1 << (operand->bits - 1)); 63338889Sjdp maxval = (1 << (operand->bits - 1)) - 1; 63438889Sjdp } 63538889Sjdp else 63638889Sjdp { 63738889Sjdp minval = 0; 63838889Sjdp maxval = (1 << operand->bits) - 1; 63938889Sjdp } 64085815Sobrien if ((cond_p && !limm_p) || (value < minval || value > maxval)) 64138889Sjdp { 64285815Sobrien if (limm_p && value != limm) 643218822Sdim *errmsg = _("too many long constants"); 644218822Sdim 64585815Sobrien else 64685815Sobrien { 64785815Sobrien limm_p = 1; 64885815Sobrien limm = value; 64985815Sobrien if (operand->flags & ARC_OPERAND_STORE) 65085815Sobrien insn |= B(ARC_REG_LIMM); 65185815Sobrien if (operand->flags & ARC_OPERAND_LOAD) 65285815Sobrien insn |= C(ARC_REG_LIMM); 65385815Sobrien ls_operand[LS_OFFSET] = OP_LIMM; 65485815Sobrien } 65538889Sjdp } 65638889Sjdp else 65785815Sobrien { 65885815Sobrien if ((value < minval || value > maxval)) 65985815Sobrien *errmsg = "need too many limms"; 66085815Sobrien else if (shimm_p && value != shimm) 66185815Sobrien { 662218822Sdim /* Check for bad operand combinations 663218822Sdim before we lose info about them. */ 66485815Sobrien if ((insn & I(-1)) == I(1)) 66585815Sobrien { 666218822Sdim *errmsg = _("to many shimms in load"); 66785815Sobrien goto out; 66885815Sobrien } 66985815Sobrien if (limm_p && operand->flags & ARC_OPERAND_LOAD) 67085815Sobrien { 671218822Sdim *errmsg = _("too many long constants"); 67285815Sobrien goto out; 67385815Sobrien } 674218822Sdim /* Convert what we thought was a shimm to a limm. */ 67585815Sobrien limm_p = 1; 67685815Sobrien limm = shimm; 677218822Sdim if (ls_operand[LS_VALUE] == OP_SHIMM 678218822Sdim && operand->flags & ARC_OPERAND_STORE) 67985815Sobrien { 68085815Sobrien insn &= ~C(-1); 68185815Sobrien insn |= C(ARC_REG_LIMM); 68285815Sobrien ls_operand[LS_VALUE] = OP_LIMM; 68385815Sobrien } 684218822Sdim if (ls_operand[LS_BASE] == OP_SHIMM 685218822Sdim && operand->flags & ARC_OPERAND_STORE) 68685815Sobrien { 68785815Sobrien insn &= ~B(-1); 68885815Sobrien insn |= B(ARC_REG_LIMM); 68985815Sobrien ls_operand[LS_BASE] = OP_LIMM; 69085815Sobrien } 69185815Sobrien } 69285815Sobrien shimm = value; 69385815Sobrien shimm_p = 1; 69485815Sobrien ls_operand[LS_OFFSET] = OP_SHIMM; 69585815Sobrien } 69638889Sjdp } 69785815Sobrien out: 69838889Sjdp return insn; 69938889Sjdp} 70038889Sjdp 70185815Sobrien/* Used in st insns to do final disasemble syntax check. */ 70238889Sjdp 70385815Sobrienstatic long 704218822Sdimextract_st_syntax (arc_insn *insn, 705218822Sdim const struct arc_operand *operand ATTRIBUTE_UNUSED, 706218822Sdim int mods ATTRIBUTE_UNUSED, 707218822Sdim const struct arc_operand_value **opval ATTRIBUTE_UNUSED, 708218822Sdim int *invalid) 70985815Sobrien{ 71085815Sobrien#define ST_SYNTAX(V,B,O) \ 71185815Sobrien((ls_operand[LS_VALUE] == (V) && \ 71285815Sobrien ls_operand[LS_BASE] == (B) && \ 71385815Sobrien ls_operand[LS_OFFSET] == (O))) 71485815Sobrien 71585815Sobrien if (!((ST_SYNTAX(OP_REG,OP_REG,OP_NONE) && (insn[0] & 511) == 0) 71685815Sobrien || ST_SYNTAX(OP_REG,OP_LIMM,OP_NONE) 71785815Sobrien || (ST_SYNTAX(OP_SHIMM,OP_REG,OP_NONE) && (insn[0] & 511) == 0) 71885815Sobrien || (ST_SYNTAX(OP_SHIMM,OP_SHIMM,OP_NONE) && (insn[0] & 511) == 0) 71985815Sobrien || ST_SYNTAX(OP_SHIMM,OP_LIMM,OP_NONE) 72085815Sobrien || ST_SYNTAX(OP_SHIMM,OP_LIMM,OP_SHIMM) 72185815Sobrien || ST_SYNTAX(OP_SHIMM,OP_SHIMM,OP_SHIMM) 72285815Sobrien || (ST_SYNTAX(OP_LIMM,OP_REG,OP_NONE) && (insn[0] & 511) == 0) 72385815Sobrien || ST_SYNTAX(OP_REG,OP_REG,OP_SHIMM) 72485815Sobrien || ST_SYNTAX(OP_REG,OP_SHIMM,OP_SHIMM) 72585815Sobrien || ST_SYNTAX(OP_SHIMM,OP_REG,OP_SHIMM) 72685815Sobrien || ST_SYNTAX(OP_LIMM,OP_SHIMM,OP_SHIMM) 72785815Sobrien || ST_SYNTAX(OP_LIMM,OP_SHIMM,OP_NONE) 72885815Sobrien || ST_SYNTAX(OP_LIMM,OP_REG,OP_SHIMM))) 72985815Sobrien *invalid = 1; 73085815Sobrien return 0; 73185815Sobrien} 73285815Sobrien 73385815Sobrienint 734218822Sdimarc_limm_fixup_adjust (arc_insn insn) 73585815Sobrien{ 73685815Sobrien int retval = 0; 73785815Sobrien 738218822Sdim /* Check for st shimm,[limm]. */ 73985815Sobrien if ((insn & (I(-1) | C(-1) | B(-1))) == 74085815Sobrien (I(2) | C(ARC_REG_SHIMM) | B(ARC_REG_LIMM))) 74185815Sobrien { 74285815Sobrien retval = insn & 0x1ff; 743218822Sdim if (retval & 0x100) /* Sign extend 9 bit offset. */ 74485815Sobrien retval |= ~0x1ff; 74585815Sobrien } 746218822Sdim return -retval; /* Negate offset for return. */ 74785815Sobrien} 74885815Sobrien 74985815Sobrien/* Used in st insns to do final syntax check. */ 75085815Sobrien 75138889Sjdpstatic arc_insn 752218822Sdiminsert_st_syntax (arc_insn insn, 753218822Sdim const struct arc_operand *operand ATTRIBUTE_UNUSED, 754218822Sdim int mods ATTRIBUTE_UNUSED, 755218822Sdim const struct arc_operand_value *reg ATTRIBUTE_UNUSED, 756218822Sdim long value ATTRIBUTE_UNUSED, 757218822Sdim const char **errmsg) 75838889Sjdp{ 759218822Sdim if (ST_SYNTAX (OP_SHIMM,OP_REG,OP_NONE) && shimm != 0) 76085815Sobrien { 761218822Sdim /* Change an illegal insn into a legal one, it's easier to 76285815Sobrien do it here than to try to handle it during operand scan. */ 76385815Sobrien limm_p = 1; 76485815Sobrien limm = shimm; 76585815Sobrien shimm_p = 0; 76685815Sobrien shimm = 0; 76785815Sobrien insn = insn & ~(C(-1) | 511); 76885815Sobrien insn |= ARC_REG_LIMM << ARC_SHIFT_REGC; 76985815Sobrien ls_operand[LS_VALUE] = OP_LIMM; 77085815Sobrien } 77185815Sobrien 772218822Sdim if (ST_SYNTAX (OP_REG, OP_SHIMM, OP_NONE) 773218822Sdim || ST_SYNTAX (OP_LIMM, OP_SHIMM, OP_NONE)) 77485815Sobrien { 775218822Sdim /* Try to salvage this syntax. */ 776218822Sdim if (shimm & 0x1) /* Odd shimms won't work. */ 77785815Sobrien { 778218822Sdim if (limm_p) /* Do we have a limm already? */ 779218822Sdim *errmsg = _("impossible store"); 780218822Sdim 78185815Sobrien limm_p = 1; 78285815Sobrien limm = shimm; 78385815Sobrien shimm = 0; 78485815Sobrien shimm_p = 0; 78585815Sobrien insn = insn & ~(B(-1) | 511); 78685815Sobrien insn |= B(ARC_REG_LIMM); 78785815Sobrien ls_operand[LS_BASE] = OP_LIMM; 78885815Sobrien } 78985815Sobrien else 79085815Sobrien { 79185815Sobrien shimm >>= 1; 79285815Sobrien insn = insn & ~511; 79385815Sobrien insn |= shimm; 79485815Sobrien ls_operand[LS_OFFSET] = OP_SHIMM; 79585815Sobrien } 79685815Sobrien } 79785815Sobrien if (ST_SYNTAX(OP_SHIMM,OP_LIMM,OP_NONE)) 798218822Sdim limm += arc_limm_fixup_adjust(insn); 799218822Sdim 800218822Sdim if (! (ST_SYNTAX (OP_REG,OP_REG,OP_NONE) 801218822Sdim || ST_SYNTAX (OP_REG,OP_LIMM,OP_NONE) 802218822Sdim || ST_SYNTAX (OP_REG,OP_REG,OP_SHIMM) 803218822Sdim || ST_SYNTAX (OP_REG,OP_SHIMM,OP_SHIMM) 804218822Sdim || (ST_SYNTAX (OP_SHIMM,OP_SHIMM,OP_NONE) && (shimm == 0)) 805218822Sdim || ST_SYNTAX (OP_SHIMM,OP_LIMM,OP_NONE) 806218822Sdim || ST_SYNTAX (OP_SHIMM,OP_REG,OP_NONE) 807218822Sdim || ST_SYNTAX (OP_SHIMM,OP_REG,OP_SHIMM) 808218822Sdim || ST_SYNTAX (OP_SHIMM,OP_SHIMM,OP_SHIMM) 809218822Sdim || ST_SYNTAX (OP_LIMM,OP_SHIMM,OP_SHIMM) 810218822Sdim || ST_SYNTAX (OP_LIMM,OP_REG,OP_NONE) 811218822Sdim || ST_SYNTAX (OP_LIMM,OP_REG,OP_SHIMM))) 812218822Sdim *errmsg = _("st operand error"); 81385815Sobrien if (addrwb_p) 81485815Sobrien { 81585815Sobrien if (ls_operand[LS_BASE] != OP_REG) 816218822Sdim *errmsg = _("address writeback not allowed"); 81785815Sobrien insn |= addrwb_p; 81885815Sobrien } 81985815Sobrien if (ST_SYNTAX(OP_SHIMM,OP_REG,OP_NONE) && shimm) 820218822Sdim *errmsg = _("store value must be zero"); 82138889Sjdp return insn; 82238889Sjdp} 82338889Sjdp 82485815Sobrien/* Used in ld insns to do final syntax check. */ 82585815Sobrien 82685815Sobrienstatic arc_insn 827218822Sdiminsert_ld_syntax (arc_insn insn, 828218822Sdim const struct arc_operand *operand ATTRIBUTE_UNUSED, 829218822Sdim int mods ATTRIBUTE_UNUSED, 830218822Sdim const struct arc_operand_value *reg ATTRIBUTE_UNUSED, 831218822Sdim long value ATTRIBUTE_UNUSED, 832218822Sdim const char **errmsg) 83385815Sobrien{ 834218822Sdim#define LD_SYNTAX(D, B, O) \ 835218822Sdim ( (ls_operand[LS_DEST] == (D) \ 836218822Sdim && ls_operand[LS_BASE] == (B) \ 837218822Sdim && ls_operand[LS_OFFSET] == (O))) 83885815Sobrien 839218822Sdim int test = insn & I (-1); 84085815Sobrien 841218822Sdim if (!(test == I (1))) 84285815Sobrien { 84385815Sobrien if ((ls_operand[LS_DEST] == OP_SHIMM || ls_operand[LS_BASE] == OP_SHIMM 84485815Sobrien || ls_operand[LS_OFFSET] == OP_SHIMM)) 845218822Sdim *errmsg = _("invalid load/shimm insn"); 84685815Sobrien } 84785815Sobrien if (!(LD_SYNTAX(OP_REG,OP_REG,OP_NONE) 84885815Sobrien || LD_SYNTAX(OP_REG,OP_REG,OP_REG) 84985815Sobrien || LD_SYNTAX(OP_REG,OP_REG,OP_SHIMM) 85085815Sobrien || (LD_SYNTAX(OP_REG,OP_LIMM,OP_REG) && !(test == I(1))) 85185815Sobrien || (LD_SYNTAX(OP_REG,OP_REG,OP_LIMM) && !(test == I(1))) 85285815Sobrien || LD_SYNTAX(OP_REG,OP_SHIMM,OP_SHIMM) 85385815Sobrien || (LD_SYNTAX(OP_REG,OP_LIMM,OP_NONE) && (test == I(1))))) 854218822Sdim *errmsg = _("ld operand error"); 85585815Sobrien if (addrwb_p) 85685815Sobrien { 85785815Sobrien if (ls_operand[LS_BASE] != OP_REG) 858218822Sdim *errmsg = _("address writeback not allowed"); 85985815Sobrien insn |= addrwb_p; 86085815Sobrien } 86185815Sobrien return insn; 86285815Sobrien} 86385815Sobrien 86485815Sobrien/* Used in ld insns to do final syntax check. */ 86585815Sobrien 86685815Sobrienstatic long 867218822Sdimextract_ld_syntax (arc_insn *insn, 868218822Sdim const struct arc_operand *operand ATTRIBUTE_UNUSED, 869218822Sdim int mods ATTRIBUTE_UNUSED, 870218822Sdim const struct arc_operand_value **opval ATTRIBUTE_UNUSED, 871218822Sdim int *invalid) 87285815Sobrien{ 87385815Sobrien int test = insn[0] & I(-1); 87485815Sobrien 87585815Sobrien if (!(test == I(1))) 87685815Sobrien { 87785815Sobrien if ((ls_operand[LS_DEST] == OP_SHIMM || ls_operand[LS_BASE] == OP_SHIMM 87885815Sobrien || ls_operand[LS_OFFSET] == OP_SHIMM)) 87985815Sobrien *invalid = 1; 88085815Sobrien } 881218822Sdim if (!( (LD_SYNTAX (OP_REG, OP_REG, OP_NONE) && (test == I(1))) 882218822Sdim || LD_SYNTAX (OP_REG, OP_REG, OP_REG) 883218822Sdim || LD_SYNTAX (OP_REG, OP_REG, OP_SHIMM) 884218822Sdim || (LD_SYNTAX (OP_REG, OP_REG, OP_LIMM) && !(test == I(1))) 885218822Sdim || (LD_SYNTAX (OP_REG, OP_LIMM, OP_REG) && !(test == I(1))) 886218822Sdim || (LD_SYNTAX (OP_REG, OP_SHIMM, OP_NONE) && (shimm == 0)) 887218822Sdim || LD_SYNTAX (OP_REG, OP_SHIMM, OP_SHIMM) 888218822Sdim || (LD_SYNTAX (OP_REG, OP_LIMM, OP_NONE) && (test == I(1))))) 88985815Sobrien *invalid = 1; 89085815Sobrien return 0; 89185815Sobrien} 89285815Sobrien 89338889Sjdp/* Called at the end of processing normal insns (eg: add) to insert a shimm 89438889Sjdp value (if present) into the insn. */ 89538889Sjdp 89638889Sjdpstatic arc_insn 897218822Sdiminsert_shimmfinish (arc_insn insn, 898218822Sdim const struct arc_operand *operand, 899218822Sdim int mods ATTRIBUTE_UNUSED, 900218822Sdim const struct arc_operand_value *reg ATTRIBUTE_UNUSED, 901218822Sdim long value ATTRIBUTE_UNUSED, 902218822Sdim const char **errmsg ATTRIBUTE_UNUSED) 90338889Sjdp{ 90438889Sjdp if (shimm_p) 90538889Sjdp insn |= (shimm & ((1 << operand->bits) - 1)) << operand->shift; 90638889Sjdp return insn; 90738889Sjdp} 90838889Sjdp 90938889Sjdp/* Called at the end of processing normal insns (eg: add) to insert a limm 91038889Sjdp value (if present) into the insn. 91138889Sjdp 91238889Sjdp Note that this function is only intended to handle instructions (with 4 byte 91338889Sjdp immediate operands). It is not intended to handle data. */ 91438889Sjdp 91538889Sjdp/* ??? Actually, there's nothing for us to do as we can't call frag_more, the 91638889Sjdp caller must do that. The extract fns take a pointer to two words. The 91738889Sjdp insert fns could be converted and then we could do something useful, but 91838889Sjdp then the reloc handlers would have to know to work on the second word of 91938889Sjdp a 2 word quantity. That's too much so we don't handle them. */ 92038889Sjdp 92138889Sjdpstatic arc_insn 922218822Sdiminsert_limmfinish (arc_insn insn, 923218822Sdim const struct arc_operand *operand ATTRIBUTE_UNUSED, 924218822Sdim int mods ATTRIBUTE_UNUSED, 925218822Sdim const struct arc_operand_value *reg ATTRIBUTE_UNUSED, 926218822Sdim long value ATTRIBUTE_UNUSED, 927218822Sdim const char **errmsg ATTRIBUTE_UNUSED) 92885815Sobrien{ 92985815Sobrien return insn; 93085815Sobrien} 93185815Sobrien 93285815Sobrienstatic arc_insn 933218822Sdiminsert_jumpflags (arc_insn insn, 934218822Sdim const struct arc_operand *operand, 935218822Sdim int mods ATTRIBUTE_UNUSED, 936218822Sdim const struct arc_operand_value *reg ATTRIBUTE_UNUSED, 937218822Sdim long value, 938218822Sdim const char **errmsg) 93938889Sjdp{ 94085815Sobrien if (!flag_p) 941218822Sdim *errmsg = _("jump flags, but no .f seen"); 942218822Sdim 943218822Sdim else if (!limm_p) 944218822Sdim *errmsg = _("jump flags, but no limm addr"); 945218822Sdim 946218822Sdim else if (limm & 0xfc000000) 947218822Sdim *errmsg = _("flag bits of jump address limm lost"); 948218822Sdim 949218822Sdim else if (limm & 0x03000000) 950218822Sdim *errmsg = _("attempt to set HR bits"); 951218822Sdim 952218822Sdim else if ((value & ((1 << operand->bits) - 1)) != value) 953218822Sdim *errmsg = _("bad jump flags value"); 954218822Sdim 95585815Sobrien jumpflags_p = 1; 95685815Sobrien limm = ((limm & ((1 << operand->shift) - 1)) 95785815Sobrien | ((value & ((1 << operand->bits) - 1)) << operand->shift)); 95838889Sjdp return insn; 95938889Sjdp} 96038889Sjdp 96138889Sjdp/* Called at the end of unary operand macros to copy the B field to C. */ 96238889Sjdp 96338889Sjdpstatic arc_insn 964218822Sdiminsert_unopmacro (arc_insn insn, 965218822Sdim const struct arc_operand *operand, 966218822Sdim int mods ATTRIBUTE_UNUSED, 967218822Sdim const struct arc_operand_value *reg ATTRIBUTE_UNUSED, 968218822Sdim long value ATTRIBUTE_UNUSED, 969218822Sdim const char **errmsg ATTRIBUTE_UNUSED) 97038889Sjdp{ 97138889Sjdp insn |= ((insn >> ARC_SHIFT_REGB) & ARC_MASK_REG) << operand->shift; 97238889Sjdp return insn; 97338889Sjdp} 97438889Sjdp 97538889Sjdp/* Insert a relative address for a branch insn (b, bl, or lp). */ 97638889Sjdp 97738889Sjdpstatic arc_insn 978218822Sdiminsert_reladdr (arc_insn insn, 979218822Sdim const struct arc_operand *operand, 980218822Sdim int mods ATTRIBUTE_UNUSED, 981218822Sdim const struct arc_operand_value *reg ATTRIBUTE_UNUSED, 982218822Sdim long value, 983218822Sdim const char **errmsg) 98438889Sjdp{ 98538889Sjdp if (value & 3) 986218822Sdim *errmsg = _("branch address not on 4 byte boundary"); 98738889Sjdp insn |= ((value >> 2) & ((1 << operand->bits) - 1)) << operand->shift; 98838889Sjdp return insn; 98938889Sjdp} 99038889Sjdp 99138889Sjdp/* Insert a limm value as a 26 bit address right shifted 2 into the insn. 99238889Sjdp 99338889Sjdp Note that this function is only intended to handle instructions (with 4 byte 99438889Sjdp immediate operands). It is not intended to handle data. */ 99538889Sjdp 99685815Sobrien/* ??? Actually, there's little for us to do as we can't call frag_more, the 99738889Sjdp caller must do that. The extract fns take a pointer to two words. The 99838889Sjdp insert fns could be converted and then we could do something useful, but 99938889Sjdp then the reloc handlers would have to know to work on the second word of 100085815Sobrien a 2 word quantity. That's too much so we don't handle them. 100138889Sjdp 100285815Sobrien We do check for correct usage of the nullify suffix, or we 100385815Sobrien set the default correctly, though. */ 100485815Sobrien 100538889Sjdpstatic arc_insn 1006218822Sdiminsert_absaddr (arc_insn insn, 1007218822Sdim const struct arc_operand *operand ATTRIBUTE_UNUSED, 1008218822Sdim int mods ATTRIBUTE_UNUSED, 1009218822Sdim const struct arc_operand_value *reg ATTRIBUTE_UNUSED, 1010218822Sdim long value ATTRIBUTE_UNUSED, 1011218822Sdim const char **errmsg) 101238889Sjdp{ 101338889Sjdp if (limm_p) 101485815Sobrien { 1015218822Sdim /* If it is a jump and link, .jd must be specified. */ 1016218822Sdim if (insn & R (-1, 9, 1)) 101785815Sobrien { 101885815Sobrien if (!nullify_p) 1019218822Sdim insn |= 0x02 << 5; /* Default nullify to .jd. */ 1020218822Sdim 1021218822Sdim else if (nullify != 0x02) 1022218822Sdim *errmsg = _("must specify .jd or no nullify suffix"); 102385815Sobrien } 102485815Sobrien } 102538889Sjdp return insn; 102638889Sjdp} 102738889Sjdp 102838889Sjdp/* Extraction functions. 102938889Sjdp 103038889Sjdp The suffix extraction functions' return value is redundant since it can be 103138889Sjdp obtained from (*OPVAL)->value. However, the boolean suffixes don't have 103238889Sjdp a suffix table entry for the "false" case, so values of zero must be 103338889Sjdp obtained from the return value (*OPVAL == NULL). */ 103438889Sjdp 103538889Sjdp/* Called by the disassembler before printing an instruction. */ 103638889Sjdp 103738889Sjdpvoid 1038218822Sdimarc_opcode_init_extract (void) 103938889Sjdp{ 1040218822Sdim arc_opcode_init_insert (); 104138889Sjdp} 104238889Sjdp 1043218822Sdimstatic const struct arc_operand_value * 1044218822Sdimlookup_register (int type, long regno) 1045218822Sdim{ 1046218822Sdim const struct arc_operand_value *r,*end; 1047218822Sdim struct arc_ext_operand_value *ext_oper = arc_ext_operands; 1048218822Sdim 1049218822Sdim while (ext_oper) 1050218822Sdim { 1051218822Sdim if (ext_oper->operand.type == type && ext_oper->operand.value == regno) 1052218822Sdim return (&ext_oper->operand); 1053218822Sdim ext_oper = ext_oper->next; 1054218822Sdim } 1055218822Sdim 1056218822Sdim if (type == REG) 1057218822Sdim return &arc_reg_names[regno]; 1058218822Sdim 1059218822Sdim /* ??? This is a little slow and can be speeded up. */ 1060218822Sdim for (r = arc_reg_names, end = arc_reg_names + arc_reg_names_count; 1061218822Sdim r < end; ++r) 1062218822Sdim if (type == r->type && regno == r->value) 1063218822Sdim return r; 1064218822Sdim return 0; 1065218822Sdim} 1066218822Sdim 106738889Sjdp/* As we're extracting registers, keep an eye out for the 'f' indicator 106838889Sjdp (ARC_REG_SHIMM_UPDATE). If we find a register (not a constant marker, 106938889Sjdp like ARC_REG_SHIMM), set OPVAL so our caller will know this is a register. 107038889Sjdp 107138889Sjdp We must also handle auxiliary registers for lr/sr insns. They are just 107238889Sjdp constants with special names. */ 107338889Sjdp 107438889Sjdpstatic long 1075218822Sdimextract_reg (arc_insn *insn, 1076218822Sdim const struct arc_operand *operand, 1077218822Sdim int mods, 1078218822Sdim const struct arc_operand_value **opval, 1079218822Sdim int *invalid ATTRIBUTE_UNUSED) 108038889Sjdp{ 108138889Sjdp int regno; 108238889Sjdp long value; 108385815Sobrien enum operand op_type; 108438889Sjdp 108538889Sjdp /* Get the register number. */ 108685815Sobrien regno = (*insn >> operand->shift) & ((1 << operand->bits) - 1); 108738889Sjdp 108838889Sjdp /* Is it a constant marker? */ 108938889Sjdp if (regno == ARC_REG_SHIMM) 109038889Sjdp { 109185815Sobrien op_type = OP_SHIMM; 1092218822Sdim /* Always return zero if dest is a shimm mlm. */ 109385815Sobrien 109485815Sobrien if ('a' != operand->fmt) 109585815Sobrien { 109685815Sobrien value = *insn & 511; 109785815Sobrien if ((operand->flags & ARC_OPERAND_SIGNED) 109885815Sobrien && (value & 256)) 109985815Sobrien value -= 512; 110085815Sobrien if (!flagshimm_handled_p) 110185815Sobrien flag_p = 0; 110285815Sobrien flagshimm_handled_p = 1; 110385815Sobrien } 110485815Sobrien else 1105218822Sdim value = 0; 110638889Sjdp } 110738889Sjdp else if (regno == ARC_REG_SHIMM_UPDATE) 110838889Sjdp { 110985815Sobrien op_type = OP_SHIMM; 111085815Sobrien 1111218822Sdim /* Always return zero if dest is a shimm mlm. */ 111285815Sobrien if ('a' != operand->fmt) 111385815Sobrien { 111485815Sobrien value = *insn & 511; 111585815Sobrien if ((operand->flags & ARC_OPERAND_SIGNED) && (value & 256)) 111685815Sobrien value -= 512; 111785815Sobrien } 111885815Sobrien else 1119218822Sdim value = 0; 1120218822Sdim 112138889Sjdp flag_p = 1; 112238889Sjdp flagshimm_handled_p = 1; 112338889Sjdp } 112438889Sjdp else if (regno == ARC_REG_LIMM) 112538889Sjdp { 112685815Sobrien op_type = OP_LIMM; 112738889Sjdp value = insn[1]; 112838889Sjdp limm_p = 1; 1129218822Sdim 1130218822Sdim /* If this is a jump instruction (j,jl), show new pc correctly. */ 113185815Sobrien if (0x07 == ((*insn & I(-1)) >> 27)) 1132218822Sdim value = (value & 0xffffff); 113338889Sjdp } 1134218822Sdim 113538889Sjdp /* It's a register, set OPVAL (that's the only way we distinguish registers 113638889Sjdp from constants here). */ 113738889Sjdp else 113838889Sjdp { 113938889Sjdp const struct arc_operand_value *reg = lookup_register (REG, regno); 1140218822Sdim 114185815Sobrien op_type = OP_REG; 114238889Sjdp 114338889Sjdp if (reg == NULL) 114438889Sjdp abort (); 114538889Sjdp if (opval != NULL) 114638889Sjdp *opval = reg; 114738889Sjdp value = regno; 114838889Sjdp } 114938889Sjdp 115038889Sjdp /* If this field takes an auxiliary register, see if it's a known one. */ 115138889Sjdp if ((mods & ARC_MOD_AUXREG) 115238889Sjdp && ARC_REG_CONSTANT_P (regno)) 115338889Sjdp { 115438889Sjdp const struct arc_operand_value *reg = lookup_register (AUXREG, value); 115538889Sjdp 115638889Sjdp /* This is really a constant, but tell the caller it has a special 115738889Sjdp name. */ 115838889Sjdp if (reg != NULL && opval != NULL) 115938889Sjdp *opval = reg; 116038889Sjdp } 1161218822Sdim 116285815Sobrien switch(operand->fmt) 116385815Sobrien { 116485815Sobrien case 'a': 116585815Sobrien ls_operand[LS_DEST] = op_type; 116685815Sobrien break; 116785815Sobrien case 's': 116885815Sobrien ls_operand[LS_BASE] = op_type; 116985815Sobrien break; 117085815Sobrien case 'c': 117185815Sobrien if ((insn[0]& I(-1)) == I(2)) 117285815Sobrien ls_operand[LS_VALUE] = op_type; 117385815Sobrien else 117485815Sobrien ls_operand[LS_OFFSET] = op_type; 117585815Sobrien break; 117685815Sobrien case 'o': case 'O': 117785815Sobrien ls_operand[LS_OFFSET] = op_type; 117885815Sobrien break; 117985815Sobrien } 118038889Sjdp 118138889Sjdp return value; 118238889Sjdp} 118338889Sjdp 118438889Sjdp/* Return the value of the "flag update" field for shimm insns. 118538889Sjdp This value is actually stored in the register field. */ 118638889Sjdp 118738889Sjdpstatic long 1188218822Sdimextract_flag (arc_insn *insn, 1189218822Sdim const struct arc_operand *operand, 1190218822Sdim int mods ATTRIBUTE_UNUSED, 1191218822Sdim const struct arc_operand_value **opval, 1192218822Sdim int *invalid ATTRIBUTE_UNUSED) 119338889Sjdp{ 119438889Sjdp int f; 119538889Sjdp const struct arc_operand_value *val; 119638889Sjdp 119738889Sjdp if (flagshimm_handled_p) 119838889Sjdp f = flag_p != 0; 119938889Sjdp else 120085815Sobrien f = (*insn & (1 << operand->shift)) != 0; 120138889Sjdp 120238889Sjdp /* There is no text for zero values. */ 120338889Sjdp if (f == 0) 120438889Sjdp return 0; 120585815Sobrien flag_p = 1; 120638889Sjdp val = arc_opcode_lookup_suffix (operand, 1); 120738889Sjdp if (opval != NULL && val != NULL) 120838889Sjdp *opval = val; 120938889Sjdp return val->value; 121038889Sjdp} 121138889Sjdp 121238889Sjdp/* Extract the condition code (if it exists). 121338889Sjdp If we've seen a shimm value in this insn (meaning that the insn can't have 121438889Sjdp a condition code field), then we don't store anything in OPVAL and return 121538889Sjdp zero. */ 121638889Sjdp 121738889Sjdpstatic long 1218218822Sdimextract_cond (arc_insn *insn, 1219218822Sdim const struct arc_operand *operand, 1220218822Sdim int mods ATTRIBUTE_UNUSED, 1221218822Sdim const struct arc_operand_value **opval, 1222218822Sdim int *invalid ATTRIBUTE_UNUSED) 122338889Sjdp{ 122438889Sjdp long cond; 122538889Sjdp const struct arc_operand_value *val; 122638889Sjdp 122738889Sjdp if (flagshimm_handled_p) 122838889Sjdp return 0; 122938889Sjdp 123085815Sobrien cond = (*insn >> operand->shift) & ((1 << operand->bits) - 1); 123138889Sjdp val = arc_opcode_lookup_suffix (operand, cond); 123238889Sjdp 123338889Sjdp /* Ignore NULL values of `val'. Several condition code values are 123438889Sjdp reserved for extensions. */ 123538889Sjdp if (opval != NULL && val != NULL) 123638889Sjdp *opval = val; 123738889Sjdp return cond; 123838889Sjdp} 123938889Sjdp 124038889Sjdp/* Extract a branch address. 124138889Sjdp We return the value as a real address (not right shifted by 2). */ 124238889Sjdp 124338889Sjdpstatic long 1244218822Sdimextract_reladdr (arc_insn *insn, 1245218822Sdim const struct arc_operand *operand, 1246218822Sdim int mods ATTRIBUTE_UNUSED, 1247218822Sdim const struct arc_operand_value **opval ATTRIBUTE_UNUSED, 1248218822Sdim int *invalid ATTRIBUTE_UNUSED) 124938889Sjdp{ 125038889Sjdp long addr; 125138889Sjdp 125285815Sobrien addr = (*insn >> operand->shift) & ((1 << operand->bits) - 1); 125338889Sjdp if ((operand->flags & ARC_OPERAND_SIGNED) 125438889Sjdp && (addr & (1 << (operand->bits - 1)))) 125538889Sjdp addr -= 1 << operand->bits; 125638889Sjdp return addr << 2; 125738889Sjdp} 125838889Sjdp 1259218822Sdim/* Extract the flags bits from a j or jl long immediate. */ 1260218822Sdim 126185815Sobrienstatic long 1262218822Sdimextract_jumpflags (arc_insn *insn, 1263218822Sdim const struct arc_operand *operand, 1264218822Sdim int mods ATTRIBUTE_UNUSED, 1265218822Sdim const struct arc_operand_value **opval ATTRIBUTE_UNUSED, 1266218822Sdim int *invalid) 126785815Sobrien{ 126885815Sobrien if (!flag_p || !limm_p) 126985815Sobrien *invalid = 1; 127085815Sobrien return ((flag_p && limm_p) 127185815Sobrien ? (insn[1] >> operand->shift) & ((1 << operand->bits) -1): 0); 127285815Sobrien} 127385815Sobrien 1274218822Sdim/* Extract st insn's offset. */ 127585815Sobrien 127685815Sobrienstatic long 1277218822Sdimextract_st_offset (arc_insn *insn, 1278218822Sdim const struct arc_operand *operand, 1279218822Sdim int mods ATTRIBUTE_UNUSED, 1280218822Sdim const struct arc_operand_value **opval ATTRIBUTE_UNUSED, 1281218822Sdim int *invalid) 128285815Sobrien{ 128385815Sobrien int value = 0; 128485815Sobrien 128585815Sobrien if (ls_operand[LS_VALUE] != OP_SHIMM || ls_operand[LS_BASE] != OP_LIMM) 128685815Sobrien { 128785815Sobrien value = insn[0] & 511; 128885815Sobrien if ((operand->flags & ARC_OPERAND_SIGNED) && (value & 256)) 128985815Sobrien value -= 512; 129085815Sobrien if (value) 129185815Sobrien ls_operand[LS_OFFSET] = OP_SHIMM; 129285815Sobrien } 129385815Sobrien else 1294218822Sdim *invalid = 1; 1295218822Sdim 1296218822Sdim return value; 129785815Sobrien} 129885815Sobrien 1299218822Sdim/* Extract ld insn's offset. */ 130085815Sobrien 130185815Sobrienstatic long 1302218822Sdimextract_ld_offset (arc_insn *insn, 1303218822Sdim const struct arc_operand *operand, 1304218822Sdim int mods, 1305218822Sdim const struct arc_operand_value **opval, 1306218822Sdim int *invalid) 130785815Sobrien{ 130885815Sobrien int test = insn[0] & I(-1); 130985815Sobrien int value; 131085815Sobrien 131185815Sobrien if (test) 131285815Sobrien { 131385815Sobrien value = insn[0] & 511; 131485815Sobrien if ((operand->flags & ARC_OPERAND_SIGNED) && (value & 256)) 131585815Sobrien value -= 512; 131685815Sobrien if (value) 131785815Sobrien ls_operand[LS_OFFSET] = OP_SHIMM; 1318218822Sdim 1319218822Sdim return value; 132085815Sobrien } 1321218822Sdim /* If it isn't in the insn, it's concealed behind reg 'c'. */ 132285815Sobrien return extract_reg (insn, &arc_operands[arc_operand_map['c']], 132385815Sobrien mods, opval, invalid); 132485815Sobrien} 132585815Sobrien 132638889Sjdp/* The only thing this does is set the `invalid' flag if B != C. 132738889Sjdp This is needed because the "mov" macro appears before it's real insn "and" 132838889Sjdp and we don't want the disassembler to confuse them. */ 132938889Sjdp 133038889Sjdpstatic long 1331218822Sdimextract_unopmacro (arc_insn *insn, 1332218822Sdim const struct arc_operand *operand ATTRIBUTE_UNUSED, 1333218822Sdim int mods ATTRIBUTE_UNUSED, 1334218822Sdim const struct arc_operand_value **opval ATTRIBUTE_UNUSED, 1335218822Sdim int *invalid) 133638889Sjdp{ 133738889Sjdp /* This misses the case where B == ARC_REG_SHIMM_UPDATE && 133838889Sjdp C == ARC_REG_SHIMM (or vice versa). No big deal. Those insns will get 133938889Sjdp printed as "and"s. */ 134085815Sobrien if (((*insn >> ARC_SHIFT_REGB) & ARC_MASK_REG) 134185815Sobrien != ((*insn >> ARC_SHIFT_REGC) & ARC_MASK_REG)) 134238889Sjdp if (invalid != NULL) 134338889Sjdp *invalid = 1; 134438889Sjdp return 0; 134538889Sjdp} 1346218822Sdim 1347218822Sdim/* ARC instructions. 134838889Sjdp 1349218822Sdim Longer versions of insns must appear before shorter ones (if gas sees 1350218822Sdim "lsr r2,r3,1" when it's parsing "lsr %a,%b" it will think the ",1" is 1351218822Sdim junk). This isn't necessary for `ld' because of the trailing ']'. 1352218822Sdim 1353218822Sdim Instructions that are really macros based on other insns must appear 1354218822Sdim before the real insn so they're chosen when disassembling. Eg: The `mov' 1355218822Sdim insn is really the `and' insn. */ 1356218822Sdim 1357218822Sdimstruct arc_opcode arc_opcodes[] = 1358218822Sdim{ 1359218822Sdim /* Base case instruction set (core versions 5-8). */ 1360218822Sdim 1361218822Sdim /* "mov" is really an "and". */ 1362218822Sdim { "mov%.q%.f %a,%b%F%S%L%U", I(-1), I(12), ARC_MACH_5, 0, 0 }, 1363218822Sdim /* "asl" is really an "add". */ 1364218822Sdim { "asl%.q%.f %a,%b%F%S%L%U", I(-1), I(8), ARC_MACH_5, 0, 0 }, 1365218822Sdim /* "lsl" is really an "add". */ 1366218822Sdim { "lsl%.q%.f %a,%b%F%S%L%U", I(-1), I(8), ARC_MACH_5, 0, 0 }, 1367218822Sdim /* "nop" is really an "xor". */ 1368218822Sdim { "nop", 0x7fffffff, 0x7fffffff, ARC_MACH_5, 0, 0 }, 1369218822Sdim /* "rlc" is really an "adc". */ 1370218822Sdim { "rlc%.q%.f %a,%b%F%S%L%U", I(-1), I(9), ARC_MACH_5, 0, 0 }, 1371218822Sdim { "adc%.q%.f %a,%b,%c%F%S%L", I(-1), I(9), ARC_MACH_5, 0, 0 }, 1372218822Sdim { "add%.q%.f %a,%b,%c%F%S%L", I(-1), I(8), ARC_MACH_5, 0, 0 }, 1373218822Sdim { "and%.q%.f %a,%b,%c%F%S%L", I(-1), I(12), ARC_MACH_5, 0, 0 }, 1374218822Sdim { "asr%.q%.f %a,%b%F%S%L", I(-1)|C(-1), I(3)|C(1), ARC_MACH_5, 0, 0 }, 1375218822Sdim { "bic%.q%.f %a,%b,%c%F%S%L", I(-1), I(14), ARC_MACH_5, 0, 0 }, 1376218822Sdim { "b%q%.n %B", I(-1), I(4), ARC_MACH_5 | ARC_OPCODE_COND_BRANCH, 0, 0 }, 1377218822Sdim { "bl%q%.n %B", I(-1), I(5), ARC_MACH_5 | ARC_OPCODE_COND_BRANCH, 0, 0 }, 1378218822Sdim { "extb%.q%.f %a,%b%F%S%L", I(-1)|C(-1), I(3)|C(7), ARC_MACH_5, 0, 0 }, 1379218822Sdim { "extw%.q%.f %a,%b%F%S%L", I(-1)|C(-1), I(3)|C(8), ARC_MACH_5, 0, 0 }, 1380218822Sdim { "flag%.q %b%G%S%L", I(-1)|A(-1)|C(-1), I(3)|A(ARC_REG_SHIMM_UPDATE)|C(0), ARC_MACH_5, 0, 0 }, 1381218822Sdim { "brk", 0x1ffffe00, 0x1ffffe00, ARC_MACH_7, 0, 0 }, 1382218822Sdim { "sleep", 0x1ffffe01, 0x1ffffe01, ARC_MACH_7, 0, 0 }, 1383218822Sdim { "swi", 0x1ffffe02, 0x1ffffe02, ARC_MACH_8, 0, 0 }, 1384218822Sdim /* %Q: force cond_p=1 -> no shimm values. This insn allows an 1385218822Sdim optional flags spec. */ 1386218822Sdim { "j%q%Q%.n%.f %b%F%J,%j", I(-1)|A(-1)|C(-1)|R(-1,7,1), I(7)|A(0)|C(0)|R(0,7,1), ARC_MACH_5 | ARC_OPCODE_COND_BRANCH, 0, 0 }, 1387218822Sdim { "j%q%Q%.n%.f %b%F%J", I(-1)|A(-1)|C(-1)|R(-1,7,1), I(7)|A(0)|C(0)|R(0,7,1), ARC_MACH_5 | ARC_OPCODE_COND_BRANCH, 0, 0 }, 1388218822Sdim /* This insn allows an optional flags spec. */ 1389218822Sdim { "jl%q%Q%.n%.f %b%F%J,%j", I(-1)|A(-1)|C(-1)|R(-1,7,1)|R(-1,9,1), I(7)|A(0)|C(0)|R(0,7,1)|R(1,9,1), ARC_MACH_6 | ARC_OPCODE_COND_BRANCH, 0, 0 }, 1390218822Sdim { "jl%q%Q%.n%.f %b%F%J", I(-1)|A(-1)|C(-1)|R(-1,7,1)|R(-1,9,1), I(7)|A(0)|C(0)|R(0,7,1)|R(1,9,1), ARC_MACH_6 | ARC_OPCODE_COND_BRANCH, 0, 0 }, 1391218822Sdim /* Put opcode 1 ld insns first so shimm gets prefered over limm. 1392218822Sdim "[%b]" is before "[%b,%o]" so 0 offsets don't get printed. */ 1393218822Sdim { "ld%Z%.X%.W%.E %a,[%s]%S%L%1", I(-1)|R(-1,13,1)|R(-1,0,511), I(1)|R(0,13,1)|R(0,0,511), ARC_MACH_5, 0, 0 }, 1394218822Sdim { "ld%z%.x%.w%.e %a,[%s]%S%L%1", I(-1)|R(-1,4,1)|R(-1,6,7), I(0)|R(0,4,1)|R(0,6,7), ARC_MACH_5, 0, 0 }, 1395218822Sdim { "ld%z%.x%.w%.e %a,[%s,%O]%S%L%1", I(-1)|R(-1,4,1)|R(-1,6,7), I(0)|R(0,4,1)|R(0,6,7), ARC_MACH_5, 0, 0 }, 1396218822Sdim { "ld%Z%.X%.W%.E %a,[%s,%O]%S%L%3", I(-1)|R(-1,13,1), I(1)|R(0,13,1), ARC_MACH_5, 0, 0 }, 1397218822Sdim { "lp%q%.n %B", I(-1), I(6), ARC_MACH_5, 0, 0 }, 1398218822Sdim { "lr %a,[%Ab]%S%L", I(-1)|C(-1), I(1)|C(0x10), ARC_MACH_5, 0, 0 }, 1399218822Sdim { "lsr%.q%.f %a,%b%F%S%L", I(-1)|C(-1), I(3)|C(2), ARC_MACH_5, 0, 0 }, 1400218822Sdim { "or%.q%.f %a,%b,%c%F%S%L", I(-1), I(13), ARC_MACH_5, 0, 0 }, 1401218822Sdim { "ror%.q%.f %a,%b%F%S%L", I(-1)|C(-1), I(3)|C(3), ARC_MACH_5, 0, 0 }, 1402218822Sdim { "rrc%.q%.f %a,%b%F%S%L", I(-1)|C(-1), I(3)|C(4), ARC_MACH_5, 0, 0 }, 1403218822Sdim { "sbc%.q%.f %a,%b,%c%F%S%L", I(-1), I(11), ARC_MACH_5, 0, 0 }, 1404218822Sdim { "sexb%.q%.f %a,%b%F%S%L", I(-1)|C(-1), I(3)|C(5), ARC_MACH_5, 0, 0 }, 1405218822Sdim { "sexw%.q%.f %a,%b%F%S%L", I(-1)|C(-1), I(3)|C(6), ARC_MACH_5, 0, 0 }, 1406218822Sdim { "sr %c,[%Ab]%S%L", I(-1)|A(-1), I(2)|A(0x10), ARC_MACH_5, 0, 0 }, 1407218822Sdim /* "[%b]" is before "[%b,%o]" so 0 offsets don't get printed. */ 1408218822Sdim { "st%y%.v%.D %c,[%s]%L%S%0", I(-1)|R(-1,25,1)|R(-1,21,1), I(2)|R(0,25,1)|R(0,21,1), ARC_MACH_5, 0, 0 }, 1409218822Sdim { "st%y%.v%.D %c,[%s,%o]%S%L%2", I(-1)|R(-1,25,1)|R(-1,21,1), I(2)|R(0,25,1)|R(0,21,1), ARC_MACH_5, 0, 0 }, 1410218822Sdim { "sub%.q%.f %a,%b,%c%F%S%L", I(-1), I(10), ARC_MACH_5, 0, 0 }, 1411218822Sdim { "xor%.q%.f %a,%b,%c%F%S%L", I(-1), I(15), ARC_MACH_5, 0, 0 } 1412218822Sdim}; 1413218822Sdim 1414218822Sdimconst int arc_opcodes_count = sizeof (arc_opcodes) / sizeof (arc_opcodes[0]); 1415218822Sdim 1416218822Sdimconst struct arc_operand_value arc_reg_names[] = 1417218822Sdim{ 1418218822Sdim /* Core register set r0-r63. */ 1419218822Sdim 1420218822Sdim /* r0-r28 - general purpose registers. */ 1421218822Sdim { "r0", 0, REG, 0 }, { "r1", 1, REG, 0 }, { "r2", 2, REG, 0 }, 1422218822Sdim { "r3", 3, REG, 0 }, { "r4", 4, REG, 0 }, { "r5", 5, REG, 0 }, 1423218822Sdim { "r6", 6, REG, 0 }, { "r7", 7, REG, 0 }, { "r8", 8, REG, 0 }, 1424218822Sdim { "r9", 9, REG, 0 }, { "r10", 10, REG, 0 }, { "r11", 11, REG, 0 }, 1425218822Sdim { "r12", 12, REG, 0 }, { "r13", 13, REG, 0 }, { "r14", 14, REG, 0 }, 1426218822Sdim { "r15", 15, REG, 0 }, { "r16", 16, REG, 0 }, { "r17", 17, REG, 0 }, 1427218822Sdim { "r18", 18, REG, 0 }, { "r19", 19, REG, 0 }, { "r20", 20, REG, 0 }, 1428218822Sdim { "r21", 21, REG, 0 }, { "r22", 22, REG, 0 }, { "r23", 23, REG, 0 }, 1429218822Sdim { "r24", 24, REG, 0 }, { "r25", 25, REG, 0 }, { "r26", 26, REG, 0 }, 1430218822Sdim { "r27", 27, REG, 0 }, { "r28", 28, REG, 0 }, 1431218822Sdim /* Maskable interrupt link register. */ 1432218822Sdim { "ilink1", 29, REG, 0 }, 1433218822Sdim /* Maskable interrupt link register. */ 1434218822Sdim { "ilink2", 30, REG, 0 }, 1435218822Sdim /* Branch-link register. */ 1436218822Sdim { "blink", 31, REG, 0 }, 1437218822Sdim 1438218822Sdim /* r32-r59 reserved for extensions. */ 1439218822Sdim { "r32", 32, REG, 0 }, { "r33", 33, REG, 0 }, { "r34", 34, REG, 0 }, 1440218822Sdim { "r35", 35, REG, 0 }, { "r36", 36, REG, 0 }, { "r37", 37, REG, 0 }, 1441218822Sdim { "r38", 38, REG, 0 }, { "r39", 39, REG, 0 }, { "r40", 40, REG, 0 }, 1442218822Sdim { "r41", 41, REG, 0 }, { "r42", 42, REG, 0 }, { "r43", 43, REG, 0 }, 1443218822Sdim { "r44", 44, REG, 0 }, { "r45", 45, REG, 0 }, { "r46", 46, REG, 0 }, 1444218822Sdim { "r47", 47, REG, 0 }, { "r48", 48, REG, 0 }, { "r49", 49, REG, 0 }, 1445218822Sdim { "r50", 50, REG, 0 }, { "r51", 51, REG, 0 }, { "r52", 52, REG, 0 }, 1446218822Sdim { "r53", 53, REG, 0 }, { "r54", 54, REG, 0 }, { "r55", 55, REG, 0 }, 1447218822Sdim { "r56", 56, REG, 0 }, { "r57", 57, REG, 0 }, { "r58", 58, REG, 0 }, 1448218822Sdim { "r59", 59, REG, 0 }, 1449218822Sdim 1450218822Sdim /* Loop count register (24 bits). */ 1451218822Sdim { "lp_count", 60, REG, 0 }, 1452218822Sdim /* Short immediate data indicator setting flags. */ 1453218822Sdim { "r61", 61, REG, ARC_REGISTER_READONLY }, 1454218822Sdim /* Long immediate data indicator setting flags. */ 1455218822Sdim { "r62", 62, REG, ARC_REGISTER_READONLY }, 1456218822Sdim /* Short immediate data indicator not setting flags. */ 1457218822Sdim { "r63", 63, REG, ARC_REGISTER_READONLY }, 1458218822Sdim 1459218822Sdim /* Small-data base register. */ 1460218822Sdim { "gp", 26, REG, 0 }, 1461218822Sdim /* Frame pointer. */ 1462218822Sdim { "fp", 27, REG, 0 }, 1463218822Sdim /* Stack pointer. */ 1464218822Sdim { "sp", 28, REG, 0 }, 1465218822Sdim 1466218822Sdim { "r29", 29, REG, 0 }, 1467218822Sdim { "r30", 30, REG, 0 }, 1468218822Sdim { "r31", 31, REG, 0 }, 1469218822Sdim { "r60", 60, REG, 0 }, 1470218822Sdim 1471218822Sdim /* Auxiliary register set. */ 1472218822Sdim 1473218822Sdim /* Auxiliary register address map: 1474218822Sdim 0xffffffff-0xffffff00 (-1..-256) - customer shimm allocation 1475218822Sdim 0xfffffeff-0x80000000 - customer limm allocation 1476218822Sdim 0x7fffffff-0x00000100 - ARC limm allocation 1477218822Sdim 0x000000ff-0x00000000 - ARC shimm allocation */ 1478218822Sdim 1479218822Sdim /* Base case auxiliary registers (shimm address). */ 1480218822Sdim { "status", 0x00, AUXREG, 0 }, 1481218822Sdim { "semaphore", 0x01, AUXREG, 0 }, 1482218822Sdim { "lp_start", 0x02, AUXREG, 0 }, 1483218822Sdim { "lp_end", 0x03, AUXREG, 0 }, 1484218822Sdim { "identity", 0x04, AUXREG, ARC_REGISTER_READONLY }, 1485218822Sdim { "debug", 0x05, AUXREG, 0 }, 1486218822Sdim}; 1487218822Sdim 1488218822Sdimconst int arc_reg_names_count = 1489218822Sdim sizeof (arc_reg_names) / sizeof (arc_reg_names[0]); 1490218822Sdim 1491218822Sdim/* The suffix table. 1492218822Sdim Operands with the same name must be stored together. */ 1493218822Sdim 1494218822Sdimconst struct arc_operand_value arc_suffixes[] = 1495218822Sdim{ 1496218822Sdim /* Entry 0 is special, default values aren't printed by the disassembler. */ 1497218822Sdim { "", 0, -1, 0 }, 1498218822Sdim 1499218822Sdim /* Base case condition codes. */ 1500218822Sdim { "al", 0, COND, 0 }, 1501218822Sdim { "ra", 0, COND, 0 }, 1502218822Sdim { "eq", 1, COND, 0 }, 1503218822Sdim { "z", 1, COND, 0 }, 1504218822Sdim { "ne", 2, COND, 0 }, 1505218822Sdim { "nz", 2, COND, 0 }, 1506218822Sdim { "pl", 3, COND, 0 }, 1507218822Sdim { "p", 3, COND, 0 }, 1508218822Sdim { "mi", 4, COND, 0 }, 1509218822Sdim { "n", 4, COND, 0 }, 1510218822Sdim { "cs", 5, COND, 0 }, 1511218822Sdim { "c", 5, COND, 0 }, 1512218822Sdim { "lo", 5, COND, 0 }, 1513218822Sdim { "cc", 6, COND, 0 }, 1514218822Sdim { "nc", 6, COND, 0 }, 1515218822Sdim { "hs", 6, COND, 0 }, 1516218822Sdim { "vs", 7, COND, 0 }, 1517218822Sdim { "v", 7, COND, 0 }, 1518218822Sdim { "vc", 8, COND, 0 }, 1519218822Sdim { "nv", 8, COND, 0 }, 1520218822Sdim { "gt", 9, COND, 0 }, 1521218822Sdim { "ge", 10, COND, 0 }, 1522218822Sdim { "lt", 11, COND, 0 }, 1523218822Sdim { "le", 12, COND, 0 }, 1524218822Sdim { "hi", 13, COND, 0 }, 1525218822Sdim { "ls", 14, COND, 0 }, 1526218822Sdim { "pnz", 15, COND, 0 }, 1527218822Sdim 1528218822Sdim /* Condition codes 16-31 reserved for extensions. */ 1529218822Sdim 1530218822Sdim { "f", 1, FLAG, 0 }, 1531218822Sdim 1532218822Sdim { "nd", ARC_DELAY_NONE, DELAY, 0 }, 1533218822Sdim { "d", ARC_DELAY_NORMAL, DELAY, 0 }, 1534218822Sdim { "jd", ARC_DELAY_JUMP, DELAY, 0 }, 1535218822Sdim 1536218822Sdim { "b", 1, SIZE1, 0 }, 1537218822Sdim { "b", 1, SIZE10, 0 }, 1538218822Sdim { "b", 1, SIZE22, 0 }, 1539218822Sdim { "w", 2, SIZE1, 0 }, 1540218822Sdim { "w", 2, SIZE10, 0 }, 1541218822Sdim { "w", 2, SIZE22, 0 }, 1542218822Sdim { "x", 1, SIGN0, 0 }, 1543218822Sdim { "x", 1, SIGN9, 0 }, 1544218822Sdim { "a", 1, ADDRESS3, 0 }, 1545218822Sdim { "a", 1, ADDRESS12, 0 }, 1546218822Sdim { "a", 1, ADDRESS24, 0 }, 1547218822Sdim 1548218822Sdim { "di", 1, CACHEBYPASS5, 0 }, 1549218822Sdim { "di", 1, CACHEBYPASS14, 0 }, 1550218822Sdim { "di", 1, CACHEBYPASS26, 0 }, 1551218822Sdim}; 1552218822Sdim 1553218822Sdimconst int arc_suffixes_count = 1554218822Sdim sizeof (arc_suffixes) / sizeof (arc_suffixes[0]); 1555218822Sdim 1556218822Sdim/* Indexed by first letter of opcode. Points to chain of opcodes with same 1557218822Sdim first letter. */ 1558218822Sdimstatic struct arc_opcode *opcode_map[26 + 1]; 1559218822Sdim 1560218822Sdim/* Indexed by insn code. Points to chain of opcodes with same insn code. */ 1561218822Sdimstatic struct arc_opcode *icode_map[32]; 1562218822Sdim 1563218822Sdim/* Configuration flags. */ 1564218822Sdim 1565218822Sdim/* Various ARC_HAVE_XXX bits. */ 1566218822Sdimstatic int cpu_type; 1567218822Sdim 1568218822Sdim/* Translate a bfd_mach_arc_xxx value to a ARC_MACH_XXX value. */ 1569218822Sdim 1570218822Sdimint 1571218822Sdimarc_get_opcode_mach (int bfd_mach, int big_p) 1572218822Sdim{ 1573218822Sdim static int mach_type_map[] = 1574218822Sdim { 1575218822Sdim ARC_MACH_5, 1576218822Sdim ARC_MACH_6, 1577218822Sdim ARC_MACH_7, 1578218822Sdim ARC_MACH_8 1579218822Sdim }; 1580218822Sdim return mach_type_map[bfd_mach - bfd_mach_arc_5] | (big_p ? ARC_MACH_BIG : 0); 1581218822Sdim} 1582218822Sdim 1583218822Sdim/* Initialize any tables that need it. 1584218822Sdim Must be called once at start up (or when first needed). 1585218822Sdim 1586218822Sdim FLAGS is a set of bits that say what version of the cpu we have, 1587218822Sdim and in particular at least (one of) ARC_MACH_XXX. */ 1588218822Sdim 1589218822Sdimvoid 1590218822Sdimarc_opcode_init_tables (int flags) 1591218822Sdim{ 1592218822Sdim static int init_p = 0; 1593218822Sdim 1594218822Sdim cpu_type = flags; 1595218822Sdim 1596218822Sdim /* We may be intentionally called more than once (for example gdb will call 1597218822Sdim us each time the user switches cpu). These tables only need to be init'd 1598218822Sdim once though. */ 1599218822Sdim if (!init_p) 1600218822Sdim { 1601218822Sdim int i,n; 1602218822Sdim 1603218822Sdim memset (arc_operand_map, 0, sizeof (arc_operand_map)); 1604218822Sdim n = sizeof (arc_operands) / sizeof (arc_operands[0]); 1605218822Sdim for (i = 0; i < n; ++i) 1606218822Sdim arc_operand_map[arc_operands[i].fmt] = i; 1607218822Sdim 1608218822Sdim memset (opcode_map, 0, sizeof (opcode_map)); 1609218822Sdim memset (icode_map, 0, sizeof (icode_map)); 1610218822Sdim /* Scan the table backwards so macros appear at the front. */ 1611218822Sdim for (i = arc_opcodes_count - 1; i >= 0; --i) 1612218822Sdim { 1613218822Sdim int opcode_hash = ARC_HASH_OPCODE (arc_opcodes[i].syntax); 1614218822Sdim int icode_hash = ARC_HASH_ICODE (arc_opcodes[i].value); 1615218822Sdim 1616218822Sdim arc_opcodes[i].next_asm = opcode_map[opcode_hash]; 1617218822Sdim opcode_map[opcode_hash] = &arc_opcodes[i]; 1618218822Sdim 1619218822Sdim arc_opcodes[i].next_dis = icode_map[icode_hash]; 1620218822Sdim icode_map[icode_hash] = &arc_opcodes[i]; 1621218822Sdim } 1622218822Sdim 1623218822Sdim init_p = 1; 1624218822Sdim } 1625218822Sdim} 1626218822Sdim 1627218822Sdim/* Return non-zero if OPCODE is supported on the specified cpu. 1628218822Sdim Cpu selection is made when calling `arc_opcode_init_tables'. */ 1629218822Sdim 1630218822Sdimint 1631218822Sdimarc_opcode_supported (const struct arc_opcode *opcode) 1632218822Sdim{ 1633218822Sdim if (ARC_OPCODE_CPU (opcode->flags) <= cpu_type) 1634218822Sdim return 1; 1635218822Sdim return 0; 1636218822Sdim} 1637218822Sdim 1638218822Sdim/* Return the first insn in the chain for assembling INSN. */ 1639218822Sdim 1640218822Sdimconst struct arc_opcode * 1641218822Sdimarc_opcode_lookup_asm (const char *insn) 1642218822Sdim{ 1643218822Sdim return opcode_map[ARC_HASH_OPCODE (insn)]; 1644218822Sdim} 1645218822Sdim 1646218822Sdim/* Return the first insn in the chain for disassembling INSN. */ 1647218822Sdim 1648218822Sdimconst struct arc_opcode * 1649218822Sdimarc_opcode_lookup_dis (unsigned int insn) 1650218822Sdim{ 1651218822Sdim return icode_map[ARC_HASH_ICODE (insn)]; 1652218822Sdim} 1653218822Sdim 1654218822Sdim/* Called by the assembler before parsing an instruction. */ 1655218822Sdim 1656218822Sdimvoid 1657218822Sdimarc_opcode_init_insert (void) 1658218822Sdim{ 1659218822Sdim int i; 1660218822Sdim 1661218822Sdim for(i = 0; i < OPERANDS; i++) 1662218822Sdim ls_operand[i] = OP_NONE; 1663218822Sdim 1664218822Sdim flag_p = 0; 1665218822Sdim flagshimm_handled_p = 0; 1666218822Sdim cond_p = 0; 1667218822Sdim addrwb_p = 0; 1668218822Sdim shimm_p = 0; 1669218822Sdim limm_p = 0; 1670218822Sdim jumpflags_p = 0; 1671218822Sdim nullify_p = 0; 1672218822Sdim nullify = 0; /* The default is important. */ 1673218822Sdim} 1674218822Sdim 1675218822Sdim/* Called by the assembler to see if the insn has a limm operand. 1676218822Sdim Also called by the disassembler to see if the insn contains a limm. */ 1677218822Sdim 1678218822Sdimint 1679218822Sdimarc_opcode_limm_p (long *limmp) 1680218822Sdim{ 1681218822Sdim if (limmp) 1682218822Sdim *limmp = limm; 1683218822Sdim return limm_p; 1684218822Sdim} 1685218822Sdim 168638889Sjdp/* Utility for the extraction functions to return the index into 168738889Sjdp `arc_suffixes'. */ 168838889Sjdp 168938889Sjdpconst struct arc_operand_value * 1690218822Sdimarc_opcode_lookup_suffix (const struct arc_operand *type, int value) 169138889Sjdp{ 1692218822Sdim const struct arc_operand_value *v,*end; 169385815Sobrien struct arc_ext_operand_value *ext_oper = arc_ext_operands; 169438889Sjdp 169585815Sobrien while (ext_oper) 169685815Sobrien { 169785815Sobrien if (type == &arc_operands[ext_oper->operand.type] 169885815Sobrien && value == ext_oper->operand.value) 169985815Sobrien return (&ext_oper->operand); 170085815Sobrien ext_oper = ext_oper->next; 170185815Sobrien } 170285815Sobrien 170338889Sjdp /* ??? This is a little slow and can be speeded up. */ 170438889Sjdp for (v = arc_suffixes, end = arc_suffixes + arc_suffixes_count; v < end; ++v) 170538889Sjdp if (type == &arc_operands[v->type] 170638889Sjdp && value == v->value) 170738889Sjdp return v; 170838889Sjdp return 0; 170938889Sjdp} 171038889Sjdp 171185815Sobrienint 1712218822Sdimarc_insn_is_j (arc_insn insn) 171385815Sobrien{ 171485815Sobrien return (insn & (I(-1))) == I(0x7); 171585815Sobrien} 171685815Sobrien 171785815Sobrienint 1718218822Sdimarc_insn_not_jl (arc_insn insn) 171985815Sobrien{ 172085815Sobrien return ((insn & (I(-1)|A(-1)|C(-1)|R(-1,7,1)|R(-1,9,1))) 172185815Sobrien != (I(0x7) | R(-1,9,1))); 172285815Sobrien} 172385815Sobrien 172485815Sobrienint 1725218822Sdimarc_operand_type (int opertype) 172685815Sobrien{ 172785815Sobrien switch (opertype) 172885815Sobrien { 172985815Sobrien case 0: 1730218822Sdim return COND; 173185815Sobrien break; 173285815Sobrien case 1: 1733218822Sdim return REG; 173485815Sobrien break; 173585815Sobrien case 2: 1736218822Sdim return AUXREG; 173785815Sobrien break; 173885815Sobrien } 173985815Sobrien return -1; 174085815Sobrien} 174185815Sobrien 174285815Sobrienstruct arc_operand_value * 1743218822Sdimget_ext_suffix (char *s) 174485815Sobrien{ 174585815Sobrien struct arc_ext_operand_value *suffix = arc_ext_operands; 174685815Sobrien 174785815Sobrien while (suffix) 174885815Sobrien { 174985815Sobrien if ((COND == suffix->operand.type) 175085815Sobrien && !strcmp(s,suffix->operand.name)) 175185815Sobrien return(&suffix->operand); 175285815Sobrien suffix = suffix->next; 175385815Sobrien } 175485815Sobrien return NULL; 175585815Sobrien} 175685815Sobrien 175785815Sobrienint 1758218822Sdimarc_get_noshortcut_flag (void) 175985815Sobrien{ 176085815Sobrien return ARC_REGISTER_NOSHORT_CUT; 176185815Sobrien} 1762