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