Statistics
| Branch: | Revision:

root / target-sparc / op_helper.c @ 3475187d

History | View | Annotate | Download (14.8 kB)

1
#include "exec.h"
2

    
3
//#define DEBUG_MMU
4

    
5
void raise_exception(int tt)
6
{
7
    env->exception_index = tt;
8
    cpu_loop_exit();
9
}   
10

    
11
#ifdef USE_INT_TO_FLOAT_HELPERS
12
void do_fitos(void)
13
{
14
    FT0 = (float) *((int32_t *)&FT1);
15
}
16

    
17
void do_fitod(void)
18
{
19
    DT0 = (double) *((int32_t *)&FT1);
20
}
21
#endif
22

    
23
void do_fabss(void)
24
{
25
    FT0 = float32_abs(FT1);
26
}
27

    
28
#ifdef TARGET_SPARC64
29
void do_fabsd(void)
30
{
31
    DT0 = float64_abs(DT1);
32
}
33
#endif
34

    
35
void do_fsqrts(void)
36
{
37
    FT0 = float32_sqrt(FT1, &env->fp_status);
38
}
39

    
40
void do_fsqrtd(void)
41
{
42
    DT0 = float64_sqrt(DT1, &env->fp_status);
43
}
44

    
45
#define FS 0
46
void do_fcmps (void)
47
{
48
    env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);
49
    if (isnan(FT0) || isnan(FT1)) {
50
        T0 = (FSR_FCC1 | FSR_FCC0) << FS;
51
        if (env->fsr & FSR_NVM) {
52
            env->fsr |= T0;
53
            raise_exception(TT_FP_EXCP);
54
        } else {
55
            env->fsr |= FSR_NVA;
56
        }
57
    } else if (FT0 < FT1) {
58
        T0 = FSR_FCC0 << FS;
59
    } else if (FT0 > FT1) {
60
        T0 = FSR_FCC1 << FS;
61
    } else {
62
        T0 = 0;
63
    }
64
    env->fsr |= T0;
65
}
66

    
67
void do_fcmpd (void)
68
{
69
    env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);
70
    if (isnan(DT0) || isnan(DT1)) {
71
        T0 = (FSR_FCC1 | FSR_FCC0) << FS;
72
        if (env->fsr & FSR_NVM) {
73
            env->fsr |= T0;
74
            raise_exception(TT_FP_EXCP);
75
        } else {
76
            env->fsr |= FSR_NVA;
77
        }
78
    } else if (DT0 < DT1) {
79
        T0 = FSR_FCC0 << FS;
80
    } else if (DT0 > DT1) {
81
        T0 = FSR_FCC1 << FS;
82
    } else {
83
        T0 = 0;
84
    }
85
    env->fsr |= T0;
86
}
87

    
88
#ifdef TARGET_SPARC64
89
#undef FS
90
#define FS 22
91
void do_fcmps_fcc1 (void)
92
{
93
    env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);
94
    if (isnan(FT0) || isnan(FT1)) {
95
        T0 = (FSR_FCC1 | FSR_FCC0) << FS;
96
        if (env->fsr & FSR_NVM) {
97
            env->fsr |= T0;
98
            raise_exception(TT_FP_EXCP);
99
        } else {
100
            env->fsr |= FSR_NVA;
101
        }
102
    } else if (FT0 < FT1) {
103
        T0 = FSR_FCC0 << FS;
104
    } else if (FT0 > FT1) {
105
        T0 = FSR_FCC1 << FS;
106
    } else {
107
        T0 = 0;
108
    }
109
    env->fsr |= T0;
110
}
111

    
112
void do_fcmpd_fcc1 (void)
113
{
114
    env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);
115
    if (isnan(DT0) || isnan(DT1)) {
116
        T0 = (FSR_FCC1 | FSR_FCC0) << FS;
117
        if (env->fsr & FSR_NVM) {
118
            env->fsr |= T0;
119
            raise_exception(TT_FP_EXCP);
120
        } else {
121
            env->fsr |= FSR_NVA;
122
        }
123
    } else if (DT0 < DT1) {
124
        T0 = FSR_FCC0 << FS;
125
    } else if (DT0 > DT1) {
126
        T0 = FSR_FCC1 << FS;
127
    } else {
128
        T0 = 0;
129
    }
130
    env->fsr |= T0;
131
}
132

    
133
#undef FS
134
#define FS 24
135
void do_fcmps_fcc2 (void)
136
{
137
    env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);
138
    if (isnan(FT0) || isnan(FT1)) {
139
        T0 = (FSR_FCC1 | FSR_FCC0) << FS;
140
        if (env->fsr & FSR_NVM) {
141
            env->fsr |= T0;
142
            raise_exception(TT_FP_EXCP);
143
        } else {
144
            env->fsr |= FSR_NVA;
145
        }
146
    } else if (FT0 < FT1) {
147
        T0 = FSR_FCC0 << FS;
148
    } else if (FT0 > FT1) {
149
        T0 = FSR_FCC1 << FS;
150
    } else {
151
        T0 = 0;
152
    }
153
    env->fsr |= T0;
154
}
155

    
156
void do_fcmpd_fcc2 (void)
157
{
158
    env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);
159
    if (isnan(DT0) || isnan(DT1)) {
160
        T0 = (FSR_FCC1 | FSR_FCC0) << FS;
161
        if (env->fsr & FSR_NVM) {
162
            env->fsr |= T0;
163
            raise_exception(TT_FP_EXCP);
164
        } else {
165
            env->fsr |= FSR_NVA;
166
        }
167
    } else if (DT0 < DT1) {
168
        T0 = FSR_FCC0 << FS;
169
    } else if (DT0 > DT1) {
170
        T0 = FSR_FCC1 << FS;
171
    } else {
172
        T0 = 0;
173
    }
174
    env->fsr |= T0;
175
}
176

    
177
#undef FS
178
#define FS 26
179
void do_fcmps_fcc3 (void)
180
{
181
    env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);
182
    if (isnan(FT0) || isnan(FT1)) {
183
        T0 = (FSR_FCC1 | FSR_FCC0) << FS;
184
        if (env->fsr & FSR_NVM) {
185
            env->fsr |= T0;
186
            raise_exception(TT_FP_EXCP);
187
        } else {
188
            env->fsr |= FSR_NVA;
189
        }
190
    } else if (FT0 < FT1) {
191
        T0 = FSR_FCC0 << FS;
192
    } else if (FT0 > FT1) {
193
        T0 = FSR_FCC1 << FS;
194
    } else {
195
        T0 = 0;
196
    }
197
    env->fsr |= T0;
198
}
199

    
200
void do_fcmpd_fcc3 (void)
201
{
202
    env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);
203
    if (isnan(DT0) || isnan(DT1)) {
204
        T0 = (FSR_FCC1 | FSR_FCC0) << FS;
205
        if (env->fsr & FSR_NVM) {
206
            env->fsr |= T0;
207
            raise_exception(TT_FP_EXCP);
208
        } else {
209
            env->fsr |= FSR_NVA;
210
        }
211
    } else if (DT0 < DT1) {
212
        T0 = FSR_FCC0 << FS;
213
    } else if (DT0 > DT1) {
214
        T0 = FSR_FCC1 << FS;
215
    } else {
216
        T0 = 0;
217
    }
218
    env->fsr |= T0;
219
}
220
#undef FS
221
#endif
222

    
223
#ifndef TARGET_SPARC64
224
void helper_ld_asi(int asi, int size, int sign)
225
{
226
    uint32_t ret;
227

    
228
    switch (asi) {
229
    case 3: /* MMU probe */
230
        {
231
            int mmulev;
232

    
233
            mmulev = (T0 >> 8) & 15;
234
            if (mmulev > 4)
235
                ret = 0;
236
            else {
237
                ret = mmu_probe(T0, mmulev);
238
                //bswap32s(&ret);
239
            }
240
#ifdef DEBUG_MMU
241
            printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret);
242
#endif
243
        }
244
        break;
245
    case 4: /* read MMU regs */
246
        {
247
            int reg = (T0 >> 8) & 0xf;
248
            
249
            ret = env->mmuregs[reg];
250
            if (reg == 3) /* Fault status cleared on read */
251
                env->mmuregs[reg] = 0;
252
#ifdef DEBUG_MMU
253
            printf("mmu_read: reg[%d] = 0x%08x\n", reg, ret);
254
#endif
255
        }
256
        break;
257
    case 0x20 ... 0x2f: /* MMU passthrough */
258
        cpu_physical_memory_read(T0, (void *) &ret, size);
259
        if (size == 4)
260
            tswap32s(&ret);
261
        else if (size == 2)
262
            tswap16s((uint16_t *)&ret);
263
        break;
264
    default:
265
        ret = 0;
266
        break;
267
    }
268
    T1 = ret;
269
}
270

    
271
void helper_st_asi(int asi, int size, int sign)
272
{
273
    switch(asi) {
274
    case 3: /* MMU flush */
275
        {
276
            int mmulev;
277

    
278
            mmulev = (T0 >> 8) & 15;
279
#ifdef DEBUG_MMU
280
            printf("mmu flush level %d\n", mmulev);
281
#endif
282
            switch (mmulev) {
283
            case 0: // flush page
284
                tlb_flush_page(env, T0 & 0xfffff000);
285
                break;
286
            case 1: // flush segment (256k)
287
            case 2: // flush region (16M)
288
            case 3: // flush context (4G)
289
            case 4: // flush entire
290
                tlb_flush(env, 1);
291
                break;
292
            default:
293
                break;
294
            }
295
#ifdef DEBUG_MMU
296
            dump_mmu();
297
#endif
298
            return;
299
        }
300
    case 4: /* write MMU regs */
301
        {
302
            int reg = (T0 >> 8) & 0xf, oldreg;
303
            
304
            oldreg = env->mmuregs[reg];
305
            switch(reg) {
306
            case 0:
307
                env->mmuregs[reg] &= ~(MMU_E | MMU_NF);
308
                env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF);
309
                // Mappings generated during no-fault mode or MMU
310
                // disabled mode are invalid in normal mode
311
                if (oldreg != env->mmuregs[reg])
312
                    tlb_flush(env, 1);
313
                break;
314
            case 2:
315
                env->mmuregs[reg] = T1;
316
                if (oldreg != env->mmuregs[reg]) {
317
                    /* we flush when the MMU context changes because
318
                       QEMU has no MMU context support */
319
                    tlb_flush(env, 1);
320
                }
321
                break;
322
            case 3:
323
            case 4:
324
                break;
325
            default:
326
                env->mmuregs[reg] = T1;
327
                break;
328
            }
329
#ifdef DEBUG_MMU
330
            if (oldreg != env->mmuregs[reg]) {
331
                printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->mmuregs[reg]);
332
            }
333
            dump_mmu();
334
#endif
335
            return;
336
        }
337
    case 0x17: /* Block copy, sta access */
338
        {
339
            // value (T1) = src
340
            // address (T0) = dst
341
            // copy 32 bytes
342
            int src = T1, dst = T0;
343
            uint8_t temp[32];
344
            
345
            tswap32s(&src);
346

    
347
            cpu_physical_memory_read(src, (void *) &temp, 32);
348
            cpu_physical_memory_write(dst, (void *) &temp, 32);
349
        }
350
        return;
351
    case 0x1f: /* Block fill, stda access */
352
        {
353
            // value (T1, T2)
354
            // address (T0) = dst
355
            // fill 32 bytes
356
            int i, dst = T0;
357
            uint64_t val;
358
            
359
            val = (((uint64_t)T1) << 32) | T2;
360
            tswap64s(&val);
361

    
362
            for (i = 0; i < 32; i += 8, dst += 8) {
363
                cpu_physical_memory_write(dst, (void *) &val, 8);
364
            }
365
        }
366
        return;
367
    case 0x20 ... 0x2f: /* MMU passthrough */
368
        {
369
            int temp = T1;
370
            if (size == 4)
371
                tswap32s(&temp);
372
            else if (size == 2)
373
                tswap16s((uint16_t *)&temp);
374
            cpu_physical_memory_write(T0, (void *) &temp, size);
375
        }
376
        return;
377
    default:
378
        return;
379
    }
380
}
381

    
382
#else
383

    
384
void helper_ld_asi(int asi, int size, int sign)
385
{
386
    uint64_t ret;
387

    
388
    if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
389
        raise_exception(TT_PRIV_INSN);
390

    
391
    switch (asi) {
392
    case 0x14: // Bypass
393
    case 0x15: // Bypass, non-cacheable
394
        {
395
            cpu_physical_memory_read(T0, (void *) &ret, size);
396
            if (size == 8)
397
                tswap64s(&ret);
398
            if (size == 4)
399
                tswap32s((uint32_t *)&ret);
400
            else if (size == 2)
401
                tswap16s((uint16_t *)&ret);
402
            break;
403
        }
404
    case 0x1c: // Bypass LE
405
    case 0x1d: // Bypass, non-cacheable LE
406
        // XXX
407
        break;
408
    case 0x45: // LSU
409
        ret = env->lsu;
410
        break;
411
    case 0x50: // I-MMU regs
412
        {
413
            int reg = (T0 >> 3) & 0xf;
414

    
415
            ret = env->immuregs[reg];
416
            break;
417
        }
418
    case 0x51: // I-MMU 8k TSB pointer
419
    case 0x52: // I-MMU 64k TSB pointer
420
    case 0x55: // I-MMU data access
421
    case 0x56: // I-MMU tag read
422
        break;
423
    case 0x58: // D-MMU regs
424
        {
425
            int reg = (T0 >> 3) & 0xf;
426

    
427
            ret = env->dmmuregs[reg];
428
            break;
429
        }
430
    case 0x59: // D-MMU 8k TSB pointer
431
    case 0x5a: // D-MMU 64k TSB pointer
432
    case 0x5b: // D-MMU data pointer
433
    case 0x5d: // D-MMU data access
434
    case 0x5e: // D-MMU tag read
435
        break;
436
    case 0x54: // I-MMU data in, WO
437
    case 0x57: // I-MMU demap, WO
438
    case 0x5c: // D-MMU data in, WO
439
    case 0x5f: // D-MMU demap, WO
440
    default:
441
        ret = 0;
442
        break;
443
    }
444
    T1 = ret;
445
}
446

    
447
void helper_st_asi(int asi, int size, int sign)
448
{
449
    if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
450
        raise_exception(TT_PRIV_INSN);
451

    
452
    switch(asi) {
453
    case 0x14: // Bypass
454
    case 0x15: // Bypass, non-cacheable
455
        {
456
            target_ulong temp = T1;
457
            if (size == 8)
458
                tswap64s(&temp);
459
            else if (size == 4)
460
                tswap32s((uint32_t *)&temp);
461
            else if (size == 2)
462
                tswap16s((uint16_t *)&temp);
463
            cpu_physical_memory_write(T0, (void *) &temp, size);
464
        }
465
        return;
466
    case 0x1c: // Bypass LE
467
    case 0x1d: // Bypass, non-cacheable LE
468
        // XXX
469
        return;
470
    case 0x45: // LSU
471
        {
472
            uint64_t oldreg;
473

    
474
            oldreg = env->lsu;
475
            env->lsu = T1 & (DMMU_E | IMMU_E);
476
            // Mappings generated during D/I MMU disabled mode are
477
            // invalid in normal mode
478
            if (oldreg != env->lsu)
479
                tlb_flush(env, 1);
480
            return;
481
        }
482
    case 0x50: // I-MMU regs
483
        {
484
            int reg = (T0 >> 3) & 0xf;
485
            uint64_t oldreg;
486
            
487
            oldreg = env->immuregs[reg];
488
            switch(reg) {
489
            case 0: // RO
490
            case 4:
491
                return;
492
            case 1: // Not in I-MMU
493
            case 2:
494
            case 7:
495
            case 8:
496
                return;
497
            case 3: // SFSR
498
                if ((T1 & 1) == 0)
499
                    T1 = 0; // Clear SFSR
500
                break;
501
            case 5: // TSB access
502
            case 6: // Tag access
503
            default:
504
                break;
505
            }
506
            env->immuregs[reg] = T1;
507
#ifdef DEBUG_MMU
508
            if (oldreg != env->immuregs[reg]) {
509
                printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->immuregs[reg]);
510
            }
511
            dump_mmu();
512
#endif
513
            return;
514
        }
515
    case 0x54: // I-MMU data in
516
        {
517
            unsigned int i;
518

    
519
            // Try finding an invalid entry
520
            for (i = 0; i < 64; i++) {
521
                if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0) {
522
                    env->itlb_tag[i] = env->immuregs[6];
523
                    env->itlb_tte[i] = T1;
524
                    return;
525
                }
526
            }
527
            // Try finding an unlocked entry
528
            for (i = 0; i < 64; i++) {
529
                if ((env->itlb_tte[i] & 0x40) == 0) {
530
                    env->itlb_tag[i] = env->immuregs[6];
531
                    env->itlb_tte[i] = T1;
532
                    return;
533
                }
534
            }
535
            // error state?
536
            return;
537
        }
538
    case 0x55: // I-MMU data access
539
        {
540
            unsigned int i = (T0 >> 3) & 0x3f;
541

    
542
            env->itlb_tag[i] = env->immuregs[6];
543
            env->itlb_tte[i] = T1;
544
            return;
545
        }
546
    case 0x57: // I-MMU demap
547
        return;
548
    case 0x58: // D-MMU regs
549
        {
550
            int reg = (T0 >> 3) & 0xf;
551
            uint64_t oldreg;
552
            
553
            oldreg = env->dmmuregs[reg];
554
            switch(reg) {
555
            case 0: // RO
556
            case 4:
557
                return;
558
            case 3: // SFSR
559
                if ((T1 & 1) == 0) {
560
                    T1 = 0; // Clear SFSR, Fault address
561
                    env->dmmuregs[4] = 0;
562
                }
563
                env->dmmuregs[reg] = T1;
564
                break;
565
            case 1: // Primary context
566
            case 2: // Secondary context
567
            case 5: // TSB access
568
            case 6: // Tag access
569
            case 7: // Virtual Watchpoint
570
            case 8: // Physical Watchpoint
571
            default:
572
                break;
573
            }
574
            env->dmmuregs[reg] = T1;
575
#ifdef DEBUG_MMU
576
            if (oldreg != env->dmmuregs[reg]) {
577
                printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->dmmuregs[reg]);
578
            }
579
            dump_mmu();
580
#endif
581
            return;
582
        }
583
    case 0x5c: // D-MMU data in
584
        {
585
            unsigned int i;
586

    
587
            // Try finding an invalid entry
588
            for (i = 0; i < 64; i++) {
589
                if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0) {
590
                    env->dtlb_tag[i] = env->dmmuregs[6];
591
                    env->dtlb_tte[i] = T1;
592
                    return;
593
                }
594
            }
595
            // Try finding an unlocked entry
596
            for (i = 0; i < 64; i++) {
597
                if ((env->dtlb_tte[i] & 0x40) == 0) {
598
                    env->dtlb_tag[i] = env->dmmuregs[6];
599
                    env->dtlb_tte[i] = T1;
600
                    return;
601
                }
602
            }
603
            // error state?
604
            return;
605
        }
606
    case 0x5d: // D-MMU data access
607
        {
608
            unsigned int i = (T0 >> 3) & 0x3f;
609

    
610
            env->dtlb_tag[i] = env->dmmuregs[6];
611
            env->dtlb_tte[i] = T1;
612
            return;
613
        }
614
    case 0x5f: // D-MMU demap
615
        return;
616
    case 0x51: // I-MMU 8k TSB pointer, RO
617
    case 0x52: // I-MMU 64k TSB pointer, RO
618
    case 0x56: // I-MMU tag read, RO
619
    case 0x59: // D-MMU 8k TSB pointer, RO
620
    case 0x5a: // D-MMU 64k TSB pointer, RO
621
    case 0x5b: // D-MMU data pointer, RO
622
    case 0x5e: // D-MMU tag read, RO
623
    default:
624
        return;
625
    }
626
}
627

    
628
#endif
629

    
630
#ifndef TARGET_SPARC64
631
void helper_rett()
632
{
633
    unsigned int cwp;
634

    
635
    env->psret = 1;
636
    cwp = (env->cwp + 1) & (NWINDOWS - 1); 
637
    if (env->wim & (1 << cwp)) {
638
        raise_exception(TT_WIN_UNF);
639
    }
640
    set_cwp(cwp);
641
    env->psrs = env->psrps;
642
}
643
#endif
644

    
645
void helper_ldfsr(void)
646
{
647
    int rnd_mode;
648
    switch (env->fsr & FSR_RD_MASK) {
649
    case FSR_RD_NEAREST:
650
        rnd_mode = float_round_nearest_even;
651
        break;
652
    default:
653
    case FSR_RD_ZERO:
654
        rnd_mode = float_round_to_zero;
655
        break;
656
    case FSR_RD_POS:
657
        rnd_mode = float_round_up;
658
        break;
659
    case FSR_RD_NEG:
660
        rnd_mode = float_round_down;
661
        break;
662
    }
663
    set_float_rounding_mode(rnd_mode, &env->fp_status);
664
}
665

    
666
void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f)
667
{
668
    int exptemp;
669

    
670
    *pmant = ldexp(frexp(f, &exptemp), 53);
671
    *pexp = exptemp;
672
}
673

    
674
double cpu_put_fp64(uint64_t mant, uint16_t exp)
675
{
676
    return ldexp((double) mant, exp - 53);
677
}
678

    
679
void helper_debug()
680
{
681
    env->exception_index = EXCP_DEBUG;
682
    cpu_loop_exit();
683
}
684

    
685
#ifndef TARGET_SPARC64
686
void do_wrpsr()
687
{
688
    PUT_PSR(env, T0);
689
}
690

    
691
void do_rdpsr()
692
{
693
    T0 = GET_PSR(env);
694
}
695

    
696
#else
697

    
698
void do_popc()
699
{
700
    T0 = (T1 & 0x5555555555555555ULL) + ((T1 >> 1) & 0x5555555555555555ULL);
701
    T0 = (T0 & 0x3333333333333333ULL) + ((T0 >> 2) & 0x3333333333333333ULL);
702
    T0 = (T0 & 0x0f0f0f0f0f0f0f0fULL) + ((T0 >> 4) & 0x0f0f0f0f0f0f0f0fULL);
703
    T0 = (T0 & 0x00ff00ff00ff00ffULL) + ((T0 >> 8) & 0x00ff00ff00ff00ffULL);
704
    T0 = (T0 & 0x0000ffff0000ffffULL) + ((T0 >> 16) & 0x0000ffff0000ffffULL);
705
    T0 = (T0 & 0x00000000ffffffffULL) + ((T0 >> 32) & 0x00000000ffffffffULL);
706
}
707
#endif