Commit | Line | Data |
---|---|---|
539ee71a AC |
1 | /* IQ2000 opcode support. -*- C -*- |
2 | ||
9b201bb5 | 3 | Copyright 2000, 2001, 2002, 2005, 2007 Free Software Foundation, Inc. |
539ee71a AC |
4 | |
5 | Contributed by Red Hat Inc; developed under contract from Fujitsu. | |
6 | ||
7 | This file is part of the GNU Binutils. | |
8 | ||
9 | This program is free software; you can redistribute it and/or modify | |
10 | it under the terms of the GNU General Public License as published by | |
9b201bb5 | 11 | the Free Software Foundation; either version 3 of the License, or |
539ee71a AC |
12 | (at your option) any later version. |
13 | ||
14 | This program is distributed in the hope that it will be useful, | |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | GNU General Public License for more details. | |
18 | ||
19 | You should have received a copy of the GNU General Public License | |
20 | along with this program; if not, write to the Free Software | |
47b0e7ad NC |
21 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
22 | MA 02110-1301, USA. */ | |
539ee71a AC |
23 | |
24 | /* This file is an addendum to iq2000.cpu. Heavy use of C code isn't | |
25 | appropriate in .cpu files, so it resides here. This especially applies | |
26 | to assembly/disassembly where parsing/printing can be quite involved. | |
27 | Such things aren't really part of the specification of the cpu, per se, | |
28 | so .cpu files provide the general framework and .opc files handle the | |
29 | nitty-gritty details as necessary. | |
30 | ||
31 | Each section is delimited with start and end markers. | |
32 | ||
33 | <arch>-opc.h additions use: "-- opc.h" | |
34 | <arch>-opc.c additions use: "-- opc.c" | |
35 | <arch>-asm.c additions use: "-- asm.c" | |
36 | <arch>-dis.c additions use: "-- dis.c" | |
47b0e7ad | 37 | <arch>-ibd.h additions use: "-- ibd.h". */ |
539ee71a AC |
38 | \f |
39 | /* -- opc.h */ | |
40 | ||
41 | /* Allows reason codes to be output when assembler errors occur. */ | |
42 | #define CGEN_VERBOSE_ASSEMBLER_ERRORS | |
43 | ||
44 | /* Override disassembly hashing - there are variable bits in the top | |
45 | byte of these instructions. */ | |
46 | #define CGEN_DIS_HASH_SIZE 8 | |
47 | #define CGEN_DIS_HASH(buf,value) (((* (unsigned char*) (buf)) >> 6) % CGEN_DIS_HASH_SIZE) | |
48 | ||
49 | /* following activates check beyond hashing since some iq2000 and iq10 | |
50 | instructions have same mnemonics but different functionality. */ | |
51 | #define CGEN_VALIDATE_INSN_SUPPORTED | |
52 | ||
47b0e7ad | 53 | extern int iq2000_cgen_insn_supported (CGEN_CPU_DESC, const CGEN_INSN *); |
539ee71a AC |
54 | |
55 | /* -- asm.c */ | |
47b0e7ad NC |
56 | |
57 | #include "safe-ctype.h" | |
58 | ||
59 | static const char * MISSING_CLOSING_PARENTHESIS = N_("missing `)'"); | |
539ee71a | 60 | |
dc4c54bb | 61 | /* Special check to ensure that instruction exists for given machine. */ |
47b0e7ad | 62 | |
539ee71a | 63 | int |
47b0e7ad | 64 | iq2000_cgen_insn_supported (CGEN_CPU_DESC cd, const CGEN_INSN *insn) |
539ee71a AC |
65 | { |
66 | int machs = cd->machs; | |
67 | ||
47b0e7ad | 68 | return (CGEN_INSN_ATTR_VALUE (insn, CGEN_INSN_MACH) & machs) != 0; |
539ee71a AC |
69 | } |
70 | ||
47b0e7ad NC |
71 | static int |
72 | iq2000_cgen_isa_register (const char **strp) | |
539ee71a AC |
73 | { |
74 | int len; | |
75 | int ch1, ch2; | |
47b0e7ad | 76 | |
539ee71a AC |
77 | if (**strp == 'r' || **strp == 'R') |
78 | { | |
79 | len = strlen (*strp); | |
80 | if (len == 2) | |
81 | { | |
82 | ch1 = (*strp)[1]; | |
83 | if ('0' <= ch1 && ch1 <= '9') | |
84 | return 1; | |
85 | } | |
86 | else if (len == 3) | |
87 | { | |
88 | ch1 = (*strp)[1]; | |
89 | ch2 = (*strp)[2]; | |
90 | if (('1' <= ch1 && ch1 <= '2') && ('0' <= ch2 && ch2 <= '9')) | |
91 | return 1; | |
92 | if ('3' == ch1 && (ch2 == '0' || ch2 == '1')) | |
93 | return 1; | |
94 | } | |
95 | } | |
47b0e7ad NC |
96 | if (**strp == '%' |
97 | && TOLOWER ((*strp)[1]) != 'l' | |
98 | && TOLOWER ((*strp)[1]) != 'h') | |
539ee71a AC |
99 | return 1; |
100 | return 0; | |
101 | } | |
102 | ||
103 | /* Handle negated literal. */ | |
104 | ||
105 | static const char * | |
47b0e7ad NC |
106 | parse_mimm (CGEN_CPU_DESC cd, |
107 | const char **strp, | |
108 | int opindex, | |
109 | unsigned long *valuep) | |
539ee71a AC |
110 | { |
111 | const char *errmsg; | |
539ee71a | 112 | |
47b0e7ad | 113 | /* Verify this isn't a register. */ |
539ee71a AC |
114 | if (iq2000_cgen_isa_register (strp)) |
115 | errmsg = _("immediate value cannot be register"); | |
116 | else | |
117 | { | |
118 | long value; | |
119 | ||
120 | errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value); | |
121 | if (errmsg == NULL) | |
122 | { | |
123 | long x = (-value) & 0xFFFF0000; | |
47b0e7ad NC |
124 | |
125 | if (x != 0 && x != (long) 0xFFFF0000) | |
539ee71a AC |
126 | errmsg = _("immediate value out of range"); |
127 | else | |
128 | *valuep = (-value & 0xFFFF); | |
129 | } | |
130 | } | |
131 | return errmsg; | |
132 | } | |
133 | ||
134 | /* Handle signed/unsigned literal. */ | |
135 | ||
136 | static const char * | |
47b0e7ad NC |
137 | parse_imm (CGEN_CPU_DESC cd, |
138 | const char **strp, | |
139 | int opindex, | |
140 | unsigned long *valuep) | |
539ee71a AC |
141 | { |
142 | const char *errmsg; | |
539ee71a AC |
143 | |
144 | if (iq2000_cgen_isa_register (strp)) | |
145 | errmsg = _("immediate value cannot be register"); | |
146 | else | |
147 | { | |
148 | long value; | |
149 | ||
150 | errmsg = cgen_parse_signed_integer (cd, strp, opindex, & value); | |
151 | if (errmsg == NULL) | |
152 | { | |
153 | long x = value & 0xFFFF0000; | |
47b0e7ad NC |
154 | |
155 | if (x != 0 && x != (long) 0xFFFF0000) | |
539ee71a AC |
156 | errmsg = _("immediate value out of range"); |
157 | else | |
158 | *valuep = (value & 0xFFFF); | |
159 | } | |
160 | } | |
161 | return errmsg; | |
162 | } | |
163 | ||
164 | /* Handle iq10 21-bit jmp offset. */ | |
165 | ||
166 | static const char * | |
47b0e7ad NC |
167 | parse_jtargq10 (CGEN_CPU_DESC cd, |
168 | const char **strp, | |
169 | int opindex, | |
170 | int reloc ATTRIBUTE_UNUSED, | |
171 | enum cgen_parse_operand_result *type_addr ATTRIBUTE_UNUSED, | |
172 | bfd_vma *valuep) | |
539ee71a AC |
173 | { |
174 | const char *errmsg; | |
175 | bfd_vma value; | |
176 | enum cgen_parse_operand_result result_type = CGEN_PARSE_OPERAND_RESULT_NUMBER; | |
177 | ||
178 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_IQ2000_OFFSET_21, | |
47b0e7ad | 179 | & result_type, & value); |
539ee71a AC |
180 | if (errmsg == NULL && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) |
181 | { | |
47b0e7ad NC |
182 | /* Check value is within 23-bits |
183 | (remembering that 2-bit shift right will occur). */ | |
539ee71a AC |
184 | if (value > 0x7fffff) |
185 | return _("21-bit offset out of range"); | |
186 | } | |
187 | *valuep = (value & 0x7FFFFF); | |
188 | return errmsg; | |
189 | } | |
190 | ||
191 | /* Handle high(). */ | |
192 | ||
193 | static const char * | |
47b0e7ad NC |
194 | parse_hi16 (CGEN_CPU_DESC cd, |
195 | const char **strp, | |
196 | int opindex, | |
197 | unsigned long *valuep) | |
539ee71a AC |
198 | { |
199 | if (strncasecmp (*strp, "%hi(", 4) == 0) | |
200 | { | |
201 | enum cgen_parse_operand_result result_type; | |
202 | bfd_vma value; | |
203 | const char *errmsg; | |
204 | ||
205 | *strp += 4; | |
206 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_HI16, | |
47b0e7ad | 207 | & result_type, & value); |
539ee71a | 208 | if (**strp != ')') |
47b0e7ad | 209 | return MISSING_CLOSING_PARENTHESIS; |
539ee71a AC |
210 | |
211 | ++*strp; | |
212 | if (errmsg == NULL | |
213 | && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) | |
214 | { | |
47b0e7ad | 215 | /* If value has top-bit of %lo on, then it will |
539ee71a | 216 | sign-propagate and so we compensate by adding |
47b0e7ad | 217 | 1 to the resultant %hi value. */ |
539ee71a AC |
218 | if (value & 0x8000) |
219 | value += 0x10000; | |
220 | value >>= 16; | |
8536c657 | 221 | value &= 0xffff; |
539ee71a AC |
222 | } |
223 | *valuep = value; | |
224 | ||
225 | return errmsg; | |
226 | } | |
227 | ||
47b0e7ad NC |
228 | /* We add %uhi in case a user just wants the high 16-bits or is using |
229 | an insn like ori for %lo which does not sign-propagate. */ | |
539ee71a AC |
230 | if (strncasecmp (*strp, "%uhi(", 5) == 0) |
231 | { | |
232 | enum cgen_parse_operand_result result_type; | |
233 | bfd_vma value; | |
234 | const char *errmsg; | |
235 | ||
236 | *strp += 5; | |
237 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_IQ2000_UHI16, | |
47b0e7ad | 238 | & result_type, & value); |
539ee71a | 239 | if (**strp != ')') |
47b0e7ad | 240 | return MISSING_CLOSING_PARENTHESIS; |
539ee71a AC |
241 | |
242 | ++*strp; | |
243 | if (errmsg == NULL | |
244 | && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) | |
47b0e7ad NC |
245 | value >>= 16; |
246 | ||
8536c657 | 247 | value &= 0xffff; |
539ee71a AC |
248 | *valuep = value; |
249 | ||
250 | return errmsg; | |
251 | } | |
252 | ||
253 | return parse_imm (cd, strp, opindex, valuep); | |
254 | } | |
255 | ||
256 | /* Handle %lo in a signed context. | |
257 | The signedness of the value doesn't matter to %lo(), but this also | |
258 | handles the case where %lo() isn't present. */ | |
259 | ||
260 | static const char * | |
47b0e7ad NC |
261 | parse_lo16 (CGEN_CPU_DESC cd, |
262 | const char **strp, | |
263 | int opindex, | |
3ec2b351 | 264 | unsigned long *valuep) |
539ee71a AC |
265 | { |
266 | if (strncasecmp (*strp, "%lo(", 4) == 0) | |
267 | { | |
268 | const char *errmsg; | |
269 | enum cgen_parse_operand_result result_type; | |
270 | bfd_vma value; | |
271 | ||
272 | *strp += 4; | |
273 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LO16, | |
47b0e7ad | 274 | & result_type, & value); |
539ee71a | 275 | if (**strp != ')') |
47b0e7ad | 276 | return MISSING_CLOSING_PARENTHESIS; |
539ee71a AC |
277 | ++*strp; |
278 | if (errmsg == NULL | |
279 | && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) | |
280 | value &= 0xffff; | |
281 | *valuep = value; | |
282 | return errmsg; | |
283 | } | |
284 | ||
285 | return parse_imm (cd, strp, opindex, valuep); | |
286 | } | |
287 | ||
288 | /* Handle %lo in a negated signed context. | |
289 | The signedness of the value doesn't matter to %lo(), but this also | |
290 | handles the case where %lo() isn't present. */ | |
291 | ||
292 | static const char * | |
47b0e7ad NC |
293 | parse_mlo16 (CGEN_CPU_DESC cd, |
294 | const char **strp, | |
295 | int opindex, | |
3ec2b351 | 296 | unsigned long *valuep) |
539ee71a AC |
297 | { |
298 | if (strncasecmp (*strp, "%lo(", 4) == 0) | |
299 | { | |
300 | const char *errmsg; | |
301 | enum cgen_parse_operand_result result_type; | |
302 | bfd_vma value; | |
303 | ||
304 | *strp += 4; | |
305 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LO16, | |
47b0e7ad | 306 | & result_type, & value); |
539ee71a | 307 | if (**strp != ')') |
47b0e7ad | 308 | return MISSING_CLOSING_PARENTHESIS; |
539ee71a AC |
309 | ++*strp; |
310 | if (errmsg == NULL | |
311 | && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) | |
312 | value = (-value) & 0xffff; | |
313 | *valuep = value; | |
314 | return errmsg; | |
315 | } | |
316 | ||
317 | return parse_mimm (cd, strp, opindex, valuep); | |
318 | } | |
319 | ||
320 | /* -- */ |