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 cc_calc_vc(uint64_t low, uint64_t high)
 406{
 407    if (high == -1ull && low == -1ull) {
 408        /* all elements match */
 409        return 0;
 410    } else if (high == 0 && low == 0) {
 411        /* no elements match */
 412        return 3;
 413    } else {
 414        /* some elements but not all match */
 415        return 1;
 416    }
 417}
 418
 419static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
 420                                  uint64_t src, uint64_t dst, uint64_t vr)
 421{
 422    uint32_t r = 0;
 423
 424    switch (cc_op) {
 425    case CC_OP_CONST0:
 426    case CC_OP_CONST1:
 427    case CC_OP_CONST2:
 428    case CC_OP_CONST3:
 429        /* cc_op value _is_ cc */
 430        r = cc_op;
 431        break;
 432    case CC_OP_LTGT0_32:
 433        r = cc_calc_ltgt0_32(dst);
 434        break;
 435    case CC_OP_LTGT0_64:
 436        r =  cc_calc_ltgt0_64(dst);
 437        break;
 438    case CC_OP_LTGT_32:
 439        r =  cc_calc_ltgt_32(src, dst);
 440        break;
 441    case CC_OP_LTGT_64:
 442        r =  cc_calc_ltgt_64(src, dst);
 443        break;
 444    case CC_OP_LTUGTU_32:
 445        r =  cc_calc_ltugtu_32(src, dst);
 446        break;
 447    case CC_OP_LTUGTU_64:
 448        r =  cc_calc_ltugtu_64(src, dst);
 449        break;
 450    case CC_OP_TM_32:
 451        r =  cc_calc_tm_32(src, dst);
 452        break;
 453    case CC_OP_TM_64:
 454        r =  cc_calc_tm_64(src, dst);
 455        break;
 456    case CC_OP_NZ:
 457        r =  cc_calc_nz(dst);
 458        break;
 459    case CC_OP_ADD_64:
 460        r =  cc_calc_add_64(src, dst, vr);
 461        break;
 462    case CC_OP_ADDU_64:
 463        r =  cc_calc_addu_64(src, dst, vr);
 464        break;
 465    case CC_OP_ADDC_64:
 466        r =  cc_calc_addc_64(src, dst, vr);
 467        break;
 468    case CC_OP_SUB_64:
 469        r =  cc_calc_sub_64(src, dst, vr);
 470        break;
 471    case CC_OP_SUBU_64:
 472        r =  cc_calc_subu_64(src, dst, vr);
 473        break;
 474    case CC_OP_SUBB_64:
 475        r =  cc_calc_subb_64(src, dst, vr);
 476        break;
 477    case CC_OP_ABS_64:
 478        r =  cc_calc_abs_64(dst);
 479        break;
 480    case CC_OP_NABS_64:
 481        r =  cc_calc_nabs_64(dst);
 482        break;
 483    case CC_OP_COMP_64:
 484        r =  cc_calc_comp_64(dst);
 485        break;
 486
 487    case CC_OP_ADD_32:
 488        r =  cc_calc_add_32(src, dst, vr);
 489        break;
 490    case CC_OP_ADDU_32:
 491        r =  cc_calc_addu_32(src, dst, vr);
 492        break;
 493    case CC_OP_ADDC_32:
 494        r =  cc_calc_addc_32(src, dst, vr);
 495        break;
 496    case CC_OP_SUB_32:
 497        r =  cc_calc_sub_32(src, dst, vr);
 498        break;
 499    case CC_OP_SUBU_32:
 500        r =  cc_calc_subu_32(src, dst, vr);
 501        break;
 502    case CC_OP_SUBB_32:
 503        r =  cc_calc_subb_32(src, dst, vr);
 504        break;
 505    case CC_OP_ABS_32:
 506        r =  cc_calc_abs_32(dst);
 507        break;
 508    case CC_OP_NABS_32:
 509        r =  cc_calc_nabs_32(dst);
 510        break;
 511    case CC_OP_COMP_32:
 512        r =  cc_calc_comp_32(dst);
 513        break;
 514
 515    case CC_OP_ICM:
 516        r =  cc_calc_icm(src, dst);
 517        break;
 518    case CC_OP_SLA_32:
 519        r =  cc_calc_sla_32(src, dst);
 520        break;
 521    case CC_OP_SLA_64:
 522        r =  cc_calc_sla_64(src, dst);
 523        break;
 524    case CC_OP_FLOGR:
 525        r = cc_calc_flogr(dst);
 526        break;
 527    case CC_OP_LCBB:
 528        r = cc_calc_lcbb(dst);
 529        break;
 530    case CC_OP_VC:
 531        r = cc_calc_vc(src, dst);
 532        break;
 533
 534    case CC_OP_NZ_F32:
 535        r = set_cc_nz_f32(dst);
 536        break;
 537    case CC_OP_NZ_F64:
 538        r = set_cc_nz_f64(dst);
 539        break;
 540    case CC_OP_NZ_F128:
 541        r = set_cc_nz_f128(make_float128(src, dst));
 542        break;
 543
 544    default:
 545        cpu_abort(env_cpu(env), "Unknown CC operation: %s\n", cc_name(cc_op));
 546    }
 547
 548    HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__,
 549               cc_name(cc_op), src, dst, vr, r);
 550    return r;
 551}
 552
 553uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
 554                 uint64_t vr)
 555{
 556    return do_calc_cc(env, cc_op, src, dst, vr);
 557}
 558
 559uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src,
 560                         uint64_t dst, uint64_t vr)
 561{
 562    return do_calc_cc(env, cc_op, src, dst, vr);
 563}
 564
 565#ifndef CONFIG_USER_ONLY
 566void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr)
 567{
 568    load_psw(env, mask, addr);
 569    cpu_loop_exit(env_cpu(env));
 570}
 571
 572void HELPER(sacf)(CPUS390XState *env, uint64_t a1)
 573{
 574    HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1);
 575
 576    switch (a1 & 0xf00) {
 577    case 0x000:
 578        env->psw.mask &= ~PSW_MASK_ASC;
 579        env->psw.mask |= PSW_ASC_PRIMARY;
 580        break;
 581    case 0x100:
 582        env->psw.mask &= ~PSW_MASK_ASC;
 583        env->psw.mask |= PSW_ASC_SECONDARY;
 584        break;
 585    case 0x300:
 586        env->psw.mask &= ~PSW_MASK_ASC;
 587        env->psw.mask |= PSW_ASC_HOME;
 588        break;
 589    default:
 590        HELPER_LOG("unknown sacf mode: %" PRIx64 "\n", a1);
 591        s390_program_interrupt(env, PGM_SPECIFICATION, 2, GETPC());
 592        break;
 593    }
 594}
 595#endif
 596