/* tc-cr16.c -- Assembler code for the CR16 CPU core.
- Copyright 2007 Free Software Foundation, Inc.
+ Copyright (C) 2007-2020 Free Software Foundation, Inc.
Contributed by M R Swami Reddy <MR.Swami.Reddy@nsc.com>
/* Chars that mean this number is a floating point constant as in 0f12.456 */
const char FLT_CHARS[] = "f'";
+#ifdef OBJ_ELF
+/* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
+symbolS * GOT_symbol;
+#endif
+
/* Target-specific multicharacter options, not const-declared at usage. */
const char *md_shortopts = "";
struct option md_longopts[] =
expression (&exp);
if (*input_line_pointer == ':')
- {
- /* Bitfields. */
- long value = 0;
+ {
+ /* Bitfields. */
+ long value = 0;
- for (;;)
- {
- unsigned long width;
-
- if (*input_line_pointer != ':')
- {
- input_line_pointer = hold;
- break;
- }
- if (exp.X_op == O_absent)
- {
- as_warn (_("using a bit field width of zero"));
- exp.X_add_number = 0;
- exp.X_op = O_constant;
- }
-
- if (exp.X_op != O_constant)
- {
- *input_line_pointer = '\0';
- as_bad (_("field width \"%s\" too complex for a bitfield"), hold);
- *input_line_pointer = ':';
- demand_empty_rest_of_line ();
- return;
- }
-
- if ((width = exp.X_add_number) >
- (unsigned int)(BITS_PER_CHAR * nbytes))
- {
- as_warn (_("field width %lu too big to fit in %d bytes: truncated to %d bits"), width, nbytes, (BITS_PER_CHAR * nbytes));
- width = BITS_PER_CHAR * nbytes;
- } /* Too big. */
-
-
- if (width > bits_available)
- {
- /* FIXME-SOMEDAY: backing up and reparsing is wasteful. */
- input_line_pointer = hold;
- exp.X_add_number = value;
- break;
- }
-
- /* Skip ':'. */
- hold = ++input_line_pointer;
-
- expression (&exp);
- if (exp.X_op != O_constant)
- {
- char cache = *input_line_pointer;
-
- *input_line_pointer = '\0';
- as_bad (_("field value \"%s\" too complex for a bitfield"), hold);
- *input_line_pointer = cache;
- demand_empty_rest_of_line ();
- return;
- }
-
- value |= ((~(-1 << width) & exp.X_add_number)
- << ((BITS_PER_CHAR * nbytes) - bits_available));
-
- if ((bits_available -= width) == 0
- || is_it_end_of_statement ()
- || *input_line_pointer != ',')
- break;
-
- hold = ++input_line_pointer;
- expression (&exp);
- }
+ for (;;)
+ {
+ unsigned long width;
- exp.X_add_number = value;
- exp.X_op = O_constant;
- exp.X_unsigned = 1;
- }
+ if (*input_line_pointer != ':')
+ {
+ input_line_pointer = hold;
+ break;
+ }
+ if (exp.X_op == O_absent)
+ {
+ as_warn (_("using a bit field width of zero"));
+ exp.X_add_number = 0;
+ exp.X_op = O_constant;
+ }
+
+ if (exp.X_op != O_constant)
+ {
+ *input_line_pointer = '\0';
+ as_bad (_("field width \"%s\" too complex for a bitfield"), hold);
+ *input_line_pointer = ':';
+ demand_empty_rest_of_line ();
+ return;
+ }
+
+ if ((width = exp.X_add_number) >
+ (unsigned int)(BITS_PER_CHAR * nbytes))
+ {
+ as_warn (ngettext ("field width %lu too big to fit in %d"
+ " byte: truncated to %d bits",
+ "field width %lu too big to fit in %d"
+ " bytes: truncated to %d bits",
+ nbytes),
+ width, nbytes, (BITS_PER_CHAR * nbytes));
+ width = BITS_PER_CHAR * nbytes;
+ } /* Too big. */
+
+
+ if (width > bits_available)
+ {
+ /* FIXME-SOMEDAY: backing up and reparsing is wasteful. */
+ input_line_pointer = hold;
+ exp.X_add_number = value;
+ break;
+ }
+
+ /* Skip ':'. */
+ hold = ++input_line_pointer;
+
+ expression (&exp);
+ if (exp.X_op != O_constant)
+ {
+ char cache = *input_line_pointer;
+
+ *input_line_pointer = '\0';
+ as_bad (_("field value \"%s\" too complex for a bitfield"), hold);
+ *input_line_pointer = cache;
+ demand_empty_rest_of_line ();
+ return;
+ }
+
+ value |= ((~(-(1 << width)) & exp.X_add_number)
+ << ((BITS_PER_CHAR * nbytes) - bits_available));
+
+ if ((bits_available -= width) == 0
+ || is_it_end_of_statement ()
+ || *input_line_pointer != ',')
+ break;
+
+ hold = ++input_line_pointer;
+ expression (&exp);
+ }
+
+ exp.X_add_number = value;
+ exp.X_op = O_constant;
+ exp.X_unsigned = 1;
+ }
if ((*(input_line_pointer) == '@') && (*(input_line_pointer +1) == 'c'))
- code_label = 1;
+ code_label = 1;
emit_expr (&exp, (unsigned int) nbytes);
++c;
if ((*(input_line_pointer) == '@') && (*(input_line_pointer +1) == 'c'))
- {
- input_line_pointer +=3;
- break;
- }
+ {
+ input_line_pointer +=3;
+ break;
+ }
}
while ((*input_line_pointer++ == ','));
demand_empty_rest_of_line ();
}
-
/* This table describes all the machine specific pseudo-ops
the assembler has to support. The fields are:
*** Pseudo-op name without dot.
/* In CR16 machine, align is in bytes (not a ptwo boundary). */
{"align", s_align_bytes, 0},
{"long", l_cons, 4 },
+ {"4byte", l_cons, 4 },
{0, 0, 0}
};
const relax_typeS md_relax_table[] =
{
/* bCC */
- {0xfa, -0x100, 2, 1}, /* 8 */
+ {0x7f, -0x80, 2, 1}, /* 8 */
{0xfffe, -0x10000, 4, 2}, /* 16 */
{0xfffffe, -0x1000000, 6, 0}, /* 24 */
};
static reg
get_register (char *reg_name)
{
- const reg_entry *reg;
+ const reg_entry *rreg;
- reg = (const reg_entry *) hash_find (reg_hash, reg_name);
+ rreg = (const reg_entry *) hash_find (reg_hash, reg_name);
- if (reg != NULL)
- return reg->value.reg_val;
+ if (rreg != NULL)
+ return rreg->value.reg_val;
return nullregister;
}
static reg
get_register_pair (char *reg_name)
{
- const reg_entry *reg;
+ const reg_entry *rreg;
char tmp_rp[16]="\0";
- /* Add '(' and ')' to the reg pair, if its not present. */
- if (reg_name[0] != '(')
+ /* Add '(' and ')' to the reg pair, if it's not present. */
+ if (reg_name[0] != '(')
{
tmp_rp[0] = '(';
strcat (tmp_rp, reg_name);
strcat (tmp_rp,")");
- reg = (const reg_entry *) hash_find (regp_hash, tmp_rp);
+ rreg = (const reg_entry *) hash_find (regp_hash, tmp_rp);
}
else
- reg = (const reg_entry *) hash_find (regp_hash, reg_name);
+ rreg = (const reg_entry *) hash_find (regp_hash, reg_name);
- if (reg != NULL)
- return reg->value.reg_val;
+ if (rreg != NULL)
+ return rreg->value.reg_val;
return nullregister;
-}
+}
/* Get the index register 'reg_name'. */
static reg
get_index_register (char *reg_name)
{
- const reg_entry *reg;
+ const reg_entry *rreg;
- reg = (const reg_entry *) hash_find (reg_hash, reg_name);
+ rreg = (const reg_entry *) hash_find (reg_hash, reg_name);
- if ((reg != NULL)
- && ((reg->value.reg_val == 12) || (reg->value.reg_val == 13)))
- return reg->value.reg_val;
+ if ((rreg != NULL)
+ && ((rreg->value.reg_val == 12) || (rreg->value.reg_val == 13)))
+ return rreg->value.reg_val;
return nullregister;
}
static reg
get_index_register_pair (char *reg_name)
{
- const reg_entry *reg;
+ const reg_entry *rreg;
- reg = (const reg_entry *) hash_find (regp_hash, reg_name);
+ rreg = (const reg_entry *) hash_find (regp_hash, reg_name);
- if (reg != NULL)
+ if (rreg != NULL)
{
- if ((reg->value.reg_val != 1) || (reg->value.reg_val != 7)
- || (reg->value.reg_val != 9) || (reg->value.reg_val > 10))
- return reg->value.reg_val;
+ if ((rreg->value.reg_val != 1) || (rreg->value.reg_val != 7)
+ || (rreg->value.reg_val != 9) || (rreg->value.reg_val > 10))
+ return rreg->value.reg_val;
- as_bad (_("Unknown register pair - index relative mode: `%d'"), reg->value.reg_val);
+ as_bad (_("Unknown register pair - index relative mode: `%d'"), rreg->value.reg_val);
}
return nullregister;
static preg
get_pregister (char *preg_name)
{
- const reg_entry *preg;
+ const reg_entry *prreg;
- preg = (const reg_entry *) hash_find (preg_hash, preg_name);
+ prreg = (const reg_entry *) hash_find (preg_hash, preg_name);
- if (preg != NULL)
- return preg->value.preg_val;
+ if (prreg != NULL)
+ return prreg->value.preg_val;
return nullpregister;
}
static preg
get_pregisterp (char *preg_name)
{
- const reg_entry *preg;
+ const reg_entry *prreg;
- preg = (const reg_entry *) hash_find (pregp_hash, preg_name);
+ prreg = (const reg_entry *) hash_find (pregp_hash, preg_name);
- if (preg != NULL)
- return preg->value.preg_val;
+ if (prreg != NULL)
+ return prreg->value.preg_val;
return nullpregister;
}
int
cr16_force_relocation (fixS *fix)
{
- /* REVISIT: Check if the "SWITCH_TABLE (fix)" should be added
- if (generic_force_reloc (fix) || SWITCH_TABLE (fix)) */
- if (generic_force_reloc (fix))
+ if (generic_force_reloc (fix) || SWITCH_TABLE (fix))
return 1;
return 0;
/* Record a fixup for a cons expression. */
void
-cr16_cons_fix_new (fragS *frag, int offset, int len, expressionS *exp)
+cr16_cons_fix_new (fragS *frag, int offset, int len, expressionS *exp,
+ bfd_reloc_code_real_type rtype)
{
- int rtype;
switch (len)
{
default: rtype = BFD_RELOC_NONE; break;
case 2: rtype = BFD_RELOC_CR16_NUM16; break;
case 4:
if (code_label)
- {
- rtype = BFD_RELOC_CR16_NUM32a;
- code_label = 0;
- }
+ {
+ rtype = BFD_RELOC_CR16_NUM32a;
+ code_label = 0;
+ }
else
- rtype = BFD_RELOC_CR16_NUM32;
+ rtype = BFD_RELOC_CR16_NUM32;
break;
}
{
arelent * reloc;
- reloc = xmalloc (sizeof (arelent));
- reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+ /* If symbols are local and resolved, then no relocation needed. */
+ if ( ((fixP->fx_addsy)
+ && (S_GET_SEGMENT (fixP->fx_addsy) == absolute_section))
+ || ((fixP->fx_subsy)
+ && (S_GET_SEGMENT (fixP->fx_subsy) == absolute_section)))
+ return NULL;
+
+ reloc = XNEW (arelent);
+ reloc->sym_ptr_ptr = XNEW (asymbol *);
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy);
reloc->address = fixP->fx_frag->fr_address + fixP->fx_where;
reloc->addend = fixP->fx_offset;
switch (fixP->fx_r_type)
{
- case BFD_RELOC_CR16_NUM8:
- fixP->fx_r_type = BFD_RELOC_CR16_NUM8;
- break;
- case BFD_RELOC_CR16_NUM16:
- fixP->fx_r_type = BFD_RELOC_CR16_NUM16;
- break;
- case BFD_RELOC_CR16_NUM32:
- fixP->fx_r_type = BFD_RELOC_CR16_NUM32;
- break;
- case BFD_RELOC_CR16_NUM32a:
- fixP->fx_r_type = BFD_RELOC_CR16_NUM32a;
- break;
- default:
- abort ();
- break;
+ case BFD_RELOC_CR16_NUM8:
+ fixP->fx_r_type = BFD_RELOC_CR16_SWITCH8;
+ break;
+ case BFD_RELOC_CR16_NUM16:
+ fixP->fx_r_type = BFD_RELOC_CR16_SWITCH16;
+ break;
+ case BFD_RELOC_CR16_NUM32:
+ fixP->fx_r_type = BFD_RELOC_CR16_SWITCH32;
+ break;
+ case BFD_RELOC_CR16_NUM32a:
+ fixP->fx_r_type = BFD_RELOC_CR16_NUM32a;
+ break;
+ default:
+ abort ();
+ break;
}
}
else
segment_name (S_GET_SEGMENT (fixP->fx_addsy)));
}
}
+#ifdef OBJ_ELF
+ if ((fixP->fx_r_type == BFD_RELOC_CR16_GOT_REGREL20)
+ && GOT_symbol
+ && fixP->fx_addsy == GOT_symbol)
+ {
+ reloc->addend = fixP->fx_offset = reloc->address;
+ }
+ else if ((fixP->fx_r_type == BFD_RELOC_CR16_GOTC_REGREL20)
+ && GOT_symbol
+ && fixP->fx_addsy == GOT_symbol)
+ {
+ reloc->addend = fixP->fx_offset = reloc->address;
+ }
+#endif
- assert ((int) fixP->fx_r_type > 0);
+ gas_assert ((int) fixP->fx_r_type > 0);
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type);
if (reloc->howto == NULL)
bfd_get_reloc_code_name (fixP->fx_r_type));
return NULL;
}
- assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
+ gas_assert (!fixP->fx_pcrel == !reloc->howto->pc_relative);
return reloc;
}
{
/* 'opcode' points to the start of the instruction, whether
we need to change the instruction's fixed encoding. */
- bfd_reloc_code_real_type reloc = BFD_RELOC_NONE;
+ char *opcode = &fragP->fr_literal[0] + fragP->fr_fix;
+ bfd_reloc_code_real_type reloc;
subseg_change (sec, 0);
+ switch (fragP->fr_subtype)
+ {
+ case 0:
+ reloc = BFD_RELOC_CR16_DISP8;
+ break;
+ case 1:
+ /* If the subtype is not changed due to :m operand qualifier,
+ then no need to update the opcode value. */
+ if ((int)opcode[1] != 0x18)
+ {
+ opcode[0] = (opcode[0] & 0xf0);
+ opcode[1] = 0x18;
+ }
+ reloc = BFD_RELOC_CR16_DISP16;
+ break;
+ case 2:
+ /* If the subtype is not changed due to :l operand qualifier,
+ then no need to update the opcode value. */
+ if ((int)opcode[1] != 0)
+ {
+ opcode[2] = opcode[0];
+ opcode[0] = opcode[1];
+ opcode[1] = 0x0;
+ }
+ reloc = BFD_RELOC_CR16_DISP24;
+ break;
+ default:
+ abort();
+ }
+
fix_new (fragP, fragP->fr_fix,
bfd_get_reloc_size (bfd_reloc_type_lookup (stdoutput, reloc)),
fragP->fr_symbol, fragP->fr_offset, 1, reloc);
fragP->fr_fix += md_relax_table[fragP->fr_subtype].rlx_length;
}
+symbolS *
+md_undefined_symbol (char *name)
+{
+ if (*name == '_' && *(name + 1) == 'G'
+ && strcmp (name, "_GLOBAL_OFFSET_TABLE_") == 0)
+ {
+ if (!GOT_symbol)
+ {
+ if (symbol_find (name))
+ as_bad (_("GOT already in symbol table"));
+ GOT_symbol = symbol_new (name, undefined_section,
+ (valueT) 0, &zero_address_frag);
+ }
+ return GOT_symbol;
+ }
+ return 0;
+}
+
/* Process machine-dependent command line options. Called once for
each option on the command line that the machine-independent part of
GAS does not understand. */
int
-md_parse_option (int c ATTRIBUTE_UNUSED, char *arg ATTRIBUTE_UNUSED)
+md_parse_option (int c ATTRIBUTE_UNUSED, const char *arg ATTRIBUTE_UNUSED)
{
return 0;
}
return;
}
-/* Turn a string in input_line_pointer into a floating point constant
- of type TYPE, and store the appropriate bytes in *LITP. The number
- of LITTLENUMS emitted is stored in *SIZEP. An error message is
- returned, or NULL on OK. */
-
-char *
+const char *
md_atof (int type, char *litP, int *sizeP)
{
- int prec;
- int i;
- LITTLENUM_TYPE words[4];
- char *t;
-
- switch (type)
- {
- case 'f':
- prec = 2;
- break;
-
- case 'd':
- prec = 4;
- break;
-
- 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;
-
- if (! target_big_endian)
- {
- for (i = prec - 1; i >= 0; i--)
- {
- md_number_to_chars (litP, (valueT) words[i], 2);
- litP += 2;
- }
- }
- else
- {
- for (i = 0; i < prec; i++)
- {
- md_number_to_chars (litP, (valueT) words[i], 2);
- litP += 2;
- }
- }
-
- return NULL;
+ return ieee_md_atof (type, litP, sizeP, target_big_endian);
}
/* Apply a fixS (fixup of an instruction or data that we didn't have
md_apply_fix (fixS *fixP, valueT *valP, segT seg)
{
valueT val = * valP;
- char *buf = fixP->fx_frag->fr_literal + fixP->fx_where;
- fixP->fx_offset = 0;
-
- switch (fixP->fx_r_type)
- {
- case BFD_RELOC_CR16_NUM8:
- bfd_put_8 (stdoutput, (unsigned char) val, buf);
- break;
- case BFD_RELOC_CR16_NUM16:
- bfd_put_16 (stdoutput, val, buf);
- break;
- case BFD_RELOC_CR16_NUM32:
- bfd_put_32 (stdoutput, val, buf);
- break;
- case BFD_RELOC_CR16_NUM32a:
- bfd_put_32 (stdoutput, val, buf);
- break;
- default:
- /* We shouldn't ever get here because linkrelax is nonzero. */
- abort ();
- break;
- }
-
- fixP->fx_done = 0;
if (fixP->fx_addsy == NULL
&& fixP->fx_pcrel == 0)
fixP->fx_done = 1;
-
- if (fixP->fx_pcrel == 1
+ else if (fixP->fx_pcrel == 1
&& fixP->fx_addsy != NULL
&& S_GET_SEGMENT (fixP->fx_addsy) == seg)
fixP->fx_done = 1;
+ else
+ fixP->fx_done = 0;
+
+ if (fixP->fx_addsy != NULL && !fixP->fx_pcrel)
+ {
+ val = fixP->fx_offset;
+ fixP->fx_done = 1;
+ }
+
+ if (fixP->fx_done)
+ {
+ char *buf = fixP->fx_frag->fr_literal + fixP->fx_where;
+
+ fixP->fx_offset = 0;
+
+ switch (fixP->fx_r_type)
+ {
+ case BFD_RELOC_CR16_NUM8:
+ bfd_put_8 (stdoutput, (unsigned char) val, buf);
+ break;
+ case BFD_RELOC_CR16_NUM16:
+ bfd_put_16 (stdoutput, val, buf);
+ break;
+ case BFD_RELOC_CR16_NUM32:
+ bfd_put_32 (stdoutput, val, buf);
+ break;
+ case BFD_RELOC_CR16_NUM32a:
+ bfd_put_32 (stdoutput, val, buf);
+ break;
+ default:
+ /* We shouldn't ever get here because linkrelax is nonzero. */
+ abort ();
+ break;
+ }
+ fixP->fx_done = 0;
+ }
+ else
+ fixP->fx_offset = * valP;
}
/* The location from which a PC relative jump should be calculated,
static void
initialise_reg_hash_table (struct hash_control ** hash_table,
- const reg_entry * register_table,
- const unsigned int num_entries)
+ const reg_entry * register_table,
+ const unsigned int num_entries)
{
- const reg_entry * reg;
+ const reg_entry * rreg;
const char *hashret;
if ((* hash_table = hash_new ()) == NULL)
as_fatal (_("Virtual memory exhausted"));
- for (reg = register_table;
- reg < (register_table + num_entries);
- reg++)
+ for (rreg = register_table;
+ rreg < (register_table + num_entries);
+ rreg++)
{
- hashret = hash_insert (* hash_table, reg->name, (char *) reg);
+ hashret = hash_insert (* hash_table, rreg->name, (char *) rreg);
if (hashret)
- as_fatal (_("Internal Error: Can't hash %s: %s"),
- reg->name, hashret);
+ as_fatal (_("Internal Error: Can't hash %s: %s"),
+ rreg->name, hashret);
}
}
const char *mnemonic = cr16_instruction[i].mnemonic;
hashret = hash_insert (cr16_inst_hash, mnemonic,
- (char *)(cr16_instruction + i));
+ (char *)(cr16_instruction + i));
if (hashret != NULL && *hashret != '\0')
as_fatal (_("Can't hash `%s': %s\n"), cr16_instruction[i].mnemonic,
int symbol_with_s = 0;
int symbol_with_m = 0;
int symbol_with_l = 0;
+ int symbol_with_at_got = 0;
+ int symbol_with_at_gotc = 0;
argument *cur_arg = cr16_ins->arg + cur_arg_num; /* Current argument. */
saved_input_line_pointer = input_line_pointer;
case O_absent:
/* Missing or bad expr becomes absolute 0. */
as_bad (_("missing or invalid displacement expression `%s' taken as 0"),
- str);
+ str);
cr16_ins->exp.X_op = O_constant;
cr16_ins->exp.X_add_number = 0;
cr16_ins->exp.X_add_symbol = NULL;
case O_subtract:
case O_add:
cur_arg->X_op = O_symbol;
+ cur_arg->constant = cr16_ins->exp.X_add_number;
+ cr16_ins->exp.X_add_number = 0;
cr16_ins->rtype = BFD_RELOC_NONE;
relocatable = 1;
if (strneq (input_line_pointer, "@c", 2))
- symbol_with_at = 1;
+ symbol_with_at = 1;
if (strneq (input_line_pointer, "@l", 2)
- || strneq (input_line_pointer, ":l", 2))
- symbol_with_l = 1;
+ || strneq (input_line_pointer, ":l", 2))
+ symbol_with_l = 1;
if (strneq (input_line_pointer, "@m", 2)
- || strneq (input_line_pointer, ":m", 2))
- symbol_with_m = 1;
+ || strneq (input_line_pointer, ":m", 2))
+ symbol_with_m = 1;
if (strneq (input_line_pointer, "@s", 2)
- || strneq (input_line_pointer, ":s", 2))
- symbol_with_s = 1;
+ || strneq (input_line_pointer, ":s", 2))
+ symbol_with_s = 1;
- switch (cur_arg->type)
- {
- case arg_cr:
- if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
- {
- if (cur_arg->size == 20)
- cr16_ins->rtype = BFD_RELOC_CR16_REGREL20;
- else
- cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a;
- }
- break;
+ if (strneq (input_line_pointer, "@cGOT", 5)
+ || strneq (input_line_pointer, "@cgot", 5))
+ {
+ if (GOT_symbol == NULL)
+ GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
- case arg_crp:
- if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
- switch (instruction->size)
- {
- case 1:
- switch (cur_arg->size)
- {
- case 0:
- cr16_ins->rtype = BFD_RELOC_CR16_REGREL0;
- break;
- case 4:
- if (IS_INSN_MNEMONIC ("loadb") || IS_INSN_MNEMONIC ("storb"))
- cr16_ins->rtype = BFD_RELOC_CR16_REGREL4;
- else
- cr16_ins->rtype = BFD_RELOC_CR16_REGREL4a;
- break;
- default: break;
- }
- break;
- case 2:
- cr16_ins->rtype = BFD_RELOC_CR16_REGREL16;
- break;
- case 3:
- if (cur_arg->size == 20)
- cr16_ins->rtype = BFD_RELOC_CR16_REGREL20;
- else
- cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a;
- break;
- default:
- break;
- }
- break;
+ symbol_with_at_gotc = 1;
+ }
+ else if (strneq (input_line_pointer, "@GOT", 4)
+ || strneq (input_line_pointer, "@got", 4))
+ {
+ if ((strneq (input_line_pointer, "+", 1))
+ || (strneq (input_line_pointer, "-", 1)))
+ as_warn (_("GOT bad expression with %s."), input_line_pointer);
- case arg_idxr:
- if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
- cr16_ins->rtype = BFD_RELOC_CR16_REGREL20;
- break;
+ if (GOT_symbol == NULL)
+ GOT_symbol = symbol_find_or_make (GLOBAL_OFFSET_TABLE_NAME);
- case arg_idxrp:
- if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
- switch (instruction->size)
- {
- case 1: cr16_ins->rtype = BFD_RELOC_CR16_REGREL0; break;
- case 2: cr16_ins->rtype = BFD_RELOC_CR16_REGREL14; break;
- case 3: cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; break;
- default: break;
- }
- break;
+ symbol_with_at_got = 1;
+ }
+
+ switch (cur_arg->type)
+ {
+ case arg_cr:
+ if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
+ {
+ if (symbol_with_at_got)
+ cr16_ins->rtype = BFD_RELOC_CR16_GOT_REGREL20;
+ else if (symbol_with_at_gotc)
+ cr16_ins->rtype = BFD_RELOC_CR16_GOTC_REGREL20;
+ else if (cur_arg->size == 20)
+ cr16_ins->rtype = BFD_RELOC_CR16_REGREL20;
+ else
+ cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a;
+ }
+ break;
- case arg_c:
- if (IS_INSN_MNEMONIC ("bal"))
- cr16_ins->rtype = BFD_RELOC_CR16_DISP24;
- else if (IS_INSN_TYPE (BRANCH_INS))
+ case arg_crp:
+ if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
+ {
+ if (symbol_with_at_got)
+ cr16_ins->rtype = BFD_RELOC_CR16_GOT_REGREL20;
+ else if (symbol_with_at_gotc)
+ cr16_ins->rtype = BFD_RELOC_CR16_GOTC_REGREL20;
+ } else {
+ switch (instruction->size)
+ {
+ case 1:
+ switch (cur_arg->size)
+ {
+ case 0:
+ cr16_ins->rtype = BFD_RELOC_CR16_REGREL0;
+ break;
+ case 4:
+ if (IS_INSN_MNEMONIC ("loadb") || IS_INSN_MNEMONIC ("storb"))
+ cr16_ins->rtype = BFD_RELOC_CR16_REGREL4;
+ else
+ cr16_ins->rtype = BFD_RELOC_CR16_REGREL4a;
+ break;
+ default: break;
+ }
+ break;
+ case 2:
+ cr16_ins->rtype = BFD_RELOC_CR16_REGREL16;
+ break;
+ case 3:
+ if (cur_arg->size == 20)
+ cr16_ins->rtype = BFD_RELOC_CR16_REGREL20;
+ else
+ cr16_ins->rtype = BFD_RELOC_CR16_REGREL20a;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+
+ case arg_idxr:
+ if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
{
- if (symbol_with_s)
- cr16_ins->rtype = BFD_RELOC_CR16_DISP8;
- else if (symbol_with_m)
- cr16_ins->rtype = BFD_RELOC_CR16_DISP16;
+ if (symbol_with_at_got)
+ cr16_ins->rtype = BFD_RELOC_CR16_GOT_REGREL20;
+ else if (symbol_with_at_gotc)
+ cr16_ins->rtype = BFD_RELOC_CR16_GOTC_REGREL20;
else
- cr16_ins->rtype = BFD_RELOC_CR16_DISP24;
+ cr16_ins->rtype = BFD_RELOC_CR16_REGREL20;
}
- else if (IS_INSN_TYPE (STOR_IMM_INS) || IS_INSN_TYPE (LD_STOR_INS)
- || IS_INSN_TYPE (CSTBIT_INS))
+ break;
+
+ case arg_idxrp:
+ if (IS_INSN_TYPE (LD_STOR_INS) || IS_INSN_TYPE (CSTBIT_INS))
{
- if (symbol_with_s)
- as_bad (_("operand %d: illegal use expression: `%s`"), cur_arg_num + 1, str);
- if (symbol_with_m)
- cr16_ins->rtype = BFD_RELOC_CR16_ABS20;
- else /* Default to (symbol_with_l) */
- cr16_ins->rtype = BFD_RELOC_CR16_ABS24;
+ if (symbol_with_at_got)
+ cr16_ins->rtype = BFD_RELOC_CR16_GOT_REGREL20;
+ else if (symbol_with_at_gotc)
+ cr16_ins->rtype = BFD_RELOC_CR16_GOTC_REGREL20;
+ else {
+ switch (instruction->size)
+ {
+ case 1: cr16_ins->rtype = BFD_RELOC_CR16_REGREL0; break;
+ case 2: cr16_ins->rtype = BFD_RELOC_CR16_REGREL14; break;
+ case 3: cr16_ins->rtype = BFD_RELOC_CR16_REGREL20; break;
+ default: break;
+ }
}
- else if (IS_INSN_TYPE (BRANCH_NEQ_INS))
- cr16_ins->rtype = BFD_RELOC_CR16_DISP4;
+ }
+ break;
+
+ case arg_c:
+ if (IS_INSN_MNEMONIC ("bal"))
+ cr16_ins->rtype = BFD_RELOC_CR16_DISP24;
+ else if (IS_INSN_TYPE (BRANCH_INS))
+ {
+ if (symbol_with_l)
+ cr16_ins->rtype = BFD_RELOC_CR16_DISP24;
+ else if (symbol_with_m)
+ cr16_ins->rtype = BFD_RELOC_CR16_DISP16;
+ else
+ cr16_ins->rtype = BFD_RELOC_CR16_DISP8;
+ }
+ else if (IS_INSN_TYPE (STOR_IMM_INS) || IS_INSN_TYPE (LD_STOR_INS)
+ || IS_INSN_TYPE (CSTBIT_INS))
+ {
+ if (symbol_with_s)
+ as_bad (_("operand %d: illegal use expression: `%s`"), cur_arg_num + 1, str);
+ if (symbol_with_at_got)
+ cr16_ins->rtype = BFD_RELOC_CR16_GOT_REGREL20;
+ else if (symbol_with_at_gotc)
+ cr16_ins->rtype = BFD_RELOC_CR16_GOTC_REGREL20;
+ else if (symbol_with_m)
+ cr16_ins->rtype = BFD_RELOC_CR16_ABS20;
+ else /* Default to (symbol_with_l) */
+ cr16_ins->rtype = BFD_RELOC_CR16_ABS24;
+ }
+ else if (IS_INSN_TYPE (BRANCH_NEQ_INS))
+ cr16_ins->rtype = BFD_RELOC_CR16_DISP4;
break;
case arg_ic:
if (IS_INSN_TYPE (ARITH_INS))
{
- if (symbol_with_s)
+ if (symbol_with_at_got)
+ cr16_ins->rtype = BFD_RELOC_CR16_GOT_REGREL20;
+ else if (symbol_with_at_gotc)
+ cr16_ins->rtype = BFD_RELOC_CR16_GOTC_REGREL20;
+ else if (symbol_with_s)
cr16_ins->rtype = BFD_RELOC_CR16_IMM4;
else if (symbol_with_m)
cr16_ins->rtype = BFD_RELOC_CR16_IMM20;
cr16_ins->rtype = BFD_RELOC_CR16_IMM32;
}
else if (IS_INSN_TYPE (ARITH_BYTE_INS))
- {
- cr16_ins->rtype = BFD_RELOC_CR16_IMM16;
- }
+ {
+ cr16_ins->rtype = BFD_RELOC_CR16_IMM16;
+ }
break;
default:
break;
- }
+ }
break;
default:
static int
getreg_image (reg r)
{
- const reg_entry *reg;
+ const reg_entry *rreg;
char *reg_name;
int is_procreg = 0; /* Nonzero means argument should be processor reg. */
/* Check whether the register is in registers table. */
if (r < MAX_REG)
- reg = cr16_regtab + r;
+ rreg = cr16_regtab + r;
else /* Register not found. */
{
as_bad (_("Unknown register: `%d'"), r);
return 0;
}
- reg_name = reg->name;
+ reg_name = rreg->name;
/* Issue a error message when register is illegal. */
#define IMAGE_ERR \
as_bad (_("Illegal register (`%s') in Instruction: `%s'"), \
- reg_name, ins_parse); \
- break;
+ reg_name, ins_parse);
- switch (reg->type)
+ switch (rreg->type)
{
case CR16_R_REGTYPE:
if (! is_procreg)
- return reg->image;
+ return rreg->image;
else
- IMAGE_ERR;
+ IMAGE_ERR;
+ break;
case CR16_P_REGTYPE:
- return reg->image;
+ return rreg->image;
break;
default:
IMAGE_ERR;
+ break;
}
return 0;
static void
set_operand (char *operand, ins * cr16_ins)
{
- char *operandS; /* Pointer to start of sub-opearand. */
- char *operandE; /* Pointer to end of sub-opearand. */
+ char *operandS; /* Pointer to start of sub-operand. */
+ char *operandE; /* Pointer to end of sub-operand. */
argument *cur_arg = &cr16_ins->arg[cur_arg_num]; /* Current argument. */
{
case arg_ic: /* Case $0x18. */
operandS++;
+ /* Fall through. */
case arg_c: /* Case 0x18. */
/* Set constant. */
process_label_constant (operandS, cr16_ins);
*operandE = '\0';
process_label_constant (operandS, cr16_ins);
operandS = operandE;
+ /* Fall through. */
case arg_rbase: /* Case (r1) or (r1,r0). */
operandS++;
/* Set register base. */
/* set the arg->rp, if reg is "r12" or "r13" or "14" or "15" */
if ((cur_arg->type != arg_rbase)
- && ((getreg_image (cur_arg->r) == 12)
- || (getreg_image (cur_arg->r) == 13)
- || (getreg_image (cur_arg->r) == 14)
- || (getreg_image (cur_arg->r) == 15)))
+ && ((getreg_image (cur_arg->r) == 12)
+ || (getreg_image (cur_arg->r) == 13)
+ || (getreg_image (cur_arg->r) == 14)
+ || (getreg_image (cur_arg->r) == 15)))
{
cur_arg->type = arg_crp;
cur_arg->rp = cur_arg->r;
cur_arg->type = arg_idxrp;
}
else
- cur_arg->rp = -1;
+ cur_arg->rp = -1;
operandE = operandS;
/* Set displacement constant. */
{
case '$':
if (strchr (operand, '(') != NULL)
- cur_arg->type = arg_icr;
+ cur_arg->type = arg_icr;
else
- cur_arg->type = arg_ic;
+ cur_arg->type = arg_ic;
goto set_params;
break;
if (strcasecmp (trap->name, s) == 0)
return trap->entry;
- /* To make compatable with CR16 4.1 tools, the below 3-lines of
+ /* To make compatible with CR16 4.1 tools, the below 3-lines of
* code added. Refer: Development Tracker item #123 */
for (trap = cr16_traps; trap < (cr16_traps + NUMTRAPS); trap++)
if (trap->entry == (unsigned int) atoi (s))
is_bcc_insn (char * op)
{
if (!(streq (op, "bal") || streq (op, "beq0b") || streq (op, "bnq0b")
- || streq (op, "beq0w") || streq (op, "bnq0w")))
+ || streq (op, "beq0w") || streq (op, "bnq0w")))
if ((op[0] == 'b') && (get_b_cc (op) != NULL))
return 1;
return 0;
/* Cinv instruction requires special handling. */
-static int
+static void
check_cinv_options (char * operand)
{
char *p = operand;
- int i_used = 0, u_used = 0, d_used = 0;
while (*++p != ']')
{
- if (*p == ',' || *p == ' ')
- continue;
-
- else if (*p == 'i')
- i_used = 1;
- else if (*p == 'u')
- u_used = 1;
- else if (*p == 'd')
- d_used = 1;
- else
- as_bad (_("Illegal `cinv' parameter: `%c'"), *p);
+ switch (*p)
+ {
+ case ',':
+ case ' ':
+ case 'i':
+ case 'u':
+ case 'd':
+ break;
+ default:
+ as_bad (_("Illegal `cinv' parameter: `%c'"), *p);
+ }
}
-
- return 0;
}
/* Retrieve the opcode image of a given register pair.
static int
getregp_image (reg r)
{
- const reg_entry *reg;
+ const reg_entry *rreg;
char *reg_name;
/* Check whether the register is in registers table. */
if (r < MAX_REG)
- reg = cr16_regptab + r;
+ rreg = cr16_regptab + r;
/* Register not found. */
else
{
return 0;
}
- reg_name = reg->name;
+ reg_name = rreg->name;
/* Issue a error message when register pair is illegal. */
#define RPAIR_IMAGE_ERR \
reg_name, ins_parse); \
break;
- switch (reg->type)
+ switch (rreg->type)
{
case CR16_RP_REGTYPE:
- return reg->image;
+ return rreg->image;
default:
RPAIR_IMAGE_ERR;
}
static int
getidxregp_image (reg r)
{
- const reg_entry *reg;
+ const reg_entry *rreg;
char *reg_name;
/* Check whether the register is in registers table. */
if (r < MAX_REG)
- reg = cr16_regptab + r;
+ rreg = cr16_regptab + r;
/* Register not found. */
else
{
return 0;
}
- reg_name = reg->name;
+ reg_name = rreg->name;
/* Issue a error message when register pair is illegal. */
#define IDX_RPAIR_IMAGE_ERR \
as_bad (_("Illegal index register pair (`%s') in Instruction: `%s'"), \
reg_name, ins_parse); \
- if (reg->type == CR16_RP_REGTYPE)
+ if (rreg->type == CR16_RP_REGTYPE)
{
- switch (reg->image)
- {
- case 0: return 0; break;
- case 2: return 1; break;
- case 4: return 2; break;
- case 6: return 3; break;
- case 8: return 4; break;
- case 10: return 5; break;
- case 3: return 6; break;
- case 5: return 7; break;
- default:
- break;
- }
+ switch (rreg->image)
+ {
+ case 0: return 0; break;
+ case 2: return 1; break;
+ case 4: return 2; break;
+ case 6: return 3; break;
+ case 8: return 4; break;
+ case 10: return 5; break;
+ case 3: return 6; break;
+ case 5: return 7; break;
+ default:
+ break;
+ }
}
IDX_RPAIR_IMAGE_ERR;
return 0;
}
-/* Retrieve the opcode image of a given processort register.
+/* Retrieve the opcode image of a given processor register.
If the register is illegal for the current instruction,
issue an error. */
static int
-getprocreg_image (reg r)
+getprocreg_image (int r)
{
- const reg_entry *reg;
+ const reg_entry *rreg;
char *reg_name;
/* Check whether the register is in registers table. */
- if (r < MAX_PREG)
- reg = &cr16_pregtab[r - MAX_REG];
+ if (r >= MAX_REG && r < MAX_PREG)
+ rreg = &cr16_pregtab[r - MAX_REG];
/* Register not found. */
else
{
return 0;
}
- reg_name = reg->name;
+ reg_name = rreg->name;
/* Issue a error message when register pair is illegal. */
#define PROCREG_IMAGE_ERR \
reg_name, ins_parse); \
break;
- switch (reg->type)
+ switch (rreg->type)
{
case CR16_P_REGTYPE:
- return reg->image;
+ return rreg->image;
default:
PROCREG_IMAGE_ERR;
}
return 0;
}
-/* Retrieve the opcode image of a given processort register.
+/* Retrieve the opcode image of a given processor register.
If the register is illegal for the current instruction,
issue an error. */
static int
-getprocregp_image (reg r)
+getprocregp_image (int r)
{
- const reg_entry *reg;
+ const reg_entry *rreg;
char *reg_name;
int pregptab_disp = 0;
/* Check whether the register is in registers table. */
- if (r < MAX_PREG)
+ if (r >= MAX_REG && r < MAX_PREG)
{
r = r - MAX_REG;
switch (r)
{
- case 4: pregptab_disp = 1; break;
- case 6: pregptab_disp = 2; break;
- case 8:
- case 9:
- case 10:
- pregptab_disp = 3; break;
- case 12:
- pregptab_disp = 4; break;
- case 14:
- pregptab_disp = 5; break;
- default: break;
+ case 4: pregptab_disp = 1; break;
+ case 6: pregptab_disp = 2; break;
+ case 8:
+ case 9:
+ case 10:
+ pregptab_disp = 3; break;
+ case 12:
+ pregptab_disp = 4; break;
+ case 14:
+ pregptab_disp = 5; break;
+ default: break;
}
- reg = &cr16_pregptab[r - pregptab_disp];
+ rreg = &cr16_pregptab[r - pregptab_disp];
}
/* Register not found. */
else
return 0;
}
- reg_name = reg->name;
+ reg_name = rreg->name;
/* Issue a error message when register pair is illegal. */
#define PROCREGP_IMAGE_ERR \
reg_name, ins_parse); \
break;
- switch (reg->type)
+ switch (rreg->type)
{
case CR16_P_REGTYPE:
- return reg->image;
+ return rreg->image;
default:
PROCREGP_IMAGE_ERR;
}
case 32:
case 28:
/* mask the upper part of the constant, that is, the bits
- going to the lowest byte of output_opcode[0].
- The upper part of output_opcode[1] is always filled,
- therefore it is always masked with 0xFFFF. */
+ going to the lowest byte of output_opcode[0].
+ The upper part of output_opcode[1] is always filled,
+ therefore it is always masked with 0xFFFF. */
mask = (1 << (nbits - 16)) - 1;
/* Divide the constant between two consecutive words :
- 0 1 2 3
- +---------+---------+---------+---------+
- | | X X X X | x X x X | |
- +---------+---------+---------+---------+
- output_opcode[0] output_opcode[1] */
+ 0 1 2 3
+ +---------+---------+---------+---------+
+ | | X X X X | x X x X | |
+ +---------+---------+---------+---------+
+ output_opcode[0] output_opcode[1] */
CR16_PRINT (0, (constant >> WORD_SHIFT) & mask, 0);
CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT);
break;
case 21:
- if ((nbits == 21) && (IS_INSN_TYPE (LD_STOR_INS))) nbits = 20;
+ if ((nbits == 21) && (IS_INSN_TYPE (LD_STOR_INS)))
+ nbits = 20;
+ /* Fall through. */
case 24:
case 22:
case 20:
/* mask the upper part of the constant, that is, the bits
- going to the lowest byte of output_opcode[0].
- The upper part of output_opcode[1] is always filled,
- therefore it is always masked with 0xFFFF. */
+ going to the lowest byte of output_opcode[0].
+ The upper part of output_opcode[1] is always filled,
+ therefore it is always masked with 0xFFFF. */
mask = (1 << (nbits - 16)) - 1;
/* Divide the constant between two consecutive words :
- 0 1 2 3
- +---------+---------+---------+---------+
- | | X X X X | - X - X | |
- +---------+---------+---------+---------+
- output_opcode[0] output_opcode[1] */
+ 0 1 2 3
+ +---------+---------+---------+---------+
+ | | X X X X | - X - X | |
+ +---------+---------+---------+---------+
+ output_opcode[0] output_opcode[1] */
if ((instruction->size > 2) && (shift == WORD_SHIFT))
- {
- if (arg->type == arg_idxrp)
- {
- CR16_PRINT (0, ((constant >> WORD_SHIFT) & mask) << 8, 0);
- CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT);
- }
- else
- {
- CR16_PRINT (0, (((((constant >> WORD_SHIFT) & mask) << 8) & 0x0f00) | ((((constant >> WORD_SHIFT) & mask) >> 4) & 0xf)),0);
- CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT);
- }
- }
+ {
+ if (arg->type == arg_idxrp)
+ {
+ CR16_PRINT (0, ((constant >> WORD_SHIFT) & mask) << 8, 0);
+ CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT);
+ }
+ else
+ {
+ CR16_PRINT (0, (((((constant >> WORD_SHIFT) & mask) << 8) & 0x0f00) | ((((constant >> WORD_SHIFT) & mask) >> 4) & 0xf)),0);
+ CR16_PRINT (1, (constant & 0xFFFF), WORD_SHIFT);
+ }
+ }
else
- CR16_PRINT (0, constant, shift);
+ CR16_PRINT (0, constant, shift);
break;
case 14:
if (arg->type == arg_idxrp)
- {
- if (instruction->size == 2)
- {
- CR16_PRINT (0, ((constant)&0xf), shift); // 0-3 bits
- CR16_PRINT (0, ((constant>>4)&0x3), (shift+20)); // 4-5 bits
- CR16_PRINT (0, ((constant>>6)&0x3), (shift+14)); // 6-7 bits
- CR16_PRINT (0, ((constant>>8)&0x3f), (shift+8)); // 8-13 bits
- }
- else
- CR16_PRINT (0, constant, shift);
- }
+ {
+ if (instruction->size == 2)
+ {
+ CR16_PRINT (0, ((constant) & 0xf), shift); /* 0-3 bits. */
+ CR16_PRINT (0, ((constant >> 4) & 0x3), (shift + 20)); /* 4-5 bits. */
+ CR16_PRINT (0, ((constant >> 6) & 0x3), (shift + 14)); /* 6-7 bits. */
+ CR16_PRINT (0, ((constant >> 8) & 0x3f), (shift + 8)); /* 8-13 bits. */
+ }
+ else
+ CR16_PRINT (0, constant, shift);
+ }
break;
case 16:
case 12:
/* 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] */
+ 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 overridden.
+ 0 1 2 3
+ +---------+---------+---------+---------+
+ | 'match' | | X X X X | |
+ +---------+---------+---------+---------+
+ output_opcode[0] output_opcode[1] */
if ((instruction->size > 2) && (shift == WORD_SHIFT))
- CR16_PRINT (1, constant, WORD_SHIFT);
+ CR16_PRINT (1, constant, WORD_SHIFT);
else
- CR16_PRINT (0, constant, shift);
+ CR16_PRINT (0, constant, shift);
break;
case 8:
- CR16_PRINT (0, ((constant/2)&0xf), shift);
- CR16_PRINT (0, ((constant/2)>>4), (shift+8));
+ CR16_PRINT (0, ((constant / 2) & 0xf), shift);
+ CR16_PRINT (0, ((constant / 2) >> 4), (shift + 8));
break;
default:
+-----------------------------+ */
if (instruction->size == 3)
- {
- CR16_PRINT (0, getidxregp_image (arg->rp), 0);
- if (getreg_image (arg->i_r) == 12)
- CR16_PRINT (0, 0, 3);
- else
- CR16_PRINT (0, 1, 3);
- }
+ {
+ CR16_PRINT (0, getidxregp_image (arg->rp), 0);
+ if (getreg_image (arg->i_r) == 12)
+ CR16_PRINT (0, 0, 3);
+ else
+ CR16_PRINT (0, 1, 3);
+ }
else
- {
- CR16_PRINT (0, getidxregp_image (arg->rp), 16);
- if (getreg_image (arg->i_r) == 12)
- CR16_PRINT (0, 0, 19);
- else
- CR16_PRINT (0, 1, 19);
- }
+ {
+ CR16_PRINT (0, getidxregp_image (arg->rp), 16);
+ if (getreg_image (arg->i_r) == 12)
+ CR16_PRINT (0, 0, 19);
+ else
+ CR16_PRINT (0, 1, 19);
+ }
print_constant (nbits, shift, arg);
break;
case arg_idxr:
if (getreg_image (arg->i_r) == 12)
- if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb")
- || IS_INSN_MNEMONIC ("tbitb"))
- CR16_PRINT (0, 0, 23);
- else CR16_PRINT (0, 0, 24);
+ if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb")
+ || IS_INSN_MNEMONIC ("tbitb"))
+ CR16_PRINT (0, 0, 23);
+ else CR16_PRINT (0, 0, 24);
else
- if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb")
- || IS_INSN_MNEMONIC ("tbitb"))
- CR16_PRINT (0, 1, 23);
- else CR16_PRINT (0, 1, 24);
+ if (IS_INSN_MNEMONIC ("cbitb") || IS_INSN_MNEMONIC ("sbitb")
+ || IS_INSN_MNEMONIC ("tbitb"))
+ CR16_PRINT (0, 1, 23);
+ else CR16_PRINT (0, 1, 24);
print_constant (nbits, shift, arg);
break;
case arg_crp:
print_constant (nbits, shift , arg);
if (instruction->size > 1)
- CR16_PRINT (0, getregp_image (arg->rp), (shift + 16));
+ CR16_PRINT (0, getregp_image (arg->rp), (shift + 16));
else if (IS_INSN_TYPE (LD_STOR_INS) || (IS_INSN_TYPE (CSTBIT_INS)))
- {
- if (instruction->size == 2)
- CR16_PRINT (0, getregp_image (arg->rp), (shift - 8));
- else if (instruction->size == 1)
- CR16_PRINT (0, getregp_image (arg->rp), 16);
- }
+ {
+ if (instruction->size == 2)
+ CR16_PRINT (0, getregp_image (arg->rp), (shift - 8));
+ else if (instruction->size == 1)
+ CR16_PRINT (0, getregp_image (arg->rp), 16);
+ }
else
- CR16_PRINT (0, getregp_image (arg->rp), shift);
+ CR16_PRINT (0, getregp_image (arg->rp), shift);
break;
default:
check_range (long *num, int bits, int unsigned flags, int update)
{
long min, max;
- int retval = OP_LEGAL;
+ op_err retval = OP_LEGAL;
long value = *num;
if (bits == 0 && value > 0) return OP_OUT_OF_RANGE;
- /* For hosts witah longs bigger than 32-bits make sure that the top
+ /* For hosts with longs bigger than 32-bits make sure that the top
bits of a 32-bit negative value read in by the parser are set,
so that the correct comparisons are made. */
if (value & 0x80000000)
- value |= (-1L << 31);
+ value |= (-1UL << 31);
/* Verify operand value is even. */
if (value == 0xB || value == 0x9)
return OP_OUT_OF_RANGE;
else if (value == -1)
- {
- if (update)
- *num = 9;
- return retval;
- }
+ {
+ if (update)
+ *num = 9;
+ return retval;
+ }
}
if (flags & OP_ESC1)
else if (flags & OP_NEG)
{
max = - 1;
- min = - ((1 << (bits - 1))-1);
+ min = - ((1 << (bits - 1)) - 1);
if ((value > max) || (value < min))
retval = OP_OUT_OF_RANGE;
}
return retval;
}
-/* Bunch of error checkings.
+/* Bunch of error checking.
The checks are made after a matching instruction was found. */
static void
{
unsigned int count = insn->arg[0].constant, reg_val;
- /* Check if count operand caused to save/retrive the RA twice
- to generate warning message. */
+ /* Check if count operand caused to save/retrieve the RA twice
+ to generate warning message. */
if (insn->nargs > 2)
{
reg_val = getreg_image (insn->arg[1].r);
if ( ((reg_val == 9) && (count > 7))
- || ((reg_val == 10) && (count > 6))
- || ((reg_val == 11) && (count > 5))
- || ((reg_val == 12) && (count > 4))
- || ((reg_val == 13) && (count > 2))
- || ((reg_val == 14) && (count > 0)))
+ || ((reg_val == 10) && (count > 6))
+ || ((reg_val == 11) && (count > 5))
+ || ((reg_val == 12) && (count > 4))
+ || ((reg_val == 13) && (count > 2))
+ || ((reg_val == 14) && (count > 0)))
as_warn (_("RA register is saved twice."));
/* Check if the third operand is "RA" or "ra" */
/* If register is a register pair ie r12/r13/r14 in operand1, then
the count constant should be validated. */
if (((reg_val == 11) && (count > 7))
- || ((reg_val == 12) && (count > 6))
- || ((reg_val == 13) && (count > 4))
- || ((reg_val == 14) && (count > 2))
- || ((reg_val == 15) && (count > 0)))
+ || ((reg_val == 12) && (count > 6))
+ || ((reg_val == 13) && (count > 4))
+ || ((reg_val == 14) && (count > 2))
+ || ((reg_val == 15) && (count > 0)))
as_bad (_("`%s' Illegal count-register combination."), ins_parse);
}
else
Returns 1 upon success, 0 upon failure. */
static int
-assemble_insn (char *mnemonic, ins *insn)
+assemble_insn (const char *mnemonic, ins *insn)
{
/* Type of each operand in the current template. */
argtype cur_type[MAX_OPERANDS];
/* If 'bal' instruction size is '2' and reg operand is not 'ra'
then goto next instruction. */
if (IS_INSN_MNEMONIC ("bal") && (i == 0)
- && (instruction->size == 2) && (insn->arg[i].rp != 14))
+ && (instruction->size == 2) && (insn->arg[i].rp != 14))
goto next_insn;
/* If 'storb' instruction with 'sp' reg and 16-bit disp of
- * reg-pair, leads to undifined trap, so this should use
+ * reg-pair, leads to undefined trap, so this should use
* 20-bit disp of reg-pair. */
if (IS_INSN_MNEMONIC ("storb") && (instruction->size == 2)
- && (insn->arg[i].r == 15) && (insn->arg[i + 1].type == arg_crp))
+ && (insn->arg[i].r == 15) && (insn->arg[i + 1].type == arg_crp))
goto next_insn;
/* Only check range - don't update the constant's value, since the
determined) is sufficient. */
else if ((insn->arg[i].X_op == O_symbol)
&& ((bfd_reloc_type_lookup (stdoutput, insn->rtype))->bitsize
- > cur_size[i]))
+ > cur_size[i]))
goto next_insn;
}
found_const_within_range = 1;
match = 1;
break;
-/* Try again with next instruction. */
-next_insn:
+ /* Try again with next instruction. */
+ next_insn:
instruction++;
}
{
switch (const_err)
{
- case OP_OUT_OF_RANGE:
- as_bad (_("Operand out of range (arg %d)"), invalid_const);
- break;
- case OP_NOT_EVEN:
- as_bad (_("Operand has odd displacement (arg %d)"), invalid_const);
- break;
- default:
- as_bad (_("Illegal operand (arg %d)"), invalid_const);
- break;
+ case OP_OUT_OF_RANGE:
+ as_bad (_("Operand out of range (arg %d)"), invalid_const);
+ break;
+ case OP_NOT_EVEN:
+ as_bad (_("Operand has odd displacement (arg %d)"), invalid_const);
+ break;
+ default:
+ as_bad (_("Illegal operand (arg %d)"), invalid_const);
+ break;
}
}
else
/* Full match - print the encoding to output file. */
{
- /* Make further checkings (such that couldn't be made earlier).
+ /* Make further checking (such that couldn't be made earlier).
Warn the user if necessary. */
warn_if_needed (insn);
for (i = 0; i < insn->nargs; i++)
{
- /* For BAL (ra),disp17 instuction only. And also set the
+ /* For BAL (ra),disp17 instruction only. And also set the
DISP24a relocation type. */
if (IS_INSN_MNEMONIC ("bal") && (instruction->size == 2) && i == 0)
{
words[j++] = output_opcode[i] & 0xFFFF;
}
- insn_size = instruction->size;
- this_frag = frag_more (insn_size * 2);
-
/* Handle relocation. */
- if ((relocatable) && (insn->rtype != BFD_RELOC_NONE))
+ if ((instruction->flags & RELAXABLE) && relocatable)
+ {
+ int relax_subtype;
+ /* Write the maximal instruction size supported. */
+ insn_size = INSN_MAX_SIZE;
+
+ if (IS_INSN_TYPE (BRANCH_INS))
+ {
+ switch (insn->rtype)
+ {
+ case BFD_RELOC_CR16_DISP24:
+ relax_subtype = 2;
+ break;
+ case BFD_RELOC_CR16_DISP16:
+ relax_subtype = 1;
+ break;
+ default:
+ relax_subtype = 0;
+ break;
+ }
+ }
+ else
+ abort ();
+
+ this_frag = frag_var (rs_machine_dependent, insn_size *2,
+ 4, relax_subtype,
+ insn->exp.X_add_symbol,
+ 0,
+ 0);
+ }
+ else
{
- reloc_howto_type *reloc_howto;
- int size;
+ insn_size = instruction->size;
+ this_frag = frag_more (insn_size * 2);
+
+ if ((relocatable) && (insn->rtype != BFD_RELOC_NONE))
+ {
+ reloc_howto_type *reloc_howto;
+ int size;
- reloc_howto = bfd_reloc_type_lookup (stdoutput, insn->rtype);
+ reloc_howto = bfd_reloc_type_lookup (stdoutput, insn->rtype);
- if (!reloc_howto)
- abort ();
+ if (!reloc_howto)
+ abort ();
- size = bfd_get_reloc_size (reloc_howto);
+ size = bfd_get_reloc_size (reloc_howto);
- if (size < 1 || size > 4)
- abort ();
+ if (size < 1 || size > 4)
+ abort ();
- fix_new_exp (frag_now, this_frag - frag_now->fr_literal,
- size, &insn->exp, reloc_howto->pc_relative,
- insn->rtype);
+ fix_new_exp (frag_now, this_frag - frag_now->fr_literal,
+ size, &insn->exp, reloc_howto->pc_relative,
+ insn->rtype);
+ }
}
/* Verify a 2-byte code alignment. */
}
}
+/* Actually assemble an instruction. */
+
+static void
+cr16_assemble (const char *op, char *param)
+{
+ ins cr16_ins;
+
+ /* Find the instruction. */
+ instruction = (const inst *) hash_find (cr16_inst_hash, op);
+ if (instruction == NULL)
+ {
+ as_bad (_("Unknown opcode: `%s'"), op);
+ return;
+ }
+
+ /* Tie dwarf2 debug info to the address at the start of the insn. */
+ dwarf2_emit_insn (0);
+
+ /* Parse the instruction's operands. */
+ parse_insn (&cr16_ins, param);
+
+ /* Assemble the instruction - return upon failure. */
+ if (assemble_insn (op, &cr16_ins) == 0)
+ return;
+
+ /* Print the instruction. */
+ print_insn (&cr16_ins);
+}
+
/* This is the guts of the machine-dependent assembler. OP points to a
machine dependent instruction. This function is supposed to emit
the frags/bytes it assembles to. */
{
ins cr16_ins;
char *param, param1[32];
- char c;
/* Reset global variables for a new instruction. */
reset_vars (op);
/* Strip the mnemonic. */
for (param = op; *param != 0 && !ISSPACE (*param); param++)
;
- c = *param;
*param++ = '\0';
- /* bCC instuctions and adjust the mnemonic by adding extra white spaces. */
+ /* bCC instructions and adjust the mnemonic by adding extra white spaces. */
if (is_bcc_insn (op))
{
strcpy (param1, get_b_cc (op));
- op = "b";
strcat (param1,",");
strcat (param1, param);
param = (char *) ¶m1;
+ cr16_assemble ("b", param);
+ return;
}
/* Checking the cinv options and adjust the mnemonic by removing the
if (streq ("cinv", op))
{
/* Validate the cinv options. */
+ unsigned int op_len, param_len;
check_cinv_options (param);
- strcat (op, param);
+ op_len = strlen (op);
+ param_len = strlen (param) + 1;
+ memmove (op + op_len, param, param_len);
}
/* MAPPING - SHIFT INSN, if imm4/imm16 positive values
lsh[b/w] imm4/imm6, reg ==> ashu[b/w] imm4/imm16, reg
- as CR16 core doesn't support lsh[b/w] right shift operaions. */
+ as CR16 core doesn't support lsh[b/w] right shift operations. */
if ((streq ("lshb", op) || streq ("lshw", op) || streq ("lshd", op))
&& (param [0] == '$'))
{
instruction = (const inst *) hash_find (cr16_inst_hash, op);
parse_operands (&cr16_ins, param1);
if (((&cr16_ins)->arg[0].type == arg_ic)
- && ((&cr16_ins)->arg[0].constant >= 0))
+ && ((&cr16_ins)->arg[0].constant >= 0))
{
if (streq ("lshb", op))
- op = "ashub";
+ cr16_assemble ("ashub", param);
else if (streq ("lshd", op))
- op = "ashud";
- else
- op = "ashuw";
+ cr16_assemble ("ashud", param);
+ else
+ cr16_assemble ("ashuw", param);
+ return;
}
}
- /* Find the instruction. */
- instruction = (const inst *) hash_find (cr16_inst_hash, op);
- if (instruction == NULL)
- {
- as_bad (_("Unknown opcode: `%s'"), op);
- return;
- }
-
- /* Tie dwarf2 debug info to the address at the start of the insn. */
- dwarf2_emit_insn (0);
-
- /* Parse the instruction's operands. */
- parse_insn (&cr16_ins, param);
-
- /* Assemble the instruction - return upon failure. */
- if (assemble_insn (op, &cr16_ins) == 0)
- return;
-
- /* Print the instruction. */
- print_insn (&cr16_ins);
+ cr16_assemble (op, param);
}