Esempio n. 1
0
static void
out_debug_aranges (segT aranges_seg, segT info_seg)
{
  unsigned int addr_size = sizeof_address;
  struct line_seg *s;
  expressionS exp;
  symbolS *aranges_end;
  char *p;
  int sizeof_offset;

  sizeof_offset = out_header (aranges_seg, &exp);
  aranges_end = exp.X_add_symbol;

  /* Version.  */
  out_two (DWARF2_VERSION);

  /* Offset to .debug_info.  */
  TC_DWARF2_EMIT_OFFSET (section_symbol (info_seg), sizeof_offset);

  /* Size of an address (offset portion).  */
  out_byte (addr_size);

  /* Size of a segment descriptor.  */
  out_byte (0);

  /* Align the header.  */
  frag_align (ffs (2 * addr_size) - 1, 0, 0);

  for (s = all_segs; s; s = s->next)
    {
      fragS *frag;
      symbolS *beg, *end;

      frag = first_frag_for_seg (s->seg);
      beg = symbol_temp_new (s->seg, 0, frag);
      s->text_start = beg;

      frag = last_frag_for_seg (s->seg);
      end = symbol_temp_new (s->seg, get_frag_fix (frag, s->seg), frag);
      s->text_end = end;

      exp.X_op = O_symbol;
      exp.X_add_symbol = beg;
      exp.X_add_number = 0;
      emit_expr (&exp, addr_size);

      exp.X_op = O_subtract;
      exp.X_add_symbol = end;
      exp.X_op_symbol = beg;
      exp.X_add_number = 0;
      emit_expr (&exp, addr_size);
    }

  p = frag_more (2 * addr_size);
  md_number_to_chars (p, 0, addr_size);
  md_number_to_chars (p + addr_size, 0, addr_size);

  symbol_set_value_now (aranges_end);
}
Esempio n. 2
0
const char *
md_atof(int type, char *litP, int *sizeP)
{
  int prec;
  LITTLENUM_TYPE words[4];
  char *t;
  int i;

  switch (type) {
  case 'f':
    prec = 2;
    break;
  case 'd':
    prec = 4;
    /* __attribute__((fallthrough)); */
  default:
    *sizeP = 0;
    return _("bad call to md_atof");
  }

  t = atof_ieee(input_line_pointer, type, words);
  if (t)
    input_line_pointer = t;

  *sizeP = prec * 2;

  for (i = prec-1; i >= 0; i--) {
    md_number_to_chars(litP, (valueT) words[i], 2);
    litP += 2;
  }
  return NULL;
}
Esempio n. 3
0
void
eh_frame_convert_frag (fragS *frag)
{
  offsetT diff;
  fragS *loc4_frag;
  int loc4_fix, ca;

  loc4_frag = (fragS *) frag->fr_opcode;
  loc4_fix = (int) frag->fr_offset;

  diff = resolve_symbol_value (frag->fr_symbol);

  ca = frag->fr_subtype >> 3;
  gas_assert (ca > 0);
  diff /= ca;
  switch (frag->fr_subtype & 7)
    {
    case 0:
      gas_assert (diff < 0x40);
      loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc | diff;
      break;

    case 1:
      gas_assert (diff < 0x100);
      loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc1;
      frag->fr_literal[frag->fr_fix] = diff;
      break;

    case 2:
      gas_assert (diff < 0x10000);
      loc4_frag->fr_literal[loc4_fix] = DW_CFA_advance_loc2;
      md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 2);
      break;

    default:
      md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4);
      break;
    }

  frag->fr_fix += frag->fr_subtype & 7;
  frag->fr_type = rs_fill;
  frag->fr_subtype = 0;
  frag->fr_offset = 0;
}
Esempio n. 4
0
void
obj_som_init_stab_section (segT seg)
{
  segT saved_seg = now_seg;
  segT space;
  subsegT saved_subseg = now_subseg;
  char *p, *file;
  unsigned int stroff;

  /* Make the space which will contain the debug subspaces.  */
  space = bfd_make_section_old_way (stdoutput, "$GDB_DEBUG$");

  /* Set SOM specific attributes for the space.  In particular we set
     the space "defined", "private", "sort_key", and "spnum" values.

     Due to a bug in pxdb (called by hpux linker), the sort keys
     of the various stabs spaces/subspaces need to be "small".  We
     reserve range 72/73 which appear to work well.  */
  obj_set_section_attributes (space, 1, 1, 72, 2);
  bfd_set_section_alignment (stdoutput, space, 2);

  /* Set the containing space for both stab sections to be $GDB_DEBUG$
     (just created above).  Also set some attributes which BFD does
     not understand.  In particular, access bits, sort keys, and load
     quadrant.  */
  obj_set_subsection_attributes (seg, space, 0x1f, 73, 0, 0, 0, 0);
  bfd_set_section_alignment (stdoutput, seg, 2);

  /* Make some space for the first special stab entry and zero the memory.
     It contains information about the length of this file's
     stab string and the like.  Using it avoids the need to
     relocate the stab strings.

     The $GDB_STRINGS$ space will be created as a side effect of
     the call to get_stab_string_offset.  */
  p = frag_more (12);
  memset (p, 0, 12);
  as_where (&file, (unsigned int *) NULL);
  stroff = get_stab_string_offset (file, "$GDB_STRINGS$");
  know (stroff == 1);
  md_number_to_chars (p, stroff, 4);
  seg_info (seg)->stabu.p = p;

  /* Set the containing space for both stab sections to be $GDB_DEBUG$
     (just created above).  Also set some attributes which BFD does
     not understand.  In particular, access bits, sort keys, and load
     quadrant.  */
  seg = bfd_get_section_by_name (stdoutput, "$GDB_STRINGS$");
  obj_set_subsection_attributes (seg, space, 0x1f, 72, 0, 0, 0, 0);
  bfd_set_section_alignment (stdoutput, seg, 2);

  subseg_set (saved_seg, saved_subseg);
}
Esempio n. 5
0
void
md_assemble(
char *str)
{

	assert(str);
	pa_ip(str);
	if (!found_jbsr)
		toP = frag_more(4);
	else
		found_jbsr = 0;

#ifdef NeXT_MOD	/* mark sections containing instructions */
    /*
     * We are putting a machine instruction in this section so mark it as
     * containg some machine instructions.
     */
    frchain_now->frch_section.flags |= S_ATTR_SOME_INSTRUCTIONS;
#endif /* NeXT_MOD */

    /* put out the opcode */
    md_number_to_chars(toP, the_insn.opcode, 4);

    /* put out the symbol-dependent stuff */
    if (the_insn.reloc != NO_RELOC) {
	    fix_new(frag_now,			  /* which frag */
		    (toP - frag_now->fr_literal), /* where */
		    4,				  /* size */
		    the_insn.exp.X_add_symbol,
		    the_insn.exp.X_subtract_symbol,
		    the_insn.exp.X_add_number,	  /* offset */
		    the_insn.pcrel,
		    the_insn.pcrel_reloc,
		    the_insn.reloc);
    }
}
static inline void
out_four (int data)
{
    md_number_to_chars (frag_more (4), data, 4);
}
static inline void
out_two (int data)
{
    md_number_to_chars (frag_more (2), data, 2);
}
Esempio n. 8
0
void
md_assemble (char *str)
{
  frv_insn insn;
  char *errmsg;
  int packing_constraint;
  finished_insnS  finished_insn;
  fragS *double_nop_frag = NULL;
  fragS *single_nop_frag = NULL;
  struct vliw_insn_list *vliw_insn_list_entry = NULL;

  /* Initialize GAS's cgen interface for a new instruction.  */
  gas_cgen_init_parse ();

  memset (&insn, 0, sizeof (insn));

  insn.insn = frv_cgen_assemble_insn
    (gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, &errmsg);
  
  if (!insn.insn)
    {
      as_bad ("%s", errmsg);
      return;
    }
  
  /* If the cpu is tomcat, then we need to insert nops to workaround
     hardware limitations.  We need to keep track of each vliw unit
     and examine the length of the unit and the individual insns
     within the unit to determine the number and location of the
     required nops.  */
  if (frv_mach == bfd_mach_frvtomcat)
    {
      /* If we've just finished a VLIW insn OR this is a branch,
	 then start up a new frag.  Fill it with nops.  We will get rid
	 of those that are not required after we've seen all of the 
	 instructions but before we start resolving fixups.  */
      if ( !FRV_IS_NOP (insn)
	  && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
	{
	  char *buffer;

	  frag_wane (frag_now);
	  frag_new (0);
	  double_nop_frag = frag_now;
	  buffer = frag_var (rs_machine_dependent, 8, 8, NOP_DELETE, NULL, 0, 0);
	  md_number_to_chars (buffer, FRV_NOP_PACK, 4);
	  md_number_to_chars (buffer+4, FRV_NOP_NOPACK, 4);

	  frag_wane (frag_now);
	  frag_new (0);
	  single_nop_frag = frag_now;
	  buffer = frag_var (rs_machine_dependent, 4, 4, NOP_DELETE, NULL, 0, 0);
	  md_number_to_chars (buffer, FRV_NOP_NOPACK, 4);
	}

      vliw_insn_list_entry = frv_insert_vliw_insn (DO_COUNT);
      vliw_insn_list_entry->insn   = insn.insn;
      if (frv_is_branch_insn (insn.insn))
	vliw_insn_list_entry->type = VLIW_BRANCH_TYPE;

      if ( !FRV_IS_NOP (insn)
	  && (frv_is_branch_insn (insn.insn) || insn.fields.f_pack))
	{
	  vliw_insn_list_entry->snop_frag = single_nop_frag;
	  vliw_insn_list_entry->dnop_frag = double_nop_frag;
	}
    }

  /* Make sure that this insn does not violate the VLIW packing constraints.  */
  /* -mno-pack disallows any packing whatsoever.  */
  if (frv_flags & EF_FRV_NOPACK)
    {
      if (! insn.fields.f_pack)
	{
	  as_bad (_("VLIW packing used for -mno-pack"));
	  return;
	}
    }
  /* -mcpu=FRV is an idealized FR-V implementation that supports all of the
     instructions, don't do vliw checking.  */
  else if (frv_mach != bfd_mach_frv)
    {
      if (!target_implements_insn_p (insn.insn))
	{
	  as_bad (_("Instruction not supported by this architecture"));
	  return;
	}
      packing_constraint = frv_vliw_add_insn (& vliw, insn.insn);
      if (frv_mach == bfd_mach_fr550 && ! packing_constraint)
	packing_constraint = fr550_check_acc_range (& vliw, & insn);
      if (insn.fields.f_pack)
	frv_vliw_reset (& vliw, frv_mach, frv_flags);
      if (packing_constraint)
	{
	  as_bad (_("VLIW packing constraint violation"));
	  return;
	}
    }

  /* Doesn't really matter what we pass for RELAX_P here.  */
  gas_cgen_finish_insn (insn.insn, insn.buffer,
			CGEN_FIELDS_BITSIZE (& insn.fields), 1, &finished_insn);


  /* If the cpu is tomcat, then we need to insert nops to workaround
     hardware limitations.  We need to keep track of each vliw unit
     and examine the length of the unit and the individual insns
     within the unit to determine the number and location of the
     required nops.  */
  if (frv_mach == bfd_mach_frvtomcat)
    {
      if (vliw_insn_list_entry)
        vliw_insn_list_entry->address = finished_insn.addr;
      else
	abort();

      if (insn.fields.f_pack)
	{
	  /* We've completed a VLIW insn.  */
	  previous_vliw_chain = current_vliw_chain;
	  current_vliw_chain = NULL;
	  current_vliw_insn  = NULL;
        } 
    }
}
Esempio n. 9
0
static void
out_debug_aranges (segT aranges_seg, segT info_seg)
{
  unsigned int addr_size = sizeof_address;
  addressT size, skip;
  struct line_seg *s;
  expressionS expr;
  char *p;

  size = 4 + 2 + 4 + 1 + 1;

  skip = 2 * addr_size - (size & (2 * addr_size - 1));
  if (skip == 2 * addr_size)
    skip = 0;
  size += skip;

  for (s = all_segs; s; s = s->next)
    size += 2 * addr_size;

  size += 2 * addr_size;

  subseg_set (aranges_seg, 0);

  /* Length of the compilation unit.  */
  out_four (size - 4);

  /* Version.  */
  out_two (2);

  /* Offset to .debug_info.  */
  /* ??? sizeof_offset */
  TC_DWARF2_EMIT_OFFSET (section_symbol (info_seg), 4);

  /* Size of an address (offset portion).  */
  out_byte (addr_size);

  /* Size of a segment descriptor.  */
  out_byte (0);

  /* Align the header.  */
  if (skip)
    frag_align (ffs (2 * addr_size) - 1, 0, 0);

  for (s = all_segs; s; s = s->next)
    {
      fragS *frag;
      symbolS *beg, *end;

      frag = first_frag_for_seg (s->seg);
      beg = symbol_temp_new (s->seg, 0, frag);
      s->text_start = beg;

      frag = last_frag_for_seg (s->seg);
      end = symbol_temp_new (s->seg, get_frag_fix (frag), frag);
      s->text_end = end;

      expr.X_op = O_symbol;
      expr.X_add_symbol = beg;
      expr.X_add_number = 0;
      emit_expr (&expr, addr_size);

      expr.X_op = O_subtract;
      expr.X_add_symbol = end;
      expr.X_op_symbol = beg;
      expr.X_add_number = 0;
      emit_expr (&expr, addr_size);
    }

  p = frag_more (2 * addr_size);
  md_number_to_chars (p, 0, addr_size);
  md_number_to_chars (p + addr_size, 0, addr_size);
}
Esempio n. 10
0
void
md_assemble (char *str)
{
  char *op_start;
  char *op_end;

  moxie_opc_info_t *opcode;
  char *p;
  char pend;

  unsigned short iword = 0;

  int nlen = 0;

  /* Drop leading whitespace.  */
  while (*str == ' ')
    str++;

  /* Find the op code end.  */
  op_start = str;
  for (op_end = str;
       *op_end && !is_end_of_line[*op_end & 0xff] && *op_end != ' ';
       op_end++)
    nlen++;

  pend = *op_end;
  *op_end = 0;

  if (nlen == 0)
    as_bad (_("can't find opcode "));
  opcode = (moxie_opc_info_t *) hash_find (opcode_hash_control, op_start);
  *op_end = pend;

  if (opcode == NULL)
    {
      as_bad (_("unknown opcode %s"), op_start);
      return;
    }

  p = frag_more (2);

  switch (opcode->itype)
    {
    case MOXIE_F2_A8V:
      iword = (1<<15) | (opcode->opcode << 12);
      while (ISSPACE (*op_end))
	op_end++;
      {
	expressionS arg;
	int reg;
	reg = parse_register_operand (&op_end);
	iword += (reg << 8);
	if (*op_end != ',')
	  as_warn (_("expecting comma delimited register operands"));
	op_end++;
	op_end = parse_exp_save_ilp (op_end, &arg);
	fix_new_exp (frag_now,
		     ((p + (target_big_endian ? 1 : 0)) - frag_now->fr_literal),
		     1,
		     &arg,
		     0,
		     BFD_RELOC_8);
      }
      break;
    case MOXIE_F1_AB:
      iword = opcode->opcode << 8;
      while (ISSPACE (*op_end))
	op_end++;
      {
	int dest, src;
	dest = parse_register_operand (&op_end);
	if (*op_end != ',')
	  as_warn (_("expecting comma delimited register operands"));
	op_end++;
	src  = parse_register_operand (&op_end);
	iword += (dest << 4) + src;
	while (ISSPACE (*op_end))
	  op_end++;
	if (*op_end != 0)
	  as_warn (_("extra stuff on line ignored"));
      }
      break;
    case MOXIE_F1_A4:
      iword = opcode->opcode << 8;
      while (ISSPACE (*op_end))
	op_end++;
      {
	expressionS arg;
	char *where;
	int regnum;

 	regnum = parse_register_operand (&op_end);
	while (ISSPACE (*op_end))
	  op_end++;

	iword += (regnum << 4);

	if (*op_end != ',')
	  {
	    as_bad (_("expecting comma delimited operands"));
	    ignore_rest_of_line ();
	    return;
	  }
	op_end++;

	op_end = parse_exp_save_ilp (op_end, &arg);
	where = frag_more (4);
	fix_new_exp (frag_now,
		     (where - frag_now->fr_literal),
		     4,
		     &arg,
		     0,
		     BFD_RELOC_32);
      }
      break;
    case MOXIE_F1_M:
    case MOXIE_F1_4:
      iword = opcode->opcode << 8;
      while (ISSPACE (*op_end))
	op_end++;
      {
	expressionS arg;
	char *where;

	op_end = parse_exp_save_ilp (op_end, &arg);
	where = frag_more (4);
	fix_new_exp (frag_now,
		     (where - frag_now->fr_literal),
		     4,
		     &arg,
		     0,
		     BFD_RELOC_32);
      }
      break;
    case MOXIE_F1_NARG:
      iword = opcode->opcode << 8;
      while (ISSPACE (*op_end))
	op_end++;
      if (*op_end != 0)
	as_warn (_("extra stuff on line ignored"));
      break;
    case MOXIE_F1_A:
      iword = opcode->opcode << 8;
      while (ISSPACE (*op_end))
	op_end++;
      {
	int reg;
	reg = parse_register_operand (&op_end);
	while (ISSPACE (*op_end))
	  op_end++;
	if (*op_end != 0)
	  as_warn (_("extra stuff on line ignored"));
	iword += (reg << 4);
      }
      break;
    case MOXIE_F1_ABi:
      iword = opcode->opcode << 8;
      while (ISSPACE (*op_end))
	op_end++;
      {
	int a, b;
	a = parse_register_operand (&op_end);
	if (*op_end != ',')
	  as_warn (_("expecting comma delimited register operands"));
	op_end++;
	if (*op_end != '(')
	  {
	    as_bad (_("expecting indirect register `($rA)'"));
	    ignore_rest_of_line ();
	    return;
	  }
	op_end++;
	b = parse_register_operand (&op_end);
	if (*op_end != ')')
	  {
	    as_bad (_("missing closing parenthesis"));
	    ignore_rest_of_line ();
	    return;
	  }
	op_end++;
	iword += (a << 4) + b;
	while (ISSPACE (*op_end))
	  op_end++;
	if (*op_end != 0)
	  as_warn (_("extra stuff on line ignored"));
      }
      break;
    case MOXIE_F1_AiB:
      iword = opcode->opcode << 8;
      while (ISSPACE (*op_end))
	op_end++;
      {
	int a, b;
	if (*op_end != '(')
	  {
	    as_bad (_("expecting indirect register `($rA)'"));
	    ignore_rest_of_line ();
	    return;
	  }
	op_end++;
	a = parse_register_operand (&op_end);
	if (*op_end != ')')
	  {
	    as_bad (_("missing closing parenthesis"));
	    ignore_rest_of_line ();
	    return;
	  }
	op_end++;
	if (*op_end != ',')
	  as_warn (_("expecting comma delimited register operands"));
	op_end++;
	b = parse_register_operand (&op_end);
	iword += (a << 4) + b;
	while (ISSPACE (*op_end))
	  op_end++;
	if (*op_end != 0)
	  as_warn (_("extra stuff on line ignored"));
      }
      break;
    case MOXIE_F1_4A:
      iword = opcode->opcode << 8;
      while (ISSPACE (*op_end))
	op_end++;
      {
	expressionS arg;
	char *where;
	int a;

	op_end = parse_exp_save_ilp (op_end, &arg);
	where = frag_more (4);
	fix_new_exp (frag_now,
		     (where - frag_now->fr_literal),
		     4,
		     &arg,
		     0,
		     BFD_RELOC_32);

	if (*op_end != ',')
	  {
	    as_bad (_("expecting comma delimited operands"));
	    ignore_rest_of_line ();
	    return;
	  }
	op_end++;

 	a = parse_register_operand (&op_end);
	while (ISSPACE (*op_end))
	  op_end++;
	if (*op_end != 0)
	  as_warn (_("extra stuff on line ignored"));

	iword += (a << 4);
      }
      break;
    case MOXIE_F1_ABi2:
      iword = opcode->opcode << 8;
      while (ISSPACE (*op_end))
	op_end++;
      {
	expressionS arg;
	char *offset;
	int a, b;

 	a = parse_register_operand (&op_end);
	while (ISSPACE (*op_end))
	  op_end++;

	if (*op_end != ',')
	  {
	    as_bad (_("expecting comma delimited operands"));
	    ignore_rest_of_line ();
	    return;
	  }
	op_end++;

	op_end = parse_exp_save_ilp (op_end, &arg);
	offset = frag_more (2);
	fix_new_exp (frag_now,
		     (offset - frag_now->fr_literal),
		     2,
		     &arg,
		     0,
		     BFD_RELOC_16);

	if (*op_end != '(')
	  {
	    as_bad (_("expecting indirect register `($rX)'"));
	    ignore_rest_of_line ();
	    return;
	  }
	op_end++;
	b = parse_register_operand (&op_end);
	if (*op_end != ')')
	  {
	    as_bad (_("missing closing parenthesis"));
	    ignore_rest_of_line ();
	    return;
	  }
	op_end++;

	while (ISSPACE (*op_end))
	  op_end++;
	if (*op_end != 0)
	  as_warn (_("extra stuff on line ignored"));

	iword += (a << 4) + b;
      }
      break;
    case MOXIE_F1_AiB2:
      iword = opcode->opcode << 8;
      while (ISSPACE (*op_end))
	op_end++;
      {
	expressionS arg;
	char *offset;
	int a, b;

	op_end = parse_exp_save_ilp (op_end, &arg);
	offset = frag_more (2);
	fix_new_exp (frag_now,
		     (offset - frag_now->fr_literal),
		     2,
		     &arg,
		     0,
		     BFD_RELOC_16);

	if (*op_end != '(')
	  {
	    as_bad (_("expecting indirect register `($rX)'"));
	    ignore_rest_of_line ();
	    return;
	  }
	op_end++;
	a = parse_register_operand (&op_end);
	if (*op_end != ')')
	  {
	    as_bad (_("missing closing parenthesis"));
	    ignore_rest_of_line ();
	    return;
	  }
	op_end++;

	if (*op_end != ',')
	  {
	    as_bad (_("expecting comma delimited operands"));
	    ignore_rest_of_line ();
	    return;
	  }
	op_end++;

 	b = parse_register_operand (&op_end);
	while (ISSPACE (*op_end))
	  op_end++;

	while (ISSPACE (*op_end))
	  op_end++;
	if (*op_end != 0)
	  as_warn (_("extra stuff on line ignored"));

	iword += (a << 4) + b;
      }
      break;
    case MOXIE_F2_NARG:
      iword = opcode->opcode << 12;
      while (ISSPACE (*op_end))
	op_end++;
      if (*op_end != 0)
	as_warn (_("extra stuff on line ignored"));
      break;
    case MOXIE_F3_PCREL:
      iword = (3<<14) | (opcode->opcode << 10);
      while (ISSPACE (*op_end))
	op_end++;
      {
	expressionS arg;

	op_end = parse_exp_save_ilp (op_end, &arg);
	fix_new_exp (frag_now,
		     (p - frag_now->fr_literal),
		     2,
		     &arg,
		     TRUE,
		     BFD_RELOC_MOXIE_10_PCREL);
      }
      break;
    default:
      abort ();
    }

  md_number_to_chars (p, iword, 2);

  while (ISSPACE (*op_end))
    op_end++;

  if (*op_end != 0)
    as_warn (_("extra stuff on line ignored"));

  if (pending_reloc)
    as_bad (_("Something forgot to clean up\n"));
}
Esempio n. 11
0
/* Convert the instructions into frags and bytes */
void
md_assemble(char *str)
{
  char *op_start;
  char *op_end;
  char op_name[10];
  const bexkat1_opc_info_t *opcode;
  char *p;
  char pend;
  unsigned int iword;
  int nlen = 0;
  int regnum;
  expressionS arg;
  int offset;

  while (*str == ' ')
    str++;
  
  // mark opcode
  op_start = str;
  for (op_end = str;
       *op_end && !is_end_of_line[*op_end & 0xff] && *op_end != ' ';
       op_end++)
    nlen++;
  
  pend = *op_end;
  *op_end = 0;
  strncpy(op_name, op_start, 10);
  *op_end = pend;

  if (nlen == 0)
    as_bad(_("can't find opcode "));
  
  while (ISSPACE(*op_end))
    op_end++;
  
  opcode = (bexkat1_opc_info_t *) hash_find(opcode_hash_control, op_name);
  if (opcode == NULL) {
    as_bad(_("unknown opcode %s"), op_name);
    return;
  }

  iword = (opcode->type << 28) | (opcode->opcode << 24) | opcode->size;

  p = frag_more(4);

  switch (opcode->type) {
  case BEXKAT1_INH:
    if (opcode->args == 0) {
      md_number_to_chars(p, iword, 4);
    }
    if (opcode->args == 1) {
      op_end = parse_exp_save_ilp(op_end, &arg);
      if (opcode->size) {
	md_number_to_chars(p, iword, 4);
	p = frag_more(4);
	fix_new_exp(frag_now,
		    (p - frag_now->fr_literal),
		    4,
		    &arg,
		    0,
		    BFD_RELOC_32);
      } else {
	if (arg.X_op != O_constant) {
	  as_bad(_("offset is not a constant expression"));
	  ignore_rest_of_line();
	  return;
	}
	offset = arg.X_add_number;
	if (offset < -16384 || offset > 16383) {
	  as_bad(_("offset is out of range: %d\n"), offset);
	  ignore_rest_of_line();
	  return;
	}
	
	md_number_to_chars(p, iword, 4);
	fix_new_exp(frag_now,
		    (p - frag_now->fr_literal),
		    4,
		    &arg,
		    0,
		    BFD_RELOC_BEXKAT1_15);
      }
    }
    break;
  case BEXKAT1_PUSH:
    if (opcode->args == 1 && opcode->opcode == 2) // bsr
      goto branch;
    if (opcode->args == 1) {
      if (opcode->size) {
	op_end = parse_exp_save_ilp(op_end, &arg);
	md_number_to_chars(p, iword, 4);
	p = frag_more(4);
	fix_new_exp(frag_now,
		    (p - frag_now->fr_literal),
		    4,
		    &arg,
		    0,
		    BFD_RELOC_32);
      } else {
	regnum = parse_regnum(&op_end);
	if (regnum == -1)
	  return; 
	while (ISSPACE(*op_end))
	  op_end++;
	iword |= (regnum & 0xf) << 20; // A
	md_number_to_chars(p, iword, 4);
      }
    }
    if (opcode->args == 2) {
      if (*op_end != '(')
	op_end = parse_exp_save_ilp(op_end, &arg);
      else { // Implicit 0 offset to allow for indirect
	arg.X_op = O_constant;
	arg.X_add_number = 0;
      }
      
      if (*op_end != '(') {
	as_bad(_("missing open paren: %s"), op_end);
	ignore_rest_of_line();
	return;
      }
      op_end++; // burn paren
      while (ISSPACE(*op_end))
	op_end++;
      
      regnum = parse_regnum(&op_end);
      if (regnum == -1)
	return; 
      while (ISSPACE(*op_end))
	op_end++;
      iword |= (regnum & 0xf) << 20; // A
      
      if (*op_end != ')') {
	as_bad(_("missing close paren: %s"), op_end);
	ignore_rest_of_line();
	return;
      }
      op_end++;
      
      if (arg.X_op != O_constant) {
	as_bad(_("offset is not a constant expression"));
	ignore_rest_of_line();
	return;
      }
      offset = arg.X_add_number;
      if (offset < -16384 || offset > 16383) {
	as_bad(_("offset is out of range: %d\n"), offset);
	ignore_rest_of_line();
	return;
      }

      md_number_to_chars(p, iword, 4);
      fix_new_exp(frag_now,
		  (p - frag_now->fr_literal),
		  4,
		  &arg,
		  0,
		  BFD_RELOC_BEXKAT1_15);
    }
    break;
  case BEXKAT1_POP:
    if (opcode->args == 0) {
      md_number_to_chars(p, iword, 4);
    }
    if (opcode->args == 1) {
      regnum = parse_regnum(&op_end);
      if (regnum == -1)
	return; 
      while (ISSPACE(*op_end))
	op_end++;
      iword |= (regnum & 0xf) << 20; // A
      md_number_to_chars(p, iword, 4);
    }
    break;
  case BEXKAT1_MOV:
    if (opcode->opcode == 0) {
      regnum = parse_regnum(&op_end);
      if (regnum == -1)
        return; 
      while (ISSPACE(*op_end))
        op_end++;
      iword |= (regnum & 0xf) << 20; // A
      md_number_to_chars(p, iword, 4);
      break;
    }
    /* __attribute__((fallthrough)); */
  case BEXKAT1_CMP:
  case BEXKAT1_FPU:
  case BEXKAT1_FP:
  case BEXKAT1_ALU:
  case BEXKAT1_INT:
  case BEXKAT1_INTU:
    if (opcode->args > 1) {
      regnum = parse_regnum(&op_end);
      if (regnum == -1)
        return; 
      while (ISSPACE(*op_end))
        op_end++;
      iword |= (regnum & 0xf) << 20; // A

      if (*op_end != ',') {
        as_bad(_("missing comma: %s"), op_end);
        return;
      }
      op_end++;
      while (ISSPACE(*op_end))
        op_end++;
    
    }

    regnum = parse_regnum(&op_end);
    if (regnum == -1)
      return; 
    while (ISSPACE(*op_end))
      op_end++;
    iword |= (regnum & 0xf) << 16; // B

    if (opcode->args > 2) {

      if (*op_end != ',') {
	as_bad(_("missing comma: %s"), op_end);
	return;
      }
      op_end++;
      while (ISSPACE(*op_end))
	op_end++;
      
      if (opcode->opcode < 8) {
	regnum = parse_regnum(&op_end);
	if (regnum == -1)
	  return; 
	while (ISSPACE(*op_end))
	  op_end++;
	iword |= (regnum & 0xf) << 12; // C
	md_number_to_chars(p, iword, 4);
      } else {
	op_end = parse_exp_save_ilp(op_end, &arg);
	if (arg.X_op != O_constant) {
	  as_bad(_("offset is not a constant expression"));
	  ignore_rest_of_line();
	  return;
	}
	offset = arg.X_add_number;
	if (offset < -16384 || offset > 16383) {
	  as_bad(_("offset is out of range: %d\n"), offset);
	  ignore_rest_of_line();
	  return;
	}
	md_number_to_chars(p, iword, 4);
	fix_new_exp(frag_now,
		    (p - frag_now->fr_literal),
		    4,
		    &arg,
		    0,
		    BFD_RELOC_BEXKAT1_15);
      }
    } else {
      md_number_to_chars(p, iword, 4);
    }
    break;
branch:
  case BEXKAT1_BRANCH:
    md_number_to_chars(p, iword, 4);
    op_end = parse_exp_save_ilp(op_end, &arg);
    if (target_big_endian)
      fix_new_exp(frag_now,
		  (p - frag_now->fr_literal),
		  4,
		  &arg,
		  TRUE,
		  BFD_RELOC_BEXKAT1_15_PCREL);
    else
      fix_new_exp(frag_now,
		  (p - frag_now->fr_literal),
		  4,
		  &arg,
		  TRUE,
		  BFD_RELOC_BEXKAT1_15_PCREL);
    break;
  case BEXKAT1_LOAD:
  case BEXKAT1_STORE:
    // A, 
    regnum = parse_regnum(&op_end);
    if (regnum == -1)
      return; 
    while (ISSPACE(*op_end))
      op_end++;
    iword |= (regnum & 0xf) << 20; // A
    
    if (*op_end != ',') {
      as_bad(_("missing comma: %s"), op_end);
      return;
    }
    op_end++;
    while (ISSPACE(*op_end))
      op_end++;
    /* __attribute__((fallthrough)); */
  case BEXKAT1_JUMP:
    if (opcode->size) { // big address
      md_number_to_chars(p, iword, 4);
      op_end = parse_exp_save_ilp(op_end, &arg);
      p = frag_more(4);
      fix_new_exp(frag_now,
		  (p - frag_now->fr_literal),
		  4,
		  &arg,
		  0,
		  BFD_RELOC_32);
    } else { // exp(B)
      if (*op_end != '(')
	op_end = parse_exp_save_ilp(op_end, &arg);
      else { // Implicit 0 offset to allow for indirect
	arg.X_op = O_constant;
	arg.X_add_number = 0;
      }
      
      if (*op_end != '(') {
	as_bad(_("missing open paren: %s"), op_end);
	ignore_rest_of_line();
	return;
      }
      op_end++; // burn paren
      while (ISSPACE(*op_end))
	op_end++;
      
      regnum = parse_regnum(&op_end);
      if (regnum == -1)
	return; 
      while (ISSPACE(*op_end))
	op_end++;
      iword |= (regnum & 0xf) << 16; // B
      
      if (*op_end != ')') {
	as_bad(_("missing close paren: %s"), op_end);
	ignore_rest_of_line();
	return;
      }
      op_end++;
      
      if (arg.X_op != O_constant) {
	as_bad(_("offset is not a constant expression"));
	ignore_rest_of_line();
	return;
      }
      offset = arg.X_add_number;
      if (offset < -16384 || offset > 16383) {
	as_bad(_("offset is out of range: %d\n"), offset);
	ignore_rest_of_line();
	return;
      }

      md_number_to_chars(p, iword, 4);
      fix_new_exp(frag_now,
		  (p - frag_now->fr_literal),
		  4,
		  &arg,
		  0,
		  BFD_RELOC_BEXKAT1_15);
    }
    break;
  case BEXKAT1_LDI:
    regnum = parse_regnum(&op_end);
    if (regnum == -1)
      return; 
    while (ISSPACE(*op_end))
      op_end++;
    iword |= (regnum & 0xf) << 20; // A
    
    if (*op_end != ',') {
      as_bad(_("missing comma: %s"), op_end);
      return;
    }
    op_end++;
    while (ISSPACE(*op_end))
      op_end++;
    op_end = parse_exp_save_ilp(op_end, &arg);
    if (opcode->size) {
      md_number_to_chars(p, iword, 4);
      p = frag_more(4);
      fix_new_exp(frag_now,
		  (p - frag_now->fr_literal),
		  4,
		  &arg,
		  0,
		  BFD_RELOC_32);
    } else {
      if (arg.X_op != O_constant) {
	as_bad(_("offset is not a constant expression"));
	ignore_rest_of_line();
	return;
      }
      offset = arg.X_add_number;
      if (offset >= 32768) {
	as_bad(_("offset is out of range: %d\n"), offset);
	ignore_rest_of_line();
	return;
      }

      md_number_to_chars(p, iword, 4);
      fix_new_exp(frag_now,
		  (p - frag_now->fr_literal),
		  4,
		  &arg,
		  0,
		  BFD_RELOC_BEXKAT1_15);
    }
    break;
  }

  while (ISSPACE(*op_end))
    op_end++;
  if (*op_end != 0)
    as_warn("extra stuff on line ignored %s %c", op_start, *op_end);
  if (pending_reloc)
    as_bad("Something forgot to clean up\n");
  return;
}