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