This is the mail archive of the binutils@sourceware.cygnus.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

ARM: Support for additional PSR flags


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:

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]