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