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