return nzcv;
}
+/* VISIBLE TO LIBVEX CLIENT */
+ULong LibVEX_GuestARM64_get_fpsr ( const VexGuestARM64State* vex_state )
+{
+ UInt w32 = vex_state->guest_QCFLAG[0] | vex_state->guest_QCFLAG[1]
+ | vex_state->guest_QCFLAG[2] | vex_state->guest_QCFLAG[3];
+ ULong fpsr = 0;
+ // QC
+ if (w32 != 0)
+ fpsr |= (1 << 27);
+ return fpsr;
+}
+
+void LibVEX_GuestARM64_set_fpsr ( /*MOD*/VexGuestARM64State* vex_state,
+ ULong fpsr )
+{
+ // QC
+ vex_state->guest_QCFLAG[0] = (UInt)((fpsr >> 27) & 1);
+ vex_state->guest_QCFLAG[1] = 0;
+ vex_state->guest_QCFLAG[2] = 0;
+ vex_state->guest_QCFLAG[3] = 0;
+}
+
/* VISIBLE TO LIBVEX CLIENT */
void LibVEX_GuestARM64_initialise ( /*OUT*/VexGuestARM64State* vex_state )
{
/* Describe any sections to be regarded by Memcheck as
'always-defined'. */
- .n_alwaysDefd = 10,
+ .n_alwaysDefd = 9,
/* flags thunk: OP is always defd, whereas DEP1 and DEP2
have to be tracked. See detailed comment in gdefs.h on
/* 5 */ ALWAYSDEFD(guest_CMLEN),
/* 6 */ ALWAYSDEFD(guest_NRADDR),
/* 7 */ ALWAYSDEFD(guest_IP_AT_SYSCALL),
- /* 8 */ ALWAYSDEFD(guest_FPCR),
- /* 9 */ ALWAYSDEFD(guest_FPSR)
+ /* 8 */ ALWAYSDEFD(guest_TPIDR_EL0)
}
};
#define OFFB_Q31 offsetof(VexGuestARM64State,guest_Q31)
#define OFFB_FPCR offsetof(VexGuestARM64State,guest_FPCR)
-#define OFFB_FPSR offsetof(VexGuestARM64State,guest_FPSR)
-//ZZ #define OFFB_TPIDRURO offsetof(VexGuestARMState,guest_TPIDRURO)
-//ZZ #define OFFB_ITSTATE offsetof(VexGuestARMState,guest_ITSTATE)
-//ZZ #define OFFB_QFLAG32 offsetof(VexGuestARMState,guest_QFLAG32)
-//ZZ #define OFFB_GEFLAG0 offsetof(VexGuestARMState,guest_GEFLAG0)
-//ZZ #define OFFB_GEFLAG1 offsetof(VexGuestARMState,guest_GEFLAG1)
-//ZZ #define OFFB_GEFLAG2 offsetof(VexGuestARMState,guest_GEFLAG2)
-//ZZ #define OFFB_GEFLAG3 offsetof(VexGuestARMState,guest_GEFLAG3)
+#define OFFB_QCFLAG offsetof(VexGuestARM64State,guest_QCFLAG)
#define OFFB_CMSTART offsetof(VexGuestARM64State,guest_CMSTART)
#define OFFB_CMLEN offsetof(VexGuestARM64State,guest_CMLEN)
/* Cases for FPSR
0xD51B44 001 Rt MSR fpsr, rT
0xD53B44 001 Rt MSR rT, fpsr
+ The only part of this we model is FPSR.QC. All other bits
+ are ignored when writing to it and RAZ when reading from it.
*/
if ( (INSN(31,0) & 0xFFFFFFE0) == 0xD51B4420 /*MSR*/
|| (INSN(31,0) & 0xFFFFFFE0) == 0xD53B4420 /*MRS*/) {
Bool toSys = INSN(21,21) == 0;
UInt tt = INSN(4,0);
if (toSys) {
- stmt( IRStmt_Put( OFFB_FPSR, getIReg32orZR(tt)) );
+ /* Just deal with FPSR.QC. Make up a V128 value which is
+ zero if Xt[27] is zero and any other value if Xt[27] is
+ nonzero. */
+ IRTemp qc64 = newTemp(Ity_I64);
+ assign(qc64, binop(Iop_And64,
+ binop(Iop_Shr64, getIReg64orZR(tt), mkU8(27)),
+ mkU64(1)));
+ IRExpr* qcV128 = binop(Iop_64HLtoV128, mkexpr(qc64), mkexpr(qc64));
+ stmt( IRStmt_Put( OFFB_QCFLAG, qcV128 ) );
DIP("msr fpsr, %s\n", nameIReg64orZR(tt));
} else {
- putIReg32orZR(tt, IRExpr_Get(OFFB_FPSR, Ity_I32));
+ /* Generate a value which is all zeroes except for bit 27,
+ which must be zero if QCFLAG is all zeroes and one otherwise. */
+ IRTemp qcV128 = newTemp(Ity_V128);
+ assign(qcV128, IRExpr_Get( OFFB_QCFLAG, Ity_V128 ));
+ IRTemp qc64 = newTemp(Ity_I64);
+ assign(qc64, binop(Iop_Or64, unop(Iop_V128HIto64, mkexpr(qcV128)),
+ unop(Iop_V128to64, mkexpr(qcV128))));
+ IRExpr* res = binop(Iop_Shl64,
+ unop(Iop_1Uto64,
+ binop(Iop_CmpNE64, mkexpr(qc64), mkU64(0))),
+ mkU8(27));
+ putIReg64orZR(tt, res);
DIP("mrs %s, fpsr\n", nameIReg64orZR(tt));
}
return True;
/* Cases for NZCV
D51B42 000 Rt MSR nzcv, rT
D53B42 000 Rt MRS rT, nzcv
+ The only parts of NZCV that actually exist are bits 31:28, which
+ are the N Z C and V bits themselves. Hence the flags thunk provides
+ all the state we need.
*/
if ( (INSN(31,0) & 0xFFFFFFE0) == 0xD51B4200 /*MSR*/
|| (INSN(31,0) & 0xFFFFFFE0) == 0xD53B4200 /*MRS*/) {
U128 guest_Q30;
U128 guest_Q31;
+ /* A 128-bit value which is used to represent the FPSR.QC (sticky
+ saturation) flag, when necessary. If the value stored here
+ is zero, FPSR.QC is currently zero. If it is any other value,
+ FPSR.QC is currently one. We don't currently represent any
+ other bits of FPSR, so this is all that that is for FPSR. */
+ U128 guest_QCFLAG;
+
/* Various pseudo-regs mandated by Vex or Valgrind. */
/* Emulation notes */
UInt guest_EMNOTE;
note of bits 23 and 22. */
UInt guest_FPCR;
- /* The complete FPSR. As with FPCR, the guest may write and
- read any values here, and the emulation ignores it, with the
- exception of bit 27 (QC, the sticky saturation bit) which
- does get set when required. */
- UInt guest_FPSR;
-
/* Padding to make it have an 16-aligned size */
- UInt pad_end_0;
- ULong pad_end_1;
+ /* UInt pad_end_0; */
+ /* ULong pad_end_1; */
}
VexGuestARM64State;
ULong LibVEX_GuestARM64_get_nzcv ( /*IN*/
const VexGuestARM64State* vex_state );
+/* Calculate the ARM64 FPSR state from the saved data, in the format
+ 36x0:qc:27x0 */
+extern
+ULong LibVEX_GuestARM64_get_fpsr ( /*IN*/
+ const VexGuestARM64State* vex_state );
+
+/* Set the ARM64 FPSR representation from the given FPSR value. */
+extern
+void LibVEX_GuestARM64_set_fpsr ( /*MOD*/VexGuestARM64State* vex_state,
+ ULong fpsr );
+
+
#endif /* ndef __LIBVEX_PUB_GUEST_ARM64_H */