* gdbserver/{remote-gutils.c remote-server.c Makefile.in
[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"
3b17ee1b 25#define OLD_TABLE
7da1e27d
SG
26#include "opcode/hppa.h"
27
01d1590b
SG
28static 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"
34 };
7da1e27d 35
01d1590b
SG
36static char *compare_cond_names[] =
37{ "", ",=", ",<", ",<=", ",<<", ",<<=", ",sv",
38 ",od", ",tr", ",<>", ",>=", ",>", ",>>=",
39 ",>>", ",nsv", ",ev"
40 };
7da1e27d 41
01d1590b
SG
42static char *add_cond_names[] =
43{ "", ",=", ",<", ",<=", ",nuv", ",znv", ",sv",
44 ",od", ",tr", ",<>", ",>=", ",>", ",uv",
45 ",vnz", ",nsv", ",ev"
46 };
47
48static char *logical_cond_names[] =
49{ "", ",=", ",<", ",<=", 0, 0, 0, ",od",
50 ",tr", ",<>", ",>=", ",>", 0, 0, 0, ",ev"
51 };
52
53static char *unit_cond_names[] =
54{ "", 0, ",sbz", ",shz", ",sdc", 0, ",sbc", ",shc",
55 ",tr", 0, ",nbz", ",nhz", ",ndc", 0, ",nbc", ",nhc"
56 };
57
58static char *shift_cond_names[] =
59{"", ",=", ",<", ",od", ",tr", ",<>", ",>=", ",ev"};
60
61static char *index_compl_names[] = {"", ",m", ",s", ",sm"};
62static char *short_ldst_compl_names[] = {"", ",ma", "", ",mb"};
63static char *short_bytes_compl_names[] = {"", ",b,m", ",e", ",e,m"};
64static char *float_format_names[] = {",sgl", ",dbl", ",quad"};
65static char *float_comp_names[] =
7da1e27d
SG
66{",false?", ",false", ",?", ",!<=>", ",=", ",=t", ",?=", ",!<>",
67 ",!?>=", ",<", ",?<", ",!>=", ",!?>", ",<=", ",?<=", ",!>",
68 ",!?<=", ",>", ",?>", ",!<=", ",!?<", ",>=", ",?>=", ",!<",
69 ",!?=", ",<>", ",!=", ",!=t", ",!?", ",<=>", ",true?", ",true"
70 };
71
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)
76
77#define GET_COND(insn) (GET_FIELD ((insn), 16, 18) + \
78 (GET_FIELD ((insn), 19, 19) ? 8 : 0))
79
01d1590b
SG
80static void fput_reg PARAMS ((unsigned reg, FILE *stream));
81static void fput_const PARAMS ((unsigned num, FILE *stream));
82static void fput_reg_r PARAMS ((unsigned reg, FILE *stream));
83static void fput_creg PARAMS ((unsigned reg, FILE *stream));
7da1e27d
SG
84
85/* Print one instruction from MEMADDR on STREAM. */
86int
87print_insn (memaddr, stream)
88 CORE_ADDR memaddr;
89 FILE *stream;
90{
fa9265e5
SG
91 long insn;
92 unsigned int i, op;
7da1e27d 93
fa9265e5 94 insn = read_memory_integer (memaddr, sizeof (insn));
7da1e27d
SG
95
96 for (i = 0; i < NUMOPCODES; ++i)
97 {
98 const struct pa_opcode *opcode = &pa_opcodes[i];
99 if ((insn & opcode->mask) == opcode->match)
100 {
101 register const char *s;
102
103 fputs_filtered (opcode->name, stream);
104
105 if (!index ("cCY<?!@-+&U>~nZFM", opcode->args[0]))
106 fputs_filtered (" ", stream);
107 for (s = opcode->args; *s != '\0'; ++s)
108 {
109 switch (*s)
110 {
111 case 'x':
112 fput_reg (GET_FIELD (insn, 11, 15), stream);
113 break;
114 case 'X':
115 if (GET_FIELD (insn, 25, 25))
116 fput_reg_r (GET_FIELD (insn, 11, 15), stream);
117 else
118 fput_reg (GET_FIELD (insn, 11, 15), stream);
119 break;
120 case 'b':
121 fput_reg (GET_FIELD (insn, 6, 10), stream);
122 break;
123 case '^':
124 fput_creg (GET_FIELD (insn, 6, 10), stream);
125 break;
126 case 'E':
127 if (GET_FIELD (insn, 25, 25))
128 fput_reg_r (GET_FIELD (insn, 6, 10), stream);
129 else
130 fput_reg (GET_FIELD (insn, 6, 10), stream);
131 break;
132 case 't':
133 fput_reg (GET_FIELD (insn, 27, 31), stream);
134 break;
135 case 'v':
136 if (GET_FIELD (insn, 25, 25))
137 fput_reg_r (GET_FIELD (insn, 27, 31), stream);
138 else
139 fput_reg (GET_FIELD (insn, 27, 31), stream);
140 break;
141 case '4':
142 fput_creg (GET_FIELD (insn, 6, 10), stream);
143 break;
144 case '6':
145 fput_reg (GET_FIELD (insn, 11, 15), stream);
146 break;
147 case '7':
148 fput_reg (GET_FIELD (insn, 27, 31), stream);
149 break;
150 case '8':
151 fput_reg (GET_FIELD (insn, 16, 20), stream);
152 break;
153 case '9':
154 fput_reg (GET_FIELD (insn, 21, 25), stream);
155 break;
156 case '5':
157 fput_const (extract_5_load (insn), stream);
158 break;
159 /* case 's': */
160 case 'S':
161 fprintf_filtered (stream, "sr%d", extract_3 (insn));
162 break;
163 case 'c':
164 fprintf_filtered (stream, "%s ",
165 index_compl_names[GET_COMPL (insn)]);
166 break;
167 case 'C':
168 fprintf_filtered (stream, "%s ",
169 short_ldst_compl_names[GET_COMPL (insn)]);
170 break;
171 case 'Y':
172 fprintf_filtered (stream, "%s ",
173 short_bytes_compl_names[GET_COMPL (insn)]);
174 break;
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 */
178 case '<':
179 fputs_filtered (compare_cond_names[GET_FIELD (insn, 16, 18)],
180 stream);
181 break;
182 case '?':
183 fputs_filtered (compare_cond_names[GET_FIELD (insn, 16, 18) + 8],
184 stream);
185 break;
186 case '!':
187 fputs_filtered (add_cond_names[GET_FIELD (insn, 16, 18)],
188 stream);
189 break;
190 case '@':
191 fputs_filtered (add_cond_names[GET_FIELD (insn, 16, 18) + 8],
192 stream);
193 break;
194 case '-':
195 fprintf_filtered (stream, "%s ",
196 compare_cond_names[GET_COND (insn)]);
197 break;
198 case '+':
199 fprintf_filtered (stream, "%s ",
200 add_cond_names[GET_FIELD (insn, 16, 18)]);
201 break;
202
203 case '&':
204 fprintf_filtered (stream, "%s ",
205 logical_cond_names[GET_COND (insn)]);
206 break;
207 case 'U':
208 fprintf_filtered (stream, "%s ",
209 unit_cond_names[GET_COND (insn)]);
210 break;
211 case '>':
212 case '~':
213 fprintf_filtered (stream, "%s ",
214 shift_cond_names[GET_FIELD (insn, 16, 18)]);
215 break;
216 case 'V':
217 fput_const (extract_5_store (insn), stream);
218 break;
68c8d698
SG
219 case 'r':
220 fput_const (extract_5r_store (insn), stream);
221 break;
222 case 'R':
223 fput_const (extract_5R_store (insn), stream);
224 break;
7da1e27d
SG
225 case 'i':
226 fput_const (extract_11 (insn), stream);
227 break;
228 case 'j':
229 fput_const (extract_14 (insn), stream);
230 break;
231 case 'k':
232 fput_const (extract_21 (insn), stream);
233 break;
234 case 'n':
235 if (insn & 0x2)
236 fprintf_filtered (stream, ",n ");
237 else
238 fprintf_filtered (stream, " ");
239 break;
240 case 'w':
241 print_address (memaddr + 8 + extract_12 (insn), stream);
242 break;
243 case 'W':
7da1e27d 244 op = GET_FIELD (insn, 0, 5);
9f739abd
SG
245
246 if (op == 0x38 /* be */ || op == 0x39 /* ble */)
7da1e27d 247 fput_const (extract_17 (insn), stream);
9f739abd
SG
248 else
249 print_address (memaddr + 8 + extract_17 (insn), stream);
250
7da1e27d
SG
251 break;
252 case 'B':
253 {
254 int space;
255 if (space = GET_FIELD (insn, 16, 17))
256 fprintf_filtered (stream, "sr%d,", space);
257 fput_reg (GET_FIELD (insn, 6, 10), stream);
258 break;
259 }
260 case 'p':
261 fprintf_filtered (stream, "%d",
262 31 - GET_FIELD (insn, 22, 26));
263 break;
264 case 'P':
265 fprintf_filtered (stream, "%d",
266 GET_FIELD (insn, 22, 26));
267 break;
9f739abd
SG
268 case 'Q':
269 fprintf_filtered (stream, "%d",
270 GET_FIELD (insn, 11, 15));
271 break;
7da1e27d
SG
272 case 'T':
273 fprintf_filtered (stream, "%d",
274 32 - GET_FIELD (insn, 27, 31));
275 break;
276 case 'A':
277 fput_const (GET_FIELD (insn, 6, 18), stream);
278 break;
279 case 'Z':
280 if (GET_FIELD (insn, 26, 26))
281 fprintf_filtered (stream, ",m ");
282 else
283 fprintf_filtered (stream, " ");
284 break;
285 case 'D':
286 fput_const (GET_FIELD (insn, 6, 31), stream);
287 break;
288 case 'f':
289 fprintf_filtered (stream, ",%d", GET_FIELD (insn, 23, 25));
290 break;
291 case 'O':
292 fput_const ((GET_FIELD (insn, 6,20) << 5 |
293 GET_FIELD (insn, 27, 31)), stream);
294 break;
295 case 'o':
296 fput_const (GET_FIELD (insn, 6, 20), stream);
297 break;
298 case '2':
299 fput_const ((GET_FIELD (insn, 6, 22) << 5 |
300 GET_FIELD (insn, 27, 31)), stream);
301 break;
302 case '1':
303 fput_const ((GET_FIELD (insn, 11, 20) << 5 |
304 GET_FIELD (insn, 27, 31)), stream);
305 break;
306 case '0':
307 fput_const ((GET_FIELD (insn, 16, 20) << 5 |
308 GET_FIELD (insn, 27, 31)), stream);
309 break;
310 case 'u':
311 fprintf_filtered (stream, "%d", GET_FIELD (insn, 23, 25));
312 break;
313 case 'F':
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)],
317 stream);
318 else
319 fprintf_filtered (stream, "%s ",
320 float_format_names[GET_FIELD
321 (insn, 19, 20)]);
322 break;
323 case 'G':
324 fprintf_filtered (stream, "%s ",
325 float_format_names[GET_FIELD (insn,
326 17, 18)]);
327 break;
328 case 'H':
329 fputs_filtered (float_format_names[GET_FIELD
330 (insn, 26, 26)], stream);
331 break;
332 case 'M':
333 fputs_filtered (float_comp_names[GET_FIELD (insn, 27, 31)],
334 stream);
335 break;
336 case '}':
337 fprintf_filtered (stream, "fp%d", GET_FIELD (insn, 6, 10));
338 break;
339 case '|':
340 fprintf_filtered (stream, "fp%d", GET_FIELD (insn, 11, 15));
341 break;
342 case '{':
343 if (GET_FIELD (insn, 23, 25) == 0)
344 fprintf_filtered (stream, "fp%d",
345 GET_FIELD (insn, 27, 31));
346 else
347 fprintf_filtered (stream, "cp%d",
348 GET_FIELD (insn, 27, 31));
349 break;
350 default:
351 fprintf_filtered (stream, "%c", *s);
352 break;
353 }
354 }
9f739abd
SG
355
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
359 print it out. */
360
361 op = GET_FIELD (insn, 0, 5);
362 if (op == 0x38 /* be */ || op == 0x39 /* ble */)
363 {
364 CORE_ADDR target_address;
fa9265e5 365 long prev_insn;
9f739abd
SG
366 int basereg, basereg_prev;
367
368 target_address = extract_17 (insn);
369 basereg = GET_FIELD (insn, 6, 10);
370 if (basereg != 0)
371 {
fa9265e5
SG
372 prev_insn = read_memory_integer (memaddr - 4,
373 sizeof(prev_insn));
9f739abd
SG
374 basereg_prev = GET_FIELD (prev_insn, 6, 10);
375
376 if ((prev_insn & 0xfc000000) == 0x20000000 /* ldil */
377 && basereg == basereg_prev)
378 target_address += extract_21 (prev_insn);
379 }
380 fprintf_filtered (stream, "\t! ");
381 print_address (target_address, stream);
382 }
383
7da1e27d
SG
384 return sizeof(insn);
385 }
386 }
387 fprintf_filtered (stream, "%#8x", insn);
388 return sizeof(insn);
389}
390
391/* Utility function to print registers */
392
01d1590b 393static void
7da1e27d
SG
394fput_reg (reg, stream)
395 unsigned reg;
396 FILE *stream;
397{
398 if (reg)
399 fputs_filtered (reg_names[reg], stream);
400 else
401 fputs_filtered ("r0", stream);
402}
403
404void
405fput_reg_r (reg, stream)
406 unsigned reg;
407 FILE *stream;
408{
409 if (reg)
410 fputs_filtered (reg_names[reg], stream);
411 else
412 fputs_filtered ("r0", stream);
413 fputs_filtered ("R", stream);
414}
415
416void
417fput_creg (reg, stream)
418 unsigned reg;
419 FILE *stream;
420{
421 fputs_filtered (control_reg[reg], stream);
422}
423
424/* print constants with sign */
425
426void
427fput_const (num, stream)
428 unsigned num;
429 FILE *stream;
430{
431 if ((int)num < 0)
432 fprintf_filtered (stream, "-%x", -(int)num);
433 else
434 fprintf_filtered (stream, "%x", num);
435}
This page took 0.135425 seconds and 4 git commands to generate.