| /* NDS32-specific support for 32-bit ELF. | 
 |    Copyright (C) 2012-2024 Free Software Foundation, Inc. | 
 |    Contributed by Andes Technology Corporation. | 
 |  | 
 |    This file is part of BFD, the Binary File Descriptor library. | 
 |  | 
 |    This program is free software; you can redistribute it and/or modify | 
 |    it under the terms of the GNU General Public License as published by | 
 |    the Free Software Foundation; either version 3 of the License, or | 
 |    (at your option) any later version. | 
 |  | 
 |    This program is distributed in the hope that it will be useful, | 
 |    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |    GNU General Public License for more details. | 
 |  | 
 |    You should have received a copy of the GNU General Public License | 
 |    along with this program; if not, write to the Free Software | 
 |    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA | 
 |    02110-1301, USA.  */ | 
 |  | 
 | #include "sysdep.h" | 
 | #include <stdio.h> | 
 | #include "ansidecl.h" | 
 | #include "disassemble.h" | 
 | #include "bfd.h" | 
 | #include "symcat.h" | 
 | #include "libiberty.h" | 
 | #include "opintl.h" | 
 | #include <stdint.h> | 
 | #include "hashtab.h" | 
 | #include "nds32-asm.h" | 
 | #include "opcode/nds32.h" | 
 |  | 
 | /* Get fields macro define.  */ | 
 | #define MASK_OP(insn, mask)	((insn) & (0x3f << 25 | (mask))) | 
 |  | 
 | /* For mapping symbol.  */ | 
 | enum map_type | 
 | { | 
 |   MAP_DATA0, | 
 |   MAP_DATA1, | 
 |   MAP_DATA2, | 
 |   MAP_DATA3, | 
 |   MAP_DATA4, | 
 |   MAP_CODE, | 
 | }; | 
 |  | 
 | struct nds32_private_data | 
 | { | 
 |   /* Whether any mapping symbols are present in the provided symbol | 
 |      table.  -1 if we do not know yet, otherwise 0 or 1.  */ | 
 |   int has_mapping_symbols; | 
 |  | 
 |   /* Track the last type (although this doesn't seem to be useful).  */ | 
 |   enum map_type last_mapping_type; | 
 |  | 
 |   /* Tracking symbol table information.  */ | 
 |   int last_symbol_index; | 
 |   bfd_vma last_addr; | 
 | }; | 
 |  | 
 | /* Default text to print if an instruction isn't recognized.  */ | 
 | #define UNKNOWN_INSN_MSG _("*unknown*") | 
 | #define NDS32_PARSE_INSN16      0x01 | 
 | #define NDS32_PARSE_INSN32      0x02 | 
 |  | 
 | static uint32_t nds32_mask_opcode (uint32_t); | 
 | static void nds32_special_opcode (uint32_t, struct nds32_opcode **); | 
 | static int get_mapping_symbol_type (struct disassemble_info *, int, | 
 | 				    enum map_type *); | 
 | static int is_mapping_symbol (struct disassemble_info *, int, | 
 | 			      enum map_type *); | 
 |  | 
 | /* Hash function for disassemble.  */ | 
 |  | 
 | static htab_t opcode_htab; | 
 |  | 
 | /* Find the value map register name.  */ | 
 |  | 
 | static const keyword_t * | 
 | nds32_find_reg_keyword (const keyword_t *reg, int value) | 
 | { | 
 |   if (!reg) | 
 |     return NULL; | 
 |  | 
 |   while (reg->name != NULL && reg->value != value) | 
 |     { | 
 |       reg++; | 
 |     } | 
 |   if (reg->name == NULL) | 
 |     return NULL; | 
 |   return reg; | 
 | } | 
 |  | 
 | static void | 
 | nds32_parse_audio_ext (const field_t *pfd, | 
 | 		       disassemble_info *info, uint32_t insn) | 
 | { | 
 |   fprintf_ftype func = info->fprintf_func; | 
 |   void *stream = info->stream; | 
 |   const keyword_t *psys_reg; | 
 |   int int_value, new_value; | 
 |  | 
 |   if (pfd->hw_res == HW_INT || pfd->hw_res == HW_UINT) | 
 |     { | 
 |       if (pfd->hw_res == HW_INT) | 
 | 	int_value = (unsigned) N32_IMMS (insn >> pfd->bitpos, | 
 | 					 pfd->bitsize) << pfd->shift; | 
 |       else | 
 | 	int_value = __GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; | 
 |  | 
 |       if (int_value < 10) | 
 | 	func (stream, "#%d", int_value); | 
 |       else | 
 | 	func (stream, "#0x%x", int_value); | 
 |       return; | 
 |     } | 
 |   int_value = | 
 |     __GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; | 
 |   new_value = int_value; | 
 |   psys_reg = (keyword_t*) nds32_keywords[pfd->hw_res]; | 
 |  | 
 |   /* p = bit[4].bit[1:0], r = bit[4].bit[3:2].  */ | 
 |   if (strcmp (pfd->name, "im5_i") == 0) | 
 |     { | 
 |       new_value = int_value & 0x03; | 
 |       new_value |= ((int_value & 0x10) >> 2); | 
 |     } | 
 |   else if (strcmp (pfd->name, "im5_m") == 0) | 
 |     { | 
 |       new_value = ((int_value & 0x1C) >> 2); | 
 |     } | 
 |   /* p = 0.bit[1:0], r = 0.bit[3:2].  */ | 
 |   /* q = 1.bit[1:0], s = 1.bit[5:4].  */ | 
 |   else if (strcmp (pfd->name, "im6_iq") == 0) | 
 |     { | 
 |       new_value |= 0x04; | 
 |     } | 
 |   else if (strcmp (pfd->name, "im6_ms") == 0) | 
 |     { | 
 |       new_value |= 0x04; | 
 |     } | 
 |   /*  Rt CONCAT(c, t21, t0).  */ | 
 |   else if (strcmp (pfd->name, "a_rt21") == 0) | 
 |     { | 
 |       new_value = (insn & 0x00000020) >> 5; | 
 |       new_value |= (insn & 0x00000C00) >> 9; | 
 |       new_value |= (insn & 0x00008000) >> 12; | 
 |     } | 
 |   else if (strcmp (pfd->name, "a_rte") == 0) | 
 |     { | 
 |       new_value = (insn & 0x00000C00) >> 9; | 
 |       new_value |= (insn & 0x00008000) >> 12; | 
 |     } | 
 |   else if (strcmp (pfd->name, "a_rte1") == 0) | 
 |     { | 
 |       new_value = (insn & 0x00000C00) >> 9; | 
 |       new_value |= (insn & 0x00008000) >> 12; | 
 |       new_value |= 0x01; | 
 |     } | 
 |   else if (strcmp (pfd->name, "a_rte69") == 0) | 
 |     { | 
 |       new_value = int_value << 1; | 
 |     } | 
 |   else if (strcmp (pfd->name, "a_rte69_1") == 0) | 
 |     { | 
 |       new_value = int_value << 1; | 
 |       new_value |= 0x01; | 
 |     } | 
 |  | 
 |   psys_reg = nds32_find_reg_keyword (psys_reg, new_value); | 
 |   if (!psys_reg) | 
 |     func (stream, "???"); | 
 |   else | 
 |     func (stream, "$%s", psys_reg->name); | 
 | } | 
 |  | 
 | /* Match instruction opcode with keyword table.  */ | 
 |  | 
 | static field_t * | 
 | match_field (char *name) | 
 | { | 
 |   field_t *pfd; | 
 |   int k; | 
 |  | 
 |   for (k = 0; k < NDS32_CORE_COUNT; k++) | 
 |     { | 
 |       pfd = (field_t *) nds32_field_table[k]; | 
 |       while (1) | 
 | 	{ | 
 | 	  if (pfd->name == NULL) | 
 | 	    break; | 
 | 	  if (strcmp (name, pfd->name) == 0) | 
 | 	    return pfd; | 
 | 	  pfd++; | 
 | 	} | 
 |     } | 
 |  | 
 |   return NULL; | 
 | } | 
 |  | 
 | /* Dump instruction.  If the opcode is unknown, return FALSE.  */ | 
 |  | 
 | static void | 
 | nds32_parse_opcode (struct nds32_opcode *opc, bfd_vma pc ATTRIBUTE_UNUSED, | 
 | 		    disassemble_info *info, uint32_t insn, | 
 | 		    uint32_t parse_mode) | 
 | { | 
 |   int op = 0; | 
 |   fprintf_ftype func = info->fprintf_func; | 
 |   void *stream = info->stream; | 
 |   const char *pstr_src; | 
 |   char *pstr_tmp; | 
 |   char tmp_string[16]; | 
 |   unsigned int push25gpr = 0, lsmwRb, lsmwRe, lsmwEnb4, checkbit, i; | 
 |   int int_value, ifthe1st = 1; | 
 |   const field_t *pfd; | 
 |   const keyword_t *psys_reg; | 
 |  | 
 |   if (opc == NULL) | 
 |     { | 
 |       func (stream, UNKNOWN_INSN_MSG); | 
 |       return; | 
 |     } | 
 |  | 
 |   pstr_src = opc->instruction; | 
 |   if (*pstr_src == 0) | 
 |     { | 
 |       func (stream, "%s", opc->opcode); | 
 |       return; | 
 |     } | 
 |   /* NDS32_PARSE_INSN16.  */ | 
 |   if (parse_mode & NDS32_PARSE_INSN16) | 
 |     { | 
 |       func (stream, "%s ", opc->opcode); | 
 |     } | 
 |  | 
 |   /* NDS32_PARSE_INSN32.  */ | 
 |   else | 
 |     { | 
 |       op = N32_OP6 (insn); | 
 |       if (op == N32_OP6_LSMW) | 
 | 	func (stream, "%s.", opc->opcode); | 
 |       else if (strstr (opc->instruction, "tito")) | 
 | 	func (stream, "%s", opc->opcode); | 
 |       else | 
 | 	func (stream, "%s\t", opc->opcode); | 
 |     } | 
 |  | 
 |   while (*pstr_src) | 
 |     { | 
 |       switch (*pstr_src) | 
 | 	{ | 
 | 	case '%': | 
 | 	case '=': | 
 | 	case '&': | 
 | 	  pstr_src++; | 
 | 	  /* Compare with nds32_operand_fields[].name.  */ | 
 | 	  pstr_tmp = &tmp_string[0]; | 
 | 	  while (*pstr_src) | 
 | 	    { | 
 | 	      if ((*pstr_src == ',') || (*pstr_src == ' ') | 
 | 		  || (*pstr_src == '{') || (*pstr_src == '}') | 
 | 		  || (*pstr_src == '[') || (*pstr_src == ']') | 
 | 		  || (*pstr_src == '(') || (*pstr_src == ')') | 
 | 		  || (*pstr_src == '+') || (*pstr_src == '<')) | 
 | 		break; | 
 | 	      *pstr_tmp++ = *pstr_src++; | 
 | 	    } | 
 | 	  *pstr_tmp = 0; | 
 |  | 
 | 	  if ((pfd = match_field (&tmp_string[0])) == NULL) | 
 | 	    return; | 
 |  | 
 | 	  /* For insn-16.  */ | 
 | 	  if (parse_mode & NDS32_PARSE_INSN16) | 
 | 	    { | 
 | 	      if (pfd->hw_res == HW_GPR) | 
 | 		{ | 
 | 		  int_value = | 
 | 		    __GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; | 
 | 		  /* push25/pop25.  */ | 
 | 		  if ((opc->value == 0xfc00) || (opc->value == 0xfc80)) | 
 | 		    { | 
 | 		      if (int_value == 0) | 
 | 			int_value = 6; | 
 | 		      else | 
 | 			int_value = (6 + (0x01 << int_value)); | 
 | 		      push25gpr = int_value; | 
 | 		    } | 
 | 		  else if (strcmp (pfd->name, "rt4") == 0) | 
 | 		    { | 
 | 		      int_value = nds32_r45map[int_value]; | 
 | 		    } | 
 | 		  func (stream, "$%s", nds32_keyword_gpr[int_value].name); | 
 | 		} | 
 | 	      else if ((pfd->hw_res == HW_INT) || (pfd->hw_res == HW_UINT)) | 
 | 		{ | 
 | 		  if (pfd->hw_res == HW_INT) | 
 | 		    int_value | 
 | 		      = (unsigned) N32_IMMS (insn >> pfd->bitpos, | 
 | 					     pfd->bitsize) << pfd->shift; | 
 | 		  else | 
 | 		    int_value = | 
 | 		      __GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; | 
 |  | 
 | 		  /* movpi45.  */ | 
 | 		  if (opc->value == 0xfa00) | 
 | 		    { | 
 | 		      int_value += 16; | 
 | 		      func (stream, "#0x%x", int_value); | 
 | 		    } | 
 | 		  /* lwi45.fe.  */ | 
 | 		  else if (opc->value == 0xb200) | 
 | 		    { | 
 | 		      int_value = 0 - (128 - int_value); | 
 | 		      func (stream, "#%d", int_value); | 
 | 		    } | 
 | 		  /* beqz38/bnez38/beqs38/bnes38/j8/beqzs8/bnezs8.  */ | 
 | 		  else if ((opc->value == 0xc000) || (opc->value == 0xc800) | 
 | 			   || (opc->value == 0xd000) || (opc->value == 0xd800) | 
 | 			   || (opc->value == 0xd500) || (opc->value == 0xe800) | 
 | 			   || (opc->value == 0xe900)) | 
 | 		    { | 
 | 		      info->print_address_func (int_value + pc, info); | 
 | 		    } | 
 | 		  /* push25/pop25.  */ | 
 | 		  else if ((opc->value == 0xfc00) || (opc->value == 0xfc80)) | 
 | 		    { | 
 | 		      func (stream, "#%d    ! {$r6", int_value); | 
 | 		      if (push25gpr != 6) | 
 | 			func (stream, "~$%s", nds32_keyword_gpr[push25gpr].name); | 
 | 		      func (stream, ", $fp, $gp, $lp}"); | 
 | 		    } | 
 | 		  else if (pfd->hw_res == HW_INT) | 
 | 		    { | 
 | 		      if (int_value < 10) | 
 | 			func (stream, "#%d", int_value); | 
 | 		      else | 
 | 			func (stream, "#0x%x", int_value); | 
 | 		    } | 
 | 		  else /* if (pfd->hw_res == HW_UINT).  */ | 
 | 		    { | 
 | 		      if (int_value < 10) | 
 | 			func (stream, "#%u", int_value); | 
 | 		      else | 
 | 			func (stream, "#0x%x", int_value); | 
 | 		    } | 
 | 		} | 
 |  | 
 | 	    } | 
 | 	  /* for audio-ext.  */ | 
 | 	  else if (op == N32_OP6_AEXT) | 
 | 	    { | 
 | 	      nds32_parse_audio_ext (pfd, info, insn); | 
 | 	    } | 
 | 	  /* for insn-32.  */ | 
 | 	  else if (pfd->hw_res < HW_INT) | 
 | 	    { | 
 | 	      int_value = | 
 | 		__GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; | 
 |  | 
 | 	      psys_reg = *(nds32_keyword_table[pfd->hw_res >> 8] | 
 | 			   + (pfd->hw_res & 0xff)); | 
 |  | 
 | 	      psys_reg = nds32_find_reg_keyword (psys_reg, int_value); | 
 | 	      /* For HW_SR, dump the index when it can't | 
 | 		 map the register name.  */ | 
 | 	      if (!psys_reg && pfd->hw_res == HW_SR) | 
 | 		func (stream, "%d", int_value); | 
 | 	      else if (!psys_reg) | 
 | 		func (stream, "???"); | 
 | 	      else | 
 | 		{ | 
 | 		  if (pfd->hw_res == HW_GPR || pfd->hw_res == HW_CPR | 
 | 		      || pfd->hw_res == HW_FDR || pfd->hw_res == HW_FSR | 
 | 		      || pfd->hw_res == HW_DXR || pfd->hw_res == HW_SR | 
 | 		      || pfd->hw_res == HW_USR) | 
 | 		    func (stream, "$%s", psys_reg->name); | 
 | 		  else if (pfd->hw_res == HW_DTITON | 
 | 			   || pfd->hw_res == HW_DTITOFF) | 
 | 		    func (stream, ".%s", psys_reg->name); | 
 | 		  else | 
 | 		    func (stream, "%s", psys_reg->name); | 
 | 		} | 
 | 	    } | 
 | 	  else if ((pfd->hw_res == HW_INT) || (pfd->hw_res == HW_UINT)) | 
 | 	    { | 
 | 	      if (pfd->hw_res == HW_INT) | 
 | 		int_value = (unsigned) N32_IMMS (insn >> pfd->bitpos, | 
 | 						 pfd->bitsize) << pfd->shift; | 
 | 	      else | 
 | 		int_value = | 
 | 		  __GF (insn, pfd->bitpos, pfd->bitsize) << pfd->shift; | 
 |  | 
 | 	      if ((op == N32_OP6_BR1) || (op == N32_OP6_BR2)) | 
 | 		{ | 
 | 		  info->print_address_func (int_value + pc, info); | 
 | 		} | 
 | 	      else if ((op == N32_OP6_BR3) && (pfd->bitpos == 0)) | 
 | 		{ | 
 | 		  info->print_address_func (int_value + pc, info); | 
 | 		} | 
 | 	      else if (op == N32_OP6_JI) | 
 | 		{ | 
 | 		  /* FIXME: Handle relocation.  */ | 
 | 		  if (info->flags & INSN_HAS_RELOC) | 
 | 		    pc = 0; | 
 | 		  info->print_address_func (int_value + pc, info); | 
 | 		} | 
 | 	      else if (op == N32_OP6_LSMW) | 
 | 		{ | 
 | 		  /* lmw.adm/smw.adm.  */ | 
 | 		  func (stream, "#0x%x    ! {", int_value); | 
 | 		  lsmwEnb4 = int_value; | 
 | 		  lsmwRb = ((insn >> 20) & 0x1F); | 
 | 		  lsmwRe = ((insn >> 10) & 0x1F); | 
 |  | 
 | 		  /* If [Rb, Re] specifies at least one register, | 
 | 		     Rb(4,0) <= Re(4,0) and 0 <= Rb(4,0), Re(4,0) < 28. | 
 | 		     Disassembling does not consider this currently because of | 
 | 		     the convience comparing with bsp320.  */ | 
 | 		  if (lsmwRb != 31 || lsmwRe != 31) | 
 | 		    { | 
 | 		      func (stream, "$%s", nds32_keyword_gpr[lsmwRb].name); | 
 | 		      if (lsmwRb != lsmwRe) | 
 | 			func (stream, "~$%s", nds32_keyword_gpr[lsmwRe].name); | 
 | 		      ifthe1st = 0; | 
 | 		    } | 
 | 		  if (lsmwEnb4 != 0) | 
 | 		    { | 
 | 		      /* $fp, $gp, $lp, $sp.  */ | 
 | 		      checkbit = 0x08; | 
 | 		      for (i = 0; i < 4; i++) | 
 | 			{ | 
 | 			  if (lsmwEnb4 & checkbit) | 
 | 			    { | 
 | 			      if (ifthe1st == 1) | 
 | 				{ | 
 | 				  ifthe1st = 0; | 
 | 				  func (stream, "$%s", nds32_keyword_gpr[28 + i].name); | 
 | 				} | 
 | 			      else | 
 | 				func (stream, ", $%s", nds32_keyword_gpr[28 + i].name); | 
 | 			    } | 
 | 			  checkbit >>= 1; | 
 | 			} | 
 | 		    } | 
 | 		  func (stream, "}"); | 
 | 		} | 
 | 	      else if (pfd->hw_res == HW_INT) | 
 | 		{ | 
 | 		  if (int_value < 10) | 
 | 		    func (stream, "#%d", int_value); | 
 | 		  else | 
 | 		    func (stream, "#0x%x", int_value); | 
 | 		} | 
 | 	      else /* if (pfd->hw_res == HW_UINT).  */ | 
 | 		{ | 
 | 		  if (int_value < 10) | 
 | 		    func (stream, "#%u", int_value); | 
 | 		  else | 
 | 		    func (stream, "#0x%x", int_value); | 
 | 		} | 
 | 	    } | 
 | 	  break; | 
 |  | 
 | 	case '{': | 
 | 	case '}': | 
 | 	  pstr_src++; | 
 | 	  break; | 
 |  | 
 | 	case ',': | 
 | 	  func (stream, ", "); | 
 | 	  pstr_src++; | 
 | 	  break; | 
 | 	   | 
 | 	case '+': | 
 | 	  func (stream, " + "); | 
 | 	  pstr_src++; | 
 | 	  break; | 
 | 	   | 
 | 	case '<': | 
 | 	  if (pstr_src[1] == '<') | 
 | 	    { | 
 | 	      func (stream, " << "); | 
 | 	      pstr_src += 2; | 
 | 	    } | 
 | 	  else | 
 | 	    { | 
 | 	      func (stream, " <"); | 
 | 	      pstr_src++; | 
 | 	    } | 
 | 	  break; | 
 | 	   | 
 | 	default: | 
 | 	  func (stream, "%c", *pstr_src++); | 
 | 	  break; | 
 | 	} | 
 |     } | 
 | } | 
 |  | 
 | /* Filter instructions with some bits must be fixed.  */ | 
 |  | 
 | static void | 
 | nds32_filter_unknown_insn (uint32_t insn, struct nds32_opcode **opc) | 
 | { | 
 |   if (!(*opc)) | 
 |     return; | 
 |  | 
 |   switch ((*opc)->value) | 
 |     { | 
 |     case JREG (JR): | 
 |     case JREG (JRNEZ): | 
 |       /* jr jr.xtoff */ | 
 |       if (__GF (insn, 6, 2) != 0 || __GF (insn, 15, 10) != 0) | 
 |         *opc = NULL; | 
 |       break; | 
 |     case MISC (STANDBY): | 
 |       if (__GF (insn, 7, 18) != 0) | 
 |         *opc = NULL; | 
 |       break; | 
 |     case SIMD (PBSAD): | 
 |     case SIMD (PBSADA): | 
 |       if (__GF (insn, 5, 5) != 0) | 
 |         *opc = NULL; | 
 |       break; | 
 |     case BR2 (SOP0): | 
 |       if (__GF (insn, 20, 5) != 0) | 
 |         *opc = NULL; | 
 |       break; | 
 |     case JREG (JRAL): | 
 |       if (__GF (insn, 5, 3) != 0 || __GF (insn, 15, 5) != 0) | 
 |         *opc = NULL; | 
 |       break; | 
 |     case ALU1 (NOR): | 
 |     case ALU1 (SLT): | 
 |     case ALU1 (SLTS): | 
 |     case ALU1 (SLLI): | 
 |     case ALU1 (SRLI): | 
 |     case ALU1 (SRAI): | 
 |     case ALU1 (ROTRI): | 
 |     case ALU1 (SLL): | 
 |     case ALU1 (SRL): | 
 |     case ALU1 (SRA): | 
 |     case ALU1 (ROTR): | 
 |     case ALU1 (SEB): | 
 |     case ALU1 (SEH): | 
 |     case ALU1 (ZEH): | 
 |     case ALU1 (WSBH): | 
 |     case ALU1 (SVA): | 
 |     case ALU1 (SVS): | 
 |     case ALU1 (CMOVZ): | 
 |     case ALU1 (CMOVN): | 
 |       if (__GF (insn, 5, 5) != 0) | 
 |         *opc = NULL; | 
 |       break; | 
 |     case MISC (IRET): | 
 |     case MISC (ISB): | 
 |     case MISC (DSB): | 
 |       if (__GF (insn, 5, 20) != 0) | 
 |         *opc = NULL; | 
 |       break; | 
 |     } | 
 | } | 
 |  | 
 | static void | 
 | print_insn32 (bfd_vma pc, disassemble_info *info, uint32_t insn, | 
 | 	      uint32_t parse_mode) | 
 | { | 
 |   /* Get the final correct opcode and parse.  */ | 
 |   struct nds32_opcode *opc; | 
 |   uint32_t opcode = nds32_mask_opcode (insn); | 
 |   opc = (struct nds32_opcode *) htab_find (opcode_htab, &opcode); | 
 |  | 
 |   nds32_special_opcode (insn, &opc); | 
 |   nds32_filter_unknown_insn (insn, &opc); | 
 |   nds32_parse_opcode (opc, pc, info, insn, parse_mode); | 
 | } | 
 |  | 
 | static void | 
 | print_insn16 (bfd_vma pc, disassemble_info *info, | 
 | 	      uint32_t insn, uint32_t parse_mode) | 
 | { | 
 |   struct nds32_opcode *opc; | 
 |   uint32_t opcode; | 
 |  | 
 |   /* Get highest 7 bit in default.  */ | 
 |   unsigned int mask = 0xfe00; | 
 |  | 
 |   /* Classify 16-bit instruction to 4 sets by bit 13 and 14.  */ | 
 |   switch (__GF (insn, 13, 2)) | 
 |     { | 
 |     case 0x0: | 
 |       /* mov55 movi55 */ | 
 |       if (__GF (insn, 11, 2) == 0) | 
 | 	{ | 
 | 	  mask = 0xfc00; | 
 | 	  /* ifret16 = mov55 $sp, $sp*/ | 
 | 	  if (__GF (insn, 0, 11) == 0x3ff) | 
 | 	    mask = 0xffff; | 
 | 	} | 
 |       else if (__GF (insn, 9, 4) == 0xb) | 
 | 	mask = 0xfe07; | 
 |       break; | 
 |     case 0x1: | 
 |       /* lwi37 swi37 */ | 
 |       if (__GF (insn, 11, 2) == 0x3) | 
 | 	mask = 0xf880; | 
 |       break; | 
 |     case 0x2: | 
 |       mask = 0xf800; | 
 |       /* Exclude beqz38, bnez38, beqs38, and bnes38.  */ | 
 |       if (__GF (insn, 12, 1) == 0x1 | 
 | 	  && __GF (insn, 8, 3) == 0x5) | 
 | 	{ | 
 | 	  if (__GF (insn, 11, 1) == 0x0) | 
 | 	    mask = 0xff00; | 
 | 	  else | 
 | 	    mask = 0xffe0; | 
 | 	} | 
 |       break; | 
 |     case 0x3: | 
 |       switch (__GF (insn, 11, 2)) | 
 | 	{ | 
 | 	case 0x1: | 
 | 	  /* beqzs8 bnezs8 */ | 
 | 	  if (__GF (insn, 9, 2) == 0x0) | 
 | 	    mask = 0xff00; | 
 | 	  /* addi10s */ | 
 | 	  else if (__GF(insn, 10, 1) == 0x1) | 
 | 	    mask = 0xfc00; | 
 | 	  break; | 
 | 	case 0x2: | 
 | 	  /* lwi37.sp swi37.sp */ | 
 | 	  mask = 0xf880; | 
 | 	  break; | 
 | 	case 0x3: | 
 | 	  if (__GF (insn, 8, 3) == 0x5) | 
 | 	    mask = 0xff00; | 
 | 	  else if (__GF (insn, 8, 3) == 0x4) | 
 | 	    mask = 0xff80; | 
 | 	  else if (__GF (insn, 9 , 2) == 0x3) | 
 | 	    mask = 0xfe07; | 
 | 	  break; | 
 | 	} | 
 |       break; | 
 |     } | 
 |   opcode = insn & mask; | 
 |   opc = (struct nds32_opcode *) htab_find (opcode_htab, &opcode); | 
 |  | 
 |   nds32_special_opcode (insn, &opc); | 
 |   /* Get the final correct opcode and parse it.  */ | 
 |   nds32_parse_opcode (opc, pc, info, insn, parse_mode); | 
 | } | 
 |  | 
 | static hashval_t | 
 | htab_hash_hash (const void *p) | 
 | { | 
 |   return (*(unsigned int *) p) % 49; | 
 | } | 
 |  | 
 | static int | 
 | htab_hash_eq (const void *p, const void *q) | 
 | { | 
 |   uint32_t pinsn = ((struct nds32_opcode *) p)->value; | 
 |   uint32_t qinsn = *((uint32_t *) q); | 
 |  | 
 |   return (pinsn == qinsn); | 
 | } | 
 |  | 
 | /* Get the format of instruction.  */ | 
 |  | 
 | static uint32_t | 
 | nds32_mask_opcode (uint32_t insn) | 
 | { | 
 |   uint32_t opcode = N32_OP6 (insn); | 
 |   switch (opcode) | 
 |     { | 
 |     case N32_OP6_LBI: | 
 |     case N32_OP6_LHI: | 
 |     case N32_OP6_LWI: | 
 |     case N32_OP6_LDI: | 
 |     case N32_OP6_LBI_BI: | 
 |     case N32_OP6_LHI_BI: | 
 |     case N32_OP6_LWI_BI: | 
 |     case N32_OP6_LDI_BI: | 
 |     case N32_OP6_SBI: | 
 |     case N32_OP6_SHI: | 
 |     case N32_OP6_SWI: | 
 |     case N32_OP6_SDI: | 
 |     case N32_OP6_SBI_BI: | 
 |     case N32_OP6_SHI_BI: | 
 |     case N32_OP6_SWI_BI: | 
 |     case N32_OP6_SDI_BI: | 
 |     case N32_OP6_LBSI: | 
 |     case N32_OP6_LHSI: | 
 |     case N32_OP6_LWSI: | 
 |     case N32_OP6_LBSI_BI: | 
 |     case N32_OP6_LHSI_BI: | 
 |     case N32_OP6_LWSI_BI: | 
 |     case N32_OP6_MOVI: | 
 |     case N32_OP6_SETHI: | 
 |     case N32_OP6_ADDI: | 
 |     case N32_OP6_SUBRI: | 
 |     case N32_OP6_ANDI: | 
 |     case N32_OP6_XORI: | 
 |     case N32_OP6_ORI: | 
 |     case N32_OP6_SLTI: | 
 |     case N32_OP6_SLTSI: | 
 |     case N32_OP6_CEXT: | 
 |     case N32_OP6_BITCI: | 
 |       return MASK_OP (insn, 0); | 
 |     case N32_OP6_ALU2: | 
 |       /* FFBI */ | 
 |       if (__GF (insn, 0, 7) == (N32_ALU2_FFBI | N32_BIT (6))) | 
 | 	return MASK_OP (insn, 0x7f); | 
 |       else if (__GF (insn, 0, 7) == (N32_ALU2_MFUSR | N32_BIT (6)) | 
 | 	       || __GF (insn, 0, 7) == (N32_ALU2_MTUSR | N32_BIT (6))) | 
 | 	/* RDOV CLROV */ | 
 | 	return MASK_OP (insn, 0xf81ff); | 
 |       else if (__GF (insn, 0, 10) == (N32_ALU2_ONEOP | N32_BIT (7))) | 
 | 	{ | 
 | 	  /* INSB */ | 
 | 	  if (__GF (insn, 12, 3) == 4) | 
 | 	    return MASK_OP (insn, 0x73ff); | 
 | 	  return MASK_OP (insn, 0x7fff); | 
 | 	} | 
 |       return MASK_OP (insn, 0x3ff); | 
 |     case N32_OP6_ALU1: | 
 |     case N32_OP6_SIMD: | 
 |       return MASK_OP (insn, 0x1f); | 
 |     case N32_OP6_MEM: | 
 |       return MASK_OP (insn, 0xff); | 
 |     case N32_OP6_JREG: | 
 |       return MASK_OP (insn, 0x7f); | 
 |     case N32_OP6_LSMW: | 
 |       return MASK_OP (insn, 0x23); | 
 |     case N32_OP6_SBGP: | 
 |     case N32_OP6_LBGP: | 
 |       return MASK_OP (insn, 0x1 << 19); | 
 |     case N32_OP6_HWGP: | 
 |       if (__GF (insn, 18, 2) == 0x3) | 
 | 	return MASK_OP (insn, 0x7 << 17); | 
 |       return MASK_OP (insn, 0x3 << 18); | 
 |     case N32_OP6_DPREFI: | 
 |       return MASK_OP (insn, 0x1 << 24); | 
 |     case N32_OP6_LWC: | 
 |     case N32_OP6_SWC: | 
 |     case N32_OP6_LDC: | 
 |     case N32_OP6_SDC: | 
 |       return MASK_OP (insn, 0x1 << 12); | 
 |     case N32_OP6_JI: | 
 |       return MASK_OP (insn, 0x1 << 24); | 
 |     case N32_OP6_BR1: | 
 |       return MASK_OP (insn, 0x1 << 14); | 
 |     case N32_OP6_BR2: | 
 |       if (__GF (insn, 16, 4) == 0) | 
 | 	return MASK_OP (insn, 0x1ff << 16); | 
 |       else | 
 | 	return MASK_OP (insn, 0xf << 16); | 
 |     case N32_OP6_BR3: | 
 |       return MASK_OP (insn, 0x1 << 19); | 
 |     case N32_OP6_MISC: | 
 |       switch (__GF (insn, 0, 5)) | 
 | 	{ | 
 | 	case N32_MISC_MTSR: | 
 | 	  /* SETGIE and SETEND  */ | 
 | 	  if (__GF (insn, 5, 5) == 0x1 || __GF (insn, 5, 5) == 0x2) | 
 | 	    return MASK_OP (insn, 0x1fffff); | 
 | 	  return MASK_OP (insn, 0x1f); | 
 | 	case N32_MISC_TLBOP: | 
 | 	  if (__GF (insn, 5, 5) == 5 || __GF (insn, 5, 5) == 7) | 
 | 	    /* PB FLUA  */ | 
 | 	    return MASK_OP (insn, 0x3ff); | 
 | 	  return MASK_OP (insn, 0x1f); | 
 | 	default: | 
 | 	  return MASK_OP (insn, 0x1f); | 
 | 	} | 
 |     case N32_OP6_COP: | 
 |       if (__GF (insn, 4, 2) == 0) | 
 | 	{ | 
 | 	  /* FPU */ | 
 | 	  switch (__GF (insn, 0, 4)) | 
 | 	    { | 
 | 	    case 0x0: | 
 | 	    case 0x8: | 
 | 	      /* FS1/F2OP FD1/F2OP */ | 
 | 	      if (__GF (insn, 6, 4) == 0xf) | 
 | 		return MASK_OP (insn, 0x7fff); | 
 | 	      /* FS1 FD1 */ | 
 | 	      return MASK_OP (insn, 0x3ff); | 
 | 	    case 0x4: | 
 | 	    case 0xc: | 
 | 	      /* FS2 */ | 
 | 	      return MASK_OP (insn, 0x3ff); | 
 | 	    case 0x1: | 
 | 	    case 0x9: | 
 | 	      /* XR */ | 
 | 	      if (__GF (insn, 6, 4) == 0xc) | 
 | 		return MASK_OP (insn, 0x7fff); | 
 | 	      /* MFCP MTCP */ | 
 | 	      return MASK_OP (insn, 0x3ff); | 
 | 	    default: | 
 | 	      return MASK_OP (insn, 0xff); | 
 | 	    } | 
 | 	} | 
 |       else if  (__GF (insn, 0, 2) == 0) | 
 | 	return MASK_OP (insn, 0xf); | 
 |       return MASK_OP (insn, 0xcf); | 
 |     case N32_OP6_AEXT: | 
 |       /* AUDIO */ | 
 |       switch (__GF (insn, 23, 2)) | 
 | 	{ | 
 | 	case 0x0: | 
 | 	  if (__GF (insn, 5, 4) == 0) | 
 | 	    /* AMxxx AMAyyS AMyyS AMAWzS AMWzS */ | 
 | 	    return MASK_OP (insn, (0x1f << 20) | 0x1ff); | 
 | 	  else if (__GF (insn, 5, 4) == 1) | 
 | 	    /* ALR ASR ALA ASA AUPI */ | 
 | 	    return MASK_OP (insn, (0x1f << 20) | (0xf << 5)); | 
 | 	  else if (__GF (insn, 20, 3) == 0 && __GF (insn, 6, 3) == 1) | 
 | 	    /* ALR2 */ | 
 | 	    return MASK_OP (insn, (0x1f << 20) | (0x7 << 6)); | 
 | 	  else if (__GF (insn, 20 ,3) == 2 && __GF (insn, 6, 3) == 1) | 
 | 	    /* AWEXT ASATS48 */ | 
 | 	    return MASK_OP (insn, (0x1f << 20) | (0xf << 5)); | 
 | 	  else if (__GF (insn, 20 ,3) == 3 && __GF (insn, 6, 3) == 1) | 
 | 	    /* AMTAR AMTAR2 AMFAR AMFAR2 */ | 
 | 	    return MASK_OP (insn, (0x1f << 20) | (0x1f << 5)); | 
 | 	  else if (__GF (insn, 7, 2) == 3) | 
 | 	    /* AMxxxSA */ | 
 | 	    return MASK_OP (insn, (0x1f << 20) | (0x3 << 7)); | 
 | 	  else if (__GF (insn, 6, 3) == 2) | 
 | 	    /* AMxxxL.S  */ | 
 | 	    return MASK_OP (insn, (0x1f << 20) | (0xf << 5)); | 
 | 	  else | 
 | 	    /* AmxxxL.l AmxxxL2.S AMxxxL2.L  */ | 
 | 	    return MASK_OP (insn, (0x1f << 20) | (0x7 << 6)); | 
 | 	case 0x1: | 
 | 	  if (__GF (insn, 20, 3) == 0) | 
 | 	    /* AADDL ASUBL */ | 
 | 	    return MASK_OP (insn, (0x1f << 20) | (0x1 << 5)); | 
 | 	  else if (__GF (insn, 20, 3) == 1) | 
 | 	    /* AMTARI Ix AMTARI Mx */ | 
 | 	    return MASK_OP (insn, (0x1f << 20)); | 
 | 	  else if (__GF (insn, 6, 3) == 2) | 
 | 	    /* AMAWzSl.S AMWzSl.S */ | 
 | 	    return MASK_OP (insn, (0x1f << 20) | (0xf << 5)); | 
 | 	  else if (__GF (insn, 7, 2) == 3) | 
 | 	    /* AMAWzSSA AMWzSSA */ | 
 | 	    return MASK_OP (insn, (0x1f << 20) | (0x3 << 7)); | 
 | 	  else | 
 | 	    /* AMAWzSL.L AMAWzSL2.S AMAWzSL2.L | 
 | 	       AMWzSL.L AMWzSL.L AMWzSL2.S */ | 
 | 	    return MASK_OP (insn, (0x1f << 20) | (0x7 << 6)); | 
 | 	case 0x2: | 
 | 	  if (__GF (insn, 6, 3) == 2) | 
 | 	    /* AMAyySl.S AMWyySl.S */ | 
 | 	    return MASK_OP (insn, (0x1f << 20) | (0xf << 5)); | 
 | 	  else if (__GF (insn, 7, 2) == 3) | 
 | 	    /* AMAWyySSA AMWyySSA */ | 
 | 	    return MASK_OP (insn, (0x1f << 20) | (0x3 << 7)); | 
 | 	  else | 
 | 	    /* AMAWyySL.L AMAWyySL2.S AMAWyySL2.L | 
 | 	       AMWyySL.L AMWyySL.L AMWyySL2.S */ | 
 | 	    return MASK_OP (insn, (0x1f << 20) | (0x7 << 6)); | 
 | 	} | 
 |       return MASK_OP (insn, 0x1f << 20); | 
 |     default: | 
 |       return 1u << 31; | 
 |     } | 
 | } | 
 |  | 
 | /* Define cctl subtype.  */ | 
 | static char *cctl_subtype [] = | 
 | { | 
 |   /* 0x0 */ | 
 |   "st0", "st0", "st0", "st2", "st2", "st3", "st3", "st4", | 
 |   "st1", "st1", "st1", "st0", "st0", NULL, NULL, "st5", | 
 |   /* 0x10 */ | 
 |   "st0", NULL, NULL, "st2", "st2", "st3", "st3", NULL, | 
 |   "st1", NULL, NULL, "st0", "st0", NULL, NULL, NULL | 
 | }; | 
 |  | 
 | /* Check the subset of opcode.  */ | 
 |  | 
 | static void | 
 | nds32_special_opcode (uint32_t insn, struct nds32_opcode **opc) | 
 | { | 
 |   char *string = NULL; | 
 |   uint32_t op; | 
 |  | 
 |   if (!(*opc)) | 
 |     return; | 
 |  | 
 |   /* Check if special case.  */ | 
 |   switch ((*opc)->value) | 
 |     { | 
 |     case OP6 (LWC): | 
 |     case OP6 (SWC): | 
 |     case OP6 (LDC): | 
 |     case OP6 (SDC): | 
 |     case FPU_RA_IMMBI (LWC): | 
 |     case FPU_RA_IMMBI (SWC): | 
 |     case FPU_RA_IMMBI (LDC): | 
 |     case FPU_RA_IMMBI (SDC): | 
 |       /* Check if cp0 => FPU.  */ | 
 |       if (__GF (insn, 13, 2) == 0) | 
 |       { | 
 | 	while (!((*opc)->attr & ATTR (FPU)) && (*opc)->next) | 
 | 	  *opc = (*opc)->next; | 
 |       } | 
 |       break; | 
 |     case ALU1 (ADD): | 
 |     case ALU1 (SUB): | 
 |     case ALU1 (AND): | 
 |     case ALU1 (XOR): | 
 |     case ALU1 (OR): | 
 |       /* Check if (add/add_slli) (sub/sub_slli) (and/and_slli).  */ | 
 |       if (N32_SH5(insn) != 0) | 
 |         string = "sh"; | 
 |       break; | 
 |     case ALU1 (SRLI): | 
 |       /* Check if nop.  */ | 
 |       if (__GF (insn, 10, 15) == 0) | 
 |         string = "nop"; | 
 |       break; | 
 |     case MISC (CCTL): | 
 |       string = cctl_subtype [__GF (insn, 5, 5)]; | 
 |       break; | 
 |     case JREG (JR): | 
 |     case JREG (JRAL): | 
 |     case JREG (JR) | JREG_RET: | 
 |       if (__GF (insn, 8, 2) != 0) | 
 | 	string = "tit"; | 
 |       break; | 
 |     case N32_OP6_COP: | 
 |       break; | 
 |     case 0x9200: | 
 |       /* nop16 */ | 
 |       if (__GF (insn, 0, 9) == 0) | 
 | 	string = "nop16"; | 
 |       break; | 
 |     } | 
 |  | 
 |   if (string) | 
 |     { | 
 |       while (strstr ((*opc)->opcode, string) == NULL | 
 | 	     && strstr ((*opc)->instruction, string) == NULL && (*opc)->next) | 
 | 	*opc = (*opc)->next; | 
 |       return; | 
 |     } | 
 |  | 
 |   /* Classify instruction is COP or FPU.  */ | 
 |   op = N32_OP6 (insn); | 
 |   if (op == N32_OP6_COP && __GF (insn, 4, 2) != 0) | 
 |     { | 
 |       while (((*opc)->attr & ATTR (FPU)) != 0 && (*opc)->next) | 
 | 	*opc = (*opc)->next; | 
 |     } | 
 | } | 
 |  | 
 | int | 
 | print_insn_nds32 (bfd_vma pc, disassemble_info *info) | 
 | { | 
 |   int status; | 
 |   bfd_byte buf[4]; | 
 |   bfd_byte buf_data[16]; | 
 |   uint64_t given; | 
 |   uint64_t given1; | 
 |   uint32_t insn; | 
 |   int n; | 
 |   int last_symbol_index = -1; | 
 |   bfd_vma addr; | 
 |   int is_data = false; | 
 |   bool found = false; | 
 |   struct nds32_private_data *private_data; | 
 |   unsigned int size; | 
 |   enum map_type mapping_type = MAP_CODE; | 
 |  | 
 |   if (info->private_data == NULL) | 
 |     { | 
 |       /* Note: remain lifecycle throughout whole execution.  */ | 
 |       static struct nds32_private_data private; | 
 |       private.has_mapping_symbols = -1;	/* unknown yet.  */ | 
 |       private.last_symbol_index = -1; | 
 |       private.last_addr = 0; | 
 |       info->private_data = &private; | 
 |     } | 
 |   private_data = info->private_data; | 
 |  | 
 |   if (info->symtab_size != 0) | 
 |     { | 
 |       int start; | 
 |       if (pc == 0) | 
 | 	start = 0; | 
 |       else | 
 | 	{ | 
 | 	  start = info->symtab_pos; | 
 | 	  if (start < private_data->last_symbol_index) | 
 | 	    start = private_data->last_symbol_index; | 
 | 	} | 
 |  | 
 |       if (0 > start) | 
 | 	start = 0; | 
 |  | 
 |       if (private_data->has_mapping_symbols != 0 | 
 | 	  && ((strncmp (".text", info->section->name, 5) == 0))) | 
 | 	{ | 
 | 	  for (n = start; n < info->symtab_size; n++) | 
 | 	    { | 
 | 	      addr = bfd_asymbol_value (info->symtab[n]); | 
 | 	      if (addr > pc) | 
 | 		break; | 
 | 	      if (get_mapping_symbol_type (info, n, &mapping_type)) | 
 | 		{ | 
 | 		  last_symbol_index = n; | 
 | 		  found = true; | 
 | 		} | 
 | 	    } | 
 |  | 
 | 	  if (found) | 
 | 	    private_data->has_mapping_symbols = 1; | 
 | 	  else if (!found && private_data->has_mapping_symbols == -1) | 
 | 	    { | 
 | 	      /* Make sure there are no any mapping symbol.  */ | 
 | 	      for (n = 0; n < info->symtab_size; n++) | 
 | 		{ | 
 | 		  if (is_mapping_symbol (info, n, &mapping_type)) | 
 | 		    { | 
 | 		      private_data->has_mapping_symbols = -1; | 
 | 		      break; | 
 | 		    } | 
 | 		} | 
 | 	      if (private_data->has_mapping_symbols == -1) | 
 | 		private_data->has_mapping_symbols = 0; | 
 | 	    } | 
 |  | 
 | 	  private_data->last_symbol_index = last_symbol_index; | 
 | 	  private_data->last_mapping_type = mapping_type; | 
 | 	  is_data = (private_data->last_mapping_type == MAP_DATA0 | 
 | 		     || private_data->last_mapping_type == MAP_DATA1 | 
 | 		     || private_data->last_mapping_type == MAP_DATA2 | 
 | 		     || private_data->last_mapping_type == MAP_DATA3 | 
 | 		     || private_data->last_mapping_type == MAP_DATA4); | 
 | 	} | 
 |     } | 
 |  | 
 |   /* Wonder data or instruction.  */ | 
 |   if (is_data) | 
 |     { | 
 |       unsigned int i1; | 
 |  | 
 |       /* Fix corner case: there is no next mapping symbol, | 
 | 	 let mapping type decides size */ | 
 |       size = 16; | 
 |       if (last_symbol_index + 1 >= info->symtab_size) | 
 | 	{ | 
 | 	  if (mapping_type == MAP_DATA0) | 
 | 	    size = 1; | 
 | 	  if (mapping_type == MAP_DATA1) | 
 | 	    size = 2; | 
 | 	  if (mapping_type == MAP_DATA2) | 
 | 	    size = 4; | 
 | 	  if (mapping_type == MAP_DATA3) | 
 | 	    size = 8; | 
 | 	  if (mapping_type == MAP_DATA4) | 
 | 	    size = 16; | 
 | 	} | 
 |       for (n = last_symbol_index + 1; n < info->symtab_size; n++) | 
 | 	{ | 
 | 	  addr = bfd_asymbol_value (info->symtab[n]); | 
 |  | 
 | 	  enum map_type fake_mapping_type; | 
 | 	  if (get_mapping_symbol_type (info, n, &fake_mapping_type) | 
 | 	      && (addr > pc | 
 | 		  && ((info->section == NULL) | 
 | 		      || (info->section == info->symtab[n]->section))) | 
 | 	      && (addr - pc < size)) | 
 | 	    { | 
 | 	      size = addr - pc; | 
 | 	      break; | 
 | 	    } | 
 | 	} | 
 |  | 
 |       if (size == 3) | 
 | 	size = (pc & 1) ? 1 : 2; | 
 |  | 
 |       /* Read bytes from BFD.  */ | 
 |       info->read_memory_func (pc, buf_data, size, info); | 
 |       given = 0; | 
 |       given1 = 0; | 
 |       /* Start assembling data.  */ | 
 |       /* Little endian of data.  */ | 
 |       if (info->endian == BFD_ENDIAN_LITTLE) | 
 | 	{ | 
 | 	  for (i1 = size - 1;; i1--) | 
 | 	    { | 
 | 	      if (i1 >= 8) | 
 | 		given1 = buf_data[i1] | (given1 << 8); | 
 | 	      else | 
 | 		given = buf_data[i1] | (given << 8); | 
 |  | 
 | 	      if (i1 == 0) | 
 | 		break; | 
 | 	    } | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* Big endian of data.  */ | 
 | 	  for (i1 = 0; i1 < size; i1++) | 
 | 	    { | 
 | 	      if (i1 <= 7) | 
 | 		given = buf_data[i1] | (given << 8); | 
 | 	      else | 
 | 		given1 = buf_data[i1] | (given1 << 8); | 
 | 	    } | 
 | 	} | 
 |  | 
 |       info->bytes_per_line = 4; | 
 |  | 
 |       if (size == 16) | 
 | 	info->fprintf_func (info->stream, ".qword\t0x%016" PRIx64 "%016" PRIx64, | 
 | 			    given, given1); | 
 |       else if (size == 8) | 
 | 	info->fprintf_func (info->stream, ".dword\t0x%016" PRIx64, given); | 
 |       else if (size == 4) | 
 | 	info->fprintf_func (info->stream, ".word\t0x%08" PRIx64, given); | 
 |       else if (size == 2) | 
 | 	{ | 
 | 	  /* short */ | 
 | 	  if (mapping_type == MAP_DATA0) | 
 | 	    info->fprintf_func (info->stream, ".byte\t0x%02" PRIx64, | 
 | 				given & 0xFF); | 
 | 	  else | 
 | 	    info->fprintf_func (info->stream, ".short\t0x%04" PRIx64, given); | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  /* byte */ | 
 | 	  info->fprintf_func (info->stream, ".byte\t0x%02" PRIx64, given); | 
 | 	} | 
 |  | 
 |       return size; | 
 |     } | 
 |  | 
 |   size = 4; | 
 |   status = info->read_memory_func (pc, buf, 4, info); | 
 |   if (status) | 
 |     { | 
 |       /* For the last 16-bit instruction.  */ | 
 |       size = 2; | 
 |       status = info->read_memory_func (pc, buf, 2, info); | 
 |       if (status) | 
 | 	{ | 
 | 	  (*info->memory_error_func) (status, pc, info); | 
 | 	  return -1; | 
 | 	} | 
 |       buf[2] = 0; | 
 |       buf[3] = 0; | 
 |     } | 
 |  | 
 |   insn = bfd_getb32 (buf); | 
 |   /* 16-bit instruction.  */ | 
 |   if (insn & 0x80000000) | 
 |     { | 
 |       print_insn16 (pc, info, (insn >> 16), NDS32_PARSE_INSN16); | 
 |       return 2; | 
 |     } | 
 |  | 
 |   /* 32-bit instructions.  */ | 
 |   if (size == 4) | 
 |     print_insn32 (pc, info, insn, NDS32_PARSE_INSN32); | 
 |   else | 
 |     info->fprintf_func (info->stream, | 
 | 			_("insufficient data to decode instruction")); | 
 |   return 4; | 
 | } | 
 |  | 
 | /* Ignore disassembling unnecessary name.  */ | 
 |  | 
 | static bool | 
 | nds32_symbol_is_valid (asymbol *sym, | 
 | 		       struct disassemble_info *info ATTRIBUTE_UNUSED) | 
 | { | 
 |   const char *name; | 
 |  | 
 |   if (sym == NULL) | 
 |     return false; | 
 |  | 
 |   name = bfd_asymbol_name (sym); | 
 |  | 
 |   /* Mapping symbol is invalid.  */ | 
 |   if (name[0] == '$') | 
 |     return false; | 
 |   return true; | 
 | } | 
 |  | 
 | static void | 
 | nds32_add_opcode_hash_table (unsigned indx) | 
 | { | 
 |   opcode_t *opc; | 
 |  | 
 |   opc = nds32_opcode_table[indx]; | 
 |   if (opc == NULL) | 
 |     return; | 
 |  | 
 |   while (opc->opcode != NULL) | 
 |     { | 
 |       opcode_t **slot; | 
 |  | 
 |       slot = (opcode_t **) htab_find_slot | 
 | 	(opcode_htab, &opc->value, INSERT); | 
 |       if (*slot == NULL) | 
 | 	{ | 
 | 	  /* This is the new one.  */ | 
 | 	  *slot = opc; | 
 | 	} | 
 |       else | 
 | 	{ | 
 | 	  opcode_t *tmp; | 
 |  | 
 | 	  /* Already exists.  Append to the list.  */ | 
 | 	  tmp = *slot; | 
 | 	  while (tmp->next) | 
 | 	    tmp = tmp->next; | 
 | 	  tmp->next = opc; | 
 | 	  opc->next = NULL; | 
 | 	} | 
 |       opc++; | 
 |     } | 
 | } | 
 |  | 
 | void | 
 | disassemble_init_nds32 (struct disassemble_info *info) | 
 | { | 
 |   static unsigned init_done = 0; | 
 |   unsigned k; | 
 |  | 
 |   /* Set up symbol checking function.  */ | 
 |   info->symbol_is_valid = nds32_symbol_is_valid; | 
 |  | 
 |   /* Only need to initialize once: | 
 |      High level will call this function for every object file. | 
 |      For example, when disassemble all members of a library.  */ | 
 |   if (init_done) | 
 |     return; | 
 |  | 
 |   /* Setup main core.  */ | 
 |   nds32_keyword_table[NDS32_MAIN_CORE] = &nds32_keywords[0]; | 
 |   nds32_opcode_table[NDS32_MAIN_CORE] = &nds32_opcodes[0]; | 
 |   nds32_field_table[NDS32_MAIN_CORE] = &nds32_operand_fields[0]; | 
 |  | 
 |   /* Build opcode table.  */ | 
 |   opcode_htab = htab_create_alloc (1024, htab_hash_hash, htab_hash_eq, | 
 | 				   NULL, xcalloc, free); | 
 |  | 
 |   for (k = 0; k < NDS32_CORE_COUNT; k++) | 
 |     { | 
 |       /* Add op-codes.  */ | 
 |       nds32_add_opcode_hash_table (k); | 
 |     } | 
 |  | 
 |   init_done = 1; | 
 | } | 
 |  | 
 | static int | 
 | is_mapping_symbol (struct disassemble_info *info, int n, | 
 | 		   enum map_type *map_type) | 
 | { | 
 |   const char *name = NULL; | 
 |  | 
 |   /* Get symbol name.  */ | 
 |   name = bfd_asymbol_name (info->symtab[n]); | 
 |  | 
 |   if (name[1] == 'c') | 
 |     { | 
 |       *map_type = MAP_CODE; | 
 |       return true; | 
 |     } | 
 |   else if (name[1] == 'd' && name[2] == '0') | 
 |     { | 
 |       *map_type = MAP_DATA0; | 
 |       return true; | 
 |     } | 
 |   else if (name[1] == 'd' && name[2] == '1') | 
 |     { | 
 |       *map_type = MAP_DATA1; | 
 |       return true; | 
 |     } | 
 |   else if (name[1] == 'd' && name[2] == '2') | 
 |     { | 
 |       *map_type = MAP_DATA2; | 
 |       return true; | 
 |     } | 
 |   else if (name[1] == 'd' && name[2] == '3') | 
 |     { | 
 |       *map_type = MAP_DATA3; | 
 |       return true; | 
 |     } | 
 |   else if (name[1] == 'd' && name[2] == '4') | 
 |     { | 
 |       *map_type = MAP_DATA4; | 
 |       return true; | 
 |     } | 
 |  | 
 |   return false; | 
 | } | 
 |  | 
 | static int | 
 | get_mapping_symbol_type (struct disassemble_info *info, int n, | 
 | 			 enum map_type *map_type) | 
 | { | 
 |   /* If the symbol is in a different section, ignore it.  */ | 
 |   if (info->section != NULL | 
 |       && info->section != info->symtab[n]->section) | 
 |     return false; | 
 |  | 
 |   return is_mapping_symbol (info, n, map_type); | 
 | } |