aboutsummaryrefslogtreecommitdiff
path: root/target-s390x
diff options
context:
space:
mode:
Diffstat (limited to 'target-s390x')
-rw-r--r--target-s390x/cc_helper.c4
-rw-r--r--target-s390x/cpu.c8
-rw-r--r--target-s390x/cpu.h39
-rw-r--r--target-s390x/fpu_helper.c43
-rw-r--r--target-s390x/helper.c2
-rw-r--r--target-s390x/helper.h9
-rw-r--r--target-s390x/insn-data.def91
-rw-r--r--target-s390x/int_helper.c42
-rw-r--r--target-s390x/mem_helper.c123
-rw-r--r--target-s390x/misc_helper.c34
-rw-r--r--target-s390x/mmu_helper.c2
-rw-r--r--target-s390x/translate.c360
12 files changed, 591 insertions, 166 deletions
diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c
index 00bc883a8a..bfce3f1e60 100644
--- a/target-s390x/cc_helper.c
+++ b/target-s390x/cc_helper.c
@@ -195,7 +195,7 @@ static uint32_t cc_calc_abs_64(int64_t dst)
if ((uint64_t)dst == 0x8000000000000000ULL) {
return 3;
} else if (dst) {
- return 1;
+ return 2;
} else {
return 0;
}
@@ -296,7 +296,7 @@ static uint32_t cc_calc_abs_32(int32_t dst)
if ((uint32_t)dst == 0x80000000UL) {
return 3;
} else if (dst) {
- return 1;
+ return 2;
} else {
return 0;
}
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index d2f9836e86..7f17823e40 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -118,6 +118,10 @@ static void s390_cpu_initial_reset(CPUState *s)
env->pfault_token = -1UL;
+ /* tininess for underflow is detected before rounding */
+ set_float_detect_tininess(float_tininess_before_rounding,
+ &env->fpu_status);
+
/* Reset state inside the kernel that we cannot access yet from QEMU. */
if (kvm_enabled()) {
kvm_s390_reset_vcpu(cpu);
@@ -143,6 +147,10 @@ static void s390_cpu_full_reset(CPUState *s)
env->pfault_token = -1UL;
+ /* tininess for underflow is detected before rounding */
+ set_float_detect_tininess(float_tininess_before_rounding,
+ &env->fpu_status);
+
/* Reset state inside the kernel that we cannot access yet from QEMU. */
if (kvm_enabled()) {
kvm_s390_reset_vcpu(cpu);
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index a71abaeef7..584e74b89a 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -48,7 +48,7 @@
#define MMU_MODE1_SUFFIX _secondary
#define MMU_MODE2_SUFFIX _home
-#define MMU_USER_IDX 1
+#define MMU_USER_IDX 0
#define MAX_EXT_QUEUE 16
#define MAX_IO_QUEUE 16
@@ -302,13 +302,39 @@ static inline CPU_DoubleU *get_freg(CPUS390XState *cs, int nr)
#define CR0_LOWPROT 0x0000000010000000ULL
#define CR0_EDAT 0x0000000000800000ULL
+/* MMU */
+#define MMU_PRIMARY_IDX 0
+#define MMU_SECONDARY_IDX 1
+#define MMU_HOME_IDX 2
+
static inline int cpu_mmu_index (CPUS390XState *env)
{
- if (env->psw.mask & PSW_MASK_PSTATE) {
- return 1;
+ switch (env->psw.mask & PSW_MASK_ASC) {
+ case PSW_ASC_PRIMARY:
+ return MMU_PRIMARY_IDX;
+ case PSW_ASC_SECONDARY:
+ return MMU_SECONDARY_IDX;
+ case PSW_ASC_HOME:
+ return MMU_HOME_IDX;
+ case PSW_ASC_ACCREG:
+ /* Fallthrough: access register mode is not yet supported */
+ default:
+ abort();
}
+}
- return 0;
+static inline uint64_t cpu_mmu_idx_to_asc(int mmu_idx)
+{
+ switch (mmu_idx) {
+ case MMU_PRIMARY_IDX:
+ return PSW_ASC_PRIMARY;
+ case MMU_SECONDARY_IDX:
+ return PSW_ASC_SECONDARY;
+ case MMU_HOME_IDX:
+ return PSW_ASC_HOME;
+ default:
+ abort();
+ }
}
static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc,
@@ -995,6 +1021,11 @@ static inline uint64_t time2tod(uint64_t ns) {
return (ns << 9) / 125;
}
+/* Converts s390's clock format to ns */
+static inline uint64_t tod2time(uint64_t t) {
+ return (t * 125) >> 9;
+}
+
static inline void cpu_inject_ext(S390CPU *cpu, uint32_t code, uint32_t param,
uint64_t param64)
{
diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c
index b946ec1d51..45b7ddfbe3 100644
--- a/target-s390x/fpu_helper.c
+++ b/target-s390x/fpu_helper.c
@@ -265,7 +265,7 @@ uint64_t HELPER(ldeb)(CPUS390XState *env, uint64_t f2)
{
float64 ret = float32_to_float64(f2, &env->fpu_status);
handle_exceptions(env, GETPC());
- return ret;
+ return float64_maybe_silence_nan(ret);
}
/* convert 128-bit float to 64-bit float */
@@ -273,7 +273,7 @@ uint64_t HELPER(ldxb)(CPUS390XState *env, uint64_t ah, uint64_t al)
{
float64 ret = float128_to_float64(make_float128(ah, al), &env->fpu_status);
handle_exceptions(env, GETPC());
- return ret;
+ return float64_maybe_silence_nan(ret);
}
/* convert 64-bit float to 128-bit float */
@@ -281,7 +281,7 @@ uint64_t HELPER(lxdb)(CPUS390XState *env, uint64_t f2)
{
float128 ret = float64_to_float128(f2, &env->fpu_status);
handle_exceptions(env, GETPC());
- return RET128(ret);
+ return RET128(float128_maybe_silence_nan(ret));
}
/* convert 32-bit float to 128-bit float */
@@ -289,7 +289,7 @@ uint64_t HELPER(lxeb)(CPUS390XState *env, uint64_t f2)
{
float128 ret = float32_to_float128(f2, &env->fpu_status);
handle_exceptions(env, GETPC());
- return RET128(ret);
+ return RET128(float128_maybe_silence_nan(ret));
}
/* convert 64-bit float to 32-bit float */
@@ -297,7 +297,7 @@ uint64_t HELPER(ledb)(CPUS390XState *env, uint64_t f2)
{
float32 ret = float64_to_float32(f2, &env->fpu_status);
handle_exceptions(env, GETPC());
- return ret;
+ return float32_maybe_silence_nan(ret);
}
/* convert 128-bit float to 32-bit float */
@@ -305,7 +305,7 @@ uint64_t HELPER(lexb)(CPUS390XState *env, uint64_t ah, uint64_t al)
{
float32 ret = float128_to_float32(make_float128(ah, al), &env->fpu_status);
handle_exceptions(env, GETPC());
- return ret;
+ return float32_maybe_silence_nan(ret);
}
/* 32-bit FP compare */
@@ -552,6 +552,37 @@ uint64_t HELPER(clfxb)(CPUS390XState *env, uint64_t h, uint64_t l, uint32_t m3)
return ret;
}
+/* round to integer 32-bit */
+uint64_t HELPER(fieb)(CPUS390XState *env, uint64_t f2, uint32_t m3)
+{
+ int hold = swap_round_mode(env, m3);
+ float32 ret = float32_round_to_int(f2, &env->fpu_status);
+ set_float_rounding_mode(hold, &env->fpu_status);
+ handle_exceptions(env, GETPC());
+ return ret;
+}
+
+/* round to integer 64-bit */
+uint64_t HELPER(fidb)(CPUS390XState *env, uint64_t f2, uint32_t m3)
+{
+ int hold = swap_round_mode(env, m3);
+ float64 ret = float64_round_to_int(f2, &env->fpu_status);
+ set_float_rounding_mode(hold, &env->fpu_status);
+ handle_exceptions(env, GETPC());
+ return ret;
+}
+
+/* round to integer 128-bit */
+uint64_t HELPER(fixb)(CPUS390XState *env, uint64_t ah, uint64_t al, uint32_t m3)
+{
+ int hold = swap_round_mode(env, m3);
+ float128 ret = float128_round_to_int(make_float128(ah, al),
+ &env->fpu_status);
+ set_float_rounding_mode(hold, &env->fpu_status);
+ handle_exceptions(env, GETPC());
+ return RET128(ret);
+}
+
/* 32-bit FP multiply and add */
uint64_t HELPER(maeb)(CPUS390XState *env, uint64_t f1,
uint64_t f2, uint64_t f3)
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index 6b47766494..90d273c098 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -112,7 +112,7 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr,
{
S390CPU *cpu = S390_CPU(cs);
CPUS390XState *env = &cpu->env;
- uint64_t asc = env->psw.mask & PSW_MASK_ASC;
+ uint64_t asc = cpu_mmu_idx_to_asc(mmu_idx);
target_ulong vaddr, raddr;
int prot;
diff --git a/target-s390x/helper.h b/target-s390x/helper.h
index 8d2c8596bb..7e048ecb00 100644
--- a/target-s390x/helper.h
+++ b/target-s390x/helper.h
@@ -15,10 +15,6 @@ DEF_HELPER_4(clst, i64, env, i64, i64, i64)
DEF_HELPER_4(mvpg, void, env, i64, i64, i64)
DEF_HELPER_4(mvst, i64, env, i64, i64, i64)
DEF_HELPER_5(ex, i32, env, i32, i64, i64, i64)
-DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_NO_RWG_SE, i32, s32)
-DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_NO_RWG_SE, s32, s32)
-DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_NO_RWG_SE, i64, s64)
-DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_NO_RWG_SE, s64, s64)
DEF_HELPER_FLAGS_4(stam, TCG_CALL_NO_WG, void, env, i32, i64, i32)
DEF_HELPER_FLAGS_4(lam, TCG_CALL_NO_WG, void, env, i32, i64, i32)
DEF_HELPER_4(mvcle, i32, env, i32, i64, i32)
@@ -64,6 +60,9 @@ DEF_HELPER_FLAGS_4(clgxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
DEF_HELPER_FLAGS_3(clfeb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_3(clfdb, TCG_CALL_NO_WG, i64, env, i64, i32)
DEF_HELPER_FLAGS_4(clfxb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
+DEF_HELPER_FLAGS_3(fieb, TCG_CALL_NO_WG, i64, env, i64, i32)
+DEF_HELPER_FLAGS_3(fidb, TCG_CALL_NO_WG, i64, env, i64, i32)
+DEF_HELPER_FLAGS_4(fixb, TCG_CALL_NO_WG, i64, env, i64, i64, i32)
DEF_HELPER_FLAGS_4(maeb, TCG_CALL_NO_WG, i64, env, i64, i64, i64)
DEF_HELPER_FLAGS_4(madb, TCG_CALL_NO_WG, i64, env, i64, i64, i64)
DEF_HELPER_FLAGS_4(mseb, TCG_CALL_NO_WG, i64, env, i64, i64, i64)
@@ -78,6 +77,8 @@ DEF_HELPER_FLAGS_3(sqxb, TCG_CALL_NO_WG, i64, env, i64, i64)
DEF_HELPER_FLAGS_1(cvd, TCG_CALL_NO_RWG_SE, i64, s32)
DEF_HELPER_FLAGS_4(unpk, TCG_CALL_NO_WG, void, env, i32, i64, i64)
DEF_HELPER_FLAGS_4(tr, TCG_CALL_NO_WG, void, env, i32, i64, i64)
+DEF_HELPER_4(tre, i64, env, i64, i64, i64)
+DEF_HELPER_4(trt, i32, 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)
diff --git a/target-s390x/insn-data.def b/target-s390x/insn-data.def
index 72c3a2edda..1223670721 100644
--- a/target-s390x/insn-data.def
+++ b/target-s390x/insn-data.def
@@ -34,6 +34,9 @@
C(0xb34a, AXBR, RRE, Z, 0, x2_o, x1, 0, axb, f128)
C(0xed0a, AEB, RXE, Z, e1, m2_32u, new, e1, aeb, f32)
C(0xed1a, ADB, RXE, Z, f1_o, m2_64, f1, 0, adb, f64)
+/* ADD HIGH */
+ C(0xb9c8, AHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, add, adds32)
+ C(0xb9d8, AHHLR, RRF_a, HW, r2_sr32, r3, new, r1_32h, add, adds32)
/* ADD IMMEDIATE */
C(0xc209, AFI, RIL_a, EI, r1, i2, new, r1_32, add, adds32)
C(0xeb6a, ASI, SIY, GIE, m1_32s, i2, new, m1_32, add, adds32)
@@ -41,6 +44,8 @@
C(0xc208, AGFI, RIL_a, EI, r1, i2, r1, 0, add, adds64)
C(0xeb7a, AGSI, SIY, GIE, m1_64, i2, new, m1_64, add, adds64)
C(0xecd9, AGHIK, RIE_d, DO, r3, i2, r1, 0, add, adds64)
+/* ADD IMMEDIATE HIGH */
+ C(0xcc08, AIH, RIL_a, HW, r1_sr32, i2, new, r1_32h, add, adds32)
/* ADD HALFWORD */
C(0x4a00, AH, RX_a, Z, r1, m2_16s, new, r1_32, add, adds32)
C(0xe37a, AHY, RXY_a, LD, r1, m2_16s, new, r1_32, add, adds32)
@@ -58,6 +63,9 @@
C(0xb9ea, ALGRK, RRF_a, DO, r2, r3, r1, 0, add, addu64)
C(0xe30a, ALG, RXY_a, Z, r1, m2_64, r1, 0, add, addu64)
C(0xe31a, ALGF, RXY_a, Z, r1, m2_32u, r1, 0, add, addu64)
+/* ADD LOGICAL HIGH */
+ C(0xb9ca, ALHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, add, addu32)
+ C(0xb9da, ALHHLR, RRF_a, HW, r2_sr32, r3, new, r1_32h, add, addu32)
/* ADD LOGICAL IMMEDIATE */
C(0xc20b, ALFI, RIL_a, EI, r1, i2_32u, new, r1_32, add, addu32)
C(0xc20a, ALGFI, RIL_a, EI, r1, i2_32u, r1, 0, add, addu64)
@@ -66,6 +74,9 @@
C(0xecda, ALHSIK, RIE_d, DO, r3, i2, new, r1_32, add, addu32)
C(0xeb7e, ALGSI, SIY, GIE, m1_64, i2, new, m1_64, add, addu64)
C(0xecdb, ALGHSIK, RIE_d, DO, r3, i2, r1, 0, add, addu64)
+/* ADD LOGICAL WITH SIGNED IMMEDIATE HIGH */
+ C(0xcc0a, ALSIH, RIL_a, HW, r1_sr32, i2, new, r1_32h, add, addu32)
+ C(0xcc0b, ALSIHN, RIL_a, HW, r1_sr32, i2, new, r1_32h, add, 0)
/* ADD LOGICAL WITH CARRY */
C(0xb998, ALCR, RRE, Z, r1, r2, new, r1_32, addc, addc32)
C(0xb988, ALCGR, RRE, Z, r1, r2, r1, 0, addc, addc64)
@@ -111,6 +122,8 @@
/* BRANCH RELATIVE ON COUNT */
C(0xa706, BRCT, RI_b, Z, 0, 0, 0, 0, bct32, 0)
C(0xa707, BRCTG, RI_b, Z, 0, 0, 0, 0, bct64, 0)
+/* BRANCH RELATIVE ON COUNT HIGH */
+ C(0xcc06, BRCTH, RIL_b, HW, 0, 0, 0, 0, bcth, 0)
/* BRANCH ON INDEX */
D(0x8600, BXH, RS_a, Z, 0, a2, 0, 0, bx32, 0, 0)
D(0x8700, BXLE, RS_a, Z, 0, a2, 0, 0, bx32, 0, 1)
@@ -159,8 +172,14 @@
C(0xe55c, CHSI, SIL, GIE, m1_32s, i2, 0, 0, 0, cmps64)
C(0xe558, CGHSI, SIL, GIE, m1_64, i2, 0, 0, 0, cmps64)
/* COMPARE HALFWORD RELATIVE LONG */
- C(0xc605, CHRL, RIL_a, GIE, r1_o, mri2_32s, 0, 0, 0, cmps32)
- C(0xc604, CGHRL, RIL_a, GIE, r1_o, mri2_64, 0, 0, 0, cmps64)
+ C(0xc605, CHRL, RIL_b, GIE, r1_o, mri2_32s, 0, 0, 0, cmps32)
+ C(0xc604, CGHRL, RIL_b, GIE, r1_o, mri2_64, 0, 0, 0, cmps64)
+/* COMPARE HIGH */
+ C(0xb9cd, CHHR, RRE, HW, r1_sr32, r2_sr32, 0, 0, 0, cmps32)
+ C(0xb9dd, CHLR, RRE, HW, r1_sr32, r2_o, 0, 0, 0, cmps32)
+ C(0xe3cd, CHF, RXY_a, HW, r1_sr32, m2_32s, 0, 0, 0, cmps32)
+/* COMPARE IMMEDIATE HIGH */
+ C(0xcc0d, CIH, RIL_a, HW, r1_sr32, i2, 0, 0, 0, cmps32)
/* COMPARE LOGICAL */
C(0x1500, CLR, RR_a, Z, r1, r2, 0, 0, 0, cmpu32)
@@ -171,6 +190,10 @@
C(0xe321, CLG, RXY_a, Z, r1, m2_64, 0, 0, 0, cmpu64)
C(0xe331, CLGF, RXY_a, Z, r1, m2_32u, 0, 0, 0, cmpu64)
C(0xd500, CLC, SS_a, Z, la1, a2, 0, 0, clc, 0)
+/* COMPARE LOGICAL HIGH */
+ C(0xb9cf, CLHHR, RRE, HW, r1_sr32, r2_sr32, 0, 0, 0, cmpu32)
+ C(0xb9df, CLHLR, RRE, HW, r1_sr32, r2_o, 0, 0, 0, cmpu32)
+ C(0xe3cf, CLHF, RXY_a, HW, r1_sr32, m2_32s, 0, 0, 0, cmpu32)
/* COMPARE LOGICAL IMMEDIATE */
C(0xc20f, CLFI, RIL_a, EI, r1, i2, 0, 0, 0, cmpu32)
C(0xc20e, CLGFI, RIL_a, EI, r1, i2_32u, 0, 0, 0, cmpu64)
@@ -179,6 +202,8 @@
C(0xe555, CLHHSI, SIL, GIE, m1_16u, i2_16u, 0, 0, 0, cmpu64)
C(0xe55d, CLFHSI, SIL, GIE, m1_32u, i2_16u, 0, 0, 0, cmpu64)
C(0xe559, CLGHSI, SIL, GIE, m1_64, i2_16u, 0, 0, 0, cmpu64)
+/* COMPARE LOGICAL IMMEDIATE HIGH */
+ C(0xcc0f, CLIH, RIL_a, HW, r1_sr32, i2, 0, 0, 0, cmpu32)
/* COMPARE LOGICAL RELATIVE LONG */
C(0xc60f, CLRL, RIL_b, GIE, r1_o, mri2_32u, 0, 0, 0, cmpu32)
C(0xc60a, CLGRL, RIL_b, GIE, r1_o, mri2_64, 0, 0, 0, cmpu64)
@@ -230,8 +255,10 @@
/* COMPARE LOGICAL AND TRAP */
D(0xb973, CLRT, RRF_c, GIE, r1_32u, r2_32u, 0, 0, ct, 0, 1)
D(0xb961, CLGRT, RRF_c, GIE, r1_o, r2_o, 0, 0, ct, 0, 1)
+ D(0xeb23, CLT, RSY_b, MIE, r1_32u, m2_32u, 0, 0, ct, 0, 1)
+ D(0xeb2b, CLGT, RSY_b, MIE, r1_o, m2_64, 0, 0, ct, 0, 1)
D(0xec73, CLFIT, RIE_a, GIE, r1_32u, i2_32u, 0, 0, ct, 0, 1)
- D(0xec71, CLGIT, RIE_a, GIE, r1_o, i2_32u, 0, 0, ct, 0, 0)
+ D(0xec71, CLGIT, RIE_a, GIE, r1_o, i2_32u, 0, 0, ct, 0, 1)
/* CONVERT TO DECIMAL */
C(0x4e00, CVD, RX_a, Z, r1_o, a2, 0, 0, cvd, 0)
@@ -336,7 +363,7 @@
/* LOAD */
C(0x1800, LR, RR_a, Z, 0, r2_o, 0, cond_r1r2_32, mov2, 0)
C(0x5800, L, RX_a, Z, 0, a2, new, r1_32, ld32s, 0)
- C(0xe358, LY, RXY_a, Z, 0, a2, new, r1_32, ld32s, 0)
+ C(0xe358, LY, RXY_a, LD, 0, a2, new, r1_32, ld32s, 0)
C(0xb904, LGR, RRE, Z, 0, r2_o, 0, r1, mov2, 0)
C(0xb914, LGFR, RRE, Z, 0, r2_32s, 0, r1, mov2, 0)
C(0xe304, LG, RXY_a, Z, 0, a2, r1, 0, ld64, 0)
@@ -357,6 +384,9 @@
/* LOAD ADDRESS */
C(0x4100, LA, RX_a, Z, 0, a2, 0, r1, mov2, 0)
C(0xe371, LAY, RXY_a, LD, 0, a2, 0, r1, mov2, 0)
+/* LOAD ADDRESS EXTENDED */
+ C(0x5100, LAE, RX_a, Z, 0, a2, 0, r1, mov2e, 0)
+ C(0xe375, LAEY, RXY_a, GIE, 0, a2, 0, r1, mov2e, 0)
/* LOAD ADDRESS RELATIVE LONG */
C(0xc000, LARL, RIL_b, Z, 0, ri2, 0, r1, mov2, 0)
/* LOAD AND ADD */
@@ -384,11 +414,16 @@
C(0xb302, LTEBR, RRE, Z, 0, e2, 0, cond_e1e2, mov2, f32)
C(0xb312, LTDBR, RRE, Z, 0, f2_o, 0, f1, mov2, f64)
C(0xb342, LTXBR, RRE, Z, 0, x2_o, 0, x1, movx, f128)
+/* LOAD AND TRAP */
+ C(0xe39f, LAT, RXY_a, LAT, 0, m2_32u, r1, 0, lat, 0)
+ C(0xe385, LGAT, RXY_a, LAT, 0, a2, r1, 0, lgat, 0)
/* LOAD BYTE */
C(0xb926, LBR, RRE, EI, 0, r2_8s, 0, r1_32, mov2, 0)
C(0xb906, LGBR, RRE, EI, 0, r2_8s, 0, r1, mov2, 0)
C(0xe376, LB, RXY_a, LD, 0, a2, new, r1_32, ld8s, 0)
C(0xe377, LGB, RXY_a, LD, 0, a2, r1, 0, ld8s, 0)
+/* LOAD BYTE HIGH */
+ C(0xe3c0, LBH, RXY_a, HW, 0, a2, new, r1_32h, ld8s, 0)
/* LOAD COMPLEMENT */
C(0x1300, LCR, RR_a, Z, 0, r2, new, r1_32, neg, neg32)
C(0xb903, LCGR, RRE, Z, 0, r2, r1, 0, neg, neg64)
@@ -403,15 +438,23 @@
C(0x4800, LH, RX_a, Z, 0, a2, new, r1_32, ld16s, 0)
C(0xe378, LHY, RXY_a, LD, 0, a2, new, r1_32, ld16s, 0)
C(0xe315, LGH, RXY_a, Z, 0, a2, r1, 0, ld16s, 0)
+/* LOAD HALFWORD HIGH */
+ C(0xe3c4, LHH, RXY_a, HW, 0, a2, new, r1_32h, ld16s, 0)
/* LOAD HALFWORD IMMEDIATE */
C(0xa708, LHI, RI_a, Z, 0, i2, 0, r1_32, mov2, 0)
C(0xa709, LGHI, RI_a, Z, 0, i2, 0, r1, mov2, 0)
/* LOAD HALFWORD RELATIVE LONG */
C(0xc405, LHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16s, 0)
C(0xc404, LGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16s, 0)
+/* LOAD HIGH */
+ C(0xe3ca, LFH, RXY_a, HW, 0, a2, new, r1_32h, ld32u, 0)
+/* LOAG HIGH AND TRAP */
+ C(0xe3c8, LFHAT, RXY_a, LAT, 0, m2_32u, r1, 0, lfhat, 0)
/* LOAD LOGICAL */
C(0xb916, LLGFR, RRE, Z, 0, r2_32u, 0, r1, mov2, 0)
C(0xe316, LLGF, RXY_a, Z, 0, a2, r1, 0, ld32u, 0)
+/* LOAD LOGICAL AND TRAP */
+ C(0xe39d, LLGFAT, RXY_a, LAT, 0, a2, r1, 0, llgfat, 0)
/* LOAD LOGICAL RELATIVE LONG */
C(0xc40e, LLGFRL, RIL_b, GIE, 0, ri2, r1, 0, ld32u, 0)
/* LOAD LOGICAL CHARACTER */
@@ -419,11 +462,15 @@
C(0xb984, LLGCR, RRE, EI, 0, r2_8u, 0, r1, mov2, 0)
C(0xe394, LLC, RXY_a, EI, 0, a2, new, r1_32, ld8u, 0)
C(0xe390, LLGC, RXY_a, Z, 0, a2, r1, 0, ld8u, 0)
+/* LOAD LOGICAL CHARACTER HIGH */
+ C(0xe3c2, LLCH, RXY_a, HW, 0, a2, new, r1_32h, ld8u, 0)
/* LOAD LOGICAL HALFWORD */
C(0xb995, LLHR, RRE, EI, 0, r2_16u, 0, r1_32, mov2, 0)
C(0xb985, LLGHR, RRE, EI, 0, r2_16u, 0, r1, mov2, 0)
C(0xe395, LLH, RXY_a, EI, 0, a2, new, r1_32, ld16u, 0)
C(0xe391, LLGH, RXY_a, Z, 0, a2, r1, 0, ld16u, 0)
+/* LOAD LOGICAL HALFWORD HIGH */
+ C(0xe3c6, LLHH, RXY_a, HW, 0, a2, new, r1_32h, ld16u, 0)
/* LOAD LOGICAL HALFWORD RELATIVE LONG */
C(0xc402, LLHRL, RIL_b, GIE, 0, ri2, new, r1_32, ld16u, 0)
C(0xc406, LLGHRL, RIL_b, GIE, 0, ri2, r1, 0, ld16u, 0)
@@ -437,6 +484,9 @@
/* LOAD LOGICAL THIRTY ONE BITS */
C(0xb917, LLGTR, RRE, Z, 0, r2_o, r1, 0, llgt, 0)
C(0xe317, LLGT, RXY_a, Z, 0, m2_32u, r1, 0, llgt, 0)
+/* LOAD LOGICAL THIRTY ONE BITS AND TRAP */
+ C(0xe39c, LLGTAT, RXY_a, LAT, 0, m2_32u, r1, 0, llgtat, 0)
+
/* LOAD FPR FROM GR */
C(0xb3c1, LDGR, RRE, FPRGR, 0, r2_o, 0, f1, mov2, 0)
/* LOAD GR FROM FPR */
@@ -448,6 +498,7 @@
C(0xb301, LNEBR, RRE, Z, 0, e2, new, e1, nabsf32, f32)
C(0xb311, LNDBR, RRE, Z, 0, f2_o, f1, 0, nabsf64, f64)
C(0xb341, LNXBR, RRE, Z, 0, x2_o, x1, 0, nabsf128, f128)
+ C(0xb371, LNDFR, RRE, FPSSH, 0, f2_o, f1, 0, nabsf64, 0)
/* LOAD ON CONDITION */
C(0xb9f2, LOCR, RRF_c, LOC, r1, r2, new, r1_32, loc, 0)
C(0xb9e2, LOCGR, RRF_c, LOC, r1, r2, r1, 0, loc, 0)
@@ -461,6 +512,7 @@
C(0xb300, LPEBR, RRE, Z, 0, e2, new, e1, absf32, f32)
C(0xb310, LPDBR, RRE, Z, 0, f2_o, f1, 0, absf64, f64)
C(0xb340, LPXBR, RRE, Z, 0, x2_o, x1, 0, absf128, f128)
+ C(0xb370, LPDFR, RRE, FPSSH, 0, f2_o, f1, 0, absf64, 0)
/* LOAD REVERSED */
C(0xb91f, LRVR, RRE, Z, 0, r2_32u, new, r1_32, rev32, 0)
C(0xb90f, LRVGR, RRE, Z, 0, r2_o, r1, 0, rev64, 0)
@@ -476,6 +528,10 @@
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 FP INTEGER */
+ C(0xb357, FIEBR, RRF_e, Z, 0, e2, new, e1, fieb, 0)
+ C(0xb35f, FIDBR, RRF_e, Z, 0, f2_o, f1, 0, fidb, 0)
+ C(0xb347, FIXBR, RRF_e, Z, 0, x2_o, x1, 0, fixb, 0)
/* LOAD LENGTHENED */
C(0xb304, LDEBR, RRE, Z, 0, e2, f1, 0, ldeb, 0)
@@ -595,8 +651,9 @@
/* ROTATE THEN INSERT SELECTED BITS */
C(0xec55, RISBG, RIE_f, GIE, 0, r2, r1, 0, risbg, s64)
- C(0xec5d, RISBHG, RIE_f, GIE, 0, r2, r1, 0, risbg, 0)
- C(0xec51, RISBLG, RIE_f, GIE, 0, r2, r1, 0, risbg, 0)
+ C(0xec59, RISBGN, RIE_f, MIE, 0, r2, r1, 0, risbg, 0)
+ C(0xec5d, RISBHG, RIE_f, HW, 0, r2, r1, 0, risbg, 0)
+ C(0xec51, RISBLG, RIE_f, HW, 0, r2, r1, 0, risbg, 0)
/* ROTATE_THEN <OP> SELECTED BITS */
C(0xec54, RNSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0)
C(0xec56, ROSBG, RIE_f, GIE, 0, r2, r1, 0, rosbg, 0)
@@ -619,7 +676,7 @@
C(0xb299, SRNM, S, Z, 0, 0, 0, 0, srnm, 0)
C(0xb2b8, SRNMB, S, FPE, 0, 0, 0, 0, srnm, 0)
/* SET DFP ROUNDING MODE */
- C(0xb2b9, SRNMT, S, DFP, 0, 0, 0, 0, srnm, 0)
+ C(0xb2b9, SRNMT, S, DFPR, 0, 0, 0, 0, srnm, 0)
/* SHIFT LEFT SINGLE */
D(0x8b00, SLA, RS_a, Z, r1, sh32, new, r1_32, sla, 0, 31)
@@ -667,15 +724,21 @@
/* STORE CHARACTER */
C(0x4200, STC, RX_a, Z, r1_o, a2, 0, 0, st8, 0)
C(0xe372, STCY, RXY_a, LD, r1_o, a2, 0, 0, st8, 0)
+/* STORE CHARACTER HIGH */
+ C(0xe3c3, STCH, RXY_a, HW, r1_sr32, a2, 0, 0, st8, 0)
/* STORE CHARACTERS UNDER MASK */
D(0xbe00, STCM, RS_b, Z, r1_o, a2, 0, 0, stcm, 0, 0)
D(0xeb2d, STCMY, RSY_b, LD, r1_o, a2, 0, 0, stcm, 0, 0)
- D(0xeb2c, STCMH, RSY_b, LD, r1_o, a2, 0, 0, stcm, 0, 32)
+ D(0xeb2c, STCMH, RSY_b, Z, r1_o, a2, 0, 0, stcm, 0, 32)
/* STORE HALFWORD */
C(0x4000, STH, RX_a, Z, r1_o, a2, 0, 0, st16, 0)
C(0xe370, STHY, RXY_a, LD, r1_o, a2, 0, 0, st16, 0)
+/* STORE HALFWORD HIGH */
+ C(0xe3c7, STHH, RXY_a, HW, r1_sr32, a2, 0, 0, st16, 0)
/* STORE HALFWORD RELATIVE LONG */
C(0xc407, STHRL, RIL_b, GIE, r1_o, ri2, 0, 0, st16, 0)
+/* STORE HIGH */
+ C(0xe3cb, STFH, RXY_a, HW, r1_sr32, a2, 0, 0, st32, 0)
/* STORE ON CONDITION */
D(0xebf3, STOC, RSY_b, LOC, 0, 0, 0, 0, soc, 0, 0)
D(0xebe3, STOCG, RSY_b, LOC, 0, 0, 0, 0, soc, 0, 1)
@@ -715,6 +778,9 @@
/* SUBTRACT HALFWORD */
C(0x4b00, SH, RX_a, Z, r1, m2_16s, new, r1_32, sub, subs32)
C(0xe37b, SHY, RXY_a, LD, r1, m2_16s, new, r1_32, sub, subs32)
+/* SUBTRACT HIGH */
+ C(0xb9c9, SHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, sub, subs32)
+ C(0xb9d9, SHHLR, RRF_a, HW, r2_sr32, r3, new, r1_32h, sub, subs32)
/* SUBTRACT LOGICAL */
C(0x1f00, SLR, RR_a, Z, r1, r2, new, r1_32, sub, subu32)
C(0xb9fb, SLRK, RRF_a, DO, r2, r3, new, r1_32, sub, subu32)
@@ -725,6 +791,9 @@
C(0xb9eb, SLGRK, RRF_a, DO, r2, r3, r1, 0, sub, subu64)
C(0xe30b, SLG, RXY_a, Z, r1, m2_64, r1, 0, sub, subu64)
C(0xe31b, SLGF, RXY_a, Z, r1, m2_32u, r1, 0, sub, subu64)
+/* SUBTRACT LOCICAL HIGH */
+ C(0xb9cb, SLHHHR, RRF_a, HW, r2_sr32, r3_sr32, new, r1_32h, sub, subu32)
+ C(0xb9db, SLHHLR, RRF_a, HW, r2_sr32, r3, new, r1_32h, sub, subu32)
/* SUBTRACT LOGICAL IMMEDIATE */
C(0xc205, SLFI, RIL_a, EI, r1, i2_32u, new, r1_32, sub, subu32)
C(0xc204, SLGFI, RIL_a, EI, r1, i2_32u, r1, 0, sub, subu64)
@@ -752,6 +821,10 @@
/* TRANSLATE */
C(0xdc00, TR, SS_a, Z, la1, a2, 0, 0, tr, 0)
+/* TRANSLATE AND TEST */
+ C(0xdd00, TRT, SS_a, Z, la1, a2, 0, 0, trt, 0)
+/* TRANSLATE EXTENDED */
+ C(0xb2a5, TRE, RRE, Z, 0, r2, r1_P, 0, tre, 0)
/* UNPACK */
/* Really format SS_b, but we pack both lengths into one argument
@@ -812,7 +885,7 @@
C(0xae00, SIGP, RS_a, Z, r3_o, a2, 0, 0, sigp, 0)
/* STORE CLOCK */
C(0xb205, STCK, S, Z, la2, 0, new, m1_64, stck, 0)
- C(0xb27c, STCKF, S, Z, la2, 0, new, m1_64, stck, 0)
+ C(0xb27c, STCKF, S, SCF, la2, 0, new, m1_64, stck, 0)
/* STORE CLOCK EXTENDED */
C(0xb278, STCKE, S, Z, 0, a2, 0, 0, stcke, 0)
/* STORE CLOCK COMPARATOR */
diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c
index cb8dd98542..2c2b3f622c 100644
--- a/target-s390x/int_helper.c
+++ b/target-s390x/int_helper.c
@@ -115,48 +115,6 @@ uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al,
return ret;
}
-/* absolute value 32-bit */
-uint32_t HELPER(abs_i32)(int32_t val)
-{
- if (val < 0) {
- return -val;
- } else {
- return val;
- }
-}
-
-/* negative absolute value 32-bit */
-int32_t HELPER(nabs_i32)(int32_t val)
-{
- if (val < 0) {
- return val;
- } else {
- return -val;
- }
-}
-
-/* absolute value 64-bit */
-uint64_t HELPER(abs_i64)(int64_t val)
-{
- HELPER_LOG("%s: val 0x%" PRIx64 "\n", __func__, val);
-
- if (val < 0) {
- return -val;
- } else {
- return val;
- }
-}
-
-/* negative absolute value 64-bit */
-int64_t HELPER(nabs_i64)(int64_t val)
-{
- if (val < 0) {
- return val;
- } else {
- return -val;
- }
-}
-
/* count leading zeros, for find leftmost one */
uint64_t HELPER(clz)(uint64_t v)
{
diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c
index 0e8cd0f489..b4e5d44011 100644
--- a/target-s390x/mem_helper.c
+++ b/target-s390x/mem_helper.c
@@ -213,21 +213,22 @@ void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src)
if (dest == (src + 1)) {
memset(g2h(dest), cpu_ldub_data(env, src), l + 1);
return;
- } else {
+ /* mvc and memmove do not behave the same when areas overlap! */
+ } else if ((dest < src) || (src + l < dest)) {
memmove(g2h(dest), g2h(src), l + 1);
return;
}
#endif
/* handle the parts that fit into 8-byte loads/stores */
- if (dest != (src + 1)) {
+ if ((dest + 8 <= src) || (src + 8 <= dest)) {
for (i = 0; i < l_64; i++) {
cpu_stq_data(env, dest + x, cpu_ldq_data(env, src + x));
x += 8;
}
}
- /* slow version crossing pages with byte accesses */
+ /* slow version with byte accesses which always work */
for (i = x; i <= l; i++) {
cpu_stb_data(env, dest + i, cpu_ldub_data(env, src + i));
}
@@ -509,6 +510,9 @@ uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1,
case 0xc00:
helper_tr(env, l, get_address(env, 0, b1, d1),
get_address(env, 0, b2, d2));
+ case 0xd00:
+ cc = helper_trt(env, l, get_address(env, 0, b1, d1),
+ get_address(env, 0, b2, d2));
break;
default:
goto abort;
@@ -801,6 +805,66 @@ void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array,
}
}
+uint64_t HELPER(tre)(CPUS390XState *env, uint64_t array,
+ uint64_t len, uint64_t trans)
+{
+ uint8_t end = env->regs[0] & 0xff;
+ uint64_t l = len;
+ uint64_t i;
+
+ if (!(env->psw.mask & PSW_MASK_64)) {
+ array &= 0x7fffffff;
+ l = (uint32_t)l;
+ }
+
+ /* Lest we fail to service interrupts in a timely manner, limit the
+ amount of work we're willing to do. For now, let's cap at 8k. */
+ if (l > 0x2000) {
+ l = 0x2000;
+ env->cc_op = 3;
+ } else {
+ env->cc_op = 0;
+ }
+
+ for (i = 0; i < l; i++) {
+ uint8_t byte, new_byte;
+
+ byte = cpu_ldub_data(env, array + i);
+
+ if (byte == end) {
+ env->cc_op = 1;
+ break;
+ }
+
+ new_byte = cpu_ldub_data(env, trans + byte);
+ cpu_stb_data(env, array + i, new_byte);
+ }
+
+ env->retxl = len - i;
+ return array + i;
+}
+
+uint32_t HELPER(trt)(CPUS390XState *env, uint32_t len, uint64_t array,
+ uint64_t trans)
+{
+ uint32_t cc = 0;
+ int i;
+
+ for (i = 0; i <= len; i++) {
+ uint8_t byte = cpu_ldub_data(env, array + i);
+ uint8_t sbyte = cpu_ldub_data(env, trans + byte);
+
+ if (sbyte != 0) {
+ env->regs[1] = array + i;
+ env->regs[2] = (env->regs[2] & ~0xff) | sbyte;
+ cc = (i == len) ? 2 : 1;
+ break;
+ }
+ }
+
+ return cc;
+}
+
#if !defined(CONFIG_USER_ONLY)
void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
{
@@ -952,59 +1016,46 @@ uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint64_t r2)
return cc;
}
-static uint32_t mvc_asc(CPUS390XState *env, int64_t l, uint64_t a1,
- uint64_t mode1, uint64_t a2, uint64_t mode2)
+uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
{
- CPUState *cs = CPU(s390_env_get_cpu(env));
- target_ulong src, dest;
- int flags, cc = 0, i;
+ int cc = 0, i;
- if (!l) {
- return 0;
- } else if (l > 256) {
+ HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
+ __func__, l, a1, a2);
+
+ if (l > 256) {
/* max 256 */
l = 256;
cc = 3;
}
- if (mmu_translate(env, a1, 1, mode1, &dest, &flags, true)) {
- cpu_loop_exit(CPU(s390_env_get_cpu(env)));
- }
- dest |= a1 & ~TARGET_PAGE_MASK;
-
- if (mmu_translate(env, a2, 0, mode2, &src, &flags, true)) {
- cpu_loop_exit(CPU(s390_env_get_cpu(env)));
- }
- src |= a2 & ~TARGET_PAGE_MASK;
-
/* XXX replace w/ memcpy */
for (i = 0; i < l; i++) {
- /* XXX be more clever */
- if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) ||
- (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) {
- mvc_asc(env, l - i, a1 + i, mode1, a2 + i, mode2);
- break;
- }
- stb_phys(cs->as, dest + i, ldub_phys(cs->as, src + i));
+ cpu_stb_secondary(env, a1 + i, cpu_ldub_primary(env, a2 + i));
}
return cc;
}
-uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
+uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
{
+ int cc = 0, i;
+
HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
__func__, l, a1, a2);
- return mvc_asc(env, l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY);
-}
+ if (l > 256) {
+ /* max 256 */
+ l = 256;
+ cc = 3;
+ }
-uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2)
-{
- HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n",
- __func__, l, a1, a2);
+ /* XXX replace w/ memcpy */
+ for (i = 0; i < l; i++) {
+ cpu_stb_primary(env, a1 + i, cpu_ldub_secondary(env, a2 + i));
+ }
- return mvc_asc(env, l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY);
+ return cc;
}
/* invalidate pte */
diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c
index e1007fa35b..b375ab724b 100644
--- a/target-s390x/misc_helper.c
+++ b/target-s390x/misc_helper.c
@@ -61,7 +61,7 @@ void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp,
/* Advance past the insn. */
t = cpu_ldub_code(env, env->psw.addr);
env->int_pgm_ilen = t = get_ilen(t);
- env->psw.addr += 2 * t;
+ env->psw.addr += t;
cpu_loop_exit(cs);
}
@@ -268,7 +268,8 @@ void HELPER(spx)(CPUS390XState *env, uint64_t a1)
tlb_flush_page(cs, TARGET_PAGE_SIZE);
}
-static inline uint64_t clock_value(CPUS390XState *env)
+/* Store Clock */
+uint64_t HELPER(stck)(CPUS390XState *env)
{
uint64_t time;
@@ -278,12 +279,6 @@ static inline uint64_t clock_value(CPUS390XState *env)
return time;
}
-/* Store Clock */
-uint64_t HELPER(stck)(CPUS390XState *env)
-{
- return clock_value(env);
-}
-
/* Set Clock Comparator */
void HELPER(sckc)(CPUS390XState *env, uint64_t time)
{
@@ -291,19 +286,21 @@ void HELPER(sckc)(CPUS390XState *env, uint64_t time)
return;
}
- /* difference between now and then */
- time -= clock_value(env);
+ env->ckc = time;
+
+ /* difference between origins */
+ time -= env->tod_offset;
+
/* nanoseconds */
- time = (time * 125) >> 9;
+ time = tod2time(time);
- timer_mod(env->tod_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time);
+ timer_mod(env->tod_timer, env->tod_basetime + time);
}
/* Store Clock Comparator */
uint64_t HELPER(stckc)(CPUS390XState *env)
{
- /* XXX implement */
- return 0;
+ return env->ckc;
}
/* Set CPU Timer */
@@ -314,16 +311,17 @@ void HELPER(spt)(CPUS390XState *env, uint64_t time)
}
/* nanoseconds */
- time = (time * 125) >> 9;
+ time = tod2time(time);
+
+ env->cputm = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time;
- timer_mod(env->cpu_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + time);
+ timer_mod(env->cpu_timer, env->cputm);
}
/* Store CPU Timer */
uint64_t HELPER(stpt)(CPUS390XState *env)
{
- /* XXX implement */
- return 0;
+ return time2tod(env->cputm - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
}
/* Store System Information */
diff --git a/target-s390x/mmu_helper.c b/target-s390x/mmu_helper.c
index e8dcd0c18f..815ff42dde 100644
--- a/target-s390x/mmu_helper.c
+++ b/target-s390x/mmu_helper.c
@@ -358,7 +358,7 @@ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
/* Convert real address -> absolute address */
*raddr = mmu_real2abs(env, *raddr);
- if (*raddr <= ram_size) {
+ if (*raddr < ram_size) {
sk = &env->storage_keys[*raddr / TARGET_PAGE_SIZE];
if (*flags & PAGE_READ) {
*sk |= SK_R;
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index fbffd3066d..9b877148c6 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -320,7 +320,21 @@ static void gen_program_exception(DisasContext *s, int code)
static inline void gen_illegal_opcode(DisasContext *s)
{
- gen_program_exception(s, PGM_SPECIFICATION);
+ gen_program_exception(s, PGM_OPERATION);
+}
+
+static inline void gen_trap(DisasContext *s)
+{
+ TCGv_i32 t;
+
+ /* Set DXC to 0xff. */
+ t = tcg_temp_new_i32();
+ tcg_gen_ld_i32(t, cpu_env, offsetof(CPUS390XState, fpc));
+ tcg_gen_ori_i32(t, t, 0xff00);
+ tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, fpc));
+ tcg_temp_free_i32(t);
+
+ gen_program_exception(s, PGM_DATA);
}
#ifndef CONFIG_USER_ONLY
@@ -1119,6 +1133,8 @@ typedef enum DisasFacility {
FAC_HFP_MA, /* HFP multiply-and-add/subtract */
FAC_HW, /* high-word */
FAC_IEEEE_SIM, /* IEEE exception sumilation */
+ FAC_MIE, /* miscellaneous-instruction-extensions */
+ FAC_LAT, /* load-and-trap */
FAC_LOC, /* load/store on condition */
FAC_LD, /* long displacement */
FAC_PC, /* population count */
@@ -1310,7 +1326,13 @@ static ExitStatus help_branch(DisasContext *s, DisasCompare *c,
static ExitStatus op_abs(DisasContext *s, DisasOps *o)
{
- gen_helper_abs_i64(o->out, o->in2);
+ TCGv_i64 z, n;
+ z = tcg_const_i64(0);
+ n = tcg_temp_new_i64();
+ tcg_gen_neg_i64(n, o->in2);
+ tcg_gen_movcond_i64(TCG_COND_LT, o->out, o->in2, z, n, o->in2);
+ tcg_temp_free_i64(n);
+ tcg_temp_free_i64(z);
return NO_EXIT;
}
@@ -1460,6 +1482,30 @@ static ExitStatus op_bct32(DisasContext *s, DisasOps *o)
return help_branch(s, &c, is_imm, imm, o->in2);
}
+static ExitStatus op_bcth(DisasContext *s, DisasOps *o)
+{
+ int r1 = get_field(s->fields, r1);
+ int imm = get_field(s->fields, i2);
+ DisasCompare c;
+ TCGv_i64 t;
+
+ c.cond = TCG_COND_NE;
+ c.is_64 = false;
+ c.g1 = false;
+ c.g2 = false;
+
+ t = tcg_temp_new_i64();
+ tcg_gen_shri_i64(t, regs[r1], 32);
+ tcg_gen_subi_i64(t, t, 1);
+ store_reg32h_i64(r1, t);
+ c.u.s32.a = tcg_temp_new_i32();
+ c.u.s32.b = tcg_const_i32(0);
+ tcg_gen_trunc_i64_i32(c.u.s32.a, t);
+ tcg_temp_free_i64(t);
+
+ return help_branch(s, &c, 1, imm, o->in2);
+}
+
static ExitStatus op_bct64(DisasContext *s, DisasOps *o)
{
int r1 = get_field(s->fields, r1);
@@ -1961,7 +2007,6 @@ static ExitStatus op_ct(DisasContext *s, DisasOps *o)
{
int m3 = get_field(s->fields, m3);
TCGLabel *lab = gen_new_label();
- TCGv_i32 t;
TCGCond c;
c = tcg_invert_cond(ltgt_cond[m3]);
@@ -1970,15 +2015,8 @@ static ExitStatus op_ct(DisasContext *s, DisasOps *o)
}
tcg_gen_brcond_i64(c, o->in1, o->in2, lab);
- /* Set DXC to 0xff. */
- t = tcg_temp_new_i32();
- tcg_gen_ld_i32(t, cpu_env, offsetof(CPUS390XState, fpc));
- tcg_gen_ori_i32(t, t, 0xff00);
- tcg_gen_st_i32(t, cpu_env, offsetof(CPUS390XState, fpc));
- tcg_temp_free_i32(t);
-
/* Trap. */
- gen_program_exception(s, PGM_DATA);
+ gen_trap(s);
gen_set_label(lab);
return NO_EXIT;
@@ -2101,13 +2139,37 @@ static ExitStatus op_ex(DisasContext *s, DisasOps *o)
TCGv_i64 tmp;
update_psw_addr(s);
- update_cc_op(s);
+ gen_op_calc_cc(s);
tmp = tcg_const_i64(s->next_pc);
gen_helper_ex(cc_op, cpu_env, cc_op, o->in1, o->in2, tmp);
tcg_temp_free_i64(tmp);
- set_cc_static(s);
+ return NO_EXIT;
+}
+
+static ExitStatus op_fieb(DisasContext *s, DisasOps *o)
+{
+ TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3));
+ gen_helper_fieb(o->out, cpu_env, o->in2, m3);
+ tcg_temp_free_i32(m3);
+ return NO_EXIT;
+}
+
+static ExitStatus op_fidb(DisasContext *s, DisasOps *o)
+{
+ TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3));
+ gen_helper_fidb(o->out, cpu_env, o->in2, m3);
+ tcg_temp_free_i32(m3);
+ return NO_EXIT;
+}
+
+static ExitStatus op_fixb(DisasContext *s, DisasOps *o)
+{
+ TCGv_i32 m3 = tcg_const_i32(get_field(s->fields, m3));
+ gen_helper_fixb(o->out, cpu_env, o->in1, o->in2, m3);
+ return_low128(o->out2);
+ tcg_temp_free_i32(m3);
return NO_EXIT;
}
@@ -2320,6 +2382,61 @@ static ExitStatus op_ld64(DisasContext *s, DisasOps *o)
return NO_EXIT;
}
+static ExitStatus op_lat(DisasContext *s, DisasOps *o)
+{
+ TCGLabel *lab = gen_new_label();
+ store_reg32_i64(get_field(s->fields, r1), o->in2);
+ /* The value is stored even in case of trap. */
+ tcg_gen_brcondi_i64(TCG_COND_NE, o->in2, 0, lab);
+ gen_trap(s);
+ gen_set_label(lab);
+ return NO_EXIT;
+}
+
+static ExitStatus op_lgat(DisasContext *s, DisasOps *o)
+{
+ TCGLabel *lab = gen_new_label();
+ tcg_gen_qemu_ld64(o->out, o->in2, get_mem_index(s));
+ /* The value is stored even in case of trap. */
+ tcg_gen_brcondi_i64(TCG_COND_NE, o->out, 0, lab);
+ gen_trap(s);
+ gen_set_label(lab);
+ return NO_EXIT;
+}
+
+static ExitStatus op_lfhat(DisasContext *s, DisasOps *o)
+{
+ TCGLabel *lab = gen_new_label();
+ store_reg32h_i64(get_field(s->fields, r1), o->in2);
+ /* The value is stored even in case of trap. */
+ tcg_gen_brcondi_i64(TCG_COND_NE, o->in2, 0, lab);
+ gen_trap(s);
+ gen_set_label(lab);
+ return NO_EXIT;
+}
+
+static ExitStatus op_llgfat(DisasContext *s, DisasOps *o)
+{
+ TCGLabel *lab = gen_new_label();
+ tcg_gen_qemu_ld32u(o->out, o->in2, get_mem_index(s));
+ /* The value is stored even in case of trap. */
+ tcg_gen_brcondi_i64(TCG_COND_NE, o->out, 0, lab);
+ gen_trap(s);
+ gen_set_label(lab);
+ return NO_EXIT;
+}
+
+static ExitStatus op_llgtat(DisasContext *s, DisasOps *o)
+{
+ TCGLabel *lab = gen_new_label();
+ tcg_gen_andi_i64(o->out, o->in2, 0x7fffffff);
+ /* The value is stored even in case of trap. */
+ tcg_gen_brcondi_i64(TCG_COND_NE, o->out, 0, lab);
+ gen_trap(s);
+ gen_set_label(lab);
+ return NO_EXIT;
+}
+
static ExitStatus op_loc(DisasContext *s, DisasOps *o)
{
DisasCompare c;
@@ -2435,21 +2552,45 @@ static ExitStatus op_lm32(DisasContext *s, DisasOps *o)
{
int r1 = get_field(s->fields, r1);
int r3 = get_field(s->fields, r3);
- TCGv_i64 t = tcg_temp_new_i64();
- TCGv_i64 t4 = tcg_const_i64(4);
+ TCGv_i64 t1, t2;
- while (1) {
- tcg_gen_qemu_ld32u(t, o->in2, get_mem_index(s));
- store_reg32_i64(r1, t);
- if (r1 == r3) {
- break;
- }
- tcg_gen_add_i64(o->in2, o->in2, t4);
+ /* Only one register to read. */
+ t1 = tcg_temp_new_i64();
+ if (unlikely(r1 == r3)) {
+ tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
+ store_reg32_i64(r1, t1);
+ tcg_temp_free(t1);
+ return NO_EXIT;
+ }
+
+ /* First load the values of the first and last registers to trigger
+ possible page faults. */
+ t2 = tcg_temp_new_i64();
+ tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
+ tcg_gen_addi_i64(t2, o->in2, 4 * ((r3 - r1) & 15));
+ tcg_gen_qemu_ld32u(t2, t2, get_mem_index(s));
+ store_reg32_i64(r1, t1);
+ store_reg32_i64(r3, t2);
+
+ /* Only two registers to read. */
+ if (((r1 + 1) & 15) == r3) {
+ tcg_temp_free(t2);
+ tcg_temp_free(t1);
+ return NO_EXIT;
+ }
+
+ /* Then load the remaining registers. Page fault can't occur. */
+ r3 = (r3 - 1) & 15;
+ tcg_gen_movi_i64(t2, 4);
+ while (r1 != r3) {
r1 = (r1 + 1) & 15;
+ tcg_gen_add_i64(o->in2, o->in2, t2);
+ tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
+ store_reg32_i64(r1, t1);
}
+ tcg_temp_free(t2);
+ tcg_temp_free(t1);
- tcg_temp_free_i64(t);
- tcg_temp_free_i64(t4);
return NO_EXIT;
}
@@ -2457,21 +2598,45 @@ static ExitStatus op_lmh(DisasContext *s, DisasOps *o)
{
int r1 = get_field(s->fields, r1);
int r3 = get_field(s->fields, r3);
- TCGv_i64 t = tcg_temp_new_i64();
- TCGv_i64 t4 = tcg_const_i64(4);
+ TCGv_i64 t1, t2;
- while (1) {
- tcg_gen_qemu_ld32u(t, o->in2, get_mem_index(s));
- store_reg32h_i64(r1, t);
- if (r1 == r3) {
- break;
- }
- tcg_gen_add_i64(o->in2, o->in2, t4);
+ /* Only one register to read. */
+ t1 = tcg_temp_new_i64();
+ if (unlikely(r1 == r3)) {
+ tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
+ store_reg32h_i64(r1, t1);
+ tcg_temp_free(t1);
+ return NO_EXIT;
+ }
+
+ /* First load the values of the first and last registers to trigger
+ possible page faults. */
+ t2 = tcg_temp_new_i64();
+ tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
+ tcg_gen_addi_i64(t2, o->in2, 4 * ((r3 - r1) & 15));
+ tcg_gen_qemu_ld32u(t2, t2, get_mem_index(s));
+ store_reg32h_i64(r1, t1);
+ store_reg32h_i64(r3, t2);
+
+ /* Only two registers to read. */
+ if (((r1 + 1) & 15) == r3) {
+ tcg_temp_free(t2);
+ tcg_temp_free(t1);
+ return NO_EXIT;
+ }
+
+ /* Then load the remaining registers. Page fault can't occur. */
+ r3 = (r3 - 1) & 15;
+ tcg_gen_movi_i64(t2, 4);
+ while (r1 != r3) {
r1 = (r1 + 1) & 15;
+ tcg_gen_add_i64(o->in2, o->in2, t2);
+ tcg_gen_qemu_ld32u(t1, o->in2, get_mem_index(s));
+ store_reg32h_i64(r1, t1);
}
+ tcg_temp_free(t2);
+ tcg_temp_free(t1);
- tcg_temp_free_i64(t);
- tcg_temp_free_i64(t4);
return NO_EXIT;
}
@@ -2479,18 +2644,40 @@ static ExitStatus op_lm64(DisasContext *s, DisasOps *o)
{
int r1 = get_field(s->fields, r1);
int r3 = get_field(s->fields, r3);
- TCGv_i64 t8 = tcg_const_i64(8);
+ TCGv_i64 t1, t2;
- while (1) {
+ /* Only one register to read. */
+ if (unlikely(r1 == r3)) {
tcg_gen_qemu_ld64(regs[r1], o->in2, get_mem_index(s));
- if (r1 == r3) {
- break;
- }
- tcg_gen_add_i64(o->in2, o->in2, t8);
+ return NO_EXIT;
+ }
+
+ /* First load the values of the first and last registers to trigger
+ possible page faults. */
+ t1 = tcg_temp_new_i64();
+ t2 = tcg_temp_new_i64();
+ tcg_gen_qemu_ld64(t1, o->in2, get_mem_index(s));
+ tcg_gen_addi_i64(t2, o->in2, 8 * ((r3 - r1) & 15));
+ tcg_gen_qemu_ld64(regs[r3], t2, get_mem_index(s));
+ tcg_gen_mov_i64(regs[r1], t1);
+ tcg_temp_free(t2);
+
+ /* Only two registers to read. */
+ if (((r1 + 1) & 15) == r3) {
+ tcg_temp_free(t1);
+ return NO_EXIT;
+ }
+
+ /* Then load the remaining registers. Page fault can't occur. */
+ r3 = (r3 - 1) & 15;
+ tcg_gen_movi_i64(t1, 8);
+ while (r1 != r3) {
r1 = (r1 + 1) & 15;
+ tcg_gen_add_i64(o->in2, o->in2, t1);
+ tcg_gen_qemu_ld64(regs[r1], o->in2, get_mem_index(s));
}
+ tcg_temp_free(t1);
- tcg_temp_free_i64(t8);
return NO_EXIT;
}
@@ -2521,6 +2708,41 @@ static ExitStatus op_mov2(DisasContext *s, DisasOps *o)
return NO_EXIT;
}
+static ExitStatus op_mov2e(DisasContext *s, DisasOps *o)
+{
+ int b2 = get_field(s->fields, b2);
+ TCGv ar1 = tcg_temp_new_i64();
+
+ o->out = o->in2;
+ o->g_out = o->g_in2;
+ TCGV_UNUSED_I64(o->in2);
+ o->g_in2 = false;
+
+ switch (s->tb->flags & FLAG_MASK_ASC) {
+ case PSW_ASC_PRIMARY >> 32:
+ tcg_gen_movi_i64(ar1, 0);
+ break;
+ case PSW_ASC_ACCREG >> 32:
+ tcg_gen_movi_i64(ar1, 1);
+ break;
+ case PSW_ASC_SECONDARY >> 32:
+ if (b2) {
+ tcg_gen_ld32u_i64(ar1, cpu_env, offsetof(CPUS390XState, aregs[b2]));
+ } else {
+ tcg_gen_movi_i64(ar1, 0);
+ }
+ break;
+ case PSW_ASC_HOME >> 32:
+ tcg_gen_movi_i64(ar1, 2);
+ break;
+ }
+
+ tcg_gen_st32_i64(ar1, cpu_env, offsetof(CPUS390XState, aregs[1]));
+ tcg_temp_free_i64(ar1);
+
+ return NO_EXIT;
+}
+
static ExitStatus op_movx(DisasContext *s, DisasOps *o)
{
o->out = o->in1;
@@ -2681,7 +2903,13 @@ static ExitStatus op_msdb(DisasContext *s, DisasOps *o)
static ExitStatus op_nabs(DisasContext *s, DisasOps *o)
{
- gen_helper_nabs_i64(o->out, o->in2);
+ TCGv_i64 z, n;
+ z = tcg_const_i64(0);
+ n = tcg_temp_new_i64();
+ tcg_gen_neg_i64(n, o->in2);
+ tcg_gen_movcond_i64(TCG_COND_GE, o->out, o->in2, z, n, o->in2);
+ tcg_temp_free_i64(n);
+ tcg_temp_free_i64(z);
return NO_EXIT;
}
@@ -3646,6 +3874,25 @@ static ExitStatus op_tr(DisasContext *s, DisasOps *o)
return NO_EXIT;
}
+static ExitStatus op_tre(DisasContext *s, DisasOps *o)
+{
+ potential_page_fault(s);
+ gen_helper_tre(o->out, cpu_env, o->out, o->out2, o->in2);
+ return_low128(o->out2);
+ set_cc_static(s);
+ return NO_EXIT;
+}
+
+static ExitStatus op_trt(DisasContext *s, DisasOps *o)
+{
+ TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1));
+ potential_page_fault(s);
+ gen_helper_trt(cc_op, cpu_env, l, o->addr1, o->in2);
+ tcg_temp_free_i32(l);
+ set_cc_static(s);
+ return NO_EXIT;
+}
+
static ExitStatus op_unpk(DisasContext *s, DisasOps *o)
{
TCGv_i32 l = tcg_const_i32(get_field(s->fields, l1));
@@ -3989,6 +4236,12 @@ static void wout_r1_32(DisasContext *s, DisasFields *f, DisasOps *o)
}
#define SPEC_wout_r1_32 0
+static void wout_r1_32h(DisasContext *s, DisasFields *f, DisasOps *o)
+{
+ store_reg32h_i64(get_field(f, r1), o->out);
+}
+#define SPEC_wout_r1_32h 0
+
static void wout_r1_P32(DisasContext *s, DisasFields *f, DisasOps *o)
{
int r1 = get_field(f, r1);
@@ -4159,6 +4412,13 @@ static void in1_r2(DisasContext *s, DisasFields *f, DisasOps *o)
}
#define SPEC_in1_r2 0
+static void in1_r2_sr32(DisasContext *s, DisasFields *f, DisasOps *o)
+{
+ o->in1 = tcg_temp_new_i64();
+ tcg_gen_shri_i64(o->in1, regs[get_field(f, r2)], 32);
+}
+#define SPEC_in1_r2_sr32 0
+
static void in1_r3(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in1 = load_reg(get_field(f, r3));
@@ -4372,6 +4632,13 @@ static void in2_r3(DisasContext *s, DisasFields *f, DisasOps *o)
}
#define SPEC_in2_r3 0
+static void in2_r3_sr32(DisasContext *s, DisasFields *f, DisasOps *o)
+{
+ o->in2 = tcg_temp_new_i64();
+ tcg_gen_shri_i64(o->in2, regs[get_field(f, r3)], 32);
+}
+#define SPEC_in2_r3_sr32 0
+
static void in2_r2_32s(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = tcg_temp_new_i64();
@@ -4386,6 +4653,13 @@ static void in2_r2_32u(DisasContext *s, DisasFields *f, DisasOps *o)
}
#define SPEC_in2_r2_32u 0
+static void in2_r2_sr32(DisasContext *s, DisasFields *f, DisasOps *o)
+{
+ o->in2 = tcg_temp_new_i64();
+ tcg_gen_shri_i64(o->in2, regs[get_field(f, r2)], 32);
+}
+#define SPEC_in2_r2_sr32 0
+
static void in2_e2(DisasContext *s, DisasFields *f, DisasOps *o)
{
o->in2 = load_freg32_i64(get_field(f, r2));