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