blob: 674a21dfbb4453a900795a619464f44bef33f9f1 [file] [log] [blame]
bellard9a64fbe2004-01-04 22:58:38 +00001/*
bellard3fc6c082005-07-02 20:59:34 +00002 * PowerPC emulation helpers for qemu.
ths5fafdf22007-09-16 21:08:06 +00003 *
j_mayer76a66252007-03-07 08:32:30 +00004 * Copyright (c) 2003-2007 Jocelyn Mayer
bellard9a64fbe2004-01-04 22:58:38 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
aurel32fad6cb12009-01-04 22:05:52 +000018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
bellard9a64fbe2004-01-04 22:58:38 +000019 */
aurel327b239be2009-01-04 22:09:19 +000020#include <string.h>
bellard9a64fbe2004-01-04 22:58:38 +000021#include "exec.h"
j_mayer603fccc2007-10-28 12:54:53 +000022#include "host-utils.h"
pbrooka7812ae2008-11-17 14:43:54 +000023#include "helper.h"
bellard9a64fbe2004-01-04 22:58:38 +000024
j_mayer0411a972007-10-25 21:35:50 +000025#include "helper_regs.h"
j_mayer0487d6a2007-03-20 22:11:31 +000026
bellardfdabc362005-07-04 22:17:05 +000027//#define DEBUG_OP
28//#define DEBUG_EXCEPTIONS
j_mayer76a66252007-03-07 08:32:30 +000029//#define DEBUG_SOFTWARE_TLB
bellardfdabc362005-07-04 22:17:05 +000030
aliguorid12d51d2009-01-15 21:48:06 +000031#ifdef DEBUG_SOFTWARE_TLB
aliguori93fcfe32009-01-15 22:34:14 +000032# define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
aliguorid12d51d2009-01-15 21:48:06 +000033#else
34# define LOG_SWTLB(...) do { } while (0)
35#endif
36
37
bellard9a64fbe2004-01-04 22:58:38 +000038/*****************************************************************************/
39/* Exceptions processing helpers */
bellard9a64fbe2004-01-04 22:58:38 +000040
aurel3264adab32008-11-22 10:09:17 +000041void helper_raise_exception_err (uint32_t exception, uint32_t error_code)
bellard9a64fbe2004-01-04 22:58:38 +000042{
aurel32e06fcd72008-12-11 22:42:14 +000043#if 0
44 printf("Raise exception %3x code : %d\n", exception, error_code);
45#endif
46 env->exception_index = exception;
47 env->error_code = error_code;
48 cpu_loop_exit();
j_mayer76a66252007-03-07 08:32:30 +000049}
bellard9fddaa02004-05-21 12:59:32 +000050
aurel32e06fcd72008-12-11 22:42:14 +000051void helper_raise_exception (uint32_t exception)
bellard9fddaa02004-05-21 12:59:32 +000052{
aurel32e06fcd72008-12-11 22:42:14 +000053 helper_raise_exception_err(exception, 0);
bellard9a64fbe2004-01-04 22:58:38 +000054}
55
56/*****************************************************************************/
j_mayer76a66252007-03-07 08:32:30 +000057/* Registers load and stores */
pbrooka7812ae2008-11-17 14:43:54 +000058target_ulong helper_load_cr (void)
j_mayer76a66252007-03-07 08:32:30 +000059{
aurel32e1571902008-10-21 11:31:14 +000060 return (env->crf[0] << 28) |
61 (env->crf[1] << 24) |
62 (env->crf[2] << 20) |
63 (env->crf[3] << 16) |
64 (env->crf[4] << 12) |
65 (env->crf[5] << 8) |
66 (env->crf[6] << 4) |
67 (env->crf[7] << 0);
j_mayer76a66252007-03-07 08:32:30 +000068}
69
aurel32e1571902008-10-21 11:31:14 +000070void helper_store_cr (target_ulong val, uint32_t mask)
j_mayer76a66252007-03-07 08:32:30 +000071{
72 int i, sh;
73
j_mayer36081602007-09-17 08:21:54 +000074 for (i = 0, sh = 7; i < 8; i++, sh--) {
j_mayer76a66252007-03-07 08:32:30 +000075 if (mask & (1 << sh))
aurel32e1571902008-10-21 11:31:14 +000076 env->crf[i] = (val >> (sh * 4)) & 0xFUL;
j_mayer76a66252007-03-07 08:32:30 +000077 }
78}
79
aurel3245d827d2008-12-07 13:40:29 +000080/*****************************************************************************/
81/* SPR accesses */
82void helper_load_dump_spr (uint32_t sprn)
j_mayera4967752007-04-16 07:10:48 +000083{
aliguori93fcfe32009-01-15 22:34:14 +000084 qemu_log("Read SPR %d %03x => " ADDRX "\n",
j_mayera4967752007-04-16 07:10:48 +000085 sprn, sprn, env->spr[sprn]);
j_mayera4967752007-04-16 07:10:48 +000086}
87
aurel3245d827d2008-12-07 13:40:29 +000088void helper_store_dump_spr (uint32_t sprn)
j_mayera4967752007-04-16 07:10:48 +000089{
aliguori93fcfe32009-01-15 22:34:14 +000090 qemu_log("Write SPR %d %03x <= " ADDRX "\n",
aurel3245d827d2008-12-07 13:40:29 +000091 sprn, sprn, env->spr[sprn]);
j_mayera4967752007-04-16 07:10:48 +000092}
93
aurel3245d827d2008-12-07 13:40:29 +000094target_ulong helper_load_tbl (void)
95{
96 return cpu_ppc_load_tbl(env);
97}
98
99target_ulong helper_load_tbu (void)
100{
101 return cpu_ppc_load_tbu(env);
102}
103
104target_ulong helper_load_atbl (void)
105{
106 return cpu_ppc_load_atbl(env);
107}
108
109target_ulong helper_load_atbu (void)
110{
111 return cpu_ppc_load_atbu(env);
112}
113
114target_ulong helper_load_601_rtcl (void)
115{
116 return cpu_ppc601_load_rtcl(env);
117}
118
119target_ulong helper_load_601_rtcu (void)
120{
121 return cpu_ppc601_load_rtcu(env);
122}
123
124#if !defined(CONFIG_USER_ONLY)
125#if defined (TARGET_PPC64)
126void helper_store_asr (target_ulong val)
127{
128 ppc_store_asr(env, val);
129}
130#endif
131
132void helper_store_sdr1 (target_ulong val)
133{
134 ppc_store_sdr1(env, val);
135}
136
137void helper_store_tbl (target_ulong val)
138{
139 cpu_ppc_store_tbl(env, val);
140}
141
142void helper_store_tbu (target_ulong val)
143{
144 cpu_ppc_store_tbu(env, val);
145}
146
147void helper_store_atbl (target_ulong val)
148{
149 cpu_ppc_store_atbl(env, val);
150}
151
152void helper_store_atbu (target_ulong val)
153{
154 cpu_ppc_store_atbu(env, val);
155}
156
157void helper_store_601_rtcl (target_ulong val)
158{
159 cpu_ppc601_store_rtcl(env, val);
160}
161
162void helper_store_601_rtcu (target_ulong val)
163{
164 cpu_ppc601_store_rtcu(env, val);
165}
166
167target_ulong helper_load_decr (void)
168{
169 return cpu_ppc_load_decr(env);
170}
171
172void helper_store_decr (target_ulong val)
173{
174 cpu_ppc_store_decr(env, val);
175}
176
177void helper_store_hid0_601 (target_ulong val)
178{
179 target_ulong hid0;
180
181 hid0 = env->spr[SPR_HID0];
182 if ((val ^ hid0) & 0x00000008) {
183 /* Change current endianness */
184 env->hflags &= ~(1 << MSR_LE);
185 env->hflags_nmsr &= ~(1 << MSR_LE);
186 env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
187 env->hflags |= env->hflags_nmsr;
aliguori93fcfe32009-01-15 22:34:14 +0000188 qemu_log("%s: set endianness to %c => " ADDRX "\n",
aurel3245d827d2008-12-07 13:40:29 +0000189 __func__, val & 0x8 ? 'l' : 'b', env->hflags);
aurel3245d827d2008-12-07 13:40:29 +0000190 }
191 env->spr[SPR_HID0] = (uint32_t)val;
192}
193
194void helper_store_403_pbr (uint32_t num, target_ulong value)
195{
196 if (likely(env->pb[num] != value)) {
197 env->pb[num] = value;
198 /* Should be optimized */
199 tlb_flush(env, 1);
200 }
201}
202
203target_ulong helper_load_40x_pit (void)
204{
205 return load_40x_pit(env);
206}
207
208void helper_store_40x_pit (target_ulong val)
209{
210 store_40x_pit(env, val);
211}
212
213void helper_store_40x_dbcr0 (target_ulong val)
214{
215 store_40x_dbcr0(env, val);
216}
217
218void helper_store_40x_sler (target_ulong val)
219{
220 store_40x_sler(env, val);
221}
222
223void helper_store_booke_tcr (target_ulong val)
224{
225 store_booke_tcr(env, val);
226}
227
228void helper_store_booke_tsr (target_ulong val)
229{
230 store_booke_tsr(env, val);
231}
232
233void helper_store_ibatu (uint32_t nr, target_ulong val)
234{
235 ppc_store_ibatu(env, nr, val);
236}
237
238void helper_store_ibatl (uint32_t nr, target_ulong val)
239{
240 ppc_store_ibatl(env, nr, val);
241}
242
243void helper_store_dbatu (uint32_t nr, target_ulong val)
244{
245 ppc_store_dbatu(env, nr, val);
246}
247
248void helper_store_dbatl (uint32_t nr, target_ulong val)
249{
250 ppc_store_dbatl(env, nr, val);
251}
252
253void helper_store_601_batl (uint32_t nr, target_ulong val)
254{
255 ppc_store_ibatl_601(env, nr, val);
256}
257
258void helper_store_601_batu (uint32_t nr, target_ulong val)
259{
260 ppc_store_ibatu_601(env, nr, val);
261}
262#endif
263
j_mayer76a66252007-03-07 08:32:30 +0000264/*****************************************************************************/
aurel32ff4a62c2008-11-30 16:23:56 +0000265/* Memory load and stores */
266
aurel3276db3ba2008-12-08 18:11:21 +0000267static always_inline target_ulong addr_add(target_ulong addr, target_long arg)
aurel32ff4a62c2008-11-30 16:23:56 +0000268{
269#if defined(TARGET_PPC64)
aurel3276db3ba2008-12-08 18:11:21 +0000270 if (!msr_sf)
271 return (uint32_t)(addr + arg);
aurel32ff4a62c2008-11-30 16:23:56 +0000272 else
273#endif
aurel3276db3ba2008-12-08 18:11:21 +0000274 return addr + arg;
aurel32ff4a62c2008-11-30 16:23:56 +0000275}
276
277void helper_lmw (target_ulong addr, uint32_t reg)
278{
aurel3276db3ba2008-12-08 18:11:21 +0000279 for (; reg < 32; reg++) {
aurel32ff4a62c2008-11-30 16:23:56 +0000280 if (msr_le)
aurel3276db3ba2008-12-08 18:11:21 +0000281 env->gpr[reg] = bswap32(ldl(addr));
aurel32ff4a62c2008-11-30 16:23:56 +0000282 else
aurel3276db3ba2008-12-08 18:11:21 +0000283 env->gpr[reg] = ldl(addr);
284 addr = addr_add(addr, 4);
aurel32ff4a62c2008-11-30 16:23:56 +0000285 }
286}
287
288void helper_stmw (target_ulong addr, uint32_t reg)
289{
aurel3276db3ba2008-12-08 18:11:21 +0000290 for (; reg < 32; reg++) {
aurel32ff4a62c2008-11-30 16:23:56 +0000291 if (msr_le)
aurel3276db3ba2008-12-08 18:11:21 +0000292 stl(addr, bswap32((uint32_t)env->gpr[reg]));
aurel32ff4a62c2008-11-30 16:23:56 +0000293 else
aurel3276db3ba2008-12-08 18:11:21 +0000294 stl(addr, (uint32_t)env->gpr[reg]);
295 addr = addr_add(addr, 4);
aurel32ff4a62c2008-11-30 16:23:56 +0000296 }
297}
298
aurel32dfbc7992008-11-30 16:24:21 +0000299void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg)
300{
301 int sh;
aurel3276db3ba2008-12-08 18:11:21 +0000302 for (; nb > 3; nb -= 4) {
303 env->gpr[reg] = ldl(addr);
aurel32dfbc7992008-11-30 16:24:21 +0000304 reg = (reg + 1) % 32;
aurel3276db3ba2008-12-08 18:11:21 +0000305 addr = addr_add(addr, 4);
aurel32dfbc7992008-11-30 16:24:21 +0000306 }
307 if (unlikely(nb > 0)) {
308 env->gpr[reg] = 0;
aurel3276db3ba2008-12-08 18:11:21 +0000309 for (sh = 24; nb > 0; nb--, sh -= 8) {
310 env->gpr[reg] |= ldub(addr) << sh;
311 addr = addr_add(addr, 1);
aurel32dfbc7992008-11-30 16:24:21 +0000312 }
313 }
314}
315/* PPC32 specification says we must generate an exception if
316 * rA is in the range of registers to be loaded.
317 * In an other hand, IBM says this is valid, but rA won't be loaded.
318 * For now, I'll follow the spec...
319 */
320void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
321{
322 if (likely(xer_bc != 0)) {
323 if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
324 (reg < rb && (reg + xer_bc) > rb))) {
aurel32e06fcd72008-12-11 22:42:14 +0000325 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
326 POWERPC_EXCP_INVAL |
327 POWERPC_EXCP_INVAL_LSWX);
aurel32dfbc7992008-11-30 16:24:21 +0000328 } else {
329 helper_lsw(addr, xer_bc, reg);
330 }
331 }
332}
333
334void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
335{
336 int sh;
aurel3276db3ba2008-12-08 18:11:21 +0000337 for (; nb > 3; nb -= 4) {
338 stl(addr, env->gpr[reg]);
aurel32dfbc7992008-11-30 16:24:21 +0000339 reg = (reg + 1) % 32;
aurel3276db3ba2008-12-08 18:11:21 +0000340 addr = addr_add(addr, 4);
aurel32dfbc7992008-11-30 16:24:21 +0000341 }
342 if (unlikely(nb > 0)) {
aurel32a16b45e2008-12-29 09:46:58 +0000343 for (sh = 24; nb > 0; nb--, sh -= 8) {
aurel3276db3ba2008-12-08 18:11:21 +0000344 stb(addr, (env->gpr[reg] >> sh) & 0xFF);
aurel32a16b45e2008-12-29 09:46:58 +0000345 addr = addr_add(addr, 1);
346 }
aurel32dfbc7992008-11-30 16:24:21 +0000347 }
348}
349
aurel32799a8c82008-11-30 16:24:05 +0000350static void do_dcbz(target_ulong addr, int dcache_line_size)
351{
aurel3276db3ba2008-12-08 18:11:21 +0000352 addr &= ~(dcache_line_size - 1);
aurel32799a8c82008-11-30 16:24:05 +0000353 int i;
aurel32799a8c82008-11-30 16:24:05 +0000354 for (i = 0 ; i < dcache_line_size ; i += 4) {
aurel32dcc532c2008-11-30 17:54:21 +0000355 stl(addr + i , 0);
aurel32799a8c82008-11-30 16:24:05 +0000356 }
aurel3276db3ba2008-12-08 18:11:21 +0000357 if (env->reserve == addr)
aurel32799a8c82008-11-30 16:24:05 +0000358 env->reserve = (target_ulong)-1ULL;
359}
360
361void helper_dcbz(target_ulong addr)
362{
363 do_dcbz(addr, env->dcache_line_size);
364}
365
366void helper_dcbz_970(target_ulong addr)
367{
368 if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1)
369 do_dcbz(addr, 32);
370 else
371 do_dcbz(addr, env->dcache_line_size);
372}
373
aurel3237d269d2008-11-30 16:24:13 +0000374void helper_icbi(target_ulong addr)
375{
376 uint32_t tmp;
377
aurel3276db3ba2008-12-08 18:11:21 +0000378 addr &= ~(env->dcache_line_size - 1);
aurel3237d269d2008-11-30 16:24:13 +0000379 /* Invalidate one cache line :
380 * PowerPC specification says this is to be treated like a load
381 * (not a fetch) by the MMU. To be sure it will be so,
382 * do the load "by hand".
383 */
aurel32dcc532c2008-11-30 17:54:21 +0000384 tmp = ldl(addr);
aurel3237d269d2008-11-30 16:24:13 +0000385 tb_invalidate_page_range(addr, addr + env->icache_line_size);
386}
387
aurel32bdb4b682008-11-30 16:24:30 +0000388// XXX: to be tested
389target_ulong helper_lscbx (target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
390{
391 int i, c, d;
aurel32bdb4b682008-11-30 16:24:30 +0000392 d = 24;
393 for (i = 0; i < xer_bc; i++) {
aurel3276db3ba2008-12-08 18:11:21 +0000394 c = ldub(addr);
395 addr = addr_add(addr, 1);
aurel32bdb4b682008-11-30 16:24:30 +0000396 /* ra (if not 0) and rb are never modified */
397 if (likely(reg != rb && (ra == 0 || reg != ra))) {
398 env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
399 }
400 if (unlikely(c == xer_cmp))
401 break;
402 if (likely(d != 0)) {
403 d -= 8;
404 } else {
405 d = 24;
406 reg++;
407 reg = reg & 0x1F;
408 }
409 }
410 return i;
411}
412
aurel32ff4a62c2008-11-30 16:23:56 +0000413/*****************************************************************************/
bellardfdabc362005-07-04 22:17:05 +0000414/* Fixed point operations helpers */
j_mayerd9bce9d2007-03-17 14:02:15 +0000415#if defined(TARGET_PPC64)
bellardfdabc362005-07-04 22:17:05 +0000416
aurel3274637402008-11-01 00:54:12 +0000417/* multiply high word */
418uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2)
bellardfdabc362005-07-04 22:17:05 +0000419{
aurel3274637402008-11-01 00:54:12 +0000420 uint64_t tl, th;
421
422 muls64(&tl, &th, arg1, arg2);
423 return th;
bellardfdabc362005-07-04 22:17:05 +0000424}
425
aurel3274637402008-11-01 00:54:12 +0000426/* multiply high word unsigned */
427uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2)
bellardfdabc362005-07-04 22:17:05 +0000428{
aurel3274637402008-11-01 00:54:12 +0000429 uint64_t tl, th;
bellardfdabc362005-07-04 22:17:05 +0000430
aurel3274637402008-11-01 00:54:12 +0000431 mulu64(&tl, &th, arg1, arg2);
432 return th;
bellardfdabc362005-07-04 22:17:05 +0000433}
434
aurel3274637402008-11-01 00:54:12 +0000435uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
j_mayerd9bce9d2007-03-17 14:02:15 +0000436{
437 int64_t th;
438 uint64_t tl;
439
aurel3274637402008-11-01 00:54:12 +0000440 muls64(&tl, (uint64_t *)&th, arg1, arg2);
j_mayer88ad9202007-10-25 23:36:08 +0000441 /* If th != 0 && th != -1, then we had an overflow */
j_mayer6f2d8972007-11-12 00:04:48 +0000442 if (likely((uint64_t)(th + 1) <= 1)) {
aurel323d7b4172008-10-21 11:28:46 +0000443 env->xer &= ~(1 << XER_OV);
j_mayerd9bce9d2007-03-17 14:02:15 +0000444 } else {
aurel323d7b4172008-10-21 11:28:46 +0000445 env->xer |= (1 << XER_OV) | (1 << XER_SO);
j_mayerd9bce9d2007-03-17 14:02:15 +0000446 }
aurel3274637402008-11-01 00:54:12 +0000447 return (int64_t)tl;
j_mayerd9bce9d2007-03-17 14:02:15 +0000448}
449#endif
450
aurel3226d67362008-10-21 11:31:27 +0000451target_ulong helper_cntlzw (target_ulong t)
j_mayer603fccc2007-10-28 12:54:53 +0000452{
aurel3226d67362008-10-21 11:31:27 +0000453 return clz32(t);
j_mayer603fccc2007-10-28 12:54:53 +0000454}
455
456#if defined(TARGET_PPC64)
aurel3226d67362008-10-21 11:31:27 +0000457target_ulong helper_cntlzd (target_ulong t)
j_mayer603fccc2007-10-28 12:54:53 +0000458{
aurel3226d67362008-10-21 11:31:27 +0000459 return clz64(t);
j_mayer603fccc2007-10-28 12:54:53 +0000460}
461#endif
462
bellard9a64fbe2004-01-04 22:58:38 +0000463/* shift right arithmetic helper */
aurel3226d67362008-10-21 11:31:27 +0000464target_ulong helper_sraw (target_ulong value, target_ulong shift)
bellard9a64fbe2004-01-04 22:58:38 +0000465{
466 int32_t ret;
467
aurel3226d67362008-10-21 11:31:27 +0000468 if (likely(!(shift & 0x20))) {
469 if (likely((uint32_t)shift != 0)) {
470 shift &= 0x1f;
471 ret = (int32_t)value >> shift;
472 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
aurel323d7b4172008-10-21 11:28:46 +0000473 env->xer &= ~(1 << XER_CA);
bellardfdabc362005-07-04 22:17:05 +0000474 } else {
aurel323d7b4172008-10-21 11:28:46 +0000475 env->xer |= (1 << XER_CA);
bellardfdabc362005-07-04 22:17:05 +0000476 }
477 } else {
aurel3226d67362008-10-21 11:31:27 +0000478 ret = (int32_t)value;
aurel323d7b4172008-10-21 11:28:46 +0000479 env->xer &= ~(1 << XER_CA);
bellardfdabc362005-07-04 22:17:05 +0000480 }
bellard9a64fbe2004-01-04 22:58:38 +0000481 } else {
aurel3226d67362008-10-21 11:31:27 +0000482 ret = (int32_t)value >> 31;
483 if (ret) {
aurel323d7b4172008-10-21 11:28:46 +0000484 env->xer |= (1 << XER_CA);
aurel3226d67362008-10-21 11:31:27 +0000485 } else {
486 env->xer &= ~(1 << XER_CA);
j_mayer76a66252007-03-07 08:32:30 +0000487 }
bellardfdabc362005-07-04 22:17:05 +0000488 }
aurel3226d67362008-10-21 11:31:27 +0000489 return (target_long)ret;
bellard9a64fbe2004-01-04 22:58:38 +0000490}
491
j_mayerd9bce9d2007-03-17 14:02:15 +0000492#if defined(TARGET_PPC64)
aurel3226d67362008-10-21 11:31:27 +0000493target_ulong helper_srad (target_ulong value, target_ulong shift)
j_mayerd9bce9d2007-03-17 14:02:15 +0000494{
495 int64_t ret;
496
aurel3226d67362008-10-21 11:31:27 +0000497 if (likely(!(shift & 0x40))) {
498 if (likely((uint64_t)shift != 0)) {
499 shift &= 0x3f;
500 ret = (int64_t)value >> shift;
501 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
aurel323d7b4172008-10-21 11:28:46 +0000502 env->xer &= ~(1 << XER_CA);
j_mayerd9bce9d2007-03-17 14:02:15 +0000503 } else {
aurel323d7b4172008-10-21 11:28:46 +0000504 env->xer |= (1 << XER_CA);
j_mayerd9bce9d2007-03-17 14:02:15 +0000505 }
506 } else {
aurel3226d67362008-10-21 11:31:27 +0000507 ret = (int64_t)value;
aurel323d7b4172008-10-21 11:28:46 +0000508 env->xer &= ~(1 << XER_CA);
j_mayerd9bce9d2007-03-17 14:02:15 +0000509 }
510 } else {
aurel3226d67362008-10-21 11:31:27 +0000511 ret = (int64_t)value >> 63;
512 if (ret) {
aurel323d7b4172008-10-21 11:28:46 +0000513 env->xer |= (1 << XER_CA);
aurel3226d67362008-10-21 11:31:27 +0000514 } else {
515 env->xer &= ~(1 << XER_CA);
j_mayerd9bce9d2007-03-17 14:02:15 +0000516 }
517 }
aurel3226d67362008-10-21 11:31:27 +0000518 return ret;
j_mayerd9bce9d2007-03-17 14:02:15 +0000519}
520#endif
521
aurel3226d67362008-10-21 11:31:27 +0000522target_ulong helper_popcntb (target_ulong val)
j_mayerd9bce9d2007-03-17 14:02:15 +0000523{
aurel326176a262008-11-01 00:54:33 +0000524 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
525 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
526 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
527 return val;
j_mayerd9bce9d2007-03-17 14:02:15 +0000528}
529
530#if defined(TARGET_PPC64)
aurel3226d67362008-10-21 11:31:27 +0000531target_ulong helper_popcntb_64 (target_ulong val)
j_mayerd9bce9d2007-03-17 14:02:15 +0000532{
aurel326176a262008-11-01 00:54:33 +0000533 val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL);
534 val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL);
535 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & 0x0f0f0f0f0f0f0f0fULL);
536 return val;
j_mayerd9bce9d2007-03-17 14:02:15 +0000537}
538#endif
539
bellardfdabc362005-07-04 22:17:05 +0000540/*****************************************************************************/
bellard9a64fbe2004-01-04 22:58:38 +0000541/* Floating point operations helpers */
aurel32a0d7d5a2008-11-23 16:30:50 +0000542uint64_t helper_float32_to_float64(uint32_t arg)
543{
544 CPU_FloatU f;
545 CPU_DoubleU d;
546 f.l = arg;
547 d.d = float32_to_float64(f.f, &env->fp_status);
548 return d.ll;
549}
550
551uint32_t helper_float64_to_float32(uint64_t arg)
552{
553 CPU_FloatU f;
554 CPU_DoubleU d;
555 d.ll = arg;
556 f.f = float64_to_float32(d.d, &env->fp_status);
557 return f.l;
558}
559
aurel320ca9d382008-03-13 19:19:16 +0000560static always_inline int isden (float64 d)
j_mayer7c580442007-10-27 17:54:30 +0000561{
aurel320ca9d382008-03-13 19:19:16 +0000562 CPU_DoubleU u;
j_mayer7c580442007-10-27 17:54:30 +0000563
aurel320ca9d382008-03-13 19:19:16 +0000564 u.d = d;
j_mayer7c580442007-10-27 17:54:30 +0000565
aurel320ca9d382008-03-13 19:19:16 +0000566 return ((u.ll >> 52) & 0x7FF) == 0;
j_mayer7c580442007-10-27 17:54:30 +0000567}
568
aurel32af129062008-11-19 16:10:23 +0000569uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
j_mayer7c580442007-10-27 17:54:30 +0000570{
aurel32af129062008-11-19 16:10:23 +0000571 CPU_DoubleU farg;
j_mayer7c580442007-10-27 17:54:30 +0000572 int isneg;
aurel32af129062008-11-19 16:10:23 +0000573 int ret;
574 farg.ll = arg;
aurel32f23c3462008-12-15 17:14:27 +0000575 isneg = float64_is_neg(farg.d);
aurel32af129062008-11-19 16:10:23 +0000576 if (unlikely(float64_is_nan(farg.d))) {
577 if (float64_is_signaling_nan(farg.d)) {
j_mayer7c580442007-10-27 17:54:30 +0000578 /* Signaling NaN: flags are undefined */
aurel32af129062008-11-19 16:10:23 +0000579 ret = 0x00;
j_mayer7c580442007-10-27 17:54:30 +0000580 } else {
581 /* Quiet NaN */
aurel32af129062008-11-19 16:10:23 +0000582 ret = 0x11;
j_mayer7c580442007-10-27 17:54:30 +0000583 }
aurel32f23c3462008-12-15 17:14:27 +0000584 } else if (unlikely(float64_is_infinity(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +0000585 /* +/- infinity */
586 if (isneg)
aurel32af129062008-11-19 16:10:23 +0000587 ret = 0x09;
j_mayer7c580442007-10-27 17:54:30 +0000588 else
aurel32af129062008-11-19 16:10:23 +0000589 ret = 0x05;
j_mayer7c580442007-10-27 17:54:30 +0000590 } else {
aurel32f23c3462008-12-15 17:14:27 +0000591 if (float64_is_zero(farg.d)) {
j_mayer7c580442007-10-27 17:54:30 +0000592 /* +/- zero */
593 if (isneg)
aurel32af129062008-11-19 16:10:23 +0000594 ret = 0x12;
j_mayer7c580442007-10-27 17:54:30 +0000595 else
aurel32af129062008-11-19 16:10:23 +0000596 ret = 0x02;
j_mayer7c580442007-10-27 17:54:30 +0000597 } else {
aurel32af129062008-11-19 16:10:23 +0000598 if (isden(farg.d)) {
j_mayer7c580442007-10-27 17:54:30 +0000599 /* Denormalized numbers */
aurel32af129062008-11-19 16:10:23 +0000600 ret = 0x10;
j_mayer7c580442007-10-27 17:54:30 +0000601 } else {
602 /* Normalized numbers */
aurel32af129062008-11-19 16:10:23 +0000603 ret = 0x00;
j_mayer7c580442007-10-27 17:54:30 +0000604 }
605 if (isneg) {
aurel32af129062008-11-19 16:10:23 +0000606 ret |= 0x08;
j_mayer7c580442007-10-27 17:54:30 +0000607 } else {
aurel32af129062008-11-19 16:10:23 +0000608 ret |= 0x04;
j_mayer7c580442007-10-27 17:54:30 +0000609 }
610 }
611 }
612 if (set_fprf) {
613 /* We update FPSCR_FPRF */
614 env->fpscr &= ~(0x1F << FPSCR_FPRF);
aurel32af129062008-11-19 16:10:23 +0000615 env->fpscr |= ret << FPSCR_FPRF;
j_mayer7c580442007-10-27 17:54:30 +0000616 }
617 /* We just need fpcc to update Rc1 */
aurel32af129062008-11-19 16:10:23 +0000618 return ret & 0xF;
j_mayer7c580442007-10-27 17:54:30 +0000619}
620
621/* Floating-point invalid operations exception */
aurel32af129062008-11-19 16:10:23 +0000622static always_inline uint64_t fload_invalid_op_excp (int op)
j_mayer7c580442007-10-27 17:54:30 +0000623{
aurel32af129062008-11-19 16:10:23 +0000624 uint64_t ret = 0;
j_mayer7c580442007-10-27 17:54:30 +0000625 int ve;
626
627 ve = fpscr_ve;
aurel32e0147e42008-12-15 17:13:55 +0000628 switch (op) {
629 case POWERPC_EXCP_FP_VXSNAN:
j_mayer7c580442007-10-27 17:54:30 +0000630 env->fpscr |= 1 << FPSCR_VXSNAN;
aurel32e0147e42008-12-15 17:13:55 +0000631 break;
632 case POWERPC_EXCP_FP_VXSOFT:
j_mayer7c580442007-10-27 17:54:30 +0000633 env->fpscr |= 1 << FPSCR_VXSOFT;
aurel32e0147e42008-12-15 17:13:55 +0000634 break;
j_mayer7c580442007-10-27 17:54:30 +0000635 case POWERPC_EXCP_FP_VXISI:
636 /* Magnitude subtraction of infinities */
637 env->fpscr |= 1 << FPSCR_VXISI;
638 goto update_arith;
639 case POWERPC_EXCP_FP_VXIDI:
640 /* Division of infinity by infinity */
641 env->fpscr |= 1 << FPSCR_VXIDI;
642 goto update_arith;
643 case POWERPC_EXCP_FP_VXZDZ:
644 /* Division of zero by zero */
645 env->fpscr |= 1 << FPSCR_VXZDZ;
646 goto update_arith;
647 case POWERPC_EXCP_FP_VXIMZ:
648 /* Multiplication of zero by infinity */
649 env->fpscr |= 1 << FPSCR_VXIMZ;
650 goto update_arith;
651 case POWERPC_EXCP_FP_VXVC:
652 /* Ordered comparison of NaN */
653 env->fpscr |= 1 << FPSCR_VXVC;
654 env->fpscr &= ~(0xF << FPSCR_FPCC);
655 env->fpscr |= 0x11 << FPSCR_FPCC;
656 /* We must update the target FPR before raising the exception */
657 if (ve != 0) {
658 env->exception_index = POWERPC_EXCP_PROGRAM;
659 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
660 /* Update the floating-point enabled exception summary */
661 env->fpscr |= 1 << FPSCR_FEX;
662 /* Exception is differed */
663 ve = 0;
664 }
665 break;
666 case POWERPC_EXCP_FP_VXSQRT:
667 /* Square root of a negative number */
668 env->fpscr |= 1 << FPSCR_VXSQRT;
669 update_arith:
670 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
671 if (ve == 0) {
672 /* Set the result to quiet NaN */
aurel32e0147e42008-12-15 17:13:55 +0000673 ret = 0xFFF8000000000000ULL;
j_mayer7c580442007-10-27 17:54:30 +0000674 env->fpscr &= ~(0xF << FPSCR_FPCC);
675 env->fpscr |= 0x11 << FPSCR_FPCC;
676 }
677 break;
678 case POWERPC_EXCP_FP_VXCVI:
679 /* Invalid conversion */
680 env->fpscr |= 1 << FPSCR_VXCVI;
681 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
682 if (ve == 0) {
683 /* Set the result to quiet NaN */
aurel32e0147e42008-12-15 17:13:55 +0000684 ret = 0xFFF8000000000000ULL;
j_mayer7c580442007-10-27 17:54:30 +0000685 env->fpscr &= ~(0xF << FPSCR_FPCC);
686 env->fpscr |= 0x11 << FPSCR_FPCC;
687 }
688 break;
689 }
690 /* Update the floating-point invalid operation summary */
691 env->fpscr |= 1 << FPSCR_VX;
692 /* Update the floating-point exception summary */
693 env->fpscr |= 1 << FPSCR_FX;
694 if (ve != 0) {
695 /* Update the floating-point enabled exception summary */
696 env->fpscr |= 1 << FPSCR_FEX;
697 if (msr_fe0 != 0 || msr_fe1 != 0)
aurel32e06fcd72008-12-11 22:42:14 +0000698 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
j_mayer7c580442007-10-27 17:54:30 +0000699 }
aurel32af129062008-11-19 16:10:23 +0000700 return ret;
j_mayer7c580442007-10-27 17:54:30 +0000701}
702
aurel32e33e94f2008-12-18 22:44:21 +0000703static always_inline void float_zero_divide_excp (void)
j_mayer7c580442007-10-27 17:54:30 +0000704{
j_mayer7c580442007-10-27 17:54:30 +0000705 env->fpscr |= 1 << FPSCR_ZX;
706 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
707 /* Update the floating-point exception summary */
708 env->fpscr |= 1 << FPSCR_FX;
709 if (fpscr_ze != 0) {
710 /* Update the floating-point enabled exception summary */
711 env->fpscr |= 1 << FPSCR_FEX;
712 if (msr_fe0 != 0 || msr_fe1 != 0) {
aurel32e06fcd72008-12-11 22:42:14 +0000713 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
714 POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
j_mayer7c580442007-10-27 17:54:30 +0000715 }
j_mayer7c580442007-10-27 17:54:30 +0000716 }
717}
718
719static always_inline void float_overflow_excp (void)
720{
721 env->fpscr |= 1 << FPSCR_OX;
722 /* Update the floating-point exception summary */
723 env->fpscr |= 1 << FPSCR_FX;
724 if (fpscr_oe != 0) {
725 /* XXX: should adjust the result */
726 /* Update the floating-point enabled exception summary */
727 env->fpscr |= 1 << FPSCR_FEX;
728 /* We must update the target FPR before raising the exception */
729 env->exception_index = POWERPC_EXCP_PROGRAM;
730 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
731 } else {
732 env->fpscr |= 1 << FPSCR_XX;
733 env->fpscr |= 1 << FPSCR_FI;
734 }
735}
736
737static always_inline void float_underflow_excp (void)
738{
739 env->fpscr |= 1 << FPSCR_UX;
740 /* Update the floating-point exception summary */
741 env->fpscr |= 1 << FPSCR_FX;
742 if (fpscr_ue != 0) {
743 /* XXX: should adjust the result */
744 /* Update the floating-point enabled exception summary */
745 env->fpscr |= 1 << FPSCR_FEX;
746 /* We must update the target FPR before raising the exception */
747 env->exception_index = POWERPC_EXCP_PROGRAM;
748 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
749 }
750}
751
752static always_inline void float_inexact_excp (void)
753{
754 env->fpscr |= 1 << FPSCR_XX;
755 /* Update the floating-point exception summary */
756 env->fpscr |= 1 << FPSCR_FX;
757 if (fpscr_xe != 0) {
758 /* Update the floating-point enabled exception summary */
759 env->fpscr |= 1 << FPSCR_FEX;
760 /* We must update the target FPR before raising the exception */
761 env->exception_index = POWERPC_EXCP_PROGRAM;
762 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
763 }
764}
765
766static always_inline void fpscr_set_rounding_mode (void)
767{
768 int rnd_type;
769
770 /* Set rounding mode */
771 switch (fpscr_rn) {
772 case 0:
773 /* Best approximation (round to nearest) */
774 rnd_type = float_round_nearest_even;
775 break;
776 case 1:
777 /* Smaller magnitude (round toward zero) */
778 rnd_type = float_round_to_zero;
779 break;
780 case 2:
781 /* Round toward +infinite */
782 rnd_type = float_round_up;
783 break;
784 default:
785 case 3:
786 /* Round toward -infinite */
787 rnd_type = float_round_down;
788 break;
789 }
790 set_float_rounding_mode(rnd_type, &env->fp_status);
791}
792
aurel326e35d522008-12-14 18:40:58 +0000793void helper_fpscr_clrbit (uint32_t bit)
794{
795 int prev;
796
797 prev = (env->fpscr >> bit) & 1;
798 env->fpscr &= ~(1 << bit);
799 if (prev == 1) {
800 switch (bit) {
801 case FPSCR_RN1:
802 case FPSCR_RN:
803 fpscr_set_rounding_mode();
804 break;
805 default:
806 break;
807 }
808 }
809}
810
aurel32af129062008-11-19 16:10:23 +0000811void helper_fpscr_setbit (uint32_t bit)
j_mayer7c580442007-10-27 17:54:30 +0000812{
813 int prev;
814
815 prev = (env->fpscr >> bit) & 1;
816 env->fpscr |= 1 << bit;
817 if (prev == 0) {
818 switch (bit) {
819 case FPSCR_VX:
820 env->fpscr |= 1 << FPSCR_FX;
821 if (fpscr_ve)
822 goto raise_ve;
823 case FPSCR_OX:
824 env->fpscr |= 1 << FPSCR_FX;
825 if (fpscr_oe)
826 goto raise_oe;
827 break;
828 case FPSCR_UX:
829 env->fpscr |= 1 << FPSCR_FX;
830 if (fpscr_ue)
831 goto raise_ue;
832 break;
833 case FPSCR_ZX:
834 env->fpscr |= 1 << FPSCR_FX;
835 if (fpscr_ze)
836 goto raise_ze;
837 break;
838 case FPSCR_XX:
839 env->fpscr |= 1 << FPSCR_FX;
840 if (fpscr_xe)
841 goto raise_xe;
842 break;
843 case FPSCR_VXSNAN:
844 case FPSCR_VXISI:
845 case FPSCR_VXIDI:
846 case FPSCR_VXZDZ:
847 case FPSCR_VXIMZ:
848 case FPSCR_VXVC:
849 case FPSCR_VXSOFT:
850 case FPSCR_VXSQRT:
851 case FPSCR_VXCVI:
852 env->fpscr |= 1 << FPSCR_VX;
853 env->fpscr |= 1 << FPSCR_FX;
854 if (fpscr_ve != 0)
855 goto raise_ve;
856 break;
857 case FPSCR_VE:
858 if (fpscr_vx != 0) {
859 raise_ve:
860 env->error_code = POWERPC_EXCP_FP;
861 if (fpscr_vxsnan)
862 env->error_code |= POWERPC_EXCP_FP_VXSNAN;
863 if (fpscr_vxisi)
864 env->error_code |= POWERPC_EXCP_FP_VXISI;
865 if (fpscr_vxidi)
866 env->error_code |= POWERPC_EXCP_FP_VXIDI;
867 if (fpscr_vxzdz)
868 env->error_code |= POWERPC_EXCP_FP_VXZDZ;
869 if (fpscr_vximz)
870 env->error_code |= POWERPC_EXCP_FP_VXIMZ;
871 if (fpscr_vxvc)
872 env->error_code |= POWERPC_EXCP_FP_VXVC;
873 if (fpscr_vxsoft)
874 env->error_code |= POWERPC_EXCP_FP_VXSOFT;
875 if (fpscr_vxsqrt)
876 env->error_code |= POWERPC_EXCP_FP_VXSQRT;
877 if (fpscr_vxcvi)
878 env->error_code |= POWERPC_EXCP_FP_VXCVI;
879 goto raise_excp;
880 }
881 break;
882 case FPSCR_OE:
883 if (fpscr_ox != 0) {
884 raise_oe:
885 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
886 goto raise_excp;
887 }
888 break;
889 case FPSCR_UE:
890 if (fpscr_ux != 0) {
891 raise_ue:
892 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
893 goto raise_excp;
894 }
895 break;
896 case FPSCR_ZE:
897 if (fpscr_zx != 0) {
898 raise_ze:
899 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
900 goto raise_excp;
901 }
902 break;
903 case FPSCR_XE:
904 if (fpscr_xx != 0) {
905 raise_xe:
906 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
907 goto raise_excp;
908 }
909 break;
910 case FPSCR_RN1:
911 case FPSCR_RN:
912 fpscr_set_rounding_mode();
913 break;
914 default:
915 break;
916 raise_excp:
917 /* Update the floating-point enabled exception summary */
918 env->fpscr |= 1 << FPSCR_FEX;
919 /* We have to update Rc1 before raising the exception */
920 env->exception_index = POWERPC_EXCP_PROGRAM;
921 break;
922 }
923 }
924}
925
aurel32af129062008-11-19 16:10:23 +0000926void helper_store_fpscr (uint64_t arg, uint32_t mask)
j_mayer7c580442007-10-27 17:54:30 +0000927{
928 /*
929 * We use only the 32 LSB of the incoming fpr
930 */
j_mayer7c580442007-10-27 17:54:30 +0000931 uint32_t prev, new;
932 int i;
933
j_mayer7c580442007-10-27 17:54:30 +0000934 prev = env->fpscr;
aurel32af129062008-11-19 16:10:23 +0000935 new = (uint32_t)arg;
aurel3227ee5df2008-12-15 00:30:28 +0000936 new &= ~0x60000000;
937 new |= prev & 0x60000000;
938 for (i = 0; i < 8; i++) {
j_mayer7c580442007-10-27 17:54:30 +0000939 if (mask & (1 << i)) {
940 env->fpscr &= ~(0xF << (4 * i));
941 env->fpscr |= new & (0xF << (4 * i));
942 }
943 }
944 /* Update VX and FEX */
945 if (fpscr_ix != 0)
946 env->fpscr |= 1 << FPSCR_VX;
aurel3255670252008-03-10 00:09:28 +0000947 else
948 env->fpscr &= ~(1 << FPSCR_VX);
j_mayer7c580442007-10-27 17:54:30 +0000949 if ((fpscr_ex & fpscr_eex) != 0) {
950 env->fpscr |= 1 << FPSCR_FEX;
951 env->exception_index = POWERPC_EXCP_PROGRAM;
952 /* XXX: we should compute it properly */
953 env->error_code = POWERPC_EXCP_FP;
954 }
aurel3255670252008-03-10 00:09:28 +0000955 else
956 env->fpscr &= ~(1 << FPSCR_FEX);
j_mayer7c580442007-10-27 17:54:30 +0000957 fpscr_set_rounding_mode();
958}
j_mayer7c580442007-10-27 17:54:30 +0000959
aurel32af129062008-11-19 16:10:23 +0000960void helper_float_check_status (void)
j_mayer7c580442007-10-27 17:54:30 +0000961{
aurel32af129062008-11-19 16:10:23 +0000962#ifdef CONFIG_SOFTFLOAT
j_mayer7c580442007-10-27 17:54:30 +0000963 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
964 (env->error_code & POWERPC_EXCP_FP)) {
965 /* Differred floating-point exception after target FPR update */
966 if (msr_fe0 != 0 || msr_fe1 != 0)
aurel32e06fcd72008-12-11 22:42:14 +0000967 helper_raise_exception_err(env->exception_index, env->error_code);
aurel32be94c952008-12-13 12:13:33 +0000968 } else {
969 int status = get_float_exception_flags(&env->fp_status);
aurel32e33e94f2008-12-18 22:44:21 +0000970 if (status & float_flag_divbyzero) {
971 float_zero_divide_excp();
972 } else if (status & float_flag_overflow) {
aurel32be94c952008-12-13 12:13:33 +0000973 float_overflow_excp();
974 } else if (status & float_flag_underflow) {
975 float_underflow_excp();
976 } else if (status & float_flag_inexact) {
977 float_inexact_excp();
978 }
j_mayer7c580442007-10-27 17:54:30 +0000979 }
aurel32af129062008-11-19 16:10:23 +0000980#else
981 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
982 (env->error_code & POWERPC_EXCP_FP)) {
983 /* Differred floating-point exception after target FPR update */
984 if (msr_fe0 != 0 || msr_fe1 != 0)
aurel32e06fcd72008-12-11 22:42:14 +0000985 helper_raise_exception_err(env->exception_index, env->error_code);
aurel32af129062008-11-19 16:10:23 +0000986 }
aurel32af129062008-11-19 16:10:23 +0000987#endif
988}
989
990#ifdef CONFIG_SOFTFLOAT
991void helper_reset_fpstatus (void)
992{
aurel32be94c952008-12-13 12:13:33 +0000993 set_float_exception_flags(0, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +0000994}
995#endif
996
aurel32af129062008-11-19 16:10:23 +0000997/* fadd - fadd. */
998uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
999{
1000 CPU_DoubleU farg1, farg2;
1001
1002 farg1.ll = arg1;
1003 farg2.ll = arg2;
aurel321cdb9c32008-04-07 21:24:25 +00001004#if USE_PRECISE_EMULATION
aurel32af129062008-11-19 16:10:23 +00001005 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1006 float64_is_signaling_nan(farg2.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001007 /* sNaN addition */
aurel32af129062008-11-19 16:10:23 +00001008 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel3217218d12008-12-15 17:14:35 +00001009 } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1010 float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001011 /* Magnitude subtraction of infinities */
aurel32cf1cf212008-12-13 11:46:36 +00001012 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
aurel3217218d12008-12-15 17:14:35 +00001013 } else {
1014 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001015 }
aurel32af129062008-11-19 16:10:23 +00001016#else
1017 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
1018#endif
1019 return farg1.ll;
j_mayer7c580442007-10-27 17:54:30 +00001020}
1021
aurel32af129062008-11-19 16:10:23 +00001022/* fsub - fsub. */
1023uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
j_mayer7c580442007-10-27 17:54:30 +00001024{
aurel32af129062008-11-19 16:10:23 +00001025 CPU_DoubleU farg1, farg2;
1026
1027 farg1.ll = arg1;
1028 farg2.ll = arg2;
1029#if USE_PRECISE_EMULATION
1030{
1031 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1032 float64_is_signaling_nan(farg2.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001033 /* sNaN subtraction */
aurel32af129062008-11-19 16:10:23 +00001034 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel3217218d12008-12-15 17:14:35 +00001035 } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1036 float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001037 /* Magnitude subtraction of infinities */
aurel32af129062008-11-19 16:10:23 +00001038 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
aurel3217218d12008-12-15 17:14:35 +00001039 } else {
1040 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001041 }
1042}
aurel32af129062008-11-19 16:10:23 +00001043#else
1044 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
1045#endif
1046 return farg1.ll;
1047}
j_mayer7c580442007-10-27 17:54:30 +00001048
aurel32af129062008-11-19 16:10:23 +00001049/* fmul - fmul. */
1050uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
j_mayer7c580442007-10-27 17:54:30 +00001051{
aurel32af129062008-11-19 16:10:23 +00001052 CPU_DoubleU farg1, farg2;
1053
1054 farg1.ll = arg1;
1055 farg2.ll = arg2;
1056#if USE_PRECISE_EMULATION
1057 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1058 float64_is_signaling_nan(farg2.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001059 /* sNaN multiplication */
aurel32af129062008-11-19 16:10:23 +00001060 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel32f23c3462008-12-15 17:14:27 +00001061 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1062 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
j_mayer7c580442007-10-27 17:54:30 +00001063 /* Multiplication of zero by infinity */
aurel32af129062008-11-19 16:10:23 +00001064 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
j_mayer7c580442007-10-27 17:54:30 +00001065 } else {
aurel32af129062008-11-19 16:10:23 +00001066 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001067 }
aurel32af129062008-11-19 16:10:23 +00001068#else
1069 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1070#endif
1071 return farg1.ll;
1072}
j_mayer7c580442007-10-27 17:54:30 +00001073
aurel32af129062008-11-19 16:10:23 +00001074/* fdiv - fdiv. */
1075uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
j_mayer7c580442007-10-27 17:54:30 +00001076{
aurel32af129062008-11-19 16:10:23 +00001077 CPU_DoubleU farg1, farg2;
1078
1079 farg1.ll = arg1;
1080 farg2.ll = arg2;
1081#if USE_PRECISE_EMULATION
1082 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1083 float64_is_signaling_nan(farg2.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001084 /* sNaN division */
aurel32af129062008-11-19 16:10:23 +00001085 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel32f23c3462008-12-15 17:14:27 +00001086 } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001087 /* Division of infinity by infinity */
aurel32af129062008-11-19 16:10:23 +00001088 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
aurel32e33e94f2008-12-18 22:44:21 +00001089 } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
1090 /* Division of zero by zero */
1091 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
j_mayer7c580442007-10-27 17:54:30 +00001092 } else {
aurel32af129062008-11-19 16:10:23 +00001093 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001094 }
aurel32af129062008-11-19 16:10:23 +00001095#else
1096 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
1097#endif
1098 return farg1.ll;
j_mayer7c580442007-10-27 17:54:30 +00001099}
j_mayer7c580442007-10-27 17:54:30 +00001100
aurel32af129062008-11-19 16:10:23 +00001101/* fabs */
1102uint64_t helper_fabs (uint64_t arg)
bellard9a64fbe2004-01-04 22:58:38 +00001103{
aurel32af129062008-11-19 16:10:23 +00001104 CPU_DoubleU farg;
bellard9a64fbe2004-01-04 22:58:38 +00001105
aurel32af129062008-11-19 16:10:23 +00001106 farg.ll = arg;
1107 farg.d = float64_abs(farg.d);
1108 return farg.ll;
1109}
1110
1111/* fnabs */
1112uint64_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;
1120}
1121
1122/* fneg */
1123uint64_t helper_fneg (uint64_t arg)
1124{
1125 CPU_DoubleU farg;
1126
1127 farg.ll = arg;
1128 farg.d = float64_chs(farg.d);
1129 return farg.ll;
1130}
1131
1132/* fctiw - fctiw. */
1133uint64_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))) {
j_mayer7c580442007-10-27 17:54:30 +00001139 /* sNaN conversion */
aurel32af129062008-11-19 16:10:23 +00001140 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
aurel32f23c3462008-12-15 17:14:27 +00001141 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001142 /* qNan / infinity conversion */
aurel32af129062008-11-19 16:10:23 +00001143 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
j_mayer7c580442007-10-27 17:54:30 +00001144 } else {
aurel32af129062008-11-19 16:10:23 +00001145 farg.ll = float64_to_int32(farg.d, &env->fp_status);
aurel321cdb9c32008-04-07 21:24:25 +00001146#if USE_PRECISE_EMULATION
j_mayer7c580442007-10-27 17:54:30 +00001147 /* XXX: higher bits are not supposed to be significant.
1148 * to make tests easier, return the same as a real PowerPC 750
1149 */
aurel32af129062008-11-19 16:10:23 +00001150 farg.ll |= 0xFFF80000ULL << 32;
j_mayere864cab2007-03-22 22:17:08 +00001151#endif
j_mayer7c580442007-10-27 17:54:30 +00001152 }
aurel32af129062008-11-19 16:10:23 +00001153 return farg.ll;
bellard9a64fbe2004-01-04 22:58:38 +00001154}
1155
aurel32af129062008-11-19 16:10:23 +00001156/* fctiwz - fctiwz. */
1157uint64_t helper_fctiwz (uint64_t arg)
bellard9a64fbe2004-01-04 22:58:38 +00001158{
aurel32af129062008-11-19 16:10:23 +00001159 CPU_DoubleU farg;
1160 farg.ll = arg;
bellard9a64fbe2004-01-04 22:58:38 +00001161
aurel32af129062008-11-19 16:10:23 +00001162 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001163 /* sNaN conversion */
aurel32af129062008-11-19 16:10:23 +00001164 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
aurel32f23c3462008-12-15 17:14:27 +00001165 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001166 /* qNan / infinity conversion */
aurel32af129062008-11-19 16:10:23 +00001167 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
j_mayer7c580442007-10-27 17:54:30 +00001168 } else {
aurel32af129062008-11-19 16:10:23 +00001169 farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
aurel321cdb9c32008-04-07 21:24:25 +00001170#if USE_PRECISE_EMULATION
j_mayer7c580442007-10-27 17:54:30 +00001171 /* XXX: higher bits are not supposed to be significant.
1172 * to make tests easier, return the same as a real PowerPC 750
1173 */
aurel32af129062008-11-19 16:10:23 +00001174 farg.ll |= 0xFFF80000ULL << 32;
j_mayere864cab2007-03-22 22:17:08 +00001175#endif
j_mayer7c580442007-10-27 17:54:30 +00001176 }
aurel32af129062008-11-19 16:10:23 +00001177 return farg.ll;
bellard9a64fbe2004-01-04 22:58:38 +00001178}
1179
j_mayer426613d2007-03-23 09:45:27 +00001180#if defined(TARGET_PPC64)
aurel32af129062008-11-19 16:10:23 +00001181/* fcfid - fcfid. */
1182uint64_t helper_fcfid (uint64_t arg)
j_mayer426613d2007-03-23 09:45:27 +00001183{
aurel32af129062008-11-19 16:10:23 +00001184 CPU_DoubleU farg;
1185 farg.d = int64_to_float64(arg, &env->fp_status);
1186 return farg.ll;
j_mayer426613d2007-03-23 09:45:27 +00001187}
1188
aurel32af129062008-11-19 16:10:23 +00001189/* fctid - fctid. */
1190uint64_t helper_fctid (uint64_t arg)
j_mayer426613d2007-03-23 09:45:27 +00001191{
aurel32af129062008-11-19 16:10:23 +00001192 CPU_DoubleU farg;
1193 farg.ll = arg;
j_mayer426613d2007-03-23 09:45:27 +00001194
aurel32af129062008-11-19 16:10:23 +00001195 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001196 /* sNaN conversion */
aurel32af129062008-11-19 16:10:23 +00001197 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
aurel32f23c3462008-12-15 17:14:27 +00001198 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001199 /* qNan / infinity conversion */
aurel32af129062008-11-19 16:10:23 +00001200 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
j_mayer7c580442007-10-27 17:54:30 +00001201 } else {
aurel32af129062008-11-19 16:10:23 +00001202 farg.ll = float64_to_int64(farg.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001203 }
aurel32af129062008-11-19 16:10:23 +00001204 return farg.ll;
j_mayer426613d2007-03-23 09:45:27 +00001205}
1206
aurel32af129062008-11-19 16:10:23 +00001207/* fctidz - fctidz. */
1208uint64_t helper_fctidz (uint64_t arg)
j_mayer426613d2007-03-23 09:45:27 +00001209{
aurel32af129062008-11-19 16:10:23 +00001210 CPU_DoubleU farg;
1211 farg.ll = arg;
j_mayer426613d2007-03-23 09:45:27 +00001212
aurel32af129062008-11-19 16:10:23 +00001213 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001214 /* sNaN conversion */
aurel32af129062008-11-19 16:10:23 +00001215 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
aurel32f23c3462008-12-15 17:14:27 +00001216 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001217 /* qNan / infinity conversion */
aurel32af129062008-11-19 16:10:23 +00001218 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
j_mayer7c580442007-10-27 17:54:30 +00001219 } else {
aurel32af129062008-11-19 16:10:23 +00001220 farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001221 }
aurel32af129062008-11-19 16:10:23 +00001222 return farg.ll;
j_mayer426613d2007-03-23 09:45:27 +00001223}
1224
1225#endif
1226
aurel32af129062008-11-19 16:10:23 +00001227static always_inline uint64_t do_fri (uint64_t arg, int rounding_mode)
j_mayerd7e4b872007-09-30 01:11:48 +00001228{
aurel32af129062008-11-19 16:10:23 +00001229 CPU_DoubleU farg;
1230 farg.ll = arg;
1231
1232 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001233 /* sNaN round */
aurel32af129062008-11-19 16:10:23 +00001234 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
aurel32f23c3462008-12-15 17:14:27 +00001235 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001236 /* qNan / infinity round */
aurel32af129062008-11-19 16:10:23 +00001237 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
j_mayer7c580442007-10-27 17:54:30 +00001238 } else {
1239 set_float_rounding_mode(rounding_mode, &env->fp_status);
aurel32af129062008-11-19 16:10:23 +00001240 farg.ll = float64_round_to_int(farg.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001241 /* Restore rounding mode from FPSCR */
1242 fpscr_set_rounding_mode();
1243 }
aurel32af129062008-11-19 16:10:23 +00001244 return farg.ll;
j_mayerd7e4b872007-09-30 01:11:48 +00001245}
1246
aurel32af129062008-11-19 16:10:23 +00001247uint64_t helper_frin (uint64_t arg)
j_mayerd7e4b872007-09-30 01:11:48 +00001248{
aurel32af129062008-11-19 16:10:23 +00001249 return do_fri(arg, float_round_nearest_even);
j_mayerd7e4b872007-09-30 01:11:48 +00001250}
1251
aurel32af129062008-11-19 16:10:23 +00001252uint64_t helper_friz (uint64_t arg)
j_mayerd7e4b872007-09-30 01:11:48 +00001253{
aurel32af129062008-11-19 16:10:23 +00001254 return do_fri(arg, float_round_to_zero);
j_mayerd7e4b872007-09-30 01:11:48 +00001255}
1256
aurel32af129062008-11-19 16:10:23 +00001257uint64_t helper_frip (uint64_t arg)
j_mayerd7e4b872007-09-30 01:11:48 +00001258{
aurel32af129062008-11-19 16:10:23 +00001259 return do_fri(arg, float_round_up);
j_mayerd7e4b872007-09-30 01:11:48 +00001260}
1261
aurel32af129062008-11-19 16:10:23 +00001262uint64_t helper_frim (uint64_t arg)
j_mayerd7e4b872007-09-30 01:11:48 +00001263{
aurel32af129062008-11-19 16:10:23 +00001264 return do_fri(arg, float_round_down);
j_mayerd7e4b872007-09-30 01:11:48 +00001265}
1266
aurel32af129062008-11-19 16:10:23 +00001267/* fmadd - fmadd. */
1268uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1269{
1270 CPU_DoubleU farg1, farg2, farg3;
1271
1272 farg1.ll = arg1;
1273 farg2.ll = arg2;
1274 farg3.ll = arg3;
aurel321cdb9c32008-04-07 21:24:25 +00001275#if USE_PRECISE_EMULATION
aurel32af129062008-11-19 16:10:23 +00001276 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1277 float64_is_signaling_nan(farg2.d) ||
1278 float64_is_signaling_nan(farg3.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001279 /* sNaN operation */
aurel32af129062008-11-19 16:10:23 +00001280 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel32da1e7ac2008-12-15 17:14:43 +00001281 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1282 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1283 /* Multiplication of zero by infinity */
1284 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
j_mayer7c580442007-10-27 17:54:30 +00001285 } else {
j_mayere864cab2007-03-22 22:17:08 +00001286#ifdef FLOAT128
j_mayer7c580442007-10-27 17:54:30 +00001287 /* This is the way the PowerPC specification defines it */
1288 float128 ft0_128, ft1_128;
j_mayere864cab2007-03-22 22:17:08 +00001289
aurel32af129062008-11-19 16:10:23 +00001290 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1291 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001292 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
aurel32da1e7ac2008-12-15 17:14:43 +00001293 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1294 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1295 /* Magnitude subtraction of infinities */
1296 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1297 } else {
1298 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1299 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1300 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1301 }
j_mayere864cab2007-03-22 22:17:08 +00001302#else
j_mayer7c580442007-10-27 17:54:30 +00001303 /* This is OK on x86 hosts */
aurel32af129062008-11-19 16:10:23 +00001304 farg1.d = (farg1.d * farg2.d) + farg3.d;
j_mayere864cab2007-03-22 22:17:08 +00001305#endif
j_mayer7c580442007-10-27 17:54:30 +00001306 }
aurel32af129062008-11-19 16:10:23 +00001307#else
1308 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1309 farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
1310#endif
1311 return farg1.ll;
j_mayere864cab2007-03-22 22:17:08 +00001312}
1313
aurel32af129062008-11-19 16:10:23 +00001314/* fmsub - fmsub. */
1315uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
j_mayere864cab2007-03-22 22:17:08 +00001316{
aurel32af129062008-11-19 16:10:23 +00001317 CPU_DoubleU farg1, farg2, farg3;
1318
1319 farg1.ll = arg1;
1320 farg2.ll = arg2;
1321 farg3.ll = arg3;
1322#if USE_PRECISE_EMULATION
1323 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1324 float64_is_signaling_nan(farg2.d) ||
1325 float64_is_signaling_nan(farg3.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001326 /* sNaN operation */
aurel32af129062008-11-19 16:10:23 +00001327 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel32da1e7ac2008-12-15 17:14:43 +00001328 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1329 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1330 /* Multiplication of zero by infinity */
1331 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
j_mayer7c580442007-10-27 17:54:30 +00001332 } else {
j_mayere864cab2007-03-22 22:17:08 +00001333#ifdef FLOAT128
j_mayer7c580442007-10-27 17:54:30 +00001334 /* This is the way the PowerPC specification defines it */
1335 float128 ft0_128, ft1_128;
j_mayere864cab2007-03-22 22:17:08 +00001336
aurel32af129062008-11-19 16:10:23 +00001337 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1338 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001339 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
aurel32da1e7ac2008-12-15 17:14:43 +00001340 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1341 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1342 /* Magnitude subtraction of infinities */
1343 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1344 } else {
1345 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1346 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1347 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1348 }
j_mayere864cab2007-03-22 22:17:08 +00001349#else
j_mayer7c580442007-10-27 17:54:30 +00001350 /* This is OK on x86 hosts */
aurel32af129062008-11-19 16:10:23 +00001351 farg1.d = (farg1.d * farg2.d) - farg3.d;
j_mayere864cab2007-03-22 22:17:08 +00001352#endif
j_mayer7c580442007-10-27 17:54:30 +00001353 }
aurel32af129062008-11-19 16:10:23 +00001354#else
1355 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1356 farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
1357#endif
1358 return farg1.ll;
j_mayere864cab2007-03-22 22:17:08 +00001359}
j_mayere864cab2007-03-22 22:17:08 +00001360
aurel32af129062008-11-19 16:10:23 +00001361/* fnmadd - fnmadd. */
1362uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
bellard4b3686f2004-05-23 22:18:12 +00001363{
aurel32af129062008-11-19 16:10:23 +00001364 CPU_DoubleU farg1, farg2, farg3;
1365
1366 farg1.ll = arg1;
1367 farg2.ll = arg2;
1368 farg3.ll = arg3;
1369
1370 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1371 float64_is_signaling_nan(farg2.d) ||
1372 float64_is_signaling_nan(farg3.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001373 /* sNaN operation */
aurel32af129062008-11-19 16:10:23 +00001374 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel32da1e7ac2008-12-15 17:14:43 +00001375 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1376 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1377 /* Multiplication of zero by infinity */
1378 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
j_mayer7c580442007-10-27 17:54:30 +00001379 } else {
aurel321cdb9c32008-04-07 21:24:25 +00001380#if USE_PRECISE_EMULATION
j_mayere864cab2007-03-22 22:17:08 +00001381#ifdef FLOAT128
j_mayer7c580442007-10-27 17:54:30 +00001382 /* This is the way the PowerPC specification defines it */
1383 float128 ft0_128, ft1_128;
j_mayere864cab2007-03-22 22:17:08 +00001384
aurel32af129062008-11-19 16:10:23 +00001385 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1386 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001387 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
aurel32da1e7ac2008-12-15 17:14:43 +00001388 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1389 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1390 /* Magnitude subtraction of infinities */
1391 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1392 } else {
1393 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1394 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1395 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1396 }
j_mayere864cab2007-03-22 22:17:08 +00001397#else
j_mayer7c580442007-10-27 17:54:30 +00001398 /* This is OK on x86 hosts */
aurel32af129062008-11-19 16:10:23 +00001399 farg1.d = (farg1.d * farg2.d) + farg3.d;
j_mayere864cab2007-03-22 22:17:08 +00001400#endif
1401#else
aurel32af129062008-11-19 16:10:23 +00001402 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1403 farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
j_mayere864cab2007-03-22 22:17:08 +00001404#endif
aurel32a44d2ce2008-12-13 11:46:27 +00001405 if (likely(!float64_is_nan(farg1.d)))
aurel32af129062008-11-19 16:10:23 +00001406 farg1.d = float64_chs(farg1.d);
j_mayer7c580442007-10-27 17:54:30 +00001407 }
aurel32af129062008-11-19 16:10:23 +00001408 return farg1.ll;
bellard4b3686f2004-05-23 22:18:12 +00001409}
1410
aurel32af129062008-11-19 16:10:23 +00001411/* fnmsub - fnmsub. */
1412uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
bellard4b3686f2004-05-23 22:18:12 +00001413{
aurel32af129062008-11-19 16:10:23 +00001414 CPU_DoubleU farg1, farg2, farg3;
1415
1416 farg1.ll = arg1;
1417 farg2.ll = arg2;
1418 farg3.ll = arg3;
1419
1420 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1421 float64_is_signaling_nan(farg2.d) ||
1422 float64_is_signaling_nan(farg3.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001423 /* sNaN operation */
aurel32af129062008-11-19 16:10:23 +00001424 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel32da1e7ac2008-12-15 17:14:43 +00001425 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1426 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1427 /* Multiplication of zero by infinity */
1428 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
j_mayer7c580442007-10-27 17:54:30 +00001429 } else {
aurel321cdb9c32008-04-07 21:24:25 +00001430#if USE_PRECISE_EMULATION
j_mayere864cab2007-03-22 22:17:08 +00001431#ifdef FLOAT128
j_mayer7c580442007-10-27 17:54:30 +00001432 /* This is the way the PowerPC specification defines it */
1433 float128 ft0_128, ft1_128;
j_mayere864cab2007-03-22 22:17:08 +00001434
aurel32af129062008-11-19 16:10:23 +00001435 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1436 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001437 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
aurel32da1e7ac2008-12-15 17:14:43 +00001438 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1439 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1440 /* Magnitude subtraction of infinities */
1441 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1442 } else {
1443 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1444 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1445 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1446 }
j_mayere864cab2007-03-22 22:17:08 +00001447#else
j_mayer7c580442007-10-27 17:54:30 +00001448 /* This is OK on x86 hosts */
aurel32af129062008-11-19 16:10:23 +00001449 farg1.d = (farg1.d * farg2.d) - farg3.d;
j_mayere864cab2007-03-22 22:17:08 +00001450#endif
1451#else
aurel32af129062008-11-19 16:10:23 +00001452 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1453 farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
j_mayere864cab2007-03-22 22:17:08 +00001454#endif
aurel32a44d2ce2008-12-13 11:46:27 +00001455 if (likely(!float64_is_nan(farg1.d)))
aurel32af129062008-11-19 16:10:23 +00001456 farg1.d = float64_chs(farg1.d);
j_mayer7c580442007-10-27 17:54:30 +00001457 }
aurel32af129062008-11-19 16:10:23 +00001458 return farg1.ll;
bellard1ef59d02004-04-26 19:48:05 +00001459}
1460
aurel32af129062008-11-19 16:10:23 +00001461/* frsp - frsp. */
1462uint64_t helper_frsp (uint64_t arg)
1463{
1464 CPU_DoubleU farg;
aurel326ad193e2008-12-15 01:00:17 +00001465 float32 f32;
aurel32af129062008-11-19 16:10:23 +00001466 farg.ll = arg;
1467
aurel321cdb9c32008-04-07 21:24:25 +00001468#if USE_PRECISE_EMULATION
aurel32af129062008-11-19 16:10:23 +00001469 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001470 /* sNaN square root */
aurel32af129062008-11-19 16:10:23 +00001471 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
j_mayer7c580442007-10-27 17:54:30 +00001472 } else {
aurel326ad193e2008-12-15 01:00:17 +00001473 f32 = float64_to_float32(farg.d, &env->fp_status);
1474 farg.d = float32_to_float64(f32, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001475 }
aurel32af129062008-11-19 16:10:23 +00001476#else
aurel326ad193e2008-12-15 01:00:17 +00001477 f32 = float64_to_float32(farg.d, &env->fp_status);
1478 farg.d = float32_to_float64(f32, &env->fp_status);
aurel32af129062008-11-19 16:10:23 +00001479#endif
1480 return farg.ll;
j_mayer7c580442007-10-27 17:54:30 +00001481}
j_mayer7c580442007-10-27 17:54:30 +00001482
aurel32af129062008-11-19 16:10:23 +00001483/* fsqrt - fsqrt. */
1484uint64_t helper_fsqrt (uint64_t arg)
bellard9a64fbe2004-01-04 22:58:38 +00001485{
aurel32af129062008-11-19 16:10:23 +00001486 CPU_DoubleU farg;
1487 farg.ll = arg;
1488
1489 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001490 /* sNaN square root */
aurel32af129062008-11-19 16:10:23 +00001491 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel32f23c3462008-12-15 17:14:27 +00001492 } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001493 /* Square root of a negative nonzero number */
aurel32af129062008-11-19 16:10:23 +00001494 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
j_mayer7c580442007-10-27 17:54:30 +00001495 } else {
aurel32af129062008-11-19 16:10:23 +00001496 farg.d = float64_sqrt(farg.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001497 }
aurel32af129062008-11-19 16:10:23 +00001498 return farg.ll;
bellard9a64fbe2004-01-04 22:58:38 +00001499}
1500
aurel32af129062008-11-19 16:10:23 +00001501/* fre - fre. */
1502uint64_t helper_fre (uint64_t arg)
j_mayerd7e4b872007-09-30 01:11:48 +00001503{
aurel32c609b122009-02-04 13:52:39 +00001504 CPU_DoubleU farg;
aurel3206f73322009-02-04 14:08:08 +00001505 farg.ll = arg;
j_mayerd7e4b872007-09-30 01:11:48 +00001506
aurel32af129062008-11-19 16:10:23 +00001507 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001508 /* sNaN reciprocal */
aurel32af129062008-11-19 16:10:23 +00001509 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
j_mayerd7e4b872007-09-30 01:11:48 +00001510 } else {
aurel32c609b122009-02-04 13:52:39 +00001511 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
j_mayerd7e4b872007-09-30 01:11:48 +00001512 }
aurel32af129062008-11-19 16:10:23 +00001513 return farg.d;
j_mayerd7e4b872007-09-30 01:11:48 +00001514}
1515
aurel32af129062008-11-19 16:10:23 +00001516/* fres - fres. */
1517uint64_t helper_fres (uint64_t arg)
bellard9a64fbe2004-01-04 22:58:38 +00001518{
aurel3206f73322009-02-04 14:08:08 +00001519 CPU_DoubleU farg;
aurel326c01bf62008-12-18 22:42:23 +00001520 float32 f32;
aurel3206f73322009-02-04 14:08:08 +00001521 farg.ll = arg;
bellard4ecc3192005-03-13 17:01:22 +00001522
aurel32af129062008-11-19 16:10:23 +00001523 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001524 /* sNaN reciprocal */
aurel32af129062008-11-19 16:10:23 +00001525 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
bellard4ecc3192005-03-13 17:01:22 +00001526 } else {
aurel32c609b122009-02-04 13:52:39 +00001527 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
aurel326c01bf62008-12-18 22:42:23 +00001528 f32 = float64_to_float32(farg.d, &env->fp_status);
1529 farg.d = float32_to_float64(f32, &env->fp_status);
bellard4ecc3192005-03-13 17:01:22 +00001530 }
aurel32af129062008-11-19 16:10:23 +00001531 return farg.ll;
bellard9a64fbe2004-01-04 22:58:38 +00001532}
1533
aurel32af129062008-11-19 16:10:23 +00001534/* frsqrte - frsqrte. */
1535uint64_t helper_frsqrte (uint64_t arg)
bellard9a64fbe2004-01-04 22:58:38 +00001536{
aurel32c609b122009-02-04 13:52:39 +00001537 CPU_DoubleU farg;
aurel326c01bf62008-12-18 22:42:23 +00001538 float32 f32;
aurel3206f73322009-02-04 14:08:08 +00001539 farg.ll = arg;
bellard4ecc3192005-03-13 17:01:22 +00001540
aurel32af129062008-11-19 16:10:23 +00001541 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001542 /* sNaN reciprocal square root */
aurel32af129062008-11-19 16:10:23 +00001543 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel32f23c3462008-12-15 17:14:27 +00001544 } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001545 /* Reciprocal square root of a negative nonzero number */
aurel32af129062008-11-19 16:10:23 +00001546 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
bellard4ecc3192005-03-13 17:01:22 +00001547 } else {
aurel326c01bf62008-12-18 22:42:23 +00001548 farg.d = float64_sqrt(farg.d, &env->fp_status);
aurel32c609b122009-02-04 13:52:39 +00001549 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
aurel326c01bf62008-12-18 22:42:23 +00001550 f32 = float64_to_float32(farg.d, &env->fp_status);
1551 farg.d = float32_to_float64(f32, &env->fp_status);
bellard4ecc3192005-03-13 17:01:22 +00001552 }
aurel32af129062008-11-19 16:10:23 +00001553 return farg.ll;
bellard9a64fbe2004-01-04 22:58:38 +00001554}
1555
aurel32af129062008-11-19 16:10:23 +00001556/* fsel - fsel. */
1557uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
bellard9a64fbe2004-01-04 22:58:38 +00001558{
aurel326ad73652008-12-14 11:12:10 +00001559 CPU_DoubleU farg1;
aurel32af129062008-11-19 16:10:23 +00001560
1561 farg1.ll = arg1;
aurel32af129062008-11-19 16:10:23 +00001562
aurel32572c8952008-12-29 09:47:11 +00001563 if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_nan(farg1.d))
aurel326ad73652008-12-14 11:12:10 +00001564 return arg2;
bellard4ecc3192005-03-13 17:01:22 +00001565 else
aurel326ad73652008-12-14 11:12:10 +00001566 return arg3;
bellard9a64fbe2004-01-04 22:58:38 +00001567}
1568
aurel329a819372008-12-14 19:34:09 +00001569void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
bellard9a64fbe2004-01-04 22:58:38 +00001570{
aurel32af129062008-11-19 16:10:23 +00001571 CPU_DoubleU farg1, farg2;
aurel32e1571902008-10-21 11:31:14 +00001572 uint32_t ret = 0;
aurel32af129062008-11-19 16:10:23 +00001573 farg1.ll = arg1;
1574 farg2.ll = arg2;
aurel32e1571902008-10-21 11:31:14 +00001575
aurel32af129062008-11-19 16:10:23 +00001576 if (unlikely(float64_is_nan(farg1.d) ||
1577 float64_is_nan(farg2.d))) {
aurel329a819372008-12-14 19:34:09 +00001578 ret = 0x01UL;
1579 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1580 ret = 0x08UL;
1581 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1582 ret = 0x04UL;
1583 } else {
1584 ret = 0x02UL;
1585 }
1586
1587 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1588 env->fpscr |= ret << FPSCR_FPRF;
1589 env->crf[crfD] = ret;
1590 if (unlikely(ret == 0x01UL
1591 && (float64_is_signaling_nan(farg1.d) ||
1592 float64_is_signaling_nan(farg2.d)))) {
1593 /* sNaN comparison */
1594 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1595 }
1596}
1597
1598void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1599{
1600 CPU_DoubleU farg1, farg2;
1601 uint32_t ret = 0;
1602 farg1.ll = arg1;
1603 farg2.ll = arg2;
1604
1605 if (unlikely(float64_is_nan(farg1.d) ||
1606 float64_is_nan(farg2.d))) {
1607 ret = 0x01UL;
1608 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1609 ret = 0x08UL;
1610 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1611 ret = 0x04UL;
1612 } else {
1613 ret = 0x02UL;
1614 }
1615
1616 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1617 env->fpscr |= ret << FPSCR_FPRF;
1618 env->crf[crfD] = ret;
1619 if (unlikely (ret == 0x01UL)) {
aurel32af129062008-11-19 16:10:23 +00001620 if (float64_is_signaling_nan(farg1.d) ||
1621 float64_is_signaling_nan(farg2.d)) {
j_mayer7c580442007-10-27 17:54:30 +00001622 /* sNaN comparison */
1623 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1624 POWERPC_EXCP_FP_VXVC);
1625 } else {
1626 /* qNaN comparison */
1627 fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
1628 }
bellard9a64fbe2004-01-04 22:58:38 +00001629 }
bellard9a64fbe2004-01-04 22:58:38 +00001630}
1631
j_mayer76a66252007-03-07 08:32:30 +00001632#if !defined (CONFIG_USER_ONLY)
aurel326527f6e2008-12-06 13:03:35 +00001633void helper_store_msr (target_ulong val)
j_mayer0411a972007-10-25 21:35:50 +00001634{
aurel326527f6e2008-12-06 13:03:35 +00001635 val = hreg_store_msr(env, val, 0);
1636 if (val != 0) {
j_mayer0411a972007-10-25 21:35:50 +00001637 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
aurel32e06fcd72008-12-11 22:42:14 +00001638 helper_raise_exception(val);
j_mayer0411a972007-10-25 21:35:50 +00001639 }
1640}
1641
aurel32d72a19f2008-11-30 16:24:55 +00001642static always_inline void do_rfi (target_ulong nip, target_ulong msr,
j_mayer0411a972007-10-25 21:35:50 +00001643 target_ulong msrm, int keep_msrh)
bellard9a64fbe2004-01-04 22:58:38 +00001644{
j_mayer426613d2007-03-23 09:45:27 +00001645#if defined(TARGET_PPC64)
j_mayer0411a972007-10-25 21:35:50 +00001646 if (msr & (1ULL << MSR_SF)) {
1647 nip = (uint64_t)nip;
1648 msr &= (uint64_t)msrm;
j_mayera42bd6c2007-03-30 10:22:46 +00001649 } else {
j_mayer0411a972007-10-25 21:35:50 +00001650 nip = (uint32_t)nip;
1651 msr = (uint32_t)(msr & msrm);
1652 if (keep_msrh)
1653 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
j_mayera42bd6c2007-03-30 10:22:46 +00001654 }
j_mayer426613d2007-03-23 09:45:27 +00001655#else
j_mayer0411a972007-10-25 21:35:50 +00001656 nip = (uint32_t)nip;
1657 msr &= (uint32_t)msrm;
j_mayer426613d2007-03-23 09:45:27 +00001658#endif
j_mayer0411a972007-10-25 21:35:50 +00001659 /* XXX: beware: this is false if VLE is supported */
1660 env->nip = nip & ~((target_ulong)0x00000003);
j_mayera4f30712007-11-17 21:14:09 +00001661 hreg_store_msr(env, msr, 1);
j_mayerd9bce9d2007-03-17 14:02:15 +00001662#if defined (DEBUG_OP)
j_mayer0411a972007-10-25 21:35:50 +00001663 cpu_dump_rfi(env->nip, env->msr);
j_mayerd9bce9d2007-03-17 14:02:15 +00001664#endif
j_mayer0411a972007-10-25 21:35:50 +00001665 /* No need to raise an exception here,
1666 * as rfi is always the last insn of a TB
1667 */
j_mayerd9bce9d2007-03-17 14:02:15 +00001668 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1669}
1670
aurel32d72a19f2008-11-30 16:24:55 +00001671void helper_rfi (void)
j_mayer0411a972007-10-25 21:35:50 +00001672{
aurel32d72a19f2008-11-30 16:24:55 +00001673 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1674 ~((target_ulong)0xFFFF0000), 1);
j_mayer0411a972007-10-25 21:35:50 +00001675}
1676
j_mayerd9bce9d2007-03-17 14:02:15 +00001677#if defined(TARGET_PPC64)
aurel32d72a19f2008-11-30 16:24:55 +00001678void helper_rfid (void)
j_mayer426613d2007-03-23 09:45:27 +00001679{
aurel32d72a19f2008-11-30 16:24:55 +00001680 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1681 ~((target_ulong)0xFFFF0000), 0);
bellard9a64fbe2004-01-04 22:58:38 +00001682}
j_mayer78636672007-11-16 14:11:28 +00001683
aurel32d72a19f2008-11-30 16:24:55 +00001684void helper_hrfid (void)
j_mayerbe147d02007-09-30 13:03:23 +00001685{
aurel32d72a19f2008-11-30 16:24:55 +00001686 do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
1687 ~((target_ulong)0xFFFF0000), 0);
j_mayerbe147d02007-09-30 13:03:23 +00001688}
1689#endif
j_mayerd9bce9d2007-03-17 14:02:15 +00001690#endif
bellard9a64fbe2004-01-04 22:58:38 +00001691
aurel32cab3bee2008-11-24 11:28:19 +00001692void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
bellard9a64fbe2004-01-04 22:58:38 +00001693{
aurel32cab3bee2008-11-24 11:28:19 +00001694 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1695 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1696 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1697 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1698 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
aurel32e06fcd72008-12-11 22:42:14 +00001699 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
j_mayera42bd6c2007-03-30 10:22:46 +00001700 }
bellard9a64fbe2004-01-04 22:58:38 +00001701}
1702
j_mayerd9bce9d2007-03-17 14:02:15 +00001703#if defined(TARGET_PPC64)
aurel32cab3bee2008-11-24 11:28:19 +00001704void helper_td (target_ulong arg1, target_ulong arg2, uint32_t flags)
j_mayerd9bce9d2007-03-17 14:02:15 +00001705{
aurel32cab3bee2008-11-24 11:28:19 +00001706 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1707 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1708 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1709 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1710 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01)))))
aurel32e06fcd72008-12-11 22:42:14 +00001711 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
j_mayerd9bce9d2007-03-17 14:02:15 +00001712}
1713#endif
1714
bellardfdabc362005-07-04 22:17:05 +00001715/*****************************************************************************/
j_mayer76a66252007-03-07 08:32:30 +00001716/* PowerPC 601 specific instructions (POWER bridge) */
bellard9a64fbe2004-01-04 22:58:38 +00001717
aurel3222e0e172008-12-06 12:19:14 +00001718target_ulong helper_clcs (uint32_t arg)
bellard9a64fbe2004-01-04 22:58:38 +00001719{
aurel3222e0e172008-12-06 12:19:14 +00001720 switch (arg) {
j_mayer76a66252007-03-07 08:32:30 +00001721 case 0x0CUL:
1722 /* Instruction cache line size */
aurel3222e0e172008-12-06 12:19:14 +00001723 return env->icache_line_size;
j_mayer76a66252007-03-07 08:32:30 +00001724 break;
1725 case 0x0DUL:
1726 /* Data cache line size */
aurel3222e0e172008-12-06 12:19:14 +00001727 return env->dcache_line_size;
j_mayer76a66252007-03-07 08:32:30 +00001728 break;
1729 case 0x0EUL:
1730 /* Minimum cache line size */
aurel3222e0e172008-12-06 12:19:14 +00001731 return (env->icache_line_size < env->dcache_line_size) ?
1732 env->icache_line_size : env->dcache_line_size;
j_mayer76a66252007-03-07 08:32:30 +00001733 break;
1734 case 0x0FUL:
1735 /* Maximum cache line size */
aurel3222e0e172008-12-06 12:19:14 +00001736 return (env->icache_line_size > env->dcache_line_size) ?
1737 env->icache_line_size : env->dcache_line_size;
j_mayer76a66252007-03-07 08:32:30 +00001738 break;
1739 default:
1740 /* Undefined */
aurel3222e0e172008-12-06 12:19:14 +00001741 return 0;
j_mayer76a66252007-03-07 08:32:30 +00001742 break;
1743 }
1744}
1745
aurel3222e0e172008-12-06 12:19:14 +00001746target_ulong helper_div (target_ulong arg1, target_ulong arg2)
j_mayer76a66252007-03-07 08:32:30 +00001747{
aurel3222e0e172008-12-06 12:19:14 +00001748 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
j_mayer76a66252007-03-07 08:32:30 +00001749
aurel3222e0e172008-12-06 12:19:14 +00001750 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1751 (int32_t)arg2 == 0) {
j_mayer76a66252007-03-07 08:32:30 +00001752 env->spr[SPR_MQ] = 0;
aurel3222e0e172008-12-06 12:19:14 +00001753 return INT32_MIN;
j_mayer76a66252007-03-07 08:32:30 +00001754 } else {
aurel3222e0e172008-12-06 12:19:14 +00001755 env->spr[SPR_MQ] = tmp % arg2;
1756 return tmp / (int32_t)arg2;
j_mayer76a66252007-03-07 08:32:30 +00001757 }
1758}
1759
aurel3222e0e172008-12-06 12:19:14 +00001760target_ulong helper_divo (target_ulong arg1, target_ulong arg2)
j_mayer76a66252007-03-07 08:32:30 +00001761{
aurel3222e0e172008-12-06 12:19:14 +00001762 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
j_mayer76a66252007-03-07 08:32:30 +00001763
aurel3222e0e172008-12-06 12:19:14 +00001764 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1765 (int32_t)arg2 == 0) {
aurel323d7b4172008-10-21 11:28:46 +00001766 env->xer |= (1 << XER_OV) | (1 << XER_SO);
aurel3222e0e172008-12-06 12:19:14 +00001767 env->spr[SPR_MQ] = 0;
1768 return INT32_MIN;
j_mayer76a66252007-03-07 08:32:30 +00001769 } else {
aurel3222e0e172008-12-06 12:19:14 +00001770 env->spr[SPR_MQ] = tmp % arg2;
1771 tmp /= (int32_t)arg2;
1772 if ((int32_t)tmp != tmp) {
aurel323d7b4172008-10-21 11:28:46 +00001773 env->xer |= (1 << XER_OV) | (1 << XER_SO);
j_mayer76a66252007-03-07 08:32:30 +00001774 } else {
aurel323d7b4172008-10-21 11:28:46 +00001775 env->xer &= ~(1 << XER_OV);
j_mayer76a66252007-03-07 08:32:30 +00001776 }
aurel3222e0e172008-12-06 12:19:14 +00001777 return tmp;
j_mayer76a66252007-03-07 08:32:30 +00001778 }
1779}
1780
aurel3222e0e172008-12-06 12:19:14 +00001781target_ulong helper_divs (target_ulong arg1, target_ulong arg2)
j_mayer76a66252007-03-07 08:32:30 +00001782{
aurel3222e0e172008-12-06 12:19:14 +00001783 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1784 (int32_t)arg2 == 0) {
j_mayer76a66252007-03-07 08:32:30 +00001785 env->spr[SPR_MQ] = 0;
aurel3222e0e172008-12-06 12:19:14 +00001786 return INT32_MIN;
j_mayer76a66252007-03-07 08:32:30 +00001787 } else {
aurel3222e0e172008-12-06 12:19:14 +00001788 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1789 return (int32_t)arg1 / (int32_t)arg2;
j_mayer76a66252007-03-07 08:32:30 +00001790 }
1791}
1792
aurel3222e0e172008-12-06 12:19:14 +00001793target_ulong helper_divso (target_ulong arg1, target_ulong arg2)
j_mayer76a66252007-03-07 08:32:30 +00001794{
aurel3222e0e172008-12-06 12:19:14 +00001795 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1796 (int32_t)arg2 == 0) {
1797 env->xer |= (1 << XER_OV) | (1 << XER_SO);
j_mayer76a66252007-03-07 08:32:30 +00001798 env->spr[SPR_MQ] = 0;
aurel3222e0e172008-12-06 12:19:14 +00001799 return INT32_MIN;
j_mayer76a66252007-03-07 08:32:30 +00001800 } else {
aurel323d7b4172008-10-21 11:28:46 +00001801 env->xer &= ~(1 << XER_OV);
aurel3222e0e172008-12-06 12:19:14 +00001802 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1803 return (int32_t)arg1 / (int32_t)arg2;
j_mayer76a66252007-03-07 08:32:30 +00001804 }
1805}
1806
1807#if !defined (CONFIG_USER_ONLY)
aurel3222e0e172008-12-06 12:19:14 +00001808target_ulong helper_rac (target_ulong addr)
j_mayer76a66252007-03-07 08:32:30 +00001809{
j_mayer76a66252007-03-07 08:32:30 +00001810 mmu_ctx_t ctx;
j_mayerfaadf502007-11-03 13:37:12 +00001811 int nb_BATs;
aurel3222e0e172008-12-06 12:19:14 +00001812 target_ulong ret = 0;
j_mayer76a66252007-03-07 08:32:30 +00001813
1814 /* We don't have to generate many instances of this instruction,
1815 * as rac is supervisor only.
1816 */
j_mayerfaadf502007-11-03 13:37:12 +00001817 /* XXX: FIX THIS: Pretend we have no BAT */
1818 nb_BATs = env->nb_BATs;
1819 env->nb_BATs = 0;
aurel3222e0e172008-12-06 12:19:14 +00001820 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0)
1821 ret = ctx.raddr;
j_mayerfaadf502007-11-03 13:37:12 +00001822 env->nb_BATs = nb_BATs;
aurel3222e0e172008-12-06 12:19:14 +00001823 return ret;
bellard9a64fbe2004-01-04 22:58:38 +00001824}
1825
aurel32d72a19f2008-11-30 16:24:55 +00001826void helper_rfsvc (void)
j_mayer76a66252007-03-07 08:32:30 +00001827{
aurel32d72a19f2008-11-30 16:24:55 +00001828 do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
j_mayer76a66252007-03-07 08:32:30 +00001829}
j_mayer76a66252007-03-07 08:32:30 +00001830#endif
1831
1832/*****************************************************************************/
1833/* 602 specific instructions */
1834/* mfrom is the most crazy instruction ever seen, imho ! */
1835/* Real implementation uses a ROM table. Do the same */
aurel325e9ae182008-12-13 12:30:21 +00001836/* Extremly decomposed:
1837 * -arg / 256
1838 * return 256 * log10(10 + 1.0) + 0.5
1839 */
aurel32db9a16a2008-12-08 18:11:50 +00001840#if !defined (CONFIG_USER_ONLY)
aurel32cf02a652008-11-30 16:23:35 +00001841target_ulong helper_602_mfrom (target_ulong arg)
j_mayer76a66252007-03-07 08:32:30 +00001842{
aurel32cf02a652008-11-30 16:23:35 +00001843 if (likely(arg < 602)) {
j_mayer76a66252007-03-07 08:32:30 +00001844#include "mfrom_table.c"
aurel3245d827d2008-12-07 13:40:29 +00001845 return mfrom_ROM_table[arg];
j_mayer76a66252007-03-07 08:32:30 +00001846 } else {
aurel32cf02a652008-11-30 16:23:35 +00001847 return 0;
j_mayer76a66252007-03-07 08:32:30 +00001848 }
1849}
aurel32db9a16a2008-12-08 18:11:50 +00001850#endif
j_mayer76a66252007-03-07 08:32:30 +00001851
1852/*****************************************************************************/
1853/* Embedded PowerPC specific helpers */
j_mayer76a66252007-03-07 08:32:30 +00001854
j_mayera750fc02007-09-26 23:54:22 +00001855/* XXX: to be improved to check access rights when in user-mode */
aurel3206dca6a2008-12-06 16:37:18 +00001856target_ulong helper_load_dcr (target_ulong dcrn)
j_mayera750fc02007-09-26 23:54:22 +00001857{
aurel3206dca6a2008-12-06 16:37:18 +00001858 target_ulong val = 0;
j_mayera750fc02007-09-26 23:54:22 +00001859
1860 if (unlikely(env->dcr_env == NULL)) {
aliguori93fcfe32009-01-15 22:34:14 +00001861 qemu_log("No DCR environment\n");
aurel32e06fcd72008-12-11 22:42:14 +00001862 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1863 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
aurel3206dca6a2008-12-06 16:37:18 +00001864 } else if (unlikely(ppc_dcr_read(env->dcr_env, dcrn, &val) != 0)) {
aliguori93fcfe32009-01-15 22:34:14 +00001865 qemu_log("DCR read error %d %03x\n", (int)dcrn, (int)dcrn);
aurel32e06fcd72008-12-11 22:42:14 +00001866 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1867 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
j_mayera750fc02007-09-26 23:54:22 +00001868 }
aurel3206dca6a2008-12-06 16:37:18 +00001869 return val;
j_mayera750fc02007-09-26 23:54:22 +00001870}
1871
aurel3206dca6a2008-12-06 16:37:18 +00001872void helper_store_dcr (target_ulong dcrn, target_ulong val)
j_mayera750fc02007-09-26 23:54:22 +00001873{
1874 if (unlikely(env->dcr_env == NULL)) {
aliguori93fcfe32009-01-15 22:34:14 +00001875 qemu_log("No DCR environment\n");
aurel32e06fcd72008-12-11 22:42:14 +00001876 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1877 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
aurel3206dca6a2008-12-06 16:37:18 +00001878 } else if (unlikely(ppc_dcr_write(env->dcr_env, dcrn, val) != 0)) {
aliguori93fcfe32009-01-15 22:34:14 +00001879 qemu_log("DCR write error %d %03x\n", (int)dcrn, (int)dcrn);
aurel32e06fcd72008-12-11 22:42:14 +00001880 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1881 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
j_mayera750fc02007-09-26 23:54:22 +00001882 }
1883}
1884
j_mayer76a66252007-03-07 08:32:30 +00001885#if !defined(CONFIG_USER_ONLY)
aurel32d72a19f2008-11-30 16:24:55 +00001886void helper_40x_rfci (void)
j_mayer76a66252007-03-07 08:32:30 +00001887{
aurel32d72a19f2008-11-30 16:24:55 +00001888 do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
1889 ~((target_ulong)0xFFFF0000), 0);
j_mayer76a66252007-03-07 08:32:30 +00001890}
1891
aurel32d72a19f2008-11-30 16:24:55 +00001892void helper_rfci (void)
j_mayera42bd6c2007-03-30 10:22:46 +00001893{
aurel32d72a19f2008-11-30 16:24:55 +00001894 do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
1895 ~((target_ulong)0x3FFF0000), 0);
j_mayera42bd6c2007-03-30 10:22:46 +00001896}
1897
aurel32d72a19f2008-11-30 16:24:55 +00001898void helper_rfdi (void)
j_mayera42bd6c2007-03-30 10:22:46 +00001899{
aurel32d72a19f2008-11-30 16:24:55 +00001900 do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
1901 ~((target_ulong)0x3FFF0000), 0);
j_mayera42bd6c2007-03-30 10:22:46 +00001902}
1903
aurel32d72a19f2008-11-30 16:24:55 +00001904void helper_rfmci (void)
j_mayera42bd6c2007-03-30 10:22:46 +00001905{
aurel32d72a19f2008-11-30 16:24:55 +00001906 do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
1907 ~((target_ulong)0x3FFF0000), 0);
j_mayera42bd6c2007-03-30 10:22:46 +00001908}
j_mayer76a66252007-03-07 08:32:30 +00001909#endif
1910
1911/* 440 specific */
aurel32ef0d51a2008-11-30 17:26:29 +00001912target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
j_mayer76a66252007-03-07 08:32:30 +00001913{
1914 target_ulong mask;
1915 int i;
1916
1917 i = 1;
1918 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
aurel32ef0d51a2008-11-30 17:26:29 +00001919 if ((high & mask) == 0) {
1920 if (update_Rc) {
1921 env->crf[0] = 0x4;
1922 }
j_mayer76a66252007-03-07 08:32:30 +00001923 goto done;
aurel32ef0d51a2008-11-30 17:26:29 +00001924 }
j_mayer76a66252007-03-07 08:32:30 +00001925 i++;
1926 }
1927 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
aurel32ef0d51a2008-11-30 17:26:29 +00001928 if ((low & mask) == 0) {
1929 if (update_Rc) {
1930 env->crf[0] = 0x8;
1931 }
1932 goto done;
1933 }
j_mayer76a66252007-03-07 08:32:30 +00001934 i++;
1935 }
aurel32ef0d51a2008-11-30 17:26:29 +00001936 if (update_Rc) {
1937 env->crf[0] = 0x2;
1938 }
j_mayer76a66252007-03-07 08:32:30 +00001939 done:
aurel32ef0d51a2008-11-30 17:26:29 +00001940 env->xer = (env->xer & ~0x7F) | i;
1941 if (update_Rc) {
1942 env->crf[0] |= xer_so;
1943 }
1944 return i;
j_mayer76a66252007-03-07 08:32:30 +00001945}
1946
aurel321c978562008-11-23 10:54:04 +00001947/*****************************************************************************/
aurel32d6a46fe2009-01-03 13:31:19 +00001948/* Altivec extension helpers */
1949#if defined(WORDS_BIGENDIAN)
1950#define HI_IDX 0
1951#define LO_IDX 1
1952#else
1953#define HI_IDX 1
1954#define LO_IDX 0
1955#endif
1956
1957#if defined(WORDS_BIGENDIAN)
1958#define VECTOR_FOR_INORDER_I(index, element) \
1959 for (index = 0; index < ARRAY_SIZE(r->element); index++)
1960#else
1961#define VECTOR_FOR_INORDER_I(index, element) \
1962 for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
1963#endif
1964
aurel3234ba2852009-02-04 09:05:53 +00001965/* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise,
1966 * execute the following block. */
1967#define DO_HANDLE_NAN(result, x) \
1968 if (float32_is_nan(x) || float32_is_signaling_nan(x)) { \
1969 CPU_FloatU __f; \
1970 __f.f = x; \
1971 __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \
1972 result = __f.f; \
1973 } else
1974
1975#define HANDLE_NAN1(result, x) \
1976 DO_HANDLE_NAN(result, x)
1977#define HANDLE_NAN2(result, x, y) \
1978 DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y)
1979#define HANDLE_NAN3(result, x, y, z) \
1980 DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z)
1981
aurel3200d3b8f2009-01-04 22:11:59 +00001982/* Saturating arithmetic helpers. */
1983#define SATCVT(from, to, from_type, to_type, min, max, use_min, use_max) \
1984 static always_inline to_type cvt##from##to (from_type x, int *sat) \
1985 { \
1986 to_type r; \
1987 if (use_min && x < min) { \
1988 r = min; \
1989 *sat = 1; \
1990 } else if (use_max && x > max) { \
1991 r = max; \
1992 *sat = 1; \
1993 } else { \
1994 r = x; \
1995 } \
1996 return r; \
1997 }
1998SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX, 1, 1)
1999SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX, 1, 1)
2000SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX, 1, 1)
2001SATCVT(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX, 0, 1)
2002SATCVT(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX, 0, 1)
2003SATCVT(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX, 0, 1)
2004SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX, 1, 1)
2005SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX, 1, 1)
2006SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX, 1, 1)
2007#undef SATCVT
2008
aurel32cbfb6ae2009-01-04 22:13:10 +00002009#define LVE(name, access, swap, element) \
2010 void helper_##name (ppc_avr_t *r, target_ulong addr) \
2011 { \
2012 size_t n_elems = ARRAY_SIZE(r->element); \
2013 int adjust = HI_IDX*(n_elems-1); \
2014 int sh = sizeof(r->element[0]) >> 1; \
2015 int index = (addr & 0xf) >> sh; \
2016 if(msr_le) { \
2017 r->element[LO_IDX ? index : (adjust - index)] = swap(access(addr)); \
2018 } else { \
2019 r->element[LO_IDX ? index : (adjust - index)] = access(addr); \
2020 } \
2021 }
2022#define I(x) (x)
2023LVE(lvebx, ldub, I, u8)
2024LVE(lvehx, lduw, bswap16, u16)
2025LVE(lvewx, ldl, bswap32, u32)
2026#undef I
2027#undef LVE
2028
aurel32bf8d8de2009-01-04 22:09:42 +00002029void helper_lvsl (ppc_avr_t *r, target_ulong sh)
2030{
2031 int i, j = (sh & 0xf);
2032
2033 VECTOR_FOR_INORDER_I (i, u8) {
2034 r->u8[i] = j++;
2035 }
2036}
2037
2038void helper_lvsr (ppc_avr_t *r, target_ulong sh)
2039{
2040 int i, j = 0x10 - (sh & 0xf);
2041
2042 VECTOR_FOR_INORDER_I (i, u8) {
2043 r->u8[i] = j++;
2044 }
2045}
2046
aurel32cbfb6ae2009-01-04 22:13:10 +00002047#define STVE(name, access, swap, element) \
2048 void helper_##name (ppc_avr_t *r, target_ulong addr) \
2049 { \
2050 size_t n_elems = ARRAY_SIZE(r->element); \
2051 int adjust = HI_IDX*(n_elems-1); \
2052 int sh = sizeof(r->element[0]) >> 1; \
2053 int index = (addr & 0xf) >> sh; \
2054 if(msr_le) { \
2055 access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \
2056 } else { \
2057 access(addr, r->element[LO_IDX ? index : (adjust - index)]); \
2058 } \
2059 }
2060#define I(x) (x)
2061STVE(stvebx, stb, I, u8)
2062STVE(stvehx, stw, bswap16, u16)
2063STVE(stvewx, stl, bswap32, u32)
2064#undef I
2065#undef LVE
2066
aurel326e87b7c2009-02-03 19:56:09 +00002067void helper_mtvscr (ppc_avr_t *r)
2068{
2069#if defined(WORDS_BIGENDIAN)
2070 env->vscr = r->u32[3];
2071#else
2072 env->vscr = r->u32[0];
2073#endif
2074 set_flush_to_zero(vscr_nj, &env->vec_status);
2075}
2076
aurel32e343da72009-01-04 22:09:31 +00002077void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2078{
2079 int i;
2080 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2081 r->u32[i] = ~a->u32[i] < b->u32[i];
2082 }
2083}
2084
aurel327872c512009-01-03 13:31:40 +00002085#define VARITH_DO(name, op, element) \
2086void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2087{ \
2088 int i; \
2089 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2090 r->element[i] = a->element[i] op b->element[i]; \
2091 } \
2092}
2093#define VARITH(suffix, element) \
2094 VARITH_DO(add##suffix, +, element) \
2095 VARITH_DO(sub##suffix, -, element)
2096VARITH(ubm, u8)
2097VARITH(uhm, u16)
2098VARITH(uwm, u32)
2099#undef VARITH_DO
2100#undef VARITH
2101
aurel325ab09f32009-01-08 23:19:50 +00002102#define VARITHSAT_CASE(type, op, cvt, element) \
2103 { \
2104 type result = (type)a->element[i] op (type)b->element[i]; \
2105 r->element[i] = cvt(result, &sat); \
2106 }
2107
2108#define VARITHSAT_DO(name, op, optype, cvt, element) \
2109 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2110 { \
2111 int sat = 0; \
2112 int i; \
2113 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2114 switch (sizeof(r->element[0])) { \
2115 case 1: VARITHSAT_CASE(optype, op, cvt, element); break; \
2116 case 2: VARITHSAT_CASE(optype, op, cvt, element); break; \
2117 case 4: VARITHSAT_CASE(optype, op, cvt, element); break; \
2118 } \
2119 } \
2120 if (sat) { \
2121 env->vscr |= (1 << VSCR_SAT); \
2122 } \
2123 }
2124#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
2125 VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
2126 VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
2127#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
2128 VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
2129 VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
2130VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
2131VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
2132VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
2133VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
2134VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
2135VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
2136#undef VARITHSAT_CASE
2137#undef VARITHSAT_DO
2138#undef VARITHSAT_SIGNED
2139#undef VARITHSAT_UNSIGNED
2140
aurel32fab3cbe2009-01-03 13:31:49 +00002141#define VAVG_DO(name, element, etype) \
2142 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2143 { \
2144 int i; \
2145 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2146 etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
2147 r->element[i] = x >> 1; \
2148 } \
2149 }
2150
2151#define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
2152 VAVG_DO(avgs##type, signed_element, signed_type) \
2153 VAVG_DO(avgu##type, unsigned_element, unsigned_type)
2154VAVG(b, s8, int16_t, u8, uint16_t)
2155VAVG(h, s16, int32_t, u16, uint32_t)
2156VAVG(w, s32, int64_t, u32, uint64_t)
2157#undef VAVG_DO
2158#undef VAVG
2159
aurel32e1406322009-02-04 13:52:17 +00002160#define VCF(suffix, cvt, element) \
2161 void helper_vcf##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
2162 { \
2163 int i; \
2164 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2165 float32 t = cvt(b->element[i], &env->vec_status); \
2166 r->f[i] = float32_scalbn (t, -uim, &env->vec_status); \
2167 } \
2168 }
2169VCF(ux, uint32_to_float32, u32)
2170VCF(sx, int32_to_float32, s32)
2171#undef VCF
2172
aurel321add6e22009-01-08 18:54:38 +00002173#define VCMP_DO(suffix, compare, element, record) \
2174 void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2175 { \
2176 uint32_t ones = (uint32_t)-1; \
2177 uint32_t all = ones; \
2178 uint32_t none = 0; \
2179 int i; \
2180 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2181 uint32_t result = (a->element[i] compare b->element[i] ? ones : 0x0); \
2182 switch (sizeof (a->element[0])) { \
2183 case 4: r->u32[i] = result; break; \
2184 case 2: r->u16[i] = result; break; \
2185 case 1: r->u8[i] = result; break; \
2186 } \
2187 all &= result; \
2188 none |= result; \
2189 } \
2190 if (record) { \
2191 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
2192 } \
2193 }
2194#define VCMP(suffix, compare, element) \
2195 VCMP_DO(suffix, compare, element, 0) \
2196 VCMP_DO(suffix##_dot, compare, element, 1)
2197VCMP(equb, ==, u8)
2198VCMP(equh, ==, u16)
2199VCMP(equw, ==, u32)
2200VCMP(gtub, >, u8)
2201VCMP(gtuh, >, u16)
2202VCMP(gtuw, >, u32)
2203VCMP(gtsb, >, s8)
2204VCMP(gtsh, >, s16)
2205VCMP(gtsw, >, s32)
2206#undef VCMP_DO
2207#undef VCMP
2208
aurel32b161ae22009-01-04 22:12:29 +00002209void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2210{
2211 int sat = 0;
2212 int i;
2213
2214 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2215 int32_t prod = a->s16[i] * b->s16[i];
2216 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2217 r->s16[i] = cvtswsh (t, &sat);
2218 }
2219
2220 if (sat) {
2221 env->vscr |= (1 << VSCR_SAT);
2222 }
2223}
2224
2225void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2226{
2227 int sat = 0;
2228 int i;
2229
2230 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2231 int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
2232 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2233 r->s16[i] = cvtswsh (t, &sat);
2234 }
2235
2236 if (sat) {
2237 env->vscr |= (1 << VSCR_SAT);
2238 }
2239}
2240
aurel32e4039332009-01-03 13:31:58 +00002241#define VMINMAX_DO(name, compare, element) \
2242 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2243 { \
2244 int i; \
2245 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2246 if (a->element[i] compare b->element[i]) { \
2247 r->element[i] = b->element[i]; \
2248 } else { \
2249 r->element[i] = a->element[i]; \
2250 } \
2251 } \
2252 }
2253#define VMINMAX(suffix, element) \
2254 VMINMAX_DO(min##suffix, >, element) \
2255 VMINMAX_DO(max##suffix, <, element)
2256VMINMAX(sb, s8)
2257VMINMAX(sh, s16)
2258VMINMAX(sw, s32)
2259VMINMAX(ub, u8)
2260VMINMAX(uh, u16)
2261VMINMAX(uw, u32)
2262#undef VMINMAX_DO
2263#undef VMINMAX
2264
aurel321536ff62009-02-09 16:48:39 +00002265#define VMINMAXFP(suffix, rT, rF) \
2266 void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2267 { \
2268 int i; \
2269 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2270 HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
2271 if (float32_lt_quiet(a->f[i], b->f[i], &env->vec_status)) { \
2272 r->f[i] = rT->f[i]; \
2273 } else { \
2274 r->f[i] = rF->f[i]; \
2275 } \
2276 } \
2277 } \
2278 }
2279VMINMAXFP(minfp, a, b)
2280VMINMAXFP(maxfp, b, a)
2281#undef VMINMAXFP
2282
aurel32bcd2ee22009-01-04 22:13:00 +00002283void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2284{
2285 int i;
2286 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2287 int32_t prod = a->s16[i] * b->s16[i];
2288 r->s16[i] = (int16_t) (prod + c->s16[i]);
2289 }
2290}
2291
aurel323b430042009-01-04 22:08:38 +00002292#define VMRG_DO(name, element, highp) \
2293 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2294 { \
2295 ppc_avr_t result; \
2296 int i; \
2297 size_t n_elems = ARRAY_SIZE(r->element); \
2298 for (i = 0; i < n_elems/2; i++) { \
2299 if (highp) { \
2300 result.element[i*2+HI_IDX] = a->element[i]; \
2301 result.element[i*2+LO_IDX] = b->element[i]; \
2302 } else { \
2303 result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
2304 result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
2305 } \
2306 } \
2307 *r = result; \
2308 }
2309#if defined(WORDS_BIGENDIAN)
2310#define MRGHI 0
aurel32b392e752009-01-05 21:40:27 +00002311#define MRGLO 1
aurel323b430042009-01-04 22:08:38 +00002312#else
2313#define MRGHI 1
2314#define MRGLO 0
2315#endif
2316#define VMRG(suffix, element) \
2317 VMRG_DO(mrgl##suffix, element, MRGHI) \
2318 VMRG_DO(mrgh##suffix, element, MRGLO)
2319VMRG(b, u8)
2320VMRG(h, u16)
2321VMRG(w, u32)
2322#undef VMRG_DO
2323#undef VMRG
2324#undef MRGHI
2325#undef MRGLO
2326
aurel32b04ae982009-01-04 22:11:39 +00002327void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2328{
2329 int32_t prod[16];
2330 int i;
2331
2332 for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
2333 prod[i] = (int32_t)a->s8[i] * b->u8[i];
2334 }
2335
2336 VECTOR_FOR_INORDER_I(i, s32) {
2337 r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2338 }
2339}
2340
aurel32eae07262009-01-04 22:12:49 +00002341void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2342{
2343 int32_t prod[8];
2344 int i;
2345
2346 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2347 prod[i] = a->s16[i] * b->s16[i];
2348 }
2349
2350 VECTOR_FOR_INORDER_I(i, s32) {
2351 r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1];
2352 }
2353}
2354
2355void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2356{
2357 int32_t prod[8];
2358 int i;
2359 int sat = 0;
2360
2361 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2362 prod[i] = (int32_t)a->s16[i] * b->s16[i];
2363 }
2364
2365 VECTOR_FOR_INORDER_I (i, s32) {
2366 int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1];
2367 r->u32[i] = cvtsdsw(t, &sat);
2368 }
2369
2370 if (sat) {
2371 env->vscr |= (1 << VSCR_SAT);
2372 }
2373}
2374
aurel32b04ae982009-01-04 22:11:39 +00002375void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2376{
2377 uint16_t prod[16];
2378 int i;
2379
2380 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2381 prod[i] = a->u8[i] * b->u8[i];
2382 }
2383
2384 VECTOR_FOR_INORDER_I(i, u32) {
2385 r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2386 }
2387}
2388
aurel324d9903b2009-01-04 22:12:39 +00002389void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2390{
2391 uint32_t prod[8];
2392 int i;
2393
2394 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2395 prod[i] = a->u16[i] * b->u16[i];
2396 }
2397
2398 VECTOR_FOR_INORDER_I(i, u32) {
2399 r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1];
2400 }
2401}
2402
2403void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2404{
2405 uint32_t prod[8];
2406 int i;
2407 int sat = 0;
2408
2409 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2410 prod[i] = a->u16[i] * b->u16[i];
2411 }
2412
2413 VECTOR_FOR_INORDER_I (i, s32) {
2414 uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1];
2415 r->u32[i] = cvtuduw(t, &sat);
2416 }
2417
2418 if (sat) {
2419 env->vscr |= (1 << VSCR_SAT);
2420 }
2421}
2422
aurel322c277902009-01-04 22:08:48 +00002423#define VMUL_DO(name, mul_element, prod_element, evenp) \
2424 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2425 { \
2426 int i; \
2427 VECTOR_FOR_INORDER_I(i, prod_element) { \
2428 if (evenp) { \
2429 r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2430 } else { \
2431 r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2432 } \
2433 } \
2434 }
2435#define VMUL(suffix, mul_element, prod_element) \
2436 VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2437 VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2438VMUL(sb, s8, s16)
2439VMUL(sh, s16, s32)
2440VMUL(ub, u8, u16)
2441VMUL(uh, u16, u32)
2442#undef VMUL_DO
2443#undef VMUL
2444
aurel32d1258692009-01-04 22:11:49 +00002445void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2446{
2447 ppc_avr_t result;
2448 int i;
2449 VECTOR_FOR_INORDER_I (i, u8) {
2450 int s = c->u8[i] & 0x1f;
2451#if defined(WORDS_BIGENDIAN)
2452 int index = s & 0xf;
2453#else
2454 int index = 15 - (s & 0xf);
2455#endif
2456 if (s & 0x10) {
2457 result.u8[i] = b->u8[index];
2458 } else {
2459 result.u8[i] = a->u8[index];
2460 }
2461 }
2462 *r = result;
2463}
2464
aurel325335a142009-01-04 22:12:09 +00002465#if defined(WORDS_BIGENDIAN)
2466#define PKBIG 1
2467#else
2468#define PKBIG 0
2469#endif
aurel321dd9ffb2009-01-04 22:12:19 +00002470void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2471{
2472 int i, j;
2473 ppc_avr_t result;
2474#if defined(WORDS_BIGENDIAN)
2475 const ppc_avr_t *x[2] = { a, b };
2476#else
2477 const ppc_avr_t *x[2] = { b, a };
2478#endif
2479
2480 VECTOR_FOR_INORDER_I (i, u64) {
2481 VECTOR_FOR_INORDER_I (j, u32){
2482 uint32_t e = x[i]->u32[j];
2483 result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
2484 ((e >> 6) & 0x3e0) |
2485 ((e >> 3) & 0x1f));
2486 }
2487 }
2488 *r = result;
2489}
2490
aurel325335a142009-01-04 22:12:09 +00002491#define VPK(suffix, from, to, cvt, dosat) \
2492 void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2493 { \
2494 int i; \
2495 int sat = 0; \
2496 ppc_avr_t result; \
2497 ppc_avr_t *a0 = PKBIG ? a : b; \
2498 ppc_avr_t *a1 = PKBIG ? b : a; \
2499 VECTOR_FOR_INORDER_I (i, from) { \
2500 result.to[i] = cvt(a0->from[i], &sat); \
2501 result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
2502 } \
2503 *r = result; \
2504 if (dosat && sat) { \
2505 env->vscr |= (1 << VSCR_SAT); \
2506 } \
2507 }
2508#define I(x, y) (x)
2509VPK(shss, s16, s8, cvtshsb, 1)
2510VPK(shus, s16, u8, cvtshub, 1)
2511VPK(swss, s32, s16, cvtswsh, 1)
2512VPK(swus, s32, u16, cvtswuh, 1)
2513VPK(uhus, u16, u8, cvtuhub, 1)
2514VPK(uwus, u32, u16, cvtuwuh, 1)
2515VPK(uhum, u16, u8, I, 0)
2516VPK(uwum, u32, u16, I, 0)
2517#undef I
2518#undef VPK
2519#undef PKBIG
2520
aurel32f6b19642009-02-04 13:52:03 +00002521#define VRFI(suffix, rounding) \
2522 void helper_vrfi##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2523 { \
2524 int i; \
2525 float_status s = env->vec_status; \
2526 set_float_rounding_mode(rounding, &s); \
2527 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2528 HANDLE_NAN1(r->f[i], b->f[i]) { \
2529 r->f[i] = float32_round_to_int (b->f[i], &s); \
2530 } \
2531 } \
2532 }
2533VRFI(n, float_round_nearest_even)
2534VRFI(m, float_round_down)
2535VRFI(p, float_round_up)
2536VRFI(z, float_round_to_zero)
2537#undef VRFI
2538
aurel325e1d0982009-01-04 22:09:52 +00002539#define VROTATE(suffix, element) \
2540 void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2541 { \
2542 int i; \
2543 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2544 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2545 unsigned int shift = b->element[i] & mask; \
2546 r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2547 } \
2548 }
2549VROTATE(b, u8)
2550VROTATE(h, u16)
2551VROTATE(w, u32)
2552#undef VROTATE
2553
aurel32d1258692009-01-04 22:11:49 +00002554void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2555{
2556 r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2557 r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2558}
2559
aurel32b5807632009-02-05 22:33:36 +00002560void helper_vlogefp (ppc_avr_t *r, ppc_avr_t *b)
aurel32f586ce02009-02-05 13:42:57 +00002561{
2562 int i;
2563 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2564 HANDLE_NAN1(r->f[i], b->f[i]) {
2565 r->f[i] = float32_log2(b->f[i], &env->vec_status);
2566 }
2567 }
2568}
2569
aurel32d9430ad2009-01-08 18:54:48 +00002570#if defined(WORDS_BIGENDIAN)
2571#define LEFT 0
2572#define RIGHT 1
2573#else
2574#define LEFT 1
2575#define RIGHT 0
2576#endif
2577/* The specification says that the results are undefined if all of the
2578 * shift counts are not identical. We check to make sure that they are
2579 * to conform to what real hardware appears to do. */
2580#define VSHIFT(suffix, leftp) \
2581 void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2582 { \
2583 int shift = b->u8[LO_IDX*0x15] & 0x7; \
2584 int doit = 1; \
2585 int i; \
2586 for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
2587 doit = doit && ((b->u8[i] & 0x7) == shift); \
2588 } \
2589 if (doit) { \
2590 if (shift == 0) { \
2591 *r = *a; \
2592 } else if (leftp) { \
2593 uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \
2594 r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \
2595 r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \
2596 } else { \
2597 uint64_t carry = a->u64[HI_IDX] << (64 - shift); \
2598 r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \
2599 r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \
2600 } \
2601 } \
2602 }
2603VSHIFT(l, LEFT)
2604VSHIFT(r, RIGHT)
2605#undef VSHIFT
2606#undef LEFT
2607#undef RIGHT
2608
aurel32d79f0802009-01-04 22:09:08 +00002609#define VSL(suffix, element) \
2610 void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2611 { \
2612 int i; \
2613 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2614 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2615 unsigned int shift = b->element[i] & mask; \
2616 r->element[i] = a->element[i] << shift; \
2617 } \
2618 }
2619VSL(b, u8)
2620VSL(h, u16)
2621VSL(w, u32)
2622#undef VSL
2623
aurel32cd633b12009-01-04 22:10:09 +00002624void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
2625{
2626 int sh = shift & 0xf;
2627 int i;
2628 ppc_avr_t result;
2629
2630#if defined(WORDS_BIGENDIAN)
2631 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2632 int index = sh + i;
2633 if (index > 0xf) {
2634 result.u8[i] = b->u8[index-0x10];
2635 } else {
2636 result.u8[i] = a->u8[index];
2637 }
2638 }
2639#else
2640 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2641 int index = (16 - sh) + i;
2642 if (index > 0xf) {
2643 result.u8[i] = a->u8[index-0x10];
2644 } else {
2645 result.u8[i] = b->u8[index];
2646 }
2647 }
2648#endif
2649 *r = result;
2650}
2651
aurel327b239be2009-01-04 22:09:19 +00002652void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2653{
2654 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2655
2656#if defined (WORDS_BIGENDIAN)
2657 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2658 memset (&r->u8[16-sh], 0, sh);
2659#else
2660 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2661 memset (&r->u8[0], 0, sh);
2662#endif
2663}
2664
aurel32e4e6bee2009-01-04 22:10:49 +00002665/* Experimental testing shows that hardware masks the immediate. */
2666#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
2667#if defined(WORDS_BIGENDIAN)
2668#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2669#else
2670#define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
2671#endif
2672#define VSPLT(suffix, element) \
2673 void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
2674 { \
2675 uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
2676 int i; \
2677 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2678 r->element[i] = s; \
2679 } \
2680 }
2681VSPLT(b, u8)
2682VSPLT(h, u16)
2683VSPLT(w, u32)
2684#undef VSPLT
2685#undef SPLAT_ELEMENT
2686#undef _SPLAT_MASKED
2687
aurel32c0267662009-01-08 18:54:57 +00002688#define VSPLTI(suffix, element, splat_type) \
2689 void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat) \
2690 { \
2691 splat_type x = (int8_t)(splat << 3) >> 3; \
2692 int i; \
2693 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2694 r->element[i] = x; \
2695 } \
2696 }
2697VSPLTI(b, s8, int8_t)
2698VSPLTI(h, s16, int16_t)
2699VSPLTI(w, s32, int32_t)
2700#undef VSPLTI
2701
aurel3207ef34c2009-01-04 22:08:58 +00002702#define VSR(suffix, element) \
2703 void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2704 { \
2705 int i; \
2706 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2707 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2708 unsigned int shift = b->element[i] & mask; \
2709 r->element[i] = a->element[i] >> shift; \
2710 } \
2711 }
2712VSR(ab, s8)
2713VSR(ah, s16)
2714VSR(aw, s32)
2715VSR(b, u8)
2716VSR(h, u16)
2717VSR(w, u32)
2718#undef VSR
2719
aurel327b239be2009-01-04 22:09:19 +00002720void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2721{
2722 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2723
2724#if defined (WORDS_BIGENDIAN)
2725 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2726 memset (&r->u8[0], 0, sh);
2727#else
2728 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2729 memset (&r->u8[16-sh], 0, sh);
2730#endif
2731}
2732
aurel32e343da72009-01-04 22:09:31 +00002733void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2734{
2735 int i;
2736 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2737 r->u32[i] = a->u32[i] >= b->u32[i];
2738 }
2739}
2740
aurel328142cdd2009-01-04 22:13:21 +00002741void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2742{
2743 int64_t t;
2744 int i, upper;
2745 ppc_avr_t result;
2746 int sat = 0;
2747
2748#if defined(WORDS_BIGENDIAN)
2749 upper = ARRAY_SIZE(r->s32)-1;
2750#else
2751 upper = 0;
2752#endif
2753 t = (int64_t)b->s32[upper];
2754 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2755 t += a->s32[i];
2756 result.s32[i] = 0;
2757 }
2758 result.s32[upper] = cvtsdsw(t, &sat);
2759 *r = result;
2760
2761 if (sat) {
2762 env->vscr |= (1 << VSCR_SAT);
2763 }
2764}
2765
2766void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2767{
2768 int i, j, upper;
2769 ppc_avr_t result;
2770 int sat = 0;
2771
2772#if defined(WORDS_BIGENDIAN)
2773 upper = 1;
2774#else
2775 upper = 0;
2776#endif
2777 for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
2778 int64_t t = (int64_t)b->s32[upper+i*2];
2779 result.u64[i] = 0;
2780 for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
2781 t += a->s32[2*i+j];
2782 }
2783 result.s32[upper+i*2] = cvtsdsw(t, &sat);
2784 }
2785
2786 *r = result;
2787 if (sat) {
2788 env->vscr |= (1 << VSCR_SAT);
2789 }
2790}
2791
2792void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2793{
2794 int i, j;
2795 int sat = 0;
2796
2797 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2798 int64_t t = (int64_t)b->s32[i];
2799 for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
2800 t += a->s8[4*i+j];
2801 }
2802 r->s32[i] = cvtsdsw(t, &sat);
2803 }
2804
2805 if (sat) {
2806 env->vscr |= (1 << VSCR_SAT);
2807 }
2808}
2809
2810void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2811{
2812 int sat = 0;
2813 int i;
2814
2815 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2816 int64_t t = (int64_t)b->s32[i];
2817 t += a->s16[2*i] + a->s16[2*i+1];
2818 r->s32[i] = cvtsdsw(t, &sat);
2819 }
2820
2821 if (sat) {
2822 env->vscr |= (1 << VSCR_SAT);
2823 }
2824}
2825
2826void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2827{
2828 int i, j;
2829 int sat = 0;
2830
2831 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2832 uint64_t t = (uint64_t)b->u32[i];
2833 for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
2834 t += a->u8[4*i+j];
2835 }
2836 r->u32[i] = cvtuduw(t, &sat);
2837 }
2838
2839 if (sat) {
2840 env->vscr |= (1 << VSCR_SAT);
2841 }
2842}
2843
aurel3279f85c32009-01-04 22:11:10 +00002844#if defined(WORDS_BIGENDIAN)
2845#define UPKHI 1
2846#define UPKLO 0
2847#else
2848#define UPKHI 0
2849#define UPKLO 1
2850#endif
2851#define VUPKPX(suffix, hi) \
2852 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2853 { \
2854 int i; \
2855 ppc_avr_t result; \
2856 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
2857 uint16_t e = b->u16[hi ? i : i+4]; \
2858 uint8_t a = (e >> 15) ? 0xff : 0; \
2859 uint8_t r = (e >> 10) & 0x1f; \
2860 uint8_t g = (e >> 5) & 0x1f; \
2861 uint8_t b = e & 0x1f; \
2862 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
2863 } \
2864 *r = result; \
2865 }
2866VUPKPX(lpx, UPKLO)
2867VUPKPX(hpx, UPKHI)
2868#undef VUPKPX
2869
aurel326cf1c6e2009-01-04 22:11:20 +00002870#define VUPK(suffix, unpacked, packee, hi) \
2871 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2872 { \
2873 int i; \
2874 ppc_avr_t result; \
2875 if (hi) { \
2876 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
2877 result.unpacked[i] = b->packee[i]; \
2878 } \
2879 } else { \
2880 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
2881 result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
2882 } \
2883 } \
2884 *r = result; \
2885 }
2886VUPK(hsb, s16, s8, UPKHI)
2887VUPK(hsh, s32, s16, UPKHI)
2888VUPK(lsb, s16, s8, UPKLO)
2889VUPK(lsh, s32, s16, UPKLO)
2890#undef VUPK
aurel3279f85c32009-01-04 22:11:10 +00002891#undef UPKHI
2892#undef UPKLO
2893
aurel3234ba2852009-02-04 09:05:53 +00002894#undef DO_HANDLE_NAN
2895#undef HANDLE_NAN1
2896#undef HANDLE_NAN2
2897#undef HANDLE_NAN3
aurel32d6a46fe2009-01-03 13:31:19 +00002898#undef VECTOR_FOR_INORDER_I
2899#undef HI_IDX
2900#undef LO_IDX
2901
2902/*****************************************************************************/
j_mayer0487d6a2007-03-20 22:11:31 +00002903/* SPE extension helpers */
2904/* Use a table to make this quicker */
2905static uint8_t hbrev[16] = {
2906 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
2907 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
2908};
2909
j_mayerb068d6a2007-10-07 17:13:44 +00002910static always_inline uint8_t byte_reverse (uint8_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002911{
2912 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
2913}
2914
j_mayerb068d6a2007-10-07 17:13:44 +00002915static always_inline uint32_t word_reverse (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002916{
2917 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
2918 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
2919}
2920
j_mayer3cd7d1d2007-11-12 01:56:18 +00002921#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
aurel3257951c22008-11-10 11:10:23 +00002922target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
j_mayer0487d6a2007-03-20 22:11:31 +00002923{
2924 uint32_t a, b, d, mask;
2925
j_mayer3cd7d1d2007-11-12 01:56:18 +00002926 mask = UINT32_MAX >> (32 - MASKBITS);
aurel3257951c22008-11-10 11:10:23 +00002927 a = arg1 & mask;
2928 b = arg2 & mask;
j_mayer3cd7d1d2007-11-12 01:56:18 +00002929 d = word_reverse(1 + word_reverse(a | ~b));
aurel3257951c22008-11-10 11:10:23 +00002930 return (arg1 & ~mask) | (d & b);
j_mayer0487d6a2007-03-20 22:11:31 +00002931}
2932
aurel3257951c22008-11-10 11:10:23 +00002933uint32_t helper_cntlsw32 (uint32_t val)
2934{
2935 if (val & 0x80000000)
2936 return clz32(~val);
2937 else
2938 return clz32(val);
2939}
2940
2941uint32_t helper_cntlzw32 (uint32_t val)
2942{
2943 return clz32(val);
j_mayer0487d6a2007-03-20 22:11:31 +00002944}
2945
aurel321c978562008-11-23 10:54:04 +00002946/* Single-precision floating-point conversions */
2947static always_inline uint32_t efscfsi (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002948{
aurel320ca9d382008-03-13 19:19:16 +00002949 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002950
aurel32fbd265b2009-02-03 19:55:51 +00002951 u.f = int32_to_float32(val, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002952
aurel320ca9d382008-03-13 19:19:16 +00002953 return u.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002954}
2955
aurel321c978562008-11-23 10:54:04 +00002956static always_inline uint32_t efscfui (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002957{
aurel320ca9d382008-03-13 19:19:16 +00002958 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002959
aurel32fbd265b2009-02-03 19:55:51 +00002960 u.f = uint32_to_float32(val, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002961
aurel320ca9d382008-03-13 19:19:16 +00002962 return u.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002963}
2964
aurel321c978562008-11-23 10:54:04 +00002965static always_inline int32_t efsctsi (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002966{
aurel320ca9d382008-03-13 19:19:16 +00002967 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002968
aurel320ca9d382008-03-13 19:19:16 +00002969 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002970 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002971 if (unlikely(float32_is_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00002972 return 0;
2973
aurel32fbd265b2009-02-03 19:55:51 +00002974 return float32_to_int32(u.f, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002975}
2976
aurel321c978562008-11-23 10:54:04 +00002977static always_inline uint32_t efsctui (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002978{
aurel320ca9d382008-03-13 19:19:16 +00002979 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002980
aurel320ca9d382008-03-13 19:19:16 +00002981 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002982 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002983 if (unlikely(float32_is_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00002984 return 0;
2985
aurel32fbd265b2009-02-03 19:55:51 +00002986 return float32_to_uint32(u.f, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002987}
2988
aurel321c978562008-11-23 10:54:04 +00002989static always_inline uint32_t efsctsiz (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002990{
aurel320ca9d382008-03-13 19:19:16 +00002991 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002992
aurel320ca9d382008-03-13 19:19:16 +00002993 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002994 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002995 if (unlikely(float32_is_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00002996 return 0;
2997
aurel32fbd265b2009-02-03 19:55:51 +00002998 return float32_to_int32_round_to_zero(u.f, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002999}
3000
aurel321c978562008-11-23 10:54:04 +00003001static always_inline uint32_t efsctuiz (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003002{
aurel320ca9d382008-03-13 19:19:16 +00003003 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003004
aurel320ca9d382008-03-13 19:19:16 +00003005 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003006 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00003007 if (unlikely(float32_is_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00003008 return 0;
3009
aurel32fbd265b2009-02-03 19:55:51 +00003010 return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003011}
3012
aurel321c978562008-11-23 10:54:04 +00003013static always_inline uint32_t efscfsf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003014{
aurel320ca9d382008-03-13 19:19:16 +00003015 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003016 float32 tmp;
3017
aurel32fbd265b2009-02-03 19:55:51 +00003018 u.f = int32_to_float32(val, &env->vec_status);
3019 tmp = int64_to_float32(1ULL << 32, &env->vec_status);
3020 u.f = float32_div(u.f, tmp, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003021
aurel320ca9d382008-03-13 19:19:16 +00003022 return u.l;
j_mayer0487d6a2007-03-20 22:11:31 +00003023}
3024
aurel321c978562008-11-23 10:54:04 +00003025static always_inline uint32_t efscfuf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003026{
aurel320ca9d382008-03-13 19:19:16 +00003027 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003028 float32 tmp;
3029
aurel32fbd265b2009-02-03 19:55:51 +00003030 u.f = uint32_to_float32(val, &env->vec_status);
3031 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3032 u.f = float32_div(u.f, tmp, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003033
aurel320ca9d382008-03-13 19:19:16 +00003034 return u.l;
j_mayer0487d6a2007-03-20 22:11:31 +00003035}
3036
aurel321c978562008-11-23 10:54:04 +00003037static always_inline uint32_t efsctsf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003038{
aurel320ca9d382008-03-13 19:19:16 +00003039 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003040 float32 tmp;
3041
aurel320ca9d382008-03-13 19:19:16 +00003042 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003043 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00003044 if (unlikely(float32_is_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00003045 return 0;
aurel32fbd265b2009-02-03 19:55:51 +00003046 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3047 u.f = float32_mul(u.f, tmp, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003048
aurel32fbd265b2009-02-03 19:55:51 +00003049 return float32_to_int32(u.f, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003050}
3051
aurel321c978562008-11-23 10:54:04 +00003052static always_inline uint32_t efsctuf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003053{
aurel320ca9d382008-03-13 19:19:16 +00003054 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003055 float32 tmp;
3056
aurel320ca9d382008-03-13 19:19:16 +00003057 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003058 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00003059 if (unlikely(float32_is_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00003060 return 0;
aurel32fbd265b2009-02-03 19:55:51 +00003061 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3062 u.f = float32_mul(u.f, tmp, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003063
aurel32fbd265b2009-02-03 19:55:51 +00003064 return float32_to_uint32(u.f, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003065}
3066
aurel321c978562008-11-23 10:54:04 +00003067#define HELPER_SPE_SINGLE_CONV(name) \
3068uint32_t helper_e##name (uint32_t val) \
3069{ \
3070 return e##name(val); \
3071}
3072/* efscfsi */
3073HELPER_SPE_SINGLE_CONV(fscfsi);
3074/* efscfui */
3075HELPER_SPE_SINGLE_CONV(fscfui);
3076/* efscfuf */
3077HELPER_SPE_SINGLE_CONV(fscfuf);
3078/* efscfsf */
3079HELPER_SPE_SINGLE_CONV(fscfsf);
3080/* efsctsi */
3081HELPER_SPE_SINGLE_CONV(fsctsi);
3082/* efsctui */
3083HELPER_SPE_SINGLE_CONV(fsctui);
3084/* efsctsiz */
3085HELPER_SPE_SINGLE_CONV(fsctsiz);
3086/* efsctuiz */
3087HELPER_SPE_SINGLE_CONV(fsctuiz);
3088/* efsctsf */
3089HELPER_SPE_SINGLE_CONV(fsctsf);
3090/* efsctuf */
3091HELPER_SPE_SINGLE_CONV(fsctuf);
3092
3093#define HELPER_SPE_VECTOR_CONV(name) \
3094uint64_t helper_ev##name (uint64_t val) \
3095{ \
3096 return ((uint64_t)e##name(val >> 32) << 32) | \
3097 (uint64_t)e##name(val); \
3098}
3099/* evfscfsi */
3100HELPER_SPE_VECTOR_CONV(fscfsi);
3101/* evfscfui */
3102HELPER_SPE_VECTOR_CONV(fscfui);
3103/* evfscfuf */
3104HELPER_SPE_VECTOR_CONV(fscfuf);
3105/* evfscfsf */
3106HELPER_SPE_VECTOR_CONV(fscfsf);
3107/* evfsctsi */
3108HELPER_SPE_VECTOR_CONV(fsctsi);
3109/* evfsctui */
3110HELPER_SPE_VECTOR_CONV(fsctui);
3111/* evfsctsiz */
3112HELPER_SPE_VECTOR_CONV(fsctsiz);
3113/* evfsctuiz */
3114HELPER_SPE_VECTOR_CONV(fsctuiz);
3115/* evfsctsf */
3116HELPER_SPE_VECTOR_CONV(fsctsf);
3117/* evfsctuf */
3118HELPER_SPE_VECTOR_CONV(fsctuf);
3119
3120/* Single-precision floating-point arithmetic */
3121static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003122{
aurel321c978562008-11-23 10:54:04 +00003123 CPU_FloatU u1, u2;
3124 u1.l = op1;
3125 u2.l = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003126 u1.f = float32_add(u1.f, u2.f, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003127 return u1.l;
j_mayer0487d6a2007-03-20 22:11:31 +00003128}
3129
aurel321c978562008-11-23 10:54:04 +00003130static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003131{
aurel321c978562008-11-23 10:54:04 +00003132 CPU_FloatU u1, u2;
3133 u1.l = op1;
3134 u2.l = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003135 u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003136 return u1.l;
j_mayer0487d6a2007-03-20 22:11:31 +00003137}
3138
aurel321c978562008-11-23 10:54:04 +00003139static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003140{
aurel321c978562008-11-23 10:54:04 +00003141 CPU_FloatU u1, u2;
3142 u1.l = op1;
3143 u2.l = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003144 u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003145 return u1.l;
j_mayer0487d6a2007-03-20 22:11:31 +00003146}
3147
aurel321c978562008-11-23 10:54:04 +00003148static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003149{
aurel321c978562008-11-23 10:54:04 +00003150 CPU_FloatU u1, u2;
3151 u1.l = op1;
3152 u2.l = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003153 u1.f = float32_div(u1.f, u2.f, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003154 return u1.l;
j_mayer0487d6a2007-03-20 22:11:31 +00003155}
3156
aurel321c978562008-11-23 10:54:04 +00003157#define HELPER_SPE_SINGLE_ARITH(name) \
3158uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
3159{ \
3160 return e##name(op1, op2); \
3161}
3162/* efsadd */
3163HELPER_SPE_SINGLE_ARITH(fsadd);
3164/* efssub */
3165HELPER_SPE_SINGLE_ARITH(fssub);
3166/* efsmul */
3167HELPER_SPE_SINGLE_ARITH(fsmul);
3168/* efsdiv */
3169HELPER_SPE_SINGLE_ARITH(fsdiv);
3170
3171#define HELPER_SPE_VECTOR_ARITH(name) \
3172uint64_t helper_ev##name (uint64_t op1, uint64_t op2) \
3173{ \
3174 return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
3175 (uint64_t)e##name(op1, op2); \
3176}
3177/* evfsadd */
3178HELPER_SPE_VECTOR_ARITH(fsadd);
3179/* evfssub */
3180HELPER_SPE_VECTOR_ARITH(fssub);
3181/* evfsmul */
3182HELPER_SPE_VECTOR_ARITH(fsmul);
3183/* evfsdiv */
3184HELPER_SPE_VECTOR_ARITH(fsdiv);
3185
3186/* Single-precision floating-point comparisons */
3187static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003188{
aurel321c978562008-11-23 10:54:04 +00003189 CPU_FloatU u1, u2;
3190 u1.l = op1;
3191 u2.l = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003192 return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
j_mayer0487d6a2007-03-20 22:11:31 +00003193}
3194
aurel321c978562008-11-23 10:54:04 +00003195static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003196{
aurel321c978562008-11-23 10:54:04 +00003197 CPU_FloatU u1, u2;
3198 u1.l = op1;
3199 u2.l = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003200 return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
j_mayer0487d6a2007-03-20 22:11:31 +00003201}
3202
aurel321c978562008-11-23 10:54:04 +00003203static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003204{
aurel321c978562008-11-23 10:54:04 +00003205 CPU_FloatU u1, u2;
3206 u1.l = op1;
3207 u2.l = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003208 return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
j_mayer0487d6a2007-03-20 22:11:31 +00003209}
3210
aurel321c978562008-11-23 10:54:04 +00003211static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003212{
3213 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00003214 return efststlt(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00003215}
3216
aurel321c978562008-11-23 10:54:04 +00003217static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003218{
3219 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00003220 return efststgt(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00003221}
3222
aurel321c978562008-11-23 10:54:04 +00003223static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003224{
3225 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00003226 return efststeq(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00003227}
3228
aurel321c978562008-11-23 10:54:04 +00003229#define HELPER_SINGLE_SPE_CMP(name) \
3230uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
3231{ \
3232 return e##name(op1, op2) << 2; \
3233}
3234/* efststlt */
3235HELPER_SINGLE_SPE_CMP(fststlt);
3236/* efststgt */
3237HELPER_SINGLE_SPE_CMP(fststgt);
3238/* efststeq */
3239HELPER_SINGLE_SPE_CMP(fststeq);
3240/* efscmplt */
3241HELPER_SINGLE_SPE_CMP(fscmplt);
3242/* efscmpgt */
3243HELPER_SINGLE_SPE_CMP(fscmpgt);
3244/* efscmpeq */
3245HELPER_SINGLE_SPE_CMP(fscmpeq);
3246
3247static always_inline uint32_t evcmp_merge (int t0, int t1)
j_mayer0487d6a2007-03-20 22:11:31 +00003248{
aurel321c978562008-11-23 10:54:04 +00003249 return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
j_mayer0487d6a2007-03-20 22:11:31 +00003250}
3251
aurel321c978562008-11-23 10:54:04 +00003252#define HELPER_VECTOR_SPE_CMP(name) \
3253uint32_t helper_ev##name (uint64_t op1, uint64_t op2) \
3254{ \
3255 return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
3256}
3257/* evfststlt */
3258HELPER_VECTOR_SPE_CMP(fststlt);
3259/* evfststgt */
3260HELPER_VECTOR_SPE_CMP(fststgt);
3261/* evfststeq */
3262HELPER_VECTOR_SPE_CMP(fststeq);
3263/* evfscmplt */
3264HELPER_VECTOR_SPE_CMP(fscmplt);
3265/* evfscmpgt */
3266HELPER_VECTOR_SPE_CMP(fscmpgt);
3267/* evfscmpeq */
3268HELPER_VECTOR_SPE_CMP(fscmpeq);
3269
3270/* Double-precision floating-point conversion */
3271uint64_t helper_efdcfsi (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003272{
aurel321c978562008-11-23 10:54:04 +00003273 CPU_DoubleU u;
3274
aurel32fbd265b2009-02-03 19:55:51 +00003275 u.d = int32_to_float64(val, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003276
3277 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00003278}
3279
aurel321c978562008-11-23 10:54:04 +00003280uint64_t helper_efdcfsid (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003281{
aurel320ca9d382008-03-13 19:19:16 +00003282 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003283
aurel32fbd265b2009-02-03 19:55:51 +00003284 u.d = int64_to_float64(val, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003285
aurel320ca9d382008-03-13 19:19:16 +00003286 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00003287}
3288
aurel321c978562008-11-23 10:54:04 +00003289uint64_t helper_efdcfui (uint32_t val)
3290{
3291 CPU_DoubleU u;
3292
aurel32fbd265b2009-02-03 19:55:51 +00003293 u.d = uint32_to_float64(val, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003294
3295 return u.ll;
3296}
3297
3298uint64_t helper_efdcfuid (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003299{
aurel320ca9d382008-03-13 19:19:16 +00003300 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003301
aurel32fbd265b2009-02-03 19:55:51 +00003302 u.d = uint64_to_float64(val, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003303
aurel320ca9d382008-03-13 19:19:16 +00003304 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00003305}
3306
aurel321c978562008-11-23 10:54:04 +00003307uint32_t helper_efdctsi (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003308{
aurel320ca9d382008-03-13 19:19:16 +00003309 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003310
aurel320ca9d382008-03-13 19:19:16 +00003311 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003312 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00003313 if (unlikely(float64_is_nan(u.d)))
j_mayer0487d6a2007-03-20 22:11:31 +00003314 return 0;
3315
aurel32fbd265b2009-02-03 19:55:51 +00003316 return float64_to_int32(u.d, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003317}
3318
aurel321c978562008-11-23 10:54:04 +00003319uint32_t helper_efdctui (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003320{
aurel320ca9d382008-03-13 19:19:16 +00003321 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003322
aurel320ca9d382008-03-13 19:19:16 +00003323 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003324 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00003325 if (unlikely(float64_is_nan(u.d)))
j_mayer0487d6a2007-03-20 22:11:31 +00003326 return 0;
3327
aurel32fbd265b2009-02-03 19:55:51 +00003328 return float64_to_uint32(u.d, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003329}
3330
aurel321c978562008-11-23 10:54:04 +00003331uint32_t helper_efdctsiz (uint64_t val)
3332{
3333 CPU_DoubleU u;
3334
3335 u.ll = val;
3336 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00003337 if (unlikely(float64_is_nan(u.d)))
aurel321c978562008-11-23 10:54:04 +00003338 return 0;
3339
aurel32fbd265b2009-02-03 19:55:51 +00003340 return float64_to_int32_round_to_zero(u.d, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003341}
3342
3343uint64_t helper_efdctsidz (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003344{
aurel320ca9d382008-03-13 19:19:16 +00003345 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003346
aurel320ca9d382008-03-13 19:19:16 +00003347 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003348 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00003349 if (unlikely(float64_is_nan(u.d)))
j_mayer0487d6a2007-03-20 22:11:31 +00003350 return 0;
3351
aurel32fbd265b2009-02-03 19:55:51 +00003352 return float64_to_int64_round_to_zero(u.d, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003353}
3354
aurel321c978562008-11-23 10:54:04 +00003355uint32_t helper_efdctuiz (uint64_t val)
3356{
3357 CPU_DoubleU u;
3358
3359 u.ll = val;
3360 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00003361 if (unlikely(float64_is_nan(u.d)))
aurel321c978562008-11-23 10:54:04 +00003362 return 0;
3363
aurel32fbd265b2009-02-03 19:55:51 +00003364 return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003365}
3366
3367uint64_t helper_efdctuidz (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003368{
aurel320ca9d382008-03-13 19:19:16 +00003369 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003370
aurel320ca9d382008-03-13 19:19:16 +00003371 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003372 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00003373 if (unlikely(float64_is_nan(u.d)))
j_mayer0487d6a2007-03-20 22:11:31 +00003374 return 0;
3375
aurel32fbd265b2009-02-03 19:55:51 +00003376 return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003377}
3378
aurel321c978562008-11-23 10:54:04 +00003379uint64_t helper_efdcfsf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003380{
aurel320ca9d382008-03-13 19:19:16 +00003381 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003382 float64 tmp;
3383
aurel32fbd265b2009-02-03 19:55:51 +00003384 u.d = int32_to_float64(val, &env->vec_status);
3385 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3386 u.d = float64_div(u.d, tmp, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003387
aurel320ca9d382008-03-13 19:19:16 +00003388 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00003389}
3390
aurel321c978562008-11-23 10:54:04 +00003391uint64_t helper_efdcfuf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003392{
aurel320ca9d382008-03-13 19:19:16 +00003393 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003394 float64 tmp;
3395
aurel32fbd265b2009-02-03 19:55:51 +00003396 u.d = uint32_to_float64(val, &env->vec_status);
3397 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3398 u.d = float64_div(u.d, tmp, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003399
aurel320ca9d382008-03-13 19:19:16 +00003400 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00003401}
3402
aurel321c978562008-11-23 10:54:04 +00003403uint32_t helper_efdctsf (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003404{
aurel320ca9d382008-03-13 19:19:16 +00003405 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003406 float64 tmp;
3407
aurel320ca9d382008-03-13 19:19:16 +00003408 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003409 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00003410 if (unlikely(float64_is_nan(u.d)))
j_mayer0487d6a2007-03-20 22:11:31 +00003411 return 0;
aurel32fbd265b2009-02-03 19:55:51 +00003412 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3413 u.d = float64_mul(u.d, tmp, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003414
aurel32fbd265b2009-02-03 19:55:51 +00003415 return float64_to_int32(u.d, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003416}
3417
aurel321c978562008-11-23 10:54:04 +00003418uint32_t helper_efdctuf (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003419{
aurel320ca9d382008-03-13 19:19:16 +00003420 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003421 float64 tmp;
3422
aurel320ca9d382008-03-13 19:19:16 +00003423 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003424 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00003425 if (unlikely(float64_is_nan(u.d)))
j_mayer0487d6a2007-03-20 22:11:31 +00003426 return 0;
aurel32fbd265b2009-02-03 19:55:51 +00003427 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3428 u.d = float64_mul(u.d, tmp, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003429
aurel32fbd265b2009-02-03 19:55:51 +00003430 return float64_to_uint32(u.d, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003431}
3432
aurel321c978562008-11-23 10:54:04 +00003433uint32_t helper_efscfd (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003434{
aurel320ca9d382008-03-13 19:19:16 +00003435 CPU_DoubleU u1;
3436 CPU_FloatU u2;
j_mayer0487d6a2007-03-20 22:11:31 +00003437
aurel320ca9d382008-03-13 19:19:16 +00003438 u1.ll = val;
aurel32fbd265b2009-02-03 19:55:51 +00003439 u2.f = float64_to_float32(u1.d, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003440
aurel320ca9d382008-03-13 19:19:16 +00003441 return u2.l;
j_mayer0487d6a2007-03-20 22:11:31 +00003442}
3443
aurel321c978562008-11-23 10:54:04 +00003444uint64_t helper_efdcfs (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003445{
aurel320ca9d382008-03-13 19:19:16 +00003446 CPU_DoubleU u2;
3447 CPU_FloatU u1;
j_mayer0487d6a2007-03-20 22:11:31 +00003448
aurel320ca9d382008-03-13 19:19:16 +00003449 u1.l = val;
aurel32fbd265b2009-02-03 19:55:51 +00003450 u2.d = float32_to_float64(u1.f, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003451
aurel320ca9d382008-03-13 19:19:16 +00003452 return u2.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00003453}
3454
aurel321c978562008-11-23 10:54:04 +00003455/* Double precision fixed-point arithmetic */
3456uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003457{
aurel321c978562008-11-23 10:54:04 +00003458 CPU_DoubleU u1, u2;
3459 u1.ll = op1;
3460 u2.ll = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003461 u1.d = float64_add(u1.d, u2.d, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003462 return u1.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00003463}
3464
aurel321c978562008-11-23 10:54:04 +00003465uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003466{
aurel321c978562008-11-23 10:54:04 +00003467 CPU_DoubleU u1, u2;
3468 u1.ll = op1;
3469 u2.ll = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003470 u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003471 return u1.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00003472}
3473
aurel321c978562008-11-23 10:54:04 +00003474uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
3475{
3476 CPU_DoubleU u1, u2;
3477 u1.ll = op1;
3478 u2.ll = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003479 u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003480 return u1.ll;
3481}
j_mayer0487d6a2007-03-20 22:11:31 +00003482
aurel321c978562008-11-23 10:54:04 +00003483uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
3484{
3485 CPU_DoubleU u1, u2;
3486 u1.ll = op1;
3487 u2.ll = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003488 u1.d = float64_div(u1.d, u2.d, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003489 return u1.ll;
3490}
3491
3492/* Double precision floating point helpers */
3493uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
3494{
3495 CPU_DoubleU u1, u2;
3496 u1.ll = op1;
3497 u2.ll = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003498 return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
aurel321c978562008-11-23 10:54:04 +00003499}
3500
3501uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
3502{
3503 CPU_DoubleU u1, u2;
3504 u1.ll = op1;
3505 u2.ll = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003506 return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
aurel321c978562008-11-23 10:54:04 +00003507}
3508
3509uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
3510{
3511 CPU_DoubleU u1, u2;
3512 u1.ll = op1;
3513 u2.ll = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003514 return float64_eq(u1.d, u2.d, &env->vec_status) ? 4 : 0;
aurel321c978562008-11-23 10:54:04 +00003515}
3516
3517uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003518{
3519 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00003520 return helper_efdtstlt(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00003521}
3522
aurel321c978562008-11-23 10:54:04 +00003523uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003524{
3525 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00003526 return helper_efdtstgt(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00003527}
3528
aurel321c978562008-11-23 10:54:04 +00003529uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003530{
3531 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00003532 return helper_efdtsteq(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00003533}
3534
bellardfdabc362005-07-04 22:17:05 +00003535/*****************************************************************************/
3536/* Softmmu support */
3537#if !defined (CONFIG_USER_ONLY)
3538
3539#define MMUSUFFIX _mmu
bellardfdabc362005-07-04 22:17:05 +00003540
3541#define SHIFT 0
3542#include "softmmu_template.h"
3543
3544#define SHIFT 1
3545#include "softmmu_template.h"
3546
3547#define SHIFT 2
3548#include "softmmu_template.h"
3549
3550#define SHIFT 3
3551#include "softmmu_template.h"
3552
3553/* try to fill the TLB and return an exception if error. If retaddr is
3554 NULL, it means that the function was called in C code (i.e. not
3555 from generated code or from helper.c) */
3556/* XXX: fix it to restore all registers */
j_mayer6ebbf392007-10-14 07:07:08 +00003557void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
bellardfdabc362005-07-04 22:17:05 +00003558{
3559 TranslationBlock *tb;
3560 CPUState *saved_env;
bellard44f86252007-11-11 12:35:55 +00003561 unsigned long pc;
bellardfdabc362005-07-04 22:17:05 +00003562 int ret;
3563
3564 /* XXX: hack to restore env in all cases, even if not called from
3565 generated code */
3566 saved_env = env;
3567 env = cpu_single_env;
j_mayer6ebbf392007-10-14 07:07:08 +00003568 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
j_mayer76a66252007-03-07 08:32:30 +00003569 if (unlikely(ret != 0)) {
bellardfdabc362005-07-04 22:17:05 +00003570 if (likely(retaddr)) {
3571 /* now we have a real cpu fault */
bellard44f86252007-11-11 12:35:55 +00003572 pc = (unsigned long)retaddr;
bellardfdabc362005-07-04 22:17:05 +00003573 tb = tb_find_pc(pc);
3574 if (likely(tb)) {
3575 /* the PC is inside the translated code. It means that we have
3576 a virtual CPU fault */
3577 cpu_restore_state(tb, env, pc, NULL);
j_mayer76a66252007-03-07 08:32:30 +00003578 }
bellardfdabc362005-07-04 22:17:05 +00003579 }
aurel32e06fcd72008-12-11 22:42:14 +00003580 helper_raise_exception_err(env->exception_index, env->error_code);
bellardfdabc362005-07-04 22:17:05 +00003581 }
3582 env = saved_env;
3583}
bellardfdabc362005-07-04 22:17:05 +00003584
aurel3274d37792008-12-06 21:46:17 +00003585/* Segment registers load and store */
3586target_ulong helper_load_sr (target_ulong sr_num)
3587{
3588 return env->sr[sr_num];
3589}
3590
3591void helper_store_sr (target_ulong sr_num, target_ulong val)
3592{
aurel3245d827d2008-12-07 13:40:29 +00003593 ppc_store_sr(env, sr_num, val);
aurel3274d37792008-12-06 21:46:17 +00003594}
3595
3596/* SLB management */
3597#if defined(TARGET_PPC64)
3598target_ulong helper_load_slb (target_ulong slb_nr)
3599{
3600 return ppc_load_slb(env, slb_nr);
3601}
3602
3603void helper_store_slb (target_ulong slb_nr, target_ulong rs)
3604{
3605 ppc_store_slb(env, slb_nr, rs);
3606}
3607
3608void helper_slbia (void)
3609{
3610 ppc_slb_invalidate_all(env);
3611}
3612
3613void helper_slbie (target_ulong addr)
3614{
3615 ppc_slb_invalidate_one(env, addr);
3616}
3617
3618#endif /* defined(TARGET_PPC64) */
3619
3620/* TLB management */
3621void helper_tlbia (void)
3622{
3623 ppc_tlb_invalidate_all(env);
3624}
3625
3626void helper_tlbie (target_ulong addr)
3627{
3628 ppc_tlb_invalidate_one(env, addr);
3629}
3630
j_mayer76a66252007-03-07 08:32:30 +00003631/* Software driven TLBs management */
3632/* PowerPC 602/603 software TLB load instructions helpers */
aurel3274d37792008-12-06 21:46:17 +00003633static void do_6xx_tlb (target_ulong new_EPN, int is_code)
j_mayer76a66252007-03-07 08:32:30 +00003634{
3635 target_ulong RPN, CMP, EPN;
3636 int way;
j_mayerd9bce9d2007-03-17 14:02:15 +00003637
j_mayer76a66252007-03-07 08:32:30 +00003638 RPN = env->spr[SPR_RPA];
3639 if (is_code) {
3640 CMP = env->spr[SPR_ICMP];
3641 EPN = env->spr[SPR_IMISS];
3642 } else {
3643 CMP = env->spr[SPR_DCMP];
3644 EPN = env->spr[SPR_DMISS];
3645 }
3646 way = (env->spr[SPR_SRR1] >> 17) & 1;
aliguorid12d51d2009-01-15 21:48:06 +00003647 LOG_SWTLB("%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
j_mayer6b542af2007-11-24 02:03:55 +00003648 " PTE1 " ADDRX " way %d\n",
aurel320e698052008-12-08 18:11:42 +00003649 __func__, new_EPN, EPN, CMP, RPN, way);
j_mayer76a66252007-03-07 08:32:30 +00003650 /* Store this TLB */
aurel320f3955e2008-11-30 16:22:56 +00003651 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
j_mayerd9bce9d2007-03-17 14:02:15 +00003652 way, is_code, CMP, RPN);
j_mayer76a66252007-03-07 08:32:30 +00003653}
3654
aurel3274d37792008-12-06 21:46:17 +00003655void helper_6xx_tlbd (target_ulong EPN)
aurel320f3955e2008-11-30 16:22:56 +00003656{
aurel3274d37792008-12-06 21:46:17 +00003657 do_6xx_tlb(EPN, 0);
aurel320f3955e2008-11-30 16:22:56 +00003658}
3659
aurel3274d37792008-12-06 21:46:17 +00003660void helper_6xx_tlbi (target_ulong EPN)
aurel320f3955e2008-11-30 16:22:56 +00003661{
aurel3274d37792008-12-06 21:46:17 +00003662 do_6xx_tlb(EPN, 1);
aurel320f3955e2008-11-30 16:22:56 +00003663}
3664
3665/* PowerPC 74xx software TLB load instructions helpers */
aurel3274d37792008-12-06 21:46:17 +00003666static void do_74xx_tlb (target_ulong new_EPN, int is_code)
j_mayer7dbe11a2007-10-01 05:16:57 +00003667{
3668 target_ulong RPN, CMP, EPN;
3669 int way;
3670
3671 RPN = env->spr[SPR_PTELO];
3672 CMP = env->spr[SPR_PTEHI];
3673 EPN = env->spr[SPR_TLBMISS] & ~0x3;
3674 way = env->spr[SPR_TLBMISS] & 0x3;
aliguorid12d51d2009-01-15 21:48:06 +00003675 LOG_SWTLB("%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
j_mayer6b542af2007-11-24 02:03:55 +00003676 " PTE1 " ADDRX " way %d\n",
aurel320e698052008-12-08 18:11:42 +00003677 __func__, new_EPN, EPN, CMP, RPN, way);
j_mayer7dbe11a2007-10-01 05:16:57 +00003678 /* Store this TLB */
aurel320f3955e2008-11-30 16:22:56 +00003679 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
j_mayer7dbe11a2007-10-01 05:16:57 +00003680 way, is_code, CMP, RPN);
3681}
3682
aurel3274d37792008-12-06 21:46:17 +00003683void helper_74xx_tlbd (target_ulong EPN)
aurel320f3955e2008-11-30 16:22:56 +00003684{
aurel3274d37792008-12-06 21:46:17 +00003685 do_74xx_tlb(EPN, 0);
aurel320f3955e2008-11-30 16:22:56 +00003686}
3687
aurel3274d37792008-12-06 21:46:17 +00003688void helper_74xx_tlbi (target_ulong EPN)
aurel320f3955e2008-11-30 16:22:56 +00003689{
aurel3274d37792008-12-06 21:46:17 +00003690 do_74xx_tlb(EPN, 1);
aurel320f3955e2008-11-30 16:22:56 +00003691}
3692
j_mayera11b8152007-10-28 00:55:05 +00003693static always_inline target_ulong booke_tlb_to_page_size (int size)
j_mayera8dea122007-03-31 11:33:48 +00003694{
3695 return 1024 << (2 * size);
3696}
3697
j_mayera11b8152007-10-28 00:55:05 +00003698static always_inline int booke_page_size_to_tlb (target_ulong page_size)
j_mayera8dea122007-03-31 11:33:48 +00003699{
3700 int size;
3701
3702 switch (page_size) {
3703 case 0x00000400UL:
3704 size = 0x0;
3705 break;
3706 case 0x00001000UL:
3707 size = 0x1;
3708 break;
3709 case 0x00004000UL:
3710 size = 0x2;
3711 break;
3712 case 0x00010000UL:
3713 size = 0x3;
3714 break;
3715 case 0x00040000UL:
3716 size = 0x4;
3717 break;
3718 case 0x00100000UL:
3719 size = 0x5;
3720 break;
3721 case 0x00400000UL:
3722 size = 0x6;
3723 break;
3724 case 0x01000000UL:
3725 size = 0x7;
3726 break;
3727 case 0x04000000UL:
3728 size = 0x8;
3729 break;
3730 case 0x10000000UL:
3731 size = 0x9;
3732 break;
3733 case 0x40000000UL:
3734 size = 0xA;
3735 break;
3736#if defined (TARGET_PPC64)
3737 case 0x000100000000ULL:
3738 size = 0xB;
3739 break;
3740 case 0x000400000000ULL:
3741 size = 0xC;
3742 break;
3743 case 0x001000000000ULL:
3744 size = 0xD;
3745 break;
3746 case 0x004000000000ULL:
3747 size = 0xE;
3748 break;
3749 case 0x010000000000ULL:
3750 size = 0xF;
3751 break;
3752#endif
3753 default:
3754 size = -1;
3755 break;
3756 }
3757
3758 return size;
3759}
3760
j_mayer76a66252007-03-07 08:32:30 +00003761/* Helpers for 4xx TLB management */
aurel3274d37792008-12-06 21:46:17 +00003762target_ulong helper_4xx_tlbre_lo (target_ulong entry)
j_mayer76a66252007-03-07 08:32:30 +00003763{
j_mayera8dea122007-03-31 11:33:48 +00003764 ppcemb_tlb_t *tlb;
aurel3274d37792008-12-06 21:46:17 +00003765 target_ulong ret;
j_mayera8dea122007-03-31 11:33:48 +00003766 int size;
j_mayer76a66252007-03-07 08:32:30 +00003767
aurel3274d37792008-12-06 21:46:17 +00003768 entry &= 0x3F;
3769 tlb = &env->tlb[entry].tlbe;
3770 ret = tlb->EPN;
j_mayera8dea122007-03-31 11:33:48 +00003771 if (tlb->prot & PAGE_VALID)
aurel3274d37792008-12-06 21:46:17 +00003772 ret |= 0x400;
j_mayera8dea122007-03-31 11:33:48 +00003773 size = booke_page_size_to_tlb(tlb->size);
3774 if (size < 0 || size > 0x7)
3775 size = 1;
aurel3274d37792008-12-06 21:46:17 +00003776 ret |= size << 7;
j_mayera8dea122007-03-31 11:33:48 +00003777 env->spr[SPR_40x_PID] = tlb->PID;
aurel3274d37792008-12-06 21:46:17 +00003778 return ret;
j_mayer76a66252007-03-07 08:32:30 +00003779}
3780
aurel3274d37792008-12-06 21:46:17 +00003781target_ulong helper_4xx_tlbre_hi (target_ulong entry)
j_mayer76a66252007-03-07 08:32:30 +00003782{
j_mayera8dea122007-03-31 11:33:48 +00003783 ppcemb_tlb_t *tlb;
aurel3274d37792008-12-06 21:46:17 +00003784 target_ulong ret;
j_mayer76a66252007-03-07 08:32:30 +00003785
aurel3274d37792008-12-06 21:46:17 +00003786 entry &= 0x3F;
3787 tlb = &env->tlb[entry].tlbe;
3788 ret = tlb->RPN;
j_mayera8dea122007-03-31 11:33:48 +00003789 if (tlb->prot & PAGE_EXEC)
aurel3274d37792008-12-06 21:46:17 +00003790 ret |= 0x200;
j_mayera8dea122007-03-31 11:33:48 +00003791 if (tlb->prot & PAGE_WRITE)
aurel3274d37792008-12-06 21:46:17 +00003792 ret |= 0x100;
3793 return ret;
j_mayer76a66252007-03-07 08:32:30 +00003794}
3795
aurel3274d37792008-12-06 21:46:17 +00003796void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
j_mayer76a66252007-03-07 08:32:30 +00003797{
j_mayera8dea122007-03-31 11:33:48 +00003798 ppcemb_tlb_t *tlb;
j_mayer76a66252007-03-07 08:32:30 +00003799 target_ulong page, end;
3800
aliguorid12d51d2009-01-15 21:48:06 +00003801 LOG_SWTLB("%s entry %d val " ADDRX "\n", __func__, (int)entry, val);
aurel3274d37792008-12-06 21:46:17 +00003802 entry &= 0x3F;
3803 tlb = &env->tlb[entry].tlbe;
j_mayer76a66252007-03-07 08:32:30 +00003804 /* Invalidate previous TLB (if it's valid) */
3805 if (tlb->prot & PAGE_VALID) {
3806 end = tlb->EPN + tlb->size;
aliguorid12d51d2009-01-15 21:48:06 +00003807 LOG_SWTLB("%s: invalidate old TLB %d start " ADDRX
aurel3274d37792008-12-06 21:46:17 +00003808 " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
j_mayer76a66252007-03-07 08:32:30 +00003809 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3810 tlb_flush_page(env, page);
3811 }
aurel3274d37792008-12-06 21:46:17 +00003812 tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
j_mayerc294fc52007-04-24 06:44:14 +00003813 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
3814 * If this ever occurs, one should use the ppcemb target instead
3815 * of the ppc or ppc64 one
3816 */
aurel3274d37792008-12-06 21:46:17 +00003817 if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
j_mayer71c8b8f2007-09-19 05:46:03 +00003818 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
3819 "are not supported (%d)\n",
aurel3274d37792008-12-06 21:46:17 +00003820 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
j_mayerc294fc52007-04-24 06:44:14 +00003821 }
aurel3274d37792008-12-06 21:46:17 +00003822 tlb->EPN = val & ~(tlb->size - 1);
3823 if (val & 0x40)
j_mayer76a66252007-03-07 08:32:30 +00003824 tlb->prot |= PAGE_VALID;
3825 else
3826 tlb->prot &= ~PAGE_VALID;
aurel3274d37792008-12-06 21:46:17 +00003827 if (val & 0x20) {
j_mayerc294fc52007-04-24 06:44:14 +00003828 /* XXX: TO BE FIXED */
3829 cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
3830 }
j_mayerc55e9ae2007-04-16 09:21:46 +00003831 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
aurel3274d37792008-12-06 21:46:17 +00003832 tlb->attr = val & 0xFF;
aliguorid12d51d2009-01-15 21:48:06 +00003833 LOG_SWTLB("%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
j_mayerc55e9ae2007-04-16 09:21:46 +00003834 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
aurel320e698052008-12-08 18:11:42 +00003835 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
j_mayerc55e9ae2007-04-16 09:21:46 +00003836 tlb->prot & PAGE_READ ? 'r' : '-',
3837 tlb->prot & PAGE_WRITE ? 'w' : '-',
3838 tlb->prot & PAGE_EXEC ? 'x' : '-',
3839 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
j_mayer76a66252007-03-07 08:32:30 +00003840 /* Invalidate new TLB (if valid) */
3841 if (tlb->prot & PAGE_VALID) {
3842 end = tlb->EPN + tlb->size;
aliguorid12d51d2009-01-15 21:48:06 +00003843 LOG_SWTLB("%s: invalidate TLB %d start " ADDRX
aurel320e698052008-12-08 18:11:42 +00003844 " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
j_mayer76a66252007-03-07 08:32:30 +00003845 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3846 tlb_flush_page(env, page);
3847 }
j_mayer76a66252007-03-07 08:32:30 +00003848}
3849
aurel3274d37792008-12-06 21:46:17 +00003850void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
j_mayer76a66252007-03-07 08:32:30 +00003851{
j_mayera8dea122007-03-31 11:33:48 +00003852 ppcemb_tlb_t *tlb;
j_mayer76a66252007-03-07 08:32:30 +00003853
aliguorid12d51d2009-01-15 21:48:06 +00003854 LOG_SWTLB("%s entry %i val " ADDRX "\n", __func__, (int)entry, val);
aurel3274d37792008-12-06 21:46:17 +00003855 entry &= 0x3F;
3856 tlb = &env->tlb[entry].tlbe;
3857 tlb->RPN = val & 0xFFFFFC00;
j_mayer76a66252007-03-07 08:32:30 +00003858 tlb->prot = PAGE_READ;
aurel3274d37792008-12-06 21:46:17 +00003859 if (val & 0x200)
j_mayer76a66252007-03-07 08:32:30 +00003860 tlb->prot |= PAGE_EXEC;
aurel3274d37792008-12-06 21:46:17 +00003861 if (val & 0x100)
j_mayer76a66252007-03-07 08:32:30 +00003862 tlb->prot |= PAGE_WRITE;
aliguorid12d51d2009-01-15 21:48:06 +00003863 LOG_SWTLB("%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
j_mayerc55e9ae2007-04-16 09:21:46 +00003864 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
aurel3274d37792008-12-06 21:46:17 +00003865 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
j_mayerc55e9ae2007-04-16 09:21:46 +00003866 tlb->prot & PAGE_READ ? 'r' : '-',
3867 tlb->prot & PAGE_WRITE ? 'w' : '-',
3868 tlb->prot & PAGE_EXEC ? 'x' : '-',
3869 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
j_mayer76a66252007-03-07 08:32:30 +00003870}
j_mayer5eb79952007-09-19 05:44:04 +00003871
aurel3274d37792008-12-06 21:46:17 +00003872target_ulong helper_4xx_tlbsx (target_ulong address)
3873{
3874 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
3875}
3876
j_mayera4bb6c32007-09-21 05:28:33 +00003877/* PowerPC 440 TLB management */
aurel3274d37792008-12-06 21:46:17 +00003878void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
j_mayer5eb79952007-09-19 05:44:04 +00003879{
3880 ppcemb_tlb_t *tlb;
j_mayera4bb6c32007-09-21 05:28:33 +00003881 target_ulong EPN, RPN, size;
j_mayer5eb79952007-09-19 05:44:04 +00003882 int do_flush_tlbs;
3883
aliguorid12d51d2009-01-15 21:48:06 +00003884 LOG_SWTLB("%s word %d entry %d value " ADDRX "\n",
aurel320e698052008-12-08 18:11:42 +00003885 __func__, word, (int)entry, value);
j_mayer5eb79952007-09-19 05:44:04 +00003886 do_flush_tlbs = 0;
aurel3274d37792008-12-06 21:46:17 +00003887 entry &= 0x3F;
3888 tlb = &env->tlb[entry].tlbe;
j_mayera4bb6c32007-09-21 05:28:33 +00003889 switch (word) {
3890 default:
3891 /* Just here to please gcc */
3892 case 0:
aurel3274d37792008-12-06 21:46:17 +00003893 EPN = value & 0xFFFFFC00;
j_mayera4bb6c32007-09-21 05:28:33 +00003894 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
j_mayer5eb79952007-09-19 05:44:04 +00003895 do_flush_tlbs = 1;
j_mayera4bb6c32007-09-21 05:28:33 +00003896 tlb->EPN = EPN;
aurel3274d37792008-12-06 21:46:17 +00003897 size = booke_tlb_to_page_size((value >> 4) & 0xF);
j_mayera4bb6c32007-09-21 05:28:33 +00003898 if ((tlb->prot & PAGE_VALID) && tlb->size < size)
3899 do_flush_tlbs = 1;
3900 tlb->size = size;
3901 tlb->attr &= ~0x1;
aurel3274d37792008-12-06 21:46:17 +00003902 tlb->attr |= (value >> 8) & 1;
3903 if (value & 0x200) {
j_mayera4bb6c32007-09-21 05:28:33 +00003904 tlb->prot |= PAGE_VALID;
3905 } else {
3906 if (tlb->prot & PAGE_VALID) {
3907 tlb->prot &= ~PAGE_VALID;
3908 do_flush_tlbs = 1;
3909 }
j_mayer5eb79952007-09-19 05:44:04 +00003910 }
j_mayera4bb6c32007-09-21 05:28:33 +00003911 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
3912 if (do_flush_tlbs)
3913 tlb_flush(env, 1);
3914 break;
3915 case 1:
aurel3274d37792008-12-06 21:46:17 +00003916 RPN = value & 0xFFFFFC0F;
j_mayera4bb6c32007-09-21 05:28:33 +00003917 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
3918 tlb_flush(env, 1);
3919 tlb->RPN = RPN;
3920 break;
3921 case 2:
aurel3274d37792008-12-06 21:46:17 +00003922 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
j_mayera4bb6c32007-09-21 05:28:33 +00003923 tlb->prot = tlb->prot & PAGE_VALID;
aurel3274d37792008-12-06 21:46:17 +00003924 if (value & 0x1)
j_mayera4bb6c32007-09-21 05:28:33 +00003925 tlb->prot |= PAGE_READ << 4;
aurel3274d37792008-12-06 21:46:17 +00003926 if (value & 0x2)
j_mayera4bb6c32007-09-21 05:28:33 +00003927 tlb->prot |= PAGE_WRITE << 4;
aurel3274d37792008-12-06 21:46:17 +00003928 if (value & 0x4)
j_mayera4bb6c32007-09-21 05:28:33 +00003929 tlb->prot |= PAGE_EXEC << 4;
aurel3274d37792008-12-06 21:46:17 +00003930 if (value & 0x8)
j_mayera4bb6c32007-09-21 05:28:33 +00003931 tlb->prot |= PAGE_READ;
aurel3274d37792008-12-06 21:46:17 +00003932 if (value & 0x10)
j_mayera4bb6c32007-09-21 05:28:33 +00003933 tlb->prot |= PAGE_WRITE;
aurel3274d37792008-12-06 21:46:17 +00003934 if (value & 0x20)
j_mayera4bb6c32007-09-21 05:28:33 +00003935 tlb->prot |= PAGE_EXEC;
3936 break;
j_mayer5eb79952007-09-19 05:44:04 +00003937 }
j_mayer5eb79952007-09-19 05:44:04 +00003938}
3939
aurel3274d37792008-12-06 21:46:17 +00003940target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
j_mayer5eb79952007-09-19 05:44:04 +00003941{
3942 ppcemb_tlb_t *tlb;
aurel3274d37792008-12-06 21:46:17 +00003943 target_ulong ret;
j_mayer5eb79952007-09-19 05:44:04 +00003944 int size;
3945
aurel3274d37792008-12-06 21:46:17 +00003946 entry &= 0x3F;
3947 tlb = &env->tlb[entry].tlbe;
j_mayera4bb6c32007-09-21 05:28:33 +00003948 switch (word) {
3949 default:
3950 /* Just here to please gcc */
3951 case 0:
aurel3274d37792008-12-06 21:46:17 +00003952 ret = tlb->EPN;
j_mayera4bb6c32007-09-21 05:28:33 +00003953 size = booke_page_size_to_tlb(tlb->size);
3954 if (size < 0 || size > 0xF)
3955 size = 1;
aurel3274d37792008-12-06 21:46:17 +00003956 ret |= size << 4;
j_mayera4bb6c32007-09-21 05:28:33 +00003957 if (tlb->attr & 0x1)
aurel3274d37792008-12-06 21:46:17 +00003958 ret |= 0x100;
j_mayera4bb6c32007-09-21 05:28:33 +00003959 if (tlb->prot & PAGE_VALID)
aurel3274d37792008-12-06 21:46:17 +00003960 ret |= 0x200;
j_mayera4bb6c32007-09-21 05:28:33 +00003961 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
3962 env->spr[SPR_440_MMUCR] |= tlb->PID;
3963 break;
3964 case 1:
aurel3274d37792008-12-06 21:46:17 +00003965 ret = tlb->RPN;
j_mayera4bb6c32007-09-21 05:28:33 +00003966 break;
3967 case 2:
aurel3274d37792008-12-06 21:46:17 +00003968 ret = tlb->attr & ~0x1;
j_mayera4bb6c32007-09-21 05:28:33 +00003969 if (tlb->prot & (PAGE_READ << 4))
aurel3274d37792008-12-06 21:46:17 +00003970 ret |= 0x1;
j_mayera4bb6c32007-09-21 05:28:33 +00003971 if (tlb->prot & (PAGE_WRITE << 4))
aurel3274d37792008-12-06 21:46:17 +00003972 ret |= 0x2;
j_mayera4bb6c32007-09-21 05:28:33 +00003973 if (tlb->prot & (PAGE_EXEC << 4))
aurel3274d37792008-12-06 21:46:17 +00003974 ret |= 0x4;
j_mayera4bb6c32007-09-21 05:28:33 +00003975 if (tlb->prot & PAGE_READ)
aurel3274d37792008-12-06 21:46:17 +00003976 ret |= 0x8;
j_mayera4bb6c32007-09-21 05:28:33 +00003977 if (tlb->prot & PAGE_WRITE)
aurel3274d37792008-12-06 21:46:17 +00003978 ret |= 0x10;
j_mayera4bb6c32007-09-21 05:28:33 +00003979 if (tlb->prot & PAGE_EXEC)
aurel3274d37792008-12-06 21:46:17 +00003980 ret |= 0x20;
j_mayera4bb6c32007-09-21 05:28:33 +00003981 break;
3982 }
aurel3274d37792008-12-06 21:46:17 +00003983 return ret;
j_mayer5eb79952007-09-19 05:44:04 +00003984}
aurel3274d37792008-12-06 21:46:17 +00003985
3986target_ulong helper_440_tlbsx (target_ulong address)
3987{
3988 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
3989}
3990
j_mayer76a66252007-03-07 08:32:30 +00003991#endif /* !CONFIG_USER_ONLY */