Commit | Line | Data |
---|---|---|
9c03036a DE |
1 | /* Assembler interface for targets using CGEN. -*- C -*- |
2 | CGEN: Cpu tools GENerator | |
3 | ||
4 | This file is used to generate m32r-asm.c. | |
5 | ||
6 | Copyright (C) 1996, 1997 Free Software Foundation, Inc. | |
7 | ||
8 | This file is part of the GNU Binutils and GDB, the GNU debugger. | |
9 | ||
10 | This program is free software; you can redistribute it and/or modify | |
11 | it under the terms of the GNU General Public License as published by | |
12 | the Free Software Foundation; either version 2, or (at your option) | |
13 | any later version. | |
14 | ||
15 | This program is distributed in the hope that it will be useful, | |
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | GNU General Public License for more details. | |
19 | ||
20 | You should have received a copy of the GNU General Public License | |
21 | along with this program; if not, write to the Free Software | |
22 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
23 | ||
24 | #include <ctype.h> | |
25 | #include <stdio.h> | |
26 | #include "ansidecl.h" | |
27 | #include "bfd.h" | |
28 | #include "m32r-opc.h" | |
29 | ||
30 | /* ??? The layout of this stuff is still work in progress. | |
31 | For speed in assembly/disassembly, we use inline functions. That of course | |
32 | will only work for GCC. When this stuff is finished, we can decide whether | |
33 | to keep the inline functions (and only get the performance increase when | |
34 | compiled with GCC), or switch to macros, or use something else. | |
35 | */ | |
36 | ||
37 | static const char *parse_insn_normal | |
38 | PARAMS ((const struct cgen_insn *, const char **, struct cgen_fields *)); | |
39 | static void insert_insn_normal | |
40 | PARAMS ((const struct cgen_insn *, struct cgen_fields *, cgen_insn_t *)); | |
41 | \f | |
42 | /* Default insertion routine. | |
43 | ||
44 | SHIFT is negative for left shifts, positive for right shifts. | |
45 | All bits of VALUE to be inserted must be valid as we don't handle | |
46 | signed vs unsigned shifts. | |
47 | ||
48 | ATTRS is a mask of the boolean attributes. We don't need any at the | |
49 | moment, but for consistency with extract_normal we have them. */ | |
50 | ||
51 | /* FIXME: This duplicates functionality with bfd's howto table and | |
52 | bfd_install_relocation. */ | |
53 | /* FIXME: For architectures where insns can be representable as ints, | |
54 | store insn in `field' struct and add registers, etc. while parsing. */ | |
55 | ||
56 | static CGEN_INLINE void | |
57 | insert_normal (value, attrs, start, length, shift, total_length, buffer) | |
58 | long value; | |
59 | unsigned int attrs; | |
60 | int start, length, shift, total_length; | |
61 | char *buffer; | |
62 | { | |
63 | bfd_vma x; | |
64 | ||
65 | #if 0 /*def CGEN_INT_INSN*/ | |
66 | *buffer |= ((value & ((1 << length) - 1)) | |
67 | << (total_length - (start + length))); | |
68 | #else | |
69 | switch (total_length) | |
70 | { | |
71 | case 8: | |
72 | x = *(unsigned char *) buffer; | |
73 | break; | |
74 | case 16: | |
75 | if (CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG) | |
76 | x = bfd_getb16 (buffer); | |
77 | else | |
78 | x = bfd_getl16 (buffer); | |
79 | break; | |
80 | case 32: | |
81 | if (CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG) | |
82 | x = bfd_getb32 (buffer); | |
83 | else | |
84 | x = bfd_getl32 (buffer); | |
85 | break; | |
86 | default : | |
87 | abort (); | |
88 | } | |
89 | ||
90 | if (shift < 0) | |
91 | value <<= -shift; | |
92 | else | |
93 | value >>= shift; | |
94 | ||
95 | x |= ((value & ((1 << length) - 1)) | |
96 | << (total_length - (start + length))); | |
97 | ||
98 | switch (total_length) | |
99 | { | |
100 | case 8: | |
101 | *buffer = value; | |
102 | break; | |
103 | case 16: | |
104 | if (CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG) | |
105 | bfd_putb16 (x, buffer); | |
106 | else | |
107 | bfd_putl16 (x, buffer); | |
108 | break; | |
109 | case 32: | |
110 | if (CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG) | |
111 | bfd_putb32 (x, buffer); | |
112 | else | |
113 | bfd_putl32 (x, buffer); | |
114 | break; | |
115 | default : | |
116 | abort (); | |
117 | } | |
118 | #endif | |
119 | } | |
120 | \f | |
121 | /* -- assembler routines inserted here */ | |
122 | /* -- asm.c */ | |
123 | ||
124 | /* Handle shigh(), high(). */ | |
125 | ||
126 | static const char * | |
127 | parse_h_hi16 (strp, opindex, min, max, valuep) | |
128 | const char **strp; | |
129 | int opindex; | |
130 | unsigned long min, max; | |
131 | unsigned long *valuep; | |
132 | { | |
133 | const char *errmsg; | |
134 | ||
135 | /* FIXME: Need # in assembler syntax (means '#' is optional). */ | |
136 | if (**strp == '#') | |
137 | ++*strp; | |
138 | ||
139 | if (strncmp (*strp, "high(", 5) == 0) | |
140 | { | |
141 | *strp += 5; | |
142 | /* FIXME: If value was a number, right shift by 16. */ | |
143 | errmsg = cgen_parse_address (strp, opindex, BFD_RELOC_M32R_HI16_ULO, valuep); | |
144 | if (**strp != ')') | |
145 | return "missing `)'"; | |
146 | ++*strp; | |
147 | return errmsg; | |
148 | } | |
149 | else if (strncmp (*strp, "shigh(", 6) == 0) | |
150 | { | |
151 | *strp += 6; | |
152 | /* FIXME: If value was a number, right shift by 16 (+ sign test). */ | |
153 | errmsg = cgen_parse_address (strp, opindex, BFD_RELOC_M32R_HI16_SLO, valuep); | |
154 | if (**strp != ')') | |
155 | return "missing `)'"; | |
156 | ++*strp; | |
157 | return errmsg; | |
158 | } | |
159 | ||
160 | return cgen_parse_unsigned_integer (strp, opindex, min, max, valuep); | |
161 | } | |
162 | ||
163 | /* Handle low() in a signed context. Also handle sda(). | |
164 | The signedness of the value doesn't matter to low(), but this also | |
165 | handles the case where low() isn't present. */ | |
166 | ||
167 | static const char * | |
168 | parse_h_slo16 (strp, opindex, min, max, valuep) | |
169 | const char **strp; | |
170 | int opindex; | |
171 | long min, max; | |
172 | long *valuep; | |
173 | { | |
174 | const char *errmsg; | |
175 | ||
176 | /* FIXME: Need # in assembler syntax (means '#' is optional). */ | |
177 | if (**strp == '#') | |
178 | ++*strp; | |
179 | ||
180 | if (strncmp (*strp, "low(", 4) == 0) | |
181 | { | |
182 | *strp += 4; | |
183 | errmsg = cgen_parse_address (strp, opindex, BFD_RELOC_M32R_LO16, valuep); | |
184 | if (**strp != ')') | |
185 | return "missing `)'"; | |
186 | ++*strp; | |
187 | return errmsg; | |
188 | } | |
189 | ||
190 | if (strncmp (*strp, "sda(", 4) == 0) | |
191 | { | |
192 | *strp += 4; | |
193 | errmsg = cgen_parse_address (strp, opindex, BFD_RELOC_M32R_SDA16, valuep); | |
194 | if (**strp != ')') | |
195 | return "missing `)'"; | |
196 | ++*strp; | |
197 | return errmsg; | |
198 | } | |
199 | ||
200 | return cgen_parse_signed_integer (strp, opindex, min, max, valuep); | |
201 | } | |
202 | ||
203 | /* Handle low() in an unsigned context. | |
204 | The signedness of the value doesn't matter to low(), but this also | |
205 | handles the case where low() isn't present. */ | |
206 | ||
207 | static const char * | |
208 | parse_h_ulo16 (strp, opindex, min, max, valuep) | |
209 | const char **strp; | |
210 | int opindex; | |
211 | unsigned long min, max; | |
212 | unsigned long *valuep; | |
213 | { | |
214 | const char *errmsg; | |
215 | ||
216 | /* FIXME: Need # in assembler syntax (means '#' is optional). */ | |
217 | if (**strp == '#') | |
218 | ++*strp; | |
219 | ||
220 | if (strncmp (*strp, "low(", 4) == 0) | |
221 | { | |
222 | *strp += 4; | |
223 | errmsg = cgen_parse_address (strp, opindex, BFD_RELOC_M32R_LO16, valuep); | |
224 | if (**strp != ')') | |
225 | return "missing `)'"; | |
226 | ++*strp; | |
227 | return errmsg; | |
228 | } | |
229 | ||
230 | return cgen_parse_unsigned_integer (strp, opindex, min, max, valuep); | |
231 | } | |
232 | ||
233 | /* -- */ | |
234 | ||
235 | /* Main entry point for operand parsing. | |
236 | ||
237 | This function is basically just a big switch statement. Earlier versions | |
238 | used tables to look up the function to use, but | |
239 | - if the table contains both assembler and disassembler functions then | |
240 | the disassembler contains much of the assembler and vice-versa, | |
241 | - there's a lot of inlining possibilities as things grow, | |
242 | - using a switch statement avoids the function call overhead. | |
243 | ||
244 | This function could be moved into `parse_insn_normal', but keeping it | |
245 | separate makes clear the interface between `parse_insn_normal' and each of | |
246 | the handlers. | |
247 | */ | |
248 | ||
249 | CGEN_INLINE const char * | |
250 | m32r_cgen_parse_operand (opindex, strp, fields) | |
251 | int opindex; | |
252 | const char **strp; | |
253 | struct cgen_fields *fields; | |
254 | { | |
255 | const char *errmsg; | |
256 | ||
257 | switch (opindex) | |
258 | { | |
259 | case 0 : | |
260 | errmsg = cgen_parse_keyword (strp, & m32r_cgen_opval_h_gr, &fields->f_r2); | |
261 | break; | |
262 | case 1 : | |
263 | errmsg = cgen_parse_keyword (strp, & m32r_cgen_opval_h_gr, &fields->f_r1); | |
264 | break; | |
265 | case 2 : | |
266 | errmsg = cgen_parse_keyword (strp, & m32r_cgen_opval_h_gr, &fields->f_r1); | |
267 | break; | |
268 | case 3 : | |
269 | errmsg = cgen_parse_keyword (strp, & m32r_cgen_opval_h_gr, &fields->f_r2); | |
270 | break; | |
271 | case 4 : | |
272 | errmsg = cgen_parse_keyword (strp, & m32r_cgen_opval_h_cr, &fields->f_r2); | |
273 | break; | |
274 | case 5 : | |
275 | errmsg = cgen_parse_keyword (strp, & m32r_cgen_opval_h_cr, &fields->f_r1); | |
276 | break; | |
277 | case 6 : | |
278 | errmsg = cgen_parse_signed_integer (strp, 6, -128, 127, &fields->f_simm8); | |
279 | break; | |
280 | case 7 : | |
281 | errmsg = cgen_parse_signed_integer (strp, 7, -32768, 32767, &fields->f_simm16); | |
282 | break; | |
283 | case 8 : | |
284 | errmsg = cgen_parse_unsigned_integer (strp, 8, 0, 15, &fields->f_uimm4); | |
285 | break; | |
286 | case 9 : | |
287 | errmsg = cgen_parse_unsigned_integer (strp, 9, 0, 31, &fields->f_uimm5); | |
288 | break; | |
289 | case 10 : | |
290 | errmsg = cgen_parse_unsigned_integer (strp, 10, 0, 65535, &fields->f_uimm16); | |
291 | break; | |
292 | case 11 : | |
293 | errmsg = parse_h_hi16 (strp, 11, 0, 65535, &fields->f_hi16); | |
294 | break; | |
295 | case 12 : | |
296 | errmsg = parse_h_slo16 (strp, 12, -32768, 32767, &fields->f_simm16); | |
297 | break; | |
298 | case 13 : | |
299 | errmsg = parse_h_ulo16 (strp, 13, 0, 65535, &fields->f_uimm16); | |
300 | break; | |
301 | case 14 : | |
302 | errmsg = cgen_parse_address (strp, 14, 0, &fields->f_uimm24); | |
303 | break; | |
304 | case 15 : | |
305 | errmsg = cgen_parse_address (strp, 15, 0, &fields->f_disp8); | |
306 | break; | |
307 | case 16 : | |
308 | errmsg = cgen_parse_address (strp, 16, 0, &fields->f_disp16); | |
309 | break; | |
310 | case 17 : | |
311 | errmsg = cgen_parse_address (strp, 17, 0, &fields->f_disp24); | |
312 | break; | |
313 | ||
314 | default : | |
315 | fprintf (stderr, "Unrecognized field %d while parsing.\n", opindex); | |
316 | abort (); | |
317 | } | |
318 | ||
319 | return errmsg; | |
320 | } | |
321 | ||
322 | /* Main entry point for operand insertion. | |
323 | ||
324 | This function is basically just a big switch statement. Earlier versions | |
325 | used tables to look up the function to use, but | |
326 | - if the table contains both assembler and disassembler functions then | |
327 | the disassembler contains much of the assembler and vice-versa, | |
328 | - there's a lot of inlining possibilities as things grow, | |
329 | - using a switch statement avoids the function call overhead. | |
330 | ||
331 | This function could be moved into `parse_insn_normal', but keeping it | |
332 | separate makes clear the interface between `parse_insn_normal' and each of | |
333 | the handlers. It's also needed by GAS to insert operands that couldn't be | |
334 | resolved during parsing. | |
335 | */ | |
336 | ||
337 | CGEN_INLINE void | |
338 | m32r_cgen_insert_operand (opindex, fields, buffer) | |
339 | int opindex; | |
340 | struct cgen_fields *fields; | |
341 | cgen_insn_t *buffer; | |
342 | { | |
343 | switch (opindex) | |
344 | { | |
345 | case 0 : | |
346 | insert_normal (fields->f_r2, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields), buffer); | |
347 | break; | |
348 | case 1 : | |
349 | insert_normal (fields->f_r1, 0|(1<<CGEN_OPERAND_UNSIGNED), 4, 4, 0, CGEN_FIELDS_BITSIZE (fields), buffer); | |
350 | break; | |
351 | case 2 : | |
352 | insert_normal (fields->f_r1, 0|(1<<CGEN_OPERAND_UNSIGNED), 4, 4, 0, CGEN_FIELDS_BITSIZE (fields), buffer); | |
353 | break; | |
354 | case 3 : | |
355 | insert_normal (fields->f_r2, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields), buffer); | |
356 | break; | |
357 | case 4 : | |
358 | insert_normal (fields->f_r2, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields), buffer); | |
359 | break; | |
360 | case 5 : | |
361 | insert_normal (fields->f_r1, 0|(1<<CGEN_OPERAND_UNSIGNED), 4, 4, 0, CGEN_FIELDS_BITSIZE (fields), buffer); | |
362 | break; | |
363 | case 6 : | |
364 | insert_normal (fields->f_simm8, 0, 8, 8, 0, CGEN_FIELDS_BITSIZE (fields), buffer); | |
365 | break; | |
366 | case 7 : | |
367 | insert_normal (fields->f_simm16, 0, 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), buffer); | |
368 | break; | |
369 | case 8 : | |
370 | insert_normal (fields->f_uimm4, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, 0, CGEN_FIELDS_BITSIZE (fields), buffer); | |
371 | break; | |
372 | case 9 : | |
373 | insert_normal (fields->f_uimm5, 0|(1<<CGEN_OPERAND_UNSIGNED), 11, 5, 0, CGEN_FIELDS_BITSIZE (fields), buffer); | |
374 | break; | |
375 | case 10 : | |
376 | insert_normal (fields->f_uimm16, 0|(1<<CGEN_OPERAND_UNSIGNED), 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), buffer); | |
377 | break; | |
378 | case 11 : | |
379 | insert_normal (fields->f_hi16, 0|(1<<CGEN_OPERAND_SIGN_OPT)|(1<<CGEN_OPERAND_UNSIGNED), 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), buffer); | |
380 | break; | |
381 | case 12 : | |
382 | insert_normal (fields->f_simm16, 0, 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), buffer); | |
383 | break; | |
384 | case 13 : | |
385 | insert_normal (fields->f_uimm16, 0|(1<<CGEN_OPERAND_UNSIGNED), 16, 16, 0, CGEN_FIELDS_BITSIZE (fields), buffer); | |
386 | break; | |
387 | case 14 : | |
388 | insert_normal (fields->f_uimm24, 0|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_ABS_ADDR)|(1<<CGEN_OPERAND_UNSIGNED), 8, 24, 0, CGEN_FIELDS_BITSIZE (fields), buffer); | |
389 | break; | |
390 | case 15 : | |
391 | insert_normal (fields->f_disp8, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), 8, 8, 2, CGEN_FIELDS_BITSIZE (fields), buffer); | |
392 | break; | |
393 | case 16 : | |
394 | insert_normal (fields->f_disp16, 0|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), 16, 16, 2, CGEN_FIELDS_BITSIZE (fields), buffer); | |
395 | break; | |
396 | case 17 : | |
397 | insert_normal (fields->f_disp24, 0|(1<<CGEN_OPERAND_RELAX)|(1<<CGEN_OPERAND_RELOC)|(1<<CGEN_OPERAND_PCREL_ADDR), 8, 24, 2, CGEN_FIELDS_BITSIZE (fields), buffer); | |
398 | break; | |
399 | ||
400 | default : | |
401 | fprintf (stderr, "Unrecognized field %d while building insn.\n", | |
402 | opindex); | |
403 | abort (); | |
404 | } | |
405 | } | |
406 | ||
407 | /* Main entry point for operand validation. | |
408 | ||
409 | This function is called from GAS when it has fully resolved an operand | |
410 | that couldn't be resolved during parsing. | |
411 | ||
412 | The result is NULL for success or an error message (which may be | |
413 | computed into a static buffer). | |
414 | */ | |
415 | ||
416 | CGEN_INLINE const char * | |
417 | m32r_cgen_validate_operand (opindex, fields) | |
418 | int opindex; | |
419 | const struct cgen_fields *fields; | |
420 | { | |
421 | const char *errmsg = NULL; | |
422 | ||
423 | switch (opindex) | |
424 | { | |
425 | case 0 : | |
426 | /* nothing to do */ | |
427 | break; | |
428 | case 1 : | |
429 | /* nothing to do */ | |
430 | break; | |
431 | case 2 : | |
432 | /* nothing to do */ | |
433 | break; | |
434 | case 3 : | |
435 | /* nothing to do */ | |
436 | break; | |
437 | case 4 : | |
438 | /* nothing to do */ | |
439 | break; | |
440 | case 5 : | |
441 | /* nothing to do */ | |
442 | break; | |
443 | case 6 : | |
444 | errmsg = cgen_validate_signed_integer (fields->f_simm8, -128, 127); | |
445 | break; | |
446 | case 7 : | |
447 | errmsg = cgen_validate_signed_integer (fields->f_simm16, -32768, 32767); | |
448 | break; | |
449 | case 8 : | |
450 | errmsg = cgen_validate_unsigned_integer (fields->f_uimm4, 0, 15); | |
451 | break; | |
452 | case 9 : | |
453 | errmsg = cgen_validate_unsigned_integer (fields->f_uimm5, 0, 31); | |
454 | break; | |
455 | case 10 : | |
456 | errmsg = cgen_validate_unsigned_integer (fields->f_uimm16, 0, 65535); | |
457 | break; | |
458 | case 11 : | |
459 | errmsg = cgen_validate_unsigned_integer (fields->f_hi16, 0, 65535); | |
460 | break; | |
461 | case 12 : | |
462 | errmsg = cgen_validate_signed_integer (fields->f_simm16, -32768, 32767); | |
463 | break; | |
464 | case 13 : | |
465 | errmsg = cgen_validate_unsigned_integer (fields->f_uimm16, 0, 65535); | |
466 | break; | |
467 | case 14 : | |
468 | /* nothing to do */ | |
469 | break; | |
470 | case 15 : | |
471 | /* nothing to do */ | |
472 | break; | |
473 | case 16 : | |
474 | /* nothing to do */ | |
475 | break; | |
476 | case 17 : | |
477 | /* nothing to do */ | |
478 | break; | |
479 | ||
480 | default : | |
481 | fprintf (stderr, "Unrecognized field %d while validating operand.\n", | |
482 | opindex); | |
483 | abort (); | |
484 | } | |
485 | ||
486 | return errmsg; | |
487 | } | |
488 | ||
489 | cgen_parse_fn *m32r_cgen_parse_handlers[] = { | |
490 | 0, /* default */ | |
491 | parse_insn_normal, | |
492 | }; | |
493 | ||
494 | cgen_insert_fn *m32r_cgen_insert_handlers[] = { | |
495 | 0, /* default */ | |
496 | insert_insn_normal, | |
497 | }; | |
498 | ||
499 | void | |
500 | m32r_cgen_init_asm (mach, endian) | |
501 | int mach; | |
502 | enum cgen_endian endian; | |
503 | { | |
504 | m32r_cgen_init_tables (mach); | |
505 | cgen_set_cpu (& m32r_cgen_opcode_data, mach, endian); | |
506 | cgen_asm_init (); | |
507 | } | |
508 | ||
509 | \f | |
510 | /* Default insn parser. | |
511 | ||
512 | The syntax string is scanned and operands are parsed and stored in FIELDS. | |
513 | Relocs are queued as we go via other callbacks. | |
514 | ||
515 | ??? Note that this is currently an all-or-nothing parser. If we fail to | |
516 | parse the instruction, we return 0 and the caller will start over from | |
517 | the beginning. Backtracking will be necessary in parsing subexpressions, | |
518 | but that can be handled there. Not handling backtracking here may get | |
519 | expensive in the case of the m68k. Deal with later. | |
520 | ||
521 | Returns NULL for success, an error message for failure. | |
522 | */ | |
523 | ||
524 | static const char * | |
525 | parse_insn_normal (insn, strp, fields) | |
526 | const struct cgen_insn *insn; | |
527 | const char **strp; | |
528 | struct cgen_fields *fields; | |
529 | { | |
530 | const struct cgen_syntax *syntax = CGEN_INSN_SYNTAX (insn); | |
531 | const char *str = *strp; | |
532 | const char *errmsg; | |
533 | const unsigned char *syn; | |
534 | #ifdef CGEN_MNEMONIC_OPERANDS | |
535 | int past_opcode_p; | |
536 | #endif | |
537 | ||
538 | /* If mnemonics are constant, they're not stored with the syntax string. */ | |
539 | #ifndef CGEN_MNEMONIC_OPERANDS | |
540 | { | |
541 | const char *p = syntax->mnemonic; | |
542 | ||
543 | while (*p && *p == *str) | |
544 | ++p, ++str; | |
545 | if (*p || (*str && !isspace (*str))) | |
546 | return "unrecognized instruction"; | |
547 | ||
548 | while (isspace (*str)) | |
549 | ++str; | |
550 | } | |
551 | #endif | |
552 | ||
553 | CGEN_INIT_PARSE (); | |
554 | cgen_asm_init_parse (); | |
555 | #ifdef CGEN_MNEMONIC_OPERANDS | |
556 | past_opcode_p = 0; | |
557 | #endif | |
558 | ||
559 | /* We don't check for (*str != '\0') here because we want to parse | |
560 | any trailing fake arguments in the syntax string. */ | |
561 | for (syn = syntax->syntax; *syn != '\0'; ) | |
562 | { | |
563 | /* Non operand chars must match exactly. */ | |
564 | /* FIXME: Need to better handle whitespace. */ | |
565 | if (CGEN_SYNTAX_CHAR_P (*syn)) | |
566 | { | |
567 | if (*str == CGEN_SYNTAX_CHAR (*syn)) | |
568 | { | |
569 | #ifdef CGEN_MNEMONIC_OPERANDS | |
570 | if (*syn == ' ') | |
571 | past_opcode_p = 1; | |
572 | #endif | |
573 | ++syn; | |
574 | ++str; | |
575 | } | |
576 | else | |
577 | { | |
578 | /* Syntax char didn't match. Can't be this insn. */ | |
579 | /* FIXME: would like to return "expected char `c'" */ | |
580 | return "syntax error"; | |
581 | } | |
582 | continue; | |
583 | } | |
584 | ||
585 | /* We have an operand of some sort. */ | |
586 | errmsg = m32r_cgen_parse_operand (CGEN_SYNTAX_FIELD (*syn), | |
587 | &str, fields); | |
588 | if (errmsg) | |
589 | return errmsg; | |
590 | ||
591 | /* Done with this operand, continue with next one. */ | |
592 | ++syn; | |
593 | } | |
594 | ||
595 | /* If we're at the end of the syntax string, we're done. */ | |
596 | if (*syn == '\0') | |
597 | { | |
598 | /* FIXME: For the moment we assume a valid `str' can only contain | |
599 | blanks now. IE: We needn't try again with a longer version of | |
600 | the insn and it is assumed that longer versions of insns appear | |
601 | before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3). */ | |
602 | while (isspace (*str)) | |
603 | ++str; | |
604 | ||
605 | if (*str != '\0') | |
606 | return "junk at end of line"; /* FIXME: would like to include `str' */ | |
607 | ||
608 | return NULL; | |
609 | } | |
610 | ||
611 | /* We couldn't parse it. */ | |
612 | return "unrecognized instruction"; | |
613 | } | |
614 | ||
615 | /* Default insn builder (insert handler). | |
616 | The instruction is recorded in target byte order. */ | |
617 | ||
618 | static void | |
619 | insert_insn_normal (insn, fields, buffer) | |
620 | const struct cgen_insn *insn; | |
621 | struct cgen_fields *fields; | |
622 | cgen_insn_t *buffer; | |
623 | { | |
624 | const struct cgen_syntax *syntax = CGEN_INSN_SYNTAX (insn); | |
625 | bfd_vma value; | |
626 | const unsigned char *syn; | |
627 | ||
628 | CGEN_INIT_INSERT (); | |
629 | value = syntax->value; | |
630 | ||
631 | /* If we're recording insns as numbers (rather than a string of bytes), | |
632 | target byte order handling is deferred until later. */ | |
633 | #undef min | |
634 | #define min(a,b) ((a) < (b) ? (a) : (b)) | |
635 | #if 0 /*def CGEN_INT_INSN*/ | |
636 | *buffer = value; | |
637 | #else | |
638 | switch (min (CGEN_BASE_INSN_BITSIZE, CGEN_FIELDS_BITSIZE (fields))) | |
639 | { | |
640 | case 8: | |
641 | *buffer = value; | |
642 | break; | |
643 | case 16: | |
644 | if (CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG) | |
645 | bfd_putb16 (value, (char *) buffer); | |
646 | else | |
647 | bfd_putl16 (value, (char *) buffer); | |
648 | break; | |
649 | case 32: | |
650 | if (CGEN_CURRENT_ENDIAN == CGEN_ENDIAN_BIG) | |
651 | bfd_putb32 (value, (char *) buffer); | |
652 | else | |
653 | bfd_putl32 (value, (char *) buffer); | |
654 | break; | |
655 | default: | |
656 | abort (); | |
657 | } | |
658 | #endif | |
659 | ||
660 | /* ??? Rather than scanning the syntax string again, we could store | |
661 | in `fields' a null terminated list of the fields that are present. */ | |
662 | ||
663 | for (syn = syntax->syntax; *syn != '\0'; ++syn) | |
664 | { | |
665 | if (CGEN_SYNTAX_CHAR_P (*syn)) | |
666 | continue; | |
667 | ||
668 | m32r_cgen_insert_operand (CGEN_SYNTAX_FIELD (*syn), fields, buffer); | |
669 | } | |
670 | } | |
671 | \f | |
672 | /* Main entry point. | |
673 | This routine is called for each instruction to be assembled. | |
674 | STR points to the insn to be assembled. | |
675 | We assume all necessary tables have been initialized. | |
676 | The result is a pointer to the insn's entry in the opcode table, | |
677 | or NULL if an error occured (an error message will have already been | |
678 | printed). */ | |
679 | ||
680 | const struct cgen_insn * | |
681 | m32r_cgen_assemble_insn (str, fields, buf) | |
682 | const char *str; | |
683 | struct cgen_fields *fields; | |
684 | cgen_insn_t *buf; | |
685 | { | |
686 | const char *start; | |
687 | CGEN_INSN_LIST *ilist; | |
688 | ||
689 | /* Skip leading white space. */ | |
690 | while (isspace (*str)) | |
691 | ++str; | |
692 | ||
693 | /* The instructions are stored in hashed lists. | |
694 | Get the first in the list. */ | |
695 | ilist = CGEN_ASM_LOOKUP_INSN (str); | |
696 | ||
697 | /* Keep looking until we find a match. */ | |
698 | ||
699 | start = str; | |
700 | for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist)) | |
701 | { | |
702 | const struct cgen_insn *insn = ilist->insn; | |
703 | ||
704 | #if 0 /* not needed as unsupported opcodes shouldn't be in the hash lists */ | |
705 | /* Is this insn supported by the selected cpu? */ | |
706 | if (! m32r_cgen_insn_supported (insn)) | |
707 | continue; | |
708 | #endif | |
709 | ||
710 | #if 1 /* FIXME: wip */ | |
711 | /* If the RELAX attribute is set, this is an insn that shouldn't be | |
712 | chosen immediately. Instead, it is used during assembler/linker | |
713 | relaxation if possible. */ | |
714 | if (CGEN_INSN_ATTR (insn, CGEN_INSN_RELAX) != 0) | |
715 | continue; | |
716 | #endif | |
717 | ||
718 | str = start; | |
719 | ||
720 | /* Record a default length for the insn. This will get set to the | |
721 | correct value while parsing. */ | |
722 | /* FIXME: wip */ | |
723 | CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn); | |
724 | ||
725 | /* ??? The extent to which moving the parse and insert handlers into | |
726 | this function (thus removing the function call) will speed things up | |
727 | is unclear. The simplicity and flexibility of the current scheme is | |
728 | appropriate for now. One could have the best of both worlds with | |
729 | inline functions but of course that would only work for gcc. Since | |
730 | we're machine generating some code we could do that here too. Maybe | |
731 | later. */ | |
732 | if (! (*CGEN_PARSE_FN (insn)) (insn, &str, fields)) | |
733 | { | |
734 | (*CGEN_INSERT_FN (insn)) (insn, fields, buf); | |
735 | /* It is up to the caller to actually output the insn and any | |
736 | queued relocs. */ | |
737 | return insn; | |
738 | } | |
739 | ||
740 | /* Try the next entry. */ | |
741 | } | |
742 | ||
743 | /* FIXME: Define this as a callback, or pass back string? */ | |
744 | as_bad ("bad instruction `%s'", start); | |
745 | return NULL; | |
746 | } | |
747 | \f | |
748 | /* Record each member of OPVALS in the assembler's symbol table. | |
749 | FIXME: Not currently used. */ | |
750 | ||
751 | void | |
752 | m32r_cgen_asm_hash_keywords (opvals) | |
753 | struct cgen_keyword *opvals; | |
754 | { | |
755 | struct cgen_keyword_search search = cgen_keyword_search_init (opvals, NULL); | |
756 | const struct cgen_keyword_entry *ke; | |
757 | ||
758 | while ((ke = cgen_keyword_search_next (&search)) != NULL) | |
759 | { | |
760 | #if 0 /* Unnecessary, should be done in the search routine. */ | |
761 | if (! m32r_cgen_opval_supported (ke)) | |
762 | continue; | |
763 | #endif | |
764 | cgen_asm_record_register (ke->name, ke->value); | |
765 | } | |
766 | } |