4187119d |
1 | /* Print Convex instructions for GDB, the GNU debugger. |
2 | Copyright (C) 1989 Free Software Foundation, Inc. |
3 | |
4 | This file is part of GDB. |
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 | |
26 | /* reg (fmt_field, inst_field) -- |
27 | the {first,second,third} operand of instruction as fmt_field = [ijk] |
28 | gets the value of the field from the [ijk] position of the instruction */ |
29 | |
30 | #define reg(a,b) ((char (*)[3])(op[fmt->a]))[inst.f0.b] |
31 | |
32 | /* lit (fmt_field) -- field [ijk] is a literal (PSW, VL, eg) */ |
33 | |
34 | #define lit(i) op[fmt->i] |
35 | |
36 | /* aj[j] -- name for A register j */ |
37 | |
38 | #define aj ((char (*)[3])(op[A])) |
39 | \f |
40 | union inst { |
41 | struct { |
42 | unsigned : 7; |
43 | unsigned i : 3; |
44 | unsigned j : 3; |
45 | unsigned k : 3; |
46 | unsigned : 16; |
47 | unsigned : 32; |
48 | } f0; |
49 | struct { |
50 | unsigned : 8; |
51 | unsigned indir : 1; |
52 | unsigned len : 1; |
53 | unsigned j : 3; |
54 | unsigned k : 3; |
55 | unsigned : 16; |
56 | unsigned : 32; |
57 | } f1; |
58 | unsigned char byte[8]; |
59 | unsigned short half[4]; |
60 | char signed_byte[8]; |
61 | short signed_half[4]; |
62 | }; |
63 | |
64 | struct opform { |
65 | int mask; /* opcode mask */ |
66 | int shift; /* opcode align */ |
67 | struct formstr *formstr[3]; /* ST, E0, E1 */ |
68 | }; |
69 | |
70 | struct formstr { |
71 | unsigned lop:8, rop:5; /* opcode */ |
72 | unsigned fmt:5; /* inst format */ |
73 | unsigned i:5, j:5, k:2; /* operand formats */ |
74 | }; |
75 | |
76 | #include "convex-opcode.h" |
77 | |
78 | unsigned char formdecode [] = { |
79 | 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, |
80 | 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, |
81 | 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, |
82 | 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, |
83 | 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, |
84 | 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, |
85 | 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, |
86 | 4,4,4,4,4,4,4,4,5,5,5,5,6,6,7,8, |
87 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
88 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
89 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
90 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
91 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
92 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
93 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
94 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, |
95 | }; |
96 | |
97 | struct opform opdecode[] = { |
98 | 0x7e00, 9, format0, e0_format0, e1_format0, |
99 | 0x3f00, 8, format1, e0_format1, e1_format1, |
100 | 0x1fc0, 6, format2, e0_format2, e1_format2, |
101 | 0x0fc0, 6, format3, e0_format3, e1_format3, |
102 | 0x0700, 8, format4, e0_format4, e1_format4, |
103 | 0x03c0, 6, format5, e0_format5, e1_format5, |
104 | 0x01f8, 3, format6, e0_format6, e1_format6, |
105 | 0x00f8, 3, format7, e0_format7, e1_format7, |
106 | 0x0000, 0, formatx, formatx, formatx, |
107 | 0x0f80, 7, formatx, formatx, formatx, |
108 | 0x0f80, 7, formatx, formatx, formatx, |
109 | }; |
110 | \f |
111 | /* Print the instruction at address MEMADDR in debugged memory, |
112 | on STREAM. Returns length of the instruction, in bytes. */ |
113 | |
114 | int |
115 | print_insn (memaddr, stream) |
116 | CORE_ADDR memaddr; |
117 | FILE *stream; |
118 | { |
119 | union inst inst; |
120 | struct formstr *fmt; |
121 | register int format, op1, pfx; |
122 | int l; |
123 | |
124 | read_memory (memaddr, &inst, sizeof inst); |
125 | |
126 | /* Remove and note prefix, if present */ |
127 | |
128 | pfx = inst.half[0]; |
129 | if ((pfx & 0xfff0) == 0x7ef0) |
130 | { |
131 | pfx = ((pfx >> 3) & 1) + 1; |
132 | *(long long *) &inst = *(long long *) &inst.half[1]; |
133 | } |
134 | else pfx = 0; |
135 | |
136 | /* Split opcode into format.op1 and look up in appropriate table */ |
137 | |
138 | format = formdecode[inst.byte[0]]; |
139 | op1 = (inst.half[0] & opdecode[format].mask) >> opdecode[format].shift; |
140 | if (format == 9) |
141 | { |
142 | if (pfx) |
143 | fmt = formatx; |
144 | else if (inst.f1.j == 0) |
145 | fmt = &format1a[op1]; |
146 | else if (inst.f1.j == 1) |
147 | fmt = &format1b[op1]; |
148 | else |
149 | fmt = formatx; |
150 | } |
151 | else |
152 | fmt = &opdecode[format].formstr[pfx][op1]; |
153 | |
154 | /* Print it */ |
155 | |
156 | if (fmt->fmt == xxx) |
157 | { |
158 | /* noninstruction */ |
159 | fprintf (stream, "0x%04x", pfx ? pfx : inst.half[0]); |
160 | return 2; |
161 | } |
162 | |
163 | if (pfx) |
164 | pfx = 2; |
165 | |
166 | fprintf (stream, "%s%s%s", lop[fmt->lop], rop[fmt->rop], |
167 | &" "[strlen(lop[fmt->lop]) + strlen(rop[fmt->rop])]); |
168 | |
169 | switch (fmt->fmt) |
170 | { |
171 | case rrr: /* three register */ |
172 | fprintf (stream, "%s,%s,%s", reg(i,i), reg(j,j), reg(k,k)); |
173 | return pfx + 2; |
174 | |
175 | case rr: /* two register */ |
176 | fprintf (stream, "%s,%s", reg(i,j), reg(j,k)); |
177 | return pfx + 2; |
178 | |
179 | case rxr: /* two register, reversed i and j fields */ |
180 | fprintf (stream, "%s,%s", reg(i,k), reg(j,j)); |
181 | return pfx + 2; |
182 | |
183 | case r: /* one register */ |
184 | fprintf (stream, "%s", reg(i,k)); |
185 | return pfx + 2; |
186 | |
187 | case nops: /* no operands */ |
188 | return pfx + 2; |
189 | |
190 | case nr: /* short immediate, one register */ |
191 | fprintf (stream, "#%d,%s", inst.f0.j, reg(i,k)); |
192 | return pfx + 2; |
193 | |
194 | case pcrel: /* pc relative */ |
195 | print_address (memaddr + 2 * inst.signed_byte[1], stream); |
196 | return pfx + 2; |
197 | |
198 | case lr: /* literal, one register */ |
199 | fprintf (stream, "%s,%s", lit(i), reg(j,k)); |
200 | return pfx + 2; |
201 | |
202 | case rxl: /* one register, literal */ |
203 | fprintf (stream, "%s,%s", reg(i,k), lit(j)); |
204 | return pfx + 2; |
205 | |
206 | case rlr: /* register, literal, register */ |
207 | fprintf (stream, "%s,%s,%s", reg(i,j), lit(j), reg(k,k)); |
208 | return pfx + 2; |
209 | |
210 | case rrl: /* register, register, literal */ |
211 | fprintf (stream, "%s,%s,%s", reg(i,j), reg(j,k), lit(k)); |
212 | return pfx + 2; |
213 | |
214 | case iml: /* immediate, literal */ |
215 | if (inst.f1.len) |
216 | { |
217 | fprintf (stream, "#%#x,%s", |
218 | (inst.signed_half[1] << 16) + inst.half[2], lit(i)); |
219 | return pfx + 6; |
220 | } |
221 | else |
222 | { |
223 | fprintf (stream, "#%d,%s", inst.signed_half[1], lit(i)); |
224 | return pfx + 4; |
225 | } |
226 | |
227 | case imr: /* immediate, register */ |
228 | if (inst.f1.len) |
229 | { |
230 | fprintf (stream, "#%#x,%s", |
231 | (inst.signed_half[1] << 16) + inst.half[2], reg(i,k)); |
232 | return pfx + 6; |
233 | } |
234 | else |
235 | { |
236 | fprintf (stream, "#%d,%s", inst.signed_half[1], reg(i,k)); |
237 | return pfx + 4; |
238 | } |
239 | |
240 | case a1r: /* memory, register */ |
241 | l = print_effa (inst, stream); |
242 | fprintf (stream, ",%s", reg(i,k)); |
243 | return pfx + l; |
244 | |
245 | case a1l: /* memory, literal */ |
246 | l = print_effa (inst, stream); |
247 | fprintf (stream, ",%s", lit(i)); |
248 | return pfx + l; |
249 | |
250 | case a2r: /* register, memory */ |
251 | fprintf (stream, "%s,", reg(i,k)); |
252 | return pfx + print_effa (inst, stream); |
253 | |
254 | case a2l: /* literal, memory */ |
255 | fprintf (stream, "%s,", lit(i)); |
256 | return pfx + print_effa (inst, stream); |
257 | |
258 | case a3: /* memory */ |
259 | return pfx + print_effa (inst, stream); |
260 | |
261 | case a4: /* system call */ |
262 | l = 29; goto a4a5; |
263 | case a5: /* trap */ |
264 | l = 27; |
265 | a4a5: |
266 | if (inst.f1.len) |
267 | { |
268 | unsigned int m = (inst.signed_half[1] << 16) + inst.half[2]; |
269 | fprintf (stream, "#%d,#%d", m >> l, m & (-1 >> (32-l))); |
270 | return pfx + 6; |
271 | } |
272 | else |
273 | { |
274 | unsigned int m = inst.signed_half[1]; |
275 | fprintf (stream, "#%d,#%d", m >> l, m & (-1 >> (32-l))); |
276 | return pfx + 4; |
277 | } |
278 | } |
279 | } |
280 | |
281 | |
282 | /* print effective address @nnn(aj), return instruction length */ |
283 | |
284 | int print_effa (inst, stream) |
285 | union inst inst; |
286 | FILE *stream; |
287 | { |
288 | int n, l; |
289 | |
290 | if (inst.f1.len) |
291 | { |
292 | n = (inst.signed_half[1] << 16) + inst.half[2]; |
293 | l = 6; |
294 | } |
295 | else |
296 | { |
297 | n = inst.signed_half[1]; |
298 | l = 4; |
299 | } |
300 | |
301 | if (inst.f1.indir) |
302 | printf ("@"); |
303 | |
304 | if (!inst.f1.j) |
305 | { |
306 | print_address (n, stream); |
307 | return l; |
308 | } |
309 | |
310 | fprintf (stream, (n & 0xf0000000) == 0x80000000 ? "%#x(%s)" : "%d(%s)", |
311 | n, aj[inst.f1.j]); |
312 | |
313 | return l; |
314 | } |