/* tc-m32c.c -- Assembler for the Renesas M32C.
- Copyright (C) 2005, 2006 Free Software Foundation.
+ Copyright (C) 2005-2016 Free Software Foundation, Inc.
Contributed by RedHat.
This file is part of GAS, the GNU Assembler.
GAS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
+ the Free Software Foundation; either version 3, or (at your option)
any later version.
GAS is distributed in the hope that it will be useful,
Boston, MA 02111-1307, USA. */
#include "as.h"
-#include "subsegs.h"
+#include "subsegs.h"
#include "symcat.h"
#include "opcodes/m32c-desc.h"
#include "opcodes/m32c-opc.h"
}
m32c_insn;
-#define rl_for(insn) (CGEN_ATTR_CGEN_INSN_RL_TYPE_VALUE (&(insn.insn->base->attrs)))
-#define relaxable(insn) (CGEN_ATTR_CGEN_INSN_RELAXABLE_VALUE (&(insn.insn->base->attrs)))
+#define rl_for(_insn) (CGEN_ATTR_CGEN_INSN_RL_TYPE_VALUE (&((_insn).insn->base->attrs)))
+#define relaxable(_insn) (CGEN_ATTR_CGEN_INSN_RELAXABLE_VALUE (&((_insn).insn->base->attrs)))
const char comment_chars[] = ";";
const char line_comment_chars[] = "#";
#define OPTION_CPU_M16C (OPTION_MD_BASE)
#define OPTION_CPU_M32C (OPTION_MD_BASE + 1)
#define OPTION_LINKRELAX (OPTION_MD_BASE + 2)
+#define OPTION_H_TICK_HEX (OPTION_MD_BASE + 3)
struct option md_longopts[] =
{
{ "m16c", no_argument, NULL, OPTION_CPU_M16C },
{ "m32c", no_argument, NULL, OPTION_CPU_M32C },
{ "relax", no_argument, NULL, OPTION_LINKRELAX },
+ { "h-tick-hex", no_argument, NULL, OPTION_H_TICK_HEX },
{NULL, no_argument, NULL, 0}
};
size_t md_longopts_size = sizeof (md_longopts);
static void s_bss (int);
int
-md_parse_option (int c, char * arg ATTRIBUTE_UNUSED)
+md_parse_option (int c, const char * arg ATTRIBUTE_UNUSED)
{
switch (c)
{
m32c_relax = 1;
break;
+ case OPTION_H_TICK_HEX:
+ enable_h_tick_hex = 1;
+ break;
+
default:
return 0;
}
md_show_usage (FILE * stream)
{
fprintf (stream, _(" M32C specific command line options:\n"));
-}
+}
static void
s_bss (int ignore ATTRIBUTE_UNUSED)
/* Pad with nops for objdump. */
n_nops = (32 - ((insn_size) % 32)) / 8;
for (i = 1; i <= n_nops; i++)
- md_assemble ("nop");
+ md_assemble ((char *) "nop");
}
}
if (s[0] == '[' && s[1] == '[')
indirection[operand] = relative;
}
-
+
if (indirection[1] == none && indirection[2] == none)
return FALSE;
-
+
operand = 1;
ns_len = strlen (str);
- new_str = (char*) xmalloc (ns_len);
+ new_str = XNEWVEC (char, ns_len);
ns = new_str;
ns_end = ns + ns_len;
-
+
for (s = str; *s; s++)
{
if (s[0] == ',')
operand = 2;
-
+
if (s[0] == '[' && ! brace_n[operand])
{
brace_n[operand] += 1;
if (indirection[operand] != none)
continue;
}
-
+
else if (s[0] == '[' && brace_n[operand])
{
brace_n[operand] += 1;
{
fprintf (stderr, "Unmatched [[operand-%d]] %d\n", operand, brace_n[operand]);
}
-
+
if (indirection[1] != none && indirection[2] != none)
- md_assemble ("src-dest-indirect");
+ md_assemble ((char *) "src-dest-indirect");
else if (indirection[1] != none)
- md_assemble ("src-indirect");
+ md_assemble ((char *) "src-indirect");
else if (indirection[2] != none)
- md_assemble ("dest-indirect");
+ md_assemble ((char *) "dest-indirect");
md_assemble (new_str);
free (new_str);
insn.insn = m32c_cgen_assemble_insn
(gas_cgen_cpu_desc, str, & insn.fields, insn.buffer, & errmsg);
-
+
if (!insn.insn)
{
as_bad ("%s", errmsg);
last_insn_had_delay_slot
= CGEN_INSN_ATTR_VALUE (insn.insn, CGEN_INSN_DELAY_SLOT);
+ (void) last_insn_had_delay_slot;
insn_size = CGEN_INSN_BITSIZE(insn.insn);
rl_type = rl_for (insn);
/* The syntax in the manual says constants begin with '#'.
We just ignore it. */
-void
+void
md_operand (expressionS * exp)
{
/* In case of a syntax error, escape back to try next syntax combo. */
md_section_align (segT segment, valueT size)
{
int align = bfd_get_section_alignment (stdoutput, segment);
- return ((size + (1 << align) - 1) & (-1 << align));
+ return ((size + (1 << align) - 1) & -(1 << align));
}
symbolS *
/* 19 */ { 32767, -32768, 3, 20 }, /* jsr16.w */
/* 20 */ { 0, 0, 4, 0 }, /* jsr16.a */
/* 21 */ { 32767, -32768, 3, 11 }, /* jsr32.w */
- /* 22 */ { 0, 0, 4, 0 } /* jsr32.a */
+ /* 22 */ { 0, 0, 4, 0 }, /* jsr32.a */
+
+ /* 23 */ { 0, 0, 3, 0 }, /* adjnz pc8 */
+ /* 24 */ { 0, 0, 4, 0 }, /* adjnz disp8 pc8 */
+ /* 25 */ { 0, 0, 5, 0 }, /* adjnz disp16 pc8 */
+ /* 26 */ { 0, 0, 6, 0 } /* adjnz disp24 pc8 */
};
enum {
M32C_MACRO_JCND16_A,
M32C_MACRO_JCND32_W,
M32C_MACRO_JCND32_A,
-} M32C_Macros;
+ /* the digit is the array index of the pcrel byte */
+ M32C_MACRO_ADJNZ_2,
+ M32C_MACRO_ADJNZ_3,
+ M32C_MACRO_ADJNZ_4,
+ M32C_MACRO_ADJNZ_5,
+};
static struct {
int insn;
/* 19 */ { M32C_INSN_JSR16_W, 3, M32C_INSN_JSR16_A, 2 },
/* 20 */ { M32C_INSN_JSR16_A, 4, M32C_INSN_JSR16_A, 0 },
/* 21 */ { M32C_INSN_JSR32_W, 3, M32C_INSN_JSR32_A, 2 },
- /* 22 */ { M32C_INSN_JSR32_A, 4, M32C_INSN_JSR32_A, 0 }
+ /* 22 */ { M32C_INSN_JSR32_A, 4, M32C_INSN_JSR32_A, 0 },
+
+ /* 23 */ { -M32C_MACRO_ADJNZ_2, 3, -M32C_MACRO_ADJNZ_2, 0 },
+ /* 24 */ { -M32C_MACRO_ADJNZ_3, 4, -M32C_MACRO_ADJNZ_3, 0 },
+ /* 25 */ { -M32C_MACRO_ADJNZ_4, 5, -M32C_MACRO_ADJNZ_4, 0 },
+ /* 26 */ { -M32C_MACRO_ADJNZ_5, 6, -M32C_MACRO_ADJNZ_5, 0 }
};
#define NUM_MAPPINGS (sizeof (subtype_mappings) / sizeof (subtype_mappings[0]))
}
static int
-insn_to_subtype (int insn)
+insn_to_subtype (int inum, const CGEN_INSN *insn)
{
unsigned int i;
+
+ if (insn
+ && (strncmp (insn->base->mnemonic, "adjnz", 5) == 0
+ || strncmp (insn->base->mnemonic, "sbjnz", 5) == 0))
+ {
+ i = 23 + insn->base->bitsize/8 - 3;
+ /*printf("mapping %d used for %s\n", i, insn->base->mnemonic);*/
+ return i;
+ }
+
for (i=0; i<NUM_MAPPINGS; i++)
- if (insn == subtype_mappings[i].insn)
+ if (inum == subtype_mappings[i].insn)
{
/*printf("mapping %d used\n", i);*/
return i;
int where = fragP->fr_opcode - fragP->fr_literal;
if (fragP->fr_subtype == 1)
- fragP->fr_subtype = insn_to_subtype (fragP->fr_cgen.insn->base->num);
+ fragP->fr_subtype = insn_to_subtype (fragP->fr_cgen.insn->base->num, fragP->fr_cgen.insn);
if (S_GET_SEGMENT (fragP->fr_symbol) != segment)
{
int new_insn;
new_insn = subtype_mappings[fragP->fr_subtype].insn_for_extern;
- fragP->fr_subtype = insn_to_subtype (new_insn);
+ fragP->fr_subtype = insn_to_subtype (new_insn, 0);
}
if (fragP->fr_cgen.insn->base
}
return subtype_mappings[fragP->fr_subtype].bytes - (fragP->fr_fix - where);
-}
+}
/* *fragP has been relaxed to its final size, and now needs to have
the bytes inside it modified to conform to the new size.
{
int addend;
int operand;
- int new_insn;
int where = fragP->fr_opcode - fragP->fr_literal;
int rl_where = fragP->fr_opcode - fragP->fr_literal;
unsigned char *op = (unsigned char *)fragP->fr_opcode;
- int op_base = 0;
- int op_op = 0;
int rl_addend = 0;
addend = target_address_for (fragP) - (fragP->fr_address + where);
- new_insn = subtype_mappings[fragP->fr_subtype].insn;
fragP->fr_fix = where + subtype_mappings[fragP->fr_subtype].bytes;
- op_base = 0;
-
switch (subtype_mappings[fragP->fr_subtype].insn)
{
case M32C_INSN_JCND16_5:
op[1] = addend - 1;
operand = M32C_OPERAND_LAB_8_8;
- op_op = 1;
rl_addend = 0x21;
break;
op[4] = (addend - 3) >> 8;
operand = M32C_OPERAND_LAB_8_16;
where += 2;
- new_insn = M32C_INSN_JMP16_W;
- op_base = 2;
- op_op = 3;
rl_addend = 0x51;
break;
op[2] = 0xfc;
operand = M32C_OPERAND_LAB_8_24;
where += 2;
- new_insn = M32C_INSN_JMP16_A;
- op_base = 2;
- op_op = 3;
rl_addend = 0x61;
break;
case M32C_INSN_JCND16:
op[2] = addend - 2;
operand = M32C_OPERAND_LAB_16_8;
- op_base = 0;
- op_op = 2;
rl_addend = 0x31;
break;
op[5] = (addend - 4) >> 8;
operand = M32C_OPERAND_LAB_8_16;
where += 3;
- new_insn = M32C_INSN_JMP16_W;
- op_base = 3;
- op_op = 4;
rl_addend = 0x61;
break;
op[3] = 0xfc;
operand = M32C_OPERAND_LAB_8_24;
where += 3;
- new_insn = M32C_INSN_JMP16_A;
- op_base = 3;
- op_op = 4;
rl_addend = 0x71;
break;
case M32C_INSN_JMP16_S:
op[0] = 0x60 | ((addend-2) & 0x07);
operand = M32C_OPERAND_LAB_5_3;
- op_base = 0;
- op_op = 0;
rl_addend = 0x10;
break;
op[0] = 0xfe;
op[1] = addend - 1;
operand = M32C_OPERAND_LAB_8_8;
- op_base = 0;
- op_op = 1;
rl_addend = 0x21;
break;
op[1] = addend - 1;
op[2] = (addend - 1) >> 8;
operand = M32C_OPERAND_LAB_8_16;
- op_base = 0;
- op_op = 1;
rl_addend = 0x31;
break;
op[2] = 0;
op[3] = 0;
operand = M32C_OPERAND_LAB_8_24;
- op_base = 0;
- op_op = 1;
rl_addend = 0x41;
break;
case M32C_INSN_JCND32:
op[1] = addend - 1;
operand = M32C_OPERAND_LAB_8_8;
- op_base = 0;
- op_op = 1;
rl_addend = 0x21;
break;
op[4] = (addend - 3) >> 8;
operand = M32C_OPERAND_LAB_8_16;
where += 2;
- new_insn = M32C_INSN_JMP32_W;
- op_base = 2;
- op_op = 3;
rl_addend = 0x51;
break;
op[2] = 0xcc;
operand = M32C_OPERAND_LAB_8_24;
where += 2;
- new_insn = M32C_INSN_JMP32_A;
- op_base = 2;
- op_op = 3;
rl_addend = 0x61;
break;
-
-
case M32C_INSN_JMP32_S:
addend = ((addend-2) & 0x07);
op[0] = 0x4a | (addend & 0x01) | ((addend << 3) & 0x30);
operand = M32C_OPERAND_LAB32_JMP_S;
- op_base = 0;
- op_op = 0;
rl_addend = 0x10;
break;
op[0] = 0xbb;
op[1] = addend - 1;
operand = M32C_OPERAND_LAB_8_8;
- op_base = 0;
- op_op = 1;
rl_addend = 0x21;
break;
op[1] = addend - 1;
op[2] = (addend - 1) >> 8;
operand = M32C_OPERAND_LAB_8_16;
- op_base = 0;
- op_op = 1;
rl_addend = 0x31;
break;
op[2] = 0;
op[3] = 0;
operand = M32C_OPERAND_LAB_8_24;
- op_base = 0;
- op_op = 1;
rl_addend = 0x41;
break;
op[1] = addend - 1;
op[2] = (addend - 1) >> 8;
operand = M32C_OPERAND_LAB_8_16;
- op_base = 0;
- op_op = 1;
rl_addend = 0x31;
break;
op[2] = 0;
op[3] = 0;
operand = M32C_OPERAND_LAB_8_24;
- op_base = 0;
- op_op = 1;
rl_addend = 0x41;
break;
op[1] = addend - 1;
op[2] = (addend - 1) >> 8;
operand = M32C_OPERAND_LAB_8_16;
- op_base = 0;
- op_op = 1;
rl_addend = 0x31;
break;
op[2] = 0;
op[3] = 0;
operand = M32C_OPERAND_LAB_8_24;
- op_base = 0;
- op_op = 1;
rl_addend = 0x41;
break;
-
+ case -M32C_MACRO_ADJNZ_2:
+ rl_addend = 0x31;
+ op[2] = addend - 2;
+ operand = M32C_OPERAND_LAB_16_8;
+ break;
+ case -M32C_MACRO_ADJNZ_3:
+ rl_addend = 0x41;
+ op[3] = addend - 2;
+ operand = M32C_OPERAND_LAB_24_8;
+ break;
+ case -M32C_MACRO_ADJNZ_4:
+ rl_addend = 0x51;
+ op[4] = addend - 2;
+ operand = M32C_OPERAND_LAB_32_8;
+ break;
+ case -M32C_MACRO_ADJNZ_5:
+ rl_addend = 0x61;
+ op[5] = addend - 2;
+ operand = M32C_OPERAND_LAB_40_8;
+ break;
default:
printf("\nHey! Need more opcode converters! missing: %d %s\n\n",
|| (m32c_relax && (operand != M32C_OPERAND_LAB_5_3
&& operand != M32C_OPERAND_LAB32_JMP_S)))
{
- assert (fragP->fr_cgen.insn != 0);
+ gas_assert (fragP->fr_cgen.insn != 0);
gas_cgen_record_fixup (fragP,
where,
fragP->fr_cgen.insn,
cgen_operand_lookup_by_num (gas_cgen_cpu_desc,
operand),
fragP->fr_cgen.opinfo,
- fragP->fr_symbol, fragP->fr_offset);
+ fragP->fr_symbol,
+ fragP->fr_offset);
}
}
\f
return BFD_RELOC_NONE;
}
+void
+m32c_cons_fix_new (fragS * frag,
+ int where,
+ int size,
+ expressionS *exp,
+ bfd_reloc_code_real_type type)
+{
+ switch (size)
+ {
+ case 1:
+ type = BFD_RELOC_8;
+ break;
+ case 2:
+ type = BFD_RELOC_16;
+ break;
+ case 3:
+ type = BFD_RELOC_24;
+ break;
+ case 4:
+ default:
+ type = BFD_RELOC_32;
+ break;
+ case 8:
+ type = BFD_RELOC_64;
+ break;
+ }
+
+ fix_new_exp (frag, where, (int) size, exp, 0, type);
+}
+
void
m32c_apply_fix (struct fix *f, valueT *t, segT s)
{
|| fx->fx_r_type == BFD_RELOC_M32C_RL_2ADDR)
{
arelent * reloc;
-
- reloc = xmalloc (sizeof (* reloc));
-
- reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
+
+ reloc = XNEW (arelent);
+
+ reloc->sym_ptr_ptr = XNEW (asymbol *);
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fx->fx_addsy);
reloc->address = fx->fx_frag->fr_address + fx->fx_where;
reloc->howto = bfd_reloc_type_lookup (stdoutput, fx->fx_r_type);
/* Equal to MAX_PRECISION in atof-ieee.c. */
#define MAX_LITTLENUMS 6
-char *
+const char *
md_atof (int type, char * litP, int * sizeP)
{
- int i;
- int prec;
- LITTLENUM_TYPE words [MAX_LITTLENUMS];
- char * t;
-
- switch (type)
- {
- case 'f':
- case 'F':
- case 's':
- case 'S':
- prec = 2;
- break;
-
- case 'd':
- case 'D':
- case 'r':
- case 'R':
- prec = 4;
- break;
-
- /* FIXME: Some targets allow other format chars for bigger sizes here. */
-
- 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 * sizeof (LITTLENUM_TYPE);
-
- for (i = 0; i < prec; i++)
- {
- md_number_to_chars (litP, (valueT) words[i],
- sizeof (LITTLENUM_TYPE));
- litP += sizeof (LITTLENUM_TYPE);
- }
-
- return 0;
+ return ieee_md_atof (type, litP, sizeP, TRUE);
}
bfd_boolean
}
/* Worker function for m32c_is_colon_insn(). */
-static char restore_colon PARAMS ((int));
-
-static char
-restore_colon (int advance_i_l_p_by)
+static int
+restore_colon (char *next_i_l_p, char *nul_char)
{
- char c;
-
/* Restore the colon, and advance input_line_pointer to
the end of the new symbol. */
- * input_line_pointer = ':';
- input_line_pointer += advance_i_l_p_by;
- c = * input_line_pointer;
- * input_line_pointer = 0;
-
- return c;
+ *input_line_pointer = *nul_char;
+ input_line_pointer = next_i_l_p;
+ *nul_char = *next_i_l_p;
+ *next_i_l_p = 0;
+ return 1;
}
/* Determines if the symbol starting at START and ending in
(but which has now been replaced bu a NUL) is in fact an
:Z, :S, :Q, or :G suffix.
If it is, then it restores the colon, advances INPUT_LINE_POINTER
- to the real end of the instruction/symbol, and returns the character
- that really terminated the symbol. Otherwise it returns 0. */
-char
-m32c_is_colon_insn (char *start ATTRIBUTE_UNUSED)
+ to the real end of the instruction/symbol, saves the char there to
+ NUL_CHAR and pokes a NUL, and returns 1. Otherwise it returns 0. */
+int
+m32c_is_colon_insn (char *start ATTRIBUTE_UNUSED, char *nul_char)
{
char * i_l_p = input_line_pointer;
+ if (*nul_char == '"')
+ ++i_l_p;
+
/* Check to see if the text following the colon is 'G' */
if (TOLOWER (i_l_p[1]) == 'g' && (i_l_p[2] == ' ' || i_l_p[2] == '\t'))
- return restore_colon (2);
+ return restore_colon (i_l_p + 2, nul_char);
/* Check to see if the text following the colon is 'Q' */
if (TOLOWER (i_l_p[1]) == 'q' && (i_l_p[2] == ' ' || i_l_p[2] == '\t'))
- return restore_colon (2);
+ return restore_colon (i_l_p + 2, nul_char);
/* Check to see if the text following the colon is 'S' */
if (TOLOWER (i_l_p[1]) == 's' && (i_l_p[2] == ' ' || i_l_p[2] == '\t'))
- return restore_colon (2);
+ return restore_colon (i_l_p + 2, nul_char);
/* Check to see if the text following the colon is 'Z' */
if (TOLOWER (i_l_p[1]) == 'z' && (i_l_p[2] == ' ' || i_l_p[2] == '\t'))
- return restore_colon (2);
+ return restore_colon (i_l_p + 2, nul_char);
return 0;
}