2001-03-13 Fernando Nasser <fnasser@redhat.com>
[deliverable/binutils-gdb.git] / opcodes / cgen-ibld.in
CommitLineData
f6e6b40f
BE
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
4a9f416d 6Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
f6e6b40f
BE
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));
6bb95a0f
DB
60static void put_insn_int_value
61 PARAMS ((CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT));
62
f6e6b40f
BE
63\f
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
aed80dae 81 x = bfd_get_bits (bufp, word_length, big_p);
f6e6b40f
BE
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
aed80dae 91 bfd_put_bits ((bfd_vma) x, bufp, word_length, big_p);
f6e6b40f
BE
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
6bb95a0f 129#if 0
f6e6b40f
BE
130 if (CGEN_INT_INSN_P
131 && word_offset != 0)
132 abort ();
6bb95a0f 133#endif
f6e6b40f
BE
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)
6bb95a0f 185 shift = (word_offset + start + 1) - length;
f6e6b40f 186 else
6bb95a0f 187 shift = total_length - (word_offset + start + length);
f6e6b40f
BE
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;
4a9f416d 221 const CGEN_SYNTAX_CHAR_TYPE * syn;
f6e6b40f
BE
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
6bb95a0f
DB
231 put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
232 CGEN_FIELDS_BITSIZE (fields), value);
f6e6b40f
BE
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
4a9f416d 247 for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
f6e6b40f
BE
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}
6bb95a0f
DB
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}
f6e6b40f
BE
286\f
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{
aed80dae 349 unsigned long x;
f6e6b40f
BE
350 int shift;
351 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
352
aed80dae 353 x = bfd_get_bits (bufp, word_length, big_p);
f6e6b40f 354
f6e6b40f
BE
355 if (CGEN_INSN_LSB0_P)
356 shift = (start + 1) - length;
357 else
358 shift = (word_length - (start + length));
aed80dae 359 return x >> shift;
f6e6b40f
BE
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{
aed80dae 403 CGEN_INSN_INT value, mask;
f6e6b40f
BE
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
6bb95a0f 413#if 0
f6e6b40f
BE
414 if (CGEN_INT_INSN_P
415 && word_offset != 0)
416 abort ();
6bb95a0f 417#endif
f6e6b40f
BE
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
6bb95a0f 433 if (CGEN_INT_INSN_P || word_offset == 0)
f6e6b40f 434 {
f6e6b40f 435 if (CGEN_INSN_LSB0_P)
6bb95a0f 436 value = insn_value >> ((word_offset + start + 1) - length);
f6e6b40f 437 else
6bb95a0f 438 value = insn_value >> (total_length - ( word_offset + start + length));
f6e6b40f
BE
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
aed80dae
FCE
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
f6e6b40f
BE
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);
4a9f416d 491 const CGEN_SYNTAX_CHAR_TYPE *syn;
f6e6b40f
BE
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\f
514/* machine generated code added here */
This page took 0.05918 seconds and 4 git commands to generate.