]>
Commit | Line | Data |
---|---|---|
7d9884b9 | 1 | /* Print Pyramid Technology 90x instructions for GDB, the GNU Debugger. |
609f87d4 | 2 | Copyright 1988, 1989, 1991, 1992 Free Software Foundation, Inc. |
dd3b648e | 3 | |
609f87d4 | 4 | This file is part of GDB, the GNU debugger. |
dd3b648e | 5 | |
99a7de40 | 6 | This program is free software; you can redistribute it and/or modify |
dd3b648e | 7 | it under the terms of the GNU General Public License as published by |
99a7de40 JG |
8 | the Free Software Foundation; either version 2 of the License, or |
9 | (at your option) any later version. | |
dd3b648e | 10 | |
99a7de40 | 11 | This program is distributed in the hope that it will be useful, |
dd3b648e RP |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
99a7de40 JG |
17 | along with this program; if not, write to the Free Software |
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
dd3b648e | 19 | |
dd3b648e | 20 | #include "defs.h" |
dd3b648e | 21 | #include "symtab.h" |
aab77d5f | 22 | #include "opcode/pyr.h" |
dd3b648e RP |
23 | #include "gdbcore.h" |
24 | ||
25 | \f | |
26 | /* A couple of functions used for debugging frame-handling on | |
27 | Pyramids. (The Pyramid-dependent handling of register values for | |
28 | windowed registers is known to be buggy.) | |
29 | ||
7d9884b9 JG |
30 | When debugging, these functions can supplant the normal definitions of some |
31 | of the macros in tm-pyramid.h The quantity of information produced | |
dd3b648e RP |
32 | when these functions are used makes the gdb unusable as a |
33 | debugger for user programs. */ | |
34 | ||
35 | extern unsigned pyr_saved_pc(), pyr_frame_chain(); | |
36 | ||
37 | CORE_ADDR pyr_frame_chain(frame) | |
38 | CORE_ADDR frame; | |
39 | { | |
40 | int foo=frame - CONTROL_STACK_FRAME_SIZE; | |
41 | /* printf ("...following chain from %x: got %x\n", frame, foo);*/ | |
42 | return foo; | |
43 | } | |
44 | ||
45 | CORE_ADDR pyr_saved_pc(frame) | |
46 | CORE_ADDR frame; | |
47 | { | |
48 | int foo=0; | |
49 | foo = read_memory_integer (((CORE_ADDR)(frame))+60, 4); | |
50 | printf ("..reading pc from frame 0x%0x+%d regs: got %0x\n", | |
51 | frame, 60/4, foo); | |
52 | return foo; | |
53 | } | |
dd3b648e RP |
54 | |
55 | /* Pyramid instructions are never longer than this many bytes. */ | |
56 | #define MAXLEN 24 | |
57 | ||
58 | /* Number of elements in the opcode table. */ | |
59 | /*const*/ static int nopcodes = (sizeof (pyr_opcodes) / sizeof( pyr_opcodes[0])); | |
60 | #define NOPCODES (nopcodes) | |
61 | ||
609f87d4 | 62 | /* Let's be byte-independent so we can use this as a cross-assembler. */ |
dd3b648e RP |
63 | |
64 | #define NEXTLONG(p) \ | |
65 | (p += 4, (((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]) | |
dd3b648e RP |
66 | \f |
67 | /* Print one instruction at address MEMADDR in debugged memory, | |
68 | on STREAM. Returns length of the instruction, in bytes. */ | |
69 | ||
70 | int | |
71 | print_insn (memaddr, stream) | |
72 | CORE_ADDR memaddr; | |
73 | FILE *stream; | |
74 | { | |
75 | unsigned char buffer[MAXLEN]; | |
76 | register int i, nargs, insn_size =4; | |
77 | register unsigned char *p; | |
78 | register char *d; | |
79 | register int insn_opcode, operand_mode; | |
80 | register int index_multiplier, index_reg_regno, op_1_regno, op_2_regno ; | |
81 | long insn; /* first word of the insn, not broken down. */ | |
82 | pyr_insn_format insn_decode; /* the same, broken out into op{code,erands} */ | |
83 | long extra_1, extra_2; | |
84 | ||
85 | read_memory (memaddr, buffer, MAXLEN); | |
86 | insn_decode = *((pyr_insn_format *) buffer); | |
87 | insn = * ((int *) buffer); | |
88 | insn_opcode = insn_decode.operator; | |
89 | operand_mode = insn_decode.mode; | |
90 | index_multiplier = insn_decode.index_scale; | |
91 | index_reg_regno = insn_decode.index_reg; | |
92 | op_1_regno = insn_decode.operand_1; | |
93 | op_2_regno = insn_decode.operand_2; | |
94 | ||
95 | ||
96 | if (*((int *)buffer) == 0x0) { | |
97 | /* "halt" looks just like an invalid "jump" to the insn decoder, | |
98 | so is dealt with as a special case */ | |
99 | fprintf (stream, "halt"); | |
100 | return (4); | |
101 | } | |
102 | ||
103 | for (i = 0; i < NOPCODES; i++) | |
104 | if (pyr_opcodes[i].datum.code == insn_opcode) | |
105 | break; | |
106 | ||
107 | if (i == NOPCODES) | |
108 | /* FIXME: Handle unrecognised instructions better. */ | |
109 | fprintf (stream, "???\t#%08x\t(op=%x mode =%x)", | |
110 | insn, insn_decode.operator, insn_decode.mode); | |
111 | else | |
112 | { | |
113 | /* Print the mnemonic for the instruction. Pyramid insn operands | |
114 | are so regular that we can deal with almost all of them | |
115 | separately. | |
116 | Unconditional branches are an exception: they are encoded as | |
117 | conditional branches (branch if false condition, I think) | |
118 | with no condition specified. The average user will not be | |
119 | aware of this. To maintain their illusion that an | |
120 | unconditional branch insn exists, we will have to FIXME to | |
121 | treat the insn mnemnonic of all branch instructions here as a | |
122 | special case: check the operands of branch insn and print an | |
123 | appropriate mnemonic. */ | |
124 | ||
125 | fprintf (stream, "%s\t", pyr_opcodes[i].name); | |
126 | ||
127 | /* Print the operands of the insn (as specified in | |
128 | insn.operand_mode). | |
129 | Branch operands of branches are a special case: they are a word | |
130 | offset, not a byte offset. */ | |
131 | ||
132 | if (insn_decode.operator == 0x01 || insn_decode.operator == 0x02) { | |
133 | register int bit_codes=(insn >> 16)&0xf; | |
134 | register int i; | |
135 | register int displacement = (insn & 0x0000ffff) << 2; | |
136 | ||
137 | static char cc_bit_names[] = "cvzn"; /* z,n,c,v: strange order? */ | |
138 | ||
139 | /* Is bfc and no bits specified an unconditional branch?*/ | |
140 | for (i=0;i<4;i++) { | |
141 | if ((bit_codes) & 0x1) | |
142 | fputc (cc_bit_names[i], stream); | |
143 | bit_codes >>= 1; | |
144 | } | |
145 | ||
146 | fprintf (stream, ",%0x", | |
147 | displacement + memaddr); | |
148 | return (insn_size); | |
149 | } | |
150 | ||
151 | switch (operand_mode) { | |
152 | case 0: | |
153 | fprintf (stream, "%s,%s", | |
154 | reg_names [op_1_regno], | |
155 | reg_names [op_2_regno]); | |
156 | break; | |
157 | ||
158 | case 1: | |
159 | fprintf (stream, " 0x%0x,%s", | |
160 | op_1_regno, | |
161 | reg_names [op_2_regno]); | |
162 | break; | |
163 | ||
164 | case 2: | |
165 | read_memory (memaddr+4, buffer, MAXLEN); | |
166 | insn_size += 4; | |
167 | extra_1 = * ((int *) buffer); | |
168 | fprintf (stream, " $0x%0x,%s", | |
169 | extra_1, | |
170 | reg_names [op_2_regno]); | |
171 | break; | |
172 | case 3: | |
173 | fprintf (stream, " (%s),%s", | |
174 | reg_names [op_1_regno], | |
175 | reg_names [op_2_regno]); | |
176 | break; | |
177 | ||
178 | case 4: | |
179 | read_memory (memaddr+4, buffer, MAXLEN); | |
180 | insn_size += 4; | |
181 | extra_1 = * ((int *) buffer); | |
182 | fprintf (stream, " 0x%0x(%s),%s", | |
183 | extra_1, | |
184 | reg_names [op_1_regno], | |
185 | reg_names [op_2_regno]); | |
186 | break; | |
187 | ||
188 | /* S1 destination mode */ | |
189 | case 5: | |
190 | fprintf (stream, | |
191 | ((index_reg_regno) ? "%s,(%s)[%s*%1d]" : "%s,(%s)"), | |
192 | reg_names [op_1_regno], | |
193 | reg_names [op_2_regno], | |
194 | reg_names [index_reg_regno], | |
195 | index_multiplier); | |
196 | break; | |
197 | ||
198 | case 6: | |
199 | fprintf (stream, | |
200 | ((index_reg_regno) ? " $%#0x,(%s)[%s*%1d]" | |
201 | : " $%#0x,(%s)"), | |
202 | op_1_regno, | |
203 | reg_names [op_2_regno], | |
204 | reg_names [index_reg_regno], | |
205 | index_multiplier); | |
206 | break; | |
207 | ||
208 | case 7: | |
209 | read_memory (memaddr+4, buffer, MAXLEN); | |
210 | insn_size += 4; | |
211 | extra_1 = * ((int *) buffer); | |
212 | fprintf (stream, | |
213 | ((index_reg_regno) ? " $%#0x,(%s)[%s*%1d]" | |
214 | : " $%#0x,(%s)"), | |
215 | extra_1, | |
216 | reg_names [op_2_regno], | |
217 | reg_names [index_reg_regno], | |
218 | index_multiplier); | |
219 | break; | |
220 | ||
221 | case 8: | |
222 | fprintf (stream, | |
223 | ((index_reg_regno) ? " (%s),(%s)[%s*%1d]" : " (%s),(%s)"), | |
224 | reg_names [op_1_regno], | |
225 | reg_names [op_2_regno], | |
226 | reg_names [index_reg_regno], | |
227 | index_multiplier); | |
228 | break; | |
229 | ||
230 | case 9: | |
231 | read_memory (memaddr+4, buffer, MAXLEN); | |
232 | insn_size += 4; | |
233 | extra_1 = * ((int *) buffer); | |
234 | fprintf (stream, | |
235 | ((index_reg_regno) | |
236 | ? "%#0x(%s),(%s)[%s*%1d]" | |
237 | : "%#0x(%s),(%s)"), | |
238 | extra_1, | |
239 | reg_names [op_1_regno], | |
240 | reg_names [op_2_regno], | |
241 | reg_names [index_reg_regno], | |
242 | index_multiplier); | |
243 | break; | |
244 | ||
245 | /* S2 destination mode */ | |
246 | case 10: | |
247 | read_memory (memaddr+4, buffer, MAXLEN); | |
248 | insn_size += 4; | |
249 | extra_1 = * ((int *) buffer); | |
250 | fprintf (stream, | |
251 | ((index_reg_regno) ? "%s,%#0x(%s)[%s*%1d]" : "%s,%#0x(%s)"), | |
252 | reg_names [op_1_regno], | |
253 | extra_1, | |
254 | reg_names [op_2_regno], | |
255 | reg_names [index_reg_regno], | |
256 | index_multiplier); | |
257 | break; | |
258 | case 11: | |
259 | read_memory (memaddr+4, buffer, MAXLEN); | |
260 | insn_size += 4; | |
261 | extra_1 = * ((int *) buffer); | |
262 | fprintf (stream, | |
263 | ((index_reg_regno) ? | |
264 | " $%#0x,%#0x(%s)[%s*%1d]" : " $%#0x,%#0x(%s)"), | |
265 | op_1_regno, | |
266 | extra_1, | |
267 | reg_names [op_2_regno], | |
268 | reg_names [index_reg_regno], | |
269 | index_multiplier); | |
270 | break; | |
271 | case 12: | |
272 | read_memory (memaddr+4, buffer, MAXLEN); | |
273 | insn_size += 4; | |
274 | extra_1 = * ((int *) buffer); | |
275 | read_memory (memaddr+8, buffer, MAXLEN); | |
276 | insn_size += 4; | |
277 | extra_2 = * ((int *) buffer); | |
278 | fprintf (stream, | |
279 | ((index_reg_regno) ? | |
280 | " $%#0x,%#0x(%s)[%s*%1d]" : " $%#0x,%#0x(%s)"), | |
281 | extra_1, | |
282 | extra_2, | |
283 | reg_names [op_2_regno], | |
284 | reg_names [index_reg_regno], | |
285 | index_multiplier); | |
286 | break; | |
287 | ||
288 | case 13: | |
289 | read_memory (memaddr+4, buffer, MAXLEN); | |
290 | insn_size += 4; | |
291 | extra_1 = * ((int *) buffer); | |
292 | fprintf (stream, | |
293 | ((index_reg_regno) | |
294 | ? " (%s),%#0x(%s)[%s*%1d]" | |
295 | : " (%s),%#0x(%s)"), | |
296 | reg_names [op_1_regno], | |
297 | extra_1, | |
298 | reg_names [op_2_regno], | |
299 | reg_names [index_reg_regno], | |
300 | index_multiplier); | |
301 | break; | |
302 | case 14: | |
303 | read_memory (memaddr+4, buffer, MAXLEN); | |
304 | insn_size += 4; | |
305 | extra_1 = * ((int *) buffer); | |
306 | read_memory (memaddr+8, buffer, MAXLEN); | |
307 | insn_size += 4; | |
308 | extra_2 = * ((int *) buffer); | |
309 | fprintf (stream, | |
310 | ((index_reg_regno) ? "%#0x(%s),%#0x(%s)[%s*%1d]" | |
311 | : "%#0x(%s),%#0x(%s) "), | |
312 | extra_1, | |
313 | reg_names [op_1_regno], | |
314 | extra_2, | |
315 | reg_names [op_2_regno], | |
316 | reg_names [index_reg_regno], | |
317 | index_multiplier); | |
318 | break; | |
319 | ||
320 | default: | |
321 | fprintf (stream, | |
322 | ((index_reg_regno) ? "%s,%s [%s*%1d]" : "%s,%s"), | |
323 | reg_names [op_1_regno], | |
324 | reg_names [op_2_regno], | |
325 | reg_names [index_reg_regno], | |
326 | index_multiplier); | |
327 | fprintf (stream, | |
328 | "\t\t# unknown mode in %08x", | |
329 | insn); | |
330 | break; | |
331 | } /* switch */ | |
332 | } | |
333 | ||
334 | { | |
335 | return insn_size; | |
336 | } | |
337 | abort (); | |
338 | } |