* bfd.c (struct bfd_preserve): New.
[binutils.git] / opcodes / cgen-ibld.in
blobd2bfd02a91f7029d3c17810e0e54633a916b4b27
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 Free Software Foundation, Inc.
8 This file is part of the GNU Binutils and GDB, the GNU debugger.
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.
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.
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.  */
24 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
25    Keep that in mind.  */
27 #include "sysdep.h"
28 #include <stdio.h>
29 #include "ansidecl.h"
30 #include "dis-asm.h"
31 #include "bfd.h"
32 #include "symcat.h"
33 #include "@prefix@-desc.h"
34 #include "@prefix@-opc.h"
35 #include "opintl.h"
36 #include "safe-ctype.h"
38 #undef min
39 #define min(a,b) ((a) < (b) ? (a) : (b))
40 #undef max
41 #define max(a,b) ((a) > (b) ? (a) : (b))
43 /* Used by the ifield rtx function.  */
44 #define FLD(f) (fields->f)
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 static int extract_normal
53      PARAMS ((CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_INT,
54               unsigned int, unsigned int, unsigned int, unsigned int,
55               unsigned int, unsigned int, bfd_vma, long *));
56 static int extract_insn_normal
57      PARAMS ((CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
58               CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma));
59 #if CGEN_INT_INSN_P
60 static void put_insn_int_value
61      PARAMS ((CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT));
62 #endif
63 #if ! CGEN_INT_INSN_P
64 static CGEN_INLINE void insert_1
65      PARAMS ((CGEN_CPU_DESC, unsigned long, int, int, int, unsigned char *));
66 static CGEN_INLINE int fill_cache
67      PARAMS ((CGEN_CPU_DESC, CGEN_EXTRACT_INFO *,  int, int, bfd_vma));
68 static CGEN_INLINE long extract_1
69      PARAMS ((CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, int,
70               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 (cd, value, start, length, word_length, bufp)
81      CGEN_CPU_DESC cd;
82      unsigned long value;
83      int start,length,word_length;
84      unsigned char *bufp;
86   unsigned long x,mask;
87   int shift;
89   x = cgen_get_insn_value (cd, bufp, word_length);
91   /* Written this way to avoid undefined behaviour.  */
92   mask = (((1L << (length - 1)) - 1) << 1) | 1;
93   if (CGEN_INSN_LSB0_P)
94     shift = (start + 1) - length;
95   else
96     shift = (word_length - (start + length));
97   x = (x & ~(mask << shift)) | ((value & mask) << shift);
99   cgen_put_insn_value (cd, bufp, word_length, (bfd_vma) x);
102 #endif /* ! CGEN_INT_INSN_P */
104 /* Default insertion routine.
106    ATTRS is a mask of the boolean attributes.
107    WORD_OFFSET is the offset in bits from the start of the insn of the value.
108    WORD_LENGTH is the length of the word in bits in which the value resides.
109    START is the starting bit number in the word, architecture origin.
110    LENGTH is the length of VALUE in bits.
111    TOTAL_LENGTH is the total length of the insn in bits.
113    The result is an error message or NULL if success.  */
115 /* ??? This duplicates functionality with bfd's howto table and
116    bfd_install_relocation.  */
117 /* ??? This doesn't handle bfd_vma's.  Create another function when
118    necessary.  */
120 static const char *
121 insert_normal (cd, value, attrs, word_offset, start, length, word_length,
122                total_length, buffer)
123      CGEN_CPU_DESC cd;
124      long value;
125      unsigned int attrs;
126      unsigned int word_offset, start, length, word_length, total_length;
127      CGEN_INSN_BYTES_PTR buffer;
129   static char errbuf[100];
130   /* Written this way to avoid undefined behaviour.  */
131   unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
133   /* If LENGTH is zero, this operand doesn't contribute to the value.  */
134   if (length == 0)
135     return NULL;
137 #if 0
138   if (CGEN_INT_INSN_P
139       && word_offset != 0)
140     abort ();
141 #endif
143   if (word_length > 32)
144     abort ();
146   /* For architectures with insns smaller than the base-insn-bitsize,
147      word_length may be too big.  */
148   if (cd->min_insn_bitsize < cd->base_insn_bitsize)
149     {
150       if (word_offset == 0
151           && word_length > total_length)
152         word_length = total_length;
153     }
155   /* Ensure VALUE will fit.  */
156   if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT))
157     {
158       long minval = - (1L << (length - 1));
159       unsigned long maxval = mask;
160       
161       if ((value > 0 && (unsigned long) value > maxval)
162           || value < minval)
163         {
164           /* xgettext:c-format */
165           sprintf (errbuf,
166                    _("operand out of range (%ld not between %ld and %lu)"),
167                    value, minval, maxval);
168           return errbuf;
169         }
170     }
171   else if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
172     {
173       unsigned long maxval = mask;
174       
175       if ((unsigned long) value > maxval)
176         {
177           /* xgettext:c-format */
178           sprintf (errbuf,
179                    _("operand out of range (%lu not between 0 and %lu)"),
180                    value, maxval);
181           return errbuf;
182         }
183     }
184   else
185     {
186       if (! cgen_signed_overflow_ok_p (cd))
187         {
188           long minval = - (1L << (length - 1));
189           long maxval =   (1L << (length - 1)) - 1;
190           
191           if (value < minval || value > maxval)
192             {
193               sprintf
194                 /* xgettext:c-format */
195                 (errbuf, _("operand out of range (%ld not between %ld and %ld)"),
196                  value, minval, maxval);
197               return errbuf;
198             }
199         }
200     }
202 #if CGEN_INT_INSN_P
204   {
205     int shift;
207     if (CGEN_INSN_LSB0_P)
208       shift = (word_offset + start + 1) - length;
209     else
210       shift = total_length - (word_offset + start + length);
211     *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
212   }
214 #else /* ! CGEN_INT_INSN_P */
216   {
217     unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
219     insert_1 (cd, value, start, length, word_length, bufp);
220   }
222 #endif /* ! CGEN_INT_INSN_P */
224   return NULL;
227 /* Default insn builder (insert handler).
228    The instruction is recorded in CGEN_INT_INSN_P byte order (meaning
229    that if CGEN_INSN_BYTES_PTR is an int * and thus, the value is
230    recorded in host byte order, otherwise BUFFER is an array of bytes
231    and the value is recorded in target byte order).
232    The result is an error message or NULL if success.  */
234 static const char *
235 insert_insn_normal (cd, insn, fields, buffer, pc)
236      CGEN_CPU_DESC cd;
237      const CGEN_INSN * insn;
238      CGEN_FIELDS * fields;
239      CGEN_INSN_BYTES_PTR buffer;
240      bfd_vma pc;
242   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
243   unsigned long value;
244   const CGEN_SYNTAX_CHAR_TYPE * syn;
246   CGEN_INIT_INSERT (cd);
247   value = CGEN_INSN_BASE_VALUE (insn);
249   /* If we're recording insns as numbers (rather than a string of bytes),
250      target byte order handling is deferred until later.  */
252 #if CGEN_INT_INSN_P
254   put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
255                       CGEN_FIELDS_BITSIZE (fields), value);
257 #else
259   cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize,
260                                         (unsigned) CGEN_FIELDS_BITSIZE (fields)),
261                        value);
263 #endif /* ! CGEN_INT_INSN_P */
265   /* ??? It would be better to scan the format's fields.
266      Still need to be able to insert a value based on the operand though;
267      e.g. storing a branch displacement that got resolved later.
268      Needs more thought first.  */
270   for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
271     {
272       const char *errmsg;
274       if (CGEN_SYNTAX_CHAR_P (* syn))
275         continue;
277       errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
278                                        fields, buffer, pc);
279       if (errmsg)
280         return errmsg;
281     }
283   return NULL;
286 #if CGEN_INT_INSN_P
287 /* Cover function to store an insn value into an integral insn.  Must go here
288  because it needs <prefix>-desc.h for CGEN_INT_INSN_P.  */
290 static void
291 put_insn_int_value (cd, buf, length, insn_length, value)
292      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
293      CGEN_INSN_BYTES_PTR buf;
294      int length;
295      int insn_length;
296      CGEN_INSN_INT value;
298   /* For architectures with insns smaller than the base-insn-bitsize,
299      length may be too big.  */
300   if (length > insn_length)
301     *buf = value;
302   else
303     {
304       int shift = insn_length - length;
305       /* Written this way to avoid undefined behaviour.  */
306       CGEN_INSN_INT mask = (((1L << (length - 1)) - 1) << 1) | 1;
307       *buf = (*buf & ~(mask << shift)) | ((value & mask) << shift);
308     }
310 #endif
312 /* Operand extraction.  */
314 #if ! CGEN_INT_INSN_P
316 /* Subroutine of extract_normal.
317    Ensure sufficient bytes are cached in EX_INFO.
318    OFFSET is the offset in bytes from the start of the insn of the value.
319    BYTES is the length of the needed value.
320    Returns 1 for success, 0 for failure.  */
322 static CGEN_INLINE int
323 fill_cache (cd, ex_info, offset, bytes, pc)
324      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
325      CGEN_EXTRACT_INFO *ex_info;
326      int offset, bytes;
327      bfd_vma pc;
329   /* It's doubtful that the middle part has already been fetched so
330      we don't optimize that case.  kiss.  */
331   unsigned int mask;
332   disassemble_info *info = (disassemble_info *) ex_info->dis_info;
334   /* First do a quick check.  */
335   mask = (1 << bytes) - 1;
336   if (((ex_info->valid >> offset) & mask) == mask)
337     return 1;
339   /* Search for the first byte we need to read.  */
340   for (mask = 1 << offset; bytes > 0; --bytes, ++offset, mask <<= 1)
341     if (! (mask & ex_info->valid))
342       break;
344   if (bytes)
345     {
346       int status;
348       pc += offset;
349       status = (*info->read_memory_func)
350         (pc, ex_info->insn_bytes + offset, bytes, info);
352       if (status != 0)
353         {
354           (*info->memory_error_func) (status, pc, info);
355           return 0;
356         }
358       ex_info->valid |= ((1 << bytes) - 1) << offset;
359     }
361   return 1;
364 /* Subroutine of extract_normal.  */
366 static CGEN_INLINE long
367 extract_1 (cd, ex_info, start, length, word_length, bufp, pc)
368      CGEN_CPU_DESC cd;
369      CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED;
370      int start,length,word_length;
371      unsigned char *bufp;
372      bfd_vma pc ATTRIBUTE_UNUSED;
374   unsigned long x;
375   int shift;
376 #if 0
377   int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
378 #endif
379   x = cgen_get_insn_value (cd, bufp, word_length);
381   if (CGEN_INSN_LSB0_P)
382     shift = (start + 1) - length;
383   else
384     shift = (word_length - (start + length));
385   return x >> shift;
388 #endif /* ! CGEN_INT_INSN_P */
390 /* Default extraction routine.
392    INSN_VALUE is the first base_insn_bitsize bits of the insn in host order,
393    or sometimes less for cases like the m32r where the base insn size is 32
394    but some insns are 16 bits.
395    ATTRS is a mask of the boolean attributes.  We only need `SIGNED',
396    but for generality we take a bitmask of all of them.
397    WORD_OFFSET is the offset in bits from the start of the insn of the value.
398    WORD_LENGTH is the length of the word in bits in which the value resides.
399    START is the starting bit number in the word, architecture origin.
400    LENGTH is the length of VALUE in bits.
401    TOTAL_LENGTH is the total length of the insn in bits.
403    Returns 1 for success, 0 for failure.  */
405 /* ??? The return code isn't properly used.  wip.  */
407 /* ??? This doesn't handle bfd_vma's.  Create another function when
408    necessary.  */
410 static int
411 extract_normal (cd, ex_info, insn_value, attrs, word_offset, start, length,
412                 word_length, total_length, pc, valuep)
413      CGEN_CPU_DESC cd;
414 #if ! CGEN_INT_INSN_P
415      CGEN_EXTRACT_INFO *ex_info;
416 #else
417      CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED;
418 #endif
419      CGEN_INSN_INT insn_value;
420      unsigned int attrs;
421      unsigned int word_offset, start, length, word_length, total_length;
422 #if ! CGEN_INT_INSN_P
423      bfd_vma pc;
424 #else
425      bfd_vma pc ATTRIBUTE_UNUSED;
426 #endif
427      long *valuep;
429   long value, mask;
431   /* If LENGTH is zero, this operand doesn't contribute to the value
432      so give it a standard value of zero.  */
433   if (length == 0)
434     {
435       *valuep = 0;
436       return 1;
437     }
439 #if 0
440   if (CGEN_INT_INSN_P
441       && word_offset != 0)
442     abort ();
443 #endif
445   if (word_length > 32)
446     abort ();
448   /* For architectures with insns smaller than the insn-base-bitsize,
449      word_length may be too big.  */
450   if (cd->min_insn_bitsize < cd->base_insn_bitsize)
451     {
452       if (word_offset == 0
453           && word_length > total_length)
454         word_length = total_length;
455     }
457   /* Does the value reside in INSN_VALUE, and at the right alignment?  */
459   if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
460     {
461       if (CGEN_INSN_LSB0_P)
462         value = insn_value >> ((word_offset + start + 1) - length);
463       else
464         value = insn_value >> (total_length - ( word_offset + start + length));
465     }
467 #if ! CGEN_INT_INSN_P
469   else
470     {
471       unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
473       if (word_length > 32)
474         abort ();
476       if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
477         return 0;
479       value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
480     }
482 #endif /* ! CGEN_INT_INSN_P */
484   /* Written this way to avoid undefined behaviour.  */
485   mask = (((1L << (length - 1)) - 1) << 1) | 1;
487   value &= mask;
488   /* sign extend? */
489   if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
490       && (value & (1L << (length - 1))))
491     value |= ~mask;
493   *valuep = value;
495   return 1;
498 /* Default insn extractor.
500    INSN_VALUE is the first base_insn_bitsize bits, translated to host order.
501    The extracted fields are stored in FIELDS.
502    EX_INFO is used to handle reading variable length insns.
503    Return the length of the insn in bits, or 0 if no match,
504    or -1 if an error occurs fetching data (memory_error_func will have
505    been called).  */
507 static int
508 extract_insn_normal (cd, insn, ex_info, insn_value, fields, pc)
509      CGEN_CPU_DESC cd;
510      const CGEN_INSN *insn;
511      CGEN_EXTRACT_INFO *ex_info;
512      CGEN_INSN_INT insn_value;
513      CGEN_FIELDS *fields;
514      bfd_vma pc;
516   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
517   const CGEN_SYNTAX_CHAR_TYPE *syn;
519   CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
521   CGEN_INIT_EXTRACT (cd);
523   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
524     {
525       int length;
527       if (CGEN_SYNTAX_CHAR_P (*syn))
528         continue;
530       length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
531                                         ex_info, insn_value, fields, pc);
532       if (length <= 0)
533         return length;
534     }
536   /* We recognized and successfully extracted this insn.  */
537   return CGEN_INSN_BITSIZE (insn);
540 /* machine generated code added here */