This is the mail archive of the
binutils@sourceware.cygnus.com
mailing list for the binutils project.
ARM: Support for additional PSR flags
- To: binutils at sourceware dot cygnus dot com
- Subject: ARM: Support for additional PSR flags
- From: Nick Clifton <nickc at cygnus dot com>
- Date: Mon, 15 May 2000 12:25:31 -0700
Hi Guys,
I am about to check in the patch below. It adds support to the ARM
assembler and disassembler for the CPSR_x, CPSR_s, SPSR_x and
SPSR_s flags tot he MSR instruction, and also allows all of these
flags to be specified in upper case (which is what ARMs
documentation uses) as well as lower case (which is what the
assembler used to support).
Cheers
Nick
2000-05-15 Nick Clifton <nickc@cygnus.com>
* arm-opc.h: Use upper case for flasg in MSR and MRS
instructions. Allow any bit to be set in the field_mask of
the MSR instruction.
* arm-dis.c (print_insn_arm): Decode _x and _s bits of the
field_mask of an MSR instruction.
Index: opcodes/arm-opc.h
===================================================================
RCS file: /cvs/src//src/opcodes/arm-opc.h,v
retrieving revision 1.4
diff -p -r1.4 arm-opc.h
*** arm-opc.h 2000/05/12 17:15:21 1.4
--- arm-opc.h 2000/05/15 19:14:24
***************
*** 1,6 ****
/* Opcode table for the ARM.
! Copyright 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
--- 1,6 ----
/* Opcode table for the ARM.
! Copyright 1994, 1995, 1996, 1997, 2000 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
*************** static struct arm_opcode arm_opcodes[] =
*** 93,100 ****
{0x00a00000, 0x0de00000, "adc%c%20's\t%12-15r, %16-19r, %o"},
{0x00c00000, 0x0de00000, "sbc%c%20's\t%12-15r, %16-19r, %o"},
{0x00e00000, 0x0de00000, "rsc%c%20's\t%12-15r, %16-19r, %o"},
! {0x0120f000, 0x0db6f000, "msr%c\t%22?scpsr%C, %o"},
! {0x010f0000, 0x0fbf0fff, "mrs%c\t%12-15r, %22?scpsr"},
{0x01000000, 0x0de00000, "tst%c%p\t%16-19r, %o"},
{0x01200000, 0x0de00000, "teq%c%p\t%16-19r, %o"},
{0x01400000, 0x0de00000, "cmp%c%p\t%16-19r, %o"},
--- 93,100 ----
{0x00a00000, 0x0de00000, "adc%c%20's\t%12-15r, %16-19r, %o"},
{0x00c00000, 0x0de00000, "sbc%c%20's\t%12-15r, %16-19r, %o"},
{0x00e00000, 0x0de00000, "rsc%c%20's\t%12-15r, %16-19r, %o"},
! {0x0120f000, 0x0db0f000, "msr%c\t%22?SCPSR%C, %o"},
! {0x010f0000, 0x0fbf0fff, "mrs%c\t%12-15r, %22?SCPSR"},
{0x01000000, 0x0de00000, "tst%c%p\t%16-19r, %o"},
{0x01200000, 0x0de00000, "teq%c%p\t%16-19r, %o"},
{0x01400000, 0x0de00000, "cmp%c%p\t%16-19r, %o"},
Index: opcodes/arm-dis.c
===================================================================
RCS file: /cvs/src//src/opcodes/arm-dis.c,v
retrieving revision 1.15
diff -p -r1.15 arm-dis.c
*** arm-dis.c 2000/02/14 19:02:47 1.15
--- arm-dis.c 2000/05/15 19:14:24
*************** print_insn_arm (pc, info, given)
*** 420,426 ****
break;
case 'C':
! switch (given & 0x00090000)
{
default:
func (stream, "_???");
--- 420,426 ----
break;
case 'C':
! switch (given & 0x000f0000)
{
default:
func (stream, "_???");
*************** print_insn_arm (pc, info, given)
*** 429,438 ****
func (stream, "_all");
break;
case 0x10000:
! func (stream, "_ctl");
break;
case 0x80000:
! func (stream, "_flg");
break;
}
break;
--- 429,444 ----
func (stream, "_all");
break;
case 0x10000:
! func (stream, "_c");
break;
+ case 0x20000:
+ func (stream, "_x");
+ break;
+ case 0x40000:
+ func (stream, "_s");
+ break;
case 0x80000:
! func (stream, "_f");
break;
}
break;
2000-05-15 Nick Clifton <nickc@cygnus.com>
* config/tc-arm.c (struct asm_psr): Add boolean field
distinguishing between CSPR and SPSR. Rename 'number' field
to 'field'.
(psrs): Rearrange contents to match new asm_psr structure.
(arm_psr_parse): Move next to psr_required_here. Make it
return an asm_psr structure.
(psr_required_here): Use asm_psr structure returned by
arm_psr_parse.
(do_msr): Reorganise to allow psr_required_here to be called
only once.
(md_undefined_name): Mark 'name' parameter as unused, since
the COFF target does not use it.
Index: gas/config/tc-arm.c
===================================================================
RCS file: /cvs/src//src/gas/config/tc-arm.c,v
retrieving revision 1.42
diff -p -r1.42 tc-arm.c
*** tc-arm.c 2000/04/24 23:57:30 1.42
--- tc-arm.c 2000/05/15 19:14:24
*************** static CONST struct asm_flg cplong_flag[
*** 381,419 ****
struct asm_psr
{
CONST char * template;
! unsigned long number;
};
! #define PSR_FIELD_MASK 0x000f0000
! #define PSR_FLAGS 0x00080000
! #define PSR_CONTROL 0x00010000 /* Undocumented instruction, its use is discouraged by ARM */
! #define PSR_ALL 0x00090000
!
! #define CPSR_ALL 0
! #define SPSR_ALL 1
! #define CPSR_FLG 2
! #define SPSR_FLG 3
! #define CPSR_CTL 4
! #define SPSR_CTL 5
static CONST struct asm_psr psrs[] =
{
! /* Valid <psr>'s */
! {"cpsr", CPSR_ALL},
! {"cpsr_all", CPSR_ALL},
! {"spsr", SPSR_ALL},
! {"spsr_all", SPSR_ALL},
!
! /* Valid <psrf>'s */
! {"cpsr_flg", CPSR_FLG},
! {"spsr_flg", SPSR_FLG},
!
! /* Valid <psrc>'s */
! {"cpsr_c", CPSR_CTL},
! {"cpsr_ctl", CPSR_CTL},
! {"spsr_c", SPSR_CTL},
! {"spsr_ctl", SPSR_CTL}
};
/* Functions called by parser. */
--- 381,430 ----
struct asm_psr
{
CONST char * template;
! boolean cpsr;
! unsigned long field;
};
! #define SPSR_BIT (1 << 22) /* The bit that distnguishes CPSR and SPSR. */
! #define PSR_SHIFT 16 /* How many bits to shift the PSR_xxx bits up by. */
! #define PSR_c (1 << 0)
! #define PSR_x (1 << 1)
! #define PSR_s (1 << 2)
! #define PSR_f (1 << 3)
static CONST struct asm_psr psrs[] =
{
! {"CPSR", true, PSR_c | PSR_f},
! {"CPSR_all", true, PSR_c | PSR_f},
! {"SPSR", false, PSR_c | PSR_f},
! {"SPSR_all", false, PSR_c | PSR_f},
! {"CPSR_flg", true, PSR_f},
! {"CPSR_f", true, PSR_f},
! {"SPSR_flg", false, PSR_f},
! {"SPSR_f", false, PSR_f},
! {"CPSR_c", true, PSR_c},
! {"CPSR_ctl", true, PSR_c},
! {"SPSR_c", false, PSR_c},
! {"SPSR_ctl", false, PSR_c},
! {"CPSR_x", true, PSR_x},
! {"CPSR_s", true, PSR_s},
! {"SPSR_x", false, PSR_x},
! {"SPSR_s", false, PSR_s},
! /* For backwards compatability with older toolchain we also
! support lower case versions of some of these flags. */
! {"cpsr", true, PSR_c | PSR_f},
! {"cpsr_all", true, PSR_c | PSR_f},
! {"spsr", false, PSR_c | PSR_f},
! {"spsr_all", false, PSR_c | PSR_f},
! {"cpsr_flg", true, PSR_f},
! {"cpsr_f", true, PSR_f},
! {"spsr_flg", false, PSR_f},
! {"spsr_f", false, PSR_f},
! {"cpsr_c", true, PSR_c},
! {"cpsr_ctl", true, PSR_c},
! {"spsr_c", false, PSR_c},
! {"spsr_ctl", false, PSR_c}
};
/* Functions called by parser. */
*************** static void do_fp_to_reg PARAMS ((char *
*** 458,464 ****
static void fix_new_arm PARAMS ((fragS *, int, short, expressionS *, int, int));
static int arm_reg_parse PARAMS ((char **));
! static int arm_psr_parse PARAMS ((char **));
static void symbol_locate PARAMS ((symbolS *, CONST char *, segT, valueT, fragS *));
static int add_to_lit_pool PARAMS ((void));
static unsigned validate_immediate PARAMS ((unsigned));
--- 469,475 ----
static void fix_new_arm PARAMS ((fragS *, int, short, expressionS *, int, int));
static int arm_reg_parse PARAMS ((char **));
! static CONST struct asm_psr * arm_psr_parse PARAMS ((char **));
static void symbol_locate PARAMS ((symbolS *, CONST char *, segT, valueT, fragS *));
static int add_to_lit_pool PARAMS ((void));
static unsigned validate_immediate PARAMS ((unsigned));
*************** static int validate_offset_imm PARAMS ((
*** 467,473 ****
static void opcode_select PARAMS ((int));
static void end_of_line PARAMS ((char *));
static int reg_required_here PARAMS ((char **, int));
! static int psr_required_here PARAMS ((char **, int, int));
static int co_proc_number PARAMS ((char **));
static int cp_opc_expr PARAMS ((char **, int, int));
static int cp_reg_required_here PARAMS ((char **, int));
--- 478,484 ----
static void opcode_select PARAMS ((int));
static void end_of_line PARAMS ((char *));
static int reg_required_here PARAMS ((char **, int));
! static int psr_required_here PARAMS ((char **));
static int co_proc_number PARAMS ((char **));
static int cp_opc_expr PARAMS ((char **, int, int));
static int cp_reg_required_here PARAMS ((char **, int));
*************** static CONST struct asm_opcode insns[] =
*** 569,576 ****
{"mrs", 0x010f0000, NULL, NULL, ARM_6UP, do_mrs},
{"msr", 0x0120f000, NULL, NULL, ARM_6UP, do_msr},
/* ScottB: our code uses 0x0128f000 for msr.
! NickC: but this is wrong because the bits 16 and 19 are handled
! by the PSR_xxx defines above. */
/* ARM 7M long multiplies - need signed/unsigned flags! */
{"smull", 0x00c00090, NULL, s_flag, ARM_LONGMUL, do_mull},
--- 580,587 ----
{"mrs", 0x010f0000, NULL, NULL, ARM_6UP, do_mrs},
{"msr", 0x0120f000, NULL, NULL, ARM_6UP, do_msr},
/* ScottB: our code uses 0x0128f000 for msr.
! NickC: but this is wrong because the bits 16 through 19 are
! handled by the PSR_xxx defines above. */
/* ARM 7M long multiplies - need signed/unsigned flags! */
{"smull", 0x00c00090, NULL, s_flag, ARM_LONGMUL, do_mull},
*************** reg_required_here (str, shift)
*** 1562,1588 ****
return FAIL;
}
static int
! psr_required_here (str, cpsr, spsr)
char ** str;
- int cpsr;
- int spsr;
{
- int psr;
char * start = *str;
! psr = arm_psr_parse (str);
! if (psr == cpsr || psr == spsr)
{
! if (psr == spsr)
! inst.instruction |= 1 << 22;
return SUCCESS;
}
! /* In the few cases where we might be able to accept something else
! this error can be overridden. */
! inst.error = _("<psr(f)> expected");
/* Restore the start point. */
*str = start;
--- 1573,1637 ----
return FAIL;
}
+ static CONST struct asm_psr *
+ arm_psr_parse (ccp)
+ register char ** ccp;
+ {
+ char * start = * ccp;
+ char c;
+ char * p;
+ CONST struct asm_psr * psr;
+
+ p = start;
+
+ /* Skip to the end of the next word in the input stream. */
+ do
+ {
+ c = *p++;
+ }
+ while (isalpha (c) || c == '_');
+
+ /* Terminate the word. */
+ *--p = 0;
+
+ /* Now locate the word in the psr hash table. */
+ psr = (CONST struct asm_psr *) hash_find (arm_psr_hsh, start);
+
+ /* Restore the input stream. */
+ *p = c;
+
+ /* If we found a valid match, advance the
+ stream pointer past the end of the word. */
+ *ccp = p;
+
+ return psr;
+ }
+
+ /* Parse the input looking for a PSR flag. */
static int
! psr_required_here (str)
char ** str;
{
char * start = *str;
! CONST struct asm_psr * psr;
! psr = arm_psr_parse (str);
!
! if (psr)
{
! /* If this is the SPSR that is being modified, set the R bit. */
! if (! psr->cpsr)
! inst.instruction |= SPSR_BIT;
!
! /* Set the psr flags in the MSR instruction. */
! inst.instruction |= psr->field << PSR_SHIFT;
return SUCCESS;
}
! /* In the few cases where we might be able to accept
! something else this error can be overridden. */
! inst.error = _("flag for {c}psr instruction expected");
/* Restore the start point. */
*str = start;
*************** do_mrs (str, flags)
*** 1874,1977 ****
return;
}
! if (skip_past_comma (&str) == FAIL
! || psr_required_here (& str, CPSR_ALL, SPSR_ALL) == FAIL)
{
! inst.error = _("<psr> expected");
return;
}
inst.instruction |= flags;
end_of_line (str);
- return;
}
! /* Three possible forms: "<psr>, Rm", "<psrf>, Rm", "<psrf>, #expression". */
static void
do_msr (str, flags)
char * str;
unsigned long flags;
{
! int reg;
skip_whitespace (str);
! if (psr_required_here (&str, CPSR_ALL, SPSR_ALL) == SUCCESS)
{
! inst.instruction |= PSR_ALL;
! /* Sytax should be "<psr>, Rm" */
! if (skip_past_comma (&str) == FAIL
! || (reg = reg_required_here (&str, 0)) == FAIL)
! {
! inst.error = BAD_ARGS;
! return;
! }
}
else
{
! if (psr_required_here (& str, CPSR_FLG, SPSR_FLG) == SUCCESS)
! inst.instruction |= PSR_FLAGS;
! else if (psr_required_here (& str, CPSR_CTL, SPSR_CTL) == SUCCESS)
! inst.instruction |= PSR_CONTROL;
! else
! {
! inst.error = BAD_ARGS;
! return;
! }
! if (skip_past_comma (&str) == FAIL)
{
! inst.error = BAD_ARGS;
return;
}
-
- /* Syntax could be "<psrf>, rm", "<psrf>, #expression" */
! if ((reg = reg_required_here (& str, 0)) != FAIL)
! ;
! /* Immediate expression. */
! else if (is_immediate_prefix (* str))
! {
! str ++;
! inst.error = NULL;
!
! if (my_get_expression (& inst.reloc.exp, & str))
! {
! inst.error = _("Register or shift expression expected");
! return;
! }
!
! if (inst.reloc.exp.X_add_symbol)
! {
! inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
! inst.reloc.pc_rel = 0;
! }
! else
! {
! unsigned value = validate_immediate (inst.reloc.exp.X_add_number);
! if (value == (unsigned) FAIL)
! {
! inst.error = _("Invalid constant");
! return;
! }
!
! inst.instruction |= value;
! }
!
! flags |= INST_IMMEDIATE;
! }
! else
! {
! inst.error = _("Error: unrecognised syntax for second argument to msr instruction");
! return;
! }
}
inst.error = NULL;
inst.instruction |= flags;
end_of_line (str);
- return;
}
/* Long Multiply Parser
--- 1923,2032 ----
return;
}
! if (skip_past_comma (&str) == FAIL)
{
! inst.error = _("comma expected after register name");
return;
}
+ skip_whitespace (str);
+
+ if ( strcmp (str, "CPSR") == 0
+ || strcmp (str, "SPSR") == 0
+ /* Lower case versions for backwards compatability. */
+ || strcmp (str, "cpsr") == 0
+ || strcmp (str, "spsr") == 0)
+ str += 4;
+ /* This is for backwards compatability with older toolchains. */
+ else if (strcmp (str, "cpsr_all") == 0
+ || strcmp (str, "spsr_all") == 0)
+ str += 7;
+ else
+ {
+ inst.error = _("{C|S}PSR expected");
+ return;
+ }
+
+ if (* str == 's' || * str == 'S')
+ inst.instruction |= SPSR_BIT;
+
inst.instruction |= flags;
end_of_line (str);
}
! /* Two possible forms:
! "{C|S}PSR_<field>, Rm",
! "{C|S}PSR_f, #expression". */
static void
do_msr (str, flags)
char * str;
unsigned long flags;
{
! skip_whitespace (str);
+ if (psr_required_here (& str) == FAIL)
+ return;
+
+ if (skip_past_comma (& str) == FAIL)
+ {
+ inst.error = _("comma missing after psr flags");
+ return;
+ }
+
skip_whitespace (str);
! if (reg_required_here (& str, 0) != FAIL)
{
! inst.error = NULL;
! inst.instruction |= flags;
! end_of_line (str);
! return;
! }
! if (! is_immediate_prefix (* str))
! {
! inst.error = _("only a register or immediate value can follow a psr flag");
! return;
! }
!
! str ++;
! inst.error = NULL;
!
! if (my_get_expression (& inst.reloc.exp, & str))
! {
! inst.error = _("only a register or immediate value can follow a psr flag");
! return;
! }
!
! if (inst.instruction & ((PSR_c | PSR_x | PSR_s) << PSR_SHIFT))
! {
! inst.error = _("can only set flag field with immediate value");
! return;
}
+
+ flags |= INST_IMMEDIATE;
+
+ if (inst.reloc.exp.X_add_symbol)
+ {
+ inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
+ inst.reloc.pc_rel = 0;
+ }
else
{
! unsigned value = validate_immediate (inst.reloc.exp.X_add_number);
! if (value == (unsigned) FAIL)
{
! inst.error = _("Invalid constant");
return;
}
! inst.instruction |= value;
}
inst.error = NULL;
inst.instruction |= flags;
end_of_line (str);
}
/* Long Multiply Parser
*************** md_section_align (segment, size)
*** 5241,5247 ****
/* ARGSUSED */
symbolS *
md_undefined_symbol (name)
! char * name;
{
#ifdef OBJ_ELF
if (name[0] == '_' && name[1] == 'G'
--- 5296,5302 ----
/* ARGSUSED */
symbolS *
md_undefined_symbol (name)
! char * name ATTRIBUTE_UNUSED;
{
#ifdef OBJ_ELF
if (name[0] == '_' && name[1] == 'G'
*************** arm_reg_parse (ccp)
*** 5306,5338 ****
return FAIL;
}
- static int
- arm_psr_parse (ccp)
- register char ** ccp;
- {
- char * start = * ccp;
- char c;
- char * p;
- CONST struct asm_psr * psr;
-
- p = start;
- c = *p++;
- while (isalpha (c) || c == '_')
- c = *p++;
-
- *--p = 0;
- psr = (CONST struct asm_psr *) hash_find (arm_psr_hsh, start);
- *p = c;
-
- if (psr)
- {
- *ccp = p;
- return psr->number;
- }
-
- return FAIL;
- }
-
int
md_apply_fix3 (fixP, val, seg)
fixS * fixP;
--- 5361,5366 ----
2000-05-15 Nick Clifton <nickc@cygnus.com>
* gas/arm/arch4t.s: Add tests of new fields to msr instruction.
Index: gas/testsuite/gas/arm/arch4t.s
===================================================================
RCS file: /cvs/src//src/gas/testsuite/gas/arm/arch4t.s,v
retrieving revision 1.1.1.1
diff -p -r1.1.1.1 arch4t.s
*** arch4t.s 1999/05/03 07:28:48 1.1.1.1
--- arch4t.s 2000/05/15 19:14:24
*************** foo:
*** 18,21 ****
--- 18,35 ----
strh r2, bar
strneh r3, [r3]
+
+ msr CPSR_f, #2
+ msr CPSR_c, r3
+ msr CPSR_x, r4
+ msr CPSR_s, r5
+ msr CPSR_f, r6
+ msr CPSR_all, r7
+
+ msr SPSR_f, #4
+ msr SPSR_c, r8
+ msr SPSR_x, r9
+ msr SPSR_s, r10
+ msr SPSR_f, r11
+ msr SPSR_all, r12
bar: