* hppa-pinsn.c (print_insn): Improve handling of be and ble
[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 unsigned int insn, i, op;
91
92 read_memory (memaddr, &insn, sizeof (insn));
93
94 for (i = 0; i < NUMOPCODES; ++i)
95 {
96 const struct pa_opcode *opcode = &pa_opcodes[i];
97 if ((insn & opcode->mask) == opcode->match)
98 {
99 register const char *s;
100
101 fputs_filtered (opcode->name, stream);
102
103 if (!index ("cCY<?!@-+&U>~nZFM", opcode->args[0]))
104 fputs_filtered (" ", stream);
105 for (s = opcode->args; *s != '\0'; ++s)
106 {
107 switch (*s)
108 {
109 case 'x':
110 fput_reg (GET_FIELD (insn, 11, 15), stream);
111 break;
112 case 'X':
113 if (GET_FIELD (insn, 25, 25))
114 fput_reg_r (GET_FIELD (insn, 11, 15), stream);
115 else
116 fput_reg (GET_FIELD (insn, 11, 15), stream);
117 break;
118 case 'b':
119 fput_reg (GET_FIELD (insn, 6, 10), stream);
120 break;
121 case '^':
122 fput_creg (GET_FIELD (insn, 6, 10), stream);
123 break;
124 case 'E':
125 if (GET_FIELD (insn, 25, 25))
126 fput_reg_r (GET_FIELD (insn, 6, 10), stream);
127 else
128 fput_reg (GET_FIELD (insn, 6, 10), stream);
129 break;
130 case 't':
131 fput_reg (GET_FIELD (insn, 27, 31), stream);
132 break;
133 case 'v':
134 if (GET_FIELD (insn, 25, 25))
135 fput_reg_r (GET_FIELD (insn, 27, 31), stream);
136 else
137 fput_reg (GET_FIELD (insn, 27, 31), stream);
138 break;
139 case '4':
140 fput_creg (GET_FIELD (insn, 6, 10), stream);
141 break;
142 case '6':
143 fput_reg (GET_FIELD (insn, 11, 15), stream);
144 break;
145 case '7':
146 fput_reg (GET_FIELD (insn, 27, 31), stream);
147 break;
148 case '8':
149 fput_reg (GET_FIELD (insn, 16, 20), stream);
150 break;
151 case '9':
152 fput_reg (GET_FIELD (insn, 21, 25), stream);
153 break;
154 case '5':
155 fput_const (extract_5_load (insn), stream);
156 break;
157 /* case 's': */
158 case 'S':
159 fprintf_filtered (stream, "sr%d", extract_3 (insn));
160 break;
161 case 'c':
162 fprintf_filtered (stream, "%s ",
163 index_compl_names[GET_COMPL (insn)]);
164 break;
165 case 'C':
166 fprintf_filtered (stream, "%s ",
167 short_ldst_compl_names[GET_COMPL (insn)]);
168 break;
169 case 'Y':
170 fprintf_filtered (stream, "%s ",
171 short_bytes_compl_names[GET_COMPL (insn)]);
172 break;
173 /* these four conditions are for the set of instructions
174 which distinguish true/false conditions by opcode rather
175 than by the 'f' bit (sigh): comb, comib, addb, addib */
176 case '<':
177 fputs_filtered (compare_cond_names[GET_FIELD (insn, 16, 18)],
178 stream);
179 break;
180 case '?':
181 fputs_filtered (compare_cond_names[GET_FIELD (insn, 16, 18) + 8],
182 stream);
183 break;
184 case '!':
185 fputs_filtered (add_cond_names[GET_FIELD (insn, 16, 18)],
186 stream);
187 break;
188 case '@':
189 fputs_filtered (add_cond_names[GET_FIELD (insn, 16, 18) + 8],
190 stream);
191 break;
192 case '-':
193 fprintf_filtered (stream, "%s ",
194 compare_cond_names[GET_COND (insn)]);
195 break;
196 case '+':
197 fprintf_filtered (stream, "%s ",
198 add_cond_names[GET_FIELD (insn, 16, 18)]);
199 break;
200
201 case '&':
202 fprintf_filtered (stream, "%s ",
203 logical_cond_names[GET_COND (insn)]);
204 break;
205 case 'U':
206 fprintf_filtered (stream, "%s ",
207 unit_cond_names[GET_COND (insn)]);
208 break;
209 case '>':
210 case '~':
211 fprintf_filtered (stream, "%s ",
212 shift_cond_names[GET_FIELD (insn, 16, 18)]);
213 break;
214 case 'V':
215 fput_const (extract_5_store (insn), stream);
216 break;
217 case 'i':
218 fput_const (extract_11 (insn), stream);
219 break;
220 case 'j':
221 fput_const (extract_14 (insn), stream);
222 break;
223 case 'k':
224 fput_const (extract_21 (insn), stream);
225 break;
226 case 'n':
227 if (insn & 0x2)
228 fprintf_filtered (stream, ",n ");
229 else
230 fprintf_filtered (stream, " ");
231 break;
232 case 'w':
233 print_address (memaddr + 8 + extract_12 (insn), stream);
234 break;
235 case 'W':
236 op = GET_FIELD (insn, 0, 5);
237
238 if (op == 0x38 /* be */ || op == 0x39 /* ble */)
239 fput_const (extract_17 (insn), stream);
240 else
241 print_address (memaddr + 8 + extract_17 (insn), stream);
242
243 break;
244 case 'B':
245 {
246 int space;
247 if (space = GET_FIELD (insn, 16, 17))
248 fprintf_filtered (stream, "sr%d,", space);
249 fput_reg (GET_FIELD (insn, 6, 10), stream);
250 break;
251 }
252 case 'p':
253 fprintf_filtered (stream, "%d",
254 31 - GET_FIELD (insn, 22, 26));
255 break;
256 case 'P':
257 fprintf_filtered (stream, "%d",
258 GET_FIELD (insn, 22, 26));
259 break;
260 case 'Q':
261 fprintf_filtered (stream, "%d",
262 GET_FIELD (insn, 11, 15));
263 break;
264 case 'T':
265 fprintf_filtered (stream, "%d",
266 32 - GET_FIELD (insn, 27, 31));
267 break;
268 case 'A':
269 fput_const (GET_FIELD (insn, 6, 18), stream);
270 break;
271 case 'Z':
272 if (GET_FIELD (insn, 26, 26))
273 fprintf_filtered (stream, ",m ");
274 else
275 fprintf_filtered (stream, " ");
276 break;
277 case 'D':
278 fput_const (GET_FIELD (insn, 6, 31), stream);
279 break;
280 case 'f':
281 fprintf_filtered (stream, ",%d", GET_FIELD (insn, 23, 25));
282 break;
283 case 'O':
284 fput_const ((GET_FIELD (insn, 6,20) << 5 |
285 GET_FIELD (insn, 27, 31)), stream);
286 break;
287 case 'o':
288 fput_const (GET_FIELD (insn, 6, 20), stream);
289 break;
290 case '2':
291 fput_const ((GET_FIELD (insn, 6, 22) << 5 |
292 GET_FIELD (insn, 27, 31)), stream);
293 break;
294 case '1':
295 fput_const ((GET_FIELD (insn, 11, 20) << 5 |
296 GET_FIELD (insn, 27, 31)), stream);
297 break;
298 case '0':
299 fput_const ((GET_FIELD (insn, 16, 20) << 5 |
300 GET_FIELD (insn, 27, 31)), stream);
301 break;
302 case 'u':
303 fprintf_filtered (stream, "%d", GET_FIELD (insn, 23, 25));
304 break;
305 case 'F':
306 /* if no destination completer, need a space here */
307 if (GET_FIELD (insn, 21, 22) == 1)
308 fputs_filtered (float_format_names[GET_FIELD (insn, 19, 20)],
309 stream);
310 else
311 fprintf_filtered (stream, "%s ",
312 float_format_names[GET_FIELD
313 (insn, 19, 20)]);
314 break;
315 case 'G':
316 fprintf_filtered (stream, "%s ",
317 float_format_names[GET_FIELD (insn,
318 17, 18)]);
319 break;
320 case 'H':
321 fputs_filtered (float_format_names[GET_FIELD
322 (insn, 26, 26)], stream);
323 break;
324 case 'M':
325 fputs_filtered (float_comp_names[GET_FIELD (insn, 27, 31)],
326 stream);
327 break;
328 case '}':
329 fprintf_filtered (stream, "fp%d", GET_FIELD (insn, 6, 10));
330 break;
331 case '|':
332 fprintf_filtered (stream, "fp%d", GET_FIELD (insn, 11, 15));
333 break;
334 case '{':
335 if (GET_FIELD (insn, 23, 25) == 0)
336 fprintf_filtered (stream, "fp%d",
337 GET_FIELD (insn, 27, 31));
338 else
339 fprintf_filtered (stream, "cp%d",
340 GET_FIELD (insn, 27, 31));
341 break;
342 default:
343 fprintf_filtered (stream, "%c", *s);
344 break;
345 }
346 }
347
348 /* If this is an external branch, examine the previous instruction and see if
349 it was an ldil that loaded something into the same base reg. If so, then
350 calculate the branch target from the constants in both instructions, and
351 print it out. */
352
353 op = GET_FIELD (insn, 0, 5);
354 if (op == 0x38 /* be */ || op == 0x39 /* ble */)
355 {
356 CORE_ADDR target_address;
357 unsigned int prev_insn;
358 int basereg, basereg_prev;
359
360 target_address = extract_17 (insn);
361 basereg = GET_FIELD (insn, 6, 10);
362 if (basereg != 0)
363 {
364 read_memory (memaddr - 4, &prev_insn, sizeof(prev_insn));
365 basereg_prev = GET_FIELD (prev_insn, 6, 10);
366
367 if ((prev_insn & 0xfc000000) == 0x20000000 /* ldil */
368 && basereg == basereg_prev)
369 target_address += extract_21 (prev_insn);
370 }
371 fprintf_filtered (stream, "\t! ");
372 print_address (target_address, stream);
373 }
374
375 return sizeof(insn);
376 }
377 }
378 fprintf_filtered (stream, "%#8x", insn);
379 return sizeof(insn);
380 }
381
382 /* Utility function to print registers */
383
384 static void
385 fput_reg (reg, stream)
386 unsigned reg;
387 FILE *stream;
388 {
389 if (reg)
390 fputs_filtered (reg_names[reg], stream);
391 else
392 fputs_filtered ("r0", stream);
393 }
394
395 void
396 fput_reg_r (reg, stream)
397 unsigned reg;
398 FILE *stream;
399 {
400 if (reg)
401 fputs_filtered (reg_names[reg], stream);
402 else
403 fputs_filtered ("r0", stream);
404 fputs_filtered ("R", stream);
405 }
406
407 void
408 fput_creg (reg, stream)
409 unsigned reg;
410 FILE *stream;
411 {
412 fputs_filtered (control_reg[reg], stream);
413 }
414
415 /* print constants with sign */
416
417 void
418 fput_const (num, stream)
419 unsigned num;
420 FILE *stream;
421 {
422 if ((int)num < 0)
423 fprintf_filtered (stream, "-%x", -(int)num);
424 else
425 fprintf_filtered (stream, "%x", num);
426 }
This page took 0.04605 seconds and 5 git commands to generate.