@@ -184,6 +184,8 @@ enum {
#define FSR_FTT_SEQ_ERROR (4ULL << 14)
#define FSR_FTT_INVAL_FPR (6ULL << 14)
+#define FSR_QNE (1ULL << 13)
+
#define FSR_FCC0_SHIFT 10
#define FSR_FCC1_SHIFT 32
#define FSR_FCC2_SHIFT 34
@@ -436,6 +438,12 @@ struct CPUArchState {
/* FPU State Register, in parts */
uint32_t fsr; /* rm, tem, aexc */
uint32_t fsr_cexc_ftt; /* cexc, ftt */
+
+ /* single-element FPU fault queue */
+ uint32_t fsr_qne; /* qne */
+ uint32_t fsr_qi; /* faulting fp instruction */
+ target_ulong fsr_qa; /* address of faulting instruction */
+
uint32_t fcc[TARGET_FCCREGS]; /* fcc* */
CPU_DoubleU fpr[TARGET_DPREGS]; /* floating point registers */
@@ -21,6 +21,7 @@
#include "cpu.h"
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
+#include "exec/cpu_ldst.h"
#include "fpu/softfloat.h"
static inline float128 f128_in(Int128 i)
@@ -538,7 +539,7 @@ uint32_t helper_flcmpd(float64 src1, float64 src2)
target_ulong cpu_get_fsr(CPUSPARCState *env)
{
- target_ulong fsr = env->fsr | env->fsr_cexc_ftt;
+ target_ulong fsr = env->fsr | env->fsr_cexc_ftt | env->fsr_qne;
fsr |= env->fcc[0] << FSR_FCC0_SHIFT;
#ifdef TARGET_SPARC64
@@ -563,6 +564,7 @@ static void set_fsr_nonsplit(CPUSPARCState *env,
target_ulong fsr)
int rnd_mode;
env->fsr = fsr & (FSR_RD_MASK | FSR_TEM_MASK | FSR_AEXC_MASK);
+ env->fsr_qne = fsr & FSR_QNE;
switch (fsr & FSR_RD_MASK) {
case FSR_RD_NEAREST:
@@ -608,3 +610,16 @@ void helper_set_fsr_nofcc(CPUSPARCState *env,
uint32_t fsr)
env->fsr_cexc_ftt = fsr & (FSR_CEXC_MASK | FSR_FTT_MASK);
set_fsr_nonsplit(env, fsr);
}
+
+#ifndef TARGET_SPARC64
+void helper_store_fp_queue(CPUSPARCState *env, uint32_t addr)
+{
+ if (!env->fsr_qne) {
+ env->fsr_cexc_ftt = FSR_FTT_SEQ_ERROR;
+ cpu_raise_exception_ra(env, TT_FP_EXCP, GETPC());
+ }
+ cpu_stl_be_data(env, addr, env->fsr_qa);
+ cpu_stl_be_data(env, addr + 4, env->fsr_qi);
+ env->fsr_qne = 0;
+}
+#endif
@@ -85,6 +85,10 @@ DEF_HELPER_FLAGS_2(fitoq, TCG_CALL_NO_WG, i128, env, s32)
DEF_HELPER_FLAGS_2(fitos, TCG_CALL_NO_WG, f32, env, s32)
+#ifndef TARGET_SPARC64
+DEF_HELPER_2(store_fp_queue, void, env, i32)
+#endif
+
#ifdef TARGET_SPARC64
DEF_HELPER_FLAGS_2(fxtos, TCG_CALL_NO_WG, f32, env, s64)
DEF_HELPER_FLAGS_2(fxtod, TCG_CALL_NO_WG, f64, env, s64)
@@ -644,8 +644,8 @@ STF 11 ..... 100100 ..... . .............
@r_r_ri_na
STFSR 11 00000 100101 ..... . ............. @n_r_ri
STXFSR 11 00001 100101 ..... . ............. @n_r_ri
{
- STQF 11 ..... 100110 ..... . ............. @q_r_ri_na
- STDFQ 11 ----- 100110 ----- - -------------
+ STQF 11 ..... 100110 ..... . ............. @q_r_ri_na
## SPARC-V9
+ STDFQ 11 ..... 100110 ..... . ............. @r_r_r_asi
## SPARC-V7-8
}
STDF 11 ..... 100111 ..... . ............. @d_r_ri_na
@@ -22,6 +22,7 @@
#include "cpu.h"
#include "trace.h"
#include "exec/log.h"
+#include "exec/cpu_ldst.h"
#include "sysemu/runstate.h"
@@ -147,6 +148,18 @@ void sparc_cpu_do_interrupt(CPUState *cs)
env->psret = 0;
cwp = cpu_cwp_dec(env, env->cwp - 1);
cpu_set_cwp(env, cwp);
+ if (intno == TT_FP_EXCP) {
+ env->fsr_qne = FSR_QNE;
+ env->fsr_qa = env->pc;
+ env->fsr_qi = cpu_ldl_code(env, env->fsr_qa);
+ /*
+ * Because of the asynchronous FPU on real Sparc 32 bit
+ * machines, the pc and npc will have already been advanced
+ * by the time that the trap is taken.
+ */
+ env->pc = env->npc;
+ env->npc = env->npc + 4;
+ }
env->regwptr[9] = env->pc;
env->regwptr[10] = env->npc;
env->psrps = env->psrs;
@@ -41,6 +41,7 @@
# define gen_helper_rett(E) qemu_build_not_reached()
# define gen_helper_power_down(E) qemu_build_not_reached()
# define gen_helper_wrpsr(E, S) qemu_build_not_reached()
+# define gen_helper_store_fp_queue(E, A) qemu_build_not_reached()
#else
# define gen_helper_clear_softint(E, S) qemu_build_not_reached()
# define gen_helper_done(E) qemu_build_not_reached()
@@ -4521,13 +4522,13 @@ static bool do_st_fpr(DisasContext *dc,
arg_r_r_ri_asi *a, MemOp sz)
TRANS(STF, ALL, do_st_fpr, a, MO_32)
TRANS(STDF, ALL, do_st_fpr, a, MO_64)
-TRANS(STQF, ALL, do_st_fpr, a, MO_128)
+TRANS(STQF, 64, do_st_fpr, a, MO_128)
TRANS(STFA, 64, do_st_fpr, a, MO_32)
TRANS(STDFA, 64, do_st_fpr, a, MO_64)
TRANS(STQFA, 64, do_st_fpr, a, MO_128)
-static bool trans_STDFQ(DisasContext *dc, arg_STDFQ *a)
+static bool trans_STDFQ(DisasContext *dc, arg_r_r_ri_asi *a)
{
if (!avail_32(dc)) {