Minor cleanup.
[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 '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.039306 seconds and 4 git commands to generate.