~fboudra/qemu-linaro/new-upstream-release-1.2.0-2012.09-0ubuntu1

« back to all changes in this revision

Viewing changes to target-ppc/op_helper.c

  • Committer: Fathi Boudra
  • Author(s): Fathi Boudra
  • Date: 2012-08-21 06:47:11 UTC
  • mfrom: (0.1.16)
  • Revision ID: fathi.boudra@linaro.org-20120821064711-7yxmubp2v8a44xce
Tags: 1.1.50-2012.08-0ubuntu1
* New upstream release.
  - support emulated systems with more than 2G of memory. (LP: #1030588)
* Drop powerpc-missing-include.patch - merged upstream.
* Update debian/control: 
  - drop perl build dependency.
  - add libfdt-dev build dependency.
* Update debian/qemu-keymaps.install file.
* Update debian/rules:
  - update QEMU_CPU for ARM architecture: armv4l -> armv7l.
  - update conf_audio_drv: default to PulseAudio since PA is the default on
    Ubuntu.
  - enable KVM on ARM architecture.
  - enable flat device tree support (--enable-fdt). (LP: #1030594)

Show diffs side-by-side

added added

removed removed

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