1 |
cebix |
1.1 |
/* Print Motorola 68k instructions. |
2 |
|
|
Copyright 1986, 87, 89, 91, 92, 93, 94, 95, 96, 97, 1998 |
3 |
|
|
Free Software Foundation, Inc. |
4 |
|
|
|
5 |
|
|
This file is free software; you can redistribute it and/or modify |
6 |
|
|
it under the terms of the GNU General Public License as published by |
7 |
|
|
the Free Software Foundation; either version 2 of the License, or |
8 |
|
|
(at your option) any later version. |
9 |
|
|
|
10 |
|
|
This program is distributed in the hope that it will be useful, |
11 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 |
|
|
GNU General Public License for more details. |
14 |
|
|
|
15 |
|
|
You should have received a copy of the GNU General Public License |
16 |
|
|
along with this program; if not, write to the Free Software |
17 |
|
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
18 |
|
|
|
19 |
|
|
#include "dis-asm.h" |
20 |
|
|
#include "floatformat.h" |
21 |
|
|
#include "opintl.h" |
22 |
|
|
|
23 |
|
|
#include "m68k.h" |
24 |
|
|
|
25 |
|
|
/* Local function prototypes */ |
26 |
|
|
|
27 |
|
|
static int |
28 |
|
|
fetch_data PARAMS ((struct disassemble_info *, bfd_byte *)); |
29 |
|
|
|
30 |
|
|
static void |
31 |
|
|
dummy_print_address PARAMS ((bfd_vma, struct disassemble_info *)); |
32 |
|
|
|
33 |
|
|
static int |
34 |
|
|
fetch_arg PARAMS ((unsigned char *, int, int, disassemble_info *)); |
35 |
|
|
|
36 |
|
|
static void |
37 |
|
|
print_base PARAMS ((int, bfd_vma, disassemble_info*)); |
38 |
|
|
|
39 |
|
|
static unsigned char * |
40 |
|
|
print_indexed PARAMS ((int, unsigned char *, bfd_vma, disassemble_info *)); |
41 |
|
|
|
42 |
|
|
static int |
43 |
|
|
print_insn_arg PARAMS ((const char *, unsigned char *, unsigned char *, |
44 |
|
|
bfd_vma, disassemble_info *)); |
45 |
|
|
|
46 |
|
|
CONST char * CONST fpcr_names[] = { |
47 |
|
|
"", "fpiar", "fpsr", "fpiar/fpsr", "fpcr", |
48 |
|
|
"fpiar/fpcr", "fpsr/fpcr", "fpiar/fpsr/fpcr"}; |
49 |
|
|
|
50 |
|
|
static char *const reg_names[] = { |
51 |
|
|
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", |
52 |
|
|
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", |
53 |
|
|
"sr", "pc"}; |
54 |
|
|
|
55 |
|
|
/* Sign-extend an (unsigned char). */ |
56 |
|
|
#if __STDC__ == 1 |
57 |
|
|
#define COERCE_SIGNED_CHAR(ch) ((signed char)(ch)) |
58 |
|
|
#else |
59 |
|
|
#define COERCE_SIGNED_CHAR(ch) ((int)(((ch) ^ 0x80) & 0xFF) - 128) |
60 |
|
|
#endif |
61 |
|
|
|
62 |
|
|
/* Get a 1 byte signed integer. */ |
63 |
|
|
#define NEXTBYTE(p) (p += 2, FETCH_DATA (info, p), COERCE_SIGNED_CHAR(p[-1])) |
64 |
|
|
|
65 |
|
|
/* Get a 2 byte signed integer. */ |
66 |
|
|
#define COERCE16(x) ((int) (((x) ^ 0x8000) - 0x8000)) |
67 |
|
|
#define NEXTWORD(p) \ |
68 |
|
|
(p += 2, FETCH_DATA (info, p), \ |
69 |
|
|
COERCE16 ((p[-2] << 8) + p[-1])) |
70 |
|
|
|
71 |
|
|
/* Get a 4 byte signed integer. */ |
72 |
|
|
#define COERCE32(x) ((bfd_signed_vma) ((x) ^ 0x80000000) - 0x80000000) |
73 |
|
|
#define NEXTLONG(p) \ |
74 |
|
|
(p += 4, FETCH_DATA (info, p), \ |
75 |
|
|
(COERCE32 ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]))) |
76 |
|
|
|
77 |
|
|
/* Get a 4 byte unsigned integer. */ |
78 |
|
|
#define NEXTULONG(p) \ |
79 |
|
|
(p += 4, FETCH_DATA (info, p), \ |
80 |
|
|
(unsigned int) ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])) |
81 |
|
|
|
82 |
|
|
/* Get a single precision float. */ |
83 |
|
|
#define NEXTSINGLE(val, p) \ |
84 |
|
|
(p += 4, FETCH_DATA (info, p), \ |
85 |
|
|
floatformat_to_double (&floatformat_ieee_single_big, (char *) p - 4, &val)) |
86 |
|
|
|
87 |
|
|
/* Get a double precision float. */ |
88 |
|
|
#define NEXTDOUBLE(val, p) \ |
89 |
|
|
(p += 8, FETCH_DATA (info, p), \ |
90 |
|
|
floatformat_to_double (&floatformat_ieee_double_big, (char *) p - 8, &val)) |
91 |
|
|
|
92 |
|
|
/* Get an extended precision float. */ |
93 |
|
|
#define NEXTEXTEND(val, p) \ |
94 |
|
|
(p += 12, FETCH_DATA (info, p), \ |
95 |
|
|
floatformat_to_double (&floatformat_m68881_ext, (char *) p - 12, &val)) |
96 |
|
|
|
97 |
|
|
/* Need a function to convert from packed to double |
98 |
|
|
precision. Actually, it's easier to print a |
99 |
|
|
packed number than a double anyway, so maybe |
100 |
|
|
there should be a special case to handle this... */ |
101 |
|
|
#define NEXTPACKED(p) \ |
102 |
|
|
(p += 12, FETCH_DATA (info, p), 0.0) |
103 |
|
|
|
104 |
|
|
|
105 |
|
|
/* Maximum length of an instruction. */ |
106 |
|
|
#define MAXLEN 22 |
107 |
|
|
|
108 |
|
|
#include <setjmp.h> |
109 |
|
|
|
110 |
|
|
struct private |
111 |
|
|
{ |
112 |
|
|
/* Points to first byte not fetched. */ |
113 |
|
|
bfd_byte *max_fetched; |
114 |
|
|
bfd_byte the_buffer[MAXLEN]; |
115 |
|
|
bfd_vma insn_start; |
116 |
|
|
jmp_buf bailout; |
117 |
|
|
}; |
118 |
|
|
|
119 |
|
|
/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive) |
120 |
|
|
to ADDR (exclusive) are valid. Returns 1 for success, longjmps |
121 |
|
|
on error. */ |
122 |
|
|
#define FETCH_DATA(info, addr) \ |
123 |
|
|
((addr) <= ((struct private *)(info->private_data))->max_fetched \ |
124 |
|
|
? 1 : fetch_data ((info), (addr))) |
125 |
|
|
|
126 |
|
|
static int |
127 |
|
|
fetch_data (info, addr) |
128 |
|
|
struct disassemble_info *info; |
129 |
|
|
bfd_byte *addr; |
130 |
|
|
{ |
131 |
|
|
int status; |
132 |
|
|
struct private *priv = (struct private *)info->private_data; |
133 |
|
|
bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer); |
134 |
|
|
|
135 |
|
|
status = (*info->read_memory_func) (start, |
136 |
|
|
priv->max_fetched, |
137 |
|
|
addr - priv->max_fetched, |
138 |
|
|
info); |
139 |
|
|
if (status != 0) |
140 |
|
|
{ |
141 |
|
|
(*info->memory_error_func) (status, start, info); |
142 |
|
|
longjmp (priv->bailout, 1); |
143 |
|
|
} |
144 |
|
|
else |
145 |
|
|
priv->max_fetched = addr; |
146 |
|
|
return 1; |
147 |
|
|
} |
148 |
|
|
|
149 |
|
|
/* This function is used to print to the bit-bucket. */ |
150 |
|
|
static int |
151 |
|
|
#ifdef __STDC__ |
152 |
|
|
dummy_printer (FILE * file, const char * format, ...) |
153 |
|
|
#else |
154 |
|
|
dummy_printer (file) FILE *file; |
155 |
|
|
#endif |
156 |
|
|
{ return 0; } |
157 |
|
|
|
158 |
|
|
static void |
159 |
|
|
dummy_print_address (vma, info) |
160 |
|
|
bfd_vma vma; |
161 |
|
|
struct disassemble_info *info; |
162 |
|
|
{ |
163 |
|
|
} |
164 |
|
|
|
165 |
|
|
/* Print the m68k instruction at address MEMADDR in debugged memory, |
166 |
|
|
on INFO->STREAM. Returns length of the instruction, in bytes. */ |
167 |
|
|
|
168 |
|
|
int |
169 |
|
|
print_insn_m68k (memaddr, info) |
170 |
|
|
bfd_vma memaddr; |
171 |
|
|
disassemble_info *info; |
172 |
|
|
{ |
173 |
|
|
register int i; |
174 |
|
|
register unsigned char *p; |
175 |
|
|
unsigned char *save_p; |
176 |
|
|
register const char *d; |
177 |
|
|
register unsigned long bestmask; |
178 |
|
|
const struct m68k_opcode *best = 0; |
179 |
|
|
unsigned int arch_mask; |
180 |
|
|
struct private priv; |
181 |
|
|
bfd_byte *buffer = priv.the_buffer; |
182 |
|
|
fprintf_ftype save_printer = info->fprintf_func; |
183 |
|
|
void (*save_print_address) PARAMS((bfd_vma, struct disassemble_info*)) |
184 |
|
|
= info->print_address_func; |
185 |
|
|
int major_opcode; |
186 |
|
|
static int numopcodes[16]; |
187 |
|
|
static const struct m68k_opcode **opcodes[16]; |
188 |
|
|
|
189 |
|
|
if (!opcodes[0]) |
190 |
|
|
{ |
191 |
|
|
/* Speed up the matching by sorting the opcode table on the upper |
192 |
|
|
four bits of the opcode. */ |
193 |
|
|
const struct m68k_opcode **opc_pointer[16]; |
194 |
|
|
|
195 |
|
|
/* First count how many opcodes are in each of the sixteen buckets. */ |
196 |
|
|
for (i = 0; i < m68k_numopcodes; i++) |
197 |
|
|
numopcodes[(m68k_opcodes[i].opcode >> 28) & 15]++; |
198 |
|
|
|
199 |
|
|
/* Then create a sorted table of pointers that point into the |
200 |
|
|
unsorted table. */ |
201 |
|
|
opc_pointer[0] = ((const struct m68k_opcode **) |
202 |
cebix |
1.2 |
malloc (sizeof (struct m68k_opcode *) |
203 |
cebix |
1.1 |
* m68k_numopcodes)); |
204 |
|
|
opcodes[0] = opc_pointer[0]; |
205 |
|
|
for (i = 1; i < 16; i++) |
206 |
|
|
{ |
207 |
|
|
opc_pointer[i] = opc_pointer[i - 1] + numopcodes[i - 1]; |
208 |
|
|
opcodes[i] = opc_pointer[i]; |
209 |
|
|
} |
210 |
|
|
|
211 |
|
|
for (i = 0; i < m68k_numopcodes; i++) |
212 |
|
|
*opc_pointer[(m68k_opcodes[i].opcode >> 28) & 15]++ = &m68k_opcodes[i]; |
213 |
|
|
|
214 |
|
|
} |
215 |
|
|
|
216 |
|
|
info->private_data = (PTR) &priv; |
217 |
|
|
/* Tell objdump to use two bytes per chunk and six bytes per line for |
218 |
|
|
displaying raw data. */ |
219 |
|
|
info->bytes_per_chunk = 2; |
220 |
|
|
info->bytes_per_line = 6; |
221 |
|
|
info->display_endian = BFD_ENDIAN_BIG; |
222 |
|
|
priv.max_fetched = priv.the_buffer; |
223 |
|
|
priv.insn_start = memaddr; |
224 |
|
|
if (setjmp (priv.bailout) != 0) |
225 |
|
|
/* Error return. */ |
226 |
|
|
return -1; |
227 |
|
|
|
228 |
|
|
switch (info->mach) |
229 |
|
|
{ |
230 |
|
|
default: |
231 |
|
|
case 0: |
232 |
|
|
arch_mask = (unsigned int) -1; |
233 |
|
|
break; |
234 |
|
|
case bfd_mach_m68000: |
235 |
|
|
arch_mask = m68000; |
236 |
|
|
break; |
237 |
|
|
case bfd_mach_m68008: |
238 |
|
|
arch_mask = m68008; |
239 |
|
|
break; |
240 |
|
|
case bfd_mach_m68010: |
241 |
|
|
arch_mask = m68010; |
242 |
|
|
break; |
243 |
|
|
case bfd_mach_m68020: |
244 |
|
|
arch_mask = m68020; |
245 |
|
|
break; |
246 |
|
|
case bfd_mach_m68030: |
247 |
|
|
arch_mask = m68030; |
248 |
|
|
break; |
249 |
|
|
case bfd_mach_m68040: |
250 |
|
|
arch_mask = m68040; |
251 |
|
|
break; |
252 |
|
|
case bfd_mach_m68060: |
253 |
|
|
arch_mask = m68060; |
254 |
|
|
break; |
255 |
|
|
} |
256 |
|
|
|
257 |
|
|
arch_mask |= m68881 | m68851; |
258 |
|
|
|
259 |
|
|
bestmask = 0; |
260 |
|
|
FETCH_DATA (info, buffer + 2); |
261 |
|
|
major_opcode = (buffer[0] >> 4) & 15; |
262 |
|
|
for (i = 0; i < numopcodes[major_opcode]; i++) |
263 |
|
|
{ |
264 |
|
|
const struct m68k_opcode *opc = opcodes[major_opcode][i]; |
265 |
|
|
unsigned long opcode = opc->opcode; |
266 |
|
|
unsigned long match = opc->match; |
267 |
|
|
|
268 |
|
|
if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24))) |
269 |
|
|
&& ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16))) |
270 |
|
|
/* Only fetch the next two bytes if we need to. */ |
271 |
|
|
&& (((0xffff & match) == 0) |
272 |
|
|
|| |
273 |
|
|
(FETCH_DATA (info, buffer + 4) |
274 |
|
|
&& ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8))) |
275 |
|
|
&& ((0xff & buffer[3] & match) == (0xff & opcode))) |
276 |
|
|
) |
277 |
|
|
&& (opc->arch & arch_mask) != 0) |
278 |
|
|
{ |
279 |
|
|
/* Don't use for printout the variants of divul and divsl |
280 |
|
|
that have the same register number in two places. |
281 |
|
|
The more general variants will match instead. */ |
282 |
|
|
for (d = opc->args; *d; d += 2) |
283 |
|
|
if (d[1] == 'D') |
284 |
|
|
break; |
285 |
|
|
|
286 |
|
|
/* Don't use for printout the variants of most floating |
287 |
|
|
point coprocessor instructions which use the same |
288 |
|
|
register number in two places, as above. */ |
289 |
|
|
if (*d == '\0') |
290 |
|
|
for (d = opc->args; *d; d += 2) |
291 |
|
|
if (d[1] == 't') |
292 |
|
|
break; |
293 |
|
|
|
294 |
|
|
/* Don't match fmovel with more than one register; wait for |
295 |
|
|
fmoveml. */ |
296 |
|
|
if (*d == '\0') |
297 |
|
|
{ |
298 |
|
|
for (d = opc->args; *d; d += 2) |
299 |
|
|
{ |
300 |
|
|
if (d[0] == 's' && d[1] == '8') |
301 |
|
|
{ |
302 |
|
|
int val; |
303 |
|
|
|
304 |
|
|
val = fetch_arg (buffer, d[1], 3, info); |
305 |
|
|
if ((val & (val - 1)) != 0) |
306 |
|
|
break; |
307 |
|
|
} |
308 |
|
|
} |
309 |
|
|
} |
310 |
|
|
|
311 |
|
|
if (*d == '\0' && match > bestmask) |
312 |
|
|
{ |
313 |
|
|
best = opc; |
314 |
|
|
bestmask = match; |
315 |
|
|
} |
316 |
|
|
} |
317 |
|
|
} |
318 |
|
|
|
319 |
|
|
if (best == 0) |
320 |
|
|
goto invalid; |
321 |
|
|
|
322 |
|
|
/* Point at first word of argument data, |
323 |
|
|
and at descriptor for first argument. */ |
324 |
|
|
p = buffer + 2; |
325 |
|
|
|
326 |
|
|
/* Figure out how long the fixed-size portion of the instruction is. |
327 |
|
|
The only place this is stored in the opcode table is |
328 |
|
|
in the arguments--look for arguments which specify fields in the 2nd |
329 |
|
|
or 3rd words of the instruction. */ |
330 |
|
|
for (d = best->args; *d; d += 2) |
331 |
|
|
{ |
332 |
|
|
/* I don't think it is necessary to be checking d[0] here; I suspect |
333 |
|
|
all this could be moved to the case statement below. */ |
334 |
|
|
if (d[0] == '#') |
335 |
|
|
{ |
336 |
|
|
if (d[1] == 'l' && p - buffer < 6) |
337 |
|
|
p = buffer + 6; |
338 |
|
|
else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8' ) |
339 |
|
|
p = buffer + 4; |
340 |
|
|
} |
341 |
|
|
if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4) |
342 |
|
|
p = buffer + 4; |
343 |
|
|
switch (d[1]) |
344 |
|
|
{ |
345 |
|
|
case '1': |
346 |
|
|
case '2': |
347 |
|
|
case '3': |
348 |
|
|
case '7': |
349 |
|
|
case '8': |
350 |
|
|
case '9': |
351 |
|
|
case 'i': |
352 |
|
|
if (p - buffer < 4) |
353 |
|
|
p = buffer + 4; |
354 |
|
|
break; |
355 |
|
|
case '4': |
356 |
|
|
case '5': |
357 |
|
|
case '6': |
358 |
|
|
if (p - buffer < 6) |
359 |
|
|
p = buffer + 6; |
360 |
|
|
break; |
361 |
|
|
default: |
362 |
|
|
break; |
363 |
|
|
} |
364 |
|
|
} |
365 |
|
|
|
366 |
|
|
/* pflusha is an exceptions. It takes no arguments but is two words |
367 |
|
|
long. Recognize it by looking at the lower 16 bits of the mask. */ |
368 |
|
|
if (p - buffer < 4 && (best->match & 0xFFFF) != 0) |
369 |
|
|
p = buffer + 4; |
370 |
|
|
|
371 |
|
|
/* lpstop is another exception. It takes a one word argument but is |
372 |
|
|
three words long. */ |
373 |
|
|
if (p - buffer < 6 |
374 |
|
|
&& (best->match & 0xffff) == 0xffff |
375 |
|
|
&& best->args[0] == '#' |
376 |
|
|
&& best->args[1] == 'w') |
377 |
|
|
{ |
378 |
|
|
/* Copy the one word argument into the usual location for a one |
379 |
|
|
word argument, to simplify printing it. We can get away with |
380 |
|
|
this because we know exactly what the second word is, and we |
381 |
|
|
aren't going to print anything based on it. */ |
382 |
|
|
p = buffer + 6; |
383 |
|
|
FETCH_DATA (info, p); |
384 |
|
|
buffer[2] = buffer[4]; |
385 |
|
|
buffer[3] = buffer[5]; |
386 |
|
|
} |
387 |
|
|
|
388 |
|
|
FETCH_DATA (info, p); |
389 |
|
|
|
390 |
|
|
d = best->args; |
391 |
|
|
|
392 |
|
|
/* We can the operands twice. The first time we don't print anything, |
393 |
|
|
but look for errors. */ |
394 |
|
|
|
395 |
|
|
save_p = p; |
396 |
|
|
info->print_address_func = dummy_print_address; |
397 |
|
|
info->fprintf_func = (fprintf_ftype)dummy_printer; |
398 |
|
|
for ( ; *d; d += 2) |
399 |
|
|
{ |
400 |
|
|
int eaten = print_insn_arg (d, buffer, p, memaddr + (p - buffer), info); |
401 |
|
|
if (eaten >= 0) |
402 |
|
|
p += eaten; |
403 |
|
|
else if (eaten == -1) |
404 |
|
|
goto invalid; |
405 |
|
|
else |
406 |
|
|
{ |
407 |
|
|
(*info->fprintf_func)(info->stream, |
408 |
|
|
/* xgettext:c-format */ |
409 |
|
|
_("<internal error in opcode table: %s %s>\n"), |
410 |
|
|
best->name, |
411 |
|
|
best->args); |
412 |
|
|
goto invalid; |
413 |
|
|
} |
414 |
|
|
|
415 |
|
|
} |
416 |
|
|
p = save_p; |
417 |
|
|
info->fprintf_func = save_printer; |
418 |
|
|
info->print_address_func = save_print_address; |
419 |
|
|
|
420 |
|
|
d = best->args; |
421 |
|
|
|
422 |
|
|
(*info->fprintf_func) (info->stream, "%s", best->name); |
423 |
|
|
|
424 |
|
|
if (*d) |
425 |
|
|
(*info->fprintf_func) (info->stream, "\t"); |
426 |
|
|
|
427 |
|
|
while (*d) |
428 |
|
|
{ |
429 |
|
|
p += print_insn_arg (d, buffer, p, memaddr + (p - buffer), info); |
430 |
|
|
d += 2; |
431 |
|
|
if (*d && *(d - 2) != 'I' && *d != 'k') |
432 |
|
|
(*info->fprintf_func) (info->stream, ","); |
433 |
|
|
} |
434 |
|
|
return p - buffer; |
435 |
|
|
|
436 |
|
|
invalid: { |
437 |
cebix |
1.2 |
extern void print_68k_invalid_opcode(unsigned long, struct disassemble_info *); |
438 |
cebix |
1.1 |
|
439 |
|
|
/* Handle undefined instructions. */ |
440 |
|
|
info->fprintf_func = save_printer; |
441 |
|
|
info->print_address_func = save_print_address; |
442 |
cebix |
1.2 |
print_68k_invalid_opcode((buffer[0] << 8) | buffer[1], info); |
443 |
cebix |
1.1 |
return 2; |
444 |
|
|
} |
445 |
|
|
} |
446 |
|
|
|
447 |
|
|
/* Returns number of bytes "eaten" by the operand, or |
448 |
|
|
return -1 if an invalid operand was found, or -2 if |
449 |
|
|
an opcode tabe error was found. */ |
450 |
|
|
|
451 |
|
|
static int |
452 |
|
|
print_insn_arg (d, buffer, p0, addr, info) |
453 |
|
|
const char *d; |
454 |
|
|
unsigned char *buffer; |
455 |
|
|
unsigned char *p0; |
456 |
|
|
bfd_vma addr; /* PC for this arg to be relative to */ |
457 |
|
|
disassemble_info *info; |
458 |
|
|
{ |
459 |
|
|
register int val = 0; |
460 |
|
|
register int place = d[1]; |
461 |
|
|
register unsigned char *p = p0; |
462 |
|
|
int regno; |
463 |
|
|
register CONST char *regname; |
464 |
|
|
register unsigned char *p1; |
465 |
|
|
double flval; |
466 |
|
|
int flt_p; |
467 |
|
|
bfd_signed_vma disp; |
468 |
|
|
unsigned int uval; |
469 |
|
|
|
470 |
|
|
switch (*d) |
471 |
|
|
{ |
472 |
|
|
case 'c': /* cache identifier */ |
473 |
|
|
{ |
474 |
|
|
static char *const cacheFieldName[] = { "nc", "dc", "ic", "bc" }; |
475 |
|
|
val = fetch_arg (buffer, place, 2, info); |
476 |
|
|
(*info->fprintf_func) (info->stream, cacheFieldName[val]); |
477 |
|
|
break; |
478 |
|
|
} |
479 |
|
|
|
480 |
|
|
case 'a': /* address register indirect only. Cf. case '+'. */ |
481 |
|
|
{ |
482 |
|
|
(*info->fprintf_func) |
483 |
|
|
(info->stream, |
484 |
|
|
"(%s)", |
485 |
|
|
reg_names [fetch_arg (buffer, place, 3, info) + 8]); |
486 |
|
|
break; |
487 |
|
|
} |
488 |
|
|
|
489 |
|
|
case '_': /* 32-bit absolute address for move16. */ |
490 |
|
|
{ |
491 |
|
|
uval = NEXTULONG (p); |
492 |
|
|
(*info->print_address_func) (uval, info); |
493 |
|
|
break; |
494 |
|
|
} |
495 |
|
|
|
496 |
|
|
case 'C': |
497 |
|
|
(*info->fprintf_func) (info->stream, "ccr"); |
498 |
|
|
break; |
499 |
|
|
|
500 |
|
|
case 'S': |
501 |
|
|
(*info->fprintf_func) (info->stream, "sr"); |
502 |
|
|
break; |
503 |
|
|
|
504 |
|
|
case 'U': |
505 |
|
|
(*info->fprintf_func) (info->stream, "usp"); |
506 |
|
|
break; |
507 |
|
|
|
508 |
|
|
case 'J': |
509 |
|
|
{ |
510 |
|
|
static const struct { char *name; int value; } names[] |
511 |
|
|
= {{"sfc", 0x000}, {"dfc", 0x001}, {"cacr", 0x002}, |
512 |
|
|
{"tc", 0x003}, {"itt0",0x004}, {"itt1", 0x005}, |
513 |
|
|
{"dtt0",0x006}, {"dtt1",0x007}, {"buscr",0x008}, |
514 |
|
|
{"usp", 0x800}, {"vbr", 0x801}, {"caar", 0x802}, |
515 |
|
|
{"msp", 0x803}, {"isp", 0x804}, |
516 |
|
|
|
517 |
|
|
/* Should we be calling this psr like we do in case 'Y'? */ |
518 |
|
|
{"mmusr",0x805}, |
519 |
|
|
|
520 |
|
|
{"urp", 0x806}, {"srp", 0x807}, {"pcr", 0x808}}; |
521 |
|
|
|
522 |
|
|
val = fetch_arg (buffer, place, 12, info); |
523 |
|
|
for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--) |
524 |
|
|
if (names[regno].value == val) |
525 |
|
|
{ |
526 |
|
|
(*info->fprintf_func) (info->stream, "%s", names[regno].name); |
527 |
|
|
break; |
528 |
|
|
} |
529 |
|
|
if (regno < 0) |
530 |
|
|
(*info->fprintf_func) (info->stream, "$%04x", val); |
531 |
|
|
} |
532 |
|
|
break; |
533 |
|
|
|
534 |
|
|
case 'Q': |
535 |
|
|
val = fetch_arg (buffer, place, 3, info); |
536 |
|
|
/* 0 means 8, except for the bkpt instruction... */ |
537 |
|
|
if (val == 0 && d[1] != 's') |
538 |
|
|
val = 8; |
539 |
|
|
(*info->fprintf_func) (info->stream, "#%d", val); |
540 |
|
|
break; |
541 |
|
|
|
542 |
|
|
case 'M': |
543 |
|
|
val = fetch_arg (buffer, place, 8, info); |
544 |
|
|
if (val & 0x80) |
545 |
|
|
val = val - 0x100; |
546 |
|
|
(*info->fprintf_func) (info->stream, "#$%02x", val); |
547 |
|
|
break; |
548 |
|
|
|
549 |
|
|
case 'T': |
550 |
|
|
val = fetch_arg (buffer, place, 4, info); |
551 |
|
|
(*info->fprintf_func) (info->stream, "#$%08x", val); |
552 |
|
|
break; |
553 |
|
|
|
554 |
|
|
case 'D': |
555 |
|
|
(*info->fprintf_func) (info->stream, "%s", |
556 |
|
|
reg_names[fetch_arg (buffer, place, 3, info)]); |
557 |
|
|
break; |
558 |
|
|
|
559 |
|
|
case 'A': |
560 |
|
|
(*info->fprintf_func) |
561 |
|
|
(info->stream, "%s", |
562 |
|
|
reg_names[fetch_arg (buffer, place, 3, info) + 010]); |
563 |
|
|
break; |
564 |
|
|
|
565 |
|
|
case 'R': |
566 |
|
|
(*info->fprintf_func) |
567 |
|
|
(info->stream, "%s", |
568 |
|
|
reg_names[fetch_arg (buffer, place, 4, info)]); |
569 |
|
|
break; |
570 |
|
|
|
571 |
|
|
case 'r': |
572 |
|
|
regno = fetch_arg (buffer, place, 4, info); |
573 |
|
|
(*info->fprintf_func) (info->stream, "(%s)", reg_names[regno]); |
574 |
|
|
break; |
575 |
|
|
|
576 |
|
|
case 'F': |
577 |
|
|
(*info->fprintf_func) |
578 |
|
|
(info->stream, "fp%d", |
579 |
|
|
fetch_arg (buffer, place, 3, info)); |
580 |
|
|
break; |
581 |
|
|
|
582 |
|
|
case 'O': |
583 |
|
|
val = fetch_arg (buffer, place, 6, info); |
584 |
|
|
if (val & 0x20) |
585 |
|
|
(*info->fprintf_func) (info->stream, "%s", reg_names [val & 7]); |
586 |
|
|
else |
587 |
|
|
(*info->fprintf_func) (info->stream, "%d", val); |
588 |
|
|
break; |
589 |
|
|
|
590 |
|
|
case '+': |
591 |
|
|
(*info->fprintf_func) |
592 |
|
|
(info->stream, "(%s)+", |
593 |
|
|
reg_names[fetch_arg (buffer, place, 3, info) + 8]); |
594 |
|
|
break; |
595 |
|
|
|
596 |
|
|
case '-': |
597 |
|
|
(*info->fprintf_func) |
598 |
|
|
(info->stream, "-(%s)", |
599 |
|
|
reg_names[fetch_arg (buffer, place, 3, info) + 8]); |
600 |
|
|
break; |
601 |
|
|
|
602 |
|
|
case 'k': |
603 |
|
|
if (place == 'k') |
604 |
|
|
(*info->fprintf_func) |
605 |
|
|
(info->stream, "{%s}", |
606 |
|
|
reg_names[fetch_arg (buffer, place, 3, info)]); |
607 |
|
|
else if (place == 'C') |
608 |
|
|
{ |
609 |
|
|
val = fetch_arg (buffer, place, 7, info); |
610 |
|
|
if ( val > 63 ) /* This is a signed constant. */ |
611 |
|
|
val -= 128; |
612 |
|
|
(*info->fprintf_func) (info->stream, "{#%d}", val); |
613 |
|
|
} |
614 |
|
|
else |
615 |
|
|
return -2; |
616 |
|
|
break; |
617 |
|
|
|
618 |
|
|
case '#': |
619 |
|
|
case '^': |
620 |
|
|
p1 = buffer + (*d == '#' ? 2 : 4); |
621 |
|
|
if (place == 's') |
622 |
|
|
val = fetch_arg (buffer, place, 4, info); |
623 |
|
|
else if (place == 'C') |
624 |
|
|
val = fetch_arg (buffer, place, 7, info); |
625 |
|
|
else if (place == '8') |
626 |
|
|
val = fetch_arg (buffer, place, 3, info); |
627 |
|
|
else if (place == '3') |
628 |
|
|
val = fetch_arg (buffer, place, 8, info); |
629 |
|
|
else if (place == 'b') { |
630 |
|
|
val = NEXTBYTE (p1); |
631 |
|
|
(*info->fprintf_func) (info->stream, "#$%02x", val & 0xff); |
632 |
|
|
break; |
633 |
|
|
} |
634 |
|
|
else if (place == 'w' || place == 'W') { |
635 |
|
|
val = NEXTWORD (p1); |
636 |
|
|
(*info->fprintf_func) (info->stream, "#$%04x", val & 0xffff); |
637 |
|
|
break; |
638 |
|
|
} |
639 |
|
|
else if (place == 'l') { |
640 |
|
|
val = NEXTLONG (p1); |
641 |
|
|
(*info->fprintf_func) (info->stream, "#$%08x", val); |
642 |
|
|
break; |
643 |
|
|
} |
644 |
|
|
else |
645 |
|
|
return -2; |
646 |
|
|
(*info->fprintf_func) (info->stream, "#%d", val); |
647 |
|
|
break; |
648 |
|
|
|
649 |
|
|
case 'B': |
650 |
|
|
if (place == 'b') |
651 |
|
|
disp = NEXTBYTE (p); |
652 |
|
|
else if (place == 'B') |
653 |
|
|
disp = COERCE_SIGNED_CHAR(buffer[1]); |
654 |
|
|
else if (place == 'w' || place == 'W') |
655 |
|
|
disp = NEXTWORD (p); |
656 |
|
|
else if (place == 'l' || place == 'L' || place == 'C') |
657 |
|
|
disp = NEXTLONG (p); |
658 |
|
|
else if (place == 'g') |
659 |
|
|
{ |
660 |
|
|
disp = NEXTBYTE (buffer); |
661 |
|
|
if (disp == 0) |
662 |
|
|
disp = NEXTWORD (p); |
663 |
|
|
else if (disp == -1) |
664 |
|
|
disp = NEXTLONG (p); |
665 |
|
|
} |
666 |
|
|
else if (place == 'c') |
667 |
|
|
{ |
668 |
|
|
if (buffer[1] & 0x40) /* If bit six is one, long offset */ |
669 |
|
|
disp = NEXTLONG (p); |
670 |
|
|
else |
671 |
|
|
disp = NEXTWORD (p); |
672 |
|
|
} |
673 |
|
|
else |
674 |
|
|
return -2; |
675 |
|
|
|
676 |
cebix |
1.2 |
#if 1 |
677 |
|
|
(*info->fprintf_func) (info->stream, "$%08x", addr + disp); |
678 |
|
|
#else |
679 |
cebix |
1.1 |
(*info->print_address_func) (addr + disp, info); |
680 |
cebix |
1.2 |
#endif |
681 |
cebix |
1.1 |
break; |
682 |
|
|
|
683 |
|
|
case 'd': |
684 |
|
|
val = NEXTWORD (p); |
685 |
|
|
(*info->fprintf_func) |
686 |
|
|
(info->stream, "($%04x,%s)", |
687 |
|
|
val, reg_names[fetch_arg (buffer, place, 3, info) + 8]); |
688 |
|
|
break; |
689 |
|
|
|
690 |
|
|
case 's': |
691 |
|
|
(*info->fprintf_func) (info->stream, "%s", |
692 |
|
|
fpcr_names[fetch_arg (buffer, place, 3, info)]); |
693 |
|
|
break; |
694 |
|
|
|
695 |
|
|
case 'I': |
696 |
|
|
/* Get coprocessor ID... */ |
697 |
|
|
val = fetch_arg (buffer, 'd', 3, info); |
698 |
|
|
|
699 |
|
|
if (val != 1) /* Unusual coprocessor ID? */ |
700 |
|
|
(*info->fprintf_func) (info->stream, "(cpid=%d) ", val); |
701 |
|
|
break; |
702 |
|
|
|
703 |
|
|
case '*': |
704 |
|
|
case '~': |
705 |
|
|
case '%': |
706 |
|
|
case ';': |
707 |
|
|
case '@': |
708 |
|
|
case '!': |
709 |
|
|
case '$': |
710 |
|
|
case '?': |
711 |
|
|
case '/': |
712 |
|
|
case '&': |
713 |
|
|
case '|': |
714 |
|
|
case '<': |
715 |
|
|
case '>': |
716 |
|
|
case 'm': |
717 |
|
|
case 'n': |
718 |
|
|
case 'o': |
719 |
|
|
case 'p': |
720 |
|
|
case 'q': |
721 |
|
|
case 'v': |
722 |
|
|
|
723 |
|
|
if (place == 'd') |
724 |
|
|
{ |
725 |
|
|
val = fetch_arg (buffer, 'x', 6, info); |
726 |
|
|
val = ((val & 7) << 3) + ((val >> 3) & 7); |
727 |
|
|
} |
728 |
|
|
else |
729 |
|
|
val = fetch_arg (buffer, 's', 6, info); |
730 |
|
|
|
731 |
|
|
/* Get register number assuming address register. */ |
732 |
|
|
regno = (val & 7) + 8; |
733 |
|
|
regname = reg_names[regno]; |
734 |
|
|
switch (val >> 3) |
735 |
|
|
{ |
736 |
|
|
case 0: |
737 |
|
|
(*info->fprintf_func) (info->stream, "%s", reg_names[val]); |
738 |
|
|
break; |
739 |
|
|
|
740 |
|
|
case 1: |
741 |
|
|
(*info->fprintf_func) (info->stream, "%s", regname); |
742 |
|
|
break; |
743 |
|
|
|
744 |
|
|
case 2: |
745 |
|
|
(*info->fprintf_func) (info->stream, "(%s)", regname); |
746 |
|
|
break; |
747 |
|
|
|
748 |
|
|
case 3: |
749 |
|
|
(*info->fprintf_func) (info->stream, "(%s)+", regname); |
750 |
|
|
break; |
751 |
|
|
|
752 |
|
|
case 4: |
753 |
|
|
(*info->fprintf_func) (info->stream, "-(%s)", regname); |
754 |
|
|
break; |
755 |
|
|
|
756 |
|
|
case 5: |
757 |
|
|
val = NEXTWORD (p); |
758 |
|
|
(*info->fprintf_func) (info->stream, "($%04x,%s)", val, regname); |
759 |
|
|
break; |
760 |
|
|
|
761 |
|
|
case 6: |
762 |
|
|
p = print_indexed (regno, p, addr, info); |
763 |
|
|
break; |
764 |
|
|
|
765 |
|
|
case 7: |
766 |
|
|
switch (val & 7) |
767 |
|
|
{ |
768 |
|
|
case 0: |
769 |
|
|
val = NEXTWORD (p); |
770 |
|
|
(*info->print_address_func) (val, info); |
771 |
|
|
break; |
772 |
|
|
|
773 |
|
|
case 1: |
774 |
|
|
uval = NEXTULONG (p); |
775 |
|
|
(*info->print_address_func) (uval, info); |
776 |
|
|
break; |
777 |
|
|
|
778 |
|
|
case 2: |
779 |
|
|
val = NEXTWORD (p); |
780 |
cebix |
1.2 |
(*info->fprintf_func) (info->stream, "($%08x,pc)", addr + val); |
781 |
cebix |
1.1 |
break; |
782 |
|
|
|
783 |
|
|
case 3: |
784 |
|
|
p = print_indexed (-1, p, addr, info); |
785 |
|
|
break; |
786 |
|
|
|
787 |
|
|
case 4: |
788 |
|
|
switch( place ) |
789 |
|
|
{ |
790 |
|
|
case 'b': |
791 |
|
|
val = NEXTBYTE (p); |
792 |
|
|
(*info->fprintf_func) (info->stream, "#$%02x", val & 0xff); |
793 |
|
|
goto imm_printed; |
794 |
|
|
|
795 |
|
|
case 'w': |
796 |
|
|
val = NEXTWORD (p); |
797 |
|
|
(*info->fprintf_func) (info->stream, "#$%04x", val & 0xffff); |
798 |
|
|
goto imm_printed; |
799 |
|
|
|
800 |
|
|
case 'l': |
801 |
|
|
val = NEXTLONG (p); |
802 |
|
|
(*info->fprintf_func) (info->stream, "#$%08x", val); |
803 |
|
|
goto imm_printed; |
804 |
|
|
|
805 |
|
|
case 'f': |
806 |
|
|
NEXTSINGLE(flval, p); |
807 |
|
|
break; |
808 |
|
|
|
809 |
|
|
case 'F': |
810 |
|
|
NEXTDOUBLE(flval, p); |
811 |
|
|
break; |
812 |
|
|
|
813 |
|
|
case 'x': |
814 |
|
|
NEXTEXTEND(flval, p); |
815 |
|
|
break; |
816 |
|
|
|
817 |
|
|
case 'p': |
818 |
|
|
flval = NEXTPACKED(p); |
819 |
|
|
break; |
820 |
|
|
|
821 |
|
|
default: |
822 |
|
|
return -1; |
823 |
|
|
} |
824 |
|
|
(*info->fprintf_func) (info->stream, "#%g", flval); |
825 |
|
|
imm_printed: |
826 |
|
|
break; |
827 |
|
|
|
828 |
|
|
default: |
829 |
|
|
return -1; |
830 |
|
|
} |
831 |
|
|
} |
832 |
|
|
break; |
833 |
|
|
|
834 |
|
|
case 'L': |
835 |
|
|
case 'l': |
836 |
|
|
if (place == 'w') |
837 |
|
|
{ |
838 |
|
|
char doneany; |
839 |
|
|
p1 = buffer + 2; |
840 |
|
|
val = NEXTWORD (p1); |
841 |
|
|
/* Move the pointer ahead if this point is farther ahead |
842 |
|
|
than the last. */ |
843 |
|
|
p = p1 > p ? p1 : p; |
844 |
|
|
if (val == 0) |
845 |
|
|
{ |
846 |
|
|
(*info->fprintf_func) (info->stream, "#0"); |
847 |
|
|
break; |
848 |
|
|
} |
849 |
|
|
if (*d == 'l') |
850 |
|
|
{ |
851 |
|
|
register int newval = 0; |
852 |
|
|
for (regno = 0; regno < 16; ++regno) |
853 |
|
|
if (val & (0x8000 >> regno)) |
854 |
|
|
newval |= 1 << regno; |
855 |
|
|
val = newval; |
856 |
|
|
} |
857 |
|
|
val &= 0xffff; |
858 |
|
|
doneany = 0; |
859 |
|
|
for (regno = 0; regno < 16; ++regno) |
860 |
|
|
if (val & (1 << regno)) |
861 |
|
|
{ |
862 |
|
|
int first_regno; |
863 |
|
|
if (doneany) |
864 |
|
|
(*info->fprintf_func) (info->stream, "/"); |
865 |
|
|
doneany = 1; |
866 |
|
|
(*info->fprintf_func) (info->stream, "%s", reg_names[regno]); |
867 |
|
|
first_regno = regno; |
868 |
|
|
while (val & (1 << (regno + 1))) |
869 |
|
|
++regno; |
870 |
|
|
if (regno > first_regno) |
871 |
|
|
(*info->fprintf_func) (info->stream, "-%s", |
872 |
|
|
reg_names[regno]); |
873 |
|
|
} |
874 |
|
|
} |
875 |
|
|
else if (place == '3') |
876 |
|
|
{ |
877 |
|
|
/* `fmovem' insn. */ |
878 |
|
|
char doneany; |
879 |
|
|
val = fetch_arg (buffer, place, 8, info); |
880 |
|
|
if (val == 0) |
881 |
|
|
{ |
882 |
|
|
(*info->fprintf_func) (info->stream, "#0"); |
883 |
|
|
break; |
884 |
|
|
} |
885 |
|
|
if (*d == 'l') |
886 |
|
|
{ |
887 |
|
|
register int newval = 0; |
888 |
|
|
for (regno = 0; regno < 8; ++regno) |
889 |
|
|
if (val & (0x80 >> regno)) |
890 |
|
|
newval |= 1 << regno; |
891 |
|
|
val = newval; |
892 |
|
|
} |
893 |
|
|
val &= 0xff; |
894 |
|
|
doneany = 0; |
895 |
|
|
for (regno = 0; regno < 8; ++regno) |
896 |
|
|
if (val & (1 << regno)) |
897 |
|
|
{ |
898 |
|
|
int first_regno; |
899 |
|
|
if (doneany) |
900 |
|
|
(*info->fprintf_func) (info->stream, "/"); |
901 |
|
|
doneany = 1; |
902 |
|
|
(*info->fprintf_func) (info->stream, "fp%d", regno); |
903 |
|
|
first_regno = regno; |
904 |
|
|
while (val & (1 << (regno + 1))) |
905 |
|
|
++regno; |
906 |
|
|
if (regno > first_regno) |
907 |
|
|
(*info->fprintf_func) (info->stream, "-fp%d", regno); |
908 |
|
|
} |
909 |
|
|
} |
910 |
|
|
else if (place == '8') |
911 |
|
|
{ |
912 |
|
|
/* fmoveml for FP status registers */ |
913 |
|
|
(*info->fprintf_func) (info->stream, "%s", |
914 |
|
|
fpcr_names[fetch_arg (buffer, place, 3, |
915 |
|
|
info)]); |
916 |
|
|
} |
917 |
|
|
else |
918 |
|
|
return -2; |
919 |
|
|
break; |
920 |
|
|
|
921 |
|
|
case 'X': |
922 |
|
|
place = '8'; |
923 |
|
|
case 'Y': |
924 |
|
|
case 'Z': |
925 |
|
|
case 'W': |
926 |
|
|
case '0': |
927 |
|
|
case '1': |
928 |
|
|
case '2': |
929 |
|
|
case '3': |
930 |
|
|
{ |
931 |
|
|
int val = fetch_arg (buffer, place, 5, info); |
932 |
|
|
char *name = 0; |
933 |
|
|
switch (val) |
934 |
|
|
{ |
935 |
|
|
case 2: name = "tt0"; break; |
936 |
|
|
case 3: name = "tt1"; break; |
937 |
|
|
case 0x10: name = "tc"; break; |
938 |
|
|
case 0x11: name = "drp"; break; |
939 |
|
|
case 0x12: name = "srp"; break; |
940 |
|
|
case 0x13: name = "crp"; break; |
941 |
|
|
case 0x14: name = "cal"; break; |
942 |
|
|
case 0x15: name = "val"; break; |
943 |
|
|
case 0x16: name = "scc"; break; |
944 |
|
|
case 0x17: name = "ac"; break; |
945 |
|
|
case 0x18: name = "psr"; break; |
946 |
|
|
case 0x19: name = "pcsr"; break; |
947 |
|
|
case 0x1c: |
948 |
|
|
case 0x1d: |
949 |
|
|
{ |
950 |
|
|
int break_reg = ((buffer[3] >> 2) & 7); |
951 |
|
|
(*info->fprintf_func) |
952 |
|
|
(info->stream, val == 0x1c ? "bad%d" : "bac%d", |
953 |
|
|
break_reg); |
954 |
|
|
} |
955 |
|
|
break; |
956 |
|
|
default: |
957 |
|
|
(*info->fprintf_func) (info->stream, "<mmu register %d>", val); |
958 |
|
|
} |
959 |
|
|
if (name) |
960 |
|
|
(*info->fprintf_func) (info->stream, "%s", name); |
961 |
|
|
} |
962 |
|
|
break; |
963 |
|
|
|
964 |
|
|
case 'f': |
965 |
|
|
{ |
966 |
|
|
int fc = fetch_arg (buffer, place, 5, info); |
967 |
|
|
if (fc == 1) |
968 |
|
|
(*info->fprintf_func) (info->stream, "dfc"); |
969 |
|
|
else if (fc == 0) |
970 |
|
|
(*info->fprintf_func) (info->stream, "sfc"); |
971 |
|
|
else |
972 |
|
|
/* xgettext:c-format */ |
973 |
|
|
(*info->fprintf_func) (info->stream, _("<function code %d>"), fc); |
974 |
|
|
} |
975 |
|
|
break; |
976 |
|
|
|
977 |
|
|
case 'V': |
978 |
|
|
(*info->fprintf_func) (info->stream, "val"); |
979 |
|
|
break; |
980 |
|
|
|
981 |
|
|
case 't': |
982 |
|
|
{ |
983 |
|
|
int level = fetch_arg (buffer, place, 3, info); |
984 |
|
|
(*info->fprintf_func) (info->stream, "%d", level); |
985 |
|
|
} |
986 |
|
|
break; |
987 |
|
|
|
988 |
|
|
default: |
989 |
|
|
return -2; |
990 |
|
|
} |
991 |
|
|
|
992 |
|
|
return p - p0; |
993 |
|
|
} |
994 |
|
|
|
995 |
|
|
/* Fetch BITS bits from a position in the instruction specified by CODE. |
996 |
|
|
CODE is a "place to put an argument", or 'x' for a destination |
997 |
|
|
that is a general address (mode and register). |
998 |
|
|
BUFFER contains the instruction. */ |
999 |
|
|
|
1000 |
|
|
static int |
1001 |
|
|
fetch_arg (buffer, code, bits, info) |
1002 |
|
|
unsigned char *buffer; |
1003 |
|
|
int code; |
1004 |
|
|
int bits; |
1005 |
|
|
disassemble_info *info; |
1006 |
|
|
{ |
1007 |
|
|
register int val = 0; |
1008 |
|
|
switch (code) |
1009 |
|
|
{ |
1010 |
|
|
case 's': |
1011 |
|
|
val = buffer[1]; |
1012 |
|
|
break; |
1013 |
|
|
|
1014 |
|
|
case 'd': /* Destination, for register or quick. */ |
1015 |
|
|
val = (buffer[0] << 8) + buffer[1]; |
1016 |
|
|
val >>= 9; |
1017 |
|
|
break; |
1018 |
|
|
|
1019 |
|
|
case 'x': /* Destination, for general arg */ |
1020 |
|
|
val = (buffer[0] << 8) + buffer[1]; |
1021 |
|
|
val >>= 6; |
1022 |
|
|
break; |
1023 |
|
|
|
1024 |
|
|
case 'k': |
1025 |
|
|
FETCH_DATA (info, buffer + 3); |
1026 |
|
|
val = (buffer[3] >> 4); |
1027 |
|
|
break; |
1028 |
|
|
|
1029 |
|
|
case 'C': |
1030 |
|
|
FETCH_DATA (info, buffer + 3); |
1031 |
|
|
val = buffer[3]; |
1032 |
|
|
break; |
1033 |
|
|
|
1034 |
|
|
case '1': |
1035 |
|
|
FETCH_DATA (info, buffer + 3); |
1036 |
|
|
val = (buffer[2] << 8) + buffer[3]; |
1037 |
|
|
val >>= 12; |
1038 |
|
|
break; |
1039 |
|
|
|
1040 |
|
|
case '2': |
1041 |
|
|
FETCH_DATA (info, buffer + 3); |
1042 |
|
|
val = (buffer[2] << 8) + buffer[3]; |
1043 |
|
|
val >>= 6; |
1044 |
|
|
break; |
1045 |
|
|
|
1046 |
|
|
case '3': |
1047 |
|
|
case 'j': |
1048 |
|
|
FETCH_DATA (info, buffer + 3); |
1049 |
|
|
val = (buffer[2] << 8) + buffer[3]; |
1050 |
|
|
break; |
1051 |
|
|
|
1052 |
|
|
case '4': |
1053 |
|
|
FETCH_DATA (info, buffer + 5); |
1054 |
|
|
val = (buffer[4] << 8) + buffer[5]; |
1055 |
|
|
val >>= 12; |
1056 |
|
|
break; |
1057 |
|
|
|
1058 |
|
|
case '5': |
1059 |
|
|
FETCH_DATA (info, buffer + 5); |
1060 |
|
|
val = (buffer[4] << 8) + buffer[5]; |
1061 |
|
|
val >>= 6; |
1062 |
|
|
break; |
1063 |
|
|
|
1064 |
|
|
case '6': |
1065 |
|
|
FETCH_DATA (info, buffer + 5); |
1066 |
|
|
val = (buffer[4] << 8) + buffer[5]; |
1067 |
|
|
break; |
1068 |
|
|
|
1069 |
|
|
case '7': |
1070 |
|
|
FETCH_DATA (info, buffer + 3); |
1071 |
|
|
val = (buffer[2] << 8) + buffer[3]; |
1072 |
|
|
val >>= 7; |
1073 |
|
|
break; |
1074 |
|
|
|
1075 |
|
|
case '8': |
1076 |
|
|
FETCH_DATA (info, buffer + 3); |
1077 |
|
|
val = (buffer[2] << 8) + buffer[3]; |
1078 |
|
|
val >>= 10; |
1079 |
|
|
break; |
1080 |
|
|
|
1081 |
|
|
case '9': |
1082 |
|
|
FETCH_DATA (info, buffer + 3); |
1083 |
|
|
val = (buffer[2] << 8) + buffer[3]; |
1084 |
|
|
val >>= 5; |
1085 |
|
|
break; |
1086 |
|
|
|
1087 |
|
|
case 'e': |
1088 |
|
|
val = (buffer[1] >> 6); |
1089 |
|
|
break; |
1090 |
|
|
|
1091 |
|
|
default: |
1092 |
|
|
abort (); |
1093 |
|
|
} |
1094 |
|
|
|
1095 |
|
|
switch (bits) |
1096 |
|
|
{ |
1097 |
|
|
case 2: |
1098 |
|
|
return val & 3; |
1099 |
|
|
case 3: |
1100 |
|
|
return val & 7; |
1101 |
|
|
case 4: |
1102 |
|
|
return val & 017; |
1103 |
|
|
case 5: |
1104 |
|
|
return val & 037; |
1105 |
|
|
case 6: |
1106 |
|
|
return val & 077; |
1107 |
|
|
case 7: |
1108 |
|
|
return val & 0177; |
1109 |
|
|
case 8: |
1110 |
|
|
return val & 0377; |
1111 |
|
|
case 12: |
1112 |
|
|
return val & 07777; |
1113 |
|
|
default: |
1114 |
|
|
abort (); |
1115 |
|
|
} |
1116 |
|
|
} |
1117 |
|
|
|
1118 |
|
|
/* Print an indexed argument. The base register is BASEREG (-1 for pc). |
1119 |
|
|
P points to extension word, in buffer. |
1120 |
|
|
ADDR is the nominal core address of that extension word. */ |
1121 |
|
|
|
1122 |
|
|
static unsigned char * |
1123 |
|
|
print_indexed (basereg, p, addr, info) |
1124 |
|
|
int basereg; |
1125 |
|
|
unsigned char *p; |
1126 |
|
|
bfd_vma addr; |
1127 |
|
|
disassemble_info *info; |
1128 |
|
|
{ |
1129 |
|
|
register int word; |
1130 |
|
|
static char *const scales[] = {"", "*2", "*4", "*8"}; |
1131 |
|
|
bfd_vma base_disp; |
1132 |
|
|
bfd_vma outer_disp; |
1133 |
|
|
char buf[40]; |
1134 |
|
|
char vmabuf[50]; |
1135 |
|
|
|
1136 |
|
|
word = NEXTWORD (p); |
1137 |
|
|
|
1138 |
|
|
/* Generate the text for the index register. |
1139 |
|
|
Where this will be output is not yet determined. */ |
1140 |
|
|
sprintf (buf, "%s.%c%s", |
1141 |
|
|
reg_names[(word >> 12) & 0xf], |
1142 |
|
|
(word & 0x800) ? 'l' : 'w', |
1143 |
|
|
scales[(word >> 9) & 3]); |
1144 |
|
|
|
1145 |
|
|
/* Handle the 68000 style of indexing. */ |
1146 |
|
|
|
1147 |
|
|
if ((word & 0x100) == 0) |
1148 |
|
|
{ |
1149 |
|
|
base_disp = word & 0xff; |
1150 |
|
|
if ((base_disp & 0x80) != 0) |
1151 |
|
|
base_disp -= 0x100; |
1152 |
|
|
if (basereg == -1) |
1153 |
|
|
base_disp += addr; |
1154 |
|
|
(*info->fprintf_func) (info->stream, "(", buf); |
1155 |
|
|
print_base (basereg, base_disp, info); |
1156 |
|
|
(*info->fprintf_func) (info->stream, ",%s)", buf); |
1157 |
|
|
return p; |
1158 |
|
|
} |
1159 |
|
|
|
1160 |
|
|
/* Handle the generalized kind. */ |
1161 |
|
|
/* First, compute the displacement to add to the base register. */ |
1162 |
|
|
|
1163 |
|
|
if (word & 0200) |
1164 |
|
|
{ |
1165 |
|
|
if (basereg == -1) |
1166 |
|
|
basereg = -3; |
1167 |
|
|
else |
1168 |
|
|
basereg = -2; |
1169 |
|
|
} |
1170 |
|
|
if (word & 0100) |
1171 |
|
|
buf[0] = '\0'; |
1172 |
|
|
base_disp = 0; |
1173 |
|
|
switch ((word >> 4) & 3) |
1174 |
|
|
{ |
1175 |
|
|
case 2: |
1176 |
|
|
base_disp = NEXTWORD (p); |
1177 |
|
|
break; |
1178 |
|
|
case 3: |
1179 |
|
|
base_disp = NEXTLONG (p); |
1180 |
|
|
} |
1181 |
|
|
if (basereg == -1) |
1182 |
|
|
base_disp += addr; |
1183 |
|
|
|
1184 |
|
|
/* Handle single-level case (not indirect) */ |
1185 |
|
|
|
1186 |
|
|
if ((word & 7) == 0) |
1187 |
|
|
{ |
1188 |
|
|
(*info->fprintf_func) (info->stream, "("); |
1189 |
|
|
print_base (basereg, base_disp, info); |
1190 |
|
|
if (buf[0] != '\0') |
1191 |
|
|
(*info->fprintf_func) (info->stream, ",%s", buf); |
1192 |
|
|
(*info->fprintf_func) (info->stream, ")"); |
1193 |
|
|
return p; |
1194 |
|
|
} |
1195 |
|
|
|
1196 |
|
|
/* Two level. Compute displacement to add after indirection. */ |
1197 |
|
|
|
1198 |
|
|
outer_disp = 0; |
1199 |
|
|
switch (word & 3) |
1200 |
|
|
{ |
1201 |
|
|
case 2: |
1202 |
|
|
outer_disp = NEXTWORD (p); |
1203 |
|
|
break; |
1204 |
|
|
case 3: |
1205 |
|
|
outer_disp = NEXTLONG (p); |
1206 |
|
|
} |
1207 |
|
|
|
1208 |
|
|
(*info->fprintf_func) (info->stream, "(["); |
1209 |
|
|
print_base (basereg, base_disp, info); |
1210 |
|
|
if ((word & 4) == 0 && buf[0] != '\0') |
1211 |
|
|
{ |
1212 |
|
|
(*info->fprintf_func) (info->stream, ",%s", buf); |
1213 |
|
|
buf[0] = '\0'; |
1214 |
|
|
} |
1215 |
|
|
if (outer_disp) |
1216 |
|
|
(*info->fprintf_func) (info->stream, "],$%08x", outer_disp); |
1217 |
|
|
else |
1218 |
|
|
(*info->fprintf_func) (info->stream, "]", outer_disp); |
1219 |
|
|
if (buf[0] != '\0') |
1220 |
|
|
(*info->fprintf_func) (info->stream, ",%s", buf); |
1221 |
|
|
(*info->fprintf_func) (info->stream, ")"); |
1222 |
|
|
|
1223 |
|
|
return p; |
1224 |
|
|
} |
1225 |
|
|
|
1226 |
|
|
/* Print a base register REGNO and displacement DISP, on INFO->STREAM. |
1227 |
|
|
REGNO = -1 for pc, -2 for none (suppressed). */ |
1228 |
|
|
|
1229 |
|
|
static void |
1230 |
|
|
print_base (regno, disp, info) |
1231 |
|
|
int regno; |
1232 |
|
|
bfd_vma disp; |
1233 |
|
|
disassemble_info *info; |
1234 |
|
|
{ |
1235 |
cebix |
1.2 |
if (regno == -1) |
1236 |
|
|
(*info->fprintf_func) (info->stream, "$%08x,pc", disp); |
1237 |
|
|
else { |
1238 |
|
|
if (regno == -3) |
1239 |
|
|
(*info->fprintf_func) (info->stream, "$%08x,zpc", disp); |
1240 |
|
|
else if (regno == -2) |
1241 |
|
|
(*info->print_address_func) (disp, info); |
1242 |
|
|
else |
1243 |
|
|
(*info->fprintf_func) (info->stream, "$%08x,%s", disp, reg_names[regno]); |
1244 |
|
|
} |
1245 |
cebix |
1.1 |
} |