source: trunk/src/binutils/opcodes/cgen-ibld.in@ 433

Last change on this file since 433 was 10, checked in by bird, 23 years ago

Initial revision

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