xref: /openbsd-src/gnu/usr.bin/binutils/opcodes/iq2000-dis.c (revision cf2f2c5620d6d9a4fd01930983c4b9a1f76d7aa3)
1d2201f2fSdrahn /* Disassembler interface for targets using CGEN. -*- C -*-
2d2201f2fSdrahn    CGEN: Cpu tools GENerator
3d2201f2fSdrahn 
4d2201f2fSdrahn THIS FILE IS MACHINE GENERATED WITH CGEN.
5d2201f2fSdrahn - the resultant file is machine generated, cgen-dis.in isn't
6d2201f2fSdrahn 
7*cf2f2c56Smiod Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002
8*cf2f2c56Smiod Free Software Foundation, Inc.
9d2201f2fSdrahn 
10d2201f2fSdrahn This file is part of the GNU Binutils and GDB, the GNU debugger.
11d2201f2fSdrahn 
12d2201f2fSdrahn This program is free software; you can redistribute it and/or modify
13d2201f2fSdrahn it under the terms of the GNU General Public License as published by
14d2201f2fSdrahn the Free Software Foundation; either version 2, or (at your option)
15d2201f2fSdrahn any later version.
16d2201f2fSdrahn 
17d2201f2fSdrahn This program is distributed in the hope that it will be useful,
18d2201f2fSdrahn but WITHOUT ANY WARRANTY; without even the implied warranty of
19d2201f2fSdrahn MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20d2201f2fSdrahn GNU General Public License for more details.
21d2201f2fSdrahn 
22d2201f2fSdrahn You should have received a copy of the GNU General Public License
23d2201f2fSdrahn along with this program; if not, write to the Free Software Foundation, Inc.,
24d2201f2fSdrahn 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
25d2201f2fSdrahn 
26d2201f2fSdrahn /* ??? Eventually more and more of this stuff can go to cpu-independent files.
27d2201f2fSdrahn    Keep that in mind.  */
28d2201f2fSdrahn 
29d2201f2fSdrahn #include "sysdep.h"
30d2201f2fSdrahn #include <stdio.h>
31d2201f2fSdrahn #include "ansidecl.h"
32d2201f2fSdrahn #include "dis-asm.h"
33d2201f2fSdrahn #include "bfd.h"
34d2201f2fSdrahn #include "symcat.h"
35*cf2f2c56Smiod #include "libiberty.h"
36d2201f2fSdrahn #include "iq2000-desc.h"
37d2201f2fSdrahn #include "iq2000-opc.h"
38d2201f2fSdrahn #include "opintl.h"
39d2201f2fSdrahn 
40d2201f2fSdrahn /* Default text to print if an instruction isn't recognized.  */
41d2201f2fSdrahn #define UNKNOWN_INSN_MSG _("*unknown*")
42d2201f2fSdrahn 
43d2201f2fSdrahn static void print_normal
44*cf2f2c56Smiod   (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
45d2201f2fSdrahn static void print_address
46*cf2f2c56Smiod   (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int);
47d2201f2fSdrahn static void print_keyword
48*cf2f2c56Smiod   (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int);
49d2201f2fSdrahn static void print_insn_normal
50*cf2f2c56Smiod   (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
51d2201f2fSdrahn static int print_insn
52*cf2f2c56Smiod   (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, char *, unsigned);
53d2201f2fSdrahn static int default_print_insn
54*cf2f2c56Smiod   (CGEN_CPU_DESC, bfd_vma, disassemble_info *);
55d2201f2fSdrahn static int read_insn
56*cf2f2c56Smiod   (CGEN_CPU_DESC, bfd_vma, disassemble_info *, char *, int, CGEN_EXTRACT_INFO *,
57*cf2f2c56Smiod    unsigned long *);
58d2201f2fSdrahn 
59d2201f2fSdrahn /* -- disassembler routines inserted here */
60d2201f2fSdrahn 
61d2201f2fSdrahn 
62d2201f2fSdrahn void iq2000_cgen_print_operand
63d2201f2fSdrahn   PARAMS ((CGEN_CPU_DESC, int, PTR, CGEN_FIELDS *,
64d2201f2fSdrahn            void const *, bfd_vma, int));
65d2201f2fSdrahn 
66d2201f2fSdrahn /* Main entry point for printing operands.
67d2201f2fSdrahn    XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
68d2201f2fSdrahn    of dis-asm.h on cgen.h.
69d2201f2fSdrahn 
70d2201f2fSdrahn    This function is basically just a big switch statement.  Earlier versions
71d2201f2fSdrahn    used tables to look up the function to use, but
72d2201f2fSdrahn    - if the table contains both assembler and disassembler functions then
73d2201f2fSdrahn      the disassembler contains much of the assembler and vice-versa,
74d2201f2fSdrahn    - there's a lot of inlining possibilities as things grow,
75d2201f2fSdrahn    - using a switch statement avoids the function call overhead.
76d2201f2fSdrahn 
77d2201f2fSdrahn    This function could be moved into `print_insn_normal', but keeping it
78d2201f2fSdrahn    separate makes clear the interface between `print_insn_normal' and each of
79d2201f2fSdrahn    the handlers.  */
80d2201f2fSdrahn 
81d2201f2fSdrahn void
iq2000_cgen_print_operand(cd,opindex,xinfo,fields,attrs,pc,length)82d2201f2fSdrahn iq2000_cgen_print_operand (cd, opindex, xinfo, fields, attrs, pc, length)
83d2201f2fSdrahn      CGEN_CPU_DESC cd;
84d2201f2fSdrahn      int opindex;
85d2201f2fSdrahn      PTR xinfo;
86d2201f2fSdrahn      CGEN_FIELDS *fields;
87d2201f2fSdrahn      void const *attrs ATTRIBUTE_UNUSED;
88d2201f2fSdrahn      bfd_vma pc;
89d2201f2fSdrahn      int length;
90d2201f2fSdrahn {
91d2201f2fSdrahn  disassemble_info *info = (disassemble_info *) xinfo;
92d2201f2fSdrahn 
93d2201f2fSdrahn   switch (opindex)
94d2201f2fSdrahn     {
95d2201f2fSdrahn     case IQ2000_OPERAND_BASE :
96d2201f2fSdrahn       print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rs, 0);
97d2201f2fSdrahn       break;
98d2201f2fSdrahn     case IQ2000_OPERAND_BASEOFF :
99d2201f2fSdrahn       print_address (cd, info, fields->f_imm, 0, pc, length);
100d2201f2fSdrahn       break;
101d2201f2fSdrahn     case IQ2000_OPERAND_BITNUM :
102d2201f2fSdrahn       print_normal (cd, info, fields->f_rt, 0, pc, length);
103d2201f2fSdrahn       break;
104d2201f2fSdrahn     case IQ2000_OPERAND_BYTECOUNT :
105d2201f2fSdrahn       print_normal (cd, info, fields->f_bytecount, 0, pc, length);
106d2201f2fSdrahn       break;
107d2201f2fSdrahn     case IQ2000_OPERAND_CAM_Y :
108d2201f2fSdrahn       print_normal (cd, info, fields->f_cam_y, 0, pc, length);
109d2201f2fSdrahn       break;
110d2201f2fSdrahn     case IQ2000_OPERAND_CAM_Z :
111d2201f2fSdrahn       print_normal (cd, info, fields->f_cam_z, 0, pc, length);
112d2201f2fSdrahn       break;
113d2201f2fSdrahn     case IQ2000_OPERAND_CM_3FUNC :
114d2201f2fSdrahn       print_normal (cd, info, fields->f_cm_3func, 0, pc, length);
115d2201f2fSdrahn       break;
116d2201f2fSdrahn     case IQ2000_OPERAND_CM_3Z :
117d2201f2fSdrahn       print_normal (cd, info, fields->f_cm_3z, 0, pc, length);
118d2201f2fSdrahn       break;
119d2201f2fSdrahn     case IQ2000_OPERAND_CM_4FUNC :
120d2201f2fSdrahn       print_normal (cd, info, fields->f_cm_4func, 0, pc, length);
121d2201f2fSdrahn       break;
122d2201f2fSdrahn     case IQ2000_OPERAND_CM_4Z :
123d2201f2fSdrahn       print_normal (cd, info, fields->f_cm_4z, 0, pc, length);
124d2201f2fSdrahn       break;
125d2201f2fSdrahn     case IQ2000_OPERAND_COUNT :
126d2201f2fSdrahn       print_normal (cd, info, fields->f_count, 0, pc, length);
127d2201f2fSdrahn       break;
128d2201f2fSdrahn     case IQ2000_OPERAND_EXECODE :
129d2201f2fSdrahn       print_normal (cd, info, fields->f_excode, 0, pc, length);
130d2201f2fSdrahn       break;
131*cf2f2c56Smiod     case IQ2000_OPERAND_F_INDEX :
132*cf2f2c56Smiod       print_normal (cd, info, fields->f_index, 0, pc, length);
133*cf2f2c56Smiod       break;
134d2201f2fSdrahn     case IQ2000_OPERAND_HI16 :
135d2201f2fSdrahn       print_normal (cd, info, fields->f_imm, 0, pc, length);
136d2201f2fSdrahn       break;
137d2201f2fSdrahn     case IQ2000_OPERAND_IMM :
138d2201f2fSdrahn       print_normal (cd, info, fields->f_imm, 0, pc, length);
139d2201f2fSdrahn       break;
140d2201f2fSdrahn     case IQ2000_OPERAND_JMPTARG :
141d2201f2fSdrahn       print_address (cd, info, fields->f_jtarg, 0|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
142d2201f2fSdrahn       break;
143d2201f2fSdrahn     case IQ2000_OPERAND_JMPTARGQ10 :
144d2201f2fSdrahn       print_address (cd, info, fields->f_jtargq10, 0|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
145d2201f2fSdrahn       break;
146d2201f2fSdrahn     case IQ2000_OPERAND_LO16 :
147d2201f2fSdrahn       print_normal (cd, info, fields->f_imm, 0, pc, length);
148d2201f2fSdrahn       break;
149d2201f2fSdrahn     case IQ2000_OPERAND_MASK :
150d2201f2fSdrahn       print_normal (cd, info, fields->f_mask, 0, pc, length);
151d2201f2fSdrahn       break;
152d2201f2fSdrahn     case IQ2000_OPERAND_MASKL :
153d2201f2fSdrahn       print_normal (cd, info, fields->f_maskl, 0, pc, length);
154d2201f2fSdrahn       break;
155d2201f2fSdrahn     case IQ2000_OPERAND_MASKQ10 :
156d2201f2fSdrahn       print_normal (cd, info, fields->f_maskq10, 0, pc, length);
157d2201f2fSdrahn       break;
158d2201f2fSdrahn     case IQ2000_OPERAND_MASKR :
159d2201f2fSdrahn       print_normal (cd, info, fields->f_rs, 0, pc, length);
160d2201f2fSdrahn       break;
161d2201f2fSdrahn     case IQ2000_OPERAND_MLO16 :
162d2201f2fSdrahn       print_normal (cd, info, fields->f_imm, 0, pc, length);
163d2201f2fSdrahn       break;
164d2201f2fSdrahn     case IQ2000_OPERAND_OFFSET :
165d2201f2fSdrahn       print_address (cd, info, fields->f_offset, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
166d2201f2fSdrahn       break;
167d2201f2fSdrahn     case IQ2000_OPERAND_RD :
168d2201f2fSdrahn       print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rd, 0);
169d2201f2fSdrahn       break;
170d2201f2fSdrahn     case IQ2000_OPERAND_RD_RS :
171d2201f2fSdrahn       print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rd_rs, 0|(1<<CGEN_OPERAND_VIRTUAL));
172d2201f2fSdrahn       break;
173d2201f2fSdrahn     case IQ2000_OPERAND_RD_RT :
174d2201f2fSdrahn       print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rd_rt, 0|(1<<CGEN_OPERAND_VIRTUAL));
175d2201f2fSdrahn       break;
176d2201f2fSdrahn     case IQ2000_OPERAND_RS :
177d2201f2fSdrahn       print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rs, 0);
178d2201f2fSdrahn       break;
179d2201f2fSdrahn     case IQ2000_OPERAND_RT :
180d2201f2fSdrahn       print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rt, 0);
181d2201f2fSdrahn       break;
182d2201f2fSdrahn     case IQ2000_OPERAND_RT_RS :
183d2201f2fSdrahn       print_keyword (cd, info, & iq2000_cgen_opval_gr_names, fields->f_rt_rs, 0|(1<<CGEN_OPERAND_VIRTUAL));
184d2201f2fSdrahn       break;
185d2201f2fSdrahn     case IQ2000_OPERAND_SHAMT :
186d2201f2fSdrahn       print_normal (cd, info, fields->f_shamt, 0, pc, length);
187d2201f2fSdrahn       break;
188d2201f2fSdrahn 
189d2201f2fSdrahn     default :
190d2201f2fSdrahn       /* xgettext:c-format */
191d2201f2fSdrahn       fprintf (stderr, _("Unrecognized field %d while printing insn.\n"),
192d2201f2fSdrahn 	       opindex);
193d2201f2fSdrahn     abort ();
194d2201f2fSdrahn   }
195d2201f2fSdrahn }
196d2201f2fSdrahn 
197d2201f2fSdrahn cgen_print_fn * const iq2000_cgen_print_handlers[] =
198d2201f2fSdrahn {
199d2201f2fSdrahn   print_insn_normal,
200d2201f2fSdrahn };
201d2201f2fSdrahn 
202d2201f2fSdrahn 
203d2201f2fSdrahn void
iq2000_cgen_init_dis(cd)204d2201f2fSdrahn iq2000_cgen_init_dis (cd)
205d2201f2fSdrahn      CGEN_CPU_DESC cd;
206d2201f2fSdrahn {
207d2201f2fSdrahn   iq2000_cgen_init_opcode_table (cd);
208d2201f2fSdrahn   iq2000_cgen_init_ibld_table (cd);
209d2201f2fSdrahn   cd->print_handlers = & iq2000_cgen_print_handlers[0];
210d2201f2fSdrahn   cd->print_operand = iq2000_cgen_print_operand;
211d2201f2fSdrahn }
212d2201f2fSdrahn 
213d2201f2fSdrahn 
214d2201f2fSdrahn /* Default print handler.  */
215d2201f2fSdrahn 
216d2201f2fSdrahn static void
print_normal(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,long value,unsigned int attrs,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)217*cf2f2c56Smiod print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
218*cf2f2c56Smiod 	      void *dis_info,
219*cf2f2c56Smiod 	      long value,
220*cf2f2c56Smiod 	      unsigned int attrs,
221*cf2f2c56Smiod 	      bfd_vma pc ATTRIBUTE_UNUSED,
222*cf2f2c56Smiod 	      int length ATTRIBUTE_UNUSED)
223d2201f2fSdrahn {
224d2201f2fSdrahn   disassemble_info *info = (disassemble_info *) dis_info;
225d2201f2fSdrahn 
226d2201f2fSdrahn #ifdef CGEN_PRINT_NORMAL
227d2201f2fSdrahn   CGEN_PRINT_NORMAL (cd, info, value, attrs, pc, length);
228d2201f2fSdrahn #endif
229d2201f2fSdrahn 
230d2201f2fSdrahn   /* Print the operand as directed by the attributes.  */
231d2201f2fSdrahn   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
232d2201f2fSdrahn     ; /* nothing to do */
233d2201f2fSdrahn   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
234d2201f2fSdrahn     (*info->fprintf_func) (info->stream, "%ld", value);
235d2201f2fSdrahn   else
236d2201f2fSdrahn     (*info->fprintf_func) (info->stream, "0x%lx", value);
237d2201f2fSdrahn }
238d2201f2fSdrahn 
239d2201f2fSdrahn /* Default address handler.  */
240d2201f2fSdrahn 
241d2201f2fSdrahn static void
print_address(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,bfd_vma value,unsigned int attrs,bfd_vma pc ATTRIBUTE_UNUSED,int length ATTRIBUTE_UNUSED)242*cf2f2c56Smiod print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
243*cf2f2c56Smiod 	       void *dis_info,
244*cf2f2c56Smiod 	       bfd_vma value,
245*cf2f2c56Smiod 	       unsigned int attrs,
246*cf2f2c56Smiod 	       bfd_vma pc ATTRIBUTE_UNUSED,
247*cf2f2c56Smiod 	       int length ATTRIBUTE_UNUSED)
248d2201f2fSdrahn {
249d2201f2fSdrahn   disassemble_info *info = (disassemble_info *) dis_info;
250d2201f2fSdrahn 
251d2201f2fSdrahn #ifdef CGEN_PRINT_ADDRESS
252d2201f2fSdrahn   CGEN_PRINT_ADDRESS (cd, info, value, attrs, pc, length);
253d2201f2fSdrahn #endif
254d2201f2fSdrahn 
255d2201f2fSdrahn   /* Print the operand as directed by the attributes.  */
256d2201f2fSdrahn   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
257d2201f2fSdrahn     ; /* nothing to do */
258d2201f2fSdrahn   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
259d2201f2fSdrahn     (*info->print_address_func) (value, info);
260d2201f2fSdrahn   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
261d2201f2fSdrahn     (*info->print_address_func) (value, info);
262d2201f2fSdrahn   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
263d2201f2fSdrahn     (*info->fprintf_func) (info->stream, "%ld", (long) value);
264d2201f2fSdrahn   else
265d2201f2fSdrahn     (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
266d2201f2fSdrahn }
267d2201f2fSdrahn 
268d2201f2fSdrahn /* Keyword print handler.  */
269d2201f2fSdrahn 
270d2201f2fSdrahn static void
print_keyword(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,CGEN_KEYWORD * keyword_table,long value,unsigned int attrs ATTRIBUTE_UNUSED)271*cf2f2c56Smiod print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
272*cf2f2c56Smiod 	       void *dis_info,
273*cf2f2c56Smiod 	       CGEN_KEYWORD *keyword_table,
274*cf2f2c56Smiod 	       long value,
275*cf2f2c56Smiod 	       unsigned int attrs ATTRIBUTE_UNUSED)
276d2201f2fSdrahn {
277d2201f2fSdrahn   disassemble_info *info = (disassemble_info *) dis_info;
278d2201f2fSdrahn   const CGEN_KEYWORD_ENTRY *ke;
279d2201f2fSdrahn 
280d2201f2fSdrahn   ke = cgen_keyword_lookup_value (keyword_table, value);
281d2201f2fSdrahn   if (ke != NULL)
282d2201f2fSdrahn     (*info->fprintf_func) (info->stream, "%s", ke->name);
283d2201f2fSdrahn   else
284d2201f2fSdrahn     (*info->fprintf_func) (info->stream, "???");
285d2201f2fSdrahn }
286d2201f2fSdrahn 
287d2201f2fSdrahn /* Default insn printer.
288d2201f2fSdrahn 
289*cf2f2c56Smiod    DIS_INFO is defined as `void *' so the disassembler needn't know anything
290d2201f2fSdrahn    about disassemble_info.  */
291d2201f2fSdrahn 
292d2201f2fSdrahn static void
print_insn_normal(CGEN_CPU_DESC cd,void * dis_info,const CGEN_INSN * insn,CGEN_FIELDS * fields,bfd_vma pc,int length)293*cf2f2c56Smiod print_insn_normal (CGEN_CPU_DESC cd,
294*cf2f2c56Smiod 		   void *dis_info,
295*cf2f2c56Smiod 		   const CGEN_INSN *insn,
296*cf2f2c56Smiod 		   CGEN_FIELDS *fields,
297*cf2f2c56Smiod 		   bfd_vma pc,
298*cf2f2c56Smiod 		   int length)
299d2201f2fSdrahn {
300d2201f2fSdrahn   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
301d2201f2fSdrahn   disassemble_info *info = (disassemble_info *) dis_info;
302d2201f2fSdrahn   const CGEN_SYNTAX_CHAR_TYPE *syn;
303d2201f2fSdrahn 
304d2201f2fSdrahn   CGEN_INIT_PRINT (cd);
305d2201f2fSdrahn 
306d2201f2fSdrahn   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
307d2201f2fSdrahn     {
308d2201f2fSdrahn       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
309d2201f2fSdrahn 	{
310d2201f2fSdrahn 	  (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
311d2201f2fSdrahn 	  continue;
312d2201f2fSdrahn 	}
313d2201f2fSdrahn       if (CGEN_SYNTAX_CHAR_P (*syn))
314d2201f2fSdrahn 	{
315d2201f2fSdrahn 	  (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
316d2201f2fSdrahn 	  continue;
317d2201f2fSdrahn 	}
318d2201f2fSdrahn 
319d2201f2fSdrahn       /* We have an operand.  */
320d2201f2fSdrahn       iq2000_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
321d2201f2fSdrahn 				 fields, CGEN_INSN_ATTRS (insn), pc, length);
322d2201f2fSdrahn     }
323d2201f2fSdrahn }
324d2201f2fSdrahn 
325d2201f2fSdrahn /* Subroutine of print_insn. Reads an insn into the given buffers and updates
326d2201f2fSdrahn    the extract info.
327d2201f2fSdrahn    Returns 0 if all is well, non-zero otherwise.  */
328d2201f2fSdrahn 
329d2201f2fSdrahn static int
read_insn(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,bfd_vma pc,disassemble_info * info,char * buf,int buflen,CGEN_EXTRACT_INFO * ex_info,unsigned long * insn_value)330*cf2f2c56Smiod read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
331*cf2f2c56Smiod 	   bfd_vma pc,
332*cf2f2c56Smiod 	   disassemble_info *info,
333*cf2f2c56Smiod 	   char *buf,
334*cf2f2c56Smiod 	   int buflen,
335*cf2f2c56Smiod 	   CGEN_EXTRACT_INFO *ex_info,
336*cf2f2c56Smiod 	   unsigned long *insn_value)
337d2201f2fSdrahn {
338d2201f2fSdrahn   int status = (*info->read_memory_func) (pc, buf, buflen, info);
339d2201f2fSdrahn   if (status != 0)
340d2201f2fSdrahn     {
341d2201f2fSdrahn       (*info->memory_error_func) (status, pc, info);
342d2201f2fSdrahn       return -1;
343d2201f2fSdrahn     }
344d2201f2fSdrahn 
345d2201f2fSdrahn   ex_info->dis_info = info;
346d2201f2fSdrahn   ex_info->valid = (1 << buflen) - 1;
347d2201f2fSdrahn   ex_info->insn_bytes = buf;
348d2201f2fSdrahn 
349d2201f2fSdrahn   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
350d2201f2fSdrahn   return 0;
351d2201f2fSdrahn }
352d2201f2fSdrahn 
353d2201f2fSdrahn /* Utility to print an insn.
354d2201f2fSdrahn    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
355d2201f2fSdrahn    The result is the size of the insn in bytes or zero for an unknown insn
356d2201f2fSdrahn    or -1 if an error occurs fetching data (memory_error_func will have
357d2201f2fSdrahn    been called).  */
358d2201f2fSdrahn 
359d2201f2fSdrahn static int
print_insn(CGEN_CPU_DESC cd,bfd_vma pc,disassemble_info * info,char * buf,unsigned int buflen)360*cf2f2c56Smiod print_insn (CGEN_CPU_DESC cd,
361*cf2f2c56Smiod 	    bfd_vma pc,
362*cf2f2c56Smiod 	    disassemble_info *info,
363*cf2f2c56Smiod 	    char *buf,
364*cf2f2c56Smiod 	    unsigned int buflen)
365d2201f2fSdrahn {
366d2201f2fSdrahn   CGEN_INSN_INT insn_value;
367d2201f2fSdrahn   const CGEN_INSN_LIST *insn_list;
368d2201f2fSdrahn   CGEN_EXTRACT_INFO ex_info;
369d2201f2fSdrahn   int basesize;
370d2201f2fSdrahn 
371d2201f2fSdrahn   /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
372d2201f2fSdrahn   basesize = cd->base_insn_bitsize < buflen * 8 ?
373d2201f2fSdrahn                                      cd->base_insn_bitsize : buflen * 8;
374d2201f2fSdrahn   insn_value = cgen_get_insn_value (cd, buf, basesize);
375d2201f2fSdrahn 
376d2201f2fSdrahn 
377d2201f2fSdrahn   /* Fill in ex_info fields like read_insn would.  Don't actually call
378d2201f2fSdrahn      read_insn, since the incoming buffer is already read (and possibly
379d2201f2fSdrahn      modified a la m32r).  */
380d2201f2fSdrahn   ex_info.valid = (1 << buflen) - 1;
381d2201f2fSdrahn   ex_info.dis_info = info;
382d2201f2fSdrahn   ex_info.insn_bytes = buf;
383d2201f2fSdrahn 
384d2201f2fSdrahn   /* The instructions are stored in hash lists.
385d2201f2fSdrahn      Pick the first one and keep trying until we find the right one.  */
386d2201f2fSdrahn 
387d2201f2fSdrahn   insn_list = CGEN_DIS_LOOKUP_INSN (cd, buf, insn_value);
388d2201f2fSdrahn   while (insn_list != NULL)
389d2201f2fSdrahn     {
390d2201f2fSdrahn       const CGEN_INSN *insn = insn_list->insn;
391d2201f2fSdrahn       CGEN_FIELDS fields;
392d2201f2fSdrahn       int length;
393d2201f2fSdrahn       unsigned long insn_value_cropped;
394d2201f2fSdrahn 
395d2201f2fSdrahn #ifdef CGEN_VALIDATE_INSN_SUPPORTED
396d2201f2fSdrahn       /* Not needed as insn shouldn't be in hash lists if not supported.  */
397d2201f2fSdrahn       /* Supported by this cpu?  */
398d2201f2fSdrahn       if (! iq2000_cgen_insn_supported (cd, insn))
399d2201f2fSdrahn         {
400d2201f2fSdrahn           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
401d2201f2fSdrahn 	  continue;
402d2201f2fSdrahn         }
403d2201f2fSdrahn #endif
404d2201f2fSdrahn 
405d2201f2fSdrahn       /* Basic bit mask must be correct.  */
406d2201f2fSdrahn       /* ??? May wish to allow target to defer this check until the extract
407d2201f2fSdrahn 	 handler.  */
408d2201f2fSdrahn 
409d2201f2fSdrahn       /* Base size may exceed this instruction's size.  Extract the
410d2201f2fSdrahn          relevant part from the buffer. */
411d2201f2fSdrahn       if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
412d2201f2fSdrahn 	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
413d2201f2fSdrahn 	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
414d2201f2fSdrahn 					   info->endian == BFD_ENDIAN_BIG);
415d2201f2fSdrahn       else
416d2201f2fSdrahn 	insn_value_cropped = insn_value;
417d2201f2fSdrahn 
418d2201f2fSdrahn       if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
419d2201f2fSdrahn 	  == CGEN_INSN_BASE_VALUE (insn))
420d2201f2fSdrahn 	{
421d2201f2fSdrahn 	  /* Printing is handled in two passes.  The first pass parses the
422d2201f2fSdrahn 	     machine insn and extracts the fields.  The second pass prints
423d2201f2fSdrahn 	     them.  */
424d2201f2fSdrahn 
425d2201f2fSdrahn 	  /* Make sure the entire insn is loaded into insn_value, if it
426d2201f2fSdrahn 	     can fit.  */
427d2201f2fSdrahn 	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
428d2201f2fSdrahn 	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
429d2201f2fSdrahn 	    {
430d2201f2fSdrahn 	      unsigned long full_insn_value;
431d2201f2fSdrahn 	      int rc = read_insn (cd, pc, info, buf,
432d2201f2fSdrahn 				  CGEN_INSN_BITSIZE (insn) / 8,
433d2201f2fSdrahn 				  & ex_info, & full_insn_value);
434d2201f2fSdrahn 	      if (rc != 0)
435d2201f2fSdrahn 		return rc;
436d2201f2fSdrahn 	      length = CGEN_EXTRACT_FN (cd, insn)
437d2201f2fSdrahn 		(cd, insn, &ex_info, full_insn_value, &fields, pc);
438d2201f2fSdrahn 	    }
439d2201f2fSdrahn 	  else
440d2201f2fSdrahn 	    length = CGEN_EXTRACT_FN (cd, insn)
441d2201f2fSdrahn 	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
442d2201f2fSdrahn 
443d2201f2fSdrahn 	  /* length < 0 -> error */
444d2201f2fSdrahn 	  if (length < 0)
445d2201f2fSdrahn 	    return length;
446d2201f2fSdrahn 	  if (length > 0)
447d2201f2fSdrahn 	    {
448d2201f2fSdrahn 	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
449d2201f2fSdrahn 	      /* length is in bits, result is in bytes */
450d2201f2fSdrahn 	      return length / 8;
451d2201f2fSdrahn 	    }
452d2201f2fSdrahn 	}
453d2201f2fSdrahn 
454d2201f2fSdrahn       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
455d2201f2fSdrahn     }
456d2201f2fSdrahn 
457d2201f2fSdrahn   return 0;
458d2201f2fSdrahn }
459d2201f2fSdrahn 
460d2201f2fSdrahn /* Default value for CGEN_PRINT_INSN.
461d2201f2fSdrahn    The result is the size of the insn in bytes or zero for an unknown insn
462d2201f2fSdrahn    or -1 if an error occured fetching bytes.  */
463d2201f2fSdrahn 
464d2201f2fSdrahn #ifndef CGEN_PRINT_INSN
465d2201f2fSdrahn #define CGEN_PRINT_INSN default_print_insn
466d2201f2fSdrahn #endif
467d2201f2fSdrahn 
468d2201f2fSdrahn static int
default_print_insn(CGEN_CPU_DESC cd,bfd_vma pc,disassemble_info * info)469*cf2f2c56Smiod default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
470d2201f2fSdrahn {
471d2201f2fSdrahn   char buf[CGEN_MAX_INSN_SIZE];
472d2201f2fSdrahn   int buflen;
473d2201f2fSdrahn   int status;
474d2201f2fSdrahn 
475d2201f2fSdrahn   /* Attempt to read the base part of the insn.  */
476d2201f2fSdrahn   buflen = cd->base_insn_bitsize / 8;
477d2201f2fSdrahn   status = (*info->read_memory_func) (pc, buf, buflen, info);
478d2201f2fSdrahn 
479d2201f2fSdrahn   /* Try again with the minimum part, if min < base.  */
480d2201f2fSdrahn   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
481d2201f2fSdrahn     {
482d2201f2fSdrahn       buflen = cd->min_insn_bitsize / 8;
483d2201f2fSdrahn       status = (*info->read_memory_func) (pc, buf, buflen, info);
484d2201f2fSdrahn     }
485d2201f2fSdrahn 
486d2201f2fSdrahn   if (status != 0)
487d2201f2fSdrahn     {
488d2201f2fSdrahn       (*info->memory_error_func) (status, pc, info);
489d2201f2fSdrahn       return -1;
490d2201f2fSdrahn     }
491d2201f2fSdrahn 
492d2201f2fSdrahn   return print_insn (cd, pc, info, buf, buflen);
493d2201f2fSdrahn }
494d2201f2fSdrahn 
495d2201f2fSdrahn /* Main entry point.
496d2201f2fSdrahn    Print one instruction from PC on INFO->STREAM.
497d2201f2fSdrahn    Return the size of the instruction (in bytes).  */
498d2201f2fSdrahn 
499d2201f2fSdrahn typedef struct cpu_desc_list {
500d2201f2fSdrahn   struct cpu_desc_list *next;
501d2201f2fSdrahn   int isa;
502d2201f2fSdrahn   int mach;
503d2201f2fSdrahn   int endian;
504d2201f2fSdrahn   CGEN_CPU_DESC cd;
505d2201f2fSdrahn } cpu_desc_list;
506d2201f2fSdrahn 
507d2201f2fSdrahn int
print_insn_iq2000(bfd_vma pc,disassemble_info * info)508*cf2f2c56Smiod print_insn_iq2000 (bfd_vma pc, disassemble_info *info)
509d2201f2fSdrahn {
510d2201f2fSdrahn   static cpu_desc_list *cd_list = 0;
511d2201f2fSdrahn   cpu_desc_list *cl = 0;
512d2201f2fSdrahn   static CGEN_CPU_DESC cd = 0;
513d2201f2fSdrahn   static int prev_isa;
514d2201f2fSdrahn   static int prev_mach;
515d2201f2fSdrahn   static int prev_endian;
516d2201f2fSdrahn   int length;
517d2201f2fSdrahn   int isa,mach;
518d2201f2fSdrahn   int endian = (info->endian == BFD_ENDIAN_BIG
519d2201f2fSdrahn 		? CGEN_ENDIAN_BIG
520d2201f2fSdrahn 		: CGEN_ENDIAN_LITTLE);
521d2201f2fSdrahn   enum bfd_architecture arch;
522d2201f2fSdrahn 
523d2201f2fSdrahn   /* ??? gdb will set mach but leave the architecture as "unknown" */
524d2201f2fSdrahn #ifndef CGEN_BFD_ARCH
525d2201f2fSdrahn #define CGEN_BFD_ARCH bfd_arch_iq2000
526d2201f2fSdrahn #endif
527d2201f2fSdrahn   arch = info->arch;
528d2201f2fSdrahn   if (arch == bfd_arch_unknown)
529d2201f2fSdrahn     arch = CGEN_BFD_ARCH;
530d2201f2fSdrahn 
531d2201f2fSdrahn   /* There's no standard way to compute the machine or isa number
532d2201f2fSdrahn      so we leave it to the target.  */
533d2201f2fSdrahn #ifdef CGEN_COMPUTE_MACH
534d2201f2fSdrahn   mach = CGEN_COMPUTE_MACH (info);
535d2201f2fSdrahn #else
536d2201f2fSdrahn   mach = info->mach;
537d2201f2fSdrahn #endif
538d2201f2fSdrahn 
539d2201f2fSdrahn #ifdef CGEN_COMPUTE_ISA
540d2201f2fSdrahn   isa = CGEN_COMPUTE_ISA (info);
541d2201f2fSdrahn #else
542d2201f2fSdrahn   isa = info->insn_sets;
543d2201f2fSdrahn #endif
544d2201f2fSdrahn 
545d2201f2fSdrahn   /* If we've switched cpu's, try to find a handle we've used before */
546d2201f2fSdrahn   if (cd
547d2201f2fSdrahn       && (isa != prev_isa
548d2201f2fSdrahn 	  || mach != prev_mach
549d2201f2fSdrahn 	  || endian != prev_endian))
550d2201f2fSdrahn     {
551d2201f2fSdrahn       cd = 0;
552d2201f2fSdrahn       for (cl = cd_list; cl; cl = cl->next)
553d2201f2fSdrahn 	{
554d2201f2fSdrahn 	  if (cl->isa == isa &&
555d2201f2fSdrahn 	      cl->mach == mach &&
556d2201f2fSdrahn 	      cl->endian == endian)
557d2201f2fSdrahn 	    {
558d2201f2fSdrahn 	      cd = cl->cd;
559d2201f2fSdrahn 	      break;
560d2201f2fSdrahn 	    }
561d2201f2fSdrahn 	}
562d2201f2fSdrahn     }
563d2201f2fSdrahn 
564d2201f2fSdrahn   /* If we haven't initialized yet, initialize the opcode table.  */
565d2201f2fSdrahn   if (! cd)
566d2201f2fSdrahn     {
567d2201f2fSdrahn       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
568d2201f2fSdrahn       const char *mach_name;
569d2201f2fSdrahn 
570d2201f2fSdrahn       if (!arch_type)
571d2201f2fSdrahn 	abort ();
572d2201f2fSdrahn       mach_name = arch_type->printable_name;
573d2201f2fSdrahn 
574d2201f2fSdrahn       prev_isa = isa;
575d2201f2fSdrahn       prev_mach = mach;
576d2201f2fSdrahn       prev_endian = endian;
577d2201f2fSdrahn       cd = iq2000_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
578d2201f2fSdrahn 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
579d2201f2fSdrahn 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
580d2201f2fSdrahn 				 CGEN_CPU_OPEN_END);
581d2201f2fSdrahn       if (!cd)
582d2201f2fSdrahn 	abort ();
583d2201f2fSdrahn 
584d2201f2fSdrahn       /* save this away for future reference */
585d2201f2fSdrahn       cl = xmalloc (sizeof (struct cpu_desc_list));
586d2201f2fSdrahn       cl->cd = cd;
587d2201f2fSdrahn       cl->isa = isa;
588d2201f2fSdrahn       cl->mach = mach;
589d2201f2fSdrahn       cl->endian = endian;
590d2201f2fSdrahn       cl->next = cd_list;
591d2201f2fSdrahn       cd_list = cl;
592d2201f2fSdrahn 
593d2201f2fSdrahn       iq2000_cgen_init_dis (cd);
594d2201f2fSdrahn     }
595d2201f2fSdrahn 
596d2201f2fSdrahn   /* We try to have as much common code as possible.
597d2201f2fSdrahn      But at this point some targets need to take over.  */
598d2201f2fSdrahn   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
599d2201f2fSdrahn      but if not possible try to move this hook elsewhere rather than
600d2201f2fSdrahn      have two hooks.  */
601d2201f2fSdrahn   length = CGEN_PRINT_INSN (cd, pc, info);
602d2201f2fSdrahn   if (length > 0)
603d2201f2fSdrahn     return length;
604d2201f2fSdrahn   if (length < 0)
605d2201f2fSdrahn     return -1;
606d2201f2fSdrahn 
607d2201f2fSdrahn   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
608d2201f2fSdrahn   return cd->default_insn_bitsize / 8;
609d2201f2fSdrahn }
610