Statistics
| Branch: | Revision:

root / target-sh4 / op_helper.c @ 94befa45

History | View | Annotate | Download (14.8 kB)

1
/*
2
 *  SH4 emulation
3
 *
4
 *  Copyright (c) 2005 Samuel Tardieu
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18
 */
19
#include <assert.h>
20
#include <stdlib.h>
21
#include "cpu.h"
22
#include "helper.h"
23

    
24
static inline void cpu_restore_state_from_retaddr(CPUSH4State *env,
25
                                                  uintptr_t retaddr)
26
{
27
    TranslationBlock *tb;
28

    
29
    if (retaddr) {
30
        tb = tb_find_pc(retaddr);
31
        if (tb) {
32
            /* the PC is inside the translated code. It means that we have
33
               a virtual CPU fault */
34
            cpu_restore_state(tb, env, retaddr);
35
        }
36
    }
37
}
38

    
39
#ifndef CONFIG_USER_ONLY
40
#include "softmmu_exec.h"
41

    
42
#define MMUSUFFIX _mmu
43

    
44
#define SHIFT 0
45
#include "softmmu_template.h"
46

    
47
#define SHIFT 1
48
#include "softmmu_template.h"
49

    
50
#define SHIFT 2
51
#include "softmmu_template.h"
52

    
53
#define SHIFT 3
54
#include "softmmu_template.h"
55

    
56
void tlb_fill(CPUSH4State *env, target_ulong addr, int is_write, int mmu_idx,
57
              uintptr_t retaddr)
58
{
59
    int ret;
60

    
61
    ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, mmu_idx);
62
    if (ret) {
63
        /* now we have a real cpu fault */
64
        cpu_restore_state_from_retaddr(env, retaddr);
65
        cpu_loop_exit(env);
66
    }
67
}
68

    
69
#endif
70

    
71
void helper_ldtlb(CPUSH4State *env)
72
{
73
#ifdef CONFIG_USER_ONLY
74
    /* XXXXX */
75
    cpu_abort(env, "Unhandled ldtlb");
76
#else
77
    cpu_load_tlb(env);
78
#endif
79
}
80

    
81
static inline void QEMU_NORETURN raise_exception(CPUSH4State *env, int index,
82
                                                 uintptr_t retaddr)
83
{
84
    env->exception_index = index;
85
    cpu_restore_state_from_retaddr(env, retaddr);
86
    cpu_loop_exit(env);
87
}
88

    
89
void helper_raise_illegal_instruction(CPUSH4State *env)
90
{
91
    raise_exception(env, 0x180, 0);
92
}
93

    
94
void helper_raise_slot_illegal_instruction(CPUSH4State *env)
95
{
96
    raise_exception(env, 0x1a0, 0);
97
}
98

    
99
void helper_raise_fpu_disable(CPUSH4State *env)
100
{
101
    raise_exception(env, 0x800, 0);
102
}
103

    
104
void helper_raise_slot_fpu_disable(CPUSH4State *env)
105
{
106
    raise_exception(env, 0x820, 0);
107
}
108

    
109
void helper_debug(CPUSH4State *env)
110
{
111
    raise_exception(env, EXCP_DEBUG, 0);
112
}
113

    
114
void helper_sleep(CPUSH4State *env)
115
{
116
    env->halted = 1;
117
    env->in_sleep = 1;
118
    raise_exception(env, EXCP_HLT, 0);
119
}
120

    
121
void helper_trapa(CPUSH4State *env, uint32_t tra)
122
{
123
    env->tra = tra << 2;
124
    raise_exception(env, 0x160, 0);
125
}
126

    
127
void helper_movcal(CPUSH4State *env, uint32_t address, uint32_t value)
128
{
129
    if (cpu_sh4_is_cached (env, address))
130
    {
131
        memory_content *r = malloc (sizeof(memory_content));
132
        r->address = address;
133
        r->value = value;
134
        r->next = NULL;
135

    
136
        *(env->movcal_backup_tail) = r;
137
        env->movcal_backup_tail = &(r->next);
138
    }
139
}
140

    
141
void helper_discard_movcal_backup(CPUSH4State *env)
142
{
143
    memory_content *current = env->movcal_backup;
144

    
145
    while(current)
146
    {
147
        memory_content *next = current->next;
148
        free (current);
149
        env->movcal_backup = current = next;
150
        if (current == NULL)
151
            env->movcal_backup_tail = &(env->movcal_backup);
152
    } 
153
}
154

    
155
void helper_ocbi(CPUSH4State *env, uint32_t address)
156
{
157
    memory_content **current = &(env->movcal_backup);
158
    while (*current)
159
    {
160
        uint32_t a = (*current)->address;
161
        if ((a & ~0x1F) == (address & ~0x1F))
162
        {
163
            memory_content *next = (*current)->next;
164
            cpu_stl_data(env, a, (*current)->value);
165
            
166
            if (next == NULL)
167
            {
168
                env->movcal_backup_tail = current;
169
            }
170

    
171
            free (*current);
172
            *current = next;
173
            break;
174
        }
175
    }
176
}
177

    
178
#define T (env->sr & SR_T)
179
#define Q (env->sr & SR_Q ? 1 : 0)
180
#define M (env->sr & SR_M ? 1 : 0)
181
#define SETT env->sr |= SR_T
182
#define CLRT env->sr &= ~SR_T
183
#define SETQ env->sr |= SR_Q
184
#define CLRQ env->sr &= ~SR_Q
185
#define SETM env->sr |= SR_M
186
#define CLRM env->sr &= ~SR_M
187

    
188
uint32_t helper_div1(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
189
{
190
    uint32_t tmp0, tmp2;
191
    uint8_t old_q, tmp1 = 0xff;
192

    
193
    //printf("div1 arg0=0x%08x arg1=0x%08x M=%d Q=%d T=%d\n", arg0, arg1, M, Q, T);
194
    old_q = Q;
195
    if ((0x80000000 & arg1) != 0)
196
        SETQ;
197
    else
198
        CLRQ;
199
    tmp2 = arg0;
200
    arg1 <<= 1;
201
    arg1 |= T;
202
    switch (old_q) {
203
    case 0:
204
        switch (M) {
205
        case 0:
206
            tmp0 = arg1;
207
            arg1 -= tmp2;
208
            tmp1 = arg1 > tmp0;
209
            switch (Q) {
210
            case 0:
211
                if (tmp1)
212
                    SETQ;
213
                else
214
                    CLRQ;
215
                break;
216
            case 1:
217
                if (tmp1 == 0)
218
                    SETQ;
219
                else
220
                    CLRQ;
221
                break;
222
            }
223
            break;
224
        case 1:
225
            tmp0 = arg1;
226
            arg1 += tmp2;
227
            tmp1 = arg1 < tmp0;
228
            switch (Q) {
229
            case 0:
230
                if (tmp1 == 0)
231
                    SETQ;
232
                else
233
                    CLRQ;
234
                break;
235
            case 1:
236
                if (tmp1)
237
                    SETQ;
238
                else
239
                    CLRQ;
240
                break;
241
            }
242
            break;
243
        }
244
        break;
245
    case 1:
246
        switch (M) {
247
        case 0:
248
            tmp0 = arg1;
249
            arg1 += tmp2;
250
            tmp1 = arg1 < tmp0;
251
            switch (Q) {
252
            case 0:
253
                if (tmp1)
254
                    SETQ;
255
                else
256
                    CLRQ;
257
                break;
258
            case 1:
259
                if (tmp1 == 0)
260
                    SETQ;
261
                else
262
                    CLRQ;
263
                break;
264
            }
265
            break;
266
        case 1:
267
            tmp0 = arg1;
268
            arg1 -= tmp2;
269
            tmp1 = arg1 > tmp0;
270
            switch (Q) {
271
            case 0:
272
                if (tmp1 == 0)
273
                    SETQ;
274
                else
275
                    CLRQ;
276
                break;
277
            case 1:
278
                if (tmp1)
279
                    SETQ;
280
                else
281
                    CLRQ;
282
                break;
283
            }
284
            break;
285
        }
286
        break;
287
    }
288
    if (Q == M)
289
        SETT;
290
    else
291
        CLRT;
292
    //printf("Output: arg1=0x%08x M=%d Q=%d T=%d\n", arg1, M, Q, T);
293
    return arg1;
294
}
295

    
296
void helper_macl(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
297
{
298
    int64_t res;
299

    
300
    res = ((uint64_t) env->mach << 32) | env->macl;
301
    res += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1;
302
    env->mach = (res >> 32) & 0xffffffff;
303
    env->macl = res & 0xffffffff;
304
    if (env->sr & SR_S) {
305
        if (res < 0)
306
            env->mach |= 0xffff0000;
307
        else
308
            env->mach &= 0x00007fff;
309
    }
310
}
311

    
312
void helper_macw(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
313
{
314
    int64_t res;
315

    
316
    res = ((uint64_t) env->mach << 32) | env->macl;
317
    res += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1;
318
    env->mach = (res >> 32) & 0xffffffff;
319
    env->macl = res & 0xffffffff;
320
    if (env->sr & SR_S) {
321
        if (res < -0x80000000) {
322
            env->mach = 1;
323
            env->macl = 0x80000000;
324
        } else if (res > 0x000000007fffffff) {
325
            env->mach = 1;
326
            env->macl = 0x7fffffff;
327
        }
328
    }
329
}
330

    
331
static inline void set_t(CPUSH4State *env)
332
{
333
    env->sr |= SR_T;
334
}
335

    
336
static inline void clr_t(CPUSH4State *env)
337
{
338
    env->sr &= ~SR_T;
339
}
340

    
341
void helper_ld_fpscr(CPUSH4State *env, uint32_t val)
342
{
343
    env->fpscr = val & FPSCR_MASK;
344
    if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) {
345
        set_float_rounding_mode(float_round_to_zero, &env->fp_status);
346
    } else {
347
        set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
348
    }
349
    set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status);
350
}
351

    
352
static void update_fpscr(CPUSH4State *env, uintptr_t retaddr)
353
{
354
    int xcpt, cause, enable;
355

    
356
    xcpt = get_float_exception_flags(&env->fp_status);
357

    
358
    /* Clear the flag entries */
359
    env->fpscr &= ~FPSCR_FLAG_MASK;
360

    
361
    if (unlikely(xcpt)) {
362
        if (xcpt & float_flag_invalid) {
363
            env->fpscr |= FPSCR_FLAG_V;
364
        }
365
        if (xcpt & float_flag_divbyzero) {
366
            env->fpscr |= FPSCR_FLAG_Z;
367
        }
368
        if (xcpt & float_flag_overflow) {
369
            env->fpscr |= FPSCR_FLAG_O;
370
        }
371
        if (xcpt & float_flag_underflow) {
372
            env->fpscr |= FPSCR_FLAG_U;
373
        }
374
        if (xcpt & float_flag_inexact) {
375
            env->fpscr |= FPSCR_FLAG_I;
376
        }
377

    
378
        /* Accumulate in cause entries */
379
        env->fpscr |= (env->fpscr & FPSCR_FLAG_MASK)
380
                      << (FPSCR_CAUSE_SHIFT - FPSCR_FLAG_SHIFT);
381

    
382
        /* Generate an exception if enabled */
383
        cause = (env->fpscr & FPSCR_CAUSE_MASK) >> FPSCR_CAUSE_SHIFT;
384
        enable = (env->fpscr & FPSCR_ENABLE_MASK) >> FPSCR_ENABLE_SHIFT;
385
        if (cause & enable) {
386
            raise_exception(env, 0x120, retaddr);
387
        }
388
    }
389
}
390

    
391
float32 helper_fabs_FT(float32 t0)
392
{
393
    return float32_abs(t0);
394
}
395

    
396
float64 helper_fabs_DT(float64 t0)
397
{
398
    return float64_abs(t0);
399
}
400

    
401
float32 helper_fadd_FT(CPUSH4State *env, float32 t0, float32 t1)
402
{
403
    set_float_exception_flags(0, &env->fp_status);
404
    t0 = float32_add(t0, t1, &env->fp_status);
405
    update_fpscr(env, GETPC());
406
    return t0;
407
}
408

    
409
float64 helper_fadd_DT(CPUSH4State *env, float64 t0, float64 t1)
410
{
411
    set_float_exception_flags(0, &env->fp_status);
412
    t0 = float64_add(t0, t1, &env->fp_status);
413
    update_fpscr(env, GETPC());
414
    return t0;
415
}
416

    
417
void helper_fcmp_eq_FT(CPUSH4State *env, float32 t0, float32 t1)
418
{
419
    int relation;
420

    
421
    set_float_exception_flags(0, &env->fp_status);
422
    relation = float32_compare(t0, t1, &env->fp_status);
423
    if (unlikely(relation == float_relation_unordered)) {
424
        update_fpscr(env, GETPC());
425
    } else if (relation == float_relation_equal) {
426
        set_t(env);
427
    } else {
428
        clr_t(env);
429
    }
430
}
431

    
432
void helper_fcmp_eq_DT(CPUSH4State *env, float64 t0, float64 t1)
433
{
434
    int relation;
435

    
436
    set_float_exception_flags(0, &env->fp_status);
437
    relation = float64_compare(t0, t1, &env->fp_status);
438
    if (unlikely(relation == float_relation_unordered)) {
439
        update_fpscr(env, GETPC());
440
    } else if (relation == float_relation_equal) {
441
        set_t(env);
442
    } else {
443
        clr_t(env);
444
    }
445
}
446

    
447
void helper_fcmp_gt_FT(CPUSH4State *env, float32 t0, float32 t1)
448
{
449
    int relation;
450

    
451
    set_float_exception_flags(0, &env->fp_status);
452
    relation = float32_compare(t0, t1, &env->fp_status);
453
    if (unlikely(relation == float_relation_unordered)) {
454
        update_fpscr(env, GETPC());
455
    } else if (relation == float_relation_greater) {
456
        set_t(env);
457
    } else {
458
        clr_t(env);
459
    }
460
}
461

    
462
void helper_fcmp_gt_DT(CPUSH4State *env, float64 t0, float64 t1)
463
{
464
    int relation;
465

    
466
    set_float_exception_flags(0, &env->fp_status);
467
    relation = float64_compare(t0, t1, &env->fp_status);
468
    if (unlikely(relation == float_relation_unordered)) {
469
        update_fpscr(env, GETPC());
470
    } else if (relation == float_relation_greater) {
471
        set_t(env);
472
    } else {
473
        clr_t(env);
474
    }
475
}
476

    
477
float64 helper_fcnvsd_FT_DT(CPUSH4State *env, float32 t0)
478
{
479
    float64 ret;
480
    set_float_exception_flags(0, &env->fp_status);
481
    ret = float32_to_float64(t0, &env->fp_status);
482
    update_fpscr(env, GETPC());
483
    return ret;
484
}
485

    
486
float32 helper_fcnvds_DT_FT(CPUSH4State *env, float64 t0)
487
{
488
    float32 ret;
489
    set_float_exception_flags(0, &env->fp_status);
490
    ret = float64_to_float32(t0, &env->fp_status);
491
    update_fpscr(env, GETPC());
492
    return ret;
493
}
494

    
495
float32 helper_fdiv_FT(CPUSH4State *env, float32 t0, float32 t1)
496
{
497
    set_float_exception_flags(0, &env->fp_status);
498
    t0 = float32_div(t0, t1, &env->fp_status);
499
    update_fpscr(env, GETPC());
500
    return t0;
501
}
502

    
503
float64 helper_fdiv_DT(CPUSH4State *env, float64 t0, float64 t1)
504
{
505
    set_float_exception_flags(0, &env->fp_status);
506
    t0 = float64_div(t0, t1, &env->fp_status);
507
    update_fpscr(env, GETPC());
508
    return t0;
509
}
510

    
511
float32 helper_float_FT(CPUSH4State *env, uint32_t t0)
512
{
513
    float32 ret;
514
    set_float_exception_flags(0, &env->fp_status);
515
    ret = int32_to_float32(t0, &env->fp_status);
516
    update_fpscr(env, GETPC());
517
    return ret;
518
}
519

    
520
float64 helper_float_DT(CPUSH4State *env, uint32_t t0)
521
{
522
    float64 ret;
523
    set_float_exception_flags(0, &env->fp_status);
524
    ret = int32_to_float64(t0, &env->fp_status);
525
    update_fpscr(env, GETPC());
526
    return ret;
527
}
528

    
529
float32 helper_fmac_FT(CPUSH4State *env, float32 t0, float32 t1, float32 t2)
530
{
531
    set_float_exception_flags(0, &env->fp_status);
532
    t0 = float32_muladd(t0, t1, t2, 0, &env->fp_status);
533
    update_fpscr(env, GETPC());
534
    return t0;
535
}
536

    
537
float32 helper_fmul_FT(CPUSH4State *env, float32 t0, float32 t1)
538
{
539
    set_float_exception_flags(0, &env->fp_status);
540
    t0 = float32_mul(t0, t1, &env->fp_status);
541
    update_fpscr(env, GETPC());
542
    return t0;
543
}
544

    
545
float64 helper_fmul_DT(CPUSH4State *env, float64 t0, float64 t1)
546
{
547
    set_float_exception_flags(0, &env->fp_status);
548
    t0 = float64_mul(t0, t1, &env->fp_status);
549
    update_fpscr(env, GETPC());
550
    return t0;
551
}
552

    
553
float32 helper_fneg_T(float32 t0)
554
{
555
    return float32_chs(t0);
556
}
557

    
558
float32 helper_fsqrt_FT(CPUSH4State *env, float32 t0)
559
{
560
    set_float_exception_flags(0, &env->fp_status);
561
    t0 = float32_sqrt(t0, &env->fp_status);
562
    update_fpscr(env, GETPC());
563
    return t0;
564
}
565

    
566
float64 helper_fsqrt_DT(CPUSH4State *env, float64 t0)
567
{
568
    set_float_exception_flags(0, &env->fp_status);
569
    t0 = float64_sqrt(t0, &env->fp_status);
570
    update_fpscr(env, GETPC());
571
    return t0;
572
}
573

    
574
float32 helper_fsub_FT(CPUSH4State *env, float32 t0, float32 t1)
575
{
576
    set_float_exception_flags(0, &env->fp_status);
577
    t0 = float32_sub(t0, t1, &env->fp_status);
578
    update_fpscr(env, GETPC());
579
    return t0;
580
}
581

    
582
float64 helper_fsub_DT(CPUSH4State *env, float64 t0, float64 t1)
583
{
584
    set_float_exception_flags(0, &env->fp_status);
585
    t0 = float64_sub(t0, t1, &env->fp_status);
586
    update_fpscr(env, GETPC());
587
    return t0;
588
}
589

    
590
uint32_t helper_ftrc_FT(CPUSH4State *env, float32 t0)
591
{
592
    uint32_t ret;
593
    set_float_exception_flags(0, &env->fp_status);
594
    ret = float32_to_int32_round_to_zero(t0, &env->fp_status);
595
    update_fpscr(env, GETPC());
596
    return ret;
597
}
598

    
599
uint32_t helper_ftrc_DT(CPUSH4State *env, float64 t0)
600
{
601
    uint32_t ret;
602
    set_float_exception_flags(0, &env->fp_status);
603
    ret = float64_to_int32_round_to_zero(t0, &env->fp_status);
604
    update_fpscr(env, GETPC());
605
    return ret;
606
}
607

    
608
void helper_fipr(CPUSH4State *env, uint32_t m, uint32_t n)
609
{
610
    int bank, i;
611
    float32 r, p;
612

    
613
    bank = (env->sr & FPSCR_FR) ? 16 : 0;
614
    r = float32_zero;
615
    set_float_exception_flags(0, &env->fp_status);
616

    
617
    for (i = 0 ; i < 4 ; i++) {
618
        p = float32_mul(env->fregs[bank + m + i],
619
                        env->fregs[bank + n + i],
620
                        &env->fp_status);
621
        r = float32_add(r, p, &env->fp_status);
622
    }
623
    update_fpscr(env, GETPC());
624

    
625
    env->fregs[bank + n + 3] = r;
626
}
627

    
628
void helper_ftrv(CPUSH4State *env, uint32_t n)
629
{
630
    int bank_matrix, bank_vector;
631
    int i, j;
632
    float32 r[4];
633
    float32 p;
634

    
635
    bank_matrix = (env->sr & FPSCR_FR) ? 0 : 16;
636
    bank_vector = (env->sr & FPSCR_FR) ? 16 : 0;
637
    set_float_exception_flags(0, &env->fp_status);
638
    for (i = 0 ; i < 4 ; i++) {
639
        r[i] = float32_zero;
640
        for (j = 0 ; j < 4 ; j++) {
641
            p = float32_mul(env->fregs[bank_matrix + 4 * j + i],
642
                            env->fregs[bank_vector + j],
643
                            &env->fp_status);
644
            r[i] = float32_add(r[i], p, &env->fp_status);
645
        }
646
    }
647
    update_fpscr(env, GETPC());
648

    
649
    for (i = 0 ; i < 4 ; i++) {
650
        env->fregs[bank_vector + i] = r[i];
651
    }
652
}