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