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