diff options
Diffstat (limited to 'gas/config/tc-microblaze.c')
-rw-r--r-- | gas/config/tc-microblaze.c | 77 |
1 files changed, 76 insertions, 1 deletions
diff --git a/gas/config/tc-microblaze.c b/gas/config/tc-microblaze.c index d900a9e..554c1d7 100644 --- a/gas/config/tc-microblaze.c +++ b/gas/config/tc-microblaze.c @@ -915,7 +915,7 @@ md_assemble (char * str) unsigned reg2; unsigned reg3; unsigned isize; - unsigned int immed = 0, temp; + unsigned int immed = 0, immed2 = 0, temp; expressionS exp; char name[20]; @@ -1177,6 +1177,77 @@ md_assemble (char * str) inst |= (immed << IMM_LOW) & IMM5_MASK; break; + case INST_TYPE_RD_R1_IMM5_IMM5: + if (strcmp (op_end, "")) + op_end = parse_reg (op_end + 1, ®1); /* Get rd. */ + else + { + as_fatal (_("Error in statement syntax")); + reg1 = 0; + } + if (strcmp (op_end, "")) + op_end = parse_reg (op_end + 1, ®2); /* Get r1. */ + else + { + as_fatal (_("Error in statement syntax")); + reg2 = 0; + } + + /* Check for spl registers. */ + if (check_spl_reg (®1)) + as_fatal (_("Cannot use special register with this instruction")); + if (check_spl_reg (®2)) + as_fatal (_("Cannot use special register with this instruction")); + + /* Width immediate value. */ + if (strcmp (op_end, "")) + op_end = parse_imm (op_end + 1, &exp, MIN_IMM_WIDTH, MAX_IMM_WIDTH); + else + as_fatal (_("Error in statement syntax")); + if (exp.X_op != O_constant) + { + as_warn (_("Symbol used as immediate width value for bit field instruction")); + immed = 1; + } + else + immed = exp.X_add_number; + if (opcode->instr == bsefi && immed > 31) + as_fatal (_("Width value must be less than 32")); + + /* Shift immediate value. */ + if (strcmp (op_end, "")) + op_end = parse_imm (op_end + 1, &exp, MIN_IMM, MAX_IMM); + else + as_fatal (_("Error in statement syntax")); + if (exp.X_op != O_constant) + { + as_warn (_("Symbol used as immediate shift value for bit field instruction")); + immed2 = 0; + } + else + { + output = frag_more (isize); + immed2 = exp.X_add_number; + } + if (immed2 != (immed2 % 32)) + { + as_warn (_("Shift value greater than 32. using <value %% 32>")); + immed2 = immed2 % 32; + } + + /* Check combined value. */ + if (immed + immed2 > 32) + as_fatal (_("Width value + shift value must not be greater than 32")); + + inst |= (reg1 << RD_LOW) & RD_MASK; + inst |= (reg2 << RA_LOW) & RA_MASK; + if (opcode->instr == bsefi) + inst |= (immed & IMM5_MASK) << IMM_WIDTH_LOW; /* bsefi */ + else + inst |= ((immed + immed2 - 1) & IMM5_MASK) << IMM_WIDTH_LOW; /* bsifi */ + inst |= (immed2 << IMM_LOW) & IMM5_MASK; + break; + case INST_TYPE_R1_R2: if (strcmp (op_end, "")) op_end = parse_reg (op_end + 1, ®1); /* Get r1. */ @@ -2209,9 +2280,12 @@ md_apply_fix (fixS * fixP, moves code around due to relaxing. */ if (fixP->fx_r_type == BFD_RELOC_64_PCREL) fixP->fx_r_type = BFD_RELOC_MICROBLAZE_64_NONE; + else if (fixP->fx_r_type == BFD_RELOC_32) + fixP->fx_r_type = BFD_RELOC_MICROBLAZE_32_NONE; else fixP->fx_r_type = BFD_RELOC_NONE; fixP->fx_addsy = section_symbol (absolute_section); + fixP->fx_done = 0; } return; } @@ -2432,6 +2506,7 @@ tc_gen_reloc (asection * section ATTRIBUTE_UNUSED, fixS * fixp) switch (fixp->fx_r_type) { case BFD_RELOC_NONE: + case BFD_RELOC_MICROBLAZE_32_NONE: case BFD_RELOC_MICROBLAZE_64_NONE: case BFD_RELOC_32: case BFD_RELOC_MICROBLAZE_32_LO: |