qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

cc_helper.c (11412B)


      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 
     36 static 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 
     47 static uint32_t cc_calc_ltgt0_32(int32_t dst)
     48 {
     49     return cc_calc_ltgt_32(dst, 0);
     50 }
     51 
     52 static 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 
     63 static uint32_t cc_calc_ltgt0_64(int64_t dst)
     64 {
     65     return cc_calc_ltgt_64(dst, 0);
     66 }
     67 
     68 static 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 
     79 static 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 
     90 static 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 
    103 static 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 
    121 static uint32_t cc_calc_nz(uint64_t dst)
    122 {
    123     return !!dst;
    124 }
    125 
    126 static 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 
    132 static uint32_t cc_calc_subu(uint64_t borrow_out, uint64_t result)
    133 {
    134     return cc_calc_addu(borrow_out + 1, result);
    135 }
    136 
    137 static 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 
    152 static 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 
    167 static 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 
    178 static uint32_t cc_calc_nabs_64(int64_t dst)
    179 {
    180     return !!dst;
    181 }
    182 
    183 static 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 
    197 static 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 
    212 static 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 
    227 static 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 
    238 static uint32_t cc_calc_nabs_32(int32_t dst)
    239 {
    240     return !!dst;
    241 }
    242 
    243 static 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 */
    257 static 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 
    271 static uint32_t cc_calc_sla(uint64_t src, int shift)
    272 {
    273     uint64_t mask = -1ULL << (63 - shift);
    274     uint64_t sign = 1ULL << 63;
    275     uint64_t match;
    276     int64_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 
    298 static uint32_t cc_calc_flogr(uint64_t dst)
    299 {
    300     return dst ? 2 : 0;
    301 }
    302 
    303 static uint32_t cc_calc_lcbb(uint64_t dst)
    304 {
    305     return dst == 16 ? 0 : 3;
    306 }
    307 
    308 static uint32_t cc_calc_vc(uint64_t low, uint64_t high)
    309 {
    310     if (high == -1ull && low == -1ull) {
    311         /* all elements match */
    312         return 0;
    313     } else if (high == 0 && low == 0) {
    314         /* no elements match */
    315         return 3;
    316     } else {
    317         /* some elements but not all match */
    318         return 1;
    319     }
    320 }
    321 
    322 static uint32_t cc_calc_muls_32(int64_t res)
    323 {
    324     const int64_t tmp = res >> 31;
    325 
    326     if (!res) {
    327         return 0;
    328     } else if (tmp && tmp != -1) {
    329         return 3;
    330     } else if (res < 0) {
    331         return 1;
    332     }
    333     return 2;
    334 }
    335 
    336 static uint64_t cc_calc_muls_64(int64_t res_high, uint64_t res_low)
    337 {
    338     if (!res_high && !res_low) {
    339         return 0;
    340     } else if (res_high + (res_low >> 63) != 0) {
    341         return 3;
    342     } else if (res_high < 0) {
    343         return 1;
    344     }
    345     return 2;
    346 }
    347 
    348 static uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op,
    349                                   uint64_t src, uint64_t dst, uint64_t vr)
    350 {
    351     uint32_t r = 0;
    352 
    353     switch (cc_op) {
    354     case CC_OP_CONST0:
    355     case CC_OP_CONST1:
    356     case CC_OP_CONST2:
    357     case CC_OP_CONST3:
    358         /* cc_op value _is_ cc */
    359         r = cc_op;
    360         break;
    361     case CC_OP_LTGT0_32:
    362         r = cc_calc_ltgt0_32(dst);
    363         break;
    364     case CC_OP_LTGT0_64:
    365         r =  cc_calc_ltgt0_64(dst);
    366         break;
    367     case CC_OP_LTGT_32:
    368         r =  cc_calc_ltgt_32(src, dst);
    369         break;
    370     case CC_OP_LTGT_64:
    371         r =  cc_calc_ltgt_64(src, dst);
    372         break;
    373     case CC_OP_LTUGTU_32:
    374         r =  cc_calc_ltugtu_32(src, dst);
    375         break;
    376     case CC_OP_LTUGTU_64:
    377         r =  cc_calc_ltugtu_64(src, dst);
    378         break;
    379     case CC_OP_TM_32:
    380         r =  cc_calc_tm_32(src, dst);
    381         break;
    382     case CC_OP_TM_64:
    383         r =  cc_calc_tm_64(src, dst);
    384         break;
    385     case CC_OP_NZ:
    386         r =  cc_calc_nz(dst);
    387         break;
    388     case CC_OP_ADDU:
    389         r = cc_calc_addu(src, dst);
    390         break;
    391     case CC_OP_SUBU:
    392         r = cc_calc_subu(src, dst);
    393         break;
    394     case CC_OP_ADD_64:
    395         r =  cc_calc_add_64(src, dst, vr);
    396         break;
    397     case CC_OP_SUB_64:
    398         r =  cc_calc_sub_64(src, dst, vr);
    399         break;
    400     case CC_OP_ABS_64:
    401         r =  cc_calc_abs_64(dst);
    402         break;
    403     case CC_OP_NABS_64:
    404         r =  cc_calc_nabs_64(dst);
    405         break;
    406     case CC_OP_COMP_64:
    407         r =  cc_calc_comp_64(dst);
    408         break;
    409     case CC_OP_MULS_64:
    410         r = cc_calc_muls_64(src, dst);
    411         break;
    412 
    413     case CC_OP_ADD_32:
    414         r =  cc_calc_add_32(src, dst, vr);
    415         break;
    416     case CC_OP_SUB_32:
    417         r =  cc_calc_sub_32(src, dst, vr);
    418         break;
    419     case CC_OP_ABS_32:
    420         r =  cc_calc_abs_32(dst);
    421         break;
    422     case CC_OP_NABS_32:
    423         r =  cc_calc_nabs_32(dst);
    424         break;
    425     case CC_OP_COMP_32:
    426         r =  cc_calc_comp_32(dst);
    427         break;
    428     case CC_OP_MULS_32:
    429         r = cc_calc_muls_32(dst);
    430         break;
    431 
    432     case CC_OP_ICM:
    433         r =  cc_calc_icm(src, dst);
    434         break;
    435     case CC_OP_SLA:
    436         r =  cc_calc_sla(src, dst);
    437         break;
    438     case CC_OP_FLOGR:
    439         r = cc_calc_flogr(dst);
    440         break;
    441     case CC_OP_LCBB:
    442         r = cc_calc_lcbb(dst);
    443         break;
    444     case CC_OP_VC:
    445         r = cc_calc_vc(src, dst);
    446         break;
    447 
    448     case CC_OP_NZ_F32:
    449         r = set_cc_nz_f32(dst);
    450         break;
    451     case CC_OP_NZ_F64:
    452         r = set_cc_nz_f64(dst);
    453         break;
    454     case CC_OP_NZ_F128:
    455         r = set_cc_nz_f128(make_float128(src, dst));
    456         break;
    457 
    458     default:
    459         cpu_abort(env_cpu(env), "Unknown CC operation: %s\n", cc_name(cc_op));
    460     }
    461 
    462     HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__,
    463                cc_name(cc_op), src, dst, vr, r);
    464     return r;
    465 }
    466 
    467 uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
    468                  uint64_t vr)
    469 {
    470     return do_calc_cc(env, cc_op, src, dst, vr);
    471 }
    472 
    473 uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src,
    474                          uint64_t dst, uint64_t vr)
    475 {
    476     return do_calc_cc(env, cc_op, src, dst, vr);
    477 }
    478 
    479 #ifndef CONFIG_USER_ONLY
    480 void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr)
    481 {
    482     s390_cpu_set_psw(env, mask, addr);
    483     cpu_loop_exit(env_cpu(env));
    484 }
    485 
    486 void HELPER(sacf)(CPUS390XState *env, uint64_t a1)
    487 {
    488     HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1);
    489 
    490     if (!(env->psw.mask & PSW_MASK_DAT)) {
    491         tcg_s390_program_interrupt(env, PGM_SPECIAL_OP, GETPC());
    492     }
    493 
    494     switch (a1 & 0xf00) {
    495     case 0x000:
    496         env->psw.mask &= ~PSW_MASK_ASC;
    497         env->psw.mask |= PSW_ASC_PRIMARY;
    498         break;
    499     case 0x100:
    500         env->psw.mask &= ~PSW_MASK_ASC;
    501         env->psw.mask |= PSW_ASC_SECONDARY;
    502         break;
    503     case 0x300:
    504         if ((env->psw.mask & PSW_MASK_PSTATE) != 0) {
    505             tcg_s390_program_interrupt(env, PGM_PRIVILEGED, GETPC());
    506         }
    507         env->psw.mask &= ~PSW_MASK_ASC;
    508         env->psw.mask |= PSW_ASC_HOME;
    509         break;
    510     default:
    511         HELPER_LOG("unknown sacf mode: %" PRIx64 "\n", a1);
    512         tcg_s390_program_interrupt(env, PGM_SPECIFICATION, GETPC());
    513     }
    514 }
    515 #endif