]> git.proxmox.com Git - qemu.git/blame - target-ppc/op_helper.c
usb-linux: Add support for buffering iso out usb packets
[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
8167ee88 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
9a64fbe4 18 */
7b239bec 19#include <string.h>
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 25
fdabc366
FB
26//#define DEBUG_OP
27//#define DEBUG_EXCEPTIONS
76a66253 28//#define DEBUG_SOFTWARE_TLB
fdabc366 29
d12d51d5 30#ifdef DEBUG_SOFTWARE_TLB
93fcfe39 31# define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
d12d51d5
AL
32#else
33# define LOG_SWTLB(...) do { } while (0)
34#endif
35
36
9a64fbe4
FB
37/*****************************************************************************/
38/* Exceptions processing helpers */
9a64fbe4 39
64adab3f 40void helper_raise_exception_err (uint32_t exception, uint32_t error_code)
9a64fbe4 41{
e06fcd75
AJ
42#if 0
43 printf("Raise exception %3x code : %d\n", exception, error_code);
44#endif
45 env->exception_index = exception;
46 env->error_code = error_code;
47 cpu_loop_exit();
76a66253 48}
9fddaa0c 49
e06fcd75 50void helper_raise_exception (uint32_t exception)
9fddaa0c 51{
e06fcd75 52 helper_raise_exception_err(exception, 0);
9a64fbe4
FB
53}
54
45d827d2
AJ
55/*****************************************************************************/
56/* SPR accesses */
57void helper_load_dump_spr (uint32_t sprn)
a496775f 58{
90e189ec
BS
59 qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn,
60 env->spr[sprn]);
a496775f
JM
61}
62
45d827d2 63void helper_store_dump_spr (uint32_t sprn)
a496775f 64{
90e189ec
BS
65 qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
66 env->spr[sprn]);
45d827d2
AJ
67}
68
69target_ulong helper_load_tbl (void)
70{
e3ea6529 71 return (target_ulong)cpu_ppc_load_tbl(env);
45d827d2
AJ
72}
73
74target_ulong helper_load_tbu (void)
75{
76 return cpu_ppc_load_tbu(env);
77}
78
79target_ulong helper_load_atbl (void)
80{
b711de95 81 return (target_ulong)cpu_ppc_load_atbl(env);
45d827d2
AJ
82}
83
84target_ulong helper_load_atbu (void)
85{
86 return cpu_ppc_load_atbu(env);
87}
88
3a7f009a
DG
89#if defined(TARGET_PPC64) && !defined(CONFIG_USER_ONLY)
90target_ulong helper_load_purr (void)
91{
92 return (target_ulong)cpu_ppc_load_purr(env);
93}
94#endif
95
45d827d2
AJ
96target_ulong helper_load_601_rtcl (void)
97{
98 return cpu_ppc601_load_rtcl(env);
99}
100
101target_ulong helper_load_601_rtcu (void)
102{
103 return cpu_ppc601_load_rtcu(env);
104}
105
106#if !defined(CONFIG_USER_ONLY)
107#if defined (TARGET_PPC64)
108void helper_store_asr (target_ulong val)
109{
110 ppc_store_asr(env, val);
111}
112#endif
113
114void helper_store_sdr1 (target_ulong val)
115{
116 ppc_store_sdr1(env, val);
117}
118
119void helper_store_tbl (target_ulong val)
120{
121 cpu_ppc_store_tbl(env, val);
122}
123
124void helper_store_tbu (target_ulong val)
125{
126 cpu_ppc_store_tbu(env, val);
127}
128
129void helper_store_atbl (target_ulong val)
130{
131 cpu_ppc_store_atbl(env, val);
132}
133
134void helper_store_atbu (target_ulong val)
135{
136 cpu_ppc_store_atbu(env, val);
137}
138
139void helper_store_601_rtcl (target_ulong val)
140{
141 cpu_ppc601_store_rtcl(env, val);
142}
143
144void helper_store_601_rtcu (target_ulong val)
145{
146 cpu_ppc601_store_rtcu(env, val);
147}
148
149target_ulong helper_load_decr (void)
150{
151 return cpu_ppc_load_decr(env);
152}
153
154void helper_store_decr (target_ulong val)
155{
156 cpu_ppc_store_decr(env, val);
157}
158
159void helper_store_hid0_601 (target_ulong val)
160{
161 target_ulong hid0;
162
163 hid0 = env->spr[SPR_HID0];
164 if ((val ^ hid0) & 0x00000008) {
165 /* Change current endianness */
166 env->hflags &= ~(1 << MSR_LE);
167 env->hflags_nmsr &= ~(1 << MSR_LE);
168 env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
169 env->hflags |= env->hflags_nmsr;
90e189ec
BS
170 qemu_log("%s: set endianness to %c => " TARGET_FMT_lx "\n", __func__,
171 val & 0x8 ? 'l' : 'b', env->hflags);
a496775f 172 }
45d827d2 173 env->spr[SPR_HID0] = (uint32_t)val;
a496775f
JM
174}
175
45d827d2
AJ
176void helper_store_403_pbr (uint32_t num, target_ulong value)
177{
178 if (likely(env->pb[num] != value)) {
179 env->pb[num] = value;
180 /* Should be optimized */
181 tlb_flush(env, 1);
182 }
183}
184
185target_ulong helper_load_40x_pit (void)
186{
187 return load_40x_pit(env);
188}
189
190void helper_store_40x_pit (target_ulong val)
191{
192 store_40x_pit(env, val);
193}
194
195void helper_store_40x_dbcr0 (target_ulong val)
196{
197 store_40x_dbcr0(env, val);
198}
199
200void helper_store_40x_sler (target_ulong val)
201{
202 store_40x_sler(env, val);
203}
204
205void helper_store_booke_tcr (target_ulong val)
206{
207 store_booke_tcr(env, val);
208}
209
210void helper_store_booke_tsr (target_ulong val)
211{
212 store_booke_tsr(env, val);
213}
214
215void helper_store_ibatu (uint32_t nr, target_ulong val)
216{
217 ppc_store_ibatu(env, nr, val);
218}
219
220void helper_store_ibatl (uint32_t nr, target_ulong val)
221{
222 ppc_store_ibatl(env, nr, val);
223}
224
225void helper_store_dbatu (uint32_t nr, target_ulong val)
226{
227 ppc_store_dbatu(env, nr, val);
228}
229
230void helper_store_dbatl (uint32_t nr, target_ulong val)
231{
232 ppc_store_dbatl(env, nr, val);
233}
234
235void helper_store_601_batl (uint32_t nr, target_ulong val)
236{
237 ppc_store_ibatl_601(env, nr, val);
238}
239
240void helper_store_601_batu (uint32_t nr, target_ulong val)
241{
242 ppc_store_ibatu_601(env, nr, val);
243}
244#endif
245
ff4a62cd
AJ
246/*****************************************************************************/
247/* Memory load and stores */
248
636aa200 249static inline target_ulong addr_add(target_ulong addr, target_long arg)
ff4a62cd
AJ
250{
251#if defined(TARGET_PPC64)
76db3ba4
AJ
252 if (!msr_sf)
253 return (uint32_t)(addr + arg);
ff4a62cd
AJ
254 else
255#endif
76db3ba4 256 return addr + arg;
ff4a62cd
AJ
257}
258
259void helper_lmw (target_ulong addr, uint32_t reg)
260{
76db3ba4 261 for (; reg < 32; reg++) {
ff4a62cd 262 if (msr_le)
76db3ba4 263 env->gpr[reg] = bswap32(ldl(addr));
ff4a62cd 264 else
76db3ba4
AJ
265 env->gpr[reg] = ldl(addr);
266 addr = addr_add(addr, 4);
ff4a62cd
AJ
267 }
268}
269
270void helper_stmw (target_ulong addr, uint32_t reg)
271{
76db3ba4 272 for (; reg < 32; reg++) {
ff4a62cd 273 if (msr_le)
76db3ba4 274 stl(addr, bswap32((uint32_t)env->gpr[reg]));
ff4a62cd 275 else
76db3ba4
AJ
276 stl(addr, (uint32_t)env->gpr[reg]);
277 addr = addr_add(addr, 4);
ff4a62cd
AJ
278 }
279}
280
dfbc799d
AJ
281void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg)
282{
283 int sh;
76db3ba4
AJ
284 for (; nb > 3; nb -= 4) {
285 env->gpr[reg] = ldl(addr);
dfbc799d 286 reg = (reg + 1) % 32;
76db3ba4 287 addr = addr_add(addr, 4);
dfbc799d
AJ
288 }
289 if (unlikely(nb > 0)) {
290 env->gpr[reg] = 0;
76db3ba4
AJ
291 for (sh = 24; nb > 0; nb--, sh -= 8) {
292 env->gpr[reg] |= ldub(addr) << sh;
293 addr = addr_add(addr, 1);
dfbc799d
AJ
294 }
295 }
296}
297/* PPC32 specification says we must generate an exception if
298 * rA is in the range of registers to be loaded.
299 * In an other hand, IBM says this is valid, but rA won't be loaded.
300 * For now, I'll follow the spec...
301 */
302void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
303{
304 if (likely(xer_bc != 0)) {
305 if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
306 (reg < rb && (reg + xer_bc) > rb))) {
e06fcd75
AJ
307 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
308 POWERPC_EXCP_INVAL |
309 POWERPC_EXCP_INVAL_LSWX);
dfbc799d
AJ
310 } else {
311 helper_lsw(addr, xer_bc, reg);
312 }
313 }
314}
315
316void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
317{
318 int sh;
76db3ba4
AJ
319 for (; nb > 3; nb -= 4) {
320 stl(addr, env->gpr[reg]);
dfbc799d 321 reg = (reg + 1) % 32;
76db3ba4 322 addr = addr_add(addr, 4);
dfbc799d
AJ
323 }
324 if (unlikely(nb > 0)) {
a16b45e7 325 for (sh = 24; nb > 0; nb--, sh -= 8) {
76db3ba4 326 stb(addr, (env->gpr[reg] >> sh) & 0xFF);
a16b45e7
AJ
327 addr = addr_add(addr, 1);
328 }
dfbc799d
AJ
329 }
330}
331
799a8c8d
AJ
332static void do_dcbz(target_ulong addr, int dcache_line_size)
333{
76db3ba4 334 addr &= ~(dcache_line_size - 1);
799a8c8d 335 int i;
799a8c8d 336 for (i = 0 ; i < dcache_line_size ; i += 4) {
dcc532c8 337 stl(addr + i , 0);
799a8c8d 338 }
18b21a2f
NF
339 if (env->reserve_addr == addr)
340 env->reserve_addr = (target_ulong)-1ULL;
799a8c8d
AJ
341}
342
343void helper_dcbz(target_ulong addr)
344{
345 do_dcbz(addr, env->dcache_line_size);
346}
347
348void helper_dcbz_970(target_ulong addr)
349{
350 if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1)
351 do_dcbz(addr, 32);
352 else
353 do_dcbz(addr, env->dcache_line_size);
354}
355
37d269df
AJ
356void helper_icbi(target_ulong addr)
357{
76db3ba4 358 addr &= ~(env->dcache_line_size - 1);
37d269df
AJ
359 /* Invalidate one cache line :
360 * PowerPC specification says this is to be treated like a load
361 * (not a fetch) by the MMU. To be sure it will be so,
362 * do the load "by hand".
363 */
577f25a5 364 ldl(addr);
37d269df
AJ
365 tb_invalidate_page_range(addr, addr + env->icache_line_size);
366}
367
bdb4b689
AJ
368// XXX: to be tested
369target_ulong helper_lscbx (target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
370{
371 int i, c, d;
bdb4b689
AJ
372 d = 24;
373 for (i = 0; i < xer_bc; i++) {
76db3ba4
AJ
374 c = ldub(addr);
375 addr = addr_add(addr, 1);
bdb4b689
AJ
376 /* ra (if not 0) and rb are never modified */
377 if (likely(reg != rb && (ra == 0 || reg != ra))) {
378 env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
379 }
380 if (unlikely(c == xer_cmp))
381 break;
382 if (likely(d != 0)) {
383 d -= 8;
384 } else {
385 d = 24;
386 reg++;
387 reg = reg & 0x1F;
388 }
389 }
390 return i;
391}
392
9a64fbe4 393/*****************************************************************************/
fdabc366 394/* Fixed point operations helpers */
d9bce9d9 395#if defined(TARGET_PPC64)
d9bce9d9 396
74637406
AJ
397/* multiply high word */
398uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2)
fdabc366 399{
74637406 400 uint64_t tl, th;
fdabc366 401
74637406
AJ
402 muls64(&tl, &th, arg1, arg2);
403 return th;
d9bce9d9 404}
d9bce9d9 405
74637406
AJ
406/* multiply high word unsigned */
407uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2)
fdabc366 408{
74637406 409 uint64_t tl, th;
fdabc366 410
74637406
AJ
411 mulu64(&tl, &th, arg1, arg2);
412 return th;
fdabc366
FB
413}
414
74637406 415uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
fdabc366 416{
d9bce9d9
JM
417 int64_t th;
418 uint64_t tl;
419
74637406 420 muls64(&tl, (uint64_t *)&th, arg1, arg2);
88ad920b 421 /* If th != 0 && th != -1, then we had an overflow */
6f2d8978 422 if (likely((uint64_t)(th + 1) <= 1)) {
3d7b417e 423 env->xer &= ~(1 << XER_OV);
fdabc366 424 } else {
3d7b417e 425 env->xer |= (1 << XER_OV) | (1 << XER_SO);
fdabc366 426 }
74637406 427 return (int64_t)tl;
d9bce9d9
JM
428}
429#endif
430
26d67362 431target_ulong helper_cntlzw (target_ulong t)
603fccce 432{
26d67362 433 return clz32(t);
603fccce
JM
434}
435
436#if defined(TARGET_PPC64)
26d67362 437target_ulong helper_cntlzd (target_ulong t)
603fccce 438{
26d67362 439 return clz64(t);
603fccce
JM
440}
441#endif
442
9a64fbe4 443/* shift right arithmetic helper */
26d67362 444target_ulong helper_sraw (target_ulong value, target_ulong shift)
9a64fbe4
FB
445{
446 int32_t ret;
447
26d67362
AJ
448 if (likely(!(shift & 0x20))) {
449 if (likely((uint32_t)shift != 0)) {
450 shift &= 0x1f;
451 ret = (int32_t)value >> shift;
452 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
3d7b417e 453 env->xer &= ~(1 << XER_CA);
fdabc366 454 } else {
3d7b417e 455 env->xer |= (1 << XER_CA);
fdabc366
FB
456 }
457 } else {
26d67362 458 ret = (int32_t)value;
3d7b417e 459 env->xer &= ~(1 << XER_CA);
fdabc366
FB
460 }
461 } else {
26d67362
AJ
462 ret = (int32_t)value >> 31;
463 if (ret) {
3d7b417e 464 env->xer |= (1 << XER_CA);
26d67362
AJ
465 } else {
466 env->xer &= ~(1 << XER_CA);
76a66253 467 }
fdabc366 468 }
26d67362 469 return (target_long)ret;
9a64fbe4
FB
470}
471
d9bce9d9 472#if defined(TARGET_PPC64)
26d67362 473target_ulong helper_srad (target_ulong value, target_ulong shift)
d9bce9d9
JM
474{
475 int64_t ret;
476
26d67362
AJ
477 if (likely(!(shift & 0x40))) {
478 if (likely((uint64_t)shift != 0)) {
479 shift &= 0x3f;
480 ret = (int64_t)value >> shift;
481 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
3d7b417e 482 env->xer &= ~(1 << XER_CA);
d9bce9d9 483 } else {
3d7b417e 484 env->xer |= (1 << XER_CA);
d9bce9d9
JM
485 }
486 } else {
26d67362 487 ret = (int64_t)value;
3d7b417e 488 env->xer &= ~(1 << XER_CA);
d9bce9d9
JM
489 }
490 } else {
26d67362
AJ
491 ret = (int64_t)value >> 63;
492 if (ret) {
3d7b417e 493 env->xer |= (1 << XER_CA);
26d67362
AJ
494 } else {
495 env->xer &= ~(1 << XER_CA);
d9bce9d9
JM
496 }
497 }
26d67362 498 return ret;
d9bce9d9
JM
499}
500#endif
501
eaabeef2
DG
502#if defined(TARGET_PPC64)
503target_ulong helper_popcntb (target_ulong val)
504{
505 val = (val & 0x5555555555555555ULL) + ((val >> 1) &
506 0x5555555555555555ULL);
507 val = (val & 0x3333333333333333ULL) + ((val >> 2) &
508 0x3333333333333333ULL);
509 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
510 0x0f0f0f0f0f0f0f0fULL);
511 return val;
512}
513
514target_ulong helper_popcntw (target_ulong val)
515{
516 val = (val & 0x5555555555555555ULL) + ((val >> 1) &
517 0x5555555555555555ULL);
518 val = (val & 0x3333333333333333ULL) + ((val >> 2) &
519 0x3333333333333333ULL);
520 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) &
521 0x0f0f0f0f0f0f0f0fULL);
522 val = (val & 0x00ff00ff00ff00ffULL) + ((val >> 8) &
523 0x00ff00ff00ff00ffULL);
524 val = (val & 0x0000ffff0000ffffULL) + ((val >> 16) &
525 0x0000ffff0000ffffULL);
526 return val;
527}
528
529target_ulong helper_popcntd (target_ulong val)
530{
3601ff11 531 return ctpop64(val);
eaabeef2
DG
532}
533#else
26d67362 534target_ulong helper_popcntb (target_ulong val)
d9bce9d9 535{
6176a26d
AJ
536 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
537 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
538 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
539 return val;
d9bce9d9
JM
540}
541
eaabeef2 542target_ulong helper_popcntw (target_ulong val)
d9bce9d9 543{
eaabeef2
DG
544 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
545 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
546 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
547 val = (val & 0x00ff00ff) + ((val >> 8) & 0x00ff00ff);
548 val = (val & 0x0000ffff) + ((val >> 16) & 0x0000ffff);
6176a26d 549 return val;
d9bce9d9
JM
550}
551#endif
552
fdabc366 553/*****************************************************************************/
9a64fbe4 554/* Floating point operations helpers */
a0d7d5a7
AJ
555uint64_t helper_float32_to_float64(uint32_t arg)
556{
557 CPU_FloatU f;
558 CPU_DoubleU d;
559 f.l = arg;
560 d.d = float32_to_float64(f.f, &env->fp_status);
561 return d.ll;
562}
563
564uint32_t helper_float64_to_float32(uint64_t arg)
565{
566 CPU_FloatU f;
567 CPU_DoubleU d;
568 d.ll = arg;
569 f.f = float64_to_float32(d.d, &env->fp_status);
570 return f.l;
571}
572
636aa200 573static inline int isden(float64 d)
7c58044c 574{
0ca9d380 575 CPU_DoubleU u;
7c58044c 576
0ca9d380 577 u.d = d;
7c58044c 578
0ca9d380 579 return ((u.ll >> 52) & 0x7FF) == 0;
7c58044c
JM
580}
581
af12906f 582uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
7c58044c 583{
af12906f 584 CPU_DoubleU farg;
7c58044c 585 int isneg;
af12906f
AJ
586 int ret;
587 farg.ll = arg;
f23c346e 588 isneg = float64_is_neg(farg.d);
d788b570 589 if (unlikely(float64_is_any_nan(farg.d))) {
af12906f 590 if (float64_is_signaling_nan(farg.d)) {
7c58044c 591 /* Signaling NaN: flags are undefined */
af12906f 592 ret = 0x00;
7c58044c
JM
593 } else {
594 /* Quiet NaN */
af12906f 595 ret = 0x11;
7c58044c 596 }
f23c346e 597 } else if (unlikely(float64_is_infinity(farg.d))) {
7c58044c
JM
598 /* +/- infinity */
599 if (isneg)
af12906f 600 ret = 0x09;
7c58044c 601 else
af12906f 602 ret = 0x05;
7c58044c 603 } else {
f23c346e 604 if (float64_is_zero(farg.d)) {
7c58044c
JM
605 /* +/- zero */
606 if (isneg)
af12906f 607 ret = 0x12;
7c58044c 608 else
af12906f 609 ret = 0x02;
7c58044c 610 } else {
af12906f 611 if (isden(farg.d)) {
7c58044c 612 /* Denormalized numbers */
af12906f 613 ret = 0x10;
7c58044c
JM
614 } else {
615 /* Normalized numbers */
af12906f 616 ret = 0x00;
7c58044c
JM
617 }
618 if (isneg) {
af12906f 619 ret |= 0x08;
7c58044c 620 } else {
af12906f 621 ret |= 0x04;
7c58044c
JM
622 }
623 }
624 }
625 if (set_fprf) {
626 /* We update FPSCR_FPRF */
627 env->fpscr &= ~(0x1F << FPSCR_FPRF);
af12906f 628 env->fpscr |= ret << FPSCR_FPRF;
7c58044c
JM
629 }
630 /* We just need fpcc to update Rc1 */
af12906f 631 return ret & 0xF;
7c58044c
JM
632}
633
634/* Floating-point invalid operations exception */
636aa200 635static inline uint64_t fload_invalid_op_excp(int op)
7c58044c 636{
af12906f 637 uint64_t ret = 0;
7c58044c
JM
638 int ve;
639
640 ve = fpscr_ve;
e0147e41
AJ
641 switch (op) {
642 case POWERPC_EXCP_FP_VXSNAN:
7c58044c 643 env->fpscr |= 1 << FPSCR_VXSNAN;
e0147e41
AJ
644 break;
645 case POWERPC_EXCP_FP_VXSOFT:
7c58044c 646 env->fpscr |= 1 << FPSCR_VXSOFT;
e0147e41 647 break;
7c58044c
JM
648 case POWERPC_EXCP_FP_VXISI:
649 /* Magnitude subtraction of infinities */
650 env->fpscr |= 1 << FPSCR_VXISI;
651 goto update_arith;
652 case POWERPC_EXCP_FP_VXIDI:
653 /* Division of infinity by infinity */
654 env->fpscr |= 1 << FPSCR_VXIDI;
655 goto update_arith;
656 case POWERPC_EXCP_FP_VXZDZ:
657 /* Division of zero by zero */
658 env->fpscr |= 1 << FPSCR_VXZDZ;
659 goto update_arith;
660 case POWERPC_EXCP_FP_VXIMZ:
661 /* Multiplication of zero by infinity */
662 env->fpscr |= 1 << FPSCR_VXIMZ;
663 goto update_arith;
664 case POWERPC_EXCP_FP_VXVC:
665 /* Ordered comparison of NaN */
666 env->fpscr |= 1 << FPSCR_VXVC;
667 env->fpscr &= ~(0xF << FPSCR_FPCC);
668 env->fpscr |= 0x11 << FPSCR_FPCC;
669 /* We must update the target FPR before raising the exception */
670 if (ve != 0) {
671 env->exception_index = POWERPC_EXCP_PROGRAM;
672 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
673 /* Update the floating-point enabled exception summary */
674 env->fpscr |= 1 << FPSCR_FEX;
675 /* Exception is differed */
676 ve = 0;
677 }
678 break;
679 case POWERPC_EXCP_FP_VXSQRT:
680 /* Square root of a negative number */
681 env->fpscr |= 1 << FPSCR_VXSQRT;
682 update_arith:
683 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
684 if (ve == 0) {
685 /* Set the result to quiet NaN */
3eb28bbd 686 ret = 0x7FF8000000000000ULL;
7c58044c
JM
687 env->fpscr &= ~(0xF << FPSCR_FPCC);
688 env->fpscr |= 0x11 << FPSCR_FPCC;
689 }
690 break;
691 case POWERPC_EXCP_FP_VXCVI:
692 /* Invalid conversion */
693 env->fpscr |= 1 << FPSCR_VXCVI;
694 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
695 if (ve == 0) {
696 /* Set the result to quiet NaN */
3eb28bbd 697 ret = 0x7FF8000000000000ULL;
7c58044c
JM
698 env->fpscr &= ~(0xF << FPSCR_FPCC);
699 env->fpscr |= 0x11 << FPSCR_FPCC;
700 }
701 break;
702 }
703 /* Update the floating-point invalid operation summary */
704 env->fpscr |= 1 << FPSCR_VX;
705 /* Update the floating-point exception summary */
706 env->fpscr |= 1 << FPSCR_FX;
707 if (ve != 0) {
708 /* Update the floating-point enabled exception summary */
709 env->fpscr |= 1 << FPSCR_FEX;
710 if (msr_fe0 != 0 || msr_fe1 != 0)
e06fcd75 711 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
7c58044c 712 }
af12906f 713 return ret;
7c58044c
JM
714}
715
636aa200 716static inline void float_zero_divide_excp(void)
7c58044c 717{
7c58044c
JM
718 env->fpscr |= 1 << FPSCR_ZX;
719 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
720 /* Update the floating-point exception summary */
721 env->fpscr |= 1 << FPSCR_FX;
722 if (fpscr_ze != 0) {
723 /* Update the floating-point enabled exception summary */
724 env->fpscr |= 1 << FPSCR_FEX;
725 if (msr_fe0 != 0 || msr_fe1 != 0) {
e06fcd75
AJ
726 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
727 POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
7c58044c 728 }
7c58044c
JM
729 }
730}
731
636aa200 732static inline void float_overflow_excp(void)
7c58044c
JM
733{
734 env->fpscr |= 1 << FPSCR_OX;
735 /* Update the floating-point exception summary */
736 env->fpscr |= 1 << FPSCR_FX;
737 if (fpscr_oe != 0) {
738 /* XXX: should adjust the result */
739 /* Update the floating-point enabled exception summary */
740 env->fpscr |= 1 << FPSCR_FEX;
741 /* We must update the target FPR before raising the exception */
742 env->exception_index = POWERPC_EXCP_PROGRAM;
743 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
744 } else {
745 env->fpscr |= 1 << FPSCR_XX;
746 env->fpscr |= 1 << FPSCR_FI;
747 }
748}
749
636aa200 750static inline void float_underflow_excp(void)
7c58044c
JM
751{
752 env->fpscr |= 1 << FPSCR_UX;
753 /* Update the floating-point exception summary */
754 env->fpscr |= 1 << FPSCR_FX;
755 if (fpscr_ue != 0) {
756 /* XXX: should adjust the result */
757 /* Update the floating-point enabled exception summary */
758 env->fpscr |= 1 << FPSCR_FEX;
759 /* We must update the target FPR before raising the exception */
760 env->exception_index = POWERPC_EXCP_PROGRAM;
761 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
762 }
763}
764
636aa200 765static inline void float_inexact_excp(void)
7c58044c
JM
766{
767 env->fpscr |= 1 << FPSCR_XX;
768 /* Update the floating-point exception summary */
769 env->fpscr |= 1 << FPSCR_FX;
770 if (fpscr_xe != 0) {
771 /* Update the floating-point enabled exception summary */
772 env->fpscr |= 1 << FPSCR_FEX;
773 /* We must update the target FPR before raising the exception */
774 env->exception_index = POWERPC_EXCP_PROGRAM;
775 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
776 }
777}
778
636aa200 779static inline void fpscr_set_rounding_mode(void)
7c58044c
JM
780{
781 int rnd_type;
782
783 /* Set rounding mode */
784 switch (fpscr_rn) {
785 case 0:
786 /* Best approximation (round to nearest) */
787 rnd_type = float_round_nearest_even;
788 break;
789 case 1:
790 /* Smaller magnitude (round toward zero) */
791 rnd_type = float_round_to_zero;
792 break;
793 case 2:
794 /* Round toward +infinite */
795 rnd_type = float_round_up;
796 break;
797 default:
798 case 3:
799 /* Round toward -infinite */
800 rnd_type = float_round_down;
801 break;
802 }
803 set_float_rounding_mode(rnd_type, &env->fp_status);
804}
805
6e35d524
AJ
806void helper_fpscr_clrbit (uint32_t bit)
807{
808 int prev;
809
810 prev = (env->fpscr >> bit) & 1;
811 env->fpscr &= ~(1 << bit);
812 if (prev == 1) {
813 switch (bit) {
814 case FPSCR_RN1:
815 case FPSCR_RN:
816 fpscr_set_rounding_mode();
817 break;
818 default:
819 break;
820 }
821 }
822}
823
af12906f 824void helper_fpscr_setbit (uint32_t bit)
7c58044c
JM
825{
826 int prev;
827
828 prev = (env->fpscr >> bit) & 1;
829 env->fpscr |= 1 << bit;
830 if (prev == 0) {
831 switch (bit) {
832 case FPSCR_VX:
833 env->fpscr |= 1 << FPSCR_FX;
834 if (fpscr_ve)
835 goto raise_ve;
836 case FPSCR_OX:
837 env->fpscr |= 1 << FPSCR_FX;
838 if (fpscr_oe)
839 goto raise_oe;
840 break;
841 case FPSCR_UX:
842 env->fpscr |= 1 << FPSCR_FX;
843 if (fpscr_ue)
844 goto raise_ue;
845 break;
846 case FPSCR_ZX:
847 env->fpscr |= 1 << FPSCR_FX;
848 if (fpscr_ze)
849 goto raise_ze;
850 break;
851 case FPSCR_XX:
852 env->fpscr |= 1 << FPSCR_FX;
853 if (fpscr_xe)
854 goto raise_xe;
855 break;
856 case FPSCR_VXSNAN:
857 case FPSCR_VXISI:
858 case FPSCR_VXIDI:
859 case FPSCR_VXZDZ:
860 case FPSCR_VXIMZ:
861 case FPSCR_VXVC:
862 case FPSCR_VXSOFT:
863 case FPSCR_VXSQRT:
864 case FPSCR_VXCVI:
865 env->fpscr |= 1 << FPSCR_VX;
866 env->fpscr |= 1 << FPSCR_FX;
867 if (fpscr_ve != 0)
868 goto raise_ve;
869 break;
870 case FPSCR_VE:
871 if (fpscr_vx != 0) {
872 raise_ve:
873 env->error_code = POWERPC_EXCP_FP;
874 if (fpscr_vxsnan)
875 env->error_code |= POWERPC_EXCP_FP_VXSNAN;
876 if (fpscr_vxisi)
877 env->error_code |= POWERPC_EXCP_FP_VXISI;
878 if (fpscr_vxidi)
879 env->error_code |= POWERPC_EXCP_FP_VXIDI;
880 if (fpscr_vxzdz)
881 env->error_code |= POWERPC_EXCP_FP_VXZDZ;
882 if (fpscr_vximz)
883 env->error_code |= POWERPC_EXCP_FP_VXIMZ;
884 if (fpscr_vxvc)
885 env->error_code |= POWERPC_EXCP_FP_VXVC;
886 if (fpscr_vxsoft)
887 env->error_code |= POWERPC_EXCP_FP_VXSOFT;
888 if (fpscr_vxsqrt)
889 env->error_code |= POWERPC_EXCP_FP_VXSQRT;
890 if (fpscr_vxcvi)
891 env->error_code |= POWERPC_EXCP_FP_VXCVI;
892 goto raise_excp;
893 }
894 break;
895 case FPSCR_OE:
896 if (fpscr_ox != 0) {
897 raise_oe:
898 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
899 goto raise_excp;
900 }
901 break;
902 case FPSCR_UE:
903 if (fpscr_ux != 0) {
904 raise_ue:
905 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
906 goto raise_excp;
907 }
908 break;
909 case FPSCR_ZE:
910 if (fpscr_zx != 0) {
911 raise_ze:
912 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
913 goto raise_excp;
914 }
915 break;
916 case FPSCR_XE:
917 if (fpscr_xx != 0) {
918 raise_xe:
919 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
920 goto raise_excp;
921 }
922 break;
923 case FPSCR_RN1:
924 case FPSCR_RN:
925 fpscr_set_rounding_mode();
926 break;
927 default:
928 break;
929 raise_excp:
930 /* Update the floating-point enabled exception summary */
931 env->fpscr |= 1 << FPSCR_FEX;
932 /* We have to update Rc1 before raising the exception */
933 env->exception_index = POWERPC_EXCP_PROGRAM;
934 break;
935 }
936 }
937}
938
af12906f 939void helper_store_fpscr (uint64_t arg, uint32_t mask)
7c58044c
JM
940{
941 /*
942 * We use only the 32 LSB of the incoming fpr
943 */
7c58044c
JM
944 uint32_t prev, new;
945 int i;
946
7c58044c 947 prev = env->fpscr;
af12906f 948 new = (uint32_t)arg;
27ee5df0
AJ
949 new &= ~0x60000000;
950 new |= prev & 0x60000000;
951 for (i = 0; i < 8; i++) {
7c58044c
JM
952 if (mask & (1 << i)) {
953 env->fpscr &= ~(0xF << (4 * i));
954 env->fpscr |= new & (0xF << (4 * i));
955 }
956 }
957 /* Update VX and FEX */
958 if (fpscr_ix != 0)
959 env->fpscr |= 1 << FPSCR_VX;
5567025f
AJ
960 else
961 env->fpscr &= ~(1 << FPSCR_VX);
7c58044c
JM
962 if ((fpscr_ex & fpscr_eex) != 0) {
963 env->fpscr |= 1 << FPSCR_FEX;
964 env->exception_index = POWERPC_EXCP_PROGRAM;
965 /* XXX: we should compute it properly */
966 env->error_code = POWERPC_EXCP_FP;
967 }
5567025f
AJ
968 else
969 env->fpscr &= ~(1 << FPSCR_FEX);
7c58044c
JM
970 fpscr_set_rounding_mode();
971}
7c58044c 972
af12906f 973void helper_float_check_status (void)
7c58044c 974{
af12906f 975#ifdef CONFIG_SOFTFLOAT
7c58044c
JM
976 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
977 (env->error_code & POWERPC_EXCP_FP)) {
978 /* Differred floating-point exception after target FPR update */
979 if (msr_fe0 != 0 || msr_fe1 != 0)
e06fcd75 980 helper_raise_exception_err(env->exception_index, env->error_code);
be94c952
AJ
981 } else {
982 int status = get_float_exception_flags(&env->fp_status);
e33e94f9
AJ
983 if (status & float_flag_divbyzero) {
984 float_zero_divide_excp();
985 } else if (status & float_flag_overflow) {
be94c952
AJ
986 float_overflow_excp();
987 } else if (status & float_flag_underflow) {
988 float_underflow_excp();
989 } else if (status & float_flag_inexact) {
990 float_inexact_excp();
991 }
7c58044c 992 }
af12906f
AJ
993#else
994 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
995 (env->error_code & POWERPC_EXCP_FP)) {
996 /* Differred floating-point exception after target FPR update */
997 if (msr_fe0 != 0 || msr_fe1 != 0)
e06fcd75 998 helper_raise_exception_err(env->exception_index, env->error_code);
af12906f 999 }
af12906f
AJ
1000#endif
1001}
1002
1003#ifdef CONFIG_SOFTFLOAT
1004void helper_reset_fpstatus (void)
1005{
be94c952 1006 set_float_exception_flags(0, &env->fp_status);
7c58044c
JM
1007}
1008#endif
1009
af12906f
AJ
1010/* fadd - fadd. */
1011uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
7c58044c 1012{
af12906f
AJ
1013 CPU_DoubleU farg1, farg2;
1014
1015 farg1.ll = arg1;
1016 farg2.ll = arg2;
dd94ad96 1017
96912e39
AJ
1018 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1019 float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
7c58044c 1020 /* Magnitude subtraction of infinities */
cf1cf21e 1021 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
17218d1f 1022 } else {
96912e39
AJ
1023 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1024 float64_is_signaling_nan(farg2.d))) {
1025 /* sNaN addition */
1026 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1027 }
17218d1f 1028 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
7c58044c 1029 }
dd94ad96 1030
af12906f 1031 return farg1.ll;
7c58044c
JM
1032}
1033
af12906f
AJ
1034/* fsub - fsub. */
1035uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
1036{
1037 CPU_DoubleU farg1, farg2;
1038
1039 farg1.ll = arg1;
1040 farg2.ll = arg2;
dd94ad96 1041
96912e39
AJ
1042 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1043 float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
7c58044c 1044 /* Magnitude subtraction of infinities */
af12906f 1045 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
17218d1f 1046 } else {
96912e39
AJ
1047 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1048 float64_is_signaling_nan(farg2.d))) {
1049 /* sNaN subtraction */
1050 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1051 }
17218d1f 1052 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
7c58044c 1053 }
dd94ad96 1054
af12906f
AJ
1055 return farg1.ll;
1056}
7c58044c 1057
af12906f
AJ
1058/* fmul - fmul. */
1059uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
7c58044c 1060{
af12906f
AJ
1061 CPU_DoubleU farg1, farg2;
1062
1063 farg1.ll = arg1;
1064 farg2.ll = arg2;
dd94ad96 1065
96912e39
AJ
1066 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1067 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
7c58044c 1068 /* Multiplication of zero by infinity */
af12906f 1069 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
7c58044c 1070 } else {
96912e39
AJ
1071 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1072 float64_is_signaling_nan(farg2.d))) {
1073 /* sNaN multiplication */
1074 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1075 }
af12906f 1076 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
7c58044c 1077 }
dd94ad96 1078
af12906f
AJ
1079 return farg1.ll;
1080}
7c58044c 1081
af12906f
AJ
1082/* fdiv - fdiv. */
1083uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
7c58044c 1084{
af12906f
AJ
1085 CPU_DoubleU farg1, farg2;
1086
1087 farg1.ll = arg1;
1088 farg2.ll = arg2;
dd94ad96 1089
96912e39 1090 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) {
7c58044c 1091 /* Division of infinity by infinity */
af12906f 1092 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
e33e94f9
AJ
1093 } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
1094 /* Division of zero by zero */
1095 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
7c58044c 1096 } else {
96912e39
AJ
1097 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1098 float64_is_signaling_nan(farg2.d))) {
1099 /* sNaN division */
1100 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1101 }
af12906f 1102 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
7c58044c 1103 }
dd94ad96 1104
af12906f 1105 return farg1.ll;
7c58044c 1106}
7c58044c 1107
af12906f
AJ
1108/* fabs */
1109uint64_t helper_fabs (uint64_t arg)
9a64fbe4 1110{
af12906f 1111 CPU_DoubleU farg;
9a64fbe4 1112
af12906f
AJ
1113 farg.ll = arg;
1114 farg.d = float64_abs(farg.d);
1115 return farg.ll;
1116}
1117
1118/* fnabs */
1119uint64_t helper_fnabs (uint64_t arg)
1120{
1121 CPU_DoubleU farg;
1122
1123 farg.ll = arg;
1124 farg.d = float64_abs(farg.d);
1125 farg.d = float64_chs(farg.d);
1126 return farg.ll;
1127}
1128
1129/* fneg */
1130uint64_t helper_fneg (uint64_t arg)
1131{
1132 CPU_DoubleU farg;
1133
1134 farg.ll = arg;
1135 farg.d = float64_chs(farg.d);
1136 return farg.ll;
1137}
1138
1139/* fctiw - fctiw. */
1140uint64_t helper_fctiw (uint64_t arg)
1141{
1142 CPU_DoubleU farg;
1143 farg.ll = arg;
1144
1145 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1146 /* sNaN conversion */
af12906f 1147 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
18569871 1148 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
7c58044c 1149 /* qNan / infinity conversion */
af12906f 1150 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
7c58044c 1151 } else {
af12906f 1152 farg.ll = float64_to_int32(farg.d, &env->fp_status);
7c58044c
JM
1153 /* XXX: higher bits are not supposed to be significant.
1154 * to make tests easier, return the same as a real PowerPC 750
1155 */
af12906f 1156 farg.ll |= 0xFFF80000ULL << 32;
7c58044c 1157 }
af12906f 1158 return farg.ll;
9a64fbe4
FB
1159}
1160
af12906f
AJ
1161/* fctiwz - fctiwz. */
1162uint64_t helper_fctiwz (uint64_t arg)
9a64fbe4 1163{
af12906f
AJ
1164 CPU_DoubleU farg;
1165 farg.ll = arg;
4ecc3190 1166
af12906f 1167 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1168 /* sNaN conversion */
af12906f 1169 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
18569871 1170 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
7c58044c 1171 /* qNan / infinity conversion */
af12906f 1172 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
7c58044c 1173 } else {
af12906f 1174 farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
7c58044c
JM
1175 /* XXX: higher bits are not supposed to be significant.
1176 * to make tests easier, return the same as a real PowerPC 750
1177 */
af12906f 1178 farg.ll |= 0xFFF80000ULL << 32;
7c58044c 1179 }
af12906f 1180 return farg.ll;
9a64fbe4
FB
1181}
1182
426613db 1183#if defined(TARGET_PPC64)
af12906f
AJ
1184/* fcfid - fcfid. */
1185uint64_t helper_fcfid (uint64_t arg)
426613db 1186{
af12906f
AJ
1187 CPU_DoubleU farg;
1188 farg.d = int64_to_float64(arg, &env->fp_status);
1189 return farg.ll;
426613db
JM
1190}
1191
af12906f
AJ
1192/* fctid - fctid. */
1193uint64_t helper_fctid (uint64_t arg)
426613db 1194{
af12906f
AJ
1195 CPU_DoubleU farg;
1196 farg.ll = arg;
426613db 1197
af12906f 1198 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1199 /* sNaN conversion */
af12906f 1200 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
18569871 1201 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
7c58044c 1202 /* qNan / infinity conversion */
af12906f 1203 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
7c58044c 1204 } else {
af12906f 1205 farg.ll = float64_to_int64(farg.d, &env->fp_status);
7c58044c 1206 }
af12906f 1207 return farg.ll;
426613db
JM
1208}
1209
af12906f
AJ
1210/* fctidz - fctidz. */
1211uint64_t helper_fctidz (uint64_t arg)
426613db 1212{
af12906f
AJ
1213 CPU_DoubleU farg;
1214 farg.ll = arg;
426613db 1215
af12906f 1216 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1217 /* sNaN conversion */
af12906f 1218 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
18569871 1219 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
7c58044c 1220 /* qNan / infinity conversion */
af12906f 1221 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
7c58044c 1222 } else {
af12906f 1223 farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
7c58044c 1224 }
af12906f 1225 return farg.ll;
426613db
JM
1226}
1227
1228#endif
1229
636aa200 1230static inline uint64_t do_fri(uint64_t arg, int rounding_mode)
d7e4b87e 1231{
af12906f
AJ
1232 CPU_DoubleU farg;
1233 farg.ll = arg;
1234
1235 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1236 /* sNaN round */
af12906f 1237 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
18569871 1238 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
7c58044c 1239 /* qNan / infinity round */
af12906f 1240 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
7c58044c
JM
1241 } else {
1242 set_float_rounding_mode(rounding_mode, &env->fp_status);
af12906f 1243 farg.ll = float64_round_to_int(farg.d, &env->fp_status);
7c58044c
JM
1244 /* Restore rounding mode from FPSCR */
1245 fpscr_set_rounding_mode();
1246 }
af12906f 1247 return farg.ll;
d7e4b87e
JM
1248}
1249
af12906f 1250uint64_t helper_frin (uint64_t arg)
d7e4b87e 1251{
af12906f 1252 return do_fri(arg, float_round_nearest_even);
d7e4b87e
JM
1253}
1254
af12906f 1255uint64_t helper_friz (uint64_t arg)
d7e4b87e 1256{
af12906f 1257 return do_fri(arg, float_round_to_zero);
d7e4b87e
JM
1258}
1259
af12906f 1260uint64_t helper_frip (uint64_t arg)
d7e4b87e 1261{
af12906f 1262 return do_fri(arg, float_round_up);
d7e4b87e
JM
1263}
1264
af12906f 1265uint64_t helper_frim (uint64_t arg)
d7e4b87e 1266{
af12906f 1267 return do_fri(arg, float_round_down);
d7e4b87e
JM
1268}
1269
af12906f
AJ
1270/* fmadd - fmadd. */
1271uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
e864cabd 1272{
af12906f
AJ
1273 CPU_DoubleU farg1, farg2, farg3;
1274
1275 farg1.ll = arg1;
1276 farg2.ll = arg2;
1277 farg3.ll = arg3;
dd94ad96 1278
96912e39
AJ
1279 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1280 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
da1e7ac9
AJ
1281 /* Multiplication of zero by infinity */
1282 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
7c58044c 1283 } else {
96912e39
AJ
1284 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1285 float64_is_signaling_nan(farg2.d) ||
1286 float64_is_signaling_nan(farg3.d))) {
1287 /* sNaN operation */
1288 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1289 }
7c58044c
JM
1290 /* This is the way the PowerPC specification defines it */
1291 float128 ft0_128, ft1_128;
1292
af12906f
AJ
1293 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1294 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
7c58044c 1295 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
da1e7ac9
AJ
1296 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1297 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1298 /* Magnitude subtraction of infinities */
1299 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1300 } else {
1301 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1302 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1303 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1304 }
7c58044c 1305 }
dd94ad96 1306
af12906f 1307 return farg1.ll;
e864cabd
JM
1308}
1309
af12906f
AJ
1310/* fmsub - fmsub. */
1311uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
e864cabd 1312{
af12906f
AJ
1313 CPU_DoubleU farg1, farg2, farg3;
1314
1315 farg1.ll = arg1;
1316 farg2.ll = arg2;
1317 farg3.ll = arg3;
dd94ad96 1318
96912e39 1319 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
da1e7ac9
AJ
1320 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1321 /* Multiplication of zero by infinity */
1322 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
7c58044c 1323 } else {
96912e39
AJ
1324 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1325 float64_is_signaling_nan(farg2.d) ||
1326 float64_is_signaling_nan(farg3.d))) {
1327 /* sNaN operation */
1328 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1329 }
7c58044c
JM
1330 /* This is the way the PowerPC specification defines it */
1331 float128 ft0_128, ft1_128;
1332
af12906f
AJ
1333 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1334 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
7c58044c 1335 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
da1e7ac9
AJ
1336 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1337 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1338 /* Magnitude subtraction of infinities */
1339 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1340 } else {
1341 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1342 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1343 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1344 }
7c58044c 1345 }
af12906f 1346 return farg1.ll;
e864cabd 1347}
e864cabd 1348
af12906f
AJ
1349/* fnmadd - fnmadd. */
1350uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
4b3686fa 1351{
af12906f
AJ
1352 CPU_DoubleU farg1, farg2, farg3;
1353
1354 farg1.ll = arg1;
1355 farg2.ll = arg2;
1356 farg3.ll = arg3;
1357
96912e39
AJ
1358 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1359 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
da1e7ac9
AJ
1360 /* Multiplication of zero by infinity */
1361 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
7c58044c 1362 } else {
96912e39
AJ
1363 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1364 float64_is_signaling_nan(farg2.d) ||
1365 float64_is_signaling_nan(farg3.d))) {
1366 /* sNaN operation */
1367 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1368 }
7c58044c
JM
1369 /* This is the way the PowerPC specification defines it */
1370 float128 ft0_128, ft1_128;
1371
af12906f
AJ
1372 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1373 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
7c58044c 1374 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
da1e7ac9
AJ
1375 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1376 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1377 /* Magnitude subtraction of infinities */
1378 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1379 } else {
1380 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1381 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1382 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1383 }
d788b570 1384 if (likely(!float64_is_any_nan(farg1.d))) {
af12906f 1385 farg1.d = float64_chs(farg1.d);
d788b570 1386 }
7c58044c 1387 }
af12906f 1388 return farg1.ll;
4b3686fa
FB
1389}
1390
af12906f
AJ
1391/* fnmsub - fnmsub. */
1392uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
4b3686fa 1393{
af12906f
AJ
1394 CPU_DoubleU farg1, farg2, farg3;
1395
1396 farg1.ll = arg1;
1397 farg2.ll = arg2;
1398 farg3.ll = arg3;
1399
96912e39 1400 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
da1e7ac9
AJ
1401 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1402 /* Multiplication of zero by infinity */
1403 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
7c58044c 1404 } else {
96912e39
AJ
1405 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1406 float64_is_signaling_nan(farg2.d) ||
1407 float64_is_signaling_nan(farg3.d))) {
1408 /* sNaN operation */
1409 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1410 }
7c58044c
JM
1411 /* This is the way the PowerPC specification defines it */
1412 float128 ft0_128, ft1_128;
1413
af12906f
AJ
1414 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1415 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
7c58044c 1416 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
da1e7ac9
AJ
1417 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1418 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1419 /* Magnitude subtraction of infinities */
1420 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1421 } else {
1422 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1423 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1424 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1425 }
d788b570 1426 if (likely(!float64_is_any_nan(farg1.d))) {
af12906f 1427 farg1.d = float64_chs(farg1.d);
d788b570 1428 }
7c58044c 1429 }
af12906f 1430 return farg1.ll;
1ef59d0a
FB
1431}
1432
af12906f
AJ
1433/* frsp - frsp. */
1434uint64_t helper_frsp (uint64_t arg)
7c58044c 1435{
af12906f 1436 CPU_DoubleU farg;
6ad193ed 1437 float32 f32;
af12906f
AJ
1438 farg.ll = arg;
1439
af12906f 1440 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1441 /* sNaN square root */
96912e39 1442 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
7c58044c 1443 }
96912e39
AJ
1444 f32 = float64_to_float32(farg.d, &env->fp_status);
1445 farg.d = float32_to_float64(f32, &env->fp_status);
1446
af12906f 1447 return farg.ll;
7c58044c 1448}
7c58044c 1449
af12906f
AJ
1450/* fsqrt - fsqrt. */
1451uint64_t helper_fsqrt (uint64_t arg)
9a64fbe4 1452{
af12906f
AJ
1453 CPU_DoubleU farg;
1454 farg.ll = arg;
1455
96912e39 1456 if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
7c58044c 1457 /* Square root of a negative nonzero number */
af12906f 1458 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
7c58044c 1459 } else {
96912e39
AJ
1460 if (unlikely(float64_is_signaling_nan(farg.d))) {
1461 /* sNaN square root */
1462 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1463 }
af12906f 1464 farg.d = float64_sqrt(farg.d, &env->fp_status);
7c58044c 1465 }
af12906f 1466 return farg.ll;
9a64fbe4
FB
1467}
1468
af12906f
AJ
1469/* fre - fre. */
1470uint64_t helper_fre (uint64_t arg)
d7e4b87e 1471{
c609b12e 1472 CPU_DoubleU farg;
06f7332a 1473 farg.ll = arg;
d7e4b87e 1474
af12906f 1475 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1476 /* sNaN reciprocal */
96912e39 1477 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
d7e4b87e 1478 }
96912e39 1479 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
af12906f 1480 return farg.d;
d7e4b87e
JM
1481}
1482
af12906f
AJ
1483/* fres - fres. */
1484uint64_t helper_fres (uint64_t arg)
9a64fbe4 1485{
06f7332a 1486 CPU_DoubleU farg;
6c01bf6c 1487 float32 f32;
06f7332a 1488 farg.ll = arg;
4ecc3190 1489
af12906f 1490 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1491 /* sNaN reciprocal */
96912e39 1492 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
4ecc3190 1493 }
96912e39
AJ
1494 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1495 f32 = float64_to_float32(farg.d, &env->fp_status);
1496 farg.d = float32_to_float64(f32, &env->fp_status);
1497
af12906f 1498 return farg.ll;
9a64fbe4
FB
1499}
1500
af12906f
AJ
1501/* frsqrte - frsqrte. */
1502uint64_t helper_frsqrte (uint64_t arg)
9a64fbe4 1503{
c609b12e 1504 CPU_DoubleU farg;
6c01bf6c 1505 float32 f32;
06f7332a 1506 farg.ll = arg;
4ecc3190 1507
96912e39 1508 if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
7c58044c 1509 /* Reciprocal square root of a negative nonzero number */
af12906f 1510 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
4ecc3190 1511 } else {
96912e39
AJ
1512 if (unlikely(float64_is_signaling_nan(farg.d))) {
1513 /* sNaN reciprocal square root */
1514 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1515 }
6c01bf6c 1516 farg.d = float64_sqrt(farg.d, &env->fp_status);
c609b12e 1517 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
6c01bf6c
AJ
1518 f32 = float64_to_float32(farg.d, &env->fp_status);
1519 farg.d = float32_to_float64(f32, &env->fp_status);
4ecc3190 1520 }
af12906f 1521 return farg.ll;
9a64fbe4
FB
1522}
1523
af12906f
AJ
1524/* fsel - fsel. */
1525uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
9a64fbe4 1526{
6ad7365a 1527 CPU_DoubleU farg1;
af12906f
AJ
1528
1529 farg1.ll = arg1;
af12906f 1530
d788b570 1531 if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_any_nan(farg1.d)) {
6ad7365a 1532 return arg2;
d788b570 1533 } else {
6ad7365a 1534 return arg3;
d788b570 1535 }
9a64fbe4
FB
1536}
1537
9a819377 1538void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
9a64fbe4 1539{
af12906f 1540 CPU_DoubleU farg1, farg2;
e1571908 1541 uint32_t ret = 0;
af12906f
AJ
1542 farg1.ll = arg1;
1543 farg2.ll = arg2;
e1571908 1544
d788b570
AJ
1545 if (unlikely(float64_is_any_nan(farg1.d) ||
1546 float64_is_any_nan(farg2.d))) {
9a819377
AJ
1547 ret = 0x01UL;
1548 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1549 ret = 0x08UL;
1550 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1551 ret = 0x04UL;
7c58044c 1552 } else {
9a819377 1553 ret = 0x02UL;
9a64fbe4 1554 }
9a819377 1555
7c58044c 1556 env->fpscr &= ~(0x0F << FPSCR_FPRF);
e1571908 1557 env->fpscr |= ret << FPSCR_FPRF;
9a819377
AJ
1558 env->crf[crfD] = ret;
1559 if (unlikely(ret == 0x01UL
1560 && (float64_is_signaling_nan(farg1.d) ||
1561 float64_is_signaling_nan(farg2.d)))) {
1562 /* sNaN comparison */
1563 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1564 }
9a64fbe4
FB
1565}
1566
9a819377 1567void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
9a64fbe4 1568{
af12906f 1569 CPU_DoubleU farg1, farg2;
e1571908 1570 uint32_t ret = 0;
af12906f
AJ
1571 farg1.ll = arg1;
1572 farg2.ll = arg2;
e1571908 1573
d788b570
AJ
1574 if (unlikely(float64_is_any_nan(farg1.d) ||
1575 float64_is_any_nan(farg2.d))) {
9a819377
AJ
1576 ret = 0x01UL;
1577 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1578 ret = 0x08UL;
1579 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1580 ret = 0x04UL;
1581 } else {
1582 ret = 0x02UL;
1583 }
1584
1585 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1586 env->fpscr |= ret << FPSCR_FPRF;
1587 env->crf[crfD] = ret;
1588 if (unlikely (ret == 0x01UL)) {
af12906f
AJ
1589 if (float64_is_signaling_nan(farg1.d) ||
1590 float64_is_signaling_nan(farg2.d)) {
7c58044c
JM
1591 /* sNaN comparison */
1592 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1593 POWERPC_EXCP_FP_VXVC);
1594 } else {
1595 /* qNaN comparison */
1596 fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
1597 }
9a64fbe4 1598 }
9a64fbe4
FB
1599}
1600
76a66253 1601#if !defined (CONFIG_USER_ONLY)
6527f6ea 1602void helper_store_msr (target_ulong val)
0411a972 1603{
6527f6ea
AJ
1604 val = hreg_store_msr(env, val, 0);
1605 if (val != 0) {
0411a972 1606 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
e06fcd75 1607 helper_raise_exception(val);
0411a972
JM
1608 }
1609}
1610
636aa200
BS
1611static inline void do_rfi(target_ulong nip, target_ulong msr,
1612 target_ulong msrm, int keep_msrh)
9a64fbe4 1613{
426613db 1614#if defined(TARGET_PPC64)
0411a972
JM
1615 if (msr & (1ULL << MSR_SF)) {
1616 nip = (uint64_t)nip;
1617 msr &= (uint64_t)msrm;
a42bd6cc 1618 } else {
0411a972
JM
1619 nip = (uint32_t)nip;
1620 msr = (uint32_t)(msr & msrm);
1621 if (keep_msrh)
1622 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
a42bd6cc 1623 }
426613db 1624#else
0411a972
JM
1625 nip = (uint32_t)nip;
1626 msr &= (uint32_t)msrm;
426613db 1627#endif
0411a972
JM
1628 /* XXX: beware: this is false if VLE is supported */
1629 env->nip = nip & ~((target_ulong)0x00000003);
a4f30719 1630 hreg_store_msr(env, msr, 1);
fdabc366 1631#if defined (DEBUG_OP)
0411a972 1632 cpu_dump_rfi(env->nip, env->msr);
fdabc366 1633#endif
0411a972
JM
1634 /* No need to raise an exception here,
1635 * as rfi is always the last insn of a TB
1636 */
fdabc366 1637 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
9a64fbe4 1638}
d9bce9d9 1639
d72a19f7 1640void helper_rfi (void)
0411a972 1641{
d72a19f7 1642 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
c3d420ea 1643 ~((target_ulong)0x783F0000), 1);
0411a972
JM
1644}
1645
d9bce9d9 1646#if defined(TARGET_PPC64)
d72a19f7 1647void helper_rfid (void)
426613db 1648{
d72a19f7 1649 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
c3d420ea 1650 ~((target_ulong)0x783F0000), 0);
d9bce9d9 1651}
7863667f 1652
d72a19f7 1653void helper_hrfid (void)
be147d08 1654{
d72a19f7 1655 do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
c3d420ea 1656 ~((target_ulong)0x783F0000), 0);
be147d08
JM
1657}
1658#endif
76a66253 1659#endif
9a64fbe4 1660
cab3bee2 1661void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
9a64fbe4 1662{
cab3bee2
AJ
1663 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1664 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1665 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1666 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1667 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
e06fcd75 1668 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
a42bd6cc 1669 }
9a64fbe4
FB
1670}
1671
d9bce9d9 1672#if defined(TARGET_PPC64)
cab3bee2 1673void helper_td (target_ulong arg1, target_ulong arg2, uint32_t flags)
d9bce9d9 1674{
cab3bee2
AJ
1675 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1676 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1677 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1678 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1679 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01)))))
e06fcd75 1680 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
d9bce9d9
JM
1681}
1682#endif
1683
fdabc366 1684/*****************************************************************************/
76a66253 1685/* PowerPC 601 specific instructions (POWER bridge) */
9a64fbe4 1686
22e0e173 1687target_ulong helper_clcs (uint32_t arg)
9a64fbe4 1688{
22e0e173 1689 switch (arg) {
76a66253
JM
1690 case 0x0CUL:
1691 /* Instruction cache line size */
22e0e173 1692 return env->icache_line_size;
76a66253
JM
1693 break;
1694 case 0x0DUL:
1695 /* Data cache line size */
22e0e173 1696 return env->dcache_line_size;
76a66253
JM
1697 break;
1698 case 0x0EUL:
1699 /* Minimum cache line size */
22e0e173
AJ
1700 return (env->icache_line_size < env->dcache_line_size) ?
1701 env->icache_line_size : env->dcache_line_size;
76a66253
JM
1702 break;
1703 case 0x0FUL:
1704 /* Maximum cache line size */
22e0e173
AJ
1705 return (env->icache_line_size > env->dcache_line_size) ?
1706 env->icache_line_size : env->dcache_line_size;
76a66253
JM
1707 break;
1708 default:
1709 /* Undefined */
22e0e173 1710 return 0;
76a66253
JM
1711 break;
1712 }
1713}
1714
22e0e173 1715target_ulong helper_div (target_ulong arg1, target_ulong arg2)
76a66253 1716{
22e0e173 1717 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
76a66253 1718
22e0e173
AJ
1719 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1720 (int32_t)arg2 == 0) {
76a66253 1721 env->spr[SPR_MQ] = 0;
22e0e173 1722 return INT32_MIN;
76a66253 1723 } else {
22e0e173
AJ
1724 env->spr[SPR_MQ] = tmp % arg2;
1725 return tmp / (int32_t)arg2;
76a66253
JM
1726 }
1727}
1728
22e0e173 1729target_ulong helper_divo (target_ulong arg1, target_ulong arg2)
76a66253 1730{
22e0e173 1731 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
76a66253 1732
22e0e173
AJ
1733 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1734 (int32_t)arg2 == 0) {
3d7b417e 1735 env->xer |= (1 << XER_OV) | (1 << XER_SO);
76a66253 1736 env->spr[SPR_MQ] = 0;
22e0e173 1737 return INT32_MIN;
76a66253 1738 } else {
22e0e173
AJ
1739 env->spr[SPR_MQ] = tmp % arg2;
1740 tmp /= (int32_t)arg2;
1741 if ((int32_t)tmp != tmp) {
3d7b417e 1742 env->xer |= (1 << XER_OV) | (1 << XER_SO);
76a66253 1743 } else {
3d7b417e 1744 env->xer &= ~(1 << XER_OV);
76a66253 1745 }
22e0e173 1746 return tmp;
76a66253
JM
1747 }
1748}
1749
22e0e173 1750target_ulong helper_divs (target_ulong arg1, target_ulong arg2)
76a66253 1751{
22e0e173
AJ
1752 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1753 (int32_t)arg2 == 0) {
1754 env->spr[SPR_MQ] = 0;
1755 return INT32_MIN;
76a66253 1756 } else {
22e0e173
AJ
1757 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1758 return (int32_t)arg1 / (int32_t)arg2;
76a66253 1759 }
76a66253
JM
1760}
1761
22e0e173 1762target_ulong helper_divso (target_ulong arg1, target_ulong arg2)
76a66253 1763{
22e0e173
AJ
1764 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1765 (int32_t)arg2 == 0) {
3d7b417e 1766 env->xer |= (1 << XER_OV) | (1 << XER_SO);
22e0e173
AJ
1767 env->spr[SPR_MQ] = 0;
1768 return INT32_MIN;
76a66253 1769 } else {
3d7b417e 1770 env->xer &= ~(1 << XER_OV);
22e0e173
AJ
1771 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1772 return (int32_t)arg1 / (int32_t)arg2;
76a66253
JM
1773 }
1774}
1775
1776#if !defined (CONFIG_USER_ONLY)
22e0e173 1777target_ulong helper_rac (target_ulong addr)
76a66253 1778{
c227f099 1779 mmu_ctx_t ctx;
faadf50e 1780 int nb_BATs;
22e0e173 1781 target_ulong ret = 0;
76a66253
JM
1782
1783 /* We don't have to generate many instances of this instruction,
1784 * as rac is supervisor only.
1785 */
faadf50e
JM
1786 /* XXX: FIX THIS: Pretend we have no BAT */
1787 nb_BATs = env->nb_BATs;
1788 env->nb_BATs = 0;
22e0e173
AJ
1789 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0)
1790 ret = ctx.raddr;
faadf50e 1791 env->nb_BATs = nb_BATs;
22e0e173 1792 return ret;
76a66253
JM
1793}
1794
d72a19f7 1795void helper_rfsvc (void)
76a66253 1796{
d72a19f7 1797 do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
76a66253 1798}
76a66253
JM
1799#endif
1800
1801/*****************************************************************************/
1802/* 602 specific instructions */
1803/* mfrom is the most crazy instruction ever seen, imho ! */
1804/* Real implementation uses a ROM table. Do the same */
5e9ae189
AJ
1805/* Extremly decomposed:
1806 * -arg / 256
1807 * return 256 * log10(10 + 1.0) + 0.5
1808 */
db9a16a7 1809#if !defined (CONFIG_USER_ONLY)
cf02a65c 1810target_ulong helper_602_mfrom (target_ulong arg)
76a66253 1811{
cf02a65c 1812 if (likely(arg < 602)) {
76a66253 1813#include "mfrom_table.c"
45d827d2 1814 return mfrom_ROM_table[arg];
76a66253 1815 } else {
cf02a65c 1816 return 0;
76a66253
JM
1817 }
1818}
db9a16a7 1819#endif
76a66253
JM
1820
1821/*****************************************************************************/
1822/* Embedded PowerPC specific helpers */
76a66253 1823
a750fc0b 1824/* XXX: to be improved to check access rights when in user-mode */
95ff895f 1825target_ulong helper_load_dcr (target_ulong dcrn)
a750fc0b 1826{
73b01960 1827 uint32_t val = 0;
a750fc0b
JM
1828
1829 if (unlikely(env->dcr_env == NULL)) {
93fcfe39 1830 qemu_log("No DCR environment\n");
e06fcd75
AJ
1831 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1832 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
95ff895f
AJ
1833 } else if (unlikely(ppc_dcr_read(env->dcr_env, (uint32_t)dcrn, &val) != 0)) {
1834 qemu_log("DCR read error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
e06fcd75
AJ
1835 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1836 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
a750fc0b 1837 }
06dca6a7 1838 return val;
a750fc0b
JM
1839}
1840
95ff895f 1841void helper_store_dcr (target_ulong dcrn, target_ulong val)
a750fc0b
JM
1842{
1843 if (unlikely(env->dcr_env == NULL)) {
93fcfe39 1844 qemu_log("No DCR environment\n");
e06fcd75
AJ
1845 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1846 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
95ff895f
AJ
1847 } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn, (uint32_t)val) != 0)) {
1848 qemu_log("DCR write error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
e06fcd75
AJ
1849 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1850 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
a750fc0b
JM
1851 }
1852}
1853
76a66253 1854#if !defined(CONFIG_USER_ONLY)
d72a19f7 1855void helper_40x_rfci (void)
76a66253 1856{
d72a19f7
AJ
1857 do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
1858 ~((target_ulong)0xFFFF0000), 0);
a42bd6cc
JM
1859}
1860
d72a19f7 1861void helper_rfci (void)
a42bd6cc 1862{
d72a19f7
AJ
1863 do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
1864 ~((target_ulong)0x3FFF0000), 0);
a42bd6cc
JM
1865}
1866
d72a19f7 1867void helper_rfdi (void)
a42bd6cc 1868{
d72a19f7
AJ
1869 do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
1870 ~((target_ulong)0x3FFF0000), 0);
a42bd6cc
JM
1871}
1872
d72a19f7 1873void helper_rfmci (void)
a42bd6cc 1874{
d72a19f7
AJ
1875 do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
1876 ~((target_ulong)0x3FFF0000), 0);
76a66253 1877}
76a66253
JM
1878#endif
1879
1880/* 440 specific */
ef0d51af 1881target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
76a66253
JM
1882{
1883 target_ulong mask;
1884 int i;
1885
1886 i = 1;
1887 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
ef0d51af
AJ
1888 if ((high & mask) == 0) {
1889 if (update_Rc) {
1890 env->crf[0] = 0x4;
1891 }
76a66253 1892 goto done;
ef0d51af 1893 }
76a66253
JM
1894 i++;
1895 }
1896 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
ef0d51af
AJ
1897 if ((low & mask) == 0) {
1898 if (update_Rc) {
1899 env->crf[0] = 0x8;
1900 }
1901 goto done;
1902 }
76a66253
JM
1903 i++;
1904 }
ef0d51af
AJ
1905 if (update_Rc) {
1906 env->crf[0] = 0x2;
1907 }
76a66253 1908 done:
ef0d51af
AJ
1909 env->xer = (env->xer & ~0x7F) | i;
1910 if (update_Rc) {
1911 env->crf[0] |= xer_so;
1912 }
1913 return i;
fdabc366
FB
1914}
1915
d6a46fe8
AJ
1916/*****************************************************************************/
1917/* Altivec extension helpers */
e2542fe2 1918#if defined(HOST_WORDS_BIGENDIAN)
d6a46fe8
AJ
1919#define HI_IDX 0
1920#define LO_IDX 1
1921#else
1922#define HI_IDX 1
1923#define LO_IDX 0
1924#endif
1925
e2542fe2 1926#if defined(HOST_WORDS_BIGENDIAN)
d6a46fe8
AJ
1927#define VECTOR_FOR_INORDER_I(index, element) \
1928 for (index = 0; index < ARRAY_SIZE(r->element); index++)
1929#else
1930#define VECTOR_FOR_INORDER_I(index, element) \
1931 for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
1932#endif
1933
34ba2857
AJ
1934/* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise,
1935 * execute the following block. */
1936#define DO_HANDLE_NAN(result, x) \
82b323cd 1937 if (float32_is_any_nan(x)) { \
34ba2857
AJ
1938 CPU_FloatU __f; \
1939 __f.f = x; \
1940 __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \
1941 result = __f.f; \
1942 } else
1943
1944#define HANDLE_NAN1(result, x) \
1945 DO_HANDLE_NAN(result, x)
1946#define HANDLE_NAN2(result, x, y) \
1947 DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y)
1948#define HANDLE_NAN3(result, x, y, z) \
1949 DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z)
1950
00d3b8f5 1951/* Saturating arithmetic helpers. */
d62d2863 1952#define SATCVT(from, to, from_type, to_type, min, max) \
636aa200 1953 static inline to_type cvt##from##to(from_type x, int *sat) \
00d3b8f5
AJ
1954 { \
1955 to_type r; \
d62d2863 1956 if (x < (from_type)min) { \
00d3b8f5
AJ
1957 r = min; \
1958 *sat = 1; \
d62d2863 1959 } else if (x > (from_type)max) { \
00d3b8f5
AJ
1960 r = max; \
1961 *sat = 1; \
1962 } else { \
1963 r = x; \
1964 } \
1965 return r; \
1966 }
d62d2863
BS
1967#define SATCVTU(from, to, from_type, to_type, min, max) \
1968 static inline to_type cvt##from##to(from_type x, int *sat) \
1969 { \
1970 to_type r; \
1971 if (x > (from_type)max) { \
1972 r = max; \
1973 *sat = 1; \
1974 } else { \
1975 r = x; \
1976 } \
1977 return r; \
c5b76b38 1978 }
d62d2863
BS
1979SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
1980SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
1981SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX)
1982
1983SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX)
1984SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX)
1985SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX)
1986SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX)
1987SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX)
1988SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
00d3b8f5 1989#undef SATCVT
d62d2863 1990#undef SATCVTU
00d3b8f5 1991
cbfb6ae9 1992#define LVE(name, access, swap, element) \
c227f099 1993 void helper_##name (ppc_avr_t *r, target_ulong addr) \
cbfb6ae9
AJ
1994 { \
1995 size_t n_elems = ARRAY_SIZE(r->element); \
1996 int adjust = HI_IDX*(n_elems-1); \
1997 int sh = sizeof(r->element[0]) >> 1; \
1998 int index = (addr & 0xf) >> sh; \
1999 if(msr_le) { \
2000 r->element[LO_IDX ? index : (adjust - index)] = swap(access(addr)); \
2001 } else { \
2002 r->element[LO_IDX ? index : (adjust - index)] = access(addr); \
2003 } \
2004 }
2005#define I(x) (x)
2006LVE(lvebx, ldub, I, u8)
2007LVE(lvehx, lduw, bswap16, u16)
2008LVE(lvewx, ldl, bswap32, u32)
2009#undef I
2010#undef LVE
2011
c227f099 2012void helper_lvsl (ppc_avr_t *r, target_ulong sh)
bf8d8ded
AJ
2013{
2014 int i, j = (sh & 0xf);
2015
2016 VECTOR_FOR_INORDER_I (i, u8) {
2017 r->u8[i] = j++;
2018 }
2019}
2020
c227f099 2021void helper_lvsr (ppc_avr_t *r, target_ulong sh)
bf8d8ded
AJ
2022{
2023 int i, j = 0x10 - (sh & 0xf);
2024
2025 VECTOR_FOR_INORDER_I (i, u8) {
2026 r->u8[i] = j++;
2027 }
2028}
2029
cbfb6ae9 2030#define STVE(name, access, swap, element) \
c227f099 2031 void helper_##name (ppc_avr_t *r, target_ulong addr) \
cbfb6ae9
AJ
2032 { \
2033 size_t n_elems = ARRAY_SIZE(r->element); \
2034 int adjust = HI_IDX*(n_elems-1); \
2035 int sh = sizeof(r->element[0]) >> 1; \
2036 int index = (addr & 0xf) >> sh; \
2037 if(msr_le) { \
2038 access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \
2039 } else { \
2040 access(addr, r->element[LO_IDX ? index : (adjust - index)]); \
2041 } \
2042 }
2043#define I(x) (x)
2044STVE(stvebx, stb, I, u8)
2045STVE(stvehx, stw, bswap16, u16)
2046STVE(stvewx, stl, bswap32, u32)
2047#undef I
2048#undef LVE
2049
c227f099 2050void helper_mtvscr (ppc_avr_t *r)
6e87b7c7 2051{
e2542fe2 2052#if defined(HOST_WORDS_BIGENDIAN)
6e87b7c7
AJ
2053 env->vscr = r->u32[3];
2054#else
2055 env->vscr = r->u32[0];
2056#endif
2057 set_flush_to_zero(vscr_nj, &env->vec_status);
2058}
2059
c227f099 2060void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
e343da72
AJ
2061{
2062 int i;
2063 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2064 r->u32[i] = ~a->u32[i] < b->u32[i];
2065 }
2066}
2067
c227f099
AL
2068#define VARITH_DO(name, op, element) \
2069void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2070{ \
2071 int i; \
2072 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2073 r->element[i] = a->element[i] op b->element[i]; \
2074 } \
7872c51c
AJ
2075}
2076#define VARITH(suffix, element) \
2077 VARITH_DO(add##suffix, +, element) \
2078 VARITH_DO(sub##suffix, -, element)
2079VARITH(ubm, u8)
2080VARITH(uhm, u16)
2081VARITH(uwm, u32)
2082#undef VARITH_DO
2083#undef VARITH
2084
56fdd213 2085#define VARITHFP(suffix, func) \
c227f099 2086 void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
56fdd213
AJ
2087 { \
2088 int i; \
2089 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2090 HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
2091 r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \
2092 } \
2093 } \
2094 }
2095VARITHFP(addfp, float32_add)
2096VARITHFP(subfp, float32_sub)
2097#undef VARITHFP
2098
5ab09f33
AJ
2099#define VARITHSAT_CASE(type, op, cvt, element) \
2100 { \
2101 type result = (type)a->element[i] op (type)b->element[i]; \
2102 r->element[i] = cvt(result, &sat); \
2103 }
2104
2105#define VARITHSAT_DO(name, op, optype, cvt, element) \
c227f099 2106 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
5ab09f33
AJ
2107 { \
2108 int sat = 0; \
2109 int i; \
2110 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2111 switch (sizeof(r->element[0])) { \
2112 case 1: VARITHSAT_CASE(optype, op, cvt, element); break; \
2113 case 2: VARITHSAT_CASE(optype, op, cvt, element); break; \
2114 case 4: VARITHSAT_CASE(optype, op, cvt, element); break; \
2115 } \
2116 } \
2117 if (sat) { \
2118 env->vscr |= (1 << VSCR_SAT); \
2119 } \
2120 }
2121#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
2122 VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
2123 VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
2124#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
2125 VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
2126 VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
2127VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
2128VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
2129VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
2130VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
2131VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
2132VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
2133#undef VARITHSAT_CASE
2134#undef VARITHSAT_DO
2135#undef VARITHSAT_SIGNED
2136#undef VARITHSAT_UNSIGNED
2137
fab3cbe9 2138#define VAVG_DO(name, element, etype) \
c227f099 2139 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
fab3cbe9
AJ
2140 { \
2141 int i; \
2142 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2143 etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
2144 r->element[i] = x >> 1; \
2145 } \
2146 }
2147
2148#define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
2149 VAVG_DO(avgs##type, signed_element, signed_type) \
2150 VAVG_DO(avgu##type, unsigned_element, unsigned_type)
2151VAVG(b, s8, int16_t, u8, uint16_t)
2152VAVG(h, s16, int32_t, u16, uint32_t)
2153VAVG(w, s32, int64_t, u32, uint64_t)
2154#undef VAVG_DO
2155#undef VAVG
2156
e140632e 2157#define VCF(suffix, cvt, element) \
c227f099 2158 void helper_vcf##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
e140632e
AJ
2159 { \
2160 int i; \
2161 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2162 float32 t = cvt(b->element[i], &env->vec_status); \
2163 r->f[i] = float32_scalbn (t, -uim, &env->vec_status); \
2164 } \
2165 }
2166VCF(ux, uint32_to_float32, u32)
2167VCF(sx, int32_to_float32, s32)
2168#undef VCF
2169
1add6e23 2170#define VCMP_DO(suffix, compare, element, record) \
c227f099 2171 void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1add6e23
AJ
2172 { \
2173 uint32_t ones = (uint32_t)-1; \
2174 uint32_t all = ones; \
2175 uint32_t none = 0; \
2176 int i; \
2177 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2178 uint32_t result = (a->element[i] compare b->element[i] ? ones : 0x0); \
2179 switch (sizeof (a->element[0])) { \
2180 case 4: r->u32[i] = result; break; \
2181 case 2: r->u16[i] = result; break; \
2182 case 1: r->u8[i] = result; break; \
2183 } \
2184 all &= result; \
2185 none |= result; \
2186 } \
2187 if (record) { \
2188 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
2189 } \
2190 }
2191#define VCMP(suffix, compare, element) \
2192 VCMP_DO(suffix, compare, element, 0) \
2193 VCMP_DO(suffix##_dot, compare, element, 1)
2194VCMP(equb, ==, u8)
2195VCMP(equh, ==, u16)
2196VCMP(equw, ==, u32)
2197VCMP(gtub, >, u8)
2198VCMP(gtuh, >, u16)
2199VCMP(gtuw, >, u32)
2200VCMP(gtsb, >, s8)
2201VCMP(gtsh, >, s16)
2202VCMP(gtsw, >, s32)
2203#undef VCMP_DO
2204#undef VCMP
2205
819ca121 2206#define VCMPFP_DO(suffix, compare, order, record) \
c227f099 2207 void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
819ca121
AJ
2208 { \
2209 uint32_t ones = (uint32_t)-1; \
2210 uint32_t all = ones; \
2211 uint32_t none = 0; \
2212 int i; \
2213 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2214 uint32_t result; \
2215 int rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status); \
2216 if (rel == float_relation_unordered) { \
2217 result = 0; \
2218 } else if (rel compare order) { \
2219 result = ones; \
2220 } else { \
2221 result = 0; \
2222 } \
2223 r->u32[i] = result; \
2224 all &= result; \
2225 none |= result; \
2226 } \
2227 if (record) { \
2228 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
2229 } \
2230 }
2231#define VCMPFP(suffix, compare, order) \
2232 VCMPFP_DO(suffix, compare, order, 0) \
2233 VCMPFP_DO(suffix##_dot, compare, order, 1)
2234VCMPFP(eqfp, ==, float_relation_equal)
2235VCMPFP(gefp, !=, float_relation_less)
2236VCMPFP(gtfp, ==, float_relation_greater)
2237#undef VCMPFP_DO
2238#undef VCMPFP
2239
c227f099 2240static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
636aa200 2241 int record)
819ca121
AJ
2242{
2243 int i;
2244 int all_in = 0;
2245 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2246 int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
2247 if (le_rel == float_relation_unordered) {
2248 r->u32[i] = 0xc0000000;
2249 /* ALL_IN does not need to be updated here. */
2250 } else {
2251 float32 bneg = float32_chs(b->f[i]);
2252 int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
2253 int le = le_rel != float_relation_greater;
2254 int ge = ge_rel != float_relation_less;
2255 r->u32[i] = ((!le) << 31) | ((!ge) << 30);
2256 all_in |= (!le | !ge);
2257 }
2258 }
2259 if (record) {
2260 env->crf[6] = (all_in == 0) << 1;
2261 }
2262}
2263
c227f099 2264void helper_vcmpbfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
819ca121
AJ
2265{
2266 vcmpbfp_internal(r, a, b, 0);
2267}
2268
c227f099 2269void helper_vcmpbfp_dot (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
819ca121
AJ
2270{
2271 vcmpbfp_internal(r, a, b, 1);
2272}
2273
875b31db 2274#define VCT(suffix, satcvt, element) \
c227f099 2275 void helper_vct##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
875b31db
AJ
2276 { \
2277 int i; \
2278 int sat = 0; \
2279 float_status s = env->vec_status; \
2280 set_float_rounding_mode(float_round_to_zero, &s); \
2281 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
82b323cd 2282 if (float32_is_any_nan(b->f[i])) { \
875b31db
AJ
2283 r->element[i] = 0; \
2284 } else { \
2285 float64 t = float32_to_float64(b->f[i], &s); \
2286 int64_t j; \
2287 t = float64_scalbn(t, uim, &s); \
2288 j = float64_to_int64(t, &s); \
2289 r->element[i] = satcvt(j, &sat); \
2290 } \
2291 } \
2292 if (sat) { \
2293 env->vscr |= (1 << VSCR_SAT); \
2294 } \
2295 }
2296VCT(uxs, cvtsduw, u32)
2297VCT(sxs, cvtsdsw, s32)
2298#undef VCT
2299
c227f099 2300void helper_vmaddfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
35cf7c7e
AJ
2301{
2302 int i;
2303 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2304 HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
2305 /* Need to do the computation in higher precision and round
2306 * once at the end. */
2307 float64 af, bf, cf, t;
2308 af = float32_to_float64(a->f[i], &env->vec_status);
2309 bf = float32_to_float64(b->f[i], &env->vec_status);
2310 cf = float32_to_float64(c->f[i], &env->vec_status);
2311 t = float64_mul(af, cf, &env->vec_status);
2312 t = float64_add(t, bf, &env->vec_status);
2313 r->f[i] = float64_to_float32(t, &env->vec_status);
2314 }
2315 }
2316}
2317
c227f099 2318void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
b161ae27
AJ
2319{
2320 int sat = 0;
2321 int i;
2322
2323 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2324 int32_t prod = a->s16[i] * b->s16[i];
2325 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2326 r->s16[i] = cvtswsh (t, &sat);
2327 }
2328
2329 if (sat) {
2330 env->vscr |= (1 << VSCR_SAT);
2331 }
2332}
2333
c227f099 2334void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
b161ae27
AJ
2335{
2336 int sat = 0;
2337 int i;
2338
2339 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2340 int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
2341 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2342 r->s16[i] = cvtswsh (t, &sat);
2343 }
2344
2345 if (sat) {
2346 env->vscr |= (1 << VSCR_SAT);
2347 }
2348}
2349
e4039339 2350#define VMINMAX_DO(name, compare, element) \
c227f099 2351 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
e4039339
AJ
2352 { \
2353 int i; \
2354 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2355 if (a->element[i] compare b->element[i]) { \
2356 r->element[i] = b->element[i]; \
2357 } else { \
2358 r->element[i] = a->element[i]; \
2359 } \
2360 } \
2361 }
2362#define VMINMAX(suffix, element) \
2363 VMINMAX_DO(min##suffix, >, element) \
2364 VMINMAX_DO(max##suffix, <, element)
2365VMINMAX(sb, s8)
2366VMINMAX(sh, s16)
2367VMINMAX(sw, s32)
2368VMINMAX(ub, u8)
2369VMINMAX(uh, u16)
2370VMINMAX(uw, u32)
2371#undef VMINMAX_DO
2372#undef VMINMAX
2373
1536ff64 2374#define VMINMAXFP(suffix, rT, rF) \
c227f099 2375 void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1536ff64
AJ
2376 { \
2377 int i; \
2378 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2379 HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
2380 if (float32_lt_quiet(a->f[i], b->f[i], &env->vec_status)) { \
2381 r->f[i] = rT->f[i]; \
2382 } else { \
2383 r->f[i] = rF->f[i]; \
2384 } \
2385 } \
2386 } \
2387 }
2388VMINMAXFP(minfp, a, b)
2389VMINMAXFP(maxfp, b, a)
2390#undef VMINMAXFP
2391
c227f099 2392void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
bcd2ee23
AJ
2393{
2394 int i;
2395 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2396 int32_t prod = a->s16[i] * b->s16[i];
2397 r->s16[i] = (int16_t) (prod + c->s16[i]);
2398 }
2399}
2400
3b430048 2401#define VMRG_DO(name, element, highp) \
c227f099 2402 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
3b430048 2403 { \
c227f099 2404 ppc_avr_t result; \
3b430048
AJ
2405 int i; \
2406 size_t n_elems = ARRAY_SIZE(r->element); \
2407 for (i = 0; i < n_elems/2; i++) { \
2408 if (highp) { \
2409 result.element[i*2+HI_IDX] = a->element[i]; \
2410 result.element[i*2+LO_IDX] = b->element[i]; \
2411 } else { \
2412 result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
2413 result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
2414 } \
2415 } \
2416 *r = result; \
2417 }
e2542fe2 2418#if defined(HOST_WORDS_BIGENDIAN)
3b430048 2419#define MRGHI 0
b392e756 2420#define MRGLO 1
3b430048
AJ
2421#else
2422#define MRGHI 1
2423#define MRGLO 0
2424#endif
2425#define VMRG(suffix, element) \
2426 VMRG_DO(mrgl##suffix, element, MRGHI) \
2427 VMRG_DO(mrgh##suffix, element, MRGLO)
2428VMRG(b, u8)
2429VMRG(h, u16)
2430VMRG(w, u32)
2431#undef VMRG_DO
2432#undef VMRG
2433#undef MRGHI
2434#undef MRGLO
2435
c227f099 2436void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
b04ae981
AJ
2437{
2438 int32_t prod[16];
2439 int i;
2440
2441 for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
2442 prod[i] = (int32_t)a->s8[i] * b->u8[i];
2443 }
2444
2445 VECTOR_FOR_INORDER_I(i, s32) {
2446 r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2447 }
2448}
2449
c227f099 2450void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
eae07261
AJ
2451{
2452 int32_t prod[8];
2453 int i;
2454
2455 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2456 prod[i] = a->s16[i] * b->s16[i];
2457 }
2458
2459 VECTOR_FOR_INORDER_I(i, s32) {
2460 r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1];
2461 }
2462}
2463
c227f099 2464void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
eae07261
AJ
2465{
2466 int32_t prod[8];
2467 int i;
2468 int sat = 0;
2469
2470 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2471 prod[i] = (int32_t)a->s16[i] * b->s16[i];
2472 }
2473
2474 VECTOR_FOR_INORDER_I (i, s32) {
2475 int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1];
2476 r->u32[i] = cvtsdsw(t, &sat);
2477 }
2478
2479 if (sat) {
2480 env->vscr |= (1 << VSCR_SAT);
2481 }
2482}
2483
c227f099 2484void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
b04ae981
AJ
2485{
2486 uint16_t prod[16];
2487 int i;
2488
2489 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2490 prod[i] = a->u8[i] * b->u8[i];
2491 }
2492
2493 VECTOR_FOR_INORDER_I(i, u32) {
2494 r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2495 }
2496}
2497
c227f099 2498void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
4d9903b6
AJ
2499{
2500 uint32_t prod[8];
2501 int i;
2502
2503 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2504 prod[i] = a->u16[i] * b->u16[i];
2505 }
2506
2507 VECTOR_FOR_INORDER_I(i, u32) {
2508 r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1];
2509 }
2510}
2511
c227f099 2512void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
4d9903b6
AJ
2513{
2514 uint32_t prod[8];
2515 int i;
2516 int sat = 0;
2517
2518 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2519 prod[i] = a->u16[i] * b->u16[i];
2520 }
2521
2522 VECTOR_FOR_INORDER_I (i, s32) {
2523 uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1];
2524 r->u32[i] = cvtuduw(t, &sat);
2525 }
2526
2527 if (sat) {
2528 env->vscr |= (1 << VSCR_SAT);
2529 }
2530}
2531
2c277908 2532#define VMUL_DO(name, mul_element, prod_element, evenp) \
c227f099 2533 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2c277908
AJ
2534 { \
2535 int i; \
2536 VECTOR_FOR_INORDER_I(i, prod_element) { \
2537 if (evenp) { \
2538 r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2539 } else { \
2540 r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2541 } \
2542 } \
2543 }
2544#define VMUL(suffix, mul_element, prod_element) \
2545 VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2546 VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2547VMUL(sb, s8, s16)
2548VMUL(sh, s16, s32)
2549VMUL(ub, u8, u16)
2550VMUL(uh, u16, u32)
2551#undef VMUL_DO
2552#undef VMUL
2553
c227f099 2554void helper_vnmsubfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
35cf7c7e
AJ
2555{
2556 int i;
2557 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2558 HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
2559 /* Need to do the computation is higher precision and round
2560 * once at the end. */
2561 float64 af, bf, cf, t;
2562 af = float32_to_float64(a->f[i], &env->vec_status);
2563 bf = float32_to_float64(b->f[i], &env->vec_status);
2564 cf = float32_to_float64(c->f[i], &env->vec_status);
2565 t = float64_mul(af, cf, &env->vec_status);
2566 t = float64_sub(t, bf, &env->vec_status);
2567 t = float64_chs(t);
2568 r->f[i] = float64_to_float32(t, &env->vec_status);
2569 }
2570 }
2571}
2572
c227f099 2573void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
d1258698 2574{
c227f099 2575 ppc_avr_t result;
d1258698
AJ
2576 int i;
2577 VECTOR_FOR_INORDER_I (i, u8) {
2578 int s = c->u8[i] & 0x1f;
e2542fe2 2579#if defined(HOST_WORDS_BIGENDIAN)
d1258698
AJ
2580 int index = s & 0xf;
2581#else
2582 int index = 15 - (s & 0xf);
2583#endif
2584 if (s & 0x10) {
2585 result.u8[i] = b->u8[index];
2586 } else {
2587 result.u8[i] = a->u8[index];
2588 }
2589 }
2590 *r = result;
2591}
2592
e2542fe2 2593#if defined(HOST_WORDS_BIGENDIAN)
5335a145
AJ
2594#define PKBIG 1
2595#else
2596#define PKBIG 0
2597#endif
c227f099 2598void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1dd9ffb9
AJ
2599{
2600 int i, j;
c227f099 2601 ppc_avr_t result;
e2542fe2 2602#if defined(HOST_WORDS_BIGENDIAN)
c227f099 2603 const ppc_avr_t *x[2] = { a, b };
1dd9ffb9 2604#else
c227f099 2605 const ppc_avr_t *x[2] = { b, a };
1dd9ffb9
AJ
2606#endif
2607
2608 VECTOR_FOR_INORDER_I (i, u64) {
2609 VECTOR_FOR_INORDER_I (j, u32){
2610 uint32_t e = x[i]->u32[j];
2611 result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
2612 ((e >> 6) & 0x3e0) |
2613 ((e >> 3) & 0x1f));
2614 }
2615 }
2616 *r = result;
2617}
2618
5335a145 2619#define VPK(suffix, from, to, cvt, dosat) \
c227f099 2620 void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
5335a145
AJ
2621 { \
2622 int i; \
2623 int sat = 0; \
c227f099
AL
2624 ppc_avr_t result; \
2625 ppc_avr_t *a0 = PKBIG ? a : b; \
2626 ppc_avr_t *a1 = PKBIG ? b : a; \
5335a145
AJ
2627 VECTOR_FOR_INORDER_I (i, from) { \
2628 result.to[i] = cvt(a0->from[i], &sat); \
2629 result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
2630 } \
2631 *r = result; \
2632 if (dosat && sat) { \
2633 env->vscr |= (1 << VSCR_SAT); \
2634 } \
2635 }
2636#define I(x, y) (x)
2637VPK(shss, s16, s8, cvtshsb, 1)
2638VPK(shus, s16, u8, cvtshub, 1)
2639VPK(swss, s32, s16, cvtswsh, 1)
2640VPK(swus, s32, u16, cvtswuh, 1)
2641VPK(uhus, u16, u8, cvtuhub, 1)
2642VPK(uwus, u32, u16, cvtuwuh, 1)
2643VPK(uhum, u16, u8, I, 0)
2644VPK(uwum, u32, u16, I, 0)
2645#undef I
2646#undef VPK
2647#undef PKBIG
2648
c227f099 2649void helper_vrefp (ppc_avr_t *r, ppc_avr_t *b)
bdfbac35
AJ
2650{
2651 int i;
2652 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2653 HANDLE_NAN1(r->f[i], b->f[i]) {
2654 r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
2655 }
2656 }
2657}
2658
f6b19645 2659#define VRFI(suffix, rounding) \
c227f099 2660 void helper_vrfi##suffix (ppc_avr_t *r, ppc_avr_t *b) \
f6b19645
AJ
2661 { \
2662 int i; \
2663 float_status s = env->vec_status; \
2664 set_float_rounding_mode(rounding, &s); \
2665 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2666 HANDLE_NAN1(r->f[i], b->f[i]) { \
2667 r->f[i] = float32_round_to_int (b->f[i], &s); \
2668 } \
2669 } \
2670 }
2671VRFI(n, float_round_nearest_even)
2672VRFI(m, float_round_down)
2673VRFI(p, float_round_up)
2674VRFI(z, float_round_to_zero)
2675#undef VRFI
2676
5e1d0985 2677#define VROTATE(suffix, element) \
c227f099 2678 void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
5e1d0985
AJ
2679 { \
2680 int i; \
2681 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2682 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2683 unsigned int shift = b->element[i] & mask; \
2684 r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2685 } \
2686 }
2687VROTATE(b, u8)
2688VROTATE(h, u16)
2689VROTATE(w, u32)
2690#undef VROTATE
2691
c227f099 2692void helper_vrsqrtefp (ppc_avr_t *r, ppc_avr_t *b)
071fc3b1
AJ
2693{
2694 int i;
2695 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2696 HANDLE_NAN1(r->f[i], b->f[i]) {
2697 float32 t = float32_sqrt(b->f[i], &env->vec_status);
2698 r->f[i] = float32_div(float32_one, t, &env->vec_status);
2699 }
2700 }
2701}
2702
c227f099 2703void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
d1258698
AJ
2704{
2705 r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2706 r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2707}
2708
0bffbc6c
AJ
2709void helper_vexptefp (ppc_avr_t *r, ppc_avr_t *b)
2710{
2711 int i;
2712 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2713 HANDLE_NAN1(r->f[i], b->f[i]) {
2714 r->f[i] = float32_exp2(b->f[i], &env->vec_status);
2715 }
2716 }
2717}
2718
c227f099 2719void helper_vlogefp (ppc_avr_t *r, ppc_avr_t *b)
f586ce09
AJ
2720{
2721 int i;
2722 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2723 HANDLE_NAN1(r->f[i], b->f[i]) {
2724 r->f[i] = float32_log2(b->f[i], &env->vec_status);
2725 }
2726 }
2727}
2728
e2542fe2 2729#if defined(HOST_WORDS_BIGENDIAN)
d9430add
AJ
2730#define LEFT 0
2731#define RIGHT 1
2732#else
2733#define LEFT 1
2734#define RIGHT 0
2735#endif
2736/* The specification says that the results are undefined if all of the
2737 * shift counts are not identical. We check to make sure that they are
2738 * to conform to what real hardware appears to do. */
2739#define VSHIFT(suffix, leftp) \
c227f099 2740 void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
d9430add 2741 { \
1481e16a 2742 int shift = b->u8[LO_IDX*15] & 0x7; \
d9430add
AJ
2743 int doit = 1; \
2744 int i; \
2745 for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
2746 doit = doit && ((b->u8[i] & 0x7) == shift); \
2747 } \
2748 if (doit) { \
2749 if (shift == 0) { \
2750 *r = *a; \
2751 } else if (leftp) { \
2752 uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \
2753 r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \
2754 r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \
2755 } else { \
2756 uint64_t carry = a->u64[HI_IDX] << (64 - shift); \
2757 r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \
2758 r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \
2759 } \
2760 } \
2761 }
2762VSHIFT(l, LEFT)
2763VSHIFT(r, RIGHT)
2764#undef VSHIFT
2765#undef LEFT
2766#undef RIGHT
2767
d79f0809 2768#define VSL(suffix, element) \
c227f099 2769 void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
d79f0809
AJ
2770 { \
2771 int i; \
2772 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2773 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2774 unsigned int shift = b->element[i] & mask; \
2775 r->element[i] = a->element[i] << shift; \
2776 } \
2777 }
2778VSL(b, u8)
2779VSL(h, u16)
2780VSL(w, u32)
2781#undef VSL
2782
c227f099 2783void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
cd633b10
AJ
2784{
2785 int sh = shift & 0xf;
2786 int i;
c227f099 2787 ppc_avr_t result;
cd633b10 2788
e2542fe2 2789#if defined(HOST_WORDS_BIGENDIAN)
cd633b10
AJ
2790 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2791 int index = sh + i;
2792 if (index > 0xf) {
2793 result.u8[i] = b->u8[index-0x10];
2794 } else {
2795 result.u8[i] = a->u8[index];
2796 }
2797 }
2798#else
2799 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2800 int index = (16 - sh) + i;
2801 if (index > 0xf) {
2802 result.u8[i] = a->u8[index-0x10];
2803 } else {
2804 result.u8[i] = b->u8[index];
2805 }
2806 }
2807#endif
2808 *r = result;
2809}
2810
c227f099 2811void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
7b239bec
AJ
2812{
2813 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2814
e2542fe2 2815#if defined (HOST_WORDS_BIGENDIAN)
7b239bec
AJ
2816 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2817 memset (&r->u8[16-sh], 0, sh);
2818#else
2819 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2820 memset (&r->u8[0], 0, sh);
2821#endif
2822}
2823
e4e6bee7
AJ
2824/* Experimental testing shows that hardware masks the immediate. */
2825#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
e2542fe2 2826#if defined(HOST_WORDS_BIGENDIAN)
e4e6bee7
AJ
2827#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2828#else
2829#define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
2830#endif
2831#define VSPLT(suffix, element) \
c227f099 2832 void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
e4e6bee7
AJ
2833 { \
2834 uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
2835 int i; \
2836 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2837 r->element[i] = s; \
2838 } \
2839 }
2840VSPLT(b, u8)
2841VSPLT(h, u16)
2842VSPLT(w, u32)
2843#undef VSPLT
2844#undef SPLAT_ELEMENT
2845#undef _SPLAT_MASKED
2846
c026766b 2847#define VSPLTI(suffix, element, splat_type) \
c227f099 2848 void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat) \
c026766b
AJ
2849 { \
2850 splat_type x = (int8_t)(splat << 3) >> 3; \
2851 int i; \
2852 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2853 r->element[i] = x; \
2854 } \
2855 }
2856VSPLTI(b, s8, int8_t)
2857VSPLTI(h, s16, int16_t)
2858VSPLTI(w, s32, int32_t)
2859#undef VSPLTI
2860
07ef34c3 2861#define VSR(suffix, element) \
c227f099 2862 void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
07ef34c3
AJ
2863 { \
2864 int i; \
2865 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2866 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2867 unsigned int shift = b->element[i] & mask; \
2868 r->element[i] = a->element[i] >> shift; \
2869 } \
2870 }
2871VSR(ab, s8)
2872VSR(ah, s16)
2873VSR(aw, s32)
2874VSR(b, u8)
2875VSR(h, u16)
2876VSR(w, u32)
2877#undef VSR
2878
c227f099 2879void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
7b239bec
AJ
2880{
2881 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2882
e2542fe2 2883#if defined (HOST_WORDS_BIGENDIAN)
7b239bec
AJ
2884 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2885 memset (&r->u8[0], 0, sh);
2886#else
2887 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2888 memset (&r->u8[16-sh], 0, sh);
2889#endif
2890}
2891
c227f099 2892void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
e343da72
AJ
2893{
2894 int i;
2895 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2896 r->u32[i] = a->u32[i] >= b->u32[i];
2897 }
2898}
2899
c227f099 2900void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
8142cddd
AJ
2901{
2902 int64_t t;
2903 int i, upper;
c227f099 2904 ppc_avr_t result;
8142cddd
AJ
2905 int sat = 0;
2906
e2542fe2 2907#if defined(HOST_WORDS_BIGENDIAN)
8142cddd
AJ
2908 upper = ARRAY_SIZE(r->s32)-1;
2909#else
2910 upper = 0;
2911#endif
2912 t = (int64_t)b->s32[upper];
2913 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2914 t += a->s32[i];
2915 result.s32[i] = 0;
2916 }
2917 result.s32[upper] = cvtsdsw(t, &sat);
2918 *r = result;
2919
2920 if (sat) {
2921 env->vscr |= (1 << VSCR_SAT);
2922 }
2923}
2924
c227f099 2925void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
8142cddd
AJ
2926{
2927 int i, j, upper;
c227f099 2928 ppc_avr_t result;
8142cddd
AJ
2929 int sat = 0;
2930
e2542fe2 2931#if defined(HOST_WORDS_BIGENDIAN)
8142cddd
AJ
2932 upper = 1;
2933#else
2934 upper = 0;
2935#endif
2936 for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
2937 int64_t t = (int64_t)b->s32[upper+i*2];
2938 result.u64[i] = 0;
2939 for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
2940 t += a->s32[2*i+j];
2941 }
2942 result.s32[upper+i*2] = cvtsdsw(t, &sat);
2943 }
2944
2945 *r = result;
2946 if (sat) {
2947 env->vscr |= (1 << VSCR_SAT);
2948 }
2949}
2950
c227f099 2951void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
8142cddd
AJ
2952{
2953 int i, j;
2954 int sat = 0;
2955
2956 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2957 int64_t t = (int64_t)b->s32[i];
2958 for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
2959 t += a->s8[4*i+j];
2960 }
2961 r->s32[i] = cvtsdsw(t, &sat);
2962 }
2963
2964 if (sat) {
2965 env->vscr |= (1 << VSCR_SAT);
2966 }
2967}
2968
c227f099 2969void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
8142cddd
AJ
2970{
2971 int sat = 0;
2972 int i;
2973
2974 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2975 int64_t t = (int64_t)b->s32[i];
2976 t += a->s16[2*i] + a->s16[2*i+1];
2977 r->s32[i] = cvtsdsw(t, &sat);
2978 }
2979
2980 if (sat) {
2981 env->vscr |= (1 << VSCR_SAT);
2982 }
2983}
2984
c227f099 2985void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
8142cddd
AJ
2986{
2987 int i, j;
2988 int sat = 0;
2989
2990 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2991 uint64_t t = (uint64_t)b->u32[i];
2992 for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
2993 t += a->u8[4*i+j];
2994 }
2995 r->u32[i] = cvtuduw(t, &sat);
2996 }
2997
2998 if (sat) {
2999 env->vscr |= (1 << VSCR_SAT);
3000 }
3001}
3002
e2542fe2 3003#if defined(HOST_WORDS_BIGENDIAN)
79f85c3a
AJ
3004#define UPKHI 1
3005#define UPKLO 0
3006#else
3007#define UPKHI 0
3008#define UPKLO 1
3009#endif
3010#define VUPKPX(suffix, hi) \
c227f099 3011 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
79f85c3a
AJ
3012 { \
3013 int i; \
c227f099 3014 ppc_avr_t result; \
79f85c3a
AJ
3015 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
3016 uint16_t e = b->u16[hi ? i : i+4]; \
3017 uint8_t a = (e >> 15) ? 0xff : 0; \
3018 uint8_t r = (e >> 10) & 0x1f; \
3019 uint8_t g = (e >> 5) & 0x1f; \
3020 uint8_t b = e & 0x1f; \
3021 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
3022 } \
3023 *r = result; \
3024 }
3025VUPKPX(lpx, UPKLO)
3026VUPKPX(hpx, UPKHI)
3027#undef VUPKPX
3028
6cf1c6e5 3029#define VUPK(suffix, unpacked, packee, hi) \
c227f099 3030 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
6cf1c6e5
AJ
3031 { \
3032 int i; \
c227f099 3033 ppc_avr_t result; \
6cf1c6e5
AJ
3034 if (hi) { \
3035 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
3036 result.unpacked[i] = b->packee[i]; \
3037 } \
3038 } else { \
3039 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
3040 result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
3041 } \
3042 } \
3043 *r = result; \
3044 }
3045VUPK(hsb, s16, s8, UPKHI)
3046VUPK(hsh, s32, s16, UPKHI)
3047VUPK(lsb, s16, s8, UPKLO)
3048VUPK(lsh, s32, s16, UPKLO)
3049#undef VUPK
79f85c3a
AJ
3050#undef UPKHI
3051#undef UPKLO
3052
34ba2857
AJ
3053#undef DO_HANDLE_NAN
3054#undef HANDLE_NAN1
3055#undef HANDLE_NAN2
3056#undef HANDLE_NAN3
d6a46fe8
AJ
3057#undef VECTOR_FOR_INORDER_I
3058#undef HI_IDX
3059#undef LO_IDX
3060
1c97856d 3061/*****************************************************************************/
0487d6a8
JM
3062/* SPE extension helpers */
3063/* Use a table to make this quicker */
3064static uint8_t hbrev[16] = {
3065 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
3066 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
3067};
3068
636aa200 3069static inline uint8_t byte_reverse(uint8_t val)
0487d6a8
JM
3070{
3071 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
3072}
3073
636aa200 3074static inline uint32_t word_reverse(uint32_t val)
0487d6a8
JM
3075{
3076 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
3077 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
3078}
3079
3cd7d1dd 3080#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
57951c27 3081target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
0487d6a8
JM
3082{
3083 uint32_t a, b, d, mask;
3084
3cd7d1dd 3085 mask = UINT32_MAX >> (32 - MASKBITS);
57951c27
AJ
3086 a = arg1 & mask;
3087 b = arg2 & mask;
3cd7d1dd 3088 d = word_reverse(1 + word_reverse(a | ~b));
57951c27 3089 return (arg1 & ~mask) | (d & b);
0487d6a8
JM
3090}
3091
57951c27 3092uint32_t helper_cntlsw32 (uint32_t val)
0487d6a8
JM
3093{
3094 if (val & 0x80000000)
603fccce 3095 return clz32(~val);
0487d6a8 3096 else
603fccce 3097 return clz32(val);
0487d6a8
JM
3098}
3099
57951c27 3100uint32_t helper_cntlzw32 (uint32_t val)
0487d6a8 3101{
603fccce 3102 return clz32(val);
0487d6a8
JM
3103}
3104
1c97856d 3105/* Single-precision floating-point conversions */
636aa200 3106static inline uint32_t efscfsi(uint32_t val)
0487d6a8 3107{
0ca9d380 3108 CPU_FloatU u;
0487d6a8 3109
fbd265b6 3110 u.f = int32_to_float32(val, &env->vec_status);
0487d6a8 3111
0ca9d380 3112 return u.l;
0487d6a8
JM
3113}
3114
636aa200 3115static inline uint32_t efscfui(uint32_t val)
0487d6a8 3116{
0ca9d380 3117 CPU_FloatU u;
0487d6a8 3118
fbd265b6 3119 u.f = uint32_to_float32(val, &env->vec_status);
0487d6a8 3120
0ca9d380 3121 return u.l;
0487d6a8
JM
3122}
3123
636aa200 3124static inline int32_t efsctsi(uint32_t val)
0487d6a8 3125{
0ca9d380 3126 CPU_FloatU u;
0487d6a8 3127
0ca9d380 3128 u.l = val;
0487d6a8 3129 /* NaN are not treated the same way IEEE 754 does */
18569871 3130 if (unlikely(float32_is_quiet_nan(u.f)))
0487d6a8
JM
3131 return 0;
3132
fbd265b6 3133 return float32_to_int32(u.f, &env->vec_status);
0487d6a8
JM
3134}
3135
636aa200 3136static inline uint32_t efsctui(uint32_t val)
0487d6a8 3137{
0ca9d380 3138 CPU_FloatU u;
0487d6a8 3139
0ca9d380 3140 u.l = val;
0487d6a8 3141 /* NaN are not treated the same way IEEE 754 does */
18569871 3142 if (unlikely(float32_is_quiet_nan(u.f)))
0487d6a8
JM
3143 return 0;
3144
fbd265b6 3145 return float32_to_uint32(u.f, &env->vec_status);
0487d6a8
JM
3146}
3147
636aa200 3148static inline uint32_t efsctsiz(uint32_t val)
0487d6a8 3149{
0ca9d380 3150 CPU_FloatU u;
0487d6a8 3151
0ca9d380 3152 u.l = val;
0487d6a8 3153 /* NaN are not treated the same way IEEE 754 does */
18569871 3154 if (unlikely(float32_is_quiet_nan(u.f)))
0487d6a8
JM
3155 return 0;
3156
fbd265b6 3157 return float32_to_int32_round_to_zero(u.f, &env->vec_status);
0487d6a8
JM
3158}
3159
636aa200 3160static inline uint32_t efsctuiz(uint32_t val)
0487d6a8 3161{
0ca9d380 3162 CPU_FloatU u;
0487d6a8 3163
0ca9d380 3164 u.l = val;
0487d6a8 3165 /* NaN are not treated the same way IEEE 754 does */
18569871 3166 if (unlikely(float32_is_quiet_nan(u.f)))
0487d6a8
JM
3167 return 0;
3168
fbd265b6 3169 return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
0487d6a8
JM
3170}
3171
636aa200 3172static inline uint32_t efscfsf(uint32_t val)
0487d6a8 3173{
0ca9d380 3174 CPU_FloatU u;
0487d6a8
JM
3175 float32 tmp;
3176
fbd265b6
AJ
3177 u.f = int32_to_float32(val, &env->vec_status);
3178 tmp = int64_to_float32(1ULL << 32, &env->vec_status);
3179 u.f = float32_div(u.f, tmp, &env->vec_status);
0487d6a8 3180
0ca9d380 3181 return u.l;
0487d6a8
JM
3182}
3183
636aa200 3184static inline uint32_t efscfuf(uint32_t val)
0487d6a8 3185{
0ca9d380 3186 CPU_FloatU u;
0487d6a8
JM
3187 float32 tmp;
3188
fbd265b6
AJ
3189 u.f = uint32_to_float32(val, &env->vec_status);
3190 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3191 u.f = float32_div(u.f, tmp, &env->vec_status);
0487d6a8 3192
0ca9d380 3193 return u.l;
0487d6a8
JM
3194}
3195
636aa200 3196static inline uint32_t efsctsf(uint32_t val)
0487d6a8 3197{
0ca9d380 3198 CPU_FloatU u;
0487d6a8
JM
3199 float32 tmp;
3200
0ca9d380 3201 u.l = val;
0487d6a8 3202 /* NaN are not treated the same way IEEE 754 does */
18569871 3203 if (unlikely(float32_is_quiet_nan(u.f)))
0487d6a8 3204 return 0;
fbd265b6
AJ
3205 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3206 u.f = float32_mul(u.f, tmp, &env->vec_status);
0487d6a8 3207
fbd265b6 3208 return float32_to_int32(u.f, &env->vec_status);
0487d6a8
JM
3209}
3210
636aa200 3211static inline uint32_t efsctuf(uint32_t val)
0487d6a8 3212{
0ca9d380 3213 CPU_FloatU u;
0487d6a8
JM
3214 float32 tmp;
3215
0ca9d380 3216 u.l = val;
0487d6a8 3217 /* NaN are not treated the same way IEEE 754 does */
18569871 3218 if (unlikely(float32_is_quiet_nan(u.f)))
0487d6a8 3219 return 0;
fbd265b6
AJ
3220 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3221 u.f = float32_mul(u.f, tmp, &env->vec_status);
0487d6a8 3222
fbd265b6 3223 return float32_to_uint32(u.f, &env->vec_status);
0487d6a8
JM
3224}
3225
1c97856d
AJ
3226#define HELPER_SPE_SINGLE_CONV(name) \
3227uint32_t helper_e##name (uint32_t val) \
3228{ \
3229 return e##name(val); \
3230}
3231/* efscfsi */
3232HELPER_SPE_SINGLE_CONV(fscfsi);
3233/* efscfui */
3234HELPER_SPE_SINGLE_CONV(fscfui);
3235/* efscfuf */
3236HELPER_SPE_SINGLE_CONV(fscfuf);
3237/* efscfsf */
3238HELPER_SPE_SINGLE_CONV(fscfsf);
3239/* efsctsi */
3240HELPER_SPE_SINGLE_CONV(fsctsi);
3241/* efsctui */
3242HELPER_SPE_SINGLE_CONV(fsctui);
3243/* efsctsiz */
3244HELPER_SPE_SINGLE_CONV(fsctsiz);
3245/* efsctuiz */
3246HELPER_SPE_SINGLE_CONV(fsctuiz);
3247/* efsctsf */
3248HELPER_SPE_SINGLE_CONV(fsctsf);
3249/* efsctuf */
3250HELPER_SPE_SINGLE_CONV(fsctuf);
3251
3252#define HELPER_SPE_VECTOR_CONV(name) \
3253uint64_t helper_ev##name (uint64_t val) \
3254{ \
3255 return ((uint64_t)e##name(val >> 32) << 32) | \
3256 (uint64_t)e##name(val); \
0487d6a8 3257}
1c97856d
AJ
3258/* evfscfsi */
3259HELPER_SPE_VECTOR_CONV(fscfsi);
3260/* evfscfui */
3261HELPER_SPE_VECTOR_CONV(fscfui);
3262/* evfscfuf */
3263HELPER_SPE_VECTOR_CONV(fscfuf);
3264/* evfscfsf */
3265HELPER_SPE_VECTOR_CONV(fscfsf);
3266/* evfsctsi */
3267HELPER_SPE_VECTOR_CONV(fsctsi);
3268/* evfsctui */
3269HELPER_SPE_VECTOR_CONV(fsctui);
3270/* evfsctsiz */
3271HELPER_SPE_VECTOR_CONV(fsctsiz);
3272/* evfsctuiz */
3273HELPER_SPE_VECTOR_CONV(fsctuiz);
3274/* evfsctsf */
3275HELPER_SPE_VECTOR_CONV(fsctsf);
3276/* evfsctuf */
3277HELPER_SPE_VECTOR_CONV(fsctuf);
0487d6a8 3278
1c97856d 3279/* Single-precision floating-point arithmetic */
636aa200 3280static inline uint32_t efsadd(uint32_t op1, uint32_t op2)
0487d6a8 3281{
1c97856d
AJ
3282 CPU_FloatU u1, u2;
3283 u1.l = op1;
3284 u2.l = op2;
fbd265b6 3285 u1.f = float32_add(u1.f, u2.f, &env->vec_status);
1c97856d 3286 return u1.l;
0487d6a8
JM
3287}
3288
636aa200 3289static inline uint32_t efssub(uint32_t op1, uint32_t op2)
0487d6a8 3290{
1c97856d
AJ
3291 CPU_FloatU u1, u2;
3292 u1.l = op1;
3293 u2.l = op2;
fbd265b6 3294 u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
1c97856d 3295 return u1.l;
0487d6a8
JM
3296}
3297
636aa200 3298static inline uint32_t efsmul(uint32_t op1, uint32_t op2)
0487d6a8 3299{
1c97856d
AJ
3300 CPU_FloatU u1, u2;
3301 u1.l = op1;
3302 u2.l = op2;
fbd265b6 3303 u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
1c97856d 3304 return u1.l;
0487d6a8
JM
3305}
3306
636aa200 3307static inline uint32_t efsdiv(uint32_t op1, uint32_t op2)
0487d6a8 3308{
1c97856d
AJ
3309 CPU_FloatU u1, u2;
3310 u1.l = op1;
3311 u2.l = op2;
fbd265b6 3312 u1.f = float32_div(u1.f, u2.f, &env->vec_status);
1c97856d 3313 return u1.l;
0487d6a8
JM
3314}
3315
1c97856d
AJ
3316#define HELPER_SPE_SINGLE_ARITH(name) \
3317uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
3318{ \
3319 return e##name(op1, op2); \
3320}
3321/* efsadd */
3322HELPER_SPE_SINGLE_ARITH(fsadd);
3323/* efssub */
3324HELPER_SPE_SINGLE_ARITH(fssub);
3325/* efsmul */
3326HELPER_SPE_SINGLE_ARITH(fsmul);
3327/* efsdiv */
3328HELPER_SPE_SINGLE_ARITH(fsdiv);
3329
3330#define HELPER_SPE_VECTOR_ARITH(name) \
3331uint64_t helper_ev##name (uint64_t op1, uint64_t op2) \
3332{ \
3333 return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
3334 (uint64_t)e##name(op1, op2); \
3335}
3336/* evfsadd */
3337HELPER_SPE_VECTOR_ARITH(fsadd);
3338/* evfssub */
3339HELPER_SPE_VECTOR_ARITH(fssub);
3340/* evfsmul */
3341HELPER_SPE_VECTOR_ARITH(fsmul);
3342/* evfsdiv */
3343HELPER_SPE_VECTOR_ARITH(fsdiv);
3344
3345/* Single-precision floating-point comparisons */
019702c8 3346static inline uint32_t efscmplt(uint32_t op1, uint32_t op2)
0487d6a8 3347{
1c97856d
AJ
3348 CPU_FloatU u1, u2;
3349 u1.l = op1;
3350 u2.l = op2;
fbd265b6 3351 return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
0487d6a8
JM
3352}
3353
019702c8 3354static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2)
0487d6a8 3355{
1c97856d
AJ
3356 CPU_FloatU u1, u2;
3357 u1.l = op1;
3358 u2.l = op2;
fbd265b6 3359 return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
0487d6a8
JM
3360}
3361
019702c8 3362static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2)
0487d6a8 3363{
1c97856d
AJ
3364 CPU_FloatU u1, u2;
3365 u1.l = op1;
3366 u2.l = op2;
019702c8 3367 return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
0487d6a8
JM
3368}
3369
019702c8 3370static inline uint32_t efststlt(uint32_t op1, uint32_t op2)
0487d6a8 3371{
019702c8
AJ
3372 /* XXX: TODO: ignore special values (NaN, infinites, ...) */
3373 return efscmplt(op1, op2);
0487d6a8
JM
3374}
3375
019702c8 3376static inline uint32_t efststgt(uint32_t op1, uint32_t op2)
0487d6a8 3377{
019702c8
AJ
3378 /* XXX: TODO: ignore special values (NaN, infinites, ...) */
3379 return efscmpgt(op1, op2);
0487d6a8
JM
3380}
3381
019702c8 3382static inline uint32_t efststeq(uint32_t op1, uint32_t op2)
0487d6a8 3383{
019702c8
AJ
3384 /* XXX: TODO: ignore special values (NaN, infinites, ...) */
3385 return efscmpeq(op1, op2);
0487d6a8
JM
3386}
3387
1c97856d
AJ
3388#define HELPER_SINGLE_SPE_CMP(name) \
3389uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
3390{ \
3391 return e##name(op1, op2) << 2; \
3392}
3393/* efststlt */
3394HELPER_SINGLE_SPE_CMP(fststlt);
3395/* efststgt */
3396HELPER_SINGLE_SPE_CMP(fststgt);
3397/* efststeq */
3398HELPER_SINGLE_SPE_CMP(fststeq);
3399/* efscmplt */
3400HELPER_SINGLE_SPE_CMP(fscmplt);
3401/* efscmpgt */
3402HELPER_SINGLE_SPE_CMP(fscmpgt);
3403/* efscmpeq */
3404HELPER_SINGLE_SPE_CMP(fscmpeq);
3405
636aa200 3406static inline uint32_t evcmp_merge(int t0, int t1)
0487d6a8 3407{
1c97856d 3408 return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
0487d6a8
JM
3409}
3410
1c97856d
AJ
3411#define HELPER_VECTOR_SPE_CMP(name) \
3412uint32_t helper_ev##name (uint64_t op1, uint64_t op2) \
3413{ \
3414 return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
0487d6a8 3415}
1c97856d
AJ
3416/* evfststlt */
3417HELPER_VECTOR_SPE_CMP(fststlt);
3418/* evfststgt */
3419HELPER_VECTOR_SPE_CMP(fststgt);
3420/* evfststeq */
3421HELPER_VECTOR_SPE_CMP(fststeq);
3422/* evfscmplt */
3423HELPER_VECTOR_SPE_CMP(fscmplt);
3424/* evfscmpgt */
3425HELPER_VECTOR_SPE_CMP(fscmpgt);
3426/* evfscmpeq */
3427HELPER_VECTOR_SPE_CMP(fscmpeq);
0487d6a8 3428
1c97856d
AJ
3429/* Double-precision floating-point conversion */
3430uint64_t helper_efdcfsi (uint32_t val)
0487d6a8 3431{
1c97856d
AJ
3432 CPU_DoubleU u;
3433
fbd265b6 3434 u.d = int32_to_float64(val, &env->vec_status);
1c97856d
AJ
3435
3436 return u.ll;
0487d6a8
JM
3437}
3438
1c97856d 3439uint64_t helper_efdcfsid (uint64_t val)
0487d6a8 3440{
0ca9d380 3441 CPU_DoubleU u;
0487d6a8 3442
fbd265b6 3443 u.d = int64_to_float64(val, &env->vec_status);
0487d6a8 3444
0ca9d380 3445 return u.ll;
0487d6a8
JM
3446}
3447
1c97856d
AJ
3448uint64_t helper_efdcfui (uint32_t val)
3449{
3450 CPU_DoubleU u;
3451
fbd265b6 3452 u.d = uint32_to_float64(val, &env->vec_status);
1c97856d
AJ
3453
3454 return u.ll;
3455}
3456
3457uint64_t helper_efdcfuid (uint64_t val)
0487d6a8 3458{
0ca9d380 3459 CPU_DoubleU u;
0487d6a8 3460
fbd265b6 3461 u.d = uint64_to_float64(val, &env->vec_status);
0487d6a8 3462
0ca9d380 3463 return u.ll;
0487d6a8
JM
3464}
3465
1c97856d 3466uint32_t helper_efdctsi (uint64_t val)
0487d6a8 3467{
0ca9d380 3468 CPU_DoubleU u;
0487d6a8 3469
0ca9d380 3470 u.ll = val;
0487d6a8 3471 /* NaN are not treated the same way IEEE 754 does */
d788b570 3472 if (unlikely(float64_is_any_nan(u.d))) {
0487d6a8 3473 return 0;
d788b570 3474 }
0487d6a8 3475
fbd265b6 3476 return float64_to_int32(u.d, &env->vec_status);
0487d6a8
JM
3477}
3478
1c97856d 3479uint32_t helper_efdctui (uint64_t val)
0487d6a8 3480{
0ca9d380 3481 CPU_DoubleU u;
0487d6a8 3482
0ca9d380 3483 u.ll = val;
0487d6a8 3484 /* NaN are not treated the same way IEEE 754 does */
d788b570 3485 if (unlikely(float64_is_any_nan(u.d))) {
0487d6a8 3486 return 0;
d788b570 3487 }
0487d6a8 3488
fbd265b6 3489 return float64_to_uint32(u.d, &env->vec_status);
0487d6a8
JM
3490}
3491
1c97856d 3492uint32_t helper_efdctsiz (uint64_t val)
0487d6a8 3493{
0ca9d380 3494 CPU_DoubleU u;
0487d6a8 3495
0ca9d380 3496 u.ll = val;
0487d6a8 3497 /* NaN are not treated the same way IEEE 754 does */
d788b570 3498 if (unlikely(float64_is_any_nan(u.d))) {
0487d6a8 3499 return 0;
d788b570 3500 }
0487d6a8 3501
fbd265b6 3502 return float64_to_int32_round_to_zero(u.d, &env->vec_status);
0487d6a8
JM
3503}
3504
1c97856d 3505uint64_t helper_efdctsidz (uint64_t val)
0487d6a8 3506{
0ca9d380 3507 CPU_DoubleU u;
0487d6a8 3508
0ca9d380 3509 u.ll = val;
0487d6a8 3510 /* NaN are not treated the same way IEEE 754 does */
d788b570 3511 if (unlikely(float64_is_any_nan(u.d))) {
0487d6a8 3512 return 0;
d788b570 3513 }
0487d6a8 3514
fbd265b6 3515 return float64_to_int64_round_to_zero(u.d, &env->vec_status);
0487d6a8
JM
3516}
3517
1c97856d 3518uint32_t helper_efdctuiz (uint64_t val)
0487d6a8 3519{
1c97856d 3520 CPU_DoubleU u;
0487d6a8 3521
1c97856d
AJ
3522 u.ll = val;
3523 /* NaN are not treated the same way IEEE 754 does */
d788b570 3524 if (unlikely(float64_is_any_nan(u.d))) {
1c97856d 3525 return 0;
d788b570 3526 }
0487d6a8 3527
fbd265b6 3528 return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
0487d6a8
JM
3529}
3530
1c97856d 3531uint64_t helper_efdctuidz (uint64_t val)
0487d6a8 3532{
1c97856d 3533 CPU_DoubleU u;
0487d6a8 3534
1c97856d
AJ
3535 u.ll = val;
3536 /* NaN are not treated the same way IEEE 754 does */
d788b570 3537 if (unlikely(float64_is_any_nan(u.d))) {
1c97856d 3538 return 0;
d788b570 3539 }
0487d6a8 3540
fbd265b6 3541 return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
0487d6a8
JM
3542}
3543
1c97856d 3544uint64_t helper_efdcfsf (uint32_t val)
0487d6a8 3545{
0ca9d380 3546 CPU_DoubleU u;
0487d6a8
JM
3547 float64 tmp;
3548
fbd265b6
AJ
3549 u.d = int32_to_float64(val, &env->vec_status);
3550 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3551 u.d = float64_div(u.d, tmp, &env->vec_status);
0487d6a8 3552
0ca9d380 3553 return u.ll;
0487d6a8
JM
3554}
3555
1c97856d 3556uint64_t helper_efdcfuf (uint32_t val)
0487d6a8 3557{
0ca9d380 3558 CPU_DoubleU u;
0487d6a8
JM
3559 float64 tmp;
3560
fbd265b6
AJ
3561 u.d = uint32_to_float64(val, &env->vec_status);
3562 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3563 u.d = float64_div(u.d, tmp, &env->vec_status);
0487d6a8 3564
0ca9d380 3565 return u.ll;
0487d6a8
JM
3566}
3567
1c97856d 3568uint32_t helper_efdctsf (uint64_t val)
0487d6a8 3569{
0ca9d380 3570 CPU_DoubleU u;
0487d6a8
JM
3571 float64 tmp;
3572
0ca9d380 3573 u.ll = val;
0487d6a8 3574 /* NaN are not treated the same way IEEE 754 does */
d788b570 3575 if (unlikely(float64_is_any_nan(u.d))) {
0487d6a8 3576 return 0;
d788b570 3577 }
fbd265b6
AJ
3578 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3579 u.d = float64_mul(u.d, tmp, &env->vec_status);
0487d6a8 3580
fbd265b6 3581 return float64_to_int32(u.d, &env->vec_status);
0487d6a8
JM
3582}
3583
1c97856d 3584uint32_t helper_efdctuf (uint64_t val)
0487d6a8 3585{
0ca9d380 3586 CPU_DoubleU u;
0487d6a8
JM
3587 float64 tmp;
3588
0ca9d380 3589 u.ll = val;
0487d6a8 3590 /* NaN are not treated the same way IEEE 754 does */
d788b570 3591 if (unlikely(float64_is_any_nan(u.d))) {
0487d6a8 3592 return 0;
d788b570 3593 }
fbd265b6
AJ
3594 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3595 u.d = float64_mul(u.d, tmp, &env->vec_status);
0487d6a8 3596
fbd265b6 3597 return float64_to_uint32(u.d, &env->vec_status);
0487d6a8
JM
3598}
3599
1c97856d 3600uint32_t helper_efscfd (uint64_t val)
0487d6a8 3601{
0ca9d380
AJ
3602 CPU_DoubleU u1;
3603 CPU_FloatU u2;
0487d6a8 3604
0ca9d380 3605 u1.ll = val;
fbd265b6 3606 u2.f = float64_to_float32(u1.d, &env->vec_status);
0487d6a8 3607
0ca9d380 3608 return u2.l;
0487d6a8
JM
3609}
3610
1c97856d 3611uint64_t helper_efdcfs (uint32_t val)
0487d6a8 3612{
0ca9d380
AJ
3613 CPU_DoubleU u2;
3614 CPU_FloatU u1;
0487d6a8 3615
0ca9d380 3616 u1.l = val;
fbd265b6 3617 u2.d = float32_to_float64(u1.f, &env->vec_status);
0487d6a8 3618
0ca9d380 3619 return u2.ll;
0487d6a8
JM
3620}
3621
1c97856d
AJ
3622/* Double precision fixed-point arithmetic */
3623uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
0487d6a8 3624{
1c97856d
AJ
3625 CPU_DoubleU u1, u2;
3626 u1.ll = op1;
3627 u2.ll = op2;
fbd265b6 3628 u1.d = float64_add(u1.d, u2.d, &env->vec_status);
1c97856d 3629 return u1.ll;
0487d6a8
JM
3630}
3631
1c97856d 3632uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
0487d6a8 3633{
1c97856d
AJ
3634 CPU_DoubleU u1, u2;
3635 u1.ll = op1;
3636 u2.ll = op2;
fbd265b6 3637 u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
1c97856d 3638 return u1.ll;
0487d6a8
JM
3639}
3640
1c97856d 3641uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
0487d6a8 3642{
1c97856d
AJ
3643 CPU_DoubleU u1, u2;
3644 u1.ll = op1;
3645 u2.ll = op2;
fbd265b6 3646 u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
1c97856d 3647 return u1.ll;
0487d6a8
JM
3648}
3649
1c97856d 3650uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
0487d6a8 3651{
1c97856d
AJ
3652 CPU_DoubleU u1, u2;
3653 u1.ll = op1;
3654 u2.ll = op2;
fbd265b6 3655 u1.d = float64_div(u1.d, u2.d, &env->vec_status);
1c97856d 3656 return u1.ll;
0487d6a8
JM
3657}
3658
1c97856d
AJ
3659/* Double precision floating point helpers */
3660uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
0487d6a8 3661{
1c97856d
AJ
3662 CPU_DoubleU u1, u2;
3663 u1.ll = op1;
3664 u2.ll = op2;
fbd265b6 3665 return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
0487d6a8
JM
3666}
3667
1c97856d 3668uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
0487d6a8 3669{
1c97856d
AJ
3670 CPU_DoubleU u1, u2;
3671 u1.ll = op1;
3672 u2.ll = op2;
fbd265b6 3673 return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
0487d6a8
JM
3674}
3675
1c97856d 3676uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
0487d6a8 3677{
1c97856d
AJ
3678 CPU_DoubleU u1, u2;
3679 u1.ll = op1;
3680 u2.ll = op2;
211315fb 3681 return float64_eq_quiet(u1.d, u2.d, &env->vec_status) ? 4 : 0;
0487d6a8
JM
3682}
3683
1c97856d 3684uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
0487d6a8 3685{
1c97856d
AJ
3686 /* XXX: TODO: test special values (NaN, infinites, ...) */
3687 return helper_efdtstlt(op1, op2);
0487d6a8
JM
3688}
3689
1c97856d
AJ
3690uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
3691{
3692 /* XXX: TODO: test special values (NaN, infinites, ...) */
3693 return helper_efdtstgt(op1, op2);
3694}
0487d6a8 3695
1c97856d
AJ
3696uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
3697{
3698 /* XXX: TODO: test special values (NaN, infinites, ...) */
3699 return helper_efdtsteq(op1, op2);
3700}
0487d6a8 3701
fdabc366
FB
3702/*****************************************************************************/
3703/* Softmmu support */
3704#if !defined (CONFIG_USER_ONLY)
3705
3706#define MMUSUFFIX _mmu
fdabc366
FB
3707
3708#define SHIFT 0
3709#include "softmmu_template.h"
3710
3711#define SHIFT 1
3712#include "softmmu_template.h"
3713
3714#define SHIFT 2
3715#include "softmmu_template.h"
3716
3717#define SHIFT 3
3718#include "softmmu_template.h"
3719
3720/* try to fill the TLB and return an exception if error. If retaddr is
3721 NULL, it means that the function was called in C code (i.e. not
3722 from generated code or from helper.c) */
3723/* XXX: fix it to restore all registers */
6ebbf390 3724void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
fdabc366
FB
3725{
3726 TranslationBlock *tb;
3727 CPUState *saved_env;
44f8625d 3728 unsigned long pc;
fdabc366
FB
3729 int ret;
3730
3731 /* XXX: hack to restore env in all cases, even if not called from
3732 generated code */
3733 saved_env = env;
3734 env = cpu_single_env;
6ebbf390 3735 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
76a66253 3736 if (unlikely(ret != 0)) {
fdabc366
FB
3737 if (likely(retaddr)) {
3738 /* now we have a real cpu fault */
44f8625d 3739 pc = (unsigned long)retaddr;
fdabc366
FB
3740 tb = tb_find_pc(pc);
3741 if (likely(tb)) {
3742 /* the PC is inside the translated code. It means that we have
3743 a virtual CPU fault */
618ba8e6 3744 cpu_restore_state(tb, env, pc);
76a66253 3745 }
fdabc366 3746 }
e06fcd75 3747 helper_raise_exception_err(env->exception_index, env->error_code);
fdabc366
FB
3748 }
3749 env = saved_env;
9a64fbe4
FB
3750}
3751
74d37793
AJ
3752/* Segment registers load and store */
3753target_ulong helper_load_sr (target_ulong sr_num)
3754{
f6b868fc
BS
3755#if defined(TARGET_PPC64)
3756 if (env->mmu_model & POWERPC_MMU_64)
3757 return ppc_load_sr(env, sr_num);
3758#endif
74d37793
AJ
3759 return env->sr[sr_num];
3760}
3761
3762void helper_store_sr (target_ulong sr_num, target_ulong val)
3763{
45d827d2 3764 ppc_store_sr(env, sr_num, val);
74d37793
AJ
3765}
3766
3767/* SLB management */
3768#if defined(TARGET_PPC64)
f6b868fc 3769void helper_store_slb (target_ulong rb, target_ulong rs)
74d37793 3770{
81762d6d
DG
3771 if (ppc_store_slb(env, rb, rs) < 0) {
3772 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
3773 }
74d37793
AJ
3774}
3775
efdef95f
DG
3776target_ulong helper_load_slb_esid (target_ulong rb)
3777{
3778 target_ulong rt;
3779
3780 if (ppc_load_slb_esid(env, rb, &rt) < 0) {
3781 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
3782 }
3783 return rt;
3784}
3785
3786target_ulong helper_load_slb_vsid (target_ulong rb)
3787{
3788 target_ulong rt;
3789
3790 if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
3791 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_INVAL);
3792 }
3793 return rt;
3794}
3795
74d37793
AJ
3796void helper_slbia (void)
3797{
3798 ppc_slb_invalidate_all(env);
3799}
3800
3801void helper_slbie (target_ulong addr)
3802{
3803 ppc_slb_invalidate_one(env, addr);
3804}
3805
3806#endif /* defined(TARGET_PPC64) */
3807
3808/* TLB management */
3809void helper_tlbia (void)
3810{
3811 ppc_tlb_invalidate_all(env);
3812}
3813
3814void helper_tlbie (target_ulong addr)
3815{
3816 ppc_tlb_invalidate_one(env, addr);
3817}
3818
76a66253
JM
3819/* Software driven TLBs management */
3820/* PowerPC 602/603 software TLB load instructions helpers */
74d37793 3821static void do_6xx_tlb (target_ulong new_EPN, int is_code)
76a66253
JM
3822{
3823 target_ulong RPN, CMP, EPN;
3824 int way;
d9bce9d9 3825
76a66253
JM
3826 RPN = env->spr[SPR_RPA];
3827 if (is_code) {
3828 CMP = env->spr[SPR_ICMP];
3829 EPN = env->spr[SPR_IMISS];
3830 } else {
3831 CMP = env->spr[SPR_DCMP];
3832 EPN = env->spr[SPR_DMISS];
3833 }
3834 way = (env->spr[SPR_SRR1] >> 17) & 1;
577f25a5 3835 (void)EPN; /* avoid a compiler warning */
90e189ec
BS
3836 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
3837 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
3838 RPN, way);
76a66253 3839 /* Store this TLB */
0f3955e2 3840 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
d9bce9d9 3841 way, is_code, CMP, RPN);
76a66253
JM
3842}
3843
74d37793 3844void helper_6xx_tlbd (target_ulong EPN)
0f3955e2 3845{
74d37793 3846 do_6xx_tlb(EPN, 0);
0f3955e2
AJ
3847}
3848
74d37793 3849void helper_6xx_tlbi (target_ulong EPN)
0f3955e2 3850{
74d37793 3851 do_6xx_tlb(EPN, 1);
0f3955e2
AJ
3852}
3853
3854/* PowerPC 74xx software TLB load instructions helpers */
74d37793 3855static void do_74xx_tlb (target_ulong new_EPN, int is_code)
7dbe11ac
JM
3856{
3857 target_ulong RPN, CMP, EPN;
3858 int way;
3859
3860 RPN = env->spr[SPR_PTELO];
3861 CMP = env->spr[SPR_PTEHI];
3862 EPN = env->spr[SPR_TLBMISS] & ~0x3;
3863 way = env->spr[SPR_TLBMISS] & 0x3;
577f25a5 3864 (void)EPN; /* avoid a compiler warning */
90e189ec
BS
3865 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
3866 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
3867 RPN, way);
7dbe11ac 3868 /* Store this TLB */
0f3955e2 3869 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
7dbe11ac
JM
3870 way, is_code, CMP, RPN);
3871}
3872
74d37793 3873void helper_74xx_tlbd (target_ulong EPN)
0f3955e2 3874{
74d37793 3875 do_74xx_tlb(EPN, 0);
0f3955e2
AJ
3876}
3877
74d37793 3878void helper_74xx_tlbi (target_ulong EPN)
0f3955e2 3879{
74d37793 3880 do_74xx_tlb(EPN, 1);
0f3955e2
AJ
3881}
3882
636aa200 3883static inline target_ulong booke_tlb_to_page_size(int size)
a8dea12f
JM
3884{
3885 return 1024 << (2 * size);
3886}
3887
636aa200 3888static inline int booke_page_size_to_tlb(target_ulong page_size)
a8dea12f
JM
3889{
3890 int size;
3891
3892 switch (page_size) {
3893 case 0x00000400UL:
3894 size = 0x0;
3895 break;
3896 case 0x00001000UL:
3897 size = 0x1;
3898 break;
3899 case 0x00004000UL:
3900 size = 0x2;
3901 break;
3902 case 0x00010000UL:
3903 size = 0x3;
3904 break;
3905 case 0x00040000UL:
3906 size = 0x4;
3907 break;
3908 case 0x00100000UL:
3909 size = 0x5;
3910 break;
3911 case 0x00400000UL:
3912 size = 0x6;
3913 break;
3914 case 0x01000000UL:
3915 size = 0x7;
3916 break;
3917 case 0x04000000UL:
3918 size = 0x8;
3919 break;
3920 case 0x10000000UL:
3921 size = 0x9;
3922 break;
3923 case 0x40000000UL:
3924 size = 0xA;
3925 break;
3926#if defined (TARGET_PPC64)
3927 case 0x000100000000ULL:
3928 size = 0xB;
3929 break;
3930 case 0x000400000000ULL:
3931 size = 0xC;
3932 break;
3933 case 0x001000000000ULL:
3934 size = 0xD;
3935 break;
3936 case 0x004000000000ULL:
3937 size = 0xE;
3938 break;
3939 case 0x010000000000ULL:
3940 size = 0xF;
3941 break;
3942#endif
3943 default:
3944 size = -1;
3945 break;
3946 }
3947
3948 return size;
3949}
3950
76a66253 3951/* Helpers for 4xx TLB management */
999fa40e
JC
3952#define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
3953
3954#define PPC4XX_TLBHI_V 0x00000040
3955#define PPC4XX_TLBHI_E 0x00000020
3956#define PPC4XX_TLBHI_SIZE_MIN 0
3957#define PPC4XX_TLBHI_SIZE_MAX 7
3958#define PPC4XX_TLBHI_SIZE_DEFAULT 1
3959#define PPC4XX_TLBHI_SIZE_SHIFT 7
3960#define PPC4XX_TLBHI_SIZE_MASK 0x00000007
3961
3962#define PPC4XX_TLBLO_EX 0x00000200
3963#define PPC4XX_TLBLO_WR 0x00000100
3964#define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
3965#define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
3966
3967target_ulong helper_4xx_tlbre_hi (target_ulong entry)
76a66253 3968{
c227f099 3969 ppcemb_tlb_t *tlb;
74d37793 3970 target_ulong ret;
a8dea12f 3971 int size;
76a66253 3972
999fa40e 3973 entry &= PPC4XX_TLB_ENTRY_MASK;
74d37793
AJ
3974 tlb = &env->tlb[entry].tlbe;
3975 ret = tlb->EPN;
999fa40e
JC
3976 if (tlb->prot & PAGE_VALID) {
3977 ret |= PPC4XX_TLBHI_V;
3978 }
a8dea12f 3979 size = booke_page_size_to_tlb(tlb->size);
999fa40e
JC
3980 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
3981 size = PPC4XX_TLBHI_SIZE_DEFAULT;
3982 }
3983 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
a8dea12f 3984 env->spr[SPR_40x_PID] = tlb->PID;
74d37793 3985 return ret;
76a66253
JM
3986}
3987
999fa40e 3988target_ulong helper_4xx_tlbre_lo (target_ulong entry)
76a66253 3989{
c227f099 3990 ppcemb_tlb_t *tlb;
74d37793 3991 target_ulong ret;
76a66253 3992
999fa40e 3993 entry &= PPC4XX_TLB_ENTRY_MASK;
74d37793
AJ
3994 tlb = &env->tlb[entry].tlbe;
3995 ret = tlb->RPN;
999fa40e
JC
3996 if (tlb->prot & PAGE_EXEC) {
3997 ret |= PPC4XX_TLBLO_EX;
3998 }
3999 if (tlb->prot & PAGE_WRITE) {
4000 ret |= PPC4XX_TLBLO_WR;
4001 }
74d37793 4002 return ret;
76a66253
JM
4003}
4004
74d37793 4005void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
76a66253 4006{
c227f099 4007 ppcemb_tlb_t *tlb;
76a66253
JM
4008 target_ulong page, end;
4009
90e189ec
BS
4010 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
4011 val);
999fa40e 4012 entry &= PPC4XX_TLB_ENTRY_MASK;
74d37793 4013 tlb = &env->tlb[entry].tlbe;
76a66253
JM
4014 /* Invalidate previous TLB (if it's valid) */
4015 if (tlb->prot & PAGE_VALID) {
4016 end = tlb->EPN + tlb->size;
90e189ec
BS
4017 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
4018 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
999fa40e 4019 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
76a66253 4020 tlb_flush_page(env, page);
999fa40e 4021 }
76a66253 4022 }
999fa40e
JC
4023 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
4024 & PPC4XX_TLBHI_SIZE_MASK);
c294fc58
JM
4025 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
4026 * If this ever occurs, one should use the ppcemb target instead
4027 * of the ppc or ppc64 one
4028 */
999fa40e 4029 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
71c8b8fd
JM
4030 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
4031 "are not supported (%d)\n",
74d37793 4032 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
c294fc58 4033 }
74d37793 4034 tlb->EPN = val & ~(tlb->size - 1);
999fa40e 4035 if (val & PPC4XX_TLBHI_V) {
76a66253 4036 tlb->prot |= PAGE_VALID;
999fa40e 4037 if (val & PPC4XX_TLBHI_E) {
c5b9729a
EI
4038 /* XXX: TO BE FIXED */
4039 cpu_abort(env,
4040 "Little-endian TLB entries are not supported by now\n");
4041 }
4042 } else {
76a66253 4043 tlb->prot &= ~PAGE_VALID;
c294fc58 4044 }
c55e9aef 4045 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
90e189ec
BS
4046 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
4047 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
4048 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4049 tlb->prot & PAGE_READ ? 'r' : '-',
4050 tlb->prot & PAGE_WRITE ? 'w' : '-',
4051 tlb->prot & PAGE_EXEC ? 'x' : '-',
4052 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
76a66253
JM
4053 /* Invalidate new TLB (if valid) */
4054 if (tlb->prot & PAGE_VALID) {
4055 end = tlb->EPN + tlb->size;
90e189ec
BS
4056 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
4057 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
999fa40e 4058 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
76a66253 4059 tlb_flush_page(env, page);
999fa40e 4060 }
76a66253 4061 }
76a66253
JM
4062}
4063
74d37793 4064void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
76a66253 4065{
c227f099 4066 ppcemb_tlb_t *tlb;
76a66253 4067
90e189ec
BS
4068 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
4069 val);
999fa40e 4070 entry &= PPC4XX_TLB_ENTRY_MASK;
74d37793 4071 tlb = &env->tlb[entry].tlbe;
999fa40e
JC
4072 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
4073 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
76a66253 4074 tlb->prot = PAGE_READ;
999fa40e 4075 if (val & PPC4XX_TLBLO_EX) {
76a66253 4076 tlb->prot |= PAGE_EXEC;
999fa40e
JC
4077 }
4078 if (val & PPC4XX_TLBLO_WR) {
76a66253 4079 tlb->prot |= PAGE_WRITE;
999fa40e 4080 }
90e189ec
BS
4081 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
4082 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
4083 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4084 tlb->prot & PAGE_READ ? 'r' : '-',
4085 tlb->prot & PAGE_WRITE ? 'w' : '-',
4086 tlb->prot & PAGE_EXEC ? 'x' : '-',
4087 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
76a66253 4088}
5eb7995e 4089
74d37793
AJ
4090target_ulong helper_4xx_tlbsx (target_ulong address)
4091{
4092 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
4093}
4094
a4bb6c3e 4095/* PowerPC 440 TLB management */
74d37793 4096void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
5eb7995e 4097{
c227f099 4098 ppcemb_tlb_t *tlb;
a4bb6c3e 4099 target_ulong EPN, RPN, size;
5eb7995e
JM
4100 int do_flush_tlbs;
4101
90e189ec
BS
4102 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
4103 __func__, word, (int)entry, value);
5eb7995e 4104 do_flush_tlbs = 0;
74d37793
AJ
4105 entry &= 0x3F;
4106 tlb = &env->tlb[entry].tlbe;
a4bb6c3e
JM
4107 switch (word) {
4108 default:
4109 /* Just here to please gcc */
4110 case 0:
74d37793 4111 EPN = value & 0xFFFFFC00;
a4bb6c3e 4112 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
5eb7995e 4113 do_flush_tlbs = 1;
a4bb6c3e 4114 tlb->EPN = EPN;
74d37793 4115 size = booke_tlb_to_page_size((value >> 4) & 0xF);
a4bb6c3e
JM
4116 if ((tlb->prot & PAGE_VALID) && tlb->size < size)
4117 do_flush_tlbs = 1;
4118 tlb->size = size;
4119 tlb->attr &= ~0x1;
74d37793
AJ
4120 tlb->attr |= (value >> 8) & 1;
4121 if (value & 0x200) {
a4bb6c3e
JM
4122 tlb->prot |= PAGE_VALID;
4123 } else {
4124 if (tlb->prot & PAGE_VALID) {
4125 tlb->prot &= ~PAGE_VALID;
4126 do_flush_tlbs = 1;
4127 }
5eb7995e 4128 }
a4bb6c3e
JM
4129 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
4130 if (do_flush_tlbs)
4131 tlb_flush(env, 1);
4132 break;
4133 case 1:
74d37793 4134 RPN = value & 0xFFFFFC0F;
a4bb6c3e
JM
4135 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
4136 tlb_flush(env, 1);
4137 tlb->RPN = RPN;
4138 break;
4139 case 2:
74d37793 4140 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
a4bb6c3e 4141 tlb->prot = tlb->prot & PAGE_VALID;
74d37793 4142 if (value & 0x1)
a4bb6c3e 4143 tlb->prot |= PAGE_READ << 4;
74d37793 4144 if (value & 0x2)
a4bb6c3e 4145 tlb->prot |= PAGE_WRITE << 4;
74d37793 4146 if (value & 0x4)
a4bb6c3e 4147 tlb->prot |= PAGE_EXEC << 4;
74d37793 4148 if (value & 0x8)
a4bb6c3e 4149 tlb->prot |= PAGE_READ;
74d37793 4150 if (value & 0x10)
a4bb6c3e 4151 tlb->prot |= PAGE_WRITE;
74d37793 4152 if (value & 0x20)
a4bb6c3e
JM
4153 tlb->prot |= PAGE_EXEC;
4154 break;
5eb7995e 4155 }
5eb7995e
JM
4156}
4157
74d37793 4158target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
5eb7995e 4159{
c227f099 4160 ppcemb_tlb_t *tlb;
74d37793 4161 target_ulong ret;
5eb7995e
JM
4162 int size;
4163
74d37793
AJ
4164 entry &= 0x3F;
4165 tlb = &env->tlb[entry].tlbe;
a4bb6c3e
JM
4166 switch (word) {
4167 default:
4168 /* Just here to please gcc */
4169 case 0:
74d37793 4170 ret = tlb->EPN;
a4bb6c3e
JM
4171 size = booke_page_size_to_tlb(tlb->size);
4172 if (size < 0 || size > 0xF)
4173 size = 1;
74d37793 4174 ret |= size << 4;
a4bb6c3e 4175 if (tlb->attr & 0x1)
74d37793 4176 ret |= 0x100;
a4bb6c3e 4177 if (tlb->prot & PAGE_VALID)
74d37793 4178 ret |= 0x200;
a4bb6c3e
JM
4179 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
4180 env->spr[SPR_440_MMUCR] |= tlb->PID;
4181 break;
4182 case 1:
74d37793 4183 ret = tlb->RPN;
a4bb6c3e
JM
4184 break;
4185 case 2:
74d37793 4186 ret = tlb->attr & ~0x1;
a4bb6c3e 4187 if (tlb->prot & (PAGE_READ << 4))
74d37793 4188 ret |= 0x1;
a4bb6c3e 4189 if (tlb->prot & (PAGE_WRITE << 4))
74d37793 4190 ret |= 0x2;
a4bb6c3e 4191 if (tlb->prot & (PAGE_EXEC << 4))
74d37793 4192 ret |= 0x4;
a4bb6c3e 4193 if (tlb->prot & PAGE_READ)
74d37793 4194 ret |= 0x8;
a4bb6c3e 4195 if (tlb->prot & PAGE_WRITE)
74d37793 4196 ret |= 0x10;
a4bb6c3e 4197 if (tlb->prot & PAGE_EXEC)
74d37793 4198 ret |= 0x20;
a4bb6c3e
JM
4199 break;
4200 }
74d37793 4201 return ret;
5eb7995e 4202}
74d37793
AJ
4203
4204target_ulong helper_440_tlbsx (target_ulong address)
4205{
4206 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
4207}
4208
76a66253 4209#endif /* !CONFIG_USER_ONLY */