1 | /* Opcode table for the ARC.
|
---|
2 | Copyright 1994, 1995, 1997, 1998, 2000, 2001
|
---|
3 | Free Software Foundation, Inc.
|
---|
4 | Contributed by Doug Evans (dje@cygnus.com).
|
---|
5 |
|
---|
6 | This program is free software; you can redistribute it and/or modify
|
---|
7 | it under the terms of the GNU General Public License as published by
|
---|
8 | the Free Software Foundation; either version 2, or (at your option)
|
---|
9 | any later version.
|
---|
10 |
|
---|
11 | This program is distributed in the hope that it will be useful,
|
---|
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
14 | GNU General Public License for more details.
|
---|
15 |
|
---|
16 | You should have received a copy of the GNU General Public License
|
---|
17 | along with this program; if not, write to the Free Software Foundation,
|
---|
18 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
---|
19 |
|
---|
20 | #include "sysdep.h"
|
---|
21 | #include <stdio.h>
|
---|
22 | #include "ansidecl.h"
|
---|
23 | #include "bfd.h"
|
---|
24 | #include "opcode/arc.h"
|
---|
25 |
|
---|
26 | #define INSERT_FN(fn) \
|
---|
27 | static arc_insn fn PARAMS ((arc_insn, const struct arc_operand *, \
|
---|
28 | int, const struct arc_operand_value *, long, \
|
---|
29 | const char **))
|
---|
30 | #define EXTRACT_FN(fn) \
|
---|
31 | static long fn PARAMS ((arc_insn *, const struct arc_operand *, \
|
---|
32 | int, const struct arc_operand_value **, int *))
|
---|
33 |
|
---|
34 | INSERT_FN (insert_reg);
|
---|
35 | INSERT_FN (insert_shimmfinish);
|
---|
36 | INSERT_FN (insert_limmfinish);
|
---|
37 | INSERT_FN (insert_offset);
|
---|
38 | INSERT_FN (insert_base);
|
---|
39 | INSERT_FN (insert_st_syntax);
|
---|
40 | INSERT_FN (insert_ld_syntax);
|
---|
41 | INSERT_FN (insert_addr_wb);
|
---|
42 | INSERT_FN (insert_flag);
|
---|
43 | INSERT_FN (insert_nullify);
|
---|
44 | INSERT_FN (insert_flagfinish);
|
---|
45 | INSERT_FN (insert_cond);
|
---|
46 | INSERT_FN (insert_forcelimm);
|
---|
47 | INSERT_FN (insert_reladdr);
|
---|
48 | INSERT_FN (insert_absaddr);
|
---|
49 | INSERT_FN (insert_jumpflags);
|
---|
50 | INSERT_FN (insert_unopmacro);
|
---|
51 |
|
---|
52 | EXTRACT_FN (extract_reg);
|
---|
53 | EXTRACT_FN (extract_ld_offset);
|
---|
54 | EXTRACT_FN (extract_ld_syntax);
|
---|
55 | EXTRACT_FN (extract_st_offset);
|
---|
56 | EXTRACT_FN (extract_st_syntax);
|
---|
57 | EXTRACT_FN (extract_flag);
|
---|
58 | EXTRACT_FN (extract_cond);
|
---|
59 | EXTRACT_FN (extract_reladdr);
|
---|
60 | EXTRACT_FN (extract_jumpflags);
|
---|
61 | EXTRACT_FN (extract_unopmacro);
|
---|
62 |
|
---|
63 | enum operand {OP_NONE,OP_REG,OP_SHIMM,OP_LIMM};
|
---|
64 |
|
---|
65 | #define OPERANDS 3
|
---|
66 |
|
---|
67 | enum operand ls_operand[OPERANDS];
|
---|
68 |
|
---|
69 | struct arc_opcode *arc_ext_opcodes;
|
---|
70 | struct arc_ext_operand_value *arc_ext_operands;
|
---|
71 |
|
---|
72 | #define LS_VALUE 0
|
---|
73 | #define LS_DEST 0
|
---|
74 | #define LS_BASE 1
|
---|
75 | #define LS_OFFSET 2
|
---|
76 |
|
---|
77 | /* Various types of ARC operands, including insn suffixes. */
|
---|
78 |
|
---|
79 | /* Insn format values:
|
---|
80 |
|
---|
81 | 'a' REGA register A field
|
---|
82 | 'b' REGB register B field
|
---|
83 | 'c' REGC register C field
|
---|
84 | 'S' SHIMMFINISH finish inserting a shimm value
|
---|
85 | 'L' LIMMFINISH finish inserting a limm value
|
---|
86 | 'o' OFFSET offset in st insns
|
---|
87 | 'O' OFFSET offset in ld insns
|
---|
88 | '0' SYNTAX_ST_NE enforce store insn syntax, no errors
|
---|
89 | '1' SYNTAX_LD_NE enforce load insn syntax, no errors
|
---|
90 | '2' SYNTAX_ST enforce store insn syntax, errors, last pattern only
|
---|
91 | '3' SYNTAX_LD enforce load insn syntax, errors, last pattern only
|
---|
92 | 's' BASE base in st insn
|
---|
93 | 'f' FLAG F flag
|
---|
94 | 'F' FLAGFINISH finish inserting the F flag
|
---|
95 | 'G' FLAGINSN insert F flag in "flag" insn
|
---|
96 | 'n' DELAY N field (nullify field)
|
---|
97 | 'q' COND condition code field
|
---|
98 | 'Q' FORCELIMM set `cond_p' to 1 to ensure a constant is a limm
|
---|
99 | 'B' BRANCH branch address (22 bit pc relative)
|
---|
100 | 'J' JUMP jump address (26 bit absolute)
|
---|
101 | 'j' JUMPFLAGS optional high order bits of 'J'
|
---|
102 | 'z' SIZE1 size field in ld a,[b,c]
|
---|
103 | 'Z' SIZE10 size field in ld a,[b,shimm]
|
---|
104 | 'y' SIZE22 size field in st c,[b,shimm]
|
---|
105 | 'x' SIGN0 sign extend field ld a,[b,c]
|
---|
106 | 'X' SIGN9 sign extend field ld a,[b,shimm]
|
---|
107 | 'w' ADDRESS3 write-back field in ld a,[b,c]
|
---|
108 | 'W' ADDRESS12 write-back field in ld a,[b,shimm]
|
---|
109 | 'v' ADDRESS24 write-back field in st c,[b,shimm]
|
---|
110 | 'e' CACHEBYPASS5 cache bypass in ld a,[b,c]
|
---|
111 | 'E' CACHEBYPASS14 cache bypass in ld a,[b,shimm]
|
---|
112 | 'D' CACHEBYPASS26 cache bypass in st c,[b,shimm]
|
---|
113 | 'U' UNOPMACRO fake operand to copy REGB to REGC for unop macros
|
---|
114 |
|
---|
115 | The following modifiers may appear between the % and char (eg: %.f):
|
---|
116 |
|
---|
117 | '.' MODDOT '.' prefix must be present
|
---|
118 | 'r' REG generic register value, for register table
|
---|
119 | 'A' AUXREG auxiliary register in lr a,[b], sr c,[b]
|
---|
120 |
|
---|
121 | Fields are:
|
---|
122 |
|
---|
123 | CHAR BITS SHIFT FLAGS INSERT_FN EXTRACT_FN */
|
---|
124 |
|
---|
125 | const struct arc_operand arc_operands[] =
|
---|
126 | {
|
---|
127 | /* place holder (??? not sure if needed). */
|
---|
128 | #define UNUSED 0
|
---|
129 | { 0, 0, 0, 0, 0, 0 },
|
---|
130 |
|
---|
131 | /* register A or shimm/limm indicator. */
|
---|
132 | #define REGA (UNUSED + 1)
|
---|
133 | { 'a', 6, ARC_SHIFT_REGA, ARC_OPERAND_SIGNED | ARC_OPERAND_ERROR, insert_reg, extract_reg },
|
---|
134 |
|
---|
135 | /* register B or shimm/limm indicator. */
|
---|
136 | #define REGB (REGA + 1)
|
---|
137 | { 'b', 6, ARC_SHIFT_REGB, ARC_OPERAND_SIGNED | ARC_OPERAND_ERROR, insert_reg, extract_reg },
|
---|
138 |
|
---|
139 | /* register C or shimm/limm indicator. */
|
---|
140 | #define REGC (REGB + 1)
|
---|
141 | { 'c', 6, ARC_SHIFT_REGC, ARC_OPERAND_SIGNED | ARC_OPERAND_ERROR, insert_reg, extract_reg },
|
---|
142 |
|
---|
143 | /* fake operand used to insert shimm value into most instructions. */
|
---|
144 | #define SHIMMFINISH (REGC + 1)
|
---|
145 | { 'S', 9, 0, ARC_OPERAND_SIGNED + ARC_OPERAND_FAKE, insert_shimmfinish, 0 },
|
---|
146 |
|
---|
147 | /* fake operand used to insert limm value into most instructions. */
|
---|
148 | #define LIMMFINISH (SHIMMFINISH + 1)
|
---|
149 | { 'L', 32, 32, ARC_OPERAND_ADDRESS + ARC_OPERAND_LIMM + ARC_OPERAND_FAKE, insert_limmfinish, 0 },
|
---|
150 |
|
---|
151 | /* shimm operand when there is no reg indicator (st). */
|
---|
152 | #define ST_OFFSET (LIMMFINISH + 1)
|
---|
153 | { 'o', 9, 0, ARC_OPERAND_LIMM | ARC_OPERAND_SIGNED | ARC_OPERAND_STORE, insert_offset, extract_st_offset },
|
---|
154 |
|
---|
155 | /* shimm operand when there is no reg indicator (ld). */
|
---|
156 | #define LD_OFFSET (ST_OFFSET + 1)
|
---|
157 | { 'O', 9, 0,ARC_OPERAND_LIMM | ARC_OPERAND_SIGNED | ARC_OPERAND_LOAD, insert_offset, extract_ld_offset },
|
---|
158 |
|
---|
159 | /* operand for base. */
|
---|
160 | #define BASE (LD_OFFSET + 1)
|
---|
161 | { 's', 6, ARC_SHIFT_REGB, ARC_OPERAND_LIMM | ARC_OPERAND_SIGNED, insert_base, extract_reg},
|
---|
162 |
|
---|
163 | /* 0 enforce syntax for st insns. */
|
---|
164 | #define SYNTAX_ST_NE (BASE + 1)
|
---|
165 | { '0', 9, 0, ARC_OPERAND_FAKE, insert_st_syntax, extract_st_syntax },
|
---|
166 |
|
---|
167 | /* 1 enforce syntax for ld insns. */
|
---|
168 | #define SYNTAX_LD_NE (SYNTAX_ST_NE + 1)
|
---|
169 | { '1', 9, 0, ARC_OPERAND_FAKE, insert_ld_syntax, extract_ld_syntax },
|
---|
170 |
|
---|
171 | /* 0 enforce syntax for st insns. */
|
---|
172 | #define SYNTAX_ST (SYNTAX_LD_NE + 1)
|
---|
173 | { '2', 9, 0, ARC_OPERAND_FAKE | ARC_OPERAND_ERROR, insert_st_syntax, extract_st_syntax },
|
---|
174 |
|
---|
175 | /* 0 enforce syntax for ld insns. */
|
---|
176 | #define SYNTAX_LD (SYNTAX_ST + 1)
|
---|
177 | { '3', 9, 0, ARC_OPERAND_FAKE | ARC_OPERAND_ERROR, insert_ld_syntax, extract_ld_syntax },
|
---|
178 |
|
---|
179 | /* flag update bit (insertion is defered until we know how). */
|
---|
180 | #define FLAG (SYNTAX_LD + 1)
|
---|
181 | { 'f', 1, 8, ARC_OPERAND_SUFFIX, insert_flag, extract_flag },
|
---|
182 |
|
---|
183 | /* fake utility operand to finish 'f' suffix handling. */
|
---|
184 | #define FLAGFINISH (FLAG + 1)
|
---|
185 | { 'F', 1, 8, ARC_OPERAND_FAKE, insert_flagfinish, 0 },
|
---|
186 |
|
---|
187 | /* fake utility operand to set the 'f' flag for the "flag" insn. */
|
---|
188 | #define FLAGINSN (FLAGFINISH + 1)
|
---|
189 | { 'G', 1, 8, ARC_OPERAND_FAKE, insert_flag, 0 },
|
---|
190 |
|
---|
191 | /* branch delay types. */
|
---|
192 | #define DELAY (FLAGINSN + 1)
|
---|
193 | { 'n', 2, 5, ARC_OPERAND_SUFFIX , insert_nullify, 0 },
|
---|
194 |
|
---|
195 | /* conditions. */
|
---|
196 | #define COND (DELAY + 1)
|
---|
197 | { 'q', 5, 0, ARC_OPERAND_SUFFIX, insert_cond, extract_cond },
|
---|
198 |
|
---|
199 | /* set `cond_p' to 1 to ensure a constant is treated as a limm. */
|
---|
200 | #define FORCELIMM (COND + 1)
|
---|
201 | { 'Q', 0, 0, ARC_OPERAND_FAKE, insert_forcelimm, 0 },
|
---|
202 |
|
---|
203 | /* branch address; b, bl, and lp insns. */
|
---|
204 | #define BRANCH (FORCELIMM + 1)
|
---|
205 | { 'B', 20, 7, (ARC_OPERAND_RELATIVE_BRANCH + ARC_OPERAND_SIGNED) | ARC_OPERAND_ERROR, insert_reladdr, extract_reladdr },
|
---|
206 |
|
---|
207 | /* jump address; j insn (this is basically the same as 'L' except that the
|
---|
208 | value is right shifted by 2). */
|
---|
209 | #define JUMP (BRANCH + 1)
|
---|
210 | { 'J', 24, 32, ARC_OPERAND_ERROR | (ARC_OPERAND_ABSOLUTE_BRANCH + ARC_OPERAND_LIMM + ARC_OPERAND_FAKE), insert_absaddr, 0 },
|
---|
211 |
|
---|
212 | /* jump flags; j{,l} insn value or'ed into 'J' addr for flag values. */
|
---|
213 | #define JUMPFLAGS (JUMP + 1)
|
---|
214 | { 'j', 6, 26, ARC_OPERAND_JUMPFLAGS | ARC_OPERAND_ERROR, insert_jumpflags, extract_jumpflags },
|
---|
215 |
|
---|
216 | /* size field, stored in bit 1,2. */
|
---|
217 | #define SIZE1 (JUMPFLAGS + 1)
|
---|
218 | { 'z', 2, 1, ARC_OPERAND_SUFFIX, 0, 0 },
|
---|
219 |
|
---|
220 | /* size field, stored in bit 10,11. */
|
---|
221 | #define SIZE10 (SIZE1 + 1)
|
---|
222 | { 'Z', 2, 10, ARC_OPERAND_SUFFIX, 0, 0 },
|
---|
223 |
|
---|
224 | /* size field, stored in bit 22,23. */
|
---|
225 | #define SIZE22 (SIZE10 + 1)
|
---|
226 | { 'y', 2, 22, ARC_OPERAND_SUFFIX, 0, 0 },
|
---|
227 |
|
---|
228 | /* sign extend field, stored in bit 0. */
|
---|
229 | #define SIGN0 (SIZE22 + 1)
|
---|
230 | { 'x', 1, 0, ARC_OPERAND_SUFFIX, 0, 0 },
|
---|
231 |
|
---|
232 | /* sign extend field, stored in bit 9. */
|
---|
233 | #define SIGN9 (SIGN0 + 1)
|
---|
234 | { 'X', 1, 9, ARC_OPERAND_SUFFIX, 0, 0 },
|
---|
235 |
|
---|
236 | /* address write back, stored in bit 3. */
|
---|
237 | #define ADDRESS3 (SIGN9 + 1)
|
---|
238 | { 'w', 1, 3, ARC_OPERAND_SUFFIX, insert_addr_wb, 0},
|
---|
239 |
|
---|
240 | /* address write back, stored in bit 12. */
|
---|
241 | #define ADDRESS12 (ADDRESS3 + 1)
|
---|
242 | { 'W', 1, 12, ARC_OPERAND_SUFFIX, insert_addr_wb, 0},
|
---|
243 |
|
---|
244 | /* address write back, stored in bit 24. */
|
---|
245 | #define ADDRESS24 (ADDRESS12 + 1)
|
---|
246 | { 'v', 1, 24, ARC_OPERAND_SUFFIX, insert_addr_wb, 0},
|
---|
247 |
|
---|
248 | /* cache bypass, stored in bit 5. */
|
---|
249 | #define CACHEBYPASS5 (ADDRESS24 + 1)
|
---|
250 | { 'e', 1, 5, ARC_OPERAND_SUFFIX, 0, 0 },
|
---|
251 |
|
---|
252 | /* cache bypass, stored in bit 14. */
|
---|
253 | #define CACHEBYPASS14 (CACHEBYPASS5 + 1)
|
---|
254 | { 'E', 1, 14, ARC_OPERAND_SUFFIX, 0, 0 },
|
---|
255 |
|
---|
256 | /* cache bypass, stored in bit 26. */
|
---|
257 | #define CACHEBYPASS26 (CACHEBYPASS14 + 1)
|
---|
258 | { 'D', 1, 26, ARC_OPERAND_SUFFIX, 0, 0 },
|
---|
259 |
|
---|
260 | /* unop macro, used to copy REGB to REGC. */
|
---|
261 | #define UNOPMACRO (CACHEBYPASS26 + 1)
|
---|
262 | { 'U', 6, ARC_SHIFT_REGC, ARC_OPERAND_FAKE, insert_unopmacro, extract_unopmacro },
|
---|
263 |
|
---|
264 | /* '.' modifier ('.' required). */
|
---|
265 | #define MODDOT (UNOPMACRO + 1)
|
---|
266 | { '.', 1, 0, ARC_MOD_DOT, 0, 0 },
|
---|
267 |
|
---|
268 | /* Dummy 'r' modifier for the register table.
|
---|
269 | It's called a "dummy" because there's no point in inserting an 'r' into all
|
---|
270 | the %a/%b/%c occurrences in the insn table. */
|
---|
271 | #define REG (MODDOT + 1)
|
---|
272 | { 'r', 6, 0, ARC_MOD_REG, 0, 0 },
|
---|
273 |
|
---|
274 | /* Known auxiliary register modifier (stored in shimm field). */
|
---|
275 | #define AUXREG (REG + 1)
|
---|
276 | { 'A', 9, 0, ARC_MOD_AUXREG, 0, 0 },
|
---|
277 |
|
---|
278 | /* end of list place holder. */
|
---|
279 | { 0, 0, 0, 0, 0, 0 }
|
---|
280 | };
|
---|
281 | |
---|
282 |
|
---|
283 | /* Given a format letter, yields the index into `arc_operands'.
|
---|
284 | eg: arc_operand_map['a'] = REGA. */
|
---|
285 | unsigned char arc_operand_map[256];
|
---|
286 |
|
---|
287 | /* ARC instructions.
|
---|
288 |
|
---|
289 | Longer versions of insns must appear before shorter ones (if gas sees
|
---|
290 | "lsr r2,r3,1" when it's parsing "lsr %a,%b" it will think the ",1" is
|
---|
291 | junk). This isn't necessary for `ld' because of the trailing ']'.
|
---|
292 |
|
---|
293 | Instructions that are really macros based on other insns must appear
|
---|
294 | before the real insn so they're chosen when disassembling. Eg: The `mov'
|
---|
295 | insn is really the `and' insn. */
|
---|
296 |
|
---|
297 | struct arc_opcode arc_opcodes[] =
|
---|
298 | {
|
---|
299 | /* Base case instruction set (core versions 5-8) */
|
---|
300 |
|
---|
301 | /* "mov" is really an "and". */
|
---|
302 | { "mov%.q%.f %a,%b%F%S%L%U", I(-1), I(12), ARC_MACH_5, 0, 0 },
|
---|
303 | /* "asl" is really an "add". */
|
---|
304 | { "asl%.q%.f %a,%b%F%S%L%U", I(-1), I(8), ARC_MACH_5, 0, 0 },
|
---|
305 | /* "lsl" is really an "add". */
|
---|
306 | { "lsl%.q%.f %a,%b%F%S%L%U", I(-1), I(8), ARC_MACH_5, 0, 0 },
|
---|
307 | /* "nop" is really an "xor". */
|
---|
308 | { "nop", 0x7fffffff, 0x7fffffff, ARC_MACH_5, 0, 0 },
|
---|
309 | /* "rlc" is really an "adc". */
|
---|
310 | { "rlc%.q%.f %a,%b%F%S%L%U", I(-1), I(9), ARC_MACH_5, 0, 0 },
|
---|
311 | { "adc%.q%.f %a,%b,%c%F%S%L", I(-1), I(9), ARC_MACH_5, 0, 0 },
|
---|
312 | { "add%.q%.f %a,%b,%c%F%S%L", I(-1), I(8), ARC_MACH_5, 0, 0 },
|
---|
313 | { "and%.q%.f %a,%b,%c%F%S%L", I(-1), I(12), ARC_MACH_5, 0, 0 },
|
---|
314 | { "asr%.q%.f %a,%b%F%S%L", I(-1)|C(-1), I(3)|C(1), ARC_MACH_5, 0, 0 },
|
---|
315 | { "bic%.q%.f %a,%b,%c%F%S%L", I(-1), I(14), ARC_MACH_5, 0, 0 },
|
---|
316 | { "b%q%.n %B", I(-1), I(4), ARC_MACH_5 | ARC_OPCODE_COND_BRANCH, 0, 0 },
|
---|
317 | { "bl%q%.n %B", I(-1), I(5), ARC_MACH_5 | ARC_OPCODE_COND_BRANCH, 0, 0 },
|
---|
318 | { "extb%.q%.f %a,%b%F%S%L", I(-1)|C(-1), I(3)|C(7), ARC_MACH_5, 0, 0 },
|
---|
319 | { "extw%.q%.f %a,%b%F%S%L", I(-1)|C(-1), I(3)|C(8), ARC_MACH_5, 0, 0 },
|
---|
320 | { "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 },
|
---|
321 | { "brk", 0x1ffffe00, 0x1ffffe00, ARC_MACH_7, 0, 0 },
|
---|
322 | { "sleep", 0x1ffffe01, 0x1ffffe01, ARC_MACH_7, 0, 0 },
|
---|
323 | { "swi", 0x1ffffe02, 0x1ffffe02, ARC_MACH_8, 0, 0 },
|
---|
324 | /* %Q: force cond_p=1 -> no shimm values. This insn allows an
|
---|
325 | optional flags spec. */
|
---|
326 | { "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 },
|
---|
327 | { "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 },
|
---|
328 | /* This insn allows an optional flags spec. */
|
---|
329 | { "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 },
|
---|
330 | { "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 },
|
---|
331 | /* Put opcode 1 ld insns first so shimm gets prefered over limm.
|
---|
332 | "[%b]" is before "[%b,%o]" so 0 offsets don't get printed. */
|
---|
333 | { "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 },
|
---|
334 | { "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 },
|
---|
335 | { "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 },
|
---|
336 | { "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 },
|
---|
337 | { "lp%q%.n %B", I(-1), I(6), ARC_MACH_5, 0, 0 },
|
---|
338 | { "lr %a,[%Ab]%S%L", I(-1)|C(-1), I(1)|C(0x10), ARC_MACH_5, 0, 0 },
|
---|
339 | { "lsr%.q%.f %a,%b%F%S%L", I(-1)|C(-1), I(3)|C(2), ARC_MACH_5, 0, 0 },
|
---|
340 | { "or%.q%.f %a,%b,%c%F%S%L", I(-1), I(13), ARC_MACH_5, 0, 0 },
|
---|
341 | { "ror%.q%.f %a,%b%F%S%L", I(-1)|C(-1), I(3)|C(3), ARC_MACH_5, 0, 0 },
|
---|
342 | { "rrc%.q%.f %a,%b%F%S%L", I(-1)|C(-1), I(3)|C(4), ARC_MACH_5, 0, 0 },
|
---|
343 | { "sbc%.q%.f %a,%b,%c%F%S%L", I(-1), I(11), ARC_MACH_5, 0, 0 },
|
---|
344 | { "sexb%.q%.f %a,%b%F%S%L", I(-1)|C(-1), I(3)|C(5), ARC_MACH_5, 0, 0 },
|
---|
345 | { "sexw%.q%.f %a,%b%F%S%L", I(-1)|C(-1), I(3)|C(6), ARC_MACH_5, 0, 0 },
|
---|
346 | { "sr %c,[%Ab]%S%L", I(-1)|A(-1), I(2)|A(0x10), ARC_MACH_5, 0, 0 },
|
---|
347 | /* "[%b]" is before "[%b,%o]" so 0 offsets don't get printed. */
|
---|
348 | { "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 },
|
---|
349 | { "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 },
|
---|
350 | { "sub%.q%.f %a,%b,%c%F%S%L", I(-1), I(10), ARC_MACH_5, 0, 0 },
|
---|
351 | { "xor%.q%.f %a,%b,%c%F%S%L", I(-1), I(15), ARC_MACH_5, 0, 0 }
|
---|
352 | };
|
---|
353 |
|
---|
354 | const int arc_opcodes_count = sizeof (arc_opcodes) / sizeof (arc_opcodes[0]);
|
---|
355 |
|
---|
356 | const struct arc_operand_value arc_reg_names[] =
|
---|
357 | {
|
---|
358 | /* Core register set r0-r63. */
|
---|
359 |
|
---|
360 | /* r0-r28 - general purpose registers. */
|
---|
361 | { "r0", 0, REG, 0 }, { "r1", 1, REG, 0 }, { "r2", 2, REG, 0 },
|
---|
362 | { "r3", 3, REG, 0 }, { "r4", 4, REG, 0 }, { "r5", 5, REG, 0 },
|
---|
363 | { "r6", 6, REG, 0 }, { "r7", 7, REG, 0 }, { "r8", 8, REG, 0 },
|
---|
364 | { "r9", 9, REG, 0 }, { "r10", 10, REG, 0 }, { "r11", 11, REG, 0 },
|
---|
365 | { "r12", 12, REG, 0 }, { "r13", 13, REG, 0 }, { "r14", 14, REG, 0 },
|
---|
366 | { "r15", 15, REG, 0 }, { "r16", 16, REG, 0 }, { "r17", 17, REG, 0 },
|
---|
367 | { "r18", 18, REG, 0 }, { "r19", 19, REG, 0 }, { "r20", 20, REG, 0 },
|
---|
368 | { "r21", 21, REG, 0 }, { "r22", 22, REG, 0 }, { "r23", 23, REG, 0 },
|
---|
369 | { "r24", 24, REG, 0 }, { "r25", 25, REG, 0 }, { "r26", 26, REG, 0 },
|
---|
370 | { "r27", 27, REG, 0 }, { "r28", 28, REG, 0 },
|
---|
371 | /* Maskable interrupt link register. */
|
---|
372 | { "ilink1", 29, REG, 0 },
|
---|
373 | /* Maskable interrupt link register. */
|
---|
374 | { "ilink2", 30, REG, 0 },
|
---|
375 | /* Branch-link register. */
|
---|
376 | { "blink", 31, REG, 0 },
|
---|
377 |
|
---|
378 | /* r32-r59 reserved for extensions. */
|
---|
379 | { "r32", 32, REG, 0 }, { "r33", 33, REG, 0 }, { "r34", 34, REG, 0 },
|
---|
380 | { "r35", 35, REG, 0 }, { "r36", 36, REG, 0 }, { "r37", 37, REG, 0 },
|
---|
381 | { "r38", 38, REG, 0 }, { "r39", 39, REG, 0 }, { "r40", 40, REG, 0 },
|
---|
382 | { "r41", 41, REG, 0 }, { "r42", 42, REG, 0 }, { "r43", 43, REG, 0 },
|
---|
383 | { "r44", 44, REG, 0 }, { "r45", 45, REG, 0 }, { "r46", 46, REG, 0 },
|
---|
384 | { "r47", 47, REG, 0 }, { "r48", 48, REG, 0 }, { "r49", 49, REG, 0 },
|
---|
385 | { "r50", 50, REG, 0 }, { "r51", 51, REG, 0 }, { "r52", 52, REG, 0 },
|
---|
386 | { "r53", 53, REG, 0 }, { "r54", 54, REG, 0 }, { "r55", 55, REG, 0 },
|
---|
387 | { "r56", 56, REG, 0 }, { "r57", 57, REG, 0 }, { "r58", 58, REG, 0 },
|
---|
388 | { "r59", 59, REG, 0 },
|
---|
389 |
|
---|
390 | /* Loop count register (24 bits). */
|
---|
391 | { "lp_count", 60, REG, 0 },
|
---|
392 | /* Short immediate data indicator setting flags. */
|
---|
393 | { "r61", 61, REG, ARC_REGISTER_READONLY },
|
---|
394 | /* Long immediate data indicator setting flags. */
|
---|
395 | { "r62", 62, REG, ARC_REGISTER_READONLY },
|
---|
396 | /* Short immediate data indicator not setting flags. */
|
---|
397 | { "r63", 63, REG, ARC_REGISTER_READONLY },
|
---|
398 |
|
---|
399 | /* Small-data base register. */
|
---|
400 | { "gp", 26, REG, 0 },
|
---|
401 | /* Frame pointer. */
|
---|
402 | { "fp", 27, REG, 0 },
|
---|
403 | /* Stack pointer. */
|
---|
404 | { "sp", 28, REG, 0 },
|
---|
405 |
|
---|
406 | { "r29", 29, REG, 0 },
|
---|
407 | { "r30", 30, REG, 0 },
|
---|
408 | { "r31", 31, REG, 0 },
|
---|
409 | { "r60", 60, REG, 0 },
|
---|
410 |
|
---|
411 | /* Auxiliary register set. */
|
---|
412 |
|
---|
413 | /* Auxiliary register address map:
|
---|
414 | 0xffffffff-0xffffff00 (-1..-256) - customer shimm allocation
|
---|
415 | 0xfffffeff-0x80000000 - customer limm allocation
|
---|
416 | 0x7fffffff-0x00000100 - ARC limm allocation
|
---|
417 | 0x000000ff-0x00000000 - ARC shimm allocation */
|
---|
418 |
|
---|
419 | /* Base case auxiliary registers (shimm address). */
|
---|
420 | { "status", 0x00, AUXREG, 0 },
|
---|
421 | { "semaphore", 0x01, AUXREG, 0 },
|
---|
422 | { "lp_start", 0x02, AUXREG, 0 },
|
---|
423 | { "lp_end", 0x03, AUXREG, 0 },
|
---|
424 | { "identity", 0x04, AUXREG, ARC_REGISTER_READONLY },
|
---|
425 | { "debug", 0x05, AUXREG, 0 },
|
---|
426 | };
|
---|
427 |
|
---|
428 | const int arc_reg_names_count =
|
---|
429 | sizeof (arc_reg_names) / sizeof (arc_reg_names[0]);
|
---|
430 |
|
---|
431 | /* The suffix table.
|
---|
432 | Operands with the same name must be stored together. */
|
---|
433 |
|
---|
434 | const struct arc_operand_value arc_suffixes[] =
|
---|
435 | {
|
---|
436 | /* Entry 0 is special, default values aren't printed by the disassembler. */
|
---|
437 | { "", 0, -1, 0 },
|
---|
438 |
|
---|
439 | /* Base case condition codes. */
|
---|
440 | { "al", 0, COND, 0 },
|
---|
441 | { "ra", 0, COND, 0 },
|
---|
442 | { "eq", 1, COND, 0 },
|
---|
443 | { "z", 1, COND, 0 },
|
---|
444 | { "ne", 2, COND, 0 },
|
---|
445 | { "nz", 2, COND, 0 },
|
---|
446 | { "pl", 3, COND, 0 },
|
---|
447 | { "p", 3, COND, 0 },
|
---|
448 | { "mi", 4, COND, 0 },
|
---|
449 | { "n", 4, COND, 0 },
|
---|
450 | { "cs", 5, COND, 0 },
|
---|
451 | { "c", 5, COND, 0 },
|
---|
452 | { "lo", 5, COND, 0 },
|
---|
453 | { "cc", 6, COND, 0 },
|
---|
454 | { "nc", 6, COND, 0 },
|
---|
455 | { "hs", 6, COND, 0 },
|
---|
456 | { "vs", 7, COND, 0 },
|
---|
457 | { "v", 7, COND, 0 },
|
---|
458 | { "vc", 8, COND, 0 },
|
---|
459 | { "nv", 8, COND, 0 },
|
---|
460 | { "gt", 9, COND, 0 },
|
---|
461 | { "ge", 10, COND, 0 },
|
---|
462 | { "lt", 11, COND, 0 },
|
---|
463 | { "le", 12, COND, 0 },
|
---|
464 | { "hi", 13, COND, 0 },
|
---|
465 | { "ls", 14, COND, 0 },
|
---|
466 | { "pnz", 15, COND, 0 },
|
---|
467 |
|
---|
468 | /* Condition codes 16-31 reserved for extensions. */
|
---|
469 |
|
---|
470 | { "f", 1, FLAG, 0 },
|
---|
471 |
|
---|
472 | { "nd", ARC_DELAY_NONE, DELAY, 0 },
|
---|
473 | { "d", ARC_DELAY_NORMAL, DELAY, 0 },
|
---|
474 | { "jd", ARC_DELAY_JUMP, DELAY, 0 },
|
---|
475 |
|
---|
476 | { "b", 1, SIZE1, 0 },
|
---|
477 | { "b", 1, SIZE10, 0 },
|
---|
478 | { "b", 1, SIZE22, 0 },
|
---|
479 | { "w", 2, SIZE1, 0 },
|
---|
480 | { "w", 2, SIZE10, 0 },
|
---|
481 | { "w", 2, SIZE22, 0 },
|
---|
482 | { "x", 1, SIGN0, 0 },
|
---|
483 | { "x", 1, SIGN9, 0 },
|
---|
484 | { "a", 1, ADDRESS3, 0 },
|
---|
485 | { "a", 1, ADDRESS12, 0 },
|
---|
486 | { "a", 1, ADDRESS24, 0 },
|
---|
487 |
|
---|
488 | { "di", 1, CACHEBYPASS5, 0 },
|
---|
489 | { "di", 1, CACHEBYPASS14, 0 },
|
---|
490 | { "di", 1, CACHEBYPASS26, 0 },
|
---|
491 | };
|
---|
492 |
|
---|
493 | const int arc_suffixes_count =
|
---|
494 | sizeof (arc_suffixes) / sizeof (arc_suffixes[0]);
|
---|
495 |
|
---|
496 | /* Indexed by first letter of opcode. Points to chain of opcodes with same
|
---|
497 | first letter. */
|
---|
498 | static struct arc_opcode *opcode_map[26 + 1];
|
---|
499 |
|
---|
500 | /* Indexed by insn code. Points to chain of opcodes with same insn code. */
|
---|
501 | static struct arc_opcode *icode_map[32];
|
---|
502 | |
---|
503 |
|
---|
504 | /* Configuration flags. */
|
---|
505 |
|
---|
506 | /* Various ARC_HAVE_XXX bits. */
|
---|
507 | static int cpu_type;
|
---|
508 |
|
---|
509 | /* Translate a bfd_mach_arc_xxx value to a ARC_MACH_XXX value. */
|
---|
510 |
|
---|
511 | int
|
---|
512 | arc_get_opcode_mach (bfd_mach, big_p)
|
---|
513 | int bfd_mach, big_p;
|
---|
514 | {
|
---|
515 | static int mach_type_map[] =
|
---|
516 | {
|
---|
517 | ARC_MACH_5,
|
---|
518 | ARC_MACH_6,
|
---|
519 | ARC_MACH_7,
|
---|
520 | ARC_MACH_8
|
---|
521 | };
|
---|
522 | return mach_type_map[bfd_mach - bfd_mach_arc_5] | (big_p ? ARC_MACH_BIG : 0);
|
---|
523 | }
|
---|
524 |
|
---|
525 | /* Initialize any tables that need it.
|
---|
526 | Must be called once at start up (or when first needed).
|
---|
527 |
|
---|
528 | FLAGS is a set of bits that say what version of the cpu we have,
|
---|
529 | and in particular at least (one of) ARC_MACH_XXX. */
|
---|
530 |
|
---|
531 | void
|
---|
532 | arc_opcode_init_tables (flags)
|
---|
533 | int flags;
|
---|
534 | {
|
---|
535 | static int init_p = 0;
|
---|
536 |
|
---|
537 | cpu_type = flags;
|
---|
538 |
|
---|
539 | /* We may be intentionally called more than once (for example gdb will call
|
---|
540 | us each time the user switches cpu). These tables only need to be init'd
|
---|
541 | once though. */
|
---|
542 | if (!init_p)
|
---|
543 | {
|
---|
544 | register int i,n;
|
---|
545 |
|
---|
546 | memset (arc_operand_map, 0, sizeof (arc_operand_map));
|
---|
547 | n = sizeof (arc_operands) / sizeof (arc_operands[0]);
|
---|
548 | for (i = 0; i < n; ++i)
|
---|
549 | arc_operand_map[arc_operands[i].fmt] = i;
|
---|
550 |
|
---|
551 | memset (opcode_map, 0, sizeof (opcode_map));
|
---|
552 | memset (icode_map, 0, sizeof (icode_map));
|
---|
553 | /* Scan the table backwards so macros appear at the front. */
|
---|
554 | for (i = arc_opcodes_count - 1; i >= 0; --i)
|
---|
555 | {
|
---|
556 | int opcode_hash = ARC_HASH_OPCODE (arc_opcodes[i].syntax);
|
---|
557 | int icode_hash = ARC_HASH_ICODE (arc_opcodes[i].value);
|
---|
558 |
|
---|
559 | arc_opcodes[i].next_asm = opcode_map[opcode_hash];
|
---|
560 | opcode_map[opcode_hash] = &arc_opcodes[i];
|
---|
561 |
|
---|
562 | arc_opcodes[i].next_dis = icode_map[icode_hash];
|
---|
563 | icode_map[icode_hash] = &arc_opcodes[i];
|
---|
564 | }
|
---|
565 |
|
---|
566 | init_p = 1;
|
---|
567 | }
|
---|
568 | }
|
---|
569 |
|
---|
570 | /* Return non-zero if OPCODE is supported on the specified cpu.
|
---|
571 | Cpu selection is made when calling `arc_opcode_init_tables'. */
|
---|
572 |
|
---|
573 | int
|
---|
574 | arc_opcode_supported (opcode)
|
---|
575 | const struct arc_opcode *opcode;
|
---|
576 | {
|
---|
577 | if (ARC_OPCODE_CPU (opcode->flags) <= cpu_type)
|
---|
578 | return 1;
|
---|
579 | return 0;
|
---|
580 | }
|
---|
581 |
|
---|
582 | /* Return the first insn in the chain for assembling INSN. */
|
---|
583 |
|
---|
584 | const struct arc_opcode *
|
---|
585 | arc_opcode_lookup_asm (insn)
|
---|
586 | const char *insn;
|
---|
587 | {
|
---|
588 | return opcode_map[ARC_HASH_OPCODE (insn)];
|
---|
589 | }
|
---|
590 |
|
---|
591 | /* Return the first insn in the chain for disassembling INSN. */
|
---|
592 |
|
---|
593 | const struct arc_opcode *
|
---|
594 | arc_opcode_lookup_dis (insn)
|
---|
595 | unsigned int insn;
|
---|
596 | {
|
---|
597 | return icode_map[ARC_HASH_ICODE (insn)];
|
---|
598 | }
|
---|
599 | |
---|
600 |
|
---|
601 | /* Nonzero if we've seen an 'f' suffix (in certain insns). */
|
---|
602 | static int flag_p;
|
---|
603 |
|
---|
604 | /* Nonzero if we've finished processing the 'f' suffix. */
|
---|
605 | static int flagshimm_handled_p;
|
---|
606 |
|
---|
607 | /* Nonzero if we've seen a 'a' suffix (address writeback). */
|
---|
608 | static int addrwb_p;
|
---|
609 |
|
---|
610 | /* Nonzero if we've seen a 'q' suffix (condition code). */
|
---|
611 | static int cond_p;
|
---|
612 |
|
---|
613 | /* Nonzero if we've inserted a nullify condition. */
|
---|
614 | static int nullify_p;
|
---|
615 |
|
---|
616 | /* The value of the a nullify condition we inserted. */
|
---|
617 | static int nullify;
|
---|
618 |
|
---|
619 | /* Nonzero if we've inserted jumpflags. */
|
---|
620 | static int jumpflags_p;
|
---|
621 |
|
---|
622 | /* Nonzero if we've inserted a shimm. */
|
---|
623 | static int shimm_p;
|
---|
624 |
|
---|
625 | /* The value of the shimm we inserted (each insn only gets one but it can
|
---|
626 | appear multiple times). */
|
---|
627 | static int shimm;
|
---|
628 |
|
---|
629 | /* Nonzero if we've inserted a limm (during assembly) or seen a limm
|
---|
630 | (during disassembly). */
|
---|
631 | static int limm_p;
|
---|
632 |
|
---|
633 | /* The value of the limm we inserted. Each insn only gets one but it can
|
---|
634 | appear multiple times. */
|
---|
635 | static long limm;
|
---|
636 | |
---|
637 |
|
---|
638 | /* Insertion functions. */
|
---|
639 |
|
---|
640 | /* Called by the assembler before parsing an instruction. */
|
---|
641 |
|
---|
642 | void
|
---|
643 | arc_opcode_init_insert ()
|
---|
644 | {
|
---|
645 | int i;
|
---|
646 |
|
---|
647 | for(i = 0; i < OPERANDS; i++)
|
---|
648 | ls_operand[i] = OP_NONE;
|
---|
649 |
|
---|
650 | flag_p = 0;
|
---|
651 | flagshimm_handled_p = 0;
|
---|
652 | cond_p = 0;
|
---|
653 | addrwb_p = 0;
|
---|
654 | shimm_p = 0;
|
---|
655 | limm_p = 0;
|
---|
656 | jumpflags_p = 0;
|
---|
657 | nullify_p = 0;
|
---|
658 | nullify = 0; /* the default is important. */
|
---|
659 | }
|
---|
660 |
|
---|
661 | /* Called by the assembler to see if the insn has a limm operand.
|
---|
662 | Also called by the disassembler to see if the insn contains a limm. */
|
---|
663 |
|
---|
664 | int
|
---|
665 | arc_opcode_limm_p (limmp)
|
---|
666 | long *limmp;
|
---|
667 | {
|
---|
668 | if (limmp)
|
---|
669 | *limmp = limm;
|
---|
670 | return limm_p;
|
---|
671 | }
|
---|
672 |
|
---|
673 | /* Insert a value into a register field.
|
---|
674 | If REG is NULL, then this is actually a constant.
|
---|
675 |
|
---|
676 | We must also handle auxiliary registers for lr/sr insns. */
|
---|
677 |
|
---|
678 | static arc_insn
|
---|
679 | insert_reg (insn, operand, mods, reg, value, errmsg)
|
---|
680 | arc_insn insn;
|
---|
681 | const struct arc_operand *operand;
|
---|
682 | int mods;
|
---|
683 | const struct arc_operand_value *reg;
|
---|
684 | long value;
|
---|
685 | const char **errmsg;
|
---|
686 | {
|
---|
687 | static char buf[100];
|
---|
688 | enum operand op_type = OP_NONE;
|
---|
689 |
|
---|
690 | if (reg == NULL)
|
---|
691 | {
|
---|
692 | /* We have a constant that also requires a value stored in a register
|
---|
693 | field. Handle these by updating the register field and saving the
|
---|
694 | value for later handling by either %S (shimm) or %L (limm). */
|
---|
695 |
|
---|
696 | /* Try to use a shimm value before a limm one. */
|
---|
697 | if (ARC_SHIMM_CONST_P (value)
|
---|
698 | /* If we've seen a conditional suffix we have to use a limm. */
|
---|
699 | && !cond_p
|
---|
700 | /* If we already have a shimm value that is different than ours
|
---|
701 | we have to use a limm. */
|
---|
702 | && (!shimm_p || shimm == value))
|
---|
703 | {
|
---|
704 | int marker;
|
---|
705 |
|
---|
706 | op_type = OP_SHIMM;
|
---|
707 | /* forget about shimm as dest mlm. */
|
---|
708 |
|
---|
709 | if ('a' != operand->fmt)
|
---|
710 | {
|
---|
711 | shimm_p = 1;
|
---|
712 | shimm = value;
|
---|
713 | flagshimm_handled_p = 1;
|
---|
714 | marker = flag_p ? ARC_REG_SHIMM_UPDATE : ARC_REG_SHIMM;
|
---|
715 | }
|
---|
716 | else
|
---|
717 | {
|
---|
718 | /* don't request flag setting on shimm as dest. */
|
---|
719 | marker = ARC_REG_SHIMM;
|
---|
720 | }
|
---|
721 | insn |= marker << operand->shift;
|
---|
722 | /* insn |= value & 511; - done later. */
|
---|
723 | }
|
---|
724 | /* We have to use a limm. If we've already seen one they must match. */
|
---|
725 | else if (!limm_p || limm == value)
|
---|
726 | {
|
---|
727 | op_type = OP_LIMM;
|
---|
728 | limm_p = 1;
|
---|
729 | limm = value;
|
---|
730 | insn |= ARC_REG_LIMM << operand->shift;
|
---|
731 | /* The constant is stored later. */
|
---|
732 | }
|
---|
733 | else
|
---|
734 | {
|
---|
735 | *errmsg = "unable to fit different valued constants into instruction";
|
---|
736 | }
|
---|
737 | }
|
---|
738 | else
|
---|
739 | {
|
---|
740 | /* We have to handle both normal and auxiliary registers. */
|
---|
741 |
|
---|
742 | if (reg->type == AUXREG)
|
---|
743 | {
|
---|
744 | if (!(mods & ARC_MOD_AUXREG))
|
---|
745 | *errmsg = "auxiliary register not allowed here";
|
---|
746 | else
|
---|
747 | {
|
---|
748 | if ((insn & I(-1)) == I(2)) /* check for use validity. */
|
---|
749 | {
|
---|
750 | if (reg->flags & ARC_REGISTER_READONLY)
|
---|
751 | *errmsg = "attempt to set readonly register";
|
---|
752 | }
|
---|
753 | else
|
---|
754 | {
|
---|
755 | if (reg->flags & ARC_REGISTER_WRITEONLY)
|
---|
756 | *errmsg = "attempt to read writeonly register";
|
---|
757 | }
|
---|
758 | insn |= ARC_REG_SHIMM << operand->shift;
|
---|
759 | insn |= reg->value << arc_operands[reg->type].shift;
|
---|
760 | }
|
---|
761 | }
|
---|
762 | else
|
---|
763 | {
|
---|
764 | /* check for use validity. */
|
---|
765 | if ('a' == operand->fmt || ((insn & I(-1)) < I(2)))
|
---|
766 | {
|
---|
767 | if (reg->flags & ARC_REGISTER_READONLY)
|
---|
768 | *errmsg = "attempt to set readonly register";
|
---|
769 | }
|
---|
770 | if ('a' != operand->fmt)
|
---|
771 | {
|
---|
772 | if (reg->flags & ARC_REGISTER_WRITEONLY)
|
---|
773 | *errmsg = "attempt to read writeonly register";
|
---|
774 | }
|
---|
775 | /* We should never get an invalid register number here. */
|
---|
776 | if ((unsigned int) reg->value > 60)
|
---|
777 | {
|
---|
778 | sprintf (buf, "invalid register number `%d'", reg->value);
|
---|
779 | *errmsg = buf;
|
---|
780 | }
|
---|
781 | insn |= reg->value << operand->shift;
|
---|
782 | op_type = OP_REG;
|
---|
783 | }
|
---|
784 | }
|
---|
785 |
|
---|
786 | switch (operand->fmt)
|
---|
787 | {
|
---|
788 | case 'a':
|
---|
789 | ls_operand[LS_DEST] = op_type;
|
---|
790 | break;
|
---|
791 | case 's':
|
---|
792 | ls_operand[LS_BASE] = op_type;
|
---|
793 | break;
|
---|
794 | case 'c':
|
---|
795 | if ((insn & I(-1)) == I(2))
|
---|
796 | ls_operand[LS_VALUE] = op_type;
|
---|
797 | else
|
---|
798 | ls_operand[LS_OFFSET] = op_type;
|
---|
799 | break;
|
---|
800 | case 'o': case 'O':
|
---|
801 | ls_operand[LS_OFFSET] = op_type;
|
---|
802 | break;
|
---|
803 | }
|
---|
804 |
|
---|
805 | return insn;
|
---|
806 | }
|
---|
807 |
|
---|
808 | /* Called when we see an 'f' flag. */
|
---|
809 |
|
---|
810 | static arc_insn
|
---|
811 | insert_flag (insn, operand, mods, reg, value, errmsg)
|
---|
812 | arc_insn insn;
|
---|
813 | const struct arc_operand *operand ATTRIBUTE_UNUSED;
|
---|
814 | int mods ATTRIBUTE_UNUSED;
|
---|
815 | const struct arc_operand_value *reg ATTRIBUTE_UNUSED;
|
---|
816 | long value ATTRIBUTE_UNUSED;
|
---|
817 | const char **errmsg ATTRIBUTE_UNUSED;
|
---|
818 | {
|
---|
819 | /* We can't store anything in the insn until we've parsed the registers.
|
---|
820 | Just record the fact that we've got this flag. `insert_reg' will use it
|
---|
821 | to store the correct value (ARC_REG_SHIMM_UPDATE or bit 0x100). */
|
---|
822 | flag_p = 1;
|
---|
823 | return insn;
|
---|
824 | }
|
---|
825 |
|
---|
826 | /* Called when we see an nullify condition. */
|
---|
827 |
|
---|
828 | static arc_insn
|
---|
829 | insert_nullify (insn, operand, mods, reg, value, errmsg)
|
---|
830 | arc_insn insn;
|
---|
831 | const struct arc_operand *operand;
|
---|
832 | int mods ATTRIBUTE_UNUSED;
|
---|
833 | const struct arc_operand_value *reg ATTRIBUTE_UNUSED;
|
---|
834 | long value;
|
---|
835 | const char **errmsg ATTRIBUTE_UNUSED;
|
---|
836 | {
|
---|
837 | nullify_p = 1;
|
---|
838 | insn |= (value & ((1 << operand->bits) - 1)) << operand->shift;
|
---|
839 | nullify = value;
|
---|
840 | return insn;
|
---|
841 | }
|
---|
842 |
|
---|
843 | /* Called after completely building an insn to ensure the 'f' flag gets set
|
---|
844 | properly. This is needed because we don't know how to set this flag until
|
---|
845 | we've parsed the registers. */
|
---|
846 |
|
---|
847 | static arc_insn
|
---|
848 | insert_flagfinish (insn, operand, mods, reg, value, errmsg)
|
---|
849 | arc_insn insn;
|
---|
850 | const struct arc_operand *operand;
|
---|
851 | int mods ATTRIBUTE_UNUSED;
|
---|
852 | const struct arc_operand_value *reg ATTRIBUTE_UNUSED;
|
---|
853 | long value ATTRIBUTE_UNUSED;
|
---|
854 | const char **errmsg ATTRIBUTE_UNUSED;
|
---|
855 | {
|
---|
856 | if (flag_p && !flagshimm_handled_p)
|
---|
857 | {
|
---|
858 | if (shimm_p)
|
---|
859 | abort ();
|
---|
860 | flagshimm_handled_p = 1;
|
---|
861 | insn |= (1 << operand->shift);
|
---|
862 | }
|
---|
863 | return insn;
|
---|
864 | }
|
---|
865 |
|
---|
866 | /* Called when we see a conditional flag (eg: .eq). */
|
---|
867 |
|
---|
868 | static arc_insn
|
---|
869 | insert_cond (insn, operand, mods, reg, value, errmsg)
|
---|
870 | arc_insn insn;
|
---|
871 | const struct arc_operand *operand;
|
---|
872 | int mods ATTRIBUTE_UNUSED;
|
---|
873 | const struct arc_operand_value *reg ATTRIBUTE_UNUSED;
|
---|
874 | long value;
|
---|
875 | const char **errmsg ATTRIBUTE_UNUSED;
|
---|
876 | {
|
---|
877 | cond_p = 1;
|
---|
878 | insn |= (value & ((1 << operand->bits) - 1)) << operand->shift;
|
---|
879 | return insn;
|
---|
880 | }
|
---|
881 |
|
---|
882 | /* Used in the "j" instruction to prevent constants from being interpreted as
|
---|
883 | shimm values (which the jump insn doesn't accept). This can also be used
|
---|
884 | to force the use of limm values in other situations (eg: ld r0,[foo] uses
|
---|
885 | this).
|
---|
886 | ??? The mechanism is sound. Access to it is a bit klunky right now. */
|
---|
887 |
|
---|
888 | static arc_insn
|
---|
889 | insert_forcelimm (insn, operand, mods, reg, value, errmsg)
|
---|
890 | arc_insn insn;
|
---|
891 | const struct arc_operand *operand ATTRIBUTE_UNUSED;
|
---|
892 | int mods ATTRIBUTE_UNUSED;
|
---|
893 | const struct arc_operand_value *reg ATTRIBUTE_UNUSED;
|
---|
894 | long value ATTRIBUTE_UNUSED;
|
---|
895 | const char **errmsg ATTRIBUTE_UNUSED;
|
---|
896 | {
|
---|
897 | cond_p = 1;
|
---|
898 | return insn;
|
---|
899 | }
|
---|
900 |
|
---|
901 | static arc_insn
|
---|
902 | insert_addr_wb (insn, operand, mods, reg, value, errmsg)
|
---|
903 | arc_insn insn;
|
---|
904 | const struct arc_operand *operand;
|
---|
905 | int mods ATTRIBUTE_UNUSED;
|
---|
906 | const struct arc_operand_value *reg ATTRIBUTE_UNUSED;
|
---|
907 | long value ATTRIBUTE_UNUSED;
|
---|
908 | const char **errmsg ATTRIBUTE_UNUSED;
|
---|
909 | {
|
---|
910 | addrwb_p = 1 << operand->shift;
|
---|
911 | return insn;
|
---|
912 | }
|
---|
913 |
|
---|
914 | static arc_insn
|
---|
915 | insert_base (insn, operand, mods, reg, value, errmsg)
|
---|
916 | arc_insn insn;
|
---|
917 | const struct arc_operand *operand;
|
---|
918 | int mods;
|
---|
919 | const struct arc_operand_value *reg;
|
---|
920 | long value;
|
---|
921 | const char **errmsg;
|
---|
922 | {
|
---|
923 | if (reg != NULL)
|
---|
924 | {
|
---|
925 | arc_insn myinsn;
|
---|
926 | myinsn = insert_reg (0, operand,mods, reg, value, errmsg) >> operand->shift;
|
---|
927 | insn |= B(myinsn);
|
---|
928 | ls_operand[LS_BASE] = OP_REG;
|
---|
929 | }
|
---|
930 | else if (ARC_SHIMM_CONST_P (value) && !cond_p)
|
---|
931 | {
|
---|
932 | if (shimm_p && value != shimm)
|
---|
933 | {
|
---|
934 | /* convert the previous shimm operand to a limm. */
|
---|
935 | limm_p = 1;
|
---|
936 | limm = shimm;
|
---|
937 | insn &= ~C(-1); /* we know where the value is in insn. */
|
---|
938 | insn |= C(ARC_REG_LIMM);
|
---|
939 | ls_operand[LS_VALUE] = OP_LIMM;
|
---|
940 | }
|
---|
941 | insn |= ARC_REG_SHIMM << operand->shift;
|
---|
942 | shimm_p = 1;
|
---|
943 | shimm = value;
|
---|
944 | ls_operand[LS_BASE] = OP_SHIMM;
|
---|
945 | }
|
---|
946 | else
|
---|
947 | {
|
---|
948 | if (limm_p && value != limm)
|
---|
949 | {
|
---|
950 | *errmsg = "too many long constants";
|
---|
951 | return insn;
|
---|
952 | }
|
---|
953 | limm_p = 1;
|
---|
954 | limm = value;
|
---|
955 | insn |= B(ARC_REG_LIMM);
|
---|
956 | ls_operand[LS_BASE] = OP_LIMM;
|
---|
957 | }
|
---|
958 |
|
---|
959 | return insn;
|
---|
960 | }
|
---|
961 |
|
---|
962 | /* Used in ld/st insns to handle the offset field. We don't try to
|
---|
963 | match operand syntax here. we catch bad combinations later. */
|
---|
964 |
|
---|
965 | static arc_insn
|
---|
966 | insert_offset (insn, operand, mods, reg, value, errmsg)
|
---|
967 | arc_insn insn;
|
---|
968 | const struct arc_operand *operand;
|
---|
969 | int mods;
|
---|
970 | const struct arc_operand_value *reg;
|
---|
971 | long value;
|
---|
972 | const char **errmsg;
|
---|
973 | {
|
---|
974 | long minval, maxval;
|
---|
975 |
|
---|
976 | if (reg != NULL)
|
---|
977 | {
|
---|
978 | arc_insn myinsn;
|
---|
979 | myinsn = insert_reg (0,operand,mods,reg,value,errmsg) >> operand->shift;
|
---|
980 | ls_operand[LS_OFFSET] = OP_REG;
|
---|
981 | if (operand->flags & ARC_OPERAND_LOAD) /* not if store, catch it later. */
|
---|
982 | if ((insn & I(-1)) != I(1)) /* not if opcode == 1, catch it later. */
|
---|
983 | insn |= C(myinsn);
|
---|
984 | }
|
---|
985 | else
|
---|
986 | {
|
---|
987 | /* This is *way* more general than necessary, but maybe some day it'll
|
---|
988 | be useful. */
|
---|
989 | if (operand->flags & ARC_OPERAND_SIGNED)
|
---|
990 | {
|
---|
991 | minval = -(1 << (operand->bits - 1));
|
---|
992 | maxval = (1 << (operand->bits - 1)) - 1;
|
---|
993 | }
|
---|
994 | else
|
---|
995 | {
|
---|
996 | minval = 0;
|
---|
997 | maxval = (1 << operand->bits) - 1;
|
---|
998 | }
|
---|
999 | if ((cond_p && !limm_p) || (value < minval || value > maxval))
|
---|
1000 | {
|
---|
1001 | if (limm_p && value != limm)
|
---|
1002 | {
|
---|
1003 | *errmsg = "too many long constants";
|
---|
1004 | }
|
---|
1005 | else
|
---|
1006 | {
|
---|
1007 | limm_p = 1;
|
---|
1008 | limm = value;
|
---|
1009 | if (operand->flags & ARC_OPERAND_STORE)
|
---|
1010 | insn |= B(ARC_REG_LIMM);
|
---|
1011 | if (operand->flags & ARC_OPERAND_LOAD)
|
---|
1012 | insn |= C(ARC_REG_LIMM);
|
---|
1013 | ls_operand[LS_OFFSET] = OP_LIMM;
|
---|
1014 | }
|
---|
1015 | }
|
---|
1016 | else
|
---|
1017 | {
|
---|
1018 | if ((value < minval || value > maxval))
|
---|
1019 | *errmsg = "need too many limms";
|
---|
1020 | else if (shimm_p && value != shimm)
|
---|
1021 | {
|
---|
1022 | /* check for bad operand combinations before we lose info about them. */
|
---|
1023 | if ((insn & I(-1)) == I(1))
|
---|
1024 | {
|
---|
1025 | *errmsg = "to many shimms in load";
|
---|
1026 | goto out;
|
---|
1027 | }
|
---|
1028 | if (limm_p && operand->flags & ARC_OPERAND_LOAD)
|
---|
1029 | {
|
---|
1030 | *errmsg = "too many long constants";
|
---|
1031 | goto out;
|
---|
1032 | }
|
---|
1033 | /* convert what we thought was a shimm to a limm. */
|
---|
1034 | limm_p = 1;
|
---|
1035 | limm = shimm;
|
---|
1036 | if (ls_operand[LS_VALUE] == OP_SHIMM && operand->flags & ARC_OPERAND_STORE)
|
---|
1037 | {
|
---|
1038 | insn &= ~C(-1);
|
---|
1039 | insn |= C(ARC_REG_LIMM);
|
---|
1040 | ls_operand[LS_VALUE] = OP_LIMM;
|
---|
1041 | }
|
---|
1042 | if (ls_operand[LS_BASE] == OP_SHIMM && operand->flags & ARC_OPERAND_STORE)
|
---|
1043 | {
|
---|
1044 | insn &= ~B(-1);
|
---|
1045 | insn |= B(ARC_REG_LIMM);
|
---|
1046 | ls_operand[LS_BASE] = OP_LIMM;
|
---|
1047 | }
|
---|
1048 | }
|
---|
1049 | shimm = value;
|
---|
1050 | shimm_p = 1;
|
---|
1051 | ls_operand[LS_OFFSET] = OP_SHIMM;
|
---|
1052 | }
|
---|
1053 | }
|
---|
1054 | out:
|
---|
1055 | return insn;
|
---|
1056 | }
|
---|
1057 |
|
---|
1058 | /* Used in st insns to do final disasemble syntax check. */
|
---|
1059 |
|
---|
1060 | static long
|
---|
1061 | extract_st_syntax (insn, operand, mods, opval, invalid)
|
---|
1062 | arc_insn *insn;
|
---|
1063 | const struct arc_operand *operand ATTRIBUTE_UNUSED;
|
---|
1064 | int mods ATTRIBUTE_UNUSED;
|
---|
1065 | const struct arc_operand_value **opval ATTRIBUTE_UNUSED;
|
---|
1066 | int *invalid;
|
---|
1067 | {
|
---|
1068 | #define ST_SYNTAX(V,B,O) \
|
---|
1069 | ((ls_operand[LS_VALUE] == (V) && \
|
---|
1070 | ls_operand[LS_BASE] == (B) && \
|
---|
1071 | ls_operand[LS_OFFSET] == (O)))
|
---|
1072 |
|
---|
1073 | if (!((ST_SYNTAX(OP_REG,OP_REG,OP_NONE) && (insn[0] & 511) == 0)
|
---|
1074 | || ST_SYNTAX(OP_REG,OP_LIMM,OP_NONE)
|
---|
1075 | || (ST_SYNTAX(OP_SHIMM,OP_REG,OP_NONE) && (insn[0] & 511) == 0)
|
---|
1076 | || (ST_SYNTAX(OP_SHIMM,OP_SHIMM,OP_NONE) && (insn[0] & 511) == 0)
|
---|
1077 | || ST_SYNTAX(OP_SHIMM,OP_LIMM,OP_NONE)
|
---|
1078 | || ST_SYNTAX(OP_SHIMM,OP_LIMM,OP_SHIMM)
|
---|
1079 | || ST_SYNTAX(OP_SHIMM,OP_SHIMM,OP_SHIMM)
|
---|
1080 | || (ST_SYNTAX(OP_LIMM,OP_REG,OP_NONE) && (insn[0] & 511) == 0)
|
---|
1081 | || ST_SYNTAX(OP_REG,OP_REG,OP_SHIMM)
|
---|
1082 | || ST_SYNTAX(OP_REG,OP_SHIMM,OP_SHIMM)
|
---|
1083 | || ST_SYNTAX(OP_SHIMM,OP_REG,OP_SHIMM)
|
---|
1084 | || ST_SYNTAX(OP_LIMM,OP_SHIMM,OP_SHIMM)
|
---|
1085 | || ST_SYNTAX(OP_LIMM,OP_SHIMM,OP_NONE)
|
---|
1086 | || ST_SYNTAX(OP_LIMM,OP_REG,OP_SHIMM)))
|
---|
1087 | *invalid = 1;
|
---|
1088 | return 0;
|
---|
1089 | }
|
---|
1090 |
|
---|
1091 | int
|
---|
1092 | arc_limm_fixup_adjust(insn)
|
---|
1093 | arc_insn insn;
|
---|
1094 | {
|
---|
1095 | int retval = 0;
|
---|
1096 |
|
---|
1097 | /* check for st shimm,[limm]. */
|
---|
1098 | if ((insn & (I(-1) | C(-1) | B(-1))) ==
|
---|
1099 | (I(2) | C(ARC_REG_SHIMM) | B(ARC_REG_LIMM)))
|
---|
1100 | {
|
---|
1101 | retval = insn & 0x1ff;
|
---|
1102 | if (retval & 0x100) /* sign extend 9 bit offset. */
|
---|
1103 | retval |= ~0x1ff;
|
---|
1104 | }
|
---|
1105 | return -retval; /* negate offset for return. */
|
---|
1106 | }
|
---|
1107 |
|
---|
1108 | /* Used in st insns to do final syntax check. */
|
---|
1109 |
|
---|
1110 | static arc_insn
|
---|
1111 | insert_st_syntax (insn, operand, mods, reg, value, errmsg)
|
---|
1112 | arc_insn insn;
|
---|
1113 | const struct arc_operand *operand ATTRIBUTE_UNUSED;
|
---|
1114 | int mods ATTRIBUTE_UNUSED;
|
---|
1115 | const struct arc_operand_value *reg ATTRIBUTE_UNUSED;
|
---|
1116 | long value ATTRIBUTE_UNUSED;
|
---|
1117 | const char **errmsg;
|
---|
1118 | {
|
---|
1119 | if (ST_SYNTAX(OP_SHIMM,OP_REG,OP_NONE) && shimm != 0)
|
---|
1120 | {
|
---|
1121 | /* change an illegal insn into a legal one, it's easier to
|
---|
1122 | do it here than to try to handle it during operand scan. */
|
---|
1123 | limm_p = 1;
|
---|
1124 | limm = shimm;
|
---|
1125 | shimm_p = 0;
|
---|
1126 | shimm = 0;
|
---|
1127 | insn = insn & ~(C(-1) | 511);
|
---|
1128 | insn |= ARC_REG_LIMM << ARC_SHIFT_REGC;
|
---|
1129 | ls_operand[LS_VALUE] = OP_LIMM;
|
---|
1130 | }
|
---|
1131 |
|
---|
1132 | if (ST_SYNTAX(OP_REG,OP_SHIMM,OP_NONE) || ST_SYNTAX(OP_LIMM,OP_SHIMM,OP_NONE))
|
---|
1133 | {
|
---|
1134 | /* try to salvage this syntax. */
|
---|
1135 | if (shimm & 0x1) /* odd shimms won't work. */
|
---|
1136 | {
|
---|
1137 | if (limm_p) /* do we have a limm already? */
|
---|
1138 | {
|
---|
1139 | *errmsg = "impossible store";
|
---|
1140 | }
|
---|
1141 | limm_p = 1;
|
---|
1142 | limm = shimm;
|
---|
1143 | shimm = 0;
|
---|
1144 | shimm_p = 0;
|
---|
1145 | insn = insn & ~(B(-1) | 511);
|
---|
1146 | insn |= B(ARC_REG_LIMM);
|
---|
1147 | ls_operand[LS_BASE] = OP_LIMM;
|
---|
1148 | }
|
---|
1149 | else
|
---|
1150 | {
|
---|
1151 | shimm >>= 1;
|
---|
1152 | insn = insn & ~511;
|
---|
1153 | insn |= shimm;
|
---|
1154 | ls_operand[LS_OFFSET] = OP_SHIMM;
|
---|
1155 | }
|
---|
1156 | }
|
---|
1157 | if (ST_SYNTAX(OP_SHIMM,OP_LIMM,OP_NONE))
|
---|
1158 | {
|
---|
1159 | limm += arc_limm_fixup_adjust(insn);
|
---|
1160 | }
|
---|
1161 | if (!(ST_SYNTAX(OP_REG,OP_REG,OP_NONE)
|
---|
1162 | || ST_SYNTAX(OP_REG,OP_LIMM,OP_NONE)
|
---|
1163 | || ST_SYNTAX(OP_REG,OP_REG,OP_SHIMM)
|
---|
1164 | || ST_SYNTAX(OP_REG,OP_SHIMM,OP_SHIMM)
|
---|
1165 | || (ST_SYNTAX(OP_SHIMM,OP_SHIMM,OP_NONE) && (shimm == 0))
|
---|
1166 | || ST_SYNTAX(OP_SHIMM,OP_LIMM,OP_NONE)
|
---|
1167 | || ST_SYNTAX(OP_SHIMM,OP_REG,OP_NONE)
|
---|
1168 | || ST_SYNTAX(OP_SHIMM,OP_REG,OP_SHIMM)
|
---|
1169 | || ST_SYNTAX(OP_SHIMM,OP_SHIMM,OP_SHIMM)
|
---|
1170 | || ST_SYNTAX(OP_LIMM,OP_SHIMM,OP_SHIMM)
|
---|
1171 | || ST_SYNTAX(OP_LIMM,OP_REG,OP_NONE)
|
---|
1172 | || ST_SYNTAX(OP_LIMM,OP_REG,OP_SHIMM)))
|
---|
1173 | *errmsg = "st operand error";
|
---|
1174 | if (addrwb_p)
|
---|
1175 | {
|
---|
1176 | if (ls_operand[LS_BASE] != OP_REG)
|
---|
1177 | *errmsg = "address writeback not allowed";
|
---|
1178 | insn |= addrwb_p;
|
---|
1179 | }
|
---|
1180 | if (ST_SYNTAX(OP_SHIMM,OP_REG,OP_NONE) && shimm)
|
---|
1181 | *errmsg = "store value must be zero";
|
---|
1182 | return insn;
|
---|
1183 | }
|
---|
1184 |
|
---|
1185 | /* Used in ld insns to do final syntax check. */
|
---|
1186 |
|
---|
1187 | static arc_insn
|
---|
1188 | insert_ld_syntax (insn, operand, mods, reg, value, errmsg)
|
---|
1189 | arc_insn insn;
|
---|
1190 | const struct arc_operand *operand ATTRIBUTE_UNUSED;
|
---|
1191 | int mods ATTRIBUTE_UNUSED;
|
---|
1192 | const struct arc_operand_value *reg ATTRIBUTE_UNUSED;
|
---|
1193 | long value ATTRIBUTE_UNUSED;
|
---|
1194 | const char **errmsg;
|
---|
1195 | {
|
---|
1196 | #define LD_SYNTAX(D,B,O) \
|
---|
1197 | ((ls_operand[LS_DEST] == (D) && \
|
---|
1198 | ls_operand[LS_BASE] == (B) && \
|
---|
1199 | ls_operand[LS_OFFSET] == (O)))
|
---|
1200 |
|
---|
1201 | int test = insn & I(-1);
|
---|
1202 |
|
---|
1203 | if (!(test == I(1)))
|
---|
1204 | {
|
---|
1205 | if ((ls_operand[LS_DEST] == OP_SHIMM || ls_operand[LS_BASE] == OP_SHIMM
|
---|
1206 | || ls_operand[LS_OFFSET] == OP_SHIMM))
|
---|
1207 | *errmsg = "invalid load/shimm insn";
|
---|
1208 | }
|
---|
1209 | if (!(LD_SYNTAX(OP_REG,OP_REG,OP_NONE)
|
---|
1210 | || LD_SYNTAX(OP_REG,OP_REG,OP_REG)
|
---|
1211 | || LD_SYNTAX(OP_REG,OP_REG,OP_SHIMM)
|
---|
1212 | || (LD_SYNTAX(OP_REG,OP_LIMM,OP_REG) && !(test == I(1)))
|
---|
1213 | || (LD_SYNTAX(OP_REG,OP_REG,OP_LIMM) && !(test == I(1)))
|
---|
1214 | || LD_SYNTAX(OP_REG,OP_SHIMM,OP_SHIMM)
|
---|
1215 | || (LD_SYNTAX(OP_REG,OP_LIMM,OP_NONE) && (test == I(1)))))
|
---|
1216 | *errmsg = "ld operand error";
|
---|
1217 | if (addrwb_p)
|
---|
1218 | {
|
---|
1219 | if (ls_operand[LS_BASE] != OP_REG)
|
---|
1220 | *errmsg = "address writeback not allowed";
|
---|
1221 | insn |= addrwb_p;
|
---|
1222 | }
|
---|
1223 | return insn;
|
---|
1224 | }
|
---|
1225 |
|
---|
1226 | /* Used in ld insns to do final syntax check. */
|
---|
1227 |
|
---|
1228 | static long
|
---|
1229 | extract_ld_syntax (insn, operand, mods, opval, invalid)
|
---|
1230 | arc_insn *insn;
|
---|
1231 | const struct arc_operand *operand ATTRIBUTE_UNUSED;
|
---|
1232 | int mods ATTRIBUTE_UNUSED;
|
---|
1233 | const struct arc_operand_value **opval ATTRIBUTE_UNUSED;
|
---|
1234 | int *invalid;
|
---|
1235 | {
|
---|
1236 | int test = insn[0] & I(-1);
|
---|
1237 |
|
---|
1238 | if (!(test == I(1)))
|
---|
1239 | {
|
---|
1240 | if ((ls_operand[LS_DEST] == OP_SHIMM || ls_operand[LS_BASE] == OP_SHIMM
|
---|
1241 | || ls_operand[LS_OFFSET] == OP_SHIMM))
|
---|
1242 | *invalid = 1;
|
---|
1243 | }
|
---|
1244 | if (!((LD_SYNTAX(OP_REG,OP_REG,OP_NONE) && (test == I(1)))
|
---|
1245 | || LD_SYNTAX(OP_REG,OP_REG,OP_REG)
|
---|
1246 | || LD_SYNTAX(OP_REG,OP_REG,OP_SHIMM)
|
---|
1247 | || (LD_SYNTAX(OP_REG,OP_REG,OP_LIMM) && !(test == I(1)))
|
---|
1248 | || (LD_SYNTAX(OP_REG,OP_LIMM,OP_REG) && !(test == I(1)))
|
---|
1249 | || (LD_SYNTAX(OP_REG,OP_SHIMM,OP_NONE) && (shimm == 0))
|
---|
1250 | || LD_SYNTAX(OP_REG,OP_SHIMM,OP_SHIMM)
|
---|
1251 | || (LD_SYNTAX(OP_REG,OP_LIMM,OP_NONE) && (test == I(1)))))
|
---|
1252 | *invalid = 1;
|
---|
1253 | return 0;
|
---|
1254 | }
|
---|
1255 |
|
---|
1256 | /* Called at the end of processing normal insns (eg: add) to insert a shimm
|
---|
1257 | value (if present) into the insn. */
|
---|
1258 |
|
---|
1259 | static arc_insn
|
---|
1260 | insert_shimmfinish (insn, operand, mods, reg, value, errmsg)
|
---|
1261 | arc_insn insn;
|
---|
1262 | const struct arc_operand *operand;
|
---|
1263 | int mods ATTRIBUTE_UNUSED;
|
---|
1264 | const struct arc_operand_value *reg ATTRIBUTE_UNUSED;
|
---|
1265 | long value ATTRIBUTE_UNUSED;
|
---|
1266 | const char **errmsg ATTRIBUTE_UNUSED;
|
---|
1267 | {
|
---|
1268 | if (shimm_p)
|
---|
1269 | insn |= (shimm & ((1 << operand->bits) - 1)) << operand->shift;
|
---|
1270 | return insn;
|
---|
1271 | }
|
---|
1272 |
|
---|
1273 | /* Called at the end of processing normal insns (eg: add) to insert a limm
|
---|
1274 | value (if present) into the insn.
|
---|
1275 |
|
---|
1276 | Note that this function is only intended to handle instructions (with 4 byte
|
---|
1277 | immediate operands). It is not intended to handle data. */
|
---|
1278 |
|
---|
1279 | /* ??? Actually, there's nothing for us to do as we can't call frag_more, the
|
---|
1280 | caller must do that. The extract fns take a pointer to two words. The
|
---|
1281 | insert fns could be converted and then we could do something useful, but
|
---|
1282 | then the reloc handlers would have to know to work on the second word of
|
---|
1283 | a 2 word quantity. That's too much so we don't handle them. */
|
---|
1284 |
|
---|
1285 | static arc_insn
|
---|
1286 | insert_limmfinish (insn, operand, mods, reg, value, errmsg)
|
---|
1287 | arc_insn insn;
|
---|
1288 | const struct arc_operand *operand ATTRIBUTE_UNUSED;
|
---|
1289 | int mods ATTRIBUTE_UNUSED;
|
---|
1290 | const struct arc_operand_value *reg ATTRIBUTE_UNUSED;
|
---|
1291 | long value ATTRIBUTE_UNUSED;
|
---|
1292 | const char **errmsg ATTRIBUTE_UNUSED;
|
---|
1293 | {
|
---|
1294 | #if 0
|
---|
1295 | if (limm_p)
|
---|
1296 | ; /* nothing to do, gas does it. */
|
---|
1297 | #endif
|
---|
1298 | return insn;
|
---|
1299 | }
|
---|
1300 |
|
---|
1301 | static arc_insn
|
---|
1302 | insert_jumpflags (insn, operand, mods, reg, value, errmsg)
|
---|
1303 | arc_insn insn;
|
---|
1304 | const struct arc_operand *operand;
|
---|
1305 | int mods ATTRIBUTE_UNUSED;
|
---|
1306 | const struct arc_operand_value *reg ATTRIBUTE_UNUSED;
|
---|
1307 | long value;
|
---|
1308 | const char **errmsg;
|
---|
1309 | {
|
---|
1310 | if (!flag_p)
|
---|
1311 | {
|
---|
1312 | *errmsg = "jump flags, but no .f seen";
|
---|
1313 | }
|
---|
1314 | if (!limm_p)
|
---|
1315 | {
|
---|
1316 | *errmsg = "jump flags, but no limm addr";
|
---|
1317 | }
|
---|
1318 | if (limm & 0xfc000000)
|
---|
1319 | {
|
---|
1320 | *errmsg = "flag bits of jump address limm lost";
|
---|
1321 | }
|
---|
1322 | if (limm & 0x03000000)
|
---|
1323 | {
|
---|
1324 | *errmsg = "attempt to set HR bits";
|
---|
1325 | }
|
---|
1326 | if ((value & ((1 << operand->bits) - 1)) != value)
|
---|
1327 | {
|
---|
1328 | *errmsg = "bad jump flags value";
|
---|
1329 | }
|
---|
1330 | jumpflags_p = 1;
|
---|
1331 | limm = ((limm & ((1 << operand->shift) - 1))
|
---|
1332 | | ((value & ((1 << operand->bits) - 1)) << operand->shift));
|
---|
1333 | return insn;
|
---|
1334 | }
|
---|
1335 |
|
---|
1336 | /* Called at the end of unary operand macros to copy the B field to C. */
|
---|
1337 |
|
---|
1338 | static arc_insn
|
---|
1339 | insert_unopmacro (insn, operand, mods, reg, value, errmsg)
|
---|
1340 | arc_insn insn;
|
---|
1341 | const struct arc_operand *operand;
|
---|
1342 | int mods ATTRIBUTE_UNUSED;
|
---|
1343 | const struct arc_operand_value *reg ATTRIBUTE_UNUSED;
|
---|
1344 | long value ATTRIBUTE_UNUSED;
|
---|
1345 | const char **errmsg ATTRIBUTE_UNUSED;
|
---|
1346 | {
|
---|
1347 | insn |= ((insn >> ARC_SHIFT_REGB) & ARC_MASK_REG) << operand->shift;
|
---|
1348 | return insn;
|
---|
1349 | }
|
---|
1350 |
|
---|
1351 | /* Insert a relative address for a branch insn (b, bl, or lp). */
|
---|
1352 |
|
---|
1353 | static arc_insn
|
---|
1354 | insert_reladdr (insn, operand, mods, reg, value, errmsg)
|
---|
1355 | arc_insn insn;
|
---|
1356 | const struct arc_operand *operand;
|
---|
1357 | int mods ATTRIBUTE_UNUSED;
|
---|
1358 | const struct arc_operand_value *reg ATTRIBUTE_UNUSED;
|
---|
1359 | long value;
|
---|
1360 | const char **errmsg;
|
---|
1361 | {
|
---|
1362 | if (value & 3)
|
---|
1363 | *errmsg = "branch address not on 4 byte boundary";
|
---|
1364 | insn |= ((value >> 2) & ((1 << operand->bits) - 1)) << operand->shift;
|
---|
1365 | return insn;
|
---|
1366 | }
|
---|
1367 |
|
---|
1368 | /* Insert a limm value as a 26 bit address right shifted 2 into the insn.
|
---|
1369 |
|
---|
1370 | Note that this function is only intended to handle instructions (with 4 byte
|
---|
1371 | immediate operands). It is not intended to handle data. */
|
---|
1372 |
|
---|
1373 | /* ??? Actually, there's little for us to do as we can't call frag_more, the
|
---|
1374 | caller must do that. The extract fns take a pointer to two words. The
|
---|
1375 | insert fns could be converted and then we could do something useful, but
|
---|
1376 | then the reloc handlers would have to know to work on the second word of
|
---|
1377 | a 2 word quantity. That's too much so we don't handle them.
|
---|
1378 |
|
---|
1379 | We do check for correct usage of the nullify suffix, or we
|
---|
1380 | set the default correctly, though. */
|
---|
1381 |
|
---|
1382 | static arc_insn
|
---|
1383 | insert_absaddr (insn, operand, mods, reg, value, errmsg)
|
---|
1384 | arc_insn insn;
|
---|
1385 | const struct arc_operand *operand ATTRIBUTE_UNUSED;
|
---|
1386 | int mods ATTRIBUTE_UNUSED;
|
---|
1387 | const struct arc_operand_value *reg ATTRIBUTE_UNUSED;
|
---|
1388 | long value ATTRIBUTE_UNUSED;
|
---|
1389 | const char **errmsg;
|
---|
1390 | {
|
---|
1391 | if (limm_p)
|
---|
1392 | {
|
---|
1393 | /* if it is a jump and link, .jd must be specified. */
|
---|
1394 | if (insn & R(-1,9,1))
|
---|
1395 | {
|
---|
1396 | if (!nullify_p)
|
---|
1397 | {
|
---|
1398 | insn |= 0x02 << 5; /* default nullify to .jd. */
|
---|
1399 | }
|
---|
1400 | else
|
---|
1401 | {
|
---|
1402 | if (nullify != 0x02)
|
---|
1403 | {
|
---|
1404 | *errmsg = "must specify .jd or no nullify suffix";
|
---|
1405 | }
|
---|
1406 | }
|
---|
1407 | }
|
---|
1408 | }
|
---|
1409 | return insn;
|
---|
1410 | }
|
---|
1411 | |
---|
1412 |
|
---|
1413 | /* Extraction functions.
|
---|
1414 |
|
---|
1415 | The suffix extraction functions' return value is redundant since it can be
|
---|
1416 | obtained from (*OPVAL)->value. However, the boolean suffixes don't have
|
---|
1417 | a suffix table entry for the "false" case, so values of zero must be
|
---|
1418 | obtained from the return value (*OPVAL == NULL). */
|
---|
1419 |
|
---|
1420 | static const struct arc_operand_value *lookup_register (int type, long regno);
|
---|
1421 |
|
---|
1422 | /* Called by the disassembler before printing an instruction. */
|
---|
1423 |
|
---|
1424 | void
|
---|
1425 | arc_opcode_init_extract ()
|
---|
1426 | {
|
---|
1427 | arc_opcode_init_insert();
|
---|
1428 | }
|
---|
1429 |
|
---|
1430 | /* As we're extracting registers, keep an eye out for the 'f' indicator
|
---|
1431 | (ARC_REG_SHIMM_UPDATE). If we find a register (not a constant marker,
|
---|
1432 | like ARC_REG_SHIMM), set OPVAL so our caller will know this is a register.
|
---|
1433 |
|
---|
1434 | We must also handle auxiliary registers for lr/sr insns. They are just
|
---|
1435 | constants with special names. */
|
---|
1436 |
|
---|
1437 | static long
|
---|
1438 | extract_reg (insn, operand, mods, opval, invalid)
|
---|
1439 | arc_insn *insn;
|
---|
1440 | const struct arc_operand *operand;
|
---|
1441 | int mods;
|
---|
1442 | const struct arc_operand_value **opval;
|
---|
1443 | int *invalid ATTRIBUTE_UNUSED;
|
---|
1444 | {
|
---|
1445 | int regno;
|
---|
1446 | long value;
|
---|
1447 | enum operand op_type;
|
---|
1448 |
|
---|
1449 | /* Get the register number. */
|
---|
1450 | regno = (*insn >> operand->shift) & ((1 << operand->bits) - 1);
|
---|
1451 |
|
---|
1452 | /* Is it a constant marker? */
|
---|
1453 | if (regno == ARC_REG_SHIMM)
|
---|
1454 | {
|
---|
1455 | op_type = OP_SHIMM;
|
---|
1456 | /* always return zero if dest is a shimm mlm. */
|
---|
1457 |
|
---|
1458 | if ('a' != operand->fmt)
|
---|
1459 | {
|
---|
1460 | value = *insn & 511;
|
---|
1461 | if ((operand->flags & ARC_OPERAND_SIGNED)
|
---|
1462 | && (value & 256))
|
---|
1463 | value -= 512;
|
---|
1464 | if (!flagshimm_handled_p)
|
---|
1465 | flag_p = 0;
|
---|
1466 | flagshimm_handled_p = 1;
|
---|
1467 | }
|
---|
1468 | else
|
---|
1469 | {
|
---|
1470 | value = 0;
|
---|
1471 | }
|
---|
1472 | }
|
---|
1473 | else if (regno == ARC_REG_SHIMM_UPDATE)
|
---|
1474 | {
|
---|
1475 | op_type = OP_SHIMM;
|
---|
1476 |
|
---|
1477 | /* always return zero if dest is a shimm mlm. */
|
---|
1478 |
|
---|
1479 | if ('a' != operand->fmt)
|
---|
1480 | {
|
---|
1481 | value = *insn & 511;
|
---|
1482 | if ((operand->flags & ARC_OPERAND_SIGNED) && (value & 256))
|
---|
1483 | value -= 512;
|
---|
1484 | }
|
---|
1485 | else
|
---|
1486 | {
|
---|
1487 | value = 0;
|
---|
1488 | }
|
---|
1489 | flag_p = 1;
|
---|
1490 | flagshimm_handled_p = 1;
|
---|
1491 | }
|
---|
1492 | else if (regno == ARC_REG_LIMM)
|
---|
1493 | {
|
---|
1494 | op_type = OP_LIMM;
|
---|
1495 | value = insn[1];
|
---|
1496 | limm_p = 1;
|
---|
1497 | /* if this is a jump instruction (j,jl), show new pc correctly. */
|
---|
1498 | if (0x07 == ((*insn & I(-1)) >> 27))
|
---|
1499 | {
|
---|
1500 | value = (value & 0xffffff);
|
---|
1501 | }
|
---|
1502 | }
|
---|
1503 | /* It's a register, set OPVAL (that's the only way we distinguish registers
|
---|
1504 | from constants here). */
|
---|
1505 | else
|
---|
1506 | {
|
---|
1507 | const struct arc_operand_value *reg = lookup_register (REG, regno);
|
---|
1508 | op_type = OP_REG;
|
---|
1509 |
|
---|
1510 | if (reg == NULL)
|
---|
1511 | abort ();
|
---|
1512 | if (opval != NULL)
|
---|
1513 | *opval = reg;
|
---|
1514 | value = regno;
|
---|
1515 | }
|
---|
1516 |
|
---|
1517 | /* If this field takes an auxiliary register, see if it's a known one. */
|
---|
1518 | if ((mods & ARC_MOD_AUXREG)
|
---|
1519 | && ARC_REG_CONSTANT_P (regno))
|
---|
1520 | {
|
---|
1521 | const struct arc_operand_value *reg = lookup_register (AUXREG, value);
|
---|
1522 |
|
---|
1523 | /* This is really a constant, but tell the caller it has a special
|
---|
1524 | name. */
|
---|
1525 | if (reg != NULL && opval != NULL)
|
---|
1526 | *opval = reg;
|
---|
1527 | }
|
---|
1528 | switch(operand->fmt)
|
---|
1529 | {
|
---|
1530 | case 'a':
|
---|
1531 | ls_operand[LS_DEST] = op_type;
|
---|
1532 | break;
|
---|
1533 | case 's':
|
---|
1534 | ls_operand[LS_BASE] = op_type;
|
---|
1535 | break;
|
---|
1536 | case 'c':
|
---|
1537 | if ((insn[0]& I(-1)) == I(2))
|
---|
1538 | ls_operand[LS_VALUE] = op_type;
|
---|
1539 | else
|
---|
1540 | ls_operand[LS_OFFSET] = op_type;
|
---|
1541 | break;
|
---|
1542 | case 'o': case 'O':
|
---|
1543 | ls_operand[LS_OFFSET] = op_type;
|
---|
1544 | break;
|
---|
1545 | }
|
---|
1546 |
|
---|
1547 | return value;
|
---|
1548 | }
|
---|
1549 |
|
---|
1550 | /* Return the value of the "flag update" field for shimm insns.
|
---|
1551 | This value is actually stored in the register field. */
|
---|
1552 |
|
---|
1553 | static long
|
---|
1554 | extract_flag (insn, operand, mods, opval, invalid)
|
---|
1555 | arc_insn *insn;
|
---|
1556 | const struct arc_operand *operand;
|
---|
1557 | int mods ATTRIBUTE_UNUSED;
|
---|
1558 | const struct arc_operand_value **opval;
|
---|
1559 | int *invalid ATTRIBUTE_UNUSED;
|
---|
1560 | {
|
---|
1561 | int f;
|
---|
1562 | const struct arc_operand_value *val;
|
---|
1563 |
|
---|
1564 | if (flagshimm_handled_p)
|
---|
1565 | f = flag_p != 0;
|
---|
1566 | else
|
---|
1567 | f = (*insn & (1 << operand->shift)) != 0;
|
---|
1568 |
|
---|
1569 | /* There is no text for zero values. */
|
---|
1570 | if (f == 0)
|
---|
1571 | return 0;
|
---|
1572 | flag_p = 1;
|
---|
1573 | val = arc_opcode_lookup_suffix (operand, 1);
|
---|
1574 | if (opval != NULL && val != NULL)
|
---|
1575 | *opval = val;
|
---|
1576 | return val->value;
|
---|
1577 | }
|
---|
1578 |
|
---|
1579 | /* Extract the condition code (if it exists).
|
---|
1580 | If we've seen a shimm value in this insn (meaning that the insn can't have
|
---|
1581 | a condition code field), then we don't store anything in OPVAL and return
|
---|
1582 | zero. */
|
---|
1583 |
|
---|
1584 | static long
|
---|
1585 | extract_cond (insn, operand, mods, opval, invalid)
|
---|
1586 | arc_insn *insn;
|
---|
1587 | const struct arc_operand *operand;
|
---|
1588 | int mods ATTRIBUTE_UNUSED;
|
---|
1589 | const struct arc_operand_value **opval;
|
---|
1590 | int *invalid ATTRIBUTE_UNUSED;
|
---|
1591 | {
|
---|
1592 | long cond;
|
---|
1593 | const struct arc_operand_value *val;
|
---|
1594 |
|
---|
1595 | if (flagshimm_handled_p)
|
---|
1596 | return 0;
|
---|
1597 |
|
---|
1598 | cond = (*insn >> operand->shift) & ((1 << operand->bits) - 1);
|
---|
1599 | val = arc_opcode_lookup_suffix (operand, cond);
|
---|
1600 |
|
---|
1601 | /* Ignore NULL values of `val'. Several condition code values are
|
---|
1602 | reserved for extensions. */
|
---|
1603 | if (opval != NULL && val != NULL)
|
---|
1604 | *opval = val;
|
---|
1605 | return cond;
|
---|
1606 | }
|
---|
1607 |
|
---|
1608 | /* Extract a branch address.
|
---|
1609 | We return the value as a real address (not right shifted by 2). */
|
---|
1610 |
|
---|
1611 | static long
|
---|
1612 | extract_reladdr (insn, operand, mods, opval, invalid)
|
---|
1613 | arc_insn *insn;
|
---|
1614 | const struct arc_operand *operand;
|
---|
1615 | int mods ATTRIBUTE_UNUSED;
|
---|
1616 | const struct arc_operand_value **opval ATTRIBUTE_UNUSED;
|
---|
1617 | int *invalid ATTRIBUTE_UNUSED;
|
---|
1618 | {
|
---|
1619 | long addr;
|
---|
1620 |
|
---|
1621 | addr = (*insn >> operand->shift) & ((1 << operand->bits) - 1);
|
---|
1622 | if ((operand->flags & ARC_OPERAND_SIGNED)
|
---|
1623 | && (addr & (1 << (operand->bits - 1))))
|
---|
1624 | addr -= 1 << operand->bits;
|
---|
1625 | return addr << 2;
|
---|
1626 | }
|
---|
1627 |
|
---|
1628 | /* extract the flags bits from a j or jl long immediate. */
|
---|
1629 | static long
|
---|
1630 | extract_jumpflags(insn, operand, mods, opval, invalid)
|
---|
1631 | arc_insn *insn;
|
---|
1632 | const struct arc_operand *operand;
|
---|
1633 | int mods ATTRIBUTE_UNUSED;
|
---|
1634 | const struct arc_operand_value **opval ATTRIBUTE_UNUSED;
|
---|
1635 | int *invalid;
|
---|
1636 | {
|
---|
1637 | if (!flag_p || !limm_p)
|
---|
1638 | *invalid = 1;
|
---|
1639 | return ((flag_p && limm_p)
|
---|
1640 | ? (insn[1] >> operand->shift) & ((1 << operand->bits) -1): 0);
|
---|
1641 | }
|
---|
1642 |
|
---|
1643 | /* extract st insn's offset. */
|
---|
1644 |
|
---|
1645 | static long
|
---|
1646 | extract_st_offset (insn, operand, mods, opval, invalid)
|
---|
1647 | arc_insn *insn;
|
---|
1648 | const struct arc_operand *operand;
|
---|
1649 | int mods ATTRIBUTE_UNUSED;
|
---|
1650 | const struct arc_operand_value **opval ATTRIBUTE_UNUSED;
|
---|
1651 | int *invalid;
|
---|
1652 | {
|
---|
1653 | int value = 0;
|
---|
1654 |
|
---|
1655 | if (ls_operand[LS_VALUE] != OP_SHIMM || ls_operand[LS_BASE] != OP_LIMM)
|
---|
1656 | {
|
---|
1657 | value = insn[0] & 511;
|
---|
1658 | if ((operand->flags & ARC_OPERAND_SIGNED) && (value & 256))
|
---|
1659 | value -= 512;
|
---|
1660 | if (value)
|
---|
1661 | ls_operand[LS_OFFSET] = OP_SHIMM;
|
---|
1662 | }
|
---|
1663 | else
|
---|
1664 | {
|
---|
1665 | *invalid = 1;
|
---|
1666 | }
|
---|
1667 | return(value);
|
---|
1668 | }
|
---|
1669 |
|
---|
1670 | /* extract ld insn's offset. */
|
---|
1671 |
|
---|
1672 | static long
|
---|
1673 | extract_ld_offset (insn, operand, mods, opval, invalid)
|
---|
1674 | arc_insn *insn;
|
---|
1675 | const struct arc_operand *operand;
|
---|
1676 | int mods;
|
---|
1677 | const struct arc_operand_value **opval;
|
---|
1678 | int *invalid;
|
---|
1679 | {
|
---|
1680 | int test = insn[0] & I(-1);
|
---|
1681 | int value;
|
---|
1682 |
|
---|
1683 | if (test)
|
---|
1684 | {
|
---|
1685 | value = insn[0] & 511;
|
---|
1686 | if ((operand->flags & ARC_OPERAND_SIGNED) && (value & 256))
|
---|
1687 | value -= 512;
|
---|
1688 | if (value)
|
---|
1689 | ls_operand[LS_OFFSET] = OP_SHIMM;
|
---|
1690 | return(value);
|
---|
1691 | }
|
---|
1692 | /* if it isn't in the insn, it's concealed behind reg 'c'. */
|
---|
1693 | return extract_reg (insn, &arc_operands[arc_operand_map['c']],
|
---|
1694 | mods, opval, invalid);
|
---|
1695 | }
|
---|
1696 |
|
---|
1697 | /* The only thing this does is set the `invalid' flag if B != C.
|
---|
1698 | This is needed because the "mov" macro appears before it's real insn "and"
|
---|
1699 | and we don't want the disassembler to confuse them. */
|
---|
1700 |
|
---|
1701 | static long
|
---|
1702 | extract_unopmacro (insn, operand, mods, opval, invalid)
|
---|
1703 | arc_insn *insn;
|
---|
1704 | const struct arc_operand *operand ATTRIBUTE_UNUSED;
|
---|
1705 | int mods ATTRIBUTE_UNUSED;
|
---|
1706 | const struct arc_operand_value **opval ATTRIBUTE_UNUSED;
|
---|
1707 | int *invalid;
|
---|
1708 | {
|
---|
1709 | /* This misses the case where B == ARC_REG_SHIMM_UPDATE &&
|
---|
1710 | C == ARC_REG_SHIMM (or vice versa). No big deal. Those insns will get
|
---|
1711 | printed as "and"s. */
|
---|
1712 | if (((*insn >> ARC_SHIFT_REGB) & ARC_MASK_REG)
|
---|
1713 | != ((*insn >> ARC_SHIFT_REGC) & ARC_MASK_REG))
|
---|
1714 | if (invalid != NULL)
|
---|
1715 | *invalid = 1;
|
---|
1716 | return 0;
|
---|
1717 | }
|
---|
1718 |
|
---|
1719 | /* Utility for the extraction functions to return the index into
|
---|
1720 | `arc_suffixes'. */
|
---|
1721 |
|
---|
1722 | const struct arc_operand_value *
|
---|
1723 | arc_opcode_lookup_suffix (type, value)
|
---|
1724 | const struct arc_operand *type;
|
---|
1725 | int value;
|
---|
1726 | {
|
---|
1727 | register const struct arc_operand_value *v,*end;
|
---|
1728 | struct arc_ext_operand_value *ext_oper = arc_ext_operands;
|
---|
1729 |
|
---|
1730 | while (ext_oper)
|
---|
1731 | {
|
---|
1732 | if (type == &arc_operands[ext_oper->operand.type]
|
---|
1733 | && value == ext_oper->operand.value)
|
---|
1734 | return (&ext_oper->operand);
|
---|
1735 | ext_oper = ext_oper->next;
|
---|
1736 | }
|
---|
1737 |
|
---|
1738 | /* ??? This is a little slow and can be speeded up. */
|
---|
1739 |
|
---|
1740 | for (v = arc_suffixes, end = arc_suffixes + arc_suffixes_count; v < end; ++v)
|
---|
1741 | if (type == &arc_operands[v->type]
|
---|
1742 | && value == v->value)
|
---|
1743 | return v;
|
---|
1744 | return 0;
|
---|
1745 | }
|
---|
1746 |
|
---|
1747 | static const struct arc_operand_value *
|
---|
1748 | lookup_register (type, regno)
|
---|
1749 | int type;
|
---|
1750 | long regno;
|
---|
1751 | {
|
---|
1752 | register const struct arc_operand_value *r,*end;
|
---|
1753 | struct arc_ext_operand_value *ext_oper = arc_ext_operands;
|
---|
1754 |
|
---|
1755 | while (ext_oper)
|
---|
1756 | {
|
---|
1757 | if (ext_oper->operand.type == type && ext_oper->operand.value == regno)
|
---|
1758 | return (&ext_oper->operand);
|
---|
1759 | ext_oper = ext_oper->next;
|
---|
1760 | }
|
---|
1761 |
|
---|
1762 | if (type == REG)
|
---|
1763 | return &arc_reg_names[regno];
|
---|
1764 |
|
---|
1765 | /* ??? This is a little slow and can be speeded up. */
|
---|
1766 |
|
---|
1767 | for (r = arc_reg_names, end = arc_reg_names + arc_reg_names_count;
|
---|
1768 | r < end; ++r)
|
---|
1769 | if (type == r->type && regno == r->value)
|
---|
1770 | return r;
|
---|
1771 | return 0;
|
---|
1772 | }
|
---|
1773 |
|
---|
1774 | int
|
---|
1775 | arc_insn_is_j(insn)
|
---|
1776 | arc_insn insn;
|
---|
1777 | {
|
---|
1778 | return (insn & (I(-1))) == I(0x7);
|
---|
1779 | }
|
---|
1780 |
|
---|
1781 | int
|
---|
1782 | arc_insn_not_jl(insn)
|
---|
1783 | arc_insn insn;
|
---|
1784 | {
|
---|
1785 | return ((insn & (I(-1)|A(-1)|C(-1)|R(-1,7,1)|R(-1,9,1)))
|
---|
1786 | != (I(0x7) | R(-1,9,1)));
|
---|
1787 | }
|
---|
1788 |
|
---|
1789 | int
|
---|
1790 | arc_operand_type(int opertype)
|
---|
1791 | {
|
---|
1792 | switch (opertype)
|
---|
1793 | {
|
---|
1794 | case 0:
|
---|
1795 | return(COND);
|
---|
1796 | break;
|
---|
1797 | case 1:
|
---|
1798 | return(REG);
|
---|
1799 | break;
|
---|
1800 | case 2:
|
---|
1801 | return(AUXREG);
|
---|
1802 | break;
|
---|
1803 | }
|
---|
1804 | return -1;
|
---|
1805 | }
|
---|
1806 |
|
---|
1807 | struct arc_operand_value *
|
---|
1808 | get_ext_suffix(s)
|
---|
1809 | char *s;
|
---|
1810 | {
|
---|
1811 | struct arc_ext_operand_value *suffix = arc_ext_operands;
|
---|
1812 |
|
---|
1813 | while (suffix)
|
---|
1814 | {
|
---|
1815 | if ((COND == suffix->operand.type)
|
---|
1816 | && !strcmp(s,suffix->operand.name))
|
---|
1817 | return(&suffix->operand);
|
---|
1818 | suffix = suffix->next;
|
---|
1819 | }
|
---|
1820 | return NULL;
|
---|
1821 | }
|
---|
1822 |
|
---|
1823 | int
|
---|
1824 | arc_get_noshortcut_flag()
|
---|
1825 | {
|
---|
1826 | return ARC_REGISTER_NOSHORT_CUT;
|
---|
1827 | }
|
---|