1 /* Instruction building/extraction support for @arch@. -*- C -*-
3 THIS FILE IS MACHINE GENERATED WITH CGEN: Cpu tools GENerator.
4 - the resultant file is machine generated, cgen-ibld.in isn't
6 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2005, 2006
7 Free Software Foundation, Inc.
9 This file is part of the GNU Binutils and GDB, the GNU debugger.
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
25 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
34 #include "@prefix@-desc.h"
35 #include "@prefix@-opc.h"
37 #include "safe-ctype.h"
40 #define min(a,b) ((a) < (b) ? (a) : (b))
42 #define max(a,b) ((a) > (b) ? (a) : (b))
44 /* Used by the ifield rtx function. */
45 #define FLD(f) (fields->f)
47 static const char * insert_normal
48 (CGEN_CPU_DESC, long, unsigned int, unsigned int, unsigned int,
49 unsigned int, unsigned int, unsigned int, CGEN_INSN_BYTES_PTR);
50 static const char * insert_insn_normal
51 (CGEN_CPU_DESC, const CGEN_INSN *,
52 CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma);
53 static int extract_normal
54 (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 (CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
59 CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma);
61 static void put_insn_int_value
62 (CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT);
65 static CGEN_INLINE void insert_1
66 (CGEN_CPU_DESC, unsigned long, int, int, int, unsigned char *);
67 static CGEN_INLINE int fill_cache
68 (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, bfd_vma);
69 static CGEN_INLINE long extract_1
70 (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, int, unsigned char *, bfd_vma);
73 /* Operand insertion. */
77 /* Subroutine of insert_normal. */
79 static CGEN_INLINE void
80 insert_1 (CGEN_CPU_DESC cd,
90 x = cgen_get_insn_value (cd, bufp, word_length);
92 /* Written this way to avoid undefined behaviour. */
93 mask = (((1L << (length - 1)) - 1) << 1) | 1;
95 shift = (start + 1) - length;
97 shift = (word_length - (start + length));
98 x = (x & ~(mask << shift)) | ((value & mask) << shift);
100 cgen_put_insn_value (cd, bufp, word_length, (bfd_vma) x);
103 #endif /* ! CGEN_INT_INSN_P */
105 /* Default insertion routine.
107 ATTRS is a mask of the boolean attributes.
108 WORD_OFFSET is the offset in bits from the start of the insn of the value.
109 WORD_LENGTH is the length of the word in bits in which the value resides.
110 START is the starting bit number in the word, architecture origin.
111 LENGTH is the length of VALUE in bits.
112 TOTAL_LENGTH is the total length of the insn in bits.
114 The result is an error message or NULL if success. */
116 /* ??? This duplicates functionality with bfd's howto table and
117 bfd_install_relocation. */
118 /* ??? This doesn't handle bfd_vma's. Create another function when
122 insert_normal (CGEN_CPU_DESC cd,
125 unsigned int word_offset,
128 unsigned int word_length,
129 unsigned int total_length,
130 CGEN_INSN_BYTES_PTR buffer)
132 static char errbuf[100];
133 /* Written this way to avoid undefined behaviour. */
134 unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
136 /* If LENGTH is zero, this operand doesn't contribute to the value. */
140 if (word_length > 32)
143 /* For architectures with insns smaller than the base-insn-bitsize,
144 word_length may be too big. */
145 if (cd->min_insn_bitsize < cd->base_insn_bitsize)
148 && word_length > total_length)
149 word_length = total_length;
152 /* Ensure VALUE will fit. */
153 if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT))
155 long minval = - (1L << (length - 1));
156 unsigned long maxval = mask;
158 if ((value > 0 && (unsigned long) value > maxval)
161 /* xgettext:c-format */
163 _("operand out of range (%ld not between %ld and %lu)"),
164 value, minval, maxval);
168 else if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
170 unsigned long maxval = mask;
172 if ((unsigned long) value > maxval)
174 /* xgettext:c-format */
176 _("operand out of range (%lu not between 0 and %lu)"),
183 if (! cgen_signed_overflow_ok_p (cd))
185 long minval = - (1L << (length - 1));
186 long maxval = (1L << (length - 1)) - 1;
188 if (value < minval || value > maxval)
191 /* xgettext:c-format */
192 (errbuf, _("operand out of range (%ld not between %ld and %ld)"),
193 value, minval, maxval);
204 if (CGEN_INSN_LSB0_P)
205 shift = (word_offset + start + 1) - length;
207 shift = total_length - (word_offset + start + length);
208 *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
211 #else /* ! CGEN_INT_INSN_P */
214 unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
216 insert_1 (cd, value, start, length, word_length, bufp);
219 #endif /* ! CGEN_INT_INSN_P */
224 /* Default insn builder (insert handler).
225 The instruction is recorded in CGEN_INT_INSN_P byte order (meaning
226 that if CGEN_INSN_BYTES_PTR is an int * and thus, the value is
227 recorded in host byte order, otherwise BUFFER is an array of bytes
228 and the value is recorded in target byte order).
229 The result is an error message or NULL if success. */
232 insert_insn_normal (CGEN_CPU_DESC cd,
233 const CGEN_INSN * insn,
234 CGEN_FIELDS * fields,
235 CGEN_INSN_BYTES_PTR buffer,
238 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
240 const CGEN_SYNTAX_CHAR_TYPE * syn;
242 CGEN_INIT_INSERT (cd);
243 value = CGEN_INSN_BASE_VALUE (insn);
245 /* If we're recording insns as numbers (rather than a string of bytes),
246 target byte order handling is deferred until later. */
250 put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
251 CGEN_FIELDS_BITSIZE (fields), value);
255 cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize,
256 (unsigned) CGEN_FIELDS_BITSIZE (fields)),
259 #endif /* ! CGEN_INT_INSN_P */
261 /* ??? It would be better to scan the format's fields.
262 Still need to be able to insert a value based on the operand though;
263 e.g. storing a branch displacement that got resolved later.
264 Needs more thought first. */
266 for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
270 if (CGEN_SYNTAX_CHAR_P (* syn))
273 errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
283 /* Cover function to store an insn value into an integral insn. Must go here
284 because it needs <prefix>-desc.h for CGEN_INT_INSN_P. */
287 put_insn_int_value (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
288 CGEN_INSN_BYTES_PTR buf,
293 /* For architectures with insns smaller than the base-insn-bitsize,
294 length may be too big. */
295 if (length > insn_length)
299 int shift = insn_length - length;
300 /* Written this way to avoid undefined behaviour. */
301 CGEN_INSN_INT mask = (((1L << (length - 1)) - 1) << 1) | 1;
303 *buf = (*buf & ~(mask << shift)) | ((value & mask) << shift);
308 /* Operand extraction. */
310 #if ! CGEN_INT_INSN_P
312 /* Subroutine of extract_normal.
313 Ensure sufficient bytes are cached in EX_INFO.
314 OFFSET is the offset in bytes from the start of the insn of the value.
315 BYTES is the length of the needed value.
316 Returns 1 for success, 0 for failure. */
318 static CGEN_INLINE int
319 fill_cache (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
320 CGEN_EXTRACT_INFO *ex_info,
325 /* It's doubtful that the middle part has already been fetched so
326 we don't optimize that case. kiss. */
328 disassemble_info *info = (disassemble_info *) ex_info->dis_info;
330 /* First do a quick check. */
331 mask = (1 << bytes) - 1;
332 if (((ex_info->valid >> offset) & mask) == mask)
335 /* Search for the first byte we need to read. */
336 for (mask = 1 << offset; bytes > 0; --bytes, ++offset, mask <<= 1)
337 if (! (mask & ex_info->valid))
345 status = (*info->read_memory_func)
346 (pc, ex_info->insn_bytes + offset, bytes, info);
350 (*info->memory_error_func) (status, pc, info);
354 ex_info->valid |= ((1 << bytes) - 1) << offset;
360 /* Subroutine of extract_normal. */
362 static CGEN_INLINE long
363 extract_1 (CGEN_CPU_DESC cd,
364 CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
369 bfd_vma pc ATTRIBUTE_UNUSED)
374 x = cgen_get_insn_value (cd, bufp, word_length);
376 if (CGEN_INSN_LSB0_P)
377 shift = (start + 1) - length;
379 shift = (word_length - (start + length));
383 #endif /* ! CGEN_INT_INSN_P */
385 /* Default extraction routine.
387 INSN_VALUE is the first base_insn_bitsize bits of the insn in host order,
388 or sometimes less for cases like the m32r where the base insn size is 32
389 but some insns are 16 bits.
390 ATTRS is a mask of the boolean attributes. We only need `SIGNED',
391 but for generality we take a bitmask of all of them.
392 WORD_OFFSET is the offset in bits from the start of the insn of the value.
393 WORD_LENGTH is the length of the word in bits in which the value resides.
394 START is the starting bit number in the word, architecture origin.
395 LENGTH is the length of VALUE in bits.
396 TOTAL_LENGTH is the total length of the insn in bits.
398 Returns 1 for success, 0 for failure. */
400 /* ??? The return code isn't properly used. wip. */
402 /* ??? This doesn't handle bfd_vma's. Create another function when
406 extract_normal (CGEN_CPU_DESC cd,
407 #if ! CGEN_INT_INSN_P
408 CGEN_EXTRACT_INFO *ex_info,
410 CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
412 CGEN_INSN_INT insn_value,
414 unsigned int word_offset,
417 unsigned int word_length,
418 unsigned int total_length,
419 #if ! CGEN_INT_INSN_P
422 bfd_vma pc ATTRIBUTE_UNUSED,
428 /* If LENGTH is zero, this operand doesn't contribute to the value
429 so give it a standard value of zero. */
436 if (word_length > 32)
439 /* For architectures with insns smaller than the insn-base-bitsize,
440 word_length may be too big. */
441 if (cd->min_insn_bitsize < cd->base_insn_bitsize)
443 if (word_offset + word_length > total_length)
444 word_length = total_length - word_offset;
447 /* Does the value reside in INSN_VALUE, and at the right alignment? */
449 if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
451 if (CGEN_INSN_LSB0_P)
452 value = insn_value >> ((word_offset + start + 1) - length);
454 value = insn_value >> (total_length - ( word_offset + start + length));
457 #if ! CGEN_INT_INSN_P
461 unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
463 if (word_length > 32)
466 if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
469 value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
472 #endif /* ! CGEN_INT_INSN_P */
474 /* Written this way to avoid undefined behaviour. */
475 mask = (((1L << (length - 1)) - 1) << 1) | 1;
479 if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
480 && (value & (1L << (length - 1))))
488 /* Default insn extractor.
490 INSN_VALUE is the first base_insn_bitsize bits, translated to host order.
491 The extracted fields are stored in FIELDS.
492 EX_INFO is used to handle reading variable length insns.
493 Return the length of the insn in bits, or 0 if no match,
494 or -1 if an error occurs fetching data (memory_error_func will have
498 extract_insn_normal (CGEN_CPU_DESC cd,
499 const CGEN_INSN *insn,
500 CGEN_EXTRACT_INFO *ex_info,
501 CGEN_INSN_INT insn_value,
505 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
506 const CGEN_SYNTAX_CHAR_TYPE *syn;
508 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
510 CGEN_INIT_EXTRACT (cd);
512 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
516 if (CGEN_SYNTAX_CHAR_P (*syn))
519 length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
520 ex_info, insn_value, fields, pc);
525 /* We recognized and successfully extracted this insn. */
526 return CGEN_INSN_BITSIZE (insn);
529 /* Machine generated code added here. */