+
+void
+d10v_frob_label (symbolS *lab)
+{
+ d10v_cleanup ();
+ symbol_set_frag (lab, frag_now);
+ S_SET_VALUE (lab, (valueT) frag_now_fix ());
+ dwarf2_emit_label (lab);
+}
+
+/* Like normal .word, except support @word.
+ Clobbers input_line_pointer, checks end-of-line. */
+
+static void
+d10v_dot_word (int dummy ATTRIBUTE_UNUSED)
+{
+ expressionS exp;
+ char *p;
+
+ if (is_it_end_of_statement ())
+ {
+ demand_empty_rest_of_line ();
+ return;
+ }
+
+ do
+ {
+ expression (&exp);
+ if (!strncasecmp (input_line_pointer, "@word", 5))
+ {
+ exp.X_add_number = 0;
+ input_line_pointer += 5;
+
+ p = frag_more (2);
+ fix_new_exp (frag_now, p - frag_now->fr_literal, 2,
+ &exp, 0, BFD_RELOC_D10V_18);
+ }
+ else
+ emit_expr (&exp, 2);
+ }
+ while (*input_line_pointer++ == ',');
+
+ input_line_pointer--; /* Put terminator back into stream. */
+ demand_empty_rest_of_line ();
+}
+
+/* Mitsubishi asked that we support some old syntax that apparently
+ had immediate operands starting with '#'. This is in some of their
+ sample code but is not documented (although it appears in some
+ examples in their assembler manual). For now, we'll solve this
+ compatibility problem by simply ignoring any '#' at the beginning
+ of an operand. */
+
+/* Operands that begin with '#' should fall through to here.
+ From expr.c. */
+
+void
+md_operand (expressionS *expressionP)
+{
+ if (*input_line_pointer == '#' && ! do_not_ignore_hash)
+ {
+ input_line_pointer++;
+ expression (expressionP);
+ }
+}
+
+bfd_boolean
+d10v_fix_adjustable (fixS *fixP)
+{
+ /* We need the symbol name for the VTABLE entries. */
+ if (fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
+ || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
+ return 0;
+
+ return 1;
+}
+
+/* The target specific pseudo-ops which we support. */
+const pseudo_typeS md_pseudo_table[] =
+{
+ { "word", d10v_dot_word, 2 },
+ { NULL, NULL, 0 }
+};
+
+void
+md_assemble (char *str)
+{
+ /* etype is saved extype. For multi-line instructions. */
+ packing_type extype = PACK_UNSPEC; /* Parallel, etc. */
+ struct d10v_opcode *opcode;
+ unsigned long insn;
+ char *str2;
+
+ if (etype == PACK_UNSPEC)
+ {
+ /* Look for the special multiple instruction separators. */
+ str2 = strstr (str, "||");
+ if (str2)
+ extype = PACK_PARALLEL;
+ else
+ {
+ str2 = strstr (str, "->");
+ if (str2)
+ extype = PACK_LEFT_RIGHT;
+ else
+ {
+ str2 = strstr (str, "<-");
+ if (str2)
+ extype = PACK_RIGHT_LEFT;
+ }
+ }
+
+ /* str2 points to the separator, if there is one. */
+ if (str2)
+ {
+ *str2 = 0;
+
+ /* If two instructions are present and we already have one saved,
+ then first write out the saved one. */
+ d10v_cleanup ();
+
+ /* Assemble first instruction and save it. */
+ prev_insn = do_assemble (str, &prev_opcode);
+ prev_seg = now_seg;
+ prev_subseg = now_subseg;
+ if (prev_insn == (unsigned long) -1)
+ as_fatal (_("can't find previous opcode "));
+ fixups = fixups->next;
+ str = str2 + 2;
+ }
+ }
+
+ insn = do_assemble (str, &opcode);
+ if (insn == (unsigned long) -1)
+ {
+ if (extype != PACK_UNSPEC)
+ etype = extype;
+ else
+ as_bad (_("could not assemble: %s"), str);
+ return;
+ }
+
+ if (etype != PACK_UNSPEC)
+ {
+ extype = etype;
+ etype = PACK_UNSPEC;
+ }
+
+ /* If this is a long instruction, write it and any previous short
+ instruction. */
+ if (opcode->format & LONG_OPCODE)
+ {
+ if (extype != PACK_UNSPEC)
+ as_fatal (_("Unable to mix instructions as specified"));
+ d10v_cleanup ();
+ write_long (insn, fixups);
+ prev_opcode = NULL;
+ return;
+ }
+
+ if (prev_opcode
+ && prev_seg
+ && ((prev_seg != now_seg) || (prev_subseg != now_subseg)))
+ d10v_cleanup ();
+
+ if (prev_opcode
+ && (0 == write_2_short (prev_opcode, prev_insn, opcode, insn, extype,
+ fixups)))
+ {
+ /* No instructions saved. */
+ prev_opcode = NULL;
+ }
+ else
+ {
+ if (extype != PACK_UNSPEC)
+ as_fatal (_("Unable to mix instructions as specified"));
+ /* Save last instruction so it may be packed on next pass. */
+ prev_opcode = opcode;
+ prev_insn = insn;
+ prev_seg = now_seg;
+ prev_subseg = now_subseg;
+ fixups = fixups->next;
+ }
+}
+