]> git.proxmox.com Git - mirror_qemu.git/blame - target-ppc/op_helper.c
better fpu state dump
[mirror_qemu.git] / target-ppc / op_helper.c
CommitLineData
9a64fbe4 1/*
3fc6c082 2 * PowerPC emulation helpers for qemu.
9a64fbe4 3 *
3fc6c082 4 * Copyright (c) 2003-2005 Jocelyn Mayer
9a64fbe4
FB
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
9a64fbe4
FB
23#define MEMSUFFIX _raw
24#include "op_helper_mem.h"
a541f297 25#if !defined(CONFIG_USER_ONLY)
9a64fbe4
FB
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 */
9fddaa0c 34void cpu_loop_exit(void)
9a64fbe4 35{
9fddaa0c 36 longjmp(env->jmp_env, 1);
9a64fbe4
FB
37}
38
9fddaa0c 39void do_raise_exception_err (uint32_t exception, int error_code)
9a64fbe4 40{
9fddaa0c
FB
41#if 0
42 printf("Raise exception %3x code : %d\n", exception, error_code);
43#endif
44 switch (exception) {
9fddaa0c
FB
45 case EXCP_PROGRAM:
46 if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
47 return;
48 break;
49 default:
50 break;
9a64fbe4 51}
9fddaa0c
FB
52 env->exception_index = exception;
53 env->error_code = error_code;
9a64fbe4
FB
54 cpu_loop_exit();
55 }
9fddaa0c
FB
56
57void do_raise_exception (uint32_t exception)
58{
59 do_raise_exception_err(exception, 0);
9a64fbe4
FB
60}
61
62/*****************************************************************************/
63/* Helpers for "fat" micro operations */
9a64fbe4
FB
64/* shift right arithmetic helper */
65void do_sraw (void)
66{
67 int32_t ret;
68
69 xer_ca = 0;
70 if (T1 & 0x20) {
71 ret = (-1) * (T0 >> 31);
4b3686fa 72 if (ret < 0 && (T0 & ~0x80000000) != 0)
9a64fbe4 73 xer_ca = 1;
4b3686fa
FB
74#if 1 // TRY
75 } else if (T1 == 0) {
76 ret = T0;
77#endif
9a64fbe4
FB
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 }
4b3686fa 83 T0 = ret;
9a64fbe4
FB
84}
85
86/* Floating point operations helpers */
9a64fbe4
FB
87void do_fctiw (void)
88{
89 union {
90 double d;
91 uint64_t i;
4ecc3190 92 } p;
9a64fbe4 93
4ecc3190 94 /* XXX: higher bits are not supposed to be significant.
3fc6c082 95 * to make tests easier, return the same as a real PowerPC 750 (aka G3)
4ecc3190
FB
96 */
97 p.i = float64_to_int32(FT0, &env->fp_status);
98 p.i |= 0xFFF80000ULL << 32;
99 FT0 = p.d;
9a64fbe4
FB
100}
101
102void do_fctiwz (void)
103{
104 union {
105 double d;
106 uint64_t i;
4ecc3190
FB
107 } p;
108
109 /* XXX: higher bits are not supposed to be significant.
3fc6c082 110 * to make tests easier, return the same as a real PowerPC 750 (aka G3)
4ecc3190
FB
111 */
112 p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status);
113 p.i |= 0xFFF80000ULL << 32;
114 FT0 = p.d;
9a64fbe4
FB
115}
116
4b3686fa
FB
117void do_fnmadd (void)
118{
4ecc3190
FB
119 FT0 = (FT0 * FT1) + FT2;
120 if (!isnan(FT0))
121 FT0 = -FT0;
4b3686fa
FB
122}
123
124void do_fnmsub (void)
125{
4ecc3190
FB
126 FT0 = (FT0 * FT1) - FT2;
127 if (!isnan(FT0))
128 FT0 = -FT0;
4b3686fa
FB
129}
130
4ecc3190 131void do_fdiv (void)
1ef59d0a 132{
4ecc3190
FB
133 if (FT0 == -0.0 && FT1 == -0.0)
134 FT0 = 0.0 / 0.0;
135 else
136 FT0 /= FT1;
1ef59d0a
FB
137}
138
9a64fbe4
FB
139void do_fsqrt (void)
140{
141 FT0 = sqrt(FT0);
142}
143
9a64fbe4
FB
144void do_fres (void)
145{
4ecc3190
FB
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 }
9a64fbe4
FB
168}
169
4ecc3190 170void do_frsqrte (void)
9a64fbe4 171{
4ecc3190
FB
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 }
9a64fbe4
FB
195}
196
197void do_fsel (void)
198{
199 if (FT0 >= 0)
9a64fbe4 200 FT0 = FT1;
4ecc3190
FB
201 else
202 FT0 = FT2;
9a64fbe4
FB
203}
204
205void do_fcmpu (void)
206{
9a64fbe4
FB
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 }
4b3686fa 218 env->fpscr[3] = T0;
9a64fbe4
FB
219}
220
221void 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 }
4b3686fa 242 env->fpscr[3] = T0;
9a64fbe4
FB
243}
244
245void do_fabs (void)
246{
4ecc3190
FB
247 union {
248 double d;
249 uint64_t i;
250 } p;
251
252 p.d = FT0;
253 p.i &= ~0x8000000000000000ULL;
254 FT0 = p.d;
9a64fbe4
FB
255}
256
257void do_fnabs (void)
258{
4ecc3190
FB
259 union {
260 double d;
261 uint64_t i;
262 } p;
263
264 p.d = FT0;
265 p.i |= 0x8000000000000000ULL;
266 FT0 = p.d;
9a64fbe4
FB
267}
268
269/* Instruction cache invalidation helper */
985a19d6
FB
270#define ICACHE_LINE_SIZE 32
271
4b3686fa
FB
272void do_check_reservation (void)
273{
18fba28c 274 if ((env->reserve & ~0x03) == T0)
4b3686fa
FB
275 env->reserve = -1;
276}
277
9a64fbe4
FB
278void do_icbi (void)
279{
985a19d6
FB
280 /* Invalidate one cache line */
281 T0 &= ~(ICACHE_LINE_SIZE - 1);
282 tb_invalidate_page_range(T0, T0 + ICACHE_LINE_SIZE);
9a64fbe4
FB
283}
284
285/* TLB invalidation helpers */
286void do_tlbia (void)
287{
ad081323 288 tlb_flush(env, 1);
9a64fbe4
FB
289}
290
291void do_tlbie (void)
292{
293 tlb_flush_page(env, T0);
294}
295