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 <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 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)); 52 53static 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 *)); 57static int extract_insn_normal 58 PARAMS ((CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *, 59 CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma)); 60static void put_insn_int_value 61 PARAMS ((CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT)); 62 63 64/* Operand insertion. */ 65 66#if ! CGEN_INT_INSN_P 67 68/* Subroutine of insert_normal. */ 69 70static CGEN_INLINE void 71insert_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 112static const char * 113insert_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 206 (meaning that if CGEN_INT_INSN_P BUFFER is an int * and thus the value is 207 recorded in host byte order, otherwise BUFFER is an array of bytes and the 208 value is recorded in target byte order). 209 The result is an error message or NULL if success. */ 210 211static const char * 212insert_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 266static void 267put_insn_int_value (cd, buf, length, insn_length, value) 268 CGEN_CPU_DESC cd; 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 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 297static CGEN_INLINE int 298fill_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 341static CGEN_INLINE long 342extract_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 384static int 385extract_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? */ 432 433 if (CGEN_INT_INSN_P || word_offset == 0) 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 481static int 482extract_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 514/* machine generated code added here */ 515