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