* Makefile.am: Update dependencies with "make dep-am".
[deliverable/binutils-gdb.git] / opcodes / cgen-ibld.in
CommitLineData
f6e6b40f
BE
1/* Instruction building/extraction support for @arch@. -*- C -*-
2
3THIS FILE IS MACHINE GENERATED WITH CGEN: Cpu tools GENerator.
4- the resultant file is machine generated, cgen-ibld.in isn't
5
060d22b0 6Copyright 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
f6e6b40f
BE
7
8This file is part of the GNU Binutils and GDB, the GNU debugger.
9
10This program is free software; you can redistribute it and/or modify
11it under the terms of the GNU General Public License as published by
12the Free Software Foundation; either version 2, or (at your option)
13any later version.
14
15This program is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software Foundation, Inc.,
2259 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
46static 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));
49static const char * insert_insn_normal
50 PARAMS ((CGEN_CPU_DESC, const CGEN_INSN *,
51 CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma));
52
53static 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 *));
57static int extract_insn_normal
58 PARAMS ((CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
59 CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma));
6bb95a0f
DB
60static void put_insn_int_value
61 PARAMS ((CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT));
62
f6e6b40f
BE
63\f
64/* Operand insertion. */
65
66#if ! CGEN_INT_INSN_P
67
68/* Subroutine of insert_normal. */
69
70static CGEN_INLINE void
71insert_1 (cd, value, start, length, word_length, bufp)
72 CGEN_CPU_DESC cd;
73 unsigned long value;
74 int start,length,word_length;
75 unsigned char *bufp;
76{
77 unsigned long x,mask;
78 int shift;
79 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
80
aed80dae 81 x = bfd_get_bits (bufp, word_length, big_p);
f6e6b40f
BE
82
83 /* Written this way to avoid undefined behaviour. */
84 mask = (((1L << (length - 1)) - 1) << 1) | 1;
85 if (CGEN_INSN_LSB0_P)
86 shift = (start + 1) - length;
87 else
88 shift = (word_length - (start + length));
89 x = (x & ~(mask << shift)) | ((value & mask) << shift);
90
aed80dae 91 bfd_put_bits ((bfd_vma) x, bufp, word_length, big_p);
f6e6b40f
BE
92}
93
94#endif /* ! CGEN_INT_INSN_P */
95
96/* Default insertion routine.
97
98 ATTRS is a mask of the boolean attributes.
99 WORD_OFFSET is the offset in bits from the start of the insn of the value.
100 WORD_LENGTH is the length of the word in bits in which the value resides.
101 START is the starting bit number in the word, architecture origin.
102 LENGTH is the length of VALUE in bits.
103 TOTAL_LENGTH is the total length of the insn in bits.
104
105 The result is an error message or NULL if success. */
106
107/* ??? This duplicates functionality with bfd's howto table and
108 bfd_install_relocation. */
109/* ??? This doesn't handle bfd_vma's. Create another function when
110 necessary. */
111
112static const char *
113insert_normal (cd, value, attrs, word_offset, start, length, word_length,
114 total_length, buffer)
115 CGEN_CPU_DESC cd;
116 long value;
117 unsigned int attrs;
118 unsigned int word_offset, start, length, word_length, total_length;
119 CGEN_INSN_BYTES_PTR buffer;
120{
121 static char errbuf[100];
122 /* Written this way to avoid undefined behaviour. */
123 unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
124
125 /* If LENGTH is zero, this operand doesn't contribute to the value. */
126 if (length == 0)
127 return NULL;
128
6bb95a0f 129#if 0
f6e6b40f
BE
130 if (CGEN_INT_INSN_P
131 && word_offset != 0)
132 abort ();
6bb95a0f 133#endif
f6e6b40f
BE
134
135 if (word_length > 32)
136 abort ();
137
138 /* For architectures with insns smaller than the base-insn-bitsize,
139 word_length may be too big. */
140 if (cd->min_insn_bitsize < cd->base_insn_bitsize)
141 {
142 if (word_offset == 0
143 && word_length > total_length)
144 word_length = total_length;
145 }
146
147 /* Ensure VALUE will fit. */
17f0ac84
GK
148 if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT))
149 {
150 long minval = - (1L << (length - 1));
151 unsigned long maxval = mask;
152
153 if ((value > 0 && (unsigned long) value > maxval)
154 || value < minval)
155 {
156 /* xgettext:c-format */
157 sprintf (errbuf,
158 _("operand out of range (%ld not between %ld and %lu)"),
159 value, minval, maxval);
160 return errbuf;
161 }
162 }
163 else if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
f6e6b40f
BE
164 {
165 unsigned long maxval = mask;
166
167 if ((unsigned long) value > maxval)
168 {
169 /* xgettext:c-format */
170 sprintf (errbuf,
171 _("operand out of range (%lu not between 0 and %lu)"),
172 value, maxval);
173 return errbuf;
174 }
175 }
176 else
177 {
178 if (! cgen_signed_overflow_ok_p (cd))
179 {
180 long minval = - (1L << (length - 1));
181 long maxval = (1L << (length - 1)) - 1;
182
183 if (value < minval || value > maxval)
184 {
185 sprintf
186 /* xgettext:c-format */
187 (errbuf, _("operand out of range (%ld not between %ld and %ld)"),
188 value, minval, maxval);
189 return errbuf;
190 }
191 }
192 }
193
194#if CGEN_INT_INSN_P
195
196 {
197 int shift;
198
199 if (CGEN_INSN_LSB0_P)
6bb95a0f 200 shift = (word_offset + start + 1) - length;
f6e6b40f 201 else
6bb95a0f 202 shift = total_length - (word_offset + start + length);
f6e6b40f
BE
203 *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
204 }
205
206#else /* ! CGEN_INT_INSN_P */
207
208 {
209 unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
210
211 insert_1 (cd, value, start, length, word_length, bufp);
212 }
213
214#endif /* ! CGEN_INT_INSN_P */
215
216 return NULL;
217}
218
219/* Default insn builder (insert handler).
0e70c820
BE
220 The instruction is recorded in CGEN_INT_INSN_P byte order (meaning
221 that if CGEN_INSN_BYTES_PTR is an int * and thus, the value is
222 recorded in host byte order, otherwise BUFFER is an array of bytes
223 and the value is recorded in target byte order).
f6e6b40f
BE
224 The result is an error message or NULL if success. */
225
226static const char *
227insert_insn_normal (cd, insn, fields, buffer, pc)
228 CGEN_CPU_DESC cd;
229 const CGEN_INSN * insn;
230 CGEN_FIELDS * fields;
231 CGEN_INSN_BYTES_PTR buffer;
232 bfd_vma pc;
233{
234 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
235 unsigned long value;
4a9f416d 236 const CGEN_SYNTAX_CHAR_TYPE * syn;
f6e6b40f
BE
237
238 CGEN_INIT_INSERT (cd);
239 value = CGEN_INSN_BASE_VALUE (insn);
240
241 /* If we're recording insns as numbers (rather than a string of bytes),
242 target byte order handling is deferred until later. */
243
244#if CGEN_INT_INSN_P
245
6bb95a0f
DB
246 put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
247 CGEN_FIELDS_BITSIZE (fields), value);
f6e6b40f
BE
248
249#else
250
251 cgen_put_insn_value (cd, buffer, min (cd->base_insn_bitsize,
252 CGEN_FIELDS_BITSIZE (fields)),
253 value);
254
255#endif /* ! CGEN_INT_INSN_P */
256
257 /* ??? It would be better to scan the format's fields.
258 Still need to be able to insert a value based on the operand though;
259 e.g. storing a branch displacement that got resolved later.
260 Needs more thought first. */
261
4a9f416d 262 for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
f6e6b40f
BE
263 {
264 const char *errmsg;
265
266 if (CGEN_SYNTAX_CHAR_P (* syn))
267 continue;
268
269 errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
270 fields, buffer, pc);
271 if (errmsg)
272 return errmsg;
273 }
274
275 return NULL;
276}
6bb95a0f
DB
277
278/* Cover function to store an insn value into an integral insn. Must go here
279 because it needs <prefix>-desc.h for CGEN_INT_INSN_P. */
280
281static void
282put_insn_int_value (cd, buf, length, insn_length, value)
fca2040b 283 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
6bb95a0f
DB
284 CGEN_INSN_BYTES_PTR buf;
285 int length;
286 int insn_length;
287 CGEN_INSN_INT value;
288{
289 /* For architectures with insns smaller than the base-insn-bitsize,
290 length may be too big. */
291 if (length > insn_length)
292 *buf = value;
293 else
294 {
295 int shift = insn_length - length;
296 /* Written this way to avoid undefined behaviour. */
297 CGEN_INSN_INT mask = (((1L << (length - 1)) - 1) << 1) | 1;
298 *buf = (*buf & ~(mask << shift)) | ((value & mask) << shift);
299 }
300}
f6e6b40f
BE
301\f
302/* Operand extraction. */
303
304#if ! CGEN_INT_INSN_P
305
306/* Subroutine of extract_normal.
307 Ensure sufficient bytes are cached in EX_INFO.
308 OFFSET is the offset in bytes from the start of the insn of the value.
309 BYTES is the length of the needed value.
310 Returns 1 for success, 0 for failure. */
311
312static CGEN_INLINE int
313fill_cache (cd, ex_info, offset, bytes, pc)
314 CGEN_CPU_DESC cd;
315 CGEN_EXTRACT_INFO *ex_info;
316 int offset, bytes;
317 bfd_vma pc;
318{
319 /* It's doubtful that the middle part has already been fetched so
320 we don't optimize that case. kiss. */
321 int mask;
322 disassemble_info *info = (disassemble_info *) ex_info->dis_info;
323
324 /* First do a quick check. */
325 mask = (1 << bytes) - 1;
326 if (((ex_info->valid >> offset) & mask) == mask)
327 return 1;
328
329 /* Search for the first byte we need to read. */
330 for (mask = 1 << offset; bytes > 0; --bytes, ++offset, mask <<= 1)
331 if (! (mask & ex_info->valid))
332 break;
333
334 if (bytes)
335 {
336 int status;
337
338 pc += offset;
339 status = (*info->read_memory_func)
340 (pc, ex_info->insn_bytes + offset, bytes, info);
341
342 if (status != 0)
343 {
344 (*info->memory_error_func) (status, pc, info);
345 return 0;
346 }
347
348 ex_info->valid |= ((1 << bytes) - 1) << offset;
349 }
350
351 return 1;
352}
353
354/* Subroutine of extract_normal. */
355
356static CGEN_INLINE long
357extract_1 (cd, ex_info, start, length, word_length, bufp, pc)
358 CGEN_CPU_DESC cd;
359 CGEN_EXTRACT_INFO *ex_info;
360 int start,length,word_length;
361 unsigned char *bufp;
362 bfd_vma pc;
363{
aed80dae 364 unsigned long x;
f6e6b40f
BE
365 int shift;
366 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
367
aed80dae 368 x = bfd_get_bits (bufp, word_length, big_p);
f6e6b40f 369
f6e6b40f
BE
370 if (CGEN_INSN_LSB0_P)
371 shift = (start + 1) - length;
372 else
373 shift = (word_length - (start + length));
aed80dae 374 return x >> shift;
f6e6b40f
BE
375}
376
377#endif /* ! CGEN_INT_INSN_P */
378
379/* Default extraction routine.
380
381 INSN_VALUE is the first base_insn_bitsize bits of the insn in host order,
382 or sometimes less for cases like the m32r where the base insn size is 32
383 but some insns are 16 bits.
384 ATTRS is a mask of the boolean attributes. We only need `SIGNED',
385 but for generality we take a bitmask of all of them.
386 WORD_OFFSET is the offset in bits from the start of the insn of the value.
387 WORD_LENGTH is the length of the word in bits in which the value resides.
388 START is the starting bit number in the word, architecture origin.
389 LENGTH is the length of VALUE in bits.
390 TOTAL_LENGTH is the total length of the insn in bits.
391
392 Returns 1 for success, 0 for failure. */
393
394/* ??? The return code isn't properly used. wip. */
395
396/* ??? This doesn't handle bfd_vma's. Create another function when
397 necessary. */
398
399static int
400extract_normal (cd, ex_info, insn_value, attrs, word_offset, start, length,
401 word_length, total_length, pc, valuep)
402 CGEN_CPU_DESC cd;
403#if ! CGEN_INT_INSN_P
404 CGEN_EXTRACT_INFO *ex_info;
405#else
406 CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED;
407#endif
408 CGEN_INSN_INT insn_value;
409 unsigned int attrs;
410 unsigned int word_offset, start, length, word_length, total_length;
411#if ! CGEN_INT_INSN_P
412 bfd_vma pc;
413#else
414 bfd_vma pc ATTRIBUTE_UNUSED;
415#endif
416 long *valuep;
417{
fc7bc883 418 long value, mask;
f6e6b40f
BE
419
420 /* If LENGTH is zero, this operand doesn't contribute to the value
421 so give it a standard value of zero. */
422 if (length == 0)
423 {
424 *valuep = 0;
425 return 1;
426 }
427
6bb95a0f 428#if 0
f6e6b40f
BE
429 if (CGEN_INT_INSN_P
430 && word_offset != 0)
431 abort ();
6bb95a0f 432#endif
f6e6b40f
BE
433
434 if (word_length > 32)
435 abort ();
436
437 /* For architectures with insns smaller than the insn-base-bitsize,
438 word_length may be too big. */
439 if (cd->min_insn_bitsize < cd->base_insn_bitsize)
440 {
441 if (word_offset == 0
442 && word_length > total_length)
443 word_length = total_length;
444 }
445
a00ad97d 446 /* Does the value reside in INSN_VALUE, and at the right alignment? */
f6e6b40f 447
a00ad97d 448 if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
f6e6b40f 449 {
f6e6b40f 450 if (CGEN_INSN_LSB0_P)
6bb95a0f 451 value = insn_value >> ((word_offset + start + 1) - length);
f6e6b40f 452 else
6bb95a0f 453 value = insn_value >> (total_length - ( word_offset + start + length));
f6e6b40f
BE
454 }
455
456#if ! CGEN_INT_INSN_P
457
458 else
459 {
460 unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
461
462 if (word_length > 32)
463 abort ();
464
465 if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
466 return 0;
467
468 value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
469 }
470
471#endif /* ! CGEN_INT_INSN_P */
472
aed80dae
FCE
473 /* Written this way to avoid undefined behaviour. */
474 mask = (((1L << (length - 1)) - 1) << 1) | 1;
475
476 value &= mask;
477 /* sign extend? */
478 if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
479 && (value & (1L << (length - 1))))
480 value |= ~mask;
481
f6e6b40f
BE
482 *valuep = value;
483
484 return 1;
485}
486
487/* Default insn extractor.
488
489 INSN_VALUE is the first base_insn_bitsize bits, translated to host order.
490 The extracted fields are stored in FIELDS.
491 EX_INFO is used to handle reading variable length insns.
492 Return the length of the insn in bits, or 0 if no match,
493 or -1 if an error occurs fetching data (memory_error_func will have
494 been called). */
495
496static int
497extract_insn_normal (cd, insn, ex_info, insn_value, fields, pc)
498 CGEN_CPU_DESC cd;
499 const CGEN_INSN *insn;
500 CGEN_EXTRACT_INFO *ex_info;
501 CGEN_INSN_INT insn_value;
502 CGEN_FIELDS *fields;
503 bfd_vma pc;
504{
505 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
4a9f416d 506 const CGEN_SYNTAX_CHAR_TYPE *syn;
f6e6b40f
BE
507
508 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
509
510 CGEN_INIT_EXTRACT (cd);
511
512 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
513 {
514 int length;
515
516 if (CGEN_SYNTAX_CHAR_P (*syn))
517 continue;
518
519 length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
520 ex_info, insn_value, fields, pc);
521 if (length <= 0)
522 return length;
523 }
524
525 /* We recognized and successfully extracted this insn. */
526 return CGEN_INSN_BITSIZE (insn);
527}
528\f
529/* machine generated code added here */
This page took 0.091623 seconds and 4 git commands to generate.