Commit | Line | Data |
---|---|---|
539ee71a AC |
1 | /* IQ2000 opcode support. -*- C -*- |
2 | ||
47b0e7ad | 3 | Copyright 2000, 2001, 2002, 2005 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 | |
11 | the Free Software Foundation; either version 2 of the License, or | |
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; | |
221 | } | |
222 | *valuep = value; | |
223 | ||
224 | return errmsg; | |
225 | } | |
226 | ||
47b0e7ad NC |
227 | /* We add %uhi in case a user just wants the high 16-bits or is using |
228 | an insn like ori for %lo which does not sign-propagate. */ | |
539ee71a AC |
229 | if (strncasecmp (*strp, "%uhi(", 5) == 0) |
230 | { | |
231 | enum cgen_parse_operand_result result_type; | |
232 | bfd_vma value; | |
233 | const char *errmsg; | |
234 | ||
235 | *strp += 5; | |
236 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_IQ2000_UHI16, | |
47b0e7ad | 237 | & result_type, & value); |
539ee71a | 238 | if (**strp != ')') |
47b0e7ad | 239 | return MISSING_CLOSING_PARENTHESIS; |
539ee71a AC |
240 | |
241 | ++*strp; | |
242 | if (errmsg == NULL | |
243 | && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) | |
47b0e7ad NC |
244 | value >>= 16; |
245 | ||
539ee71a AC |
246 | *valuep = value; |
247 | ||
248 | return errmsg; | |
249 | } | |
250 | ||
251 | return parse_imm (cd, strp, opindex, valuep); | |
252 | } | |
253 | ||
254 | /* Handle %lo in a signed context. | |
255 | The signedness of the value doesn't matter to %lo(), but this also | |
256 | handles the case where %lo() isn't present. */ | |
257 | ||
258 | static const char * | |
47b0e7ad NC |
259 | parse_lo16 (CGEN_CPU_DESC cd, |
260 | const char **strp, | |
261 | int opindex, | |
3ec2b351 | 262 | unsigned long *valuep) |
539ee71a AC |
263 | { |
264 | if (strncasecmp (*strp, "%lo(", 4) == 0) | |
265 | { | |
266 | const char *errmsg; | |
267 | enum cgen_parse_operand_result result_type; | |
268 | bfd_vma value; | |
269 | ||
270 | *strp += 4; | |
271 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LO16, | |
47b0e7ad | 272 | & result_type, & value); |
539ee71a | 273 | if (**strp != ')') |
47b0e7ad | 274 | return MISSING_CLOSING_PARENTHESIS; |
539ee71a AC |
275 | ++*strp; |
276 | if (errmsg == NULL | |
277 | && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) | |
278 | value &= 0xffff; | |
279 | *valuep = value; | |
280 | return errmsg; | |
281 | } | |
282 | ||
283 | return parse_imm (cd, strp, opindex, valuep); | |
284 | } | |
285 | ||
286 | /* Handle %lo in a negated signed context. | |
287 | The signedness of the value doesn't matter to %lo(), but this also | |
288 | handles the case where %lo() isn't present. */ | |
289 | ||
290 | static const char * | |
47b0e7ad NC |
291 | parse_mlo16 (CGEN_CPU_DESC cd, |
292 | const char **strp, | |
293 | int opindex, | |
3ec2b351 | 294 | unsigned long *valuep) |
539ee71a AC |
295 | { |
296 | if (strncasecmp (*strp, "%lo(", 4) == 0) | |
297 | { | |
298 | const char *errmsg; | |
299 | enum cgen_parse_operand_result result_type; | |
300 | bfd_vma value; | |
301 | ||
302 | *strp += 4; | |
303 | errmsg = cgen_parse_address (cd, strp, opindex, BFD_RELOC_LO16, | |
47b0e7ad | 304 | & result_type, & value); |
539ee71a | 305 | if (**strp != ')') |
47b0e7ad | 306 | return MISSING_CLOSING_PARENTHESIS; |
539ee71a AC |
307 | ++*strp; |
308 | if (errmsg == NULL | |
309 | && result_type == CGEN_PARSE_OPERAND_RESULT_NUMBER) | |
310 | value = (-value) & 0xffff; | |
311 | *valuep = value; | |
312 | return errmsg; | |
313 | } | |
314 | ||
315 | return parse_mimm (cd, strp, opindex, valuep); | |
316 | } | |
317 | ||
318 | /* -- */ |