xref: /netbsd-src/external/gpl3/binutils.old/dist/opcodes/or1k-dis.c (revision e992f068c547fd6e84b3f104dc2340adcc955732)
1ede78133Schristos /* DO NOT EDIT!  -*- buffer-read-only: t -*- vi:set ro:  */
275fd0b74Schristos /* Disassembler interface for targets using CGEN. -*- C -*-
375fd0b74Schristos    CGEN: Cpu tools GENerator
475fd0b74Schristos 
575fd0b74Schristos    THIS FILE IS MACHINE GENERATED WITH CGEN.
675fd0b74Schristos    - the resultant file is machine generated, cgen-dis.in isn't
775fd0b74Schristos 
8*e992f068Schristos    Copyright (C) 1996-2022 Free Software Foundation, Inc.
975fd0b74Schristos 
1075fd0b74Schristos    This file is part of libopcodes.
1175fd0b74Schristos 
1275fd0b74Schristos    This library is free software; you can redistribute it and/or modify
1375fd0b74Schristos    it under the terms of the GNU General Public License as published by
1475fd0b74Schristos    the Free Software Foundation; either version 3, or (at your option)
1575fd0b74Schristos    any later version.
1675fd0b74Schristos 
1775fd0b74Schristos    It is distributed in the hope that it will be useful, but WITHOUT
1875fd0b74Schristos    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1975fd0b74Schristos    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
2075fd0b74Schristos    License for more details.
2175fd0b74Schristos 
2275fd0b74Schristos    You should have received a copy of the GNU General Public License
2375fd0b74Schristos    along with this program; if not, write to the Free Software Foundation, Inc.,
2475fd0b74Schristos    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2575fd0b74Schristos 
2675fd0b74Schristos /* ??? Eventually more and more of this stuff can go to cpu-independent files.
2775fd0b74Schristos    Keep that in mind.  */
2875fd0b74Schristos 
2975fd0b74Schristos #include "sysdep.h"
3075fd0b74Schristos #include <stdio.h>
3175fd0b74Schristos #include "ansidecl.h"
32ede78133Schristos #include "disassemble.h"
3375fd0b74Schristos #include "bfd.h"
3475fd0b74Schristos #include "symcat.h"
3575fd0b74Schristos #include "libiberty.h"
3675fd0b74Schristos #include "or1k-desc.h"
3775fd0b74Schristos #include "or1k-opc.h"
3875fd0b74Schristos #include "opintl.h"
3975fd0b74Schristos 
4075fd0b74Schristos /* Default text to print if an instruction isn't recognized.  */
4175fd0b74Schristos #define UNKNOWN_INSN_MSG _("*unknown*")
4275fd0b74Schristos 
4375fd0b74Schristos static void print_normal
4475fd0b74Schristos   (CGEN_CPU_DESC, void *, long, unsigned int, bfd_vma, int);
4575fd0b74Schristos static void print_address
4675fd0b74Schristos   (CGEN_CPU_DESC, void *, bfd_vma, unsigned int, bfd_vma, int) ATTRIBUTE_UNUSED;
4775fd0b74Schristos static void print_keyword
4875fd0b74Schristos   (CGEN_CPU_DESC, void *, CGEN_KEYWORD *, long, unsigned int) ATTRIBUTE_UNUSED;
4975fd0b74Schristos static void print_insn_normal
5075fd0b74Schristos   (CGEN_CPU_DESC, void *, const CGEN_INSN *, CGEN_FIELDS *, bfd_vma, int);
5175fd0b74Schristos static int print_insn
5275fd0b74Schristos   (CGEN_CPU_DESC, bfd_vma,  disassemble_info *, bfd_byte *, unsigned);
5375fd0b74Schristos static int default_print_insn
5475fd0b74Schristos   (CGEN_CPU_DESC, bfd_vma, disassemble_info *) ATTRIBUTE_UNUSED;
5575fd0b74Schristos static int read_insn
5675fd0b74Schristos   (CGEN_CPU_DESC, bfd_vma, disassemble_info *, bfd_byte *, int, CGEN_EXTRACT_INFO *,
5775fd0b74Schristos    unsigned long *);
5875fd0b74Schristos 
5975fd0b74Schristos /* -- disassembler routines inserted here.  */
6075fd0b74Schristos 
61012573ebSchristos /* -- dis.c */
62012573ebSchristos 
63012573ebSchristos 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)64012573ebSchristos print_regpair (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
65012573ebSchristos 	       void * dis_info,
66012573ebSchristos 	       long value,
67012573ebSchristos 	       unsigned int attrs ATTRIBUTE_UNUSED,
68012573ebSchristos 	       bfd_vma pc ATTRIBUTE_UNUSED,
69012573ebSchristos 	       int length ATTRIBUTE_UNUSED)
70012573ebSchristos {
71012573ebSchristos   disassemble_info *info = dis_info;
72012573ebSchristos   char reg1_index;
73012573ebSchristos   char reg2_index;
74012573ebSchristos 
75012573ebSchristos   reg1_index = value & 0x1f;
76012573ebSchristos   reg2_index = reg1_index + ((value & (1 << 5)) ? 2 : 1);
77012573ebSchristos 
78012573ebSchristos   (*info->fprintf_func) (info->stream, "r%d,r%d", reg1_index, reg2_index);
79012573ebSchristos }
80012573ebSchristos 
81012573ebSchristos /* -- */
8275fd0b74Schristos 
8375fd0b74Schristos void or1k_cgen_print_operand
84*e992f068Schristos   (CGEN_CPU_DESC, int, void *, CGEN_FIELDS *, void const *, bfd_vma, int);
8575fd0b74Schristos 
8675fd0b74Schristos /* Main entry point for printing operands.
8775fd0b74Schristos    XINFO is a `void *' and not a `disassemble_info *' to not put a requirement
8875fd0b74Schristos    of dis-asm.h on cgen.h.
8975fd0b74Schristos 
9075fd0b74Schristos    This function is basically just a big switch statement.  Earlier versions
9175fd0b74Schristos    used tables to look up the function to use, but
9275fd0b74Schristos    - if the table contains both assembler and disassembler functions then
9375fd0b74Schristos      the disassembler contains much of the assembler and vice-versa,
9475fd0b74Schristos    - there's a lot of inlining possibilities as things grow,
9575fd0b74Schristos    - using a switch statement avoids the function call overhead.
9675fd0b74Schristos 
9775fd0b74Schristos    This function could be moved into `print_insn_normal', but keeping it
9875fd0b74Schristos    separate makes clear the interface between `print_insn_normal' and each of
9975fd0b74Schristos    the handlers.  */
10075fd0b74Schristos 
10175fd0b74Schristos 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)10275fd0b74Schristos or1k_cgen_print_operand (CGEN_CPU_DESC cd,
10375fd0b74Schristos 			   int opindex,
10475fd0b74Schristos 			   void * xinfo,
10575fd0b74Schristos 			   CGEN_FIELDS *fields,
10675fd0b74Schristos 			   void const *attrs ATTRIBUTE_UNUSED,
10775fd0b74Schristos 			   bfd_vma pc,
10875fd0b74Schristos 			   int length)
10975fd0b74Schristos {
11075fd0b74Schristos   disassemble_info *info = (disassemble_info *) xinfo;
11175fd0b74Schristos 
11275fd0b74Schristos   switch (opindex)
11375fd0b74Schristos     {
114012573ebSchristos     case OR1K_OPERAND_DISP21 :
115012573ebSchristos       print_address (cd, info, fields->f_disp21, 0|(1<<CGEN_OPERAND_ABS_ADDR), pc, length);
116012573ebSchristos       break;
11775fd0b74Schristos     case OR1K_OPERAND_DISP26 :
11875fd0b74Schristos       print_address (cd, info, fields->f_disp26, 0|(1<<CGEN_OPERAND_PCREL_ADDR), pc, length);
11975fd0b74Schristos       break;
12075fd0b74Schristos     case OR1K_OPERAND_RA :
12175fd0b74Schristos       print_keyword (cd, info, & or1k_cgen_opval_h_gpr, fields->f_r2, 0);
12275fd0b74Schristos       break;
123012573ebSchristos     case OR1K_OPERAND_RAD32F :
124012573ebSchristos       print_regpair (cd, info, fields->f_rad32, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
125012573ebSchristos       break;
126012573ebSchristos     case OR1K_OPERAND_RADI :
127012573ebSchristos       print_regpair (cd, info, fields->f_rad32, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
12875fd0b74Schristos       break;
12975fd0b74Schristos     case OR1K_OPERAND_RASF :
13075fd0b74Schristos       print_keyword (cd, info, & or1k_cgen_opval_h_fsr, fields->f_r2, 0);
13175fd0b74Schristos       break;
13275fd0b74Schristos     case OR1K_OPERAND_RB :
13375fd0b74Schristos       print_keyword (cd, info, & or1k_cgen_opval_h_gpr, fields->f_r3, 0);
13475fd0b74Schristos       break;
135012573ebSchristos     case OR1K_OPERAND_RBD32F :
136012573ebSchristos       print_regpair (cd, info, fields->f_rbd32, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
137012573ebSchristos       break;
138012573ebSchristos     case OR1K_OPERAND_RBDI :
139012573ebSchristos       print_regpair (cd, info, fields->f_rbd32, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
14075fd0b74Schristos       break;
14175fd0b74Schristos     case OR1K_OPERAND_RBSF :
14275fd0b74Schristos       print_keyword (cd, info, & or1k_cgen_opval_h_fsr, fields->f_r3, 0);
14375fd0b74Schristos       break;
14475fd0b74Schristos     case OR1K_OPERAND_RD :
14575fd0b74Schristos       print_keyword (cd, info, & or1k_cgen_opval_h_gpr, fields->f_r1, 0);
14675fd0b74Schristos       break;
147012573ebSchristos     case OR1K_OPERAND_RDD32F :
148012573ebSchristos       print_regpair (cd, info, fields->f_rdd32, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
149012573ebSchristos       break;
150012573ebSchristos     case OR1K_OPERAND_RDDI :
151012573ebSchristos       print_regpair (cd, info, fields->f_rdd32, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
152012573ebSchristos       break;
15375fd0b74Schristos     case OR1K_OPERAND_RDSF :
15475fd0b74Schristos       print_keyword (cd, info, & or1k_cgen_opval_h_fsr, fields->f_r1, 0);
15575fd0b74Schristos       break;
15675fd0b74Schristos     case OR1K_OPERAND_SIMM16 :
15775fd0b74Schristos       print_normal (cd, info, fields->f_simm16, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT), pc, length);
15875fd0b74Schristos       break;
15975fd0b74Schristos     case OR1K_OPERAND_SIMM16_SPLIT :
16075fd0b74Schristos       print_normal (cd, info, fields->f_simm16_split, 0|(1<<CGEN_OPERAND_SIGNED)|(1<<CGEN_OPERAND_SIGN_OPT)|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
16175fd0b74Schristos       break;
16275fd0b74Schristos     case OR1K_OPERAND_UIMM16 :
16375fd0b74Schristos       print_normal (cd, info, fields->f_uimm16, 0, pc, length);
16475fd0b74Schristos       break;
16575fd0b74Schristos     case OR1K_OPERAND_UIMM16_SPLIT :
16675fd0b74Schristos       print_normal (cd, info, fields->f_uimm16_split, 0|(1<<CGEN_OPERAND_VIRTUAL), pc, length);
16775fd0b74Schristos       break;
16875fd0b74Schristos     case OR1K_OPERAND_UIMM6 :
16975fd0b74Schristos       print_normal (cd, info, fields->f_uimm6, 0, pc, length);
17075fd0b74Schristos       break;
17175fd0b74Schristos 
17275fd0b74Schristos     default :
17375fd0b74Schristos       /* xgettext:c-format */
174ede78133Schristos       opcodes_error_handler
175ede78133Schristos 	(_("internal error: unrecognized field %d while printing insn"),
17675fd0b74Schristos 	 opindex);
17775fd0b74Schristos       abort ();
17875fd0b74Schristos   }
17975fd0b74Schristos }
18075fd0b74Schristos 
18175fd0b74Schristos cgen_print_fn * const or1k_cgen_print_handlers[] =
18275fd0b74Schristos {
18375fd0b74Schristos   print_insn_normal,
18475fd0b74Schristos };
18575fd0b74Schristos 
18675fd0b74Schristos 
18775fd0b74Schristos void
or1k_cgen_init_dis(CGEN_CPU_DESC cd)18875fd0b74Schristos or1k_cgen_init_dis (CGEN_CPU_DESC cd)
18975fd0b74Schristos {
19075fd0b74Schristos   or1k_cgen_init_opcode_table (cd);
19175fd0b74Schristos   or1k_cgen_init_ibld_table (cd);
19275fd0b74Schristos   cd->print_handlers = & or1k_cgen_print_handlers[0];
19375fd0b74Schristos   cd->print_operand = or1k_cgen_print_operand;
19475fd0b74Schristos }
19575fd0b74Schristos 
19675fd0b74Schristos 
19775fd0b74Schristos /* Default print handler.  */
19875fd0b74Schristos 
19975fd0b74Schristos 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)20075fd0b74Schristos print_normal (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
20175fd0b74Schristos 	      void *dis_info,
20275fd0b74Schristos 	      long value,
20375fd0b74Schristos 	      unsigned int attrs,
20475fd0b74Schristos 	      bfd_vma pc ATTRIBUTE_UNUSED,
20575fd0b74Schristos 	      int length ATTRIBUTE_UNUSED)
20675fd0b74Schristos {
20775fd0b74Schristos   disassemble_info *info = (disassemble_info *) dis_info;
20875fd0b74Schristos 
20975fd0b74Schristos   /* Print the operand as directed by the attributes.  */
21075fd0b74Schristos   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
21175fd0b74Schristos     ; /* nothing to do */
21275fd0b74Schristos   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
21375fd0b74Schristos     (*info->fprintf_func) (info->stream, "%ld", value);
21475fd0b74Schristos   else
21575fd0b74Schristos     (*info->fprintf_func) (info->stream, "0x%lx", value);
21675fd0b74Schristos }
21775fd0b74Schristos 
21875fd0b74Schristos /* Default address handler.  */
21975fd0b74Schristos 
22075fd0b74Schristos 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)22175fd0b74Schristos print_address (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
22275fd0b74Schristos 	       void *dis_info,
22375fd0b74Schristos 	       bfd_vma value,
22475fd0b74Schristos 	       unsigned int attrs,
22575fd0b74Schristos 	       bfd_vma pc ATTRIBUTE_UNUSED,
22675fd0b74Schristos 	       int length ATTRIBUTE_UNUSED)
22775fd0b74Schristos {
22875fd0b74Schristos   disassemble_info *info = (disassemble_info *) dis_info;
22975fd0b74Schristos 
23075fd0b74Schristos   /* Print the operand as directed by the attributes.  */
23175fd0b74Schristos   if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SEM_ONLY))
23275fd0b74Schristos     ; /* Nothing to do.  */
23375fd0b74Schristos   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_PCREL_ADDR))
23475fd0b74Schristos     (*info->print_address_func) (value, info);
23575fd0b74Schristos   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_ABS_ADDR))
23675fd0b74Schristos     (*info->print_address_func) (value, info);
23775fd0b74Schristos   else if (CGEN_BOOL_ATTR (attrs, CGEN_OPERAND_SIGNED))
23875fd0b74Schristos     (*info->fprintf_func) (info->stream, "%ld", (long) value);
23975fd0b74Schristos   else
24075fd0b74Schristos     (*info->fprintf_func) (info->stream, "0x%lx", (long) value);
24175fd0b74Schristos }
24275fd0b74Schristos 
24375fd0b74Schristos /* Keyword print handler.  */
24475fd0b74Schristos 
24575fd0b74Schristos static void
print_keyword(CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,void * dis_info,CGEN_KEYWORD * keyword_table,long value,unsigned int attrs ATTRIBUTE_UNUSED)24675fd0b74Schristos print_keyword (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
24775fd0b74Schristos 	       void *dis_info,
24875fd0b74Schristos 	       CGEN_KEYWORD *keyword_table,
24975fd0b74Schristos 	       long value,
25075fd0b74Schristos 	       unsigned int attrs ATTRIBUTE_UNUSED)
25175fd0b74Schristos {
25275fd0b74Schristos   disassemble_info *info = (disassemble_info *) dis_info;
25375fd0b74Schristos   const CGEN_KEYWORD_ENTRY *ke;
25475fd0b74Schristos 
25575fd0b74Schristos   ke = cgen_keyword_lookup_value (keyword_table, value);
25675fd0b74Schristos   if (ke != NULL)
25775fd0b74Schristos     (*info->fprintf_func) (info->stream, "%s", ke->name);
25875fd0b74Schristos   else
25975fd0b74Schristos     (*info->fprintf_func) (info->stream, "???");
26075fd0b74Schristos }
26175fd0b74Schristos 
26275fd0b74Schristos /* Default insn printer.
26375fd0b74Schristos 
26475fd0b74Schristos    DIS_INFO is defined as `void *' so the disassembler needn't know anything
26575fd0b74Schristos    about disassemble_info.  */
26675fd0b74Schristos 
26775fd0b74Schristos static void
print_insn_normal(CGEN_CPU_DESC cd,void * dis_info,const CGEN_INSN * insn,CGEN_FIELDS * fields,bfd_vma pc,int length)26875fd0b74Schristos print_insn_normal (CGEN_CPU_DESC cd,
26975fd0b74Schristos 		   void *dis_info,
27075fd0b74Schristos 		   const CGEN_INSN *insn,
27175fd0b74Schristos 		   CGEN_FIELDS *fields,
27275fd0b74Schristos 		   bfd_vma pc,
27375fd0b74Schristos 		   int length)
27475fd0b74Schristos {
27575fd0b74Schristos   const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
27675fd0b74Schristos   disassemble_info *info = (disassemble_info *) dis_info;
27775fd0b74Schristos   const CGEN_SYNTAX_CHAR_TYPE *syn;
27875fd0b74Schristos 
27975fd0b74Schristos   CGEN_INIT_PRINT (cd);
28075fd0b74Schristos 
28175fd0b74Schristos   for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
28275fd0b74Schristos     {
28375fd0b74Schristos       if (CGEN_SYNTAX_MNEMONIC_P (*syn))
28475fd0b74Schristos 	{
28575fd0b74Schristos 	  (*info->fprintf_func) (info->stream, "%s", CGEN_INSN_MNEMONIC (insn));
28675fd0b74Schristos 	  continue;
28775fd0b74Schristos 	}
28875fd0b74Schristos       if (CGEN_SYNTAX_CHAR_P (*syn))
28975fd0b74Schristos 	{
29075fd0b74Schristos 	  (*info->fprintf_func) (info->stream, "%c", CGEN_SYNTAX_CHAR (*syn));
29175fd0b74Schristos 	  continue;
29275fd0b74Schristos 	}
29375fd0b74Schristos 
29475fd0b74Schristos       /* We have an operand.  */
29575fd0b74Schristos       or1k_cgen_print_operand (cd, CGEN_SYNTAX_FIELD (*syn), info,
29675fd0b74Schristos 				 fields, CGEN_INSN_ATTRS (insn), pc, length);
29775fd0b74Schristos     }
29875fd0b74Schristos }
29975fd0b74Schristos 
30075fd0b74Schristos /* Subroutine of print_insn. Reads an insn into the given buffers and updates
30175fd0b74Schristos    the extract info.
30275fd0b74Schristos    Returns 0 if all is well, non-zero otherwise.  */
30375fd0b74Schristos 
30475fd0b74Schristos 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)30575fd0b74Schristos read_insn (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
30675fd0b74Schristos 	   bfd_vma pc,
30775fd0b74Schristos 	   disassemble_info *info,
30875fd0b74Schristos 	   bfd_byte *buf,
30975fd0b74Schristos 	   int buflen,
31075fd0b74Schristos 	   CGEN_EXTRACT_INFO *ex_info,
31175fd0b74Schristos 	   unsigned long *insn_value)
31275fd0b74Schristos {
31375fd0b74Schristos   int status = (*info->read_memory_func) (pc, buf, buflen, info);
31475fd0b74Schristos 
31575fd0b74Schristos   if (status != 0)
31675fd0b74Schristos     {
31775fd0b74Schristos       (*info->memory_error_func) (status, pc, info);
31875fd0b74Schristos       return -1;
31975fd0b74Schristos     }
32075fd0b74Schristos 
32175fd0b74Schristos   ex_info->dis_info = info;
32275fd0b74Schristos   ex_info->valid = (1 << buflen) - 1;
32375fd0b74Schristos   ex_info->insn_bytes = buf;
32475fd0b74Schristos 
32575fd0b74Schristos   *insn_value = bfd_get_bits (buf, buflen * 8, info->endian == BFD_ENDIAN_BIG);
32675fd0b74Schristos   return 0;
32775fd0b74Schristos }
32875fd0b74Schristos 
32975fd0b74Schristos /* Utility to print an insn.
33075fd0b74Schristos    BUF is the base part of the insn, target byte order, BUFLEN bytes long.
33175fd0b74Schristos    The result is the size of the insn in bytes or zero for an unknown insn
33275fd0b74Schristos    or -1 if an error occurs fetching data (memory_error_func will have
33375fd0b74Schristos    been called).  */
33475fd0b74Schristos 
33575fd0b74Schristos static int
print_insn(CGEN_CPU_DESC cd,bfd_vma pc,disassemble_info * info,bfd_byte * buf,unsigned int buflen)33675fd0b74Schristos print_insn (CGEN_CPU_DESC cd,
33775fd0b74Schristos 	    bfd_vma pc,
33875fd0b74Schristos 	    disassemble_info *info,
33975fd0b74Schristos 	    bfd_byte *buf,
34075fd0b74Schristos 	    unsigned int buflen)
34175fd0b74Schristos {
34275fd0b74Schristos   CGEN_INSN_INT insn_value;
34375fd0b74Schristos   const CGEN_INSN_LIST *insn_list;
34475fd0b74Schristos   CGEN_EXTRACT_INFO ex_info;
34575fd0b74Schristos   int basesize;
34675fd0b74Schristos 
34775fd0b74Schristos   /* Extract base part of instruction, just in case CGEN_DIS_* uses it. */
34875fd0b74Schristos   basesize = cd->base_insn_bitsize < buflen * 8 ?
34975fd0b74Schristos                                      cd->base_insn_bitsize : buflen * 8;
350*e992f068Schristos   insn_value = cgen_get_insn_value (cd, buf, basesize, cd->insn_endian);
35175fd0b74Schristos 
35275fd0b74Schristos 
35375fd0b74Schristos   /* Fill in ex_info fields like read_insn would.  Don't actually call
35475fd0b74Schristos      read_insn, since the incoming buffer is already read (and possibly
35575fd0b74Schristos      modified a la m32r).  */
35675fd0b74Schristos   ex_info.valid = (1 << buflen) - 1;
35775fd0b74Schristos   ex_info.dis_info = info;
35875fd0b74Schristos   ex_info.insn_bytes = buf;
35975fd0b74Schristos 
36075fd0b74Schristos   /* The instructions are stored in hash lists.
36175fd0b74Schristos      Pick the first one and keep trying until we find the right one.  */
36275fd0b74Schristos 
36375fd0b74Schristos   insn_list = CGEN_DIS_LOOKUP_INSN (cd, (char *) buf, insn_value);
36475fd0b74Schristos   while (insn_list != NULL)
36575fd0b74Schristos     {
36675fd0b74Schristos       const CGEN_INSN *insn = insn_list->insn;
36775fd0b74Schristos       CGEN_FIELDS fields;
36875fd0b74Schristos       int length;
36975fd0b74Schristos       unsigned long insn_value_cropped;
37075fd0b74Schristos 
37175fd0b74Schristos #ifdef CGEN_VALIDATE_INSN_SUPPORTED
37275fd0b74Schristos       /* Not needed as insn shouldn't be in hash lists if not supported.  */
37375fd0b74Schristos       /* Supported by this cpu?  */
37475fd0b74Schristos       if (! or1k_cgen_insn_supported (cd, insn))
37575fd0b74Schristos         {
37675fd0b74Schristos           insn_list = CGEN_DIS_NEXT_INSN (insn_list);
37775fd0b74Schristos 	  continue;
37875fd0b74Schristos         }
37975fd0b74Schristos #endif
38075fd0b74Schristos 
38175fd0b74Schristos       /* Basic bit mask must be correct.  */
38275fd0b74Schristos       /* ??? May wish to allow target to defer this check until the extract
38375fd0b74Schristos 	 handler.  */
38475fd0b74Schristos 
38575fd0b74Schristos       /* Base size may exceed this instruction's size.  Extract the
38675fd0b74Schristos          relevant part from the buffer. */
38775fd0b74Schristos       if ((unsigned) (CGEN_INSN_BITSIZE (insn) / 8) < buflen &&
38875fd0b74Schristos 	  (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
38975fd0b74Schristos 	insn_value_cropped = bfd_get_bits (buf, CGEN_INSN_BITSIZE (insn),
39075fd0b74Schristos 					   info->endian == BFD_ENDIAN_BIG);
39175fd0b74Schristos       else
39275fd0b74Schristos 	insn_value_cropped = insn_value;
39375fd0b74Schristos 
39475fd0b74Schristos       if ((insn_value_cropped & CGEN_INSN_BASE_MASK (insn))
39575fd0b74Schristos 	  == CGEN_INSN_BASE_VALUE (insn))
39675fd0b74Schristos 	{
39775fd0b74Schristos 	  /* Printing is handled in two passes.  The first pass parses the
39875fd0b74Schristos 	     machine insn and extracts the fields.  The second pass prints
39975fd0b74Schristos 	     them.  */
40075fd0b74Schristos 
40175fd0b74Schristos 	  /* Make sure the entire insn is loaded into insn_value, if it
40275fd0b74Schristos 	     can fit.  */
40375fd0b74Schristos 	  if (((unsigned) CGEN_INSN_BITSIZE (insn) > cd->base_insn_bitsize) &&
40475fd0b74Schristos 	      (unsigned) (CGEN_INSN_BITSIZE (insn) / 8) <= sizeof (unsigned long))
40575fd0b74Schristos 	    {
40675fd0b74Schristos 	      unsigned long full_insn_value;
40775fd0b74Schristos 	      int rc = read_insn (cd, pc, info, buf,
40875fd0b74Schristos 				  CGEN_INSN_BITSIZE (insn) / 8,
40975fd0b74Schristos 				  & ex_info, & full_insn_value);
41075fd0b74Schristos 	      if (rc != 0)
41175fd0b74Schristos 		return rc;
41275fd0b74Schristos 	      length = CGEN_EXTRACT_FN (cd, insn)
41375fd0b74Schristos 		(cd, insn, &ex_info, full_insn_value, &fields, pc);
41475fd0b74Schristos 	    }
41575fd0b74Schristos 	  else
41675fd0b74Schristos 	    length = CGEN_EXTRACT_FN (cd, insn)
41775fd0b74Schristos 	      (cd, insn, &ex_info, insn_value_cropped, &fields, pc);
41875fd0b74Schristos 
41975fd0b74Schristos 	  /* Length < 0 -> error.  */
42075fd0b74Schristos 	  if (length < 0)
42175fd0b74Schristos 	    return length;
42275fd0b74Schristos 	  if (length > 0)
42375fd0b74Schristos 	    {
42475fd0b74Schristos 	      CGEN_PRINT_FN (cd, insn) (cd, info, insn, &fields, pc, length);
42575fd0b74Schristos 	      /* Length is in bits, result is in bytes.  */
42675fd0b74Schristos 	      return length / 8;
42775fd0b74Schristos 	    }
42875fd0b74Schristos 	}
42975fd0b74Schristos 
43075fd0b74Schristos       insn_list = CGEN_DIS_NEXT_INSN (insn_list);
43175fd0b74Schristos     }
43275fd0b74Schristos 
43375fd0b74Schristos   return 0;
43475fd0b74Schristos }
43575fd0b74Schristos 
43675fd0b74Schristos /* Default value for CGEN_PRINT_INSN.
43775fd0b74Schristos    The result is the size of the insn in bytes or zero for an unknown insn
43875fd0b74Schristos    or -1 if an error occured fetching bytes.  */
43975fd0b74Schristos 
44075fd0b74Schristos #ifndef CGEN_PRINT_INSN
44175fd0b74Schristos #define CGEN_PRINT_INSN default_print_insn
44275fd0b74Schristos #endif
44375fd0b74Schristos 
44475fd0b74Schristos static int
default_print_insn(CGEN_CPU_DESC cd,bfd_vma pc,disassemble_info * info)44575fd0b74Schristos default_print_insn (CGEN_CPU_DESC cd, bfd_vma pc, disassemble_info *info)
44675fd0b74Schristos {
44775fd0b74Schristos   bfd_byte buf[CGEN_MAX_INSN_SIZE];
44875fd0b74Schristos   int buflen;
44975fd0b74Schristos   int status;
45075fd0b74Schristos 
45175fd0b74Schristos   /* Attempt to read the base part of the insn.  */
45275fd0b74Schristos   buflen = cd->base_insn_bitsize / 8;
45375fd0b74Schristos   status = (*info->read_memory_func) (pc, buf, buflen, info);
45475fd0b74Schristos 
45575fd0b74Schristos   /* Try again with the minimum part, if min < base.  */
45675fd0b74Schristos   if (status != 0 && (cd->min_insn_bitsize < cd->base_insn_bitsize))
45775fd0b74Schristos     {
45875fd0b74Schristos       buflen = cd->min_insn_bitsize / 8;
45975fd0b74Schristos       status = (*info->read_memory_func) (pc, buf, buflen, info);
46075fd0b74Schristos     }
46175fd0b74Schristos 
46275fd0b74Schristos   if (status != 0)
46375fd0b74Schristos     {
46475fd0b74Schristos       (*info->memory_error_func) (status, pc, info);
46575fd0b74Schristos       return -1;
46675fd0b74Schristos     }
46775fd0b74Schristos 
46875fd0b74Schristos   return print_insn (cd, pc, info, buf, buflen);
46975fd0b74Schristos }
47075fd0b74Schristos 
47175fd0b74Schristos /* Main entry point.
47275fd0b74Schristos    Print one instruction from PC on INFO->STREAM.
47375fd0b74Schristos    Return the size of the instruction (in bytes).  */
47475fd0b74Schristos 
47575fd0b74Schristos typedef struct cpu_desc_list
47675fd0b74Schristos {
47775fd0b74Schristos   struct cpu_desc_list *next;
47875fd0b74Schristos   CGEN_BITSET *isa;
47975fd0b74Schristos   int mach;
48075fd0b74Schristos   int endian;
481*e992f068Schristos   int insn_endian;
48275fd0b74Schristos   CGEN_CPU_DESC cd;
48375fd0b74Schristos } cpu_desc_list;
48475fd0b74Schristos 
48575fd0b74Schristos int
print_insn_or1k(bfd_vma pc,disassemble_info * info)48675fd0b74Schristos print_insn_or1k (bfd_vma pc, disassemble_info *info)
48775fd0b74Schristos {
48875fd0b74Schristos   static cpu_desc_list *cd_list = 0;
48975fd0b74Schristos   cpu_desc_list *cl = 0;
49075fd0b74Schristos   static CGEN_CPU_DESC cd = 0;
49175fd0b74Schristos   static CGEN_BITSET *prev_isa;
49275fd0b74Schristos   static int prev_mach;
49375fd0b74Schristos   static int prev_endian;
494*e992f068Schristos   static int prev_insn_endian;
49575fd0b74Schristos   int length;
49675fd0b74Schristos   CGEN_BITSET *isa;
49775fd0b74Schristos   int mach;
49875fd0b74Schristos   int endian = (info->endian == BFD_ENDIAN_BIG
49975fd0b74Schristos 		? CGEN_ENDIAN_BIG
50075fd0b74Schristos 		: CGEN_ENDIAN_LITTLE);
501*e992f068Schristos   int insn_endian = (info->endian_code == BFD_ENDIAN_BIG
502*e992f068Schristos                      ? CGEN_ENDIAN_BIG
503*e992f068Schristos                      : CGEN_ENDIAN_LITTLE);
50475fd0b74Schristos   enum bfd_architecture arch;
50575fd0b74Schristos 
50675fd0b74Schristos   /* ??? gdb will set mach but leave the architecture as "unknown" */
50775fd0b74Schristos #ifndef CGEN_BFD_ARCH
50875fd0b74Schristos #define CGEN_BFD_ARCH bfd_arch_or1k
50975fd0b74Schristos #endif
51075fd0b74Schristos   arch = info->arch;
51175fd0b74Schristos   if (arch == bfd_arch_unknown)
51275fd0b74Schristos     arch = CGEN_BFD_ARCH;
51375fd0b74Schristos 
51475fd0b74Schristos   /* There's no standard way to compute the machine or isa number
51575fd0b74Schristos      so we leave it to the target.  */
51675fd0b74Schristos #ifdef CGEN_COMPUTE_MACH
51775fd0b74Schristos   mach = CGEN_COMPUTE_MACH (info);
51875fd0b74Schristos #else
51975fd0b74Schristos   mach = info->mach;
52075fd0b74Schristos #endif
52175fd0b74Schristos 
52275fd0b74Schristos #ifdef CGEN_COMPUTE_ISA
52375fd0b74Schristos   {
52475fd0b74Schristos     static CGEN_BITSET *permanent_isa;
52575fd0b74Schristos 
52675fd0b74Schristos     if (!permanent_isa)
52775fd0b74Schristos       permanent_isa = cgen_bitset_create (MAX_ISAS);
52875fd0b74Schristos     isa = permanent_isa;
52975fd0b74Schristos     cgen_bitset_clear (isa);
53075fd0b74Schristos     cgen_bitset_add (isa, CGEN_COMPUTE_ISA (info));
53175fd0b74Schristos   }
53275fd0b74Schristos #else
533012573ebSchristos   isa = info->private_data;
53475fd0b74Schristos #endif
53575fd0b74Schristos 
53675fd0b74Schristos   /* If we've switched cpu's, try to find a handle we've used before */
53775fd0b74Schristos   if (cd
53875fd0b74Schristos       && (cgen_bitset_compare (isa, prev_isa) != 0
53975fd0b74Schristos 	  || mach != prev_mach
54075fd0b74Schristos 	  || endian != prev_endian))
54175fd0b74Schristos     {
54275fd0b74Schristos       cd = 0;
54375fd0b74Schristos       for (cl = cd_list; cl; cl = cl->next)
54475fd0b74Schristos 	{
54575fd0b74Schristos 	  if (cgen_bitset_compare (cl->isa, isa) == 0 &&
54675fd0b74Schristos 	      cl->mach == mach &&
54775fd0b74Schristos 	      cl->endian == endian)
54875fd0b74Schristos 	    {
54975fd0b74Schristos 	      cd = cl->cd;
55075fd0b74Schristos  	      prev_isa = cd->isas;
55175fd0b74Schristos 	      break;
55275fd0b74Schristos 	    }
55375fd0b74Schristos 	}
55475fd0b74Schristos     }
55575fd0b74Schristos 
55675fd0b74Schristos   /* If we haven't initialized yet, initialize the opcode table.  */
55775fd0b74Schristos   if (! cd)
55875fd0b74Schristos     {
55975fd0b74Schristos       const bfd_arch_info_type *arch_type = bfd_lookup_arch (arch, mach);
56075fd0b74Schristos       const char *mach_name;
56175fd0b74Schristos 
56275fd0b74Schristos       if (!arch_type)
56375fd0b74Schristos 	abort ();
56475fd0b74Schristos       mach_name = arch_type->printable_name;
56575fd0b74Schristos 
56675fd0b74Schristos       prev_isa = cgen_bitset_copy (isa);
56775fd0b74Schristos       prev_mach = mach;
56875fd0b74Schristos       prev_endian = endian;
569*e992f068Schristos       prev_insn_endian = insn_endian;
57075fd0b74Schristos       cd = or1k_cgen_cpu_open (CGEN_CPU_OPEN_ISAS, prev_isa,
57175fd0b74Schristos 				 CGEN_CPU_OPEN_BFDMACH, mach_name,
57275fd0b74Schristos 				 CGEN_CPU_OPEN_ENDIAN, prev_endian,
573*e992f068Schristos                                  CGEN_CPU_OPEN_INSN_ENDIAN, prev_insn_endian,
57475fd0b74Schristos 				 CGEN_CPU_OPEN_END);
57575fd0b74Schristos       if (!cd)
57675fd0b74Schristos 	abort ();
57775fd0b74Schristos 
57875fd0b74Schristos       /* Save this away for future reference.  */
57975fd0b74Schristos       cl = xmalloc (sizeof (struct cpu_desc_list));
58075fd0b74Schristos       cl->cd = cd;
58175fd0b74Schristos       cl->isa = prev_isa;
58275fd0b74Schristos       cl->mach = mach;
58375fd0b74Schristos       cl->endian = endian;
58475fd0b74Schristos       cl->next = cd_list;
58575fd0b74Schristos       cd_list = cl;
58675fd0b74Schristos 
58775fd0b74Schristos       or1k_cgen_init_dis (cd);
58875fd0b74Schristos     }
58975fd0b74Schristos 
59075fd0b74Schristos   /* We try to have as much common code as possible.
59175fd0b74Schristos      But at this point some targets need to take over.  */
59275fd0b74Schristos   /* ??? Some targets may need a hook elsewhere.  Try to avoid this,
59375fd0b74Schristos      but if not possible try to move this hook elsewhere rather than
59475fd0b74Schristos      have two hooks.  */
59575fd0b74Schristos   length = CGEN_PRINT_INSN (cd, pc, info);
59675fd0b74Schristos   if (length > 0)
59775fd0b74Schristos     return length;
59875fd0b74Schristos   if (length < 0)
59975fd0b74Schristos     return -1;
60075fd0b74Schristos 
60175fd0b74Schristos   (*info->fprintf_func) (info->stream, UNKNOWN_INSN_MSG);
60275fd0b74Schristos   return cd->default_insn_bitsize / 8;
60375fd0b74Schristos }
604