Statistics
| Branch: | Revision:

root / target-sh4 / op_helper.c @ a8aec295

History | View | Annotate | Download (14.5 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
#ifndef CONFIG_USER_ONLY
25
#include "exec/softmmu_exec.h"
26

    
27
#define MMUSUFFIX _mmu
28

    
29
#define SHIFT 0
30
#include "exec/softmmu_template.h"
31

    
32
#define SHIFT 1
33
#include "exec/softmmu_template.h"
34

    
35
#define SHIFT 2
36
#include "exec/softmmu_template.h"
37

    
38
#define SHIFT 3
39
#include "exec/softmmu_template.h"
40

    
41
void tlb_fill(CPUSH4State *env, target_ulong addr, int is_write, int mmu_idx,
42
              uintptr_t retaddr)
43
{
44
    int ret;
45

    
46
    ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, mmu_idx);
47
    if (ret) {
48
        /* now we have a real cpu fault */
49
        if (retaddr) {
50
            cpu_restore_state(env, retaddr);
51
        }
52
        cpu_loop_exit(env);
53
    }
54
}
55

    
56
#endif
57

    
58
void helper_ldtlb(CPUSH4State *env)
59
{
60
#ifdef CONFIG_USER_ONLY
61
    /* XXXXX */
62
    cpu_abort(env, "Unhandled ldtlb");
63
#else
64
    cpu_load_tlb(env);
65
#endif
66
}
67

    
68
static inline void QEMU_NORETURN raise_exception(CPUSH4State *env, int index,
69
                                                 uintptr_t retaddr)
70
{
71
    env->exception_index = index;
72
    if (retaddr) {
73
        cpu_restore_state(env, retaddr);
74
    }
75
    cpu_loop_exit(env);
76
}
77

    
78
void helper_raise_illegal_instruction(CPUSH4State *env)
79
{
80
    raise_exception(env, 0x180, 0);
81
}
82

    
83
void helper_raise_slot_illegal_instruction(CPUSH4State *env)
84
{
85
    raise_exception(env, 0x1a0, 0);
86
}
87

    
88
void helper_raise_fpu_disable(CPUSH4State *env)
89
{
90
    raise_exception(env, 0x800, 0);
91
}
92

    
93
void helper_raise_slot_fpu_disable(CPUSH4State *env)
94
{
95
    raise_exception(env, 0x820, 0);
96
}
97

    
98
void helper_debug(CPUSH4State *env)
99
{
100
    raise_exception(env, EXCP_DEBUG, 0);
101
}
102

    
103
void helper_sleep(CPUSH4State *env)
104
{
105
    CPUState *cs = CPU(sh_env_get_cpu(env));
106

    
107
    cs->halted = 1;
108
    env->in_sleep = 1;
109
    raise_exception(env, EXCP_HLT, 0);
110
}
111

    
112
void helper_trapa(CPUSH4State *env, uint32_t tra)
113
{
114
    env->tra = tra << 2;
115
    raise_exception(env, 0x160, 0);
116
}
117

    
118
void helper_movcal(CPUSH4State *env, uint32_t address, uint32_t value)
119
{
120
    if (cpu_sh4_is_cached (env, address))
121
    {
122
        memory_content *r = malloc (sizeof(memory_content));
123
        r->address = address;
124
        r->value = value;
125
        r->next = NULL;
126

    
127
        *(env->movcal_backup_tail) = r;
128
        env->movcal_backup_tail = &(r->next);
129
    }
130
}
131

    
132
void helper_discard_movcal_backup(CPUSH4State *env)
133
{
134
    memory_content *current = env->movcal_backup;
135

    
136
    while(current)
137
    {
138
        memory_content *next = current->next;
139
        free (current);
140
        env->movcal_backup = current = next;
141
        if (current == NULL)
142
            env->movcal_backup_tail = &(env->movcal_backup);
143
    } 
144
}
145

    
146
void helper_ocbi(CPUSH4State *env, uint32_t address)
147
{
148
    memory_content **current = &(env->movcal_backup);
149
    while (*current)
150
    {
151
        uint32_t a = (*current)->address;
152
        if ((a & ~0x1F) == (address & ~0x1F))
153
        {
154
            memory_content *next = (*current)->next;
155
            cpu_stl_data(env, a, (*current)->value);
156
            
157
            if (next == NULL)
158
            {
159
                env->movcal_backup_tail = current;
160
            }
161

    
162
            free (*current);
163
            *current = next;
164
            break;
165
        }
166
    }
167
}
168

    
169
#define T (env->sr & SR_T)
170
#define Q (env->sr & SR_Q ? 1 : 0)
171
#define M (env->sr & SR_M ? 1 : 0)
172
#define SETT env->sr |= SR_T
173
#define CLRT env->sr &= ~SR_T
174
#define SETQ env->sr |= SR_Q
175
#define CLRQ env->sr &= ~SR_Q
176
#define SETM env->sr |= SR_M
177
#define CLRM env->sr &= ~SR_M
178

    
179
uint32_t helper_div1(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
180
{
181
    uint32_t tmp0, tmp2;
182
    uint8_t old_q, tmp1 = 0xff;
183

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

    
287
void helper_macl(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
288
{
289
    int64_t res;
290

    
291
    res = ((uint64_t) env->mach << 32) | env->macl;
292
    res += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1;
293
    env->mach = (res >> 32) & 0xffffffff;
294
    env->macl = res & 0xffffffff;
295
    if (env->sr & SR_S) {
296
        if (res < 0)
297
            env->mach |= 0xffff0000;
298
        else
299
            env->mach &= 0x00007fff;
300
    }
301
}
302

    
303
void helper_macw(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
304
{
305
    int64_t res;
306

    
307
    res = ((uint64_t) env->mach << 32) | env->macl;
308
    res += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1;
309
    env->mach = (res >> 32) & 0xffffffff;
310
    env->macl = res & 0xffffffff;
311
    if (env->sr & SR_S) {
312
        if (res < -0x80000000) {
313
            env->mach = 1;
314
            env->macl = 0x80000000;
315
        } else if (res > 0x000000007fffffff) {
316
            env->mach = 1;
317
            env->macl = 0x7fffffff;
318
        }
319
    }
320
}
321

    
322
static inline void set_t(CPUSH4State *env)
323
{
324
    env->sr |= SR_T;
325
}
326

    
327
static inline void clr_t(CPUSH4State *env)
328
{
329
    env->sr &= ~SR_T;
330
}
331

    
332
void helper_ld_fpscr(CPUSH4State *env, uint32_t val)
333
{
334
    env->fpscr = val & FPSCR_MASK;
335
    if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) {
336
        set_float_rounding_mode(float_round_to_zero, &env->fp_status);
337
    } else {
338
        set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
339
    }
340
    set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status);
341
}
342

    
343
static void update_fpscr(CPUSH4State *env, uintptr_t retaddr)
344
{
345
    int xcpt, cause, enable;
346

    
347
    xcpt = get_float_exception_flags(&env->fp_status);
348

    
349
    /* Clear the flag entries */
350
    env->fpscr &= ~FPSCR_FLAG_MASK;
351

    
352
    if (unlikely(xcpt)) {
353
        if (xcpt & float_flag_invalid) {
354
            env->fpscr |= FPSCR_FLAG_V;
355
        }
356
        if (xcpt & float_flag_divbyzero) {
357
            env->fpscr |= FPSCR_FLAG_Z;
358
        }
359
        if (xcpt & float_flag_overflow) {
360
            env->fpscr |= FPSCR_FLAG_O;
361
        }
362
        if (xcpt & float_flag_underflow) {
363
            env->fpscr |= FPSCR_FLAG_U;
364
        }
365
        if (xcpt & float_flag_inexact) {
366
            env->fpscr |= FPSCR_FLAG_I;
367
        }
368

    
369
        /* Accumulate in cause entries */
370
        env->fpscr |= (env->fpscr & FPSCR_FLAG_MASK)
371
                      << (FPSCR_CAUSE_SHIFT - FPSCR_FLAG_SHIFT);
372

    
373
        /* Generate an exception if enabled */
374
        cause = (env->fpscr & FPSCR_CAUSE_MASK) >> FPSCR_CAUSE_SHIFT;
375
        enable = (env->fpscr & FPSCR_ENABLE_MASK) >> FPSCR_ENABLE_SHIFT;
376
        if (cause & enable) {
377
            raise_exception(env, 0x120, retaddr);
378
        }
379
    }
380
}
381

    
382
float32 helper_fabs_FT(float32 t0)
383
{
384
    return float32_abs(t0);
385
}
386

    
387
float64 helper_fabs_DT(float64 t0)
388
{
389
    return float64_abs(t0);
390
}
391

    
392
float32 helper_fadd_FT(CPUSH4State *env, float32 t0, float32 t1)
393
{
394
    set_float_exception_flags(0, &env->fp_status);
395
    t0 = float32_add(t0, t1, &env->fp_status);
396
    update_fpscr(env, GETPC());
397
    return t0;
398
}
399

    
400
float64 helper_fadd_DT(CPUSH4State *env, float64 t0, float64 t1)
401
{
402
    set_float_exception_flags(0, &env->fp_status);
403
    t0 = float64_add(t0, t1, &env->fp_status);
404
    update_fpscr(env, GETPC());
405
    return t0;
406
}
407

    
408
void helper_fcmp_eq_FT(CPUSH4State *env, float32 t0, float32 t1)
409
{
410
    int relation;
411

    
412
    set_float_exception_flags(0, &env->fp_status);
413
    relation = float32_compare(t0, t1, &env->fp_status);
414
    if (unlikely(relation == float_relation_unordered)) {
415
        update_fpscr(env, GETPC());
416
    } else if (relation == float_relation_equal) {
417
        set_t(env);
418
    } else {
419
        clr_t(env);
420
    }
421
}
422

    
423
void helper_fcmp_eq_DT(CPUSH4State *env, float64 t0, float64 t1)
424
{
425
    int relation;
426

    
427
    set_float_exception_flags(0, &env->fp_status);
428
    relation = float64_compare(t0, t1, &env->fp_status);
429
    if (unlikely(relation == float_relation_unordered)) {
430
        update_fpscr(env, GETPC());
431
    } else if (relation == float_relation_equal) {
432
        set_t(env);
433
    } else {
434
        clr_t(env);
435
    }
436
}
437

    
438
void helper_fcmp_gt_FT(CPUSH4State *env, float32 t0, float32 t1)
439
{
440
    int relation;
441

    
442
    set_float_exception_flags(0, &env->fp_status);
443
    relation = float32_compare(t0, t1, &env->fp_status);
444
    if (unlikely(relation == float_relation_unordered)) {
445
        update_fpscr(env, GETPC());
446
    } else if (relation == float_relation_greater) {
447
        set_t(env);
448
    } else {
449
        clr_t(env);
450
    }
451
}
452

    
453
void helper_fcmp_gt_DT(CPUSH4State *env, float64 t0, float64 t1)
454
{
455
    int relation;
456

    
457
    set_float_exception_flags(0, &env->fp_status);
458
    relation = float64_compare(t0, t1, &env->fp_status);
459
    if (unlikely(relation == float_relation_unordered)) {
460
        update_fpscr(env, GETPC());
461
    } else if (relation == float_relation_greater) {
462
        set_t(env);
463
    } else {
464
        clr_t(env);
465
    }
466
}
467

    
468
float64 helper_fcnvsd_FT_DT(CPUSH4State *env, float32 t0)
469
{
470
    float64 ret;
471
    set_float_exception_flags(0, &env->fp_status);
472
    ret = float32_to_float64(t0, &env->fp_status);
473
    update_fpscr(env, GETPC());
474
    return ret;
475
}
476

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

    
486
float32 helper_fdiv_FT(CPUSH4State *env, float32 t0, float32 t1)
487
{
488
    set_float_exception_flags(0, &env->fp_status);
489
    t0 = float32_div(t0, t1, &env->fp_status);
490
    update_fpscr(env, GETPC());
491
    return t0;
492
}
493

    
494
float64 helper_fdiv_DT(CPUSH4State *env, float64 t0, float64 t1)
495
{
496
    set_float_exception_flags(0, &env->fp_status);
497
    t0 = float64_div(t0, t1, &env->fp_status);
498
    update_fpscr(env, GETPC());
499
    return t0;
500
}
501

    
502
float32 helper_float_FT(CPUSH4State *env, uint32_t t0)
503
{
504
    float32 ret;
505
    set_float_exception_flags(0, &env->fp_status);
506
    ret = int32_to_float32(t0, &env->fp_status);
507
    update_fpscr(env, GETPC());
508
    return ret;
509
}
510

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

    
520
float32 helper_fmac_FT(CPUSH4State *env, float32 t0, float32 t1, float32 t2)
521
{
522
    set_float_exception_flags(0, &env->fp_status);
523
    t0 = float32_muladd(t0, t1, t2, 0, &env->fp_status);
524
    update_fpscr(env, GETPC());
525
    return t0;
526
}
527

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

    
536
float64 helper_fmul_DT(CPUSH4State *env, float64 t0, float64 t1)
537
{
538
    set_float_exception_flags(0, &env->fp_status);
539
    t0 = float64_mul(t0, t1, &env->fp_status);
540
    update_fpscr(env, GETPC());
541
    return t0;
542
}
543

    
544
float32 helper_fneg_T(float32 t0)
545
{
546
    return float32_chs(t0);
547
}
548

    
549
float32 helper_fsqrt_FT(CPUSH4State *env, float32 t0)
550
{
551
    set_float_exception_flags(0, &env->fp_status);
552
    t0 = float32_sqrt(t0, &env->fp_status);
553
    update_fpscr(env, GETPC());
554
    return t0;
555
}
556

    
557
float64 helper_fsqrt_DT(CPUSH4State *env, float64 t0)
558
{
559
    set_float_exception_flags(0, &env->fp_status);
560
    t0 = float64_sqrt(t0, &env->fp_status);
561
    update_fpscr(env, GETPC());
562
    return t0;
563
}
564

    
565
float32 helper_fsub_FT(CPUSH4State *env, float32 t0, float32 t1)
566
{
567
    set_float_exception_flags(0, &env->fp_status);
568
    t0 = float32_sub(t0, t1, &env->fp_status);
569
    update_fpscr(env, GETPC());
570
    return t0;
571
}
572

    
573
float64 helper_fsub_DT(CPUSH4State *env, float64 t0, float64 t1)
574
{
575
    set_float_exception_flags(0, &env->fp_status);
576
    t0 = float64_sub(t0, t1, &env->fp_status);
577
    update_fpscr(env, GETPC());
578
    return t0;
579
}
580

    
581
uint32_t helper_ftrc_FT(CPUSH4State *env, float32 t0)
582
{
583
    uint32_t ret;
584
    set_float_exception_flags(0, &env->fp_status);
585
    ret = float32_to_int32_round_to_zero(t0, &env->fp_status);
586
    update_fpscr(env, GETPC());
587
    return ret;
588
}
589

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

    
599
void helper_fipr(CPUSH4State *env, uint32_t m, uint32_t n)
600
{
601
    int bank, i;
602
    float32 r, p;
603

    
604
    bank = (env->sr & FPSCR_FR) ? 16 : 0;
605
    r = float32_zero;
606
    set_float_exception_flags(0, &env->fp_status);
607

    
608
    for (i = 0 ; i < 4 ; i++) {
609
        p = float32_mul(env->fregs[bank + m + i],
610
                        env->fregs[bank + n + i],
611
                        &env->fp_status);
612
        r = float32_add(r, p, &env->fp_status);
613
    }
614
    update_fpscr(env, GETPC());
615

    
616
    env->fregs[bank + n + 3] = r;
617
}
618

    
619
void helper_ftrv(CPUSH4State *env, uint32_t n)
620
{
621
    int bank_matrix, bank_vector;
622
    int i, j;
623
    float32 r[4];
624
    float32 p;
625

    
626
    bank_matrix = (env->sr & FPSCR_FR) ? 0 : 16;
627
    bank_vector = (env->sr & FPSCR_FR) ? 16 : 0;
628
    set_float_exception_flags(0, &env->fp_status);
629
    for (i = 0 ; i < 4 ; i++) {
630
        r[i] = float32_zero;
631
        for (j = 0 ; j < 4 ; j++) {
632
            p = float32_mul(env->fregs[bank_matrix + 4 * j + i],
633
                            env->fregs[bank_vector + j],
634
                            &env->fp_status);
635
            r[i] = float32_add(r[i], p, &env->fp_status);
636
        }
637
    }
638
    update_fpscr(env, GETPC());
639

    
640
    for (i = 0 ; i < 4 ; i++) {
641
        env->fregs[bank_vector + i] = r[i];
642
    }
643
}