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