try to make hppa opcode table, updated for gas, still be compatible with gdb
[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 #define OLD_TABLE
26 #include "opcode/hppa.h"
27
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"
34 };
35
36 static char *compare_cond_names[] =
37 { "", ",=", ",<", ",<=", ",<<", ",<<=", ",sv",
38 ",od", ",tr", ",<>", ",>=", ",>", ",>>=",
39 ",>>", ",nsv", ",ev"
40 };
41
42 static char *add_cond_names[] =
43 { "", ",=", ",<", ",<=", ",nuv", ",znv", ",sv",
44 ",od", ",tr", ",<>", ",>=", ",>", ",uv",
45 ",vnz", ",nsv", ",ev"
46 };
47
48 static char *logical_cond_names[] =
49 { "", ",=", ",<", ",<=", 0, 0, 0, ",od",
50 ",tr", ",<>", ",>=", ",>", 0, 0, 0, ",ev"
51 };
52
53 static char *unit_cond_names[] =
54 { "", 0, ",sbz", ",shz", ",sdc", 0, ",sbc", ",shc",
55 ",tr", 0, ",nbz", ",nhz", ",ndc", 0, ",nbc", ",nhc"
56 };
57
58 static char *shift_cond_names[] =
59 {"", ",=", ",<", ",od", ",tr", ",<>", ",>=", ",ev"};
60
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"
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
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));
84
85 /* Print one instruction from MEMADDR on STREAM. */
86 int
87 print_insn (memaddr, stream)
88 CORE_ADDR memaddr;
89 FILE *stream;
90 {
91 long insn;
92 unsigned int i, op;
93
94 insn = read_memory_integer (memaddr, sizeof (insn));
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;
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;
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':
244 op = GET_FIELD (insn, 0, 5);
245
246 if (op == 0x38 /* be */ || op == 0x39 /* ble */)
247 fput_const (extract_17 (insn), stream);
248 else
249 print_address (memaddr + 8 + extract_17 (insn), stream);
250
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;
268 case 'Q':
269 fprintf_filtered (stream, "%d",
270 GET_FIELD (insn, 11, 15));
271 break;
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 }
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;
365 long prev_insn;
366 int basereg, basereg_prev;
367
368 target_address = extract_17 (insn);
369 basereg = GET_FIELD (insn, 6, 10);
370 if (basereg != 0)
371 {
372 prev_insn = read_memory_integer (memaddr - 4,
373 sizeof(prev_insn));
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
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
393 static void
394 fput_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
404 void
405 fput_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
416 void
417 fput_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
426 void
427 fput_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.06534 seconds and 5 git commands to generate.