These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / target-s390x / int_helper.c
1 /*
2  *  S/390 integer helper routines
3  *
4  *  Copyright (c) 2009 Ulrich Hecht
5  *  Copyright (c) 2009 Alexander Graf
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "qemu/osdep.h"
22 #include "cpu.h"
23 #include "qemu/host-utils.h"
24 #include "exec/helper-proto.h"
25
26 /* #define DEBUG_HELPER */
27 #ifdef DEBUG_HELPER
28 #define HELPER_LOG(x...) qemu_log(x)
29 #else
30 #define HELPER_LOG(x...)
31 #endif
32
33 /* 64/32 -> 32 signed division */
34 int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64)
35 {
36     int32_t ret, b = b64;
37     int64_t q;
38
39     if (b == 0) {
40         runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
41     }
42
43     ret = q = a / b;
44     env->retxl = a % b;
45
46     /* Catch non-representable quotient.  */
47     if (ret != q) {
48         runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
49     }
50
51     return ret;
52 }
53
54 /* 64/32 -> 32 unsigned division */
55 uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64)
56 {
57     uint32_t ret, b = b64;
58     uint64_t q;
59
60     if (b == 0) {
61         runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
62     }
63
64     ret = q = a / b;
65     env->retxl = a % b;
66
67     /* Catch non-representable quotient.  */
68     if (ret != q) {
69         runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
70     }
71
72     return ret;
73 }
74
75 /* 64/64 -> 64 signed division */
76 int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b)
77 {
78     /* Catch divide by zero, and non-representable quotient (MIN / -1).  */
79     if (b == 0 || (b == -1 && a == (1ll << 63))) {
80         runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
81     }
82     env->retxl = a % b;
83     return a / b;
84 }
85
86 /* 128 -> 64/64 unsigned division */
87 uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al,
88                         uint64_t b)
89 {
90     uint64_t ret;
91     /* Signal divide by zero.  */
92     if (b == 0) {
93         runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
94     }
95     if (ah == 0) {
96         /* 64 -> 64/64 case */
97         env->retxl = al % b;
98         ret = al / b;
99     } else {
100         /* ??? Move i386 idivq helper to host-utils.  */
101 #ifdef CONFIG_INT128
102         __uint128_t a = ((__uint128_t)ah << 64) | al;
103         __uint128_t q = a / b;
104         env->retxl = a % b;
105         ret = q;
106         if (ret != q) {
107             runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
108         }
109 #else
110         S390CPU *cpu = s390_env_get_cpu(env);
111         /* 32-bit hosts would need special wrapper functionality - just abort if
112            we encounter such a case; it's very unlikely anyways. */
113         cpu_abort(CPU(cpu), "128 -> 64/64 division not implemented\n");
114 #endif
115     }
116     return ret;
117 }
118
119 /* count leading zeros, for find leftmost one */
120 uint64_t HELPER(clz)(uint64_t v)
121 {
122     return clz64(v);
123 }
124
125 uint64_t HELPER(cvd)(int32_t reg)
126 {
127     /* positive 0 */
128     uint64_t dec = 0x0c;
129     int64_t bin = reg;
130     int shift;
131
132     if (bin < 0) {
133         bin = -bin;
134         dec = 0x0d;
135     }
136
137     for (shift = 4; (shift < 64) && bin; shift += 4) {
138         dec |= (bin % 10) << shift;
139         bin /= 10;
140     }
141
142     return dec;
143 }
144
145 uint64_t HELPER(popcnt)(uint64_t r2)
146 {
147     uint64_t ret = 0;
148     int i;
149
150     for (i = 0; i < 64; i += 8) {
151         uint64_t t = ctpop32((r2 >> i) & 0xff);
152         ret |= t << i;
153     }
154     return ret;
155 }