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 "safe-ctype.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. */
/* Current instruction we're assembling. */
const inst *instruction;
-/* Initialize global variables. */
+/* Global variables. */
+
+/* Array to hold an instruction encoding. */
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;
+
/* A copy of the original instruction (used in error messages). */
char ins_parse[MAX_INST_LEN];
-/* Holds the current processed argument number. */
-int processing_arg_number;
+
+/* The current processed argument number. */
+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 int get_flags (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 void parse_operand (char *, ins *);
static int gettrap (char *);
static void handle_LoadStor (char *);
static int get_cinv_parameters (char *);
-static unsigned long getconstant (unsigned long, int);
+static long getconstant (long, int);
+static op_err check_range (long *, int, unsigned int, int);
static int getreg_image (reg);
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 the flags of a given operand. */
static int
-get_flags (operand_type op)
+get_opflags (operand_type op)
{
if (op < MAX_OPRD)
return crx_optab[op].flags;
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 = 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
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;
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)
-{
- 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++;
- }
-
- /* Arithmetic instructions :
- 16-bit positive signed immediate -->> represent as 32-bit. */
- if (IS_INSN_TYPE (ARITH_INS) && !relocatable && !signflag)
- {
- if (cnt_bits == 16)
- {
- crx_ins->arg[op_num].size = 32;
- return;
- }
- }
- /* Index addressing mode :
- 6-bit positive signed immediate -->> represent as 22-bit. */
- if (IS_INSN_TYPE (LD_STOR_INS)
- || 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 = 22;
- return;
- }
- if (cnt_bits == 22)
- as_bad (_("Offset out of range in Instruction `%s'"), ins_parse);
- }
- }
- /* load/stor instructions :
- 16-bit positive signed immediate -->> represent as 32-bit. */
- 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 = 32;
- return;
- }
- if (cnt_bits == 32)
- as_bad (_("Offset out of range in Instruction `%s'"), ins_parse);
- }
- }
- /* Post-increment mode :
- 12-bit positive signed immediate -->> represent as 28-bit. */
- 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 = 28;
- 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)
+process_label_constant (char *str, ins * crx_ins)
{
- char *save;
- unsigned long int temp, cnt;
- const cst4_entry *cst4_op;
- int is_cst4=0;
- int constant_val = 0;
- save = input_line_pointer;
- signflag = 0;
-
- if (str[0] == '-')
- {
- signflag = 1;
- str++;
- }
- else if (str[0] == '+')
- str++;
+ char *saved_input_line_pointer;
+ argument *cur_arg = &crx_ins->arg[cur_arg_num]; /* Current argument. */
+ saved_input_line_pointer = input_line_pointer;
input_line_pointer = str;
expression (&crx_ins->exp);
-
+
switch (crx_ins->exp.X_op)
{
case O_big:
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)
- {
- /* 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. */
if (IS_INSN_TYPE (LD_STOR_INS_INC))
- /* 'load/stor <num>(reg)+'. */
crx_ins->rtype = BFD_RELOC_CRX_REGREL12;
else if (IS_INSN_TYPE (CSTBIT_INS)
|| IS_INSN_TYPE (STOR_IMM_INS))
- /* 'stor imm' and '[stc]bit'. */
crx_ins->rtype = BFD_RELOC_CRX_REGREL28;
else
- /* General load/stor 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))
else if (IS_INSN_TYPE (CMPBR_INS) || IS_INSN_TYPE (COP_BRANCH_INS))
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-opearand. */
+ char *operandE; /* Pointer to end of sub-opearand. */
+ expressionS scale;
+ int scale_val;
+ char *input_save, c;
+ argument *cur_arg = &crx_ins->arg[cur_arg_num]; /* Current argument. */
+
+ /* Initialize pointers. */
+ operandS = operandE = operand;
- switch (crx_ins->arg[op_num].type)
+ 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)
+ case arg_sc: /* Case *+0x18. */
+ case arg_ic: /* Case $0x18. */
+ operandS++;
+ 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;
+
+ 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;
+ 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'"),
- reg_name, ins_parse);
+ operandS, ins_parse);
- i++;
- while (operand[i] == ' ')
- i++;
+ 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)
+ 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'"),
- regindex_name, ins_parse);
+ operandS, ins_parse);
- /* Setting the scale parameters. */
- while (operand[i] == ' ')
- i++;
+ /* Skip leading white space. */
+ while (ISSPACE (*operandE))
+ operandE++;
+ operandS = operandE;
- if (operand[i] == ')')
- crx_ins->arg[op_num].scale = 0;
+ /* 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)
- - 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] = '(';
- case arg_rbase:
- 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);
-
- if (crx_ins->arg[op_num].type != arg_rbase)
- crx_ins->arg[op_num].type = arg_cr;
- 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;
+ /* 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 '(':
- crx_ins->arg[number].type = arg_rbase;
- set_cons_rparams (operand, crx_ins, number);
- crx_ins->arg[number].size = REG_SIZE;
- 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]);
}
static void
parse_insn (ins *insn, char *operands)
{
- /* Handle 'excp'/'cinv' */
+ int i;
+
+ /* Handle instructions with no operands. */
+ for (i = 0; no_op_insn[i] != NULL; i++)
+ {
+ if (streq (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;
}
char *reg_name;
int is_procreg = 0; /* Nonzero means argument should be processor reg. */
- if (((IS_INSN_MNEMONIC ("mtpr")) && (processing_arg_number == 1))
- || ((IS_INSN_MNEMONIC ("mfpr")) && (processing_arg_number == 0)) )
+ 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. */
case CRX_C_REGTYPE:
case CRX_CS_REGTYPE:
+ return reg->image;
break;
default:
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));
/* 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 overriden.
+ will be overridden.
0 1 2 3
+---------+---------+---------+---------+
| 'match' | | X X X X | |
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
+--------------------------------+
| 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);
+ case arg_ic:
+ case arg_c:
print_constant (nbits, shift, arg);
break;
case arg_cr:
/* case base_cst4. */
- if ((instruction->flags & DISPU4MAP) && cst4flag)
- output_opcode[0] |= (getconstant (arg->constant, nbits)
- << (shift + REG_SIZE));
+ if (instruction->flags & DISPU4MAP)
+ print_constant (nbits, shift + REG_SIZE, arg);
else
/* rbase_disps<NN> and other such cases. */
print_constant (nbits, shift, arg);
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)
+{
+ long min, max;
+ int retval = OP_LEGAL;
+ int bin;
+ long upper_64kb = 0xFFFF0000;
+ long value = *num;
+
+ /* For hosts witah longs bigger than 32-bits make sure that the top
+ bits of a 32-bit negative value read in by the parser are set,
+ so that the correct comparisons are made. */
+ if (value & 0x80000000)
+ value |= (-1L << 31);
+
+ /* 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)
+ {
+ value >>= 1;
+ 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;
+
+ int mul = (instruction->flags & DISPUB4) ? 1
+ : (instruction->flags & DISPUW4) ? 2
+ : (instruction->flags & DISPUD4) ? 4 : 0;
+
+ for (bin = 0; bin < 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 < cst4_maps; bin++)
+ {
+ if (value == 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 << (bits - 1)) - 1;
+ min = - (1 << (bits - 1));
+ if ((value > max) || (value < min))
+ retval = OP_OUT_OF_RANGE;
+ }
+ else if (flags & OP_UNSIGNED)
+ {
+ max = ((((1 << (bits - 1)) - 1) << 1) | 1);
+ min = 0;
+ if (((unsigned long) value > (unsigned long) max)
+ || ((unsigned long) value < (unsigned long) min))
+ 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. */
- int ins_type;
+ unsigned int ins_type;
+ /* Boolean flag to mark whether a match was found. */
int match = 0;
- int done_flag = 0;
- int dispu4map_type = 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++;
-
- 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;
-
/* 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.
during a search for matching instruction. */
ins_type = CRX_INS_TYPE(instruction->flags);
- 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. */
/* 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)
- {
- for (i = 0; i < insn->nargs; i++)
+ if (cur_type[i] != insn->arg[i].type)
{
- if ((get_flags (instruction->operands[i].op_type) & OPERAND_UNSIGNED)
- && (insn->arg[i].signflag))
- {
- done_flag = 0;
- break;
- }
+ 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)
{
- /* 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))
+ /* 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)
{
- /* 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);
+ 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;
}
+ }
+
+ return 0;
+ }
+ else
+ /* Full match - print the encoding to output file. */
+ {
+ /* Make further checkings (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;
- /* 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) && !relocatable)
- {
- if ((instruction->operands[1].op_type == rbase_disps12)
- && (insn->arg[1].constant == 0))
- {
- instruction--;
- GET_ACTUAL_SIZE;
- }
- }
-
- /* 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)
+ for (i = 0; i < insn->nargs; i++)
{
- if (getreg_image (insn->arg[0].r) == getreg_image (sp))
- as_bad (_("`%s' has undefined result"), ins_parse);
+ 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);
}
- /* 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));
- }
+ /* First, copy the instruction's opcode. */
+ output_opcode[0] = BIN (instruction->match, instruction->match_bits);
- /* Handle positive constants. */
- if (!signflag)
+ for (i = 0; i < insn->nargs; i++)
{
- if ((instruction->flags & DISPU4MAP) && !relocatable)
- {
- /* Get the map type of the instruction. */
- instrtype = instruction->flags & REVERSE_MATCH ? 0 : 1;
- cons = &insn->arg[instrtype].constant;
- dispu4map_type = instruction->flags & DISPU4MAP;
-
- switch (dispu4map_type)
- {
- 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:
- as_bad (_("Invalid DISPU4 type"));
- break;
- }
- }
+ cur_arg_num = i;
+ print_operand (cur_size[i], instruction->operands[i].shift,
+ &insn->arg[i]);
+ }
+ }
- /* Check whether a cst4 mapping has to be done. */
- if ((instruction->flags & CST4MAP) && !relocatable)
- {
- /* '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;
- }
- }
- }
- }
+ return 1;
+}
- /* 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 (CSTBIT_INS)
- || IS_INSN_TYPE (STOR_IMM_INS)) & !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;
- }
- }
+/* Bunch of error checkings.
+ The checks are made after a matching instruction was found. */
- for (i = 0; i < insn->nargs; i++)
- {
- /* Mark a CST4 argument, if exists. */
- if (get_flags (instruction->operands[i].op_type) & OPERAND_CST4)
- cst4flag = 1;
+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);
+ }
- /* Handle reserved escape sequences. */
- if ((get_flags (instruction->operands[i].op_type) & OPERAND_ESC)
- && !relocatable)
- {
- /* 0x7e and 0x7f are reserved escape sequences of dispe9. */
- if (insn->arg[i].constant == 0x7e || insn->arg[i].constant == 0x7f)
- {
- /* Use a disps17 for these values. */
- instruction++;
- GET_ACTUAL_SIZE;
- }
- }
- }
+ /* 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);
+ }
- /* First, copy the instruction's opcode. */
- output_opcode[0] = BIN (instruction->match, instruction->match_bits);
+ /* 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));
+ }
+}
- /* Swap the argument values in case bcop instructions. */
- if (IS_INSN_TYPE (COP_BRANCH_INS))
- {
- temp_value = insn->arg[0].constant;
- insn->arg[0].constant = insn->arg[1].constant;
- insn->arg[1].constant = temp_value;
- }
+/* 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. */
- for (i = 0; i < insn->nargs; i++)
+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'.
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++)
/* 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++)
/* 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);
- return;
- }
+ return;
/* Print the instruction. */
print_insn (&crx_ins);