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