OSDN Git Service

6394fe062275788118ec1c2433a12bebd7a99b6c
[pf3gnuchains/pf3gnuchains3x.git] / opcodes / cgen-ibld.in
1 /* Instruction building/extraction support for @arch@. -*- C -*-
2
3 THIS FILE IS MACHINE GENERATED WITH CGEN: Cpu tools GENerator.
4 - the resultant file is machine generated, cgen-ibld.in isn't
5
6 Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
7
8 This file is part of the GNU Binutils and GDB, the GNU debugger.
9
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.
14
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.
19
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.  */
23
24 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
25    Keep that in mind.  */
26
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"
37
38 #undef min
39 #define min(a,b) ((a) < (b) ? (a) : (b))
40 #undef max
41 #define max(a,b) ((a) > (b) ? (a) : (b))
42
43 /* Used by the ifield rtx function.  */
44 #define FLD(f) (fields->f)
45
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
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 \f
61 /* Operand insertion.  */
62
63 #if ! CGEN_INT_INSN_P
64
65 /* Subroutine of insert_normal.  */
66
67 static CGEN_INLINE void
68 insert_1 (cd, value, start, length, word_length, bufp)
69      CGEN_CPU_DESC cd;
70      unsigned long value;
71      int start,length,word_length;
72      unsigned char *bufp;
73 {
74   unsigned long x,mask;
75   int shift;
76   int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
77
78   switch (word_length)
79     {
80     case 8:
81       x = *bufp;
82       break;
83     case 16:
84       if (big_p)
85         x = bfd_getb16 (bufp);
86       else
87         x = bfd_getl16 (bufp);
88       break;
89     case 24:
90       /* ??? This may need reworking as these cases don't necessarily
91          want the first byte and the last two bytes handled like this.  */
92       if (big_p)
93         x = (bufp[0] << 16) | bfd_getb16 (bufp + 1);
94       else
95         x = bfd_getl16 (bufp) | (bufp[2] << 16);
96       break;
97     case 32:
98       if (big_p)
99         x = bfd_getb32 (bufp);
100       else
101         x = bfd_getl32 (bufp);
102       break;
103     default :
104       abort ();
105     }
106
107   /* Written this way to avoid undefined behaviour.  */
108   mask = (((1L << (length - 1)) - 1) << 1) | 1;
109   if (CGEN_INSN_LSB0_P)
110     shift = (start + 1) - length;
111   else
112     shift = (word_length - (start + length));
113   x = (x & ~(mask << shift)) | ((value & mask) << shift);
114
115   switch (word_length)
116     {
117     case 8:
118       *bufp = x;
119       break;
120     case 16:
121       if (big_p)
122         bfd_putb16 (x, bufp);
123       else
124         bfd_putl16 (x, bufp);
125       break;
126     case 24:
127       /* ??? This may need reworking as these cases don't necessarily
128          want the first byte and the last two bytes handled like this.  */
129       if (big_p)
130         {
131           bufp[0] = x >> 16;
132           bfd_putb16 (x, bufp + 1);
133         }
134       else
135         {
136           bfd_putl16 (x, bufp);
137           bufp[2] = x >> 16;
138         }
139       break;
140     case 32:
141       if (big_p)
142         bfd_putb32 (x, bufp);
143       else
144         bfd_putl32 (x, bufp);
145       break;
146     default :
147       abort ();
148     }
149 }
150
151 #endif /* ! CGEN_INT_INSN_P */
152
153 /* Default insertion routine.
154
155    ATTRS is a mask of the boolean attributes.
156    WORD_OFFSET is the offset in bits from the start of the insn of the value.
157    WORD_LENGTH is the length of the word in bits in which the value resides.
158    START is the starting bit number in the word, architecture origin.
159    LENGTH is the length of VALUE in bits.
160    TOTAL_LENGTH is the total length of the insn in bits.
161
162    The result is an error message or NULL if success.  */
163
164 /* ??? This duplicates functionality with bfd's howto table and
165    bfd_install_relocation.  */
166 /* ??? This doesn't handle bfd_vma's.  Create another function when
167    necessary.  */
168
169 static const char *
170 insert_normal (cd, value, attrs, word_offset, start, length, word_length,
171                total_length, buffer)
172      CGEN_CPU_DESC cd;
173      long value;
174      unsigned int attrs;
175      unsigned int word_offset, start, length, word_length, total_length;
176      CGEN_INSN_BYTES_PTR buffer;
177 {
178   static char errbuf[100];
179   /* Written this way to avoid undefined behaviour.  */
180   unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
181
182   /* If LENGTH is zero, this operand doesn't contribute to the value.  */
183   if (length == 0)
184     return NULL;
185
186   if (CGEN_INT_INSN_P
187       && word_offset != 0)
188     abort ();
189
190   if (word_length > 32)
191     abort ();
192
193   /* For architectures with insns smaller than the base-insn-bitsize,
194      word_length may be too big.  */
195   if (cd->min_insn_bitsize < cd->base_insn_bitsize)
196     {
197       if (word_offset == 0
198           && word_length > total_length)
199         word_length = total_length;
200     }
201
202   /* Ensure VALUE will fit.  */
203   if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
204     {
205       unsigned long maxval = mask;
206       
207       if ((unsigned long) value > maxval)
208         {
209           /* xgettext:c-format */
210           sprintf (errbuf,
211                    _("operand out of range (%lu not between 0 and %lu)"),
212                    value, maxval);
213           return errbuf;
214         }
215     }
216   else
217     {
218       if (! cgen_signed_overflow_ok_p (cd))
219         {
220           long minval = - (1L << (length - 1));
221           long maxval =   (1L << (length - 1)) - 1;
222           
223           if (value < minval || value > maxval)
224             {
225               sprintf
226                 /* xgettext:c-format */
227                 (errbuf, _("operand out of range (%ld not between %ld and %ld)"),
228                  value, minval, maxval);
229               return errbuf;
230             }
231         }
232     }
233
234 #if CGEN_INT_INSN_P
235
236   {
237     int shift;
238
239     if (CGEN_INSN_LSB0_P)
240       shift = (start + 1) - length;
241     else
242       shift = word_length - (start + length);
243     *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
244   }
245
246 #else /* ! CGEN_INT_INSN_P */
247
248   {
249     unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
250
251     insert_1 (cd, value, start, length, word_length, bufp);
252   }
253
254 #endif /* ! CGEN_INT_INSN_P */
255
256   return NULL;
257 }
258
259 /* Default insn builder (insert handler).
260    The instruction is recorded in CGEN_INT_INSN_P byte order
261    (meaning that if CGEN_INT_INSN_P BUFFER is an int * and thus the value is
262    recorded in host byte order, otherwise BUFFER is an array of bytes and the
263    value is recorded in target byte order).
264    The result is an error message or NULL if success.  */
265
266 static const char *
267 insert_insn_normal (cd, insn, fields, buffer, pc)
268      CGEN_CPU_DESC cd;
269      const CGEN_INSN * insn;
270      CGEN_FIELDS * fields;
271      CGEN_INSN_BYTES_PTR buffer;
272      bfd_vma pc;
273 {
274   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
275   unsigned long value;
276   const unsigned char * syn;
277
278   CGEN_INIT_INSERT (cd);
279   value = CGEN_INSN_BASE_VALUE (insn);
280
281   /* If we're recording insns as numbers (rather than a string of bytes),
282      target byte order handling is deferred until later.  */
283
284 #if CGEN_INT_INSN_P
285
286   *buffer = value;
287
288 #else
289
290   cgen_put_insn_value (cd, buffer, min (cd->base_insn_bitsize,
291                                         CGEN_FIELDS_BITSIZE (fields)),
292                        value);
293
294 #endif /* ! CGEN_INT_INSN_P */
295
296   /* ??? It would be better to scan the format's fields.
297      Still need to be able to insert a value based on the operand though;
298      e.g. storing a branch displacement that got resolved later.
299      Needs more thought first.  */
300
301   for (syn = CGEN_SYNTAX_STRING (syntax); * syn != '\0'; ++ syn)
302     {
303       const char *errmsg;
304
305       if (CGEN_SYNTAX_CHAR_P (* syn))
306         continue;
307
308       errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
309                                        fields, buffer, pc);
310       if (errmsg)
311         return errmsg;
312     }
313
314   return NULL;
315 }
316 \f
317 /* Operand extraction.  */
318
319 #if ! CGEN_INT_INSN_P
320
321 /* Subroutine of extract_normal.
322    Ensure sufficient bytes are cached in EX_INFO.
323    OFFSET is the offset in bytes from the start of the insn of the value.
324    BYTES is the length of the needed value.
325    Returns 1 for success, 0 for failure.  */
326
327 static CGEN_INLINE int
328 fill_cache (cd, ex_info, offset, bytes, pc)
329      CGEN_CPU_DESC cd;
330      CGEN_EXTRACT_INFO *ex_info;
331      int offset, bytes;
332      bfd_vma pc;
333 {
334   /* It's doubtful that the middle part has already been fetched so
335      we don't optimize that case.  kiss.  */
336   int mask;
337   disassemble_info *info = (disassemble_info *) ex_info->dis_info;
338
339   /* First do a quick check.  */
340   mask = (1 << bytes) - 1;
341   if (((ex_info->valid >> offset) & mask) == mask)
342     return 1;
343
344   /* Search for the first byte we need to read.  */
345   for (mask = 1 << offset; bytes > 0; --bytes, ++offset, mask <<= 1)
346     if (! (mask & ex_info->valid))
347       break;
348
349   if (bytes)
350     {
351       int status;
352
353       pc += offset;
354       status = (*info->read_memory_func)
355         (pc, ex_info->insn_bytes + offset, bytes, info);
356
357       if (status != 0)
358         {
359           (*info->memory_error_func) (status, pc, info);
360           return 0;
361         }
362
363       ex_info->valid |= ((1 << bytes) - 1) << offset;
364     }
365
366   return 1;
367 }
368
369 /* Subroutine of extract_normal.  */
370
371 static CGEN_INLINE long
372 extract_1 (cd, ex_info, start, length, word_length, bufp, pc)
373      CGEN_CPU_DESC cd;
374      CGEN_EXTRACT_INFO *ex_info;
375      int start,length,word_length;
376      unsigned char *bufp;
377      bfd_vma pc;
378 {
379   unsigned long x,mask;
380   int shift;
381   int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
382
383   switch (word_length)
384     {
385     case 8:
386       x = *bufp;
387       break;
388     case 16:
389       if (big_p)
390         x = bfd_getb16 (bufp);
391       else
392         x = bfd_getl16 (bufp);
393       break;
394     case 24:
395       /* ??? This may need reworking as these cases don't necessarily
396          want the first byte and the last two bytes handled like this.  */
397       if (big_p)
398         x = (bufp[0] << 16) | bfd_getb16 (bufp + 1);
399       else
400         x = bfd_getl16 (bufp) | (bufp[2] << 16);
401       break;
402     case 32:
403       if (big_p)
404         x = bfd_getb32 (bufp);
405       else
406         x = bfd_getl32 (bufp);
407       break;
408     default :
409       abort ();
410     }
411
412   /* Written this way to avoid undefined behaviour.  */
413   mask = (((1L << (length - 1)) - 1) << 1) | 1;
414   if (CGEN_INSN_LSB0_P)
415     shift = (start + 1) - length;
416   else
417     shift = (word_length - (start + length));
418   return (x >> shift) & mask;
419 }
420
421 #endif /* ! CGEN_INT_INSN_P */
422
423 /* Default extraction routine.
424
425    INSN_VALUE is the first base_insn_bitsize bits of the insn in host order,
426    or sometimes less for cases like the m32r where the base insn size is 32
427    but some insns are 16 bits.
428    ATTRS is a mask of the boolean attributes.  We only need `SIGNED',
429    but for generality we take a bitmask of all of them.
430    WORD_OFFSET is the offset in bits from the start of the insn of the value.
431    WORD_LENGTH is the length of the word in bits in which the value resides.
432    START is the starting bit number in the word, architecture origin.
433    LENGTH is the length of VALUE in bits.
434    TOTAL_LENGTH is the total length of the insn in bits.
435
436    Returns 1 for success, 0 for failure.  */
437
438 /* ??? The return code isn't properly used.  wip.  */
439
440 /* ??? This doesn't handle bfd_vma's.  Create another function when
441    necessary.  */
442
443 static int
444 extract_normal (cd, ex_info, insn_value, attrs, word_offset, start, length,
445                 word_length, total_length, pc, valuep)
446      CGEN_CPU_DESC cd;
447 #if ! CGEN_INT_INSN_P
448      CGEN_EXTRACT_INFO *ex_info;
449 #else
450      CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED;
451 #endif
452      CGEN_INSN_INT insn_value;
453      unsigned int attrs;
454      unsigned int word_offset, start, length, word_length, total_length;
455 #if ! CGEN_INT_INSN_P
456      bfd_vma pc;
457 #else
458      bfd_vma pc ATTRIBUTE_UNUSED;
459 #endif
460      long *valuep;
461 {
462   CGEN_INSN_INT value;
463
464   /* If LENGTH is zero, this operand doesn't contribute to the value
465      so give it a standard value of zero.  */
466   if (length == 0)
467     {
468       *valuep = 0;
469       return 1;
470     }
471
472   if (CGEN_INT_INSN_P
473       && word_offset != 0)
474     abort ();
475
476   if (word_length > 32)
477     abort ();
478
479   /* For architectures with insns smaller than the insn-base-bitsize,
480      word_length may be too big.  */
481   if (cd->min_insn_bitsize < cd->base_insn_bitsize)
482     {
483       if (word_offset == 0
484           && word_length > total_length)
485         word_length = total_length;
486     }
487
488   /* Does the value reside in INSN_VALUE?  */
489
490   if (word_offset == 0)
491     {
492       /* Written this way to avoid undefined behaviour.  */
493       CGEN_INSN_INT mask = (((1L << (length - 1)) - 1) << 1) | 1;
494
495       if (CGEN_INSN_LSB0_P)
496         value = insn_value >> ((start + 1) - length);
497       else
498         value = insn_value >> (word_length - (start + length));
499       value &= mask;
500       /* sign extend? */
501       if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
502           && (value & (1L << (length - 1))))
503         value |= ~mask;
504     }
505
506 #if ! CGEN_INT_INSN_P
507
508   else
509     {
510       unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
511
512       if (word_length > 32)
513         abort ();
514
515       if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
516         return 0;
517
518       value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
519     }
520
521 #endif /* ! CGEN_INT_INSN_P */
522
523   *valuep = value;
524
525   return 1;
526 }
527
528 /* Default insn extractor.
529
530    INSN_VALUE is the first base_insn_bitsize bits, translated to host order.
531    The extracted fields are stored in FIELDS.
532    EX_INFO is used to handle reading variable length insns.
533    Return the length of the insn in bits, or 0 if no match,
534    or -1 if an error occurs fetching data (memory_error_func will have
535    been called).  */
536
537 static int
538 extract_insn_normal (cd, insn, ex_info, insn_value, fields, pc)
539      CGEN_CPU_DESC cd;
540      const CGEN_INSN *insn;
541      CGEN_EXTRACT_INFO *ex_info;
542      CGEN_INSN_INT insn_value;
543      CGEN_FIELDS *fields;
544      bfd_vma pc;
545 {
546   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
547   const unsigned char *syn;
548
549   CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
550
551   CGEN_INIT_EXTRACT (cd);
552
553   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
554     {
555       int length;
556
557       if (CGEN_SYNTAX_CHAR_P (*syn))
558         continue;
559
560       length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
561                                         ex_info, insn_value, fields, pc);
562       if (length <= 0)
563         return length;
564     }
565
566   /* We recognized and successfully extracted this insn.  */
567   return CGEN_INSN_BITSIZE (insn);
568 }
569 \f
570 /* machine generated code added here */