* 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.
This commit is contained in:
Tomer Levi 2004-10-27 10:28:22 +00:00
parent 812337be05
commit 9bb1ebc211

View file

@ -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)
/* 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++)
{
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)
{
/* '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++;
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)
/* 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)
{
/* 0x7e and 0x7f are reserved escape sequences of dispe9. */
if (insn->arg[0].constant == 0x7e || insn->arg[0].constant == 0x7f)
{
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;
}
/* 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[i].constant == 0x7e || insn->arg[i].constant == 0x7f)
{
/* Use a disps17 for these values. */
instruction++;
GET_ACTUAL_SIZE;
}
}
}
/* 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);