2000-08-04 Ben Elliston <bje@redhat.com>
[deliverable/binutils-gdb.git] / opcodes / cgen-ibld.in
1 /* Instruction building/extraction support for @arch@. -*- C -*-
2
3 THIS FILE IS MACHINE GENERATED WITH CGEN: Cpu tools GENerator.
4 - the resultant file is machine generated, cgen-ibld.in isn't
5
6 Copyright (C) 1996, 1997, 1998, 1999, 2000 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 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
25 Keep that in mind. */
26
27 #include "sysdep.h"
28 #include <ctype.h>
29 #include <stdio.h>
30 #include "ansidecl.h"
31 #include "dis-asm.h"
32 #include "bfd.h"
33 #include "symcat.h"
34 #include "@prefix@-desc.h"
35 #include "@prefix@-opc.h"
36 #include "opintl.h"
37
38 #undef min
39 #define min(a,b) ((a) < (b) ? (a) : (b))
40 #undef max
41 #define max(a,b) ((a) > (b) ? (a) : (b))
42
43 /* Used by the ifield rtx function. */
44 #define FLD(f) (fields->f)
45
46 static const char * insert_normal
47 PARAMS ((CGEN_CPU_DESC, long, unsigned int, unsigned int, unsigned int,
48 unsigned int, unsigned int, unsigned int, CGEN_INSN_BYTES_PTR));
49 static const char * insert_insn_normal
50 PARAMS ((CGEN_CPU_DESC, const CGEN_INSN *,
51 CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma));
52
53 static int extract_normal
54 PARAMS ((CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_INT,
55 unsigned int, unsigned int, unsigned int, unsigned int,
56 unsigned int, unsigned int, bfd_vma, long *));
57 static int extract_insn_normal
58 PARAMS ((CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
59 CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma));
60 \f
61 /* Operand insertion. */
62
63 #if ! CGEN_INT_INSN_P
64
65 /* Subroutine of insert_normal. */
66
67 static CGEN_INLINE void
68 insert_1 (cd, value, start, length, word_length, bufp)
69 CGEN_CPU_DESC cd;
70 unsigned long value;
71 int start,length,word_length;
72 unsigned char *bufp;
73 {
74 unsigned long x,mask;
75 int shift;
76 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
77
78 switch (word_length)
79 {
80 case 8:
81 x = *bufp;
82 break;
83 case 16:
84 if (big_p)
85 x = bfd_getb16 (bufp);
86 else
87 x = bfd_getl16 (bufp);
88 break;
89 case 24:
90 /* ??? This may need reworking as these cases don't necessarily
91 want the first byte and the last two bytes handled like this. */
92 if (big_p)
93 x = (bufp[0] << 16) | bfd_getb16 (bufp + 1);
94 else
95 x = bfd_getl16 (bufp) | (bufp[2] << 16);
96 break;
97 case 32:
98 if (big_p)
99 x = bfd_getb32 (bufp);
100 else
101 x = bfd_getl32 (bufp);
102 break;
103 default :
104 abort ();
105 }
106
107 /* Written this way to avoid undefined behaviour. */
108 mask = (((1L << (length - 1)) - 1) << 1) | 1;
109 if (CGEN_INSN_LSB0_P)
110 shift = (start + 1) - length;
111 else
112 shift = (word_length - (start + length));
113 x = (x & ~(mask << shift)) | ((value & mask) << shift);
114
115 switch (word_length)
116 {
117 case 8:
118 *bufp = x;
119 break;
120 case 16:
121 if (big_p)
122 bfd_putb16 (x, bufp);
123 else
124 bfd_putl16 (x, bufp);
125 break;
126 case 24:
127 /* ??? This may need reworking as these cases don't necessarily
128 want the first byte and the last two bytes handled like this. */
129 if (big_p)
130 {
131 bufp[0] = x >> 16;
132 bfd_putb16 (x, bufp + 1);
133 }
134 else
135 {
136 bfd_putl16 (x, bufp);
137 bufp[2] = x >> 16;
138 }
139 break;
140 case 32:
141 if (big_p)
142 bfd_putb32 (x, bufp);
143 else
144 bfd_putl32 (x, bufp);
145 break;
146 default :
147 abort ();
148 }
149 }
150
151 #endif /* ! CGEN_INT_INSN_P */
152
153 /* Default insertion routine.
154
155 ATTRS is a mask of the boolean attributes.
156 WORD_OFFSET is the offset in bits from the start of the insn of the value.
157 WORD_LENGTH is the length of the word in bits in which the value resides.
158 START is the starting bit number in the word, architecture origin.
159 LENGTH is the length of VALUE in bits.
160 TOTAL_LENGTH is the total length of the insn in bits.
161
162 The result is an error message or NULL if success. */
163
164 /* ??? This duplicates functionality with bfd's howto table and
165 bfd_install_relocation. */
166 /* ??? This doesn't handle bfd_vma's. Create another function when
167 necessary. */
168
169 static const char *
170 insert_normal (cd, value, attrs, word_offset, start, length, word_length,
171 total_length, buffer)
172 CGEN_CPU_DESC cd;
173 long value;
174 unsigned int attrs;
175 unsigned int word_offset, start, length, word_length, total_length;
176 CGEN_INSN_BYTES_PTR buffer;
177 {
178 static char errbuf[100];
179 /* Written this way to avoid undefined behaviour. */
180 unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
181
182 /* If LENGTH is zero, this operand doesn't contribute to the value. */
183 if (length == 0)
184 return NULL;
185
186 if (CGEN_INT_INSN_P
187 && word_offset != 0)
188 abort ();
189
190 if (word_length > 32)
191 abort ();
192
193 /* For architectures with insns smaller than the base-insn-bitsize,
194 word_length may be too big. */
195 if (cd->min_insn_bitsize < cd->base_insn_bitsize)
196 {
197 if (word_offset == 0
198 && word_length > total_length)
199 word_length = total_length;
200 }
201
202 /* Ensure VALUE will fit. */
203 if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
204 {
205 unsigned long maxval = mask;
206
207 if ((unsigned long) value > maxval)
208 {
209 /* xgettext:c-format */
210 sprintf (errbuf,
211 _("operand out of range (%lu not between 0 and %lu)"),
212 value, maxval);
213 return errbuf;
214 }
215 }
216 else
217 {
218 if (! cgen_signed_overflow_ok_p (cd))
219 {
220 long minval = - (1L << (length - 1));
221 long maxval = (1L << (length - 1)) - 1;
222
223 if (value < minval || value > maxval)
224 {
225 sprintf
226 /* xgettext:c-format */
227 (errbuf, _("operand out of range (%ld not between %ld and %ld)"),
228 value, minval, maxval);
229 return errbuf;
230 }
231 }
232 }
233
234 #if CGEN_INT_INSN_P
235
236 {
237 int shift;
238
239 if (CGEN_INSN_LSB0_P)
240 shift = (start + 1) - length;
241 else
242 shift = word_length - (start + length);
243 *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
244 }
245
246 #else /* ! CGEN_INT_INSN_P */
247
248 {
249 unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
250
251 insert_1 (cd, value, start, length, word_length, bufp);
252 }
253
254 #endif /* ! CGEN_INT_INSN_P */
255
256 return NULL;
257 }
258
259 /* Default insn builder (insert handler).
260 The instruction is recorded in CGEN_INT_INSN_P byte order
261 (meaning that if CGEN_INT_INSN_P BUFFER is an int * and thus the value is
262 recorded in host byte order, otherwise BUFFER is an array of bytes and the
263 value is recorded in target byte order).
264 The result is an error message or NULL if success. */
265
266 static const char *
267 insert_insn_normal (cd, insn, fields, buffer, pc)
268 CGEN_CPU_DESC cd;
269 const CGEN_INSN * insn;
270 CGEN_FIELDS * fields;
271 CGEN_INSN_BYTES_PTR buffer;
272 bfd_vma pc;
273 {
274 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
275 unsigned long value;
276 const unsigned char * syn;
277
278 CGEN_INIT_INSERT (cd);
279 value = CGEN_INSN_BASE_VALUE (insn);
280
281 /* If we're recording insns as numbers (rather than a string of bytes),
282 target byte order handling is deferred until later. */
283
284 #if CGEN_INT_INSN_P
285
286 *buffer = value;
287
288 #else
289
290 cgen_put_insn_value (cd, buffer, min (cd->base_insn_bitsize,
291 CGEN_FIELDS_BITSIZE (fields)),
292 value);
293
294 #endif /* ! CGEN_INT_INSN_P */
295
296 /* ??? It would be better to scan the format's fields.
297 Still need to be able to insert a value based on the operand though;
298 e.g. storing a branch displacement that got resolved later.
299 Needs more thought first. */
300
301 for (syn = CGEN_SYNTAX_STRING (syntax); * syn != '\0'; ++ syn)
302 {
303 const char *errmsg;
304
305 if (CGEN_SYNTAX_CHAR_P (* syn))
306 continue;
307
308 errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
309 fields, buffer, pc);
310 if (errmsg)
311 return errmsg;
312 }
313
314 return NULL;
315 }
316 \f
317 /* Operand extraction. */
318
319 #if ! CGEN_INT_INSN_P
320
321 /* Subroutine of extract_normal.
322 Ensure sufficient bytes are cached in EX_INFO.
323 OFFSET is the offset in bytes from the start of the insn of the value.
324 BYTES is the length of the needed value.
325 Returns 1 for success, 0 for failure. */
326
327 static CGEN_INLINE int
328 fill_cache (cd, ex_info, offset, bytes, pc)
329 CGEN_CPU_DESC cd;
330 CGEN_EXTRACT_INFO *ex_info;
331 int offset, bytes;
332 bfd_vma pc;
333 {
334 /* It's doubtful that the middle part has already been fetched so
335 we don't optimize that case. kiss. */
336 int mask;
337 disassemble_info *info = (disassemble_info *) ex_info->dis_info;
338
339 /* First do a quick check. */
340 mask = (1 << bytes) - 1;
341 if (((ex_info->valid >> offset) & mask) == mask)
342 return 1;
343
344 /* Search for the first byte we need to read. */
345 for (mask = 1 << offset; bytes > 0; --bytes, ++offset, mask <<= 1)
346 if (! (mask & ex_info->valid))
347 break;
348
349 if (bytes)
350 {
351 int status;
352
353 pc += offset;
354 status = (*info->read_memory_func)
355 (pc, ex_info->insn_bytes + offset, bytes, info);
356
357 if (status != 0)
358 {
359 (*info->memory_error_func) (status, pc, info);
360 return 0;
361 }
362
363 ex_info->valid |= ((1 << bytes) - 1) << offset;
364 }
365
366 return 1;
367 }
368
369 /* Subroutine of extract_normal. */
370
371 static CGEN_INLINE long
372 extract_1 (cd, ex_info, start, length, word_length, bufp, pc)
373 CGEN_CPU_DESC cd;
374 CGEN_EXTRACT_INFO *ex_info;
375 int start,length,word_length;
376 unsigned char *bufp;
377 bfd_vma pc;
378 {
379 unsigned long x,mask;
380 int shift;
381 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
382
383 switch (word_length)
384 {
385 case 8:
386 x = *bufp;
387 break;
388 case 16:
389 if (big_p)
390 x = bfd_getb16 (bufp);
391 else
392 x = bfd_getl16 (bufp);
393 break;
394 case 24:
395 /* ??? This may need reworking as these cases don't necessarily
396 want the first byte and the last two bytes handled like this. */
397 if (big_p)
398 x = (bufp[0] << 16) | bfd_getb16 (bufp + 1);
399 else
400 x = bfd_getl16 (bufp) | (bufp[2] << 16);
401 break;
402 case 32:
403 if (big_p)
404 x = bfd_getb32 (bufp);
405 else
406 x = bfd_getl32 (bufp);
407 break;
408 default :
409 abort ();
410 }
411
412 /* Written this way to avoid undefined behaviour. */
413 mask = (((1L << (length - 1)) - 1) << 1) | 1;
414 if (CGEN_INSN_LSB0_P)
415 shift = (start + 1) - length;
416 else
417 shift = (word_length - (start + length));
418 return (x >> shift) & mask;
419 }
420
421 #endif /* ! CGEN_INT_INSN_P */
422
423 /* Default extraction routine.
424
425 INSN_VALUE is the first base_insn_bitsize bits of the insn in host order,
426 or sometimes less for cases like the m32r where the base insn size is 32
427 but some insns are 16 bits.
428 ATTRS is a mask of the boolean attributes. We only need `SIGNED',
429 but for generality we take a bitmask of all of them.
430 WORD_OFFSET is the offset in bits from the start of the insn of the value.
431 WORD_LENGTH is the length of the word in bits in which the value resides.
432 START is the starting bit number in the word, architecture origin.
433 LENGTH is the length of VALUE in bits.
434 TOTAL_LENGTH is the total length of the insn in bits.
435
436 Returns 1 for success, 0 for failure. */
437
438 /* ??? The return code isn't properly used. wip. */
439
440 /* ??? This doesn't handle bfd_vma's. Create another function when
441 necessary. */
442
443 static int
444 extract_normal (cd, ex_info, insn_value, attrs, word_offset, start, length,
445 word_length, total_length, pc, valuep)
446 CGEN_CPU_DESC cd;
447 #if ! CGEN_INT_INSN_P
448 CGEN_EXTRACT_INFO *ex_info;
449 #else
450 CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED;
451 #endif
452 CGEN_INSN_INT insn_value;
453 unsigned int attrs;
454 unsigned int word_offset, start, length, word_length, total_length;
455 #if ! CGEN_INT_INSN_P
456 bfd_vma pc;
457 #else
458 bfd_vma pc ATTRIBUTE_UNUSED;
459 #endif
460 long *valuep;
461 {
462 CGEN_INSN_INT value;
463
464 /* If LENGTH is zero, this operand doesn't contribute to the value
465 so give it a standard value of zero. */
466 if (length == 0)
467 {
468 *valuep = 0;
469 return 1;
470 }
471
472 if (CGEN_INT_INSN_P
473 && word_offset != 0)
474 abort ();
475
476 if (word_length > 32)
477 abort ();
478
479 /* For architectures with insns smaller than the insn-base-bitsize,
480 word_length may be too big. */
481 if (cd->min_insn_bitsize < cd->base_insn_bitsize)
482 {
483 if (word_offset == 0
484 && word_length > total_length)
485 word_length = total_length;
486 }
487
488 /* Does the value reside in INSN_VALUE? */
489
490 if (word_offset == 0)
491 {
492 /* Written this way to avoid undefined behaviour. */
493 CGEN_INSN_INT mask = (((1L << (length - 1)) - 1) << 1) | 1;
494
495 if (CGEN_INSN_LSB0_P)
496 value = insn_value >> ((start + 1) - length);
497 else
498 value = insn_value >> (word_length - (start + length));
499 value &= mask;
500 /* sign extend? */
501 if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
502 && (value & (1L << (length - 1))))
503 value |= ~mask;
504 }
505
506 #if ! CGEN_INT_INSN_P
507
508 else
509 {
510 unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
511
512 if (word_length > 32)
513 abort ();
514
515 if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
516 return 0;
517
518 value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
519 }
520
521 #endif /* ! CGEN_INT_INSN_P */
522
523 *valuep = value;
524
525 return 1;
526 }
527
528 /* Default insn extractor.
529
530 INSN_VALUE is the first base_insn_bitsize bits, translated to host order.
531 The extracted fields are stored in FIELDS.
532 EX_INFO is used to handle reading variable length insns.
533 Return the length of the insn in bits, or 0 if no match,
534 or -1 if an error occurs fetching data (memory_error_func will have
535 been called). */
536
537 static int
538 extract_insn_normal (cd, insn, ex_info, insn_value, fields, pc)
539 CGEN_CPU_DESC cd;
540 const CGEN_INSN *insn;
541 CGEN_EXTRACT_INFO *ex_info;
542 CGEN_INSN_INT insn_value;
543 CGEN_FIELDS *fields;
544 bfd_vma pc;
545 {
546 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
547 const unsigned char *syn;
548
549 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
550
551 CGEN_INIT_EXTRACT (cd);
552
553 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
554 {
555 int length;
556
557 if (CGEN_SYNTAX_CHAR_P (*syn))
558 continue;
559
560 length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
561 ex_info, insn_value, fields, pc);
562 if (length <= 0)
563 return length;
564 }
565
566 /* We recognized and successfully extracted this insn. */
567 return CGEN_INSN_BITSIZE (insn);
568 }
569 \f
570 /* machine generated code added here */
This page took 0.043273 seconds and 5 git commands to generate.