* cgen-asm.in (insert_normal): Use CGEN_BOOL_ATTR.
[deliverable/binutils-gdb.git] / opcodes / cgen-asm.in
1 /* Assembler interface for targets using CGEN. -*- C -*-
2 CGEN: Cpu tools GENerator
3
4 THIS FILE IS USED TO GENERATE @prefix@-asm.c.
5
6 Copyright (C) 1996, 1997, 1998 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 Foundation, Inc.,
22 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23
24 #include "sysdep.h"
25 #include <ctype.h>
26 #include <stdio.h>
27 #include "ansidecl.h"
28 #include "bfd.h"
29 #include "symcat.h"
30 #include "@prefix@-opc.h"
31 #include "opintl.h"
32
33 #undef min
34 #define min(a,b) ((a) < (b) ? (a) : (b))
35 #undef max
36 #define max(a,b) ((a) > (b) ? (a) : (b))
37
38 #undef INLINE
39 #ifdef __GNUC__
40 #define INLINE __inline__
41 #else
42 #define INLINE
43 #endif
44
45 /* Used by the ifield rtx function. */
46 #define FLD(f) (fields->f)
47
48 static const char * insert_normal
49 PARAMS ((CGEN_OPCODE_DESC, long, unsigned int, unsigned int, unsigned int,
50 unsigned int, unsigned int, unsigned int, CGEN_INSN_BYTES_PTR));
51 static const char * parse_insn_normal
52 PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN *,
53 const char **, CGEN_FIELDS *));
54 static const char * insert_insn_normal
55 PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN *,
56 CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma));
57 \f
58 /* -- assembler routines inserted here */
59 \f
60 #if ! CGEN_INT_INSN_P
61
62 /* Subroutine of insert_normal. */
63
64 static INLINE void
65 insert_1 (od, value, start, length, word_length, bufp)
66 CGEN_OPCODE_DESC od;
67 unsigned long value;
68 int start,length,word_length;
69 unsigned char *bufp;
70 {
71 unsigned long x,mask;
72 int shift;
73 int big_p = CGEN_OPCODE_INSN_ENDIAN (od) == CGEN_ENDIAN_BIG;
74
75 switch (word_length)
76 {
77 case 8:
78 x = *bufp;
79 break;
80 case 16:
81 if (big_p)
82 x = bfd_getb16 (bufp);
83 else
84 x = bfd_getl16 (bufp);
85 break;
86 case 24:
87 /* ??? This may need reworking as these cases don't necessarily
88 want the first byte and the last two bytes handled like this. */
89 if (big_p)
90 x = (bufp[0] << 16) | bfd_getb16 (bufp + 1);
91 else
92 x = bfd_getl16 (bufp) | (bufp[2] << 16);
93 break;
94 case 32:
95 if (big_p)
96 x = bfd_getb32 (bufp);
97 else
98 x = bfd_getl32 (bufp);
99 break;
100 default :
101 abort ();
102 }
103
104 /* Written this way to avoid undefined behaviour. */
105 mask = (((1L << (length - 1)) - 1) << 1) | 1;
106 if (CGEN_INSN_LSB0_P)
107 shift = (start + 1) - length;
108 else
109 shift = (word_length - (start + length));
110 x = (x & ~(mask << shift)) | ((value & mask) << shift);
111
112 switch (word_length)
113 {
114 case 8:
115 *bufp = x;
116 break;
117 case 16:
118 if (big_p)
119 bfd_putb16 (x, bufp);
120 else
121 bfd_putl16 (x, bufp);
122 break;
123 case 24:
124 /* ??? This may need reworking as these cases don't necessarily
125 want the first byte and the last two bytes handled like this. */
126 if (big_p)
127 {
128 bufp[0] = x >> 16;
129 bfd_putb16 (x, bufp + 1);
130 }
131 else
132 {
133 bfd_putl16 (x, bufp);
134 bufp[2] = x >> 16;
135 }
136 break;
137 case 32:
138 if (big_p)
139 bfd_putb32 (x, bufp);
140 else
141 bfd_putl32 (x, bufp);
142 break;
143 default :
144 abort ();
145 }
146 }
147
148 #endif /* ! CGEN_INT_INSN_P */
149
150 /* Default insertion routine.
151
152 ATTRS is a mask of the boolean attributes.
153 WORD_OFFSET is the offset in bits from the start of the insn of the value.
154 WORD_LENGTH is the length of the word in bits in which the value resides.
155 START is the starting bit number in the word, architecture origin.
156 LENGTH is the length of VALUE in bits.
157 TOTAL_LENGTH is the total length of the insn in bits.
158
159 The result is an error message or NULL if success. */
160
161 /* ??? This duplicates functionality with bfd's howto table and
162 bfd_install_relocation. */
163 /* ??? This doesn't handle bfd_vma's. Create another function when
164 necessary. */
165
166 static const char *
167 insert_normal (od, value, attrs, word_offset, start, length, word_length,
168 total_length, buffer)
169 CGEN_OPCODE_DESC od;
170 long value;
171 unsigned int attrs;
172 unsigned int word_offset, start, length, word_length, total_length;
173 CGEN_INSN_BYTES_PTR buffer;
174 {
175 static char errbuf[100];
176 /* Written this way to avoid undefined behaviour. */
177 unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
178
179 /* If LENGTH is zero, this operand doesn't contribute to the value. */
180 if (length == 0)
181 return NULL;
182
183 if (CGEN_INT_INSN_P
184 && word_offset != 0)
185 abort ();
186
187 if (word_length > 32)
188 abort ();
189
190 /* For architectures with insns smaller than the insn-base-bitsize,
191 word_length may be too big. */
192 #if CGEN_MIN_INSN_BITSIZE < CGEN_BASE_INSN_BITSIZE
193 if (word_offset == 0
194 && word_length > total_length)
195 word_length = total_length;
196 #endif
197
198 /* Ensure VALUE will fit. */
199 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED))
200 {
201 unsigned long maxval = mask;
202 if ((unsigned long) value > maxval)
203 {
204 /* xgettext:c-format */
205 sprintf (errbuf,
206 _("operand out of range (%lu not between 0 and %lu)"),
207 value, maxval);
208 return errbuf;
209 }
210 }
211 else
212 {
213 long minval = - (1L << (length - 1));
214 long maxval = (1L << (length - 1)) - 1;
215 if (value < minval || value > maxval)
216 {
217 sprintf
218 /* xgettext:c-format */
219 (errbuf, _("operand out of range (%ld not between %ld and %ld)"),
220 value, minval, maxval);
221 return errbuf;
222 }
223 }
224
225 #if CGEN_INT_INSN_P
226
227 {
228 int shift;
229
230 if (CGEN_INSN_LSB0_P)
231 shift = (start + 1) - length;
232 else
233 shift = word_length - (start + length);
234 *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
235 }
236
237 #else /* ! CGEN_INT_INSN_P */
238
239 {
240 unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
241
242 insert_1 (od, value, start, length, word_length, bufp);
243 }
244
245 #endif /* ! CGEN_INT_INSN_P */
246
247 return NULL;
248 }
249 \f
250 /* Default insn parser.
251
252 The syntax string is scanned and operands are parsed and stored in FIELDS.
253 Relocs are queued as we go via other callbacks.
254
255 ??? Note that this is currently an all-or-nothing parser. If we fail to
256 parse the instruction, we return 0 and the caller will start over from
257 the beginning. Backtracking will be necessary in parsing subexpressions,
258 but that can be handled there. Not handling backtracking here may get
259 expensive in the case of the m68k. Deal with later.
260
261 Returns NULL for success, an error message for failure.
262 */
263
264 static const char *
265 parse_insn_normal (od, insn, strp, fields)
266 CGEN_OPCODE_DESC od;
267 const CGEN_INSN * insn;
268 const char ** strp;
269 CGEN_FIELDS * fields;
270 {
271 const CGEN_SYNTAX * syntax = CGEN_INSN_SYNTAX (insn);
272 const char * str = *strp;
273 const char * errmsg;
274 const char * p;
275 const unsigned char * syn;
276 #ifdef CGEN_MNEMONIC_OPERANDS
277 /* FIXME: wip */
278 int past_opcode_p;
279 #endif
280
281 /* For now we assume the mnemonic is first (there are no leading operands).
282 We can parse it without needing to set up operand parsing.
283 GAS's input scrubber will ensure mnemonics are lowercase, but we may
284 not be called from GAS. */
285 p = CGEN_INSN_MNEMONIC (insn);
286 while (*p && tolower (*p) == tolower (*str))
287 ++p, ++str;
288
289 if (* p || (* str && !isspace (* str)))
290 return _("unrecognized instruction");
291
292 CGEN_INIT_PARSE (od);
293 cgen_init_parse_operand (od);
294 #ifdef CGEN_MNEMONIC_OPERANDS
295 past_opcode_p = 0;
296 #endif
297
298 /* We don't check for (*str != '\0') here because we want to parse
299 any trailing fake arguments in the syntax string. */
300 syn = CGEN_SYNTAX_STRING (syntax);
301
302 /* Mnemonics come first for now, ensure valid string. */
303 if (! CGEN_SYNTAX_MNEMONIC_P (* syn))
304 abort ();
305
306 ++syn;
307
308 while (* syn != 0)
309 {
310 /* Non operand chars must match exactly. */
311 if (CGEN_SYNTAX_CHAR_P (* syn))
312 {
313 if (*str == CGEN_SYNTAX_CHAR (* syn))
314 {
315 #ifdef CGEN_MNEMONIC_OPERANDS
316 if (* syn == ' ')
317 past_opcode_p = 1;
318 #endif
319 ++ syn;
320 ++ str;
321 }
322 else
323 {
324 /* Syntax char didn't match. Can't be this insn. */
325 /* FIXME: would like to return something like
326 "expected char `c'" */
327 return _("syntax error");
328 }
329 continue;
330 }
331
332 /* We have an operand of some sort. */
333 errmsg = @arch@_cgen_parse_operand (od, CGEN_SYNTAX_FIELD (*syn),
334 &str, fields);
335 if (errmsg)
336 return errmsg;
337
338 /* Done with this operand, continue with next one. */
339 ++ syn;
340 }
341
342 /* If we're at the end of the syntax string, we're done. */
343 if (* syn == '\0')
344 {
345 /* FIXME: For the moment we assume a valid `str' can only contain
346 blanks now. IE: We needn't try again with a longer version of
347 the insn and it is assumed that longer versions of insns appear
348 before shorter ones (eg: lsr r2,r3,1 vs lsr r2,r3). */
349 while (isspace (* str))
350 ++ str;
351
352 if (* str != '\0')
353 return _("junk at end of line"); /* FIXME: would like to include `str' */
354
355 return NULL;
356 }
357
358 /* We couldn't parse it. */
359 return _("unrecognized instruction");
360 }
361
362 /* Default insn builder (insert handler).
363 The instruction is recorded in CGEN_INT_INSN_P byte order
364 (meaning that if CGEN_INT_INSN_P BUFFER is an int * and thus the value is
365 recorded in host byte order, otherwise BUFFER is an array of bytes and the
366 value is recorded in target byte order).
367 The result is an error message or NULL if success. */
368
369 static const char *
370 insert_insn_normal (od, insn, fields, buffer, pc)
371 CGEN_OPCODE_DESC od;
372 const CGEN_INSN * insn;
373 CGEN_FIELDS * fields;
374 CGEN_INSN_BYTES_PTR buffer;
375 bfd_vma pc;
376 {
377 const CGEN_SYNTAX * syntax = CGEN_INSN_SYNTAX (insn);
378 unsigned long value;
379 const unsigned char * syn;
380
381 CGEN_INIT_INSERT (od);
382 value = CGEN_INSN_BASE_VALUE (insn);
383
384 /* If we're recording insns as numbers (rather than a string of bytes),
385 target byte order handling is deferred until later. */
386
387 #if CGEN_INT_INSN_P
388
389 *buffer = value;
390
391 #else
392
393 cgen_put_insn_value (od, buffer, min (CGEN_BASE_INSN_BITSIZE,
394 CGEN_FIELDS_BITSIZE (fields)),
395 value);
396
397 #endif /* ! CGEN_INT_INSN_P */
398
399 /* ??? It would be better to scan the format's fields.
400 Still need to be able to insert a value based on the operand though;
401 e.g. storing a branch displacement that got resolved later.
402 Needs more thought first. */
403
404 for (syn = CGEN_SYNTAX_STRING (syntax); * syn != '\0'; ++ syn)
405 {
406 const char *errmsg;
407
408 if (CGEN_SYNTAX_CHAR_P (* syn))
409 continue;
410
411 errmsg = @arch@_cgen_insert_operand (od, CGEN_SYNTAX_FIELD (*syn),
412 fields, buffer, pc);
413 if (errmsg)
414 return errmsg;
415 }
416
417 return NULL;
418 }
419 \f
420 /* Main entry point.
421 This routine is called for each instruction to be assembled.
422 STR points to the insn to be assembled.
423 We assume all necessary tables have been initialized.
424 The assembled instruction, less any fixups, is stored in BUF.
425 Remember that if CGEN_INT_INSN_P then BUF is an int and thus the value
426 still needs to be converted to target byte order, otherwise BUF is an array
427 of bytes in target byte order.
428 The result is a pointer to the insn's entry in the opcode table,
429 or NULL if an error occured (an error message will have already been
430 printed).
431
432 Note that when processing (non-alias) macro-insns,
433 this function recurses. */
434
435 const CGEN_INSN *
436 @arch@_cgen_assemble_insn (od, str, fields, buf, errmsg)
437 CGEN_OPCODE_DESC od;
438 const char * str;
439 CGEN_FIELDS * fields;
440 CGEN_INSN_BYTES_PTR buf;
441 char ** errmsg;
442 {
443 const char * start;
444 CGEN_INSN_LIST * ilist;
445
446 /* Skip leading white space. */
447 while (isspace (* str))
448 ++ str;
449
450 /* The instructions are stored in hashed lists.
451 Get the first in the list. */
452 ilist = CGEN_ASM_LOOKUP_INSN (od, str);
453
454 /* Keep looking until we find a match. */
455
456 start = str;
457 for ( ; ilist != NULL ; ilist = CGEN_ASM_NEXT_INSN (ilist))
458 {
459 const CGEN_INSN *insn = ilist->insn;
460
461 #if 0 /* not needed as unsupported opcodes shouldn't be in the hash lists */
462 /* Is this insn supported by the selected cpu? */
463 if (! @arch@_cgen_insn_supported (od, insn))
464 continue;
465 #endif
466
467 /* If the RELAX attribute is set, this is an insn that shouldn't be
468 chosen immediately. Instead, it is used during assembler/linker
469 relaxation if possible. */
470 if (CGEN_INSN_ATTR (insn, CGEN_INSN_RELAX) != 0)
471 continue;
472
473 str = start;
474
475 /* Allow parse/insert handlers to obtain length of insn. */
476 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
477
478 if (! CGEN_PARSE_FN (insn) (od, insn, & str, fields))
479 {
480 /* ??? 0 is passed for `pc' */
481 if (CGEN_INSERT_FN (insn) (od, insn, fields, buf, (bfd_vma) 0) != NULL)
482 continue;
483 /* It is up to the caller to actually output the insn and any
484 queued relocs. */
485 return insn;
486 }
487
488 /* Try the next entry. */
489 }
490
491 /* FIXME: We can return a better error message than this.
492 Need to track why it failed and pick the right one. */
493 {
494 static char errbuf[100];
495 if (strlen (start) > 50)
496 /* xgettext:c-format */
497 sprintf (errbuf, _("bad instruction `%.50s...'"), start);
498 else
499 /* xgettext:c-format */
500 sprintf (errbuf, _("bad instruction `%.50s'"), start);
501
502 *errmsg = errbuf;
503 return NULL;
504 }
505 }
506 \f
507 #if 0 /* This calls back to GAS which we can't do without care. */
508
509 /* Record each member of OPVALS in the assembler's symbol table.
510 This lets GAS parse registers for us.
511 ??? Interesting idea but not currently used. */
512
513 /* Record each member of OPVALS in the assembler's symbol table.
514 FIXME: Not currently used. */
515
516 void
517 @arch@_cgen_asm_hash_keywords (od, opvals)
518 CGEN_OPCODE_DESC od;
519 CGEN_KEYWORD * opvals;
520 {
521 CGEN_KEYWORD_SEARCH search = cgen_keyword_search_init (opvals, NULL);
522 const CGEN_KEYWORD_ENTRY * ke;
523
524 while ((ke = cgen_keyword_search_next (& search)) != NULL)
525 {
526 #if 0 /* Unnecessary, should be done in the search routine. */
527 if (! @arch@_cgen_opval_supported (ke))
528 continue;
529 #endif
530 cgen_asm_record_register (od, ke->name, ke->value);
531 }
532 }
533
534 #endif /* 0 */
This page took 0.046338 seconds and 5 git commands to generate.