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 32fc8d72c2SBlue Swirl /* 64/64 -> 128 unsigned multiplication */ 331ac5889fSRichard Henderson uint64_t HELPER(mul128)(CPUS390XState *env, uint64_t v1, uint64_t v2) 34fc8d72c2SBlue Swirl { 351ac5889fSRichard Henderson uint64_t reth; 361ac5889fSRichard Henderson mulu64(&env->retxl, &reth, v1, v2); 371ac5889fSRichard Henderson return reth; 38fc8d72c2SBlue Swirl } 39fc8d72c2SBlue Swirl 40891452e5SRichard Henderson /* 64/32 -> 32 signed division */ 41b4e2bd35SRichard Henderson int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64) 42fc8d72c2SBlue Swirl { 43b4e2bd35SRichard Henderson int32_t ret, b = b64; 44b4e2bd35SRichard Henderson int64_t q; 45b4e2bd35SRichard Henderson 46b4e2bd35SRichard Henderson if (b == 0) { 47b4e2bd35SRichard Henderson runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); 48b4e2bd35SRichard Henderson } 49b4e2bd35SRichard Henderson 50b4e2bd35SRichard Henderson ret = q = a / b; 51b4e2bd35SRichard Henderson env->retxl = a % b; 52b4e2bd35SRichard Henderson 53b4e2bd35SRichard Henderson /* Catch non-representable quotient. */ 54b4e2bd35SRichard Henderson if (ret != q) { 55b4e2bd35SRichard Henderson runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); 56b4e2bd35SRichard Henderson } 57b4e2bd35SRichard Henderson 58b4e2bd35SRichard Henderson return ret; 59891452e5SRichard Henderson } 60fc8d72c2SBlue Swirl 61891452e5SRichard Henderson /* 64/32 -> 32 unsigned division */ 62b4e2bd35SRichard Henderson uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64) 63891452e5SRichard Henderson { 64b4e2bd35SRichard Henderson uint32_t ret, b = b64; 65b4e2bd35SRichard Henderson uint64_t q; 66b4e2bd35SRichard Henderson 67b4e2bd35SRichard Henderson if (b == 0) { 68b4e2bd35SRichard Henderson runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); 69b4e2bd35SRichard Henderson } 70b4e2bd35SRichard Henderson 71b4e2bd35SRichard Henderson ret = q = a / b; 72b4e2bd35SRichard Henderson env->retxl = a % b; 73b4e2bd35SRichard Henderson 74b4e2bd35SRichard Henderson /* Catch non-representable quotient. */ 75b4e2bd35SRichard Henderson if (ret != q) { 76b4e2bd35SRichard Henderson runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); 77b4e2bd35SRichard Henderson } 78b4e2bd35SRichard Henderson 79b4e2bd35SRichard Henderson return ret; 80891452e5SRichard Henderson } 81891452e5SRichard Henderson 82891452e5SRichard Henderson /* 64/64 -> 64 signed division */ 83891452e5SRichard Henderson int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b) 84891452e5SRichard Henderson { 85b4e2bd35SRichard Henderson /* Catch divide by zero, and non-representable quotient (MIN / -1). */ 86b4e2bd35SRichard Henderson if (b == 0 || (b == -1 && a == (1ll << 63))) { 87b4e2bd35SRichard Henderson runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); 88b4e2bd35SRichard Henderson } 89891452e5SRichard Henderson env->retxl = a % b; 90891452e5SRichard Henderson return a / b; 91891452e5SRichard Henderson } 92891452e5SRichard Henderson 93891452e5SRichard Henderson /* 128 -> 64/64 unsigned division */ 94891452e5SRichard Henderson uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al, 95891452e5SRichard Henderson uint64_t b) 96891452e5SRichard Henderson { 97891452e5SRichard Henderson uint64_t ret; 98b4e2bd35SRichard Henderson /* Signal divide by zero. */ 99b4e2bd35SRichard Henderson if (b == 0) { 100b4e2bd35SRichard Henderson runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); 101b4e2bd35SRichard Henderson } 102891452e5SRichard Henderson if (ah == 0) { 103fc8d72c2SBlue Swirl /* 64 -> 64/64 case */ 104891452e5SRichard Henderson env->retxl = al % b; 105891452e5SRichard Henderson ret = al / b; 106fc8d72c2SBlue Swirl } else { 107891452e5SRichard Henderson /* ??? Move i386 idivq helper to host-utils. */ 108fc8d72c2SBlue Swirl #if HOST_LONG_BITS == 64 && defined(__GNUC__) 109fc8d72c2SBlue Swirl /* assuming 64-bit hosts have __uint128_t */ 110891452e5SRichard Henderson __uint128_t a = ((__uint128_t)ah << 64) | al; 111891452e5SRichard Henderson __uint128_t q = a / b; 112891452e5SRichard Henderson env->retxl = a % b; 113891452e5SRichard Henderson ret = q; 114b4e2bd35SRichard Henderson if (ret != q) { 115b4e2bd35SRichard Henderson runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC()); 116b4e2bd35SRichard Henderson } 117fc8d72c2SBlue Swirl #else 118fc8d72c2SBlue Swirl /* 32-bit hosts would need special wrapper functionality - just abort if 119fc8d72c2SBlue Swirl we encounter such a case; it's very unlikely anyways. */ 120fc8d72c2SBlue Swirl cpu_abort(env, "128 -> 64/64 division not implemented\n"); 121fc8d72c2SBlue Swirl #endif 122fc8d72c2SBlue Swirl } 123891452e5SRichard Henderson return ret; 124fc8d72c2SBlue Swirl } 125fc8d72c2SBlue Swirl 126fc8d72c2SBlue Swirl /* absolute value 32-bit */ 127fc8d72c2SBlue Swirl uint32_t HELPER(abs_i32)(int32_t val) 128fc8d72c2SBlue Swirl { 129fc8d72c2SBlue Swirl if (val < 0) { 130fc8d72c2SBlue Swirl return -val; 131fc8d72c2SBlue Swirl } else { 132fc8d72c2SBlue Swirl return val; 133fc8d72c2SBlue Swirl } 134fc8d72c2SBlue Swirl } 135fc8d72c2SBlue Swirl 136fc8d72c2SBlue Swirl /* negative absolute value 32-bit */ 137fc8d72c2SBlue Swirl int32_t HELPER(nabs_i32)(int32_t val) 138fc8d72c2SBlue Swirl { 139fc8d72c2SBlue Swirl if (val < 0) { 140fc8d72c2SBlue Swirl return val; 141fc8d72c2SBlue Swirl } else { 142fc8d72c2SBlue Swirl return -val; 143fc8d72c2SBlue Swirl } 144fc8d72c2SBlue Swirl } 145fc8d72c2SBlue Swirl 146fc8d72c2SBlue Swirl /* absolute value 64-bit */ 147fc8d72c2SBlue Swirl uint64_t HELPER(abs_i64)(int64_t val) 148fc8d72c2SBlue Swirl { 149fc8d72c2SBlue Swirl HELPER_LOG("%s: val 0x%" PRIx64 "\n", __func__, val); 150fc8d72c2SBlue Swirl 151fc8d72c2SBlue Swirl if (val < 0) { 152fc8d72c2SBlue Swirl return -val; 153fc8d72c2SBlue Swirl } else { 154fc8d72c2SBlue Swirl return val; 155fc8d72c2SBlue Swirl } 156fc8d72c2SBlue Swirl } 157fc8d72c2SBlue Swirl 158fc8d72c2SBlue Swirl /* negative absolute value 64-bit */ 159fc8d72c2SBlue Swirl int64_t HELPER(nabs_i64)(int64_t val) 160fc8d72c2SBlue Swirl { 161fc8d72c2SBlue Swirl if (val < 0) { 162fc8d72c2SBlue Swirl return val; 163fc8d72c2SBlue Swirl } else { 164fc8d72c2SBlue Swirl return -val; 165fc8d72c2SBlue Swirl } 166fc8d72c2SBlue Swirl } 167fc8d72c2SBlue Swirl 168102bf2c6SRichard Henderson /* count leading zeros, for find leftmost one */ 169102bf2c6SRichard Henderson uint64_t HELPER(clz)(uint64_t v) 170fc8d72c2SBlue Swirl { 171102bf2c6SRichard Henderson return clz64(v); 172fc8d72c2SBlue Swirl } 173fc8d72c2SBlue Swirl 174fc8d72c2SBlue Swirl uint64_t HELPER(cvd)(int32_t bin) 175fc8d72c2SBlue Swirl { 176fc8d72c2SBlue Swirl /* positive 0 */ 177fc8d72c2SBlue Swirl uint64_t dec = 0x0c; 178fc8d72c2SBlue Swirl int shift = 4; 179fc8d72c2SBlue Swirl 180fc8d72c2SBlue Swirl if (bin < 0) { 181fc8d72c2SBlue Swirl bin = -bin; 182fc8d72c2SBlue Swirl dec = 0x0d; 183fc8d72c2SBlue Swirl } 184fc8d72c2SBlue Swirl 185fc8d72c2SBlue Swirl for (shift = 4; (shift < 64) && bin; shift += 4) { 186fc8d72c2SBlue Swirl int current_number = bin % 10; 187fc8d72c2SBlue Swirl 188fc8d72c2SBlue Swirl dec |= (current_number) << shift; 189fc8d72c2SBlue Swirl bin /= 10; 190fc8d72c2SBlue Swirl } 191fc8d72c2SBlue Swirl 192fc8d72c2SBlue Swirl return dec; 193fc8d72c2SBlue Swirl } 194