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