~ubuntu-branches/ubuntu/hoary/binutils/hoary

« back to all changes in this revision

Viewing changes to opcodes/cgen-ibld.in

  • Committer: Bazaar Package Importer
  • Author(s): James Troup
  • Date: 2004-05-19 10:35:44 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20040519103544-17h3o6e8pwndydrg
Tags: 2.14.90.0.7-8
debian/rules: don't use gcc-2.95 on m68k.  Thanks to Adam Conrad for
pointing this out.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 Free Software Foundation, Inc.
 
7
 
 
8
This file is part of the GNU Binutils and GDB, the GNU debugger.
 
9
 
 
10
This program 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 2, or (at your option)
 
13
any later version.
 
14
 
 
15
This program is distributed in the hope that it will be useful,
 
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
GNU General Public 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
59 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
 
 
46
static const char * insert_normal
 
47
  (CGEN_CPU_DESC, long, unsigned int, unsigned int, unsigned int,
 
48
   unsigned int, unsigned int, unsigned int, CGEN_INSN_BYTES_PTR);
 
49
static const char * insert_insn_normal
 
50
  (CGEN_CPU_DESC, const CGEN_INSN *,
 
51
   CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma);
 
52
static int extract_normal
 
53
  (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 *);
 
56
static int extract_insn_normal
 
57
  (CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
 
58
   CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma);
 
59
#if CGEN_INT_INSN_P
 
60
static void put_insn_int_value
 
61
  (CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT);
 
62
#endif
 
63
#if ! CGEN_INT_INSN_P
 
64
static CGEN_INLINE void insert_1
 
65
  (CGEN_CPU_DESC, unsigned long, int, int, int, unsigned char *);
 
66
static CGEN_INLINE int fill_cache
 
67
  (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *,  int, int, bfd_vma);
 
68
static CGEN_INLINE long extract_1
 
69
  (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, int, unsigned char *, bfd_vma);
 
70
#endif
 
71
 
 
72
/* Operand insertion.  */
 
73
 
 
74
#if ! CGEN_INT_INSN_P
 
75
 
 
76
/* Subroutine of insert_normal.  */
 
77
 
 
78
static CGEN_INLINE void
 
79
insert_1 (CGEN_CPU_DESC cd,
 
80
          unsigned long value,
 
81
          int start,
 
82
          int length,
 
83
          int 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
 
 
120
static const char *
 
121
insert_normal (CGEN_CPU_DESC cd,
 
122
               long value,
 
123
               unsigned int attrs,
 
124
               unsigned int word_offset,
 
125
               unsigned int start,
 
126
               unsigned int length,
 
127
               unsigned int word_length,
 
128
               unsigned int total_length,
 
129
               CGEN_INSN_BYTES_PTR buffer)
 
130
{
 
131
  static char errbuf[100];
 
132
  /* Written this way to avoid undefined behaviour.  */
 
133
  unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
 
134
 
 
135
  /* If LENGTH is zero, this operand doesn't contribute to the value.  */
 
136
  if (length == 0)
 
137
    return NULL;
 
138
 
 
139
#if 0
 
140
  if (CGEN_INT_INSN_P
 
141
      && word_offset != 0)
 
142
    abort ();
 
143
#endif
 
144
 
 
145
  if (word_length > 32)
 
146
    abort ();
 
147
 
 
148
  /* For architectures with insns smaller than the base-insn-bitsize,
 
149
     word_length may be too big.  */
 
150
  if (cd->min_insn_bitsize < cd->base_insn_bitsize)
 
151
    {
 
152
      if (word_offset == 0
 
153
          && word_length > total_length)
 
154
        word_length = total_length;
 
155
    }
 
156
 
 
157
  /* Ensure VALUE will fit.  */
 
158
  if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT))
 
159
    {
 
160
      long minval = - (1L << (length - 1));
 
161
      unsigned long maxval = mask;
 
162
      
 
163
      if ((value > 0 && (unsigned long) value > maxval)
 
164
          || value < minval)
 
165
        {
 
166
          /* xgettext:c-format */
 
167
          sprintf (errbuf,
 
168
                   _("operand out of range (%ld not between %ld and %lu)"),
 
169
                   value, minval, maxval);
 
170
          return errbuf;
 
171
        }
 
172
    }
 
173
  else if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
 
174
    {
 
175
      unsigned long maxval = mask;
 
176
      
 
177
      if ((unsigned long) value > maxval)
 
178
        {
 
179
          /* xgettext:c-format */
 
180
          sprintf (errbuf,
 
181
                   _("operand out of range (%lu not between 0 and %lu)"),
 
182
                   value, maxval);
 
183
          return errbuf;
 
184
        }
 
185
    }
 
186
  else
 
187
    {
 
188
      if (! cgen_signed_overflow_ok_p (cd))
 
189
        {
 
190
          long minval = - (1L << (length - 1));
 
191
          long maxval =   (1L << (length - 1)) - 1;
 
192
          
 
193
          if (value < minval || value > maxval)
 
194
            {
 
195
              sprintf
 
196
                /* xgettext:c-format */
 
197
                (errbuf, _("operand out of range (%ld not between %ld and %ld)"),
 
198
                 value, minval, maxval);
 
199
              return errbuf;
 
200
            }
 
201
        }
 
202
    }
 
203
 
 
204
#if CGEN_INT_INSN_P
 
205
 
 
206
  {
 
207
    int shift;
 
208
 
 
209
    if (CGEN_INSN_LSB0_P)
 
210
      shift = (word_offset + start + 1) - length;
 
211
    else
 
212
      shift = total_length - (word_offset + start + length);
 
213
    *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
 
214
  }
 
215
 
 
216
#else /* ! CGEN_INT_INSN_P */
 
217
 
 
218
  {
 
219
    unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
 
220
 
 
221
    insert_1 (cd, value, start, length, word_length, bufp);
 
222
  }
 
223
 
 
224
#endif /* ! CGEN_INT_INSN_P */
 
225
 
 
226
  return NULL;
 
227
}
 
228
 
 
229
/* Default insn builder (insert handler).
 
230
   The instruction is recorded in CGEN_INT_INSN_P byte order (meaning
 
231
   that if CGEN_INSN_BYTES_PTR is an int * and thus, the value is
 
232
   recorded in host byte order, otherwise BUFFER is an array of bytes
 
233
   and the value is recorded in target byte order).
 
234
   The result is an error message or NULL if success.  */
 
235
 
 
236
static const char *
 
237
insert_insn_normal (CGEN_CPU_DESC cd,
 
238
                    const CGEN_INSN * insn,
 
239
                    CGEN_FIELDS * fields,
 
240
                    CGEN_INSN_BYTES_PTR buffer,
 
241
                    bfd_vma pc)
 
242
{
 
243
  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
 
244
  unsigned long value;
 
245
  const CGEN_SYNTAX_CHAR_TYPE * syn;
 
246
 
 
247
  CGEN_INIT_INSERT (cd);
 
248
  value = CGEN_INSN_BASE_VALUE (insn);
 
249
 
 
250
  /* If we're recording insns as numbers (rather than a string of bytes),
 
251
     target byte order handling is deferred until later.  */
 
252
 
 
253
#if CGEN_INT_INSN_P
 
254
 
 
255
  put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
 
256
                      CGEN_FIELDS_BITSIZE (fields), value);
 
257
 
 
258
#else
 
259
 
 
260
  cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize,
 
261
                                        (unsigned) CGEN_FIELDS_BITSIZE (fields)),
 
262
                       value);
 
263
 
 
264
#endif /* ! CGEN_INT_INSN_P */
 
265
 
 
266
  /* ??? It would be better to scan the format's fields.
 
267
     Still need to be able to insert a value based on the operand though;
 
268
     e.g. storing a branch displacement that got resolved later.
 
269
     Needs more thought first.  */
 
270
 
 
271
  for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
 
272
    {
 
273
      const char *errmsg;
 
274
 
 
275
      if (CGEN_SYNTAX_CHAR_P (* syn))
 
276
        continue;
 
277
 
 
278
      errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
 
279
                                       fields, buffer, pc);
 
280
      if (errmsg)
 
281
        return errmsg;
 
282
    }
 
283
 
 
284
  return NULL;
 
285
}
 
286
 
 
287
#if CGEN_INT_INSN_P
 
288
/* Cover function to store an insn value into an integral insn.  Must go here
 
289
 because it needs <prefix>-desc.h for CGEN_INT_INSN_P.  */
 
290
 
 
291
static void
 
292
put_insn_int_value (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
 
 
322
static CGEN_INLINE int
 
323
fill_cache (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
 
324
            CGEN_EXTRACT_INFO *ex_info,
 
325
            int offset,
 
326
            int 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
 
 
366
static CGEN_INLINE long
 
367
extract_1 (CGEN_CPU_DESC cd,
 
368
           CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
 
369
           int start,
 
370
           int length,
 
371
           int word_length,
 
372
           unsigned char *bufp,
 
373
           bfd_vma pc ATTRIBUTE_UNUSED)
 
374
{
 
375
  unsigned long x;
 
376
  int shift;
 
377
#if 0
 
378
  int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
 
379
#endif
 
380
  x = cgen_get_insn_value (cd, bufp, word_length);
 
381
 
 
382
  if (CGEN_INSN_LSB0_P)
 
383
    shift = (start + 1) - length;
 
384
  else
 
385
    shift = (word_length - (start + length));
 
386
  return x >> shift;
 
387
}
 
388
 
 
389
#endif /* ! CGEN_INT_INSN_P */
 
390
 
 
391
/* Default extraction routine.
 
392
 
 
393
   INSN_VALUE is the first base_insn_bitsize bits of the insn in host order,
 
394
   or sometimes less for cases like the m32r where the base insn size is 32
 
395
   but some insns are 16 bits.
 
396
   ATTRS is a mask of the boolean attributes.  We only need `SIGNED',
 
397
   but for generality we take a bitmask of all of them.
 
398
   WORD_OFFSET is the offset in bits from the start of the insn of the value.
 
399
   WORD_LENGTH is the length of the word in bits in which the value resides.
 
400
   START is the starting bit number in the word, architecture origin.
 
401
   LENGTH is the length of VALUE in bits.
 
402
   TOTAL_LENGTH is the total length of the insn in bits.
 
403
 
 
404
   Returns 1 for success, 0 for failure.  */
 
405
 
 
406
/* ??? The return code isn't properly used.  wip.  */
 
407
 
 
408
/* ??? This doesn't handle bfd_vma's.  Create another function when
 
409
   necessary.  */
 
410
 
 
411
static int
 
412
extract_normal (CGEN_CPU_DESC cd,
 
413
#if ! CGEN_INT_INSN_P
 
414
                CGEN_EXTRACT_INFO *ex_info,
 
415
#else
 
416
                CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
 
417
#endif
 
418
                CGEN_INSN_INT insn_value,
 
419
                unsigned int attrs,
 
420
                unsigned int word_offset,
 
421
                unsigned int start,
 
422
                unsigned int length,
 
423
                unsigned int word_length,
 
424
                unsigned int total_length,
 
425
#if ! CGEN_INT_INSN_P
 
426
                bfd_vma pc,
 
427
#else
 
428
                bfd_vma pc ATTRIBUTE_UNUSED,
 
429
#endif
 
430
                long *valuep)
 
431
{
 
432
  long value, mask;
 
433
 
 
434
  /* If LENGTH is zero, this operand doesn't contribute to the value
 
435
     so give it a standard value of zero.  */
 
436
  if (length == 0)
 
437
    {
 
438
      *valuep = 0;
 
439
      return 1;
 
440
    }
 
441
 
 
442
#if 0
 
443
  if (CGEN_INT_INSN_P
 
444
      && word_offset != 0)
 
445
    abort ();
 
446
#endif
 
447
 
 
448
  if (word_length > 32)
 
449
    abort ();
 
450
 
 
451
  /* For architectures with insns smaller than the insn-base-bitsize,
 
452
     word_length may be too big.  */
 
453
  if (cd->min_insn_bitsize < cd->base_insn_bitsize)
 
454
    {
 
455
      if (word_offset == 0
 
456
          && word_length > total_length)
 
457
        word_length = total_length;
 
458
    }
 
459
 
 
460
  /* Does the value reside in INSN_VALUE, and at the right alignment?  */
 
461
 
 
462
  if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
 
463
    {
 
464
      if (CGEN_INSN_LSB0_P)
 
465
        value = insn_value >> ((word_offset + start + 1) - length);
 
466
      else
 
467
        value = insn_value >> (total_length - ( word_offset + start + length));
 
468
    }
 
469
 
 
470
#if ! CGEN_INT_INSN_P
 
471
 
 
472
  else
 
473
    {
 
474
      unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
 
475
 
 
476
      if (word_length > 32)
 
477
        abort ();
 
478
 
 
479
      if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
 
480
        return 0;
 
481
 
 
482
      value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
 
483
    }
 
484
 
 
485
#endif /* ! CGEN_INT_INSN_P */
 
486
 
 
487
  /* Written this way to avoid undefined behaviour.  */
 
488
  mask = (((1L << (length - 1)) - 1) << 1) | 1;
 
489
 
 
490
  value &= mask;
 
491
  /* sign extend? */
 
492
  if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
 
493
      && (value & (1L << (length - 1))))
 
494
    value |= ~mask;
 
495
 
 
496
  *valuep = value;
 
497
 
 
498
  return 1;
 
499
}
 
500
 
 
501
/* Default insn extractor.
 
502
 
 
503
   INSN_VALUE is the first base_insn_bitsize bits, translated to host order.
 
504
   The extracted fields are stored in FIELDS.
 
505
   EX_INFO is used to handle reading variable length insns.
 
506
   Return the length of the insn in bits, or 0 if no match,
 
507
   or -1 if an error occurs fetching data (memory_error_func will have
 
508
   been called).  */
 
509
 
 
510
static int
 
511
extract_insn_normal (CGEN_CPU_DESC cd,
 
512
                     const CGEN_INSN *insn,
 
513
                     CGEN_EXTRACT_INFO *ex_info,
 
514
                     CGEN_INSN_INT insn_value,
 
515
                     CGEN_FIELDS *fields,
 
516
                     bfd_vma pc)
 
517
{
 
518
  const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
 
519
  const CGEN_SYNTAX_CHAR_TYPE *syn;
 
520
 
 
521
  CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
 
522
 
 
523
  CGEN_INIT_EXTRACT (cd);
 
524
 
 
525
  for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
 
526
    {
 
527
      int length;
 
528
 
 
529
      if (CGEN_SYNTAX_CHAR_P (*syn))
 
530
        continue;
 
531
 
 
532
      length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
 
533
                                        ex_info, insn_value, fields, pc);
 
534
      if (length <= 0)
 
535
        return length;
 
536
    }
 
537
 
 
538
  /* We recognized and successfully extracted this insn.  */
 
539
  return CGEN_INSN_BITSIZE (insn);
 
540
}
 
541
 
 
542
/* machine generated code added here */