1 /* 2 * S/390 integer 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 "qemu/host-utils.h" 27 #include "exec/helper-proto.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 /* 64/32 -> 32 signed division */ 37 uint64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64) 38 { 39 int32_t b = b64; 40 int64_t q, r; 41 42 if (b == 0) { 43 tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); 44 } 45 46 q = a / b; 47 r = a % b; 48 49 /* Catch non-representable quotient. */ 50 if (q != (int32_t)q) { 51 tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); 52 } 53 54 return deposit64(q, 32, 32, r); 55 } 56 57 /* 64/32 -> 32 unsigned division */ 58 uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64) 59 { 60 uint32_t b = b64; 61 uint64_t q, r; 62 63 if (b == 0) { 64 tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); 65 } 66 67 q = a / b; 68 r = a % b; 69 70 /* Catch non-representable quotient. */ 71 if (q != (uint32_t)q) { 72 tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); 73 } 74 75 return deposit64(q, 32, 32, r); 76 } 77 78 /* 64/64 -> 64 signed division */ 79 Int128 HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b) 80 { 81 /* Catch divide by zero, and non-representable quotient (MIN / -1). */ 82 if (b == 0 || (b == -1 && a == (1ll << 63))) { 83 tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); 84 } 85 return int128_make128(a / b, a % b); 86 } 87 88 /* 128 -> 64/64 unsigned division */ 89 Int128 HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t b) 90 { 91 if (b != 0) { 92 uint64_t r = divu128(&al, &ah, b); 93 if (ah == 0) { 94 return int128_make128(al, r); 95 } 96 } 97 /* divide by zero or overflow */ 98 tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); 99 } 100 101 uint64_t HELPER(cvd)(int32_t reg) 102 { 103 /* positive 0 */ 104 uint64_t dec = 0x0c; 105 int64_t bin = reg; 106 int shift; 107 108 if (bin < 0) { 109 bin = -bin; 110 dec = 0x0d; 111 } 112 113 for (shift = 4; (shift < 64) && bin; shift += 4) { 114 dec |= (bin % 10) << shift; 115 bin /= 10; 116 } 117 118 return dec; 119 } 120 121 uint64_t HELPER(popcnt)(uint64_t val) 122 { 123 /* Note that we don't fold past bytes. */ 124 val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL); 125 val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL); 126 val = (val + (val >> 4)) & 0x0f0f0f0f0f0f0f0fULL; 127 return val; 128 } 129