Revert 2001-08-08 changes.
[binutils.git] / opcodes / cgen-ibld.in
blob0ca4200aa2ae47c6adb086dc223889db21eb3cde
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 <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"
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));
53 static 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 *));
57 static int extract_insn_normal
58      PARAMS ((CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
59               CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma));
60 static void put_insn_int_value
61      PARAMS ((CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT));
64 /* Operand insertion.  */
66 #if ! CGEN_INT_INSN_P
68 /* Subroutine of insert_normal.  */
70 static CGEN_INLINE void
71 insert_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;
77   unsigned long x,mask;
78   int shift;
79   int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
81   x = bfd_get_bits (bufp, word_length, big_p);
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);
91   bfd_put_bits ((bfd_vma) x, bufp, word_length, big_p);
94 #endif /* ! CGEN_INT_INSN_P */
96 /* Default insertion routine.
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.
105    The result is an error message or NULL if success.  */
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.  */
112 static const char *
113 insert_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;
121   static char errbuf[100];
122   /* Written this way to avoid undefined behaviour.  */
123   unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
125   /* If LENGTH is zero, this operand doesn't contribute to the value.  */
126   if (length == 0)
127     return NULL;
129 #if 0
130   if (CGEN_INT_INSN_P
131       && word_offset != 0)
132     abort ();
133 #endif
135   if (word_length > 32)
136     abort ();
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     }
147   /* Ensure VALUE will fit.  */
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))
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     }
194 #if CGEN_INT_INSN_P
196   {
197     int shift;
199     if (CGEN_INSN_LSB0_P)
200       shift = (word_offset + start + 1) - length;
201     else
202       shift = total_length - (word_offset + start + length);
203     *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
204   }
206 #else /* ! CGEN_INT_INSN_P */
208   {
209     unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
211     insert_1 (cd, value, start, length, word_length, bufp);
212   }
214 #endif /* ! CGEN_INT_INSN_P */
216   return NULL;
219 /* Default insn builder (insert handler).
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).
224    The result is an error message or NULL if success.  */
226 static const char *
227 insert_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;
234   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
235   unsigned long value;
236   const CGEN_SYNTAX_CHAR_TYPE * syn;
238   CGEN_INIT_INSERT (cd);
239   value = CGEN_INSN_BASE_VALUE (insn);
241   /* If we're recording insns as numbers (rather than a string of bytes),
242      target byte order handling is deferred until later.  */
244 #if CGEN_INT_INSN_P
246   put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
247                       CGEN_FIELDS_BITSIZE (fields), value);
249 #else
251   cgen_put_insn_value (cd, buffer, min (cd->base_insn_bitsize,
252                                         CGEN_FIELDS_BITSIZE (fields)),
253                        value);
255 #endif /* ! CGEN_INT_INSN_P */
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.  */
262   for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
263     {
264       const char *errmsg;
266       if (CGEN_SYNTAX_CHAR_P (* syn))
267         continue;
269       errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
270                                        fields, buffer, pc);
271       if (errmsg)
272         return errmsg;
273     }
275   return NULL;
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.  */
281 static void
282 put_insn_int_value (cd, buf, length, insn_length, value)
283      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
284      CGEN_INSN_BYTES_PTR buf;
285      int length;
286      int insn_length;
287      CGEN_INSN_INT value;
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     }
302 /* Operand extraction.  */
304 #if ! CGEN_INT_INSN_P
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.  */
312 static CGEN_INLINE int
313 fill_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;
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;
324   /* First do a quick check.  */
325   mask = (1 << bytes) - 1;
326   if (((ex_info->valid >> offset) & mask) == mask)
327     return 1;
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;
334   if (bytes)
335     {
336       int status;
338       pc += offset;
339       status = (*info->read_memory_func)
340         (pc, ex_info->insn_bytes + offset, bytes, info);
342       if (status != 0)
343         {
344           (*info->memory_error_func) (status, pc, info);
345           return 0;
346         }
348       ex_info->valid |= ((1 << bytes) - 1) << offset;
349     }
351   return 1;
354 /* Subroutine of extract_normal.  */
356 static CGEN_INLINE long
357 extract_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;
364   unsigned long x;
365   int shift;
366   int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
368   x = bfd_get_bits (bufp, word_length, big_p);
370   if (CGEN_INSN_LSB0_P)
371     shift = (start + 1) - length;
372   else
373     shift = (word_length - (start + length));
374   return x >> shift;
377 #endif /* ! CGEN_INT_INSN_P */
379 /* Default extraction routine.
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.
392    Returns 1 for success, 0 for failure.  */
394 /* ??? The return code isn't properly used.  wip.  */
396 /* ??? This doesn't handle bfd_vma's.  Create another function when
397    necessary.  */
399 static int
400 extract_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;
418   CGEN_INSN_INT value, mask;
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     }
428 #if 0
429   if (CGEN_INT_INSN_P
430       && word_offset != 0)
431     abort ();
432 #endif
434   if (word_length > 32)
435     abort ();
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     }
446   /* Does the value reside in INSN_VALUE, and at the right alignment?  */
448   if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
449     {
450       if (CGEN_INSN_LSB0_P)
451         value = insn_value >> ((word_offset + start + 1) - length);
452       else
453         value = insn_value >> (total_length - ( word_offset + start + length));
454     }
456 #if ! CGEN_INT_INSN_P
458   else
459     {
460       unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
462       if (word_length > 32)
463         abort ();
465       if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
466         return 0;
468       value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
469     }
471 #endif /* ! CGEN_INT_INSN_P */
473   /* Written this way to avoid undefined behaviour.  */
474   mask = (((1L << (length - 1)) - 1) << 1) | 1;
476   value &= mask;
477   /* sign extend? */
478   if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
479       && (value & (1L << (length - 1))))
480     value |= ~mask;
482   *valuep = value;
484   return 1;
487 /* Default insn extractor.
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).  */
496 static int
497 extract_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;
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)
513     {
514       int length;
516       if (CGEN_SYNTAX_CHAR_P (*syn))
517         continue;
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     }
525   /* We recognized and successfully extracted this insn.  */
526   return CGEN_INSN_BITSIZE (insn);
529 /* machine generated code added here */