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