5cf57848c5d48ebae3851db8c2e29b5e29dd5133
[deliverable/binutils-gdb.git] / opcodes / cgen-ibld.in
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 \f
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,length,word_length,
82 unsigned char *bufp)
83 {
84 unsigned long x,mask;
85 int shift;
86
87 x = cgen_get_insn_value (cd, bufp, word_length);
88
89 /* Written this way to avoid undefined behaviour. */
90 mask = (((1L << (length - 1)) - 1) << 1) | 1;
91 if (CGEN_INSN_LSB0_P)
92 shift = (start + 1) - length;
93 else
94 shift = (word_length - (start + length));
95 x = (x & ~(mask << shift)) | ((value & mask) << shift);
96
97 cgen_put_insn_value (cd, bufp, word_length, (bfd_vma) x);
98 }
99
100 #endif /* ! CGEN_INT_INSN_P */
101
102 /* Default insertion routine.
103
104 ATTRS is a mask of the boolean attributes.
105 WORD_OFFSET is the offset in bits from the start of the insn of the value.
106 WORD_LENGTH is the length of the word in bits in which the value resides.
107 START is the starting bit number in the word, architecture origin.
108 LENGTH is the length of VALUE in bits.
109 TOTAL_LENGTH is the total length of the insn in bits.
110
111 The result is an error message or NULL if success. */
112
113 /* ??? This duplicates functionality with bfd's howto table and
114 bfd_install_relocation. */
115 /* ??? This doesn't handle bfd_vma's. Create another function when
116 necessary. */
117
118 static const char *
119 insert_normal (CGEN_CPU_DESC cd,
120 long value,
121 unsigned int attrs,
122 unsigned int word_offset,
123 unsigned int start,
124 unsigned int length,
125 unsigned int word_length,
126 unsigned int 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
234 static const char *
235 insert_insn_normal (CGEN_CPU_DESC cd,
236 const CGEN_INSN * insn,
237 CGEN_FIELDS * fields,
238 CGEN_INSN_BYTES_PTR buffer,
239 bfd_vma pc)
240 {
241 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
242 unsigned long value;
243 const CGEN_SYNTAX_CHAR_TYPE * syn;
244
245 CGEN_INIT_INSERT (cd);
246 value = CGEN_INSN_BASE_VALUE (insn);
247
248 /* If we're recording insns as numbers (rather than a string of bytes),
249 target byte order handling is deferred until later. */
250
251 #if CGEN_INT_INSN_P
252
253 put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
254 CGEN_FIELDS_BITSIZE (fields), value);
255
256 #else
257
258 cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize,
259 (unsigned) CGEN_FIELDS_BITSIZE (fields)),
260 value);
261
262 #endif /* ! CGEN_INT_INSN_P */
263
264 /* ??? It would be better to scan the format's fields.
265 Still need to be able to insert a value based on the operand though;
266 e.g. storing a branch displacement that got resolved later.
267 Needs more thought first. */
268
269 for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
270 {
271 const char *errmsg;
272
273 if (CGEN_SYNTAX_CHAR_P (* syn))
274 continue;
275
276 errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
277 fields, buffer, pc);
278 if (errmsg)
279 return errmsg;
280 }
281
282 return NULL;
283 }
284
285 #if CGEN_INT_INSN_P
286 /* Cover function to store an insn value into an integral insn. Must go here
287 because it needs <prefix>-desc.h for CGEN_INT_INSN_P. */
288
289 static void
290 put_insn_int_value (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
291 CGEN_INSN_BYTES_PTR buf,
292 int length,
293 int insn_length,
294 CGEN_INSN_INT value)
295 {
296 /* For architectures with insns smaller than the base-insn-bitsize,
297 length may be too big. */
298 if (length > insn_length)
299 *buf = value;
300 else
301 {
302 int shift = insn_length - length;
303 /* Written this way to avoid undefined behaviour. */
304 CGEN_INSN_INT mask = (((1L << (length - 1)) - 1) << 1) | 1;
305 *buf = (*buf & ~(mask << shift)) | ((value & mask) << shift);
306 }
307 }
308 #endif
309 \f
310 /* Operand extraction. */
311
312 #if ! CGEN_INT_INSN_P
313
314 /* Subroutine of extract_normal.
315 Ensure sufficient bytes are cached in EX_INFO.
316 OFFSET is the offset in bytes from the start of the insn of the value.
317 BYTES is the length of the needed value.
318 Returns 1 for success, 0 for failure. */
319
320 static CGEN_INLINE int
321 fill_cache (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
322 CGEN_EXTRACT_INFO *ex_info,
323 int offset, bytes,
324 bfd_vma pc)
325 {
326 /* It's doubtful that the middle part has already been fetched so
327 we don't optimize that case. kiss. */
328 unsigned int mask;
329 disassemble_info *info = (disassemble_info *) ex_info->dis_info;
330
331 /* First do a quick check. */
332 mask = (1 << bytes) - 1;
333 if (((ex_info->valid >> offset) & mask) == mask)
334 return 1;
335
336 /* Search for the first byte we need to read. */
337 for (mask = 1 << offset; bytes > 0; --bytes, ++offset, mask <<= 1)
338 if (! (mask & ex_info->valid))
339 break;
340
341 if (bytes)
342 {
343 int status;
344
345 pc += offset;
346 status = (*info->read_memory_func)
347 (pc, ex_info->insn_bytes + offset, bytes, info);
348
349 if (status != 0)
350 {
351 (*info->memory_error_func) (status, pc, info);
352 return 0;
353 }
354
355 ex_info->valid |= ((1 << bytes) - 1) << offset;
356 }
357
358 return 1;
359 }
360
361 /* Subroutine of extract_normal. */
362
363 static CGEN_INLINE long
364 extract_1 (CGEN_CPU_DESC cd,
365 CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
366 int start,
367 int length,
368 int word_length,
369 unsigned char *bufp,
370 bfd_vma pc ATTRIBUTE_UNUSED)
371 {
372 unsigned long x;
373 int shift;
374 #if 0
375 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
376 #endif
377 x = cgen_get_insn_value (cd, bufp, word_length);
378
379 if (CGEN_INSN_LSB0_P)
380 shift = (start + 1) - length;
381 else
382 shift = (word_length - (start + length));
383 return x >> shift;
384 }
385
386 #endif /* ! CGEN_INT_INSN_P */
387
388 /* Default extraction routine.
389
390 INSN_VALUE is the first base_insn_bitsize bits of the insn in host order,
391 or sometimes less for cases like the m32r where the base insn size is 32
392 but some insns are 16 bits.
393 ATTRS is a mask of the boolean attributes. We only need `SIGNED',
394 but for generality we take a bitmask of all of them.
395 WORD_OFFSET is the offset in bits from the start of the insn of the value.
396 WORD_LENGTH is the length of the word in bits in which the value resides.
397 START is the starting bit number in the word, architecture origin.
398 LENGTH is the length of VALUE in bits.
399 TOTAL_LENGTH is the total length of the insn in bits.
400
401 Returns 1 for success, 0 for failure. */
402
403 /* ??? The return code isn't properly used. wip. */
404
405 /* ??? This doesn't handle bfd_vma's. Create another function when
406 necessary. */
407
408 static int
409 extract_normal (CGEN_CPU_DESC cd;
410 #if ! CGEN_INT_INSN_P
411 CGEN_EXTRACT_INFO *ex_info,
412 #else
413 CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
414 #endif
415 CGEN_INSN_INT insn_value,
416 unsigned int attrs,
417 unsigned int word_offset,
418 unsigned int start,
419 unsigned int length,
420 unsigned int word_length,
421 unsigned int 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
507 static int
508 extract_insn_normal (CGEN_CPU_DESC cd,
509 const CGEN_INSN *insn,
510 CGEN_EXTRACT_INFO *ex_info,
511 CGEN_INSN_INT insn_value,
512 CGEN_FIELDS *fields,
513 bfd_vma pc)
514 {
515 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
516 const CGEN_SYNTAX_CHAR_TYPE *syn;
517
518 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
519
520 CGEN_INIT_EXTRACT (cd);
521
522 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
523 {
524 int length;
525
526 if (CGEN_SYNTAX_CHAR_P (*syn))
527 continue;
528
529 length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
530 ex_info, insn_value, fields, pc);
531 if (length <= 0)
532 return length;
533 }
534
535 /* We recognized and successfully extracted this insn. */
536 return CGEN_INSN_BITSIZE (insn);
537 }
538 \f
539 /* machine generated code added here */
This page took 0.053456 seconds and 3 git commands to generate.