]> git.proxmox.com Git - qemu.git/blame - target-ppc/op_helper.c
target-ppc: convert wait instruction to TCG
[qemu.git] / target-ppc / op_helper.c
CommitLineData
9a64fbe4 1/*
3fc6c082 2 * PowerPC emulation helpers for qemu.
5fafdf24 3 *
76a66253 4 * Copyright (c) 2003-2007 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 */
9a64fbe4 20#include "exec.h"
603fccce 21#include "host-utils.h"
a7812ae4 22#include "helper.h"
9a64fbe4 23
0411a972 24#include "helper_regs.h"
0487d6a8
JM
25#include "op_helper.h"
26
9a64fbe4 27#define MEMSUFFIX _raw
0487d6a8 28#include "op_helper.h"
9a64fbe4 29#include "op_helper_mem.h"
a541f297 30#if !defined(CONFIG_USER_ONLY)
9a64fbe4 31#define MEMSUFFIX _user
0487d6a8 32#include "op_helper.h"
9a64fbe4
FB
33#include "op_helper_mem.h"
34#define MEMSUFFIX _kernel
0487d6a8 35#include "op_helper.h"
9a64fbe4 36#include "op_helper_mem.h"
1e42b8f0
JM
37#define MEMSUFFIX _hypv
38#include "op_helper.h"
39#include "op_helper_mem.h"
40#endif
9a64fbe4 41
fdabc366
FB
42//#define DEBUG_OP
43//#define DEBUG_EXCEPTIONS
76a66253 44//#define DEBUG_SOFTWARE_TLB
fdabc366 45
9a64fbe4
FB
46/*****************************************************************************/
47/* Exceptions processing helpers */
9a64fbe4 48
64adab3f 49void helper_raise_exception_err (uint32_t exception, uint32_t error_code)
9a64fbe4 50{
64adab3f 51 raise_exception_err(env, exception, error_code);
76a66253 52}
9fddaa0c 53
64adab3f 54void helper_raise_debug (void)
9fddaa0c 55{
64adab3f 56 raise_exception(env, EXCP_DEBUG);
9a64fbe4
FB
57}
58
64adab3f 59
76a66253
JM
60/*****************************************************************************/
61/* Registers load and stores */
a7812ae4 62target_ulong helper_load_cr (void)
76a66253 63{
e1571908
AJ
64 return (env->crf[0] << 28) |
65 (env->crf[1] << 24) |
66 (env->crf[2] << 20) |
67 (env->crf[3] << 16) |
68 (env->crf[4] << 12) |
69 (env->crf[5] << 8) |
70 (env->crf[6] << 4) |
71 (env->crf[7] << 0);
76a66253
JM
72}
73
e1571908 74void helper_store_cr (target_ulong val, uint32_t mask)
76a66253
JM
75{
76 int i, sh;
77
36081602 78 for (i = 0, sh = 7; i < 8; i++, sh--) {
76a66253 79 if (mask & (1 << sh))
e1571908 80 env->crf[i] = (val >> (sh * 4)) & 0xFUL;
76a66253
JM
81 }
82}
83
c80f84e3
JM
84#if defined(TARGET_PPC64)
85void do_store_pri (int prio)
86{
87 env->spr[SPR_PPR] &= ~0x001C000000000000ULL;
88 env->spr[SPR_PPR] |= ((uint64_t)prio & 0x7) << 50;
89}
90#endif
91
a496775f
JM
92target_ulong ppc_load_dump_spr (int sprn)
93{
6b80055d 94 if (loglevel != 0) {
a496775f
JM
95 fprintf(logfile, "Read SPR %d %03x => " ADDRX "\n",
96 sprn, sprn, env->spr[sprn]);
97 }
98
99 return env->spr[sprn];
100}
101
102void ppc_store_dump_spr (int sprn, target_ulong val)
103{
6b80055d 104 if (loglevel != 0) {
a496775f
JM
105 fprintf(logfile, "Write SPR %d %03x => " ADDRX " <= " ADDRX "\n",
106 sprn, sprn, env->spr[sprn], val);
107 }
108 env->spr[sprn] = val;
109}
110
9a64fbe4 111/*****************************************************************************/
fdabc366 112/* Fixed point operations helpers */
d9bce9d9 113#if defined(TARGET_PPC64)
d9bce9d9 114
74637406
AJ
115/* multiply high word */
116uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2)
fdabc366 117{
74637406 118 uint64_t tl, th;
fdabc366 119
74637406
AJ
120 muls64(&tl, &th, arg1, arg2);
121 return th;
d9bce9d9 122}
d9bce9d9 123
74637406
AJ
124/* multiply high word unsigned */
125uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2)
fdabc366 126{
74637406 127 uint64_t tl, th;
fdabc366 128
74637406
AJ
129 mulu64(&tl, &th, arg1, arg2);
130 return th;
fdabc366
FB
131}
132
74637406 133uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
fdabc366 134{
d9bce9d9
JM
135 int64_t th;
136 uint64_t tl;
137
74637406 138 muls64(&tl, (uint64_t *)&th, arg1, arg2);
88ad920b 139 /* If th != 0 && th != -1, then we had an overflow */
6f2d8978 140 if (likely((uint64_t)(th + 1) <= 1)) {
3d7b417e 141 env->xer &= ~(1 << XER_OV);
fdabc366 142 } else {
3d7b417e 143 env->xer |= (1 << XER_OV) | (1 << XER_SO);
fdabc366 144 }
74637406 145 return (int64_t)tl;
d9bce9d9
JM
146}
147#endif
148
26d67362 149target_ulong helper_cntlzw (target_ulong t)
603fccce 150{
26d67362 151 return clz32(t);
603fccce
JM
152}
153
154#if defined(TARGET_PPC64)
26d67362 155target_ulong helper_cntlzd (target_ulong t)
603fccce 156{
26d67362 157 return clz64(t);
603fccce
JM
158}
159#endif
160
9a64fbe4 161/* shift right arithmetic helper */
26d67362 162target_ulong helper_sraw (target_ulong value, target_ulong shift)
9a64fbe4
FB
163{
164 int32_t ret;
165
26d67362
AJ
166 if (likely(!(shift & 0x20))) {
167 if (likely((uint32_t)shift != 0)) {
168 shift &= 0x1f;
169 ret = (int32_t)value >> shift;
170 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
3d7b417e 171 env->xer &= ~(1 << XER_CA);
fdabc366 172 } else {
3d7b417e 173 env->xer |= (1 << XER_CA);
fdabc366
FB
174 }
175 } else {
26d67362 176 ret = (int32_t)value;
3d7b417e 177 env->xer &= ~(1 << XER_CA);
fdabc366
FB
178 }
179 } else {
26d67362
AJ
180 ret = (int32_t)value >> 31;
181 if (ret) {
3d7b417e 182 env->xer |= (1 << XER_CA);
26d67362
AJ
183 } else {
184 env->xer &= ~(1 << XER_CA);
76a66253 185 }
fdabc366 186 }
26d67362 187 return (target_long)ret;
9a64fbe4
FB
188}
189
d9bce9d9 190#if defined(TARGET_PPC64)
26d67362 191target_ulong helper_srad (target_ulong value, target_ulong shift)
d9bce9d9
JM
192{
193 int64_t ret;
194
26d67362
AJ
195 if (likely(!(shift & 0x40))) {
196 if (likely((uint64_t)shift != 0)) {
197 shift &= 0x3f;
198 ret = (int64_t)value >> shift;
199 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
3d7b417e 200 env->xer &= ~(1 << XER_CA);
d9bce9d9 201 } else {
3d7b417e 202 env->xer |= (1 << XER_CA);
d9bce9d9
JM
203 }
204 } else {
26d67362 205 ret = (int64_t)value;
3d7b417e 206 env->xer &= ~(1 << XER_CA);
d9bce9d9
JM
207 }
208 } else {
26d67362
AJ
209 ret = (int64_t)value >> 63;
210 if (ret) {
3d7b417e 211 env->xer |= (1 << XER_CA);
26d67362
AJ
212 } else {
213 env->xer &= ~(1 << XER_CA);
d9bce9d9
JM
214 }
215 }
26d67362 216 return ret;
d9bce9d9
JM
217}
218#endif
219
26d67362 220target_ulong helper_popcntb (target_ulong val)
d9bce9d9 221{
6176a26d
AJ
222 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
223 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
224 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
225 return val;
d9bce9d9
JM
226}
227
228#if defined(TARGET_PPC64)
26d67362 229target_ulong helper_popcntb_64 (target_ulong val)
d9bce9d9 230{
6176a26d
AJ
231 val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL);
232 val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL);
233 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & 0x0f0f0f0f0f0f0f0fULL);
234 return val;
d9bce9d9
JM
235}
236#endif
237
fdabc366 238/*****************************************************************************/
9a64fbe4 239/* Floating point operations helpers */
a0d7d5a7
AJ
240uint64_t helper_float32_to_float64(uint32_t arg)
241{
242 CPU_FloatU f;
243 CPU_DoubleU d;
244 f.l = arg;
245 d.d = float32_to_float64(f.f, &env->fp_status);
246 return d.ll;
247}
248
249uint32_t helper_float64_to_float32(uint64_t arg)
250{
251 CPU_FloatU f;
252 CPU_DoubleU d;
253 d.ll = arg;
254 f.f = float64_to_float32(d.d, &env->fp_status);
255 return f.l;
256}
257
0ca9d380 258static always_inline int fpisneg (float64 d)
7c58044c 259{
0ca9d380 260 CPU_DoubleU u;
7c58044c 261
0ca9d380 262 u.d = d;
7c58044c 263
0ca9d380 264 return u.ll >> 63 != 0;
7c58044c
JM
265}
266
0ca9d380 267static always_inline int isden (float64 d)
7c58044c 268{
0ca9d380 269 CPU_DoubleU u;
7c58044c 270
0ca9d380 271 u.d = d;
7c58044c 272
0ca9d380 273 return ((u.ll >> 52) & 0x7FF) == 0;
7c58044c
JM
274}
275
0ca9d380 276static always_inline int iszero (float64 d)
7c58044c 277{
0ca9d380 278 CPU_DoubleU u;
7c58044c 279
0ca9d380 280 u.d = d;
7c58044c 281
0ca9d380 282 return (u.ll & ~0x8000000000000000ULL) == 0;
7c58044c
JM
283}
284
0ca9d380 285static always_inline int isinfinity (float64 d)
7c58044c 286{
0ca9d380 287 CPU_DoubleU u;
7c58044c 288
0ca9d380 289 u.d = d;
7c58044c 290
0ca9d380
AJ
291 return ((u.ll >> 52) & 0x7FF) == 0x7FF &&
292 (u.ll & 0x000FFFFFFFFFFFFFULL) == 0;
7c58044c
JM
293}
294
80621676
AJ
295#ifdef CONFIG_SOFTFLOAT
296static always_inline int isfinite (float64 d)
297{
298 CPU_DoubleU u;
299
300 u.d = d;
301
302 return (((u.ll >> 52) & 0x7FF) != 0x7FF);
303}
304
305static always_inline int isnormal (float64 d)
306{
307 CPU_DoubleU u;
308
309 u.d = d;
310
311 uint32_t exp = (u.ll >> 52) & 0x7FF;
312 return ((0 < exp) && (exp < 0x7FF));
313}
314#endif
315
af12906f 316uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
7c58044c 317{
af12906f 318 CPU_DoubleU farg;
7c58044c 319 int isneg;
af12906f
AJ
320 int ret;
321 farg.ll = arg;
322 isneg = fpisneg(farg.d);
323 if (unlikely(float64_is_nan(farg.d))) {
324 if (float64_is_signaling_nan(farg.d)) {
7c58044c 325 /* Signaling NaN: flags are undefined */
af12906f 326 ret = 0x00;
7c58044c
JM
327 } else {
328 /* Quiet NaN */
af12906f 329 ret = 0x11;
7c58044c 330 }
af12906f 331 } else if (unlikely(isinfinity(farg.d))) {
7c58044c
JM
332 /* +/- infinity */
333 if (isneg)
af12906f 334 ret = 0x09;
7c58044c 335 else
af12906f 336 ret = 0x05;
7c58044c 337 } else {
af12906f 338 if (iszero(farg.d)) {
7c58044c
JM
339 /* +/- zero */
340 if (isneg)
af12906f 341 ret = 0x12;
7c58044c 342 else
af12906f 343 ret = 0x02;
7c58044c 344 } else {
af12906f 345 if (isden(farg.d)) {
7c58044c 346 /* Denormalized numbers */
af12906f 347 ret = 0x10;
7c58044c
JM
348 } else {
349 /* Normalized numbers */
af12906f 350 ret = 0x00;
7c58044c
JM
351 }
352 if (isneg) {
af12906f 353 ret |= 0x08;
7c58044c 354 } else {
af12906f 355 ret |= 0x04;
7c58044c
JM
356 }
357 }
358 }
359 if (set_fprf) {
360 /* We update FPSCR_FPRF */
361 env->fpscr &= ~(0x1F << FPSCR_FPRF);
af12906f 362 env->fpscr |= ret << FPSCR_FPRF;
7c58044c
JM
363 }
364 /* We just need fpcc to update Rc1 */
af12906f 365 return ret & 0xF;
7c58044c
JM
366}
367
368/* Floating-point invalid operations exception */
af12906f 369static always_inline uint64_t fload_invalid_op_excp (int op)
7c58044c 370{
af12906f 371 uint64_t ret = 0;
7c58044c
JM
372 int ve;
373
374 ve = fpscr_ve;
375 if (op & POWERPC_EXCP_FP_VXSNAN) {
376 /* Operation on signaling NaN */
377 env->fpscr |= 1 << FPSCR_VXSNAN;
378 }
379 if (op & POWERPC_EXCP_FP_VXSOFT) {
380 /* Software-defined condition */
381 env->fpscr |= 1 << FPSCR_VXSOFT;
382 }
383 switch (op & ~(POWERPC_EXCP_FP_VXSOFT | POWERPC_EXCP_FP_VXSNAN)) {
384 case POWERPC_EXCP_FP_VXISI:
385 /* Magnitude subtraction of infinities */
386 env->fpscr |= 1 << FPSCR_VXISI;
387 goto update_arith;
388 case POWERPC_EXCP_FP_VXIDI:
389 /* Division of infinity by infinity */
390 env->fpscr |= 1 << FPSCR_VXIDI;
391 goto update_arith;
392 case POWERPC_EXCP_FP_VXZDZ:
393 /* Division of zero by zero */
394 env->fpscr |= 1 << FPSCR_VXZDZ;
395 goto update_arith;
396 case POWERPC_EXCP_FP_VXIMZ:
397 /* Multiplication of zero by infinity */
398 env->fpscr |= 1 << FPSCR_VXIMZ;
399 goto update_arith;
400 case POWERPC_EXCP_FP_VXVC:
401 /* Ordered comparison of NaN */
402 env->fpscr |= 1 << FPSCR_VXVC;
403 env->fpscr &= ~(0xF << FPSCR_FPCC);
404 env->fpscr |= 0x11 << FPSCR_FPCC;
405 /* We must update the target FPR before raising the exception */
406 if (ve != 0) {
407 env->exception_index = POWERPC_EXCP_PROGRAM;
408 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
409 /* Update the floating-point enabled exception summary */
410 env->fpscr |= 1 << FPSCR_FEX;
411 /* Exception is differed */
412 ve = 0;
413 }
414 break;
415 case POWERPC_EXCP_FP_VXSQRT:
416 /* Square root of a negative number */
417 env->fpscr |= 1 << FPSCR_VXSQRT;
418 update_arith:
419 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
420 if (ve == 0) {
421 /* Set the result to quiet NaN */
af12906f 422 ret = UINT64_MAX;
7c58044c
JM
423 env->fpscr &= ~(0xF << FPSCR_FPCC);
424 env->fpscr |= 0x11 << FPSCR_FPCC;
425 }
426 break;
427 case POWERPC_EXCP_FP_VXCVI:
428 /* Invalid conversion */
429 env->fpscr |= 1 << FPSCR_VXCVI;
430 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
431 if (ve == 0) {
432 /* Set the result to quiet NaN */
af12906f 433 ret = UINT64_MAX;
7c58044c
JM
434 env->fpscr &= ~(0xF << FPSCR_FPCC);
435 env->fpscr |= 0x11 << FPSCR_FPCC;
436 }
437 break;
438 }
439 /* Update the floating-point invalid operation summary */
440 env->fpscr |= 1 << FPSCR_VX;
441 /* Update the floating-point exception summary */
442 env->fpscr |= 1 << FPSCR_FX;
443 if (ve != 0) {
444 /* Update the floating-point enabled exception summary */
445 env->fpscr |= 1 << FPSCR_FEX;
446 if (msr_fe0 != 0 || msr_fe1 != 0)
64adab3f 447 raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
7c58044c 448 }
af12906f 449 return ret;
7c58044c
JM
450}
451
af12906f 452static always_inline uint64_t float_zero_divide_excp (uint64_t arg1, uint64_t arg2)
7c58044c 453{
7c58044c
JM
454 env->fpscr |= 1 << FPSCR_ZX;
455 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
456 /* Update the floating-point exception summary */
457 env->fpscr |= 1 << FPSCR_FX;
458 if (fpscr_ze != 0) {
459 /* Update the floating-point enabled exception summary */
460 env->fpscr |= 1 << FPSCR_FEX;
461 if (msr_fe0 != 0 || msr_fe1 != 0) {
64adab3f
AJ
462 raise_exception_err(env, POWERPC_EXCP_PROGRAM,
463 POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
7c58044c
JM
464 }
465 } else {
466 /* Set the result to infinity */
af12906f
AJ
467 arg1 = ((arg1 ^ arg2) & 0x8000000000000000ULL);
468 arg1 |= 0x7FFULL << 52;
7c58044c 469 }
af12906f 470 return arg1;
7c58044c
JM
471}
472
473static always_inline void float_overflow_excp (void)
474{
475 env->fpscr |= 1 << FPSCR_OX;
476 /* Update the floating-point exception summary */
477 env->fpscr |= 1 << FPSCR_FX;
478 if (fpscr_oe != 0) {
479 /* XXX: should adjust the result */
480 /* Update the floating-point enabled exception summary */
481 env->fpscr |= 1 << FPSCR_FEX;
482 /* We must update the target FPR before raising the exception */
483 env->exception_index = POWERPC_EXCP_PROGRAM;
484 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
485 } else {
486 env->fpscr |= 1 << FPSCR_XX;
487 env->fpscr |= 1 << FPSCR_FI;
488 }
489}
490
491static always_inline void float_underflow_excp (void)
492{
493 env->fpscr |= 1 << FPSCR_UX;
494 /* Update the floating-point exception summary */
495 env->fpscr |= 1 << FPSCR_FX;
496 if (fpscr_ue != 0) {
497 /* XXX: should adjust the result */
498 /* Update the floating-point enabled exception summary */
499 env->fpscr |= 1 << FPSCR_FEX;
500 /* We must update the target FPR before raising the exception */
501 env->exception_index = POWERPC_EXCP_PROGRAM;
502 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
503 }
504}
505
506static always_inline void float_inexact_excp (void)
507{
508 env->fpscr |= 1 << FPSCR_XX;
509 /* Update the floating-point exception summary */
510 env->fpscr |= 1 << FPSCR_FX;
511 if (fpscr_xe != 0) {
512 /* Update the floating-point enabled exception summary */
513 env->fpscr |= 1 << FPSCR_FEX;
514 /* We must update the target FPR before raising the exception */
515 env->exception_index = POWERPC_EXCP_PROGRAM;
516 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
517 }
518}
519
520static always_inline void fpscr_set_rounding_mode (void)
521{
522 int rnd_type;
523
524 /* Set rounding mode */
525 switch (fpscr_rn) {
526 case 0:
527 /* Best approximation (round to nearest) */
528 rnd_type = float_round_nearest_even;
529 break;
530 case 1:
531 /* Smaller magnitude (round toward zero) */
532 rnd_type = float_round_to_zero;
533 break;
534 case 2:
535 /* Round toward +infinite */
536 rnd_type = float_round_up;
537 break;
538 default:
539 case 3:
540 /* Round toward -infinite */
541 rnd_type = float_round_down;
542 break;
543 }
544 set_float_rounding_mode(rnd_type, &env->fp_status);
545}
546
af12906f 547void helper_fpscr_setbit (uint32_t bit)
7c58044c
JM
548{
549 int prev;
550
551 prev = (env->fpscr >> bit) & 1;
552 env->fpscr |= 1 << bit;
553 if (prev == 0) {
554 switch (bit) {
555 case FPSCR_VX:
556 env->fpscr |= 1 << FPSCR_FX;
557 if (fpscr_ve)
558 goto raise_ve;
559 case FPSCR_OX:
560 env->fpscr |= 1 << FPSCR_FX;
561 if (fpscr_oe)
562 goto raise_oe;
563 break;
564 case FPSCR_UX:
565 env->fpscr |= 1 << FPSCR_FX;
566 if (fpscr_ue)
567 goto raise_ue;
568 break;
569 case FPSCR_ZX:
570 env->fpscr |= 1 << FPSCR_FX;
571 if (fpscr_ze)
572 goto raise_ze;
573 break;
574 case FPSCR_XX:
575 env->fpscr |= 1 << FPSCR_FX;
576 if (fpscr_xe)
577 goto raise_xe;
578 break;
579 case FPSCR_VXSNAN:
580 case FPSCR_VXISI:
581 case FPSCR_VXIDI:
582 case FPSCR_VXZDZ:
583 case FPSCR_VXIMZ:
584 case FPSCR_VXVC:
585 case FPSCR_VXSOFT:
586 case FPSCR_VXSQRT:
587 case FPSCR_VXCVI:
588 env->fpscr |= 1 << FPSCR_VX;
589 env->fpscr |= 1 << FPSCR_FX;
590 if (fpscr_ve != 0)
591 goto raise_ve;
592 break;
593 case FPSCR_VE:
594 if (fpscr_vx != 0) {
595 raise_ve:
596 env->error_code = POWERPC_EXCP_FP;
597 if (fpscr_vxsnan)
598 env->error_code |= POWERPC_EXCP_FP_VXSNAN;
599 if (fpscr_vxisi)
600 env->error_code |= POWERPC_EXCP_FP_VXISI;
601 if (fpscr_vxidi)
602 env->error_code |= POWERPC_EXCP_FP_VXIDI;
603 if (fpscr_vxzdz)
604 env->error_code |= POWERPC_EXCP_FP_VXZDZ;
605 if (fpscr_vximz)
606 env->error_code |= POWERPC_EXCP_FP_VXIMZ;
607 if (fpscr_vxvc)
608 env->error_code |= POWERPC_EXCP_FP_VXVC;
609 if (fpscr_vxsoft)
610 env->error_code |= POWERPC_EXCP_FP_VXSOFT;
611 if (fpscr_vxsqrt)
612 env->error_code |= POWERPC_EXCP_FP_VXSQRT;
613 if (fpscr_vxcvi)
614 env->error_code |= POWERPC_EXCP_FP_VXCVI;
615 goto raise_excp;
616 }
617 break;
618 case FPSCR_OE:
619 if (fpscr_ox != 0) {
620 raise_oe:
621 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
622 goto raise_excp;
623 }
624 break;
625 case FPSCR_UE:
626 if (fpscr_ux != 0) {
627 raise_ue:
628 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
629 goto raise_excp;
630 }
631 break;
632 case FPSCR_ZE:
633 if (fpscr_zx != 0) {
634 raise_ze:
635 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
636 goto raise_excp;
637 }
638 break;
639 case FPSCR_XE:
640 if (fpscr_xx != 0) {
641 raise_xe:
642 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
643 goto raise_excp;
644 }
645 break;
646 case FPSCR_RN1:
647 case FPSCR_RN:
648 fpscr_set_rounding_mode();
649 break;
650 default:
651 break;
652 raise_excp:
653 /* Update the floating-point enabled exception summary */
654 env->fpscr |= 1 << FPSCR_FEX;
655 /* We have to update Rc1 before raising the exception */
656 env->exception_index = POWERPC_EXCP_PROGRAM;
657 break;
658 }
659 }
660}
661
af12906f 662void helper_store_fpscr (uint64_t arg, uint32_t mask)
7c58044c
JM
663{
664 /*
665 * We use only the 32 LSB of the incoming fpr
666 */
7c58044c
JM
667 uint32_t prev, new;
668 int i;
669
7c58044c 670 prev = env->fpscr;
af12906f 671 new = (uint32_t)arg;
7c58044c
JM
672 new &= ~0x90000000;
673 new |= prev & 0x90000000;
674 for (i = 0; i < 7; i++) {
675 if (mask & (1 << i)) {
676 env->fpscr &= ~(0xF << (4 * i));
677 env->fpscr |= new & (0xF << (4 * i));
678 }
679 }
680 /* Update VX and FEX */
681 if (fpscr_ix != 0)
682 env->fpscr |= 1 << FPSCR_VX;
5567025f
AJ
683 else
684 env->fpscr &= ~(1 << FPSCR_VX);
7c58044c
JM
685 if ((fpscr_ex & fpscr_eex) != 0) {
686 env->fpscr |= 1 << FPSCR_FEX;
687 env->exception_index = POWERPC_EXCP_PROGRAM;
688 /* XXX: we should compute it properly */
689 env->error_code = POWERPC_EXCP_FP;
690 }
5567025f
AJ
691 else
692 env->fpscr &= ~(1 << FPSCR_FEX);
7c58044c
JM
693 fpscr_set_rounding_mode();
694}
7c58044c 695
af12906f 696void helper_float_check_status (void)
7c58044c 697{
af12906f 698#ifdef CONFIG_SOFTFLOAT
7c58044c
JM
699 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
700 (env->error_code & POWERPC_EXCP_FP)) {
701 /* Differred floating-point exception after target FPR update */
702 if (msr_fe0 != 0 || msr_fe1 != 0)
64adab3f 703 raise_exception_err(env, env->exception_index, env->error_code);
7c58044c
JM
704 } else if (env->fp_status.float_exception_flags & float_flag_overflow) {
705 float_overflow_excp();
706 } else if (env->fp_status.float_exception_flags & float_flag_underflow) {
707 float_underflow_excp();
708 } else if (env->fp_status.float_exception_flags & float_flag_inexact) {
709 float_inexact_excp();
710 }
af12906f
AJ
711#else
712 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
713 (env->error_code & POWERPC_EXCP_FP)) {
714 /* Differred floating-point exception after target FPR update */
715 if (msr_fe0 != 0 || msr_fe1 != 0)
64adab3f 716 raise_exception_err(env, env->exception_index, env->error_code);
af12906f
AJ
717 }
718 RETURN();
719#endif
720}
721
722#ifdef CONFIG_SOFTFLOAT
723void helper_reset_fpstatus (void)
724{
725 env->fp_status.float_exception_flags = 0;
7c58044c
JM
726}
727#endif
728
af12906f
AJ
729/* fadd - fadd. */
730uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
7c58044c 731{
af12906f
AJ
732 CPU_DoubleU farg1, farg2;
733
734 farg1.ll = arg1;
735 farg2.ll = arg2;
736#if USE_PRECISE_EMULATION
737 if (unlikely(float64_is_signaling_nan(farg1.d) ||
738 float64_is_signaling_nan(farg2.d))) {
7c58044c 739 /* sNaN addition */
af12906f
AJ
740 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
741 } else if (likely(isfinite(farg1.d) || isfinite(farg2.d) ||
742 fpisneg(farg1.d) == fpisneg(farg2.d))) {
743 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
7c58044c
JM
744 } else {
745 /* Magnitude subtraction of infinities */
af12906f 746 farg1.ll == fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
7c58044c 747 }
af12906f
AJ
748#else
749 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
750#endif
751 return farg1.ll;
7c58044c
JM
752}
753
af12906f
AJ
754/* fsub - fsub. */
755uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
756{
757 CPU_DoubleU farg1, farg2;
758
759 farg1.ll = arg1;
760 farg2.ll = arg2;
761#if USE_PRECISE_EMULATION
7c58044c 762{
af12906f
AJ
763 if (unlikely(float64_is_signaling_nan(farg1.d) ||
764 float64_is_signaling_nan(farg2.d))) {
7c58044c 765 /* sNaN subtraction */
af12906f
AJ
766 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
767 } else if (likely(isfinite(farg1.d) || isfinite(farg2.d) ||
768 fpisneg(farg1.d) != fpisneg(farg2.d))) {
769 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
7c58044c
JM
770 } else {
771 /* Magnitude subtraction of infinities */
af12906f 772 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
7c58044c
JM
773 }
774}
af12906f
AJ
775#else
776 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
777#endif
778 return farg1.ll;
779}
7c58044c 780
af12906f
AJ
781/* fmul - fmul. */
782uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
7c58044c 783{
af12906f
AJ
784 CPU_DoubleU farg1, farg2;
785
786 farg1.ll = arg1;
787 farg2.ll = arg2;
788#if USE_PRECISE_EMULATION
789 if (unlikely(float64_is_signaling_nan(farg1.d) ||
790 float64_is_signaling_nan(farg2.d))) {
7c58044c 791 /* sNaN multiplication */
af12906f
AJ
792 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
793 } else if (unlikely((isinfinity(farg1.d) && iszero(farg2.d)) ||
794 (iszero(farg1.d) && isinfinity(farg2.d)))) {
7c58044c 795 /* Multiplication of zero by infinity */
af12906f 796 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
7c58044c 797 } else {
af12906f 798 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
7c58044c
JM
799 }
800}
af12906f
AJ
801#else
802 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
803#endif
804 return farg1.ll;
805}
7c58044c 806
af12906f
AJ
807/* fdiv - fdiv. */
808uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
7c58044c 809{
af12906f
AJ
810 CPU_DoubleU farg1, farg2;
811
812 farg1.ll = arg1;
813 farg2.ll = arg2;
814#if USE_PRECISE_EMULATION
815 if (unlikely(float64_is_signaling_nan(farg1.d) ||
816 float64_is_signaling_nan(farg2.d))) {
7c58044c 817 /* sNaN division */
af12906f
AJ
818 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
819 } else if (unlikely(isinfinity(farg1.d) && isinfinity(farg2.d))) {
7c58044c 820 /* Division of infinity by infinity */
af12906f
AJ
821 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
822 } else if (unlikely(iszero(farg2.d))) {
823 if (iszero(farg1.d)) {
7c58044c 824 /* Division of zero by zero */
af12906f 825 farg1.ll fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
7c58044c
JM
826 } else {
827 /* Division by zero */
af12906f 828 farg1.ll = float_zero_divide_excp(farg1.d, farg2.d);
7c58044c
JM
829 }
830 } else {
af12906f 831 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
7c58044c 832 }
af12906f
AJ
833#else
834 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
835#endif
836 return farg1.ll;
7c58044c 837}
7c58044c 838
af12906f
AJ
839/* fabs */
840uint64_t helper_fabs (uint64_t arg)
9a64fbe4 841{
af12906f 842 CPU_DoubleU farg;
9a64fbe4 843
af12906f
AJ
844 farg.ll = arg;
845 farg.d = float64_abs(farg.d);
846 return farg.ll;
847}
848
849/* fnabs */
850uint64_t helper_fnabs (uint64_t arg)
851{
852 CPU_DoubleU farg;
853
854 farg.ll = arg;
855 farg.d = float64_abs(farg.d);
856 farg.d = float64_chs(farg.d);
857 return farg.ll;
858}
859
860/* fneg */
861uint64_t helper_fneg (uint64_t arg)
862{
863 CPU_DoubleU farg;
864
865 farg.ll = arg;
866 farg.d = float64_chs(farg.d);
867 return farg.ll;
868}
869
870/* fctiw - fctiw. */
871uint64_t helper_fctiw (uint64_t arg)
872{
873 CPU_DoubleU farg;
874 farg.ll = arg;
875
876 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 877 /* sNaN conversion */
af12906f
AJ
878 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
879 } else if (unlikely(float64_is_nan(farg.d) || isinfinity(farg.d))) {
7c58044c 880 /* qNan / infinity conversion */
af12906f 881 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
7c58044c 882 } else {
af12906f 883 farg.ll = float64_to_int32(farg.d, &env->fp_status);
1cdb9c3d 884#if USE_PRECISE_EMULATION
7c58044c
JM
885 /* XXX: higher bits are not supposed to be significant.
886 * to make tests easier, return the same as a real PowerPC 750
887 */
af12906f 888 farg.ll |= 0xFFF80000ULL << 32;
e864cabd 889#endif
7c58044c 890 }
af12906f 891 return farg.ll;
9a64fbe4
FB
892}
893
af12906f
AJ
894/* fctiwz - fctiwz. */
895uint64_t helper_fctiwz (uint64_t arg)
9a64fbe4 896{
af12906f
AJ
897 CPU_DoubleU farg;
898 farg.ll = arg;
4ecc3190 899
af12906f 900 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 901 /* sNaN conversion */
af12906f
AJ
902 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
903 } else if (unlikely(float64_is_nan(farg.d) || isinfinity(farg.d))) {
7c58044c 904 /* qNan / infinity conversion */
af12906f 905 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
7c58044c 906 } else {
af12906f 907 farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
1cdb9c3d 908#if USE_PRECISE_EMULATION
7c58044c
JM
909 /* XXX: higher bits are not supposed to be significant.
910 * to make tests easier, return the same as a real PowerPC 750
911 */
af12906f 912 farg.ll |= 0xFFF80000ULL << 32;
e864cabd 913#endif
7c58044c 914 }
af12906f 915 return farg.ll;
9a64fbe4
FB
916}
917
426613db 918#if defined(TARGET_PPC64)
af12906f
AJ
919/* fcfid - fcfid. */
920uint64_t helper_fcfid (uint64_t arg)
426613db 921{
af12906f
AJ
922 CPU_DoubleU farg;
923 farg.d = int64_to_float64(arg, &env->fp_status);
924 return farg.ll;
426613db
JM
925}
926
af12906f
AJ
927/* fctid - fctid. */
928uint64_t helper_fctid (uint64_t arg)
426613db 929{
af12906f
AJ
930 CPU_DoubleU farg;
931 farg.ll = arg;
426613db 932
af12906f 933 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 934 /* sNaN conversion */
af12906f
AJ
935 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
936 } else if (unlikely(float64_is_nan(farg.d) || isinfinity(farg.d))) {
7c58044c 937 /* qNan / infinity conversion */
af12906f 938 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
7c58044c 939 } else {
af12906f 940 farg.ll = float64_to_int64(farg.d, &env->fp_status);
7c58044c 941 }
af12906f 942 return farg.ll;
426613db
JM
943}
944
af12906f
AJ
945/* fctidz - fctidz. */
946uint64_t helper_fctidz (uint64_t arg)
426613db 947{
af12906f
AJ
948 CPU_DoubleU farg;
949 farg.ll = arg;
426613db 950
af12906f 951 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 952 /* sNaN conversion */
af12906f
AJ
953 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
954 } else if (unlikely(float64_is_nan(farg.d) || isinfinity(farg.d))) {
7c58044c 955 /* qNan / infinity conversion */
af12906f 956 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
7c58044c 957 } else {
af12906f 958 farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
7c58044c 959 }
af12906f 960 return farg.ll;
426613db
JM
961}
962
963#endif
964
af12906f 965static always_inline uint64_t do_fri (uint64_t arg, int rounding_mode)
d7e4b87e 966{
af12906f
AJ
967 CPU_DoubleU farg;
968 farg.ll = arg;
969
970 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 971 /* sNaN round */
af12906f
AJ
972 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
973 } else if (unlikely(float64_is_nan(farg.d) || isinfinity(farg.d))) {
7c58044c 974 /* qNan / infinity round */
af12906f 975 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
7c58044c
JM
976 } else {
977 set_float_rounding_mode(rounding_mode, &env->fp_status);
af12906f 978 farg.ll = float64_round_to_int(farg.d, &env->fp_status);
7c58044c
JM
979 /* Restore rounding mode from FPSCR */
980 fpscr_set_rounding_mode();
981 }
af12906f 982 return farg.ll;
d7e4b87e
JM
983}
984
af12906f 985uint64_t helper_frin (uint64_t arg)
d7e4b87e 986{
af12906f 987 return do_fri(arg, float_round_nearest_even);
d7e4b87e
JM
988}
989
af12906f 990uint64_t helper_friz (uint64_t arg)
d7e4b87e 991{
af12906f 992 return do_fri(arg, float_round_to_zero);
d7e4b87e
JM
993}
994
af12906f 995uint64_t helper_frip (uint64_t arg)
d7e4b87e 996{
af12906f 997 return do_fri(arg, float_round_up);
d7e4b87e
JM
998}
999
af12906f 1000uint64_t helper_frim (uint64_t arg)
d7e4b87e 1001{
af12906f 1002 return do_fri(arg, float_round_down);
d7e4b87e
JM
1003}
1004
af12906f
AJ
1005/* fmadd - fmadd. */
1006uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
e864cabd 1007{
af12906f
AJ
1008 CPU_DoubleU farg1, farg2, farg3;
1009
1010 farg1.ll = arg1;
1011 farg2.ll = arg2;
1012 farg3.ll = arg3;
1013#if USE_PRECISE_EMULATION
1014 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1015 float64_is_signaling_nan(farg2.d) ||
1016 float64_is_signaling_nan(farg3.d))) {
7c58044c 1017 /* sNaN operation */
af12906f 1018 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
7c58044c 1019 } else {
e864cabd 1020#ifdef FLOAT128
7c58044c
JM
1021 /* This is the way the PowerPC specification defines it */
1022 float128 ft0_128, ft1_128;
1023
af12906f
AJ
1024 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1025 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
7c58044c 1026 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
af12906f 1027 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
7c58044c 1028 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
af12906f 1029 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
e864cabd 1030#else
7c58044c 1031 /* This is OK on x86 hosts */
af12906f 1032 farg1.d = (farg1.d * farg2.d) + farg3.d;
e864cabd 1033#endif
7c58044c 1034 }
af12906f
AJ
1035#else
1036 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1037 farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
1038#endif
1039 return farg1.ll;
e864cabd
JM
1040}
1041
af12906f
AJ
1042/* fmsub - fmsub. */
1043uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
e864cabd 1044{
af12906f
AJ
1045 CPU_DoubleU farg1, farg2, farg3;
1046
1047 farg1.ll = arg1;
1048 farg2.ll = arg2;
1049 farg3.ll = arg3;
1050#if USE_PRECISE_EMULATION
1051 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1052 float64_is_signaling_nan(farg2.d) ||
1053 float64_is_signaling_nan(farg3.d))) {
7c58044c 1054 /* sNaN operation */
af12906f 1055 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
7c58044c 1056 } else {
e864cabd 1057#ifdef FLOAT128
7c58044c
JM
1058 /* This is the way the PowerPC specification defines it */
1059 float128 ft0_128, ft1_128;
1060
af12906f
AJ
1061 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1062 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
7c58044c 1063 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
af12906f 1064 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
7c58044c 1065 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
af12906f 1066 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
e864cabd 1067#else
7c58044c 1068 /* This is OK on x86 hosts */
af12906f 1069 farg1.d = (farg1.d * farg2.d) - farg3.d;
e864cabd 1070#endif
7c58044c 1071 }
af12906f
AJ
1072#else
1073 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1074 farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
1075#endif
1076 return farg1.ll;
e864cabd 1077}
e864cabd 1078
af12906f
AJ
1079/* fnmadd - fnmadd. */
1080uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
4b3686fa 1081{
af12906f
AJ
1082 CPU_DoubleU farg1, farg2, farg3;
1083
1084 farg1.ll = arg1;
1085 farg2.ll = arg2;
1086 farg3.ll = arg3;
1087
1088 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1089 float64_is_signaling_nan(farg2.d) ||
1090 float64_is_signaling_nan(farg3.d))) {
7c58044c 1091 /* sNaN operation */
af12906f 1092 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
7c58044c 1093 } else {
1cdb9c3d 1094#if USE_PRECISE_EMULATION
e864cabd 1095#ifdef FLOAT128
7c58044c
JM
1096 /* This is the way the PowerPC specification defines it */
1097 float128 ft0_128, ft1_128;
1098
af12906f
AJ
1099 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1100 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
7c58044c 1101 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
af12906f 1102 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
7c58044c 1103 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
af12906f 1104 farg1.d= float128_to_float64(ft0_128, &env->fp_status);
e864cabd 1105#else
7c58044c 1106 /* This is OK on x86 hosts */
af12906f 1107 farg1.d = (farg1.d * farg2.d) + farg3.d;
e864cabd
JM
1108#endif
1109#else
af12906f
AJ
1110 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1111 farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
e864cabd 1112#endif
af12906f
AJ
1113 if (likely(!isnan(farg1.d)))
1114 farg1.d = float64_chs(farg1.d);
7c58044c 1115 }
af12906f 1116 return farg1.ll;
4b3686fa
FB
1117}
1118
af12906f
AJ
1119/* fnmsub - fnmsub. */
1120uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
4b3686fa 1121{
af12906f
AJ
1122 CPU_DoubleU farg1, farg2, farg3;
1123
1124 farg1.ll = arg1;
1125 farg2.ll = arg2;
1126 farg3.ll = arg3;
1127
1128 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1129 float64_is_signaling_nan(farg2.d) ||
1130 float64_is_signaling_nan(farg3.d))) {
7c58044c 1131 /* sNaN operation */
af12906f 1132 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
7c58044c 1133 } else {
1cdb9c3d 1134#if USE_PRECISE_EMULATION
e864cabd 1135#ifdef FLOAT128
7c58044c
JM
1136 /* This is the way the PowerPC specification defines it */
1137 float128 ft0_128, ft1_128;
1138
af12906f
AJ
1139 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1140 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
7c58044c 1141 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
af12906f 1142 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
7c58044c 1143 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
af12906f 1144 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
e864cabd 1145#else
7c58044c 1146 /* This is OK on x86 hosts */
af12906f 1147 farg1.d = (farg1.d * farg2.d) - farg3.d;
e864cabd
JM
1148#endif
1149#else
af12906f
AJ
1150 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1151 farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
e864cabd 1152#endif
af12906f
AJ
1153 if (likely(!isnan(farg1.d)))
1154 farg1.d = float64_chs(farg1.d);
7c58044c 1155 }
af12906f 1156 return farg1.ll;
1ef59d0a
FB
1157}
1158
af12906f
AJ
1159
1160/* frsp - frsp. */
1161uint64_t helper_frsp (uint64_t arg)
7c58044c 1162{
af12906f
AJ
1163 CPU_DoubleU farg;
1164 farg.ll = arg;
1165
1166#if USE_PRECISE_EMULATION
1167 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1168 /* sNaN square root */
af12906f 1169 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
7c58044c 1170 } else {
af12906f 1171 fard.d = float64_to_float32(farg.d, &env->fp_status);
7c58044c 1172 }
af12906f
AJ
1173#else
1174 farg.d = float64_to_float32(farg.d, &env->fp_status);
1175#endif
1176 return farg.ll;
7c58044c 1177}
7c58044c 1178
af12906f
AJ
1179/* fsqrt - fsqrt. */
1180uint64_t helper_fsqrt (uint64_t arg)
9a64fbe4 1181{
af12906f
AJ
1182 CPU_DoubleU farg;
1183 farg.ll = arg;
1184
1185 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1186 /* sNaN square root */
af12906f
AJ
1187 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1188 } else if (unlikely(fpisneg(farg.d) && !iszero(farg.d))) {
7c58044c 1189 /* Square root of a negative nonzero number */
af12906f 1190 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
7c58044c 1191 } else {
af12906f 1192 farg.d = float64_sqrt(farg.d, &env->fp_status);
7c58044c 1193 }
af12906f 1194 return farg.ll;
9a64fbe4
FB
1195}
1196
af12906f
AJ
1197/* fre - fre. */
1198uint64_t helper_fre (uint64_t arg)
d7e4b87e 1199{
af12906f
AJ
1200 CPU_DoubleU farg;
1201 farg.ll = arg;
d7e4b87e 1202
af12906f 1203 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1204 /* sNaN reciprocal */
af12906f
AJ
1205 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1206 } else if (unlikely(iszero(farg.d))) {
7c58044c 1207 /* Zero reciprocal */
af12906f
AJ
1208 farg.ll = float_zero_divide_excp(1.0, farg.d);
1209 } else if (likely(isnormal(farg.d))) {
1210 farg.d = float64_div(1.0, farg.d, &env->fp_status);
d7e4b87e 1211 } else {
af12906f
AJ
1212 if (farg.ll == 0x8000000000000000ULL) {
1213 farg.ll = 0xFFF0000000000000ULL;
1214 } else if (farg.ll == 0x0000000000000000ULL) {
1215 farg.ll = 0x7FF0000000000000ULL;
1216 } else if (isnan(farg.d)) {
1217 farg.ll = 0x7FF8000000000000ULL;
1218 } else if (fpisneg(farg.d)) {
1219 farg.ll = 0x8000000000000000ULL;
d7e4b87e 1220 } else {
af12906f 1221 farg.ll = 0x0000000000000000ULL;
d7e4b87e 1222 }
d7e4b87e 1223 }
af12906f 1224 return farg.d;
d7e4b87e
JM
1225}
1226
af12906f
AJ
1227/* fres - fres. */
1228uint64_t helper_fres (uint64_t arg)
9a64fbe4 1229{
af12906f
AJ
1230 CPU_DoubleU farg;
1231 farg.ll = arg;
4ecc3190 1232
af12906f 1233 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1234 /* sNaN reciprocal */
af12906f
AJ
1235 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1236 } else if (unlikely(iszero(farg.d))) {
7c58044c 1237 /* Zero reciprocal */
af12906f
AJ
1238 farg.ll = float_zero_divide_excp(1.0, farg.d);
1239 } else if (likely(isnormal(farg.d))) {
1cdb9c3d 1240#if USE_PRECISE_EMULATION
af12906f
AJ
1241 farg.d = float64_div(1.0, farg.d, &env->fp_status);
1242 farg.d = float64_to_float32(farg.d, &env->fp_status);
e864cabd 1243#else
af12906f 1244 farg.d = float32_div(1.0, farg.d, &env->fp_status);
e864cabd 1245#endif
4ecc3190 1246 } else {
af12906f
AJ
1247 if (farg.ll == 0x8000000000000000ULL) {
1248 farg.ll = 0xFFF0000000000000ULL;
1249 } else if (farg.ll == 0x0000000000000000ULL) {
1250 farg.ll = 0x7FF0000000000000ULL;
1251 } else if (isnan(farg.d)) {
1252 farg.ll = 0x7FF8000000000000ULL;
1253 } else if (fpisneg(farg.d)) {
1254 farg.ll = 0x8000000000000000ULL;
4ecc3190 1255 } else {
af12906f 1256 farg.ll = 0x0000000000000000ULL;
4ecc3190 1257 }
4ecc3190 1258 }
af12906f 1259 return farg.ll;
9a64fbe4
FB
1260}
1261
af12906f
AJ
1262/* frsqrte - frsqrte. */
1263uint64_t helper_frsqrte (uint64_t arg)
9a64fbe4 1264{
af12906f
AJ
1265 CPU_DoubleU farg;
1266 farg.ll = arg;
4ecc3190 1267
af12906f 1268 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1269 /* sNaN reciprocal square root */
af12906f
AJ
1270 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1271 } else if (unlikely(fpisneg(farg.d) && !iszero(farg.d))) {
7c58044c 1272 /* Reciprocal square root of a negative nonzero number */
af12906f
AJ
1273 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
1274 } else if (likely(isnormal(farg.d))) {
1275 farg.d = float64_sqrt(farg.d, &env->fp_status);
1276 farg.d = float32_div(1.0, farg.d, &env->fp_status);
4ecc3190 1277 } else {
af12906f
AJ
1278 if (farg.ll == 0x8000000000000000ULL) {
1279 farg.ll = 0xFFF0000000000000ULL;
1280 } else if (farg.ll == 0x0000000000000000ULL) {
1281 farg.ll = 0x7FF0000000000000ULL;
1282 } else if (isnan(farg.d)) {
1283 farg.ll |= 0x000FFFFFFFFFFFFFULL;
1284 } else if (fpisneg(farg.d)) {
1285 farg.ll = 0x7FF8000000000000ULL;
4ecc3190 1286 } else {
af12906f 1287 farg.ll = 0x0000000000000000ULL;
4ecc3190 1288 }
4ecc3190 1289 }
af12906f 1290 return farg.ll;
9a64fbe4
FB
1291}
1292
af12906f
AJ
1293/* fsel - fsel. */
1294uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
9a64fbe4 1295{
af12906f
AJ
1296 CPU_DoubleU farg1, farg2, farg3;
1297
1298 farg1.ll = arg1;
1299 farg2.ll = arg2;
1300 farg3.ll = arg3;
1301
1302 if (!fpisneg(farg1.d) || iszero(farg1.d))
1303 return farg2.ll;
4ecc3190 1304 else
af12906f 1305 return farg2.ll;
9a64fbe4
FB
1306}
1307
af12906f 1308uint32_t helper_fcmpu (uint64_t arg1, uint64_t arg2)
9a64fbe4 1309{
af12906f 1310 CPU_DoubleU farg1, farg2;
e1571908 1311 uint32_t ret = 0;
af12906f
AJ
1312 farg1.ll = arg1;
1313 farg2.ll = arg2;
e1571908 1314
af12906f
AJ
1315 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1316 float64_is_signaling_nan(farg2.d))) {
7c58044c
JM
1317 /* sNaN comparison */
1318 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1319 } else {
af12906f 1320 if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
e1571908 1321 ret = 0x08UL;
af12906f 1322 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
e1571908 1323 ret = 0x04UL;
fdabc366 1324 } else {
e1571908 1325 ret = 0x02UL;
fdabc366 1326 }
9a64fbe4 1327 }
7c58044c 1328 env->fpscr &= ~(0x0F << FPSCR_FPRF);
e1571908
AJ
1329 env->fpscr |= ret << FPSCR_FPRF;
1330 return ret;
9a64fbe4
FB
1331}
1332
af12906f 1333uint32_t helper_fcmpo (uint64_t arg1, uint64_t arg2)
9a64fbe4 1334{
af12906f 1335 CPU_DoubleU farg1, farg2;
e1571908 1336 uint32_t ret = 0;
af12906f
AJ
1337 farg1.ll = arg1;
1338 farg2.ll = arg2;
e1571908 1339
af12906f
AJ
1340 if (unlikely(float64_is_nan(farg1.d) ||
1341 float64_is_nan(farg2.d))) {
1342 if (float64_is_signaling_nan(farg1.d) ||
1343 float64_is_signaling_nan(farg2.d)) {
7c58044c
JM
1344 /* sNaN comparison */
1345 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1346 POWERPC_EXCP_FP_VXVC);
1347 } else {
1348 /* qNaN comparison */
1349 fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
1350 }
1351 } else {
af12906f 1352 if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
e1571908 1353 ret = 0x08UL;
af12906f 1354 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
e1571908 1355 ret = 0x04UL;
fdabc366 1356 } else {
e1571908 1357 ret = 0x02UL;
fdabc366 1358 }
9a64fbe4 1359 }
7c58044c 1360 env->fpscr &= ~(0x0F << FPSCR_FPRF);
e1571908
AJ
1361 env->fpscr |= ret << FPSCR_FPRF;
1362 return ret;
9a64fbe4
FB
1363}
1364
76a66253 1365#if !defined (CONFIG_USER_ONLY)
6b80055d 1366void cpu_dump_rfi (target_ulong RA, target_ulong msr);
0411a972 1367
6676f424 1368void do_store_msr (void)
0411a972 1369{
6676f424
AJ
1370 T0 = hreg_store_msr(env, T0, 0);
1371 if (T0 != 0) {
0411a972 1372 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
64adab3f 1373 raise_exception(env, T0);
0411a972
JM
1374 }
1375}
1376
1377static always_inline void __do_rfi (target_ulong nip, target_ulong msr,
1378 target_ulong msrm, int keep_msrh)
9a64fbe4 1379{
426613db 1380#if defined(TARGET_PPC64)
0411a972
JM
1381 if (msr & (1ULL << MSR_SF)) {
1382 nip = (uint64_t)nip;
1383 msr &= (uint64_t)msrm;
a42bd6cc 1384 } else {
0411a972
JM
1385 nip = (uint32_t)nip;
1386 msr = (uint32_t)(msr & msrm);
1387 if (keep_msrh)
1388 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
a42bd6cc 1389 }
426613db 1390#else
0411a972
JM
1391 nip = (uint32_t)nip;
1392 msr &= (uint32_t)msrm;
426613db 1393#endif
0411a972
JM
1394 /* XXX: beware: this is false if VLE is supported */
1395 env->nip = nip & ~((target_ulong)0x00000003);
a4f30719 1396 hreg_store_msr(env, msr, 1);
fdabc366 1397#if defined (DEBUG_OP)
0411a972 1398 cpu_dump_rfi(env->nip, env->msr);
fdabc366 1399#endif
0411a972
JM
1400 /* No need to raise an exception here,
1401 * as rfi is always the last insn of a TB
1402 */
fdabc366 1403 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
9a64fbe4 1404}
d9bce9d9 1405
0411a972
JM
1406void do_rfi (void)
1407{
1408 __do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1409 ~((target_ulong)0xFFFF0000), 1);
1410}
1411
d9bce9d9 1412#if defined(TARGET_PPC64)
426613db
JM
1413void do_rfid (void)
1414{
0411a972
JM
1415 __do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1416 ~((target_ulong)0xFFFF0000), 0);
d9bce9d9 1417}
7863667f 1418
be147d08
JM
1419void do_hrfid (void)
1420{
0411a972
JM
1421 __do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
1422 ~((target_ulong)0xFFFF0000), 0);
be147d08
JM
1423}
1424#endif
76a66253 1425#endif
9a64fbe4 1426
cab3bee2 1427void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
9a64fbe4 1428{
cab3bee2
AJ
1429 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1430 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1431 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1432 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1433 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
64adab3f 1434 raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
a42bd6cc 1435 }
9a64fbe4
FB
1436}
1437
d9bce9d9 1438#if defined(TARGET_PPC64)
cab3bee2 1439void helper_td (target_ulong arg1, target_ulong arg2, uint32_t flags)
d9bce9d9 1440{
cab3bee2
AJ
1441 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1442 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1443 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1444 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1445 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01)))))
64adab3f 1446 raise_exception_err(env, POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
d9bce9d9
JM
1447}
1448#endif
1449
fdabc366 1450/*****************************************************************************/
76a66253
JM
1451/* PowerPC 601 specific instructions (POWER bridge) */
1452void do_POWER_abso (void)
9a64fbe4 1453{
9c7e37e7 1454 if ((int32_t)T0 == INT32_MIN) {
76a66253 1455 T0 = INT32_MAX;
3d7b417e 1456 env->xer |= (1 << XER_OV) | (1 << XER_SO);
9c7e37e7 1457 } else if ((int32_t)T0 < 0) {
76a66253 1458 T0 = -T0;
3d7b417e 1459 env->xer &= ~(1 << XER_OV);
9c7e37e7 1460 } else {
3d7b417e 1461 env->xer &= ~(1 << XER_OV);
76a66253 1462 }
9a64fbe4
FB
1463}
1464
76a66253 1465void do_POWER_clcs (void)
9a64fbe4 1466{
76a66253
JM
1467 switch (T0) {
1468 case 0x0CUL:
1469 /* Instruction cache line size */
d63001d1 1470 T0 = env->icache_line_size;
76a66253
JM
1471 break;
1472 case 0x0DUL:
1473 /* Data cache line size */
d63001d1 1474 T0 = env->dcache_line_size;
76a66253
JM
1475 break;
1476 case 0x0EUL:
1477 /* Minimum cache line size */
d63001d1
JM
1478 T0 = env->icache_line_size < env->dcache_line_size ?
1479 env->icache_line_size : env->dcache_line_size;
76a66253
JM
1480 break;
1481 case 0x0FUL:
1482 /* Maximum cache line size */
d63001d1
JM
1483 T0 = env->icache_line_size > env->dcache_line_size ?
1484 env->icache_line_size : env->dcache_line_size;
76a66253
JM
1485 break;
1486 default:
1487 /* Undefined */
1488 break;
1489 }
1490}
1491
1492void do_POWER_div (void)
1493{
1494 uint64_t tmp;
1495
6f2d8978
JM
1496 if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
1497 (int32_t)T1 == 0) {
1498 T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
76a66253
JM
1499 env->spr[SPR_MQ] = 0;
1500 } else {
1501 tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
1502 env->spr[SPR_MQ] = tmp % T1;
d9bce9d9 1503 T0 = tmp / (int32_t)T1;
76a66253
JM
1504 }
1505}
1506
1507void do_POWER_divo (void)
1508{
1509 int64_t tmp;
1510
6f2d8978
JM
1511 if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
1512 (int32_t)T1 == 0) {
1513 T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
76a66253 1514 env->spr[SPR_MQ] = 0;
3d7b417e 1515 env->xer |= (1 << XER_OV) | (1 << XER_SO);
76a66253
JM
1516 } else {
1517 tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
1518 env->spr[SPR_MQ] = tmp % T1;
d9bce9d9 1519 tmp /= (int32_t)T1;
76a66253 1520 if (tmp > (int64_t)INT32_MAX || tmp < (int64_t)INT32_MIN) {
3d7b417e 1521 env->xer |= (1 << XER_OV) | (1 << XER_SO);
76a66253 1522 } else {
3d7b417e 1523 env->xer &= ~(1 << XER_OV);
76a66253
JM
1524 }
1525 T0 = tmp;
1526 }
1527}
1528
1529void do_POWER_divs (void)
1530{
6f2d8978
JM
1531 if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
1532 (int32_t)T1 == 0) {
1533 T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
76a66253
JM
1534 env->spr[SPR_MQ] = 0;
1535 } else {
1536 env->spr[SPR_MQ] = T0 % T1;
d9bce9d9 1537 T0 = (int32_t)T0 / (int32_t)T1;
76a66253
JM
1538 }
1539}
1540
1541void do_POWER_divso (void)
1542{
6f2d8978
JM
1543 if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == (int32_t)-1) ||
1544 (int32_t)T1 == 0) {
1545 T0 = UINT32_MAX * ((uint32_t)T0 >> 31);
76a66253 1546 env->spr[SPR_MQ] = 0;
3d7b417e 1547 env->xer |= (1 << XER_OV) | (1 << XER_SO);
76a66253 1548 } else {
d9bce9d9
JM
1549 T0 = (int32_t)T0 / (int32_t)T1;
1550 env->spr[SPR_MQ] = (int32_t)T0 % (int32_t)T1;
3d7b417e 1551 env->xer &= ~(1 << XER_OV);
76a66253
JM
1552 }
1553}
1554
1555void do_POWER_dozo (void)
1556{
d9bce9d9 1557 if ((int32_t)T1 > (int32_t)T0) {
76a66253
JM
1558 T2 = T0;
1559 T0 = T1 - T0;
d9bce9d9
JM
1560 if (((uint32_t)(~T2) ^ (uint32_t)T1 ^ UINT32_MAX) &
1561 ((uint32_t)(~T2) ^ (uint32_t)T0) & (1UL << 31)) {
3d7b417e 1562 env->xer |= (1 << XER_OV) | (1 << XER_SO);
76a66253 1563 } else {
3d7b417e 1564 env->xer &= ~(1 << XER_OV);
76a66253
JM
1565 }
1566 } else {
1567 T0 = 0;
3d7b417e 1568 env->xer &= ~(1 << XER_OV);
76a66253
JM
1569 }
1570}
1571
1572void do_POWER_maskg (void)
1573{
1574 uint32_t ret;
1575
d9bce9d9 1576 if ((uint32_t)T0 == (uint32_t)(T1 + 1)) {
6f2d8978 1577 ret = UINT32_MAX;
76a66253 1578 } else {
6f2d8978
JM
1579 ret = (UINT32_MAX >> ((uint32_t)T0)) ^
1580 ((UINT32_MAX >> ((uint32_t)T1)) >> 1);
d9bce9d9 1581 if ((uint32_t)T0 > (uint32_t)T1)
76a66253
JM
1582 ret = ~ret;
1583 }
1584 T0 = ret;
1585}
1586
1587void do_POWER_mulo (void)
1588{
1589 uint64_t tmp;
1590
1591 tmp = (uint64_t)T0 * (uint64_t)T1;
1592 env->spr[SPR_MQ] = tmp >> 32;
1593 T0 = tmp;
1594 if (tmp >> 32 != ((uint64_t)T0 >> 16) * ((uint64_t)T1 >> 16)) {
3d7b417e 1595 env->xer |= (1 << XER_OV) | (1 << XER_SO);
76a66253 1596 } else {
3d7b417e 1597 env->xer &= ~(1 << XER_OV);
76a66253
JM
1598 }
1599}
1600
1601#if !defined (CONFIG_USER_ONLY)
1602void do_POWER_rac (void)
1603{
76a66253 1604 mmu_ctx_t ctx;
faadf50e 1605 int nb_BATs;
76a66253
JM
1606
1607 /* We don't have to generate many instances of this instruction,
1608 * as rac is supervisor only.
1609 */
faadf50e
JM
1610 /* XXX: FIX THIS: Pretend we have no BAT */
1611 nb_BATs = env->nb_BATs;
1612 env->nb_BATs = 0;
1613 if (get_physical_address(env, &ctx, T0, 0, ACCESS_INT) == 0)
76a66253 1614 T0 = ctx.raddr;
faadf50e 1615 env->nb_BATs = nb_BATs;
76a66253
JM
1616}
1617
1618void do_POWER_rfsvc (void)
1619{
0411a972 1620 __do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
76a66253
JM
1621}
1622
056401ea
JM
1623void do_store_hid0_601 (void)
1624{
1625 uint32_t hid0;
1626
1627 hid0 = env->spr[SPR_HID0];
1628 if ((T0 ^ hid0) & 0x00000008) {
1629 /* Change current endianness */
1630 env->hflags &= ~(1 << MSR_LE);
1631 env->hflags_nmsr &= ~(1 << MSR_LE);
1632 env->hflags_nmsr |= (1 << MSR_LE) & (((T0 >> 3) & 1) << MSR_LE);
1633 env->hflags |= env->hflags_nmsr;
1634 if (loglevel != 0) {
1635 fprintf(logfile, "%s: set endianness to %c => " ADDRX "\n",
1636 __func__, T0 & 0x8 ? 'l' : 'b', env->hflags);
1637 }
1638 }
1639 env->spr[SPR_HID0] = T0;
76a66253
JM
1640}
1641#endif
1642
1643/*****************************************************************************/
1644/* 602 specific instructions */
1645/* mfrom is the most crazy instruction ever seen, imho ! */
1646/* Real implementation uses a ROM table. Do the same */
1647#define USE_MFROM_ROM_TABLE
cf02a65c 1648target_ulong helper_602_mfrom (target_ulong arg)
76a66253 1649{
cf02a65c 1650 if (likely(arg < 602)) {
d9bce9d9 1651#if defined(USE_MFROM_ROM_TABLE)
76a66253 1652#include "mfrom_table.c"
cf02a65c 1653 return mfrom_ROM_table[T0];
fdabc366 1654#else
76a66253
JM
1655 double d;
1656 /* Extremly decomposed:
cf02a65c
AJ
1657 * -arg / 256
1658 * return 256 * log10(10 + 1.0) + 0.5
76a66253 1659 */
cf02a65c 1660 d = arg;
76a66253
JM
1661 d = float64_div(d, 256, &env->fp_status);
1662 d = float64_chs(d);
1663 d = exp10(d); // XXX: use float emulation function
1664 d = float64_add(d, 1.0, &env->fp_status);
1665 d = log10(d); // XXX: use float emulation function
1666 d = float64_mul(d, 256, &env->fp_status);
1667 d = float64_add(d, 0.5, &env->fp_status);
cf02a65c 1668 return float64_round_to_int(d, &env->fp_status);
fdabc366 1669#endif
76a66253 1670 } else {
cf02a65c 1671 return 0;
76a66253
JM
1672 }
1673}
1674
1675/*****************************************************************************/
1676/* Embedded PowerPC specific helpers */
76a66253 1677
a750fc0b
JM
1678/* XXX: to be improved to check access rights when in user-mode */
1679void do_load_dcr (void)
1680{
1681 target_ulong val;
1682
1683 if (unlikely(env->dcr_env == NULL)) {
1684 if (loglevel != 0) {
1685 fprintf(logfile, "No DCR environment\n");
1686 }
64adab3f
AJ
1687 raise_exception_err(env, POWERPC_EXCP_PROGRAM,
1688 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
a750fc0b
JM
1689 } else if (unlikely(ppc_dcr_read(env->dcr_env, T0, &val) != 0)) {
1690 if (loglevel != 0) {
1691 fprintf(logfile, "DCR read error %d %03x\n", (int)T0, (int)T0);
1692 }
64adab3f
AJ
1693 raise_exception_err(env, POWERPC_EXCP_PROGRAM,
1694 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
a750fc0b
JM
1695 } else {
1696 T0 = val;
1697 }
1698}
1699
1700void do_store_dcr (void)
1701{
1702 if (unlikely(env->dcr_env == NULL)) {
1703 if (loglevel != 0) {
1704 fprintf(logfile, "No DCR environment\n");
1705 }
64adab3f
AJ
1706 raise_exception_err(env, POWERPC_EXCP_PROGRAM,
1707 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
a750fc0b
JM
1708 } else if (unlikely(ppc_dcr_write(env->dcr_env, T0, T1) != 0)) {
1709 if (loglevel != 0) {
1710 fprintf(logfile, "DCR write error %d %03x\n", (int)T0, (int)T0);
1711 }
64adab3f
AJ
1712 raise_exception_err(env, POWERPC_EXCP_PROGRAM,
1713 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
a750fc0b
JM
1714 }
1715}
1716
76a66253 1717#if !defined(CONFIG_USER_ONLY)
a42bd6cc 1718void do_40x_rfci (void)
76a66253 1719{
0411a972
JM
1720 __do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
1721 ~((target_ulong)0xFFFF0000), 0);
a42bd6cc
JM
1722}
1723
1724void do_rfci (void)
1725{
0411a972
JM
1726 __do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
1727 ~((target_ulong)0x3FFF0000), 0);
a42bd6cc
JM
1728}
1729
1730void do_rfdi (void)
1731{
0411a972
JM
1732 __do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
1733 ~((target_ulong)0x3FFF0000), 0);
a42bd6cc
JM
1734}
1735
1736void do_rfmci (void)
1737{
0411a972
JM
1738 __do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
1739 ~((target_ulong)0x3FFF0000), 0);
76a66253
JM
1740}
1741
76a66253
JM
1742void do_load_403_pb (int num)
1743{
1744 T0 = env->pb[num];
1745}
1746
1747void do_store_403_pb (int num)
1748{
1749 if (likely(env->pb[num] != T0)) {
1750 env->pb[num] = T0;
1751 /* Should be optimized */
1752 tlb_flush(env, 1);
1753 }
1754}
1755#endif
1756
1757/* 440 specific */
1758void do_440_dlmzb (void)
1759{
1760 target_ulong mask;
1761 int i;
1762
1763 i = 1;
1764 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1765 if ((T0 & mask) == 0)
1766 goto done;
1767 i++;
1768 }
1769 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
1770 if ((T1 & mask) == 0)
1771 break;
1772 i++;
1773 }
1774 done:
1775 T0 = i;
fdabc366
FB
1776}
1777
1c97856d 1778/*****************************************************************************/
0487d6a8
JM
1779/* SPE extension helpers */
1780/* Use a table to make this quicker */
1781static uint8_t hbrev[16] = {
1782 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
1783 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
1784};
1785
b068d6a7 1786static always_inline uint8_t byte_reverse (uint8_t val)
0487d6a8
JM
1787{
1788 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
1789}
1790
b068d6a7 1791static always_inline uint32_t word_reverse (uint32_t val)
0487d6a8
JM
1792{
1793 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
1794 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
1795}
1796
3cd7d1dd 1797#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
57951c27 1798target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
0487d6a8
JM
1799{
1800 uint32_t a, b, d, mask;
1801
3cd7d1dd 1802 mask = UINT32_MAX >> (32 - MASKBITS);
57951c27
AJ
1803 a = arg1 & mask;
1804 b = arg2 & mask;
3cd7d1dd 1805 d = word_reverse(1 + word_reverse(a | ~b));
57951c27 1806 return (arg1 & ~mask) | (d & b);
0487d6a8
JM
1807}
1808
57951c27 1809uint32_t helper_cntlsw32 (uint32_t val)
0487d6a8
JM
1810{
1811 if (val & 0x80000000)
603fccce 1812 return clz32(~val);
0487d6a8 1813 else
603fccce 1814 return clz32(val);
0487d6a8
JM
1815}
1816
57951c27 1817uint32_t helper_cntlzw32 (uint32_t val)
0487d6a8 1818{
603fccce 1819 return clz32(val);
0487d6a8
JM
1820}
1821
1c97856d
AJ
1822/* Single-precision floating-point conversions */
1823static always_inline uint32_t efscfsi (uint32_t val)
0487d6a8 1824{
0ca9d380 1825 CPU_FloatU u;
0487d6a8
JM
1826
1827 u.f = int32_to_float32(val, &env->spe_status);
1828
0ca9d380 1829 return u.l;
0487d6a8
JM
1830}
1831
1c97856d 1832static always_inline uint32_t efscfui (uint32_t val)
0487d6a8 1833{
0ca9d380 1834 CPU_FloatU u;
0487d6a8
JM
1835
1836 u.f = uint32_to_float32(val, &env->spe_status);
1837
0ca9d380 1838 return u.l;
0487d6a8
JM
1839}
1840
1c97856d 1841static always_inline int32_t efsctsi (uint32_t val)
0487d6a8 1842{
0ca9d380 1843 CPU_FloatU u;
0487d6a8 1844
0ca9d380 1845 u.l = val;
0487d6a8
JM
1846 /* NaN are not treated the same way IEEE 754 does */
1847 if (unlikely(isnan(u.f)))
1848 return 0;
1849
1850 return float32_to_int32(u.f, &env->spe_status);
1851}
1852
1c97856d 1853static always_inline uint32_t efsctui (uint32_t val)
0487d6a8 1854{
0ca9d380 1855 CPU_FloatU u;
0487d6a8 1856
0ca9d380 1857 u.l = val;
0487d6a8
JM
1858 /* NaN are not treated the same way IEEE 754 does */
1859 if (unlikely(isnan(u.f)))
1860 return 0;
1861
1862 return float32_to_uint32(u.f, &env->spe_status);
1863}
1864
1c97856d 1865static always_inline uint32_t efsctsiz (uint32_t val)
0487d6a8 1866{
0ca9d380 1867 CPU_FloatU u;
0487d6a8 1868
0ca9d380 1869 u.l = val;
0487d6a8
JM
1870 /* NaN are not treated the same way IEEE 754 does */
1871 if (unlikely(isnan(u.f)))
1872 return 0;
1873
1874 return float32_to_int32_round_to_zero(u.f, &env->spe_status);
1875}
1876
1c97856d 1877static always_inline uint32_t efsctuiz (uint32_t val)
0487d6a8 1878{
0ca9d380 1879 CPU_FloatU u;
0487d6a8 1880
0ca9d380 1881 u.l = val;
0487d6a8
JM
1882 /* NaN are not treated the same way IEEE 754 does */
1883 if (unlikely(isnan(u.f)))
1884 return 0;
1885
1886 return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
1887}
1888
1c97856d 1889static always_inline uint32_t efscfsf (uint32_t val)
0487d6a8 1890{
0ca9d380 1891 CPU_FloatU u;
0487d6a8
JM
1892 float32 tmp;
1893
1894 u.f = int32_to_float32(val, &env->spe_status);
1895 tmp = int64_to_float32(1ULL << 32, &env->spe_status);
1896 u.f = float32_div(u.f, tmp, &env->spe_status);
1897
0ca9d380 1898 return u.l;
0487d6a8
JM
1899}
1900
1c97856d 1901static always_inline uint32_t efscfuf (uint32_t val)
0487d6a8 1902{
0ca9d380 1903 CPU_FloatU u;
0487d6a8
JM
1904 float32 tmp;
1905
1906 u.f = uint32_to_float32(val, &env->spe_status);
1907 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
1908 u.f = float32_div(u.f, tmp, &env->spe_status);
1909
0ca9d380 1910 return u.l;
0487d6a8
JM
1911}
1912
1c97856d 1913static always_inline uint32_t efsctsf (uint32_t val)
0487d6a8 1914{
0ca9d380 1915 CPU_FloatU u;
0487d6a8
JM
1916 float32 tmp;
1917
0ca9d380 1918 u.l = val;
0487d6a8
JM
1919 /* NaN are not treated the same way IEEE 754 does */
1920 if (unlikely(isnan(u.f)))
1921 return 0;
1922 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
1923 u.f = float32_mul(u.f, tmp, &env->spe_status);
1924
1925 return float32_to_int32(u.f, &env->spe_status);
1926}
1927
1c97856d 1928static always_inline uint32_t efsctuf (uint32_t val)
0487d6a8 1929{
0ca9d380 1930 CPU_FloatU u;
0487d6a8
JM
1931 float32 tmp;
1932
0ca9d380 1933 u.l = val;
0487d6a8
JM
1934 /* NaN are not treated the same way IEEE 754 does */
1935 if (unlikely(isnan(u.f)))
1936 return 0;
1937 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
1938 u.f = float32_mul(u.f, tmp, &env->spe_status);
1939
1940 return float32_to_uint32(u.f, &env->spe_status);
1941}
1942
1c97856d
AJ
1943#define HELPER_SPE_SINGLE_CONV(name) \
1944uint32_t helper_e##name (uint32_t val) \
1945{ \
1946 return e##name(val); \
1947}
1948/* efscfsi */
1949HELPER_SPE_SINGLE_CONV(fscfsi);
1950/* efscfui */
1951HELPER_SPE_SINGLE_CONV(fscfui);
1952/* efscfuf */
1953HELPER_SPE_SINGLE_CONV(fscfuf);
1954/* efscfsf */
1955HELPER_SPE_SINGLE_CONV(fscfsf);
1956/* efsctsi */
1957HELPER_SPE_SINGLE_CONV(fsctsi);
1958/* efsctui */
1959HELPER_SPE_SINGLE_CONV(fsctui);
1960/* efsctsiz */
1961HELPER_SPE_SINGLE_CONV(fsctsiz);
1962/* efsctuiz */
1963HELPER_SPE_SINGLE_CONV(fsctuiz);
1964/* efsctsf */
1965HELPER_SPE_SINGLE_CONV(fsctsf);
1966/* efsctuf */
1967HELPER_SPE_SINGLE_CONV(fsctuf);
1968
1969#define HELPER_SPE_VECTOR_CONV(name) \
1970uint64_t helper_ev##name (uint64_t val) \
1971{ \
1972 return ((uint64_t)e##name(val >> 32) << 32) | \
1973 (uint64_t)e##name(val); \
0487d6a8 1974}
1c97856d
AJ
1975/* evfscfsi */
1976HELPER_SPE_VECTOR_CONV(fscfsi);
1977/* evfscfui */
1978HELPER_SPE_VECTOR_CONV(fscfui);
1979/* evfscfuf */
1980HELPER_SPE_VECTOR_CONV(fscfuf);
1981/* evfscfsf */
1982HELPER_SPE_VECTOR_CONV(fscfsf);
1983/* evfsctsi */
1984HELPER_SPE_VECTOR_CONV(fsctsi);
1985/* evfsctui */
1986HELPER_SPE_VECTOR_CONV(fsctui);
1987/* evfsctsiz */
1988HELPER_SPE_VECTOR_CONV(fsctsiz);
1989/* evfsctuiz */
1990HELPER_SPE_VECTOR_CONV(fsctuiz);
1991/* evfsctsf */
1992HELPER_SPE_VECTOR_CONV(fsctsf);
1993/* evfsctuf */
1994HELPER_SPE_VECTOR_CONV(fsctuf);
0487d6a8 1995
1c97856d
AJ
1996/* Single-precision floating-point arithmetic */
1997static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
0487d6a8 1998{
1c97856d
AJ
1999 CPU_FloatU u1, u2;
2000 u1.l = op1;
2001 u2.l = op2;
2002 u1.f = float32_add(u1.f, u2.f, &env->spe_status);
2003 return u1.l;
0487d6a8
JM
2004}
2005
1c97856d 2006static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
0487d6a8 2007{
1c97856d
AJ
2008 CPU_FloatU u1, u2;
2009 u1.l = op1;
2010 u2.l = op2;
2011 u1.f = float32_sub(u1.f, u2.f, &env->spe_status);
2012 return u1.l;
0487d6a8
JM
2013}
2014
1c97856d 2015static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
0487d6a8 2016{
1c97856d
AJ
2017 CPU_FloatU u1, u2;
2018 u1.l = op1;
2019 u2.l = op2;
2020 u1.f = float32_mul(u1.f, u2.f, &env->spe_status);
2021 return u1.l;
0487d6a8
JM
2022}
2023
1c97856d 2024static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
0487d6a8 2025{
1c97856d
AJ
2026 CPU_FloatU u1, u2;
2027 u1.l = op1;
2028 u2.l = op2;
2029 u1.f = float32_div(u1.f, u2.f, &env->spe_status);
2030 return u1.l;
0487d6a8
JM
2031}
2032
1c97856d
AJ
2033#define HELPER_SPE_SINGLE_ARITH(name) \
2034uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
2035{ \
2036 return e##name(op1, op2); \
2037}
2038/* efsadd */
2039HELPER_SPE_SINGLE_ARITH(fsadd);
2040/* efssub */
2041HELPER_SPE_SINGLE_ARITH(fssub);
2042/* efsmul */
2043HELPER_SPE_SINGLE_ARITH(fsmul);
2044/* efsdiv */
2045HELPER_SPE_SINGLE_ARITH(fsdiv);
2046
2047#define HELPER_SPE_VECTOR_ARITH(name) \
2048uint64_t helper_ev##name (uint64_t op1, uint64_t op2) \
2049{ \
2050 return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
2051 (uint64_t)e##name(op1, op2); \
2052}
2053/* evfsadd */
2054HELPER_SPE_VECTOR_ARITH(fsadd);
2055/* evfssub */
2056HELPER_SPE_VECTOR_ARITH(fssub);
2057/* evfsmul */
2058HELPER_SPE_VECTOR_ARITH(fsmul);
2059/* evfsdiv */
2060HELPER_SPE_VECTOR_ARITH(fsdiv);
2061
2062/* Single-precision floating-point comparisons */
2063static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
0487d6a8 2064{
1c97856d
AJ
2065 CPU_FloatU u1, u2;
2066 u1.l = op1;
2067 u2.l = op2;
2068 return float32_lt(u1.f, u2.f, &env->spe_status) ? 4 : 0;
0487d6a8
JM
2069}
2070
1c97856d 2071static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
0487d6a8 2072{
1c97856d
AJ
2073 CPU_FloatU u1, u2;
2074 u1.l = op1;
2075 u2.l = op2;
2076 return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 4;
0487d6a8
JM
2077}
2078
1c97856d 2079static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
0487d6a8 2080{
1c97856d
AJ
2081 CPU_FloatU u1, u2;
2082 u1.l = op1;
2083 u2.l = op2;
2084 return float32_eq(u1.f, u2.f, &env->spe_status) ? 4 : 0;
0487d6a8
JM
2085}
2086
1c97856d 2087static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
0487d6a8
JM
2088{
2089 /* XXX: TODO: test special values (NaN, infinites, ...) */
1c97856d 2090 return efststlt(op1, op2);
0487d6a8
JM
2091}
2092
1c97856d 2093static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
0487d6a8
JM
2094{
2095 /* XXX: TODO: test special values (NaN, infinites, ...) */
1c97856d 2096 return efststgt(op1, op2);
0487d6a8
JM
2097}
2098
1c97856d 2099static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
0487d6a8
JM
2100{
2101 /* XXX: TODO: test special values (NaN, infinites, ...) */
1c97856d 2102 return efststeq(op1, op2);
0487d6a8
JM
2103}
2104
1c97856d
AJ
2105#define HELPER_SINGLE_SPE_CMP(name) \
2106uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
2107{ \
2108 return e##name(op1, op2) << 2; \
2109}
2110/* efststlt */
2111HELPER_SINGLE_SPE_CMP(fststlt);
2112/* efststgt */
2113HELPER_SINGLE_SPE_CMP(fststgt);
2114/* efststeq */
2115HELPER_SINGLE_SPE_CMP(fststeq);
2116/* efscmplt */
2117HELPER_SINGLE_SPE_CMP(fscmplt);
2118/* efscmpgt */
2119HELPER_SINGLE_SPE_CMP(fscmpgt);
2120/* efscmpeq */
2121HELPER_SINGLE_SPE_CMP(fscmpeq);
2122
2123static always_inline uint32_t evcmp_merge (int t0, int t1)
0487d6a8 2124{
1c97856d 2125 return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
0487d6a8
JM
2126}
2127
1c97856d
AJ
2128#define HELPER_VECTOR_SPE_CMP(name) \
2129uint32_t helper_ev##name (uint64_t op1, uint64_t op2) \
2130{ \
2131 return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
0487d6a8 2132}
1c97856d
AJ
2133/* evfststlt */
2134HELPER_VECTOR_SPE_CMP(fststlt);
2135/* evfststgt */
2136HELPER_VECTOR_SPE_CMP(fststgt);
2137/* evfststeq */
2138HELPER_VECTOR_SPE_CMP(fststeq);
2139/* evfscmplt */
2140HELPER_VECTOR_SPE_CMP(fscmplt);
2141/* evfscmpgt */
2142HELPER_VECTOR_SPE_CMP(fscmpgt);
2143/* evfscmpeq */
2144HELPER_VECTOR_SPE_CMP(fscmpeq);
0487d6a8 2145
1c97856d
AJ
2146/* Double-precision floating-point conversion */
2147uint64_t helper_efdcfsi (uint32_t val)
0487d6a8 2148{
1c97856d
AJ
2149 CPU_DoubleU u;
2150
2151 u.d = int32_to_float64(val, &env->spe_status);
2152
2153 return u.ll;
0487d6a8
JM
2154}
2155
1c97856d 2156uint64_t helper_efdcfsid (uint64_t val)
0487d6a8 2157{
0ca9d380 2158 CPU_DoubleU u;
0487d6a8 2159
0ca9d380 2160 u.d = int64_to_float64(val, &env->spe_status);
0487d6a8 2161
0ca9d380 2162 return u.ll;
0487d6a8
JM
2163}
2164
1c97856d
AJ
2165uint64_t helper_efdcfui (uint32_t val)
2166{
2167 CPU_DoubleU u;
2168
2169 u.d = uint32_to_float64(val, &env->spe_status);
2170
2171 return u.ll;
2172}
2173
2174uint64_t helper_efdcfuid (uint64_t val)
0487d6a8 2175{
0ca9d380 2176 CPU_DoubleU u;
0487d6a8 2177
0ca9d380 2178 u.d = uint64_to_float64(val, &env->spe_status);
0487d6a8 2179
0ca9d380 2180 return u.ll;
0487d6a8
JM
2181}
2182
1c97856d 2183uint32_t helper_efdctsi (uint64_t val)
0487d6a8 2184{
0ca9d380 2185 CPU_DoubleU u;
0487d6a8 2186
0ca9d380 2187 u.ll = val;
0487d6a8 2188 /* NaN are not treated the same way IEEE 754 does */
0ca9d380 2189 if (unlikely(isnan(u.d)))
0487d6a8
JM
2190 return 0;
2191
1c97856d 2192 return float64_to_int32(u.d, &env->spe_status);
0487d6a8
JM
2193}
2194
1c97856d 2195uint32_t helper_efdctui (uint64_t val)
0487d6a8 2196{
0ca9d380 2197 CPU_DoubleU u;
0487d6a8 2198
0ca9d380 2199 u.ll = val;
0487d6a8 2200 /* NaN are not treated the same way IEEE 754 does */
0ca9d380 2201 if (unlikely(isnan(u.d)))
0487d6a8
JM
2202 return 0;
2203
1c97856d 2204 return float64_to_uint32(u.d, &env->spe_status);
0487d6a8
JM
2205}
2206
1c97856d 2207uint32_t helper_efdctsiz (uint64_t val)
0487d6a8 2208{
0ca9d380 2209 CPU_DoubleU u;
0487d6a8 2210
0ca9d380 2211 u.ll = val;
0487d6a8 2212 /* NaN are not treated the same way IEEE 754 does */
0ca9d380 2213 if (unlikely(isnan(u.d)))
0487d6a8
JM
2214 return 0;
2215
1c97856d 2216 return float64_to_int32_round_to_zero(u.d, &env->spe_status);
0487d6a8
JM
2217}
2218
1c97856d 2219uint64_t helper_efdctsidz (uint64_t val)
0487d6a8 2220{
0ca9d380 2221 CPU_DoubleU u;
0487d6a8 2222
0ca9d380 2223 u.ll = val;
0487d6a8 2224 /* NaN are not treated the same way IEEE 754 does */
0ca9d380 2225 if (unlikely(isnan(u.d)))
0487d6a8
JM
2226 return 0;
2227
1c97856d 2228 return float64_to_int64_round_to_zero(u.d, &env->spe_status);
0487d6a8
JM
2229}
2230
1c97856d 2231uint32_t helper_efdctuiz (uint64_t val)
0487d6a8 2232{
1c97856d 2233 CPU_DoubleU u;
0487d6a8 2234
1c97856d
AJ
2235 u.ll = val;
2236 /* NaN are not treated the same way IEEE 754 does */
2237 if (unlikely(isnan(u.d)))
2238 return 0;
0487d6a8 2239
1c97856d 2240 return float64_to_uint32_round_to_zero(u.d, &env->spe_status);
0487d6a8
JM
2241}
2242
1c97856d 2243uint64_t helper_efdctuidz (uint64_t val)
0487d6a8 2244{
1c97856d 2245 CPU_DoubleU u;
0487d6a8 2246
1c97856d
AJ
2247 u.ll = val;
2248 /* NaN are not treated the same way IEEE 754 does */
2249 if (unlikely(isnan(u.d)))
2250 return 0;
0487d6a8 2251
1c97856d 2252 return float64_to_uint64_round_to_zero(u.d, &env->spe_status);
0487d6a8
JM
2253}
2254
1c97856d 2255uint64_t helper_efdcfsf (uint32_t val)
0487d6a8 2256{
0ca9d380 2257 CPU_DoubleU u;
0487d6a8
JM
2258 float64 tmp;
2259
0ca9d380 2260 u.d = int32_to_float64(val, &env->spe_status);
0487d6a8 2261 tmp = int64_to_float64(1ULL << 32, &env->spe_status);
0ca9d380 2262 u.d = float64_div(u.d, tmp, &env->spe_status);
0487d6a8 2263
0ca9d380 2264 return u.ll;
0487d6a8
JM
2265}
2266
1c97856d 2267uint64_t helper_efdcfuf (uint32_t val)
0487d6a8 2268{
0ca9d380 2269 CPU_DoubleU u;
0487d6a8
JM
2270 float64 tmp;
2271
0ca9d380 2272 u.d = uint32_to_float64(val, &env->spe_status);
0487d6a8 2273 tmp = int64_to_float64(1ULL << 32, &env->spe_status);
0ca9d380 2274 u.d = float64_div(u.d, tmp, &env->spe_status);
0487d6a8 2275
0ca9d380 2276 return u.ll;
0487d6a8
JM
2277}
2278
1c97856d 2279uint32_t helper_efdctsf (uint64_t val)
0487d6a8 2280{
0ca9d380 2281 CPU_DoubleU u;
0487d6a8
JM
2282 float64 tmp;
2283
0ca9d380 2284 u.ll = val;
0487d6a8 2285 /* NaN are not treated the same way IEEE 754 does */
0ca9d380 2286 if (unlikely(isnan(u.d)))
0487d6a8
JM
2287 return 0;
2288 tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
0ca9d380 2289 u.d = float64_mul(u.d, tmp, &env->spe_status);
0487d6a8 2290
0ca9d380 2291 return float64_to_int32(u.d, &env->spe_status);
0487d6a8
JM
2292}
2293
1c97856d 2294uint32_t helper_efdctuf (uint64_t val)
0487d6a8 2295{
0ca9d380 2296 CPU_DoubleU u;
0487d6a8
JM
2297 float64 tmp;
2298
0ca9d380 2299 u.ll = val;
0487d6a8 2300 /* NaN are not treated the same way IEEE 754 does */
0ca9d380 2301 if (unlikely(isnan(u.d)))
0487d6a8
JM
2302 return 0;
2303 tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
0ca9d380 2304 u.d = float64_mul(u.d, tmp, &env->spe_status);
0487d6a8 2305
0ca9d380 2306 return float64_to_uint32(u.d, &env->spe_status);
0487d6a8
JM
2307}
2308
1c97856d 2309uint32_t helper_efscfd (uint64_t val)
0487d6a8 2310{
0ca9d380
AJ
2311 CPU_DoubleU u1;
2312 CPU_FloatU u2;
0487d6a8 2313
0ca9d380
AJ
2314 u1.ll = val;
2315 u2.f = float64_to_float32(u1.d, &env->spe_status);
0487d6a8 2316
0ca9d380 2317 return u2.l;
0487d6a8
JM
2318}
2319
1c97856d 2320uint64_t helper_efdcfs (uint32_t val)
0487d6a8 2321{
0ca9d380
AJ
2322 CPU_DoubleU u2;
2323 CPU_FloatU u1;
0487d6a8 2324
0ca9d380
AJ
2325 u1.l = val;
2326 u2.d = float32_to_float64(u1.f, &env->spe_status);
0487d6a8 2327
0ca9d380 2328 return u2.ll;
0487d6a8
JM
2329}
2330
1c97856d
AJ
2331/* Double precision fixed-point arithmetic */
2332uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
0487d6a8 2333{
1c97856d
AJ
2334 CPU_DoubleU u1, u2;
2335 u1.ll = op1;
2336 u2.ll = op2;
2337 u1.d = float64_add(u1.d, u2.d, &env->spe_status);
2338 return u1.ll;
0487d6a8
JM
2339}
2340
1c97856d 2341uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
0487d6a8 2342{
1c97856d
AJ
2343 CPU_DoubleU u1, u2;
2344 u1.ll = op1;
2345 u2.ll = op2;
2346 u1.d = float64_sub(u1.d, u2.d, &env->spe_status);
2347 return u1.ll;
0487d6a8
JM
2348}
2349
1c97856d 2350uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
0487d6a8 2351{
1c97856d
AJ
2352 CPU_DoubleU u1, u2;
2353 u1.ll = op1;
2354 u2.ll = op2;
2355 u1.d = float64_mul(u1.d, u2.d, &env->spe_status);
2356 return u1.ll;
0487d6a8
JM
2357}
2358
1c97856d 2359uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
0487d6a8 2360{
1c97856d
AJ
2361 CPU_DoubleU u1, u2;
2362 u1.ll = op1;
2363 u2.ll = op2;
2364 u1.d = float64_div(u1.d, u2.d, &env->spe_status);
2365 return u1.ll;
0487d6a8
JM
2366}
2367
1c97856d
AJ
2368/* Double precision floating point helpers */
2369uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
0487d6a8 2370{
1c97856d
AJ
2371 CPU_DoubleU u1, u2;
2372 u1.ll = op1;
2373 u2.ll = op2;
2374 return float64_lt(u1.d, u2.d, &env->spe_status) ? 4 : 0;
0487d6a8
JM
2375}
2376
1c97856d 2377uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
0487d6a8 2378{
1c97856d
AJ
2379 CPU_DoubleU u1, u2;
2380 u1.ll = op1;
2381 u2.ll = op2;
2382 return float64_le(u1.d, u2.d, &env->spe_status) ? 0 : 4;
0487d6a8
JM
2383}
2384
1c97856d 2385uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
0487d6a8 2386{
1c97856d
AJ
2387 CPU_DoubleU u1, u2;
2388 u1.ll = op1;
2389 u2.ll = op2;
2390 return float64_eq(u1.d, u2.d, &env->spe_status) ? 4 : 0;
0487d6a8
JM
2391}
2392
1c97856d 2393uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
0487d6a8 2394{
1c97856d
AJ
2395 /* XXX: TODO: test special values (NaN, infinites, ...) */
2396 return helper_efdtstlt(op1, op2);
0487d6a8
JM
2397}
2398
1c97856d
AJ
2399uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
2400{
2401 /* XXX: TODO: test special values (NaN, infinites, ...) */
2402 return helper_efdtstgt(op1, op2);
2403}
0487d6a8 2404
1c97856d
AJ
2405uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
2406{
2407 /* XXX: TODO: test special values (NaN, infinites, ...) */
2408 return helper_efdtsteq(op1, op2);
2409}
0487d6a8 2410
fdabc366
FB
2411/*****************************************************************************/
2412/* Softmmu support */
2413#if !defined (CONFIG_USER_ONLY)
2414
2415#define MMUSUFFIX _mmu
fdabc366
FB
2416
2417#define SHIFT 0
2418#include "softmmu_template.h"
2419
2420#define SHIFT 1
2421#include "softmmu_template.h"
2422
2423#define SHIFT 2
2424#include "softmmu_template.h"
2425
2426#define SHIFT 3
2427#include "softmmu_template.h"
2428
2429/* try to fill the TLB and return an exception if error. If retaddr is
2430 NULL, it means that the function was called in C code (i.e. not
2431 from generated code or from helper.c) */
2432/* XXX: fix it to restore all registers */
6ebbf390 2433void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
fdabc366
FB
2434{
2435 TranslationBlock *tb;
2436 CPUState *saved_env;
44f8625d 2437 unsigned long pc;
fdabc366
FB
2438 int ret;
2439
2440 /* XXX: hack to restore env in all cases, even if not called from
2441 generated code */
2442 saved_env = env;
2443 env = cpu_single_env;
6ebbf390 2444 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
76a66253 2445 if (unlikely(ret != 0)) {
fdabc366
FB
2446 if (likely(retaddr)) {
2447 /* now we have a real cpu fault */
44f8625d 2448 pc = (unsigned long)retaddr;
fdabc366
FB
2449 tb = tb_find_pc(pc);
2450 if (likely(tb)) {
2451 /* the PC is inside the translated code. It means that we have
2452 a virtual CPU fault */
2453 cpu_restore_state(tb, env, pc, NULL);
76a66253 2454 }
fdabc366 2455 }
64adab3f 2456 raise_exception_err(env, env->exception_index, env->error_code);
fdabc366
FB
2457 }
2458 env = saved_env;
9a64fbe4
FB
2459}
2460
76a66253
JM
2461/* Software driven TLBs management */
2462/* PowerPC 602/603 software TLB load instructions helpers */
0f3955e2 2463static void helper_load_6xx_tlb (target_ulong new_EPN, int is_code)
76a66253
JM
2464{
2465 target_ulong RPN, CMP, EPN;
2466 int way;
d9bce9d9 2467
76a66253
JM
2468 RPN = env->spr[SPR_RPA];
2469 if (is_code) {
2470 CMP = env->spr[SPR_ICMP];
2471 EPN = env->spr[SPR_IMISS];
2472 } else {
2473 CMP = env->spr[SPR_DCMP];
2474 EPN = env->spr[SPR_DMISS];
2475 }
2476 way = (env->spr[SPR_SRR1] >> 17) & 1;
2477#if defined (DEBUG_SOFTWARE_TLB)
2478 if (loglevel != 0) {
6b542af7
JM
2479 fprintf(logfile, "%s: EPN " TDX " " ADDRX " PTE0 " ADDRX
2480 " PTE1 " ADDRX " way %d\n",
2481 __func__, T0, EPN, CMP, RPN, way);
76a66253
JM
2482 }
2483#endif
2484 /* Store this TLB */
0f3955e2 2485 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
d9bce9d9 2486 way, is_code, CMP, RPN);
76a66253
JM
2487}
2488
0f3955e2
AJ
2489void helper_load_6xx_tlbd (target_ulong EPN)
2490{
2491 helper_load_6xx_tlb(EPN, 0);
2492}
2493
2494void helper_load_6xx_tlbi (target_ulong EPN)
2495{
2496 helper_load_6xx_tlb(EPN, 1);
2497}
2498
2499/* PowerPC 74xx software TLB load instructions helpers */
2500static void helper_load_74xx_tlb (target_ulong new_EPN, int is_code)
7dbe11ac
JM
2501{
2502 target_ulong RPN, CMP, EPN;
2503 int way;
2504
2505 RPN = env->spr[SPR_PTELO];
2506 CMP = env->spr[SPR_PTEHI];
2507 EPN = env->spr[SPR_TLBMISS] & ~0x3;
2508 way = env->spr[SPR_TLBMISS] & 0x3;
2509#if defined (DEBUG_SOFTWARE_TLB)
2510 if (loglevel != 0) {
6b542af7
JM
2511 fprintf(logfile, "%s: EPN " TDX " " ADDRX " PTE0 " ADDRX
2512 " PTE1 " ADDRX " way %d\n",
2513 __func__, T0, EPN, CMP, RPN, way);
7dbe11ac
JM
2514 }
2515#endif
2516 /* Store this TLB */
0f3955e2 2517 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
7dbe11ac
JM
2518 way, is_code, CMP, RPN);
2519}
2520
0f3955e2
AJ
2521void helper_load_74xx_tlbd (target_ulong EPN)
2522{
2523 helper_load_74xx_tlb(EPN, 0);
2524}
2525
2526void helper_load_74xx_tlbi (target_ulong EPN)
2527{
2528 helper_load_74xx_tlb(EPN, 1);
2529}
2530
a11b8151 2531static always_inline target_ulong booke_tlb_to_page_size (int size)
a8dea12f
JM
2532{
2533 return 1024 << (2 * size);
2534}
2535
a11b8151 2536static always_inline int booke_page_size_to_tlb (target_ulong page_size)
a8dea12f
JM
2537{
2538 int size;
2539
2540 switch (page_size) {
2541 case 0x00000400UL:
2542 size = 0x0;
2543 break;
2544 case 0x00001000UL:
2545 size = 0x1;
2546 break;
2547 case 0x00004000UL:
2548 size = 0x2;
2549 break;
2550 case 0x00010000UL:
2551 size = 0x3;
2552 break;
2553 case 0x00040000UL:
2554 size = 0x4;
2555 break;
2556 case 0x00100000UL:
2557 size = 0x5;
2558 break;
2559 case 0x00400000UL:
2560 size = 0x6;
2561 break;
2562 case 0x01000000UL:
2563 size = 0x7;
2564 break;
2565 case 0x04000000UL:
2566 size = 0x8;
2567 break;
2568 case 0x10000000UL:
2569 size = 0x9;
2570 break;
2571 case 0x40000000UL:
2572 size = 0xA;
2573 break;
2574#if defined (TARGET_PPC64)
2575 case 0x000100000000ULL:
2576 size = 0xB;
2577 break;
2578 case 0x000400000000ULL:
2579 size = 0xC;
2580 break;
2581 case 0x001000000000ULL:
2582 size = 0xD;
2583 break;
2584 case 0x004000000000ULL:
2585 size = 0xE;
2586 break;
2587 case 0x010000000000ULL:
2588 size = 0xF;
2589 break;
2590#endif
2591 default:
2592 size = -1;
2593 break;
2594 }
2595
2596 return size;
2597}
2598
76a66253 2599/* Helpers for 4xx TLB management */
76a66253
JM
2600void do_4xx_tlbre_lo (void)
2601{
a8dea12f
JM
2602 ppcemb_tlb_t *tlb;
2603 int size;
76a66253
JM
2604
2605 T0 &= 0x3F;
a8dea12f
JM
2606 tlb = &env->tlb[T0].tlbe;
2607 T0 = tlb->EPN;
2608 if (tlb->prot & PAGE_VALID)
2609 T0 |= 0x400;
2610 size = booke_page_size_to_tlb(tlb->size);
2611 if (size < 0 || size > 0x7)
2612 size = 1;
2613 T0 |= size << 7;
2614 env->spr[SPR_40x_PID] = tlb->PID;
76a66253
JM
2615}
2616
2617void do_4xx_tlbre_hi (void)
2618{
a8dea12f 2619 ppcemb_tlb_t *tlb;
76a66253
JM
2620
2621 T0 &= 0x3F;
a8dea12f
JM
2622 tlb = &env->tlb[T0].tlbe;
2623 T0 = tlb->RPN;
2624 if (tlb->prot & PAGE_EXEC)
2625 T0 |= 0x200;
2626 if (tlb->prot & PAGE_WRITE)
2627 T0 |= 0x100;
76a66253
JM
2628}
2629
c55e9aef 2630void do_4xx_tlbwe_hi (void)
76a66253 2631{
a8dea12f 2632 ppcemb_tlb_t *tlb;
76a66253
JM
2633 target_ulong page, end;
2634
c55e9aef 2635#if defined (DEBUG_SOFTWARE_TLB)
6b80055d 2636 if (loglevel != 0) {
6b542af7 2637 fprintf(logfile, "%s T0 " TDX " T1 " TDX "\n", __func__, T0, T1);
c55e9aef
JM
2638 }
2639#endif
76a66253 2640 T0 &= 0x3F;
a8dea12f 2641 tlb = &env->tlb[T0].tlbe;
76a66253
JM
2642 /* Invalidate previous TLB (if it's valid) */
2643 if (tlb->prot & PAGE_VALID) {
2644 end = tlb->EPN + tlb->size;
c55e9aef 2645#if defined (DEBUG_SOFTWARE_TLB)
6b80055d 2646 if (loglevel != 0) {
c55e9aef
JM
2647 fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
2648 " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end);
2649 }
2650#endif
76a66253
JM
2651 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
2652 tlb_flush_page(env, page);
2653 }
a8dea12f 2654 tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7);
c294fc58
JM
2655 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
2656 * If this ever occurs, one should use the ppcemb target instead
2657 * of the ppc or ppc64 one
2658 */
2659 if ((T1 & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
71c8b8fd
JM
2660 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
2661 "are not supported (%d)\n",
c294fc58
JM
2662 tlb->size, TARGET_PAGE_SIZE, (int)((T1 >> 7) & 0x7));
2663 }
a750fc0b 2664 tlb->EPN = T1 & ~(tlb->size - 1);
c55e9aef 2665 if (T1 & 0x40)
76a66253
JM
2666 tlb->prot |= PAGE_VALID;
2667 else
2668 tlb->prot &= ~PAGE_VALID;
c294fc58
JM
2669 if (T1 & 0x20) {
2670 /* XXX: TO BE FIXED */
2671 cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
2672 }
c55e9aef 2673 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
a8dea12f 2674 tlb->attr = T1 & 0xFF;
c55e9aef 2675#if defined (DEBUG_SOFTWARE_TLB)
c294fc58
JM
2676 if (loglevel != 0) {
2677 fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
c55e9aef 2678 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
5fafdf24 2679 (int)T0, tlb->RPN, tlb->EPN, tlb->size,
c55e9aef
JM
2680 tlb->prot & PAGE_READ ? 'r' : '-',
2681 tlb->prot & PAGE_WRITE ? 'w' : '-',
2682 tlb->prot & PAGE_EXEC ? 'x' : '-',
2683 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2684 }
2685#endif
76a66253
JM
2686 /* Invalidate new TLB (if valid) */
2687 if (tlb->prot & PAGE_VALID) {
2688 end = tlb->EPN + tlb->size;
c55e9aef 2689#if defined (DEBUG_SOFTWARE_TLB)
6b80055d 2690 if (loglevel != 0) {
c55e9aef
JM
2691 fprintf(logfile, "%s: invalidate TLB %d start " ADDRX
2692 " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end);
2693 }
2694#endif
76a66253
JM
2695 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
2696 tlb_flush_page(env, page);
2697 }
76a66253
JM
2698}
2699
c55e9aef 2700void do_4xx_tlbwe_lo (void)
76a66253 2701{
a8dea12f 2702 ppcemb_tlb_t *tlb;
76a66253 2703
c55e9aef 2704#if defined (DEBUG_SOFTWARE_TLB)
6b80055d 2705 if (loglevel != 0) {
6b542af7 2706 fprintf(logfile, "%s T0 " TDX " T1 " TDX "\n", __func__, T0, T1);
c55e9aef
JM
2707 }
2708#endif
76a66253 2709 T0 &= 0x3F;
a8dea12f 2710 tlb = &env->tlb[T0].tlbe;
76a66253
JM
2711 tlb->RPN = T1 & 0xFFFFFC00;
2712 tlb->prot = PAGE_READ;
2713 if (T1 & 0x200)
2714 tlb->prot |= PAGE_EXEC;
2715 if (T1 & 0x100)
2716 tlb->prot |= PAGE_WRITE;
c55e9aef 2717#if defined (DEBUG_SOFTWARE_TLB)
6b80055d
JM
2718 if (loglevel != 0) {
2719 fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
c55e9aef 2720 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
5fafdf24 2721 (int)T0, tlb->RPN, tlb->EPN, tlb->size,
c55e9aef
JM
2722 tlb->prot & PAGE_READ ? 'r' : '-',
2723 tlb->prot & PAGE_WRITE ? 'w' : '-',
2724 tlb->prot & PAGE_EXEC ? 'x' : '-',
2725 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
2726 }
2727#endif
76a66253 2728}
5eb7995e 2729
a4bb6c3e
JM
2730/* PowerPC 440 TLB management */
2731void do_440_tlbwe (int word)
5eb7995e
JM
2732{
2733 ppcemb_tlb_t *tlb;
a4bb6c3e 2734 target_ulong EPN, RPN, size;
5eb7995e
JM
2735 int do_flush_tlbs;
2736
2737#if defined (DEBUG_SOFTWARE_TLB)
2738 if (loglevel != 0) {
6b542af7 2739 fprintf(logfile, "%s word %d T0 " TDX " T1 " TDX "\n",
69facb78 2740 __func__, word, T0, T1);
5eb7995e
JM
2741 }
2742#endif
2743 do_flush_tlbs = 0;
2744 T0 &= 0x3F;
2745 tlb = &env->tlb[T0].tlbe;
a4bb6c3e
JM
2746 switch (word) {
2747 default:
2748 /* Just here to please gcc */
2749 case 0:
2750 EPN = T1 & 0xFFFFFC00;
2751 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
5eb7995e 2752 do_flush_tlbs = 1;
a4bb6c3e
JM
2753 tlb->EPN = EPN;
2754 size = booke_tlb_to_page_size((T1 >> 4) & 0xF);
2755 if ((tlb->prot & PAGE_VALID) && tlb->size < size)
2756 do_flush_tlbs = 1;
2757 tlb->size = size;
2758 tlb->attr &= ~0x1;
2759 tlb->attr |= (T1 >> 8) & 1;
2760 if (T1 & 0x200) {
2761 tlb->prot |= PAGE_VALID;
2762 } else {
2763 if (tlb->prot & PAGE_VALID) {
2764 tlb->prot &= ~PAGE_VALID;
2765 do_flush_tlbs = 1;
2766 }
5eb7995e 2767 }
a4bb6c3e
JM
2768 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
2769 if (do_flush_tlbs)
2770 tlb_flush(env, 1);
2771 break;
2772 case 1:
2773 RPN = T1 & 0xFFFFFC0F;
2774 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
2775 tlb_flush(env, 1);
2776 tlb->RPN = RPN;
2777 break;
2778 case 2:
2779 tlb->attr = (tlb->attr & 0x1) | (T1 & 0x0000FF00);
2780 tlb->prot = tlb->prot & PAGE_VALID;
2781 if (T1 & 0x1)
2782 tlb->prot |= PAGE_READ << 4;
2783 if (T1 & 0x2)
2784 tlb->prot |= PAGE_WRITE << 4;
2785 if (T1 & 0x4)
2786 tlb->prot |= PAGE_EXEC << 4;
2787 if (T1 & 0x8)
2788 tlb->prot |= PAGE_READ;
2789 if (T1 & 0x10)
2790 tlb->prot |= PAGE_WRITE;
2791 if (T1 & 0x20)
2792 tlb->prot |= PAGE_EXEC;
2793 break;
5eb7995e 2794 }
5eb7995e
JM
2795}
2796
a4bb6c3e 2797void do_440_tlbre (int word)
5eb7995e
JM
2798{
2799 ppcemb_tlb_t *tlb;
2800 int size;
2801
2802 T0 &= 0x3F;
2803 tlb = &env->tlb[T0].tlbe;
a4bb6c3e
JM
2804 switch (word) {
2805 default:
2806 /* Just here to please gcc */
2807 case 0:
2808 T0 = tlb->EPN;
2809 size = booke_page_size_to_tlb(tlb->size);
2810 if (size < 0 || size > 0xF)
2811 size = 1;
2812 T0 |= size << 4;
2813 if (tlb->attr & 0x1)
2814 T0 |= 0x100;
2815 if (tlb->prot & PAGE_VALID)
2816 T0 |= 0x200;
2817 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
2818 env->spr[SPR_440_MMUCR] |= tlb->PID;
2819 break;
2820 case 1:
2821 T0 = tlb->RPN;
2822 break;
2823 case 2:
2824 T0 = tlb->attr & ~0x1;
2825 if (tlb->prot & (PAGE_READ << 4))
2826 T0 |= 0x1;
2827 if (tlb->prot & (PAGE_WRITE << 4))
2828 T0 |= 0x2;
2829 if (tlb->prot & (PAGE_EXEC << 4))
2830 T0 |= 0x4;
2831 if (tlb->prot & PAGE_READ)
2832 T0 |= 0x8;
2833 if (tlb->prot & PAGE_WRITE)
2834 T0 |= 0x10;
2835 if (tlb->prot & PAGE_EXEC)
2836 T0 |= 0x20;
2837 break;
2838 }
5eb7995e 2839}
76a66253 2840#endif /* !CONFIG_USER_ONLY */