1 /* Instruction building/extraction support for @arch@. -*- C -*-
3 THIS FILE IS MACHINE GENERATED WITH CGEN: Cpu tools GENerator.
4 - the resultant file is machine generated, cgen-ibld.in isn't
6 Copyright (C) 1996-2024 Free Software Foundation, Inc.
8 This file is part of libopcodes.
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)
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.
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. */
24 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
33 #include "@prefix@-desc.h"
34 #include "@prefix@-opc.h"
35 #include "cgen/basic-modes.h"
37 #include "safe-ctype.h"
40 #define min(a,b) ((a) < (b) ? (a) : (b))
42 #define max(a,b) ((a) > (b) ? (a) : (b))
44 /* Used by the ifield rtx function. */
45 #define FLD(f) (fields->f)
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);
61 static void put_insn_int_value
62 (CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT);
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);
73 /* Operand insertion. */
77 /* Subroutine of insert_normal. */
79 static CGEN_INLINE void
80 insert_1 (CGEN_CPU_DESC cd,
87 unsigned long x, mask;
90 x = cgen_get_insn_value (cd, bufp, word_length, cd->endian);
92 /* Written this way to avoid undefined behaviour. */
93 mask = (1UL << (length - 1) << 1) - 1;
95 shift = (start + 1) - length;
97 shift = (word_length - (start + length));
98 x = (x & ~(mask << shift)) | ((value & mask) << shift);
100 cgen_put_insn_value (cd, bufp, word_length, (bfd_vma) x, cd->endian);
103 #endif /* ! CGEN_INT_INSN_P */
105 /* Default insertion routine.
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.
114 The result is an error message or NULL if success. */
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
122 insert_normal (CGEN_CPU_DESC cd,
125 unsigned int word_offset,
128 unsigned int word_length,
129 unsigned int total_length,
130 CGEN_INSN_BYTES_PTR buffer)
132 static char errbuf[100];
135 /* If LENGTH is zero, this operand doesn't contribute to the value. */
139 /* Written this way to avoid undefined behaviour. */
140 mask = (1UL << (length - 1) << 1) - 1;
142 if (word_length > 8 * sizeof (CGEN_INSN_INT))
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)
150 && word_length > total_length)
151 word_length = total_length;
154 /* Ensure VALUE will fit. */
155 if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT))
157 long minval = - (1UL << (length - 1));
158 unsigned long maxval = mask;
160 if ((value > 0 && (unsigned long) value > maxval)
163 /* xgettext:c-format */
165 _("operand out of range (%ld not between %ld and %lu)"),
166 value, minval, maxval);
170 else if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
172 unsigned long maxval = mask;
173 unsigned long val = (unsigned long) value;
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))
184 /* xgettext:c-format */
186 _("operand out of range (0x%lx not between 0 and 0x%lx)"),
193 if (! cgen_signed_overflow_ok_p (cd))
195 long minval = - (1UL << (length - 1));
196 long maxval = (1UL << (length - 1)) - 1;
198 if (value < minval || value > maxval)
201 /* xgettext:c-format */
202 (errbuf, _("operand out of range (%ld not between %ld and %ld)"),
203 value, minval, maxval);
212 int shift_within_word, shift_to_word, shift;
214 /* How to shift the value to BIT0 of the word. */
215 shift_to_word = total_length - (word_offset + word_length);
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;
221 shift_within_word = word_length - start - length;
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);
228 #else /* ! CGEN_INT_INSN_P */
231 unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
233 insert_1 (cd, value, start, length, word_length, bufp);
236 #endif /* ! CGEN_INT_INSN_P */
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. */
249 insert_insn_normal (CGEN_CPU_DESC cd,
250 const CGEN_INSN * insn,
251 CGEN_FIELDS * fields,
252 CGEN_INSN_BYTES_PTR buffer,
255 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
257 const CGEN_SYNTAX_CHAR_TYPE * syn;
259 CGEN_INIT_INSERT (cd);
260 value = CGEN_INSN_BASE_VALUE (insn);
262 /* If we're recording insns as numbers (rather than a string of bytes),
263 target byte order handling is deferred until later. */
267 put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
268 CGEN_FIELDS_BITSIZE (fields), value);
272 cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize,
273 (unsigned) CGEN_FIELDS_BITSIZE (fields)),
274 value, cd->insn_endian);
276 #endif /* ! CGEN_INT_INSN_P */
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. */
283 for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
287 if (CGEN_SYNTAX_CHAR_P (* syn))
290 errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
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. */
304 put_insn_int_value (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
305 CGEN_INSN_BYTES_PTR buf,
310 /* For architectures with insns smaller than the base-insn-bitsize,
311 length may be too big. */
312 if (length > insn_length)
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;
320 *buf = (*buf & ~(mask << shift)) | ((value & mask) << shift);
325 /* Operand extraction. */
327 #if ! CGEN_INT_INSN_P
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. */
335 static CGEN_INLINE int
336 fill_cache (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
337 CGEN_EXTRACT_INFO *ex_info,
342 /* It's doubtful that the middle part has already been fetched so
343 we don't optimize that case. kiss. */
345 disassemble_info *info = (disassemble_info *) ex_info->dis_info;
347 /* First do a quick check. */
348 mask = (1 << bytes) - 1;
349 if (((ex_info->valid >> offset) & mask) == mask)
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))
362 status = (*info->read_memory_func)
363 (pc, ex_info->insn_bytes + offset, bytes, info);
367 (*info->memory_error_func) (status, pc, info);
371 ex_info->valid |= ((1 << bytes) - 1) << offset;
377 /* Subroutine of extract_normal. */
379 static CGEN_INLINE long
380 extract_1 (CGEN_CPU_DESC cd,
381 CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
386 bfd_vma pc ATTRIBUTE_UNUSED)
391 x = cgen_get_insn_value (cd, bufp, word_length, cd->endian);
393 if (CGEN_INSN_LSB0_P)
394 shift = (start + 1) - length;
396 shift = (word_length - (start + length));
400 #endif /* ! CGEN_INT_INSN_P */
402 /* Default extraction routine.
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.
415 Returns 1 for success, 0 for failure. */
417 /* ??? The return code isn't properly used. wip. */
419 /* ??? This doesn't handle bfd_vma's. Create another function when
423 extract_normal (CGEN_CPU_DESC cd,
424 #if ! CGEN_INT_INSN_P
425 CGEN_EXTRACT_INFO *ex_info,
427 CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
429 CGEN_INSN_INT insn_value,
431 unsigned int word_offset,
434 unsigned int word_length,
435 unsigned int total_length,
436 #if ! CGEN_INT_INSN_P
439 bfd_vma pc ATTRIBUTE_UNUSED,
445 /* If LENGTH is zero, this operand doesn't contribute to the value
446 so give it a standard value of zero. */
453 if (word_length > 8 * sizeof (CGEN_INSN_INT))
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)
460 if (word_offset + word_length > total_length)
461 word_length = total_length - word_offset;
464 /* Does the value reside in INSN_VALUE, and at the right alignment? */
466 if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
468 if (CGEN_INSN_LSB0_P)
469 value = insn_value >> ((word_offset + start + 1) - length);
471 value = insn_value >> (total_length - ( word_offset + start + length));
474 #if ! CGEN_INT_INSN_P
478 unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
480 if (word_length > 8 * sizeof (CGEN_INSN_INT))
483 if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
489 value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
492 #endif /* ! CGEN_INT_INSN_P */
494 /* Written this way to avoid undefined behaviour. */
495 mask = (1UL << (length - 1) << 1) - 1;
499 if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
500 && (value & (1UL << (length - 1))))
508 /* Default insn extractor.
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
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,
525 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
526 const CGEN_SYNTAX_CHAR_TYPE *syn;
528 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
530 CGEN_INIT_EXTRACT (cd);
532 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
536 if (CGEN_SYNTAX_CHAR_P (*syn))
539 length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
540 ex_info, insn_value, fields, pc);
545 /* We recognized and successfully extracted this insn. */
546 return CGEN_INSN_BITSIZE (insn);
549 /* Machine generated code added here. */