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-2022 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