2 * S/390 condition code helper routines
4 * Copyright (c) 2009 Ulrich Hecht
5 * Copyright (c) 2009 Alexander Graf
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
24 /* #define DEBUG_HELPER */
26 #define HELPER_LOG(x...) qemu_log(x)
28 #define HELPER_LOG(x...)
31 static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src,
36 } else if (src < dst) {
43 static inline uint32_t cc_calc_ltgt0_32(CPUS390XState *env, int32_t dst)
45 return cc_calc_ltgt_32(env, dst, 0);
48 static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src,
53 } else if (src < dst) {
60 static inline uint32_t cc_calc_ltgt0_64(CPUS390XState *env, int64_t dst)
62 return cc_calc_ltgt_64(env, dst, 0);
65 static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src,
70 } else if (src < dst) {
77 static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src,
82 } else if (src < dst) {
89 static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val,
92 uint16_t r = val & mask;
94 HELPER_LOG("%s: val 0x%x mask 0x%x\n", __func__, val, mask);
95 if (r == 0 || mask == 0) {
97 } else if (r == mask) {
104 /* set condition code for test under mask */
105 static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val,
108 uint16_t r = val & mask;
110 HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __func__, val, mask, r);
111 if (r == 0 || mask == 0) {
113 } else if (r == mask) {
116 while (!(mask & 0x8000)) {
128 static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst)
133 static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1,
134 int64_t a2, int64_t ar)
136 if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
137 return 3; /* overflow */
149 static uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1,
150 uint64_t a2, uint64_t ar)
152 return (ar != 0) + 2 * (ar < a1);
155 static uint32_t cc_calc_addc_64(CPUS390XState *env, uint64_t a1,
156 uint64_t a2, uint64_t ar)
158 /* Recover a2 + carry_in. */
159 uint64_t a2c = ar - a1;
160 /* Check for a2+carry_in overflow, then a1+a2c overflow. */
161 int carry_out = (a2c < a2) || (ar < a1);
163 return (ar != 0) + 2 * carry_out;
166 static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1,
167 int64_t a2, int64_t ar)
169 if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
170 return 3; /* overflow */
182 static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1,
183 uint64_t a2, uint64_t ar)
196 static uint32_t cc_calc_subb_64(CPUS390XState *env, uint64_t a1,
197 uint64_t a2, uint64_t ar)
199 /* We had borrow-in if normal subtraction isn't equal. */
200 int borrow_in = ar - (a1 - a2);
203 /* If a2 was ULONG_MAX, and borrow_in, then a2 is logically 65 bits,
204 and we must have had borrow out. */
205 if (borrow_in && a2 == (uint64_t)-1) {
209 borrow_out = (a2 > a1);
212 return (ar != 0) + 2 * !borrow_out;
215 static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst)
217 if ((uint64_t)dst == 0x8000000000000000ULL) {
226 static inline uint32_t cc_calc_nabs_64(CPUS390XState *env, int64_t dst)
231 static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst)
233 if ((uint64_t)dst == 0x8000000000000000ULL) {
235 } else if (dst < 0) {
237 } else if (dst > 0) {
245 static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1,
246 int32_t a2, int32_t ar)
248 if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
249 return 3; /* overflow */
261 static uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1,
262 uint32_t a2, uint32_t ar)
264 return (ar != 0) + 2 * (ar < a1);
267 static uint32_t cc_calc_addc_32(CPUS390XState *env, uint32_t a1,
268 uint32_t a2, uint32_t ar)
270 /* Recover a2 + carry_in. */
271 uint32_t a2c = ar - a1;
272 /* Check for a2+carry_in overflow, then a1+a2c overflow. */
273 int carry_out = (a2c < a2) || (ar < a1);
275 return (ar != 0) + 2 * carry_out;
278 static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1,
279 int32_t a2, int32_t ar)
281 if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
282 return 3; /* overflow */
294 static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1,
295 uint32_t a2, uint32_t ar)
308 static uint32_t cc_calc_subb_32(CPUS390XState *env, uint32_t a1,
309 uint32_t a2, uint32_t ar)
311 /* We had borrow-in if normal subtraction isn't equal. */
312 int borrow_in = ar - (a1 - a2);
315 /* If a2 was UINT_MAX, and borrow_in, then a2 is logically 65 bits,
316 and we must have had borrow out. */
317 if (borrow_in && a2 == (uint32_t)-1) {
321 borrow_out = (a2 > a1);
324 return (ar != 0) + 2 * !borrow_out;
327 static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst)
329 if ((uint32_t)dst == 0x80000000UL) {
338 static inline uint32_t cc_calc_nabs_32(CPUS390XState *env, int32_t dst)
343 static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst)
345 if ((uint32_t)dst == 0x80000000UL) {
347 } else if (dst < 0) {
349 } else if (dst > 0) {
356 /* calculate condition code for insert character under mask insn */
357 static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask,
362 HELPER_LOG("%s: mask 0x%x val %d\n", __func__, mask, val);
366 } else if (val & 0x80000000) {
389 static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src,
392 uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift);
395 /* check if the sign bit stays the same */
396 if (src & (1ULL << 63)) {
402 if ((src & mask) != match) {
407 r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63));
409 if ((int64_t)r == 0) {
411 } else if ((int64_t)r < 0) {
419 static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
420 uint64_t src, uint64_t dst, uint64_t vr)
429 /* cc_op value _is_ cc */
433 r = cc_calc_ltgt0_32(env, dst);
436 r = cc_calc_ltgt0_64(env, dst);
439 r = cc_calc_ltgt_32(env, src, dst);
442 r = cc_calc_ltgt_64(env, src, dst);
444 case CC_OP_LTUGTU_32:
445 r = cc_calc_ltugtu_32(env, src, dst);
447 case CC_OP_LTUGTU_64:
448 r = cc_calc_ltugtu_64(env, src, dst);
451 r = cc_calc_tm_32(env, src, dst);
454 r = cc_calc_tm_64(env, src, dst);
457 r = cc_calc_nz(env, dst);
460 r = cc_calc_add_64(env, src, dst, vr);
463 r = cc_calc_addu_64(env, src, dst, vr);
466 r = cc_calc_addc_64(env, src, dst, vr);
469 r = cc_calc_sub_64(env, src, dst, vr);
472 r = cc_calc_subu_64(env, src, dst, vr);
475 r = cc_calc_subb_64(env, src, dst, vr);
478 r = cc_calc_abs_64(env, dst);
481 r = cc_calc_nabs_64(env, dst);
484 r = cc_calc_comp_64(env, dst);
488 r = cc_calc_add_32(env, src, dst, vr);
491 r = cc_calc_addu_32(env, src, dst, vr);
494 r = cc_calc_addc_32(env, src, dst, vr);
497 r = cc_calc_sub_32(env, src, dst, vr);
500 r = cc_calc_subu_32(env, src, dst, vr);
503 r = cc_calc_subb_32(env, src, dst, vr);
506 r = cc_calc_abs_64(env, dst);
509 r = cc_calc_nabs_64(env, dst);
512 r = cc_calc_comp_32(env, dst);
516 r = cc_calc_icm_32(env, src, dst);
519 r = cc_calc_slag(env, src, dst);
523 r = set_cc_f32(env, src, dst);
526 r = set_cc_f64(env, src, dst);
529 r = set_cc_nz_f32(dst);
532 r = set_cc_nz_f64(dst);
536 cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op));
539 HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__,
540 cc_name(cc_op), src, dst, vr, r);
544 uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
547 return do_calc_cc(env, cc_op, src, dst, vr);
550 uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src,
551 uint64_t dst, uint64_t vr)
553 return do_calc_cc(env, cc_op, src, dst, vr);
556 /* insert psw mask and condition code into r1 */
557 void HELPER(ipm)(CPUS390XState *env, uint32_t cc, uint32_t r1)
559 uint64_t r = env->regs[r1];
561 r &= 0xffffffff00ffffffULL;
562 r |= (cc << 28) | ((env->psw.mask >> 40) & 0xf);
564 HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __func__,
565 cc, env->psw.mask, r);
568 #ifndef CONFIG_USER_ONLY
569 void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr)
571 load_psw(env, mask, addr);
575 void HELPER(sacf)(CPUS390XState *env, uint64_t a1)
577 HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1);
579 switch (a1 & 0xf00) {
581 env->psw.mask &= ~PSW_MASK_ASC;
582 env->psw.mask |= PSW_ASC_PRIMARY;
585 env->psw.mask &= ~PSW_MASK_ASC;
586 env->psw.mask |= PSW_ASC_SECONDARY;
589 env->psw.mask &= ~PSW_MASK_ASC;
590 env->psw.mask |= PSW_ASC_HOME;
593 qemu_log("unknown sacf mode: %" PRIx64 "\n", a1);
594 program_interrupt(env, PGM_SPECIFICATION, 2);