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 10fc8d72c2SBlue Swirl * version 2 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 21fc8d72c2SBlue Swirl #include "cpu.h" 221de7afc9SPaolo Bonzini #include "qemu/host-utils.h" 23fc8d72c2SBlue Swirl #include "helper.h" 24fc8d72c2SBlue Swirl 25fc8d72c2SBlue Swirl /* #define DEBUG_HELPER */ 26fc8d72c2SBlue Swirl #ifdef DEBUG_HELPER 27fc8d72c2SBlue Swirl #define HELPER_LOG(x...) qemu_log(x) 28fc8d72c2SBlue Swirl #else 29fc8d72c2SBlue Swirl #define HELPER_LOG(x...) 30fc8d72c2SBlue Swirl #endif 31fc8d72c2SBlue Swirl 32891452e5SRichard Henderson /* 64/32 -> 32 signed division */ 33b4e2bd35SRichard Henderson int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64) 34fc8d72c2SBlue Swirl { 35b4e2bd35SRichard Henderson int32_t ret, b = b64; 36b4e2bd35SRichard Henderson int64_t q; 37b4e2bd35SRichard Henderson 38b4e2bd35SRichard Henderson if (b == 0) { 39b4e2bd35SRichard Henderson runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); 40b4e2bd35SRichard Henderson } 41b4e2bd35SRichard Henderson 42b4e2bd35SRichard Henderson ret = q = a / b; 43b4e2bd35SRichard Henderson env->retxl = a % b; 44b4e2bd35SRichard Henderson 45b4e2bd35SRichard Henderson /* Catch non-representable quotient. */ 46b4e2bd35SRichard Henderson if (ret != q) { 47b4e2bd35SRichard Henderson runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); 48b4e2bd35SRichard Henderson } 49b4e2bd35SRichard Henderson 50b4e2bd35SRichard Henderson return ret; 51891452e5SRichard Henderson } 52fc8d72c2SBlue Swirl 53891452e5SRichard Henderson /* 64/32 -> 32 unsigned division */ 54b4e2bd35SRichard Henderson uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64) 55891452e5SRichard Henderson { 56b4e2bd35SRichard Henderson uint32_t ret, b = b64; 57b4e2bd35SRichard Henderson uint64_t q; 58b4e2bd35SRichard Henderson 59b4e2bd35SRichard Henderson if (b == 0) { 60b4e2bd35SRichard Henderson runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); 61b4e2bd35SRichard Henderson } 62b4e2bd35SRichard Henderson 63b4e2bd35SRichard Henderson ret = q = a / b; 64b4e2bd35SRichard Henderson env->retxl = a % b; 65b4e2bd35SRichard Henderson 66b4e2bd35SRichard Henderson /* Catch non-representable quotient. */ 67b4e2bd35SRichard Henderson if (ret != q) { 68b4e2bd35SRichard Henderson runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); 69b4e2bd35SRichard Henderson } 70b4e2bd35SRichard Henderson 71b4e2bd35SRichard Henderson return ret; 72891452e5SRichard Henderson } 73891452e5SRichard Henderson 74891452e5SRichard Henderson /* 64/64 -> 64 signed division */ 75891452e5SRichard Henderson int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b) 76891452e5SRichard Henderson { 77b4e2bd35SRichard Henderson /* Catch divide by zero, and non-representable quotient (MIN / -1). */ 78b4e2bd35SRichard Henderson if (b == 0 || (b == -1 && a == (1ll << 63))) { 79b4e2bd35SRichard Henderson runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); 80b4e2bd35SRichard Henderson } 81891452e5SRichard Henderson env->retxl = a % b; 82891452e5SRichard Henderson return a / b; 83891452e5SRichard Henderson } 84891452e5SRichard Henderson 85891452e5SRichard Henderson /* 128 -> 64/64 unsigned division */ 86891452e5SRichard Henderson uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al, 87891452e5SRichard Henderson uint64_t b) 88891452e5SRichard Henderson { 89891452e5SRichard Henderson uint64_t ret; 90b4e2bd35SRichard Henderson /* Signal divide by zero. */ 91b4e2bd35SRichard Henderson if (b == 0) { 92b4e2bd35SRichard Henderson runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); 93b4e2bd35SRichard Henderson } 94891452e5SRichard Henderson if (ah == 0) { 95fc8d72c2SBlue Swirl /* 64 -> 64/64 case */ 96891452e5SRichard Henderson env->retxl = al % b; 97891452e5SRichard Henderson ret = al / b; 98fc8d72c2SBlue Swirl } else { 99891452e5SRichard Henderson /* ??? Move i386 idivq helper to host-utils. */ 100d49b8e0bSGabriel Kerneis #ifdef CONFIG_INT128 101891452e5SRichard Henderson __uint128_t a = ((__uint128_t)ah << 64) | al; 102891452e5SRichard Henderson __uint128_t q = a / b; 103891452e5SRichard Henderson env->retxl = a % b; 104891452e5SRichard Henderson ret = q; 105b4e2bd35SRichard Henderson if (ret != q) { 106b4e2bd35SRichard Henderson runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); 107b4e2bd35SRichard Henderson } 108fc8d72c2SBlue Swirl #else 109a47dddd7SAndreas Färber S390CPU *cpu = s390_env_get_cpu(env); 110fc8d72c2SBlue Swirl /* 32-bit hosts would need special wrapper functionality - just abort if 111fc8d72c2SBlue Swirl we encounter such a case; it's very unlikely anyways. */ 112a47dddd7SAndreas Färber cpu_abort(CPU(cpu), "128 -> 64/64 division not implemented\n"); 113fc8d72c2SBlue Swirl #endif 114fc8d72c2SBlue Swirl } 115891452e5SRichard Henderson return ret; 116fc8d72c2SBlue Swirl } 117fc8d72c2SBlue Swirl 118fc8d72c2SBlue Swirl /* absolute value 32-bit */ 119fc8d72c2SBlue Swirl uint32_t HELPER(abs_i32)(int32_t val) 120fc8d72c2SBlue Swirl { 121fc8d72c2SBlue Swirl if (val < 0) { 122fc8d72c2SBlue Swirl return -val; 123fc8d72c2SBlue Swirl } else { 124fc8d72c2SBlue Swirl return val; 125fc8d72c2SBlue Swirl } 126fc8d72c2SBlue Swirl } 127fc8d72c2SBlue Swirl 128fc8d72c2SBlue Swirl /* negative absolute value 32-bit */ 129fc8d72c2SBlue Swirl int32_t HELPER(nabs_i32)(int32_t val) 130fc8d72c2SBlue Swirl { 131fc8d72c2SBlue Swirl if (val < 0) { 132fc8d72c2SBlue Swirl return val; 133fc8d72c2SBlue Swirl } else { 134fc8d72c2SBlue Swirl return -val; 135fc8d72c2SBlue Swirl } 136fc8d72c2SBlue Swirl } 137fc8d72c2SBlue Swirl 138fc8d72c2SBlue Swirl /* absolute value 64-bit */ 139fc8d72c2SBlue Swirl uint64_t HELPER(abs_i64)(int64_t val) 140fc8d72c2SBlue Swirl { 141fc8d72c2SBlue Swirl HELPER_LOG("%s: val 0x%" PRIx64 "\n", __func__, val); 142fc8d72c2SBlue Swirl 143fc8d72c2SBlue Swirl if (val < 0) { 144fc8d72c2SBlue Swirl return -val; 145fc8d72c2SBlue Swirl } else { 146fc8d72c2SBlue Swirl return val; 147fc8d72c2SBlue Swirl } 148fc8d72c2SBlue Swirl } 149fc8d72c2SBlue Swirl 150fc8d72c2SBlue Swirl /* negative absolute value 64-bit */ 151fc8d72c2SBlue Swirl int64_t HELPER(nabs_i64)(int64_t val) 152fc8d72c2SBlue Swirl { 153fc8d72c2SBlue Swirl if (val < 0) { 154fc8d72c2SBlue Swirl return val; 155fc8d72c2SBlue Swirl } else { 156fc8d72c2SBlue Swirl return -val; 157fc8d72c2SBlue Swirl } 158fc8d72c2SBlue Swirl } 159fc8d72c2SBlue Swirl 160102bf2c6SRichard Henderson /* count leading zeros, for find leftmost one */ 161102bf2c6SRichard Henderson uint64_t HELPER(clz)(uint64_t v) 162fc8d72c2SBlue Swirl { 163102bf2c6SRichard Henderson return clz64(v); 164fc8d72c2SBlue Swirl } 165fc8d72c2SBlue Swirl 166fc8d72c2SBlue Swirl uint64_t HELPER(cvd)(int32_t bin) 167fc8d72c2SBlue Swirl { 168fc8d72c2SBlue Swirl /* positive 0 */ 169fc8d72c2SBlue Swirl uint64_t dec = 0x0c; 170fc8d72c2SBlue Swirl int shift = 4; 171fc8d72c2SBlue Swirl 172fc8d72c2SBlue Swirl if (bin < 0) { 173fc8d72c2SBlue Swirl bin = -bin; 174fc8d72c2SBlue Swirl dec = 0x0d; 175fc8d72c2SBlue Swirl } 176fc8d72c2SBlue Swirl 177fc8d72c2SBlue Swirl for (shift = 4; (shift < 64) && bin; shift += 4) { 178fc8d72c2SBlue Swirl int current_number = bin % 10; 179fc8d72c2SBlue Swirl 180fc8d72c2SBlue Swirl dec |= (current_number) << shift; 181fc8d72c2SBlue Swirl bin /= 10; 182fc8d72c2SBlue Swirl } 183fc8d72c2SBlue Swirl 184fc8d72c2SBlue Swirl return dec; 185fc8d72c2SBlue Swirl } 18699b4f24bSRichard Henderson 18799b4f24bSRichard Henderson uint64_t HELPER(popcnt)(uint64_t r2) 18899b4f24bSRichard Henderson { 18999b4f24bSRichard Henderson uint64_t ret = 0; 19099b4f24bSRichard Henderson int i; 19199b4f24bSRichard Henderson 19299b4f24bSRichard Henderson for (i = 0; i < 64; i += 8) { 19399b4f24bSRichard Henderson uint64_t t = ctpop32((r2 >> i) & 0xff); 19499b4f24bSRichard Henderson ret |= t << i; 19599b4f24bSRichard Henderson } 19699b4f24bSRichard Henderson return ret; 19799b4f24bSRichard Henderson } 198