]> Git Repo - binutils.git/blob - opcodes/cgen-ibld.in
Add libctf to update-copyright.py
[binutils.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-2020 Free Software Foundation, Inc.
7
8    This file is part of libopcodes.
9
10    This library 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 3, or (at your option)
13    any later version.
14
15    It is distributed in the hope that it will be useful, but WITHOUT
16    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
18    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    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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 <stdio.h>
29 #include "ansidecl.h"
30 #include "dis-asm.h"
31 #include "bfd.h"
32 #include "symcat.h"
33 #include "@[email protected]"
34 #include "@[email protected]"
35 #include "cgen/basic-modes.h"
36 #include "opintl.h"
37 #include "safe-ctype.h"
38
39 #undef  min
40 #define min(a,b) ((a) < (b) ? (a) : (b))
41 #undef  max
42 #define max(a,b) ((a) > (b) ? (a) : (b))
43
44 /* Used by the ifield rtx function.  */
45 #define FLD(f) (fields->f)
46
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
72 \f
73 /* Operand insertion.  */
74
75 #if ! CGEN_INT_INSN_P
76
77 /* Subroutine of insert_normal.  */
78
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)
86 {
87   unsigned long x, mask;
88   int shift;
89
90   x = cgen_get_insn_value (cd, bufp, word_length, cd->endian);
91
92   /* Written this way to avoid undefined behaviour.  */
93   mask = (1UL << (length - 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);
99
100   cgen_put_insn_value (cd, bufp, word_length, (bfd_vma) x, cd->endian);
101 }
102
103 #endif /* ! CGEN_INT_INSN_P */
104
105 /* Default insertion routine.
106
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.
113
114    The result is an error message or NULL if success.  */
115
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.  */
120
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)
131 {
132   static char errbuf[100];
133   unsigned long mask;
134
135   /* If LENGTH is zero, this operand doesn't contribute to the value.  */
136   if (length == 0)
137     return NULL;
138
139   /* Written this way to avoid undefined behaviour.  */
140   mask = (1UL << (length - 1) << 1) - 1;
141
142   if (word_length > 8 * sizeof (CGEN_INSN_INT))
143     abort ();
144
145   /* For architectures with insns smaller than the base-insn-bitsize,
146      word_length may be too big.  */
147   if (cd->min_insn_bitsize < cd->base_insn_bitsize)
148     {
149       if (word_offset == 0
150           && word_length > total_length)
151         word_length = total_length;
152     }
153
154   /* Ensure VALUE will fit.  */
155   if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT))
156     {
157       long minval = - (1UL << (length - 1));
158       unsigned long maxval = mask;
159
160       if ((value > 0 && (unsigned long) value > maxval)
161           || value < minval)
162         {
163           /* xgettext:c-format */
164           sprintf (errbuf,
165                    _("operand out of range (%ld not between %ld and %lu)"),
166                    value, minval, maxval);
167           return errbuf;
168         }
169     }
170   else if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
171     {
172       unsigned long maxval = mask;
173       unsigned long val = (unsigned long) value;
174
175       /* For hosts with a word size > 32 check to see if value has been sign
176          extended beyond 32 bits.  If so then ignore these higher sign bits
177          as the user is attempting to store a 32-bit signed value into an
178          unsigned 32-bit field which is allowed.  */
179       if (sizeof (unsigned long) > 4 && ((value >> 32) == -1))
180         val &= 0xFFFFFFFF;
181
182       if (val > maxval)
183         {
184           /* xgettext:c-format */
185           sprintf (errbuf,
186                    _("operand out of range (0x%lx not between 0 and 0x%lx)"),
187                    val, maxval);
188           return errbuf;
189         }
190     }
191   else
192     {
193       if (! cgen_signed_overflow_ok_p (cd))
194         {
195           long minval = - (1UL << (length - 1));
196           long maxval =   (1UL << (length - 1)) - 1;
197
198           if (value < minval || value > maxval)
199             {
200               sprintf
201                 /* xgettext:c-format */
202                 (errbuf, _("operand out of range (%ld not between %ld and %ld)"),
203                  value, minval, maxval);
204               return errbuf;
205             }
206         }
207     }
208
209 #if CGEN_INT_INSN_P
210
211   {
212     int shift_within_word, shift_to_word, shift;
213
214     /* How to shift the value to BIT0 of the word.  */
215     shift_to_word = total_length - (word_offset + word_length);
216
217     /* How to shift the value to the field within the word.  */
218     if (CGEN_INSN_LSB0_P)
219       shift_within_word = start + 1 - length;
220     else
221       shift_within_word = word_length - start - length;
222
223     /* The total SHIFT, then mask in the value.  */
224     shift = shift_to_word + shift_within_word;
225     *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
226   }
227
228 #else /* ! CGEN_INT_INSN_P */
229
230   {
231     unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
232
233     insert_1 (cd, value, start, length, word_length, bufp);
234   }
235
236 #endif /* ! CGEN_INT_INSN_P */
237
238   return NULL;
239 }
240
241 /* Default insn builder (insert handler).
242    The instruction is recorded in CGEN_INT_INSN_P byte order (meaning
243    that if CGEN_INSN_BYTES_PTR is an int * and thus, the value is
244    recorded in host byte order, otherwise BUFFER is an array of bytes
245    and the value is recorded in target byte order).
246    The result is an error message or NULL if success.  */
247
248 static const char *
249 insert_insn_normal (CGEN_CPU_DESC cd,
250                     const CGEN_INSN * insn,
251                     CGEN_FIELDS * fields,
252                     CGEN_INSN_BYTES_PTR buffer,
253                     bfd_vma pc)
254 {
255   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
256   unsigned long value;
257   const CGEN_SYNTAX_CHAR_TYPE * syn;
258
259   CGEN_INIT_INSERT (cd);
260   value = CGEN_INSN_BASE_VALUE (insn);
261
262   /* If we're recording insns as numbers (rather than a string of bytes),
263      target byte order handling is deferred until later.  */
264
265 #if CGEN_INT_INSN_P
266
267   put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
268                       CGEN_FIELDS_BITSIZE (fields), value);
269
270 #else
271
272   cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize,
273                                         (unsigned) CGEN_FIELDS_BITSIZE (fields)),
274                        value, cd->insn_endian);
275
276 #endif /* ! CGEN_INT_INSN_P */
277
278   /* ??? It would be better to scan the format's fields.
279      Still need to be able to insert a value based on the operand though;
280      e.g. storing a branch displacement that got resolved later.
281      Needs more thought first.  */
282
283   for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
284     {
285       const char *errmsg;
286
287       if (CGEN_SYNTAX_CHAR_P (* syn))
288         continue;
289
290       errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
291                                        fields, buffer, pc);
292       if (errmsg)
293         return errmsg;
294     }
295
296   return NULL;
297 }
298
299 #if CGEN_INT_INSN_P
300 /* Cover function to store an insn value into an integral insn.  Must go here
301    because it needs <prefix>-desc.h for CGEN_INT_INSN_P.  */
302
303 static void
304 put_insn_int_value (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
305                     CGEN_INSN_BYTES_PTR buf,
306                     int length,
307                     int insn_length,
308                     CGEN_INSN_INT value)
309 {
310   /* For architectures with insns smaller than the base-insn-bitsize,
311      length may be too big.  */
312   if (length > insn_length)
313     *buf = value;
314   else
315     {
316       int shift = insn_length - length;
317       /* Written this way to avoid undefined behaviour.  */
318       CGEN_INSN_INT mask = length == 0 ? 0 : (1UL << (length - 1) << 1) - 1;
319
320       *buf = (*buf & ~(mask << shift)) | ((value & mask) << shift);
321     }
322 }
323 #endif
324 \f
325 /* Operand extraction.  */
326
327 #if ! CGEN_INT_INSN_P
328
329 /* Subroutine of extract_normal.
330    Ensure sufficient bytes are cached in EX_INFO.
331    OFFSET is the offset in bytes from the start of the insn of the value.
332    BYTES is the length of the needed value.
333    Returns 1 for success, 0 for failure.  */
334
335 static CGEN_INLINE int
336 fill_cache (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
337             CGEN_EXTRACT_INFO *ex_info,
338             int offset,
339             int bytes,
340             bfd_vma pc)
341 {
342   /* It's doubtful that the middle part has already been fetched so
343      we don't optimize that case.  kiss.  */
344   unsigned int mask;
345   disassemble_info *info = (disassemble_info *) ex_info->dis_info;
346
347   /* First do a quick check.  */
348   mask = (1 << bytes) - 1;
349   if (((ex_info->valid >> offset) & mask) == mask)
350     return 1;
351
352   /* Search for the first byte we need to read.  */
353   for (mask = 1 << offset; bytes > 0; --bytes, ++offset, mask <<= 1)
354     if (! (mask & ex_info->valid))
355       break;
356
357   if (bytes)
358     {
359       int status;
360
361       pc += offset;
362       status = (*info->read_memory_func)
363         (pc, ex_info->insn_bytes + offset, bytes, info);
364
365       if (status != 0)
366         {
367           (*info->memory_error_func) (status, pc, info);
368           return 0;
369         }
370
371       ex_info->valid |= ((1 << bytes) - 1) << offset;
372     }
373
374   return 1;
375 }
376
377 /* Subroutine of extract_normal.  */
378
379 static CGEN_INLINE long
380 extract_1 (CGEN_CPU_DESC cd,
381            CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
382            int start,
383            int length,
384            int word_length,
385            unsigned char *bufp,
386            bfd_vma pc ATTRIBUTE_UNUSED)
387 {
388   unsigned long x;
389   int shift;
390
391   x = cgen_get_insn_value (cd, bufp, word_length, cd->endian);
392
393   if (CGEN_INSN_LSB0_P)
394     shift = (start + 1) - length;
395   else
396     shift = (word_length - (start + length));
397   return x >> shift;
398 }
399
400 #endif /* ! CGEN_INT_INSN_P */
401
402 /* Default extraction routine.
403
404    INSN_VALUE is the first base_insn_bitsize bits of the insn in host order,
405    or sometimes less for cases like the m32r where the base insn size is 32
406    but some insns are 16 bits.
407    ATTRS is a mask of the boolean attributes.  We only need `SIGNED',
408    but for generality we take a bitmask of all of them.
409    WORD_OFFSET is the offset in bits from the start of the insn of the value.
410    WORD_LENGTH is the length of the word in bits in which the value resides.
411    START is the starting bit number in the word, architecture origin.
412    LENGTH is the length of VALUE in bits.
413    TOTAL_LENGTH is the total length of the insn in bits.
414
415    Returns 1 for success, 0 for failure.  */
416
417 /* ??? The return code isn't properly used.  wip.  */
418
419 /* ??? This doesn't handle bfd_vma's.  Create another function when
420    necessary.  */
421
422 static int
423 extract_normal (CGEN_CPU_DESC cd,
424 #if ! CGEN_INT_INSN_P
425                 CGEN_EXTRACT_INFO *ex_info,
426 #else
427                 CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
428 #endif
429                 CGEN_INSN_INT insn_value,
430                 unsigned int attrs,
431                 unsigned int word_offset,
432                 unsigned int start,
433                 unsigned int length,
434                 unsigned int word_length,
435                 unsigned int total_length,
436 #if ! CGEN_INT_INSN_P
437                 bfd_vma pc,
438 #else
439                 bfd_vma pc ATTRIBUTE_UNUSED,
440 #endif
441                 long *valuep)
442 {
443   long value, mask;
444
445   /* If LENGTH is zero, this operand doesn't contribute to the value
446      so give it a standard value of zero.  */
447   if (length == 0)
448     {
449       *valuep = 0;
450       return 1;
451     }
452
453   if (word_length > 8 * sizeof (CGEN_INSN_INT))
454     abort ();
455
456   /* For architectures with insns smaller than the insn-base-bitsize,
457      word_length may be too big.  */
458   if (cd->min_insn_bitsize < cd->base_insn_bitsize)
459     {
460       if (word_offset + word_length > total_length)
461         word_length = total_length - word_offset;
462     }
463
464   /* Does the value reside in INSN_VALUE, and at the right alignment?  */
465
466   if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
467     {
468       if (CGEN_INSN_LSB0_P)
469         value = insn_value >> ((word_offset + start + 1) - length);
470       else
471         value = insn_value >> (total_length - ( word_offset + start + length));
472     }
473
474 #if ! CGEN_INT_INSN_P
475
476   else
477     {
478       unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
479
480       if (word_length > 8 * sizeof (CGEN_INSN_INT))
481         abort ();
482
483       if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
484         {
485           *valuep = 0;
486           return 0;
487         }
488
489       value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
490     }
491
492 #endif /* ! CGEN_INT_INSN_P */
493
494   /* Written this way to avoid undefined behaviour.  */
495   mask = (1UL << (length - 1) << 1) - 1;
496
497   value &= mask;
498   /* sign extend? */
499   if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
500       && (value & (1UL << (length - 1))))
501     value |= ~mask;
502
503   *valuep = value;
504
505   return 1;
506 }
507
508 /* Default insn extractor.
509
510    INSN_VALUE is the first base_insn_bitsize bits, translated to host order.
511    The extracted fields are stored in FIELDS.
512    EX_INFO is used to handle reading variable length insns.
513    Return the length of the insn in bits, or 0 if no match,
514    or -1 if an error occurs fetching data (memory_error_func will have
515    been called).  */
516
517 static int
518 extract_insn_normal (CGEN_CPU_DESC cd,
519                      const CGEN_INSN *insn,
520                      CGEN_EXTRACT_INFO *ex_info,
521                      CGEN_INSN_INT insn_value,
522                      CGEN_FIELDS *fields,
523                      bfd_vma pc)
524 {
525   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
526   const CGEN_SYNTAX_CHAR_TYPE *syn;
527
528   CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
529
530   CGEN_INIT_EXTRACT (cd);
531
532   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
533     {
534       int length;
535
536       if (CGEN_SYNTAX_CHAR_P (*syn))
537         continue;
538
539       length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
540                                         ex_info, insn_value, fields, pc);
541       if (length <= 0)
542         return length;
543     }
544
545   /* We recognized and successfully extracted this insn.  */
546   return CGEN_INSN_BITSIZE (insn);
547 }
548 \f
549 /* Machine generated code added here.  */
This page took 0.062846 seconds and 4 git commands to generate.