Statistics
| Branch: | Revision:

root / target-mips / op_helper.c @ 36388314

History | View | Annotate | Download (96 kB)

1
/*
2
 *  MIPS emulation helpers for qemu.
3
 *
4
 *  Copyright (c) 2004-2005 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 <stdlib.h>
20
#include "exec.h"
21

    
22
#include "host-utils.h"
23

    
24
#include "helper.h"
25

    
26
#ifndef CONFIG_USER_ONLY
27
static inline void cpu_mips_tlb_flush (CPUState *env, int flush_global);
28
#endif
29

    
30
/*****************************************************************************/
31
/* Exceptions processing helpers */
32

    
33
void helper_raise_exception_err (uint32_t exception, int error_code)
34
{
35
#if 1
36
    if (exception < 0x100)
37
        qemu_log("%s: %d %d\n", __func__, exception, error_code);
38
#endif
39
    env->exception_index = exception;
40
    env->error_code = error_code;
41
    cpu_loop_exit();
42
}
43

    
44
void helper_raise_exception (uint32_t exception)
45
{
46
    helper_raise_exception_err(exception, 0);
47
}
48

    
49
void helper_interrupt_restart (void)
50
{
51
    if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
52
        !(env->CP0_Status & (1 << CP0St_ERL)) &&
53
        !(env->hflags & MIPS_HFLAG_DM) &&
54
        (env->CP0_Status & (1 << CP0St_IE)) &&
55
        (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) {
56
        env->CP0_Cause &= ~(0x1f << CP0Ca_EC);
57
        helper_raise_exception(EXCP_EXT_INTERRUPT);
58
    }
59
}
60

    
61
#if !defined(CONFIG_USER_ONLY)
62
static void do_restore_state (void *pc_ptr)
63
{
64
    TranslationBlock *tb;
65
    unsigned long pc = (unsigned long) pc_ptr;
66
    
67
    tb = tb_find_pc (pc);
68
    if (tb) {
69
        cpu_restore_state (tb, env, pc, NULL);
70
    }
71
}
72
#endif
73

    
74
#if defined(CONFIG_USER_ONLY)
75
#define HELPER_LD(name, insn, type)                                     \
76
static inline type do_##name(target_ulong addr, int mem_idx)            \
77
{                                                                       \
78
    return (type) insn##_raw(addr);                                     \
79
}
80
#else
81
#define HELPER_LD(name, insn, type)                                     \
82
static inline type do_##name(target_ulong addr, int mem_idx)            \
83
{                                                                       \
84
    switch (mem_idx)                                                    \
85
    {                                                                   \
86
    case 0: return (type) insn##_kernel(addr); break;                   \
87
    case 1: return (type) insn##_super(addr); break;                    \
88
    default:                                                            \
89
    case 2: return (type) insn##_user(addr); break;                     \
90
    }                                                                   \
91
}
92
#endif
93
HELPER_LD(lbu, ldub, uint8_t)
94
HELPER_LD(lw, ldl, int32_t)
95
#ifdef TARGET_MIPS64
96
HELPER_LD(ld, ldq, int64_t)
97
#endif
98
#undef HELPER_LD
99

    
100
#if defined(CONFIG_USER_ONLY)
101
#define HELPER_ST(name, insn, type)                                     \
102
static inline void do_##name(target_ulong addr, type val, int mem_idx)  \
103
{                                                                       \
104
    insn##_raw(addr, val);                                              \
105
}
106
#else
107
#define HELPER_ST(name, insn, type)                                     \
108
static inline void do_##name(target_ulong addr, type val, int mem_idx)  \
109
{                                                                       \
110
    switch (mem_idx)                                                    \
111
    {                                                                   \
112
    case 0: insn##_kernel(addr, val); break;                            \
113
    case 1: insn##_super(addr, val); break;                             \
114
    default:                                                            \
115
    case 2: insn##_user(addr, val); break;                              \
116
    }                                                                   \
117
}
118
#endif
119
HELPER_ST(sb, stb, uint8_t)
120
HELPER_ST(sw, stl, uint32_t)
121
#ifdef TARGET_MIPS64
122
HELPER_ST(sd, stq, uint64_t)
123
#endif
124
#undef HELPER_ST
125

    
126
target_ulong helper_clo (target_ulong arg1)
127
{
128
    return clo32(arg1);
129
}
130

    
131
target_ulong helper_clz (target_ulong arg1)
132
{
133
    return clz32(arg1);
134
}
135

    
136
#if defined(TARGET_MIPS64)
137
target_ulong helper_dclo (target_ulong arg1)
138
{
139
    return clo64(arg1);
140
}
141

    
142
target_ulong helper_dclz (target_ulong arg1)
143
{
144
    return clz64(arg1);
145
}
146
#endif /* TARGET_MIPS64 */
147

    
148
/* 64 bits arithmetic for 32 bits hosts */
149
static inline uint64_t get_HILO (void)
150
{
151
    return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
152
}
153

    
154
static inline void set_HILO (uint64_t HILO)
155
{
156
    env->active_tc.LO[0] = (int32_t)HILO;
157
    env->active_tc.HI[0] = (int32_t)(HILO >> 32);
158
}
159

    
160
static inline void set_HIT0_LO (target_ulong arg1, uint64_t HILO)
161
{
162
    env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
163
    arg1 = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
164
}
165

    
166
static inline void set_HI_LOT0 (target_ulong arg1, uint64_t HILO)
167
{
168
    arg1 = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
169
    env->active_tc.HI[0] = (int32_t)(HILO >> 32);
170
}
171

    
172
/* Multiplication variants of the vr54xx. */
173
target_ulong helper_muls (target_ulong arg1, target_ulong arg2)
174
{
175
    set_HI_LOT0(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
176

    
177
    return arg1;
178
}
179

    
180
target_ulong helper_mulsu (target_ulong arg1, target_ulong arg2)
181
{
182
    set_HI_LOT0(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
183

    
184
    return arg1;
185
}
186

    
187
target_ulong helper_macc (target_ulong arg1, target_ulong arg2)
188
{
189
    set_HI_LOT0(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
190

    
191
    return arg1;
192
}
193

    
194
target_ulong helper_macchi (target_ulong arg1, target_ulong arg2)
195
{
196
    set_HIT0_LO(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
197

    
198
    return arg1;
199
}
200

    
201
target_ulong helper_maccu (target_ulong arg1, target_ulong arg2)
202
{
203
    set_HI_LOT0(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
204

    
205
    return arg1;
206
}
207

    
208
target_ulong helper_macchiu (target_ulong arg1, target_ulong arg2)
209
{
210
    set_HIT0_LO(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
211

    
212
    return arg1;
213
}
214

    
215
target_ulong helper_msac (target_ulong arg1, target_ulong arg2)
216
{
217
    set_HI_LOT0(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
218

    
219
    return arg1;
220
}
221

    
222
target_ulong helper_msachi (target_ulong arg1, target_ulong arg2)
223
{
224
    set_HIT0_LO(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
225

    
226
    return arg1;
227
}
228

    
229
target_ulong helper_msacu (target_ulong arg1, target_ulong arg2)
230
{
231
    set_HI_LOT0(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
232

    
233
    return arg1;
234
}
235

    
236
target_ulong helper_msachiu (target_ulong arg1, target_ulong arg2)
237
{
238
    set_HIT0_LO(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
239

    
240
    return arg1;
241
}
242

    
243
target_ulong helper_mulhi (target_ulong arg1, target_ulong arg2)
244
{
245
    set_HIT0_LO(arg1, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
246

    
247
    return arg1;
248
}
249

    
250
target_ulong helper_mulhiu (target_ulong arg1, target_ulong arg2)
251
{
252
    set_HIT0_LO(arg1, (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
253

    
254
    return arg1;
255
}
256

    
257
target_ulong helper_mulshi (target_ulong arg1, target_ulong arg2)
258
{
259
    set_HIT0_LO(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
260

    
261
    return arg1;
262
}
263

    
264
target_ulong helper_mulshiu (target_ulong arg1, target_ulong arg2)
265
{
266
    set_HIT0_LO(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
267

    
268
    return arg1;
269
}
270

    
271
#ifdef TARGET_MIPS64
272
void helper_dmult (target_ulong arg1, target_ulong arg2)
273
{
274
    muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
275
}
276

    
277
void helper_dmultu (target_ulong arg1, target_ulong arg2)
278
{
279
    mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
280
}
281
#endif
282

    
283
#ifndef CONFIG_USER_ONLY
284

    
285
static inline target_phys_addr_t do_translate_address(target_ulong address, int rw)
286
{
287
    target_phys_addr_t lladdr;
288

    
289
    lladdr = cpu_mips_translate_address(env, address, rw);
290

    
291
    if (lladdr == -1LL) {
292
        cpu_loop_exit();
293
    } else {
294
        return lladdr;
295
    }
296
}
297

    
298
#define HELPER_LD_ATOMIC(name, insn)                                          \
299
target_ulong helper_##name(target_ulong arg, int mem_idx)                     \
300
{                                                                             \
301
    env->lladdr = do_translate_address(arg, 0);                               \
302
    env->llval = do_##insn(arg, mem_idx);                                     \
303
    return env->llval;                                                        \
304
}
305
HELPER_LD_ATOMIC(ll, lw)
306
#ifdef TARGET_MIPS64
307
HELPER_LD_ATOMIC(lld, ld)
308
#endif
309
#undef HELPER_LD_ATOMIC
310

    
311
#define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask)                      \
312
target_ulong helper_##name(target_ulong arg1, target_ulong arg2, int mem_idx) \
313
{                                                                             \
314
    target_long tmp;                                                          \
315
                                                                              \
316
    if (arg2 & almask) {                                                      \
317
        env->CP0_BadVAddr = arg2;                                             \
318
        helper_raise_exception(EXCP_AdES);                                    \
319
    }                                                                         \
320
    if (do_translate_address(arg2, 1) == env->lladdr) {                       \
321
        tmp = do_##ld_insn(arg2, mem_idx);                                    \
322
        if (tmp == env->llval) {                                              \
323
            do_##st_insn(arg2, arg1, mem_idx);                                \
324
            return 1;                                                         \
325
        }                                                                     \
326
    }                                                                         \
327
    return 0;                                                                 \
328
}
329
HELPER_ST_ATOMIC(sc, lw, sw, 0x3)
330
#ifdef TARGET_MIPS64
331
HELPER_ST_ATOMIC(scd, ld, sd, 0x7)
332
#endif
333
#undef HELPER_ST_ATOMIC
334
#endif
335

    
336
#ifdef TARGET_WORDS_BIGENDIAN
337
#define GET_LMASK(v) ((v) & 3)
338
#define GET_OFFSET(addr, offset) (addr + (offset))
339
#else
340
#define GET_LMASK(v) (((v) & 3) ^ 3)
341
#define GET_OFFSET(addr, offset) (addr - (offset))
342
#endif
343

    
344
target_ulong helper_lwl(target_ulong arg1, target_ulong arg2, int mem_idx)
345
{
346
    target_ulong tmp;
347

    
348
    tmp = do_lbu(arg2, mem_idx);
349
    arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
350

    
351
    if (GET_LMASK(arg2) <= 2) {
352
        tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx);
353
        arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
354
    }
355

    
356
    if (GET_LMASK(arg2) <= 1) {
357
        tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx);
358
        arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
359
    }
360

    
361
    if (GET_LMASK(arg2) == 0) {
362
        tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx);
363
        arg1 = (arg1 & 0xFFFFFF00) | tmp;
364
    }
365
    return (int32_t)arg1;
366
}
367

    
368
target_ulong helper_lwr(target_ulong arg1, target_ulong arg2, int mem_idx)
369
{
370
    target_ulong tmp;
371

    
372
    tmp = do_lbu(arg2, mem_idx);
373
    arg1 = (arg1 & 0xFFFFFF00) | tmp;
374

    
375
    if (GET_LMASK(arg2) >= 1) {
376
        tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx);
377
        arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
378
    }
379

    
380
    if (GET_LMASK(arg2) >= 2) {
381
        tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx);
382
        arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
383
    }
384

    
385
    if (GET_LMASK(arg2) == 3) {
386
        tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx);
387
        arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
388
    }
389
    return (int32_t)arg1;
390
}
391

    
392
void helper_swl(target_ulong arg1, target_ulong arg2, int mem_idx)
393
{
394
    do_sb(arg2, (uint8_t)(arg1 >> 24), mem_idx);
395

    
396
    if (GET_LMASK(arg2) <= 2)
397
        do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx);
398

    
399
    if (GET_LMASK(arg2) <= 1)
400
        do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx);
401

    
402
    if (GET_LMASK(arg2) == 0)
403
        do_sb(GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx);
404
}
405

    
406
void helper_swr(target_ulong arg1, target_ulong arg2, int mem_idx)
407
{
408
    do_sb(arg2, (uint8_t)arg1, mem_idx);
409

    
410
    if (GET_LMASK(arg2) >= 1)
411
        do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
412

    
413
    if (GET_LMASK(arg2) >= 2)
414
        do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
415

    
416
    if (GET_LMASK(arg2) == 3)
417
        do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
418
}
419

    
420
#if defined(TARGET_MIPS64)
421
/* "half" load and stores.  We must do the memory access inline,
422
   or fault handling won't work.  */
423

    
424
#ifdef TARGET_WORDS_BIGENDIAN
425
#define GET_LMASK64(v) ((v) & 7)
426
#else
427
#define GET_LMASK64(v) (((v) & 7) ^ 7)
428
#endif
429

    
430
target_ulong helper_ldl(target_ulong arg1, target_ulong arg2, int mem_idx)
431
{
432
    uint64_t tmp;
433

    
434
    tmp = do_lbu(arg2, mem_idx);
435
    arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
436

    
437
    if (GET_LMASK64(arg2) <= 6) {
438
        tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx);
439
        arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
440
    }
441

    
442
    if (GET_LMASK64(arg2) <= 5) {
443
        tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx);
444
        arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
445
    }
446

    
447
    if (GET_LMASK64(arg2) <= 4) {
448
        tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx);
449
        arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
450
    }
451

    
452
    if (GET_LMASK64(arg2) <= 3) {
453
        tmp = do_lbu(GET_OFFSET(arg2, 4), mem_idx);
454
        arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
455
    }
456

    
457
    if (GET_LMASK64(arg2) <= 2) {
458
        tmp = do_lbu(GET_OFFSET(arg2, 5), mem_idx);
459
        arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
460
    }
461

    
462
    if (GET_LMASK64(arg2) <= 1) {
463
        tmp = do_lbu(GET_OFFSET(arg2, 6), mem_idx);
464
        arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
465
    }
466

    
467
    if (GET_LMASK64(arg2) == 0) {
468
        tmp = do_lbu(GET_OFFSET(arg2, 7), mem_idx);
469
        arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
470
    }
471

    
472
    return arg1;
473
}
474

    
475
target_ulong helper_ldr(target_ulong arg1, target_ulong arg2, int mem_idx)
476
{
477
    uint64_t tmp;
478

    
479
    tmp = do_lbu(arg2, mem_idx);
480
    arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
481

    
482
    if (GET_LMASK64(arg2) >= 1) {
483
        tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx);
484
        arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp  << 8);
485
    }
486

    
487
    if (GET_LMASK64(arg2) >= 2) {
488
        tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx);
489
        arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
490
    }
491

    
492
    if (GET_LMASK64(arg2) >= 3) {
493
        tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx);
494
        arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
495
    }
496

    
497
    if (GET_LMASK64(arg2) >= 4) {
498
        tmp = do_lbu(GET_OFFSET(arg2, -4), mem_idx);
499
        arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
500
    }
501

    
502
    if (GET_LMASK64(arg2) >= 5) {
503
        tmp = do_lbu(GET_OFFSET(arg2, -5), mem_idx);
504
        arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
505
    }
506

    
507
    if (GET_LMASK64(arg2) >= 6) {
508
        tmp = do_lbu(GET_OFFSET(arg2, -6), mem_idx);
509
        arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
510
    }
511

    
512
    if (GET_LMASK64(arg2) == 7) {
513
        tmp = do_lbu(GET_OFFSET(arg2, -7), mem_idx);
514
        arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
515
    }
516

    
517
    return arg1;
518
}
519

    
520
void helper_sdl(target_ulong arg1, target_ulong arg2, int mem_idx)
521
{
522
    do_sb(arg2, (uint8_t)(arg1 >> 56), mem_idx);
523

    
524
    if (GET_LMASK64(arg2) <= 6)
525
        do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx);
526

    
527
    if (GET_LMASK64(arg2) <= 5)
528
        do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx);
529

    
530
    if (GET_LMASK64(arg2) <= 4)
531
        do_sb(GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx);
532

    
533
    if (GET_LMASK64(arg2) <= 3)
534
        do_sb(GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx);
535

    
536
    if (GET_LMASK64(arg2) <= 2)
537
        do_sb(GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx);
538

    
539
    if (GET_LMASK64(arg2) <= 1)
540
        do_sb(GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx);
541

    
542
    if (GET_LMASK64(arg2) <= 0)
543
        do_sb(GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx);
544
}
545

    
546
void helper_sdr(target_ulong arg1, target_ulong arg2, int mem_idx)
547
{
548
    do_sb(arg2, (uint8_t)arg1, mem_idx);
549

    
550
    if (GET_LMASK64(arg2) >= 1)
551
        do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx);
552

    
553
    if (GET_LMASK64(arg2) >= 2)
554
        do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx);
555

    
556
    if (GET_LMASK64(arg2) >= 3)
557
        do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx);
558

    
559
    if (GET_LMASK64(arg2) >= 4)
560
        do_sb(GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx);
561

    
562
    if (GET_LMASK64(arg2) >= 5)
563
        do_sb(GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx);
564

    
565
    if (GET_LMASK64(arg2) >= 6)
566
        do_sb(GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx);
567

    
568
    if (GET_LMASK64(arg2) == 7)
569
        do_sb(GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx);
570
}
571
#endif /* TARGET_MIPS64 */
572

    
573
static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
574

    
575
void helper_lwm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
576
{
577
    target_ulong base_reglist = reglist & 0xf;
578
    target_ulong do_r31 = reglist & 0x10;
579
#ifdef CONFIG_USER_ONLY
580
#undef ldfun
581
#define ldfun ldl_raw
582
#else
583
    uint32_t (*ldfun)(target_ulong);
584

    
585
    switch (mem_idx)
586
    {
587
    case 0: ldfun = ldl_kernel; break;
588
    case 1: ldfun = ldl_super; break;
589
    default:
590
    case 2: ldfun = ldl_user; break;
591
    }
592
#endif
593

    
594
    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
595
        target_ulong i;
596

    
597
        for (i = 0; i < base_reglist; i++) {
598
            env->active_tc.gpr[multiple_regs[i]] = (target_long) ldfun(addr);
599
            addr += 4;
600
        }
601
    }
602

    
603
    if (do_r31) {
604
        env->active_tc.gpr[31] = (target_long) ldfun(addr);
605
    }
606
}
607

    
608
void helper_swm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
609
{
610
    target_ulong base_reglist = reglist & 0xf;
611
    target_ulong do_r31 = reglist & 0x10;
612
#ifdef CONFIG_USER_ONLY
613
#undef stfun
614
#define stfun stl_raw
615
#else
616
    void (*stfun)(target_ulong, uint32_t);
617

    
618
    switch (mem_idx)
619
    {
620
    case 0: stfun = stl_kernel; break;
621
    case 1: stfun = stl_super; break;
622
     default:
623
    case 2: stfun = stl_user; break;
624
    }
625
#endif
626

    
627
    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
628
        target_ulong i;
629

    
630
        for (i = 0; i < base_reglist; i++) {
631
            stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
632
            addr += 4;
633
        }
634
    }
635

    
636
    if (do_r31) {
637
        stfun(addr, env->active_tc.gpr[31]);
638
    }
639
}
640

    
641
#if defined(TARGET_MIPS64)
642
void helper_ldm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
643
{
644
    target_ulong base_reglist = reglist & 0xf;
645
    target_ulong do_r31 = reglist & 0x10;
646
#ifdef CONFIG_USER_ONLY
647
#undef ldfun
648
#define ldfun ldq_raw
649
#else
650
    uint64_t (*ldfun)(target_ulong);
651

    
652
    switch (mem_idx)
653
    {
654
    case 0: ldfun = ldq_kernel; break;
655
    case 1: ldfun = ldq_super; break;
656
    default:
657
    case 2: ldfun = ldq_user; break;
658
    }
659
#endif
660

    
661
    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
662
        target_ulong i;
663

    
664
        for (i = 0; i < base_reglist; i++) {
665
            env->active_tc.gpr[multiple_regs[i]] = ldfun(addr);
666
            addr += 8;
667
        }
668
    }
669

    
670
    if (do_r31) {
671
        env->active_tc.gpr[31] = ldfun(addr);
672
    }
673
}
674

    
675
void helper_sdm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
676
{
677
    target_ulong base_reglist = reglist & 0xf;
678
    target_ulong do_r31 = reglist & 0x10;
679
#ifdef CONFIG_USER_ONLY
680
#undef stfun
681
#define stfun stq_raw
682
#else
683
    void (*stfun)(target_ulong, uint64_t);
684

    
685
    switch (mem_idx)
686
    {
687
    case 0: stfun = stq_kernel; break;
688
    case 1: stfun = stq_super; break;
689
     default:
690
    case 2: stfun = stq_user; break;
691
    }
692
#endif
693

    
694
    if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
695
        target_ulong i;
696

    
697
        for (i = 0; i < base_reglist; i++) {
698
            stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
699
            addr += 8;
700
        }
701
    }
702

    
703
    if (do_r31) {
704
        stfun(addr, env->active_tc.gpr[31]);
705
    }
706
}
707
#endif
708

    
709
#ifndef CONFIG_USER_ONLY
710
/* CP0 helpers */
711
target_ulong helper_mfc0_mvpcontrol (void)
712
{
713
    return env->mvp->CP0_MVPControl;
714
}
715

    
716
target_ulong helper_mfc0_mvpconf0 (void)
717
{
718
    return env->mvp->CP0_MVPConf0;
719
}
720

    
721
target_ulong helper_mfc0_mvpconf1 (void)
722
{
723
    return env->mvp->CP0_MVPConf1;
724
}
725

    
726
target_ulong helper_mfc0_random (void)
727
{
728
    return (int32_t)cpu_mips_get_random(env);
729
}
730

    
731
target_ulong helper_mfc0_tcstatus (void)
732
{
733
    return env->active_tc.CP0_TCStatus;
734
}
735

    
736
target_ulong helper_mftc0_tcstatus(void)
737
{
738
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
739

    
740
    if (other_tc == env->current_tc)
741
        return env->active_tc.CP0_TCStatus;
742
    else
743
        return env->tcs[other_tc].CP0_TCStatus;
744
}
745

    
746
target_ulong helper_mfc0_tcbind (void)
747
{
748
    return env->active_tc.CP0_TCBind;
749
}
750

    
751
target_ulong helper_mftc0_tcbind(void)
752
{
753
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
754

    
755
    if (other_tc == env->current_tc)
756
        return env->active_tc.CP0_TCBind;
757
    else
758
        return env->tcs[other_tc].CP0_TCBind;
759
}
760

    
761
target_ulong helper_mfc0_tcrestart (void)
762
{
763
    return env->active_tc.PC;
764
}
765

    
766
target_ulong helper_mftc0_tcrestart(void)
767
{
768
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
769

    
770
    if (other_tc == env->current_tc)
771
        return env->active_tc.PC;
772
    else
773
        return env->tcs[other_tc].PC;
774
}
775

    
776
target_ulong helper_mfc0_tchalt (void)
777
{
778
    return env->active_tc.CP0_TCHalt;
779
}
780

    
781
target_ulong helper_mftc0_tchalt(void)
782
{
783
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
784

    
785
    if (other_tc == env->current_tc)
786
        return env->active_tc.CP0_TCHalt;
787
    else
788
        return env->tcs[other_tc].CP0_TCHalt;
789
}
790

    
791
target_ulong helper_mfc0_tccontext (void)
792
{
793
    return env->active_tc.CP0_TCContext;
794
}
795

    
796
target_ulong helper_mftc0_tccontext(void)
797
{
798
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
799

    
800
    if (other_tc == env->current_tc)
801
        return env->active_tc.CP0_TCContext;
802
    else
803
        return env->tcs[other_tc].CP0_TCContext;
804
}
805

    
806
target_ulong helper_mfc0_tcschedule (void)
807
{
808
    return env->active_tc.CP0_TCSchedule;
809
}
810

    
811
target_ulong helper_mftc0_tcschedule(void)
812
{
813
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
814

    
815
    if (other_tc == env->current_tc)
816
        return env->active_tc.CP0_TCSchedule;
817
    else
818
        return env->tcs[other_tc].CP0_TCSchedule;
819
}
820

    
821
target_ulong helper_mfc0_tcschefback (void)
822
{
823
    return env->active_tc.CP0_TCScheFBack;
824
}
825

    
826
target_ulong helper_mftc0_tcschefback(void)
827
{
828
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
829

    
830
    if (other_tc == env->current_tc)
831
        return env->active_tc.CP0_TCScheFBack;
832
    else
833
        return env->tcs[other_tc].CP0_TCScheFBack;
834
}
835

    
836
target_ulong helper_mfc0_count (void)
837
{
838
    return (int32_t)cpu_mips_get_count(env);
839
}
840

    
841
target_ulong helper_mftc0_entryhi(void)
842
{
843
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
844
    int32_t tcstatus;
845

    
846
    if (other_tc == env->current_tc)
847
        tcstatus = env->active_tc.CP0_TCStatus;
848
    else
849
        tcstatus = env->tcs[other_tc].CP0_TCStatus;
850

    
851
    return (env->CP0_EntryHi & ~0xff) | (tcstatus & 0xff);
852
}
853

    
854
target_ulong helper_mftc0_status(void)
855
{
856
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
857
    target_ulong t0;
858
    int32_t tcstatus;
859

    
860
    if (other_tc == env->current_tc)
861
        tcstatus = env->active_tc.CP0_TCStatus;
862
    else
863
        tcstatus = env->tcs[other_tc].CP0_TCStatus;
864

    
865
    t0 = env->CP0_Status & ~0xf1000018;
866
    t0 |= tcstatus & (0xf << CP0TCSt_TCU0);
867
    t0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX);
868
    t0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_KSU);
869

    
870
    return t0;
871
}
872

    
873
target_ulong helper_mfc0_lladdr (void)
874
{
875
    return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift);
876
}
877

    
878
target_ulong helper_mfc0_watchlo (uint32_t sel)
879
{
880
    return (int32_t)env->CP0_WatchLo[sel];
881
}
882

    
883
target_ulong helper_mfc0_watchhi (uint32_t sel)
884
{
885
    return env->CP0_WatchHi[sel];
886
}
887

    
888
target_ulong helper_mfc0_debug (void)
889
{
890
    target_ulong t0 = env->CP0_Debug;
891
    if (env->hflags & MIPS_HFLAG_DM)
892
        t0 |= 1 << CP0DB_DM;
893

    
894
    return t0;
895
}
896

    
897
target_ulong helper_mftc0_debug(void)
898
{
899
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
900
    int32_t tcstatus;
901

    
902
    if (other_tc == env->current_tc)
903
        tcstatus = env->active_tc.CP0_Debug_tcstatus;
904
    else
905
        tcstatus = env->tcs[other_tc].CP0_Debug_tcstatus;
906

    
907
    /* XXX: Might be wrong, check with EJTAG spec. */
908
    return (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
909
            (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
910
}
911

    
912
#if defined(TARGET_MIPS64)
913
target_ulong helper_dmfc0_tcrestart (void)
914
{
915
    return env->active_tc.PC;
916
}
917

    
918
target_ulong helper_dmfc0_tchalt (void)
919
{
920
    return env->active_tc.CP0_TCHalt;
921
}
922

    
923
target_ulong helper_dmfc0_tccontext (void)
924
{
925
    return env->active_tc.CP0_TCContext;
926
}
927

    
928
target_ulong helper_dmfc0_tcschedule (void)
929
{
930
    return env->active_tc.CP0_TCSchedule;
931
}
932

    
933
target_ulong helper_dmfc0_tcschefback (void)
934
{
935
    return env->active_tc.CP0_TCScheFBack;
936
}
937

    
938
target_ulong helper_dmfc0_lladdr (void)
939
{
940
    return env->lladdr >> env->CP0_LLAddr_shift;
941
}
942

    
943
target_ulong helper_dmfc0_watchlo (uint32_t sel)
944
{
945
    return env->CP0_WatchLo[sel];
946
}
947
#endif /* TARGET_MIPS64 */
948

    
949
void helper_mtc0_index (target_ulong arg1)
950
{
951
    int num = 1;
952
    unsigned int tmp = env->tlb->nb_tlb;
953

    
954
    do {
955
        tmp >>= 1;
956
        num <<= 1;
957
    } while (tmp);
958
    env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1));
959
}
960

    
961
void helper_mtc0_mvpcontrol (target_ulong arg1)
962
{
963
    uint32_t mask = 0;
964
    uint32_t newval;
965

    
966
    if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))
967
        mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
968
                (1 << CP0MVPCo_EVP);
969
    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
970
        mask |= (1 << CP0MVPCo_STLB);
971
    newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
972

    
973
    // TODO: Enable/disable shared TLB, enable/disable VPEs.
974

    
975
    env->mvp->CP0_MVPControl = newval;
976
}
977

    
978
void helper_mtc0_vpecontrol (target_ulong arg1)
979
{
980
    uint32_t mask;
981
    uint32_t newval;
982

    
983
    mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
984
           (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
985
    newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
986

    
987
    /* Yield scheduler intercept not implemented. */
988
    /* Gating storage scheduler intercept not implemented. */
989

    
990
    // TODO: Enable/disable TCs.
991

    
992
    env->CP0_VPEControl = newval;
993
}
994

    
995
void helper_mtc0_vpeconf0 (target_ulong arg1)
996
{
997
    uint32_t mask = 0;
998
    uint32_t newval;
999

    
1000
    if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
1001
        if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))
1002
            mask |= (0xff << CP0VPEC0_XTC);
1003
        mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
1004
    }
1005
    newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
1006

    
1007
    // TODO: TC exclusive handling due to ERL/EXL.
1008

    
1009
    env->CP0_VPEConf0 = newval;
1010
}
1011

    
1012
void helper_mtc0_vpeconf1 (target_ulong arg1)
1013
{
1014
    uint32_t mask = 0;
1015
    uint32_t newval;
1016

    
1017
    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1018
        mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
1019
                (0xff << CP0VPEC1_NCP1);
1020
    newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
1021

    
1022
    /* UDI not implemented. */
1023
    /* CP2 not implemented. */
1024

    
1025
    // TODO: Handle FPU (CP1) binding.
1026

    
1027
    env->CP0_VPEConf1 = newval;
1028
}
1029

    
1030
void helper_mtc0_yqmask (target_ulong arg1)
1031
{
1032
    /* Yield qualifier inputs not implemented. */
1033
    env->CP0_YQMask = 0x00000000;
1034
}
1035

    
1036
void helper_mtc0_vpeopt (target_ulong arg1)
1037
{
1038
    env->CP0_VPEOpt = arg1 & 0x0000ffff;
1039
}
1040

    
1041
void helper_mtc0_entrylo0 (target_ulong arg1)
1042
{
1043
    /* Large physaddr (PABITS) not implemented */
1044
    /* 1k pages not implemented */
1045
    env->CP0_EntryLo0 = arg1 & 0x3FFFFFFF;
1046
}
1047

    
1048
void helper_mtc0_tcstatus (target_ulong arg1)
1049
{
1050
    uint32_t mask = env->CP0_TCStatus_rw_bitmask;
1051
    uint32_t newval;
1052

    
1053
    newval = (env->active_tc.CP0_TCStatus & ~mask) | (arg1 & mask);
1054

    
1055
    // TODO: Sync with CP0_Status.
1056

    
1057
    env->active_tc.CP0_TCStatus = newval;
1058
}
1059

    
1060
void helper_mttc0_tcstatus (target_ulong arg1)
1061
{
1062
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1063

    
1064
    // TODO: Sync with CP0_Status.
1065

    
1066
    if (other_tc == env->current_tc)
1067
        env->active_tc.CP0_TCStatus = arg1;
1068
    else
1069
        env->tcs[other_tc].CP0_TCStatus = arg1;
1070
}
1071

    
1072
void helper_mtc0_tcbind (target_ulong arg1)
1073
{
1074
    uint32_t mask = (1 << CP0TCBd_TBE);
1075
    uint32_t newval;
1076

    
1077
    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1078
        mask |= (1 << CP0TCBd_CurVPE);
1079
    newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1080
    env->active_tc.CP0_TCBind = newval;
1081
}
1082

    
1083
void helper_mttc0_tcbind (target_ulong arg1)
1084
{
1085
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1086
    uint32_t mask = (1 << CP0TCBd_TBE);
1087
    uint32_t newval;
1088

    
1089
    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
1090
        mask |= (1 << CP0TCBd_CurVPE);
1091
    if (other_tc == env->current_tc) {
1092
        newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
1093
        env->active_tc.CP0_TCBind = newval;
1094
    } else {
1095
        newval = (env->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
1096
        env->tcs[other_tc].CP0_TCBind = newval;
1097
    }
1098
}
1099

    
1100
void helper_mtc0_tcrestart (target_ulong arg1)
1101
{
1102
    env->active_tc.PC = arg1;
1103
    env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1104
    env->lladdr = 0ULL;
1105
    /* MIPS16 not implemented. */
1106
}
1107

    
1108
void helper_mttc0_tcrestart (target_ulong arg1)
1109
{
1110
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1111

    
1112
    if (other_tc == env->current_tc) {
1113
        env->active_tc.PC = arg1;
1114
        env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1115
        env->lladdr = 0ULL;
1116
        /* MIPS16 not implemented. */
1117
    } else {
1118
        env->tcs[other_tc].PC = arg1;
1119
        env->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1120
        env->lladdr = 0ULL;
1121
        /* MIPS16 not implemented. */
1122
    }
1123
}
1124

    
1125
void helper_mtc0_tchalt (target_ulong arg1)
1126
{
1127
    env->active_tc.CP0_TCHalt = arg1 & 0x1;
1128

    
1129
    // TODO: Halt TC / Restart (if allocated+active) TC.
1130
}
1131

    
1132
void helper_mttc0_tchalt (target_ulong arg1)
1133
{
1134
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1135

    
1136
    // TODO: Halt TC / Restart (if allocated+active) TC.
1137

    
1138
    if (other_tc == env->current_tc)
1139
        env->active_tc.CP0_TCHalt = arg1;
1140
    else
1141
        env->tcs[other_tc].CP0_TCHalt = arg1;
1142
}
1143

    
1144
void helper_mtc0_tccontext (target_ulong arg1)
1145
{
1146
    env->active_tc.CP0_TCContext = arg1;
1147
}
1148

    
1149
void helper_mttc0_tccontext (target_ulong arg1)
1150
{
1151
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1152

    
1153
    if (other_tc == env->current_tc)
1154
        env->active_tc.CP0_TCContext = arg1;
1155
    else
1156
        env->tcs[other_tc].CP0_TCContext = arg1;
1157
}
1158

    
1159
void helper_mtc0_tcschedule (target_ulong arg1)
1160
{
1161
    env->active_tc.CP0_TCSchedule = arg1;
1162
}
1163

    
1164
void helper_mttc0_tcschedule (target_ulong arg1)
1165
{
1166
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1167

    
1168
    if (other_tc == env->current_tc)
1169
        env->active_tc.CP0_TCSchedule = arg1;
1170
    else
1171
        env->tcs[other_tc].CP0_TCSchedule = arg1;
1172
}
1173

    
1174
void helper_mtc0_tcschefback (target_ulong arg1)
1175
{
1176
    env->active_tc.CP0_TCScheFBack = arg1;
1177
}
1178

    
1179
void helper_mttc0_tcschefback (target_ulong arg1)
1180
{
1181
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1182

    
1183
    if (other_tc == env->current_tc)
1184
        env->active_tc.CP0_TCScheFBack = arg1;
1185
    else
1186
        env->tcs[other_tc].CP0_TCScheFBack = arg1;
1187
}
1188

    
1189
void helper_mtc0_entrylo1 (target_ulong arg1)
1190
{
1191
    /* Large physaddr (PABITS) not implemented */
1192
    /* 1k pages not implemented */
1193
    env->CP0_EntryLo1 = arg1 & 0x3FFFFFFF;
1194
}
1195

    
1196
void helper_mtc0_context (target_ulong arg1)
1197
{
1198
    env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
1199
}
1200

    
1201
void helper_mtc0_pagemask (target_ulong arg1)
1202
{
1203
    /* 1k pages not implemented */
1204
    env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1205
}
1206

    
1207
void helper_mtc0_pagegrain (target_ulong arg1)
1208
{
1209
    /* SmartMIPS not implemented */
1210
    /* Large physaddr (PABITS) not implemented */
1211
    /* 1k pages not implemented */
1212
    env->CP0_PageGrain = 0;
1213
}
1214

    
1215
void helper_mtc0_wired (target_ulong arg1)
1216
{
1217
    env->CP0_Wired = arg1 % env->tlb->nb_tlb;
1218
}
1219

    
1220
void helper_mtc0_srsconf0 (target_ulong arg1)
1221
{
1222
    env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
1223
}
1224

    
1225
void helper_mtc0_srsconf1 (target_ulong arg1)
1226
{
1227
    env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
1228
}
1229

    
1230
void helper_mtc0_srsconf2 (target_ulong arg1)
1231
{
1232
    env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
1233
}
1234

    
1235
void helper_mtc0_srsconf3 (target_ulong arg1)
1236
{
1237
    env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
1238
}
1239

    
1240
void helper_mtc0_srsconf4 (target_ulong arg1)
1241
{
1242
    env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
1243
}
1244

    
1245
void helper_mtc0_hwrena (target_ulong arg1)
1246
{
1247
    env->CP0_HWREna = arg1 & 0x0000000F;
1248
}
1249

    
1250
void helper_mtc0_count (target_ulong arg1)
1251
{
1252
    cpu_mips_store_count(env, arg1);
1253
}
1254

    
1255
void helper_mtc0_entryhi (target_ulong arg1)
1256
{
1257
    target_ulong old, val;
1258

    
1259
    /* 1k pages not implemented */
1260
    val = arg1 & ((TARGET_PAGE_MASK << 1) | 0xFF);
1261
#if defined(TARGET_MIPS64)
1262
    val &= env->SEGMask;
1263
#endif
1264
    old = env->CP0_EntryHi;
1265
    env->CP0_EntryHi = val;
1266
    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
1267
        uint32_t tcst = env->active_tc.CP0_TCStatus & ~0xff;
1268
        env->active_tc.CP0_TCStatus = tcst | (val & 0xff);
1269
    }
1270
    /* If the ASID changes, flush qemu's TLB.  */
1271
    if ((old & 0xFF) != (val & 0xFF))
1272
        cpu_mips_tlb_flush(env, 1);
1273
}
1274

    
1275
void helper_mttc0_entryhi(target_ulong arg1)
1276
{
1277
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1278
    int32_t tcstatus;
1279

    
1280
    env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (arg1 & ~0xff);
1281
    if (other_tc == env->current_tc) {
1282
        tcstatus = (env->active_tc.CP0_TCStatus & ~0xff) | (arg1 & 0xff);
1283
        env->active_tc.CP0_TCStatus = tcstatus;
1284
    } else {
1285
        tcstatus = (env->tcs[other_tc].CP0_TCStatus & ~0xff) | (arg1 & 0xff);
1286
        env->tcs[other_tc].CP0_TCStatus = tcstatus;
1287
    }
1288
}
1289

    
1290
void helper_mtc0_compare (target_ulong arg1)
1291
{
1292
    cpu_mips_store_compare(env, arg1);
1293
}
1294

    
1295
void helper_mtc0_status (target_ulong arg1)
1296
{
1297
    uint32_t val, old;
1298
    uint32_t mask = env->CP0_Status_rw_bitmask;
1299

    
1300
    val = arg1 & mask;
1301
    old = env->CP0_Status;
1302
    env->CP0_Status = (env->CP0_Status & ~mask) | val;
1303
    compute_hflags(env);
1304
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1305
        qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
1306
                old, old & env->CP0_Cause & CP0Ca_IP_mask,
1307
                val, val & env->CP0_Cause & CP0Ca_IP_mask,
1308
                env->CP0_Cause);
1309
        switch (env->hflags & MIPS_HFLAG_KSU) {
1310
        case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1311
        case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1312
        case MIPS_HFLAG_KM: qemu_log("\n"); break;
1313
        default: cpu_abort(env, "Invalid MMU mode!\n"); break;
1314
        }
1315
    }
1316
}
1317

    
1318
void helper_mttc0_status(target_ulong arg1)
1319
{
1320
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1321
    int32_t tcstatus = env->tcs[other_tc].CP0_TCStatus;
1322

    
1323
    env->CP0_Status = arg1 & ~0xf1000018;
1324
    tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (arg1 & (0xf << CP0St_CU0));
1325
    tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((arg1 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX));
1326
    tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((arg1 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU));
1327
    if (other_tc == env->current_tc)
1328
        env->active_tc.CP0_TCStatus = tcstatus;
1329
    else
1330
        env->tcs[other_tc].CP0_TCStatus = tcstatus;
1331
}
1332

    
1333
void helper_mtc0_intctl (target_ulong arg1)
1334
{
1335
    /* vectored interrupts not implemented, no performance counters. */
1336
    env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (arg1 & 0x000002e0);
1337
}
1338

    
1339
void helper_mtc0_srsctl (target_ulong arg1)
1340
{
1341
    uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
1342
    env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
1343
}
1344

    
1345
void helper_mtc0_cause (target_ulong arg1)
1346
{
1347
    uint32_t mask = 0x00C00300;
1348
    uint32_t old = env->CP0_Cause;
1349

    
1350
    if (env->insn_flags & ISA_MIPS32R2)
1351
        mask |= 1 << CP0Ca_DC;
1352

    
1353
    env->CP0_Cause = (env->CP0_Cause & ~mask) | (arg1 & mask);
1354

    
1355
    if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) {
1356
        if (env->CP0_Cause & (1 << CP0Ca_DC))
1357
            cpu_mips_stop_count(env);
1358
        else
1359
            cpu_mips_start_count(env);
1360
    }
1361
}
1362

    
1363
void helper_mtc0_ebase (target_ulong arg1)
1364
{
1365
    /* vectored interrupts not implemented */
1366
    /* Multi-CPU not implemented */
1367
    env->CP0_EBase = 0x80000000 | (arg1 & 0x3FFFF000);
1368
}
1369

    
1370
void helper_mtc0_config0 (target_ulong arg1)
1371
{
1372
    env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
1373
}
1374

    
1375
void helper_mtc0_config2 (target_ulong arg1)
1376
{
1377
    /* tertiary/secondary caches not implemented */
1378
    env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
1379
}
1380

    
1381
void helper_mtc0_lladdr (target_ulong arg1)
1382
{
1383
    target_long mask = env->CP0_LLAddr_rw_bitmask;
1384
    arg1 = arg1 << env->CP0_LLAddr_shift;
1385
    env->lladdr = (env->lladdr & ~mask) | (arg1 & mask);
1386
}
1387

    
1388
void helper_mtc0_watchlo (target_ulong arg1, uint32_t sel)
1389
{
1390
    /* Watch exceptions for instructions, data loads, data stores
1391
       not implemented. */
1392
    env->CP0_WatchLo[sel] = (arg1 & ~0x7);
1393
}
1394

    
1395
void helper_mtc0_watchhi (target_ulong arg1, uint32_t sel)
1396
{
1397
    env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8);
1398
    env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
1399
}
1400

    
1401
void helper_mtc0_xcontext (target_ulong arg1)
1402
{
1403
    target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
1404
    env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
1405
}
1406

    
1407
void helper_mtc0_framemask (target_ulong arg1)
1408
{
1409
    env->CP0_Framemask = arg1; /* XXX */
1410
}
1411

    
1412
void helper_mtc0_debug (target_ulong arg1)
1413
{
1414
    env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
1415
    if (arg1 & (1 << CP0DB_DM))
1416
        env->hflags |= MIPS_HFLAG_DM;
1417
    else
1418
        env->hflags &= ~MIPS_HFLAG_DM;
1419
}
1420

    
1421
void helper_mttc0_debug(target_ulong arg1)
1422
{
1423
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1424
    uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
1425

    
1426
    /* XXX: Might be wrong, check with EJTAG spec. */
1427
    if (other_tc == env->current_tc)
1428
        env->active_tc.CP0_Debug_tcstatus = val;
1429
    else
1430
        env->tcs[other_tc].CP0_Debug_tcstatus = val;
1431
    env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1432
                     (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1433
}
1434

    
1435
void helper_mtc0_performance0 (target_ulong arg1)
1436
{
1437
    env->CP0_Performance0 = arg1 & 0x000007ff;
1438
}
1439

    
1440
void helper_mtc0_taglo (target_ulong arg1)
1441
{
1442
    env->CP0_TagLo = arg1 & 0xFFFFFCF6;
1443
}
1444

    
1445
void helper_mtc0_datalo (target_ulong arg1)
1446
{
1447
    env->CP0_DataLo = arg1; /* XXX */
1448
}
1449

    
1450
void helper_mtc0_taghi (target_ulong arg1)
1451
{
1452
    env->CP0_TagHi = arg1; /* XXX */
1453
}
1454

    
1455
void helper_mtc0_datahi (target_ulong arg1)
1456
{
1457
    env->CP0_DataHi = arg1; /* XXX */
1458
}
1459

    
1460
/* MIPS MT functions */
1461
target_ulong helper_mftgpr(uint32_t sel)
1462
{
1463
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1464

    
1465
    if (other_tc == env->current_tc)
1466
        return env->active_tc.gpr[sel];
1467
    else
1468
        return env->tcs[other_tc].gpr[sel];
1469
}
1470

    
1471
target_ulong helper_mftlo(uint32_t sel)
1472
{
1473
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1474

    
1475
    if (other_tc == env->current_tc)
1476
        return env->active_tc.LO[sel];
1477
    else
1478
        return env->tcs[other_tc].LO[sel];
1479
}
1480

    
1481
target_ulong helper_mfthi(uint32_t sel)
1482
{
1483
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1484

    
1485
    if (other_tc == env->current_tc)
1486
        return env->active_tc.HI[sel];
1487
    else
1488
        return env->tcs[other_tc].HI[sel];
1489
}
1490

    
1491
target_ulong helper_mftacx(uint32_t sel)
1492
{
1493
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1494

    
1495
    if (other_tc == env->current_tc)
1496
        return env->active_tc.ACX[sel];
1497
    else
1498
        return env->tcs[other_tc].ACX[sel];
1499
}
1500

    
1501
target_ulong helper_mftdsp(void)
1502
{
1503
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1504

    
1505
    if (other_tc == env->current_tc)
1506
        return env->active_tc.DSPControl;
1507
    else
1508
        return env->tcs[other_tc].DSPControl;
1509
}
1510

    
1511
void helper_mttgpr(target_ulong arg1, uint32_t sel)
1512
{
1513
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1514

    
1515
    if (other_tc == env->current_tc)
1516
        env->active_tc.gpr[sel] = arg1;
1517
    else
1518
        env->tcs[other_tc].gpr[sel] = arg1;
1519
}
1520

    
1521
void helper_mttlo(target_ulong arg1, uint32_t sel)
1522
{
1523
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1524

    
1525
    if (other_tc == env->current_tc)
1526
        env->active_tc.LO[sel] = arg1;
1527
    else
1528
        env->tcs[other_tc].LO[sel] = arg1;
1529
}
1530

    
1531
void helper_mtthi(target_ulong arg1, uint32_t sel)
1532
{
1533
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1534

    
1535
    if (other_tc == env->current_tc)
1536
        env->active_tc.HI[sel] = arg1;
1537
    else
1538
        env->tcs[other_tc].HI[sel] = arg1;
1539
}
1540

    
1541
void helper_mttacx(target_ulong arg1, uint32_t sel)
1542
{
1543
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1544

    
1545
    if (other_tc == env->current_tc)
1546
        env->active_tc.ACX[sel] = arg1;
1547
    else
1548
        env->tcs[other_tc].ACX[sel] = arg1;
1549
}
1550

    
1551
void helper_mttdsp(target_ulong arg1)
1552
{
1553
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1554

    
1555
    if (other_tc == env->current_tc)
1556
        env->active_tc.DSPControl = arg1;
1557
    else
1558
        env->tcs[other_tc].DSPControl = arg1;
1559
}
1560

    
1561
/* MIPS MT functions */
1562
target_ulong helper_dmt(target_ulong arg1)
1563
{
1564
    // TODO
1565
    arg1 = 0;
1566
    // rt = arg1
1567

    
1568
    return arg1;
1569
}
1570

    
1571
target_ulong helper_emt(target_ulong arg1)
1572
{
1573
    // TODO
1574
    arg1 = 0;
1575
    // rt = arg1
1576

    
1577
    return arg1;
1578
}
1579

    
1580
target_ulong helper_dvpe(target_ulong arg1)
1581
{
1582
    // TODO
1583
    arg1 = 0;
1584
    // rt = arg1
1585

    
1586
    return arg1;
1587
}
1588

    
1589
target_ulong helper_evpe(target_ulong arg1)
1590
{
1591
    // TODO
1592
    arg1 = 0;
1593
    // rt = arg1
1594

    
1595
    return arg1;
1596
}
1597
#endif /* !CONFIG_USER_ONLY */
1598

    
1599
void helper_fork(target_ulong arg1, target_ulong arg2)
1600
{
1601
    // arg1 = rt, arg2 = rs
1602
    arg1 = 0;
1603
    // TODO: store to TC register
1604
}
1605

    
1606
target_ulong helper_yield(target_ulong arg1)
1607
{
1608
    if (arg1 < 0) {
1609
        /* No scheduling policy implemented. */
1610
        if (arg1 != -2) {
1611
            if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
1612
                env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
1613
                env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1614
                env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
1615
                helper_raise_exception(EXCP_THREAD);
1616
            }
1617
        }
1618
    } else if (arg1 == 0) {
1619
        if (0 /* TODO: TC underflow */) {
1620
            env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1621
            helper_raise_exception(EXCP_THREAD);
1622
        } else {
1623
            // TODO: Deallocate TC
1624
        }
1625
    } else if (arg1 > 0) {
1626
        /* Yield qualifier inputs not implemented. */
1627
        env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1628
        env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
1629
        helper_raise_exception(EXCP_THREAD);
1630
    }
1631
    return env->CP0_YQMask;
1632
}
1633

    
1634
#ifndef CONFIG_USER_ONLY
1635
/* TLB management */
1636
static void cpu_mips_tlb_flush (CPUState *env, int flush_global)
1637
{
1638
    /* Flush qemu's TLB and discard all shadowed entries.  */
1639
    tlb_flush (env, flush_global);
1640
    env->tlb->tlb_in_use = env->tlb->nb_tlb;
1641
}
1642

    
1643
static void r4k_mips_tlb_flush_extra (CPUState *env, int first)
1644
{
1645
    /* Discard entries from env->tlb[first] onwards.  */
1646
    while (env->tlb->tlb_in_use > first) {
1647
        r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
1648
    }
1649
}
1650

    
1651
static void r4k_fill_tlb (int idx)
1652
{
1653
    r4k_tlb_t *tlb;
1654

    
1655
    /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
1656
    tlb = &env->tlb->mmu.r4k.tlb[idx];
1657
    tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
1658
#if defined(TARGET_MIPS64)
1659
    tlb->VPN &= env->SEGMask;
1660
#endif
1661
    tlb->ASID = env->CP0_EntryHi & 0xFF;
1662
    tlb->PageMask = env->CP0_PageMask;
1663
    tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
1664
    tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
1665
    tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
1666
    tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
1667
    tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
1668
    tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
1669
    tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
1670
    tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
1671
    tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
1672
}
1673

    
1674
void r4k_helper_tlbwi (void)
1675
{
1676
    int idx;
1677

    
1678
    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
1679

    
1680
    /* Discard cached TLB entries.  We could avoid doing this if the
1681
       tlbwi is just upgrading access permissions on the current entry;
1682
       that might be a further win.  */
1683
    r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb);
1684

    
1685
    r4k_invalidate_tlb(env, idx, 0);
1686
    r4k_fill_tlb(idx);
1687
}
1688

    
1689
void r4k_helper_tlbwr (void)
1690
{
1691
    int r = cpu_mips_get_random(env);
1692

    
1693
    r4k_invalidate_tlb(env, r, 1);
1694
    r4k_fill_tlb(r);
1695
}
1696

    
1697
void r4k_helper_tlbp (void)
1698
{
1699
    r4k_tlb_t *tlb;
1700
    target_ulong mask;
1701
    target_ulong tag;
1702
    target_ulong VPN;
1703
    uint8_t ASID;
1704
    int i;
1705

    
1706
    ASID = env->CP0_EntryHi & 0xFF;
1707
    for (i = 0; i < env->tlb->nb_tlb; i++) {
1708
        tlb = &env->tlb->mmu.r4k.tlb[i];
1709
        /* 1k pages are not supported. */
1710
        mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1711
        tag = env->CP0_EntryHi & ~mask;
1712
        VPN = tlb->VPN & ~mask;
1713
        /* Check ASID, virtual page number & size */
1714
        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
1715
            /* TLB match */
1716
            env->CP0_Index = i;
1717
            break;
1718
        }
1719
    }
1720
    if (i == env->tlb->nb_tlb) {
1721
        /* No match.  Discard any shadow entries, if any of them match.  */
1722
        for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
1723
            tlb = &env->tlb->mmu.r4k.tlb[i];
1724
            /* 1k pages are not supported. */
1725
            mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1726
            tag = env->CP0_EntryHi & ~mask;
1727
            VPN = tlb->VPN & ~mask;
1728
            /* Check ASID, virtual page number & size */
1729
            if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
1730
                r4k_mips_tlb_flush_extra (env, i);
1731
                break;
1732
            }
1733
        }
1734

    
1735
        env->CP0_Index |= 0x80000000;
1736
    }
1737
}
1738

    
1739
void r4k_helper_tlbr (void)
1740
{
1741
    r4k_tlb_t *tlb;
1742
    uint8_t ASID;
1743
    int idx;
1744

    
1745
    ASID = env->CP0_EntryHi & 0xFF;
1746
    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
1747
    tlb = &env->tlb->mmu.r4k.tlb[idx];
1748

    
1749
    /* If this will change the current ASID, flush qemu's TLB.  */
1750
    if (ASID != tlb->ASID)
1751
        cpu_mips_tlb_flush (env, 1);
1752

    
1753
    r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
1754

    
1755
    env->CP0_EntryHi = tlb->VPN | tlb->ASID;
1756
    env->CP0_PageMask = tlb->PageMask;
1757
    env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
1758
                        (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
1759
    env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
1760
                        (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
1761
}
1762

    
1763
void helper_tlbwi(void)
1764
{
1765
    env->tlb->helper_tlbwi();
1766
}
1767

    
1768
void helper_tlbwr(void)
1769
{
1770
    env->tlb->helper_tlbwr();
1771
}
1772

    
1773
void helper_tlbp(void)
1774
{
1775
    env->tlb->helper_tlbp();
1776
}
1777

    
1778
void helper_tlbr(void)
1779
{
1780
    env->tlb->helper_tlbr();
1781
}
1782

    
1783
/* Specials */
1784
target_ulong helper_di (void)
1785
{
1786
    target_ulong t0 = env->CP0_Status;
1787

    
1788
    env->CP0_Status = t0 & ~(1 << CP0St_IE);
1789
    return t0;
1790
}
1791

    
1792
target_ulong helper_ei (void)
1793
{
1794
    target_ulong t0 = env->CP0_Status;
1795

    
1796
    env->CP0_Status = t0 | (1 << CP0St_IE);
1797
    return t0;
1798
}
1799

    
1800
static void debug_pre_eret (void)
1801
{
1802
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1803
        qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1804
                env->active_tc.PC, env->CP0_EPC);
1805
        if (env->CP0_Status & (1 << CP0St_ERL))
1806
            qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1807
        if (env->hflags & MIPS_HFLAG_DM)
1808
            qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1809
        qemu_log("\n");
1810
    }
1811
}
1812

    
1813
static void debug_post_eret (void)
1814
{
1815
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1816
        qemu_log("  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1817
                env->active_tc.PC, env->CP0_EPC);
1818
        if (env->CP0_Status & (1 << CP0St_ERL))
1819
            qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1820
        if (env->hflags & MIPS_HFLAG_DM)
1821
            qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1822
        switch (env->hflags & MIPS_HFLAG_KSU) {
1823
        case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1824
        case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1825
        case MIPS_HFLAG_KM: qemu_log("\n"); break;
1826
        default: cpu_abort(env, "Invalid MMU mode!\n"); break;
1827
        }
1828
    }
1829
}
1830

    
1831
static void set_pc (target_ulong error_pc)
1832
{
1833
    env->active_tc.PC = error_pc & ~(target_ulong)1;
1834
    if (error_pc & 1) {
1835
        env->hflags |= MIPS_HFLAG_M16;
1836
    } else {
1837
        env->hflags &= ~(MIPS_HFLAG_M16);
1838
    }
1839
}
1840

    
1841
void helper_eret (void)
1842
{
1843
    debug_pre_eret();
1844
    if (env->CP0_Status & (1 << CP0St_ERL)) {
1845
        set_pc(env->CP0_ErrorEPC);
1846
        env->CP0_Status &= ~(1 << CP0St_ERL);
1847
    } else {
1848
        set_pc(env->CP0_EPC);
1849
        env->CP0_Status &= ~(1 << CP0St_EXL);
1850
    }
1851
    compute_hflags(env);
1852
    debug_post_eret();
1853
    env->lladdr = 1;
1854
}
1855

    
1856
void helper_deret (void)
1857
{
1858
    debug_pre_eret();
1859
    set_pc(env->CP0_DEPC);
1860

    
1861
    env->hflags &= MIPS_HFLAG_DM;
1862
    compute_hflags(env);
1863
    debug_post_eret();
1864
    env->lladdr = 1;
1865
}
1866
#endif /* !CONFIG_USER_ONLY */
1867

    
1868
target_ulong helper_rdhwr_cpunum(void)
1869
{
1870
    if ((env->hflags & MIPS_HFLAG_CP0) ||
1871
        (env->CP0_HWREna & (1 << 0)))
1872
        return env->CP0_EBase & 0x3ff;
1873
    else
1874
        helper_raise_exception(EXCP_RI);
1875

    
1876
    return 0;
1877
}
1878

    
1879
target_ulong helper_rdhwr_synci_step(void)
1880
{
1881
    if ((env->hflags & MIPS_HFLAG_CP0) ||
1882
        (env->CP0_HWREna & (1 << 1)))
1883
        return env->SYNCI_Step;
1884
    else
1885
        helper_raise_exception(EXCP_RI);
1886

    
1887
    return 0;
1888
}
1889

    
1890
target_ulong helper_rdhwr_cc(void)
1891
{
1892
    if ((env->hflags & MIPS_HFLAG_CP0) ||
1893
        (env->CP0_HWREna & (1 << 2)))
1894
        return env->CP0_Count;
1895
    else
1896
        helper_raise_exception(EXCP_RI);
1897

    
1898
    return 0;
1899
}
1900

    
1901
target_ulong helper_rdhwr_ccres(void)
1902
{
1903
    if ((env->hflags & MIPS_HFLAG_CP0) ||
1904
        (env->CP0_HWREna & (1 << 3)))
1905
        return env->CCRes;
1906
    else
1907
        helper_raise_exception(EXCP_RI);
1908

    
1909
    return 0;
1910
}
1911

    
1912
void helper_pmon (int function)
1913
{
1914
    function /= 2;
1915
    switch (function) {
1916
    case 2: /* TODO: char inbyte(int waitflag); */
1917
        if (env->active_tc.gpr[4] == 0)
1918
            env->active_tc.gpr[2] = -1;
1919
        /* Fall through */
1920
    case 11: /* TODO: char inbyte (void); */
1921
        env->active_tc.gpr[2] = -1;
1922
        break;
1923
    case 3:
1924
    case 12:
1925
        printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
1926
        break;
1927
    case 17:
1928
        break;
1929
    case 158:
1930
        {
1931
            unsigned char *fmt = (void *)(unsigned long)env->active_tc.gpr[4];
1932
            printf("%s", fmt);
1933
        }
1934
        break;
1935
    }
1936
}
1937

    
1938
void helper_wait (void)
1939
{
1940
    env->halted = 1;
1941
    helper_raise_exception(EXCP_HLT);
1942
}
1943

    
1944
#if !defined(CONFIG_USER_ONLY)
1945

    
1946
static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
1947

    
1948
#define MMUSUFFIX _mmu
1949
#define ALIGNED_ONLY
1950

    
1951
#define SHIFT 0
1952
#include "softmmu_template.h"
1953

    
1954
#define SHIFT 1
1955
#include "softmmu_template.h"
1956

    
1957
#define SHIFT 2
1958
#include "softmmu_template.h"
1959

    
1960
#define SHIFT 3
1961
#include "softmmu_template.h"
1962

    
1963
static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
1964
{
1965
    env->CP0_BadVAddr = addr;
1966
    do_restore_state (retaddr);
1967
    helper_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
1968
}
1969

    
1970
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
1971
{
1972
    TranslationBlock *tb;
1973
    CPUState *saved_env;
1974
    unsigned long pc;
1975
    int ret;
1976

    
1977
    /* XXX: hack to restore env in all cases, even if not called from
1978
       generated code */
1979
    saved_env = env;
1980
    env = cpu_single_env;
1981
    ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
1982
    if (ret) {
1983
        if (retaddr) {
1984
            /* now we have a real cpu fault */
1985
            pc = (unsigned long)retaddr;
1986
            tb = tb_find_pc(pc);
1987
            if (tb) {
1988
                /* the PC is inside the translated code. It means that we have
1989
                   a virtual CPU fault */
1990
                cpu_restore_state(tb, env, pc, NULL);
1991
            }
1992
        }
1993
        helper_raise_exception_err(env->exception_index, env->error_code);
1994
    }
1995
    env = saved_env;
1996
}
1997

    
1998
void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
1999
                          int unused, int size)
2000
{
2001
    if (is_exec)
2002
        helper_raise_exception(EXCP_IBE);
2003
    else
2004
        helper_raise_exception(EXCP_DBE);
2005
}
2006
#endif /* !CONFIG_USER_ONLY */
2007

    
2008
/* Complex FPU operations which may need stack space. */
2009

    
2010
#define FLOAT_ONE32 make_float32(0x3f8 << 20)
2011
#define FLOAT_ONE64 make_float64(0x3ffULL << 52)
2012
#define FLOAT_TWO32 make_float32(1 << 30)
2013
#define FLOAT_TWO64 make_float64(1ULL << 62)
2014
#define FLOAT_QNAN32 0x7fbfffff
2015
#define FLOAT_QNAN64 0x7ff7ffffffffffffULL
2016
#define FLOAT_SNAN32 0x7fffffff
2017
#define FLOAT_SNAN64 0x7fffffffffffffffULL
2018

    
2019
/* convert MIPS rounding mode in FCR31 to IEEE library */
2020
static unsigned int ieee_rm[] = {
2021
    float_round_nearest_even,
2022
    float_round_to_zero,
2023
    float_round_up,
2024
    float_round_down
2025
};
2026

    
2027
#define RESTORE_ROUNDING_MODE \
2028
    set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status)
2029

    
2030
#define RESTORE_FLUSH_MODE \
2031
    set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status);
2032

    
2033
target_ulong helper_cfc1 (uint32_t reg)
2034
{
2035
    target_ulong arg1;
2036

    
2037
    switch (reg) {
2038
    case 0:
2039
        arg1 = (int32_t)env->active_fpu.fcr0;
2040
        break;
2041
    case 25:
2042
        arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
2043
        break;
2044
    case 26:
2045
        arg1 = env->active_fpu.fcr31 & 0x0003f07c;
2046
        break;
2047
    case 28:
2048
        arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
2049
        break;
2050
    default:
2051
        arg1 = (int32_t)env->active_fpu.fcr31;
2052
        break;
2053
    }
2054

    
2055
    return arg1;
2056
}
2057

    
2058
void helper_ctc1 (target_ulong arg1, uint32_t reg)
2059
{
2060
    switch(reg) {
2061
    case 25:
2062
        if (arg1 & 0xffffff00)
2063
            return;
2064
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
2065
                     ((arg1 & 0x1) << 23);
2066
        break;
2067
    case 26:
2068
        if (arg1 & 0x007c0000)
2069
            return;
2070
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
2071
        break;
2072
    case 28:
2073
        if (arg1 & 0x007c0000)
2074
            return;
2075
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
2076
                     ((arg1 & 0x4) << 22);
2077
        break;
2078
    case 31:
2079
        if (arg1 & 0x007c0000)
2080
            return;
2081
        env->active_fpu.fcr31 = arg1;
2082
        break;
2083
    default:
2084
        return;
2085
    }
2086
    /* set rounding mode */
2087
    RESTORE_ROUNDING_MODE;
2088
    /* set flush-to-zero mode */
2089
    RESTORE_FLUSH_MODE;
2090
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2091
    if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
2092
        helper_raise_exception(EXCP_FPE);
2093
}
2094

    
2095
static inline char ieee_ex_to_mips(char xcpt)
2096
{
2097
    return (xcpt & float_flag_inexact) >> 5 |
2098
           (xcpt & float_flag_underflow) >> 3 |
2099
           (xcpt & float_flag_overflow) >> 1 |
2100
           (xcpt & float_flag_divbyzero) << 1 |
2101
           (xcpt & float_flag_invalid) << 4;
2102
}
2103

    
2104
static inline char mips_ex_to_ieee(char xcpt)
2105
{
2106
    return (xcpt & FP_INEXACT) << 5 |
2107
           (xcpt & FP_UNDERFLOW) << 3 |
2108
           (xcpt & FP_OVERFLOW) << 1 |
2109
           (xcpt & FP_DIV0) >> 1 |
2110
           (xcpt & FP_INVALID) >> 4;
2111
}
2112

    
2113
static inline void update_fcr31(void)
2114
{
2115
    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
2116

    
2117
    SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
2118
    if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp)
2119
        helper_raise_exception(EXCP_FPE);
2120
    else
2121
        UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
2122
}
2123

    
2124
/* Float support.
2125
   Single precition routines have a "s" suffix, double precision a
2126
   "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
2127
   paired single lower "pl", paired single upper "pu".  */
2128

    
2129
/* unary operations, modifying fp status  */
2130
uint64_t helper_float_sqrt_d(uint64_t fdt0)
2131
{
2132
    return float64_sqrt(fdt0, &env->active_fpu.fp_status);
2133
}
2134

    
2135
uint32_t helper_float_sqrt_s(uint32_t fst0)
2136
{
2137
    return float32_sqrt(fst0, &env->active_fpu.fp_status);
2138
}
2139

    
2140
uint64_t helper_float_cvtd_s(uint32_t fst0)
2141
{
2142
    uint64_t fdt2;
2143

    
2144
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2145
    fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
2146
    update_fcr31();
2147
    return fdt2;
2148
}
2149

    
2150
uint64_t helper_float_cvtd_w(uint32_t wt0)
2151
{
2152
    uint64_t fdt2;
2153

    
2154
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2155
    fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
2156
    update_fcr31();
2157
    return fdt2;
2158
}
2159

    
2160
uint64_t helper_float_cvtd_l(uint64_t dt0)
2161
{
2162
    uint64_t fdt2;
2163

    
2164
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2165
    fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
2166
    update_fcr31();
2167
    return fdt2;
2168
}
2169

    
2170
uint64_t helper_float_cvtl_d(uint64_t fdt0)
2171
{
2172
    uint64_t dt2;
2173

    
2174
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2175
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2176
    update_fcr31();
2177
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2178
        dt2 = FLOAT_SNAN64;
2179
    return dt2;
2180
}
2181

    
2182
uint64_t helper_float_cvtl_s(uint32_t fst0)
2183
{
2184
    uint64_t dt2;
2185

    
2186
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2187
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2188
    update_fcr31();
2189
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2190
        dt2 = FLOAT_SNAN64;
2191
    return dt2;
2192
}
2193

    
2194
uint64_t helper_float_cvtps_pw(uint64_t dt0)
2195
{
2196
    uint32_t fst2;
2197
    uint32_t fsth2;
2198

    
2199
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2200
    fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2201
    fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
2202
    update_fcr31();
2203
    return ((uint64_t)fsth2 << 32) | fst2;
2204
}
2205

    
2206
uint64_t helper_float_cvtpw_ps(uint64_t fdt0)
2207
{
2208
    uint32_t wt2;
2209
    uint32_t wth2;
2210

    
2211
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2212
    wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2213
    wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
2214
    update_fcr31();
2215
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) {
2216
        wt2 = FLOAT_SNAN32;
2217
        wth2 = FLOAT_SNAN32;
2218
    }
2219
    return ((uint64_t)wth2 << 32) | wt2;
2220
}
2221

    
2222
uint32_t helper_float_cvts_d(uint64_t fdt0)
2223
{
2224
    uint32_t fst2;
2225

    
2226
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2227
    fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
2228
    update_fcr31();
2229
    return fst2;
2230
}
2231

    
2232
uint32_t helper_float_cvts_w(uint32_t wt0)
2233
{
2234
    uint32_t fst2;
2235

    
2236
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2237
    fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
2238
    update_fcr31();
2239
    return fst2;
2240
}
2241

    
2242
uint32_t helper_float_cvts_l(uint64_t dt0)
2243
{
2244
    uint32_t fst2;
2245

    
2246
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2247
    fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
2248
    update_fcr31();
2249
    return fst2;
2250
}
2251

    
2252
uint32_t helper_float_cvts_pl(uint32_t wt0)
2253
{
2254
    uint32_t wt2;
2255

    
2256
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2257
    wt2 = wt0;
2258
    update_fcr31();
2259
    return wt2;
2260
}
2261

    
2262
uint32_t helper_float_cvts_pu(uint32_t wth0)
2263
{
2264
    uint32_t wt2;
2265

    
2266
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2267
    wt2 = wth0;
2268
    update_fcr31();
2269
    return wt2;
2270
}
2271

    
2272
uint32_t helper_float_cvtw_s(uint32_t fst0)
2273
{
2274
    uint32_t wt2;
2275

    
2276
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2277
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2278
    update_fcr31();
2279
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2280
        wt2 = FLOAT_SNAN32;
2281
    return wt2;
2282
}
2283

    
2284
uint32_t helper_float_cvtw_d(uint64_t fdt0)
2285
{
2286
    uint32_t wt2;
2287

    
2288
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2289
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2290
    update_fcr31();
2291
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2292
        wt2 = FLOAT_SNAN32;
2293
    return wt2;
2294
}
2295

    
2296
uint64_t helper_float_roundl_d(uint64_t fdt0)
2297
{
2298
    uint64_t dt2;
2299

    
2300
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2301
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2302
    RESTORE_ROUNDING_MODE;
2303
    update_fcr31();
2304
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2305
        dt2 = FLOAT_SNAN64;
2306
    return dt2;
2307
}
2308

    
2309
uint64_t helper_float_roundl_s(uint32_t fst0)
2310
{
2311
    uint64_t dt2;
2312

    
2313
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2314
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2315
    RESTORE_ROUNDING_MODE;
2316
    update_fcr31();
2317
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2318
        dt2 = FLOAT_SNAN64;
2319
    return dt2;
2320
}
2321

    
2322
uint32_t helper_float_roundw_d(uint64_t fdt0)
2323
{
2324
    uint32_t wt2;
2325

    
2326
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2327
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2328
    RESTORE_ROUNDING_MODE;
2329
    update_fcr31();
2330
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2331
        wt2 = FLOAT_SNAN32;
2332
    return wt2;
2333
}
2334

    
2335
uint32_t helper_float_roundw_s(uint32_t fst0)
2336
{
2337
    uint32_t wt2;
2338

    
2339
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2340
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2341
    RESTORE_ROUNDING_MODE;
2342
    update_fcr31();
2343
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2344
        wt2 = FLOAT_SNAN32;
2345
    return wt2;
2346
}
2347

    
2348
uint64_t helper_float_truncl_d(uint64_t fdt0)
2349
{
2350
    uint64_t dt2;
2351

    
2352
    dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
2353
    update_fcr31();
2354
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2355
        dt2 = FLOAT_SNAN64;
2356
    return dt2;
2357
}
2358

    
2359
uint64_t helper_float_truncl_s(uint32_t fst0)
2360
{
2361
    uint64_t dt2;
2362

    
2363
    dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
2364
    update_fcr31();
2365
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2366
        dt2 = FLOAT_SNAN64;
2367
    return dt2;
2368
}
2369

    
2370
uint32_t helper_float_truncw_d(uint64_t fdt0)
2371
{
2372
    uint32_t wt2;
2373

    
2374
    wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
2375
    update_fcr31();
2376
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2377
        wt2 = FLOAT_SNAN32;
2378
    return wt2;
2379
}
2380

    
2381
uint32_t helper_float_truncw_s(uint32_t fst0)
2382
{
2383
    uint32_t wt2;
2384

    
2385
    wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
2386
    update_fcr31();
2387
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2388
        wt2 = FLOAT_SNAN32;
2389
    return wt2;
2390
}
2391

    
2392
uint64_t helper_float_ceill_d(uint64_t fdt0)
2393
{
2394
    uint64_t dt2;
2395

    
2396
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2397
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2398
    RESTORE_ROUNDING_MODE;
2399
    update_fcr31();
2400
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2401
        dt2 = FLOAT_SNAN64;
2402
    return dt2;
2403
}
2404

    
2405
uint64_t helper_float_ceill_s(uint32_t fst0)
2406
{
2407
    uint64_t dt2;
2408

    
2409
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2410
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2411
    RESTORE_ROUNDING_MODE;
2412
    update_fcr31();
2413
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2414
        dt2 = FLOAT_SNAN64;
2415
    return dt2;
2416
}
2417

    
2418
uint32_t helper_float_ceilw_d(uint64_t fdt0)
2419
{
2420
    uint32_t wt2;
2421

    
2422
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2423
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2424
    RESTORE_ROUNDING_MODE;
2425
    update_fcr31();
2426
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2427
        wt2 = FLOAT_SNAN32;
2428
    return wt2;
2429
}
2430

    
2431
uint32_t helper_float_ceilw_s(uint32_t fst0)
2432
{
2433
    uint32_t wt2;
2434

    
2435
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2436
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2437
    RESTORE_ROUNDING_MODE;
2438
    update_fcr31();
2439
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2440
        wt2 = FLOAT_SNAN32;
2441
    return wt2;
2442
}
2443

    
2444
uint64_t helper_float_floorl_d(uint64_t fdt0)
2445
{
2446
    uint64_t dt2;
2447

    
2448
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2449
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2450
    RESTORE_ROUNDING_MODE;
2451
    update_fcr31();
2452
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2453
        dt2 = FLOAT_SNAN64;
2454
    return dt2;
2455
}
2456

    
2457
uint64_t helper_float_floorl_s(uint32_t fst0)
2458
{
2459
    uint64_t dt2;
2460

    
2461
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2462
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2463
    RESTORE_ROUNDING_MODE;
2464
    update_fcr31();
2465
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2466
        dt2 = FLOAT_SNAN64;
2467
    return dt2;
2468
}
2469

    
2470
uint32_t helper_float_floorw_d(uint64_t fdt0)
2471
{
2472
    uint32_t wt2;
2473

    
2474
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2475
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2476
    RESTORE_ROUNDING_MODE;
2477
    update_fcr31();
2478
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2479
        wt2 = FLOAT_SNAN32;
2480
    return wt2;
2481
}
2482

    
2483
uint32_t helper_float_floorw_s(uint32_t fst0)
2484
{
2485
    uint32_t wt2;
2486

    
2487
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2488
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2489
    RESTORE_ROUNDING_MODE;
2490
    update_fcr31();
2491
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2492
        wt2 = FLOAT_SNAN32;
2493
    return wt2;
2494
}
2495

    
2496
/* unary operations, not modifying fp status  */
2497
#define FLOAT_UNOP(name)                                       \
2498
uint64_t helper_float_ ## name ## _d(uint64_t fdt0)                \
2499
{                                                              \
2500
    return float64_ ## name(fdt0);                             \
2501
}                                                              \
2502
uint32_t helper_float_ ## name ## _s(uint32_t fst0)                \
2503
{                                                              \
2504
    return float32_ ## name(fst0);                             \
2505
}                                                              \
2506
uint64_t helper_float_ ## name ## _ps(uint64_t fdt0)               \
2507
{                                                              \
2508
    uint32_t wt0;                                              \
2509
    uint32_t wth0;                                             \
2510
                                                               \
2511
    wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF);                 \
2512
    wth0 = float32_ ## name(fdt0 >> 32);                       \
2513
    return ((uint64_t)wth0 << 32) | wt0;                       \
2514
}
2515
FLOAT_UNOP(abs)
2516
FLOAT_UNOP(chs)
2517
#undef FLOAT_UNOP
2518

    
2519
/* MIPS specific unary operations */
2520
uint64_t helper_float_recip_d(uint64_t fdt0)
2521
{
2522
    uint64_t fdt2;
2523

    
2524
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2525
    fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
2526
    update_fcr31();
2527
    return fdt2;
2528
}
2529

    
2530
uint32_t helper_float_recip_s(uint32_t fst0)
2531
{
2532
    uint32_t fst2;
2533

    
2534
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2535
    fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
2536
    update_fcr31();
2537
    return fst2;
2538
}
2539

    
2540
uint64_t helper_float_rsqrt_d(uint64_t fdt0)
2541
{
2542
    uint64_t fdt2;
2543

    
2544
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2545
    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2546
    fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
2547
    update_fcr31();
2548
    return fdt2;
2549
}
2550

    
2551
uint32_t helper_float_rsqrt_s(uint32_t fst0)
2552
{
2553
    uint32_t fst2;
2554

    
2555
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2556
    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2557
    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
2558
    update_fcr31();
2559
    return fst2;
2560
}
2561

    
2562
uint64_t helper_float_recip1_d(uint64_t fdt0)
2563
{
2564
    uint64_t fdt2;
2565

    
2566
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2567
    fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
2568
    update_fcr31();
2569
    return fdt2;
2570
}
2571

    
2572
uint32_t helper_float_recip1_s(uint32_t fst0)
2573
{
2574
    uint32_t fst2;
2575

    
2576
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2577
    fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
2578
    update_fcr31();
2579
    return fst2;
2580
}
2581

    
2582
uint64_t helper_float_recip1_ps(uint64_t fdt0)
2583
{
2584
    uint32_t fst2;
2585
    uint32_t fsth2;
2586

    
2587
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2588
    fst2 = float32_div(FLOAT_ONE32, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2589
    fsth2 = float32_div(FLOAT_ONE32, fdt0 >> 32, &env->active_fpu.fp_status);
2590
    update_fcr31();
2591
    return ((uint64_t)fsth2 << 32) | fst2;
2592
}
2593

    
2594
uint64_t helper_float_rsqrt1_d(uint64_t fdt0)
2595
{
2596
    uint64_t fdt2;
2597

    
2598
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2599
    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2600
    fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
2601
    update_fcr31();
2602
    return fdt2;
2603
}
2604

    
2605
uint32_t helper_float_rsqrt1_s(uint32_t fst0)
2606
{
2607
    uint32_t fst2;
2608

    
2609
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2610
    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2611
    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
2612
    update_fcr31();
2613
    return fst2;
2614
}
2615

    
2616
uint64_t helper_float_rsqrt1_ps(uint64_t fdt0)
2617
{
2618
    uint32_t fst2;
2619
    uint32_t fsth2;
2620

    
2621
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2622
    fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2623
    fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
2624
    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
2625
    fsth2 = float32_div(FLOAT_ONE32, fsth2, &env->active_fpu.fp_status);
2626
    update_fcr31();
2627
    return ((uint64_t)fsth2 << 32) | fst2;
2628
}
2629

    
2630
#define FLOAT_OP(name, p) void helper_float_##name##_##p(void)
2631

    
2632
/* binary operations */
2633
#define FLOAT_BINOP(name)                                          \
2634
uint64_t helper_float_ ## name ## _d(uint64_t fdt0, uint64_t fdt1)     \
2635
{                                                                  \
2636
    uint64_t dt2;                                                  \
2637
                                                                   \
2638
    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
2639
    dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status);     \
2640
    update_fcr31();                                                \
2641
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID)                \
2642
        dt2 = FLOAT_QNAN64;                                        \
2643
    return dt2;                                                    \
2644
}                                                                  \
2645
                                                                   \
2646
uint32_t helper_float_ ## name ## _s(uint32_t fst0, uint32_t fst1)     \
2647
{                                                                  \
2648
    uint32_t wt2;                                                  \
2649
                                                                   \
2650
    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
2651
    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
2652
    update_fcr31();                                                \
2653
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID)                \
2654
        wt2 = FLOAT_QNAN32;                                        \
2655
    return wt2;                                                    \
2656
}                                                                  \
2657
                                                                   \
2658
uint64_t helper_float_ ## name ## _ps(uint64_t fdt0, uint64_t fdt1)    \
2659
{                                                                  \
2660
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;                             \
2661
    uint32_t fsth0 = fdt0 >> 32;                                   \
2662
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;                             \
2663
    uint32_t fsth1 = fdt1 >> 32;                                   \
2664
    uint32_t wt2;                                                  \
2665
    uint32_t wth2;                                                 \
2666
                                                                   \
2667
    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
2668
    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
2669
    wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status);  \
2670
    update_fcr31();                                                \
2671
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) {              \
2672
        wt2 = FLOAT_QNAN32;                                        \
2673
        wth2 = FLOAT_QNAN32;                                       \
2674
    }                                                              \
2675
    return ((uint64_t)wth2 << 32) | wt2;                           \
2676
}
2677

    
2678
FLOAT_BINOP(add)
2679
FLOAT_BINOP(sub)
2680
FLOAT_BINOP(mul)
2681
FLOAT_BINOP(div)
2682
#undef FLOAT_BINOP
2683

    
2684
/* ternary operations */
2685
#define FLOAT_TERNOP(name1, name2)                                        \
2686
uint64_t helper_float_ ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1,  \
2687
                                           uint64_t fdt2)                 \
2688
{                                                                         \
2689
    fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status);          \
2690
    return float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status);          \
2691
}                                                                         \
2692
                                                                          \
2693
uint32_t helper_float_ ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1,  \
2694
                                           uint32_t fst2)                 \
2695
{                                                                         \
2696
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
2697
    return float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
2698
}                                                                         \
2699
                                                                          \
2700
uint64_t helper_float_ ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1, \
2701
                                            uint64_t fdt2)                \
2702
{                                                                         \
2703
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;                                    \
2704
    uint32_t fsth0 = fdt0 >> 32;                                          \
2705
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;                                    \
2706
    uint32_t fsth1 = fdt1 >> 32;                                          \
2707
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;                                    \
2708
    uint32_t fsth2 = fdt2 >> 32;                                          \
2709
                                                                          \
2710
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
2711
    fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status);       \
2712
    fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
2713
    fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status);       \
2714
    return ((uint64_t)fsth2 << 32) | fst2;                                \
2715
}
2716

    
2717
FLOAT_TERNOP(mul, add)
2718
FLOAT_TERNOP(mul, sub)
2719
#undef FLOAT_TERNOP
2720

    
2721
/* negated ternary operations */
2722
#define FLOAT_NTERNOP(name1, name2)                                       \
2723
uint64_t helper_float_n ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \
2724
                                           uint64_t fdt2)                 \
2725
{                                                                         \
2726
    fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status);          \
2727
    fdt2 = float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status);          \
2728
    return float64_chs(fdt2);                                             \
2729
}                                                                         \
2730
                                                                          \
2731
uint32_t helper_float_n ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \
2732
                                           uint32_t fst2)                 \
2733
{                                                                         \
2734
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
2735
    fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
2736
    return float32_chs(fst2);                                             \
2737
}                                                                         \
2738
                                                                          \
2739
uint64_t helper_float_n ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1,\
2740
                                           uint64_t fdt2)                 \
2741
{                                                                         \
2742
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;                                    \
2743
    uint32_t fsth0 = fdt0 >> 32;                                          \
2744
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;                                    \
2745
    uint32_t fsth1 = fdt1 >> 32;                                          \
2746
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;                                    \
2747
    uint32_t fsth2 = fdt2 >> 32;                                          \
2748
                                                                          \
2749
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
2750
    fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status);       \
2751
    fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
2752
    fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status);       \
2753
    fst2 = float32_chs(fst2);                                             \
2754
    fsth2 = float32_chs(fsth2);                                           \
2755
    return ((uint64_t)fsth2 << 32) | fst2;                                \
2756
}
2757

    
2758
FLOAT_NTERNOP(mul, add)
2759
FLOAT_NTERNOP(mul, sub)
2760
#undef FLOAT_NTERNOP
2761

    
2762
/* MIPS specific binary operations */
2763
uint64_t helper_float_recip2_d(uint64_t fdt0, uint64_t fdt2)
2764
{
2765
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2766
    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
2767
    fdt2 = float64_chs(float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status));
2768
    update_fcr31();
2769
    return fdt2;
2770
}
2771

    
2772
uint32_t helper_float_recip2_s(uint32_t fst0, uint32_t fst2)
2773
{
2774
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2775
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2776
    fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
2777
    update_fcr31();
2778
    return fst2;
2779
}
2780

    
2781
uint64_t helper_float_recip2_ps(uint64_t fdt0, uint64_t fdt2)
2782
{
2783
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2784
    uint32_t fsth0 = fdt0 >> 32;
2785
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
2786
    uint32_t fsth2 = fdt2 >> 32;
2787

    
2788
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2789
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2790
    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
2791
    fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
2792
    fsth2 = float32_chs(float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status));
2793
    update_fcr31();
2794
    return ((uint64_t)fsth2 << 32) | fst2;
2795
}
2796

    
2797
uint64_t helper_float_rsqrt2_d(uint64_t fdt0, uint64_t fdt2)
2798
{
2799
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2800
    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
2801
    fdt2 = float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status);
2802
    fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
2803
    update_fcr31();
2804
    return fdt2;
2805
}
2806

    
2807
uint32_t helper_float_rsqrt2_s(uint32_t fst0, uint32_t fst2)
2808
{
2809
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2810
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2811
    fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
2812
    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
2813
    update_fcr31();
2814
    return fst2;
2815
}
2816

    
2817
uint64_t helper_float_rsqrt2_ps(uint64_t fdt0, uint64_t fdt2)
2818
{
2819
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2820
    uint32_t fsth0 = fdt0 >> 32;
2821
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
2822
    uint32_t fsth2 = fdt2 >> 32;
2823

    
2824
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2825
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2826
    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
2827
    fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
2828
    fsth2 = float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status);
2829
    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
2830
    fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
2831
    update_fcr31();
2832
    return ((uint64_t)fsth2 << 32) | fst2;
2833
}
2834

    
2835
uint64_t helper_float_addr_ps(uint64_t fdt0, uint64_t fdt1)
2836
{
2837
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2838
    uint32_t fsth0 = fdt0 >> 32;
2839
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;
2840
    uint32_t fsth1 = fdt1 >> 32;
2841
    uint32_t fst2;
2842
    uint32_t fsth2;
2843

    
2844
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2845
    fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
2846
    fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
2847
    update_fcr31();
2848
    return ((uint64_t)fsth2 << 32) | fst2;
2849
}
2850

    
2851
uint64_t helper_float_mulr_ps(uint64_t fdt0, uint64_t fdt1)
2852
{
2853
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2854
    uint32_t fsth0 = fdt0 >> 32;
2855
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;
2856
    uint32_t fsth1 = fdt1 >> 32;
2857
    uint32_t fst2;
2858
    uint32_t fsth2;
2859

    
2860
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2861
    fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
2862
    fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
2863
    update_fcr31();
2864
    return ((uint64_t)fsth2 << 32) | fst2;
2865
}
2866

    
2867
/* compare operations */
2868
#define FOP_COND_D(op, cond)                                   \
2869
void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
2870
{                                                              \
2871
    int c = cond;                                              \
2872
    update_fcr31();                                            \
2873
    if (c)                                                     \
2874
        SET_FP_COND(cc, env->active_fpu);                      \
2875
    else                                                       \
2876
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2877
}                                                              \
2878
void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
2879
{                                                              \
2880
    int c;                                                     \
2881
    fdt0 = float64_abs(fdt0);                                  \
2882
    fdt1 = float64_abs(fdt1);                                  \
2883
    c = cond;                                                  \
2884
    update_fcr31();                                            \
2885
    if (c)                                                     \
2886
        SET_FP_COND(cc, env->active_fpu);                      \
2887
    else                                                       \
2888
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2889
}
2890

    
2891
static int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
2892
{
2893
    if (float64_is_signaling_nan(a) ||
2894
        float64_is_signaling_nan(b) ||
2895
        (sig && (float64_is_nan(a) || float64_is_nan(b)))) {
2896
        float_raise(float_flag_invalid, status);
2897
        return 1;
2898
    } else if (float64_is_nan(a) || float64_is_nan(b)) {
2899
        return 1;
2900
    } else {
2901
        return 0;
2902
    }
2903
}
2904

    
2905
/* NOTE: the comma operator will make "cond" to eval to false,
2906
 * but float*_is_unordered() is still called. */
2907
FOP_COND_D(f,   (float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status), 0))
2908
FOP_COND_D(un,  float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status))
2909
FOP_COND_D(eq,  !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
2910
FOP_COND_D(ueq, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
2911
FOP_COND_D(olt, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
2912
FOP_COND_D(ult, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
2913
FOP_COND_D(ole, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
2914
FOP_COND_D(ule, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
2915
/* NOTE: the comma operator will make "cond" to eval to false,
2916
 * but float*_is_unordered() is still called. */
2917
FOP_COND_D(sf,  (float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status), 0))
2918
FOP_COND_D(ngle,float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status))
2919
FOP_COND_D(seq, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
2920
FOP_COND_D(ngl, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
2921
FOP_COND_D(lt,  !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
2922
FOP_COND_D(nge, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
2923
FOP_COND_D(le,  !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
2924
FOP_COND_D(ngt, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
2925

    
2926
#define FOP_COND_S(op, cond)                                   \
2927
void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc)    \
2928
{                                                              \
2929
    int c = cond;                                              \
2930
    update_fcr31();                                            \
2931
    if (c)                                                     \
2932
        SET_FP_COND(cc, env->active_fpu);                      \
2933
    else                                                       \
2934
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2935
}                                                              \
2936
void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
2937
{                                                              \
2938
    int c;                                                     \
2939
    fst0 = float32_abs(fst0);                                  \
2940
    fst1 = float32_abs(fst1);                                  \
2941
    c = cond;                                                  \
2942
    update_fcr31();                                            \
2943
    if (c)                                                     \
2944
        SET_FP_COND(cc, env->active_fpu);                      \
2945
    else                                                       \
2946
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2947
}
2948

    
2949
static flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
2950
{
2951
    if (float32_is_signaling_nan(a) ||
2952
        float32_is_signaling_nan(b) ||
2953
        (sig && (float32_is_nan(a) || float32_is_nan(b)))) {
2954
        float_raise(float_flag_invalid, status);
2955
        return 1;
2956
    } else if (float32_is_nan(a) || float32_is_nan(b)) {
2957
        return 1;
2958
    } else {
2959
        return 0;
2960
    }
2961
}
2962

    
2963
/* NOTE: the comma operator will make "cond" to eval to false,
2964
 * but float*_is_unordered() is still called. */
2965
FOP_COND_S(f,   (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0))
2966
FOP_COND_S(un,  float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status))
2967
FOP_COND_S(eq,  !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status))
2968
FOP_COND_S(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
2969
FOP_COND_S(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status))
2970
FOP_COND_S(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
2971
FOP_COND_S(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status))
2972
FOP_COND_S(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
2973
/* NOTE: the comma operator will make "cond" to eval to false,
2974
 * but float*_is_unordered() is still called. */
2975
FOP_COND_S(sf,  (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0))
2976
FOP_COND_S(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status))
2977
FOP_COND_S(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status))
2978
FOP_COND_S(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
2979
FOP_COND_S(lt,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status))
2980
FOP_COND_S(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
2981
FOP_COND_S(le,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status))
2982
FOP_COND_S(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
2983

    
2984
#define FOP_COND_PS(op, condl, condh)                           \
2985
void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
2986
{                                                               \
2987
    uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF);             \
2988
    uint32_t fsth0 = float32_abs(fdt0 >> 32);                   \
2989
    uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF);             \
2990
    uint32_t fsth1 = float32_abs(fdt1 >> 32);                   \
2991
    int cl = condl;                                             \
2992
    int ch = condh;                                             \
2993
                                                                \
2994
    update_fcr31();                                             \
2995
    if (cl)                                                     \
2996
        SET_FP_COND(cc, env->active_fpu);                       \
2997
    else                                                        \
2998
        CLEAR_FP_COND(cc, env->active_fpu);                     \
2999
    if (ch)                                                     \
3000
        SET_FP_COND(cc + 1, env->active_fpu);                   \
3001
    else                                                        \
3002
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
3003
}                                                               \
3004
void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
3005
{                                                               \
3006
    uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF);             \
3007
    uint32_t fsth0 = float32_abs(fdt0 >> 32);                   \
3008
    uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF);             \
3009
    uint32_t fsth1 = float32_abs(fdt1 >> 32);                   \
3010
    int cl = condl;                                             \
3011
    int ch = condh;                                             \
3012
                                                                \
3013
    update_fcr31();                                             \
3014
    if (cl)                                                     \
3015
        SET_FP_COND(cc, env->active_fpu);                       \
3016
    else                                                        \
3017
        CLEAR_FP_COND(cc, env->active_fpu);                     \
3018
    if (ch)                                                     \
3019
        SET_FP_COND(cc + 1, env->active_fpu);                   \
3020
    else                                                        \
3021
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
3022
}
3023

    
3024
/* NOTE: the comma operator will make "cond" to eval to false,
3025
 * but float*_is_unordered() is still called. */
3026
FOP_COND_PS(f,   (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0),
3027
                 (float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status), 0))
3028
FOP_COND_PS(un,  float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status),
3029
                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status))
3030
FOP_COND_PS(eq,  !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)   && float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3031
                 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3032
FOP_COND_PS(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3033
                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3034
FOP_COND_PS(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)   && float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3035
                 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3036
FOP_COND_PS(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3037
                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3038
FOP_COND_PS(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)   && float32_le(fst0, fst1, &env->active_fpu.fp_status),
3039
                 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3040
FOP_COND_PS(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
3041
                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3042
/* NOTE: the comma operator will make "cond" to eval to false,
3043
 * but float*_is_unordered() is still called. */
3044
FOP_COND_PS(sf,  (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0),
3045
                 (float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status), 0))
3046
FOP_COND_PS(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status),
3047
                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status))
3048
FOP_COND_PS(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)   && float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3049
                 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3050
FOP_COND_PS(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
3051
                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
3052
FOP_COND_PS(lt,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)   && float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3053
                 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3054
FOP_COND_PS(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
3055
                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
3056
FOP_COND_PS(le,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)   && float32_le(fst0, fst1, &env->active_fpu.fp_status),
3057
                 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
3058
FOP_COND_PS(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
3059
                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))