blob: ee086527e0589d595bc2ebca8a576401f457626c [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
aurel32bf8d8de2009-01-04 22:09:42 +00001975void helper_lvsl (ppc_avr_t *r, target_ulong sh)
1976{
1977 int i, j = (sh & 0xf);
1978
1979 VECTOR_FOR_INORDER_I (i, u8) {
1980 r->u8[i] = j++;
1981 }
1982}
1983
1984void helper_lvsr (ppc_avr_t *r, target_ulong sh)
1985{
1986 int i, j = 0x10 - (sh & 0xf);
1987
1988 VECTOR_FOR_INORDER_I (i, u8) {
1989 r->u8[i] = j++;
1990 }
1991}
1992
aurel32e343da72009-01-04 22:09:31 +00001993void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
1994{
1995 int i;
1996 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
1997 r->u32[i] = ~a->u32[i] < b->u32[i];
1998 }
1999}
2000
aurel327872c512009-01-03 13:31:40 +00002001#define VARITH_DO(name, op, element) \
2002void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2003{ \
2004 int i; \
2005 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2006 r->element[i] = a->element[i] op b->element[i]; \
2007 } \
2008}
2009#define VARITH(suffix, element) \
2010 VARITH_DO(add##suffix, +, element) \
2011 VARITH_DO(sub##suffix, -, element)
2012VARITH(ubm, u8)
2013VARITH(uhm, u16)
2014VARITH(uwm, u32)
2015#undef VARITH_DO
2016#undef VARITH
2017
aurel32fab3cbe2009-01-03 13:31:49 +00002018#define VAVG_DO(name, element, etype) \
2019 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2020 { \
2021 int i; \
2022 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2023 etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
2024 r->element[i] = x >> 1; \
2025 } \
2026 }
2027
2028#define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
2029 VAVG_DO(avgs##type, signed_element, signed_type) \
2030 VAVG_DO(avgu##type, unsigned_element, unsigned_type)
2031VAVG(b, s8, int16_t, u8, uint16_t)
2032VAVG(h, s16, int32_t, u16, uint32_t)
2033VAVG(w, s32, int64_t, u32, uint64_t)
2034#undef VAVG_DO
2035#undef VAVG
2036
aurel32e4039332009-01-03 13:31:58 +00002037#define VMINMAX_DO(name, compare, element) \
2038 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2039 { \
2040 int i; \
2041 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2042 if (a->element[i] compare b->element[i]) { \
2043 r->element[i] = b->element[i]; \
2044 } else { \
2045 r->element[i] = a->element[i]; \
2046 } \
2047 } \
2048 }
2049#define VMINMAX(suffix, element) \
2050 VMINMAX_DO(min##suffix, >, element) \
2051 VMINMAX_DO(max##suffix, <, element)
2052VMINMAX(sb, s8)
2053VMINMAX(sh, s16)
2054VMINMAX(sw, s32)
2055VMINMAX(ub, u8)
2056VMINMAX(uh, u16)
2057VMINMAX(uw, u32)
2058#undef VMINMAX_DO
2059#undef VMINMAX
2060
aurel323b430042009-01-04 22:08:38 +00002061#define VMRG_DO(name, element, highp) \
2062 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2063 { \
2064 ppc_avr_t result; \
2065 int i; \
2066 size_t n_elems = ARRAY_SIZE(r->element); \
2067 for (i = 0; i < n_elems/2; i++) { \
2068 if (highp) { \
2069 result.element[i*2+HI_IDX] = a->element[i]; \
2070 result.element[i*2+LO_IDX] = b->element[i]; \
2071 } else { \
2072 result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
2073 result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
2074 } \
2075 } \
2076 *r = result; \
2077 }
2078#if defined(WORDS_BIGENDIAN)
2079#define MRGHI 0
2080#define MRGL0 1
2081#else
2082#define MRGHI 1
2083#define MRGLO 0
2084#endif
2085#define VMRG(suffix, element) \
2086 VMRG_DO(mrgl##suffix, element, MRGHI) \
2087 VMRG_DO(mrgh##suffix, element, MRGLO)
2088VMRG(b, u8)
2089VMRG(h, u16)
2090VMRG(w, u32)
2091#undef VMRG_DO
2092#undef VMRG
2093#undef MRGHI
2094#undef MRGLO
2095
aurel322c277902009-01-04 22:08:48 +00002096#define VMUL_DO(name, mul_element, prod_element, evenp) \
2097 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2098 { \
2099 int i; \
2100 VECTOR_FOR_INORDER_I(i, prod_element) { \
2101 if (evenp) { \
2102 r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2103 } else { \
2104 r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2105 } \
2106 } \
2107 }
2108#define VMUL(suffix, mul_element, prod_element) \
2109 VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2110 VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2111VMUL(sb, s8, s16)
2112VMUL(sh, s16, s32)
2113VMUL(ub, u8, u16)
2114VMUL(uh, u16, u32)
2115#undef VMUL_DO
2116#undef VMUL
2117
aurel325e1d0982009-01-04 22:09:52 +00002118#define VROTATE(suffix, element) \
2119 void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2120 { \
2121 int i; \
2122 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2123 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2124 unsigned int shift = b->element[i] & mask; \
2125 r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2126 } \
2127 }
2128VROTATE(b, u8)
2129VROTATE(h, u16)
2130VROTATE(w, u32)
2131#undef VROTATE
2132
aurel32d79f0802009-01-04 22:09:08 +00002133#define VSL(suffix, element) \
2134 void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2135 { \
2136 int i; \
2137 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2138 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2139 unsigned int shift = b->element[i] & mask; \
2140 r->element[i] = a->element[i] << shift; \
2141 } \
2142 }
2143VSL(b, u8)
2144VSL(h, u16)
2145VSL(w, u32)
2146#undef VSL
2147
aurel32cd633b12009-01-04 22:10:09 +00002148void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
2149{
2150 int sh = shift & 0xf;
2151 int i;
2152 ppc_avr_t result;
2153
2154#if defined(WORDS_BIGENDIAN)
2155 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2156 int index = sh + i;
2157 if (index > 0xf) {
2158 result.u8[i] = b->u8[index-0x10];
2159 } else {
2160 result.u8[i] = a->u8[index];
2161 }
2162 }
2163#else
2164 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2165 int index = (16 - sh) + i;
2166 if (index > 0xf) {
2167 result.u8[i] = a->u8[index-0x10];
2168 } else {
2169 result.u8[i] = b->u8[index];
2170 }
2171 }
2172#endif
2173 *r = result;
2174}
2175
aurel327b239be2009-01-04 22:09:19 +00002176void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2177{
2178 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2179
2180#if defined (WORDS_BIGENDIAN)
2181 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2182 memset (&r->u8[16-sh], 0, sh);
2183#else
2184 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2185 memset (&r->u8[0], 0, sh);
2186#endif
2187}
2188
aurel32e4e6bee2009-01-04 22:10:49 +00002189/* Experimental testing shows that hardware masks the immediate. */
2190#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
2191#if defined(WORDS_BIGENDIAN)
2192#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2193#else
2194#define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
2195#endif
2196#define VSPLT(suffix, element) \
2197 void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
2198 { \
2199 uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
2200 int i; \
2201 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2202 r->element[i] = s; \
2203 } \
2204 }
2205VSPLT(b, u8)
2206VSPLT(h, u16)
2207VSPLT(w, u32)
2208#undef VSPLT
2209#undef SPLAT_ELEMENT
2210#undef _SPLAT_MASKED
2211
aurel3207ef34c2009-01-04 22:08:58 +00002212#define VSR(suffix, element) \
2213 void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2214 { \
2215 int i; \
2216 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2217 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2218 unsigned int shift = b->element[i] & mask; \
2219 r->element[i] = a->element[i] >> shift; \
2220 } \
2221 }
2222VSR(ab, s8)
2223VSR(ah, s16)
2224VSR(aw, s32)
2225VSR(b, u8)
2226VSR(h, u16)
2227VSR(w, u32)
2228#undef VSR
2229
aurel327b239be2009-01-04 22:09:19 +00002230void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2231{
2232 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2233
2234#if defined (WORDS_BIGENDIAN)
2235 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2236 memset (&r->u8[0], 0, sh);
2237#else
2238 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2239 memset (&r->u8[16-sh], 0, sh);
2240#endif
2241}
2242
aurel32e343da72009-01-04 22:09:31 +00002243void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
2244{
2245 int i;
2246 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2247 r->u32[i] = a->u32[i] >= b->u32[i];
2248 }
2249}
2250
aurel3279f85c32009-01-04 22:11:10 +00002251#if defined(WORDS_BIGENDIAN)
2252#define UPKHI 1
2253#define UPKLO 0
2254#else
2255#define UPKHI 0
2256#define UPKLO 1
2257#endif
2258#define VUPKPX(suffix, hi) \
2259 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2260 { \
2261 int i; \
2262 ppc_avr_t result; \
2263 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
2264 uint16_t e = b->u16[hi ? i : i+4]; \
2265 uint8_t a = (e >> 15) ? 0xff : 0; \
2266 uint8_t r = (e >> 10) & 0x1f; \
2267 uint8_t g = (e >> 5) & 0x1f; \
2268 uint8_t b = e & 0x1f; \
2269 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
2270 } \
2271 *r = result; \
2272 }
2273VUPKPX(lpx, UPKLO)
2274VUPKPX(hpx, UPKHI)
2275#undef VUPKPX
2276
aurel326cf1c6e2009-01-04 22:11:20 +00002277#define VUPK(suffix, unpacked, packee, hi) \
2278 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
2279 { \
2280 int i; \
2281 ppc_avr_t result; \
2282 if (hi) { \
2283 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
2284 result.unpacked[i] = b->packee[i]; \
2285 } \
2286 } else { \
2287 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
2288 result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
2289 } \
2290 } \
2291 *r = result; \
2292 }
2293VUPK(hsb, s16, s8, UPKHI)
2294VUPK(hsh, s32, s16, UPKHI)
2295VUPK(lsb, s16, s8, UPKLO)
2296VUPK(lsh, s32, s16, UPKLO)
2297#undef VUPK
aurel3279f85c32009-01-04 22:11:10 +00002298#undef UPKHI
2299#undef UPKLO
2300
aurel32d6a46fe2009-01-03 13:31:19 +00002301#undef VECTOR_FOR_INORDER_I
2302#undef HI_IDX
2303#undef LO_IDX
2304
2305/*****************************************************************************/
j_mayer0487d6a2007-03-20 22:11:31 +00002306/* SPE extension helpers */
2307/* Use a table to make this quicker */
2308static uint8_t hbrev[16] = {
2309 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
2310 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
2311};
2312
j_mayerb068d6a2007-10-07 17:13:44 +00002313static always_inline uint8_t byte_reverse (uint8_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002314{
2315 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
2316}
2317
j_mayerb068d6a2007-10-07 17:13:44 +00002318static always_inline uint32_t word_reverse (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002319{
2320 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
2321 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
2322}
2323
j_mayer3cd7d1d2007-11-12 01:56:18 +00002324#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
aurel3257951c22008-11-10 11:10:23 +00002325target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
j_mayer0487d6a2007-03-20 22:11:31 +00002326{
2327 uint32_t a, b, d, mask;
2328
j_mayer3cd7d1d2007-11-12 01:56:18 +00002329 mask = UINT32_MAX >> (32 - MASKBITS);
aurel3257951c22008-11-10 11:10:23 +00002330 a = arg1 & mask;
2331 b = arg2 & mask;
j_mayer3cd7d1d2007-11-12 01:56:18 +00002332 d = word_reverse(1 + word_reverse(a | ~b));
aurel3257951c22008-11-10 11:10:23 +00002333 return (arg1 & ~mask) | (d & b);
j_mayer0487d6a2007-03-20 22:11:31 +00002334}
2335
aurel3257951c22008-11-10 11:10:23 +00002336uint32_t helper_cntlsw32 (uint32_t val)
2337{
2338 if (val & 0x80000000)
2339 return clz32(~val);
2340 else
2341 return clz32(val);
2342}
2343
2344uint32_t helper_cntlzw32 (uint32_t val)
2345{
2346 return clz32(val);
j_mayer0487d6a2007-03-20 22:11:31 +00002347}
2348
aurel321c978562008-11-23 10:54:04 +00002349/* Single-precision floating-point conversions */
2350static always_inline uint32_t efscfsi (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002351{
aurel320ca9d382008-03-13 19:19:16 +00002352 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002353
2354 u.f = int32_to_float32(val, &env->spe_status);
2355
aurel320ca9d382008-03-13 19:19:16 +00002356 return u.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002357}
2358
aurel321c978562008-11-23 10:54:04 +00002359static always_inline uint32_t efscfui (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002360{
aurel320ca9d382008-03-13 19:19:16 +00002361 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002362
2363 u.f = uint32_to_float32(val, &env->spe_status);
2364
aurel320ca9d382008-03-13 19:19:16 +00002365 return u.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002366}
2367
aurel321c978562008-11-23 10:54:04 +00002368static always_inline int32_t efsctsi (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002369{
aurel320ca9d382008-03-13 19:19:16 +00002370 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002371
aurel320ca9d382008-03-13 19:19:16 +00002372 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002373 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002374 if (unlikely(float32_is_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00002375 return 0;
2376
2377 return float32_to_int32(u.f, &env->spe_status);
2378}
2379
aurel321c978562008-11-23 10:54:04 +00002380static always_inline uint32_t efsctui (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002381{
aurel320ca9d382008-03-13 19:19:16 +00002382 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002383
aurel320ca9d382008-03-13 19:19:16 +00002384 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002385 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002386 if (unlikely(float32_is_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00002387 return 0;
2388
2389 return float32_to_uint32(u.f, &env->spe_status);
2390}
2391
aurel321c978562008-11-23 10:54:04 +00002392static always_inline uint32_t efsctsiz (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002393{
aurel320ca9d382008-03-13 19:19:16 +00002394 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002395
aurel320ca9d382008-03-13 19:19:16 +00002396 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002397 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002398 if (unlikely(float32_is_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00002399 return 0;
2400
2401 return float32_to_int32_round_to_zero(u.f, &env->spe_status);
2402}
2403
aurel321c978562008-11-23 10:54:04 +00002404static always_inline uint32_t efsctuiz (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002405{
aurel320ca9d382008-03-13 19:19:16 +00002406 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002407
aurel320ca9d382008-03-13 19:19:16 +00002408 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002409 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002410 if (unlikely(float32_is_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00002411 return 0;
2412
2413 return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
2414}
2415
aurel321c978562008-11-23 10:54:04 +00002416static always_inline uint32_t efscfsf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002417{
aurel320ca9d382008-03-13 19:19:16 +00002418 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002419 float32 tmp;
2420
2421 u.f = int32_to_float32(val, &env->spe_status);
2422 tmp = int64_to_float32(1ULL << 32, &env->spe_status);
2423 u.f = float32_div(u.f, tmp, &env->spe_status);
2424
aurel320ca9d382008-03-13 19:19:16 +00002425 return u.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002426}
2427
aurel321c978562008-11-23 10:54:04 +00002428static always_inline uint32_t efscfuf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002429{
aurel320ca9d382008-03-13 19:19:16 +00002430 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002431 float32 tmp;
2432
2433 u.f = uint32_to_float32(val, &env->spe_status);
2434 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2435 u.f = float32_div(u.f, tmp, &env->spe_status);
2436
aurel320ca9d382008-03-13 19:19:16 +00002437 return u.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002438}
2439
aurel321c978562008-11-23 10:54:04 +00002440static always_inline uint32_t efsctsf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002441{
aurel320ca9d382008-03-13 19:19:16 +00002442 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002443 float32 tmp;
2444
aurel320ca9d382008-03-13 19:19:16 +00002445 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002446 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002447 if (unlikely(float32_is_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00002448 return 0;
2449 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2450 u.f = float32_mul(u.f, tmp, &env->spe_status);
2451
2452 return float32_to_int32(u.f, &env->spe_status);
2453}
2454
aurel321c978562008-11-23 10:54:04 +00002455static always_inline uint32_t efsctuf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002456{
aurel320ca9d382008-03-13 19:19:16 +00002457 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002458 float32 tmp;
2459
aurel320ca9d382008-03-13 19:19:16 +00002460 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002461 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002462 if (unlikely(float32_is_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00002463 return 0;
2464 tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
2465 u.f = float32_mul(u.f, tmp, &env->spe_status);
2466
2467 return float32_to_uint32(u.f, &env->spe_status);
2468}
2469
aurel321c978562008-11-23 10:54:04 +00002470#define HELPER_SPE_SINGLE_CONV(name) \
2471uint32_t helper_e##name (uint32_t val) \
2472{ \
2473 return e##name(val); \
2474}
2475/* efscfsi */
2476HELPER_SPE_SINGLE_CONV(fscfsi);
2477/* efscfui */
2478HELPER_SPE_SINGLE_CONV(fscfui);
2479/* efscfuf */
2480HELPER_SPE_SINGLE_CONV(fscfuf);
2481/* efscfsf */
2482HELPER_SPE_SINGLE_CONV(fscfsf);
2483/* efsctsi */
2484HELPER_SPE_SINGLE_CONV(fsctsi);
2485/* efsctui */
2486HELPER_SPE_SINGLE_CONV(fsctui);
2487/* efsctsiz */
2488HELPER_SPE_SINGLE_CONV(fsctsiz);
2489/* efsctuiz */
2490HELPER_SPE_SINGLE_CONV(fsctuiz);
2491/* efsctsf */
2492HELPER_SPE_SINGLE_CONV(fsctsf);
2493/* efsctuf */
2494HELPER_SPE_SINGLE_CONV(fsctuf);
2495
2496#define HELPER_SPE_VECTOR_CONV(name) \
2497uint64_t helper_ev##name (uint64_t val) \
2498{ \
2499 return ((uint64_t)e##name(val >> 32) << 32) | \
2500 (uint64_t)e##name(val); \
2501}
2502/* evfscfsi */
2503HELPER_SPE_VECTOR_CONV(fscfsi);
2504/* evfscfui */
2505HELPER_SPE_VECTOR_CONV(fscfui);
2506/* evfscfuf */
2507HELPER_SPE_VECTOR_CONV(fscfuf);
2508/* evfscfsf */
2509HELPER_SPE_VECTOR_CONV(fscfsf);
2510/* evfsctsi */
2511HELPER_SPE_VECTOR_CONV(fsctsi);
2512/* evfsctui */
2513HELPER_SPE_VECTOR_CONV(fsctui);
2514/* evfsctsiz */
2515HELPER_SPE_VECTOR_CONV(fsctsiz);
2516/* evfsctuiz */
2517HELPER_SPE_VECTOR_CONV(fsctuiz);
2518/* evfsctsf */
2519HELPER_SPE_VECTOR_CONV(fsctsf);
2520/* evfsctuf */
2521HELPER_SPE_VECTOR_CONV(fsctuf);
2522
2523/* Single-precision floating-point arithmetic */
2524static always_inline uint32_t efsadd (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002525{
aurel321c978562008-11-23 10:54:04 +00002526 CPU_FloatU u1, u2;
2527 u1.l = op1;
2528 u2.l = op2;
2529 u1.f = float32_add(u1.f, u2.f, &env->spe_status);
2530 return u1.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002531}
2532
aurel321c978562008-11-23 10:54:04 +00002533static always_inline uint32_t efssub (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002534{
aurel321c978562008-11-23 10:54:04 +00002535 CPU_FloatU u1, u2;
2536 u1.l = op1;
2537 u2.l = op2;
2538 u1.f = float32_sub(u1.f, u2.f, &env->spe_status);
2539 return u1.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002540}
2541
aurel321c978562008-11-23 10:54:04 +00002542static always_inline uint32_t efsmul (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002543{
aurel321c978562008-11-23 10:54:04 +00002544 CPU_FloatU u1, u2;
2545 u1.l = op1;
2546 u2.l = op2;
2547 u1.f = float32_mul(u1.f, u2.f, &env->spe_status);
2548 return u1.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002549}
2550
aurel321c978562008-11-23 10:54:04 +00002551static always_inline uint32_t efsdiv (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002552{
aurel321c978562008-11-23 10:54:04 +00002553 CPU_FloatU u1, u2;
2554 u1.l = op1;
2555 u2.l = op2;
2556 u1.f = float32_div(u1.f, u2.f, &env->spe_status);
2557 return u1.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002558}
2559
aurel321c978562008-11-23 10:54:04 +00002560#define HELPER_SPE_SINGLE_ARITH(name) \
2561uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
2562{ \
2563 return e##name(op1, op2); \
2564}
2565/* efsadd */
2566HELPER_SPE_SINGLE_ARITH(fsadd);
2567/* efssub */
2568HELPER_SPE_SINGLE_ARITH(fssub);
2569/* efsmul */
2570HELPER_SPE_SINGLE_ARITH(fsmul);
2571/* efsdiv */
2572HELPER_SPE_SINGLE_ARITH(fsdiv);
2573
2574#define HELPER_SPE_VECTOR_ARITH(name) \
2575uint64_t helper_ev##name (uint64_t op1, uint64_t op2) \
2576{ \
2577 return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
2578 (uint64_t)e##name(op1, op2); \
2579}
2580/* evfsadd */
2581HELPER_SPE_VECTOR_ARITH(fsadd);
2582/* evfssub */
2583HELPER_SPE_VECTOR_ARITH(fssub);
2584/* evfsmul */
2585HELPER_SPE_VECTOR_ARITH(fsmul);
2586/* evfsdiv */
2587HELPER_SPE_VECTOR_ARITH(fsdiv);
2588
2589/* Single-precision floating-point comparisons */
2590static always_inline uint32_t efststlt (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002591{
aurel321c978562008-11-23 10:54:04 +00002592 CPU_FloatU u1, u2;
2593 u1.l = op1;
2594 u2.l = op2;
2595 return float32_lt(u1.f, u2.f, &env->spe_status) ? 4 : 0;
j_mayer0487d6a2007-03-20 22:11:31 +00002596}
2597
aurel321c978562008-11-23 10:54:04 +00002598static always_inline uint32_t efststgt (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002599{
aurel321c978562008-11-23 10:54:04 +00002600 CPU_FloatU u1, u2;
2601 u1.l = op1;
2602 u2.l = op2;
2603 return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 4;
j_mayer0487d6a2007-03-20 22:11:31 +00002604}
2605
aurel321c978562008-11-23 10:54:04 +00002606static always_inline uint32_t efststeq (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002607{
aurel321c978562008-11-23 10:54:04 +00002608 CPU_FloatU u1, u2;
2609 u1.l = op1;
2610 u2.l = op2;
2611 return float32_eq(u1.f, u2.f, &env->spe_status) ? 4 : 0;
j_mayer0487d6a2007-03-20 22:11:31 +00002612}
2613
aurel321c978562008-11-23 10:54:04 +00002614static always_inline uint32_t efscmplt (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002615{
2616 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00002617 return efststlt(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00002618}
2619
aurel321c978562008-11-23 10:54:04 +00002620static always_inline uint32_t efscmpgt (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002621{
2622 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00002623 return efststgt(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00002624}
2625
aurel321c978562008-11-23 10:54:04 +00002626static always_inline uint32_t efscmpeq (uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002627{
2628 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00002629 return efststeq(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00002630}
2631
aurel321c978562008-11-23 10:54:04 +00002632#define HELPER_SINGLE_SPE_CMP(name) \
2633uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
2634{ \
2635 return e##name(op1, op2) << 2; \
2636}
2637/* efststlt */
2638HELPER_SINGLE_SPE_CMP(fststlt);
2639/* efststgt */
2640HELPER_SINGLE_SPE_CMP(fststgt);
2641/* efststeq */
2642HELPER_SINGLE_SPE_CMP(fststeq);
2643/* efscmplt */
2644HELPER_SINGLE_SPE_CMP(fscmplt);
2645/* efscmpgt */
2646HELPER_SINGLE_SPE_CMP(fscmpgt);
2647/* efscmpeq */
2648HELPER_SINGLE_SPE_CMP(fscmpeq);
2649
2650static always_inline uint32_t evcmp_merge (int t0, int t1)
j_mayer0487d6a2007-03-20 22:11:31 +00002651{
aurel321c978562008-11-23 10:54:04 +00002652 return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
j_mayer0487d6a2007-03-20 22:11:31 +00002653}
2654
aurel321c978562008-11-23 10:54:04 +00002655#define HELPER_VECTOR_SPE_CMP(name) \
2656uint32_t helper_ev##name (uint64_t op1, uint64_t op2) \
2657{ \
2658 return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
2659}
2660/* evfststlt */
2661HELPER_VECTOR_SPE_CMP(fststlt);
2662/* evfststgt */
2663HELPER_VECTOR_SPE_CMP(fststgt);
2664/* evfststeq */
2665HELPER_VECTOR_SPE_CMP(fststeq);
2666/* evfscmplt */
2667HELPER_VECTOR_SPE_CMP(fscmplt);
2668/* evfscmpgt */
2669HELPER_VECTOR_SPE_CMP(fscmpgt);
2670/* evfscmpeq */
2671HELPER_VECTOR_SPE_CMP(fscmpeq);
2672
2673/* Double-precision floating-point conversion */
2674uint64_t helper_efdcfsi (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002675{
aurel321c978562008-11-23 10:54:04 +00002676 CPU_DoubleU u;
2677
2678 u.d = int32_to_float64(val, &env->spe_status);
2679
2680 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00002681}
2682
aurel321c978562008-11-23 10:54:04 +00002683uint64_t helper_efdcfsid (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002684{
aurel320ca9d382008-03-13 19:19:16 +00002685 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002686
aurel320ca9d382008-03-13 19:19:16 +00002687 u.d = int64_to_float64(val, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002688
aurel320ca9d382008-03-13 19:19:16 +00002689 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00002690}
2691
aurel321c978562008-11-23 10:54:04 +00002692uint64_t helper_efdcfui (uint32_t val)
2693{
2694 CPU_DoubleU u;
2695
2696 u.d = uint32_to_float64(val, &env->spe_status);
2697
2698 return u.ll;
2699}
2700
2701uint64_t helper_efdcfuid (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002702{
aurel320ca9d382008-03-13 19:19:16 +00002703 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002704
aurel320ca9d382008-03-13 19:19:16 +00002705 u.d = uint64_to_float64(val, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002706
aurel320ca9d382008-03-13 19:19:16 +00002707 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00002708}
2709
aurel321c978562008-11-23 10:54:04 +00002710uint32_t helper_efdctsi (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002711{
aurel320ca9d382008-03-13 19:19:16 +00002712 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002713
aurel320ca9d382008-03-13 19:19:16 +00002714 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002715 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002716 if (unlikely(float64_is_nan(u.d)))
j_mayer0487d6a2007-03-20 22:11:31 +00002717 return 0;
2718
aurel321c978562008-11-23 10:54:04 +00002719 return float64_to_int32(u.d, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002720}
2721
aurel321c978562008-11-23 10:54:04 +00002722uint32_t helper_efdctui (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002723{
aurel320ca9d382008-03-13 19:19:16 +00002724 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002725
aurel320ca9d382008-03-13 19:19:16 +00002726 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002727 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002728 if (unlikely(float64_is_nan(u.d)))
j_mayer0487d6a2007-03-20 22:11:31 +00002729 return 0;
2730
aurel321c978562008-11-23 10:54:04 +00002731 return float64_to_uint32(u.d, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002732}
2733
aurel321c978562008-11-23 10:54:04 +00002734uint32_t helper_efdctsiz (uint64_t val)
2735{
2736 CPU_DoubleU u;
2737
2738 u.ll = val;
2739 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002740 if (unlikely(float64_is_nan(u.d)))
aurel321c978562008-11-23 10:54:04 +00002741 return 0;
2742
2743 return float64_to_int32_round_to_zero(u.d, &env->spe_status);
2744}
2745
2746uint64_t helper_efdctsidz (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002747{
aurel320ca9d382008-03-13 19:19:16 +00002748 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002749
aurel320ca9d382008-03-13 19:19:16 +00002750 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002751 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002752 if (unlikely(float64_is_nan(u.d)))
j_mayer0487d6a2007-03-20 22:11:31 +00002753 return 0;
2754
aurel320ca9d382008-03-13 19:19:16 +00002755 return float64_to_int64_round_to_zero(u.d, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002756}
2757
aurel321c978562008-11-23 10:54:04 +00002758uint32_t helper_efdctuiz (uint64_t val)
2759{
2760 CPU_DoubleU u;
2761
2762 u.ll = val;
2763 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002764 if (unlikely(float64_is_nan(u.d)))
aurel321c978562008-11-23 10:54:04 +00002765 return 0;
2766
2767 return float64_to_uint32_round_to_zero(u.d, &env->spe_status);
2768}
2769
2770uint64_t helper_efdctuidz (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002771{
aurel320ca9d382008-03-13 19:19:16 +00002772 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002773
aurel320ca9d382008-03-13 19:19:16 +00002774 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002775 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002776 if (unlikely(float64_is_nan(u.d)))
j_mayer0487d6a2007-03-20 22:11:31 +00002777 return 0;
2778
aurel320ca9d382008-03-13 19:19:16 +00002779 return float64_to_uint64_round_to_zero(u.d, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002780}
2781
aurel321c978562008-11-23 10:54:04 +00002782uint64_t helper_efdcfsf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002783{
aurel320ca9d382008-03-13 19:19:16 +00002784 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002785 float64 tmp;
2786
aurel320ca9d382008-03-13 19:19:16 +00002787 u.d = int32_to_float64(val, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002788 tmp = int64_to_float64(1ULL << 32, &env->spe_status);
aurel320ca9d382008-03-13 19:19:16 +00002789 u.d = float64_div(u.d, tmp, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002790
aurel320ca9d382008-03-13 19:19:16 +00002791 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00002792}
2793
aurel321c978562008-11-23 10:54:04 +00002794uint64_t helper_efdcfuf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002795{
aurel320ca9d382008-03-13 19:19:16 +00002796 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002797 float64 tmp;
2798
aurel320ca9d382008-03-13 19:19:16 +00002799 u.d = uint32_to_float64(val, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002800 tmp = int64_to_float64(1ULL << 32, &env->spe_status);
aurel320ca9d382008-03-13 19:19:16 +00002801 u.d = float64_div(u.d, tmp, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002802
aurel320ca9d382008-03-13 19:19:16 +00002803 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00002804}
2805
aurel321c978562008-11-23 10:54:04 +00002806uint32_t helper_efdctsf (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002807{
aurel320ca9d382008-03-13 19:19:16 +00002808 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002809 float64 tmp;
2810
aurel320ca9d382008-03-13 19:19:16 +00002811 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002812 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002813 if (unlikely(float64_is_nan(u.d)))
j_mayer0487d6a2007-03-20 22:11:31 +00002814 return 0;
2815 tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
aurel320ca9d382008-03-13 19:19:16 +00002816 u.d = float64_mul(u.d, tmp, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002817
aurel320ca9d382008-03-13 19:19:16 +00002818 return float64_to_int32(u.d, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002819}
2820
aurel321c978562008-11-23 10:54:04 +00002821uint32_t helper_efdctuf (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002822{
aurel320ca9d382008-03-13 19:19:16 +00002823 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00002824 float64 tmp;
2825
aurel320ca9d382008-03-13 19:19:16 +00002826 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00002827 /* NaN are not treated the same way IEEE 754 does */
aurel32a44d2ce2008-12-13 11:46:27 +00002828 if (unlikely(float64_is_nan(u.d)))
j_mayer0487d6a2007-03-20 22:11:31 +00002829 return 0;
2830 tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
aurel320ca9d382008-03-13 19:19:16 +00002831 u.d = float64_mul(u.d, tmp, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002832
aurel320ca9d382008-03-13 19:19:16 +00002833 return float64_to_uint32(u.d, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002834}
2835
aurel321c978562008-11-23 10:54:04 +00002836uint32_t helper_efscfd (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002837{
aurel320ca9d382008-03-13 19:19:16 +00002838 CPU_DoubleU u1;
2839 CPU_FloatU u2;
j_mayer0487d6a2007-03-20 22:11:31 +00002840
aurel320ca9d382008-03-13 19:19:16 +00002841 u1.ll = val;
2842 u2.f = float64_to_float32(u1.d, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002843
aurel320ca9d382008-03-13 19:19:16 +00002844 return u2.l;
j_mayer0487d6a2007-03-20 22:11:31 +00002845}
2846
aurel321c978562008-11-23 10:54:04 +00002847uint64_t helper_efdcfs (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00002848{
aurel320ca9d382008-03-13 19:19:16 +00002849 CPU_DoubleU u2;
2850 CPU_FloatU u1;
j_mayer0487d6a2007-03-20 22:11:31 +00002851
aurel320ca9d382008-03-13 19:19:16 +00002852 u1.l = val;
2853 u2.d = float32_to_float64(u1.f, &env->spe_status);
j_mayer0487d6a2007-03-20 22:11:31 +00002854
aurel320ca9d382008-03-13 19:19:16 +00002855 return u2.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00002856}
2857
aurel321c978562008-11-23 10:54:04 +00002858/* Double precision fixed-point arithmetic */
2859uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002860{
aurel321c978562008-11-23 10:54:04 +00002861 CPU_DoubleU u1, u2;
2862 u1.ll = op1;
2863 u2.ll = op2;
2864 u1.d = float64_add(u1.d, u2.d, &env->spe_status);
2865 return u1.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00002866}
2867
aurel321c978562008-11-23 10:54:04 +00002868uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002869{
aurel321c978562008-11-23 10:54:04 +00002870 CPU_DoubleU u1, u2;
2871 u1.ll = op1;
2872 u2.ll = op2;
2873 u1.d = float64_sub(u1.d, u2.d, &env->spe_status);
2874 return u1.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00002875}
2876
aurel321c978562008-11-23 10:54:04 +00002877uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
2878{
2879 CPU_DoubleU u1, u2;
2880 u1.ll = op1;
2881 u2.ll = op2;
2882 u1.d = float64_mul(u1.d, u2.d, &env->spe_status);
2883 return u1.ll;
2884}
j_mayer0487d6a2007-03-20 22:11:31 +00002885
aurel321c978562008-11-23 10:54:04 +00002886uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
2887{
2888 CPU_DoubleU u1, u2;
2889 u1.ll = op1;
2890 u2.ll = op2;
2891 u1.d = float64_div(u1.d, u2.d, &env->spe_status);
2892 return u1.ll;
2893}
2894
2895/* Double precision floating point helpers */
2896uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
2897{
2898 CPU_DoubleU u1, u2;
2899 u1.ll = op1;
2900 u2.ll = op2;
2901 return float64_lt(u1.d, u2.d, &env->spe_status) ? 4 : 0;
2902}
2903
2904uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
2905{
2906 CPU_DoubleU u1, u2;
2907 u1.ll = op1;
2908 u2.ll = op2;
2909 return float64_le(u1.d, u2.d, &env->spe_status) ? 0 : 4;
2910}
2911
2912uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
2913{
2914 CPU_DoubleU u1, u2;
2915 u1.ll = op1;
2916 u2.ll = op2;
2917 return float64_eq(u1.d, u2.d, &env->spe_status) ? 4 : 0;
2918}
2919
2920uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002921{
2922 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00002923 return helper_efdtstlt(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00002924}
2925
aurel321c978562008-11-23 10:54:04 +00002926uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002927{
2928 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00002929 return helper_efdtstgt(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00002930}
2931
aurel321c978562008-11-23 10:54:04 +00002932uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00002933{
2934 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00002935 return helper_efdtsteq(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00002936}
2937
bellardfdabc362005-07-04 22:17:05 +00002938/*****************************************************************************/
2939/* Softmmu support */
2940#if !defined (CONFIG_USER_ONLY)
2941
2942#define MMUSUFFIX _mmu
bellardfdabc362005-07-04 22:17:05 +00002943
2944#define SHIFT 0
2945#include "softmmu_template.h"
2946
2947#define SHIFT 1
2948#include "softmmu_template.h"
2949
2950#define SHIFT 2
2951#include "softmmu_template.h"
2952
2953#define SHIFT 3
2954#include "softmmu_template.h"
2955
2956/* try to fill the TLB and return an exception if error. If retaddr is
2957 NULL, it means that the function was called in C code (i.e. not
2958 from generated code or from helper.c) */
2959/* XXX: fix it to restore all registers */
j_mayer6ebbf392007-10-14 07:07:08 +00002960void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
bellardfdabc362005-07-04 22:17:05 +00002961{
2962 TranslationBlock *tb;
2963 CPUState *saved_env;
bellard44f86252007-11-11 12:35:55 +00002964 unsigned long pc;
bellardfdabc362005-07-04 22:17:05 +00002965 int ret;
2966
2967 /* XXX: hack to restore env in all cases, even if not called from
2968 generated code */
2969 saved_env = env;
2970 env = cpu_single_env;
j_mayer6ebbf392007-10-14 07:07:08 +00002971 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
j_mayer76a66252007-03-07 08:32:30 +00002972 if (unlikely(ret != 0)) {
bellardfdabc362005-07-04 22:17:05 +00002973 if (likely(retaddr)) {
2974 /* now we have a real cpu fault */
bellard44f86252007-11-11 12:35:55 +00002975 pc = (unsigned long)retaddr;
bellardfdabc362005-07-04 22:17:05 +00002976 tb = tb_find_pc(pc);
2977 if (likely(tb)) {
2978 /* the PC is inside the translated code. It means that we have
2979 a virtual CPU fault */
2980 cpu_restore_state(tb, env, pc, NULL);
j_mayer76a66252007-03-07 08:32:30 +00002981 }
bellardfdabc362005-07-04 22:17:05 +00002982 }
aurel32e06fcd72008-12-11 22:42:14 +00002983 helper_raise_exception_err(env->exception_index, env->error_code);
bellardfdabc362005-07-04 22:17:05 +00002984 }
2985 env = saved_env;
2986}
bellardfdabc362005-07-04 22:17:05 +00002987
aurel3274d37792008-12-06 21:46:17 +00002988/* Segment registers load and store */
2989target_ulong helper_load_sr (target_ulong sr_num)
2990{
2991 return env->sr[sr_num];
2992}
2993
2994void helper_store_sr (target_ulong sr_num, target_ulong val)
2995{
aurel3245d827d2008-12-07 13:40:29 +00002996 ppc_store_sr(env, sr_num, val);
aurel3274d37792008-12-06 21:46:17 +00002997}
2998
2999/* SLB management */
3000#if defined(TARGET_PPC64)
3001target_ulong helper_load_slb (target_ulong slb_nr)
3002{
3003 return ppc_load_slb(env, slb_nr);
3004}
3005
3006void helper_store_slb (target_ulong slb_nr, target_ulong rs)
3007{
3008 ppc_store_slb(env, slb_nr, rs);
3009}
3010
3011void helper_slbia (void)
3012{
3013 ppc_slb_invalidate_all(env);
3014}
3015
3016void helper_slbie (target_ulong addr)
3017{
3018 ppc_slb_invalidate_one(env, addr);
3019}
3020
3021#endif /* defined(TARGET_PPC64) */
3022
3023/* TLB management */
3024void helper_tlbia (void)
3025{
3026 ppc_tlb_invalidate_all(env);
3027}
3028
3029void helper_tlbie (target_ulong addr)
3030{
3031 ppc_tlb_invalidate_one(env, addr);
3032}
3033
j_mayer76a66252007-03-07 08:32:30 +00003034/* Software driven TLBs management */
3035/* PowerPC 602/603 software TLB load instructions helpers */
aurel3274d37792008-12-06 21:46:17 +00003036static void do_6xx_tlb (target_ulong new_EPN, int is_code)
j_mayer76a66252007-03-07 08:32:30 +00003037{
3038 target_ulong RPN, CMP, EPN;
3039 int way;
j_mayerd9bce9d2007-03-17 14:02:15 +00003040
j_mayer76a66252007-03-07 08:32:30 +00003041 RPN = env->spr[SPR_RPA];
3042 if (is_code) {
3043 CMP = env->spr[SPR_ICMP];
3044 EPN = env->spr[SPR_IMISS];
3045 } else {
3046 CMP = env->spr[SPR_DCMP];
3047 EPN = env->spr[SPR_DMISS];
3048 }
3049 way = (env->spr[SPR_SRR1] >> 17) & 1;
3050#if defined (DEBUG_SOFTWARE_TLB)
3051 if (loglevel != 0) {
aurel320e698052008-12-08 18:11:42 +00003052 fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
j_mayer6b542af2007-11-24 02:03:55 +00003053 " PTE1 " ADDRX " way %d\n",
aurel320e698052008-12-08 18:11:42 +00003054 __func__, new_EPN, EPN, CMP, RPN, way);
j_mayer76a66252007-03-07 08:32:30 +00003055 }
3056#endif
3057 /* Store this TLB */
aurel320f3955e2008-11-30 16:22:56 +00003058 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
j_mayerd9bce9d2007-03-17 14:02:15 +00003059 way, is_code, CMP, RPN);
j_mayer76a66252007-03-07 08:32:30 +00003060}
3061
aurel3274d37792008-12-06 21:46:17 +00003062void helper_6xx_tlbd (target_ulong EPN)
aurel320f3955e2008-11-30 16:22:56 +00003063{
aurel3274d37792008-12-06 21:46:17 +00003064 do_6xx_tlb(EPN, 0);
aurel320f3955e2008-11-30 16:22:56 +00003065}
3066
aurel3274d37792008-12-06 21:46:17 +00003067void helper_6xx_tlbi (target_ulong EPN)
aurel320f3955e2008-11-30 16:22:56 +00003068{
aurel3274d37792008-12-06 21:46:17 +00003069 do_6xx_tlb(EPN, 1);
aurel320f3955e2008-11-30 16:22:56 +00003070}
3071
3072/* PowerPC 74xx software TLB load instructions helpers */
aurel3274d37792008-12-06 21:46:17 +00003073static void do_74xx_tlb (target_ulong new_EPN, int is_code)
j_mayer7dbe11a2007-10-01 05:16:57 +00003074{
3075 target_ulong RPN, CMP, EPN;
3076 int way;
3077
3078 RPN = env->spr[SPR_PTELO];
3079 CMP = env->spr[SPR_PTEHI];
3080 EPN = env->spr[SPR_TLBMISS] & ~0x3;
3081 way = env->spr[SPR_TLBMISS] & 0x3;
3082#if defined (DEBUG_SOFTWARE_TLB)
3083 if (loglevel != 0) {
aurel320e698052008-12-08 18:11:42 +00003084 fprintf(logfile, "%s: EPN " ADDRX " " ADDRX " PTE0 " ADDRX
j_mayer6b542af2007-11-24 02:03:55 +00003085 " PTE1 " ADDRX " way %d\n",
aurel320e698052008-12-08 18:11:42 +00003086 __func__, new_EPN, EPN, CMP, RPN, way);
j_mayer7dbe11a2007-10-01 05:16:57 +00003087 }
3088#endif
3089 /* Store this TLB */
aurel320f3955e2008-11-30 16:22:56 +00003090 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
j_mayer7dbe11a2007-10-01 05:16:57 +00003091 way, is_code, CMP, RPN);
3092}
3093
aurel3274d37792008-12-06 21:46:17 +00003094void helper_74xx_tlbd (target_ulong EPN)
aurel320f3955e2008-11-30 16:22:56 +00003095{
aurel3274d37792008-12-06 21:46:17 +00003096 do_74xx_tlb(EPN, 0);
aurel320f3955e2008-11-30 16:22:56 +00003097}
3098
aurel3274d37792008-12-06 21:46:17 +00003099void helper_74xx_tlbi (target_ulong EPN)
aurel320f3955e2008-11-30 16:22:56 +00003100{
aurel3274d37792008-12-06 21:46:17 +00003101 do_74xx_tlb(EPN, 1);
aurel320f3955e2008-11-30 16:22:56 +00003102}
3103
j_mayera11b8152007-10-28 00:55:05 +00003104static always_inline target_ulong booke_tlb_to_page_size (int size)
j_mayera8dea122007-03-31 11:33:48 +00003105{
3106 return 1024 << (2 * size);
3107}
3108
j_mayera11b8152007-10-28 00:55:05 +00003109static always_inline int booke_page_size_to_tlb (target_ulong page_size)
j_mayera8dea122007-03-31 11:33:48 +00003110{
3111 int size;
3112
3113 switch (page_size) {
3114 case 0x00000400UL:
3115 size = 0x0;
3116 break;
3117 case 0x00001000UL:
3118 size = 0x1;
3119 break;
3120 case 0x00004000UL:
3121 size = 0x2;
3122 break;
3123 case 0x00010000UL:
3124 size = 0x3;
3125 break;
3126 case 0x00040000UL:
3127 size = 0x4;
3128 break;
3129 case 0x00100000UL:
3130 size = 0x5;
3131 break;
3132 case 0x00400000UL:
3133 size = 0x6;
3134 break;
3135 case 0x01000000UL:
3136 size = 0x7;
3137 break;
3138 case 0x04000000UL:
3139 size = 0x8;
3140 break;
3141 case 0x10000000UL:
3142 size = 0x9;
3143 break;
3144 case 0x40000000UL:
3145 size = 0xA;
3146 break;
3147#if defined (TARGET_PPC64)
3148 case 0x000100000000ULL:
3149 size = 0xB;
3150 break;
3151 case 0x000400000000ULL:
3152 size = 0xC;
3153 break;
3154 case 0x001000000000ULL:
3155 size = 0xD;
3156 break;
3157 case 0x004000000000ULL:
3158 size = 0xE;
3159 break;
3160 case 0x010000000000ULL:
3161 size = 0xF;
3162 break;
3163#endif
3164 default:
3165 size = -1;
3166 break;
3167 }
3168
3169 return size;
3170}
3171
j_mayer76a66252007-03-07 08:32:30 +00003172/* Helpers for 4xx TLB management */
aurel3274d37792008-12-06 21:46:17 +00003173target_ulong helper_4xx_tlbre_lo (target_ulong entry)
j_mayer76a66252007-03-07 08:32:30 +00003174{
j_mayera8dea122007-03-31 11:33:48 +00003175 ppcemb_tlb_t *tlb;
aurel3274d37792008-12-06 21:46:17 +00003176 target_ulong ret;
j_mayera8dea122007-03-31 11:33:48 +00003177 int size;
j_mayer76a66252007-03-07 08:32:30 +00003178
aurel3274d37792008-12-06 21:46:17 +00003179 entry &= 0x3F;
3180 tlb = &env->tlb[entry].tlbe;
3181 ret = tlb->EPN;
j_mayera8dea122007-03-31 11:33:48 +00003182 if (tlb->prot & PAGE_VALID)
aurel3274d37792008-12-06 21:46:17 +00003183 ret |= 0x400;
j_mayera8dea122007-03-31 11:33:48 +00003184 size = booke_page_size_to_tlb(tlb->size);
3185 if (size < 0 || size > 0x7)
3186 size = 1;
aurel3274d37792008-12-06 21:46:17 +00003187 ret |= size << 7;
j_mayera8dea122007-03-31 11:33:48 +00003188 env->spr[SPR_40x_PID] = tlb->PID;
aurel3274d37792008-12-06 21:46:17 +00003189 return ret;
j_mayer76a66252007-03-07 08:32:30 +00003190}
3191
aurel3274d37792008-12-06 21:46:17 +00003192target_ulong helper_4xx_tlbre_hi (target_ulong entry)
j_mayer76a66252007-03-07 08:32:30 +00003193{
j_mayera8dea122007-03-31 11:33:48 +00003194 ppcemb_tlb_t *tlb;
aurel3274d37792008-12-06 21:46:17 +00003195 target_ulong ret;
j_mayer76a66252007-03-07 08:32:30 +00003196
aurel3274d37792008-12-06 21:46:17 +00003197 entry &= 0x3F;
3198 tlb = &env->tlb[entry].tlbe;
3199 ret = tlb->RPN;
j_mayera8dea122007-03-31 11:33:48 +00003200 if (tlb->prot & PAGE_EXEC)
aurel3274d37792008-12-06 21:46:17 +00003201 ret |= 0x200;
j_mayera8dea122007-03-31 11:33:48 +00003202 if (tlb->prot & PAGE_WRITE)
aurel3274d37792008-12-06 21:46:17 +00003203 ret |= 0x100;
3204 return ret;
j_mayer76a66252007-03-07 08:32:30 +00003205}
3206
aurel3274d37792008-12-06 21:46:17 +00003207void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
j_mayer76a66252007-03-07 08:32:30 +00003208{
j_mayera8dea122007-03-31 11:33:48 +00003209 ppcemb_tlb_t *tlb;
j_mayer76a66252007-03-07 08:32:30 +00003210 target_ulong page, end;
3211
j_mayerc55e9ae2007-04-16 09:21:46 +00003212#if defined (DEBUG_SOFTWARE_TLB)
j_mayer6b800552007-04-24 07:36:03 +00003213 if (loglevel != 0) {
aurel320e698052008-12-08 18:11:42 +00003214 fprintf(logfile, "%s entry %d val " ADDRX "\n", __func__, (int)entry, val);
j_mayerc55e9ae2007-04-16 09:21:46 +00003215 }
3216#endif
aurel3274d37792008-12-06 21:46:17 +00003217 entry &= 0x3F;
3218 tlb = &env->tlb[entry].tlbe;
j_mayer76a66252007-03-07 08:32:30 +00003219 /* Invalidate previous TLB (if it's valid) */
3220 if (tlb->prot & PAGE_VALID) {
3221 end = tlb->EPN + tlb->size;
j_mayerc55e9ae2007-04-16 09:21:46 +00003222#if defined (DEBUG_SOFTWARE_TLB)
j_mayer6b800552007-04-24 07:36:03 +00003223 if (loglevel != 0) {
j_mayerc55e9ae2007-04-16 09:21:46 +00003224 fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
aurel3274d37792008-12-06 21:46:17 +00003225 " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
j_mayerc55e9ae2007-04-16 09:21:46 +00003226 }
3227#endif
j_mayer76a66252007-03-07 08:32:30 +00003228 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3229 tlb_flush_page(env, page);
3230 }
aurel3274d37792008-12-06 21:46:17 +00003231 tlb->size = booke_tlb_to_page_size((val >> 7) & 0x7);
j_mayerc294fc52007-04-24 06:44:14 +00003232 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
3233 * If this ever occurs, one should use the ppcemb target instead
3234 * of the ppc or ppc64 one
3235 */
aurel3274d37792008-12-06 21:46:17 +00003236 if ((val & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
j_mayer71c8b8f2007-09-19 05:46:03 +00003237 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
3238 "are not supported (%d)\n",
aurel3274d37792008-12-06 21:46:17 +00003239 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
j_mayerc294fc52007-04-24 06:44:14 +00003240 }
aurel3274d37792008-12-06 21:46:17 +00003241 tlb->EPN = val & ~(tlb->size - 1);
3242 if (val & 0x40)
j_mayer76a66252007-03-07 08:32:30 +00003243 tlb->prot |= PAGE_VALID;
3244 else
3245 tlb->prot &= ~PAGE_VALID;
aurel3274d37792008-12-06 21:46:17 +00003246 if (val & 0x20) {
j_mayerc294fc52007-04-24 06:44:14 +00003247 /* XXX: TO BE FIXED */
3248 cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
3249 }
j_mayerc55e9ae2007-04-16 09:21:46 +00003250 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
aurel3274d37792008-12-06 21:46:17 +00003251 tlb->attr = val & 0xFF;
j_mayerc55e9ae2007-04-16 09:21:46 +00003252#if defined (DEBUG_SOFTWARE_TLB)
j_mayerc294fc52007-04-24 06:44:14 +00003253 if (loglevel != 0) {
3254 fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
j_mayerc55e9ae2007-04-16 09:21:46 +00003255 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
aurel320e698052008-12-08 18:11:42 +00003256 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
j_mayerc55e9ae2007-04-16 09:21:46 +00003257 tlb->prot & PAGE_READ ? 'r' : '-',
3258 tlb->prot & PAGE_WRITE ? 'w' : '-',
3259 tlb->prot & PAGE_EXEC ? 'x' : '-',
3260 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3261 }
3262#endif
j_mayer76a66252007-03-07 08:32:30 +00003263 /* Invalidate new TLB (if valid) */
3264 if (tlb->prot & PAGE_VALID) {
3265 end = tlb->EPN + tlb->size;
j_mayerc55e9ae2007-04-16 09:21:46 +00003266#if defined (DEBUG_SOFTWARE_TLB)
j_mayer6b800552007-04-24 07:36:03 +00003267 if (loglevel != 0) {
j_mayerc55e9ae2007-04-16 09:21:46 +00003268 fprintf(logfile, "%s: invalidate TLB %d start " ADDRX
aurel320e698052008-12-08 18:11:42 +00003269 " end " ADDRX "\n", __func__, (int)entry, tlb->EPN, end);
j_mayerc55e9ae2007-04-16 09:21:46 +00003270 }
3271#endif
j_mayer76a66252007-03-07 08:32:30 +00003272 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
3273 tlb_flush_page(env, page);
3274 }
j_mayer76a66252007-03-07 08:32:30 +00003275}
3276
aurel3274d37792008-12-06 21:46:17 +00003277void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
j_mayer76a66252007-03-07 08:32:30 +00003278{
j_mayera8dea122007-03-31 11:33:48 +00003279 ppcemb_tlb_t *tlb;
j_mayer76a66252007-03-07 08:32:30 +00003280
j_mayerc55e9ae2007-04-16 09:21:46 +00003281#if defined (DEBUG_SOFTWARE_TLB)
j_mayer6b800552007-04-24 07:36:03 +00003282 if (loglevel != 0) {
aurel320e698052008-12-08 18:11:42 +00003283 fprintf(logfile, "%s entry %i val " ADDRX "\n", __func__, (int)entry, val);
j_mayerc55e9ae2007-04-16 09:21:46 +00003284 }
3285#endif
aurel3274d37792008-12-06 21:46:17 +00003286 entry &= 0x3F;
3287 tlb = &env->tlb[entry].tlbe;
3288 tlb->RPN = val & 0xFFFFFC00;
j_mayer76a66252007-03-07 08:32:30 +00003289 tlb->prot = PAGE_READ;
aurel3274d37792008-12-06 21:46:17 +00003290 if (val & 0x200)
j_mayer76a66252007-03-07 08:32:30 +00003291 tlb->prot |= PAGE_EXEC;
aurel3274d37792008-12-06 21:46:17 +00003292 if (val & 0x100)
j_mayer76a66252007-03-07 08:32:30 +00003293 tlb->prot |= PAGE_WRITE;
j_mayerc55e9ae2007-04-16 09:21:46 +00003294#if defined (DEBUG_SOFTWARE_TLB)
j_mayer6b800552007-04-24 07:36:03 +00003295 if (loglevel != 0) {
3296 fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
j_mayerc55e9ae2007-04-16 09:21:46 +00003297 " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
aurel3274d37792008-12-06 21:46:17 +00003298 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
j_mayerc55e9ae2007-04-16 09:21:46 +00003299 tlb->prot & PAGE_READ ? 'r' : '-',
3300 tlb->prot & PAGE_WRITE ? 'w' : '-',
3301 tlb->prot & PAGE_EXEC ? 'x' : '-',
3302 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
3303 }
3304#endif
j_mayer76a66252007-03-07 08:32:30 +00003305}
j_mayer5eb79952007-09-19 05:44:04 +00003306
aurel3274d37792008-12-06 21:46:17 +00003307target_ulong helper_4xx_tlbsx (target_ulong address)
3308{
3309 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
3310}
3311
j_mayera4bb6c32007-09-21 05:28:33 +00003312/* PowerPC 440 TLB management */
aurel3274d37792008-12-06 21:46:17 +00003313void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
j_mayer5eb79952007-09-19 05:44:04 +00003314{
3315 ppcemb_tlb_t *tlb;
j_mayera4bb6c32007-09-21 05:28:33 +00003316 target_ulong EPN, RPN, size;
j_mayer5eb79952007-09-19 05:44:04 +00003317 int do_flush_tlbs;
3318
3319#if defined (DEBUG_SOFTWARE_TLB)
3320 if (loglevel != 0) {
aurel320e698052008-12-08 18:11:42 +00003321 fprintf(logfile, "%s word %d entry %d value " ADDRX "\n",
3322 __func__, word, (int)entry, value);
j_mayer5eb79952007-09-19 05:44:04 +00003323 }
3324#endif
3325 do_flush_tlbs = 0;
aurel3274d37792008-12-06 21:46:17 +00003326 entry &= 0x3F;
3327 tlb = &env->tlb[entry].tlbe;
j_mayera4bb6c32007-09-21 05:28:33 +00003328 switch (word) {
3329 default:
3330 /* Just here to please gcc */
3331 case 0:
aurel3274d37792008-12-06 21:46:17 +00003332 EPN = value & 0xFFFFFC00;
j_mayera4bb6c32007-09-21 05:28:33 +00003333 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
j_mayer5eb79952007-09-19 05:44:04 +00003334 do_flush_tlbs = 1;
j_mayera4bb6c32007-09-21 05:28:33 +00003335 tlb->EPN = EPN;
aurel3274d37792008-12-06 21:46:17 +00003336 size = booke_tlb_to_page_size((value >> 4) & 0xF);
j_mayera4bb6c32007-09-21 05:28:33 +00003337 if ((tlb->prot & PAGE_VALID) && tlb->size < size)
3338 do_flush_tlbs = 1;
3339 tlb->size = size;
3340 tlb->attr &= ~0x1;
aurel3274d37792008-12-06 21:46:17 +00003341 tlb->attr |= (value >> 8) & 1;
3342 if (value & 0x200) {
j_mayera4bb6c32007-09-21 05:28:33 +00003343 tlb->prot |= PAGE_VALID;
3344 } else {
3345 if (tlb->prot & PAGE_VALID) {
3346 tlb->prot &= ~PAGE_VALID;
3347 do_flush_tlbs = 1;
3348 }
j_mayer5eb79952007-09-19 05:44:04 +00003349 }
j_mayera4bb6c32007-09-21 05:28:33 +00003350 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
3351 if (do_flush_tlbs)
3352 tlb_flush(env, 1);
3353 break;
3354 case 1:
aurel3274d37792008-12-06 21:46:17 +00003355 RPN = value & 0xFFFFFC0F;
j_mayera4bb6c32007-09-21 05:28:33 +00003356 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
3357 tlb_flush(env, 1);
3358 tlb->RPN = RPN;
3359 break;
3360 case 2:
aurel3274d37792008-12-06 21:46:17 +00003361 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
j_mayera4bb6c32007-09-21 05:28:33 +00003362 tlb->prot = tlb->prot & PAGE_VALID;
aurel3274d37792008-12-06 21:46:17 +00003363 if (value & 0x1)
j_mayera4bb6c32007-09-21 05:28:33 +00003364 tlb->prot |= PAGE_READ << 4;
aurel3274d37792008-12-06 21:46:17 +00003365 if (value & 0x2)
j_mayera4bb6c32007-09-21 05:28:33 +00003366 tlb->prot |= PAGE_WRITE << 4;
aurel3274d37792008-12-06 21:46:17 +00003367 if (value & 0x4)
j_mayera4bb6c32007-09-21 05:28:33 +00003368 tlb->prot |= PAGE_EXEC << 4;
aurel3274d37792008-12-06 21:46:17 +00003369 if (value & 0x8)
j_mayera4bb6c32007-09-21 05:28:33 +00003370 tlb->prot |= PAGE_READ;
aurel3274d37792008-12-06 21:46:17 +00003371 if (value & 0x10)
j_mayera4bb6c32007-09-21 05:28:33 +00003372 tlb->prot |= PAGE_WRITE;
aurel3274d37792008-12-06 21:46:17 +00003373 if (value & 0x20)
j_mayera4bb6c32007-09-21 05:28:33 +00003374 tlb->prot |= PAGE_EXEC;
3375 break;
j_mayer5eb79952007-09-19 05:44:04 +00003376 }
j_mayer5eb79952007-09-19 05:44:04 +00003377}
3378
aurel3274d37792008-12-06 21:46:17 +00003379target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
j_mayer5eb79952007-09-19 05:44:04 +00003380{
3381 ppcemb_tlb_t *tlb;
aurel3274d37792008-12-06 21:46:17 +00003382 target_ulong ret;
j_mayer5eb79952007-09-19 05:44:04 +00003383 int size;
3384
aurel3274d37792008-12-06 21:46:17 +00003385 entry &= 0x3F;
3386 tlb = &env->tlb[entry].tlbe;
j_mayera4bb6c32007-09-21 05:28:33 +00003387 switch (word) {
3388 default:
3389 /* Just here to please gcc */
3390 case 0:
aurel3274d37792008-12-06 21:46:17 +00003391 ret = tlb->EPN;
j_mayera4bb6c32007-09-21 05:28:33 +00003392 size = booke_page_size_to_tlb(tlb->size);
3393 if (size < 0 || size > 0xF)
3394 size = 1;
aurel3274d37792008-12-06 21:46:17 +00003395 ret |= size << 4;
j_mayera4bb6c32007-09-21 05:28:33 +00003396 if (tlb->attr & 0x1)
aurel3274d37792008-12-06 21:46:17 +00003397 ret |= 0x100;
j_mayera4bb6c32007-09-21 05:28:33 +00003398 if (tlb->prot & PAGE_VALID)
aurel3274d37792008-12-06 21:46:17 +00003399 ret |= 0x200;
j_mayera4bb6c32007-09-21 05:28:33 +00003400 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
3401 env->spr[SPR_440_MMUCR] |= tlb->PID;
3402 break;
3403 case 1:
aurel3274d37792008-12-06 21:46:17 +00003404 ret = tlb->RPN;
j_mayera4bb6c32007-09-21 05:28:33 +00003405 break;
3406 case 2:
aurel3274d37792008-12-06 21:46:17 +00003407 ret = tlb->attr & ~0x1;
j_mayera4bb6c32007-09-21 05:28:33 +00003408 if (tlb->prot & (PAGE_READ << 4))
aurel3274d37792008-12-06 21:46:17 +00003409 ret |= 0x1;
j_mayera4bb6c32007-09-21 05:28:33 +00003410 if (tlb->prot & (PAGE_WRITE << 4))
aurel3274d37792008-12-06 21:46:17 +00003411 ret |= 0x2;
j_mayera4bb6c32007-09-21 05:28:33 +00003412 if (tlb->prot & (PAGE_EXEC << 4))
aurel3274d37792008-12-06 21:46:17 +00003413 ret |= 0x4;
j_mayera4bb6c32007-09-21 05:28:33 +00003414 if (tlb->prot & PAGE_READ)
aurel3274d37792008-12-06 21:46:17 +00003415 ret |= 0x8;
j_mayera4bb6c32007-09-21 05:28:33 +00003416 if (tlb->prot & PAGE_WRITE)
aurel3274d37792008-12-06 21:46:17 +00003417 ret |= 0x10;
j_mayera4bb6c32007-09-21 05:28:33 +00003418 if (tlb->prot & PAGE_EXEC)
aurel3274d37792008-12-06 21:46:17 +00003419 ret |= 0x20;
j_mayera4bb6c32007-09-21 05:28:33 +00003420 break;
3421 }
aurel3274d37792008-12-06 21:46:17 +00003422 return ret;
j_mayer5eb79952007-09-19 05:44:04 +00003423}
aurel3274d37792008-12-06 21:46:17 +00003424
3425target_ulong helper_440_tlbsx (target_ulong address)
3426{
3427 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
3428}
3429
j_mayer76a66252007-03-07 08:32:30 +00003430#endif /* !CONFIG_USER_ONLY */