rebuild
[deliverable/binutils-gdb.git] / opcodes / i960c-dis.c
CommitLineData
10cb538e
JW
1/* Disassembler interface for targets using CGEN. -*- C -*-
2 CGEN: Cpu tools GENerator
3
4THIS FILE IS USED TO GENERATE i960c-dis.c.
5
c6d4ea9d 6Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
10cb538e
JW
7
8This file is part of the GNU Binutils and GDB, the GNU debugger.
9
10This program is free software; you can redistribute it and/or modify
11it under the terms of the GNU General Public License as published by
12the Free Software Foundation; either version 2, or (at your option)
13any later version.
14
15This program is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software Foundation, Inc.,
2259 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
23
24#include "sysdep.h"
25#include <stdio.h>
26#include "ansidecl.h"
27#include "dis-asm.h"
28#include "bfd.h"
29#include "symcat.h"
30#include "i960c-opc.h"
31#include "opintl.h"
32
33#undef INLINE
34#ifdef __GNUC__
35#define INLINE __inline__
36#else
37#define INLINE
38#endif
39
40/* Default text to print if an instruction isn't recognized. */
41#define UNKNOWN_INSN_MSG _("*unknown*")
42
43/* Used by the ifield rtx function. */
44#define FLD(f) (fields->f)
45
46static int extract_normal
47 PARAMS ((CGEN_OPCODE_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_INT,
48 unsigned int, unsigned int, unsigned int, unsigned int,
49 unsigned int, unsigned int, bfd_vma, long *));
50static void print_normal
51 PARAMS ((CGEN_OPCODE_DESC, PTR, long, unsigned int, bfd_vma, int));
52static void print_address
53 PARAMS ((CGEN_OPCODE_DESC, PTR, bfd_vma, unsigned int, bfd_vma, int));
54static void print_keyword
55 PARAMS ((CGEN_OPCODE_DESC, PTR, CGEN_KEYWORD *, long, unsigned int));
56static int extract_insn_normal
57 PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
58 CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma));
59static void print_insn_normal
60 PARAMS ((CGEN_OPCODE_DESC, PTR, const CGEN_INSN *, CGEN_FIELDS *,
61 bfd_vma, int));
62static int print_insn PARAMS ((CGEN_OPCODE_DESC, bfd_vma,
63 disassemble_info *, char *, int));
64static int default_print_insn
65 PARAMS ((CGEN_OPCODE_DESC, bfd_vma, disassemble_info *));
66\f
67/* -- disassembler routines inserted here */
68
69/* Main entry point for operand extraction.
70
71 This function is basically just a big switch statement. Earlier versions
72 used tables to look up the function to use, but
73 - if the table contains both assembler and disassembler functions then
74 the disassembler contains much of the assembler and vice-versa,
75 - there's a lot of inlining possibilities as things grow,
76 - using a switch statement avoids the function call overhead.
77
78 This function could be moved into `print_insn_normal', but keeping it
79 separate makes clear the interface between `print_insn_normal' and each of
80 the handlers.
81*/
82
83int
84i960_cgen_extract_operand (od, opindex, ex_info, insn_value, fields, pc)
85 CGEN_OPCODE_DESC od;
86 int opindex;
87 CGEN_EXTRACT_INFO *ex_info;
88 CGEN_INSN_INT insn_value;
89 CGEN_FIELDS * fields;
90 bfd_vma pc;
91{
92 int length;
93 unsigned int total_length = CGEN_FIELDS_BITSIZE (fields);
94
95 switch (opindex)
96 {
97 case I960_OPERAND_SRC1 :
98 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 27, 5, 32, total_length, pc, & fields->f_src1);
99 break;
100 case I960_OPERAND_SRC2 :
101 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 13, 5, 32, total_length, pc, & fields->f_src2);
102 break;
103 case I960_OPERAND_DST :
104 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 5, 32, total_length, pc, & fields->f_srcdst);
105 break;
106 case I960_OPERAND_LIT1 :
107 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 27, 5, 32, total_length, pc, & fields->f_src1);
108 break;
109 case I960_OPERAND_LIT2 :
110 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 13, 5, 32, total_length, pc, & fields->f_src2);
111 break;
112 case I960_OPERAND_ST_SRC :
113 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 5, 32, total_length, pc, & fields->f_srcdst);
114 break;
115 case I960_OPERAND_ABASE :
116 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 13, 5, 32, total_length, pc, & fields->f_abase);
117 break;
118 case I960_OPERAND_OFFSET :
119 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 20, 12, 32, total_length, pc, & fields->f_offset);
120 break;
121 case I960_OPERAND_SCALE :
122 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 22, 3, 32, total_length, pc, & fields->f_scale);
123 break;
124 case I960_OPERAND_INDEX :
125 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 27, 5, 32, total_length, pc, & fields->f_index);
126 break;
127 case I960_OPERAND_OPTDISP :
128 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 32, 0, 32, 32, total_length, pc, & fields->f_optdisp);
129 break;
130 case I960_OPERAND_BR_SRC1 :
131 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 5, 32, total_length, pc, & fields->f_br_src1);
132 break;
133 case I960_OPERAND_BR_SRC2 :
134 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 13, 5, 32, total_length, pc, & fields->f_br_src2);
135 break;
136 case I960_OPERAND_BR_DISP :
137 {
138 long value;
5730d39d 139 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_PCREL_ADDR), 0, 19, 11, 32, total_length, pc, & value);
10cb538e
JW
140 value = ((((value) << (2))) + (pc));
141 fields->f_br_disp = value;
142 }
143 break;
144 case I960_OPERAND_BR_LIT1 :
145 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 0, 8, 5, 32, total_length, pc, & fields->f_br_src1);
146 break;
147 case I960_OPERAND_CTRL_DISP :
148 {
149 long value;
5730d39d 150 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_PCREL_ADDR), 0, 8, 22, 32, total_length, pc, & value);
10cb538e
JW
151 value = ((((value) << (2))) + (pc));
152 fields->f_ctrl_disp = value;
153 }
154 break;
155
156 default :
157 /* xgettext:c-format */
158 fprintf (stderr, _("Unrecognized field %d while decoding insn.\n"),
159 opindex);
160 abort ();
161 }
162
163 return length;
164}
165
166/* Main entry point for printing operands.
167
168 This function is basically just a big switch statement. Earlier versions
169 used tables to look up the function to use, but
170 - if the table contains both assembler and disassembler functions then
171 the disassembler contains much of the assembler and vice-versa,
172 - there's a lot of inlining possibilities as things grow,
173 - using a switch statement avoids the function call overhead.
174
175 This function could be moved into `print_insn_normal', but keeping it
176 separate makes clear the interface between `print_insn_normal' and each of
177 the handlers.
178*/
179
180void
181i960_cgen_print_operand (od, opindex, info, fields, attrs, pc, length)
182 CGEN_OPCODE_DESC od;
183 int opindex;
184 disassemble_info * info;
185 CGEN_FIELDS * fields;
186 void const * attrs;
187 bfd_vma pc;
188 int length;
189{
190 switch (opindex)
191 {
192 case I960_OPERAND_SRC1 :
193 print_keyword (od, info, & i960_cgen_opval_h_gr, fields->f_src1, 0|(1<<CGEN_OPERAND_UNSIGNED));
194 break;
195 case I960_OPERAND_SRC2 :
196 print_keyword (od, info, & i960_cgen_opval_h_gr, fields->f_src2, 0|(1<<CGEN_OPERAND_UNSIGNED));
197 break;
198 case I960_OPERAND_DST :
199 print_keyword (od, info, & i960_cgen_opval_h_gr, fields->f_srcdst, 0|(1<<CGEN_OPERAND_UNSIGNED));
200 break;
201 case I960_OPERAND_LIT1 :
202 print_normal (od, info, fields->f_src1, 0|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
203 break;
204 case I960_OPERAND_LIT2 :
205 print_normal (od, info, fields->f_src2, 0|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
206 break;
207 case I960_OPERAND_ST_SRC :
208 print_keyword (od, info, & i960_cgen_opval_h_gr, fields->f_srcdst, 0|(1<<CGEN_OPERAND_UNSIGNED));
209 break;
210 case I960_OPERAND_ABASE :
211 print_keyword (od, info, & i960_cgen_opval_h_gr, fields->f_abase, 0|(1<<CGEN_OPERAND_UNSIGNED));
212 break;
213 case I960_OPERAND_OFFSET :
214 print_normal (od, info, fields->f_offset, 0|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
215 break;
216 case I960_OPERAND_SCALE :
217 print_normal (od, info, fields->f_scale, 0|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
218 break;
219 case I960_OPERAND_INDEX :
220 print_keyword (od, info, & i960_cgen_opval_h_gr, fields->f_index, 0|(1<<CGEN_OPERAND_UNSIGNED));
221 break;
222 case I960_OPERAND_OPTDISP :
223 print_normal (od, info, fields->f_optdisp, 0|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
224 break;
225 case I960_OPERAND_BR_SRC1 :
226 print_keyword (od, info, & i960_cgen_opval_h_gr, fields->f_br_src1, 0|(1<<CGEN_OPERAND_UNSIGNED));
227 break;
228 case I960_OPERAND_BR_SRC2 :
229 print_keyword (od, info, & i960_cgen_opval_h_gr, fields->f_br_src2, 0|(1<<CGEN_OPERAND_UNSIGNED));
230 break;
231 case I960_OPERAND_BR_DISP :
5730d39d 232 print_address (od, info, fields->f_br_disp, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
10cb538e
JW
233 break;
234 case I960_OPERAND_BR_LIT1 :
235 print_normal (od, info, fields->f_br_src1, 0|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
236 break;
237 case I960_OPERAND_CTRL_DISP :
5730d39d 238 print_address (od, info, fields->f_ctrl_disp, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
10cb538e
JW
239 break;
240
241 default :
242 /* xgettext:c-format */
243 fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
244 opindex);
245 abort ();
246 }
247}
248
249cgen_extract_fn * const i960_cgen_extract_handlers[] =
250{
251 0, /* default */
252 extract_insn_normal,
253};
254
255cgen_print_fn * const i960_cgen_print_handlers[] =
256{
257 0, /* default */
258 print_insn_normal,
259};
260
261
262void
263i960_cgen_init_dis (od)
264 CGEN_OPCODE_DESC od;
265{
266}
267
268\f
269#if ! CGEN_INT_INSN_P
270
271/* Subroutine of extract_normal.
272 Ensure sufficient bytes are cached in EX_INFO.
273 OFFSET is the offset in bytes from the start of the insn of the value.
274 BYTES is the length of the needed value.
275 Returns 1 for success, 0 for failure. */
276
277static INLINE int
278fill_cache (od, ex_info, offset, bytes, pc)
279 CGEN_OPCODE_DESC od;
280 CGEN_EXTRACT_INFO *ex_info;
281 int offset, bytes;
282 bfd_vma pc;
283{
284 /* It's doubtful that the middle part has already been fetched so
285 we don't optimize that case. kiss. */
286 int mask;
287 disassemble_info *info = (disassemble_info *) ex_info->dis_info;
288
289 /* First do a quick check. */
290 mask = (1 << bytes) - 1;
291 if (((ex_info->valid >> offset) & mask) == mask)
292 return 1;
293
294 /* Search for the first byte we need to read. */
295 for (mask = 1 << offset; bytes > 0; --bytes, ++offset, mask <<= 1)
296 if (! (mask & ex_info->valid))
297 break;
298
299 if (bytes)
300 {
301 int status;
302
303 pc += offset;
304 status = (*info->read_memory_func)
305 (pc, ex_info->insn_bytes + offset, bytes, info);
306
307 if (status != 0)
308 {
309 (*info->memory_error_func) (status, pc, info);
310 return 0;
311 }
312
313 ex_info->valid |= ((1 << bytes) - 1) << offset;
314 }
315
316 return 1;
317}
318
319/* Subroutine of extract_normal. */
320
321static INLINE long
322extract_1 (od, ex_info, start, length, word_length, bufp, pc)
323 CGEN_OPCODE_DESC od;
324 CGEN_EXTRACT_INFO *ex_info;
325 int start,length,word_length;
326 unsigned char *bufp;
327 bfd_vma pc;
328{
329 unsigned long x,mask;
330 int shift;
331 int big_p = CGEN_OPCODE_INSN_ENDIAN (od) == CGEN_ENDIAN_BIG;
332
333 switch (word_length)
334 {
335 case 8:
336 x = *bufp;
337 break;
338 case 16:
339 if (big_p)
340 x = bfd_getb16 (bufp);
341 else
342 x = bfd_getl16 (bufp);
343 break;
344 case 24:
345 /* ??? This may need reworking as these cases don't necessarily
346 want the first byte and the last two bytes handled like this. */
347 if (big_p)
348 x = (bufp[0] << 16) | bfd_getb16 (bufp + 1);
349 else
350 x = bfd_getl16 (bufp) | (bufp[2] << 16);
351 break;
352 case 32:
353 if (big_p)
354 x = bfd_getb32 (bufp);
355 else
356 x = bfd_getl32 (bufp);
357 break;
358 default :
359 abort ();
360 }
361
362 /* Written this way to avoid undefined behaviour. */
363 mask = (((1L << (length - 1)) - 1) << 1) | 1;
364 if (CGEN_INSN_LSB0_P)
365 shift = (start + 1) - length;
366 else
367 shift = (word_length - (start + length));
368 return (x >> shift) & mask;
369}
370
371#endif /* ! CGEN_INT_INSN_P */
372
373/* Default extraction routine.
374
375 INSN_VALUE is the first CGEN_BASE_INSN_SIZE bits of the insn in host order,
376 or sometimes less for cases like the m32r where the base insn size is 32
377 but some insns are 16 bits.
378 ATTRS is a mask of the boolean attributes. We only need `UNSIGNED',
379 but for generality we take a bitmask of all of them.
380 WORD_OFFSET is the offset in bits from the start of the insn of the value.
381 WORD_LENGTH is the length of the word in bits in which the value resides.
382 START is the starting bit number in the word, architecture origin.
383 LENGTH is the length of VALUE in bits.
384 TOTAL_LENGTH is the total length of the insn in bits.
385
386 Returns 1 for success, 0 for failure. */
387
388/* ??? The return code isn't properly used. wip. */
389
390/* ??? This doesn't handle bfd_vma's. Create another function when
391 necessary. */
392
393static int
394extract_normal (od, ex_info, insn_value, attrs, word_offset, start, length,
395 word_length, total_length, pc, valuep)
396 CGEN_OPCODE_DESC od;
397 CGEN_EXTRACT_INFO *ex_info;
398 CGEN_INSN_INT insn_value;
399 unsigned int attrs;
400 unsigned int word_offset, start, length, word_length, total_length;
401 bfd_vma pc;
402 long *valuep;
403{
404 CGEN_INSN_INT value;
405
406 /* If LENGTH is zero, this operand doesn't contribute to the value
407 so give it a standard value of zero. */
408 if (length == 0)
409 {
410 *valuep = 0;
411 return 1;
412 }
413
414 if (CGEN_INT_INSN_P
415 && word_offset != 0)
416 abort ();
417
418 if (word_length > 32)
419 abort ();
420
421 /* For architectures with insns smaller than the insn-base-bitsize,
422 word_length may be too big. */
423#if CGEN_MIN_INSN_BITSIZE < CGEN_BASE_INSN_BITSIZE
424 if (word_offset == 0
425 && word_length > total_length)
426 word_length = total_length;
427#endif
428
429 /* Does the value reside in INSN_VALUE? */
430
431 if (word_offset == 0)
432 {
433 /* Written this way to avoid undefined behaviour. */
434 CGEN_INSN_INT mask = (((1L << (length - 1)) - 1) << 1) | 1;
435
436 if (CGEN_INSN_LSB0_P)
437 value = insn_value >> ((start + 1) - length);
438 else
439 value = insn_value >> (word_length - (start + length));
440 value &= mask;
441 /* sign extend? */
5730d39d 442 if (! CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED)
10cb538e
JW
443 && (value & (1L << (length - 1))))
444 value |= ~mask;
445 }
446
447#if ! CGEN_INT_INSN_P
448
449 else
450 {
451 unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
452
453 if (word_length > 32)
454 abort ();
455
456 if (fill_cache (od, ex_info, word_offset / 8, word_length / 8, pc) == 0)
457 return 0;
458
459 value = extract_1 (od, ex_info, start, length, word_length, bufp, pc);
460 }
461
462#endif /* ! CGEN_INT_INSN_P */
463
464 *valuep = value;
465
466 return 1;
467}
468
469/* Default print handler. */
470
471static void
472print_normal (od, dis_info, value, attrs, pc, length)
473 CGEN_OPCODE_DESC od;
474 PTR dis_info;
475 long value;
476 unsigned int attrs;
477 bfd_vma pc;
478 int length;
479{
480 disassemble_info *info = (disassemble_info *) dis_info;
481
482#ifdef CGEN_PRINT_NORMAL
483 CGEN_PRINT_NORMAL (od, info, value, attrs, pc, length);
484#endif
485
486 /* Print the operand as directed by the attributes. */
487 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
488 ; /* nothing to do */
489 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED))
490 (*info->fprintf_func) (info->stream, "0x%lx", value);
491 else
492 (*info->fprintf_func) (info->stream, "%ld", value);
493}
494
495/* Default address handler. */
496
497static void
498print_address (od, dis_info, value, attrs, pc, length)
499 CGEN_OPCODE_DESC od;
500 PTR dis_info;
501 bfd_vma value;
502 unsigned int attrs;
503 bfd_vma pc;
504 int length;
505{
506 disassemble_info *info = (disassemble_info *) dis_info;
507
508#ifdef CGEN_PRINT_ADDRESS
509 CGEN_PRINT_ADDRESS (od, info, value, attrs, pc, length);
510#endif
511
512 /* Print the operand as directed by the attributes. */
513 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
514 ; /* nothing to do */
515 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
516 (*info->print_address_func) (value, info);
517 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
518 (*info->print_address_func) (value, info);
519 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED))
520 (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
521 else
522 (*info->fprintf_func) (info->stream, "%ld", (long) value);
523}
524
525/* Keyword print handler. */
526
527static void
528print_keyword (od, dis_info, keyword_table, value, attrs)
529 CGEN_OPCODE_DESC od;
530 PTR dis_info;
531 CGEN_KEYWORD *keyword_table;
532 long value;
533 unsigned int attrs;
534{
535 disassemble_info *info = (disassemble_info *) dis_info;
536 const CGEN_KEYWORD_ENTRY *ke;
537
538 ke = cgen_keyword_lookup_value (keyword_table, value);
539 if (ke != NULL)
540 (*info->fprintf_func) (info->stream, "%s", ke->name);
541 else
542 (*info->fprintf_func) (info->stream, "???");
543}
544\f
545/* Default insn extractor.
546
547 INSN_VALUE is the first CGEN_BASE_INSN_SIZE bytes, translated to host order.
548 The extracted fields are stored in FIELDS.
549 EX_INFO is used to handle reading variable length insns.
550 Return the length of the insn in bits, or 0 if no match,
551 or -1 if an error occurs fetching data (memory_error_func will have
552 been called). */
553
554static int
555extract_insn_normal (od, insn, ex_info, insn_value, fields, pc)
556 CGEN_OPCODE_DESC od;
557 const CGEN_INSN *insn;
558 CGEN_EXTRACT_INFO *ex_info;
559 CGEN_INSN_INT insn_value;
560 CGEN_FIELDS *fields;
561 bfd_vma pc;
562{
563 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
564 const unsigned char *syn;
565
566 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
567
568 CGEN_INIT_EXTRACT (od);
569
570 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
571 {
572 int length;
573
574 if (CGEN_SYNTAX_CHAR_P (*syn))
575 continue;
576
577 length = i960_cgen_extract_operand (od, CGEN_SYNTAX_FIELD (*syn),
578 ex_info, insn_value, fields, pc);
579 if (length <= 0)
580 return length;
581 }
582
583 /* We recognized and successfully extracted this insn. */
584 return CGEN_INSN_BITSIZE (insn);
585}
586
587/* Default insn printer.
588
589 DIS_INFO is defined as `PTR' so the disassembler needn't know anything
590 about disassemble_info. */
591
592static void
593print_insn_normal (od, dis_info, insn, fields, pc, length)
594 CGEN_OPCODE_DESC od;
595 PTR dis_info;
596 const CGEN_INSN *insn;
597 CGEN_FIELDS *fields;
598 bfd_vma pc;
599 int length;
600{
601 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
602 disassemble_info *info = (disassemble_info *) dis_info;
603 const unsigned char *syn;
604
605 CGEN_INIT_PRINT (od);
606
607 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
608 {
609 if (CGEN_SYNTAX_MNEMONIC_P (*syn))
610 {
611 (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
612 continue;
613 }
614 if (CGEN_SYNTAX_CHAR_P (*syn))
615 {
616 (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
617 continue;
618 }
619
620 /* We have an operand. */
621 i960_cgen_print_operand (od, CGEN_SYNTAX_FIELD (*syn), info,
622 fields, CGEN_INSN_ATTRS (insn), pc, length);
623 }
624}
625\f
626/* Utility to print an insn.
627 BUF is the base part of the insn, target byte order, BUFLEN bytes long.
628 The result is the size of the insn in bytes or zero for an unknown insn
629 or -1 if an error occurs fetching data (memory_error_func will have
630 been called). */
631
632static int
633print_insn (od, pc, info, buf, buflen)
634 CGEN_OPCODE_DESC od;
635 bfd_vma pc;
636 disassemble_info *info;
637 char *buf;
638 int buflen;
639{
640 unsigned long insn_value;
641 const CGEN_INSN_LIST *insn_list;
642 CGEN_EXTRACT_INFO ex_info;
643
644 ex_info.dis_info = info;
645 ex_info.valid = (1 << CGEN_BASE_INSN_SIZE) - 1;
646 ex_info.insn_bytes = buf;
647
648 switch (buflen)
649 {
650 case 1:
651 insn_value = buf[0];
652 break;
653 case 2:
654 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buf) : bfd_getl16 (buf);
655 break;
656 case 4:
657 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb32 (buf) : bfd_getl32 (buf);
658 break;
659 default:
660 abort ();
661 }
662
663 /* The instructions are stored in hash lists.
664 Pick the first one and keep trying until we find the right one. */
665
666 insn_list = CGEN_DIS_LOOKUP_INSN (od, buf, insn_value);
667 while (insn_list != NULL)
668 {
669 const CGEN_INSN *insn = insn_list->insn;
670 CGEN_FIELDS fields;
671 int length;
672
673#if 0 /* not needed as insn shouldn't be in hash lists if not supported */
674 /* Supported by this cpu? */
675 if (! i960_cgen_insn_supported (od, insn))
676 continue;
677#endif
678
679 /* Basic bit mask must be correct. */
680 /* ??? May wish to allow target to defer this check until the extract
681 handler. */
682 if ((insn_value & CGEN_INSN_BASE_MASK (insn))
683 == CGEN_INSN_BASE_VALUE (insn))
684 {
685 /* Printing is handled in two passes. The first pass parses the
686 machine insn and extracts the fields. The second pass prints
687 them. */
688
689 length = (*CGEN_EXTRACT_FN (insn)) (od, insn, &ex_info, insn_value,
690 &fields, pc);
691 /* length < 0 -> error */
692 if (length < 0)
693 return length;
694 if (length > 0)
695 {
696 (*CGEN_PRINT_FN (insn)) (od, info, insn, &fields, pc, length);
697 /* length is in bits, result is in bytes */
698 return length / 8;
699 }
700 }
701
702 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
703 }
704
705 return 0;
706}
707
708/* Default value for CGEN_PRINT_INSN.
709 The result is the size of the insn in bytes or zero for an unknown insn
710 or -1 if an error occured fetching bytes. */
711
712#ifndef CGEN_PRINT_INSN
713#define CGEN_PRINT_INSN default_print_insn
714#endif
715
716static int
717default_print_insn (od, pc, info)
718 CGEN_OPCODE_DESC od;
719 bfd_vma pc;
720 disassemble_info *info;
721{
722 char buf[CGEN_MAX_INSN_SIZE];
723 int status;
724
725 /* Read the base part of the insn. */
726
727 status = (*info->read_memory_func) (pc, buf, CGEN_BASE_INSN_SIZE, info);
728 if (status != 0)
729 {
730 (*info->memory_error_func) (status, pc, info);
731 return -1;
732 }
733
734 return print_insn (od, pc, info, buf, CGEN_BASE_INSN_SIZE);
735}
736
737/* Main entry point.
738 Print one instruction from PC on INFO->STREAM.
739 Return the size of the instruction (in bytes). */
740
741int
742print_insn_i960 (pc, info)
743 bfd_vma pc;
744 disassemble_info *info;
745{
746 int length;
747 static CGEN_OPCODE_DESC od = 0;
748 int mach = info->mach;
749 int big_p = info->endian == BFD_ENDIAN_BIG;
750
751 /* If we haven't initialized yet, initialize the opcode table. */
752 if (! od)
753 {
754 od = i960_cgen_opcode_open (mach,
755 big_p ?
756 CGEN_ENDIAN_BIG
757 : CGEN_ENDIAN_LITTLE);
758 i960_cgen_init_dis (od);
759 }
760 /* If we've switched cpu's, re-initialize. */
761 /* ??? Perhaps we should use BFD_ENDIAN. */
762 else if (mach != CGEN_OPCODE_MACH (od)
763 || (CGEN_OPCODE_ENDIAN (od)
764 != (big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE)))
765 {
766 cgen_set_cpu (od, mach, big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE);
767 }
768
769 /* We try to have as much common code as possible.
770 But at this point some targets need to take over. */
771 /* ??? Some targets may need a hook elsewhere. Try to avoid this,
772 but if not possible try to move this hook elsewhere rather than
773 have two hooks. */
774 length = CGEN_PRINT_INSN (od, pc, info);
775 if (length > 0)
776 return length;
777 if (length < 0)
778 return -1;
779
780 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
781 return CGEN_DEFAULT_INSN_SIZE;
782}
This page took 0.067127 seconds and 4 git commands to generate.