* Patches from Jeffrey Law <law@cs.utah.edu>.
[deliverable/binutils-gdb.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 (pa-gdb-bugs@cs.utah.edu).
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 'r':
219 fput_const (extract_5r_store (insn), stream);
220 break;
221 case 'R':
222 fput_const (extract_5R_store (insn), stream);
223 break;
224 case 'i':
225 fput_const (extract_11 (insn), stream);
226 break;
227 case 'j':
228 fput_const (extract_14 (insn), stream);
229 break;
230 case 'k':
231 fput_const (extract_21 (insn), stream);
232 break;
233 case 'n':
234 if (insn & 0x2)
235 fprintf_filtered (stream, ",n ");
236 else
237 fprintf_filtered (stream, " ");
238 break;
239 case 'w':
240 print_address (memaddr + 8 + extract_12 (insn), stream);
241 break;
242 case 'W':
243 op = GET_FIELD (insn, 0, 5);
244
245 if (op == 0x38 /* be */ || op == 0x39 /* ble */)
246 fput_const (extract_17 (insn), stream);
247 else
248 print_address (memaddr + 8 + extract_17 (insn), stream);
249
250 break;
251 case 'B':
252 {
253 int space;
254 if (space = GET_FIELD (insn, 16, 17))
255 fprintf_filtered (stream, "sr%d,", space);
256 fput_reg (GET_FIELD (insn, 6, 10), stream);
257 break;
258 }
259 case 'p':
260 fprintf_filtered (stream, "%d",
261 31 - GET_FIELD (insn, 22, 26));
262 break;
263 case 'P':
264 fprintf_filtered (stream, "%d",
265 GET_FIELD (insn, 22, 26));
266 break;
267 case 'Q':
268 fprintf_filtered (stream, "%d",
269 GET_FIELD (insn, 11, 15));
270 break;
271 case 'T':
272 fprintf_filtered (stream, "%d",
273 32 - GET_FIELD (insn, 27, 31));
274 break;
275 case 'A':
276 fput_const (GET_FIELD (insn, 6, 18), stream);
277 break;
278 case 'Z':
279 if (GET_FIELD (insn, 26, 26))
280 fprintf_filtered (stream, ",m ");
281 else
282 fprintf_filtered (stream, " ");
283 break;
284 case 'D':
285 fput_const (GET_FIELD (insn, 6, 31), stream);
286 break;
287 case 'f':
288 fprintf_filtered (stream, ",%d", GET_FIELD (insn, 23, 25));
289 break;
290 case 'O':
291 fput_const ((GET_FIELD (insn, 6,20) << 5 |
292 GET_FIELD (insn, 27, 31)), stream);
293 break;
294 case 'o':
295 fput_const (GET_FIELD (insn, 6, 20), stream);
296 break;
297 case '2':
298 fput_const ((GET_FIELD (insn, 6, 22) << 5 |
299 GET_FIELD (insn, 27, 31)), stream);
300 break;
301 case '1':
302 fput_const ((GET_FIELD (insn, 11, 20) << 5 |
303 GET_FIELD (insn, 27, 31)), stream);
304 break;
305 case '0':
306 fput_const ((GET_FIELD (insn, 16, 20) << 5 |
307 GET_FIELD (insn, 27, 31)), stream);
308 break;
309 case 'u':
310 fprintf_filtered (stream, "%d", GET_FIELD (insn, 23, 25));
311 break;
312 case 'F':
313 /* if no destination completer, need a space here */
314 if (GET_FIELD (insn, 21, 22) == 1)
315 fputs_filtered (float_format_names[GET_FIELD (insn, 19, 20)],
316 stream);
317 else
318 fprintf_filtered (stream, "%s ",
319 float_format_names[GET_FIELD
320 (insn, 19, 20)]);
321 break;
322 case 'G':
323 fprintf_filtered (stream, "%s ",
324 float_format_names[GET_FIELD (insn,
325 17, 18)]);
326 break;
327 case 'H':
328 fputs_filtered (float_format_names[GET_FIELD
329 (insn, 26, 26)], stream);
330 break;
331 case 'M':
332 fputs_filtered (float_comp_names[GET_FIELD (insn, 27, 31)],
333 stream);
334 break;
335 case '}':
336 fprintf_filtered (stream, "fp%d", GET_FIELD (insn, 6, 10));
337 break;
338 case '|':
339 fprintf_filtered (stream, "fp%d", GET_FIELD (insn, 11, 15));
340 break;
341 case '{':
342 if (GET_FIELD (insn, 23, 25) == 0)
343 fprintf_filtered (stream, "fp%d",
344 GET_FIELD (insn, 27, 31));
345 else
346 fprintf_filtered (stream, "cp%d",
347 GET_FIELD (insn, 27, 31));
348 break;
349 default:
350 fprintf_filtered (stream, "%c", *s);
351 break;
352 }
353 }
354
355 /* If this is an external branch, examine the previous instruction and see if
356 it was an ldil that loaded something into the same base reg. If so, then
357 calculate the branch target from the constants in both instructions, and
358 print it out. */
359
360 op = GET_FIELD (insn, 0, 5);
361 if (op == 0x38 /* be */ || op == 0x39 /* ble */)
362 {
363 CORE_ADDR target_address;
364 long prev_insn;
365 int basereg, basereg_prev;
366
367 target_address = extract_17 (insn);
368 basereg = GET_FIELD (insn, 6, 10);
369 if (basereg != 0)
370 {
371 prev_insn = read_memory_integer (memaddr - 4,
372 sizeof(prev_insn));
373 basereg_prev = GET_FIELD (prev_insn, 6, 10);
374
375 if ((prev_insn & 0xfc000000) == 0x20000000 /* ldil */
376 && basereg == basereg_prev)
377 target_address += extract_21 (prev_insn);
378 }
379 fprintf_filtered (stream, "\t! ");
380 print_address (target_address, stream);
381 }
382
383 return sizeof(insn);
384 }
385 }
386 fprintf_filtered (stream, "%#8x", insn);
387 return sizeof(insn);
388 }
389
390 /* Utility function to print registers */
391
392 static void
393 fput_reg (reg, stream)
394 unsigned reg;
395 FILE *stream;
396 {
397 if (reg)
398 fputs_filtered (reg_names[reg], stream);
399 else
400 fputs_filtered ("r0", stream);
401 }
402
403 void
404 fput_reg_r (reg, stream)
405 unsigned reg;
406 FILE *stream;
407 {
408 if (reg)
409 fputs_filtered (reg_names[reg], stream);
410 else
411 fputs_filtered ("r0", stream);
412 fputs_filtered ("R", stream);
413 }
414
415 void
416 fput_creg (reg, stream)
417 unsigned reg;
418 FILE *stream;
419 {
420 fputs_filtered (control_reg[reg], stream);
421 }
422
423 /* print constants with sign */
424
425 void
426 fput_const (num, stream)
427 unsigned num;
428 FILE *stream;
429 {
430 if ((int)num < 0)
431 fprintf_filtered (stream, "-%x", -(int)num);
432 else
433 fprintf_filtered (stream, "%x", num);
434 }
This page took 0.040611 seconds and 5 git commands to generate.