root / target-ppc / op_helper.c @ 70ead434
History | View | Annotate | Download (12.9 kB)
1 | 9a64fbe4 | bellard | /*
|
---|---|---|---|
2 | 3fc6c082 | bellard | * PowerPC emulation helpers for qemu.
|
3 | 9a64fbe4 | bellard | *
|
4 | 3fc6c082 | bellard | * Copyright (c) 2003-2005 Jocelyn Mayer
|
5 | 9a64fbe4 | bellard | *
|
6 | 9a64fbe4 | bellard | * This library is free software; you can redistribute it and/or
|
7 | 9a64fbe4 | bellard | * modify it under the terms of the GNU Lesser General Public
|
8 | 9a64fbe4 | bellard | * License as published by the Free Software Foundation; either
|
9 | 9a64fbe4 | bellard | * version 2 of the License, or (at your option) any later version.
|
10 | 9a64fbe4 | bellard | *
|
11 | 9a64fbe4 | bellard | * This library is distributed in the hope that it will be useful,
|
12 | 9a64fbe4 | bellard | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | 9a64fbe4 | bellard | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 | 9a64fbe4 | bellard | * Lesser General Public License for more details.
|
15 | 9a64fbe4 | bellard | *
|
16 | 9a64fbe4 | bellard | * You should have received a copy of the GNU Lesser General Public
|
17 | 9a64fbe4 | bellard | * License along with this library; if not, write to the Free Software
|
18 | 9a64fbe4 | bellard | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
19 | 9a64fbe4 | bellard | */
|
20 | 9a64fbe4 | bellard | #include "exec.h" |
21 | 9a64fbe4 | bellard | |
22 | 9a64fbe4 | bellard | #define MEMSUFFIX _raw
|
23 | 9a64fbe4 | bellard | #include "op_helper_mem.h" |
24 | a541f297 | bellard | #if !defined(CONFIG_USER_ONLY)
|
25 | 9a64fbe4 | bellard | #define MEMSUFFIX _user
|
26 | 9a64fbe4 | bellard | #include "op_helper_mem.h" |
27 | 9a64fbe4 | bellard | #define MEMSUFFIX _kernel
|
28 | 9a64fbe4 | bellard | #include "op_helper_mem.h" |
29 | 9a64fbe4 | bellard | #endif
|
30 | 9a64fbe4 | bellard | |
31 | fdabc366 | bellard | //#define DEBUG_OP
|
32 | fdabc366 | bellard | //#define DEBUG_EXCEPTIONS
|
33 | fdabc366 | bellard | //#define FLUSH_ALL_TLBS
|
34 | fdabc366 | bellard | |
35 | fdabc366 | bellard | #define Ts0 (long)((target_long)T0) |
36 | fdabc366 | bellard | #define Ts1 (long)((target_long)T1) |
37 | fdabc366 | bellard | #define Ts2 (long)((target_long)T2) |
38 | fdabc366 | bellard | |
39 | 9a64fbe4 | bellard | /*****************************************************************************/
|
40 | 9a64fbe4 | bellard | /* Exceptions processing helpers */
|
41 | 9fddaa0c | bellard | void cpu_loop_exit(void) |
42 | 9a64fbe4 | bellard | { |
43 | 9fddaa0c | bellard | longjmp(env->jmp_env, 1);
|
44 | 9a64fbe4 | bellard | } |
45 | 9a64fbe4 | bellard | |
46 | 9fddaa0c | bellard | void do_raise_exception_err (uint32_t exception, int error_code) |
47 | 9a64fbe4 | bellard | { |
48 | 9fddaa0c | bellard | #if 0
|
49 | 9fddaa0c | bellard | printf("Raise exception %3x code : %d\n", exception, error_code);
|
50 | 9fddaa0c | bellard | #endif
|
51 | 9fddaa0c | bellard | switch (exception) {
|
52 | 9fddaa0c | bellard | case EXCP_PROGRAM:
|
53 | 9fddaa0c | bellard | if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0) |
54 | 9fddaa0c | bellard | return;
|
55 | 9fddaa0c | bellard | break;
|
56 | 9fddaa0c | bellard | default:
|
57 | 9fddaa0c | bellard | break;
|
58 | 9a64fbe4 | bellard | } |
59 | 9fddaa0c | bellard | env->exception_index = exception; |
60 | 9fddaa0c | bellard | env->error_code = error_code; |
61 | 9a64fbe4 | bellard | cpu_loop_exit(); |
62 | 9a64fbe4 | bellard | } |
63 | 9fddaa0c | bellard | |
64 | 9fddaa0c | bellard | void do_raise_exception (uint32_t exception)
|
65 | 9fddaa0c | bellard | { |
66 | 9fddaa0c | bellard | do_raise_exception_err(exception, 0);
|
67 | 9a64fbe4 | bellard | } |
68 | 9a64fbe4 | bellard | |
69 | 9a64fbe4 | bellard | /*****************************************************************************/
|
70 | fdabc366 | bellard | /* Fixed point operations helpers */
|
71 | fdabc366 | bellard | void do_addo (void) |
72 | fdabc366 | bellard | { |
73 | fdabc366 | bellard | T2 = T0; |
74 | fdabc366 | bellard | T0 += T1; |
75 | fdabc366 | bellard | if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) { |
76 | fdabc366 | bellard | xer_ov = 0;
|
77 | fdabc366 | bellard | } else {
|
78 | fdabc366 | bellard | xer_so = 1;
|
79 | fdabc366 | bellard | xer_ov = 1;
|
80 | fdabc366 | bellard | } |
81 | fdabc366 | bellard | } |
82 | fdabc366 | bellard | |
83 | fdabc366 | bellard | void do_addco (void) |
84 | fdabc366 | bellard | { |
85 | fdabc366 | bellard | T2 = T0; |
86 | fdabc366 | bellard | T0 += T1; |
87 | fdabc366 | bellard | if (likely(T0 >= T2)) {
|
88 | fdabc366 | bellard | xer_ca = 0;
|
89 | fdabc366 | bellard | } else {
|
90 | fdabc366 | bellard | xer_ca = 1;
|
91 | fdabc366 | bellard | } |
92 | fdabc366 | bellard | if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) { |
93 | fdabc366 | bellard | xer_ov = 0;
|
94 | fdabc366 | bellard | } else {
|
95 | fdabc366 | bellard | xer_so = 1;
|
96 | fdabc366 | bellard | xer_ov = 1;
|
97 | fdabc366 | bellard | } |
98 | fdabc366 | bellard | } |
99 | fdabc366 | bellard | |
100 | fdabc366 | bellard | void do_adde (void) |
101 | fdabc366 | bellard | { |
102 | fdabc366 | bellard | T2 = T0; |
103 | fdabc366 | bellard | T0 += T1 + xer_ca; |
104 | fdabc366 | bellard | if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) { |
105 | fdabc366 | bellard | xer_ca = 0;
|
106 | fdabc366 | bellard | } else {
|
107 | fdabc366 | bellard | xer_ca = 1;
|
108 | fdabc366 | bellard | } |
109 | fdabc366 | bellard | } |
110 | fdabc366 | bellard | |
111 | fdabc366 | bellard | void do_addeo (void) |
112 | fdabc366 | bellard | { |
113 | fdabc366 | bellard | T2 = T0; |
114 | fdabc366 | bellard | T0 += T1 + xer_ca; |
115 | fdabc366 | bellard | if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) { |
116 | fdabc366 | bellard | xer_ca = 0;
|
117 | fdabc366 | bellard | } else {
|
118 | fdabc366 | bellard | xer_ca = 1;
|
119 | fdabc366 | bellard | } |
120 | fdabc366 | bellard | if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) { |
121 | fdabc366 | bellard | xer_ov = 0;
|
122 | fdabc366 | bellard | } else {
|
123 | fdabc366 | bellard | xer_so = 1;
|
124 | fdabc366 | bellard | xer_ov = 1;
|
125 | fdabc366 | bellard | } |
126 | fdabc366 | bellard | } |
127 | fdabc366 | bellard | |
128 | fdabc366 | bellard | void do_addmeo (void) |
129 | fdabc366 | bellard | { |
130 | fdabc366 | bellard | T1 = T0; |
131 | fdabc366 | bellard | T0 += xer_ca + (-1);
|
132 | fdabc366 | bellard | if (likely(!(T1 & (T1 ^ T0) & (1 << 31)))) { |
133 | fdabc366 | bellard | xer_ov = 0;
|
134 | fdabc366 | bellard | } else {
|
135 | fdabc366 | bellard | xer_so = 1;
|
136 | fdabc366 | bellard | xer_ov = 1;
|
137 | fdabc366 | bellard | } |
138 | fdabc366 | bellard | if (likely(T1 != 0)) |
139 | fdabc366 | bellard | xer_ca = 1;
|
140 | fdabc366 | bellard | } |
141 | fdabc366 | bellard | |
142 | fdabc366 | bellard | void do_addzeo (void) |
143 | fdabc366 | bellard | { |
144 | fdabc366 | bellard | T1 = T0; |
145 | fdabc366 | bellard | T0 += xer_ca; |
146 | fdabc366 | bellard | if (likely(!((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)))) { |
147 | fdabc366 | bellard | xer_ov = 0;
|
148 | fdabc366 | bellard | } else {
|
149 | fdabc366 | bellard | xer_so = 1;
|
150 | fdabc366 | bellard | xer_ov = 1;
|
151 | fdabc366 | bellard | } |
152 | fdabc366 | bellard | if (likely(T0 >= T1)) {
|
153 | fdabc366 | bellard | xer_ca = 0;
|
154 | fdabc366 | bellard | } else {
|
155 | fdabc366 | bellard | xer_ca = 1;
|
156 | fdabc366 | bellard | } |
157 | fdabc366 | bellard | } |
158 | fdabc366 | bellard | |
159 | fdabc366 | bellard | void do_divwo (void) |
160 | fdabc366 | bellard | { |
161 | fdabc366 | bellard | if (likely(!((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0))) { |
162 | fdabc366 | bellard | xer_ov = 0;
|
163 | fdabc366 | bellard | T0 = (Ts0 / Ts1); |
164 | fdabc366 | bellard | } else {
|
165 | fdabc366 | bellard | xer_so = 1;
|
166 | fdabc366 | bellard | xer_ov = 1;
|
167 | fdabc366 | bellard | T0 = (-1) * ((uint32_t)T0 >> 31); |
168 | fdabc366 | bellard | } |
169 | fdabc366 | bellard | } |
170 | fdabc366 | bellard | |
171 | fdabc366 | bellard | void do_divwuo (void) |
172 | fdabc366 | bellard | { |
173 | fdabc366 | bellard | if (likely((uint32_t)T1 != 0)) { |
174 | fdabc366 | bellard | xer_ov = 0;
|
175 | fdabc366 | bellard | T0 = (uint32_t)T0 / (uint32_t)T1; |
176 | fdabc366 | bellard | } else {
|
177 | fdabc366 | bellard | xer_so = 1;
|
178 | fdabc366 | bellard | xer_ov = 1;
|
179 | fdabc366 | bellard | T0 = 0;
|
180 | fdabc366 | bellard | } |
181 | fdabc366 | bellard | } |
182 | fdabc366 | bellard | |
183 | fdabc366 | bellard | void do_mullwo (void) |
184 | fdabc366 | bellard | { |
185 | fdabc366 | bellard | int64_t res = (int64_t)Ts0 * (int64_t)Ts1; |
186 | fdabc366 | bellard | |
187 | fdabc366 | bellard | if (likely((int32_t)res == res)) {
|
188 | fdabc366 | bellard | xer_ov = 0;
|
189 | fdabc366 | bellard | } else {
|
190 | fdabc366 | bellard | xer_ov = 1;
|
191 | fdabc366 | bellard | xer_so = 1;
|
192 | fdabc366 | bellard | } |
193 | fdabc366 | bellard | T0 = (int32_t)res; |
194 | fdabc366 | bellard | } |
195 | fdabc366 | bellard | |
196 | fdabc366 | bellard | void do_nego (void) |
197 | fdabc366 | bellard | { |
198 | fdabc366 | bellard | if (likely(T0 != INT32_MIN)) {
|
199 | fdabc366 | bellard | xer_ov = 0;
|
200 | fdabc366 | bellard | T0 = -Ts0; |
201 | fdabc366 | bellard | } else {
|
202 | fdabc366 | bellard | xer_ov = 1;
|
203 | fdabc366 | bellard | xer_so = 1;
|
204 | fdabc366 | bellard | } |
205 | fdabc366 | bellard | } |
206 | fdabc366 | bellard | |
207 | fdabc366 | bellard | void do_subfo (void) |
208 | fdabc366 | bellard | { |
209 | fdabc366 | bellard | T2 = T0; |
210 | fdabc366 | bellard | T0 = T1 - T0; |
211 | fdabc366 | bellard | if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) { |
212 | fdabc366 | bellard | xer_ov = 0;
|
213 | fdabc366 | bellard | } else {
|
214 | fdabc366 | bellard | xer_so = 1;
|
215 | fdabc366 | bellard | xer_ov = 1;
|
216 | fdabc366 | bellard | } |
217 | fdabc366 | bellard | RETURN(); |
218 | fdabc366 | bellard | } |
219 | fdabc366 | bellard | |
220 | fdabc366 | bellard | void do_subfco (void) |
221 | fdabc366 | bellard | { |
222 | fdabc366 | bellard | T2 = T0; |
223 | fdabc366 | bellard | T0 = T1 - T0; |
224 | fdabc366 | bellard | if (likely(T0 > T1)) {
|
225 | fdabc366 | bellard | xer_ca = 0;
|
226 | fdabc366 | bellard | } else {
|
227 | fdabc366 | bellard | xer_ca = 1;
|
228 | fdabc366 | bellard | } |
229 | fdabc366 | bellard | if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) { |
230 | fdabc366 | bellard | xer_ov = 0;
|
231 | fdabc366 | bellard | } else {
|
232 | fdabc366 | bellard | xer_so = 1;
|
233 | fdabc366 | bellard | xer_ov = 1;
|
234 | fdabc366 | bellard | } |
235 | fdabc366 | bellard | } |
236 | fdabc366 | bellard | |
237 | fdabc366 | bellard | void do_subfe (void) |
238 | fdabc366 | bellard | { |
239 | fdabc366 | bellard | T0 = T1 + ~T0 + xer_ca; |
240 | fdabc366 | bellard | if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) { |
241 | fdabc366 | bellard | xer_ca = 0;
|
242 | fdabc366 | bellard | } else {
|
243 | fdabc366 | bellard | xer_ca = 1;
|
244 | fdabc366 | bellard | } |
245 | fdabc366 | bellard | } |
246 | fdabc366 | bellard | |
247 | fdabc366 | bellard | void do_subfeo (void) |
248 | fdabc366 | bellard | { |
249 | fdabc366 | bellard | T2 = T0; |
250 | fdabc366 | bellard | T0 = T1 + ~T0 + xer_ca; |
251 | fdabc366 | bellard | if (likely(!((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)))) { |
252 | fdabc366 | bellard | xer_ov = 0;
|
253 | fdabc366 | bellard | } else {
|
254 | fdabc366 | bellard | xer_so = 1;
|
255 | fdabc366 | bellard | xer_ov = 1;
|
256 | fdabc366 | bellard | } |
257 | fdabc366 | bellard | if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) { |
258 | fdabc366 | bellard | xer_ca = 0;
|
259 | fdabc366 | bellard | } else {
|
260 | fdabc366 | bellard | xer_ca = 1;
|
261 | fdabc366 | bellard | } |
262 | fdabc366 | bellard | } |
263 | fdabc366 | bellard | |
264 | fdabc366 | bellard | void do_subfmeo (void) |
265 | fdabc366 | bellard | { |
266 | fdabc366 | bellard | T1 = T0; |
267 | fdabc366 | bellard | T0 = ~T0 + xer_ca - 1;
|
268 | fdabc366 | bellard | if (likely(!(~T1 & (~T1 ^ T0) & (1 << 31)))) { |
269 | fdabc366 | bellard | xer_ov = 0;
|
270 | fdabc366 | bellard | } else {
|
271 | fdabc366 | bellard | xer_so = 1;
|
272 | fdabc366 | bellard | xer_ov = 1;
|
273 | fdabc366 | bellard | } |
274 | fdabc366 | bellard | if (likely(T1 != -1)) |
275 | fdabc366 | bellard | xer_ca = 1;
|
276 | fdabc366 | bellard | } |
277 | fdabc366 | bellard | |
278 | fdabc366 | bellard | void do_subfzeo (void) |
279 | fdabc366 | bellard | { |
280 | fdabc366 | bellard | T1 = T0; |
281 | fdabc366 | bellard | T0 = ~T0 + xer_ca; |
282 | fdabc366 | bellard | if (likely(!((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)))) { |
283 | fdabc366 | bellard | xer_ov = 0;
|
284 | fdabc366 | bellard | } else {
|
285 | fdabc366 | bellard | xer_ov = 1;
|
286 | fdabc366 | bellard | xer_so = 1;
|
287 | fdabc366 | bellard | } |
288 | fdabc366 | bellard | if (likely(T0 >= ~T1)) {
|
289 | fdabc366 | bellard | xer_ca = 0;
|
290 | fdabc366 | bellard | } else {
|
291 | fdabc366 | bellard | xer_ca = 1;
|
292 | fdabc366 | bellard | } |
293 | fdabc366 | bellard | } |
294 | fdabc366 | bellard | |
295 | 9a64fbe4 | bellard | /* shift right arithmetic helper */
|
296 | 9a64fbe4 | bellard | void do_sraw (void) |
297 | 9a64fbe4 | bellard | { |
298 | 9a64fbe4 | bellard | int32_t ret; |
299 | 9a64fbe4 | bellard | |
300 | fdabc366 | bellard | if (likely(!(T1 & 0x20UL))) { |
301 | fdabc366 | bellard | if (likely(T1 != 0)) { |
302 | fdabc366 | bellard | ret = (int32_t)T0 >> (T1 & 0x1fUL);
|
303 | fdabc366 | bellard | if (likely(ret >= 0 || ((int32_t)T0 & ((1 << T1) - 1)) == 0)) { |
304 | 9a64fbe4 | bellard | xer_ca = 0;
|
305 | fdabc366 | bellard | } else {
|
306 | 9a64fbe4 | bellard | xer_ca = 1;
|
307 | fdabc366 | bellard | } |
308 | fdabc366 | bellard | } else {
|
309 | 4b3686fa | bellard | ret = T0; |
310 | fdabc366 | bellard | xer_ca = 0;
|
311 | fdabc366 | bellard | } |
312 | fdabc366 | bellard | } else {
|
313 | fdabc366 | bellard | ret = (-1) * ((uint32_t)T0 >> 31); |
314 | fdabc366 | bellard | if (likely(ret >= 0 || ((uint32_t)T0 & ~0x80000000UL) == 0)) { |
315 | fdabc366 | bellard | xer_ca = 0;
|
316 | 9a64fbe4 | bellard | } else {
|
317 | 9a64fbe4 | bellard | xer_ca = 1;
|
318 | 9a64fbe4 | bellard | } |
319 | fdabc366 | bellard | } |
320 | 4b3686fa | bellard | T0 = ret; |
321 | 9a64fbe4 | bellard | } |
322 | 9a64fbe4 | bellard | |
323 | fdabc366 | bellard | /*****************************************************************************/
|
324 | 9a64fbe4 | bellard | /* Floating point operations helpers */
|
325 | 9a64fbe4 | bellard | void do_fctiw (void) |
326 | 9a64fbe4 | bellard | { |
327 | 9a64fbe4 | bellard | union {
|
328 | 9a64fbe4 | bellard | double d;
|
329 | 9a64fbe4 | bellard | uint64_t i; |
330 | 4ecc3190 | bellard | } p; |
331 | 9a64fbe4 | bellard | |
332 | 4ecc3190 | bellard | /* XXX: higher bits are not supposed to be significant.
|
333 | 3fc6c082 | bellard | * to make tests easier, return the same as a real PowerPC 750 (aka G3)
|
334 | 4ecc3190 | bellard | */
|
335 | 4ecc3190 | bellard | p.i = float64_to_int32(FT0, &env->fp_status); |
336 | 4ecc3190 | bellard | p.i |= 0xFFF80000ULL << 32; |
337 | 4ecc3190 | bellard | FT0 = p.d; |
338 | 9a64fbe4 | bellard | } |
339 | 9a64fbe4 | bellard | |
340 | 9a64fbe4 | bellard | void do_fctiwz (void) |
341 | 9a64fbe4 | bellard | { |
342 | 9a64fbe4 | bellard | union {
|
343 | 9a64fbe4 | bellard | double d;
|
344 | 9a64fbe4 | bellard | uint64_t i; |
345 | 4ecc3190 | bellard | } p; |
346 | 4ecc3190 | bellard | |
347 | 4ecc3190 | bellard | /* XXX: higher bits are not supposed to be significant.
|
348 | 3fc6c082 | bellard | * to make tests easier, return the same as a real PowerPC 750 (aka G3)
|
349 | 4ecc3190 | bellard | */
|
350 | 4ecc3190 | bellard | p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status); |
351 | 4ecc3190 | bellard | p.i |= 0xFFF80000ULL << 32; |
352 | 4ecc3190 | bellard | FT0 = p.d; |
353 | 9a64fbe4 | bellard | } |
354 | 9a64fbe4 | bellard | |
355 | 4b3686fa | bellard | void do_fnmadd (void) |
356 | 4b3686fa | bellard | { |
357 | fdabc366 | bellard | FT0 = float64_mul(FT0, FT1, &env->fp_status); |
358 | fdabc366 | bellard | FT0 = float64_add(FT0, FT2, &env->fp_status); |
359 | fdabc366 | bellard | if (likely(!isnan(FT0)))
|
360 | fdabc366 | bellard | FT0 = float64_chs(FT0); |
361 | 4b3686fa | bellard | } |
362 | 4b3686fa | bellard | |
363 | 4b3686fa | bellard | void do_fnmsub (void) |
364 | 4b3686fa | bellard | { |
365 | fdabc366 | bellard | FT0 = float64_mul(FT0, FT1, &env->fp_status); |
366 | fdabc366 | bellard | FT0 = float64_sub(FT0, FT2, &env->fp_status); |
367 | fdabc366 | bellard | if (likely(!isnan(FT0)))
|
368 | fdabc366 | bellard | FT0 = float64_chs(FT0); |
369 | 1ef59d0a | bellard | } |
370 | 1ef59d0a | bellard | |
371 | 9a64fbe4 | bellard | void do_fsqrt (void) |
372 | 9a64fbe4 | bellard | { |
373 | fdabc366 | bellard | FT0 = float64_sqrt(FT0, &env->fp_status); |
374 | 9a64fbe4 | bellard | } |
375 | 9a64fbe4 | bellard | |
376 | 9a64fbe4 | bellard | void do_fres (void) |
377 | 9a64fbe4 | bellard | { |
378 | 4ecc3190 | bellard | union {
|
379 | 4ecc3190 | bellard | double d;
|
380 | 4ecc3190 | bellard | uint64_t i; |
381 | 4ecc3190 | bellard | } p; |
382 | 4ecc3190 | bellard | |
383 | fdabc366 | bellard | if (likely(isnormal(FT0))) {
|
384 | 4ecc3190 | bellard | FT0 = (float)(1.0 / FT0); |
385 | 4ecc3190 | bellard | } else {
|
386 | 4ecc3190 | bellard | p.d = FT0; |
387 | 4ecc3190 | bellard | if (p.i == 0x8000000000000000ULL) { |
388 | 4ecc3190 | bellard | p.i = 0xFFF0000000000000ULL;
|
389 | 4ecc3190 | bellard | } else if (p.i == 0x0000000000000000ULL) { |
390 | 4ecc3190 | bellard | p.i = 0x7FF0000000000000ULL;
|
391 | 4ecc3190 | bellard | } else if (isnan(FT0)) { |
392 | 4ecc3190 | bellard | p.i = 0x7FF8000000000000ULL;
|
393 | 4ecc3190 | bellard | } else if (FT0 < 0.0) { |
394 | 4ecc3190 | bellard | p.i = 0x8000000000000000ULL;
|
395 | 4ecc3190 | bellard | } else {
|
396 | 4ecc3190 | bellard | p.i = 0x0000000000000000ULL;
|
397 | 4ecc3190 | bellard | } |
398 | 4ecc3190 | bellard | FT0 = p.d; |
399 | 4ecc3190 | bellard | } |
400 | 9a64fbe4 | bellard | } |
401 | 9a64fbe4 | bellard | |
402 | 4ecc3190 | bellard | void do_frsqrte (void) |
403 | 9a64fbe4 | bellard | { |
404 | 4ecc3190 | bellard | union {
|
405 | 4ecc3190 | bellard | double d;
|
406 | 4ecc3190 | bellard | uint64_t i; |
407 | 4ecc3190 | bellard | } p; |
408 | 4ecc3190 | bellard | |
409 | fdabc366 | bellard | if (likely(isnormal(FT0) && FT0 > 0.0)) { |
410 | fdabc366 | bellard | FT0 = float64_sqrt(FT0, &env->fp_status); |
411 | fdabc366 | bellard | FT0 = float32_div(1.0, FT0, &env->fp_status); |
412 | 4ecc3190 | bellard | } else {
|
413 | 4ecc3190 | bellard | p.d = FT0; |
414 | 4ecc3190 | bellard | if (p.i == 0x8000000000000000ULL) { |
415 | 4ecc3190 | bellard | p.i = 0xFFF0000000000000ULL;
|
416 | 4ecc3190 | bellard | } else if (p.i == 0x0000000000000000ULL) { |
417 | 4ecc3190 | bellard | p.i = 0x7FF0000000000000ULL;
|
418 | 4ecc3190 | bellard | } else if (isnan(FT0)) { |
419 | 4ecc3190 | bellard | if (!(p.i & 0x0008000000000000ULL)) |
420 | 4ecc3190 | bellard | p.i |= 0x000FFFFFFFFFFFFFULL;
|
421 | 4ecc3190 | bellard | } else if (FT0 < 0) { |
422 | 4ecc3190 | bellard | p.i = 0x7FF8000000000000ULL;
|
423 | 4ecc3190 | bellard | } else {
|
424 | 4ecc3190 | bellard | p.i = 0x0000000000000000ULL;
|
425 | 4ecc3190 | bellard | } |
426 | 4ecc3190 | bellard | FT0 = p.d; |
427 | 4ecc3190 | bellard | } |
428 | 9a64fbe4 | bellard | } |
429 | 9a64fbe4 | bellard | |
430 | 9a64fbe4 | bellard | void do_fsel (void) |
431 | 9a64fbe4 | bellard | { |
432 | 9a64fbe4 | bellard | if (FT0 >= 0) |
433 | 9a64fbe4 | bellard | FT0 = FT1; |
434 | 4ecc3190 | bellard | else
|
435 | 4ecc3190 | bellard | FT0 = FT2; |
436 | 9a64fbe4 | bellard | } |
437 | 9a64fbe4 | bellard | |
438 | 9a64fbe4 | bellard | void do_fcmpu (void) |
439 | 9a64fbe4 | bellard | { |
440 | fdabc366 | bellard | if (likely(!isnan(FT0) && !isnan(FT1))) {
|
441 | fdabc366 | bellard | if (float64_lt(FT0, FT1, &env->fp_status)) {
|
442 | fdabc366 | bellard | T0 = 0x08UL;
|
443 | fdabc366 | bellard | } else if (!float64_le(FT0, FT1, &env->fp_status)) { |
444 | fdabc366 | bellard | T0 = 0x04UL;
|
445 | fdabc366 | bellard | } else {
|
446 | fdabc366 | bellard | T0 = 0x02UL;
|
447 | fdabc366 | bellard | } |
448 | fdabc366 | bellard | } else {
|
449 | fdabc366 | bellard | T0 = 0x01UL;
|
450 | 9a64fbe4 | bellard | env->fpscr[4] |= 0x1; |
451 | 9a64fbe4 | bellard | env->fpscr[6] |= 0x1; |
452 | 9a64fbe4 | bellard | } |
453 | 4b3686fa | bellard | env->fpscr[3] = T0;
|
454 | 9a64fbe4 | bellard | } |
455 | 9a64fbe4 | bellard | |
456 | 9a64fbe4 | bellard | void do_fcmpo (void) |
457 | 9a64fbe4 | bellard | { |
458 | 9a64fbe4 | bellard | env->fpscr[4] &= ~0x1; |
459 | fdabc366 | bellard | if (likely(!isnan(FT0) && !isnan(FT1))) {
|
460 | fdabc366 | bellard | if (float64_lt(FT0, FT1, &env->fp_status)) {
|
461 | fdabc366 | bellard | T0 = 0x08UL;
|
462 | fdabc366 | bellard | } else if (!float64_le(FT0, FT1, &env->fp_status)) { |
463 | fdabc366 | bellard | T0 = 0x04UL;
|
464 | fdabc366 | bellard | } else {
|
465 | fdabc366 | bellard | T0 = 0x02UL;
|
466 | fdabc366 | bellard | } |
467 | fdabc366 | bellard | } else {
|
468 | fdabc366 | bellard | T0 = 0x01UL;
|
469 | 9a64fbe4 | bellard | env->fpscr[4] |= 0x1; |
470 | 9a64fbe4 | bellard | /* I don't know how to test "quiet" nan... */
|
471 | 9a64fbe4 | bellard | if (0 /* || ! quiet_nan(...) */) { |
472 | 9a64fbe4 | bellard | env->fpscr[6] |= 0x1; |
473 | 9a64fbe4 | bellard | if (!(env->fpscr[1] & 0x8)) |
474 | 9a64fbe4 | bellard | env->fpscr[4] |= 0x8; |
475 | 9a64fbe4 | bellard | } else {
|
476 | 9a64fbe4 | bellard | env->fpscr[4] |= 0x8; |
477 | 9a64fbe4 | bellard | } |
478 | 9a64fbe4 | bellard | } |
479 | 4b3686fa | bellard | env->fpscr[3] = T0;
|
480 | 9a64fbe4 | bellard | } |
481 | 9a64fbe4 | bellard | |
482 | fdabc366 | bellard | void do_rfi (void) |
483 | 9a64fbe4 | bellard | { |
484 | fdabc366 | bellard | env->nip = env->spr[SPR_SRR0] & ~0x00000003;
|
485 | fdabc366 | bellard | T0 = env->spr[SPR_SRR1] & ~0xFFFF0000UL;
|
486 | fdabc366 | bellard | do_store_msr(env, T0); |
487 | fdabc366 | bellard | #if defined (DEBUG_OP)
|
488 | fdabc366 | bellard | dump_rfi(); |
489 | fdabc366 | bellard | #endif
|
490 | fdabc366 | bellard | env->interrupt_request |= CPU_INTERRUPT_EXITTB; |
491 | 9a64fbe4 | bellard | } |
492 | 9a64fbe4 | bellard | |
493 | fdabc366 | bellard | void do_tw (uint32_t cmp, int flags) |
494 | 9a64fbe4 | bellard | { |
495 | fdabc366 | bellard | if (!likely(!((Ts0 < (int32_t)cmp && (flags & 0x10)) || |
496 | fdabc366 | bellard | (Ts0 > (int32_t)cmp && (flags & 0x08)) ||
|
497 | fdabc366 | bellard | (Ts0 == (int32_t)cmp && (flags & 0x04)) ||
|
498 | fdabc366 | bellard | (T0 < cmp && (flags & 0x02)) ||
|
499 | fdabc366 | bellard | (T0 > cmp && (flags & 0x01)))))
|
500 | fdabc366 | bellard | do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP); |
501 | 9a64fbe4 | bellard | } |
502 | 9a64fbe4 | bellard | |
503 | 9a64fbe4 | bellard | /* Instruction cache invalidation helper */
|
504 | 9a64fbe4 | bellard | void do_icbi (void) |
505 | 9a64fbe4 | bellard | { |
506 | fdabc366 | bellard | uint32_t tmp; |
507 | fdabc366 | bellard | /* Invalidate one cache line :
|
508 | fdabc366 | bellard | * PowerPC specification says this is to be treated like a load
|
509 | fdabc366 | bellard | * (not a fetch) by the MMU. To be sure it will be so,
|
510 | fdabc366 | bellard | * do the load "by hand".
|
511 | fdabc366 | bellard | */
|
512 | fdabc366 | bellard | #if defined(TARGET_PPC64)
|
513 | fdabc366 | bellard | if (!msr_sf)
|
514 | fdabc366 | bellard | T0 &= 0xFFFFFFFFULL;
|
515 | fdabc366 | bellard | #endif
|
516 | fdabc366 | bellard | tmp = ldl_kernel(T0); |
517 | 985a19d6 | bellard | T0 &= ~(ICACHE_LINE_SIZE - 1);
|
518 | 985a19d6 | bellard | tb_invalidate_page_range(T0, T0 + ICACHE_LINE_SIZE); |
519 | 9a64fbe4 | bellard | } |
520 | 9a64fbe4 | bellard | |
521 | fdabc366 | bellard | /*****************************************************************************/
|
522 | fdabc366 | bellard | /* MMU related helpers */
|
523 | 9a64fbe4 | bellard | /* TLB invalidation helpers */
|
524 | 9a64fbe4 | bellard | void do_tlbia (void) |
525 | 9a64fbe4 | bellard | { |
526 | ad081323 | bellard | tlb_flush(env, 1);
|
527 | 9a64fbe4 | bellard | } |
528 | 9a64fbe4 | bellard | |
529 | 9a64fbe4 | bellard | void do_tlbie (void) |
530 | 9a64fbe4 | bellard | { |
531 | fdabc366 | bellard | #if !defined(FLUSH_ALL_TLBS)
|
532 | 9a64fbe4 | bellard | tlb_flush_page(env, T0); |
533 | fdabc366 | bellard | #else
|
534 | fdabc366 | bellard | do_tlbia(); |
535 | fdabc366 | bellard | #endif
|
536 | fdabc366 | bellard | } |
537 | fdabc366 | bellard | |
538 | fdabc366 | bellard | /*****************************************************************************/
|
539 | fdabc366 | bellard | /* Softmmu support */
|
540 | fdabc366 | bellard | #if !defined (CONFIG_USER_ONLY)
|
541 | fdabc366 | bellard | |
542 | fdabc366 | bellard | #define MMUSUFFIX _mmu
|
543 | fdabc366 | bellard | #define GETPC() (__builtin_return_address(0)) |
544 | fdabc366 | bellard | |
545 | fdabc366 | bellard | #define SHIFT 0 |
546 | fdabc366 | bellard | #include "softmmu_template.h" |
547 | fdabc366 | bellard | |
548 | fdabc366 | bellard | #define SHIFT 1 |
549 | fdabc366 | bellard | #include "softmmu_template.h" |
550 | fdabc366 | bellard | |
551 | fdabc366 | bellard | #define SHIFT 2 |
552 | fdabc366 | bellard | #include "softmmu_template.h" |
553 | fdabc366 | bellard | |
554 | fdabc366 | bellard | #define SHIFT 3 |
555 | fdabc366 | bellard | #include "softmmu_template.h" |
556 | fdabc366 | bellard | |
557 | fdabc366 | bellard | /* try to fill the TLB and return an exception if error. If retaddr is
|
558 | fdabc366 | bellard | NULL, it means that the function was called in C code (i.e. not
|
559 | fdabc366 | bellard | from generated code or from helper.c) */
|
560 | fdabc366 | bellard | /* XXX: fix it to restore all registers */
|
561 | fdabc366 | bellard | void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr) |
562 | fdabc366 | bellard | { |
563 | fdabc366 | bellard | TranslationBlock *tb; |
564 | fdabc366 | bellard | CPUState *saved_env; |
565 | fdabc366 | bellard | target_phys_addr_t pc; |
566 | fdabc366 | bellard | int ret;
|
567 | fdabc366 | bellard | |
568 | fdabc366 | bellard | /* XXX: hack to restore env in all cases, even if not called from
|
569 | fdabc366 | bellard | generated code */
|
570 | fdabc366 | bellard | saved_env = env; |
571 | fdabc366 | bellard | env = cpu_single_env; |
572 | fdabc366 | bellard | ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1);
|
573 | fdabc366 | bellard | if (!likely(ret == 0)) { |
574 | fdabc366 | bellard | if (likely(retaddr)) {
|
575 | fdabc366 | bellard | /* now we have a real cpu fault */
|
576 | fdabc366 | bellard | pc = (target_phys_addr_t)retaddr; |
577 | fdabc366 | bellard | tb = tb_find_pc(pc); |
578 | fdabc366 | bellard | if (likely(tb)) {
|
579 | fdabc366 | bellard | /* the PC is inside the translated code. It means that we have
|
580 | fdabc366 | bellard | a virtual CPU fault */
|
581 | fdabc366 | bellard | cpu_restore_state(tb, env, pc, NULL);
|
582 | fdabc366 | bellard | } |
583 | fdabc366 | bellard | } |
584 | fdabc366 | bellard | do_raise_exception_err(env->exception_index, env->error_code); |
585 | fdabc366 | bellard | } |
586 | fdabc366 | bellard | env = saved_env; |
587 | 9a64fbe4 | bellard | } |
588 | fdabc366 | bellard | #endif /* !CONFIG_USER_ONLY */ |