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