* cgen asm/disasm
[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 <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
46 static 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));
49 static const char * insert_insn_normal
50 PARAMS ((CGEN_CPU_DESC, const CGEN_INSN *,
51 CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma));
52
53 static 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 *));
57 static int extract_insn_normal
58 PARAMS ((CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
59 CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma));
60 static void put_insn_int_value
61 PARAMS ((CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT));
62
63 \f
64 /* Operand insertion. */
65
66 #if ! CGEN_INT_INSN_P
67
68 /* Subroutine of insert_normal. */
69
70 static CGEN_INLINE void
71 insert_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
81 x = bfd_get_bits (bufp, word_length, big_p);
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
91 bfd_put_bits ((bfd_vma) x, bufp, word_length, big_p);
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
112 static const char *
113 insert_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
129 #if 0
130 if (CGEN_INT_INSN_P
131 && word_offset != 0)
132 abort ();
133 #endif
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)
185 shift = (word_offset + start + 1) - length;
186 else
187 shift = total_length - (word_offset + start + length);
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 (meaning
206 that if CGEN_INSN_BYTES_PTR is an int * and thus, the value is
207 recorded in host byte order, otherwise BUFFER is an array of bytes
208 and the value is recorded in target byte order).
209 The result is an error message or NULL if success. */
210
211 static const char *
212 insert_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;
221 const CGEN_SYNTAX_CHAR_TYPE * syn;
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
231 put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
232 CGEN_FIELDS_BITSIZE (fields), value);
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
247 for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
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 }
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
266 static void
267 put_insn_int_value (cd, buf, length, insn_length, value)
268 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
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 }
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
297 static CGEN_INLINE int
298 fill_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
341 static CGEN_INLINE long
342 extract_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 {
349 unsigned long x;
350 int shift;
351 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG;
352
353 x = bfd_get_bits (bufp, word_length, big_p);
354
355 if (CGEN_INSN_LSB0_P)
356 shift = (start + 1) - length;
357 else
358 shift = (word_length - (start + length));
359 return x >> shift;
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
384 static int
385 extract_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 {
403 CGEN_INSN_INT value, mask;
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
413 #if 0
414 if (CGEN_INT_INSN_P
415 && word_offset != 0)
416 abort ();
417 #endif
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, and at the right alignment? */
432
433 if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
434 {
435 if (CGEN_INSN_LSB0_P)
436 value = insn_value >> ((word_offset + start + 1) - length);
437 else
438 value = insn_value >> (total_length - ( word_offset + start + length));
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
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
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
481 static int
482 extract_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);
491 const CGEN_SYNTAX_CHAR_TYPE *syn;
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.042399 seconds and 5 git commands to generate.