blob: 17e070ae75caa265e994743ccf44404d4de10373 [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
Blue Swirl8167ee82009-07-16 20:47:01 +000017 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
bellard9a64fbe2004-01-04 22:58:38 +000018 */
aurel327b239be2009-01-04 22:09:19 +000019#include <string.h>
bellard9a64fbe2004-01-04 22:58:38 +000020#include "exec.h"
j_mayer603fccc2007-10-28 12:54:53 +000021#include "host-utils.h"
pbrooka7812ae2008-11-17 14:43:54 +000022#include "helper.h"
bellard9a64fbe2004-01-04 22:58:38 +000023
j_mayer0411a972007-10-25 21:35:50 +000024#include "helper_regs.h"
j_mayer0487d6a2007-03-20 22:11:31 +000025
bellardfdabc362005-07-04 22:17:05 +000026//#define DEBUG_OP
27//#define DEBUG_EXCEPTIONS
j_mayer76a66252007-03-07 08:32:30 +000028//#define DEBUG_SOFTWARE_TLB
bellardfdabc362005-07-04 22:17:05 +000029
aliguorid12d51d2009-01-15 21:48:06 +000030#ifdef DEBUG_SOFTWARE_TLB
aliguori93fcfe32009-01-15 22:34:14 +000031# define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
aliguorid12d51d2009-01-15 21:48:06 +000032#else
33# define LOG_SWTLB(...) do { } while (0)
34#endif
35
36
bellard9a64fbe2004-01-04 22:58:38 +000037/*****************************************************************************/
38/* Exceptions processing helpers */
bellard9a64fbe2004-01-04 22:58:38 +000039
aurel3264adab32008-11-22 10:09:17 +000040void helper_raise_exception_err (uint32_t exception, uint32_t error_code)
bellard9a64fbe2004-01-04 22:58:38 +000041{
aurel32e06fcd72008-12-11 22:42:14 +000042#if 0
43 printf("Raise exception %3x code : %d\n", exception, error_code);
44#endif
45 env->exception_index = exception;
46 env->error_code = error_code;
47 cpu_loop_exit();
j_mayer76a66252007-03-07 08:32:30 +000048}
bellard9fddaa02004-05-21 12:59:32 +000049
aurel32e06fcd72008-12-11 22:42:14 +000050void helper_raise_exception (uint32_t exception)
bellard9fddaa02004-05-21 12:59:32 +000051{
aurel32e06fcd72008-12-11 22:42:14 +000052 helper_raise_exception_err(exception, 0);
bellard9a64fbe2004-01-04 22:58:38 +000053}
54
55/*****************************************************************************/
aurel3245d827d2008-12-07 13:40:29 +000056/* SPR accesses */
57void helper_load_dump_spr (uint32_t sprn)
j_mayera4967752007-04-16 07:10:48 +000058{
Blue Swirl90e189e2009-08-16 11:13:18 +000059 qemu_log("Read SPR %d %03x => " TARGET_FMT_lx "\n", sprn, sprn,
60 env->spr[sprn]);
j_mayera4967752007-04-16 07:10:48 +000061}
62
aurel3245d827d2008-12-07 13:40:29 +000063void helper_store_dump_spr (uint32_t sprn)
j_mayera4967752007-04-16 07:10:48 +000064{
Blue Swirl90e189e2009-08-16 11:13:18 +000065 qemu_log("Write SPR %d %03x <= " TARGET_FMT_lx "\n", sprn, sprn,
66 env->spr[sprn]);
j_mayera4967752007-04-16 07:10:48 +000067}
68
aurel3245d827d2008-12-07 13:40:29 +000069target_ulong helper_load_tbl (void)
70{
Alexander Grafe3ea6522009-12-21 12:24:17 +010071 return (target_ulong)cpu_ppc_load_tbl(env);
aurel3245d827d2008-12-07 13:40:29 +000072}
73
74target_ulong helper_load_tbu (void)
75{
76 return cpu_ppc_load_tbu(env);
77}
78
79target_ulong helper_load_atbl (void)
80{
Aurelien Jarnob711de92009-12-21 13:52:08 +010081 return (target_ulong)cpu_ppc_load_atbl(env);
aurel3245d827d2008-12-07 13:40:29 +000082}
83
84target_ulong helper_load_atbu (void)
85{
86 return cpu_ppc_load_atbu(env);
87}
88
89target_ulong helper_load_601_rtcl (void)
90{
91 return cpu_ppc601_load_rtcl(env);
92}
93
94target_ulong helper_load_601_rtcu (void)
95{
96 return cpu_ppc601_load_rtcu(env);
97}
98
99#if !defined(CONFIG_USER_ONLY)
100#if defined (TARGET_PPC64)
101void helper_store_asr (target_ulong val)
102{
103 ppc_store_asr(env, val);
104}
105#endif
106
107void helper_store_sdr1 (target_ulong val)
108{
109 ppc_store_sdr1(env, val);
110}
111
112void helper_store_tbl (target_ulong val)
113{
114 cpu_ppc_store_tbl(env, val);
115}
116
117void helper_store_tbu (target_ulong val)
118{
119 cpu_ppc_store_tbu(env, val);
120}
121
122void helper_store_atbl (target_ulong val)
123{
124 cpu_ppc_store_atbl(env, val);
125}
126
127void helper_store_atbu (target_ulong val)
128{
129 cpu_ppc_store_atbu(env, val);
130}
131
132void helper_store_601_rtcl (target_ulong val)
133{
134 cpu_ppc601_store_rtcl(env, val);
135}
136
137void helper_store_601_rtcu (target_ulong val)
138{
139 cpu_ppc601_store_rtcu(env, val);
140}
141
142target_ulong helper_load_decr (void)
143{
144 return cpu_ppc_load_decr(env);
145}
146
147void helper_store_decr (target_ulong val)
148{
149 cpu_ppc_store_decr(env, val);
150}
151
152void helper_store_hid0_601 (target_ulong val)
153{
154 target_ulong hid0;
155
156 hid0 = env->spr[SPR_HID0];
157 if ((val ^ hid0) & 0x00000008) {
158 /* Change current endianness */
159 env->hflags &= ~(1 << MSR_LE);
160 env->hflags_nmsr &= ~(1 << MSR_LE);
161 env->hflags_nmsr |= (1 << MSR_LE) & (((val >> 3) & 1) << MSR_LE);
162 env->hflags |= env->hflags_nmsr;
Blue Swirl90e189e2009-08-16 11:13:18 +0000163 qemu_log("%s: set endianness to %c => " TARGET_FMT_lx "\n", __func__,
164 val & 0x8 ? 'l' : 'b', env->hflags);
aurel3245d827d2008-12-07 13:40:29 +0000165 }
166 env->spr[SPR_HID0] = (uint32_t)val;
167}
168
169void helper_store_403_pbr (uint32_t num, target_ulong value)
170{
171 if (likely(env->pb[num] != value)) {
172 env->pb[num] = value;
173 /* Should be optimized */
174 tlb_flush(env, 1);
175 }
176}
177
178target_ulong helper_load_40x_pit (void)
179{
180 return load_40x_pit(env);
181}
182
183void helper_store_40x_pit (target_ulong val)
184{
185 store_40x_pit(env, val);
186}
187
188void helper_store_40x_dbcr0 (target_ulong val)
189{
190 store_40x_dbcr0(env, val);
191}
192
193void helper_store_40x_sler (target_ulong val)
194{
195 store_40x_sler(env, val);
196}
197
198void helper_store_booke_tcr (target_ulong val)
199{
200 store_booke_tcr(env, val);
201}
202
203void helper_store_booke_tsr (target_ulong val)
204{
205 store_booke_tsr(env, val);
206}
207
208void helper_store_ibatu (uint32_t nr, target_ulong val)
209{
210 ppc_store_ibatu(env, nr, val);
211}
212
213void helper_store_ibatl (uint32_t nr, target_ulong val)
214{
215 ppc_store_ibatl(env, nr, val);
216}
217
218void helper_store_dbatu (uint32_t nr, target_ulong val)
219{
220 ppc_store_dbatu(env, nr, val);
221}
222
223void helper_store_dbatl (uint32_t nr, target_ulong val)
224{
225 ppc_store_dbatl(env, nr, val);
226}
227
228void helper_store_601_batl (uint32_t nr, target_ulong val)
229{
230 ppc_store_ibatl_601(env, nr, val);
231}
232
233void helper_store_601_batu (uint32_t nr, target_ulong val)
234{
235 ppc_store_ibatu_601(env, nr, val);
236}
237#endif
238
j_mayer76a66252007-03-07 08:32:30 +0000239/*****************************************************************************/
aurel32ff4a62c2008-11-30 16:23:56 +0000240/* Memory load and stores */
241
Blue Swirl636aa202009-08-16 09:06:54 +0000242static inline target_ulong addr_add(target_ulong addr, target_long arg)
aurel32ff4a62c2008-11-30 16:23:56 +0000243{
244#if defined(TARGET_PPC64)
aurel3276db3ba2008-12-08 18:11:21 +0000245 if (!msr_sf)
246 return (uint32_t)(addr + arg);
aurel32ff4a62c2008-11-30 16:23:56 +0000247 else
248#endif
aurel3276db3ba2008-12-08 18:11:21 +0000249 return addr + arg;
aurel32ff4a62c2008-11-30 16:23:56 +0000250}
251
252void helper_lmw (target_ulong addr, uint32_t reg)
253{
aurel3276db3ba2008-12-08 18:11:21 +0000254 for (; reg < 32; reg++) {
aurel32ff4a62c2008-11-30 16:23:56 +0000255 if (msr_le)
aurel3276db3ba2008-12-08 18:11:21 +0000256 env->gpr[reg] = bswap32(ldl(addr));
aurel32ff4a62c2008-11-30 16:23:56 +0000257 else
aurel3276db3ba2008-12-08 18:11:21 +0000258 env->gpr[reg] = ldl(addr);
259 addr = addr_add(addr, 4);
aurel32ff4a62c2008-11-30 16:23:56 +0000260 }
261}
262
263void helper_stmw (target_ulong addr, uint32_t reg)
264{
aurel3276db3ba2008-12-08 18:11:21 +0000265 for (; reg < 32; reg++) {
aurel32ff4a62c2008-11-30 16:23:56 +0000266 if (msr_le)
aurel3276db3ba2008-12-08 18:11:21 +0000267 stl(addr, bswap32((uint32_t)env->gpr[reg]));
aurel32ff4a62c2008-11-30 16:23:56 +0000268 else
aurel3276db3ba2008-12-08 18:11:21 +0000269 stl(addr, (uint32_t)env->gpr[reg]);
270 addr = addr_add(addr, 4);
aurel32ff4a62c2008-11-30 16:23:56 +0000271 }
272}
273
aurel32dfbc7992008-11-30 16:24:21 +0000274void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg)
275{
276 int sh;
aurel3276db3ba2008-12-08 18:11:21 +0000277 for (; nb > 3; nb -= 4) {
278 env->gpr[reg] = ldl(addr);
aurel32dfbc7992008-11-30 16:24:21 +0000279 reg = (reg + 1) % 32;
aurel3276db3ba2008-12-08 18:11:21 +0000280 addr = addr_add(addr, 4);
aurel32dfbc7992008-11-30 16:24:21 +0000281 }
282 if (unlikely(nb > 0)) {
283 env->gpr[reg] = 0;
aurel3276db3ba2008-12-08 18:11:21 +0000284 for (sh = 24; nb > 0; nb--, sh -= 8) {
285 env->gpr[reg] |= ldub(addr) << sh;
286 addr = addr_add(addr, 1);
aurel32dfbc7992008-11-30 16:24:21 +0000287 }
288 }
289}
290/* PPC32 specification says we must generate an exception if
291 * rA is in the range of registers to be loaded.
292 * In an other hand, IBM says this is valid, but rA won't be loaded.
293 * For now, I'll follow the spec...
294 */
295void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
296{
297 if (likely(xer_bc != 0)) {
298 if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
299 (reg < rb && (reg + xer_bc) > rb))) {
aurel32e06fcd72008-12-11 22:42:14 +0000300 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
301 POWERPC_EXCP_INVAL |
302 POWERPC_EXCP_INVAL_LSWX);
aurel32dfbc7992008-11-30 16:24:21 +0000303 } else {
304 helper_lsw(addr, xer_bc, reg);
305 }
306 }
307}
308
309void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
310{
311 int sh;
aurel3276db3ba2008-12-08 18:11:21 +0000312 for (; nb > 3; nb -= 4) {
313 stl(addr, env->gpr[reg]);
aurel32dfbc7992008-11-30 16:24:21 +0000314 reg = (reg + 1) % 32;
aurel3276db3ba2008-12-08 18:11:21 +0000315 addr = addr_add(addr, 4);
aurel32dfbc7992008-11-30 16:24:21 +0000316 }
317 if (unlikely(nb > 0)) {
aurel32a16b45e2008-12-29 09:46:58 +0000318 for (sh = 24; nb > 0; nb--, sh -= 8) {
aurel3276db3ba2008-12-08 18:11:21 +0000319 stb(addr, (env->gpr[reg] >> sh) & 0xFF);
aurel32a16b45e2008-12-29 09:46:58 +0000320 addr = addr_add(addr, 1);
321 }
aurel32dfbc7992008-11-30 16:24:21 +0000322 }
323}
324
aurel32799a8c82008-11-30 16:24:05 +0000325static void do_dcbz(target_ulong addr, int dcache_line_size)
326{
aurel3276db3ba2008-12-08 18:11:21 +0000327 addr &= ~(dcache_line_size - 1);
aurel32799a8c82008-11-30 16:24:05 +0000328 int i;
aurel32799a8c82008-11-30 16:24:05 +0000329 for (i = 0 ; i < dcache_line_size ; i += 4) {
aurel32dcc532c2008-11-30 17:54:21 +0000330 stl(addr + i , 0);
aurel32799a8c82008-11-30 16:24:05 +0000331 }
Nathan Froyd18b21a22009-08-03 08:43:25 -0700332 if (env->reserve_addr == addr)
333 env->reserve_addr = (target_ulong)-1ULL;
aurel32799a8c82008-11-30 16:24:05 +0000334}
335
336void helper_dcbz(target_ulong addr)
337{
338 do_dcbz(addr, env->dcache_line_size);
339}
340
341void helper_dcbz_970(target_ulong addr)
342{
343 if (((env->spr[SPR_970_HID5] >> 7) & 0x3) == 1)
344 do_dcbz(addr, 32);
345 else
346 do_dcbz(addr, env->dcache_line_size);
347}
348
aurel3237d269d2008-11-30 16:24:13 +0000349void helper_icbi(target_ulong addr)
350{
aurel3276db3ba2008-12-08 18:11:21 +0000351 addr &= ~(env->dcache_line_size - 1);
aurel3237d269d2008-11-30 16:24:13 +0000352 /* Invalidate one cache line :
353 * PowerPC specification says this is to be treated like a load
354 * (not a fetch) by the MMU. To be sure it will be so,
355 * do the load "by hand".
356 */
Blue Swirl577f25a2010-10-13 18:38:08 +0000357 ldl(addr);
aurel3237d269d2008-11-30 16:24:13 +0000358 tb_invalidate_page_range(addr, addr + env->icache_line_size);
359}
360
aurel32bdb4b682008-11-30 16:24:30 +0000361// XXX: to be tested
362target_ulong helper_lscbx (target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
363{
364 int i, c, d;
aurel32bdb4b682008-11-30 16:24:30 +0000365 d = 24;
366 for (i = 0; i < xer_bc; i++) {
aurel3276db3ba2008-12-08 18:11:21 +0000367 c = ldub(addr);
368 addr = addr_add(addr, 1);
aurel32bdb4b682008-11-30 16:24:30 +0000369 /* ra (if not 0) and rb are never modified */
370 if (likely(reg != rb && (ra == 0 || reg != ra))) {
371 env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
372 }
373 if (unlikely(c == xer_cmp))
374 break;
375 if (likely(d != 0)) {
376 d -= 8;
377 } else {
378 d = 24;
379 reg++;
380 reg = reg & 0x1F;
381 }
382 }
383 return i;
384}
385
aurel32ff4a62c2008-11-30 16:23:56 +0000386/*****************************************************************************/
bellardfdabc362005-07-04 22:17:05 +0000387/* Fixed point operations helpers */
j_mayerd9bce9d2007-03-17 14:02:15 +0000388#if defined(TARGET_PPC64)
bellardfdabc362005-07-04 22:17:05 +0000389
aurel3274637402008-11-01 00:54:12 +0000390/* multiply high word */
391uint64_t helper_mulhd (uint64_t arg1, uint64_t arg2)
bellardfdabc362005-07-04 22:17:05 +0000392{
aurel3274637402008-11-01 00:54:12 +0000393 uint64_t tl, th;
394
395 muls64(&tl, &th, arg1, arg2);
396 return th;
bellardfdabc362005-07-04 22:17:05 +0000397}
398
aurel3274637402008-11-01 00:54:12 +0000399/* multiply high word unsigned */
400uint64_t helper_mulhdu (uint64_t arg1, uint64_t arg2)
bellardfdabc362005-07-04 22:17:05 +0000401{
aurel3274637402008-11-01 00:54:12 +0000402 uint64_t tl, th;
bellardfdabc362005-07-04 22:17:05 +0000403
aurel3274637402008-11-01 00:54:12 +0000404 mulu64(&tl, &th, arg1, arg2);
405 return th;
bellardfdabc362005-07-04 22:17:05 +0000406}
407
aurel3274637402008-11-01 00:54:12 +0000408uint64_t helper_mulldo (uint64_t arg1, uint64_t arg2)
j_mayerd9bce9d2007-03-17 14:02:15 +0000409{
410 int64_t th;
411 uint64_t tl;
412
aurel3274637402008-11-01 00:54:12 +0000413 muls64(&tl, (uint64_t *)&th, arg1, arg2);
j_mayer88ad9202007-10-25 23:36:08 +0000414 /* If th != 0 && th != -1, then we had an overflow */
j_mayer6f2d8972007-11-12 00:04:48 +0000415 if (likely((uint64_t)(th + 1) <= 1)) {
aurel323d7b4172008-10-21 11:28:46 +0000416 env->xer &= ~(1 << XER_OV);
j_mayerd9bce9d2007-03-17 14:02:15 +0000417 } else {
aurel323d7b4172008-10-21 11:28:46 +0000418 env->xer |= (1 << XER_OV) | (1 << XER_SO);
j_mayerd9bce9d2007-03-17 14:02:15 +0000419 }
aurel3274637402008-11-01 00:54:12 +0000420 return (int64_t)tl;
j_mayerd9bce9d2007-03-17 14:02:15 +0000421}
422#endif
423
aurel3226d67362008-10-21 11:31:27 +0000424target_ulong helper_cntlzw (target_ulong t)
j_mayer603fccc2007-10-28 12:54:53 +0000425{
aurel3226d67362008-10-21 11:31:27 +0000426 return clz32(t);
j_mayer603fccc2007-10-28 12:54:53 +0000427}
428
429#if defined(TARGET_PPC64)
aurel3226d67362008-10-21 11:31:27 +0000430target_ulong helper_cntlzd (target_ulong t)
j_mayer603fccc2007-10-28 12:54:53 +0000431{
aurel3226d67362008-10-21 11:31:27 +0000432 return clz64(t);
j_mayer603fccc2007-10-28 12:54:53 +0000433}
434#endif
435
bellard9a64fbe2004-01-04 22:58:38 +0000436/* shift right arithmetic helper */
aurel3226d67362008-10-21 11:31:27 +0000437target_ulong helper_sraw (target_ulong value, target_ulong shift)
bellard9a64fbe2004-01-04 22:58:38 +0000438{
439 int32_t ret;
440
aurel3226d67362008-10-21 11:31:27 +0000441 if (likely(!(shift & 0x20))) {
442 if (likely((uint32_t)shift != 0)) {
443 shift &= 0x1f;
444 ret = (int32_t)value >> shift;
445 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
aurel323d7b4172008-10-21 11:28:46 +0000446 env->xer &= ~(1 << XER_CA);
bellardfdabc362005-07-04 22:17:05 +0000447 } else {
aurel323d7b4172008-10-21 11:28:46 +0000448 env->xer |= (1 << XER_CA);
bellardfdabc362005-07-04 22:17:05 +0000449 }
450 } else {
aurel3226d67362008-10-21 11:31:27 +0000451 ret = (int32_t)value;
aurel323d7b4172008-10-21 11:28:46 +0000452 env->xer &= ~(1 << XER_CA);
bellardfdabc362005-07-04 22:17:05 +0000453 }
bellard9a64fbe2004-01-04 22:58:38 +0000454 } else {
aurel3226d67362008-10-21 11:31:27 +0000455 ret = (int32_t)value >> 31;
456 if (ret) {
aurel323d7b4172008-10-21 11:28:46 +0000457 env->xer |= (1 << XER_CA);
aurel3226d67362008-10-21 11:31:27 +0000458 } else {
459 env->xer &= ~(1 << XER_CA);
j_mayer76a66252007-03-07 08:32:30 +0000460 }
bellardfdabc362005-07-04 22:17:05 +0000461 }
aurel3226d67362008-10-21 11:31:27 +0000462 return (target_long)ret;
bellard9a64fbe2004-01-04 22:58:38 +0000463}
464
j_mayerd9bce9d2007-03-17 14:02:15 +0000465#if defined(TARGET_PPC64)
aurel3226d67362008-10-21 11:31:27 +0000466target_ulong helper_srad (target_ulong value, target_ulong shift)
j_mayerd9bce9d2007-03-17 14:02:15 +0000467{
468 int64_t ret;
469
aurel3226d67362008-10-21 11:31:27 +0000470 if (likely(!(shift & 0x40))) {
471 if (likely((uint64_t)shift != 0)) {
472 shift &= 0x3f;
473 ret = (int64_t)value >> shift;
474 if (likely(ret >= 0 || (value & ((1 << shift) - 1)) == 0)) {
aurel323d7b4172008-10-21 11:28:46 +0000475 env->xer &= ~(1 << XER_CA);
j_mayerd9bce9d2007-03-17 14:02:15 +0000476 } else {
aurel323d7b4172008-10-21 11:28:46 +0000477 env->xer |= (1 << XER_CA);
j_mayerd9bce9d2007-03-17 14:02:15 +0000478 }
479 } else {
aurel3226d67362008-10-21 11:31:27 +0000480 ret = (int64_t)value;
aurel323d7b4172008-10-21 11:28:46 +0000481 env->xer &= ~(1 << XER_CA);
j_mayerd9bce9d2007-03-17 14:02:15 +0000482 }
483 } else {
aurel3226d67362008-10-21 11:31:27 +0000484 ret = (int64_t)value >> 63;
485 if (ret) {
aurel323d7b4172008-10-21 11:28:46 +0000486 env->xer |= (1 << XER_CA);
aurel3226d67362008-10-21 11:31:27 +0000487 } else {
488 env->xer &= ~(1 << XER_CA);
j_mayerd9bce9d2007-03-17 14:02:15 +0000489 }
490 }
aurel3226d67362008-10-21 11:31:27 +0000491 return ret;
j_mayerd9bce9d2007-03-17 14:02:15 +0000492}
493#endif
494
aurel3226d67362008-10-21 11:31:27 +0000495target_ulong helper_popcntb (target_ulong val)
j_mayerd9bce9d2007-03-17 14:02:15 +0000496{
aurel326176a262008-11-01 00:54:33 +0000497 val = (val & 0x55555555) + ((val >> 1) & 0x55555555);
498 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
499 val = (val & 0x0f0f0f0f) + ((val >> 4) & 0x0f0f0f0f);
500 return val;
j_mayerd9bce9d2007-03-17 14:02:15 +0000501}
502
503#if defined(TARGET_PPC64)
aurel3226d67362008-10-21 11:31:27 +0000504target_ulong helper_popcntb_64 (target_ulong val)
j_mayerd9bce9d2007-03-17 14:02:15 +0000505{
aurel326176a262008-11-01 00:54:33 +0000506 val = (val & 0x5555555555555555ULL) + ((val >> 1) & 0x5555555555555555ULL);
507 val = (val & 0x3333333333333333ULL) + ((val >> 2) & 0x3333333333333333ULL);
508 val = (val & 0x0f0f0f0f0f0f0f0fULL) + ((val >> 4) & 0x0f0f0f0f0f0f0f0fULL);
509 return val;
j_mayerd9bce9d2007-03-17 14:02:15 +0000510}
511#endif
512
bellardfdabc362005-07-04 22:17:05 +0000513/*****************************************************************************/
bellard9a64fbe2004-01-04 22:58:38 +0000514/* Floating point operations helpers */
aurel32a0d7d5a2008-11-23 16:30:50 +0000515uint64_t helper_float32_to_float64(uint32_t arg)
516{
517 CPU_FloatU f;
518 CPU_DoubleU d;
519 f.l = arg;
520 d.d = float32_to_float64(f.f, &env->fp_status);
521 return d.ll;
522}
523
524uint32_t helper_float64_to_float32(uint64_t arg)
525{
526 CPU_FloatU f;
527 CPU_DoubleU d;
528 d.ll = arg;
529 f.f = float64_to_float32(d.d, &env->fp_status);
530 return f.l;
531}
532
Blue Swirl636aa202009-08-16 09:06:54 +0000533static inline int isden(float64 d)
j_mayer7c580442007-10-27 17:54:30 +0000534{
aurel320ca9d382008-03-13 19:19:16 +0000535 CPU_DoubleU u;
j_mayer7c580442007-10-27 17:54:30 +0000536
aurel320ca9d382008-03-13 19:19:16 +0000537 u.d = d;
j_mayer7c580442007-10-27 17:54:30 +0000538
aurel320ca9d382008-03-13 19:19:16 +0000539 return ((u.ll >> 52) & 0x7FF) == 0;
j_mayer7c580442007-10-27 17:54:30 +0000540}
541
aurel32af129062008-11-19 16:10:23 +0000542uint32_t helper_compute_fprf (uint64_t arg, uint32_t set_fprf)
j_mayer7c580442007-10-27 17:54:30 +0000543{
aurel32af129062008-11-19 16:10:23 +0000544 CPU_DoubleU farg;
j_mayer7c580442007-10-27 17:54:30 +0000545 int isneg;
aurel32af129062008-11-19 16:10:23 +0000546 int ret;
547 farg.ll = arg;
aurel32f23c3462008-12-15 17:14:27 +0000548 isneg = float64_is_neg(farg.d);
Aurelien Jarnod788b572011-01-17 19:29:33 +0100549 if (unlikely(float64_is_any_nan(farg.d))) {
aurel32af129062008-11-19 16:10:23 +0000550 if (float64_is_signaling_nan(farg.d)) {
j_mayer7c580442007-10-27 17:54:30 +0000551 /* Signaling NaN: flags are undefined */
aurel32af129062008-11-19 16:10:23 +0000552 ret = 0x00;
j_mayer7c580442007-10-27 17:54:30 +0000553 } else {
554 /* Quiet NaN */
aurel32af129062008-11-19 16:10:23 +0000555 ret = 0x11;
j_mayer7c580442007-10-27 17:54:30 +0000556 }
aurel32f23c3462008-12-15 17:14:27 +0000557 } else if (unlikely(float64_is_infinity(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +0000558 /* +/- infinity */
559 if (isneg)
aurel32af129062008-11-19 16:10:23 +0000560 ret = 0x09;
j_mayer7c580442007-10-27 17:54:30 +0000561 else
aurel32af129062008-11-19 16:10:23 +0000562 ret = 0x05;
j_mayer7c580442007-10-27 17:54:30 +0000563 } else {
aurel32f23c3462008-12-15 17:14:27 +0000564 if (float64_is_zero(farg.d)) {
j_mayer7c580442007-10-27 17:54:30 +0000565 /* +/- zero */
566 if (isneg)
aurel32af129062008-11-19 16:10:23 +0000567 ret = 0x12;
j_mayer7c580442007-10-27 17:54:30 +0000568 else
aurel32af129062008-11-19 16:10:23 +0000569 ret = 0x02;
j_mayer7c580442007-10-27 17:54:30 +0000570 } else {
aurel32af129062008-11-19 16:10:23 +0000571 if (isden(farg.d)) {
j_mayer7c580442007-10-27 17:54:30 +0000572 /* Denormalized numbers */
aurel32af129062008-11-19 16:10:23 +0000573 ret = 0x10;
j_mayer7c580442007-10-27 17:54:30 +0000574 } else {
575 /* Normalized numbers */
aurel32af129062008-11-19 16:10:23 +0000576 ret = 0x00;
j_mayer7c580442007-10-27 17:54:30 +0000577 }
578 if (isneg) {
aurel32af129062008-11-19 16:10:23 +0000579 ret |= 0x08;
j_mayer7c580442007-10-27 17:54:30 +0000580 } else {
aurel32af129062008-11-19 16:10:23 +0000581 ret |= 0x04;
j_mayer7c580442007-10-27 17:54:30 +0000582 }
583 }
584 }
585 if (set_fprf) {
586 /* We update FPSCR_FPRF */
587 env->fpscr &= ~(0x1F << FPSCR_FPRF);
aurel32af129062008-11-19 16:10:23 +0000588 env->fpscr |= ret << FPSCR_FPRF;
j_mayer7c580442007-10-27 17:54:30 +0000589 }
590 /* We just need fpcc to update Rc1 */
aurel32af129062008-11-19 16:10:23 +0000591 return ret & 0xF;
j_mayer7c580442007-10-27 17:54:30 +0000592}
593
594/* Floating-point invalid operations exception */
Blue Swirl636aa202009-08-16 09:06:54 +0000595static inline uint64_t fload_invalid_op_excp(int op)
j_mayer7c580442007-10-27 17:54:30 +0000596{
aurel32af129062008-11-19 16:10:23 +0000597 uint64_t ret = 0;
j_mayer7c580442007-10-27 17:54:30 +0000598 int ve;
599
600 ve = fpscr_ve;
aurel32e0147e42008-12-15 17:13:55 +0000601 switch (op) {
602 case POWERPC_EXCP_FP_VXSNAN:
j_mayer7c580442007-10-27 17:54:30 +0000603 env->fpscr |= 1 << FPSCR_VXSNAN;
aurel32e0147e42008-12-15 17:13:55 +0000604 break;
605 case POWERPC_EXCP_FP_VXSOFT:
j_mayer7c580442007-10-27 17:54:30 +0000606 env->fpscr |= 1 << FPSCR_VXSOFT;
aurel32e0147e42008-12-15 17:13:55 +0000607 break;
j_mayer7c580442007-10-27 17:54:30 +0000608 case POWERPC_EXCP_FP_VXISI:
609 /* Magnitude subtraction of infinities */
610 env->fpscr |= 1 << FPSCR_VXISI;
611 goto update_arith;
612 case POWERPC_EXCP_FP_VXIDI:
613 /* Division of infinity by infinity */
614 env->fpscr |= 1 << FPSCR_VXIDI;
615 goto update_arith;
616 case POWERPC_EXCP_FP_VXZDZ:
617 /* Division of zero by zero */
618 env->fpscr |= 1 << FPSCR_VXZDZ;
619 goto update_arith;
620 case POWERPC_EXCP_FP_VXIMZ:
621 /* Multiplication of zero by infinity */
622 env->fpscr |= 1 << FPSCR_VXIMZ;
623 goto update_arith;
624 case POWERPC_EXCP_FP_VXVC:
625 /* Ordered comparison of NaN */
626 env->fpscr |= 1 << FPSCR_VXVC;
627 env->fpscr &= ~(0xF << FPSCR_FPCC);
628 env->fpscr |= 0x11 << FPSCR_FPCC;
629 /* We must update the target FPR before raising the exception */
630 if (ve != 0) {
631 env->exception_index = POWERPC_EXCP_PROGRAM;
632 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_VXVC;
633 /* Update the floating-point enabled exception summary */
634 env->fpscr |= 1 << FPSCR_FEX;
635 /* Exception is differed */
636 ve = 0;
637 }
638 break;
639 case POWERPC_EXCP_FP_VXSQRT:
640 /* Square root of a negative number */
641 env->fpscr |= 1 << FPSCR_VXSQRT;
642 update_arith:
643 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
644 if (ve == 0) {
645 /* Set the result to quiet NaN */
Aurelien Jarno3eb28bb2011-01-06 15:38:18 +0100646 ret = 0x7FF8000000000000ULL;
j_mayer7c580442007-10-27 17:54:30 +0000647 env->fpscr &= ~(0xF << FPSCR_FPCC);
648 env->fpscr |= 0x11 << FPSCR_FPCC;
649 }
650 break;
651 case POWERPC_EXCP_FP_VXCVI:
652 /* Invalid conversion */
653 env->fpscr |= 1 << FPSCR_VXCVI;
654 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
655 if (ve == 0) {
656 /* Set the result to quiet NaN */
Aurelien Jarno3eb28bb2011-01-06 15:38:18 +0100657 ret = 0x7FF8000000000000ULL;
j_mayer7c580442007-10-27 17:54:30 +0000658 env->fpscr &= ~(0xF << FPSCR_FPCC);
659 env->fpscr |= 0x11 << FPSCR_FPCC;
660 }
661 break;
662 }
663 /* Update the floating-point invalid operation summary */
664 env->fpscr |= 1 << FPSCR_VX;
665 /* Update the floating-point exception summary */
666 env->fpscr |= 1 << FPSCR_FX;
667 if (ve != 0) {
668 /* Update the floating-point enabled exception summary */
669 env->fpscr |= 1 << FPSCR_FEX;
670 if (msr_fe0 != 0 || msr_fe1 != 0)
aurel32e06fcd72008-12-11 22:42:14 +0000671 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_FP | op);
j_mayer7c580442007-10-27 17:54:30 +0000672 }
aurel32af129062008-11-19 16:10:23 +0000673 return ret;
j_mayer7c580442007-10-27 17:54:30 +0000674}
675
Blue Swirl636aa202009-08-16 09:06:54 +0000676static inline void float_zero_divide_excp(void)
j_mayer7c580442007-10-27 17:54:30 +0000677{
j_mayer7c580442007-10-27 17:54:30 +0000678 env->fpscr |= 1 << FPSCR_ZX;
679 env->fpscr &= ~((1 << FPSCR_FR) | (1 << FPSCR_FI));
680 /* Update the floating-point exception summary */
681 env->fpscr |= 1 << FPSCR_FX;
682 if (fpscr_ze != 0) {
683 /* Update the floating-point enabled exception summary */
684 env->fpscr |= 1 << FPSCR_FEX;
685 if (msr_fe0 != 0 || msr_fe1 != 0) {
aurel32e06fcd72008-12-11 22:42:14 +0000686 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
687 POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX);
j_mayer7c580442007-10-27 17:54:30 +0000688 }
j_mayer7c580442007-10-27 17:54:30 +0000689 }
690}
691
Blue Swirl636aa202009-08-16 09:06:54 +0000692static inline void float_overflow_excp(void)
j_mayer7c580442007-10-27 17:54:30 +0000693{
694 env->fpscr |= 1 << FPSCR_OX;
695 /* Update the floating-point exception summary */
696 env->fpscr |= 1 << FPSCR_FX;
697 if (fpscr_oe != 0) {
698 /* XXX: should adjust the result */
699 /* Update the floating-point enabled exception summary */
700 env->fpscr |= 1 << FPSCR_FEX;
701 /* We must update the target FPR before raising the exception */
702 env->exception_index = POWERPC_EXCP_PROGRAM;
703 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
704 } else {
705 env->fpscr |= 1 << FPSCR_XX;
706 env->fpscr |= 1 << FPSCR_FI;
707 }
708}
709
Blue Swirl636aa202009-08-16 09:06:54 +0000710static inline void float_underflow_excp(void)
j_mayer7c580442007-10-27 17:54:30 +0000711{
712 env->fpscr |= 1 << FPSCR_UX;
713 /* Update the floating-point exception summary */
714 env->fpscr |= 1 << FPSCR_FX;
715 if (fpscr_ue != 0) {
716 /* XXX: should adjust the result */
717 /* Update the floating-point enabled exception summary */
718 env->fpscr |= 1 << FPSCR_FEX;
719 /* We must update the target FPR before raising the exception */
720 env->exception_index = POWERPC_EXCP_PROGRAM;
721 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
722 }
723}
724
Blue Swirl636aa202009-08-16 09:06:54 +0000725static inline void float_inexact_excp(void)
j_mayer7c580442007-10-27 17:54:30 +0000726{
727 env->fpscr |= 1 << FPSCR_XX;
728 /* Update the floating-point exception summary */
729 env->fpscr |= 1 << FPSCR_FX;
730 if (fpscr_xe != 0) {
731 /* Update the floating-point enabled exception summary */
732 env->fpscr |= 1 << FPSCR_FEX;
733 /* We must update the target FPR before raising the exception */
734 env->exception_index = POWERPC_EXCP_PROGRAM;
735 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
736 }
737}
738
Blue Swirl636aa202009-08-16 09:06:54 +0000739static inline void fpscr_set_rounding_mode(void)
j_mayer7c580442007-10-27 17:54:30 +0000740{
741 int rnd_type;
742
743 /* Set rounding mode */
744 switch (fpscr_rn) {
745 case 0:
746 /* Best approximation (round to nearest) */
747 rnd_type = float_round_nearest_even;
748 break;
749 case 1:
750 /* Smaller magnitude (round toward zero) */
751 rnd_type = float_round_to_zero;
752 break;
753 case 2:
754 /* Round toward +infinite */
755 rnd_type = float_round_up;
756 break;
757 default:
758 case 3:
759 /* Round toward -infinite */
760 rnd_type = float_round_down;
761 break;
762 }
763 set_float_rounding_mode(rnd_type, &env->fp_status);
764}
765
aurel326e35d522008-12-14 18:40:58 +0000766void helper_fpscr_clrbit (uint32_t bit)
767{
768 int prev;
769
770 prev = (env->fpscr >> bit) & 1;
771 env->fpscr &= ~(1 << bit);
772 if (prev == 1) {
773 switch (bit) {
774 case FPSCR_RN1:
775 case FPSCR_RN:
776 fpscr_set_rounding_mode();
777 break;
778 default:
779 break;
780 }
781 }
782}
783
aurel32af129062008-11-19 16:10:23 +0000784void helper_fpscr_setbit (uint32_t bit)
j_mayer7c580442007-10-27 17:54:30 +0000785{
786 int prev;
787
788 prev = (env->fpscr >> bit) & 1;
789 env->fpscr |= 1 << bit;
790 if (prev == 0) {
791 switch (bit) {
792 case FPSCR_VX:
793 env->fpscr |= 1 << FPSCR_FX;
794 if (fpscr_ve)
795 goto raise_ve;
796 case FPSCR_OX:
797 env->fpscr |= 1 << FPSCR_FX;
798 if (fpscr_oe)
799 goto raise_oe;
800 break;
801 case FPSCR_UX:
802 env->fpscr |= 1 << FPSCR_FX;
803 if (fpscr_ue)
804 goto raise_ue;
805 break;
806 case FPSCR_ZX:
807 env->fpscr |= 1 << FPSCR_FX;
808 if (fpscr_ze)
809 goto raise_ze;
810 break;
811 case FPSCR_XX:
812 env->fpscr |= 1 << FPSCR_FX;
813 if (fpscr_xe)
814 goto raise_xe;
815 break;
816 case FPSCR_VXSNAN:
817 case FPSCR_VXISI:
818 case FPSCR_VXIDI:
819 case FPSCR_VXZDZ:
820 case FPSCR_VXIMZ:
821 case FPSCR_VXVC:
822 case FPSCR_VXSOFT:
823 case FPSCR_VXSQRT:
824 case FPSCR_VXCVI:
825 env->fpscr |= 1 << FPSCR_VX;
826 env->fpscr |= 1 << FPSCR_FX;
827 if (fpscr_ve != 0)
828 goto raise_ve;
829 break;
830 case FPSCR_VE:
831 if (fpscr_vx != 0) {
832 raise_ve:
833 env->error_code = POWERPC_EXCP_FP;
834 if (fpscr_vxsnan)
835 env->error_code |= POWERPC_EXCP_FP_VXSNAN;
836 if (fpscr_vxisi)
837 env->error_code |= POWERPC_EXCP_FP_VXISI;
838 if (fpscr_vxidi)
839 env->error_code |= POWERPC_EXCP_FP_VXIDI;
840 if (fpscr_vxzdz)
841 env->error_code |= POWERPC_EXCP_FP_VXZDZ;
842 if (fpscr_vximz)
843 env->error_code |= POWERPC_EXCP_FP_VXIMZ;
844 if (fpscr_vxvc)
845 env->error_code |= POWERPC_EXCP_FP_VXVC;
846 if (fpscr_vxsoft)
847 env->error_code |= POWERPC_EXCP_FP_VXSOFT;
848 if (fpscr_vxsqrt)
849 env->error_code |= POWERPC_EXCP_FP_VXSQRT;
850 if (fpscr_vxcvi)
851 env->error_code |= POWERPC_EXCP_FP_VXCVI;
852 goto raise_excp;
853 }
854 break;
855 case FPSCR_OE:
856 if (fpscr_ox != 0) {
857 raise_oe:
858 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_OX;
859 goto raise_excp;
860 }
861 break;
862 case FPSCR_UE:
863 if (fpscr_ux != 0) {
864 raise_ue:
865 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_UX;
866 goto raise_excp;
867 }
868 break;
869 case FPSCR_ZE:
870 if (fpscr_zx != 0) {
871 raise_ze:
872 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_ZX;
873 goto raise_excp;
874 }
875 break;
876 case FPSCR_XE:
877 if (fpscr_xx != 0) {
878 raise_xe:
879 env->error_code = POWERPC_EXCP_FP | POWERPC_EXCP_FP_XX;
880 goto raise_excp;
881 }
882 break;
883 case FPSCR_RN1:
884 case FPSCR_RN:
885 fpscr_set_rounding_mode();
886 break;
887 default:
888 break;
889 raise_excp:
890 /* Update the floating-point enabled exception summary */
891 env->fpscr |= 1 << FPSCR_FEX;
892 /* We have to update Rc1 before raising the exception */
893 env->exception_index = POWERPC_EXCP_PROGRAM;
894 break;
895 }
896 }
897}
898
aurel32af129062008-11-19 16:10:23 +0000899void helper_store_fpscr (uint64_t arg, uint32_t mask)
j_mayer7c580442007-10-27 17:54:30 +0000900{
901 /*
902 * We use only the 32 LSB of the incoming fpr
903 */
j_mayer7c580442007-10-27 17:54:30 +0000904 uint32_t prev, new;
905 int i;
906
j_mayer7c580442007-10-27 17:54:30 +0000907 prev = env->fpscr;
aurel32af129062008-11-19 16:10:23 +0000908 new = (uint32_t)arg;
aurel3227ee5df2008-12-15 00:30:28 +0000909 new &= ~0x60000000;
910 new |= prev & 0x60000000;
911 for (i = 0; i < 8; i++) {
j_mayer7c580442007-10-27 17:54:30 +0000912 if (mask & (1 << i)) {
913 env->fpscr &= ~(0xF << (4 * i));
914 env->fpscr |= new & (0xF << (4 * i));
915 }
916 }
917 /* Update VX and FEX */
918 if (fpscr_ix != 0)
919 env->fpscr |= 1 << FPSCR_VX;
aurel3255670252008-03-10 00:09:28 +0000920 else
921 env->fpscr &= ~(1 << FPSCR_VX);
j_mayer7c580442007-10-27 17:54:30 +0000922 if ((fpscr_ex & fpscr_eex) != 0) {
923 env->fpscr |= 1 << FPSCR_FEX;
924 env->exception_index = POWERPC_EXCP_PROGRAM;
925 /* XXX: we should compute it properly */
926 env->error_code = POWERPC_EXCP_FP;
927 }
aurel3255670252008-03-10 00:09:28 +0000928 else
929 env->fpscr &= ~(1 << FPSCR_FEX);
j_mayer7c580442007-10-27 17:54:30 +0000930 fpscr_set_rounding_mode();
931}
j_mayer7c580442007-10-27 17:54:30 +0000932
aurel32af129062008-11-19 16:10:23 +0000933void helper_float_check_status (void)
j_mayer7c580442007-10-27 17:54:30 +0000934{
aurel32af129062008-11-19 16:10:23 +0000935#ifdef CONFIG_SOFTFLOAT
j_mayer7c580442007-10-27 17:54:30 +0000936 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
937 (env->error_code & POWERPC_EXCP_FP)) {
938 /* Differred floating-point exception after target FPR update */
939 if (msr_fe0 != 0 || msr_fe1 != 0)
aurel32e06fcd72008-12-11 22:42:14 +0000940 helper_raise_exception_err(env->exception_index, env->error_code);
aurel32be94c952008-12-13 12:13:33 +0000941 } else {
942 int status = get_float_exception_flags(&env->fp_status);
aurel32e33e94f2008-12-18 22:44:21 +0000943 if (status & float_flag_divbyzero) {
944 float_zero_divide_excp();
945 } else if (status & float_flag_overflow) {
aurel32be94c952008-12-13 12:13:33 +0000946 float_overflow_excp();
947 } else if (status & float_flag_underflow) {
948 float_underflow_excp();
949 } else if (status & float_flag_inexact) {
950 float_inexact_excp();
951 }
j_mayer7c580442007-10-27 17:54:30 +0000952 }
aurel32af129062008-11-19 16:10:23 +0000953#else
954 if (env->exception_index == POWERPC_EXCP_PROGRAM &&
955 (env->error_code & POWERPC_EXCP_FP)) {
956 /* Differred floating-point exception after target FPR update */
957 if (msr_fe0 != 0 || msr_fe1 != 0)
aurel32e06fcd72008-12-11 22:42:14 +0000958 helper_raise_exception_err(env->exception_index, env->error_code);
aurel32af129062008-11-19 16:10:23 +0000959 }
aurel32af129062008-11-19 16:10:23 +0000960#endif
961}
962
963#ifdef CONFIG_SOFTFLOAT
964void helper_reset_fpstatus (void)
965{
aurel32be94c952008-12-13 12:13:33 +0000966 set_float_exception_flags(0, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +0000967}
968#endif
969
aurel32af129062008-11-19 16:10:23 +0000970/* fadd - fadd. */
971uint64_t helper_fadd (uint64_t arg1, uint64_t arg2)
972{
973 CPU_DoubleU farg1, farg2;
974
975 farg1.ll = arg1;
976 farg2.ll = arg2;
Aurelien Jarnodd94ad92011-01-06 15:38:18 +0100977
Aurelien Jarno96912e32011-01-17 19:29:33 +0100978 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
979 float64_is_neg(farg1.d) != float64_is_neg(farg2.d))) {
j_mayer7c580442007-10-27 17:54:30 +0000980 /* Magnitude subtraction of infinities */
aurel32cf1cf212008-12-13 11:46:36 +0000981 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
aurel3217218d12008-12-15 17:14:35 +0000982 } else {
Aurelien Jarno96912e32011-01-17 19:29:33 +0100983 if (unlikely(float64_is_signaling_nan(farg1.d) ||
984 float64_is_signaling_nan(farg2.d))) {
985 /* sNaN addition */
986 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
987 }
aurel3217218d12008-12-15 17:14:35 +0000988 farg1.d = float64_add(farg1.d, farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +0000989 }
Aurelien Jarnodd94ad92011-01-06 15:38:18 +0100990
aurel32af129062008-11-19 16:10:23 +0000991 return farg1.ll;
j_mayer7c580442007-10-27 17:54:30 +0000992}
993
aurel32af129062008-11-19 16:10:23 +0000994/* fsub - fsub. */
995uint64_t helper_fsub (uint64_t arg1, uint64_t arg2)
j_mayer7c580442007-10-27 17:54:30 +0000996{
aurel32af129062008-11-19 16:10:23 +0000997 CPU_DoubleU farg1, farg2;
998
999 farg1.ll = arg1;
1000 farg2.ll = arg2;
Aurelien Jarnodd94ad92011-01-06 15:38:18 +01001001
Aurelien Jarno96912e32011-01-17 19:29:33 +01001002 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d) &&
1003 float64_is_neg(farg1.d) == float64_is_neg(farg2.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001004 /* Magnitude subtraction of infinities */
aurel32af129062008-11-19 16:10:23 +00001005 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
aurel3217218d12008-12-15 17:14:35 +00001006 } else {
Aurelien Jarno96912e32011-01-17 19:29:33 +01001007 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1008 float64_is_signaling_nan(farg2.d))) {
1009 /* sNaN subtraction */
1010 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1011 }
aurel3217218d12008-12-15 17:14:35 +00001012 farg1.d = float64_sub(farg1.d, farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001013 }
Aurelien Jarnodd94ad92011-01-06 15:38:18 +01001014
aurel32af129062008-11-19 16:10:23 +00001015 return farg1.ll;
1016}
j_mayer7c580442007-10-27 17:54:30 +00001017
aurel32af129062008-11-19 16:10:23 +00001018/* fmul - fmul. */
1019uint64_t helper_fmul (uint64_t arg1, uint64_t arg2)
j_mayer7c580442007-10-27 17:54:30 +00001020{
aurel32af129062008-11-19 16:10:23 +00001021 CPU_DoubleU farg1, farg2;
1022
1023 farg1.ll = arg1;
1024 farg2.ll = arg2;
Aurelien Jarnodd94ad92011-01-06 15:38:18 +01001025
Aurelien Jarno96912e32011-01-17 19:29:33 +01001026 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1027 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
j_mayer7c580442007-10-27 17:54:30 +00001028 /* Multiplication of zero by infinity */
aurel32af129062008-11-19 16:10:23 +00001029 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
j_mayer7c580442007-10-27 17:54:30 +00001030 } else {
Aurelien Jarno96912e32011-01-17 19:29:33 +01001031 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1032 float64_is_signaling_nan(farg2.d))) {
1033 /* sNaN multiplication */
1034 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1035 }
aurel32af129062008-11-19 16:10:23 +00001036 farg1.d = float64_mul(farg1.d, farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001037 }
Aurelien Jarnodd94ad92011-01-06 15:38:18 +01001038
aurel32af129062008-11-19 16:10:23 +00001039 return farg1.ll;
1040}
j_mayer7c580442007-10-27 17:54:30 +00001041
aurel32af129062008-11-19 16:10:23 +00001042/* fdiv - fdiv. */
1043uint64_t helper_fdiv (uint64_t arg1, uint64_t arg2)
j_mayer7c580442007-10-27 17:54:30 +00001044{
aurel32af129062008-11-19 16:10:23 +00001045 CPU_DoubleU farg1, farg2;
1046
1047 farg1.ll = arg1;
1048 farg2.ll = arg2;
Aurelien Jarnodd94ad92011-01-06 15:38:18 +01001049
Aurelien Jarno96912e32011-01-17 19:29:33 +01001050 if (unlikely(float64_is_infinity(farg1.d) && float64_is_infinity(farg2.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001051 /* Division of infinity by infinity */
aurel32af129062008-11-19 16:10:23 +00001052 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIDI);
aurel32e33e94f2008-12-18 22:44:21 +00001053 } else if (unlikely(float64_is_zero(farg1.d) && float64_is_zero(farg2.d))) {
1054 /* Division of zero by zero */
1055 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXZDZ);
j_mayer7c580442007-10-27 17:54:30 +00001056 } else {
Aurelien Jarno96912e32011-01-17 19:29:33 +01001057 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1058 float64_is_signaling_nan(farg2.d))) {
1059 /* sNaN division */
1060 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1061 }
aurel32af129062008-11-19 16:10:23 +00001062 farg1.d = float64_div(farg1.d, farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001063 }
Aurelien Jarnodd94ad92011-01-06 15:38:18 +01001064
aurel32af129062008-11-19 16:10:23 +00001065 return farg1.ll;
j_mayer7c580442007-10-27 17:54:30 +00001066}
j_mayer7c580442007-10-27 17:54:30 +00001067
aurel32af129062008-11-19 16:10:23 +00001068/* fabs */
1069uint64_t helper_fabs (uint64_t arg)
bellard9a64fbe2004-01-04 22:58:38 +00001070{
aurel32af129062008-11-19 16:10:23 +00001071 CPU_DoubleU farg;
bellard9a64fbe2004-01-04 22:58:38 +00001072
aurel32af129062008-11-19 16:10:23 +00001073 farg.ll = arg;
1074 farg.d = float64_abs(farg.d);
1075 return farg.ll;
1076}
1077
1078/* fnabs */
1079uint64_t helper_fnabs (uint64_t arg)
1080{
1081 CPU_DoubleU farg;
1082
1083 farg.ll = arg;
1084 farg.d = float64_abs(farg.d);
1085 farg.d = float64_chs(farg.d);
1086 return farg.ll;
1087}
1088
1089/* fneg */
1090uint64_t helper_fneg (uint64_t arg)
1091{
1092 CPU_DoubleU farg;
1093
1094 farg.ll = arg;
1095 farg.d = float64_chs(farg.d);
1096 return farg.ll;
1097}
1098
1099/* fctiw - fctiw. */
1100uint64_t helper_fctiw (uint64_t arg)
1101{
1102 CPU_DoubleU farg;
1103 farg.ll = arg;
1104
1105 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001106 /* sNaN conversion */
aurel32af129062008-11-19 16:10:23 +00001107 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
Peter Maydell18569872010-12-17 15:56:06 +00001108 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001109 /* qNan / infinity conversion */
aurel32af129062008-11-19 16:10:23 +00001110 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
j_mayer7c580442007-10-27 17:54:30 +00001111 } else {
aurel32af129062008-11-19 16:10:23 +00001112 farg.ll = float64_to_int32(farg.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001113 /* XXX: higher bits are not supposed to be significant.
1114 * to make tests easier, return the same as a real PowerPC 750
1115 */
aurel32af129062008-11-19 16:10:23 +00001116 farg.ll |= 0xFFF80000ULL << 32;
j_mayer7c580442007-10-27 17:54:30 +00001117 }
aurel32af129062008-11-19 16:10:23 +00001118 return farg.ll;
bellard9a64fbe2004-01-04 22:58:38 +00001119}
1120
aurel32af129062008-11-19 16:10:23 +00001121/* fctiwz - fctiwz. */
1122uint64_t helper_fctiwz (uint64_t arg)
bellard9a64fbe2004-01-04 22:58:38 +00001123{
aurel32af129062008-11-19 16:10:23 +00001124 CPU_DoubleU farg;
1125 farg.ll = arg;
bellard9a64fbe2004-01-04 22:58:38 +00001126
aurel32af129062008-11-19 16:10:23 +00001127 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001128 /* sNaN conversion */
aurel32af129062008-11-19 16:10:23 +00001129 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
Peter Maydell18569872010-12-17 15:56:06 +00001130 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001131 /* qNan / infinity conversion */
aurel32af129062008-11-19 16:10:23 +00001132 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
j_mayer7c580442007-10-27 17:54:30 +00001133 } else {
aurel32af129062008-11-19 16:10:23 +00001134 farg.ll = float64_to_int32_round_to_zero(farg.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001135 /* XXX: higher bits are not supposed to be significant.
1136 * to make tests easier, return the same as a real PowerPC 750
1137 */
aurel32af129062008-11-19 16:10:23 +00001138 farg.ll |= 0xFFF80000ULL << 32;
j_mayer7c580442007-10-27 17:54:30 +00001139 }
aurel32af129062008-11-19 16:10:23 +00001140 return farg.ll;
bellard9a64fbe2004-01-04 22:58:38 +00001141}
1142
j_mayer426613d2007-03-23 09:45:27 +00001143#if defined(TARGET_PPC64)
aurel32af129062008-11-19 16:10:23 +00001144/* fcfid - fcfid. */
1145uint64_t helper_fcfid (uint64_t arg)
j_mayer426613d2007-03-23 09:45:27 +00001146{
aurel32af129062008-11-19 16:10:23 +00001147 CPU_DoubleU farg;
1148 farg.d = int64_to_float64(arg, &env->fp_status);
1149 return farg.ll;
j_mayer426613d2007-03-23 09:45:27 +00001150}
1151
aurel32af129062008-11-19 16:10:23 +00001152/* fctid - fctid. */
1153uint64_t helper_fctid (uint64_t arg)
j_mayer426613d2007-03-23 09:45:27 +00001154{
aurel32af129062008-11-19 16:10:23 +00001155 CPU_DoubleU farg;
1156 farg.ll = arg;
j_mayer426613d2007-03-23 09:45:27 +00001157
aurel32af129062008-11-19 16:10:23 +00001158 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001159 /* sNaN conversion */
aurel32af129062008-11-19 16:10:23 +00001160 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
Peter Maydell18569872010-12-17 15:56:06 +00001161 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001162 /* qNan / infinity conversion */
aurel32af129062008-11-19 16:10:23 +00001163 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
j_mayer7c580442007-10-27 17:54:30 +00001164 } else {
aurel32af129062008-11-19 16:10:23 +00001165 farg.ll = float64_to_int64(farg.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001166 }
aurel32af129062008-11-19 16:10:23 +00001167 return farg.ll;
j_mayer426613d2007-03-23 09:45:27 +00001168}
1169
aurel32af129062008-11-19 16:10:23 +00001170/* fctidz - fctidz. */
1171uint64_t helper_fctidz (uint64_t arg)
j_mayer426613d2007-03-23 09:45:27 +00001172{
aurel32af129062008-11-19 16:10:23 +00001173 CPU_DoubleU farg;
1174 farg.ll = arg;
j_mayer426613d2007-03-23 09:45:27 +00001175
aurel32af129062008-11-19 16:10:23 +00001176 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001177 /* sNaN conversion */
aurel32af129062008-11-19 16:10:23 +00001178 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
Peter Maydell18569872010-12-17 15:56:06 +00001179 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001180 /* qNan / infinity conversion */
aurel32af129062008-11-19 16:10:23 +00001181 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
j_mayer7c580442007-10-27 17:54:30 +00001182 } else {
aurel32af129062008-11-19 16:10:23 +00001183 farg.ll = float64_to_int64_round_to_zero(farg.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001184 }
aurel32af129062008-11-19 16:10:23 +00001185 return farg.ll;
j_mayer426613d2007-03-23 09:45:27 +00001186}
1187
1188#endif
1189
Blue Swirl636aa202009-08-16 09:06:54 +00001190static inline uint64_t do_fri(uint64_t arg, int rounding_mode)
j_mayerd7e4b872007-09-30 01:11:48 +00001191{
aurel32af129062008-11-19 16:10:23 +00001192 CPU_DoubleU farg;
1193 farg.ll = arg;
1194
1195 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001196 /* sNaN round */
aurel32af129062008-11-19 16:10:23 +00001197 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN | POWERPC_EXCP_FP_VXCVI);
Peter Maydell18569872010-12-17 15:56:06 +00001198 } else if (unlikely(float64_is_quiet_nan(farg.d) || float64_is_infinity(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001199 /* qNan / infinity round */
aurel32af129062008-11-19 16:10:23 +00001200 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXCVI);
j_mayer7c580442007-10-27 17:54:30 +00001201 } else {
1202 set_float_rounding_mode(rounding_mode, &env->fp_status);
aurel32af129062008-11-19 16:10:23 +00001203 farg.ll = float64_round_to_int(farg.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001204 /* Restore rounding mode from FPSCR */
1205 fpscr_set_rounding_mode();
1206 }
aurel32af129062008-11-19 16:10:23 +00001207 return farg.ll;
j_mayerd7e4b872007-09-30 01:11:48 +00001208}
1209
aurel32af129062008-11-19 16:10:23 +00001210uint64_t helper_frin (uint64_t arg)
j_mayerd7e4b872007-09-30 01:11:48 +00001211{
aurel32af129062008-11-19 16:10:23 +00001212 return do_fri(arg, float_round_nearest_even);
j_mayerd7e4b872007-09-30 01:11:48 +00001213}
1214
aurel32af129062008-11-19 16:10:23 +00001215uint64_t helper_friz (uint64_t arg)
j_mayerd7e4b872007-09-30 01:11:48 +00001216{
aurel32af129062008-11-19 16:10:23 +00001217 return do_fri(arg, float_round_to_zero);
j_mayerd7e4b872007-09-30 01:11:48 +00001218}
1219
aurel32af129062008-11-19 16:10:23 +00001220uint64_t helper_frip (uint64_t arg)
j_mayerd7e4b872007-09-30 01:11:48 +00001221{
aurel32af129062008-11-19 16:10:23 +00001222 return do_fri(arg, float_round_up);
j_mayerd7e4b872007-09-30 01:11:48 +00001223}
1224
aurel32af129062008-11-19 16:10:23 +00001225uint64_t helper_frim (uint64_t arg)
j_mayerd7e4b872007-09-30 01:11:48 +00001226{
aurel32af129062008-11-19 16:10:23 +00001227 return do_fri(arg, float_round_down);
j_mayerd7e4b872007-09-30 01:11:48 +00001228}
1229
aurel32af129062008-11-19 16:10:23 +00001230/* fmadd - fmadd. */
1231uint64_t helper_fmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
1232{
1233 CPU_DoubleU farg1, farg2, farg3;
1234
1235 farg1.ll = arg1;
1236 farg2.ll = arg2;
1237 farg3.ll = arg3;
Aurelien Jarnodd94ad92011-01-06 15:38:18 +01001238
Aurelien Jarno96912e32011-01-17 19:29:33 +01001239 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1240 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
aurel32da1e7ac2008-12-15 17:14:43 +00001241 /* Multiplication of zero by infinity */
1242 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
j_mayer7c580442007-10-27 17:54:30 +00001243 } else {
Aurelien Jarno96912e32011-01-17 19:29:33 +01001244 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1245 float64_is_signaling_nan(farg2.d) ||
1246 float64_is_signaling_nan(farg3.d))) {
1247 /* sNaN operation */
1248 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1249 }
j_mayere864cab2007-03-22 22:17:08 +00001250#ifdef FLOAT128
j_mayer7c580442007-10-27 17:54:30 +00001251 /* This is the way the PowerPC specification defines it */
1252 float128 ft0_128, ft1_128;
j_mayere864cab2007-03-22 22:17:08 +00001253
aurel32af129062008-11-19 16:10:23 +00001254 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1255 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001256 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
aurel32da1e7ac2008-12-15 17:14:43 +00001257 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1258 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1259 /* Magnitude subtraction of infinities */
1260 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1261 } else {
1262 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1263 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1264 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1265 }
j_mayere864cab2007-03-22 22:17:08 +00001266#else
j_mayer7c580442007-10-27 17:54:30 +00001267 /* This is OK on x86 hosts */
aurel32af129062008-11-19 16:10:23 +00001268 farg1.d = (farg1.d * farg2.d) + farg3.d;
j_mayere864cab2007-03-22 22:17:08 +00001269#endif
j_mayer7c580442007-10-27 17:54:30 +00001270 }
Aurelien Jarnodd94ad92011-01-06 15:38:18 +01001271
aurel32af129062008-11-19 16:10:23 +00001272 return farg1.ll;
j_mayere864cab2007-03-22 22:17:08 +00001273}
1274
aurel32af129062008-11-19 16:10:23 +00001275/* fmsub - fmsub. */
1276uint64_t helper_fmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
j_mayere864cab2007-03-22 22:17:08 +00001277{
aurel32af129062008-11-19 16:10:23 +00001278 CPU_DoubleU farg1, farg2, farg3;
1279
1280 farg1.ll = arg1;
1281 farg2.ll = arg2;
1282 farg3.ll = arg3;
Aurelien Jarnodd94ad92011-01-06 15:38:18 +01001283
Aurelien Jarno96912e32011-01-17 19:29:33 +01001284 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
aurel32da1e7ac2008-12-15 17:14:43 +00001285 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1286 /* Multiplication of zero by infinity */
1287 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
j_mayer7c580442007-10-27 17:54:30 +00001288 } else {
Aurelien Jarno96912e32011-01-17 19:29:33 +01001289 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1290 float64_is_signaling_nan(farg2.d) ||
1291 float64_is_signaling_nan(farg3.d))) {
1292 /* sNaN operation */
1293 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1294 }
j_mayere864cab2007-03-22 22:17:08 +00001295#ifdef FLOAT128
j_mayer7c580442007-10-27 17:54:30 +00001296 /* This is the way the PowerPC specification defines it */
1297 float128 ft0_128, ft1_128;
j_mayere864cab2007-03-22 22:17:08 +00001298
aurel32af129062008-11-19 16:10:23 +00001299 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1300 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001301 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
aurel32da1e7ac2008-12-15 17:14:43 +00001302 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1303 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1304 /* Magnitude subtraction of infinities */
1305 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1306 } else {
1307 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1308 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1309 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1310 }
j_mayere864cab2007-03-22 22:17:08 +00001311#else
j_mayer7c580442007-10-27 17:54:30 +00001312 /* This is OK on x86 hosts */
aurel32af129062008-11-19 16:10:23 +00001313 farg1.d = (farg1.d * farg2.d) - farg3.d;
j_mayere864cab2007-03-22 22:17:08 +00001314#endif
j_mayer7c580442007-10-27 17:54:30 +00001315 }
aurel32af129062008-11-19 16:10:23 +00001316 return farg1.ll;
j_mayere864cab2007-03-22 22:17:08 +00001317}
j_mayere864cab2007-03-22 22:17:08 +00001318
aurel32af129062008-11-19 16:10:23 +00001319/* fnmadd - fnmadd. */
1320uint64_t helper_fnmadd (uint64_t arg1, uint64_t arg2, uint64_t arg3)
bellard4b3686f2004-05-23 22:18:12 +00001321{
aurel32af129062008-11-19 16:10:23 +00001322 CPU_DoubleU farg1, farg2, farg3;
1323
1324 farg1.ll = arg1;
1325 farg2.ll = arg2;
1326 farg3.ll = arg3;
1327
Aurelien Jarno96912e32011-01-17 19:29:33 +01001328 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
1329 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
aurel32da1e7ac2008-12-15 17:14:43 +00001330 /* Multiplication of zero by infinity */
1331 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
j_mayer7c580442007-10-27 17:54:30 +00001332 } else {
Aurelien Jarno96912e32011-01-17 19:29:33 +01001333 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1334 float64_is_signaling_nan(farg2.d) ||
1335 float64_is_signaling_nan(farg3.d))) {
1336 /* sNaN operation */
1337 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1338 }
j_mayere864cab2007-03-22 22:17:08 +00001339#ifdef FLOAT128
j_mayer7c580442007-10-27 17:54:30 +00001340 /* This is the way the PowerPC specification defines it */
1341 float128 ft0_128, ft1_128;
j_mayere864cab2007-03-22 22:17:08 +00001342
aurel32af129062008-11-19 16:10:23 +00001343 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1344 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001345 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
aurel32da1e7ac2008-12-15 17:14:43 +00001346 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1347 float128_is_neg(ft0_128) != float64_is_neg(farg3.d))) {
1348 /* Magnitude subtraction of infinities */
1349 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1350 } else {
1351 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1352 ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
1353 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1354 }
j_mayere864cab2007-03-22 22:17:08 +00001355#else
j_mayer7c580442007-10-27 17:54:30 +00001356 /* This is OK on x86 hosts */
aurel32af129062008-11-19 16:10:23 +00001357 farg1.d = (farg1.d * farg2.d) + farg3.d;
j_mayere864cab2007-03-22 22:17:08 +00001358#endif
Aurelien Jarnod788b572011-01-17 19:29:33 +01001359 if (likely(!float64_is_any_nan(farg1.d))) {
aurel32af129062008-11-19 16:10:23 +00001360 farg1.d = float64_chs(farg1.d);
Aurelien Jarnod788b572011-01-17 19:29:33 +01001361 }
j_mayer7c580442007-10-27 17:54:30 +00001362 }
aurel32af129062008-11-19 16:10:23 +00001363 return farg1.ll;
bellard4b3686f2004-05-23 22:18:12 +00001364}
1365
aurel32af129062008-11-19 16:10:23 +00001366/* fnmsub - fnmsub. */
1367uint64_t helper_fnmsub (uint64_t arg1, uint64_t arg2, uint64_t arg3)
bellard4b3686f2004-05-23 22:18:12 +00001368{
aurel32af129062008-11-19 16:10:23 +00001369 CPU_DoubleU farg1, farg2, farg3;
1370
1371 farg1.ll = arg1;
1372 farg2.ll = arg2;
1373 farg3.ll = arg3;
1374
Aurelien Jarno96912e32011-01-17 19:29:33 +01001375 if (unlikely((float64_is_infinity(farg1.d) && float64_is_zero(farg2.d)) ||
aurel32da1e7ac2008-12-15 17:14:43 +00001376 (float64_is_zero(farg1.d) && float64_is_infinity(farg2.d)))) {
1377 /* Multiplication of zero by infinity */
1378 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXIMZ);
j_mayer7c580442007-10-27 17:54:30 +00001379 } else {
Aurelien Jarno96912e32011-01-17 19:29:33 +01001380 if (unlikely(float64_is_signaling_nan(farg1.d) ||
1381 float64_is_signaling_nan(farg2.d) ||
1382 float64_is_signaling_nan(farg3.d))) {
1383 /* sNaN operation */
1384 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1385 }
j_mayere864cab2007-03-22 22:17:08 +00001386#ifdef FLOAT128
j_mayer7c580442007-10-27 17:54:30 +00001387 /* This is the way the PowerPC specification defines it */
1388 float128 ft0_128, ft1_128;
j_mayere864cab2007-03-22 22:17:08 +00001389
aurel32af129062008-11-19 16:10:23 +00001390 ft0_128 = float64_to_float128(farg1.d, &env->fp_status);
1391 ft1_128 = float64_to_float128(farg2.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001392 ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
aurel32da1e7ac2008-12-15 17:14:43 +00001393 if (unlikely(float128_is_infinity(ft0_128) && float64_is_infinity(farg3.d) &&
1394 float128_is_neg(ft0_128) == float64_is_neg(farg3.d))) {
1395 /* Magnitude subtraction of infinities */
1396 farg1.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXISI);
1397 } else {
1398 ft1_128 = float64_to_float128(farg3.d, &env->fp_status);
1399 ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
1400 farg1.d = float128_to_float64(ft0_128, &env->fp_status);
1401 }
j_mayere864cab2007-03-22 22:17:08 +00001402#else
j_mayer7c580442007-10-27 17:54:30 +00001403 /* This is OK on x86 hosts */
aurel32af129062008-11-19 16:10:23 +00001404 farg1.d = (farg1.d * farg2.d) - farg3.d;
j_mayere864cab2007-03-22 22:17:08 +00001405#endif
Aurelien Jarnod788b572011-01-17 19:29:33 +01001406 if (likely(!float64_is_any_nan(farg1.d))) {
aurel32af129062008-11-19 16:10:23 +00001407 farg1.d = float64_chs(farg1.d);
Aurelien Jarnod788b572011-01-17 19:29:33 +01001408 }
j_mayer7c580442007-10-27 17:54:30 +00001409 }
aurel32af129062008-11-19 16:10:23 +00001410 return farg1.ll;
bellard1ef59d02004-04-26 19:48:05 +00001411}
1412
aurel32af129062008-11-19 16:10:23 +00001413/* frsp - frsp. */
1414uint64_t helper_frsp (uint64_t arg)
1415{
1416 CPU_DoubleU farg;
aurel326ad193e2008-12-15 01:00:17 +00001417 float32 f32;
aurel32af129062008-11-19 16:10:23 +00001418 farg.ll = arg;
1419
aurel32af129062008-11-19 16:10:23 +00001420 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001421 /* sNaN square root */
Aurelien Jarno96912e32011-01-17 19:29:33 +01001422 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
j_mayer7c580442007-10-27 17:54:30 +00001423 }
Aurelien Jarno96912e32011-01-17 19:29:33 +01001424 f32 = float64_to_float32(farg.d, &env->fp_status);
1425 farg.d = float32_to_float64(f32, &env->fp_status);
1426
aurel32af129062008-11-19 16:10:23 +00001427 return farg.ll;
j_mayer7c580442007-10-27 17:54:30 +00001428}
j_mayer7c580442007-10-27 17:54:30 +00001429
aurel32af129062008-11-19 16:10:23 +00001430/* fsqrt - fsqrt. */
1431uint64_t helper_fsqrt (uint64_t arg)
bellard9a64fbe2004-01-04 22:58:38 +00001432{
aurel32af129062008-11-19 16:10:23 +00001433 CPU_DoubleU farg;
1434 farg.ll = arg;
1435
Aurelien Jarno96912e32011-01-17 19:29:33 +01001436 if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001437 /* Square root of a negative nonzero number */
aurel32af129062008-11-19 16:10:23 +00001438 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
j_mayer7c580442007-10-27 17:54:30 +00001439 } else {
Aurelien Jarno96912e32011-01-17 19:29:33 +01001440 if (unlikely(float64_is_signaling_nan(farg.d))) {
1441 /* sNaN square root */
1442 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1443 }
aurel32af129062008-11-19 16:10:23 +00001444 farg.d = float64_sqrt(farg.d, &env->fp_status);
j_mayer7c580442007-10-27 17:54:30 +00001445 }
aurel32af129062008-11-19 16:10:23 +00001446 return farg.ll;
bellard9a64fbe2004-01-04 22:58:38 +00001447}
1448
aurel32af129062008-11-19 16:10:23 +00001449/* fre - fre. */
1450uint64_t helper_fre (uint64_t arg)
j_mayerd7e4b872007-09-30 01:11:48 +00001451{
aurel32c609b122009-02-04 13:52:39 +00001452 CPU_DoubleU farg;
aurel3206f73322009-02-04 14:08:08 +00001453 farg.ll = arg;
j_mayerd7e4b872007-09-30 01:11:48 +00001454
aurel32af129062008-11-19 16:10:23 +00001455 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001456 /* sNaN reciprocal */
Aurelien Jarno96912e32011-01-17 19:29:33 +01001457 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
j_mayerd7e4b872007-09-30 01:11:48 +00001458 }
Aurelien Jarno96912e32011-01-17 19:29:33 +01001459 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
aurel32af129062008-11-19 16:10:23 +00001460 return farg.d;
j_mayerd7e4b872007-09-30 01:11:48 +00001461}
1462
aurel32af129062008-11-19 16:10:23 +00001463/* fres - fres. */
1464uint64_t helper_fres (uint64_t arg)
bellard9a64fbe2004-01-04 22:58:38 +00001465{
aurel3206f73322009-02-04 14:08:08 +00001466 CPU_DoubleU farg;
aurel326c01bf62008-12-18 22:42:23 +00001467 float32 f32;
aurel3206f73322009-02-04 14:08:08 +00001468 farg.ll = arg;
bellard4ecc3192005-03-13 17:01:22 +00001469
aurel32af129062008-11-19 16:10:23 +00001470 if (unlikely(float64_is_signaling_nan(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001471 /* sNaN reciprocal */
Aurelien Jarno96912e32011-01-17 19:29:33 +01001472 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
bellard4ecc3192005-03-13 17:01:22 +00001473 }
Aurelien Jarno96912e32011-01-17 19:29:33 +01001474 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
1475 f32 = float64_to_float32(farg.d, &env->fp_status);
1476 farg.d = float32_to_float64(f32, &env->fp_status);
1477
aurel32af129062008-11-19 16:10:23 +00001478 return farg.ll;
bellard9a64fbe2004-01-04 22:58:38 +00001479}
1480
aurel32af129062008-11-19 16:10:23 +00001481/* frsqrte - frsqrte. */
1482uint64_t helper_frsqrte (uint64_t arg)
bellard9a64fbe2004-01-04 22:58:38 +00001483{
aurel32c609b122009-02-04 13:52:39 +00001484 CPU_DoubleU farg;
aurel326c01bf62008-12-18 22:42:23 +00001485 float32 f32;
aurel3206f73322009-02-04 14:08:08 +00001486 farg.ll = arg;
bellard4ecc3192005-03-13 17:01:22 +00001487
Aurelien Jarno96912e32011-01-17 19:29:33 +01001488 if (unlikely(float64_is_neg(farg.d) && !float64_is_zero(farg.d))) {
j_mayer7c580442007-10-27 17:54:30 +00001489 /* Reciprocal square root of a negative nonzero number */
aurel32af129062008-11-19 16:10:23 +00001490 farg.ll = fload_invalid_op_excp(POWERPC_EXCP_FP_VXSQRT);
bellard4ecc3192005-03-13 17:01:22 +00001491 } else {
Aurelien Jarno96912e32011-01-17 19:29:33 +01001492 if (unlikely(float64_is_signaling_nan(farg.d))) {
1493 /* sNaN reciprocal square root */
1494 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1495 }
aurel326c01bf62008-12-18 22:42:23 +00001496 farg.d = float64_sqrt(farg.d, &env->fp_status);
aurel32c609b122009-02-04 13:52:39 +00001497 farg.d = float64_div(float64_one, farg.d, &env->fp_status);
aurel326c01bf62008-12-18 22:42:23 +00001498 f32 = float64_to_float32(farg.d, &env->fp_status);
1499 farg.d = float32_to_float64(f32, &env->fp_status);
bellard4ecc3192005-03-13 17:01:22 +00001500 }
aurel32af129062008-11-19 16:10:23 +00001501 return farg.ll;
bellard9a64fbe2004-01-04 22:58:38 +00001502}
1503
aurel32af129062008-11-19 16:10:23 +00001504/* fsel - fsel. */
1505uint64_t helper_fsel (uint64_t arg1, uint64_t arg2, uint64_t arg3)
bellard9a64fbe2004-01-04 22:58:38 +00001506{
aurel326ad73652008-12-14 11:12:10 +00001507 CPU_DoubleU farg1;
aurel32af129062008-11-19 16:10:23 +00001508
1509 farg1.ll = arg1;
aurel32af129062008-11-19 16:10:23 +00001510
Aurelien Jarnod788b572011-01-17 19:29:33 +01001511 if ((!float64_is_neg(farg1.d) || float64_is_zero(farg1.d)) && !float64_is_any_nan(farg1.d)) {
aurel326ad73652008-12-14 11:12:10 +00001512 return arg2;
Aurelien Jarnod788b572011-01-17 19:29:33 +01001513 } else {
aurel326ad73652008-12-14 11:12:10 +00001514 return arg3;
Aurelien Jarnod788b572011-01-17 19:29:33 +01001515 }
bellard9a64fbe2004-01-04 22:58:38 +00001516}
1517
aurel329a819372008-12-14 19:34:09 +00001518void helper_fcmpu (uint64_t arg1, uint64_t arg2, uint32_t crfD)
bellard9a64fbe2004-01-04 22:58:38 +00001519{
aurel32af129062008-11-19 16:10:23 +00001520 CPU_DoubleU farg1, farg2;
aurel32e1571902008-10-21 11:31:14 +00001521 uint32_t ret = 0;
aurel32af129062008-11-19 16:10:23 +00001522 farg1.ll = arg1;
1523 farg2.ll = arg2;
aurel32e1571902008-10-21 11:31:14 +00001524
Aurelien Jarnod788b572011-01-17 19:29:33 +01001525 if (unlikely(float64_is_any_nan(farg1.d) ||
1526 float64_is_any_nan(farg2.d))) {
aurel329a819372008-12-14 19:34:09 +00001527 ret = 0x01UL;
1528 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1529 ret = 0x08UL;
1530 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1531 ret = 0x04UL;
1532 } else {
1533 ret = 0x02UL;
1534 }
1535
1536 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1537 env->fpscr |= ret << FPSCR_FPRF;
1538 env->crf[crfD] = ret;
1539 if (unlikely(ret == 0x01UL
1540 && (float64_is_signaling_nan(farg1.d) ||
1541 float64_is_signaling_nan(farg2.d)))) {
1542 /* sNaN comparison */
1543 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN);
1544 }
1545}
1546
1547void helper_fcmpo (uint64_t arg1, uint64_t arg2, uint32_t crfD)
1548{
1549 CPU_DoubleU farg1, farg2;
1550 uint32_t ret = 0;
1551 farg1.ll = arg1;
1552 farg2.ll = arg2;
1553
Aurelien Jarnod788b572011-01-17 19:29:33 +01001554 if (unlikely(float64_is_any_nan(farg1.d) ||
1555 float64_is_any_nan(farg2.d))) {
aurel329a819372008-12-14 19:34:09 +00001556 ret = 0x01UL;
1557 } else if (float64_lt(farg1.d, farg2.d, &env->fp_status)) {
1558 ret = 0x08UL;
1559 } else if (!float64_le(farg1.d, farg2.d, &env->fp_status)) {
1560 ret = 0x04UL;
1561 } else {
1562 ret = 0x02UL;
1563 }
1564
1565 env->fpscr &= ~(0x0F << FPSCR_FPRF);
1566 env->fpscr |= ret << FPSCR_FPRF;
1567 env->crf[crfD] = ret;
1568 if (unlikely (ret == 0x01UL)) {
aurel32af129062008-11-19 16:10:23 +00001569 if (float64_is_signaling_nan(farg1.d) ||
1570 float64_is_signaling_nan(farg2.d)) {
j_mayer7c580442007-10-27 17:54:30 +00001571 /* sNaN comparison */
1572 fload_invalid_op_excp(POWERPC_EXCP_FP_VXSNAN |
1573 POWERPC_EXCP_FP_VXVC);
1574 } else {
1575 /* qNaN comparison */
1576 fload_invalid_op_excp(POWERPC_EXCP_FP_VXVC);
1577 }
bellard9a64fbe2004-01-04 22:58:38 +00001578 }
bellard9a64fbe2004-01-04 22:58:38 +00001579}
1580
j_mayer76a66252007-03-07 08:32:30 +00001581#if !defined (CONFIG_USER_ONLY)
aurel326527f6e2008-12-06 13:03:35 +00001582void helper_store_msr (target_ulong val)
j_mayer0411a972007-10-25 21:35:50 +00001583{
aurel326527f6e2008-12-06 13:03:35 +00001584 val = hreg_store_msr(env, val, 0);
1585 if (val != 0) {
j_mayer0411a972007-10-25 21:35:50 +00001586 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
aurel32e06fcd72008-12-11 22:42:14 +00001587 helper_raise_exception(val);
j_mayer0411a972007-10-25 21:35:50 +00001588 }
1589}
1590
Blue Swirl636aa202009-08-16 09:06:54 +00001591static inline void do_rfi(target_ulong nip, target_ulong msr,
1592 target_ulong msrm, int keep_msrh)
bellard9a64fbe2004-01-04 22:58:38 +00001593{
j_mayer426613d2007-03-23 09:45:27 +00001594#if defined(TARGET_PPC64)
j_mayer0411a972007-10-25 21:35:50 +00001595 if (msr & (1ULL << MSR_SF)) {
1596 nip = (uint64_t)nip;
1597 msr &= (uint64_t)msrm;
j_mayera42bd6c2007-03-30 10:22:46 +00001598 } else {
j_mayer0411a972007-10-25 21:35:50 +00001599 nip = (uint32_t)nip;
1600 msr = (uint32_t)(msr & msrm);
1601 if (keep_msrh)
1602 msr |= env->msr & ~((uint64_t)0xFFFFFFFF);
j_mayera42bd6c2007-03-30 10:22:46 +00001603 }
j_mayer426613d2007-03-23 09:45:27 +00001604#else
j_mayer0411a972007-10-25 21:35:50 +00001605 nip = (uint32_t)nip;
1606 msr &= (uint32_t)msrm;
j_mayer426613d2007-03-23 09:45:27 +00001607#endif
j_mayer0411a972007-10-25 21:35:50 +00001608 /* XXX: beware: this is false if VLE is supported */
1609 env->nip = nip & ~((target_ulong)0x00000003);
j_mayera4f30712007-11-17 21:14:09 +00001610 hreg_store_msr(env, msr, 1);
j_mayerd9bce9d2007-03-17 14:02:15 +00001611#if defined (DEBUG_OP)
j_mayer0411a972007-10-25 21:35:50 +00001612 cpu_dump_rfi(env->nip, env->msr);
j_mayerd9bce9d2007-03-17 14:02:15 +00001613#endif
j_mayer0411a972007-10-25 21:35:50 +00001614 /* No need to raise an exception here,
1615 * as rfi is always the last insn of a TB
1616 */
j_mayerd9bce9d2007-03-17 14:02:15 +00001617 env->interrupt_request |= CPU_INTERRUPT_EXITTB;
1618}
1619
aurel32d72a19f2008-11-30 16:24:55 +00001620void helper_rfi (void)
j_mayer0411a972007-10-25 21:35:50 +00001621{
aurel32d72a19f2008-11-30 16:24:55 +00001622 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
Thomas Monjalonc3d420e2010-05-28 21:07:32 +02001623 ~((target_ulong)0x783F0000), 1);
j_mayer0411a972007-10-25 21:35:50 +00001624}
1625
j_mayerd9bce9d2007-03-17 14:02:15 +00001626#if defined(TARGET_PPC64)
aurel32d72a19f2008-11-30 16:24:55 +00001627void helper_rfid (void)
j_mayer426613d2007-03-23 09:45:27 +00001628{
aurel32d72a19f2008-11-30 16:24:55 +00001629 do_rfi(env->spr[SPR_SRR0], env->spr[SPR_SRR1],
Thomas Monjalonc3d420e2010-05-28 21:07:32 +02001630 ~((target_ulong)0x783F0000), 0);
bellard9a64fbe2004-01-04 22:58:38 +00001631}
j_mayer78636672007-11-16 14:11:28 +00001632
aurel32d72a19f2008-11-30 16:24:55 +00001633void helper_hrfid (void)
j_mayerbe147d02007-09-30 13:03:23 +00001634{
aurel32d72a19f2008-11-30 16:24:55 +00001635 do_rfi(env->spr[SPR_HSRR0], env->spr[SPR_HSRR1],
Thomas Monjalonc3d420e2010-05-28 21:07:32 +02001636 ~((target_ulong)0x783F0000), 0);
j_mayerbe147d02007-09-30 13:03:23 +00001637}
1638#endif
j_mayerd9bce9d2007-03-17 14:02:15 +00001639#endif
bellard9a64fbe2004-01-04 22:58:38 +00001640
aurel32cab3bee2008-11-24 11:28:19 +00001641void helper_tw (target_ulong arg1, target_ulong arg2, uint32_t flags)
bellard9a64fbe2004-01-04 22:58:38 +00001642{
aurel32cab3bee2008-11-24 11:28:19 +00001643 if (!likely(!(((int32_t)arg1 < (int32_t)arg2 && (flags & 0x10)) ||
1644 ((int32_t)arg1 > (int32_t)arg2 && (flags & 0x08)) ||
1645 ((int32_t)arg1 == (int32_t)arg2 && (flags & 0x04)) ||
1646 ((uint32_t)arg1 < (uint32_t)arg2 && (flags & 0x02)) ||
1647 ((uint32_t)arg1 > (uint32_t)arg2 && (flags & 0x01))))) {
aurel32e06fcd72008-12-11 22:42:14 +00001648 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
j_mayera42bd6c2007-03-30 10:22:46 +00001649 }
bellard9a64fbe2004-01-04 22:58:38 +00001650}
1651
j_mayerd9bce9d2007-03-17 14:02:15 +00001652#if defined(TARGET_PPC64)
aurel32cab3bee2008-11-24 11:28:19 +00001653void helper_td (target_ulong arg1, target_ulong arg2, uint32_t flags)
j_mayerd9bce9d2007-03-17 14:02:15 +00001654{
aurel32cab3bee2008-11-24 11:28:19 +00001655 if (!likely(!(((int64_t)arg1 < (int64_t)arg2 && (flags & 0x10)) ||
1656 ((int64_t)arg1 > (int64_t)arg2 && (flags & 0x08)) ||
1657 ((int64_t)arg1 == (int64_t)arg2 && (flags & 0x04)) ||
1658 ((uint64_t)arg1 < (uint64_t)arg2 && (flags & 0x02)) ||
1659 ((uint64_t)arg1 > (uint64_t)arg2 && (flags & 0x01)))))
aurel32e06fcd72008-12-11 22:42:14 +00001660 helper_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
j_mayerd9bce9d2007-03-17 14:02:15 +00001661}
1662#endif
1663
bellardfdabc362005-07-04 22:17:05 +00001664/*****************************************************************************/
j_mayer76a66252007-03-07 08:32:30 +00001665/* PowerPC 601 specific instructions (POWER bridge) */
bellard9a64fbe2004-01-04 22:58:38 +00001666
aurel3222e0e172008-12-06 12:19:14 +00001667target_ulong helper_clcs (uint32_t arg)
bellard9a64fbe2004-01-04 22:58:38 +00001668{
aurel3222e0e172008-12-06 12:19:14 +00001669 switch (arg) {
j_mayer76a66252007-03-07 08:32:30 +00001670 case 0x0CUL:
1671 /* Instruction cache line size */
aurel3222e0e172008-12-06 12:19:14 +00001672 return env->icache_line_size;
j_mayer76a66252007-03-07 08:32:30 +00001673 break;
1674 case 0x0DUL:
1675 /* Data cache line size */
aurel3222e0e172008-12-06 12:19:14 +00001676 return env->dcache_line_size;
j_mayer76a66252007-03-07 08:32:30 +00001677 break;
1678 case 0x0EUL:
1679 /* Minimum cache line size */
aurel3222e0e172008-12-06 12:19:14 +00001680 return (env->icache_line_size < env->dcache_line_size) ?
1681 env->icache_line_size : env->dcache_line_size;
j_mayer76a66252007-03-07 08:32:30 +00001682 break;
1683 case 0x0FUL:
1684 /* Maximum cache line size */
aurel3222e0e172008-12-06 12:19:14 +00001685 return (env->icache_line_size > env->dcache_line_size) ?
1686 env->icache_line_size : env->dcache_line_size;
j_mayer76a66252007-03-07 08:32:30 +00001687 break;
1688 default:
1689 /* Undefined */
aurel3222e0e172008-12-06 12:19:14 +00001690 return 0;
j_mayer76a66252007-03-07 08:32:30 +00001691 break;
1692 }
1693}
1694
aurel3222e0e172008-12-06 12:19:14 +00001695target_ulong helper_div (target_ulong arg1, target_ulong arg2)
j_mayer76a66252007-03-07 08:32:30 +00001696{
aurel3222e0e172008-12-06 12:19:14 +00001697 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
j_mayer76a66252007-03-07 08:32:30 +00001698
aurel3222e0e172008-12-06 12:19:14 +00001699 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1700 (int32_t)arg2 == 0) {
j_mayer76a66252007-03-07 08:32:30 +00001701 env->spr[SPR_MQ] = 0;
aurel3222e0e172008-12-06 12:19:14 +00001702 return INT32_MIN;
j_mayer76a66252007-03-07 08:32:30 +00001703 } else {
aurel3222e0e172008-12-06 12:19:14 +00001704 env->spr[SPR_MQ] = tmp % arg2;
1705 return tmp / (int32_t)arg2;
j_mayer76a66252007-03-07 08:32:30 +00001706 }
1707}
1708
aurel3222e0e172008-12-06 12:19:14 +00001709target_ulong helper_divo (target_ulong arg1, target_ulong arg2)
j_mayer76a66252007-03-07 08:32:30 +00001710{
aurel3222e0e172008-12-06 12:19:14 +00001711 uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
j_mayer76a66252007-03-07 08:32:30 +00001712
aurel3222e0e172008-12-06 12:19:14 +00001713 if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1714 (int32_t)arg2 == 0) {
aurel323d7b4172008-10-21 11:28:46 +00001715 env->xer |= (1 << XER_OV) | (1 << XER_SO);
aurel3222e0e172008-12-06 12:19:14 +00001716 env->spr[SPR_MQ] = 0;
1717 return INT32_MIN;
j_mayer76a66252007-03-07 08:32:30 +00001718 } else {
aurel3222e0e172008-12-06 12:19:14 +00001719 env->spr[SPR_MQ] = tmp % arg2;
1720 tmp /= (int32_t)arg2;
1721 if ((int32_t)tmp != tmp) {
aurel323d7b4172008-10-21 11:28:46 +00001722 env->xer |= (1 << XER_OV) | (1 << XER_SO);
j_mayer76a66252007-03-07 08:32:30 +00001723 } else {
aurel323d7b4172008-10-21 11:28:46 +00001724 env->xer &= ~(1 << XER_OV);
j_mayer76a66252007-03-07 08:32:30 +00001725 }
aurel3222e0e172008-12-06 12:19:14 +00001726 return tmp;
j_mayer76a66252007-03-07 08:32:30 +00001727 }
1728}
1729
aurel3222e0e172008-12-06 12:19:14 +00001730target_ulong helper_divs (target_ulong arg1, target_ulong arg2)
j_mayer76a66252007-03-07 08:32:30 +00001731{
aurel3222e0e172008-12-06 12:19:14 +00001732 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1733 (int32_t)arg2 == 0) {
j_mayer76a66252007-03-07 08:32:30 +00001734 env->spr[SPR_MQ] = 0;
aurel3222e0e172008-12-06 12:19:14 +00001735 return INT32_MIN;
j_mayer76a66252007-03-07 08:32:30 +00001736 } else {
aurel3222e0e172008-12-06 12:19:14 +00001737 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1738 return (int32_t)arg1 / (int32_t)arg2;
j_mayer76a66252007-03-07 08:32:30 +00001739 }
1740}
1741
aurel3222e0e172008-12-06 12:19:14 +00001742target_ulong helper_divso (target_ulong arg1, target_ulong arg2)
j_mayer76a66252007-03-07 08:32:30 +00001743{
aurel3222e0e172008-12-06 12:19:14 +00001744 if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
1745 (int32_t)arg2 == 0) {
1746 env->xer |= (1 << XER_OV) | (1 << XER_SO);
j_mayer76a66252007-03-07 08:32:30 +00001747 env->spr[SPR_MQ] = 0;
aurel3222e0e172008-12-06 12:19:14 +00001748 return INT32_MIN;
j_mayer76a66252007-03-07 08:32:30 +00001749 } else {
aurel323d7b4172008-10-21 11:28:46 +00001750 env->xer &= ~(1 << XER_OV);
aurel3222e0e172008-12-06 12:19:14 +00001751 env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
1752 return (int32_t)arg1 / (int32_t)arg2;
j_mayer76a66252007-03-07 08:32:30 +00001753 }
1754}
1755
1756#if !defined (CONFIG_USER_ONLY)
aurel3222e0e172008-12-06 12:19:14 +00001757target_ulong helper_rac (target_ulong addr)
j_mayer76a66252007-03-07 08:32:30 +00001758{
Anthony Liguoric227f092009-10-01 16:12:16 -05001759 mmu_ctx_t ctx;
j_mayerfaadf502007-11-03 13:37:12 +00001760 int nb_BATs;
aurel3222e0e172008-12-06 12:19:14 +00001761 target_ulong ret = 0;
j_mayer76a66252007-03-07 08:32:30 +00001762
1763 /* We don't have to generate many instances of this instruction,
1764 * as rac is supervisor only.
1765 */
j_mayerfaadf502007-11-03 13:37:12 +00001766 /* XXX: FIX THIS: Pretend we have no BAT */
1767 nb_BATs = env->nb_BATs;
1768 env->nb_BATs = 0;
aurel3222e0e172008-12-06 12:19:14 +00001769 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0)
1770 ret = ctx.raddr;
j_mayerfaadf502007-11-03 13:37:12 +00001771 env->nb_BATs = nb_BATs;
aurel3222e0e172008-12-06 12:19:14 +00001772 return ret;
bellard9a64fbe2004-01-04 22:58:38 +00001773}
1774
aurel32d72a19f2008-11-30 16:24:55 +00001775void helper_rfsvc (void)
j_mayer76a66252007-03-07 08:32:30 +00001776{
aurel32d72a19f2008-11-30 16:24:55 +00001777 do_rfi(env->lr, env->ctr, 0x0000FFFF, 0);
j_mayer76a66252007-03-07 08:32:30 +00001778}
j_mayer76a66252007-03-07 08:32:30 +00001779#endif
1780
1781/*****************************************************************************/
1782/* 602 specific instructions */
1783/* mfrom is the most crazy instruction ever seen, imho ! */
1784/* Real implementation uses a ROM table. Do the same */
aurel325e9ae182008-12-13 12:30:21 +00001785/* Extremly decomposed:
1786 * -arg / 256
1787 * return 256 * log10(10 + 1.0) + 0.5
1788 */
aurel32db9a16a2008-12-08 18:11:50 +00001789#if !defined (CONFIG_USER_ONLY)
aurel32cf02a652008-11-30 16:23:35 +00001790target_ulong helper_602_mfrom (target_ulong arg)
j_mayer76a66252007-03-07 08:32:30 +00001791{
aurel32cf02a652008-11-30 16:23:35 +00001792 if (likely(arg < 602)) {
j_mayer76a66252007-03-07 08:32:30 +00001793#include "mfrom_table.c"
aurel3245d827d2008-12-07 13:40:29 +00001794 return mfrom_ROM_table[arg];
j_mayer76a66252007-03-07 08:32:30 +00001795 } else {
aurel32cf02a652008-11-30 16:23:35 +00001796 return 0;
j_mayer76a66252007-03-07 08:32:30 +00001797 }
1798}
aurel32db9a16a2008-12-08 18:11:50 +00001799#endif
j_mayer76a66252007-03-07 08:32:30 +00001800
1801/*****************************************************************************/
1802/* Embedded PowerPC specific helpers */
j_mayer76a66252007-03-07 08:32:30 +00001803
j_mayera750fc02007-09-26 23:54:22 +00001804/* XXX: to be improved to check access rights when in user-mode */
Aurelien Jarno95ff8952010-02-06 16:59:11 +01001805target_ulong helper_load_dcr (target_ulong dcrn)
j_mayera750fc02007-09-26 23:54:22 +00001806{
Alexander Graf73b01962009-12-21 14:02:39 +01001807 uint32_t val = 0;
j_mayera750fc02007-09-26 23:54:22 +00001808
1809 if (unlikely(env->dcr_env == NULL)) {
aliguori93fcfe32009-01-15 22:34:14 +00001810 qemu_log("No DCR environment\n");
aurel32e06fcd72008-12-11 22:42:14 +00001811 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1812 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
Aurelien Jarno95ff8952010-02-06 16:59:11 +01001813 } else if (unlikely(ppc_dcr_read(env->dcr_env, (uint32_t)dcrn, &val) != 0)) {
1814 qemu_log("DCR read error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
aurel32e06fcd72008-12-11 22:42:14 +00001815 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1816 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
j_mayera750fc02007-09-26 23:54:22 +00001817 }
aurel3206dca6a2008-12-06 16:37:18 +00001818 return val;
j_mayera750fc02007-09-26 23:54:22 +00001819}
1820
Aurelien Jarno95ff8952010-02-06 16:59:11 +01001821void helper_store_dcr (target_ulong dcrn, target_ulong val)
j_mayera750fc02007-09-26 23:54:22 +00001822{
1823 if (unlikely(env->dcr_env == NULL)) {
aliguori93fcfe32009-01-15 22:34:14 +00001824 qemu_log("No DCR environment\n");
aurel32e06fcd72008-12-11 22:42:14 +00001825 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1826 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
Aurelien Jarno95ff8952010-02-06 16:59:11 +01001827 } else if (unlikely(ppc_dcr_write(env->dcr_env, (uint32_t)dcrn, (uint32_t)val) != 0)) {
1828 qemu_log("DCR write error %d %03x\n", (uint32_t)dcrn, (uint32_t)dcrn);
aurel32e06fcd72008-12-11 22:42:14 +00001829 helper_raise_exception_err(POWERPC_EXCP_PROGRAM,
1830 POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
j_mayera750fc02007-09-26 23:54:22 +00001831 }
1832}
1833
j_mayer76a66252007-03-07 08:32:30 +00001834#if !defined(CONFIG_USER_ONLY)
aurel32d72a19f2008-11-30 16:24:55 +00001835void helper_40x_rfci (void)
j_mayer76a66252007-03-07 08:32:30 +00001836{
aurel32d72a19f2008-11-30 16:24:55 +00001837 do_rfi(env->spr[SPR_40x_SRR2], env->spr[SPR_40x_SRR3],
1838 ~((target_ulong)0xFFFF0000), 0);
j_mayer76a66252007-03-07 08:32:30 +00001839}
1840
aurel32d72a19f2008-11-30 16:24:55 +00001841void helper_rfci (void)
j_mayera42bd6c2007-03-30 10:22:46 +00001842{
aurel32d72a19f2008-11-30 16:24:55 +00001843 do_rfi(env->spr[SPR_BOOKE_CSRR0], SPR_BOOKE_CSRR1,
1844 ~((target_ulong)0x3FFF0000), 0);
j_mayera42bd6c2007-03-30 10:22:46 +00001845}
1846
aurel32d72a19f2008-11-30 16:24:55 +00001847void helper_rfdi (void)
j_mayera42bd6c2007-03-30 10:22:46 +00001848{
aurel32d72a19f2008-11-30 16:24:55 +00001849 do_rfi(env->spr[SPR_BOOKE_DSRR0], SPR_BOOKE_DSRR1,
1850 ~((target_ulong)0x3FFF0000), 0);
j_mayera42bd6c2007-03-30 10:22:46 +00001851}
1852
aurel32d72a19f2008-11-30 16:24:55 +00001853void helper_rfmci (void)
j_mayera42bd6c2007-03-30 10:22:46 +00001854{
aurel32d72a19f2008-11-30 16:24:55 +00001855 do_rfi(env->spr[SPR_BOOKE_MCSRR0], SPR_BOOKE_MCSRR1,
1856 ~((target_ulong)0x3FFF0000), 0);
j_mayera42bd6c2007-03-30 10:22:46 +00001857}
j_mayer76a66252007-03-07 08:32:30 +00001858#endif
1859
1860/* 440 specific */
aurel32ef0d51a2008-11-30 17:26:29 +00001861target_ulong helper_dlmzb (target_ulong high, target_ulong low, uint32_t update_Rc)
j_mayer76a66252007-03-07 08:32:30 +00001862{
1863 target_ulong mask;
1864 int i;
1865
1866 i = 1;
1867 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
aurel32ef0d51a2008-11-30 17:26:29 +00001868 if ((high & mask) == 0) {
1869 if (update_Rc) {
1870 env->crf[0] = 0x4;
1871 }
j_mayer76a66252007-03-07 08:32:30 +00001872 goto done;
aurel32ef0d51a2008-11-30 17:26:29 +00001873 }
j_mayer76a66252007-03-07 08:32:30 +00001874 i++;
1875 }
1876 for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
aurel32ef0d51a2008-11-30 17:26:29 +00001877 if ((low & mask) == 0) {
1878 if (update_Rc) {
1879 env->crf[0] = 0x8;
1880 }
1881 goto done;
1882 }
j_mayer76a66252007-03-07 08:32:30 +00001883 i++;
1884 }
aurel32ef0d51a2008-11-30 17:26:29 +00001885 if (update_Rc) {
1886 env->crf[0] = 0x2;
1887 }
j_mayer76a66252007-03-07 08:32:30 +00001888 done:
aurel32ef0d51a2008-11-30 17:26:29 +00001889 env->xer = (env->xer & ~0x7F) | i;
1890 if (update_Rc) {
1891 env->crf[0] |= xer_so;
1892 }
1893 return i;
j_mayer76a66252007-03-07 08:32:30 +00001894}
1895
aurel321c978562008-11-23 10:54:04 +00001896/*****************************************************************************/
aurel32d6a46fe2009-01-03 13:31:19 +00001897/* Altivec extension helpers */
Juan Quintelae2542fe2009-07-27 16:13:06 +02001898#if defined(HOST_WORDS_BIGENDIAN)
aurel32d6a46fe2009-01-03 13:31:19 +00001899#define HI_IDX 0
1900#define LO_IDX 1
1901#else
1902#define HI_IDX 1
1903#define LO_IDX 0
1904#endif
1905
Juan Quintelae2542fe2009-07-27 16:13:06 +02001906#if defined(HOST_WORDS_BIGENDIAN)
aurel32d6a46fe2009-01-03 13:31:19 +00001907#define VECTOR_FOR_INORDER_I(index, element) \
1908 for (index = 0; index < ARRAY_SIZE(r->element); index++)
1909#else
1910#define VECTOR_FOR_INORDER_I(index, element) \
1911 for (index = ARRAY_SIZE(r->element)-1; index >= 0; index--)
1912#endif
1913
aurel3234ba2852009-02-04 09:05:53 +00001914/* If X is a NaN, store the corresponding QNaN into RESULT. Otherwise,
1915 * execute the following block. */
1916#define DO_HANDLE_NAN(result, x) \
Aurelien Jarno82b323c2011-01-06 15:38:18 +01001917 if (float32_is_any_nan(x)) { \
aurel3234ba2852009-02-04 09:05:53 +00001918 CPU_FloatU __f; \
1919 __f.f = x; \
1920 __f.l = __f.l | (1 << 22); /* Set QNaN bit. */ \
1921 result = __f.f; \
1922 } else
1923
1924#define HANDLE_NAN1(result, x) \
1925 DO_HANDLE_NAN(result, x)
1926#define HANDLE_NAN2(result, x, y) \
1927 DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y)
1928#define HANDLE_NAN3(result, x, y, z) \
1929 DO_HANDLE_NAN(result, x) DO_HANDLE_NAN(result, y) DO_HANDLE_NAN(result, z)
1930
aurel3200d3b8f2009-01-04 22:11:59 +00001931/* Saturating arithmetic helpers. */
Blue Swirld62d2862010-09-18 05:53:15 +00001932#define SATCVT(from, to, from_type, to_type, min, max) \
Blue Swirl636aa202009-08-16 09:06:54 +00001933 static inline to_type cvt##from##to(from_type x, int *sat) \
aurel3200d3b8f2009-01-04 22:11:59 +00001934 { \
1935 to_type r; \
Blue Swirld62d2862010-09-18 05:53:15 +00001936 if (x < (from_type)min) { \
aurel3200d3b8f2009-01-04 22:11:59 +00001937 r = min; \
1938 *sat = 1; \
Blue Swirld62d2862010-09-18 05:53:15 +00001939 } else if (x > (from_type)max) { \
aurel3200d3b8f2009-01-04 22:11:59 +00001940 r = max; \
1941 *sat = 1; \
1942 } else { \
1943 r = x; \
1944 } \
1945 return r; \
1946 }
Blue Swirld62d2862010-09-18 05:53:15 +00001947#define SATCVTU(from, to, from_type, to_type, min, max) \
1948 static inline to_type cvt##from##to(from_type x, int *sat) \
1949 { \
1950 to_type r; \
1951 if (x > (from_type)max) { \
1952 r = max; \
1953 *sat = 1; \
1954 } else { \
1955 r = x; \
1956 } \
1957 return r; \
Blue Swirlc5b76b32009-06-13 08:44:31 +00001958 }
Blue Swirld62d2862010-09-18 05:53:15 +00001959SATCVT(sh, sb, int16_t, int8_t, INT8_MIN, INT8_MAX)
1960SATCVT(sw, sh, int32_t, int16_t, INT16_MIN, INT16_MAX)
1961SATCVT(sd, sw, int64_t, int32_t, INT32_MIN, INT32_MAX)
1962
1963SATCVTU(uh, ub, uint16_t, uint8_t, 0, UINT8_MAX)
1964SATCVTU(uw, uh, uint32_t, uint16_t, 0, UINT16_MAX)
1965SATCVTU(ud, uw, uint64_t, uint32_t, 0, UINT32_MAX)
1966SATCVT(sh, ub, int16_t, uint8_t, 0, UINT8_MAX)
1967SATCVT(sw, uh, int32_t, uint16_t, 0, UINT16_MAX)
1968SATCVT(sd, uw, int64_t, uint32_t, 0, UINT32_MAX)
aurel3200d3b8f2009-01-04 22:11:59 +00001969#undef SATCVT
Blue Swirld62d2862010-09-18 05:53:15 +00001970#undef SATCVTU
aurel3200d3b8f2009-01-04 22:11:59 +00001971
aurel32cbfb6ae2009-01-04 22:13:10 +00001972#define LVE(name, access, swap, element) \
Anthony Liguoric227f092009-10-01 16:12:16 -05001973 void helper_##name (ppc_avr_t *r, target_ulong addr) \
aurel32cbfb6ae2009-01-04 22:13:10 +00001974 { \
1975 size_t n_elems = ARRAY_SIZE(r->element); \
1976 int adjust = HI_IDX*(n_elems-1); \
1977 int sh = sizeof(r->element[0]) >> 1; \
1978 int index = (addr & 0xf) >> sh; \
1979 if(msr_le) { \
1980 r->element[LO_IDX ? index : (adjust - index)] = swap(access(addr)); \
1981 } else { \
1982 r->element[LO_IDX ? index : (adjust - index)] = access(addr); \
1983 } \
1984 }
1985#define I(x) (x)
1986LVE(lvebx, ldub, I, u8)
1987LVE(lvehx, lduw, bswap16, u16)
1988LVE(lvewx, ldl, bswap32, u32)
1989#undef I
1990#undef LVE
1991
Anthony Liguoric227f092009-10-01 16:12:16 -05001992void helper_lvsl (ppc_avr_t *r, target_ulong sh)
aurel32bf8d8de2009-01-04 22:09:42 +00001993{
1994 int i, j = (sh & 0xf);
1995
1996 VECTOR_FOR_INORDER_I (i, u8) {
1997 r->u8[i] = j++;
1998 }
1999}
2000
Anthony Liguoric227f092009-10-01 16:12:16 -05002001void helper_lvsr (ppc_avr_t *r, target_ulong sh)
aurel32bf8d8de2009-01-04 22:09:42 +00002002{
2003 int i, j = 0x10 - (sh & 0xf);
2004
2005 VECTOR_FOR_INORDER_I (i, u8) {
2006 r->u8[i] = j++;
2007 }
2008}
2009
aurel32cbfb6ae2009-01-04 22:13:10 +00002010#define STVE(name, access, swap, element) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002011 void helper_##name (ppc_avr_t *r, target_ulong addr) \
aurel32cbfb6ae2009-01-04 22:13:10 +00002012 { \
2013 size_t n_elems = ARRAY_SIZE(r->element); \
2014 int adjust = HI_IDX*(n_elems-1); \
2015 int sh = sizeof(r->element[0]) >> 1; \
2016 int index = (addr & 0xf) >> sh; \
2017 if(msr_le) { \
2018 access(addr, swap(r->element[LO_IDX ? index : (adjust - index)])); \
2019 } else { \
2020 access(addr, r->element[LO_IDX ? index : (adjust - index)]); \
2021 } \
2022 }
2023#define I(x) (x)
2024STVE(stvebx, stb, I, u8)
2025STVE(stvehx, stw, bswap16, u16)
2026STVE(stvewx, stl, bswap32, u32)
2027#undef I
2028#undef LVE
2029
Anthony Liguoric227f092009-10-01 16:12:16 -05002030void helper_mtvscr (ppc_avr_t *r)
aurel326e87b7c2009-02-03 19:56:09 +00002031{
Juan Quintelae2542fe2009-07-27 16:13:06 +02002032#if defined(HOST_WORDS_BIGENDIAN)
aurel326e87b7c2009-02-03 19:56:09 +00002033 env->vscr = r->u32[3];
2034#else
2035 env->vscr = r->u32[0];
2036#endif
2037 set_flush_to_zero(vscr_nj, &env->vec_status);
2038}
2039
Anthony Liguoric227f092009-10-01 16:12:16 -05002040void helper_vaddcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
aurel32e343da72009-01-04 22:09:31 +00002041{
2042 int i;
2043 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2044 r->u32[i] = ~a->u32[i] < b->u32[i];
2045 }
2046}
2047
Anthony Liguoric227f092009-10-01 16:12:16 -05002048#define VARITH_DO(name, op, element) \
2049void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
2050{ \
2051 int i; \
2052 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2053 r->element[i] = a->element[i] op b->element[i]; \
2054 } \
aurel327872c512009-01-03 13:31:40 +00002055}
2056#define VARITH(suffix, element) \
2057 VARITH_DO(add##suffix, +, element) \
2058 VARITH_DO(sub##suffix, -, element)
2059VARITH(ubm, u8)
2060VARITH(uhm, u16)
2061VARITH(uwm, u32)
2062#undef VARITH_DO
2063#undef VARITH
2064
aurel3256fdd212009-02-09 16:48:51 +00002065#define VARITHFP(suffix, func) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002066 void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
aurel3256fdd212009-02-09 16:48:51 +00002067 { \
2068 int i; \
2069 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2070 HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
2071 r->f[i] = func(a->f[i], b->f[i], &env->vec_status); \
2072 } \
2073 } \
2074 }
2075VARITHFP(addfp, float32_add)
2076VARITHFP(subfp, float32_sub)
2077#undef VARITHFP
2078
aurel325ab09f32009-01-08 23:19:50 +00002079#define VARITHSAT_CASE(type, op, cvt, element) \
2080 { \
2081 type result = (type)a->element[i] op (type)b->element[i]; \
2082 r->element[i] = cvt(result, &sat); \
2083 }
2084
2085#define VARITHSAT_DO(name, op, optype, cvt, element) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002086 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
aurel325ab09f32009-01-08 23:19:50 +00002087 { \
2088 int sat = 0; \
2089 int i; \
2090 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2091 switch (sizeof(r->element[0])) { \
2092 case 1: VARITHSAT_CASE(optype, op, cvt, element); break; \
2093 case 2: VARITHSAT_CASE(optype, op, cvt, element); break; \
2094 case 4: VARITHSAT_CASE(optype, op, cvt, element); break; \
2095 } \
2096 } \
2097 if (sat) { \
2098 env->vscr |= (1 << VSCR_SAT); \
2099 } \
2100 }
2101#define VARITHSAT_SIGNED(suffix, element, optype, cvt) \
2102 VARITHSAT_DO(adds##suffix##s, +, optype, cvt, element) \
2103 VARITHSAT_DO(subs##suffix##s, -, optype, cvt, element)
2104#define VARITHSAT_UNSIGNED(suffix, element, optype, cvt) \
2105 VARITHSAT_DO(addu##suffix##s, +, optype, cvt, element) \
2106 VARITHSAT_DO(subu##suffix##s, -, optype, cvt, element)
2107VARITHSAT_SIGNED(b, s8, int16_t, cvtshsb)
2108VARITHSAT_SIGNED(h, s16, int32_t, cvtswsh)
2109VARITHSAT_SIGNED(w, s32, int64_t, cvtsdsw)
2110VARITHSAT_UNSIGNED(b, u8, uint16_t, cvtshub)
2111VARITHSAT_UNSIGNED(h, u16, uint32_t, cvtswuh)
2112VARITHSAT_UNSIGNED(w, u32, uint64_t, cvtsduw)
2113#undef VARITHSAT_CASE
2114#undef VARITHSAT_DO
2115#undef VARITHSAT_SIGNED
2116#undef VARITHSAT_UNSIGNED
2117
aurel32fab3cbe2009-01-03 13:31:49 +00002118#define VAVG_DO(name, element, etype) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002119 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
aurel32fab3cbe2009-01-03 13:31:49 +00002120 { \
2121 int i; \
2122 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2123 etype x = (etype)a->element[i] + (etype)b->element[i] + 1; \
2124 r->element[i] = x >> 1; \
2125 } \
2126 }
2127
2128#define VAVG(type, signed_element, signed_type, unsigned_element, unsigned_type) \
2129 VAVG_DO(avgs##type, signed_element, signed_type) \
2130 VAVG_DO(avgu##type, unsigned_element, unsigned_type)
2131VAVG(b, s8, int16_t, u8, uint16_t)
2132VAVG(h, s16, int32_t, u16, uint32_t)
2133VAVG(w, s32, int64_t, u32, uint64_t)
2134#undef VAVG_DO
2135#undef VAVG
2136
aurel32e1406322009-02-04 13:52:17 +00002137#define VCF(suffix, cvt, element) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002138 void helper_vcf##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
aurel32e1406322009-02-04 13:52:17 +00002139 { \
2140 int i; \
2141 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2142 float32 t = cvt(b->element[i], &env->vec_status); \
2143 r->f[i] = float32_scalbn (t, -uim, &env->vec_status); \
2144 } \
2145 }
2146VCF(ux, uint32_to_float32, u32)
2147VCF(sx, int32_to_float32, s32)
2148#undef VCF
2149
aurel321add6e22009-01-08 18:54:38 +00002150#define VCMP_DO(suffix, compare, element, record) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002151 void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
aurel321add6e22009-01-08 18:54:38 +00002152 { \
2153 uint32_t ones = (uint32_t)-1; \
2154 uint32_t all = ones; \
2155 uint32_t none = 0; \
2156 int i; \
2157 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2158 uint32_t result = (a->element[i] compare b->element[i] ? ones : 0x0); \
2159 switch (sizeof (a->element[0])) { \
2160 case 4: r->u32[i] = result; break; \
2161 case 2: r->u16[i] = result; break; \
2162 case 1: r->u8[i] = result; break; \
2163 } \
2164 all &= result; \
2165 none |= result; \
2166 } \
2167 if (record) { \
2168 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
2169 } \
2170 }
2171#define VCMP(suffix, compare, element) \
2172 VCMP_DO(suffix, compare, element, 0) \
2173 VCMP_DO(suffix##_dot, compare, element, 1)
2174VCMP(equb, ==, u8)
2175VCMP(equh, ==, u16)
2176VCMP(equw, ==, u32)
2177VCMP(gtub, >, u8)
2178VCMP(gtuh, >, u16)
2179VCMP(gtuw, >, u32)
2180VCMP(gtsb, >, s8)
2181VCMP(gtsh, >, s16)
2182VCMP(gtsw, >, s32)
2183#undef VCMP_DO
2184#undef VCMP
2185
aurel32819ca122009-02-09 16:49:10 +00002186#define VCMPFP_DO(suffix, compare, order, record) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002187 void helper_vcmp##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
aurel32819ca122009-02-09 16:49:10 +00002188 { \
2189 uint32_t ones = (uint32_t)-1; \
2190 uint32_t all = ones; \
2191 uint32_t none = 0; \
2192 int i; \
2193 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2194 uint32_t result; \
2195 int rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status); \
2196 if (rel == float_relation_unordered) { \
2197 result = 0; \
2198 } else if (rel compare order) { \
2199 result = ones; \
2200 } else { \
2201 result = 0; \
2202 } \
2203 r->u32[i] = result; \
2204 all &= result; \
2205 none |= result; \
2206 } \
2207 if (record) { \
2208 env->crf[6] = ((all != 0) << 3) | ((none == 0) << 1); \
2209 } \
2210 }
2211#define VCMPFP(suffix, compare, order) \
2212 VCMPFP_DO(suffix, compare, order, 0) \
2213 VCMPFP_DO(suffix##_dot, compare, order, 1)
2214VCMPFP(eqfp, ==, float_relation_equal)
2215VCMPFP(gefp, !=, float_relation_less)
2216VCMPFP(gtfp, ==, float_relation_greater)
2217#undef VCMPFP_DO
2218#undef VCMPFP
2219
Anthony Liguoric227f092009-10-01 16:12:16 -05002220static inline void vcmpbfp_internal(ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b,
Blue Swirl636aa202009-08-16 09:06:54 +00002221 int record)
aurel32819ca122009-02-09 16:49:10 +00002222{
2223 int i;
2224 int all_in = 0;
2225 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2226 int le_rel = float32_compare_quiet(a->f[i], b->f[i], &env->vec_status);
2227 if (le_rel == float_relation_unordered) {
2228 r->u32[i] = 0xc0000000;
2229 /* ALL_IN does not need to be updated here. */
2230 } else {
2231 float32 bneg = float32_chs(b->f[i]);
2232 int ge_rel = float32_compare_quiet(a->f[i], bneg, &env->vec_status);
2233 int le = le_rel != float_relation_greater;
2234 int ge = ge_rel != float_relation_less;
2235 r->u32[i] = ((!le) << 31) | ((!ge) << 30);
2236 all_in |= (!le | !ge);
2237 }
2238 }
2239 if (record) {
2240 env->crf[6] = (all_in == 0) << 1;
2241 }
2242}
2243
Anthony Liguoric227f092009-10-01 16:12:16 -05002244void helper_vcmpbfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
aurel32819ca122009-02-09 16:49:10 +00002245{
2246 vcmpbfp_internal(r, a, b, 0);
2247}
2248
Anthony Liguoric227f092009-10-01 16:12:16 -05002249void helper_vcmpbfp_dot (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
aurel32819ca122009-02-09 16:49:10 +00002250{
2251 vcmpbfp_internal(r, a, b, 1);
2252}
2253
aurel32875b31d2009-02-09 16:49:20 +00002254#define VCT(suffix, satcvt, element) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002255 void helper_vct##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t uim) \
aurel32875b31d2009-02-09 16:49:20 +00002256 { \
2257 int i; \
2258 int sat = 0; \
2259 float_status s = env->vec_status; \
2260 set_float_rounding_mode(float_round_to_zero, &s); \
2261 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
Aurelien Jarno82b323c2011-01-06 15:38:18 +01002262 if (float32_is_any_nan(b->f[i])) { \
aurel32875b31d2009-02-09 16:49:20 +00002263 r->element[i] = 0; \
2264 } else { \
2265 float64 t = float32_to_float64(b->f[i], &s); \
2266 int64_t j; \
2267 t = float64_scalbn(t, uim, &s); \
2268 j = float64_to_int64(t, &s); \
2269 r->element[i] = satcvt(j, &sat); \
2270 } \
2271 } \
2272 if (sat) { \
2273 env->vscr |= (1 << VSCR_SAT); \
2274 } \
2275 }
2276VCT(uxs, cvtsduw, u32)
2277VCT(sxs, cvtsdsw, s32)
2278#undef VCT
2279
Anthony Liguoric227f092009-10-01 16:12:16 -05002280void helper_vmaddfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
aurel3235cf7c72009-02-09 16:48:59 +00002281{
2282 int i;
2283 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2284 HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
2285 /* Need to do the computation in higher precision and round
2286 * once at the end. */
2287 float64 af, bf, cf, t;
2288 af = float32_to_float64(a->f[i], &env->vec_status);
2289 bf = float32_to_float64(b->f[i], &env->vec_status);
2290 cf = float32_to_float64(c->f[i], &env->vec_status);
2291 t = float64_mul(af, cf, &env->vec_status);
2292 t = float64_add(t, bf, &env->vec_status);
2293 r->f[i] = float64_to_float32(t, &env->vec_status);
2294 }
2295 }
2296}
2297
Anthony Liguoric227f092009-10-01 16:12:16 -05002298void helper_vmhaddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
aurel32b161ae22009-01-04 22:12:29 +00002299{
2300 int sat = 0;
2301 int i;
2302
2303 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2304 int32_t prod = a->s16[i] * b->s16[i];
2305 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2306 r->s16[i] = cvtswsh (t, &sat);
2307 }
2308
2309 if (sat) {
2310 env->vscr |= (1 << VSCR_SAT);
2311 }
2312}
2313
Anthony Liguoric227f092009-10-01 16:12:16 -05002314void helper_vmhraddshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
aurel32b161ae22009-01-04 22:12:29 +00002315{
2316 int sat = 0;
2317 int i;
2318
2319 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2320 int32_t prod = a->s16[i] * b->s16[i] + 0x00004000;
2321 int32_t t = (int32_t)c->s16[i] + (prod >> 15);
2322 r->s16[i] = cvtswsh (t, &sat);
2323 }
2324
2325 if (sat) {
2326 env->vscr |= (1 << VSCR_SAT);
2327 }
2328}
2329
aurel32e4039332009-01-03 13:31:58 +00002330#define VMINMAX_DO(name, compare, element) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002331 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
aurel32e4039332009-01-03 13:31:58 +00002332 { \
2333 int i; \
2334 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2335 if (a->element[i] compare b->element[i]) { \
2336 r->element[i] = b->element[i]; \
2337 } else { \
2338 r->element[i] = a->element[i]; \
2339 } \
2340 } \
2341 }
2342#define VMINMAX(suffix, element) \
2343 VMINMAX_DO(min##suffix, >, element) \
2344 VMINMAX_DO(max##suffix, <, element)
2345VMINMAX(sb, s8)
2346VMINMAX(sh, s16)
2347VMINMAX(sw, s32)
2348VMINMAX(ub, u8)
2349VMINMAX(uh, u16)
2350VMINMAX(uw, u32)
2351#undef VMINMAX_DO
2352#undef VMINMAX
2353
aurel321536ff62009-02-09 16:48:39 +00002354#define VMINMAXFP(suffix, rT, rF) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002355 void helper_v##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
aurel321536ff62009-02-09 16:48:39 +00002356 { \
2357 int i; \
2358 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2359 HANDLE_NAN2(r->f[i], a->f[i], b->f[i]) { \
2360 if (float32_lt_quiet(a->f[i], b->f[i], &env->vec_status)) { \
2361 r->f[i] = rT->f[i]; \
2362 } else { \
2363 r->f[i] = rF->f[i]; \
2364 } \
2365 } \
2366 } \
2367 }
2368VMINMAXFP(minfp, a, b)
2369VMINMAXFP(maxfp, b, a)
2370#undef VMINMAXFP
2371
Anthony Liguoric227f092009-10-01 16:12:16 -05002372void helper_vmladduhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
aurel32bcd2ee22009-01-04 22:13:00 +00002373{
2374 int i;
2375 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2376 int32_t prod = a->s16[i] * b->s16[i];
2377 r->s16[i] = (int16_t) (prod + c->s16[i]);
2378 }
2379}
2380
aurel323b430042009-01-04 22:08:38 +00002381#define VMRG_DO(name, element, highp) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002382 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
aurel323b430042009-01-04 22:08:38 +00002383 { \
Anthony Liguoric227f092009-10-01 16:12:16 -05002384 ppc_avr_t result; \
aurel323b430042009-01-04 22:08:38 +00002385 int i; \
2386 size_t n_elems = ARRAY_SIZE(r->element); \
2387 for (i = 0; i < n_elems/2; i++) { \
2388 if (highp) { \
2389 result.element[i*2+HI_IDX] = a->element[i]; \
2390 result.element[i*2+LO_IDX] = b->element[i]; \
2391 } else { \
2392 result.element[n_elems - i*2 - (1+HI_IDX)] = b->element[n_elems - i - 1]; \
2393 result.element[n_elems - i*2 - (1+LO_IDX)] = a->element[n_elems - i - 1]; \
2394 } \
2395 } \
2396 *r = result; \
2397 }
Juan Quintelae2542fe2009-07-27 16:13:06 +02002398#if defined(HOST_WORDS_BIGENDIAN)
aurel323b430042009-01-04 22:08:38 +00002399#define MRGHI 0
aurel32b392e752009-01-05 21:40:27 +00002400#define MRGLO 1
aurel323b430042009-01-04 22:08:38 +00002401#else
2402#define MRGHI 1
2403#define MRGLO 0
2404#endif
2405#define VMRG(suffix, element) \
2406 VMRG_DO(mrgl##suffix, element, MRGHI) \
2407 VMRG_DO(mrgh##suffix, element, MRGLO)
2408VMRG(b, u8)
2409VMRG(h, u16)
2410VMRG(w, u32)
2411#undef VMRG_DO
2412#undef VMRG
2413#undef MRGHI
2414#undef MRGLO
2415
Anthony Liguoric227f092009-10-01 16:12:16 -05002416void helper_vmsummbm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
aurel32b04ae982009-01-04 22:11:39 +00002417{
2418 int32_t prod[16];
2419 int i;
2420
2421 for (i = 0; i < ARRAY_SIZE(r->s8); i++) {
2422 prod[i] = (int32_t)a->s8[i] * b->u8[i];
2423 }
2424
2425 VECTOR_FOR_INORDER_I(i, s32) {
2426 r->s32[i] = c->s32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2427 }
2428}
2429
Anthony Liguoric227f092009-10-01 16:12:16 -05002430void helper_vmsumshm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
aurel32eae07262009-01-04 22:12:49 +00002431{
2432 int32_t prod[8];
2433 int i;
2434
2435 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2436 prod[i] = a->s16[i] * b->s16[i];
2437 }
2438
2439 VECTOR_FOR_INORDER_I(i, s32) {
2440 r->s32[i] = c->s32[i] + prod[2*i] + prod[2*i+1];
2441 }
2442}
2443
Anthony Liguoric227f092009-10-01 16:12:16 -05002444void helper_vmsumshs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
aurel32eae07262009-01-04 22:12:49 +00002445{
2446 int32_t prod[8];
2447 int i;
2448 int sat = 0;
2449
2450 for (i = 0; i < ARRAY_SIZE(r->s16); i++) {
2451 prod[i] = (int32_t)a->s16[i] * b->s16[i];
2452 }
2453
2454 VECTOR_FOR_INORDER_I (i, s32) {
2455 int64_t t = (int64_t)c->s32[i] + prod[2*i] + prod[2*i+1];
2456 r->u32[i] = cvtsdsw(t, &sat);
2457 }
2458
2459 if (sat) {
2460 env->vscr |= (1 << VSCR_SAT);
2461 }
2462}
2463
Anthony Liguoric227f092009-10-01 16:12:16 -05002464void helper_vmsumubm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
aurel32b04ae982009-01-04 22:11:39 +00002465{
2466 uint16_t prod[16];
2467 int i;
2468
2469 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2470 prod[i] = a->u8[i] * b->u8[i];
2471 }
2472
2473 VECTOR_FOR_INORDER_I(i, u32) {
2474 r->u32[i] = c->u32[i] + prod[4*i] + prod[4*i+1] + prod[4*i+2] + prod[4*i+3];
2475 }
2476}
2477
Anthony Liguoric227f092009-10-01 16:12:16 -05002478void helper_vmsumuhm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
aurel324d9903b2009-01-04 22:12:39 +00002479{
2480 uint32_t prod[8];
2481 int i;
2482
2483 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2484 prod[i] = a->u16[i] * b->u16[i];
2485 }
2486
2487 VECTOR_FOR_INORDER_I(i, u32) {
2488 r->u32[i] = c->u32[i] + prod[2*i] + prod[2*i+1];
2489 }
2490}
2491
Anthony Liguoric227f092009-10-01 16:12:16 -05002492void helper_vmsumuhs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
aurel324d9903b2009-01-04 22:12:39 +00002493{
2494 uint32_t prod[8];
2495 int i;
2496 int sat = 0;
2497
2498 for (i = 0; i < ARRAY_SIZE(r->u16); i++) {
2499 prod[i] = a->u16[i] * b->u16[i];
2500 }
2501
2502 VECTOR_FOR_INORDER_I (i, s32) {
2503 uint64_t t = (uint64_t)c->u32[i] + prod[2*i] + prod[2*i+1];
2504 r->u32[i] = cvtuduw(t, &sat);
2505 }
2506
2507 if (sat) {
2508 env->vscr |= (1 << VSCR_SAT);
2509 }
2510}
2511
aurel322c277902009-01-04 22:08:48 +00002512#define VMUL_DO(name, mul_element, prod_element, evenp) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002513 void helper_v##name (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
aurel322c277902009-01-04 22:08:48 +00002514 { \
2515 int i; \
2516 VECTOR_FOR_INORDER_I(i, prod_element) { \
2517 if (evenp) { \
2518 r->prod_element[i] = a->mul_element[i*2+HI_IDX] * b->mul_element[i*2+HI_IDX]; \
2519 } else { \
2520 r->prod_element[i] = a->mul_element[i*2+LO_IDX] * b->mul_element[i*2+LO_IDX]; \
2521 } \
2522 } \
2523 }
2524#define VMUL(suffix, mul_element, prod_element) \
2525 VMUL_DO(mule##suffix, mul_element, prod_element, 1) \
2526 VMUL_DO(mulo##suffix, mul_element, prod_element, 0)
2527VMUL(sb, s8, s16)
2528VMUL(sh, s16, s32)
2529VMUL(ub, u8, u16)
2530VMUL(uh, u16, u32)
2531#undef VMUL_DO
2532#undef VMUL
2533
Anthony Liguoric227f092009-10-01 16:12:16 -05002534void helper_vnmsubfp (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
aurel3235cf7c72009-02-09 16:48:59 +00002535{
2536 int i;
2537 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2538 HANDLE_NAN3(r->f[i], a->f[i], b->f[i], c->f[i]) {
2539 /* Need to do the computation is higher precision and round
2540 * once at the end. */
2541 float64 af, bf, cf, t;
2542 af = float32_to_float64(a->f[i], &env->vec_status);
2543 bf = float32_to_float64(b->f[i], &env->vec_status);
2544 cf = float32_to_float64(c->f[i], &env->vec_status);
2545 t = float64_mul(af, cf, &env->vec_status);
2546 t = float64_sub(t, bf, &env->vec_status);
2547 t = float64_chs(t);
2548 r->f[i] = float64_to_float32(t, &env->vec_status);
2549 }
2550 }
2551}
2552
Anthony Liguoric227f092009-10-01 16:12:16 -05002553void helper_vperm (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
aurel32d1258692009-01-04 22:11:49 +00002554{
Anthony Liguoric227f092009-10-01 16:12:16 -05002555 ppc_avr_t result;
aurel32d1258692009-01-04 22:11:49 +00002556 int i;
2557 VECTOR_FOR_INORDER_I (i, u8) {
2558 int s = c->u8[i] & 0x1f;
Juan Quintelae2542fe2009-07-27 16:13:06 +02002559#if defined(HOST_WORDS_BIGENDIAN)
aurel32d1258692009-01-04 22:11:49 +00002560 int index = s & 0xf;
2561#else
2562 int index = 15 - (s & 0xf);
2563#endif
2564 if (s & 0x10) {
2565 result.u8[i] = b->u8[index];
2566 } else {
2567 result.u8[i] = a->u8[index];
2568 }
2569 }
2570 *r = result;
2571}
2572
Juan Quintelae2542fe2009-07-27 16:13:06 +02002573#if defined(HOST_WORDS_BIGENDIAN)
aurel325335a142009-01-04 22:12:09 +00002574#define PKBIG 1
2575#else
2576#define PKBIG 0
2577#endif
Anthony Liguoric227f092009-10-01 16:12:16 -05002578void helper_vpkpx (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
aurel321dd9ffb2009-01-04 22:12:19 +00002579{
2580 int i, j;
Anthony Liguoric227f092009-10-01 16:12:16 -05002581 ppc_avr_t result;
Juan Quintelae2542fe2009-07-27 16:13:06 +02002582#if defined(HOST_WORDS_BIGENDIAN)
Anthony Liguoric227f092009-10-01 16:12:16 -05002583 const ppc_avr_t *x[2] = { a, b };
aurel321dd9ffb2009-01-04 22:12:19 +00002584#else
Anthony Liguoric227f092009-10-01 16:12:16 -05002585 const ppc_avr_t *x[2] = { b, a };
aurel321dd9ffb2009-01-04 22:12:19 +00002586#endif
2587
2588 VECTOR_FOR_INORDER_I (i, u64) {
2589 VECTOR_FOR_INORDER_I (j, u32){
2590 uint32_t e = x[i]->u32[j];
2591 result.u16[4*i+j] = (((e >> 9) & 0xfc00) |
2592 ((e >> 6) & 0x3e0) |
2593 ((e >> 3) & 0x1f));
2594 }
2595 }
2596 *r = result;
2597}
2598
aurel325335a142009-01-04 22:12:09 +00002599#define VPK(suffix, from, to, cvt, dosat) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002600 void helper_vpk##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
aurel325335a142009-01-04 22:12:09 +00002601 { \
2602 int i; \
2603 int sat = 0; \
Anthony Liguoric227f092009-10-01 16:12:16 -05002604 ppc_avr_t result; \
2605 ppc_avr_t *a0 = PKBIG ? a : b; \
2606 ppc_avr_t *a1 = PKBIG ? b : a; \
aurel325335a142009-01-04 22:12:09 +00002607 VECTOR_FOR_INORDER_I (i, from) { \
2608 result.to[i] = cvt(a0->from[i], &sat); \
2609 result.to[i+ARRAY_SIZE(r->from)] = cvt(a1->from[i], &sat); \
2610 } \
2611 *r = result; \
2612 if (dosat && sat) { \
2613 env->vscr |= (1 << VSCR_SAT); \
2614 } \
2615 }
2616#define I(x, y) (x)
2617VPK(shss, s16, s8, cvtshsb, 1)
2618VPK(shus, s16, u8, cvtshub, 1)
2619VPK(swss, s32, s16, cvtswsh, 1)
2620VPK(swus, s32, u16, cvtswuh, 1)
2621VPK(uhus, u16, u8, cvtuhub, 1)
2622VPK(uwus, u32, u16, cvtuwuh, 1)
2623VPK(uhum, u16, u8, I, 0)
2624VPK(uwum, u32, u16, I, 0)
2625#undef I
2626#undef VPK
2627#undef PKBIG
2628
Anthony Liguoric227f092009-10-01 16:12:16 -05002629void helper_vrefp (ppc_avr_t *r, ppc_avr_t *b)
aurel32bdfbac32009-02-09 16:49:29 +00002630{
2631 int i;
2632 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2633 HANDLE_NAN1(r->f[i], b->f[i]) {
2634 r->f[i] = float32_div(float32_one, b->f[i], &env->vec_status);
2635 }
2636 }
2637}
2638
aurel32f6b19642009-02-04 13:52:03 +00002639#define VRFI(suffix, rounding) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002640 void helper_vrfi##suffix (ppc_avr_t *r, ppc_avr_t *b) \
aurel32f6b19642009-02-04 13:52:03 +00002641 { \
2642 int i; \
2643 float_status s = env->vec_status; \
2644 set_float_rounding_mode(rounding, &s); \
2645 for (i = 0; i < ARRAY_SIZE(r->f); i++) { \
2646 HANDLE_NAN1(r->f[i], b->f[i]) { \
2647 r->f[i] = float32_round_to_int (b->f[i], &s); \
2648 } \
2649 } \
2650 }
2651VRFI(n, float_round_nearest_even)
2652VRFI(m, float_round_down)
2653VRFI(p, float_round_up)
2654VRFI(z, float_round_to_zero)
2655#undef VRFI
2656
aurel325e1d0982009-01-04 22:09:52 +00002657#define VROTATE(suffix, element) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002658 void helper_vrl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
aurel325e1d0982009-01-04 22:09:52 +00002659 { \
2660 int i; \
2661 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2662 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2663 unsigned int shift = b->element[i] & mask; \
2664 r->element[i] = (a->element[i] << shift) | (a->element[i] >> (sizeof(a->element[0]) * 8 - shift)); \
2665 } \
2666 }
2667VROTATE(b, u8)
2668VROTATE(h, u16)
2669VROTATE(w, u32)
2670#undef VROTATE
2671
Anthony Liguoric227f092009-10-01 16:12:16 -05002672void helper_vrsqrtefp (ppc_avr_t *r, ppc_avr_t *b)
aurel32071fc3b2009-02-09 16:49:40 +00002673{
2674 int i;
2675 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2676 HANDLE_NAN1(r->f[i], b->f[i]) {
2677 float32 t = float32_sqrt(b->f[i], &env->vec_status);
2678 r->f[i] = float32_div(float32_one, t, &env->vec_status);
2679 }
2680 }
2681}
2682
Anthony Liguoric227f092009-10-01 16:12:16 -05002683void helper_vsel (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, ppc_avr_t *c)
aurel32d1258692009-01-04 22:11:49 +00002684{
2685 r->u64[0] = (a->u64[0] & ~c->u64[0]) | (b->u64[0] & c->u64[0]);
2686 r->u64[1] = (a->u64[1] & ~c->u64[1]) | (b->u64[1] & c->u64[1]);
2687}
2688
Aurelien Jarno0bffbc62009-02-09 12:20:50 +01002689void helper_vexptefp (ppc_avr_t *r, ppc_avr_t *b)
2690{
2691 int i;
2692 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2693 HANDLE_NAN1(r->f[i], b->f[i]) {
2694 r->f[i] = float32_exp2(b->f[i], &env->vec_status);
2695 }
2696 }
2697}
2698
Anthony Liguoric227f092009-10-01 16:12:16 -05002699void helper_vlogefp (ppc_avr_t *r, ppc_avr_t *b)
aurel32f586ce02009-02-05 13:42:57 +00002700{
2701 int i;
2702 for (i = 0; i < ARRAY_SIZE(r->f); i++) {
2703 HANDLE_NAN1(r->f[i], b->f[i]) {
2704 r->f[i] = float32_log2(b->f[i], &env->vec_status);
2705 }
2706 }
2707}
2708
Juan Quintelae2542fe2009-07-27 16:13:06 +02002709#if defined(HOST_WORDS_BIGENDIAN)
aurel32d9430ad2009-01-08 18:54:48 +00002710#define LEFT 0
2711#define RIGHT 1
2712#else
2713#define LEFT 1
2714#define RIGHT 0
2715#endif
2716/* The specification says that the results are undefined if all of the
2717 * shift counts are not identical. We check to make sure that they are
2718 * to conform to what real hardware appears to do. */
2719#define VSHIFT(suffix, leftp) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002720 void helper_vs##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
aurel32d9430ad2009-01-08 18:54:48 +00002721 { \
malc1481e162009-05-13 15:18:48 +04002722 int shift = b->u8[LO_IDX*15] & 0x7; \
aurel32d9430ad2009-01-08 18:54:48 +00002723 int doit = 1; \
2724 int i; \
2725 for (i = 0; i < ARRAY_SIZE(r->u8); i++) { \
2726 doit = doit && ((b->u8[i] & 0x7) == shift); \
2727 } \
2728 if (doit) { \
2729 if (shift == 0) { \
2730 *r = *a; \
2731 } else if (leftp) { \
2732 uint64_t carry = a->u64[LO_IDX] >> (64 - shift); \
2733 r->u64[HI_IDX] = (a->u64[HI_IDX] << shift) | carry; \
2734 r->u64[LO_IDX] = a->u64[LO_IDX] << shift; \
2735 } else { \
2736 uint64_t carry = a->u64[HI_IDX] << (64 - shift); \
2737 r->u64[LO_IDX] = (a->u64[LO_IDX] >> shift) | carry; \
2738 r->u64[HI_IDX] = a->u64[HI_IDX] >> shift; \
2739 } \
2740 } \
2741 }
2742VSHIFT(l, LEFT)
2743VSHIFT(r, RIGHT)
2744#undef VSHIFT
2745#undef LEFT
2746#undef RIGHT
2747
aurel32d79f0802009-01-04 22:09:08 +00002748#define VSL(suffix, element) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002749 void helper_vsl##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
aurel32d79f0802009-01-04 22:09:08 +00002750 { \
2751 int i; \
2752 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2753 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2754 unsigned int shift = b->element[i] & mask; \
2755 r->element[i] = a->element[i] << shift; \
2756 } \
2757 }
2758VSL(b, u8)
2759VSL(h, u16)
2760VSL(w, u32)
2761#undef VSL
2762
Anthony Liguoric227f092009-10-01 16:12:16 -05002763void helper_vsldoi (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b, uint32_t shift)
aurel32cd633b12009-01-04 22:10:09 +00002764{
2765 int sh = shift & 0xf;
2766 int i;
Anthony Liguoric227f092009-10-01 16:12:16 -05002767 ppc_avr_t result;
aurel32cd633b12009-01-04 22:10:09 +00002768
Juan Quintelae2542fe2009-07-27 16:13:06 +02002769#if defined(HOST_WORDS_BIGENDIAN)
aurel32cd633b12009-01-04 22:10:09 +00002770 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2771 int index = sh + i;
2772 if (index > 0xf) {
2773 result.u8[i] = b->u8[index-0x10];
2774 } else {
2775 result.u8[i] = a->u8[index];
2776 }
2777 }
2778#else
2779 for (i = 0; i < ARRAY_SIZE(r->u8); i++) {
2780 int index = (16 - sh) + i;
2781 if (index > 0xf) {
2782 result.u8[i] = a->u8[index-0x10];
2783 } else {
2784 result.u8[i] = b->u8[index];
2785 }
2786 }
2787#endif
2788 *r = result;
2789}
2790
Anthony Liguoric227f092009-10-01 16:12:16 -05002791void helper_vslo (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
aurel327b239be2009-01-04 22:09:19 +00002792{
2793 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2794
Juan Quintelae2542fe2009-07-27 16:13:06 +02002795#if defined (HOST_WORDS_BIGENDIAN)
aurel327b239be2009-01-04 22:09:19 +00002796 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2797 memset (&r->u8[16-sh], 0, sh);
2798#else
2799 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2800 memset (&r->u8[0], 0, sh);
2801#endif
2802}
2803
aurel32e4e6bee2009-01-04 22:10:49 +00002804/* Experimental testing shows that hardware masks the immediate. */
2805#define _SPLAT_MASKED(element) (splat & (ARRAY_SIZE(r->element) - 1))
Juan Quintelae2542fe2009-07-27 16:13:06 +02002806#if defined(HOST_WORDS_BIGENDIAN)
aurel32e4e6bee2009-01-04 22:10:49 +00002807#define SPLAT_ELEMENT(element) _SPLAT_MASKED(element)
2808#else
2809#define SPLAT_ELEMENT(element) (ARRAY_SIZE(r->element)-1 - _SPLAT_MASKED(element))
2810#endif
2811#define VSPLT(suffix, element) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002812 void helper_vsplt##suffix (ppc_avr_t *r, ppc_avr_t *b, uint32_t splat) \
aurel32e4e6bee2009-01-04 22:10:49 +00002813 { \
2814 uint32_t s = b->element[SPLAT_ELEMENT(element)]; \
2815 int i; \
2816 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2817 r->element[i] = s; \
2818 } \
2819 }
2820VSPLT(b, u8)
2821VSPLT(h, u16)
2822VSPLT(w, u32)
2823#undef VSPLT
2824#undef SPLAT_ELEMENT
2825#undef _SPLAT_MASKED
2826
aurel32c0267662009-01-08 18:54:57 +00002827#define VSPLTI(suffix, element, splat_type) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002828 void helper_vspltis##suffix (ppc_avr_t *r, uint32_t splat) \
aurel32c0267662009-01-08 18:54:57 +00002829 { \
2830 splat_type x = (int8_t)(splat << 3) >> 3; \
2831 int i; \
2832 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2833 r->element[i] = x; \
2834 } \
2835 }
2836VSPLTI(b, s8, int8_t)
2837VSPLTI(h, s16, int16_t)
2838VSPLTI(w, s32, int32_t)
2839#undef VSPLTI
2840
aurel3207ef34c2009-01-04 22:08:58 +00002841#define VSR(suffix, element) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002842 void helper_vsr##suffix (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b) \
aurel3207ef34c2009-01-04 22:08:58 +00002843 { \
2844 int i; \
2845 for (i = 0; i < ARRAY_SIZE(r->element); i++) { \
2846 unsigned int mask = ((1 << (3 + (sizeof (a->element[0]) >> 1))) - 1); \
2847 unsigned int shift = b->element[i] & mask; \
2848 r->element[i] = a->element[i] >> shift; \
2849 } \
2850 }
2851VSR(ab, s8)
2852VSR(ah, s16)
2853VSR(aw, s32)
2854VSR(b, u8)
2855VSR(h, u16)
2856VSR(w, u32)
2857#undef VSR
2858
Anthony Liguoric227f092009-10-01 16:12:16 -05002859void helper_vsro (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
aurel327b239be2009-01-04 22:09:19 +00002860{
2861 int sh = (b->u8[LO_IDX*0xf] >> 3) & 0xf;
2862
Juan Quintelae2542fe2009-07-27 16:13:06 +02002863#if defined (HOST_WORDS_BIGENDIAN)
aurel327b239be2009-01-04 22:09:19 +00002864 memmove (&r->u8[sh], &a->u8[0], 16-sh);
2865 memset (&r->u8[0], 0, sh);
2866#else
2867 memmove (&r->u8[0], &a->u8[sh], 16-sh);
2868 memset (&r->u8[16-sh], 0, sh);
2869#endif
2870}
2871
Anthony Liguoric227f092009-10-01 16:12:16 -05002872void helper_vsubcuw (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
aurel32e343da72009-01-04 22:09:31 +00002873{
2874 int i;
2875 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2876 r->u32[i] = a->u32[i] >= b->u32[i];
2877 }
2878}
2879
Anthony Liguoric227f092009-10-01 16:12:16 -05002880void helper_vsumsws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
aurel328142cdd2009-01-04 22:13:21 +00002881{
2882 int64_t t;
2883 int i, upper;
Anthony Liguoric227f092009-10-01 16:12:16 -05002884 ppc_avr_t result;
aurel328142cdd2009-01-04 22:13:21 +00002885 int sat = 0;
2886
Juan Quintelae2542fe2009-07-27 16:13:06 +02002887#if defined(HOST_WORDS_BIGENDIAN)
aurel328142cdd2009-01-04 22:13:21 +00002888 upper = ARRAY_SIZE(r->s32)-1;
2889#else
2890 upper = 0;
2891#endif
2892 t = (int64_t)b->s32[upper];
2893 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2894 t += a->s32[i];
2895 result.s32[i] = 0;
2896 }
2897 result.s32[upper] = cvtsdsw(t, &sat);
2898 *r = result;
2899
2900 if (sat) {
2901 env->vscr |= (1 << VSCR_SAT);
2902 }
2903}
2904
Anthony Liguoric227f092009-10-01 16:12:16 -05002905void helper_vsum2sws (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
aurel328142cdd2009-01-04 22:13:21 +00002906{
2907 int i, j, upper;
Anthony Liguoric227f092009-10-01 16:12:16 -05002908 ppc_avr_t result;
aurel328142cdd2009-01-04 22:13:21 +00002909 int sat = 0;
2910
Juan Quintelae2542fe2009-07-27 16:13:06 +02002911#if defined(HOST_WORDS_BIGENDIAN)
aurel328142cdd2009-01-04 22:13:21 +00002912 upper = 1;
2913#else
2914 upper = 0;
2915#endif
2916 for (i = 0; i < ARRAY_SIZE(r->u64); i++) {
2917 int64_t t = (int64_t)b->s32[upper+i*2];
2918 result.u64[i] = 0;
2919 for (j = 0; j < ARRAY_SIZE(r->u64); j++) {
2920 t += a->s32[2*i+j];
2921 }
2922 result.s32[upper+i*2] = cvtsdsw(t, &sat);
2923 }
2924
2925 *r = result;
2926 if (sat) {
2927 env->vscr |= (1 << VSCR_SAT);
2928 }
2929}
2930
Anthony Liguoric227f092009-10-01 16:12:16 -05002931void helper_vsum4sbs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
aurel328142cdd2009-01-04 22:13:21 +00002932{
2933 int i, j;
2934 int sat = 0;
2935
2936 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2937 int64_t t = (int64_t)b->s32[i];
2938 for (j = 0; j < ARRAY_SIZE(r->s32); j++) {
2939 t += a->s8[4*i+j];
2940 }
2941 r->s32[i] = cvtsdsw(t, &sat);
2942 }
2943
2944 if (sat) {
2945 env->vscr |= (1 << VSCR_SAT);
2946 }
2947}
2948
Anthony Liguoric227f092009-10-01 16:12:16 -05002949void helper_vsum4shs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
aurel328142cdd2009-01-04 22:13:21 +00002950{
2951 int sat = 0;
2952 int i;
2953
2954 for (i = 0; i < ARRAY_SIZE(r->s32); i++) {
2955 int64_t t = (int64_t)b->s32[i];
2956 t += a->s16[2*i] + a->s16[2*i+1];
2957 r->s32[i] = cvtsdsw(t, &sat);
2958 }
2959
2960 if (sat) {
2961 env->vscr |= (1 << VSCR_SAT);
2962 }
2963}
2964
Anthony Liguoric227f092009-10-01 16:12:16 -05002965void helper_vsum4ubs (ppc_avr_t *r, ppc_avr_t *a, ppc_avr_t *b)
aurel328142cdd2009-01-04 22:13:21 +00002966{
2967 int i, j;
2968 int sat = 0;
2969
2970 for (i = 0; i < ARRAY_SIZE(r->u32); i++) {
2971 uint64_t t = (uint64_t)b->u32[i];
2972 for (j = 0; j < ARRAY_SIZE(r->u32); j++) {
2973 t += a->u8[4*i+j];
2974 }
2975 r->u32[i] = cvtuduw(t, &sat);
2976 }
2977
2978 if (sat) {
2979 env->vscr |= (1 << VSCR_SAT);
2980 }
2981}
2982
Juan Quintelae2542fe2009-07-27 16:13:06 +02002983#if defined(HOST_WORDS_BIGENDIAN)
aurel3279f85c32009-01-04 22:11:10 +00002984#define UPKHI 1
2985#define UPKLO 0
2986#else
2987#define UPKHI 0
2988#define UPKLO 1
2989#endif
2990#define VUPKPX(suffix, hi) \
Anthony Liguoric227f092009-10-01 16:12:16 -05002991 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
aurel3279f85c32009-01-04 22:11:10 +00002992 { \
2993 int i; \
Anthony Liguoric227f092009-10-01 16:12:16 -05002994 ppc_avr_t result; \
aurel3279f85c32009-01-04 22:11:10 +00002995 for (i = 0; i < ARRAY_SIZE(r->u32); i++) { \
2996 uint16_t e = b->u16[hi ? i : i+4]; \
2997 uint8_t a = (e >> 15) ? 0xff : 0; \
2998 uint8_t r = (e >> 10) & 0x1f; \
2999 uint8_t g = (e >> 5) & 0x1f; \
3000 uint8_t b = e & 0x1f; \
3001 result.u32[i] = (a << 24) | (r << 16) | (g << 8) | b; \
3002 } \
3003 *r = result; \
3004 }
3005VUPKPX(lpx, UPKLO)
3006VUPKPX(hpx, UPKHI)
3007#undef VUPKPX
3008
aurel326cf1c6e2009-01-04 22:11:20 +00003009#define VUPK(suffix, unpacked, packee, hi) \
Anthony Liguoric227f092009-10-01 16:12:16 -05003010 void helper_vupk##suffix (ppc_avr_t *r, ppc_avr_t *b) \
aurel326cf1c6e2009-01-04 22:11:20 +00003011 { \
3012 int i; \
Anthony Liguoric227f092009-10-01 16:12:16 -05003013 ppc_avr_t result; \
aurel326cf1c6e2009-01-04 22:11:20 +00003014 if (hi) { \
3015 for (i = 0; i < ARRAY_SIZE(r->unpacked); i++) { \
3016 result.unpacked[i] = b->packee[i]; \
3017 } \
3018 } else { \
3019 for (i = ARRAY_SIZE(r->unpacked); i < ARRAY_SIZE(r->packee); i++) { \
3020 result.unpacked[i-ARRAY_SIZE(r->unpacked)] = b->packee[i]; \
3021 } \
3022 } \
3023 *r = result; \
3024 }
3025VUPK(hsb, s16, s8, UPKHI)
3026VUPK(hsh, s32, s16, UPKHI)
3027VUPK(lsb, s16, s8, UPKLO)
3028VUPK(lsh, s32, s16, UPKLO)
3029#undef VUPK
aurel3279f85c32009-01-04 22:11:10 +00003030#undef UPKHI
3031#undef UPKLO
3032
aurel3234ba2852009-02-04 09:05:53 +00003033#undef DO_HANDLE_NAN
3034#undef HANDLE_NAN1
3035#undef HANDLE_NAN2
3036#undef HANDLE_NAN3
aurel32d6a46fe2009-01-03 13:31:19 +00003037#undef VECTOR_FOR_INORDER_I
3038#undef HI_IDX
3039#undef LO_IDX
3040
3041/*****************************************************************************/
j_mayer0487d6a2007-03-20 22:11:31 +00003042/* SPE extension helpers */
3043/* Use a table to make this quicker */
3044static uint8_t hbrev[16] = {
3045 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
3046 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
3047};
3048
Blue Swirl636aa202009-08-16 09:06:54 +00003049static inline uint8_t byte_reverse(uint8_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003050{
3051 return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
3052}
3053
Blue Swirl636aa202009-08-16 09:06:54 +00003054static inline uint32_t word_reverse(uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003055{
3056 return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
3057 (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
3058}
3059
j_mayer3cd7d1d2007-11-12 01:56:18 +00003060#define MASKBITS 16 // Random value - to be fixed (implementation dependant)
aurel3257951c22008-11-10 11:10:23 +00003061target_ulong helper_brinc (target_ulong arg1, target_ulong arg2)
j_mayer0487d6a2007-03-20 22:11:31 +00003062{
3063 uint32_t a, b, d, mask;
3064
j_mayer3cd7d1d2007-11-12 01:56:18 +00003065 mask = UINT32_MAX >> (32 - MASKBITS);
aurel3257951c22008-11-10 11:10:23 +00003066 a = arg1 & mask;
3067 b = arg2 & mask;
j_mayer3cd7d1d2007-11-12 01:56:18 +00003068 d = word_reverse(1 + word_reverse(a | ~b));
aurel3257951c22008-11-10 11:10:23 +00003069 return (arg1 & ~mask) | (d & b);
j_mayer0487d6a2007-03-20 22:11:31 +00003070}
3071
aurel3257951c22008-11-10 11:10:23 +00003072uint32_t helper_cntlsw32 (uint32_t val)
3073{
3074 if (val & 0x80000000)
3075 return clz32(~val);
3076 else
3077 return clz32(val);
3078}
3079
3080uint32_t helper_cntlzw32 (uint32_t val)
3081{
3082 return clz32(val);
j_mayer0487d6a2007-03-20 22:11:31 +00003083}
3084
aurel321c978562008-11-23 10:54:04 +00003085/* Single-precision floating-point conversions */
Blue Swirl636aa202009-08-16 09:06:54 +00003086static inline uint32_t efscfsi(uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003087{
aurel320ca9d382008-03-13 19:19:16 +00003088 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003089
aurel32fbd265b2009-02-03 19:55:51 +00003090 u.f = int32_to_float32(val, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003091
aurel320ca9d382008-03-13 19:19:16 +00003092 return u.l;
j_mayer0487d6a2007-03-20 22:11:31 +00003093}
3094
Blue Swirl636aa202009-08-16 09:06:54 +00003095static inline uint32_t efscfui(uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003096{
aurel320ca9d382008-03-13 19:19:16 +00003097 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003098
aurel32fbd265b2009-02-03 19:55:51 +00003099 u.f = uint32_to_float32(val, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003100
aurel320ca9d382008-03-13 19:19:16 +00003101 return u.l;
j_mayer0487d6a2007-03-20 22:11:31 +00003102}
3103
Blue Swirl636aa202009-08-16 09:06:54 +00003104static inline int32_t efsctsi(uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003105{
aurel320ca9d382008-03-13 19:19:16 +00003106 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003107
aurel320ca9d382008-03-13 19:19:16 +00003108 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003109 /* NaN are not treated the same way IEEE 754 does */
Peter Maydell18569872010-12-17 15:56:06 +00003110 if (unlikely(float32_is_quiet_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00003111 return 0;
3112
aurel32fbd265b2009-02-03 19:55:51 +00003113 return float32_to_int32(u.f, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003114}
3115
Blue Swirl636aa202009-08-16 09:06:54 +00003116static inline uint32_t efsctui(uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003117{
aurel320ca9d382008-03-13 19:19:16 +00003118 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003119
aurel320ca9d382008-03-13 19:19:16 +00003120 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003121 /* NaN are not treated the same way IEEE 754 does */
Peter Maydell18569872010-12-17 15:56:06 +00003122 if (unlikely(float32_is_quiet_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00003123 return 0;
3124
aurel32fbd265b2009-02-03 19:55:51 +00003125 return float32_to_uint32(u.f, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003126}
3127
Blue Swirl636aa202009-08-16 09:06:54 +00003128static inline uint32_t efsctsiz(uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003129{
aurel320ca9d382008-03-13 19:19:16 +00003130 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003131
aurel320ca9d382008-03-13 19:19:16 +00003132 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003133 /* NaN are not treated the same way IEEE 754 does */
Peter Maydell18569872010-12-17 15:56:06 +00003134 if (unlikely(float32_is_quiet_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00003135 return 0;
3136
aurel32fbd265b2009-02-03 19:55:51 +00003137 return float32_to_int32_round_to_zero(u.f, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003138}
3139
Blue Swirl636aa202009-08-16 09:06:54 +00003140static inline uint32_t efsctuiz(uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003141{
aurel320ca9d382008-03-13 19:19:16 +00003142 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003143
aurel320ca9d382008-03-13 19:19:16 +00003144 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003145 /* NaN are not treated the same way IEEE 754 does */
Peter Maydell18569872010-12-17 15:56:06 +00003146 if (unlikely(float32_is_quiet_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00003147 return 0;
3148
aurel32fbd265b2009-02-03 19:55:51 +00003149 return float32_to_uint32_round_to_zero(u.f, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003150}
3151
Blue Swirl636aa202009-08-16 09:06:54 +00003152static inline uint32_t efscfsf(uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003153{
aurel320ca9d382008-03-13 19:19:16 +00003154 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003155 float32 tmp;
3156
aurel32fbd265b2009-02-03 19:55:51 +00003157 u.f = int32_to_float32(val, &env->vec_status);
3158 tmp = int64_to_float32(1ULL << 32, &env->vec_status);
3159 u.f = float32_div(u.f, tmp, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003160
aurel320ca9d382008-03-13 19:19:16 +00003161 return u.l;
j_mayer0487d6a2007-03-20 22:11:31 +00003162}
3163
Blue Swirl636aa202009-08-16 09:06:54 +00003164static inline uint32_t efscfuf(uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003165{
aurel320ca9d382008-03-13 19:19:16 +00003166 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003167 float32 tmp;
3168
aurel32fbd265b2009-02-03 19:55:51 +00003169 u.f = uint32_to_float32(val, &env->vec_status);
3170 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3171 u.f = float32_div(u.f, tmp, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003172
aurel320ca9d382008-03-13 19:19:16 +00003173 return u.l;
j_mayer0487d6a2007-03-20 22:11:31 +00003174}
3175
Blue Swirl636aa202009-08-16 09:06:54 +00003176static inline uint32_t efsctsf(uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003177{
aurel320ca9d382008-03-13 19:19:16 +00003178 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003179 float32 tmp;
3180
aurel320ca9d382008-03-13 19:19:16 +00003181 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003182 /* NaN are not treated the same way IEEE 754 does */
Peter Maydell18569872010-12-17 15:56:06 +00003183 if (unlikely(float32_is_quiet_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00003184 return 0;
aurel32fbd265b2009-02-03 19:55:51 +00003185 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3186 u.f = float32_mul(u.f, tmp, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003187
aurel32fbd265b2009-02-03 19:55:51 +00003188 return float32_to_int32(u.f, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003189}
3190
Blue Swirl636aa202009-08-16 09:06:54 +00003191static inline uint32_t efsctuf(uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003192{
aurel320ca9d382008-03-13 19:19:16 +00003193 CPU_FloatU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003194 float32 tmp;
3195
aurel320ca9d382008-03-13 19:19:16 +00003196 u.l = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003197 /* NaN are not treated the same way IEEE 754 does */
Peter Maydell18569872010-12-17 15:56:06 +00003198 if (unlikely(float32_is_quiet_nan(u.f)))
j_mayer0487d6a2007-03-20 22:11:31 +00003199 return 0;
aurel32fbd265b2009-02-03 19:55:51 +00003200 tmp = uint64_to_float32(1ULL << 32, &env->vec_status);
3201 u.f = float32_mul(u.f, tmp, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003202
aurel32fbd265b2009-02-03 19:55:51 +00003203 return float32_to_uint32(u.f, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003204}
3205
aurel321c978562008-11-23 10:54:04 +00003206#define HELPER_SPE_SINGLE_CONV(name) \
3207uint32_t helper_e##name (uint32_t val) \
3208{ \
3209 return e##name(val); \
3210}
3211/* efscfsi */
3212HELPER_SPE_SINGLE_CONV(fscfsi);
3213/* efscfui */
3214HELPER_SPE_SINGLE_CONV(fscfui);
3215/* efscfuf */
3216HELPER_SPE_SINGLE_CONV(fscfuf);
3217/* efscfsf */
3218HELPER_SPE_SINGLE_CONV(fscfsf);
3219/* efsctsi */
3220HELPER_SPE_SINGLE_CONV(fsctsi);
3221/* efsctui */
3222HELPER_SPE_SINGLE_CONV(fsctui);
3223/* efsctsiz */
3224HELPER_SPE_SINGLE_CONV(fsctsiz);
3225/* efsctuiz */
3226HELPER_SPE_SINGLE_CONV(fsctuiz);
3227/* efsctsf */
3228HELPER_SPE_SINGLE_CONV(fsctsf);
3229/* efsctuf */
3230HELPER_SPE_SINGLE_CONV(fsctuf);
3231
3232#define HELPER_SPE_VECTOR_CONV(name) \
3233uint64_t helper_ev##name (uint64_t val) \
3234{ \
3235 return ((uint64_t)e##name(val >> 32) << 32) | \
3236 (uint64_t)e##name(val); \
3237}
3238/* evfscfsi */
3239HELPER_SPE_VECTOR_CONV(fscfsi);
3240/* evfscfui */
3241HELPER_SPE_VECTOR_CONV(fscfui);
3242/* evfscfuf */
3243HELPER_SPE_VECTOR_CONV(fscfuf);
3244/* evfscfsf */
3245HELPER_SPE_VECTOR_CONV(fscfsf);
3246/* evfsctsi */
3247HELPER_SPE_VECTOR_CONV(fsctsi);
3248/* evfsctui */
3249HELPER_SPE_VECTOR_CONV(fsctui);
3250/* evfsctsiz */
3251HELPER_SPE_VECTOR_CONV(fsctsiz);
3252/* evfsctuiz */
3253HELPER_SPE_VECTOR_CONV(fsctuiz);
3254/* evfsctsf */
3255HELPER_SPE_VECTOR_CONV(fsctsf);
3256/* evfsctuf */
3257HELPER_SPE_VECTOR_CONV(fsctuf);
3258
3259/* Single-precision floating-point arithmetic */
Blue Swirl636aa202009-08-16 09:06:54 +00003260static inline uint32_t efsadd(uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003261{
aurel321c978562008-11-23 10:54:04 +00003262 CPU_FloatU u1, u2;
3263 u1.l = op1;
3264 u2.l = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003265 u1.f = float32_add(u1.f, u2.f, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003266 return u1.l;
j_mayer0487d6a2007-03-20 22:11:31 +00003267}
3268
Blue Swirl636aa202009-08-16 09:06:54 +00003269static inline uint32_t efssub(uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003270{
aurel321c978562008-11-23 10:54:04 +00003271 CPU_FloatU u1, u2;
3272 u1.l = op1;
3273 u2.l = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003274 u1.f = float32_sub(u1.f, u2.f, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003275 return u1.l;
j_mayer0487d6a2007-03-20 22:11:31 +00003276}
3277
Blue Swirl636aa202009-08-16 09:06:54 +00003278static inline uint32_t efsmul(uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003279{
aurel321c978562008-11-23 10:54:04 +00003280 CPU_FloatU u1, u2;
3281 u1.l = op1;
3282 u2.l = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003283 u1.f = float32_mul(u1.f, u2.f, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003284 return u1.l;
j_mayer0487d6a2007-03-20 22:11:31 +00003285}
3286
Blue Swirl636aa202009-08-16 09:06:54 +00003287static inline uint32_t efsdiv(uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003288{
aurel321c978562008-11-23 10:54:04 +00003289 CPU_FloatU u1, u2;
3290 u1.l = op1;
3291 u2.l = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003292 u1.f = float32_div(u1.f, u2.f, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003293 return u1.l;
j_mayer0487d6a2007-03-20 22:11:31 +00003294}
3295
aurel321c978562008-11-23 10:54:04 +00003296#define HELPER_SPE_SINGLE_ARITH(name) \
3297uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
3298{ \
3299 return e##name(op1, op2); \
3300}
3301/* efsadd */
3302HELPER_SPE_SINGLE_ARITH(fsadd);
3303/* efssub */
3304HELPER_SPE_SINGLE_ARITH(fssub);
3305/* efsmul */
3306HELPER_SPE_SINGLE_ARITH(fsmul);
3307/* efsdiv */
3308HELPER_SPE_SINGLE_ARITH(fsdiv);
3309
3310#define HELPER_SPE_VECTOR_ARITH(name) \
3311uint64_t helper_ev##name (uint64_t op1, uint64_t op2) \
3312{ \
3313 return ((uint64_t)e##name(op1 >> 32, op2 >> 32) << 32) | \
3314 (uint64_t)e##name(op1, op2); \
3315}
3316/* evfsadd */
3317HELPER_SPE_VECTOR_ARITH(fsadd);
3318/* evfssub */
3319HELPER_SPE_VECTOR_ARITH(fssub);
3320/* evfsmul */
3321HELPER_SPE_VECTOR_ARITH(fsmul);
3322/* evfsdiv */
3323HELPER_SPE_VECTOR_ARITH(fsdiv);
3324
3325/* Single-precision floating-point comparisons */
Blue Swirl636aa202009-08-16 09:06:54 +00003326static inline uint32_t efststlt(uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003327{
aurel321c978562008-11-23 10:54:04 +00003328 CPU_FloatU u1, u2;
3329 u1.l = op1;
3330 u2.l = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003331 return float32_lt(u1.f, u2.f, &env->vec_status) ? 4 : 0;
j_mayer0487d6a2007-03-20 22:11:31 +00003332}
3333
Blue Swirl636aa202009-08-16 09:06:54 +00003334static inline uint32_t efststgt(uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003335{
aurel321c978562008-11-23 10:54:04 +00003336 CPU_FloatU u1, u2;
3337 u1.l = op1;
3338 u2.l = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003339 return float32_le(u1.f, u2.f, &env->vec_status) ? 0 : 4;
j_mayer0487d6a2007-03-20 22:11:31 +00003340}
3341
Blue Swirl636aa202009-08-16 09:06:54 +00003342static inline uint32_t efststeq(uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003343{
aurel321c978562008-11-23 10:54:04 +00003344 CPU_FloatU u1, u2;
3345 u1.l = op1;
3346 u2.l = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003347 return float32_eq(u1.f, u2.f, &env->vec_status) ? 4 : 0;
j_mayer0487d6a2007-03-20 22:11:31 +00003348}
3349
Blue Swirl636aa202009-08-16 09:06:54 +00003350static inline uint32_t efscmplt(uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003351{
3352 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00003353 return efststlt(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00003354}
3355
Blue Swirl636aa202009-08-16 09:06:54 +00003356static inline uint32_t efscmpgt(uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003357{
3358 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00003359 return efststgt(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00003360}
3361
Blue Swirl636aa202009-08-16 09:06:54 +00003362static inline uint32_t efscmpeq(uint32_t op1, uint32_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003363{
3364 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00003365 return efststeq(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00003366}
3367
aurel321c978562008-11-23 10:54:04 +00003368#define HELPER_SINGLE_SPE_CMP(name) \
3369uint32_t helper_e##name (uint32_t op1, uint32_t op2) \
3370{ \
3371 return e##name(op1, op2) << 2; \
3372}
3373/* efststlt */
3374HELPER_SINGLE_SPE_CMP(fststlt);
3375/* efststgt */
3376HELPER_SINGLE_SPE_CMP(fststgt);
3377/* efststeq */
3378HELPER_SINGLE_SPE_CMP(fststeq);
3379/* efscmplt */
3380HELPER_SINGLE_SPE_CMP(fscmplt);
3381/* efscmpgt */
3382HELPER_SINGLE_SPE_CMP(fscmpgt);
3383/* efscmpeq */
3384HELPER_SINGLE_SPE_CMP(fscmpeq);
3385
Blue Swirl636aa202009-08-16 09:06:54 +00003386static inline uint32_t evcmp_merge(int t0, int t1)
j_mayer0487d6a2007-03-20 22:11:31 +00003387{
aurel321c978562008-11-23 10:54:04 +00003388 return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
j_mayer0487d6a2007-03-20 22:11:31 +00003389}
3390
aurel321c978562008-11-23 10:54:04 +00003391#define HELPER_VECTOR_SPE_CMP(name) \
3392uint32_t helper_ev##name (uint64_t op1, uint64_t op2) \
3393{ \
3394 return evcmp_merge(e##name(op1 >> 32, op2 >> 32), e##name(op1, op2)); \
3395}
3396/* evfststlt */
3397HELPER_VECTOR_SPE_CMP(fststlt);
3398/* evfststgt */
3399HELPER_VECTOR_SPE_CMP(fststgt);
3400/* evfststeq */
3401HELPER_VECTOR_SPE_CMP(fststeq);
3402/* evfscmplt */
3403HELPER_VECTOR_SPE_CMP(fscmplt);
3404/* evfscmpgt */
3405HELPER_VECTOR_SPE_CMP(fscmpgt);
3406/* evfscmpeq */
3407HELPER_VECTOR_SPE_CMP(fscmpeq);
3408
3409/* Double-precision floating-point conversion */
3410uint64_t helper_efdcfsi (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003411{
aurel321c978562008-11-23 10:54:04 +00003412 CPU_DoubleU u;
3413
aurel32fbd265b2009-02-03 19:55:51 +00003414 u.d = int32_to_float64(val, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003415
3416 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00003417}
3418
aurel321c978562008-11-23 10:54:04 +00003419uint64_t helper_efdcfsid (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003420{
aurel320ca9d382008-03-13 19:19:16 +00003421 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003422
aurel32fbd265b2009-02-03 19:55:51 +00003423 u.d = int64_to_float64(val, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003424
aurel320ca9d382008-03-13 19:19:16 +00003425 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00003426}
3427
aurel321c978562008-11-23 10:54:04 +00003428uint64_t helper_efdcfui (uint32_t val)
3429{
3430 CPU_DoubleU u;
3431
aurel32fbd265b2009-02-03 19:55:51 +00003432 u.d = uint32_to_float64(val, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003433
3434 return u.ll;
3435}
3436
3437uint64_t helper_efdcfuid (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003438{
aurel320ca9d382008-03-13 19:19:16 +00003439 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003440
aurel32fbd265b2009-02-03 19:55:51 +00003441 u.d = uint64_to_float64(val, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003442
aurel320ca9d382008-03-13 19:19:16 +00003443 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00003444}
3445
aurel321c978562008-11-23 10:54:04 +00003446uint32_t helper_efdctsi (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003447{
aurel320ca9d382008-03-13 19:19:16 +00003448 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003449
aurel320ca9d382008-03-13 19:19:16 +00003450 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003451 /* NaN are not treated the same way IEEE 754 does */
Aurelien Jarnod788b572011-01-17 19:29:33 +01003452 if (unlikely(float64_is_any_nan(u.d))) {
j_mayer0487d6a2007-03-20 22:11:31 +00003453 return 0;
Aurelien Jarnod788b572011-01-17 19:29:33 +01003454 }
j_mayer0487d6a2007-03-20 22:11:31 +00003455
aurel32fbd265b2009-02-03 19:55:51 +00003456 return float64_to_int32(u.d, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003457}
3458
aurel321c978562008-11-23 10:54:04 +00003459uint32_t helper_efdctui (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003460{
aurel320ca9d382008-03-13 19:19:16 +00003461 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003462
aurel320ca9d382008-03-13 19:19:16 +00003463 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003464 /* NaN are not treated the same way IEEE 754 does */
Aurelien Jarnod788b572011-01-17 19:29:33 +01003465 if (unlikely(float64_is_any_nan(u.d))) {
j_mayer0487d6a2007-03-20 22:11:31 +00003466 return 0;
Aurelien Jarnod788b572011-01-17 19:29:33 +01003467 }
j_mayer0487d6a2007-03-20 22:11:31 +00003468
aurel32fbd265b2009-02-03 19:55:51 +00003469 return float64_to_uint32(u.d, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003470}
3471
aurel321c978562008-11-23 10:54:04 +00003472uint32_t helper_efdctsiz (uint64_t val)
3473{
3474 CPU_DoubleU u;
3475
3476 u.ll = val;
3477 /* NaN are not treated the same way IEEE 754 does */
Aurelien Jarnod788b572011-01-17 19:29:33 +01003478 if (unlikely(float64_is_any_nan(u.d))) {
aurel321c978562008-11-23 10:54:04 +00003479 return 0;
Aurelien Jarnod788b572011-01-17 19:29:33 +01003480 }
aurel321c978562008-11-23 10:54:04 +00003481
aurel32fbd265b2009-02-03 19:55:51 +00003482 return float64_to_int32_round_to_zero(u.d, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003483}
3484
3485uint64_t helper_efdctsidz (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003486{
aurel320ca9d382008-03-13 19:19:16 +00003487 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003488
aurel320ca9d382008-03-13 19:19:16 +00003489 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003490 /* NaN are not treated the same way IEEE 754 does */
Aurelien Jarnod788b572011-01-17 19:29:33 +01003491 if (unlikely(float64_is_any_nan(u.d))) {
j_mayer0487d6a2007-03-20 22:11:31 +00003492 return 0;
Aurelien Jarnod788b572011-01-17 19:29:33 +01003493 }
j_mayer0487d6a2007-03-20 22:11:31 +00003494
aurel32fbd265b2009-02-03 19:55:51 +00003495 return float64_to_int64_round_to_zero(u.d, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003496}
3497
aurel321c978562008-11-23 10:54:04 +00003498uint32_t helper_efdctuiz (uint64_t val)
3499{
3500 CPU_DoubleU u;
3501
3502 u.ll = val;
3503 /* NaN are not treated the same way IEEE 754 does */
Aurelien Jarnod788b572011-01-17 19:29:33 +01003504 if (unlikely(float64_is_any_nan(u.d))) {
aurel321c978562008-11-23 10:54:04 +00003505 return 0;
Aurelien Jarnod788b572011-01-17 19:29:33 +01003506 }
aurel321c978562008-11-23 10:54:04 +00003507
aurel32fbd265b2009-02-03 19:55:51 +00003508 return float64_to_uint32_round_to_zero(u.d, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003509}
3510
3511uint64_t helper_efdctuidz (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003512{
aurel320ca9d382008-03-13 19:19:16 +00003513 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003514
aurel320ca9d382008-03-13 19:19:16 +00003515 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003516 /* NaN are not treated the same way IEEE 754 does */
Aurelien Jarnod788b572011-01-17 19:29:33 +01003517 if (unlikely(float64_is_any_nan(u.d))) {
j_mayer0487d6a2007-03-20 22:11:31 +00003518 return 0;
Aurelien Jarnod788b572011-01-17 19:29:33 +01003519 }
j_mayer0487d6a2007-03-20 22:11:31 +00003520
aurel32fbd265b2009-02-03 19:55:51 +00003521 return float64_to_uint64_round_to_zero(u.d, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003522}
3523
aurel321c978562008-11-23 10:54:04 +00003524uint64_t helper_efdcfsf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003525{
aurel320ca9d382008-03-13 19:19:16 +00003526 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003527 float64 tmp;
3528
aurel32fbd265b2009-02-03 19:55:51 +00003529 u.d = int32_to_float64(val, &env->vec_status);
3530 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3531 u.d = float64_div(u.d, tmp, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003532
aurel320ca9d382008-03-13 19:19:16 +00003533 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00003534}
3535
aurel321c978562008-11-23 10:54:04 +00003536uint64_t helper_efdcfuf (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003537{
aurel320ca9d382008-03-13 19:19:16 +00003538 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003539 float64 tmp;
3540
aurel32fbd265b2009-02-03 19:55:51 +00003541 u.d = uint32_to_float64(val, &env->vec_status);
3542 tmp = int64_to_float64(1ULL << 32, &env->vec_status);
3543 u.d = float64_div(u.d, tmp, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003544
aurel320ca9d382008-03-13 19:19:16 +00003545 return u.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00003546}
3547
aurel321c978562008-11-23 10:54:04 +00003548uint32_t helper_efdctsf (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003549{
aurel320ca9d382008-03-13 19:19:16 +00003550 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003551 float64 tmp;
3552
aurel320ca9d382008-03-13 19:19:16 +00003553 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003554 /* NaN are not treated the same way IEEE 754 does */
Aurelien Jarnod788b572011-01-17 19:29:33 +01003555 if (unlikely(float64_is_any_nan(u.d))) {
j_mayer0487d6a2007-03-20 22:11:31 +00003556 return 0;
Aurelien Jarnod788b572011-01-17 19:29:33 +01003557 }
aurel32fbd265b2009-02-03 19:55:51 +00003558 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3559 u.d = float64_mul(u.d, tmp, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003560
aurel32fbd265b2009-02-03 19:55:51 +00003561 return float64_to_int32(u.d, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003562}
3563
aurel321c978562008-11-23 10:54:04 +00003564uint32_t helper_efdctuf (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003565{
aurel320ca9d382008-03-13 19:19:16 +00003566 CPU_DoubleU u;
j_mayer0487d6a2007-03-20 22:11:31 +00003567 float64 tmp;
3568
aurel320ca9d382008-03-13 19:19:16 +00003569 u.ll = val;
j_mayer0487d6a2007-03-20 22:11:31 +00003570 /* NaN are not treated the same way IEEE 754 does */
Aurelien Jarnod788b572011-01-17 19:29:33 +01003571 if (unlikely(float64_is_any_nan(u.d))) {
j_mayer0487d6a2007-03-20 22:11:31 +00003572 return 0;
Aurelien Jarnod788b572011-01-17 19:29:33 +01003573 }
aurel32fbd265b2009-02-03 19:55:51 +00003574 tmp = uint64_to_float64(1ULL << 32, &env->vec_status);
3575 u.d = float64_mul(u.d, tmp, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003576
aurel32fbd265b2009-02-03 19:55:51 +00003577 return float64_to_uint32(u.d, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003578}
3579
aurel321c978562008-11-23 10:54:04 +00003580uint32_t helper_efscfd (uint64_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003581{
aurel320ca9d382008-03-13 19:19:16 +00003582 CPU_DoubleU u1;
3583 CPU_FloatU u2;
j_mayer0487d6a2007-03-20 22:11:31 +00003584
aurel320ca9d382008-03-13 19:19:16 +00003585 u1.ll = val;
aurel32fbd265b2009-02-03 19:55:51 +00003586 u2.f = float64_to_float32(u1.d, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003587
aurel320ca9d382008-03-13 19:19:16 +00003588 return u2.l;
j_mayer0487d6a2007-03-20 22:11:31 +00003589}
3590
aurel321c978562008-11-23 10:54:04 +00003591uint64_t helper_efdcfs (uint32_t val)
j_mayer0487d6a2007-03-20 22:11:31 +00003592{
aurel320ca9d382008-03-13 19:19:16 +00003593 CPU_DoubleU u2;
3594 CPU_FloatU u1;
j_mayer0487d6a2007-03-20 22:11:31 +00003595
aurel320ca9d382008-03-13 19:19:16 +00003596 u1.l = val;
aurel32fbd265b2009-02-03 19:55:51 +00003597 u2.d = float32_to_float64(u1.f, &env->vec_status);
j_mayer0487d6a2007-03-20 22:11:31 +00003598
aurel320ca9d382008-03-13 19:19:16 +00003599 return u2.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00003600}
3601
aurel321c978562008-11-23 10:54:04 +00003602/* Double precision fixed-point arithmetic */
3603uint64_t helper_efdadd (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003604{
aurel321c978562008-11-23 10:54:04 +00003605 CPU_DoubleU u1, u2;
3606 u1.ll = op1;
3607 u2.ll = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003608 u1.d = float64_add(u1.d, u2.d, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003609 return u1.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00003610}
3611
aurel321c978562008-11-23 10:54:04 +00003612uint64_t helper_efdsub (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003613{
aurel321c978562008-11-23 10:54:04 +00003614 CPU_DoubleU u1, u2;
3615 u1.ll = op1;
3616 u2.ll = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003617 u1.d = float64_sub(u1.d, u2.d, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003618 return u1.ll;
j_mayer0487d6a2007-03-20 22:11:31 +00003619}
3620
aurel321c978562008-11-23 10:54:04 +00003621uint64_t helper_efdmul (uint64_t op1, uint64_t op2)
3622{
3623 CPU_DoubleU u1, u2;
3624 u1.ll = op1;
3625 u2.ll = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003626 u1.d = float64_mul(u1.d, u2.d, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003627 return u1.ll;
3628}
j_mayer0487d6a2007-03-20 22:11:31 +00003629
aurel321c978562008-11-23 10:54:04 +00003630uint64_t helper_efddiv (uint64_t op1, uint64_t op2)
3631{
3632 CPU_DoubleU u1, u2;
3633 u1.ll = op1;
3634 u2.ll = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003635 u1.d = float64_div(u1.d, u2.d, &env->vec_status);
aurel321c978562008-11-23 10:54:04 +00003636 return u1.ll;
3637}
3638
3639/* Double precision floating point helpers */
3640uint32_t helper_efdtstlt (uint64_t op1, uint64_t op2)
3641{
3642 CPU_DoubleU u1, u2;
3643 u1.ll = op1;
3644 u2.ll = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003645 return float64_lt(u1.d, u2.d, &env->vec_status) ? 4 : 0;
aurel321c978562008-11-23 10:54:04 +00003646}
3647
3648uint32_t helper_efdtstgt (uint64_t op1, uint64_t op2)
3649{
3650 CPU_DoubleU u1, u2;
3651 u1.ll = op1;
3652 u2.ll = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003653 return float64_le(u1.d, u2.d, &env->vec_status) ? 0 : 4;
aurel321c978562008-11-23 10:54:04 +00003654}
3655
3656uint32_t helper_efdtsteq (uint64_t op1, uint64_t op2)
3657{
3658 CPU_DoubleU u1, u2;
3659 u1.ll = op1;
3660 u2.ll = op2;
aurel32fbd265b2009-02-03 19:55:51 +00003661 return float64_eq(u1.d, u2.d, &env->vec_status) ? 4 : 0;
aurel321c978562008-11-23 10:54:04 +00003662}
3663
3664uint32_t helper_efdcmplt (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003665{
3666 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00003667 return helper_efdtstlt(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00003668}
3669
aurel321c978562008-11-23 10:54:04 +00003670uint32_t helper_efdcmpgt (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003671{
3672 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00003673 return helper_efdtstgt(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00003674}
3675
aurel321c978562008-11-23 10:54:04 +00003676uint32_t helper_efdcmpeq (uint64_t op1, uint64_t op2)
j_mayer0487d6a2007-03-20 22:11:31 +00003677{
3678 /* XXX: TODO: test special values (NaN, infinites, ...) */
aurel321c978562008-11-23 10:54:04 +00003679 return helper_efdtsteq(op1, op2);
j_mayer0487d6a2007-03-20 22:11:31 +00003680}
3681
bellardfdabc362005-07-04 22:17:05 +00003682/*****************************************************************************/
3683/* Softmmu support */
3684#if !defined (CONFIG_USER_ONLY)
3685
3686#define MMUSUFFIX _mmu
bellardfdabc362005-07-04 22:17:05 +00003687
3688#define SHIFT 0
3689#include "softmmu_template.h"
3690
3691#define SHIFT 1
3692#include "softmmu_template.h"
3693
3694#define SHIFT 2
3695#include "softmmu_template.h"
3696
3697#define SHIFT 3
3698#include "softmmu_template.h"
3699
3700/* try to fill the TLB and return an exception if error. If retaddr is
3701 NULL, it means that the function was called in C code (i.e. not
3702 from generated code or from helper.c) */
3703/* XXX: fix it to restore all registers */
j_mayer6ebbf392007-10-14 07:07:08 +00003704void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
bellardfdabc362005-07-04 22:17:05 +00003705{
3706 TranslationBlock *tb;
3707 CPUState *saved_env;
bellard44f86252007-11-11 12:35:55 +00003708 unsigned long pc;
bellardfdabc362005-07-04 22:17:05 +00003709 int ret;
3710
3711 /* XXX: hack to restore env in all cases, even if not called from
3712 generated code */
3713 saved_env = env;
3714 env = cpu_single_env;
j_mayer6ebbf392007-10-14 07:07:08 +00003715 ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
j_mayer76a66252007-03-07 08:32:30 +00003716 if (unlikely(ret != 0)) {
bellardfdabc362005-07-04 22:17:05 +00003717 if (likely(retaddr)) {
3718 /* now we have a real cpu fault */
bellard44f86252007-11-11 12:35:55 +00003719 pc = (unsigned long)retaddr;
bellardfdabc362005-07-04 22:17:05 +00003720 tb = tb_find_pc(pc);
3721 if (likely(tb)) {
3722 /* the PC is inside the translated code. It means that we have
3723 a virtual CPU fault */
3724 cpu_restore_state(tb, env, pc, NULL);
j_mayer76a66252007-03-07 08:32:30 +00003725 }
bellardfdabc362005-07-04 22:17:05 +00003726 }
aurel32e06fcd72008-12-11 22:42:14 +00003727 helper_raise_exception_err(env->exception_index, env->error_code);
bellardfdabc362005-07-04 22:17:05 +00003728 }
3729 env = saved_env;
3730}
bellardfdabc362005-07-04 22:17:05 +00003731
aurel3274d37792008-12-06 21:46:17 +00003732/* Segment registers load and store */
3733target_ulong helper_load_sr (target_ulong sr_num)
3734{
blueswir1f6b868fc2009-03-07 20:50:01 +00003735#if defined(TARGET_PPC64)
3736 if (env->mmu_model & POWERPC_MMU_64)
3737 return ppc_load_sr(env, sr_num);
3738#endif
aurel3274d37792008-12-06 21:46:17 +00003739 return env->sr[sr_num];
3740}
3741
3742void helper_store_sr (target_ulong sr_num, target_ulong val)
3743{
aurel3245d827d2008-12-07 13:40:29 +00003744 ppc_store_sr(env, sr_num, val);
aurel3274d37792008-12-06 21:46:17 +00003745}
3746
3747/* SLB management */
3748#if defined(TARGET_PPC64)
3749target_ulong helper_load_slb (target_ulong slb_nr)
3750{
3751 return ppc_load_slb(env, slb_nr);
3752}
3753
blueswir1f6b868fc2009-03-07 20:50:01 +00003754void helper_store_slb (target_ulong rb, target_ulong rs)
aurel3274d37792008-12-06 21:46:17 +00003755{
blueswir1f6b868fc2009-03-07 20:50:01 +00003756 ppc_store_slb(env, rb, rs);
aurel3274d37792008-12-06 21:46:17 +00003757}
3758
3759void helper_slbia (void)
3760{
3761 ppc_slb_invalidate_all(env);
3762}
3763
3764void helper_slbie (target_ulong addr)
3765{
3766 ppc_slb_invalidate_one(env, addr);
3767}
3768
3769#endif /* defined(TARGET_PPC64) */
3770
3771/* TLB management */
3772void helper_tlbia (void)
3773{
3774 ppc_tlb_invalidate_all(env);
3775}
3776
3777void helper_tlbie (target_ulong addr)
3778{
3779 ppc_tlb_invalidate_one(env, addr);
3780}
3781
j_mayer76a66252007-03-07 08:32:30 +00003782/* Software driven TLBs management */
3783/* PowerPC 602/603 software TLB load instructions helpers */
aurel3274d37792008-12-06 21:46:17 +00003784static void do_6xx_tlb (target_ulong new_EPN, int is_code)
j_mayer76a66252007-03-07 08:32:30 +00003785{
3786 target_ulong RPN, CMP, EPN;
3787 int way;
j_mayerd9bce9d2007-03-17 14:02:15 +00003788
j_mayer76a66252007-03-07 08:32:30 +00003789 RPN = env->spr[SPR_RPA];
3790 if (is_code) {
3791 CMP = env->spr[SPR_ICMP];
3792 EPN = env->spr[SPR_IMISS];
3793 } else {
3794 CMP = env->spr[SPR_DCMP];
3795 EPN = env->spr[SPR_DMISS];
3796 }
3797 way = (env->spr[SPR_SRR1] >> 17) & 1;
Blue Swirl577f25a2010-10-13 18:38:08 +00003798 (void)EPN; /* avoid a compiler warning */
Blue Swirl90e189e2009-08-16 11:13:18 +00003799 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
3800 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
3801 RPN, way);
j_mayer76a66252007-03-07 08:32:30 +00003802 /* Store this TLB */
aurel320f3955e2008-11-30 16:22:56 +00003803 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
j_mayerd9bce9d2007-03-17 14:02:15 +00003804 way, is_code, CMP, RPN);
j_mayer76a66252007-03-07 08:32:30 +00003805}
3806
aurel3274d37792008-12-06 21:46:17 +00003807void helper_6xx_tlbd (target_ulong EPN)
aurel320f3955e2008-11-30 16:22:56 +00003808{
aurel3274d37792008-12-06 21:46:17 +00003809 do_6xx_tlb(EPN, 0);
aurel320f3955e2008-11-30 16:22:56 +00003810}
3811
aurel3274d37792008-12-06 21:46:17 +00003812void helper_6xx_tlbi (target_ulong EPN)
aurel320f3955e2008-11-30 16:22:56 +00003813{
aurel3274d37792008-12-06 21:46:17 +00003814 do_6xx_tlb(EPN, 1);
aurel320f3955e2008-11-30 16:22:56 +00003815}
3816
3817/* PowerPC 74xx software TLB load instructions helpers */
aurel3274d37792008-12-06 21:46:17 +00003818static void do_74xx_tlb (target_ulong new_EPN, int is_code)
j_mayer7dbe11a2007-10-01 05:16:57 +00003819{
3820 target_ulong RPN, CMP, EPN;
3821 int way;
3822
3823 RPN = env->spr[SPR_PTELO];
3824 CMP = env->spr[SPR_PTEHI];
3825 EPN = env->spr[SPR_TLBMISS] & ~0x3;
3826 way = env->spr[SPR_TLBMISS] & 0x3;
Blue Swirl577f25a2010-10-13 18:38:08 +00003827 (void)EPN; /* avoid a compiler warning */
Blue Swirl90e189e2009-08-16 11:13:18 +00003828 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
3829 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
3830 RPN, way);
j_mayer7dbe11a2007-10-01 05:16:57 +00003831 /* Store this TLB */
aurel320f3955e2008-11-30 16:22:56 +00003832 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
j_mayer7dbe11a2007-10-01 05:16:57 +00003833 way, is_code, CMP, RPN);
3834}
3835
aurel3274d37792008-12-06 21:46:17 +00003836void helper_74xx_tlbd (target_ulong EPN)
aurel320f3955e2008-11-30 16:22:56 +00003837{
aurel3274d37792008-12-06 21:46:17 +00003838 do_74xx_tlb(EPN, 0);
aurel320f3955e2008-11-30 16:22:56 +00003839}
3840
aurel3274d37792008-12-06 21:46:17 +00003841void helper_74xx_tlbi (target_ulong EPN)
aurel320f3955e2008-11-30 16:22:56 +00003842{
aurel3274d37792008-12-06 21:46:17 +00003843 do_74xx_tlb(EPN, 1);
aurel320f3955e2008-11-30 16:22:56 +00003844}
3845
Blue Swirl636aa202009-08-16 09:06:54 +00003846static inline target_ulong booke_tlb_to_page_size(int size)
j_mayera8dea122007-03-31 11:33:48 +00003847{
3848 return 1024 << (2 * size);
3849}
3850
Blue Swirl636aa202009-08-16 09:06:54 +00003851static inline int booke_page_size_to_tlb(target_ulong page_size)
j_mayera8dea122007-03-31 11:33:48 +00003852{
3853 int size;
3854
3855 switch (page_size) {
3856 case 0x00000400UL:
3857 size = 0x0;
3858 break;
3859 case 0x00001000UL:
3860 size = 0x1;
3861 break;
3862 case 0x00004000UL:
3863 size = 0x2;
3864 break;
3865 case 0x00010000UL:
3866 size = 0x3;
3867 break;
3868 case 0x00040000UL:
3869 size = 0x4;
3870 break;
3871 case 0x00100000UL:
3872 size = 0x5;
3873 break;
3874 case 0x00400000UL:
3875 size = 0x6;
3876 break;
3877 case 0x01000000UL:
3878 size = 0x7;
3879 break;
3880 case 0x04000000UL:
3881 size = 0x8;
3882 break;
3883 case 0x10000000UL:
3884 size = 0x9;
3885 break;
3886 case 0x40000000UL:
3887 size = 0xA;
3888 break;
3889#if defined (TARGET_PPC64)
3890 case 0x000100000000ULL:
3891 size = 0xB;
3892 break;
3893 case 0x000400000000ULL:
3894 size = 0xC;
3895 break;
3896 case 0x001000000000ULL:
3897 size = 0xD;
3898 break;
3899 case 0x004000000000ULL:
3900 size = 0xE;
3901 break;
3902 case 0x010000000000ULL:
3903 size = 0xF;
3904 break;
3905#endif
3906 default:
3907 size = -1;
3908 break;
3909 }
3910
3911 return size;
3912}
3913
j_mayer76a66252007-03-07 08:32:30 +00003914/* Helpers for 4xx TLB management */
John Clark999fa402010-10-05 18:38:55 +02003915#define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
j_mayer76a66252007-03-07 08:32:30 +00003916
John Clark999fa402010-10-05 18:38:55 +02003917#define PPC4XX_TLBHI_V 0x00000040
3918#define PPC4XX_TLBHI_E 0x00000020
3919#define PPC4XX_TLBHI_SIZE_MIN 0
3920#define PPC4XX_TLBHI_SIZE_MAX 7
3921#define PPC4XX_TLBHI_SIZE_DEFAULT 1
3922#define PPC4XX_TLBHI_SIZE_SHIFT 7
3923#define PPC4XX_TLBHI_SIZE_MASK 0x00000007
3924
3925#define PPC4XX_TLBLO_EX 0x00000200
3926#define PPC4XX_TLBLO_WR 0x00000100
3927#define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
3928#define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
j_mayer76a66252007-03-07 08:32:30 +00003929
aurel3274d37792008-12-06 21:46:17 +00003930target_ulong helper_4xx_tlbre_hi (target_ulong entry)
j_mayer76a66252007-03-07 08:32:30 +00003931{
Anthony Liguoric227f092009-10-01 16:12:16 -05003932 ppcemb_tlb_t *tlb;
aurel3274d37792008-12-06 21:46:17 +00003933 target_ulong ret;
John Clark999fa402010-10-05 18:38:55 +02003934 int size;
j_mayer76a66252007-03-07 08:32:30 +00003935
John Clark999fa402010-10-05 18:38:55 +02003936 entry &= PPC4XX_TLB_ENTRY_MASK;
3937 tlb = &env->tlb[entry].tlbe;
3938 ret = tlb->EPN;
3939 if (tlb->prot & PAGE_VALID) {
3940 ret |= PPC4XX_TLBHI_V;
3941 }
3942 size = booke_page_size_to_tlb(tlb->size);
3943 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
3944 size = PPC4XX_TLBHI_SIZE_DEFAULT;
3945 }
3946 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
3947 env->spr[SPR_40x_PID] = tlb->PID;
3948 return ret;
3949}
3950
3951target_ulong helper_4xx_tlbre_lo (target_ulong entry)
3952{
3953 ppcemb_tlb_t *tlb;
3954 target_ulong ret;
3955
3956 entry &= PPC4XX_TLB_ENTRY_MASK;
aurel3274d37792008-12-06 21:46:17 +00003957 tlb = &env->tlb[entry].tlbe;
3958 ret = tlb->RPN;
John Clark999fa402010-10-05 18:38:55 +02003959 if (tlb->prot & PAGE_EXEC) {
3960 ret |= PPC4XX_TLBLO_EX;
3961 }
3962 if (tlb->prot & PAGE_WRITE) {
3963 ret |= PPC4XX_TLBLO_WR;
3964 }
aurel3274d37792008-12-06 21:46:17 +00003965 return ret;
j_mayer76a66252007-03-07 08:32:30 +00003966}
3967
aurel3274d37792008-12-06 21:46:17 +00003968void helper_4xx_tlbwe_hi (target_ulong entry, target_ulong val)
j_mayer76a66252007-03-07 08:32:30 +00003969{
Anthony Liguoric227f092009-10-01 16:12:16 -05003970 ppcemb_tlb_t *tlb;
j_mayer76a66252007-03-07 08:32:30 +00003971 target_ulong page, end;
3972
Blue Swirl90e189e2009-08-16 11:13:18 +00003973 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
3974 val);
John Clark999fa402010-10-05 18:38:55 +02003975 entry &= PPC4XX_TLB_ENTRY_MASK;
aurel3274d37792008-12-06 21:46:17 +00003976 tlb = &env->tlb[entry].tlbe;
j_mayer76a66252007-03-07 08:32:30 +00003977 /* Invalidate previous TLB (if it's valid) */
3978 if (tlb->prot & PAGE_VALID) {
3979 end = tlb->EPN + tlb->size;
Blue Swirl90e189e2009-08-16 11:13:18 +00003980 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
3981 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
John Clark999fa402010-10-05 18:38:55 +02003982 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
j_mayer76a66252007-03-07 08:32:30 +00003983 tlb_flush_page(env, page);
John Clark999fa402010-10-05 18:38:55 +02003984 }
j_mayer76a66252007-03-07 08:32:30 +00003985 }
John Clark999fa402010-10-05 18:38:55 +02003986 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
3987 & PPC4XX_TLBHI_SIZE_MASK);
j_mayerc294fc52007-04-24 06:44:14 +00003988 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
3989 * If this ever occurs, one should use the ppcemb target instead
3990 * of the ppc or ppc64 one
3991 */
John Clark999fa402010-10-05 18:38:55 +02003992 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
j_mayer71c8b8f2007-09-19 05:46:03 +00003993 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
3994 "are not supported (%d)\n",
aurel3274d37792008-12-06 21:46:17 +00003995 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
j_mayerc294fc52007-04-24 06:44:14 +00003996 }
aurel3274d37792008-12-06 21:46:17 +00003997 tlb->EPN = val & ~(tlb->size - 1);
John Clark999fa402010-10-05 18:38:55 +02003998 if (val & PPC4XX_TLBHI_V) {
j_mayer76a66252007-03-07 08:32:30 +00003999 tlb->prot |= PAGE_VALID;
John Clark999fa402010-10-05 18:38:55 +02004000 if (val & PPC4XX_TLBHI_E) {
Edgar E. Iglesiasc5b97292010-01-11 14:41:53 +01004001 /* XXX: TO BE FIXED */
4002 cpu_abort(env,
4003 "Little-endian TLB entries are not supported by now\n");
4004 }
4005 } else {
j_mayer76a66252007-03-07 08:32:30 +00004006 tlb->prot &= ~PAGE_VALID;
j_mayerc294fc52007-04-24 06:44:14 +00004007 }
j_mayerc55e9ae2007-04-16 09:21:46 +00004008 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
Blue Swirl90e189e2009-08-16 11:13:18 +00004009 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
4010 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
4011 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4012 tlb->prot & PAGE_READ ? 'r' : '-',
4013 tlb->prot & PAGE_WRITE ? 'w' : '-',
4014 tlb->prot & PAGE_EXEC ? 'x' : '-',
4015 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
j_mayer76a66252007-03-07 08:32:30 +00004016 /* Invalidate new TLB (if valid) */
4017 if (tlb->prot & PAGE_VALID) {
4018 end = tlb->EPN + tlb->size;
Blue Swirl90e189e2009-08-16 11:13:18 +00004019 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
4020 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
John Clark999fa402010-10-05 18:38:55 +02004021 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
j_mayer76a66252007-03-07 08:32:30 +00004022 tlb_flush_page(env, page);
John Clark999fa402010-10-05 18:38:55 +02004023 }
j_mayer76a66252007-03-07 08:32:30 +00004024 }
j_mayer76a66252007-03-07 08:32:30 +00004025}
4026
aurel3274d37792008-12-06 21:46:17 +00004027void helper_4xx_tlbwe_lo (target_ulong entry, target_ulong val)
j_mayer76a66252007-03-07 08:32:30 +00004028{
Anthony Liguoric227f092009-10-01 16:12:16 -05004029 ppcemb_tlb_t *tlb;
j_mayer76a66252007-03-07 08:32:30 +00004030
Blue Swirl90e189e2009-08-16 11:13:18 +00004031 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
4032 val);
John Clark999fa402010-10-05 18:38:55 +02004033 entry &= PPC4XX_TLB_ENTRY_MASK;
aurel3274d37792008-12-06 21:46:17 +00004034 tlb = &env->tlb[entry].tlbe;
John Clark999fa402010-10-05 18:38:55 +02004035 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
4036 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
j_mayer76a66252007-03-07 08:32:30 +00004037 tlb->prot = PAGE_READ;
John Clark999fa402010-10-05 18:38:55 +02004038 if (val & PPC4XX_TLBLO_EX) {
j_mayer76a66252007-03-07 08:32:30 +00004039 tlb->prot |= PAGE_EXEC;
John Clark999fa402010-10-05 18:38:55 +02004040 }
4041 if (val & PPC4XX_TLBLO_WR) {
j_mayer76a66252007-03-07 08:32:30 +00004042 tlb->prot |= PAGE_WRITE;
John Clark999fa402010-10-05 18:38:55 +02004043 }
Blue Swirl90e189e2009-08-16 11:13:18 +00004044 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
4045 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
4046 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
4047 tlb->prot & PAGE_READ ? 'r' : '-',
4048 tlb->prot & PAGE_WRITE ? 'w' : '-',
4049 tlb->prot & PAGE_EXEC ? 'x' : '-',
4050 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
j_mayer76a66252007-03-07 08:32:30 +00004051}
j_mayer5eb79952007-09-19 05:44:04 +00004052
aurel3274d37792008-12-06 21:46:17 +00004053target_ulong helper_4xx_tlbsx (target_ulong address)
4054{
4055 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
4056}
4057
j_mayera4bb6c32007-09-21 05:28:33 +00004058/* PowerPC 440 TLB management */
aurel3274d37792008-12-06 21:46:17 +00004059void helper_440_tlbwe (uint32_t word, target_ulong entry, target_ulong value)
j_mayer5eb79952007-09-19 05:44:04 +00004060{
Anthony Liguoric227f092009-10-01 16:12:16 -05004061 ppcemb_tlb_t *tlb;
j_mayera4bb6c32007-09-21 05:28:33 +00004062 target_ulong EPN, RPN, size;
j_mayer5eb79952007-09-19 05:44:04 +00004063 int do_flush_tlbs;
4064
Blue Swirl90e189e2009-08-16 11:13:18 +00004065 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
4066 __func__, word, (int)entry, value);
j_mayer5eb79952007-09-19 05:44:04 +00004067 do_flush_tlbs = 0;
aurel3274d37792008-12-06 21:46:17 +00004068 entry &= 0x3F;
4069 tlb = &env->tlb[entry].tlbe;
j_mayera4bb6c32007-09-21 05:28:33 +00004070 switch (word) {
4071 default:
4072 /* Just here to please gcc */
4073 case 0:
aurel3274d37792008-12-06 21:46:17 +00004074 EPN = value & 0xFFFFFC00;
j_mayera4bb6c32007-09-21 05:28:33 +00004075 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
j_mayer5eb79952007-09-19 05:44:04 +00004076 do_flush_tlbs = 1;
j_mayera4bb6c32007-09-21 05:28:33 +00004077 tlb->EPN = EPN;
aurel3274d37792008-12-06 21:46:17 +00004078 size = booke_tlb_to_page_size((value >> 4) & 0xF);
j_mayera4bb6c32007-09-21 05:28:33 +00004079 if ((tlb->prot & PAGE_VALID) && tlb->size < size)
4080 do_flush_tlbs = 1;
4081 tlb->size = size;
4082 tlb->attr &= ~0x1;
aurel3274d37792008-12-06 21:46:17 +00004083 tlb->attr |= (value >> 8) & 1;
4084 if (value & 0x200) {
j_mayera4bb6c32007-09-21 05:28:33 +00004085 tlb->prot |= PAGE_VALID;
4086 } else {
4087 if (tlb->prot & PAGE_VALID) {
4088 tlb->prot &= ~PAGE_VALID;
4089 do_flush_tlbs = 1;
4090 }
j_mayer5eb79952007-09-19 05:44:04 +00004091 }
j_mayera4bb6c32007-09-21 05:28:33 +00004092 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
4093 if (do_flush_tlbs)
4094 tlb_flush(env, 1);
4095 break;
4096 case 1:
aurel3274d37792008-12-06 21:46:17 +00004097 RPN = value & 0xFFFFFC0F;
j_mayera4bb6c32007-09-21 05:28:33 +00004098 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
4099 tlb_flush(env, 1);
4100 tlb->RPN = RPN;
4101 break;
4102 case 2:
aurel3274d37792008-12-06 21:46:17 +00004103 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
j_mayera4bb6c32007-09-21 05:28:33 +00004104 tlb->prot = tlb->prot & PAGE_VALID;
aurel3274d37792008-12-06 21:46:17 +00004105 if (value & 0x1)
j_mayera4bb6c32007-09-21 05:28:33 +00004106 tlb->prot |= PAGE_READ << 4;
aurel3274d37792008-12-06 21:46:17 +00004107 if (value & 0x2)
j_mayera4bb6c32007-09-21 05:28:33 +00004108 tlb->prot |= PAGE_WRITE << 4;
aurel3274d37792008-12-06 21:46:17 +00004109 if (value & 0x4)
j_mayera4bb6c32007-09-21 05:28:33 +00004110 tlb->prot |= PAGE_EXEC << 4;
aurel3274d37792008-12-06 21:46:17 +00004111 if (value & 0x8)
j_mayera4bb6c32007-09-21 05:28:33 +00004112 tlb->prot |= PAGE_READ;
aurel3274d37792008-12-06 21:46:17 +00004113 if (value & 0x10)
j_mayera4bb6c32007-09-21 05:28:33 +00004114 tlb->prot |= PAGE_WRITE;
aurel3274d37792008-12-06 21:46:17 +00004115 if (value & 0x20)
j_mayera4bb6c32007-09-21 05:28:33 +00004116 tlb->prot |= PAGE_EXEC;
4117 break;
j_mayer5eb79952007-09-19 05:44:04 +00004118 }
j_mayer5eb79952007-09-19 05:44:04 +00004119}
4120
aurel3274d37792008-12-06 21:46:17 +00004121target_ulong helper_440_tlbre (uint32_t word, target_ulong entry)
j_mayer5eb79952007-09-19 05:44:04 +00004122{
Anthony Liguoric227f092009-10-01 16:12:16 -05004123 ppcemb_tlb_t *tlb;
aurel3274d37792008-12-06 21:46:17 +00004124 target_ulong ret;
j_mayer5eb79952007-09-19 05:44:04 +00004125 int size;
4126
aurel3274d37792008-12-06 21:46:17 +00004127 entry &= 0x3F;
4128 tlb = &env->tlb[entry].tlbe;
j_mayera4bb6c32007-09-21 05:28:33 +00004129 switch (word) {
4130 default:
4131 /* Just here to please gcc */
4132 case 0:
aurel3274d37792008-12-06 21:46:17 +00004133 ret = tlb->EPN;
j_mayera4bb6c32007-09-21 05:28:33 +00004134 size = booke_page_size_to_tlb(tlb->size);
4135 if (size < 0 || size > 0xF)
4136 size = 1;
aurel3274d37792008-12-06 21:46:17 +00004137 ret |= size << 4;
j_mayera4bb6c32007-09-21 05:28:33 +00004138 if (tlb->attr & 0x1)
aurel3274d37792008-12-06 21:46:17 +00004139 ret |= 0x100;
j_mayera4bb6c32007-09-21 05:28:33 +00004140 if (tlb->prot & PAGE_VALID)
aurel3274d37792008-12-06 21:46:17 +00004141 ret |= 0x200;
j_mayera4bb6c32007-09-21 05:28:33 +00004142 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
4143 env->spr[SPR_440_MMUCR] |= tlb->PID;
4144 break;
4145 case 1:
aurel3274d37792008-12-06 21:46:17 +00004146 ret = tlb->RPN;
j_mayera4bb6c32007-09-21 05:28:33 +00004147 break;
4148 case 2:
aurel3274d37792008-12-06 21:46:17 +00004149 ret = tlb->attr & ~0x1;
j_mayera4bb6c32007-09-21 05:28:33 +00004150 if (tlb->prot & (PAGE_READ << 4))
aurel3274d37792008-12-06 21:46:17 +00004151 ret |= 0x1;
j_mayera4bb6c32007-09-21 05:28:33 +00004152 if (tlb->prot & (PAGE_WRITE << 4))
aurel3274d37792008-12-06 21:46:17 +00004153 ret |= 0x2;
j_mayera4bb6c32007-09-21 05:28:33 +00004154 if (tlb->prot & (PAGE_EXEC << 4))
aurel3274d37792008-12-06 21:46:17 +00004155 ret |= 0x4;
j_mayera4bb6c32007-09-21 05:28:33 +00004156 if (tlb->prot & PAGE_READ)
aurel3274d37792008-12-06 21:46:17 +00004157 ret |= 0x8;
j_mayera4bb6c32007-09-21 05:28:33 +00004158 if (tlb->prot & PAGE_WRITE)
aurel3274d37792008-12-06 21:46:17 +00004159 ret |= 0x10;
j_mayera4bb6c32007-09-21 05:28:33 +00004160 if (tlb->prot & PAGE_EXEC)
aurel3274d37792008-12-06 21:46:17 +00004161 ret |= 0x20;
j_mayera4bb6c32007-09-21 05:28:33 +00004162 break;
4163 }
aurel3274d37792008-12-06 21:46:17 +00004164 return ret;
j_mayer5eb79952007-09-19 05:44:04 +00004165}
aurel3274d37792008-12-06 21:46:17 +00004166
4167target_ulong helper_440_tlbsx (target_ulong address)
4168{
4169 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
4170}
4171
j_mayer76a66252007-03-07 08:32:30 +00004172#endif /* !CONFIG_USER_ONLY */