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