* sun build fix for thinko (?)
[binutils-gdb.git] / opcodes / fr30-dis.c
blob3e17061bef10d2114685f0712129bf37a1a7fa4d
1 /* Disassembler interface for targets using CGEN. -*- C -*-
2 CGEN: Cpu tools GENerator
4 THIS FILE IS USED TO GENERATE fr30-dis.c.
6 Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
8 This file is part of the GNU Binutils and GDB, the GNU debugger.
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2, or (at your option)
13 any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software Foundation, Inc.,
22 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
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 "fr30-opc.h"
31 #include "opintl.h"
33 #undef INLINE
34 #ifdef __GNUC__
35 #define INLINE __inline__
36 #else
37 #define INLINE
38 #endif
40 /* Default text to print if an instruction isn't recognized. */
41 #define UNKNOWN_INSN_MSG _("*unknown*")
43 static int extract_normal
44 PARAMS ((CGEN_OPCODE_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_BYTES,
45 unsigned int, int, int, int, long *));
46 static void print_normal
47 PARAMS ((CGEN_OPCODE_DESC, PTR, long, unsigned int, bfd_vma, int));
48 static void print_address
49 PARAMS ((CGEN_OPCODE_DESC, PTR, bfd_vma, unsigned int, bfd_vma, int));
50 static void print_keyword
51 PARAMS ((CGEN_OPCODE_DESC, PTR, CGEN_KEYWORD *, long, unsigned int));
52 static int extract_insn_normal
53 PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
54 unsigned long, CGEN_FIELDS *, bfd_vma));
55 static void print_insn_normal
56 PARAMS ((CGEN_OPCODE_DESC, PTR, const CGEN_INSN *, CGEN_FIELDS *,
57 bfd_vma, int));
58 static int print_insn PARAMS ((CGEN_OPCODE_DESC, bfd_vma,
59 disassemble_info *, char *, int));
60 static int default_print_insn
61 PARAMS ((CGEN_OPCODE_DESC, bfd_vma, disassemble_info *));
63 /* -- disassembler routines inserted here */
65 /* Main entry point for operand extraction.
67 This function is basically just a big switch statement. Earlier versions
68 used tables to look up the function to use, but
69 - if the table contains both assembler and disassembler functions then
70 the disassembler contains much of the assembler and vice-versa,
71 - there's a lot of inlining possibilities as things grow,
72 - using a switch statement avoids the function call overhead.
74 This function could be moved into `print_insn_normal', but keeping it
75 separate makes clear the interface between `print_insn_normal' and each of
76 the handlers.
79 int
80 fr30_cgen_extract_operand (od, opindex, ex_info, insn_value, fields, pc)
81 CGEN_OPCODE_DESC od;
82 int opindex;
83 CGEN_EXTRACT_INFO *ex_info;
84 CGEN_INSN_BYTES insn_value;
85 CGEN_FIELDS * fields;
86 bfd_vma pc;
88 int length;
90 switch (opindex)
92 case FR30_OPERAND_RI :
93 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, CGEN_FIELDS_BITSIZE (fields), & fields->f_Ri);
94 break;
95 case FR30_OPERAND_RJ :
96 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 8, 4, CGEN_FIELDS_BITSIZE (fields), & fields->f_Rj);
97 break;
98 case FR30_OPERAND_RS1 :
99 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 8, 4, CGEN_FIELDS_BITSIZE (fields), & fields->f_Rs1);
100 break;
101 case FR30_OPERAND_RS2 :
102 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 12, 4, CGEN_FIELDS_BITSIZE (fields), & fields->f_Rs2);
103 break;
104 case FR30_OPERAND_U4 :
105 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 8, 4, CGEN_FIELDS_BITSIZE (fields), & fields->f_u4);
106 break;
107 case FR30_OPERAND_M4 :
109 long value;
110 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 8, 4, CGEN_FIELDS_BITSIZE (fields), & value);
111 value = ((value) | ((! (15))));
112 fields->f_m4 = value;
114 break;
115 case FR30_OPERAND_I8 :
116 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 4, 8, CGEN_FIELDS_BITSIZE (fields), & fields->f_i8);
117 break;
118 case FR30_OPERAND_U8 :
119 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), & fields->f_u8);
120 break;
121 case FR30_OPERAND_O8 :
122 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 4, 8, CGEN_FIELDS_BITSIZE (fields), & fields->f_o8);
123 break;
124 case FR30_OPERAND_S10 :
126 long value;
127 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_SIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), & value);
128 value = ((value) << (2));
129 fields->f_s10 = value;
131 break;
132 case FR30_OPERAND_U10 :
134 long value;
135 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), & value);
136 value = ((value) << (2));
137 fields->f_u10 = value;
139 break;
140 case FR30_OPERAND_DIR8 :
141 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), & fields->f_dir8);
142 break;
143 case FR30_OPERAND_DIR9 :
145 long value;
146 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), & value);
147 value = ((value) << (1));
148 fields->f_dir9 = value;
150 break;
151 case FR30_OPERAND_DIR10 :
153 long value;
154 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), & value);
155 value = ((value) << (2));
156 fields->f_dir10 = value;
158 break;
159 case FR30_OPERAND_LABEL9 :
161 long value;
162 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_SIGNED), 8, 8, CGEN_FIELDS_BITSIZE (fields), & value);
163 value = ((value) << (1));
164 fields->f_rel8 = value;
166 break;
167 case FR30_OPERAND_LABEL12 :
169 long value;
170 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_SIGNED), 5, 11, CGEN_FIELDS_BITSIZE (fields), & value);
171 value = ((value) << (1));
172 fields->f_rel11 = value;
174 break;
175 case FR30_OPERAND_CC :
176 length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_UNSIGNED), 4, 4, CGEN_FIELDS_BITSIZE (fields), & fields->f_cc);
177 break;
179 default :
180 /* xgettext:c-format */
181 fprintf (stderr, _("Unrecognized field %d while decoding insn.\n"),
182 opindex);
183 abort ();
186 return length;
189 /* Main entry point for printing operands.
191 This function is basically just a big switch statement. Earlier versions
192 used tables to look up the function to use, but
193 - if the table contains both assembler and disassembler functions then
194 the disassembler contains much of the assembler and vice-versa,
195 - there's a lot of inlining possibilities as things grow,
196 - using a switch statement avoids the function call overhead.
198 This function could be moved into `print_insn_normal', but keeping it
199 separate makes clear the interface between `print_insn_normal' and each of
200 the handlers.
203 void
204 fr30_cgen_print_operand (od, opindex, info, fields, attrs, pc, length)
205 CGEN_OPCODE_DESC od;
206 int opindex;
207 disassemble_info * info;
208 CGEN_FIELDS * fields;
209 void const * attrs;
210 bfd_vma pc;
211 int length;
213 switch (opindex)
215 case FR30_OPERAND_RI :
216 print_keyword (od, info, & fr30_cgen_opval_h_gr, fields->f_Ri, 0|(1<<CGEN_OPERAND_UNSIGNED));
217 break;
218 case FR30_OPERAND_RJ :
219 print_keyword (od, info, & fr30_cgen_opval_h_gr, fields->f_Rj, 0|(1<<CGEN_OPERAND_UNSIGNED));
220 break;
221 case FR30_OPERAND_RS1 :
222 print_keyword (od, info, & fr30_cgen_opval_h_dr, fields->f_Rs1, 0|(1<<CGEN_OPERAND_UNSIGNED));
223 break;
224 case FR30_OPERAND_RS2 :
225 print_keyword (od, info, & fr30_cgen_opval_h_dr, fields->f_Rs2, 0|(1<<CGEN_OPERAND_UNSIGNED));
226 break;
227 case FR30_OPERAND_U4 :
228 print_normal (od, info, fields->f_u4, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
229 break;
230 case FR30_OPERAND_M4 :
231 print_normal (od, info, fields->f_m4, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
232 break;
233 case FR30_OPERAND_I8 :
234 print_normal (od, info, fields->f_i8, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
235 break;
236 case FR30_OPERAND_U8 :
237 print_normal (od, info, fields->f_u8, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
238 break;
239 case FR30_OPERAND_O8 :
240 print_normal (od, info, fields->f_o8, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
241 break;
242 case FR30_OPERAND_S10 :
243 print_normal (od, info, fields->f_s10, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_SIGNED), pc, length);
244 break;
245 case FR30_OPERAND_U10 :
246 print_normal (od, info, fields->f_u10, 0|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
247 break;
248 case FR30_OPERAND_DIR8 :
249 print_normal (od, info, fields->f_dir8, 0|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
250 break;
251 case FR30_OPERAND_DIR9 :
252 print_normal (od, info, fields->f_dir9, 0|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
253 break;
254 case FR30_OPERAND_DIR10 :
255 print_normal (od, info, fields->f_dir10, 0|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
256 break;
257 case FR30_OPERAND_LABEL9 :
258 print_normal (od, info, fields->f_rel8, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
259 break;
260 case FR30_OPERAND_LABEL12 :
261 print_normal (od, info, fields->f_rel11, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
262 break;
263 case FR30_OPERAND_CC :
264 print_normal (od, info, fields->f_cc, 0|(1<<CGEN_OPERAND_UNSIGNED), pc, length);
265 break;
267 default :
268 /* xgettext:c-format */
269 fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
270 opindex);
271 abort ();
275 cgen_extract_fn * const fr30_cgen_extract_handlers[] =
277 0, /* default */
278 extract_insn_normal,
281 cgen_print_fn * const fr30_cgen_print_handlers[] =
283 0, /* default */
284 print_insn_normal,
288 void
289 fr30_cgen_init_dis (od)
290 CGEN_OPCODE_DESC od;
295 #if ! CGEN_INT_INSN_P
297 /* Subroutine of extract_normal. */
299 static INLINE long
300 extract_1 (od, ex_info, start, length, word_length, bufp)
301 CGEN_OPCODE_DESC od;
302 CGEN_EXTRACT_INFO *info;
303 int start,length,word_length;
304 unsigned char *bufp;
306 unsigned long x,mask;
307 int shift;
308 int big_p = CGEN_OPCODE_INSN_ENDIAN (od) == CGEN_ENDIAN_BIG;
310 /* FIXME: Need to use ex_info to ensure bytes have been fetched. */
312 switch (word_length)
314 case 8:
315 x = *bufp;
316 break;
317 case 16:
318 if (big_p)
319 x = bfd_getb16 (bufp);
320 else
321 x = bfd_getl16 (bufp);
322 break;
323 case 24:
324 /* ??? This may need reworking as these cases don't necessarily
325 want the first byte and the last two bytes handled like this. */
326 if (big_p)
327 x = (bfd_getb8 (bufp) << 16) | bfd_getb16 (bufp + 1);
328 else
329 x = bfd_getl16 (bufp) | (bfd_getb8 (bufp + 2) << 16);
330 break;
331 case 32:
332 if (big_p)
333 x = bfd_getb32 (bufp);
334 else
335 x = bfd_getl32 (bufp);
336 break;
337 default :
338 abort ();
341 /* Written this way to avoid undefined behaviour. */
342 mask = (((1L << (length - 1)) - 1) << 1) | 1;
343 if (CGEN_INSN_LSB0_P)
344 shift = start;
345 else
346 shift = (word_length - (start + length));
347 return (x >> shift) & mask;
350 #endif /* ! CGEN_INT_INSN_P */
352 /* Default extraction routine.
354 ATTRS is a mask of the boolean attributes. We only need `unsigned',
355 but for generality we take a bitmask of all of them. */
357 /* ??? This doesn't handle bfd_vma's. Create another function when
358 necessary. */
360 static int
361 extract_normal (od, ex_info, insn_value, attrs, start, length, total_length, valuep)
362 CGEN_OPCODE_DESC od;
363 CGEN_EXTRACT_INFO *ex_info;
364 CGEN_INSN_BYTES insn_value;
365 unsigned int attrs;
366 int start, length, total_length;
367 long *valuep;
369 unsigned long value;
371 /* If LENGTH is zero, this operand doesn't contribute to the value
372 so give it a standard value of zero. */
373 if (length == 0)
375 *valuep = 0;
376 return 1;
379 #if CGEN_INT_INSN_P
382 /* Written this way to avoid undefined behaviour. */
383 unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
385 if (CGEN_INSN_LSB0_P)
386 value = insn_value >> start;
387 else
388 value = insn_value >> (total_length - (start + length));
389 value &= mask;
390 /* sign extend? */
391 if (! (attrs & CGEN_ATTR_MASK (CGEN_OPERAND_UNSIGNED))
392 && (value & (1L << (length - 1))))
393 value |= ~mask;
396 #else
398 /* The hard case is probably too slow for the normal cases.
399 It's certainly more difficult to understand than the normal case.
400 Thus this is split into two. Keep it that way. The hard case is defined
401 to be when a field straddles a (loosely defined) word boundary
402 (??? which may require target specific help to determine). */
404 #if 0 /*wip*/
406 #define HARD_CASE_P 0 /* FIXME:wip */
408 if (HARD_CASE_P)
411 #endif
412 else
414 unsigned char *bufp = (unsigned char *) insn_value;
416 if (length > 32)
417 abort ();
419 /* Adjust start,total_length,bufp to point to the pseudo-word that holds
420 the value. For example in a 48 bit insn where the value to insert
421 (say an immediate value) is the last 16 bits then word_length here
422 would be 16. To handle a 24 bit insn with an 18 bit immediate,
423 extract_1 handles 24 bits (using a combination of bfd_get8,16). */
425 if (total_length > 32)
427 int needed_width = start % 8 + length;
428 int fetch_length = (needed_width <= 8 ? 8
429 : needed_width <= 16 ? 16
430 : 32);
432 if (CGEN_INSN_LSB0_P)
434 if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
436 abort (); /* wip */
438 else
440 int offset = start & ~7;
442 bufp += offset / 8;
443 start -= offset;
444 total_length -= offset;
447 else
449 if (CGEN_INSN_WORD_ENDIAN (od) == CGEN_ENDIAN_BIG)
451 int offset = start & ~7;
453 bufp += offset / 8;
454 start -= offset;
455 total_length -= offset;
457 else
459 abort (); /* wip */
464 /* FIXME: which bytes are being extracted have been lost. */
465 value = extract_1 (od, ex_info, start, length, total_length, bufp);
468 #endif /* ! CGEN_INT_INSN_P */
470 *valuep = value;
472 /* FIXME: for now */
473 return 1;
476 /* Default print handler. */
478 static void
479 print_normal (od, dis_info, value, attrs, pc, length)
480 CGEN_OPCODE_DESC od;
481 PTR dis_info;
482 long value;
483 unsigned int attrs;
484 bfd_vma pc;
485 int length;
487 disassemble_info *info = (disassemble_info *) dis_info;
489 #ifdef CGEN_PRINT_NORMAL
490 CGEN_PRINT_NORMAL (od, info, value, attrs, pc, length);
491 #endif
493 /* Print the operand as directed by the attributes. */
494 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
495 ; /* nothing to do */
496 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED))
497 (*info->fprintf_func) (info->stream, "0x%lx", value);
498 else
499 (*info->fprintf_func) (info->stream, "%ld", value);
502 /* Default address handler. */
504 static void
505 print_address (od, dis_info, value, attrs, pc, length)
506 CGEN_OPCODE_DESC od;
507 PTR dis_info;
508 bfd_vma value;
509 unsigned int attrs;
510 bfd_vma pc;
511 int length;
513 disassemble_info *info = (disassemble_info *) dis_info;
515 #ifdef CGEN_PRINT_ADDRESS
516 CGEN_PRINT_ADDRESS (od, info, value, attrs, pc, length);
517 #endif
519 /* Print the operand as directed by the attributes. */
520 if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
521 ; /* nothing to do */
522 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
523 (*info->print_address_func) (value, info);
524 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
525 (*info->print_address_func) (value, info);
526 else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED))
527 (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
528 else
529 (*info->fprintf_func) (info->stream, "%ld", (long) value);
532 /* Keyword print handler. */
534 static void
535 print_keyword (od, dis_info, keyword_table, value, attrs)
536 CGEN_OPCODE_DESC od;
537 PTR dis_info;
538 CGEN_KEYWORD *keyword_table;
539 long value;
540 unsigned int attrs;
542 disassemble_info *info = (disassemble_info *) dis_info;
543 const CGEN_KEYWORD_ENTRY *ke;
545 ke = cgen_keyword_lookup_value (keyword_table, value);
546 if (ke != NULL)
547 (*info->fprintf_func) (info->stream, "%s", ke->name);
548 else
549 (*info->fprintf_func) (info->stream, "???");
552 /* Default insn extractor.
554 INSN_VALUE is the first CGEN_BASE_INSN_SIZE bytes, translated to host order.
555 The extracted fields are stored in FIELDS.
556 EX_INFO is used to handle reading variable length insns.
557 Return the length of the insn in bits, or 0 if no match,
558 or -1 if an error occurs fetching data (memory_error_func will have
559 been called). */
561 static int
562 extract_insn_normal (od, insn, ex_info, insn_value, fields, pc)
563 CGEN_OPCODE_DESC od;
564 const CGEN_INSN *insn;
565 CGEN_EXTRACT_INFO *ex_info;
566 unsigned long insn_value;
567 CGEN_FIELDS *fields;
568 bfd_vma pc;
570 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
571 const unsigned char *syn;
573 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
575 CGEN_INIT_EXTRACT (od);
577 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
579 int length;
581 if (CGEN_SYNTAX_CHAR_P (*syn))
582 continue;
584 length = fr30_cgen_extract_operand (od, CGEN_SYNTAX_FIELD (*syn),
585 ex_info, insn_value, fields, pc);
586 if (length <= 0)
587 return length;
590 /* We recognized and successfully extracted this insn. */
591 return CGEN_INSN_BITSIZE (insn);
594 /* Default insn printer.
596 DIS_INFO is defined as `PTR' so the disassembler needn't know anything
597 about disassemble_info. */
599 static void
600 print_insn_normal (od, dis_info, insn, fields, pc, length)
601 CGEN_OPCODE_DESC od;
602 PTR dis_info;
603 const CGEN_INSN *insn;
604 CGEN_FIELDS *fields;
605 bfd_vma pc;
606 int length;
608 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
609 disassemble_info *info = (disassemble_info *) dis_info;
610 const unsigned char *syn;
612 CGEN_INIT_PRINT (od);
614 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
616 if (CGEN_SYNTAX_MNEMONIC_P (*syn))
618 (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
619 continue;
621 if (CGEN_SYNTAX_CHAR_P (*syn))
623 (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
624 continue;
627 /* We have an operand. */
628 fr30_cgen_print_operand (od, CGEN_SYNTAX_FIELD (*syn), info,
629 fields, CGEN_INSN_ATTRS (insn), pc, length);
633 /* Utility to print an insn.
634 BUF is the base part of the insn, target byte order, BUFLEN bytes long.
635 The result is the size of the insn in bytes or zero for an unknown insn
636 or -1 if an error occurs fetching data (memory_error_func will have
637 been called). */
639 static int
640 print_insn (od, pc, info, buf, buflen)
641 CGEN_OPCODE_DESC od;
642 bfd_vma pc;
643 disassemble_info *info;
644 char *buf;
645 int buflen;
647 unsigned long insn_value;
648 const CGEN_INSN_LIST *insn_list;
649 CGEN_EXTRACT_INFO ex_info;
651 ex_info.dis_info = info;
652 ex_info.valid = (1 << CGEN_BASE_INSN_SIZE) - 1;
653 ex_info.bytes = buf;
655 switch (buflen)
657 case 1:
658 insn_value = buf[0];
659 break;
660 case 2:
661 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb16 (buf) : bfd_getl16 (buf);
662 break;
663 case 4:
664 insn_value = info->endian == BFD_ENDIAN_BIG ? bfd_getb32 (buf) : bfd_getl32 (buf);
665 break;
666 default:
667 abort ();
670 /* The instructions are stored in hash lists.
671 Pick the first one and keep trying until we find the right one. */
673 insn_list = CGEN_DIS_LOOKUP_INSN (od, buf, insn_value);
674 while (insn_list != NULL)
676 const CGEN_INSN *insn = insn_list->insn;
677 CGEN_FIELDS fields;
678 int length;
680 #if 0 /* not needed as insn shouldn't be in hash lists if not supported */
681 /* Supported by this cpu? */
682 if (! fr30_cgen_insn_supported (od, insn))
683 continue;
684 #endif
686 /* Basic bit mask must be correct. */
687 /* ??? May wish to allow target to defer this check until the extract
688 handler. */
689 if ((insn_value & CGEN_INSN_MASK (insn)) == CGEN_INSN_VALUE (insn))
691 /* Printing is handled in two passes. The first pass parses the
692 machine insn and extracts the fields. The second pass prints
693 them. */
695 length = (*CGEN_EXTRACT_FN (insn)) (od, insn, &ex_info, insn_value,
696 &fields, pc);
697 /* length < 0 -> error */
698 if (length < 0)
699 return length;
700 if (length > 0)
702 (*CGEN_PRINT_FN (insn)) (od, info, insn, &fields, pc, length);
703 /* length is in bits, result is in bytes */
704 return length / 8;
708 insn_list = CGEN_DIS_NEXT_INSN (insn_list);
711 return 0;
714 /* Default value for CGEN_PRINT_INSN.
715 The result is the size of the insn in bytes or zero for an unknown insn
716 or -1 if an error occured fetching bytes. */
718 #ifndef CGEN_PRINT_INSN
719 #define CGEN_PRINT_INSN default_print_insn
720 #endif
722 static int
723 default_print_insn (od, pc, info)
724 CGEN_OPCODE_DESC od;
725 bfd_vma pc;
726 disassemble_info *info;
728 char buf[CGEN_MAX_INSN_SIZE];
729 int status;
731 /* Read the base part of the insn. */
733 status = (*info->read_memory_func) (pc, buf, CGEN_BASE_INSN_SIZE, info);
734 if (status != 0)
736 (*info->memory_error_func) (status, pc, info);
737 return -1;
740 return print_insn (od, pc, info, buf, CGEN_BASE_INSN_SIZE);
743 /* Main entry point.
744 Print one instruction from PC on INFO->STREAM.
745 Return the size of the instruction (in bytes). */
748 print_insn_fr30 (pc, info)
749 bfd_vma pc;
750 disassemble_info *info;
752 int length;
753 static CGEN_OPCODE_DESC od = 0;
754 int mach = info->mach;
755 int big_p = info->endian == BFD_ENDIAN_BIG;
757 /* If we haven't initialized yet, initialize the opcode table. */
758 if (! od)
760 od = fr30_cgen_opcode_open (mach,
761 big_p ?
762 CGEN_ENDIAN_BIG
763 : CGEN_ENDIAN_LITTLE);
764 fr30_cgen_init_dis (od);
766 /* If we've switched cpu's, re-initialize. */
767 /* ??? Perhaps we should use BFD_ENDIAN. */
768 else if (mach != CGEN_OPCODE_MACH (od)
769 || (CGEN_OPCODE_ENDIAN (od)
770 != (big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE)))
772 cgen_set_cpu (od, mach, big_p ? CGEN_ENDIAN_BIG : CGEN_ENDIAN_LITTLE);
775 /* We try to have as much common code as possible.
776 But at this point some targets need to take over. */
777 /* ??? Some targets may need a hook elsewhere. Try to avoid this,
778 but if not possible try to move this hook elsewhere rather than
779 have two hooks. */
780 length = CGEN_PRINT_INSN (od, pc, info);
781 if (length > 0)
782 return length;
783 if (length < 0)
784 return -1;
786 (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
787 return CGEN_DEFAULT_INSN_SIZE;