blob: 1c820885abc7994fd25e31b62c24b9e088a53cc6 [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
bellard9a64fbe2004-01-04 22:58:38 +000031/*****************************************************************************/
32/* Exceptions processing helpers */
bellard9a64fbe2004-01-04 22:58:38 +000033
aurel3264adab32008-11-22 10:09:17 +000034void helper_raise_exception_err (uint32_t exception, uint32_t error_code)
bellard9a64fbe2004-01-04 22:58:38 +000035{
aurel32e06fcd72008-12-11 22:42:14 +000036#if 0
37 printf("Raise exception %3x code : %d\n", exception, error_code);
38#endif
39 env->exception_index = exception;
40 env->error_code = error_code;
41 cpu_loop_exit();
j_mayer76a66252007-03-07 08:32:30 +000042}
bellard9fddaa02004-05-21 12:59:32 +000043
aurel32e06fcd72008-12-11 22:42:14 +000044void helper_raise_exception (uint32_t exception)
bellard9fddaa02004-05-21 12:59:32 +000045{
aurel32e06fcd72008-12-11 22:42:14 +000046 helper_raise_exception_err(exception, 0);
bellard9a64fbe2004-01-04 22:58:38 +000047}
48
49/*****************************************************************************/
j_mayer76a66252007-03-07 08:32:30 +000050/* Registers load and stores */
pbrooka7812ae2008-11-17 14:43:54 +000051target_ulong helper_load_cr (void)
j_mayer76a66252007-03-07 08:32:30 +000052{
aurel32e1571902008-10-21 11:31:14 +000053 return (env->crf[0] << 28) |
54 (env->crf[1] << 24) |
55 (env->crf[2] << 20) |
56 (env->crf[3] << 16) |
57 (env->crf[4] << 12) |
58 (env->crf[5] << 8) |
59 (env->crf[6] << 4) |
60 (env->crf[7] << 0);
j_mayer76a66252007-03-07 08:32:30 +000061}
62
aurel32e1571902008-10-21 11:31:14 +000063void helper_store_cr (target_ulong val, uint32_t mask)
j_mayer76a66252007-03-07 08:32:30 +000064{
65 int i, sh;
66
j_mayer36081602007-09-17 08:21:54 +000067 for (i = 0, sh = 7; i < 8; i++, sh--) {
j_mayer76a66252007-03-07 08:32:30 +000068 if (mask & (1 << sh))
aurel32e1571902008-10-21 11:31:14 +000069 env->crf[i] = (val >> (sh * 4)) & 0xFUL;
j_mayer76a66252007-03-07 08:32:30 +000070 }
71}
72
aurel3245d827d2008-12-07 13:40:29 +000073/*****************************************************************************/
74/* SPR accesses */
75void helper_load_dump_spr (uint32_t sprn)
j_mayera4967752007-04-16 07:10:48 +000076{
j_mayer6b800552007-04-24 07:36:03 +000077 if (loglevel != 0) {
j_mayera4967752007-04-16 07:10:48 +000078 fprintf(logfile, "Read SPR %d %03x => " ADDRX "\n",
79 sprn, sprn, env->spr[sprn]);
80 }
j_mayera4967752007-04-16 07:10:48 +000081}
82
aurel3245d827d2008-12-07 13:40:29 +000083void helper_store_dump_spr (uint32_t sprn)
j_mayera4967752007-04-16 07:10:48 +000084{
j_mayer6b800552007-04-24 07:36:03 +000085 if (loglevel != 0) {
aurel3245d827d2008-12-07 13:40:29 +000086 fprintf(logfile, "Write SPR %d %03x <= " ADDRX "\n",
87 sprn, sprn, env->spr[sprn]);
j_mayera4967752007-04-16 07:10:48 +000088 }
j_mayera4967752007-04-16 07:10:48 +000089}
90
aurel3245d827d2008-12-07 13:40:29 +000091target_ulong helper_load_tbl (void)
92{
93 return cpu_ppc_load_tbl(env);
94}
95
96target_ulong helper_load_tbu (void)
97{
98 return cpu_ppc_load_tbu(env);
99}
100
101target_ulong helper_load_atbl (void)
102{
103 return cpu_ppc_load_atbl(env);
104}
105
106target_ulong helper_load_atbu (void)
107{
108 return cpu_ppc_load_atbu(env);
109}
110
111target_ulong helper_load_601_rtcl (void)
112{
113 return cpu_ppc601_load_rtcl(env);
114}
115
116target_ulong helper_load_601_rtcu (void)
117{
118 return cpu_ppc601_load_rtcu(env);
119}
120
121#if !defined(CONFIG_USER_ONLY)
122#if defined (TARGET_PPC64)
123void helper_store_asr (target_ulong val)
124{
125 ppc_store_asr(env, val);
126}
127#endif
128
129void helper_store_sdr1 (target_ulong val)
130{
131 ppc_store_sdr1(env, val);
132}
133
134void helper_store_tbl (target_ulong val)
135{
136 cpu_ppc_store_tbl(env, val);
137}
138
139void helper_store_tbu (target_ulong val)
140{
141 cpu_ppc_store_tbu(env, val);
142}
143
144void helper_store_atbl (target_ulong val)
145{
146 cpu_ppc_store_atbl(env, val);
147}
148
149void helper_store_atbu (target_ulong val)
150{
151 cpu_ppc_store_atbu(env, val);
152}
153
154void helper_store_601_rtcl (target_ulong val)
155{
156 cpu_ppc601_store_rtcl(env, val);
157}
158
159void helper_store_601_rtcu (target_ulong val)
160{
161 cpu_ppc601_store_rtcu(env, val);
162}
163
164target_ulong helper_load_decr (void)
165{
166 return cpu_ppc_load_decr(env);
167}
168
169void helper_store_decr (target_ulong val)
170{
171 cpu_ppc_store_decr(env, val);
172}
173
174void helper_store_hid0_601 (target_ulong val)
175{
176 target_ulong hid0;
177
178 hid0 = env->spr[SPR_HID0];
179 if ((val ^ hid0) & 0x00000008) {
180 /* Change current endianness */
181 env->hflags &= ~(1 << MSR_LE);
182 env->hflags_nmsr &= ~(1 << MSR_LE);
183 env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
184 env->hflags |= env->hflags_nmsr;
185 if (loglevel != 0) {
186 fprintf(logfile, "%s: set endianness to %c => " ADDRX "\n",
187 __func__, val & 0x8 ? 'l' : 'b', env->hflags);
188 }
189 }
190 env->spr[SPR_HID0] = (uint32_t)val;
191}
192
193void helper_store_403_pbr (uint32_t num, target_ulong value)
194{
195 if (likely(env->pb[num] != value)) {
196 env->pb[num] = value;
197 /* Should be optimized */
198 tlb_flush(env, 1);
199 }
200}
201
202target_ulong helper_load_40x_pit (void)
203{
204 return load_40x_pit(env);
205}
206
207void helper_store_40x_pit (target_ulong val)
208{
209 store_40x_pit(env, val);
210}
211
212void helper_store_40x_dbcr0 (target_ulong val)
213{
214 store_40x_dbcr0(env, val);
215}
216
217void helper_store_40x_sler (target_ulong val)
218{
219 store_40x_sler(env, val);
220}
221
222void helper_store_booke_tcr (target_ulong val)
223{
224 store_booke_tcr(env, val);
225}
226
227void helper_store_booke_tsr (target_ulong val)
228{
229 store_booke_tsr(env, val);
230}
231
232void helper_store_ibatu (uint32_t nr, target_ulong val)
233{
234 ppc_store_ibatu(env, nr, val);
235}
236
237void helper_store_ibatl (uint32_t nr, target_ulong val)
238{
239 ppc_store_ibatl(env, nr, val);
240}
241
242void helper_store_dbatu (uint32_t nr, target_ulong val)
243{
244 ppc_store_dbatu(env, nr, val);
245}
246
247void helper_store_dbatl (uint32_t nr, target_ulong val)
248{
249 ppc_store_dbatl(env, nr, val);
250}
251
252void helper_store_601_batl (uint32_t nr, target_ulong val)
253{
254 ppc_store_ibatl_601(env, nr, val);
255}
256
257void helper_store_601_batu (uint32_t nr, target_ulong val)
258{
259 ppc_store_ibatu_601(env, nr, val);
260}
261#endif
262
j_mayer76a66252007-03-07 08:32:30 +0000263/*****************************************************************************/
aurel32ff4a62c2008-11-30 16:23:56 +0000264/* Memory load and stores */
265
aurel3276db3ba2008-12-08 18:11:21 +0000266static always_inline target_ulong addr_add(target_ulong addr, target_long arg)
aurel32ff4a62c2008-11-30 16:23:56 +0000267{
268#if defined(TARGET_PPC64)
aurel3276db3ba2008-12-08 18:11:21 +0000269 if (!msr_sf)
270 return (uint32_t)(addr + arg);
aurel32ff4a62c2008-11-30 16:23:56 +0000271 else
272#endif
aurel3276db3ba2008-12-08 18:11:21 +0000273 return addr + arg;
aurel32ff4a62c2008-11-30 16:23:56 +0000274}
275
276void helper_lmw (target_ulong addr, uint32_t reg)
277{
aurel3276db3ba2008-12-08 18:11:21 +0000278 for (; reg < 32; reg++) {
aurel32ff4a62c2008-11-30 16:23:56 +0000279 if (msr_le)
aurel3276db3ba2008-12-08 18:11:21 +0000280 env->gpr[reg] = bswap32(ldl(addr));
aurel32ff4a62c2008-11-30 16:23:56 +0000281 else
aurel3276db3ba2008-12-08 18:11:21 +0000282 env->gpr[reg] = ldl(addr);
283 addr = addr_add(addr, 4);
aurel32ff4a62c2008-11-30 16:23:56 +0000284 }
285}
286
287void helper_stmw (target_ulong addr, uint32_t reg)
288{
aurel3276db3ba2008-12-08 18:11:21 +0000289 for (; reg < 32; reg++) {
aurel32ff4a62c2008-11-30 16:23:56 +0000290 if (msr_le)
aurel3276db3ba2008-12-08 18:11:21 +0000291 stl(addr, bswap32((uint32_t)env->gpr[reg]));
aurel32ff4a62c2008-11-30 16:23:56 +0000292 else
aurel3276db3ba2008-12-08 18:11:21 +0000293 stl(addr, (uint32_t)env->gpr[reg]);
294 addr = addr_add(addr, 4);
aurel32ff4a62c2008-11-30 16:23:56 +0000295 }
296}
297
aurel32dfbc7992008-11-30 16:24:21 +0000298void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg)
299{
300 int sh;
aurel3276db3ba2008-12-08 18:11:21 +0000301 for (; nb > 3; nb -= 4) {
302 env->gpr[reg] = ldl(addr);
aurel32dfbc7992008-11-30 16:24:21 +0000303 reg = (reg + 1) % 32;
aurel3276db3ba2008-12-08 18:11:21 +0000304 addr = addr_add(addr, 4);
aurel32dfbc7992008-11-30 16:24:21 +0000305 }
306 if (unlikely(nb > 0)) {
307 env->gpr[reg] = 0;
aurel3276db3ba2008-12-08 18:11:21 +0000308 for (sh = 24; nb > 0; nb--, sh -= 8) {
309 env->gpr[reg] |= ldub(addr) << sh;
310 addr = addr_add(addr, 1);
aurel32dfbc7992008-11-30 16:24:21 +0000311 }
312 }
313}
314/* PPC32 specification says we must generate an exception if
315 * rA is in the range of registers to be loaded.
316 * In an other hand, IBM says this is valid, but rA won't be loaded.
317 * For now, I'll follow the spec...
318 */
319void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
320{
321 if (likely(xer_bc != 0)) {
322 if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
323 (reg < rb && (reg + xer_bc) > rb))) {
aurel32e06fcd72008-12-11 22:42:14 +0000324 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
325 POWERPC_EXCP_INVAL |
326 POWERPC_EXCP_INVAL_LSWX);
aurel32dfbc7992008-11-30 16:24:21 +0000327 } else {
328 helper_lsw(addr, xer_bc, reg);
329 }
330 }
331}
332
333void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
334{
335 int sh;
aurel3276db3ba2008-12-08 18:11:21 +0000336 for (; nb > 3; nb -= 4) {
337 stl(addr, env->gpr[reg]);
aurel32dfbc7992008-11-30 16:24:21 +0000338 reg = (reg + 1) % 32;
aurel3276db3ba2008-12-08 18:11:21 +0000339 addr = addr_add(addr, 4);
aurel32dfbc7992008-11-30 16:24:21 +0000340 }
341 if (unlikely(nb > 0)) {
aurel32a16b45e2008-12-29 09:46:58 +0000342 for (sh = 24; nb > 0; nb--, sh -= 8) {
aurel3276db3ba2008-12-08 18:11:21 +0000343 stb(addr, (env->gpr[reg] >> sh) & 0xFF);
aurel32a16b45e2008-12-29 09:46:58 +0000344 addr = addr_add(addr, 1);
345 }
aurel32dfbc7992008-11-30 16:24:21 +0000346 }
347}
348
aurel32799a8c82008-11-30 16:24:05 +0000349static void do_dcbz(target_ulong addr, int dcache_line_size)
350{
aurel3276db3ba2008-12-08 18:11:21 +0000351 addr &= ~(dcache_line_size - 1);
aurel32799a8c82008-11-30 16:24:05 +0000352 int i;
aurel32799a8c82008-11-30 16:24:05 +0000353 for (i = 0 ; i < dcache_line_size ; i += 4) {
aurel32dcc532c2008-11-30 17:54:21 +0000354 stl(addr + i , 0);
aurel32799a8c82008-11-30 16:24:05 +0000355 }
aurel3276db3ba2008-12-08 18:11:21 +0000356 if (env->reserve == addr)
aurel32799a8c82008-11-30 16:24:05 +0000357 env->reserve = (target_ulong)-1ULL;
358}
359
360void helper_dcbz(target_ulong addr)
361{
362 do_dcbz(addr, env->dcache_line_size);
363}
364
365void helper_dcbz_970(target_ulong addr)
366{
367 if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1)
368 do_dcbz(addr, 32);
369 else
370 do_dcbz(addr, env->dcache_line_size);
371}
372
aurel3237d269d2008-11-30 16:24:13 +0000373void helper_icbi(target_ulong addr)
374{
375 uint32_t tmp;
376
aurel3276db3ba2008-12-08 18:11:21 +0000377 addr &= ~(env->dcache_line_size - 1);
aurel3237d269d2008-11-30 16:24:13 +0000378 /* Invalidate one cache line :
379 * PowerPC specification says this is to be treated like a load
380 * (not a fetch) by the MMU. To be sure it will be so,
381 * do the load "by hand".
382 */
aurel32dcc532c2008-11-30 17:54:21 +0000383 tmp = ldl(addr);
aurel3237d269d2008-11-30 16:24:13 +0000384 tb_invalidate_page_range(addr, addr + env->icache_line_size);
385}
386
aurel32bdb4b682008-11-30 16:24:30 +0000387// XXX: to be tested
388target_ulong helper_lscbx (target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
389{
390 int i, c, d;
aurel32bdb4b682008-11-30 16:24:30 +0000391 d = 24;
392 for (i = 0; i < xer_bc; i++) {
aurel3276db3ba2008-12-08 18:11:21 +0000393 c = ldub(addr);
394 addr = addr_add(addr, 1);
aurel32bdb4b682008-11-30 16:24:30 +0000395 /* ra (if not 0) and rb are never modified */
396 if (likely(reg != rb && (ra == 0 || reg != ra))) {
397 env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
398 }
399 if (unlikely(c == xer_cmp))
400 break;
401 if (likely(d != 0)) {
402 d -= 8;
403 } else {
404 d = 24;
405 reg++;
406 reg = reg & 0x1F;
407 }
408 }
409 return i;
410}
411
aurel32ff4a62c2008-11-30 16:23:56 +0000412/*****************************************************************************/
bellardfdabc362005-07-04 22:17:05 +0000413/* Fixed point operations helpers */
j_mayerd9bce9d2007-03-17 14:02:15 +0000414#if defined(TARGET_PPC64)
bellardfdabc362005-07-04 22:17:05 +0000415
aurel3274637402008-11-01 00:54:12 +0000416/* multiply high word */
417uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2)
bellardfdabc362005-07-04 22:17:05 +0000418{
aurel3274637402008-11-01 00:54:12 +0000419 uint64_t tl, th;
420
421 muls64(&tl, &th, arg1, arg2);
422 return th;
bellardfdabc362005-07-04 22:17:05 +0000423}
424
aurel3274637402008-11-01 00:54:12 +0000425/* multiply high word unsigned */
426uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2)
bellardfdabc362005-07-04 22:17:05 +0000427{
aurel3274637402008-11-01 00:54:12 +0000428 uint64_t tl, th;
bellardfdabc362005-07-04 22:17:05 +0000429
aurel3274637402008-11-01 00:54:12 +0000430 mulu64(&tl, &th, arg1, arg2);
431 return th;
bellardfdabc362005-07-04 22:17:05 +0000432}
433
aurel3274637402008-11-01 00:54:12 +0000434uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
j_mayerd9bce9d2007-03-17 14:02:15 +0000435{
436 int64_t th;
437 uint64_t tl;
438
aurel3274637402008-11-01 00:54:12 +0000439 muls64(&tl, (uint64_t *)&th, arg1, arg2);
j_mayer88ad9202007-10-25 23:36:08 +0000440 /* If th != 0 && th != -1, then we had an overflow */
j_mayer6f2d8972007-11-12 00:04:48 +0000441 if (likely((uint64_t)(th + 1) <= 1)) {
aurel323d7b4172008-10-21 11:28:46 +0000442 env->xer &= ~(1 << XER_OV);
j_mayerd9bce9d2007-03-17 14:02:15 +0000443 } else {
aurel323d7b4172008-10-21 11:28:46 +0000444 env->xer |= (1 << XER_OV) | (1 << XER_SO);
j_mayerd9bce9d2007-03-17 14:02:15 +0000445 }
aurel3274637402008-11-01 00:54:12 +0000446 return (int64_t)tl;
j_mayerd9bce9d2007-03-17 14:02:15 +0000447}
448#endif
449
aurel3226d67362008-10-21 11:31:27 +0000450target_ulong helper_cntlzw (target_ulong t)
j_mayer603fccc2007-10-28 12:54:53 +0000451{
aurel3226d67362008-10-21 11:31:27 +0000452 return clz32(t);
j_mayer603fccc2007-10-28 12:54:53 +0000453}
454
455#if defined(TARGET_PPC64)
aurel3226d67362008-10-21 11:31:27 +0000456target_ulong helper_cntlzd (target_ulong t)
j_mayer603fccc2007-10-28 12:54:53 +0000457{
aurel3226d67362008-10-21 11:31:27 +0000458 return clz64(t);
j_mayer603fccc2007-10-28 12:54:53 +0000459}
460#endif
461
bellard9a64fbe2004-01-04 22:58:38 +0000462/* shift right arithmetic helper */
aurel3226d67362008-10-21 11:31:27 +0000463target_ulong helper_sraw (target_ulong value, target_ulong shift)
bellard9a64fbe2004-01-04 22:58:38 +0000464{
465 int32_t ret;
466
aurel3226d67362008-10-21 11:31:27 +0000467 if (likely(!(shift & 0x20))) {
468 if (likely((uint32_t)shift != 0)) {
469 shift &= 0x1f;
470 ret = (int32_t)value >> shift;
471 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
aurel323d7b4172008-10-21 11:28:46 +0000472 env->xer &= ~(1 << XER_CA);
bellardfdabc362005-07-04 22:17:05 +0000473 } else {
aurel323d7b4172008-10-21 11:28:46 +0000474 env->xer |= (1 << XER_CA);
bellardfdabc362005-07-04 22:17:05 +0000475 }
476 } else {
aurel3226d67362008-10-21 11:31:27 +0000477 ret = (int32_t)value;
aurel323d7b4172008-10-21 11:28:46 +0000478 env->xer &= ~(1 << XER_CA);
bellardfdabc362005-07-04 22:17:05 +0000479 }
bellard9a64fbe2004-01-04 22:58:38 +0000480 } else {
aurel3226d67362008-10-21 11:31:27 +0000481 ret = (int32_t)value >> 31;
482 if (ret) {
aurel323d7b4172008-10-21 11:28:46 +0000483 env->xer |= (1 << XER_CA);
aurel3226d67362008-10-21 11:31:27 +0000484 } else {
485 env->xer &= ~(1 << XER_CA);
j_mayer76a66252007-03-07 08:32:30 +0000486 }
bellardfdabc362005-07-04 22:17:05 +0000487 }
aurel3226d67362008-10-21 11:31:27 +0000488 return (target_long)ret;
bellard9a64fbe2004-01-04 22:58:38 +0000489}
490
j_mayerd9bce9d2007-03-17 14:02:15 +0000491#if defined(TARGET_PPC64)
aurel3226d67362008-10-21 11:31:27 +0000492target_ulong helper_srad (target_ulong value, target_ulong shift)
j_mayerd9bce9d2007-03-17 14:02:15 +0000493{
494 int64_t ret;
495
aurel3226d67362008-10-21 11:31:27 +0000496 if (likely(!(shift & 0x40))) {
497 if (likely((uint64_t)shift != 0)) {
498 shift &= 0x3f;
499 ret = (int64_t)value >> shift;
500 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
aurel323d7b4172008-10-21 11:28:46 +0000501 env->xer &= ~(1 << XER_CA);
j_mayerd9bce9d2007-03-17 14:02:15 +0000502 } else {
aurel323d7b4172008-10-21 11:28:46 +0000503 env->xer |= (1 << XER_CA);
j_mayerd9bce9d2007-03-17 14:02:15 +0000504 }
505 } else {
aurel3226d67362008-10-21 11:31:27 +0000506 ret = (int64_t)value;
aurel323d7b4172008-10-21 11:28:46 +0000507 env->xer &= ~(1 << XER_CA);
j_mayerd9bce9d2007-03-17 14:02:15 +0000508 }
509 } else {
aurel3226d67362008-10-21 11:31:27 +0000510 ret = (int64_t)value >> 63;
511 if (ret) {
aurel323d7b4172008-10-21 11:28:46 +0000512 env->xer |= (1 << XER_CA);
aurel3226d67362008-10-21 11:31:27 +0000513 } else {
514 env->xer &= ~(1 << XER_CA);
j_mayerd9bce9d2007-03-17 14:02:15 +0000515 }
516 }
aurel3226d67362008-10-21 11:31:27 +0000517 return ret;
j_mayerd9bce9d2007-03-17 14:02:15 +0000518}
519#endif
520
aurel3226d67362008-10-21 11:31:27 +0000521target_ulong helper_popcntb (target_ulong val)
j_mayerd9bce9d2007-03-17 14:02:15 +0000522{
aurel326176a262008-11-01 00:54:33 +0000523 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
524 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
525 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
526 return val;
j_mayerd9bce9d2007-03-17 14:02:15 +0000527}
528
529#if defined(TARGET_PPC64)
aurel3226d67362008-10-21 11:31:27 +0000530target_ulong helper_popcntb_64 (target_ulong val)
j_mayerd9bce9d2007-03-17 14:02:15 +0000531{
aurel326176a262008-11-01 00:54:33 +0000532 val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL);
533 val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL);
534 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & 0x0f0f0f0f0f0f0f0fULL);
535 return val;
j_mayerd9bce9d2007-03-17 14:02:15 +0000536}
537#endif
538
bellardfdabc362005-07-04 22:17:05 +0000539/*****************************************************************************/
bellard9a64fbe2004-01-04 22:58:38 +0000540/* Floating point operations helpers */
aurel32a0d7d5a2008-11-23 16:30:50 +0000541uint64_t helper_float32_to_float64(uint32_t arg)
542{
543 CPU_FloatU f;
544 CPU_DoubleU d;
545 f.l = arg;
546 d.d = float32_to_float64(f.f, &env->fp_status);
547 return d.ll;
548}
549
550uint32_t helper_float64_to_float32(uint64_t arg)
551{
552 CPU_FloatU f;
553 CPU_DoubleU d;
554 d.ll = arg;
555 f.f = float64_to_float32(d.d, &env->fp_status);
556 return f.l;
557}
558
aurel320ca9d382008-03-13 19:19:16 +0000559static always_inline int isden (float64 d)
j_mayer7c580442007-10-27 17:54:30 +0000560{
aurel320ca9d382008-03-13 19:19:16 +0000561 CPU_DoubleU u;
j_mayer7c580442007-10-27 17:54:30 +0000562
aurel320ca9d382008-03-13 19:19:16 +0000563 u.d = d;
j_mayer7c580442007-10-27 17:54:30 +0000564
aurel320ca9d382008-03-13 19:19:16 +0000565 return ((u.ll >> 52) & 0x7FF) == 0;
j_mayer7c580442007-10-27 17:54:30 +0000566}
567
aurel32af129062008-11-19 16:10:23 +0000568uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
j_mayer7c580442007-10-27 17:54:30 +0000569{
aurel32af129062008-11-19 16:10:23 +0000570 CPU_DoubleU farg;
j_mayer7c580442007-10-27 17:54:30 +0000571 int isneg;
aurel32af129062008-11-19 16:10:23 +0000572 int ret;
573 farg.ll = arg;
aurel32f23c3462008-12-15 17:14:27 +0000574 isneg = float64_is_neg(farg.d);
aurel32af129062008-11-19 16:10:23 +0000575 if (unlikely(float64_is_nan(farg.d))) {
576 if (float64_is_signaling_nan(farg.d)) {
j_mayer7c580442007-10-27 17:54:30 +0000577 /* Signaling NaN: flags are undefined */
aurel32af129062008-11-19 16:10:23 +0000578 ret = 0x00;
j_mayer7c580442007-10-27 17:54:30 +0000579 } else {
580 /* Quiet NaN */
aurel32af129062008-11-19 16:10:23 +0000581 ret = 0x11;
j_mayer7c580442007-10-27 17:54:30 +0000582 }
aurel32f23c3462008-12-15 17:14:27 +0000583 } else if (unlikely(float64_is_infinity(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +0000584 /* +/- infinity */
585 if (isneg)
aurel32af129062008-11-19 16:10:23 +0000586 ret = 0x09;
j_mayer7c580442007-10-27 17:54:30 +0000587 else
aurel32af129062008-11-19 16:10:23 +0000588 ret = 0x05;
j_mayer7c580442007-10-27 17:54:30 +0000589 } else {
aurel32f23c3462008-12-15 17:14:27 +0000590 if (float64_is_zero(farg.d)) {
j_mayer7c580442007-10-27 17:54:30 +0000591 /* +/- zero */
592 if (isneg)
aurel32af129062008-11-19 16:10:23 +0000593 ret = 0x12;
j_mayer7c580442007-10-27 17:54:30 +0000594 else
aurel32af129062008-11-19 16:10:23 +0000595 ret = 0x02;
j_mayer7c580442007-10-27 17:54:30 +0000596 } else {
aurel32af129062008-11-19 16:10:23 +0000597 if (isden(farg.d)) {
j_mayer7c580442007-10-27 17:54:30 +0000598 /* Denormalized numbers */
aurel32af129062008-11-19 16:10:23 +0000599 ret = 0x10;
j_mayer7c580442007-10-27 17:54:30 +0000600 } else {
601 /* Normalized numbers */
aurel32af129062008-11-19 16:10:23 +0000602 ret = 0x00;
j_mayer7c580442007-10-27 17:54:30 +0000603 }
604 if (isneg) {
aurel32af129062008-11-19 16:10:23 +0000605 ret |= 0x08;
j_mayer7c580442007-10-27 17:54:30 +0000606 } else {
aurel32af129062008-11-19 16:10:23 +0000607 ret |= 0x04;
j_mayer7c580442007-10-27 17:54:30 +0000608 }
609 }
610 }
611 if (set_fprf) {
612 /* We update FPSCR_FPRF */
613 env->fpscr &= ~(0x1F << FPSCR_FPRF);
aurel32af129062008-11-19 16:10:23 +0000614 env->fpscr |= ret << FPSCR_FPRF;
j_mayer7c580442007-10-27 17:54:30 +0000615 }
616 /* We just need fpcc to update Rc1 */
aurel32af129062008-11-19 16:10:23 +0000617 return ret & 0xF;
j_mayer7c580442007-10-27 17:54:30 +0000618}
619
620/* Floating-point invalid operations exception */
aurel32af129062008-11-19 16:10:23 +0000621static always_inline uint64_t fload_invalid_op_excp (int op)
j_mayer7c580442007-10-27 17:54:30 +0000622{
aurel32af129062008-11-19 16:10:23 +0000623 uint64_t ret = 0;
j_mayer7c580442007-10-27 17:54:30 +0000624 int ve;
625
626 ve = fpscr_ve;
aurel32e0147e42008-12-15 17:13:55 +0000627 switch (op) {
628 case POWERPC_EXCP_FP_VXSNAN:
j_mayer7c580442007-10-27 17:54:30 +0000629 env->fpscr |= 1 << FPSCR_VXSNAN;
aurel32e0147e42008-12-15 17:13:55 +0000630 break;
631 case POWERPC_EXCP_FP_VXSOFT:
j_mayer7c580442007-10-27 17:54:30 +0000632 env->fpscr |= 1 << FPSCR_VXSOFT;
aurel32e0147e42008-12-15 17:13:55 +0000633 break;
j_mayer7c580442007-10-27 17:54:30 +0000634 case POWERPC_EXCP_FP_VXISI:
635 /* Magnitude subtraction of infinities */
636 env->fpscr |= 1 << FPSCR_VXISI;
637 goto update_arith;
638 case POWERPC_EXCP_FP_VXIDI:
639 /* Division of infinity by infinity */
640 env->fpscr |= 1 << FPSCR_VXIDI;
641 goto update_arith;
642 case POWERPC_EXCP_FP_VXZDZ:
643 /* Division of zero by zero */
644 env->fpscr |= 1 << FPSCR_VXZDZ;
645 goto update_arith;
646 case POWERPC_EXCP_FP_VXIMZ:
647 /* Multiplication of zero by infinity */
648 env->fpscr |= 1 << FPSCR_VXIMZ;
649 goto update_arith;
650 case POWERPC_EXCP_FP_VXVC:
651 /* Ordered comparison of NaN */
652 env->fpscr |= 1 << FPSCR_VXVC;
653 env->fpscr &= ~(0xF << FPSCR_FPCC);
654 env->fpscr |= 0x11 << FPSCR_FPCC;
655 /* We must update the target FPR before raising the exception */
656 if (ve != 0) {
657 env->exception_index = POWERPC_EXCP_PROGRAM;
658 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
659 /* Update the floating-point enabled exception summary */
660 env->fpscr |= 1 << FPSCR_FEX;
661 /* Exception is differed */
662 ve = 0;
663 }
664 break;
665 case POWERPC_EXCP_FP_VXSQRT:
666 /* Square root of a negative number */
667 env->fpscr |= 1 << FPSCR_VXSQRT;
668 update_arith:
669 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
670 if (ve == 0) {
671 /* Set the result to quiet NaN */
aurel32e0147e42008-12-15 17:13:55 +0000672 ret = 0xFFF8000000000000ULL;
j_mayer7c580442007-10-27 17:54:30 +0000673 env->fpscr &= ~(0xF << FPSCR_FPCC);
674 env->fpscr |= 0x11 << FPSCR_FPCC;
675 }
676 break;
677 case POWERPC_EXCP_FP_VXCVI:
678 /* Invalid conversion */
679 env->fpscr |= 1 << FPSCR_VXCVI;
680 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
681 if (ve == 0) {
682 /* Set the result to quiet NaN */
aurel32e0147e42008-12-15 17:13:55 +0000683 ret = 0xFFF8000000000000ULL;
j_mayer7c580442007-10-27 17:54:30 +0000684 env->fpscr &= ~(0xF << FPSCR_FPCC);
685 env->fpscr |= 0x11 << FPSCR_FPCC;
686 }
687 break;
688 }
689 /* Update the floating-point invalid operation summary */
690 env->fpscr |= 1 << FPSCR_VX;
691 /* Update the floating-point exception summary */
692 env->fpscr |= 1 << FPSCR_FX;
693 if (ve != 0) {
694 /* Update the floating-point enabled exception summary */
695 env->fpscr |= 1 << FPSCR_FEX;
696 if (msr_fe0 != 0 || msr_fe1 != 0)
aurel32e06fcd72008-12-11 22:42:14 +0000697 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
j_mayer7c580442007-10-27 17:54:30 +0000698 }
aurel32af129062008-11-19 16:10:23 +0000699 return ret;
j_mayer7c580442007-10-27 17:54:30 +0000700}
701
aurel32e33e94f2008-12-18 22:44:21 +0000702static always_inline void float_zero_divide_excp (void)
j_mayer7c580442007-10-27 17:54:30 +0000703{
j_mayer7c580442007-10-27 17:54:30 +0000704 env->fpscr |= 1 << FPSCR_ZX;
705 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
706 /* Update the floating-point exception summary */
707 env->fpscr |= 1 << FPSCR_FX;
708 if (fpscr_ze != 0) {
709 /* Update the floating-point enabled exception summary */
710 env->fpscr |= 1 << FPSCR_FEX;
711 if (msr_fe0 != 0 || msr_fe1 != 0) {
aurel32e06fcd72008-12-11 22:42:14 +0000712 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
713 POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
j_mayer7c580442007-10-27 17:54:30 +0000714 }
j_mayer7c580442007-10-27 17:54:30 +0000715 }
716}
717
718static always_inline void float_overflow_excp (void)
719{
720 env->fpscr |= 1 << FPSCR_OX;
721 /* Update the floating-point exception summary */
722 env->fpscr |= 1 << FPSCR_FX;
723 if (fpscr_oe != 0) {
724 /* XXX: should adjust the result */
725 /* Update the floating-point enabled exception summary */
726 env->fpscr |= 1 << FPSCR_FEX;
727 /* We must update the target FPR before raising the exception */
728 env->exception_index = POWERPC_EXCP_PROGRAM;
729 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
730 } else {
731 env->fpscr |= 1 << FPSCR_XX;
732 env->fpscr |= 1 << FPSCR_FI;
733 }
734}
735
736static always_inline void float_underflow_excp (void)
737{
738 env->fpscr |= 1 << FPSCR_UX;
739 /* Update the floating-point exception summary */
740 env->fpscr |= 1 << FPSCR_FX;
741 if (fpscr_ue != 0) {
742 /* XXX: should adjust the result */
743 /* Update the floating-point enabled exception summary */
744 env->fpscr |= 1 << FPSCR_FEX;
745 /* We must update the target FPR before raising the exception */
746 env->exception_index = POWERPC_EXCP_PROGRAM;
747 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
748 }
749}
750
751static always_inline void float_inexact_excp (void)
752{
753 env->fpscr |= 1 << FPSCR_XX;
754 /* Update the floating-point exception summary */
755 env->fpscr |= 1 << FPSCR_FX;
756 if (fpscr_xe != 0) {
757 /* Update the floating-point enabled exception summary */
758 env->fpscr |= 1 << FPSCR_FEX;
759 /* We must update the target FPR before raising the exception */
760 env->exception_index = POWERPC_EXCP_PROGRAM;
761 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
762 }
763}
764
765static always_inline void fpscr_set_rounding_mode (void)
766{
767 int rnd_type;
768
769 /* Set rounding mode */
770 switch (fpscr_rn) {
771 case 0:
772 /* Best approximation (round to nearest) */
773 rnd_type = float_round_nearest_even;
774 break;
775 case 1:
776 /* Smaller magnitude (round toward zero) */
777 rnd_type = float_round_to_zero;
778 break;
779 case 2:
780 /* Round toward +infinite */
781 rnd_type = float_round_up;
782 break;
783 default:
784 case 3:
785 /* Round toward -infinite */
786 rnd_type = float_round_down;
787 break;
788 }
789 set_float_rounding_mode(rnd_type, &env->fp_status);
790}
791
aurel326e35d522008-12-14 18:40:58 +0000792void helper_fpscr_clrbit (uint32_t bit)
793{
794 int prev;
795
796 prev = (env->fpscr >> bit) & 1;
797 env->fpscr &= ~(1 << bit);
798 if (prev == 1) {
799 switch (bit) {
800 case FPSCR_RN1:
801 case FPSCR_RN:
802 fpscr_set_rounding_mode();
803 break;
804 default:
805 break;
806 }
807 }
808}
809
aurel32af129062008-11-19 16:10:23 +0000810void helper_fpscr_setbit (uint32_t bit)
j_mayer7c580442007-10-27 17:54:30 +0000811{
812 int prev;
813
814 prev = (env->fpscr >> bit) & 1;
815 env->fpscr |= 1 << bit;
816 if (prev == 0) {
817 switch (bit) {
818 case FPSCR_VX:
819 env->fpscr |= 1 << FPSCR_FX;
820 if (fpscr_ve)
821 goto raise_ve;
822 case FPSCR_OX:
823 env->fpscr |= 1 << FPSCR_FX;
824 if (fpscr_oe)
825 goto raise_oe;
826 break;
827 case FPSCR_UX:
828 env->fpscr |= 1 << FPSCR_FX;
829 if (fpscr_ue)
830 goto raise_ue;
831 break;
832 case FPSCR_ZX:
833 env->fpscr |= 1 << FPSCR_FX;
834 if (fpscr_ze)
835 goto raise_ze;
836 break;
837 case FPSCR_XX:
838 env->fpscr |= 1 << FPSCR_FX;
839 if (fpscr_xe)
840 goto raise_xe;
841 break;
842 case FPSCR_VXSNAN:
843 case FPSCR_VXISI:
844 case FPSCR_VXIDI:
845 case FPSCR_VXZDZ:
846 case FPSCR_VXIMZ:
847 case FPSCR_VXVC:
848 case FPSCR_VXSOFT:
849 case FPSCR_VXSQRT:
850 case FPSCR_VXCVI:
851 env->fpscr |= 1 << FPSCR_VX;
852 env->fpscr |= 1 << FPSCR_FX;
853 if (fpscr_ve != 0)
854 goto raise_ve;
855 break;
856 case FPSCR_VE:
857 if (fpscr_vx != 0) {
858 raise_ve:
859 env->error_code = POWERPC_EXCP_FP;
860 if (fpscr_vxsnan)
861 env->error_code |= POWERPC_EXCP_FP_VXSNAN;
862 if (fpscr_vxisi)
863 env->error_code |= POWERPC_EXCP_FP_VXISI;
864 if (fpscr_vxidi)
865 env->error_code |= POWERPC_EXCP_FP_VXIDI;
866 if (fpscr_vxzdz)
867 env->error_code |= POWERPC_EXCP_FP_VXZDZ;
868 if (fpscr_vximz)
869 env->error_code |= POWERPC_EXCP_FP_VXIMZ;
870 if (fpscr_vxvc)
871 env->error_code |= POWERPC_EXCP_FP_VXVC;
872 if (fpscr_vxsoft)
873 env->error_code |= POWERPC_EXCP_FP_VXSOFT;
874 if (fpscr_vxsqrt)
875 env->error_code |= POWERPC_EXCP_FP_VXSQRT;
876 if (fpscr_vxcvi)
877 env->error_code |= POWERPC_EXCP_FP_VXCVI;
878 goto raise_excp;
879 }
880 break;
881 case FPSCR_OE:
882 if (fpscr_ox != 0) {
883 raise_oe:
884 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
885 goto raise_excp;
886 }
887 break;
888 case FPSCR_UE:
889 if (fpscr_ux != 0) {
890 raise_ue:
891 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
892 goto raise_excp;
893 }
894 break;
895 case FPSCR_ZE:
896 if (fpscr_zx != 0) {
897 raise_ze:
898 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
899 goto raise_excp;
900 }
901 break;
902 case FPSCR_XE:
903 if (fpscr_xx != 0) {
904 raise_xe:
905 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
906 goto raise_excp;
907 }
908 break;
909 case FPSCR_RN1:
910 case FPSCR_RN:
911 fpscr_set_rounding_mode();
912 break;
913 default:
914 break;
915 raise_excp:
916 /* Update the floating-point enabled exception summary */
917 env->fpscr |= 1 << FPSCR_FEX;
918 /* We have to update Rc1 before raising the exception */
919 env->exception_index = POWERPC_EXCP_PROGRAM;
920 break;
921 }
922 }
923}
924
aurel32af129062008-11-19 16:10:23 +0000925void helper_store_fpscr (uint64_t arg, uint32_t mask)
j_mayer7c580442007-10-27 17:54:30 +0000926{
927 /*
928 * We use only the 32 LSB of the incoming fpr
929 */
j_mayer7c580442007-10-27 17:54:30 +0000930 uint32_t prev, new;
931 int i;
932
j_mayer7c580442007-10-27 17:54:30 +0000933 prev = env->fpscr;
aurel32af129062008-11-19 16:10:23 +0000934 new = (uint32_t)arg;
aurel3227ee5df2008-12-15 00:30:28 +0000935 new &= ~0x60000000;
936 new |= prev & 0x60000000;
937 for (i = 0; i < 8; i++) {
j_mayer7c580442007-10-27 17:54:30 +0000938 if (mask & (1 << i)) {
939 env->fpscr &= ~(0xF << (4 * i));
940 env->fpscr |= new & (0xF << (4 * i));
941 }
942 }
943 /* Update VX and FEX */
944 if (fpscr_ix != 0)
945 env->fpscr |= 1 << FPSCR_VX;
aurel3255670252008-03-10 00:09:28 +0000946 else
947 env->fpscr &= ~(1 << FPSCR_VX);
j_mayer7c580442007-10-27 17:54:30 +0000948 if ((fpscr_ex & fpscr_eex) != 0) {
949 env->fpscr |= 1 << FPSCR_FEX;
950 env->exception_index = POWERPC_EXCP_PROGRAM;
951 /* XXX: we should compute it properly */
952 env->error_code = POWERPC_EXCP_FP;
953 }
aurel3255670252008-03-10 00:09:28 +0000954 else
955 env->fpscr &= ~(1 << FPSCR_FEX);
j_mayer7c580442007-10-27 17:54:30 +0000956 fpscr_set_rounding_mode();
957}
j_mayer7c580442007-10-27 17:54:30 +0000958
aurel32af129062008-11-19 16:10:23 +0000959void helper_float_check_status (void)
j_mayer7c580442007-10-27 17:54:30 +0000960{
aurel32af129062008-11-19 16:10:23 +0000961#ifdef CONFIG_SOFTFLOAT
j_mayer7c580442007-10-27 17:54:30 +0000962 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
963 (env->error_code & POWERPC_EXCP_FP)) {
964 /* Differred floating-point exception after target FPR update */
965 if (msr_fe0 != 0 || msr_fe1 != 0)
aurel32e06fcd72008-12-11 22:42:14 +0000966 helper_raise_exception_err(env->exception_index, env->error_code);
aurel32be94c952008-12-13 12:13:33 +0000967 } else {
968 int status = get_float_exception_flags(&env->fp_status);
aurel32e33e94f2008-12-18 22:44:21 +0000969 if (status & float_flag_divbyzero) {
970 float_zero_divide_excp();
971 } else if (status & float_flag_overflow) {
aurel32be94c952008-12-13 12:13:33 +0000972 float_overflow_excp();
973 } else if (status & float_flag_underflow) {
974 float_underflow_excp();
975 } else if (status & float_flag_inexact) {
976 float_inexact_excp();
977 }
j_mayer7c580442007-10-27 17:54:30 +0000978 }
aurel32af129062008-11-19 16:10:23 +0000979#else
980 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
981 (env->error_code & POWERPC_EXCP_FP)) {
982 /* Differred floating-point exception after target FPR update */
983 if (msr_fe0 != 0 || msr_fe1 != 0)
aurel32e06fcd72008-12-11 22:42:14 +0000984 helper_raise_exception_err(env->exception_index, env->error_code);
aurel32af129062008-11-19 16:10:23 +0000985 }
aurel32af129062008-11-19 16:10:23 +0000986#endif
987}
988
989#ifdef CONFIG_SOFTFLOAT
990void helper_reset_fpstatus (void)
991{
aurel32be94c952008-12-13 12:13:33 +0000992 set_float_exception_flags(0, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +0000993}
994#endif
995
aurel32af129062008-11-19 16:10:23 +0000996/* fadd - fadd. */
997uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
998{
999 CPU_DoubleU farg1, farg2;
1000
1001 farg1.ll = arg1;
1002 farg2.ll = arg2;
aurel321cdb9c32008-04-07 21:24:25 +00001003#if USE_PRECISE_EMULATION
aurel32af129062008-11-19 16:10:23 +00001004 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1005 float64_is_signaling_nan(farg2.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001006 /* sNaN addition */
aurel32af129062008-11-19 16:10:23 +00001007 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel3217218d12008-12-15 17:14:35 +00001008 } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1009 float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001010 /* Magnitude subtraction of infinities */
aurel32cf1cf212008-12-13 11:46:36 +00001011 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
aurel3217218d12008-12-15 17:14:35 +00001012 } else {
1013 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001014 }
aurel32af129062008-11-19 16:10:23 +00001015#else
1016 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
1017#endif
1018 return farg1.ll;
j_mayer7c580442007-10-27 17:54:30 +00001019}
1020
aurel32af129062008-11-19 16:10:23 +00001021/* fsub - fsub. */
1022uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
j_mayer7c580442007-10-27 17:54:30 +00001023{
aurel32af129062008-11-19 16:10:23 +00001024 CPU_DoubleU farg1, farg2;
1025
1026 farg1.ll = arg1;
1027 farg2.ll = arg2;
1028#if USE_PRECISE_EMULATION
1029{
1030 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1031 float64_is_signaling_nan(farg2.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001032 /* sNaN subtraction */
aurel32af129062008-11-19 16:10:23 +00001033 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel3217218d12008-12-15 17:14:35 +00001034 } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1035 float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001036 /* Magnitude subtraction of infinities */
aurel32af129062008-11-19 16:10:23 +00001037 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
aurel3217218d12008-12-15 17:14:35 +00001038 } else {
1039 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001040 }
1041}
aurel32af129062008-11-19 16:10:23 +00001042#else
1043 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
1044#endif
1045 return farg1.ll;
1046}
j_mayer7c580442007-10-27 17:54:30 +00001047
aurel32af129062008-11-19 16:10:23 +00001048/* fmul - fmul. */
1049uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
j_mayer7c580442007-10-27 17:54:30 +00001050{
aurel32af129062008-11-19 16:10:23 +00001051 CPU_DoubleU farg1, farg2;
1052
1053 farg1.ll = arg1;
1054 farg2.ll = arg2;
1055#if USE_PRECISE_EMULATION
1056 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1057 float64_is_signaling_nan(farg2.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001058 /* sNaN multiplication */
aurel32af129062008-11-19 16:10:23 +00001059 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel32f23c3462008-12-15 17:14:27 +00001060 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1061 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
j_mayer7c580442007-10-27 17:54:30 +00001062 /* Multiplication of zero by infinity */
aurel32af129062008-11-19 16:10:23 +00001063 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
j_mayer7c580442007-10-27 17:54:30 +00001064 } else {
aurel32af129062008-11-19 16:10:23 +00001065 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001066 }
aurel32af129062008-11-19 16:10:23 +00001067#else
1068 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1069#endif
1070 return farg1.ll;
1071}
j_mayer7c580442007-10-27 17:54:30 +00001072
aurel32af129062008-11-19 16:10:23 +00001073/* fdiv - fdiv. */
1074uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
j_mayer7c580442007-10-27 17:54:30 +00001075{
aurel32af129062008-11-19 16:10:23 +00001076 CPU_DoubleU farg1, farg2;
1077
1078 farg1.ll = arg1;
1079 farg2.ll = arg2;
1080#if USE_PRECISE_EMULATION
1081 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1082 float64_is_signaling_nan(farg2.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001083 /* sNaN division */
aurel32af129062008-11-19 16:10:23 +00001084 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel32f23c3462008-12-15 17:14:27 +00001085 } else if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001086 /* Division of infinity by infinity */
aurel32af129062008-11-19 16:10:23 +00001087 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
aurel32e33e94f2008-12-18 22:44:21 +00001088 } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
1089 /* Division of zero by zero */
1090 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
j_mayer7c580442007-10-27 17:54:30 +00001091 } else {
aurel32af129062008-11-19 16:10:23 +00001092 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001093 }
aurel32af129062008-11-19 16:10:23 +00001094#else
1095 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
1096#endif
1097 return farg1.ll;
j_mayer7c580442007-10-27 17:54:30 +00001098}
j_mayer7c580442007-10-27 17:54:30 +00001099
aurel32af129062008-11-19 16:10:23 +00001100/* fabs */
1101uint64_t helper_fabs (uint64_t arg)
bellard9a64fbe2004-01-04 22:58:38 +00001102{
aurel32af129062008-11-19 16:10:23 +00001103 CPU_DoubleU farg;
bellard9a64fbe2004-01-04 22:58:38 +00001104
aurel32af129062008-11-19 16:10:23 +00001105 farg.ll = arg;
1106 farg.d = float64_abs(farg.d);
1107 return farg.ll;
1108}
1109
1110/* fnabs */
1111uint64_t helper_fnabs (uint64_t arg)
1112{
1113 CPU_DoubleU farg;
1114
1115 farg.ll = arg;
1116 farg.d = float64_abs(farg.d);
1117 farg.d = float64_chs(farg.d);
1118 return farg.ll;
1119}
1120
1121/* fneg */
1122uint64_t helper_fneg (uint64_t arg)
1123{
1124 CPU_DoubleU farg;
1125
1126 farg.ll = arg;
1127 farg.d = float64_chs(farg.d);
1128 return farg.ll;
1129}
1130
1131/* fctiw - fctiw. */
1132uint64_t helper_fctiw (uint64_t arg)
1133{
1134 CPU_DoubleU farg;
1135 farg.ll = arg;
1136
1137 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001138 /* sNaN conversion */
aurel32af129062008-11-19 16:10:23 +00001139 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
aurel32f23c3462008-12-15 17:14:27 +00001140 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001141 /* qNan / infinity conversion */
aurel32af129062008-11-19 16:10:23 +00001142 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
j_mayer7c580442007-10-27 17:54:30 +00001143 } else {
aurel32af129062008-11-19 16:10:23 +00001144 farg.ll = float64_to_int32(farg.d, &env->fp_status);
aurel321cdb9c32008-04-07 21:24:25 +00001145#if USE_PRECISE_EMULATION
j_mayer7c580442007-10-27 17:54:30 +00001146 /* XXX: higher bits are not supposed to be significant.
1147 * to make tests easier, return the same as a real PowerPC 750
1148 */
aurel32af129062008-11-19 16:10:23 +00001149 farg.ll |= 0xFFF80000ULL << 32;
j_mayere864cab2007-03-22 22:17:08 +00001150#endif
j_mayer7c580442007-10-27 17:54:30 +00001151 }
aurel32af129062008-11-19 16:10:23 +00001152 return farg.ll;
bellard9a64fbe2004-01-04 22:58:38 +00001153}
1154
aurel32af129062008-11-19 16:10:23 +00001155/* fctiwz - fctiwz. */
1156uint64_t helper_fctiwz (uint64_t arg)
bellard9a64fbe2004-01-04 22:58:38 +00001157{
aurel32af129062008-11-19 16:10:23 +00001158 CPU_DoubleU farg;
1159 farg.ll = arg;
bellard9a64fbe2004-01-04 22:58:38 +00001160
aurel32af129062008-11-19 16:10:23 +00001161 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001162 /* sNaN conversion */
aurel32af129062008-11-19 16:10:23 +00001163 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
aurel32f23c3462008-12-15 17:14:27 +00001164 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001165 /* qNan / infinity conversion */
aurel32af129062008-11-19 16:10:23 +00001166 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
j_mayer7c580442007-10-27 17:54:30 +00001167 } else {
aurel32af129062008-11-19 16:10:23 +00001168 farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
aurel321cdb9c32008-04-07 21:24:25 +00001169#if USE_PRECISE_EMULATION
j_mayer7c580442007-10-27 17:54:30 +00001170 /* XXX: higher bits are not supposed to be significant.
1171 * to make tests easier, return the same as a real PowerPC 750
1172 */
aurel32af129062008-11-19 16:10:23 +00001173 farg.ll |= 0xFFF80000ULL << 32;
j_mayere864cab2007-03-22 22:17:08 +00001174#endif
j_mayer7c580442007-10-27 17:54:30 +00001175 }
aurel32af129062008-11-19 16:10:23 +00001176 return farg.ll;
bellard9a64fbe2004-01-04 22:58:38 +00001177}
1178
j_mayer426613d2007-03-23 09:45:27 +00001179#if defined(TARGET_PPC64)
aurel32af129062008-11-19 16:10:23 +00001180/* fcfid - fcfid. */
1181uint64_t helper_fcfid (uint64_t arg)
j_mayer426613d2007-03-23 09:45:27 +00001182{
aurel32af129062008-11-19 16:10:23 +00001183 CPU_DoubleU farg;
1184 farg.d = int64_to_float64(arg, &env->fp_status);
1185 return farg.ll;
j_mayer426613d2007-03-23 09:45:27 +00001186}
1187
aurel32af129062008-11-19 16:10:23 +00001188/* fctid - fctid. */
1189uint64_t helper_fctid (uint64_t arg)
j_mayer426613d2007-03-23 09:45:27 +00001190{
aurel32af129062008-11-19 16:10:23 +00001191 CPU_DoubleU farg;
1192 farg.ll = arg;
j_mayer426613d2007-03-23 09:45:27 +00001193
aurel32af129062008-11-19 16:10:23 +00001194 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001195 /* sNaN conversion */
aurel32af129062008-11-19 16:10:23 +00001196 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
aurel32f23c3462008-12-15 17:14:27 +00001197 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001198 /* qNan / infinity conversion */
aurel32af129062008-11-19 16:10:23 +00001199 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
j_mayer7c580442007-10-27 17:54:30 +00001200 } else {
aurel32af129062008-11-19 16:10:23 +00001201 farg.ll = float64_to_int64(farg.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001202 }
aurel32af129062008-11-19 16:10:23 +00001203 return farg.ll;
j_mayer426613d2007-03-23 09:45:27 +00001204}
1205
aurel32af129062008-11-19 16:10:23 +00001206/* fctidz - fctidz. */
1207uint64_t helper_fctidz (uint64_t arg)
j_mayer426613d2007-03-23 09:45:27 +00001208{
aurel32af129062008-11-19 16:10:23 +00001209 CPU_DoubleU farg;
1210 farg.ll = arg;
j_mayer426613d2007-03-23 09:45:27 +00001211
aurel32af129062008-11-19 16:10:23 +00001212 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001213 /* sNaN conversion */
aurel32af129062008-11-19 16:10:23 +00001214 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
aurel32f23c3462008-12-15 17:14:27 +00001215 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001216 /* qNan / infinity conversion */
aurel32af129062008-11-19 16:10:23 +00001217 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
j_mayer7c580442007-10-27 17:54:30 +00001218 } else {
aurel32af129062008-11-19 16:10:23 +00001219 farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001220 }
aurel32af129062008-11-19 16:10:23 +00001221 return farg.ll;
j_mayer426613d2007-03-23 09:45:27 +00001222}
1223
1224#endif
1225
aurel32af129062008-11-19 16:10:23 +00001226static always_inline uint64_t do_fri (uint64_t arg, int rounding_mode)
j_mayerd7e4b872007-09-30 01:11:48 +00001227{
aurel32af129062008-11-19 16:10:23 +00001228 CPU_DoubleU farg;
1229 farg.ll = arg;
1230
1231 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001232 /* sNaN round */
aurel32af129062008-11-19 16:10:23 +00001233 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
aurel32f23c3462008-12-15 17:14:27 +00001234 } else if (unlikely(float64_is_nan(farg.d) || float64_is_infinity(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001235 /* qNan / infinity round */
aurel32af129062008-11-19 16:10:23 +00001236 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
j_mayer7c580442007-10-27 17:54:30 +00001237 } else {
1238 set_float_rounding_mode(rounding_mode, &env->fp_status);
aurel32af129062008-11-19 16:10:23 +00001239 farg.ll = float64_round_to_int(farg.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001240 /* Restore rounding mode from FPSCR */
1241 fpscr_set_rounding_mode();
1242 }
aurel32af129062008-11-19 16:10:23 +00001243 return farg.ll;
j_mayerd7e4b872007-09-30 01:11:48 +00001244}
1245
aurel32af129062008-11-19 16:10:23 +00001246uint64_t helper_frin (uint64_t arg)
j_mayerd7e4b872007-09-30 01:11:48 +00001247{
aurel32af129062008-11-19 16:10:23 +00001248 return do_fri(arg, float_round_nearest_even);
j_mayerd7e4b872007-09-30 01:11:48 +00001249}
1250
aurel32af129062008-11-19 16:10:23 +00001251uint64_t helper_friz (uint64_t arg)
j_mayerd7e4b872007-09-30 01:11:48 +00001252{
aurel32af129062008-11-19 16:10:23 +00001253 return do_fri(arg, float_round_to_zero);
j_mayerd7e4b872007-09-30 01:11:48 +00001254}
1255
aurel32af129062008-11-19 16:10:23 +00001256uint64_t helper_frip (uint64_t arg)
j_mayerd7e4b872007-09-30 01:11:48 +00001257{
aurel32af129062008-11-19 16:10:23 +00001258 return do_fri(arg, float_round_up);
j_mayerd7e4b872007-09-30 01:11:48 +00001259}
1260
aurel32af129062008-11-19 16:10:23 +00001261uint64_t helper_frim (uint64_t arg)
j_mayerd7e4b872007-09-30 01:11:48 +00001262{
aurel32af129062008-11-19 16:10:23 +00001263 return do_fri(arg, float_round_down);
j_mayerd7e4b872007-09-30 01:11:48 +00001264}
1265
aurel32af129062008-11-19 16:10:23 +00001266/* fmadd - fmadd. */
1267uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1268{
1269 CPU_DoubleU farg1, farg2, farg3;
1270
1271 farg1.ll = arg1;
1272 farg2.ll = arg2;
1273 farg3.ll = arg3;
aurel321cdb9c32008-04-07 21:24:25 +00001274#if USE_PRECISE_EMULATION
aurel32af129062008-11-19 16:10:23 +00001275 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1276 float64_is_signaling_nan(farg2.d) ||
1277 float64_is_signaling_nan(farg3.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001278 /* sNaN operation */
aurel32af129062008-11-19 16:10:23 +00001279 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel32da1e7ac2008-12-15 17:14:43 +00001280 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1281 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1282 /* Multiplication of zero by infinity */
1283 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
j_mayer7c580442007-10-27 17:54:30 +00001284 } else {
j_mayere864cab2007-03-22 22:17:08 +00001285#ifdef FLOAT128
j_mayer7c580442007-10-27 17:54:30 +00001286 /* This is the way the PowerPC specification defines it */
1287 float128 ft0_128, ft1_128;
j_mayere864cab2007-03-22 22:17:08 +00001288
aurel32af129062008-11-19 16:10:23 +00001289 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1290 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001291 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
aurel32da1e7ac2008-12-15 17:14:43 +00001292 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1293 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1294 /* Magnitude subtraction of infinities */
1295 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1296 } else {
1297 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1298 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1299 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1300 }
j_mayere864cab2007-03-22 22:17:08 +00001301#else
j_mayer7c580442007-10-27 17:54:30 +00001302 /* This is OK on x86 hosts */
aurel32af129062008-11-19 16:10:23 +00001303 farg1.d = (farg1.d * farg2.d) + farg3.d;
j_mayere864cab2007-03-22 22:17:08 +00001304#endif
j_mayer7c580442007-10-27 17:54:30 +00001305 }
aurel32af129062008-11-19 16:10:23 +00001306#else
1307 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1308 farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
1309#endif
1310 return farg1.ll;
j_mayere864cab2007-03-22 22:17:08 +00001311}
1312
aurel32af129062008-11-19 16:10:23 +00001313/* fmsub - fmsub. */
1314uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
j_mayere864cab2007-03-22 22:17:08 +00001315{
aurel32af129062008-11-19 16:10:23 +00001316 CPU_DoubleU farg1, farg2, farg3;
1317
1318 farg1.ll = arg1;
1319 farg2.ll = arg2;
1320 farg3.ll = arg3;
1321#if USE_PRECISE_EMULATION
1322 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1323 float64_is_signaling_nan(farg2.d) ||
1324 float64_is_signaling_nan(farg3.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001325 /* sNaN operation */
aurel32af129062008-11-19 16:10:23 +00001326 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel32da1e7ac2008-12-15 17:14:43 +00001327 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1328 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1329 /* Multiplication of zero by infinity */
1330 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
j_mayer7c580442007-10-27 17:54:30 +00001331 } else {
j_mayere864cab2007-03-22 22:17:08 +00001332#ifdef FLOAT128
j_mayer7c580442007-10-27 17:54:30 +00001333 /* This is the way the PowerPC specification defines it */
1334 float128 ft0_128, ft1_128;
j_mayere864cab2007-03-22 22:17:08 +00001335
aurel32af129062008-11-19 16:10:23 +00001336 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1337 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001338 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
aurel32da1e7ac2008-12-15 17:14:43 +00001339 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1340 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1341 /* Magnitude subtraction of infinities */
1342 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1343 } else {
1344 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1345 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1346 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1347 }
j_mayere864cab2007-03-22 22:17:08 +00001348#else
j_mayer7c580442007-10-27 17:54:30 +00001349 /* This is OK on x86 hosts */
aurel32af129062008-11-19 16:10:23 +00001350 farg1.d = (farg1.d * farg2.d) - farg3.d;
j_mayere864cab2007-03-22 22:17:08 +00001351#endif
j_mayer7c580442007-10-27 17:54:30 +00001352 }
aurel32af129062008-11-19 16:10:23 +00001353#else
1354 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1355 farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
1356#endif
1357 return farg1.ll;
j_mayere864cab2007-03-22 22:17:08 +00001358}
j_mayere864cab2007-03-22 22:17:08 +00001359
aurel32af129062008-11-19 16:10:23 +00001360/* fnmadd - fnmadd. */
1361uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
bellard4b3686f2004-05-23 22:18:12 +00001362{
aurel32af129062008-11-19 16:10:23 +00001363 CPU_DoubleU farg1, farg2, farg3;
1364
1365 farg1.ll = arg1;
1366 farg2.ll = arg2;
1367 farg3.ll = arg3;
1368
1369 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1370 float64_is_signaling_nan(farg2.d) ||
1371 float64_is_signaling_nan(farg3.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001372 /* sNaN operation */
aurel32af129062008-11-19 16:10:23 +00001373 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel32da1e7ac2008-12-15 17:14:43 +00001374 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1375 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1376 /* Multiplication of zero by infinity */
1377 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
j_mayer7c580442007-10-27 17:54:30 +00001378 } else {
aurel321cdb9c32008-04-07 21:24:25 +00001379#if USE_PRECISE_EMULATION
j_mayere864cab2007-03-22 22:17:08 +00001380#ifdef FLOAT128
j_mayer7c580442007-10-27 17:54:30 +00001381 /* This is the way the PowerPC specification defines it */
1382 float128 ft0_128, ft1_128;
j_mayere864cab2007-03-22 22:17:08 +00001383
aurel32af129062008-11-19 16:10:23 +00001384 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1385 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001386 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
aurel32da1e7ac2008-12-15 17:14:43 +00001387 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1388 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1389 /* Magnitude subtraction of infinities */
1390 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1391 } else {
1392 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1393 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1394 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1395 }
j_mayere864cab2007-03-22 22:17:08 +00001396#else
j_mayer7c580442007-10-27 17:54:30 +00001397 /* This is OK on x86 hosts */
aurel32af129062008-11-19 16:10:23 +00001398 farg1.d = (farg1.d * farg2.d) + farg3.d;
j_mayere864cab2007-03-22 22:17:08 +00001399#endif
1400#else
aurel32af129062008-11-19 16:10:23 +00001401 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1402 farg1.d = float64_add(farg1.d, farg3.d, &env->fp_status);
j_mayere864cab2007-03-22 22:17:08 +00001403#endif
aurel32a44d2ce2008-12-13 11:46:27 +00001404 if (likely(!float64_is_nan(farg1.d)))
aurel32af129062008-11-19 16:10:23 +00001405 farg1.d = float64_chs(farg1.d);
j_mayer7c580442007-10-27 17:54:30 +00001406 }
aurel32af129062008-11-19 16:10:23 +00001407 return farg1.ll;
bellard4b3686f2004-05-23 22:18:12 +00001408}
1409
aurel32af129062008-11-19 16:10:23 +00001410/* fnmsub - fnmsub. */
1411uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
bellard4b3686f2004-05-23 22:18:12 +00001412{
aurel32af129062008-11-19 16:10:23 +00001413 CPU_DoubleU farg1, farg2, farg3;
1414
1415 farg1.ll = arg1;
1416 farg2.ll = arg2;
1417 farg3.ll = arg3;
1418
1419 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1420 float64_is_signaling_nan(farg2.d) ||
1421 float64_is_signaling_nan(farg3.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001422 /* sNaN operation */
aurel32af129062008-11-19 16:10:23 +00001423 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel32da1e7ac2008-12-15 17:14:43 +00001424 } else if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1425 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1426 /* Multiplication of zero by infinity */
1427 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
j_mayer7c580442007-10-27 17:54:30 +00001428 } else {
aurel321cdb9c32008-04-07 21:24:25 +00001429#if USE_PRECISE_EMULATION
j_mayere864cab2007-03-22 22:17:08 +00001430#ifdef FLOAT128
j_mayer7c580442007-10-27 17:54:30 +00001431 /* This is the way the PowerPC specification defines it */
1432 float128 ft0_128, ft1_128;
j_mayere864cab2007-03-22 22:17:08 +00001433
aurel32af129062008-11-19 16:10:23 +00001434 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1435 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001436 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
aurel32da1e7ac2008-12-15 17:14:43 +00001437 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1438 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1439 /* Magnitude subtraction of infinities */
1440 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1441 } else {
1442 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1443 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1444 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1445 }
j_mayere864cab2007-03-22 22:17:08 +00001446#else
j_mayer7c580442007-10-27 17:54:30 +00001447 /* This is OK on x86 hosts */
aurel32af129062008-11-19 16:10:23 +00001448 farg1.d = (farg1.d * farg2.d) - farg3.d;
j_mayere864cab2007-03-22 22:17:08 +00001449#endif
1450#else
aurel32af129062008-11-19 16:10:23 +00001451 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
1452 farg1.d = float64_sub(farg1.d, farg3.d, &env->fp_status);
j_mayere864cab2007-03-22 22:17:08 +00001453#endif
aurel32a44d2ce2008-12-13 11:46:27 +00001454 if (likely(!float64_is_nan(farg1.d)))
aurel32af129062008-11-19 16:10:23 +00001455 farg1.d = float64_chs(farg1.d);
j_mayer7c580442007-10-27 17:54:30 +00001456 }
aurel32af129062008-11-19 16:10:23 +00001457 return farg1.ll;
bellard1ef59d02004-04-26 19:48:05 +00001458}
1459
aurel32af129062008-11-19 16:10:23 +00001460/* frsp - frsp. */
1461uint64_t helper_frsp (uint64_t arg)
1462{
1463 CPU_DoubleU farg;
aurel326ad193e2008-12-15 01:00:17 +00001464 float32 f32;
aurel32af129062008-11-19 16:10:23 +00001465 farg.ll = arg;
1466
aurel321cdb9c32008-04-07 21:24:25 +00001467#if USE_PRECISE_EMULATION
aurel32af129062008-11-19 16:10:23 +00001468 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001469 /* sNaN square root */
aurel32af129062008-11-19 16:10:23 +00001470 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
j_mayer7c580442007-10-27 17:54:30 +00001471 } else {
aurel326ad193e2008-12-15 01:00:17 +00001472 f32 = float64_to_float32(farg.d, &env->fp_status);
1473 farg.d = float32_to_float64(f32, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001474 }
aurel32af129062008-11-19 16:10:23 +00001475#else
aurel326ad193e2008-12-15 01:00:17 +00001476 f32 = float64_to_float32(farg.d, &env->fp_status);
1477 farg.d = float32_to_float64(f32, &env->fp_status);
aurel32af129062008-11-19 16:10:23 +00001478#endif
1479 return farg.ll;
j_mayer7c580442007-10-27 17:54:30 +00001480}
j_mayer7c580442007-10-27 17:54:30 +00001481
aurel32af129062008-11-19 16:10:23 +00001482/* fsqrt - fsqrt. */
1483uint64_t helper_fsqrt (uint64_t arg)
bellard9a64fbe2004-01-04 22:58:38 +00001484{
aurel32af129062008-11-19 16:10:23 +00001485 CPU_DoubleU farg;
1486 farg.ll = arg;
1487
1488 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001489 /* sNaN square root */
aurel32af129062008-11-19 16:10:23 +00001490 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel32f23c3462008-12-15 17:14:27 +00001491 } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001492 /* Square root of a negative nonzero number */
aurel32af129062008-11-19 16:10:23 +00001493 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
j_mayer7c580442007-10-27 17:54:30 +00001494 } else {
aurel32af129062008-11-19 16:10:23 +00001495 farg.d = float64_sqrt(farg.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001496 }
aurel32af129062008-11-19 16:10:23 +00001497 return farg.ll;
bellard9a64fbe2004-01-04 22:58:38 +00001498}
1499
aurel32af129062008-11-19 16:10:23 +00001500/* fre - fre. */
1501uint64_t helper_fre (uint64_t arg)
j_mayerd7e4b872007-09-30 01:11:48 +00001502{
aurel3205b93602008-12-15 17:13:48 +00001503 CPU_DoubleU fone, farg;
aurel3201feec02008-12-16 10:44:29 +00001504 fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
aurel32af129062008-11-19 16:10:23 +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 {
aurel326c01bf62008-12-18 22:42:23 +00001511 farg.d = float64_div(fone.d, 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{
aurel3205b93602008-12-15 17:13:48 +00001519 CPU_DoubleU fone, farg;
aurel326c01bf62008-12-18 22:42:23 +00001520 float32 f32;
aurel3201feec02008-12-16 10:44:29 +00001521 fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
aurel32af129062008-11-19 16:10:23 +00001522 farg.ll = arg;
bellard4ecc3192005-03-13 17:01:22 +00001523
aurel32af129062008-11-19 16:10:23 +00001524 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001525 /* sNaN reciprocal */
aurel32af129062008-11-19 16:10:23 +00001526 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
bellard4ecc3192005-03-13 17:01:22 +00001527 } else {
aurel326c01bf62008-12-18 22:42:23 +00001528 farg.d = float64_div(fone.d, farg.d, &env->fp_status);
1529 f32 = float64_to_float32(farg.d, &env->fp_status);
1530 farg.d = float32_to_float64(f32, &env->fp_status);
bellard4ecc3192005-03-13 17:01:22 +00001531 }
aurel32af129062008-11-19 16:10:23 +00001532 return farg.ll;
bellard9a64fbe2004-01-04 22:58:38 +00001533}
1534
aurel32af129062008-11-19 16:10:23 +00001535/* frsqrte - frsqrte. */
1536uint64_t helper_frsqrte (uint64_t arg)
bellard9a64fbe2004-01-04 22:58:38 +00001537{
aurel3205b93602008-12-15 17:13:48 +00001538 CPU_DoubleU fone, farg;
aurel326c01bf62008-12-18 22:42:23 +00001539 float32 f32;
aurel3201feec02008-12-16 10:44:29 +00001540 fone.ll = 0x3FF0000000000000ULL; /* 1.0 */
aurel32af129062008-11-19 16:10:23 +00001541 farg.ll = arg;
bellard4ecc3192005-03-13 17:01:22 +00001542
aurel32af129062008-11-19 16:10:23 +00001543 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001544 /* sNaN reciprocal square root */
aurel32af129062008-11-19 16:10:23 +00001545 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
aurel32f23c3462008-12-15 17:14:27 +00001546 } else if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001547 /* Reciprocal square root of a negative nonzero number */
aurel32af129062008-11-19 16:10:23 +00001548 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
bellard4ecc3192005-03-13 17:01:22 +00001549 } else {
aurel326c01bf62008-12-18 22:42:23 +00001550 farg.d = float64_sqrt(farg.d, &env->fp_status);
1551 farg.d = float64_div(fone.d, farg.d, &env->fp_status);
1552 f32 = float64_to_float32(farg.d, &env->fp_status);
1553 farg.d = float32_to_float64(f32, &env->fp_status);
bellard4ecc3192005-03-13 17:01:22 +00001554 }
aurel32af129062008-11-19 16:10:23 +00001555 return farg.ll;
bellard9a64fbe2004-01-04 22:58:38 +00001556}
1557
aurel32af129062008-11-19 16:10:23 +00001558/* fsel - fsel. */
1559uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
bellard9a64fbe2004-01-04 22:58:38 +00001560{
aurel326ad73652008-12-14 11:12:10 +00001561 CPU_DoubleU farg1;
aurel32af129062008-11-19 16:10:23 +00001562
1563 farg1.ll = arg1;
aurel32af129062008-11-19 16:10:23 +00001564
aurel32572c8952008-12-29 09:47:11 +00001565 if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_nan(farg1.d))
aurel326ad73652008-12-14 11:12:10 +00001566 return arg2;
bellard4ecc3192005-03-13 17:01:22 +00001567 else
aurel326ad73652008-12-14 11:12:10 +00001568 return arg3;
bellard9a64fbe2004-01-04 22:58:38 +00001569}
1570
aurel329a819372008-12-14 19:34:09 +00001571void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
bellard9a64fbe2004-01-04 22:58:38 +00001572{
aurel32af129062008-11-19 16:10:23 +00001573 CPU_DoubleU farg1, farg2;
aurel32e1571902008-10-21 11:31:14 +00001574 uint32_t ret = 0;
aurel32af129062008-11-19 16:10:23 +00001575 farg1.ll = arg1;
1576 farg2.ll = arg2;
aurel32e1571902008-10-21 11:31:14 +00001577
aurel32af129062008-11-19 16:10:23 +00001578 if (unlikely(float64_is_nan(farg1.d) ||
1579 float64_is_nan(farg2.d))) {
aurel329a819372008-12-14 19:34:09 +00001580 ret = 0x01UL;
1581 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1582 ret = 0x08UL;
1583 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1584 ret = 0x04UL;
1585 } else {
1586 ret = 0x02UL;
1587 }
1588
1589 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1590 env->fpscr |= ret << FPSCR_FPRF;
1591 env->crf[crfD] = ret;
1592 if (unlikely(ret == 0x01UL
1593 && (float64_is_signaling_nan(farg1.d) ||
1594 float64_is_signaling_nan(farg2.d)))) {
1595 /* sNaN comparison */
1596 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1597 }
1598}
1599
1600void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1601{
1602 CPU_DoubleU farg1, farg2;
1603 uint32_t ret = 0;
1604 farg1.ll = arg1;
1605 farg2.ll = arg2;
1606
1607 if (unlikely(float64_is_nan(farg1.d) ||
1608 float64_is_nan(farg2.d))) {
1609 ret = 0x01UL;
1610 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1611 ret = 0x08UL;
1612 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1613 ret = 0x04UL;
1614 } else {
1615 ret = 0x02UL;
1616 }
1617
1618 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1619 env->fpscr |= ret << FPSCR_FPRF;
1620 env->crf[crfD] = ret;
1621 if (unlikely (ret == 0x01UL)) {
aurel32af129062008-11-19 16:10:23 +00001622 if (float64_is_signaling_nan(farg1.d) ||
1623 float64_is_signaling_nan(farg2.d)) {
j_mayer7c580442007-10-27 17:54:30 +00001624 /* sNaN comparison */
1625 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1626 POWERPC_EXCP_FP_VXVC);
1627 } else {
1628 /* qNaN comparison */
1629 fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
1630 }
bellard9a64fbe2004-01-04 22:58:38 +00001631 }
bellard9a64fbe2004-01-04 22:58:38 +00001632}
1633
j_mayer76a66252007-03-07 08:32:30 +00001634#if !defined (CONFIG_USER_ONLY)
aurel326527f6e2008-12-06 13:03:35 +00001635void helper_store_msr (target_ulong val)
j_mayer0411a972007-10-25 21:35:50 +00001636{
aurel326527f6e2008-12-06 13:03:35 +00001637 val = hreg_store_msr(env, val, 0);
1638 if (val != 0) {
j_mayer0411a972007-10-25 21:35:50 +00001639 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
aurel32e06fcd72008-12-11 22:42:14 +00001640 helper_raise_exception(val);
j_mayer0411a972007-10-25 21:35:50 +00001641 }
1642}
1643
aurel32d72a19f2008-11-30 16:24:55 +00001644static always_inline void do_rfi (target_ulong nip, target_ulong msr,
j_mayer0411a972007-10-25 21:35:50 +00001645 target_ulong msrm, int keep_msrh)
bellard9a64fbe2004-01-04 22:58:38 +00001646{
j_mayer426613d2007-03-23 09:45:27 +00001647#if defined(TARGET_PPC64)
j_mayer0411a972007-10-25 21:35:50 +00001648 if (msr & (1ULL << MSR_SF)) {
1649 nip = (uint64_t)nip;
1650 msr &= (uint64_t)msrm;
j_mayera42bd6c2007-03-30 10:22:46 +00001651 } else {
j_mayer0411a972007-10-25 21:35:50 +00001652 nip = (uint32_t)nip;
1653 msr = (uint32_t)(msr & msrm);
1654 if (keep_msrh)
1655 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
j_mayera42bd6c2007-03-30 10:22:46 +00001656 }
j_mayer426613d2007-03-23 09:45:27 +00001657#else
j_mayer0411a972007-10-25 21:35:50 +00001658 nip = (uint32_t)nip;
1659 msr &= (uint32_t)msrm;
j_mayer426613d2007-03-23 09:45:27 +00001660#endif
j_mayer0411a972007-10-25 21:35:50 +00001661 /* XXX: beware: this is false if VLE is supported */
1662 env->nip = nip & ~((target_ulong)0x00000003);
j_mayera4f30712007-11-17 21:14:09 +00001663 hreg_store_msr(env, msr, 1);
j_mayerd9bce9d2007-03-17 14:02:15 +00001664#if defined (DEBUG_OP)
j_mayer0411a972007-10-25 21:35:50 +00001665 cpu_dump_rfi(env->nip, env->msr);
j_mayerd9bce9d2007-03-17 14:02:15 +00001666#endif
j_mayer0411a972007-10-25 21:35:50 +00001667 /* No need to raise an exception here,
1668 * as rfi is always the last insn of a TB
1669 */
j_mayerd9bce9d2007-03-17 14:02:15 +00001670 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1671}
1672
aurel32d72a19f2008-11-30 16:24:55 +00001673void helper_rfi (void)
j_mayer0411a972007-10-25 21:35:50 +00001674{
aurel32d72a19f2008-11-30 16:24:55 +00001675 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1676 ~((target_ulong)0xFFFF0000), 1);
j_mayer0411a972007-10-25 21:35:50 +00001677}
1678
j_mayerd9bce9d2007-03-17 14:02:15 +00001679#if defined(TARGET_PPC64)
aurel32d72a19f2008-11-30 16:24:55 +00001680void helper_rfid (void)
j_mayer426613d2007-03-23 09:45:27 +00001681{
aurel32d72a19f2008-11-30 16:24:55 +00001682 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
1683 ~((target_ulong)0xFFFF0000), 0);
bellard9a64fbe2004-01-04 22:58:38 +00001684}
j_mayer78636672007-11-16 14:11:28 +00001685
aurel32d72a19f2008-11-30 16:24:55 +00001686void helper_hrfid (void)
j_mayerbe147d02007-09-30 13:03:23 +00001687{
aurel32d72a19f2008-11-30 16:24:55 +00001688 do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
1689 ~((target_ulong)0xFFFF0000), 0);
j_mayerbe147d02007-09-30 13:03:23 +00001690}
1691#endif
j_mayerd9bce9d2007-03-17 14:02:15 +00001692#endif
bellard9a64fbe2004-01-04 22:58:38 +00001693
aurel32cab3bee2008-11-24 11:28:19 +00001694void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
bellard9a64fbe2004-01-04 22:58:38 +00001695{
aurel32cab3bee2008-11-24 11:28:19 +00001696 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1697 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1698 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1699 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1700 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
aurel32e06fcd72008-12-11 22:42:14 +00001701 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
j_mayera42bd6c2007-03-30 10:22:46 +00001702 }
bellard9a64fbe2004-01-04 22:58:38 +00001703}
1704
j_mayerd9bce9d2007-03-17 14:02:15 +00001705#if defined(TARGET_PPC64)
aurel32cab3bee2008-11-24 11:28:19 +00001706void helper_td (target_ulong arg1, target_ulong arg2, uint32_t flags)
j_mayerd9bce9d2007-03-17 14:02:15 +00001707{
aurel32cab3bee2008-11-24 11:28:19 +00001708 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1709 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1710 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1711 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1712 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01)))))
aurel32e06fcd72008-12-11 22:42:14 +00001713 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
j_mayerd9bce9d2007-03-17 14:02:15 +00001714}
1715#endif
1716
bellardfdabc362005-07-04 22:17:05 +00001717/*****************************************************************************/
j_mayer76a66252007-03-07 08:32:30 +00001718/* PowerPC 601 specific instructions (POWER bridge) */
bellard9a64fbe2004-01-04 22:58:38 +00001719
aurel3222e0e172008-12-06 12:19:14 +00001720target_ulong helper_clcs (uint32_t arg)
bellard9a64fbe2004-01-04 22:58:38 +00001721{
aurel3222e0e172008-12-06 12:19:14 +00001722 switch (arg) {
j_mayer76a66252007-03-07 08:32:30 +00001723 case 0x0CUL:
1724 /* Instruction cache line size */
aurel3222e0e172008-12-06 12:19:14 +00001725 return env->icache_line_size;
j_mayer76a66252007-03-07 08:32:30 +00001726 break;
1727 case 0x0DUL:
1728 /* Data cache line size */
aurel3222e0e172008-12-06 12:19:14 +00001729 return env->dcache_line_size;
j_mayer76a66252007-03-07 08:32:30 +00001730 break;
1731 case 0x0EUL:
1732 /* Minimum cache line size */
aurel3222e0e172008-12-06 12:19:14 +00001733 return (env->icache_line_size < env->dcache_line_size) ?
1734 env->icache_line_size : env->dcache_line_size;
j_mayer76a66252007-03-07 08:32:30 +00001735 break;
1736 case 0x0FUL:
1737 /* Maximum cache line size */
aurel3222e0e172008-12-06 12:19:14 +00001738 return (env->icache_line_size > env->dcache_line_size) ?
1739 env->icache_line_size : env->dcache_line_size;
j_mayer76a66252007-03-07 08:32:30 +00001740 break;
1741 default:
1742 /* Undefined */
aurel3222e0e172008-12-06 12:19:14 +00001743 return 0;
j_mayer76a66252007-03-07 08:32:30 +00001744 break;
1745 }
1746}
1747
aurel3222e0e172008-12-06 12:19:14 +00001748target_ulong helper_div (target_ulong arg1, target_ulong arg2)
j_mayer76a66252007-03-07 08:32:30 +00001749{
aurel3222e0e172008-12-06 12:19:14 +00001750 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
j_mayer76a66252007-03-07 08:32:30 +00001751
aurel3222e0e172008-12-06 12:19:14 +00001752 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1753 (int32_t)arg2 == 0) {
j_mayer76a66252007-03-07 08:32:30 +00001754 env->spr[SPR_MQ] = 0;
aurel3222e0e172008-12-06 12:19:14 +00001755 return INT32_MIN;
j_mayer76a66252007-03-07 08:32:30 +00001756 } else {
aurel3222e0e172008-12-06 12:19:14 +00001757 env->spr[SPR_MQ] = tmp % arg2;
1758 return tmp / (int32_t)arg2;
j_mayer76a66252007-03-07 08:32:30 +00001759 }
1760}
1761
aurel3222e0e172008-12-06 12:19:14 +00001762target_ulong helper_divo (target_ulong arg1, target_ulong arg2)
j_mayer76a66252007-03-07 08:32:30 +00001763{
aurel3222e0e172008-12-06 12:19:14 +00001764 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
j_mayer76a66252007-03-07 08:32:30 +00001765
aurel3222e0e172008-12-06 12:19:14 +00001766 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1767 (int32_t)arg2 == 0) {
aurel323d7b4172008-10-21 11:28:46 +00001768 env->xer |= (1 << XER_OV) | (1 << XER_SO);
aurel3222e0e172008-12-06 12:19:14 +00001769 env->spr[SPR_MQ] = 0;
1770 return INT32_MIN;
j_mayer76a66252007-03-07 08:32:30 +00001771 } else {
aurel3222e0e172008-12-06 12:19:14 +00001772 env->spr[SPR_MQ] = tmp % arg2;
1773 tmp /= (int32_t)arg2;
1774 if ((int32_t)tmp != tmp) {
aurel323d7b4172008-10-21 11:28:46 +00001775 env->xer |= (1 << XER_OV) | (1 << XER_SO);
j_mayer76a66252007-03-07 08:32:30 +00001776 } else {
aurel323d7b4172008-10-21 11:28:46 +00001777 env->xer &= ~(1 << XER_OV);
j_mayer76a66252007-03-07 08:32:30 +00001778 }
aurel3222e0e172008-12-06 12:19:14 +00001779 return tmp;
j_mayer76a66252007-03-07 08:32:30 +00001780 }
1781}
1782
aurel3222e0e172008-12-06 12:19:14 +00001783target_ulong helper_divs (target_ulong arg1, target_ulong arg2)
j_mayer76a66252007-03-07 08:32:30 +00001784{
aurel3222e0e172008-12-06 12:19:14 +00001785 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1786 (int32_t)arg2 == 0) {
j_mayer76a66252007-03-07 08:32:30 +00001787 env->spr[SPR_MQ] = 0;
aurel3222e0e172008-12-06 12:19:14 +00001788 return INT32_MIN;
j_mayer76a66252007-03-07 08:32:30 +00001789 } else {
aurel3222e0e172008-12-06 12:19:14 +00001790 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1791 return (int32_t)arg1 / (int32_t)arg2;
j_mayer76a66252007-03-07 08:32:30 +00001792 }
1793}
1794
aurel3222e0e172008-12-06 12:19:14 +00001795target_ulong helper_divso (target_ulong arg1, target_ulong arg2)
j_mayer76a66252007-03-07 08:32:30 +00001796{
aurel3222e0e172008-12-06 12:19:14 +00001797 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1798 (int32_t)arg2 == 0) {
1799 env->xer |= (1 << XER_OV) | (1 << XER_SO);
j_mayer76a66252007-03-07 08:32:30 +00001800 env->spr[SPR_MQ] = 0;
aurel3222e0e172008-12-06 12:19:14 +00001801 return INT32_MIN;
j_mayer76a66252007-03-07 08:32:30 +00001802 } else {
aurel323d7b4172008-10-21 11:28:46 +00001803 env->xer &= ~(1 << XER_OV);
aurel3222e0e172008-12-06 12:19:14 +00001804 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1805 return (int32_t)arg1 / (int32_t)arg2;
j_mayer76a66252007-03-07 08:32:30 +00001806 }
1807}
1808
1809#if !defined (CONFIG_USER_ONLY)
aurel3222e0e172008-12-06 12:19:14 +00001810target_ulong helper_rac (target_ulong addr)
j_mayer76a66252007-03-07 08:32:30 +00001811{
j_mayer76a66252007-03-07 08:32:30 +00001812 mmu_ctx_t ctx;
j_mayerfaadf502007-11-03 13:37:12 +00001813 int nb_BATs;
aurel3222e0e172008-12-06 12:19:14 +00001814 target_ulong ret = 0;
j_mayer76a66252007-03-07 08:32:30 +00001815
1816 /* We don't have to generate many instances of this instruction,
1817 * as rac is supervisor only.
1818 */
j_mayerfaadf502007-11-03 13:37:12 +00001819 /* XXX: FIX THIS: Pretend we have no BAT */
1820 nb_BATs = env->nb_BATs;
1821 env->nb_BATs = 0;
aurel3222e0e172008-12-06 12:19:14 +00001822 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0)
1823 ret = ctx.raddr;
j_mayerfaadf502007-11-03 13:37:12 +00001824 env->nb_BATs = nb_BATs;
aurel3222e0e172008-12-06 12:19:14 +00001825 return ret;
bellard9a64fbe2004-01-04 22:58:38 +00001826}
1827
aurel32d72a19f2008-11-30 16:24:55 +00001828void helper_rfsvc (void)
j_mayer76a66252007-03-07 08:32:30 +00001829{
aurel32d72a19f2008-11-30 16:24:55 +00001830 do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
j_mayer76a66252007-03-07 08:32:30 +00001831}
j_mayer76a66252007-03-07 08:32:30 +00001832#endif
1833
1834/*****************************************************************************/
1835/* 602 specific instructions */
1836/* mfrom is the most crazy instruction ever seen, imho ! */
1837/* Real implementation uses a ROM table. Do the same */
aurel325e9ae182008-12-13 12:30:21 +00001838/* Extremly decomposed:
1839 * -arg / 256
1840 * return 256 * log10(10 + 1.0) + 0.5
1841 */
aurel32db9a16a2008-12-08 18:11:50 +00001842#if !defined (CONFIG_USER_ONLY)
aurel32cf02a652008-11-30 16:23:35 +00001843target_ulong helper_602_mfrom (target_ulong arg)
j_mayer76a66252007-03-07 08:32:30 +00001844{
aurel32cf02a652008-11-30 16:23:35 +00001845 if (likely(arg < 602)) {
j_mayer76a66252007-03-07 08:32:30 +00001846#include "mfrom_table.c"
aurel3245d827d2008-12-07 13:40:29 +00001847 return mfrom_ROM_table[arg];
j_mayer76a66252007-03-07 08:32:30 +00001848 } else {
aurel32cf02a652008-11-30 16:23:35 +00001849 return 0;
j_mayer76a66252007-03-07 08:32:30 +00001850 }
1851}
aurel32db9a16a2008-12-08 18:11:50 +00001852#endif
j_mayer76a66252007-03-07 08:32:30 +00001853
1854/*****************************************************************************/
1855/* Embedded PowerPC specific helpers */
j_mayer76a66252007-03-07 08:32:30 +00001856
j_mayera750fc02007-09-26 23:54:22 +00001857/* XXX: to be improved to check access rights when in user-mode */
aurel3206dca6a2008-12-06 16:37:18 +00001858target_ulong helper_load_dcr (target_ulong dcrn)
j_mayera750fc02007-09-26 23:54:22 +00001859{
aurel3206dca6a2008-12-06 16:37:18 +00001860 target_ulong val = 0;
j_mayera750fc02007-09-26 23:54:22 +00001861
1862 if (unlikely(env->dcr_env == NULL)) {
1863 if (loglevel != 0) {
1864 fprintf(logfile, "No DCR environment\n");
1865 }
aurel32e06fcd72008-12-11 22:42:14 +00001866 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1867 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
aurel3206dca6a2008-12-06 16:37:18 +00001868 } else if (unlikely(ppc_dcr_read(env->dcr_env, dcrn, &val) != 0)) {
j_mayera750fc02007-09-26 23:54:22 +00001869 if (loglevel != 0) {
aurel3245d827d2008-12-07 13:40:29 +00001870 fprintf(logfile, "DCR read error %d %03x\n", (int)dcrn, (int)dcrn);
j_mayera750fc02007-09-26 23:54:22 +00001871 }
aurel32e06fcd72008-12-11 22:42:14 +00001872 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1873 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
j_mayera750fc02007-09-26 23:54:22 +00001874 }
aurel3206dca6a2008-12-06 16:37:18 +00001875 return val;
j_mayera750fc02007-09-26 23:54:22 +00001876}
1877
aurel3206dca6a2008-12-06 16:37:18 +00001878void helper_store_dcr (target_ulong dcrn, target_ulong val)
j_mayera750fc02007-09-26 23:54:22 +00001879{
1880 if (unlikely(env->dcr_env == NULL)) {
1881 if (loglevel != 0) {
1882 fprintf(logfile, "No DCR environment\n");
1883 }
aurel32e06fcd72008-12-11 22:42:14 +00001884 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1885 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
aurel3206dca6a2008-12-06 16:37:18 +00001886 } else if (unlikely(ppc_dcr_write(env->dcr_env, dcrn, val) != 0)) {
j_mayera750fc02007-09-26 23:54:22 +00001887 if (loglevel != 0) {
aurel3245d827d2008-12-07 13:40:29 +00001888 fprintf(logfile, "DCR write error %d %03x\n", (int)dcrn, (int)dcrn);
j_mayera750fc02007-09-26 23:54:22 +00001889 }
aurel32e06fcd72008-12-11 22:42:14 +00001890 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1891 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
j_mayera750fc02007-09-26 23:54:22 +00001892 }
1893}
1894
j_mayer76a66252007-03-07 08:32:30 +00001895#if !defined(CONFIG_USER_ONLY)
aurel32d72a19f2008-11-30 16:24:55 +00001896void helper_40x_rfci (void)
j_mayer76a66252007-03-07 08:32:30 +00001897{
aurel32d72a19f2008-11-30 16:24:55 +00001898 do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
1899 ~((target_ulong)0xFFFF0000), 0);
j_mayer76a66252007-03-07 08:32:30 +00001900}
1901
aurel32d72a19f2008-11-30 16:24:55 +00001902void helper_rfci (void)
j_mayera42bd6c2007-03-30 10:22:46 +00001903{
aurel32d72a19f2008-11-30 16:24:55 +00001904 do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
1905 ~((target_ulong)0x3FFF0000), 0);
j_mayera42bd6c2007-03-30 10:22:46 +00001906}
1907
aurel32d72a19f2008-11-30 16:24:55 +00001908void helper_rfdi (void)
j_mayera42bd6c2007-03-30 10:22:46 +00001909{
aurel32d72a19f2008-11-30 16:24:55 +00001910 do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
1911 ~((target_ulong)0x3FFF0000), 0);
j_mayera42bd6c2007-03-30 10:22:46 +00001912}
1913
aurel32d72a19f2008-11-30 16:24:55 +00001914void helper_rfmci (void)
j_mayera42bd6c2007-03-30 10:22:46 +00001915{
aurel32d72a19f2008-11-30 16:24:55 +00001916 do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
1917 ~((target_ulong)0x3FFF0000), 0);
j_mayera42bd6c2007-03-30 10:22:46 +00001918}
j_mayer76a66252007-03-07 08:32:30 +00001919#endif
1920
1921/* 440 specific */
aurel32ef0d51a2008-11-30 17:26:29 +00001922target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
j_mayer76a66252007-03-07 08:32:30 +00001923{
1924 target_ulong mask;
1925 int i;
1926
1927 i = 1;
1928 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
aurel32ef0d51a2008-11-30 17:26:29 +00001929 if ((high & mask) == 0) {
1930 if (update_Rc) {
1931 env->crf[0] = 0x4;
1932 }
j_mayer76a66252007-03-07 08:32:30 +00001933 goto done;
aurel32ef0d51a2008-11-30 17:26:29 +00001934 }
j_mayer76a66252007-03-07 08:32:30 +00001935 i++;
1936 }
1937 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
aurel32ef0d51a2008-11-30 17:26:29 +00001938 if ((low & mask) == 0) {
1939 if (update_Rc) {
1940 env->crf[0] = 0x8;
1941 }
1942 goto done;
1943 }
j_mayer76a66252007-03-07 08:32:30 +00001944 i++;
1945 }
aurel32ef0d51a2008-11-30 17:26:29 +00001946 if (update_Rc) {
1947 env->crf[0] = 0x2;
1948 }
j_mayer76a66252007-03-07 08:32:30 +00001949 done:
aurel32ef0d51a2008-11-30 17:26:29 +00001950 env->xer = (env->xer & ~0x7F) | i;
1951 if (update_Rc) {
1952 env->crf[0] |= xer_so;
1953 }
1954 return i;
j_mayer76a66252007-03-07 08:32:30 +00001955}
1956
aurel321c978562008-11-23 10:54:04 +00001957/*****************************************************************************/
aurel32d6a46fe2009-01-03 13:31:19 +00001958/* Altivec extension helpers */
1959#if defined(WORDS_BIGENDIAN)
1960#define HI_IDX 0
1961#define LO_IDX 1
1962#else
1963#define HI_IDX 1
1964#define LO_IDX 0
1965#endif
1966
1967#if defined(WORDS_BIGENDIAN)
1968#define VECTOR_FOR_INORDER_I(index, element) \
1969 for (index = 0; index < ARRAY_SIZE(r->element); index++)
1970#else
1971#define VECTOR_FOR_INORDER_I(index, element) \
1972 for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
1973#endif
1974
aurel3200d3b8f2009-01-04 22:11:59 +00001975/* Saturating arithmetic helpers. */
1976#define SATCVT(from, to, from_type, to_type, min, max, use_min, use_max) \
1977 static always_inline to_type cvt##from##to (from_type x, int *sat) \
1978 { \
1979 to_type r; \
1980 if (use_min && x < min) { \
1981 r = min; \
1982 *sat = 1; \
1983 } else if (use_max && x > max) { \
1984 r = max; \
1985 *sat = 1; \
1986 } else { \
1987 r = x; \
1988 } \
1989 return r; \
1990 }
1991SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX, 1, 1)
1992SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX, 1, 1)
1993SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX, 1, 1)
1994SATCVT(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX, 0, 1)
1995SATCVT(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX, 0, 1)
1996SATCVT(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX, 0, 1)
1997SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX, 1, 1)
1998SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX, 1, 1)
1999SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX, 1, 1)
2000#undef SATCVT
2001
aurel32bf8d8de2009-01-04 22:09:42 +00002002void helper_lvsl (ppc_avr_t *r, target_ulong sh)
2003{
2004 int i, j = (sh & 0xf);
2005
2006 VECTOR_FOR_INORDER_I (i, u8) {
2007 r->u8[i] = j++;
2008 }
2009}
2010
2011void helper_lvsr (ppc_avr_t *r, target_ulong sh)
2012{
2013 int i, j = 0x10 - (sh & 0xf);
2014
2015 VECTOR_FOR_INORDER_I (i, u8) {
2016 r->u8[i] = j++;
2017 }
2018}
2019
aurel32e343da72009-01-04 22:09:31 +00002020void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2021{
2022 int i;
2023 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2024 r->u32[i] = ~a->u32[i] < b->u32[i];
2025 }
2026}
2027
aurel327872c512009-01-03 13:31:40 +00002028#define VARITH_DO(name, op, element) \
2029void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2030{ \
2031 int i; \
2032 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2033 r->element[i] = a->element[i] op b->element[i]; \
2034 } \
2035}
2036#define VARITH(suffix, element) \
2037 VARITH_DO(add##suffix, +, element) \
2038 VARITH_DO(sub##suffix, -, element)
2039VARITH(ubm, u8)
2040VARITH(uhm, u16)
2041VARITH(uwm, u32)
2042#undef VARITH_DO
2043#undef VARITH
2044
aurel32fab3cbe2009-01-03 13:31:49 +00002045#define VAVG_DO(name, element, etype) \
2046 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2047 { \
2048 int i; \
2049 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2050 etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
2051 r->element[i] = x >> 1; \
2052 } \
2053 }
2054
2055#define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
2056 VAVG_DO(avgs##type, signed_element, signed_type) \
2057 VAVG_DO(avgu##type, unsigned_element, unsigned_type)
2058VAVG(b, s8, int16_t, u8, uint16_t)
2059VAVG(h, s16, int32_t, u16, uint32_t)
2060VAVG(w, s32, int64_t, u32, uint64_t)
2061#undef VAVG_DO
2062#undef VAVG
2063
aurel32e4039332009-01-03 13:31:58 +00002064#define VMINMAX_DO(name, compare, element) \
2065 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2066 { \
2067 int i; \
2068 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2069 if (a->element[i] compare b->element[i]) { \
2070 r->element[i] = b->element[i]; \
2071 } else { \
2072 r->element[i] = a->element[i]; \
2073 } \
2074 } \
2075 }
2076#define VMINMAX(suffix, element) \
2077 VMINMAX_DO(min##suffix, >, element) \
2078 VMINMAX_DO(max##suffix, <, element)
2079VMINMAX(sb, s8)
2080VMINMAX(sh, s16)
2081VMINMAX(sw, s32)
2082VMINMAX(ub, u8)
2083VMINMAX(uh, u16)
2084VMINMAX(uw, u32)
2085#undef VMINMAX_DO
2086#undef VMINMAX
2087
aurel323b430042009-01-04 22:08:38 +00002088#define VMRG_DO(name, element, highp) \
2089 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2090 { \
2091 ppc_avr_t result; \
2092 int i; \
2093 size_t n_elems = ARRAY_SIZE(r->element); \
2094 for (i = 0; i < n_elems/2; i++) { \
2095 if (highp) { \
2096 result.element[i*2+HI_IDX] = a->element[i]; \
2097 result.element[i*2+LO_IDX] = b->element[i]; \
2098 } else { \
2099 result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
2100 result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
2101 } \
2102 } \
2103 *r = result; \
2104 }
2105#if defined(WORDS_BIGENDIAN)
2106#define MRGHI 0
2107#define MRGL0 1
2108#else
2109#define MRGHI 1
2110#define MRGLO 0
2111#endif
2112#define VMRG(suffix, element) \
2113 VMRG_DO(mrgl##suffix, element, MRGHI) \
2114 VMRG_DO(mrgh##suffix, element, MRGLO)
2115VMRG(b, u8)
2116VMRG(h, u16)
2117VMRG(w, u32)
2118#undef VMRG_DO
2119#undef VMRG
2120#undef MRGHI
2121#undef MRGLO
2122
aurel32b04ae982009-01-04 22:11:39 +00002123void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2124{
2125 int32_t prod[16];
2126 int i;
2127
2128 for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
2129 prod[i] = (int32_t)a->s8[i] * b->u8[i];
2130 }
2131
2132 VECTOR_FOR_INORDER_I(i, s32) {
2133 r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2134 }
2135}
2136
2137void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2138{
2139 uint16_t prod[16];
2140 int i;
2141
2142 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2143 prod[i] = a->u8[i] * b->u8[i];
2144 }
2145
2146 VECTOR_FOR_INORDER_I(i, u32) {
2147 r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2148 }
2149}
2150
aurel322c277902009-01-04 22:08:48 +00002151#define VMUL_DO(name, mul_element, prod_element, evenp) \
2152 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2153 { \
2154 int i; \
2155 VECTOR_FOR_INORDER_I(i, prod_element) { \
2156 if (evenp) { \
2157 r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2158 } else { \
2159 r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2160 } \
2161 } \
2162 }
2163#define VMUL(suffix, mul_element, prod_element) \
2164 VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2165 VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2166VMUL(sb, s8, s16)
2167VMUL(sh, s16, s32)
2168VMUL(ub, u8, u16)
2169VMUL(uh, u16, u32)
2170#undef VMUL_DO
2171#undef VMUL
2172
aurel32d1258692009-01-04 22:11:49 +00002173void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2174{
2175 ppc_avr_t result;
2176 int i;
2177 VECTOR_FOR_INORDER_I (i, u8) {
2178 int s = c->u8[i] & 0x1f;
2179#if defined(WORDS_BIGENDIAN)
2180 int index = s & 0xf;
2181#else
2182 int index = 15 - (s & 0xf);
2183#endif
2184 if (s & 0x10) {
2185 result.u8[i] = b->u8[index];
2186 } else {
2187 result.u8[i] = a->u8[index];
2188 }
2189 }
2190 *r = result;
2191}
2192
aurel325335a142009-01-04 22:12:09 +00002193#if defined(WORDS_BIGENDIAN)
2194#define PKBIG 1
2195#else
2196#define PKBIG 0
2197#endif
2198#define VPK(suffix, from, to, cvt, dosat) \
2199 void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2200 { \
2201 int i; \
2202 int sat = 0; \
2203 ppc_avr_t result; \
2204 ppc_avr_t *a0 = PKBIG ? a : b; \
2205 ppc_avr_t *a1 = PKBIG ? b : a; \
2206 VECTOR_FOR_INORDER_I (i, from) { \
2207 result.to[i] = cvt(a0->from[i], &sat); \
2208 result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
2209 } \
2210 *r = result; \
2211 if (dosat && sat) { \
2212 env->vscr |= (1 << VSCR_SAT); \
2213 } \
2214 }
2215#define I(x, y) (x)
2216VPK(shss, s16, s8, cvtshsb, 1)
2217VPK(shus, s16, u8, cvtshub, 1)
2218VPK(swss, s32, s16, cvtswsh, 1)
2219VPK(swus, s32, u16, cvtswuh, 1)
2220VPK(uhus, u16, u8, cvtuhub, 1)
2221VPK(uwus, u32, u16, cvtuwuh, 1)
2222VPK(uhum, u16, u8, I, 0)
2223VPK(uwum, u32, u16, I, 0)
2224#undef I
2225#undef VPK
2226#undef PKBIG
2227
aurel325e1d0982009-01-04 22:09:52 +00002228#define VROTATE(suffix, element) \
2229 void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2230 { \
2231 int i; \
2232 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2233 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2234 unsigned int shift = b->element[i] & mask; \
2235 r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2236 } \
2237 }
2238VROTATE(b, u8)
2239VROTATE(h, u16)
2240VROTATE(w, u32)
2241#undef VROTATE
2242
aurel32d1258692009-01-04 22:11:49 +00002243void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
2244{
2245 r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2246 r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2247}
2248
aurel32d79f0802009-01-04 22:09:08 +00002249#define VSL(suffix, element) \
2250 void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2251 { \
2252 int i; \
2253 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2254 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2255 unsigned int shift = b->element[i] & mask; \
2256 r->element[i] = a->element[i] << shift; \
2257 } \
2258 }
2259VSL(b, u8)
2260VSL(h, u16)
2261VSL(w, u32)
2262#undef VSL
2263
aurel32cd633b12009-01-04 22:10:09 +00002264void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
2265{
2266 int sh = shift & 0xf;
2267 int i;
2268 ppc_avr_t result;
2269
2270#if defined(WORDS_BIGENDIAN)
2271 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2272 int index = sh + i;
2273 if (index > 0xf) {
2274 result.u8[i] = b->u8[index-0x10];
2275 } else {
2276 result.u8[i] = a->u8[index];
2277 }
2278 }
2279#else
2280 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2281 int index = (16 - sh) + i;
2282 if (index > 0xf) {
2283 result.u8[i] = a->u8[index-0x10];
2284 } else {
2285 result.u8[i] = b->u8[index];
2286 }
2287 }
2288#endif
2289 *r = result;
2290}
2291
aurel327b239be2009-01-04 22:09:19 +00002292void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2293{
2294 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2295
2296#if defined (WORDS_BIGENDIAN)
2297 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2298 memset (&r->u8[16-sh], 0, sh);
2299#else
2300 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2301 memset (&r->u8[0], 0, sh);
2302#endif
2303}
2304
aurel32e4e6bee2009-01-04 22:10:49 +00002305/* Experimental testing shows that hardware masks the immediate. */
2306#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
2307#if defined(WORDS_BIGENDIAN)
2308#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2309#else
2310#define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
2311#endif
2312#define VSPLT(suffix, element) \
2313 void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
2314 { \
2315 uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
2316 int i; \
2317 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2318 r->element[i] = s; \
2319 } \
2320 }
2321VSPLT(b, u8)
2322VSPLT(h, u16)
2323VSPLT(w, u32)
2324#undef VSPLT
2325#undef SPLAT_ELEMENT
2326#undef _SPLAT_MASKED
2327
aurel3207ef34c2009-01-04 22:08:58 +00002328#define VSR(suffix, element) \
2329 void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2330 { \
2331 int i; \
2332 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2333 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2334 unsigned int shift = b->element[i] & mask; \
2335 r->element[i] = a->element[i] >> shift; \
2336 } \
2337 }
2338VSR(ab, s8)
2339VSR(ah, s16)
2340VSR(aw, s32)
2341VSR(b, u8)
2342VSR(h, u16)
2343VSR(w, u32)
2344#undef VSR
2345
aurel327b239be2009-01-04 22:09:19 +00002346void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2347{
2348 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2349
2350#if defined (WORDS_BIGENDIAN)
2351 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2352 memset (&r->u8[0], 0, sh);
2353#else
2354 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2355 memset (&r->u8[16-sh], 0, sh);
2356#endif
2357}
2358
aurel32e343da72009-01-04 22:09:31 +00002359void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2360{
2361 int i;
2362 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2363 r->u32[i] = a->u32[i] >= b->u32[i];
2364 }
2365}
2366
aurel3279f85c32009-01-04 22:11:10 +00002367#if defined(WORDS_BIGENDIAN)
2368#define UPKHI 1
2369#define UPKLO 0
2370#else
2371#define UPKHI 0
2372#define UPKLO 1
2373#endif
2374#define VUPKPX(suffix, hi) \
2375 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2376 { \
2377 int i; \
2378 ppc_avr_t result; \
2379 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
2380 uint16_t e = b->u16[hi ? i : i+4]; \
2381 uint8_t a = (e >> 15) ? 0xff : 0; \
2382 uint8_t r = (e >> 10) & 0x1f; \
2383 uint8_t g = (e >> 5) & 0x1f; \
2384 uint8_t b = e & 0x1f; \
2385 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
2386 } \
2387 *r = result; \
2388 }
2389VUPKPX(lpx, UPKLO)
2390VUPKPX(hpx, UPKHI)
2391#undef VUPKPX
2392
aurel326cf1c6e2009-01-04 22:11:20 +00002393#define VUPK(suffix, unpacked, packee, hi) \
2394 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2395 { \
2396 int i; \
2397 ppc_avr_t result; \
2398 if (hi) { \
2399 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
2400 result.unpacked[i] = b->packee[i]; \
2401 } \
2402 } else { \
2403 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
2404 result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
2405 } \
2406 } \
2407 *r = result; \
2408 }
2409VUPK(hsb, s16, s8, UPKHI)
2410VUPK(hsh, s32, s16, UPKHI)
2411VUPK(lsb, s16, s8, UPKLO)
2412VUPK(lsh, s32, s16, UPKLO)
2413#undef VUPK
aurel3279f85c32009-01-04 22:11:10 +00002414#undef UPKHI
2415#undef UPKLO
2416
aurel32d6a46fe2009-01-03 13:31:19 +00002417#undef VECTOR_FOR_INORDER_I
2418#undef HI_IDX
2419#undef LO_IDX
2420
2421/*****************************************************************************/
j_mayer0487d6a2007-03-20 22:11:31 +00002422/* SPE extension helpers */
2423/* Use a table to make this quicker */
2424static uint8_t hbrev[16] = {
2425 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
2426 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
2427};
2428
j_mayerb068d6a2007-10-07 17:13:44 +00002429static always_inline uint8_t byte_reverse (uint8_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002430{
2431 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
2432}
2433
j_mayerb068d6a2007-10-07 17:13:44 +00002434static always_inline uint32_t word_reverse (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002435{
2436 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
2437 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
2438}
2439
j_mayer3cd7d1d2007-11-12 01:56:18 +00002440#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
aurel3257951c22008-11-10 11:10:23 +00002441target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
j_mayer0487d6a2007-03-20 22:11:31 +00002442{
2443 uint32_t a, b, d, mask;
2444
j_mayer3cd7d1d2007-11-12 01:56:18 +00002445 mask = UINT32_MAX >> (32 - MASKBITS);
aurel3257951c22008-11-10 11:10:23 +00002446 a = arg1 & mask;
2447 b = arg2 & mask;
j_mayer3cd7d1d2007-11-12 01:56:18 +00002448 d = word_reverse(1 + word_reverse(a | ~b));
aurel3257951c22008-11-10 11:10:23 +00002449 return (arg1 & ~mask) | (d & b);
j_mayer0487d6a2007-03-20 22:11:31 +00002450}
2451
aurel3257951c22008-11-10 11:10:23 +00002452uint32_t helper_cntlsw32 (uint32_t val)
2453{
2454 if (val & 0x80000000)
2455 return clz32(~val);
2456 else
2457 return clz32(val);
2458}
2459
2460uint32_t helper_cntlzw32 (uint32_t val)
2461{
2462 return clz32(val);
j_mayer0487d6a2007-03-20 22:11:31 +00002463}
2464
aurel321c978562008-11-23 10:54:04 +00002465/* Single-precision floating-point conversions */
2466static always_inline uint32_t efscfsi (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002467{
aurel320ca9d382008-03-13 19:19:16 +00002468 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002469
2470 u.f = int32_to_float32(val, &env->spe_status);
2471
aurel320ca9d382008-03-13 19:19:16 +00002472 return u.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002473}
2474
aurel321c978562008-11-23 10:54:04 +00002475static always_inline uint32_t efscfui (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002476{
aurel320ca9d382008-03-13 19:19:16 +00002477 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002478
2479 u.f = uint32_to_float32(val, &env->spe_status);
2480
aurel320ca9d382008-03-13 19:19:16 +00002481 return u.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002482}
2483
aurel321c978562008-11-23 10:54:04 +00002484static always_inline int32_t efsctsi (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002485{
aurel320ca9d382008-03-13 19:19:16 +00002486 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002487
aurel320ca9d382008-03-13 19:19:16 +00002488 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002489 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002490 if (unlikely(float32_is_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00002491 return 0;
2492
2493 return float32_to_int32(u.f, &env->spe_status);
2494}
2495
aurel321c978562008-11-23 10:54:04 +00002496static always_inline uint32_t efsctui (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002497{
aurel320ca9d382008-03-13 19:19:16 +00002498 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002499
aurel320ca9d382008-03-13 19:19:16 +00002500 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002501 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002502 if (unlikely(float32_is_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00002503 return 0;
2504
2505 return float32_to_uint32(u.f, &env->spe_status);
2506}
2507
aurel321c978562008-11-23 10:54:04 +00002508static always_inline uint32_t efsctsiz (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002509{
aurel320ca9d382008-03-13 19:19:16 +00002510 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002511
aurel320ca9d382008-03-13 19:19:16 +00002512 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002513 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002514 if (unlikely(float32_is_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00002515 return 0;
2516
2517 return float32_to_int32_round_to_zero(u.f, &env->spe_status);
2518}
2519
aurel321c978562008-11-23 10:54:04 +00002520static always_inline uint32_t efsctuiz (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002521{
aurel320ca9d382008-03-13 19:19:16 +00002522 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002523
aurel320ca9d382008-03-13 19:19:16 +00002524 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002525 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002526 if (unlikely(float32_is_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00002527 return 0;
2528
2529 return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
2530}
2531
aurel321c978562008-11-23 10:54:04 +00002532static always_inline uint32_t efscfsf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002533{
aurel320ca9d382008-03-13 19:19:16 +00002534 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002535 float32 tmp;
2536
2537 u.f = int32_to_float32(val, &env->spe_status);
2538 tmp = int64_to_float32(1ULL << 32, &env->spe_status);
2539 u.f = float32_div(u.f, tmp, &env->spe_status);
2540
aurel320ca9d382008-03-13 19:19:16 +00002541 return u.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002542}
2543
aurel321c978562008-11-23 10:54:04 +00002544static always_inline uint32_t efscfuf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002545{
aurel320ca9d382008-03-13 19:19:16 +00002546 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002547 float32 tmp;
2548
2549 u.f = uint32_to_float32(val, &env->spe_status);
2550 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2551 u.f = float32_div(u.f, tmp, &env->spe_status);
2552
aurel320ca9d382008-03-13 19:19:16 +00002553 return u.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002554}
2555
aurel321c978562008-11-23 10:54:04 +00002556static always_inline uint32_t efsctsf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002557{
aurel320ca9d382008-03-13 19:19:16 +00002558 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002559 float32 tmp;
2560
aurel320ca9d382008-03-13 19:19:16 +00002561 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002562 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002563 if (unlikely(float32_is_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00002564 return 0;
2565 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2566 u.f = float32_mul(u.f, tmp, &env->spe_status);
2567
2568 return float32_to_int32(u.f, &env->spe_status);
2569}
2570
aurel321c978562008-11-23 10:54:04 +00002571static always_inline uint32_t efsctuf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002572{
aurel320ca9d382008-03-13 19:19:16 +00002573 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002574 float32 tmp;
2575
aurel320ca9d382008-03-13 19:19:16 +00002576 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002577 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002578 if (unlikely(float32_is_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00002579 return 0;
2580 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2581 u.f = float32_mul(u.f, tmp, &env->spe_status);
2582
2583 return float32_to_uint32(u.f, &env->spe_status);
2584}
2585
aurel321c978562008-11-23 10:54:04 +00002586#define HELPER_SPE_SINGLE_CONV(name) \
2587uint32_t helper_e##name (uint32_t val) \
2588{ \
2589 return e##name(val); \
2590}
2591/* efscfsi */
2592HELPER_SPE_SINGLE_CONV(fscfsi);
2593/* efscfui */
2594HELPER_SPE_SINGLE_CONV(fscfui);
2595/* efscfuf */
2596HELPER_SPE_SINGLE_CONV(fscfuf);
2597/* efscfsf */
2598HELPER_SPE_SINGLE_CONV(fscfsf);
2599/* efsctsi */
2600HELPER_SPE_SINGLE_CONV(fsctsi);
2601/* efsctui */
2602HELPER_SPE_SINGLE_CONV(fsctui);
2603/* efsctsiz */
2604HELPER_SPE_SINGLE_CONV(fsctsiz);
2605/* efsctuiz */
2606HELPER_SPE_SINGLE_CONV(fsctuiz);
2607/* efsctsf */
2608HELPER_SPE_SINGLE_CONV(fsctsf);
2609/* efsctuf */
2610HELPER_SPE_SINGLE_CONV(fsctuf);
2611
2612#define HELPER_SPE_VECTOR_CONV(name) \
2613uint64_t helper_ev##name (uint64_t val) \
2614{ \
2615 return ((uint64_t)e##name(val >> 32) << 32) | \
2616 (uint64_t)e##name(val); \
2617}
2618/* evfscfsi */
2619HELPER_SPE_VECTOR_CONV(fscfsi);
2620/* evfscfui */
2621HELPER_SPE_VECTOR_CONV(fscfui);
2622/* evfscfuf */
2623HELPER_SPE_VECTOR_CONV(fscfuf);
2624/* evfscfsf */
2625HELPER_SPE_VECTOR_CONV(fscfsf);
2626/* evfsctsi */
2627HELPER_SPE_VECTOR_CONV(fsctsi);
2628/* evfsctui */
2629HELPER_SPE_VECTOR_CONV(fsctui);
2630/* evfsctsiz */
2631HELPER_SPE_VECTOR_CONV(fsctsiz);
2632/* evfsctuiz */
2633HELPER_SPE_VECTOR_CONV(fsctuiz);
2634/* evfsctsf */
2635HELPER_SPE_VECTOR_CONV(fsctsf);
2636/* evfsctuf */
2637HELPER_SPE_VECTOR_CONV(fsctuf);
2638
2639/* Single-precision floating-point arithmetic */
2640static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002641{
aurel321c978562008-11-23 10:54:04 +00002642 CPU_FloatU u1, u2;
2643 u1.l = op1;
2644 u2.l = op2;
2645 u1.f = float32_add(u1.f, u2.f, &env->spe_status);
2646 return u1.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002647}
2648
aurel321c978562008-11-23 10:54:04 +00002649static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002650{
aurel321c978562008-11-23 10:54:04 +00002651 CPU_FloatU u1, u2;
2652 u1.l = op1;
2653 u2.l = op2;
2654 u1.f = float32_sub(u1.f, u2.f, &env->spe_status);
2655 return u1.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002656}
2657
aurel321c978562008-11-23 10:54:04 +00002658static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002659{
aurel321c978562008-11-23 10:54:04 +00002660 CPU_FloatU u1, u2;
2661 u1.l = op1;
2662 u2.l = op2;
2663 u1.f = float32_mul(u1.f, u2.f, &env->spe_status);
2664 return u1.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002665}
2666
aurel321c978562008-11-23 10:54:04 +00002667static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002668{
aurel321c978562008-11-23 10:54:04 +00002669 CPU_FloatU u1, u2;
2670 u1.l = op1;
2671 u2.l = op2;
2672 u1.f = float32_div(u1.f, u2.f, &env->spe_status);
2673 return u1.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002674}
2675
aurel321c978562008-11-23 10:54:04 +00002676#define HELPER_SPE_SINGLE_ARITH(name) \
2677uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
2678{ \
2679 return e##name(op1, op2); \
2680}
2681/* efsadd */
2682HELPER_SPE_SINGLE_ARITH(fsadd);
2683/* efssub */
2684HELPER_SPE_SINGLE_ARITH(fssub);
2685/* efsmul */
2686HELPER_SPE_SINGLE_ARITH(fsmul);
2687/* efsdiv */
2688HELPER_SPE_SINGLE_ARITH(fsdiv);
2689
2690#define HELPER_SPE_VECTOR_ARITH(name) \
2691uint64_t helper_ev##name (uint64_t op1, uint64_t op2) \
2692{ \
2693 return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
2694 (uint64_t)e##name(op1, op2); \
2695}
2696/* evfsadd */
2697HELPER_SPE_VECTOR_ARITH(fsadd);
2698/* evfssub */
2699HELPER_SPE_VECTOR_ARITH(fssub);
2700/* evfsmul */
2701HELPER_SPE_VECTOR_ARITH(fsmul);
2702/* evfsdiv */
2703HELPER_SPE_VECTOR_ARITH(fsdiv);
2704
2705/* Single-precision floating-point comparisons */
2706static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002707{
aurel321c978562008-11-23 10:54:04 +00002708 CPU_FloatU u1, u2;
2709 u1.l = op1;
2710 u2.l = op2;
2711 return float32_lt(u1.f, u2.f, &env->spe_status) ? 4 : 0;
j_mayer0487d6a2007-03-20 22:11:31 +00002712}
2713
aurel321c978562008-11-23 10:54:04 +00002714static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002715{
aurel321c978562008-11-23 10:54:04 +00002716 CPU_FloatU u1, u2;
2717 u1.l = op1;
2718 u2.l = op2;
2719 return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 4;
j_mayer0487d6a2007-03-20 22:11:31 +00002720}
2721
aurel321c978562008-11-23 10:54:04 +00002722static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002723{
aurel321c978562008-11-23 10:54:04 +00002724 CPU_FloatU u1, u2;
2725 u1.l = op1;
2726 u2.l = op2;
2727 return float32_eq(u1.f, u2.f, &env->spe_status) ? 4 : 0;
j_mayer0487d6a2007-03-20 22:11:31 +00002728}
2729
aurel321c978562008-11-23 10:54:04 +00002730static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002731{
2732 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00002733 return efststlt(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00002734}
2735
aurel321c978562008-11-23 10:54:04 +00002736static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002737{
2738 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00002739 return efststgt(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00002740}
2741
aurel321c978562008-11-23 10:54:04 +00002742static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002743{
2744 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00002745 return efststeq(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00002746}
2747
aurel321c978562008-11-23 10:54:04 +00002748#define HELPER_SINGLE_SPE_CMP(name) \
2749uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
2750{ \
2751 return e##name(op1, op2) << 2; \
2752}
2753/* efststlt */
2754HELPER_SINGLE_SPE_CMP(fststlt);
2755/* efststgt */
2756HELPER_SINGLE_SPE_CMP(fststgt);
2757/* efststeq */
2758HELPER_SINGLE_SPE_CMP(fststeq);
2759/* efscmplt */
2760HELPER_SINGLE_SPE_CMP(fscmplt);
2761/* efscmpgt */
2762HELPER_SINGLE_SPE_CMP(fscmpgt);
2763/* efscmpeq */
2764HELPER_SINGLE_SPE_CMP(fscmpeq);
2765
2766static always_inline uint32_t evcmp_merge (int t0, int t1)
j_mayer0487d6a2007-03-20 22:11:31 +00002767{
aurel321c978562008-11-23 10:54:04 +00002768 return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
j_mayer0487d6a2007-03-20 22:11:31 +00002769}
2770
aurel321c978562008-11-23 10:54:04 +00002771#define HELPER_VECTOR_SPE_CMP(name) \
2772uint32_t helper_ev##name (uint64_t op1, uint64_t op2) \
2773{ \
2774 return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
2775}
2776/* evfststlt */
2777HELPER_VECTOR_SPE_CMP(fststlt);
2778/* evfststgt */
2779HELPER_VECTOR_SPE_CMP(fststgt);
2780/* evfststeq */
2781HELPER_VECTOR_SPE_CMP(fststeq);
2782/* evfscmplt */
2783HELPER_VECTOR_SPE_CMP(fscmplt);
2784/* evfscmpgt */
2785HELPER_VECTOR_SPE_CMP(fscmpgt);
2786/* evfscmpeq */
2787HELPER_VECTOR_SPE_CMP(fscmpeq);
2788
2789/* Double-precision floating-point conversion */
2790uint64_t helper_efdcfsi (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002791{
aurel321c978562008-11-23 10:54:04 +00002792 CPU_DoubleU u;
2793
2794 u.d = int32_to_float64(val, &env->spe_status);
2795
2796 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00002797}
2798
aurel321c978562008-11-23 10:54:04 +00002799uint64_t helper_efdcfsid (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002800{
aurel320ca9d382008-03-13 19:19:16 +00002801 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002802
aurel320ca9d382008-03-13 19:19:16 +00002803 u.d = int64_to_float64(val, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002804
aurel320ca9d382008-03-13 19:19:16 +00002805 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00002806}
2807
aurel321c978562008-11-23 10:54:04 +00002808uint64_t helper_efdcfui (uint32_t val)
2809{
2810 CPU_DoubleU u;
2811
2812 u.d = uint32_to_float64(val, &env->spe_status);
2813
2814 return u.ll;
2815}
2816
2817uint64_t helper_efdcfuid (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002818{
aurel320ca9d382008-03-13 19:19:16 +00002819 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002820
aurel320ca9d382008-03-13 19:19:16 +00002821 u.d = uint64_to_float64(val, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002822
aurel320ca9d382008-03-13 19:19:16 +00002823 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00002824}
2825
aurel321c978562008-11-23 10:54:04 +00002826uint32_t helper_efdctsi (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002827{
aurel320ca9d382008-03-13 19:19:16 +00002828 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002829
aurel320ca9d382008-03-13 19:19:16 +00002830 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002831 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002832 if (unlikely(float64_is_nan(u.d)))
j_mayer0487d6a2007-03-20 22:11:31 +00002833 return 0;
2834
aurel321c978562008-11-23 10:54:04 +00002835 return float64_to_int32(u.d, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002836}
2837
aurel321c978562008-11-23 10:54:04 +00002838uint32_t helper_efdctui (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002839{
aurel320ca9d382008-03-13 19:19:16 +00002840 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002841
aurel320ca9d382008-03-13 19:19:16 +00002842 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002843 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002844 if (unlikely(float64_is_nan(u.d)))
j_mayer0487d6a2007-03-20 22:11:31 +00002845 return 0;
2846
aurel321c978562008-11-23 10:54:04 +00002847 return float64_to_uint32(u.d, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002848}
2849
aurel321c978562008-11-23 10:54:04 +00002850uint32_t helper_efdctsiz (uint64_t val)
2851{
2852 CPU_DoubleU u;
2853
2854 u.ll = val;
2855 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002856 if (unlikely(float64_is_nan(u.d)))
aurel321c978562008-11-23 10:54:04 +00002857 return 0;
2858
2859 return float64_to_int32_round_to_zero(u.d, &env->spe_status);
2860}
2861
2862uint64_t helper_efdctsidz (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002863{
aurel320ca9d382008-03-13 19:19:16 +00002864 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002865
aurel320ca9d382008-03-13 19:19:16 +00002866 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002867 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002868 if (unlikely(float64_is_nan(u.d)))
j_mayer0487d6a2007-03-20 22:11:31 +00002869 return 0;
2870
aurel320ca9d382008-03-13 19:19:16 +00002871 return float64_to_int64_round_to_zero(u.d, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002872}
2873
aurel321c978562008-11-23 10:54:04 +00002874uint32_t helper_efdctuiz (uint64_t val)
2875{
2876 CPU_DoubleU u;
2877
2878 u.ll = val;
2879 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002880 if (unlikely(float64_is_nan(u.d)))
aurel321c978562008-11-23 10:54:04 +00002881 return 0;
2882
2883 return float64_to_uint32_round_to_zero(u.d, &env->spe_status);
2884}
2885
2886uint64_t helper_efdctuidz (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002887{
aurel320ca9d382008-03-13 19:19:16 +00002888 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002889
aurel320ca9d382008-03-13 19:19:16 +00002890 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002891 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002892 if (unlikely(float64_is_nan(u.d)))
j_mayer0487d6a2007-03-20 22:11:31 +00002893 return 0;
2894
aurel320ca9d382008-03-13 19:19:16 +00002895 return float64_to_uint64_round_to_zero(u.d, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002896}
2897
aurel321c978562008-11-23 10:54:04 +00002898uint64_t helper_efdcfsf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002899{
aurel320ca9d382008-03-13 19:19:16 +00002900 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002901 float64 tmp;
2902
aurel320ca9d382008-03-13 19:19:16 +00002903 u.d = int32_to_float64(val, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002904 tmp = int64_to_float64(1ULL << 32, &env->spe_status);
aurel320ca9d382008-03-13 19:19:16 +00002905 u.d = float64_div(u.d, tmp, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002906
aurel320ca9d382008-03-13 19:19:16 +00002907 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00002908}
2909
aurel321c978562008-11-23 10:54:04 +00002910uint64_t helper_efdcfuf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002911{
aurel320ca9d382008-03-13 19:19:16 +00002912 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002913 float64 tmp;
2914
aurel320ca9d382008-03-13 19:19:16 +00002915 u.d = uint32_to_float64(val, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002916 tmp = int64_to_float64(1ULL << 32, &env->spe_status);
aurel320ca9d382008-03-13 19:19:16 +00002917 u.d = float64_div(u.d, tmp, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002918
aurel320ca9d382008-03-13 19:19:16 +00002919 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00002920}
2921
aurel321c978562008-11-23 10:54:04 +00002922uint32_t helper_efdctsf (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002923{
aurel320ca9d382008-03-13 19:19:16 +00002924 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002925 float64 tmp;
2926
aurel320ca9d382008-03-13 19:19:16 +00002927 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002928 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002929 if (unlikely(float64_is_nan(u.d)))
j_mayer0487d6a2007-03-20 22:11:31 +00002930 return 0;
2931 tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
aurel320ca9d382008-03-13 19:19:16 +00002932 u.d = float64_mul(u.d, tmp, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002933
aurel320ca9d382008-03-13 19:19:16 +00002934 return float64_to_int32(u.d, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002935}
2936
aurel321c978562008-11-23 10:54:04 +00002937uint32_t helper_efdctuf (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002938{
aurel320ca9d382008-03-13 19:19:16 +00002939 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002940 float64 tmp;
2941
aurel320ca9d382008-03-13 19:19:16 +00002942 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002943 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002944 if (unlikely(float64_is_nan(u.d)))
j_mayer0487d6a2007-03-20 22:11:31 +00002945 return 0;
2946 tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
aurel320ca9d382008-03-13 19:19:16 +00002947 u.d = float64_mul(u.d, tmp, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002948
aurel320ca9d382008-03-13 19:19:16 +00002949 return float64_to_uint32(u.d, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002950}
2951
aurel321c978562008-11-23 10:54:04 +00002952uint32_t helper_efscfd (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002953{
aurel320ca9d382008-03-13 19:19:16 +00002954 CPU_DoubleU u1;
2955 CPU_FloatU u2;
j_mayer0487d6a2007-03-20 22:11:31 +00002956
aurel320ca9d382008-03-13 19:19:16 +00002957 u1.ll = val;
2958 u2.f = float64_to_float32(u1.d, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002959
aurel320ca9d382008-03-13 19:19:16 +00002960 return u2.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002961}
2962
aurel321c978562008-11-23 10:54:04 +00002963uint64_t helper_efdcfs (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002964{
aurel320ca9d382008-03-13 19:19:16 +00002965 CPU_DoubleU u2;
2966 CPU_FloatU u1;
j_mayer0487d6a2007-03-20 22:11:31 +00002967
aurel320ca9d382008-03-13 19:19:16 +00002968 u1.l = val;
2969 u2.d = float32_to_float64(u1.f, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002970
aurel320ca9d382008-03-13 19:19:16 +00002971 return u2.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00002972}
2973
aurel321c978562008-11-23 10:54:04 +00002974/* Double precision fixed-point arithmetic */
2975uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002976{
aurel321c978562008-11-23 10:54:04 +00002977 CPU_DoubleU u1, u2;
2978 u1.ll = op1;
2979 u2.ll = op2;
2980 u1.d = float64_add(u1.d, u2.d, &env->spe_status);
2981 return u1.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00002982}
2983
aurel321c978562008-11-23 10:54:04 +00002984uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002985{
aurel321c978562008-11-23 10:54:04 +00002986 CPU_DoubleU u1, u2;
2987 u1.ll = op1;
2988 u2.ll = op2;
2989 u1.d = float64_sub(u1.d, u2.d, &env->spe_status);
2990 return u1.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00002991}
2992
aurel321c978562008-11-23 10:54:04 +00002993uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
2994{
2995 CPU_DoubleU u1, u2;
2996 u1.ll = op1;
2997 u2.ll = op2;
2998 u1.d = float64_mul(u1.d, u2.d, &env->spe_status);
2999 return u1.ll;
3000}
j_mayer0487d6a2007-03-20 22:11:31 +00003001
aurel321c978562008-11-23 10:54:04 +00003002uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
3003{
3004 CPU_DoubleU u1, u2;
3005 u1.ll = op1;
3006 u2.ll = op2;
3007 u1.d = float64_div(u1.d, u2.d, &env->spe_status);
3008 return u1.ll;
3009}
3010
3011/* Double precision floating point helpers */
3012uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
3013{
3014 CPU_DoubleU u1, u2;
3015 u1.ll = op1;
3016 u2.ll = op2;
3017 return float64_lt(u1.d, u2.d, &env->spe_status) ? 4 : 0;
3018}
3019
3020uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
3021{
3022 CPU_DoubleU u1, u2;
3023 u1.ll = op1;
3024 u2.ll = op2;
3025 return float64_le(u1.d, u2.d, &env->spe_status) ? 0 : 4;
3026}
3027
3028uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
3029{
3030 CPU_DoubleU u1, u2;
3031 u1.ll = op1;
3032 u2.ll = op2;
3033 return float64_eq(u1.d, u2.d, &env->spe_status) ? 4 : 0;
3034}
3035
3036uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003037{
3038 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00003039 return helper_efdtstlt(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00003040}
3041
aurel321c978562008-11-23 10:54:04 +00003042uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003043{
3044 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00003045 return helper_efdtstgt(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00003046}
3047
aurel321c978562008-11-23 10:54:04 +00003048uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003049{
3050 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00003051 return helper_efdtsteq(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00003052}
3053
bellardfdabc362005-07-04 22:17:05 +00003054/*****************************************************************************/
3055/* Softmmu support */
3056#if !defined (CONFIG_USER_ONLY)
3057
3058#define MMUSUFFIX _mmu
bellardfdabc362005-07-04 22:17:05 +00003059
3060#define SHIFT 0
3061#include "softmmu_template.h"
3062
3063#define SHIFT 1
3064#include "softmmu_template.h"
3065
3066#define SHIFT 2
3067#include "softmmu_template.h"
3068
3069#define SHIFT 3
3070#include "softmmu_template.h"
3071
3072/* try to fill the TLB and return an exception if error. If retaddr is
3073 NULL, it means that the function was called in C code (i.e. not
3074 from generated code or from helper.c) */
3075/* XXX: fix it to restore all registers */
j_mayer6ebbf392007-10-14 07:07:08 +00003076void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
bellardfdabc362005-07-04 22:17:05 +00003077{
3078 TranslationBlock *tb;
3079 CPUState *saved_env;
bellard44f86252007-11-11 12:35:55 +00003080 unsigned long pc;
bellardfdabc362005-07-04 22:17:05 +00003081 int ret;
3082
3083 /* XXX: hack to restore env in all cases, even if not called from
3084 generated code */
3085 saved_env = env;
3086 env = cpu_single_env;
j_mayer6ebbf392007-10-14 07:07:08 +00003087 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
j_mayer76a66252007-03-07 08:32:30 +00003088 if (unlikely(ret != 0)) {
bellardfdabc362005-07-04 22:17:05 +00003089 if (likely(retaddr)) {
3090 /* now we have a real cpu fault */
bellard44f86252007-11-11 12:35:55 +00003091 pc = (unsigned long)retaddr;
bellardfdabc362005-07-04 22:17:05 +00003092 tb = tb_find_pc(pc);
3093 if (likely(tb)) {
3094 /* the PC is inside the translated code. It means that we have
3095 a virtual CPU fault */
3096 cpu_restore_state(tb, env, pc, NULL);
j_mayer76a66252007-03-07 08:32:30 +00003097 }
bellardfdabc362005-07-04 22:17:05 +00003098 }
aurel32e06fcd72008-12-11 22:42:14 +00003099 helper_raise_exception_err(env->exception_index, env->error_code);
bellardfdabc362005-07-04 22:17:05 +00003100 }
3101 env = saved_env;
3102}
bellardfdabc362005-07-04 22:17:05 +00003103
aurel3274d37792008-12-06 21:46:17 +00003104/* Segment registers load and store */
3105target_ulong helper_load_sr (target_ulong sr_num)
3106{
3107 return env->sr[sr_num];
3108}
3109
3110void helper_store_sr (target_ulong sr_num, target_ulong val)
3111{
aurel3245d827d2008-12-07 13:40:29 +00003112 ppc_store_sr(env, sr_num, val);
aurel3274d37792008-12-06 21:46:17 +00003113}
3114
3115/* SLB management */
3116#if defined(TARGET_PPC64)
3117target_ulong helper_load_slb (target_ulong slb_nr)
3118{
3119 return ppc_load_slb(env, slb_nr);
3120}
3121
3122void helper_store_slb (target_ulong slb_nr, target_ulong rs)
3123{
3124 ppc_store_slb(env, slb_nr, rs);
3125}
3126
3127void helper_slbia (void)
3128{
3129 ppc_slb_invalidate_all(env);
3130}
3131
3132void helper_slbie (target_ulong addr)
3133{
3134 ppc_slb_invalidate_one(env, addr);
3135}
3136
3137#endif /* defined(TARGET_PPC64) */
3138
3139/* TLB management */
3140void helper_tlbia (void)
3141{
3142 ppc_tlb_invalidate_all(env);
3143}
3144
3145void helper_tlbie (target_ulong addr)
3146{
3147 ppc_tlb_invalidate_one(env, addr);
3148}
3149
j_mayer76a66252007-03-07 08:32:30 +00003150/* Software driven TLBs management */
3151/* PowerPC 602/603 software TLB load instructions helpers */
aurel3274d37792008-12-06 21:46:17 +00003152static void do_6xx_tlb (target_ulong new_EPN, int is_code)
j_mayer76a66252007-03-07 08:32:30 +00003153{
3154 target_ulong RPN, CMP, EPN;
3155 int way;
j_mayerd9bce9d2007-03-17 14:02:15 +00003156
j_mayer76a66252007-03-07 08:32:30 +00003157 RPN = env->spr[SPR_RPA];
3158 if (is_code) {
3159 CMP = env->spr[SPR_ICMP];
3160 EPN = env->spr[SPR_IMISS];
3161 } else {
3162 CMP = env->spr[SPR_DCMP];
3163 EPN = env->spr[SPR_DMISS];
3164 }
3165 way = (env->spr[SPR_SRR1] >> 17) & 1;
3166#if defined (DEBUG_SOFTWARE_TLB)
3167 if (loglevel != 0) {
aurel320e698052008-12-08 18:11:42 +00003168 fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
j_mayer6b542af2007-11-24 02:03:55 +00003169 " PTE1 " ADDRX " way %d\n",
aurel320e698052008-12-08 18:11:42 +00003170 __func__, new_EPN, EPN, CMP, RPN, way);
j_mayer76a66252007-03-07 08:32:30 +00003171 }
3172#endif
3173 /* Store this TLB */
aurel320f3955e2008-11-30 16:22:56 +00003174 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
j_mayerd9bce9d2007-03-17 14:02:15 +00003175 way, is_code, CMP, RPN);
j_mayer76a66252007-03-07 08:32:30 +00003176}
3177
aurel3274d37792008-12-06 21:46:17 +00003178void helper_6xx_tlbd (target_ulong EPN)
aurel320f3955e2008-11-30 16:22:56 +00003179{
aurel3274d37792008-12-06 21:46:17 +00003180 do_6xx_tlb(EPN, 0);
aurel320f3955e2008-11-30 16:22:56 +00003181}
3182
aurel3274d37792008-12-06 21:46:17 +00003183void helper_6xx_tlbi (target_ulong EPN)
aurel320f3955e2008-11-30 16:22:56 +00003184{
aurel3274d37792008-12-06 21:46:17 +00003185 do_6xx_tlb(EPN, 1);
aurel320f3955e2008-11-30 16:22:56 +00003186}
3187
3188/* PowerPC 74xx software TLB load instructions helpers */
aurel3274d37792008-12-06 21:46:17 +00003189static void do_74xx_tlb (target_ulong new_EPN, int is_code)
j_mayer7dbe11a2007-10-01 05:16:57 +00003190{
3191 target_ulong RPN, CMP, EPN;
3192 int way;
3193
3194 RPN = env->spr[SPR_PTELO];
3195 CMP = env->spr[SPR_PTEHI];
3196 EPN = env->spr[SPR_TLBMISS] & ~0x3;
3197 way = env->spr[SPR_TLBMISS] & 0x3;
3198#if defined (DEBUG_SOFTWARE_TLB)
3199 if (loglevel != 0) {
aurel320e698052008-12-08 18:11:42 +00003200 fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
j_mayer6b542af2007-11-24 02:03:55 +00003201 " PTE1 " ADDRX " way %d\n",
aurel320e698052008-12-08 18:11:42 +00003202 __func__, new_EPN, EPN, CMP, RPN, way);
j_mayer7dbe11a2007-10-01 05:16:57 +00003203 }
3204#endif
3205 /* Store this TLB */
aurel320f3955e2008-11-30 16:22:56 +00003206 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
j_mayer7dbe11a2007-10-01 05:16:57 +00003207 way, is_code, CMP, RPN);
3208}
3209
aurel3274d37792008-12-06 21:46:17 +00003210void helper_74xx_tlbd (target_ulong EPN)
aurel320f3955e2008-11-30 16:22:56 +00003211{
aurel3274d37792008-12-06 21:46:17 +00003212 do_74xx_tlb(EPN, 0);
aurel320f3955e2008-11-30 16:22:56 +00003213}
3214
aurel3274d37792008-12-06 21:46:17 +00003215void helper_74xx_tlbi (target_ulong EPN)
aurel320f3955e2008-11-30 16:22:56 +00003216{
aurel3274d37792008-12-06 21:46:17 +00003217 do_74xx_tlb(EPN, 1);
aurel320f3955e2008-11-30 16:22:56 +00003218}
3219
j_mayera11b8152007-10-28 00:55:05 +00003220static always_inline target_ulong booke_tlb_to_page_size (int size)
j_mayera8dea122007-03-31 11:33:48 +00003221{
3222 return 1024 << (2 * size);
3223}
3224
j_mayera11b8152007-10-28 00:55:05 +00003225static always_inline int booke_page_size_to_tlb (target_ulong page_size)
j_mayera8dea122007-03-31 11:33:48 +00003226{
3227 int size;
3228
3229 switch (page_size) {
3230 case 0x00000400UL:
3231 size = 0x0;
3232 break;
3233 case 0x00001000UL:
3234 size = 0x1;
3235 break;
3236 case 0x00004000UL:
3237 size = 0x2;
3238 break;
3239 case 0x00010000UL:
3240 size = 0x3;
3241 break;
3242 case 0x00040000UL:
3243 size = 0x4;
3244 break;
3245 case 0x00100000UL:
3246 size = 0x5;
3247 break;
3248 case 0x00400000UL:
3249 size = 0x6;
3250 break;
3251 case 0x01000000UL:
3252 size = 0x7;
3253 break;
3254 case 0x04000000UL:
3255 size = 0x8;
3256 break;
3257 case 0x10000000UL:
3258 size = 0x9;
3259 break;
3260 case 0x40000000UL:
3261 size = 0xA;
3262 break;
3263#if defined (TARGET_PPC64)
3264 case 0x000100000000ULL:
3265 size = 0xB;
3266 break;
3267 case 0x000400000000ULL:
3268 size = 0xC;
3269 break;
3270 case 0x001000000000ULL:
3271 size = 0xD;
3272 break;
3273 case 0x004000000000ULL:
3274 size = 0xE;
3275 break;
3276 case 0x010000000000ULL:
3277 size = 0xF;
3278 break;
3279#endif
3280 default:
3281 size = -1;
3282 break;
3283 }
3284
3285 return size;
3286}
3287
j_mayer76a66252007-03-07 08:32:30 +00003288/* Helpers for 4xx TLB management */
aurel3274d37792008-12-06 21:46:17 +00003289target_ulong helper_4xx_tlbre_lo (target_ulong entry)
j_mayer76a66252007-03-07 08:32:30 +00003290{
j_mayera8dea122007-03-31 11:33:48 +00003291 ppcemb_tlb_t *tlb;
aurel3274d37792008-12-06 21:46:17 +00003292 target_ulong ret;
j_mayera8dea122007-03-31 11:33:48 +00003293 int size;
j_mayer76a66252007-03-07 08:32:30 +00003294
aurel3274d37792008-12-06 21:46:17 +00003295 entry &= 0x3F;
3296 tlb = &env->tlb[entry].tlbe;
3297 ret = tlb->EPN;
j_mayera8dea122007-03-31 11:33:48 +00003298 if (tlb->prot & PAGE_VALID)
aurel3274d37792008-12-06 21:46:17 +00003299 ret |= 0x400;
j_mayera8dea122007-03-31 11:33:48 +00003300 size = booke_page_size_to_tlb(tlb->size);
3301 if (size < 0 || size > 0x7)
3302 size = 1;
aurel3274d37792008-12-06 21:46:17 +00003303 ret |= size << 7;
j_mayera8dea122007-03-31 11:33:48 +00003304 env->spr[SPR_40x_PID] = tlb->PID;
aurel3274d37792008-12-06 21:46:17 +00003305 return ret;
j_mayer76a66252007-03-07 08:32:30 +00003306}
3307
aurel3274d37792008-12-06 21:46:17 +00003308target_ulong helper_4xx_tlbre_hi (target_ulong entry)
j_mayer76a66252007-03-07 08:32:30 +00003309{
j_mayera8dea122007-03-31 11:33:48 +00003310 ppcemb_tlb_t *tlb;
aurel3274d37792008-12-06 21:46:17 +00003311 target_ulong ret;
j_mayer76a66252007-03-07 08:32:30 +00003312
aurel3274d37792008-12-06 21:46:17 +00003313 entry &= 0x3F;
3314 tlb = &env->tlb[entry].tlbe;
3315 ret = tlb->RPN;
j_mayera8dea122007-03-31 11:33:48 +00003316 if (tlb->prot & PAGE_EXEC)
aurel3274d37792008-12-06 21:46:17 +00003317 ret |= 0x200;
j_mayera8dea122007-03-31 11:33:48 +00003318 if (tlb->prot & PAGE_WRITE)
aurel3274d37792008-12-06 21:46:17 +00003319 ret |= 0x100;
3320 return ret;
j_mayer76a66252007-03-07 08:32:30 +00003321}
3322
aurel3274d37792008-12-06 21:46:17 +00003323void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
j_mayer76a66252007-03-07 08:32:30 +00003324{
j_mayera8dea122007-03-31 11:33:48 +00003325 ppcemb_tlb_t *tlb;
j_mayer76a66252007-03-07 08:32:30 +00003326 target_ulong page, end;
3327
j_mayerc55e9ae2007-04-16 09:21:46 +00003328#if defined (DEBUG_SOFTWARE_TLB)
j_mayer6b800552007-04-24 07:36:03 +00003329 if (loglevel != 0) {
aurel320e698052008-12-08 18:11:42 +00003330 fprintf(logfile, "%s entry %d val " ADDRX "\n", __func__, (int)entry, val);
j_mayerc55e9ae2007-04-16 09:21:46 +00003331 }
3332#endif
aurel3274d37792008-12-06 21:46:17 +00003333 entry &= 0x3F;
3334 tlb = &env->tlb[entry].tlbe;
j_mayer76a66252007-03-07 08:32:30 +00003335 /* Invalidate previous TLB (if it's valid) */
3336 if (tlb->prot & PAGE_VALID) {
3337 end = tlb->EPN + tlb->size;
j_mayerc55e9ae2007-04-16 09:21:46 +00003338#if defined (DEBUG_SOFTWARE_TLB)
j_mayer6b800552007-04-24 07:36:03 +00003339 if (loglevel != 0) {
j_mayerc55e9ae2007-04-16 09:21:46 +00003340 fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
aurel3274d37792008-12-06 21:46:17 +00003341 " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
j_mayerc55e9ae2007-04-16 09:21:46 +00003342 }
3343#endif
j_mayer76a66252007-03-07 08:32:30 +00003344 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3345 tlb_flush_page(env, page);
3346 }
aurel3274d37792008-12-06 21:46:17 +00003347 tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
j_mayerc294fc52007-04-24 06:44:14 +00003348 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
3349 * If this ever occurs, one should use the ppcemb target instead
3350 * of the ppc or ppc64 one
3351 */
aurel3274d37792008-12-06 21:46:17 +00003352 if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
j_mayer71c8b8f2007-09-19 05:46:03 +00003353 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
3354 "are not supported (%d)\n",
aurel3274d37792008-12-06 21:46:17 +00003355 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
j_mayerc294fc52007-04-24 06:44:14 +00003356 }
aurel3274d37792008-12-06 21:46:17 +00003357 tlb->EPN = val & ~(tlb->size - 1);
3358 if (val & 0x40)
j_mayer76a66252007-03-07 08:32:30 +00003359 tlb->prot |= PAGE_VALID;
3360 else
3361 tlb->prot &= ~PAGE_VALID;
aurel3274d37792008-12-06 21:46:17 +00003362 if (val & 0x20) {
j_mayerc294fc52007-04-24 06:44:14 +00003363 /* XXX: TO BE FIXED */
3364 cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
3365 }
j_mayerc55e9ae2007-04-16 09:21:46 +00003366 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
aurel3274d37792008-12-06 21:46:17 +00003367 tlb->attr = val & 0xFF;
j_mayerc55e9ae2007-04-16 09:21:46 +00003368#if defined (DEBUG_SOFTWARE_TLB)
j_mayerc294fc52007-04-24 06:44:14 +00003369 if (loglevel != 0) {
3370 fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
j_mayerc55e9ae2007-04-16 09:21:46 +00003371 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
aurel320e698052008-12-08 18:11:42 +00003372 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
j_mayerc55e9ae2007-04-16 09:21:46 +00003373 tlb->prot & PAGE_READ ? 'r' : '-',
3374 tlb->prot & PAGE_WRITE ? 'w' : '-',
3375 tlb->prot & PAGE_EXEC ? 'x' : '-',
3376 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3377 }
3378#endif
j_mayer76a66252007-03-07 08:32:30 +00003379 /* Invalidate new TLB (if valid) */
3380 if (tlb->prot & PAGE_VALID) {
3381 end = tlb->EPN + tlb->size;
j_mayerc55e9ae2007-04-16 09:21:46 +00003382#if defined (DEBUG_SOFTWARE_TLB)
j_mayer6b800552007-04-24 07:36:03 +00003383 if (loglevel != 0) {
j_mayerc55e9ae2007-04-16 09:21:46 +00003384 fprintf(logfile, "%s: invalidate TLB %d start " ADDRX
aurel320e698052008-12-08 18:11:42 +00003385 " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
j_mayerc55e9ae2007-04-16 09:21:46 +00003386 }
3387#endif
j_mayer76a66252007-03-07 08:32:30 +00003388 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3389 tlb_flush_page(env, page);
3390 }
j_mayer76a66252007-03-07 08:32:30 +00003391}
3392
aurel3274d37792008-12-06 21:46:17 +00003393void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
j_mayer76a66252007-03-07 08:32:30 +00003394{
j_mayera8dea122007-03-31 11:33:48 +00003395 ppcemb_tlb_t *tlb;
j_mayer76a66252007-03-07 08:32:30 +00003396
j_mayerc55e9ae2007-04-16 09:21:46 +00003397#if defined (DEBUG_SOFTWARE_TLB)
j_mayer6b800552007-04-24 07:36:03 +00003398 if (loglevel != 0) {
aurel320e698052008-12-08 18:11:42 +00003399 fprintf(logfile, "%s entry %i val " ADDRX "\n", __func__, (int)entry, val);
j_mayerc55e9ae2007-04-16 09:21:46 +00003400 }
3401#endif
aurel3274d37792008-12-06 21:46:17 +00003402 entry &= 0x3F;
3403 tlb = &env->tlb[entry].tlbe;
3404 tlb->RPN = val & 0xFFFFFC00;
j_mayer76a66252007-03-07 08:32:30 +00003405 tlb->prot = PAGE_READ;
aurel3274d37792008-12-06 21:46:17 +00003406 if (val & 0x200)
j_mayer76a66252007-03-07 08:32:30 +00003407 tlb->prot |= PAGE_EXEC;
aurel3274d37792008-12-06 21:46:17 +00003408 if (val & 0x100)
j_mayer76a66252007-03-07 08:32:30 +00003409 tlb->prot |= PAGE_WRITE;
j_mayerc55e9ae2007-04-16 09:21:46 +00003410#if defined (DEBUG_SOFTWARE_TLB)
j_mayer6b800552007-04-24 07:36:03 +00003411 if (loglevel != 0) {
3412 fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
j_mayerc55e9ae2007-04-16 09:21:46 +00003413 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
aurel3274d37792008-12-06 21:46:17 +00003414 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
j_mayerc55e9ae2007-04-16 09:21:46 +00003415 tlb->prot & PAGE_READ ? 'r' : '-',
3416 tlb->prot & PAGE_WRITE ? 'w' : '-',
3417 tlb->prot & PAGE_EXEC ? 'x' : '-',
3418 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3419 }
3420#endif
j_mayer76a66252007-03-07 08:32:30 +00003421}
j_mayer5eb79952007-09-19 05:44:04 +00003422
aurel3274d37792008-12-06 21:46:17 +00003423target_ulong helper_4xx_tlbsx (target_ulong address)
3424{
3425 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
3426}
3427
j_mayera4bb6c32007-09-21 05:28:33 +00003428/* PowerPC 440 TLB management */
aurel3274d37792008-12-06 21:46:17 +00003429void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
j_mayer5eb79952007-09-19 05:44:04 +00003430{
3431 ppcemb_tlb_t *tlb;
j_mayera4bb6c32007-09-21 05:28:33 +00003432 target_ulong EPN, RPN, size;
j_mayer5eb79952007-09-19 05:44:04 +00003433 int do_flush_tlbs;
3434
3435#if defined (DEBUG_SOFTWARE_TLB)
3436 if (loglevel != 0) {
aurel320e698052008-12-08 18:11:42 +00003437 fprintf(logfile, "%s word %d entry %d value " ADDRX "\n",
3438 __func__, word, (int)entry, value);
j_mayer5eb79952007-09-19 05:44:04 +00003439 }
3440#endif
3441 do_flush_tlbs = 0;
aurel3274d37792008-12-06 21:46:17 +00003442 entry &= 0x3F;
3443 tlb = &env->tlb[entry].tlbe;
j_mayera4bb6c32007-09-21 05:28:33 +00003444 switch (word) {
3445 default:
3446 /* Just here to please gcc */
3447 case 0:
aurel3274d37792008-12-06 21:46:17 +00003448 EPN = value & 0xFFFFFC00;
j_mayera4bb6c32007-09-21 05:28:33 +00003449 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
j_mayer5eb79952007-09-19 05:44:04 +00003450 do_flush_tlbs = 1;
j_mayera4bb6c32007-09-21 05:28:33 +00003451 tlb->EPN = EPN;
aurel3274d37792008-12-06 21:46:17 +00003452 size = booke_tlb_to_page_size((value >> 4) & 0xF);
j_mayera4bb6c32007-09-21 05:28:33 +00003453 if ((tlb->prot & PAGE_VALID) && tlb->size < size)
3454 do_flush_tlbs = 1;
3455 tlb->size = size;
3456 tlb->attr &= ~0x1;
aurel3274d37792008-12-06 21:46:17 +00003457 tlb->attr |= (value >> 8) & 1;
3458 if (value & 0x200) {
j_mayera4bb6c32007-09-21 05:28:33 +00003459 tlb->prot |= PAGE_VALID;
3460 } else {
3461 if (tlb->prot & PAGE_VALID) {
3462 tlb->prot &= ~PAGE_VALID;
3463 do_flush_tlbs = 1;
3464 }
j_mayer5eb79952007-09-19 05:44:04 +00003465 }
j_mayera4bb6c32007-09-21 05:28:33 +00003466 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
3467 if (do_flush_tlbs)
3468 tlb_flush(env, 1);
3469 break;
3470 case 1:
aurel3274d37792008-12-06 21:46:17 +00003471 RPN = value & 0xFFFFFC0F;
j_mayera4bb6c32007-09-21 05:28:33 +00003472 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
3473 tlb_flush(env, 1);
3474 tlb->RPN = RPN;
3475 break;
3476 case 2:
aurel3274d37792008-12-06 21:46:17 +00003477 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
j_mayera4bb6c32007-09-21 05:28:33 +00003478 tlb->prot = tlb->prot & PAGE_VALID;
aurel3274d37792008-12-06 21:46:17 +00003479 if (value & 0x1)
j_mayera4bb6c32007-09-21 05:28:33 +00003480 tlb->prot |= PAGE_READ << 4;
aurel3274d37792008-12-06 21:46:17 +00003481 if (value & 0x2)
j_mayera4bb6c32007-09-21 05:28:33 +00003482 tlb->prot |= PAGE_WRITE << 4;
aurel3274d37792008-12-06 21:46:17 +00003483 if (value & 0x4)
j_mayera4bb6c32007-09-21 05:28:33 +00003484 tlb->prot |= PAGE_EXEC << 4;
aurel3274d37792008-12-06 21:46:17 +00003485 if (value & 0x8)
j_mayera4bb6c32007-09-21 05:28:33 +00003486 tlb->prot |= PAGE_READ;
aurel3274d37792008-12-06 21:46:17 +00003487 if (value & 0x10)
j_mayera4bb6c32007-09-21 05:28:33 +00003488 tlb->prot |= PAGE_WRITE;
aurel3274d37792008-12-06 21:46:17 +00003489 if (value & 0x20)
j_mayera4bb6c32007-09-21 05:28:33 +00003490 tlb->prot |= PAGE_EXEC;
3491 break;
j_mayer5eb79952007-09-19 05:44:04 +00003492 }
j_mayer5eb79952007-09-19 05:44:04 +00003493}
3494
aurel3274d37792008-12-06 21:46:17 +00003495target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
j_mayer5eb79952007-09-19 05:44:04 +00003496{
3497 ppcemb_tlb_t *tlb;
aurel3274d37792008-12-06 21:46:17 +00003498 target_ulong ret;
j_mayer5eb79952007-09-19 05:44:04 +00003499 int size;
3500
aurel3274d37792008-12-06 21:46:17 +00003501 entry &= 0x3F;
3502 tlb = &env->tlb[entry].tlbe;
j_mayera4bb6c32007-09-21 05:28:33 +00003503 switch (word) {
3504 default:
3505 /* Just here to please gcc */
3506 case 0:
aurel3274d37792008-12-06 21:46:17 +00003507 ret = tlb->EPN;
j_mayera4bb6c32007-09-21 05:28:33 +00003508 size = booke_page_size_to_tlb(tlb->size);
3509 if (size < 0 || size > 0xF)
3510 size = 1;
aurel3274d37792008-12-06 21:46:17 +00003511 ret |= size << 4;
j_mayera4bb6c32007-09-21 05:28:33 +00003512 if (tlb->attr & 0x1)
aurel3274d37792008-12-06 21:46:17 +00003513 ret |= 0x100;
j_mayera4bb6c32007-09-21 05:28:33 +00003514 if (tlb->prot & PAGE_VALID)
aurel3274d37792008-12-06 21:46:17 +00003515 ret |= 0x200;
j_mayera4bb6c32007-09-21 05:28:33 +00003516 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
3517 env->spr[SPR_440_MMUCR] |= tlb->PID;
3518 break;
3519 case 1:
aurel3274d37792008-12-06 21:46:17 +00003520 ret = tlb->RPN;
j_mayera4bb6c32007-09-21 05:28:33 +00003521 break;
3522 case 2:
aurel3274d37792008-12-06 21:46:17 +00003523 ret = tlb->attr & ~0x1;
j_mayera4bb6c32007-09-21 05:28:33 +00003524 if (tlb->prot & (PAGE_READ << 4))
aurel3274d37792008-12-06 21:46:17 +00003525 ret |= 0x1;
j_mayera4bb6c32007-09-21 05:28:33 +00003526 if (tlb->prot & (PAGE_WRITE << 4))
aurel3274d37792008-12-06 21:46:17 +00003527 ret |= 0x2;
j_mayera4bb6c32007-09-21 05:28:33 +00003528 if (tlb->prot & (PAGE_EXEC << 4))
aurel3274d37792008-12-06 21:46:17 +00003529 ret |= 0x4;
j_mayera4bb6c32007-09-21 05:28:33 +00003530 if (tlb->prot & PAGE_READ)
aurel3274d37792008-12-06 21:46:17 +00003531 ret |= 0x8;
j_mayera4bb6c32007-09-21 05:28:33 +00003532 if (tlb->prot & PAGE_WRITE)
aurel3274d37792008-12-06 21:46:17 +00003533 ret |= 0x10;
j_mayera4bb6c32007-09-21 05:28:33 +00003534 if (tlb->prot & PAGE_EXEC)
aurel3274d37792008-12-06 21:46:17 +00003535 ret |= 0x20;
j_mayera4bb6c32007-09-21 05:28:33 +00003536 break;
3537 }
aurel3274d37792008-12-06 21:46:17 +00003538 return ret;
j_mayer5eb79952007-09-19 05:44:04 +00003539}
aurel3274d37792008-12-06 21:46:17 +00003540
3541target_ulong helper_440_tlbsx (target_ulong address)
3542{
3543 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
3544}
3545
j_mayer76a66252007-03-07 08:32:30 +00003546#endif /* !CONFIG_USER_ONLY */