xref: /openbmc/qemu/target/sparc/helper.c (revision fcf5ef2a)
1*fcf5ef2aSThomas Huth /*
2*fcf5ef2aSThomas Huth  *  Misc Sparc helpers
3*fcf5ef2aSThomas Huth  *
4*fcf5ef2aSThomas Huth  *  Copyright (c) 2003-2005 Fabrice Bellard
5*fcf5ef2aSThomas Huth  *
6*fcf5ef2aSThomas Huth  * This library is free software; you can redistribute it and/or
7*fcf5ef2aSThomas Huth  * modify it under the terms of the GNU Lesser General Public
8*fcf5ef2aSThomas Huth  * License as published by the Free Software Foundation; either
9*fcf5ef2aSThomas Huth  * version 2 of the License, or (at your option) any later version.
10*fcf5ef2aSThomas Huth  *
11*fcf5ef2aSThomas Huth  * This library is distributed in the hope that it will be useful,
12*fcf5ef2aSThomas Huth  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*fcf5ef2aSThomas Huth  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14*fcf5ef2aSThomas Huth  * Lesser General Public License for more details.
15*fcf5ef2aSThomas Huth  *
16*fcf5ef2aSThomas Huth  * You should have received a copy of the GNU Lesser General Public
17*fcf5ef2aSThomas Huth  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18*fcf5ef2aSThomas Huth  */
19*fcf5ef2aSThomas Huth 
20*fcf5ef2aSThomas Huth #include "qemu/osdep.h"
21*fcf5ef2aSThomas Huth #include "cpu.h"
22*fcf5ef2aSThomas Huth #include "exec/exec-all.h"
23*fcf5ef2aSThomas Huth #include "qemu/host-utils.h"
24*fcf5ef2aSThomas Huth #include "exec/helper-proto.h"
25*fcf5ef2aSThomas Huth #include "sysemu/sysemu.h"
26*fcf5ef2aSThomas Huth 
27*fcf5ef2aSThomas Huth void cpu_raise_exception_ra(CPUSPARCState *env, int tt, uintptr_t ra)
28*fcf5ef2aSThomas Huth {
29*fcf5ef2aSThomas Huth     CPUState *cs = CPU(sparc_env_get_cpu(env));
30*fcf5ef2aSThomas Huth 
31*fcf5ef2aSThomas Huth     cs->exception_index = tt;
32*fcf5ef2aSThomas Huth     cpu_loop_exit_restore(cs, ra);
33*fcf5ef2aSThomas Huth }
34*fcf5ef2aSThomas Huth 
35*fcf5ef2aSThomas Huth void helper_raise_exception(CPUSPARCState *env, int tt)
36*fcf5ef2aSThomas Huth {
37*fcf5ef2aSThomas Huth     CPUState *cs = CPU(sparc_env_get_cpu(env));
38*fcf5ef2aSThomas Huth 
39*fcf5ef2aSThomas Huth     cs->exception_index = tt;
40*fcf5ef2aSThomas Huth     cpu_loop_exit(cs);
41*fcf5ef2aSThomas Huth }
42*fcf5ef2aSThomas Huth 
43*fcf5ef2aSThomas Huth void helper_debug(CPUSPARCState *env)
44*fcf5ef2aSThomas Huth {
45*fcf5ef2aSThomas Huth     CPUState *cs = CPU(sparc_env_get_cpu(env));
46*fcf5ef2aSThomas Huth 
47*fcf5ef2aSThomas Huth     cs->exception_index = EXCP_DEBUG;
48*fcf5ef2aSThomas Huth     cpu_loop_exit(cs);
49*fcf5ef2aSThomas Huth }
50*fcf5ef2aSThomas Huth 
51*fcf5ef2aSThomas Huth #ifdef TARGET_SPARC64
52*fcf5ef2aSThomas Huth target_ulong helper_popc(target_ulong val)
53*fcf5ef2aSThomas Huth {
54*fcf5ef2aSThomas Huth     return ctpop64(val);
55*fcf5ef2aSThomas Huth }
56*fcf5ef2aSThomas Huth 
57*fcf5ef2aSThomas Huth void helper_tick_set_count(void *opaque, uint64_t count)
58*fcf5ef2aSThomas Huth {
59*fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY)
60*fcf5ef2aSThomas Huth     cpu_tick_set_count(opaque, count);
61*fcf5ef2aSThomas Huth #endif
62*fcf5ef2aSThomas Huth }
63*fcf5ef2aSThomas Huth 
64*fcf5ef2aSThomas Huth uint64_t helper_tick_get_count(CPUSPARCState *env, void *opaque, int mem_idx)
65*fcf5ef2aSThomas Huth {
66*fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY)
67*fcf5ef2aSThomas Huth     CPUTimer *timer = opaque;
68*fcf5ef2aSThomas Huth 
69*fcf5ef2aSThomas Huth     if (timer->npt && mem_idx < MMU_KERNEL_IDX) {
70*fcf5ef2aSThomas Huth         cpu_raise_exception_ra(env, TT_PRIV_INSN, GETPC());
71*fcf5ef2aSThomas Huth     }
72*fcf5ef2aSThomas Huth 
73*fcf5ef2aSThomas Huth     return cpu_tick_get_count(timer);
74*fcf5ef2aSThomas Huth #else
75*fcf5ef2aSThomas Huth     return 0;
76*fcf5ef2aSThomas Huth #endif
77*fcf5ef2aSThomas Huth }
78*fcf5ef2aSThomas Huth 
79*fcf5ef2aSThomas Huth void helper_tick_set_limit(void *opaque, uint64_t limit)
80*fcf5ef2aSThomas Huth {
81*fcf5ef2aSThomas Huth #if !defined(CONFIG_USER_ONLY)
82*fcf5ef2aSThomas Huth     cpu_tick_set_limit(opaque, limit);
83*fcf5ef2aSThomas Huth #endif
84*fcf5ef2aSThomas Huth }
85*fcf5ef2aSThomas Huth #endif
86*fcf5ef2aSThomas Huth 
87*fcf5ef2aSThomas Huth static target_ulong do_udiv(CPUSPARCState *env, target_ulong a,
88*fcf5ef2aSThomas Huth                             target_ulong b, int cc, uintptr_t ra)
89*fcf5ef2aSThomas Huth {
90*fcf5ef2aSThomas Huth     int overflow = 0;
91*fcf5ef2aSThomas Huth     uint64_t x0;
92*fcf5ef2aSThomas Huth     uint32_t x1;
93*fcf5ef2aSThomas Huth 
94*fcf5ef2aSThomas Huth     x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
95*fcf5ef2aSThomas Huth     x1 = (b & 0xffffffff);
96*fcf5ef2aSThomas Huth 
97*fcf5ef2aSThomas Huth     if (x1 == 0) {
98*fcf5ef2aSThomas Huth         cpu_raise_exception_ra(env, TT_DIV_ZERO, ra);
99*fcf5ef2aSThomas Huth     }
100*fcf5ef2aSThomas Huth 
101*fcf5ef2aSThomas Huth     x0 = x0 / x1;
102*fcf5ef2aSThomas Huth     if (x0 > UINT32_MAX) {
103*fcf5ef2aSThomas Huth         x0 = UINT32_MAX;
104*fcf5ef2aSThomas Huth         overflow = 1;
105*fcf5ef2aSThomas Huth     }
106*fcf5ef2aSThomas Huth 
107*fcf5ef2aSThomas Huth     if (cc) {
108*fcf5ef2aSThomas Huth         env->cc_dst = x0;
109*fcf5ef2aSThomas Huth         env->cc_src2 = overflow;
110*fcf5ef2aSThomas Huth         env->cc_op = CC_OP_DIV;
111*fcf5ef2aSThomas Huth     }
112*fcf5ef2aSThomas Huth     return x0;
113*fcf5ef2aSThomas Huth }
114*fcf5ef2aSThomas Huth 
115*fcf5ef2aSThomas Huth target_ulong helper_udiv(CPUSPARCState *env, target_ulong a, target_ulong b)
116*fcf5ef2aSThomas Huth {
117*fcf5ef2aSThomas Huth     return do_udiv(env, a, b, 0, GETPC());
118*fcf5ef2aSThomas Huth }
119*fcf5ef2aSThomas Huth 
120*fcf5ef2aSThomas Huth target_ulong helper_udiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
121*fcf5ef2aSThomas Huth {
122*fcf5ef2aSThomas Huth     return do_udiv(env, a, b, 1, GETPC());
123*fcf5ef2aSThomas Huth }
124*fcf5ef2aSThomas Huth 
125*fcf5ef2aSThomas Huth static target_ulong do_sdiv(CPUSPARCState *env, target_ulong a,
126*fcf5ef2aSThomas Huth                             target_ulong b, int cc, uintptr_t ra)
127*fcf5ef2aSThomas Huth {
128*fcf5ef2aSThomas Huth     int overflow = 0;
129*fcf5ef2aSThomas Huth     int64_t x0;
130*fcf5ef2aSThomas Huth     int32_t x1;
131*fcf5ef2aSThomas Huth 
132*fcf5ef2aSThomas Huth     x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
133*fcf5ef2aSThomas Huth     x1 = (b & 0xffffffff);
134*fcf5ef2aSThomas Huth 
135*fcf5ef2aSThomas Huth     if (x1 == 0) {
136*fcf5ef2aSThomas Huth         cpu_raise_exception_ra(env, TT_DIV_ZERO, ra);
137*fcf5ef2aSThomas Huth     } else if (x1 == -1 && x0 == INT64_MIN) {
138*fcf5ef2aSThomas Huth         x0 = INT32_MAX;
139*fcf5ef2aSThomas Huth         overflow = 1;
140*fcf5ef2aSThomas Huth     } else {
141*fcf5ef2aSThomas Huth         x0 = x0 / x1;
142*fcf5ef2aSThomas Huth         if ((int32_t) x0 != x0) {
143*fcf5ef2aSThomas Huth             x0 = x0 < 0 ? INT32_MIN : INT32_MAX;
144*fcf5ef2aSThomas Huth             overflow = 1;
145*fcf5ef2aSThomas Huth         }
146*fcf5ef2aSThomas Huth     }
147*fcf5ef2aSThomas Huth 
148*fcf5ef2aSThomas Huth     if (cc) {
149*fcf5ef2aSThomas Huth         env->cc_dst = x0;
150*fcf5ef2aSThomas Huth         env->cc_src2 = overflow;
151*fcf5ef2aSThomas Huth         env->cc_op = CC_OP_DIV;
152*fcf5ef2aSThomas Huth     }
153*fcf5ef2aSThomas Huth     return x0;
154*fcf5ef2aSThomas Huth }
155*fcf5ef2aSThomas Huth 
156*fcf5ef2aSThomas Huth target_ulong helper_sdiv(CPUSPARCState *env, target_ulong a, target_ulong b)
157*fcf5ef2aSThomas Huth {
158*fcf5ef2aSThomas Huth     return do_sdiv(env, a, b, 0, GETPC());
159*fcf5ef2aSThomas Huth }
160*fcf5ef2aSThomas Huth 
161*fcf5ef2aSThomas Huth target_ulong helper_sdiv_cc(CPUSPARCState *env, target_ulong a, target_ulong b)
162*fcf5ef2aSThomas Huth {
163*fcf5ef2aSThomas Huth     return do_sdiv(env, a, b, 1, GETPC());
164*fcf5ef2aSThomas Huth }
165*fcf5ef2aSThomas Huth 
166*fcf5ef2aSThomas Huth #ifdef TARGET_SPARC64
167*fcf5ef2aSThomas Huth int64_t helper_sdivx(CPUSPARCState *env, int64_t a, int64_t b)
168*fcf5ef2aSThomas Huth {
169*fcf5ef2aSThomas Huth     if (b == 0) {
170*fcf5ef2aSThomas Huth         /* Raise divide by zero trap.  */
171*fcf5ef2aSThomas Huth         cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC());
172*fcf5ef2aSThomas Huth     } else if (b == -1) {
173*fcf5ef2aSThomas Huth         /* Avoid overflow trap with i386 divide insn.  */
174*fcf5ef2aSThomas Huth         return -a;
175*fcf5ef2aSThomas Huth     } else {
176*fcf5ef2aSThomas Huth         return a / b;
177*fcf5ef2aSThomas Huth     }
178*fcf5ef2aSThomas Huth }
179*fcf5ef2aSThomas Huth 
180*fcf5ef2aSThomas Huth uint64_t helper_udivx(CPUSPARCState *env, uint64_t a, uint64_t b)
181*fcf5ef2aSThomas Huth {
182*fcf5ef2aSThomas Huth     if (b == 0) {
183*fcf5ef2aSThomas Huth         /* Raise divide by zero trap.  */
184*fcf5ef2aSThomas Huth         cpu_raise_exception_ra(env, TT_DIV_ZERO, GETPC());
185*fcf5ef2aSThomas Huth     }
186*fcf5ef2aSThomas Huth     return a / b;
187*fcf5ef2aSThomas Huth }
188*fcf5ef2aSThomas Huth #endif
189*fcf5ef2aSThomas Huth 
190*fcf5ef2aSThomas Huth target_ulong helper_taddcctv(CPUSPARCState *env, target_ulong src1,
191*fcf5ef2aSThomas Huth                              target_ulong src2)
192*fcf5ef2aSThomas Huth {
193*fcf5ef2aSThomas Huth     target_ulong dst;
194*fcf5ef2aSThomas Huth 
195*fcf5ef2aSThomas Huth     /* Tag overflow occurs if either input has bits 0 or 1 set.  */
196*fcf5ef2aSThomas Huth     if ((src1 | src2) & 3) {
197*fcf5ef2aSThomas Huth         goto tag_overflow;
198*fcf5ef2aSThomas Huth     }
199*fcf5ef2aSThomas Huth 
200*fcf5ef2aSThomas Huth     dst = src1 + src2;
201*fcf5ef2aSThomas Huth 
202*fcf5ef2aSThomas Huth     /* Tag overflow occurs if the addition overflows.  */
203*fcf5ef2aSThomas Huth     if (~(src1 ^ src2) & (src1 ^ dst) & (1u << 31)) {
204*fcf5ef2aSThomas Huth         goto tag_overflow;
205*fcf5ef2aSThomas Huth     }
206*fcf5ef2aSThomas Huth 
207*fcf5ef2aSThomas Huth     /* Only modify the CC after any exceptions have been generated.  */
208*fcf5ef2aSThomas Huth     env->cc_op = CC_OP_TADDTV;
209*fcf5ef2aSThomas Huth     env->cc_src = src1;
210*fcf5ef2aSThomas Huth     env->cc_src2 = src2;
211*fcf5ef2aSThomas Huth     env->cc_dst = dst;
212*fcf5ef2aSThomas Huth     return dst;
213*fcf5ef2aSThomas Huth 
214*fcf5ef2aSThomas Huth  tag_overflow:
215*fcf5ef2aSThomas Huth     cpu_raise_exception_ra(env, TT_TOVF, GETPC());
216*fcf5ef2aSThomas Huth }
217*fcf5ef2aSThomas Huth 
218*fcf5ef2aSThomas Huth target_ulong helper_tsubcctv(CPUSPARCState *env, target_ulong src1,
219*fcf5ef2aSThomas Huth                              target_ulong src2)
220*fcf5ef2aSThomas Huth {
221*fcf5ef2aSThomas Huth     target_ulong dst;
222*fcf5ef2aSThomas Huth 
223*fcf5ef2aSThomas Huth     /* Tag overflow occurs if either input has bits 0 or 1 set.  */
224*fcf5ef2aSThomas Huth     if ((src1 | src2) & 3) {
225*fcf5ef2aSThomas Huth         goto tag_overflow;
226*fcf5ef2aSThomas Huth     }
227*fcf5ef2aSThomas Huth 
228*fcf5ef2aSThomas Huth     dst = src1 - src2;
229*fcf5ef2aSThomas Huth 
230*fcf5ef2aSThomas Huth     /* Tag overflow occurs if the subtraction overflows.  */
231*fcf5ef2aSThomas Huth     if ((src1 ^ src2) & (src1 ^ dst) & (1u << 31)) {
232*fcf5ef2aSThomas Huth         goto tag_overflow;
233*fcf5ef2aSThomas Huth     }
234*fcf5ef2aSThomas Huth 
235*fcf5ef2aSThomas Huth     /* Only modify the CC after any exceptions have been generated.  */
236*fcf5ef2aSThomas Huth     env->cc_op = CC_OP_TSUBTV;
237*fcf5ef2aSThomas Huth     env->cc_src = src1;
238*fcf5ef2aSThomas Huth     env->cc_src2 = src2;
239*fcf5ef2aSThomas Huth     env->cc_dst = dst;
240*fcf5ef2aSThomas Huth     return dst;
241*fcf5ef2aSThomas Huth 
242*fcf5ef2aSThomas Huth  tag_overflow:
243*fcf5ef2aSThomas Huth     cpu_raise_exception_ra(env, TT_TOVF, GETPC());
244*fcf5ef2aSThomas Huth }
245*fcf5ef2aSThomas Huth 
246*fcf5ef2aSThomas Huth #ifndef TARGET_SPARC64
247*fcf5ef2aSThomas Huth void helper_power_down(CPUSPARCState *env)
248*fcf5ef2aSThomas Huth {
249*fcf5ef2aSThomas Huth     CPUState *cs = CPU(sparc_env_get_cpu(env));
250*fcf5ef2aSThomas Huth 
251*fcf5ef2aSThomas Huth     cs->halted = 1;
252*fcf5ef2aSThomas Huth     cs->exception_index = EXCP_HLT;
253*fcf5ef2aSThomas Huth     env->pc = env->npc;
254*fcf5ef2aSThomas Huth     env->npc = env->pc + 4;
255*fcf5ef2aSThomas Huth     cpu_loop_exit(cs);
256*fcf5ef2aSThomas Huth }
257*fcf5ef2aSThomas Huth #endif
258