* libcoff.h, coffgen.c (coff_count_linenumbers), coffcode.h
[deliverable/binutils-gdb.git] / gdb / hppa-pinsn.c
CommitLineData
7da1e27d 1/* Disassembler for the PA-RISC. Somewhat derived from sparc-pinsn.c.
5140562f 2 Copyright 1989, 1990, 1992 Free Software Foundation, Inc.
7da1e27d
SG
3
4 Contributed by the Center for Software Science at the
5 University of Utah (pa-gdb-bugs@cs.utah.edu).
6
5140562f 7This file is part of GDB.
7da1e27d 8
5140562f 9This program is free software; you can redistribute it and/or modify
7da1e27d 10it under the terms of the GNU General Public License as published by
5140562f
JG
11the Free Software Foundation; either version 2 of the License, or
12(at your option) any later version.
7da1e27d 13
5140562f 14This program is distributed in the hope that it will be useful,
7da1e27d
SG
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
5140562f
JG
20along with this program; if not, write to the Free Software
21Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
7da1e27d
SG
22
23#include "defs.h"
24#include "symtab.h"
25#include "opcode/hppa.h"
26
01d1590b
SG
27static 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 };
7da1e27d 34
01d1590b
SG
35static char *compare_cond_names[] =
36{ "", ",=", ",<", ",<=", ",<<", ",<<=", ",sv",
37 ",od", ",tr", ",<>", ",>=", ",>", ",>>=",
38 ",>>", ",nsv", ",ev"
39 };
7da1e27d 40
01d1590b
SG
41static char *add_cond_names[] =
42{ "", ",=", ",<", ",<=", ",nuv", ",znv", ",sv",
43 ",od", ",tr", ",<>", ",>=", ",>", ",uv",
44 ",vnz", ",nsv", ",ev"
45 };
46
47static char *logical_cond_names[] =
48{ "", ",=", ",<", ",<=", 0, 0, 0, ",od",
49 ",tr", ",<>", ",>=", ",>", 0, 0, 0, ",ev"
50 };
51
52static char *unit_cond_names[] =
53{ "", 0, ",sbz", ",shz", ",sdc", 0, ",sbc", ",shc",
54 ",tr", 0, ",nbz", ",nhz", ",ndc", 0, ",nbc", ",nhc"
55 };
56
57static char *shift_cond_names[] =
58{"", ",=", ",<", ",od", ",tr", ",<>", ",>=", ",ev"};
59
60static char *index_compl_names[] = {"", ",m", ",s", ",sm"};
61static char *short_ldst_compl_names[] = {"", ",ma", "", ",mb"};
62static char *short_bytes_compl_names[] = {"", ",b,m", ",e", ",e,m"};
63static char *float_format_names[] = {",sgl", ",dbl", ",quad"};
64static char *float_comp_names[] =
7da1e27d
SG
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
01d1590b
SG
79static void fput_reg PARAMS ((unsigned reg, FILE *stream));
80static void fput_const PARAMS ((unsigned num, FILE *stream));
81static void fput_reg_r PARAMS ((unsigned reg, FILE *stream));
82static void fput_creg PARAMS ((unsigned reg, FILE *stream));
7da1e27d
SG
83
84/* Print one instruction from MEMADDR on STREAM. */
85int
86print_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':
7da1e27d 236 op = GET_FIELD (insn, 0, 5);
9f739abd
SG
237
238 if (op == 0x38 /* be */ || op == 0x39 /* ble */)
7da1e27d 239 fput_const (extract_17 (insn), stream);
9f739abd
SG
240 else
241 print_address (memaddr + 8 + extract_17 (insn), stream);
242
7da1e27d
SG
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;
9f739abd
SG
260 case 'Q':
261 fprintf_filtered (stream, "%d",
262 GET_FIELD (insn, 11, 15));
263 break;
7da1e27d
SG
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 }
9f739abd
SG
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
7da1e27d
SG
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
01d1590b 384static void
7da1e27d
SG
385fput_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
395void
396fput_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
407void
408fput_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
417void
418fput_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.056619 seconds and 4 git commands to generate.