aboutsummaryrefslogtreecommitdiff
path: root/gas
diff options
context:
space:
mode:
authorTomer Levi <Tomer.Levi@nsc.com>2004-10-27 10:28:22 +0000
committerTomer Levi <Tomer.Levi@nsc.com>2004-10-27 10:28:22 +0000
commit9bb1ebc211827bb6994d04e66ec8fe4db6809c0a (patch)
tree315b68c78a935b8f4a696286e0d5867a1e308881 /gas
parent812337be05c3c8f929ccc87f518b8d00c8ac20e8 (diff)
downloadfsf-binutils-gdb-9bb1ebc211827bb6994d04e66ec8fe4db6809c0a.zip
fsf-binutils-gdb-9bb1ebc211827bb6994d04e66ec8fe4db6809c0a.tar.gz
fsf-binutils-gdb-9bb1ebc211827bb6994d04e66ec8fe4db6809c0a.tar.bz2
* config/tc-crx.c: Remove global variable 'post_inc_mode'.
(get_flags): New function. (get_number_of_bits): Edit comments, update numeric values to supported sizes. (process_label_constant): Don't support the colon format (SYMBOL:[s|m|l]). (set_cons_rparams): Support argument type 'arg_rbase'. (get_operandtype): Bug fix in 'rbase' operand type parsing. (handle_LoadStor): Bug fix, first handle post-increment mode. (getreg_image): Remove redundant code, update according to latest CRX spec. (print_constant): Bug fix relate to 3-word instructions. (assemble_insn): Bug fix, when matching instructions, verify also instruction type (not only mnemonic). Add various error checking. (preprocess_reglist): Support HI/LO and user registers.
Diffstat (limited to 'gas')
-rw-r--r--gas/config/tc-crx.c535
1 files changed, 270 insertions, 265 deletions
diff --git a/gas/config/tc-crx.c b/gas/config/tc-crx.c
index e3145f5..3f75fff 100644
--- a/gas/config/tc-crx.c
+++ b/gas/config/tc-crx.c
@@ -98,8 +98,6 @@ int signflag;
int cst4flag;
/* 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;
@@ -163,6 +161,7 @@ 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 int get_number_of_operands (void);
static void get_operandtype (char *, int, ins *);
static int gettrap (char *);
@@ -206,6 +205,17 @@ getarg_type (operand_type op)
return nullargs;
}
+/* Return the flags of a given operand. */
+
+static int
+get_flags (operand_type op)
+{
+ if (op < MAX_OPRD)
+ return crx_optab[op].flags;
+ else
+ return 0;
+}
+
/* Get the core processor register 'reg_name'. */
static reg
@@ -281,7 +291,7 @@ reset_vars (char *op, ins *crx_ins)
unsigned int i;
processing_arg_number = relocatable = size_was_set
- = signflag = post_inc_mode = cst4flag = 0;
+ = signflag = cst4flag = 0;
memset (& output_opcode, '\0', sizeof (output_opcode));
/* Memset the 'signflag' field in every argument. */
@@ -598,10 +608,9 @@ md_begin (void)
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;
@@ -626,7 +635,8 @@ md_begin (void)
}
/* Initialize reg_hash hash table. */
- reg_hash = hash_new ();
+ if ((reg_hash = hash_new ()) == NULL)
+ as_fatal (_("Virtual memory exhausted"));
{
const reg_entry *regtab;
@@ -643,7 +653,8 @@ md_begin (void)
}
/* Initialize copreg_hash hash table. */
- copreg_hash = hash_new ();
+ if ((copreg_hash = hash_new ()) == NULL)
+ as_fatal (_("Virtual memory exhausted"));
{
const reg_entry *copregtab;
@@ -683,18 +694,19 @@ get_number_of_bits (ins * crx_ins, int op_num)
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 = 17;
+ crx_ins->arg[op_num].size = 32;
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. */
+ /* Index addressing mode :
+ 6-bit positive signed immediate -->> represent as 22-bit. */
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))
{
@@ -702,31 +714,30 @@ get_number_of_bits (ins * crx_ins, int op_num)
{
if (cnt_bits == 6)
{
- crx_ins->arg[op_num].size = 7;
+ crx_ins->arg[op_num].size = 22;
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. */
+ /* 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 = 17;
+ 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))
@@ -735,7 +746,7 @@ get_number_of_bits (ins * crx_ins, int op_num)
{
if (cnt_bits == 12)
{
- crx_ins->arg[op_num].size = 13;
+ 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;
@@ -799,6 +810,7 @@ get_number_of_bits (ins * crx_ins, int op_num)
crx_ins->arg[op_num].size = 33;
return;
}
+
if (signflag && !relocatable)
return;
@@ -831,8 +843,6 @@ process_label_constant (char *str, ins * crx_ins, int number)
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;
@@ -844,35 +854,6 @@ process_label_constant (char *str, ins * crx_ins, int number)
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;
-
- 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';
- }
input_line_pointer = str;
expression (&crx_ins->exp);
@@ -1076,8 +1057,7 @@ process_label_constant (char *str, ins * crx_ins, int number)
}
}
}
- if (IS_INSN_TYPE (LD_STOR_INS) && crx_ins->arg[number].type == arg_cr
- && !post_inc_mode)
+ if (IS_INSN_TYPE (LD_STOR_INS) && crx_ins->arg[number].type == arg_cr)
{
/* Cases handled ---
dispub4/dispuw4/dispud4 and for load store dispubwd4
@@ -1160,15 +1140,16 @@ process_label_constant (char *str, ins * crx_ins, int number)
switch (crx_ins->arg[number].type)
{
case arg_cr:
- /* Have to consider various cases here --load/stor++[bwd] rbase, reg. */
+ /* 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[bwd] imm' and '[stc]bit[bwd]'. */
+ /* 'stor imm' and '[stc]bit'. */
crx_ins->rtype = BFD_RELOC_CRX_REGREL28;
else
- /* General load store instruction. */
+ /* General load/stor instruction. */
crx_ins->rtype = BFD_RELOC_CRX_REGREL32;
break;
case arg_icr:
@@ -1182,37 +1163,14 @@ process_label_constant (char *str, ins * crx_ins, int number)
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:
@@ -1350,9 +1308,9 @@ set_indexmode_parameters (char *operand, ins * crx_ins, int op_num)
/* Parsing the operands of types
- constants
- - rbase -> (register)
+ - (rbase)
- offset(rbase)
- - offset(rbase)+ - post increment mode. */
+ - offset(rbase)+ (post-increment mode). */
static void
set_cons_rparams (char *operand, ins * crx_ins, int op_num)
@@ -1381,6 +1339,7 @@ set_cons_rparams (char *operand, ins * crx_ins, int op_num)
operand[i] = '\0';
process_label_constant (operand, crx_ins, op_num);
operand[i] = '(';
+ case arg_rbase:
i++;
reg_count = 0;
while (operand[i] != ')')
@@ -1394,11 +1353,8 @@ set_cons_rparams (char *operand, ins * crx_ins, int op_num)
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;
+ if (crx_ins->arg[op_num].type != arg_rbase)
+ crx_ins->arg[op_num].type = arg_cr;
break;
default:
break;
@@ -1416,7 +1372,6 @@ static void
get_operandtype (char *operand, int number, ins * crx_ins)
{
int ret_val;
- char temp_operand[30];
switch (operand[0])
{
@@ -1484,32 +1439,9 @@ get_operandtype (char *operand, int number, ins * crx_ins)
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;
- }
+ 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;
@@ -1677,18 +1609,25 @@ gettrap (char *s)
static void
handle_LoadStor (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++;
}
@@ -1758,15 +1697,11 @@ getreg_image (reg r)
{
const reg_entry *reg;
char *reg_name;
- int special_register_flag = 0;
- int movpr_flag = 0; /* Nonzero means current mnemonic is 'mtpr'/'mfpr' */
-
- if (IS_INSN_MNEMONIC ("mtpr") || IS_INSN_MNEMONIC ("mfpr"))
- movpr_flag = 1;
+ 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)) )
- special_register_flag = 1;
+ is_procreg = 1;
/* Check whether the register is in registers table. */
if (r < MAX_REG)
@@ -1792,21 +1727,27 @@ getreg_image (reg r)
switch (reg->type)
{
case CRX_U_REGTYPE:
+ if (is_procreg || (instruction->flags & USER_REG))
+ return reg->image;
+ else
+ IMAGE_ERR;
+
case CRX_CFG_REGTYPE:
- case CRX_MTPR_REGTYPE:
- if (movpr_flag && special_register_flag)
+ if (is_procreg)
return reg->image;
else
IMAGE_ERR;
case CRX_R_REGTYPE:
- case CRX_C_REGTYPE:
- case CRX_CS_REGTYPE:
- if (!(movpr_flag && special_register_flag))
+ if (! is_procreg)
return reg->image;
else
IMAGE_ERR;
+ case CRX_C_REGTYPE:
+ case CRX_CS_REGTYPE:
+ break;
+
default:
IMAGE_ERR;
}
@@ -1891,9 +1832,17 @@ print_constant (int nbits, int shift, argument *arg)
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 overriden.
+ 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);
@@ -1941,7 +1890,7 @@ print_operand (int nbits, int shift, argument *arg)
case arg_icr:
/* 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);
@@ -1955,11 +1904,11 @@ print_operand (int nbits, int shift, argument *arg)
case arg_cr:
/* case base_cst4. */
- if ((instruction->flags & CST4MAP) && cst4flag)
+ if ((instruction->flags & DISPU4MAP) && cst4flag)
output_opcode[0] |= (getconstant (arg->constant, nbits)
<< (shift + REG_SIZE));
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);
@@ -2010,9 +1959,11 @@ assemble_insn (char *mnemonic, ins *insn)
int bits_act[MAX_OPERANDS];
/* Location (in bits) of each operand in the current instruction. */
int shift_act[MAX_OPERANDS];
+ /* Instruction type to match. */
+ int ins_type;
int match = 0;
int done_flag = 0;
- int cst4maptype = 0;
+ int dispu4map_type = 0;
int changed_already = 0;
unsigned int temp_value = 0;
int instrtype, i;
@@ -2047,11 +1998,21 @@ assemble_insn (char *mnemonic, ins *insn)
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.
+ 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);
+
while (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. */
for (i = 0; i < insn->nargs; i++)
@@ -2064,25 +2025,17 @@ assemble_insn (char *mnemonic, ins *insn)
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 (done_flag)
{
for (i = 0; i < insn->nargs; i++)
{
- if (((instruction->operands[i].op_type == us3)
- || (instruction->operands[i].op_type == us4)
- || (instruction->operands[i].op_type == us5))
- && (insn->arg[i].signflag == 1))
- {
- done_flag = 0;
- break;
- }
+ if ((get_flags (instruction->operands[i].op_type) & OPERAND_UNSIGNED)
+ && (insn->arg[i].signflag))
+ {
+ done_flag = 0;
+ break;
+ }
}
}
@@ -2126,33 +2079,58 @@ assemble_insn (char *mnemonic, ins *insn)
else
/* Full match - print the final image. */
{
- /* 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))
+ /* 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))
{
- /* The coprocessor id is always the first argument. */
- if ((instruction->operands[0].op_type == us4)
- && (insn->arg[0].constant == 0)
- && (! IS_INSN_MNEMONIC ("mtcr")
- && ! IS_INSN_MNEMONIC ("mfcr")))
- {
- as_bad (_("Internal Coprocessor 0 doesn't support instruction `%s'"),
- mnemonic);
- }
+ /* 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);
}
+
+ /* 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)
+ {
+ 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));
+ }
+
/* Handle positive constants. */
if (!signflag)
{
- if (IS_INSN_TYPE (LD_STOR_INS) && !relocatable)
+ if ((instruction->flags & DISPU4MAP) && !relocatable)
{
/* Get the map type of the instruction. */
instrtype = instruction->flags & REVERSE_MATCH ? 0 : 1;
cons = &insn->arg[instrtype].constant;
- cst4maptype = instruction->flags & CST4MAP;
+ dispu4map_type = instruction->flags & DISPU4MAP;
- switch (cst4maptype)
+ switch (dispu4map_type)
{
case DISPUB4:
/* 14 and 15 are reserved escape sequences of dispub4. */
@@ -2195,93 +2173,62 @@ assemble_insn (char *mnemonic, ins *insn)
*cons /= 4;
break;
default:
+ as_bad (_("Invalid DISPU4 type"));
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
+
+ /* 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++)
{
- /* 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)
{
- /* '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;
- }
+ 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)
+
+ /* Special check for 'addub 0, r0' instruction -
+ The opcode '0000 0000 0000 0000' is not allowed. */
+ if (IS_INSN_MNEMONIC ("addub"))
{
- if (instruction->operands[1].op_type == rbase_dispu12)
+ if ((instruction->operands[0].op_type == cst4)
+ && instruction->operands[1].op_type == regr)
{
- if (insn->arg[1].constant == 0)
- {
- instruction--;
- GET_ACTUAL_SIZE;
- }
+ 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)
- || IS_INSN_TYPE (LD_STOR_INS_INC)) & !relocatable)
+ || IS_INSN_TYPE (STOR_IMM_INS)) & !relocatable)
{
instrtype = instruction->flags & REVERSE_MATCH ? 0 : 1;
changed_already = 0;
@@ -2310,23 +2257,27 @@ assemble_insn (char *mnemonic, ins *insn)
}
changed_already = 0;
}
- if (IS_INSN_TYPE (BRANCH_INS) && !relocatable)
+ }
+
+ 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;
+
+ /* 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[0].constant == 0x7e || insn->arg[0].constant == 0x7f)
+ if (insn->arg[i].constant == 0x7e || insn->arg[i].constant == 0x7f)
{
+ /* Use a disps17 for these values. */
instruction++;
GET_ACTUAL_SIZE;
}
}
- }
-
- for (i = 0; i < insn->nargs; i++)
- {
- if (instruction->operands[i].op_type == cst4
- || instruction->operands[i].op_type == rbase_cst4)
- cst4flag = 1;
- }
+ }
/* First, copy the instruction's opcode. */
output_opcode[0] = BIN (instruction->match, instruction->match_bits);
@@ -2381,6 +2332,7 @@ preprocess_reglist (char *param, int *allocated)
char *new_param; /* New created operands string. */
char *paramP = param; /* Pointer to original opearands 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;
@@ -2411,30 +2363,64 @@ preprocess_reglist (char *param, int *allocated)
/* 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++;
}
@@ -2443,9 +2429,28 @@ preprocess_reglist (char *param, int *allocated)
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);