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