xref: /qemu/target/s390x/tcg/int_helper.c (revision 41c6a6dd84f36b33b3cc6e4a3512455b471d8845)
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
10*41c6a6ddSThomas 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"
234e58b838SDavid Hildenbrand #include "internal.h"
2463c91552SPaolo Bonzini #include "exec/exec-all.h"
251de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
262ef6175aSRichard Henderson #include "exec/helper-proto.h"
27fc8d72c2SBlue Swirl 
28fc8d72c2SBlue Swirl /* #define DEBUG_HELPER */
29fc8d72c2SBlue Swirl #ifdef DEBUG_HELPER
30fc8d72c2SBlue Swirl #define HELPER_LOG(x...) qemu_log(x)
31fc8d72c2SBlue Swirl #else
32fc8d72c2SBlue Swirl #define HELPER_LOG(x...)
33fc8d72c2SBlue Swirl #endif
34fc8d72c2SBlue Swirl 
35891452e5SRichard Henderson /* 64/32 -> 32 signed division */
36b4e2bd35SRichard Henderson int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64)
37fc8d72c2SBlue Swirl {
38b4e2bd35SRichard Henderson     int32_t ret, b = b64;
39b4e2bd35SRichard Henderson     int64_t q;
40b4e2bd35SRichard Henderson 
41b4e2bd35SRichard Henderson     if (b == 0) {
427693f77aSDavid Hildenbrand         s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC());
43b4e2bd35SRichard Henderson     }
44b4e2bd35SRichard Henderson 
45b4e2bd35SRichard Henderson     ret = q = a / b;
46b4e2bd35SRichard Henderson     env->retxl = a % b;
47b4e2bd35SRichard Henderson 
48b4e2bd35SRichard Henderson     /* Catch non-representable quotient.  */
49b4e2bd35SRichard Henderson     if (ret != q) {
507693f77aSDavid Hildenbrand         s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC());
51b4e2bd35SRichard Henderson     }
52b4e2bd35SRichard Henderson 
53b4e2bd35SRichard Henderson     return ret;
54891452e5SRichard Henderson }
55fc8d72c2SBlue Swirl 
56891452e5SRichard Henderson /* 64/32 -> 32 unsigned division */
57b4e2bd35SRichard Henderson uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64)
58891452e5SRichard Henderson {
59b4e2bd35SRichard Henderson     uint32_t ret, b = b64;
60b4e2bd35SRichard Henderson     uint64_t q;
61b4e2bd35SRichard Henderson 
62b4e2bd35SRichard Henderson     if (b == 0) {
637693f77aSDavid Hildenbrand         s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC());
64b4e2bd35SRichard Henderson     }
65b4e2bd35SRichard Henderson 
66b4e2bd35SRichard Henderson     ret = q = a / b;
67b4e2bd35SRichard Henderson     env->retxl = a % b;
68b4e2bd35SRichard Henderson 
69b4e2bd35SRichard Henderson     /* Catch non-representable quotient.  */
70b4e2bd35SRichard Henderson     if (ret != q) {
717693f77aSDavid Hildenbrand         s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC());
72b4e2bd35SRichard Henderson     }
73b4e2bd35SRichard Henderson 
74b4e2bd35SRichard Henderson     return ret;
75891452e5SRichard Henderson }
76891452e5SRichard Henderson 
77891452e5SRichard Henderson /* 64/64 -> 64 signed division */
78891452e5SRichard Henderson int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b)
79891452e5SRichard Henderson {
80b4e2bd35SRichard Henderson     /* Catch divide by zero, and non-representable quotient (MIN / -1).  */
81b4e2bd35SRichard Henderson     if (b == 0 || (b == -1 && a == (1ll << 63))) {
827693f77aSDavid Hildenbrand         s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC());
83b4e2bd35SRichard Henderson     }
84891452e5SRichard Henderson     env->retxl = a % b;
85891452e5SRichard Henderson     return a / b;
86891452e5SRichard Henderson }
87891452e5SRichard Henderson 
88891452e5SRichard Henderson /* 128 -> 64/64 unsigned division */
89891452e5SRichard Henderson uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al,
90891452e5SRichard Henderson                         uint64_t b)
91891452e5SRichard Henderson {
92891452e5SRichard Henderson     uint64_t ret;
93b4e2bd35SRichard Henderson     /* Signal divide by zero.  */
94b4e2bd35SRichard Henderson     if (b == 0) {
957693f77aSDavid Hildenbrand         s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC());
96b4e2bd35SRichard Henderson     }
97891452e5SRichard Henderson     if (ah == 0) {
98fc8d72c2SBlue Swirl         /* 64 -> 64/64 case */
99891452e5SRichard Henderson         env->retxl = al % b;
100891452e5SRichard Henderson         ret = al / b;
101fc8d72c2SBlue Swirl     } else {
102891452e5SRichard Henderson         /* ??? Move i386 idivq helper to host-utils.  */
103d49b8e0bSGabriel Kerneis #ifdef CONFIG_INT128
104891452e5SRichard Henderson         __uint128_t a = ((__uint128_t)ah << 64) | al;
105891452e5SRichard Henderson         __uint128_t q = a / b;
106891452e5SRichard Henderson         env->retxl = a % b;
107891452e5SRichard Henderson         ret = q;
108b4e2bd35SRichard Henderson         if (ret != q) {
1097693f77aSDavid Hildenbrand             s390_program_interrupt(env, PGM_FIXPT_DIVIDE, ILEN_AUTO, GETPC());
110b4e2bd35SRichard Henderson         }
111fc8d72c2SBlue Swirl #else
112a47dddd7SAndreas Färber         S390CPU *cpu = s390_env_get_cpu(env);
113fc8d72c2SBlue Swirl         /* 32-bit hosts would need special wrapper functionality - just abort if
114fc8d72c2SBlue Swirl            we encounter such a case; it's very unlikely anyways. */
115a47dddd7SAndreas Färber         cpu_abort(CPU(cpu), "128 -> 64/64 division not implemented\n");
116fc8d72c2SBlue Swirl #endif
117fc8d72c2SBlue Swirl     }
118891452e5SRichard Henderson     return ret;
119fc8d72c2SBlue Swirl }
120fc8d72c2SBlue Swirl 
12192f2b4e7SAurelien Jarno uint64_t HELPER(cvd)(int32_t reg)
122fc8d72c2SBlue Swirl {
123fc8d72c2SBlue Swirl     /* positive 0 */
124fc8d72c2SBlue Swirl     uint64_t dec = 0x0c;
12592f2b4e7SAurelien Jarno     int64_t bin = reg;
12692f2b4e7SAurelien Jarno     int shift;
127fc8d72c2SBlue Swirl 
128fc8d72c2SBlue Swirl     if (bin < 0) {
129fc8d72c2SBlue Swirl         bin = -bin;
130fc8d72c2SBlue Swirl         dec = 0x0d;
131fc8d72c2SBlue Swirl     }
132fc8d72c2SBlue Swirl 
133fc8d72c2SBlue Swirl     for (shift = 4; (shift < 64) && bin; shift += 4) {
13492f2b4e7SAurelien Jarno         dec |= (bin % 10) << shift;
135fc8d72c2SBlue Swirl         bin /= 10;
136fc8d72c2SBlue Swirl     }
137fc8d72c2SBlue Swirl 
138fc8d72c2SBlue Swirl     return dec;
139fc8d72c2SBlue Swirl }
14099b4f24bSRichard Henderson 
141250a87d5SRichard Henderson uint64_t HELPER(popcnt)(uint64_t val)
14299b4f24bSRichard Henderson {
143250a87d5SRichard Henderson     /* Note that we don't fold past bytes. */
144250a87d5SRichard Henderson     val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL);
145250a87d5SRichard Henderson     val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL);
146250a87d5SRichard Henderson     val = (val + (val >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
147250a87d5SRichard Henderson     return val;
14899b4f24bSRichard Henderson }
149