+void
+mn10300_cons_fix_new (fragS *frag, int off, int size, expressionS *exp,
+ bfd_reloc_code_real_type r ATTRIBUTE_UNUSED)
+{
+ struct mn10300_fixup fixup;
+
+ fixup.opindex = -1;
+ fixup.exp = *exp;
+ fixup.reloc = BFD_RELOC_UNUSED;
+
+ mn10300_check_fixup (&fixup);
+
+ if (fixup.reloc == BFD_RELOC_MN10300_GOT32)
+ switch (size)
+ {
+ case 2:
+ fixup.reloc = BFD_RELOC_MN10300_GOT16;
+ break;
+
+ case 3:
+ fixup.reloc = BFD_RELOC_MN10300_GOT24;
+ break;
+
+ case 4:
+ break;
+
+ default:
+ goto error;
+ }
+ else if (fixup.reloc == BFD_RELOC_UNUSED)
+ switch (size)
+ {
+ case 1:
+ fixup.reloc = BFD_RELOC_8;
+ break;
+
+ case 2:
+ fixup.reloc = BFD_RELOC_16;
+ break;
+
+ case 3:
+ fixup.reloc = BFD_RELOC_24;
+ break;
+
+ case 4:
+ fixup.reloc = BFD_RELOC_32;
+ break;
+
+ default:
+ goto error;
+ }
+ else if (size != 4)
+ {
+ error:
+ as_bad (_("unsupported BFD relocation size %u"), size);
+ fixup.reloc = BFD_RELOC_UNUSED;
+ }
+
+ fix_new_exp (frag, off, size, &fixup.exp, 0, fixup.reloc);
+}
+
+static bfd_boolean
+check_operand (const struct mn10300_operand *operand,
+ offsetT val)
+{
+ /* No need to check 32bit operands for a bit. Note that
+ MN10300_OPERAND_SPLIT is an implicit 32bit operand. */
+ if (operand->bits != 32
+ && (operand->flags & MN10300_OPERAND_SPLIT) == 0)
+ {
+ long min, max;
+ offsetT test;
+ int bits;
+
+ bits = operand->bits;
+ if (operand->flags & MN10300_OPERAND_24BIT)
+ bits = 24;
+
+ if ((operand->flags & MN10300_OPERAND_SIGNED) != 0)
+ {
+ max = (1 << (bits - 1)) - 1;
+ min = - (1 << (bits - 1));
+ }
+ else
+ {
+ max = (1 << bits) - 1;
+ min = 0;
+ }
+
+ test = val;
+
+ if (test < (offsetT) min || test > (offsetT) max)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* Insert an operand value into an instruction. */
+
+static void
+mn10300_insert_operand (unsigned long *insnp,
+ unsigned long *extensionp,
+ const struct mn10300_operand *operand,
+ offsetT val,
+ char *file,
+ unsigned int line,
+ unsigned int shift)
+{
+ /* No need to check 32bit operands for a bit. Note that
+ MN10300_OPERAND_SPLIT is an implicit 32bit operand. */
+ if (operand->bits != 32
+ && (operand->flags & MN10300_OPERAND_SPLIT) == 0)
+ {
+ long min, max;
+ offsetT test;
+ int bits;
+
+ bits = operand->bits;
+ if (operand->flags & MN10300_OPERAND_24BIT)
+ bits = 24;
+
+ if ((operand->flags & MN10300_OPERAND_SIGNED) != 0)
+ {
+ max = (1 << (bits - 1)) - 1;
+ min = - (1 << (bits - 1));
+ }
+ else
+ {
+ max = (1 << bits) - 1;
+ min = 0;
+ }
+
+ test = val;
+
+ if (test < (offsetT) min || test > (offsetT) max)
+ as_warn_value_out_of_range (_("operand"), test, (offsetT) min, (offsetT) max, file, line);
+ }
+
+ if ((operand->flags & MN10300_OPERAND_SPLIT) != 0)
+ {
+ *insnp |= (val >> (32 - operand->bits)) & ((1 << operand->bits) - 1);
+ *extensionp |= ((val & ((1 << (32 - operand->bits)) - 1))
+ << operand->shift);
+ }
+ else if ((operand->flags & MN10300_OPERAND_24BIT) != 0)
+ {
+ *insnp |= (val >> (24 - operand->bits)) & ((1 << operand->bits) - 1);
+ *extensionp |= ((val & ((1 << (24 - operand->bits)) - 1))
+ << operand->shift);
+ }
+ else if ((operand->flags & (MN10300_OPERAND_FSREG | MN10300_OPERAND_FDREG)))
+ {
+ /* See devo/opcodes/m10300-opc.c just before #define FSM0 for an
+ explanation of these variables. Note that FMT-implied shifts
+ are not taken into account for FP registers. */
+ unsigned long mask_low, mask_high;
+ int shl_low, shr_high, shl_high;
+
+ switch (operand->bits)
+ {
+ case 5:
+ /* Handle regular FP registers. */
+ if (operand->shift >= 0)
+ {
+ /* This is an `m' register. */
+ shl_low = operand->shift;
+ shl_high = 8 + (8 & shl_low) + (shl_low & 4) / 4;
+ }
+ else
+ {
+ /* This is an `n' register. */
+ shl_low = -operand->shift;
+ shl_high = shl_low / 4;
+ }
+
+ mask_low = 0x0f;
+ mask_high = 0x10;
+ shr_high = 4;
+ break;
+
+ case 3:
+ /* Handle accumulators. */
+ shl_low = -operand->shift;
+ shl_high = 0;
+ mask_low = 0x03;
+ mask_high = 0x04;
+ shr_high = 2;
+ break;
+
+ default:
+ abort ();
+ }
+ *insnp |= ((((val & mask_high) >> shr_high) << shl_high)
+ | ((val & mask_low) << shl_low));
+ }
+ else if ((operand->flags & MN10300_OPERAND_EXTENDED) == 0)
+ {
+ *insnp |= (((long) val & ((1 << operand->bits) - 1))
+ << (operand->shift + shift));
+
+ if ((operand->flags & MN10300_OPERAND_REPEATED) != 0)
+ *insnp |= (((long) val & ((1 << operand->bits) - 1))
+ << (operand->shift + shift + operand->bits));
+ }
+ else
+ {
+ *extensionp |= (((long) val & ((1 << operand->bits) - 1))
+ << (operand->shift + shift));
+
+ if ((operand->flags & MN10300_OPERAND_REPEATED) != 0)
+ *extensionp |= (((long) val & ((1 << operand->bits) - 1))
+ << (operand->shift + shift + operand->bits));
+ }
+}
+
+void
+md_assemble (char *str)
+{
+ char *s;
+ struct mn10300_opcode *opcode;
+ struct mn10300_opcode *next_opcode;
+ const unsigned char *opindex_ptr;
+ int next_opindex, relaxable;
+ unsigned long insn, extension, size = 0;
+ char *f;
+ int i;
+ int match;
+
+ /* Get the opcode. */
+ for (s = str; *s != '\0' && !ISSPACE (*s); s++)
+ ;
+ if (*s != '\0')
+ *s++ = '\0';
+
+ /* Find the first opcode with the proper name. */
+ opcode = (struct mn10300_opcode *) hash_find (mn10300_hash, str);
+ if (opcode == NULL)
+ {
+ as_bad (_("Unrecognized opcode: `%s'"), str);
+ return;
+ }
+
+ str = s;
+ while (ISSPACE (*str))
+ ++str;
+
+ input_line_pointer = str;
+
+ for (;;)
+ {
+ const char *errmsg;
+ int op_idx;
+ char *hold;
+ int extra_shift = 0;
+
+ errmsg = _("Invalid opcode/operands");
+
+ /* Reset the array of register operands. */
+ memset (mn10300_reg_operands, -1, sizeof (mn10300_reg_operands));
+
+ relaxable = 0;
+ fc = 0;
+ match = 0;
+ next_opindex = 0;
+ insn = opcode->opcode;
+ extension = 0;
+
+ /* If the instruction is not available on the current machine
+ then it can not possibly match. */
+ if (opcode->machine
+ && !(opcode->machine == AM33_2 && HAVE_AM33_2)
+ && !(opcode->machine == AM33 && HAVE_AM33)
+ && !(opcode->machine == AM30 && HAVE_AM30))
+ goto error;
+
+ for (op_idx = 1, opindex_ptr = opcode->operands;
+ *opindex_ptr != 0;
+ opindex_ptr++, op_idx++)
+ {
+ const struct mn10300_operand *operand;
+ expressionS ex;
+
+ if (next_opindex == 0)
+ {
+ operand = &mn10300_operands[*opindex_ptr];
+ }
+ else
+ {
+ operand = &mn10300_operands[next_opindex];
+ next_opindex = 0;
+ }