1fc8d72c2SBlue Swirl /* 2fc8d72c2SBlue Swirl * S/390 integer helper routines 3fc8d72c2SBlue Swirl * 4fc8d72c2SBlue Swirl * Copyright (c) 2009 Ulrich Hecht 5fc8d72c2SBlue Swirl * Copyright (c) 2009 Alexander Graf 6fc8d72c2SBlue Swirl * 7fc8d72c2SBlue Swirl * This library is free software; you can redistribute it and/or 8fc8d72c2SBlue Swirl * modify it under the terms of the GNU Lesser General Public 9fc8d72c2SBlue Swirl * License as published by the Free Software Foundation; either 1041c6a6ddSThomas Huth * version 2.1 of the License, or (at your option) any later version. 11fc8d72c2SBlue Swirl * 12fc8d72c2SBlue Swirl * This library is distributed in the hope that it will be useful, 13fc8d72c2SBlue Swirl * but WITHOUT ANY WARRANTY; without even the implied warranty of 14fc8d72c2SBlue Swirl * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15fc8d72c2SBlue Swirl * Lesser General Public License for more details. 16fc8d72c2SBlue Swirl * 17fc8d72c2SBlue Swirl * You should have received a copy of the GNU Lesser General Public 18fc8d72c2SBlue Swirl * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19fc8d72c2SBlue Swirl */ 20fc8d72c2SBlue Swirl 219615495aSPeter Maydell #include "qemu/osdep.h" 22fc8d72c2SBlue Swirl #include "cpu.h" 23b6b47223SCho, Yu-Chen #include "s390x-internal.h" 241e36aee6SRichard Henderson #include "tcg_s390x.h" 2563c91552SPaolo Bonzini #include "exec/exec-all.h" 261de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 272ef6175aSRichard Henderson #include "exec/helper-proto.h" 28fc8d72c2SBlue Swirl 29fc8d72c2SBlue Swirl /* #define DEBUG_HELPER */ 30fc8d72c2SBlue Swirl #ifdef DEBUG_HELPER 31fc8d72c2SBlue Swirl #define HELPER_LOG(x...) qemu_log(x) 32fc8d72c2SBlue Swirl #else 33fc8d72c2SBlue Swirl #define HELPER_LOG(x...) 34fc8d72c2SBlue Swirl #endif 35fc8d72c2SBlue Swirl 36891452e5SRichard Henderson /* 64/32 -> 32 signed division */ 376d28ff40SRichard Henderson uint64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64) 38fc8d72c2SBlue Swirl { 396d28ff40SRichard Henderson int32_t b = b64; 406d28ff40SRichard Henderson int64_t q, r; 41b4e2bd35SRichard Henderson 42b4e2bd35SRichard Henderson if (b == 0) { 431e36aee6SRichard Henderson tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); 44b4e2bd35SRichard Henderson } 45b4e2bd35SRichard Henderson 466d28ff40SRichard Henderson q = a / b; 476d28ff40SRichard Henderson r = a % b; 48b4e2bd35SRichard Henderson 49b4e2bd35SRichard Henderson /* Catch non-representable quotient. */ 506d28ff40SRichard Henderson if (q != (int32_t)q) { 511e36aee6SRichard Henderson tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); 52b4e2bd35SRichard Henderson } 53b4e2bd35SRichard Henderson 546d28ff40SRichard Henderson return deposit64(q, 32, 32, r); 55891452e5SRichard Henderson } 56fc8d72c2SBlue Swirl 57891452e5SRichard Henderson /* 64/32 -> 32 unsigned division */ 58b4e2bd35SRichard Henderson uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64) 59891452e5SRichard Henderson { 606d28ff40SRichard Henderson uint32_t b = b64; 616d28ff40SRichard Henderson uint64_t q, r; 62b4e2bd35SRichard Henderson 63b4e2bd35SRichard Henderson if (b == 0) { 641e36aee6SRichard Henderson tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); 65b4e2bd35SRichard Henderson } 66b4e2bd35SRichard Henderson 676d28ff40SRichard Henderson q = a / b; 686d28ff40SRichard Henderson r = a % b; 69b4e2bd35SRichard Henderson 70b4e2bd35SRichard Henderson /* Catch non-representable quotient. */ 716d28ff40SRichard Henderson if (q != (uint32_t)q) { 721e36aee6SRichard Henderson tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); 73b4e2bd35SRichard Henderson } 74b4e2bd35SRichard Henderson 756d28ff40SRichard Henderson return deposit64(q, 32, 32, r); 76891452e5SRichard Henderson } 77891452e5SRichard Henderson 78891452e5SRichard Henderson /* 64/64 -> 64 signed division */ 794e5712f9SRichard Henderson Int128 HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b) 80891452e5SRichard Henderson { 81b4e2bd35SRichard Henderson /* Catch divide by zero, and non-representable quotient (MIN / -1). */ 82b4e2bd35SRichard Henderson if (b == 0 || (b == -1 && a == (1ll << 63))) { 831e36aee6SRichard Henderson tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); 84b4e2bd35SRichard Henderson } 854e5712f9SRichard Henderson return int128_make128(a / b, a % b); 86891452e5SRichard Henderson } 87891452e5SRichard Henderson 88891452e5SRichard Henderson /* 128 -> 64/64 unsigned division */ 894e5712f9SRichard Henderson Int128 HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al, uint64_t b) 90891452e5SRichard Henderson { 914e5712f9SRichard Henderson if (b != 0) { 924e5712f9SRichard Henderson uint64_t r = divu128(&al, &ah, b); 93891452e5SRichard Henderson if (ah == 0) { 944e5712f9SRichard Henderson return int128_make128(al, r); 954e5712f9SRichard Henderson } 964e5712f9SRichard Henderson } 974e5712f9SRichard Henderson /* divide by zero or overflow */ 981e36aee6SRichard Henderson tcg_s390_program_interrupt(env, PGM_FIXPT_DIVIDE, GETPC()); 99b4e2bd35SRichard Henderson } 100fc8d72c2SBlue Swirl 10192f2b4e7SAurelien Jarno uint64_t HELPER(cvd)(int32_t reg) 102fc8d72c2SBlue Swirl { 103fc8d72c2SBlue Swirl /* positive 0 */ 104fc8d72c2SBlue Swirl uint64_t dec = 0x0c; 10592f2b4e7SAurelien Jarno int64_t bin = reg; 10692f2b4e7SAurelien Jarno int shift; 107fc8d72c2SBlue Swirl 108fc8d72c2SBlue Swirl if (bin < 0) { 109fc8d72c2SBlue Swirl bin = -bin; 110fc8d72c2SBlue Swirl dec = 0x0d; 111fc8d72c2SBlue Swirl } 112fc8d72c2SBlue Swirl 113fc8d72c2SBlue Swirl for (shift = 4; (shift < 64) && bin; shift += 4) { 11492f2b4e7SAurelien Jarno dec |= (bin % 10) << shift; 115fc8d72c2SBlue Swirl bin /= 10; 116fc8d72c2SBlue Swirl } 117fc8d72c2SBlue Swirl 118fc8d72c2SBlue Swirl return dec; 119fc8d72c2SBlue Swirl } 12099b4f24bSRichard Henderson 121*a6e55a82SIlya Leoshkevich Int128 HELPER(cvdg)(int64_t reg) 122*a6e55a82SIlya Leoshkevich { 123*a6e55a82SIlya Leoshkevich /* positive 0 */ 124*a6e55a82SIlya Leoshkevich Int128 dec = int128_make64(0x0c); 125*a6e55a82SIlya Leoshkevich Int128 bin = int128_makes64(reg); 126*a6e55a82SIlya Leoshkevich Int128 base = int128_make64(10); 127*a6e55a82SIlya Leoshkevich int shift; 128*a6e55a82SIlya Leoshkevich 129*a6e55a82SIlya Leoshkevich if (!int128_nonneg(bin)) { 130*a6e55a82SIlya Leoshkevich bin = int128_neg(bin); 131*a6e55a82SIlya Leoshkevich dec = int128_make64(0x0d); 132*a6e55a82SIlya Leoshkevich } 133*a6e55a82SIlya Leoshkevich 134*a6e55a82SIlya Leoshkevich for (shift = 4; (shift < 128) && int128_nz(bin); shift += 4) { 135*a6e55a82SIlya Leoshkevich dec = int128_or(dec, int128_lshift(int128_remu(bin, base), shift)); 136*a6e55a82SIlya Leoshkevich bin = int128_divu(bin, base); 137*a6e55a82SIlya Leoshkevich } 138*a6e55a82SIlya Leoshkevich 139*a6e55a82SIlya Leoshkevich return dec; 140*a6e55a82SIlya Leoshkevich } 141*a6e55a82SIlya Leoshkevich 142250a87d5SRichard Henderson uint64_t HELPER(popcnt)(uint64_t val) 14399b4f24bSRichard Henderson { 144250a87d5SRichard Henderson /* Note that we don't fold past bytes. */ 145250a87d5SRichard Henderson val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL); 146250a87d5SRichard Henderson val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL); 147250a87d5SRichard Henderson val = (val + (val >> 4)) & 0x0f0f0f0f0f0f0f0fULL; 148250a87d5SRichard Henderson return val; 14999b4f24bSRichard Henderson } 150