]> git.proxmox.com Git - qemu.git/blame - target-ppc/op_helper.c
Add vsldoi instruction.
[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
07ef34c3
AJ
2189#define VSR(suffix, element) \
2190 void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2191 { \
2192 int i; \
2193 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2194 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2195 unsigned int shift = b->element[i] & mask; \
2196 r->element[i] = a->element[i] >> shift; \
2197 } \
2198 }
2199VSR(ab, s8)
2200VSR(ah, s16)
2201VSR(aw, s32)
2202VSR(b, u8)
2203VSR(h, u16)
2204VSR(w, u32)
2205#undef VSR
2206
7b239bec
AJ
2207void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2208{
2209 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2210
2211#if defined (WORDS_BIGENDIAN)
2212 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2213 memset (&r->u8[0], 0, sh);
2214#else
2215 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2216 memset (&r->u8[16-sh], 0, sh);
2217#endif
2218}
2219
e343da72
AJ
2220void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2221{
2222 int i;
2223 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2224 r->u32[i] = a->u32[i] >= b->u32[i];
2225 }
2226}
2227
d6a46fe8
AJ
2228#undef VECTOR_FOR_INORDER_I
2229#undef HI_IDX
2230#undef LO_IDX
2231
1c97856d 2232/*****************************************************************************/
0487d6a8
JM
2233/* SPE extension helpers */
2234/* Use a table to make this quicker */
2235static uint8_t hbrev[16] = {
2236 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
2237 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
2238};
2239
b068d6a7 2240static always_inline uint8_t byte_reverse (uint8_t val)
0487d6a8
JM
2241{
2242 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
2243}
2244
b068d6a7 2245static always_inline uint32_t word_reverse (uint32_t val)
0487d6a8
JM
2246{
2247 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
2248 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
2249}
2250
3cd7d1dd 2251#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
57951c27 2252target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
0487d6a8
JM
2253{
2254 uint32_t a, b, d, mask;
2255
3cd7d1dd 2256 mask = UINT32_MAX >> (32 - MASKBITS);
57951c27
AJ
2257 a = arg1 & mask;
2258 b = arg2 & mask;
3cd7d1dd 2259 d = word_reverse(1 + word_reverse(a | ~b));
57951c27 2260 return (arg1 & ~mask) | (d & b);
0487d6a8
JM
2261}
2262
57951c27 2263uint32_t helper_cntlsw32 (uint32_t val)
0487d6a8
JM
2264{
2265 if (val & 0x80000000)
603fccce 2266 return clz32(~val);
0487d6a8 2267 else
603fccce 2268 return clz32(val);
0487d6a8
JM
2269}
2270
57951c27 2271uint32_t helper_cntlzw32 (uint32_t val)
0487d6a8 2272{
603fccce 2273 return clz32(val);
0487d6a8
JM
2274}
2275
1c97856d
AJ
2276/* Single-precision floating-point conversions */
2277static always_inline uint32_t efscfsi (uint32_t val)
0487d6a8 2278{
0ca9d380 2279 CPU_FloatU u;
0487d6a8
JM
2280
2281 u.f = int32_to_float32(val, &env->spe_status);
2282
0ca9d380 2283 return u.l;
0487d6a8
JM
2284}
2285
1c97856d 2286static always_inline uint32_t efscfui (uint32_t val)
0487d6a8 2287{
0ca9d380 2288 CPU_FloatU u;
0487d6a8
JM
2289
2290 u.f = uint32_to_float32(val, &env->spe_status);
2291
0ca9d380 2292 return u.l;
0487d6a8
JM
2293}
2294
1c97856d 2295static always_inline int32_t efsctsi (uint32_t val)
0487d6a8 2296{
0ca9d380 2297 CPU_FloatU u;
0487d6a8 2298
0ca9d380 2299 u.l = val;
0487d6a8 2300 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2301 if (unlikely(float32_is_nan(u.f)))
0487d6a8
JM
2302 return 0;
2303
2304 return float32_to_int32(u.f, &env->spe_status);
2305}
2306
1c97856d 2307static always_inline uint32_t efsctui (uint32_t val)
0487d6a8 2308{
0ca9d380 2309 CPU_FloatU u;
0487d6a8 2310
0ca9d380 2311 u.l = val;
0487d6a8 2312 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2313 if (unlikely(float32_is_nan(u.f)))
0487d6a8
JM
2314 return 0;
2315
2316 return float32_to_uint32(u.f, &env->spe_status);
2317}
2318
1c97856d 2319static always_inline uint32_t efsctsiz (uint32_t val)
0487d6a8 2320{
0ca9d380 2321 CPU_FloatU u;
0487d6a8 2322
0ca9d380 2323 u.l = val;
0487d6a8 2324 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2325 if (unlikely(float32_is_nan(u.f)))
0487d6a8
JM
2326 return 0;
2327
2328 return float32_to_int32_round_to_zero(u.f, &env->spe_status);
2329}
2330
1c97856d 2331static always_inline uint32_t efsctuiz (uint32_t val)
0487d6a8 2332{
0ca9d380 2333 CPU_FloatU u;
0487d6a8 2334
0ca9d380 2335 u.l = val;
0487d6a8 2336 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2337 if (unlikely(float32_is_nan(u.f)))
0487d6a8
JM
2338 return 0;
2339
2340 return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
2341}
2342
1c97856d 2343static always_inline uint32_t efscfsf (uint32_t val)
0487d6a8 2344{
0ca9d380 2345 CPU_FloatU u;
0487d6a8
JM
2346 float32 tmp;
2347
2348 u.f = int32_to_float32(val, &env->spe_status);
2349 tmp = int64_to_float32(1ULL << 32, &env->spe_status);
2350 u.f = float32_div(u.f, tmp, &env->spe_status);
2351
0ca9d380 2352 return u.l;
0487d6a8
JM
2353}
2354
1c97856d 2355static always_inline uint32_t efscfuf (uint32_t val)
0487d6a8 2356{
0ca9d380 2357 CPU_FloatU u;
0487d6a8
JM
2358 float32 tmp;
2359
2360 u.f = uint32_to_float32(val, &env->spe_status);
2361 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2362 u.f = float32_div(u.f, tmp, &env->spe_status);
2363
0ca9d380 2364 return u.l;
0487d6a8
JM
2365}
2366
1c97856d 2367static always_inline uint32_t efsctsf (uint32_t val)
0487d6a8 2368{
0ca9d380 2369 CPU_FloatU u;
0487d6a8
JM
2370 float32 tmp;
2371
0ca9d380 2372 u.l = val;
0487d6a8 2373 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2374 if (unlikely(float32_is_nan(u.f)))
0487d6a8
JM
2375 return 0;
2376 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2377 u.f = float32_mul(u.f, tmp, &env->spe_status);
2378
2379 return float32_to_int32(u.f, &env->spe_status);
2380}
2381
1c97856d 2382static always_inline uint32_t efsctuf (uint32_t val)
0487d6a8 2383{
0ca9d380 2384 CPU_FloatU u;
0487d6a8
JM
2385 float32 tmp;
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 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2392 u.f = float32_mul(u.f, tmp, &env->spe_status);
2393
2394 return float32_to_uint32(u.f, &env->spe_status);
2395}
2396
1c97856d
AJ
2397#define HELPER_SPE_SINGLE_CONV(name) \
2398uint32_t helper_e##name (uint32_t val) \
2399{ \
2400 return e##name(val); \
2401}
2402/* efscfsi */
2403HELPER_SPE_SINGLE_CONV(fscfsi);
2404/* efscfui */
2405HELPER_SPE_SINGLE_CONV(fscfui);
2406/* efscfuf */
2407HELPER_SPE_SINGLE_CONV(fscfuf);
2408/* efscfsf */
2409HELPER_SPE_SINGLE_CONV(fscfsf);
2410/* efsctsi */
2411HELPER_SPE_SINGLE_CONV(fsctsi);
2412/* efsctui */
2413HELPER_SPE_SINGLE_CONV(fsctui);
2414/* efsctsiz */
2415HELPER_SPE_SINGLE_CONV(fsctsiz);
2416/* efsctuiz */
2417HELPER_SPE_SINGLE_CONV(fsctuiz);
2418/* efsctsf */
2419HELPER_SPE_SINGLE_CONV(fsctsf);
2420/* efsctuf */
2421HELPER_SPE_SINGLE_CONV(fsctuf);
2422
2423#define HELPER_SPE_VECTOR_CONV(name) \
2424uint64_t helper_ev##name (uint64_t val) \
2425{ \
2426 return ((uint64_t)e##name(val >> 32) << 32) | \
2427 (uint64_t)e##name(val); \
0487d6a8 2428}
1c97856d
AJ
2429/* evfscfsi */
2430HELPER_SPE_VECTOR_CONV(fscfsi);
2431/* evfscfui */
2432HELPER_SPE_VECTOR_CONV(fscfui);
2433/* evfscfuf */
2434HELPER_SPE_VECTOR_CONV(fscfuf);
2435/* evfscfsf */
2436HELPER_SPE_VECTOR_CONV(fscfsf);
2437/* evfsctsi */
2438HELPER_SPE_VECTOR_CONV(fsctsi);
2439/* evfsctui */
2440HELPER_SPE_VECTOR_CONV(fsctui);
2441/* evfsctsiz */
2442HELPER_SPE_VECTOR_CONV(fsctsiz);
2443/* evfsctuiz */
2444HELPER_SPE_VECTOR_CONV(fsctuiz);
2445/* evfsctsf */
2446HELPER_SPE_VECTOR_CONV(fsctsf);
2447/* evfsctuf */
2448HELPER_SPE_VECTOR_CONV(fsctuf);
0487d6a8 2449
1c97856d
AJ
2450/* Single-precision floating-point arithmetic */
2451static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
0487d6a8 2452{
1c97856d
AJ
2453 CPU_FloatU u1, u2;
2454 u1.l = op1;
2455 u2.l = op2;
2456 u1.f = float32_add(u1.f, u2.f, &env->spe_status);
2457 return u1.l;
0487d6a8
JM
2458}
2459
1c97856d 2460static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
0487d6a8 2461{
1c97856d
AJ
2462 CPU_FloatU u1, u2;
2463 u1.l = op1;
2464 u2.l = op2;
2465 u1.f = float32_sub(u1.f, u2.f, &env->spe_status);
2466 return u1.l;
0487d6a8
JM
2467}
2468
1c97856d 2469static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
0487d6a8 2470{
1c97856d
AJ
2471 CPU_FloatU u1, u2;
2472 u1.l = op1;
2473 u2.l = op2;
2474 u1.f = float32_mul(u1.f, u2.f, &env->spe_status);
2475 return u1.l;
0487d6a8
JM
2476}
2477
1c97856d 2478static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
0487d6a8 2479{
1c97856d
AJ
2480 CPU_FloatU u1, u2;
2481 u1.l = op1;
2482 u2.l = op2;
2483 u1.f = float32_div(u1.f, u2.f, &env->spe_status);
2484 return u1.l;
0487d6a8
JM
2485}
2486
1c97856d
AJ
2487#define HELPER_SPE_SINGLE_ARITH(name) \
2488uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
2489{ \
2490 return e##name(op1, op2); \
2491}
2492/* efsadd */
2493HELPER_SPE_SINGLE_ARITH(fsadd);
2494/* efssub */
2495HELPER_SPE_SINGLE_ARITH(fssub);
2496/* efsmul */
2497HELPER_SPE_SINGLE_ARITH(fsmul);
2498/* efsdiv */
2499HELPER_SPE_SINGLE_ARITH(fsdiv);
2500
2501#define HELPER_SPE_VECTOR_ARITH(name) \
2502uint64_t helper_ev##name (uint64_t op1, uint64_t op2) \
2503{ \
2504 return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
2505 (uint64_t)e##name(op1, op2); \
2506}
2507/* evfsadd */
2508HELPER_SPE_VECTOR_ARITH(fsadd);
2509/* evfssub */
2510HELPER_SPE_VECTOR_ARITH(fssub);
2511/* evfsmul */
2512HELPER_SPE_VECTOR_ARITH(fsmul);
2513/* evfsdiv */
2514HELPER_SPE_VECTOR_ARITH(fsdiv);
2515
2516/* Single-precision floating-point comparisons */
2517static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
0487d6a8 2518{
1c97856d
AJ
2519 CPU_FloatU u1, u2;
2520 u1.l = op1;
2521 u2.l = op2;
2522 return float32_lt(u1.f, u2.f, &env->spe_status) ? 4 : 0;
0487d6a8
JM
2523}
2524
1c97856d 2525static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
0487d6a8 2526{
1c97856d
AJ
2527 CPU_FloatU u1, u2;
2528 u1.l = op1;
2529 u2.l = op2;
2530 return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 4;
0487d6a8
JM
2531}
2532
1c97856d 2533static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
0487d6a8 2534{
1c97856d
AJ
2535 CPU_FloatU u1, u2;
2536 u1.l = op1;
2537 u2.l = op2;
2538 return float32_eq(u1.f, u2.f, &env->spe_status) ? 4 : 0;
0487d6a8
JM
2539}
2540
1c97856d 2541static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
0487d6a8
JM
2542{
2543 /* XXX: TODO: test special values (NaN, infinites, ...) */
1c97856d 2544 return efststlt(op1, op2);
0487d6a8
JM
2545}
2546
1c97856d 2547static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
0487d6a8
JM
2548{
2549 /* XXX: TODO: test special values (NaN, infinites, ...) */
1c97856d 2550 return efststgt(op1, op2);
0487d6a8
JM
2551}
2552
1c97856d 2553static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
0487d6a8
JM
2554{
2555 /* XXX: TODO: test special values (NaN, infinites, ...) */
1c97856d 2556 return efststeq(op1, op2);
0487d6a8
JM
2557}
2558
1c97856d
AJ
2559#define HELPER_SINGLE_SPE_CMP(name) \
2560uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
2561{ \
2562 return e##name(op1, op2) << 2; \
2563}
2564/* efststlt */
2565HELPER_SINGLE_SPE_CMP(fststlt);
2566/* efststgt */
2567HELPER_SINGLE_SPE_CMP(fststgt);
2568/* efststeq */
2569HELPER_SINGLE_SPE_CMP(fststeq);
2570/* efscmplt */
2571HELPER_SINGLE_SPE_CMP(fscmplt);
2572/* efscmpgt */
2573HELPER_SINGLE_SPE_CMP(fscmpgt);
2574/* efscmpeq */
2575HELPER_SINGLE_SPE_CMP(fscmpeq);
2576
2577static always_inline uint32_t evcmp_merge (int t0, int t1)
0487d6a8 2578{
1c97856d 2579 return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
0487d6a8
JM
2580}
2581
1c97856d
AJ
2582#define HELPER_VECTOR_SPE_CMP(name) \
2583uint32_t helper_ev##name (uint64_t op1, uint64_t op2) \
2584{ \
2585 return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
0487d6a8 2586}
1c97856d
AJ
2587/* evfststlt */
2588HELPER_VECTOR_SPE_CMP(fststlt);
2589/* evfststgt */
2590HELPER_VECTOR_SPE_CMP(fststgt);
2591/* evfststeq */
2592HELPER_VECTOR_SPE_CMP(fststeq);
2593/* evfscmplt */
2594HELPER_VECTOR_SPE_CMP(fscmplt);
2595/* evfscmpgt */
2596HELPER_VECTOR_SPE_CMP(fscmpgt);
2597/* evfscmpeq */
2598HELPER_VECTOR_SPE_CMP(fscmpeq);
0487d6a8 2599
1c97856d
AJ
2600/* Double-precision floating-point conversion */
2601uint64_t helper_efdcfsi (uint32_t val)
0487d6a8 2602{
1c97856d
AJ
2603 CPU_DoubleU u;
2604
2605 u.d = int32_to_float64(val, &env->spe_status);
2606
2607 return u.ll;
0487d6a8
JM
2608}
2609
1c97856d 2610uint64_t helper_efdcfsid (uint64_t val)
0487d6a8 2611{
0ca9d380 2612 CPU_DoubleU u;
0487d6a8 2613
0ca9d380 2614 u.d = int64_to_float64(val, &env->spe_status);
0487d6a8 2615
0ca9d380 2616 return u.ll;
0487d6a8
JM
2617}
2618
1c97856d
AJ
2619uint64_t helper_efdcfui (uint32_t val)
2620{
2621 CPU_DoubleU u;
2622
2623 u.d = uint32_to_float64(val, &env->spe_status);
2624
2625 return u.ll;
2626}
2627
2628uint64_t helper_efdcfuid (uint64_t val)
0487d6a8 2629{
0ca9d380 2630 CPU_DoubleU u;
0487d6a8 2631
0ca9d380 2632 u.d = uint64_to_float64(val, &env->spe_status);
0487d6a8 2633
0ca9d380 2634 return u.ll;
0487d6a8
JM
2635}
2636
1c97856d 2637uint32_t helper_efdctsi (uint64_t val)
0487d6a8 2638{
0ca9d380 2639 CPU_DoubleU u;
0487d6a8 2640
0ca9d380 2641 u.ll = val;
0487d6a8 2642 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2643 if (unlikely(float64_is_nan(u.d)))
0487d6a8
JM
2644 return 0;
2645
1c97856d 2646 return float64_to_int32(u.d, &env->spe_status);
0487d6a8
JM
2647}
2648
1c97856d 2649uint32_t helper_efdctui (uint64_t val)
0487d6a8 2650{
0ca9d380 2651 CPU_DoubleU u;
0487d6a8 2652
0ca9d380 2653 u.ll = val;
0487d6a8 2654 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2655 if (unlikely(float64_is_nan(u.d)))
0487d6a8
JM
2656 return 0;
2657
1c97856d 2658 return float64_to_uint32(u.d, &env->spe_status);
0487d6a8
JM
2659}
2660
1c97856d 2661uint32_t helper_efdctsiz (uint64_t val)
0487d6a8 2662{
0ca9d380 2663 CPU_DoubleU u;
0487d6a8 2664
0ca9d380 2665 u.ll = val;
0487d6a8 2666 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2667 if (unlikely(float64_is_nan(u.d)))
0487d6a8
JM
2668 return 0;
2669
1c97856d 2670 return float64_to_int32_round_to_zero(u.d, &env->spe_status);
0487d6a8
JM
2671}
2672
1c97856d 2673uint64_t helper_efdctsidz (uint64_t val)
0487d6a8 2674{
0ca9d380 2675 CPU_DoubleU u;
0487d6a8 2676
0ca9d380 2677 u.ll = val;
0487d6a8 2678 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2679 if (unlikely(float64_is_nan(u.d)))
0487d6a8
JM
2680 return 0;
2681
1c97856d 2682 return float64_to_int64_round_to_zero(u.d, &env->spe_status);
0487d6a8
JM
2683}
2684
1c97856d 2685uint32_t helper_efdctuiz (uint64_t val)
0487d6a8 2686{
1c97856d 2687 CPU_DoubleU u;
0487d6a8 2688
1c97856d
AJ
2689 u.ll = val;
2690 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2691 if (unlikely(float64_is_nan(u.d)))
1c97856d 2692 return 0;
0487d6a8 2693
1c97856d 2694 return float64_to_uint32_round_to_zero(u.d, &env->spe_status);
0487d6a8
JM
2695}
2696
1c97856d 2697uint64_t helper_efdctuidz (uint64_t val)
0487d6a8 2698{
1c97856d 2699 CPU_DoubleU u;
0487d6a8 2700
1c97856d
AJ
2701 u.ll = val;
2702 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2703 if (unlikely(float64_is_nan(u.d)))
1c97856d 2704 return 0;
0487d6a8 2705
1c97856d 2706 return float64_to_uint64_round_to_zero(u.d, &env->spe_status);
0487d6a8
JM
2707}
2708
1c97856d 2709uint64_t helper_efdcfsf (uint32_t val)
0487d6a8 2710{
0ca9d380 2711 CPU_DoubleU u;
0487d6a8
JM
2712 float64 tmp;
2713
0ca9d380 2714 u.d = int32_to_float64(val, &env->spe_status);
0487d6a8 2715 tmp = int64_to_float64(1ULL << 32, &env->spe_status);
0ca9d380 2716 u.d = float64_div(u.d, tmp, &env->spe_status);
0487d6a8 2717
0ca9d380 2718 return u.ll;
0487d6a8
JM
2719}
2720
1c97856d 2721uint64_t helper_efdcfuf (uint32_t val)
0487d6a8 2722{
0ca9d380 2723 CPU_DoubleU u;
0487d6a8
JM
2724 float64 tmp;
2725
0ca9d380 2726 u.d = uint32_to_float64(val, &env->spe_status);
0487d6a8 2727 tmp = int64_to_float64(1ULL << 32, &env->spe_status);
0ca9d380 2728 u.d = float64_div(u.d, tmp, &env->spe_status);
0487d6a8 2729
0ca9d380 2730 return u.ll;
0487d6a8
JM
2731}
2732
1c97856d 2733uint32_t helper_efdctsf (uint64_t val)
0487d6a8 2734{
0ca9d380 2735 CPU_DoubleU u;
0487d6a8
JM
2736 float64 tmp;
2737
0ca9d380 2738 u.ll = val;
0487d6a8 2739 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2740 if (unlikely(float64_is_nan(u.d)))
0487d6a8
JM
2741 return 0;
2742 tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
0ca9d380 2743 u.d = float64_mul(u.d, tmp, &env->spe_status);
0487d6a8 2744
0ca9d380 2745 return float64_to_int32(u.d, &env->spe_status);
0487d6a8
JM
2746}
2747
1c97856d 2748uint32_t helper_efdctuf (uint64_t val)
0487d6a8 2749{
0ca9d380 2750 CPU_DoubleU u;
0487d6a8
JM
2751 float64 tmp;
2752
0ca9d380 2753 u.ll = val;
0487d6a8 2754 /* NaN are not treated the same way IEEE 754 does */
a44d2ce1 2755 if (unlikely(float64_is_nan(u.d)))
0487d6a8
JM
2756 return 0;
2757 tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
0ca9d380 2758 u.d = float64_mul(u.d, tmp, &env->spe_status);
0487d6a8 2759
0ca9d380 2760 return float64_to_uint32(u.d, &env->spe_status);
0487d6a8
JM
2761}
2762
1c97856d 2763uint32_t helper_efscfd (uint64_t val)
0487d6a8 2764{
0ca9d380
AJ
2765 CPU_DoubleU u1;
2766 CPU_FloatU u2;
0487d6a8 2767
0ca9d380
AJ
2768 u1.ll = val;
2769 u2.f = float64_to_float32(u1.d, &env->spe_status);
0487d6a8 2770
0ca9d380 2771 return u2.l;
0487d6a8
JM
2772}
2773
1c97856d 2774uint64_t helper_efdcfs (uint32_t val)
0487d6a8 2775{
0ca9d380
AJ
2776 CPU_DoubleU u2;
2777 CPU_FloatU u1;
0487d6a8 2778
0ca9d380
AJ
2779 u1.l = val;
2780 u2.d = float32_to_float64(u1.f, &env->spe_status);
0487d6a8 2781
0ca9d380 2782 return u2.ll;
0487d6a8
JM
2783}
2784
1c97856d
AJ
2785/* Double precision fixed-point arithmetic */
2786uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
0487d6a8 2787{
1c97856d
AJ
2788 CPU_DoubleU u1, u2;
2789 u1.ll = op1;
2790 u2.ll = op2;
2791 u1.d = float64_add(u1.d, u2.d, &env->spe_status);
2792 return u1.ll;
0487d6a8
JM
2793}
2794
1c97856d 2795uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
0487d6a8 2796{
1c97856d
AJ
2797 CPU_DoubleU u1, u2;
2798 u1.ll = op1;
2799 u2.ll = op2;
2800 u1.d = float64_sub(u1.d, u2.d, &env->spe_status);
2801 return u1.ll;
0487d6a8
JM
2802}
2803
1c97856d 2804uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
0487d6a8 2805{
1c97856d
AJ
2806 CPU_DoubleU u1, u2;
2807 u1.ll = op1;
2808 u2.ll = op2;
2809 u1.d = float64_mul(u1.d, u2.d, &env->spe_status);
2810 return u1.ll;
0487d6a8
JM
2811}
2812
1c97856d 2813uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
0487d6a8 2814{
1c97856d
AJ
2815 CPU_DoubleU u1, u2;
2816 u1.ll = op1;
2817 u2.ll = op2;
2818 u1.d = float64_div(u1.d, u2.d, &env->spe_status);
2819 return u1.ll;
0487d6a8
JM
2820}
2821
1c97856d
AJ
2822/* Double precision floating point helpers */
2823uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
0487d6a8 2824{
1c97856d
AJ
2825 CPU_DoubleU u1, u2;
2826 u1.ll = op1;
2827 u2.ll = op2;
2828 return float64_lt(u1.d, u2.d, &env->spe_status) ? 4 : 0;
0487d6a8
JM
2829}
2830
1c97856d 2831uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
0487d6a8 2832{
1c97856d
AJ
2833 CPU_DoubleU u1, u2;
2834 u1.ll = op1;
2835 u2.ll = op2;
2836 return float64_le(u1.d, u2.d, &env->spe_status) ? 0 : 4;
0487d6a8
JM
2837}
2838
1c97856d 2839uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
0487d6a8 2840{
1c97856d
AJ
2841 CPU_DoubleU u1, u2;
2842 u1.ll = op1;
2843 u2.ll = op2;
2844 return float64_eq(u1.d, u2.d, &env->spe_status) ? 4 : 0;
0487d6a8
JM
2845}
2846
1c97856d 2847uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
0487d6a8 2848{
1c97856d
AJ
2849 /* XXX: TODO: test special values (NaN, infinites, ...) */
2850 return helper_efdtstlt(op1, op2);
0487d6a8
JM
2851}
2852
1c97856d
AJ
2853uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
2854{
2855 /* XXX: TODO: test special values (NaN, infinites, ...) */
2856 return helper_efdtstgt(op1, op2);
2857}
0487d6a8 2858
1c97856d
AJ
2859uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
2860{
2861 /* XXX: TODO: test special values (NaN, infinites, ...) */
2862 return helper_efdtsteq(op1, op2);
2863}
0487d6a8 2864
fdabc366
FB
2865/*****************************************************************************/
2866/* Softmmu support */
2867#if !defined (CONFIG_USER_ONLY)
2868
2869#define MMUSUFFIX _mmu
fdabc366
FB
2870
2871#define SHIFT 0
2872#include "softmmu_template.h"
2873
2874#define SHIFT 1
2875#include "softmmu_template.h"
2876
2877#define SHIFT 2
2878#include "softmmu_template.h"
2879
2880#define SHIFT 3
2881#include "softmmu_template.h"
2882
2883/* try to fill the TLB and return an exception if error. If retaddr is
2884 NULL, it means that the function was called in C code (i.e. not
2885 from generated code or from helper.c) */
2886/* XXX: fix it to restore all registers */
6ebbf390 2887void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
fdabc366
FB
2888{
2889 TranslationBlock *tb;
2890 CPUState *saved_env;
44f8625d 2891 unsigned long pc;
fdabc366
FB
2892 int ret;
2893
2894 /* XXX: hack to restore env in all cases, even if not called from
2895 generated code */
2896 saved_env = env;
2897 env = cpu_single_env;
6ebbf390 2898 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
76a66253 2899 if (unlikely(ret != 0)) {
fdabc366
FB
2900 if (likely(retaddr)) {
2901 /* now we have a real cpu fault */
44f8625d 2902 pc = (unsigned long)retaddr;
fdabc366
FB
2903 tb = tb_find_pc(pc);
2904 if (likely(tb)) {
2905 /* the PC is inside the translated code. It means that we have
2906 a virtual CPU fault */
2907 cpu_restore_state(tb, env, pc, NULL);
76a66253 2908 }
fdabc366 2909 }
e06fcd75 2910 helper_raise_exception_err(env->exception_index, env->error_code);
fdabc366
FB
2911 }
2912 env = saved_env;
9a64fbe4
FB
2913}
2914
74d37793
AJ
2915/* Segment registers load and store */
2916target_ulong helper_load_sr (target_ulong sr_num)
2917{
2918 return env->sr[sr_num];
2919}
2920
2921void helper_store_sr (target_ulong sr_num, target_ulong val)
2922{
45d827d2 2923 ppc_store_sr(env, sr_num, val);
74d37793
AJ
2924}
2925
2926/* SLB management */
2927#if defined(TARGET_PPC64)
2928target_ulong helper_load_slb (target_ulong slb_nr)
2929{
2930 return ppc_load_slb(env, slb_nr);
2931}
2932
2933void helper_store_slb (target_ulong slb_nr, target_ulong rs)
2934{
2935 ppc_store_slb(env, slb_nr, rs);
2936}
2937
2938void helper_slbia (void)
2939{
2940 ppc_slb_invalidate_all(env);
2941}
2942
2943void helper_slbie (target_ulong addr)
2944{
2945 ppc_slb_invalidate_one(env, addr);
2946}
2947
2948#endif /* defined(TARGET_PPC64) */
2949
2950/* TLB management */
2951void helper_tlbia (void)
2952{
2953 ppc_tlb_invalidate_all(env);
2954}
2955
2956void helper_tlbie (target_ulong addr)
2957{
2958 ppc_tlb_invalidate_one(env, addr);
2959}
2960
76a66253
JM
2961/* Software driven TLBs management */
2962/* PowerPC 602/603 software TLB load instructions helpers */
74d37793 2963static void do_6xx_tlb (target_ulong new_EPN, int is_code)
76a66253
JM
2964{
2965 target_ulong RPN, CMP, EPN;
2966 int way;
d9bce9d9 2967
76a66253
JM
2968 RPN = env->spr[SPR_RPA];
2969 if (is_code) {
2970 CMP = env->spr[SPR_ICMP];
2971 EPN = env->spr[SPR_IMISS];
2972 } else {
2973 CMP = env->spr[SPR_DCMP];
2974 EPN = env->spr[SPR_DMISS];
2975 }
2976 way = (env->spr[SPR_SRR1] >> 17) & 1;
2977#if defined (DEBUG_SOFTWARE_TLB)
2978 if (loglevel != 0) {
0e69805a 2979 fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
6b542af7 2980 " PTE1 " ADDRX " way %d\n",
0e69805a 2981 __func__, new_EPN, EPN, CMP, RPN, way);
76a66253
JM
2982 }
2983#endif
2984 /* Store this TLB */
0f3955e2 2985 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
d9bce9d9 2986 way, is_code, CMP, RPN);
76a66253
JM
2987}
2988
74d37793 2989void helper_6xx_tlbd (target_ulong EPN)
0f3955e2 2990{
74d37793 2991 do_6xx_tlb(EPN, 0);
0f3955e2
AJ
2992}
2993
74d37793 2994void helper_6xx_tlbi (target_ulong EPN)
0f3955e2 2995{
74d37793 2996 do_6xx_tlb(EPN, 1);
0f3955e2
AJ
2997}
2998
2999/* PowerPC 74xx software TLB load instructions helpers */
74d37793 3000static void do_74xx_tlb (target_ulong new_EPN, int is_code)
7dbe11ac
JM
3001{
3002 target_ulong RPN, CMP, EPN;
3003 int way;
3004
3005 RPN = env->spr[SPR_PTELO];
3006 CMP = env->spr[SPR_PTEHI];
3007 EPN = env->spr[SPR_TLBMISS] & ~0x3;
3008 way = env->spr[SPR_TLBMISS] & 0x3;
3009#if defined (DEBUG_SOFTWARE_TLB)
3010 if (loglevel != 0) {
0e69805a 3011 fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
6b542af7 3012 " PTE1 " ADDRX " way %d\n",
0e69805a 3013 __func__, new_EPN, EPN, CMP, RPN, way);
7dbe11ac
JM
3014 }
3015#endif
3016 /* Store this TLB */
0f3955e2 3017 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
7dbe11ac
JM
3018 way, is_code, CMP, RPN);
3019}
3020
74d37793 3021void helper_74xx_tlbd (target_ulong EPN)
0f3955e2 3022{
74d37793 3023 do_74xx_tlb(EPN, 0);
0f3955e2
AJ
3024}
3025
74d37793 3026void helper_74xx_tlbi (target_ulong EPN)
0f3955e2 3027{
74d37793 3028 do_74xx_tlb(EPN, 1);
0f3955e2
AJ
3029}
3030
a11b8151 3031static always_inline target_ulong booke_tlb_to_page_size (int size)
a8dea12f
JM
3032{
3033 return 1024 << (2 * size);
3034}
3035
a11b8151 3036static always_inline int booke_page_size_to_tlb (target_ulong page_size)
a8dea12f
JM
3037{
3038 int size;
3039
3040 switch (page_size) {
3041 case 0x00000400UL:
3042 size = 0x0;
3043 break;
3044 case 0x00001000UL:
3045 size = 0x1;
3046 break;
3047 case 0x00004000UL:
3048 size = 0x2;
3049 break;
3050 case 0x00010000UL:
3051 size = 0x3;
3052 break;
3053 case 0x00040000UL:
3054 size = 0x4;
3055 break;
3056 case 0x00100000UL:
3057 size = 0x5;
3058 break;
3059 case 0x00400000UL:
3060 size = 0x6;
3061 break;
3062 case 0x01000000UL:
3063 size = 0x7;
3064 break;
3065 case 0x04000000UL:
3066 size = 0x8;
3067 break;
3068 case 0x10000000UL:
3069 size = 0x9;
3070 break;
3071 case 0x40000000UL:
3072 size = 0xA;
3073 break;
3074#if defined (TARGET_PPC64)
3075 case 0x000100000000ULL:
3076 size = 0xB;
3077 break;
3078 case 0x000400000000ULL:
3079 size = 0xC;
3080 break;
3081 case 0x001000000000ULL:
3082 size = 0xD;
3083 break;
3084 case 0x004000000000ULL:
3085 size = 0xE;
3086 break;
3087 case 0x010000000000ULL:
3088 size = 0xF;
3089 break;
3090#endif
3091 default:
3092 size = -1;
3093 break;
3094 }
3095
3096 return size;
3097}
3098
76a66253 3099/* Helpers for 4xx TLB management */
74d37793 3100target_ulong helper_4xx_tlbre_lo (target_ulong entry)
76a66253 3101{
a8dea12f 3102 ppcemb_tlb_t *tlb;
74d37793 3103 target_ulong ret;
a8dea12f 3104 int size;
76a66253 3105
74d37793
AJ
3106 entry &= 0x3F;
3107 tlb = &env->tlb[entry].tlbe;
3108 ret = tlb->EPN;
a8dea12f 3109 if (tlb->prot & PAGE_VALID)
74d37793 3110 ret |= 0x400;
a8dea12f
JM
3111 size = booke_page_size_to_tlb(tlb->size);
3112 if (size < 0 || size > 0x7)
3113 size = 1;
74d37793 3114 ret |= size << 7;
a8dea12f 3115 env->spr[SPR_40x_PID] = tlb->PID;
74d37793 3116 return ret;
76a66253
JM
3117}
3118
74d37793 3119target_ulong helper_4xx_tlbre_hi (target_ulong entry)
76a66253 3120{
a8dea12f 3121 ppcemb_tlb_t *tlb;
74d37793 3122 target_ulong ret;
76a66253 3123
74d37793
AJ
3124 entry &= 0x3F;
3125 tlb = &env->tlb[entry].tlbe;
3126 ret = tlb->RPN;
a8dea12f 3127 if (tlb->prot & PAGE_EXEC)
74d37793 3128 ret |= 0x200;
a8dea12f 3129 if (tlb->prot & PAGE_WRITE)
74d37793
AJ
3130 ret |= 0x100;
3131 return ret;
76a66253
JM
3132}
3133
74d37793 3134void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
76a66253 3135{
a8dea12f 3136 ppcemb_tlb_t *tlb;
76a66253
JM
3137 target_ulong page, end;
3138
c55e9aef 3139#if defined (DEBUG_SOFTWARE_TLB)
6b80055d 3140 if (loglevel != 0) {
0e69805a 3141 fprintf(logfile, "%s entry %d val " ADDRX "\n", __func__, (int)entry, val);
c55e9aef
JM
3142 }
3143#endif
74d37793
AJ
3144 entry &= 0x3F;
3145 tlb = &env->tlb[entry].tlbe;
76a66253
JM
3146 /* Invalidate previous TLB (if it's valid) */
3147 if (tlb->prot & PAGE_VALID) {
3148 end = tlb->EPN + tlb->size;
c55e9aef 3149#if defined (DEBUG_SOFTWARE_TLB)
6b80055d 3150 if (loglevel != 0) {
c55e9aef 3151 fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
74d37793 3152 " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
c55e9aef
JM
3153 }
3154#endif
76a66253
JM
3155 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3156 tlb_flush_page(env, page);
3157 }
74d37793 3158 tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
c294fc58
JM
3159 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
3160 * If this ever occurs, one should use the ppcemb target instead
3161 * of the ppc or ppc64 one
3162 */
74d37793 3163 if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
71c8b8fd
JM
3164 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
3165 "are not supported (%d)\n",
74d37793 3166 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
c294fc58 3167 }
74d37793
AJ
3168 tlb->EPN = val & ~(tlb->size - 1);
3169 if (val & 0x40)
76a66253
JM
3170 tlb->prot |= PAGE_VALID;
3171 else
3172 tlb->prot &= ~PAGE_VALID;
74d37793 3173 if (val & 0x20) {
c294fc58
JM
3174 /* XXX: TO BE FIXED */
3175 cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
3176 }
c55e9aef 3177 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
74d37793 3178 tlb->attr = val & 0xFF;
c55e9aef 3179#if defined (DEBUG_SOFTWARE_TLB)
c294fc58
JM
3180 if (loglevel != 0) {
3181 fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
c55e9aef 3182 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
0e69805a 3183 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
c55e9aef
JM
3184 tlb->prot & PAGE_READ ? 'r' : '-',
3185 tlb->prot & PAGE_WRITE ? 'w' : '-',
3186 tlb->prot & PAGE_EXEC ? 'x' : '-',
3187 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3188 }
3189#endif
76a66253
JM
3190 /* Invalidate new TLB (if valid) */
3191 if (tlb->prot & PAGE_VALID) {
3192 end = tlb->EPN + tlb->size;
c55e9aef 3193#if defined (DEBUG_SOFTWARE_TLB)
6b80055d 3194 if (loglevel != 0) {
c55e9aef 3195 fprintf(logfile, "%s: invalidate TLB %d start " ADDRX
0e69805a 3196 " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
c55e9aef
JM
3197 }
3198#endif
76a66253
JM
3199 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3200 tlb_flush_page(env, page);
3201 }
76a66253
JM
3202}
3203
74d37793 3204void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
76a66253 3205{
a8dea12f 3206 ppcemb_tlb_t *tlb;
76a66253 3207
c55e9aef 3208#if defined (DEBUG_SOFTWARE_TLB)
6b80055d 3209 if (loglevel != 0) {
0e69805a 3210 fprintf(logfile, "%s entry %i val " ADDRX "\n", __func__, (int)entry, val);
c55e9aef
JM
3211 }
3212#endif
74d37793
AJ
3213 entry &= 0x3F;
3214 tlb = &env->tlb[entry].tlbe;
3215 tlb->RPN = val & 0xFFFFFC00;
76a66253 3216 tlb->prot = PAGE_READ;
74d37793 3217 if (val & 0x200)
76a66253 3218 tlb->prot |= PAGE_EXEC;
74d37793 3219 if (val & 0x100)
76a66253 3220 tlb->prot |= PAGE_WRITE;
c55e9aef 3221#if defined (DEBUG_SOFTWARE_TLB)
6b80055d
JM
3222 if (loglevel != 0) {
3223 fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
c55e9aef 3224 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
74d37793 3225 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
c55e9aef
JM
3226 tlb->prot & PAGE_READ ? 'r' : '-',
3227 tlb->prot & PAGE_WRITE ? 'w' : '-',
3228 tlb->prot & PAGE_EXEC ? 'x' : '-',
3229 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3230 }
3231#endif
76a66253 3232}
5eb7995e 3233
74d37793
AJ
3234target_ulong helper_4xx_tlbsx (target_ulong address)
3235{
3236 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
3237}
3238
a4bb6c3e 3239/* PowerPC 440 TLB management */
74d37793 3240void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
5eb7995e
JM
3241{
3242 ppcemb_tlb_t *tlb;
a4bb6c3e 3243 target_ulong EPN, RPN, size;
5eb7995e
JM
3244 int do_flush_tlbs;
3245
3246#if defined (DEBUG_SOFTWARE_TLB)
3247 if (loglevel != 0) {
0e69805a
AJ
3248 fprintf(logfile, "%s word %d entry %d value " ADDRX "\n",
3249 __func__, word, (int)entry, value);
5eb7995e
JM
3250 }
3251#endif
3252 do_flush_tlbs = 0;
74d37793
AJ
3253 entry &= 0x3F;
3254 tlb = &env->tlb[entry].tlbe;
a4bb6c3e
JM
3255 switch (word) {
3256 default:
3257 /* Just here to please gcc */
3258 case 0:
74d37793 3259 EPN = value & 0xFFFFFC00;
a4bb6c3e 3260 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
5eb7995e 3261 do_flush_tlbs = 1;
a4bb6c3e 3262 tlb->EPN = EPN;
74d37793 3263 size = booke_tlb_to_page_size((value >> 4) & 0xF);
a4bb6c3e
JM
3264 if ((tlb->prot & PAGE_VALID) && tlb->size < size)
3265 do_flush_tlbs = 1;
3266 tlb->size = size;
3267 tlb->attr &= ~0x1;
74d37793
AJ
3268 tlb->attr |= (value >> 8) & 1;
3269 if (value & 0x200) {
a4bb6c3e
JM
3270 tlb->prot |= PAGE_VALID;
3271 } else {
3272 if (tlb->prot & PAGE_VALID) {
3273 tlb->prot &= ~PAGE_VALID;
3274 do_flush_tlbs = 1;
3275 }
5eb7995e 3276 }
a4bb6c3e
JM
3277 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
3278 if (do_flush_tlbs)
3279 tlb_flush(env, 1);
3280 break;
3281 case 1:
74d37793 3282 RPN = value & 0xFFFFFC0F;
a4bb6c3e
JM
3283 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
3284 tlb_flush(env, 1);
3285 tlb->RPN = RPN;
3286 break;
3287 case 2:
74d37793 3288 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
a4bb6c3e 3289 tlb->prot = tlb->prot & PAGE_VALID;
74d37793 3290 if (value & 0x1)
a4bb6c3e 3291 tlb->prot |= PAGE_READ << 4;
74d37793 3292 if (value & 0x2)
a4bb6c3e 3293 tlb->prot |= PAGE_WRITE << 4;
74d37793 3294 if (value & 0x4)
a4bb6c3e 3295 tlb->prot |= PAGE_EXEC << 4;
74d37793 3296 if (value & 0x8)
a4bb6c3e 3297 tlb->prot |= PAGE_READ;
74d37793 3298 if (value & 0x10)
a4bb6c3e 3299 tlb->prot |= PAGE_WRITE;
74d37793 3300 if (value & 0x20)
a4bb6c3e
JM
3301 tlb->prot |= PAGE_EXEC;
3302 break;
5eb7995e 3303 }
5eb7995e
JM
3304}
3305
74d37793 3306target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
5eb7995e
JM
3307{
3308 ppcemb_tlb_t *tlb;
74d37793 3309 target_ulong ret;
5eb7995e
JM
3310 int size;
3311
74d37793
AJ
3312 entry &= 0x3F;
3313 tlb = &env->tlb[entry].tlbe;
a4bb6c3e
JM
3314 switch (word) {
3315 default:
3316 /* Just here to please gcc */
3317 case 0:
74d37793 3318 ret = tlb->EPN;
a4bb6c3e
JM
3319 size = booke_page_size_to_tlb(tlb->size);
3320 if (size < 0 || size > 0xF)
3321 size = 1;
74d37793 3322 ret |= size << 4;
a4bb6c3e 3323 if (tlb->attr & 0x1)
74d37793 3324 ret |= 0x100;
a4bb6c3e 3325 if (tlb->prot & PAGE_VALID)
74d37793 3326 ret |= 0x200;
a4bb6c3e
JM
3327 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
3328 env->spr[SPR_440_MMUCR] |= tlb->PID;
3329 break;
3330 case 1:
74d37793 3331 ret = tlb->RPN;
a4bb6c3e
JM
3332 break;
3333 case 2:
74d37793 3334 ret = tlb->attr & ~0x1;
a4bb6c3e 3335 if (tlb->prot & (PAGE_READ << 4))
74d37793 3336 ret |= 0x1;
a4bb6c3e 3337 if (tlb->prot & (PAGE_WRITE << 4))
74d37793 3338 ret |= 0x2;
a4bb6c3e 3339 if (tlb->prot & (PAGE_EXEC << 4))
74d37793 3340 ret |= 0x4;
a4bb6c3e 3341 if (tlb->prot & PAGE_READ)
74d37793 3342 ret |= 0x8;
a4bb6c3e 3343 if (tlb->prot & PAGE_WRITE)
74d37793 3344 ret |= 0x10;
a4bb6c3e 3345 if (tlb->prot & PAGE_EXEC)
74d37793 3346 ret |= 0x20;
a4bb6c3e
JM
3347 break;
3348 }
74d37793 3349 return ret;
5eb7995e 3350}
74d37793
AJ
3351
3352target_ulong helper_440_tlbsx (target_ulong address)
3353{
3354 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
3355}
3356
76a66253 3357#endif /* !CONFIG_USER_ONLY */