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 */ 334fda26a7SBlue Swirl void HELPER(mlg)(CPUS390XState *env, uint32_t r1, uint64_t v2) 34fc8d72c2SBlue Swirl { 35fc8d72c2SBlue Swirl #if HOST_LONG_BITS == 64 && defined(__GNUC__) 36fc8d72c2SBlue Swirl /* assuming 64-bit hosts have __uint128_t */ 37fc8d72c2SBlue Swirl __uint128_t res = (__uint128_t)env->regs[r1 + 1]; 38fc8d72c2SBlue Swirl 39fc8d72c2SBlue Swirl res *= (__uint128_t)v2; 40fc8d72c2SBlue Swirl env->regs[r1] = (uint64_t)(res >> 64); 41fc8d72c2SBlue Swirl env->regs[r1 + 1] = (uint64_t)res; 42fc8d72c2SBlue Swirl #else 43fc8d72c2SBlue Swirl mulu64(&env->regs[r1 + 1], &env->regs[r1], env->regs[r1 + 1], v2); 44fc8d72c2SBlue Swirl #endif 45fc8d72c2SBlue Swirl } 46fc8d72c2SBlue Swirl 47fc8d72c2SBlue Swirl /* 128 -> 64/64 unsigned division */ 484fda26a7SBlue Swirl void HELPER(dlg)(CPUS390XState *env, uint32_t r1, uint64_t v2) 49fc8d72c2SBlue Swirl { 50fc8d72c2SBlue Swirl uint64_t divisor = v2; 51fc8d72c2SBlue Swirl 52fc8d72c2SBlue Swirl if (!env->regs[r1]) { 53fc8d72c2SBlue Swirl /* 64 -> 64/64 case */ 54fc8d72c2SBlue Swirl env->regs[r1] = env->regs[r1 + 1] % divisor; 55fc8d72c2SBlue Swirl env->regs[r1 + 1] = env->regs[r1 + 1] / divisor; 56fc8d72c2SBlue Swirl return; 57fc8d72c2SBlue Swirl } else { 58fc8d72c2SBlue Swirl #if HOST_LONG_BITS == 64 && defined(__GNUC__) 59fc8d72c2SBlue Swirl /* assuming 64-bit hosts have __uint128_t */ 60fc8d72c2SBlue Swirl __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) | 61fc8d72c2SBlue Swirl (env->regs[r1 + 1]); 62fc8d72c2SBlue Swirl __uint128_t quotient = dividend / divisor; 63fc8d72c2SBlue Swirl __uint128_t remainder = dividend % divisor; 64fc8d72c2SBlue Swirl 65fc8d72c2SBlue Swirl env->regs[r1 + 1] = quotient; 66fc8d72c2SBlue Swirl env->regs[r1] = remainder; 67fc8d72c2SBlue Swirl #else 68fc8d72c2SBlue Swirl /* 32-bit hosts would need special wrapper functionality - just abort if 69fc8d72c2SBlue Swirl we encounter such a case; it's very unlikely anyways. */ 70fc8d72c2SBlue Swirl cpu_abort(env, "128 -> 64/64 division not implemented\n"); 71fc8d72c2SBlue Swirl #endif 72fc8d72c2SBlue Swirl } 73fc8d72c2SBlue Swirl } 74fc8d72c2SBlue Swirl 75fc8d72c2SBlue Swirl /* absolute value 32-bit */ 76fc8d72c2SBlue Swirl uint32_t HELPER(abs_i32)(int32_t val) 77fc8d72c2SBlue Swirl { 78fc8d72c2SBlue Swirl if (val < 0) { 79fc8d72c2SBlue Swirl return -val; 80fc8d72c2SBlue Swirl } else { 81fc8d72c2SBlue Swirl return val; 82fc8d72c2SBlue Swirl } 83fc8d72c2SBlue Swirl } 84fc8d72c2SBlue Swirl 85fc8d72c2SBlue Swirl /* negative absolute value 32-bit */ 86fc8d72c2SBlue Swirl int32_t HELPER(nabs_i32)(int32_t val) 87fc8d72c2SBlue Swirl { 88fc8d72c2SBlue Swirl if (val < 0) { 89fc8d72c2SBlue Swirl return val; 90fc8d72c2SBlue Swirl } else { 91fc8d72c2SBlue Swirl return -val; 92fc8d72c2SBlue Swirl } 93fc8d72c2SBlue Swirl } 94fc8d72c2SBlue Swirl 95fc8d72c2SBlue Swirl /* absolute value 64-bit */ 96fc8d72c2SBlue Swirl uint64_t HELPER(abs_i64)(int64_t val) 97fc8d72c2SBlue Swirl { 98fc8d72c2SBlue Swirl HELPER_LOG("%s: val 0x%" PRIx64 "\n", __func__, val); 99fc8d72c2SBlue Swirl 100fc8d72c2SBlue Swirl if (val < 0) { 101fc8d72c2SBlue Swirl return -val; 102fc8d72c2SBlue Swirl } else { 103fc8d72c2SBlue Swirl return val; 104fc8d72c2SBlue Swirl } 105fc8d72c2SBlue Swirl } 106fc8d72c2SBlue Swirl 107fc8d72c2SBlue Swirl /* negative absolute value 64-bit */ 108fc8d72c2SBlue Swirl int64_t HELPER(nabs_i64)(int64_t val) 109fc8d72c2SBlue Swirl { 110fc8d72c2SBlue Swirl if (val < 0) { 111fc8d72c2SBlue Swirl return val; 112fc8d72c2SBlue Swirl } else { 113fc8d72c2SBlue Swirl return -val; 114fc8d72c2SBlue Swirl } 115fc8d72c2SBlue Swirl } 116fc8d72c2SBlue Swirl 117fc8d72c2SBlue Swirl /* add with carry 32-bit unsigned */ 118fc8d72c2SBlue Swirl uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2) 119fc8d72c2SBlue Swirl { 120fc8d72c2SBlue Swirl uint32_t res; 121fc8d72c2SBlue Swirl 122fc8d72c2SBlue Swirl res = v1 + v2; 123fc8d72c2SBlue Swirl if (cc & 2) { 124fc8d72c2SBlue Swirl res++; 125fc8d72c2SBlue Swirl } 126fc8d72c2SBlue Swirl 127fc8d72c2SBlue Swirl return res; 128fc8d72c2SBlue Swirl } 129fc8d72c2SBlue Swirl 130fc8d72c2SBlue Swirl /* subtract unsigned v2 from v1 with borrow */ 1314fda26a7SBlue Swirl uint32_t HELPER(slb)(CPUS390XState *env, uint32_t cc, uint32_t r1, uint32_t v2) 132fc8d72c2SBlue Swirl { 133fc8d72c2SBlue Swirl uint32_t v1 = env->regs[r1]; 134fc8d72c2SBlue Swirl uint32_t res = v1 + (~v2) + (cc >> 1); 135fc8d72c2SBlue Swirl 136fc8d72c2SBlue Swirl env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res; 137fc8d72c2SBlue Swirl if (cc & 2) { 138fc8d72c2SBlue Swirl /* borrow */ 139fc8d72c2SBlue Swirl return v1 ? 1 : 0; 140fc8d72c2SBlue Swirl } else { 141fc8d72c2SBlue Swirl return v1 ? 3 : 2; 142fc8d72c2SBlue Swirl } 143fc8d72c2SBlue Swirl } 144fc8d72c2SBlue Swirl 145fc8d72c2SBlue Swirl /* subtract unsigned v2 from v1 with borrow */ 1464fda26a7SBlue Swirl uint32_t HELPER(slbg)(CPUS390XState *env, uint32_t cc, uint32_t r1, 1474fda26a7SBlue Swirl uint64_t v1, uint64_t v2) 148fc8d72c2SBlue Swirl { 149fc8d72c2SBlue Swirl uint64_t res = v1 + (~v2) + (cc >> 1); 150fc8d72c2SBlue Swirl 151fc8d72c2SBlue Swirl env->regs[r1] = res; 152fc8d72c2SBlue Swirl if (cc & 2) { 153fc8d72c2SBlue Swirl /* borrow */ 154fc8d72c2SBlue Swirl return v1 ? 1 : 0; 155fc8d72c2SBlue Swirl } else { 156fc8d72c2SBlue Swirl return v1 ? 3 : 2; 157fc8d72c2SBlue Swirl } 158fc8d72c2SBlue Swirl } 159fc8d72c2SBlue Swirl 160fc8d72c2SBlue Swirl /* find leftmost one */ 1614fda26a7SBlue Swirl uint32_t HELPER(flogr)(CPUS390XState *env, uint32_t r1, uint64_t v2) 162fc8d72c2SBlue Swirl { 163fc8d72c2SBlue Swirl uint64_t res = 0; 164fc8d72c2SBlue Swirl uint64_t ov2 = v2; 165fc8d72c2SBlue Swirl 166fc8d72c2SBlue Swirl while (!(v2 & 0x8000000000000000ULL) && v2) { 167fc8d72c2SBlue Swirl v2 <<= 1; 168fc8d72c2SBlue Swirl res++; 169fc8d72c2SBlue Swirl } 170fc8d72c2SBlue Swirl 171fc8d72c2SBlue Swirl if (!v2) { 172fc8d72c2SBlue Swirl env->regs[r1] = 64; 173fc8d72c2SBlue Swirl env->regs[r1 + 1] = 0; 174fc8d72c2SBlue Swirl return 0; 175fc8d72c2SBlue Swirl } else { 176fc8d72c2SBlue Swirl env->regs[r1] = res; 177fc8d72c2SBlue Swirl env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res); 178fc8d72c2SBlue Swirl return 2; 179fc8d72c2SBlue Swirl } 180fc8d72c2SBlue Swirl } 181fc8d72c2SBlue Swirl 182fc8d72c2SBlue Swirl uint64_t HELPER(cvd)(int32_t bin) 183fc8d72c2SBlue Swirl { 184fc8d72c2SBlue Swirl /* positive 0 */ 185fc8d72c2SBlue Swirl uint64_t dec = 0x0c; 186fc8d72c2SBlue Swirl int shift = 4; 187fc8d72c2SBlue Swirl 188fc8d72c2SBlue Swirl if (bin < 0) { 189fc8d72c2SBlue Swirl bin = -bin; 190fc8d72c2SBlue Swirl dec = 0x0d; 191fc8d72c2SBlue Swirl } 192fc8d72c2SBlue Swirl 193fc8d72c2SBlue Swirl for (shift = 4; (shift < 64) && bin; shift += 4) { 194fc8d72c2SBlue Swirl int current_number = bin % 10; 195fc8d72c2SBlue Swirl 196fc8d72c2SBlue Swirl dec |= (current_number) << shift; 197fc8d72c2SBlue Swirl bin /= 10; 198fc8d72c2SBlue Swirl } 199fc8d72c2SBlue Swirl 200fc8d72c2SBlue Swirl return dec; 201fc8d72c2SBlue Swirl } 202