diff --git a/gas/Makefile.am b/gas/Makefile.am index b85755d..aec1631 100644 --- a/gas/Makefile.am +++ b/gas/Makefile.am @@ -164,6 +164,7 @@ TARGET_CPU_CFILES = \ config/tc-moxie.c \ config/tc-msp430.c \ config/tc-mt.c \ + config/tc-nds32.c \ config/tc-nios2.c \ config/tc-ns32k.c \ config/tc-openrisc.c \ @@ -235,6 +236,7 @@ TARGET_CPU_HFILES = \ config/tc-mn10300.h \ config/tc-msp430.h \ config/tc-mt.h \ + config/tc-nds32.h \ config/tc-nios2.h \ config/tc-ns32k.h \ config/tc-openrisc.h \ diff --git a/gas/NEWS b/gas/NEWS index fc1514e..2e62450 100644 --- a/gas/NEWS +++ b/gas/NEWS @@ -1,5 +1,7 @@ -*- text -*- +* Add support for the Andes NDS32. + Changes in 2.24: * Add support for the Texas Instruments MSP430X processor. diff --git a/gas/config/tc-nds32.c b/gas/config/tc-nds32.c new file mode 100644 index 0000000..793e5c9 --- /dev/null +++ b/gas/config/tc-nds32.c @@ -0,0 +1,5913 @@ +/* tc-nds32.c -- Assemble for the nds32 + Copyright (C) 2012-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + This file is part of GAS, the GNU Assembler. + + GAS 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, or (at your option) + any later version. + + GAS 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 GAS; see the file COPYING. If not, write to the Free + Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#include "as.h" +#include "safe-ctype.h" +#include "subsegs.h" +#include "symcat.h" +#include "dwarf2dbg.h" +#include "dw2gencfi.h" +#include "opcodes/nds32-asm.h" +#include "elf/nds32.h" +#include "bfd/elf32-nds32.h" +#include "hash.h" +#include "sb.h" +#include "macro.h" +#include "struc-symbol.h" +#include "opcode/nds32.h" + +#include + +/* GAS definitions. */ + +/* Characters which start a comment. */ +const char comment_chars[] = "!"; +/* Characters which start a comment when they appear at the start of a line. */ +const char line_comment_chars[] = "#!"; +/* Characters which separate lines (null and newline are by default). */ +const char line_separator_chars[] = ";"; +/* Characters which may be used as the exponent character + in a floating point number. */ +const char EXP_CHARS[] = "eE"; +/* Characters which may be used to indicate a floating point constant. */ +const char FLT_CHARS[] = "dDfF"; + +static int enable_16bit = 1; +/* Save for md_assemble to distinguish if this instruction is + expanded from the pseudo instruction. */ +static bfd_boolean pseudo_opcode = FALSE; +static struct nds32_relocs_pattern *relocs_list = NULL; +struct nds32_relocs_pattern +{ + segT seg; + fragS *frag; + frchainS *frchain; + symbolS *sym; + int reloc; + unsigned int insn; + unsigned int size; + char *where; + struct nds32_relocs_pattern *next; +}; +/* +static int relax_jal_bound = 3; +static int multi_call_relax; +static int pltgot_call_relax; +*/ +static int vec_size = 0; +/* If the assembly code is generated by compiler, it is supposed to have + ".flag verbatim" at beginning of the content. We have + 'nds32_flag' to parse it and set this field to be non-zero. */ +static int verbatim = 0; +static struct hash_control *nds32_gprs_hash; +static struct hash_control *nds32_hint_hash; + +/* Generate relocation for relax or not, and the default is true. */ +static int enable_relax_relocs = 1; +/* The value will be used in RELAX_ENTRY. */ +static int enable_relax_ex9 = 0; +/* The value will be used in RELAX_ENTRY. */ +static int enable_relax_ifc = 0; +/* Save option -O for perfomance. */ +static int optimize = 0; +/* Save option -Os for code size. */ +static int optimize_for_space = 0; + +struct nds32_keyword nds32_fsrs[] = { + /* Standard names. */ + {"$fs0", 0, 0}, {"$fs1", 1, 0}, {"$fs2", 2, 0}, {"$fs3", 3, 0}, + {"$fs4", 4, 0}, {"$fs5", 5, 0}, {"$fs6", 6, 0}, {"$fs7", 7, 0}, + {"$fs8", 8, 0}, {"$fs9", 9, 0}, {"$fs10", 10, 0}, {"$fs11", 11, 0}, + {"$fs12", 12, 0}, {"$fs13", 13, 0}, {"$fs14", 14, 0}, {"$fs15", 15, 0}, + {"$fs16", 16, 0}, {"$fs17", 17, 0}, {"$fs18", 18, 0}, {"$fs19", 19, 0}, + {"$fs20", 20, 0}, {"$fs21", 21, 0}, {"$fs22", 22, 0}, {"$fs23", 23, 0}, + {"$fs24", 24, 0}, {"$fs25", 25, 0}, {"$fs26", 26, 0}, {"$fs27", 27, 0}, + {"$fs28", 28, 0}, {"$fs29", 29, 0}, {"$fs30", 30, 0}, {"$fs31", 31, 0}, + {NULL, 0, 0} +}; + +struct nds32_keyword nds32_fdrs[] = { + /* Standard names. */ + {"$fd0", 0, 0}, {"$fd1", 1, 0}, {"$fd2", 2, 0}, {"$fd3", 3, 0}, + {"$fd4", 4, 0}, {"$fd5", 5, 0}, {"$fd6", 6, 0}, {"$fd7", 7, 0}, + {"$fd8", 8, 0}, {"$fd9", 9, 0}, {"$fd10", 10, 0}, {"$fd11", 11, 0}, + {"$fd12", 12, 0}, {"$fd13", 13, 0}, {"$fd14", 14, 0}, {"$fd15", 15, 0}, + {"$fd16", 16, 0}, {"$fd17", 17, 0}, {"$fd18", 18, 0}, {"$fd19", 19, 0}, + {"$fd20", 20, 0}, {"$fd21", 21, 0}, {"$fd22", 22, 0}, {"$fd23", 23, 0}, + {"$fd24", 24, 0}, {"$fd25", 25, 0}, {"$fd26", 26, 0}, {"$fd27", 27, 0}, + {"$fd28", 28, 0}, {"$fd29", 29, 0}, {"$fd30", 30, 0}, {"$fd31", 31, 0}, + {NULL, 0, 0} +}; + +struct nds32_keyword nds32_gprs[] = { + /* Standard names. */ + {"$r0", 0, 0}, {"$r1", 1, 0}, {"$r2", 2, 0}, {"$r3", 3, 0}, + {"$r4", 4, 0}, {"$r5", 5, 0}, {"$r6", 6, 0}, {"$r7", 7, 0}, + {"$r8", 8, 0}, {"$r9", 9, 0}, {"$r10", 10, 0}, {"$r11", 11, 0}, + {"$r12", 12, 0}, {"$r13", 13, 0}, {"$r14", 14, 0}, {"$r15", 15, 0}, + {"$r16", 16, 0}, {"$r17", 17, 0}, {"$r18", 18, 0}, {"$r19", 19, 0}, + {"$r20", 20, 0}, {"$r21", 21, 0}, {"$r22", 22, 0}, {"$r23", 23, 0}, + {"$r24", 24, 0}, {"$r25", 25, 0}, {"$r26", 26, 0}, {"$r27", 27, 0}, + {"$r28", 28, 0}, {"$r29", 29, 0}, {"$r30", 30, 0}, {"$r31", 31, 0}, + /* Names for parameter passing. */ + {"$a0", 0, 0}, {"$a1", 1, 0}, {"$a2", 2, 0}, {"$a3", 3, 0}, + {"$a4", 4, 0}, {"$a5", 5, 0}, + /* Names reserved for 5-bit addressing only. */ + {"$s0", 6, 0}, {"$s1", 7, 0}, {"$s2", 8, 0}, {"$s3", 9, 0}, + {"$s4", 10, 0}, {"$s5", 11, 0}, {"$s6", 12, 0}, {"$s7", 13, 0}, + {"$s8", 14, 0}, {"$s9", 28, 0}, + {"$ta", 15, 0}, + {"$t0", 16, 0}, {"$t1", 17, 0}, {"$t2", 18, 0}, {"$t3", 19, 0}, + {"$t4", 20, 0}, {"$t5", 21, 0}, {"$t6", 22, 0}, {"$t7", 23, 0}, + {"$t8", 24, 0}, {"$t9", 25, 0}, + {"$p0", 26, 0}, {"$p1", 27, 0}, + {"$fp", 28, 0}, {"$gp", 29, 0}, {"$lp", 30, 0}, {"$sp", 31, 0}, + /* Names reserved for 4-bit addressing only. */ + {"$h0", 0, 0}, {"$h1", 1, 0}, {"$h2", 2, 0}, {"$h3", 3, 0}, + {"$h4", 4, 0}, {"$h5", 5, 0}, {"$h6", 6, 0}, {"$h7", 7, 0}, + {"$h8", 8, 0}, {"$h9", 9, 0}, {"$h10", 10, 0}, {"$h11", 11, 0}, + {"$h12", 16, 0}, {"$h13", 17, 0}, {"$h14", 18, 0}, {"$h15", 19, 0}, + /* Names reserved for 3-bit addressing only. */ + {"$o0", 0, 0}, {"$o1", 1, 0}, {"$o2", 2, 0}, {"$o3", 3, 0}, + {"$o4", 4, 0}, {"$o5", 5, 0}, {"$o6", 6, 0}, {"$o7", 7, 0}, + {NULL, 0, 0} +}; + + +static struct hash_control *nds32_relax_info_hash; +static relax_info_t relax_table[] = +{ + { + "jal", /* opcode */ + BR_RANGE_S16M, /* br_range */ + {{0, 0, 0}}, /* cond_field */ + { + { + INSN_JAL /* jal label */ + }, /* BR_RANGE_S256 */ + { + INSN_JAL /* jal label */ + }, /* BR_RANGE_S16K */ + { + INSN_JAL /* jal label */ + }, /* BR_RANGE_S64K */ + { + INSN_JAL /* jal label */ + }, /* BR_RANGE_S16M */ + { + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JRAL_TA + }, /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + {{0, 0, 0}}, /* BR_RANGE_S256 */ + {{0, 0, 0}}, /* BR_RANGE_S16K */ + {{0, 0, 0}}, /* BR_RANGE_S64K */ + {{0, 0, 0}}, /* BR_RANGE_S16M */ + {{0, 0, 0}} /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 4, 4, 4, 12}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, 0, BFD_RELOC_NDS32_HI20}, + {0, 12, NDS32_RELAX, BFD_RELOC_NDS32_LONGCALL1}, + {4, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_ORIGIN, 0}, + {8, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "bltzal", /* opcode */ + BR_RANGE_S64K, /* br_range */ + { + {0, 20, 0x1F}, + { 0, 0, 0 } + }, /* cond_field */ + { + { + INSN_BLTZAL /* bltzal $rt, label */ + }, /* BR_RANGE_S256 */ + { + INSN_BLTZAL /* bltzal $rt, label */ + }, /* BR_RANGE_S16K */ + { + INSN_BLTZAL /* bltzal $rt, label */ + }, /* BR_RANGE_S64K */ + { + INSN_BGEZ, /* bgez $rt, $1 */ + INSN_JAL /* jal label */ + }, /* BR_RANGE_S16M */ + { + INSN_BGEZ, /* bgez $rt, $1 */ + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JRAL_TA /* jral $ta */ + } /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 20, 0x1F}, + {0, 0, 0} + } /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 4, 4, 8, 16}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_17_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGCALL2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_17_PCREL}, + {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGCALL3}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_ORIGIN, 0}, + {12, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "bgezal", /* opcode */ + BR_RANGE_S64K, /* br_range */ + { + {0, 20, 0x1F}, + { 0, 0, 0 } + }, /* cond_field */ + { + { + INSN_BGEZAL /* bgezal $rt, label */ + }, /* BR_RANGE_S256 */ + { + INSN_BGEZAL /* bgezal $rt, label */ + }, /* BR_RANGE_S16K */ + { + INSN_BGEZAL /* bgezal $rt, label */ + }, /* BR_RANGE_S64K */ + { + INSN_BLTZ, /* bltz $rt, $1 */ + INSN_JAL /* jal label */ + }, /* BR_RANGE_S16M */ + { + INSN_BLTZ, /* bltz $rt, $1 */ + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JRAL_TA /* jral $ta */ + } /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 20, 0x1F}, + {0, 0, 0} + } /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 4, 4, 8, 16}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_17_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGCALL2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_17_PCREL}, + {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGCALL3}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_ORIGIN, 0}, + {12, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "j", /* opcode */ + BR_RANGE_S16M, /* br_range */ + {{0, 0, 0}}, /* cond_field */ + { + { + (INSN_J8 << 16) /* j8 label */ + }, /* BR_RANGE_S256 */ + { + INSN_J /* j label */ + }, /* BR_RANGE_S16K */ + { + INSN_J /* j label */ + }, /* BR_RANGE_S64K */ + { + INSN_J /* j label */ + }, /* BR_RANGE_S16M */ + { + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JR_TA /* jr $ta */ + }, /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + {{0, 0, 0}}, /* BR_RANGE_S256 */ + {{0, 0, 0}}, /* BR_RANGE_S16K */ + {{0, 0, 0}}, /* BR_RANGE_S64K */ + {{0, 0, 0}}, /* BR_RANGE_S16M */ + {{0, 0, 0}} /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {2, 4, 4, 4, 12}, /* relax_code_size */ + {2, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 2, 0, BFD_RELOC_NDS32_9_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, 0, BFD_RELOC_NDS32_HI20}, + {0, 12, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP1}, + {4, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_ORIGIN, 0}, + {8, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "j8", /* opcode */ + BR_RANGE_S256, /* br_range */ + {{0, 0, 0}}, /* cond_field */ + { + { + (INSN_J8 << 16) /* j8 label */ + }, /* BR_RANGE_S256 */ + { + INSN_J /* j label */ + }, /* BR_RANGE_S16K */ + { + INSN_J /* j label */ + }, /* BR_RANGE_S64K */ + { + INSN_J /* j label */ + }, /* BR_RANGE_S16M */ + { + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JR_TA /* jr $ta */ + }, /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + {{0, 0, 0}}, /* BR_RANGE_S256 */ + {{0, 0, 0}}, /* BR_RANGE_S16K */ + {{0, 0, 0}}, /* BR_RANGE_S64K */ + {{0, 0, 0}}, /* BR_RANGE_S16M */ + {{0, 0, 0}} /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {2, 4, 4, 4, 12}, /* relax_code_size */ + {2, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 2, 0, BFD_RELOC_NDS32_9_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, 0, BFD_RELOC_NDS32_HI20}, + {0, 12, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP1}, + {4, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {8, 4, NDS32_ORIGIN, 0}, + {8, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "beqz", /* opcode */ + BR_RANGE_S64K, /* br_range */ + { + {0, 20, 0x1F}, + { 0, 0, 0 } + }, /* cond_field */ + { + { + INSN_BEQZ /* beqz $rt, label */ + }, /* BR_RANGE_S256 */ + { + INSN_BEQZ /* beqz $rt, label */ + }, /* BR_RANGE_S16K */ + { + INSN_BEQZ /* beqz $rt, label */ + }, /* BR_RANGE_S64K */ + { + INSN_BNEZ, /* bnez $rt, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S16M */ + { + INSN_BNEZ, /* bnez $rt, $1 */ + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JR_TA /* jr $ta */ + } /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 20, 0x1F}, + {0, 0, 0} + } /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 4, 4, 8, 16}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_ORIGIN, 0}, + {12, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "bgez", /* opcode */ + BR_RANGE_S64K, /* br_range */ + { + {0, 20, 0x1F}, + { 0, 0, 0 } + }, /* cond_field */ + { + { + INSN_BGEZ /* bgez $rt, label */ + }, /* BR_RANGE_S256 */ + { + INSN_BGEZ /* bgez $rt, label */ + }, /* BR_RANGE_S16K */ + { + INSN_BGEZ /* bgez $rt, label */ + }, /* BR_RANGE_S64K */ + { + INSN_BLTZ, /* bltz $rt, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S16M */ + { + INSN_BLTZ, /* bltz $rt, $1 */ + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JR_TA /* jr $ta */ + } /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 20, 0x1F}, + {0, 0, 0} + } /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 4, 4, 8, 16}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_ORIGIN, 0}, + {12, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "bnez", /* opcode */ + BR_RANGE_S64K, /* br_range */ + { + {0, 20, 0x1F}, + { 0, 0, 0 } + }, /* cond_field */ + { + { + INSN_BNEZ /* bnez $rt, label */ + }, /* BR_RANGE_S256 */ + { + INSN_BNEZ /* bnez $rt, label */ + }, /* BR_RANGE_S16K */ + { + INSN_BNEZ /* bnez $rt, label */ + }, /* BR_RANGE_S64K */ + { + INSN_BEQZ, /* beqz $rt, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S16M */ + { + INSN_BEQZ, /* beqz $rt, $1 */ + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JR_TA /* jr $ta */ + } /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 20, 0x1F}, + {0, 0, 0} + } /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 4, 4, 8, 16}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_ORIGIN, 0}, + {12, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "bgtz", /* opcode */ + BR_RANGE_S64K, /* br_range */ + { + {0, 20, 0x1F}, + { 0, 0, 0 } + }, /* cond_field */ + { + { + INSN_BGTZ /* bgtz $rt, label */ + }, /* BR_RANGE_S256 */ + { + INSN_BGTZ /* bgtz $rt, label */ + }, /* BR_RANGE_S16K */ + { + INSN_BGTZ /* bgtz $rt, label */ + }, /* BR_RANGE_S64K */ + { + INSN_BLEZ, /* blez $rt, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S16M */ + { + INSN_BLEZ, /* blez $rt, $1 */ + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JR_TA /* jr $ta */ + } /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 20, 0x1F}, + {0, 0, 0} + } /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 4, 4, 8, 16}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_ORIGIN, 0}, + {12, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "blez", /* opcode */ + BR_RANGE_S64K, /* br_range */ + { + {0, 20, 0x1F}, + { 0, 0, 0 } + }, /* cond_field */ + { + { + INSN_BLEZ /* blez $rt, label */ + }, /* BR_RANGE_S256 */ + { + INSN_BLEZ /* blez $rt, label */ + }, /* BR_RANGE_S16K */ + { + INSN_BLEZ /* blez $rt, label */ + }, /* BR_RANGE_S64K */ + { + INSN_BGTZ, /* bgtz $rt, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S16M */ + { + INSN_BGTZ, /* bgtz $rt, $1 */ + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JR_TA /* jr $ta */ + } /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 20, 0x1F}, + {0, 0, 0} + } /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 4, 4, 8, 16}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_ORIGIN, 0}, + {12, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "bltz", /* opcode */ + BR_RANGE_S64K, /* br_range */ + { + {0, 20, 0x1F}, + { 0, 0, 0 } + }, /* cond_field */ + { + { + INSN_BLTZ /* bltz $rt, label */ + }, /* BR_RANGE_S256 */ + { + INSN_BLTZ /* bltz $rt, label */ + }, /* BR_RANGE_S16K */ + { + INSN_BLTZ /* bltz $rt, label */ + }, /* BR_RANGE_S64K */ + { + INSN_BGEZ, /* bgez $rt, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S16M */ + { + INSN_BGEZ, /* bgez $rt, $1 */ + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JR_TA /* jr $ta */ + } /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 20, 0x1F}, + {0, 0, 0} + } /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 4, 4, 8, 16}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_ORIGIN, 0}, + {12, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "beq", /* opcode */ + BR_RANGE_S16K, /* br_range */ + { + {0, 20, 0x1F}, + {0, 15, 0x1F}, + { 0, 0, 0 } + }, /* cond_field */ + { + { + INSN_BEQ /* beq $rt, $ra, label */ + }, /* BR_RANGE_S256 */ + { + INSN_BEQ /* beq $rt, $ra, label */ + }, /* BR_RANGE_S16K */ + { + INSN_BNE, /* bne $rt, $ra, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S64K */ + { + INSN_BNE, /* bne $rt, $ra, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S16M */ + { + INSN_BNE, /* bne $rt, $ra, $1 */ + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JR_TA /* jr $ta */ + } /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + { + {0, 20, 0x1F}, + {0, 15, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 20, 0x1F}, + {0, 15, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 20, 0x1F}, + {0, 15, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 20, 0x1F}, + {0, 15, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 20, 0x1F}, + {0, 15, 0x1F}, + {0, 0, 0} + } /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 4, 8, 8, 16}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_15_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_ORIGIN, 0}, + {12, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "bne", /* opcode */ + BR_RANGE_S16K, /* br_range */ + { + {0, 20, 0x1F}, + {0, 15, 0x1F}, + { 0, 0, 0 } + }, /* cond_field */ + { + { + INSN_BNE /* bne $rt, $ra, label */ + }, /* BR_RANGE_S256 */ + { + INSN_BNE /* bne $rt, $ra, label */ + }, /* BR_RANGE_S16K */ + { + INSN_BEQ, /* beq $rt, $ra, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S64K */ + { + INSN_BEQ, /* beq $rt, $ra, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S16M */ + { + INSN_BEQ, /* beq $rt, $ra, $1 */ + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JR_TA /* jr $ta */ + } /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + { + {0, 20, 0x1F}, + {0, 15, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 20, 0x1F}, + {0, 15, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 20, 0x1F}, + {0, 15, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 20, 0x1F}, + {0, 15, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 20, 0x1F}, + {0, 15, 0x1F}, + {0, 0, 0} + } /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 4, 8, 8, 16}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_15_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_ORIGIN, 0}, + {12, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "beqz38", /* opcode */ + BR_RANGE_S256, /* br_range */ + { + {0, 8, 0x7}, + { 0, 0, 0 } + }, /* cond_field */ + { + { + INSN_BEQZ /* beqz $rt, label */ + }, /* BR_RANGE_S256 */ + { + INSN_BEQZ /* beqz $rt, label */ + }, /* BR_RANGE_S16K */ + { + INSN_BEQZ /* beqz $rt, label */ + }, /* BR_RANGE_S64K */ + { + INSN_BNEZ, /* bnez $rt, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S16M */ + { + INSN_BNEZ, /* bnez $rt, $1 */ + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JR_TA /* jr $ta */ + } /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 20, 0x1F}, + {0, 0, 0} + } /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 4, 4, 8, 16}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_17_PCREL}, + {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_ORIGIN, 0}, + {12, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "bnez38", /* opcode */ + BR_RANGE_S256, /* br_range */ + { + {0, 8, 0x7}, + { 0, 0, 0 } + }, /* cond_field */ + { + { + INSN_BNEZ /* bnez $rt, label */ + }, /* BR_RANGE_S256 */ + { + INSN_BNEZ /* bnez $rt, label */ + }, /* BR_RANGE_S16K */ + { + INSN_BNEZ /* bnez $rt, label */ + }, /* BR_RANGE_S64K */ + { + INSN_BEQZ, /* beqz $rt, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S16M */ + { + INSN_BEQZ, /* beqz $rt, $1 */ + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JR_TA /* jr $ta */ + } /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 20, 0x1F}, + {0, 0, 0} + } /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 4, 4, 8, 16}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_17_PCREL}, + {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_ORIGIN, 0}, + {12, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "beqzs8", /* opcode */ + BR_RANGE_S256, /* br_range */ + {{0, 0, 0}}, /* cond_field */ + { + { + INSN_BEQZ_TA /* beqz $r15, label */ + }, /* BR_RANGE_S256 */ + { + INSN_BNEZ /* bnez $rt, label */ + }, /* BR_RANGE_S16K */ + { + INSN_BNEZ /* bnez $rt, label */ + }, /* BR_RANGE_S64K */ + { + INSN_BNEZ_TA, /* bnez $r15, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S16M */ + { + INSN_BNEZ_TA, /* bnez $r15, $1 */ + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JR_TA /* jr $ta */ + } /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + {{0, 0, 0}}, /* BR_RANGE_S256 */ + {{0, 0, 0}}, /* BR_RANGE_S16K */ + {{0, 0, 0}}, /* BR_RANGE_S64K */ + {{0, 0, 0}}, /* BR_RANGE_S16M */ + {{0, 0, 0}} /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 4, 4, 8, 16}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_17_PCREL}, + {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_ORIGIN, 0}, + {12, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "bnezs8", /* opcode */ + BR_RANGE_S256, /* br_range */ + {{0, 0, 0}}, /* cond_field */ + { + { + INSN_BNEZ_TA /* bnez $r15, label */ + }, /* BR_RANGE_S256 */ + { + INSN_BNEZ_TA /* bnez $r15, label */ + }, /* BR_RANGE_S16K */ + { + INSN_BNEZ_TA /* bnez $r15, label */ + }, /* BR_RANGE_S64K */ + { + INSN_BEQZ_TA, /* beqz $r15, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S16M */ + { + INSN_BEQZ_TA, /* beqz $r15, $1 */ + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JR_TA /* jr $ta */ + } /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + {{0, 0, 0}}, /* BR_RANGE_S256 */ + {{0, 0, 0}}, /* BR_RANGE_S16K */ + {{0, 0, 0}}, /* BR_RANGE_S64K */ + {{0, 0, 0}}, /* BR_RANGE_S16M */ + {{0, 0, 0}} /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 4, 4, 8, 16}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_17_PCREL}, + {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, 0, BFD_RELOC_NDS32_17_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_ORIGIN, 0}, + {12, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "bnes38", /* opcode */ + BR_RANGE_S256, /* br_range */ + { + {0, 8, 0x7}, + { 0, 0, 0 } + }, /* cond_field */ + { + { + INSN_BNE_R5 /* bne $rt, $r5, label */ + }, /* BR_RANGE_S256 */ + { + INSN_BNE_R5 /* bne $rt, $r5, label */ + }, /* BR_RANGE_S16K */ + { + INSN_BEQ_R5, /* beq $rt, $r5, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S64K */ + { + INSN_BEQ_R5, /* beq $rt, $r5, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S16M */ + { + INSN_BEQ_R5, /* beq $rt, $r5, $1 */ + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JR_TA /* jr $ta */ + } /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 20, 0x1F}, + {0, 0, 0} + } /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 4, 8, 8, 16}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_17_PCREL}, + {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_15_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_ORIGIN, 0}, + {12, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "beqs38", /* opcode */ + BR_RANGE_S256, /* br_range */ + { + {0, 8, 0x7}, + { 0, 0, 0 } + }, /* cond_field */ + { + { + INSN_BEQ_R5 /* beq $rt, $r5, label */ + }, /* BR_RANGE_S256 */ + { + INSN_BEQ_R5 /* beq $rt, $r5, label */ + }, /* BR_RANGE_S16K */ + { + INSN_BNE_R5, /* bne $rt, $r5, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S64K */ + { + INSN_BNE_R5, /* bne $rt, $r5, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S16M */ + { + INSN_BNE_R5, /* bne $rt, $r5, $1 */ + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JR_TA /* jr $ta */ + } /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 20, 0x1F}, + {0, 0, 0} + } /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 4, 8, 8, 16}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, NDS32_ORIGIN, BFD_RELOC_NDS32_17_PCREL}, + {0, 2, NDS32_CONVERT, BFD_RELOC_NDS32_9_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 4, 0, BFD_RELOC_NDS32_15_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 8, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP2}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, NDS32_ORIGIN| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_15_PCREL}, + {0, 2, NDS32_CONVERT| NDS32_CREATE_LABLE, BFD_RELOC_NDS32_9_PCREL}, + {0, 16, NDS32_RELAX, BFD_RELOC_NDS32_LONGJUMP3}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_ORIGIN, 0}, + {12, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "beqc", /* opcode */ + BR_RANGE_S256, /* br_range */ + { + {0, 8, 0x7FF}, + {0, 20, 0x1F}, + {0, 0, 0} + }, /* cond_field */ + { + { + INSN_BEQC /* beqc $rt, imm11s, label */ + }, /* BR_RANGE_S256 */ + { + INSN_MOVI_TA, /* movi $ta, imm11s */ + INSN_BEQ_TA /* beq $rt, $ta, label */ + }, /* BR_RANGE_S16K */ + { + INSN_MOVI_TA, /* movi $ta, imm11s */ + INSN_BEQ_TA /* beq $rt, $ta, label */ + }, /* BR_RANGE_S64K */ + { + INSN_BNEC, /* bnec $rt, imm11s, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S16M */ + { + INSN_BNEC, /* bnec $rt, imm11s, $1 */ + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JR_TA /* jr $ta */ + } /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + { + {0, 8, 0x7FF}, + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 0, 0xFFFFF}, + {4, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 0, 0xFFFFF}, + {4, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 8, 0x7FF}, + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 8, 0x7FF}, + {0, 20, 0x1F}, + {0, 0, 0} + } /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 8, 8, 8, 16}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, 0, BFD_RELOC_NDS32_WORD_9_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {4, 4, 0, BFD_RELOC_NDS32_15_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {4, 4, 0, BFD_RELOC_NDS32_15_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_WORD_9_PCREL}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_WORD_9_PCREL}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_ORIGIN, 0}, + {12, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + "bnec", /* opcode */ + BR_RANGE_S256, /* br_range */ + { + {0, 8, 0x7FF}, + {0, 20, 0x1F}, + {0, 0, 0} + }, /* cond_field */ + { + { + INSN_BNEC /* bnec $rt, imm11s, label */ + }, /* BR_RANGE_S256 */ + { + INSN_MOVI_TA, /* movi $ta, imm11s */ + INSN_BNE_TA /* bne $rt, $ta, label */ + }, /* BR_RANGE_S16K */ + { + INSN_MOVI_TA, /* movi $ta, imm11s */ + INSN_BNE_TA /* bne $rt, $ta, label */ + }, /* BR_RANGE_S64K */ + { + INSN_BEQC, /* beqc $rt, imm11s, $1 */ + INSN_J /* j label */ + }, /* BR_RANGE_S16M */ + { + INSN_BEQC, /* beqc $rt, imm11s, $1 */ + INSN_SETHI_TA, /* sethi $ta, label */ + INSN_ORI_TA, /* ori $ta, $ta, label */ + INSN_JR_TA /* jr $ta */ + } /* BR_RANGE_U4G */ + }, /* relax_code_seq */ + { + { + {0, 8, 0x7FF}, + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {0, 0, 0xFFFFF}, + {4, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {0, 0, 0xFFFFF}, + {4, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 8, 0x7FF}, + {0, 20, 0x1F}, + {0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 8, 0x7FF}, + {0, 20, 0x1F}, + {0, 0, 0} + } /* BR_RANGE_U4G */ + }, /* relax_code_condition */ + {4, 8, 8, 8, 16}, /* relax_code_size */ + {4, 4, 4, 4, 4}, /* relax_branch_isize */ + { + { + {0, 4, 0, BFD_RELOC_NDS32_WORD_9_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S256 */ + { + {4, 4, 0, BFD_RELOC_NDS32_15_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16K */ + { + {4, 4, 0, BFD_RELOC_NDS32_15_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S64K */ + { + {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_WORD_9_PCREL}, + {4, 4, 0, BFD_RELOC_NDS32_25_PCREL}, + {0, 0, 0, 0} + }, /* BR_RANGE_S16M */ + { + {0, 4, NDS32_CREATE_LABLE, BFD_RELOC_NDS32_WORD_9_PCREL}, + {4, 4, 0, BFD_RELOC_NDS32_HI20}, + {8, 4, 0, BFD_RELOC_NDS32_LO12S0_ORI}, + {12, 4, NDS32_ORIGIN, 0}, + {12, 2, NDS32_CONVERT, 0}, + {0, 0, 0, 0} + } /* BR_RANGE_U4G */ + } /* relax_fixup */ + }, + { + NULL, /* opcode */ + 0, /* br_range */ + {{0, 0, 0}}, /* cond_field */ + {{0}}, /* relax_code_seq */ + {{{0, 0, 0}}}, /* relax_code_condition */ + {0}, /* relax_code_size */ + {0}, /* relax_branch_isize */ + {{{0, 0, 0, 0}}}, /* relax_fixup */ + }, +}; + + +/* GAS definitions for command-line options. */ +enum options +{ + OPTION_BIG = OPTION_MD_BASE, + OPTION_LITTLE, + OPTION_TURBO, + OPTION_PIC, + OPTION_RELAX_FP_AS_GP_OFF, + OPTION_RELAX_B2BB_ON, + OPTION_RELAX_ALL_OFF, + OPTION_OPTIMIZE, + OPTION_OPTIMIZE_SPACE +}; + +const char *md_shortopts = "m:G:O"; +struct option md_longopts[] = { + {"O1", no_argument, NULL, OPTION_OPTIMIZE}, + {"Os", no_argument, NULL, OPTION_OPTIMIZE_SPACE}, + {"big", no_argument, NULL, OPTION_BIG}, + {"little", no_argument, NULL, OPTION_LITTLE}, + {"EB", no_argument, NULL, OPTION_BIG}, + {"EL", no_argument, NULL, OPTION_LITTLE}, + {"meb", no_argument, NULL, OPTION_BIG}, + {"mel", no_argument, NULL, OPTION_LITTLE}, + {"mall-ext", no_argument, NULL, OPTION_TURBO}, + {"mpic", no_argument, NULL, OPTION_PIC}, + /* Relaxation related options. */ + {"mno-fp-as-gp-relax", no_argument, NULL, OPTION_RELAX_FP_AS_GP_OFF}, + {"mb2bb", no_argument, NULL, OPTION_RELAX_B2BB_ON}, + {"mno-all-relax", no_argument, NULL, OPTION_RELAX_ALL_OFF}, + {NULL, no_argument, NULL, 0} +}; + +size_t md_longopts_size = sizeof (md_longopts); + +struct nds32_parse_option_table +{ + const char *name; /* Option string. */ + char *help; /* Help description. */ + int (*func) (char *arg); /* How to parse it. */ +}; + + +/* The value `-1' represents this option has *NOT* been set. */ +#ifdef NDS32_DEFAULT_ARCH_NAME +static char* nds32_arch_name = NDS32_DEFAULT_ARCH_NAME; +#else +static char* nds32_arch_name = "v3"; +#endif +static int nds32_baseline = -1; +static int nds32_gpr16 = -1; +static int nds32_fpu_sp_ext = -1; +static int nds32_fpu_dp_ext = -1; +static int nds32_freg = -1; +static int nds32_abi = -1; + +/* Record ELF flags */ +static int nds32_elf_flags = 0; +static int nds32_fpu_com = 0; + +static int nds32_parse_arch (char *str); +static int nds32_parse_baseline (char *str); +static int nds32_parse_freg (char *str); +static int nds32_parse_abi (char *str); + +static struct nds32_parse_option_table parse_opts [] = +{ + {"arch=", _("\t Assemble for architecture \n\ + could be\n\ + v3, v3j, v3m, v3f, v3s, "\ + "v2, v2j, v2f, v2s"), nds32_parse_arch}, + {"baseline=", _("\t Assemble for baseline \n\ + could be v2, v3, v3m"), + nds32_parse_baseline}, + {"fpu-freg=", _("\t Specify a FPU configuration\n\ + \n\ + 0: 8 SP / 4 DP registers\n\ + 1: 16 SP / 8 DP registers\n\ + 2: 32 SP / 16 DP registers\n\ + 3: 32 SP / 32 DP registers"), nds32_parse_freg}, + {"abi=", _("\t Specify a abi version\n\ + could be v1, v2, v2fp, v2fpp"), nds32_parse_abi}, + {NULL, NULL, NULL} +}; + +static int nds32_mac = 1; +static int nds32_div = 1; +static int nds32_16bit_ext = 1; +static int nds32_dx_regs = NDS32_DEFAULT_DX_REGS; +static int nds32_perf_ext = NDS32_DEFAULT_PERF_EXT; +static int nds32_perf_ext2 = NDS32_DEFAULT_PERF_EXT2; +static int nds32_string_ext = NDS32_DEFAULT_STRING_EXT; +static int nds32_audio_ext = NDS32_DEFAULT_AUDIO_EXT; +static int nds32_fpu_fma = 0; +static int nds32_pic = 0; +static int nds32_relax_fp_as_gp = 1; +static int nds32_relax_b2bb = 0; +static int nds32_relax_all = 1; +struct nds32_set_option_table +{ + const char *name; /* Option string. */ + char *help; /* Help description. */ + int *var; /* Variable to be set. */ + int value; /* Value to set. */ +}; + +/* The option in this group has both Enable/Disable settings. + Just list on here. */ + +static struct nds32_set_option_table toggle_opts [] = +{ + {"mac", _("Multiply instructions support"), &nds32_mac, 1}, + {"div", _("Divide instructions support"), &nds32_div, 1}, + {"16bit-ext", _("16-bit extension"), &nds32_16bit_ext, 1}, + {"dx-regs", _("d0/d1 registers"), &nds32_dx_regs, 1}, + {"perf-ext", _("Performance extension"), &nds32_perf_ext, 1}, + {"perf2-ext", _("Performance extension 2"), &nds32_perf_ext2, 1}, + {"string-ext", _("String extension"), &nds32_string_ext, 1}, + {"reduced-regs", _("Reduced Register configuration (GPR16) option"), &nds32_gpr16, 1}, + {"audio-isa-ext", _("AUDIO ISA extension"), &nds32_audio_ext, 1}, + {"fpu-sp-ext", _("FPU SP extension"), &nds32_fpu_sp_ext, 1}, + {"fpu-dp-ext", _("FPU DP extension"), &nds32_fpu_dp_ext, 1}, + {"fpu-fma", _("FPU fused-multiply-add instructions"), &nds32_fpu_fma, 1}, + {NULL, NULL, NULL, 0} +}; + + +/* GAS declarations. */ + +/* This is the callback for nds32-asm.c to parse operands. */ +int +nds32_asm_parse_operand (struct nds32_asm_desc *pdesc, + struct nds32_asm_insn *pinsn, + char **pstr, int64_t *value); + + +struct nds32_asm_desc asm_desc; + +/* md_after_parse_args () + + GAS will call md_after_parse_args whenever it is defined. + This function checks any conflicting options specified. */ + +void +nds32_after_parse_args (void) +{ + /* If -march option is not used in command-line, set the value of option + variable according to NDS32_DEFAULT_ARCH_NAME. */ + nds32_parse_arch (nds32_arch_name); +} + +/* This function is called when printing usage message (--help). */ + +void +md_show_usage (FILE *stream) +{ + struct nds32_parse_option_table *coarse_tune; + struct nds32_set_option_table *fine_tune; + + fprintf (stream, _("\n NDS32-specific assembler options:\n")); + fprintf (stream, _("\ + -O1, Optimize for performance\n\ + -Os Optimize for space\n")); + fprintf (stream, _("\ + -EL, -mel or -little Produce little endian output\n\ + -EB, -meb or -big Produce big endian output\n\ + -mpic Generate PIC\n\ + -mno-fp-as-gp-relax Suppress fp-as-gp relaxation for this file\n\ + -mb2bb-relax Back-to-back branch optimization\n\ + -mno-all-relax Suppress all relaxation for this file\n")); + + for (coarse_tune = parse_opts; coarse_tune->name != NULL; coarse_tune++) + { + if (coarse_tune->help != NULL) + fprintf (stream, _(" -m%s%s\n"), + coarse_tune->name, _(coarse_tune->help)); + } + + for (fine_tune = toggle_opts; fine_tune->name != NULL; fine_tune++) + { + if (fine_tune->help != NULL) + fprintf (stream, _(" -m[no-]%-17sEnable/Disable %s\n"), + fine_tune->name, _(fine_tune->help)); + } + + fprintf (stream, _("\ + -mall-ext Turn on all extensions and instructions support\n")); +} + +void +nds32_frag_init (fragS *fragp) +{ + fragp->tc_frag_data.flag = 0; + fragp->tc_frag_data.opcode = NULL; + fragp->tc_frag_data.fixup = NULL; +} + + + +/* This function reads an expression from a C string and returns a pointer past + the end of the expression. */ + +static char * +parse_expression (char *str, expressionS *exp) +{ + char *s; + char *tmp; + + tmp = input_line_pointer; /* Save line pointer. */ + input_line_pointer = str; + expression (exp); + s = input_line_pointer; + input_line_pointer = tmp; /* Restore line pointer. */ + + return s; /* Return pointer to where parsing stopped. */ +} + +void +nds32_start_line_hook (void) +{ +} + +/* + * Pseudo opcodes + */ + +typedef void (*nds32_pseudo_opcode_func) (int argc, char *argv[], int pv); +struct nds32_pseudo_opcode +{ + const char *opcode; + int argc; + nds32_pseudo_opcode_func proc; + int pseudo_val; + + /* Some instructions are not pseudo opcode, but they might still be + expanded or changed with other instruction combination for some + conditions. We also apply this structure to assist such work. + + For example, if the distance of branch target '.L0' is larger than + imm8s<<1 range, + + the instruction: + + beqzs8 .L0 + + will be transformed into: + + bnezs8 .LCB0 + j .L0 + .LCB0: + + However, sometimes we do not want assembler to do such changes + because compiler knows how to generate corresponding instruction sequence. + Use this field to indicate that this opcode is also a physical instruction. + If the flag 'verbatim' is nozero and this opcode + is a physical instruction, we should not expand it. */ + int physical_op; +}; +#define PV_DONT_CARE 0 + +static struct hash_control *nds32_pseudo_opcode_hash = NULL; + +static int +builtin_isreg (const char *s, const char *x ATTRIBUTE_UNUSED) +{ + return s[0] == '$'; +} + +static int +builtin_regnum (const char *s, const char *x ATTRIBUTE_UNUSED) +{ + struct nds32_keyword *k; + + k = hash_find (nds32_gprs_hash, s); + + if (k == NULL) + return -1; + + return k->value; +} + +static int +builtin_addend (const char *s, char *x ATTRIBUTE_UNUSED) +{ + const char *ptr = s; + + while (*ptr != '+' && *ptr != '-' && *ptr) + ++ptr; + + if (*ptr == 0) + return 0; + else + return strtol (ptr, NULL, 0); +} + +static void +md_assemblef (char *format, ...) +{ + /* FIXME: hope this is long enough. */ + char line[1024]; + va_list ap; + unsigned int r; + + va_start(ap, format); + r = vsnprintf (line, sizeof (line), format, ap); + md_assemble (line); + + gas_assert (r < sizeof (line)); +} + +/* Some prototypes here, since some op may use another op. */ +static void do_pseudo_li_internal (char *rt, int imm32s); +static void do_pseudo_move_reg_internal (char *dst, char *src); + +static void +do_pseudo_b (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + char *arg_label = argv[0]; + /* b label */ + if (nds32_pic + && (strstr (arg_label, "@GOT") || strstr (arg_label, "@PLT"))) + { + md_assemblef ("sethi $ta,hi20(%s)", arg_label); + md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label); + md_assemble ("add $ta,$ta,$gp"); + md_assemble ("jr $ta"); + } + else + { + md_assemblef ("j %s", arg_label); + } +} + +static void +do_pseudo_bal (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + char *arg_label = argv[0]; + /* bal|call label */ + if (nds32_pic + && (strstr (arg_label, "@GOT") || strstr (arg_label, "@PLT"))) + { + md_assemblef ("sethi $ta,hi20(%s)", arg_label); + md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label); + md_assemble ("add $ta,$ta,$gp"); + md_assemble ("jral $ta"); + } + else + { + md_assemblef ("jal %s", arg_label); + } +} + +static void +do_pseudo_bge (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + /* rt5, ra5, label */ + md_assemblef ("slt $ta,%s,%s", argv[0], argv[1]); + md_assemblef ("beqz $ta,%s", argv[2]); +} + +static void +do_pseudo_bges (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + /* rt5, ra5, label */ + md_assemblef ("slts $ta,%s,%s", argv[0], argv[1]); + md_assemblef ("beqz $ta,%s", argv[2]); +} + +static void +do_pseudo_bgt (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + /* bgt rt5, ra5, label */ + md_assemblef ("slt $ta,%s,%s", argv[1], argv[0]); + md_assemblef ("bnez $ta,%s", argv[2]); +} + +static void +do_pseudo_bgts (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + /* bgt rt5, ra5, label */ + md_assemblef ("slts $ta,%s,%s", argv[1], argv[0]); + md_assemblef ("bnez $ta,%s", argv[2]); +} + +static void +do_pseudo_ble (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + /* bgt rt5, ra5, label */ + md_assemblef ("slt $ta,%s,%s", argv[1], argv[0]); + md_assemblef ("beqz $ta,%s", argv[2]); +} + +static void +do_pseudo_bles (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + /* bgt rt5, ra5, label */ + md_assemblef ("slts $ta,%s,%s", argv[1], argv[0]); + md_assemblef ("beqz $ta,%s", argv[2]); +} + +static void +do_pseudo_blt (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + /* rt5, ra5, label */ + md_assemblef ("slt $ta,%s,%s", argv[0], argv[1]); + md_assemblef ("bnez $ta,%s", argv[2]); +} + +static void +do_pseudo_blts (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + /* rt5, ra5, label */ + md_assemblef ("slts $ta,%s,%s", argv[0], argv[1]); + md_assemblef ("bnez $ta,%s", argv[2]); +} + +static void +do_pseudo_br (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + md_assemblef ("jr %s", argv[0]); +} + +static void +do_pseudo_bral (int argc, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + if (argc == 1) + md_assemblef ("jral $lp,%s", argv[0]); + else + md_assemblef ("jral %s,%s", argv[0], argv[1]); +} + +static void +do_pseudo_la_internal (const char *arg_reg, const char *arg_label, const char *line) +{ + /* rt, label */ + if (!nds32_pic) + { + md_assemblef ("sethi %s,hi20(%s)", arg_reg, arg_label); + md_assemblef ("ori %s,%s,lo12(%s)", arg_reg, arg_reg, arg_label); + } + else if ((strstr (arg_label, "@PLT") || strstr (arg_label, "@GOTOFF"))) + { + md_assemblef ("sethi $ta,hi20(%s)", arg_label); + md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label); + md_assemblef ("add %s,$ta,$gp", arg_reg); + } + else if (strstr (arg_label, "@GOT")) + { + long addend = builtin_addend (arg_label, NULL); + + md_assemblef ("sethi $ta,hi20(%s)", arg_label); + md_assemblef ("ori $ta,$ta,lo12(%s)", arg_label); + md_assemblef ("lw %s,[$gp+$ta]", arg_reg); + if (addend != 0) + { + if (addend < 0x4000 && addend >= -0x4000) + { + md_assemblef ("addi %s,%s,%d", arg_reg, arg_reg, addend); + } + else + { + do_pseudo_li_internal ("$ta", addend); + md_assemblef ("add %s,$ta,%s", arg_reg, arg_reg); + } + } + } + else + as_bad (_("need PIC qualifier with symbol. '%s'"), line); +} + +static void +do_pseudo_la (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + do_pseudo_la_internal (argv[0], argv[1], argv[argc]); +} + +static void +do_pseudo_li_internal (char *rt, int imm32s) +{ + if (enable_16bit && imm32s <= 0xf && imm32s >= -0x10) + md_assemblef ("movi55 %s,%d", rt, imm32s); + else if (imm32s <= 0x7ffff && imm32s >= -0x80000) + md_assemblef ("movi %s,%d", rt, imm32s); + else if ((imm32s & 0xfff) == 0) + md_assemblef ("sethi %s,hi20(%d)", rt, imm32s); + else + { + md_assemblef ("sethi %s,hi20(%d)", rt, imm32s); + md_assemblef ("ori %s,%s,lo12(%d)", rt, rt, imm32s); + } +} + +static void +do_pseudo_li (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + /* Validate argv[1] for constant expression. */ + expressionS exp; + + parse_expression (argv[1], &exp); + if (exp.X_op != O_constant) + { + as_bad (_("Operand is not a constant. `%s'"), argv[argc]); + return; + } + + do_pseudo_li_internal (argv[0], exp.X_add_number); +} + +static void +do_pseudo_ls_bhw (int argc ATTRIBUTE_UNUSED, char *argv[], int pv) +{ + char ls = 'r'; + char size = 'x'; + const char *sign = ""; + + /* Prepare arguments for various load/store. */ + sign = (pv & 0x10) ? "s" : ""; + ls = (pv & 0x80000000) ? 's' : 'l'; + switch (pv & 0x3) + { + case 0: size = 'b'; break; + case 1: size = 'h'; break; + case 2: size = 'w'; break; + } + + if (ls == 's' || size == 'w') + sign = ""; + + if (builtin_isreg (argv[1], NULL)) + { + /* lwi */ + md_assemblef ("%c%c%si %s,[%s]", ls, size, argv[0], argv[1]); + } + else if (!nds32_pic) + { + /* lwi */ + md_assemblef ("sethi $ta,hi20(%s)", argv[1]); + md_assemblef ("%c%c%si %s,[$ta+lo12(%s)]", ls, size, sign, argv[0], argv[1]); + } + else + { + /* PIC code. */ + if (strstr (argv[1], "@GOTOFF")) + { + /* lw */ + md_assemblef ("sethi $ta,hi20(%s)", argv[1]); + md_assemblef ("ori $ta,$ta,lo12(%s)", argv[1]); + md_assemblef ("%c%c%s %s,[$ta+$gp]", ls, size, sign, argv[0]); + } + else if (strstr (argv[1], "@GOT")) + { + long addend = builtin_addend (argv[1], NULL); + /* lw */ + md_assemblef ("sethi $ta,hi20(%s)", argv[1]); + md_assemblef ("ori $ta,$ta,lo12(%s)", argv[1]); + md_assemble ("lw $ta,[$gp+$ta]"); /* Load address word. */ + if (addend < 0x10000 && addend >= -0x10000) + { + md_assemblef ("%c%c%si %s,[$ta+(%d)]", ls, size, sign, argv[0], addend); + } + else + { + /* lw */ + do_pseudo_li_internal (argv[0], addend); + md_assemblef ("%c%c%s %s,[$ta+%s]", ls, size, sign, argv[0], argv[0]); + } + } + else + { + as_bad(_("needs @GOT or @GOTOFF. %s"), argv[argc]); + } + } +} + +static void +do_pseudo_ls_bhwp (int argc ATTRIBUTE_UNUSED, char *argv[], int pv) +{ + char *arg_rt = argv[0]; + char *arg_label = argv[1]; + char *arg_inc = argv[2]; + char ls = 'r'; + char size = 'x'; + const char *sign = ""; + + /* Prepare arguments for various load/store. */ + sign = (pv & 0x10) ? "s" : ""; + ls = (pv & 0x80000000) ? 's' : 'l'; + switch (pv & 0x3) + { + case 0: size = 'b'; break; + case 1: size = 'h'; break; + case 2: size = 'w'; break; + } + + if (ls == 's' || size == 'w') + sign = ""; + + do_pseudo_la_internal ("$ta", arg_label, argv[argc]); + md_assemblef ("%c%c%si.bi %s,[$ta],%s", ls, size, sign, arg_rt, arg_inc); +} + +static void +do_pseudo_ls_bhwpc (int argc ATTRIBUTE_UNUSED, char *argv[], int pv) +{ + char *arg_rt = argv[0]; + char *arg_inc = argv[2]; + char ls = 'r'; + char size = 'x'; + const char *sign = ""; + + /* Prepare arguments for various load/store. */ + sign = (pv & 0x10) ? "s" : ""; + ls = (pv & 0x80000000) ? 's' : 'l'; + switch (pv & 0x3) + { + case 0: size = 'b'; break; + case 1: size = 'h'; break; + case 2: size = 'w'; break; + } + + if (ls == 's' || size == 'w') + sign = ""; + + md_assemblef ("%c%c%si.bi %s,[$ta],%s", ls, size, sign, arg_rt, arg_inc); +} + +static void +do_pseudo_ls_bhwi (int argc ATTRIBUTE_UNUSED, char *argv[], int pv) +{ + char ls = 'r'; + char size = 'x'; + const char *sign = ""; + + /* Prepare arguments for various load/store. */ + sign = (pv & 0x10) ? "s" : ""; + ls = (pv & 0x80000000) ? 's' : 'l'; + switch (pv & 0x3) + { + case 0: size = 'b'; break; + case 1: size = 'h'; break; + case 2: size = 'w'; break; + } + + if (ls == 's' || size == 'w') + sign = ""; + + md_assemblef ("%c%c%si.bi %s,%s,%s", + ls, size, sign, argv[0], argv[1], argv[2]); +} + +static void +do_pseudo_move_reg_internal (char *dst, char *src) +{ + if (enable_16bit) + md_assemblef ("mov55 %s,%s", dst, src); + else + md_assemblef ("ori %s,%s,0", dst, src); +} + +static void +do_pseudo_move (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + if (builtin_isreg (argv[1], NULL)) + do_pseudo_move_reg_internal (argv[0], argv[1]); + else + /* move $rt, imm -> li $rt, imm */ + do_pseudo_li (argc, argv, PV_DONT_CARE); +} + +static void +do_pseudo_neg (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + md_assemble ("movi $ta,0"); + md_assemblef ("sub %s,$ta,%s", argv[0], argv[1]); +} + +static void +do_pseudo_not (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + md_assemblef ("nor %s,%s,%s", argv[0], argv[1], argv[1]); +} + +static void +do_pseudo_pushpopm (int argc, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + /* posh/pop $ra, $rb */ + /* SMW.{b | a}{i | d}{m?} Rb, [Ra], Re, Enable4 */ + int rb, re, ra, en4; + int i; + char *opc = "pushpopm"; + + if (argc == 3) + as_bad ("'pushm/popm $ra5, $rb5, $label' is deprecated. " + "Only 'pushm/popm $ra5' is supported now. %s", argv[argc]); + else if (argc == 1) + as_bad ("'pushm/popm $ra5, $rb5'. %s\n", argv[argc]); + + if (strstr (argv[argc], "pop") == argv[argc]) + opc = "lmw.bim"; + else if (strstr (argv[argc], "push") == argv[argc]) + opc = "smw.adm"; + else + as_fatal ("nds32-as internal error. %s", argv[argc]); + + rb = builtin_regnum (argv[0], NULL); + re = builtin_regnum (argv[1], NULL); + + if (re < rb) + { + as_warn ("$rb should not be smaller than $ra. %s", argv[argc]); + /* Swap to right order. */ + ra = re; + re = rb; + rb = ra; + } + + /* Build enable4 mask. */ + en4 = 0; + if (re >= 28 || rb >= 28) + { + for (i = (rb >= 28? rb: 28); i <= re; i++) + en4 |= 1 << (3 - (i - 28)); + } + + /* Adjust $re, $rb. */ + if (rb >= 28) + rb = re = 31; + else if (re >= 28) + re = 27; + + md_assemblef ("%s $r%d,[$sp],$r%d,%d", opc, rb, re, en4); +} + +static void +do_pseudo_pushpop (int argc, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + /* push/pop $ra5, $label=$sp */ + char *argvm[3]; + + if (argc == 2) + as_bad ("'push/pop $ra5, rb5' is deprecated. " + "Only 'push/pop $ra5' is supported now. %s", argv[argc]); + + argvm[0] = argv[0]; + argvm[1] = argv[0]; + argvm[2] = argv[argc]; + do_pseudo_pushpopm (2, argvm, PV_DONT_CARE); +} + +static void +do_pseudo_v3push (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + md_assemblef ("push25 %s,%s", argv[0], argv[1]); +} + +static void +do_pseudo_v3pop (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + md_assemblef ("pop25 %s,%s", argv[0], argv[1]); +} + +/* pv == 0, parsing "push.s" pseudo instruction operands. + pv != 0, parsing "pop.s" pseudo instruction operands. */ + +static void +do_pseudo_pushpop_stack (int argc, char *argv[], int pv) +{ + /* push.s Rb,Re,{$fp $gp $lp $sp} ==> smw.adm Rb,[$sp],Re,Eable4 */ + /* pop.s Rb,Re,{$fp $gp $lp $sp} ==> lmw.bim Rb,[$sp],Re,Eable4 */ + + int rb, re; + int en4; + int last_arg_index; + char *opc = (pv == 0) ? "smw.adm" : "lmw.bim"; + + rb = re = 0; + + if (argc == 1) + { + /* argc=1, operands pattern: { $fp $gp $lp $sp } */ + + /* Set register number Rb = Re = $sp = $r31. */ + rb = re = 31; + } + else if (argc == 2 || argc == 3) + { + /* argc=2, operands pattern: Rb, Re */ + /* argc=3, operands pattern: Rb, Re, { $fp $gp $lp $sp } */ + + /* Get register number in integer. */ + rb = builtin_regnum (argv[0], NULL); + re = builtin_regnum (argv[1], NULL); + + /* Rb should be equal/less than Re. */ + if (rb > re) + as_bad ("The first operand (%s) should be equal to or smaller than " + "second operand (%s).", argv[0], argv[1]); + + /* forbid using $fp|$gp|$lp|$sp in Rb or Re + r28 r29 r30 r31 */ + if (rb >= 28) + as_bad ("Cannot use $fp, $gp, $lp, or $sp at first operand !!"); + if (re >= 28) + as_bad ("Cannot use $fp, $gp, $lp, or $sp at second operand !!"); + } + else + { + as_bad ("Invalid operands pattern !!"); + } + + /* Build Enable4 mask. */ + /* Using last_arg_index for argc=1|2|3 is safe, because $fp, $gp, $lp, + and $sp only appear in argc=1 or argc=3 if argc=2, en4 remains 0, + which is also valid for code generation. */ + en4 = 0; + last_arg_index = argc - 1; + if (strstr (argv[last_arg_index], "$fp")) + en4 |= 8; + if (strstr (argv[last_arg_index], "$gp")) + en4 |= 4; + if (strstr (argv[last_arg_index], "$lp")) + en4 |= 2; + if (strstr (argv[last_arg_index], "$sp")) + en4 |= 1; + + md_assemblef ("%s $r%d,[$sp],$r%d,%d", opc, rb, re, en4); +} + +static void +do_pseudo_push_bhwd (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + char size = 'x'; + /* If users omit push location, use $sp as default value. */ + char location[8] = "$sp"; /* 8 is enough for register name. */ + + switch (pv & 0x3) + { + case 0: size = 'b'; break; + case 1: size = 'h'; break; + case 2: size = 'w'; break; + case 3: size = 'w'; break; + } + + if (argc == 2) + { + strncpy (location, argv[1], 8); + location[7] = '\0'; + } + + md_assemblef ("l.%c $ta,%s", size, argv[0]); + md_assemblef ("smw.adm $ta,[%s],$ta", location); + + if ((pv & 0x3) == 0x3) /* double-word */ + { + md_assemblef ("l.w $ta,%s+4", argv[0]); + md_assemblef ("smw.adm $ta,[%s],$ta", location); + } +} + +static void +do_pseudo_pop_bhwd (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + char size = 'x'; + /* If users omit pop location, use $sp as default value. */ + char location[8] = "$sp"; /* 8 is enough for register name. */ + + switch (pv & 0x3) + { + case 0: size = 'b'; break; + case 1: size = 'h'; break; + case 2: size = 'w'; break; + case 3: size = 'w'; break; + } + + if (argc == 3) + { + strncpy (location, argv[2], 8); + location[7] = '\0'; + } + + if ((pv & 0x3) == 0x3) /* double-word */ + { + md_assemblef ("lmw.bim %s,[%s],%s", argv[1], location, argv[1]); + md_assemblef ("s.w %s,%s+4", argv[1], argv[0]); + } + + md_assemblef ("lmw.bim %s,[%s],%s", argv[1], location, argv[1]); + md_assemblef ("s.%c %s,%s", size, argv[1], argv[0]); +} + +static void +do_pseudo_pusha (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + /* If users omit push location, use $sp as default value. */ + char location[8] = "$sp"; /* 8 is enough for register name. */ + + if (argc == 2) + { + strncpy (location, argv[1], 8); + location[7] = '\0'; + } + + md_assemblef ("la $ta,%s", argv[0]); + md_assemblef ("smw.adm $ta,[%s],$ta", location); +} + +static void +do_pseudo_pushi (int argc ATTRIBUTE_UNUSED, char *argv[], int pv ATTRIBUTE_UNUSED) +{ + /* If users omit push location, use $sp as default value. */ + char location[8] = "$sp"; /* 8 is enough for register name. */ + + if (argc == 2) + { + strncpy (location, argv[1], 8); + location[7] = '\0'; + } + + md_assemblef ("li $ta,%s", argv[0]); + md_assemblef ("smw.adm $ta,[%s],$ta", location); +} + +struct nds32_pseudo_opcode nds32_pseudo_opcode_table[] = { + {"b", 1, do_pseudo_b, 0, 0}, + {"bal", 1, do_pseudo_bal, 0, 0}, + + {"bge", 3, do_pseudo_bge, 0, 0}, + {"bges", 3, do_pseudo_bges, 0, 0}, + + {"bgt", 3, do_pseudo_bgt, 0, 0}, + {"bgts", 3, do_pseudo_bgts, 0, 0}, + + {"ble", 3, do_pseudo_ble, 0, 0}, + {"bles", 3, do_pseudo_bles, 0, 0}, + + {"blt", 3, do_pseudo_blt, 0, 0}, + {"blts", 3, do_pseudo_blts, 0, 0}, + + {"br", 1, do_pseudo_br, 0, 0}, + {"bral", 1, do_pseudo_bral, 0, 0}, + + {"call", 1, do_pseudo_bal, 0, 0}, + + {"la", 2, do_pseudo_la, 0, 0}, + {"li", 2, do_pseudo_li, 0, 0}, + + {"l.b", 2, do_pseudo_ls_bhw, 0, 0}, + {"l.h", 2, do_pseudo_ls_bhw, 1, 0}, + {"l.w", 2, do_pseudo_ls_bhw, 2, 0}, + {"l.bs", 2, do_pseudo_ls_bhw, 0 | 0x10, 0}, + {"l.hs", 2, do_pseudo_ls_bhw, 1 | 0x10, 0}, + {"s.b", 2, do_pseudo_ls_bhw, 0 | 0x80000000, 0}, + {"s.h", 2, do_pseudo_ls_bhw, 1 | 0x80000000, 0}, + {"s.w", 2, do_pseudo_ls_bhw, 2 | 0x80000000, 0}, + + {"l.bp", 3, do_pseudo_ls_bhwp, 0, 0}, + {"l.bpc", 3, do_pseudo_ls_bhwpc, 0, 0}, + {"l.hp", 3, do_pseudo_ls_bhwp, 1, 0}, + {"l.hpc", 3, do_pseudo_ls_bhwpc, 1, 0}, + {"l.wp", 3, do_pseudo_ls_bhwp, 2, 0}, + {"l.wpc", 3, do_pseudo_ls_bhwpc, 2, 0}, + {"l.bsp", 3, do_pseudo_ls_bhwp, 0 | 0x10, 0}, + {"l.bspc", 3, do_pseudo_ls_bhwpc, 0 | 0x10, 0}, + {"l.hsp", 3, do_pseudo_ls_bhwp, 1 | 0x10, 0}, + {"l.hspc", 3, do_pseudo_ls_bhwpc, 1 | 0x10, 0}, + {"s.bp", 3, do_pseudo_ls_bhwp, 0 | 0x80000000, 0}, + {"s.bpc", 3, do_pseudo_ls_bhwpc, 0 | 0x80000000, 0}, + {"s.hp", 3, do_pseudo_ls_bhwp, 1 | 0x80000000, 0}, + {"s.hpc", 3, do_pseudo_ls_bhwpc, 1 | 0x80000000, 0}, + {"s.wp", 3, do_pseudo_ls_bhwp, 2 | 0x80000000, 0}, + {"s.wpc", 3, do_pseudo_ls_bhwpc, 2 | 0x80000000, 0}, + {"s.bsp", 3, do_pseudo_ls_bhwp, 0 | 0x80000000 | 0x10, 0}, + {"s.hsp", 3, do_pseudo_ls_bhwp, 1 | 0x80000000 | 0x10, 0}, + + {"lbi.p", 3, do_pseudo_ls_bhwi, 0, 0}, + {"lhi.p", 3, do_pseudo_ls_bhwi, 1, 0}, + {"lwi.p", 3, do_pseudo_ls_bhwi, 2, 0}, + {"sbi.p", 3, do_pseudo_ls_bhwi, 0 | 0x80000000, 0}, + {"shi.p", 3, do_pseudo_ls_bhwi, 1 | 0x80000000, 0}, + {"swi.p", 3, do_pseudo_ls_bhwi, 2 | 0x80000000, 0}, + {"lbsi.p", 3, do_pseudo_ls_bhwi, 0 | 0x10, 0}, + {"lhsi.p", 3, do_pseudo_ls_bhwi, 1 | 0x10, 0}, + {"lwsi.p", 3, do_pseudo_ls_bhwi, 0 | 0x10, 0}, + + {"move", 2, do_pseudo_move, 0, 0}, + {"neg", 2, do_pseudo_neg, 0, 0}, + {"not", 2, do_pseudo_not, 0, 0}, + + {"pop", 2, do_pseudo_pushpop, 0, 0}, + {"push", 2, do_pseudo_pushpop, 0, 0}, + {"popm", 2, do_pseudo_pushpopm, 0, 0}, + {"pushm", 3, do_pseudo_pushpopm, 0, 0}, + + {"v3push", 2, do_pseudo_v3push, 0, 0}, + {"v3pop", 2, do_pseudo_v3pop, 0, 0}, + + /* Support pseudo instructions of pushing/poping registers into/from stack + push.s Rb, Re, { $fp $gp $lp $sp } ==> smw.adm Rb,[$sp],Re,Enable4 + pop.s Rb, Re, { $fp $gp $lp $sp } ==> lmw.bim Rb,[$sp],Re,Enable4 */ + { "push.s", 3, do_pseudo_pushpop_stack, 0, 0 }, + { "pop.s", 3, do_pseudo_pushpop_stack, 1, 0 }, + { "push.b", 2, do_pseudo_push_bhwd, 0, 0 }, + { "push.h", 2, do_pseudo_push_bhwd, 1, 0 }, + { "push.w", 2, do_pseudo_push_bhwd, 2, 0 }, + { "push.d", 2, do_pseudo_push_bhwd, 3, 0 }, + { "pop.b", 3, do_pseudo_pop_bhwd, 0, 0 }, + { "pop.h", 3, do_pseudo_pop_bhwd, 1, 0 }, + { "pop.w", 3, do_pseudo_pop_bhwd, 2, 0 }, + { "pop.d", 3, do_pseudo_pop_bhwd, 3, 0 }, + { "pusha", 2, do_pseudo_pusha, 0, 0 }, + { "pushi", 2, do_pseudo_pushi, 0, 0 }, + + {NULL, 0, NULL, 0, 0} +}; + +static void +nds32_init_nds32_pseudo_opcodes (void) +{ + struct nds32_pseudo_opcode *opcode = nds32_pseudo_opcode_table; + + nds32_pseudo_opcode_hash = hash_new (); + for ( ; opcode->opcode; opcode++) + { + void *op; + + op = hash_find (nds32_pseudo_opcode_hash, opcode->opcode); + if (op != NULL) + { + as_warn (_("Duplicated pseudo-opcode %s."), opcode->opcode); + continue; + } + hash_insert (nds32_pseudo_opcode_hash, opcode->opcode, opcode); + } +} + +static struct nds32_pseudo_opcode * +nds32_lookup_pseudo_opcode (char *str) +{ + int i = 0; + /* Assume pseudo-opcode are less than 16-char in length. */ + char op[16] = {0}; + + for (i = 0; i < (int)ARRAY_SIZE (op); i++) + { + if (ISSPACE(op[i] = str[i])) + break; + } + + if (i >= (int)ARRAY_SIZE (op)) + return NULL; + + op[i] = '\0'; + + return hash_find (nds32_pseudo_opcode_hash, op); +} + +static void +nds32_pseudo_opcode_wrapper (char *line, struct nds32_pseudo_opcode *opcode) +{ + int argc = 0; + char *argv[8] = {NULL}; + char *s; + char *str = xstrdup (line); + + /* Parse arguments for opcode. */ + s = str + strlen (opcode->opcode); + + if (!s[0]) + goto end; + + /* Dummy comma to ease separate arguments as below. */ + s[0] = ','; + do + { + if (s[0] == ',') + { + if (argc >= opcode->argc + || (argc >= (int)ARRAY_SIZE (argv) - 1)) + as_bad (_("Too many argument. `%s'"), line); + + argv[argc] = s + 1; + argc ++; + s[0] = '\0'; + } + ++s; + } while (s[0] != '\0'); +end: + /* Put the origin line for debugging. */ + argv[argc] = line; + opcode->proc (argc, argv, opcode->pseudo_val); + free (str); +} + +/* This function will be invoked from function `nds32_after_parse_args'. + Thus, if the value of option has been set, keep the value the way it is. */ + +static int +nds32_parse_arch (char *str) +{ + static const struct nds32_arch + { + const char *name; + int baseline; + int reduced_reg; + int fpu_sp_ext; + int fpu_dp_ext; + int fpu_freg; + int abi; + } archs[] = + { + {"v3m", ISA_V3M, 1, 0, 0, E_NDS32_FPU_REG_32SP_16DP, E_NDS_ABI_AABI}, + {"v3j", ISA_V3, 1, 0, 0, E_NDS32_FPU_REG_32SP_16DP, E_NDS_ABI_AABI}, + {"v3s", ISA_V3, 0, 1, 0, E_NDS32_FPU_REG_32SP_16DP, E_NDS_ABI_V2FP_PLUS}, + {"v3f", ISA_V3, 0, 1, 1, E_NDS32_FPU_REG_32SP_16DP, E_NDS_ABI_V2FP_PLUS}, + {"v3", ISA_V3, 0, 0, 0, E_NDS32_FPU_REG_32SP_16DP, E_NDS_ABI_AABI}, + {"v2j", ISA_V2, 1, 0, 0, E_NDS32_FPU_REG_32SP_16DP, E_NDS_ABI_AABI}, + {"v2s", ISA_V2, 0, 1, 0, E_NDS32_FPU_REG_32SP_16DP, E_NDS_ABI_V2FP_PLUS}, + {"v2f", ISA_V2, 0, 1, 1, E_NDS32_FPU_REG_32SP_16DP, E_NDS_ABI_V2FP_PLUS}, + {"v2", ISA_V2, 0, 0, 0, E_NDS32_FPU_REG_32SP_16DP, E_NDS_ABI_AABI}, + }; + size_t i; + + for (i = 0; i < ARRAY_SIZE (archs); i++) + { + if (strcmp (str, archs[i].name) != 0) + continue; + + /* The value `-1' represents this option has *NOT* been set. */ + nds32_baseline = (-1 != nds32_baseline) ? nds32_baseline : archs[i].baseline; + nds32_gpr16 = (-1 != nds32_gpr16) ? nds32_gpr16 : archs[i].reduced_reg; + nds32_fpu_sp_ext = (-1 != nds32_fpu_sp_ext) ? nds32_fpu_sp_ext : archs[i].fpu_sp_ext; + nds32_fpu_dp_ext = (-1 != nds32_fpu_dp_ext) ? nds32_fpu_dp_ext : archs[i].fpu_dp_ext; + nds32_freg = (-1 != nds32_freg) ? nds32_freg : archs[i].fpu_freg; + nds32_abi = (-1 != nds32_abi) ? nds32_abi : archs[i].abi; + + return 1; + } + + /* Logic here rejects the input arch name. */ + as_bad (_("unknown arch name `%s'\n"), str); + + return 1; +} + +/* This function parses "baseline" specified. */ + +static int +nds32_parse_baseline (char *str) +{ + if (strcmp (str, "v3") == 0) + nds32_baseline = ISA_V3; + else if (strcmp (str, "v3m") == 0) + nds32_baseline = ISA_V3M; + else if (strcmp (str, "v2") == 0) + nds32_baseline = ISA_V2; + else + { + /* Logic here rejects the input baseline. */ + as_bad (_("unknown baseline `%s'\n"), str); + return 0; + } + + return 1; +} + +/* This function parses "fpu-freg" specified. */ + +static int +nds32_parse_freg (char *str) +{ + if (strcmp (str, "2") == 0) + nds32_freg = E_NDS32_FPU_REG_32SP_16DP; + else if (strcmp (str, "3") == 0) + nds32_freg = E_NDS32_FPU_REG_32SP_32DP; + else if (strcmp (str, "1") == 0) + nds32_freg = E_NDS32_FPU_REG_16SP_8DP; + else if (strcmp (str, "0") == 0) + nds32_freg = E_NDS32_FPU_REG_8SP_4DP; + else + { + /* Logic here rejects the input FPU configuration. */ + as_bad (_("unknown FPU configuration `%s'\n"), str); + return 0; + } + + return 1; +} + +/* This function parse "abi=" specified. */ + +static int +nds32_parse_abi (char *str) +{ + if (strcmp (str, "v2") == 0) + nds32_abi = E_NDS_ABI_AABI; + /* Obsolete. */ + else if (strcmp (str, "v2fp") == 0) + nds32_abi = E_NDS_ABI_V2FP; + else if (strcmp (str, "v1") == 0) + nds32_abi = E_NDS_ABI_V1; + else if (strcmp (str,"v2fpp") == 0) + nds32_abi = E_NDS_ABI_V2FP_PLUS; + else + { + /* Logic here rejects the input abi version. */ + as_bad (_("unknown ABI version`%s'\n"), str); + return 0; + } + + return 1; +} + +/* This function turn on all extensions and instructions support. */ + +static int +nds32_all_ext (void) +{ + nds32_mac = 1; + nds32_div = 1; + nds32_dx_regs = 1; + nds32_16bit_ext = 1; + nds32_perf_ext = 1; + nds32_perf_ext2 = 1; + nds32_string_ext = 1; + nds32_audio_ext = 1; + nds32_fpu_fma = 1; + nds32_fpu_sp_ext = 1; + nds32_fpu_dp_ext = 1; + + return 1; +} + +/* GAS will call md_parse_option whenever getopt returns an unrecognized code, + presumably indicating a special code value which appears in md_longopts. + This function should return non-zero if it handled the option and zero + otherwise. There is no need to print a message about an option not being + recognized. This will be handled by the generic code. */ + +int +nds32_parse_option (int c, char *arg) +{ + struct nds32_parse_option_table *coarse_tune; + struct nds32_set_option_table *fine_tune; + char *ptr_arg = NULL; + + switch (c) + { + case OPTION_OPTIMIZE: + optimize = 1; + optimize_for_space = 0; + break; + case OPTION_OPTIMIZE_SPACE: + optimize = 0; + optimize_for_space = 1; + break; + case OPTION_BIG: + target_big_endian = 1; + break; + case OPTION_LITTLE: + target_big_endian = 0; + break; + case OPTION_TURBO: + nds32_all_ext (); + break; + case OPTION_PIC: + nds32_pic = 1; + break; + case OPTION_RELAX_FP_AS_GP_OFF: + nds32_relax_fp_as_gp = 0; + break; + case OPTION_RELAX_B2BB_ON: + nds32_relax_b2bb = 1; + break; + case OPTION_RELAX_ALL_OFF: + nds32_relax_all = 0; + break; + default: + /* Determination of which option table to search for to save time. */ + ptr_arg = strchr (arg, '='); + if (ptr_arg) + { + /* Find the value after '='. */ + if (ptr_arg != NULL) + ptr_arg++; + for (coarse_tune = parse_opts; coarse_tune->name != NULL; coarse_tune++) + { + if (strncmp (arg, coarse_tune->name, (ptr_arg - arg)) == 0) + { + coarse_tune->func (ptr_arg); + return 1; + } + } + } + else + { + for (fine_tune = toggle_opts; fine_tune->name != NULL; fine_tune++) + { + int disable = 0; + + /* Filter out the Disable option first. */ + if (strncmp (arg, "no-", 3) == 0) + { + disable = 1; + arg += 3; + } + + if (strcmp (arg, fine_tune->name) == 0) + { + if (fine_tune->var != NULL) + *fine_tune->var = (disable) ? 0 : 1; + return 1; + } + } + } + /* Nothing match. */ + return 0; + } + + return 1; +} + +/* tc_check_label */ + +void +nds32_check_label (symbolS *label ATTRIBUTE_UNUSED) +{ + /* The code used to create BB is move to frob_label. + They should go there. */ +} + +static void +set_endian_little (int on) +{ + target_big_endian = !on; +} + +/* These functions toggles the generation of 16-bit. First encounter signals + the beginning of not generating 16-bit instructions and next encounter + signals the restoring back to default behavior. */ + +static void +trigger_16bit (int trigger) +{ + enable_16bit = trigger; +} + +static int backup_16bit_mode; +static void +restore_16bit (int no_use ATTRIBUTE_UNUSED) +{ + enable_16bit = backup_16bit_mode; +} + +static void +off_16bit (int no_use ATTRIBUTE_UNUSED) +{ + backup_16bit_mode = enable_16bit; + enable_16bit = 0; +} + +/* Built-in segments for small object. */ +typedef struct nds32_seg_entryT +{ + segT s; + const char *name; + flagword flags; +} nds32_seg_entry; + +nds32_seg_entry nds32_seg_table[] = { + {NULL, ".sdata_f", SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA + | SEC_HAS_CONTENTS | SEC_SMALL_DATA}, + {NULL, ".sdata_b", SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA + | SEC_HAS_CONTENTS | SEC_SMALL_DATA}, + {NULL, ".sdata_h", SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA + | SEC_HAS_CONTENTS | SEC_SMALL_DATA}, + {NULL, ".sdata_w", SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA + | SEC_HAS_CONTENTS | SEC_SMALL_DATA}, + {NULL, ".sdata_d", SEC_ALLOC | SEC_LOAD | SEC_RELOC | SEC_DATA + | SEC_HAS_CONTENTS | SEC_SMALL_DATA}, + {NULL, ".sbss_f", SEC_ALLOC | SEC_SMALL_DATA}, + {NULL, ".sbss_b", SEC_ALLOC | SEC_SMALL_DATA}, + {NULL, ".sbss_h", SEC_ALLOC | SEC_SMALL_DATA}, + {NULL, ".sbss_w", SEC_ALLOC | SEC_SMALL_DATA}, + {NULL, ".sbss_d", SEC_ALLOC | SEC_SMALL_DATA} +}; + +/* Indexes to nds32_seg_table[]. */ +enum NDS32_SECTIONS_ENUM +{ + SDATA_F_SECTION = 0, + SDATA_B_SECTION = 1, + SDATA_H_SECTION = 2, + SDATA_W_SECTION = 3, + SDATA_D_SECTION = 4, + SBSS_F_SECTION = 5, + SBSS_B_SECTION = 6, + SBSS_H_SECTION = 7, + SBSS_W_SECTION = 8, + SBSS_D_SECTION = 9 +}; + +/* The following code is borrowed from v850_seg. Revise this is needed. */ + +static void +do_nds32_seg (int i, subsegT sub) +{ + nds32_seg_entry *seg = nds32_seg_table + i; + + obj_elf_section_change_hook (); + + if (seg->s != NULL) + subseg_set (seg->s, sub); + else + { + seg->s = subseg_new (seg->name, sub); + if (OUTPUT_FLAVOR == bfd_target_elf_flavour) + { + bfd_set_section_flags (stdoutput, seg->s, seg->flags); + if ((seg->flags & SEC_LOAD) == 0) + seg_info (seg->s)->bss = 1; + } + } +} + +static void +nds32_seg (int i) +{ + subsegT sub = get_absolute_expression (); + + do_nds32_seg (i, sub); + demand_empty_rest_of_line (); +} + +/* Set if label adjustment is needed. I should not adjust .xbyte in dwarf. */ +static symbolS *nds32_last_label; /* Last label for aligment. */ + +/* This code is referred from D30V for adjust label to be with pedning + aligment. For example, + LBYTE: .byte 0x12 + LHALF: .half 0x12 + LWORD: .word 0x12 + Without this, the above label will not attatch to incoming data. */ + +static void +nds32_adjust_label (int n) +{ + /* FIXME: I think adjust lable and alignment is + the programmer's obligation. Saddly, VLSI team doesn't + properly use .align for their test cases. + So I re-implement cons_align and auto adjust labels, again. + + I think d30v's implmentation is simple and good enough. */ + + symbolS *label = nds32_last_label; + nds32_last_label = NULL; + + /* SEC_ALLOC is used to eliminate .debug_ sections. + SEC_CODE is used to include section for ILM. */ + if (((now_seg->flags & SEC_ALLOC) == 0 && (now_seg->flags & SEC_CODE) == 0) + || strcmp (now_seg->name, ".eh_frame") == 0 + || strcmp (now_seg->name, ".gcc_except_table") == 0) + return; + + /* Only frag by alignment when needed. + Otherwise, it will fail to optimize labels on 4-byte boundary. (bug8454) + See md_convert_frag () and RELAX_SET_RELAXABLE (frag) for details. */ + if (frag_now_fix () & ((1 << n) -1 )) + { + if (subseg_text_p (now_seg)) + frag_align_code (n, 0); + else + frag_align (n, 0, 0); + + /* Record the minimum alignment for this segment. */ + record_alignment (now_seg, n - OCTETS_PER_BYTE_POWER); + } + + if (label != NULL) + { + symbolS *sym; + int label_seen = FALSE; + struct frag *old_frag; + valueT old_value, new_value; + + gas_assert (S_GET_SEGMENT (label) == now_seg); + + old_frag = symbol_get_frag (label); + old_value = S_GET_VALUE (label); + new_value = (valueT) frag_now_fix (); + + /* Multiple labels may be on the same address. And the last symbol + may not be a label at all, e.g., register name, external function names, + so I have to track the last label in tc_frob_label instead of + just using symbol_lastP. */ + for (sym = symbol_lastP; sym != NULL; sym = symbol_previous (sym)) + { + if (symbol_get_frag (sym) == old_frag + && S_GET_VALUE (sym) == old_value) + { + /* Warning HERE! */ + label_seen = TRUE; + symbol_set_frag (sym, frag_now); + S_SET_VALUE (sym, new_value); + } + else if (label_seen && symbol_get_frag (sym) != old_frag) + break; + } + } +} + +void +nds32_cons_align (int size ATTRIBUTE_UNUSED) +{ + /* Do nothing here. + This is called before `md_flush_pending_output' is called by `cons'. + + There are two things should be done for auto-adjust-label. + 1. Align data/instructions and adjust label to be attached to them. + 2. Clear auto-adjust state, so incommng data/instructions will not + adjust the label. + + For example, + .byte 0x1 + .L0: + .word 0x2 + .word 0x3 + in this case, '.word 0x2' will adjust the label, .L0, but '.word 0x3' should not. + + I think `md_flush_pending_output' is a good place to clear the auto-adjust state, + but it is also called by `cons' before this function. + To simplify the code, instead of overriding .zero, .fill, .space, etc, + I think we should just adjust label in `nds32_aligned_X_cons' instead of here. */ +} + +static void +nds32_aligned_cons (int idx) +{ + nds32_adjust_label (idx); + /* Call default handler. */ + cons (1 << idx); + if (now_seg->flags & SEC_CODE + && now_seg->flags & SEC_ALLOC && now_seg->flags & SEC_RELOC) + { + /* Use BFD_RELOC_NDS32_DATA to avoid EX9 optimization replacing data. */ + expressionS exp; + + exp.X_add_number = 0; + exp.X_op = O_constant; + fix_new_exp (frag_now, + frag_now_fix () - (1 << idx), + 1 << idx, + &exp, + 0, + BFD_RELOC_NDS32_DATA); + } +} + +/* `.double' directive. */ + +static void +nds32_aligned_float_cons (int type) +{ + switch (type) + { + case 'f': + case 'F': + case 's': + case 'S': + nds32_adjust_label (2); + break; + case 'd': + case 'D': + case 'r': + case 'R': + nds32_adjust_label (4); + break; + default: + as_bad ("Unrecognized float type, %c\n", (char)type); + } + /* Call default handler. */ + float_cons (type); +} + +static void +nds32_enable_pic (int ignore ATTRIBUTE_UNUSED) +{ + /* Another way to do -mpic. + This is for GCC internal use and should always be first line + of code, otherwise, the effect is not determined. */ + nds32_pic = 1; +} + +static void +nds32_set_abi (int ver) +{ + nds32_abi = ver; +} + +/* Relax directive to set relocation R_NDS32_RELAX_ENTRY value. */ + +static void +nds32_relax_relocs (int relax) +{ + char saved_char; + char *name; + int i; + char *subtype_relax[] = + {"", "", "ex9", "ifc"}; + + name = input_line_pointer; + while (*input_line_pointer && !ISSPACE (*input_line_pointer)) + input_line_pointer++; + saved_char = *input_line_pointer; + *input_line_pointer = 0; + + for (i = 0; i < (int) ARRAY_SIZE(subtype_relax); i++) + { + if (strcmp (name, subtype_relax[i]) == 0) + { + switch (i) + { + case 0: + case 1: + enable_relax_relocs = relax & enable_relax_relocs; + enable_relax_ex9 = relax & enable_relax_ex9; + enable_relax_ifc = relax & enable_relax_ifc; + break; + case 2: + enable_relax_ex9 = relax; + break; + case 3: + enable_relax_ifc = relax; + break; + default: + break; + } + break; + } + } + *input_line_pointer = saved_char; + ignore_rest_of_line (); +} + +/* Record which arguments register($r0 ~ $r5) is not used in callee. + bit[i] for $ri */ + +static void +nds32_set_hint_func_args (int ignore ATTRIBUTE_UNUSED) +{ + ignore_rest_of_line (); +} + +/* Insert relocations to mark the begin and end of a fp-omitted function, + for further relaxation use. + bit[i] for $ri */ + +static void +nds32_omit_fp_begin (int mode) +{ + expressionS exp; + + if (nds32_relax_fp_as_gp == 0) + return; + exp.X_op = O_symbol; + exp.X_add_symbol = abs_section_sym; + if (mode == 1) + { + exp.X_add_number = R_NDS32_RELAX_REGION_OMIT_FP_FLAG; + fix_new_exp (frag_now, frag_now_fix (), 0, &exp, 0, + BFD_RELOC_NDS32_RELAX_REGION_BEGIN); + } + else + { + exp.X_add_number = R_NDS32_RELAX_REGION_OMIT_FP_FLAG; + fix_new_exp (frag_now, frag_now_fix (), 0, &exp, 0, + BFD_RELOC_NDS32_RELAX_REGION_END); + } +} + +/* Insert relocations to mark the begin and end of ex9 region, + for further relaxation use. + bit[i] for $ri */ + +static void +nds32_no_ex9_begin (int mode) +{ + expressionS exp; + + exp.X_op = O_symbol; + exp.X_add_symbol = abs_section_sym; + if (mode == 1) + { + exp.X_add_number = R_NDS32_RELAX_REGION_NO_EX9_FLAG; + fix_new_exp (frag_now, frag_now_fix (), 0, &exp, 0, + BFD_RELOC_NDS32_RELAX_REGION_BEGIN); + } + else + { + exp.X_add_number = R_NDS32_RELAX_REGION_NO_EX9_FLAG; + fix_new_exp (frag_now, frag_now_fix (), 0, &exp, 0, + BFD_RELOC_NDS32_RELAX_REGION_END); + } +} + +static void +nds32_loop_begin (int mode) +{ + /* Insert loop region relocation here. */ + expressionS exp; + + exp.X_op = O_symbol; + exp.X_add_symbol = abs_section_sym; + if (mode == 1) + { + exp.X_add_number = R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG; + fix_new_exp (frag_now, frag_now_fix (), 0, &exp, 0, + BFD_RELOC_NDS32_RELAX_REGION_BEGIN); + } + else + { + exp.X_add_number = R_NDS32_RELAX_REGION_INNERMOST_LOOP_FLAG; + fix_new_exp (frag_now, frag_now_fix (), 0, &exp, 0, + BFD_RELOC_NDS32_RELAX_REGION_END); + } +} + +struct nds32_relocs_group +{ + struct nds32_relocs_pattern *pattern; + struct nds32_relocs_group *next; +}; + +static struct nds32_relocs_group *nds32_relax_hint_current = NULL; + +/* Insert a relax hint. */ + +static void +nds32_relax_hint (int mode ATTRIBUTE_UNUSED) +{ + char *name; + char saved_char; + struct nds32_relocs_pattern *relocs = NULL; + struct nds32_relocs_group *group, *new; + + name = input_line_pointer; + while (*input_line_pointer && !ISSPACE (*input_line_pointer)) + input_line_pointer++; + saved_char = *input_line_pointer; + *input_line_pointer = 0; + name = strdup (name); + + /* Find relax hint entry for next instruction, and all member will be + initialized at that time. */ + relocs = hash_find (nds32_hint_hash, name); + if (relocs == NULL) + { + relocs = malloc (sizeof (struct nds32_relocs_pattern)); + hash_insert (nds32_hint_hash, name, relocs); + } + else + { + while (relocs->next) + relocs=relocs->next; + relocs->next = malloc (sizeof (struct nds32_relocs_pattern)); + relocs = relocs->next; + } + + relocs->next = NULL; + *input_line_pointer = saved_char; + ignore_rest_of_line (); + + /* Get the final one of relax hint series. */ + + /* It has to build this list because there are maybe more than one + instructions relative to the same instruction. It to connect to + next instruction after md_assemble. */ + new = malloc (sizeof (struct nds32_relocs_group)); + new->pattern = relocs; + new->next = NULL; + group = nds32_relax_hint_current; + if (!group) + nds32_relax_hint_current = new; + else + { + while (group->next != NULL) + group = group->next; + group->next = new; + } +} + +/* Decide the size of vector entries, only accepts 4 or 16 now. */ + +static void +nds32_vec_size (int ignore ATTRIBUTE_UNUSED) +{ + expressionS exp; + + expression (&exp); + + if (exp.X_op == O_constant) + { + if (exp.X_add_number == 4 || exp.X_add_number == 16) + { + if (vec_size == 0) + vec_size = exp.X_add_number; + else if (vec_size != exp.X_add_number) + as_warn (_("Different arguments of .vec_size are found, " + "previous %d, current %d"), + (int) vec_size, (int) exp.X_add_number); + } + else + as_warn (_("Argument of .vec_size is expected 4 or 16, actual: %d."), + (int) exp.X_add_number); + } + else + as_warn (_("Argument of .vec_size is not a constant.")); +} + +/* The behavior of ".flag" directive varies depending on the target. + In nds32 target, we use it to recognize whether this assembly content is + generated by compiler. Other features can also be added in this function + in the future. */ + +static void +nds32_flag (int ignore ATTRIBUTE_UNUSED) +{ + char *name; + char saved_char; + int i; + char *possible_flags[] = { "verbatim" }; + + /* Skip whitespaces. */ + name = input_line_pointer; + while (*input_line_pointer && !ISSPACE (*input_line_pointer)) + input_line_pointer++; + saved_char = *input_line_pointer; + *input_line_pointer = 0; + + for (i = 0; i < (int) ARRAY_SIZE (possible_flags); i++) + { + if (strcmp (name, possible_flags[i]) == 0) + { + switch (i) + { + case 0: + /* flag: verbatim */ + verbatim = 1; + break; + default: + break; + } + /* Already found the flag, no need to continue next loop. */ + break; + } + } + + *input_line_pointer = saved_char; + ignore_rest_of_line (); +} + +static void +nds32_n12hc (int ignore ATTRIBUTE_UNUSED) +{ + /* N1213HC core is used. */ +} + + +/* The target specific pseudo-ops which we support. */ +const pseudo_typeS md_pseudo_table[] = { + /* Forced alignment if declared these ways. */ + {"ascii", stringer, 8 + 0}, + {"asciz", stringer, 8 + 1}, + {"double", nds32_aligned_float_cons, 'd'}, + {"dword", nds32_aligned_cons, 3}, + {"float", nds32_aligned_float_cons, 'f'}, + {"half", nds32_aligned_cons, 1}, + {"hword", nds32_aligned_cons, 1}, + {"int", nds32_aligned_cons, 2}, + {"long", nds32_aligned_cons, 2}, + {"octa", nds32_aligned_cons, 4}, + {"quad", nds32_aligned_cons, 3}, + {"qword", nds32_aligned_cons, 4}, + {"short", nds32_aligned_cons, 1}, + {"byte", nds32_aligned_cons, 0}, + {"single", nds32_aligned_float_cons, 'f'}, + {"string", stringer, 8 + 1}, + {"word", nds32_aligned_cons, 2}, + + {"little", set_endian_little, 1}, + {"big", set_endian_little, 0}, + {"16bit_on", trigger_16bit, 1}, + {"16bit_off", trigger_16bit, 0}, + {"restore_16bit", restore_16bit, 0}, + {"off_16bit", off_16bit, 0}, + + {"sdata_d", nds32_seg, SDATA_D_SECTION}, + {"sdata_w", nds32_seg, SDATA_W_SECTION}, + {"sdata_h", nds32_seg, SDATA_H_SECTION}, + {"sdata_b", nds32_seg, SDATA_B_SECTION}, + {"sdata_f", nds32_seg, SDATA_F_SECTION}, + + {"sbss_d", nds32_seg, SBSS_D_SECTION}, + {"sbss_w", nds32_seg, SBSS_W_SECTION}, + {"sbss_h", nds32_seg, SBSS_H_SECTION}, + {"sbss_b", nds32_seg, SBSS_B_SECTION}, + {"sbss_f", nds32_seg, SBSS_F_SECTION}, + + {"pic", nds32_enable_pic, 0}, + {"n12_hc", nds32_n12hc, 0}, + {"abi_1", nds32_set_abi, E_NDS_ABI_V1}, + {"abi_2", nds32_set_abi, E_NDS_ABI_AABI}, + /* Obsolete. */ + {"abi_2fp", nds32_set_abi, E_NDS_ABI_V2FP}, + {"abi_2fp_plus", nds32_set_abi, E_NDS_ABI_V2FP_PLUS}, + {"relax", nds32_relax_relocs, 1}, + {"no_relax", nds32_relax_relocs, 0}, + {"hint_func_args", nds32_set_hint_func_args, 0}, /* Abandon?? */ + {"omit_fp_begin", nds32_omit_fp_begin, 1}, + {"omit_fp_end", nds32_omit_fp_begin, 0}, + {"no_ex9_begin", nds32_no_ex9_begin, 1}, + {"no_ex9_end", nds32_no_ex9_begin, 0}, + {"vec_size", nds32_vec_size, 0}, + {"flag", nds32_flag, 0}, + {"innermost_loop_begin", nds32_loop_begin, 1}, + {"innermost_loop_end", nds32_loop_begin, 0}, + {"relax_hint", nds32_relax_hint, 0}, + {NULL, NULL, 0} +}; + +void +nds32_pre_do_align (int n, char *fill, int len, int max) +{ + /* Only make a frag if we HAVE to... */ + if (n != 0 && !need_pass_2) + { + if (fill == NULL) + { + if (subseg_text_p (now_seg)) + frag_align_code (n, max); + else + frag_align (n, 0, max); + } + else if (len <= 1) + frag_align (n, *fill, max); + else + frag_align_pattern (n, fill, len, max); + } +} + +void +nds32_do_align (int n) +{ + /* Optimize for space and label exists. */ + expressionS exp; + + /* FIXME:I think this will break debug info sections and except_table. */ + if (!enable_relax_relocs || !subseg_text_p (now_seg)) + return; + + /* Create and attach a BFD_RELOC_NDS32_LABEL fixup + the size of instruction may not be correct because + it could be relaxable. */ + exp.X_op = O_symbol; + exp.X_add_symbol = section_symbol (now_seg); + exp.X_add_number = n; + fix_new_exp (frag_now, + frag_now_fix (), 0, &exp, 0, BFD_RELOC_NDS32_LABEL); +} + +/* Supported Andes machines. */ +struct nds32_machs +{ + enum bfd_architecture bfd_mach; + int mach_flags; +}; + +/* This is the callback for nds32-asm.c to parse operands. */ + +int +nds32_asm_parse_operand (struct nds32_asm_desc *pdesc ATTRIBUTE_UNUSED, + struct nds32_asm_insn *pinsn, + char **pstr, int64_t *value) +{ + char *hold; + expressionS *pexp = pinsn->info; + + hold = input_line_pointer; + input_line_pointer = *pstr; + expression (pexp); + *pstr = input_line_pointer; + input_line_pointer = hold; + + switch (pexp->X_op) + { + case O_symbol: + *value = 0; + return NASM_R_SYMBOL; + case O_constant: + *value = pexp->X_add_number; + return NASM_R_CONST; + case O_illegal: + case O_absent: + case O_register: + default: + return NASM_R_ILLEGAL; + } +} + +/* GAS will call this function at the start of the assembly, after the command + line arguments have been parsed and all the machine independent + initializations have been completed. */ + +void +md_begin (void) +{ + struct nds32_keyword *k; + relax_info_t *relax_info; + + bfd_set_arch_mach (stdoutput, TARGET_ARCH, nds32_baseline); + + nds32_init_nds32_pseudo_opcodes (); + asm_desc.parse_operand = nds32_asm_parse_operand; + nds32_asm_init (&asm_desc, 0); + + /* Initial general pupose registers hash table. */ + nds32_gprs_hash = hash_new (); + for (k = nds32_gprs; k->name; k++) + hash_insert (nds32_gprs_hash, k->name, k); + + /* Initial branch hash table. */ + nds32_relax_info_hash = hash_new (); + for (relax_info = relax_table; relax_info->opcode; relax_info++) + hash_insert (nds32_relax_info_hash, relax_info->opcode, relax_info); + + /* Initial relax hint hash table. */ + nds32_hint_hash = hash_new (); +} + +/* HANDLE_ALIGN in write.c. */ + +void +nds32_handle_align (fragS *fragp) +{ + static const unsigned char nop16[] = { 0x92, 0x00 }; + static const unsigned char nop32[] = { 0x40, 0x00, 0x00, 0x09 }; + int bytes; + char *p; + + if (fragp->fr_type != rs_align_code) + return; + + bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix; + p = fragp->fr_literal + fragp->fr_fix; + + if (bytes & 1) + { + *p++ = 0; + bytes--; + } + + if (bytes & 2) + { + expressionS exp_t; + exp_t.X_op = O_symbol; + exp_t.X_add_symbol = abs_section_sym; + exp_t.X_add_number = R_NDS32_INSN16_CONVERT_FLAG; + fix_new_exp (fragp, fragp->fr_fix, 2, &exp_t, 0, + BFD_RELOC_NDS32_INSN16); + memcpy (p, nop16, 2); + p += 2; + bytes -= 2; + } + + while (bytes >= 4) + { + memcpy (p, nop32, 4); + p += 4; + bytes -= 4; + } + + bytes = fragp->fr_next->fr_address - fragp->fr_address - fragp->fr_fix; + fragp->fr_fix += bytes; +} + +/* md_flush_pending_output */ + +void +nds32_flush_pending_output (void) +{ + nds32_last_label = NULL; +} + +void +nds32_frob_label (symbolS *label) +{ + dwarf2_emit_label (label); +} + +/* TC_START_LABEL */ + +int +nds32_start_label (int asmdone ATTRIBUTE_UNUSED, int secdone ATTRIBUTE_UNUSED) +{ + return 1; +} + +/* TARGET_FORMAT */ + +const char * +nds32_target_format (void) +{ +#ifdef TE_LINUX + if (target_big_endian) + return "elf32-nds32be-linux"; + else + return "elf32-nds32le-linux"; +#else + if (target_big_endian) + return "elf32-nds32be"; + else + return "elf32-nds32le"; +#endif +} + +static enum nds32_br_range +get_range_type (const struct nds32_field *field) +{ + gas_assert (field != NULL); + + if (field->bitpos != 0) + return BR_RANGE_U4G; + + if (field->bitsize == 24 && field->shift == 1) + return BR_RANGE_S16M; + else if (field->bitsize == 16 && field->shift == 1) + return BR_RANGE_S64K; + else if (field->bitsize == 14 && field->shift == 1) + return BR_RANGE_S16K; + else if (field->bitsize == 8 && field->shift == 1) + return BR_RANGE_S256; + else + return BR_RANGE_U4G; +} + +/* Save pseudo instruction relocation list. */ + +static struct nds32_relocs_pattern* +nds32_elf_save_pseudo_pattern (int reloc, struct nds32_asm_insn *insn, + char *out, symbolS *sym, + struct nds32_relocs_pattern *reloc_ptr) +{ + if (!reloc_ptr) + reloc_ptr = malloc (sizeof (struct nds32_relocs_pattern)); + reloc_ptr->seg = now_seg; + reloc_ptr->sym = sym; + reloc_ptr->frag = frag_now; + reloc_ptr->frchain = frchain_now; + reloc_ptr->reloc = reloc; + reloc_ptr->insn = insn->opcode->value; + reloc_ptr->size = insn->opcode->isize; + reloc_ptr->where = out; + reloc_ptr->next = NULL; + return reloc_ptr; +} + +/* Check X_md to transform relocation. */ + +static void +nds32_elf_record_fixup_exp (char *str, const struct nds32_field *fld, + expressionS *pexp, char* out, + struct nds32_asm_insn *insn) +{ + int reloc = -1; + symbolS *sym = NULL; + struct nds32_relocs_group *group; + struct nds32_relocs_pattern *reloc_ptr; + + /* Handle instruction relocation. */ + if (fld && fld->bitpos == 0 && (insn->attr & NASM_ATTR_HI20)) + { + /* Relocation for hi20 modifier. */ + sym = pexp->X_add_symbol; + switch (pexp->X_md) + { + case BFD_RELOC_NDS32_GOTOFF: + /* @GOTOFF */ + reloc = BFD_RELOC_NDS32_GOTOFF_HI20; + break; + case BFD_RELOC_NDS32_GOT20: + /* @GOT */ + reloc = BFD_RELOC_NDS32_GOT_HI20; + break; + case BFD_RELOC_NDS32_25_PLTREL: + /* @PLT */ + if (!nds32_pic) + as_bad (_("Invalid PIC expression.")); + else + reloc = BFD_RELOC_NDS32_PLT_GOTREL_HI20; + break; + default: + /* No suffix. */ + reloc = BFD_RELOC_NDS32_HI20; + break; + } + + fix_new_exp (frag_now, out - frag_now->fr_literal, + insn->opcode->isize, insn->info, 0 /* pcrel */, + reloc); + } + else if (fld && fld->bitpos == 0 && (insn->attr & NASM_ATTR_LO12)) + { + /* Relocation for lo12 modifier. */ + if (fld->bitsize == 15 && fld->shift == 0) + { + switch (pexp->X_md) + { + case BFD_RELOC_NDS32_GOTOFF: + /* @GOTOFF */ + reloc = BFD_RELOC_NDS32_GOTOFF_LO12; + break; + case BFD_RELOC_NDS32_GOT20: + /* @GOT */ + reloc = BFD_RELOC_NDS32_GOT_LO12; + break; + case BFD_RELOC_NDS32_25_PLTREL: + /* @PLT */ + if (!nds32_pic) + as_bad (_("Invalid PIC expression.")); + else + reloc = BFD_RELOC_NDS32_PLT_GOTREL_LO12; + break; + default: + /* No suffix. */ + reloc = BFD_RELOC_NDS32_LO12S0; /* [ls]bi || ori */ + break; + } + } + else if (fld->bitsize == 15 && fld->shift == 1) + reloc = BFD_RELOC_NDS32_LO12S1; /* [ls]hi */ + else if (fld->bitsize == 15 && fld->shift == 2) + reloc = BFD_RELOC_NDS32_LO12S2; /* [ls]wi */ + else if (fld->bitsize == 15 && fld->shift == 3) + reloc = BFD_RELOC_NDS32_LO12S3; /* [ls]di */ + else if (fld->bitsize == 12 && fld->shift == 2) + reloc = BFD_RELOC_NDS32_LO12S2; /* f[ls][sd]i */ + + fix_new_exp (frag_now, out - frag_now->fr_literal, + insn->opcode->isize, insn->info, 0 /* pcrel */, + reloc); + } + else if (fld && fld->bitpos == 0 && insn->opcode->isize == 4 + && (insn->attr & NASM_ATTR_PCREL)) + { + /* Relocation for 32-bit branch instructions. */ + if (fld->bitsize == 24 && fld->shift == 1) + reloc = BFD_RELOC_NDS32_25_PCREL; + else if (fld->bitsize == 16 && fld->shift == 1) + reloc = BFD_RELOC_NDS32_17_PCREL; + else if (fld->bitsize == 14 && fld->shift == 1) + reloc = BFD_RELOC_NDS32_15_PCREL; + else if (fld->bitsize == 8 && fld->shift == 1) + reloc = BFD_RELOC_NDS32_WORD_9_PCREL; + else + abort (); + + fix_new_exp (frag_now, out - frag_now->fr_literal, + insn->opcode->isize, insn->info, 1 /* pcrel */, + reloc); + } + else if (fld && fld->bitpos == 0 && insn->opcode->isize == 4 + && (insn->attr & NASM_ATTR_GPREL)) + { + /* Relocation for 32-bit gp-relative instructions. */ + if (fld->bitsize == 19 && fld->shift == 0) + reloc = BFD_RELOC_NDS32_SDA19S0; + else if (fld->bitsize == 18 && fld->shift == 1) + reloc = BFD_RELOC_NDS32_SDA18S1; + else if (fld->bitsize == 17 && fld->shift == 2) + reloc = BFD_RELOC_NDS32_SDA17S2; + else + abort (); + + fix_new_exp (frag_now, out - frag_now->fr_literal, + insn->opcode->isize, insn->info, 0 /* pcrel */, + reloc); + } + else if (fld && fld->bitpos == 0 && insn->opcode->isize == 2 + && (insn->attr & NASM_ATTR_PCREL)) + { + /* Relocation for 16-bit branch instructions. */ + if (fld->bitsize == 8 && fld->shift == 1) + reloc = BFD_RELOC_NDS32_9_PCREL; + else + abort (); + + fix_new_exp (frag_now, out - frag_now->fr_literal, + insn->opcode->isize, insn->info, 1 /* pcrel */, + reloc); + } + else if (fld) + { + as_bad (_("Don't know how to handle this field. %s"), + str); + } + + if (pseudo_opcode) + { + /* Save instruction relation for pseudo instruction expanding pattern. */ + reloc_ptr = nds32_elf_save_pseudo_pattern (reloc, insn, out, sym, NULL); + if (!relocs_list) + relocs_list = reloc_ptr; + else + { + struct nds32_relocs_pattern *temp = relocs_list; + while (temp->next) + temp = temp->next; + temp->next = reloc_ptr; + } + } + else if (nds32_relax_hint_current) + { + /* Save instruction relation by relax hint. */ + group = nds32_relax_hint_current; + while (group) + { + nds32_elf_save_pseudo_pattern (reloc, insn, out, sym, group->pattern); + group = group->next; + free (nds32_relax_hint_current); + nds32_relax_hint_current = group; + } + } +} + +#define N32_MEM_EXT(insn) (N32_OP6_MEM<< 25| insn) + +/* Relax pattern for link time relaxation. */ + +static struct nds32_relocation_map relocation_table[] = +{ + { + /* Load-Store: sethi lwi+ + Load address: sethi ori */ + BFD_RELOC_NDS32_HI20, /* main_type */ + { + { + {BFD_RELOC_NDS32_LOADSTORE, 0}, + {0, 0} + }, + { + {BFD_RELOC_NDS32_INSN16, 0}, + {0, 0} + }, + { + {0, 0} + } + }, + }, + { + /* Load-Store: sethi ori lwi+ + Load address: sethi ori add */ + BFD_RELOC_NDS32_GOTOFF_HI20, /* main_type */ + { + { + {BFD_RELOC_NDS32_LOADSTORE, 0}, + {0, 0} + }, + { + {BFD_RELOC_NDS32_INSN16, 0}, + {BFD_RELOC_NDS32_PTR, 0}, + {BFD_RELOC_NDS32_PTR_COUNT, 0}, + {0, 0} + }, + { + {BFD_RELOC_NDS32_GOTOFF_SUFF, 0}, + {BFD_RELOC_NDS32_PTR_RESOLVED, 0}, + {0, 0} + }, + { + {0, 0} + } + }, + }, + { + /* Load-Store: sethi ori lw lwi+ + Load address: sethi ori lw [addi|add] */ + BFD_RELOC_NDS32_GOT_HI20, /* main_type */ + { + { + {BFD_RELOC_NDS32_LOADSTORE, 0}, + {0, 0} + }, + { + {BFD_RELOC_NDS32_INSN16, 0}, + /* For pseudo la and l.w. + Lw is the next one instruction. */ + {BFD_RELOC_NDS32_PTR, N32_MEM_EXT (N32_MEM_LW)}, + {BFD_RELOC_NDS32_PTR_COUNT, 0}, + {0, 0} + }, + { + {BFD_RELOC_NDS32_GOT_SUFF, N32_MEM_EXT (N32_MEM_LW)}, + {BFD_RELOC_NDS32_PTR_RESOLVED, N32_MEM_EXT (N32_MEM_LW)}, + {0, 0} + }, + { + {0, 0}, + }, + }, + }, + { + BFD_RELOC_NDS32_PLT_GOTREL_HI20, /* main_type */ + { + { + {BFD_RELOC_NDS32_LOADSTORE, 0}, + {0, 0} + }, + { + {BFD_RELOC_NDS32_INSN16, 0}, + /* For pseudo bal. + jral is the target instruction. */ + {BFD_RELOC_NDS32_PTR, INSN_JRAL}, + {BFD_RELOC_NDS32_PTR, (INSN_JRAL | (REG_LP << 20))}, + {BFD_RELOC_NDS32_PTR_COUNT, 0}, + {0, 0} + }, + { + /* For pseudo bal. + jral is the target instruction. */ + {BFD_RELOC_NDS32_PTR, INSN_JRAL}, + {BFD_RELOC_NDS32_PTR, (INSN_JRAL | (REG_LP << 20))}, + {BFD_RELOC_NDS32_PTR_COUNT, 0}, + {0, 0} + }, + { + {BFD_RELOC_NDS32_PLT_GOT_SUFF, 0}, + {BFD_RELOC_NDS32_PTR_RESOLVED, 0}, + {0, 0} + }, + { + {0, 0}, + }, + }, + }, + { + 0, + { + { + {0, 0}, + }, + }, + } +}; + +/* Since sethi loadstore relocation has to using next instruction to determine + elimination itself or not, we have to return the next instruction range. */ + +static int +nds32_elf_sethi_range (struct nds32_relocs_pattern *relocs_ptr) +{ + unsigned int insn = relocs_ptr->insn; + int range; + switch (insn) + { + case INSN_LBI: + case INSN_SBI: + case INSN_LBSI: + case N32_MEM_EXT (N32_MEM_LB): + case N32_MEM_EXT (N32_MEM_LBS): + case N32_MEM_EXT (N32_MEM_SB): + range = 0x01; + break; + case INSN_LHI: + case INSN_SHI: + case INSN_LHSI: + case N32_MEM_EXT (N32_MEM_LH): + case N32_MEM_EXT (N32_MEM_LHS): + case N32_MEM_EXT (N32_MEM_SH): + range = 0x02; + break; + case INSN_LWI: + case INSN_SWI: + case N32_MEM_EXT (N32_MEM_LW): + case N32_MEM_EXT (N32_MEM_SW): + range = 0x04; + break; + case INSN_FLSI: + case INSN_FSSI: + range = 0x08; + break; + case INSN_FLDI: + case INSN_FSDI: + range = 0x10; + break; + case INSN_ORI: + range = 0x20; + break; + default: + range = 0x0; + break; + } + return range; +} + +/* The args means: instruction size, the 1st instruction is converted to 16 or + not, optimize option, 16 bit instruction is enable. */ +#define SET_ADDEND( size, convertible, optimize, insn16_on ) \ + (((size) & 0xff) | ((convertible) ? 1 << 31 : 0) \ + | ((optimize) ? 1<< 30 : 0) | (insn16_on ? 1 << 29 : 0)) + +/* Insert new fix. */ + +static void +nds32_elf_insert_relocation (struct nds32_relocs_pattern *pattern, unsigned int reloc, + unsigned int insn_mask, symbolS *sym) +{ + expressionS exp; + symbolS *sym_t; + struct nds32_relocs_pattern *pattern_t; + int range; + fragS *frag = pattern->frag; + char *out = pattern->where; + unsigned int size = pattern->size; + static int ptr_count = 0; + + exp.X_op = O_symbol; + exp.X_add_symbol = abs_section_sym; + exp.X_add_number = 0; + + switch (reloc) + { + case BFD_RELOC_NDS32_LOADSTORE: + /* To get the sethi match pattern. */ + range = nds32_elf_sethi_range (pattern->next); + exp.X_add_number = SET_ADDEND (4 /* size */, 0, optimize, enable_16bit); + exp.X_add_number |= ((range & 0x3f) << 8); + fix_new_exp (frag, out - frag->fr_literal, size, &exp, 0 /* pcrel */, reloc); + break; + + case BFD_RELOC_NDS32_PTR: + pattern_t = pattern->next; + while (pattern_t) + { + if (insn_mask == 0 || pattern_t->insn == insn_mask) + { + sym_t = symbol_temp_new (pattern_t->seg, + pattern_t->where - pattern_t->frag->fr_literal, + pattern_t->frag); + exp.X_add_symbol = sym_t; + fix_new_exp (frag, out - frag->fr_literal, 0, &exp, 0 /* pcrel */, reloc); + ptr_count++; + break; + } + pattern_t = pattern_t->next; + } + break; + + case BFD_RELOC_NDS32_PTR_COUNT: + /* In current design, it only be referanced once. */ + if (ptr_count != 0) + { + exp.X_add_number = ptr_count; + fix_new_exp (frag, out - frag->fr_literal, size, &exp, 0, reloc); + } + ptr_count = 0; + break; + + case BFD_RELOC_NDS32_GOTOFF_SUFF: + case BFD_RELOC_NDS32_GOT_SUFF: + case BFD_RELOC_NDS32_PLT_GOT_SUFF: + /* It has to record symbol. */ + if (insn_mask == 0 || pattern->insn == insn_mask) + { + exp.X_add_symbol = sym; + fix_new_exp (frag, out - frag->fr_literal, size, &exp, 0, reloc); + } + break; + + case BFD_RELOC_NDS32_PTR_RESOLVED: + default: + if (insn_mask == 0 || pattern->insn == insn_mask) + { + fix_new_exp (frag, out - frag->fr_literal, size, &exp, 0, reloc); + } + } +} + +static void +nds32_set_elf_flags_by_insn (struct nds32_asm_insn * insn) +{ + /* Set E_NDS32_HAS_EXT_INST. */ + if (insn->opcode->attr & NASM_ATTR_PERF_EXT) + { + if (nds32_perf_ext) + nds32_elf_flags |= E_NDS32_HAS_EXT_INST; + else + as_bad (_("instruction %s requires enabling performance extension"), + insn->opcode->opcode); + } + else if (insn->opcode->attr & NASM_ATTR_PERF2_EXT) + { + if (nds32_perf_ext2) + nds32_elf_flags |= E_NDS32_HAS_EXT2_INST; + else + as_bad (_("instruction %s requires enabling performance extension II"), + insn->opcode->opcode); + } + else if (insn->opcode->attr & NASM_ATTR_AUDIO_ISAEXT) + { + if (nds32_audio_ext) + nds32_elf_flags |= E_NDS32_HAS_AUDIO_INST; + else + as_bad (_("instruction %s requires enabling AUDIO extension"), + insn->opcode->opcode); + } + else if (insn->opcode->attr & NASM_ATTR_STR_EXT) + { + if (nds32_string_ext) + nds32_elf_flags |= E_NDS32_HAS_STRING_INST; + else + as_bad (_("instruction %s requires enabling STRING extension"), + insn->opcode->opcode); + } + else if ((insn->opcode->attr & NASM_ATTR_DIV) + && (insn->opcode->attr & NASM_ATTR_DXREG)) + { + if (nds32_div && nds32_dx_regs) + nds32_elf_flags |= E_NDS32_HAS_DIV_DX_INST; + else + as_bad (_("instruction %s requires enabling DIV & DX_REGS extension"), + insn->opcode->opcode); + } + else if (insn->opcode->attr & NASM_ATTR_FPU) + { + if (nds32_fpu_sp_ext || nds32_fpu_dp_ext) + { + if (!(nds32_elf_flags & (E_NDS32_HAS_FPU_INST | E_NDS32_HAS_FPU_DP_INST))) + nds32_fpu_com = 1; + } + else + as_bad (_("instruction %s requires enabling FPU extension"), + insn->opcode->opcode); + } + else if (insn->opcode->attr & NASM_ATTR_FPU_SP_EXT) + { + if (nds32_fpu_sp_ext) + nds32_elf_flags |= E_NDS32_HAS_FPU_INST; + else + as_bad (_("instruction %s requires enabling FPU_SP extension"), + insn->opcode->opcode); + } + else if ((insn->opcode->attr & NASM_ATTR_FPU_SP_EXT) + && (insn->opcode->attr & NASM_ATTR_MAC)) + { + if (nds32_fpu_sp_ext && nds32_mac) + { + nds32_elf_flags |= E_NDS32_HAS_FPU_MAC_INST; + nds32_elf_flags |= E_NDS32_HAS_FPU_INST; + } + else + as_bad (_("instruction %s requires enabling FPU_MAC extension"), + insn->opcode->opcode); + } + else if (insn->opcode->attr & NASM_ATTR_FPU_DP_EXT) + { + if (nds32_fpu_dp_ext) + nds32_elf_flags |= E_NDS32_HAS_FPU_DP_INST; + else + as_bad (_("instruction %s requires enabling FPU_DP extension"), + insn->opcode->opcode); + } + else if ((insn->opcode->attr & NASM_ATTR_FPU_DP_EXT) + && (insn->opcode->attr & NASM_ATTR_MAC)) + { + if (nds32_fpu_dp_ext && nds32_mac) + { + nds32_elf_flags |= E_NDS32_HAS_FPU_MAC_INST; + nds32_elf_flags |= E_NDS32_HAS_FPU_DP_INST; + } + else + as_bad (_("instruction %s requires enabling FPU_MAC extension"), + insn->opcode->opcode); + } + /* TODO: FPU_BOTH */ + else if ((insn->opcode->attr & NASM_ATTR_MAC) + && (insn->opcode->attr & NASM_ATTR_DXREG)) + { + if (nds32_mac && nds32_dx_regs) + nds32_elf_flags |= E_NDS32_HAS_MAC_DX_INST; + else + as_bad (_("instruction %s requires enabling DX_REGS extension"), + insn->opcode->opcode); + } + /* TODO: for DX_REG set but not for MAC, DIV, AUDIO */ + else if (insn->opcode->attr & NASM_ATTR_IFC_EXT) + { + nds32_elf_flags |= E_NDS32_HAS_IFC_INST; + } + /* TODO: E_NDS32_HAS_SATURATION_INST */ +} + +/* Append relax relocation for link time relaxing. */ + +static void +nds32_elf_append_relax_relocs (const char *key ATTRIBUTE_UNUSED, void *value) +{ + struct nds32_relocs_pattern *relocs_temp = + (struct nds32_relocs_pattern *) value; + unsigned int reloc, group_type, insn; + symbolS *sym; + unsigned int i = 0, x = 0, y; + segT seg_bak = now_seg; + frchainS *frchain_bak = frchain_now; + + if (!relocs_temp) + return; + + group_type = relocs_temp->reloc; + sym = relocs_temp->sym; + /* Inserting fix up must specify now_seg or frchain_now. */ + now_seg = relocs_temp->seg; + frchain_now = relocs_temp->frchain; + + /* Find pattern in relocation table. */ + while (i < (sizeof (relocation_table)/sizeof (relocation_table[0])) + &&relocation_table[i].main_type != group_type) + i++; + + /* Can not find relocation pattern. */ + if (relocation_table[i].main_type == 0) + return; + + while (relocs_temp) + { + y = 0; + + while (relocation_table[i].reloc_insn[x][y][0] != 0) + { + reloc = relocation_table[i].reloc_insn[x][y][0]; + insn = relocation_table[i].reloc_insn[x][y][1]; + nds32_elf_insert_relocation (relocs_temp, reloc, insn, sym); + y++; + } + + /* Next instruction. */ + relocs_temp = relocs_temp->next; + + /* There are load store instruction shared setting symbol part, so + re-using the final relocation. */ + if (relocation_table[i].reloc_insn[x+1][0][0] != 0) + x++; + } + + now_seg = seg_bak; + frchain_now = frchain_bak; +} + +/* Check instruction if it can be used for the baseline. */ + +static bfd_boolean +nds32_check_insn_available (struct nds32_asm_insn insn, char *str) +{ + int attr = insn.attr & ATTR_ALL; + static int baseline_isa = 0; + /* No isa setting or all isa can use. */ + if (attr == 0 || attr == ATTR_ALL) + return TRUE; + + if (baseline_isa == 0) + { + /* Map option baseline and instruction attribute. */ + switch (nds32_baseline) + { + case ISA_V2: + baseline_isa = ATTR(ISA_V2); + break; + case ISA_V3: + baseline_isa = ATTR(ISA_V3); + break; + case ISA_V3M: + baseline_isa = ATTR(ISA_V3M); + break; + } + } + + if ((baseline_isa & attr) == 0) + { + as_bad (_("Not support instrcution %s in the baseline."), str); + return FALSE; + } + return TRUE; +} + +/* Stub of machine dependent. */ + +void +md_assemble (char *str) +{ + struct nds32_asm_insn insn; + char *out; + struct nds32_pseudo_opcode *popcode; + const struct nds32_field *fld = NULL; + fixS *fixP ATTRIBUTE_UNUSED; + int insn_type; + uint16_t insn_16; + uint32_t insn_32; + struct nds32_relocs_pattern *relocs_temp; + expressionS *pexp; + + popcode = nds32_lookup_pseudo_opcode (str); + /* Note that we need to check 'verbatim' and + 'opcode->physical_op'. If the assembly content is generated by + compiler and this opcode is a physical instruction, there is no + need to perform pseudo instruction expansion/transformation. */ + if (popcode && !(verbatim && popcode->physical_op)) + { + pseudo_opcode = TRUE; + nds32_pseudo_opcode_wrapper (str, popcode); + pseudo_opcode = FALSE; + nds32_elf_append_relax_relocs (NULL, relocs_list); + + /* Free pseudo list. */ + relocs_temp = relocs_list; + while (relocs_temp) + { + relocs_list = relocs_list->next; + free (relocs_temp); + relocs_temp = relocs_list; + } + + return; + } + + insn.info = (expressionS *) alloca (sizeof (expressionS)); + nds32_assemble (&asm_desc, &insn, str); + + switch (asm_desc.result) + { + case NASM_ERR_UNKNOWN_OP: + as_bad (_("Unrecognized opcode, %s."), str); + return; + case NASM_ERR_SYNTAX: + as_bad (_("Incorrect syntax, %s."), str); + return; + case NASM_ERR_OPERAND: + as_bad (_("Unrecognized operand, %s."), str); + return; + case NASM_ERR_OUT_OF_RANGE: + as_bad (_("Operand out of range, %s."), str); + return; + case NASM_ERR_REG_REDUCED: + as_bad (_("Prohibited register used for reduced-register, %s."), str); + return; + case NASM_ERR_JUNK_EOL: + as_bad (_("Junk at end of line, %s."), str); + return; + } + + gas_assert (insn.opcode); + + nds32_set_elf_flags_by_insn (&insn); + + gas_assert (insn.opcode->isize == 4 || insn.opcode->isize == 2); + + if (!nds32_check_insn_available (insn, str)) + return; + + /* Create new frag if the instruction can be relaxed. */ + fld = insn.field; + if (!verbatim && fld && (insn.attr & NASM_ATTR_BRANCH)) + { + /* User assembly code branch relax for it. */ + fragS *fragp = frag_now; + + /* If fld is not NULL, it is a symbol. */ + /* Get branch range type. */ + enum nds32_br_range range_type; + range_type = get_range_type (fld); + + pexp = insn.info; + + out = frag_var (rs_machine_dependent, + NDS32_MAXCHAR, + 0, /* VAR is un-used. */ + range_type, /* SUBTYPE is used as range type. */ + pexp->X_add_symbol, + pexp->X_add_number, + 0); + /* If the original frag is full, the instruction must save in next + one. */ + while (fragp->fr_next != frag_now) + fragp = fragp->fr_next; + fragp->fr_fix += insn.opcode->isize; + fragp->tc_frag_data.opcode = insn.opcode; + fragp->tc_frag_data.insn = insn.insn; + dwarf2_emit_insn (insn.opcode->isize); + if (insn.opcode->isize == 4) + bfd_putb32 (insn.insn, out); + else if (insn.opcode->isize == 2) + bfd_putb16 (insn.insn, out); + return; + /* md_convert_frag will insert relocations. */ + } + else if (!verbatim && !fld && (optimize || optimize_for_space)) + { + /* User assembly code without relocating convert it to 16bits if needed. */ + insn_32 = insn.insn; + + /* Convert instruction to 16-bits. */ + if (insn.opcode->isize == 4 + && nds32_convert_32_to_16 (stdoutput, insn_32, + &insn_16, &insn_type)) + { + out = frag_more (2); + frag_var (rs_fill, 0, 0, 0, NULL, 0, NULL); + bfd_putb16 (insn_16, out); + dwarf2_emit_insn (2); + return; + } + } + + out = frag_more (insn.opcode->isize); + + if (insn.opcode->isize == 4) + bfd_putb32 (insn.insn, out); + else if (insn.opcode->isize == 2) + bfd_putb16 (insn.insn, out); + + dwarf2_emit_insn (insn.opcode->isize); + + if (fld) + { + /* Compiler generating code and user assembly pseudo load-store, insert + fixup here. */ + pexp = insn.info; + nds32_elf_record_fixup_exp (str, fld, pexp, out, &insn); + } +} + +/* md_macro_start */ + +void +nds32_macro_start (void) +{ +} + +/* md_macro_info */ + +void +nds32_macro_info (void *info ATTRIBUTE_UNUSED) +{ +} + +/* md_macro_end */ + +void +nds32_macro_end (void) +{ +} + +/* GAS will call this function with one argument, an expressionS pointer, for + any expression that can not be recognized. When the function is called, + input_line_pointer will point to the start of the expression. */ + +void +md_operand (expressionS *expressionP) +{ + if (*input_line_pointer == '#') + { + input_line_pointer++; + expression (expressionP); + } +} + +/* GAS will call this function for each section at the end of the assembly, to + permit the CPU back end to adjust the alignment of a section. The function + must take two arguments, a segT for the section and a valueT for the size of + the section, and return a valueT for the rounded size. */ + +valueT +md_section_align (segT segment, valueT size) +{ + int align = bfd_get_section_alignment (stdoutput, segment); + + return ((size + (1 << align) - 1) & (-1 << align)); +} + +/* GAS will call this function when a symbol table lookup fails, before it + creates a new symbol. Typically this would be used to supply symbols whose + name or value changes dynamically, possibly in a context sensitive way. + Predefined symbols with fixed values, such as register names or condition + codes, are typically entered directly into the symbol table when md_begin + is called. One argument is passed, a char * for the symbol. */ + +symbolS * +md_undefined_symbol (char *name ATTRIBUTE_UNUSED) +{ + return NULL; +} + +static long +nds32_calc_branch_offset (segT segment, fragS *fragP, + long stretch ATTRIBUTE_UNUSED, + relax_info_t *relax_info, + enum nds32_br_range branch_range_type) +{ + struct nds32_opcode *opcode = fragP->tc_frag_data.opcode; + symbolS *branch_symbol = fragP->fr_symbol; + offsetT branch_offset = fragP->fr_offset; + offsetT branch_target_address; + offsetT branch_insn_address; + long offset = 0; + + if ((S_GET_SEGMENT (branch_symbol) != segment) + || S_IS_WEAK (branch_symbol)) + { + /* The symbol is not in the SEGMENT. It could be far far away. */ + offset = 0x80000000; + } + else + { + /* Calculate symbol-to-instruction offset. */ + branch_target_address = S_GET_VALUE (branch_symbol) + branch_offset; + /* If the destination symbol is beyond current frag address, + STRETCH will take effect to symbol's position. */ + if (S_GET_VALUE (branch_symbol) > fragP->fr_address) + branch_target_address += stretch; + + branch_insn_address = fragP->fr_address + fragP->fr_fix; + branch_insn_address -= opcode->isize; + + /* Update BRANCH_INSN_ADDRESS to relaxed position. */ + branch_insn_address += (relax_info->relax_code_size[branch_range_type] + - relax_info->relax_branch_isize[branch_range_type]); + + offset = branch_target_address - branch_insn_address; + } + + return offset; +} + +static enum nds32_br_range +nds32_convert_to_range_type (long offset) +{ + enum nds32_br_range range_type; + + if (-(0x100) <= offset && offset < 0x100) /* 256 bytes */ + range_type = BR_RANGE_S256; + else if (-(0x4000) <= offset && offset < 0x4000) /* 16K bytes */ + range_type = BR_RANGE_S16K; + else if (-(0x10000) <= offset && offset < 0x10000) /* 64K bytes */ + range_type = BR_RANGE_S64K; + else if (-(0x1000000) <= offset && offset < 0x1000000) /* 16M bytes */ + range_type = BR_RANGE_S16M; + else /* 4G bytes */ + range_type = BR_RANGE_U4G; + + return range_type; +} + +/* Set insntruction register mask. */ + +static void +nds32_elf_get_set_cond (relax_info_t *relax_info, int offset, uint32_t *insn, + uint32_t ori_insn, int range) +{ + nds32_cond_field_t *cond_fields = relax_info->cond_field; + nds32_cond_field_t *code_seq_cond = relax_info->relax_code_condition[range]; + uint32_t mask; + int i = 0; + + /* The instruction has conditions. Collect condition values. */ + while (offset == code_seq_cond[i].offset) + { + mask = (ori_insn >> cond_fields[i].bitpos) & cond_fields[i].bitmask; + *insn |= (mask & code_seq_cond[i].bitmask) << code_seq_cond[i].bitpos; + i++; + } +} + + +static int +nds32_relax_branch_instructions (segT segment, fragS *fragP, + long stretch ATTRIBUTE_UNUSED, + int init) +{ + enum nds32_br_range branch_range_type; + struct nds32_opcode *opcode = fragP->tc_frag_data.opcode; + long offset = 0; + enum nds32_br_range real_range_type; + int adjust = 0; + relax_info_t *relax_info; + int diff = 0; + int i, j, k; + int code_seq_size; + uint32_t *code_seq; + uint32_t insn; + int insn_size; + uint16_t insn_16; + int insn_type; + int code_seq_offset; + + /* Replace with gas_assert (fragP->fr_symbol != NULL); */ + if (fragP->fr_symbol == NULL) + return adjust; + + /* If frag_var is not enough room, the previos frag is fr_full and with + opcode. The new one is rs_dependent but without opcode. */ + if (opcode == NULL) + return adjust; + + relax_info = hash_find (nds32_relax_info_hash, opcode->opcode); + + if (relax_info == NULL) + return adjust; + + if (init) + branch_range_type = relax_info->br_range; + else + branch_range_type = fragP->fr_subtype; + + offset = nds32_calc_branch_offset (segment, fragP, stretch, + relax_info, branch_range_type); + + real_range_type = nds32_convert_to_range_type (offset); + + /* If actual range is equal to instruction jump range, do nothing. */ + if (real_range_type == branch_range_type) + return adjust; + + /* Find out proper relaxation code sequence. */ + for (i = BR_RANGE_S256; i < BR_RANGE_NUM; i++) + { + if (real_range_type <= (unsigned int) i) + { + if (init) + diff = relax_info->relax_code_size[i] - opcode->isize; + else + diff = relax_info->relax_code_size[i] + - relax_info->relax_code_size[branch_range_type]; + + /* If the instruction could be converted to 16-bits, + minus the difference. */ + code_seq_offset = 0; + j = 0; + k = 0; + code_seq_size = relax_info->relax_code_size[i]; + code_seq = relax_info->relax_code_seq[i]; + while (code_seq_offset < code_seq_size) + { + insn = code_seq[j]; + if (insn & 0x80000000) /* 16-bits instruction. */ + { + insn_size = 2; + } + else /* 32-bits instruction. */ + { + insn_size = 4; + + while (relax_info->relax_fixup[i][k].size !=0 + && relax_info->relax_fixup[i][k].offset < code_seq_offset) + k++; + if (relax_info->relax_fixup[i][k].size !=0 + && relax_info->relax_fixup[i][k].ramp & NDS32_ORIGIN) + { + /* Set register num to insntruction. */ + nds32_elf_get_set_cond (relax_info, code_seq_offset, &insn, + fragP->tc_frag_data.insn, i); + + /* Try to convert to 16-bits instruction. */ + if (nds32_convert_32_to_16 (stdoutput, + insn, &insn_16, &insn_type)) + diff -= 2; + } + } + + code_seq_offset += insn_size; + j++; + } + + /* Update fr_subtype to new NDS32_BR_RANGE. */ + fragP->fr_subtype = i; + break; + } + } + + return diff + adjust; +} + +/* md_relax_frag */ + +int +nds32_relax_frag (segT segment, fragS *fragP, long stretch ATTRIBUTE_UNUSED) +{ + /* Currently, there are two kinds of relaxation in nds32 assembler. + 1. relax for branch + 2. relax for 32-bits to 16-bits */ + + int adjust; + + adjust = nds32_relax_branch_instructions (segment, fragP, stretch, 0); + + return adjust; +} + +/* This function returns an initial guess of the length by which a fragment + must grow to hold a branch to reach its destination. Also updates + fr_type/fr_subtype as necessary. + + It is called just before doing relaxation. Any symbol that is now undefined + will not become defined. The guess for fr_var is ACTUALLY the growth beyond + fr_fix. Whatever we do to grow fr_fix or fr_var contributes to our returned + value. Although it may not be explicit in the frag, pretend fr_var starts + with a 0 value. */ + +int +md_estimate_size_before_relax (fragS *fragP, segT segment) +{ + /* Currently, there are two kinds of relaxation in nds32 assembler. + 1. relax for branch + 2. relax for 32-bits to 16-bits */ + + int adjust; + + adjust = nds32_relax_branch_instructions (segment, fragP, 0, 1); + + return adjust; +} + +/* GAS will call this for each rs_machine_dependent fragment. The instruction + is completed using the data from the relaxation pass. It may also create any + necessary relocations. + + *FRAGP has been relaxed to its final size, and now needs to have the bytes + inside it modified to conform to the new size. It is called after relaxation + is finished. + + fragP->fr_type == rs_machine_dependent. + fragP->fr_subtype is the subtype of what the address relaxed to. */ + +void +md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec, fragS *fragP) +{ + /* Convert branch relaxation instructions. */ + symbolS *branch_symbol = fragP->fr_symbol; + offsetT branch_offset = fragP->fr_offset; + enum nds32_br_range branch_range_type = fragP->fr_subtype; + struct nds32_opcode *opcode = fragP->tc_frag_data.opcode; + uint32_t origin_insn = fragP->tc_frag_data.insn; + int backup_endian; + relax_info_t *relax_info; + char *fr_buffer; + int fr_where; + int addend ATTRIBUTE_UNUSED; + offsetT branch_target_address; + offsetT branch_insn_address; + expressionS exp; + fixS *fixP; + uint32_t *code_seq; + int code_size; + uint32_t insn; + int insn_size; + int offset; + int i, j, k; + uint16_t insn_16; + int insn_type; + int buf_offset; + nds32_relax_fixup_info_t fixup_info[MAX_RELAX_NUM]; + /* Save the 1st instruction is converted to 16 bit or not. */ + bfd_boolean insn_convert = FALSE; + int fixup_size; + + /* Replace with gas_assert (branch_symbol != NULL); */ + if (branch_symbol == NULL) + return; + + /* If frag_var is not enough room, the previos frag is fr_full and with + opcode. The new one is rs_dependent but without opcode. */ + if (opcode == NULL) + return; + + relax_info = hash_find (nds32_relax_info_hash, opcode->opcode); + + if (relax_info == NULL) + return; + + backup_endian = target_big_endian; + target_big_endian = 1; + + fr_where = fragP->fr_fix - opcode->isize; + fr_buffer = fragP->fr_literal + fr_where; + + if ((S_GET_SEGMENT (branch_symbol) != sec) + || S_IS_WEAK (branch_symbol)) + { + if (fragP->fr_offset & 3) + as_warn (_("Addend to unresolved symbol is not on word boundary.")); + addend = 0; + } + else + { + /* Calculate symbol-to-instruction offset. */ + branch_target_address = S_GET_VALUE (branch_symbol) + branch_offset; + branch_insn_address = fragP->fr_address + fr_where; + addend = (branch_target_address - branch_insn_address) >> 1; + } + + code_size = relax_info->relax_code_size[branch_range_type]; + code_seq = relax_info->relax_code_seq[branch_range_type]; + + memcpy (fixup_info, + relax_info->relax_fixup[branch_range_type], + sizeof(fixup_info)); + + /* Fill in frag. */ + i = 0; + k = 0; + offset = 0; /* code_seq offset */ + buf_offset = 0; /* fr_buffer offset */ + while (offset < code_size) + { + insn = code_seq[i]; + if (insn & 0x80000000) /* 16-bits instruction. */ + { + insn = (insn >> 16) & 0xFFFF; + insn_size = 2; + } + else /* 32-bits instruction. */ + { + insn_size = 4; + } + + nds32_elf_get_set_cond (relax_info, offset, &insn, + origin_insn, branch_range_type); + + /* Try to convert to 16-bits instruction. Currently, only the first + insntruction in pattern can be converted. EX: bnez sethi ori jr, + only bnez can be converted to 16 bit and ori can't. */ + + while (fixup_info[k].size != 0 + && relax_info->relax_fixup[branch_range_type][k].offset < offset) + k++; + if ((fixup_info[k].size != 0 + && fixup_info[k].ramp & NDS32_ORIGIN) + && nds32_convert_32_to_16 (stdoutput, insn, &insn_16, &insn_type)) + { + /* Reduce to 16-bits instructions, adjust fixup_info[j]->offset. */ + for (j = 0; fixup_info[j].size != 0; j++) + { + if (fixup_info[j].ramp & NDS32_RELAX) + fixup_info[j].size -= 2; + + if (fixup_info[j].offset > buf_offset) + fixup_info[j].offset -= 2; + } + + md_number_to_chars (fr_buffer + buf_offset, insn_16, 2); + buf_offset += 2; + if (offset == 0) + insn_convert = TRUE; + } + else + { + md_number_to_chars (fr_buffer + buf_offset, insn, insn_size); + buf_offset += insn_size; + } + + offset += insn_size; + i++; + } + + /* Set up fixup. */ + exp.X_op = O_symbol; + + for (i = 0; fixup_info[i].size != 0; i++) + { + fixup_size = fixup_info[i].size; + + if (((fixup_info[i].ramp & NDS32_ORIGIN) && insn_convert == TRUE) + ||((fixup_info[i].ramp & NDS32_CONVERT) && insn_convert == FALSE)) + continue; + + if ((fixup_info[i].ramp & NDS32_CREATE_LABLE) != 0) + { + /* This is a reverse branch. */ + exp.X_add_symbol = symbol_temp_new (sec, 0, fragP->fr_next); + exp.X_add_number = 0; + } + else if ((fixup_info[i].ramp & NDS32_RELAX) != 0) + { + /* This is a relax relocation. */ + exp.X_add_symbol = abs_section_sym; + exp.X_add_number = + SET_ADDEND (fixup_size /* size */ , + insn_convert , optimize, enable_16bit); + } + else + { + exp.X_add_symbol = branch_symbol; + exp.X_add_number = branch_offset; + } + + if (fixup_info[i].r_type != 0) + { + fixP = fix_new_exp (fragP, + fr_where + fixup_info[i].offset, + fixup_size, + &exp, + 0, + fixup_info[i].r_type); + fixP->fx_addnumber = fixP->fx_offset; + } + } + + fragP->fr_fix = fr_where + buf_offset; + + target_big_endian = backup_endian; +} + +/* tc_frob_file_before_fix */ + +void +nds32_frob_file_before_fix (void) +{ +} + +/* TC_FORCE_RELOCATION */ + +int +nds32_force_relocation (fixS *fix ATTRIBUTE_UNUSED) +{ + /* Always force relocation, because linker may adjust the code. */ + return 1; +} + + +/* TC_VALIDATE_FIX_SUB */ + +int +nds32_validate_fix_sub (fixS *fix, segT add_symbol_segment) +{ + segT sub_symbol_segment; + + /* This code is referred from Xtensa. Check their implementation for + details. */ + + /* Make sure both symbols are in the same segment, and that segment is + "normal" and relaxable. */ + sub_symbol_segment = S_GET_SEGMENT (fix->fx_subsy); + return (sub_symbol_segment == add_symbol_segment + && add_symbol_segment != undefined_section); +} + +void +md_number_to_chars (char *buf, valueT val, int n) +{ + if (target_big_endian) + number_to_chars_bigendian (buf, val, n); + else + number_to_chars_littleendian (buf, val, n); +} + +/* Equal to MAX_PRECISION in atof-ieee.c. */ +#define MAX_LITTLENUMS 6 + +/* This function is called to convert an ASCII string into a floating point + value in format used by the CPU. */ + +char * +md_atof (int type, char *litP, int *sizeP) +{ + int i; + int prec; + LITTLENUM_TYPE words[MAX_LITTLENUMS]; + char *t; + + switch (type) + { + case 'f': + case 'F': + case 's': + case 'S': + prec = 2; + break; + case 'd': + case 'D': + case 'r': + case 'R': + prec = 4; + break; + default: + *sizeP = 0; + return _("Bad call to md_atof()"); + } + + t = atof_ieee (input_line_pointer, type, words); + if (t) + input_line_pointer = t; + *sizeP = prec * sizeof (LITTLENUM_TYPE); + + if (target_big_endian) + { + for (i = 0; i < prec; i++) + { + md_number_to_chars (litP, (valueT) words[i], + sizeof (LITTLENUM_TYPE)); + litP += sizeof (LITTLENUM_TYPE); + } + } + else + { + for (i = prec - 1; i >= 0; i--) + { + md_number_to_chars (litP, (valueT) words[i], + sizeof (LITTLENUM_TYPE)); + litP += sizeof (LITTLENUM_TYPE); + } + } + + return 0; +} + +/* md_elf_section_change_hook */ + +void +nds32_elf_section_change_hook (void) +{ +} + +/* md_cleanup */ + +void +nds32_cleanup (void) +{ +} + +/* This function is used to scan leb128 subtraction expressions, + and insert fixups for them. + + e.g., .leb128 .L1 - .L0 + + These expressions are heavily used in debug information or + exception tables. Because relaxation will change code size, + we must resolve them in link time. */ + +static void +nds32_insert_leb128_fixes (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec, void *xxx ATTRIBUTE_UNUSED) +{ + segment_info_type *seginfo = seg_info (sec); + struct frag *fragP; + + subseg_set (sec, 0); + + for (fragP = seginfo->frchainP->frch_root; + fragP; fragP = fragP->fr_next) + { + expressionS *exp; + + /* Only unsigned leb128 can be handle. */ + if (fragP->fr_type != rs_leb128 || fragP->fr_subtype != 0 + || fragP->fr_symbol == NULL) + continue; + + exp = symbol_get_value_expression (fragP->fr_symbol); + + if (exp->X_op != O_subtract) + continue; + + fix_new_exp (fragP, fragP->fr_fix, 0, + exp, 0, BFD_RELOC_NDS32_DIFF_ULEB128); + } +} + +static void +nds32_insert_relax_entry (bfd *abfd ATTRIBUTE_UNUSED, asection *sec, + void *xxx ATTRIBUTE_UNUSED) +{ + segment_info_type *seginfo; + fragS *fragP; + fixS *fixP; + expressionS exp; + fixS *fixp; + + seginfo = seg_info (sec); + if (!seginfo || !symbol_rootP || !subseg_text_p (sec)) + return; + /* If there is no relocation and relax is disabled, it is not necessary to + insert R_NDS32_RELAX_ENTRY for linker do EX9 or IFC optimization. */ + for (fixp = seginfo->fix_root; fixp; fixp = fixp->fx_next) + if (!fixp->fx_done) + break; + if (!fixp && !enable_relax_ex9 && !verbatim) + return; + + subseg_change (sec, 0); + + /* Set RELAX_ENTRY flags for linker. */ + fragP = seginfo->frchainP->frch_root; + exp.X_op = O_symbol; + exp.X_add_symbol = section_symbol (sec); + exp.X_add_number = 0; + if (!enable_relax_relocs) + exp.X_add_number |= R_NDS32_RELAX_ENTRY_DISABLE_RELAX_FLAG; + else + { + /* These flags are only enabled when global relax is enabled. + Maybe we can check DISABLE_RELAX_FLAG at linke-time, + so we set them anyway. */ + if (enable_relax_ex9) + exp.X_add_number |= R_NDS32_RELAX_ENTRY_EX9_FLAG; + if (enable_relax_ifc) + exp.X_add_number |= R_NDS32_RELAX_ENTRY_IFC_FLAG; + if (verbatim) + exp.X_add_number |= R_NDS32_RELAX_ENTRY_VERBATIM_FLAG; + } + if (optimize) + exp.X_add_number |= R_NDS32_RELAX_ENTRY_OPTIMIZE_FLAG; + if (optimize_for_space) + exp.X_add_number |= R_NDS32_RELAX_ENTRY_OPTIMIZE_FOR_SPACE_FLAG; + + fixP = fix_new_exp (fragP, 0, 0, &exp, 0, BFD_RELOC_NDS32_RELAX_ENTRY); + fixP->fx_no_overflow = 1; +} + +/* Analysis relax hint and insert suitable relocation pattern. */ + +static void +nds32_elf_analysis_relax_hint (void) +{ + hash_traverse (nds32_hint_hash, nds32_elf_append_relax_relocs); +} + +void +md_end (void) +{ + nds32_elf_analysis_relax_hint (); + bfd_map_over_sections (stdoutput, nds32_insert_leb128_fixes, NULL); +} + +/* Implement md_allow_local_subtract. */ + +bfd_boolean +nds32_allow_local_subtract (expressionS *expr_l ATTRIBUTE_UNUSED, + expressionS *expr_r ATTRIBUTE_UNUSED, + segT sec ATTRIBUTE_UNUSED) +{ + /* Don't allow any subtraction, because relax may change the code. */ + return FALSE; +} + +/* Sort relocation by address. + + We didn't use qsort () in stdlib, because quick-sort is not a stable + sorting algorithm. Relocations at the same address (r_offset) must keep + their relative order. For example, RELAX_ENTRY must be the very first + relocation entry. + + Currently, this function implements insertion-sort. */ + +static int +compar_relent (const void *lhs, const void *rhs) +{ + const arelent **l = (const arelent **) lhs; + const arelent **r = (const arelent **) rhs; + + if ((*l)->address > (*r)->address) + return 1; + else if ((*l)->address == (*r)->address) + return 0; + else + return -1; +} + +/* SET_SECTION_RELOCS () + + Although this macro is originally used to set a relocation for each section, + we use it to sort relocations in the same section by the address of the + relocation. */ + +void +nds32_set_section_relocs (asection *sec, arelent ** relocs ATTRIBUTE_UNUSED, + unsigned int n ATTRIBUTE_UNUSED) +{ + bfd *abfd ATTRIBUTE_UNUSED = sec->owner; + if (bfd_get_section_flags (abfd, sec) & (flagword) SEC_RELOC) + nds32_insertion_sort (sec->orelocation, sec->reloc_count, sizeof (arelent**), + compar_relent); +} + +long +nds32_pcrel_from_section (fixS *fixP, segT sec ATTRIBUTE_UNUSED) +{ + if (fixP->fx_addsy == NULL || !S_IS_DEFINED (fixP->fx_addsy) + || S_IS_EXTERNAL (fixP->fx_addsy) || S_IS_WEAK (fixP->fx_addsy)) + { + /* Let linker resolve undefined symbols. */ + return 0; + } + + return fixP->fx_frag->fr_address + fixP->fx_where; +} + +/* md_post_relax_hook () + Insert relax entry relocation into sections. */ + +void +nds32_post_relax_hook (void) +{ + bfd_map_over_sections (stdoutput, nds32_insert_relax_entry, NULL); +} + + + +/* tc_fix_adjustable () + + Return whether this symbol (fixup) can be replaced with + section symbols. */ + +bfd_boolean +nds32_fix_adjustable (fixS *fixP) +{ + switch (fixP->fx_r_type) + { + case BFD_RELOC_NDS32_WORD_9_PCREL: + case BFD_RELOC_NDS32_9_PCREL: + case BFD_RELOC_NDS32_15_PCREL: + case BFD_RELOC_NDS32_17_PCREL: + case BFD_RELOC_NDS32_25_PCREL: + case BFD_RELOC_NDS32_HI20: + case BFD_RELOC_NDS32_LO12S0: + case BFD_RELOC_8: + case BFD_RELOC_16: + case BFD_RELOC_32: + case BFD_RELOC_NDS32_PTR: + return 1; + default: + return 0; + } +} + +/* elf_tc_final_processing */ + +void +elf_nds32_final_processing (void) +{ + /* An FPU_COM instruction is found without previous non-FPU_COM instruction. */ + if (nds32_fpu_com + && !(nds32_elf_flags & (E_NDS32_HAS_FPU_INST | E_NDS32_HAS_FPU_DP_INST))) + { + /* Since only FPU_COM instructions are used and no other FPU instructions + are used. The nds32_elf_flags will be decided by the enabled options by + command line or default configuration. */ + if (nds32_fpu_dp_ext || nds32_fpu_sp_ext) + { + nds32_elf_flags |= nds32_fpu_dp_ext ? E_NDS32_HAS_FPU_DP_INST : 0; + nds32_elf_flags |= nds32_fpu_sp_ext ? E_NDS32_HAS_FPU_INST : 0; + } + else + { + /* Should never here. */ + as_bad (_("Used FPU instructions requires enabling FPU extension")); + } + } + + if (nds32_elf_flags & (E_NDS32_HAS_FPU_INST | E_NDS32_HAS_FPU_DP_INST)) + { + /* Single/double FPU has been used, set FPU register config. */ + /* We did not check the actual number of register used. We may + want to do it while assemble. */ + nds32_elf_flags &= ~E_NDS32_FPU_REG_CONF; + nds32_elf_flags |= (nds32_freg << E_NDS32_FPU_REG_CONF_SHIFT); + } + + if (nds32_pic) + nds32_elf_flags |= E_NDS32_HAS_PIC; + + if (nds32_gpr16) + nds32_elf_flags |= E_NDS32_HAS_REDUCED_REGS; + + nds32_elf_flags |= (E_NDS32_ELF_VER_1_4 | nds32_abi); + elf_elfheader (stdoutput)->e_flags |= nds32_elf_flags; +} + +/* Implement md_apply_fix. Apply the fix-up or tranform the fix-up for + later relocation generation. */ + +void +nds32_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) +{ + char *where = fixP->fx_frag->fr_literal + fixP->fx_where; + bfd_vma value = *valP; + + if (fixP->fx_r_type < BFD_RELOC_UNUSED + && fixP->fx_r_type > BFD_RELOC_NONE + && fixP->fx_r_type != BFD_RELOC_NDS32_DIFF_ULEB128) + { + /* FIXME: This implementation is partially borrowed from our old + nds32 binutils. Its purpose is to leave original bfd + relocation untouched, while other relocation created by CGEN + will be converted into general bfd relocations. + However, since we no longer use CGEN, we can simply use + a little piece of code to deal with general bfd relocation, + especially for the BFD_RELOC_NDS32_DATA, which is just used + as a marker for different purpose. + It is believed that we can construct a better mechanism to + deal with the whole relocation issue in nds32 target + without using CGEN. */ + fixP->fx_addnumber = value; + fixP->tc_fix_data = NULL; + if (fixP->fx_r_type == BFD_RELOC_NDS32_DATA) + fixP->fx_done = 1; + return; + } + + if (fixP->fx_addsy == (symbolS *) NULL) + fixP->fx_done = 1; + + if (fixP->fx_subsy != (symbolS *) NULL) + { + /* HOW DIFF RELOCATION WORKS. + + First of all, this relocation is used to calculate the distance + between two symbols in the SAME section. It is used for jump- + table, debug information, exception table, et al. Therefore, + it is a unsigned positive value. It is NOT used for general- + purpose arithmetic. + + Consider this example, the distance between .LEND and .LBEGIN + is stored at the address of foo. + + ---- >8 ---- >8 ---- >8 ---- >8 ---- + .data + foo: + .word .LBEGIN - .LEND + + .text + [before] + .LBEGIN + \ + [between] distance + / + .LEND + [after] + ---- 8< ---- 8< ---- 8< ---- 8< ---- + + We use a single relocation entry for this expression. + * The initial distance value is stored direcly in that location + specified by r_offset (i.e., foo in this example.) + * The begin of the region, i.e., .LBEGIN, is specified by + r_info/R_SYM and r_addend, e.g., .text + 0x32. + * The end of region, i.e., .LEND, is represented by + .LBEGIN + distance instead of .LEND, so we only need + a single relocation entry instead of two. + + When an instruction is relaxed, we adjust the relocation entry + depending on where the instruction locates. There are three + cases, before, after and between the region. + * between: Distance value is read from r_offset, adjusted and + written back into r_offset. + * before: Only r_addend is adjust. + * after: We don't care about it. + + Hereby, there are some limitation. + + `(.LEND - 1) - .LBEGIN' and `(.LEND - .LBEGIN) - 1' + are semantically different, and we cannot handle latter case + when relaxation. + + The latter expression means subtracting 1 from the distance + between .LEND and .LBEGIN. And the former expression means + the distance between (.LEND - 1) and .LBEGIN. + + The nuance affects whether to adjust distance value when relax + an instruction. In another words, whether the instruction + locates in the region. Because we use a single relocation entry, + there is no field left for .LEND and the subtrahend. + + Since GCC-4.5, GCC may produce debug information in such expression + .long .L1-1-.L0 + in order to describe register clobbering during an function-call. + .L0: + call foo + .L1: + + Check http://gcc.gnu.org/ml/gcc-patches/2009-06/msg01317.html + for details. */ + + value -= S_GET_VALUE (fixP->fx_subsy); + *valP = value; + fixP->fx_subsy = NULL; + fixP->fx_offset -= value; + + switch (fixP->fx_r_type) + { + case BFD_RELOC_8: + fixP->fx_r_type = BFD_RELOC_NDS32_DIFF8; + md_number_to_chars (where, value, 1); + break; + case BFD_RELOC_16: + fixP->fx_r_type = BFD_RELOC_NDS32_DIFF16; + md_number_to_chars (where, value, 2); + break; + case BFD_RELOC_32: + fixP->fx_r_type = BFD_RELOC_NDS32_DIFF32; + md_number_to_chars (where, value, 4); + break; + case BFD_RELOC_NDS32_DIFF_ULEB128: + /* cvt_frag_to_fill () has called output_leb128 () for us. */ + break; + default: + as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex")); + return; + } + } + else if (fixP->fx_done) + { + /* We're finished with this fixup. Install it because + bfd_install_relocation won't be called to do it. */ + switch (fixP->fx_r_type) + { + case BFD_RELOC_8: + md_number_to_chars (where, value, 1); + break; + case BFD_RELOC_16: + md_number_to_chars (where, value, 2); + break; + case BFD_RELOC_32: + md_number_to_chars (where, value, 4); + break; + case BFD_RELOC_64: + md_number_to_chars (where, value, 8); + default: + as_bad_where (fixP->fx_file, fixP->fx_line, + _("Internal error: Unknown fixup type %d (`%s')"), + fixP->fx_r_type, bfd_get_reloc_code_name (fixP->fx_r_type)); + break; + } + } +} + +/* Implement tc_gen_reloc. Generate ELF relocation for a fix-up. */ + +arelent * +tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixP) +{ + arelent *reloc; + bfd_reloc_code_real_type code; + + reloc = (arelent *) xmalloc (sizeof (arelent)); + + reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy); + reloc->address = fixP->fx_frag->fr_address + fixP->fx_where; + + code = fixP->fx_r_type; + + reloc->howto = bfd_reloc_type_lookup (stdoutput, code); + if (reloc->howto == (reloc_howto_type *) NULL) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("internal error: can't export reloc type %d (`%s')"), + fixP->fx_r_type, bfd_get_reloc_code_name (code)); + return NULL; + } + + /* Add relocation handling here. */ + + switch (fixP->fx_r_type) + { + default: + /* In general, addend of a relocation is the offset to the + associated symbol. */ + reloc->addend = fixP->fx_offset; + break; + + case BFD_RELOC_NDS32_DATA: + /* Prevent linker from optimizing data in text sections. + For example, jump table. */ + reloc->addend = fixP->fx_size; + break; + } + + return reloc; +} + +/* Implement md_parse_name. */ + +int +nds32_parse_name (char const *name, expressionS *exprP, + enum expr_mode mode ATTRIBUTE_UNUSED, + char *nextcharP ATTRIBUTE_UNUSED) +{ + char *suffix_table[] = { "GOTOFF", "GOT", "PLT" }; + short unsigned int reloc_table [] = + { + BFD_RELOC_NDS32_GOTOFF, BFD_RELOC_NDS32_GOT20, + BFD_RELOC_NDS32_25_PLTREL + }; + segT segment; + + exprP->X_op_symbol = NULL; + exprP->X_md = BFD_RELOC_UNUSED; + + exprP->X_add_symbol = symbol_find_or_make (name); + + segment = S_GET_SEGMENT (exprP->X_add_symbol); + if (segment != undefined_section) + return 0; + + if (*nextcharP == '@') + { + size_t i; + char *next; + for (i = 0; i < ARRAY_SIZE(suffix_table); i++) + { + next = input_line_pointer + 1 + strlen(suffix_table[i]); + if (strncasecmp (input_line_pointer + 1, suffix_table[i], + strlen (suffix_table[i])) == 0 + && !is_part_of_name (*next)) + { + exprP->X_md = reloc_table[i]; + *input_line_pointer = *nextcharP; + input_line_pointer = next; + *nextcharP = *input_line_pointer; + *input_line_pointer = '\0'; + break; + } + } + } + + exprP->X_op = O_symbol; + exprP->X_add_number = 0; + + return 1; +} + +/* Implement tc_regname_to_dw2regnum. */ + +int +tc_nds32_regname_to_dw2regnum (char *regname) +{ + symbolS *sym = symbol_find (regname); + + if (S_GET_SEGMENT (sym) == reg_section + && sym->sy_value.X_add_number < 32) + return sym->sy_value.X_add_number; + return -1; +} + +void +tc_nds32_frame_initial_instructions (void) +{ + /* CIE */ + /* Default cfa is register-28/sp. */ + cfi_add_CFA_def_cfa (31, 0); +} diff --git a/gas/config/tc-nds32.h b/gas/config/tc-nds32.h new file mode 100644 index 0000000..f3add64 --- /dev/null +++ b/gas/config/tc-nds32.h @@ -0,0 +1,273 @@ +/* tc-nds32.h -- Header file for tc-nds32.c. + Copyright (C) 2012-2013 Free Software Foundation, Inc. + Contributed by Andes Technology Corporation. + + This file is part of GAS. + + GAS 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, or (at your option) + any later version. + + GAS 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 GAS; see the file COPYING. If not, write to the Free + Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#ifndef TC_NDS32 +#define TC_NDS32 + +#include "bfd_stdint.h" + +#define LISTING_HEADER \ + (target_big_endian ? "NDS32 GAS" : "NDS32 GAS Little Endian") + +/* The target BFD architecture. */ +#define TARGET_ARCH bfd_arch_nds32 + +/* mapping to mach_table[5] */ +#define ISA_V1 bfd_mach_n1h +#define ISA_V2 bfd_mach_n1h_v2 +#define ISA_V3 bfd_mach_n1h_v3 +#define ISA_V3M bfd_mach_n1h_v3m + +/* Default to big endian. Please note that for Andes architecture, + instructions are always in big-endian format. */ +#ifndef TARGET_BYTES_BIG_ENDIAN +#define TARGET_BYTES_BIG_ENDIAN 1 +#endif + +/* This is used to construct expressions out of @GOTOFF, @PLT and @GOT + symbols. The relocation type is stored in X_md. */ +#define O_PIC_reloc O_md1 + +/* + * as.c + */ +/* extend GAS command line option handling capability */ +extern int nds32_parse_option (int, char *); +extern void nds32_after_parse_args (void); +/* The endianness of the target format may change based on command + line arguments. */ +extern const char *nds32_target_format (void); +#define md_parse_option(optc, optarg) nds32_parse_option (optc, optarg) +#define md_after_parse_args() nds32_after_parse_args () +#define TARGET_FORMAT nds32_target_format() + + +/* expr.c */ +extern int nds32_parse_name (char const *, expressionS *, enum expr_mode, char *); +extern bfd_boolean nds32_allow_local_subtract (expressionS *, expressionS *, segT); +#define md_parse_name(name, exprP, mode, nextcharP) \ + nds32_parse_name (name, exprP, mode, nextcharP) +#define md_allow_local_subtract(lhs,rhs,sect) nds32_allow_local_subtract (lhs, rhs, sect) + +/* + * dwarf2dbg.c + */ +#define DWARF2_USE_FIXED_ADVANCE_PC 1 + +/* + * write.c + */ +extern long nds32_pcrel_from_section (struct fix *, segT); +extern bfd_boolean nds32_fix_adjustable (struct fix *); +extern void nds32_frob_file (void); +extern void nds32_post_relax_hook (void); +extern void nds32_frob_file_before_fix (void); +extern void elf_nds32_final_processing (void); +extern int nds32_validate_fix_sub (struct fix *, segT); +extern int nds32_force_relocation (struct fix *); +extern void nds32_set_section_relocs(asection *, arelent ** , unsigned int ); + +/* Fill in rs_align_code fragments. TODO: Review this. */ +extern void nds32_handle_align (fragS *); +extern int nds32_relax_frag (segT, fragS *, long); +extern int tc_nds32_regname_to_dw2regnum (char *regname); +extern void tc_nds32_frame_initial_instructions (void); +#define MD_PCREL_FROM_SECTION(fix, sect) nds32_pcrel_from_section(fix, sect) +#define TC_FINALIZE_SYMS_BEFORE_SIZE_SEG 0 +#define tc_fix_adjustable(FIX) nds32_fix_adjustable (FIX) +#define md_apply_fix(fixP, addn, seg) nds32_apply_fix (fixP, addn, seg) +#define md_post_relax_hook nds32_post_relax_hook () +#define tc_frob_file_before_fix() nds32_frob_file_before_fix () +#define elf_tc_final_processing() elf_nds32_final_processing () +/* For DIFF relocations. The default behavior is inconsistent with the + asm internal document. */ +#define TC_FORCE_RELOCATION_SUB_SAME(FIX, SEC) \ + (! SEG_NORMAL (SEC) || TC_FORCE_RELOCATION (FIX)) +#define TC_FORCE_RELOCATION(fix) nds32_force_relocation (fix) +#define TC_VALIDATE_FIX_SUB(FIX,SEG) nds32_validate_fix_sub (FIX,SEG) +#define SET_SECTION_RELOCS(sec, relocs, n) nds32_set_section_relocs (sec, relocs, n) +/* Values passed to md_apply_fix don't include the symbol value. */ +#define MD_APPLY_SYM_VALUE(FIX) 0 +#define HANDLE_ALIGN(f) nds32_handle_align (f) +#undef DIFF_EXPR_OK /* They should be fixed in linker. */ +#define md_relax_frag(segment, fragP, stretch) nds32_relax_frag (segment, fragP, stretch) +#define WORKING_DOT_WORD /* We don't need to handle .word strangely. */ +/* Using to chain fixup with previous fixup. */ +#define TC_FIX_TYPE struct fix* +#define TC_INIT_FIX_DATA(fixP) do \ +{ \ + fixP->tc_fix_data=NULL; \ +} while (0) + +/* + * read.c + */ +/* extend GAS macro handling capability */ +extern void nds32_macro_start (void); +extern void nds32_macro_end (void); +extern void nds32_macro_info (void *macro); +extern void nds32_start_line_hook (void); +extern void nds32_elf_section_change_hook (void); +extern void md_begin (void); +extern void md_end (void); +extern int nds32_start_label (int, int); +extern void nds32_cleanup (void); +extern void nds32_flush_pending_output (void); +extern void nds32_cons_align (int n); +extern void nds32_check_label (symbolS *); +extern void nds32_frob_label (symbolS *); +void nds32_pre_do_align(int, char*, int, int); +void nds32_do_align(int); +#define md_macro_start() nds32_macro_start() +#define md_macro_end() nds32_macro_end() +#define md_macro_info(args) nds32_macro_info(args) +#define TC_START_LABEL(C, S, STR) (C == ':' && nds32_start_label (0, 0)) +#define tc_check_label(label) nds32_check_label (label) +#define tc_frob_label(label) nds32_frob_label (label) +#define md_end md_end +#define md_start_line_hook() nds32_start_line_hook() +#define md_cons_align(n) nds32_cons_align (n) +/* COLE: TODO: Review md_do_align. */ +#define md_do_align(N, FILL, LEN, MAX, LABEL) \ + nds32_pre_do_align(N, FILL, LEN, MAX); \ + if ((N) > 1 && (subseg_text_p (now_seg) \ + || strncmp(now_seg->name, ".gcc_except_table", sizeof(".gcc_except_table") - 1) == 0)) \ + nds32_do_align (N); \ + goto LABEL; +#define md_elf_section_change_hook() nds32_elf_section_change_hook() +#define md_flush_pending_output() nds32_flush_pending_output () +#define md_cleanup() nds32_cleanup () +#define LOCAL_LABELS_FB 1 /* Permit temporary numeric labels. */ + +/* + * frags.c + */ +struct nds32_frag_type { + relax_substateT flag; + struct nds32_opcode *opcode; + uint32_t insn; + /* To Save previos label fixup if existence. */ + struct fix *fixup; +}; + +extern void nds32_frag_init(fragS*); + +#define TC_FRAG_TYPE struct nds32_frag_type +#define TC_FRAG_INIT(fragP) nds32_frag_init(fragP) + +/* + * CFI directive + */ +extern void nds32_elf_frame_initial_instructions(void); +extern int tc_nds32_regname_to_dw2regnum (char *regname); + +#define TARGET_USE_CFIPOP 1 +#define DWARF2_DEFAULT_RETURN_COLUMN 30 +#define DWARF2_CIE_DATA_ALIGNMENT -4 +#define DWARF2_LINE_MIN_INSN_LENGTH 2 + +#define tc_regname_to_dw2regnum tc_nds32_regname_to_dw2regnum +#define tc_cfi_frame_initial_instructions tc_nds32_frame_initial_instructions + +/* + * COLE: TODO: Review These. They seem to be obsoleted. + */ +#if 1 +#define TC_RELOC_RTSYM_LOC_FIXUP(FIX) \ + ((FIX)->fx_addsy == NULL \ + || (! S_IS_EXTERNAL ((FIX)->fx_addsy) \ + && ! S_IS_WEAK ((FIX)->fx_addsy) \ + && S_IS_DEFINED ((FIX)->fx_addsy) \ + && ! S_IS_COMMON ((FIX)->fx_addsy))) +#define TC_HANDLES_FX_DONE +/* This arranges for gas/write.c to not apply a relocation if + obj_fix_adjustable() says it is not adjustable. */ +#define TC_FIX_ADJUSTABLE(fixP) obj_fix_adjustable (fixP) +#endif + +/* Because linker may relax the code, assemble-time expression + optimization is not allowed. */ +#define md_allow_eh_opt 0 + +/* For nds32 relax. */ +enum nds32_br_range +{ + BR_RANGE_S256 = 0, + BR_RANGE_S16K, + BR_RANGE_S64K, + BR_RANGE_S16M, + BR_RANGE_U4G, + BR_RANGE_NUM +}; + +enum nds32_ramp +{ + NDS32_CREATE_LABLE = 1, + NDS32_RELAX = 2, + NDS32_ORIGIN = 4, + NDS32_CONVERT = 8 +}; + +typedef struct nds32_relax_fixup_info +{ + int offset; + int size; + /* Reverse branch has to jump to the end of instruction pattern. */ + int ramp; + enum bfd_reloc_code_real r_type; +} nds32_relax_fixup_info_t; + +typedef struct nds32_cond_field +{ + int offset; + int bitpos; /* Register position. */ + int bitmask; /* Number of register bits. */ +} nds32_cond_field_t; + +/* The max relaxation pattern is 20-bytes including the nop. */ +#define NDS32_MAXCHAR 20 +/* In current, the max entend number of instruction for one pseudo instruction + is 4, but its number of relocation may be 5. */ +#define MAX_RELAX_NUM 8 + +typedef struct nds32_relax_info +{ + /* Opcode for the instruction. */ + const char *opcode; + enum nds32_br_range br_range; + nds32_cond_field_t cond_field[MAX_RELAX_NUM]; /* TODO: Reuse nds32_field? */ + /* Code sequences for different branch range. */ + uint32_t relax_code_seq[BR_RANGE_NUM][MAX_RELAX_NUM]; + nds32_cond_field_t relax_code_condition[BR_RANGE_NUM][MAX_RELAX_NUM]; + int relax_code_size[BR_RANGE_NUM]; + int relax_branch_isize[BR_RANGE_NUM]; + nds32_relax_fixup_info_t relax_fixup[BR_RANGE_NUM][MAX_RELAX_NUM]; +} relax_info_t; + +/* Relocation table. */ +struct nds32_relocation_map +{ + unsigned int main_type; + /* Number of instructions, {relocations type, instruction type}. */ + unsigned int reloc_insn[6][6][3]; +}; + +#endif /* TC_NDS32 */ diff --git a/gas/configure.in b/gas/configure.in index 121fcfc..9e1ba59 100644 --- a/gas/configure.in +++ b/gas/configure.in @@ -363,6 +363,75 @@ changequote([,])dnl using_cgen=yes ;; + nds32) + # Decide BASELINE, REDUCED_REGS, FPU_DP_EXT, FPU_SP_EXT features + # based on arch_name. + AC_MSG_CHECKING(for default configuration of --with-arch) + if test "x${with_arch}" != x; then + case ${with_arch} in + v2j | v2s | v2f | v2 | v3m | v3j | v3s | v3f | v3 ) + AC_DEFINE_UNQUOTED(NDS32_DEFAULT_ARCH_NAME, "$with_arch", + [Define value for nds32_arch_name]) + ;; + *) + AC_MSG_ERROR(This kind of arch name does *NOT* exist!) + ;; + esac + fi + AC_MSG_RESULT($with_arch) + + # Decide features one by one. + AC_MSG_CHECKING(for default configuration of --enable-dx-regs) + if test "x${enable_dx_regs}" == xyes; then + AC_DEFINE(NDS32_DEFAULT_DX_REGS, 1, + [Define value for nds32_dx_regs]) + else + AC_DEFINE(NDS32_DEFAULT_DX_REGS, 0, + [Define default value for nds32_dx_regs]) + fi + AC_MSG_RESULT($enable_dx_regs) + + AC_MSG_CHECKING(for default configuration of --enable-perf-ext) + if test "x${enable_perf_ext}" == xno; then + AC_DEFINE(NDS32_DEFAULT_PERF_EXT, 0, + [Define value for nds32_perf_ext]) + else + AC_DEFINE(NDS32_DEFAULT_PERF_EXT, 1, + [Define default value for nds32_perf_ext]) + fi + AC_MSG_RESULT($enable_perf_ext) + + AC_MSG_CHECKING(for default configuration of --enable-perf-ext2) + if test "x${enable_perf_ext2}" == xno; then + AC_DEFINE(NDS32_DEFAULT_PERF_EXT2, 0, + [Define value for nds32_perf_ext2]) + else + AC_DEFINE(NDS32_DEFAULT_PERF_EXT2, 1, + [Define default value for nds32_perf_ext2]) + fi + AC_MSG_RESULT($enable_perf_ext2) + + AC_MSG_CHECKING(for default configuration of --enable-string-ext) + if test "x${enable_string_ext}" == xno; then + AC_DEFINE(NDS32_DEFAULT_STRING_EXT, 0, + [Define value for nds32_string_ext]) + else + AC_DEFINE(NDS32_DEFAULT_STRING_EXT, 1, + [Define default value for nds32_string_ext]) + fi + AC_MSG_RESULT($enable_string_ext) + + AC_MSG_CHECKING(for default configuration of --enable-audio-ext) + if test "x${enable_audio_ext}" == xno; then + AC_DEFINE(NDS32_DEFAULT_AUDIO_EXT, 0, + [Define value for nds32_audio_ext]) + else + AC_DEFINE(NDS32_DEFAULT_AUDIO_EXT, 1, + [Define default value for nds32_audio_ext]) + fi + AC_MSG_RESULT($enable_audio_ext) + ;; + i386 | s390 | sparc) if test $this_target = $target ; then AC_DEFINE_UNQUOTED(DEFAULT_ARCH, "${arch}", [Default architecture.]) diff --git a/gas/configure.tgt b/gas/configure.tgt index 77c1d9b..fdc0612 100644 --- a/gas/configure.tgt +++ b/gas/configure.tgt @@ -79,6 +79,8 @@ case ${cpu} in mips*el) cpu_type=mips endian=little ;; mips*) cpu_type=mips endian=big ;; mt) cpu_type=mt endian=big ;; + nds32be) cpu_type=nds32 endian=big ;; + nds32le) cpu_type=nds32 endian=little ;; or32*) cpu_type=or32 endian=big ;; pjl*) cpu_type=pj endian=little ;; pj*) cpu_type=pj endian=big ;; @@ -344,6 +346,9 @@ case ${generic_target} in msp430-*-*) fmt=elf ;; + nds32-*-elf*) fmt=elf ;; + nds32-*-linux*) fmt=elf em=linux ;; + nios2-*-rtems*) fmt=elf ;; nios2*-linux*) fmt=elf em=linux ;; diff --git a/gas/doc/Makefile.am b/gas/doc/Makefile.am index 3d1e933..e5b3c5f 100644 --- a/gas/doc/Makefile.am +++ b/gas/doc/Makefile.am @@ -75,6 +75,7 @@ CPU_DOCS = \ c-mt.texi \ c-msp430.texi \ c-nios2.texi \ + c-nds32.texi \ c-ns32k.texi \ c-pdp11.texi \ c-pj.texi \ diff --git a/gas/doc/all.texi b/gas/doc/all.texi index 99dbf8f..348f902 100644 --- a/gas/doc/all.texi +++ b/gas/doc/all.texi @@ -59,6 +59,7 @@ @set MS1 @set MSP430 @set NIOSII +@set NDS32 @set NS32K @set PDP11 @set PJ diff --git a/gas/doc/as.texinfo b/gas/doc/as.texinfo index 9843574..6d37d70 100644 --- a/gas/doc/as.texinfo +++ b/gas/doc/as.texinfo @@ -436,6 +436,18 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}. [@b{-relax-all}] [@b{-relax-section}] [@b{-no-relax}] [@b{-EB}] [@b{-EL}] @end ifset +@ifset NDS32 + +@emph{Target NDS32 options:} + [@b{-EL}] [@b{-EB}] [@b{-O}] [@b{-Os}] [@b{-mcpu=@var{cpu}}] + [@b{-misa=@var{isa}}] [@b{-mabi=@var{abi}}] [@b{-mall-ext}] + [@b{-m[no-]16-bit}] [@b{-m[no-]perf-ext}] [@b{-m[no-]perf2-ext}] + [@b{-m[no-]string-ext}] [@b{-m[no-]dsp-ext}] [@b{-m[no-]mac}] [@b{-m[no-]div}] + [@b{-m[no-]audio-isa-ext}] [@b{-m[no-]fpu-sp-ext}] [@b{-m[no-]fpu-dp-ext}] + [@b{-m[no-]fpu-fma}] [@b{-mfpu-freg=@var{FREG}}] [@b{-mreduced-regs}] + [@b{-mfull-regs}] [@b{-m[no-]dx-regs}] [@b{-mpic}] [@b{-mno-relax}] + [@b{-mb2bb}] +@end ifset @ifset PDP11 @emph{Target PDP11 options:} @@ -1465,6 +1477,25 @@ Meta processor. See the info pages for documentation of the MMIX-specific options. @end ifset +@ifset NDS32 + +@ifclear man +@xref{NDS32 Options}, for the options available when @value{AS} is configured +for a NDS32 processor. +@end ifclear +@c ended inside the included file +@end ifset + +@ifset man +@c man begin OPTIONS +The following options are available when @value{AS} is configured for a +NDS32 processor. +@c man end +@c man begin INCLUDE +@include c-nds32.texi +@c ended inside the included file +@end ifset + @c man end @ifset PPC @@ -7121,6 +7152,9 @@ subject, see the hardware manufacturer's manual. @ifset MSP430 * MSP430-Dependent:: MSP430 Dependent Features @end ifset +@ifset NDS32 +* NDS32-Dependent:: Andes NDS32 Dependent Features +@end ifset @ifset NIOSII * NiosII-Dependent:: Altera Nios II Dependent Features @end ifset @@ -7335,6 +7369,10 @@ family. @include c-msp430.texi @end ifset +@ifset NDS32 +@include c-nds32.texi +@end ifset + @ifset NIOSII @include c-nios2.texi @end ifset diff --git a/gas/doc/c-nds32.texi b/gas/doc/c-nds32.texi new file mode 100644 index 0000000..f853abb --- /dev/null +++ b/gas/doc/c-nds32.texi @@ -0,0 +1,291 @@ +@c Copyright 1991, 1992, 1993, 1994, 1995, 1997, 1999, 2000, 2001, +@c 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2013 +@c Free Software Foundation, Inc. +@c This is part of the GAS manual. +@c For copying conditions, see the file as.texinfo. +@page +@node NDS32-Dependent +@chapter NDS32 Dependent Features + +@cindex NDS32 processor +The NDS32 processors family includes high-performance and low-power 32-bit +processors for high-end to low-end. @sc{gnu} @code{@value{AS}} for NDS32 +architectures supports NDS32 ISA version 3. For detail about NDS32 +instruction set, please see the AndeStar ISA User Manual which is availible +at http://www.andestech.com/en/index/index.htm + +@menu +* NDS32 Options:: Assembler options +* NDS32 Syntax:: High-level assembly macros +@end menu + +@node NDS32 Options +@section NDS32 Options + +@cindex NDS32 options +@cindex options for NDS32 +The NDS32 configurations of @sc{gnu} @code{@value{AS}} support these +special options: + +@table @code + +@item -O1 +Optimize for performance. + +@item -Os +Optimize for space. + +@item -EL +Produce little endian data output. + +@item -EB +Produce little endian data output. + +@item -mpic +Generate PIC. + +@item -mno-fp-as-gp-relax +Suppress fp-as-gp relaxation for this file. + +@item -mb2bb-relax +Back-to-back branch optimization. + +@item -mno-all-relax +Suppress all relaxation for this file. + +@item -march= +Assemble for architecture which could be v3, v3j, v3m, v3f, +v3s, v2, v2j, v2f, v2s. + +@item -mbaseline= +Assemble for baseline which could be v2, v3, v3m. + +@item -mfpu-freg=@var{FREG} +Specify a FPU configuration. +@table @code +@item 0 8 SP / 4 DP registers +@item 1 16 SP / 8 DP registers +@item 2 32 SP / 16 DP registers +@item 3 32 SP / 32 DP registers +@end table + +@item -mabi=@var{abi} +Specify a abi version could be v1, v2, v2fp, v2fpp. + +@item -m[no-]mac +Enable/Disable Multiply instructions support. + +@item -m[no-]div +Enable/Disable Divide instructions support. + +@item -m[no-]16bit-ext +Enable/Disable 16-bit extension + +@item -m[no-]dx-regs +Enable/Disable d0/d1 registers + +@item -m[no-]perf-ext +Enable/Disable Performance extension + +@item -m[no-]perf2-ext +Enable/Disable Performance extension 2 + +@item -m[no-]string-ext +Enable/Disable String extension + +@item -m[no-]reduced-regs +Enable/Disable Reduced Register configuration (GPR16) option + +@item -m[no-]audio-isa-ext +Enable/Disable AUDIO ISA extension + +@item -m[no-]fpu-sp-ext +Enable/Disable FPU SP extension + +@item -m[no-]fpu-dp-ext +Enable/Disable FPU DP extension + +@item -m[no-]fpu-fma +Enable/Disable FPU fused-multiply-add instructions + +@item -mall-ext +Turn on all extensions and instructions support +@end table + +@node NDS32 Syntax +@section Syntax + +@menu +* NDS32-Chars:: Special Characters +* NDS32-Regs:: Register Names +* NDS32-Ops:: Pseudo Instructions +@end menu + +@node NDS32-Chars +@subsection Special Characters + +Use @samp{#} at column 1 and @samp{!} anywhere in the line except inside +quotes. + +Multiple instructions in a line are allowed though not recommended and +should be separated by @samp{;}. + +Assembler is not case-sensitive in general except user defined label. +For example, @samp{jral F1} is different from @samp{jral f1} while it is +the same as @samp{JRAL F1}. + +@node NDS32-Regs +@subsection Register Names +@table @code +@item General purpose registers (GPR) +There are 32 32-bit general purpose registers $r0 to $r31. + +@item Accumulators d0 and d1 +64-bit accumulators: $d0.hi, $d0.lo, $d1.hi, and $d1.lo. + +@item Assembler reserved register $ta +Register $ta ($r15) is reserved for assembler using. + +@item Operating system reserved registers $p0 and $p1 +Registers $p0 ($r26) and $p1 ($r27) are used by operating system as scratch +registers. + +@item Frame pointer $fp +Register $r28 is regarded as the frame pointer. + +@item Global pointer +Register $r29 is regarded as the global pointer. + +@item Link pointer +Register $r30 is regarded as the link pointer. + +@item Stack pointer +Register $r31 is regarded as the stack pointer. +@end table + +@node NDS32-Ops +@subsection Pseudo Instructions +@table @code +@item li rt5,imm32 +load 32-bit integer into register rt5. @samp{sethi rt5,hi20(imm32)} and then +@samp{ori rt5,reg,lo12(imm32)}. + +@item la rt5,var +Load 32-bit address of var into register rt5. @samp{sethi rt5,hi20(var)} and +then @samp{ori reg,rt5,lo12(var)} + +@item l.[bhw] rt5,var +Load value of var into register rt5. @samp{sethi $ta,hi20(var)} and then +@samp{l[bhw]i rt5,[$ta+lo12(var)]} + +@item l.[bh]s rt5,var +Load value of var into register rt5. @samp{sethi $ta,hi20(var)} and then +@samp{l[bh]si rt5,[$ta+lo12(var)]} + +@item l.[bhw]p rt5,var,inc +Load value of var into register rt5 and increment $ta by amount inc. +@samp{la $ta,var} and then @samp{l[bhw]i.bi rt5,[$ta],inc} + +@item l.[bhw]pc rt5,inc +Continue loading value of var into register rt5 and increment $ta by amount inc. +@samp{l[bhw]i.bi rt5,[$ta],inc.} + +@item l.[bh]sp rt5,var,inc +Load value of var into register rt5 and increment $ta by amount inc. +@samp{la $ta,var} and then @samp{l[bh]si.bi rt5,[$ta],inc} + +@item l.[bh]spc rt5,inc +Continue loading value of var into register rt5 and increment $ta by amount inc. +@samp{l[bh]si.bi rt5,[$ta],inc.} + +@item s.[bhw] rt5,var +Store register rt5 to var. +@samp{sethi $ta,hi20(var)} and then @samp{s[bhw]i rt5,[$ta+lo12(var)]} + +@item s.[bhw]p rt5,var,inc +Store register rt5 to var and increment $ta by amount inc. +@samp{la $ta,var} and then @samp{s[bhw]i.bi rt5,[$ta],inc} + +@item s.[bhw]pc rt5,inc +Continue storing register rt5 to var and increment $ta by amount inc. +@samp{s[bhw]i.bi rt5,[$ta],inc.} + +@item not rt5,ra5 +Alias of @samp{nor rt5,ra5,ra5}. + +@item neg rt5,ra5 +Alias of @samp{subri rt5,ra5,0}. + +@item br rb5 +Depending on how it is assembled, it is translated into @samp{r5 rb5} +or @samp{jr rb5}. + +@item b label +Branch to label depending on how it is assembled, it is translated into +@samp{j8 label}, @samp{j label}, or "@samp{la $ta,label} @samp{br $ta}". + +@item bral rb5 +Alias of jral br5 depending on how it is assembled, it is translated +into @samp{jral5 rb5} or @samp{jral rb5}. + +@item bal fname +Alias of jal fname depending on how it is assembled, it is translated into +@samp{jal fname} or "@samp{la $ta,fname} @samp{bral $ta}". + +@item call fname +Call function fname same as @samp{jal fname}. + +@item move rt5,ra5 +For 16-bit, this is @samp{mov55 rt5,ra5}. +For no 16-bit, this is @samp{ori rt5,ra5,0}. + +@item move rt5,var +This is the same as @samp{l.w rt5,var}. + +@item move rt5,imm32 +This is the same as @samp{li rt5,imm32}. + +@item pushm ra5,rb5 +Push contents of registers from ra5 to rb5 into stack. + +@item push ra5 +Push content of register ra5 into stack. (same @samp{pushm ra5,ra5}). + +@item push.d var +Push value of double-word variable var into stack. + +@item push.w var +Push value of word variable var into stack. + +@item push.h var +Push value of half-word variable var into stack. + +@item push.b var +Push value of byte variable var into stack. + +@item pusha var +Push 32-bit address of variable var into stack. + +@item pushi imm32 +Push 32-bit immediate value into stack. + +@item popm ra5,rb5 +Pop top of stack values into registers ra5 to rb5. + +@item pop rt5 +Pop top of stack value into register. (same as @samp{popm rt5,rt5}.) + +@item pop.d var,ra5 +Pop value of double-word variable var from stack using register ra5 +as 2nd scratch register. (1st is $ta) + +@item pop.w var,ra5 +Pop value of word variable var from stack using register ra5. + +@item pop.h var,ra5 +Pop value of half-word variable var from stack using register ra5. + +@item pop.b var,ra5 +Pop value of byte variable var from stack using register ra5. + +@end table diff --git a/gas/testsuite/gas/nds32/alu-1.d b/gas/testsuite/gas/nds32/alu-1.d new file mode 100644 index 0000000..f1385cd --- /dev/null +++ b/gas/testsuite/gas/nds32/alu-1.d @@ -0,0 +1,47 @@ +#objdump: -d --prefix-addresses +#name: nds32 alu_1 instructions +#as: + +# Test alu_1 instructions + +.*: file format .* + +Disassembly of section .text: +0+0000 <[^>]*> add \$r0, \$r1, \$r2 +0+0004 <[^>]*> and \$r0, \$r1, \$r2 +0+0008 <[^>]*> cmovn \$r0, \$r1, \$r2 +0+000c <[^>]*> cmovz \$r0, \$r1, \$r2 +0+0010 <[^>]*> nop +0+0014 <[^>]*> nor \$r0, \$r1, \$r2 +0+0018 <[^>]*> or \$r0, \$r1, \$r2 +0+001c <[^>]*> rotr \$r0, \$r1, \$r2 +0+0020 <[^>]*> rotri \$r0, \$r1, #1 +0+0024 <[^>]*> seb \$r0, \$r1 +0+0028 <[^>]*> seh \$r0, \$r1 +0+002c <[^>]*> sll \$r0, \$r1, \$r2 +0+0030 <[^>]*> slli \$r0, \$r1, #1 +0+0034 <[^>]*> slt \$r0, \$r1, \$r2 +0+0038 <[^>]*> slts \$r0, \$r1, \$r2 +0+003c <[^>]*> sra \$r0, \$r1, \$r2 +0+0040 <[^>]*> srai \$r0, \$r1, #1 +0+0044 <[^>]*> srl \$r0, \$r1, \$r2 +0+0048 <[^>]*> srli \$r0, \$r1, #1 +0+004c <[^>]*> sub \$r0, \$r1, \$r2 +0+0050 <[^>]*> sva \$r0, \$r1, \$r2 +0+0054 <[^>]*> svs \$r0, \$r1, \$r2 +0+0058 <[^>]*> wsbh \$r0, \$r1 +0+005c <[^>]*> xor \$r0, \$r1, \$r2 +0+0060 <[^>]*> zeh \$r0, \$r1 +0+0064 <[^>]*> divr \$r0, \$r1, \$r2, \$r3 +0+0068 <[^>]*> divsr \$r0, \$r1, \$r2, \$r3 +0+006c <[^>]*> add_slli \$r0, \$r1, \$r2, #1 +0+0070 <[^>]*> add_srli \$r0, \$r1, \$r2, #1 +0+0074 <[^>]*> and_slli \$r0, \$r1, \$r2, #1 +0+0078 <[^>]*> and_srli \$r0, \$r1, \$r2, #1 +0+007c <[^>]*> bitc \$r0, \$r1, \$r2 +0+0080 <[^>]*> or_slli \$r0, \$r1, \$r2, #1 +0+0084 <[^>]*> or_srli \$r0, \$r1, \$r2, #1 +0+0088 <[^>]*> sub_slli \$r0, \$r1, \$r2, #1 +0+008c <[^>]*> sub_srli \$r0, \$r1, \$r2, #1 +0+0090 <[^>]*> xor_slli \$r0, \$r1, \$r2, #1 +0+0094 <[^>]*> xor_srli \$r0, \$r1, \$r2, #1 diff --git a/gas/testsuite/gas/nds32/alu-1.s b/gas/testsuite/gas/nds32/alu-1.s new file mode 100644 index 0000000..5f12783 --- /dev/null +++ b/gas/testsuite/gas/nds32/alu-1.s @@ -0,0 +1,39 @@ +foo: + add $r0, $r1, $r2 + and $r0, $r1, $r2 + cmovn $r0, $r1, $r2 + cmovz $r0, $r1, $r2 + nop + nor $r0, $r1, $r2 + or $r0, $r1, $r2 + rotr $r0, $r1, $r2 + rotri $r0, $r1, 1 + seb $r0, $r1 + seh $r0, $r1 + sll $r0, $r1, $r2 + slli $r0, $r1, 1 + slt $r0, $r1, $r2 + slts $r0, $r1, $r2 + sra $r0, $r1, $r2 + srai $r0, $r1, 1 + srl $r0, $r1, $r2 + srli $r0, $r1, 1 + sub $r0, $r1, $r2 + sva $r0, $r1, $r2 + svs $r0, $r1, $r2 + wsbh $r0, $r1 + xor $r0, $r1, $r2 + zeh $r0, $r1 + divr $r0, $r1, $r2, $r3 + divsr $r0, $r1, $r2, $r3 + add_slli $r0, $r1, $r2, 1 + add_srli $r0, $r1, $r2, 1 + and_slli $r0, $r1, $r2, 1 + and_srli $r0, $r1, $r2, 1 + bitc $r0, $r1, $r2 + or_slli $r0, $r1, $r2, 1 + or_srli $r0, $r1, $r2, 1 + sub_slli $r0, $r1, $r2, 1 + sub_srli $r0, $r1, $r2, 1 + xor_slli $r0, $r1, $r2, 1 + xor_srli $r0, $r1, $r2, 1 diff --git a/gas/testsuite/gas/nds32/alu-2.d b/gas/testsuite/gas/nds32/alu-2.d new file mode 100644 index 0000000..11c2eb1 --- /dev/null +++ b/gas/testsuite/gas/nds32/alu-2.d @@ -0,0 +1,41 @@ +#objdump: -d --prefix-addresses +#name: nds32 alu_2 instructions +#as: + +# Test alu_2 instructions + +.*: file format .* + +Disassembly of section .text: +0+0000 <[^>]*> madd64 \$d0, \$r0, \$r1 +0+0004 <[^>]*> madds64 \$d0, \$r0, \$r1 +0+0008 <[^>]*> mfusr \$r0, \$pc +0+000c <[^>]*> msub64 \$d0, \$r0, \$r1 +0+0010 <[^>]*> msubs64 \$d0, \$r0, \$r1 +0+0014 <[^>]*> mtusr \$r0, \$pc +0+0018 <[^>]*> mul \$r0, \$r1, \$r2 +0+001c <[^>]*> mult32 \$d0, \$r1, \$r2 +0+0020 <[^>]*> mult64 \$d0, \$r1, \$r2 +0+0024 <[^>]*> mults64 \$d0, \$r1, \$r2 +0+0028 <[^>]*> abs \$r0, \$r1 +0+002c <[^>]*> ave \$r0, \$r1, \$r2 +0+0030 <[^>]*> bclr \$r0, \$r1, #1 +0+0034 <[^>]*> bset \$r0, \$r1, #1 +0+0038 <[^>]*> btgl \$r0, \$r1, #1 +0+003c <[^>]*> btst \$r0, \$r1, #1 +0+0040 <[^>]*> clip \$r0, \$r1, #1 +0+0044 <[^>]*> clips \$r0, \$r1, #1 +0+0048 <[^>]*> clo \$r0, \$r1 +0+004c <[^>]*> clz \$r0, \$r1 +0+0050 <[^>]*> max \$r0, \$r1, \$r2 +0+0054 <[^>]*> min \$r0, \$r1, \$r2 +0+0058 <[^>]*> bse \$r0, \$r1, \$r2 +0+005c <[^>]*> bsp \$r0, \$r1, \$r2 +0+0060 <[^>]*> ffb \$r0, \$r1, \$r2 +0+0064 <[^>]*> ffbi \$r0, \$r1, #0x8 +0+0068 <[^>]*> ffmism \$r0, \$r1, \$r2 +0+006c <[^>]*> flmism \$r0, \$r1, \$r2 +0+0070 <[^>]*> maddr32 \$r0, \$r0, \$r1 +0+0074 <[^>]*> msubr32 \$r0, \$r1, \$r2 +0+0078 <[^>]*> mulr64 \$r0, \$r1, \$r2 +0+007c <[^>]*> mulsr64 \$r0, \$r1, \$r2 diff --git a/gas/testsuite/gas/nds32/alu-2.s b/gas/testsuite/gas/nds32/alu-2.s new file mode 100644 index 0000000..d1743db --- /dev/null +++ b/gas/testsuite/gas/nds32/alu-2.s @@ -0,0 +1,33 @@ +foo: + madd64 $d0, $r0, $r1 + madds64 $d0, $r0, $r1 + mfusr $r0, $pc + msub64 $d0, $r0, $r1 + msubs64 $d0, $r0, $r1 + mtusr $r0, $pc + mul $r0, $r1, $r2 + mult32 $d0, $r1, $r2 + mult64 $d0, $r1, $r2 + mults64 $d0, $r1, $r2 + abs $r0, $r1 + ave $r0, $r1, $r2 + bclr $r0, $r1, 1 + bset $r0, $r1, 1 + btgl $r0, $r1, 1 + btst $r0, $r1, 1 + clip $r0, $r1, 1 + clips $r0, $r1, 1 + clo $r0, $r1 + clz $r0, $r1 + max $r0, $r1, $r2 + min $r0, $r1, $r2 + bse $r0, $r1, $r2 + bsp $r0, $r1, $r2 + ffb $r0, $r1, $r2 + ffbi $r0, $r1, 1 + ffmism $r0, $r1, $r2 + flmism $r0, $r1, $r2 + maddr32 $r0, $r0, $r1 + msubr32 $r0, $r1, $r2 + mulr64 $r0, $r1, $r2 + mulsr64 $r0, $r1, $r2 diff --git a/gas/testsuite/gas/nds32/br-1.d b/gas/testsuite/gas/nds32/br-1.d new file mode 100644 index 0000000..b4842d8 --- /dev/null +++ b/gas/testsuite/gas/nds32/br-1.d @@ -0,0 +1,14 @@ +#objdump: -dr --prefix-addresses +#name: nds32 branch 1 instructions +#as: + +# Test br-1 instructions + +.*: file format .* + +Disassembly of section .text: +0+0000 <[^>]*> beq \$r0, \$r1, 00000000 + 0: R_NDS32_15_PCREL_RELA .text + 0: R_NDS32_RELAX_ENTRY .text +0+0004 <[^>]*> bne \$r0, \$r1, 00000004 + 4: R_NDS32_15_PCREL_RELA .text diff --git a/gas/testsuite/gas/nds32/br-1.s b/gas/testsuite/gas/nds32/br-1.s new file mode 100644 index 0000000..58d993a --- /dev/null +++ b/gas/testsuite/gas/nds32/br-1.s @@ -0,0 +1,3 @@ +foo: + beq $r0, $r1, foo + bne $r0, $r1, foo diff --git a/gas/testsuite/gas/nds32/br-2.d b/gas/testsuite/gas/nds32/br-2.d new file mode 100644 index 0000000..24ce157 --- /dev/null +++ b/gas/testsuite/gas/nds32/br-2.d @@ -0,0 +1,24 @@ +#objdump: -dr --prefix-addresses +#name: nds32 branch 2 instructions +#as: + +# Test br-2 instructions + +.*: file format .* + +Disassembly of section .text: +0+0000 <[^>]*> beqz \$r0, 00000000 + 0: R_NDS32_17_PCREL_RELA .text + 0: R_NDS32_RELAX_ENTRY .text +0+0004 <[^>]*> bgez \$r0, 00000004 + 4: R_NDS32_17_PCREL_RELA .text +0+0008 <[^>]*> bgezal \$r0, 00000008 + 8: R_NDS32_17_PCREL_RELA .text +0+000c <[^>]*> bgtz \$r0, 0000000c + c: R_NDS32_17_PCREL_RELA .text +0+0010 <[^>]*> blez \$r0, 00000010 + 10: R_NDS32_17_PCREL_RELA .text +0+0014 <[^>]*> bltz \$r0, 00000014 + 14: R_NDS32_17_PCREL_RELA .text +0+0018 <[^>]*> bltzal \$r0, 00000018 + 18: R_NDS32_17_PCREL_RELA .text diff --git a/gas/testsuite/gas/nds32/br-2.s b/gas/testsuite/gas/nds32/br-2.s new file mode 100644 index 0000000..554a8de --- /dev/null +++ b/gas/testsuite/gas/nds32/br-2.s @@ -0,0 +1,8 @@ +foo: + beqz $r0, foo + bgez $r0, foo + bgezal $r0, foo + bgtz $r0, foo + blez $r0, foo + bltz $r0, foo + bltzal $r0, foo diff --git a/gas/testsuite/gas/nds32/ji-jr.d b/gas/testsuite/gas/nds32/ji-jr.d new file mode 100644 index 0000000..ac79218 --- /dev/null +++ b/gas/testsuite/gas/nds32/ji-jr.d @@ -0,0 +1,17 @@ +#objdump: -dr --prefix-addresses +#name: nds32 load-store instructions +#as: + +# Test ls instructions + +.*: file format .* + +Disassembly of section .text: +0+0000 <[^>]*> j8 00000000 + 0: R_NDS32_9_PCREL_RELA .text + 0: R_NDS32_RELAX_ENTRY .text +0+0002 <[^>]*> jal 00000002 + 2: R_NDS32_25_PCREL_RELA .text +0+0006 <[^>]*> jr \$r0 +0+000a <[^>]*> jral \$lp, \$r0 +0+000e <[^>]*> ret \$lp diff --git a/gas/testsuite/gas/nds32/ji-jr.s b/gas/testsuite/gas/nds32/ji-jr.s new file mode 100644 index 0000000..2457d0b --- /dev/null +++ b/gas/testsuite/gas/nds32/ji-jr.s @@ -0,0 +1,6 @@ +foo: + j foo + jal foo + jr $r0 + jral $r0 + ret diff --git a/gas/testsuite/gas/nds32/ls.d b/gas/testsuite/gas/nds32/ls.d new file mode 100644 index 0000000..688ed11 --- /dev/null +++ b/gas/testsuite/gas/nds32/ls.d @@ -0,0 +1,25 @@ +#objdump: -d --prefix-addresses +#name: nds32 load-store instructions +#as: + +# Test ls instructions + +.*: file format .* + +Disassembly of section .text: +0+0000 <[^>]*> lw \$r0, \[\$r1 \+ \(\$r2 << 1\)\] +0+0004 <[^>]*> lh \$r0, \[\$r1 \+ \(\$r2 << 1\)\] +0+0008 <[^>]*> lhs \$r0, \[\$r1 \+ \(\$r2 << 1\)\] +0+000c <[^>]*> lb \$r0, \[\$r1 \+ \(\$r2 << 1\)\] +0+0010 <[^>]*> lbs \$r0, \[\$r1 \+ \(\$r2 << 1\)\] +0+0014 <[^>]*> sw \$r0, \[\$r1 \+ \(\$r2 << 1\)\] +0+0018 <[^>]*> sh \$r0, \[\$r1 \+ \(\$r2 << 1\)\] +0+001c <[^>]*> sb \$r0, \[\$r1 \+ \(\$r2 << 1\)\] +0+0020 <[^>]*> lw.bi \$r0, \[\$r1\], \(\$r2 << 1\) +0+0024 <[^>]*> lh.bi \$r0, \[\$r1\], \(\$r2 << 1\) +0+0028 <[^>]*> lhs.bi \$r0, \[\$r1\], \(\$r2 << 1\) +0+002c <[^>]*> lb.bi \$r0, \[\$r1\], \(\$r2 << 1\) +0+0030 <[^>]*> lbs.bi \$r0, \[\$r1\], \(\$r2 << 1\) +0+0034 <[^>]*> sw.bi \$r0, \[\$r1\], \(\$r2 << 1\) +0+0038 <[^>]*> sh.bi \$r0, \[\$r1\], \(\$r2 << 1\) +0+003c <[^>]*> sb.bi \$r0, \[\$r1\], \(\$r2 << 1\) diff --git a/gas/testsuite/gas/nds32/ls.s b/gas/testsuite/gas/nds32/ls.s new file mode 100644 index 0000000..88d3d33 --- /dev/null +++ b/gas/testsuite/gas/nds32/ls.s @@ -0,0 +1,17 @@ +foo: + lw $r0, [$r1 + ($r2 << 1)] + lh $r0, [$r1 + ($r2 << 1)] + lhs $r0, [$r1 + ($r2 << 1)] + lb $r0, [$r1 + ($r2 << 1)] + lbs $r0, [$r1 + ($r2 << 1)] + sw $r0, [$r1 + ($r2 << 1)] + sh $r0, [$r1 + ($r2 << 1)] + sb $r0, [$r1 + ($r2 << 1)] + lw.bi $r0, [$r1], $r2 << 1 + lh.bi $r0, [$r1], $r2 << 1 + lhs.bi $r0, [$r1], $r2 << 1 + lb.bi $r0, [$r1], $r2 << 1 + lbs.bi $r0, [$r1], $r2 << 1 + sw.bi $r0, [$r1], $r2 << 1 + sh.bi $r0, [$r1], $r2 << 1 + sb.bi $r0, [$r1], $r2 << 1 diff --git a/gas/testsuite/gas/nds32/lsi.d b/gas/testsuite/gas/nds32/lsi.d new file mode 100644 index 0000000..9f9839e --- /dev/null +++ b/gas/testsuite/gas/nds32/lsi.d @@ -0,0 +1,25 @@ +#objdump: -d --prefix-addresses +#name: nds32 load-store immediate instructions +#as: + +# Test lsi instructions + +.*: file format .* + +Disassembly of section .text: +0+0000 <[^>]*> lwi \$r0, \[\$r1 \+ #4\] +0+0004 <[^>]*> lhi \$r0, \[\$r1 \+ #2\] +0+0008 <[^>]*> lhsi \$r0, \[\$r1 \+ #-2\] +0+000c <[^>]*> lbi \$r0, \[\$r1 \+ #1\] +0+0010 <[^>]*> lbsi \$r0, \[\$r1 \+ #-1\] +0+0014 <[^>]*> swi \$r0, \[\$r1 \+ #4\] +0+0018 <[^>]*> shi \$r0, \[\$r1 \+ #2\] +0+001c <[^>]*> sbi \$r0, \[\$r1 \+ #1\] +0+0020 <[^>]*> lwi.bi \$r0, \[\$r1\], #4 +0+0024 <[^>]*> lhi.bi \$r0, \[\$r1\], #2 +0+0028 <[^>]*> lhsi.bi \$r0, \[\$r1\], #-2 +0+002c <[^>]*> lbi.bi \$r0, \[\$r1\], #1 +0+0030 <[^>]*> lbsi.bi \$r0, \[\$r1\], #-1 +0+0034 <[^>]*> swi.bi \$r0, \[\$r1\], #4 +0+0038 <[^>]*> shi.bi \$r0, \[\$r1\], #2 +0+003c <[^>]*> sbi.bi \$r0, \[\$r1\], #1 diff --git a/gas/testsuite/gas/nds32/lsi.s b/gas/testsuite/gas/nds32/lsi.s new file mode 100644 index 0000000..a2dd62a --- /dev/null +++ b/gas/testsuite/gas/nds32/lsi.s @@ -0,0 +1,17 @@ +foo: + lwi $r0, [$r1 + (1 << 2)] + lhi $r0, [$r1 + (1 << 1)] + lhsi $r0, [$r1 + (-1 << 1)] + lbi $r0, [$r1 + 1] + lbsi $r0, [$r1 + (-1)] + swi $r0, [$r1 + (1 << 2)] + shi $r0, [$r1 + (1 << 1)] + sbi $r0, [$r1 + 1] + lwi.bi $r0, [$r1], (1 << 2) + lhi.bi $r0, [$r1], (1 << 1) + lhsi.bi $r0, [$r1], (-1 << 1) + lbi.bi $r0, [$r1], 1 + lbsi.bi $r0, [$r1], -1 + swi.bi $r0, [$r1], (1 << 2) + shi.bi $r0, [$r1], (1 << 1) + sbi.bi $r0, [$r1], 1 diff --git a/gas/testsuite/gas/nds32/nds32.exp b/gas/testsuite/gas/nds32/nds32.exp new file mode 100644 index 0000000..52f890c --- /dev/null +++ b/gas/testsuite/gas/nds32/nds32.exp @@ -0,0 +1,13 @@ + +if { [istarget nds32*] } { + run_dump_test "alu-1" + run_dump_test "alu-2" + run_dump_test "lsi" + run_dump_test "ls" + run_dump_test "br-1" + run_dump_test "br-2" + run_dump_test "ji-jr" + run_dump_test "to-16bit-v1" + run_dump_test "to-16bit-v2" + run_dump_test "to-16bit-v3" +} diff --git a/gas/testsuite/gas/nds32/to-16bit-v1.d b/gas/testsuite/gas/nds32/to-16bit-v1.d new file mode 100644 index 0000000..a45de36 --- /dev/null +++ b/gas/testsuite/gas/nds32/to-16bit-v1.d @@ -0,0 +1,79 @@ +#objdump: -d --prefix-addresses +#name: nds32 convert 32 to 16 (v1 instructions) +#as: -Os -mno-reduced-regs + +# Test the convert 32bits to 16bits + +.*: file format .* + + +Disassembly of section .text: +0+0000 .* +0+0002 .* +0+0004 .* +0+0006 .* +0+0008 .* +0+000a .* +0+000c .* +0+000e .* +0+0010 .* +0+0012 .* +0+0014 .* +0+0016 .* +0+0018 .* +0+001a .* +0+001c .* +0+001e .* +0+0020 .* +0+0022 .* +0+0024 .* +0+0026 .* +0+0028 .* +0+002a .* +0+002c .* +0+002e .* +0+0030 .* +0+0032 .* +0+0034 .* +0+0036 .* +0+0038 .* +0+003a .* +0+003c .* +0+003e .* +0+0040 .* +0+0042 .* +0+0044 .* +0+0046 .* +0+0048 .* +0+004a .* +0+004c .* +0+004e .* +0+0050 .* +0+0052 .* +0+0054 .* +0+0056 .* +0+0058 .* +0+005a .* +0+005c .* +0+005e .* +0+0060 .* +0+0062 .* +0+0064 .* +0+0066 .* +0+0068 .* +0+006a .* +0+006c .* +0+006e .* +0+0070 .* +0+0072 .* +0+0074 .* +0+0076 .* +0+0078 .* +0+007a .* +0+007c .* +0+007e .* +0+0080 .* +0+0082 .* +0+0084 .* +0+0086 .* +0+0088 .* diff --git a/gas/testsuite/gas/nds32/to-16bit-v1.s b/gas/testsuite/gas/nds32/to-16bit-v1.s new file mode 100644 index 0000000..195463c --- /dev/null +++ b/gas/testsuite/gas/nds32/to-16bit-v1.s @@ -0,0 +1,70 @@ +foo: + move $r0, $r0 + move $sp, $sp + movi $r0, -16 + movi $sp, 15 + add $r0, $r0, $r0 + add $r19, $sp, $r19 + sub $r0, $r0, $r0 + sub $r19, $r19, $sp + addi $r0, $r0, 0 + addi $r19, $r19, 31 + srai $r0, $r0, 0 + srai $r19, $r19, 31 + srli $r0, $r0, 0 + srli $r19, $r19, 31 + slli $r0, $r0, 0 + slli $r7, $r7, 7 + zeb $r0, $r0 + zeb $r7, $r7 + zeh $r0, $r0 + zeh $r7, $r7 + seb $r0, $r0 + seb $r7, $r7 + seh $r0, $r0 + seh $r7, $r7 + andi $r0, $r0, 1 + andi $r7, $r7, 0x7ff + add $r0, $r0, $r0 + add $r7, $r7, $r7 + sub $r0, $r0, $r0 + sub $r7, $r7, $r7 + addi $r0, $r0, 0 + addi $r7, $r7, 7 + lwi $r0, [$r0 + 0] + lwi $r7, [$r7 + 28] + lwi.bi $r0, [$r0], 0 + lwi.bi $r7, [$r7], 28 + lhi $r0, [$r0 + 0] + lhi $r7, [$r7 + 14] + lbi $r0, [$r0 + 0] + lbi $r7, [$r7 + 7] + swi $r0, [$r0 + 0] + swi $r7, [$r7 + 28] + swi.bi $r0, [$r0], 0 + swi.bi $r7, [$r7], 28 + shi $r0, [$r0 + 0] + shi $r7, [$r7 + 14] + sbi $r0, [$r0 + 0] + sbi $r7, [$r7 + 7] + lwi $r0, [$r0 + 0] + lwi $r19, [$sp + 0] + swi $r0, [$r0 + 0] + swi $r19, [$sp + 0] + lwi $r0, [$fp + 0] + lwi $r7, [$fp + 508] + swi $r0, [$fp + 0] + swi $r7, [$fp + 508] + jr $r0 + jr $sp + ret $r0 + ret $sp + jral $r0 + jral $sp + slts $r15, $r0, $r0 + slts $r15, $r19, $sp + slt $r15, $r0, $r0 + slt $r15, $r19, $sp + sltsi $r15, $r0, 0 + sltsi $r15, $r19, 31 + slti $r15, $r0, 0 diff --git a/gas/testsuite/gas/nds32/to-16bit-v2.d b/gas/testsuite/gas/nds32/to-16bit-v2.d new file mode 100644 index 0000000..5ca929c --- /dev/null +++ b/gas/testsuite/gas/nds32/to-16bit-v2.d @@ -0,0 +1,15 @@ +#objdump: -d --prefix-addresses +#name: nds32 convert 32 to 16 (v2 instructions) +#as: -Os -mno-reduced-regs + +# Test the convert 32bits to 16bits + +.*: file format .* + + +Disassembly of section .text: +0+0000 .* +0+0002 .* +0+0004 .* +0+0006 .* +0+0008 .* diff --git a/gas/testsuite/gas/nds32/to-16bit-v2.s b/gas/testsuite/gas/nds32/to-16bit-v2.s new file mode 100644 index 0000000..1ac3328 --- /dev/null +++ b/gas/testsuite/gas/nds32/to-16bit-v2.s @@ -0,0 +1,6 @@ +foo: +addi $sp, $sp, -512 +addi $sp, $sp, 511 +lwi $r0, [$sp + 0] +lwi $r7, [$sp + 508] +swi $r0, [$sp + 0] diff --git a/gas/testsuite/gas/nds32/to-16bit-v3.d b/gas/testsuite/gas/nds32/to-16bit-v3.d new file mode 100644 index 0000000..2efa8b7 --- /dev/null +++ b/gas/testsuite/gas/nds32/to-16bit-v3.d @@ -0,0 +1,25 @@ +#objdump: -d --prefix-addresses +#name: nds32 convert 32 to 16 (v3 instructions) +#as: -Os -mno-reduced-regs + +# Test the convert 32bits to 16bits + +.*: file format .* + + +Disassembly of section .text: +0+0000 .* +0+0002 .* +0+0004 .* +0+0006 .* +0+0008 .* +0+000a .* +0+000c .* +0+000e .* +0+0010 .* +0+0012 .* +0+0014 .* +0+0016 .* +0+0018 .* +0+001a .* +0+001c .* diff --git a/gas/testsuite/gas/nds32/to-16bit-v3.s b/gas/testsuite/gas/nds32/to-16bit-v3.s new file mode 100644 index 0000000..595a782 --- /dev/null +++ b/gas/testsuite/gas/nds32/to-16bit-v3.s @@ -0,0 +1,16 @@ +foo: +andi $r0, $r0, 1 +andi $r7, $r7, 255 +movi $r0, 16 +movi $r19, 47 +subri $r0, $r0, 0 +subri $r7, $r7, 0 +nor $r0, $r0, $r0 +nor $r7, $r7, $r7 +mul $r0, $r0, $r0 +mul $r7, $r7, $r7 +xor $r0, $r0, $r0 +xor $r7, $r7, $r7 +and $r0, $r0, $r0 +and $r7, $r7, $r7 +or $r0, $r0, $r0