7a67dd45 |
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 | |
6 | GDB is free software; you can redistribute it and/or modify |
7 | it under the terms of the GNU General Public License as published by |
8 | the Free Software Foundation; either version 1, or (at your option) |
9 | any later version. |
10 | |
11 | GDB is distributed in the hope that it will be useful, |
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 |
17 | along with GDB; see the file COPYING. If not, write to |
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ |
19 | |
20 | #include <stdio.h> |
21 | |
22 | #include "defs.h" |
23 | #include "param.h" |
24 | #include "symtab.h" |
25 | #include "opcode.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 | |
32 | When debugging, these functions supplant the normal definitions of some |
33 | of the macros in m-pyramid.h The quantity of information produced |
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 | } |