Patchwork [139/147] target-s390: Implement LOAD/SET FP AND SIGNAL

login
register
mail settings
Submitter Richard Henderson
Date Sept. 28, 2012, 1:16 a.m.
Message ID <1348794975-28703-1-git-send-email-rth@twiddle.net>
Download mbox | patch
Permalink /patch/187680/
State New
Headers show

Comments

Richard Henderson - Sept. 28, 2012, 1:16 a.m.
Signed-off-by: Richard Henderson <rth@twiddle.net>
---
 target-s390x/fpu_helper.c  | 37 +++++++++++++++++++++++++++++--------
 target-s390x/helper.h      |  1 +
 target-s390x/insn-data.def |  4 ++++
 target-s390x/translate.c   |  6 ++++++
 4 files changed, 40 insertions(+), 8 deletions(-)

Patch

diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c
index 899421e..edfcee1 100644
--- a/target-s390x/fpu_helper.c
+++ b/target-s390x/fpu_helper.c
@@ -674,19 +674,40 @@  uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
     return RET128(ret);
 }
 
+static const int fpc_to_rnd[4] = {
+    float_round_nearest_even,
+    float_round_to_zero,
+    float_round_up,
+    float_round_down
+};
+
 /* set fpc */
 void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc)
 {
-    static const int rnd[4] = {
-        float_round_nearest_even,
-        float_round_to_zero,
-        float_round_up,
-        float_round_down
-    };
-
     /* Install everything in the main FPC.  */
     env->fpc = fpc;
 
     /* Install the rounding mode in the shadow fpu_status.  */
-    set_float_rounding_mode(rnd[fpc & 3], &env->fpu_status);
+    set_float_rounding_mode(fpc_to_rnd[fpc & 3], &env->fpu_status);
+}
+
+/* set fpc and signal */
+void HELPER(sfas)(CPUS390XState *env, uint64_t val)
+{
+    uint32_t signalling = env->fpc;
+    uint32_t source = val;
+    uint32_t s390_exc;
+
+    /* The contents of the source operand are placed in the FPC register;
+       then the flags in the FPC register are set to the logical OR of the
+       signalling flags and the source flags.  */
+    env->fpc = source | (signalling & 0x00ff0000);
+    set_float_rounding_mode(fpc_to_rnd[source & 3], &env->fpu_status);
+
+    /* If any signalling flag is 1 and the corresponding source mask
+       is also 1, a simulated-iee-exception trap occurs.  */
+    s390_exc = (signalling >> 16) & (source >> 24);
+    if (s390_exc) {
+        ieee_exception(env, s390_exc | 3, GETPC());
+    }
 }
diff --git a/target-s390x/helper.h b/target-s390x/helper.h
index 03effd1..9df25ab 100644
--- a/target-s390x/helper.h
+++ b/target-s390x/helper.h
@@ -86,6 +86,7 @@  DEF_HELPER_4(unpk, void, env, i32, i64, i64)
 DEF_HELPER_4(tr, void, env, i32, i64, i64)
 DEF_HELPER_4(cksm, i64, env, i64, i64, i64)
 DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_CONST, void, env, i64)
+DEF_HELPER_FLAGS_2(sfas, TCG_CALL_CONST, void, env, i64)
 DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_PURE|TCG_CALL_CONST, i64, i64)
 
 DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_PURE|TCG_CALL_CONST,
diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def
index 79341a4..e915984 100644
--- a/target-s390x/insn-data.def
+++ b/target-s390x/insn-data.def
@@ -433,6 +433,8 @@ 
 
 /* LOAD FPC */
     C(0xb29d, LFPC,    S,     Z,   0, m2_32u, 0, 0, sfpc, 0)
+/* LOAD FPC AND SIGNAL */
+    C(0xb2bd, LFAS,    S,     IEEEE_SIM, 0, m2_32u, 0, 0, sfas, 0)
 
 /* LOAD LENGTHENED */
     C(0xb304, LDEBR,   RRE,   Z,   0, e2, f1, 0, ldeb, 0)
@@ -566,6 +568,8 @@ 
     C(0xb24e, SAR,     RRE,   Z,   0, r2_o, 0, 0, sar, 0)
 /* SET FPC */
     C(0xb384, SFPC,    RRE,   Z,   0, r1_o, 0, 0, sfpc, 0)
+/* SET FPC AND SIGNAL */
+    C(0xb385, SFASR,   RRE,   IEEEE_SIM, 0, r1_o, 0, 0, sfas, 0)
 /* SET BFP ROUNDING MODE */
     C(0xb299, SRNM,    S,     Z,   0, 0, 0, 0, srnm, 0)
     C(0xb2b8, SRNMB,   S,     FPE, 0, 0, 0, 0, srnm, 0)
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index 6cf2634..b945ba1 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -2921,6 +2921,12 @@  static ExitStatus op_sfpc(DisasContext *s, DisasOps *o)
     return NO_EXIT;
 }
 
+static ExitStatus op_sfas(DisasContext *s, DisasOps *o)
+{
+    gen_helper_sfas(cpu_env, o->in2);
+    return NO_EXIT;
+}
+
 static ExitStatus op_srnm(DisasContext *s, DisasOps *o)
 {
     int b2 = get_field(s->fields, b2);