Statistics
| Branch: | Revision:

root / target-sparc / helper.c @ 1de7afc9

History | View | Annotate | Download (5.3 kB)

1
/*
2
 *  Misc Sparc helpers
3
 *
4
 *  Copyright (c) 2003-2005 Fabrice Bellard
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18
 */
19

    
20
#include "cpu.h"
21
#include "qemu/host-utils.h"
22
#include "helper.h"
23
#include "sysemu.h"
24

    
25
void helper_raise_exception(CPUSPARCState *env, int tt)
26
{
27
    env->exception_index = tt;
28
    cpu_loop_exit(env);
29
}
30

    
31
void helper_debug(CPUSPARCState *env)
32
{
33
    env->exception_index = EXCP_DEBUG;
34
    cpu_loop_exit(env);
35
}
36

    
37
#ifdef TARGET_SPARC64
38
target_ulong helper_popc(target_ulong val)
39
{
40
    return ctpop64(val);
41
}
42

    
43
void helper_tick_set_count(void *opaque, uint64_t count)
44
{
45
#if !defined(CONFIG_USER_ONLY)
46
    cpu_tick_set_count(opaque, count);
47
#endif
48
}
49

    
50
uint64_t helper_tick_get_count(void *opaque)
51
{
52
#if !defined(CONFIG_USER_ONLY)
53
    return cpu_tick_get_count(opaque);
54
#else
55
    return 0;
56
#endif
57
}
58

    
59
void helper_tick_set_limit(void *opaque, uint64_t limit)
60
{
61
#if !defined(CONFIG_USER_ONLY)
62
    cpu_tick_set_limit(opaque, limit);
63
#endif
64
}
65
#endif
66

    
67
static target_ulong helper_udiv_common(CPUSPARCState *env, target_ulong a,
68
                                       target_ulong b, int cc)
69
{
70
    int overflow = 0;
71
    uint64_t x0;
72
    uint32_t x1;
73

    
74
    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
75
    x1 = (b & 0xffffffff);
76

    
77
    if (x1 == 0) {
78
        cpu_restore_state(env, GETPC());
79
        helper_raise_exception(env, TT_DIV_ZERO);
80
    }
81

    
82
    x0 = x0 / x1;
83
    if (x0 > 0xffffffff) {
84
        x0 = 0xffffffff;
85
        overflow = 1;
86
    }
87

    
88
    if (cc) {
89
        env->cc_dst = x0;
90
        env->cc_src2 = overflow;
91
        env->cc_op = CC_OP_DIV;
92
    }
93
    return x0;
94
}
95

    
96
target_ulong helper_udiv(CPUSPARCState *env, target_ulong a, target_ulong b)
97
{
98
    return helper_udiv_common(env, a, b, 0);
99
}
100

    
101
target_ulong helper_udiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
102
{
103
    return helper_udiv_common(env, a, b, 1);
104
}
105

    
106
static target_ulong helper_sdiv_common(CPUSPARCState *env, target_ulong a,
107
                                       target_ulong b, int cc)
108
{
109
    int overflow = 0;
110
    int64_t x0;
111
    int32_t x1;
112

    
113
    x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
114
    x1 = (b & 0xffffffff);
115

    
116
    if (x1 == 0) {
117
        cpu_restore_state(env, GETPC());
118
        helper_raise_exception(env, TT_DIV_ZERO);
119
    }
120

    
121
    x0 = x0 / x1;
122
    if ((int32_t) x0 != x0) {
123
        x0 = x0 < 0 ? 0x80000000 : 0x7fffffff;
124
        overflow = 1;
125
    }
126

    
127
    if (cc) {
128
        env->cc_dst = x0;
129
        env->cc_src2 = overflow;
130
        env->cc_op = CC_OP_DIV;
131
    }
132
    return x0;
133
}
134

    
135
target_ulong helper_sdiv(CPUSPARCState *env, target_ulong a, target_ulong b)
136
{
137
    return helper_sdiv_common(env, a, b, 0);
138
}
139

    
140
target_ulong helper_sdiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
141
{
142
    return helper_sdiv_common(env, a, b, 1);
143
}
144

    
145
#ifdef TARGET_SPARC64
146
int64_t helper_sdivx(CPUSPARCState *env, int64_t a, int64_t b)
147
{
148
    if (b == 0) {
149
        /* Raise divide by zero trap.  */
150
        cpu_restore_state(env, GETPC());
151
        helper_raise_exception(env, TT_DIV_ZERO);
152
    } else if (b == -1) {
153
        /* Avoid overflow trap with i386 divide insn.  */
154
        return -a;
155
    } else {
156
        return a / b;
157
    }
158
}
159

    
160
uint64_t helper_udivx(CPUSPARCState *env, uint64_t a, uint64_t b)
161
{
162
    if (b == 0) {
163
        /* Raise divide by zero trap.  */
164
        cpu_restore_state(env, GETPC());
165
        helper_raise_exception(env, TT_DIV_ZERO);
166
    }
167
    return a / b;
168
}
169
#endif
170

    
171
target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1,
172
                             target_ulong src2)
173
{
174
    target_ulong dst;
175

    
176
    /* Tag overflow occurs if either input has bits 0 or 1 set.  */
177
    if ((src1 | src2) & 3) {
178
        goto tag_overflow;
179
    }
180

    
181
    dst = src1 + src2;
182

    
183
    /* Tag overflow occurs if the addition overflows.  */
184
    if (~(src1 ^ src2) & (src1 ^ dst) & (1u << 31)) {
185
        goto tag_overflow;
186
    }
187

    
188
    /* Only modify the CC after any exceptions have been generated.  */
189
    env->cc_op = CC_OP_TADDTV;
190
    env->cc_src = src1;
191
    env->cc_src2 = src2;
192
    env->cc_dst = dst;
193
    return dst;
194

    
195
 tag_overflow:
196
    cpu_restore_state(env, GETPC());
197
    helper_raise_exception(env, TT_TOVF);
198
}
199

    
200
target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1,
201
                             target_ulong src2)
202
{
203
    target_ulong dst;
204

    
205
    /* Tag overflow occurs if either input has bits 0 or 1 set.  */
206
    if ((src1 | src2) & 3) {
207
        goto tag_overflow;
208
    }
209

    
210
    dst = src1 - src2;
211

    
212
    /* Tag overflow occurs if the subtraction overflows.  */
213
    if ((src1 ^ src2) & (src1 ^ dst) & (1u << 31)) {
214
        goto tag_overflow;
215
    }
216

    
217
    /* Only modify the CC after any exceptions have been generated.  */
218
    env->cc_op = CC_OP_TSUBTV;
219
    env->cc_src = src1;
220
    env->cc_src2 = src2;
221
    env->cc_dst = dst;
222
    return dst;
223

    
224
 tag_overflow:
225
    cpu_restore_state(env, GETPC());
226
    helper_raise_exception(env, TT_TOVF);
227
}