cgen-ibld.in revision 89857
1/* Instruction building/extraction support for @arch@. -*- C -*- 2 3THIS FILE IS MACHINE GENERATED WITH CGEN: Cpu tools GENerator. 4- the resultant file is machine generated, cgen-ibld.in isn't 5 6Copyright 1996, 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc. 7 8This file is part of the GNU Binutils and GDB, the GNU debugger. 9 10This program is free software; you can redistribute it and/or modify 11it under the terms of the GNU General Public License as published by 12the Free Software Foundation; either version 2, or (at your option) 13any later version. 14 15This program is distributed in the hope that it will be useful, 16but WITHOUT ANY WARRANTY; without even the implied warranty of 17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18GNU General Public License for more details. 19 20You should have received a copy of the GNU General Public License 21along with this program; if not, write to the Free Software Foundation, Inc., 2259 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 46static 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)); 49static const char * insert_insn_normal 50 PARAMS ((CGEN_CPU_DESC, const CGEN_INSN *, 51 CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma)); 52static int extract_normal 53 PARAMS ((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 *)); 56static int extract_insn_normal 57 PARAMS ((CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *, 58 CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma)); 59#if CGEN_INT_INSN_P 60static void put_insn_int_value 61 PARAMS ((CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT)); 62#endif 63#if ! CGEN_INT_INSN_P 64static CGEN_INLINE void insert_1 65 PARAMS ((CGEN_CPU_DESC, unsigned long, int, int, int, unsigned char *)); 66static CGEN_INLINE int fill_cache 67 PARAMS ((CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, bfd_vma)); 68static CGEN_INLINE long extract_1 69 PARAMS ((CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, int, 70 unsigned char *, bfd_vma)); 71#endif 72 73/* Operand insertion. */ 74 75#if ! CGEN_INT_INSN_P 76 77/* Subroutine of insert_normal. */ 78 79static CGEN_INLINE void 80insert_1 (cd, value, start, length, word_length, bufp) 81 CGEN_CPU_DESC cd; 82 unsigned long value; 83 int start,length,word_length; 84 unsigned char *bufp; 85{ 86 unsigned long x,mask; 87 int shift; 88 89 x = cgen_get_insn_value (cd, bufp, word_length); 90 91 /* Written this way to avoid undefined behaviour. */ 92 mask = (((1L << (length - 1)) - 1) << 1) | 1; 93 if (CGEN_INSN_LSB0_P) 94 shift = (start + 1) - length; 95 else 96 shift = (word_length - (start + length)); 97 x = (x & ~(mask << shift)) | ((value & mask) << shift); 98 99 cgen_put_insn_value (cd, bufp, word_length, (bfd_vma) x); 100} 101 102#endif /* ! CGEN_INT_INSN_P */ 103 104/* Default insertion routine. 105 106 ATTRS is a mask of the boolean attributes. 107 WORD_OFFSET is the offset in bits from the start of the insn of the value. 108 WORD_LENGTH is the length of the word in bits in which the value resides. 109 START is the starting bit number in the word, architecture origin. 110 LENGTH is the length of VALUE in bits. 111 TOTAL_LENGTH is the total length of the insn in bits. 112 113 The result is an error message or NULL if success. */ 114 115/* ??? This duplicates functionality with bfd's howto table and 116 bfd_install_relocation. */ 117/* ??? This doesn't handle bfd_vma's. Create another function when 118 necessary. */ 119 120static const char * 121insert_normal (cd, value, attrs, word_offset, start, length, word_length, 122 total_length, buffer) 123 CGEN_CPU_DESC cd; 124 long value; 125 unsigned int attrs; 126 unsigned int word_offset, start, length, word_length, 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 234static const char * 235insert_insn_normal (cd, insn, fields, buffer, pc) 236 CGEN_CPU_DESC cd; 237 const CGEN_INSN * insn; 238 CGEN_FIELDS * fields; 239 CGEN_INSN_BYTES_PTR buffer; 240 bfd_vma pc; 241{ 242 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn); 243 unsigned long value; 244 const CGEN_SYNTAX_CHAR_TYPE * syn; 245 246 CGEN_INIT_INSERT (cd); 247 value = CGEN_INSN_BASE_VALUE (insn); 248 249 /* If we're recording insns as numbers (rather than a string of bytes), 250 target byte order handling is deferred until later. */ 251 252#if CGEN_INT_INSN_P 253 254 put_insn_int_value (cd, buffer, cd->base_insn_bitsize, 255 CGEN_FIELDS_BITSIZE (fields), value); 256 257#else 258 259 cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize, 260 (unsigned) CGEN_FIELDS_BITSIZE (fields)), 261 value); 262 263#endif /* ! CGEN_INT_INSN_P */ 264 265 /* ??? It would be better to scan the format's fields. 266 Still need to be able to insert a value based on the operand though; 267 e.g. storing a branch displacement that got resolved later. 268 Needs more thought first. */ 269 270 for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn) 271 { 272 const char *errmsg; 273 274 if (CGEN_SYNTAX_CHAR_P (* syn)) 275 continue; 276 277 errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn), 278 fields, buffer, pc); 279 if (errmsg) 280 return errmsg; 281 } 282 283 return NULL; 284} 285 286#if CGEN_INT_INSN_P 287/* Cover function to store an insn value into an integral insn. Must go here 288 because it needs <prefix>-desc.h for CGEN_INT_INSN_P. */ 289 290static void 291put_insn_int_value (cd, buf, length, insn_length, value) 292 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED; 293 CGEN_INSN_BYTES_PTR buf; 294 int length; 295 int insn_length; 296 CGEN_INSN_INT value; 297{ 298 /* For architectures with insns smaller than the base-insn-bitsize, 299 length may be too big. */ 300 if (length > insn_length) 301 *buf = value; 302 else 303 { 304 int shift = insn_length - length; 305 /* Written this way to avoid undefined behaviour. */ 306 CGEN_INSN_INT mask = (((1L << (length - 1)) - 1) << 1) | 1; 307 *buf = (*buf & ~(mask << shift)) | ((value & mask) << shift); 308 } 309} 310#endif 311 312/* Operand extraction. */ 313 314#if ! CGEN_INT_INSN_P 315 316/* Subroutine of extract_normal. 317 Ensure sufficient bytes are cached in EX_INFO. 318 OFFSET is the offset in bytes from the start of the insn of the value. 319 BYTES is the length of the needed value. 320 Returns 1 for success, 0 for failure. */ 321 322static CGEN_INLINE int 323fill_cache (cd, ex_info, offset, bytes, pc) 324 CGEN_CPU_DESC cd ATTRIBUTE_UNUSED; 325 CGEN_EXTRACT_INFO *ex_info; 326 int offset, bytes; 327 bfd_vma pc; 328{ 329 /* It's doubtful that the middle part has already been fetched so 330 we don't optimize that case. kiss. */ 331 unsigned int mask; 332 disassemble_info *info = (disassemble_info *) ex_info->dis_info; 333 334 /* First do a quick check. */ 335 mask = (1 << bytes) - 1; 336 if (((ex_info->valid >> offset) & mask) == mask) 337 return 1; 338 339 /* Search for the first byte we need to read. */ 340 for (mask = 1 << offset; bytes > 0; --bytes, ++offset, mask <<= 1) 341 if (! (mask & ex_info->valid)) 342 break; 343 344 if (bytes) 345 { 346 int status; 347 348 pc += offset; 349 status = (*info->read_memory_func) 350 (pc, ex_info->insn_bytes + offset, bytes, info); 351 352 if (status != 0) 353 { 354 (*info->memory_error_func) (status, pc, info); 355 return 0; 356 } 357 358 ex_info->valid |= ((1 << bytes) - 1) << offset; 359 } 360 361 return 1; 362} 363 364/* Subroutine of extract_normal. */ 365 366static CGEN_INLINE long 367extract_1 (cd, ex_info, start, length, word_length, bufp, pc) 368 CGEN_CPU_DESC cd; 369 CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED; 370 int start,length,word_length; 371 unsigned char *bufp; 372 bfd_vma pc ATTRIBUTE_UNUSED; 373{ 374 unsigned long x; 375 int shift; 376#if 0 377 int big_p = CGEN_CPU_INSN_ENDIAN (cd) == CGEN_ENDIAN_BIG; 378#endif 379 x = cgen_get_insn_value (cd, bufp, word_length); 380 381 if (CGEN_INSN_LSB0_P) 382 shift = (start + 1) - length; 383 else 384 shift = (word_length - (start + length)); 385 return x >> shift; 386} 387 388#endif /* ! CGEN_INT_INSN_P */ 389 390/* Default extraction routine. 391 392 INSN_VALUE is the first base_insn_bitsize bits of the insn in host order, 393 or sometimes less for cases like the m32r where the base insn size is 32 394 but some insns are 16 bits. 395 ATTRS is a mask of the boolean attributes. We only need `SIGNED', 396 but for generality we take a bitmask of all of them. 397 WORD_OFFSET is the offset in bits from the start of the insn of the value. 398 WORD_LENGTH is the length of the word in bits in which the value resides. 399 START is the starting bit number in the word, architecture origin. 400 LENGTH is the length of VALUE in bits. 401 TOTAL_LENGTH is the total length of the insn in bits. 402 403 Returns 1 for success, 0 for failure. */ 404 405/* ??? The return code isn't properly used. wip. */ 406 407/* ??? This doesn't handle bfd_vma's. Create another function when 408 necessary. */ 409 410static int 411extract_normal (cd, ex_info, insn_value, attrs, word_offset, start, length, 412 word_length, total_length, pc, valuep) 413 CGEN_CPU_DESC cd; 414#if ! CGEN_INT_INSN_P 415 CGEN_EXTRACT_INFO *ex_info; 416#else 417 CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED; 418#endif 419 CGEN_INSN_INT insn_value; 420 unsigned int attrs; 421 unsigned int word_offset, start, length, word_length, 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 507static int 508extract_insn_normal (cd, insn, ex_info, insn_value, fields, pc) 509 CGEN_CPU_DESC cd; 510 const CGEN_INSN *insn; 511 CGEN_EXTRACT_INFO *ex_info; 512 CGEN_INSN_INT insn_value; 513 CGEN_FIELDS *fields; 514 bfd_vma pc; 515{ 516 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn); 517 const CGEN_SYNTAX_CHAR_TYPE *syn; 518 519 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn); 520 521 CGEN_INIT_EXTRACT (cd); 522 523 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn) 524 { 525 int length; 526 527 if (CGEN_SYNTAX_CHAR_P (*syn)) 528 continue; 529 530 length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn), 531 ex_info, insn_value, fields, pc); 532 if (length <= 0) 533 return length; 534 } 535 536 /* We recognized and successfully extracted this insn. */ 537 return CGEN_INSN_BITSIZE (insn); 538} 539 540/* machine generated code added here */ 541