Statistics
| Branch: | Revision:

root / target-s390x / int_helper.c @ 420840e5

History | View | Annotate | Download (4.4 kB)

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 "cpu.h"
22
#include "qemu/host-utils.h"
23
#include "helper.h"
24

    
25
/* #define DEBUG_HELPER */
26
#ifdef DEBUG_HELPER
27
#define HELPER_LOG(x...) qemu_log(x)
28
#else
29
#define HELPER_LOG(x...)
30
#endif
31

    
32
/* 64/32 -> 32 signed division */
33
int64_t HELPER(divs32)(CPUS390XState *env, int64_t a, int64_t b64)
34
{
35
    int32_t ret, b = b64;
36
    int64_t q;
37

    
38
    if (b == 0) {
39
        runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
40
    }
41

    
42
    ret = q = a / b;
43
    env->retxl = a % b;
44

    
45
    /* Catch non-representable quotient.  */
46
    if (ret != q) {
47
        runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
48
    }
49

    
50
    return ret;
51
}
52

    
53
/* 64/32 -> 32 unsigned division */
54
uint64_t HELPER(divu32)(CPUS390XState *env, uint64_t a, uint64_t b64)
55
{
56
    uint32_t ret, b = b64;
57
    uint64_t q;
58

    
59
    if (b == 0) {
60
        runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
61
    }
62

    
63
    ret = q = a / b;
64
    env->retxl = a % b;
65

    
66
    /* Catch non-representable quotient.  */
67
    if (ret != q) {
68
        runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
69
    }
70

    
71
    return ret;
72
}
73

    
74
/* 64/64 -> 64 signed division */
75
int64_t HELPER(divs64)(CPUS390XState *env, int64_t a, int64_t b)
76
{
77
    /* Catch divide by zero, and non-representable quotient (MIN / -1).  */
78
    if (b == 0 || (b == -1 && a == (1ll << 63))) {
79
        runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
80
    }
81
    env->retxl = a % b;
82
    return a / b;
83
}
84

    
85
/* 128 -> 64/64 unsigned division */
86
uint64_t HELPER(divu64)(CPUS390XState *env, uint64_t ah, uint64_t al,
87
                        uint64_t b)
88
{
89
    uint64_t ret;
90
    /* Signal divide by zero.  */
91
    if (b == 0) {
92
        runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
93
    }
94
    if (ah == 0) {
95
        /* 64 -> 64/64 case */
96
        env->retxl = al % b;
97
        ret = al / b;
98
    } else {
99
        /* ??? Move i386 idivq helper to host-utils.  */
100
#ifdef CONFIG_INT128
101
        __uint128_t a = ((__uint128_t)ah << 64) | al;
102
        __uint128_t q = a / b;
103
        env->retxl = a % b;
104
        ret = q;
105
        if (ret != q) {
106
            runtime_exception(env, PGM_FIXPT_DIVIDE, GETPC());
107
        }
108
#else
109
        /* 32-bit hosts would need special wrapper functionality - just abort if
110
           we encounter such a case; it's very unlikely anyways. */
111
        cpu_abort(env, "128 -> 64/64 division not implemented\n");
112
#endif
113
    }
114
    return ret;
115
}
116

    
117
/* absolute value 32-bit */
118
uint32_t HELPER(abs_i32)(int32_t val)
119
{
120
    if (val < 0) {
121
        return -val;
122
    } else {
123
        return val;
124
    }
125
}
126

    
127
/* negative absolute value 32-bit */
128
int32_t HELPER(nabs_i32)(int32_t val)
129
{
130
    if (val < 0) {
131
        return val;
132
    } else {
133
        return -val;
134
    }
135
}
136

    
137
/* absolute value 64-bit */
138
uint64_t HELPER(abs_i64)(int64_t val)
139
{
140
    HELPER_LOG("%s: val 0x%" PRIx64 "\n", __func__, val);
141

    
142
    if (val < 0) {
143
        return -val;
144
    } else {
145
        return val;
146
    }
147
}
148

    
149
/* negative absolute value 64-bit */
150
int64_t HELPER(nabs_i64)(int64_t val)
151
{
152
    if (val < 0) {
153
        return val;
154
    } else {
155
        return -val;
156
    }
157
}
158

    
159
/* count leading zeros, for find leftmost one */
160
uint64_t HELPER(clz)(uint64_t v)
161
{
162
    return clz64(v);
163
}
164

    
165
uint64_t HELPER(cvd)(int32_t bin)
166
{
167
    /* positive 0 */
168
    uint64_t dec = 0x0c;
169
    int shift = 4;
170

    
171
    if (bin < 0) {
172
        bin = -bin;
173
        dec = 0x0d;
174
    }
175

    
176
    for (shift = 4; (shift < 64) && bin; shift += 4) {
177
        int current_number = bin % 10;
178

    
179
        dec |= (current_number) << shift;
180
        bin /= 10;
181
    }
182

    
183
    return dec;
184
}
185

    
186
uint64_t HELPER(popcnt)(uint64_t r2)
187
{
188
    uint64_t ret = 0;
189
    int i;
190

    
191
    for (i = 0; i < 64; i += 8) {
192
        uint64_t t = ctpop32((r2 >> i) & 0xff);
193
        ret |= t << i;
194
    }
195
    return ret;
196
}