From 0d082ff02a9c8b80b44aede5599417bcfb4d3685 Mon Sep 17 00:00:00 2001 From: Tomer Levi Date: Wed, 27 Oct 2004 10:28:22 +0000 Subject: [PATCH] * 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. --- gas/config/tc-crx.c | 535 ++++++++++++++++++++++++++-------------------------- 1 file changed, 270 insertions(+), 265 deletions(-) diff --git a/gas/config/tc-crx.c b/gas/config/tc-crx.c index e3145f5b5f..3f75ffff24 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 (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 and other such cases. */ + /* rbase_disps 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. */ 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. */ 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. */ + 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. */ 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); -- 2.11.0