/* tc-crx.c -- Assembler code for the CRX CPU core.
- Copyright 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004-2020 Free Software Foundation, Inc.
Contributed by Tomer Levi, NSC, Israel.
Originally written for GAS 2.12 by Tomer Levi, NSC, Israel.
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 2, or (at your option)
+ 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,
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, 59 Temple Place - Suite 330, Boston,
- MA 02111-1307, USA. */
+ Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
#include "as.h"
+#include "bfd_stdint.h"
#include "safe-ctype.h"
#include "dwarf2dbg.h"
#include "opcode/crx.h"
#include "elf/crx.h"
-#include <limits.h>
-
/* Word is considered here as a 16-bit unsigned short int. */
-#define WORD_SIZE 16
#define WORD_SHIFT 16
/* Register is 4-bit size. */
/* Maximum bits which may be set in a `mask16' operand. */
#define MAX_REGS_IN_MASK16 8
-/* Escape to 16-bit immediate. */
-#define ESC_16 0xE
-/* Escape to 32-bit immediate. */
-#define ESC_32 0xF
-
/* Utility macros for string comparison. */
#define streq(a, b) (strcmp (a, b) == 0)
#define strneq(a, b, c) (strncmp (a, b, c) == 0)
-/* A mask to set n_bits starting from offset offs. */
-#define SET_BITS_MASK(offs,n_bits) ((((1 << (n_bits)) - 1) << (offs)))
-/* A mask to clear n_bits starting from offset offs. */
-#define CLEAR_BITS_MASK(offs,n_bits) (~(((1 << (n_bits)) - 1) << (offs)))
-
-/* Get the argument type for each operand of a given instruction. */
-#define GET_ACTUAL_TYPE \
- for (i = 0; i < insn->nargs; i++) \
- atyp_act[i] = getarg_type (instruction->operands[i].op_type)
-
-/* Get the size (in bits) for each operand of a given instruction. */
-#define GET_ACTUAL_SIZE \
- for (i = 0; i < insn->nargs; i++) \
- bits_act[i] = getbits (instruction->operands[i].op_type)
-
-/* Non-zero if OP is instruction with no operands. */
-#define NO_OPERANDS_INST(OP) \
- (streq (OP, "di") || streq (OP, "nop") \
- || streq (OP, "retx") || streq (OP, "ei") \
- || streq (OP, "wait") || streq (OP, "eiwait"))
-
-/* Print a number NUM, shifted by SHIFT bytes, into a location
+/* Assign a number NUM, shifted by SHIFT bytes, into a location
pointed by index BYTE of array 'output_opcode'. */
#define CRX_PRINT(BYTE, NUM, SHIFT) output_opcode[BYTE] |= (NUM << SHIFT)
+/* Operand errors. */
+typedef enum
+ {
+ OP_LEGAL = 0, /* Legal operand. */
+ OP_OUT_OF_RANGE, /* Operand not within permitted range. */
+ OP_NOT_EVEN, /* Operand is Odd number, should be even. */
+ OP_ILLEGAL_DISPU4, /* Operand is not within DISPU4 range. */
+ OP_ILLEGAL_CST4, /* Operand is not within CST4 range. */
+ OP_NOT_UPPER_64KB /* Operand is not within the upper 64KB
+ (0xFFFF0000-0xFFFFFFFF). */
+ }
+op_err;
+
/* Opcode mnemonics hash table. */
static struct hash_control *crx_inst_hash;
/* CRX registers hash table. */
/* CRX coprocessor registers hash table. */
static struct hash_control *copreg_hash;
/* Current instruction we're assembling. */
-const inst *instruction;
+static const inst *instruction;
+
+/* Global variables. */
+
+/* Array to hold an instruction encoding. */
+static long output_opcode[2];
-/* Initialize global variables. */
-long output_opcode[2];
/* Nonzero means a relocatable symbol. */
-int relocatable;
-/* Nonzero means a constant's bit-size was already set. */
-int size_was_set;
-/* Nonzero means a negative constant. */
-int signflag;
-/* Nonzero means a CST4 instruction. */
-int cst4flag;
+static int relocatable;
+
/* A copy of the original instruction (used in error messages). */
-char ins_parse[MAX_INST_LEN];
-/* Nonzero means instruction is represented in post increment mode. */
-int post_inc_mode;
-/* Holds the current processed argument number. */
-int processing_arg_number;
+static char ins_parse[MAX_INST_LEN];
+
+/* The current processed argument number. */
+static int cur_arg_num;
/* Generic assembler global variables which must be defined by all targets. */
{0, 0, 0}
};
+/* CRX relaxation table. */
const relax_typeS md_relax_table[] =
{
/* bCC */
{0xfffe, -0x10000, 4, 4}, /* 16 */
{0xfffffffe, -0xfffffffe, 6, 0}, /* 32 */
- /* cmpbr */
+ /* cmpbr/bcop */
{0xfe, -0x100, 4, 6}, /* 8 */
{0xfffffe, -0x1000000, 6, 0} /* 24 */
};
-static void reset_vars (char *, ins *);
+static void reset_vars (char *);
static reg get_register (char *);
static copreg get_copregister (char *);
-static void get_number_of_bits (ins *, int);
-static argtype getarg_type (operand_type);
-static int getbits (operand_type);
+static argtype get_optype (operand_type);
+static int get_opbits (operand_type);
+static int get_opflags (operand_type);
static int get_number_of_operands (void);
-static void get_operandtype (char *, int, ins *);
-static int gettrap (char *);
-static void handle_LoadStor (char *);
-static int get_cinv_parameters (char *);
-static unsigned long getconstant (unsigned long, int);
-static int getreg_image (reg);
+static void parse_operand (char *, ins *);
+static int gettrap (const char *);
+static void handle_LoadStor (const char *);
+static int get_cinv_parameters (const char *);
+static long getconstant (long, int);
+static op_err check_range (long *, int, unsigned int, int);
+static int getreg_image (int);
static void parse_operands (ins *, char *);
static void parse_insn (ins *, char *);
static void print_operand (int, int, argument *);
static void print_constant (int, int, argument *);
static int exponent2scale (int);
-static void mask_const (unsigned long *, int);
static void mask_reg (int, unsigned short *);
-static int process_label_constant (char *, ins *, int);
-static void set_indexmode_parameters (char *, ins *, int);
-static void set_cons_rparams (char *, ins *, int);
+static void process_label_constant (char *, ins *);
+static void set_operand (char *, ins *);
static char * preprocess_reglist (char *, int *);
static int assemble_insn (char *, ins *);
static void print_insn (ins *);
+static void warn_if_needed (ins *);
+static int adjust_if_needed (ins *);
/* Return the bit size for a given operand. */
static int
-getbits (operand_type op)
+get_opbits (operand_type op)
{
if (op < MAX_OPRD)
return crx_optab[op].bit_size;
/* Return the argument type of a given operand. */
static argtype
-getarg_type (operand_type op)
+get_optype (operand_type op)
{
if (op < MAX_OPRD)
return crx_optab[op].arg_type;
return nullargs;
}
+/* Return the flags of a given operand. */
+
+static int
+get_opflags (operand_type op)
+{
+ if (op < MAX_OPRD)
+ return crx_optab[op].flags;
+ else
+ return 0;
+}
+
/* Get the core processor register 'reg_name'. */
static reg
get_register (char *reg_name)
{
- const reg_entry *reg;
+ const reg_entry *rreg;
- reg = (const reg_entry *) hash_find (reg_hash, reg_name);
+ rreg = (const reg_entry *) hash_find (reg_hash, reg_name);
- if (reg != NULL)
- return reg->value.reg_val;
+ if (rreg != NULL)
+ return rreg->value.reg_val;
else
return nullregister;
}
static copreg
get_copregister (char *copreg_name)
{
- const reg_entry *copreg;
+ const reg_entry *coreg;
- copreg = (const reg_entry *) hash_find (copreg_hash, copreg_name);
+ coreg = (const reg_entry *) hash_find (copreg_hash, copreg_name);
- if (copreg != NULL)
- return copreg->value.copreg_val;
+ if (coreg != NULL)
+ return coreg->value.copreg_val;
else
return nullcopregister;
}
-/* Mask a constant to the number of bits it is to be mapped to. */
-
-static void
-mask_const (unsigned long int *t, int size)
-{
- *t &= (((LONGLONG)1 << size) - 1);
-}
-
/* Round up a section size to the appropriate boundary. */
valueT
/* Reset global variables before parsing a new instruction. */
static void
-reset_vars (char *op, ins *crx_ins)
+reset_vars (char *op)
{
- unsigned int i;
-
- processing_arg_number = relocatable = size_was_set
- = signflag = post_inc_mode = cst4flag = 0;
+ cur_arg_num = relocatable = 0;
memset (& output_opcode, '\0', sizeof (output_opcode));
- /* Memset the 'signflag' field in every argument. */
- for (i = 0; i < MAX_OPERANDS; i++)
- crx_ins->arg[i].signflag = 0;
-
/* Save a copy of the original OP (used in error messages). */
- strcpy (ins_parse, op);
+ strncpy (ins_parse, op, sizeof ins_parse - 1);
+ ins_parse [sizeof ins_parse - 1] = 0;
}
/* This macro decides whether a particular reloc is an entry in a
{
arelent * reloc;
- reloc = xmalloc (sizeof (arelent));
- reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+ reloc = XNEW (arelent);
+ reloc->sym_ptr_ptr = XNEW (asymbol *);
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
reloc->addend = fixP->fx_offset;
}
}
- assert ((int) fixP->fx_r_type > 0);
+ gas_assert ((int) fixP->fx_r_type > 0);
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
if (reloc->howto == (reloc_howto_type *) NULL)
bfd_get_reloc_code_name (fixP->fx_r_type));
return NULL;
}
- assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
+ gas_assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
return reloc;
}
{
/* 'opcode' points to the start of the instruction, whether
we need to change the instruction's fixed encoding. */
- char *opcode = fragP->fr_literal + fragP->fr_fix;
+ char *opcode = &fragP->fr_literal[0] + fragP->fr_fix;
bfd_reloc_code_real_type reloc;
subseg_change (sec, 0);
GAS does not understand. */
int
-md_parse_option (int c ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED)
+md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED)
{
return 0;
}
return;
}
-/* Turn a string in input_line_pointer into a floating point constant
- of type TYPE, and store the appropriate bytes in *LITP. The number
- of LITTLENUMS emitted is stored in *SIZEP. An error message is
- returned, or NULL on OK. */
-
-char *
+const char *
md_atof (int type, char *litP, int *sizeP)
{
- int prec;
- LITTLENUM_TYPE words[4];
- char *t;
- int i;
-
- switch (type)
- {
- case 'f':
- prec = 2;
- break;
-
- case 'd':
- 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 * 2;
-
- if (! target_big_endian)
- {
- for (i = prec - 1; i >= 0; i--)
- {
- md_number_to_chars (litP, (valueT) words[i], 2);
- litP += 2;
- }
- }
- else
- {
- for (i = 0; i < prec; i++)
- {
- md_number_to_chars (litP, (valueT) words[i], 2);
- litP += 2;
- }
- }
-
- return NULL;
+ return ieee_md_atof (type, litP, sizeP, target_big_endian);
}
/* Apply a fixS (fixup of an instruction or data that we didn't have
fixuping relocations of debug sections. */
void
-md_apply_fix3 (fixS *fixP, valueT *valP, segT seg)
+md_apply_fix (fixS *fixP, valueT *valP, segT seg)
{
valueT val = * valP;
char *buf = fixP->fx_frag->fr_literal + fixP->fx_where;
int i = 0;
/* Set up a hash table for the instructions. */
- crx_inst_hash = hash_new ();
- if (crx_inst_hash == NULL)
+ if ((crx_inst_hash = hash_new ()) == NULL)
as_fatal (_("Virtual memory exhausted"));
while (crx_instruction[i].mnemonic != NULL)
const char *mnemonic = crx_instruction[i].mnemonic;
hashret = hash_insert (crx_inst_hash, mnemonic,
- (PTR) &crx_instruction[i]);
+ (void *) &crx_instruction[i]);
if (hashret != NULL && *hashret != '\0')
as_fatal (_("Can't hash `%s': %s\n"), crx_instruction[i].mnemonic,
}
/* Initialize reg_hash hash table. */
- reg_hash = hash_new ();
+ if ((reg_hash = hash_new ()) == NULL)
+ as_fatal (_("Virtual memory exhausted"));
{
const reg_entry *regtab;
for (regtab = crx_regtab;
regtab < (crx_regtab + NUMREGS); regtab++)
{
- hashret = hash_insert (reg_hash, regtab->name, (PTR) regtab);
+ hashret = hash_insert (reg_hash, regtab->name, (void *) regtab);
if (hashret)
- as_fatal (_("Internal Error: Can't hash %s: %s"),
+ as_fatal (_("Internal error: Can't hash %s: %s"),
regtab->name,
hashret);
}
}
/* Initialize copreg_hash hash table. */
- copreg_hash = hash_new ();
+ if ((copreg_hash = hash_new ()) == NULL)
+ as_fatal (_("Virtual memory exhausted"));
{
const reg_entry *copregtab;
for (copregtab = crx_copregtab; copregtab < (crx_copregtab + NUMCOPREGS);
copregtab++)
{
- hashret = hash_insert (copreg_hash, copregtab->name, (PTR) copregtab);
+ hashret = hash_insert (copreg_hash, copregtab->name,
+ (void *) copregtab);
if (hashret)
- as_fatal (_("Internal Error: Can't hash %s: %s"),
+ as_fatal (_("Internal error: Can't hash %s: %s"),
copregtab->name,
hashret);
}
linkrelax = 1;
}
-/* Get the number of bits corresponding to a constant -
- here we check for possible overflow cases. */
+/* Process constants (immediate/absolute)
+ and labels (jump targets/Memory locations). */
static void
-get_number_of_bits (ins * crx_ins, int op_num)
+process_label_constant (char *str, ins * crx_ins)
{
- int cnt_bits = 0;
- unsigned long int temp = crx_ins->arg[op_num].constant;
- const cst4_entry *cst4_op;
-
- /* If the constant's size was already set - nothing to do. */
- if (size_was_set)
- return;
-
- /* Already dealt with negative numbers in process_label_constants. */
- while (temp > 0)
- {
- temp >>= 1;
- cnt_bits++;
- }
-
- if (IS_INSN_TYPE (ARITH_INS) && !relocatable && !signflag)
- {
- if (cnt_bits == 16)
- {
- crx_ins->arg[op_num].size = 17;
- return;
- }
- }
- /* If a signed +ve is represented in 6 bits then we have to represent
- it in 22 bits in case of the index mode of addressing. */
- if (IS_INSN_TYPE (LD_STOR_INS)
- || IS_INSN_TYPE (LD_STOR_INS_INC)
- || IS_INSN_TYPE (STOR_IMM_INS)
- || IS_INSN_TYPE (CSTBIT_INS))
- {
- if (!signflag && crx_ins->arg[op_num].type == arg_icr)
- {
- if (cnt_bits == 6)
- {
- crx_ins->arg[op_num].size = 7;
- return;
- }
- if (cnt_bits == 22)
- as_bad (_("Offset out of range in Instruction `%s'"), ins_parse);
- }
- }
- /* If a signed +ve is represnted in 16 bits in case of load/stor disp16
- then change it to 17 bits.
- If a signed +ve is represnted in 12 bits in post increment instruction
- increase it to 13 bits. */
- if (IS_INSN_TYPE (LD_STOR_INS))
- {
- if (!signflag && crx_ins->arg[op_num].type == arg_cr)
- {
- if (cnt_bits == 16)
- {
- crx_ins->arg[op_num].size = 17;
- return;
- }
- if (cnt_bits == 32)
- as_bad (_("Offset out of range in Instruction `%s'"), ins_parse);
- }
- }
-
- if (IS_INSN_TYPE (CSTBIT_INS)
- || IS_INSN_TYPE (LD_STOR_INS_INC)
- || IS_INSN_TYPE (STOR_IMM_INS))
- {
- if (!signflag && crx_ins->arg[op_num].type == arg_cr)
- {
- if (cnt_bits == 12)
- {
- crx_ins->arg[op_num].size = 13;
- if (IS_INSN_TYPE (LD_STOR_INS_INC))
- as_bad (_("Offset out of range in Instruction `%s'"), ins_parse);
- return;
- }
- if (IS_INSN_TYPE (CSTBIT_INS) || IS_INSN_TYPE (STOR_IMM_INS))
- {
- if (cnt_bits == 28)
- as_bad (_("Offset out of range in Instruction `%s'"), ins_parse);
- }
-
- }
- }
-
- /* Handle negative cst4 mapping for arithmetic/cmp&br operations. */
- if (signflag && !relocatable
- && ((IS_INSN_TYPE (ARITH_INS) || IS_INSN_TYPE (ARITH_BYTE_INS))
- || ((IS_INSN_TYPE (CMPBR_INS) && op_num == 0))))
- {
- for (cst4_op = cst4_map; cst4_op < (cst4_map + cst4_maps); cst4_op++)
- {
- if (crx_ins->arg[op_num].constant == (unsigned int)(-cst4_op->value))
- {
- crx_ins->arg[op_num].size = 4;
- crx_ins->arg[op_num].constant = cst4_op->binary;
- crx_ins->arg[op_num].signflag = 0;
- return;
- }
- }
- }
- /* Because of the cst4 mapping -- -1 and -4 already handled above
- as well as for relocatable cases. */
- if (signflag && IS_INSN_TYPE (ARITH_BYTE_INS))
- {
- if (!relocatable)
- {
- if (crx_ins->arg[op_num].constant <= 0xffff)
- crx_ins->arg[op_num].size = 16;
- else
- /* Setting to 18 so that there is no match. */
- crx_ins->arg[op_num].size = 18;
- }
- else
- crx_ins->arg[op_num].size = 16;
- return;
- }
-
- if (signflag && IS_INSN_TYPE (ARITH_INS))
- {
- /* For all immediates which can be expressed in less than 16 bits. */
- if (crx_ins->arg[op_num].constant <= 0xffff && !relocatable)
- {
- crx_ins->arg[op_num].size = 16;
- return;
- }
- /* Either it is relocatable or not representable in 16 bits. */
- if (crx_ins->arg[op_num].constant < 0xffffffff || relocatable)
- {
- crx_ins->arg[op_num].size = 32;
- return;
- }
- crx_ins->arg[op_num].size = 33;
- return;
- }
- if (signflag && !relocatable)
- return;
-
- if (!relocatable)
- crx_ins->arg[op_num].size = cnt_bits;
-
- /* Checking for Error Conditions. */
- if (IS_INSN_TYPE (ARITH_INS) && !signflag)
- {
- if (cnt_bits > 32)
- as_bad (_("Cannot represent Immediate in %d bits in Instruction `%s'"),
- cnt_bits, ins_parse);
- }
- else if (IS_INSN_TYPE (ARITH_BYTE_INS) && !signflag)
- {
- if (cnt_bits > 16)
- as_bad (_("Cannot represent Immediate in %d bits in Instruction `%s'"),
- cnt_bits, ins_parse);
- }
-}
-
-/* Handle the constants -immediate/absolute values and
- Labels (jump targets/Memory locations). */
-
-static int
-process_label_constant (char *str, ins * crx_ins, int number)
-{
- char *save;
- unsigned long int temp, cnt;
- const cst4_entry *cst4_op;
- int is_cst4=0;
- int constant_val = 0;
- int cmp_br_type_flag = 0, i;
- int br_type_flag = 0;
- save = input_line_pointer;
- signflag = 0;
-
- if (str[0] == '-')
- {
- signflag = 1;
- str++;
- }
- else if (str[0] == '+')
- str++;
-
- /* Preprocessing for cmpbr instruction and getting the size flag. */
- if (strstr (str, ":s") != NULL && (IS_INSN_TYPE (CMPBR_INS)
- || IS_INSN_TYPE (COP_BRANCH_INS)))
- cmp_br_type_flag = 8;
+ char *saved_input_line_pointer;
+ argument *cur_arg = &crx_ins->arg[cur_arg_num]; /* Current argument. */
- if (strstr (str, ":l") != NULL && (IS_INSN_TYPE (CMPBR_INS)
- || IS_INSN_TYPE (COP_BRANCH_INS)))
- cmp_br_type_flag = 24;
-
- /* Branch instruction preprocessing. */
- if (IS_INSN_TYPE (BRANCH_INS))
- {
- if (strstr (str, ":s") != NULL)
- br_type_flag = 8;
- else if (strstr (str, ":m") != NULL)
- br_type_flag = 16;
- else if (strstr (str, ":l") != NULL)
- br_type_flag = 32;
- }
- /* Making the label cleared for processing removing :lms etc from labels. */
- if (cmp_br_type_flag != 0 || br_type_flag != 0)
- {
- i = 0;
- while (str[i] != ':')
- {
- i++;
- }
- str[i] = '\0';
- }
+ saved_input_line_pointer = input_line_pointer;
input_line_pointer = str;
expression (&crx_ins->exp);
crx_ins->exp.X_add_number = 0;
crx_ins->exp.X_add_symbol = (symbolS *) 0;
crx_ins->exp.X_op_symbol = (symbolS *) 0;
- break;
+ /* Fall through. */
case O_constant:
- crx_ins->arg[number].constant = crx_ins->exp.X_add_number;
- constant_val = crx_ins->exp.X_add_number;
- if ((IS_INSN_TYPE (CMPBR_INS) || IS_INSN_TYPE (COP_BRANCH_INS))
- && number == 2)
- {
- LONGLONG temp64 = 0;
- char ptr;
- char temp_str[30];
- unsigned int jump_value = 0;
- int BR_MASK = 0, BR_SIZE = 0;
- temp_str[0] = '\0';
- if (signflag)
- {
- temp_str[0] = '-';
- temp_str[1] = '\0';
- }
- strncat (temp_str, str, strlen (str));
- temp64 = strtoll (temp_str, (char **) &ptr,0);
-
- if (temp64 % 2 != 0)
- as_bad (_("Odd Offset in displacement in Instruction `%s'"),
- ins_parse);
-
- /* Determine the branch size. */
- jump_value = (unsigned int)temp64 & 0xFFFFFFFF;
- if (((jump_value & 0xFFFFFF00) == 0xFFFFFF00)
- || ((jump_value & 0xFFFFFF00) == 0x0))
- {
- BR_MASK = 0xFF;
- BR_SIZE = 8;
- }
- else
- if (((jump_value & 0xFF000000) == 0xFF000000)
- || ((jump_value & 0xFF000000) == 0x0))
- {
- BR_MASK = 0xFFFFFF;
- BR_SIZE = 24;
- }
- jump_value = jump_value >> 1;
- crx_ins->arg[number].constant = jump_value & BR_MASK;
- crx_ins->arg[number].size = BR_SIZE;
- size_was_set = 1;
- crx_ins->arg[number].signflag = signflag;
- input_line_pointer = save;
- return crx_ins->exp.X_op;
- }
-
- if (IS_INSN_TYPE (BRANCH_INS)
- || IS_INSN_MNEMONIC ("bal")
- || IS_INSN_TYPE (DCR_BRANCH_INS))
- {
- LONGLONG temp64 = 0;
- char ptr;
- char temp_str[30];
- unsigned int jump_value = 0;
- int BR_MASK = 0, BR_SIZE = 0;
-
- temp_str[0] = '\0';
- if (signflag)
- {
- temp_str[0] = '-';
- temp_str[1] = '\0';
- }
- strncat (temp_str, str, strlen (str));
- temp64 = strtoll (temp_str, (char **) &ptr,0);
-
- if (temp64 % 2 != 0)
- as_bad (_("Odd Offset in displacement in Instruction `%s'"),
- ins_parse);
-
- /* Determine the branch size. */
- jump_value = (unsigned int)temp64 & 0xFFFFFFFF;
- if (!IS_INSN_MNEMONIC ("bal") && !IS_INSN_TYPE (DCR_BRANCH_INS)
- && (((jump_value & 0xFFFFFF00) == 0xFFFFFF00)
- || ((jump_value & 0xFFFFFF00) == 0x0)))
- {
- BR_MASK = 0xFF;
- BR_SIZE = 8;
- }
- else if (((jump_value & 0xFFFF0000) == 0xFFFF0000)
- || ((jump_value & 0xFFFF0000) == 0x0))
- {
- BR_MASK = 0xFFFF;
- BR_SIZE = 16;
- }
- else
- {
- BR_MASK = 0xFFFFFFFF;
- BR_SIZE = 32;
- }
- jump_value = jump_value >> 1;
- crx_ins->arg[number].constant = jump_value & BR_MASK;
- crx_ins->arg[number].size = BR_SIZE;
- size_was_set = 1;
- crx_ins->arg[number].signflag = signflag;
- input_line_pointer = save;
- return crx_ins->exp.X_op;
- }
- /* Fix for movd $0xF12344, r0 -- signflag has to be set. */
- if (constant_val < 0 && signflag != 1
- && !IS_INSN_TYPE (LD_STOR_INS) && !IS_INSN_TYPE (LD_STOR_INS_INC)
- && !IS_INSN_TYPE (CSTBIT_INS) && !IS_INSN_TYPE (STOR_IMM_INS)
- && !IS_INSN_TYPE (BRANCH_INS) && !IS_INSN_MNEMONIC ("bal"))
- {
- crx_ins->arg[number].constant =
- ~(crx_ins->arg[number].constant) + 1;
- signflag = 1;
- }
- /* For load/store instruction when the value is in the offset part. */
- if (constant_val < 0 && signflag != 1
- && (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (LD_STOR_INS_INC)
- || IS_INSN_TYPE (CSTBIT_INS) || IS_INSN_TYPE (STOR_IMM_INS)))
- {
- if (crx_ins->arg[number].type == arg_cr
- || crx_ins->arg[number].type == arg_icr)
- {
- crx_ins->arg[number].constant =
- ~(crx_ins->arg[number].constant) + 1;
- signflag = 1;
- }
- }
- if (signflag)
- {
- /* Signflag in never set in case of load store instructions
- Mapping in case of only the arithinsn case. */
- if ((crx_ins->arg[number].constant != 1
- && crx_ins->arg[number].constant != 4)
- || (!IS_INSN_TYPE (ARITH_INS)
- && !IS_INSN_TYPE (ARITH_BYTE_INS)
- && !IS_INSN_TYPE (CMPBR_INS)))
- {
- /* Counting the number of bits required to represent
- the constant. */
- cnt = 0;
- temp = crx_ins->arg[number].constant - 1;
- while (temp > 0)
- {
- temp >>= 1;
- cnt++;
- }
- crx_ins->arg[number].size = cnt + 1;
- crx_ins->arg[number].constant =
- ~(crx_ins->arg[number].constant) + 1;
- if (IS_INSN_TYPE (ARITH_INS) || IS_INSN_TYPE (ARITH_BYTE_INS))
- {
- char ptr;
- LONGLONG temp64;
-
- temp64 = strtoull (str, (char **) &ptr, 0);
- if (cnt < 4)
- crx_ins->arg[number].size = 5;
-
- if (IS_INSN_TYPE (ARITH_INS))
- {
- if (crx_ins->arg[number].size > 32
- || (temp64 > ULONG_MAX))
- {
- if (crx_ins->arg[number].size > 32)
- as_bad (_("In Instruction `%s': Immediate size is \
- %lu bits cannot be accomodated"),
- ins_parse, cnt + 1);
-
- if (temp64 > ULONG_MAX)
- as_bad (_("Value given more than 32 bits in \
- Instruction `%s'"), ins_parse);
- }
- }
- if (IS_INSN_TYPE (ARITH_BYTE_INS))
- {
- if (crx_ins->arg[number].size > 16
- || !((temp64 & 0xFFFF0000) == 0xFFFF0000
- || (temp64 & 0xFFFF0000) == 0x0))
- {
- if (crx_ins->arg[number].size > 16)
- as_bad (_("In Instruction `%s': Immediate size is \
- %lu bits cannot be accomodated"),
- ins_parse, cnt + 1);
-
- if (!((temp64 & 0xFFFF0000) == 0xFFFF0000
- || (temp64 & 0xFFFF0000) == 0x0))
- as_bad (_("Value given more than 16 bits in \
- Instruction `%s'"), ins_parse);
- }
- }
- }
- if (IS_INSN_TYPE (LD_STOR_INS) && crx_ins->arg[number].type == arg_cr
- && !post_inc_mode)
- {
- /* Cases handled ---
- dispub4/dispuw4/dispud4 and for load store dispubwd4
- is applicable only. */
- if (crx_ins->arg[number].size <= 4)
- crx_ins->arg[number].size = 5;
- }
- /* Argument number is checked to distinguish between
- immediate and displacement in cmpbranch and bcopcond. */
- if ((IS_INSN_TYPE (CMPBR_INS) || IS_INSN_TYPE (COP_BRANCH_INS))
- && number == 2)
- {
- if (crx_ins->arg[number].size != 32)
- crx_ins->arg[number].constant =
- crx_ins->arg[number].constant >> 1;
- }
-
- mask_const (&crx_ins->arg[number].constant,
- (int) crx_ins->arg[number].size);
- }
- }
- else
- {
- /* Argument number is checked to distinguish between
- immediate and displacement in cmpbranch and bcopcond. */
- if (((IS_INSN_TYPE (CMPBR_INS) || IS_INSN_TYPE (COP_BRANCH_INS))
- && number == 2)
- || IS_INSN_TYPE (BRANCH_NEQ_INS))
- {
- if (IS_INSN_TYPE (BRANCH_NEQ_INS))
- {
- if (crx_ins->arg[number].constant == 0)
- as_bad (_("Instruction `%s' has Zero offset"), ins_parse);
- }
-
- if (crx_ins->arg[number].constant % 2 != 0)
- as_bad (_("Instruction `%s' has odd offset"), ins_parse);
-
- if (IS_INSN_TYPE (BRANCH_NEQ_INS))
- {
- if (crx_ins->arg[number].constant > 32
- || crx_ins->arg[number].constant < 2)
- as_bad (_("Instruction `%s' has illegal offset (%ld)"),
- ins_parse, crx_ins->arg[number].constant);
-
- crx_ins->arg[number].constant -= 2;
- }
-
- crx_ins->arg[number].constant =
- crx_ins->arg[number].constant >> 1;
- get_number_of_bits (crx_ins, number);
- }
-
- /* Compare branch argument number zero to be compared -
- mapped to cst4. */
- if (IS_INSN_TYPE (CMPBR_INS) && number == 0)
- {
- for (cst4_op = cst4_map; cst4_op < (cst4_map + cst4_maps); cst4_op++)
- {
- if (crx_ins->arg[number].constant == (unsigned int)cst4_op->value)
- {
- crx_ins->arg[number].constant = cst4_op->binary;
- is_cst4 = 1;
- break;
- }
- }
- if (!is_cst4)
- as_bad (_("Instruction `%s' has invalid imm value as an \
- operand"), ins_parse);
- }
- }
+ cur_arg->X_op = O_constant;
+ cur_arg->constant = crx_ins->exp.X_add_number;
break;
case O_symbol:
case O_subtract:
- crx_ins->arg[number].constant = 0;
+ case O_add:
+ cur_arg->X_op = O_symbol;
crx_ins->rtype = BFD_RELOC_NONE;
relocatable = 1;
- switch (crx_ins->arg[number].type)
+ switch (cur_arg->type)
{
case arg_cr:
- /* Have to consider various cases here --load/stor++[bwd] rbase, reg. */
if (IS_INSN_TYPE (LD_STOR_INS_INC))
crx_ins->rtype = BFD_RELOC_CRX_REGREL12;
else if (IS_INSN_TYPE (CSTBIT_INS)
|| IS_INSN_TYPE (STOR_IMM_INS))
- /* 'stor[bwd] imm' and '[stc]bit[bwd]'. */
crx_ins->rtype = BFD_RELOC_CRX_REGREL28;
else
- /* General load store instruction. */
crx_ins->rtype = BFD_RELOC_CRX_REGREL32;
- break;
- case arg_icr:
- /* Index Mode 22 bits relocation. */
+ break;
+
+ case arg_idxr:
crx_ins->rtype = BFD_RELOC_CRX_REGREL22;
break;
+
case arg_c:
- /* Absolute types. */
- /* Case for jumps...dx types. */
- /* For bal. */
if (IS_INSN_MNEMONIC ("bal") || IS_INSN_TYPE (DCR_BRANCH_INS))
crx_ins->rtype = BFD_RELOC_CRX_REL16;
else if (IS_INSN_TYPE (BRANCH_INS))
- {
- crx_ins->rtype = BFD_RELOC_CRX_REL8;
-
- /* Overriding the above by the br_type_flag set above. */
- switch (br_type_flag)
- {
- default:
- break;
- case 8:
- crx_ins->rtype = BFD_RELOC_CRX_REL8;
- break;
- case 16:
- crx_ins->rtype = BFD_RELOC_CRX_REL16;
- break;
- case 32:
- crx_ins->rtype = BFD_RELOC_CRX_REL32;
- break;
- }
- }
+ crx_ins->rtype = BFD_RELOC_CRX_REL8;
else if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (STOR_IMM_INS)
|| IS_INSN_TYPE (CSTBIT_INS))
crx_ins->rtype = BFD_RELOC_CRX_ABS32;
else if (IS_INSN_TYPE (BRANCH_NEQ_INS))
crx_ins->rtype = BFD_RELOC_CRX_REL4;
else if (IS_INSN_TYPE (CMPBR_INS) || IS_INSN_TYPE (COP_BRANCH_INS))
- {
- if (cmp_br_type_flag == 24)
- crx_ins->rtype = BFD_RELOC_CRX_REL24;
- else
- crx_ins->rtype = BFD_RELOC_CRX_REL8_CMP;
- }
+ crx_ins->rtype = BFD_RELOC_CRX_REL8_CMP;
break;
+
case arg_ic:
- case arg_dc:
if (IS_INSN_TYPE (ARITH_INS))
crx_ins->rtype = BFD_RELOC_CRX_IMM32;
else if (IS_INSN_TYPE (ARITH_BYTE_INS))
default:
break;
}
- crx_ins->arg[number].size = (bfd_reloc_type_lookup (stdoutput, crx_ins->rtype))->bitsize;
break;
default:
+ cur_arg->X_op = crx_ins->exp.X_op;
break;
}
- input_line_pointer = save;
- crx_ins->arg[number].signflag = signflag;
- return crx_ins->exp.X_op;
+ input_line_pointer = saved_input_line_pointer;
+ return;
}
/* Get the values of the scale to be encoded -
return exponent;
}
-/* This is used to set the index mode parameters. Used to set the attributes of
- an indexmode type of operand. op_num is the operand number. */
+/* Parsing different types of operands
+ -> constants Immediate/Absolute/Relative numbers
+ -> Labels Relocatable symbols
+ -> (rbase) Register base
+ -> disp(rbase) Register relative
+ -> disp(rbase)+ Post-increment mode
+ -> disp(rbase,ridx,scl) Register index mode */
static void
-set_indexmode_parameters (char *operand, ins * crx_ins, int op_num)
+set_operand (char *operand, ins * crx_ins)
{
- char address_str[30];
- char scale_str[MAX_OPERANDS];
- int scale_cnt = 0;
- char reg_name[MAX_REGNAME_LEN];
- char regindex_name[MAX_REGNAME_LEN];
- int i = 0;
- int reg_counter = 0, addr_cnt = 0, temp_int_val = 0;
+ char *operandS; /* Pointer to start of sub-operand. */
+ char *operandE; /* Pointer to end of sub-operand. */
+ expressionS scale;
+ int scale_val;
+ char *input_save, c;
+ argument *cur_arg = &crx_ins->arg[cur_arg_num]; /* Current argument. */
- switch (crx_ins->arg[op_num].type)
+ /* Initialize pointers. */
+ operandS = operandE = operand;
+
+ switch (cur_arg->type)
{
- case arg_icr:
- while (operand[i] != '(')
- {
- address_str[addr_cnt++] = operand[i];
- i++;
- }
- address_str[addr_cnt] = '\0';
- process_label_constant (address_str, crx_ins, op_num);
- i++;
- reg_counter = 0;
- while (operand[i] != ',' && operand[i] != ' ')
- {
- reg_name[reg_counter++] = operand[i];
- i++;
- }
- reg_name[reg_counter] = '\0';
- if ((crx_ins->arg[op_num].r = get_register (reg_name)) == nullregister)
- as_bad (_("Illegal register `%s' in Instruction `%s'"),
- reg_name, ins_parse);
+ case arg_sc: /* Case *+0x18. */
+ case arg_ic: /* Case $0x18. */
+ operandS++;
+ /* Fall through. */
+ case arg_c: /* Case 0x18. */
+ /* Set constant. */
+ process_label_constant (operandS, crx_ins);
+
+ if (cur_arg->type != arg_ic)
+ cur_arg->type = arg_c;
+ break;
- i++;
- while (operand[i] == ' ')
- i++;
+ case arg_icr: /* Case $0x18(r1). */
+ operandS++;
+ case arg_cr: /* Case 0x18(r1). */
+ /* Set displacement constant. */
+ while (*operandE != '(')
+ operandE++;
+ *operandE = '\0';
+ process_label_constant (operandS, crx_ins);
+ operandS = operandE;
+ /* Fall through. */
+ case arg_rbase: /* Case (r1). */
+ operandS++;
+ /* Set register base. */
+ while (*operandE != ')')
+ operandE++;
+ *operandE = '\0';
+ if ((cur_arg->r = get_register (operandS)) == nullregister)
+ as_bad (_("Illegal register `%s' in instruction `%s'"),
+ operandS, ins_parse);
+
+ if (cur_arg->type != arg_rbase)
+ cur_arg->type = arg_cr;
+ break;
- reg_counter = 0;
- while (operand[i] != ')' && operand[i] != ',')
- {
- regindex_name[reg_counter++] = operand[i];
- i++;
- }
- regindex_name[reg_counter] = '\0';
- reg_counter = 0;
- if ((crx_ins->arg[op_num].i_r = get_register (regindex_name))
- == nullregister)
- as_bad (_("Illegal register `%s' in Instruction `%s'"),
- regindex_name, ins_parse);
-
- /* Setting the scale parameters. */
- while (operand[i] == ' ')
- i++;
-
- if (operand[i] == ')')
- crx_ins->arg[op_num].scale = 0;
+ case arg_idxr:
+ /* Set displacement constant. */
+ while (*operandE != '(')
+ operandE++;
+ *operandE = '\0';
+ process_label_constant (operandS, crx_ins);
+ operandS = ++operandE;
+
+ /* Set register base. */
+ while ((*operandE != ',') && (! ISSPACE (*operandE)))
+ operandE++;
+ *operandE++ = '\0';
+ if ((cur_arg->r = get_register (operandS)) == nullregister)
+ as_bad (_("Illegal register `%s' in instruction `%s'"),
+ operandS, ins_parse);
+
+ /* Skip leading white space. */
+ while (ISSPACE (*operandE))
+ operandE++;
+ operandS = operandE;
+
+ /* Set register index. */
+ while ((*operandE != ')') && (*operandE != ','))
+ operandE++;
+ c = *operandE;
+ *operandE++ = '\0';
+
+ if ((cur_arg->i_r = get_register (operandS)) == nullregister)
+ as_bad (_("Illegal register `%s' in instruction `%s'"),
+ operandS, ins_parse);
+
+ /* Skip leading white space. */
+ while (ISSPACE (*operandE))
+ operandE++;
+ operandS = operandE;
+
+ /* Set the scale. */
+ if (c == ')')
+ cur_arg->scale = 0;
else
{
- if (operand[i] == ',')
- i++;
+ while (*operandE != ')')
+ operandE++;
+ *operandE = '\0';
- while (operand[i] != ' ' && operand[i] != ')')
- {
- scale_str[scale_cnt++] = operand[i];
- i++;
- }
+ /* Preprocess the scale string. */
+ input_save = input_line_pointer;
+ input_line_pointer = operandS;
+ expression (&scale);
+ input_line_pointer = input_save;
- scale_str[scale_cnt] = '\0';
- /* Preprocess the scale string. */
- if (strstr (scale_str, "0x") != NULL
- || strstr (scale_str, "0X") != NULL)
- {
- sscanf (scale_str, "%x", &temp_int_val);
- memset (&scale_str, '\0', sizeof (scale_str));
- sprintf (scale_str, "%d", temp_int_val);
- }
- /* Preprocess over. */
- temp_int_val = atoi (scale_str);
+ scale_val = scale.X_add_number;
- if (temp_int_val != 1 && temp_int_val != 2
- && temp_int_val != 4 && temp_int_val != 8)
- as_bad (_("Illegal Scale - `%s'"), scale_str);
+ /* Check if the scale value is legal. */
+ if (scale_val != 1 && scale_val != 2
+ && scale_val != 4 && scale_val != 8)
+ as_bad (_("Illegal Scale - `%d'"), scale_val);
- crx_ins->arg[op_num].scale = exponent2scale (temp_int_val);
+ cur_arg->scale = exponent2scale (scale_val);
}
break;
+
default:
break;
}
}
-/* Parsing the operands of types
- - constants
- - rbase -> (register)
- - offset(rbase)
- - offset(rbase)+ - post increment mode. */
+/* Parse a single operand.
+ operand - Current operand to parse.
+ crx_ins - Current assembled instruction. */
static void
-set_cons_rparams (char *operand, ins * crx_ins, int op_num)
+parse_operand (char *operand, ins * crx_ins)
{
- int i = 0, reg_count = 0;
- char reg_name[MAX_REGNAME_LEN];
- int change_flag = 0;
+ int ret_val;
+ argument *cur_arg = &crx_ins->arg[cur_arg_num]; /* Current argument. */
- if (crx_ins->arg[op_num].type == arg_dc)
- change_flag = 1;
+ /* Initialize the type to NULL before parsing. */
+ cur_arg->type = nullargs;
- switch (crx_ins->arg[op_num].type)
+ /* Check whether this is a general processor register. */
+ if ((ret_val = get_register (operand)) != nullregister)
{
- case arg_sc: /* Case *+347. */
- case arg_dc: /* Case $18. */
- i++;
- case arg_c:/* Case where its a simple constant. */
- process_label_constant (operand + i, crx_ins, op_num);
- crx_ins->arg[op_num].type = arg_c;
- break;
- case arg_dcr: /* Case $9(r13). */
- operand++;
- case arg_cr: /* Case 9(r13. */
- while (operand[i] != '(')
- i++;
- operand[i] = '\0';
- process_label_constant (operand, crx_ins, op_num);
- operand[i] = '(';
- i++;
- reg_count = 0;
- while (operand[i] != ')')
- {
- reg_name[reg_count] = operand[i];
- i++;
- reg_count++;
- }
- reg_name[reg_count] = '\0';
- if ((crx_ins->arg[op_num].r = get_register (reg_name)) == nullregister)
- as_bad (_("Illegal register `%s' in Instruction `%s'"),
- reg_name, ins_parse);
-
- crx_ins->arg[op_num].type = arg_cr;
- /* Post increment is represented in assembly as offset (register)+. */
- if (strstr (operand + i, "+") != NULL)
- /* There is a plus after the ')'. */
- post_inc_mode = 1;
- break;
- default:
- break;
+ cur_arg->type = arg_r;
+ cur_arg->r = ret_val;
+ cur_arg->X_op = O_register;
+ return;
}
- if (change_flag == 1)
- crx_ins->arg[op_num].type = arg_ic;
-}
-/* This is used to get the operand attributes -
- operand - current operand to be used
- number - operand number
- crx_ins - current assembled instruction. */
-
-static void
-get_operandtype (char *operand, int number, ins * crx_ins)
-{
- int ret_val;
- char temp_operand[30];
+ /* Check whether this is a core [special] coprocessor register. */
+ if ((ret_val = get_copregister (operand)) != nullcopregister)
+ {
+ cur_arg->type = arg_copr;
+ if (ret_val >= cs0)
+ cur_arg->type = arg_copsr;
+ cur_arg->cr = ret_val;
+ cur_arg->X_op = O_register;
+ return;
+ }
+ /* Deal with special characters. */
switch (operand[0])
{
- /* When it is a register. */
- case 'r':
- case 'c':
- case 'i':
- case 'u':
- case 's':
- case 'p':
- case 'l':
- case 'h':
- /* Check whether this is a general processor register. */
- ret_val = get_register (operand);
- if (ret_val != nullregister)
- {
- crx_ins->arg[number].type = arg_r;
- crx_ins->arg[number].r = ret_val;
- crx_ins->arg[number].size = REG_SIZE;
- }
- else
- {
- /* Check whether this is a core [special] coprocessor register. */
- ret_val = get_copregister (operand);
- if (ret_val != nullcopregister)
- {
- crx_ins->arg[number].type = arg_copr;
- if (ret_val >= cs0)
- crx_ins->arg[number].type = arg_copsr;
- crx_ins->arg[number].cr = ret_val;
- crx_ins->arg[number].size = REG_SIZE;
- }
- else
- {
- if (strchr (operand, '(') != NULL)
- {
- if (strchr (operand, ',') != NULL
- && (strchr (operand, ',') > strchr (operand, '(')))
- {
- crx_ins->arg[number].type = arg_icr;
- crx_ins->arg[number].constant = 0;
- set_indexmode_parameters (operand, crx_ins, number);
- get_number_of_bits (crx_ins, number);
- return;
- }
- else
- crx_ins->arg[number].type = arg_cr;
- }
- else
- crx_ins->arg[number].type = arg_c;
- crx_ins->arg[number].constant = 0;
- set_cons_rparams (operand, crx_ins, number);
- get_number_of_bits (crx_ins, number);
- }
- }
- break;
case '$':
if (strchr (operand, '(') != NULL)
- crx_ins->arg[number].type = arg_dcr;
+ cur_arg->type = arg_icr;
else
- crx_ins->arg[number].type = arg_dc;
- crx_ins->arg[number].constant = 0;
- set_cons_rparams (operand, crx_ins, number);
- get_number_of_bits (crx_ins, number);
+ cur_arg->type = arg_ic;
+ goto set_params;
break;
- case '(':
- /* Augmenting a zero in front of an operand -- won't work for tbit/sbit. */
- strcpy (temp_operand, "0");
- strcat (temp_operand, operand);
- if (strchr (temp_operand, ',') != NULL
- && (strchr (temp_operand, ',') > strchr (temp_operand, '(')))
- {
- crx_ins->arg[number].type = arg_icr;
- crx_ins->arg[number].constant = 0;
- set_indexmode_parameters (temp_operand, crx_ins, number);
- get_number_of_bits (crx_ins, number);
- return;
- }
- else
- {
- crx_ins->arg[number].type = arg_cr;
- crx_ins->arg[number].constant = 0;
- set_cons_rparams (temp_operand, crx_ins, number);
- get_number_of_bits (crx_ins, number);
- if ((! strneq (instruction->mnemonic, "load", 4))
- && (! strneq (instruction->mnemonic, "stor", 4)))
- {
- crx_ins->arg[number].type = arg_rbase;
- crx_ins->arg[number].size = REG_SIZE;
- }
- return;
- }
- break;
case '*':
- crx_ins->arg[number].type = arg_sc;
- crx_ins->arg[number].constant = 0;
- set_cons_rparams (operand, crx_ins, number);
- get_number_of_bits (crx_ins, number);
+ cur_arg->type = arg_sc;
+ goto set_params;
break;
- case '+':
- case '-':
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- if (strchr (operand, '(') != NULL)
- {
- if (strchr (operand, ',') != NULL
- && (strchr (operand, ',') > strchr (operand, '(')))
- {
- crx_ins->arg[number].type = arg_icr;
- crx_ins->arg[number].constant = 0;
- set_indexmode_parameters (operand, crx_ins, number);
- get_number_of_bits (crx_ins, number);
- return;
- }
- else
- crx_ins->arg[number].type = arg_cr;
- }
- else
- crx_ins->arg[number].type = arg_c;
- crx_ins->arg[number].constant = 0;
- set_cons_rparams (operand, crx_ins, number);
- get_number_of_bits (crx_ins, number);
+
+ case '(':
+ cur_arg->type = arg_rbase;
+ goto set_params;
break;
+
default:
- if (strchr (operand, '(') != NULL)
- {
- if (strchr (operand, ',') != NULL
- && (strchr (operand, ',') > strchr (operand, '(')))
- {
- crx_ins->arg[number].type = arg_icr;
- crx_ins->arg[number].constant = 0;
- set_indexmode_parameters (operand, crx_ins, number);
- get_number_of_bits (crx_ins, number);
- return;
- }
- else
- crx_ins->arg[number].type = arg_cr;
- }
+ break;
+ }
+
+ if (strchr (operand, '(') != NULL)
+ {
+ if (strchr (operand, ',') != NULL
+ && (strchr (operand, ',') > strchr (operand, '(')))
+ cur_arg->type = arg_idxr;
else
- crx_ins->arg[number].type = arg_c;
- crx_ins->arg[number].constant = 0;
- set_cons_rparams (operand, crx_ins, number);
- get_number_of_bits (crx_ins, number);
- break;
+ cur_arg->type = arg_cr;
}
+ else
+ cur_arg->type = arg_c;
+ goto set_params;
+
+ /* Parse an operand according to its type. */
+ set_params:
+ cur_arg->constant = 0;
+ set_operand (operand, crx_ins);
}
-/* Operands are parsed over here, separated into various operands. Each operand
- is then analyzed to fillup the fields in the crx_ins data structure. */
+/* Parse the various operands. Each operand is then analyzed to fillup
+ the fields in the crx_ins data structure. */
static void
parse_operands (ins * crx_ins, char *operands)
if (bracket_flag || sq_bracket_flag)
as_fatal (_("Missing matching brackets : `%s'"), ins_parse);
- /* Now to recongnize the operand types. */
+ /* Now we parse each operand separately. */
for (op_num = 0; op_num < crx_ins->nargs; op_num++)
{
- get_operandtype (operand[op_num], op_num, crx_ins);
+ cur_arg_num = op_num;
+ parse_operand (operand[op_num], crx_ins);
free (operand[op_num]);
}
This routine is used by assembling the 'excp' instruction. */
static int
-gettrap (char *s)
+gettrap (const char *s)
{
const trap_entry *trap;
return 0;
}
-/* Post-Increment instructions, as well as Store-Immediate instructions, are a
- sub-group within load/stor instruction groups.
- Therefore, when parsing a Post-Increment/Store-Immediate insn, we have to
- advance the instruction pointer to the start of that sub-group (that is, up
+/* Post-Increment instructions, as well as Store-Immediate instructions, are a
+ sub-group within load/stor instruction groups.
+ Therefore, when parsing a Post-Increment/Store-Immediate insn, we have to
+ advance the instruction pointer to the start of that sub-group (that is, up
to the first instruction of that type).
Otherwise, the insn will be mistakenly identified as of type LD_STOR_INS. */
static void
-handle_LoadStor (char *operands)
+handle_LoadStor (const char *operands)
{
- /* Assuming Store-Immediate insn has the following format :
- 'MNEMONIC $DISP, ...' (e.g. 'storb $1, 12(r5)').
- STOR_IMM_INS are the only store insns containing a dollar sign ($). */
- if (strstr (operands, "$") != NULL)
- while (! IS_INSN_TYPE (STOR_IMM_INS))
- instruction++;
+ /* Post-Increment instructions precede Store-Immediate instructions in
+ CRX instruction table, hence they are handled before.
+ This synchronization should be kept. */
/* Assuming Post-Increment insn has the following format :
'MNEMONIC DISP(REG)+, REG' (e.g. 'loadw 12(r5)+, r6').
LD_STOR_INS_INC are the only store insns containing a plus sign (+). */
if (strstr (operands, ")+") != NULL)
- while (! IS_INSN_TYPE (LD_STOR_INS_INC))
+ {
+ while (! IS_INSN_TYPE (LD_STOR_INS_INC))
+ instruction++;
+ return;
+ }
+
+ /* Assuming Store-Immediate insn has the following format :
+ 'MNEMONIC $DISP, ...' (e.g. 'storb $1, 12(r5)').
+ STOR_IMM_INS are the only store insns containing a dollar sign ($). */
+ if (strstr (operands, "$") != NULL)
+ while (! IS_INSN_TYPE (STOR_IMM_INS))
instruction++;
}
static void
parse_insn (ins *insn, char *operands)
{
- /* Handle 'excp'/'cinv' */
+ int i;
+
+ /* Handle instructions with no operands. */
+ for (i = 0; crx_no_op_insn[i] != NULL; i++)
+ {
+ if (streq (crx_no_op_insn[i], instruction->mnemonic))
+ {
+ insn->nargs = 0;
+ return;
+ }
+ }
+
+ /* Handle 'excp'/'cinv' instructions. */
if (IS_INSN_MNEMONIC ("excp") || IS_INSN_MNEMONIC ("cinv"))
{
insn->nargs = 1;
insn->arg[0].type = arg_ic;
- insn->arg[0].size = 4;
insn->arg[0].constant = IS_INSN_MNEMONIC ("excp") ?
gettrap (operands) : get_cinv_parameters (operands);
+ insn->arg[0].X_op = O_constant;
return;
}
/* Cinv instruction requires special handling. */
static int
-get_cinv_parameters (char * operand)
+get_cinv_parameters (const char *operand)
{
- char *p = operand;
+ const char *p = operand;
int d_used = 0, i_used = 0, u_used = 0, b_used = 0;
while (*++p != ']')
issue an error. */
static int
-getreg_image (reg r)
+getreg_image (int r)
{
- const reg_entry *reg;
+ const reg_entry *rreg;
char *reg_name;
- int special_register_flag = 0;
- int movpr_flag = 0; /* Nonzero means current mnemonic is 'mtpr'/'mfpr' */
+ int is_procreg = 0; /* Nonzero means argument should be processor reg. */
- if (IS_INSN_MNEMONIC ("mtpr") || IS_INSN_MNEMONIC ("mfpr"))
- movpr_flag = 1;
-
- if (((IS_INSN_MNEMONIC ("mtpr")) && (processing_arg_number == 1))
- || ((IS_INSN_MNEMONIC ("mfpr")) && (processing_arg_number == 0)) )
- special_register_flag = 1;
+ if (((IS_INSN_MNEMONIC ("mtpr")) && (cur_arg_num == 1))
+ || ((IS_INSN_MNEMONIC ("mfpr")) && (cur_arg_num == 0)) )
+ is_procreg = 1;
/* Check whether the register is in registers table. */
if (r < MAX_REG)
- reg = &crx_regtab[r];
+ rreg = &crx_regtab[r];
/* Check whether the register is in coprocessor registers table. */
- else if (r < MAX_COPREG)
- reg = &crx_copregtab[r-MAX_REG];
+ else if (r < (int) MAX_COPREG)
+ rreg = &crx_copregtab[r-MAX_REG];
/* Register not found. */
else
{
return 0;
}
- reg_name = reg->name;
+ reg_name = rreg->name;
/* Issue a error message when register is illegal. */
#define IMAGE_ERR \
- as_bad (_("Illegal register (`%s') in Instruction: `%s'"), \
- reg_name, ins_parse); \
- break;
+ as_bad (_("Illegal register (`%s') in instruction: `%s'"), \
+ reg_name, ins_parse);
- switch (reg->type)
+ switch (rreg->type)
{
case CRX_U_REGTYPE:
+ if (is_procreg || (instruction->flags & USER_REG))
+ return rreg->image;
+ else
+ IMAGE_ERR;
+ break;
+
case CRX_CFG_REGTYPE:
- case CRX_MTPR_REGTYPE:
- if (movpr_flag && special_register_flag)
- return reg->image;
+ if (is_procreg)
+ return rreg->image;
else
IMAGE_ERR;
+ break;
case CRX_R_REGTYPE:
- case CRX_C_REGTYPE:
- case CRX_CS_REGTYPE:
- if (!(movpr_flag && special_register_flag))
- return reg->image;
+ if (! is_procreg)
+ return rreg->image;
else
IMAGE_ERR;
+ break;
+
+ case CRX_C_REGTYPE:
+ case CRX_CS_REGTYPE:
+ return rreg->image;
+ break;
default:
IMAGE_ERR;
+ break;
}
return 0;
}
-/* Routine used to get the binary-string equivalent of a integer constant
- which currently require currbits to represent itself to be extended to
- nbits. */
+/* Routine used to represent integer X using NBITS bits. */
-static unsigned long int
-getconstant (unsigned long int x, int nbits)
+static long
+getconstant (long x, int nbits)
{
- int cnt = 0;
- unsigned long int temp = x;
-
- while (temp > 0)
- {
- temp >>= 1;
- cnt++;
- }
-
- /* Escape sequence to next 16bit immediate. */
- if (cnt > nbits)
- as_bad (_("Value `%ld' truncated to fit `%d' bits in instruction `%s'"),
- x, cnt, ins_parse);
- else
- {
- if (signflag)
- x |= SET_BITS_MASK (cnt, nbits - cnt);
- else
- x &= CLEAR_BITS_MASK (cnt, nbits - cnt);
- }
-
- /* The following expression avoids overflow if
- 'nbits' is the number of bits in 'bfd_vma'. */
- return (x & ((((1 << (nbits - 1)) - 1) << 1) | 1));
+ return x & ((((1U << (nbits - 1)) - 1) << 1) | 1);
}
/* Print a constant value to 'output_opcode':
break;
}
- /* When instruction size is 3, a 16-bit constant is always
- filling the upper part of output_opcode[1]. */
- if (instruction->size > 2)
+ /* When instruction size is 3 and 'shift' is 16, a 16-bit constant is
+ always filling the upper part of output_opcode[1]. If we mistakenly
+ write it to output_opcode[0], the constant prefix (that is, 'match')
+ will be overridden.
+ 0 1 2 3
+ +---------+---------+---------+---------+
+ | 'match' | | X X X X | |
+ +---------+---------+---------+---------+
+ output_opcode[0] output_opcode[1] */
+
+ if ((instruction->size > 2) && (shift == WORD_SHIFT))
CRX_PRINT (1, constant, WORD_SHIFT);
else
CRX_PRINT (0, constant, shift);
case arg_copr:
if (arg->cr < c0 || arg->cr > c15)
- as_bad (_("Illegal Co-processor register in Instruction `%s' "),
+ as_bad (_("Illegal co-processor register in instruction `%s'"),
ins_parse);
CRX_PRINT (0, getreg_image (arg->cr), shift);
break;
case arg_copsr:
if (arg->cr < cs0 || arg->cr > cs15)
- as_bad (_("Illegal Co-processor special register in Instruction `%s' "),
+ as_bad (_("Illegal co-processor special register in instruction `%s'"),
ins_parse);
CRX_PRINT (0, getreg_image (arg->cr), shift);
break;
- case arg_ic:
- print_constant (nbits, shift, arg);
- break;
-
- case arg_icr:
+ case arg_idxr:
/* 16 12 8 6 0
+--------------------------------+
- | reg | r_base | scl| disp |
+ | r_base | r_idx | scl| disp |
+--------------------------------+ */
CRX_PRINT (0, getreg_image (arg->r), 12);
CRX_PRINT (0, getreg_image (arg->i_r), 8);
CRX_PRINT (0, arg->scale, 6);
+ /* Fall through. */
+ case arg_ic:
+ case arg_c:
print_constant (nbits, shift, arg);
break;
case arg_cr:
/* case base_cst4. */
- if ((instruction->flags & CST4MAP) && cst4flag)
- output_opcode[0] |= (getconstant (arg->constant, nbits)
- << (shift + REG_SIZE));
+ if (instruction->flags & DISPU4MAP)
+ print_constant (nbits, shift + REG_SIZE, arg);
else
- /* rbase_dispu<NN> and other such cases. */
+ /* rbase_disps<NN> and other such cases. */
print_constant (nbits, shift, arg);
/* Add the register argument to the output_opcode. */
CRX_PRINT (0, getreg_image (arg->r), shift);
break;
- case arg_c:
- print_constant (nbits, shift, arg);
- break;
-
default:
break;
}
return i;
}
-/* Assemble a single instruction :
- Instruction has been parsed and all operand values set appropriately.
- Algorithm for assembling -
- For instruction to be assembled:
- Step 1: Find instruction in the array crx_instruction with same mnemonic.
- Step 2: Find instruction with same operand types.
- Step 3: If (size_of_operands) match then done, else increment the
- array_index and goto Step3.
- Step 4: Cannot assemble
+/* Verify that the number NUM can be represented in BITS bits (that is,
+ within its permitted range), based on the instruction's FLAGS.
+ If UPDATE is nonzero, update the value of NUM if necessary.
+ Return OP_LEGAL upon success, actual error type upon failure. */
+
+static op_err
+check_range (long *num, int bits, int unsigned flags, int update)
+{
+ uint32_t max;
+ op_err retval = OP_LEGAL;
+ int bin;
+ uint32_t upper_64kb = 0xffff0000;
+ uint32_t value = *num;
+
+ /* Verify operand value is even. */
+ if (flags & OP_EVEN)
+ {
+ if (value % 2)
+ return OP_NOT_EVEN;
+ }
+
+ if (flags & OP_UPPER_64KB)
+ {
+ /* Check if value is to be mapped to upper 64 KB memory area. */
+ if ((value & upper_64kb) == upper_64kb)
+ {
+ value -= upper_64kb;
+ if (update)
+ *num = value;
+ }
+ else
+ return OP_NOT_UPPER_64KB;
+ }
+
+ if (flags & OP_SHIFT)
+ {
+ /* All OP_SHIFT args are also OP_SIGNED, so we want to keep the
+ sign. However, right shift of a signed type with a negative
+ value is implementation defined. See ISO C 6.5.7. So we use
+ an unsigned type and sign extend afterwards. */
+ value >>= 1;
+ value = (value ^ 0x40000000) - 0x40000000;
+ if (update)
+ *num = value;
+ }
+ else if (flags & OP_SHIFT_DEC)
+ {
+ value = (value >> 1) - 1;
+ if (update)
+ *num = value;
+ }
+
+ if (flags & OP_ESC)
+ {
+ /* 0x7e and 0x7f are reserved escape sequences of dispe9. */
+ if (value == 0x7e || value == 0x7f)
+ return OP_OUT_OF_RANGE;
+ }
+
+ if (flags & OP_DISPU4)
+ {
+ int is_dispu4 = 0;
+
+ uint32_t mul = (instruction->flags & DISPUB4 ? 1
+ : instruction->flags & DISPUW4 ? 2
+ : instruction->flags & DISPUD4 ? 4
+ : 0);
+
+ for (bin = 0; bin < crx_cst4_maps; bin++)
+ {
+ if (value == mul * bin)
+ {
+ is_dispu4 = 1;
+ if (update)
+ *num = bin;
+ break;
+ }
+ }
+ if (!is_dispu4)
+ retval = OP_ILLEGAL_DISPU4;
+ }
+ else if (flags & OP_CST4)
+ {
+ int is_cst4 = 0;
+
+ for (bin = 0; bin < crx_cst4_maps; bin++)
+ {
+ if (value == (uint32_t) crx_cst4_map[bin])
+ {
+ is_cst4 = 1;
+ if (update)
+ *num = bin;
+ break;
+ }
+ }
+ if (!is_cst4)
+ retval = OP_ILLEGAL_CST4;
+ }
+ else if (flags & OP_SIGNED)
+ {
+ max = 1;
+ max = max << (bits - 1);
+ value += max;
+ max = ((max - 1) << 1) | 1;
+ if (value > max)
+ retval = OP_OUT_OF_RANGE;
+ }
+ else if (flags & OP_UNSIGNED)
+ {
+ max = 1;
+ max = max << (bits - 1);
+ max = ((max - 1) << 1) | 1;
+ if (value > max)
+ retval = OP_OUT_OF_RANGE;
+ }
+ return retval;
+}
+
+/* Assemble a single instruction:
+ INSN is already parsed (that is, all operand values and types are set).
+ For instruction to be assembled, we need to find an appropriate template in
+ the instruction table, meeting the following conditions:
+ 1: Has the same number of operands.
+ 2: Has the same operand types.
+ 3: Each operand size is sufficient to represent the instruction's values.
Returns 1 upon success, 0 upon failure. */
static int
assemble_insn (char *mnemonic, ins *insn)
{
- /* Argument type of each operand in the instruction we are looking for. */
- argtype atyp[MAX_OPERANDS];
- /* Argument type of each operand in the current instruction. */
- argtype atyp_act[MAX_OPERANDS];
- /* Size (in bits) of each operand in the instruction we are looking for. */
- int bits[MAX_OPERANDS];
- /* Size (in bits) of each operand in the current instruction. */
- int bits_act[MAX_OPERANDS];
- /* Location (in bits) of each operand in the current instruction. */
- int shift_act[MAX_OPERANDS];
+ /* Type of each operand in the current template. */
+ argtype cur_type[MAX_OPERANDS];
+ /* Size (in bits) of each operand in the current template. */
+ unsigned int cur_size[MAX_OPERANDS];
+ /* Flags of each operand in the current template. */
+ unsigned int cur_flags[MAX_OPERANDS];
+ /* Instruction type to match. */
+ unsigned int ins_type;
+ /* Boolean flag to mark whether a match was found. */
int match = 0;
- int done_flag = 0;
- int cst4maptype = 0;
- int changed_already = 0;
- unsigned int temp_value = 0;
- int instrtype, i;
- /* A pointer to the argument's constant value. */
- unsigned long int *cons;
- /* Pointer to loop over all cst4_map entries. */
- const cst4_entry *cst4_op;
-
- /* Instruction has no operands -> copy only the constant opcode. */
+ int i;
+ /* Nonzero if an instruction with same number of operands was found. */
+ int found_same_number_of_operands = 0;
+ /* Nonzero if an instruction with same argument types was found. */
+ int found_same_argument_types = 0;
+ /* Nonzero if a constant was found within the required range. */
+ int found_const_within_range = 0;
+ /* Argument number of an operand with invalid type. */
+ int invalid_optype = -1;
+ /* Argument number of an operand with invalid constant value. */
+ int invalid_const = -1;
+ /* Operand error (used for issuing various constant error messages). */
+ op_err op_error, const_err = OP_LEGAL;
+
+/* Retrieve data (based on FUNC) for each operand of a given instruction. */
+#define GET_CURRENT_DATA(FUNC, ARRAY) \
+ for (i = 0; i < insn->nargs; i++) \
+ ARRAY[i] = FUNC (instruction->operands[i].op_type)
+
+#define GET_CURRENT_TYPE GET_CURRENT_DATA(get_optype, cur_type)
+#define GET_CURRENT_SIZE GET_CURRENT_DATA(get_opbits, cur_size)
+#define GET_CURRENT_FLAGS GET_CURRENT_DATA(get_opflags, cur_flags)
+
+ /* Instruction has no operands -> only copy the constant opcode. */
if (insn->nargs == 0)
{
output_opcode[0] = BIN (instruction->match, instruction->match_bits);
return 1;
}
- /* Find instruction with same number of operands. */
- while (get_number_of_operands () != insn->nargs
- && IS_INSN_MNEMONIC (mnemonic))
- instruction++;
+ /* In some case, same mnemonic can appear with different instruction types.
+ For example, 'storb' is supported with 3 different types :
+ LD_STOR_INS, LD_STOR_INS_INC, STOR_IMM_INS.
+ We assume that when reaching this point, the instruction type was
+ pre-determined. We need to make sure that the type stays the same
+ during a search for matching instruction. */
+ ins_type = CRX_INS_TYPE(instruction->flags);
- if (!IS_INSN_MNEMONIC (mnemonic))
- return 0;
-
- /* Initialize argument type and size of each given operand. */
- for (i = 0; i < insn->nargs; i++)
- {
- atyp[i] = insn->arg[i].type;
- bits[i] = insn->arg[i].size;
- }
-
- /* Initialize argument type and size of each operand in current inst. */
- GET_ACTUAL_TYPE;
- GET_ACTUAL_SIZE;
-
- while (match != 1
+ while (/* Check that match is still not found. */
+ match != 1
/* Check we didn't get to end of table. */
&& instruction->mnemonic != NULL
/* Check that the actual mnemonic is still available. */
- && IS_INSN_MNEMONIC (mnemonic))
+ && IS_INSN_MNEMONIC (mnemonic)
+ /* Check that the instruction type wasn't changed. */
+ && IS_INSN_TYPE(ins_type))
{
- /* Check for argement type compatibility. */
+ /* Check whether number of arguments is legal. */
+ if (get_number_of_operands () != insn->nargs)
+ goto next_insn;
+ found_same_number_of_operands = 1;
+
+ /* Initialize arrays with data of each operand in current template. */
+ GET_CURRENT_TYPE;
+ GET_CURRENT_SIZE;
+ GET_CURRENT_FLAGS;
+
+ /* Check for type compatibility. */
for (i = 0; i < insn->nargs; i++)
{
- if (atyp_act[i] == atyp[i])
- done_flag = 1;
- else
- {
- done_flag = 0;
- break;
- }
- }
- if (done_flag)
- {
- /* Check for post inc mode of the current instruction. */
- if (post_inc_mode == 1 || IS_INSN_TYPE (LD_STOR_INS_INC))
- done_flag = (post_inc_mode == IS_INSN_TYPE (LD_STOR_INS_INC));
- }
+ if (cur_type[i] != insn->arg[i].type)
+ {
+ if (invalid_optype == -1)
+ invalid_optype = i + 1;
+ goto next_insn;
+ }
+ }
+ found_same_argument_types = 1;
- if (done_flag == 0)
- {
- /* Try again with next instruction. */
- instruction++;
- GET_ACTUAL_TYPE;
- GET_ACTUAL_SIZE;
- continue;
- }
- else
- {
- /* Check for size compatibility. */
- for (i = 0; i < insn->nargs; i++)
- {
- if (bits[i] > bits_act[i])
- {
- /* Actual size is too small - try again. */
- done_flag = 0;
- instruction++;
- GET_ACTUAL_TYPE;
- GET_ACTUAL_SIZE;
- break;
- }
- }
+ for (i = 0; i < insn->nargs; i++)
+ {
+ /* Reverse the operand indices for certain opcodes:
+ Index 0 -->> 1
+ Index 1 -->> 0
+ Other index -->> stays the same. */
+ int j = instruction->flags & REVERSE_MATCH ?
+ i == 0 ? 1 :
+ i == 1 ? 0 : i :
+ i;
+
+ /* Only check range - don't update the constant's value, since the
+ current instruction may not be the last we try to match.
+ The constant's value will be updated later, right before printing
+ it to the object file. */
+ if ((insn->arg[j].X_op == O_constant)
+ && (op_error = check_range (&insn->arg[j].constant, cur_size[j],
+ cur_flags[j], 0)))
+ {
+ if (invalid_const == -1)
+ {
+ invalid_const = j + 1;
+ const_err = op_error;
+ }
+ goto next_insn;
+ }
+ /* For symbols, we make sure the relocation size (which was already
+ determined) is sufficient. */
+ else if ((insn->arg[j].X_op == O_symbol)
+ && ((bfd_reloc_type_lookup (stdoutput, insn->rtype))->bitsize
+ > cur_size[j]))
+ goto next_insn;
+ }
+ found_const_within_range = 1;
- }
+ /* If we got till here -> Full match is found. */
+ match = 1;
+ break;
- if (done_flag == 1)
- {
- /* Full match is found. */
- match = 1;
- break;
- }
+ /* Try again with next instruction. */
+ next_insn:
+ instruction++;
}
- if (match == 0)
- /* We haven't found a match - instruction can't be assembled. */
- return 0;
- else
- /* Full match - print the final image. */
+ if (!match)
{
- /* Error checking for Co-Processor instructions :
- The internal coprocessor 0 can only accept the
- "mtcr" and "mfcr" instructions. */
- if (IS_INSN_TYPE (COP_REG_INS) || IS_INSN_TYPE (COPS_REG_INS)
- || IS_INSN_TYPE (COP_BRANCH_INS))
+ /* We haven't found a match - instruction can't be assembled. */
+ if (!found_same_number_of_operands)
+ as_bad (_("Incorrect number of operands"));
+ else if (!found_same_argument_types)
+ as_bad (_("Illegal type of operand (arg %d)"), invalid_optype);
+ else if (!found_const_within_range)
+ {
+ switch (const_err)
{
- /* The coprocessor id is always the first argument. */
- if ((instruction->operands[0].op_type == i4)
- && (insn->arg[0].constant == 0)
- && (! IS_INSN_MNEMONIC ("mtcr")
- && ! IS_INSN_MNEMONIC ("mfcr")))
- {
- as_bad (_("Internal Coprocessor 0 doesn't support instruction `%s'"),
- mnemonic);
- }
+ case OP_OUT_OF_RANGE:
+ as_bad (_("Operand out of range (arg %d)"), invalid_const);
+ break;
+ case OP_NOT_EVEN:
+ as_bad (_("Operand has odd displacement (arg %d)"), invalid_const);
+ break;
+ case OP_ILLEGAL_DISPU4:
+ as_bad (_("Invalid DISPU4 operand value (arg %d)"), invalid_const);
+ break;
+ case OP_ILLEGAL_CST4:
+ as_bad (_("Invalid CST4 operand value (arg %d)"), invalid_const);
+ break;
+ case OP_NOT_UPPER_64KB:
+ as_bad (_("Operand value is not within upper 64 KB (arg %d)"),
+ invalid_const);
+ break;
+ default:
+ as_bad (_("Illegal operand (arg %d)"), invalid_const);
+ break;
}
- /* Handle positive constants. */
- if (!signflag)
- {
- if (IS_INSN_TYPE (LD_STOR_INS) && !relocatable)
- {
- /* Get the map type of the instruction. */
- instrtype = instruction->flags & REVERSE_MATCH ? 0 : 1;
- cons = &insn->arg[instrtype].constant;
- cst4maptype = instruction->flags & CST4MAP;
-
- switch (cst4maptype)
- {
- case DISPUB4:
- /* 14 and 15 are reserved escape sequences of dispub4. */
- if (*cons == 14 || *cons == 15)
- {
- instruction++;
- GET_ACTUAL_SIZE;
- }
- break;
-
- case DISPUW4:
- /* Mapping has to be done. */
- if (*cons <= 15 && *cons % 2 != 0)
- {
- instruction++;
- GET_ACTUAL_SIZE;
- }
- else if (*cons > 15 && *cons < 27 && *cons % 2 == 0)
- {
- instruction--;
- GET_ACTUAL_SIZE;
- }
- if (*cons < 27 && *cons % 2 == 0)
- *cons /= 2;
- break;
-
- case DISPUD4:
- /* Mapping has to be done. */
- if (*cons <= 15 && *cons % 4 != 0)
- {
- instruction++;
- GET_ACTUAL_SIZE;
- }
- else if (*cons > 15 && *cons < 53 && *cons % 4 == 0)
- {
- instruction--;
- GET_ACTUAL_SIZE;
- }
- if (*cons < 53 && *cons % 4 == 0)
- *cons /= 4;
- break;
- default:
- break;
- }
- }
- if ((IS_INSN_TYPE (ARITH_BYTE_INS) || IS_INSN_TYPE (ARITH_INS))
- && !relocatable)
- {
- /* Check whether a cst4 mapping has to be done. */
- if ((instruction->operands[0].op_type == cst4
- || instruction->operands[0].op_type == i16)
- && (instruction->operands[1].op_type == regr))
- {
- /* 'const' equals reserved escape sequences -->>
- represent as i16. */
- if (insn->arg[0].constant == ESC_16
- || insn->arg[0].constant == ESC_32)
- {
- instruction++;
- GET_ACTUAL_SIZE;
- }
- else
- {
- /* Loop over cst4_map entries. */
- for (cst4_op = cst4_map; cst4_op < (cst4_map + cst4_maps);
- cst4_op++)
- {
- /* 'const' equals a binary, which is already mapped
- by a different value -->> represent as i16. */
- if (insn->arg[0].constant == (unsigned int)cst4_op->binary
- && cst4_op->binary != cst4_op->value)
- {
- instruction++;
- GET_ACTUAL_SIZE;
- }
- /* 'const' equals a value bigger than 16 -->> map to
- its binary and represent as cst4. */
- else if (insn->arg[0].constant == (unsigned int)cst4_op->value
- && insn->arg[0].constant >= 16)
- {
- instruction--;
- insn->arg[0].constant = cst4_op->binary;
- GET_ACTUAL_SIZE;
- }
- }
- }
- }
- /* Special check for 'addub 0, r0' instruction -
- The opcode '0000 0000 0000 0000' is not allowed. */
- if (IS_INSN_MNEMONIC ("addub"))
- {
- if ((instruction->operands[0].op_type == cst4)
- && instruction->operands[1].op_type == regr)
- {
- if (insn->arg[0].constant == 0 && insn->arg[1].r == r0)
- instruction++;
- }
- }
- }
- if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (STOR_IMM_INS)
- || IS_INSN_TYPE (LD_STOR_INS_INC))
- {
- instrtype = instruction->flags & REVERSE_MATCH ? 0 : 1;
- if (instruction->operands[instrtype].op_type == rbase)
- instruction++;
- }
- /* Error checking in case of post-increment instruction. */
- if (IS_INSN_TYPE (LD_STOR_INS_INC))
- {
- if (!((strneq (instruction->mnemonic, "stor", 4))
- && (insn->arg[0].type != arg_r)))
- if (insn->arg[0].r == insn->arg[1].r)
- as_bad (_("Invalid instruction : `%s' Source and Destination register \
- same in Post INC mode"), ins_parse);
- }
- if (IS_INSN_TYPE (CSTBIT_INS) && !relocatable)
- {
- if (instruction->operands[1].op_type == rbase_dispu12)
- {
- if (insn->arg[1].constant == 0)
- {
- instruction--;
- GET_ACTUAL_SIZE;
- }
- }
- }
- if ((IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS)
- || IS_INSN_TYPE (STOR_IMM_INS)
- || IS_INSN_TYPE (LD_STOR_INS_INC)) & !relocatable)
- {
- instrtype = instruction->flags & REVERSE_MATCH ? 0 : 1;
- changed_already = 0;
- /* Convert 32 bits accesses to 16 bits accesses. */
- if (instruction->operands[instrtype].op_type == abs32)
- {
- if ((insn->arg[instrtype].constant & 0xFFFF0000) == 0xFFFF0000)
- {
- instruction--;
- insn->arg[instrtype].constant =
- insn->arg[instrtype].constant & 0xFFFF;
- insn->arg[instrtype].size = 16;
- changed_already = 1;
- GET_ACTUAL_SIZE;
- }
- }
- /* Convert 16 bits accesses to 32 bits accesses. */
- if (instruction->operands[instrtype].op_type == abs16
- && changed_already != 1)
- {
- instruction++;
- insn->arg[instrtype].constant =
- insn->arg[instrtype].constant & 0xFFFF;
- insn->arg[instrtype].size = 32;
- GET_ACTUAL_SIZE;
- }
- changed_already = 0;
- }
- if (IS_INSN_TYPE (BRANCH_INS) && !relocatable)
- {
- /* 0x7e and 0x7f are reserved escape sequences of dispe9. */
- if (insn->arg[0].constant == 0x7e || insn->arg[0].constant == 0x7f)
- {
- instruction++;
- GET_ACTUAL_SIZE;
- }
- }
- }
+ }
+
+ return 0;
+ }
+ else
+ /* Full match - print the encoding to output file. */
+ {
+ /* Make further checking (such that couldn't be made earlier).
+ Warn the user if necessary. */
+ warn_if_needed (insn);
+
+ /* Check whether we need to adjust the instruction pointer. */
+ if (adjust_if_needed (insn))
+ /* If instruction pointer was adjusted, we need to update
+ the size of the current template operands. */
+ GET_CURRENT_SIZE;
for (i = 0; i < insn->nargs; i++)
{
- if (instruction->operands[i].op_type == cst4
- || instruction->operands[i].op_type == rbase_cst4)
- cst4flag = 1;
- }
+ int j = instruction->flags & REVERSE_MATCH ?
+ i == 0 ? 1 :
+ i == 1 ? 0 : i :
+ i;
+
+ /* This time, update constant value before printing it. */
+ if ((insn->arg[j].X_op == O_constant)
+ && (check_range (&insn->arg[j].constant, cur_size[j],
+ cur_flags[j], 1) != OP_LEGAL))
+ as_fatal (_("Illegal operand (arg %d)"), j+1);
+ }
/* First, copy the instruction's opcode. */
output_opcode[0] = BIN (instruction->match, instruction->match_bits);
- /* Swap the argument values in case bcop instructions. */
- if (IS_INSN_TYPE (COP_BRANCH_INS))
+ for (i = 0; i < insn->nargs; i++)
{
- temp_value = insn->arg[0].constant;
- insn->arg[0].constant = insn->arg[1].constant;
- insn->arg[1].constant = temp_value;
+ cur_arg_num = i;
+ print_operand (cur_size[i], instruction->operands[i].shift,
+ &insn->arg[i]);
}
+ }
- for (i = 0; i < insn->nargs; i++)
+ return 1;
+}
+
+/* Bunch of error checking.
+ The checks are made after a matching instruction was found. */
+
+void
+warn_if_needed (ins *insn)
+{
+ /* If the post-increment address mode is used and the load/store
+ source register is the same as rbase, the result of the
+ instruction is undefined. */
+ if (IS_INSN_TYPE (LD_STOR_INS_INC))
+ {
+ /* Enough to verify that one of the arguments is a simple reg. */
+ if ((insn->arg[0].type == arg_r) || (insn->arg[1].type == arg_r))
+ if (insn->arg[0].r == insn->arg[1].r)
+ as_bad (_("Same src/dest register is used (`r%d'), result is undefined"),
+ insn->arg[0].r);
+ }
+
+ /* Some instruction assume the stack pointer as rptr operand.
+ Issue an error when the register to be loaded is also SP. */
+ if (instruction->flags & NO_SP)
+ {
+ if (getreg_image (insn->arg[0].r) == getreg_image (sp))
+ as_bad (_("`%s' has undefined result"), ins_parse);
+ }
+
+ /* If the rptr register is specified as one of the registers to be loaded,
+ the final contents of rptr are undefined. Thus, we issue an error. */
+ if (instruction->flags & NO_RPTR)
+ {
+ if ((1 << getreg_image (insn->arg[0].r)) & insn->arg[1].constant)
+ as_bad (_("Same src/dest register is used (`r%d'), result is undefined"),
+ getreg_image (insn->arg[0].r));
+ }
+}
+
+/* In some cases, we need to adjust the instruction pointer although a
+ match was already found. Here, we gather all these cases.
+ Returns 1 if instruction pointer was adjusted, otherwise 0. */
+
+int
+adjust_if_needed (ins *insn)
+{
+ int ret_value = 0;
+
+ /* Special check for 'addub $0, r0' instruction -
+ The opcode '0000 0000 0000 0000' is not allowed. */
+ if (IS_INSN_MNEMONIC ("addub"))
+ {
+ if ((instruction->operands[0].op_type == cst4)
+ && instruction->operands[1].op_type == regr)
{
- shift_act[i] = instruction->operands[i].shift;
- signflag = insn->arg[i].signflag;
- processing_arg_number = i;
- print_operand (bits_act[i], shift_act[i], &insn->arg[i]);
+ if (insn->arg[0].constant == 0 && insn->arg[1].r == r0)
+ {
+ instruction++;
+ ret_value = 1;
+ }
}
}
- return 1;
+ /* Optimization: Omit a zero displacement in bit operations,
+ saving 2-byte encoding space (e.g., 'cbitw $8, 0(r1)'). */
+ if (IS_INSN_TYPE (CSTBIT_INS))
+ {
+ if ((instruction->operands[1].op_type == rbase_disps12)
+ && (insn->arg[1].X_op == O_constant)
+ && (insn->arg[1].constant == 0))
+ {
+ instruction--;
+ ret_value = 1;
+ }
+ }
+
+ return ret_value;
}
/* Set the appropriate bit for register 'r' in 'mask'.
{
if ((reg)r > (reg)sp)
{
- as_bad (_("Invalid Register in Register List"));
+ as_bad (_("Invalid register in register list"));
return;
}
int reg_counter = 0; /* Count number of parsed registers. */
unsigned short int mask = 0; /* Mask for 16 general purpose registers. */
char *new_param; /* New created operands string. */
- char *paramP = param; /* Pointer to original opearands string. */
+ char *paramP = param; /* Pointer to original operands string. */
char maskstring[10]; /* Array to print the mask as a string. */
+ int hi_found = 0, lo_found = 0; /* Boolean flags for hi/lo registers. */
reg r;
copreg cr;
while (*paramP++ != '{');
- new_param = (char *)xcalloc (MAX_INST_LEN, sizeof (char));
+ new_param = XCNEWVEC (char, MAX_INST_LEN);
*allocated = 1;
strncpy (new_param, param, paramP - param - 1);
/* Coprocessor register c<N>. */
if (IS_INSN_TYPE (COP_REG_INS))
{
- if ((cr = get_copregister (reg_name)) == nullcopregister)
- as_bad (_("Illegal register `%s' in cop-register list"), reg_name);
+ if (((cr = get_copregister (reg_name)) == nullcopregister)
+ || (crx_copregtab[cr-MAX_REG].type != CRX_C_REGTYPE))
+ as_fatal (_("Illegal register `%s' in cop-register list"), reg_name);
mask_reg (getreg_image (cr - c0), &mask);
}
/* Coprocessor Special register cs<N>. */
else if (IS_INSN_TYPE (COPS_REG_INS))
{
- if ((cr = get_copregister (reg_name)) == nullcopregister)
- as_bad (_("Illegal register `%s' in cop-special-register list"),
+ if (((cr = get_copregister (reg_name)) == nullcopregister)
+ || (crx_copregtab[cr-MAX_REG].type != CRX_CS_REGTYPE))
+ as_fatal (_("Illegal register `%s' in cop-special-register list"),
reg_name);
mask_reg (getreg_image (cr - cs0), &mask);
}
+ /* User register u<N>. */
+ else if (instruction->flags & USER_REG)
+ {
+ if (streq(reg_name, "uhi"))
+ {
+ hi_found = 1;
+ goto next_inst;
+ }
+ else if (streq(reg_name, "ulo"))
+ {
+ lo_found = 1;
+ goto next_inst;
+ }
+ else if (((r = get_register (reg_name)) == nullregister)
+ || (crx_regtab[r].type != CRX_U_REGTYPE))
+ as_fatal (_("Illegal register `%s' in user register list"), reg_name);
+
+ mask_reg (getreg_image (r - u0), &mask);
+ }
/* General purpose register r<N>. */
else
{
- if ((r = get_register (reg_name)) == nullregister)
- as_bad (_("Illegal register `%s' in register list"), reg_name);
- mask_reg (getreg_image (r), &mask);
+ if (streq(reg_name, "hi"))
+ {
+ hi_found = 1;
+ goto next_inst;
+ }
+ else if (streq(reg_name, "lo"))
+ {
+ lo_found = 1;
+ goto next_inst;
+ }
+ else if (((r = get_register (reg_name)) == nullregister)
+ || (crx_regtab[r].type != CRX_R_REGTYPE))
+ as_fatal (_("Illegal register `%s' in register list"), reg_name);
+
+ mask_reg (getreg_image (r - r0), &mask);
}
if (++reg_counter > MAX_REGS_IN_MASK16)
as_bad (_("Maximum %d bits may be set in `mask16' operand"),
MAX_REGS_IN_MASK16);
+ next_inst:
while (!ISALNUM (*paramP) && *paramP != '}')
paramP++;
}
as_warn (_("rest of line ignored; first ignored character is `%c'"),
*paramP);
- if (mask == 0)
- as_bad (_("Illegal `mask16' operand, operation is undefined - `%s'"),
- ins_parse);
+ switch (hi_found + lo_found)
+ {
+ case 0:
+ /* At least one register should be specified. */
+ if (mask == 0)
+ as_bad (_("Illegal `mask16' operand, operation is undefined - `%s'"),
+ ins_parse);
+ break;
+
+ case 1:
+ /* HI can't be specified without LO (and vise-versa). */
+ as_bad (_("HI/LO registers should be specified together"));
+ break;
+
+ case 2:
+ /* HI/LO registers mustn't be masked with additional registers. */
+ if (mask != 0)
+ as_bad (_("HI/LO registers should be specified without additional registers"));
+
+ default:
+ break;
+ }
sprintf (maskstring, "$0x%x", mask);
strcat (new_param, maskstring);
unsigned int i, j, insn_size;
char *this_frag;
unsigned short words[4];
+ int addr_mod;
/* Arrange the insn encodings in a WORD size array. */
for (i = 0, j = 0; i < 2; i++)
words[j++] = output_opcode[i] & 0xFFFF;
}
- /* Handle relaxtion. */
+ /* Handle relaxation. */
if ((instruction->flags & RELAXABLE) && relocatable)
{
int relax_subtype;
/* bal */
else if (IS_INSN_TYPE (DCR_BRANCH_INS) || IS_INSN_MNEMONIC ("bal"))
relax_subtype = 3;
- /* cmpbr */
- else if (IS_INSN_TYPE (CMPBR_INS))
+ /* cmpbr/bcop */
+ else if (IS_INSN_TYPE (CMPBR_INS) || IS_INSN_TYPE (COP_BRANCH_INS))
relax_subtype = 5;
else
abort ();
}
}
+ /* Verify a 2-byte code alignment. */
+ addr_mod = frag_now_fix () & 1;
+ if (frag_now->has_code && frag_now->insn_addr != addr_mod)
+ as_bad (_("instruction address is not a multiple of 2"));
+ frag_now->insn_addr = addr_mod;
+ frag_now->has_code = 1;
+
/* Write the instruction encoding to frag. */
for (i = 0; i < insn_size; i++)
{
char c;
/* Reset global variables for a new instruction. */
- reset_vars (op, &crx_ins);
+ reset_vars (op);
/* Strip the mnemonic. */
for (param = op; *param != 0 && !ISSPACE (*param); param++)
if (instruction == NULL)
{
as_bad (_("Unknown opcode: `%s'"), op);
+ param[-1] = c;
return;
}
/* Tie dwarf2 debug info to the address at the start of the insn. */
dwarf2_emit_insn (0);
- if (NO_OPERANDS_INST (op))
- /* Handle instructions with no operands. */
- crx_ins.nargs = 0;
- else
- /* Parse the instruction's operands. */
- parse_insn (&crx_ins, param);
+ /* Parse the instruction's operands. */
+ parse_insn (&crx_ins, param);
- /* Assemble the instruction. */
+ /* Assemble the instruction - return upon failure. */
if (assemble_insn (op, &crx_ins) == 0)
{
- as_bad (_("Illegal operands in instruction : `%s'"), ins_parse);
+ param[-1] = c;
return;
}
/* Print the instruction. */
+ param[-1] = c;
print_insn (&crx_ins);
}