]> Git Repo - binutils.git/blob - gdb/hppa-pinsn.c
Add reminders for next release.
[binutils.git] / gdb / hppa-pinsn.c
1 /* Disassembler for the PA-RISC. Somewhat derived from sparc-pinsn.c.
2    Copyright 1989, 1990, 1992 Free Software Foundation, Inc.
3
4    Contributed by the Center for Software Science at the
5    University of Utah ([email protected]).
6
7 This file is part of GDB.
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 #include "defs.h"
24 #include "symtab.h"
25 #include "opcode/hppa.h"
26
27 static char *control_reg[] =
28 {  "rctr", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",
29    "pidr1", "pidr2", "ccr", "sar", "pidr3", "pidr4",
30    "iva", "eiem", "itmr", "pcsq", "pcoq", "iir", "isr",
31    "ior", "ipsw", "eirr", "tr0", "tr1", "tr2", "tr3",
32    "tr4", "tr5", "tr6", "tr7"
33    };
34
35 static char *compare_cond_names[] =
36 {  "", ",=", ",<", ",<=", ",<<", ",<<=", ",sv",
37    ",od", ",tr", ",<>", ",>=", ",>", ",>>=",
38    ",>>", ",nsv", ",ev"
39    };
40
41 static char *add_cond_names[] =
42 {  "", ",=", ",<", ",<=", ",nuv", ",znv", ",sv",
43    ",od", ",tr", ",<>", ",>=", ",>", ",uv",
44    ",vnz", ",nsv", ",ev"
45    };
46
47 static char *logical_cond_names[] =
48 {  "", ",=", ",<", ",<=", 0, 0, 0, ",od",
49    ",tr", ",<>", ",>=", ",>", 0, 0, 0, ",ev"
50    };
51
52 static char *unit_cond_names[] =
53 {  "", 0, ",sbz", ",shz", ",sdc", 0, ",sbc", ",shc",
54    ",tr", 0, ",nbz", ",nhz", ",ndc", 0, ",nbc", ",nhc"
55    };
56
57 static char *shift_cond_names[] =
58 {"", ",=", ",<", ",od", ",tr", ",<>", ",>=", ",ev"};
59
60 static char *index_compl_names[] = {"", ",m", ",s", ",sm"};
61 static char *short_ldst_compl_names[] = {"", ",ma", "", ",mb"};
62 static char *short_bytes_compl_names[] = {"", ",b,m", ",e", ",e,m"};
63 static char *float_format_names[] = {",sgl", ",dbl", ",quad"};
64 static char *float_comp_names[] =
65 {",false?", ",false", ",?", ",!<=>", ",=", ",=t", ",?=", ",!<>",
66  ",!?>=", ",<", ",?<", ",!>=", ",!?>", ",<=", ",?<=", ",!>",
67  ",!?<=", ",>", ",?>", ",!<=", ",!?<", ",>=", ",?>=", ",!<",
68  ",!?=", ",<>", ",!=", ",!=t", ",!?", ",<=>", ",true?", ",true"
69  };
70
71 /* For a bunch of different instructions form an index into a 
72    completer name table. */
73 #define GET_COMPL(insn) (GET_FIELD (insn, 26, 26) | \
74                          GET_FIELD (insn, 18, 18) << 1)
75
76 #define GET_COND(insn) (GET_FIELD ((insn), 16, 18) + \
77                         (GET_FIELD ((insn), 19, 19) ? 8 : 0))
78
79 static void fput_reg PARAMS ((unsigned reg, FILE *stream));
80 static void fput_const PARAMS ((unsigned num, FILE *stream));
81 static void fput_reg_r PARAMS ((unsigned reg, FILE *stream));
82 static void fput_creg PARAMS ((unsigned reg, FILE *stream));
83
84 /* Print one instruction from MEMADDR on STREAM.  */
85 int
86 print_insn (memaddr, stream)
87      CORE_ADDR memaddr;
88      FILE *stream;
89 {
90   long insn;
91   unsigned int i, op;
92
93   insn = read_memory_integer (memaddr, sizeof (insn));
94
95   for (i = 0; i < NUMOPCODES; ++i)
96     {
97       const struct pa_opcode *opcode = &pa_opcodes[i];
98       if ((insn & opcode->mask) == opcode->match)
99         {
100           register const char *s;
101           
102           fputs_filtered (opcode->name, stream);
103         
104           if (!index ("cCY<?!@-+&U>~nZFM", opcode->args[0]))
105             fputs_filtered (" ", stream);
106           for (s = opcode->args; *s != '\0'; ++s)
107             {
108               switch (*s)
109                 {
110                 case 'x':
111                   fput_reg (GET_FIELD (insn, 11, 15), stream);
112                   break;
113                 case 'X':
114                   if (GET_FIELD (insn, 25, 25))
115                       fput_reg_r (GET_FIELD (insn, 11, 15), stream);
116                   else
117                       fput_reg (GET_FIELD (insn, 11, 15), stream);
118                   break;
119                 case 'b':
120                   fput_reg (GET_FIELD (insn, 6, 10), stream);
121                   break;
122                 case '^':
123                   fput_creg (GET_FIELD (insn, 6, 10), stream);
124                   break;
125                 case 'E':
126                   if (GET_FIELD (insn, 25, 25))
127                       fput_reg_r (GET_FIELD (insn, 6, 10), stream);
128                   else
129                       fput_reg (GET_FIELD (insn, 6, 10), stream);
130                   break;
131                 case 't':
132                   fput_reg (GET_FIELD (insn, 27, 31), stream);
133                   break;
134                 case 'v':
135                   if (GET_FIELD (insn, 25, 25))
136                       fput_reg_r (GET_FIELD (insn, 27, 31), stream);
137                   else
138                       fput_reg (GET_FIELD (insn, 27, 31), stream);
139                   break;
140                 case '4':
141                   fput_creg (GET_FIELD (insn, 6, 10), stream);
142                   break;
143                 case '6':
144                   fput_reg (GET_FIELD (insn, 11, 15), stream);
145                   break;
146                 case '7':
147                   fput_reg (GET_FIELD (insn, 27, 31), stream);
148                   break;
149                 case '8':
150                   fput_reg (GET_FIELD (insn, 16, 20), stream);
151                   break;
152                 case '9':
153                   fput_reg (GET_FIELD (insn, 21, 25), stream);
154                   break;
155                 case '5':
156                   fput_const (extract_5_load (insn), stream);
157                   break;
158                   /* case 's': */
159                 case 'S':
160                   fprintf_filtered (stream, "sr%d", extract_3 (insn));
161                   break;
162                 case 'c':
163                   fprintf_filtered (stream, "%s ",
164                                     index_compl_names[GET_COMPL (insn)]);
165                   break;
166                 case 'C':
167                   fprintf_filtered (stream, "%s ",
168                                     short_ldst_compl_names[GET_COMPL (insn)]);
169                   break;
170                 case 'Y':
171                   fprintf_filtered (stream, "%s ",
172                                     short_bytes_compl_names[GET_COMPL (insn)]);
173                   break;
174                 /* these four conditions are for the set of instructions
175                    which distinguish true/false conditions by opcode rather
176                    than by the 'f' bit (sigh): comb, comib, addb, addib */
177                 case '<':
178                   fputs_filtered (compare_cond_names[GET_FIELD (insn, 16, 18)],
179                                   stream);
180                   break;
181                 case '?':
182                   fputs_filtered (compare_cond_names[GET_FIELD (insn, 16, 18) + 8],
183                                   stream);
184                   break;
185                 case '!':
186                   fputs_filtered (add_cond_names[GET_FIELD (insn, 16, 18)],
187                                   stream);
188                   break;
189                 case '@':
190                   fputs_filtered (add_cond_names[GET_FIELD (insn, 16, 18) + 8],
191                                   stream);
192                   break;
193                 case '-':
194                   fprintf_filtered (stream, "%s ",
195                                     compare_cond_names[GET_COND (insn)]);
196                   break;
197                 case '+':
198                   fprintf_filtered (stream, "%s ",
199                                     add_cond_names[GET_FIELD (insn, 16, 18)]);
200                   break;
201
202                 case '&':
203                   fprintf_filtered (stream, "%s ",
204                                     logical_cond_names[GET_COND (insn)]);
205                   break;
206                 case 'U':
207                   fprintf_filtered (stream, "%s ",
208                                     unit_cond_names[GET_COND (insn)]);
209                   break;
210                 case '>':
211                 case '~':
212                   fprintf_filtered (stream, "%s ",
213                                     shift_cond_names[GET_FIELD (insn, 16, 18)]);
214                   break;
215                 case 'V':
216                   fput_const (extract_5_store (insn), stream);
217                   break;
218                 case 'i':
219                   fput_const (extract_11 (insn), stream);
220                   break;
221                 case 'j':
222                   fput_const (extract_14 (insn), stream);
223                   break;
224                 case 'k':
225                   fput_const (extract_21 (insn), stream);
226                   break;
227                 case 'n':
228                   if (insn & 0x2)
229                     fprintf_filtered (stream, ",n ");
230                   else
231                     fprintf_filtered (stream, " ");
232                   break;
233                 case 'w':
234                   print_address (memaddr + 8 + extract_12 (insn), stream);
235                   break;
236                 case 'W':
237                   op = GET_FIELD (insn, 0, 5);
238
239                   if (op == 0x38 /* be */ || op == 0x39 /* ble */)
240                     fput_const (extract_17 (insn), stream);
241                   else
242                     print_address (memaddr + 8 + extract_17 (insn), stream);
243
244                   break;
245                 case 'B':
246                   {
247                     int space;
248                     if (space = GET_FIELD (insn, 16, 17))
249                       fprintf_filtered (stream, "sr%d,", space);
250                     fput_reg (GET_FIELD (insn, 6, 10), stream);
251                     break;
252                   }
253                 case 'p':
254                   fprintf_filtered (stream, "%d",
255                                     31 - GET_FIELD (insn, 22, 26));
256                   break;
257                 case 'P':
258                   fprintf_filtered (stream, "%d",
259                                     GET_FIELD (insn, 22, 26));
260                   break;
261                 case 'Q':
262                   fprintf_filtered (stream, "%d",
263                                     GET_FIELD (insn, 11, 15));
264                   break;
265                 case 'T':
266                   fprintf_filtered (stream, "%d",
267                                     32 - GET_FIELD (insn, 27, 31));
268                   break;
269                 case 'A':
270                   fput_const (GET_FIELD (insn, 6, 18), stream);
271                   break;
272                 case 'Z':
273                   if (GET_FIELD (insn, 26, 26))
274                     fprintf_filtered (stream, ",m ");
275                   else
276                     fprintf_filtered (stream, " ");
277                   break;
278                 case 'D':
279                   fput_const (GET_FIELD (insn, 6, 31), stream);
280                   break;
281                 case 'f':
282                   fprintf_filtered (stream, ",%d", GET_FIELD (insn, 23, 25));
283                   break;
284                 case 'O':
285                   fput_const ((GET_FIELD (insn, 6,20) << 5 |
286                                GET_FIELD (insn, 27, 31)), stream);
287                   break;
288                 case 'o':
289                   fput_const (GET_FIELD (insn, 6, 20), stream);
290                   break;
291                 case '2':
292                   fput_const ((GET_FIELD (insn, 6, 22) << 5 |
293                                GET_FIELD (insn, 27, 31)), stream);
294                   break;
295                 case '1':
296                   fput_const ((GET_FIELD (insn, 11, 20) << 5 |
297                                GET_FIELD (insn, 27, 31)), stream);
298                   break;
299                 case '0':
300                   fput_const ((GET_FIELD (insn, 16, 20) << 5 |
301                                GET_FIELD (insn, 27, 31)), stream);
302                   break;
303                 case 'u':
304                   fprintf_filtered (stream, "%d", GET_FIELD (insn, 23, 25));
305                   break;
306                 case 'F':
307                   /* if no destination completer, need a space here */
308                   if (GET_FIELD (insn, 21, 22) == 1)
309                     fputs_filtered (float_format_names[GET_FIELD (insn, 19, 20)],
310                                     stream);
311                   else
312                     fprintf_filtered (stream, "%s ",
313                                       float_format_names[GET_FIELD
314                                                          (insn, 19, 20)]);
315                   break;
316                 case 'G':
317                   fprintf_filtered (stream, "%s ",
318                                     float_format_names[GET_FIELD (insn,
319                                                                   17, 18)]);
320                   break;
321                 case 'H':
322                     fputs_filtered (float_format_names[GET_FIELD 
323                                                       (insn, 26, 26)], stream);
324                   break;
325                 case 'M':
326                   fputs_filtered (float_comp_names[GET_FIELD (insn, 27, 31)],
327                                   stream);
328                   break;
329                 case '}':
330                   fprintf_filtered (stream, "fp%d", GET_FIELD (insn, 6, 10));
331                   break;
332                 case '|':
333                   fprintf_filtered (stream, "fp%d", GET_FIELD (insn, 11, 15));
334                   break;
335                 case '{':
336                   if (GET_FIELD (insn, 23, 25) == 0)
337                     fprintf_filtered (stream, "fp%d",
338                                       GET_FIELD (insn, 27, 31));
339                   else
340                     fprintf_filtered (stream, "cp%d",
341                                       GET_FIELD (insn, 27, 31));
342                   break;
343                 default:
344                   fprintf_filtered (stream, "%c", *s);
345                   break;
346                 }
347             }
348
349 /* If this is an external branch, examine the previous instruction and see if
350    it was an ldil that loaded something into the same base reg.  If so, then
351    calculate the branch target from the constants in both instructions, and
352    print it out. */
353
354           op = GET_FIELD (insn, 0, 5);
355           if (op == 0x38 /* be */ || op == 0x39 /* ble */)
356             {
357               CORE_ADDR target_address;
358               long prev_insn;
359               int basereg, basereg_prev;
360
361               target_address = extract_17 (insn);
362               basereg = GET_FIELD (insn, 6, 10);
363               if (basereg != 0)
364                 {
365                   prev_insn = read_memory_integer (memaddr - 4,
366                                                    sizeof(prev_insn));
367                   basereg_prev = GET_FIELD (prev_insn, 6, 10);
368
369                   if ((prev_insn & 0xfc000000) == 0x20000000 /* ldil */
370                       && basereg == basereg_prev)
371                     target_address += extract_21 (prev_insn);
372                 }
373               fprintf_filtered (stream, "\t! ");
374               print_address (target_address, stream);
375             }
376
377           return sizeof(insn);
378         }
379     }
380   fprintf_filtered (stream, "%#8x", insn);
381   return sizeof(insn);
382 }
383   
384 /* Utility function to print registers */
385
386 static void
387 fput_reg (reg, stream)
388      unsigned reg;
389      FILE *stream;
390 {
391   if (reg)
392     fputs_filtered (reg_names[reg], stream);
393   else
394     fputs_filtered ("r0", stream);
395 }
396
397 void
398 fput_reg_r (reg, stream)
399      unsigned reg;
400      FILE *stream;
401 {
402   if (reg)
403     fputs_filtered (reg_names[reg], stream);
404   else
405     fputs_filtered ("r0", stream);
406   fputs_filtered ("R", stream);
407 }
408
409 void
410 fput_creg (reg, stream)
411      unsigned reg;
412      FILE *stream;
413 {
414   fputs_filtered (control_reg[reg], stream);
415 }
416
417 /* print constants with sign */
418
419 void
420 fput_const (num, stream)
421      unsigned num;
422      FILE *stream;
423 {
424   if ((int)num < 0)
425     fprintf_filtered (stream, "-%x", -(int)num);
426   else
427     fprintf_filtered (stream, "%x", num);
428 }
This page took 0.050989 seconds and 4 git commands to generate.