s390x/tcg: Handle SET FPC AND LOAD FPC 3-bit BFP rounding modes

We already forward the 3 bits correctly in the translation functions. We
also have to handle them properly and check for specification
exceptions.

Setting an invalid rounding mode (BFP only, all DFP rounding modes)
results in a specification exception. Setting unassigned bits in the
fpc, results in a specification exception.

This fixes LOAD FPC (AND SIGNAL), SET FPC (AND SIGNAL). Also for,
SET BFP ROUNDING MODE, 3-bit rounding mode is now explicitly checked.

Note: TCG_CALL_NO_WG is required for sfpc handler, as we now inject
exceptions.

We won't be modeling abscence of the "floating-point extension facility"
for now, not necessary as most take the facility for granted without
checking.

z14 PoP, 9-23, "LOAD FPC"
    When the floating-point extension facility is
    installed, bits 29-31 of the second operand must
    specify a valid BFP rounding mode and bits 6-7,
    14-15, 24, and 28 must be zero; otherwise, a
    specification exception is recognized.

Signed-off-by: David Hildenbrand <david@redhat.com>
Message-Id: <20190218122710.23639-9-david@redhat.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
This commit is contained in:
David Hildenbrand 2019-02-18 13:27:03 +01:00 committed by Cornelia Huck
parent 8772bbe4e7
commit 2aea83c672
2 changed files with 19 additions and 5 deletions

View File

@ -753,21 +753,30 @@ uint64_t HELPER(sqxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
return RET128(ret); return RET128(ret);
} }
static const int fpc_to_rnd[4] = { static const int fpc_to_rnd[8] = {
float_round_nearest_even, float_round_nearest_even,
float_round_to_zero, float_round_to_zero,
float_round_up, float_round_up,
float_round_down float_round_down,
-1,
-1,
-1,
float_round_to_odd,
}; };
/* set fpc */ /* set fpc */
void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc) void HELPER(sfpc)(CPUS390XState *env, uint64_t fpc)
{ {
if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u ||
(!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) {
s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, GETPC());
}
/* Install everything in the main FPC. */ /* Install everything in the main FPC. */
env->fpc = fpc; env->fpc = fpc;
/* Install the rounding mode in the shadow fpu_status. */ /* Install the rounding mode in the shadow fpu_status. */
set_float_rounding_mode(fpc_to_rnd[fpc & 3], &env->fpu_status); set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
} }
/* set fpc and signal */ /* set fpc and signal */
@ -776,12 +785,17 @@ void HELPER(sfas)(CPUS390XState *env, uint64_t fpc)
uint32_t signalling = env->fpc; uint32_t signalling = env->fpc;
uint32_t s390_exc; uint32_t s390_exc;
if (fpc_to_rnd[fpc & 0x7] == -1 || fpc & 0x03030088u ||
(!s390_has_feat(S390_FEAT_FLOATING_POINT_EXT) && fpc & 0x4)) {
s390_program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO, GETPC());
}
/* /*
* FPC is set to the FPC operand with a bitwise OR of the signalling * FPC is set to the FPC operand with a bitwise OR of the signalling
* flags. * flags.
*/ */
env->fpc = fpc | (signalling & 0x00ff0000); env->fpc = fpc | (signalling & 0x00ff0000);
set_float_rounding_mode(fpc_to_rnd[fpc & 3], &env->fpu_status); set_float_rounding_mode(fpc_to_rnd[fpc & 0x7], &env->fpu_status);
/* /*
* If any signaling flag is enabled in the new FPC mask, a * If any signaling flag is enabled in the new FPC mask, a

View File

@ -104,7 +104,7 @@ DEF_HELPER_4(trtr, i32, env, i32, i64, i64)
DEF_HELPER_5(trXX, i32, env, i32, i32, i32, i32) DEF_HELPER_5(trXX, i32, env, i32, i32, i32, i32)
DEF_HELPER_4(cksm, i64, env, i64, 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_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(sfpc, TCG_CALL_NO_WG, void, env, i64)
DEF_HELPER_FLAGS_2(sfas, TCG_CALL_NO_WG, 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) DEF_HELPER_FLAGS_1(popcnt, TCG_CALL_NO_RWG_SE, i64, i64)
DEF_HELPER_2(stfle, i32, env, i64) DEF_HELPER_2(stfle, i32, env, i64)