binutils-gdb/opcodes/nds32-dis.c
Nick Clifton fbaf61ad52 Andes Technology has good news for you, we plan to update the nds32 port of binutils on upstream!
We have not only removed all unsupported and obsolete code, but also supported lost of new features,
including better link-time relaxations and TLS implementations. Besides, the files generated by the
newly assembler and linker usually get higher performance and more optimized code size.

ld	* emultempl/nds32elf.em (hyper_relax): New variable.
	(nds32_elf_create_output_section_statements):
	the parameters of bfd_elf32_nds32_set_target_option
	(PARSE_AND_LIST_PROLOGUE, PARSE_AND_LIST_OPTIONS,
	PARSE_AND_LIST_ARGS_CASES): Add new option --mhyper-relax.
	* emultempl/nds32elf.em (nds32_elf_after_open): Updated.
	* emultempl/nds32elf.em (tls_desc_trampoline): New variable.
	* (nds32_elf_create_output_section_statements): Updated.
	* (nds32_elf_after_parse): Disable relaxations when PIC is enable.
	* (PARSE_AND_LIST_PROLOGUE, PARSE_AND_LIST_OPTIONS,
	PARSE_AND_LIST_ARGS_CASES): Add new option --m[no-]tlsdesc-trampoline.

include	* elf/nds32.h: Remove the unused target features.
	* dis-asm.h (disassemble_init_nds32): Declared.
	* elf/nds32.h (E_NDS32_NULL): Removed.
	(E_NDS32_HAS_DSP_INST, E_NDS32_HAS_ZOL): New.
	* opcode/nds32.h: Ident.
	(N32_SUB6, INSN_LW): New macros.
	(enum n32_opcodes): Updated.
	* elf/nds32.h: Doc fixes.
	* elf/nds32.h: Add R_NDS32_LSI.
	* elf/nds32.h: Add new relocations for TLS.

gas 	* config/tc-nds32.c: Remove the unused target features.
	(nds32_relax_relocs, md_pseudo_table, nds32_elf_record_fixup_exp,
	nds32_set_elf_flags_by_insn, nds32_insert_relax_entry,
	nds32_apply_fix): Likewise.
	(nds32_no_ex9_begin): Removed.
	* config/tc-nds32.c (add_mapping_symbol_for_align,
	make_mapping_symbol, add_mapping_symbol): New functions.
	* config/tc-nds32.h (enum mstate): New.
	(nds32_segment_info_type): Likewise.
	* configure.ac (--enable-dsp-ext, --enable-zol-ext): New options.
	* config.in: Regenerated.
	* configure: Regenerated.
	* config/tc-nds32.c (nds32_dx_regs):
	Set the value according to the configuration.
	(nds32_perf_ext, nds32_perf_ext2, nds32_string_ext, nds32_audio_ext):
	Likewise.
	(nds32_dsp_ext): New variable. Set the value according to the
	configuration.
	(nds32_zol_ext): Likewise.
	(asm_desc, nds32_pseudo_opcode_table): Make them static.
	(nds32_set_elf_flags_by_insn): Updated.
	(nds32_check_insn_available): Updated.
	(nds32_str_tolower): New function.
	* config/tc-nds32.c (relax_table): Updated.
	(md_begin): Updated.
	(md_assemble): Use XNEW macro to allocate space for `insn.info',
	and then remember to free it.
	(md_section_align): Cast (-1) to ValueT.
	(nds32_get_align): Cast (~0U) to addressT.
	(nds32_relax_branch_instructions): Updated.
	(md_convert_frag): Add new local variable `final_r_type'.
	(invalid_prev_frag): Add new bfd_boolean parameter `relax'.
	All callers changed.
	* config/tc-nds32.c (struct nds32_relocs_pattern): Add `insn' field.
	(struct nds32_hint_map): Add `option_list' field.
	(struct suffix_name, suffix_table): Remove the unused `pic' field.
	(do_pseudo_b, do_pseudo_bal): Remove the suffix checking.
	(do_pseudo_la_internal, do_pseudo_pushpopm): Indent.
	(relax_hint_bias, relax_hint_id_current): New static variables.
	(reset_bias, relax_hint_begin): New variables.
	(nds_itoa): New function.
	(CLEAN_REG, GET_OPCODE): New macros.
	(struct relax_hint_id): New.
	(nds32_relax_hint): For .relax_hint directive, we can use `begin'
	and `end' to mark the relax pattern without giving exactly id number.
	(nds32_elf_append_relax_relocs): Handle the case that the .relax_hint
	directives are attached to pseudo instruction.
	(nds32_elf_save_pseudo_pattern): Change the second parameter from
	instruction's opcode to byte code.
	(nds32_elf_build_relax_relation): Add new bfd_boolean parameter
	`pseudo_hint'.
	(nds32_lookup_pseudo_opcode): Fix the overflow issue.
	(enum nds32_insn_type): Add N32_RELAX_ALU1 and N32_RELAX_16BIT.
	(nds32_elf_record_fixup_exp, relax_ls_table, hint_map,
	nds32_find_reloc_table, nds32_match_hint_insn, nds32_parse_name):
	Updated.
	* config/tc-nds32.h (MAX_RELAX_NUM): Extend it to 6.
	(enum nds32_relax_hint_type): Merge NDS32_RELAX_HINT_LA and
	NDS32_RELAX_HINT_LS into NDS32_RELAX_HINT_LALS. Add
	NDS32_RELAX_HINT_LA_PLT, NDS32_RELAX_HINT_LA_GOT and
	NDS32_RELAX_HINT_LA_GOTOFF.
	* config/tc-nds32.h (relax_ls_table): Add floating load/store
	to gp relax pattern.
	(hint_map, nds32_find_reloc_table): Likewise.
	* configure.ac: Define NDS32_LINUX_TOOLCHAIN.
	* configure: Regenerated.
	* config.in: Regenerated.
	* config/tc-nds32.h (enum nds32_ramp): Updated.
	(enum nds32_relax_hint_type): Likewise.
	* config/tc-nds32.c: Include "errno.h" and "limits.h".
	(relax_ls_table): Add TLS relax patterns.
	(nds32_elf_append_relax_relocs): Attach BFD_RELOC_NDS32_GROUP on
	each instructions of TLS patterns.
	(nds32_elf_record_fixup_exp): Updated.
	(nds32_apply_fix): Likewise.
	(suffix_table): Add TLSDESC suffix.

binutils* testsuite/binutils-all/objcopy.exp: Set the unsupported reloc number
	from 215 to 255 for NDS32.

bfd	* elf32-nds32.c (nds32_elf_relax_loadstore):
	Remove the unused target features.
	(bfd_elf32_nds32_set_target_option): Remove the unused parameters.
	(nds32_elf_relax_piclo12, nds32_elf_relax_letlslo12,
	nds32_elf_relax_letlsadd, nds32_elf_relax_letlsls,
	nds32_elf_relax_pltgot_suff, nds32_elf_relax_got_suff
	nds32_elf_relax_gotoff_suff, calculate_plt_memory_address,
	calculate_plt_offset, calculate_got_memory_address,
	nds32_elf_check_dup_relocs): Removed.
	All callers changed.
	* elf32-nds32.h: Remove the unused macros and defines.
	(elf_nds32_link_hash_table): Remove the unused variable.
	(bfd_elf32_nds32_set_target_option): Update prototype.
	(nds32_elf_ex9_init): Removed.
	* elf32-nds32.c (nds32_convert_32_to_16): Updated.
	* elf32-nds32.c (HOWTO2, HOWTO3): Define new HOWTO macros
	to initialize array nds32_elf_howto_table in any order
	without lots of EMPTY_HOWTO.
	(nds32_reloc_map): Updated.
	* reloc.c: Add BFD_RELOC_NDS32_LSI.
	* bfd-in2.h: Regenerated.
	* bfd/libbfd.h: Regenerated.
	* elf32-nds32.c (nds32_elf_relax_howto_table): Add R_NDS32_LSI.
	(nds32_reloc_map): Likewise.
	(nds32_elf_relax_flsi): New function.
	(nds32_elf_relax_section): Support floating load/store relaxation.
	* elf32-nds32.c (NDS32_GUARD_SEC_P, elf32_nds32_local_gp_offset):
	New macro.
	(struct elf_nds32_link_hash_entry): New `offset_to_gp' field.
	(struct elf_nds32_obj_tdata): New `offset_to_gp' and `hdr_size' fields.
	(elf32_nds32_allocate_local_sym_info, nds32_elf_relax_guard,
	nds32_elf_is_target_special_symbol, nds32_elf_maybe_function_sym):
	New functions.
	(nds32_info_to_howto_rel): Add BFD_ASSERT.
	(bfd_elf32_bfd_reloc_type_table_lookup, nds32_elf_link_hash_newfunc,
	nds32_elf_link_hash_table_create, nds32_elf_relocate_section,
	nds32_elf_relax_loadstore, nds32_elf_relax_lo12, nds32_relax_adjust_label,
	bfd_elf32_nds32_set_target_option, nds32_fag_mark_relax): Updated.
	(nds32_elf_final_sda_base): Improve it to find the better gp value.
	(insert_nds32_elf_blank): Must consider `len' when inserting blanks.
	* elf32-nds32.h (bfd_elf32_nds32_set_target_option): Update prototype.
	(struct elf_nds32_link_hash_table): Add new variable `hyper_relax'.
	* elf32-nds32.c (elf32_nds32_allocate_dynrelocs): New function.
	(create_got_section): Likewise.
	(allocate_dynrelocs, nds32_elf_size_dynamic_sections,
	nds32_elf_relocate_section, nds32_elf_finish_dynamic_symbol): Updated.
	(nds32_elf_check_relocs): Fix the issue that the shared library may
	has TEXTREL entry in the dynamic section.
	(nds32_elf_create_dynamic_sections): Enable to call readonly_dynrelocs
	since the TEXTREL issue is fixed in the nds32_elf_check_relocs.
	(nds32_elf_finish_dynamic_sections): Update and add DT_RELASZ
	dynamic entry.
	(calculate_offset): Remove the unused parameter `pic_ext_target' and
	related codes.
	All callers changed.
	(elf_backend_dtrel_excludes_plt): Disable it temporarily since it
	will cause some errors for our test cases.
	* elf32-nds32.c (nds32_elf_merge_private_bfd_data): Allow to link the
	generic object.
	* reloc.c: Add TLS relocations.
	* libbfd.h: Regenerated.
	* bfd-in2.h: Regenerated.
	* elf32-nds32.h (struct section_id_list_t): New.
	(elf32_nds32_lookup_section_id, elf32_nds32_check_relax_group,
	elf32_nds32_unify_relax_group, nds32_elf_unify_tls_model):
	New prototypes.
	(elf32_nds32_compute_jump_table_size, elf32_nds32_local_tlsdesc_gotent):
	New macro.
	(nds32_insertion_sort, bfd_elf32_nds32_set_target_option,
	elf_nds32_link_hash_table): Updated.
	* elf32-nds32.c (enum elf_nds32_tls_type): New.
	(struct elf32_nds32_relax_group_t, struct relax_group_list_t): New.
	(elf32_nds32_add_dynreloc, patch_tls_desc_to_ie, get_tls_type,
	fls, ones32, list_insert, list_insert_sibling, dump_chain,
	elf32_nds32_check_relax_group, elf32_nds32_lookup_section_id,
	elf32_nds32_unify_relax_group, nds32_elf_unify_tls_model): New functions.
	(elf_nds32_obj_tdata): Add new fields.
	(elf32_nds32_relax_group_ptr, nds32_elf_local_tlsdesc_gotent): New macros.
	(nds32_elf_howto_table): Add TLS relocations.
	(nds32_reloc_map): Likewise.
	(nds32_elf_copy_indirect_symbol, nds32_elf_size_dynamic_sections,
	nds32_elf_finish_dynamic_symbol, elf32_nds32_allocate_local_sym_info,
	nds32_elf_relocate_section, bfd_elf32_nds32_set_target_option,
	nds32_elf_check_relocs, allocate_dynrelocs): Updated.
	(nds32_elf_relax_section): Call nds32_elf_unify_tls_model.
	(dtpoff_base): Rename it to `gottpof' and then update it.

opcodes	* nds32-asm.c (operand_fields): Remove the unused fields.
	(nds32_opcodes): Remove the unused instructions.
	* nds32-dis.c (nds32_ex9_info): Removed.
	(nds32_parse_opcode): Updated.
	(print_insn_nds32): Likewise.
	* nds32-asm.c (config.h, stdlib.h, string.h): New includes.
	(LEX_SET_FIELD, LEX_GET_FIELD): Update defines.
	(nds32_asm_init, build_operand_hash_table, build_keyword_hash_table,
	build_opcode_hash_table): New functions.
	(nds32_keyword_table, nds32_keyword_count_table, nds32_field_table,
	nds32_opcode_table): New.
	(hw_ktabs): Declare it to a pointer rather than an array.
	(build_hash_table): Removed.
	* nds32-asm.h (enum): Add SYN_INPUT, SYN_OUTPUT, SYN_LOPT,
	SYN_ROPT and upadte HW_GPR and HW_INT.
	* nds32-dis.c (keywords): Remove const.
	(match_field): New function.
	(nds32_parse_opcode): Updated.
	* disassemble.c (disassemble_init_for_target):
	Add disassemble_init_nds32.
	* nds32-dis.c (eum map_type): New.
	(nds32_private_data): Likewise.
	(get_mapping_symbol_type, is_mapping_symbol, nds32_symbol_is_valid,
	nds32_add_opcode_hash_table, disassemble_init_nds32): New functions.
	(print_insn_nds32): Updated.
	* nds32-asm.c (parse_aext_reg): Add new parameter.
	(parse_re, parse_re2, parse_aext_reg): Only reduced registers
	are allowed to use.
	All callers changed.
	* nds32-asm.c (keyword_usr, keyword_sr): Updated.
	(operand_fields): Add new fields.
	(nds32_opcodes): Add new instructions.
	(keyword_aridxi_mx): New keyword.
	* nds32-asm.h (enum): Add NASM_ATTR_DSP_ISAEXT, HW_AEXT_ARIDXI_MX
	and NASM_ATTR_ZOL.
	(ALU2_1, ALU2_2, ALU2_3): New macros.
	* nds32-dis.c (nds32_filter_unknown_insn): Updated.
2018-09-20 13:32:58 +01:00

1339 lines
32 KiB
C

/* NDS32-specific support for 32-bit ELF.
Copyright (C) 2012-2018 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 "bfd_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
extern const field_t *nds32_field_table[NDS32_CORE_COUNT];
extern opcode_t *nds32_opcode_table[NDS32_CORE_COUNT];
extern keyword_t **nds32_keyword_table[NDS32_CORE_COUNT];
extern struct nds32_opcode nds32_opcodes[];
extern const field_t operand_fields[];
extern keyword_t *keywords[];
extern const keyword_t keyword_gpr[];
static void print_insn16 (bfd_vma pc, disassemble_info *info,
uint32_t insn, uint32_t parse_mode);
static void print_insn32 (bfd_vma pc, disassemble_info *info, uint32_t insn,
uint32_t parse_mode);
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 *);
/* define in objdump.c. */
struct objdump_disasm_info
{
bfd * abfd;
asection * sec;
bfd_boolean require_sec;
arelent ** dynrelbuf;
long dynrelcount;
disassembler_ftype disassemble_fn;
arelent * reloc;
};
/* Hash function for disassemble. */
static htab_t opcode_htab;
/* Find the value map register name. */
static keyword_t *
nds32_find_reg_keyword (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;
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 =
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*) 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;
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 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", 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 =
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", 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 =
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", keyword_gpr[lsmwRb].name);
if (lsmwRb != lsmwRe)
func (stream, "~$%s", 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", keyword_gpr[28 + i].name);
}
else
func (stream, ", $%s", 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 (1 << 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];
long long given;
long long given1;
uint32_t insn;
int n;
int last_symbol_index = -1;
bfd_vma addr;
int is_data = FALSE;
bfd_boolean found = FALSE;
struct nds32_private_data *private_data;
unsigned int size = 16;
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 */
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, (bfd_byte *) 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%016llx%016llx",
given, given1);
else if (size == 8)
info->fprintf_func (info->stream, ".dword\t0x%016llx", given);
else if (size == 4)
info->fprintf_func (info->stream, ".word\t0x%08llx", given);
else if (size == 2)
{
/* short */
if (mapping_type == MAP_DATA0)
info->fprintf_func (info->stream, ".byte\t0x%02llx", given & 0xFF);
else
info->fprintf_func (info->stream, ".short\t0x%04llx", given);
}
else
{
/* byte */
info->fprintf_func (info->stream, ".byte\t0x%02llx", given);
}
return size;
}
status = info->read_memory_func (pc, (bfd_byte *) buf, 4, info);
if (status)
{
/* For the last 16-bit instruction. */
status = info->read_memory_func (pc, (bfd_byte *) buf, 2, info);
if (status)
{
(*info->memory_error_func)(status, pc, info);
return -1;
}
}
insn = bfd_getb32 (buf);
/* 16-bit instruction. */
if (insn & 0x80000000)
{
print_insn16 (pc, info, (insn >> 16), NDS32_PARSE_INSN16);
return 2;
}
/* 32-bit instructions. */
else
{
print_insn32 (pc, info, insn, NDS32_PARSE_INSN32);
return 4;
}
}
/* Ignore disassembling unnecessary name. */
static bfd_boolean
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] = &keywords[0];
nds32_opcode_table[NDS32_MAIN_CORE] = &nds32_opcodes[0];
nds32_field_table[NDS32_MAIN_CORE] = &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);
}