Statistics
| Branch: | Revision:

root / target-mips / op_helper.c @ a7812ae4

History | View | Annotate | Download (88.3 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 do_raise_exception_err (uint32_t exception, int error_code)
30
{
31
#if 1
32
    if (logfile && exception < 0x100)
33
        fprintf(logfile, "%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 do_raise_exception (uint32_t exception)
41
{
42
    do_raise_exception_err(exception, 0);
43
}
44

    
45
void do_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
        do_raise_exception(EXCP_EXT_INTERRUPT);
54
    }
55
}
56

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

    
68
target_ulong do_clo (target_ulong t0)
69
{
70
    return clo32(t0);
71
}
72

    
73
target_ulong do_clz (target_ulong t0)
74
{
75
    return clz32(t0);
76
}
77

    
78
#if defined(TARGET_MIPS64)
79
target_ulong do_dclo (target_ulong t0)
80
{
81
    return clo64(t0);
82
}
83

    
84
target_ulong do_dclz (target_ulong t0)
85
{
86
    return clz64(t0);
87
}
88
#endif /* TARGET_MIPS64 */
89

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

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

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

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

    
114
#if TARGET_LONG_BITS > HOST_LONG_BITS
115
void do_madd (target_ulong t0, target_ulong t1)
116
{
117
    int64_t tmp;
118

    
119
    tmp = ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1);
120
    set_HILO((int64_t)get_HILO() + tmp);
121
}
122

    
123
void do_maddu (target_ulong t0, target_ulong t1)
124
{
125
    uint64_t tmp;
126

    
127
    tmp = ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1);
128
    set_HILO(get_HILO() + tmp);
129
}
130

    
131
void do_msub (target_ulong t0, target_ulong t1)
132
{
133
    int64_t tmp;
134

    
135
    tmp = ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1);
136
    set_HILO((int64_t)get_HILO() - tmp);
137
}
138

    
139
void do_msubu (target_ulong t0, target_ulong t1)
140
{
141
    uint64_t tmp;
142

    
143
    tmp = ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1);
144
    set_HILO(get_HILO() - tmp);
145
}
146
#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
147

    
148
/* Multiplication variants of the vr54xx. */
149
target_ulong do_muls (target_ulong t0, target_ulong t1)
150
{
151
    set_HI_LOT0(t0, 0 - ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1));
152

    
153
    return t0;
154
}
155

    
156
target_ulong do_mulsu (target_ulong t0, target_ulong t1)
157
{
158
    set_HI_LOT0(t0, 0 - ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1));
159

    
160
    return t0;
161
}
162

    
163
target_ulong do_macc (target_ulong t0, target_ulong t1)
164
{
165
    set_HI_LOT0(t0, ((int64_t)get_HILO()) + ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1));
166

    
167
    return t0;
168
}
169

    
170
target_ulong do_macchi (target_ulong t0, target_ulong t1)
171
{
172
    set_HIT0_LO(t0, ((int64_t)get_HILO()) + ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1));
173

    
174
    return t0;
175
}
176

    
177
target_ulong do_maccu (target_ulong t0, target_ulong t1)
178
{
179
    set_HI_LOT0(t0, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1));
180

    
181
    return t0;
182
}
183

    
184
target_ulong do_macchiu (target_ulong t0, target_ulong t1)
185
{
186
    set_HIT0_LO(t0, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1));
187

    
188
    return t0;
189
}
190

    
191
target_ulong do_msac (target_ulong t0, target_ulong t1)
192
{
193
    set_HI_LOT0(t0, ((int64_t)get_HILO()) - ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1));
194

    
195
    return t0;
196
}
197

    
198
target_ulong do_msachi (target_ulong t0, target_ulong t1)
199
{
200
    set_HIT0_LO(t0, ((int64_t)get_HILO()) - ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1));
201

    
202
    return t0;
203
}
204

    
205
target_ulong do_msacu (target_ulong t0, target_ulong t1)
206
{
207
    set_HI_LOT0(t0, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1));
208

    
209
    return t0;
210
}
211

    
212
target_ulong do_msachiu (target_ulong t0, target_ulong t1)
213
{
214
    set_HIT0_LO(t0, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1));
215

    
216
    return t0;
217
}
218

    
219
target_ulong do_mulhi (target_ulong t0, target_ulong t1)
220
{
221
    set_HIT0_LO(t0, (int64_t)(int32_t)t0 * (int64_t)(int32_t)t1);
222

    
223
    return t0;
224
}
225

    
226
target_ulong do_mulhiu (target_ulong t0, target_ulong t1)
227
{
228
    set_HIT0_LO(t0, (uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1);
229

    
230
    return t0;
231
}
232

    
233
target_ulong do_mulshi (target_ulong t0, target_ulong t1)
234
{
235
    set_HIT0_LO(t0, 0 - ((int64_t)(int32_t)t0 * (int64_t)(int32_t)t1));
236

    
237
    return t0;
238
}
239

    
240
target_ulong do_mulshiu (target_ulong t0, target_ulong t1)
241
{
242
    set_HIT0_LO(t0, 0 - ((uint64_t)(uint32_t)t0 * (uint64_t)(uint32_t)t1));
243

    
244
    return t0;
245
}
246

    
247
#ifdef TARGET_MIPS64
248
void do_dmult (target_ulong t0, target_ulong t1)
249
{
250
    muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), t0, t1);
251
}
252

    
253
void do_dmultu (target_ulong t0, target_ulong t1)
254
{
255
    mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), t0, t1);
256
}
257
#endif
258

    
259
#ifdef TARGET_WORDS_BIGENDIAN
260
#define GET_LMASK(v) ((v) & 3)
261
#define GET_OFFSET(addr, offset) (addr + (offset))
262
#else
263
#define GET_LMASK(v) (((v) & 3) ^ 3)
264
#define GET_OFFSET(addr, offset) (addr - (offset))
265
#endif
266

    
267
target_ulong do_lwl(target_ulong t0, target_ulong t1, int mem_idx)
268
{
269
    target_ulong tmp;
270

    
271
#ifdef CONFIG_USER_ONLY
272
#define ldfun ldub_raw
273
#else
274
    int (*ldfun)(target_ulong);
275

    
276
    switch (mem_idx)
277
    {
278
    case 0: ldfun = ldub_kernel; break;
279
    case 1: ldfun = ldub_super; break;
280
    default:
281
    case 2: ldfun = ldub_user; break;
282
    }
283
#endif
284
    tmp = ldfun(t0);
285
    t1 = (t1 & 0x00FFFFFF) | (tmp << 24);
286

    
287
    if (GET_LMASK(t0) <= 2) {
288
        tmp = ldfun(GET_OFFSET(t0, 1));
289
        t1 = (t1 & 0xFF00FFFF) | (tmp << 16);
290
    }
291

    
292
    if (GET_LMASK(t0) <= 1) {
293
        tmp = ldfun(GET_OFFSET(t0, 2));
294
        t1 = (t1 & 0xFFFF00FF) | (tmp << 8);
295
    }
296

    
297
    if (GET_LMASK(t0) == 0) {
298
        tmp = ldfun(GET_OFFSET(t0, 3));
299
        t1 = (t1 & 0xFFFFFF00) | tmp;
300
    }
301
    return (int32_t)t1;
302
}
303

    
304
target_ulong do_lwr(target_ulong t0, target_ulong t1, int mem_idx)
305
{
306
    target_ulong tmp;
307

    
308
#ifdef CONFIG_USER_ONLY
309
#define ldfun ldub_raw
310
#else
311
    int (*ldfun)(target_ulong);
312

    
313
    switch (mem_idx)
314
    {
315
    case 0: ldfun = ldub_kernel; break;
316
    case 1: ldfun = ldub_super; break;
317
    default:
318
    case 2: ldfun = ldub_user; break;
319
    }
320
#endif
321
    tmp = ldfun(t0);
322
    t1 = (t1 & 0xFFFFFF00) | tmp;
323

    
324
    if (GET_LMASK(t0) >= 1) {
325
        tmp = ldfun(GET_OFFSET(t0, -1));
326
        t1 = (t1 & 0xFFFF00FF) | (tmp << 8);
327
    }
328

    
329
    if (GET_LMASK(t0) >= 2) {
330
        tmp = ldfun(GET_OFFSET(t0, -2));
331
        t1 = (t1 & 0xFF00FFFF) | (tmp << 16);
332
    }
333

    
334
    if (GET_LMASK(t0) == 3) {
335
        tmp = ldfun(GET_OFFSET(t0, -3));
336
        t1 = (t1 & 0x00FFFFFF) | (tmp << 24);
337
    }
338
    return (int32_t)t1;
339
}
340

    
341
void do_swl(target_ulong t0, target_ulong t1, int mem_idx)
342
{
343
#ifdef CONFIG_USER_ONLY
344
#define stfun stb_raw
345
#else
346
    void (*stfun)(target_ulong, int);
347

    
348
    switch (mem_idx)
349
    {
350
    case 0: stfun = stb_kernel; break;
351
    case 1: stfun = stb_super; break;
352
    default:
353
    case 2: stfun = stb_user; break;
354
    }
355
#endif
356
    stfun(t0, (uint8_t)(t1 >> 24));
357

    
358
    if (GET_LMASK(t0) <= 2)
359
        stfun(GET_OFFSET(t0, 1), (uint8_t)(t1 >> 16));
360

    
361
    if (GET_LMASK(t0) <= 1)
362
        stfun(GET_OFFSET(t0, 2), (uint8_t)(t1 >> 8));
363

    
364
    if (GET_LMASK(t0) == 0)
365
        stfun(GET_OFFSET(t0, 3), (uint8_t)t1);
366
}
367

    
368
void do_swr(target_ulong t0, target_ulong t1, int mem_idx)
369
{
370
#ifdef CONFIG_USER_ONLY
371
#define stfun stb_raw
372
#else
373
    void (*stfun)(target_ulong, int);
374

    
375
    switch (mem_idx)
376
    {
377
    case 0: stfun = stb_kernel; break;
378
    case 1: stfun = stb_super; break;
379
    default:
380
    case 2: stfun = stb_user; break;
381
    }
382
#endif
383
    stfun(t0, (uint8_t)t1);
384

    
385
    if (GET_LMASK(t0) >= 1)
386
        stfun(GET_OFFSET(t0, -1), (uint8_t)(t1 >> 8));
387

    
388
    if (GET_LMASK(t0) >= 2)
389
        stfun(GET_OFFSET(t0, -2), (uint8_t)(t1 >> 16));
390

    
391
    if (GET_LMASK(t0) == 3)
392
        stfun(GET_OFFSET(t0, -3), (uint8_t)(t1 >> 24));
393
}
394

    
395
#if defined(TARGET_MIPS64)
396
/* "half" load and stores.  We must do the memory access inline,
397
   or fault handling won't work.  */
398

    
399
#ifdef TARGET_WORDS_BIGENDIAN
400
#define GET_LMASK64(v) ((v) & 7)
401
#else
402
#define GET_LMASK64(v) (((v) & 7) ^ 7)
403
#endif
404

    
405
target_ulong do_ldl(target_ulong t0, target_ulong t1, int mem_idx)
406
{
407
    uint64_t tmp;
408

    
409
#ifdef CONFIG_USER_ONLY
410
#define ldfun ldub_raw
411
#else
412
    int (*ldfun)(target_ulong);
413

    
414
    switch (mem_idx)
415
    {
416
    case 0: ldfun = ldub_kernel; break;
417
    case 1: ldfun = ldub_super; break;
418
    default:
419
    case 2: ldfun = ldub_user; break;
420
    }
421
#endif
422
    tmp = ldfun(t0);
423
    t1 = (t1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
424

    
425
    if (GET_LMASK64(t0) <= 6) {
426
        tmp = ldfun(GET_OFFSET(t0, 1));
427
        t1 = (t1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
428
    }
429

    
430
    if (GET_LMASK64(t0) <= 5) {
431
        tmp = ldfun(GET_OFFSET(t0, 2));
432
        t1 = (t1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
433
    }
434

    
435
    if (GET_LMASK64(t0) <= 4) {
436
        tmp = ldfun(GET_OFFSET(t0, 3));
437
        t1 = (t1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
438
    }
439

    
440
    if (GET_LMASK64(t0) <= 3) {
441
        tmp = ldfun(GET_OFFSET(t0, 4));
442
        t1 = (t1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
443
    }
444

    
445
    if (GET_LMASK64(t0) <= 2) {
446
        tmp = ldfun(GET_OFFSET(t0, 5));
447
        t1 = (t1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
448
    }
449

    
450
    if (GET_LMASK64(t0) <= 1) {
451
        tmp = ldfun(GET_OFFSET(t0, 6));
452
        t1 = (t1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8);
453
    }
454

    
455
    if (GET_LMASK64(t0) == 0) {
456
        tmp = ldfun(GET_OFFSET(t0, 7));
457
        t1 = (t1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
458
    }
459

    
460
    return t1;
461
}
462

    
463
target_ulong do_ldr(target_ulong t0, target_ulong t1, int mem_idx)
464
{
465
    uint64_t tmp;
466

    
467
#ifdef CONFIG_USER_ONLY
468
#define ldfun ldub_raw
469
#else
470
    int (*ldfun)(target_ulong);
471

    
472
    switch (mem_idx)
473
    {
474
    case 0: ldfun = ldub_kernel; break;
475
    case 1: ldfun = ldub_super; break;
476
    default:
477
    case 2: ldfun = ldub_user; break;
478
    }
479
#endif
480
    tmp = ldfun(t0);
481
    t1 = (t1 & 0xFFFFFFFFFFFFFF00ULL) | tmp;
482

    
483
    if (GET_LMASK64(t0) >= 1) {
484
        tmp = ldfun(GET_OFFSET(t0, -1));
485
        t1 = (t1 & 0xFFFFFFFFFFFF00FFULL) | (tmp  << 8);
486
    }
487

    
488
    if (GET_LMASK64(t0) >= 2) {
489
        tmp = ldfun(GET_OFFSET(t0, -2));
490
        t1 = (t1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16);
491
    }
492

    
493
    if (GET_LMASK64(t0) >= 3) {
494
        tmp = ldfun(GET_OFFSET(t0, -3));
495
        t1 = (t1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24);
496
    }
497

    
498
    if (GET_LMASK64(t0) >= 4) {
499
        tmp = ldfun(GET_OFFSET(t0, -4));
500
        t1 = (t1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32);
501
    }
502

    
503
    if (GET_LMASK64(t0) >= 5) {
504
        tmp = ldfun(GET_OFFSET(t0, -5));
505
        t1 = (t1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40);
506
    }
507

    
508
    if (GET_LMASK64(t0) >= 6) {
509
        tmp = ldfun(GET_OFFSET(t0, -6));
510
        t1 = (t1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48);
511
    }
512

    
513
    if (GET_LMASK64(t0) == 7) {
514
        tmp = ldfun(GET_OFFSET(t0, -7));
515
        t1 = (t1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56);
516
    }
517

    
518
    return t1;
519
}
520

    
521
void do_sdl(target_ulong t0, target_ulong t1, int mem_idx)
522
{
523
#ifdef CONFIG_USER_ONLY
524
#define stfun stb_raw
525
#else
526
    void (*stfun)(target_ulong, int);
527

    
528
    switch (mem_idx)
529
    {
530
    case 0: stfun = stb_kernel; break;
531
    case 1: stfun = stb_super; break;
532
    default:
533
    case 2: stfun = stb_user; break;
534
    }
535
#endif
536
    stfun(t0, (uint8_t)(t1 >> 56));
537

    
538
    if (GET_LMASK64(t0) <= 6)
539
        stfun(GET_OFFSET(t0, 1), (uint8_t)(t1 >> 48));
540

    
541
    if (GET_LMASK64(t0) <= 5)
542
        stfun(GET_OFFSET(t0, 2), (uint8_t)(t1 >> 40));
543

    
544
    if (GET_LMASK64(t0) <= 4)
545
        stfun(GET_OFFSET(t0, 3), (uint8_t)(t1 >> 32));
546

    
547
    if (GET_LMASK64(t0) <= 3)
548
        stfun(GET_OFFSET(t0, 4), (uint8_t)(t1 >> 24));
549

    
550
    if (GET_LMASK64(t0) <= 2)
551
        stfun(GET_OFFSET(t0, 5), (uint8_t)(t1 >> 16));
552

    
553
    if (GET_LMASK64(t0) <= 1)
554
        stfun(GET_OFFSET(t0, 6), (uint8_t)(t1 >> 8));
555

    
556
    if (GET_LMASK64(t0) <= 0)
557
        stfun(GET_OFFSET(t0, 7), (uint8_t)t1);
558
}
559

    
560
void do_sdr(target_ulong t0, target_ulong t1, int mem_idx)
561
{
562
#ifdef CONFIG_USER_ONLY
563
#define stfun stb_raw
564
#else
565
    void (*stfun)(target_ulong, int);
566

    
567
    switch (mem_idx)
568
    {
569
    case 0: stfun = stb_kernel; break;
570
    case 1: stfun = stb_super; break;
571
     default:
572
    case 2: stfun = stb_user; break;
573
    }
574
#endif
575
    stfun(t0, (uint8_t)t1);
576

    
577
    if (GET_LMASK64(t0) >= 1)
578
        stfun(GET_OFFSET(t0, -1), (uint8_t)(t1 >> 8));
579

    
580
    if (GET_LMASK64(t0) >= 2)
581
        stfun(GET_OFFSET(t0, -2), (uint8_t)(t1 >> 16));
582

    
583
    if (GET_LMASK64(t0) >= 3)
584
        stfun(GET_OFFSET(t0, -3), (uint8_t)(t1 >> 24));
585

    
586
    if (GET_LMASK64(t0) >= 4)
587
        stfun(GET_OFFSET(t0, -4), (uint8_t)(t1 >> 32));
588

    
589
    if (GET_LMASK64(t0) >= 5)
590
        stfun(GET_OFFSET(t0, -5), (uint8_t)(t1 >> 40));
591

    
592
    if (GET_LMASK64(t0) >= 6)
593
        stfun(GET_OFFSET(t0, -6), (uint8_t)(t1 >> 48));
594

    
595
    if (GET_LMASK64(t0) == 7)
596
        stfun(GET_OFFSET(t0, -7), (uint8_t)(t1 >> 56));
597
}
598
#endif /* TARGET_MIPS64 */
599

    
600
#ifndef CONFIG_USER_ONLY
601
/* CP0 helpers */
602
target_ulong do_mfc0_mvpcontrol (void)
603
{
604
    return env->mvp->CP0_MVPControl;
605
}
606

    
607
target_ulong do_mfc0_mvpconf0 (void)
608
{
609
    return env->mvp->CP0_MVPConf0;
610
}
611

    
612
target_ulong do_mfc0_mvpconf1 (void)
613
{
614
    return env->mvp->CP0_MVPConf1;
615
}
616

    
617
target_ulong do_mfc0_random (void)
618
{
619
    return (int32_t)cpu_mips_get_random(env);
620
}
621

    
622
target_ulong do_mfc0_tcstatus (void)
623
{
624
    return env->active_tc.CP0_TCStatus;
625
}
626

    
627
target_ulong do_mftc0_tcstatus(void)
628
{
629
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
630

    
631
    if (other_tc == env->current_tc)
632
        return env->active_tc.CP0_TCStatus;
633
    else
634
        return env->tcs[other_tc].CP0_TCStatus;
635
}
636

    
637
target_ulong do_mfc0_tcbind (void)
638
{
639
    return env->active_tc.CP0_TCBind;
640
}
641

    
642
target_ulong do_mftc0_tcbind(void)
643
{
644
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
645

    
646
    if (other_tc == env->current_tc)
647
        return env->active_tc.CP0_TCBind;
648
    else
649
        return env->tcs[other_tc].CP0_TCBind;
650
}
651

    
652
target_ulong do_mfc0_tcrestart (void)
653
{
654
    return env->active_tc.PC;
655
}
656

    
657
target_ulong do_mftc0_tcrestart(void)
658
{
659
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
660

    
661
    if (other_tc == env->current_tc)
662
        return env->active_tc.PC;
663
    else
664
        return env->tcs[other_tc].PC;
665
}
666

    
667
target_ulong do_mfc0_tchalt (void)
668
{
669
    return env->active_tc.CP0_TCHalt;
670
}
671

    
672
target_ulong do_mftc0_tchalt(void)
673
{
674
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
675

    
676
    if (other_tc == env->current_tc)
677
        return env->active_tc.CP0_TCHalt;
678
    else
679
        return env->tcs[other_tc].CP0_TCHalt;
680
}
681

    
682
target_ulong do_mfc0_tccontext (void)
683
{
684
    return env->active_tc.CP0_TCContext;
685
}
686

    
687
target_ulong do_mftc0_tccontext(void)
688
{
689
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
690

    
691
    if (other_tc == env->current_tc)
692
        return env->active_tc.CP0_TCContext;
693
    else
694
        return env->tcs[other_tc].CP0_TCContext;
695
}
696

    
697
target_ulong do_mfc0_tcschedule (void)
698
{
699
    return env->active_tc.CP0_TCSchedule;
700
}
701

    
702
target_ulong do_mftc0_tcschedule(void)
703
{
704
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
705

    
706
    if (other_tc == env->current_tc)
707
        return env->active_tc.CP0_TCSchedule;
708
    else
709
        return env->tcs[other_tc].CP0_TCSchedule;
710
}
711

    
712
target_ulong do_mfc0_tcschefback (void)
713
{
714
    return env->active_tc.CP0_TCScheFBack;
715
}
716

    
717
target_ulong do_mftc0_tcschefback(void)
718
{
719
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
720

    
721
    if (other_tc == env->current_tc)
722
        return env->active_tc.CP0_TCScheFBack;
723
    else
724
        return env->tcs[other_tc].CP0_TCScheFBack;
725
}
726

    
727
target_ulong do_mfc0_count (void)
728
{
729
    return (int32_t)cpu_mips_get_count(env);
730
}
731

    
732
target_ulong do_mftc0_entryhi(void)
733
{
734
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
735
    int32_t tcstatus;
736

    
737
    if (other_tc == env->current_tc)
738
        tcstatus = env->active_tc.CP0_TCStatus;
739
    else
740
        tcstatus = env->tcs[other_tc].CP0_TCStatus;
741

    
742
    return (env->CP0_EntryHi & ~0xff) | (tcstatus & 0xff);
743
}
744

    
745
target_ulong do_mftc0_status(void)
746
{
747
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
748
    target_ulong t0;
749
    int32_t tcstatus;
750

    
751
    if (other_tc == env->current_tc)
752
        tcstatus = env->active_tc.CP0_TCStatus;
753
    else
754
        tcstatus = env->tcs[other_tc].CP0_TCStatus;
755

    
756
    t0 = env->CP0_Status & ~0xf1000018;
757
    t0 |= tcstatus & (0xf << CP0TCSt_TCU0);
758
    t0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX);
759
    t0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_KSU);
760

    
761
    return t0;
762
}
763

    
764
target_ulong do_mfc0_lladdr (void)
765
{
766
    return (int32_t)env->CP0_LLAddr >> 4;
767
}
768

    
769
target_ulong do_mfc0_watchlo (uint32_t sel)
770
{
771
    return (int32_t)env->CP0_WatchLo[sel];
772
}
773

    
774
target_ulong do_mfc0_watchhi (uint32_t sel)
775
{
776
    return env->CP0_WatchHi[sel];
777
}
778

    
779
target_ulong do_mfc0_debug (void)
780
{
781
    target_ulong t0 = env->CP0_Debug;
782
    if (env->hflags & MIPS_HFLAG_DM)
783
        t0 |= 1 << CP0DB_DM;
784

    
785
    return t0;
786
}
787

    
788
target_ulong do_mftc0_debug(void)
789
{
790
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
791
    int32_t tcstatus;
792

    
793
    if (other_tc == env->current_tc)
794
        tcstatus = env->active_tc.CP0_Debug_tcstatus;
795
    else
796
        tcstatus = env->tcs[other_tc].CP0_Debug_tcstatus;
797

    
798
    /* XXX: Might be wrong, check with EJTAG spec. */
799
    return (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
800
            (tcstatus & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
801
}
802

    
803
#if defined(TARGET_MIPS64)
804
target_ulong do_dmfc0_tcrestart (void)
805
{
806
    return env->active_tc.PC;
807
}
808

    
809
target_ulong do_dmfc0_tchalt (void)
810
{
811
    return env->active_tc.CP0_TCHalt;
812
}
813

    
814
target_ulong do_dmfc0_tccontext (void)
815
{
816
    return env->active_tc.CP0_TCContext;
817
}
818

    
819
target_ulong do_dmfc0_tcschedule (void)
820
{
821
    return env->active_tc.CP0_TCSchedule;
822
}
823

    
824
target_ulong do_dmfc0_tcschefback (void)
825
{
826
    return env->active_tc.CP0_TCScheFBack;
827
}
828

    
829
target_ulong do_dmfc0_lladdr (void)
830
{
831
    return env->CP0_LLAddr >> 4;
832
}
833

    
834
target_ulong do_dmfc0_watchlo (uint32_t sel)
835
{
836
    return env->CP0_WatchLo[sel];
837
}
838
#endif /* TARGET_MIPS64 */
839

    
840
void do_mtc0_index (target_ulong t0)
841
{
842
    int num = 1;
843
    unsigned int tmp = env->tlb->nb_tlb;
844

    
845
    do {
846
        tmp >>= 1;
847
        num <<= 1;
848
    } while (tmp);
849
    env->CP0_Index = (env->CP0_Index & 0x80000000) | (t0 & (num - 1));
850
}
851

    
852
void do_mtc0_mvpcontrol (target_ulong t0)
853
{
854
    uint32_t mask = 0;
855
    uint32_t newval;
856

    
857
    if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))
858
        mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
859
                (1 << CP0MVPCo_EVP);
860
    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
861
        mask |= (1 << CP0MVPCo_STLB);
862
    newval = (env->mvp->CP0_MVPControl & ~mask) | (t0 & mask);
863

    
864
    // TODO: Enable/disable shared TLB, enable/disable VPEs.
865

    
866
    env->mvp->CP0_MVPControl = newval;
867
}
868

    
869
void do_mtc0_vpecontrol (target_ulong t0)
870
{
871
    uint32_t mask;
872
    uint32_t newval;
873

    
874
    mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
875
           (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
876
    newval = (env->CP0_VPEControl & ~mask) | (t0 & mask);
877

    
878
    /* Yield scheduler intercept not implemented. */
879
    /* Gating storage scheduler intercept not implemented. */
880

    
881
    // TODO: Enable/disable TCs.
882

    
883
    env->CP0_VPEControl = newval;
884
}
885

    
886
void do_mtc0_vpeconf0 (target_ulong t0)
887
{
888
    uint32_t mask = 0;
889
    uint32_t newval;
890

    
891
    if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
892
        if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))
893
            mask |= (0xff << CP0VPEC0_XTC);
894
        mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
895
    }
896
    newval = (env->CP0_VPEConf0 & ~mask) | (t0 & mask);
897

    
898
    // TODO: TC exclusive handling due to ERL/EXL.
899

    
900
    env->CP0_VPEConf0 = newval;
901
}
902

    
903
void do_mtc0_vpeconf1 (target_ulong t0)
904
{
905
    uint32_t mask = 0;
906
    uint32_t newval;
907

    
908
    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
909
        mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
910
                (0xff << CP0VPEC1_NCP1);
911
    newval = (env->CP0_VPEConf1 & ~mask) | (t0 & mask);
912

    
913
    /* UDI not implemented. */
914
    /* CP2 not implemented. */
915

    
916
    // TODO: Handle FPU (CP1) binding.
917

    
918
    env->CP0_VPEConf1 = newval;
919
}
920

    
921
void do_mtc0_yqmask (target_ulong t0)
922
{
923
    /* Yield qualifier inputs not implemented. */
924
    env->CP0_YQMask = 0x00000000;
925
}
926

    
927
void do_mtc0_vpeopt (target_ulong t0)
928
{
929
    env->CP0_VPEOpt = t0 & 0x0000ffff;
930
}
931

    
932
void do_mtc0_entrylo0 (target_ulong t0)
933
{
934
    /* Large physaddr (PABITS) not implemented */
935
    /* 1k pages not implemented */
936
    env->CP0_EntryLo0 = t0 & 0x3FFFFFFF;
937
}
938

    
939
void do_mtc0_tcstatus (target_ulong t0)
940
{
941
    uint32_t mask = env->CP0_TCStatus_rw_bitmask;
942
    uint32_t newval;
943

    
944
    newval = (env->active_tc.CP0_TCStatus & ~mask) | (t0 & mask);
945

    
946
    // TODO: Sync with CP0_Status.
947

    
948
    env->active_tc.CP0_TCStatus = newval;
949
}
950

    
951
void do_mttc0_tcstatus (target_ulong t0)
952
{
953
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
954

    
955
    // TODO: Sync with CP0_Status.
956

    
957
    if (other_tc == env->current_tc)
958
        env->active_tc.CP0_TCStatus = t0;
959
    else
960
        env->tcs[other_tc].CP0_TCStatus = t0;
961
}
962

    
963
void do_mtc0_tcbind (target_ulong t0)
964
{
965
    uint32_t mask = (1 << CP0TCBd_TBE);
966
    uint32_t newval;
967

    
968
    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
969
        mask |= (1 << CP0TCBd_CurVPE);
970
    newval = (env->active_tc.CP0_TCBind & ~mask) | (t0 & mask);
971
    env->active_tc.CP0_TCBind = newval;
972
}
973

    
974
void do_mttc0_tcbind (target_ulong t0)
975
{
976
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
977
    uint32_t mask = (1 << CP0TCBd_TBE);
978
    uint32_t newval;
979

    
980
    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
981
        mask |= (1 << CP0TCBd_CurVPE);
982
    if (other_tc == env->current_tc) {
983
        newval = (env->active_tc.CP0_TCBind & ~mask) | (t0 & mask);
984
        env->active_tc.CP0_TCBind = newval;
985
    } else {
986
        newval = (env->tcs[other_tc].CP0_TCBind & ~mask) | (t0 & mask);
987
        env->tcs[other_tc].CP0_TCBind = newval;
988
    }
989
}
990

    
991
void do_mtc0_tcrestart (target_ulong t0)
992
{
993
    env->active_tc.PC = t0;
994
    env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
995
    env->CP0_LLAddr = 0ULL;
996
    /* MIPS16 not implemented. */
997
}
998

    
999
void do_mttc0_tcrestart (target_ulong t0)
1000
{
1001
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1002

    
1003
    if (other_tc == env->current_tc) {
1004
        env->active_tc.PC = t0;
1005
        env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1006
        env->CP0_LLAddr = 0ULL;
1007
        /* MIPS16 not implemented. */
1008
    } else {
1009
        env->tcs[other_tc].PC = t0;
1010
        env->tcs[other_tc].CP0_TCStatus &= ~(1 << CP0TCSt_TDS);
1011
        env->CP0_LLAddr = 0ULL;
1012
        /* MIPS16 not implemented. */
1013
    }
1014
}
1015

    
1016
void do_mtc0_tchalt (target_ulong t0)
1017
{
1018
    env->active_tc.CP0_TCHalt = t0 & 0x1;
1019

    
1020
    // TODO: Halt TC / Restart (if allocated+active) TC.
1021
}
1022

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

    
1027
    // TODO: Halt TC / Restart (if allocated+active) TC.
1028

    
1029
    if (other_tc == env->current_tc)
1030
        env->active_tc.CP0_TCHalt = t0;
1031
    else
1032
        env->tcs[other_tc].CP0_TCHalt = t0;
1033
}
1034

    
1035
void do_mtc0_tccontext (target_ulong t0)
1036
{
1037
    env->active_tc.CP0_TCContext = t0;
1038
}
1039

    
1040
void do_mttc0_tccontext (target_ulong t0)
1041
{
1042
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1043

    
1044
    if (other_tc == env->current_tc)
1045
        env->active_tc.CP0_TCContext = t0;
1046
    else
1047
        env->tcs[other_tc].CP0_TCContext = t0;
1048
}
1049

    
1050
void do_mtc0_tcschedule (target_ulong t0)
1051
{
1052
    env->active_tc.CP0_TCSchedule = t0;
1053
}
1054

    
1055
void do_mttc0_tcschedule (target_ulong t0)
1056
{
1057
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1058

    
1059
    if (other_tc == env->current_tc)
1060
        env->active_tc.CP0_TCSchedule = t0;
1061
    else
1062
        env->tcs[other_tc].CP0_TCSchedule = t0;
1063
}
1064

    
1065
void do_mtc0_tcschefback (target_ulong t0)
1066
{
1067
    env->active_tc.CP0_TCScheFBack = t0;
1068
}
1069

    
1070
void do_mttc0_tcschefback (target_ulong t0)
1071
{
1072
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1073

    
1074
    if (other_tc == env->current_tc)
1075
        env->active_tc.CP0_TCScheFBack = t0;
1076
    else
1077
        env->tcs[other_tc].CP0_TCScheFBack = t0;
1078
}
1079

    
1080
void do_mtc0_entrylo1 (target_ulong t0)
1081
{
1082
    /* Large physaddr (PABITS) not implemented */
1083
    /* 1k pages not implemented */
1084
    env->CP0_EntryLo1 = t0 & 0x3FFFFFFF;
1085
}
1086

    
1087
void do_mtc0_context (target_ulong t0)
1088
{
1089
    env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (t0 & ~0x007FFFFF);
1090
}
1091

    
1092
void do_mtc0_pagemask (target_ulong t0)
1093
{
1094
    /* 1k pages not implemented */
1095
    env->CP0_PageMask = t0 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
1096
}
1097

    
1098
void do_mtc0_pagegrain (target_ulong t0)
1099
{
1100
    /* SmartMIPS not implemented */
1101
    /* Large physaddr (PABITS) not implemented */
1102
    /* 1k pages not implemented */
1103
    env->CP0_PageGrain = 0;
1104
}
1105

    
1106
void do_mtc0_wired (target_ulong t0)
1107
{
1108
    env->CP0_Wired = t0 % env->tlb->nb_tlb;
1109
}
1110

    
1111
void do_mtc0_srsconf0 (target_ulong t0)
1112
{
1113
    env->CP0_SRSConf0 |= t0 & env->CP0_SRSConf0_rw_bitmask;
1114
}
1115

    
1116
void do_mtc0_srsconf1 (target_ulong t0)
1117
{
1118
    env->CP0_SRSConf1 |= t0 & env->CP0_SRSConf1_rw_bitmask;
1119
}
1120

    
1121
void do_mtc0_srsconf2 (target_ulong t0)
1122
{
1123
    env->CP0_SRSConf2 |= t0 & env->CP0_SRSConf2_rw_bitmask;
1124
}
1125

    
1126
void do_mtc0_srsconf3 (target_ulong t0)
1127
{
1128
    env->CP0_SRSConf3 |= t0 & env->CP0_SRSConf3_rw_bitmask;
1129
}
1130

    
1131
void do_mtc0_srsconf4 (target_ulong t0)
1132
{
1133
    env->CP0_SRSConf4 |= t0 & env->CP0_SRSConf4_rw_bitmask;
1134
}
1135

    
1136
void do_mtc0_hwrena (target_ulong t0)
1137
{
1138
    env->CP0_HWREna = t0 & 0x0000000F;
1139
}
1140

    
1141
void do_mtc0_count (target_ulong t0)
1142
{
1143
    cpu_mips_store_count(env, t0);
1144
}
1145

    
1146
void do_mtc0_entryhi (target_ulong t0)
1147
{
1148
    target_ulong old, val;
1149

    
1150
    /* 1k pages not implemented */
1151
    val = t0 & ((TARGET_PAGE_MASK << 1) | 0xFF);
1152
#if defined(TARGET_MIPS64)
1153
    val &= env->SEGMask;
1154
#endif
1155
    old = env->CP0_EntryHi;
1156
    env->CP0_EntryHi = val;
1157
    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
1158
        uint32_t tcst = env->active_tc.CP0_TCStatus & ~0xff;
1159
        env->active_tc.CP0_TCStatus = tcst | (val & 0xff);
1160
    }
1161
    /* If the ASID changes, flush qemu's TLB.  */
1162
    if ((old & 0xFF) != (val & 0xFF))
1163
        cpu_mips_tlb_flush(env, 1);
1164
}
1165

    
1166
void do_mttc0_entryhi(target_ulong t0)
1167
{
1168
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1169
    int32_t tcstatus;
1170

    
1171
    env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (t0 & ~0xff);
1172
    if (other_tc == env->current_tc) {
1173
        tcstatus = (env->active_tc.CP0_TCStatus & ~0xff) | (t0 & 0xff);
1174
        env->active_tc.CP0_TCStatus = tcstatus;
1175
    } else {
1176
        tcstatus = (env->tcs[other_tc].CP0_TCStatus & ~0xff) | (t0 & 0xff);
1177
        env->tcs[other_tc].CP0_TCStatus = tcstatus;
1178
    }
1179
}
1180

    
1181
void do_mtc0_compare (target_ulong t0)
1182
{
1183
    cpu_mips_store_compare(env, t0);
1184
}
1185

    
1186
void do_mtc0_status (target_ulong t0)
1187
{
1188
    uint32_t val, old;
1189
    uint32_t mask = env->CP0_Status_rw_bitmask;
1190

    
1191
    val = t0 & mask;
1192
    old = env->CP0_Status;
1193
    env->CP0_Status = (env->CP0_Status & ~mask) | val;
1194
    compute_hflags(env);
1195
    if (loglevel & CPU_LOG_EXEC)
1196
        do_mtc0_status_debug(old, val);
1197
    cpu_mips_update_irq(env);
1198
}
1199

    
1200
void do_mttc0_status(target_ulong t0)
1201
{
1202
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1203
    int32_t tcstatus = env->tcs[other_tc].CP0_TCStatus;
1204

    
1205
    env->CP0_Status = t0 & ~0xf1000018;
1206
    tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (t0 & (0xf << CP0St_CU0));
1207
    tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((t0 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX));
1208
    tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((t0 & (0x3 << CP0St_KSU)) << (CP0TCSt_TKSU - CP0St_KSU));
1209
    if (other_tc == env->current_tc)
1210
        env->active_tc.CP0_TCStatus = tcstatus;
1211
    else
1212
        env->tcs[other_tc].CP0_TCStatus = tcstatus;
1213
}
1214

    
1215
void do_mtc0_intctl (target_ulong t0)
1216
{
1217
    /* vectored interrupts not implemented, no performance counters. */
1218
    env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (t0 & 0x000002e0);
1219
}
1220

    
1221
void do_mtc0_srsctl (target_ulong t0)
1222
{
1223
    uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
1224
    env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (t0 & mask);
1225
}
1226

    
1227
void do_mtc0_cause (target_ulong t0)
1228
{
1229
    uint32_t mask = 0x00C00300;
1230
    uint32_t old = env->CP0_Cause;
1231

    
1232
    if (env->insn_flags & ISA_MIPS32R2)
1233
        mask |= 1 << CP0Ca_DC;
1234

    
1235
    env->CP0_Cause = (env->CP0_Cause & ~mask) | (t0 & mask);
1236

    
1237
    if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) {
1238
        if (env->CP0_Cause & (1 << CP0Ca_DC))
1239
            cpu_mips_stop_count(env);
1240
        else
1241
            cpu_mips_start_count(env);
1242
    }
1243

    
1244
    /* Handle the software interrupt as an hardware one, as they
1245
       are very similar */
1246
    if (t0 & CP0Ca_IP_mask) {
1247
        cpu_mips_update_irq(env);
1248
    }
1249
}
1250

    
1251
void do_mtc0_ebase (target_ulong t0)
1252
{
1253
    /* vectored interrupts not implemented */
1254
    /* Multi-CPU not implemented */
1255
    env->CP0_EBase = 0x80000000 | (t0 & 0x3FFFF000);
1256
}
1257

    
1258
void do_mtc0_config0 (target_ulong t0)
1259
{
1260
    env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (t0 & 0x00000007);
1261
}
1262

    
1263
void do_mtc0_config2 (target_ulong t0)
1264
{
1265
    /* tertiary/secondary caches not implemented */
1266
    env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF);
1267
}
1268

    
1269
void do_mtc0_watchlo (target_ulong t0, uint32_t sel)
1270
{
1271
    /* Watch exceptions for instructions, data loads, data stores
1272
       not implemented. */
1273
    env->CP0_WatchLo[sel] = (t0 & ~0x7);
1274
}
1275

    
1276
void do_mtc0_watchhi (target_ulong t0, uint32_t sel)
1277
{
1278
    env->CP0_WatchHi[sel] = (t0 & 0x40FF0FF8);
1279
    env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & t0 & 0x7);
1280
}
1281

    
1282
void do_mtc0_xcontext (target_ulong t0)
1283
{
1284
    target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
1285
    env->CP0_XContext = (env->CP0_XContext & mask) | (t0 & ~mask);
1286
}
1287

    
1288
void do_mtc0_framemask (target_ulong t0)
1289
{
1290
    env->CP0_Framemask = t0; /* XXX */
1291
}
1292

    
1293
void do_mtc0_debug (target_ulong t0)
1294
{
1295
    env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (t0 & 0x13300120);
1296
    if (t0 & (1 << CP0DB_DM))
1297
        env->hflags |= MIPS_HFLAG_DM;
1298
    else
1299
        env->hflags &= ~MIPS_HFLAG_DM;
1300
}
1301

    
1302
void do_mttc0_debug(target_ulong t0)
1303
{
1304
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1305
    uint32_t val = t0 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
1306

    
1307
    /* XXX: Might be wrong, check with EJTAG spec. */
1308
    if (other_tc == env->current_tc)
1309
        env->active_tc.CP0_Debug_tcstatus = val;
1310
    else
1311
        env->tcs[other_tc].CP0_Debug_tcstatus = val;
1312
    env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
1313
                     (t0 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
1314
}
1315

    
1316
void do_mtc0_performance0 (target_ulong t0)
1317
{
1318
    env->CP0_Performance0 = t0 & 0x000007ff;
1319
}
1320

    
1321
void do_mtc0_taglo (target_ulong t0)
1322
{
1323
    env->CP0_TagLo = t0 & 0xFFFFFCF6;
1324
}
1325

    
1326
void do_mtc0_datalo (target_ulong t0)
1327
{
1328
    env->CP0_DataLo = t0; /* XXX */
1329
}
1330

    
1331
void do_mtc0_taghi (target_ulong t0)
1332
{
1333
    env->CP0_TagHi = t0; /* XXX */
1334
}
1335

    
1336
void do_mtc0_datahi (target_ulong t0)
1337
{
1338
    env->CP0_DataHi = t0; /* XXX */
1339
}
1340

    
1341
void do_mtc0_status_debug(uint32_t old, uint32_t val)
1342
{
1343
    fprintf(logfile, "Status %08x (%08x) => %08x (%08x) Cause %08x",
1344
            old, old & env->CP0_Cause & CP0Ca_IP_mask,
1345
            val, val & env->CP0_Cause & CP0Ca_IP_mask,
1346
            env->CP0_Cause);
1347
    switch (env->hflags & MIPS_HFLAG_KSU) {
1348
    case MIPS_HFLAG_UM: fputs(", UM\n", logfile); break;
1349
    case MIPS_HFLAG_SM: fputs(", SM\n", logfile); break;
1350
    case MIPS_HFLAG_KM: fputs("\n", logfile); break;
1351
    default: cpu_abort(env, "Invalid MMU mode!\n"); break;
1352
    }
1353
}
1354

    
1355
void do_mtc0_status_irqraise_debug(void)
1356
{
1357
    fprintf(logfile, "Raise pending IRQs\n");
1358
}
1359
#endif /* !CONFIG_USER_ONLY */
1360

    
1361
/* MIPS MT functions */
1362
target_ulong do_mftgpr(uint32_t sel)
1363
{
1364
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1365

    
1366
    if (other_tc == env->current_tc)
1367
        return env->active_tc.gpr[sel];
1368
    else
1369
        return env->tcs[other_tc].gpr[sel];
1370
}
1371

    
1372
target_ulong do_mftlo(uint32_t sel)
1373
{
1374
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1375

    
1376
    if (other_tc == env->current_tc)
1377
        return env->active_tc.LO[sel];
1378
    else
1379
        return env->tcs[other_tc].LO[sel];
1380
}
1381

    
1382
target_ulong do_mfthi(uint32_t sel)
1383
{
1384
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1385

    
1386
    if (other_tc == env->current_tc)
1387
        return env->active_tc.HI[sel];
1388
    else
1389
        return env->tcs[other_tc].HI[sel];
1390
}
1391

    
1392
target_ulong do_mftacx(uint32_t sel)
1393
{
1394
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1395

    
1396
    if (other_tc == env->current_tc)
1397
        return env->active_tc.ACX[sel];
1398
    else
1399
        return env->tcs[other_tc].ACX[sel];
1400
}
1401

    
1402
target_ulong do_mftdsp(void)
1403
{
1404
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1405

    
1406
    if (other_tc == env->current_tc)
1407
        return env->active_tc.DSPControl;
1408
    else
1409
        return env->tcs[other_tc].DSPControl;
1410
}
1411

    
1412
void do_mttgpr(target_ulong t0, uint32_t sel)
1413
{
1414
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1415

    
1416
    if (other_tc == env->current_tc)
1417
        env->active_tc.gpr[sel] = t0;
1418
    else
1419
        env->tcs[other_tc].gpr[sel] = t0;
1420
}
1421

    
1422
void do_mttlo(target_ulong t0, uint32_t sel)
1423
{
1424
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1425

    
1426
    if (other_tc == env->current_tc)
1427
        env->active_tc.LO[sel] = t0;
1428
    else
1429
        env->tcs[other_tc].LO[sel] = t0;
1430
}
1431

    
1432
void do_mtthi(target_ulong t0, uint32_t sel)
1433
{
1434
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1435

    
1436
    if (other_tc == env->current_tc)
1437
        env->active_tc.HI[sel] = t0;
1438
    else
1439
        env->tcs[other_tc].HI[sel] = t0;
1440
}
1441

    
1442
void do_mttacx(target_ulong t0, uint32_t sel)
1443
{
1444
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1445

    
1446
    if (other_tc == env->current_tc)
1447
        env->active_tc.ACX[sel] = t0;
1448
    else
1449
        env->tcs[other_tc].ACX[sel] = t0;
1450
}
1451

    
1452
void do_mttdsp(target_ulong t0)
1453
{
1454
    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
1455

    
1456
    if (other_tc == env->current_tc)
1457
        env->active_tc.DSPControl = t0;
1458
    else
1459
        env->tcs[other_tc].DSPControl = t0;
1460
}
1461

    
1462
/* MIPS MT functions */
1463
target_ulong do_dmt(target_ulong t0)
1464
{
1465
    // TODO
1466
    t0 = 0;
1467
    // rt = t0
1468

    
1469
    return t0;
1470
}
1471

    
1472
target_ulong do_emt(target_ulong t0)
1473
{
1474
    // TODO
1475
    t0 = 0;
1476
    // rt = t0
1477

    
1478
    return t0;
1479
}
1480

    
1481
target_ulong do_dvpe(target_ulong t0)
1482
{
1483
    // TODO
1484
    t0 = 0;
1485
    // rt = t0
1486

    
1487
    return t0;
1488
}
1489

    
1490
target_ulong do_evpe(target_ulong t0)
1491
{
1492
    // TODO
1493
    t0 = 0;
1494
    // rt = t0
1495

    
1496
    return t0;
1497
}
1498

    
1499
void do_fork(target_ulong t0, target_ulong t1)
1500
{
1501
    // t0 = rt, t1 = rs
1502
    t0 = 0;
1503
    // TODO: store to TC register
1504
}
1505

    
1506
target_ulong do_yield(target_ulong t0)
1507
{
1508
    if (t0 < 0) {
1509
        /* No scheduling policy implemented. */
1510
        if (t0 != -2) {
1511
            if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
1512
                env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) {
1513
                env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1514
                env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
1515
                do_raise_exception(EXCP_THREAD);
1516
            }
1517
        }
1518
    } else if (t0 == 0) {
1519
        if (0 /* TODO: TC underflow */) {
1520
            env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1521
            do_raise_exception(EXCP_THREAD);
1522
        } else {
1523
            // TODO: Deallocate TC
1524
        }
1525
    } else if (t0 > 0) {
1526
        /* Yield qualifier inputs not implemented. */
1527
        env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
1528
        env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
1529
        do_raise_exception(EXCP_THREAD);
1530
    }
1531
    return env->CP0_YQMask;
1532
}
1533

    
1534
#ifndef CONFIG_USER_ONLY
1535
/* TLB management */
1536
void cpu_mips_tlb_flush (CPUState *env, int flush_global)
1537
{
1538
    /* Flush qemu's TLB and discard all shadowed entries.  */
1539
    tlb_flush (env, flush_global);
1540
    env->tlb->tlb_in_use = env->tlb->nb_tlb;
1541
}
1542

    
1543
static void r4k_mips_tlb_flush_extra (CPUState *env, int first)
1544
{
1545
    /* Discard entries from env->tlb[first] onwards.  */
1546
    while (env->tlb->tlb_in_use > first) {
1547
        r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
1548
    }
1549
}
1550

    
1551
static void r4k_fill_tlb (int idx)
1552
{
1553
    r4k_tlb_t *tlb;
1554

    
1555
    /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
1556
    tlb = &env->tlb->mmu.r4k.tlb[idx];
1557
    tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
1558
#if defined(TARGET_MIPS64)
1559
    tlb->VPN &= env->SEGMask;
1560
#endif
1561
    tlb->ASID = env->CP0_EntryHi & 0xFF;
1562
    tlb->PageMask = env->CP0_PageMask;
1563
    tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
1564
    tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
1565
    tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
1566
    tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
1567
    tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
1568
    tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
1569
    tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
1570
    tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
1571
    tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
1572
}
1573

    
1574
void r4k_do_tlbwi (void)
1575
{
1576
    int idx;
1577

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

    
1580
    /* Discard cached TLB entries.  We could avoid doing this if the
1581
       tlbwi is just upgrading access permissions on the current entry;
1582
       that might be a further win.  */
1583
    r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb);
1584

    
1585
    r4k_invalidate_tlb(env, idx, 0);
1586
    r4k_fill_tlb(idx);
1587
}
1588

    
1589
void r4k_do_tlbwr (void)
1590
{
1591
    int r = cpu_mips_get_random(env);
1592

    
1593
    r4k_invalidate_tlb(env, r, 1);
1594
    r4k_fill_tlb(r);
1595
}
1596

    
1597
void r4k_do_tlbp (void)
1598
{
1599
    r4k_tlb_t *tlb;
1600
    target_ulong mask;
1601
    target_ulong tag;
1602
    target_ulong VPN;
1603
    uint8_t ASID;
1604
    int i;
1605

    
1606
    ASID = env->CP0_EntryHi & 0xFF;
1607
    for (i = 0; i < env->tlb->nb_tlb; i++) {
1608
        tlb = &env->tlb->mmu.r4k.tlb[i];
1609
        /* 1k pages are not supported. */
1610
        mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1611
        tag = env->CP0_EntryHi & ~mask;
1612
        VPN = tlb->VPN & ~mask;
1613
        /* Check ASID, virtual page number & size */
1614
        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
1615
            /* TLB match */
1616
            env->CP0_Index = i;
1617
            break;
1618
        }
1619
    }
1620
    if (i == env->tlb->nb_tlb) {
1621
        /* No match.  Discard any shadow entries, if any of them match.  */
1622
        for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
1623
            tlb = &env->tlb->mmu.r4k.tlb[i];
1624
            /* 1k pages are not supported. */
1625
            mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
1626
            tag = env->CP0_EntryHi & ~mask;
1627
            VPN = tlb->VPN & ~mask;
1628
            /* Check ASID, virtual page number & size */
1629
            if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
1630
                r4k_mips_tlb_flush_extra (env, i);
1631
                break;
1632
            }
1633
        }
1634

    
1635
        env->CP0_Index |= 0x80000000;
1636
    }
1637
}
1638

    
1639
void r4k_do_tlbr (void)
1640
{
1641
    r4k_tlb_t *tlb;
1642
    uint8_t ASID;
1643
    int idx;
1644

    
1645
    ASID = env->CP0_EntryHi & 0xFF;
1646
    idx = (env->CP0_Index & ~0x80000000) % env->tlb->nb_tlb;
1647
    tlb = &env->tlb->mmu.r4k.tlb[idx];
1648

    
1649
    /* If this will change the current ASID, flush qemu's TLB.  */
1650
    if (ASID != tlb->ASID)
1651
        cpu_mips_tlb_flush (env, 1);
1652

    
1653
    r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
1654

    
1655
    env->CP0_EntryHi = tlb->VPN | tlb->ASID;
1656
    env->CP0_PageMask = tlb->PageMask;
1657
    env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
1658
                        (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
1659
    env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
1660
                        (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
1661
}
1662

    
1663
void do_tlbwi(void)
1664
{
1665
    env->tlb->do_tlbwi();
1666
}
1667

    
1668
void do_tlbwr(void)
1669
{
1670
    env->tlb->do_tlbwr();
1671
}
1672

    
1673
void do_tlbp(void)
1674
{
1675
    env->tlb->do_tlbp();
1676
}
1677

    
1678
void do_tlbr(void)
1679
{
1680
    env->tlb->do_tlbr();
1681
}
1682

    
1683
/* Specials */
1684
target_ulong do_di (void)
1685
{
1686
    target_ulong t0 = env->CP0_Status;
1687

    
1688
    env->CP0_Status = t0 & ~(1 << CP0St_IE);
1689
    cpu_mips_update_irq(env);
1690

    
1691
    return t0;
1692
}
1693

    
1694
target_ulong do_ei (void)
1695
{
1696
    target_ulong t0 = env->CP0_Status;
1697

    
1698
    env->CP0_Status = t0 | (1 << CP0St_IE);
1699
    cpu_mips_update_irq(env);
1700

    
1701
    return t0;
1702
}
1703

    
1704
void debug_pre_eret (void)
1705
{
1706
    fprintf(logfile, "ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1707
            env->active_tc.PC, env->CP0_EPC);
1708
    if (env->CP0_Status & (1 << CP0St_ERL))
1709
        fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1710
    if (env->hflags & MIPS_HFLAG_DM)
1711
        fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1712
    fputs("\n", logfile);
1713
}
1714

    
1715
void debug_post_eret (void)
1716
{
1717
    fprintf(logfile, "  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
1718
            env->active_tc.PC, env->CP0_EPC);
1719
    if (env->CP0_Status & (1 << CP0St_ERL))
1720
        fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
1721
    if (env->hflags & MIPS_HFLAG_DM)
1722
        fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
1723
    switch (env->hflags & MIPS_HFLAG_KSU) {
1724
    case MIPS_HFLAG_UM: fputs(", UM\n", logfile); break;
1725
    case MIPS_HFLAG_SM: fputs(", SM\n", logfile); break;
1726
    case MIPS_HFLAG_KM: fputs("\n", logfile); break;
1727
    default: cpu_abort(env, "Invalid MMU mode!\n"); break;
1728
    }
1729
}
1730

    
1731
void do_eret (void)
1732
{
1733
    if (loglevel & CPU_LOG_EXEC)
1734
        debug_pre_eret();
1735
    if (env->CP0_Status & (1 << CP0St_ERL)) {
1736
        env->active_tc.PC = env->CP0_ErrorEPC;
1737
        env->CP0_Status &= ~(1 << CP0St_ERL);
1738
    } else {
1739
        env->active_tc.PC = env->CP0_EPC;
1740
        env->CP0_Status &= ~(1 << CP0St_EXL);
1741
    }
1742
    compute_hflags(env);
1743
    if (loglevel & CPU_LOG_EXEC)
1744
        debug_post_eret();
1745
    env->CP0_LLAddr = 1;
1746
}
1747

    
1748
void do_deret (void)
1749
{
1750
    if (loglevel & CPU_LOG_EXEC)
1751
        debug_pre_eret();
1752
    env->active_tc.PC = env->CP0_DEPC;
1753
    env->hflags &= MIPS_HFLAG_DM;
1754
    compute_hflags(env);
1755
    if (loglevel & CPU_LOG_EXEC)
1756
        debug_post_eret();
1757
    env->CP0_LLAddr = 1;
1758
}
1759
#endif /* !CONFIG_USER_ONLY */
1760

    
1761
target_ulong do_rdhwr_cpunum(void)
1762
{
1763
    if ((env->hflags & MIPS_HFLAG_CP0) ||
1764
        (env->CP0_HWREna & (1 << 0)))
1765
        return env->CP0_EBase & 0x3ff;
1766
    else
1767
        do_raise_exception(EXCP_RI);
1768

    
1769
    return 0;
1770
}
1771

    
1772
target_ulong do_rdhwr_synci_step(void)
1773
{
1774
    if ((env->hflags & MIPS_HFLAG_CP0) ||
1775
        (env->CP0_HWREna & (1 << 1)))
1776
        return env->SYNCI_Step;
1777
    else
1778
        do_raise_exception(EXCP_RI);
1779

    
1780
    return 0;
1781
}
1782

    
1783
target_ulong do_rdhwr_cc(void)
1784
{
1785
    if ((env->hflags & MIPS_HFLAG_CP0) ||
1786
        (env->CP0_HWREna & (1 << 2)))
1787
        return env->CP0_Count;
1788
    else
1789
        do_raise_exception(EXCP_RI);
1790

    
1791
    return 0;
1792
}
1793

    
1794
target_ulong do_rdhwr_ccres(void)
1795
{
1796
    if ((env->hflags & MIPS_HFLAG_CP0) ||
1797
        (env->CP0_HWREna & (1 << 3)))
1798
        return env->CCRes;
1799
    else
1800
        do_raise_exception(EXCP_RI);
1801

    
1802
    return 0;
1803
}
1804

    
1805
void do_pmon (int function)
1806
{
1807
    function /= 2;
1808
    switch (function) {
1809
    case 2: /* TODO: char inbyte(int waitflag); */
1810
        if (env->active_tc.gpr[4] == 0)
1811
            env->active_tc.gpr[2] = -1;
1812
        /* Fall through */
1813
    case 11: /* TODO: char inbyte (void); */
1814
        env->active_tc.gpr[2] = -1;
1815
        break;
1816
    case 3:
1817
    case 12:
1818
        printf("%c", (char)(env->active_tc.gpr[4] & 0xFF));
1819
        break;
1820
    case 17:
1821
        break;
1822
    case 158:
1823
        {
1824
            unsigned char *fmt = (void *)(unsigned long)env->active_tc.gpr[4];
1825
            printf("%s", fmt);
1826
        }
1827
        break;
1828
    }
1829
}
1830

    
1831
void do_wait (void)
1832
{
1833
    env->halted = 1;
1834
    do_raise_exception(EXCP_HLT);
1835
}
1836

    
1837
#if !defined(CONFIG_USER_ONLY)
1838

    
1839
static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
1840

    
1841
#define MMUSUFFIX _mmu
1842
#define ALIGNED_ONLY
1843

    
1844
#define SHIFT 0
1845
#include "softmmu_template.h"
1846

    
1847
#define SHIFT 1
1848
#include "softmmu_template.h"
1849

    
1850
#define SHIFT 2
1851
#include "softmmu_template.h"
1852

    
1853
#define SHIFT 3
1854
#include "softmmu_template.h"
1855

    
1856
static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
1857
{
1858
    env->CP0_BadVAddr = addr;
1859
    do_restore_state (retaddr);
1860
    do_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
1861
}
1862

    
1863
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
1864
{
1865
    TranslationBlock *tb;
1866
    CPUState *saved_env;
1867
    unsigned long pc;
1868
    int ret;
1869

    
1870
    /* XXX: hack to restore env in all cases, even if not called from
1871
       generated code */
1872
    saved_env = env;
1873
    env = cpu_single_env;
1874
    ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
1875
    if (ret) {
1876
        if (retaddr) {
1877
            /* now we have a real cpu fault */
1878
            pc = (unsigned long)retaddr;
1879
            tb = tb_find_pc(pc);
1880
            if (tb) {
1881
                /* the PC is inside the translated code. It means that we have
1882
                   a virtual CPU fault */
1883
                cpu_restore_state(tb, env, pc, NULL);
1884
            }
1885
        }
1886
        do_raise_exception_err(env->exception_index, env->error_code);
1887
    }
1888
    env = saved_env;
1889
}
1890

    
1891
void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
1892
                          int unused, int size)
1893
{
1894
    if (is_exec)
1895
        do_raise_exception(EXCP_IBE);
1896
    else
1897
        do_raise_exception(EXCP_DBE);
1898
}
1899
#endif /* !CONFIG_USER_ONLY */
1900

    
1901
/* Complex FPU operations which may need stack space. */
1902

    
1903
#define FLOAT_ONE32 make_float32(0x3f8 << 20)
1904
#define FLOAT_ONE64 make_float64(0x3ffULL << 52)
1905
#define FLOAT_TWO32 make_float32(1 << 30)
1906
#define FLOAT_TWO64 make_float64(1ULL << 62)
1907
#define FLOAT_QNAN32 0x7fbfffff
1908
#define FLOAT_QNAN64 0x7ff7ffffffffffffULL
1909
#define FLOAT_SNAN32 0x7fffffff
1910
#define FLOAT_SNAN64 0x7fffffffffffffffULL
1911

    
1912
/* convert MIPS rounding mode in FCR31 to IEEE library */
1913
unsigned int ieee_rm[] = {
1914
    float_round_nearest_even,
1915
    float_round_to_zero,
1916
    float_round_up,
1917
    float_round_down
1918
};
1919

    
1920
#define RESTORE_ROUNDING_MODE \
1921
    set_float_rounding_mode(ieee_rm[env->active_fpu.fcr31 & 3], &env->active_fpu.fp_status)
1922

    
1923
target_ulong do_cfc1 (uint32_t reg)
1924
{
1925
    target_ulong t0;
1926

    
1927
    switch (reg) {
1928
    case 0:
1929
        t0 = (int32_t)env->active_fpu.fcr0;
1930
        break;
1931
    case 25:
1932
        t0 = ((env->active_fpu.fcr31 >> 24) & 0xfe) | ((env->active_fpu.fcr31 >> 23) & 0x1);
1933
        break;
1934
    case 26:
1935
        t0 = env->active_fpu.fcr31 & 0x0003f07c;
1936
        break;
1937
    case 28:
1938
        t0 = (env->active_fpu.fcr31 & 0x00000f83) | ((env->active_fpu.fcr31 >> 22) & 0x4);
1939
        break;
1940
    default:
1941
        t0 = (int32_t)env->active_fpu.fcr31;
1942
        break;
1943
    }
1944

    
1945
    return t0;
1946
}
1947

    
1948
void do_ctc1 (target_ulong t0, uint32_t reg)
1949
{
1950
    switch(reg) {
1951
    case 25:
1952
        if (t0 & 0xffffff00)
1953
            return;
1954
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((t0 & 0xfe) << 24) |
1955
                     ((t0 & 0x1) << 23);
1956
        break;
1957
    case 26:
1958
        if (t0 & 0x007c0000)
1959
            return;
1960
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfffc0f83) | (t0 & 0x0003f07c);
1961
        break;
1962
    case 28:
1963
        if (t0 & 0x007c0000)
1964
            return;
1965
        env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0xfefff07c) | (t0 & 0x00000f83) |
1966
                     ((t0 & 0x4) << 22);
1967
        break;
1968
    case 31:
1969
        if (t0 & 0x007c0000)
1970
            return;
1971
        env->active_fpu.fcr31 = t0;
1972
        break;
1973
    default:
1974
        return;
1975
    }
1976
    /* set rounding mode */
1977
    RESTORE_ROUNDING_MODE;
1978
    set_float_exception_flags(0, &env->active_fpu.fp_status);
1979
    if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31))
1980
        do_raise_exception(EXCP_FPE);
1981
}
1982

    
1983
static inline char ieee_ex_to_mips(char xcpt)
1984
{
1985
    return (xcpt & float_flag_inexact) >> 5 |
1986
           (xcpt & float_flag_underflow) >> 3 |
1987
           (xcpt & float_flag_overflow) >> 1 |
1988
           (xcpt & float_flag_divbyzero) << 1 |
1989
           (xcpt & float_flag_invalid) << 4;
1990
}
1991

    
1992
static inline char mips_ex_to_ieee(char xcpt)
1993
{
1994
    return (xcpt & FP_INEXACT) << 5 |
1995
           (xcpt & FP_UNDERFLOW) << 3 |
1996
           (xcpt & FP_OVERFLOW) << 1 |
1997
           (xcpt & FP_DIV0) >> 1 |
1998
           (xcpt & FP_INVALID) >> 4;
1999
}
2000

    
2001
static inline void update_fcr31(void)
2002
{
2003
    int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status));
2004

    
2005
    SET_FP_CAUSE(env->active_fpu.fcr31, tmp);
2006
    if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp)
2007
        do_raise_exception(EXCP_FPE);
2008
    else
2009
        UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp);
2010
}
2011

    
2012
/* Float support.
2013
   Single precition routines have a "s" suffix, double precision a
2014
   "d" suffix, 32bit integer "w", 64bit integer "l", paired single "ps",
2015
   paired single lower "pl", paired single upper "pu".  */
2016

    
2017
/* unary operations, modifying fp status  */
2018
uint64_t do_float_sqrt_d(uint64_t fdt0)
2019
{
2020
    return float64_sqrt(fdt0, &env->active_fpu.fp_status);
2021
}
2022

    
2023
uint32_t do_float_sqrt_s(uint32_t fst0)
2024
{
2025
    return float32_sqrt(fst0, &env->active_fpu.fp_status);
2026
}
2027

    
2028
uint64_t do_float_cvtd_s(uint32_t fst0)
2029
{
2030
    uint64_t fdt2;
2031

    
2032
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2033
    fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status);
2034
    update_fcr31();
2035
    return fdt2;
2036
}
2037

    
2038
uint64_t do_float_cvtd_w(uint32_t wt0)
2039
{
2040
    uint64_t fdt2;
2041

    
2042
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2043
    fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status);
2044
    update_fcr31();
2045
    return fdt2;
2046
}
2047

    
2048
uint64_t do_float_cvtd_l(uint64_t dt0)
2049
{
2050
    uint64_t fdt2;
2051

    
2052
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2053
    fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status);
2054
    update_fcr31();
2055
    return fdt2;
2056
}
2057

    
2058
uint64_t do_float_cvtl_d(uint64_t fdt0)
2059
{
2060
    uint64_t dt2;
2061

    
2062
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2063
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2064
    update_fcr31();
2065
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2066
        dt2 = FLOAT_SNAN64;
2067
    return dt2;
2068
}
2069

    
2070
uint64_t do_float_cvtl_s(uint32_t fst0)
2071
{
2072
    uint64_t dt2;
2073

    
2074
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2075
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2076
    update_fcr31();
2077
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2078
        dt2 = FLOAT_SNAN64;
2079
    return dt2;
2080
}
2081

    
2082
uint64_t do_float_cvtps_pw(uint64_t dt0)
2083
{
2084
    uint32_t fst2;
2085
    uint32_t fsth2;
2086

    
2087
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2088
    fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2089
    fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status);
2090
    update_fcr31();
2091
    return ((uint64_t)fsth2 << 32) | fst2;
2092
}
2093

    
2094
uint64_t do_float_cvtpw_ps(uint64_t fdt0)
2095
{
2096
    uint32_t wt2;
2097
    uint32_t wth2;
2098

    
2099
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2100
    wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2101
    wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status);
2102
    update_fcr31();
2103
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) {
2104
        wt2 = FLOAT_SNAN32;
2105
        wth2 = FLOAT_SNAN32;
2106
    }
2107
    return ((uint64_t)wth2 << 32) | wt2;
2108
}
2109

    
2110
uint32_t do_float_cvts_d(uint64_t fdt0)
2111
{
2112
    uint32_t fst2;
2113

    
2114
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2115
    fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status);
2116
    update_fcr31();
2117
    return fst2;
2118
}
2119

    
2120
uint32_t do_float_cvts_w(uint32_t wt0)
2121
{
2122
    uint32_t fst2;
2123

    
2124
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2125
    fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status);
2126
    update_fcr31();
2127
    return fst2;
2128
}
2129

    
2130
uint32_t do_float_cvts_l(uint64_t dt0)
2131
{
2132
    uint32_t fst2;
2133

    
2134
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2135
    fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status);
2136
    update_fcr31();
2137
    return fst2;
2138
}
2139

    
2140
uint32_t do_float_cvts_pl(uint32_t wt0)
2141
{
2142
    uint32_t wt2;
2143

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

    
2150
uint32_t do_float_cvts_pu(uint32_t wth0)
2151
{
2152
    uint32_t wt2;
2153

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

    
2160
uint32_t do_float_cvtw_s(uint32_t fst0)
2161
{
2162
    uint32_t wt2;
2163

    
2164
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2165
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2166
    update_fcr31();
2167
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2168
        wt2 = FLOAT_SNAN32;
2169
    return wt2;
2170
}
2171

    
2172
uint32_t do_float_cvtw_d(uint64_t fdt0)
2173
{
2174
    uint32_t wt2;
2175

    
2176
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2177
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2178
    update_fcr31();
2179
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2180
        wt2 = FLOAT_SNAN32;
2181
    return wt2;
2182
}
2183

    
2184
uint64_t do_float_roundl_d(uint64_t fdt0)
2185
{
2186
    uint64_t dt2;
2187

    
2188
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2189
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2190
    RESTORE_ROUNDING_MODE;
2191
    update_fcr31();
2192
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2193
        dt2 = FLOAT_SNAN64;
2194
    return dt2;
2195
}
2196

    
2197
uint64_t do_float_roundl_s(uint32_t fst0)
2198
{
2199
    uint64_t dt2;
2200

    
2201
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2202
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2203
    RESTORE_ROUNDING_MODE;
2204
    update_fcr31();
2205
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2206
        dt2 = FLOAT_SNAN64;
2207
    return dt2;
2208
}
2209

    
2210
uint32_t do_float_roundw_d(uint64_t fdt0)
2211
{
2212
    uint32_t wt2;
2213

    
2214
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2215
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2216
    RESTORE_ROUNDING_MODE;
2217
    update_fcr31();
2218
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2219
        wt2 = FLOAT_SNAN32;
2220
    return wt2;
2221
}
2222

    
2223
uint32_t do_float_roundw_s(uint32_t fst0)
2224
{
2225
    uint32_t wt2;
2226

    
2227
    set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
2228
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2229
    RESTORE_ROUNDING_MODE;
2230
    update_fcr31();
2231
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2232
        wt2 = FLOAT_SNAN32;
2233
    return wt2;
2234
}
2235

    
2236
uint64_t do_float_truncl_d(uint64_t fdt0)
2237
{
2238
    uint64_t dt2;
2239

    
2240
    dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
2241
    update_fcr31();
2242
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2243
        dt2 = FLOAT_SNAN64;
2244
    return dt2;
2245
}
2246

    
2247
uint64_t do_float_truncl_s(uint32_t fst0)
2248
{
2249
    uint64_t dt2;
2250

    
2251
    dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
2252
    update_fcr31();
2253
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2254
        dt2 = FLOAT_SNAN64;
2255
    return dt2;
2256
}
2257

    
2258
uint32_t do_float_truncw_d(uint64_t fdt0)
2259
{
2260
    uint32_t wt2;
2261

    
2262
    wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
2263
    update_fcr31();
2264
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2265
        wt2 = FLOAT_SNAN32;
2266
    return wt2;
2267
}
2268

    
2269
uint32_t do_float_truncw_s(uint32_t fst0)
2270
{
2271
    uint32_t wt2;
2272

    
2273
    wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
2274
    update_fcr31();
2275
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2276
        wt2 = FLOAT_SNAN32;
2277
    return wt2;
2278
}
2279

    
2280
uint64_t do_float_ceill_d(uint64_t fdt0)
2281
{
2282
    uint64_t dt2;
2283

    
2284
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2285
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2286
    RESTORE_ROUNDING_MODE;
2287
    update_fcr31();
2288
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2289
        dt2 = FLOAT_SNAN64;
2290
    return dt2;
2291
}
2292

    
2293
uint64_t do_float_ceill_s(uint32_t fst0)
2294
{
2295
    uint64_t dt2;
2296

    
2297
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2298
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2299
    RESTORE_ROUNDING_MODE;
2300
    update_fcr31();
2301
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2302
        dt2 = FLOAT_SNAN64;
2303
    return dt2;
2304
}
2305

    
2306
uint32_t do_float_ceilw_d(uint64_t fdt0)
2307
{
2308
    uint32_t wt2;
2309

    
2310
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2311
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2312
    RESTORE_ROUNDING_MODE;
2313
    update_fcr31();
2314
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2315
        wt2 = FLOAT_SNAN32;
2316
    return wt2;
2317
}
2318

    
2319
uint32_t do_float_ceilw_s(uint32_t fst0)
2320
{
2321
    uint32_t wt2;
2322

    
2323
    set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
2324
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2325
    RESTORE_ROUNDING_MODE;
2326
    update_fcr31();
2327
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2328
        wt2 = FLOAT_SNAN32;
2329
    return wt2;
2330
}
2331

    
2332
uint64_t do_float_floorl_d(uint64_t fdt0)
2333
{
2334
    uint64_t dt2;
2335

    
2336
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2337
    dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
2338
    RESTORE_ROUNDING_MODE;
2339
    update_fcr31();
2340
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2341
        dt2 = FLOAT_SNAN64;
2342
    return dt2;
2343
}
2344

    
2345
uint64_t do_float_floorl_s(uint32_t fst0)
2346
{
2347
    uint64_t dt2;
2348

    
2349
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2350
    dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
2351
    RESTORE_ROUNDING_MODE;
2352
    update_fcr31();
2353
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2354
        dt2 = FLOAT_SNAN64;
2355
    return dt2;
2356
}
2357

    
2358
uint32_t do_float_floorw_d(uint64_t fdt0)
2359
{
2360
    uint32_t wt2;
2361

    
2362
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2363
    wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
2364
    RESTORE_ROUNDING_MODE;
2365
    update_fcr31();
2366
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2367
        wt2 = FLOAT_SNAN32;
2368
    return wt2;
2369
}
2370

    
2371
uint32_t do_float_floorw_s(uint32_t fst0)
2372
{
2373
    uint32_t wt2;
2374

    
2375
    set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
2376
    wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
2377
    RESTORE_ROUNDING_MODE;
2378
    update_fcr31();
2379
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
2380
        wt2 = FLOAT_SNAN32;
2381
    return wt2;
2382
}
2383

    
2384
/* unary operations, not modifying fp status  */
2385
#define FLOAT_UNOP(name)                                       \
2386
uint64_t do_float_ ## name ## _d(uint64_t fdt0)                \
2387
{                                                              \
2388
    return float64_ ## name(fdt0);                             \
2389
}                                                              \
2390
uint32_t do_float_ ## name ## _s(uint32_t fst0)                \
2391
{                                                              \
2392
    return float32_ ## name(fst0);                             \
2393
}                                                              \
2394
uint64_t do_float_ ## name ## _ps(uint64_t fdt0)               \
2395
{                                                              \
2396
    uint32_t wt0;                                              \
2397
    uint32_t wth0;                                             \
2398
                                                               \
2399
    wt0 = float32_ ## name(fdt0 & 0XFFFFFFFF);                 \
2400
    wth0 = float32_ ## name(fdt0 >> 32);                       \
2401
    return ((uint64_t)wth0 << 32) | wt0;                       \
2402
}
2403
FLOAT_UNOP(abs)
2404
FLOAT_UNOP(chs)
2405
#undef FLOAT_UNOP
2406

    
2407
/* MIPS specific unary operations */
2408
uint64_t do_float_recip_d(uint64_t fdt0)
2409
{
2410
    uint64_t fdt2;
2411

    
2412
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2413
    fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
2414
    update_fcr31();
2415
    return fdt2;
2416
}
2417

    
2418
uint32_t do_float_recip_s(uint32_t fst0)
2419
{
2420
    uint32_t fst2;
2421

    
2422
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2423
    fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status);
2424
    update_fcr31();
2425
    return fst2;
2426
}
2427

    
2428
uint64_t do_float_rsqrt_d(uint64_t fdt0)
2429
{
2430
    uint64_t fdt2;
2431

    
2432
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2433
    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2434
    fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
2435
    update_fcr31();
2436
    return fdt2;
2437
}
2438

    
2439
uint32_t do_float_rsqrt_s(uint32_t fst0)
2440
{
2441
    uint32_t fst2;
2442

    
2443
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2444
    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2445
    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
2446
    update_fcr31();
2447
    return fst2;
2448
}
2449

    
2450
uint64_t do_float_recip1_d(uint64_t fdt0)
2451
{
2452
    uint64_t fdt2;
2453

    
2454
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2455
    fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status);
2456
    update_fcr31();
2457
    return fdt2;
2458
}
2459

    
2460
uint32_t do_float_recip1_s(uint32_t fst0)
2461
{
2462
    uint32_t fst2;
2463

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

    
2470
uint64_t do_float_recip1_ps(uint64_t fdt0)
2471
{
2472
    uint32_t fst2;
2473
    uint32_t fsth2;
2474

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

    
2482
uint64_t do_float_rsqrt1_d(uint64_t fdt0)
2483
{
2484
    uint64_t fdt2;
2485

    
2486
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2487
    fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status);
2488
    fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status);
2489
    update_fcr31();
2490
    return fdt2;
2491
}
2492

    
2493
uint32_t do_float_rsqrt1_s(uint32_t fst0)
2494
{
2495
    uint32_t fst2;
2496

    
2497
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2498
    fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status);
2499
    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
2500
    update_fcr31();
2501
    return fst2;
2502
}
2503

    
2504
uint64_t do_float_rsqrt1_ps(uint64_t fdt0)
2505
{
2506
    uint32_t fst2;
2507
    uint32_t fsth2;
2508

    
2509
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2510
    fst2 = float32_sqrt(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status);
2511
    fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status);
2512
    fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status);
2513
    fsth2 = float32_div(FLOAT_ONE32, fsth2, &env->active_fpu.fp_status);
2514
    update_fcr31();
2515
    return ((uint64_t)fsth2 << 32) | fst2;
2516
}
2517

    
2518
#define FLOAT_OP(name, p) void do_float_##name##_##p(void)
2519

    
2520
/* binary operations */
2521
#define FLOAT_BINOP(name)                                          \
2522
uint64_t do_float_ ## name ## _d(uint64_t fdt0, uint64_t fdt1)     \
2523
{                                                                  \
2524
    uint64_t dt2;                                                  \
2525
                                                                   \
2526
    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
2527
    dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status);     \
2528
    update_fcr31();                                                \
2529
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID)                \
2530
        dt2 = FLOAT_QNAN64;                                        \
2531
    return dt2;                                                    \
2532
}                                                                  \
2533
                                                                   \
2534
uint32_t do_float_ ## name ## _s(uint32_t fst0, uint32_t fst1)     \
2535
{                                                                  \
2536
    uint32_t wt2;                                                  \
2537
                                                                   \
2538
    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
2539
    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
2540
    update_fcr31();                                                \
2541
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID)                \
2542
        wt2 = FLOAT_QNAN32;                                        \
2543
    return wt2;                                                    \
2544
}                                                                  \
2545
                                                                   \
2546
uint64_t do_float_ ## name ## _ps(uint64_t fdt0, uint64_t fdt1)    \
2547
{                                                                  \
2548
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;                             \
2549
    uint32_t fsth0 = fdt0 >> 32;                                   \
2550
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;                             \
2551
    uint32_t fsth1 = fdt1 >> 32;                                   \
2552
    uint32_t wt2;                                                  \
2553
    uint32_t wth2;                                                 \
2554
                                                                   \
2555
    set_float_exception_flags(0, &env->active_fpu.fp_status);            \
2556
    wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status);     \
2557
    wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status);  \
2558
    update_fcr31();                                                \
2559
    if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) {              \
2560
        wt2 = FLOAT_QNAN32;                                        \
2561
        wth2 = FLOAT_QNAN32;                                       \
2562
    }                                                              \
2563
    return ((uint64_t)wth2 << 32) | wt2;                           \
2564
}
2565

    
2566
FLOAT_BINOP(add)
2567
FLOAT_BINOP(sub)
2568
FLOAT_BINOP(mul)
2569
FLOAT_BINOP(div)
2570
#undef FLOAT_BINOP
2571

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

    
2605
FLOAT_TERNOP(mul, add)
2606
FLOAT_TERNOP(mul, sub)
2607
#undef FLOAT_TERNOP
2608

    
2609
/* negated ternary operations */
2610
#define FLOAT_NTERNOP(name1, name2)                                       \
2611
uint64_t do_float_n ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \
2612
                                           uint64_t fdt2)                 \
2613
{                                                                         \
2614
    fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status);          \
2615
    fdt2 = float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status);          \
2616
    return float64_chs(fdt2);                                             \
2617
}                                                                         \
2618
                                                                          \
2619
uint32_t do_float_n ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \
2620
                                           uint32_t fst2)                 \
2621
{                                                                         \
2622
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
2623
    fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
2624
    return float32_chs(fst2);                                             \
2625
}                                                                         \
2626
                                                                          \
2627
uint64_t do_float_n ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1,\
2628
                                           uint64_t fdt2)                 \
2629
{                                                                         \
2630
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;                                    \
2631
    uint32_t fsth0 = fdt0 >> 32;                                          \
2632
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;                                    \
2633
    uint32_t fsth1 = fdt1 >> 32;                                          \
2634
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;                                    \
2635
    uint32_t fsth2 = fdt2 >> 32;                                          \
2636
                                                                          \
2637
    fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status);          \
2638
    fsth0 = float32_ ## name1 (fsth0, fsth1, &env->active_fpu.fp_status);       \
2639
    fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status);          \
2640
    fsth2 = float32_ ## name2 (fsth0, fsth2, &env->active_fpu.fp_status);       \
2641
    fst2 = float32_chs(fst2);                                             \
2642
    fsth2 = float32_chs(fsth2);                                           \
2643
    return ((uint64_t)fsth2 << 32) | fst2;                                \
2644
}
2645

    
2646
FLOAT_NTERNOP(mul, add)
2647
FLOAT_NTERNOP(mul, sub)
2648
#undef FLOAT_NTERNOP
2649

    
2650
/* MIPS specific binary operations */
2651
uint64_t do_float_recip2_d(uint64_t fdt0, uint64_t fdt2)
2652
{
2653
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2654
    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
2655
    fdt2 = float64_chs(float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status));
2656
    update_fcr31();
2657
    return fdt2;
2658
}
2659

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

    
2669
uint64_t do_float_recip2_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_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status));
2680
    fsth2 = float32_chs(float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status));
2681
    update_fcr31();
2682
    return ((uint64_t)fsth2 << 32) | fst2;
2683
}
2684

    
2685
uint64_t do_float_rsqrt2_d(uint64_t fdt0, uint64_t fdt2)
2686
{
2687
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2688
    fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status);
2689
    fdt2 = float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status);
2690
    fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status));
2691
    update_fcr31();
2692
    return fdt2;
2693
}
2694

    
2695
uint32_t do_float_rsqrt2_s(uint32_t fst0, uint32_t fst2)
2696
{
2697
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2698
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2699
    fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
2700
    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
2701
    update_fcr31();
2702
    return fst2;
2703
}
2704

    
2705
uint64_t do_float_rsqrt2_ps(uint64_t fdt0, uint64_t fdt2)
2706
{
2707
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2708
    uint32_t fsth0 = fdt0 >> 32;
2709
    uint32_t fst2 = fdt2 & 0XFFFFFFFF;
2710
    uint32_t fsth2 = fdt2 >> 32;
2711

    
2712
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2713
    fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status);
2714
    fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status);
2715
    fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status);
2716
    fsth2 = float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status);
2717
    fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status));
2718
    fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status));
2719
    update_fcr31();
2720
    return ((uint64_t)fsth2 << 32) | fst2;
2721
}
2722

    
2723
uint64_t do_float_addr_ps(uint64_t fdt0, uint64_t fdt1)
2724
{
2725
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2726
    uint32_t fsth0 = fdt0 >> 32;
2727
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;
2728
    uint32_t fsth1 = fdt1 >> 32;
2729
    uint32_t fst2;
2730
    uint32_t fsth2;
2731

    
2732
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2733
    fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status);
2734
    fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status);
2735
    update_fcr31();
2736
    return ((uint64_t)fsth2 << 32) | fst2;
2737
}
2738

    
2739
uint64_t do_float_mulr_ps(uint64_t fdt0, uint64_t fdt1)
2740
{
2741
    uint32_t fst0 = fdt0 & 0XFFFFFFFF;
2742
    uint32_t fsth0 = fdt0 >> 32;
2743
    uint32_t fst1 = fdt1 & 0XFFFFFFFF;
2744
    uint32_t fsth1 = fdt1 >> 32;
2745
    uint32_t fst2;
2746
    uint32_t fsth2;
2747

    
2748
    set_float_exception_flags(0, &env->active_fpu.fp_status);
2749
    fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status);
2750
    fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status);
2751
    update_fcr31();
2752
    return ((uint64_t)fsth2 << 32) | fst2;
2753
}
2754

    
2755
/* compare operations */
2756
#define FOP_COND_D(op, cond)                                   \
2757
void do_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
2758
{                                                              \
2759
    int c = cond;                                              \
2760
    update_fcr31();                                            \
2761
    if (c)                                                     \
2762
        SET_FP_COND(cc, env->active_fpu);                      \
2763
    else                                                       \
2764
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2765
}                                                              \
2766
void do_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
2767
{                                                              \
2768
    int c;                                                     \
2769
    fdt0 = float64_abs(fdt0);                                  \
2770
    fdt1 = float64_abs(fdt1);                                  \
2771
    c = cond;                                                  \
2772
    update_fcr31();                                            \
2773
    if (c)                                                     \
2774
        SET_FP_COND(cc, env->active_fpu);                      \
2775
    else                                                       \
2776
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2777
}
2778

    
2779
int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
2780
{
2781
    if (float64_is_signaling_nan(a) ||
2782
        float64_is_signaling_nan(b) ||
2783
        (sig && (float64_is_nan(a) || float64_is_nan(b)))) {
2784
        float_raise(float_flag_invalid, status);
2785
        return 1;
2786
    } else if (float64_is_nan(a) || float64_is_nan(b)) {
2787
        return 1;
2788
    } else {
2789
        return 0;
2790
    }
2791
}
2792

    
2793
/* NOTE: the comma operator will make "cond" to eval to false,
2794
 * but float*_is_unordered() is still called. */
2795
FOP_COND_D(f,   (float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status), 0))
2796
FOP_COND_D(un,  float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status))
2797
FOP_COND_D(eq,  !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
2798
FOP_COND_D(ueq, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
2799
FOP_COND_D(olt, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
2800
FOP_COND_D(ult, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
2801
FOP_COND_D(ole, !float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
2802
FOP_COND_D(ule, float64_is_unordered(0, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
2803
/* NOTE: the comma operator will make "cond" to eval to false,
2804
 * but float*_is_unordered() is still called. */
2805
FOP_COND_D(sf,  (float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status), 0))
2806
FOP_COND_D(ngle,float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status))
2807
FOP_COND_D(seq, !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
2808
FOP_COND_D(ngl, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_eq(fdt0, fdt1, &env->active_fpu.fp_status))
2809
FOP_COND_D(lt,  !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
2810
FOP_COND_D(nge, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_lt(fdt0, fdt1, &env->active_fpu.fp_status))
2811
FOP_COND_D(le,  !float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status) && float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
2812
FOP_COND_D(ngt, float64_is_unordered(1, fdt1, fdt0, &env->active_fpu.fp_status)  || float64_le(fdt0, fdt1, &env->active_fpu.fp_status))
2813

    
2814
#define FOP_COND_S(op, cond)                                   \
2815
void do_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc)    \
2816
{                                                              \
2817
    int c = cond;                                              \
2818
    update_fcr31();                                            \
2819
    if (c)                                                     \
2820
        SET_FP_COND(cc, env->active_fpu);                      \
2821
    else                                                       \
2822
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2823
}                                                              \
2824
void do_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \
2825
{                                                              \
2826
    int c;                                                     \
2827
    fst0 = float32_abs(fst0);                                  \
2828
    fst1 = float32_abs(fst1);                                  \
2829
    c = cond;                                                  \
2830
    update_fcr31();                                            \
2831
    if (c)                                                     \
2832
        SET_FP_COND(cc, env->active_fpu);                      \
2833
    else                                                       \
2834
        CLEAR_FP_COND(cc, env->active_fpu);                    \
2835
}
2836

    
2837
flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
2838
{
2839
    if (float32_is_signaling_nan(a) ||
2840
        float32_is_signaling_nan(b) ||
2841
        (sig && (float32_is_nan(a) || float32_is_nan(b)))) {
2842
        float_raise(float_flag_invalid, status);
2843
        return 1;
2844
    } else if (float32_is_nan(a) || float32_is_nan(b)) {
2845
        return 1;
2846
    } else {
2847
        return 0;
2848
    }
2849
}
2850

    
2851
/* NOTE: the comma operator will make "cond" to eval to false,
2852
 * but float*_is_unordered() is still called. */
2853
FOP_COND_S(f,   (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0))
2854
FOP_COND_S(un,  float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status))
2855
FOP_COND_S(eq,  !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status))
2856
FOP_COND_S(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
2857
FOP_COND_S(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status))
2858
FOP_COND_S(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
2859
FOP_COND_S(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status))
2860
FOP_COND_S(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
2861
/* NOTE: the comma operator will make "cond" to eval to false,
2862
 * but float*_is_unordered() is still called. */
2863
FOP_COND_S(sf,  (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0))
2864
FOP_COND_S(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status))
2865
FOP_COND_S(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_eq(fst0, fst1, &env->active_fpu.fp_status))
2866
FOP_COND_S(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)  || float32_eq(fst0, fst1, &env->active_fpu.fp_status))
2867
FOP_COND_S(lt,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_lt(fst0, fst1, &env->active_fpu.fp_status))
2868
FOP_COND_S(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)  || float32_lt(fst0, fst1, &env->active_fpu.fp_status))
2869
FOP_COND_S(le,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status) && float32_le(fst0, fst1, &env->active_fpu.fp_status))
2870
FOP_COND_S(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)  || float32_le(fst0, fst1, &env->active_fpu.fp_status))
2871

    
2872
#define FOP_COND_PS(op, condl, condh)                           \
2873
void do_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc)    \
2874
{                                                               \
2875
    uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF);             \
2876
    uint32_t fsth0 = float32_abs(fdt0 >> 32);                   \
2877
    uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF);             \
2878
    uint32_t fsth1 = float32_abs(fdt1 >> 32);                   \
2879
    int cl = condl;                                             \
2880
    int ch = condh;                                             \
2881
                                                                \
2882
    update_fcr31();                                             \
2883
    if (cl)                                                     \
2884
        SET_FP_COND(cc, env->active_fpu);                       \
2885
    else                                                        \
2886
        CLEAR_FP_COND(cc, env->active_fpu);                     \
2887
    if (ch)                                                     \
2888
        SET_FP_COND(cc + 1, env->active_fpu);                   \
2889
    else                                                        \
2890
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
2891
}                                                               \
2892
void do_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \
2893
{                                                               \
2894
    uint32_t fst0 = float32_abs(fdt0 & 0XFFFFFFFF);             \
2895
    uint32_t fsth0 = float32_abs(fdt0 >> 32);                   \
2896
    uint32_t fst1 = float32_abs(fdt1 & 0XFFFFFFFF);             \
2897
    uint32_t fsth1 = float32_abs(fdt1 >> 32);                   \
2898
    int cl = condl;                                             \
2899
    int ch = condh;                                             \
2900
                                                                \
2901
    update_fcr31();                                             \
2902
    if (cl)                                                     \
2903
        SET_FP_COND(cc, env->active_fpu);                       \
2904
    else                                                        \
2905
        CLEAR_FP_COND(cc, env->active_fpu);                     \
2906
    if (ch)                                                     \
2907
        SET_FP_COND(cc + 1, env->active_fpu);                   \
2908
    else                                                        \
2909
        CLEAR_FP_COND(cc + 1, env->active_fpu);                 \
2910
}
2911

    
2912
/* NOTE: the comma operator will make "cond" to eval to false,
2913
 * but float*_is_unordered() is still called. */
2914
FOP_COND_PS(f,   (float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status), 0),
2915
                 (float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status), 0))
2916
FOP_COND_PS(un,  float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status),
2917
                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status))
2918
FOP_COND_PS(eq,  !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)   && float32_eq(fst0, fst1, &env->active_fpu.fp_status),
2919
                 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
2920
FOP_COND_PS(ueq, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
2921
                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
2922
FOP_COND_PS(olt, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)   && float32_lt(fst0, fst1, &env->active_fpu.fp_status),
2923
                 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
2924
FOP_COND_PS(ult, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
2925
                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
2926
FOP_COND_PS(ole, !float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)   && float32_le(fst0, fst1, &env->active_fpu.fp_status),
2927
                 !float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
2928
FOP_COND_PS(ule, float32_is_unordered(0, fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
2929
                 float32_is_unordered(0, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
2930
/* NOTE: the comma operator will make "cond" to eval to false,
2931
 * but float*_is_unordered() is still called. */
2932
FOP_COND_PS(sf,  (float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status), 0),
2933
                 (float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status), 0))
2934
FOP_COND_PS(ngle,float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status),
2935
                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status))
2936
FOP_COND_PS(seq, !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)   && float32_eq(fst0, fst1, &env->active_fpu.fp_status),
2937
                 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
2938
FOP_COND_PS(ngl, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)    || float32_eq(fst0, fst1, &env->active_fpu.fp_status),
2939
                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_eq(fsth0, fsth1, &env->active_fpu.fp_status))
2940
FOP_COND_PS(lt,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)   && float32_lt(fst0, fst1, &env->active_fpu.fp_status),
2941
                 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
2942
FOP_COND_PS(nge, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)    || float32_lt(fst0, fst1, &env->active_fpu.fp_status),
2943
                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_lt(fsth0, fsth1, &env->active_fpu.fp_status))
2944
FOP_COND_PS(le,  !float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)   && float32_le(fst0, fst1, &env->active_fpu.fp_status),
2945
                 !float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status) && float32_le(fsth0, fsth1, &env->active_fpu.fp_status))
2946
FOP_COND_PS(ngt, float32_is_unordered(1, fst1, fst0, &env->active_fpu.fp_status)    || float32_le(fst0, fst1, &env->active_fpu.fp_status),
2947
                 float32_is_unordered(1, fsth1, fsth0, &env->active_fpu.fp_status)  || float32_le(fsth0, fsth1, &env->active_fpu.fp_status))