]> git.proxmox.com Git - mirror_qemu.git/blob - target-ppc/op_helper.c
better fpu state dump
[mirror_qemu.git] / target-ppc / op_helper.c
1 /*
2 * PowerPC emulation helpers for qemu.
3 *
4 * Copyright (c) 2003-2005 Jocelyn Mayer
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, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20 #include <math.h>
21 #include "exec.h"
22
23 #define MEMSUFFIX _raw
24 #include "op_helper_mem.h"
25 #if !defined(CONFIG_USER_ONLY)
26 #define MEMSUFFIX _user
27 #include "op_helper_mem.h"
28 #define MEMSUFFIX _kernel
29 #include "op_helper_mem.h"
30 #endif
31
32 /*****************************************************************************/
33 /* Exceptions processing helpers */
34 void cpu_loop_exit(void)
35 {
36 longjmp(env->jmp_env, 1);
37 }
38
39 void do_raise_exception_err (uint32_t exception, int error_code)
40 {
41 #if 0
42 printf("Raise exception %3x code : %d\n", exception, error_code);
43 #endif
44 switch (exception) {
45 case EXCP_PROGRAM:
46 if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
47 return;
48 break;
49 default:
50 break;
51 }
52 env->exception_index = exception;
53 env->error_code = error_code;
54 cpu_loop_exit();
55 }
56
57 void do_raise_exception (uint32_t exception)
58 {
59 do_raise_exception_err(exception, 0);
60 }
61
62 /*****************************************************************************/
63 /* Helpers for "fat" micro operations */
64 /* shift right arithmetic helper */
65 void do_sraw (void)
66 {
67 int32_t ret;
68
69 xer_ca = 0;
70 if (T1 & 0x20) {
71 ret = (-1) * (T0 >> 31);
72 if (ret < 0 && (T0 & ~0x80000000) != 0)
73 xer_ca = 1;
74 #if 1 // TRY
75 } else if (T1 == 0) {
76 ret = T0;
77 #endif
78 } else {
79 ret = (int32_t)T0 >> (T1 & 0x1f);
80 if (ret < 0 && ((int32_t)T0 & ((1 << T1) - 1)) != 0)
81 xer_ca = 1;
82 }
83 T0 = ret;
84 }
85
86 /* Floating point operations helpers */
87 void do_fctiw (void)
88 {
89 union {
90 double d;
91 uint64_t i;
92 } p;
93
94 /* XXX: higher bits are not supposed to be significant.
95 * to make tests easier, return the same as a real PowerPC 750 (aka G3)
96 */
97 p.i = float64_to_int32(FT0, &env->fp_status);
98 p.i |= 0xFFF80000ULL << 32;
99 FT0 = p.d;
100 }
101
102 void do_fctiwz (void)
103 {
104 union {
105 double d;
106 uint64_t i;
107 } p;
108
109 /* XXX: higher bits are not supposed to be significant.
110 * to make tests easier, return the same as a real PowerPC 750 (aka G3)
111 */
112 p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status);
113 p.i |= 0xFFF80000ULL << 32;
114 FT0 = p.d;
115 }
116
117 void do_fnmadd (void)
118 {
119 FT0 = (FT0 * FT1) + FT2;
120 if (!isnan(FT0))
121 FT0 = -FT0;
122 }
123
124 void do_fnmsub (void)
125 {
126 FT0 = (FT0 * FT1) - FT2;
127 if (!isnan(FT0))
128 FT0 = -FT0;
129 }
130
131 void do_fdiv (void)
132 {
133 if (FT0 == -0.0 && FT1 == -0.0)
134 FT0 = 0.0 / 0.0;
135 else
136 FT0 /= FT1;
137 }
138
139 void do_fsqrt (void)
140 {
141 FT0 = sqrt(FT0);
142 }
143
144 void do_fres (void)
145 {
146 union {
147 double d;
148 uint64_t i;
149 } p;
150
151 if (isnormal(FT0)) {
152 FT0 = (float)(1.0 / FT0);
153 } else {
154 p.d = FT0;
155 if (p.i == 0x8000000000000000ULL) {
156 p.i = 0xFFF0000000000000ULL;
157 } else if (p.i == 0x0000000000000000ULL) {
158 p.i = 0x7FF0000000000000ULL;
159 } else if (isnan(FT0)) {
160 p.i = 0x7FF8000000000000ULL;
161 } else if (FT0 < 0.0) {
162 p.i = 0x8000000000000000ULL;
163 } else {
164 p.i = 0x0000000000000000ULL;
165 }
166 FT0 = p.d;
167 }
168 }
169
170 void do_frsqrte (void)
171 {
172 union {
173 double d;
174 uint64_t i;
175 } p;
176
177 if (isnormal(FT0) && FT0 > 0.0) {
178 FT0 = (float)(1.0 / sqrt(FT0));
179 } else {
180 p.d = FT0;
181 if (p.i == 0x8000000000000000ULL) {
182 p.i = 0xFFF0000000000000ULL;
183 } else if (p.i == 0x0000000000000000ULL) {
184 p.i = 0x7FF0000000000000ULL;
185 } else if (isnan(FT0)) {
186 if (!(p.i & 0x0008000000000000ULL))
187 p.i |= 0x000FFFFFFFFFFFFFULL;
188 } else if (FT0 < 0) {
189 p.i = 0x7FF8000000000000ULL;
190 } else {
191 p.i = 0x0000000000000000ULL;
192 }
193 FT0 = p.d;
194 }
195 }
196
197 void do_fsel (void)
198 {
199 if (FT0 >= 0)
200 FT0 = FT1;
201 else
202 FT0 = FT2;
203 }
204
205 void do_fcmpu (void)
206 {
207 if (isnan(FT0) || isnan(FT1)) {
208 T0 = 0x01;
209 env->fpscr[4] |= 0x1;
210 env->fpscr[6] |= 0x1;
211 } else if (FT0 < FT1) {
212 T0 = 0x08;
213 } else if (FT0 > FT1) {
214 T0 = 0x04;
215 } else {
216 T0 = 0x02;
217 }
218 env->fpscr[3] = T0;
219 }
220
221 void do_fcmpo (void)
222 {
223 env->fpscr[4] &= ~0x1;
224 if (isnan(FT0) || isnan(FT1)) {
225 T0 = 0x01;
226 env->fpscr[4] |= 0x1;
227 /* I don't know how to test "quiet" nan... */
228 if (0 /* || ! quiet_nan(...) */) {
229 env->fpscr[6] |= 0x1;
230 if (!(env->fpscr[1] & 0x8))
231 env->fpscr[4] |= 0x8;
232 } else {
233 env->fpscr[4] |= 0x8;
234 }
235 } else if (FT0 < FT1) {
236 T0 = 0x08;
237 } else if (FT0 > FT1) {
238 T0 = 0x04;
239 } else {
240 T0 = 0x02;
241 }
242 env->fpscr[3] = T0;
243 }
244
245 void do_fabs (void)
246 {
247 union {
248 double d;
249 uint64_t i;
250 } p;
251
252 p.d = FT0;
253 p.i &= ~0x8000000000000000ULL;
254 FT0 = p.d;
255 }
256
257 void do_fnabs (void)
258 {
259 union {
260 double d;
261 uint64_t i;
262 } p;
263
264 p.d = FT0;
265 p.i |= 0x8000000000000000ULL;
266 FT0 = p.d;
267 }
268
269 /* Instruction cache invalidation helper */
270 #define ICACHE_LINE_SIZE 32
271
272 void do_check_reservation (void)
273 {
274 if ((env->reserve & ~0x03) == T0)
275 env->reserve = -1;
276 }
277
278 void do_icbi (void)
279 {
280 /* Invalidate one cache line */
281 T0 &= ~(ICACHE_LINE_SIZE - 1);
282 tb_invalidate_page_range(T0, T0 + ICACHE_LINE_SIZE);
283 }
284
285 /* TLB invalidation helpers */
286 void do_tlbia (void)
287 {
288 tlb_flush(env, 1);
289 }
290
291 void do_tlbie (void)
292 {
293 tlb_flush_page(env, T0);
294 }
295