* a29k-dis.c (print_insn): Print the opcode.
[binutils-gdb.git] / opcodes / a29k-dis.c
1 /* Instruction printing code for the AMD 29000
2 Copyright (C) 1990 Free Software Foundation, Inc.
3 Contributed by Cygnus Support. Written by Jim Kingdon.
4
5 This file is part of GDB.
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
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
20
21 #include "dis-asm.h"
22 #include "opcode/a29k.h"
23
24 /* Print a symbolic representation of a general-purpose
25 register number NUM on STREAM.
26 NUM is a number as found in the instruction, not as found in
27 debugging symbols; it must be in the range 0-255. */
28 static void
29 print_general (num, info)
30 int num;
31 struct disassemble_info *info;
32 {
33 if (num < 128)
34 (*info->fprintf_func) (info->stream, "gr%d", num);
35 else
36 (*info->fprintf_func) (info->stream, "lr%d", num - 128);
37 }
38
39 /* Like print_general but a special-purpose register.
40
41 The mnemonics used by the AMD assembler are not quite the same
42 as the ones in the User's Manual. We use the ones that the
43 assembler uses. */
44 static void
45 print_special (num, info)
46 int num;
47 struct disassemble_info *info;
48 {
49 /* Register names of registers 0-SPEC0_NUM-1. */
50 static char *spec0_names[] = {
51 "vab", "ops", "cps", "cfg", "cha", "chd", "chc", "rbp", "tmc", "tmr",
52 "pc0", "pc1", "pc2", "mmu", "lru"
53 };
54 #define SPEC0_NUM ((sizeof spec0_names) / (sizeof spec0_names[0]))
55
56 /* Register names of registers 128-128+SPEC128_NUM-1. */
57 static char *spec128_names[] = {
58 "ipc", "ipa", "ipb", "q", "alu", "bp", "fc", "cr"
59 };
60 #define SPEC128_NUM ((sizeof spec128_names) / (sizeof spec128_names[0]))
61
62 /* Register names of registers 160-160+SPEC160_NUM-1. */
63 static char *spec160_names[] = {
64 "fpe", "inte", "fps", "sr163", "exop"
65 };
66 #define SPEC160_NUM ((sizeof spec160_names) / (sizeof spec160_names[0]))
67
68 if (num < SPEC0_NUM)
69 (*info->fprintf_func) (info->stream, spec0_names[num]);
70 else if (num >= 128 && num < 128 + SPEC128_NUM)
71 (*info->fprintf_func) (info->stream, spec128_names[num-128]);
72 else if (num >= 160 && num < 160 + SPEC160_NUM)
73 (*info->fprintf_func) (info->stream, spec160_names[num-160]);
74 else
75 (*info->fprintf_func) (info->stream, "sr%d", num);
76 }
77
78 /* Is an instruction with OPCODE a delayed branch? */
79 static int
80 is_delayed_branch (opcode)
81 int opcode;
82 {
83 return (opcode == 0xa8 || opcode == 0xa9 || opcode == 0xa0 || opcode == 0xa1
84 || opcode == 0xa4 || opcode == 0xa5
85 || opcode == 0xb4 || opcode == 0xb5
86 || opcode == 0xc4 || opcode == 0xc0
87 || opcode == 0xac || opcode == 0xad
88 || opcode == 0xcc);
89 }
90
91 /* Now find the four bytes of INSN and put them in *INSN{0,8,16,24}. */
92 static void
93 find_bytes_big (insn, insn0, insn8, insn16, insn24)
94 char *insn;
95 unsigned char *insn0;
96 unsigned char *insn8;
97 unsigned char *insn16;
98 unsigned char *insn24;
99 {
100 *insn24 = insn[0];
101 *insn16 = insn[1];
102 *insn8 = insn[2];
103 *insn0 = insn[3];
104 }
105
106 static void
107 find_bytes_little (insn, insn0, insn8, insn16, insn24)
108 char *insn;
109 unsigned char *insn0;
110 unsigned char *insn8;
111 unsigned char *insn16;
112 unsigned char *insn24;
113 {
114 *insn24 = insn[3];
115 *insn16 = insn[2];
116 *insn8 = insn[1];
117 *insn0 = insn[0];
118 }
119
120 typedef (*find_byte_func_type)
121 PARAMS ((char *, unsigned char *, unsigned char *,
122 unsigned char *, unsigned char *));
123
124 /* Print one instruction from MEMADDR on INFO->STREAM.
125 Return the size of the instruction (always 4 on a29k). */
126
127 static int
128 print_insn (memaddr, info)
129 bfd_vma memaddr;
130 struct disassemble_info *info;
131 {
132 /* The raw instruction. */
133 char insn[4];
134
135 /* The four bytes of the instruction. */
136 unsigned char insn24, insn16, insn8, insn0;
137
138 find_byte_func_type find_byte_func = (find_byte_func_type)info->private_data;
139
140 struct a29k_opcode CONST * opcode;
141
142 {
143 int status =
144 (*info->read_memory_func) (memaddr, (bfd_byte *) &insn[0], 4, info);
145 if (status != 0)
146 {
147 (*info->memory_error_func) (status, memaddr, info);
148 return -1;
149 }
150 }
151
152 (*find_byte_func) (insn, &insn0, &insn8, &insn16, &insn24);
153
154 printf ("%02x%02x%02x%02x ", insn24, insn16, insn8, insn0);
155
156 /* Handle the nop (aseq 0x40,gr1,gr1) specially */
157 if ((insn24==0x70) && (insn16==0x40) && (insn8==0x01) && (insn0==0x01)) {
158 (*info->fprintf_func) (info->stream,"nop");
159 return 4;
160 }
161
162 /* The opcode is always in insn24. */
163 for (opcode = &a29k_opcodes[0];
164 opcode < &a29k_opcodes[num_opcodes];
165 ++opcode)
166 {
167 if ((insn24<<24) == opcode->opcode)
168 {
169 char *s;
170
171 (*info->fprintf_func) (info->stream, "%s ", opcode->name);
172 for (s = opcode->args; *s != '\0'; ++s)
173 {
174 switch (*s)
175 {
176 case 'a':
177 print_general (insn8, info);
178 break;
179
180 case 'b':
181 print_general (insn0, info);
182 break;
183
184 case 'c':
185 print_general (insn16, info);
186 break;
187
188 case 'i':
189 (*info->fprintf_func) (info->stream, "%d", insn0);
190 break;
191
192 case 'x':
193 (*info->fprintf_func) (info->stream, "0x%x", (insn16 << 8) + insn0);
194 break;
195
196 case 'h':
197 /* This used to be %x for binutils. */
198 (*info->fprintf_func) (info->stream, "0x%x",
199 (insn16 << 24) + (insn0 << 16));
200 break;
201
202 case 'X':
203 (*info->fprintf_func) (info->stream, "%d",
204 ((insn16 << 8) + insn0) | 0xffff0000);
205 break;
206
207 case 'P':
208 /* This output looks just like absolute addressing, but
209 maybe that's OK (it's what the GDB m68k and EBMON
210 a29k disassemblers do). */
211 /* All the shifting is to sign-extend it. p*/
212 (*info->print_address_func)
213 (memaddr +
214 (((int)((insn16 << 10) + (insn0 << 2)) << 14) >> 14),
215 info);
216 break;
217
218 case 'A':
219 (*info->print_address_func)
220 ((insn16 << 10) + (insn0 << 2), info);
221 break;
222
223 case 'e':
224 (*info->fprintf_func) (info->stream, "%d", insn16 >> 7);
225 break;
226
227 case 'n':
228 (*info->fprintf_func) (info->stream, "0x%x", insn16 & 0x7f);
229 break;
230
231 case 'v':
232 (*info->fprintf_func) (info->stream, "0x%x", insn16);
233 break;
234
235 case 's':
236 print_special (insn8, info);
237 break;
238
239 case 'u':
240 (*info->fprintf_func) (info->stream, "%d", insn0 >> 7);
241 break;
242
243 case 'r':
244 (*info->fprintf_func) (info->stream, "%d", (insn0 >> 4) & 7);
245 break;
246
247 case 'd':
248 (*info->fprintf_func) (info->stream, "%d", (insn0 >> 2) & 3);
249 break;
250
251 case 'f':
252 (*info->fprintf_func) (info->stream, "%d", insn0 & 3);
253 break;
254
255 case 'F':
256 (*info->fprintf_func) (info->stream, "%d", (insn16 >> 2) & 15);
257 break;
258
259 case 'C':
260 (*info->fprintf_func) (info->stream, "%d", insn16 & 3);
261 break;
262
263 default:
264 (*info->fprintf_func) (info->stream, "%c", *s);
265 }
266 }
267
268 /* Now we look for a const,consth pair of instructions,
269 in which case we try to print the symbolic address. */
270 if (insn24 == 2) /* consth */
271 {
272 int errcode;
273 char prev_insn[4];
274 unsigned char prev_insn0, prev_insn8, prev_insn16, prev_insn24;
275
276 errcode = (*info->read_memory_func) (memaddr - 4,
277 (bfd_byte *) &prev_insn[0],
278 4,
279 info);
280 if (errcode == 0)
281 {
282 /* If it is a delayed branch, we need to look at the
283 instruction before the delayed brach to handle
284 things like
285
286 const _foo
287 call _printf
288 consth _foo
289 */
290 (*find_byte_func) (prev_insn, &prev_insn0, &prev_insn8,
291 &prev_insn16, &prev_insn24);
292 if (is_delayed_branch (prev_insn24))
293 {
294 errcode = (*info->read_memory_func)
295 (memaddr - 8, (bfd_byte *) &prev_insn[0], 4, info);
296 (*find_byte_func) (prev_insn, &prev_insn0, &prev_insn8,
297 &prev_insn16, &prev_insn24);
298 }
299 }
300
301 /* If there was a problem reading memory, then assume
302 the previous instruction was not const. */
303 if (errcode == 0)
304 {
305 /* Is it const to the same register? */
306 if (prev_insn24 == 3
307 && prev_insn8 == insn8)
308 {
309 (*info->fprintf_func) (info->stream, "\t; ");
310 (*info->print_address_func)
311 (((insn16 << 24) + (insn0 << 16)
312 + (prev_insn16 << 8) + (prev_insn0)),
313 info);
314 }
315 }
316 }
317
318 return 4;
319 }
320 }
321 /* This used to be %8x for binutils. */
322 (*info->fprintf_func)
323 (info->stream, ".word 0x%08x",
324 (insn24 << 24) + (insn16 << 16) + (insn8 << 8) + insn0);
325 return 4;
326 }
327
328 /* Disassemble an big-endian a29k instruction. */
329 int
330 print_insn_big_a29k (memaddr, info)
331 bfd_vma memaddr;
332 struct disassemble_info *info;
333 {
334 info->private_data = (PTR) find_bytes_big;
335 return print_insn (memaddr, info);
336 }
337
338 /* Disassemble a little-endian a29k instruction. */
339 int
340 print_insn_little_a29k (memaddr, info)
341 bfd_vma memaddr;
342 struct disassemble_info *info;
343 {
344 info->private_data = (PTR) find_bytes_little;
345 return print_insn (memaddr, info);
346 }