Commit | Line | Data |
---|---|---|
112087ed KR |
1 | /* Disassembler for the PA-RISC. Somewhat derived from sparc-pinsn.c. |
2 | Copyright 1989, 1990, 1992, 1993 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 program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program; if not, write to the Free Software | |
feb82d0a DT |
19 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
20 | ||
21 | /* Define this name if you want to restrict the | |
22 | disassembler to host-native formats. */ | |
23 | ||
24 | /* #define LOCAL_ONLY 1 */ | |
112087ed | 25 | |
17068960 | 26 | #include <ansidecl.h> |
112087ed | 27 | #include "sysdep.h" |
17068960 | 28 | #include "dis-asm.h" |
feb82d0a | 29 | #include "libhppa.h" |
112087ed KR |
30 | #include "opcode/hppa.h" |
31 | ||
feb82d0a DT |
32 | #ifdef LOCAL_ONLY |
33 | /* Needed for HP-specific architecture version numbers. */ | |
34 | #include <unistd.h> | |
35 | #endif | |
36 | ||
18de15d8 JK |
37 | /* Integer register names, indexed by the numbers which appear in the |
38 | opcodes. */ | |
39 | static const char *const reg_names[] = | |
feb82d0a DT |
40 | {"flags", |
41 | "r1", "rp", "r3", "r4", "r5", "r6", "r7", "r8", "r9", | |
18de15d8 | 42 | "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", |
feb82d0a DT |
43 | "r20", "r21", "r22", "r23", "r24", "r25", "r26", "dp", "ret0", "ret1", |
44 | "sp", "r31"}; | |
18de15d8 JK |
45 | |
46 | /* Floating point register names, indexed by the numbers which appear in the | |
47 | opcodes. */ | |
48 | static const char *const fp_reg_names[] = | |
feb82d0a DT |
49 | {"fpsr", "fpe2", "fpe4", "fpe6", "fr4", "fr5", "fr6", "fr7", "fr8", "fr9", |
50 | "fr10", "fr11", "fr12", "fr13", "fr14", "fr15", "fr16", "fr17", "fr18", "fr19", | |
51 | "fr20", "fr21", "fr22", "fr23", "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", | |
52 | "fr30", "fr31"}; | |
53 | ||
54 | /* (No longer) Format '-': Sign-extension completers */ | |
55 | static const char *const sign_extension_names[] = { ",u", ",s" }; | |
56 | ||
57 | /* Format '/': Deposit completers */ | |
58 | static const char *const deposit_names[] = { ",z", "" }; | |
59 | ||
60 | /* Format '}': Floating conversion types */ | |
61 | static const char *const conversion_names[] = | |
62 | { "ff", "xf", "fx", "fxt", "", "uxf", "fxu", "fxut" }; | |
63 | ||
64 | /* Format <none yet>: Kinds of floating point test */ | |
65 | static const char *const float_test_names[] = | |
66 | { "", ",acc", ",rej", "", "", ",acc8", ",rej8", "", | |
67 | "", ",acc6", "", "", "", ",acc4", "", "", | |
68 | "", ",acc2" }; | |
112087ed KR |
69 | |
70 | typedef unsigned int CORE_ADDR; | |
71 | ||
72 | /* Get at various relevent fields of an instruction word. */ | |
73 | ||
74 | #define MASK_5 0x1f | |
75 | #define MASK_11 0x7ff | |
76 | #define MASK_14 0x3fff | |
77 | #define MASK_21 0x1fffff | |
78 | ||
feb82d0a | 79 | /* These macros get bit fields using HP's numbering (MSB = 0) */ |
112087ed | 80 | |
feb82d0a DT |
81 | /* Now defined in "libhppa.h" |
82 | #define GET_FIELD(X, FROM, TO) \ | |
112087ed | 83 | ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) |
feb82d0a DT |
84 | |
85 | #define GET_BIT( X, WHICH ) \ | |
86 | GET_FIELD( X, WHICH, WHICH ) | |
87 | */ | |
112087ed KR |
88 | |
89 | /* Some of these have been converted to 2-d arrays because they | |
90 | consume less storage this way. If the maintenance becomes a | |
feb82d0a DT |
91 | problem, convert them back to const 1-d pointer arrays. */ |
92 | static const char control_reg[][6] = | |
93 | { | |
94 | "rctr", | |
95 | "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", | |
112087ed KR |
96 | "pidr1", "pidr2", "ccr", "sar", "pidr3", "pidr4", |
97 | "iva", "eiem", "itmr", "pcsq", "pcoq", "iir", "isr", | |
feb82d0a DT |
98 | "ior", "ipsw", "eirr", |
99 | "tr0", "tr1", "tr2", "tr3", "tr4", "tr5", "tr6", "tr7" | |
112087ed KR |
100 | }; |
101 | ||
102 | static const char compare_cond_names[][5] = { | |
103 | "", ",=", ",<", ",<=", ",<<", ",<<=", ",sv", | |
104 | ",od", ",tr", ",<>", ",>=", ",>", ",>>=", | |
105 | ",>>", ",nsv", ",ev" | |
106 | }; | |
feb82d0a DT |
107 | |
108 | static const char compare_cond_names_double[][6] = { | |
109 | "*", ",*=", ",*<", ",*<=", ",*<<", ",*<<=", ",*sv", | |
110 | ",*od", ",*tr", ",*<>", ",*>=", ",*>", ",*>>=", | |
111 | ",*>>", ",*nsv", ",*ev" | |
112 | }; | |
113 | ||
112087ed KR |
114 | static const char add_cond_names[][5] = { |
115 | "", ",=", ",<", ",<=", ",nuv", ",znv", ",sv", | |
116 | ",od", ",tr", ",<>", ",>=", ",>", ",uv", | |
117 | ",vnz", ",nsv", ",ev" | |
118 | }; | |
feb82d0a DT |
119 | |
120 | static const char add_cond_names_double[][6] = { | |
121 | "*", ",*=", ",*<", ",*<=", ",*nuv", ",*znv", ",*sv", | |
122 | ",*od", ",*tr", ",*<>", ",*>=", ",*>", ",*uv", | |
123 | ",*vnz", ",*nsv", ",*ev" | |
124 | }; | |
125 | ||
112087ed KR |
126 | static const char *const logical_cond_names[] = { |
127 | "", ",=", ",<", ",<=", 0, 0, 0, ",od", | |
feb82d0a DT |
128 | ",tr", ",<>", ",>=", ",>", 0, 0, 0, ",ev" |
129 | }; | |
130 | ||
131 | static const char *const logical_cond_names_double[] = { | |
132 | "*", ",*=", ",*<", ",*<=", 0, 0, 0, ",*od", | |
133 | ",*tr", ",*<>", ",*>=", ",*>", 0, 0, 0, ",*ev" | |
134 | }; | |
112087ed KR |
135 | static const char *const unit_cond_names[] = { |
136 | "", 0, ",sbz", ",shz", ",sdc", 0, ",sbc", ",shc", | |
137 | ",tr", 0, ",nbz", ",nhz", ",ndc", 0, ",nbc", ",nhc" | |
138 | }; | |
feb82d0a DT |
139 | static const char *const unit_cond_names_double[] = { |
140 | "*", 0, ",*sbz", ",*shz", ",*sdc", 0, ",*sbc", ",*shc", | |
141 | ",*tr", 0, ",*nbz", ",*nhz", ",*ndc", 0, ",*nbc", ",*nhc" | |
142 | }; | |
112087ed KR |
143 | static const char shift_cond_names[][4] = { |
144 | "", ",=", ",<", ",od", ",tr", ",<>", ",>=", ",ev" | |
145 | }; | |
feb82d0a DT |
146 | |
147 | static const char shift_cond_names_double[][5] = { | |
148 | "*", ",*=", ",*<", ",*od", ",*tr", ",*<>", ",*>=", ",*ev" | |
112087ed | 149 | }; |
feb82d0a DT |
150 | |
151 | /* Format 'c' */ | |
152 | static const char index_compl_names[][4] = {"", ",m", ",s", ",sm"}; | |
153 | ||
154 | /* Format 'C' */ | |
155 | static const char short_ldst_compl_names[][4] = {"", ",ma", ",o", ",mb"}; | |
156 | ||
157 | /* Format 'Y' */ | |
158 | static const char *const short_bytes_compl_names[] = { "", ",b,m", ",e", ",e,m" }; | |
159 | ||
160 | /* Format '$' */ | |
161 | static const char *const branch_push_pop_names[] = { "", ",pop", ",l", ",l,push" }; | |
162 | ||
163 | /* Format '=' */ | |
164 | static const char *const saturation_names[] = { ",us", ",ss", "", "" }; | |
165 | ||
166 | /* Format '3' */ | |
167 | static const char *const shift_names[] = { "", "", ",u", ",s" }; | |
168 | ||
169 | /* Format 'e' */ | |
170 | static const char *const mix_names[] = { ",l", "", ",r", "" }; | |
171 | ||
17068960 | 172 | static const char *const float_format_names[] = {",sgl", ",dbl", "", ",quad"}; |
feb82d0a | 173 | |
112087ed KR |
174 | static const char float_comp_names[][8] = |
175 | { | |
176 | ",false?", ",false", ",?", ",!<=>", ",=", ",=t", ",?=", ",!<>", | |
177 | ",!?>=", ",<", ",?<", ",!>=", ",!?>", ",<=", ",?<=", ",!>", | |
178 | ",!?<=", ",>", ",?>", ",!<=", ",!?<", ",>=", ",?>=", ",!<", | |
179 | ",!?=", ",<>", ",!=", ",!=t", ",!?", ",<=>", ",true?", ",true" | |
180 | }; | |
181 | ||
182 | /* For a bunch of different instructions form an index into a | |
183 | completer name table. */ | |
184 | #define GET_COMPL(insn) (GET_FIELD (insn, 26, 26) | \ | |
185 | GET_FIELD (insn, 18, 18) << 1) | |
186 | ||
feb82d0a DT |
187 | /* Like GET_COMPL, but if the last five bits are 0 and the M bit is |
188 | * set, return "2" for ",o" */ | |
189 | #define GET_COMPL_O(insn) ( (GET_COMPL(insn) == 1) \ | |
190 | ? ((GET_FIELD (insn, 27, 31 ) == 0) ? 2 : 1 )\ | |
191 | : GET_COMPL(insn)) | |
192 | ||
112087ed KR |
193 | #define GET_COND(insn) (GET_FIELD ((insn), 16, 18) + \ |
194 | (GET_FIELD ((insn), 19, 19) ? 8 : 0)) | |
195 | ||
feb82d0a DT |
196 | #define GET_PUSH_POP(insn) ((GET_BIT ((insn), 18) << 1) | GET_BIT((insn), 31)) |
197 | ||
198 | /* Two-part register extract */ | |
199 | #define MERGED_REG(insn) ((GET_FIELD((insn), 16, 18)) << 2 | GET_FIELD((insn), 21, 22)) | |
200 | ||
112087ed KR |
201 | /* Utility function to print registers. Put these first, so gcc's function |
202 | inlining can do its stuff. */ | |
203 | ||
204 | #define fputs_filtered(STR,F) (*info->fprintf_func) (info->stream, "%s", STR) | |
205 | ||
206 | static void | |
207 | fput_reg (reg, info) | |
208 | unsigned reg; | |
209 | disassemble_info *info; | |
210 | { | |
211 | (*info->fprintf_func) (info->stream, reg ? reg_names[reg] : "r0"); | |
212 | } | |
213 | ||
214 | static void | |
18de15d8 | 215 | fput_fp_reg (reg, info) |
112087ed KR |
216 | unsigned reg; |
217 | disassemble_info *info; | |
218 | { | |
18de15d8 JK |
219 | (*info->fprintf_func) (info->stream, reg ? fp_reg_names[reg] : "fr0"); |
220 | } | |
221 | ||
222 | static void | |
223 | fput_fp_reg_r (reg, info) | |
224 | unsigned reg; | |
225 | disassemble_info *info; | |
226 | { | |
227 | /* Special case floating point exception registers. */ | |
228 | if (reg < 4) | |
229 | (*info->fprintf_func) (info->stream, "fpe%d", reg * 2 + 1); | |
230 | else | |
231 | (*info->fprintf_func) (info->stream, "%sR", reg ? fp_reg_names[reg] | |
232 | : "fr0"); | |
112087ed KR |
233 | } |
234 | ||
235 | static void | |
236 | fput_creg (reg, info) | |
237 | unsigned reg; | |
238 | disassemble_info *info; | |
239 | { | |
240 | (*info->fprintf_func) (info->stream, control_reg[reg]); | |
241 | } | |
242 | ||
feb82d0a | 243 | /* print constants in hex with sign */ |
112087ed KR |
244 | |
245 | static void | |
feb82d0a | 246 | fput_hex_const (num, info) |
112087ed KR |
247 | unsigned num; |
248 | disassemble_info *info; | |
249 | { | |
feb82d0a DT |
250 | /* Mark negative numbers as negative; only mark |
251 | numbers as hex if necessary. */ | |
112087ed | 252 | if ((int)num < 0) |
feb82d0a DT |
253 | { |
254 | if ((int)num > -10) | |
255 | (*info->fprintf_func) (info->stream, "-%d", -(int)num ); | |
256 | else | |
257 | (*info->fprintf_func) (info->stream, "-0x%x", -(int)num); | |
258 | } | |
259 | else if ((int)num < 10) | |
260 | (*info->fprintf_func) (info->stream, "%d", num ); | |
112087ed | 261 | else |
feb82d0a | 262 | (*info->fprintf_func) (info->stream, "0x%x", num); |
112087ed KR |
263 | } |
264 | ||
feb82d0a | 265 | /* print constants in decimal with sign */ |
112087ed | 266 | |
feb82d0a DT |
267 | static void |
268 | fput_decimal_const (num, info) | |
269 | unsigned num; | |
270 | disassemble_info *info; | |
112087ed | 271 | { |
feb82d0a DT |
272 | if ((int)num < 0) |
273 | (*info->fprintf_func) (info->stream, "-%d", -(int)num); | |
274 | else | |
275 | (*info->fprintf_func) (info->stream, "%d", num); | |
112087ed KR |
276 | } |
277 | ||
feb82d0a DT |
278 | /* Routines to extract various sized constants out of hppa |
279 | instructions. */ | |
112087ed | 280 | |
feb82d0a DT |
281 | /* extract a 3-bit space register number from a be, ble, |
282 | mtsp, pitlb or mfsp */ | |
112087ed KR |
283 | static int |
284 | extract_3 (word) | |
285 | unsigned word; | |
286 | { | |
287 | return GET_FIELD (word, 18, 18) << 2 | GET_FIELD (word, 16, 17); | |
288 | } | |
289 | ||
290 | static int | |
291 | extract_5_load (word) | |
292 | unsigned word; | |
293 | { | |
294 | return low_sign_extend (word >> 16 & MASK_5, 5); | |
295 | } | |
296 | ||
297 | /* extract the immediate field from a st{bhw}s instruction */ | |
298 | static int | |
299 | extract_5_store (word) | |
300 | unsigned word; | |
301 | { | |
302 | return low_sign_extend (word & MASK_5, 5); | |
303 | } | |
304 | ||
305 | /* extract the immediate field from a break instruction */ | |
306 | static unsigned | |
307 | extract_5r_store (word) | |
308 | unsigned word; | |
309 | { | |
310 | return (word & MASK_5); | |
311 | } | |
312 | ||
313 | /* extract the immediate field from a {sr}sm instruction */ | |
314 | static unsigned | |
315 | extract_5R_store (word) | |
316 | unsigned word; | |
317 | { | |
318 | return (word >> 16 & MASK_5); | |
319 | } | |
320 | ||
321 | /* extract the immediate field from a bb instruction */ | |
322 | static unsigned | |
323 | extract_5Q_store (word) | |
324 | unsigned word; | |
325 | { | |
326 | return (word >> 21 & MASK_5); | |
327 | } | |
328 | ||
329 | /* extract an 11 bit immediate field */ | |
330 | static int | |
331 | extract_11 (word) | |
332 | unsigned word; | |
333 | { | |
334 | return low_sign_extend (word & MASK_11, 11); | |
335 | } | |
336 | ||
337 | /* extract a 14 bit immediate field */ | |
338 | static int | |
339 | extract_14 (word) | |
340 | unsigned word; | |
341 | { | |
342 | return low_sign_extend (word & MASK_14, 14); | |
343 | } | |
344 | ||
112087ed KR |
345 | /* extract a 21 bit constant */ |
346 | ||
347 | static int | |
348 | extract_21 (word) | |
349 | unsigned word; | |
350 | { | |
351 | int val; | |
352 | ||
353 | word &= MASK_21; | |
354 | word <<= 11; | |
355 | val = GET_FIELD (word, 20, 20); | |
356 | val <<= 11; | |
357 | val |= GET_FIELD (word, 9, 19); | |
358 | val <<= 2; | |
359 | val |= GET_FIELD (word, 5, 6); | |
360 | val <<= 5; | |
361 | val |= GET_FIELD (word, 0, 4); | |
362 | val <<= 2; | |
363 | val |= GET_FIELD (word, 7, 8); | |
364 | return sign_extend (val, 21) << 11; | |
365 | } | |
366 | ||
112087ed KR |
367 | /* extract a 12 bit constant from branch instructions */ |
368 | ||
369 | static int | |
370 | extract_12 (word) | |
371 | unsigned word; | |
372 | { | |
373 | return sign_extend (GET_FIELD (word, 19, 28) | | |
374 | GET_FIELD (word, 29, 29) << 10 | | |
375 | (word & 0x1) << 11, 12) << 2; | |
376 | } | |
377 | ||
378 | /* extract a 17 bit constant from branch instructions, returning the | |
379 | 19 bit signed value. */ | |
380 | ||
381 | static int | |
382 | extract_17 (word) | |
383 | unsigned word; | |
384 | { | |
385 | return sign_extend (GET_FIELD (word, 19, 28) | | |
386 | GET_FIELD (word, 29, 29) << 10 | | |
387 | GET_FIELD (word, 11, 15) << 11 | | |
388 | (word & 0x1) << 16, 17) << 2; | |
389 | } | |
390 | ||
391 | /* Print one instruction. */ | |
392 | int | |
393 | print_insn_hppa (memaddr, info) | |
394 | bfd_vma memaddr; | |
395 | disassemble_info *info; | |
396 | { | |
feb82d0a DT |
397 | bfd_byte buffer[4]; |
398 | unsigned int insn, i; | |
399 | ||
400 | #ifdef LOCAL_ONLY | |
401 | static int got_version_id = 0; | |
402 | static enum pa_arch pa_version; | |
403 | #endif | |
112087ed | 404 | |
feb82d0a DT |
405 | /* Get the instruction to disassemble. |
406 | */ | |
112087ed KR |
407 | { |
408 | int status = | |
feb82d0a | 409 | (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info); |
112087ed KR |
410 | if (status != 0) |
411 | { | |
412 | (*info->memory_error_func) (status, memaddr, info); | |
413 | return -1; | |
414 | } | |
415 | } | |
feb82d0a DT |
416 | insn = bfd_getb32 (buffer); |
417 | ||
418 | #ifdef LOCAL_ONLY | |
419 | /* Get the architecture version of this machine, and assume | |
420 | it's the same as our target (this won't work for remote | |
421 | or core debugging, nor for looking at PA2.0 binaries from | |
422 | a 1.x machine, which is not only legal but part of our | |
423 | test system!). Values are: | |
424 | ||
425 | CPU_PA_RISC1_0 0x20B | |
426 | CPU_PA_RISC1_1 0x210 | |
427 | CPU_PA_RISC1_2 0x211 | |
428 | CPU_PA_RISC2_0 0x214 | |
429 | ||
430 | What we really want is a way to query the bfd for the | |
431 | architecture the binary was compiled/assembled for. */ | |
432 | if(!got_version_id) | |
433 | { | |
434 | int version_id; | |
435 | ||
436 | got_version_id = 1; | |
437 | version_id = sysconf (_SC_CPU_VERSION); | |
438 | switch (version_id) | |
439 | { | |
440 | case CPU_PA_RISC1_0 : | |
441 | case CPU_PA_RISC1_1 : | |
442 | case CPU_PA_RISC1_2 : | |
443 | pa_version = pa10; | |
444 | break; | |
445 | ||
446 | case CPU_PA_RISC2_0 : | |
447 | pa_version = pa20; | |
448 | break; | |
449 | ||
450 | default: | |
451 | /* Now what? */ | |
452 | break; | |
453 | } | |
454 | } | |
455 | #endif | |
112087ed | 456 | |
feb82d0a DT |
457 | /* This linear search through the opcode table is potentially |
458 | a bottleneck. If it becomes one, we can use the six-bit actual | |
459 | opcode as an index into a table of pointers to smaller tables. | |
460 | ||
461 | A better organization might use the fact that there are only | |
462 | about 40 distinct formats for instructions, rather than looking | |
463 | at the hundred-plus kinds of operands. */ | |
112087ed KR |
464 | for (i = 0; i < NUMOPCODES; ++i) |
465 | { | |
466 | const struct pa_opcode *opcode = &pa_opcodes[i]; | |
467 | if ((insn & opcode->mask) == opcode->match) | |
468 | { | |
469 | register const char *s; | |
feb82d0a DT |
470 | int added_space = 0; |
471 | ||
472 | #ifdef LOCAL_ONLY | |
473 | if (opcode->arch == pa20 | |
474 | && pa_version == pa10) | |
475 | /* Target file has new architecture, host is old. | |
476 | This can't be a correct match, can it? | |
477 | NOTE: the other way is ok. */ | |
478 | continue; | |
479 | #endif | |
480 | ||
481 | fputs_filtered (opcode->name, info); | |
112087ed | 482 | |
112087ed KR |
483 | for (s = opcode->args; *s != '\0'; ++s) |
484 | { | |
feb82d0a DT |
485 | if (!added_space |
486 | && 0 == strchr(completer_chars, *s)) | |
487 | { | |
488 | /* This is the first non-completer. | |
489 | Print a space here, after all completers, | |
490 | before any regular operands. */ | |
491 | fputs_filtered (" ", info); | |
492 | added_space = 1; | |
493 | } | |
494 | ||
495 | /* '*s' describes either an extraction and a format, | |
496 | or is a literal string to dump to the disassembly. */ | |
112087ed KR |
497 | switch (*s) |
498 | { | |
499 | case 'x': | |
500 | fput_reg (GET_FIELD (insn, 11, 15), info); | |
501 | break; | |
feb82d0a | 502 | |
112087ed KR |
503 | case 'X': |
504 | if (GET_FIELD (insn, 25, 25)) | |
feb82d0a DT |
505 | fput_fp_reg_r (GET_FIELD (insn, 11, 15), info); |
506 | else | |
507 | fput_fp_reg (GET_FIELD (insn, 11, 15), info); | |
508 | break; | |
509 | ||
510 | case 'g': | |
511 | if (GET_FIELD (insn, 30, 30)) | |
512 | fput_fp_reg_r (GET_FIELD (insn, 11, 15), info); | |
112087ed | 513 | else |
feb82d0a | 514 | fput_fp_reg (GET_FIELD (insn, 11, 15), info); |
112087ed | 515 | break; |
feb82d0a | 516 | |
112087ed KR |
517 | case 'b': |
518 | fput_reg (GET_FIELD (insn, 6, 10), info); | |
519 | break; | |
feb82d0a | 520 | |
112087ed KR |
521 | case '^': |
522 | fput_creg (GET_FIELD (insn, 6, 10), info); | |
523 | break; | |
feb82d0a | 524 | |
112087ed KR |
525 | case 'E': |
526 | if (GET_FIELD (insn, 25, 25)) | |
feb82d0a | 527 | fput_fp_reg_r (GET_FIELD (insn, 6, 10), info); |
112087ed | 528 | else |
feb82d0a | 529 | fput_fp_reg (GET_FIELD (insn, 6, 10), info); |
112087ed | 530 | break; |
feb82d0a | 531 | |
112087ed KR |
532 | case 't': |
533 | fput_reg (GET_FIELD (insn, 27, 31), info); | |
534 | break; | |
feb82d0a | 535 | |
112087ed KR |
536 | case 'v': |
537 | if (GET_FIELD (insn, 25, 25)) | |
feb82d0a | 538 | fput_fp_reg_r (GET_FIELD (insn, 27, 31), info); |
112087ed | 539 | else |
feb82d0a | 540 | fput_fp_reg (GET_FIELD (insn, 27, 31), info); |
18de15d8 | 541 | break; |
feb82d0a | 542 | |
18de15d8 JK |
543 | case 'y': |
544 | fput_fp_reg (GET_FIELD (insn, 27, 31), info); | |
112087ed | 545 | break; |
feb82d0a DT |
546 | |
547 | case 'B': | |
548 | fput_fp_reg (GET_FIELD (insn, 11, 15), info); | |
549 | break; | |
550 | ||
112087ed | 551 | case '4': |
e59f3227 JL |
552 | { |
553 | int reg = GET_FIELD (insn, 6, 10); | |
554 | ||
555 | reg |= (GET_FIELD (insn, 26, 26) << 4); | |
556 | fput_fp_reg (reg, info); | |
557 | break; | |
558 | } | |
feb82d0a | 559 | |
112087ed | 560 | case '6': |
e59f3227 JL |
561 | { |
562 | int reg = GET_FIELD (insn, 11, 15); | |
563 | ||
564 | reg |= (GET_FIELD (insn, 26, 26) << 4); | |
565 | fput_fp_reg (reg, info); | |
566 | break; | |
567 | } | |
feb82d0a | 568 | |
112087ed | 569 | case '7': |
e59f3227 JL |
570 | { |
571 | int reg = GET_FIELD (insn, 27, 31); | |
572 | ||
573 | reg |= (GET_FIELD (insn, 26, 26) << 4); | |
574 | fput_fp_reg (reg, info); | |
575 | break; | |
576 | } | |
feb82d0a | 577 | |
112087ed | 578 | case '8': |
e59f3227 JL |
579 | { |
580 | int reg = GET_FIELD (insn, 16, 20); | |
581 | ||
582 | reg |= (GET_FIELD (insn, 26, 26) << 4); | |
583 | fput_fp_reg (reg, info); | |
584 | break; | |
585 | } | |
feb82d0a | 586 | |
112087ed | 587 | case '9': |
e59f3227 JL |
588 | { |
589 | int reg = GET_FIELD (insn, 21, 25); | |
590 | ||
591 | reg |= (GET_FIELD (insn, 26, 26) << 4); | |
592 | fput_fp_reg (reg, info); | |
593 | break; | |
594 | } | |
feb82d0a | 595 | |
112087ed | 596 | case '5': |
feb82d0a | 597 | fput_hex_const (extract_5_load (insn), info); |
112087ed | 598 | break; |
feb82d0a | 599 | |
112087ed | 600 | case 's': |
e3960b96 JL |
601 | (*info->fprintf_func) (info->stream, |
602 | "sr%d", GET_FIELD (insn, 16, 17)); | |
112087ed | 603 | break; |
feb82d0a | 604 | |
112087ed | 605 | case 'S': |
feb82d0a DT |
606 | /* Used when 'assemble_3' is specified. |
607 | */ | |
608 | (*info->fprintf_func) (info->stream, "sr%d", | |
609 | extract_3 (insn)); | |
112087ed | 610 | break; |
feb82d0a | 611 | |
112087ed | 612 | case 'c': |
feb82d0a | 613 | fputs_filtered (index_compl_names[GET_COMPL (insn)], info); |
112087ed | 614 | break; |
feb82d0a | 615 | |
112087ed | 616 | case 'C': |
feb82d0a | 617 | fputs_filtered (short_ldst_compl_names[GET_COMPL_O (insn)], info); |
112087ed | 618 | break; |
feb82d0a DT |
619 | |
620 | case 'm': | |
621 | fputs_filtered (short_ldst_compl_names[ | |
622 | (GET_BIT(insn,29) << 1 | GET_BIT(insn,28)) ], | |
623 | info); | |
624 | break; | |
625 | ||
112087ed | 626 | case 'Y': |
feb82d0a | 627 | fputs_filtered (short_bytes_compl_names[GET_COMPL (insn)], info); |
112087ed | 628 | break; |
feb82d0a | 629 | |
112087ed KR |
630 | /* these four conditions are for the set of instructions |
631 | which distinguish true/false conditions by opcode rather | |
632 | than by the 'f' bit (sigh): comb, comib, addb, addib */ | |
633 | case '<': | |
634 | fputs_filtered (compare_cond_names[GET_FIELD (insn, 16, 18)], | |
635 | info); | |
636 | break; | |
feb82d0a | 637 | |
112087ed | 638 | case '?': |
feb82d0a DT |
639 | fputs_filtered (compare_cond_names[GET_FIELD (insn, 16, 18) |
640 | + GET_FIELD (insn, 4, 4) * 8], info); | |
112087ed | 641 | break; |
feb82d0a | 642 | |
112087ed | 643 | case '@': |
feb82d0a DT |
644 | fputs_filtered (add_cond_names[GET_FIELD (insn, 16, 18) |
645 | + GET_FIELD (insn, 4, 4) * 8], info); | |
112087ed | 646 | break; |
feb82d0a | 647 | |
5aef7c67 | 648 | case 'a': |
feb82d0a | 649 | fputs_filtered (compare_cond_names[GET_COND (insn)], info); |
112087ed | 650 | break; |
feb82d0a | 651 | |
5aef7c67 | 652 | case 'd': |
feb82d0a | 653 | fputs_filtered (add_cond_names[GET_COND (insn)], info); |
4d135f1c | 654 | break; |
feb82d0a | 655 | |
112087ed | 656 | case '!': |
feb82d0a | 657 | fputs_filtered (add_cond_names[GET_FIELD (insn, 16, 18)], info); |
112087ed KR |
658 | break; |
659 | ||
660 | case '&': | |
feb82d0a | 661 | fputs_filtered (logical_cond_names[GET_COND (insn)], info); |
112087ed | 662 | break; |
feb82d0a | 663 | |
112087ed | 664 | case 'U': |
feb82d0a | 665 | fputs_filtered (unit_cond_names[GET_COND (insn)], info); |
112087ed | 666 | break; |
feb82d0a | 667 | |
e3960b96 | 668 | case '|': |
112087ed KR |
669 | case '>': |
670 | case '~': | |
feb82d0a | 671 | fputs_filtered (shift_cond_names[GET_FIELD (insn, 16, 18)], info); |
112087ed | 672 | break; |
feb82d0a | 673 | |
112087ed | 674 | case 'V': |
feb82d0a | 675 | fput_hex_const (extract_5_store (insn), info); |
112087ed | 676 | break; |
feb82d0a | 677 | |
b2ad2e64 | 678 | case 'r': |
feb82d0a | 679 | fput_hex_const (extract_5r_store (insn), info); |
b2ad2e64 | 680 | break; |
feb82d0a | 681 | |
112087ed | 682 | case 'R': |
feb82d0a | 683 | fput_hex_const (extract_5R_store (insn), info); |
112087ed | 684 | break; |
feb82d0a | 685 | |
112087ed | 686 | case 'Q': |
feb82d0a | 687 | fput_hex_const (extract_5Q_store (insn), info); |
112087ed | 688 | break; |
feb82d0a | 689 | |
112087ed | 690 | case 'i': |
feb82d0a | 691 | fput_hex_const (extract_11 (insn), info); |
112087ed | 692 | break; |
feb82d0a | 693 | |
112087ed | 694 | case 'j': |
feb82d0a | 695 | fput_hex_const (extract_14 (insn), info); |
112087ed | 696 | break; |
feb82d0a | 697 | |
112087ed | 698 | case 'k': |
feb82d0a | 699 | fput_hex_const (extract_21 (insn), info); |
112087ed | 700 | break; |
feb82d0a | 701 | |
112087ed KR |
702 | case 'n': |
703 | if (insn & 0x2) | |
feb82d0a | 704 | fputs_filtered (",n", info); |
112087ed | 705 | break; |
feb82d0a | 706 | |
e3960b96 JL |
707 | case 'N': |
708 | if ((insn & 0x20) && s[1]) | |
feb82d0a | 709 | fputs_filtered (",n", info); |
e3960b96 | 710 | else if (insn & 0x20) |
feb82d0a | 711 | fputs_filtered (",n", info); |
e3960b96 | 712 | break; |
feb82d0a | 713 | |
112087ed KR |
714 | case 'w': |
715 | (*info->print_address_func) (memaddr + 8 + extract_12 (insn), | |
716 | info); | |
717 | break; | |
feb82d0a | 718 | |
112087ed | 719 | case 'W': |
feb82d0a | 720 | /* 17 bit PC-relative branch. */ |
e3960b96 JL |
721 | (*info->print_address_func) ((memaddr + 8 |
722 | + extract_17 (insn)), | |
723 | info); | |
724 | break; | |
feb82d0a | 725 | |
e3960b96 JL |
726 | case 'z': |
727 | /* 17 bit displacement. This is an offset from a register | |
728 | so it gets disasssembled as just a number, not any sort | |
feb82d0a DT |
729 | of address. */ |
730 | fput_hex_const (extract_17 (insn), info); | |
112087ed | 731 | break; |
feb82d0a | 732 | |
112087ed | 733 | case 'p': |
feb82d0a DT |
734 | if( pa20 != opcode->arch ) { |
735 | fput_decimal_const (31 - GET_FIELD (insn, 22, 26), info); | |
736 | } | |
737 | else { | |
738 | fput_decimal_const (63 - CATENATE (GET_BIT (insn, 20), 1, | |
739 | GET_FIELD (insn, 22, 26), 5), | |
740 | info); | |
741 | } | |
742 | break; | |
743 | ||
112087ed | 744 | case 'P': |
feb82d0a | 745 | fput_decimal_const (GET_FIELD (insn, 22, 26), info); |
112087ed | 746 | break; |
feb82d0a | 747 | |
112087ed | 748 | case 'T': |
feb82d0a | 749 | fput_decimal_const (32 - GET_FIELD (insn, 27, 31), info); |
112087ed | 750 | break; |
feb82d0a | 751 | |
112087ed | 752 | case 'A': |
feb82d0a | 753 | fput_hex_const (GET_FIELD (insn, 6, 18), info); |
112087ed | 754 | break; |
feb82d0a | 755 | |
112087ed KR |
756 | case 'Z': |
757 | if (GET_FIELD (insn, 26, 26)) | |
feb82d0a | 758 | fputs_filtered (",m", info); |
112087ed | 759 | break; |
feb82d0a | 760 | |
112087ed | 761 | case 'D': |
feb82d0a | 762 | fput_hex_const (GET_FIELD (insn, 6, 31), info); |
112087ed | 763 | break; |
feb82d0a | 764 | |
112087ed | 765 | case 'f': |
feb82d0a | 766 | fput_decimal_const (GET_FIELD (insn, 23, 25), info); |
112087ed | 767 | break; |
feb82d0a | 768 | |
112087ed | 769 | case 'O': |
feb82d0a | 770 | fput_hex_const ((GET_FIELD (insn, 6,20) << 5 | |
112087ed KR |
771 | GET_FIELD (insn, 27, 31)), info); |
772 | break; | |
feb82d0a | 773 | |
112087ed | 774 | case 'o': |
feb82d0a | 775 | fput_hex_const (GET_FIELD (insn, 6, 20), info); |
112087ed | 776 | break; |
feb82d0a | 777 | |
112087ed | 778 | case '2': |
feb82d0a | 779 | fput_hex_const ((GET_FIELD (insn, 6, 22) << 5 | |
112087ed KR |
780 | GET_FIELD (insn, 27, 31)), info); |
781 | break; | |
feb82d0a | 782 | |
112087ed | 783 | case '1': |
feb82d0a | 784 | fput_hex_const ((GET_FIELD (insn, 11, 20) << 5 | |
112087ed KR |
785 | GET_FIELD (insn, 27, 31)), info); |
786 | break; | |
feb82d0a | 787 | |
112087ed | 788 | case '0': |
feb82d0a | 789 | fput_hex_const ((GET_FIELD (insn, 16, 20) << 5 | |
112087ed KR |
790 | GET_FIELD (insn, 27, 31)), info); |
791 | break; | |
feb82d0a | 792 | |
112087ed | 793 | case 'u': |
feb82d0a | 794 | fput_decimal_const (GET_FIELD (insn, 23, 25), info); |
112087ed | 795 | break; |
feb82d0a | 796 | |
112087ed | 797 | case 'F': |
feb82d0a | 798 | fputs_filtered (float_format_names[GET_FIELD (insn, 19, 20)], |
112087ed | 799 | info); |
112087ed | 800 | break; |
feb82d0a | 801 | |
112087ed | 802 | case 'G': |
feb82d0a DT |
803 | fputs_filtered (float_format_names[GET_FIELD (insn, 17, 18)], |
804 | info); | |
112087ed | 805 | break; |
feb82d0a | 806 | |
112087ed | 807 | case 'H': |
e59f3227 | 808 | if (GET_FIELD (insn, 26, 26) == 1) |
feb82d0a | 809 | fputs_filtered (float_format_names[0], info); |
e59f3227 | 810 | else |
feb82d0a | 811 | fputs_filtered (float_format_names[1], info); |
112087ed | 812 | break; |
feb82d0a | 813 | |
112087ed | 814 | case 'I': |
e3960b96 JL |
815 | /* if no destination completer and not before a completer |
816 | for fcmp, need a space here */ | |
112087ed KR |
817 | fputs_filtered (float_format_names[GET_FIELD (insn, 20, 20)], |
818 | info); | |
112087ed | 819 | break; |
feb82d0a | 820 | |
112087ed KR |
821 | case 'J': |
822 | if (GET_FIELD (insn, 24, 24)) | |
feb82d0a | 823 | fput_fp_reg_r (GET_FIELD (insn, 6, 10), info); |
112087ed | 824 | else |
feb82d0a | 825 | fput_fp_reg (GET_FIELD (insn, 6, 10), info); |
112087ed | 826 | break; |
feb82d0a | 827 | |
112087ed KR |
828 | case 'K': |
829 | if (GET_FIELD (insn, 19, 19)) | |
feb82d0a | 830 | fput_fp_reg_r (GET_FIELD (insn, 11, 15), info); |
112087ed | 831 | else |
feb82d0a | 832 | fput_fp_reg (GET_FIELD (insn, 11, 15), info); |
112087ed | 833 | break; |
feb82d0a | 834 | |
112087ed | 835 | case 'M': |
feb82d0a DT |
836 | fputs_filtered (float_comp_names[GET_FIELD (insn, 27, 31)], |
837 | info); | |
838 | break; | |
839 | ||
840 | case 'L': { | |
841 | long temp; | |
842 | ||
843 | temp = GET_FIELD (insn, 18, 27) << 1; | |
844 | temp = assemble_16a (GET_FIELD (insn, 16, 17), | |
845 | temp, | |
846 | GET_BIT (insn, 31)); | |
847 | fput_hex_const (temp, info); | |
848 | break; | |
849 | } | |
850 | ||
851 | case 'l': { | |
852 | long temp; | |
853 | ||
854 | temp = assemble_16a (s, | |
855 | GET_FIELD (insn, 18, 28), | |
856 | GET_BIT (insn, 31)); | |
857 | fput_hex_const (temp, info); | |
858 | break; | |
859 | } | |
860 | ||
861 | case 'q': | |
862 | ||
863 | /* TEMP HACK - FIXME - edie */ | |
864 | fput_hex_const (sign_extend (GET_FIELD (insn, 20, 30), 0), info); | |
865 | break; | |
866 | ||
867 | case '#': | |
868 | fput_decimal_const (GET_FIELD (insn, 20, 28), info); | |
869 | break; | |
870 | ||
871 | case '$': | |
872 | fputs_filtered (branch_push_pop_names[GET_PUSH_POP(insn)], info); | |
873 | break; | |
874 | ||
875 | case '.': | |
876 | fput_creg( 11, info ); /* %cr11, printed by gdb as "sar" */ | |
877 | break; | |
878 | ||
879 | case '-': | |
880 | /* 22 bit PC-relative branch. */ | |
881 | (*info->print_address_func) (memaddr + 8 + | |
882 | (assemble_22 (GET_FIELD (insn, 6, 10), | |
883 | GET_FIELD (insn, 11, 15), | |
884 | GET_FIELD (insn, 19, 29), | |
885 | GET_FIELD (insn, 31, 31)) << 2), | |
886 | info); | |
887 | break; | |
888 | ||
889 | case '/': | |
890 | fputs_filtered (deposit_names[GET_BIT(insn,21)], info); | |
891 | break; | |
892 | ||
893 | case '*': | |
894 | /* TEMP HACK - FIXME - edie */ | |
895 | fput_decimal_const (sign_extend (assemble_6 (GET_BIT (insn, 23), | |
896 | GET_FIELD (insn, 27, 31)), 0), | |
897 | info); | |
898 | break; | |
899 | ||
900 | case '[': | |
901 | /* TEMP HACK - FIXME - edie */ | |
902 | fput_decimal_const (sign_extend (CATENATE (GET_BIT (insn, 20), 1, | |
903 | GET_FIELD (insn, 22, 26), 5), | |
904 | 0), | |
905 | info); | |
906 | break; | |
907 | ||
908 | case ']': | |
909 | /* TEMP HACK - FIXME - edie */ | |
910 | fput_decimal_const (sign_extend (assemble_6 (GET_BIT (insn, 19), GET_FIELD (insn, 27, 31)), 0), info); | |
911 | break; | |
912 | ||
913 | case '=': | |
914 | fputs_filtered (saturation_names[GET_FIELD(insn,24,25)], info); | |
915 | break; | |
916 | ||
917 | case ';': | |
918 | /* Always positive */ | |
919 | fput_decimal_const (GET_FIELD (insn, 24, 25), info); | |
920 | break; | |
921 | ||
922 | case ':': | |
923 | /* Always positive */ | |
924 | fput_decimal_const (GET_FIELD (insn, 22, 25), info); | |
925 | break; | |
926 | ||
927 | case '3': | |
928 | fputs_filtered (shift_names[GET_FIELD(insn,20,21)], info); | |
929 | break; | |
930 | ||
931 | case '%': | |
932 | fputs_filtered (",", info); | |
933 | fput_decimal_const (GET_FIELD (insn, 17, 18), info ); | |
934 | fput_decimal_const (GET_FIELD (insn, 20, 21), info ); | |
935 | fput_decimal_const (GET_FIELD (insn, 22, 23), info ); | |
936 | fput_decimal_const (GET_FIELD (insn, 24, 25), info ); | |
937 | break; | |
938 | ||
939 | case 'e': | |
940 | fputs_filtered (mix_names[GET_FIELD(insn,17,18)], info); | |
941 | break; | |
942 | ||
943 | case '}': | |
944 | fputs_filtered (conversion_names[GET_FIELD(insn,14,16)], info); | |
945 | break; | |
946 | ||
947 | case 'h': | |
948 | fput_hex_const (GET_FIELD (insn, 6, 15), info); | |
949 | break; | |
950 | ||
951 | case '_': | |
952 | fput_decimal_const ((GET_FIELD (insn, 16, 18) - 1), info); | |
953 | break; | |
954 | ||
955 | case '+': { | |
956 | int temp = GET_FIELD (insn, 16, 18) ^ 1; | |
957 | ||
958 | if (temp == 0) | |
959 | /* shouldn't happen, as spec says that if | |
960 | this field is "1", then it's a different | |
961 | format. */ | |
962 | fput_decimal_const (7, info); | |
963 | else | |
964 | fput_decimal_const (temp - 1, info); | |
965 | break; | |
966 | } | |
967 | ||
968 | case '{': | |
969 | /* Funky two-part six-bit register specifier */ | |
970 | if (GET_BIT (insn, 23)) | |
971 | fput_fp_reg_r (MERGED_REG (insn), info); | |
972 | else | |
973 | fput_fp_reg (MERGED_REG (insn), info); | |
112087ed | 974 | break; |
feb82d0a | 975 | |
112087ed KR |
976 | default: |
977 | (*info->fprintf_func) (info->stream, "%c", *s); | |
978 | break; | |
979 | } | |
feb82d0a DT |
980 | } /* For each operand */ |
981 | ||
982 | return sizeof (insn); | |
983 | } /* If matched */ | |
984 | } /* For each opcode */ | |
985 | ||
112087ed KR |
986 | (*info->fprintf_func) (info->stream, "#%8x", insn); |
987 | return sizeof(insn); | |
988 | } | |
feb82d0a | 989 |