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