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