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