]> git.proxmox.com Git - qemu.git/blame - target-ppc/op_helper.c
Merge remote branch 'arm/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);
af12906f
AJ
549 if (unlikely(float64_is_nan(farg.d))) {
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 */
e0147e41 646 ret = 0xFFF8000000000000ULL;
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 */
e0147e41 657 ret = 0xFFF8000000000000ULL;
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;
977#if USE_PRECISE_EMULATION
978 if (unlikely(float64_is_signaling_nan(farg1.d) ||
979 float64_is_signaling_nan(farg2.d))) {
7c58044c 980 /* sNaN addition */
af12906f 981 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
17218d1f
AJ
982 } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
983 float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
7c58044c 984 /* Magnitude subtraction of infinities */
cf1cf21e 985 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
17218d1f
AJ
986 } else {
987 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
7c58044c 988 }
af12906f
AJ
989#else
990 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
991#endif
992 return farg1.ll;
7c58044c
JM
993}
994
af12906f
AJ
995/* fsub - fsub. */
996uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
997{
998 CPU_DoubleU farg1, farg2;
999
1000 farg1.ll = arg1;
1001 farg2.ll = arg2;
1002#if USE_PRECISE_EMULATION
7c58044c 1003{
af12906f
AJ
1004 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1005 float64_is_signaling_nan(farg2.d))) {
7c58044c 1006 /* sNaN subtraction */
af12906f 1007 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
17218d1f
AJ
1008 } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1009 float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
7c58044c 1010 /* Magnitude subtraction of infinities */
af12906f 1011 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
17218d1f
AJ
1012 } else {
1013 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
7c58044c
JM
1014 }
1015}
af12906f
AJ
1016#else
1017 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
1018#endif
1019 return farg1.ll;
1020}
7c58044c 1021
af12906f
AJ
1022/* fmul - fmul. */
1023uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
7c58044c 1024{
af12906f
AJ
1025 CPU_DoubleU farg1, farg2;
1026
1027 farg1.ll = arg1;
1028 farg2.ll = arg2;
1029#if USE_PRECISE_EMULATION
1030 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1031 float64_is_signaling_nan(farg2.d))) {
7c58044c 1032 /* sNaN multiplication */
af12906f 1033 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
f23c346e
AJ
1034 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1035 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
7c58044c 1036 /* Multiplication of zero by infinity */
af12906f 1037 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
7c58044c 1038 } else {
af12906f 1039 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
7c58044c 1040 }
af12906f
AJ
1041#else
1042 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1043#endif
1044 return farg1.ll;
1045}
7c58044c 1046
af12906f
AJ
1047/* fdiv - fdiv. */
1048uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
7c58044c 1049{
af12906f
AJ
1050 CPU_DoubleU farg1, farg2;
1051
1052 farg1.ll = arg1;
1053 farg2.ll = arg2;
1054#if USE_PRECISE_EMULATION
1055 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1056 float64_is_signaling_nan(farg2.d))) {
7c58044c 1057 /* sNaN division */
af12906f 1058 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
f23c346e 1059 } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) {
7c58044c 1060 /* Division of infinity by infinity */
af12906f 1061 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
e33e94f9
AJ
1062 } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
1063 /* Division of zero by zero */
1064 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
7c58044c 1065 } else {
af12906f 1066 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
7c58044c 1067 }
af12906f
AJ
1068#else
1069 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
1070#endif
1071 return farg1.ll;
7c58044c 1072}
7c58044c 1073
af12906f
AJ
1074/* fabs */
1075uint64_t helper_fabs (uint64_t arg)
9a64fbe4 1076{
af12906f 1077 CPU_DoubleU farg;
9a64fbe4 1078
af12906f
AJ
1079 farg.ll = arg;
1080 farg.d = float64_abs(farg.d);
1081 return farg.ll;
1082}
1083
1084/* fnabs */
1085uint64_t helper_fnabs (uint64_t arg)
1086{
1087 CPU_DoubleU farg;
1088
1089 farg.ll = arg;
1090 farg.d = float64_abs(farg.d);
1091 farg.d = float64_chs(farg.d);
1092 return farg.ll;
1093}
1094
1095/* fneg */
1096uint64_t helper_fneg (uint64_t arg)
1097{
1098 CPU_DoubleU farg;
1099
1100 farg.ll = arg;
1101 farg.d = float64_chs(farg.d);
1102 return farg.ll;
1103}
1104
1105/* fctiw - fctiw. */
1106uint64_t helper_fctiw (uint64_t arg)
1107{
1108 CPU_DoubleU farg;
1109 farg.ll = arg;
1110
1111 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1112 /* sNaN conversion */
af12906f 1113 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
f23c346e 1114 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
7c58044c 1115 /* qNan / infinity conversion */
af12906f 1116 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
7c58044c 1117 } else {
af12906f 1118 farg.ll = float64_to_int32(farg.d, &env->fp_status);
1cdb9c3d 1119#if USE_PRECISE_EMULATION
7c58044c
JM
1120 /* XXX: higher bits are not supposed to be significant.
1121 * to make tests easier, return the same as a real PowerPC 750
1122 */
af12906f 1123 farg.ll |= 0xFFF80000ULL << 32;
e864cabd 1124#endif
7c58044c 1125 }
af12906f 1126 return farg.ll;
9a64fbe4
FB
1127}
1128
af12906f
AJ
1129/* fctiwz - fctiwz. */
1130uint64_t helper_fctiwz (uint64_t arg)
9a64fbe4 1131{
af12906f
AJ
1132 CPU_DoubleU farg;
1133 farg.ll = arg;
4ecc3190 1134
af12906f 1135 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1136 /* sNaN conversion */
af12906f 1137 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
f23c346e 1138 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
7c58044c 1139 /* qNan / infinity conversion */
af12906f 1140 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
7c58044c 1141 } else {
af12906f 1142 farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
1cdb9c3d 1143#if USE_PRECISE_EMULATION
7c58044c
JM
1144 /* XXX: higher bits are not supposed to be significant.
1145 * to make tests easier, return the same as a real PowerPC 750
1146 */
af12906f 1147 farg.ll |= 0xFFF80000ULL << 32;
e864cabd 1148#endif
7c58044c 1149 }
af12906f 1150 return farg.ll;
9a64fbe4
FB
1151}
1152
426613db 1153#if defined(TARGET_PPC64)
af12906f
AJ
1154/* fcfid - fcfid. */
1155uint64_t helper_fcfid (uint64_t arg)
426613db 1156{
af12906f
AJ
1157 CPU_DoubleU farg;
1158 farg.d = int64_to_float64(arg, &env->fp_status);
1159 return farg.ll;
426613db
JM
1160}
1161
af12906f
AJ
1162/* fctid - fctid. */
1163uint64_t helper_fctid (uint64_t arg)
426613db 1164{
af12906f
AJ
1165 CPU_DoubleU farg;
1166 farg.ll = arg;
426613db 1167
af12906f 1168 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1169 /* sNaN conversion */
af12906f 1170 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
f23c346e 1171 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
7c58044c 1172 /* qNan / infinity conversion */
af12906f 1173 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
7c58044c 1174 } else {
af12906f 1175 farg.ll = float64_to_int64(farg.d, &env->fp_status);
7c58044c 1176 }
af12906f 1177 return farg.ll;
426613db
JM
1178}
1179
af12906f
AJ
1180/* fctidz - fctidz. */
1181uint64_t helper_fctidz (uint64_t arg)
426613db 1182{
af12906f
AJ
1183 CPU_DoubleU farg;
1184 farg.ll = arg;
426613db 1185
af12906f 1186 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1187 /* sNaN conversion */
af12906f 1188 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
f23c346e 1189 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
7c58044c 1190 /* qNan / infinity conversion */
af12906f 1191 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
7c58044c 1192 } else {
af12906f 1193 farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
7c58044c 1194 }
af12906f 1195 return farg.ll;
426613db
JM
1196}
1197
1198#endif
1199
636aa200 1200static inline uint64_t do_fri(uint64_t arg, int rounding_mode)
d7e4b87e 1201{
af12906f
AJ
1202 CPU_DoubleU farg;
1203 farg.ll = arg;
1204
1205 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1206 /* sNaN round */
af12906f 1207 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
f23c346e 1208 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
7c58044c 1209 /* qNan / infinity round */
af12906f 1210 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
7c58044c
JM
1211 } else {
1212 set_float_rounding_mode(rounding_mode, &env->fp_status);
af12906f 1213 farg.ll = float64_round_to_int(farg.d, &env->fp_status);
7c58044c
JM
1214 /* Restore rounding mode from FPSCR */
1215 fpscr_set_rounding_mode();
1216 }
af12906f 1217 return farg.ll;
d7e4b87e
JM
1218}
1219
af12906f 1220uint64_t helper_frin (uint64_t arg)
d7e4b87e 1221{
af12906f 1222 return do_fri(arg, float_round_nearest_even);
d7e4b87e
JM
1223}
1224
af12906f 1225uint64_t helper_friz (uint64_t arg)
d7e4b87e 1226{
af12906f 1227 return do_fri(arg, float_round_to_zero);
d7e4b87e
JM
1228}
1229
af12906f 1230uint64_t helper_frip (uint64_t arg)
d7e4b87e 1231{
af12906f 1232 return do_fri(arg, float_round_up);
d7e4b87e
JM
1233}
1234
af12906f 1235uint64_t helper_frim (uint64_t arg)
d7e4b87e 1236{
af12906f 1237 return do_fri(arg, float_round_down);
d7e4b87e
JM
1238}
1239
af12906f
AJ
1240/* fmadd - fmadd. */
1241uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
e864cabd 1242{
af12906f
AJ
1243 CPU_DoubleU farg1, farg2, farg3;
1244
1245 farg1.ll = arg1;
1246 farg2.ll = arg2;
1247 farg3.ll = arg3;
1248#if USE_PRECISE_EMULATION
1249 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1250 float64_is_signaling_nan(farg2.d) ||
1251 float64_is_signaling_nan(farg3.d))) {
7c58044c 1252 /* sNaN operation */
af12906f 1253 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
da1e7ac9
AJ
1254 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1255 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1256 /* Multiplication of zero by infinity */
1257 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
7c58044c 1258 } else {
e864cabd 1259#ifdef FLOAT128
7c58044c
JM
1260 /* This is the way the PowerPC specification defines it */
1261 float128 ft0_128, ft1_128;
1262
af12906f
AJ
1263 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1264 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
7c58044c 1265 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
da1e7ac9
AJ
1266 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1267 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1268 /* Magnitude subtraction of infinities */
1269 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1270 } else {
1271 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1272 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1273 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1274 }
e864cabd 1275#else
7c58044c 1276 /* This is OK on x86 hosts */
af12906f 1277 farg1.d = (farg1.d * farg2.d) + farg3.d;
e864cabd 1278#endif
7c58044c 1279 }
af12906f
AJ
1280#else
1281 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1282 farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
1283#endif
1284 return farg1.ll;
e864cabd
JM
1285}
1286
af12906f
AJ
1287/* fmsub - fmsub. */
1288uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
e864cabd 1289{
af12906f
AJ
1290 CPU_DoubleU farg1, farg2, farg3;
1291
1292 farg1.ll = arg1;
1293 farg2.ll = arg2;
1294 farg3.ll = arg3;
1295#if USE_PRECISE_EMULATION
1296 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1297 float64_is_signaling_nan(farg2.d) ||
1298 float64_is_signaling_nan(farg3.d))) {
7c58044c 1299 /* sNaN operation */
af12906f 1300 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
da1e7ac9
AJ
1301 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1302 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1303 /* Multiplication of zero by infinity */
1304 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
7c58044c 1305 } else {
e864cabd 1306#ifdef FLOAT128
7c58044c
JM
1307 /* This is the way the PowerPC specification defines it */
1308 float128 ft0_128, ft1_128;
1309
af12906f
AJ
1310 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1311 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
7c58044c 1312 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
da1e7ac9
AJ
1313 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1314 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1315 /* Magnitude subtraction of infinities */
1316 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1317 } else {
1318 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1319 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1320 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1321 }
e864cabd 1322#else
7c58044c 1323 /* This is OK on x86 hosts */
af12906f 1324 farg1.d = (farg1.d * farg2.d) - farg3.d;
e864cabd 1325#endif
7c58044c 1326 }
af12906f
AJ
1327#else
1328 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1329 farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
1330#endif
1331 return farg1.ll;
e864cabd 1332}
e864cabd 1333
af12906f
AJ
1334/* fnmadd - fnmadd. */
1335uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
4b3686fa 1336{
af12906f
AJ
1337 CPU_DoubleU farg1, farg2, farg3;
1338
1339 farg1.ll = arg1;
1340 farg2.ll = arg2;
1341 farg3.ll = arg3;
1342
1343 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1344 float64_is_signaling_nan(farg2.d) ||
1345 float64_is_signaling_nan(farg3.d))) {
7c58044c 1346 /* sNaN operation */
af12906f 1347 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
da1e7ac9
AJ
1348 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1349 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1350 /* Multiplication of zero by infinity */
1351 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
7c58044c 1352 } else {
1cdb9c3d 1353#if USE_PRECISE_EMULATION
e864cabd 1354#ifdef FLOAT128
7c58044c
JM
1355 /* This is the way the PowerPC specification defines it */
1356 float128 ft0_128, ft1_128;
1357
af12906f
AJ
1358 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1359 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
7c58044c 1360 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
da1e7ac9
AJ
1361 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1362 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1363 /* Magnitude subtraction of infinities */
1364 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1365 } else {
1366 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1367 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1368 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1369 }
e864cabd 1370#else
7c58044c 1371 /* This is OK on x86 hosts */
af12906f 1372 farg1.d = (farg1.d * farg2.d) + farg3.d;
e864cabd
JM
1373#endif
1374#else
af12906f
AJ
1375 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1376 farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
e864cabd 1377#endif
a44d2ce1 1378 if (likely(!float64_is_nan(farg1.d)))
af12906f 1379 farg1.d = float64_chs(farg1.d);
7c58044c 1380 }
af12906f 1381 return farg1.ll;
4b3686fa
FB
1382}
1383
af12906f
AJ
1384/* fnmsub - fnmsub. */
1385uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
4b3686fa 1386{
af12906f
AJ
1387 CPU_DoubleU farg1, farg2, farg3;
1388
1389 farg1.ll = arg1;
1390 farg2.ll = arg2;
1391 farg3.ll = arg3;
1392
1393 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1394 float64_is_signaling_nan(farg2.d) ||
1395 float64_is_signaling_nan(farg3.d))) {
7c58044c 1396 /* sNaN operation */
af12906f 1397 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
da1e7ac9
AJ
1398 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1399 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1400 /* Multiplication of zero by infinity */
1401 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
7c58044c 1402 } else {
1cdb9c3d 1403#if USE_PRECISE_EMULATION
e864cabd 1404#ifdef FLOAT128
7c58044c
JM
1405 /* This is the way the PowerPC specification defines it */
1406 float128 ft0_128, ft1_128;
1407
af12906f
AJ
1408 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1409 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
7c58044c 1410 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
da1e7ac9
AJ
1411 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1412 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1413 /* Magnitude subtraction of infinities */
1414 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1415 } else {
1416 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1417 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1418 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1419 }
e864cabd 1420#else
7c58044c 1421 /* This is OK on x86 hosts */
af12906f 1422 farg1.d = (farg1.d * farg2.d) - farg3.d;
e864cabd
JM
1423#endif
1424#else
af12906f
AJ
1425 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1426 farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
e864cabd 1427#endif
a44d2ce1 1428 if (likely(!float64_is_nan(farg1.d)))
af12906f 1429 farg1.d = float64_chs(farg1.d);
7c58044c 1430 }
af12906f 1431 return farg1.ll;
1ef59d0a
FB
1432}
1433
af12906f
AJ
1434/* frsp - frsp. */
1435uint64_t helper_frsp (uint64_t arg)
7c58044c 1436{
af12906f 1437 CPU_DoubleU farg;
6ad193ed 1438 float32 f32;
af12906f
AJ
1439 farg.ll = arg;
1440
1441#if USE_PRECISE_EMULATION
1442 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1443 /* sNaN square root */
af12906f 1444 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
7c58044c 1445 } else {
6ad193ed
AJ
1446 f32 = float64_to_float32(farg.d, &env->fp_status);
1447 farg.d = float32_to_float64(f32, &env->fp_status);
7c58044c 1448 }
af12906f 1449#else
6ad193ed
AJ
1450 f32 = float64_to_float32(farg.d, &env->fp_status);
1451 farg.d = float32_to_float64(f32, &env->fp_status);
af12906f
AJ
1452#endif
1453 return farg.ll;
7c58044c 1454}
7c58044c 1455
af12906f
AJ
1456/* fsqrt - fsqrt. */
1457uint64_t helper_fsqrt (uint64_t arg)
9a64fbe4 1458{
af12906f
AJ
1459 CPU_DoubleU farg;
1460 farg.ll = arg;
1461
1462 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1463 /* sNaN square root */
af12906f 1464 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
f23c346e 1465 } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
7c58044c 1466 /* Square root of a negative nonzero number */
af12906f 1467 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
7c58044c 1468 } else {
af12906f 1469 farg.d = float64_sqrt(farg.d, &env->fp_status);
7c58044c 1470 }
af12906f 1471 return farg.ll;
9a64fbe4
FB
1472}
1473
af12906f
AJ
1474/* fre - fre. */
1475uint64_t helper_fre (uint64_t arg)
d7e4b87e 1476{
c609b12e 1477 CPU_DoubleU farg;
06f7332a 1478 farg.ll = arg;
d7e4b87e 1479
af12906f 1480 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1481 /* sNaN reciprocal */
af12906f 1482 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
d7e4b87e 1483 } else {
c609b12e 1484 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
d7e4b87e 1485 }
af12906f 1486 return farg.d;
d7e4b87e
JM
1487}
1488
af12906f
AJ
1489/* fres - fres. */
1490uint64_t helper_fres (uint64_t arg)
9a64fbe4 1491{
06f7332a 1492 CPU_DoubleU farg;
6c01bf6c 1493 float32 f32;
06f7332a 1494 farg.ll = arg;
4ecc3190 1495
af12906f 1496 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1497 /* sNaN reciprocal */
af12906f 1498 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
4ecc3190 1499 } else {
c609b12e 1500 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
6c01bf6c
AJ
1501 f32 = float64_to_float32(farg.d, &env->fp_status);
1502 farg.d = float32_to_float64(f32, &env->fp_status);
4ecc3190 1503 }
af12906f 1504 return farg.ll;
9a64fbe4
FB
1505}
1506
af12906f
AJ
1507/* frsqrte - frsqrte. */
1508uint64_t helper_frsqrte (uint64_t arg)
9a64fbe4 1509{
c609b12e 1510 CPU_DoubleU farg;
6c01bf6c 1511 float32 f32;
06f7332a 1512 farg.ll = arg;
4ecc3190 1513
af12906f 1514 if (unlikely(float64_is_signaling_nan(farg.d))) {
7c58044c 1515 /* sNaN reciprocal square root */
af12906f 1516 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
f23c346e 1517 } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
7c58044c 1518 /* Reciprocal square root of a negative nonzero number */
af12906f 1519 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
4ecc3190 1520 } else {
6c01bf6c 1521 farg.d = float64_sqrt(farg.d, &env->fp_status);
c609b12e 1522 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
6c01bf6c
AJ
1523 f32 = float64_to_float32(farg.d, &env->fp_status);
1524 farg.d = float32_to_float64(f32, &env->fp_status);
4ecc3190 1525 }
af12906f 1526 return farg.ll;
9a64fbe4
FB
1527}
1528
af12906f
AJ
1529/* fsel - fsel. */
1530uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
9a64fbe4 1531{
6ad7365a 1532 CPU_DoubleU farg1;
af12906f
AJ
1533
1534 farg1.ll = arg1;
af12906f 1535
572c8952 1536 if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_nan(farg1.d))
6ad7365a 1537 return arg2;
4ecc3190 1538 else
6ad7365a 1539 return arg3;
9a64fbe4
FB
1540}
1541
9a819377 1542void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
9a64fbe4 1543{
af12906f 1544 CPU_DoubleU farg1, farg2;
e1571908 1545 uint32_t ret = 0;
af12906f
AJ
1546 farg1.ll = arg1;
1547 farg2.ll = arg2;
e1571908 1548
9a819377
AJ
1549 if (unlikely(float64_is_nan(farg1.d) ||
1550 float64_is_nan(farg2.d))) {
1551 ret = 0x01UL;
1552 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1553 ret = 0x08UL;
1554 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1555 ret = 0x04UL;
7c58044c 1556 } else {
9a819377 1557 ret = 0x02UL;
9a64fbe4 1558 }
9a819377 1559
7c58044c 1560 env->fpscr &= ~(0x0F << FPSCR_FPRF);
e1571908 1561 env->fpscr |= ret << FPSCR_FPRF;
9a819377
AJ
1562 env->crf[crfD] = ret;
1563 if (unlikely(ret == 0x01UL
1564 && (float64_is_signaling_nan(farg1.d) ||
1565 float64_is_signaling_nan(farg2.d)))) {
1566 /* sNaN comparison */
1567 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1568 }
9a64fbe4
FB
1569}
1570
9a819377 1571void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
9a64fbe4 1572{
af12906f 1573 CPU_DoubleU farg1, farg2;
e1571908 1574 uint32_t ret = 0;
af12906f
AJ
1575 farg1.ll = arg1;
1576 farg2.ll = arg2;
e1571908 1577
af12906f
AJ
1578 if (unlikely(float64_is_nan(farg1.d) ||
1579 float64_is_nan(farg2.d))) {
9a819377
AJ
1580 ret = 0x01UL;
1581 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1582 ret = 0x08UL;
1583 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1584 ret = 0x04UL;
1585 } else {
1586 ret = 0x02UL;
1587 }
1588
1589 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1590 env->fpscr |= ret << FPSCR_FPRF;
1591 env->crf[crfD] = ret;
1592 if (unlikely (ret == 0x01UL)) {
af12906f
AJ
1593 if (float64_is_signaling_nan(farg1.d) ||
1594 float64_is_signaling_nan(farg2.d)) {
7c58044c
JM
1595 /* sNaN comparison */
1596 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1597 POWERPC_EXCP_FP_VXVC);
1598 } else {
1599 /* qNaN comparison */
1600 fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
1601 }
9a64fbe4 1602 }
9a64fbe4
FB
1603}
1604
76a66253 1605#if !defined (CONFIG_USER_ONLY)
6527f6ea 1606void helper_store_msr (target_ulong val)
0411a972 1607{
6527f6ea
AJ
1608 val = hreg_store_msr(env, val, 0);
1609 if (val != 0) {
0411a972 1610 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
e06fcd75 1611 helper_raise_exception(val);
0411a972
JM
1612 }
1613}
1614
636aa200
BS
1615static inline void do_rfi(target_ulong nip, target_ulong msr,
1616 target_ulong msrm, int keep_msrh)
9a64fbe4 1617{
426613db 1618#if defined(TARGET_PPC64)
0411a972
JM
1619 if (msr & (1ULL << MSR_SF)) {
1620 nip = (uint64_t)nip;
1621 msr &= (uint64_t)msrm;
a42bd6cc 1622 } else {
0411a972
JM
1623 nip = (uint32_t)nip;
1624 msr = (uint32_t)(msr & msrm);
1625 if (keep_msrh)
1626 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
a42bd6cc 1627 }
426613db 1628#else
0411a972
JM
1629 nip = (uint32_t)nip;
1630 msr &= (uint32_t)msrm;
426613db 1631#endif
0411a972
JM
1632 /* XXX: beware: this is false if VLE is supported */
1633 env->nip = nip & ~((target_ulong)0x00000003);
a4f30719 1634 hreg_store_msr(env, msr, 1);
fdabc366 1635#if defined (DEBUG_OP)
0411a972 1636 cpu_dump_rfi(env->nip, env->msr);
fdabc366 1637#endif
0411a972
JM
1638 /* No need to raise an exception here,
1639 * as rfi is always the last insn of a TB
1640 */
fdabc366 1641 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
9a64fbe4 1642}
d9bce9d9 1643
d72a19f7 1644void helper_rfi (void)
0411a972 1645{
d72a19f7 1646 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
c3d420ea 1647 ~((target_ulong)0x783F0000), 1);
0411a972
JM
1648}
1649
d9bce9d9 1650#if defined(TARGET_PPC64)
d72a19f7 1651void helper_rfid (void)
426613db 1652{
d72a19f7 1653 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
c3d420ea 1654 ~((target_ulong)0x783F0000), 0);
d9bce9d9 1655}
7863667f 1656
d72a19f7 1657void helper_hrfid (void)
be147d08 1658{
d72a19f7 1659 do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
c3d420ea 1660 ~((target_ulong)0x783F0000), 0);
be147d08
JM
1661}
1662#endif
76a66253 1663#endif
9a64fbe4 1664
cab3bee2 1665void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
9a64fbe4 1666{
cab3bee2
AJ
1667 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1668 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1669 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1670 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1671 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
e06fcd75 1672 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
a42bd6cc 1673 }
9a64fbe4
FB
1674}
1675
d9bce9d9 1676#if defined(TARGET_PPC64)
cab3bee2 1677void helper_td (target_ulong arg1, target_ulong arg2, uint32_t flags)
d9bce9d9 1678{
cab3bee2
AJ
1679 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1680 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1681 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1682 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1683 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01)))))
e06fcd75 1684 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
d9bce9d9
JM
1685}
1686#endif
1687
fdabc366 1688/*****************************************************************************/
76a66253 1689/* PowerPC 601 specific instructions (POWER bridge) */
9a64fbe4 1690
22e0e173 1691target_ulong helper_clcs (uint32_t arg)
9a64fbe4 1692{
22e0e173 1693 switch (arg) {
76a66253
JM
1694 case 0x0CUL:
1695 /* Instruction cache line size */
22e0e173 1696 return env->icache_line_size;
76a66253
JM
1697 break;
1698 case 0x0DUL:
1699 /* Data cache line size */
22e0e173 1700 return env->dcache_line_size;
76a66253
JM
1701 break;
1702 case 0x0EUL:
1703 /* Minimum cache line size */
22e0e173
AJ
1704 return (env->icache_line_size < env->dcache_line_size) ?
1705 env->icache_line_size : env->dcache_line_size;
76a66253
JM
1706 break;
1707 case 0x0FUL:
1708 /* Maximum cache line size */
22e0e173
AJ
1709 return (env->icache_line_size > env->dcache_line_size) ?
1710 env->icache_line_size : env->dcache_line_size;
76a66253
JM
1711 break;
1712 default:
1713 /* Undefined */
22e0e173 1714 return 0;
76a66253
JM
1715 break;
1716 }
1717}
1718
22e0e173 1719target_ulong helper_div (target_ulong arg1, target_ulong arg2)
76a66253 1720{
22e0e173 1721 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
76a66253 1722
22e0e173
AJ
1723 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1724 (int32_t)arg2 == 0) {
76a66253 1725 env->spr[SPR_MQ] = 0;
22e0e173 1726 return INT32_MIN;
76a66253 1727 } else {
22e0e173
AJ
1728 env->spr[SPR_MQ] = tmp % arg2;
1729 return tmp / (int32_t)arg2;
76a66253
JM
1730 }
1731}
1732
22e0e173 1733target_ulong helper_divo (target_ulong arg1, target_ulong arg2)
76a66253 1734{
22e0e173 1735 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
76a66253 1736
22e0e173
AJ
1737 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1738 (int32_t)arg2 == 0) {
3d7b417e 1739 env->xer |= (1 << XER_OV) | (1 << XER_SO);
76a66253 1740 env->spr[SPR_MQ] = 0;
22e0e173 1741 return INT32_MIN;
76a66253 1742 } else {
22e0e173
AJ
1743 env->spr[SPR_MQ] = tmp % arg2;
1744 tmp /= (int32_t)arg2;
1745 if ((int32_t)tmp != tmp) {
3d7b417e 1746 env->xer |= (1 << XER_OV) | (1 << XER_SO);
76a66253 1747 } else {
3d7b417e 1748 env->xer &= ~(1 << XER_OV);
76a66253 1749 }
22e0e173 1750 return tmp;
76a66253
JM
1751 }
1752}
1753
22e0e173 1754target_ulong helper_divs (target_ulong arg1, target_ulong arg2)
76a66253 1755{
22e0e173
AJ
1756 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1757 (int32_t)arg2 == 0) {
1758 env->spr[SPR_MQ] = 0;
1759 return INT32_MIN;
76a66253 1760 } else {
22e0e173
AJ
1761 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1762 return (int32_t)arg1 / (int32_t)arg2;
76a66253 1763 }
76a66253
JM
1764}
1765
22e0e173 1766target_ulong helper_divso (target_ulong arg1, target_ulong arg2)
76a66253 1767{
22e0e173
AJ
1768 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1769 (int32_t)arg2 == 0) {
3d7b417e 1770 env->xer |= (1 << XER_OV) | (1 << XER_SO);
22e0e173
AJ
1771 env->spr[SPR_MQ] = 0;
1772 return INT32_MIN;
76a66253 1773 } else {
3d7b417e 1774 env->xer &= ~(1 << XER_OV);
22e0e173
AJ
1775 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1776 return (int32_t)arg1 / (int32_t)arg2;
76a66253
JM
1777 }
1778}
1779
1780#if !defined (CONFIG_USER_ONLY)
22e0e173 1781target_ulong helper_rac (target_ulong addr)
76a66253 1782{
c227f099 1783 mmu_ctx_t ctx;
faadf50e 1784 int nb_BATs;
22e0e173 1785 target_ulong ret = 0;
76a66253
JM
1786
1787 /* We don't have to generate many instances of this instruction,
1788 * as rac is supervisor only.
1789 */
faadf50e
JM
1790 /* XXX: FIX THIS: Pretend we have no BAT */
1791 nb_BATs = env->nb_BATs;
1792 env->nb_BATs = 0;
22e0e173
AJ
1793 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0)
1794 ret = ctx.raddr;
faadf50e 1795 env->nb_BATs = nb_BATs;
22e0e173 1796 return ret;
76a66253
JM
1797}
1798
d72a19f7 1799void helper_rfsvc (void)
76a66253 1800{
d72a19f7 1801 do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
76a66253 1802}
76a66253
JM
1803#endif
1804
1805/*****************************************************************************/
1806/* 602 specific instructions */
1807/* mfrom is the most crazy instruction ever seen, imho ! */
1808/* Real implementation uses a ROM table. Do the same */
5e9ae189
AJ
1809/* Extremly decomposed:
1810 * -arg / 256
1811 * return 256 * log10(10 + 1.0) + 0.5
1812 */
db9a16a7 1813#if !defined (CONFIG_USER_ONLY)
cf02a65c 1814target_ulong helper_602_mfrom (target_ulong arg)
76a66253 1815{
cf02a65c 1816 if (likely(arg < 602)) {
76a66253 1817#include "mfrom_table.c"
45d827d2 1818 return mfrom_ROM_table[arg];
76a66253 1819 } else {
cf02a65c 1820 return 0;
76a66253
JM
1821 }
1822}
db9a16a7 1823#endif
76a66253
JM
1824
1825/*****************************************************************************/
1826/* Embedded PowerPC specific helpers */
76a66253 1827
a750fc0b 1828/* XXX: to be improved to check access rights when in user-mode */
95ff895f 1829target_ulong helper_load_dcr (target_ulong dcrn)
a750fc0b 1830{
73b01960 1831 uint32_t val = 0;
a750fc0b
JM
1832
1833 if (unlikely(env->dcr_env == NULL)) {
93fcfe39 1834 qemu_log("No DCR environment\n");
e06fcd75
AJ
1835 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1836 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
95ff895f
AJ
1837 } else if (unlikely(ppc_dcr_read(env->dcr_env, (uint32_t)dcrn, &val) != 0)) {
1838 qemu_log("DCR read error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
e06fcd75
AJ
1839 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1840 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
a750fc0b 1841 }
06dca6a7 1842 return val;
a750fc0b
JM
1843}
1844
95ff895f 1845void helper_store_dcr (target_ulong dcrn, target_ulong val)
a750fc0b
JM
1846{
1847 if (unlikely(env->dcr_env == NULL)) {
93fcfe39 1848 qemu_log("No DCR environment\n");
e06fcd75
AJ
1849 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1850 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
95ff895f
AJ
1851 } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn, (uint32_t)val) != 0)) {
1852 qemu_log("DCR write error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
e06fcd75
AJ
1853 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1854 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
a750fc0b
JM
1855 }
1856}
1857
76a66253 1858#if !defined(CONFIG_USER_ONLY)
d72a19f7 1859void helper_40x_rfci (void)
76a66253 1860{
d72a19f7
AJ
1861 do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
1862 ~((target_ulong)0xFFFF0000), 0);
a42bd6cc
JM
1863}
1864
d72a19f7 1865void helper_rfci (void)
a42bd6cc 1866{
d72a19f7
AJ
1867 do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
1868 ~((target_ulong)0x3FFF0000), 0);
a42bd6cc
JM
1869}
1870
d72a19f7 1871void helper_rfdi (void)
a42bd6cc 1872{
d72a19f7
AJ
1873 do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
1874 ~((target_ulong)0x3FFF0000), 0);
a42bd6cc
JM
1875}
1876
d72a19f7 1877void helper_rfmci (void)
a42bd6cc 1878{
d72a19f7
AJ
1879 do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
1880 ~((target_ulong)0x3FFF0000), 0);
76a66253 1881}
76a66253
JM
1882#endif
1883
1884/* 440 specific */
ef0d51af 1885target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
76a66253
JM
1886{
1887 target_ulong mask;
1888 int i;
1889
1890 i = 1;
1891 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
ef0d51af
AJ
1892 if ((high & mask) == 0) {
1893 if (update_Rc) {
1894 env->crf[0] = 0x4;
1895 }
76a66253 1896 goto done;
ef0d51af 1897 }
76a66253
JM
1898 i++;
1899 }
1900 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
ef0d51af
AJ
1901 if ((low & mask) == 0) {
1902 if (update_Rc) {
1903 env->crf[0] = 0x8;
1904 }
1905 goto done;
1906 }
76a66253
JM
1907 i++;
1908 }
ef0d51af
AJ
1909 if (update_Rc) {
1910 env->crf[0] = 0x2;
1911 }
76a66253 1912 done:
ef0d51af
AJ
1913 env->xer = (env->xer & ~0x7F) | i;
1914 if (update_Rc) {
1915 env->crf[0] |= xer_so;
1916 }
1917 return i;
fdabc366
FB
1918}
1919
d6a46fe8
AJ
1920/*****************************************************************************/
1921/* Altivec extension helpers */
e2542fe2 1922#if defined(HOST_WORDS_BIGENDIAN)
d6a46fe8
AJ
1923#define HI_IDX 0
1924#define LO_IDX 1
1925#else
1926#define HI_IDX 1
1927#define LO_IDX 0
1928#endif
1929
e2542fe2 1930#if defined(HOST_WORDS_BIGENDIAN)
d6a46fe8
AJ
1931#define VECTOR_FOR_INORDER_I(index, element) \
1932 for (index = 0; index < ARRAY_SIZE(r->element); index++)
1933#else
1934#define VECTOR_FOR_INORDER_I(index, element) \
1935 for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
1936#endif
1937
34ba2857
AJ
1938/* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise,
1939 * execute the following block. */
1940#define DO_HANDLE_NAN(result, x) \
1941 if (float32_is_nan(x) || float32_is_signaling_nan(x)) { \
1942 CPU_FloatU __f; \
1943 __f.f = x; \
1944 __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \
1945 result = __f.f; \
1946 } else
1947
1948#define HANDLE_NAN1(result, x) \
1949 DO_HANDLE_NAN(result, x)
1950#define HANDLE_NAN2(result, x, y) \
1951 DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y)
1952#define HANDLE_NAN3(result, x, y, z) \
1953 DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z)
1954
00d3b8f5 1955/* Saturating arithmetic helpers. */
d62d2863 1956#define SATCVT(from, to, from_type, to_type, min, max) \
636aa200 1957 static inline to_type cvt##from##to(from_type x, int *sat) \
00d3b8f5
AJ
1958 { \
1959 to_type r; \
d62d2863 1960 if (x < (from_type)min) { \
00d3b8f5
AJ
1961 r = min; \
1962 *sat = 1; \
d62d2863 1963 } else if (x > (from_type)max) { \
00d3b8f5
AJ
1964 r = max; \
1965 *sat = 1; \
1966 } else { \
1967 r = x; \
1968 } \
1969 return r; \
1970 }
d62d2863
BS
1971#define SATCVTU(from, to, from_type, to_type, min, max) \
1972 static inline to_type cvt##from##to(from_type x, int *sat) \
1973 { \
1974 to_type r; \
1975 if (x > (from_type)max) { \
1976 r = max; \
1977 *sat = 1; \
1978 } else { \
1979 r = x; \
1980 } \
1981 return r; \
c5b76b38 1982 }
d62d2863
BS
1983SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
1984SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
1985SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX)
1986
1987SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX)
1988SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX)
1989SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX)
1990SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX)
1991SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX)
1992SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
00d3b8f5 1993#undef SATCVT
d62d2863 1994#undef SATCVTU
00d3b8f5 1995
cbfb6ae9 1996#define LVE(name, access, swap, element) \
c227f099 1997 void helper_##name (ppc_avr_t *r, target_ulong addr) \
cbfb6ae9
AJ
1998 { \
1999 size_t n_elems = ARRAY_SIZE(r->element); \
2000 int adjust = HI_IDX*(n_elems-1); \
2001 int sh = sizeof(r->element[0]) >> 1; \
2002 int index = (addr & 0xf) >> sh; \
2003 if(msr_le) { \
2004 r->element[LO_IDX ? index : (adjust - index)] = swap(access(addr)); \
2005 } else { \
2006 r->element[LO_IDX ? index : (adjust - index)] = access(addr); \
2007 } \
2008 }
2009#define I(x) (x)
2010LVE(lvebx, ldub, I, u8)
2011LVE(lvehx, lduw, bswap16, u16)
2012LVE(lvewx, ldl, bswap32, u32)
2013#undef I
2014#undef LVE
2015
c227f099 2016void helper_lvsl (ppc_avr_t *r, target_ulong sh)
bf8d8ded
AJ
2017{
2018 int i, j = (sh & 0xf);
2019
2020 VECTOR_FOR_INORDER_I (i, u8) {
2021 r->u8[i] = j++;
2022 }
2023}
2024
c227f099 2025void helper_lvsr (ppc_avr_t *r, target_ulong sh)
bf8d8ded
AJ
2026{
2027 int i, j = 0x10 - (sh & 0xf);
2028
2029 VECTOR_FOR_INORDER_I (i, u8) {
2030 r->u8[i] = j++;
2031 }
2032}
2033
cbfb6ae9 2034#define STVE(name, access, swap, element) \
c227f099 2035 void helper_##name (ppc_avr_t *r, target_ulong addr) \
cbfb6ae9
AJ
2036 { \
2037 size_t n_elems = ARRAY_SIZE(r->element); \
2038 int adjust = HI_IDX*(n_elems-1); \
2039 int sh = sizeof(r->element[0]) >> 1; \
2040 int index = (addr & 0xf) >> sh; \
2041 if(msr_le) { \
2042 access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \
2043 } else { \
2044 access(addr, r->element[LO_IDX ? index : (adjust - index)]); \
2045 } \
2046 }
2047#define I(x) (x)
2048STVE(stvebx, stb, I, u8)
2049STVE(stvehx, stw, bswap16, u16)
2050STVE(stvewx, stl, bswap32, u32)
2051#undef I
2052#undef LVE
2053
c227f099 2054void helper_mtvscr (ppc_avr_t *r)
6e87b7c7 2055{
e2542fe2 2056#if defined(HOST_WORDS_BIGENDIAN)
6e87b7c7
AJ
2057 env->vscr = r->u32[3];
2058#else
2059 env->vscr = r->u32[0];
2060#endif
2061 set_flush_to_zero(vscr_nj, &env->vec_status);
2062}
2063
c227f099 2064void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
e343da72
AJ
2065{
2066 int i;
2067 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2068 r->u32[i] = ~a->u32[i] < b->u32[i];
2069 }
2070}
2071
c227f099
AL
2072#define VARITH_DO(name, op, element) \
2073void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2074{ \
2075 int i; \
2076 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2077 r->element[i] = a->element[i] op b->element[i]; \
2078 } \
7872c51c
AJ
2079}
2080#define VARITH(suffix, element) \
2081 VARITH_DO(add##suffix, +, element) \
2082 VARITH_DO(sub##suffix, -, element)
2083VARITH(ubm, u8)
2084VARITH(uhm, u16)
2085VARITH(uwm, u32)
2086#undef VARITH_DO
2087#undef VARITH
2088
56fdd213 2089#define VARITHFP(suffix, func) \
c227f099 2090 void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
56fdd213
AJ
2091 { \
2092 int i; \
2093 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2094 HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
2095 r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \
2096 } \
2097 } \
2098 }
2099VARITHFP(addfp, float32_add)
2100VARITHFP(subfp, float32_sub)
2101#undef VARITHFP
2102
5ab09f33
AJ
2103#define VARITHSAT_CASE(type, op, cvt, element) \
2104 { \
2105 type result = (type)a->element[i] op (type)b->element[i]; \
2106 r->element[i] = cvt(result, &sat); \
2107 }
2108
2109#define VARITHSAT_DO(name, op, optype, cvt, element) \
c227f099 2110 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
5ab09f33
AJ
2111 { \
2112 int sat = 0; \
2113 int i; \
2114 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2115 switch (sizeof(r->element[0])) { \
2116 case 1: VARITHSAT_CASE(optype, op, cvt, element); break; \
2117 case 2: VARITHSAT_CASE(optype, op, cvt, element); break; \
2118 case 4: VARITHSAT_CASE(optype, op, cvt, element); break; \
2119 } \
2120 } \
2121 if (sat) { \
2122 env->vscr |= (1 << VSCR_SAT); \
2123 } \
2124 }
2125#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
2126 VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
2127 VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
2128#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
2129 VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
2130 VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
2131VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
2132VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
2133VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
2134VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
2135VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
2136VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
2137#undef VARITHSAT_CASE
2138#undef VARITHSAT_DO
2139#undef VARITHSAT_SIGNED
2140#undef VARITHSAT_UNSIGNED
2141
fab3cbe9 2142#define VAVG_DO(name, element, etype) \
c227f099 2143 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
fab3cbe9
AJ
2144 { \
2145 int i; \
2146 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2147 etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
2148 r->element[i] = x >> 1; \
2149 } \
2150 }
2151
2152#define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
2153 VAVG_DO(avgs##type, signed_element, signed_type) \
2154 VAVG_DO(avgu##type, unsigned_element, unsigned_type)
2155VAVG(b, s8, int16_t, u8, uint16_t)
2156VAVG(h, s16, int32_t, u16, uint32_t)
2157VAVG(w, s32, int64_t, u32, uint64_t)
2158#undef VAVG_DO
2159#undef VAVG
2160
e140632e 2161#define VCF(suffix, cvt, element) \
c227f099 2162 void helper_vcf##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
e140632e
AJ
2163 { \
2164 int i; \
2165 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2166 float32 t = cvt(b->element[i], &env->vec_status); \
2167 r->f[i] = float32_scalbn (t, -uim, &env->vec_status); \
2168 } \
2169 }
2170VCF(ux, uint32_to_float32, u32)
2171VCF(sx, int32_to_float32, s32)
2172#undef VCF
2173
1add6e23 2174#define VCMP_DO(suffix, compare, element, record) \
c227f099 2175 void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1add6e23
AJ
2176 { \
2177 uint32_t ones = (uint32_t)-1; \
2178 uint32_t all = ones; \
2179 uint32_t none = 0; \
2180 int i; \
2181 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2182 uint32_t result = (a->element[i] compare b->element[i] ? ones : 0x0); \
2183 switch (sizeof (a->element[0])) { \
2184 case 4: r->u32[i] = result; break; \
2185 case 2: r->u16[i] = result; break; \
2186 case 1: r->u8[i] = result; break; \
2187 } \
2188 all &= result; \
2189 none |= result; \
2190 } \
2191 if (record) { \
2192 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
2193 } \
2194 }
2195#define VCMP(suffix, compare, element) \
2196 VCMP_DO(suffix, compare, element, 0) \
2197 VCMP_DO(suffix##_dot, compare, element, 1)
2198VCMP(equb, ==, u8)
2199VCMP(equh, ==, u16)
2200VCMP(equw, ==, u32)
2201VCMP(gtub, >, u8)
2202VCMP(gtuh, >, u16)
2203VCMP(gtuw, >, u32)
2204VCMP(gtsb, >, s8)
2205VCMP(gtsh, >, s16)
2206VCMP(gtsw, >, s32)
2207#undef VCMP_DO
2208#undef VCMP
2209
819ca121 2210#define VCMPFP_DO(suffix, compare, order, record) \
c227f099 2211 void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
819ca121
AJ
2212 { \
2213 uint32_t ones = (uint32_t)-1; \
2214 uint32_t all = ones; \
2215 uint32_t none = 0; \
2216 int i; \
2217 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2218 uint32_t result; \
2219 int rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status); \
2220 if (rel == float_relation_unordered) { \
2221 result = 0; \
2222 } else if (rel compare order) { \
2223 result = ones; \
2224 } else { \
2225 result = 0; \
2226 } \
2227 r->u32[i] = result; \
2228 all &= result; \
2229 none |= result; \
2230 } \
2231 if (record) { \
2232 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
2233 } \
2234 }
2235#define VCMPFP(suffix, compare, order) \
2236 VCMPFP_DO(suffix, compare, order, 0) \
2237 VCMPFP_DO(suffix##_dot, compare, order, 1)
2238VCMPFP(eqfp, ==, float_relation_equal)
2239VCMPFP(gefp, !=, float_relation_less)
2240VCMPFP(gtfp, ==, float_relation_greater)
2241#undef VCMPFP_DO
2242#undef VCMPFP
2243
c227f099 2244static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
636aa200 2245 int record)
819ca121
AJ
2246{
2247 int i;
2248 int all_in = 0;
2249 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2250 int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
2251 if (le_rel == float_relation_unordered) {
2252 r->u32[i] = 0xc0000000;
2253 /* ALL_IN does not need to be updated here. */
2254 } else {
2255 float32 bneg = float32_chs(b->f[i]);
2256 int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
2257 int le = le_rel != float_relation_greater;
2258 int ge = ge_rel != float_relation_less;
2259 r->u32[i] = ((!le) << 31) | ((!ge) << 30);
2260 all_in |= (!le | !ge);
2261 }
2262 }
2263 if (record) {
2264 env->crf[6] = (all_in == 0) << 1;
2265 }
2266}
2267
c227f099 2268void helper_vcmpbfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
819ca121
AJ
2269{
2270 vcmpbfp_internal(r, a, b, 0);
2271}
2272
c227f099 2273void helper_vcmpbfp_dot (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
819ca121
AJ
2274{
2275 vcmpbfp_internal(r, a, b, 1);
2276}
2277
875b31db 2278#define VCT(suffix, satcvt, element) \
c227f099 2279 void helper_vct##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
875b31db
AJ
2280 { \
2281 int i; \
2282 int sat = 0; \
2283 float_status s = env->vec_status; \
2284 set_float_rounding_mode(float_round_to_zero, &s); \
2285 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2286 if (float32_is_nan(b->f[i]) || \
2287 float32_is_signaling_nan(b->f[i])) { \
2288 r->element[i] = 0; \
2289 } else { \
2290 float64 t = float32_to_float64(b->f[i], &s); \
2291 int64_t j; \
2292 t = float64_scalbn(t, uim, &s); \
2293 j = float64_to_int64(t, &s); \
2294 r->element[i] = satcvt(j, &sat); \
2295 } \
2296 } \
2297 if (sat) { \
2298 env->vscr |= (1 << VSCR_SAT); \
2299 } \
2300 }
2301VCT(uxs, cvtsduw, u32)
2302VCT(sxs, cvtsdsw, s32)
2303#undef VCT
2304
c227f099 2305void helper_vmaddfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
35cf7c7e
AJ
2306{
2307 int i;
2308 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2309 HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
2310 /* Need to do the computation in higher precision and round
2311 * once at the end. */
2312 float64 af, bf, cf, t;
2313 af = float32_to_float64(a->f[i], &env->vec_status);
2314 bf = float32_to_float64(b->f[i], &env->vec_status);
2315 cf = float32_to_float64(c->f[i], &env->vec_status);
2316 t = float64_mul(af, cf, &env->vec_status);
2317 t = float64_add(t, bf, &env->vec_status);
2318 r->f[i] = float64_to_float32(t, &env->vec_status);
2319 }
2320 }
2321}
2322
c227f099 2323void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
b161ae27
AJ
2324{
2325 int sat = 0;
2326 int i;
2327
2328 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2329 int32_t prod = a->s16[i] * b->s16[i];
2330 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2331 r->s16[i] = cvtswsh (t, &sat);
2332 }
2333
2334 if (sat) {
2335 env->vscr |= (1 << VSCR_SAT);
2336 }
2337}
2338
c227f099 2339void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
b161ae27
AJ
2340{
2341 int sat = 0;
2342 int i;
2343
2344 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2345 int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
2346 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2347 r->s16[i] = cvtswsh (t, &sat);
2348 }
2349
2350 if (sat) {
2351 env->vscr |= (1 << VSCR_SAT);
2352 }
2353}
2354
e4039339 2355#define VMINMAX_DO(name, compare, element) \
c227f099 2356 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
e4039339
AJ
2357 { \
2358 int i; \
2359 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2360 if (a->element[i] compare b->element[i]) { \
2361 r->element[i] = b->element[i]; \
2362 } else { \
2363 r->element[i] = a->element[i]; \
2364 } \
2365 } \
2366 }
2367#define VMINMAX(suffix, element) \
2368 VMINMAX_DO(min##suffix, >, element) \
2369 VMINMAX_DO(max##suffix, <, element)
2370VMINMAX(sb, s8)
2371VMINMAX(sh, s16)
2372VMINMAX(sw, s32)
2373VMINMAX(ub, u8)
2374VMINMAX(uh, u16)
2375VMINMAX(uw, u32)
2376#undef VMINMAX_DO
2377#undef VMINMAX
2378
1536ff64 2379#define VMINMAXFP(suffix, rT, rF) \
c227f099 2380 void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
1536ff64
AJ
2381 { \
2382 int i; \
2383 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2384 HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
2385 if (float32_lt_quiet(a->f[i], b->f[i], &env->vec_status)) { \
2386 r->f[i] = rT->f[i]; \
2387 } else { \
2388 r->f[i] = rF->f[i]; \
2389 } \
2390 } \
2391 } \
2392 }
2393VMINMAXFP(minfp, a, b)
2394VMINMAXFP(maxfp, b, a)
2395#undef VMINMAXFP
2396
c227f099 2397void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
bcd2ee23
AJ
2398{
2399 int i;
2400 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2401 int32_t prod = a->s16[i] * b->s16[i];
2402 r->s16[i] = (int16_t) (prod + c->s16[i]);
2403 }
2404}
2405
3b430048 2406#define VMRG_DO(name, element, highp) \
c227f099 2407 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
3b430048 2408 { \
c227f099 2409 ppc_avr_t result; \
3b430048
AJ
2410 int i; \
2411 size_t n_elems = ARRAY_SIZE(r->element); \
2412 for (i = 0; i < n_elems/2; i++) { \
2413 if (highp) { \
2414 result.element[i*2+HI_IDX] = a->element[i]; \
2415 result.element[i*2+LO_IDX] = b->element[i]; \
2416 } else { \
2417 result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
2418 result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
2419 } \
2420 } \
2421 *r = result; \
2422 }
e2542fe2 2423#if defined(HOST_WORDS_BIGENDIAN)
3b430048 2424#define MRGHI 0
b392e756 2425#define MRGLO 1
3b430048
AJ
2426#else
2427#define MRGHI 1
2428#define MRGLO 0
2429#endif
2430#define VMRG(suffix, element) \
2431 VMRG_DO(mrgl##suffix, element, MRGHI) \
2432 VMRG_DO(mrgh##suffix, element, MRGLO)
2433VMRG(b, u8)
2434VMRG(h, u16)
2435VMRG(w, u32)
2436#undef VMRG_DO
2437#undef VMRG
2438#undef MRGHI
2439#undef MRGLO
2440
c227f099 2441void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
b04ae981
AJ
2442{
2443 int32_t prod[16];
2444 int i;
2445
2446 for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
2447 prod[i] = (int32_t)a->s8[i] * b->u8[i];
2448 }
2449
2450 VECTOR_FOR_INORDER_I(i, s32) {
2451 r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2452 }
2453}
2454
c227f099 2455void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
eae07261
AJ
2456{
2457 int32_t prod[8];
2458 int i;
2459
2460 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2461 prod[i] = a->s16[i] * b->s16[i];
2462 }
2463
2464 VECTOR_FOR_INORDER_I(i, s32) {
2465 r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1];
2466 }
2467}
2468
c227f099 2469void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
eae07261
AJ
2470{
2471 int32_t prod[8];
2472 int i;
2473 int sat = 0;
2474
2475 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2476 prod[i] = (int32_t)a->s16[i] * b->s16[i];
2477 }
2478
2479 VECTOR_FOR_INORDER_I (i, s32) {
2480 int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1];
2481 r->u32[i] = cvtsdsw(t, &sat);
2482 }
2483
2484 if (sat) {
2485 env->vscr |= (1 << VSCR_SAT);
2486 }
2487}
2488
c227f099 2489void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
b04ae981
AJ
2490{
2491 uint16_t prod[16];
2492 int i;
2493
2494 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2495 prod[i] = a->u8[i] * b->u8[i];
2496 }
2497
2498 VECTOR_FOR_INORDER_I(i, u32) {
2499 r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2500 }
2501}
2502
c227f099 2503void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
4d9903b6
AJ
2504{
2505 uint32_t prod[8];
2506 int i;
2507
2508 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2509 prod[i] = a->u16[i] * b->u16[i];
2510 }
2511
2512 VECTOR_FOR_INORDER_I(i, u32) {
2513 r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1];
2514 }
2515}
2516
c227f099 2517void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
4d9903b6
AJ
2518{
2519 uint32_t prod[8];
2520 int i;
2521 int sat = 0;
2522
2523 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2524 prod[i] = a->u16[i] * b->u16[i];
2525 }
2526
2527 VECTOR_FOR_INORDER_I (i, s32) {
2528 uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1];
2529 r->u32[i] = cvtuduw(t, &sat);
2530 }
2531
2532 if (sat) {
2533 env->vscr |= (1 << VSCR_SAT);
2534 }
2535}
2536
2c277908 2537#define VMUL_DO(name, mul_element, prod_element, evenp) \
c227f099 2538 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2c277908
AJ
2539 { \
2540 int i; \
2541 VECTOR_FOR_INORDER_I(i, prod_element) { \
2542 if (evenp) { \
2543 r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2544 } else { \
2545 r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2546 } \
2547 } \
2548 }
2549#define VMUL(suffix, mul_element, prod_element) \
2550 VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2551 VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2552VMUL(sb, s8, s16)
2553VMUL(sh, s16, s32)
2554VMUL(ub, u8, u16)
2555VMUL(uh, u16, u32)
2556#undef VMUL_DO
2557#undef VMUL
2558
c227f099 2559void helper_vnmsubfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
35cf7c7e
AJ
2560{
2561 int i;
2562 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2563 HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
2564 /* Need to do the computation is higher precision and round
2565 * once at the end. */
2566 float64 af, bf, cf, t;
2567 af = float32_to_float64(a->f[i], &env->vec_status);
2568 bf = float32_to_float64(b->f[i], &env->vec_status);
2569 cf = float32_to_float64(c->f[i], &env->vec_status);
2570 t = float64_mul(af, cf, &env->vec_status);
2571 t = float64_sub(t, bf, &env->vec_status);
2572 t = float64_chs(t);
2573 r->f[i] = float64_to_float32(t, &env->vec_status);
2574 }
2575 }
2576}
2577
c227f099 2578void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
d1258698 2579{
c227f099 2580 ppc_avr_t result;
d1258698
AJ
2581 int i;
2582 VECTOR_FOR_INORDER_I (i, u8) {
2583 int s = c->u8[i] & 0x1f;
e2542fe2 2584#if defined(HOST_WORDS_BIGENDIAN)
d1258698
AJ
2585 int index = s & 0xf;
2586#else
2587 int index = 15 - (s & 0xf);
2588#endif
2589 if (s & 0x10) {
2590 result.u8[i] = b->u8[index];
2591 } else {
2592 result.u8[i] = a->u8[index];
2593 }
2594 }
2595 *r = result;
2596}
2597
e2542fe2 2598#if defined(HOST_WORDS_BIGENDIAN)
5335a145
AJ
2599#define PKBIG 1
2600#else
2601#define PKBIG 0
2602#endif
c227f099 2603void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1dd9ffb9
AJ
2604{
2605 int i, j;
c227f099 2606 ppc_avr_t result;
e2542fe2 2607#if defined(HOST_WORDS_BIGENDIAN)
c227f099 2608 const ppc_avr_t *x[2] = { a, b };
1dd9ffb9 2609#else
c227f099 2610 const ppc_avr_t *x[2] = { b, a };
1dd9ffb9
AJ
2611#endif
2612
2613 VECTOR_FOR_INORDER_I (i, u64) {
2614 VECTOR_FOR_INORDER_I (j, u32){
2615 uint32_t e = x[i]->u32[j];
2616 result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
2617 ((e >> 6) & 0x3e0) |
2618 ((e >> 3) & 0x1f));
2619 }
2620 }
2621 *r = result;
2622}
2623
5335a145 2624#define VPK(suffix, from, to, cvt, dosat) \
c227f099 2625 void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
5335a145
AJ
2626 { \
2627 int i; \
2628 int sat = 0; \
c227f099
AL
2629 ppc_avr_t result; \
2630 ppc_avr_t *a0 = PKBIG ? a : b; \
2631 ppc_avr_t *a1 = PKBIG ? b : a; \
5335a145
AJ
2632 VECTOR_FOR_INORDER_I (i, from) { \
2633 result.to[i] = cvt(a0->from[i], &sat); \
2634 result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
2635 } \
2636 *r = result; \
2637 if (dosat && sat) { \
2638 env->vscr |= (1 << VSCR_SAT); \
2639 } \
2640 }
2641#define I(x, y) (x)
2642VPK(shss, s16, s8, cvtshsb, 1)
2643VPK(shus, s16, u8, cvtshub, 1)
2644VPK(swss, s32, s16, cvtswsh, 1)
2645VPK(swus, s32, u16, cvtswuh, 1)
2646VPK(uhus, u16, u8, cvtuhub, 1)
2647VPK(uwus, u32, u16, cvtuwuh, 1)
2648VPK(uhum, u16, u8, I, 0)
2649VPK(uwum, u32, u16, I, 0)
2650#undef I
2651#undef VPK
2652#undef PKBIG
2653
c227f099 2654void helper_vrefp (ppc_avr_t *r, ppc_avr_t *b)
bdfbac35
AJ
2655{
2656 int i;
2657 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2658 HANDLE_NAN1(r->f[i], b->f[i]) {
2659 r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
2660 }
2661 }
2662}
2663
f6b19645 2664#define VRFI(suffix, rounding) \
c227f099 2665 void helper_vrfi##suffix (ppc_avr_t *r, ppc_avr_t *b) \
f6b19645
AJ
2666 { \
2667 int i; \
2668 float_status s = env->vec_status; \
2669 set_float_rounding_mode(rounding, &s); \
2670 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2671 HANDLE_NAN1(r->f[i], b->f[i]) { \
2672 r->f[i] = float32_round_to_int (b->f[i], &s); \
2673 } \
2674 } \
2675 }
2676VRFI(n, float_round_nearest_even)
2677VRFI(m, float_round_down)
2678VRFI(p, float_round_up)
2679VRFI(z, float_round_to_zero)
2680#undef VRFI
2681
5e1d0985 2682#define VROTATE(suffix, element) \
c227f099 2683 void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
5e1d0985
AJ
2684 { \
2685 int i; \
2686 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2687 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2688 unsigned int shift = b->element[i] & mask; \
2689 r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2690 } \
2691 }
2692VROTATE(b, u8)
2693VROTATE(h, u16)
2694VROTATE(w, u32)
2695#undef VROTATE
2696
c227f099 2697void helper_vrsqrtefp (ppc_avr_t *r, ppc_avr_t *b)
071fc3b1
AJ
2698{
2699 int i;
2700 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2701 HANDLE_NAN1(r->f[i], b->f[i]) {
2702 float32 t = float32_sqrt(b->f[i], &env->vec_status);
2703 r->f[i] = float32_div(float32_one, t, &env->vec_status);
2704 }
2705 }
2706}
2707
c227f099 2708void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
d1258698
AJ
2709{
2710 r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2711 r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2712}
2713
0bffbc6c
AJ
2714void helper_vexptefp (ppc_avr_t *r, ppc_avr_t *b)
2715{
2716 int i;
2717 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2718 HANDLE_NAN1(r->f[i], b->f[i]) {
2719 r->f[i] = float32_exp2(b->f[i], &env->vec_status);
2720 }
2721 }
2722}
2723
c227f099 2724void helper_vlogefp (ppc_avr_t *r, ppc_avr_t *b)
f586ce09
AJ
2725{
2726 int i;
2727 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2728 HANDLE_NAN1(r->f[i], b->f[i]) {
2729 r->f[i] = float32_log2(b->f[i], &env->vec_status);
2730 }
2731 }
2732}
2733
e2542fe2 2734#if defined(HOST_WORDS_BIGENDIAN)
d9430add
AJ
2735#define LEFT 0
2736#define RIGHT 1
2737#else
2738#define LEFT 1
2739#define RIGHT 0
2740#endif
2741/* The specification says that the results are undefined if all of the
2742 * shift counts are not identical. We check to make sure that they are
2743 * to conform to what real hardware appears to do. */
2744#define VSHIFT(suffix, leftp) \
c227f099 2745 void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
d9430add 2746 { \
1481e16a 2747 int shift = b->u8[LO_IDX*15] & 0x7; \
d9430add
AJ
2748 int doit = 1; \
2749 int i; \
2750 for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
2751 doit = doit && ((b->u8[i] & 0x7) == shift); \
2752 } \
2753 if (doit) { \
2754 if (shift == 0) { \
2755 *r = *a; \
2756 } else if (leftp) { \
2757 uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \
2758 r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \
2759 r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \
2760 } else { \
2761 uint64_t carry = a->u64[HI_IDX] << (64 - shift); \
2762 r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \
2763 r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \
2764 } \
2765 } \
2766 }
2767VSHIFT(l, LEFT)
2768VSHIFT(r, RIGHT)
2769#undef VSHIFT
2770#undef LEFT
2771#undef RIGHT
2772
d79f0809 2773#define VSL(suffix, element) \
c227f099 2774 void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
d79f0809
AJ
2775 { \
2776 int i; \
2777 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2778 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2779 unsigned int shift = b->element[i] & mask; \
2780 r->element[i] = a->element[i] << shift; \
2781 } \
2782 }
2783VSL(b, u8)
2784VSL(h, u16)
2785VSL(w, u32)
2786#undef VSL
2787
c227f099 2788void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
cd633b10
AJ
2789{
2790 int sh = shift & 0xf;
2791 int i;
c227f099 2792 ppc_avr_t result;
cd633b10 2793
e2542fe2 2794#if defined(HOST_WORDS_BIGENDIAN)
cd633b10
AJ
2795 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2796 int index = sh + i;
2797 if (index > 0xf) {
2798 result.u8[i] = b->u8[index-0x10];
2799 } else {
2800 result.u8[i] = a->u8[index];
2801 }
2802 }
2803#else
2804 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2805 int index = (16 - sh) + i;
2806 if (index > 0xf) {
2807 result.u8[i] = a->u8[index-0x10];
2808 } else {
2809 result.u8[i] = b->u8[index];
2810 }
2811 }
2812#endif
2813 *r = result;
2814}
2815
c227f099 2816void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
7b239bec
AJ
2817{
2818 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2819
e2542fe2 2820#if defined (HOST_WORDS_BIGENDIAN)
7b239bec
AJ
2821 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2822 memset (&r->u8[16-sh], 0, sh);
2823#else
2824 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2825 memset (&r->u8[0], 0, sh);
2826#endif
2827}
2828
e4e6bee7
AJ
2829/* Experimental testing shows that hardware masks the immediate. */
2830#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
e2542fe2 2831#if defined(HOST_WORDS_BIGENDIAN)
e4e6bee7
AJ
2832#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2833#else
2834#define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
2835#endif
2836#define VSPLT(suffix, element) \
c227f099 2837 void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
e4e6bee7
AJ
2838 { \
2839 uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
2840 int i; \
2841 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2842 r->element[i] = s; \
2843 } \
2844 }
2845VSPLT(b, u8)
2846VSPLT(h, u16)
2847VSPLT(w, u32)
2848#undef VSPLT
2849#undef SPLAT_ELEMENT
2850#undef _SPLAT_MASKED
2851
c026766b 2852#define VSPLTI(suffix, element, splat_type) \
c227f099 2853 void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat) \
c026766b
AJ
2854 { \
2855 splat_type x = (int8_t)(splat << 3) >> 3; \
2856 int i; \
2857 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2858 r->element[i] = x; \
2859 } \
2860 }
2861VSPLTI(b, s8, int8_t)
2862VSPLTI(h, s16, int16_t)
2863VSPLTI(w, s32, int32_t)
2864#undef VSPLTI
2865
07ef34c3 2866#define VSR(suffix, element) \
c227f099 2867 void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
07ef34c3
AJ
2868 { \
2869 int i; \
2870 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2871 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2872 unsigned int shift = b->element[i] & mask; \
2873 r->element[i] = a->element[i] >> shift; \
2874 } \
2875 }
2876VSR(ab, s8)
2877VSR(ah, s16)
2878VSR(aw, s32)
2879VSR(b, u8)
2880VSR(h, u16)
2881VSR(w, u32)
2882#undef VSR
2883
c227f099 2884void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
7b239bec
AJ
2885{
2886 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2887
e2542fe2 2888#if defined (HOST_WORDS_BIGENDIAN)
7b239bec
AJ
2889 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2890 memset (&r->u8[0], 0, sh);
2891#else
2892 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2893 memset (&r->u8[16-sh], 0, sh);
2894#endif
2895}
2896
c227f099 2897void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
e343da72
AJ
2898{
2899 int i;
2900 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2901 r->u32[i] = a->u32[i] >= b->u32[i];
2902 }
2903}
2904
c227f099 2905void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
8142cddd
AJ
2906{
2907 int64_t t;
2908 int i, upper;
c227f099 2909 ppc_avr_t result;
8142cddd
AJ
2910 int sat = 0;
2911
e2542fe2 2912#if defined(HOST_WORDS_BIGENDIAN)
8142cddd
AJ
2913 upper = ARRAY_SIZE(r->s32)-1;
2914#else
2915 upper = 0;
2916#endif
2917 t = (int64_t)b->s32[upper];
2918 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2919 t += a->s32[i];
2920 result.s32[i] = 0;
2921 }
2922 result.s32[upper] = cvtsdsw(t, &sat);
2923 *r = result;
2924
2925 if (sat) {
2926 env->vscr |= (1 << VSCR_SAT);
2927 }
2928}
2929
c227f099 2930void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
8142cddd
AJ
2931{
2932 int i, j, upper;
c227f099 2933 ppc_avr_t result;
8142cddd
AJ
2934 int sat = 0;
2935
e2542fe2 2936#if defined(HOST_WORDS_BIGENDIAN)
8142cddd
AJ
2937 upper = 1;
2938#else
2939 upper = 0;
2940#endif
2941 for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
2942 int64_t t = (int64_t)b->s32[upper+i*2];
2943 result.u64[i] = 0;
2944 for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
2945 t += a->s32[2*i+j];
2946 }
2947 result.s32[upper+i*2] = cvtsdsw(t, &sat);
2948 }
2949
2950 *r = result;
2951 if (sat) {
2952 env->vscr |= (1 << VSCR_SAT);
2953 }
2954}
2955
c227f099 2956void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
8142cddd
AJ
2957{
2958 int i, j;
2959 int sat = 0;
2960
2961 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2962 int64_t t = (int64_t)b->s32[i];
2963 for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
2964 t += a->s8[4*i+j];
2965 }
2966 r->s32[i] = cvtsdsw(t, &sat);
2967 }
2968
2969 if (sat) {
2970 env->vscr |= (1 << VSCR_SAT);
2971 }
2972}
2973
c227f099 2974void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
8142cddd
AJ
2975{
2976 int sat = 0;
2977 int i;
2978
2979 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2980 int64_t t = (int64_t)b->s32[i];
2981 t += a->s16[2*i] + a->s16[2*i+1];
2982 r->s32[i] = cvtsdsw(t, &sat);
2983 }
2984
2985 if (sat) {
2986 env->vscr |= (1 << VSCR_SAT);
2987 }
2988}
2989
c227f099 2990void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
8142cddd
AJ
2991{
2992 int i, j;
2993 int sat = 0;
2994
2995 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2996 uint64_t t = (uint64_t)b->u32[i];
2997 for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
2998 t += a->u8[4*i+j];
2999 }
3000 r->u32[i] = cvtuduw(t, &sat);
3001 }
3002
3003 if (sat) {
3004 env->vscr |= (1 << VSCR_SAT);
3005 }
3006}
3007
e2542fe2 3008#if defined(HOST_WORDS_BIGENDIAN)
79f85c3a
AJ
3009#define UPKHI 1
3010#define UPKLO 0
3011#else
3012#define UPKHI 0
3013#define UPKLO 1
3014#endif
3015#define VUPKPX(suffix, hi) \
c227f099 3016 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
79f85c3a
AJ
3017 { \
3018 int i; \
c227f099 3019 ppc_avr_t result; \
79f85c3a
AJ
3020 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
3021 uint16_t e = b->u16[hi ? i : i+4]; \
3022 uint8_t a = (e >> 15) ? 0xff : 0; \
3023 uint8_t r = (e >> 10) & 0x1f; \
3024 uint8_t g = (e >> 5) & 0x1f; \
3025 uint8_t b = e & 0x1f; \
3026 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
3027 } \
3028 *r = result; \
3029 }
3030VUPKPX(lpx, UPKLO)
3031VUPKPX(hpx, UPKHI)
3032#undef VUPKPX
3033
6cf1c6e5 3034#define VUPK(suffix, unpacked, packee, hi) \
c227f099 3035 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
6cf1c6e5
AJ
3036 { \
3037 int i; \
c227f099 3038 ppc_avr_t result; \
6cf1c6e5
AJ
3039 if (hi) { \
3040 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
3041 result.unpacked[i] = b->packee[i]; \
3042 } \
3043 } else { \
3044 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
3045 result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
3046 } \
3047 } \
3048 *r = result; \
3049 }
3050VUPK(hsb, s16, s8, UPKHI)
3051VUPK(hsh, s32, s16, UPKHI)
3052VUPK(lsb, s16, s8, UPKLO)
3053VUPK(lsh, s32, s16, UPKLO)
3054#undef VUPK
79f85c3a
AJ
3055#undef UPKHI
3056#undef UPKLO
3057
34ba2857
AJ
3058#undef DO_HANDLE_NAN
3059#undef HANDLE_NAN1
3060#undef HANDLE_NAN2
3061#undef HANDLE_NAN3
d6a46fe8
AJ
3062#undef VECTOR_FOR_INORDER_I
3063#undef HI_IDX
3064#undef LO_IDX
3065
1c97856d 3066/*****************************************************************************/
0487d6a8
JM
3067/* SPE extension helpers */
3068/* Use a table to make this quicker */
3069static uint8_t hbrev[16] = {
3070 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
3071 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
3072};
3073
636aa200 3074static inline uint8_t byte_reverse(uint8_t val)
0487d6a8
JM
3075{
3076 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
3077}
3078
636aa200 3079static inline uint32_t word_reverse(uint32_t val)
0487d6a8
JM
3080{
3081 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
3082 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
3083}
3084
3cd7d1dd 3085#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
57951c27 3086target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
0487d6a8
JM
3087{
3088 uint32_t a, b, d, mask;
3089
3cd7d1dd 3090 mask = UINT32_MAX >> (32 - MASKBITS);
57951c27
AJ
3091 a = arg1 & mask;
3092 b = arg2 & mask;
3cd7d1dd 3093 d = word_reverse(1 + word_reverse(a | ~b));
57951c27 3094 return (arg1 & ~mask) | (d & b);
0487d6a8
JM
3095}
3096
57951c27 3097uint32_t helper_cntlsw32 (uint32_t val)
0487d6a8
JM
3098{
3099 if (val & 0x80000000)
603fccce 3100 return clz32(~val);
0487d6a8 3101 else
603fccce 3102 return clz32(val);
0487d6a8
JM
3103}
3104
57951c27 3105uint32_t helper_cntlzw32 (uint32_t val)
0487d6a8 3106{
603fccce 3107 return clz32(val);
0487d6a8
JM
3108}
3109
1c97856d 3110/* Single-precision floating-point conversions */
636aa200 3111static inline uint32_t efscfsi(uint32_t val)
0487d6a8 3112{
0ca9d380 3113 CPU_FloatU u;
0487d6a8 3114
fbd265b6 3115 u.f = int32_to_float32(val, &env->vec_status);
0487d6a8 3116
0ca9d380 3117 return u.l;
0487d6a8
JM
3118}
3119
636aa200 3120static inline uint32_t efscfui(uint32_t val)
0487d6a8 3121{
0ca9d380 3122 CPU_FloatU u;
0487d6a8 3123
fbd265b6 3124 u.f = uint32_to_float32(val, &env->vec_status);
0487d6a8 3125
0ca9d380 3126 return u.l;
0487d6a8
JM
3127}
3128
636aa200 3129static inline int32_t efsctsi(uint32_t val)
0487d6a8 3130{
0ca9d380 3131 CPU_FloatU u;
0487d6a8 3132
0ca9d380 3133 u.l = val;
0487d6a8 3134 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3135 if (unlikely(float32_is_nan(u.f)))
0487d6a8
JM
3136 return 0;
3137
fbd265b6 3138 return float32_to_int32(u.f, &env->vec_status);
0487d6a8
JM
3139}
3140
636aa200 3141static inline uint32_t efsctui(uint32_t val)
0487d6a8 3142{
0ca9d380 3143 CPU_FloatU u;
0487d6a8 3144
0ca9d380 3145 u.l = val;
0487d6a8 3146 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3147 if (unlikely(float32_is_nan(u.f)))
0487d6a8
JM
3148 return 0;
3149
fbd265b6 3150 return float32_to_uint32(u.f, &env->vec_status);
0487d6a8
JM
3151}
3152
636aa200 3153static inline uint32_t efsctsiz(uint32_t val)
0487d6a8 3154{
0ca9d380 3155 CPU_FloatU u;
0487d6a8 3156
0ca9d380 3157 u.l = val;
0487d6a8 3158 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3159 if (unlikely(float32_is_nan(u.f)))
0487d6a8
JM
3160 return 0;
3161
fbd265b6 3162 return float32_to_int32_round_to_zero(u.f, &env->vec_status);
0487d6a8
JM
3163}
3164
636aa200 3165static inline uint32_t efsctuiz(uint32_t val)
0487d6a8 3166{
0ca9d380 3167 CPU_FloatU u;
0487d6a8 3168
0ca9d380 3169 u.l = val;
0487d6a8 3170 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3171 if (unlikely(float32_is_nan(u.f)))
0487d6a8
JM
3172 return 0;
3173
fbd265b6 3174 return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
0487d6a8
JM
3175}
3176
636aa200 3177static inline uint32_t efscfsf(uint32_t val)
0487d6a8 3178{
0ca9d380 3179 CPU_FloatU u;
0487d6a8
JM
3180 float32 tmp;
3181
fbd265b6
AJ
3182 u.f = int32_to_float32(val, &env->vec_status);
3183 tmp = int64_to_float32(1ULL << 32, &env->vec_status);
3184 u.f = float32_div(u.f, tmp, &env->vec_status);
0487d6a8 3185
0ca9d380 3186 return u.l;
0487d6a8
JM
3187}
3188
636aa200 3189static inline uint32_t efscfuf(uint32_t val)
0487d6a8 3190{
0ca9d380 3191 CPU_FloatU u;
0487d6a8
JM
3192 float32 tmp;
3193
fbd265b6
AJ
3194 u.f = uint32_to_float32(val, &env->vec_status);
3195 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3196 u.f = float32_div(u.f, tmp, &env->vec_status);
0487d6a8 3197
0ca9d380 3198 return u.l;
0487d6a8
JM
3199}
3200
636aa200 3201static inline uint32_t efsctsf(uint32_t val)
0487d6a8 3202{
0ca9d380 3203 CPU_FloatU u;
0487d6a8
JM
3204 float32 tmp;
3205
0ca9d380 3206 u.l = val;
0487d6a8 3207 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3208 if (unlikely(float32_is_nan(u.f)))
0487d6a8 3209 return 0;
fbd265b6
AJ
3210 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3211 u.f = float32_mul(u.f, tmp, &env->vec_status);
0487d6a8 3212
fbd265b6 3213 return float32_to_int32(u.f, &env->vec_status);
0487d6a8
JM
3214}
3215
636aa200 3216static inline uint32_t efsctuf(uint32_t val)
0487d6a8 3217{
0ca9d380 3218 CPU_FloatU u;
0487d6a8
JM
3219 float32 tmp;
3220
0ca9d380 3221 u.l = val;
0487d6a8 3222 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3223 if (unlikely(float32_is_nan(u.f)))
0487d6a8 3224 return 0;
fbd265b6
AJ
3225 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3226 u.f = float32_mul(u.f, tmp, &env->vec_status);
0487d6a8 3227
fbd265b6 3228 return float32_to_uint32(u.f, &env->vec_status);
0487d6a8
JM
3229}
3230
1c97856d
AJ
3231#define HELPER_SPE_SINGLE_CONV(name) \
3232uint32_t helper_e##name (uint32_t val) \
3233{ \
3234 return e##name(val); \
3235}
3236/* efscfsi */
3237HELPER_SPE_SINGLE_CONV(fscfsi);
3238/* efscfui */
3239HELPER_SPE_SINGLE_CONV(fscfui);
3240/* efscfuf */
3241HELPER_SPE_SINGLE_CONV(fscfuf);
3242/* efscfsf */
3243HELPER_SPE_SINGLE_CONV(fscfsf);
3244/* efsctsi */
3245HELPER_SPE_SINGLE_CONV(fsctsi);
3246/* efsctui */
3247HELPER_SPE_SINGLE_CONV(fsctui);
3248/* efsctsiz */
3249HELPER_SPE_SINGLE_CONV(fsctsiz);
3250/* efsctuiz */
3251HELPER_SPE_SINGLE_CONV(fsctuiz);
3252/* efsctsf */
3253HELPER_SPE_SINGLE_CONV(fsctsf);
3254/* efsctuf */
3255HELPER_SPE_SINGLE_CONV(fsctuf);
3256
3257#define HELPER_SPE_VECTOR_CONV(name) \
3258uint64_t helper_ev##name (uint64_t val) \
3259{ \
3260 return ((uint64_t)e##name(val >> 32) << 32) | \
3261 (uint64_t)e##name(val); \
0487d6a8 3262}
1c97856d
AJ
3263/* evfscfsi */
3264HELPER_SPE_VECTOR_CONV(fscfsi);
3265/* evfscfui */
3266HELPER_SPE_VECTOR_CONV(fscfui);
3267/* evfscfuf */
3268HELPER_SPE_VECTOR_CONV(fscfuf);
3269/* evfscfsf */
3270HELPER_SPE_VECTOR_CONV(fscfsf);
3271/* evfsctsi */
3272HELPER_SPE_VECTOR_CONV(fsctsi);
3273/* evfsctui */
3274HELPER_SPE_VECTOR_CONV(fsctui);
3275/* evfsctsiz */
3276HELPER_SPE_VECTOR_CONV(fsctsiz);
3277/* evfsctuiz */
3278HELPER_SPE_VECTOR_CONV(fsctuiz);
3279/* evfsctsf */
3280HELPER_SPE_VECTOR_CONV(fsctsf);
3281/* evfsctuf */
3282HELPER_SPE_VECTOR_CONV(fsctuf);
0487d6a8 3283
1c97856d 3284/* Single-precision floating-point arithmetic */
636aa200 3285static inline uint32_t efsadd(uint32_t op1, uint32_t op2)
0487d6a8 3286{
1c97856d
AJ
3287 CPU_FloatU u1, u2;
3288 u1.l = op1;
3289 u2.l = op2;
fbd265b6 3290 u1.f = float32_add(u1.f, u2.f, &env->vec_status);
1c97856d 3291 return u1.l;
0487d6a8
JM
3292}
3293
636aa200 3294static inline uint32_t efssub(uint32_t op1, uint32_t op2)
0487d6a8 3295{
1c97856d
AJ
3296 CPU_FloatU u1, u2;
3297 u1.l = op1;
3298 u2.l = op2;
fbd265b6 3299 u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
1c97856d 3300 return u1.l;
0487d6a8
JM
3301}
3302
636aa200 3303static inline uint32_t efsmul(uint32_t op1, uint32_t op2)
0487d6a8 3304{
1c97856d
AJ
3305 CPU_FloatU u1, u2;
3306 u1.l = op1;
3307 u2.l = op2;
fbd265b6 3308 u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
1c97856d 3309 return u1.l;
0487d6a8
JM
3310}
3311
636aa200 3312static inline uint32_t efsdiv(uint32_t op1, uint32_t op2)
0487d6a8 3313{
1c97856d
AJ
3314 CPU_FloatU u1, u2;
3315 u1.l = op1;
3316 u2.l = op2;
fbd265b6 3317 u1.f = float32_div(u1.f, u2.f, &env->vec_status);
1c97856d 3318 return u1.l;
0487d6a8
JM
3319}
3320
1c97856d
AJ
3321#define HELPER_SPE_SINGLE_ARITH(name) \
3322uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
3323{ \
3324 return e##name(op1, op2); \
3325}
3326/* efsadd */
3327HELPER_SPE_SINGLE_ARITH(fsadd);
3328/* efssub */
3329HELPER_SPE_SINGLE_ARITH(fssub);
3330/* efsmul */
3331HELPER_SPE_SINGLE_ARITH(fsmul);
3332/* efsdiv */
3333HELPER_SPE_SINGLE_ARITH(fsdiv);
3334
3335#define HELPER_SPE_VECTOR_ARITH(name) \
3336uint64_t helper_ev##name (uint64_t op1, uint64_t op2) \
3337{ \
3338 return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
3339 (uint64_t)e##name(op1, op2); \
3340}
3341/* evfsadd */
3342HELPER_SPE_VECTOR_ARITH(fsadd);
3343/* evfssub */
3344HELPER_SPE_VECTOR_ARITH(fssub);
3345/* evfsmul */
3346HELPER_SPE_VECTOR_ARITH(fsmul);
3347/* evfsdiv */
3348HELPER_SPE_VECTOR_ARITH(fsdiv);
3349
3350/* Single-precision floating-point comparisons */
636aa200 3351static inline uint32_t efststlt(uint32_t op1, uint32_t op2)
0487d6a8 3352{
1c97856d
AJ
3353 CPU_FloatU u1, u2;
3354 u1.l = op1;
3355 u2.l = op2;
fbd265b6 3356 return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
0487d6a8
JM
3357}
3358
636aa200 3359static inline uint32_t efststgt(uint32_t op1, uint32_t op2)
0487d6a8 3360{
1c97856d
AJ
3361 CPU_FloatU u1, u2;
3362 u1.l = op1;
3363 u2.l = op2;
fbd265b6 3364 return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
0487d6a8
JM
3365}
3366
636aa200 3367static inline uint32_t efststeq(uint32_t op1, uint32_t op2)
0487d6a8 3368{
1c97856d
AJ
3369 CPU_FloatU u1, u2;
3370 u1.l = op1;
3371 u2.l = op2;
fbd265b6 3372 return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
0487d6a8
JM
3373}
3374
636aa200 3375static inline uint32_t efscmplt(uint32_t op1, uint32_t op2)
0487d6a8
JM
3376{
3377 /* XXX: TODO: test special values (NaN, infinites, ...) */
1c97856d 3378 return efststlt(op1, op2);
0487d6a8
JM
3379}
3380
636aa200 3381static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2)
0487d6a8
JM
3382{
3383 /* XXX: TODO: test special values (NaN, infinites, ...) */
1c97856d 3384 return efststgt(op1, op2);
0487d6a8
JM
3385}
3386
636aa200 3387static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2)
0487d6a8
JM
3388{
3389 /* XXX: TODO: test special values (NaN, infinites, ...) */
1c97856d 3390 return efststeq(op1, op2);
0487d6a8
JM
3391}
3392
1c97856d
AJ
3393#define HELPER_SINGLE_SPE_CMP(name) \
3394uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
3395{ \
3396 return e##name(op1, op2) << 2; \
3397}
3398/* efststlt */
3399HELPER_SINGLE_SPE_CMP(fststlt);
3400/* efststgt */
3401HELPER_SINGLE_SPE_CMP(fststgt);
3402/* efststeq */
3403HELPER_SINGLE_SPE_CMP(fststeq);
3404/* efscmplt */
3405HELPER_SINGLE_SPE_CMP(fscmplt);
3406/* efscmpgt */
3407HELPER_SINGLE_SPE_CMP(fscmpgt);
3408/* efscmpeq */
3409HELPER_SINGLE_SPE_CMP(fscmpeq);
3410
636aa200 3411static inline uint32_t evcmp_merge(int t0, int t1)
0487d6a8 3412{
1c97856d 3413 return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
0487d6a8
JM
3414}
3415
1c97856d
AJ
3416#define HELPER_VECTOR_SPE_CMP(name) \
3417uint32_t helper_ev##name (uint64_t op1, uint64_t op2) \
3418{ \
3419 return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
0487d6a8 3420}
1c97856d
AJ
3421/* evfststlt */
3422HELPER_VECTOR_SPE_CMP(fststlt);
3423/* evfststgt */
3424HELPER_VECTOR_SPE_CMP(fststgt);
3425/* evfststeq */
3426HELPER_VECTOR_SPE_CMP(fststeq);
3427/* evfscmplt */
3428HELPER_VECTOR_SPE_CMP(fscmplt);
3429/* evfscmpgt */
3430HELPER_VECTOR_SPE_CMP(fscmpgt);
3431/* evfscmpeq */
3432HELPER_VECTOR_SPE_CMP(fscmpeq);
0487d6a8 3433
1c97856d
AJ
3434/* Double-precision floating-point conversion */
3435uint64_t helper_efdcfsi (uint32_t val)
0487d6a8 3436{
1c97856d
AJ
3437 CPU_DoubleU u;
3438
fbd265b6 3439 u.d = int32_to_float64(val, &env->vec_status);
1c97856d
AJ
3440
3441 return u.ll;
0487d6a8
JM
3442}
3443
1c97856d 3444uint64_t helper_efdcfsid (uint64_t val)
0487d6a8 3445{
0ca9d380 3446 CPU_DoubleU u;
0487d6a8 3447
fbd265b6 3448 u.d = int64_to_float64(val, &env->vec_status);
0487d6a8 3449
0ca9d380 3450 return u.ll;
0487d6a8
JM
3451}
3452
1c97856d
AJ
3453uint64_t helper_efdcfui (uint32_t val)
3454{
3455 CPU_DoubleU u;
3456
fbd265b6 3457 u.d = uint32_to_float64(val, &env->vec_status);
1c97856d
AJ
3458
3459 return u.ll;
3460}
3461
3462uint64_t helper_efdcfuid (uint64_t val)
0487d6a8 3463{
0ca9d380 3464 CPU_DoubleU u;
0487d6a8 3465
fbd265b6 3466 u.d = uint64_to_float64(val, &env->vec_status);
0487d6a8 3467
0ca9d380 3468 return u.ll;
0487d6a8
JM
3469}
3470
1c97856d 3471uint32_t helper_efdctsi (uint64_t val)
0487d6a8 3472{
0ca9d380 3473 CPU_DoubleU u;
0487d6a8 3474
0ca9d380 3475 u.ll = val;
0487d6a8 3476 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3477 if (unlikely(float64_is_nan(u.d)))
0487d6a8
JM
3478 return 0;
3479
fbd265b6 3480 return float64_to_int32(u.d, &env->vec_status);
0487d6a8
JM
3481}
3482
1c97856d 3483uint32_t helper_efdctui (uint64_t val)
0487d6a8 3484{
0ca9d380 3485 CPU_DoubleU u;
0487d6a8 3486
0ca9d380 3487 u.ll = val;
0487d6a8 3488 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3489 if (unlikely(float64_is_nan(u.d)))
0487d6a8
JM
3490 return 0;
3491
fbd265b6 3492 return float64_to_uint32(u.d, &env->vec_status);
0487d6a8
JM
3493}
3494
1c97856d 3495uint32_t helper_efdctsiz (uint64_t val)
0487d6a8 3496{
0ca9d380 3497 CPU_DoubleU u;
0487d6a8 3498
0ca9d380 3499 u.ll = val;
0487d6a8 3500 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3501 if (unlikely(float64_is_nan(u.d)))
0487d6a8
JM
3502 return 0;
3503
fbd265b6 3504 return float64_to_int32_round_to_zero(u.d, &env->vec_status);
0487d6a8
JM
3505}
3506
1c97856d 3507uint64_t helper_efdctsidz (uint64_t val)
0487d6a8 3508{
0ca9d380 3509 CPU_DoubleU u;
0487d6a8 3510
0ca9d380 3511 u.ll = val;
0487d6a8 3512 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3513 if (unlikely(float64_is_nan(u.d)))
0487d6a8
JM
3514 return 0;
3515
fbd265b6 3516 return float64_to_int64_round_to_zero(u.d, &env->vec_status);
0487d6a8
JM
3517}
3518
1c97856d 3519uint32_t helper_efdctuiz (uint64_t val)
0487d6a8 3520{
1c97856d 3521 CPU_DoubleU u;
0487d6a8 3522
1c97856d
AJ
3523 u.ll = val;
3524 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3525 if (unlikely(float64_is_nan(u.d)))
1c97856d 3526 return 0;
0487d6a8 3527
fbd265b6 3528 return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
0487d6a8
JM
3529}
3530
1c97856d 3531uint64_t helper_efdctuidz (uint64_t val)
0487d6a8 3532{
1c97856d 3533 CPU_DoubleU u;
0487d6a8 3534
1c97856d
AJ
3535 u.ll = val;
3536 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3537 if (unlikely(float64_is_nan(u.d)))
1c97856d 3538 return 0;
0487d6a8 3539
fbd265b6 3540 return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
0487d6a8
JM
3541}
3542
1c97856d 3543uint64_t helper_efdcfsf (uint32_t val)
0487d6a8 3544{
0ca9d380 3545 CPU_DoubleU u;
0487d6a8
JM
3546 float64 tmp;
3547
fbd265b6
AJ
3548 u.d = int32_to_float64(val, &env->vec_status);
3549 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3550 u.d = float64_div(u.d, tmp, &env->vec_status);
0487d6a8 3551
0ca9d380 3552 return u.ll;
0487d6a8
JM
3553}
3554
1c97856d 3555uint64_t helper_efdcfuf (uint32_t val)
0487d6a8 3556{
0ca9d380 3557 CPU_DoubleU u;
0487d6a8
JM
3558 float64 tmp;
3559
fbd265b6
AJ
3560 u.d = uint32_to_float64(val, &env->vec_status);
3561 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3562 u.d = float64_div(u.d, tmp, &env->vec_status);
0487d6a8 3563
0ca9d380 3564 return u.ll;
0487d6a8
JM
3565}
3566
1c97856d 3567uint32_t helper_efdctsf (uint64_t val)
0487d6a8 3568{
0ca9d380 3569 CPU_DoubleU u;
0487d6a8
JM
3570 float64 tmp;
3571
0ca9d380 3572 u.ll = val;
0487d6a8 3573 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3574 if (unlikely(float64_is_nan(u.d)))
0487d6a8 3575 return 0;
fbd265b6
AJ
3576 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3577 u.d = float64_mul(u.d, tmp, &env->vec_status);
0487d6a8 3578
fbd265b6 3579 return float64_to_int32(u.d, &env->vec_status);
0487d6a8
JM
3580}
3581
1c97856d 3582uint32_t helper_efdctuf (uint64_t val)
0487d6a8 3583{
0ca9d380 3584 CPU_DoubleU u;
0487d6a8
JM
3585 float64 tmp;
3586
0ca9d380 3587 u.ll = val;
0487d6a8 3588 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 3589 if (unlikely(float64_is_nan(u.d)))
0487d6a8 3590 return 0;
fbd265b6
AJ
3591 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3592 u.d = float64_mul(u.d, tmp, &env->vec_status);
0487d6a8 3593
fbd265b6 3594 return float64_to_uint32(u.d, &env->vec_status);
0487d6a8
JM
3595}
3596
1c97856d 3597uint32_t helper_efscfd (uint64_t val)
0487d6a8 3598{
0ca9d380
AJ
3599 CPU_DoubleU u1;
3600 CPU_FloatU u2;
0487d6a8 3601
0ca9d380 3602 u1.ll = val;
fbd265b6 3603 u2.f = float64_to_float32(u1.d, &env->vec_status);
0487d6a8 3604
0ca9d380 3605 return u2.l;
0487d6a8
JM
3606}
3607
1c97856d 3608uint64_t helper_efdcfs (uint32_t val)
0487d6a8 3609{
0ca9d380
AJ
3610 CPU_DoubleU u2;
3611 CPU_FloatU u1;
0487d6a8 3612
0ca9d380 3613 u1.l = val;
fbd265b6 3614 u2.d = float32_to_float64(u1.f, &env->vec_status);
0487d6a8 3615
0ca9d380 3616 return u2.ll;
0487d6a8
JM
3617}
3618
1c97856d
AJ
3619/* Double precision fixed-point arithmetic */
3620uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
0487d6a8 3621{
1c97856d
AJ
3622 CPU_DoubleU u1, u2;
3623 u1.ll = op1;
3624 u2.ll = op2;
fbd265b6 3625 u1.d = float64_add(u1.d, u2.d, &env->vec_status);
1c97856d 3626 return u1.ll;
0487d6a8
JM
3627}
3628
1c97856d 3629uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
0487d6a8 3630{
1c97856d
AJ
3631 CPU_DoubleU u1, u2;
3632 u1.ll = op1;
3633 u2.ll = op2;
fbd265b6 3634 u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
1c97856d 3635 return u1.ll;
0487d6a8
JM
3636}
3637
1c97856d 3638uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
0487d6a8 3639{
1c97856d
AJ
3640 CPU_DoubleU u1, u2;
3641 u1.ll = op1;
3642 u2.ll = op2;
fbd265b6 3643 u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
1c97856d 3644 return u1.ll;
0487d6a8
JM
3645}
3646
1c97856d 3647uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
0487d6a8 3648{
1c97856d
AJ
3649 CPU_DoubleU u1, u2;
3650 u1.ll = op1;
3651 u2.ll = op2;
fbd265b6 3652 u1.d = float64_div(u1.d, u2.d, &env->vec_status);
1c97856d 3653 return u1.ll;
0487d6a8
JM
3654}
3655
1c97856d
AJ
3656/* Double precision floating point helpers */
3657uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
0487d6a8 3658{
1c97856d
AJ
3659 CPU_DoubleU u1, u2;
3660 u1.ll = op1;
3661 u2.ll = op2;
fbd265b6 3662 return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
0487d6a8
JM
3663}
3664
1c97856d 3665uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
0487d6a8 3666{
1c97856d
AJ
3667 CPU_DoubleU u1, u2;
3668 u1.ll = op1;
3669 u2.ll = op2;
fbd265b6 3670 return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
0487d6a8
JM
3671}
3672
1c97856d 3673uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
0487d6a8 3674{
1c97856d
AJ
3675 CPU_DoubleU u1, u2;
3676 u1.ll = op1;
3677 u2.ll = op2;
fbd265b6 3678 return float64_eq(u1.d, u2.d, &env->vec_status) ? 4 : 0;
0487d6a8
JM
3679}
3680
1c97856d 3681uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
0487d6a8 3682{
1c97856d
AJ
3683 /* XXX: TODO: test special values (NaN, infinites, ...) */
3684 return helper_efdtstlt(op1, op2);
0487d6a8
JM
3685}
3686
1c97856d
AJ
3687uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
3688{
3689 /* XXX: TODO: test special values (NaN, infinites, ...) */
3690 return helper_efdtstgt(op1, op2);
3691}
0487d6a8 3692
1c97856d
AJ
3693uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
3694{
3695 /* XXX: TODO: test special values (NaN, infinites, ...) */
3696 return helper_efdtsteq(op1, op2);
3697}
0487d6a8 3698
fdabc366
FB
3699/*****************************************************************************/
3700/* Softmmu support */
3701#if !defined (CONFIG_USER_ONLY)
3702
3703#define MMUSUFFIX _mmu
fdabc366
FB
3704
3705#define SHIFT 0
3706#include "softmmu_template.h"
3707
3708#define SHIFT 1
3709#include "softmmu_template.h"
3710
3711#define SHIFT 2
3712#include "softmmu_template.h"
3713
3714#define SHIFT 3
3715#include "softmmu_template.h"
3716
3717/* try to fill the TLB and return an exception if error. If retaddr is
3718 NULL, it means that the function was called in C code (i.e. not
3719 from generated code or from helper.c) */
3720/* XXX: fix it to restore all registers */
6ebbf390 3721void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
fdabc366
FB
3722{
3723 TranslationBlock *tb;
3724 CPUState *saved_env;
44f8625d 3725 unsigned long pc;
fdabc366
FB
3726 int ret;
3727
3728 /* XXX: hack to restore env in all cases, even if not called from
3729 generated code */
3730 saved_env = env;
3731 env = cpu_single_env;
6ebbf390 3732 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
76a66253 3733 if (unlikely(ret != 0)) {
fdabc366
FB
3734 if (likely(retaddr)) {
3735 /* now we have a real cpu fault */
44f8625d 3736 pc = (unsigned long)retaddr;
fdabc366
FB
3737 tb = tb_find_pc(pc);
3738 if (likely(tb)) {
3739 /* the PC is inside the translated code. It means that we have
3740 a virtual CPU fault */
3741 cpu_restore_state(tb, env, pc, NULL);
76a66253 3742 }
fdabc366 3743 }
e06fcd75 3744 helper_raise_exception_err(env->exception_index, env->error_code);
fdabc366
FB
3745 }
3746 env = saved_env;
9a64fbe4
FB
3747}
3748
74d37793
AJ
3749/* Segment registers load and store */
3750target_ulong helper_load_sr (target_ulong sr_num)
3751{
f6b868fc
BS
3752#if defined(TARGET_PPC64)
3753 if (env->mmu_model & POWERPC_MMU_64)
3754 return ppc_load_sr(env, sr_num);
3755#endif
74d37793
AJ
3756 return env->sr[sr_num];
3757}
3758
3759void helper_store_sr (target_ulong sr_num, target_ulong val)
3760{
45d827d2 3761 ppc_store_sr(env, sr_num, val);
74d37793
AJ
3762}
3763
3764/* SLB management */
3765#if defined(TARGET_PPC64)
3766target_ulong helper_load_slb (target_ulong slb_nr)
3767{
3768 return ppc_load_slb(env, slb_nr);
3769}
3770
f6b868fc 3771void helper_store_slb (target_ulong rb, target_ulong rs)
74d37793 3772{
f6b868fc 3773 ppc_store_slb(env, rb, rs);
74d37793
AJ
3774}
3775
3776void helper_slbia (void)
3777{
3778 ppc_slb_invalidate_all(env);
3779}
3780
3781void helper_slbie (target_ulong addr)
3782{
3783 ppc_slb_invalidate_one(env, addr);
3784}
3785
3786#endif /* defined(TARGET_PPC64) */
3787
3788/* TLB management */
3789void helper_tlbia (void)
3790{
3791 ppc_tlb_invalidate_all(env);
3792}
3793
3794void helper_tlbie (target_ulong addr)
3795{
3796 ppc_tlb_invalidate_one(env, addr);
3797}
3798
76a66253
JM
3799/* Software driven TLBs management */
3800/* PowerPC 602/603 software TLB load instructions helpers */
74d37793 3801static void do_6xx_tlb (target_ulong new_EPN, int is_code)
76a66253
JM
3802{
3803 target_ulong RPN, CMP, EPN;
3804 int way;
d9bce9d9 3805
76a66253
JM
3806 RPN = env->spr[SPR_RPA];
3807 if (is_code) {
3808 CMP = env->spr[SPR_ICMP];
3809 EPN = env->spr[SPR_IMISS];
3810 } else {
3811 CMP = env->spr[SPR_DCMP];
3812 EPN = env->spr[SPR_DMISS];
3813 }
3814 way = (env->spr[SPR_SRR1] >> 17) & 1;
577f25a5 3815 (void)EPN; /* avoid a compiler warning */
90e189ec
BS
3816 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
3817 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
3818 RPN, way);
76a66253 3819 /* Store this TLB */
0f3955e2 3820 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
d9bce9d9 3821 way, is_code, CMP, RPN);
76a66253
JM
3822}
3823
74d37793 3824void helper_6xx_tlbd (target_ulong EPN)
0f3955e2 3825{
74d37793 3826 do_6xx_tlb(EPN, 0);
0f3955e2
AJ
3827}
3828
74d37793 3829void helper_6xx_tlbi (target_ulong EPN)
0f3955e2 3830{
74d37793 3831 do_6xx_tlb(EPN, 1);
0f3955e2
AJ
3832}
3833
3834/* PowerPC 74xx software TLB load instructions helpers */
74d37793 3835static void do_74xx_tlb (target_ulong new_EPN, int is_code)
7dbe11ac
JM
3836{
3837 target_ulong RPN, CMP, EPN;
3838 int way;
3839
3840 RPN = env->spr[SPR_PTELO];
3841 CMP = env->spr[SPR_PTEHI];
3842 EPN = env->spr[SPR_TLBMISS] & ~0x3;
3843 way = env->spr[SPR_TLBMISS] & 0x3;
577f25a5 3844 (void)EPN; /* avoid a compiler warning */
90e189ec
BS
3845 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
3846 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
3847 RPN, way);
7dbe11ac 3848 /* Store this TLB */
0f3955e2 3849 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
7dbe11ac
JM
3850 way, is_code, CMP, RPN);
3851}
3852
74d37793 3853void helper_74xx_tlbd (target_ulong EPN)
0f3955e2 3854{
74d37793 3855 do_74xx_tlb(EPN, 0);
0f3955e2
AJ
3856}
3857
74d37793 3858void helper_74xx_tlbi (target_ulong EPN)
0f3955e2 3859{
74d37793 3860 do_74xx_tlb(EPN, 1);
0f3955e2
AJ
3861}
3862
636aa200 3863static inline target_ulong booke_tlb_to_page_size(int size)
a8dea12f
JM
3864{
3865 return 1024 << (2 * size);
3866}
3867
636aa200 3868static inline int booke_page_size_to_tlb(target_ulong page_size)
a8dea12f
JM
3869{
3870 int size;
3871
3872 switch (page_size) {
3873 case 0x00000400UL:
3874 size = 0x0;
3875 break;
3876 case 0x00001000UL:
3877 size = 0x1;
3878 break;
3879 case 0x00004000UL:
3880 size = 0x2;
3881 break;
3882 case 0x00010000UL:
3883 size = 0x3;
3884 break;
3885 case 0x00040000UL:
3886 size = 0x4;
3887 break;
3888 case 0x00100000UL:
3889 size = 0x5;
3890 break;
3891 case 0x00400000UL:
3892 size = 0x6;
3893 break;
3894 case 0x01000000UL:
3895 size = 0x7;
3896 break;
3897 case 0x04000000UL:
3898 size = 0x8;
3899 break;
3900 case 0x10000000UL:
3901 size = 0x9;
3902 break;
3903 case 0x40000000UL:
3904 size = 0xA;
3905 break;
3906#if defined (TARGET_PPC64)
3907 case 0x000100000000ULL:
3908 size = 0xB;
3909 break;
3910 case 0x000400000000ULL:
3911 size = 0xC;
3912 break;
3913 case 0x001000000000ULL:
3914 size = 0xD;
3915 break;
3916 case 0x004000000000ULL:
3917 size = 0xE;
3918 break;
3919 case 0x010000000000ULL:
3920 size = 0xF;
3921 break;
3922#endif
3923 default:
3924 size = -1;
3925 break;
3926 }
3927
3928 return size;
3929}
3930
76a66253 3931/* Helpers for 4xx TLB management */
999fa40e
JC
3932#define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
3933
3934#define PPC4XX_TLBHI_V 0x00000040
3935#define PPC4XX_TLBHI_E 0x00000020
3936#define PPC4XX_TLBHI_SIZE_MIN 0
3937#define PPC4XX_TLBHI_SIZE_MAX 7
3938#define PPC4XX_TLBHI_SIZE_DEFAULT 1
3939#define PPC4XX_TLBHI_SIZE_SHIFT 7
3940#define PPC4XX_TLBHI_SIZE_MASK 0x00000007
3941
3942#define PPC4XX_TLBLO_EX 0x00000200
3943#define PPC4XX_TLBLO_WR 0x00000100
3944#define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
3945#define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
3946
3947target_ulong helper_4xx_tlbre_hi (target_ulong entry)
76a66253 3948{
c227f099 3949 ppcemb_tlb_t *tlb;
74d37793 3950 target_ulong ret;
a8dea12f 3951 int size;
76a66253 3952
999fa40e 3953 entry &= PPC4XX_TLB_ENTRY_MASK;
74d37793
AJ
3954 tlb = &env->tlb[entry].tlbe;
3955 ret = tlb->EPN;
999fa40e
JC
3956 if (tlb->prot & PAGE_VALID) {
3957 ret |= PPC4XX_TLBHI_V;
3958 }
a8dea12f 3959 size = booke_page_size_to_tlb(tlb->size);
999fa40e
JC
3960 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
3961 size = PPC4XX_TLBHI_SIZE_DEFAULT;
3962 }
3963 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
a8dea12f 3964 env->spr[SPR_40x_PID] = tlb->PID;
74d37793 3965 return ret;
76a66253
JM
3966}
3967
999fa40e 3968target_ulong helper_4xx_tlbre_lo (target_ulong entry)
76a66253 3969{
c227f099 3970 ppcemb_tlb_t *tlb;
74d37793 3971 target_ulong ret;
76a66253 3972
999fa40e 3973 entry &= PPC4XX_TLB_ENTRY_MASK;
74d37793
AJ
3974 tlb = &env->tlb[entry].tlbe;
3975 ret = tlb->RPN;
999fa40e
JC
3976 if (tlb->prot & PAGE_EXEC) {
3977 ret |= PPC4XX_TLBLO_EX;
3978 }
3979 if (tlb->prot & PAGE_WRITE) {
3980 ret |= PPC4XX_TLBLO_WR;
3981 }
74d37793 3982 return ret;
76a66253
JM
3983}
3984
74d37793 3985void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
76a66253 3986{
c227f099 3987 ppcemb_tlb_t *tlb;
76a66253
JM
3988 target_ulong page, end;
3989
90e189ec
BS
3990 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
3991 val);
999fa40e 3992 entry &= PPC4XX_TLB_ENTRY_MASK;
74d37793 3993 tlb = &env->tlb[entry].tlbe;
76a66253
JM
3994 /* Invalidate previous TLB (if it's valid) */
3995 if (tlb->prot & PAGE_VALID) {
3996 end = tlb->EPN + tlb->size;
90e189ec
BS
3997 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
3998 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
999fa40e 3999 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
76a66253 4000 tlb_flush_page(env, page);
999fa40e 4001 }
76a66253 4002 }
999fa40e
JC
4003 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
4004 & PPC4XX_TLBHI_SIZE_MASK);
c294fc58
JM
4005 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
4006 * If this ever occurs, one should use the ppcemb target instead
4007 * of the ppc or ppc64 one
4008 */
999fa40e 4009 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
71c8b8fd
JM
4010 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
4011 "are not supported (%d)\n",
74d37793 4012 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
c294fc58 4013 }
74d37793 4014 tlb->EPN = val & ~(tlb->size - 1);
999fa40e 4015 if (val & PPC4XX_TLBHI_V) {
76a66253 4016 tlb->prot |= PAGE_VALID;
999fa40e 4017 if (val & PPC4XX_TLBHI_E) {
c5b9729a
EI
4018 /* XXX: TO BE FIXED */
4019 cpu_abort(env,
4020 "Little-endian TLB entries are not supported by now\n");
4021 }
4022 } else {
76a66253 4023 tlb->prot &= ~PAGE_VALID;
c294fc58 4024 }
c55e9aef 4025 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
90e189ec
BS
4026 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
4027 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
4028 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4029 tlb->prot & PAGE_READ ? 'r' : '-',
4030 tlb->prot & PAGE_WRITE ? 'w' : '-',
4031 tlb->prot & PAGE_EXEC ? 'x' : '-',
4032 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
76a66253
JM
4033 /* Invalidate new TLB (if valid) */
4034 if (tlb->prot & PAGE_VALID) {
4035 end = tlb->EPN + tlb->size;
90e189ec
BS
4036 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
4037 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
999fa40e 4038 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
76a66253 4039 tlb_flush_page(env, page);
999fa40e 4040 }
76a66253 4041 }
76a66253
JM
4042}
4043
74d37793 4044void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
76a66253 4045{
c227f099 4046 ppcemb_tlb_t *tlb;
76a66253 4047
90e189ec
BS
4048 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
4049 val);
999fa40e 4050 entry &= PPC4XX_TLB_ENTRY_MASK;
74d37793 4051 tlb = &env->tlb[entry].tlbe;
999fa40e
JC
4052 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
4053 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
76a66253 4054 tlb->prot = PAGE_READ;
999fa40e 4055 if (val & PPC4XX_TLBLO_EX) {
76a66253 4056 tlb->prot |= PAGE_EXEC;
999fa40e
JC
4057 }
4058 if (val & PPC4XX_TLBLO_WR) {
76a66253 4059 tlb->prot |= PAGE_WRITE;
999fa40e 4060 }
90e189ec
BS
4061 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
4062 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
4063 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4064 tlb->prot & PAGE_READ ? 'r' : '-',
4065 tlb->prot & PAGE_WRITE ? 'w' : '-',
4066 tlb->prot & PAGE_EXEC ? 'x' : '-',
4067 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
76a66253 4068}
5eb7995e 4069
74d37793
AJ
4070target_ulong helper_4xx_tlbsx (target_ulong address)
4071{
4072 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
4073}
4074
a4bb6c3e 4075/* PowerPC 440 TLB management */
74d37793 4076void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
5eb7995e 4077{
c227f099 4078 ppcemb_tlb_t *tlb;
a4bb6c3e 4079 target_ulong EPN, RPN, size;
5eb7995e
JM
4080 int do_flush_tlbs;
4081
90e189ec
BS
4082 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
4083 __func__, word, (int)entry, value);
5eb7995e 4084 do_flush_tlbs = 0;
74d37793
AJ
4085 entry &= 0x3F;
4086 tlb = &env->tlb[entry].tlbe;
a4bb6c3e
JM
4087 switch (word) {
4088 default:
4089 /* Just here to please gcc */
4090 case 0:
74d37793 4091 EPN = value & 0xFFFFFC00;
a4bb6c3e 4092 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
5eb7995e 4093 do_flush_tlbs = 1;
a4bb6c3e 4094 tlb->EPN = EPN;
74d37793 4095 size = booke_tlb_to_page_size((value >> 4) & 0xF);
a4bb6c3e
JM
4096 if ((tlb->prot & PAGE_VALID) && tlb->size < size)
4097 do_flush_tlbs = 1;
4098 tlb->size = size;
4099 tlb->attr &= ~0x1;
74d37793
AJ
4100 tlb->attr |= (value >> 8) & 1;
4101 if (value & 0x200) {
a4bb6c3e
JM
4102 tlb->prot |= PAGE_VALID;
4103 } else {
4104 if (tlb->prot & PAGE_VALID) {
4105 tlb->prot &= ~PAGE_VALID;
4106 do_flush_tlbs = 1;
4107 }
5eb7995e 4108 }
a4bb6c3e
JM
4109 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
4110 if (do_flush_tlbs)
4111 tlb_flush(env, 1);
4112 break;
4113 case 1:
74d37793 4114 RPN = value & 0xFFFFFC0F;
a4bb6c3e
JM
4115 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
4116 tlb_flush(env, 1);
4117 tlb->RPN = RPN;
4118 break;
4119 case 2:
74d37793 4120 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
a4bb6c3e 4121 tlb->prot = tlb->prot & PAGE_VALID;
74d37793 4122 if (value & 0x1)
a4bb6c3e 4123 tlb->prot |= PAGE_READ << 4;
74d37793 4124 if (value & 0x2)
a4bb6c3e 4125 tlb->prot |= PAGE_WRITE << 4;
74d37793 4126 if (value & 0x4)
a4bb6c3e 4127 tlb->prot |= PAGE_EXEC << 4;
74d37793 4128 if (value & 0x8)
a4bb6c3e 4129 tlb->prot |= PAGE_READ;
74d37793 4130 if (value & 0x10)
a4bb6c3e 4131 tlb->prot |= PAGE_WRITE;
74d37793 4132 if (value & 0x20)
a4bb6c3e
JM
4133 tlb->prot |= PAGE_EXEC;
4134 break;
5eb7995e 4135 }
5eb7995e
JM
4136}
4137
74d37793 4138target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
5eb7995e 4139{
c227f099 4140 ppcemb_tlb_t *tlb;
74d37793 4141 target_ulong ret;
5eb7995e
JM
4142 int size;
4143
74d37793
AJ
4144 entry &= 0x3F;
4145 tlb = &env->tlb[entry].tlbe;
a4bb6c3e
JM
4146 switch (word) {
4147 default:
4148 /* Just here to please gcc */
4149 case 0:
74d37793 4150 ret = tlb->EPN;
a4bb6c3e
JM
4151 size = booke_page_size_to_tlb(tlb->size);
4152 if (size < 0 || size > 0xF)
4153 size = 1;
74d37793 4154 ret |= size << 4;
a4bb6c3e 4155 if (tlb->attr & 0x1)
74d37793 4156 ret |= 0x100;
a4bb6c3e 4157 if (tlb->prot & PAGE_VALID)
74d37793 4158 ret |= 0x200;
a4bb6c3e
JM
4159 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
4160 env->spr[SPR_440_MMUCR] |= tlb->PID;
4161 break;
4162 case 1:
74d37793 4163 ret = tlb->RPN;
a4bb6c3e
JM
4164 break;
4165 case 2:
74d37793 4166 ret = tlb->attr & ~0x1;
a4bb6c3e 4167 if (tlb->prot & (PAGE_READ << 4))
74d37793 4168 ret |= 0x1;
a4bb6c3e 4169 if (tlb->prot & (PAGE_WRITE << 4))
74d37793 4170 ret |= 0x2;
a4bb6c3e 4171 if (tlb->prot & (PAGE_EXEC << 4))
74d37793 4172 ret |= 0x4;
a4bb6c3e 4173 if (tlb->prot & PAGE_READ)
74d37793 4174 ret |= 0x8;
a4bb6c3e 4175 if (tlb->prot & PAGE_WRITE)
74d37793 4176 ret |= 0x10;
a4bb6c3e 4177 if (tlb->prot & PAGE_EXEC)
74d37793 4178 ret |= 0x20;
a4bb6c3e
JM
4179 break;
4180 }
74d37793 4181 return ret;
5eb7995e 4182}
74d37793
AJ
4183
4184target_ulong helper_440_tlbsx (target_ulong address)
4185{
4186 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
4187}
4188
76a66253 4189#endif /* !CONFIG_USER_ONLY */