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