qemu/target-s390x/cc_helper.c
<<
>>
Prefs
   1/*
   2 *  S/390 condition code helper routines
   3 *
   4 *  Copyright (c) 2009 Ulrich Hecht
   5 *  Copyright (c) 2009 Alexander Graf
   6 *
   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.
  11 *
  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.
  16 *
  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/>.
  19 */
  20
  21#include "qemu/osdep.h"
  22#include "cpu.h"
  23#include "exec/helper-proto.h"
  24#include "qemu/host-utils.h"
  25
  26/* #define DEBUG_HELPER */
  27#ifdef DEBUG_HELPER
  28#define HELPER_LOG(x...) qemu_log(x)
  29#else
  30#define HELPER_LOG(x...)
  31#endif
  32
  33static uint32_t cc_calc_ltgt_32(int32_t src, int32_t dst)
  34{
  35    if (src == dst) {
  36        return 0;
  37    } else if (src < dst) {
  38        return 1;
  39    } else {
  40        return 2;
  41    }
  42}
  43
  44static uint32_t cc_calc_ltgt0_32(int32_t dst)
  45{
  46    return cc_calc_ltgt_32(dst, 0);
  47}
  48
  49static uint32_t cc_calc_ltgt_64(int64_t src, int64_t dst)
  50{
  51    if (src == dst) {
  52        return 0;
  53    } else if (src < dst) {
  54        return 1;
  55    } else {
  56        return 2;
  57    }
  58}
  59
  60static uint32_t cc_calc_ltgt0_64(int64_t dst)
  61{
  62    return cc_calc_ltgt_64(dst, 0);
  63}
  64
  65static uint32_t cc_calc_ltugtu_32(uint32_t src, uint32_t dst)
  66{
  67    if (src == dst) {
  68        return 0;
  69    } else if (src < dst) {
  70        return 1;
  71    } else {
  72        return 2;
  73    }
  74}
  75
  76static uint32_t cc_calc_ltugtu_64(uint64_t src, uint64_t dst)
  77{
  78    if (src == dst) {
  79        return 0;
  80    } else if (src < dst) {
  81        return 1;
  82    } else {
  83        return 2;
  84    }
  85}
  86
  87static uint32_t cc_calc_tm_32(uint32_t val, uint32_t mask)
  88{
  89    uint32_t r = val & mask;
  90
  91    if (r == 0) {
  92        return 0;
  93    } else if (r == mask) {
  94        return 3;
  95    } else {
  96        return 1;
  97    }
  98}
  99
 100static uint32_t cc_calc_tm_64(uint64_t val, uint64_t mask)
 101{
 102    uint64_t r = val & mask;
 103
 104    if (r == 0) {
 105        return 0;
 106    } else if (r == mask) {
 107        return 3;
 108    } else {
 109        int top = clz64(mask);
 110        if ((int64_t)(val << top) < 0) {
 111            return 2;
 112        } else {
 113            return 1;
 114        }
 115    }
 116}
 117
 118static uint32_t cc_calc_nz(uint64_t dst)
 119{
 120    return !!dst;
 121}
 122
 123static uint32_t cc_calc_add_64(int64_t a1, int64_t a2, int64_t ar)
 124{
 125    if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
 126        return 3; /* overflow */
 127    } else {
 128        if (ar < 0) {
 129            return 1;
 130        } else if (ar > 0) {
 131            return 2;
 132        } else {
 133            return 0;
 134        }
 135    }
 136}
 137
 138static uint32_t cc_calc_addu_64(uint64_t a1, uint64_t a2, uint64_t ar)
 139{
 140    return (ar != 0) + 2 * (ar < a1);
 141}
 142
 143static uint32_t cc_calc_addc_64(uint64_t a1, uint64_t a2, uint64_t ar)
 144{
 145    /* Recover a2 + carry_in.  */
 146    uint64_t a2c = ar - a1;
 147    /* Check for a2+carry_in overflow, then a1+a2c overflow.  */
 148    int carry_out = (a2c < a2) || (ar < a1);
 149
 150    return (ar != 0) + 2 * carry_out;
 151}
 152
 153static uint32_t cc_calc_sub_64(int64_t a1, int64_t a2, int64_t ar)
 154{
 155    if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
 156        return 3; /* overflow */
 157    } else {
 158        if (ar < 0) {
 159            return 1;
 160        } else if (ar > 0) {
 161            return 2;
 162        } else {
 163            return 0;
 164        }
 165    }
 166}
 167
 168static uint32_t cc_calc_subu_64(uint64_t a1, uint64_t a2, uint64_t ar)
 169{
 170    if (ar == 0) {
 171        return 2;
 172    } else {
 173        if (a2 > a1) {
 174            return 1;
 175        } else {
 176            return 3;
 177        }
 178    }
 179}
 180
 181static uint32_t cc_calc_subb_64(uint64_t a1, uint64_t a2, uint64_t ar)
 182{
 183    int borrow_out;
 184
 185    if (ar != a1 - a2) {        /* difference means borrow-in */
 186        borrow_out = (a2 >= a1);
 187    } else {
 188        borrow_out = (a2 > a1);
 189    }
 190
 191    return (ar != 0) + 2 * !borrow_out;
 192}
 193
 194static uint32_t cc_calc_abs_64(int64_t dst)
 195{
 196    if ((uint64_t)dst == 0x8000000000000000ULL) {
 197        return 3;
 198    } else if (dst) {
 199        return 2;
 200    } else {
 201        return 0;
 202    }
 203}
 204
 205static uint32_t cc_calc_nabs_64(int64_t dst)
 206{
 207    return !!dst;
 208}
 209
 210static uint32_t cc_calc_comp_64(int64_t dst)
 211{
 212    if ((uint64_t)dst == 0x8000000000000000ULL) {
 213        return 3;
 214    } else if (dst < 0) {
 215        return 1;
 216    } else if (dst > 0) {
 217        return 2;
 218    } else {
 219        return 0;
 220    }
 221}
 222
 223
 224static uint32_t cc_calc_add_32(int32_t a1, int32_t a2, int32_t ar)
 225{
 226    if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) {
 227        return 3; /* overflow */
 228    } else {
 229        if (ar < 0) {
 230            return 1;
 231        } else if (ar > 0) {
 232            return 2;
 233        } else {
 234            return 0;
 235        }
 236    }
 237}
 238
 239static uint32_t cc_calc_addu_32(uint32_t a1, uint32_t a2, uint32_t ar)
 240{
 241    return (ar != 0) + 2 * (ar < a1);
 242}
 243
 244static uint32_t cc_calc_addc_32(uint32_t a1, uint32_t a2, uint32_t ar)
 245{
 246    /* Recover a2 + carry_in.  */
 247    uint32_t a2c = ar - a1;
 248    /* Check for a2+carry_in overflow, then a1+a2c overflow.  */
 249    int carry_out = (a2c < a2) || (ar < a1);
 250
 251    return (ar != 0) + 2 * carry_out;
 252}
 253
 254static uint32_t cc_calc_sub_32(int32_t a1, int32_t a2, int32_t ar)
 255{
 256    if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) {
 257        return 3; /* overflow */
 258    } else {
 259        if (ar < 0) {
 260            return 1;
 261        } else if (ar > 0) {
 262            return 2;
 263        } else {
 264            return 0;
 265        }
 266    }
 267}
 268
 269static uint32_t cc_calc_subu_32(uint32_t a1, uint32_t a2, uint32_t ar)
 270{
 271    if (ar == 0) {
 272        return 2;
 273    } else {
 274        if (a2 > a1) {
 275            return 1;
 276        } else {
 277            return 3;
 278        }
 279    }
 280}
 281
 282static uint32_t cc_calc_subb_32(uint32_t a1, uint32_t a2, uint32_t ar)
 283{
 284    int borrow_out;
 285
 286    if (ar != a1 - a2) {        /* difference means borrow-in */
 287        borrow_out = (a2 >= a1);
 288    } else {
 289        borrow_out = (a2 > a1);
 290    }
 291
 292    return (ar != 0) + 2 * !borrow_out;
 293}
 294
 295static uint32_t cc_calc_abs_32(int32_t dst)
 296{
 297    if ((uint32_t)dst == 0x80000000UL) {
 298        return 3;
 299    } else if (dst) {
 300        return 2;
 301    } else {
 302        return 0;
 303    }
 304}
 305
 306static uint32_t cc_calc_nabs_32(int32_t dst)
 307{
 308    return !!dst;
 309}
 310
 311static uint32_t cc_calc_comp_32(int32_t dst)
 312{
 313    if ((uint32_t)dst == 0x80000000UL) {
 314        return 3;
 315    } else if (dst < 0) {
 316        return 1;
 317    } else if (dst > 0) {
 318        return 2;
 319    } else {
 320        return 0;
 321    }
 322}
 323
 324/* calculate condition code for insert character under mask insn */
 325static uint32_t cc_calc_icm(uint64_t mask, uint64_t val)
 326{
 327    if ((val & mask) == 0) {
 328        return 0;
 329    } else {
 330        int top = clz64(mask);
 331        if ((int64_t)(val << top) < 0) {
 332            return 1;
 333        } else {
 334            return 2;
 335        }
 336    }
 337}
 338
 339static uint32_t cc_calc_sla_32(uint32_t src, int shift)
 340{
 341    uint32_t mask = ((1U << shift) - 1U) << (32 - shift);
 342    uint32_t sign = 1U << 31;
 343    uint32_t match;
 344    int32_t r;
 345
 346    /* Check if the sign bit stays the same.  */
 347    if (src & sign) {
 348        match = mask;
 349    } else {
 350        match = 0;
 351    }
 352    if ((src & mask) != match) {
 353        /* Overflow.  */
 354        return 3;
 355    }
 356
 357    r = ((src << shift) & ~sign) | (src & sign);
 358    if (r == 0) {
 359        return 0;
 360    } else if (r < 0) {
 361        return 1;
 362    }
 363    return 2;
 364}
 365
 366static uint32_t cc_calc_sla_64(uint64_t src, int shift)
 367{
 368    uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift);
 369    uint64_t sign = 1ULL << 63;
 370    uint64_t match;
 371    int64_t r;
 372
 373    /* Check if the sign bit stays the same.  */
 374    if (src & sign) {
 375        match = mask;
 376    } else {
 377        match = 0;
 378    }
 379    if ((src & mask) != match) {
 380        /* Overflow.  */
 381        return 3;
 382    }
 383
 384    r = ((src << shift) & ~sign) | (src & sign);
 385    if (r == 0) {
 386        return 0;
 387    } else if (r < 0) {
 388        return 1;
 389    }
 390    return 2;
 391}
 392
 393static uint32_t cc_calc_flogr(uint64_t dst)
 394{
 395    return dst ? 2 : 0;
 396}
 397
 398static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
 399                                  uint64_t src, uint64_t dst, uint64_t vr)
 400{
 401    S390CPU *cpu = s390_env_get_cpu(env);
 402    uint32_t r = 0;
 403
 404    switch (cc_op) {
 405    case CC_OP_CONST0:
 406    case CC_OP_CONST1:
 407    case CC_OP_CONST2:
 408    case CC_OP_CONST3:
 409        /* cc_op value _is_ cc */
 410        r = cc_op;
 411        break;
 412    case CC_OP_LTGT0_32:
 413        r = cc_calc_ltgt0_32(dst);
 414        break;
 415    case CC_OP_LTGT0_64:
 416        r =  cc_calc_ltgt0_64(dst);
 417        break;
 418    case CC_OP_LTGT_32:
 419        r =  cc_calc_ltgt_32(src, dst);
 420        break;
 421    case CC_OP_LTGT_64:
 422        r =  cc_calc_ltgt_64(src, dst);
 423        break;
 424    case CC_OP_LTUGTU_32:
 425        r =  cc_calc_ltugtu_32(src, dst);
 426        break;
 427    case CC_OP_LTUGTU_64:
 428        r =  cc_calc_ltugtu_64(src, dst);
 429        break;
 430    case CC_OP_TM_32:
 431        r =  cc_calc_tm_32(src, dst);
 432        break;
 433    case CC_OP_TM_64:
 434        r =  cc_calc_tm_64(src, dst);
 435        break;
 436    case CC_OP_NZ:
 437        r =  cc_calc_nz(dst);
 438        break;
 439    case CC_OP_ADD_64:
 440        r =  cc_calc_add_64(src, dst, vr);
 441        break;
 442    case CC_OP_ADDU_64:
 443        r =  cc_calc_addu_64(src, dst, vr);
 444        break;
 445    case CC_OP_ADDC_64:
 446        r =  cc_calc_addc_64(src, dst, vr);
 447        break;
 448    case CC_OP_SUB_64:
 449        r =  cc_calc_sub_64(src, dst, vr);
 450        break;
 451    case CC_OP_SUBU_64:
 452        r =  cc_calc_subu_64(src, dst, vr);
 453        break;
 454    case CC_OP_SUBB_64:
 455        r =  cc_calc_subb_64(src, dst, vr);
 456        break;
 457    case CC_OP_ABS_64:
 458        r =  cc_calc_abs_64(dst);
 459        break;
 460    case CC_OP_NABS_64:
 461        r =  cc_calc_nabs_64(dst);
 462        break;
 463    case CC_OP_COMP_64:
 464        r =  cc_calc_comp_64(dst);
 465        break;
 466
 467    case CC_OP_ADD_32:
 468        r =  cc_calc_add_32(src, dst, vr);
 469        break;
 470    case CC_OP_ADDU_32:
 471        r =  cc_calc_addu_32(src, dst, vr);
 472        break;
 473    case CC_OP_ADDC_32:
 474        r =  cc_calc_addc_32(src, dst, vr);
 475        break;
 476    case CC_OP_SUB_32:
 477        r =  cc_calc_sub_32(src, dst, vr);
 478        break;
 479    case CC_OP_SUBU_32:
 480        r =  cc_calc_subu_32(src, dst, vr);
 481        break;
 482    case CC_OP_SUBB_32:
 483        r =  cc_calc_subb_32(src, dst, vr);
 484        break;
 485    case CC_OP_ABS_32:
 486        r =  cc_calc_abs_32(dst);
 487        break;
 488    case CC_OP_NABS_32:
 489        r =  cc_calc_nabs_32(dst);
 490        break;
 491    case CC_OP_COMP_32:
 492        r =  cc_calc_comp_32(dst);
 493        break;
 494
 495    case CC_OP_ICM:
 496        r =  cc_calc_icm(src, dst);
 497        break;
 498    case CC_OP_SLA_32:
 499        r =  cc_calc_sla_32(src, dst);
 500        break;
 501    case CC_OP_SLA_64:
 502        r =  cc_calc_sla_64(src, dst);
 503        break;
 504    case CC_OP_FLOGR:
 505        r = cc_calc_flogr(dst);
 506        break;
 507
 508    case CC_OP_NZ_F32:
 509        r = set_cc_nz_f32(dst);
 510        break;
 511    case CC_OP_NZ_F64:
 512        r = set_cc_nz_f64(dst);
 513        break;
 514    case CC_OP_NZ_F128:
 515        r = set_cc_nz_f128(make_float128(src, dst));
 516        break;
 517
 518    default:
 519        cpu_abort(CPU(cpu), "Unknown CC operation: %s\n", cc_name(cc_op));
 520    }
 521
 522    HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__,
 523               cc_name(cc_op), src, dst, vr, r);
 524    return r;
 525}
 526
 527uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
 528                 uint64_t vr)
 529{
 530    return do_calc_cc(env, cc_op, src, dst, vr);
 531}
 532
 533uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src,
 534                         uint64_t dst, uint64_t vr)
 535{
 536    return do_calc_cc(env, cc_op, src, dst, vr);
 537}
 538
 539#ifndef CONFIG_USER_ONLY
 540void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr)
 541{
 542    load_psw(env, mask, addr);
 543    cpu_loop_exit(CPU(s390_env_get_cpu(env)));
 544}
 545
 546void HELPER(sacf)(CPUS390XState *env, uint64_t a1)
 547{
 548    HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1);
 549
 550    switch (a1 & 0xf00) {
 551    case 0x000:
 552        env->psw.mask &= ~PSW_MASK_ASC;
 553        env->psw.mask |= PSW_ASC_PRIMARY;
 554        break;
 555    case 0x100:
 556        env->psw.mask &= ~PSW_MASK_ASC;
 557        env->psw.mask |= PSW_ASC_SECONDARY;
 558        break;
 559    case 0x300:
 560        env->psw.mask &= ~PSW_MASK_ASC;
 561        env->psw.mask |= PSW_ASC_HOME;
 562        break;
 563    default:
 564        HELPER_LOG("unknown sacf mode: %" PRIx64 "\n", a1);
 565        program_interrupt(env, PGM_SPECIFICATION, 2);
 566        break;
 567    }
 568}
 569#endif
 570