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