summaryrefslogtreecommitdiff
path: root/target-s390x
diff options
context:
space:
mode:
authorRichard Henderson <rth@twiddle.net>2012-09-10 17:23:13 -0700
committerRichard Henderson <rth@twiddle.net>2013-01-05 12:18:45 -0800
commit411edc22cbab9a44f6d6c6cdef8637ba1f313e37 (patch)
treedc71292d311d9afd2efdc8e98e6b6694e28fa8d7 /target-s390x
parenta12000b9ece917f62d6405e7ee83c8abb6ad7afa (diff)
downloadqemu-411edc22cbab9a44f6d6c6cdef8637ba1f313e37.tar.gz
qemu-411edc22cbab9a44f6d6c6cdef8637ba1f313e37.tar.bz2
qemu-411edc22cbab9a44f6d6c6cdef8637ba1f313e37.zip
target-s390: Implement LOAD/SET FP AND SIGNAL
Signed-off-by: Richard Henderson <rth@twiddle.net>
Diffstat (limited to 'target-s390x')
-rw-r--r--target-s390x/fpu_helper.c37
-rw-r--r--target-s390x/helper.h1
-rw-r--r--target-s390x/insn-data.def4
-rw-r--r--target-s390x/translate.c6
4 files changed, 40 insertions, 8 deletions
diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c
index b6e5040ff5..94375b6a63 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 23d23d5b3a..b7376339cd 100644
--- a/target-s390x/helper.h
+++ b/target-s390x/helper.h
@@ -87,6 +87,7 @@ DEF_HELPER_4(tr, void, env, i32, i64, i64)
DEF_HELPER_4(cksm, i64, env, i64, i64, i64)
DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_NO_RWG_SE, i32, env, i32, i64, i64, i64)
DEF_HELPER_FLAGS_2(sfpc, TCG_CALL_NO_RWG, void, env, i64)
+DEF_HELPER_FLAGS_2(sfas, TCG_CALL_NO_WG, void, env, i64)
DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64)
#ifndef CONFIG_USER_ONLY
diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def
index 79341a4b41..e915984828 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 c4d9fffa21..34b9cdf127 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);