daily update
[binutils.git] / opcodes / cgen-ibld.in
blob75506cdfc7aeaae14aac7f0d1f3e87bec09fe803
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
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)
14    any later version.
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.
26    Keep that in mind.  */
28 #include "sysdep.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 #include "safe-ctype.h"
39 #undef  min
40 #define min(a,b) ((a) < (b) ? (a) : (b))
41 #undef  max
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);
60 #if CGEN_INT_INSN_P
61 static void put_insn_int_value
62   (CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT);
63 #endif
64 #if ! CGEN_INT_INSN_P
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);
71 #endif
73 /* Operand insertion.  */
75 #if ! CGEN_INT_INSN_P
77 /* Subroutine of insert_normal.  */
79 static CGEN_INLINE void
80 insert_1 (CGEN_CPU_DESC cd,
81           unsigned long value,
82           int start,
83           int length,
84           int word_length,
85           unsigned char *bufp)
87   unsigned long x,mask;
88   int shift;
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;
94   if (CGEN_INSN_LSB0_P)
95     shift = (start + 1) - length;
96   else
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
119    necessary.  */
121 static const char *
122 insert_normal (CGEN_CPU_DESC cd,
123                long value,
124                unsigned int attrs,
125                unsigned int word_offset,
126                unsigned int start,
127                unsigned int length,
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.  */
137   if (length == 0)
138     return NULL;
140   if (word_length > 32)
141     abort ();
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)
146     {
147       if (word_offset == 0
148           && word_length > total_length)
149         word_length = total_length;
150     }
152   /* Ensure VALUE will fit.  */
153   if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT))
154     {
155       long minval = - (1L << (length - 1));
156       unsigned long maxval = mask;
157       
158       if ((value > 0 && (unsigned long) value > maxval)
159           || value < minval)
160         {
161           /* xgettext:c-format */
162           sprintf (errbuf,
163                    _("operand out of range (%ld not between %ld and %lu)"),
164                    value, minval, maxval);
165           return errbuf;
166         }
167     }
168   else if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
169     {
170       unsigned long maxval = mask;
171       
172       if ((unsigned long) value > maxval)
173         {
174           /* xgettext:c-format */
175           sprintf (errbuf,
176                    _("operand out of range (%lu not between 0 and %lu)"),
177                    value, maxval);
178           return errbuf;
179         }
180     }
181   else
182     {
183       if (! cgen_signed_overflow_ok_p (cd))
184         {
185           long minval = - (1L << (length - 1));
186           long maxval =   (1L << (length - 1)) - 1;
187           
188           if (value < minval || value > maxval)
189             {
190               sprintf
191                 /* xgettext:c-format */
192                 (errbuf, _("operand out of range (%ld not between %ld and %ld)"),
193                  value, minval, maxval);
194               return errbuf;
195             }
196         }
197     }
199 #if CGEN_INT_INSN_P
201   {
202     int shift;
204     if (CGEN_INSN_LSB0_P)
205       shift = (word_offset + start + 1) - length;
206     else
207       shift = total_length - (word_offset + start + length);
208     *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
209   }
211 #else /* ! CGEN_INT_INSN_P */
213   {
214     unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
216     insert_1 (cd, value, start, length, word_length, bufp);
217   }
219 #endif /* ! CGEN_INT_INSN_P */
221   return NULL;
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.  */
231 static const char *
232 insert_insn_normal (CGEN_CPU_DESC cd,
233                     const CGEN_INSN * insn,
234                     CGEN_FIELDS * fields,
235                     CGEN_INSN_BYTES_PTR buffer,
236                     bfd_vma pc)
238   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
239   unsigned long value;
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.  */
248 #if CGEN_INT_INSN_P
250   put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
251                       CGEN_FIELDS_BITSIZE (fields), value);
253 #else
255   cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize,
256                                         (unsigned) CGEN_FIELDS_BITSIZE (fields)),
257                        value);
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)
267     {
268       const char *errmsg;
270       if (CGEN_SYNTAX_CHAR_P (* syn))
271         continue;
273       errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
274                                        fields, buffer, pc);
275       if (errmsg)
276         return errmsg;
277     }
279   return NULL;
282 #if CGEN_INT_INSN_P
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.  */
286 static void
287 put_insn_int_value (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
288                     CGEN_INSN_BYTES_PTR buf,
289                     int length,
290                     int insn_length,
291                     CGEN_INSN_INT value)
293   /* For architectures with insns smaller than the base-insn-bitsize,
294      length may be too big.  */
295   if (length > insn_length)
296     *buf = value;
297   else
298     {
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);
304     }
306 #endif
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,
321             int offset,
322             int bytes,
323             bfd_vma pc)
325   /* It's doubtful that the middle part has already been fetched so
326      we don't optimize that case.  kiss.  */
327   unsigned int mask;
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)
333     return 1;
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))
338       break;
340   if (bytes)
341     {
342       int status;
344       pc += offset;
345       status = (*info->read_memory_func)
346         (pc, ex_info->insn_bytes + offset, bytes, info);
348       if (status != 0)
349         {
350           (*info->memory_error_func) (status, pc, info);
351           return 0;
352         }
354       ex_info->valid |= ((1 << bytes) - 1) << offset;
355     }
357   return 1;
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,
365            int start,
366            int length,
367            int word_length,
368            unsigned char *bufp,
369            bfd_vma pc ATTRIBUTE_UNUSED)
371   unsigned long x;
372   int shift;
374   x = cgen_get_insn_value (cd, bufp, word_length);
376   if (CGEN_INSN_LSB0_P)
377     shift = (start + 1) - length;
378   else
379     shift = (word_length - (start + length));
380   return x >> shift;
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
403    necessary.  */
405 static int
406 extract_normal (CGEN_CPU_DESC cd,
407 #if ! CGEN_INT_INSN_P
408                 CGEN_EXTRACT_INFO *ex_info,
409 #else
410                 CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
411 #endif
412                 CGEN_INSN_INT insn_value,
413                 unsigned int attrs,
414                 unsigned int word_offset,
415                 unsigned int start,
416                 unsigned int length,
417                 unsigned int word_length,
418                 unsigned int total_length,
419 #if ! CGEN_INT_INSN_P
420                 bfd_vma pc,
421 #else
422                 bfd_vma pc ATTRIBUTE_UNUSED,
423 #endif
424                 long *valuep)
426   long value, mask;
428   /* If LENGTH is zero, this operand doesn't contribute to the value
429      so give it a standard value of zero.  */
430   if (length == 0)
431     {
432       *valuep = 0;
433       return 1;
434     }
436   if (word_length > 32)
437     abort ();
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)
442     {
443       if (word_offset == 0
444           && word_length > total_length)
445         word_length = total_length;
446     }
448   /* Does the value reside in INSN_VALUE, and at the right alignment?  */
450   if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
451     {
452       if (CGEN_INSN_LSB0_P)
453         value = insn_value >> ((word_offset + start + 1) - length);
454       else
455         value = insn_value >> (total_length - ( word_offset + start + length));
456     }
458 #if ! CGEN_INT_INSN_P
460   else
461     {
462       unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
464       if (word_length > 32)
465         abort ();
467       if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
468         return 0;
470       value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
471     }
473 #endif /* ! CGEN_INT_INSN_P */
475   /* Written this way to avoid undefined behaviour.  */
476   mask = (((1L << (length - 1)) - 1) << 1) | 1;
478   value &= mask;
479   /* sign extend? */
480   if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
481       && (value & (1L << (length - 1))))
482     value |= ~mask;
484   *valuep = value;
486   return 1;
489 /* Default insn extractor.
491    INSN_VALUE is the first base_insn_bitsize bits, translated to host order.
492    The extracted fields are stored in FIELDS.
493    EX_INFO is used to handle reading variable length insns.
494    Return the length of the insn in bits, or 0 if no match,
495    or -1 if an error occurs fetching data (memory_error_func will have
496    been called).  */
498 static int
499 extract_insn_normal (CGEN_CPU_DESC cd,
500                      const CGEN_INSN *insn,
501                      CGEN_EXTRACT_INFO *ex_info,
502                      CGEN_INSN_INT insn_value,
503                      CGEN_FIELDS *fields,
504                      bfd_vma pc)
506   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
507   const CGEN_SYNTAX_CHAR_TYPE *syn;
509   CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
511   CGEN_INIT_EXTRACT (cd);
513   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
514     {
515       int length;
517       if (CGEN_SYNTAX_CHAR_P (*syn))
518         continue;
520       length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
521                                         ex_info, insn_value, fields, pc);
522       if (length <= 0)
523         return length;
524     }
526   /* We recognized and successfully extracted this insn.  */
527   return CGEN_INSN_BITSIZE (insn);
530 /* Machine generated code added here.  */