OSDN Git Service

bfd/ChangeLog:
[pf3gnuchains/pf3gnuchains3x.git] / opcodes / frv-dis.c
1 /* Disassembler interface for targets using CGEN. -*- C -*-
2    CGEN: Cpu tools GENerator
3
4 THIS FILE IS MACHINE GENERATED WITH CGEN.
5 - the resultant file is machine generated, cgen-dis.in isn't
6
7 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002
8 Free Software Foundation, Inc.
9
10 This file is part of the GNU Binutils and GDB, the GNU debugger.
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2, or (at your option)
15 any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software Foundation, Inc.,
24 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
25
26 /* ??? Eventually more and more of this stuff can go to cpu-independent files.
27    Keep that in mind.  */
28
29 #include "sysdep.h"
30 #include <stdio.h>
31 #include "ansidecl.h"
32 #include "dis-asm.h"
33 #include "bfd.h"
34 #include "symcat.h"
35 #include "libiberty.h"
36 #include "frv-desc.h"
37 #include "frv-opc.h"
38 #include "opintl.h"
39
40 /* Default text to print if an instruction isn't recognized.  */
41 #define UNKNOWN_INSN_MSG _("*unknown*")
42
43 static void print_normal
44   (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
45 static void print_address
46   (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int);
47 static void print_keyword
48   (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int);
49 static void print_insn_normal
50   (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
51 static int print_insn
52   (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, char *, unsigned);
53 static int default_print_insn
54   (CGEN_CPU_DESC, bfd_vma, disassemble_info *);
55 static int read_insn
56   (CGEN_CPU_DESC, bfd_vma, disassemble_info *, char *, int, CGEN_EXTRACT_INFO *,
57    unsigned long *);
58 \f
59 /* -- disassembler routines inserted here */
60
61 /* -- dis.c */
62 static void print_spr
63   PARAMS ((CGEN_CPU_DESC, PTR, CGEN_KEYWORD *, long, unsigned));
64 static void print_hi
65   PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
66 static void print_lo
67   PARAMS ((CGEN_CPU_DESC, PTR, long, unsigned, bfd_vma, int));
68
69 static void
70 print_at (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
71           PTR dis_info,
72           CGEN_KEYWORD *names ATTRIBUTE_UNUSED,
73           long value ATTRIBUTE_UNUSED,
74           bfd_vma pc ATTRIBUTE_UNUSED,
75           int length ATTRIBUTE_UNUSED
76           )
77 {
78   disassemble_info *info = (disassemble_info *) dis_info;
79   (*info->fprintf_func) (info->stream, "@");
80 }  
81
82 static void
83 print_spr (cd, dis_info, names, regno, attrs)
84      CGEN_CPU_DESC cd;
85      PTR dis_info;
86      CGEN_KEYWORD *names;
87      long regno;
88      unsigned int attrs;
89 {
90   /* Use the register index format for any unnamed registers.  */
91   if (cgen_keyword_lookup_value (names, regno) == NULL)
92     {
93       disassemble_info *info = (disassemble_info *) dis_info;
94       (*info->fprintf_func) (info->stream, "spr[%ld]", regno);
95     }
96   else
97     print_keyword (cd, dis_info, names, regno, attrs);
98 }
99
100 static void
101 print_hi (cd, dis_info, value, attrs, pc, length)
102      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
103      PTR dis_info;
104      long value;
105      unsigned int attrs ATTRIBUTE_UNUSED;
106      bfd_vma pc ATTRIBUTE_UNUSED;
107      int length ATTRIBUTE_UNUSED;
108 {
109   disassemble_info *info = (disassemble_info *) dis_info;
110   if (value)
111     (*info->fprintf_func) (info->stream, "0x%lx", value);
112   else
113     (*info->fprintf_func) (info->stream, "hi(0x%lx)", value);
114 }
115
116 static void
117 print_lo (cd, dis_info, value, attrs, pc, length)
118      CGEN_CPU_DESC cd ATTRIBUTE_UNUSED;
119      PTR dis_info;
120      long value;
121      unsigned int attrs ATTRIBUTE_UNUSED;
122      bfd_vma pc ATTRIBUTE_UNUSED;
123      int length ATTRIBUTE_UNUSED;
124 {
125   disassemble_info *info = (disassemble_info *) dis_info;
126   if (value)
127     (*info->fprintf_func) (info->stream, "0x%lx", value);
128   else
129     (*info->fprintf_func) (info->stream, "lo(0x%lx)", value);
130 }
131
132 /* -- */
133
134 void frv_cgen_print_operand
135   PARAMS ((CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *,
136            void const *, bfd_vma, int));
137
138 /* Main entry point for printing operands.
139    XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
140    of dis-asm.h on cgen.h.
141
142    This function is basically just a big switch statement.  Earlier versions
143    used tables to look up the function to use, but
144    - if the table contains both assembler and disassembler functions then
145      the disassembler contains much of the assembler and vice-versa,
146    - there's a lot of inlining possibilities as things grow,
147    - using a switch statement avoids the function call overhead.
148
149    This function could be moved into `print_insn_normal', but keeping it
150    separate makes clear the interface between `print_insn_normal' and each of
151    the handlers.  */
152
153 void
154 frv_cgen_print_operand (cd, opindex, xinfo, fields, attrs, pc, length)
155      CGEN_CPU_DESC cd;
156      int opindex;
157      PTR xinfo;
158      CGEN_FIELDS *fields;
159      void const *attrs ATTRIBUTE_UNUSED;
160      bfd_vma pc;
161      int length;
162 {
163  disassemble_info *info = (disassemble_info *) xinfo;
164
165   switch (opindex)
166     {
167     case FRV_OPERAND_A0 :
168       print_normal (cd, info, fields->f_A, 0, pc, length);
169       break;
170     case FRV_OPERAND_A1 :
171       print_normal (cd, info, fields->f_A, 0, pc, length);
172       break;
173     case FRV_OPERAND_ACC40SI :
174       print_keyword (cd, info, & frv_cgen_opval_acc_names, fields->f_ACC40Si, 0);
175       break;
176     case FRV_OPERAND_ACC40SK :
177       print_keyword (cd, info, & frv_cgen_opval_acc_names, fields->f_ACC40Sk, 0);
178       break;
179     case FRV_OPERAND_ACC40UI :
180       print_keyword (cd, info, & frv_cgen_opval_acc_names, fields->f_ACC40Ui, 0);
181       break;
182     case FRV_OPERAND_ACC40UK :
183       print_keyword (cd, info, & frv_cgen_opval_acc_names, fields->f_ACC40Uk, 0);
184       break;
185     case FRV_OPERAND_ACCGI :
186       print_keyword (cd, info, & frv_cgen_opval_accg_names, fields->f_ACCGi, 0);
187       break;
188     case FRV_OPERAND_ACCGK :
189       print_keyword (cd, info, & frv_cgen_opval_accg_names, fields->f_ACCGk, 0);
190       break;
191     case FRV_OPERAND_CCI :
192       print_keyword (cd, info, & frv_cgen_opval_cccr_names, fields->f_CCi, 0);
193       break;
194     case FRV_OPERAND_CPRDOUBLEK :
195       print_keyword (cd, info, & frv_cgen_opval_cpr_names, fields->f_CPRk, 0);
196       break;
197     case FRV_OPERAND_CPRI :
198       print_keyword (cd, info, & frv_cgen_opval_cpr_names, fields->f_CPRi, 0);
199       break;
200     case FRV_OPERAND_CPRJ :
201       print_keyword (cd, info, & frv_cgen_opval_cpr_names, fields->f_CPRj, 0);
202       break;
203     case FRV_OPERAND_CPRK :
204       print_keyword (cd, info, & frv_cgen_opval_cpr_names, fields->f_CPRk, 0);
205       break;
206     case FRV_OPERAND_CRI :
207       print_keyword (cd, info, & frv_cgen_opval_cccr_names, fields->f_CRi, 0);
208       break;
209     case FRV_OPERAND_CRJ :
210       print_keyword (cd, info, & frv_cgen_opval_cccr_names, fields->f_CRj, 0);
211       break;
212     case FRV_OPERAND_CRJ_FLOAT :
213       print_keyword (cd, info, & frv_cgen_opval_cccr_names, fields->f_CRj_float, 0);
214       break;
215     case FRV_OPERAND_CRJ_INT :
216       print_keyword (cd, info, & frv_cgen_opval_cccr_names, fields->f_CRj_int, 0);
217       break;
218     case FRV_OPERAND_CRK :
219       print_keyword (cd, info, & frv_cgen_opval_cccr_names, fields->f_CRk, 0);
220       break;
221     case FRV_OPERAND_FCCI_1 :
222       print_keyword (cd, info, & frv_cgen_opval_fccr_names, fields->f_FCCi_1, 0);
223       break;
224     case FRV_OPERAND_FCCI_2 :
225       print_keyword (cd, info, & frv_cgen_opval_fccr_names, fields->f_FCCi_2, 0);
226       break;
227     case FRV_OPERAND_FCCI_3 :
228       print_keyword (cd, info, & frv_cgen_opval_fccr_names, fields->f_FCCi_3, 0);
229       break;
230     case FRV_OPERAND_FCCK :
231       print_keyword (cd, info, & frv_cgen_opval_fccr_names, fields->f_FCCk, 0);
232       break;
233     case FRV_OPERAND_FRDOUBLEI :
234       print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRi, 0);
235       break;
236     case FRV_OPERAND_FRDOUBLEJ :
237       print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRj, 0);
238       break;
239     case FRV_OPERAND_FRDOUBLEK :
240       print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRk, 0);
241       break;
242     case FRV_OPERAND_FRI :
243       print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRi, 0);
244       break;
245     case FRV_OPERAND_FRINTI :
246       print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRi, 0);
247       break;
248     case FRV_OPERAND_FRINTIEVEN :
249       print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRi, 0);
250       break;
251     case FRV_OPERAND_FRINTJ :
252       print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRj, 0);
253       break;
254     case FRV_OPERAND_FRINTJEVEN :
255       print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRj, 0);
256       break;
257     case FRV_OPERAND_FRINTK :
258       print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRk, 0);
259       break;
260     case FRV_OPERAND_FRINTKEVEN :
261       print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRk, 0);
262       break;
263     case FRV_OPERAND_FRJ :
264       print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRj, 0);
265       break;
266     case FRV_OPERAND_FRK :
267       print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRk, 0);
268       break;
269     case FRV_OPERAND_FRKHI :
270       print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRk, 0);
271       break;
272     case FRV_OPERAND_FRKLO :
273       print_keyword (cd, info, & frv_cgen_opval_fr_names, fields->f_FRk, 0);
274       break;
275     case FRV_OPERAND_GRDOUBLEK :
276       print_keyword (cd, info, & frv_cgen_opval_gr_names, fields->f_GRk, 0);
277       break;
278     case FRV_OPERAND_GRI :
279       print_keyword (cd, info, & frv_cgen_opval_gr_names, fields->f_GRi, 0);
280       break;
281     case FRV_OPERAND_GRJ :
282       print_keyword (cd, info, & frv_cgen_opval_gr_names, fields->f_GRj, 0);
283       break;
284     case FRV_OPERAND_GRK :
285       print_keyword (cd, info, & frv_cgen_opval_gr_names, fields->f_GRk, 0);
286       break;
287     case FRV_OPERAND_GRKHI :
288       print_keyword (cd, info, & frv_cgen_opval_gr_names, fields->f_GRk, 0);
289       break;
290     case FRV_OPERAND_GRKLO :
291       print_keyword (cd, info, & frv_cgen_opval_gr_names, fields->f_GRk, 0);
292       break;
293     case FRV_OPERAND_ICCI_1 :
294       print_keyword (cd, info, & frv_cgen_opval_iccr_names, fields->f_ICCi_1, 0);
295       break;
296     case FRV_OPERAND_ICCI_2 :
297       print_keyword (cd, info, & frv_cgen_opval_iccr_names, fields->f_ICCi_2, 0);
298       break;
299     case FRV_OPERAND_ICCI_3 :
300       print_keyword (cd, info, & frv_cgen_opval_iccr_names, fields->f_ICCi_3, 0);
301       break;
302     case FRV_OPERAND_LI :
303       print_normal (cd, info, fields->f_LI, 0, pc, length);
304       break;
305     case FRV_OPERAND_LRAD :
306       print_normal (cd, info, fields->f_LRAD, 0, pc, length);
307       break;
308     case FRV_OPERAND_LRAE :
309       print_normal (cd, info, fields->f_LRAE, 0, pc, length);
310       break;
311     case FRV_OPERAND_LRAS :
312       print_normal (cd, info, fields->f_LRAS, 0, pc, length);
313       break;
314     case FRV_OPERAND_TLBPRL :
315       print_normal (cd, info, fields->f_TLBPRL, 0, pc, length);
316       break;
317     case FRV_OPERAND_TLBPROPX :
318       print_normal (cd, info, fields->f_TLBPRopx, 0, pc, length);
319       break;
320     case FRV_OPERAND_AE :
321       print_normal (cd, info, fields->f_ae, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
322       break;
323     case FRV_OPERAND_CALLANN :
324       print_at (cd, info, fields->f_reloc_ann, 0, pc, length);
325       break;
326     case FRV_OPERAND_CCOND :
327       print_normal (cd, info, fields->f_ccond, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
328       break;
329     case FRV_OPERAND_COND :
330       print_normal (cd, info, fields->f_cond, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
331       break;
332     case FRV_OPERAND_D12 :
333       print_normal (cd, info, fields->f_d12, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
334       break;
335     case FRV_OPERAND_DEBUG :
336       print_normal (cd, info, fields->f_debug, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
337       break;
338     case FRV_OPERAND_EIR :
339       print_normal (cd, info, fields->f_eir, 0, pc, length);
340       break;
341     case FRV_OPERAND_HINT :
342       print_normal (cd, info, fields->f_hint, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
343       break;
344     case FRV_OPERAND_HINT_NOT_TAKEN :
345       print_keyword (cd, info, & frv_cgen_opval_h_hint_not_taken, fields->f_hint, 0);
346       break;
347     case FRV_OPERAND_HINT_TAKEN :
348       print_keyword (cd, info, & frv_cgen_opval_h_hint_taken, fields->f_hint, 0);
349       break;
350     case FRV_OPERAND_LABEL16 :
351       print_address (cd, info, fields->f_label16, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
352       break;
353     case FRV_OPERAND_LABEL24 :
354       print_address (cd, info, fields->f_label24, 0|(1<<CGEN_OPERAND_PCREL_ADDR)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
355       break;
356     case FRV_OPERAND_LDANN :
357       print_at (cd, info, fields->f_reloc_ann, 0, pc, length);
358       break;
359     case FRV_OPERAND_LDDANN :
360       print_at (cd, info, fields->f_reloc_ann, 0, pc, length);
361       break;
362     case FRV_OPERAND_LOCK :
363       print_normal (cd, info, fields->f_lock, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
364       break;
365     case FRV_OPERAND_PACK :
366       print_keyword (cd, info, & frv_cgen_opval_h_pack, fields->f_pack, 0);
367       break;
368     case FRV_OPERAND_S10 :
369       print_normal (cd, info, fields->f_s10, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
370       break;
371     case FRV_OPERAND_S12 :
372       print_normal (cd, info, fields->f_d12, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
373       break;
374     case FRV_OPERAND_S16 :
375       print_normal (cd, info, fields->f_s16, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
376       break;
377     case FRV_OPERAND_S5 :
378       print_normal (cd, info, fields->f_s5, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
379       break;
380     case FRV_OPERAND_S6 :
381       print_normal (cd, info, fields->f_s6, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
382       break;
383     case FRV_OPERAND_S6_1 :
384       print_normal (cd, info, fields->f_s6_1, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
385       break;
386     case FRV_OPERAND_SLO16 :
387       print_lo (cd, info, fields->f_s16, 0|(1<<CGEN_OPERAND_SIGNED), pc, length);
388       break;
389     case FRV_OPERAND_SPR :
390       print_spr (cd, info, & frv_cgen_opval_spr_names, fields->f_spr, 0|(1<<CGEN_OPERAND_VIRTUAL));
391       break;
392     case FRV_OPERAND_U12 :
393       print_normal (cd, info, fields->f_u12, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_HASH_PREFIX)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
394       break;
395     case FRV_OPERAND_U16 :
396       print_normal (cd, info, fields->f_u16, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
397       break;
398     case FRV_OPERAND_U6 :
399       print_normal (cd, info, fields->f_u6, 0|(1<<CGEN_OPERAND_HASH_PREFIX), pc, length);
400       break;
401     case FRV_OPERAND_UHI16 :
402       print_hi (cd, info, fields->f_u16, 0, pc, length);
403       break;
404     case FRV_OPERAND_ULO16 :
405       print_lo (cd, info, fields->f_u16, 0, pc, length);
406       break;
407
408     default :
409       /* xgettext:c-format */
410       fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
411                opindex);
412     abort ();
413   }
414 }
415
416 cgen_print_fn * const frv_cgen_print_handlers[] = 
417 {
418   print_insn_normal,
419 };
420
421
422 void
423 frv_cgen_init_dis (cd)
424      CGEN_CPU_DESC cd;
425 {
426   frv_cgen_init_opcode_table (cd);
427   frv_cgen_init_ibld_table (cd);
428   cd->print_handlers = & frv_cgen_print_handlers[0];
429   cd->print_operand = frv_cgen_print_operand;
430 }
431
432 \f
433 /* Default print handler.  */
434
435 static void
436 print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
437               void *dis_info,
438               long value,
439               unsigned int attrs,
440               bfd_vma pc ATTRIBUTE_UNUSED,
441               int length ATTRIBUTE_UNUSED)
442 {
443   disassemble_info *info = (disassemble_info *) dis_info;
444
445 #ifdef CGEN_PRINT_NORMAL
446   CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
447 #endif
448
449   /* Print the operand as directed by the attributes.  */
450   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
451     ; /* nothing to do */
452   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
453     (*info->fprintf_func) (info->stream, "%ld", value);
454   else
455     (*info->fprintf_func) (info->stream, "0x%lx", value);
456 }
457
458 /* Default address handler.  */
459
460 static void
461 print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
462                void *dis_info,
463                bfd_vma value,
464                unsigned int attrs,
465                bfd_vma pc ATTRIBUTE_UNUSED,
466                int length ATTRIBUTE_UNUSED)
467 {
468   disassemble_info *info = (disassemble_info *) dis_info;
469
470 #ifdef CGEN_PRINT_ADDRESS
471   CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
472 #endif
473
474   /* Print the operand as directed by the attributes.  */
475   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
476     ; /* nothing to do */
477   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
478     (*info->print_address_func) (value, info);
479   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
480     (*info->print_address_func) (value, info);
481   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
482     (*info->fprintf_func) (info->stream, "%ld", (long) value);
483   else
484     (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
485 }
486
487 /* Keyword print handler.  */
488
489 static void
490 print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
491                void *dis_info,
492                CGEN_KEYWORD *keyword_table,
493                long value,
494                unsigned int attrs ATTRIBUTE_UNUSED)
495 {
496   disassemble_info *info = (disassemble_info *) dis_info;
497   const CGEN_KEYWORD_ENTRY *ke;
498
499   ke = cgen_keyword_lookup_value (keyword_table, value);
500   if (ke != NULL)
501     (*info->fprintf_func) (info->stream, "%s", ke->name);
502   else
503     (*info->fprintf_func) (info->stream, "???");
504 }
505 \f
506 /* Default insn printer.
507
508    DIS_INFO is defined as `void *' so the disassembler needn't know anything
509    about disassemble_info.  */
510
511 static void
512 print_insn_normal (CGEN_CPU_DESC cd,
513                    void *dis_info,
514                    const CGEN_INSN *insn,
515                    CGEN_FIELDS *fields,
516                    bfd_vma pc,
517                    int length)
518 {
519   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
520   disassemble_info *info = (disassemble_info *) dis_info;
521   const CGEN_SYNTAX_CHAR_TYPE *syn;
522
523   CGEN_INIT_PRINT (cd);
524
525   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
526     {
527       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
528         {
529           (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
530           continue;
531         }
532       if (CGEN_SYNTAX_CHAR_P (*syn))
533         {
534           (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
535           continue;
536         }
537
538       /* We have an operand.  */
539       frv_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
540                                  fields, CGEN_INSN_ATTRS (insn), pc, length);
541     }
542 }
543 \f
544 /* Subroutine of print_insn. Reads an insn into the given buffers and updates
545    the extract info.
546    Returns 0 if all is well, non-zero otherwise.  */
547
548 static int
549 read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
550            bfd_vma pc,
551            disassemble_info *info,
552            char *buf,
553            int buflen,
554            CGEN_EXTRACT_INFO *ex_info,
555            unsigned long *insn_value)
556 {
557   int status = (*info->read_memory_func) (pc, buf, buflen, info);
558   if (status != 0)
559     {
560       (*info->memory_error_func) (status, pc, info);
561       return -1;
562     }
563
564   ex_info->dis_info = info;
565   ex_info->valid = (1 << buflen) - 1;
566   ex_info->insn_bytes = buf;
567
568   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
569   return 0;
570 }
571
572 /* Utility to print an insn.
573    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
574    The result is the size of the insn in bytes or zero for an unknown insn
575    or -1 if an error occurs fetching data (memory_error_func will have
576    been called).  */
577
578 static int
579 print_insn (CGEN_CPU_DESC cd,
580             bfd_vma pc,
581             disassemble_info *info,
582             char *buf,
583             unsigned int buflen)
584 {
585   CGEN_INSN_INT insn_value;
586   const CGEN_INSN_LIST *insn_list;
587   CGEN_EXTRACT_INFO ex_info;
588   int basesize;
589
590   /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
591   basesize = cd->base_insn_bitsize < buflen * 8 ?
592                                      cd->base_insn_bitsize : buflen * 8;
593   insn_value = cgen_get_insn_value (cd, buf, basesize);
594
595
596   /* Fill in ex_info fields like read_insn would.  Don't actually call
597      read_insn, since the incoming buffer is already read (and possibly
598      modified a la m32r).  */
599   ex_info.valid = (1 << buflen) - 1;
600   ex_info.dis_info = info;
601   ex_info.insn_bytes = buf;
602
603   /* The instructions are stored in hash lists.
604      Pick the first one and keep trying until we find the right one.  */
605
606   insn_list = CGEN_DIS_LOOKUP_INSN (cd, buf, insn_value);
607   while (insn_list != NULL)
608     {
609       const CGEN_INSN *insn = insn_list->insn;
610       CGEN_FIELDS fields;
611       int length;
612       unsigned long insn_value_cropped;
613
614 #ifdef CGEN_VALIDATE_INSN_SUPPORTED 
615       /* Not needed as insn shouldn't be in hash lists if not supported.  */
616       /* Supported by this cpu?  */
617       if (! frv_cgen_insn_supported (cd, insn))
618         {
619           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
620           continue;
621         }
622 #endif
623
624       /* Basic bit mask must be correct.  */
625       /* ??? May wish to allow target to defer this check until the extract
626          handler.  */
627
628       /* Base size may exceed this instruction's size.  Extract the
629          relevant part from the buffer. */
630       if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
631           (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
632         insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn), 
633                                            info->endian == BFD_ENDIAN_BIG);
634       else
635         insn_value_cropped = insn_value;
636
637       if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
638           == CGEN_INSN_BASE_VALUE (insn))
639         {
640           /* Printing is handled in two passes.  The first pass parses the
641              machine insn and extracts the fields.  The second pass prints
642              them.  */
643
644           /* Make sure the entire insn is loaded into insn_value, if it
645              can fit.  */
646           if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
647               (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
648             {
649               unsigned long full_insn_value;
650               int rc = read_insn (cd, pc, info, buf,
651                                   CGEN_INSN_BITSIZE (insn) / 8,
652                                   & ex_info, & full_insn_value);
653               if (rc != 0)
654                 return rc;
655               length = CGEN_EXTRACT_FN (cd, insn)
656                 (cd, insn, &ex_info, full_insn_value, &fields, pc);
657             }
658           else
659             length = CGEN_EXTRACT_FN (cd, insn)
660               (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
661
662           /* length < 0 -> error */
663           if (length < 0)
664             return length;
665           if (length > 0)
666             {
667               CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
668               /* length is in bits, result is in bytes */
669               return length / 8;
670             }
671         }
672
673       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
674     }
675
676   return 0;
677 }
678
679 /* Default value for CGEN_PRINT_INSN.
680    The result is the size of the insn in bytes or zero for an unknown insn
681    or -1 if an error occured fetching bytes.  */
682
683 #ifndef CGEN_PRINT_INSN
684 #define CGEN_PRINT_INSN default_print_insn
685 #endif
686
687 static int
688 default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
689 {
690   char buf[CGEN_MAX_INSN_SIZE];
691   int buflen;
692   int status;
693
694   /* Attempt to read the base part of the insn.  */
695   buflen = cd->base_insn_bitsize / 8;
696   status = (*info->read_memory_func) (pc, buf, buflen, info);
697
698   /* Try again with the minimum part, if min < base.  */
699   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
700     {
701       buflen = cd->min_insn_bitsize / 8;
702       status = (*info->read_memory_func) (pc, buf, buflen, info);
703     }
704
705   if (status != 0)
706     {
707       (*info->memory_error_func) (status, pc, info);
708       return -1;
709     }
710
711   return print_insn (cd, pc, info, buf, buflen);
712 }
713
714 /* Main entry point.
715    Print one instruction from PC on INFO->STREAM.
716    Return the size of the instruction (in bytes).  */
717
718 typedef struct cpu_desc_list {
719   struct cpu_desc_list *next;
720   int isa;
721   int mach;
722   int endian;
723   CGEN_CPU_DESC cd;
724 } cpu_desc_list;
725
726 int
727 print_insn_frv (bfd_vma pc, disassemble_info *info)
728 {
729   static cpu_desc_list *cd_list = 0;
730   cpu_desc_list *cl = 0;
731   static CGEN_CPU_DESC cd = 0;
732   static int prev_isa;
733   static int prev_mach;
734   static int prev_endian;
735   int length;
736   int isa,mach;
737   int endian = (info->endian == BFD_ENDIAN_BIG
738                 ? CGEN_ENDIAN_BIG
739                 : CGEN_ENDIAN_LITTLE);
740   enum bfd_architecture arch;
741
742   /* ??? gdb will set mach but leave the architecture as "unknown" */
743 #ifndef CGEN_BFD_ARCH
744 #define CGEN_BFD_ARCH bfd_arch_frv
745 #endif
746   arch = info->arch;
747   if (arch == bfd_arch_unknown)
748     arch = CGEN_BFD_ARCH;
749    
750   /* There's no standard way to compute the machine or isa number
751      so we leave it to the target.  */
752 #ifdef CGEN_COMPUTE_MACH
753   mach = CGEN_COMPUTE_MACH (info);
754 #else
755   mach = info->mach;
756 #endif
757
758 #ifdef CGEN_COMPUTE_ISA
759   isa = CGEN_COMPUTE_ISA (info);
760 #else
761   isa = info->insn_sets;
762 #endif
763
764   /* If we've switched cpu's, try to find a handle we've used before */
765   if (cd
766       && (isa != prev_isa
767           || mach != prev_mach
768           || endian != prev_endian))
769     {
770       cd = 0;
771       for (cl = cd_list; cl; cl = cl->next)
772         {
773           if (cl->isa == isa &&
774               cl->mach == mach &&
775               cl->endian == endian)
776             {
777               cd = cl->cd;
778               break;
779             }
780         }
781     } 
782
783   /* If we haven't initialized yet, initialize the opcode table.  */
784   if (! cd)
785     {
786       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
787       const char *mach_name;
788
789       if (!arch_type)
790         abort ();
791       mach_name = arch_type->printable_name;
792
793       prev_isa = isa;
794       prev_mach = mach;
795       prev_endian = endian;
796       cd = frv_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
797                                  CGEN_CPU_OPEN_BFDMACH, mach_name,
798                                  CGEN_CPU_OPEN_ENDIAN, prev_endian,
799                                  CGEN_CPU_OPEN_END);
800       if (!cd)
801         abort ();
802
803       /* save this away for future reference */
804       cl = xmalloc (sizeof (struct cpu_desc_list));
805       cl->cd = cd;
806       cl->isa = isa;
807       cl->mach = mach;
808       cl->endian = endian;
809       cl->next = cd_list;
810       cd_list = cl;
811
812       frv_cgen_init_dis (cd);
813     }
814
815   /* We try to have as much common code as possible.
816      But at this point some targets need to take over.  */
817   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
818      but if not possible try to move this hook elsewhere rather than
819      have two hooks.  */
820   length = CGEN_PRINT_INSN (cd, pc, info);
821   if (length > 0)
822     return length;
823   if (length < 0)
824     return -1;
825
826   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
827   return cd->default_insn_bitsize / 8;
828 }