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