2004-04-21 Andrew Cagney <cagney@redhat.com>
[binutils.git] / opcodes / cgen-ibld.in
blob316f183c41e49acb1f40a245346e38f99409c246
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   (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   (CGEN_CPU_DESC, const CGEN_INSN *,
51    CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma);
52 static int extract_normal
53   (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   (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   (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   (CGEN_CPU_DESC, unsigned long, int, int, int, unsigned char *);
66 static CGEN_INLINE int fill_cache
67   (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *,  int, int, bfd_vma);
68 static CGEN_INLINE long extract_1
69   (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, int, unsigned char *, bfd_vma);
70 #endif
72 /* Operand insertion.  */
74 #if ! CGEN_INT_INSN_P
76 /* Subroutine of insert_normal.  */
78 static CGEN_INLINE void
79 insert_1 (CGEN_CPU_DESC cd,
80           unsigned long value,
81           int start,
82           int length,
83           int 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 (CGEN_CPU_DESC cd,
122                long value,
123                unsigned int attrs,
124                unsigned int word_offset,
125                unsigned int start,
126                unsigned int length,
127                unsigned int word_length,
128                unsigned int total_length,
129                CGEN_INSN_BYTES_PTR buffer)
131   static char errbuf[100];
132   /* Written this way to avoid undefined behaviour.  */
133   unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
135   /* If LENGTH is zero, this operand doesn't contribute to the value.  */
136   if (length == 0)
137     return NULL;
139 #if 0
140   if (CGEN_INT_INSN_P
141       && word_offset != 0)
142     abort ();
143 #endif
145   if (word_length > 32)
146     abort ();
148   /* For architectures with insns smaller than the base-insn-bitsize,
149      word_length may be too big.  */
150   if (cd->min_insn_bitsize < cd->base_insn_bitsize)
151     {
152       if (word_offset == 0
153           && word_length > total_length)
154         word_length = total_length;
155     }
157   /* Ensure VALUE will fit.  */
158   if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT))
159     {
160       long minval = - (1L << (length - 1));
161       unsigned long maxval = mask;
162       
163       if ((value > 0 && (unsigned long) value > maxval)
164           || value < minval)
165         {
166           /* xgettext:c-format */
167           sprintf (errbuf,
168                    _("operand out of range (%ld not between %ld and %lu)"),
169                    value, minval, maxval);
170           return errbuf;
171         }
172     }
173   else if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
174     {
175       unsigned long maxval = mask;
176       
177       if ((unsigned long) value > maxval)
178         {
179           /* xgettext:c-format */
180           sprintf (errbuf,
181                    _("operand out of range (%lu not between 0 and %lu)"),
182                    value, maxval);
183           return errbuf;
184         }
185     }
186   else
187     {
188       if (! cgen_signed_overflow_ok_p (cd))
189         {
190           long minval = - (1L << (length - 1));
191           long maxval =   (1L << (length - 1)) - 1;
192           
193           if (value < minval || value > maxval)
194             {
195               sprintf
196                 /* xgettext:c-format */
197                 (errbuf, _("operand out of range (%ld not between %ld and %ld)"),
198                  value, minval, maxval);
199               return errbuf;
200             }
201         }
202     }
204 #if CGEN_INT_INSN_P
206   {
207     int shift;
209     if (CGEN_INSN_LSB0_P)
210       shift = (word_offset + start + 1) - length;
211     else
212       shift = total_length - (word_offset + start + length);
213     *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
214   }
216 #else /* ! CGEN_INT_INSN_P */
218   {
219     unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
221     insert_1 (cd, value, start, length, word_length, bufp);
222   }
224 #endif /* ! CGEN_INT_INSN_P */
226   return NULL;
229 /* Default insn builder (insert handler).
230    The instruction is recorded in CGEN_INT_INSN_P byte order (meaning
231    that if CGEN_INSN_BYTES_PTR is an int * and thus, the value is
232    recorded in host byte order, otherwise BUFFER is an array of bytes
233    and the value is recorded in target byte order).
234    The result is an error message or NULL if success.  */
236 static const char *
237 insert_insn_normal (CGEN_CPU_DESC cd,
238                     const CGEN_INSN * insn,
239                     CGEN_FIELDS * fields,
240                     CGEN_INSN_BYTES_PTR buffer,
241                     bfd_vma pc)
243   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
244   unsigned long value;
245   const CGEN_SYNTAX_CHAR_TYPE * syn;
247   CGEN_INIT_INSERT (cd);
248   value = CGEN_INSN_BASE_VALUE (insn);
250   /* If we're recording insns as numbers (rather than a string of bytes),
251      target byte order handling is deferred until later.  */
253 #if CGEN_INT_INSN_P
255   put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
256                       CGEN_FIELDS_BITSIZE (fields), value);
258 #else
260   cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize,
261                                         (unsigned) CGEN_FIELDS_BITSIZE (fields)),
262                        value);
264 #endif /* ! CGEN_INT_INSN_P */
266   /* ??? It would be better to scan the format's fields.
267      Still need to be able to insert a value based on the operand though;
268      e.g. storing a branch displacement that got resolved later.
269      Needs more thought first.  */
271   for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
272     {
273       const char *errmsg;
275       if (CGEN_SYNTAX_CHAR_P (* syn))
276         continue;
278       errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
279                                        fields, buffer, pc);
280       if (errmsg)
281         return errmsg;
282     }
284   return NULL;
287 #if CGEN_INT_INSN_P
288 /* Cover function to store an insn value into an integral insn.  Must go here
289  because it needs <prefix>-desc.h for CGEN_INT_INSN_P.  */
291 static void
292 put_insn_int_value (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 (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
324             CGEN_EXTRACT_INFO *ex_info,
325             int offset,
326             int 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 (CGEN_CPU_DESC cd,
368            CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
369            int start,
370            int length,
371            int word_length,
372            unsigned char *bufp,
373            bfd_vma pc ATTRIBUTE_UNUSED)
375   unsigned long x;
376   int shift;
377 #if 0
378   int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
379 #endif
380   x = cgen_get_insn_value (cd, bufp, word_length);
382   if (CGEN_INSN_LSB0_P)
383     shift = (start + 1) - length;
384   else
385     shift = (word_length - (start + length));
386   return x >> shift;
389 #endif /* ! CGEN_INT_INSN_P */
391 /* Default extraction routine.
393    INSN_VALUE is the first base_insn_bitsize bits of the insn in host order,
394    or sometimes less for cases like the m32r where the base insn size is 32
395    but some insns are 16 bits.
396    ATTRS is a mask of the boolean attributes.  We only need `SIGNED',
397    but for generality we take a bitmask of all of them.
398    WORD_OFFSET is the offset in bits from the start of the insn of the value.
399    WORD_LENGTH is the length of the word in bits in which the value resides.
400    START is the starting bit number in the word, architecture origin.
401    LENGTH is the length of VALUE in bits.
402    TOTAL_LENGTH is the total length of the insn in bits.
404    Returns 1 for success, 0 for failure.  */
406 /* ??? The return code isn't properly used.  wip.  */
408 /* ??? This doesn't handle bfd_vma's.  Create another function when
409    necessary.  */
411 static int
412 extract_normal (CGEN_CPU_DESC cd,
413 #if ! CGEN_INT_INSN_P
414                 CGEN_EXTRACT_INFO *ex_info,
415 #else
416                 CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
417 #endif
418                 CGEN_INSN_INT insn_value,
419                 unsigned int attrs,
420                 unsigned int word_offset,
421                 unsigned int start,
422                 unsigned int length,
423                 unsigned int word_length,
424                 unsigned int total_length,
425 #if ! CGEN_INT_INSN_P
426                 bfd_vma pc,
427 #else
428                 bfd_vma pc ATTRIBUTE_UNUSED,
429 #endif
430                 long *valuep)
432   long value, mask;
434   /* If LENGTH is zero, this operand doesn't contribute to the value
435      so give it a standard value of zero.  */
436   if (length == 0)
437     {
438       *valuep = 0;
439       return 1;
440     }
442 #if 0
443   if (CGEN_INT_INSN_P
444       && word_offset != 0)
445     abort ();
446 #endif
448   if (word_length > 32)
449     abort ();
451   /* For architectures with insns smaller than the insn-base-bitsize,
452      word_length may be too big.  */
453   if (cd->min_insn_bitsize < cd->base_insn_bitsize)
454     {
455       if (word_offset == 0
456           && word_length > total_length)
457         word_length = total_length;
458     }
460   /* Does the value reside in INSN_VALUE, and at the right alignment?  */
462   if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
463     {
464       if (CGEN_INSN_LSB0_P)
465         value = insn_value >> ((word_offset + start + 1) - length);
466       else
467         value = insn_value >> (total_length - ( word_offset + start + length));
468     }
470 #if ! CGEN_INT_INSN_P
472   else
473     {
474       unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
476       if (word_length > 32)
477         abort ();
479       if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
480         return 0;
482       value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
483     }
485 #endif /* ! CGEN_INT_INSN_P */
487   /* Written this way to avoid undefined behaviour.  */
488   mask = (((1L << (length - 1)) - 1) << 1) | 1;
490   value &= mask;
491   /* sign extend? */
492   if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
493       && (value & (1L << (length - 1))))
494     value |= ~mask;
496   *valuep = value;
498   return 1;
501 /* Default insn extractor.
503    INSN_VALUE is the first base_insn_bitsize bits, translated to host order.
504    The extracted fields are stored in FIELDS.
505    EX_INFO is used to handle reading variable length insns.
506    Return the length of the insn in bits, or 0 if no match,
507    or -1 if an error occurs fetching data (memory_error_func will have
508    been called).  */
510 static int
511 extract_insn_normal (CGEN_CPU_DESC cd,
512                      const CGEN_INSN *insn,
513                      CGEN_EXTRACT_INFO *ex_info,
514                      CGEN_INSN_INT insn_value,
515                      CGEN_FIELDS *fields,
516                      bfd_vma pc)
518   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
519   const CGEN_SYNTAX_CHAR_TYPE *syn;
521   CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
523   CGEN_INIT_EXTRACT (cd);
525   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
526     {
527       int length;
529       if (CGEN_SYNTAX_CHAR_P (*syn))
530         continue;
532       length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
533                                         ex_info, insn_value, fields, pc);
534       if (length <= 0)
535         return length;
536     }
538   /* We recognized and successfully extracted this insn.  */
539   return CGEN_INSN_BITSIZE (insn);
542 /* machine generated code added here */