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