This is the mail archive of the binutils@sourceware.org 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]
Other format: [Raw text]

[PATCH ARM 6/6]: Architectural Extensions - Virtualization Extensions


All,

The attached patch adds support for the Virtualization Extensions to
v7-A under the 'virt' extension.

The main features of this patch are to add support for the HVC and ERET 
instructions, and to also add support for the new special registers
which MRS and MSR accept.  Also note that the 'virt' extension implies
the 'idiv' extension.

Proposed ChangeLogs:

bfd/ChangeLog:
	* bfd-in2.h (BFD_RELOC_ARM_HVC): Add.

gas/ChangeLog:
2010-09-22  Matthew Gretton-Dann  <matthew.gretton-dann@arm.com>

	* config/tc-arm.c (arm_ext_virt): Add.
	(arm_reg_type): Add REG_TYPE_RNB for banked registers.
	(reg_entry): Allow registers to be larger than a byte.
	(reg_alias): Fix type warning.
	(parse_operands): Parse banked registers when appropriate.
	(do_mrs): Add support for Virtualization Extensions.
	(do_hvc): Add.
	(do_t_mrs): Add support for Virtualization Extensions.
	(do_t_msr): Likewise.
	(do_t_hvc): Add.
	(SPLRBANK): Likewise.
	(reg_names): Add banked registers.
	(insns): Add support for Virtualization Extensions.
	(md_apply_fixup): Likewise.
	(arm_cpus): -mcpu=cortex-a15 implies the Virtualization 
	Extensions.
	(arm_extensions): Add 'virt' extension.
	(aeabi_set_public_attributes): Add support for Virtualization
	Extensions.
	doc/c-arm.texi: Document 'virt' extension.

gas/testsuite/ChangeLog:
2010-09-22  Matthew Gretton-Dann  <matthew.gretton-dann@arm.com>

	* gas/arm/armv7-a+virt.d: New test.
	* gas/arm/armv7-a+virt.s: Likewise.
	* gas/arm/attr-march-all.d: Update for Virtualization 
	Extensions.
	* gas/arm/attr-march-armv7-a+sec+virt.d: New test.
	* gas/arm/attr-march-armv7-a+virt.d: Likewise.

include/opcode/ChangeLog:
2010-09-22  Matthew Gretton-Dann  <matthew.gretton-dann@arm.com>

	* arm.h (ARM_EXT_VIRT): Add.
	(ARM_ARCH_V7A_IDIV_MP_SEC): Rename...
	(ARM_ARCH_V7A_IDIV_MP_SEC_VIRT): ...to this and include 
	Virtualization Extensions.

opcodes/ChangeLog:
2010-09-22  Matthew Gretton-Dann  <matthew.gretton-dann@arm.com>

	arm-dis.c (arm_opcodes): Add Virtualiztion Extensions support.
	(thumb32_opcodes): Likewise.
	(banked_regname): Add.
	(print_insn_arm): Add Virtualization Extensions support.
	(print_insn_thumb32): Likewise.

Thanks,

Matt

-- 
Matthew Gretton-Dann
Principal Engineer - PDSW Tools
ARM Ltd
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 0e7b337..4bd47ca 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -3166,6 +3166,7 @@ pc-relative or some form of GOT-indirect relocation.  */
   BFD_RELOC_ARM_T32_ADD_PC12,
   BFD_RELOC_ARM_SHIFT_IMM,
   BFD_RELOC_ARM_SMC,
+  BFD_RELOC_ARM_HVC,
   BFD_RELOC_ARM_SWI,
   BFD_RELOC_ARM_MULTI,
   BFD_RELOC_ARM_CP_OFF_IMM,
diff --git a/gas/config/tc-arm.c b/gas/config/tc-arm.c
index 886d92f..0e0b894 100644
--- a/gas/config/tc-arm.c
+++ b/gas/config/tc-arm.c
@@ -201,6 +201,7 @@ static const arm_feature_set arm_ext_mp = ARM_FEATURE (ARM_EXT_MP, 0);
 static const arm_feature_set arm_ext_sec = ARM_FEATURE (ARM_EXT_SEC, 0);
 static const arm_feature_set arm_ext_os = ARM_FEATURE (ARM_EXT_OS, 0);
 static const arm_feature_set arm_ext_adiv = ARM_FEATURE (ARM_EXT_ADIV, 0);
+static const arm_feature_set arm_ext_virt = ARM_FEATURE (ARM_EXT_VIRT, 0);
 
 static const arm_feature_set arm_arch_any = ARM_ANY;
 static const arm_feature_set arm_arch_full = ARM_FEATURE (-1, -1);
@@ -506,6 +507,7 @@ enum arm_reg_type
   REG_TYPE_MMXWC,
   REG_TYPE_MMXWCG,
   REG_TYPE_XSCALE,
+  REG_TYPE_RNB,
 };
 
 /* Structure for a hash table entry for a register.
@@ -515,7 +517,7 @@ enum arm_reg_type
 struct reg_entry
 {
   const char *               name;
-  unsigned char              number;
+  unsigned int               number;
   unsigned char              type;
   unsigned char              builtin;
   struct neon_typed_alias *  neon;
@@ -2062,7 +2064,7 @@ parse_reloc (char **str)
 /* Directives: register aliases.  */
 
 static struct reg_entry *
-insert_reg_alias (char *str, int number, int type)
+insert_reg_alias (char *str, unsigned number, int type)
 {
   struct reg_entry *new_reg;
   const char *name;
@@ -6380,9 +6382,18 @@ parse_operands (char *str, const unsigned int *pattern, bfd_boolean thumb)
 	  break;
 
         case OP_RVC_PSR:
-          po_reg_or_goto (REG_TYPE_VFC, try_psr);
+          po_reg_or_goto (REG_TYPE_VFC, try_banked_reg);
           inst.operands[i].isvec = 1;  /* Mark VFP control reg as vector.  */
           break;
+	  try_banked_reg:
+	  po_reg_or_goto (REG_TYPE_RNB, try_psr);
+	  if (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_virt))
+	    {
+	      inst.error = _("Banked registers are not available with this "
+			     "architecture.");
+	      goto failure;
+	    }
+	  break;
           try_psr:
           val = parse_psr (&str);
           break;
@@ -7851,16 +7862,30 @@ do_vmsr (void)
 static void
 do_mrs (void)
 {
+  unsigned br;
+
   if (do_vfp_nsyn_mrs () == SUCCESS)
     return;
 
-  /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all.  */
-  constraint ((inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f))
-	      != (PSR_c|PSR_f),
-	      _("'CPSR' or 'SPSR' expected"));
   constraint (inst.operands[0].reg == REG_PC, BAD_PC);
   inst.instruction |= inst.operands[0].reg << 12;
-  inst.instruction |= (inst.operands[1].imm & SPSR_BIT);
+
+  if (inst.operands[1].isreg)
+    {
+      br = inst.operands[1].reg;
+      if (((br & 0x200) == 0) && ((br & 0xf0000) != 0xf000))
+	as_bad (_("bad register for mrs"));
+    }
+  else
+    {
+      /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all.  */
+      constraint ((inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f))
+		  != (PSR_c|PSR_f),
+		  _("'CPSR' or 'SPSR' expected"));
+      br = (15<<16) | (inst.operands[1].imm & SPSR_BIT);
+    }
+
+  inst.instruction |= br;
 }
 
 /* Two possible forms:
@@ -8122,6 +8147,13 @@ do_smc (void)
 }
 
 static void
+do_hvc (void)
+{
+  inst.reloc.type = BFD_RELOC_ARM_HVC;
+  inst.reloc.pc_rel = 0;
+}
+
+static void
 do_swi (void)
 {
   inst.reloc.type = BFD_RELOC_ARM_SWI;
@@ -10734,34 +10766,47 @@ static void
 do_t_mrs (void)
 {
   unsigned Rd;
-  int flags;
 
   if (do_vfp_nsyn_mrs () == SUCCESS)
     return;
 
-  flags = inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f|SPSR_BIT);
-  if (flags == 0)
+  Rd = inst.operands[0].reg;
+  reject_bad_reg (Rd);
+  inst.instruction |= Rd << 8;
+
+  if (inst.operands[1].isreg)
     {
-      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_m),
-		  _("selected processor does not support "
-		    "requested special purpose register"));
+      unsigned br = inst.operands[1].reg;
+      if (((br & 0x200) == 0) && ((br & 0xf000) != 0xf000))
+	as_bad (_("bad register for mrs"));
+
+      inst.instruction |= br & (0xf << 16);
+      inst.instruction |= (br & 0x300) >> 4;
+      inst.instruction |= (br & SPSR_BIT) >> 2;
     }
   else
     {
-      constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1),
-		  _("selected processor does not support "
-		    "requested special purpose register"));
-      /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all.  */
-      constraint ((flags & ~SPSR_BIT) != (PSR_c|PSR_f),
-		  _("'CPSR' or 'SPSR' expected"));
-    }
-
-  Rd = inst.operands[0].reg;
-  reject_bad_reg (Rd);
+      int flags = inst.operands[1].imm & (PSR_c|PSR_x|PSR_s|PSR_f|SPSR_BIT);
+      if (flags == 0)
+	{
+	  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_m),
+		      _("selected processor does not support "
+			"requested special purpose register"));
+	}
+      else
+	{
+	  constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1),
+		      _("selected processor does not support "
+			"requested special purpose register"));
+	  /* mrs only accepts CPSR/SPSR/CPSR_all/SPSR_all.  */
+	  constraint ((flags & ~SPSR_BIT) != (PSR_c|PSR_f),
+		      _("'CPSR' or 'SPSR' expected"));
+	}
 
-  inst.instruction |= Rd << 8;
-  inst.instruction |= (flags & SPSR_BIT) >> 2;
-  inst.instruction |= inst.operands[1].imm & 0xff;
+      inst.instruction |= (flags & SPSR_BIT) >> 2;
+      inst.instruction |= inst.operands[1].imm & 0xff;
+      inst.instruction |= 0xf0000;
+    }
 }
 
 static void
@@ -10775,7 +10820,12 @@ do_t_msr (void)
 
   constraint (!inst.operands[1].isreg,
 	      _("Thumb encoding does not support an immediate here"));
-  flags = inst.operands[0].imm;
+
+  if (inst.operands[0].isreg)
+    flags = (int)(inst.operands[0].reg);
+  else
+    flags = inst.operands[0].imm;
+
   if (flags & ~0xff)
     {
       constraint (!ARM_CPU_HAS_FEATURE (cpu_variant, arm_ext_v1),
@@ -10794,7 +10844,8 @@ do_t_msr (void)
   reject_bad_reg (Rn);
 
   inst.instruction |= (flags & SPSR_BIT) >> 2;
-  inst.instruction |= (flags & ~SPSR_BIT) >> 8;
+  inst.instruction |= (flags & 0xf0000) >> 8;
+  inst.instruction |= (flags & 0x300) >> 4;
   inst.instruction |= (flags & 0xff);
   inst.instruction |= Rn << 16;
 }
@@ -11390,6 +11441,15 @@ do_t_smc (void)
 }
 
 static void
+do_t_hvc (void)
+{
+  unsigned int value = inst.reloc.exp.X_add_number;
+  inst.reloc.type = BFD_RELOC_UNUSED;
+  inst.instruction |= (value & 0x0fff);
+  inst.instruction |= (value & 0xf000) << 4;
+}
+
+static void
 do_t_ssat_usat (int bias)
 {
   unsigned Rd, Rn;
@@ -16185,6 +16245,13 @@ arm_canonicalize_symbol_name (char * name)
   REGNUM2(p, 4,t), REGNUM2(p, 5,t), REGNUM2(p, 6,t), REGNUM2(p, 7,t), \
   REGNUM2(p, 8,t), REGNUM2(p, 9,t), REGNUM2(p,10,t), REGNUM2(p,11,t), \
   REGNUM2(p,12,t), REGNUM2(p,13,t), REGNUM2(p,14,t), REGNUM2(p,15,t)
+#define SPLRBANK(base,bank,t) \
+  REGDEF(lr_##bank, 768|((base+0)<<16), t), \
+  REGDEF(sp_##bank, 768|((base+1)<<16), t), \
+  REGDEF(spsr_##bank, 768|(base<<16)|SPSR_BIT, t), \
+  REGDEF(LR_##bank, 768|((base+0)<<16), t), \
+  REGDEF(SP_##bank, 768|((base+1)<<16), t), \
+  REGDEF(SPSR_##bank, 768|(base<<16)|SPSR_BIT, t)
 
 static const struct reg_entry reg_names[] =
 {
@@ -16215,6 +16282,34 @@ static const struct reg_entry reg_names[] =
   REGSET(c,  CN), REGSET(C, CN),
   REGSET(cr, CN), REGSET(CR, CN),
 
+  /* ARM banked registers.  */
+  REGDEF(R8_usr,512|(0<<16),RNB), REGDEF(r8_usr,512|(0<<16),RNB),
+  REGDEF(R9_usr,512|(1<<16),RNB), REGDEF(r9_usr,512|(1<<16),RNB),
+  REGDEF(R10_usr,512|(2<<16),RNB), REGDEF(r10_usr,512|(2<<16),RNB),
+  REGDEF(R11_usr,512|(3<<16),RNB), REGDEF(r11_usr,512|(3<<16),RNB),
+  REGDEF(R12_usr,512|(4<<16),RNB), REGDEF(r12_usr,512|(4<<16),RNB),
+  REGDEF(SP_usr,512|(5<<16),RNB), REGDEF(sp_usr,512|(5<<16),RNB),
+  REGDEF(LR_usr,512|(6<<16),RNB), REGDEF(lr_usr,512|(6<<16),RNB),
+
+  REGDEF(R8_fiq,512|(8<<16),RNB), REGDEF(r8_fiq,512|(8<<16),RNB),
+  REGDEF(R9_fiq,512|(9<<16),RNB), REGDEF(r9_fiq,512|(9<<16),RNB),
+  REGDEF(R10_fiq,512|(10<<16),RNB), REGDEF(r10_fiq,512|(10<<16),RNB),
+  REGDEF(R11_fiq,512|(11<<16),RNB), REGDEF(r11_fiq,512|(11<<16),RNB),
+  REGDEF(R12_fiq,512|(12<<16),RNB), REGDEF(r12_fiq,512|(12<<16),RNB),
+  REGDEF(SP_fiq,512|(13<<16),RNB), REGDEF(SP_fiq,512|(13<<16),RNB),
+  REGDEF(LR_fiq,512|(14<<16),RNB), REGDEF(lr_fiq,512|(14<<16),RNB),
+  REGDEF(SPSR_fiq,512|(14<<16)|SPSR_BIT,RNB), REGDEF(spsr_fiq,512|(14<<16)|SPSR_BIT,RNB),
+
+  SPLRBANK(0,IRQ,RNB), SPLRBANK(0,irq,RNB),
+  SPLRBANK(2,SVC,RNB), SPLRBANK(2,svc,RNB),
+  SPLRBANK(4,ABT,RNB), SPLRBANK(4,abt,RNB),
+  SPLRBANK(6,UND,RNB), SPLRBANK(6,und,RNB),
+  SPLRBANK(12,MON,RNB), SPLRBANK(12,mon,RNB),
+  REGDEF(elr_hyp,768|(14<<16),RNB), REGDEF(ELR_hyp,768|(14<<16),RNB),
+  REGDEF(sp_hyp,768|(15<<16),RNB), REGDEF(SP_hyp,768|(15<<16),RNB),
+  REGDEF(spsr_hyp,768|(14<<16)|SPSR_BIT,RNB), 
+  REGDEF(SPSR_hyp,768|(14<<16)|SPSR_BIT,RNB),
+
   /* FPA registers.  */
   REGNUM(f,0,FN), REGNUM(f,1,FN), REGNUM(f,2,FN), REGNUM(f,3,FN),
   REGNUM(f,4,FN), REGNUM(f,5,FN), REGNUM(f,6,FN), REGNUM(f,7, FN),
@@ -16800,7 +16895,7 @@ static const struct asm_opcode insns[] =
 #undef  THUMB_VARIANT
 #define THUMB_VARIANT  & arm_ext_msr
 
- TCE("mrs",	10f0000, f3ef8000, 2, (APSR_RR, RVC_PSR), mrs, t_mrs),
+ TCE("mrs",	1000000, f3e08000, 2, (APSR_RR, RVC_PSR), mrs, t_mrs),
  TCE("msr",	120f000, f3808000, 2, (RVC_PSR, RR_EXi), msr, t_msr),
 
 #undef  ARM_VARIANT
@@ -17088,6 +17183,14 @@ static const struct asm_opcode insns[] =
 
  TCE("smc",	1600070, f7f08000, 1, (EXPi), smc, t_smc),
 
+#undef	ARM_VARIANT
+#define	ARM_VARIANT    & arm_ext_virt
+#undef	THUMB_VARIANT
+#define	THUMB_VARIANT    & arm_ext_virt
+
+ TCE("hvc",	1400070, f7e08000, 1, (EXPi), hvc, t_hvc),
+ TCE("eret",	160006e, f3de8f00, 0, (), noargs, noargs),
+
 #undef  ARM_VARIANT
 #define ARM_VARIANT  & arm_ext_v6t2
 #undef  THUMB_VARIANT
@@ -20389,6 +20492,15 @@ md_apply_fix (fixS *	fixP,
       md_number_to_chars (buf, newval, INSN_SIZE);
       break;
 
+    case BFD_RELOC_ARM_HVC:
+      if (((unsigned long) value) > 0xffff)
+	as_bad_where (fixP->fx_file, fixP->fx_line,
+		      _("invalid hvc expression"));
+      newval = md_chars_to_number (buf, INSN_SIZE);
+      newval |= (value & 0xf) | ((value & 0xfff0) << 4);
+      md_number_to_chars (buf, newval, INSN_SIZE);
+      break;
+
     case BFD_RELOC_ARM_SWI:
       if (fixP->tc_fix_data != 0)
 	{
@@ -22430,7 +22542,7 @@ static const struct arm_cpu_option_table arm_cpus[] =
 					 ARM_FEATURE (0, FPU_VFP_V3
                                                         | FPU_NEON_EXT_V1),
                                                           "Cortex-A9"},
-  {"cortex-a15",	ARM_ARCH_V7A_IDIV_MP_SEC,
+  {"cortex-a15",	ARM_ARCH_V7A_IDIV_MP_SEC_VIRT,
 					 FPU_ARCH_NEON_VFP_V4,
                                                           "Cortex-A15"},
   {"cortex-r4",		ARM_ARCH_V7R,	 FPU_NONE,	  "Cortex-R4"},
@@ -22529,6 +22641,8 @@ static const struct arm_option_extension_value_table arm_extensions[] =
     				   ARM_FEATURE (ARM_EXT_V6M, 0)},
   {"sec",	ARM_FEATURE (ARM_EXT_SEC, 0),
     		     ARM_FEATURE (ARM_EXT_V6K | ARM_EXT_V7A, 0)},
+  {"virt",	ARM_FEATURE (ARM_EXT_VIRT | ARM_EXT_ADIV | ARM_EXT_DIV, 0),
+				   ARM_FEATURE (ARM_EXT_V7A, 0)},
   {"xscale",	ARM_FEATURE (0, ARM_CEXT_XSCALE),	ARM_ANY},
   {NULL,	ARM_ARCH_NONE,			  ARM_ARCH_NONE}
 };
@@ -23084,6 +23198,7 @@ static void
 aeabi_set_public_attributes (void)
 {
   int arch;
+  int virt_sec = 0;
   arm_feature_set flags;
   arm_feature_set tmp;
   const cpu_arch_ver_table *p;
@@ -23214,7 +23329,11 @@ aeabi_set_public_attributes (void)
 
   /* Tag Virtualization_use.  */
   if (ARM_CPU_HAS_FEATURE (flags, arm_ext_sec))
-    aeabi_set_attribute_int (Tag_Virtualization_use, 1);
+    virt_sec |= 1;
+  if (ARM_CPU_HAS_FEATURE (flags, arm_ext_virt))
+    virt_sec |= 2;
+  if (virt_sec != 0)
+    aeabi_set_attribute_int (Tag_Virtualization_use, virt_sec);
 }
 
 /* Add the default contents for the .ARM.attributes section.  */
diff --git a/gas/doc/c-arm.texi b/gas/doc/c-arm.texi
index 2a5c351..d3cccf4 100644
--- a/gas/doc/c-arm.texi
+++ b/gas/doc/c-arm.texi
@@ -156,6 +156,8 @@ The following extensions are currently supported:
 @code{mp} (Multiprocessing Extensions for v7-A and v7-R architectures),
 @code{os} (Operating System for v6M architecture),
 @code{sec} (Security Extensions for v6K and v7-A architectures),
+@code{virt} (Virtualization Extensions for v7-A architecture, implies 
+@code{idiv}),
 and
 @code{xscale}.
 
diff --git a/gas/testsuite/gas/arm/armv7-a+virt.d b/gas/testsuite/gas/arm/armv7-a+virt.d
new file mode 100644
index 0000000..1e3224c
--- /dev/null
+++ b/gas/testsuite/gas/arm/armv7-a+virt.d
@@ -0,0 +1,145 @@
+# name: ARMv7-a+virt Instructions
+# as: -march=armv7-a+virt
+# objdump: -dr --prefix-addresses --show-raw-insn
+
+.*: +file format .*arm.*
+
+Disassembly of section .text:
+0[0-9a-f]+ <[^>]+> e1400070 	hvc	0
+0[0-9a-f]+ <[^>]+> e14fff7f 	hvc	65535	; 0xffff
+0[0-9a-f]+ <[^>]+> e160006e 	eret
+0[0-9a-f]+ <[^>]+> e1001200 	mrs	r1, R8_usr
+0[0-9a-f]+ <[^>]+> e1011200 	mrs	r1, R9_usr
+0[0-9a-f]+ <[^>]+> e1021200 	mrs	r1, R10_usr
+0[0-9a-f]+ <[^>]+> e1031200 	mrs	r1, R11_usr
+0[0-9a-f]+ <[^>]+> e1041200 	mrs	r1, R12_usr
+0[0-9a-f]+ <[^>]+> e1051200 	mrs	r1, SP_usr
+0[0-9a-f]+ <[^>]+> e1061200 	mrs	r1, LR_usr
+0[0-9a-f]+ <[^>]+> e1081200 	mrs	r1, R8_fiq
+0[0-9a-f]+ <[^>]+> e1091200 	mrs	r1, R9_fiq
+0[0-9a-f]+ <[^>]+> e10a1200 	mrs	r1, R10_fiq
+0[0-9a-f]+ <[^>]+> e10b1200 	mrs	r1, R11_fiq
+0[0-9a-f]+ <[^>]+> e10c1200 	mrs	r1, R12_fiq
+0[0-9a-f]+ <[^>]+> e10d1200 	mrs	r1, SP_fiq
+0[0-9a-f]+ <[^>]+> e10e1200 	mrs	r1, LR_fiq
+0[0-9a-f]+ <[^>]+> e14e1200 	mrs	r1, SPSR_fiq
+0[0-9a-f]+ <[^>]+> e1011300 	mrs	r1, SP_irq
+0[0-9a-f]+ <[^>]+> e1001300 	mrs	r1, LR_irq
+0[0-9a-f]+ <[^>]+> e1401300 	mrs	r1, SPSR_irq
+0[0-9a-f]+ <[^>]+> e1031300 	mrs	r1, SP_svc
+0[0-9a-f]+ <[^>]+> e1021300 	mrs	r1, LR_svc
+0[0-9a-f]+ <[^>]+> e1421300 	mrs	r1, SPSR_svc
+0[0-9a-f]+ <[^>]+> e1051300 	mrs	r1, SP_abt
+0[0-9a-f]+ <[^>]+> e1041300 	mrs	r1, LR_abt
+0[0-9a-f]+ <[^>]+> e1441300 	mrs	r1, SPSR_abt
+0[0-9a-f]+ <[^>]+> e1071300 	mrs	r1, SP_und
+0[0-9a-f]+ <[^>]+> e1061300 	mrs	r1, LR_und
+0[0-9a-f]+ <[^>]+> e1461300 	mrs	r1, SPSR_und
+0[0-9a-f]+ <[^>]+> e10d1300 	mrs	r1, SP_mon
+0[0-9a-f]+ <[^>]+> e10c1300 	mrs	r1, LR_mon
+0[0-9a-f]+ <[^>]+> e14c1300 	mrs	r1, SPSR_mon
+0[0-9a-f]+ <[^>]+> e10f1300 	mrs	r1, SP_hyp
+0[0-9a-f]+ <[^>]+> e10e1300 	mrs	r1, ELR_hyp
+0[0-9a-f]+ <[^>]+> e14e1300 	mrs	r1, SPSR_hyp
+0[0-9a-f]+ <[^>]+> e120f201 	msr	R8_usr, r1
+0[0-9a-f]+ <[^>]+> e121f201 	msr	R9_usr, r1
+0[0-9a-f]+ <[^>]+> e122f201 	msr	R10_usr, r1
+0[0-9a-f]+ <[^>]+> e123f201 	msr	R11_usr, r1
+0[0-9a-f]+ <[^>]+> e124f201 	msr	R12_usr, r1
+0[0-9a-f]+ <[^>]+> e125f201 	msr	SP_usr, r1
+0[0-9a-f]+ <[^>]+> e126f201 	msr	LR_usr, r1
+0[0-9a-f]+ <[^>]+> e128f201 	msr	R8_fiq, r1
+0[0-9a-f]+ <[^>]+> e129f201 	msr	R9_fiq, r1
+0[0-9a-f]+ <[^>]+> e12af201 	msr	R10_fiq, r1
+0[0-9a-f]+ <[^>]+> e12bf201 	msr	R11_fiq, r1
+0[0-9a-f]+ <[^>]+> e12cf201 	msr	R12_fiq, r1
+0[0-9a-f]+ <[^>]+> e12df201 	msr	SP_fiq, r1
+0[0-9a-f]+ <[^>]+> e12ef201 	msr	LR_fiq, r1
+0[0-9a-f]+ <[^>]+> e16ef201 	msr	SPSR_fiq, r1
+0[0-9a-f]+ <[^>]+> e121f301 	msr	SP_irq, r1
+0[0-9a-f]+ <[^>]+> e120f301 	msr	LR_irq, r1
+0[0-9a-f]+ <[^>]+> e160f301 	msr	SPSR_irq, r1
+0[0-9a-f]+ <[^>]+> e123f301 	msr	SP_svc, r1
+0[0-9a-f]+ <[^>]+> e122f301 	msr	LR_svc, r1
+0[0-9a-f]+ <[^>]+> e162f301 	msr	SPSR_svc, r1
+0[0-9a-f]+ <[^>]+> e125f301 	msr	SP_abt, r1
+0[0-9a-f]+ <[^>]+> e124f301 	msr	LR_abt, r1
+0[0-9a-f]+ <[^>]+> e164f301 	msr	SPSR_abt, r1
+0[0-9a-f]+ <[^>]+> e127f301 	msr	SP_und, r1
+0[0-9a-f]+ <[^>]+> e126f301 	msr	LR_und, r1
+0[0-9a-f]+ <[^>]+> e166f301 	msr	SPSR_und, r1
+0[0-9a-f]+ <[^>]+> e12df301 	msr	SP_mon, r1
+0[0-9a-f]+ <[^>]+> e12cf301 	msr	LR_mon, r1
+0[0-9a-f]+ <[^>]+> e16cf301 	msr	SPSR_mon, r1
+0[0-9a-f]+ <[^>]+> e12ff301 	msr	SP_hyp, r1
+0[0-9a-f]+ <[^>]+> e12ef301 	msr	ELR_hyp, r1
+0[0-9a-f]+ <[^>]+> e16ef301 	msr	SPSR_hyp, r1
+0[0-9a-f]+ <[^>]+> f7e0 8000 	hvc	#0
+0[0-9a-f]+ <[^>]+> f7ef 8fff 	hvc	#65535	; 0xffff
+0[0-9a-f]+ <[^>]+> f3de 8f00 	subs	pc, lr, #0
+0[0-9a-f]+ <[^>]+> f3e0 8120 	mrs	r1, R8_usr
+0[0-9a-f]+ <[^>]+> f3e1 8120 	mrs	r1, R9_usr
+0[0-9a-f]+ <[^>]+> f3e2 8120 	mrs	r1, R10_usr
+0[0-9a-f]+ <[^>]+> f3e3 8120 	mrs	r1, R11_usr
+0[0-9a-f]+ <[^>]+> f3e4 8120 	mrs	r1, R12_usr
+0[0-9a-f]+ <[^>]+> f3e5 8120 	mrs	r1, SP_usr
+0[0-9a-f]+ <[^>]+> f3e6 8120 	mrs	r1, LR_usr
+0[0-9a-f]+ <[^>]+> f3e8 8120 	mrs	r1, R8_fiq
+0[0-9a-f]+ <[^>]+> f3e9 8120 	mrs	r1, R9_fiq
+0[0-9a-f]+ <[^>]+> f3ea 8120 	mrs	r1, R10_fiq
+0[0-9a-f]+ <[^>]+> f3eb 8120 	mrs	r1, R11_fiq
+0[0-9a-f]+ <[^>]+> f3ec 8120 	mrs	r1, R12_fiq
+0[0-9a-f]+ <[^>]+> f3ed 8120 	mrs	r1, SP_fiq
+0[0-9a-f]+ <[^>]+> f3ee 8120 	mrs	r1, LR_fiq
+0[0-9a-f]+ <[^>]+> f3fe 8120 	mrs	r1, SPSR_fiq
+0[0-9a-f]+ <[^>]+> f3e1 8130 	mrs	r1, SP_irq
+0[0-9a-f]+ <[^>]+> f3e0 8130 	mrs	r1, LR_irq
+0[0-9a-f]+ <[^>]+> f3f0 8130 	mrs	r1, SPSR_irq
+0[0-9a-f]+ <[^>]+> f3e3 8130 	mrs	r1, SP_svc
+0[0-9a-f]+ <[^>]+> f3e2 8130 	mrs	r1, LR_svc
+0[0-9a-f]+ <[^>]+> f3f2 8130 	mrs	r1, SPSR_svc
+0[0-9a-f]+ <[^>]+> f3e5 8130 	mrs	r1, SP_abt
+0[0-9a-f]+ <[^>]+> f3e4 8130 	mrs	r1, LR_abt
+0[0-9a-f]+ <[^>]+> f3f4 8130 	mrs	r1, SPSR_abt
+0[0-9a-f]+ <[^>]+> f3e7 8130 	mrs	r1, SP_und
+0[0-9a-f]+ <[^>]+> f3e6 8130 	mrs	r1, LR_und
+0[0-9a-f]+ <[^>]+> f3f6 8130 	mrs	r1, SPSR_und
+0[0-9a-f]+ <[^>]+> f3ed 8130 	mrs	r1, SP_mon
+0[0-9a-f]+ <[^>]+> f3ec 8130 	mrs	r1, LR_mon
+0[0-9a-f]+ <[^>]+> f3fc 8130 	mrs	r1, SPSR_mon
+0[0-9a-f]+ <[^>]+> f3ef 8130 	mrs	r1, SP_hyp
+0[0-9a-f]+ <[^>]+> f3ee 8130 	mrs	r1, ELR_hyp
+0[0-9a-f]+ <[^>]+> f3fe 8130 	mrs	r1, SPSR_hyp
+0[0-9a-f]+ <[^>]+> f381 8020 	msr	R8_usr, r1
+0[0-9a-f]+ <[^>]+> f381 8120 	msr	R9_usr, r1
+0[0-9a-f]+ <[^>]+> f381 8220 	msr	R10_usr, r1
+0[0-9a-f]+ <[^>]+> f381 8320 	msr	R11_usr, r1
+0[0-9a-f]+ <[^>]+> f381 8420 	msr	R12_usr, r1
+0[0-9a-f]+ <[^>]+> f381 8520 	msr	SP_usr, r1
+0[0-9a-f]+ <[^>]+> f381 8620 	msr	LR_usr, r1
+0[0-9a-f]+ <[^>]+> f381 8820 	msr	R8_fiq, r1
+0[0-9a-f]+ <[^>]+> f381 8920 	msr	R9_fiq, r1
+0[0-9a-f]+ <[^>]+> f381 8a20 	msr	R10_fiq, r1
+0[0-9a-f]+ <[^>]+> f381 8b20 	msr	R11_fiq, r1
+0[0-9a-f]+ <[^>]+> f381 8c20 	msr	R12_fiq, r1
+0[0-9a-f]+ <[^>]+> f381 8d20 	msr	SP_fiq, r1
+0[0-9a-f]+ <[^>]+> f381 8e20 	msr	LR_fiq, r1
+0[0-9a-f]+ <[^>]+> f391 8e20 	msr	SPSR_fiq, r1
+0[0-9a-f]+ <[^>]+> f381 8130 	msr	SP_irq, r1
+0[0-9a-f]+ <[^>]+> f381 8030 	msr	LR_irq, r1
+0[0-9a-f]+ <[^>]+> f391 8030 	msr	SPSR_irq, r1
+0[0-9a-f]+ <[^>]+> f381 8330 	msr	SP_svc, r1
+0[0-9a-f]+ <[^>]+> f381 8230 	msr	LR_svc, r1
+0[0-9a-f]+ <[^>]+> f391 8230 	msr	SPSR_svc, r1
+0[0-9a-f]+ <[^>]+> f381 8530 	msr	SP_abt, r1
+0[0-9a-f]+ <[^>]+> f381 8430 	msr	LR_abt, r1
+0[0-9a-f]+ <[^>]+> f391 8430 	msr	SPSR_abt, r1
+0[0-9a-f]+ <[^>]+> f381 8730 	msr	SP_und, r1
+0[0-9a-f]+ <[^>]+> f381 8630 	msr	LR_und, r1
+0[0-9a-f]+ <[^>]+> f391 8630 	msr	SPSR_und, r1
+0[0-9a-f]+ <[^>]+> f381 8d30 	msr	SP_mon, r1
+0[0-9a-f]+ <[^>]+> f381 8c30 	msr	LR_mon, r1
+0[0-9a-f]+ <[^>]+> f391 8c30 	msr	SPSR_mon, r1
+0[0-9a-f]+ <[^>]+> f381 8f30 	msr	SP_hyp, r1
+0[0-9a-f]+ <[^>]+> f381 8e30 	msr	ELR_hyp, r1
+0[0-9a-f]+ <[^>]+> f391 8e30 	msr	SPSR_hyp, r1
diff --git a/gas/testsuite/gas/arm/armv7-a+virt.s b/gas/testsuite/gas/arm/armv7-a+virt.s
new file mode 100644
index 0000000..354b8bc
--- /dev/null
+++ b/gas/testsuite/gas/arm/armv7-a+virt.s
@@ -0,0 +1,146 @@
+	.text
+	.syntax unified
+	.arm
+foo:
+	hvc 0x0000
+	hvc 0xffff
+	eret
+	mrs r1, R8_usr
+	mrs r1, R9_usr
+	mrs r1, R10_usr
+	mrs r1, R11_usr
+	mrs r1, R12_usr
+	mrs r1, SP_usr
+	mrs r1, LR_usr
+	mrs r1, R8_fiq
+	mrs r1, R9_fiq
+	mrs r1, R10_fiq
+	mrs r1, R11_fiq
+	mrs r1, R12_fiq
+	mrs r1, SP_fiq
+	mrs r1, LR_fiq
+	mrs r1, SPSR_fiq
+	mrs r1, SP_irq
+	mrs r1, LR_irq
+	mrs r1, SPSR_irq
+	mrs r1, SP_svc
+	mrs r1, LR_svc
+	mrs r1, SPSR_svc
+	mrs r1, SP_abt
+	mrs r1, LR_abt
+	mrs r1, SPSR_abt
+	mrs r1, SP_und
+	mrs r1, LR_und
+	mrs r1, SPSR_und
+	mrs r1, SP_mon
+	mrs r1, LR_mon
+	mrs r1, SPSR_mon
+	mrs r1, SP_hyp
+	mrs r1, ELR_hyp
+	mrs r1, SPSR_hyp
+	msr R8_usr, r1
+	msr R9_usr, r1
+	msr R10_usr, r1
+	msr R11_usr, r1
+	msr R12_usr, r1
+	msr SP_usr, r1
+	msr LR_usr, r1
+	msr R8_fiq, r1
+	msr R9_fiq, r1
+	msr R10_fiq, r1
+	msr R11_fiq, r1
+	msr R12_fiq, r1
+	msr SP_fiq, r1
+	msr LR_fiq, r1
+	msr SPSR_fiq, r1
+	msr SP_irq, r1
+	msr LR_irq, r1
+	msr SPSR_irq, r1
+	msr SP_svc, r1
+	msr LR_svc, r1
+	msr SPSR_svc, r1
+	msr SP_abt, r1
+	msr LR_abt, r1
+	msr SPSR_abt, r1
+	msr SP_und, r1
+	msr LR_und, r1
+	msr SPSR_und, r1
+	msr SP_mon, r1
+	msr LR_mon, r1
+	msr SPSR_mon, r1
+	msr SP_hyp, r1
+	msr ELR_hyp, r1
+	msr SPSR_hyp, r1
+
+	.thumb
+bar:
+	hvc 0x0000
+	hvc 0xffff
+	eret
+	mrs r1, R8_usr
+	mrs r1, R9_usr
+	mrs r1, R10_usr
+	mrs r1, R11_usr
+	mrs r1, R12_usr
+	mrs r1, SP_usr
+	mrs r1, LR_usr
+	mrs r1, R8_fiq
+	mrs r1, R9_fiq
+	mrs r1, R10_fiq
+	mrs r1, R11_fiq
+	mrs r1, R12_fiq
+	mrs r1, SP_fiq
+	mrs r1, LR_fiq
+	mrs r1, SPSR_fiq
+	mrs r1, SP_irq
+	mrs r1, LR_irq
+	mrs r1, SPSR_irq
+	mrs r1, SP_svc
+	mrs r1, LR_svc
+	mrs r1, SPSR_svc
+	mrs r1, SP_abt
+	mrs r1, LR_abt
+	mrs r1, SPSR_abt
+	mrs r1, SP_und
+	mrs r1, LR_und
+	mrs r1, SPSR_und
+	mrs r1, SP_mon
+	mrs r1, LR_mon
+	mrs r1, SPSR_mon
+	mrs r1, SP_hyp
+	mrs r1, ELR_hyp
+	mrs r1, SPSR_hyp
+	msr R8_usr, r1
+	msr R9_usr, r1
+	msr R10_usr, r1
+	msr R11_usr, r1
+	msr R12_usr, r1
+	msr SP_usr, r1
+	msr LR_usr, r1
+	msr R8_fiq, r1
+	msr R9_fiq, r1
+	msr R10_fiq, r1
+	msr R11_fiq, r1
+	msr R12_fiq, r1
+	msr SP_fiq, r1
+	msr LR_fiq, r1
+	msr SPSR_fiq, r1
+	msr SP_irq, r1
+	msr LR_irq, r1
+	msr SPSR_irq, r1
+	msr SP_svc, r1
+	msr LR_svc, r1
+	msr SPSR_svc, r1
+	msr SP_abt, r1
+	msr LR_abt, r1
+	msr SPSR_abt, r1
+	msr SP_und, r1
+	msr LR_und, r1
+	msr SPSR_und, r1
+	msr SP_mon, r1
+	msr LR_mon, r1
+	msr SPSR_mon, r1
+	msr SP_hyp, r1
+	msr ELR_hyp, r1
+	msr SPSR_hyp, r1
+
diff --git a/gas/testsuite/gas/arm/attr-march-all.d b/gas/testsuite/gas/arm/attr-march-all.d
index a976d04..e56f317 100644
--- a/gas/testsuite/gas/arm/attr-march-all.d
+++ b/gas/testsuite/gas/arm/attr-march-all.d
@@ -14,4 +14,4 @@ File Attributes
   Tag_THUMB_ISA_use: Thumb-2
   Tag_MPextension_use: Allowed
   Tag_DIV_use: Allowed in v7-A with integer division extension
-  Tag_Virtualization_use: TrustZone
+  Tag_Virtualization_use: TrustZone and Virtualization Extensions
diff --git a/gas/testsuite/gas/arm/attr-march-armv7-a+sec+virt.d b/gas/testsuite/gas/arm/attr-march-armv7-a+sec+virt.d
new file mode 100644
index 0000000..c51e093
--- /dev/null
+++ b/gas/testsuite/gas/arm/attr-march-armv7-a+sec+virt.d
@@ -0,0 +1,16 @@
+# name: attributes for -march=armv7-a+sec+virt
+# source: blank.s
+# as: -march=armv7-a+sec+virt
+# readelf: -A
+# This test is only valid on EABI based ports.
+# target: *-*-*eabi
+
+Attribute Section: aeabi
+File Attributes
+  Tag_CPU_name: "7-A"
+  Tag_CPU_arch: v7
+  Tag_CPU_arch_profile: Application
+  Tag_ARM_ISA_use: Yes
+  Tag_THUMB_ISA_use: Thumb-2
+  Tag_DIV_use: Allowed in v7-A with integer division extension
+  Tag_Virtualization_use: TrustZone and Virtualization Extensions
diff --git a/gas/testsuite/gas/arm/attr-march-armv7-a+virt.d b/gas/testsuite/gas/arm/attr-march-armv7-a+virt.d
new file mode 100644
index 0000000..9329bc1
--- /dev/null
+++ b/gas/testsuite/gas/arm/attr-march-armv7-a+virt.d
@@ -0,0 +1,16 @@
+# name: attributes for -march=armv7-a+virt
+# source: blank.s
+# as: -march=armv7-a+virt
+# readelf: -A
+# This test is only valid on EABI based ports.
+# target: *-*-*eabi
+
+Attribute Section: aeabi
+File Attributes
+  Tag_CPU_name: "7-A"
+  Tag_CPU_arch: v7
+  Tag_CPU_arch_profile: Application
+  Tag_ARM_ISA_use: Yes
+  Tag_THUMB_ISA_use: Thumb-2
+  Tag_DIV_use: Allowed in v7-A with integer division extension
+  Tag_Virtualization_use: Virtualization Extensions
diff --git a/include/opcode/arm.h b/include/opcode/arm.h
index 58cace8..0bfd302 100644
--- a/include/opcode/arm.h
+++ b/include/opcode/arm.h
@@ -54,6 +54,7 @@
 #define ARM_EXT_OS	 0x20000000	/* OS Extensions.  */
 #define ARM_EXT_ADIV	 0x40000000	/* Integer divide extensions in ARM 
 					   state.  */
+#define ARM_EXT_VIRT	 0x80000000	/* Virtualization extensions.  */
 
 /* Co-processor space extensions.  */
 #define ARM_CEXT_XSCALE   0x00000001	/* Allow MIA etc.          */
@@ -222,10 +223,11 @@
 #define ARM_ARCH_V7A_MP_SEC \
 			ARM_FEATURE (ARM_AEXT_V7A | ARM_EXT_MP | ARM_EXT_SEC, \
 				     0)
-/* v7-a+idiv+mp+sec.  */
-#define ARM_ARCH_V7A_IDIV_MP_SEC \
+/* v7-a+idiv+mp+sec+virt.  */
+#define ARM_ARCH_V7A_IDIV_MP_SEC_VIRT \
 			ARM_FEATURE (ARM_AEXT_V7A | ARM_EXT_MP | ARM_EXT_SEC \
-				     | ARM_EXT_DIV | ARM_EXT_ADIV, 0)
+				     | ARM_EXT_DIV | ARM_EXT_ADIV \
+				     | ARM_EXT_VIRT, 0)
 
 /* There are too many feature bits to fit in a single word, so use a
    structure.  For simplicity we put all core features in one word and
diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c
index 005c957..e506abd 100644
--- a/opcodes/arm-dis.c
+++ b/opcodes/arm-dis.c
@@ -816,7 +816,8 @@ static const struct opcode32 neon_opcodes[] =
 
    %e                   print arm SMI operand (bits 0..7,8..19).
    %E			print the LSB and WIDTH fields of a BFI or BFC instruction.
-   %V                   print the 16-bit immediate field of a MOVT or MOVW instruction.  */
+   %V                   print the 16-bit immediate field of a MOVT or MOVW instruction.
+   %R			print the SPSR/CPSR or banked register of an MRS.  */
 
 static const struct opcode32 arm_opcodes[] =
 {
@@ -829,6 +830,10 @@ static const struct opcode32 arm_opcodes[] =
   {ARM_EXT_V3M, 0x00800090, 0x0fa000f0, "%22?sumull%20's%c\t%12-15Ru, %16-19Ru, %0-3R, %8-11R"},
   {ARM_EXT_V3M, 0x00a00090, 0x0fa000f0, "%22?sumlal%20's%c\t%12-15Ru, %16-19Ru, %0-3R, %8-11R"},
 
+  /* Virtualization Extension instructions.  */
+  {ARM_EXT_VIRT, 0x0160006e, 0x0fffffff, "eret%c"},
+  {ARM_EXT_VIRT, 0x01400070, 0x0ff000f0, "hvc%c\t%e"},
+
   /* Integer Divide Extension instructions.  */
   {ARM_EXT_ADIV, 0x0710f010, 0x0ff0f0f0, "sdiv%c\t%16-19r, %0-3r, %8-11r"},
   {ARM_EXT_ADIV, 0x0730f010, 0x0ff0f0f0, "udiv%c\t%16-19r, %0-3r, %8-11r"},
@@ -1091,8 +1096,9 @@ static const struct opcode32 arm_opcodes[] =
   {ARM_EXT_V1, 0x00e00000, 0x0fe00010, "rsc%20's%c\t%12-15r, %16-19r, %o"},
   {ARM_EXT_V1, 0x00e00010, 0x0fe00090, "rsc%20's%c\t%12-15R, %16-19R, %o"},
 
-  {ARM_EXT_V3, 0x0120f000, 0x0db0f000, "msr%c\t%22?SCPSR%C, %o"},
-  {ARM_EXT_V3, 0x010f0000, 0x0fbf0fff, "mrs%c\t%12-15R, %22?SCPSR"},
+  {ARM_EXT_VIRT, 0x0120f200, 0x0fb0f200, "msr%c\t%C, %0-3r"},
+  {ARM_EXT_V3, 0x0120f000, 0x0db0f000, "msr%c\t%C, %o"},
+  {ARM_EXT_V3, 0x01000000, 0x0fb00cff, "mrs%c\t%12-15R, %R"},
 
   {ARM_EXT_V1, 0x03000000, 0x0fe00000, "tst%p%c\t%16-19r, %o"},
   {ARM_EXT_V1, 0x01000000, 0x0fe00010, "tst%p%c\t%16-19r, %o"},
@@ -1103,7 +1109,6 @@ static const struct opcode32 arm_opcodes[] =
   {ARM_EXT_V1, 0x01200010, 0x0fe00090, "teq%p%c\t%16-19R, %o"},
 
   {ARM_EXT_V1, 0x03400000, 0x0fe00000, "cmp%p%c\t%16-19r, %o"},
-  {ARM_EXT_V3, 0x01400000, 0x0ff00010, "mrs%c\t%12-15R, %22?SCPSR"},
   {ARM_EXT_V1, 0x01400000, 0x0fe00010, "cmp%p%c\t%16-19r, %o"},
   {ARM_EXT_V1, 0x01400010, 0x0fe00090, "cmp%p%c\t%16-19R, %o"},
 
@@ -1313,6 +1318,7 @@ static const struct opcode16 thumb_opcodes[] =
        %M		print a modified 12-bit immediate (same location)
        %J		print a 16-bit immediate from hw1[3:0,10],hw2[14:12,7:0]
        %K		print a 16-bit immediate from hw2[3:0],hw1[3:0],hw2[11:4]
+       %H		print a 16-bit immediate from hw2[3:0],hw1[11:0]
        %S		print a possibly-shifted Rm
 
        %a		print the address of a plain load/store
@@ -1360,6 +1366,10 @@ static const struct opcode32 thumb32_opcodes[] =
   {ARM_EXT_DIV, 0xfb90f0f0, 0xfff0f0f0, "sdiv%c\t%8-11r, %16-19r, %0-3r"},
   {ARM_EXT_DIV, 0xfbb0f0f0, 0xfff0f0f0, "udiv%c\t%8-11r, %16-19r, %0-3r"},
 
+  /* Virtualization Extension instructions.  */
+  {ARM_EXT_VIRT, 0xf7e08000, 0xfff0f000, "hvc%c\t%V"},
+  /* We skip ERET as that is SUBS pc, lr, #0.  */
+
   /* MP Extension instructions.  */
   {ARM_EXT_MP,   0xf830f000, 0xff70f000, "pldw%c\t%a"},
 
@@ -1380,7 +1390,7 @@ static const struct opcode32 thumb32_opcodes[] =
   {ARM_EXT_V6T2, 0xf3c08f00, 0xfff0ffff, "bxj%c\t%16-19r%x"},
   {ARM_EXT_V6T2, 0xe810c000, 0xffd0ffff, "rfedb%c\t%16-19r%21'!"},
   {ARM_EXT_V6T2, 0xe990c000, 0xffd0ffff, "rfeia%c\t%16-19r%21'!"},
-  {ARM_EXT_V6T2, 0xf3ef8000, 0xffeff000, "mrs%c\t%8-11r, %D"},
+  {ARM_EXT_V6T2, 0xf3e08000, 0xffe0f000, "mrs%c\t%8-11r, %D"},
   {ARM_EXT_V6T2, 0xf3af8100, 0xffffffe0, "cps\t#%0-4d%X"},
   {ARM_EXT_V6T2, 0xe8d0f000, 0xfff0fff0, "tbb%c\t[%16-19r, %0-3r]%x"},
   {ARM_EXT_V6T2, 0xe8d0f010, 0xfff0fff0, "tbh%c\t[%16-19r, %0-3r, lsl #1]%x"},
@@ -2862,6 +2872,52 @@ print_insn_neon (struct disassemble_info *info, long given, bfd_boolean thumb)
   return FALSE;
 }
 
+/* Return the name of a v7A special register.  */
+
+static const char * 
+banked_regname (unsigned reg)
+{
+  switch (reg)
+    {
+      case 15: return "CPSR";
+      case 32: return "R8_usr"; 
+      case 33: return "R9_usr";
+      case 34: return "R10_usr";
+      case 35: return "R11_usr";
+      case 36: return "R12_usr";
+      case 37: return "SP_usr";
+      case 38: return "LR_usr";
+      case 40: return "R8_fiq"; 
+      case 41: return "R9_fiq";
+      case 42: return "R10_fiq";
+      case 43: return "R11_fiq";
+      case 44: return "R12_fiq";
+      case 45: return "SP_fiq";
+      case 46: return "LR_fiq";
+      case 48: return "LR_irq";
+      case 49: return "SP_irq";
+      case 50: return "LR_svc";
+      case 51: return "SP_svc";
+      case 52: return "LR_abt";
+      case 53: return "SP_abt";
+      case 54: return "LR_und";
+      case 55: return "SP_und";
+      case 60: return "LR_mon";
+      case 61: return "SP_mon";
+      case 62: return "ELR_hyp";
+      case 63: return "SP_hyp";
+      case 79: return "SPSR";
+      case 110: return "SPSR_fiq";
+      case 112: return "SPSR_irq";
+      case 114: return "SPSR_svc";
+      case 116: return "SPSR_abt";
+      case 118: return "SPSR_und";
+      case 124: return "SPSR_mon";
+      case 126: return "SPSR_hyp";
+      default: return NULL;
+    }
+}
+
 /* Print one ARM instruction from PC on INFO->STREAM.  */
 
 static void
@@ -3156,15 +3212,31 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info, long given)
 		      break;
 
 		    case 'C':
-		      func (stream, "_");
-		      if (given & 0x80000)
-			func (stream, "f");
-		      if (given & 0x40000)
-			func (stream, "s");
-		      if (given & 0x20000)
-			func (stream, "x");
-		      if (given & 0x10000)
-			func (stream, "c");
+		      if ((given & 0x02000200) == 0x200)
+			{
+			  const char * name;
+			  unsigned sysm = (given & 0x004f0000) >> 16;
+			  sysm |= (given & 0x300) >> 4;
+			  name = banked_regname (sysm);
+
+			  if (name != NULL)
+			    func (stream, "%s", name);
+			  else
+			    func (stream, "(UNDEF: %lu)", sysm);
+			}
+		      else
+			{
+			  func (stream, "%cPSR_", 
+				(given & 0x00400000) ? 'S' : 'C');
+			  if (given & 0x80000)
+			    func (stream, "f");
+			  if (given & 0x40000)
+			    func (stream, "s");
+			  if (given & 0x20000)
+			    func (stream, "x");
+			  if (given & 0x10000)
+			    func (stream, "c");
+			}
 		      break;
 
 		    case 'U':
@@ -3302,6 +3374,21 @@ print_insn_arm (bfd_vma pc, struct disassemble_info *info, long given)
 			}
 			break;
 
+		      case 'R':
+			/* Get the PSR/banked register name.  */
+			{
+			  const char * name;
+			  unsigned sysm = (given & 0x004f0000) >> 16;
+			  sysm |= (given & 0x300) >> 4;
+			  name = banked_regname (sysm);
+
+			  if (name != NULL)
+			    func (stream, "%s", name);
+			  else
+			    func (stream, "(UNDEF: %lu)", sysm);
+			}
+			break;
+
 		      case 'V':
 			/* 16-bit unsigned immediate from a MOVT or MOVW
 			   instruction, encoded in bits 0:11 and 15:19.  */
@@ -3746,6 +3833,17 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
 		}
 		break;
 
+	      case 'V':
+		{
+		  unsigned int imm = 0;
+
+		  imm |= (given & 0x00000fffu);
+		  imm |= (given & 0x000f0000u) >> 4;
+		  func (stream, "#%u", imm);
+		  value_in_comment = imm;
+		}
+		break;
+
 	      case 'S':
 		{
 		  unsigned int reg = (given & 0x0000000fu);
@@ -4070,6 +4168,18 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
 		    if (given & 0x100)
 		      func (stream, "c");
 		  }
+		else if ((given & 0x20) == 0x20)
+		  {
+		    char const* name;
+		    unsigned sysm = (given & 0xf00) >> 8;
+		    sysm |= (given & 0x30);
+		    sysm |= (given & 0x00100000) >> 14;
+		    name = banked_regname (sysm);
+		    if (name != NULL)
+		      func (stream, "%s", name);
+		    else
+		      func (stream, "(UNDEF: %lu)", sysm);
+		  }
 		else
 		  {
 		    func (stream, psr_name (given & 0xff));
@@ -4077,8 +4187,19 @@ print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
 		break;
 
 	      case 'D':
-		if ((given & 0xff) == 0)
-		  func (stream, "%cPSR", (given & 0x100000) ? 'S' : 'C');
+		if (((given & 0xff) == 0)
+		    || ((given & 0x20) == 0x20))
+		  {
+		    char const* name;
+		    unsigned sm = (given & 0xf0000) >> 16;
+		    sm |= (given & 0x30);
+		    sm |= (given & 0x00100000) >> 14;
+		    name = banked_regname (sm);
+		    if (name != NULL)
+		      func (stream, "%s", name);
+		    else
+		      func (stream, "(UNDEF: %lu)", sm);
+		  }
 		else
 		  func (stream, psr_name (given & 0xff));
 		break;

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