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