Statistics
| Branch: | Revision:

root / target-mips / op_helper.c @ d9bea114

History | View | Annotate | Download (89.6 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, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
19
 */
20
#include <stdlib.h>
21
#include "exec.h"
22

    
23
#include "host-utils.h"
24

    
25
#include "helper.h"
26
/*****************************************************************************/
27
/* Exceptions processing helpers */
28

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

    
40
void helper_raise_exception (uint32_t exception)
41
{
42
    helper_raise_exception_err(exception, 0);
43
}
44

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

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

    
70
target_ulong helper_clo (target_ulong arg1)
71
{
72
    return clo32(arg1);
73
}
74

    
75
target_ulong helper_clz (target_ulong arg1)
76
{
77
    return clz32(arg1);
78
}
79

    
80
#if defined(TARGET_MIPS64)
81
target_ulong helper_dclo (target_ulong arg1)
82
{
83
    return clo64(arg1);
84
}
85

    
86
target_ulong helper_dclz (target_ulong arg1)
87
{
88
    return clz64(arg1);
89
}
90
#endif /* TARGET_MIPS64 */
91

    
92
/* 64 bits arithmetic for 32 bits hosts */
93
static inline uint64_t get_HILO (void)
94
{
95
    return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
96
}
97

    
98
static inline void set_HILO (uint64_t HILO)
99
{
100
    env->active_tc.LO[0] = (int32_t)HILO;
101
    env->active_tc.HI[0] = (int32_t)(HILO >> 32);
102
}
103

    
104
static inline void set_HIT0_LO (target_ulong arg1, uint64_t HILO)
105
{
106
    env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
107
    arg1 = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
108
}
109

    
110
static inline void set_HI_LOT0 (target_ulong arg1, uint64_t HILO)
111
{
112
    arg1 = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
113
    env->active_tc.HI[0] = (int32_t)(HILO >> 32);
114
}
115

    
116
/* Multiplication variants of the vr54xx. */
117
target_ulong helper_muls (target_ulong arg1, target_ulong arg2)
118
{
119
    set_HI_LOT0(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
120

    
121
    return arg1;
122
}
123

    
124
target_ulong helper_mulsu (target_ulong arg1, target_ulong arg2)
125
{
126
    set_HI_LOT0(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
127

    
128
    return arg1;
129
}
130

    
131
target_ulong helper_macc (target_ulong arg1, target_ulong arg2)
132
{
133
    set_HI_LOT0(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
134

    
135
    return arg1;
136
}
137

    
138
target_ulong helper_macchi (target_ulong arg1, target_ulong arg2)
139
{
140
    set_HIT0_LO(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
141

    
142
    return arg1;
143
}
144

    
145
target_ulong helper_maccu (target_ulong arg1, target_ulong arg2)
146
{
147
    set_HI_LOT0(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
148

    
149
    return arg1;
150
}
151

    
152
target_ulong helper_macchiu (target_ulong arg1, target_ulong arg2)
153
{
154
    set_HIT0_LO(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
155

    
156
    return arg1;
157
}
158

    
159
target_ulong helper_msac (target_ulong arg1, target_ulong arg2)
160
{
161
    set_HI_LOT0(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
162

    
163
    return arg1;
164
}
165

    
166
target_ulong helper_msachi (target_ulong arg1, target_ulong arg2)
167
{
168
    set_HIT0_LO(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
169

    
170
    return arg1;
171
}
172

    
173
target_ulong helper_msacu (target_ulong arg1, target_ulong arg2)
174
{
175
    set_HI_LOT0(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
176

    
177
    return arg1;
178
}
179

    
180
target_ulong helper_msachiu (target_ulong arg1, target_ulong arg2)
181
{
182
    set_HIT0_LO(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
183

    
184
    return arg1;
185
}
186

    
187
target_ulong helper_mulhi (target_ulong arg1, target_ulong arg2)
188
{
189
    set_HIT0_LO(arg1, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
190

    
191
    return arg1;
192
}
193

    
194
target_ulong helper_mulhiu (target_ulong arg1, target_ulong arg2)
195
{
196
    set_HIT0_LO(arg1, (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
197

    
198
    return arg1;
199
}
200

    
201
target_ulong helper_mulshi (target_ulong arg1, target_ulong arg2)
202
{
203
    set_HIT0_LO(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
204

    
205
    return arg1;
206
}
207

    
208
target_ulong helper_mulshiu (target_ulong arg1, target_ulong arg2)
209
{
210
    set_HIT0_LO(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
211

    
212
    return arg1;
213
}
214

    
215
#ifdef TARGET_MIPS64
216
void helper_dmult (target_ulong arg1, target_ulong arg2)
217
{
218
    muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
219
}
220

    
221
void helper_dmultu (target_ulong arg1, target_ulong arg2)
222
{
223
    mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2);
224
}
225
#endif
226

    
227
#ifdef TARGET_WORDS_BIGENDIAN
228
#define GET_LMASK(v) ((v) & 3)
229
#define GET_OFFSET(addr, offset) (addr + (offset))
230
#else
231
#define GET_LMASK(v) (((v) & 3) ^ 3)
232
#define GET_OFFSET(addr, offset) (addr - (offset))
233
#endif
234

    
235
target_ulong helper_lwl(target_ulong arg1, target_ulong arg2, int mem_idx)
236
{
237
    target_ulong tmp;
238

    
239
#ifdef CONFIG_USER_ONLY
240
#define ldfun ldub_raw
241
#else
242
    int (*ldfun)(target_ulong);
243

    
244
    switch (mem_idx)
245
    {
246
    case 0: ldfun = ldub_kernel; break;
247
    case 1: ldfun = ldub_super; break;
248
    default:
249
    case 2: ldfun = ldub_user; break;
250
    }
251
#endif
252
    tmp = ldfun(arg2);
253
    arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
254

    
255
    if (GET_LMASK(arg2) <= 2) {
256
        tmp = ldfun(GET_OFFSET(arg2, 1));
257
        arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
258
    }
259

    
260
    if (GET_LMASK(arg2) <= 1) {
261
        tmp = ldfun(GET_OFFSET(arg2, 2));
262
        arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
263
    }
264

    
265
    if (GET_LMASK(arg2) == 0) {
266
        tmp = ldfun(GET_OFFSET(arg2, 3));
267
        arg1 = (arg1 & 0xFFFFFF00) | tmp;
268
    }
269
    return (int32_t)arg1;
270
}
271

    
272
target_ulong helper_lwr(target_ulong arg1, target_ulong arg2, int mem_idx)
273
{
274
    target_ulong tmp;
275

    
276
#ifdef CONFIG_USER_ONLY
277
#define ldfun ldub_raw
278
#else
279
    int (*ldfun)(target_ulong);
280

    
281
    switch (mem_idx)
282
    {
283
    case 0: ldfun = ldub_kernel; break;
284
    case 1: ldfun = ldub_super; break;
285
    default:
286
    case 2: ldfun = ldub_user; break;
287
    }
288
#endif
289
    tmp = ldfun(arg2);
290
    arg1 = (arg1 & 0xFFFFFF00) | tmp;
291

    
292
    if (GET_LMASK(arg2) >= 1) {
293
        tmp = ldfun(GET_OFFSET(arg2, -1));
294
        arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8);
295
    }
296

    
297
    if (GET_LMASK(arg2) >= 2) {
298
        tmp = ldfun(GET_OFFSET(arg2, -2));
299
        arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16);
300
    }
301

    
302
    if (GET_LMASK(arg2) == 3) {
303
        tmp = ldfun(GET_OFFSET(arg2, -3));
304
        arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24);
305
    }
306
    return (int32_t)arg1;
307
}
308

    
309
void helper_swl(target_ulong arg1, target_ulong arg2, int mem_idx)
310
{
311
#ifdef CONFIG_USER_ONLY
312
#define stfun stb_raw
313
#else
314
    void (*stfun)(target_ulong, int);
315

    
316
    switch (mem_idx)
317
    {
318
    case 0: stfun = stb_kernel; break;
319
    case 1: stfun = stb_super; break;
320
    default:
321
    case 2: stfun = stb_user; break;
322
    }
323
#endif
324
    stfun(arg2, (uint8_t)(arg1 >> 24));
325

    
326
    if (GET_LMASK(arg2) <= 2)
327
        stfun(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16));
328

    
329
    if (GET_LMASK(arg2) <= 1)
330
        stfun(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8));
331

    
332
    if (GET_LMASK(arg2) == 0)
333
        stfun(GET_OFFSET(arg2, 3), (uint8_t)arg1);
334
}
335

    
336
void helper_swr(target_ulong arg1, target_ulong arg2, int mem_idx)
337
{
338
#ifdef CONFIG_USER_ONLY
339
#define stfun stb_raw
340
#else
341
    void (*stfun)(target_ulong, int);
342

    
343
    switch (mem_idx)
344
    {
345
    case 0: stfun = stb_kernel; break;
346
    case 1: stfun = stb_super; break;
347
    default:
348
    case 2: stfun = stb_user; break;
349
    }
350
#endif
351
    stfun(arg2, (uint8_t)arg1);
352

    
353
    if (GET_LMASK(arg2) >= 1)
354
        stfun(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8));
355

    
356
    if (GET_LMASK(arg2) >= 2)
357
        stfun(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16));
358

    
359
    if (GET_LMASK(arg2) == 3)
360
        stfun(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24));
361
}
362

    
363
#if defined(TARGET_MIPS64)
364
/* "half" load and stores.  We must do the memory access inline,
365
   or fault handling won't work.  */
366

    
367
#ifdef TARGET_WORDS_BIGENDIAN
368
#define GET_LMASK64(v) ((v) & 7)
369
#else
370
#define GET_LMASK64(v) (((v) & 7) ^ 7)
371
#endif
372

    
373
target_ulong helper_ldl(target_ulong arg1, target_ulong arg2, int mem_idx)
374
{
375
    uint64_t tmp;
376

    
377
#ifdef CONFIG_USER_ONLY
378
#define ldfun ldub_raw
379
#else
380
    int (*ldfun)(target_ulong);
381

    
382
    switch (mem_idx)
383
    {
384
    case 0: ldfun = ldub_kernel; break;
385
    case 1: ldfun = ldub_super; break;
386
    default:
387
    case 2: ldfun = ldub_user; break;
388
    }
389
#endif
390
    tmp = ldfun(arg2);
391
    arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
392

    
393
    if (GET_LMASK64(arg2) <= 6) {
394
        tmp = ldfun(GET_OFFSET(arg2, 1));
395
        arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
396
    }
397

    
398
    if (GET_LMASK64(arg2) <= 5) {
399
        tmp = ldfun(GET_OFFSET(arg2, 2));
400
        arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
401
    }
402

    
403
    if (GET_LMASK64(arg2) <= 4) {
404
        tmp = ldfun(GET_OFFSET(arg2, 3));
405
        arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
406
    }
407

    
408
    if (GET_LMASK64(arg2) <= 3) {
409
        tmp = ldfun(GET_OFFSET(arg2, 4));
410
        arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
411
    }
412

    
413
    if (GET_LMASK64(arg2) <= 2) {
414
        tmp = ldfun(GET_OFFSET(arg2, 5));
415
        arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
416
    }
417

    
418
    if (GET_LMASK64(arg2) <= 1) {
419
        tmp = ldfun(GET_OFFSET(arg2, 6));
420
        arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
421
    }
422

    
423
    if (GET_LMASK64(arg2) == 0) {
424
        tmp = ldfun(GET_OFFSET(arg2, 7));
425
        arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
426
    }
427

    
428
    return arg1;
429
}
430

    
431
target_ulong helper_ldr(target_ulong arg1, target_ulong arg2, int mem_idx)
432
{
433
    uint64_t tmp;
434

    
435
#ifdef CONFIG_USER_ONLY
436
#define ldfun ldub_raw
437
#else
438
    int (*ldfun)(target_ulong);
439

    
440
    switch (mem_idx)
441
    {
442
    case 0: ldfun = ldub_kernel; break;
443
    case 1: ldfun = ldub_super; break;
444
    default:
445
    case 2: ldfun = ldub_user; break;
446
    }
447
#endif
448
    tmp = ldfun(arg2);
449
    arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
450

    
451
    if (GET_LMASK64(arg2) >= 1) {
452
        tmp = ldfun(GET_OFFSET(arg2, -1));
453
        arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp  << 8);
454
    }
455

    
456
    if (GET_LMASK64(arg2) >= 2) {
457
        tmp = ldfun(GET_OFFSET(arg2, -2));
458
        arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
459
    }
460

    
461
    if (GET_LMASK64(arg2) >= 3) {
462
        tmp = ldfun(GET_OFFSET(arg2, -3));
463
        arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
464
    }
465

    
466
    if (GET_LMASK64(arg2) >= 4) {
467
        tmp = ldfun(GET_OFFSET(arg2, -4));
468
        arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
469
    }
470

    
471
    if (GET_LMASK64(arg2) >= 5) {
472
        tmp = ldfun(GET_OFFSET(arg2, -5));
473
        arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
474
    }
475

    
476
    if (GET_LMASK64(arg2) >= 6) {
477
        tmp = ldfun(GET_OFFSET(arg2, -6));
478
        arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
479
    }
480

    
481
    if (GET_LMASK64(arg2) == 7) {
482
        tmp = ldfun(GET_OFFSET(arg2, -7));
483
        arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
484
    }
485

    
486
    return arg1;
487
}
488

    
489
void helper_sdl(target_ulong arg1, target_ulong arg2, int mem_idx)
490
{
491
#ifdef CONFIG_USER_ONLY
492
#define stfun stb_raw
493
#else
494
    void (*stfun)(target_ulong, int);
495

    
496
    switch (mem_idx)
497
    {
498
    case 0: stfun = stb_kernel; break;
499
    case 1: stfun = stb_super; break;
500
    default:
501
    case 2: stfun = stb_user; break;
502
    }
503
#endif
504
    stfun(arg2, (uint8_t)(arg1 >> 56));
505

    
506
    if (GET_LMASK64(arg2) <= 6)
507
        stfun(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48));
508

    
509
    if (GET_LMASK64(arg2) <= 5)
510
        stfun(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40));
511

    
512
    if (GET_LMASK64(arg2) <= 4)
513
        stfun(GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32));
514

    
515
    if (GET_LMASK64(arg2) <= 3)
516
        stfun(GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24));
517

    
518
    if (GET_LMASK64(arg2) <= 2)
519
        stfun(GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16));
520

    
521
    if (GET_LMASK64(arg2) <= 1)
522
        stfun(GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8));
523

    
524
    if (GET_LMASK64(arg2) <= 0)
525
        stfun(GET_OFFSET(arg2, 7), (uint8_t)arg1);
526
}
527

    
528
void helper_sdr(target_ulong arg1, target_ulong arg2, int mem_idx)
529
{
530
#ifdef CONFIG_USER_ONLY
531
#define stfun stb_raw
532
#else
533
    void (*stfun)(target_ulong, int);
534

    
535
    switch (mem_idx)
536
    {
537
    case 0: stfun = stb_kernel; break;
538
    case 1: stfun = stb_super; break;
539
     default:
540
    case 2: stfun = stb_user; break;
541
    }
542
#endif
543
    stfun(arg2, (uint8_t)arg1);
544

    
545
    if (GET_LMASK64(arg2) >= 1)
546
        stfun(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8));
547

    
548
    if (GET_LMASK64(arg2) >= 2)
549
        stfun(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16));
550

    
551
    if (GET_LMASK64(arg2) >= 3)
552
        stfun(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24));
553

    
554
    if (GET_LMASK64(arg2) >= 4)
555
        stfun(GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32));
556

    
557
    if (GET_LMASK64(arg2) >= 5)
558
        stfun(GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40));
559

    
560
    if (GET_LMASK64(arg2) >= 6)
561
        stfun(GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48));
562

    
563
    if (GET_LMASK64(arg2) == 7)
564
        stfun(GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56));
565
}
566
#endif /* TARGET_MIPS64 */
567

    
568
#ifndef CONFIG_USER_ONLY
569
/* CP0 helpers */
570
target_ulong helper_mfc0_mvpcontrol (void)
571
{
572
    return env->mvp->CP0_MVPControl;
573
}
574

    
575
target_ulong helper_mfc0_mvpconf0 (void)
576
{
577
    return env->mvp->CP0_MVPConf0;
578
}
579

    
580
target_ulong helper_mfc0_mvpconf1 (void)
581
{
582
    return env->mvp->CP0_MVPConf1;
583
}
584

    
585
target_ulong helper_mfc0_random (void)
586
{
587
    return (int32_t)cpu_mips_get_random(env);
588
}
589

    
590
target_ulong helper_mfc0_tcstatus (void)
591
{
592
    return env->active_tc.CP0_TCStatus;
593
}
594

    
595
target_ulong helper_mftc0_tcstatus(void)
596
{
597
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
598

    
599
    if (other_tc == env->current_tc)
600
        return env->active_tc.CP0_TCStatus;
601
    else
602
        return env->tcs[other_tc].CP0_TCStatus;
603
}
604

    
605
target_ulong helper_mfc0_tcbind (void)
606
{
607
    return env->active_tc.CP0_TCBind;
608
}
609

    
610
target_ulong helper_mftc0_tcbind(void)
611
{
612
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
613

    
614
    if (other_tc == env->current_tc)
615
        return env->active_tc.CP0_TCBind;
616
    else
617
        return env->tcs[other_tc].CP0_TCBind;
618
}
619

    
620
target_ulong helper_mfc0_tcrestart (void)
621
{
622
    return env->active_tc.PC;
623
}
624

    
625
target_ulong helper_mftc0_tcrestart(void)
626
{
627
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
628

    
629
    if (other_tc == env->current_tc)
630
        return env->active_tc.PC;
631
    else
632
        return env->tcs[other_tc].PC;
633
}
634

    
635
target_ulong helper_mfc0_tchalt (void)
636
{
637
    return env->active_tc.CP0_TCHalt;
638
}
639

    
640
target_ulong helper_mftc0_tchalt(void)
641
{
642
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
643

    
644
    if (other_tc == env->current_tc)
645
        return env->active_tc.CP0_TCHalt;
646
    else
647
        return env->tcs[other_tc].CP0_TCHalt;
648
}
649

    
650
target_ulong helper_mfc0_tccontext (void)
651
{
652
    return env->active_tc.CP0_TCContext;
653
}
654

    
655
target_ulong helper_mftc0_tccontext(void)
656
{
657
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
658

    
659
    if (other_tc == env->current_tc)
660
        return env->active_tc.CP0_TCContext;
661
    else
662
        return env->tcs[other_tc].CP0_TCContext;
663
}
664

    
665
target_ulong helper_mfc0_tcschedule (void)
666
{
667
    return env->active_tc.CP0_TCSchedule;
668
}
669

    
670
target_ulong helper_mftc0_tcschedule(void)
671
{
672
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
673

    
674
    if (other_tc == env->current_tc)
675
        return env->active_tc.CP0_TCSchedule;
676
    else
677
        return env->tcs[other_tc].CP0_TCSchedule;
678
}
679

    
680
target_ulong helper_mfc0_tcschefback (void)
681
{
682
    return env->active_tc.CP0_TCScheFBack;
683
}
684

    
685
target_ulong helper_mftc0_tcschefback(void)
686
{
687
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
688

    
689
    if (other_tc == env->current_tc)
690
        return env->active_tc.CP0_TCScheFBack;
691
    else
692
        return env->tcs[other_tc].CP0_TCScheFBack;
693
}
694

    
695
target_ulong helper_mfc0_count (void)
696
{
697
    return (int32_t)cpu_mips_get_count(env);
698
}
699

    
700
target_ulong helper_mftc0_entryhi(void)
701
{
702
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
703
    int32_t tcstatus;
704

    
705
    if (other_tc == env->current_tc)
706
        tcstatus = env->active_tc.CP0_TCStatus;
707
    else
708
        tcstatus = env->tcs[other_tc].CP0_TCStatus;
709

    
710
    return (env->CP0_EntryHi & ~0xff) | (tcstatus & 0xff);
711
}
712

    
713
target_ulong helper_mftc0_status(void)
714
{
715
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
716
    target_ulong t0;
717
    int32_t tcstatus;
718

    
719
    if (other_tc == env->current_tc)
720
        tcstatus = env->active_tc.CP0_TCStatus;
721
    else
722
        tcstatus = env->tcs[other_tc].CP0_TCStatus;
723

    
724
    t0 = env->CP0_Status & ~0xf1000018;
725
    t0 |= tcstatus & (0xf << CP0TCSt_TCU0);
726
    t0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX);
727
    t0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_KSU);
728

    
729
    return t0;
730
}
731

    
732
target_ulong helper_mfc0_lladdr (void)
733
{
734
    return (int32_t)env->CP0_LLAddr >> 4;
735
}
736

    
737
target_ulong helper_mfc0_watchlo (uint32_t sel)
738
{
739
    return (int32_t)env->CP0_WatchLo[sel];
740
}
741

    
742
target_ulong helper_mfc0_watchhi (uint32_t sel)
743
{
744
    return env->CP0_WatchHi[sel];
745
}
746

    
747
target_ulong helper_mfc0_debug (void)
748
{
749
    target_ulong t0 = env->CP0_Debug;
750
    if (env->hflags & MIPS_HFLAG_DM)
751
        t0 |= 1 << CP0DB_DM;
752

    
753
    return t0;
754
}
755

    
756
target_ulong helper_mftc0_debug(void)
757
{
758
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
759
    int32_t tcstatus;
760

    
761
    if (other_tc == env->current_tc)
762
        tcstatus = env->active_tc.CP0_Debug_tcstatus;
763
    else
764
        tcstatus = env->tcs[other_tc].CP0_Debug_tcstatus;
765

    
766
    /* XXX: Might be wrong, check with EJTAG spec. */
767
    return (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
768
            (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
769
}
770

    
771
#if defined(TARGET_MIPS64)
772
target_ulong helper_dmfc0_tcrestart (void)
773
{
774
    return env->active_tc.PC;
775
}
776

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

    
782
target_ulong helper_dmfc0_tccontext (void)
783
{
784
    return env->active_tc.CP0_TCContext;
785
}
786

    
787
target_ulong helper_dmfc0_tcschedule (void)
788
{
789
    return env->active_tc.CP0_TCSchedule;
790
}
791

    
792
target_ulong helper_dmfc0_tcschefback (void)
793
{
794
    return env->active_tc.CP0_TCScheFBack;
795
}
796

    
797
target_ulong helper_dmfc0_lladdr (void)
798
{
799
    return env->CP0_LLAddr >> 4;
800
}
801

    
802
target_ulong helper_dmfc0_watchlo (uint32_t sel)
803
{
804
    return env->CP0_WatchLo[sel];
805
}
806
#endif /* TARGET_MIPS64 */
807

    
808
void helper_mtc0_index (target_ulong arg1)
809
{
810
    int num = 1;
811
    unsigned int tmp = env->tlb->nb_tlb;
812

    
813
    do {
814
        tmp >>= 1;
815
        num <<= 1;
816
    } while (tmp);
817
    env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1));
818
}
819

    
820
void helper_mtc0_mvpcontrol (target_ulong arg1)
821
{
822
    uint32_t mask = 0;
823
    uint32_t newval;
824

    
825
    if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))
826
        mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
827
                (1 << CP0MVPCo_EVP);
828
    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
829
        mask |= (1 << CP0MVPCo_STLB);
830
    newval = (env->mvp->CP0_MVPControl & ~mask) | (arg1 & mask);
831

    
832
    // TODO: Enable/disable shared TLB, enable/disable VPEs.
833

    
834
    env->mvp->CP0_MVPControl = newval;
835
}
836

    
837
void helper_mtc0_vpecontrol (target_ulong arg1)
838
{
839
    uint32_t mask;
840
    uint32_t newval;
841

    
842
    mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
843
           (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
844
    newval = (env->CP0_VPEControl & ~mask) | (arg1 & mask);
845

    
846
    /* Yield scheduler intercept not implemented. */
847
    /* Gating storage scheduler intercept not implemented. */
848

    
849
    // TODO: Enable/disable TCs.
850

    
851
    env->CP0_VPEControl = newval;
852
}
853

    
854
void helper_mtc0_vpeconf0 (target_ulong arg1)
855
{
856
    uint32_t mask = 0;
857
    uint32_t newval;
858

    
859
    if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
860
        if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))
861
            mask |= (0xff << CP0VPEC0_XTC);
862
        mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
863
    }
864
    newval = (env->CP0_VPEConf0 & ~mask) | (arg1 & mask);
865

    
866
    // TODO: TC exclusive handling due to ERL/EXL.
867

    
868
    env->CP0_VPEConf0 = newval;
869
}
870

    
871
void helper_mtc0_vpeconf1 (target_ulong arg1)
872
{
873
    uint32_t mask = 0;
874
    uint32_t newval;
875

    
876
    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
877
        mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
878
                (0xff << CP0VPEC1_NCP1);
879
    newval = (env->CP0_VPEConf1 & ~mask) | (arg1 & mask);
880

    
881
    /* UDI not implemented. */
882
    /* CP2 not implemented. */
883

    
884
    // TODO: Handle FPU (CP1) binding.
885

    
886
    env->CP0_VPEConf1 = newval;
887
}
888

    
889
void helper_mtc0_yqmask (target_ulong arg1)
890
{
891
    /* Yield qualifier inputs not implemented. */
892
    env->CP0_YQMask = 0x00000000;
893
}
894

    
895
void helper_mtc0_vpeopt (target_ulong arg1)
896
{
897
    env->CP0_VPEOpt = arg1 & 0x0000ffff;
898
}
899

    
900
void helper_mtc0_entrylo0 (target_ulong arg1)
901
{
902
    /* Large physaddr (PABITS) not implemented */
903
    /* 1k pages not implemented */
904
    env->CP0_EntryLo0 = arg1 & 0x3FFFFFFF;
905
}
906

    
907
void helper_mtc0_tcstatus (target_ulong arg1)
908
{
909
    uint32_t mask = env->CP0_TCStatus_rw_bitmask;
910
    uint32_t newval;
911

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

    
914
    // TODO: Sync with CP0_Status.
915

    
916
    env->active_tc.CP0_TCStatus = newval;
917
}
918

    
919
void helper_mttc0_tcstatus (target_ulong arg1)
920
{
921
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
922

    
923
    // TODO: Sync with CP0_Status.
924

    
925
    if (other_tc == env->current_tc)
926
        env->active_tc.CP0_TCStatus = arg1;
927
    else
928
        env->tcs[other_tc].CP0_TCStatus = arg1;
929
}
930

    
931
void helper_mtc0_tcbind (target_ulong arg1)
932
{
933
    uint32_t mask = (1 << CP0TCBd_TBE);
934
    uint32_t newval;
935

    
936
    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
937
        mask |= (1 << CP0TCBd_CurVPE);
938
    newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
939
    env->active_tc.CP0_TCBind = newval;
940
}
941

    
942
void helper_mttc0_tcbind (target_ulong arg1)
943
{
944
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
945
    uint32_t mask = (1 << CP0TCBd_TBE);
946
    uint32_t newval;
947

    
948
    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
949
        mask |= (1 << CP0TCBd_CurVPE);
950
    if (other_tc == env->current_tc) {
951
        newval = (env->active_tc.CP0_TCBind & ~mask) | (arg1 & mask);
952
        env->active_tc.CP0_TCBind = newval;
953
    } else {
954
        newval = (env->tcs[other_tc].CP0_TCBind & ~mask) | (arg1 & mask);
955
        env->tcs[other_tc].CP0_TCBind = newval;
956
    }
957
}
958

    
959
void helper_mtc0_tcrestart (target_ulong arg1)
960
{
961
    env->active_tc.PC = arg1;
962
    env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
963
    env->CP0_LLAddr = 0ULL;
964
    /* MIPS16 not implemented. */
965
}
966

    
967
void helper_mttc0_tcrestart (target_ulong arg1)
968
{
969
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
970

    
971
    if (other_tc == env->current_tc) {
972
        env->active_tc.PC = arg1;
973
        env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
974
        env->CP0_LLAddr = 0ULL;
975
        /* MIPS16 not implemented. */
976
    } else {
977
        env->tcs[other_tc].PC = arg1;
978
        env->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
979
        env->CP0_LLAddr = 0ULL;
980
        /* MIPS16 not implemented. */
981
    }
982
}
983

    
984
void helper_mtc0_tchalt (target_ulong arg1)
985
{
986
    env->active_tc.CP0_TCHalt = arg1 & 0x1;
987

    
988
    // TODO: Halt TC / Restart (if allocated+active) TC.
989
}
990

    
991
void helper_mttc0_tchalt (target_ulong arg1)
992
{
993
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
994

    
995
    // TODO: Halt TC / Restart (if allocated+active) TC.
996

    
997
    if (other_tc == env->current_tc)
998
        env->active_tc.CP0_TCHalt = arg1;
999
    else
1000
        env->tcs[other_tc].CP0_TCHalt = arg1;
1001
}
1002

    
1003
void helper_mtc0_tccontext (target_ulong arg1)
1004
{
1005
    env->active_tc.CP0_TCContext = arg1;
1006
}
1007

    
1008
void helper_mttc0_tccontext (target_ulong arg1)
1009
{
1010
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1011

    
1012
    if (other_tc == env->current_tc)
1013
        env->active_tc.CP0_TCContext = arg1;
1014
    else
1015
        env->tcs[other_tc].CP0_TCContext = arg1;
1016
}
1017

    
1018
void helper_mtc0_tcschedule (target_ulong arg1)
1019
{
1020
    env->active_tc.CP0_TCSchedule = arg1;
1021
}
1022

    
1023
void helper_mttc0_tcschedule (target_ulong arg1)
1024
{
1025
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1026

    
1027
    if (other_tc == env->current_tc)
1028
        env->active_tc.CP0_TCSchedule = arg1;
1029
    else
1030
        env->tcs[other_tc].CP0_TCSchedule = arg1;
1031
}
1032

    
1033
void helper_mtc0_tcschefback (target_ulong arg1)
1034
{
1035
    env->active_tc.CP0_TCScheFBack = arg1;
1036
}
1037

    
1038
void helper_mttc0_tcschefback (target_ulong arg1)
1039
{
1040
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1041

    
1042
    if (other_tc == env->current_tc)
1043
        env->active_tc.CP0_TCScheFBack = arg1;
1044
    else
1045
        env->tcs[other_tc].CP0_TCScheFBack = arg1;
1046
}
1047

    
1048
void helper_mtc0_entrylo1 (target_ulong arg1)
1049
{
1050
    /* Large physaddr (PABITS) not implemented */
1051
    /* 1k pages not implemented */
1052
    env->CP0_EntryLo1 = arg1 & 0x3FFFFFFF;
1053
}
1054

    
1055
void helper_mtc0_context (target_ulong arg1)
1056
{
1057
    env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF);
1058
}
1059

    
1060
void helper_mtc0_pagemask (target_ulong arg1)
1061
{
1062
    /* 1k pages not implemented */
1063
    env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1064
}
1065

    
1066
void helper_mtc0_pagegrain (target_ulong arg1)
1067
{
1068
    /* SmartMIPS not implemented */
1069
    /* Large physaddr (PABITS) not implemented */
1070
    /* 1k pages not implemented */
1071
    env->CP0_PageGrain = 0;
1072
}
1073

    
1074
void helper_mtc0_wired (target_ulong arg1)
1075
{
1076
    env->CP0_Wired = arg1 % env->tlb->nb_tlb;
1077
}
1078

    
1079
void helper_mtc0_srsconf0 (target_ulong arg1)
1080
{
1081
    env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask;
1082
}
1083

    
1084
void helper_mtc0_srsconf1 (target_ulong arg1)
1085
{
1086
    env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask;
1087
}
1088

    
1089
void helper_mtc0_srsconf2 (target_ulong arg1)
1090
{
1091
    env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask;
1092
}
1093

    
1094
void helper_mtc0_srsconf3 (target_ulong arg1)
1095
{
1096
    env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask;
1097
}
1098

    
1099
void helper_mtc0_srsconf4 (target_ulong arg1)
1100
{
1101
    env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask;
1102
}
1103

    
1104
void helper_mtc0_hwrena (target_ulong arg1)
1105
{
1106
    env->CP0_HWREna = arg1 & 0x0000000F;
1107
}
1108

    
1109
void helper_mtc0_count (target_ulong arg1)
1110
{
1111
    cpu_mips_store_count(env, arg1);
1112
}
1113

    
1114
void helper_mtc0_entryhi (target_ulong arg1)
1115
{
1116
    target_ulong old, val;
1117

    
1118
    /* 1k pages not implemented */
1119
    val = arg1 & ((TARGET_PAGE_MASK << 1) | 0xFF);
1120
#if defined(TARGET_MIPS64)
1121
    val &= env->SEGMask;
1122
#endif
1123
    old = env->CP0_EntryHi;
1124
    env->CP0_EntryHi = val;
1125
    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
1126
        uint32_t tcst = env->active_tc.CP0_TCStatus & ~0xff;
1127
        env->active_tc.CP0_TCStatus = tcst | (val & 0xff);
1128
    }
1129
    /* If the ASID changes, flush qemu's TLB.  */
1130
    if ((old & 0xFF) != (val & 0xFF))
1131
        cpu_mips_tlb_flush(env, 1);
1132
}
1133

    
1134
void helper_mttc0_entryhi(target_ulong arg1)
1135
{
1136
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1137
    int32_t tcstatus;
1138

    
1139
    env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (arg1 & ~0xff);
1140
    if (other_tc == env->current_tc) {
1141
        tcstatus = (env->active_tc.CP0_TCStatus & ~0xff) | (arg1 & 0xff);
1142
        env->active_tc.CP0_TCStatus = tcstatus;
1143
    } else {
1144
        tcstatus = (env->tcs[other_tc].CP0_TCStatus & ~0xff) | (arg1 & 0xff);
1145
        env->tcs[other_tc].CP0_TCStatus = tcstatus;
1146
    }
1147
}
1148

    
1149
void helper_mtc0_compare (target_ulong arg1)
1150
{
1151
    cpu_mips_store_compare(env, arg1);
1152
}
1153

    
1154
void helper_mtc0_status (target_ulong arg1)
1155
{
1156
    uint32_t val, old;
1157
    uint32_t mask = env->CP0_Status_rw_bitmask;
1158

    
1159
    val = arg1 & mask;
1160
    old = env->CP0_Status;
1161
    env->CP0_Status = (env->CP0_Status & ~mask) | val;
1162
    compute_hflags(env);
1163
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1164
        qemu_log("Status %08x (%08x) => %08x (%08x) Cause %08x",
1165
                old, old & env->CP0_Cause & CP0Ca_IP_mask,
1166
                val, val & env->CP0_Cause & CP0Ca_IP_mask,
1167
                env->CP0_Cause);
1168
        switch (env->hflags & MIPS_HFLAG_KSU) {
1169
        case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1170
        case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1171
        case MIPS_HFLAG_KM: qemu_log("\n"); break;
1172
        default: cpu_abort(env, "Invalid MMU mode!\n"); break;
1173
        }
1174
    }
1175
    cpu_mips_update_irq(env);
1176
}
1177

    
1178
void helper_mttc0_status(target_ulong arg1)
1179
{
1180
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1181
    int32_t tcstatus = env->tcs[other_tc].CP0_TCStatus;
1182

    
1183
    env->CP0_Status = arg1 & ~0xf1000018;
1184
    tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (arg1 & (0xf << CP0St_CU0));
1185
    tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((arg1 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX));
1186
    tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((arg1 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU));
1187
    if (other_tc == env->current_tc)
1188
        env->active_tc.CP0_TCStatus = tcstatus;
1189
    else
1190
        env->tcs[other_tc].CP0_TCStatus = tcstatus;
1191
}
1192

    
1193
void helper_mtc0_intctl (target_ulong arg1)
1194
{
1195
    /* vectored interrupts not implemented, no performance counters. */
1196
    env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (arg1 & 0x000002e0);
1197
}
1198

    
1199
void helper_mtc0_srsctl (target_ulong arg1)
1200
{
1201
    uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
1202
    env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask);
1203
}
1204

    
1205
void helper_mtc0_cause (target_ulong arg1)
1206
{
1207
    uint32_t mask = 0x00C00300;
1208
    uint32_t old = env->CP0_Cause;
1209

    
1210
    if (env->insn_flags & ISA_MIPS32R2)
1211
        mask |= 1 << CP0Ca_DC;
1212

    
1213
    env->CP0_Cause = (env->CP0_Cause & ~mask) | (arg1 & mask);
1214

    
1215
    if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) {
1216
        if (env->CP0_Cause & (1 << CP0Ca_DC))
1217
            cpu_mips_stop_count(env);
1218
        else
1219
            cpu_mips_start_count(env);
1220
    }
1221

    
1222
    /* Handle the software interrupt as an hardware one, as they
1223
       are very similar */
1224
    if (arg1 & CP0Ca_IP_mask) {
1225
        cpu_mips_update_irq(env);
1226
    }
1227
}
1228

    
1229
void helper_mtc0_ebase (target_ulong arg1)
1230
{
1231
    /* vectored interrupts not implemented */
1232
    /* Multi-CPU not implemented */
1233
    env->CP0_EBase = 0x80000000 | (arg1 & 0x3FFFF000);
1234
}
1235

    
1236
void helper_mtc0_config0 (target_ulong arg1)
1237
{
1238
    env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007);
1239
}
1240

    
1241
void helper_mtc0_config2 (target_ulong arg1)
1242
{
1243
    /* tertiary/secondary caches not implemented */
1244
    env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
1245
}
1246

    
1247
void helper_mtc0_watchlo (target_ulong arg1, uint32_t sel)
1248
{
1249
    /* Watch exceptions for instructions, data loads, data stores
1250
       not implemented. */
1251
    env->CP0_WatchLo[sel] = (arg1 & ~0x7);
1252
}
1253

    
1254
void helper_mtc0_watchhi (target_ulong arg1, uint32_t sel)
1255
{
1256
    env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8);
1257
    env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7);
1258
}
1259

    
1260
void helper_mtc0_xcontext (target_ulong arg1)
1261
{
1262
    target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
1263
    env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask);
1264
}
1265

    
1266
void helper_mtc0_framemask (target_ulong arg1)
1267
{
1268
    env->CP0_Framemask = arg1; /* XXX */
1269
}
1270

    
1271
void helper_mtc0_debug (target_ulong arg1)
1272
{
1273
    env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120);
1274
    if (arg1 & (1 << CP0DB_DM))
1275
        env->hflags |= MIPS_HFLAG_DM;
1276
    else
1277
        env->hflags &= ~MIPS_HFLAG_DM;
1278
}
1279

    
1280
void helper_mttc0_debug(target_ulong arg1)
1281
{
1282
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1283
    uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
1284

    
1285
    /* XXX: Might be wrong, check with EJTAG spec. */
1286
    if (other_tc == env->current_tc)
1287
        env->active_tc.CP0_Debug_tcstatus = val;
1288
    else
1289
        env->tcs[other_tc].CP0_Debug_tcstatus = val;
1290
    env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1291
                     (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1292
}
1293

    
1294
void helper_mtc0_performance0 (target_ulong arg1)
1295
{
1296
    env->CP0_Performance0 = arg1 & 0x000007ff;
1297
}
1298

    
1299
void helper_mtc0_taglo (target_ulong arg1)
1300
{
1301
    env->CP0_TagLo = arg1 & 0xFFFFFCF6;
1302
}
1303

    
1304
void helper_mtc0_datalo (target_ulong arg1)
1305
{
1306
    env->CP0_DataLo = arg1; /* XXX */
1307
}
1308

    
1309
void helper_mtc0_taghi (target_ulong arg1)
1310
{
1311
    env->CP0_TagHi = arg1; /* XXX */
1312
}
1313

    
1314
void helper_mtc0_datahi (target_ulong arg1)
1315
{
1316
    env->CP0_DataHi = arg1; /* XXX */
1317
}
1318

    
1319
/* MIPS MT functions */
1320
target_ulong helper_mftgpr(uint32_t sel)
1321
{
1322
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1323

    
1324
    if (other_tc == env->current_tc)
1325
        return env->active_tc.gpr[sel];
1326
    else
1327
        return env->tcs[other_tc].gpr[sel];
1328
}
1329

    
1330
target_ulong helper_mftlo(uint32_t sel)
1331
{
1332
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1333

    
1334
    if (other_tc == env->current_tc)
1335
        return env->active_tc.LO[sel];
1336
    else
1337
        return env->tcs[other_tc].LO[sel];
1338
}
1339

    
1340
target_ulong helper_mfthi(uint32_t sel)
1341
{
1342
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1343

    
1344
    if (other_tc == env->current_tc)
1345
        return env->active_tc.HI[sel];
1346
    else
1347
        return env->tcs[other_tc].HI[sel];
1348
}
1349

    
1350
target_ulong helper_mftacx(uint32_t sel)
1351
{
1352
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1353

    
1354
    if (other_tc == env->current_tc)
1355
        return env->active_tc.ACX[sel];
1356
    else
1357
        return env->tcs[other_tc].ACX[sel];
1358
}
1359

    
1360
target_ulong helper_mftdsp(void)
1361
{
1362
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1363

    
1364
    if (other_tc == env->current_tc)
1365
        return env->active_tc.DSPControl;
1366
    else
1367
        return env->tcs[other_tc].DSPControl;
1368
}
1369

    
1370
void helper_mttgpr(target_ulong arg1, uint32_t sel)
1371
{
1372
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1373

    
1374
    if (other_tc == env->current_tc)
1375
        env->active_tc.gpr[sel] = arg1;
1376
    else
1377
        env->tcs[other_tc].gpr[sel] = arg1;
1378
}
1379

    
1380
void helper_mttlo(target_ulong arg1, uint32_t sel)
1381
{
1382
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1383

    
1384
    if (other_tc == env->current_tc)
1385
        env->active_tc.LO[sel] = arg1;
1386
    else
1387
        env->tcs[other_tc].LO[sel] = arg1;
1388
}
1389

    
1390
void helper_mtthi(target_ulong arg1, uint32_t sel)
1391
{
1392
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1393

    
1394
    if (other_tc == env->current_tc)
1395
        env->active_tc.HI[sel] = arg1;
1396
    else
1397
        env->tcs[other_tc].HI[sel] = arg1;
1398
}
1399

    
1400
void helper_mttacx(target_ulong arg1, uint32_t sel)
1401
{
1402
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1403

    
1404
    if (other_tc == env->current_tc)
1405
        env->active_tc.ACX[sel] = arg1;
1406
    else
1407
        env->tcs[other_tc].ACX[sel] = arg1;
1408
}
1409

    
1410
void helper_mttdsp(target_ulong arg1)
1411
{
1412
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1413

    
1414
    if (other_tc == env->current_tc)
1415
        env->active_tc.DSPControl = arg1;
1416
    else
1417
        env->tcs[other_tc].DSPControl = arg1;
1418
}
1419

    
1420
/* MIPS MT functions */
1421
target_ulong helper_dmt(target_ulong arg1)
1422
{
1423
    // TODO
1424
    arg1 = 0;
1425
    // rt = arg1
1426

    
1427
    return arg1;
1428
}
1429

    
1430
target_ulong helper_emt(target_ulong arg1)
1431
{
1432
    // TODO
1433
    arg1 = 0;
1434
    // rt = arg1
1435

    
1436
    return arg1;
1437
}
1438

    
1439
target_ulong helper_dvpe(target_ulong arg1)
1440
{
1441
    // TODO
1442
    arg1 = 0;
1443
    // rt = arg1
1444

    
1445
    return arg1;
1446
}
1447

    
1448
target_ulong helper_evpe(target_ulong arg1)
1449
{
1450
    // TODO
1451
    arg1 = 0;
1452
    // rt = arg1
1453

    
1454
    return arg1;
1455
}
1456
#endif /* !CONFIG_USER_ONLY */
1457

    
1458
void helper_fork(target_ulong arg1, target_ulong arg2)
1459
{
1460
    // arg1 = rt, arg2 = rs
1461
    arg1 = 0;
1462
    // TODO: store to TC register
1463
}
1464

    
1465
target_ulong helper_yield(target_ulong arg1)
1466
{
1467
    if (arg1 < 0) {
1468
        /* No scheduling policy implemented. */
1469
        if (arg1 != -2) {
1470
            if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
1471
                env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
1472
                env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1473
                env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
1474
                helper_raise_exception(EXCP_THREAD);
1475
            }
1476
        }
1477
    } else if (arg1 == 0) {
1478
        if (0 /* TODO: TC underflow */) {
1479
            env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1480
            helper_raise_exception(EXCP_THREAD);
1481
        } else {
1482
            // TODO: Deallocate TC
1483
        }
1484
    } else if (arg1 > 0) {
1485
        /* Yield qualifier inputs not implemented. */
1486
        env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1487
        env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
1488
        helper_raise_exception(EXCP_THREAD);
1489
    }
1490
    return env->CP0_YQMask;
1491
}
1492

    
1493
#ifndef CONFIG_USER_ONLY
1494
/* TLB management */
1495
void cpu_mips_tlb_flush (CPUState *env, int flush_global)
1496
{
1497
    /* Flush qemu's TLB and discard all shadowed entries.  */
1498
    tlb_flush (env, flush_global);
1499
    env->tlb->tlb_in_use = env->tlb->nb_tlb;
1500
}
1501

    
1502
static void r4k_mips_tlb_flush_extra (CPUState *env, int first)
1503
{
1504
    /* Discard entries from env->tlb[first] onwards.  */
1505
    while (env->tlb->tlb_in_use > first) {
1506
        r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
1507
    }
1508
}
1509

    
1510
static void r4k_fill_tlb (int idx)
1511
{
1512
    r4k_tlb_t *tlb;
1513

    
1514
    /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
1515
    tlb = &env->tlb->mmu.r4k.tlb[idx];
1516
    tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
1517
#if defined(TARGET_MIPS64)
1518
    tlb->VPN &= env->SEGMask;
1519
#endif
1520
    tlb->ASID = env->CP0_EntryHi & 0xFF;
1521
    tlb->PageMask = env->CP0_PageMask;
1522
    tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
1523
    tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
1524
    tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
1525
    tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
1526
    tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
1527
    tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
1528
    tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
1529
    tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
1530
    tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
1531
}
1532

    
1533
void r4k_helper_tlbwi (void)
1534
{
1535
    int idx;
1536

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

    
1539
    /* Discard cached TLB entries.  We could avoid doing this if the
1540
       tlbwi is just upgrading access permissions on the current entry;
1541
       that might be a further win.  */
1542
    r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb);
1543

    
1544
    r4k_invalidate_tlb(env, idx, 0);
1545
    r4k_fill_tlb(idx);
1546
}
1547

    
1548
void r4k_helper_tlbwr (void)
1549
{
1550
    int r = cpu_mips_get_random(env);
1551

    
1552
    r4k_invalidate_tlb(env, r, 1);
1553
    r4k_fill_tlb(r);
1554
}
1555

    
1556
void r4k_helper_tlbp (void)
1557
{
1558
    r4k_tlb_t *tlb;
1559
    target_ulong mask;
1560
    target_ulong tag;
1561
    target_ulong VPN;
1562
    uint8_t ASID;
1563
    int i;
1564

    
1565
    ASID = env->CP0_EntryHi & 0xFF;
1566
    for (i = 0; i < env->tlb->nb_tlb; i++) {
1567
        tlb = &env->tlb->mmu.r4k.tlb[i];
1568
        /* 1k pages are not supported. */
1569
        mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1570
        tag = env->CP0_EntryHi & ~mask;
1571
        VPN = tlb->VPN & ~mask;
1572
        /* Check ASID, virtual page number & size */
1573
        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
1574
            /* TLB match */
1575
            env->CP0_Index = i;
1576
            break;
1577
        }
1578
    }
1579
    if (i == env->tlb->nb_tlb) {
1580
        /* No match.  Discard any shadow entries, if any of them match.  */
1581
        for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
1582
            tlb = &env->tlb->mmu.r4k.tlb[i];
1583
            /* 1k pages are not supported. */
1584
            mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1585
            tag = env->CP0_EntryHi & ~mask;
1586
            VPN = tlb->VPN & ~mask;
1587
            /* Check ASID, virtual page number & size */
1588
            if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
1589
                r4k_mips_tlb_flush_extra (env, i);
1590
                break;
1591
            }
1592
        }
1593

    
1594
        env->CP0_Index |= 0x80000000;
1595
    }
1596
}
1597

    
1598
void r4k_helper_tlbr (void)
1599
{
1600
    r4k_tlb_t *tlb;
1601
    uint8_t ASID;
1602
    int idx;
1603

    
1604
    ASID = env->CP0_EntryHi & 0xFF;
1605
    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
1606
    tlb = &env->tlb->mmu.r4k.tlb[idx];
1607

    
1608
    /* If this will change the current ASID, flush qemu's TLB.  */
1609
    if (ASID != tlb->ASID)
1610
        cpu_mips_tlb_flush (env, 1);
1611

    
1612
    r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
1613

    
1614
    env->CP0_EntryHi = tlb->VPN | tlb->ASID;
1615
    env->CP0_PageMask = tlb->PageMask;
1616
    env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
1617
                        (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
1618
    env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
1619
                        (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
1620
}
1621

    
1622
void helper_tlbwi(void)
1623
{
1624
    env->tlb->helper_tlbwi();
1625
}
1626

    
1627
void helper_tlbwr(void)
1628
{
1629
    env->tlb->helper_tlbwr();
1630
}
1631

    
1632
void helper_tlbp(void)
1633
{
1634
    env->tlb->helper_tlbp();
1635
}
1636

    
1637
void helper_tlbr(void)
1638
{
1639
    env->tlb->helper_tlbr();
1640
}
1641

    
1642
/* Specials */
1643
target_ulong helper_di (void)
1644
{
1645
    target_ulong t0 = env->CP0_Status;
1646

    
1647
    env->CP0_Status = t0 & ~(1 << CP0St_IE);
1648
    cpu_mips_update_irq(env);
1649

    
1650
    return t0;
1651
}
1652

    
1653
target_ulong helper_ei (void)
1654
{
1655
    target_ulong t0 = env->CP0_Status;
1656

    
1657
    env->CP0_Status = t0 | (1 << CP0St_IE);
1658
    cpu_mips_update_irq(env);
1659

    
1660
    return t0;
1661
}
1662

    
1663
static void debug_pre_eret (void)
1664
{
1665
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1666
        qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1667
                env->active_tc.PC, env->CP0_EPC);
1668
        if (env->CP0_Status & (1 << CP0St_ERL))
1669
            qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1670
        if (env->hflags & MIPS_HFLAG_DM)
1671
            qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1672
        qemu_log("\n");
1673
    }
1674
}
1675

    
1676
static void debug_post_eret (void)
1677
{
1678
    if (qemu_loglevel_mask(CPU_LOG_EXEC)) {
1679
        qemu_log("  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1680
                env->active_tc.PC, env->CP0_EPC);
1681
        if (env->CP0_Status & (1 << CP0St_ERL))
1682
            qemu_log(" ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1683
        if (env->hflags & MIPS_HFLAG_DM)
1684
            qemu_log(" DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1685
        switch (env->hflags & MIPS_HFLAG_KSU) {
1686
        case MIPS_HFLAG_UM: qemu_log(", UM\n"); break;
1687
        case MIPS_HFLAG_SM: qemu_log(", SM\n"); break;
1688
        case MIPS_HFLAG_KM: qemu_log("\n"); break;
1689
        default: cpu_abort(env, "Invalid MMU mode!\n"); break;
1690
        }
1691
    }
1692
}
1693

    
1694
void helper_eret (void)
1695
{
1696
    debug_pre_eret();
1697
    if (env->CP0_Status & (1 << CP0St_ERL)) {
1698
        env->active_tc.PC = env->CP0_ErrorEPC;
1699
        env->CP0_Status &= ~(1 << CP0St_ERL);
1700
    } else {
1701
        env->active_tc.PC = env->CP0_EPC;
1702
        env->CP0_Status &= ~(1 << CP0St_EXL);
1703
    }
1704
    compute_hflags(env);
1705
    debug_post_eret();
1706
    env->CP0_LLAddr = 1;
1707
}
1708

    
1709
void helper_deret (void)
1710
{
1711
    debug_pre_eret();
1712
    env->active_tc.PC = env->CP0_DEPC;
1713
    env->hflags &= MIPS_HFLAG_DM;
1714
    compute_hflags(env);
1715
    debug_post_eret();
1716
    env->CP0_LLAddr = 1;
1717
}
1718
#endif /* !CONFIG_USER_ONLY */
1719

    
1720
target_ulong helper_rdhwr_cpunum(void)
1721
{
1722
    if ((env->hflags & MIPS_HFLAG_CP0) ||
1723
        (env->CP0_HWREna & (1 << 0)))
1724
        return env->CP0_EBase & 0x3ff;
1725
    else
1726
        helper_raise_exception(EXCP_RI);
1727

    
1728
    return 0;
1729
}
1730

    
1731
target_ulong helper_rdhwr_synci_step(void)
1732
{
1733
    if ((env->hflags & MIPS_HFLAG_CP0) ||
1734
        (env->CP0_HWREna & (1 << 1)))
1735
        return env->SYNCI_Step;
1736
    else
1737
        helper_raise_exception(EXCP_RI);
1738

    
1739
    return 0;
1740
}
1741

    
1742
target_ulong helper_rdhwr_cc(void)
1743
{
1744
    if ((env->hflags & MIPS_HFLAG_CP0) ||
1745
        (env->CP0_HWREna & (1 << 2)))
1746
        return env->CP0_Count;
1747
    else
1748
        helper_raise_exception(EXCP_RI);
1749

    
1750
    return 0;
1751
}
1752

    
1753
target_ulong helper_rdhwr_ccres(void)
1754
{
1755
    if ((env->hflags & MIPS_HFLAG_CP0) ||
1756
        (env->CP0_HWREna & (1 << 3)))
1757
        return env->CCRes;
1758
    else
1759
        helper_raise_exception(EXCP_RI);
1760

    
1761
    return 0;
1762
}
1763

    
1764
void helper_pmon (int function)
1765
{
1766
    function /= 2;
1767
    switch (function) {
1768
    case 2: /* TODO: char inbyte(int waitflag); */
1769
        if (env->active_tc.gpr[4] == 0)
1770
            env->active_tc.gpr[2] = -1;
1771
        /* Fall through */
1772
    case 11: /* TODO: char inbyte (void); */
1773
        env->active_tc.gpr[2] = -1;
1774
        break;
1775
    case 3:
1776
    case 12:
1777
        printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
1778
        break;
1779
    case 17:
1780
        break;
1781
    case 158:
1782
        {
1783
            unsigned char *fmt = (void *)(unsigned long)env->active_tc.gpr[4];
1784
            printf("%s", fmt);
1785
        }
1786
        break;
1787
    }
1788
}
1789

    
1790
void helper_wait (void)
1791
{
1792
    env->halted = 1;
1793
    helper_raise_exception(EXCP_HLT);
1794
}
1795

    
1796
#if !defined(CONFIG_USER_ONLY)
1797

    
1798
static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
1799

    
1800
#define MMUSUFFIX _mmu
1801
#define ALIGNED_ONLY
1802

    
1803
#define SHIFT 0
1804
#include "softmmu_template.h"
1805

    
1806
#define SHIFT 1
1807
#include "softmmu_template.h"
1808

    
1809
#define SHIFT 2
1810
#include "softmmu_template.h"
1811

    
1812
#define SHIFT 3
1813
#include "softmmu_template.h"
1814

    
1815
static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
1816
{
1817
    env->CP0_BadVAddr = addr;
1818
    do_restore_state (retaddr);
1819
    helper_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
1820
}
1821

    
1822
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
1823
{
1824
    TranslationBlock *tb;
1825
    CPUState *saved_env;
1826
    unsigned long pc;
1827
    int ret;
1828

    
1829
    /* XXX: hack to restore env in all cases, even if not called from
1830
       generated code */
1831
    saved_env = env;
1832
    env = cpu_single_env;
1833
    ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
1834
    if (ret) {
1835
        if (retaddr) {
1836
            /* now we have a real cpu fault */
1837
            pc = (unsigned long)retaddr;
1838
            tb = tb_find_pc(pc);
1839
            if (tb) {
1840
                /* the PC is inside the translated code. It means that we have
1841
                   a virtual CPU fault */
1842
                cpu_restore_state(tb, env, pc, NULL);
1843
            }
1844
        }
1845
        helper_raise_exception_err(env->exception_index, env->error_code);
1846
    }
1847
    env = saved_env;
1848
}
1849

    
1850
void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
1851
                          int unused, int size)
1852
{
1853
    if (is_exec)
1854
        helper_raise_exception(EXCP_IBE);
1855
    else
1856
        helper_raise_exception(EXCP_DBE);
1857
}
1858
#endif /* !CONFIG_USER_ONLY */
1859

    
1860
/* Complex FPU operations which may need stack space. */
1861

    
1862
#define FLOAT_ONE32 make_float32(0x3f8 << 20)
1863
#define FLOAT_ONE64 make_float64(0x3ffULL << 52)
1864
#define FLOAT_TWO32 make_float32(1 << 30)
1865
#define FLOAT_TWO64 make_float64(1ULL << 62)
1866
#define FLOAT_QNAN32 0x7fbfffff
1867
#define FLOAT_QNAN64 0x7ff7ffffffffffffULL
1868
#define FLOAT_SNAN32 0x7fffffff
1869
#define FLOAT_SNAN64 0x7fffffffffffffffULL
1870

    
1871
/* convert MIPS rounding mode in FCR31 to IEEE library */
1872
unsigned int ieee_rm[] = {
1873
    float_round_nearest_even,
1874
    float_round_to_zero,
1875
    float_round_up,
1876
    float_round_down
1877
};
1878

    
1879
#define RESTORE_ROUNDING_MODE \
1880
    set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status)
1881

    
1882
#define RESTORE_FLUSH_MODE \
1883
    set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status);
1884

    
1885
target_ulong helper_cfc1 (uint32_t reg)
1886
{
1887
    target_ulong arg1;
1888

    
1889
    switch (reg) {
1890
    case 0:
1891
        arg1 = (int32_t)env->active_fpu.fcr0;
1892
        break;
1893
    case 25:
1894
        arg1 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
1895
        break;
1896
    case 26:
1897
        arg1 = env->active_fpu.fcr31 & 0x0003f07c;
1898
        break;
1899
    case 28:
1900
        arg1 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
1901
        break;
1902
    default:
1903
        arg1 = (int32_t)env->active_fpu.fcr31;
1904
        break;
1905
    }
1906

    
1907
    return arg1;
1908
}
1909

    
1910
void helper_ctc1 (target_ulong arg1, uint32_t reg)
1911
{
1912
    switch(reg) {
1913
    case 25:
1914
        if (arg1 & 0xffffff00)
1915
            return;
1916
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
1917
                     ((arg1 & 0x1) << 23);
1918
        break;
1919
    case 26:
1920
        if (arg1 & 0x007c0000)
1921
            return;
1922
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (arg1 & 0x0003f07c);
1923
        break;
1924
    case 28:
1925
        if (arg1 & 0x007c0000)
1926
            return;
1927
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (arg1 & 0x00000f83) |
1928
                     ((arg1 & 0x4) << 22);
1929
        break;
1930
    case 31:
1931
        if (arg1 & 0x007c0000)
1932
            return;
1933
        env->active_fpu.fcr31 = arg1;
1934
        break;
1935
    default:
1936
        return;
1937
    }
1938
    /* set rounding mode */
1939
    RESTORE_ROUNDING_MODE;
1940
    /* set flush-to-zero mode */
1941
    RESTORE_FLUSH_MODE;
1942
    set_float_exception_flags(0, &env->active_fpu.fp_status);
1943
    if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
1944
        helper_raise_exception(EXCP_FPE);
1945
}
1946

    
1947
static inline char ieee_ex_to_mips(char xcpt)
1948
{
1949
    return (xcpt & float_flag_inexact) >> 5 |
1950
           (xcpt & float_flag_underflow) >> 3 |
1951
           (xcpt & float_flag_overflow) >> 1 |
1952
           (xcpt & float_flag_divbyzero) << 1 |
1953
           (xcpt & float_flag_invalid) << 4;
1954
}
1955

    
1956
static inline char mips_ex_to_ieee(char xcpt)
1957
{
1958
    return (xcpt & FP_INEXACT) << 5 |
1959
           (xcpt & FP_UNDERFLOW) << 3 |
1960
           (xcpt & FP_OVERFLOW) << 1 |
1961
           (xcpt & FP_DIV0) >> 1 |
1962
           (xcpt & FP_INVALID) >> 4;
1963
}
1964

    
1965
static inline void update_fcr31(void)
1966
{
1967
    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
1968

    
1969
    SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
1970
    if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp)
1971
        helper_raise_exception(EXCP_FPE);
1972
    else
1973
        UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
1974
}
1975

    
1976
/* Float support.
1977
   Single precition routines have a "s" suffix, double precision a
1978
   "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
1979
   paired single lower "pl", paired single upper "pu".  */
1980

    
1981
/* unary operations, modifying fp status  */
1982
uint64_t helper_float_sqrt_d(uint64_t fdt0)
1983
{
1984
    return float64_sqrt(fdt0, &env->active_fpu.fp_status);
1985
}
1986

    
1987
uint32_t helper_float_sqrt_s(uint32_t fst0)
1988
{
1989
    return float32_sqrt(fst0, &env->active_fpu.fp_status);
1990
}
1991

    
1992
uint64_t helper_float_cvtd_s(uint32_t fst0)
1993
{
1994
    uint64_t fdt2;
1995

    
1996
    set_float_exception_flags(0, &env->active_fpu.fp_status);
1997
    fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
1998
    update_fcr31();
1999
    return fdt2;
2000
}
2001

    
2002
uint64_t helper_float_cvtd_w(uint32_t wt0)
2003
{
2004
    uint64_t fdt2;
2005

    
2006
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2007
    fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
2008
    update_fcr31();
2009
    return fdt2;
2010
}
2011

    
2012
uint64_t helper_float_cvtd_l(uint64_t dt0)
2013
{
2014
    uint64_t fdt2;
2015

    
2016
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2017
    fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
2018
    update_fcr31();
2019
    return fdt2;
2020
}
2021

    
2022
uint64_t helper_float_cvtl_d(uint64_t fdt0)
2023
{
2024
    uint64_t dt2;
2025

    
2026
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2027
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2028
    update_fcr31();
2029
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2030
        dt2 = FLOAT_SNAN64;
2031
    return dt2;
2032
}
2033

    
2034
uint64_t helper_float_cvtl_s(uint32_t fst0)
2035
{
2036
    uint64_t dt2;
2037

    
2038
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2039
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2040
    update_fcr31();
2041
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2042
        dt2 = FLOAT_SNAN64;
2043
    return dt2;
2044
}
2045

    
2046
uint64_t helper_float_cvtps_pw(uint64_t dt0)
2047
{
2048
    uint32_t fst2;
2049
    uint32_t fsth2;
2050

    
2051
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2052
    fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2053
    fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
2054
    update_fcr31();
2055
    return ((uint64_t)fsth2 << 32) | fst2;
2056
}
2057

    
2058
uint64_t helper_float_cvtpw_ps(uint64_t fdt0)
2059
{
2060
    uint32_t wt2;
2061
    uint32_t wth2;
2062

    
2063
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2064
    wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2065
    wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
2066
    update_fcr31();
2067
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) {
2068
        wt2 = FLOAT_SNAN32;
2069
        wth2 = FLOAT_SNAN32;
2070
    }
2071
    return ((uint64_t)wth2 << 32) | wt2;
2072
}
2073

    
2074
uint32_t helper_float_cvts_d(uint64_t fdt0)
2075
{
2076
    uint32_t fst2;
2077

    
2078
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2079
    fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
2080
    update_fcr31();
2081
    return fst2;
2082
}
2083

    
2084
uint32_t helper_float_cvts_w(uint32_t wt0)
2085
{
2086
    uint32_t fst2;
2087

    
2088
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2089
    fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
2090
    update_fcr31();
2091
    return fst2;
2092
}
2093

    
2094
uint32_t helper_float_cvts_l(uint64_t dt0)
2095
{
2096
    uint32_t fst2;
2097

    
2098
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2099
    fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
2100
    update_fcr31();
2101
    return fst2;
2102
}
2103

    
2104
uint32_t helper_float_cvts_pl(uint32_t wt0)
2105
{
2106
    uint32_t wt2;
2107

    
2108
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2109
    wt2 = wt0;
2110
    update_fcr31();
2111
    return wt2;
2112
}
2113

    
2114
uint32_t helper_float_cvts_pu(uint32_t wth0)
2115
{
2116
    uint32_t wt2;
2117

    
2118
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2119
    wt2 = wth0;
2120
    update_fcr31();
2121
    return wt2;
2122
}
2123

    
2124
uint32_t helper_float_cvtw_s(uint32_t fst0)
2125
{
2126
    uint32_t wt2;
2127

    
2128
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2129
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2130
    update_fcr31();
2131
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2132
        wt2 = FLOAT_SNAN32;
2133
    return wt2;
2134
}
2135

    
2136
uint32_t helper_float_cvtw_d(uint64_t fdt0)
2137
{
2138
    uint32_t wt2;
2139

    
2140
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2141
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2142
    update_fcr31();
2143
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2144
        wt2 = FLOAT_SNAN32;
2145
    return wt2;
2146
}
2147

    
2148
uint64_t helper_float_roundl_d(uint64_t fdt0)
2149
{
2150
    uint64_t dt2;
2151

    
2152
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2153
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2154
    RESTORE_ROUNDING_MODE;
2155
    update_fcr31();
2156
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2157
        dt2 = FLOAT_SNAN64;
2158
    return dt2;
2159
}
2160

    
2161
uint64_t helper_float_roundl_s(uint32_t fst0)
2162
{
2163
    uint64_t dt2;
2164

    
2165
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2166
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2167
    RESTORE_ROUNDING_MODE;
2168
    update_fcr31();
2169
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2170
        dt2 = FLOAT_SNAN64;
2171
    return dt2;
2172
}
2173

    
2174
uint32_t helper_float_roundw_d(uint64_t fdt0)
2175
{
2176
    uint32_t wt2;
2177

    
2178
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2179
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2180
    RESTORE_ROUNDING_MODE;
2181
    update_fcr31();
2182
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2183
        wt2 = FLOAT_SNAN32;
2184
    return wt2;
2185
}
2186

    
2187
uint32_t helper_float_roundw_s(uint32_t fst0)
2188
{
2189
    uint32_t wt2;
2190

    
2191
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2192
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2193
    RESTORE_ROUNDING_MODE;
2194
    update_fcr31();
2195
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2196
        wt2 = FLOAT_SNAN32;
2197
    return wt2;
2198
}
2199

    
2200
uint64_t helper_float_truncl_d(uint64_t fdt0)
2201
{
2202
    uint64_t dt2;
2203

    
2204
    dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
2205
    update_fcr31();
2206
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2207
        dt2 = FLOAT_SNAN64;
2208
    return dt2;
2209
}
2210

    
2211
uint64_t helper_float_truncl_s(uint32_t fst0)
2212
{
2213
    uint64_t dt2;
2214

    
2215
    dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
2216
    update_fcr31();
2217
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2218
        dt2 = FLOAT_SNAN64;
2219
    return dt2;
2220
}
2221

    
2222
uint32_t helper_float_truncw_d(uint64_t fdt0)
2223
{
2224
    uint32_t wt2;
2225

    
2226
    wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
2227
    update_fcr31();
2228
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2229
        wt2 = FLOAT_SNAN32;
2230
    return wt2;
2231
}
2232

    
2233
uint32_t helper_float_truncw_s(uint32_t fst0)
2234
{
2235
    uint32_t wt2;
2236

    
2237
    wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
2238
    update_fcr31();
2239
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2240
        wt2 = FLOAT_SNAN32;
2241
    return wt2;
2242
}
2243

    
2244
uint64_t helper_float_ceill_d(uint64_t fdt0)
2245
{
2246
    uint64_t dt2;
2247

    
2248
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2249
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2250
    RESTORE_ROUNDING_MODE;
2251
    update_fcr31();
2252
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2253
        dt2 = FLOAT_SNAN64;
2254
    return dt2;
2255
}
2256

    
2257
uint64_t helper_float_ceill_s(uint32_t fst0)
2258
{
2259
    uint64_t dt2;
2260

    
2261
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2262
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2263
    RESTORE_ROUNDING_MODE;
2264
    update_fcr31();
2265
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2266
        dt2 = FLOAT_SNAN64;
2267
    return dt2;
2268
}
2269

    
2270
uint32_t helper_float_ceilw_d(uint64_t fdt0)
2271
{
2272
    uint32_t wt2;
2273

    
2274
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2275
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2276
    RESTORE_ROUNDING_MODE;
2277
    update_fcr31();
2278
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2279
        wt2 = FLOAT_SNAN32;
2280
    return wt2;
2281
}
2282

    
2283
uint32_t helper_float_ceilw_s(uint32_t fst0)
2284
{
2285
    uint32_t wt2;
2286

    
2287
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2288
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2289
    RESTORE_ROUNDING_MODE;
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_floorl_d(uint64_t fdt0)
2297
{
2298
    uint64_t dt2;
2299

    
2300
    set_float_rounding_mode(float_round_down, &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_floorl_s(uint32_t fst0)
2310
{
2311
    uint64_t dt2;
2312

    
2313
    set_float_rounding_mode(float_round_down, &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_floorw_d(uint64_t fdt0)
2323
{
2324
    uint32_t wt2;
2325

    
2326
    set_float_rounding_mode(float_round_down, &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_floorw_s(uint32_t fst0)
2336
{
2337
    uint32_t wt2;
2338

    
2339
    set_float_rounding_mode(float_round_down, &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
/* unary operations, not modifying fp status  */
2349
#define FLOAT_UNOP(name)                                       \
2350
uint64_t helper_float_ ## name ## _d(uint64_t fdt0)                \
2351
{                                                              \
2352
    return float64_ ## name(fdt0);                             \
2353
}                                                              \
2354
uint32_t helper_float_ ## name ## _s(uint32_t fst0)                \
2355
{                                                              \
2356
    return float32_ ## name(fst0);                             \
2357
}                                                              \
2358
uint64_t helper_float_ ## name ## _ps(uint64_t fdt0)               \
2359
{                                                              \
2360
    uint32_t wt0;                                              \
2361
    uint32_t wth0;                                             \
2362
                                                               \
2363
    wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF);                 \
2364
    wth0 = float32_ ## name(fdt0 >> 32);                       \
2365
    return ((uint64_t)wth0 << 32) | wt0;                       \
2366
}
2367
FLOAT_UNOP(abs)
2368
FLOAT_UNOP(chs)
2369
#undef FLOAT_UNOP
2370

    
2371
/* MIPS specific unary operations */
2372
uint64_t helper_float_recip_d(uint64_t fdt0)
2373
{
2374
    uint64_t fdt2;
2375

    
2376
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2377
    fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
2378
    update_fcr31();
2379
    return fdt2;
2380
}
2381

    
2382
uint32_t helper_float_recip_s(uint32_t fst0)
2383
{
2384
    uint32_t fst2;
2385

    
2386
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2387
    fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
2388
    update_fcr31();
2389
    return fst2;
2390
}
2391

    
2392
uint64_t helper_float_rsqrt_d(uint64_t fdt0)
2393
{
2394
    uint64_t fdt2;
2395

    
2396
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2397
    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2398
    fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
2399
    update_fcr31();
2400
    return fdt2;
2401
}
2402

    
2403
uint32_t helper_float_rsqrt_s(uint32_t fst0)
2404
{
2405
    uint32_t fst2;
2406

    
2407
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2408
    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2409
    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
2410
    update_fcr31();
2411
    return fst2;
2412
}
2413

    
2414
uint64_t helper_float_recip1_d(uint64_t fdt0)
2415
{
2416
    uint64_t fdt2;
2417

    
2418
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2419
    fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
2420
    update_fcr31();
2421
    return fdt2;
2422
}
2423

    
2424
uint32_t helper_float_recip1_s(uint32_t fst0)
2425
{
2426
    uint32_t fst2;
2427

    
2428
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2429
    fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
2430
    update_fcr31();
2431
    return fst2;
2432
}
2433

    
2434
uint64_t helper_float_recip1_ps(uint64_t fdt0)
2435
{
2436
    uint32_t fst2;
2437
    uint32_t fsth2;
2438

    
2439
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2440
    fst2 = float32_div(FLOAT_ONE32, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2441
    fsth2 = float32_div(FLOAT_ONE32, fdt0 >> 32, &env->active_fpu.fp_status);
2442
    update_fcr31();
2443
    return ((uint64_t)fsth2 << 32) | fst2;
2444
}
2445

    
2446
uint64_t helper_float_rsqrt1_d(uint64_t fdt0)
2447
{
2448
    uint64_t fdt2;
2449

    
2450
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2451
    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2452
    fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
2453
    update_fcr31();
2454
    return fdt2;
2455
}
2456

    
2457
uint32_t helper_float_rsqrt1_s(uint32_t fst0)
2458
{
2459
    uint32_t fst2;
2460

    
2461
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2462
    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2463
    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
2464
    update_fcr31();
2465
    return fst2;
2466
}
2467

    
2468
uint64_t helper_float_rsqrt1_ps(uint64_t fdt0)
2469
{
2470
    uint32_t fst2;
2471
    uint32_t fsth2;
2472

    
2473
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2474
    fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2475
    fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
2476
    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
2477
    fsth2 = float32_div(FLOAT_ONE32, fsth2, &env->active_fpu.fp_status);
2478
    update_fcr31();
2479
    return ((uint64_t)fsth2 << 32) | fst2;
2480
}
2481

    
2482
#define FLOAT_OP(name, p) void helper_float_##name##_##p(void)
2483

    
2484
/* binary operations */
2485
#define FLOAT_BINOP(name)                                          \
2486
uint64_t helper_float_ ## name ## _d(uint64_t fdt0, uint64_t fdt1)     \
2487
{                                                                  \
2488
    uint64_t dt2;                                                  \
2489
                                                                   \
2490
    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
2491
    dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status);     \
2492
    update_fcr31();                                                \
2493
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID)                \
2494
        dt2 = FLOAT_QNAN64;                                        \
2495
    return dt2;                                                    \
2496
}                                                                  \
2497
                                                                   \
2498
uint32_t helper_float_ ## name ## _s(uint32_t fst0, uint32_t fst1)     \
2499
{                                                                  \
2500
    uint32_t wt2;                                                  \
2501
                                                                   \
2502
    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
2503
    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
2504
    update_fcr31();                                                \
2505
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID)                \
2506
        wt2 = FLOAT_QNAN32;                                        \
2507
    return wt2;                                                    \
2508
}                                                                  \
2509
                                                                   \
2510
uint64_t helper_float_ ## name ## _ps(uint64_t fdt0, uint64_t fdt1)    \
2511
{                                                                  \
2512
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;                             \
2513
    uint32_t fsth0 = fdt0 >> 32;                                   \
2514
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;                             \
2515
    uint32_t fsth1 = fdt1 >> 32;                                   \
2516
    uint32_t wt2;                                                  \
2517
    uint32_t wth2;                                                 \
2518
                                                                   \
2519
    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
2520
    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
2521
    wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status);  \
2522
    update_fcr31();                                                \
2523
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) {              \
2524
        wt2 = FLOAT_QNAN32;                                        \
2525
        wth2 = FLOAT_QNAN32;                                       \
2526
    }                                                              \
2527
    return ((uint64_t)wth2 << 32) | wt2;                           \
2528
}
2529

    
2530
FLOAT_BINOP(add)
2531
FLOAT_BINOP(sub)
2532
FLOAT_BINOP(mul)
2533
FLOAT_BINOP(div)
2534
#undef FLOAT_BINOP
2535

    
2536
/* ternary operations */
2537
#define FLOAT_TERNOP(name1, name2)                                        \
2538
uint64_t helper_float_ ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1,  \
2539
                                           uint64_t fdt2)                 \
2540
{                                                                         \
2541
    fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status);          \
2542
    return float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status);          \
2543
}                                                                         \
2544
                                                                          \
2545
uint32_t helper_float_ ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1,  \
2546
                                           uint32_t fst2)                 \
2547
{                                                                         \
2548
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
2549
    return float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
2550
}                                                                         \
2551
                                                                          \
2552
uint64_t helper_float_ ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1, \
2553
                                            uint64_t fdt2)                \
2554
{                                                                         \
2555
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;                                    \
2556
    uint32_t fsth0 = fdt0 >> 32;                                          \
2557
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;                                    \
2558
    uint32_t fsth1 = fdt1 >> 32;                                          \
2559
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;                                    \
2560
    uint32_t fsth2 = fdt2 >> 32;                                          \
2561
                                                                          \
2562
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
2563
    fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status);       \
2564
    fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
2565
    fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status);       \
2566
    return ((uint64_t)fsth2 << 32) | fst2;                                \
2567
}
2568

    
2569
FLOAT_TERNOP(mul, add)
2570
FLOAT_TERNOP(mul, sub)
2571
#undef FLOAT_TERNOP
2572

    
2573
/* negated ternary operations */
2574
#define FLOAT_NTERNOP(name1, name2)                                       \
2575
uint64_t helper_float_n ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \
2576
                                           uint64_t fdt2)                 \
2577
{                                                                         \
2578
    fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status);          \
2579
    fdt2 = float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status);          \
2580
    return float64_chs(fdt2);                                             \
2581
}                                                                         \
2582
                                                                          \
2583
uint32_t helper_float_n ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \
2584
                                           uint32_t fst2)                 \
2585
{                                                                         \
2586
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
2587
    fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
2588
    return float32_chs(fst2);                                             \
2589
}                                                                         \
2590
                                                                          \
2591
uint64_t helper_float_n ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1,\
2592
                                           uint64_t fdt2)                 \
2593
{                                                                         \
2594
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;                                    \
2595
    uint32_t fsth0 = fdt0 >> 32;                                          \
2596
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;                                    \
2597
    uint32_t fsth1 = fdt1 >> 32;                                          \
2598
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;                                    \
2599
    uint32_t fsth2 = fdt2 >> 32;                                          \
2600
                                                                          \
2601
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
2602
    fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status);       \
2603
    fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
2604
    fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status);       \
2605
    fst2 = float32_chs(fst2);                                             \
2606
    fsth2 = float32_chs(fsth2);                                           \
2607
    return ((uint64_t)fsth2 << 32) | fst2;                                \
2608
}
2609

    
2610
FLOAT_NTERNOP(mul, add)
2611
FLOAT_NTERNOP(mul, sub)
2612
#undef FLOAT_NTERNOP
2613

    
2614
/* MIPS specific binary operations */
2615
uint64_t helper_float_recip2_d(uint64_t fdt0, uint64_t fdt2)
2616
{
2617
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2618
    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
2619
    fdt2 = float64_chs(float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status));
2620
    update_fcr31();
2621
    return fdt2;
2622
}
2623

    
2624
uint32_t helper_float_recip2_s(uint32_t fst0, uint32_t fst2)
2625
{
2626
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2627
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2628
    fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
2629
    update_fcr31();
2630
    return fst2;
2631
}
2632

    
2633
uint64_t helper_float_recip2_ps(uint64_t fdt0, uint64_t fdt2)
2634
{
2635
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2636
    uint32_t fsth0 = fdt0 >> 32;
2637
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
2638
    uint32_t fsth2 = fdt2 >> 32;
2639

    
2640
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2641
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2642
    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
2643
    fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
2644
    fsth2 = float32_chs(float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status));
2645
    update_fcr31();
2646
    return ((uint64_t)fsth2 << 32) | fst2;
2647
}
2648

    
2649
uint64_t helper_float_rsqrt2_d(uint64_t fdt0, uint64_t fdt2)
2650
{
2651
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2652
    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
2653
    fdt2 = float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status);
2654
    fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
2655
    update_fcr31();
2656
    return fdt2;
2657
}
2658

    
2659
uint32_t helper_float_rsqrt2_s(uint32_t fst0, uint32_t fst2)
2660
{
2661
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2662
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2663
    fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
2664
    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
2665
    update_fcr31();
2666
    return fst2;
2667
}
2668

    
2669
uint64_t helper_float_rsqrt2_ps(uint64_t fdt0, uint64_t fdt2)
2670
{
2671
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2672
    uint32_t fsth0 = fdt0 >> 32;
2673
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
2674
    uint32_t fsth2 = fdt2 >> 32;
2675

    
2676
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2677
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2678
    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
2679
    fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
2680
    fsth2 = float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status);
2681
    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
2682
    fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
2683
    update_fcr31();
2684
    return ((uint64_t)fsth2 << 32) | fst2;
2685
}
2686

    
2687
uint64_t helper_float_addr_ps(uint64_t fdt0, uint64_t fdt1)
2688
{
2689
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2690
    uint32_t fsth0 = fdt0 >> 32;
2691
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;
2692
    uint32_t fsth1 = fdt1 >> 32;
2693
    uint32_t fst2;
2694
    uint32_t fsth2;
2695

    
2696
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2697
    fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
2698
    fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
2699
    update_fcr31();
2700
    return ((uint64_t)fsth2 << 32) | fst2;
2701
}
2702

    
2703
uint64_t helper_float_mulr_ps(uint64_t fdt0, uint64_t fdt1)
2704
{
2705
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2706
    uint32_t fsth0 = fdt0 >> 32;
2707
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;
2708
    uint32_t fsth1 = fdt1 >> 32;
2709
    uint32_t fst2;
2710
    uint32_t fsth2;
2711

    
2712
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2713
    fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
2714
    fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
2715
    update_fcr31();
2716
    return ((uint64_t)fsth2 << 32) | fst2;
2717
}
2718

    
2719
/* compare operations */
2720
#define FOP_COND_D(op, cond)                                   \
2721
void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
2722
{                                                              \
2723
    int c = cond;                                              \
2724
    update_fcr31();                                            \
2725
    if (c)                                                     \
2726
        SET_FP_COND(cc, env->active_fpu);                      \
2727
    else                                                       \
2728
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2729
}                                                              \
2730
void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
2731
{                                                              \
2732
    int c;                                                     \
2733
    fdt0 = float64_abs(fdt0);                                  \
2734
    fdt1 = float64_abs(fdt1);                                  \
2735
    c = cond;                                                  \
2736
    update_fcr31();                                            \
2737
    if (c)                                                     \
2738
        SET_FP_COND(cc, env->active_fpu);                      \
2739
    else                                                       \
2740
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2741
}
2742

    
2743
static int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
2744
{
2745
    if (float64_is_signaling_nan(a) ||
2746
        float64_is_signaling_nan(b) ||
2747
        (sig && (float64_is_nan(a) || float64_is_nan(b)))) {
2748
        float_raise(float_flag_invalid, status);
2749
        return 1;
2750
    } else if (float64_is_nan(a) || float64_is_nan(b)) {
2751
        return 1;
2752
    } else {
2753
        return 0;
2754
    }
2755
}
2756

    
2757
/* NOTE: the comma operator will make "cond" to eval to false,
2758
 * but float*_is_unordered() is still called. */
2759
FOP_COND_D(f,   (float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status), 0))
2760
FOP_COND_D(un,  float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status))
2761
FOP_COND_D(eq,  !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
2762
FOP_COND_D(ueq, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
2763
FOP_COND_D(olt, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
2764
FOP_COND_D(ult, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
2765
FOP_COND_D(ole, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
2766
FOP_COND_D(ule, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
2767
/* NOTE: the comma operator will make "cond" to eval to false,
2768
 * but float*_is_unordered() is still called. */
2769
FOP_COND_D(sf,  (float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status), 0))
2770
FOP_COND_D(ngle,float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status))
2771
FOP_COND_D(seq, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
2772
FOP_COND_D(ngl, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
2773
FOP_COND_D(lt,  !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
2774
FOP_COND_D(nge, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
2775
FOP_COND_D(le,  !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
2776
FOP_COND_D(ngt, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
2777

    
2778
#define FOP_COND_S(op, cond)                                   \
2779
void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc)    \
2780
{                                                              \
2781
    int c = cond;                                              \
2782
    update_fcr31();                                            \
2783
    if (c)                                                     \
2784
        SET_FP_COND(cc, env->active_fpu);                      \
2785
    else                                                       \
2786
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2787
}                                                              \
2788
void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
2789
{                                                              \
2790
    int c;                                                     \
2791
    fst0 = float32_abs(fst0);                                  \
2792
    fst1 = float32_abs(fst1);                                  \
2793
    c = cond;                                                  \
2794
    update_fcr31();                                            \
2795
    if (c)                                                     \
2796
        SET_FP_COND(cc, env->active_fpu);                      \
2797
    else                                                       \
2798
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2799
}
2800

    
2801
static flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
2802
{
2803
    if (float32_is_signaling_nan(a) ||
2804
        float32_is_signaling_nan(b) ||
2805
        (sig && (float32_is_nan(a) || float32_is_nan(b)))) {
2806
        float_raise(float_flag_invalid, status);
2807
        return 1;
2808
    } else if (float32_is_nan(a) || float32_is_nan(b)) {
2809
        return 1;
2810
    } else {
2811
        return 0;
2812
    }
2813
}
2814

    
2815
/* NOTE: the comma operator will make "cond" to eval to false,
2816
 * but float*_is_unordered() is still called. */
2817
FOP_COND_S(f,   (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0))
2818
FOP_COND_S(un,  float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status))
2819
FOP_COND_S(eq,  !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status))
2820
FOP_COND_S(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
2821
FOP_COND_S(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status))
2822
FOP_COND_S(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
2823
FOP_COND_S(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status))
2824
FOP_COND_S(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
2825
/* NOTE: the comma operator will make "cond" to eval to false,
2826
 * but float*_is_unordered() is still called. */
2827
FOP_COND_S(sf,  (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0))
2828
FOP_COND_S(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status))
2829
FOP_COND_S(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status))
2830
FOP_COND_S(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
2831
FOP_COND_S(lt,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status))
2832
FOP_COND_S(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
2833
FOP_COND_S(le,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status))
2834
FOP_COND_S(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
2835

    
2836
#define FOP_COND_PS(op, condl, condh)                           \
2837
void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
2838
{                                                               \
2839
    uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF);             \
2840
    uint32_t fsth0 = float32_abs(fdt0 >> 32);                   \
2841
    uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF);             \
2842
    uint32_t fsth1 = float32_abs(fdt1 >> 32);                   \
2843
    int cl = condl;                                             \
2844
    int ch = condh;                                             \
2845
                                                                \
2846
    update_fcr31();                                             \
2847
    if (cl)                                                     \
2848
        SET_FP_COND(cc, env->active_fpu);                       \
2849
    else                                                        \
2850
        CLEAR_FP_COND(cc, env->active_fpu);                     \
2851
    if (ch)                                                     \
2852
        SET_FP_COND(cc + 1, env->active_fpu);                   \
2853
    else                                                        \
2854
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
2855
}                                                               \
2856
void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
2857
{                                                               \
2858
    uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF);             \
2859
    uint32_t fsth0 = float32_abs(fdt0 >> 32);                   \
2860
    uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF);             \
2861
    uint32_t fsth1 = float32_abs(fdt1 >> 32);                   \
2862
    int cl = condl;                                             \
2863
    int ch = condh;                                             \
2864
                                                                \
2865
    update_fcr31();                                             \
2866
    if (cl)                                                     \
2867
        SET_FP_COND(cc, env->active_fpu);                       \
2868
    else                                                        \
2869
        CLEAR_FP_COND(cc, env->active_fpu);                     \
2870
    if (ch)                                                     \
2871
        SET_FP_COND(cc + 1, env->active_fpu);                   \
2872
    else                                                        \
2873
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
2874
}
2875

    
2876
/* NOTE: the comma operator will make "cond" to eval to false,
2877
 * but float*_is_unordered() is still called. */
2878
FOP_COND_PS(f,   (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0),
2879
                 (float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status), 0))
2880
FOP_COND_PS(un,  float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status),
2881
                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status))
2882
FOP_COND_PS(eq,  !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)   && float32_eq(fst0, fst1, &env->active_fpu.fp_status),
2883
                 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
2884
FOP_COND_PS(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
2885
                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
2886
FOP_COND_PS(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)   && float32_lt(fst0, fst1, &env->active_fpu.fp_status),
2887
                 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
2888
FOP_COND_PS(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
2889
                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
2890
FOP_COND_PS(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)   && float32_le(fst0, fst1, &env->active_fpu.fp_status),
2891
                 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
2892
FOP_COND_PS(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
2893
                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
2894
/* NOTE: the comma operator will make "cond" to eval to false,
2895
 * but float*_is_unordered() is still called. */
2896
FOP_COND_PS(sf,  (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0),
2897
                 (float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status), 0))
2898
FOP_COND_PS(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status),
2899
                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status))
2900
FOP_COND_PS(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)   && float32_eq(fst0, fst1, &env->active_fpu.fp_status),
2901
                 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
2902
FOP_COND_PS(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
2903
                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
2904
FOP_COND_PS(lt,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)   && float32_lt(fst0, fst1, &env->active_fpu.fp_status),
2905
                 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
2906
FOP_COND_PS(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
2907
                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
2908
FOP_COND_PS(le,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)   && float32_le(fst0, fst1, &env->active_fpu.fp_status),
2909
                 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
2910
FOP_COND_PS(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
2911
                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))