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