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