xref: /qemu/target/s390x/tcg/int_helper.c (revision 102bf2c63535122cba0d7917ed8cfb8cc1c7b14c)
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