Add support for more ARM processor names.

This commit is contained in:
Nick Clifton
1997-12-12 18:42:40 +00:00
parent 0483568a24
commit f520aaee13
2 changed files with 345 additions and 138 deletions

View File

@ -1,3 +1,11 @@
Fri Dec 12 10:35:01 1997 Nick Clifton <nickc@cygnus.com>
* doc/c-arm.texi (ARM Options): Document support for new ARM
processor names.
* config/tc-arm.c (md_parse_option): Add support for new ARM
processor names.
Thu Dec 11 17:46:50 1997 Richard Henderson <rth@cygnus.com>
* config/tc-m68k.c (m68k_ip): Don't overwrite opcode table data.

View File

@ -51,8 +51,10 @@
/* The following bitmasks control CPU extensions (ARM7 onwards): */
#define ARM_LONGMUL 0x00000010 /* allow long multiplies */
#define ARM_ARCH4 0x00000020
#define ARM_THUMB ARM_ARCH4
#define ARM_HALFWORD 0x00000020 /* allow half word loads */
#define ARM_THUMB 0x00000040 /* allow BX instruction */
#define ARM_ARCHv4 (ARM_7 | ARM_LONGMUL | ARM_HALFWORD)
/* Some useful combinations: */
#define ARM_ANY 0x00ffffff
@ -73,7 +75,7 @@
#ifndef CPU_DEFAULT
#if defined __thumb__
#define CPU_DEFAULT (ARM_7 | ARM_THUMB)
#define CPU_DEFAULT (ARM_ARCHv4 | ARM_THUMB)
#else
#define CPU_DEFAULT ARM_ALL
#endif
@ -88,6 +90,9 @@ static unsigned long cpu_variant = CPU_DEFAULT | FPU_DEFAULT;
#ifdef OBJ_COFF
/* Flags stored in private area of BFD COFF structure */
static boolean uses_apcs_26 = false;
static boolean support_interwork = false;
static boolean uses_apcs_float = false;
static boolean pic_code = false;
#endif
/* This array holds the chars that always start a comment. If the
@ -419,7 +424,7 @@ static int arm_psr_parse PARAMS ((char **ccp));
static void symbol_locate PARAMS ((symbolS *, CONST char *, segT,
valueT, fragS *));
static int add_to_lit_pool PARAMS ((void));
static int validate_immediate PARAMS ((int));
static unsigned validate_immediate PARAMS ((unsigned));
static int validate_offset_imm PARAMS ((int, int));
static void opcode_select PARAMS ((int));
static void end_of_line PARAMS ((char *));
@ -856,6 +861,8 @@ static void s_ltorg PARAMS ((int));
static void s_arm PARAMS ((int));
static void s_thumb PARAMS ((int));
static void s_code PARAMS ((int));
static void s_force_thumb PARAMS ((int));
static void s_thumb_func PARAMS ((int));
static int my_get_expression PARAMS ((expressionS *, char **));
@ -867,6 +874,8 @@ CONST pseudo_typeS md_pseudo_table[] =
{"arm", s_arm, 0},
{"thumb", s_thumb, 0},
{"code", s_code, 0},
{"force_thumb", s_force_thumb, 0},
{"thumb_func", s_thumb_func, 0},
{"even", s_even, 0},
{"ltorg", s_ltorg, 0},
{"pool", s_ltorg, 0},
@ -887,7 +896,8 @@ CONST pseudo_typeS md_pseudo_table[] =
<insn>
*/
symbolS *last_label_seen;
symbolS * last_label_seen;
static int label_is_thumb_function_name = false;
/* Literal stuff */
@ -928,7 +938,7 @@ add_to_lit_pool ()
{
if (next_literal_pool_place > MAX_LITERAL_POOL_SIZE)
{
inst.error = "Literal Pool Overflow\n";
inst.error = "Literal Pool Overflow";
return FAIL;
}
@ -1016,35 +1026,21 @@ symbol_make_empty ()
return symbolP;
}
/* Check that an immediate is valid, and if so, convert it to the right format
*/
/* Check that an immediate is valid, and if so, convert it to the right format. */
/* OH, for a rotate instruction in C! */
static int
static unsigned int
validate_immediate (val)
int val;
unsigned int val;
{
unsigned int a = (unsigned int) val;
int i;
/* Do the easy (and most common ones) quickly */
for (i = 0; i <= 24; i += 2)
{
if ((a & (0xff << i)) == a)
return (int) (((32 - i) & 0x1e) << 7) | ((a >> i) & 0xff);
}
unsigned int a;
unsigned int i;
/* Now do the harder ones */
for (; i < 32; i += 2)
{
if ((a & ((0xff << i) | (0xff >> (32 - i)))) == a)
{
a = ((a >> i) & 0xff) | ((a << (32 - i)) & 0xff);
return (int) a | (((32 - i) >> 1) << 8);
}
}
return FAIL;
#define rotate_left(v, n) (v << n | v >> (32 - n))
for (i = 0; i < 32; i += 2)
if ((a = rotate_left (val, i)) <= 0xff)
return a | (i << 7); /* 12-bit pack: [shift-cnt,const] */
return FAIL;
}
static int
@ -1117,6 +1113,9 @@ s_ltorg (internal)
(valueT) frag_now_fix (), frag_now);
symbol_table_insert (current_poolP);
ARM_SET_THUMB (current_poolP, thumb_mode);
ARM_SET_INTERWORK (current_poolP, support_interwork);
while (lit_count < next_literal_pool_place)
/* First output the expression in the instruction to the pool */
emit_expr (&(literals[lit_count++].exp), 4); /* .word */
@ -1175,6 +1174,38 @@ s_align (unused) /* Same as s_align_ptwo but align 0 => align 2 */
record_alignment (now_seg, temp);
}
static void
s_force_thumb (ignore)
int ignore;
{
/* If we are not already in thumb mode go into it, EVEN if
the target processor does not support thumb instructions.
This is used by gcc/config/arm/lib1funcs.asm for example
to compile interworking support functions even if the
target processor should not support interworking. */
if (! thumb_mode)
{
thumb_mode = 1;
record_alignment (now_seg, 1);
}
demand_empty_rest_of_line ();
}
static void
s_thumb_func (ignore)
int ignore;
{
/* The following label is the name/address of the start of a Thumb function.
We need to know this for the interworking support. */
label_is_thumb_function_name = true;
demand_empty_rest_of_line();
}
static void
opcode_select (width)
int width;
@ -1702,7 +1733,7 @@ do_msr (str, flags)
}
else
{
int value = validate_immediate (inst.reloc.exp.X_add_number);
unsigned value = validate_immediate (inst.reloc.exp.X_add_number);
if (value == FAIL)
{
inst.error = "Invalid constant";
@ -2579,10 +2610,10 @@ do_ldst (str, flags)
{
/* This is actually a load/store of a halfword, or a
signed-extension load */
if ((cpu_variant & ARM_ARCH4) == 0)
if ((cpu_variant & ARM_HALFWORD) == 0)
{
inst.error
= "Processor does not support halfwords or signed bytes\n";
= "Processor does not support halfwords or signed bytes";
return;
}
@ -2730,7 +2761,7 @@ do_ldst (str, flags)
if (add_to_lit_pool () == FAIL)
{
if (!inst.error)
inst.error = "literal pool insertion failed\n";
inst.error = "literal pool insertion failed";
return;
}
@ -3998,8 +4029,8 @@ thumb_mov_compare (str, move)
if (Rs < 8 && Rd < 8)
{
if (move == THUMB_MOVE)
/* A move of two lowregs is, by convention, encoded as
ADD Rd, Rs, #0 */
/* A move of two lowregs is encoded as ADD Rd, Rs, #0
since a MOV instruction produces unpredictable results */
inst.instruction = T_OPCODE_ADD_I3;
else
inst.instruction = T_OPCODE_CMP_LR;
@ -4106,8 +4137,48 @@ thumb_load_store (str, load_store, size)
}
else if (*str == '=')
{
/* TODO: We should allow the "ldr Rd,=expr" pseudo op in thumb mode */
abort ();
/* Parse an "ldr Rd, =expr" instruction; this is another pseudo op */
str++;
while (*str == ' ')
str++;
if (my_get_expression (& inst.reloc.exp, & str))
return;
end_of_line (str);
if ( inst.reloc.exp.X_op != O_constant
&& inst.reloc.exp.X_op != O_symbol)
{
inst.error = "Constant expression expected";
return;
}
if (inst.reloc.exp.X_op == O_constant
&& ((inst.reloc.exp.X_add_number & ~0xFF) == 0))
{
/* This can be done with a mov instruction */
inst.instruction = T_OPCODE_MOV_I8 | (Rd << 8);
inst.instruction |= inst.reloc.exp.X_add_number;
return;
}
/* Insert into literal pool */
if (add_to_lit_pool () == FAIL)
{
if (!inst.error)
inst.error = "literal pool insertion failed";
return;
}
inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
inst.reloc.pc_rel = 1;
inst.instruction = T_OPCODE_LDR_PC | (Rd << 8);
inst.reloc.exp.X_add_number += 4; /* Adjust ARM pipeline offset to Thumb */
return;
}
else
{
@ -4566,7 +4637,7 @@ do_t_adr (str)
while (*str == ' ')
str++;
if (reg_required_here (&str, 4) == FAIL
if (reg_required_here (&str, 4) == FAIL /* Store Rd in temporary location inside instruction. */
|| skip_past_comma (&str) == FAIL
|| my_get_expression (&inst.reloc.exp, &str))
{
@ -4636,7 +4707,7 @@ void
md_begin ()
{
int i;
if ((arm_ops_hsh = hash_new ()) == NULL
|| (arm_tops_hsh = hash_new ()) == NULL
|| (arm_cond_hsh = hash_new ()) == NULL
@ -4662,8 +4733,17 @@ md_begin ()
set_constant_flonums ();
#ifdef OBJ_COFF
/* Set the flags in the private structure */
bfd_set_private_flags (stdoutput, uses_apcs_26 ? F_APCS26 : 0);
{
unsigned int flags = 0;
/* Set the flags in the private structure */
if (uses_apcs_26) flags |= F_APCS26;
if (support_interwork) flags |= F_INTERWORK;
if (uses_apcs_float) flags |= F_APCS_FLOAT;
if (pic_code) flags |= F_PIC;
bfd_set_private_flags (stdoutput, flags);
}
#endif
{
@ -4695,7 +4775,7 @@ md_begin ()
{
if (cpu_variant & ARM_THUMB)
mach = bfd_mach_arm_4T;
else if (cpu_variant & ARM_ARCH4)
else if ((cpu_variant & ARM_ARCHv4) == ARM_ARCHv4)
mach = bfd_mach_arm_4;
else if (cpu_variant & ARM_LONGMUL)
mach = bfd_mach_arm_3M;
@ -4846,6 +4926,14 @@ md_pcrel_from (fixP)
&& fixP->fx_subsy == NULL)
return 0; /* HACK */
if (fixP->fx_pcrel && (fixP->fx_r_type == BFD_RELOC_ARM_THUMB_ADD))
{
/* PC relative addressing on the Thumb is slightly odd
as the bottom two bits of the PC are forced to zero
for the calculation */
return (fixP->fx_where + fixP->fx_frag->fr_address) & ~3;
}
return fixP->fx_where + fixP->fx_frag->fr_address;
}
@ -4969,7 +5057,12 @@ md_apply_fix3 (fixP, val, seg)
{
if (S_IS_DEFINED (fixP->fx_addsy)
&& S_GET_SEGMENT (fixP->fx_addsy) != seg)
value += md_pcrel_from (fixP);
{
if (fixP->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH)
value = 0;
else
value += md_pcrel_from (fixP);
}
}
fixP->fx_addnumber = value; /* Remember value for emit_reloc */
@ -5244,7 +5337,9 @@ md_apply_fix3 (fixP, val, seg)
break;
default:
abort ();
as_bad_where (fixP->fx_file, fixP->fx_line,
"Unable to process relocation for thumb opcode: %x", newval);
break;
}
md_number_to_chars (buf, newval, THUMB_SIZE);
break;
@ -5404,60 +5499,40 @@ tc_gen_reloc (section, fixp)
"Literal referenced across section boundry (Implicit dump?)");
return NULL;
case BFD_RELOC_ARM_IMMEDIATE:
as_bad_where (fixp->fx_file, fixp->fx_line,
"Internal_relocation (type %d) not fixed up (IMMEDIATE)",
fixp->fx_r_type);
return NULL;
case BFD_RELOC_ARM_OFFSET_IMM:
as_bad_where (fixp->fx_file, fixp->fx_line,
"Internal_relocation (type %d) not fixed up (OFFSET_IMM)",
fixp->fx_r_type);
return NULL;
case BFD_RELOC_ARM_OFFSET_IMM8:
as_bad_where (fixp->fx_file, fixp->fx_line,
"Internal_relocation (type %d) not fixed up (OFFSET_IMM8)",
fixp->fx_r_type);
return NULL;
case BFD_RELOC_ARM_SHIFT_IMM:
as_bad_where (fixp->fx_file, fixp->fx_line,
"Internal_relocation (type %d) not fixed up (SHIFT_IMM)",
fixp->fx_r_type);
return NULL;
case BFD_RELOC_ARM_SWI:
as_bad_where (fixp->fx_file, fixp->fx_line,
"Internal_relocation (type %d) not fixed up (SWI)",
fixp->fx_r_type);
return NULL;
case BFD_RELOC_ARM_MULTI:
as_bad_where (fixp->fx_file, fixp->fx_line,
"Internal_relocation (type %d) not fixed up (MULTI)",
fixp->fx_r_type);
return NULL;
case BFD_RELOC_ARM_CP_OFF_IMM:
as_bad_where (fixp->fx_file, fixp->fx_line,
"Internal_relocation (type %d) not fixed up (CP_OFF_IMM)",
fixp->fx_r_type);
return NULL;
case BFD_RELOC_ARM_THUMB_OFFSET:
as_bad_where (fixp->fx_file, fixp->fx_line,
"Internal_relocation (type %d) not fixed up (THUMB_OFFSET)",
fixp->fx_r_type);
return NULL;
default:
abort ();
{
char * type;
switch (fixp->fx_r_type)
{
case BFD_RELOC_ARM_IMMEDIATE: type = "IMMEDIATE"; break;
case BFD_RELOC_ARM_OFFSET_IMM: type = "OFFSET_IMM"; break;
case BFD_RELOC_ARM_OFFSET_IMM8: type = "OFFSET_IMM8"; break;
case BFD_RELOC_ARM_SHIFT_IMM: type = "SHIFT_IMM"; break;
case BFD_RELOC_ARM_SWI: type = "SWI"; break;
case BFD_RELOC_ARM_MULTI: type = "MULTI"; break;
case BFD_RELOC_ARM_CP_OFF_IMM: type = "CP_OFF_IMM"; break;
case BFD_RELOC_ARM_THUMB_ADD: type = "THUMB_ADD"; break;
case BFD_RELOC_ARM_THUMB_SHIFT: type = "THUMB_SHIFT"; break;
case BFD_RELOC_ARM_THUMB_IMM: type = "THUMB_IMM"; break;
case BFD_RELOC_ARM_THUMB_OFFSET: type = "THUMB_OFFSET"; break;
default: type = "<unknown>"; break;
}
as_bad_where (fixp->fx_file, fixp->fx_line,
"Can not represent %s relocation in this object file format (%d)",
type, fixp->fx_pcrel);
return NULL;
}
}
reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
assert (reloc->howto != 0);
if (reloc->howto == NULL)
{
as_bad_where (fixp->fx_file, fixp->fx_line,
"Can not represent %s relocation in this object file format",
bfd_get_reloc_code_name (code));
return NULL;
}
return reloc;
}
@ -5503,7 +5578,7 @@ output_inst (str)
if (inst.error)
{
as_bad ("%s -- statement `%s'\n", inst.error, str);
as_bad (inst.error);
return;
}
@ -5722,40 +5797,56 @@ md_assemble (str)
if (*q && !strncmp (q, ".req ", 4))
{
int reg;
if ((reg = arm_reg_parse (&str)) == FAIL)
{
char *r;
int reg;
char * copy_of_str = str;
char * r;
q += 4;
while (*q == ' ')
q++;
q += 4;
while (*q == ' ')
q++;
for (r = q; *r != '\0'; r++)
if (*r == ' ')
break;
for (r = q; *r != '\0'; r++)
if (*r == ' ')
break;
if (r != q)
{
int regnum;
char d = *r;
if (r != q)
*r = '\0';
regnum = arm_reg_parse (& q);
*r = d;
reg = arm_reg_parse (& str);
if (reg == FAIL)
{
int regnum;
char d = *r;
*r = '\0';
regnum = arm_reg_parse (&q);
*r = d;
if (regnum != FAIL)
{
insert_reg_alias (str, regnum);
*p = c;
return;
}
else
{
as_warn ("register '%s' does not exist\n", q);
}
}
else if (regnum != FAIL)
{
if (reg != regnum)
as_warn ("ignoring redefinition of register alias '%s'", copy_of_str );
/* Do not warn abpout redefinitions to the same alias. */
}
else
as_warn ("ignoring redefinition of register alias '%s' to non-existant register '%s'",
copy_of_str, q);
}
else
{
*p = c;
return;
}
as_warn ("ignoring incomplete .req pseuso op");
*p = c;
return;
}
*p = c;
@ -5783,6 +5874,9 @@ md_assemble (str)
* ARM Procedure Calling Standard:
* -mapcs-32 32 bit APCS
* -mapcs-26 26 bit APCS
* -mapcs-float Pass floats in float regs
* -mapcs-reentrant Position independent code
* -mthumb-interwork Code supports Arm/Thumb interworking
*/
CONST char *md_shortopts = "m:";
@ -5843,6 +5937,13 @@ md_parse_option (c, arg)
cpu_variant = (cpu_variant & ~FPU_ALL) | FPU_NONE;
thumb_mode = 1;
}
else if (! strcmp (str, "thumb-interwork"))
{
cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_THUMB | ARM_ARCHv4;
#ifdef OBJ_COFF
support_interwork = true;
#endif
}
else
goto bad;
break;
@ -5854,16 +5955,60 @@ md_parse_option (c, arg)
return 1;
}
#ifdef OBJ_COFF
if (! strcmp (str, "apcs-32"))
if (! strncmp (str, "apcs-", 5))
{
uses_apcs_26 = false;
return 1;
}
else if (! strcmp (str, "apcs-26"))
{
uses_apcs_26 = true;
return 1;
}
/* GCC passes on all command line options starting "-mapcs-..."
to us, so we must parse them here. */
str += 5;
if (! strcmp (str, "32"))
{
uses_apcs_26 = false;
return 1;
}
else if (! strcmp (str, "26"))
{
uses_apcs_26 = true;
return 1;
}
else if (! strcmp (str, "frame"))
{
/* Stack frames are being generated - does not affect
linkage of code. */
return 1;
}
else if (! strcmp (str, "stack-check"))
{
/* Stack checking is being performed - does not affect
linkage, but does require that the functions
__rt_stkovf_split_small and __rt_stkovf_split_big be
present in the final link. */
return 1;
}
else if (! strcmp (str, "float"))
{
/* Floating point arguments are being passed in the floating
point registers. This does affect linking, since this
version of the APCS is incompatible with the version that
passes floating points in the integer registers. */
uses_apcs_float = true;
return 1;
}
else if (! strcmp (str, "reentrant"))
{
/* Reentrant code has been generated. This does affect
linking, since there is no point in linking reentrant/
position independent code with absolute position code. */
pic_code = true;
return 1;
}
as_bad ("Unrecognised APCS switch -m%s", arg);
return 0;
}
#endif
/* Strip off optional "arm" */
if (! strncmp (str, "arm", 3))
@ -5894,6 +6039,20 @@ md_parse_option (c, arg)
goto bad;
break;
case 's':
if (streq (str, "strongarm") || streq (str, "strongarm110"))
cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7 | ARM_ARCHv4 | ARM_LONGMUL;
else
goto bad;
break;
case '8':
if (streq (str, "8"))
cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7 | ARM_ARCHv4 | ARM_LONGMUL;
else
goto bad;
break;
case '6':
if (! strcmp (str, "6"))
cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_6;
@ -5906,20 +6065,26 @@ md_parse_option (c, arg)
cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7;
for (; *str; str++)
{
switch (*str)
switch (* str)
{
case 't':
cpu_variant |= ARM_THUMB;
cpu_variant |= (ARM_THUMB | ARM_ARCHv4);
break;
case 'm':
cpu_variant |= ARM_LONGMUL;
break;
case 'f': /* fe => fp enabled cpu. */
if (str[1] == 'e')
++ str;
else
goto bad;
case 'c': /* Unknown */
case 'd': /* debug */
case 'i': /* embedded ice */
/* Included for completeness in ARM processor
naming. */
/* Included for completeness in ARM processor naming. */
break;
default:
@ -5953,7 +6118,7 @@ md_parse_option (c, arg)
break;
case '4':
cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_7;
cpu_variant = (cpu_variant & ~ARM_ANY) | ARM_ARCHv4;
switch (*++str)
{
@ -5989,9 +6154,10 @@ md_show_usage (fp)
FILE *fp;
{
fprintf (fp,
"-m[arm][1|2|250|3|6|7[t][d][m][i]] select processor variant\n\
"-m[arm][<processor name>] select processor variant\n\
-m[arm]v[2|2a|3|3m|4|4t] select architecture variant\n\
-mthumb\t\t\tonly allow Thumb instructions\n\
-mthumb-interwork\tmark the assembled code as supporting interworking\n\
-mall\t\t\tallow any instruction\n\
-mfpa10, -mfpa11\tselect floating point architecture\n\
-mfpe-old\t\tdon't allow floating-point multiple instructions\n\
@ -5999,6 +6165,10 @@ md_show_usage (fp)
#ifdef OBJ_COFF
fprintf (fp,
"-mapcs-32, -mapcs-26\tspecify which ARM Procedure Calling Standard is in use\n");
fprintf (fp,
"-mapcs-float\t\tfloating point args are passed in floating point regs\n");
fprintf (fp,
"-mapcs-reentrant\tposition independent/reentrant code has been generated\n");
#endif
#ifdef ARM_BI_ENDIAN
fprintf (fp,
@ -6074,7 +6244,20 @@ arm_frob_label (sym)
symbolS *sym;
{
last_label_seen = sym;
ARM_SET_TYPE(sym,thumb_mode);
ARM_SET_THUMB (sym, thumb_mode);
ARM_SET_INTERWORK (sym, support_interwork);
if (label_is_thumb_function_name)
{
/* When the address of a Thumb function is taken the bottom
bit of that address should be set. This will allow
interworking between Arm and Thumb functions to work
correctly. */
THUMB_SET_FUNC (sym, 1);
label_is_thumb_function_name = false;
}
}
/* Adjust the symbol table. This marks Thumb symbols as distinct from
@ -6088,9 +6271,20 @@ arm_adjust_symtab ()
for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
{
if (ARM_GET_TYPE(sym)) /* Thumb */
if (ARM_IS_THUMB (sym))
{
switch (S_GET_STORAGE_CLASS (sym))
if (THUMB_IS_FUNC (sym))
{
/* Mark the symbol as a Thumb function. */
if ( S_GET_STORAGE_CLASS (sym) == C_STAT
|| S_GET_STORAGE_CLASS (sym) == C_LABEL) /* This can happen! */
S_SET_STORAGE_CLASS (sym, C_THUMBSTATFUNC);
else if (S_GET_STORAGE_CLASS (sym) == C_EXT)
S_SET_STORAGE_CLASS (sym, C_THUMBEXTFUNC);
else
as_bad ("%s: unexpected function type: %d", S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym));
}
else switch (S_GET_STORAGE_CLASS (sym))
{
case C_EXT:
S_SET_STORAGE_CLASS (sym, C_THUMBEXT);
@ -6105,6 +6299,11 @@ arm_adjust_symtab ()
break;
}
}
if (ARM_IS_INTERWORK (sym))
{
coffsymbol(sym->bsym)->native->u.syment.n_flags = 0xFF;
}
}
#endif
}