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