xref: /netbsd-src/external/gpl3/binutils/dist/opcodes/cgen-ibld.in (revision 413d532bcc3f62d122e56d92e13ac64825a40baf)
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 1996, 1997, 1998, 1999, 2000, 2001, 2005, 2006, 2007,
7   2008, 2010  Free Software Foundation, Inc.
8
9   This file is part of libopcodes.
10
11   This library is free software; you can redistribute it and/or modify
12   it under the terms of the GNU General Public License as published by
13   the Free Software Foundation; either version 3, or (at your option)
14   any later version.
15
16   It is distributed in the hope that it will be useful, but WITHOUT
17   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
19   License for more details.
20
21   You should have received a copy of the GNU General Public License
22   along with this program; if not, write to the Free Software Foundation, Inc.,
23   51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
24
25/* ??? Eventually more and more of this stuff can go to cpu-independent files.
26   Keep that in mind.  */
27
28#include "sysdep.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 "cgen/basic-modes.h"
37#include "opintl.h"
38#include "safe-ctype.h"
39
40#undef  min
41#define min(a,b) ((a) < (b) ? (a) : (b))
42#undef  max
43#define max(a,b) ((a) > (b) ? (a) : (b))
44
45/* Used by the ifield rtx function.  */
46#define FLD(f) (fields->f)
47
48static const char * insert_normal
49  (CGEN_CPU_DESC, long, unsigned int, unsigned int, unsigned int,
50   unsigned int, unsigned int, unsigned int, CGEN_INSN_BYTES_PTR);
51static const char * insert_insn_normal
52  (CGEN_CPU_DESC, const CGEN_INSN *,
53   CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma);
54static int extract_normal
55  (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_INT,
56   unsigned int, unsigned int, unsigned int, unsigned int,
57   unsigned int, unsigned int, bfd_vma, long *);
58static int extract_insn_normal
59  (CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
60   CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma);
61#if CGEN_INT_INSN_P
62static void put_insn_int_value
63  (CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT);
64#endif
65#if ! CGEN_INT_INSN_P
66static CGEN_INLINE void insert_1
67  (CGEN_CPU_DESC, unsigned long, int, int, int, unsigned char *);
68static CGEN_INLINE int fill_cache
69  (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *,  int, int, bfd_vma);
70static CGEN_INLINE long extract_1
71  (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, int, unsigned char *, bfd_vma);
72#endif
73
74/* Operand insertion.  */
75
76#if ! CGEN_INT_INSN_P
77
78/* Subroutine of insert_normal.  */
79
80static CGEN_INLINE void
81insert_1 (CGEN_CPU_DESC cd,
82	  unsigned long value,
83	  int start,
84	  int length,
85	  int word_length,
86	  unsigned char *bufp)
87{
88  unsigned long x,mask;
89  int shift;
90
91  x = cgen_get_insn_value (cd, bufp, word_length);
92
93  /* Written this way to avoid undefined behaviour.  */
94  mask = (((1L << (length - 1)) - 1) << 1) | 1;
95  if (CGEN_INSN_LSB0_P)
96    shift = (start + 1) - length;
97  else
98    shift = (word_length - (start + length));
99  x = (x & ~(mask << shift)) | ((value & mask) << shift);
100
101  cgen_put_insn_value (cd, bufp, word_length, (bfd_vma) x);
102}
103
104#endif /* ! CGEN_INT_INSN_P */
105
106/* Default insertion routine.
107
108   ATTRS is a mask of the boolean attributes.
109   WORD_OFFSET is the offset in bits from the start of the insn of the value.
110   WORD_LENGTH is the length of the word in bits in which the value resides.
111   START is the starting bit number in the word, architecture origin.
112   LENGTH is the length of VALUE in bits.
113   TOTAL_LENGTH is the total length of the insn in bits.
114
115   The result is an error message or NULL if success.  */
116
117/* ??? This duplicates functionality with bfd's howto table and
118   bfd_install_relocation.  */
119/* ??? This doesn't handle bfd_vma's.  Create another function when
120   necessary.  */
121
122static const char *
123insert_normal (CGEN_CPU_DESC cd,
124	       long value,
125	       unsigned int attrs,
126	       unsigned int word_offset,
127	       unsigned int start,
128	       unsigned int length,
129	       unsigned int word_length,
130	       unsigned int total_length,
131	       CGEN_INSN_BYTES_PTR buffer)
132{
133  static char errbuf[100];
134  /* Written this way to avoid undefined behaviour.  */
135  unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
136
137  /* If LENGTH is zero, this operand doesn't contribute to the value.  */
138  if (length == 0)
139    return NULL;
140
141  if (word_length > 8 * sizeof (CGEN_INSN_INT))
142    abort ();
143
144  /* For architectures with insns smaller than the base-insn-bitsize,
145     word_length may be too big.  */
146  if (cd->min_insn_bitsize < cd->base_insn_bitsize)
147    {
148      if (word_offset == 0
149	  && word_length > total_length)
150	word_length = total_length;
151    }
152
153  /* Ensure VALUE will fit.  */
154  if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT))
155    {
156      long minval = - (1L << (length - 1));
157      unsigned long maxval = mask;
158
159      if ((value > 0 && (unsigned long) value > maxval)
160	  || value < minval)
161	{
162	  /* xgettext:c-format */
163	  sprintf (errbuf,
164		   _("operand out of range (%ld not between %ld and %lu)"),
165		   value, minval, maxval);
166	  return errbuf;
167	}
168    }
169  else if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
170    {
171      unsigned long maxval = mask;
172      unsigned long val = (unsigned long) value;
173
174      /* For hosts with a word size > 32 check to see if value has been sign
175	 extended beyond 32 bits.  If so then ignore these higher sign bits
176	 as the user is attempting to store a 32-bit signed value into an
177	 unsigned 32-bit field which is allowed.  */
178      if (sizeof (unsigned long) > 4 && ((value >> 32) == -1))
179	val &= 0xFFFFFFFF;
180
181      if (val > maxval)
182	{
183	  /* xgettext:c-format */
184	  sprintf (errbuf,
185		   _("operand out of range (0x%lx not between 0 and 0x%lx)"),
186		   val, maxval);
187	  return errbuf;
188	}
189    }
190  else
191    {
192      if (! cgen_signed_overflow_ok_p (cd))
193	{
194	  long minval = - (1L << (length - 1));
195	  long maxval =   (1L << (length - 1)) - 1;
196
197	  if (value < minval || value > maxval)
198	    {
199	      sprintf
200		/* xgettext:c-format */
201		(errbuf, _("operand out of range (%ld not between %ld and %ld)"),
202		 value, minval, maxval);
203	      return errbuf;
204	    }
205	}
206    }
207
208#if CGEN_INT_INSN_P
209
210  {
211    int shift;
212
213    if (CGEN_INSN_LSB0_P)
214      shift = (word_offset + start + 1) - length;
215    else
216      shift = total_length - (word_offset + start + length);
217    *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
218  }
219
220#else /* ! CGEN_INT_INSN_P */
221
222  {
223    unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
224
225    insert_1 (cd, value, start, length, word_length, bufp);
226  }
227
228#endif /* ! CGEN_INT_INSN_P */
229
230  return NULL;
231}
232
233/* Default insn builder (insert handler).
234   The instruction is recorded in CGEN_INT_INSN_P byte order (meaning
235   that if CGEN_INSN_BYTES_PTR is an int * and thus, the value is
236   recorded in host byte order, otherwise BUFFER is an array of bytes
237   and the value is recorded in target byte order).
238   The result is an error message or NULL if success.  */
239
240static const char *
241insert_insn_normal (CGEN_CPU_DESC cd,
242		    const CGEN_INSN * insn,
243		    CGEN_FIELDS * fields,
244		    CGEN_INSN_BYTES_PTR buffer,
245		    bfd_vma pc)
246{
247  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
248  unsigned long value;
249  const CGEN_SYNTAX_CHAR_TYPE * syn;
250
251  CGEN_INIT_INSERT (cd);
252  value = CGEN_INSN_BASE_VALUE (insn);
253
254  /* If we're recording insns as numbers (rather than a string of bytes),
255     target byte order handling is deferred until later.  */
256
257#if CGEN_INT_INSN_P
258
259  put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
260		      CGEN_FIELDS_BITSIZE (fields), value);
261
262#else
263
264  cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize,
265					(unsigned) CGEN_FIELDS_BITSIZE (fields)),
266		       value);
267
268#endif /* ! CGEN_INT_INSN_P */
269
270  /* ??? It would be better to scan the format's fields.
271     Still need to be able to insert a value based on the operand though;
272     e.g. storing a branch displacement that got resolved later.
273     Needs more thought first.  */
274
275  for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
276    {
277      const char *errmsg;
278
279      if (CGEN_SYNTAX_CHAR_P (* syn))
280	continue;
281
282      errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
283				       fields, buffer, pc);
284      if (errmsg)
285	return errmsg;
286    }
287
288  return NULL;
289}
290
291#if CGEN_INT_INSN_P
292/* Cover function to store an insn value into an integral insn.  Must go here
293   because it needs <prefix>-desc.h for CGEN_INT_INSN_P.  */
294
295static void
296put_insn_int_value (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
297		    CGEN_INSN_BYTES_PTR buf,
298		    int length,
299		    int insn_length,
300		    CGEN_INSN_INT value)
301{
302  /* For architectures with insns smaller than the base-insn-bitsize,
303     length may be too big.  */
304  if (length > insn_length)
305    *buf = value;
306  else
307    {
308      int shift = insn_length - length;
309      /* Written this way to avoid undefined behaviour.  */
310      CGEN_INSN_INT mask = (((1L << (length - 1)) - 1) << 1) | 1;
311
312      *buf = (*buf & ~(mask << shift)) | ((value & mask) << shift);
313    }
314}
315#endif
316
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
327static CGEN_INLINE int
328fill_cache (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
329	    CGEN_EXTRACT_INFO *ex_info,
330	    int offset,
331	    int 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  unsigned 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
371static CGEN_INLINE long
372extract_1 (CGEN_CPU_DESC cd,
373	   CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
374	   int start,
375	   int length,
376	   int word_length,
377	   unsigned char *bufp,
378	   bfd_vma pc ATTRIBUTE_UNUSED)
379{
380  unsigned long x;
381  int shift;
382
383  x = cgen_get_insn_value (cd, bufp, word_length);
384
385  if (CGEN_INSN_LSB0_P)
386    shift = (start + 1) - length;
387  else
388    shift = (word_length - (start + length));
389  return x >> shift;
390}
391
392#endif /* ! CGEN_INT_INSN_P */
393
394/* Default extraction routine.
395
396   INSN_VALUE is the first base_insn_bitsize bits of the insn in host order,
397   or sometimes less for cases like the m32r where the base insn size is 32
398   but some insns are 16 bits.
399   ATTRS is a mask of the boolean attributes.  We only need `SIGNED',
400   but for generality we take a bitmask of all of them.
401   WORD_OFFSET is the offset in bits from the start of the insn of the value.
402   WORD_LENGTH is the length of the word in bits in which the value resides.
403   START is the starting bit number in the word, architecture origin.
404   LENGTH is the length of VALUE in bits.
405   TOTAL_LENGTH is the total length of the insn in bits.
406
407   Returns 1 for success, 0 for failure.  */
408
409/* ??? The return code isn't properly used.  wip.  */
410
411/* ??? This doesn't handle bfd_vma's.  Create another function when
412   necessary.  */
413
414static int
415extract_normal (CGEN_CPU_DESC cd,
416#if ! CGEN_INT_INSN_P
417		CGEN_EXTRACT_INFO *ex_info,
418#else
419		CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
420#endif
421		CGEN_INSN_INT insn_value,
422		unsigned int attrs,
423		unsigned int word_offset,
424		unsigned int start,
425		unsigned int length,
426		unsigned int word_length,
427		unsigned int total_length,
428#if ! CGEN_INT_INSN_P
429		bfd_vma pc,
430#else
431		bfd_vma pc ATTRIBUTE_UNUSED,
432#endif
433		long *valuep)
434{
435  long value, mask;
436
437  /* If LENGTH is zero, this operand doesn't contribute to the value
438     so give it a standard value of zero.  */
439  if (length == 0)
440    {
441      *valuep = 0;
442      return 1;
443    }
444
445  if (word_length > 8 * sizeof (CGEN_INSN_INT))
446    abort ();
447
448  /* For architectures with insns smaller than the insn-base-bitsize,
449     word_length may be too big.  */
450  if (cd->min_insn_bitsize < cd->base_insn_bitsize)
451    {
452      if (word_offset + word_length > total_length)
453	word_length = total_length - word_offset;
454    }
455
456  /* Does the value reside in INSN_VALUE, and at the right alignment?  */
457
458  if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
459    {
460      if (CGEN_INSN_LSB0_P)
461	value = insn_value >> ((word_offset + start + 1) - length);
462      else
463	value = insn_value >> (total_length - ( word_offset + start + length));
464    }
465
466#if ! CGEN_INT_INSN_P
467
468  else
469    {
470      unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
471
472      if (word_length > 8 * sizeof (CGEN_INSN_INT))
473	abort ();
474
475      if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
476	return 0;
477
478      value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
479    }
480
481#endif /* ! CGEN_INT_INSN_P */
482
483  /* Written this way to avoid undefined behaviour.  */
484  mask = (((1L << (length - 1)) - 1) << 1) | 1;
485
486  value &= mask;
487  /* sign extend? */
488  if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
489      && (value & (1L << (length - 1))))
490    value |= ~mask;
491
492  *valuep = value;
493
494  return 1;
495}
496
497/* Default insn extractor.
498
499   INSN_VALUE is the first base_insn_bitsize bits, translated to host order.
500   The extracted fields are stored in FIELDS.
501   EX_INFO is used to handle reading variable length insns.
502   Return the length of the insn in bits, or 0 if no match,
503   or -1 if an error occurs fetching data (memory_error_func will have
504   been called).  */
505
506static int
507extract_insn_normal (CGEN_CPU_DESC cd,
508		     const CGEN_INSN *insn,
509		     CGEN_EXTRACT_INFO *ex_info,
510		     CGEN_INSN_INT insn_value,
511		     CGEN_FIELDS *fields,
512		     bfd_vma pc)
513{
514  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
515  const CGEN_SYNTAX_CHAR_TYPE *syn;
516
517  CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
518
519  CGEN_INIT_EXTRACT (cd);
520
521  for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
522    {
523      int length;
524
525      if (CGEN_SYNTAX_CHAR_P (*syn))
526	continue;
527
528      length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
529					ex_info, insn_value, fields, pc);
530      if (length <= 0)
531	return length;
532    }
533
534  /* We recognized and successfully extracted this insn.  */
535  return CGEN_INSN_BITSIZE (insn);
536}
537
538/* Machine generated code added here.  */
539