]> git.proxmox.com Git - mirror_qemu.git/blame - target-ppc/op_helper.c
Convert references to logfile/loglevel to use qemu_log*() macros
[mirror_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
00d3b8f5
AJ
1968/* Saturating arithmetic helpers. */
1969#define SATCVT(from, to, from_type, to_type, min, max, use_min, use_max) \
1970 static always_inline to_type cvt##from##to (from_type x, int *sat) \
1971 { \
1972 to_type r; \
1973 if (use_min && x < min) { \
1974 r = min; \
1975 *sat = 1; \
1976 } else if (use_max && x > max) { \
1977 r = max; \
1978 *sat = 1; \
1979 } else { \
1980 r = x; \
1981 } \
1982 return r; \
1983 }
1984SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX, 1, 1)
1985SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX, 1, 1)
1986SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX, 1, 1)
1987SATCVT(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX, 0, 1)
1988SATCVT(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX, 0, 1)
1989SATCVT(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX, 0, 1)
1990SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX, 1, 1)
1991SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX, 1, 1)
1992SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX, 1, 1)
1993#undef SATCVT
1994
cbfb6ae9
AJ
1995#define LVE(name, access, swap, element) \
1996 void helper_##name (ppc_avr_t *r, target_ulong addr) \
1997 { \
1998 size_t n_elems = ARRAY_SIZE(r->element); \
1999 int adjust = HI_IDX*(n_elems-1); \
2000 int sh = sizeof(r->element[0]) >> 1; \
2001 int index = (addr & 0xf) >> sh; \
2002 if(msr_le) { \
2003 r->element[LO_IDX ? index : (adjust - index)] = swap(access(addr)); \
2004 } else { \
2005 r->element[LO_IDX ? index : (adjust - index)] = access(addr); \
2006 } \
2007 }
2008#define I(x) (x)
2009LVE(lvebx, ldub, I, u8)
2010LVE(lvehx, lduw, bswap16, u16)
2011LVE(lvewx, ldl, bswap32, u32)
2012#undef I
2013#undef LVE
2014
bf8d8ded
AJ
2015void helper_lvsl (ppc_avr_t *r, target_ulong sh)
2016{
2017 int i, j = (sh & 0xf);
2018
2019 VECTOR_FOR_INORDER_I (i, u8) {
2020 r->u8[i] = j++;
2021 }
2022}
2023
2024void helper_lvsr (ppc_avr_t *r, target_ulong sh)
2025{
2026 int i, j = 0x10 - (sh & 0xf);
2027
2028 VECTOR_FOR_INORDER_I (i, u8) {
2029 r->u8[i] = j++;
2030 }
2031}
2032
cbfb6ae9
AJ
2033#define STVE(name, access, swap, element) \
2034 void helper_##name (ppc_avr_t *r, target_ulong addr) \
2035 { \
2036 size_t n_elems = ARRAY_SIZE(r->element); \
2037 int adjust = HI_IDX*(n_elems-1); \
2038 int sh = sizeof(r->element[0]) >> 1; \
2039 int index = (addr & 0xf) >> sh; \
2040 if(msr_le) { \
2041 access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \
2042 } else { \
2043 access(addr, r->element[LO_IDX ? index : (adjust - index)]); \
2044 } \
2045 }
2046#define I(x) (x)
2047STVE(stvebx, stb, I, u8)
2048STVE(stvehx, stw, bswap16, u16)
2049STVE(stvewx, stl, bswap32, u32)
2050#undef I
2051#undef LVE
2052
e343da72
AJ
2053void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2054{
2055 int i;
2056 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2057 r->u32[i] = ~a->u32[i] < b->u32[i];
2058 }
2059}
2060
7872c51c
AJ
2061#define VARITH_DO(name, op, element) \
2062void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2063{ \
2064 int i; \
2065 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2066 r->element[i] = a->element[i] op b->element[i]; \
2067 } \
2068}
2069#define VARITH(suffix, element) \
2070 VARITH_DO(add##suffix, +, element) \
2071 VARITH_DO(sub##suffix, -, element)
2072VARITH(ubm, u8)
2073VARITH(uhm, u16)
2074VARITH(uwm, u32)
2075#undef VARITH_DO
2076#undef VARITH
2077
5ab09f33
AJ
2078#define VARITHSAT_CASE(type, op, cvt, element) \
2079 { \
2080 type result = (type)a->element[i] op (type)b->element[i]; \
2081 r->element[i] = cvt(result, &sat); \
2082 }
2083
2084#define VARITHSAT_DO(name, op, optype, cvt, element) \
2085 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2086 { \
2087 int sat = 0; \
2088 int i; \
2089 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2090 switch (sizeof(r->element[0])) { \
2091 case 1: VARITHSAT_CASE(optype, op, cvt, element); break; \
2092 case 2: VARITHSAT_CASE(optype, op, cvt, element); break; \
2093 case 4: VARITHSAT_CASE(optype, op, cvt, element); break; \
2094 } \
2095 } \
2096 if (sat) { \
2097 env->vscr |= (1 << VSCR_SAT); \
2098 } \
2099 }
2100#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
2101 VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
2102 VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
2103#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
2104 VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
2105 VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
2106VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
2107VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
2108VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
2109VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
2110VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
2111VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
2112#undef VARITHSAT_CASE
2113#undef VARITHSAT_DO
2114#undef VARITHSAT_SIGNED
2115#undef VARITHSAT_UNSIGNED
2116
fab3cbe9
AJ
2117#define VAVG_DO(name, element, etype) \
2118 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2119 { \
2120 int i; \
2121 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2122 etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
2123 r->element[i] = x >> 1; \
2124 } \
2125 }
2126
2127#define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
2128 VAVG_DO(avgs##type, signed_element, signed_type) \
2129 VAVG_DO(avgu##type, unsigned_element, unsigned_type)
2130VAVG(b, s8, int16_t, u8, uint16_t)
2131VAVG(h, s16, int32_t, u16, uint32_t)
2132VAVG(w, s32, int64_t, u32, uint64_t)
2133#undef VAVG_DO
2134#undef VAVG
2135
1add6e23
AJ
2136#define VCMP_DO(suffix, compare, element, record) \
2137 void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2138 { \
2139 uint32_t ones = (uint32_t)-1; \
2140 uint32_t all = ones; \
2141 uint32_t none = 0; \
2142 int i; \
2143 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2144 uint32_t result = (a->element[i] compare b->element[i] ? ones : 0x0); \
2145 switch (sizeof (a->element[0])) { \
2146 case 4: r->u32[i] = result; break; \
2147 case 2: r->u16[i] = result; break; \
2148 case 1: r->u8[i] = result; break; \
2149 } \
2150 all &= result; \
2151 none |= result; \
2152 } \
2153 if (record) { \
2154 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
2155 } \
2156 }
2157#define VCMP(suffix, compare, element) \
2158 VCMP_DO(suffix, compare, element, 0) \
2159 VCMP_DO(suffix##_dot, compare, element, 1)
2160VCMP(equb, ==, u8)
2161VCMP(equh, ==, u16)
2162VCMP(equw, ==, u32)
2163VCMP(gtub, >, u8)
2164VCMP(gtuh, >, u16)
2165VCMP(gtuw, >, u32)
2166VCMP(gtsb, >, s8)
2167VCMP(gtsh, >, s16)
2168VCMP(gtsw, >, s32)
2169#undef VCMP_DO
2170#undef VCMP
2171
b161ae27
AJ
2172void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2173{
2174 int sat = 0;
2175 int i;
2176
2177 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2178 int32_t prod = a->s16[i] * b->s16[i];
2179 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2180 r->s16[i] = cvtswsh (t, &sat);
2181 }
2182
2183 if (sat) {
2184 env->vscr |= (1 << VSCR_SAT);
2185 }
2186}
2187
2188void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2189{
2190 int sat = 0;
2191 int i;
2192
2193 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2194 int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
2195 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2196 r->s16[i] = cvtswsh (t, &sat);
2197 }
2198
2199 if (sat) {
2200 env->vscr |= (1 << VSCR_SAT);
2201 }
2202}
2203
e4039339
AJ
2204#define VMINMAX_DO(name, compare, element) \
2205 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2206 { \
2207 int i; \
2208 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2209 if (a->element[i] compare b->element[i]) { \
2210 r->element[i] = b->element[i]; \
2211 } else { \
2212 r->element[i] = a->element[i]; \
2213 } \
2214 } \
2215 }
2216#define VMINMAX(suffix, element) \
2217 VMINMAX_DO(min##suffix, >, element) \
2218 VMINMAX_DO(max##suffix, <, element)
2219VMINMAX(sb, s8)
2220VMINMAX(sh, s16)
2221VMINMAX(sw, s32)
2222VMINMAX(ub, u8)
2223VMINMAX(uh, u16)
2224VMINMAX(uw, u32)
2225#undef VMINMAX_DO
2226#undef VMINMAX
2227
bcd2ee23
AJ
2228void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2229{
2230 int i;
2231 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2232 int32_t prod = a->s16[i] * b->s16[i];
2233 r->s16[i] = (int16_t) (prod + c->s16[i]);
2234 }
2235}
2236
3b430048
AJ
2237#define VMRG_DO(name, element, highp) \
2238 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2239 { \
2240 ppc_avr_t result; \
2241 int i; \
2242 size_t n_elems = ARRAY_SIZE(r->element); \
2243 for (i = 0; i < n_elems/2; i++) { \
2244 if (highp) { \
2245 result.element[i*2+HI_IDX] = a->element[i]; \
2246 result.element[i*2+LO_IDX] = b->element[i]; \
2247 } else { \
2248 result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
2249 result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
2250 } \
2251 } \
2252 *r = result; \
2253 }
2254#if defined(WORDS_BIGENDIAN)
2255#define MRGHI 0
b392e756 2256#define MRGLO 1
3b430048
AJ
2257#else
2258#define MRGHI 1
2259#define MRGLO 0
2260#endif
2261#define VMRG(suffix, element) \
2262 VMRG_DO(mrgl##suffix, element, MRGHI) \
2263 VMRG_DO(mrgh##suffix, element, MRGLO)
2264VMRG(b, u8)
2265VMRG(h, u16)
2266VMRG(w, u32)
2267#undef VMRG_DO
2268#undef VMRG
2269#undef MRGHI
2270#undef MRGLO
2271
b04ae981
AJ
2272void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2273{
2274 int32_t prod[16];
2275 int i;
2276
2277 for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
2278 prod[i] = (int32_t)a->s8[i] * b->u8[i];
2279 }
2280
2281 VECTOR_FOR_INORDER_I(i, s32) {
2282 r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2283 }
2284}
2285
eae07261
AJ
2286void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2287{
2288 int32_t prod[8];
2289 int i;
2290
2291 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2292 prod[i] = a->s16[i] * b->s16[i];
2293 }
2294
2295 VECTOR_FOR_INORDER_I(i, s32) {
2296 r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1];
2297 }
2298}
2299
2300void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2301{
2302 int32_t prod[8];
2303 int i;
2304 int sat = 0;
2305
2306 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2307 prod[i] = (int32_t)a->s16[i] * b->s16[i];
2308 }
2309
2310 VECTOR_FOR_INORDER_I (i, s32) {
2311 int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1];
2312 r->u32[i] = cvtsdsw(t, &sat);
2313 }
2314
2315 if (sat) {
2316 env->vscr |= (1 << VSCR_SAT);
2317 }
2318}
2319
b04ae981
AJ
2320void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2321{
2322 uint16_t prod[16];
2323 int i;
2324
2325 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2326 prod[i] = a->u8[i] * b->u8[i];
2327 }
2328
2329 VECTOR_FOR_INORDER_I(i, u32) {
2330 r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2331 }
2332}
2333
4d9903b6
AJ
2334void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2335{
2336 uint32_t prod[8];
2337 int i;
2338
2339 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2340 prod[i] = a->u16[i] * b->u16[i];
2341 }
2342
2343 VECTOR_FOR_INORDER_I(i, u32) {
2344 r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1];
2345 }
2346}
2347
2348void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2349{
2350 uint32_t prod[8];
2351 int i;
2352 int sat = 0;
2353
2354 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2355 prod[i] = a->u16[i] * b->u16[i];
2356 }
2357
2358 VECTOR_FOR_INORDER_I (i, s32) {
2359 uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1];
2360 r->u32[i] = cvtuduw(t, &sat);
2361 }
2362
2363 if (sat) {
2364 env->vscr |= (1 << VSCR_SAT);
2365 }
2366}
2367
2c277908
AJ
2368#define VMUL_DO(name, mul_element, prod_element, evenp) \
2369 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2370 { \
2371 int i; \
2372 VECTOR_FOR_INORDER_I(i, prod_element) { \
2373 if (evenp) { \
2374 r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2375 } else { \
2376 r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2377 } \
2378 } \
2379 }
2380#define VMUL(suffix, mul_element, prod_element) \
2381 VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2382 VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2383VMUL(sb, s8, s16)
2384VMUL(sh, s16, s32)
2385VMUL(ub, u8, u16)
2386VMUL(uh, u16, u32)
2387#undef VMUL_DO
2388#undef VMUL
2389
d1258698
AJ
2390void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2391{
2392 ppc_avr_t result;
2393 int i;
2394 VECTOR_FOR_INORDER_I (i, u8) {
2395 int s = c->u8[i] & 0x1f;
2396#if defined(WORDS_BIGENDIAN)
2397 int index = s & 0xf;
2398#else
2399 int index = 15 - (s & 0xf);
2400#endif
2401 if (s & 0x10) {
2402 result.u8[i] = b->u8[index];
2403 } else {
2404 result.u8[i] = a->u8[index];
2405 }
2406 }
2407 *r = result;
2408}
2409
5335a145
AJ
2410#if defined(WORDS_BIGENDIAN)
2411#define PKBIG 1
2412#else
2413#define PKBIG 0
2414#endif
1dd9ffb9
AJ
2415void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2416{
2417 int i, j;
2418 ppc_avr_t result;
2419#if defined(WORDS_BIGENDIAN)
2420 const ppc_avr_t *x[2] = { a, b };
2421#else
2422 const ppc_avr_t *x[2] = { b, a };
2423#endif
2424
2425 VECTOR_FOR_INORDER_I (i, u64) {
2426 VECTOR_FOR_INORDER_I (j, u32){
2427 uint32_t e = x[i]->u32[j];
2428 result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
2429 ((e >> 6) & 0x3e0) |
2430 ((e >> 3) & 0x1f));
2431 }
2432 }
2433 *r = result;
2434}
2435
5335a145
AJ
2436#define VPK(suffix, from, to, cvt, dosat) \
2437 void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2438 { \
2439 int i; \
2440 int sat = 0; \
2441 ppc_avr_t result; \
2442 ppc_avr_t *a0 = PKBIG ? a : b; \
2443 ppc_avr_t *a1 = PKBIG ? b : a; \
2444 VECTOR_FOR_INORDER_I (i, from) { \
2445 result.to[i] = cvt(a0->from[i], &sat); \
2446 result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
2447 } \
2448 *r = result; \
2449 if (dosat && sat) { \
2450 env->vscr |= (1 << VSCR_SAT); \
2451 } \
2452 }
2453#define I(x, y) (x)
2454VPK(shss, s16, s8, cvtshsb, 1)
2455VPK(shus, s16, u8, cvtshub, 1)
2456VPK(swss, s32, s16, cvtswsh, 1)
2457VPK(swus, s32, u16, cvtswuh, 1)
2458VPK(uhus, u16, u8, cvtuhub, 1)
2459VPK(uwus, u32, u16, cvtuwuh, 1)
2460VPK(uhum, u16, u8, I, 0)
2461VPK(uwum, u32, u16, I, 0)
2462#undef I
2463#undef VPK
2464#undef PKBIG
2465
5e1d0985
AJ
2466#define VROTATE(suffix, element) \
2467 void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2468 { \
2469 int i; \
2470 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2471 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2472 unsigned int shift = b->element[i] & mask; \
2473 r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2474 } \
2475 }
2476VROTATE(b, u8)
2477VROTATE(h, u16)
2478VROTATE(w, u32)
2479#undef VROTATE
2480
d1258698
AJ
2481void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2482{
2483 r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2484 r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2485}
2486
d9430add
AJ
2487#if defined(WORDS_BIGENDIAN)
2488#define LEFT 0
2489#define RIGHT 1
2490#else
2491#define LEFT 1
2492#define RIGHT 0
2493#endif
2494/* The specification says that the results are undefined if all of the
2495 * shift counts are not identical. We check to make sure that they are
2496 * to conform to what real hardware appears to do. */
2497#define VSHIFT(suffix, leftp) \
2498 void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2499 { \
2500 int shift = b->u8[LO_IDX*0x15] & 0x7; \
2501 int doit = 1; \
2502 int i; \
2503 for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
2504 doit = doit && ((b->u8[i] & 0x7) == shift); \
2505 } \
2506 if (doit) { \
2507 if (shift == 0) { \
2508 *r = *a; \
2509 } else if (leftp) { \
2510 uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \
2511 r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \
2512 r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \
2513 } else { \
2514 uint64_t carry = a->u64[HI_IDX] << (64 - shift); \
2515 r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \
2516 r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \
2517 } \
2518 } \
2519 }
2520VSHIFT(l, LEFT)
2521VSHIFT(r, RIGHT)
2522#undef VSHIFT
2523#undef LEFT
2524#undef RIGHT
2525
d79f0809
AJ
2526#define VSL(suffix, element) \
2527 void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2528 { \
2529 int i; \
2530 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2531 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2532 unsigned int shift = b->element[i] & mask; \
2533 r->element[i] = a->element[i] << shift; \
2534 } \
2535 }
2536VSL(b, u8)
2537VSL(h, u16)
2538VSL(w, u32)
2539#undef VSL
2540
cd633b10
AJ
2541void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
2542{
2543 int sh = shift & 0xf;
2544 int i;
2545 ppc_avr_t result;
2546
2547#if defined(WORDS_BIGENDIAN)
2548 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2549 int index = sh + i;
2550 if (index > 0xf) {
2551 result.u8[i] = b->u8[index-0x10];
2552 } else {
2553 result.u8[i] = a->u8[index];
2554 }
2555 }
2556#else
2557 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2558 int index = (16 - sh) + i;
2559 if (index > 0xf) {
2560 result.u8[i] = a->u8[index-0x10];
2561 } else {
2562 result.u8[i] = b->u8[index];
2563 }
2564 }
2565#endif
2566 *r = result;
2567}
2568
7b239bec
AJ
2569void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2570{
2571 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2572
2573#if defined (WORDS_BIGENDIAN)
2574 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2575 memset (&r->u8[16-sh], 0, sh);
2576#else
2577 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2578 memset (&r->u8[0], 0, sh);
2579#endif
2580}
2581
e4e6bee7
AJ
2582/* Experimental testing shows that hardware masks the immediate. */
2583#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
2584#if defined(WORDS_BIGENDIAN)
2585#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2586#else
2587#define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
2588#endif
2589#define VSPLT(suffix, element) \
2590 void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
2591 { \
2592 uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
2593 int i; \
2594 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2595 r->element[i] = s; \
2596 } \
2597 }
2598VSPLT(b, u8)
2599VSPLT(h, u16)
2600VSPLT(w, u32)
2601#undef VSPLT
2602#undef SPLAT_ELEMENT
2603#undef _SPLAT_MASKED
2604
c026766b
AJ
2605#define VSPLTI(suffix, element, splat_type) \
2606 void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat) \
2607 { \
2608 splat_type x = (int8_t)(splat << 3) >> 3; \
2609 int i; \
2610 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2611 r->element[i] = x; \
2612 } \
2613 }
2614VSPLTI(b, s8, int8_t)
2615VSPLTI(h, s16, int16_t)
2616VSPLTI(w, s32, int32_t)
2617#undef VSPLTI
2618
07ef34c3
AJ
2619#define VSR(suffix, element) \
2620 void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2621 { \
2622 int i; \
2623 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2624 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2625 unsigned int shift = b->element[i] & mask; \
2626 r->element[i] = a->element[i] >> shift; \
2627 } \
2628 }
2629VSR(ab, s8)
2630VSR(ah, s16)
2631VSR(aw, s32)
2632VSR(b, u8)
2633VSR(h, u16)
2634VSR(w, u32)
2635#undef VSR
2636
7b239bec
AJ
2637void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2638{
2639 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2640
2641#if defined (WORDS_BIGENDIAN)
2642 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2643 memset (&r->u8[0], 0, sh);
2644#else
2645 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2646 memset (&r->u8[16-sh], 0, sh);
2647#endif
2648}
2649
e343da72
AJ
2650void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2651{
2652 int i;
2653 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2654 r->u32[i] = a->u32[i] >= b->u32[i];
2655 }
2656}
2657
8142cddd
AJ
2658void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2659{
2660 int64_t t;
2661 int i, upper;
2662 ppc_avr_t result;
2663 int sat = 0;
2664
2665#if defined(WORDS_BIGENDIAN)
2666 upper = ARRAY_SIZE(r->s32)-1;
2667#else
2668 upper = 0;
2669#endif
2670 t = (int64_t)b->s32[upper];
2671 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2672 t += a->s32[i];
2673 result.s32[i] = 0;
2674 }
2675 result.s32[upper] = cvtsdsw(t, &sat);
2676 *r = result;
2677
2678 if (sat) {
2679 env->vscr |= (1 << VSCR_SAT);
2680 }
2681}
2682
2683void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2684{
2685 int i, j, upper;
2686 ppc_avr_t result;
2687 int sat = 0;
2688
2689#if defined(WORDS_BIGENDIAN)
2690 upper = 1;
2691#else
2692 upper = 0;
2693#endif
2694 for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
2695 int64_t t = (int64_t)b->s32[upper+i*2];
2696 result.u64[i] = 0;
2697 for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
2698 t += a->s32[2*i+j];
2699 }
2700 result.s32[upper+i*2] = cvtsdsw(t, &sat);
2701 }
2702
2703 *r = result;
2704 if (sat) {
2705 env->vscr |= (1 << VSCR_SAT);
2706 }
2707}
2708
2709void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2710{
2711 int i, j;
2712 int sat = 0;
2713
2714 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2715 int64_t t = (int64_t)b->s32[i];
2716 for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
2717 t += a->s8[4*i+j];
2718 }
2719 r->s32[i] = cvtsdsw(t, &sat);
2720 }
2721
2722 if (sat) {
2723 env->vscr |= (1 << VSCR_SAT);
2724 }
2725}
2726
2727void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2728{
2729 int sat = 0;
2730 int i;
2731
2732 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2733 int64_t t = (int64_t)b->s32[i];
2734 t += a->s16[2*i] + a->s16[2*i+1];
2735 r->s32[i] = cvtsdsw(t, &sat);
2736 }
2737
2738 if (sat) {
2739 env->vscr |= (1 << VSCR_SAT);
2740 }
2741}
2742
2743void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2744{
2745 int i, j;
2746 int sat = 0;
2747
2748 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2749 uint64_t t = (uint64_t)b->u32[i];
2750 for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
2751 t += a->u8[4*i+j];
2752 }
2753 r->u32[i] = cvtuduw(t, &sat);
2754 }
2755
2756 if (sat) {
2757 env->vscr |= (1 << VSCR_SAT);
2758 }
2759}
2760
79f85c3a
AJ
2761#if defined(WORDS_BIGENDIAN)
2762#define UPKHI 1
2763#define UPKLO 0
2764#else
2765#define UPKHI 0
2766#define UPKLO 1
2767#endif
2768#define VUPKPX(suffix, hi) \
2769 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2770 { \
2771 int i; \
2772 ppc_avr_t result; \
2773 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
2774 uint16_t e = b->u16[hi ? i : i+4]; \
2775 uint8_t a = (e >> 15) ? 0xff : 0; \
2776 uint8_t r = (e >> 10) & 0x1f; \
2777 uint8_t g = (e >> 5) & 0x1f; \
2778 uint8_t b = e & 0x1f; \
2779 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
2780 } \
2781 *r = result; \
2782 }
2783VUPKPX(lpx, UPKLO)
2784VUPKPX(hpx, UPKHI)
2785#undef VUPKPX
2786
6cf1c6e5
AJ
2787#define VUPK(suffix, unpacked, packee, hi) \
2788 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2789 { \
2790 int i; \
2791 ppc_avr_t result; \
2792 if (hi) { \
2793 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
2794 result.unpacked[i] = b->packee[i]; \
2795 } \
2796 } else { \
2797 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
2798 result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
2799 } \
2800 } \
2801 *r = result; \
2802 }
2803VUPK(hsb, s16, s8, UPKHI)
2804VUPK(hsh, s32, s16, UPKHI)
2805VUPK(lsb, s16, s8, UPKLO)
2806VUPK(lsh, s32, s16, UPKLO)
2807#undef VUPK
79f85c3a
AJ
2808#undef UPKHI
2809#undef UPKLO
2810
d6a46fe8
AJ
2811#undef VECTOR_FOR_INORDER_I
2812#undef HI_IDX
2813#undef LO_IDX
2814
1c97856d 2815/*****************************************************************************/
0487d6a8
JM
2816/* SPE extension helpers */
2817/* Use a table to make this quicker */
2818static uint8_t hbrev[16] = {
2819 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
2820 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
2821};
2822
b068d6a7 2823static always_inline uint8_t byte_reverse (uint8_t val)
0487d6a8
JM
2824{
2825 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
2826}
2827
b068d6a7 2828static always_inline uint32_t word_reverse (uint32_t val)
0487d6a8
JM
2829{
2830 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
2831 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
2832}
2833
3cd7d1dd 2834#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
57951c27 2835target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
0487d6a8
JM
2836{
2837 uint32_t a, b, d, mask;
2838
3cd7d1dd 2839 mask = UINT32_MAX >> (32 - MASKBITS);
57951c27
AJ
2840 a = arg1 & mask;
2841 b = arg2 & mask;
3cd7d1dd 2842 d = word_reverse(1 + word_reverse(a | ~b));
57951c27 2843 return (arg1 & ~mask) | (d & b);
0487d6a8
JM
2844}
2845
57951c27 2846uint32_t helper_cntlsw32 (uint32_t val)
0487d6a8
JM
2847{
2848 if (val & 0x80000000)
603fccce 2849 return clz32(~val);
0487d6a8 2850 else
603fccce 2851 return clz32(val);
0487d6a8
JM
2852}
2853
57951c27 2854uint32_t helper_cntlzw32 (uint32_t val)
0487d6a8 2855{
603fccce 2856 return clz32(val);
0487d6a8
JM
2857}
2858
1c97856d
AJ
2859/* Single-precision floating-point conversions */
2860static always_inline uint32_t efscfsi (uint32_t val)
0487d6a8 2861{
0ca9d380 2862 CPU_FloatU u;
0487d6a8
JM
2863
2864 u.f = int32_to_float32(val, &env->spe_status);
2865
0ca9d380 2866 return u.l;
0487d6a8
JM
2867}
2868
1c97856d 2869static always_inline uint32_t efscfui (uint32_t val)
0487d6a8 2870{
0ca9d380 2871 CPU_FloatU u;
0487d6a8
JM
2872
2873 u.f = uint32_to_float32(val, &env->spe_status);
2874
0ca9d380 2875 return u.l;
0487d6a8
JM
2876}
2877
1c97856d 2878static always_inline int32_t efsctsi (uint32_t val)
0487d6a8 2879{
0ca9d380 2880 CPU_FloatU u;
0487d6a8 2881
0ca9d380 2882 u.l = val;
0487d6a8 2883 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2884 if (unlikely(float32_is_nan(u.f)))
0487d6a8
JM
2885 return 0;
2886
2887 return float32_to_int32(u.f, &env->spe_status);
2888}
2889
1c97856d 2890static always_inline uint32_t efsctui (uint32_t val)
0487d6a8 2891{
0ca9d380 2892 CPU_FloatU u;
0487d6a8 2893
0ca9d380 2894 u.l = val;
0487d6a8 2895 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2896 if (unlikely(float32_is_nan(u.f)))
0487d6a8
JM
2897 return 0;
2898
2899 return float32_to_uint32(u.f, &env->spe_status);
2900}
2901
1c97856d 2902static always_inline uint32_t efsctsiz (uint32_t val)
0487d6a8 2903{
0ca9d380 2904 CPU_FloatU u;
0487d6a8 2905
0ca9d380 2906 u.l = val;
0487d6a8 2907 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2908 if (unlikely(float32_is_nan(u.f)))
0487d6a8
JM
2909 return 0;
2910
2911 return float32_to_int32_round_to_zero(u.f, &env->spe_status);
2912}
2913
1c97856d 2914static always_inline uint32_t efsctuiz (uint32_t val)
0487d6a8 2915{
0ca9d380 2916 CPU_FloatU u;
0487d6a8 2917
0ca9d380 2918 u.l = val;
0487d6a8 2919 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2920 if (unlikely(float32_is_nan(u.f)))
0487d6a8
JM
2921 return 0;
2922
2923 return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
2924}
2925
1c97856d 2926static always_inline uint32_t efscfsf (uint32_t val)
0487d6a8 2927{
0ca9d380 2928 CPU_FloatU u;
0487d6a8
JM
2929 float32 tmp;
2930
2931 u.f = int32_to_float32(val, &env->spe_status);
2932 tmp = int64_to_float32(1ULL << 32, &env->spe_status);
2933 u.f = float32_div(u.f, tmp, &env->spe_status);
2934
0ca9d380 2935 return u.l;
0487d6a8
JM
2936}
2937
1c97856d 2938static always_inline uint32_t efscfuf (uint32_t val)
0487d6a8 2939{
0ca9d380 2940 CPU_FloatU u;
0487d6a8
JM
2941 float32 tmp;
2942
2943 u.f = uint32_to_float32(val, &env->spe_status);
2944 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2945 u.f = float32_div(u.f, tmp, &env->spe_status);
2946
0ca9d380 2947 return u.l;
0487d6a8
JM
2948}
2949
1c97856d 2950static always_inline uint32_t efsctsf (uint32_t val)
0487d6a8 2951{
0ca9d380 2952 CPU_FloatU u;
0487d6a8
JM
2953 float32 tmp;
2954
0ca9d380 2955 u.l = val;
0487d6a8 2956 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2957 if (unlikely(float32_is_nan(u.f)))
0487d6a8
JM
2958 return 0;
2959 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2960 u.f = float32_mul(u.f, tmp, &env->spe_status);
2961
2962 return float32_to_int32(u.f, &env->spe_status);
2963}
2964
1c97856d 2965static always_inline uint32_t efsctuf (uint32_t val)
0487d6a8 2966{
0ca9d380 2967 CPU_FloatU u;
0487d6a8
JM
2968 float32 tmp;
2969
0ca9d380 2970 u.l = val;
0487d6a8 2971 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2972 if (unlikely(float32_is_nan(u.f)))
0487d6a8
JM
2973 return 0;
2974 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2975 u.f = float32_mul(u.f, tmp, &env->spe_status);
2976
2977 return float32_to_uint32(u.f, &env->spe_status);
2978}
2979
1c97856d
AJ
2980#define HELPER_SPE_SINGLE_CONV(name) \
2981uint32_t helper_e##name (uint32_t val) \
2982{ \
2983 return e##name(val); \
2984}
2985/* efscfsi */
2986HELPER_SPE_SINGLE_CONV(fscfsi);
2987/* efscfui */
2988HELPER_SPE_SINGLE_CONV(fscfui);
2989/* efscfuf */
2990HELPER_SPE_SINGLE_CONV(fscfuf);
2991/* efscfsf */
2992HELPER_SPE_SINGLE_CONV(fscfsf);
2993/* efsctsi */
2994HELPER_SPE_SINGLE_CONV(fsctsi);
2995/* efsctui */
2996HELPER_SPE_SINGLE_CONV(fsctui);
2997/* efsctsiz */
2998HELPER_SPE_SINGLE_CONV(fsctsiz);
2999/* efsctuiz */
3000HELPER_SPE_SINGLE_CONV(fsctuiz);
3001/* efsctsf */
3002HELPER_SPE_SINGLE_CONV(fsctsf);
3003/* efsctuf */
3004HELPER_SPE_SINGLE_CONV(fsctuf);
3005
3006#define HELPER_SPE_VECTOR_CONV(name) \
3007uint64_t helper_ev##name (uint64_t val) \
3008{ \
3009 return ((uint64_t)e##name(val >> 32) << 32) | \
3010 (uint64_t)e##name(val); \
0487d6a8 3011}
1c97856d
AJ
3012/* evfscfsi */
3013HELPER_SPE_VECTOR_CONV(fscfsi);
3014/* evfscfui */
3015HELPER_SPE_VECTOR_CONV(fscfui);
3016/* evfscfuf */
3017HELPER_SPE_VECTOR_CONV(fscfuf);
3018/* evfscfsf */
3019HELPER_SPE_VECTOR_CONV(fscfsf);
3020/* evfsctsi */
3021HELPER_SPE_VECTOR_CONV(fsctsi);
3022/* evfsctui */
3023HELPER_SPE_VECTOR_CONV(fsctui);
3024/* evfsctsiz */
3025HELPER_SPE_VECTOR_CONV(fsctsiz);
3026/* evfsctuiz */
3027HELPER_SPE_VECTOR_CONV(fsctuiz);
3028/* evfsctsf */
3029HELPER_SPE_VECTOR_CONV(fsctsf);
3030/* evfsctuf */
3031HELPER_SPE_VECTOR_CONV(fsctuf);
0487d6a8 3032
1c97856d
AJ
3033/* Single-precision floating-point arithmetic */
3034static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
0487d6a8 3035{
1c97856d
AJ
3036 CPU_FloatU u1, u2;
3037 u1.l = op1;
3038 u2.l = op2;
3039 u1.f = float32_add(u1.f, u2.f, &env->spe_status);
3040 return u1.l;
0487d6a8
JM
3041}
3042
1c97856d 3043static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
0487d6a8 3044{
1c97856d
AJ
3045 CPU_FloatU u1, u2;
3046 u1.l = op1;
3047 u2.l = op2;
3048 u1.f = float32_sub(u1.f, u2.f, &env->spe_status);
3049 return u1.l;
0487d6a8
JM
3050}
3051
1c97856d 3052static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
0487d6a8 3053{
1c97856d
AJ
3054 CPU_FloatU u1, u2;
3055 u1.l = op1;
3056 u2.l = op2;
3057 u1.f = float32_mul(u1.f, u2.f, &env->spe_status);
3058 return u1.l;
0487d6a8
JM
3059}
3060
1c97856d 3061static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
0487d6a8 3062{
1c97856d
AJ
3063 CPU_FloatU u1, u2;
3064 u1.l = op1;
3065 u2.l = op2;
3066 u1.f = float32_div(u1.f, u2.f, &env->spe_status);
3067 return u1.l;
0487d6a8
JM
3068}
3069
1c97856d
AJ
3070#define HELPER_SPE_SINGLE_ARITH(name) \
3071uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
3072{ \
3073 return e##name(op1, op2); \
3074}
3075/* efsadd */
3076HELPER_SPE_SINGLE_ARITH(fsadd);
3077/* efssub */
3078HELPER_SPE_SINGLE_ARITH(fssub);
3079/* efsmul */
3080HELPER_SPE_SINGLE_ARITH(fsmul);
3081/* efsdiv */
3082HELPER_SPE_SINGLE_ARITH(fsdiv);
3083
3084#define HELPER_SPE_VECTOR_ARITH(name) \
3085uint64_t helper_ev##name (uint64_t op1, uint64_t op2) \
3086{ \
3087 return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
3088 (uint64_t)e##name(op1, op2); \
3089}
3090/* evfsadd */
3091HELPER_SPE_VECTOR_ARITH(fsadd);
3092/* evfssub */
3093HELPER_SPE_VECTOR_ARITH(fssub);
3094/* evfsmul */
3095HELPER_SPE_VECTOR_ARITH(fsmul);
3096/* evfsdiv */
3097HELPER_SPE_VECTOR_ARITH(fsdiv);
3098
3099/* Single-precision floating-point comparisons */
3100static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
0487d6a8 3101{
1c97856d
AJ
3102 CPU_FloatU u1, u2;
3103 u1.l = op1;
3104 u2.l = op2;
3105 return float32_lt(u1.f, u2.f, &env->spe_status) ? 4 : 0;
0487d6a8
JM
3106}
3107
1c97856d 3108static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
0487d6a8 3109{
1c97856d
AJ
3110 CPU_FloatU u1, u2;
3111 u1.l = op1;
3112 u2.l = op2;
3113 return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 4;
0487d6a8
JM
3114}
3115
1c97856d 3116static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
0487d6a8 3117{
1c97856d
AJ
3118 CPU_FloatU u1, u2;
3119 u1.l = op1;
3120 u2.l = op2;
3121 return float32_eq(u1.f, u2.f, &env->spe_status) ? 4 : 0;
0487d6a8
JM
3122}
3123
1c97856d 3124static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
0487d6a8
JM
3125{
3126 /* XXX: TODO: test special values (NaN, infinites, ...) */
1c97856d 3127 return efststlt(op1, op2);
0487d6a8
JM
3128}
3129
1c97856d 3130static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
0487d6a8
JM
3131{
3132 /* XXX: TODO: test special values (NaN, infinites, ...) */
1c97856d 3133 return efststgt(op1, op2);
0487d6a8
JM
3134}
3135
1c97856d 3136static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
0487d6a8
JM
3137{
3138 /* XXX: TODO: test special values (NaN, infinites, ...) */
1c97856d 3139 return efststeq(op1, op2);
0487d6a8
JM
3140}
3141
1c97856d
AJ
3142#define HELPER_SINGLE_SPE_CMP(name) \
3143uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
3144{ \
3145 return e##name(op1, op2) << 2; \
3146}
3147/* efststlt */
3148HELPER_SINGLE_SPE_CMP(fststlt);
3149/* efststgt */
3150HELPER_SINGLE_SPE_CMP(fststgt);
3151/* efststeq */
3152HELPER_SINGLE_SPE_CMP(fststeq);
3153/* efscmplt */
3154HELPER_SINGLE_SPE_CMP(fscmplt);
3155/* efscmpgt */
3156HELPER_SINGLE_SPE_CMP(fscmpgt);
3157/* efscmpeq */
3158HELPER_SINGLE_SPE_CMP(fscmpeq);
3159
3160static always_inline uint32_t evcmp_merge (int t0, int t1)
0487d6a8 3161{
1c97856d 3162 return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
0487d6a8
JM
3163}
3164
1c97856d
AJ
3165#define HELPER_VECTOR_SPE_CMP(name) \
3166uint32_t helper_ev##name (uint64_t op1, uint64_t op2) \
3167{ \
3168 return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
0487d6a8 3169}
1c97856d
AJ
3170/* evfststlt */
3171HELPER_VECTOR_SPE_CMP(fststlt);
3172/* evfststgt */
3173HELPER_VECTOR_SPE_CMP(fststgt);
3174/* evfststeq */
3175HELPER_VECTOR_SPE_CMP(fststeq);
3176/* evfscmplt */
3177HELPER_VECTOR_SPE_CMP(fscmplt);
3178/* evfscmpgt */
3179HELPER_VECTOR_SPE_CMP(fscmpgt);
3180/* evfscmpeq */
3181HELPER_VECTOR_SPE_CMP(fscmpeq);
0487d6a8 3182
1c97856d
AJ
3183/* Double-precision floating-point conversion */
3184uint64_t helper_efdcfsi (uint32_t val)
0487d6a8 3185{
1c97856d
AJ
3186 CPU_DoubleU u;
3187
3188 u.d = int32_to_float64(val, &env->spe_status);
3189
3190 return u.ll;
0487d6a8
JM
3191}
3192
1c97856d 3193uint64_t helper_efdcfsid (uint64_t val)
0487d6a8 3194{
0ca9d380 3195 CPU_DoubleU u;
0487d6a8 3196
0ca9d380 3197 u.d = int64_to_float64(val, &env->spe_status);
0487d6a8 3198
0ca9d380 3199 return u.ll;
0487d6a8
JM
3200}
3201
1c97856d
AJ
3202uint64_t helper_efdcfui (uint32_t val)
3203{
3204 CPU_DoubleU u;
3205
3206 u.d = uint32_to_float64(val, &env->spe_status);
3207
3208 return u.ll;
3209}
3210
3211uint64_t helper_efdcfuid (uint64_t val)
0487d6a8 3212{
0ca9d380 3213 CPU_DoubleU u;
0487d6a8 3214
0ca9d380 3215 u.d = uint64_to_float64(val, &env->spe_status);
0487d6a8 3216
0ca9d380 3217 return u.ll;
0487d6a8
JM
3218}
3219
1c97856d 3220uint32_t helper_efdctsi (uint64_t val)
0487d6a8 3221{
0ca9d380 3222 CPU_DoubleU u;
0487d6a8 3223
0ca9d380 3224 u.ll = val;
0487d6a8 3225 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3226 if (unlikely(float64_is_nan(u.d)))
0487d6a8
JM
3227 return 0;
3228
1c97856d 3229 return float64_to_int32(u.d, &env->spe_status);
0487d6a8
JM
3230}
3231
1c97856d 3232uint32_t helper_efdctui (uint64_t val)
0487d6a8 3233{
0ca9d380 3234 CPU_DoubleU u;
0487d6a8 3235
0ca9d380 3236 u.ll = val;
0487d6a8 3237 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3238 if (unlikely(float64_is_nan(u.d)))
0487d6a8
JM
3239 return 0;
3240
1c97856d 3241 return float64_to_uint32(u.d, &env->spe_status);
0487d6a8
JM
3242}
3243
1c97856d 3244uint32_t helper_efdctsiz (uint64_t val)
0487d6a8 3245{
0ca9d380 3246 CPU_DoubleU u;
0487d6a8 3247
0ca9d380 3248 u.ll = val;
0487d6a8 3249 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3250 if (unlikely(float64_is_nan(u.d)))
0487d6a8
JM
3251 return 0;
3252
1c97856d 3253 return float64_to_int32_round_to_zero(u.d, &env->spe_status);
0487d6a8
JM
3254}
3255
1c97856d 3256uint64_t helper_efdctsidz (uint64_t val)
0487d6a8 3257{
0ca9d380 3258 CPU_DoubleU u;
0487d6a8 3259
0ca9d380 3260 u.ll = val;
0487d6a8 3261 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3262 if (unlikely(float64_is_nan(u.d)))
0487d6a8
JM
3263 return 0;
3264
1c97856d 3265 return float64_to_int64_round_to_zero(u.d, &env->spe_status);
0487d6a8
JM
3266}
3267
1c97856d 3268uint32_t helper_efdctuiz (uint64_t val)
0487d6a8 3269{
1c97856d 3270 CPU_DoubleU u;
0487d6a8 3271
1c97856d
AJ
3272 u.ll = val;
3273 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3274 if (unlikely(float64_is_nan(u.d)))
1c97856d 3275 return 0;
0487d6a8 3276
1c97856d 3277 return float64_to_uint32_round_to_zero(u.d, &env->spe_status);
0487d6a8
JM
3278}
3279
1c97856d 3280uint64_t helper_efdctuidz (uint64_t val)
0487d6a8 3281{
1c97856d 3282 CPU_DoubleU u;
0487d6a8 3283
1c97856d
AJ
3284 u.ll = val;
3285 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3286 if (unlikely(float64_is_nan(u.d)))
1c97856d 3287 return 0;
0487d6a8 3288
1c97856d 3289 return float64_to_uint64_round_to_zero(u.d, &env->spe_status);
0487d6a8
JM
3290}
3291
1c97856d 3292uint64_t helper_efdcfsf (uint32_t val)
0487d6a8 3293{
0ca9d380 3294 CPU_DoubleU u;
0487d6a8
JM
3295 float64 tmp;
3296
0ca9d380 3297 u.d = int32_to_float64(val, &env->spe_status);
0487d6a8 3298 tmp = int64_to_float64(1ULL << 32, &env->spe_status);
0ca9d380 3299 u.d = float64_div(u.d, tmp, &env->spe_status);
0487d6a8 3300
0ca9d380 3301 return u.ll;
0487d6a8
JM
3302}
3303
1c97856d 3304uint64_t helper_efdcfuf (uint32_t val)
0487d6a8 3305{
0ca9d380 3306 CPU_DoubleU u;
0487d6a8
JM
3307 float64 tmp;
3308
0ca9d380 3309 u.d = uint32_to_float64(val, &env->spe_status);
0487d6a8 3310 tmp = int64_to_float64(1ULL << 32, &env->spe_status);
0ca9d380 3311 u.d = float64_div(u.d, tmp, &env->spe_status);
0487d6a8 3312
0ca9d380 3313 return u.ll;
0487d6a8
JM
3314}
3315
1c97856d 3316uint32_t helper_efdctsf (uint64_t val)
0487d6a8 3317{
0ca9d380 3318 CPU_DoubleU u;
0487d6a8
JM
3319 float64 tmp;
3320
0ca9d380 3321 u.ll = val;
0487d6a8 3322 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3323 if (unlikely(float64_is_nan(u.d)))
0487d6a8
JM
3324 return 0;
3325 tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
0ca9d380 3326 u.d = float64_mul(u.d, tmp, &env->spe_status);
0487d6a8 3327
0ca9d380 3328 return float64_to_int32(u.d, &env->spe_status);
0487d6a8
JM
3329}
3330
1c97856d 3331uint32_t helper_efdctuf (uint64_t val)
0487d6a8 3332{
0ca9d380 3333 CPU_DoubleU u;
0487d6a8
JM
3334 float64 tmp;
3335
0ca9d380 3336 u.ll = val;
0487d6a8 3337 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3338 if (unlikely(float64_is_nan(u.d)))
0487d6a8
JM
3339 return 0;
3340 tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
0ca9d380 3341 u.d = float64_mul(u.d, tmp, &env->spe_status);
0487d6a8 3342
0ca9d380 3343 return float64_to_uint32(u.d, &env->spe_status);
0487d6a8
JM
3344}
3345
1c97856d 3346uint32_t helper_efscfd (uint64_t val)
0487d6a8 3347{
0ca9d380
AJ
3348 CPU_DoubleU u1;
3349 CPU_FloatU u2;
0487d6a8 3350
0ca9d380
AJ
3351 u1.ll = val;
3352 u2.f = float64_to_float32(u1.d, &env->spe_status);
0487d6a8 3353
0ca9d380 3354 return u2.l;
0487d6a8
JM
3355}
3356
1c97856d 3357uint64_t helper_efdcfs (uint32_t val)
0487d6a8 3358{
0ca9d380
AJ
3359 CPU_DoubleU u2;
3360 CPU_FloatU u1;
0487d6a8 3361
0ca9d380
AJ
3362 u1.l = val;
3363 u2.d = float32_to_float64(u1.f, &env->spe_status);
0487d6a8 3364
0ca9d380 3365 return u2.ll;
0487d6a8
JM
3366}
3367
1c97856d
AJ
3368/* Double precision fixed-point arithmetic */
3369uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
0487d6a8 3370{
1c97856d
AJ
3371 CPU_DoubleU u1, u2;
3372 u1.ll = op1;
3373 u2.ll = op2;
3374 u1.d = float64_add(u1.d, u2.d, &env->spe_status);
3375 return u1.ll;
0487d6a8
JM
3376}
3377
1c97856d 3378uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
0487d6a8 3379{
1c97856d
AJ
3380 CPU_DoubleU u1, u2;
3381 u1.ll = op1;
3382 u2.ll = op2;
3383 u1.d = float64_sub(u1.d, u2.d, &env->spe_status);
3384 return u1.ll;
0487d6a8
JM
3385}
3386
1c97856d 3387uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
0487d6a8 3388{
1c97856d
AJ
3389 CPU_DoubleU u1, u2;
3390 u1.ll = op1;
3391 u2.ll = op2;
3392 u1.d = float64_mul(u1.d, u2.d, &env->spe_status);
3393 return u1.ll;
0487d6a8
JM
3394}
3395
1c97856d 3396uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
0487d6a8 3397{
1c97856d
AJ
3398 CPU_DoubleU u1, u2;
3399 u1.ll = op1;
3400 u2.ll = op2;
3401 u1.d = float64_div(u1.d, u2.d, &env->spe_status);
3402 return u1.ll;
0487d6a8
JM
3403}
3404
1c97856d
AJ
3405/* Double precision floating point helpers */
3406uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
0487d6a8 3407{
1c97856d
AJ
3408 CPU_DoubleU u1, u2;
3409 u1.ll = op1;
3410 u2.ll = op2;
3411 return float64_lt(u1.d, u2.d, &env->spe_status) ? 4 : 0;
0487d6a8
JM
3412}
3413
1c97856d 3414uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
0487d6a8 3415{
1c97856d
AJ
3416 CPU_DoubleU u1, u2;
3417 u1.ll = op1;
3418 u2.ll = op2;
3419 return float64_le(u1.d, u2.d, &env->spe_status) ? 0 : 4;
0487d6a8
JM
3420}
3421
1c97856d 3422uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
0487d6a8 3423{
1c97856d
AJ
3424 CPU_DoubleU u1, u2;
3425 u1.ll = op1;
3426 u2.ll = op2;
3427 return float64_eq(u1.d, u2.d, &env->spe_status) ? 4 : 0;
0487d6a8
JM
3428}
3429
1c97856d 3430uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
0487d6a8 3431{
1c97856d
AJ
3432 /* XXX: TODO: test special values (NaN, infinites, ...) */
3433 return helper_efdtstlt(op1, op2);
0487d6a8
JM
3434}
3435
1c97856d
AJ
3436uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
3437{
3438 /* XXX: TODO: test special values (NaN, infinites, ...) */
3439 return helper_efdtstgt(op1, op2);
3440}
0487d6a8 3441
1c97856d
AJ
3442uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
3443{
3444 /* XXX: TODO: test special values (NaN, infinites, ...) */
3445 return helper_efdtsteq(op1, op2);
3446}
0487d6a8 3447
fdabc366
FB
3448/*****************************************************************************/
3449/* Softmmu support */
3450#if !defined (CONFIG_USER_ONLY)
3451
3452#define MMUSUFFIX _mmu
fdabc366
FB
3453
3454#define SHIFT 0
3455#include "softmmu_template.h"
3456
3457#define SHIFT 1
3458#include "softmmu_template.h"
3459
3460#define SHIFT 2
3461#include "softmmu_template.h"
3462
3463#define SHIFT 3
3464#include "softmmu_template.h"
3465
3466/* try to fill the TLB and return an exception if error. If retaddr is
3467 NULL, it means that the function was called in C code (i.e. not
3468 from generated code or from helper.c) */
3469/* XXX: fix it to restore all registers */
6ebbf390 3470void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
fdabc366
FB
3471{
3472 TranslationBlock *tb;
3473 CPUState *saved_env;
44f8625d 3474 unsigned long pc;
fdabc366
FB
3475 int ret;
3476
3477 /* XXX: hack to restore env in all cases, even if not called from
3478 generated code */
3479 saved_env = env;
3480 env = cpu_single_env;
6ebbf390 3481 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
76a66253 3482 if (unlikely(ret != 0)) {
fdabc366
FB
3483 if (likely(retaddr)) {
3484 /* now we have a real cpu fault */
44f8625d 3485 pc = (unsigned long)retaddr;
fdabc366
FB
3486 tb = tb_find_pc(pc);
3487 if (likely(tb)) {
3488 /* the PC is inside the translated code. It means that we have
3489 a virtual CPU fault */
3490 cpu_restore_state(tb, env, pc, NULL);
76a66253 3491 }
fdabc366 3492 }
e06fcd75 3493 helper_raise_exception_err(env->exception_index, env->error_code);
fdabc366
FB
3494 }
3495 env = saved_env;
9a64fbe4
FB
3496}
3497
74d37793
AJ
3498/* Segment registers load and store */
3499target_ulong helper_load_sr (target_ulong sr_num)
3500{
3501 return env->sr[sr_num];
3502}
3503
3504void helper_store_sr (target_ulong sr_num, target_ulong val)
3505{
45d827d2 3506 ppc_store_sr(env, sr_num, val);
74d37793
AJ
3507}
3508
3509/* SLB management */
3510#if defined(TARGET_PPC64)
3511target_ulong helper_load_slb (target_ulong slb_nr)
3512{
3513 return ppc_load_slb(env, slb_nr);
3514}
3515
3516void helper_store_slb (target_ulong slb_nr, target_ulong rs)
3517{
3518 ppc_store_slb(env, slb_nr, rs);
3519}
3520
3521void helper_slbia (void)
3522{
3523 ppc_slb_invalidate_all(env);
3524}
3525
3526void helper_slbie (target_ulong addr)
3527{
3528 ppc_slb_invalidate_one(env, addr);
3529}
3530
3531#endif /* defined(TARGET_PPC64) */
3532
3533/* TLB management */
3534void helper_tlbia (void)
3535{
3536 ppc_tlb_invalidate_all(env);
3537}
3538
3539void helper_tlbie (target_ulong addr)
3540{
3541 ppc_tlb_invalidate_one(env, addr);
3542}
3543
76a66253
JM
3544/* Software driven TLBs management */
3545/* PowerPC 602/603 software TLB load instructions helpers */
74d37793 3546static void do_6xx_tlb (target_ulong new_EPN, int is_code)
76a66253
JM
3547{
3548 target_ulong RPN, CMP, EPN;
3549 int way;
d9bce9d9 3550
76a66253
JM
3551 RPN = env->spr[SPR_RPA];
3552 if (is_code) {
3553 CMP = env->spr[SPR_ICMP];
3554 EPN = env->spr[SPR_IMISS];
3555 } else {
3556 CMP = env->spr[SPR_DCMP];
3557 EPN = env->spr[SPR_DMISS];
3558 }
3559 way = (env->spr[SPR_SRR1] >> 17) & 1;
d12d51d5 3560 LOG_SWTLB("%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
6b542af7 3561 " PTE1 " ADDRX " way %d\n",
0e69805a 3562 __func__, new_EPN, EPN, CMP, RPN, way);
76a66253 3563 /* Store this TLB */
0f3955e2 3564 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
d9bce9d9 3565 way, is_code, CMP, RPN);
76a66253
JM
3566}
3567
74d37793 3568void helper_6xx_tlbd (target_ulong EPN)
0f3955e2 3569{
74d37793 3570 do_6xx_tlb(EPN, 0);
0f3955e2
AJ
3571}
3572
74d37793 3573void helper_6xx_tlbi (target_ulong EPN)
0f3955e2 3574{
74d37793 3575 do_6xx_tlb(EPN, 1);
0f3955e2
AJ
3576}
3577
3578/* PowerPC 74xx software TLB load instructions helpers */
74d37793 3579static void do_74xx_tlb (target_ulong new_EPN, int is_code)
7dbe11ac
JM
3580{
3581 target_ulong RPN, CMP, EPN;
3582 int way;
3583
3584 RPN = env->spr[SPR_PTELO];
3585 CMP = env->spr[SPR_PTEHI];
3586 EPN = env->spr[SPR_TLBMISS] & ~0x3;
3587 way = env->spr[SPR_TLBMISS] & 0x3;
d12d51d5 3588 LOG_SWTLB("%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
6b542af7 3589 " PTE1 " ADDRX " way %d\n",
0e69805a 3590 __func__, new_EPN, EPN, CMP, RPN, way);
7dbe11ac 3591 /* Store this TLB */
0f3955e2 3592 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
7dbe11ac
JM
3593 way, is_code, CMP, RPN);
3594}
3595
74d37793 3596void helper_74xx_tlbd (target_ulong EPN)
0f3955e2 3597{
74d37793 3598 do_74xx_tlb(EPN, 0);
0f3955e2
AJ
3599}
3600
74d37793 3601void helper_74xx_tlbi (target_ulong EPN)
0f3955e2 3602{
74d37793 3603 do_74xx_tlb(EPN, 1);
0f3955e2
AJ
3604}
3605
a11b8151 3606static always_inline target_ulong booke_tlb_to_page_size (int size)
a8dea12f
JM
3607{
3608 return 1024 << (2 * size);
3609}
3610
a11b8151 3611static always_inline int booke_page_size_to_tlb (target_ulong page_size)
a8dea12f
JM
3612{
3613 int size;
3614
3615 switch (page_size) {
3616 case 0x00000400UL:
3617 size = 0x0;
3618 break;
3619 case 0x00001000UL:
3620 size = 0x1;
3621 break;
3622 case 0x00004000UL:
3623 size = 0x2;
3624 break;
3625 case 0x00010000UL:
3626 size = 0x3;
3627 break;
3628 case 0x00040000UL:
3629 size = 0x4;
3630 break;
3631 case 0x00100000UL:
3632 size = 0x5;
3633 break;
3634 case 0x00400000UL:
3635 size = 0x6;
3636 break;
3637 case 0x01000000UL:
3638 size = 0x7;
3639 break;
3640 case 0x04000000UL:
3641 size = 0x8;
3642 break;
3643 case 0x10000000UL:
3644 size = 0x9;
3645 break;
3646 case 0x40000000UL:
3647 size = 0xA;
3648 break;
3649#if defined (TARGET_PPC64)
3650 case 0x000100000000ULL:
3651 size = 0xB;
3652 break;
3653 case 0x000400000000ULL:
3654 size = 0xC;
3655 break;
3656 case 0x001000000000ULL:
3657 size = 0xD;
3658 break;
3659 case 0x004000000000ULL:
3660 size = 0xE;
3661 break;
3662 case 0x010000000000ULL:
3663 size = 0xF;
3664 break;
3665#endif
3666 default:
3667 size = -1;
3668 break;
3669 }
3670
3671 return size;
3672}
3673
76a66253 3674/* Helpers for 4xx TLB management */
74d37793 3675target_ulong helper_4xx_tlbre_lo (target_ulong entry)
76a66253 3676{
a8dea12f 3677 ppcemb_tlb_t *tlb;
74d37793 3678 target_ulong ret;
a8dea12f 3679 int size;
76a66253 3680
74d37793
AJ
3681 entry &= 0x3F;
3682 tlb = &env->tlb[entry].tlbe;
3683 ret = tlb->EPN;
a8dea12f 3684 if (tlb->prot & PAGE_VALID)
74d37793 3685 ret |= 0x400;
a8dea12f
JM
3686 size = booke_page_size_to_tlb(tlb->size);
3687 if (size < 0 || size > 0x7)
3688 size = 1;
74d37793 3689 ret |= size << 7;
a8dea12f 3690 env->spr[SPR_40x_PID] = tlb->PID;
74d37793 3691 return ret;
76a66253
JM
3692}
3693
74d37793 3694target_ulong helper_4xx_tlbre_hi (target_ulong entry)
76a66253 3695{
a8dea12f 3696 ppcemb_tlb_t *tlb;
74d37793 3697 target_ulong ret;
76a66253 3698
74d37793
AJ
3699 entry &= 0x3F;
3700 tlb = &env->tlb[entry].tlbe;
3701 ret = tlb->RPN;
a8dea12f 3702 if (tlb->prot & PAGE_EXEC)
74d37793 3703 ret |= 0x200;
a8dea12f 3704 if (tlb->prot & PAGE_WRITE)
74d37793
AJ
3705 ret |= 0x100;
3706 return ret;
76a66253
JM
3707}
3708
74d37793 3709void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
76a66253 3710{
a8dea12f 3711 ppcemb_tlb_t *tlb;
76a66253
JM
3712 target_ulong page, end;
3713
d12d51d5 3714 LOG_SWTLB("%s entry %d val " ADDRX "\n", __func__, (int)entry, val);
74d37793
AJ
3715 entry &= 0x3F;
3716 tlb = &env->tlb[entry].tlbe;
76a66253
JM
3717 /* Invalidate previous TLB (if it's valid) */
3718 if (tlb->prot & PAGE_VALID) {
3719 end = tlb->EPN + tlb->size;
d12d51d5 3720 LOG_SWTLB("%s: invalidate old TLB %d start " ADDRX
74d37793 3721 " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
76a66253
JM
3722 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3723 tlb_flush_page(env, page);
3724 }
74d37793 3725 tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
c294fc58
JM
3726 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
3727 * If this ever occurs, one should use the ppcemb target instead
3728 * of the ppc or ppc64 one
3729 */
74d37793 3730 if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
71c8b8fd
JM
3731 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
3732 "are not supported (%d)\n",
74d37793 3733 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
c294fc58 3734 }
74d37793
AJ
3735 tlb->EPN = val & ~(tlb->size - 1);
3736 if (val & 0x40)
76a66253
JM
3737 tlb->prot |= PAGE_VALID;
3738 else
3739 tlb->prot &= ~PAGE_VALID;
74d37793 3740 if (val & 0x20) {
c294fc58
JM
3741 /* XXX: TO BE FIXED */
3742 cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
3743 }
c55e9aef 3744 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
74d37793 3745 tlb->attr = val & 0xFF;
d12d51d5 3746 LOG_SWTLB("%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
c55e9aef 3747 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
0e69805a 3748 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
c55e9aef
JM
3749 tlb->prot & PAGE_READ ? 'r' : '-',
3750 tlb->prot & PAGE_WRITE ? 'w' : '-',
3751 tlb->prot & PAGE_EXEC ? 'x' : '-',
3752 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
76a66253
JM
3753 /* Invalidate new TLB (if valid) */
3754 if (tlb->prot & PAGE_VALID) {
3755 end = tlb->EPN + tlb->size;
d12d51d5 3756 LOG_SWTLB("%s: invalidate TLB %d start " ADDRX
0e69805a 3757 " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
76a66253
JM
3758 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3759 tlb_flush_page(env, page);
3760 }
76a66253
JM
3761}
3762
74d37793 3763void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
76a66253 3764{
a8dea12f 3765 ppcemb_tlb_t *tlb;
76a66253 3766
d12d51d5 3767 LOG_SWTLB("%s entry %i val " ADDRX "\n", __func__, (int)entry, val);
74d37793
AJ
3768 entry &= 0x3F;
3769 tlb = &env->tlb[entry].tlbe;
3770 tlb->RPN = val & 0xFFFFFC00;
76a66253 3771 tlb->prot = PAGE_READ;
74d37793 3772 if (val & 0x200)
76a66253 3773 tlb->prot |= PAGE_EXEC;
74d37793 3774 if (val & 0x100)
76a66253 3775 tlb->prot |= PAGE_WRITE;
d12d51d5 3776 LOG_SWTLB("%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
c55e9aef 3777 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
74d37793 3778 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
c55e9aef
JM
3779 tlb->prot & PAGE_READ ? 'r' : '-',
3780 tlb->prot & PAGE_WRITE ? 'w' : '-',
3781 tlb->prot & PAGE_EXEC ? 'x' : '-',
3782 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
76a66253 3783}
5eb7995e 3784
74d37793
AJ
3785target_ulong helper_4xx_tlbsx (target_ulong address)
3786{
3787 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
3788}
3789
a4bb6c3e 3790/* PowerPC 440 TLB management */
74d37793 3791void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
5eb7995e
JM
3792{
3793 ppcemb_tlb_t *tlb;
a4bb6c3e 3794 target_ulong EPN, RPN, size;
5eb7995e
JM
3795 int do_flush_tlbs;
3796
d12d51d5 3797 LOG_SWTLB("%s word %d entry %d value " ADDRX "\n",
0e69805a 3798 __func__, word, (int)entry, value);
5eb7995e 3799 do_flush_tlbs = 0;
74d37793
AJ
3800 entry &= 0x3F;
3801 tlb = &env->tlb[entry].tlbe;
a4bb6c3e
JM
3802 switch (word) {
3803 default:
3804 /* Just here to please gcc */
3805 case 0:
74d37793 3806 EPN = value & 0xFFFFFC00;
a4bb6c3e 3807 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
5eb7995e 3808 do_flush_tlbs = 1;
a4bb6c3e 3809 tlb->EPN = EPN;
74d37793 3810 size = booke_tlb_to_page_size((value >> 4) & 0xF);
a4bb6c3e
JM
3811 if ((tlb->prot & PAGE_VALID) && tlb->size < size)
3812 do_flush_tlbs = 1;
3813 tlb->size = size;
3814 tlb->attr &= ~0x1;
74d37793
AJ
3815 tlb->attr |= (value >> 8) & 1;
3816 if (value & 0x200) {
a4bb6c3e
JM
3817 tlb->prot |= PAGE_VALID;
3818 } else {
3819 if (tlb->prot & PAGE_VALID) {
3820 tlb->prot &= ~PAGE_VALID;
3821 do_flush_tlbs = 1;
3822 }
5eb7995e 3823 }
a4bb6c3e
JM
3824 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
3825 if (do_flush_tlbs)
3826 tlb_flush(env, 1);
3827 break;
3828 case 1:
74d37793 3829 RPN = value & 0xFFFFFC0F;
a4bb6c3e
JM
3830 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
3831 tlb_flush(env, 1);
3832 tlb->RPN = RPN;
3833 break;
3834 case 2:
74d37793 3835 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
a4bb6c3e 3836 tlb->prot = tlb->prot & PAGE_VALID;
74d37793 3837 if (value & 0x1)
a4bb6c3e 3838 tlb->prot |= PAGE_READ << 4;
74d37793 3839 if (value & 0x2)
a4bb6c3e 3840 tlb->prot |= PAGE_WRITE << 4;
74d37793 3841 if (value & 0x4)
a4bb6c3e 3842 tlb->prot |= PAGE_EXEC << 4;
74d37793 3843 if (value & 0x8)
a4bb6c3e 3844 tlb->prot |= PAGE_READ;
74d37793 3845 if (value & 0x10)
a4bb6c3e 3846 tlb->prot |= PAGE_WRITE;
74d37793 3847 if (value & 0x20)
a4bb6c3e
JM
3848 tlb->prot |= PAGE_EXEC;
3849 break;
5eb7995e 3850 }
5eb7995e
JM
3851}
3852
74d37793 3853target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
5eb7995e
JM
3854{
3855 ppcemb_tlb_t *tlb;
74d37793 3856 target_ulong ret;
5eb7995e
JM
3857 int size;
3858
74d37793
AJ
3859 entry &= 0x3F;
3860 tlb = &env->tlb[entry].tlbe;
a4bb6c3e
JM
3861 switch (word) {
3862 default:
3863 /* Just here to please gcc */
3864 case 0:
74d37793 3865 ret = tlb->EPN;
a4bb6c3e
JM
3866 size = booke_page_size_to_tlb(tlb->size);
3867 if (size < 0 || size > 0xF)
3868 size = 1;
74d37793 3869 ret |= size << 4;
a4bb6c3e 3870 if (tlb->attr & 0x1)
74d37793 3871 ret |= 0x100;
a4bb6c3e 3872 if (tlb->prot & PAGE_VALID)
74d37793 3873 ret |= 0x200;
a4bb6c3e
JM
3874 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
3875 env->spr[SPR_440_MMUCR] |= tlb->PID;
3876 break;
3877 case 1:
74d37793 3878 ret = tlb->RPN;
a4bb6c3e
JM
3879 break;
3880 case 2:
74d37793 3881 ret = tlb->attr & ~0x1;
a4bb6c3e 3882 if (tlb->prot & (PAGE_READ << 4))
74d37793 3883 ret |= 0x1;
a4bb6c3e 3884 if (tlb->prot & (PAGE_WRITE << 4))
74d37793 3885 ret |= 0x2;
a4bb6c3e 3886 if (tlb->prot & (PAGE_EXEC << 4))
74d37793 3887 ret |= 0x4;
a4bb6c3e 3888 if (tlb->prot & PAGE_READ)
74d37793 3889 ret |= 0x8;
a4bb6c3e 3890 if (tlb->prot & PAGE_WRITE)
74d37793 3891 ret |= 0x10;
a4bb6c3e 3892 if (tlb->prot & PAGE_EXEC)
74d37793 3893 ret |= 0x20;
a4bb6c3e
JM
3894 break;
3895 }
74d37793 3896 return ret;
5eb7995e 3897}
74d37793
AJ
3898
3899target_ulong helper_440_tlbsx (target_ulong address)
3900{
3901 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
3902}
3903
76a66253 3904#endif /* !CONFIG_USER_ONLY */