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