blob: 0deb23ab86c83f4527b6c9209d4213425c85e4ea [file] [log] [blame]
/* tc-score.c -- Assembler for Score
Copyright (C) 2006-2021 Free Software Foundation, Inc.
Contributed by:
Brain.lin (brain.lin@sunplusct.com)
Mei Ligang (ligang@sunnorth.com.cn)
Pei-Lin Tsai (pltsai@sunplus.com)
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, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#include "tc-score7.c"
static void s3_s_score_bss (int ignore ATTRIBUTE_UNUSED);
static void s3_s_score_text (int ignore);
static void s3_score_s_section (int ignore);
static void s3_s_change_sec (int sec);
static void s3_s_score_mask (int reg_type ATTRIBUTE_UNUSED);
static void s3_s_score_ent (int aent);
static void s3_s_score_frame (int ignore ATTRIBUTE_UNUSED);
static void s3_s_score_end (int x ATTRIBUTE_UNUSED);
static void s3_s_score_set (int x ATTRIBUTE_UNUSED);
static void s3_s_score_cpload (int ignore ATTRIBUTE_UNUSED);
static void s3_s_score_cprestore (int ignore ATTRIBUTE_UNUSED);
static void s3_s_score_gpword (int ignore ATTRIBUTE_UNUSED);
static void s3_s_score_cpadd (int ignore ATTRIBUTE_UNUSED);
static void s3_s_score_lcomm (int bytes_p);
static void s_score_bss (int ignore ATTRIBUTE_UNUSED);
static void s_score_text (int ignore);
static void s_section (int ignore);
static void s_change_sec (int sec);
static void s_score_mask (int reg_type ATTRIBUTE_UNUSED);
static void s_score_ent (int aent);
static void s_score_frame (int ignore ATTRIBUTE_UNUSED);
static void s_score_end (int x ATTRIBUTE_UNUSED);
static void s_score_set (int x ATTRIBUTE_UNUSED);
static void s_score_cpload (int ignore ATTRIBUTE_UNUSED);
static void s_score_cprestore (int ignore ATTRIBUTE_UNUSED);
static void s_score_gpword (int ignore ATTRIBUTE_UNUSED);
static void s_score_cpadd (int ignore ATTRIBUTE_UNUSED);
static void s_score_lcomm (int bytes_p);
/* s3: hooks. */
static void s3_md_number_to_chars (char *buf, valueT val, int n);
static valueT s3_md_chars_to_number (char *buf, int n);
static void s3_assemble (char *str);
static void s3_operand (expressionS *);
static void s3_begin (void);
static void s3_number_to_chars (char *buf, valueT val, int n);
static const char *s3_atof (int type, char *litP, int *sizeP);
static void s3_frag_check (fragS * fragp ATTRIBUTE_UNUSED);
static void s3_validate_fix (fixS *fixP);
static int s3_force_relocation (struct fix *fixp);
static bool s3_fix_adjustable (fixS * fixP);
static void s3_elf_final_processing (void);
static int s3_estimate_size_before_relax (fragS * fragp, asection * sec ATTRIBUTE_UNUSED);
static int s3_relax_frag (asection * sec ATTRIBUTE_UNUSED, fragS * fragp, long stretch ATTRIBUTE_UNUSED);
static void s3_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, segT sec ATTRIBUTE_UNUSED, fragS * fragp);
static long s3_pcrel_from (fixS * fixP);
static valueT s3_section_align (segT segment ATTRIBUTE_UNUSED, valueT size);
static void s3_apply_fix (fixS *fixP, valueT *valP, segT seg);
static arelent **s3_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp);
/* s3: utils. */
static void s3_do_ldst_insn (char *);
static void s3_do_crdcrscrsimm5 (char *);
static void s3_do_ldst_unalign (char *);
static void s3_do_ldst_atomic (char *);
static void s3_do_ldst_cop (char *);
static void s3_do_macro_li_rdi32 (char *);
static void s3_do_macro_la_rdi32 (char *);
static void s3_do_macro_rdi32hi (char *);
static void s3_do_macro_rdi32lo (char *);
static void s3_do_macro_mul_rdrsrs (char *);
static void s3_do_macro_bcmp (char *);
static void s3_do_macro_bcmpz (char *);
static void s3_do_macro_ldst_label (char *);
static void s3_do_branch (char *);
static void s3_do_jump (char *);
static void s3_do_empty (char *);
static void s3_do16_int (char *);
static void s3_do_rdrsrs (char *);
static void s3_do_rdsi16 (char *);
static void s3_do_rdrssi14 (char *);
static void s3_do_sub_rdsi16 (char *);
static void s3_do_sub_rdi16 (char *);
static void s3_do_sub_rdrssi14 (char *);
static void s3_do_rdrsi5 (char *);
static void s3_do_rdrsi14 (char *);
static void s3_do_rdi16 (char *);
static void s3_do_ldis (char *);
static void s3_do_xrsi5 (char *);
static void s3_do_rdrs (char *);
static void s3_do_rdxrs (char *);
static void s3_do_rsrs (char *);
static void s3_do_rdcrs (char *);
static void s3_do_rdsrs (char *);
static void s3_do_rd (char *);
static void s3_do16_dsp (char *);
static void s3_do16_dsp2 (char *);
static void s3_do_dsp (char *);
static void s3_do_dsp2 (char *);
static void s3_do_dsp3 (char *);
static void s3_do_rs (char *);
static void s3_do_i15 (char *);
static void s3_do_xi5x (char *);
static void s3_do_ceinst (char *);
static void s3_do_cache (char *);
static void s3_do16_rdrs2 (char *);
static void s3_do16_br (char *);
static void s3_do16_brr (char *);
static void s3_do_ltb (char *);
static void s3_do16_mv_cmp (char *);
static void s3_do16_addi (char *);
static void s3_do16_cmpi (char *);
static void s3_do16_rdi5 (char *);
static void s3_do16_xi5 (char *);
static void s3_do16_ldst_insn (char *);
static void s3_do16_slli_srli (char *);
static void s3_do16_ldiu (char *);
static void s3_do16_push_pop (char *);
static void s3_do16_rpush (char *);
static void s3_do16_rpop (char *);
static void s3_do16_branch (char *);
static void s3_do_lw48 (char *);
static void s3_do_sw48 (char *);
static void s3_do_ldi48 (char *);
static void s3_do_sdbbp48 (char *);
static void s3_do_and48 (char *);
static void s3_do_or48 (char *);
static void s3_do_mbitclr (char *);
static void s3_do_mbitset (char *);
static void s3_do_rdi16_pic (char *);
static void s3_do_addi_s_pic (char *);
static void s3_do_addi_u_pic (char *);
static void s3_do_lw_pic (char *);
#define MARCH_SCORE3 "score3"
#define MARCH_SCORE3D "score3d"
#define MARCH_SCORE7 "score7"
#define MARCH_SCORE7D "score7d"
#define MARCH_SCORE5 "score5"
#define MARCH_SCORE5U "score5u"
#define SCORE_BI_ENDIAN
#ifdef SCORE_BI_ENDIAN
#define OPTION_EB (OPTION_MD_BASE + 0)
#define OPTION_EL (OPTION_MD_BASE + 1)
#else
#if TARGET_BYTES_BIG_ENDIAN
#define OPTION_EB (OPTION_MD_BASE + 0)
#else
#define OPTION_EL (OPTION_MD_BASE + 1)
#endif
#endif
#define OPTION_FIXDD (OPTION_MD_BASE + 2)
#define OPTION_NWARN (OPTION_MD_BASE + 3)
#define OPTION_SCORE5 (OPTION_MD_BASE + 4)
#define OPTION_SCORE5U (OPTION_MD_BASE + 5)
#define OPTION_SCORE7 (OPTION_MD_BASE + 6)
#define OPTION_R1 (OPTION_MD_BASE + 7)
#define OPTION_O0 (OPTION_MD_BASE + 8)
#define OPTION_SCORE_VERSION (OPTION_MD_BASE + 9)
#define OPTION_PIC (OPTION_MD_BASE + 10)
#define OPTION_MARCH (OPTION_MD_BASE + 11)
#define OPTION_SCORE3 (OPTION_MD_BASE + 12)
/* This array holds the chars that always start a comment. If the
pre-processor is disabled, these aren't very useful. */
const char comment_chars[] = "#";
const char line_comment_chars[] = "#";
const char line_separator_chars[] = ";";
/* Chars that can be used to separate mant from exp in floating point numbers. */
const char EXP_CHARS[] = "eE";
const char FLT_CHARS[] = "rRsSfFdDxXeEpP";
#ifdef OBJ_ELF
/* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
symbolS *GOT_symbol;
#endif
const pseudo_typeS md_pseudo_table[] =
{
{"bss", s_score_bss, 0},
{"text", s_score_text, 0},
{"word", cons, 4},
{"long", cons, 4},
{"extend", float_cons, 'x'},
{"ldouble", float_cons, 'x'},
{"packed", float_cons, 'p'},
{"end", s_score_end, 0},
{"ent", s_score_ent, 0},
{"frame", s_score_frame, 0},
{"rdata", s_change_sec, 'r'},
{"sdata", s_change_sec, 's'},
{"set", s_score_set, 0},
{"mask", s_score_mask, 'R'},
{"dword", cons, 8},
{"lcomm", s_score_lcomm, 1},
{"section", s_section, 0},
{"cpload", s_score_cpload, 0},
{"cprestore", s_score_cprestore, 0},
{"gpword", s_score_gpword, 0},
{"cpadd", s_score_cpadd, 0},
{0, 0, 0}
};
const char *md_shortopts = "nO::g::G:";
struct option md_longopts[] =
{
#ifdef OPTION_EB
{"EB" , no_argument, NULL, OPTION_EB},
#endif
#ifdef OPTION_EL
{"EL" , no_argument, NULL, OPTION_EL},
#endif
{"FIXDD" , no_argument, NULL, OPTION_FIXDD},
{"NWARN" , no_argument, NULL, OPTION_NWARN},
{"SCORE5" , no_argument, NULL, OPTION_SCORE5},
{"SCORE5U", no_argument, NULL, OPTION_SCORE5U},
{"SCORE7" , no_argument, NULL, OPTION_SCORE7},
{"USE_R1" , no_argument, NULL, OPTION_R1},
{"O0" , no_argument, NULL, OPTION_O0},
{"V" , no_argument, NULL, OPTION_SCORE_VERSION},
{"KPIC" , no_argument, NULL, OPTION_PIC},
{"march=" , required_argument, NULL, OPTION_MARCH},
{"SCORE3" , no_argument, NULL, OPTION_SCORE3},
{NULL , no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
#define s3_GP 28
#define s3_PIC_CALL_REG 29
#define s3_MAX_LITERAL_POOL_SIZE 1024
#define s3_FAIL 0x80000000
#define s3_SUCCESS 0
#define s3_INSN48_SIZE 6
#define s3_INSN_SIZE 4
#define s3_INSN16_SIZE 2
#define s3_RELAX_INST_NUM 3
/* For score5u : div/mul will pop warning message, mmu/alw/asw will pop error message. */
#define s3_BAD_ARGS _("bad arguments to instruction")
#define s3_ERR_FOR_SCORE5U_MUL_DIV _("div / mul are reserved instructions")
#define s3_ERR_FOR_SCORE5U_MMU _("This architecture doesn't support mmu")
#define s3_ERR_FOR_SCORE5U_ATOMIC _("This architecture doesn't support atomic instruction")
#define s3_BAD_SKIP_COMMA s3_BAD_ARGS
#define s3_BAD_GARBAGE _("garbage following instruction");
#define s3_skip_whitespace(str) while (*(str) == ' ') ++(str)
/* The name of the readonly data section. */
#define s3_RDATA_SECTION_NAME (OUTPUT_FLAVOR == bfd_target_aout_flavour \
? ".data" \
: OUTPUT_FLAVOR == bfd_target_ecoff_flavour \
? ".rdata" \
: OUTPUT_FLAVOR == bfd_target_coff_flavour \
? ".rdata" \
: OUTPUT_FLAVOR == bfd_target_elf_flavour \
? ".rodata" \
: (abort (), ""))
#define s3_RELAX_ENCODE(old, new, type, reloc1, reloc2, opt) \
((relax_substateT) \
(((old) << 23) \
| ((new) << 16) \
| ((type) << 9) \
| ((reloc1) << 5) \
| ((reloc2) << 1) \
| ((opt) ? 1 : 0)))
#define s3_RELAX_OLD(i) (((i) >> 23) & 0x7f)
#define s3_RELAX_NEW(i) (((i) >> 16) & 0x7f)
#define s3_RELAX_TYPE(i) (((i) >> 9) & 0x7f)
#define s3_RELAX_RELOC1(i) ((valueT) ((i) >> 5) & 0xf)
#define s3_RELAX_RELOC2(i) ((valueT) ((i) >> 1) & 0xf)
#define s3_RELAX_OPT(i) ((i) & 1)
#define s3_SET_INSN_ERROR(s) (s3_inst.error = (s))
#define s3_INSN_IS_PCE_P(s) (strstr (str, "||") != NULL)
#define s3_INSN_IS_48_P(s) (strstr (str, "48") != NULL)
#define s3_GET_INSN_CLASS(type) (s3_get_insn_class_from_type (type))
#define s3_GET_INSN_SIZE(type) ((s3_GET_INSN_CLASS (type) == INSN_CLASS_16) \
? s3_INSN16_SIZE : (s3_GET_INSN_CLASS (type) == INSN_CLASS_48) \
? s3_INSN48_SIZE : s3_INSN_SIZE)
#define s3_INSN_NAME_LEN 16
/* Relax will need some padding for alignment. */
#define s3_RELAX_PAD_BYTE 3
#define s3_USE_GLOBAL_POINTER_OPT 1
/* Enumeration matching entries in table above. */
enum s3_score_reg_type
{
s3_REG_TYPE_SCORE = 0,
#define s3_REG_TYPE_FIRST s3_REG_TYPE_SCORE
s3_REG_TYPE_SCORE_SR = 1,
s3_REG_TYPE_SCORE_CR = 2,
s3_REG_TYPE_MAX = 3
};
enum s3_score_pic_level
{
s3_NO_PIC,
s3_PIC
};
static enum s3_score_pic_level s3_score_pic = s3_NO_PIC;
enum s3_insn_type_for_dependency
{
s3_D_mtcr,
s3_D_all_insn
};
struct s3_insn_to_dependency
{
const char *insn_name;
enum s3_insn_type_for_dependency type;
};
struct s3_data_dependency
{
enum s3_insn_type_for_dependency pre_insn_type;
char pre_reg[6];
enum s3_insn_type_for_dependency cur_insn_type;
char cur_reg[6];
int bubblenum_7;
int bubblenum_3;
int warn_or_error; /* warning - 0; error - 1 */
};
static const struct s3_insn_to_dependency s3_insn_to_dependency_table[] =
{
/* move special instruction. */
{"mtcr", s3_D_mtcr},
};
static const struct s3_data_dependency s3_data_dependency_table[] =
{
/* Status register. */
{s3_D_mtcr, "cr0", s3_D_all_insn, "", 5, 1, 0},
};
/* Used to contain constructed error messages. */
static char s3_err_msg[255];
static int s3_fix_data_dependency = 0;
static int s3_warn_fix_data_dependency = 1;
static int s3_in_my_get_expression = 0;
/* Default, pop warning message when using r1. */
static int s3_nor1 = 1;
/* Default will do instruction relax, -O0 will set s3_g_opt = 0. */
static unsigned int s3_g_opt = 1;
/* The size of the small data section. */
static unsigned int s3_g_switch_value = 8;
static segT s3_pdr_seg;
struct s3_score_it
{
char name[s3_INSN_NAME_LEN];
bfd_vma instruction;
bfd_vma relax_inst;
int size;
int relax_size;
enum score_insn_type type;
char str[s3_MAX_LITERAL_POOL_SIZE];
const char *error;
int bwarn;
char reg[s3_INSN_NAME_LEN];
struct
{
bfd_reloc_code_real_type type;
expressionS exp;
int pc_rel;
}reloc;
};
static struct s3_score_it s3_inst;
typedef struct s3_proc
{
symbolS *isym;
unsigned long reg_mask;
unsigned long reg_offset;
unsigned long fpreg_mask;
unsigned long leaf;
unsigned long frame_offset;
unsigned long frame_reg;
unsigned long pc_reg;
} s3_procS;
static s3_procS s3_cur_proc;
static s3_procS *s3_cur_proc_ptr;
static int s3_numprocs;
/* Structure for a hash table entry for a register. */
struct s3_reg_entry
{
const char *name;
int number;
};
static const struct s3_reg_entry s3_score_rn_table[] =
{
{"r0", 0}, {"r1", 1}, {"r2", 2}, {"r3", 3},
{"r4", 4}, {"r5", 5}, {"r6", 6}, {"r7", 7},
{"r8", 8}, {"r9", 9}, {"r10", 10}, {"r11", 11},
{"r12", 12}, {"r13", 13}, {"r14", 14}, {"r15", 15},
{"r16", 16}, {"r17", 17}, {"r18", 18}, {"r19", 19},
{"r20", 20}, {"r21", 21}, {"r22", 22}, {"r23", 23},
{"r24", 24}, {"r25", 25}, {"r26", 26}, {"r27", 27},
{"r28", 28}, {"r29", 29}, {"r30", 30}, {"r31", 31},
{NULL, 0}
};
static const struct s3_reg_entry s3_score_srn_table[] =
{
{"sr0", 0}, {"sr1", 1}, {"sr2", 2},
{NULL, 0}
};
static const struct s3_reg_entry s3_score_crn_table[] =
{
{"cr0", 0}, {"cr1", 1}, {"cr2", 2}, {"cr3", 3},
{"cr4", 4}, {"cr5", 5}, {"cr6", 6}, {"cr7", 7},
{"cr8", 8}, {"cr9", 9}, {"cr10", 10}, {"cr11", 11},
{"cr12", 12}, {"cr13", 13}, {"cr14", 14}, {"cr15", 15},
{"cr16", 16}, {"cr17", 17}, {"cr18", 18}, {"cr19", 19},
{"cr20", 20}, {"cr21", 21}, {"cr22", 22}, {"cr23", 23},
{"cr24", 24}, {"cr25", 25}, {"cr26", 26}, {"cr27", 27},
{"cr28", 28}, {"cr29", 29}, {"cr30", 30}, {"cr31", 31},
{NULL, 0}
};
struct s3_reg_map
{
const struct s3_reg_entry *names;
int max_regno;
htab_t htab;
const char *expected;
};
static struct s3_reg_map s3_all_reg_maps[] =
{
{s3_score_rn_table, 31, NULL, N_("S+core register expected")},
{s3_score_srn_table, 2, NULL, N_("S+core special-register expected")},
{s3_score_crn_table, 31, NULL, N_("S+core co-processor register expected")},
};
static htab_t s3_score_ops_hsh = NULL;
static htab_t s3_dependency_insn_hsh = NULL;
struct s3_datafield_range
{
int data_type;
int bits;
int range[2];
};
static struct s3_datafield_range s3_score_df_range[] =
{
{_IMM4, 4, {0, (1 << 4) - 1}}, /* ( 0 ~ 15 ) */
{_IMM5, 5, {0, (1 << 5) - 1}}, /* ( 0 ~ 31 ) */
{_IMM8, 8, {0, (1 << 8) - 1}}, /* ( 0 ~ 255 ) */
{_IMM14, 14, {0, (1 << 14) - 1}}, /* ( 0 ~ 16383) */
{_IMM15, 15, {0, (1 << 15) - 1}}, /* ( 0 ~ 32767) */
{_IMM16, 16, {0, (1 << 16) - 1}}, /* ( 0 ~ 65535) */
{_SIMM10, 10, {-(1 << 9), (1 << 9) - 1}}, /* ( -512 ~ 511 ) */
{_SIMM12, 12, {-(1 << 11), (1 << 11) - 1}}, /* ( -2048 ~ 2047 ) */
{_SIMM14, 14, {-(1 << 13), (1 << 13) - 1}}, /* ( -8192 ~ 8191 ) */
{_SIMM15, 15, {-(1 << 14), (1 << 14) - 1}}, /* (-16384 ~ 16383) */
{_SIMM16, 16, {-(1 << 15), (1 << 15) - 1}}, /* (-32768 ~ 32767) */
{_SIMM14_NEG, 14, {-(1 << 13), (1 << 13) - 1}}, /* ( -8191 ~ 8192 ) */
{_IMM16_NEG, 16, {0, (1 << 16) - 1}}, /* (-65535 ~ 0 ) */
{_SIMM16_NEG, 16, {-(1 << 15), (1 << 15) - 1}}, /* (-32768 ~ 32767) */
{_IMM20, 20, {0, (1 << 20) - 1}},
{_IMM25, 25, {0, (1 << 25) - 1}},
{_DISP8div2, 8, {-(1 << 8), (1 << 8) - 1}}, /* ( -256 ~ 255 ) */
{_DISP11div2, 11, {0, 0}},
{_DISP19div2, 19, {-(1 << 19), (1 << 19) - 1}}, /* (-524288 ~ 524287) */
{_DISP24div2, 24, {0, 0}},
{_VALUE, 32, {0, ((unsigned int)1 << 31) - 1}},
{_VALUE_HI16, 16, {0, (1 << 16) - 1}},
{_VALUE_LO16, 16, {0, (1 << 16) - 1}},
{_VALUE_LDST_LO16, 16, {0, (1 << 16) - 1}},
{_SIMM16_LA, 16, {-(1 << 15), (1 << 15) - 1}}, /* (-32768 ~ 32767) */
{_IMM5_RSHIFT_1, 5, {0, (1 << 6) - 1}}, /* ( 0 ~ 63 ) */
{_IMM5_RSHIFT_2, 5, {0, (1 << 7) - 1}}, /* ( 0 ~ 127 ) */
{_SIMM16_LA_POS, 16, {0, (1 << 15) - 1}}, /* ( 0 ~ 32767) */
{_IMM5_RANGE_8_31, 5, {8, 31}}, /* But for cop0 the valid data : (8 ~ 31). */
{_IMM10_RSHIFT_2, 10, {-(1 << 11), (1 << 11) - 1}}, /* For ldc#, stc#. */
{_SIMM10, 10, {0, (1 << 10) - 1}}, /* ( -1024 ~ 1023 ) */
{_SIMM12, 12, {0, (1 << 12) - 1}}, /* ( -2048 ~ 2047 ) */
{_SIMM14, 14, {0, (1 << 14) - 1}}, /* ( -8192 ~ 8191 ) */
{_SIMM15, 15, {0, (1 << 15) - 1}}, /* (-16384 ~ 16383) */
{_SIMM16, 16, {0, (1 << 16) - 1}}, /* (-65536 ~ 65536) */
{_SIMM14_NEG, 14, {0, (1 << 16) - 1}}, /* ( -8191 ~ 8192 ) */
{_IMM16_NEG, 16, {0, (1 << 16) - 1}}, /* ( 65535 ~ 0 ) */
{_SIMM16_NEG, 16, {0, (1 << 16) - 1}}, /* ( 65535 ~ 0 ) */
{_IMM20, 20, {0, (1 << 20) - 1}}, /* (-32768 ~ 32767) */
{_IMM25, 25, {0, (1 << 25) - 1}}, /* (-32768 ~ 32767) */
{_GP_IMM15, 15, {0, (1 << 15) - 1}}, /* ( 0 ~ 65535) */
{_GP_IMM14, 14, {0, (1 << 14) - 1}}, /* ( 0 ~ 65535) */
{_SIMM16_pic, 16, {-(1 << 15), (1 << 15) - 1}}, /* (-32768 ~ 32767) */
{_IMM16_LO16_pic, 16, {0, (1 << 16) - 1}}, /* ( 65535 ~ 0 ) */
{_IMM16_pic, 16, {0, (1 << 16) - 1}}, /* ( 0 ~ 65535) */
{_SIMM5, 5, {-(1 << 4), (1 << 4) - 1}}, /* ( -16 ~ 15 ) */
{_SIMM6, 6, {-(1 << 5), (1 << 5) - 1}}, /* ( -32 ~ 31 ) */
{_IMM32, 32, {0, 0xfffffff}},
{_SIMM32, 32, {-0x80000000, 0x7fffffff}},
{_IMM11, 11, {0, (1 << 11) - 1}},
};
struct s3_asm_opcode
{
/* Instruction name. */
const char *template_name;
/* Instruction Opcode. */
bfd_vma value;
/* Instruction bit mask. */
bfd_vma bitmask;
/* Relax instruction opcode. 0x8000 imply no relaxation. */
bfd_vma relax_value;
/* Instruction type. */
enum score_insn_type type;
/* Function to call to parse args. */
void (*parms) (char *);
};
static const struct s3_asm_opcode s3_score_ldst_insns[] =
{
{"lw", 0x20000000, 0x3e000000, 0x1000, Rd_rvalueRs_SI15, s3_do_ldst_insn},
{"lw", 0x06000000, 0x3e000007, 0x8000, Rd_rvalueRs_preSI12, s3_do_ldst_insn},
{"lw", 0x0e000000, 0x3e000007, 0x0040, Rd_rvalueRs_postSI12, s3_do_ldst_insn},
{"lh", 0x22000000, 0x3e000000, 0x8000, Rd_rvalueRs_SI15, s3_do_ldst_insn},
{"lh", 0x06000001, 0x3e000007, 0x8000, Rd_rvalueRs_preSI12, s3_do_ldst_insn},
{"lh", 0x0e000001, 0x3e000007, 0x8000, Rd_rvalueRs_postSI12, s3_do_ldst_insn},
{"lhu", 0x24000000, 0x3e000000, 0x8000, Rd_rvalueRs_SI15, s3_do_ldst_insn},
{"lhu", 0x06000002, 0x3e000007, 0x8000, Rd_rvalueRs_preSI12, s3_do_ldst_insn},
{"lhu", 0x0e000002, 0x3e000007, 0x8000, Rd_rvalueRs_postSI12, s3_do_ldst_insn},
{"lb", 0x26000000, 0x3e000000, 0x8000, Rd_rvalueRs_SI15, s3_do_ldst_insn},
{"lb", 0x06000003, 0x3e000007, 0x8000, Rd_rvalueRs_preSI12, s3_do_ldst_insn},
{"lb", 0x0e000003, 0x3e000007, 0x8000, Rd_rvalueRs_postSI12, s3_do_ldst_insn},
{"sw", 0x28000000, 0x3e000000, 0x2000, Rd_lvalueRs_SI15, s3_do_ldst_insn},
{"sw", 0x06000004, 0x3e000007, 0x0060, Rd_lvalueRs_preSI12, s3_do_ldst_insn},
{"sw", 0x0e000004, 0x3e000007, 0x8000, Rd_lvalueRs_postSI12, s3_do_ldst_insn},
{"sh", 0x2a000000, 0x3e000000, 0x8000, Rd_lvalueRs_SI15, s3_do_ldst_insn},
{"sh", 0x06000005, 0x3e000007, 0x8000, Rd_lvalueRs_preSI12, s3_do_ldst_insn},
{"sh", 0x0e000005, 0x3e000007, 0x8000, Rd_lvalueRs_postSI12, s3_do_ldst_insn},
{"lbu", 0x2c000000, 0x3e000000, 0x8000, Rd_rvalueRs_SI15, s3_do_ldst_insn},
{"lbu", 0x06000006, 0x3e000007, 0x8000, Rd_rvalueRs_preSI12, s3_do_ldst_insn},
{"lbu", 0x0e000006, 0x3e000007, 0x8000, Rd_rvalueRs_postSI12, s3_do_ldst_insn},
{"sb", 0x2e000000, 0x3e000000, 0x8000, Rd_lvalueRs_SI15, s3_do_ldst_insn},
{"sb", 0x06000007, 0x3e000007, 0x8000, Rd_lvalueRs_preSI12, s3_do_ldst_insn},
{"sb", 0x0e000007, 0x3e000007, 0x8000, Rd_lvalueRs_postSI12, s3_do_ldst_insn},
};
static const struct s3_asm_opcode s3_score_insns[] =
{
{"abs", 0x3800000a, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_dsp3},
{"abs.s", 0x3800004b, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_dsp3},
{"add", 0x00000010, 0x3e0003ff, 0x4800, Rd_Rs_Rs, s3_do_rdrsrs},
{"add.c", 0x00000011, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"add.s", 0x38000048, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_dsp2},
{"addc", 0x00000012, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"addc.c", 0x00000013, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"addi", 0x02000000, 0x3e0e0001, 0x5c00, Rd_SI16, s3_do_rdsi16},
{"addi.c", 0x02000001, 0x3e0e0001, 0x8000, Rd_SI16, s3_do_rdsi16},
{"addis", 0x0a000000, 0x3e0e0001, 0x8000, Rd_SI16, s3_do_rdi16},
{"addis.c", 0x0a000001, 0x3e0e0001, 0x8000, Rd_SI16, s3_do_rdi16},
{"addi!", 0x5c00, 0x7c00, 0x8000, Rd_SI6, s3_do16_addi},
{"addri", 0x10000000, 0x3e000001, 0x8000, Rd_Rs_SI14, s3_do_rdrssi14},
{"addri.c", 0x10000001, 0x3e000001, 0x8000, Rd_Rs_SI14, s3_do_rdrssi14},
/* add.c <-> add!. */
{"add!", 0x4800, 0x7f00, 0x8000, Rd_Rs, s3_do16_rdrs2},
{"subi", 0x02000000, 0x3e0e0001, 0x8000, Rd_SI16, s3_do_sub_rdsi16},
{"subi.c", 0x02000001, 0x3e0e0001, 0x8000, Rd_SI16, s3_do_sub_rdsi16},
{"subis", 0x0a000000, 0x3e0e0001, 0x8000, Rd_SI16, s3_do_sub_rdi16},
{"subis.c", 0x0a000001, 0x3e0e0001, 0x8000, Rd_SI16, s3_do_sub_rdi16},
{"subri", 0x10000000, 0x3e000001, 0x8000, Rd_Rs_SI14, s3_do_sub_rdrssi14},
{"subri.c", 0x10000001, 0x3e000001, 0x8000, Rd_Rs_SI14, s3_do_sub_rdrssi14},
{"and", 0x00000020, 0x3e0003ff, 0x4b00, Rd_Rs_Rs, s3_do_rdrsrs},
{"and.c", 0x00000021, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"andi", 0x02080000, 0x3e0e0001, 0x8000, Rd_I16, s3_do_rdi16},
{"andi.c", 0x02080001, 0x3e0e0001, 0x8000, Rd_I16, s3_do_rdi16},
{"andis", 0x0a080000, 0x3e0e0001, 0x8000, Rd_I16, s3_do_rdi16},
{"andis.c", 0x0a080001, 0x3e0e0001, 0x8000, Rd_I16, s3_do_rdi16},
{"andri", 0x18000000, 0x3e000001, 0x8000, Rd_Rs_I14, s3_do_rdrsi14},
{"andri.c", 0x18000001, 0x3e000001, 0x8000, Rd_Rs_I14, s3_do_rdrsi14},
/* and.c <-> and!. */
{"and!", 0x4b00, 0x7f00, 0x8000, Rd_Rs, s3_do16_rdrs2},
{"bcs", 0x08000000, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bcc", 0x08000400, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bcnz", 0x08003800, 0x3e007c01, 0x3200, PC_DISP19div2, s3_do_branch},
{"bcsl", 0x08000001, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bccl", 0x08000401, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bcnzl", 0x08003801, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bcnz!", 0x3200, 0x7f00, 0x08003800, PC_DISP8div2, s3_do16_branch},
{"beq", 0x08001000, 0x3e007c01, 0x3800, PC_DISP19div2, s3_do_branch},
{"beql", 0x08001001, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"beq!", 0x3800, 0x7e00, 0x08001000, PC_DISP8div2, s3_do16_branch},
{"bgtu", 0x08000800, 0x3e007c01, 0x3400, PC_DISP19div2, s3_do_branch},
{"bgt", 0x08001800, 0x3e007c01, 0x3c00, PC_DISP19div2, s3_do_branch},
{"bge", 0x08002000, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bgtul", 0x08000801, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bgtl", 0x08001801, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bgel", 0x08002001, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bgtu!", 0x3400, 0x7e00, 0x08000800, PC_DISP8div2, s3_do16_branch},
{"bgt!", 0x3c00, 0x7e00, 0x08001800, PC_DISP8div2, s3_do16_branch},
{"bitclr", 0x00000028, 0x3e0003ff, 0x5000, Rd_Rs_I5, s3_do_rdrsi5},
{"bitclr.c", 0x00000029, 0x3e0003ff, 0x8000, Rd_Rs_I5, s3_do_rdrsi5},
{"mbitclr", 0x00000064, 0x3e00007e, 0x8000, Ra_I9_I5, s3_do_mbitclr},
{"mbitset", 0x0000006c, 0x3e00007e, 0x8000, Ra_I9_I5, s3_do_mbitset},
{"bitrev", 0x3800000c, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_dsp2},
{"bitset", 0x0000002a, 0x3e0003ff, 0x5200, Rd_Rs_I5, s3_do_rdrsi5},
{"bitset.c", 0x0000002b, 0x3e0003ff, 0x8000, Rd_Rs_I5, s3_do_rdrsi5},
{"bittst.c", 0x0000002d, 0x3e0003ff, 0x5400, x_Rs_I5, s3_do_xrsi5},
{"bittgl", 0x0000002e, 0x3e0003ff, 0x5600, Rd_Rs_I5, s3_do_rdrsi5},
{"bittgl.c", 0x0000002f, 0x3e0003ff, 0x8000, Rd_Rs_I5, s3_do_rdrsi5},
{"bitclr!", 0x5000, 0x7e00, 0x8000, Rd_I5, s3_do16_rdi5},
{"bitset!", 0x5200, 0x7e00, 0x8000, Rd_I5, s3_do16_rdi5},
{"bittst!", 0x5400, 0x7e00, 0x8000, Rd_I5, s3_do16_rdi5},
{"bittgl!", 0x5600, 0x7e00, 0x8000, Rd_I5, s3_do16_rdi5},
{"bleu", 0x08000c00, 0x3e007c01, 0x3600, PC_DISP19div2, s3_do_branch},
{"ble", 0x08001c00, 0x3e007c01, 0x3e00, PC_DISP19div2, s3_do_branch},
{"blt", 0x08002400, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bleul", 0x08000c01, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"blel", 0x08001c01, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bltl", 0x08002401, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bl", 0x08003c01, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bleu!", 0x3600, 0x7e00, 0x08000c00, PC_DISP8div2, s3_do16_branch},
{"ble!", 0x3e00, 0x7e00, 0x08001c00, PC_DISP8div2, s3_do16_branch},
{"bmi", 0x08002800, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bmil", 0x08002801, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bne", 0x08001400, 0x3e007c01, 0x3a00, PC_DISP19div2, s3_do_branch},
{"bnel", 0x08001401, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bne!", 0x3a00, 0x7e00, 0x08001400, PC_DISP8div2, s3_do16_branch},
{"bpl", 0x08002c00, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bpll", 0x08002c01, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"brcs", 0x00000008, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brcc", 0x00000408, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brgtu", 0x00000808, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brleu", 0x00000c08, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"breq", 0x00001008, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brne", 0x00001408, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brgt", 0x00001808, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brle", 0x00001c08, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brge", 0x00002008, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brlt", 0x00002408, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brmi", 0x00002808, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brpl", 0x00002c08, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brvs", 0x00003008, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brvc", 0x00003408, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brcnz", 0x00003808, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"br", 0x00003c08, 0x3e007fff, 0x0080, x_Rs_x, s3_do_rs},
{"brcsl", 0x00000009, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brccl", 0x00000409, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brgtul", 0x00000809, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brleul", 0x00000c09, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"breql", 0x00001009, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brnel", 0x00001409, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brgtl", 0x00001809, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brlel", 0x00001c09, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brgel", 0x00002009, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brltl", 0x00002409, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brmil", 0x00002809, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brpll", 0x00002c09, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brvsl", 0x00003009, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brvcl", 0x00003409, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brcnzl", 0x00003809, 0x3e007fff, 0x8000, x_Rs_x, s3_do_rs},
{"brl", 0x00003c09, 0x3e007fff, 0x00a0, x_Rs_x, s3_do_rs},
{"br!", 0x0080, 0x7fe0, 0x8000, x_Rs, s3_do16_br},
{"brl!", 0x00a0, 0x7fe0, 0x8000, x_Rs, s3_do16_br},
{"brr!", 0x00c0, 0x7fe0, 0x8000, x_Rs, s3_do16_brr},
{"bvs", 0x08003000, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bvc", 0x08003400, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bvsl", 0x08003001, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"bvcl", 0x08003401, 0x3e007c01, 0x8000, PC_DISP19div2, s3_do_branch},
{"b!", 0x3000, 0x7e00, 0x08003c00, PC_DISP8div2, s3_do16_branch},
{"b", 0x08003c00, 0x3e007c01, 0x3000, PC_DISP19div2, s3_do_branch},
{"cache", 0x30000000, 0x3ff00000, 0x8000, OP5_rvalueRs_SI15, s3_do_cache},
{"ceinst", 0x38000000, 0x3e000000, 0x8000, I5_Rs_Rs_I5_OP5, s3_do_ceinst},
{"clz", 0x0000001c, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"cmp.c", 0x00300019, 0x3ff003ff, 0x4400, x_Rs_Rs, s3_do_rsrs},
{"cmpz.c", 0x0030001b, 0x3ff07fff, 0x8000, x_Rs_x, s3_do_rs},
{"cmpi.c", 0x02040001, 0x3e0e0001, 0x6000, Rd_SI16, s3_do_rdsi16},
/* cmp.c <-> cmp!. */
{"cmp!", 0x4400, 0x7c00, 0x8000, Rd_Rs, s3_do16_mv_cmp},
{"cmpi!", 0x6000, 0x7c00, 0x8000, Rd_SI5, s3_do16_cmpi},
{"cop1", 0x0c00000c, 0x3e00001f, 0x8000, Rd_Rs_Rs_imm, s3_do_crdcrscrsimm5},
{"cop2", 0x0c000014, 0x3e00001f, 0x8000, Rd_Rs_Rs_imm, s3_do_crdcrscrsimm5},
{"cop3", 0x0c00001c, 0x3e00001f, 0x8000, Rd_Rs_Rs_imm, s3_do_crdcrscrsimm5},
{"drte", 0x0c0000a4, 0x3e0003ff, 0x8000, NO_OPD, s3_do_empty},
{"disint!", 0x00e0, 0xffe1, 0x8000, NO16_OPD, s3_do16_int},
{"enint!", 0x00e1, 0xffe1, 0x8000, NO16_OPD, s3_do16_int},
{"extsb", 0x00000058, 0x3e0003ff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"extsb.c", 0x00000059, 0x3e0003ff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"extsh", 0x0000005a, 0x3e0003ff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"extsh.c", 0x0000005b, 0x3e0003ff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"extzb", 0x0000005c, 0x3e0003ff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"extzb.c", 0x0000005d, 0x3e0003ff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"extzh", 0x0000005e, 0x3e0003ff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"extzh.c", 0x0000005f, 0x3e0003ff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"jl", 0x04000001, 0x3e000001, 0x8000, PC_DISP24div2, s3_do_jump},
{"j", 0x04000000, 0x3e000001, 0x8000, PC_DISP24div2, s3_do_jump},
{"alw", 0x0000000c, 0x3e0003ff, 0x8000, Rd_rvalue32Rs, s3_do_ldst_atomic},
{"lcb", 0x00000060, 0x3e0003ff, 0x8000, x_rvalueRs_post4, s3_do_ldst_unalign},
{"lcw", 0x00000062, 0x3e0003ff, 0x8000, Rd_rvalueRs_post4, s3_do_ldst_unalign},
{"lce", 0x00000066, 0x3e0003ff, 0x8000, Rd_rvalueRs_post4, s3_do_ldst_unalign},
{"ldc1", 0x0c00000a, 0x3e00001f, 0x8000, Rd_rvalueRs_SI10, s3_do_ldst_cop},
{"ldc2", 0x0c000012, 0x3e00001f, 0x8000, Rd_rvalueRs_SI10, s3_do_ldst_cop},
{"ldc3", 0x0c00001a, 0x3e00001f, 0x8000, Rd_rvalueRs_SI10, s3_do_ldst_cop},
/* s3_inst.relax */
{"ldi", 0x020c0000, 0x3e0e0000, 0x6400, Rd_SI16, s3_do_rdsi16},
{"ldis", 0x0a0c0000, 0x3e0e0000, 0x8000, Rd_I16, s3_do_ldis},
/* ldi <-> ldiu!. */
{"ldiu!", 0x6400, 0x7c00, 0x8000, Rd_I5, s3_do16_ldiu},
/*ltbb! , ltbh! ltbw! */
{"ltbw", 0x00000032, 0x03ff, 0x8000, Rd_Rs_Rs, s3_do_ltb},
{"ltbh", 0x00000132, 0x03ff, 0x8000, Rd_Rs_Rs, s3_do_ltb},
{"ltbb", 0x00000332, 0x03ff, 0x8000, Rd_Rs_Rs, s3_do_ltb},
{"lw!", 0x1000, 0x7000, 0x8000, Rd_rvalueRs, s3_do16_ldst_insn},
{"mfcel", 0x00000448, 0x3e007fff, 0x8000, Rd_x_x, s3_do_rd},
{"mfcel!", 0x7100, 0x7ff0, 0x00000448, x_Rs, s3_do16_dsp},
{"mad", 0x38000000, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"mad.f!", 0x7400, 0x7f00, 0x38000080, Rd_Rs, s3_do16_dsp2},
{"madh", 0x38000203, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"madh.fs", 0x380002c3, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"madh.fs!", 0x7b00, 0x7f00, 0x380002c3, Rd_Rs, s3_do16_dsp2},
{"madl", 0x38000002, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"madl.fs", 0x380000c2, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"madl.fs!", 0x7a00, 0x7f00, 0x380000c2, Rd_Rs, s3_do16_dsp2},
{"madu", 0x38000020, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"madu!", 0x7500, 0x7f00, 0x38000020, Rd_Rs, s3_do16_dsp2},
{"mad.f", 0x38000080, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"max", 0x38000007, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_dsp2},
{"mazh", 0x38000303, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"mazh.f", 0x38000383, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"mazh.f!", 0x7900, 0x7f00, 0x3800038c, Rd_Rs, s3_do16_dsp2},
{"mazl", 0x38000102, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"mazl.f", 0x38000182, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"mazl.f!", 0x7800, 0x7f00, 0x38000182, Rd_Rs, s3_do16_dsp2},
{"mfceh", 0x00000848, 0x3e007fff, 0x8000, Rd_x_x, s3_do_rd},
{"mfceh!", 0x7110, 0x7ff0, 0x00000848, x_Rs, s3_do16_dsp},
{"mfcehl", 0x00000c48, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"mfsr", 0x00000050, 0x3e0003ff, 0x8000, Rd_x_I5, s3_do_rdsrs},
{"mfcr", 0x0c000001, 0x3e00001f, 0x8000, Rd_Rs_x, s3_do_rdcrs},
{"mfc1", 0x0c000009, 0x3e00001f, 0x8000, Rd_Rs_x, s3_do_rdcrs},
{"mfc2", 0x0c000011, 0x3e00001f, 0x8000, Rd_Rs_x, s3_do_rdcrs},
{"mfc3", 0x0c000019, 0x3e00001f, 0x8000, Rd_Rs_x, s3_do_rdcrs},
{"mfcc1", 0x0c00000f, 0x3e00001f, 0x8000, Rd_Rs_x, s3_do_rdcrs},
{"mfcc2", 0x0c000017, 0x3e00001f, 0x8000, Rd_Rs_x, s3_do_rdcrs},
{"mfcc3", 0x0c00001f, 0x3e00001f, 0x8000, Rd_Rs_x, s3_do_rdcrs},
{"min", 0x38000006, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_dsp2},
{"msb", 0x38000001, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"msb.f!", 0x7600, 0x7f00, 0x38000081, Rd_Rs, s3_do16_dsp2},
{"msbh", 0x38000205, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"msbh.fs", 0x380002c5, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"msbh.fs!", 0x7f00, 0x7f00, 0x380002c5, Rd_Rs, s3_do16_dsp2},
{"msbl", 0x38000004, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"msbl.fs", 0x380000c4, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"msbl.fs!", 0x7e00, 0x7f00, 0x380000c4, Rd_Rs, s3_do16_dsp2},
{"msbu", 0x38000021, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"msbu!", 0x7700, 0x7f00, 0x38000021, Rd_Rs, s3_do16_dsp2},
{"msb.f", 0x38000081, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"mszh", 0x38000305, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"mszh.f", 0x38000385, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"mszh.f!", 0x7d00, 0x7f00, 0x38000385, Rd_Rs, s3_do16_dsp2},
{"mszl", 0x38000104, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"mszl.f", 0x38000184, 0x3ff003ff, 0x8000, x_Rs_Rs, s3_do_dsp},
{"mszl.f!", 0x7c00, 0x7f00, 0x38000184, Rd_Rs, s3_do16_dsp2},
{"mtcel!", 0x7000, 0x7ff0, 0x0000044a, x_Rs, s3_do16_dsp},
{"mtcel", 0x0000044a, 0x3e007fff, 0x8000, Rd_x_x, s3_do_rd},
{"mtceh", 0x0000084a, 0x3e007fff, 0x8000, Rd_x_x, s3_do_rd},
{"mtceh!", 0x7010, 0x7ff0, 0x0000084a, x_Rs, s3_do16_dsp},
{"mtcehl", 0x00000c4a, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"mtsr", 0x00000052, 0x3e0003ff, 0x8000, x_Rs_I5, s3_do_rdsrs},
{"mtcr", 0x0c000000, 0x3e00001f, 0x8000, Rd_Rs_x, s3_do_rdcrs},
{"mtc1", 0x0c000008, 0x3e00001f, 0x8000, Rd_Rs_x, s3_do_rdcrs},
{"mtc2", 0x0c000010, 0x3e00001f, 0x8000, Rd_Rs_x, s3_do_rdcrs},
{"mtc3", 0x0c000018, 0x3e00001f, 0x8000, Rd_Rs_x, s3_do_rdcrs},
{"mtcc1", 0x0c00000e, 0x3e00001f, 0x8000, Rd_Rs_x, s3_do_rdcrs},
{"mtcc2", 0x0c000016, 0x3e00001f, 0x8000, Rd_Rs_x, s3_do_rdcrs},
{"mtcc3", 0x0c00001e, 0x3e00001f, 0x8000, Rd_Rs_x, s3_do_rdcrs},
{"mul.f!", 0x7200, 0x7f00, 0x00000041, Rd_Rs, s3_do16_dsp2},
{"mulu!", 0x7300, 0x7f00, 0x00000042, Rd_Rs, s3_do16_dsp2},
{"mulr.l", 0x00000140, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_rdrsrs},
{"mulr.h", 0x00000240, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_rdrsrs},
{"mulr", 0x00000340, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_rdrsrs},
{"mulr.lf", 0x00000141, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_rdrsrs},
{"mulr.hf", 0x00000241, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_rdrsrs},
{"mulr.f", 0x00000341, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_rdrsrs},
{"mulur.l", 0x00000142, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_rdrsrs},
{"mulur.h", 0x00000242, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_rdrsrs},
{"mulur", 0x00000342, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_rdrsrs},
{"divr.q", 0x00000144, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_rdrsrs},
{"divr.r", 0x00000244, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_rdrsrs},
{"divr", 0x00000344, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_rdrsrs},
{"divur.q", 0x00000146, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_rdrsrs},
{"divur.r", 0x00000246, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_rdrsrs},
{"divur", 0x00000346, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_rdrsrs},
{"mvcs", 0x00000056, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"mvcc", 0x00000456, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"mvgtu", 0x00000856, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"mvleu", 0x00000c56, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"mveq", 0x00001056, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"mvne", 0x00001456, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"mvgt", 0x00001856, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"mvle", 0x00001c56, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"mvge", 0x00002056, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"mvlt", 0x00002456, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"mvmi", 0x00002856, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"mvpl", 0x00002c56, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"mvvs", 0x00003056, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"mvvc", 0x00003456, 0x3e007fff, 0x8000, Rd_Rs_x, s3_do_rdrs},
/* mv <-> mv!. */
{"mv", 0x00003c56, 0x3e007fff, 0x4000, Rd_Rs_x, s3_do_rdrs},
{"mv!", 0x4000, 0x7c00, 0x8000, Rd_Rs, s3_do16_mv_cmp},
{"neg", 0x0000001e, 0x3e0003ff, 0x8000, Rd_x_Rs, s3_do_rdxrs},
{"neg.c", 0x0000001f, 0x3e0003ff, 0x8000, Rd_x_Rs, s3_do_rdxrs},
{"nop", 0x00000000, 0x3e0003ff, 0x0000, NO_OPD, s3_do_empty},
{"not", 0x00000024, 0x3e0003ff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"not.c", 0x00000025, 0x3e0003ff, 0x8000, Rd_Rs_x, s3_do_rdrs},
{"nop!", 0x0000, 0x7fff, 0x8000, NO16_OPD, s3_do_empty},
{"or", 0x00000022, 0x3e0003ff, 0x4a00, Rd_Rs_Rs, s3_do_rdrsrs},
{"or.c", 0x00000023, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"ori", 0x020a0000, 0x3e0e0001, 0x8000, Rd_I16, s3_do_rdi16},
{"ori.c", 0x020a0001, 0x3e0e0001, 0x8000, Rd_I16, s3_do_rdi16},
{"oris", 0x0a0a0000, 0x3e0e0001, 0x8000, Rd_I16, s3_do_rdi16},
{"oris.c", 0x0a0a0001, 0x3e0e0001, 0x8000, Rd_I16, s3_do_rdi16},
{"orri", 0x1a000000, 0x3e000001, 0x8000, Rd_Rs_I14, s3_do_rdrsi14},
{"orri.c", 0x1a000001, 0x3e000001, 0x8000, Rd_Rs_I14, s3_do_rdrsi14},
/* or.c <-> or!. */
{"or!", 0x4a00, 0x7f00, 0x8000, Rd_Rs, s3_do16_rdrs2},
{"pflush", 0x0000000a, 0x3e0003ff, 0x8000, NO_OPD, s3_do_empty},
{"pop!", 0x0040, 0x7fe0, 0x8000, Rd_rvalueRs, s3_do16_push_pop},
{"push!", 0x0060, 0x7fe0, 0x8000, Rd_lvalueRs, s3_do16_push_pop},
{"rpop!", 0x6800, 0x7c00, 0x8000, Rd_I5, s3_do16_rpop},
{"rpush!", 0x6c00, 0x7c00, 0x8000, Rd_I5, s3_do16_rpush},
{"ror", 0x00000038, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"ror.c", 0x00000039, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"rorc.c", 0x0000003b, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"rol", 0x0000003c, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"rol.c", 0x0000003d, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"rolc.c", 0x0000003f, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"rori", 0x00000078, 0x3e0003ff, 0x8000, Rd_Rs_I5, s3_do_rdrsi5},
{"rori.c", 0x00000079, 0x3e0003ff, 0x8000, Rd_Rs_I5, s3_do_rdrsi5},
{"roric.c", 0x0000007b, 0x3e0003ff, 0x8000, Rd_Rs_I5, s3_do_rdrsi5},
{"roli", 0x0000007c, 0x3e0003ff, 0x8000, Rd_Rs_I5, s3_do_rdrsi5},
{"roli.c", 0x0000007d, 0x3e0003ff, 0x8000, Rd_Rs_I5, s3_do_rdrsi5},
{"rolic.c", 0x0000007f, 0x3e0003ff, 0x8000, Rd_Rs_I5, s3_do_rdrsi5},
{"rte", 0x0c000084, 0x3e0003ff, 0x8000, NO_OPD, s3_do_empty},
{"asw", 0x0000000e, 0x3e0003ff, 0x8000, Rd_lvalue32Rs, s3_do_ldst_atomic},
{"scb", 0x00000068, 0x3e0003ff, 0x8000, Rd_lvalueRs_post4, s3_do_ldst_unalign},
{"scw", 0x0000006a, 0x3e0003ff, 0x8000, Rd_lvalueRs_post4, s3_do_ldst_unalign},
{"sce", 0x0000006e, 0x3e0003ff, 0x8000, x_lvalueRs_post4, s3_do_ldst_unalign},
{"sdbbp", 0x00000006, 0x3e0003ff, 0x0020, x_I5_x, s3_do_xi5x},
{"sdbbp!", 0x0020, 0x7fe0, 0x8000, Rd_I5, s3_do16_xi5},
{"sleep", 0x0c0000c4, 0x3e0003ff, 0x8000, NO_OPD, s3_do_empty},
{"rti", 0x0c0000e4, 0x3e0003ff, 0x8000, NO_OPD, s3_do_empty},
{"sll", 0x00000030, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"sll.c", 0x00000031, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"sll.s", 0x3800004e, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_dsp2},
{"slli", 0x00000070, 0x3e0003ff, 0x5800, Rd_Rs_I5, s3_do_rdrsi5},
{"slli.c", 0x00000071, 0x3e0003ff, 0x8000, Rd_Rs_I5, s3_do_rdrsi5},
/* slli.c <-> slli!. */
{"slli!", 0x5800, 0x7e00, 0x8000, Rd_I5, s3_do16_slli_srli},
{"srl", 0x00000034, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"srl.c", 0x00000035, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"sra", 0x00000036, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"sra.c", 0x00000037, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"srli", 0x00000074, 0x3e0003ff, 0x5a00, Rd_Rs_I5, s3_do_rdrsi5},
{"srli.c", 0x00000075, 0x3e0003ff, 0x8000, Rd_Rs_I5, s3_do_rdrsi5},
{"srai", 0x00000076, 0x3e0003ff, 0x8000, Rd_Rs_I5, s3_do_rdrsi5},
{"srai.c", 0x00000077, 0x3e0003ff, 0x8000, Rd_Rs_I5, s3_do_rdrsi5},
/* srli.c <-> srli!. */
{"srli!", 0x5a00, 0x7e00, 0x8000, Rd_Rs, s3_do16_slli_srli},
{"stc1", 0x0c00000b, 0x3e00001f, 0x8000, Rd_lvalueRs_SI10, s3_do_ldst_cop},
{"stc2", 0x0c000013, 0x3e00001f, 0x8000, Rd_lvalueRs_SI10, s3_do_ldst_cop},
{"stc3", 0x0c00001b, 0x3e00001f, 0x8000, Rd_lvalueRs_SI10, s3_do_ldst_cop},
{"sub", 0x00000014, 0x3e0003ff, 0x4900, Rd_Rs_Rs, s3_do_rdrsrs},
{"sub.c", 0x00000015, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"sub.s", 0x38000049, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_dsp2},
{"subc", 0x00000016, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"subc.c", 0x00000017, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
/* sub.c <-> sub!. */
{"sub!", 0x4900, 0x7f00, 0x8000, Rd_Rs, s3_do16_rdrs2},
{"sw!", 0x2000, 0x7000, 0x8000, Rd_lvalueRs, s3_do16_ldst_insn},
{"syscall", 0x00000002, 0x3e0003ff, 0x8000, I15, s3_do_i15},
{"trapcs", 0x00000004, 0x3e007fff, 0x8000, x_I5_x, s3_do_xi5x},
{"trapcc", 0x00000404, 0x3e007fff, 0x8000, x_I5_x, s3_do_xi5x},
{"trapgtu", 0x00000804, 0x3e007fff, 0x8000, x_I5_x, s3_do_xi5x},
{"trapleu", 0x00000c04, 0x3e007fff, 0x8000, x_I5_x, s3_do_xi5x},
{"trapeq", 0x00001004, 0x3e007fff, 0x8000, x_I5_x, s3_do_xi5x},
{"trapne", 0x00001404, 0x3e007fff, 0x8000, x_I5_x, s3_do_xi5x},
{"trapgt", 0x00001804, 0x3e007fff, 0x8000, x_I5_x, s3_do_xi5x},
{"traple", 0x00001c04, 0x3e007fff, 0x8000, x_I5_x, s3_do_xi5x},
{"trapge", 0x00002004, 0x3e007fff, 0x8000, x_I5_x, s3_do_xi5x},
{"traplt", 0x00002404, 0x3e007fff, 0x8000, x_I5_x, s3_do_xi5x},
{"trapmi", 0x00002804, 0x3e007fff, 0x8000, x_I5_x, s3_do_xi5x},
{"trappl", 0x00002c04, 0x3e007fff, 0x8000, x_I5_x, s3_do_xi5x},
{"trapvs", 0x00003004, 0x3e007fff, 0x8000, x_I5_x, s3_do_xi5x},
{"trapvc", 0x00003404, 0x3e007fff, 0x8000, x_I5_x, s3_do_xi5x},
{"trap", 0x00003c04, 0x3e007fff, 0x8000, x_I5_x, s3_do_xi5x},
{"xor", 0x00000026, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
{"xor.c", 0x00000027, 0x3e0003ff, 0x8000, Rd_Rs_Rs, s3_do_rdrsrs},
/* Macro instruction. */
{"li", 0x020c0000, 0x3e0e0000, 0x8000, Insn_Type_SYN, s3_do_macro_li_rdi32},
/* la reg, imm32 -->(1) ldi reg, simm16
(2) ldis reg, %HI(imm32)
ori reg, %LO(imm32)
la reg, symbol -->(1) lis reg, %HI(imm32)
ori reg, %LO(imm32) */
{"la", 0x020c0000, 0x3e0e0000, 0x8000, Insn_Type_SYN, s3_do_macro_la_rdi32},
{"bcmpeqz", 0x0000004c, 0x3e00007e, 0x8000, Insn_BCMP, s3_do_macro_bcmpz},
{"bcmpeq", 0x0000004c, 0x3e00007e, 0x8000, Insn_BCMP, s3_do_macro_bcmp},
{"bcmpnez", 0x0000004e, 0x3e00007e, 0x8000, Insn_BCMP, s3_do_macro_bcmpz},
{"bcmpne", 0x0000004e, 0x3e00007e, 0x8000, Insn_BCMP, s3_do_macro_bcmp},
{"div", 0x00000044, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_macro_mul_rdrsrs},
{"divu", 0x00000046, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_macro_mul_rdrsrs},
{"rem", 0x00000044, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_macro_mul_rdrsrs},
{"remu", 0x00000046, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_macro_mul_rdrsrs},
{"mul", 0x00000040, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_macro_mul_rdrsrs},
{"mulu", 0x00000042, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_macro_mul_rdrsrs},
{"maz", 0x00000040, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_macro_mul_rdrsrs},
{"mazu", 0x00000042, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_macro_mul_rdrsrs},
{"mul.f", 0x00000041, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_macro_mul_rdrsrs},
{"maz.f", 0x00000041, 0x3e0003ff, 0x8000, Insn_Type_SYN, s3_do_macro_mul_rdrsrs},
{"lb", INSN_LB, 0x00000000, 0x8000, Insn_Type_SYN, s3_do_macro_ldst_label},
{"lbu", INSN_LBU, 0x00000000, 0x8000, Insn_Type_SYN, s3_do_macro_ldst_label},
{"lh", INSN_LH, 0x00000000, 0x8000, Insn_Type_SYN, s3_do_macro_ldst_label},
{"lhu", INSN_LHU, 0x00000000, 0x8000, Insn_Type_SYN, s3_do_macro_ldst_label},
{"lw", INSN_LW, 0x00000000, 0x1000, Insn_Type_SYN, s3_do_macro_ldst_label},
{"sb", INSN_SB, 0x00000000, 0x8000, Insn_Type_SYN, s3_do_macro_ldst_label},
{"sh", INSN_SH, 0x00000000, 0x8000, Insn_Type_SYN, s3_do_macro_ldst_label},
{"sw", INSN_SW, 0x00000000, 0x2000, Insn_Type_SYN, s3_do_macro_ldst_label},
/* Assembler use internal. */
{"ld_i32hi", 0x0a0c0000, 0x3e0e0000, 0x8000, Insn_internal, s3_do_macro_rdi32hi},
{"ld_i32lo", 0x020a0000, 0x3e0e0001, 0x8000, Insn_internal, s3_do_macro_rdi32lo},
{"ldis_pic", 0x0a0c0000, 0x3e0e0000, 0x8000, Insn_internal, s3_do_rdi16_pic},
{"addi_s_pic",0x02000000, 0x3e0e0001, 0x8000, Insn_internal, s3_do_addi_s_pic},
{"addi_u_pic",0x02000000, 0x3e0e0001, 0x8000, Insn_internal, s3_do_addi_u_pic},
{"lw_pic", 0x20000000, 0x3e000000, 0x8000, Insn_internal, s3_do_lw_pic},
/* 48-bit instructions. */
{"sdbbp48", 0x000000000000LL, 0x1c000000001fLL, 0x8000, Rd_I32, s3_do_sdbbp48},
{"ldi48", 0x000000000001LL, 0x1c000000001fLL, 0x8000, Rd_I32, s3_do_ldi48},
{"lw48", 0x000000000002LL, 0x1c000000001fLL, 0x8000, Rd_I30, s3_do_lw48},
{"sw48", 0x000000000003LL, 0x1c000000001fLL, 0x8000, Rd_I30, s3_do_sw48},
{"andri48", 0x040000000000LL, 0x1c0000000003LL, 0x8000, Rd_I32, s3_do_and48},
{"andri48.c", 0x040000000001LL, 0x1c0000000003LL, 0x8000, Rd_I32, s3_do_and48},
{"orri48", 0x040000000002LL, 0x1c0000000003LL, 0x8000, Rd_I32, s3_do_or48},
{"orri48.c", 0x040000000003LL, 0x1c0000000003LL, 0x8000, Rd_I32, s3_do_or48},
};
#define s3_SCORE3_PIPELINE 3
static int s3_university_version = 0;
static int s3_vector_size = s3_SCORE3_PIPELINE;
static struct s3_score_it s3_dependency_vector[s3_SCORE3_PIPELINE];
static int s3_score3d = 1;
static int
s3_end_of_line (char *str)
{
int retval = s3_SUCCESS;
s3_skip_whitespace (str);
if (*str != '\0')
{
retval = (int) s3_FAIL;
if (!s3_inst.error)
s3_inst.error = s3_BAD_GARBAGE;
}
return retval;
}
static int
s3_score_reg_parse (char **ccp, htab_t htab)
{
char *start = *ccp;
char c;
char *p;
struct s3_reg_entry *reg;
p = start;
if (!ISALPHA (*p) || !is_name_beginner (*p))
return (int) s3_FAIL;
c = *p++;
while (ISALPHA (c) || ISDIGIT (c) || c == '_')
c = *p++;
*--p = 0;
reg = (struct s3_reg_entry *) str_hash_find (htab, start);
*p = c;
if (reg)
{
*ccp = p;
return reg->number;
}
return (int) s3_FAIL;
}
/* If shift <= 0, only return reg. */
static int
s3_reg_required_here (char **str, int shift, enum s3_score_reg_type reg_type)
{
static char buff[s3_MAX_LITERAL_POOL_SIZE];
int reg = (int) s3_FAIL;
char *start = *str;
if ((reg = s3_score_reg_parse (str, s3_all_reg_maps[reg_type].htab)) != (int) s3_FAIL)
{
if (reg_type == s3_REG_TYPE_SCORE)
{
if ((reg == 1) && (s3_nor1 == 1) && (s3_inst.bwarn == 0))
{
as_warn (_("Using temp register (r1)"));
s3_inst.bwarn = 1;
}
}
if (shift >= 0)
{
if (reg_type == s3_REG_TYPE_SCORE_CR)
strcpy (s3_inst.reg, s3_score_crn_table[reg].name);
else if (reg_type == s3_REG_TYPE_SCORE_SR)
strcpy (s3_inst.reg, s3_score_srn_table[reg].name);
else
strcpy (s3_inst.reg, "");
s3_inst.instruction |= (bfd_vma) reg << shift;
}
}
else
{
*str = start;
sprintf (buff, _("register expected, not '%.100s'"), start);
s3_inst.error = buff;
}
return reg;
}
static int
s3_skip_past_comma (char **str)
{
char *p = *str;
char c;
int comma = 0;
while ((c = *p) == ' ' || c == ',')
{
p++;
if (c == ',' && comma++)
{
s3_inst.error = s3_BAD_SKIP_COMMA;
return (int) s3_FAIL;
}
}
if ((c == '\0') || (comma == 0))
{
s3_inst.error = s3_BAD_SKIP_COMMA;
return (int) s3_FAIL;
}
*str = p;
return comma ? s3_SUCCESS : (int) s3_FAIL;
}
static void
s3_do_rdrsrs (char *str)
{
int reg;
s3_skip_whitespace (str);
if ((reg = s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE)) == (int) s3_FAIL
|| s3_skip_past_comma (&str) == (int) s3_FAIL
|| s3_reg_required_here (&str, 15, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_skip_past_comma (&str) == (int) s3_FAIL
|| s3_reg_required_here (&str, 10, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_end_of_line (str) == (int) s3_FAIL)
{
return;
}
else
{
/* Check mulr, mulur rd is even number. */
if (((s3_inst.instruction & 0x3e0003ff) == 0x00000340
|| (s3_inst.instruction & 0x3e0003ff) == 0x00000342)
&& (reg % 2))
{
s3_inst.error = _("rd must be even number.");
return;
}
if ((((s3_inst.instruction >> 15) & 0x10) == 0)
&& (((s3_inst.instruction >> 10) & 0x10) == 0)
&& (((s3_inst.instruction >> 20) & 0x10) == 0)
&& (s3_inst.relax_inst != 0x8000)
&& (((s3_inst.instruction >> 20) & 0xf) == ((s3_inst.instruction >> 15) & 0xf)))
{
s3_inst.relax_inst |= (((s3_inst.instruction >> 10) & 0xf) )
| (((s3_inst.instruction >> 15) & 0xf) << 4);
s3_inst.relax_size = 2;
}
else
{
s3_inst.relax_inst = 0x8000;
}
}
}
static int
s3_walk_no_bignums (symbolS * sp)
{
if (symbol_get_value_expression (sp)->X_op == O_big)
return 1;
if (symbol_get_value_expression (sp)->X_add_symbol)
return (s3_walk_no_bignums (symbol_get_value_expression (sp)->X_add_symbol)
|| (symbol_get_value_expression (sp)->X_op_symbol
&& s3_walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol)));
return 0;
}
static int
s3_my_get_expression (expressionS * ep, char **str)
{
char *save_in;
save_in = input_line_pointer;
input_line_pointer = *str;
s3_in_my_get_expression = 1;
(void) expression (ep);
s3_in_my_get_expression = 0;
if (ep->X_op == O_illegal)
{
*str = input_line_pointer;
input_line_pointer = save_in;
s3_inst.error = _("illegal expression");
return (int) s3_FAIL;
}
/* Get rid of any bignums now, so that we don't generate an error for which
we can't establish a line number later on. Big numbers are never valid
in instructions, which is where this routine is always called. */
if (ep->X_op == O_big
|| (ep->X_add_symbol
&& (s3_walk_no_bignums (ep->X_add_symbol)
|| (ep->X_op_symbol && s3_walk_no_bignums (ep->X_op_symbol)))))
{
s3_inst.error = _("invalid constant");
*str = input_line_pointer;
input_line_pointer = save_in;
return (int) s3_FAIL;
}
if ((ep->X_add_symbol != NULL)
&& (s3_inst.type != PC_DISP19div2)
&& (s3_inst.type != PC_DISP8div2)
&& (s3_inst.type != PC_DISP24div2)
&& (s3_inst.type != PC_DISP11div2)
&& (s3_inst.type != Insn_Type_SYN)
&& (s3_inst.type != Rd_rvalueRs_SI15)
&& (s3_inst.type != Rd_lvalueRs_SI15)
&& (s3_inst.type != Insn_internal)
&& (s3_inst.type != Rd_I30)
&& (s3_inst.type != Rd_I32)
&& (s3_inst.type != Insn_BCMP))
{
s3_inst.error = s3_BAD_ARGS;
*str = input_line_pointer;
input_line_pointer = save_in;
return (int) s3_FAIL;
}
*str = input_line_pointer;
input_line_pointer = save_in;
return s3_SUCCESS;
}
/* Check if an immediate is valid. If so, convert it to the right format. */
static bfd_signed_vma
s3_validate_immediate (bfd_signed_vma val, unsigned int data_type, int hex_p)
{
switch (data_type)
{
case _VALUE_HI16:
{
bfd_signed_vma val_hi = ((val & 0xffff0000) >> 16);
if (s3_score_df_range[data_type].range[0] <= val_hi
&& val_hi <= s3_score_df_range[data_type].range[1])
return val_hi;
}
break;
case _VALUE_LO16:
{
bfd_signed_vma val_lo = (val & 0xffff);
if (s3_score_df_range[data_type].range[0] <= val_lo
&& val_lo <= s3_score_df_range[data_type].range[1])
return val_lo;
}
break;
case _SIMM14:
if (hex_p == 1)
{
if (!(val >= -0x2000 && val <= 0x3fff))
{
return (int) s3_FAIL;
}
}
else
{
if (!(val >= -8192 && val <= 8191))
{
return (int) s3_FAIL;
}
}
return val;
break;
case _SIMM16_NEG:
if (hex_p == 1)
{
if (!(val >= -0x7fff && val <= 0xffff && val != 0x8000))
{
return (int) s3_FAIL;
}
}
else
{
if (!(val >= -32767 && val <= 32768))
{
return (int) s3_FAIL;
}
}
val = -val;
return val;
break;
case _IMM5_MULTI_LOAD:
if (val >= 2 && val <= 32)
{
if (val == 32)
val = 0;
return val;
}
return (int) s3_FAIL;
case _IMM32:
if (val >= 0 && val <= 0xffffffff)
{
return val;
}
else
{
return (int) s3_FAIL;
}
default:
if (data_type == _SIMM14_NEG || data_type == _IMM16_NEG)
val = -val;
if (s3_score_df_range[data_type].range[0] <= val
&& val <= s3_score_df_range[data_type].range[1])
return val;
break;
}
return (int) s3_FAIL;
}
static int
s3_data_op2 (char **str, int shift, enum score_data_type data_type)
{
bfd_signed_vma value;
char data_exp[s3_MAX_LITERAL_POOL_SIZE];
char *dataptr;
int cnt = 0;
char *pp = NULL;
s3_skip_whitespace (*str);
s3_inst.error = NULL;
dataptr = * str;
/* Set hex_p to zero. */
int hex_p = 0;
while ((*dataptr != '\0') && (*dataptr != '|') && (cnt <= s3_MAX_LITERAL_POOL_SIZE)) /* 0x7c = ='|' */
{
data_exp[cnt] = *dataptr;
dataptr++;
cnt++;
}
data_exp[cnt] = '\0';
pp = (char *)&data_exp;
if (*dataptr == '|') /* process PCE */
{
if (s3_my_get_expression (&s3_inst.reloc.exp, &pp) == (int) s3_FAIL)
return (int) s3_FAIL;
s3_end_of_line (pp);
if (s3_inst.error != 0)
return (int) s3_FAIL; /* to ouptut_inst to printf out the error */
*str = dataptr;
}
else /* process 16 bit */
{
if (s3_my_get_expression (&s3_inst.reloc.exp, str) == (int) s3_FAIL)
{
return (int) s3_FAIL;
}
dataptr = (char *)data_exp;
for (; *dataptr != '\0'; dataptr++)
{
*dataptr = TOLOWER (*dataptr);
if (*dataptr == '!' || *dataptr == ' ')
break;
}
dataptr = (char *)data_exp;
if ((dataptr != NULL)
&& (((strstr (dataptr, "0x")) != NULL)
|| ((strstr (dataptr, "0X")) != NULL)))
{
hex_p = 1;
if ((data_type != _SIMM16_LA)
&& (data_type != _VALUE_HI16)
&& (data_type != _VALUE_LO16)
&& (data_type != _IMM16)
&& (data_type != _IMM15)
&& (data_type != _IMM14)
&& (data_type != _IMM4)
&& (data_type != _IMM5)
&& (data_type != _IMM5_MULTI_LOAD)
&& (data_type != _IMM11)
&& (data_type != _IMM8)
&& (data_type != _IMM5_RSHIFT_1)
&& (data_type != _IMM5_RSHIFT_2)
&& (data_type != _SIMM14)
&& (data_type != _SIMM14_NEG)
&& (data_type != _SIMM16_NEG)
&& (data_type != _IMM10_RSHIFT_2)
&& (data_type != _GP_IMM15)
&& (data_type != _SIMM5)
&& (data_type != _SIMM6)
&& (data_type != _IMM32)
&& (data_type != _SIMM32))
{
data_type += 24;
}
}
if ((s3_inst.reloc.exp.X_add_number == 0)
&& (s3_inst.type != Insn_Type_SYN)
&& (s3_inst.type != Rd_rvalueRs_SI15)
&& (s3_inst.type != Rd_lvalueRs_SI15)
&& (s3_inst.type != Insn_internal)
&& (((*dataptr >= 'a') && (*dataptr <= 'z'))
|| ((*dataptr == '0') && (*(dataptr + 1) == 'x') && (*(dataptr + 2) != '0'))
|| ((*dataptr == '+') && (*(dataptr + 1) != '0'))
|| ((*dataptr == '-') && (*(dataptr + 1) != '0'))))
{
s3_inst.error = s3_BAD_ARGS;
return (int) s3_FAIL;
}
}
if ((s3_inst.reloc.exp.X_add_symbol)
&& ((data_type == _SIMM16)
|| (data_type == _SIMM16_NEG)
|| (data_type == _IMM16_NEG)
|| (data_type == _SIMM14)
|| (data_type == _SIMM14_NEG)
|| (data_type == _IMM5)
|| (data_type == _IMM5_MULTI_LOAD)
|| (data_type == _IMM11)
|| (data_type == _IMM14)
|| (data_type == _IMM20)
|| (data_type == _IMM16)
|| (data_type == _IMM15)
|| (data_type == _IMM4)))
{
s3_inst.error = s3_BAD_ARGS;
return (int) s3_FAIL;
}
if (s3_inst.reloc.exp.X_add_symbol)
{
switch (data_type)
{
case _SIMM16_LA:
return (int) s3_FAIL;
case _VALUE_HI16:
s3_inst.reloc.type = BFD_RELOC_HI16_S;
s3_inst.reloc.pc_rel = 0;
break;
case _VALUE_LO16:
s3_inst.reloc.type = BFD_RELOC_LO16;
s3_inst.reloc.pc_rel = 0;
break;
case _GP_IMM15:
s3_inst.reloc.type = BFD_RELOC_SCORE_GPREL15;
s3_inst.reloc.pc_rel = 0;
break;
case _SIMM16_pic:
case _IMM16_LO16_pic:
s3_inst.reloc.type = BFD_RELOC_SCORE_GOT_LO16;
s3_inst.reloc.pc_rel = 0;
break;
default:
s3_inst.reloc.type = BFD_RELOC_32;
s3_inst.reloc.pc_rel = 0;
break;
}
}
else
{
if (data_type == _IMM16_pic)
{
s3_inst.reloc.type = BFD_RELOC_SCORE_DUMMY_HI16;
s3_inst.reloc.pc_rel = 0;
}
if (data_type == _SIMM16_LA && s3_inst.reloc.exp.X_unsigned == 1)
{
value = s3_validate_immediate (s3_inst.reloc.exp.X_add_number, _SIMM16_LA_POS, hex_p);
if (value == (int) s3_FAIL) /* for advance to check if this is ldis */
if ((s3_inst.reloc.exp.X_add_number & 0xffff) == 0)
{
s3_inst.instruction |= 0x8000000;
s3_inst.instruction |= ((s3_inst.reloc.exp.X_add_number >> 16) << 1) & 0x1fffe;
return s3_SUCCESS;
}
}
else
{
value = s3_validate_immediate (s3_inst.reloc.exp.X_add_number, data_type, hex_p);
}
if (value == (int) s3_FAIL)
{
if (data_type == _IMM32)
{
sprintf (s3_err_msg,
_("invalid constant: %d bit expression not in range %u..%u"),
s3_score_df_range[data_type].bits,
0, (unsigned)0xffffffff);
}
else if (data_type == _IMM5_MULTI_LOAD)
{
sprintf (s3_err_msg,
_("invalid constant: %d bit expression not in range %u..%u"),
5, 2, 32);
}
else if ((data_type != _SIMM14_NEG) && (data_type != _SIMM16_NEG) && (data_type != _IMM16_NEG))
{
sprintf (s3_err_msg,
_("invalid constant: %d bit expression not in range %d..%d"),
s3_score_df_range[data_type].bits,
s3_score_df_range[data_type].range[0], s3_score_df_range[data_type].range[1]);
}
else
{
sprintf (s3_err_msg,
_("invalid constant: %d bit expression not in range %d..%d"),
s3_score_df_range[data_type].bits,
-s3_score_df_range[data_type].range[1], -s3_score_df_range[data_type].range[0]);
}
s3_inst.error = s3_err_msg;
return (int) s3_FAIL;
}
if (((s3_score_df_range[data_type].range[0] != 0) || (data_type == _IMM5_RANGE_8_31))
&& data_type != _IMM5_MULTI_LOAD)
{
value &= (1 << s3_score_df_range[data_type].bits) - 1;
}
s3_inst.instruction |= value << shift;
}
if ((s3_inst.instruction & 0x3e000000) == 0x30000000)
{
if ((((s3_inst.instruction >> 20) & 0x1F) != 0)
&& (((s3_inst.instruction >> 20) & 0x1F) != 1)
&& (((s3_inst.instruction >> 20) & 0x1F) != 2)
&& (((s3_inst.instruction >> 20) & 0x1F) != 0x10))
{
s3_inst.error = _("invalid constant: bit expression not defined");
return (int) s3_FAIL;
}
}
return s3_SUCCESS;
}
/* Handle addi/addi.c/addis.c/cmpi.c/addis.c/ldi. */
static void
s3_do_rdsi16 (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_skip_past_comma (&str) == (int) s3_FAIL
|| s3_data_op2 (&str, 1, _SIMM16) == (int) s3_FAIL
|| s3_end_of_line (str) == (int) s3_FAIL)
return;
/* ldi.->ldiu! only for imm5 */
if ((s3_inst.instruction & 0x20c0000) == 0x20c0000)
{
if ((s3_inst.instruction & 0x1ffc0) != 0)
{
s3_inst.relax_inst = 0x8000;
}
else
{
s3_inst.relax_inst |= (s3_inst.instruction >> 1) & 0x1f;
s3_inst.relax_inst |= (((s3_inst.instruction >> 20)& 0x1f) <<5);
s3_inst.relax_size = 2;
}
}
/*cmpi.c */
else if ((s3_inst.instruction & 0x02040001) == 0x02040001)
{
/* imm <=0x3f (5 bit<<1)*/
if (((s3_inst.instruction & 0x1ffe0) == 0)
|| (((s3_inst.instruction & 0x1ffe0) == 0x1ffe0)
&& (s3_inst.instruction & 0x003e) != 0))
{
s3_inst.relax_inst |= (s3_inst.instruction >> 1) & 0x1f;
s3_inst.relax_inst |= (((s3_inst.instruction >> 20) & 0x1f) << 5);
s3_inst.relax_size = 2;
}
else
{
s3_inst.relax_inst =0x8000;
}
}
/* addi */
else if (((s3_inst.instruction & 0x2000000) == 0x02000000) && (s3_inst.relax_inst!=0x8000))
{
/* rd : 0-16 ; imm <=0x7f (6 bit<<1)*/
if ((((s3_inst.instruction >> 20) & 0x10) != 0x10)
&& (((s3_inst.instruction & 0x1ffc0) == 0)
|| (((s3_inst.instruction & 0x1ffc0) == 0x1ffc0)
&& (s3_inst.instruction & 0x007e) != 0)))
{
s3_inst.relax_inst |= (s3_inst.instruction >> 1) & 0x3f;
s3_inst.relax_inst |= (((s3_inst.instruction >> 20) & 0xf) << 6);
s3_inst.relax_size = 2;
}
else
{
s3_inst.relax_inst =0x8000;
}
}
else if (((s3_inst.instruction >> 20) & 0x10) == 0x10)
{
s3_inst.relax_inst = 0x8000;
}
}
static void
s3_do_ldis (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_skip_past_comma (&str) == (int) s3_FAIL
|| s3_data_op2 (&str, 1, _IMM16) == (int) s3_FAIL
|| s3_end_of_line (str) == (int) s3_FAIL)
return;
}
/* Handle subi/subi.c. */
static void
s3_do_sub_rdsi16 (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) != (int) s3_FAIL
&& s3_skip_past_comma (&str) != (int) s3_FAIL
&& s3_data_op2 (&str, 1, _SIMM16_NEG) != (int) s3_FAIL)
s3_end_of_line (str);
}
/* Handle subis/subis.c. */
static void
s3_do_sub_rdi16 (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) != (int) s3_FAIL
&& s3_skip_past_comma (&str) != (int) s3_FAIL
&& s3_data_op2 (&str, 1, _IMM16_NEG) != (int) s3_FAIL)
s3_end_of_line (str);
}
/* Handle addri/addri.c. */
static void
s3_do_rdrssi14 (char *str) /* -(2^13)~((2^13)-1) */
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) != (int) s3_FAIL
&& s3_skip_past_comma (&str) != (int) s3_FAIL
&& s3_reg_required_here (&str, 15, s3_REG_TYPE_SCORE) != (int) s3_FAIL
&& s3_skip_past_comma (&str) != (int) s3_FAIL)
s3_data_op2 (&str, 1, _SIMM14);
}
/* Handle subri.c/subri. */
static void
s3_do_sub_rdrssi14 (char *str) /* -(2^13)~((2^13)-1) */
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) != (int) s3_FAIL
&& s3_skip_past_comma (&str) != (int) s3_FAIL
&& s3_reg_required_here (&str, 15, s3_REG_TYPE_SCORE) != (int) s3_FAIL
&& s3_skip_past_comma (&str) != (int) s3_FAIL
&& s3_data_op2 (&str, 1, _SIMM14_NEG) != (int) s3_FAIL)
s3_end_of_line (str);
}
/* Handle bitclr.c/bitset.c/bittgl.c/slli.c/srai.c/srli.c/roli.c/rori.c/rolic.c.
0~((2^14)-1) */
static void
s3_do_rdrsi5 (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_skip_past_comma (&str) == (int) s3_FAIL
|| s3_reg_required_here (&str, 15, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_skip_past_comma (&str) == (int) s3_FAIL
|| s3_data_op2 (&str, 10, _IMM5) == (int) s3_FAIL
|| s3_end_of_line (str) == (int) s3_FAIL)
return;
if ((((s3_inst.instruction >> 20) & 0x1f) == ((s3_inst.instruction >> 15) & 0x1f))
&& (s3_inst.relax_inst != 0x8000) && (((s3_inst.instruction >> 15) & 0x10) == 0))
{
s3_inst.relax_inst |= (((s3_inst.instruction >> 10) & 0x1f) ) | (((s3_inst.instruction >> 15) & 0xf) << 5);
s3_inst.relax_size = 2;
}
else
s3_inst.relax_inst = 0x8000;
}
/* Handle andri/orri/andri.c/orri.c.
0 ~ ((2^14)-1) */
static void
s3_do_rdrsi14 (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) != (int) s3_FAIL
&& s3_skip_past_comma (&str) != (int) s3_FAIL
&& s3_reg_required_here (&str, 15, s3_REG_TYPE_SCORE) != (int) s3_FAIL
&& s3_skip_past_comma (&str) != (int) s3_FAIL
&& s3_data_op2 (&str, 1, _IMM14) != (int) s3_FAIL)
s3_end_of_line (str);
}
/* Handle bittst.c. */
static void
s3_do_xrsi5 (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 15, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_skip_past_comma (&str) == (int) s3_FAIL
|| s3_data_op2 (&str, 10, _IMM5) == (int) s3_FAIL
|| s3_end_of_line (str) == (int) s3_FAIL)
return;
if ((s3_inst.relax_inst != 0x8000) && (((s3_inst.instruction >> 15) & 0x10) == 0))
{
s3_inst.relax_inst |= ((s3_inst.instruction >> 10) & 0x1f) | (((s3_inst.instruction >> 15) & 0xf) << 5);
s3_inst.relax_size = 2;
}
else
s3_inst.relax_inst = 0x8000;
}
/* Handle addis/andi/ori/andis/oris/ldis. */
static void
s3_do_rdi16 (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_skip_past_comma (&str) == (int) s3_FAIL
|| s3_data_op2 (&str, 1, _IMM16) == (int) s3_FAIL
|| s3_end_of_line (str) == (int) s3_FAIL)
return;
/* ldis */
if ((s3_inst.instruction & 0x3e0e0000) == 0x0a0c0000)
{
/* rd : 0-16 ;imm =0 -> can transform to addi!*/
if ((((s3_inst.instruction >> 20) & 0x10) != 0x10) && ((s3_inst.instruction & 0x1ffff)==0))
{
s3_inst.relax_inst =0x5400; /* ldiu! */
s3_inst.relax_inst |= (s3_inst.instruction >> 1) & 0x1f;
s3_inst.relax_inst |= (((s3_inst.instruction >> 20) & 0xf) << 5);
s3_inst.relax_size = 2;
}
else
{
s3_inst.relax_inst =0x8000;
}
}
/* addis */
else if ((s3_inst.instruction & 0x3e0e0001) == 0x0a000000)
{
/* rd : 0-16 ;imm =0 -> can transform to addi!*/
if ((((s3_inst.instruction >> 20) & 0x10) != 0x10) && ((s3_inst.instruction & 0x1ffff)==0))
{
s3_inst.relax_inst =0x5c00; /* addi! */
s3_inst.relax_inst |= (s3_inst.instruction >> 1) & 0x3f;
s3_inst.relax_inst |= (((s3_inst.instruction >> 20) & 0xf) << 6);
s3_inst.relax_size = 2;
}
else
{
s3_inst.relax_inst =0x8000;
}
}
}
static void
s3_do_macro_rdi32hi (char *str)
{
s3_skip_whitespace (str);
/* Do not handle s3_end_of_line(). */
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) != (int) s3_FAIL
&& s3_skip_past_comma (&str) != (int) s3_FAIL)
s3_data_op2 (&str, 1, _VALUE_HI16);
}
static void
s3_do_macro_rdi32lo (char *str)
{
s3_skip_whitespace (str);
/* Do not handle s3_end_of_line(). */
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) != (int) s3_FAIL
&& s3_skip_past_comma (&str) != (int) s3_FAIL)
s3_data_op2 (&str, 1, _VALUE_LO16);
}
/* Handle ldis_pic. */
static void
s3_do_rdi16_pic (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) != (int) s3_FAIL
&& s3_skip_past_comma (&str) != (int) s3_FAIL
&& s3_data_op2 (&str, 1, _IMM16_pic) != (int) s3_FAIL)
s3_end_of_line (str);
}
/* Handle addi_s_pic to generate R_SCORE_GOT_LO16 . */
static void
s3_do_addi_s_pic (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) != (int) s3_FAIL
&& s3_skip_past_comma (&str) != (int) s3_FAIL
&& s3_data_op2 (&str, 1, _SIMM16_pic) != (int) s3_FAIL)
s3_end_of_line (str);
}
/* Handle addi_u_pic to generate R_SCORE_GOT_LO16 . */
static void
s3_do_addi_u_pic (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) != (int) s3_FAIL
&& s3_skip_past_comma (&str) != (int) s3_FAIL
&& s3_data_op2 (&str, 1, _IMM16_LO16_pic) != (int) s3_FAIL)
s3_end_of_line (str);
}
/* Handle mfceh/mfcel/mtceh/mtchl. */
static void
s3_do_rd (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) != (int) s3_FAIL)
s3_end_of_line (str);
}
/* Handle br{cond},cmpzteq.c ,cmpztmi.c ,cmpz.c */
static void
s3_do_rs (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 15, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_end_of_line (str) == (int) s3_FAIL)
return;
if ((s3_inst.relax_inst != 0x8000) )
{
s3_inst.relax_inst |= ((s3_inst.instruction >> 15) &0x1f);
s3_inst.relax_size = 2;
}
else
s3_inst.relax_inst = 0x8000;
}
static void
s3_do_i15 (char *str)
{
s3_skip_whitespace (str);
if (s3_data_op2 (&str, 10, _IMM15) != (int) s3_FAIL)
s3_end_of_line (str);
}
static void
s3_do_xi5x (char *str)
{
s3_skip_whitespace (str);
if (s3_data_op2 (&str, 15, _IMM5) == (int) s3_FAIL || s3_end_of_line (str) == (int) s3_FAIL)
return;
if (s3_inst.relax_inst != 0x8000)
{
s3_inst.relax_inst |= ((s3_inst.instruction >> 15) & 0x1f);
s3_inst.relax_size = 2;
}
}
static void
s3_do_rdrs (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_skip_past_comma (&str) == (int) s3_FAIL
|| s3_reg_required_here (&str, 15, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_end_of_line (str) == (int) s3_FAIL)
return;
if (s3_inst.relax_inst != 0x8000)
{
if (((s3_inst.instruction & 0x7f) == 0x56)) /* adjust mv -> mv!*/
{
/* mv! rd : 5bit , ra : 5bit */
s3_inst.relax_inst |= ((s3_inst.instruction >> 15) & 0x1f) | (((s3_inst.instruction >> 20) & 0x1f) << 5);
s3_inst.relax_size = 2;
}
else if ((((s3_inst.instruction >> 15) & 0x10) == 0x0) && (((s3_inst.instruction >> 20) & 0x10) == 0))
{
s3_inst.relax_inst |= (((s3_inst.instruction >> 15) & 0xf) << 4)
| (((s3_inst.instruction >> 20) & 0xf) << 8);
s3_inst.relax_size = 2;
}
else
{
s3_inst.relax_inst = 0x8000;
}
}
}
/* Handle mfcr/mtcr. */
static void
s3_do_rdcrs (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) != (int) s3_FAIL
&& s3_skip_past_comma (&str) != (int) s3_FAIL
&& s3_reg_required_here (&str, 15, s3_REG_TYPE_SCORE_CR) != (int) s3_FAIL)
s3_end_of_line (str);
}
/* Handle mfsr/mtsr. */
static void
s3_do_rdsrs (char *str)
{
s3_skip_whitespace (str);
/* mfsr */
if ((s3_inst.instruction & 0xff) == 0x50)
{
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) != (int) s3_FAIL
&& s3_skip_past_comma (&str) != (int) s3_FAIL
&& s3_reg_required_here (&str, 10, s3_REG_TYPE_SCORE_SR) != (int) s3_FAIL)
s3_end_of_line (str);
}
else
{
if (s3_reg_required_here (&str, 15, s3_REG_TYPE_SCORE) != (int) s3_FAIL
&& s3_skip_past_comma (&str) != (int) s3_FAIL)
s3_reg_required_here (&str, 10, s3_REG_TYPE_SCORE_SR);
}
}
/* Handle neg. */
static void
s3_do_rdxrs (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_skip_past_comma (&str) == (int) s3_FAIL
|| s3_reg_required_here (&str, 10, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_end_of_line (str) == (int) s3_FAIL)
return;
if ((s3_inst.relax_inst != 0x8000) && (((s3_inst.instruction >> 10) & 0x10) == 0)
&& (((s3_inst.instruction >> 20) & 0x10) == 0))
{
s3_inst.relax_inst |= (((s3_inst.instruction >> 10) & 0xf) << 4) | (((s3_inst.instruction >> 20) & 0xf) << 8);
s3_inst.relax_size = 2;
}
else
s3_inst.relax_inst = 0x8000;
}
/* Handle cmp.c/cmp<cond>. */
static void
s3_do_rsrs (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 15, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_skip_past_comma (&str) == (int) s3_FAIL
|| s3_reg_required_here (&str, 10, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_end_of_line (str) == (int) s3_FAIL)
return;
if ((s3_inst.relax_inst != 0x8000) && (((s3_inst.instruction >> 20) & 0x1f) == 3) )
{
s3_inst.relax_inst |= (((s3_inst.instruction >> 10) & 0x1f)) | (((s3_inst.instruction >> 15) & 0x1f) << 5);
s3_inst.relax_size = 2;
}
else
s3_inst.relax_inst = 0x8000;
}
static void
s3_do_ceinst (char *str)
{
char *strbak;
strbak = str;
s3_skip_whitespace (str);
if (s3_data_op2 (&str, 20, _IMM5) == (int) s3_FAIL
|| s3_skip_past_comma (&str) == (int) s3_FAIL
|| s3_reg_required_here (&str, 15, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_skip_past_comma (&str) == (int) s3_FAIL
|| s3_reg_required_here (&str, 10, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_skip_past_comma (&str) == (int) s3_FAIL
|| s3_data_op2 (&str, 5, _IMM5) == (int) s3_FAIL
|| s3_skip_past_comma (&str) == (int) s3_FAIL
|| s3_data_op2 (&str, 0, _IMM5) == (int) s3_FAIL
|| s3_end_of_line (str) == (int) s3_FAIL)
{
return;
}
else
{
str = strbak;
if (s3_data_op2 (&str, 0, _IMM25) == (int) s3_FAIL)
return;
}
}
static int
s3_reglow_required_here (char **str, int shift)
{
static char buff[s3_MAX_LITERAL_POOL_SIZE];
int reg;
char *start = *str;
if ((reg = s3_score_reg_parse (str, s3_all_reg_maps[s3_REG_TYPE_SCORE].htab)) != (int) s3_FAIL)
{
if ((reg == 1) && (s3_nor1 == 1) && (s3_inst.bwarn == 0))
{
as_warn (_("Using temp register(r1)"));
s3_inst.bwarn = 1;
}
if (reg < 16)
{
if (shift >= 0)
s3_inst.instruction |= (bfd_vma) reg << shift;
return reg;
}
}
/* Restore the start point, we may have got a reg of the wrong class. */
*str = start;
sprintf (buff, _("low register (r0-r15) expected, not '%.100s'"), start);
s3_inst.error = buff;
return (int) s3_FAIL;
}
/* Handle add!/and!/or!/sub!. */
static void
s3_do16_rdrs2 (char *str)
{
s3_skip_whitespace (str);
if (s3_reglow_required_here (&str, 4) == (int) s3_FAIL
|| s3_skip_past_comma (&str) == (int) s3_FAIL
|| s3_reglow_required_here (&str, 0) == (int) s3_FAIL
|| s3_end_of_line (str) == (int) s3_FAIL)
{
return;
}
}
/* Handle br!/brl!. */
static void
s3_do16_br (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 0, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_end_of_line (str) == (int) s3_FAIL)
{
return;
}
}
/* Handle brr!. */
static void
s3_do16_brr (char *str)
{
int rd = 0;
s3_skip_whitespace (str);
if ((rd = s3_reg_required_here (&str, 0,s3_REG_TYPE_SCORE)) == (int) s3_FAIL
|| s3_end_of_line (str) == (int) s3_FAIL)
{
return;
}
}
/*Handle ltbw / ltbh / ltbb */
static void
s3_do_ltb (char *str)
{
s3_skip_whitespace (str);
if (s3_reg_required_here (&str, 20, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_skip_past_comma (&str) == (int) s3_FAIL)
{
return;
}
s3_skip_whitespace (str);
if (*str++ != '[')
{
s3_inst.error = _("missing [");
return;
}
if (s3_reg_required_here (&str, 15, s3_REG_TYPE_SCORE) == (int) s3_FAIL
|| s3_skip_past_comma (&str) == (int) s3_FAIL
|| s3_reg_required_here (&str, 10, s3_REG_TYPE_SCORE) == (int) s3_FAIL)
{
return;
}
s3_skip_whitespace (str);
if (*str++ != ']')
{
s3_inst.error = _("missing ]");
return;
}
}
/* We need to be able to fix up arbitrary expressions in some statements.
This is so that we can handle symbols that are an arbitrary distance from
the pc. The most common cases are of the form ((+/-sym -/+ . - 8) & mask),
which returns part of an address in a form which will be valid for
a data instruction. We do this by pushing the expression into a symbol
in the expr_section, and creating a fix for that. */
static fixS *
s3_fix_new_score (fragS * frag, int where, short int size, expressionS * exp, int pc_rel, int reloc)
{
fixS *new_fix;
switch (exp->X_op)
{
case O_constant:
case O_symbol:
case O_add:
case O_subtract:
new_fix = fix_new_exp (frag, where, size, exp, pc_rel, reloc);
break;
default:
new_fix = fix_new (frag, where, size, make_expr_symbol (exp), 0, pc_rel, reloc);
break;
}
return new_fix;
}
static void
s3_init_dependency_vector (void)
{
int i;
for (i = 0; i < s3_vector_size; i++)
memset (&s3_dependency_vector[i], '\0', sizeof (s3_dependency_vector[i]));
return;
}
static enum s3_insn_type_for_dependency
s3_dependency_type_from_insn (char *insn_name)
{
char name[s3_INSN_NAME_LEN];
const struct s3_insn_to_dependency *tmp;
strcpy (name, insn_name);
tmp = (const struct s3_insn_to_dependency *)
str_hash_find (s3_dependency_insn_hsh, name);
if (tmp)
return tmp->type;
return s3_D_all_insn;
}
static int
s3_check_dependency (char *pre_insn, char *pre_reg,
char *cur_insn, char *cur_reg, int *warn_or_error)
{
int bubbles = 0;
unsigned int i;
enum s3_insn_type_for_dependency pre_insn_type;
enum s3_insn_type_for_dependency cur_insn_type;
pre_insn_type = s3_dependency_type_from_insn (pre_insn);
cur_insn_type = s3_dependency_type_from_insn (cur_insn);
for (i = 0; i < sizeof (s3_data_dependency_table) / sizeof (s3_data_dependency_table[0]); i++)
{
if ((pre_insn_type == s3_data_dependency_table[i].pre_insn_type)
&& (s3_D_all_insn == s3_data_dependency_table[i].cur_insn_type
|| cur_insn_type == s3_data_dependency_table[i].cur_insn_type)
&& (strcmp (s3_data_dependency_table[i].pre_reg, "") == 0
|| strcmp (s3_data_dependency_table[i].pre_reg, pre_reg) == 0)
&& (strcmp (s3_data_dependency_table[i].cur_reg, "") == 0
|| strcmp (s3_data_dependency_table[i].cur_reg, cur_reg) == 0))
{
bubbles = s3_data_dependency_table[i].bubblenum_3;
*warn_or_error = s3_data_dependency_table[i].warn_or_error;
break;
}
}
return bubbles;
}
static void
s3_build_one_frag (struct s3_score_it one_inst)
{
char *p;
int relaxable_p = s3_g_opt;
int relax_size = 0;
/* Start a new frag if frag_now is not empty. */
if (frag_now_fix () != 0)
{
if (!frag_now->tc_frag_data.is_insn)
frag_wane (frag_now);
frag_new (0);
}
frag_grow (20);
p = frag_more (one_inst.size);
s3_md_number_to_chars (p, one_inst.instruction, one_inst.size);
#ifdef OBJ_ELF
dwarf2_emit_insn (one_inst.size);
#endif
relaxable_p &= (one_inst.relax_size != 0);
relax_size = relaxable_p ? one_inst.relax_size : 0;
p = frag_var (rs_machine_dependent, relax_size + s3_RELAX_PAD_BYTE, 0,
s3_RELAX_ENCODE (one_inst.size, one_inst.relax_size,
one_inst.type, 0, 0, relaxable_p),
NULL, 0, NULL);
if (relaxable_p)
s3_md_number_to_chars (p, one_inst.relax_inst, relax_size);
}
static void
s3_handle_dependency (struct s3_score_it *theinst)
{
int i;
int warn_or_error = 0; /* warn - 0; error - 1 */
int bubbles = 0;
int remainder_bubbles = 0;
char cur_insn[s3_INSN_NAME_LEN];
char pre_insn[s3_INSN_NAME_LEN];
struct s3_score_it nop_inst;
struct s3_score_it pflush_inst;
nop_inst.instruction = 0x0000;
nop_inst.size = 2;
nop_inst.relax_inst = 0x80008000;
nop_inst.relax_size = 4;
nop_inst.type = NO16_OPD;
pflush_inst.instruction = 0x8000800a;
pflush_inst.size = 4;
pflush_inst.relax_inst = 0x8000;
pflush_inst.relax_size = 0;
pflush_inst.type = NO_OPD;
/* pflush will clear all data dependency. */
if (strcmp (theinst->name, "pflush") == 0)
{
s3_init_dependency_vector ();
return;
}
/* Push current instruction to s3_dependency_vector[0]. */
for (i = s3_vector_size - 1; i > 0; i--)
memcpy (&s3_dependency_vector[i], &s3_dependency_vector[i - 1], sizeof (s3_dependency_vector[i]));
memcpy (&s3_dependency_vector[0], theinst, sizeof (s3_dependency_vector[i]));
/* There is no dependency between nop and any instruction. */
if (strcmp (s3_dependency_vector[0].name, "nop") == 0
|| strcmp (s3_dependency_vector[0].name, "nop!") == 0)
return;
strcpy (cur_insn, s3_dependency_vector[0].name);
for (i = 1; i < s3_vector_size; i++)
{
/* The element of s3_dependency_vector is NULL. */
if (s3_dependency_vector[i].name[0] == '\0')
continue;
strcpy (pre_insn, s3_dependency_vector[i].name);
bubbles = s3_check_dependency (pre_insn, s3_dependency_vector[i].reg,
cur_insn, s3_dependency_vector[0].reg, &warn_or_error);
remainder_bubbles = bubbles - i + 1;
if (remainder_bubbles > 0)
{
int j;
if (s3_fix_data_dependency == 1)
{
if (remainder_bubbles <= 2)
{
if (s3_warn_fix_data_dependency)
as_warn (_("Fix data dependency: %s %s -- %s %s (insert %d nop!/%d)"),
s3_dependency_vector[i].name, s3_dependency_vector[i].reg,
s3_dependency_vector[0].name, s3_dependency_vector[0].reg,
remainder_bubbles, bubbles);