op_helper.c 85.1 KB
Newer Older
1
#include "exec.h"
blueswir1's avatar
blueswir1 committed
2
#include "host-utils.h"
blueswir1's avatar
blueswir1 committed
3
#include "helper.h"
4
5
6
#if !defined(CONFIG_USER_ONLY)
#include "softmmu_exec.h"
#endif /* !defined(CONFIG_USER_ONLY) */
7

bellard's avatar
bellard committed
8
//#define DEBUG_MMU
9
//#define DEBUG_MXCC
blueswir1's avatar
blueswir1 committed
10
//#define DEBUG_UNALIGNED
11
//#define DEBUG_UNASSIGNED
12
//#define DEBUG_ASI
blueswir1's avatar
blueswir1 committed
13
//#define DEBUG_PCALL
bellard's avatar
bellard committed
14

15
16
17
18
#ifdef DEBUG_MMU
#define DPRINTF_MMU(fmt, args...) \
do { printf("MMU: " fmt , ##args); } while (0)
#else
blueswir1's avatar
blueswir1 committed
19
#define DPRINTF_MMU(fmt, args...) do {} while (0)
20
21
22
23
24
25
#endif

#ifdef DEBUG_MXCC
#define DPRINTF_MXCC(fmt, args...) \
do { printf("MXCC: " fmt , ##args); } while (0)
#else
blueswir1's avatar
blueswir1 committed
26
#define DPRINTF_MXCC(fmt, args...) do {} while (0)
27
28
#endif

29
30
31
32
#ifdef DEBUG_ASI
#define DPRINTF_ASI(fmt, args...) \
do { printf("ASI: " fmt , ##args); } while (0)
#else
blueswir1's avatar
blueswir1 committed
33
#define DPRINTF_ASI(fmt, args...) do {} while (0)
34
35
#endif

blueswir1's avatar
blueswir1 committed
36
37
38
#ifdef TARGET_SPARC64
#ifndef TARGET_ABI32
#define AM_CHECK(env1) ((env1)->pstate & PS_AM)
39
#else
blueswir1's avatar
blueswir1 committed
40
41
#define AM_CHECK(env1) (1)
#endif
42
43
#endif

blueswir1's avatar
blueswir1 committed
44
45
46
47
48
49
50
51
static inline void address_mask(CPUState *env1, target_ulong *addr)
{
#ifdef TARGET_SPARC64
    if (AM_CHECK(env1))
        *addr &= 0xffffffffULL;
#endif
}

bellard's avatar
bellard committed
52
53
54
55
void raise_exception(int tt)
{
    env->exception_index = tt;
    cpu_loop_exit();
56
}
bellard's avatar
bellard committed
57

blueswir1's avatar
blueswir1 committed
58
void helper_trap(target_ulong nb_trap)
59
{
blueswir1's avatar
blueswir1 committed
60
61
62
63
64
65
66
67
68
69
70
71
    env->exception_index = TT_TRAP + (nb_trap & 0x7f);
    cpu_loop_exit();
}

void helper_trapcc(target_ulong nb_trap, target_ulong do_trap)
{
    if (do_trap) {
        env->exception_index = TT_TRAP + (nb_trap & 0x7f);
        cpu_loop_exit();
    }
}

blueswir1's avatar
blueswir1 committed
72
73
74
75
76
static inline void set_cwp(int new_cwp)
{
    cpu_set_cwp(env, new_cwp);
}

blueswir1's avatar
blueswir1 committed
77
78
void helper_check_align(target_ulong addr, uint32_t align)
{
79
80
81
82
83
    if (addr & align) {
#ifdef DEBUG_UNALIGNED
    printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
           "\n", addr, env->pc);
#endif
blueswir1's avatar
blueswir1 committed
84
        raise_exception(TT_UNALIGNED);
85
    }
blueswir1's avatar
blueswir1 committed
86
87
}

88
89
90
#define F_HELPER(name, p) void helper_f##name##p(void)

#define F_BINOP(name)                                           \
blueswir1's avatar
blueswir1 committed
91
    float32 helper_f ## name ## s (float32 src1, float32 src2)  \
92
    {                                                           \
blueswir1's avatar
blueswir1 committed
93
        return float32_ ## name (src1, src2, &env->fp_status);  \
94
95
96
97
    }                                                           \
    F_HELPER(name, d)                                           \
    {                                                           \
        DT0 = float64_ ## name (DT0, DT1, &env->fp_status);     \
blueswir1's avatar
blueswir1 committed
98
99
100
101
    }                                                           \
    F_HELPER(name, q)                                           \
    {                                                           \
        QT0 = float128_ ## name (QT0, QT1, &env->fp_status);    \
102
103
104
105
106
107
108
109
    }

F_BINOP(add);
F_BINOP(sub);
F_BINOP(mul);
F_BINOP(div);
#undef F_BINOP

110
void helper_fsmuld(float32 src1, float32 src2)
blueswir1's avatar
blueswir1 committed
111
{
112
113
    DT0 = float64_mul(float32_to_float64(src1, &env->fp_status),
                      float32_to_float64(src2, &env->fp_status),
114
115
                      &env->fp_status);
}
blueswir1's avatar
blueswir1 committed
116

blueswir1's avatar
blueswir1 committed
117
118
119
120
121
122
123
void helper_fdmulq(void)
{
    QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status),
                       float64_to_float128(DT1, &env->fp_status),
                       &env->fp_status);
}

blueswir1's avatar
blueswir1 committed
124
float32 helper_fnegs(float32 src)
125
{
blueswir1's avatar
blueswir1 committed
126
    return float32_chs(src);
127
128
}

129
130
#ifdef TARGET_SPARC64
F_HELPER(neg, d)
131
{
132
    DT0 = float64_chs(DT1);
133
}
blueswir1's avatar
blueswir1 committed
134
135
136
137
138
139

F_HELPER(neg, q)
{
    QT0 = float128_chs(QT1);
}
#endif
140
141

/* Integer to float conversion.  */
blueswir1's avatar
blueswir1 committed
142
float32 helper_fitos(int32_t src)
bellard's avatar
bellard committed
143
{
blueswir1's avatar
blueswir1 committed
144
    return int32_to_float32(src, &env->fp_status);
bellard's avatar
bellard committed
145
146
}

147
void helper_fitod(int32_t src)
bellard's avatar
bellard committed
148
{
149
    DT0 = int32_to_float64(src, &env->fp_status);
bellard's avatar
bellard committed
150
}
151

152
void helper_fitoq(int32_t src)
blueswir1's avatar
blueswir1 committed
153
{
154
    QT0 = int32_to_float128(src, &env->fp_status);
blueswir1's avatar
blueswir1 committed
155
156
}

157
#ifdef TARGET_SPARC64
158
float32 helper_fxtos(void)
159
{
160
    return int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
161
162
}

163
F_HELPER(xto, d)
164
165
166
{
    DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
}
blueswir1's avatar
blueswir1 committed
167

blueswir1's avatar
blueswir1 committed
168
169
170
171
172
F_HELPER(xto, q)
{
    QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status);
}
#endif
173
174
175
#undef F_HELPER

/* floating point conversion */
176
float32 helper_fdtos(void)
177
{
178
    return float64_to_float32(DT1, &env->fp_status);
179
180
}

181
void helper_fstod(float32 src)
182
{
183
    DT0 = float32_to_float64(src, &env->fp_status);
184
}
185

186
float32 helper_fqtos(void)
blueswir1's avatar
blueswir1 committed
187
{
188
    return float128_to_float32(QT1, &env->fp_status);
blueswir1's avatar
blueswir1 committed
189
190
}

191
void helper_fstoq(float32 src)
blueswir1's avatar
blueswir1 committed
192
{
193
    QT0 = float32_to_float128(src, &env->fp_status);
blueswir1's avatar
blueswir1 committed
194
195
196
197
198
199
200
201
202
203
204
205
}

void helper_fqtod(void)
{
    DT0 = float128_to_float64(QT1, &env->fp_status);
}

void helper_fdtoq(void)
{
    QT0 = float64_to_float128(DT1, &env->fp_status);
}

206
/* Float to integer conversion.  */
blueswir1's avatar
blueswir1 committed
207
int32_t helper_fstoi(float32 src)
208
{
blueswir1's avatar
blueswir1 committed
209
    return float32_to_int32_round_to_zero(src, &env->fp_status);
210
211
}

212
int32_t helper_fdtoi(void)
213
{
214
    return float64_to_int32_round_to_zero(DT1, &env->fp_status);
215
216
}

217
int32_t helper_fqtoi(void)
blueswir1's avatar
blueswir1 committed
218
{
219
    return float128_to_int32_round_to_zero(QT1, &env->fp_status);
blueswir1's avatar
blueswir1 committed
220
221
}

222
#ifdef TARGET_SPARC64
223
void helper_fstox(float32 src)
224
{
225
    *((int64_t *)&DT0) = float32_to_int64_round_to_zero(src, &env->fp_status);
226
227
228
229
230
231
232
}

void helper_fdtox(void)
{
    *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status);
}

blueswir1's avatar
blueswir1 committed
233
234
235
236
237
void helper_fqtox(void)
{
    *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status);
}

238
239
240
241
242
void helper_faligndata(void)
{
    uint64_t tmp;

    tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8);
blueswir1's avatar
blueswir1 committed
243
244
245
246
    /* on many architectures a shift of 64 does nothing */
    if ((env->gsr & 7) != 0) {
        tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8);
    }
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
    *((uint64_t *)&DT0) = tmp;
}

#ifdef WORDS_BIGENDIAN
#define VIS_B64(n) b[7 - (n)]
#define VIS_W64(n) w[3 - (n)]
#define VIS_SW64(n) sw[3 - (n)]
#define VIS_L64(n) l[1 - (n)]
#define VIS_B32(n) b[3 - (n)]
#define VIS_W32(n) w[1 - (n)]
#else
#define VIS_B64(n) b[n]
#define VIS_W64(n) w[n]
#define VIS_SW64(n) sw[n]
#define VIS_L64(n) l[n]
#define VIS_B32(n) b[n]
#define VIS_W32(n) w[n]
#endif

typedef union {
    uint8_t b[8];
    uint16_t w[4];
    int16_t sw[4];
    uint32_t l[2];
    float64 d;
} vis64;

typedef union {
    uint8_t b[4];
    uint16_t w[2];
    uint32_t l;
    float32 f;
} vis32;

void helper_fpmerge(void)
{
    vis64 s, d;

    s.d = DT0;
    d.d = DT1;

    // Reverse calculation order to handle overlap
    d.VIS_B64(7) = s.VIS_B64(3);
    d.VIS_B64(6) = d.VIS_B64(3);
    d.VIS_B64(5) = s.VIS_B64(2);
    d.VIS_B64(4) = d.VIS_B64(2);
    d.VIS_B64(3) = s.VIS_B64(1);
    d.VIS_B64(2) = d.VIS_B64(1);
    d.VIS_B64(1) = s.VIS_B64(0);
    //d.VIS_B64(0) = d.VIS_B64(0);

    DT0 = d.d;
}

void helper_fmul8x16(void)
{
    vis64 s, d;
    uint32_t tmp;

    s.d = DT0;
    d.d = DT1;

#define PMUL(r)                                                 \
    tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r);       \
    if ((tmp & 0xff) > 0x7f)                                    \
        tmp += 0x100;                                           \
    d.VIS_W64(r) = tmp >> 8;

    PMUL(0);
    PMUL(1);
    PMUL(2);
    PMUL(3);
#undef PMUL

    DT0 = d.d;
}

void helper_fmul8x16al(void)
{
    vis64 s, d;
    uint32_t tmp;

    s.d = DT0;
    d.d = DT1;

#define PMUL(r)                                                 \
    tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r);       \
    if ((tmp & 0xff) > 0x7f)                                    \
        tmp += 0x100;                                           \
    d.VIS_W64(r) = tmp >> 8;

    PMUL(0);
    PMUL(1);
    PMUL(2);
    PMUL(3);
#undef PMUL

    DT0 = d.d;
}

void helper_fmul8x16au(void)
{
    vis64 s, d;
    uint32_t tmp;

    s.d = DT0;
    d.d = DT1;

#define PMUL(r)                                                 \
    tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r);       \
    if ((tmp & 0xff) > 0x7f)                                    \
        tmp += 0x100;                                           \
    d.VIS_W64(r) = tmp >> 8;

    PMUL(0);
    PMUL(1);
    PMUL(2);
    PMUL(3);
#undef PMUL

    DT0 = d.d;
}

void helper_fmul8sux16(void)
{
    vis64 s, d;
    uint32_t tmp;

    s.d = DT0;
    d.d = DT1;

#define PMUL(r)                                                         \
    tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
    if ((tmp & 0xff) > 0x7f)                                            \
        tmp += 0x100;                                                   \
    d.VIS_W64(r) = tmp >> 8;

    PMUL(0);
    PMUL(1);
    PMUL(2);
    PMUL(3);
#undef PMUL

    DT0 = d.d;
}

void helper_fmul8ulx16(void)
{
    vis64 s, d;
    uint32_t tmp;

    s.d = DT0;
    d.d = DT1;

#define PMUL(r)                                                         \
    tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2));        \
    if ((tmp & 0xff) > 0x7f)                                            \
        tmp += 0x100;                                                   \
    d.VIS_W64(r) = tmp >> 8;

    PMUL(0);
    PMUL(1);
    PMUL(2);
    PMUL(3);
#undef PMUL

    DT0 = d.d;
}

void helper_fmuld8sux16(void)
{
    vis64 s, d;
    uint32_t tmp;

    s.d = DT0;
    d.d = DT1;

#define PMUL(r)                                                         \
    tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
    if ((tmp & 0xff) > 0x7f)                                            \
        tmp += 0x100;                                                   \
    d.VIS_L64(r) = tmp;

    // Reverse calculation order to handle overlap
    PMUL(1);
    PMUL(0);
#undef PMUL

    DT0 = d.d;
}

void helper_fmuld8ulx16(void)
{
    vis64 s, d;
    uint32_t tmp;

    s.d = DT0;
    d.d = DT1;

#define PMUL(r)                                                         \
    tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2));        \
    if ((tmp & 0xff) > 0x7f)                                            \
        tmp += 0x100;                                                   \
    d.VIS_L64(r) = tmp;

    // Reverse calculation order to handle overlap
    PMUL(1);
    PMUL(0);
#undef PMUL

    DT0 = d.d;
}

void helper_fexpand(void)
{
    vis32 s;
    vis64 d;

    s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff);
    d.d = DT1;
    d.VIS_L64(0) = s.VIS_W32(0) << 4;
    d.VIS_L64(1) = s.VIS_W32(1) << 4;
    d.VIS_L64(2) = s.VIS_W32(2) << 4;
    d.VIS_L64(3) = s.VIS_W32(3) << 4;

    DT0 = d.d;
}

#define VIS_HELPER(name, F)                             \
    void name##16(void)                                 \
    {                                                   \
        vis64 s, d;                                     \
                                                        \
        s.d = DT0;                                      \
        d.d = DT1;                                      \
                                                        \
        d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0));   \
        d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1));   \
        d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2));   \
        d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3));   \
                                                        \
        DT0 = d.d;                                      \
    }                                                   \
                                                        \
491
    uint32_t name##16s(uint32_t src1, uint32_t src2)    \
492
493
494
    {                                                   \
        vis32 s, d;                                     \
                                                        \
495
496
        s.l = src1;                                     \
        d.l = src2;                                     \
497
498
499
500
                                                        \
        d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0));   \
        d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1));   \
                                                        \
501
        return d.l;                                     \
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
    }                                                   \
                                                        \
    void name##32(void)                                 \
    {                                                   \
        vis64 s, d;                                     \
                                                        \
        s.d = DT0;                                      \
        d.d = DT1;                                      \
                                                        \
        d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0));   \
        d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1));   \
                                                        \
        DT0 = d.d;                                      \
    }                                                   \
                                                        \
517
    uint32_t name##32s(uint32_t src1, uint32_t src2)    \
518
519
520
    {                                                   \
        vis32 s, d;                                     \
                                                        \
521
522
        s.l = src1;                                     \
        d.l = src2;                                     \
523
524
525
                                                        \
        d.l = F(d.l, s.l);                              \
                                                        \
526
        return d.l;                                     \
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
    }

#define FADD(a, b) ((a) + (b))
#define FSUB(a, b) ((a) - (b))
VIS_HELPER(helper_fpadd, FADD)
VIS_HELPER(helper_fpsub, FSUB)

#define VIS_CMPHELPER(name, F)                                        \
    void name##16(void)                                           \
    {                                                             \
        vis64 s, d;                                               \
                                                                  \
        s.d = DT0;                                                \
        d.d = DT1;                                                \
                                                                  \
        d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0))? 1: 0;       \
        d.VIS_W64(0) |= F(d.VIS_W64(1), s.VIS_W64(1))? 2: 0;      \
        d.VIS_W64(0) |= F(d.VIS_W64(2), s.VIS_W64(2))? 4: 0;      \
        d.VIS_W64(0) |= F(d.VIS_W64(3), s.VIS_W64(3))? 8: 0;      \
                                                                  \
        DT0 = d.d;                                                \
    }                                                             \
                                                                  \
    void name##32(void)                                           \
    {                                                             \
        vis64 s, d;                                               \
                                                                  \
        s.d = DT0;                                                \
        d.d = DT1;                                                \
                                                                  \
        d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0))? 1: 0;       \
        d.VIS_L64(0) |= F(d.VIS_L64(1), s.VIS_L64(1))? 2: 0;      \
                                                                  \
        DT0 = d.d;                                                \
    }

#define FCMPGT(a, b) ((a) > (b))
#define FCMPEQ(a, b) ((a) == (b))
#define FCMPLE(a, b) ((a) <= (b))
#define FCMPNE(a, b) ((a) != (b))

VIS_CMPHELPER(helper_fcmpgt, FCMPGT)
VIS_CMPHELPER(helper_fcmpeq, FCMPEQ)
VIS_CMPHELPER(helper_fcmple, FCMPLE)
VIS_CMPHELPER(helper_fcmpne, FCMPNE)
#endif

void helper_check_ieee_exceptions(void)
{
    target_ulong status;

    status = get_float_exception_flags(&env->fp_status);
    if (status) {
        /* Copy IEEE 754 flags into FSR */
        if (status & float_flag_invalid)
            env->fsr |= FSR_NVC;
        if (status & float_flag_overflow)
            env->fsr |= FSR_OFC;
        if (status & float_flag_underflow)
            env->fsr |= FSR_UFC;
        if (status & float_flag_divbyzero)
            env->fsr |= FSR_DZC;
        if (status & float_flag_inexact)
            env->fsr |= FSR_NXC;

        if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) {
            /* Unmasked exception, generate a trap */
            env->fsr |= FSR_FTT_IEEE_EXCP;
            raise_exception(TT_FP_EXCP);
        } else {
            /* Accumulate exceptions */
            env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
        }
    }
}

void helper_clear_float_exceptions(void)
{
    set_float_exception_flags(0, &env->fp_status);
}

blueswir1's avatar
blueswir1 committed
608
float32 helper_fabss(float32 src)
609
{
blueswir1's avatar
blueswir1 committed
610
    return float32_abs(src);
611
612
}

bellard's avatar
bellard committed
613
#ifdef TARGET_SPARC64
614
void helper_fabsd(void)
bellard's avatar
bellard committed
615
616
617
{
    DT0 = float64_abs(DT1);
}
blueswir1's avatar
blueswir1 committed
618
619
620
621
622
623

void helper_fabsq(void)
{
    QT0 = float128_abs(QT1);
}
#endif
bellard's avatar
bellard committed
624

blueswir1's avatar
blueswir1 committed
625
float32 helper_fsqrts(float32 src)
626
{
blueswir1's avatar
blueswir1 committed
627
    return float32_sqrt(src, &env->fp_status);
628
629
}

630
void helper_fsqrtd(void)
631
{
bellard's avatar
bellard committed
632
    DT0 = float64_sqrt(DT1, &env->fp_status);
633
634
}

blueswir1's avatar
blueswir1 committed
635
636
637
638
639
void helper_fsqrtq(void)
{
    QT0 = float128_sqrt(QT1, &env->fp_status);
}

640
#define GEN_FCMP(name, size, reg1, reg2, FS, TRAP)                      \
641
    void glue(helper_, name) (void)                                     \
bellard's avatar
bellard committed
642
    {                                                                   \
blueswir1's avatar
blueswir1 committed
643
644
        target_ulong new_fsr;                                           \
                                                                        \
bellard's avatar
bellard committed
645
646
647
        env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                     \
        switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) {   \
        case float_relation_unordered:                                  \
blueswir1's avatar
blueswir1 committed
648
            new_fsr = (FSR_FCC1 | FSR_FCC0) << FS;                      \
649
            if ((env->fsr & FSR_NVM) || TRAP) {                         \
blueswir1's avatar
blueswir1 committed
650
                env->fsr |= new_fsr;                                    \
651
652
                env->fsr |= FSR_NVC;                                    \
                env->fsr |= FSR_FTT_IEEE_EXCP;                          \
bellard's avatar
bellard committed
653
654
655
656
657
658
                raise_exception(TT_FP_EXCP);                            \
            } else {                                                    \
                env->fsr |= FSR_NVA;                                    \
            }                                                           \
            break;                                                      \
        case float_relation_less:                                       \
blueswir1's avatar
blueswir1 committed
659
            new_fsr = FSR_FCC0 << FS;                                   \
bellard's avatar
bellard committed
660
661
            break;                                                      \
        case float_relation_greater:                                    \
blueswir1's avatar
blueswir1 committed
662
            new_fsr = FSR_FCC1 << FS;                                   \
bellard's avatar
bellard committed
663
664
            break;                                                      \
        default:                                                        \
blueswir1's avatar
blueswir1 committed
665
            new_fsr = 0;                                                \
bellard's avatar
bellard committed
666
667
            break;                                                      \
        }                                                               \
blueswir1's avatar
blueswir1 committed
668
        env->fsr |= new_fsr;                                            \
669
    }
blueswir1's avatar
blueswir1 committed
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
#define GEN_FCMPS(name, size, FS, TRAP)                                 \
    void glue(helper_, name)(float32 src1, float32 src2)                \
    {                                                                   \
        target_ulong new_fsr;                                           \
                                                                        \
        env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                     \
        switch (glue(size, _compare) (src1, src2, &env->fp_status)) {   \
        case float_relation_unordered:                                  \
            new_fsr = (FSR_FCC1 | FSR_FCC0) << FS;                      \
            if ((env->fsr & FSR_NVM) || TRAP) {                         \
                env->fsr |= new_fsr;                                    \
                env->fsr |= FSR_NVC;                                    \
                env->fsr |= FSR_FTT_IEEE_EXCP;                          \
                raise_exception(TT_FP_EXCP);                            \
            } else {                                                    \
                env->fsr |= FSR_NVA;                                    \
            }                                                           \
            break;                                                      \
        case float_relation_less:                                       \
            new_fsr = FSR_FCC0 << FS;                                   \
            break;                                                      \
        case float_relation_greater:                                    \
            new_fsr = FSR_FCC1 << FS;                                   \
            break;                                                      \
        default:                                                        \
            new_fsr = 0;                                                \
            break;                                                      \
        }                                                               \
        env->fsr |= new_fsr;                                            \
    }
700

blueswir1's avatar
blueswir1 committed
701
GEN_FCMPS(fcmps, float32, 0, 0);
702
703
GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);

blueswir1's avatar
blueswir1 committed
704
GEN_FCMPS(fcmpes, float32, 0, 1);
705
GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
bellard's avatar
bellard committed
706

blueswir1's avatar
blueswir1 committed
707
708
709
GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);

bellard's avatar
bellard committed
710
#ifdef TARGET_SPARC64
blueswir1's avatar
blueswir1 committed
711
GEN_FCMPS(fcmps_fcc1, float32, 22, 0);
712
GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
blueswir1's avatar
blueswir1 committed
713
GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
714

blueswir1's avatar
blueswir1 committed
715
GEN_FCMPS(fcmps_fcc2, float32, 24, 0);
716
GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
blueswir1's avatar
blueswir1 committed
717
GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
718

blueswir1's avatar
blueswir1 committed
719
GEN_FCMPS(fcmps_fcc3, float32, 26, 0);
720
GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
blueswir1's avatar
blueswir1 committed
721
GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
722

blueswir1's avatar
blueswir1 committed
723
GEN_FCMPS(fcmpes_fcc1, float32, 22, 1);
724
GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
blueswir1's avatar
blueswir1 committed
725
GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
bellard's avatar
bellard committed
726

blueswir1's avatar
blueswir1 committed
727
GEN_FCMPS(fcmpes_fcc2, float32, 24, 1);
728
GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
blueswir1's avatar
blueswir1 committed
729
GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
bellard's avatar
bellard committed
730

blueswir1's avatar
blueswir1 committed
731
GEN_FCMPS(fcmpes_fcc3, float32, 26, 1);
732
GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
blueswir1's avatar
blueswir1 committed
733
734
GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
#endif
blueswir1's avatar
blueswir1 committed
735
#undef GEN_FCMPS
bellard's avatar
bellard committed
736

blueswir1's avatar
blueswir1 committed
737
738
#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && \
    defined(DEBUG_MXCC)
739
740
741
static void dump_mxcc(CPUState *env)
{
    printf("mxccdata: %016llx %016llx %016llx %016llx\n",
blueswir1's avatar
blueswir1 committed
742
743
           env->mxccdata[0], env->mxccdata[1],
           env->mxccdata[2], env->mxccdata[3]);
744
745
    printf("mxccregs: %016llx %016llx %016llx %016llx\n"
           "          %016llx %016llx %016llx %016llx\n",
blueswir1's avatar
blueswir1 committed
746
747
748
749
           env->mxccregs[0], env->mxccregs[1],
           env->mxccregs[2], env->mxccregs[3],
           env->mxccregs[4], env->mxccregs[5],
           env->mxccregs[6], env->mxccregs[7]);
750
751
752
}
#endif

blueswir1's avatar
blueswir1 committed
753
754
755
756
#if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)) \
    && defined(DEBUG_ASI)
static void dump_asi(const char *txt, target_ulong addr, int asi, int size,
                     uint64_t r1)
757
758
759
760
{
    switch (size)
    {
    case 1:
blueswir1's avatar
blueswir1 committed
761
762
        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt,
                    addr, asi, r1 & 0xff);
763
764
        break;
    case 2:
blueswir1's avatar
blueswir1 committed
765
766
        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %04" PRIx64 "\n", txt,
                    addr, asi, r1 & 0xffff);
767
768
        break;
    case 4:
blueswir1's avatar
blueswir1 committed
769
770
        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %08" PRIx64 "\n", txt,
                    addr, asi, r1 & 0xffffffff);
771
772
        break;
    case 8:
blueswir1's avatar
blueswir1 committed
773
774
        DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %016" PRIx64 "\n", txt,
                    addr, asi, r1);
775
776
777
778
779
        break;
    }
}
#endif

blueswir1's avatar
blueswir1 committed
780
781
782
#ifndef TARGET_SPARC64
#ifndef CONFIG_USER_ONLY
uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
783
{
blueswir1's avatar
blueswir1 committed
784
    uint64_t ret = 0;
785
#if defined(DEBUG_MXCC) || defined(DEBUG_ASI)
blueswir1's avatar
blueswir1 committed
786
    uint32_t last_addr = addr;
787
#endif
bellard's avatar
bellard committed
788

789
    helper_check_align(addr, size - 1);
bellard's avatar
bellard committed
790
    switch (asi) {
791
    case 2: /* SuperSparc MXCC registers */
blueswir1's avatar
blueswir1 committed
792
        switch (addr) {
793
        case 0x01c00a00: /* MXCC control register */
blueswir1's avatar
blueswir1 committed
794
795
796
            if (size == 8)
                ret = env->mxccregs[3];
            else
blueswir1's avatar
blueswir1 committed
797
798
                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
                             size);
799
800
801
802
803
            break;
        case 0x01c00a04: /* MXCC control register */
            if (size == 4)
                ret = env->mxccregs[3];
            else
blueswir1's avatar
blueswir1 committed
804
805
                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
                             size);
806
            break;
807
808
        case 0x01c00c00: /* Module reset register */
            if (size == 8) {
blueswir1's avatar
blueswir1 committed
809
                ret = env->mxccregs[5];
810
811
                // should we do something here?
            } else
blueswir1's avatar
blueswir1 committed
812
813
                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
                             size);
814
            break;
815
        case 0x01c00f00: /* MBus port address register */
blueswir1's avatar
blueswir1 committed
816
817
818
            if (size == 8)
                ret = env->mxccregs[7];
            else
blueswir1's avatar
blueswir1 committed
819
820
                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
                             size);
821
822
            break;
        default:
blueswir1's avatar
blueswir1 committed
823
824
            DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
                         size);
825
826
            break;
        }
blueswir1's avatar
blueswir1 committed
827
828
        DPRINTF_MXCC("asi = %d, size = %d, sign = %d, "
                     "addr = %08x -> ret = %08x,"
blueswir1's avatar
blueswir1 committed
829
                     "addr = %08x\n", asi, size, sign, last_addr, ret, addr);
830
831
832
#ifdef DEBUG_MXCC
        dump_mxcc(env);
#endif
833
        break;
834
    case 3: /* MMU probe */
blueswir1's avatar
blueswir1 committed
835
836
837
        {
            int mmulev;

blueswir1's avatar
blueswir1 committed
838
            mmulev = (addr >> 8) & 15;
blueswir1's avatar
blueswir1 committed
839
840
            if (mmulev > 4)
                ret = 0;
blueswir1's avatar
blueswir1 committed
841
842
843
844
            else
                ret = mmu_probe(env, addr, mmulev);
            DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n",
                        addr, mmulev, ret);
blueswir1's avatar
blueswir1 committed
845
846
        }
        break;
847
    case 4: /* read MMU regs */
blueswir1's avatar
blueswir1 committed
848
        {
blueswir1's avatar
blueswir1 committed
849
            int reg = (addr >> 8) & 0x1f;
850

blueswir1's avatar
blueswir1 committed
851
852
            ret = env->mmuregs[reg];
            if (reg == 3) /* Fault status cleared on read */
blueswir1's avatar
blueswir1 committed
853
854
855
856
857
                env->mmuregs[3] = 0;
            else if (reg == 0x13) /* Fault status read */
                ret = env->mmuregs[3];
            else if (reg == 0x14) /* Fault address read */
                ret = env->mmuregs[4];
blueswir1's avatar
blueswir1 committed
858
            DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret);
blueswir1's avatar
blueswir1 committed
859
860
        }
        break;
blueswir1's avatar
blueswir1 committed
861
862
863
864
    case 5: // Turbosparc ITLB Diagnostic
    case 6: // Turbosparc DTLB Diagnostic
    case 7: // Turbosparc IOTLB Diagnostic
        break;
865
866
867
    case 9: /* Supervisor code access */
        switch(size) {
        case 1:
blueswir1's avatar
blueswir1 committed
868
            ret = ldub_code(addr);
869
870
            break;
        case 2:
871
            ret = lduw_code(addr);
872
873
874
            break;
        default:
        case 4:
875
            ret = ldl_code(addr);
876
877
            break;
        case 8:
878
            ret = ldq_code(addr);
879
880
881
            break;
        }
        break;
882
883
884
    case 0xa: /* User data access */
        switch(size) {
        case 1:
blueswir1's avatar
blueswir1 committed
885
            ret = ldub_user(addr);
886
887
            break;
        case 2:
888
            ret = lduw_user(addr);
889
890
891
            break;
        default:
        case 4:
892
            ret = ldl_user(addr);
893
894
            break;
        case 8:
895
            ret = ldq_user(addr);
896
897
898
899
900
901
            break;
        }
        break;
    case 0xb: /* Supervisor data access */
        switch(size) {
        case 1:
blueswir1's avatar
blueswir1 committed
902
            ret = ldub_kernel(addr);
903
904
            break;
        case 2:
905
            ret = lduw_kernel(addr);
906
907
908
            break;
        default:
        case 4:
909
            ret = ldl_kernel(addr);
910
911
            break;
        case 8:
912
            ret = ldq_kernel(addr);
913
914
915
            break;
        }
        break;
916
917
918
919
920
921
    case 0xc: /* I-cache tag */
    case 0xd: /* I-cache data */
    case 0xe: /* D-cache tag */
    case 0xf: /* D-cache data */
        break;
    case 0x20: /* MMU passthrough */
bellard's avatar
bellard committed
922
923
        switch(size) {
        case 1:
blueswir1's avatar
blueswir1 committed
924
            ret = ldub_phys(addr);
bellard's avatar
bellard committed
925
926
            break;
        case 2:
927
            ret = lduw_phys(addr);
bellard's avatar
bellard committed
928
929
930
            break;
        default:
        case 4:
931
            ret = ldl_phys(addr);
bellard's avatar
bellard committed
932
            break;
bellard's avatar
bellard committed
933
        case 8:
934
            ret = ldq_phys(addr);
blueswir1's avatar
blueswir1 committed
935
            break;
bellard's avatar
bellard committed
936
        }
blueswir1's avatar
blueswir1 committed
937
        break;
938
    case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
939
940
        switch(size) {
        case 1:
blueswir1's avatar
blueswir1 committed
941
            ret = ldub_phys((target_phys_addr_t)addr
942
943
944
                            | ((target_phys_addr_t)(asi & 0xf) << 32));
            break;
        case 2:
945
            ret = lduw_phys((target_phys_addr_t)addr
946
947
948
949
                            | ((target_phys_addr_t)(asi & 0xf) << 32));
            break;
        default:
        case 4:
950
            ret = ldl_phys((target_phys_addr_t)addr
951
952
953
                           | ((target_phys_addr_t)(asi & 0xf) << 32));
            break;
        case 8:
954
            ret = ldq_phys((target_phys_addr_t)addr
955
                           | ((target_phys_addr_t)(asi & 0xf) << 32));
blueswir1's avatar
blueswir1 committed
956
            break;
957
        }
blueswir1's avatar
blueswir1 committed
958
        break;
blueswir1's avatar
blueswir1 committed
959
960
961
    case 0x30: // Turbosparc secondary cache diagnostic
    case 0x31: // Turbosparc RAM snoop
    case 0x32: // Turbosparc page table descriptor diagnostic
blueswir1's avatar
blueswir1 committed
962
963
964
    case 0x39: /* data cache diagnostic register */
        ret = 0;
        break;
blueswir1's avatar
blueswir1 committed
965
    case 8: /* User code access, XXX */
966
    default:
blueswir1's avatar
blueswir1 committed
967
        do_unassigned_access(addr, 0, 0, asi);
blueswir1's avatar
blueswir1 committed
968
969
        ret = 0;
        break;
970
    }
971
972
973
    if (sign) {
        switch(size) {
        case 1:
blueswir1's avatar
blueswir1 committed
974
            ret = (int8_t) ret;
blueswir1's avatar
blueswir1 committed
975
            break;
976
        case 2:
blueswir1's avatar
blueswir1 committed
977
978
979
980
            ret = (int16_t) ret;
            break;
        case 4:
            ret = (int32_t) ret;
blueswir1's avatar
blueswir1 committed
981
            break;
982
983
984
985
        default:
            break;
        }
    }
986
#ifdef DEBUG_ASI
blueswir1's avatar
blueswir1 committed
987
    dump_asi("read ", last_addr, asi, size, ret);
988
#endif
blueswir1's avatar
blueswir1 committed
989
    return ret;
990
991
}

blueswir1's avatar
blueswir1 committed
992
void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
993
{
994
    helper_check_align(addr, size - 1);
995
    switch(asi) {
996
    case 2: /* SuperSparc MXCC registers */
blueswir1's avatar
blueswir1 committed
997
        switch (addr) {
998
999
        case 0x01c00000: /* MXCC stream data register 0 */
            if (size == 8)
blueswir1's avatar
blueswir1 committed
1000
                env->mxccdata[0] = val;
1001
            else
blueswir1's avatar
blueswir1 committed
1002
1003
                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
                             size);
1004
1005
1006
            break;
        case 0x01c00008: /* MXCC stream data register 1 */
            if (size == 8)
blueswir1's avatar
blueswir1 committed
1007
                env->mxccdata[1] = val;
1008
            else
blueswir1's avatar
blueswir1 committed
1009
1010
                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
                             size);
1011
1012
1013
            break;
        case 0x01c00010: /* MXCC stream data register 2 */
            if (size == 8)
blueswir1's avatar
blueswir1 committed
1014
                env->mxccdata[2] = val;
1015
            else
blueswir1's avatar
blueswir1 committed
1016
1017
                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
                             size);
1018
1019
1020
            break;
        case 0x01c00018: /* MXCC stream data register 3 */
            if (size == 8)
blueswir1's avatar
blueswir1 committed
1021
                env->mxccdata[3] = val;
1022
            else
blueswir1's avatar
blueswir1 committed
1023
1024
                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
                             size);
1025
1026
1027
            break;
        case 0x01c00100: /* MXCC stream source */
            if (size == 8)
blueswir1's avatar
blueswir1 committed
1028
                env->mxccregs[0] = val;
1029
            else
blueswir1's avatar
blueswir1 committed
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
                             size);
            env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
                                        0);
            env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
                                        8);
            env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
                                        16);
            env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
                                        24);
1040
1041
1042
            break;
        case 0x01c00200: /* MXCC stream destination */
            if (size == 8)
blueswir1's avatar
blueswir1 committed
1043
                env->mxccregs[1] = val;
1044
            else
blueswir1's avatar
blueswir1 committed
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
                             size);
            stq_phys((env->mxccregs[1] & 0xffffffffULL) +  0,
                     env->mxccdata[0]);
            stq_phys((env->mxccregs[1] & 0xffffffffULL) +  8,
                     env->mxccdata[1]);
            stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16,
                     env->mxccdata[2]);
            stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24,
                     env->mxccdata[3]);
1055
1056
1057
            break;
        case 0x01c00a00: /* MXCC control register */
            if (size == 8)
blueswir1's avatar
blueswir1 committed
1058
                env->mxccregs[3] = val;
1059
            else
blueswir1's avatar
blueswir1 committed
1060
1061
                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
                             size);
1062
1063
1064
            break;
        case 0x01c00a04: /* MXCC control register */
            if (size == 4)
1065
                env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL)
blueswir1's avatar
blueswir1 committed
1066
                    | val;
1067
            else
blueswir1's avatar
blueswir1 committed
1068
1069
                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
                             size);
1070
1071
            break;
        case 0x01c00e00: /* MXCC error register  */
1072
            // writing a 1 bit clears the error
1073
            if (size == 8)
blueswir1's avatar
blueswir1 committed
1074
                env->mxccregs[6] &= ~val;
1075
            else
blueswir1's avatar
blueswir1 committed
1076
1077
                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
                             size);
1078
1079
1080
            break;
        case 0x01c00f00: /* MBus port address register */
            if (size == 8)
blueswir1's avatar
blueswir1 committed
1081
                env->mxccregs[7] = val;
1082
            else
blueswir1's avatar
blueswir1 committed
1083
1084
                DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
                             size);
1085
1086
            break;
        default:
blueswir1's avatar
blueswir1 committed
1087
1088
            DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
                         size);
1089
1090
            break;
        }
blueswir1's avatar
blueswir1 committed
1091
1092
        DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %08x\n", asi,
                     size, addr, val);
1093
1094
1095
#ifdef DEBUG_MXCC
        dump_mxcc(env);