libhppa.h revision 1.1
1/* HP PA-RISC SOM object file format: definitions internal to BFD. 2 Copyright (C) 1990, 91, 92, 93, 94 Free Software Foundation, Inc. 3 4 Contributed by the Center for Software Science at the 5 University of Utah (pa-gdb-bugs@cs.utah.edu). 6 7 This file is part of BFD, the Binary File Descriptor library. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 22 23#ifndef _HPPA_H 24#define _HPPA_H 25 26#define BYTES_IN_WORD 4 27#define PA_PAGESIZE 0x1000 28 29#ifndef INLINE 30#ifdef __GNUC__ 31#define INLINE inline 32#else 33#define INLINE 34#endif /* GNU C? */ 35#endif /* INLINE */ 36 37/* The PA instruction set variants. */ 38enum pa_arch {pa10 = 10, pa11 = 11}; 39 40/* HP PA-RISC relocation types */ 41 42enum hppa_reloc_field_selector_type 43 { 44 R_HPPA_FSEL = 0x0, 45 R_HPPA_LSSEL = 0x1, 46 R_HPPA_RSSEL = 0x2, 47 R_HPPA_LSEL = 0x3, 48 R_HPPA_RSEL = 0x4, 49 R_HPPA_LDSEL = 0x5, 50 R_HPPA_RDSEL = 0x6, 51 R_HPPA_LRSEL = 0x7, 52 R_HPPA_RRSEL = 0x8, 53 R_HPPA_PSEL = 0x9, 54 R_HPPA_LPSEL = 0xa, 55 R_HPPA_RPSEL = 0xb, 56 R_HPPA_TSEL = 0xc, 57 R_HPPA_LTSEL = 0xd, 58 R_HPPA_RTSEL = 0xe 59 }; 60 61/* /usr/include/reloc.h defines these to constants. We want to use 62 them in enums, so #undef them before we start using them. We might 63 be able to fix this another way by simply managing not to include 64 /usr/include/reloc.h, but currently GDB picks up these defines 65 somewhere. */ 66#undef e_fsel 67#undef e_lssel 68#undef e_rssel 69#undef e_lsel 70#undef e_rsel 71#undef e_ldsel 72#undef e_rdsel 73#undef e_lrsel 74#undef e_rrsel 75#undef e_psel 76#undef e_lpsel 77#undef e_rpsel 78#undef e_tsel 79#undef e_ltsel 80#undef e_rtsel 81#undef e_one 82#undef e_two 83#undef e_pcrel 84#undef e_con 85#undef e_plabel 86#undef e_abs 87 88/* for compatibility */ 89enum hppa_reloc_field_selector_type_alt 90 { 91 e_fsel = R_HPPA_FSEL, 92 e_lssel = R_HPPA_LSSEL, 93 e_rssel = R_HPPA_RSSEL, 94 e_lsel = R_HPPA_LSEL, 95 e_rsel = R_HPPA_RSEL, 96 e_ldsel = R_HPPA_LDSEL, 97 e_rdsel = R_HPPA_RDSEL, 98 e_lrsel = R_HPPA_LRSEL, 99 e_rrsel = R_HPPA_RRSEL, 100 e_psel = R_HPPA_PSEL, 101 e_lpsel = R_HPPA_LPSEL, 102 e_rpsel = R_HPPA_RPSEL, 103 e_tsel = R_HPPA_TSEL, 104 e_ltsel = R_HPPA_LTSEL, 105 e_rtsel = R_HPPA_RTSEL 106 }; 107 108enum hppa_reloc_expr_type 109 { 110 R_HPPA_E_ONE = 0, 111 R_HPPA_E_TWO = 1, 112 R_HPPA_E_PCREL = 2, 113 R_HPPA_E_CON = 3, 114 R_HPPA_E_PLABEL = 7, 115 R_HPPA_E_ABS = 18 116 }; 117 118/* for compatibility */ 119enum hppa_reloc_expr_type_alt 120 { 121 e_one = R_HPPA_E_ONE, 122 e_two = R_HPPA_E_TWO, 123 e_pcrel = R_HPPA_E_PCREL, 124 e_con = R_HPPA_E_CON, 125 e_plabel = R_HPPA_E_PLABEL, 126 e_abs = R_HPPA_E_ABS 127 }; 128 129 130/* Relocations for function calls must be accompanied by parameter 131 relocation bits. These bits describe exactly where the caller has 132 placed the function's arguments and where it expects to find a return 133 value. 134 135 Both ELF and SOM encode this information within the addend field 136 of the call relocation. (Note this could break very badly if one 137 was to make a call like bl foo + 0x12345678). 138 139 The high order 10 bits contain parameter relocation information, 140 the low order 22 bits contain the constant offset. */ 141 142#define HPPA_R_ARG_RELOC(a) (((a) >> 22) & 0x3FF) 143#define HPPA_R_CONSTANT(a) ((((int)(a)) << 10) >> 10) 144#define HPPA_R_ADDEND(r,c) (((r) << 22) + ((c) & 0x3FFFFF)) 145 146/* Some functions to manipulate PA instructions. */ 147static INLINE unsigned int 148assemble_3 (x) 149 unsigned int x; 150{ 151 return (((x & 1) << 2) | ((x & 6) >> 1)) & 7; 152} 153 154static INLINE void 155dis_assemble_3 (x, r) 156 unsigned int x; 157 unsigned int *r; 158{ 159 *r = (((x & 4) >> 2) | ((x & 3) << 1)) & 7; 160} 161 162static INLINE unsigned int 163assemble_12 (x, y) 164 unsigned int x, y; 165{ 166 return (((y & 1) << 11) | ((x & 1) << 10) | ((x & 0x7fe) >> 1)) & 0xfff; 167} 168 169static INLINE void 170dis_assemble_12 (as12, x, y) 171 unsigned int as12; 172 unsigned int *x, *y; 173{ 174 *y = (as12 & 0x800) >> 11; 175 *x = ((as12 & 0x3ff) << 1) | ((as12 & 0x400) >> 10); 176} 177 178static INLINE unsigned long 179assemble_17 (x, y, z) 180 unsigned int x, y, z; 181{ 182 unsigned long temp; 183 184 temp = ((z & 1) << 16) | 185 ((x & 0x1f) << 11) | 186 ((y & 1) << 10) | 187 ((y & 0x7fe) >> 1); 188 return temp & 0x1ffff; 189} 190 191static INLINE void 192dis_assemble_17 (as17, x, y, z) 193 unsigned int as17; 194 unsigned int *x, *y, *z; 195{ 196 197 *z = (as17 & 0x10000) >> 16; 198 *x = (as17 & 0x0f800) >> 11; 199 *y = (((as17 & 0x00400) >> 10) | ((as17 & 0x3ff) << 1)) & 0x7ff; 200} 201 202static INLINE unsigned long 203assemble_21 (x) 204 unsigned int x; 205{ 206 unsigned long temp; 207 208 temp = ((x & 1) << 20) | 209 ((x & 0xffe) << 8) | 210 ((x & 0xc000) >> 7) | 211 ((x & 0x1f0000) >> 14) | 212 ((x & 0x003000) >> 12); 213 return temp & 0x1fffff; 214} 215 216static INLINE void 217dis_assemble_21 (as21, x) 218 unsigned int as21, *x; 219{ 220 unsigned long temp; 221 222 223 temp = (as21 & 0x100000) >> 20; 224 temp |= (as21 & 0x0ffe00) >> 8; 225 temp |= (as21 & 0x000180) << 7; 226 temp |= (as21 & 0x00007c) << 14; 227 temp |= (as21 & 0x000003) << 12; 228 *x = temp; 229} 230 231static INLINE unsigned long 232sign_extend (x, len) 233 unsigned int x, len; 234{ 235 return (int)(x >> (len - 1) ? (-1 << len) | x : x); 236} 237 238static INLINE unsigned int 239ones (n) 240 int n; 241{ 242 unsigned int len_ones; 243 int i; 244 245 i = 0; 246 len_ones = 0; 247 while (i < n) 248 { 249 len_ones = (len_ones << 1) | 1; 250 i++; 251 } 252 253 return len_ones; 254} 255 256static INLINE void 257sign_unext (x, len, result) 258 unsigned int x, len; 259 unsigned int *result; 260{ 261 unsigned int len_ones; 262 263 len_ones = ones (len); 264 265 *result = x & len_ones; 266} 267 268static INLINE unsigned long 269low_sign_extend (x, len) 270 unsigned int x, len; 271{ 272 return (int)((x & 0x1 ? (-1 << (len - 1)) : 0) | x >> 1); 273} 274 275static INLINE void 276low_sign_unext (x, len, result) 277 unsigned int x, len; 278 unsigned int *result; 279{ 280 unsigned int temp; 281 unsigned int sign; 282 unsigned int rest; 283 unsigned int one_bit_at_len; 284 unsigned int len_ones; 285 286 len_ones = ones (len); 287 one_bit_at_len = 1 << (len - 1); 288 289 sign_unext (x, len, &temp); 290 sign = temp & one_bit_at_len; 291 sign >>= (len - 1); 292 293 rest = temp & (len_ones ^ one_bit_at_len); 294 rest <<= 1; 295 296 *result = rest | sign; 297} 298 299/* Handle field selectors for PA instructions. */ 300 301static INLINE unsigned long 302hppa_field_adjust (value, constant_value, r_field) 303 unsigned long value; 304 unsigned long constant_value; 305 unsigned short r_field; 306{ 307 switch (r_field) 308 { 309 case e_fsel: /* F : no change */ 310 value += constant_value; 311 break; 312 313 case e_lssel: /* LS : if (bit 21) then add 0x800 314 arithmetic shift right 11 bits */ 315 value += constant_value; 316 if (value & 0x00000400) 317 value += 0x800; 318 value = (value & 0xfffff800) >> 11; 319 break; 320 321 case e_rssel: /* RS : Sign extend from bit 21 */ 322 value += constant_value; 323 if (value & 0x00000400) 324 value |= 0xfffff800; 325 else 326 value &= 0x7ff; 327 break; 328 329 case e_lsel: /* L : Arithmetic shift right 11 bits */ 330 value += constant_value; 331 value = (value & 0xfffff800) >> 11; 332 break; 333 334 case e_rsel: /* R : Set bits 0-20 to zero */ 335 value += constant_value; 336 value = value & 0x7ff; 337 break; 338 339 case e_ldsel: /* LD : Add 0x800, arithmetic shift 340 right 11 bits */ 341 value += constant_value; 342 value += 0x800; 343 value = (value & 0xfffff800) >> 11; 344 break; 345 346 case e_rdsel: /* RD : Set bits 0-20 to one */ 347 value += constant_value; 348 value |= 0xfffff800; 349 break; 350 351 case e_lrsel: /* LR : L with "rounded" constant */ 352 value = value + ((constant_value + 0x1000) & 0xffffe000); 353 value = (value & 0xfffff800) >> 11; 354 break; 355 356 case e_rrsel: /* RR : R with "rounded" constant */ 357 value = value + ((constant_value + 0x1000) & 0xffffe000); 358 value = (value & 0x7ff) + constant_value - ((constant_value + 0x1000) & 0xffffe000); 359 break; 360 361 default: 362 abort (); 363 } 364 return value; 365 366} 367 368/* PA-RISC OPCODES */ 369#define get_opcode(insn) ((insn) & 0xfc000000) >> 26 370 371/* FIXME: this list is incomplete. It should also be an enumerated 372 type rather than #defines. */ 373 374#define LDO 0x0d 375#define LDB 0x10 376#define LDH 0x11 377#define LDW 0x12 378#define LDWM 0x13 379#define STB 0x18 380#define STH 0x19 381#define STW 0x1a 382#define STWM 0x1b 383#define COMICLR 0x24 384#define SUBI 0x25 385#define SUBIO 0x25 386#define ADDIT 0x2c 387#define ADDITO 0x2c 388#define ADDI 0x2d 389#define ADDIO 0x2d 390#define LDIL 0x08 391#define ADDIL 0x0a 392 393#define MOVB 0x32 394#define MOVIB 0x33 395#define COMBT 0x20 396#define COMBF 0x22 397#define COMIBT 0x21 398#define COMIBF 0x23 399#define ADDBT 0x28 400#define ADDBF 0x2a 401#define ADDIBT 0x29 402#define ADDIBF 0x2b 403#define BVB 0x30 404#define BB 0x31 405 406#define BL 0x3a 407#define BLE 0x39 408#define BE 0x38 409 410 411/* Given a machine instruction, return its format. 412 413 FIXME: opcodes which do not map to a known format 414 should return an error of some sort. */ 415 416static INLINE char 417bfd_hppa_insn2fmt (insn) 418 unsigned long insn; 419{ 420 char fmt = -1; 421 unsigned char op = get_opcode (insn); 422 423 switch (op) 424 { 425 case ADDI: 426 case ADDIT: 427 case SUBI: 428 fmt = 11; 429 break; 430 case MOVB: 431 case MOVIB: 432 case COMBT: 433 case COMBF: 434 case COMIBT: 435 case COMIBF: 436 case ADDBT: 437 case ADDBF: 438 case ADDIBT: 439 case ADDIBF: 440 case BVB: 441 case BB: 442 fmt = 12; 443 break; 444 case LDO: 445 case LDB: 446 case LDH: 447 case LDW: 448 case LDWM: 449 case STB: 450 case STH: 451 case STW: 452 case STWM: 453 fmt = 14; 454 break; 455 case BL: 456 case BE: 457 case BLE: 458 fmt = 17; 459 break; 460 case LDIL: 461 case ADDIL: 462 fmt = 21; 463 break; 464 default: 465 fmt = 32; 466 break; 467 } 468 return fmt; 469} 470 471 472/* Insert VALUE into INSN using R_FORMAT to determine exactly what 473 bits to change. */ 474 475static INLINE unsigned long 476hppa_rebuild_insn (abfd, insn, value, r_format) 477 bfd *abfd; 478 unsigned long insn; 479 unsigned long value; 480 unsigned long r_format; 481{ 482 unsigned long const_part; 483 unsigned long rebuilt_part; 484 485 switch (r_format) 486 { 487 case 11: 488 { 489 unsigned w1, w; 490 491 const_part = insn & 0xffffe002; 492 dis_assemble_12 (value, &w1, &w); 493 rebuilt_part = (w1 << 2) | w; 494 return const_part | rebuilt_part; 495 } 496 497 case 12: 498 { 499 unsigned w1, w; 500 501 const_part = insn & 0xffffe002; 502 dis_assemble_12 (value, &w1, &w); 503 rebuilt_part = (w1 << 2) | w; 504 return const_part | rebuilt_part; 505 } 506 507 case 14: 508 const_part = insn & 0xffffc000; 509 low_sign_unext (value, 14, &rebuilt_part); 510 return const_part | rebuilt_part; 511 512 case 17: 513 { 514 unsigned w1, w2, w; 515 516 const_part = insn & 0xffe0e002; 517 dis_assemble_17 (value, &w1, &w2, &w); 518 rebuilt_part = (w2 << 2) | (w1 << 16) | w; 519 return const_part | rebuilt_part; 520 } 521 522 case 21: 523 const_part = insn & 0xffe00000; 524 dis_assemble_21 (value, &rebuilt_part); 525 return const_part | rebuilt_part; 526 527 case 32: 528 const_part = 0; 529 return value; 530 531 default: 532 abort (); 533 } 534 return insn; 535} 536 537#endif /* _HPPA_H */ 538