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