a0c57aca8576c3981b3d1741373e5db2a5e5abac
[deliverable/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 STREAM.
125 Return the size of the instruction (always 4 on a29k). */
126 static int
127 print_insn (memaddr, info)
128 bfd_vma memaddr;
129 struct disassemble_info *info;
130 {
131 /* The raw instruction. */
132 char insn[4];
133
134 /* The four bytes of the instruction. */
135 unsigned char insn24, insn16, insn8, insn0;
136
137 find_byte_func_type find_byte_func = (find_byte_func_type)info->private_data;
138
139 struct a29k_opcode CONST * opcode;
140
141 {
142 int status =
143 (*info->read_memory_func) (memaddr, (bfd_byte *) &insn[0], 4, info);
144 if (status != 0)
145 {
146 (*info->memory_error_func) (status, memaddr, info);
147 return -1;
148 }
149 }
150
151 (*find_byte_func) (insn, &insn0, &insn8, &insn16, &insn24);
152
153 /* Handle the nop (aseq 0x40,gr1,gr1) specially */
154 if ((insn24==0x70) && (insn16==0x40) && (insn8==0x01) && (insn0==0x01)) {
155 (*info->fprintf_func) (info->stream,"nop");
156 return 4;
157 }
158
159 /* The opcode is always in insn24. */
160 for (opcode = &a29k_opcodes[0];
161 opcode < &a29k_opcodes[num_opcodes];
162 ++opcode)
163 {
164 if ((insn24<<24) == opcode->opcode)
165 {
166 char *s;
167
168 (*info->fprintf_func) (info->stream, "%s ", opcode->name);
169 for (s = opcode->args; *s != '\0'; ++s)
170 {
171 switch (*s)
172 {
173 case 'a':
174 print_general (insn8, info);
175 break;
176
177 case 'b':
178 print_general (insn0, info);
179 break;
180
181 case 'c':
182 print_general (insn16, info);
183 break;
184
185 case 'i':
186 (*info->fprintf_func) (info->stream, "%d", insn0);
187 break;
188
189 case 'x':
190 (*info->fprintf_func) (info->stream, "%d", (insn16 << 8) + insn0);
191 break;
192
193 case 'h':
194 /* This used to be %x for binutils. */
195 (*info->fprintf_func) (info->stream, "0x%x",
196 (insn16 << 24) + (insn0 << 16));
197 break;
198
199 case 'X':
200 (*info->fprintf_func) (info->stream, "%d",
201 ((insn16 << 8) + insn0) | 0xffff0000);
202 break;
203
204 case 'P':
205 /* This output looks just like absolute addressing, but
206 maybe that's OK (it's what the GDB m68k and EBMON
207 a29k disassemblers do). */
208 /* All the shifting is to sign-extend it. p*/
209 (*info->print_address_func)
210 (memaddr +
211 (((int)((insn16 << 10) + (insn0 << 2)) << 14) >> 14),
212 info);
213 break;
214
215 case 'A':
216 (*info->print_address_func)
217 ((insn16 << 10) + (insn0 << 2), info);
218 break;
219
220 case 'e':
221 (*info->fprintf_func) (info->stream, "%d", insn16 >> 7);
222 break;
223
224 case 'n':
225 (*info->fprintf_func) (info->stream, "0x%x", insn16 & 0x7f);
226 break;
227
228 case 'v':
229 (*info->fprintf_func) (info->stream, "0x%x", insn16);
230 break;
231
232 case 's':
233 print_special (insn8, info);
234 break;
235
236 case 'u':
237 (*info->fprintf_func) (info->stream, "%d", insn0 >> 7);
238 break;
239
240 case 'r':
241 (*info->fprintf_func) (info->stream, "%d", (insn0 >> 4) & 7);
242 break;
243
244 case 'd':
245 (*info->fprintf_func) (info->stream, "%d", (insn0 >> 2) & 3);
246 break;
247
248 case 'f':
249 (*info->fprintf_func) (info->stream, "%d", insn0 & 3);
250 break;
251
252 case 'F':
253 (*info->fprintf_func) (info->stream, "%d", (insn16 >> 2) & 15);
254 break;
255
256 case 'C':
257 (*info->fprintf_func) (info->stream, "%d", insn16 & 3);
258 break;
259
260 default:
261 (*info->fprintf_func) (info->stream, "%c", *s);
262 }
263 }
264
265 /* Now we look for a const,consth pair of instructions,
266 in which case we try to print the symbolic address. */
267 if (insn24 == 2) /* consth */
268 {
269 int errcode;
270 char prev_insn[4];
271 unsigned char prev_insn0, prev_insn8, prev_insn16, prev_insn24;
272
273 errcode = (*info->read_memory_func) (memaddr - 4,
274 (bfd_byte *) &prev_insn[0],
275 4,
276 info);
277 if (errcode == 0)
278 {
279 /* If it is a delayed branch, we need to look at the
280 instruction before the delayed brach to handle
281 things like
282
283 const _foo
284 call _printf
285 consth _foo
286 */
287 (*find_byte_func) (prev_insn, &prev_insn0, &prev_insn8,
288 &prev_insn16, &prev_insn24);
289 if (is_delayed_branch (prev_insn24))
290 {
291 errcode = (*info->read_memory_func)
292 (memaddr - 8, (bfd_byte *) &prev_insn[0], 4, info);
293 (*find_byte_func) (prev_insn, &prev_insn0, &prev_insn8,
294 &prev_insn16, &prev_insn24);
295 }
296 }
297
298 /* If there was a problem reading memory, then assume
299 the previous instruction was not const. */
300 if (errcode == 0)
301 {
302 /* Is it const to the same register? */
303 if (prev_insn24 == 3
304 && prev_insn8 == insn8)
305 {
306 (*info->fprintf_func) (info->stream, "\t; ");
307 (*info->print_address_func)
308 (((insn16 << 24) + (insn0 << 16)
309 + (prev_insn16 << 8) + (prev_insn0)),
310 info);
311 }
312 }
313 }
314
315 return 4;
316 }
317 }
318 /* This used to be %8x for binutils. */
319 (*info->fprintf_func)
320 (info->stream, ".word 0x%8x",
321 (insn24 << 24) + (insn16 << 16) + (insn8 << 8) + insn0);
322 return 4;
323 }
324
325 /* Disassemble an big-endian a29k instruction. */
326 int
327 print_insn_big_a29k (memaddr, info)
328 bfd_vma memaddr;
329 struct disassemble_info *info;
330 {
331 info->private_data = (PTR) find_bytes_big;
332 return print_insn (memaddr, info);
333 }
334
335 /* Disassemble a little-endian a29k instruction. */
336 int
337 print_insn_little_a29k (memaddr, info)
338 bfd_vma memaddr;
339 struct disassemble_info *info;
340 {
341 info->private_data = (PTR) find_bytes_little;
342 return print_insn (memaddr, info);
343 }
This page took 0.079734 seconds and 4 git commands to generate.