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