/* tc-ppc.c -- Assemble for the PowerPC or POWER (RS/6000)
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
- 2004 Free Software Foundation, Inc.
+ 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
This file is part of GAS, the GNU Assembler.
You should have received a copy of the GNU General Public License
along with GAS; see the file COPYING. If not, write to the Free
- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
+ 02110-1301, USA. */
-#include <stdio.h>
#include "as.h"
#include "safe-ctype.h"
#include "subsegs.h"
as in 0d1.0. */
const char FLT_CHARS[] = "dD";
-/* '+' and '-' can be used as postfix predicate predictors for conditional
- branches. So they need to be accepted as symbol characters. */
-const char ppc_symbol_chars[] = "+-";
+/* Anything that can start an operand needs to be mentioned here,
+ to stop the input scrubber eating whitespace. */
+const char ppc_symbol_chars[] = "%[";
/* The dwarf2 data alignment, adjusted for 32 or 64 bit. */
int ppc_cie_data_alignment;
|| strcmp (arg, "7455") == 0)
ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
| PPC_OPCODE_ALTIVEC | PPC_OPCODE_32);
+ else if (strcmp (arg, "e300") == 0)
+ ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32
+ | PPC_OPCODE_E300);
else if (strcmp (arg, "altivec") == 0)
{
if (ppc_cpu == 0)
ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
| PPC_OPCODE_64 | PPC_OPCODE_POWER4);
}
+ else if (strcmp (arg, "power5") == 0)
+ {
+ ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
+ | PPC_OPCODE_64 | PPC_OPCODE_POWER4
+ | PPC_OPCODE_POWER5);
+ }
+ else if (strcmp (arg, "power6") == 0)
+ {
+ ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
+ | PPC_OPCODE_64 | PPC_OPCODE_POWER4
+ | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6);
+ }
+ else if (strcmp (arg, "cell") == 0)
+ {
+ ppc_cpu = (PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC
+ | PPC_OPCODE_64 | PPC_OPCODE_POWER4
+ | PPC_OPCODE_CELL);
+ }
/* -mcom means assemble for the common intersection between Power
and PowerPC. At present, we just allow the union, rather
than the intersection. */
-mbooke64 generate code for 64-bit PowerPC BookE\n\
-mbooke, mbooke32 generate code for 32-bit PowerPC BookE\n\
-mpower4 generate code for Power4 architecture\n\
+-mpower5 generate code for Power5 architecture\n\
+-mpower6 generate code for Power6 architecture\n\
+-mcell generate code for Cell Broadband Engine architecture\n\
-mcom generate code Power/PowerPC common instructions\n\
-many generate code for any architecture (PWR/PWRX/PPC)\n"));
fprintf (stream, _("\
-maltivec generate code for AltiVec\n\
+-me300 generate code for PowerPC e300 family\n\
-me500, -me500x2 generate code for Motorola e500 core complex\n\
-mspe generate code for Motorola SPE instructions\n\
-mregnames Allow symbolic names for registers\n\
else if (strcmp (default_cpu, "rs6000") == 0)
ppc_cpu |= PPC_OPCODE_POWER | PPC_OPCODE_32;
else if (strncmp (default_cpu, "powerpc", 7) == 0)
- {
- if (default_cpu[7] == '6' && default_cpu[8] == '4')
- ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_64;
- else
- ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32;
- }
+ ppc_cpu |= PPC_OPCODE_PPC | PPC_OPCODE_CLASSIC | PPC_OPCODE_32;
else
as_fatal (_("Unknown default cpu = %s, os = %s"),
default_cpu, default_os);
}
}
-/* Figure out the BFD architecture to use. */
+/* Figure out the BFD architecture to use. This function and ppc_mach
+ are called well before md_begin, when the output file is opened. */
enum bfd_architecture
ppc_arch ()
#endif
#endif
#ifdef OBJ_ELF
+# ifdef TE_VXWORKS
+ return "elf32-powerpc-vxworks";
+# else
return (target_big_endian
? (ppc_obj64 ? "elf64-powerpc" : "elf32-powerpc")
: (ppc_obj64 ? "elf64-powerpcle" : "elf32-powerpcle"));
+# endif
#endif
}
const struct powerpc_opcode *op_end;
const struct powerpc_macro *macro;
const struct powerpc_macro *macro_end;
- bfd_boolean dup_insn = FALSE;
+ unsigned int i;
+ bfd_boolean bad_insn = FALSE;
if (ppc_hash != NULL)
hash_die (ppc_hash);
/* Insert the opcodes into a hash table. */
ppc_hash = hash_new ();
+ /* Check operand masks. Code here and in the disassembler assumes
+ all the 1's in the mask are contiguous. */
+ for (i = 0; i < num_powerpc_operands; ++i)
+ {
+ unsigned long mask = powerpc_operands[i].bitm;
+ unsigned long right_bit;
+
+ right_bit = mask & -mask;
+ mask += right_bit;
+ right_bit = mask & -mask;
+ if (mask != right_bit)
+ {
+ as_bad (_("powerpc_operands[%d].bitm invalid"), i);
+ bad_insn = TRUE;
+ }
+ }
+
op_end = powerpc_opcodes + powerpc_num_opcodes;
for (op = powerpc_opcodes; op < op_end; op++)
{
- know ((op->opcode & op->mask) == op->opcode);
+ const unsigned char *o;
+ unsigned long omask = op->mask;
+
+ /* The mask had better not trim off opcode bits. */
+ if ((op->opcode & omask) != op->opcode)
+ {
+ as_bad (_("mask trims opcode bits for %s"),
+ op->name);
+ bad_insn = TRUE;
+ }
+
+ /* The operands must not overlap the opcode or each other. */
+ for (o = op->operands; *o; ++o)
+ if (*o >= num_powerpc_operands)
+ {
+ as_bad (_("operand index error for %s"),
+ op->name);
+ bad_insn = TRUE;
+ }
+ else
+ {
+ const struct powerpc_operand *operand = &powerpc_operands[*o];
+ if (operand->shift >= 0)
+ {
+ unsigned long mask = operand->bitm << operand->shift;
+ if (omask & mask)
+ {
+ as_bad (_("operand %d overlap in %s"),
+ (int) (o - op->operands), op->name);
+ bad_insn = TRUE;
+ }
+ omask |= mask;
+ }
+ }
if ((op->flags & ppc_cpu & ~(PPC_OPCODE_32 | PPC_OPCODE_64)) != 0
&& ((op->flags & (PPC_OPCODE_32 | PPC_OPCODE_64)) == 0
|| (ppc_cpu & PPC_OPCODE_BOOKE) == 0)
&& ((op->flags & (PPC_OPCODE_POWER4 | PPC_OPCODE_NOPOWER4)) == 0
|| ((op->flags & PPC_OPCODE_POWER4)
- == (ppc_cpu & PPC_OPCODE_POWER4))))
+ == (ppc_cpu & PPC_OPCODE_POWER4)))
+ && ((op->flags & PPC_OPCODE_POWER5) == 0
+ || ((op->flags & PPC_OPCODE_POWER5)
+ == (ppc_cpu & PPC_OPCODE_POWER5)))
+ && ((op->flags & PPC_OPCODE_POWER6) == 0
+ || ((op->flags & PPC_OPCODE_POWER6)
+ == (ppc_cpu & PPC_OPCODE_POWER6))))
{
const char *retval;
&& (op->flags & PPC_OPCODE_POWER) != 0)
continue;
- as_bad (_("Internal assembler error for instruction %s"),
+ as_bad (_("duplicate instruction %s"),
op->name);
- dup_insn = TRUE;
+ bad_insn = TRUE;
}
}
}
retval = hash_insert (ppc_macro_hash, macro->name, (PTR) macro);
if (retval != (const char *) NULL)
{
- as_bad (_("Internal assembler error for macro %s"), macro->name);
- dup_insn = TRUE;
+ as_bad (_("duplicate macro %s"), macro->name);
+ bad_insn = TRUE;
}
}
}
- if (dup_insn)
+ if (bad_insn)
abort ();
}
char *file;
unsigned int line;
{
- if (operand->bits != 32)
+ long min, max, right;
+ offsetT test;
+
+ max = operand->bitm;
+ right = max & -max;
+ min = 0;
+
+ if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
{
- long min, max;
- offsetT test;
+ if ((operand->flags & PPC_OPERAND_SIGNOPT) == 0)
+ max >>= 1;
+ min = ~(max | ((max & -max) - 1)) ;
- if ((operand->flags & PPC_OPERAND_SIGNED) != 0)
+ if (!ppc_obj64)
{
- if ((operand->flags & PPC_OPERAND_SIGNOPT) != 0)
- max = (1 << operand->bits) - 1;
- else
- max = (1 << (operand->bits - 1)) - 1;
- min = - (1 << (operand->bits - 1));
-
- if (!ppc_obj64)
+ /* Some people write 32 bit hex constants with the sign
+ extension done by hand. This shouldn't really be
+ valid, but, to permit this code to assemble on a 64
+ bit host, we sign extend the 32 bit value. */
+ if (val > 0
+ && (val & (offsetT) 0x80000000) != 0
+ && (val & (offsetT) 0xffffffff) == val)
{
- /* Some people write 32 bit hex constants with the sign
- extension done by hand. This shouldn't really be
- valid, but, to permit this code to assemble on a 64
- bit host, we sign extend the 32 bit value. */
- if (val > 0
- && (val & (offsetT) 0x80000000) != 0
- && (val & (offsetT) 0xffffffff) == val)
- {
- val -= 0x80000000;
- val -= 0x80000000;
- }
+ val -= 0x80000000;
+ val -= 0x80000000;
}
}
- else
- {
- max = (1 << operand->bits) - 1;
- min = 0;
- }
+ }
- if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0)
- test = - val;
- else
- test = val;
+ if ((operand->flags & PPC_OPERAND_PLUS1) != 0)
+ {
+ max++;
+ min++;
+ }
- if (test < (offsetT) min || test > (offsetT) max)
- {
- const char *err =
- _("operand out of range (%s not between %ld and %ld)");
- char buf[100];
+ if ((operand->flags & PPC_OPERAND_NEGATIVE) != 0)
+ test = - val;
+ else
+ test = val;
- sprint_value (buf, test);
- as_bad_where (file, line, err, buf, min, max);
- }
- }
+ if (test < (offsetT) min
+ || test > (offsetT) max
+ || (test & (right - 1)) != 0)
+ as_bad_value_out_of_range (_("operand"),
+ test, (offsetT) min, (offsetT) max, file, line);
if (operand->insert)
{
as_bad_where (file, line, errmsg);
}
else
- insn |= (((long) val & ((1 << operand->bits) - 1))
- << operand->shift);
+ insn |= ((long) val & operand->bitm) << operand->shift;
return insn;
}
ppc_frob_file_before_adjust ()
{
symbolS *symp;
+ asection *toc;
if (!ppc_obj64)
return;
dotname = xmalloc (len + 1);
dotname[0] = '.';
memcpy (dotname + 1, name, len);
- dotsym = symbol_find (dotname);
+ dotsym = symbol_find_noref (dotname, 1);
free (dotname);
if (dotsym != NULL && (symbol_used_p (dotsym)
|| symbol_used_in_reloc_p (dotsym)))
- {
- symbol_mark_used (symp);
- }
+ symbol_mark_used (symp);
+
}
+ toc = bfd_get_section_by_name (stdoutput, ".toc");
+ if (toc != NULL
+ && bfd_section_size (stdoutput, toc) > 0x10000)
+ as_warn (_("TOC section size exceeds 64k"));
+
/* Don't emit .TOC. symbol. */
symp = symbol_find (".TOC.");
if (symp != NULL)
struct ppc_fixup fixups[MAX_INSN_FIXUPS];
int fc;
char *f;
+ int addr_mod;
int i;
#ifdef OBJ_ELF
bfd_reloc_code_real_type reloc;
/* Write out the instruction. */
f = frag_more (4);
+ addr_mod = frag_now_fix () & 3;
+ if (frag_now->has_code && frag_now->insn_addr != addr_mod)
+ as_bad (_("instruction address is not a multiple of 4"));
+ frag_now->insn_addr = addr_mod;
+ frag_now->has_code = 1;
md_number_to_chars (f, insn, 4);
#ifdef OBJ_ELF
BFD_RELOC_UNUSED plus the operand index. This lets us easily
handle fixups for any operand type, although that is admittedly
not a very exciting feature. We pick a BFD reloc type in
- md_apply_fix3. */
+ md_apply_fix. */
for (i = 0; i < fc; i++)
{
const struct powerpc_operand *operand;
{
S_SET_VALUE (symbolP, (valueT) temp);
S_SET_EXTERNAL (symbolP);
+ S_SET_SEGMENT (symbolP, bfd_com_section_ptr);
}
demand_empty_rest_of_line ();
&symbol_rootP, &symbol_lastP);
symbol_get_tc (ppc_current_csect)->within = sym;
}
+
+#ifdef OBJ_ELF
+ dwarf2_emit_label (sym);
+#endif
}
/* This variable is set by ppc_frob_symbol if any absolute symbols are
table. */
if (! symbol_used_in_reloc_p (sym)
&& ((symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) != 0
- || (! S_IS_EXTERNAL (sym)
+ || (! (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym))
&& ! symbol_get_tc (sym)->output
&& S_GET_STORAGE_CLASS (sym) != C_FILE)))
return 1;
}
}
- if (! S_IS_EXTERNAL (sym)
+ if (! (S_IS_EXTERNAL (sym) || S_IS_WEAK (sym))
&& (symbol_get_bfdsym (sym)->flags & BSF_SECTION_SYM) == 0
&& S_GET_STORAGE_CLASS (sym) != C_FILE
&& S_GET_STORAGE_CLASS (sym) != C_FCN
/* Align a section (I don't know why this is machine dependent). */
valueT
-md_section_align (seg, addr)
- asection *seg;
- valueT addr;
+md_section_align (asection *seg ATTRIBUTE_UNUSED, valueT addr)
{
+#ifdef OBJ_ELF
+ return addr;
+#else
int align = bfd_get_section_alignment (stdoutput, seg);
return ((addr + (1 << align) - 1) & (-1 << align));
+#endif
}
/* We don't have any form of relaxing. */
case BFD_RELOC_PPC_B16_BRNTAKEN:
case BFD_RELOC_PPC_BA16_BRTAKEN:
case BFD_RELOC_PPC_BA16_BRNTAKEN:
+ case BFD_RELOC_24_PLT_PCREL:
case BFD_RELOC_PPC64_TOC:
return 1;
default:
&& fix->fx_r_type != BFD_RELOC_VTABLE_INHERIT
&& fix->fx_r_type != BFD_RELOC_VTABLE_ENTRY
&& !(fix->fx_r_type >= BFD_RELOC_PPC_TLS
- && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA)
- && (fix->fx_pcrel
- || (fix->fx_subsy != NULL
- && (S_GET_SEGMENT (fix->fx_subsy)
- == S_GET_SEGMENT (fix->fx_addsy)))
- || S_IS_LOCAL (fix->fx_addsy)));
+ && fix->fx_r_type <= BFD_RELOC_PPC64_DTPREL16_HIGHESTA));
}
#endif
+/* Implement HANDLE_ALIGN. This writes the NOP pattern into an
+ rs_align_code frag. */
+
+void
+ppc_handle_align (struct frag *fragP)
+{
+ valueT count = (fragP->fr_next->fr_address
+ - (fragP->fr_address + fragP->fr_fix));
+
+ if (count != 0 && (count & 3) == 0)
+ {
+ char *dest = fragP->fr_literal + fragP->fr_fix;
+
+ fragP->fr_var = 4;
+ md_number_to_chars (dest, 0x60000000, 4);
+
+ if ((ppc_cpu & PPC_OPCODE_POWER6) != 0)
+ {
+ /* For power6, we want the last nop to be a group terminating
+ one, "ori 1,1,0". Do this by inserting an rs_fill frag
+ immediately after this one, with its address set to the last
+ nop location. This will automatically reduce the number of
+ nops in the current frag by one. */
+ if (count > 4)
+ {
+ struct frag *group_nop = xmalloc (SIZEOF_STRUCT_FRAG + 4);
+
+ memcpy (group_nop, fragP, SIZEOF_STRUCT_FRAG);
+ group_nop->fr_address = group_nop->fr_next->fr_address - 4;
+ group_nop->fr_fix = 0;
+ group_nop->fr_offset = 1;
+ group_nop->fr_type = rs_fill;
+ fragP->fr_next = group_nop;
+ dest = group_nop->fr_literal;
+ }
+
+ md_number_to_chars (dest, 0x60210000, 4);
+ }
+ }
+}
+
/* Apply a fixup to the object code. This is called for all the
fixups we generated by the call to fix_new_exp, above. In the call
above we used a reloc code which was the largest legal reloc code
fixup. */
void
-md_apply_fix3 (fixP, valP, seg)
+md_apply_fix (fixP, valP, seg)
fixS *fixP;
valueT * valP;
segT seg ATTRIBUTE_UNUSED;
fixP->fx_done = 1;
#else
/* FIXME FIXME FIXME: The value we are passed in *valP includes
- the symbol values. Since we are using BFD_ASSEMBLER, if we are
- doing this relocation the code in write.c is going to call
- bfd_install_relocation, which is also going to use the symbol
- value. That means that if the reloc is fully resolved we want to
- use *valP since bfd_install_relocation is not being used.
+ the symbol values. If we are doing this relocation the code in
+ write.c is going to call bfd_install_relocation, which is also
+ going to use the symbol value. That means that if the reloc is
+ fully resolved we want to use *valP since bfd_install_relocation is
+ not being used.
However, if the reloc is not fully resolved we do not want to use
*valP, and must use fx_offset instead. However, if the reloc
is PC relative, we do want to use *valP since it includes the
csect. Other usages, such as `.long sym', generate relocs. This
is the documented behaviour of non-TOC symbols. */
if ((operand->flags & PPC_OPERAND_PARENS) != 0
- && operand->bits == 16
+ && (operand->bitm & 0xfff0) == 0xfff0
&& operand->shift == 0
&& (operand->insert == NULL || ppc_obj64)
&& fixP->fx_addsy != NULL
We are only prepared to turn a few of the operands into
relocs. */
if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
- && operand->bits == 26
+ && operand->bitm == 0x3fffffc
&& operand->shift == 0)
fixP->fx_r_type = BFD_RELOC_PPC_B26;
else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0
- && operand->bits == 16
+ && operand->bitm == 0xfffc
&& operand->shift == 0)
{
fixP->fx_r_type = BFD_RELOC_PPC_B16;
#endif
}
else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
- && operand->bits == 26
+ && operand->bitm == 0x3fffffc
&& operand->shift == 0)
fixP->fx_r_type = BFD_RELOC_PPC_BA26;
else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0
- && operand->bits == 16
+ && operand->bitm == 0xfffc
&& operand->shift == 0)
{
fixP->fx_r_type = BFD_RELOC_PPC_BA16;
}
#if defined (OBJ_XCOFF) || defined (OBJ_ELF)
else if ((operand->flags & PPC_OPERAND_PARENS) != 0
- && operand->bits == 16
+ && (operand->bitm & 0xfff0) == 0xfff0
&& operand->shift == 0)
{
if (ppc_is_toc_sym (fixP->fx_addsy))
value, 8);
break;
- case BFD_RELOC_LO16:
- case BFD_RELOC_16:
case BFD_RELOC_GPREL16:
case BFD_RELOC_16_GOT_PCREL:
case BFD_RELOC_16_GOTOFF:
value, 2);
break;
+ case BFD_RELOC_16:
+ if (fixP->fx_pcrel)
+ fixP->fx_r_type = BFD_RELOC_16_PCREL;
+ /* fall through */
+
+ case BFD_RELOC_16_PCREL:
+ md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+ value, 2);
+ break;
+
+ case BFD_RELOC_LO16:
+ if (fixP->fx_pcrel)
+ fixP->fx_r_type = BFD_RELOC_LO16_PCREL;
+ /* fall through */
+
+ case BFD_RELOC_LO16_PCREL:
+ md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
+ value, 2);
+ break;
+
/* This case happens when you write, for example,
lis %r3,(L1-L2)@ha
where L1 and L2 are defined later. */
case BFD_RELOC_HI16:
if (fixP->fx_pcrel)
- abort ();
+ fixP->fx_r_type = BFD_RELOC_HI16_PCREL;
+ /* fall through */
+
+ case BFD_RELOC_HI16_PCREL:
md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
PPC_HI (value), 2);
break;
case BFD_RELOC_HI16_S:
if (fixP->fx_pcrel)
- abort ();
+ fixP->fx_r_type = BFD_RELOC_HI16_S_PCREL;
+ /* fall through */
+
+ case BFD_RELOC_HI16_S_PCREL:
md_number_to_chars (fixP->fx_frag->fr_literal + fixP->fx_where,
PPC_HA (value), 2);
break;
if (fixP->fx_pcrel)
abort ();
{
- unsigned char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
+ char *where = fixP->fx_frag->fr_literal + fixP->fx_where;
unsigned long val, mask;
if (target_big_endian)
break;
case BFD_RELOC_PPC_TLS:
+ break;
+
case BFD_RELOC_PPC_DTPMOD:
case BFD_RELOC_PPC_TPREL16:
case BFD_RELOC_PPC_TPREL16_LO:
case BFD_RELOC_PPC64_DTPREL16_HIGHERA:
case BFD_RELOC_PPC64_DTPREL16_HIGHEST:
case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:
+ S_SET_THREAD_LOCAL (fixP->fx_addsy);
break;
#endif
/* Because SDA21 modifies the register field, the size is set to 4
#ifdef OBJ_ELF
fixP->fx_addnumber = value;
+
+ /* PowerPC uses RELA relocs, ie. the reloc addend is stored separately
+ from the section contents. If we are going to be emitting a reloc
+ then the section contents are immaterial, so don't warn if they
+ happen to overflow. Leave such warnings to ld. */
+ if (!fixP->fx_done)
+ fixP->fx_no_overflow = 1;
#else
if (fixP->fx_r_type != BFD_RELOC_PPC_TOC16)
fixP->fx_addnumber = 0;
}
int
-tc_ppc_regname_to_dw2regnum (const char *regname)
+tc_ppc_regname_to_dw2regnum (char *regname)
{
unsigned int regnum = -1;
unsigned int i;
{
{ "sp", 1 }, { "r.sp", 1 }, { "rtoc", 2 }, { "r.toc", 2 },
{ "mq", 64 }, { "lr", 65 }, { "ctr", 66 }, { "ap", 67 },
- { "cc", 68 }, { "xer", 76 }, { "vrsave", 109 }, { "vscr", 110 },
+ { "cr", 70 }, { "xer", 76 }, { "vrsave", 109 }, { "vscr", 110 },
{ "spe_acc", 111 }, { "spefscr", 112 }
};