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