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