diff options
author | andrew <andrew@FreeBSD.org> | 2013-03-18 08:22:35 +0000 |
---|---|---|
committer | andrew <andrew@FreeBSD.org> | 2013-03-18 08:22:35 +0000 |
commit | 7479840eb88c237a735d25cf9f01cc3a07cef955 (patch) | |
tree | 97c9127fff01109b536ae1fc308839756ae906e0 /contrib/binutils/gas | |
parent | e0722a1284e9361c5be0754fbb14d19b7e6335ae (diff) | |
download | FreeBSD-src-7479840eb88c237a735d25cf9f01cc3a07cef955.zip FreeBSD-src-7479840eb88c237a735d25cf9f01cc3a07cef955.tar.gz |
Add support for the vmsr and vmrs instructions. This supports the system
level version of the instructions. When used in userland the hardware only
allows us to read/write FPSCR.
Diffstat (limited to 'contrib/binutils/gas')
-rw-r--r-- | contrib/binutils/gas/config/tc-arm.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/contrib/binutils/gas/config/tc-arm.c b/contrib/binutils/gas/config/tc-arm.c index 83e5433..c8f3149 100644 --- a/contrib/binutils/gas/config/tc-arm.c +++ b/contrib/binutils/gas/config/tc-arm.c @@ -651,6 +651,7 @@ struct asm_opcode #define BAD_ARGS _("bad arguments to instruction") #define BAD_PC _("r15 not allowed here") +#define BAD_SP _("r13 not allowed here") #define BAD_COND _("instruction cannot be conditional") #define BAD_OVERLAP _("registers may not be the same") #define BAD_HIREG _("lo register required") @@ -659,6 +660,7 @@ struct asm_opcode #define BAD_BRANCH _("branch must be last instruction in IT block") #define BAD_NOT_IT _("instruction not allowed in IT block") #define BAD_FPU _("selected FPU does not support instruction") +#define BAD_VMRS _("APSR_nzcv may only be used with fpscr") static struct hash_control *arm_ops_hsh; static struct hash_control *arm_cond_hsh; @@ -7095,6 +7097,68 @@ do_vfp_nsyn_msr (void) return SUCCESS; } +static int +do_vfp_vmrs (void) +{ + int rt; + + /* The destination register can be r0-r14 or APSR_nzcv */ + if (inst.operands[0].reg > 14) + { + inst.error = BAD_PC; + return FAIL; + } + + /* If the destination is r13 and not in ARM mode then unprefictable */ + if (thumb_mode && inst.operands[0].reg == REG_SP) + { + inst.error = BAD_SP; + return FAIL; + } + + /* If the destination is APSR_nzcv */ + if (inst.operands[0].isvec && inst.operands[1].reg != 1) + { + inst.error = BAD_VMRS; + return FAIL; + } + + if (inst.operands[0].isvec) + rt = 15; + else + rt = inst.operands[0].reg; + + /* Or in the registers to use */ + inst.instruction |= rt << 12; + inst.instruction |= inst.operands[1].reg << 16; + + return SUCCESS; +} + +static int +do_vfp_vmsr (void) +{ + /* The destination register can be r0-r14 or APSR_nzcv */ + if (inst.operands[1].reg > 14) + { + inst.error = BAD_PC; + return FAIL; + } + + /* If the destination is r13 and not in ARM mode then unprefictable */ + if (thumb_mode && inst.operands[0].reg == REG_SP) + { + inst.error = BAD_SP; + return FAIL; + } + + /* Or in the registers to use */ + inst.instruction |= inst.operands[1].reg << 12; + inst.instruction |= inst.operands[0].reg << 16; + + return SUCCESS; +} + static void do_mrs (void) { @@ -15726,6 +15790,8 @@ static const struct asm_opcode insns[] = cCE(ftouizs, ebc0ac0, 2, (RVS, RVS), vfp_sp_monadic), cCE(fmrx, ef00a10, 2, (RR, RVC), rd_rn), cCE(fmxr, ee00a10, 2, (RVC, RR), rn_rd), + cCE(vmrs, ef00a10, 2, (APSR_RR, RVC), vfp_vmrs), + cCE(vmsr, ee00a10, 2, (RVC, RR), vfp_vmsr), /* Memory operations. */ cCE(flds, d100a00, 2, (RVS, ADDRGLDC), vfp_sp_ldst), |