* cgen-asm.in (insert_normal): Use CGEN_BOOL_ATTR.
[platform/upstream/binutils.git] / opcodes / i960c-dis.c
1 /* Disassembler interface for targets using CGEN. -*- C -*-
2    CGEN: Cpu tools GENerator
3
4 THIS FILE IS USED TO GENERATE i960c-dis.c.
5
6 Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
7
8 This file is part of the GNU Binutils and GDB, the GNU debugger.
9
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.
14
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.
19
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.  */
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
46 static 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 *));
50 static void print_normal
51      PARAMS ((CGEN_OPCODE_DESC, PTR, long, unsigned int, bfd_vma, int));
52 static void print_address
53      PARAMS ((CGEN_OPCODE_DESC, PTR, bfd_vma, unsigned int, bfd_vma, int));
54 static void print_keyword
55      PARAMS ((CGEN_OPCODE_DESC, PTR, CGEN_KEYWORD *, long, unsigned int));
56 static int extract_insn_normal
57      PARAMS ((CGEN_OPCODE_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
58               CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma));
59 static void print_insn_normal
60      PARAMS ((CGEN_OPCODE_DESC, PTR, const CGEN_INSN *, CGEN_FIELDS *,
61               bfd_vma, int));
62 static int print_insn PARAMS ((CGEN_OPCODE_DESC, bfd_vma,
63                                disassemble_info *, char *, int));
64 static 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
83 int
84 i960_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;
139         length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_PCREL_ADDR), 0, 19, 11, 32, total_length, pc, & value);
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;
150         length = extract_normal (od, ex_info, insn_value, 0|(1<<CGEN_OPERAND_PCREL_ADDR), 0, 8, 22, 32, total_length, pc, & value);
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
180 void
181 i960_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 :
232       print_address (od, info, fields->f_br_disp, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
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 :
238       print_address (od, info, fields->f_ctrl_disp, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
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
249 cgen_extract_fn * const i960_cgen_extract_handlers[] = 
250 {
251   0, /* default */
252   extract_insn_normal,
253 };
254
255 cgen_print_fn * const i960_cgen_print_handlers[] = 
256 {
257   0, /* default */
258   print_insn_normal,
259 };
260
261
262 void
263 i960_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
277 static INLINE int
278 fill_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
321 static INLINE long
322 extract_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
393 static int
394 extract_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? */
442       if (! CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_UNSIGNED)
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
471 static void
472 print_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
497 static void
498 print_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
527 static void
528 print_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
554 static int
555 extract_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
592 static void
593 print_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
632 static int
633 print_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
716 static int
717 default_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
741 int
742 print_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 }