Statistics
| Branch: | Revision:

root / target-microblaze / op_helper.c @ 618ba8e6

History | View | Annotate | Download (12.7 kB)

1
/*
2
 *  Microblaze helper routines.
3
 *
4
 *  Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com>.
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

    
20
#include <assert.h>
21
#include "exec.h"
22
#include "helper.h"
23
#include "host-utils.h"
24

    
25
#define D(x)
26

    
27
#if !defined(CONFIG_USER_ONLY)
28
#define MMUSUFFIX _mmu
29
#define SHIFT 0
30
#include "softmmu_template.h"
31
#define SHIFT 1
32
#include "softmmu_template.h"
33
#define SHIFT 2
34
#include "softmmu_template.h"
35
#define SHIFT 3
36
#include "softmmu_template.h"
37

    
38
/* Try to fill the TLB and return an exception if error. If retaddr is
39
   NULL, it means that the function was called in C code (i.e. not
40
   from generated code or from helper.c) */
41
/* XXX: fix it to restore all registers */
42
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
43
{
44
    TranslationBlock *tb;
45
    CPUState *saved_env;
46
    unsigned long pc;
47
    int ret;
48

    
49
    /* XXX: hack to restore env in all cases, even if not called from
50
       generated code */
51
    saved_env = env;
52
    env = cpu_single_env;
53

    
54
    ret = cpu_mb_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
55
    if (unlikely(ret)) {
56
        if (retaddr) {
57
            /* now we have a real cpu fault */
58
            pc = (unsigned long)retaddr;
59
            tb = tb_find_pc(pc);
60
            if (tb) {
61
                /* the PC is inside the translated code. It means that we have
62
                   a virtual CPU fault */
63
                cpu_restore_state(tb, env, pc);
64
            }
65
        }
66
        cpu_loop_exit();
67
    }
68
    env = saved_env;
69
}
70
#endif
71

    
72
void helper_put(uint32_t id, uint32_t ctrl, uint32_t data)
73
{
74
    int test = ctrl & STREAM_TEST;
75
    int atomic = ctrl & STREAM_ATOMIC;
76
    int control = ctrl & STREAM_CONTROL;
77
    int nonblock = ctrl & STREAM_NONBLOCK;
78
    int exception = ctrl & STREAM_EXCEPTION;
79

    
80
    qemu_log("Unhandled stream put to stream-id=%d data=%x %s%s%s%s%s\n",
81
             id, data,
82
             test ? "t" : "",
83
             nonblock ? "n" : "",
84
             exception ? "e" : "",
85
             control ? "c" : "",
86
             atomic ? "a" : "");
87
}
88

    
89
uint32_t helper_get(uint32_t id, uint32_t ctrl)
90
{
91
    int test = ctrl & STREAM_TEST;
92
    int atomic = ctrl & STREAM_ATOMIC;
93
    int control = ctrl & STREAM_CONTROL;
94
    int nonblock = ctrl & STREAM_NONBLOCK;
95
    int exception = ctrl & STREAM_EXCEPTION;
96

    
97
    qemu_log("Unhandled stream get from stream-id=%d %s%s%s%s%s\n",
98
             id,
99
             test ? "t" : "",
100
             nonblock ? "n" : "",
101
             exception ? "e" : "",
102
             control ? "c" : "",
103
             atomic ? "a" : "");
104
    return 0xdead0000 | id;
105
}
106

    
107
void helper_raise_exception(uint32_t index)
108
{
109
    env->exception_index = index;
110
    cpu_loop_exit();
111
}
112

    
113
void helper_debug(void)
114
{
115
    int i;
116

    
117
    qemu_log("PC=%8.8x\n", env->sregs[SR_PC]);
118
    qemu_log("rmsr=%x resr=%x rear=%x debug[%x] imm=%x iflags=%x\n",
119
             env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR],
120
             env->debug, env->imm, env->iflags);
121
    qemu_log("btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
122
             env->btaken, env->btarget,
123
             (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel",
124
             (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel",
125
             (env->sregs[SR_MSR] & MSR_EIP),
126
             (env->sregs[SR_MSR] & MSR_IE));
127
    for (i = 0; i < 32; i++) {
128
        qemu_log("r%2.2d=%8.8x ", i, env->regs[i]);
129
        if ((i + 1) % 4 == 0)
130
            qemu_log("\n");
131
    }
132
    qemu_log("\n\n");
133
}
134

    
135
static inline uint32_t compute_carry(uint32_t a, uint32_t b, uint32_t cin)
136
{
137
    uint32_t cout = 0;
138

    
139
    if ((b == ~0) && cin)
140
        cout = 1;
141
    else if ((~0 - a) < (b + cin))
142
        cout = 1;
143
    return cout;
144
}
145

    
146
uint32_t helper_cmp(uint32_t a, uint32_t b)
147
{
148
    uint32_t t;
149

    
150
    t = b + ~a + 1;
151
    if ((b & 0x80000000) ^ (a & 0x80000000))
152
        t = (t & 0x7fffffff) | (b & 0x80000000);
153
    return t;
154
}
155

    
156
uint32_t helper_cmpu(uint32_t a, uint32_t b)
157
{
158
    uint32_t t;
159

    
160
    t = b + ~a + 1;
161
    if ((b & 0x80000000) ^ (a & 0x80000000))
162
        t = (t & 0x7fffffff) | (a & 0x80000000);
163
    return t;
164
}
165

    
166
uint32_t helper_carry(uint32_t a, uint32_t b, uint32_t cf)
167
{
168
    uint32_t ncf;
169
    ncf = compute_carry(a, b, cf);
170
    return ncf;
171
}
172

    
173
static inline int div_prepare(uint32_t a, uint32_t b)
174
{
175
    if (b == 0) {
176
        env->sregs[SR_MSR] |= MSR_DZ;
177

    
178
        if ((env->sregs[SR_MSR] & MSR_EE)
179
            && !(env->pvr.regs[2] & PVR2_DIV_ZERO_EXC_MASK)) {
180
            env->sregs[SR_ESR] = ESR_EC_DIVZERO;
181
            helper_raise_exception(EXCP_HW_EXCP);
182
        }
183
        return 0;
184
    }
185
    env->sregs[SR_MSR] &= ~MSR_DZ;
186
    return 1;
187
}
188

    
189
uint32_t helper_divs(uint32_t a, uint32_t b)
190
{
191
    if (!div_prepare(a, b))
192
        return 0;
193
    return (int32_t)a / (int32_t)b;
194
}
195

    
196
uint32_t helper_divu(uint32_t a, uint32_t b)
197
{
198
    if (!div_prepare(a, b))
199
        return 0;
200
    return a / b;
201
}
202

    
203
/* raise FPU exception.  */
204
static void raise_fpu_exception(void)
205
{
206
    env->sregs[SR_ESR] = ESR_EC_FPU;
207
    helper_raise_exception(EXCP_HW_EXCP);
208
}
209

    
210
static void update_fpu_flags(int flags)
211
{
212
    int raise = 0;
213

    
214
    if (flags & float_flag_invalid) {
215
        env->sregs[SR_FSR] |= FSR_IO;
216
        raise = 1;
217
    }
218
    if (flags & float_flag_divbyzero) {
219
        env->sregs[SR_FSR] |= FSR_DZ;
220
        raise = 1;
221
    }
222
    if (flags & float_flag_overflow) {
223
        env->sregs[SR_FSR] |= FSR_OF;
224
        raise = 1;
225
    }
226
    if (flags & float_flag_underflow) {
227
        env->sregs[SR_FSR] |= FSR_UF;
228
        raise = 1;
229
    }
230
    if (raise
231
        && (env->pvr.regs[2] & PVR2_FPU_EXC_MASK)
232
        && (env->sregs[SR_MSR] & MSR_EE)) {
233
        raise_fpu_exception();
234
    }
235
}
236

    
237
uint32_t helper_fadd(uint32_t a, uint32_t b)
238
{
239
    CPU_FloatU fd, fa, fb;
240
    int flags;
241

    
242
    set_float_exception_flags(0, &env->fp_status);
243
    fa.l = a;
244
    fb.l = b;
245
    fd.f = float32_add(fa.f, fb.f, &env->fp_status);
246

    
247
    flags = get_float_exception_flags(&env->fp_status);
248
    update_fpu_flags(flags);
249
    return fd.l;
250
}
251

    
252
uint32_t helper_frsub(uint32_t a, uint32_t b)
253
{
254
    CPU_FloatU fd, fa, fb;
255
    int flags;
256

    
257
    set_float_exception_flags(0, &env->fp_status);
258
    fa.l = a;
259
    fb.l = b;
260
    fd.f = float32_sub(fb.f, fa.f, &env->fp_status);
261
    flags = get_float_exception_flags(&env->fp_status);
262
    update_fpu_flags(flags);
263
    return fd.l;
264
}
265

    
266
uint32_t helper_fmul(uint32_t a, uint32_t b)
267
{
268
    CPU_FloatU fd, fa, fb;
269
    int flags;
270

    
271
    set_float_exception_flags(0, &env->fp_status);
272
    fa.l = a;
273
    fb.l = b;
274
    fd.f = float32_mul(fa.f, fb.f, &env->fp_status);
275
    flags = get_float_exception_flags(&env->fp_status);
276
    update_fpu_flags(flags);
277

    
278
    return fd.l;
279
}
280

    
281
uint32_t helper_fdiv(uint32_t a, uint32_t b)
282
{
283
    CPU_FloatU fd, fa, fb;
284
    int flags;
285

    
286
    set_float_exception_flags(0, &env->fp_status);
287
    fa.l = a;
288
    fb.l = b;
289
    fd.f = float32_div(fb.f, fa.f, &env->fp_status);
290
    flags = get_float_exception_flags(&env->fp_status);
291
    update_fpu_flags(flags);
292

    
293
    return fd.l;
294
}
295

    
296
uint32_t helper_fcmp_un(uint32_t a, uint32_t b)
297
{
298
    CPU_FloatU fa, fb;
299
    uint32_t r = 0;
300

    
301
    fa.l = a;
302
    fb.l = b;
303

    
304
    if (float32_is_signaling_nan(fa.f) || float32_is_signaling_nan(fb.f)) {
305
        update_fpu_flags(float_flag_invalid);
306
        r = 1;
307
    }
308

    
309
    if (float32_is_quiet_nan(fa.f) || float32_is_quiet_nan(fb.f)) {
310
        r = 1;
311
    }
312

    
313
    return r;
314
}
315

    
316
uint32_t helper_fcmp_lt(uint32_t a, uint32_t b)
317
{
318
    CPU_FloatU fa, fb;
319
    int r;
320
    int flags;
321

    
322
    set_float_exception_flags(0, &env->fp_status);
323
    fa.l = a;
324
    fb.l = b;
325
    r = float32_lt(fb.f, fa.f, &env->fp_status);
326
    flags = get_float_exception_flags(&env->fp_status);
327
    update_fpu_flags(flags & float_flag_invalid);
328

    
329
    return r;
330
}
331

    
332
uint32_t helper_fcmp_eq(uint32_t a, uint32_t b)
333
{
334
    CPU_FloatU fa, fb;
335
    int flags;
336
    int r;
337

    
338
    set_float_exception_flags(0, &env->fp_status);
339
    fa.l = a;
340
    fb.l = b;
341
    r = float32_eq_quiet(fa.f, fb.f, &env->fp_status);
342
    flags = get_float_exception_flags(&env->fp_status);
343
    update_fpu_flags(flags & float_flag_invalid);
344

    
345
    return r;
346
}
347

    
348
uint32_t helper_fcmp_le(uint32_t a, uint32_t b)
349
{
350
    CPU_FloatU fa, fb;
351
    int flags;
352
    int r;
353

    
354
    fa.l = a;
355
    fb.l = b;
356
    set_float_exception_flags(0, &env->fp_status);
357
    r = float32_le(fa.f, fb.f, &env->fp_status);
358
    flags = get_float_exception_flags(&env->fp_status);
359
    update_fpu_flags(flags & float_flag_invalid);
360

    
361

    
362
    return r;
363
}
364

    
365
uint32_t helper_fcmp_gt(uint32_t a, uint32_t b)
366
{
367
    CPU_FloatU fa, fb;
368
    int flags, r;
369

    
370
    fa.l = a;
371
    fb.l = b;
372
    set_float_exception_flags(0, &env->fp_status);
373
    r = float32_lt(fa.f, fb.f, &env->fp_status);
374
    flags = get_float_exception_flags(&env->fp_status);
375
    update_fpu_flags(flags & float_flag_invalid);
376
    return r;
377
}
378

    
379
uint32_t helper_fcmp_ne(uint32_t a, uint32_t b)
380
{
381
    CPU_FloatU fa, fb;
382
    int flags, r;
383

    
384
    fa.l = a;
385
    fb.l = b;
386
    set_float_exception_flags(0, &env->fp_status);
387
    r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status);
388
    flags = get_float_exception_flags(&env->fp_status);
389
    update_fpu_flags(flags & float_flag_invalid);
390

    
391
    return r;
392
}
393

    
394
uint32_t helper_fcmp_ge(uint32_t a, uint32_t b)
395
{
396
    CPU_FloatU fa, fb;
397
    int flags, r;
398

    
399
    fa.l = a;
400
    fb.l = b;
401
    set_float_exception_flags(0, &env->fp_status);
402
    r = !float32_lt(fa.f, fb.f, &env->fp_status);
403
    flags = get_float_exception_flags(&env->fp_status);
404
    update_fpu_flags(flags & float_flag_invalid);
405

    
406
    return r;
407
}
408

    
409
uint32_t helper_flt(uint32_t a)
410
{
411
    CPU_FloatU fd, fa;
412

    
413
    fa.l = a;
414
    fd.f = int32_to_float32(fa.l, &env->fp_status);
415
    return fd.l;
416
}
417

    
418
uint32_t helper_fint(uint32_t a)
419
{
420
    CPU_FloatU fa;
421
    uint32_t r;
422
    int flags;
423

    
424
    set_float_exception_flags(0, &env->fp_status);
425
    fa.l = a;
426
    r = float32_to_int32(fa.f, &env->fp_status);
427
    flags = get_float_exception_flags(&env->fp_status);
428
    update_fpu_flags(flags);
429

    
430
    return r;
431
}
432

    
433
uint32_t helper_fsqrt(uint32_t a)
434
{
435
    CPU_FloatU fd, fa;
436
    int flags;
437

    
438
    set_float_exception_flags(0, &env->fp_status);
439
    fa.l = a;
440
    fd.l = float32_sqrt(fa.f, &env->fp_status);
441
    flags = get_float_exception_flags(&env->fp_status);
442
    update_fpu_flags(flags);
443

    
444
    return fd.l;
445
}
446

    
447
uint32_t helper_pcmpbf(uint32_t a, uint32_t b)
448
{
449
    unsigned int i;
450
    uint32_t mask = 0xff000000;
451

    
452
    for (i = 0; i < 4; i++) {
453
        if ((a & mask) == (b & mask))
454
            return i + 1;
455
        mask >>= 8;
456
    }
457
    return 0;
458
}
459

    
460
void helper_memalign(uint32_t addr, uint32_t dr, uint32_t wr, uint32_t mask)
461
{
462
    if (addr & mask) {
463
            qemu_log_mask(CPU_LOG_INT,
464
                          "unaligned access addr=%x mask=%x, wr=%d dr=r%d\n",
465
                          addr, mask, wr, dr);
466
            env->sregs[SR_EAR] = addr;
467
            env->sregs[SR_ESR] = ESR_EC_UNALIGNED_DATA | (wr << 10) \
468
                                 | (dr & 31) << 5;
469
            if (mask == 3) {
470
                env->sregs[SR_ESR] |= 1 << 11;
471
            }
472
            if (!(env->sregs[SR_MSR] & MSR_EE)) {
473
                return;
474
            }
475
            helper_raise_exception(EXCP_HW_EXCP);
476
    }
477
}
478

    
479
#if !defined(CONFIG_USER_ONLY)
480
/* Writes/reads to the MMU's special regs end up here.  */
481
uint32_t helper_mmu_read(uint32_t rn)
482
{
483
    return mmu_read(env, rn);
484
}
485

    
486
void helper_mmu_write(uint32_t rn, uint32_t v)
487
{
488
    mmu_write(env, rn, v);
489
}
490

    
491
void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
492
                          int is_asi, int size)
493
{
494
    CPUState *saved_env;
495

    
496
    if (!cpu_single_env) {
497
        /* XXX: ???   */
498
        return;
499
    }
500

    
501
    /* XXX: hack to restore env in all cases, even if not called from
502
       generated code */
503
    saved_env = env;
504
    env = cpu_single_env;
505
    qemu_log_mask(CPU_LOG_INT, "Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n",
506
             addr, is_write, is_exec);
507
    if (!(env->sregs[SR_MSR] & MSR_EE)) {
508
        env = saved_env;
509
        return;
510
    }
511

    
512
    env->sregs[SR_EAR] = addr;
513
    if (is_exec) {
514
        if ((env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) {
515
            env->sregs[SR_ESR] = ESR_EC_INSN_BUS;
516
            helper_raise_exception(EXCP_HW_EXCP);
517
        }
518
    } else {
519
        if ((env->pvr.regs[2] & PVR2_DOPB_BUS_EXC_MASK)) {
520
            env->sregs[SR_ESR] = ESR_EC_DATA_BUS;
521
            helper_raise_exception(EXCP_HW_EXCP);
522
        }
523
    }
524
    env = saved_env;
525
}
526
#endif