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