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-2024 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 "@prefix@-desc.h"
34#include "@prefix@-opc.h"
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
47static 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);
50static const char * insert_insn_normal
51  (CGEN_CPU_DESC, const CGEN_INSN *,
52   CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma);
53static 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 *);
57static 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
61static 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
65static CGEN_INLINE void insert_1
66  (CGEN_CPU_DESC, unsigned long, int, int, int, unsigned char *);
67static CGEN_INLINE int fill_cache
68  (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *,  int, int, bfd_vma);
69static CGEN_INLINE long extract_1
70  (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, int, unsigned char *, bfd_vma);
71#endif
72
73/* Operand insertion.  */
74
75#if ! CGEN_INT_INSN_P
76
77/* Subroutine of insert_normal.  */
78
79static CGEN_INLINE void
80insert_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
121static const char *
122insert_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
248static const char *
249insert_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
303static void
304put_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
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
335static CGEN_INLINE int
336fill_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
379static CGEN_INLINE long
380extract_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
422static int
423extract_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
517static int
518extract_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
549/* Machine generated code added here.  */
550