1 /* Disassembler for the PA-RISC. Somewhat derived from sparc-pinsn.c.
2 Copyright 1989, 1990, 1992 Free Software Foundation, Inc.
4 Contributed by the Center for Software Science at the
7 This file is part of GDB.
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.
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.
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. */
26 #include "opcode/hppa.h"
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"
36 static char *compare_cond_names[] =
37 { "", ",=", ",<", ",<=", ",<<", ",<<=", ",sv",
38 ",od", ",tr", ",<>", ",>=", ",>", ",>>=",
42 static char *add_cond_names[] =
43 { "", ",=", ",<", ",<=", ",nuv", ",znv", ",sv",
44 ",od", ",tr", ",<>", ",>=", ",>", ",uv",
48 static char *logical_cond_names[] =
49 { "", ",=", ",<", ",<=", 0, 0, 0, ",od",
50 ",tr", ",<>", ",>=", ",>", 0, 0, 0, ",ev"
53 static char *unit_cond_names[] =
54 { "", 0, ",sbz", ",shz", ",sdc", 0, ",sbc", ",shc",
55 ",tr", 0, ",nbz", ",nhz", ",ndc", 0, ",nbc", ",nhc"
58 static char *shift_cond_names[] =
59 {"", ",=", ",<", ",od", ",tr", ",<>", ",>=", ",ev"};
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"
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)
77 #define GET_COND(insn) (GET_FIELD ((insn), 16, 18) + \
78 (GET_FIELD ((insn), 19, 19) ? 8 : 0))
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));
85 /* Print one instruction from MEMADDR on STREAM. */
87 print_insn (memaddr, stream)
94 insn = read_memory_integer (memaddr, sizeof (insn));
96 for (i = 0; i < NUMOPCODES; ++i)
98 const struct pa_opcode *opcode = &pa_opcodes[i];
99 if ((insn & opcode->mask) == opcode->match)
101 register const char *s;
103 fputs_filtered (opcode->name, stream);
105 if (!index ("cCY<?!@-+&U>~nZFM", opcode->args[0]))
106 fputs_filtered (" ", stream);
107 for (s = opcode->args; *s != '\0'; ++s)
112 fput_reg (GET_FIELD (insn, 11, 15), stream);
115 if (GET_FIELD (insn, 25, 25))
116 fput_reg_r (GET_FIELD (insn, 11, 15), stream);
118 fput_reg (GET_FIELD (insn, 11, 15), stream);
121 fput_reg (GET_FIELD (insn, 6, 10), stream);
124 fput_creg (GET_FIELD (insn, 6, 10), stream);
127 if (GET_FIELD (insn, 25, 25))
128 fput_reg_r (GET_FIELD (insn, 6, 10), stream);
130 fput_reg (GET_FIELD (insn, 6, 10), stream);
133 fput_reg (GET_FIELD (insn, 27, 31), stream);
136 if (GET_FIELD (insn, 25, 25))
137 fput_reg_r (GET_FIELD (insn, 27, 31), stream);
139 fput_reg (GET_FIELD (insn, 27, 31), stream);
142 fput_creg (GET_FIELD (insn, 6, 10), stream);
145 fput_reg (GET_FIELD (insn, 11, 15), stream);
148 fput_reg (GET_FIELD (insn, 27, 31), stream);
151 fput_reg (GET_FIELD (insn, 16, 20), stream);
154 fput_reg (GET_FIELD (insn, 21, 25), stream);
157 fput_const (extract_5_load (insn), stream);
161 fprintf_filtered (stream, "sr%d", extract_3 (insn));
164 fprintf_filtered (stream, "%s ",
165 index_compl_names[GET_COMPL (insn)]);
168 fprintf_filtered (stream, "%s ",
169 short_ldst_compl_names[GET_COMPL (insn)]);
172 fprintf_filtered (stream, "%s ",
173 short_bytes_compl_names[GET_COMPL (insn)]);
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 */
179 fputs_filtered (compare_cond_names[GET_FIELD (insn, 16, 18)],
183 fputs_filtered (compare_cond_names[GET_FIELD (insn, 16, 18) + 8],
187 fputs_filtered (add_cond_names[GET_FIELD (insn, 16, 18)],
191 fputs_filtered (add_cond_names[GET_FIELD (insn, 16, 18) + 8],
195 fprintf_filtered (stream, "%s ",
196 compare_cond_names[GET_COND (insn)]);
199 fprintf_filtered (stream, "%s ",
200 add_cond_names[GET_FIELD (insn, 16, 18)]);
204 fprintf_filtered (stream, "%s ",
205 logical_cond_names[GET_COND (insn)]);
208 fprintf_filtered (stream, "%s ",
209 unit_cond_names[GET_COND (insn)]);
213 fprintf_filtered (stream, "%s ",
214 shift_cond_names[GET_FIELD (insn, 16, 18)]);
217 fput_const (extract_5_store (insn), stream);
220 fput_const (extract_5r_store (insn), stream);
223 fput_const (extract_5R_store (insn), stream);
226 fput_const (extract_11 (insn), stream);
229 fput_const (extract_14 (insn), stream);
232 fput_const (extract_21 (insn), stream);
236 fprintf_filtered (stream, ",n ");
238 fprintf_filtered (stream, " ");
241 print_address (memaddr + 8 + extract_12 (insn), stream);
244 op = GET_FIELD (insn, 0, 5);
246 if (op == 0x38 /* be */ || op == 0x39 /* ble */)
247 fput_const (extract_17 (insn), stream);
249 print_address (memaddr + 8 + extract_17 (insn), stream);
255 if (space = GET_FIELD (insn, 16, 17))
256 fprintf_filtered (stream, "sr%d,", space);
257 fput_reg (GET_FIELD (insn, 6, 10), stream);
261 fprintf_filtered (stream, "%d",
262 31 - GET_FIELD (insn, 22, 26));
265 fprintf_filtered (stream, "%d",
266 GET_FIELD (insn, 22, 26));
269 fprintf_filtered (stream, "%d",
270 GET_FIELD (insn, 11, 15));
273 fprintf_filtered (stream, "%d",
274 32 - GET_FIELD (insn, 27, 31));
277 fput_const (GET_FIELD (insn, 6, 18), stream);
280 if (GET_FIELD (insn, 26, 26))
281 fprintf_filtered (stream, ",m ");
283 fprintf_filtered (stream, " ");
286 fput_const (GET_FIELD (insn, 6, 31), stream);
289 fprintf_filtered (stream, ",%d", GET_FIELD (insn, 23, 25));
292 fput_const ((GET_FIELD (insn, 6,20) << 5 |
293 GET_FIELD (insn, 27, 31)), stream);
296 fput_const (GET_FIELD (insn, 6, 20), stream);
299 fput_const ((GET_FIELD (insn, 6, 22) << 5 |
300 GET_FIELD (insn, 27, 31)), stream);
303 fput_const ((GET_FIELD (insn, 11, 20) << 5 |
304 GET_FIELD (insn, 27, 31)), stream);
307 fput_const ((GET_FIELD (insn, 16, 20) << 5 |
308 GET_FIELD (insn, 27, 31)), stream);
311 fprintf_filtered (stream, "%d", GET_FIELD (insn, 23, 25));
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)],
319 fprintf_filtered (stream, "%s ",
320 float_format_names[GET_FIELD
324 fprintf_filtered (stream, "%s ",
325 float_format_names[GET_FIELD (insn,
329 fputs_filtered (float_format_names[GET_FIELD
330 (insn, 26, 26)], stream);
333 fputs_filtered (float_comp_names[GET_FIELD (insn, 27, 31)],
337 fprintf_filtered (stream, "fp%d", GET_FIELD (insn, 6, 10));
340 fprintf_filtered (stream, "fp%d", GET_FIELD (insn, 11, 15));
343 if (GET_FIELD (insn, 23, 25) == 0)
344 fprintf_filtered (stream, "fp%d",
345 GET_FIELD (insn, 27, 31));
347 fprintf_filtered (stream, "cp%d",
348 GET_FIELD (insn, 27, 31));
351 fprintf_filtered (stream, "%c", *s);
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
361 op = GET_FIELD (insn, 0, 5);
362 if (op == 0x38 /* be */ || op == 0x39 /* ble */)
364 CORE_ADDR target_address;
366 int basereg, basereg_prev;
368 target_address = extract_17 (insn);
369 basereg = GET_FIELD (insn, 6, 10);
372 prev_insn = read_memory_integer (memaddr - 4,
374 basereg_prev = GET_FIELD (prev_insn, 6, 10);
376 if ((prev_insn & 0xfc000000) == 0x20000000 /* ldil */
377 && basereg == basereg_prev)
378 target_address += extract_21 (prev_insn);
380 fprintf_filtered (stream, "\t! ");
381 print_address (target_address, stream);
387 fprintf_filtered (stream, "%#8x", insn);
391 /* Utility function to print registers */
394 fput_reg (reg, stream)
399 fputs_filtered (reg_names[reg], stream);
401 fputs_filtered ("r0", stream);
405 fput_reg_r (reg, stream)
410 fputs_filtered (reg_names[reg], stream);
412 fputs_filtered ("r0", stream);
413 fputs_filtered ("R", stream);
417 fput_creg (reg, stream)
421 fputs_filtered (control_reg[reg], stream);
424 /* print constants with sign */
427 fput_const (num, stream)
432 fprintf_filtered (stream, "-%x", -(int)num);
434 fprintf_filtered (stream, "%x", num);