~pmdj/ubuntu/trusty/qemu/2.9+applesmc+fadtv3

« back to all changes in this revision

Viewing changes to target/microblaze/op_helper.c

  • Committer: Phil Dennis-Jordan
  • Date: 2017-07-21 08:03:43 UTC
  • mfrom: (1.1.1)
  • Revision ID: phil@philjordan.eu-20170721080343-2yr2vdj7713czahv
New upstream release 2.9.0.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Microblaze helper routines.
 
3
 *
 
4
 *  Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com>.
 
5
 *  Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
 
6
 *
 
7
 * This library is free software; you can redistribute it and/or
 
8
 * modify it under the terms of the GNU Lesser General Public
 
9
 * License as published by the Free Software Foundation; either
 
10
 * version 2 of the License, or (at your option) any later version.
 
11
 *
 
12
 * This library is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
 * Lesser General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU Lesser General Public
 
18
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
 
19
 */
 
20
 
 
21
#include "qemu/osdep.h"
 
22
#include "cpu.h"
 
23
#include "exec/helper-proto.h"
 
24
#include "qemu/host-utils.h"
 
25
#include "exec/exec-all.h"
 
26
#include "exec/cpu_ldst.h"
 
27
 
 
28
#define D(x)
 
29
 
 
30
#if !defined(CONFIG_USER_ONLY)
 
31
 
 
32
/* Try to fill the TLB and return an exception if error. If retaddr is
 
33
 * NULL, it means that the function was called in C code (i.e. not
 
34
 * from generated code or from helper.c)
 
35
 */
 
36
void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type,
 
37
              int mmu_idx, uintptr_t retaddr)
 
38
{
 
39
    int ret;
 
40
 
 
41
    ret = mb_cpu_handle_mmu_fault(cs, addr, access_type, mmu_idx);
 
42
    if (unlikely(ret)) {
 
43
        if (retaddr) {
 
44
            /* now we have a real cpu fault */
 
45
            cpu_restore_state(cs, retaddr);
 
46
        }
 
47
        cpu_loop_exit(cs);
 
48
    }
 
49
}
 
50
#endif
 
51
 
 
52
void helper_put(uint32_t id, uint32_t ctrl, uint32_t data)
 
53
{
 
54
    int test = ctrl & STREAM_TEST;
 
55
    int atomic = ctrl & STREAM_ATOMIC;
 
56
    int control = ctrl & STREAM_CONTROL;
 
57
    int nonblock = ctrl & STREAM_NONBLOCK;
 
58
    int exception = ctrl & STREAM_EXCEPTION;
 
59
 
 
60
    qemu_log_mask(LOG_UNIMP, "Unhandled stream put to stream-id=%d data=%x %s%s%s%s%s\n",
 
61
             id, data,
 
62
             test ? "t" : "",
 
63
             nonblock ? "n" : "",
 
64
             exception ? "e" : "",
 
65
             control ? "c" : "",
 
66
             atomic ? "a" : "");
 
67
}
 
68
 
 
69
uint32_t helper_get(uint32_t id, uint32_t ctrl)
 
70
{
 
71
    int test = ctrl & STREAM_TEST;
 
72
    int atomic = ctrl & STREAM_ATOMIC;
 
73
    int control = ctrl & STREAM_CONTROL;
 
74
    int nonblock = ctrl & STREAM_NONBLOCK;
 
75
    int exception = ctrl & STREAM_EXCEPTION;
 
76
 
 
77
    qemu_log_mask(LOG_UNIMP, "Unhandled stream get from stream-id=%d %s%s%s%s%s\n",
 
78
             id,
 
79
             test ? "t" : "",
 
80
             nonblock ? "n" : "",
 
81
             exception ? "e" : "",
 
82
             control ? "c" : "",
 
83
             atomic ? "a" : "");
 
84
    return 0xdead0000 | id;
 
85
}
 
86
 
 
87
void helper_raise_exception(CPUMBState *env, uint32_t index)
 
88
{
 
89
    CPUState *cs = CPU(mb_env_get_cpu(env));
 
90
 
 
91
    cs->exception_index = index;
 
92
    cpu_loop_exit(cs);
 
93
}
 
94
 
 
95
void helper_debug(CPUMBState *env)
 
96
{
 
97
    int i;
 
98
 
 
99
    qemu_log("PC=%8.8x\n", env->sregs[SR_PC]);
 
100
    qemu_log("rmsr=%x resr=%x rear=%x debug[%x] imm=%x iflags=%x\n",
 
101
             env->sregs[SR_MSR], env->sregs[SR_ESR], env->sregs[SR_EAR],
 
102
             env->debug, env->imm, env->iflags);
 
103
    qemu_log("btaken=%d btarget=%x mode=%s(saved=%s) eip=%d ie=%d\n",
 
104
             env->btaken, env->btarget,
 
105
             (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel",
 
106
             (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel",
 
107
             (env->sregs[SR_MSR] & MSR_EIP),
 
108
             (env->sregs[SR_MSR] & MSR_IE));
 
109
    for (i = 0; i < 32; i++) {
 
110
        qemu_log("r%2.2d=%8.8x ", i, env->regs[i]);
 
111
        if ((i + 1) % 4 == 0)
 
112
            qemu_log("\n");
 
113
    }
 
114
    qemu_log("\n\n");
 
115
}
 
116
 
 
117
static inline uint32_t compute_carry(uint32_t a, uint32_t b, uint32_t cin)
 
118
{
 
119
    uint32_t cout = 0;
 
120
 
 
121
    if ((b == ~0) && cin)
 
122
        cout = 1;
 
123
    else if ((~0 - a) < (b + cin))
 
124
        cout = 1;
 
125
    return cout;
 
126
}
 
127
 
 
128
uint32_t helper_cmp(uint32_t a, uint32_t b)
 
129
{
 
130
    uint32_t t;
 
131
 
 
132
    t = b + ~a + 1;
 
133
    if ((b & 0x80000000) ^ (a & 0x80000000))
 
134
        t = (t & 0x7fffffff) | (b & 0x80000000);
 
135
    return t;
 
136
}
 
137
 
 
138
uint32_t helper_cmpu(uint32_t a, uint32_t b)
 
139
{
 
140
    uint32_t t;
 
141
 
 
142
    t = b + ~a + 1;
 
143
    if ((b & 0x80000000) ^ (a & 0x80000000))
 
144
        t = (t & 0x7fffffff) | (a & 0x80000000);
 
145
    return t;
 
146
}
 
147
 
 
148
uint32_t helper_carry(uint32_t a, uint32_t b, uint32_t cf)
 
149
{
 
150
    return compute_carry(a, b, cf);
 
151
}
 
152
 
 
153
static inline int div_prepare(CPUMBState *env, uint32_t a, uint32_t b)
 
154
{
 
155
    if (b == 0) {
 
156
        env->sregs[SR_MSR] |= MSR_DZ;
 
157
 
 
158
        if ((env->sregs[SR_MSR] & MSR_EE)
 
159
            && !(env->pvr.regs[2] & PVR2_DIV_ZERO_EXC_MASK)) {
 
160
            env->sregs[SR_ESR] = ESR_EC_DIVZERO;
 
161
            helper_raise_exception(env, EXCP_HW_EXCP);
 
162
        }
 
163
        return 0;
 
164
    }
 
165
    env->sregs[SR_MSR] &= ~MSR_DZ;
 
166
    return 1;
 
167
}
 
168
 
 
169
uint32_t helper_divs(CPUMBState *env, uint32_t a, uint32_t b)
 
170
{
 
171
    if (!div_prepare(env, a, b)) {
 
172
        return 0;
 
173
    }
 
174
    return (int32_t)a / (int32_t)b;
 
175
}
 
176
 
 
177
uint32_t helper_divu(CPUMBState *env, uint32_t a, uint32_t b)
 
178
{
 
179
    if (!div_prepare(env, a, b)) {
 
180
        return 0;
 
181
    }
 
182
    return a / b;
 
183
}
 
184
 
 
185
/* raise FPU exception.  */
 
186
static void raise_fpu_exception(CPUMBState *env)
 
187
{
 
188
    env->sregs[SR_ESR] = ESR_EC_FPU;
 
189
    helper_raise_exception(env, EXCP_HW_EXCP);
 
190
}
 
191
 
 
192
static void update_fpu_flags(CPUMBState *env, int flags)
 
193
{
 
194
    int raise = 0;
 
195
 
 
196
    if (flags & float_flag_invalid) {
 
197
        env->sregs[SR_FSR] |= FSR_IO;
 
198
        raise = 1;
 
199
    }
 
200
    if (flags & float_flag_divbyzero) {
 
201
        env->sregs[SR_FSR] |= FSR_DZ;
 
202
        raise = 1;
 
203
    }
 
204
    if (flags & float_flag_overflow) {
 
205
        env->sregs[SR_FSR] |= FSR_OF;
 
206
        raise = 1;
 
207
    }
 
208
    if (flags & float_flag_underflow) {
 
209
        env->sregs[SR_FSR] |= FSR_UF;
 
210
        raise = 1;
 
211
    }
 
212
    if (raise
 
213
        && (env->pvr.regs[2] & PVR2_FPU_EXC_MASK)
 
214
        && (env->sregs[SR_MSR] & MSR_EE)) {
 
215
        raise_fpu_exception(env);
 
216
    }
 
217
}
 
218
 
 
219
uint32_t helper_fadd(CPUMBState *env, uint32_t a, uint32_t b)
 
220
{
 
221
    CPU_FloatU fd, fa, fb;
 
222
    int flags;
 
223
 
 
224
    set_float_exception_flags(0, &env->fp_status);
 
225
    fa.l = a;
 
226
    fb.l = b;
 
227
    fd.f = float32_add(fa.f, fb.f, &env->fp_status);
 
228
 
 
229
    flags = get_float_exception_flags(&env->fp_status);
 
230
    update_fpu_flags(env, flags);
 
231
    return fd.l;
 
232
}
 
233
 
 
234
uint32_t helper_frsub(CPUMBState *env, uint32_t a, uint32_t b)
 
235
{
 
236
    CPU_FloatU fd, fa, fb;
 
237
    int flags;
 
238
 
 
239
    set_float_exception_flags(0, &env->fp_status);
 
240
    fa.l = a;
 
241
    fb.l = b;
 
242
    fd.f = float32_sub(fb.f, fa.f, &env->fp_status);
 
243
    flags = get_float_exception_flags(&env->fp_status);
 
244
    update_fpu_flags(env, flags);
 
245
    return fd.l;
 
246
}
 
247
 
 
248
uint32_t helper_fmul(CPUMBState *env, uint32_t a, uint32_t b)
 
249
{
 
250
    CPU_FloatU fd, fa, fb;
 
251
    int flags;
 
252
 
 
253
    set_float_exception_flags(0, &env->fp_status);
 
254
    fa.l = a;
 
255
    fb.l = b;
 
256
    fd.f = float32_mul(fa.f, fb.f, &env->fp_status);
 
257
    flags = get_float_exception_flags(&env->fp_status);
 
258
    update_fpu_flags(env, flags);
 
259
 
 
260
    return fd.l;
 
261
}
 
262
 
 
263
uint32_t helper_fdiv(CPUMBState *env, uint32_t a, uint32_t b)
 
264
{
 
265
    CPU_FloatU fd, fa, fb;
 
266
    int flags;
 
267
 
 
268
    set_float_exception_flags(0, &env->fp_status);
 
269
    fa.l = a;
 
270
    fb.l = b;
 
271
    fd.f = float32_div(fb.f, fa.f, &env->fp_status);
 
272
    flags = get_float_exception_flags(&env->fp_status);
 
273
    update_fpu_flags(env, flags);
 
274
 
 
275
    return fd.l;
 
276
}
 
277
 
 
278
uint32_t helper_fcmp_un(CPUMBState *env, uint32_t a, uint32_t b)
 
279
{
 
280
    CPU_FloatU fa, fb;
 
281
    uint32_t r = 0;
 
282
 
 
283
    fa.l = a;
 
284
    fb.l = b;
 
285
 
 
286
    if (float32_is_signaling_nan(fa.f, &env->fp_status) ||
 
287
        float32_is_signaling_nan(fb.f, &env->fp_status)) {
 
288
        update_fpu_flags(env, float_flag_invalid);
 
289
        r = 1;
 
290
    }
 
291
 
 
292
    if (float32_is_quiet_nan(fa.f, &env->fp_status) ||
 
293
        float32_is_quiet_nan(fb.f, &env->fp_status)) {
 
294
        r = 1;
 
295
    }
 
296
 
 
297
    return r;
 
298
}
 
299
 
 
300
uint32_t helper_fcmp_lt(CPUMBState *env, uint32_t a, uint32_t b)
 
301
{
 
302
    CPU_FloatU fa, fb;
 
303
    int r;
 
304
    int flags;
 
305
 
 
306
    set_float_exception_flags(0, &env->fp_status);
 
307
    fa.l = a;
 
308
    fb.l = b;
 
309
    r = float32_lt(fb.f, fa.f, &env->fp_status);
 
310
    flags = get_float_exception_flags(&env->fp_status);
 
311
    update_fpu_flags(env, flags & float_flag_invalid);
 
312
 
 
313
    return r;
 
314
}
 
315
 
 
316
uint32_t helper_fcmp_eq(CPUMBState *env, uint32_t a, uint32_t b)
 
317
{
 
318
    CPU_FloatU fa, fb;
 
319
    int flags;
 
320
    int r;
 
321
 
 
322
    set_float_exception_flags(0, &env->fp_status);
 
323
    fa.l = a;
 
324
    fb.l = b;
 
325
    r = float32_eq_quiet(fa.f, fb.f, &env->fp_status);
 
326
    flags = get_float_exception_flags(&env->fp_status);
 
327
    update_fpu_flags(env, flags & float_flag_invalid);
 
328
 
 
329
    return r;
 
330
}
 
331
 
 
332
uint32_t helper_fcmp_le(CPUMBState *env, uint32_t a, uint32_t b)
 
333
{
 
334
    CPU_FloatU fa, fb;
 
335
    int flags;
 
336
    int r;
 
337
 
 
338
    fa.l = a;
 
339
    fb.l = b;
 
340
    set_float_exception_flags(0, &env->fp_status);
 
341
    r = float32_le(fa.f, fb.f, &env->fp_status);
 
342
    flags = get_float_exception_flags(&env->fp_status);
 
343
    update_fpu_flags(env, flags & float_flag_invalid);
 
344
 
 
345
 
 
346
    return r;
 
347
}
 
348
 
 
349
uint32_t helper_fcmp_gt(CPUMBState *env, uint32_t a, uint32_t b)
 
350
{
 
351
    CPU_FloatU fa, fb;
 
352
    int flags, r;
 
353
 
 
354
    fa.l = a;
 
355
    fb.l = b;
 
356
    set_float_exception_flags(0, &env->fp_status);
 
357
    r = float32_lt(fa.f, fb.f, &env->fp_status);
 
358
    flags = get_float_exception_flags(&env->fp_status);
 
359
    update_fpu_flags(env, flags & float_flag_invalid);
 
360
    return r;
 
361
}
 
362
 
 
363
uint32_t helper_fcmp_ne(CPUMBState *env, uint32_t a, uint32_t b)
 
364
{
 
365
    CPU_FloatU fa, fb;
 
366
    int flags, r;
 
367
 
 
368
    fa.l = a;
 
369
    fb.l = b;
 
370
    set_float_exception_flags(0, &env->fp_status);
 
371
    r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status);
 
372
    flags = get_float_exception_flags(&env->fp_status);
 
373
    update_fpu_flags(env, flags & float_flag_invalid);
 
374
 
 
375
    return r;
 
376
}
 
377
 
 
378
uint32_t helper_fcmp_ge(CPUMBState *env, uint32_t a, uint32_t b)
 
379
{
 
380
    CPU_FloatU fa, fb;
 
381
    int flags, r;
 
382
 
 
383
    fa.l = a;
 
384
    fb.l = b;
 
385
    set_float_exception_flags(0, &env->fp_status);
 
386
    r = !float32_lt(fa.f, fb.f, &env->fp_status);
 
387
    flags = get_float_exception_flags(&env->fp_status);
 
388
    update_fpu_flags(env, flags & float_flag_invalid);
 
389
 
 
390
    return r;
 
391
}
 
392
 
 
393
uint32_t helper_flt(CPUMBState *env, uint32_t a)
 
394
{
 
395
    CPU_FloatU fd, fa;
 
396
 
 
397
    fa.l = a;
 
398
    fd.f = int32_to_float32(fa.l, &env->fp_status);
 
399
    return fd.l;
 
400
}
 
401
 
 
402
uint32_t helper_fint(CPUMBState *env, uint32_t a)
 
403
{
 
404
    CPU_FloatU fa;
 
405
    uint32_t r;
 
406
    int flags;
 
407
 
 
408
    set_float_exception_flags(0, &env->fp_status);
 
409
    fa.l = a;
 
410
    r = float32_to_int32(fa.f, &env->fp_status);
 
411
    flags = get_float_exception_flags(&env->fp_status);
 
412
    update_fpu_flags(env, flags);
 
413
 
 
414
    return r;
 
415
}
 
416
 
 
417
uint32_t helper_fsqrt(CPUMBState *env, uint32_t a)
 
418
{
 
419
    CPU_FloatU fd, fa;
 
420
    int flags;
 
421
 
 
422
    set_float_exception_flags(0, &env->fp_status);
 
423
    fa.l = a;
 
424
    fd.l = float32_sqrt(fa.f, &env->fp_status);
 
425
    flags = get_float_exception_flags(&env->fp_status);
 
426
    update_fpu_flags(env, flags);
 
427
 
 
428
    return fd.l;
 
429
}
 
430
 
 
431
uint32_t helper_pcmpbf(uint32_t a, uint32_t b)
 
432
{
 
433
    unsigned int i;
 
434
    uint32_t mask = 0xff000000;
 
435
 
 
436
    for (i = 0; i < 4; i++) {
 
437
        if ((a & mask) == (b & mask))
 
438
            return i + 1;
 
439
        mask >>= 8;
 
440
    }
 
441
    return 0;
 
442
}
 
443
 
 
444
void helper_memalign(CPUMBState *env, uint32_t addr, uint32_t dr, uint32_t wr,
 
445
                     uint32_t mask)
 
446
{
 
447
    if (addr & mask) {
 
448
            qemu_log_mask(CPU_LOG_INT,
 
449
                          "unaligned access addr=%x mask=%x, wr=%d dr=r%d\n",
 
450
                          addr, mask, wr, dr);
 
451
            env->sregs[SR_EAR] = addr;
 
452
            env->sregs[SR_ESR] = ESR_EC_UNALIGNED_DATA | (wr << 10) \
 
453
                                 | (dr & 31) << 5;
 
454
            if (mask == 3) {
 
455
                env->sregs[SR_ESR] |= 1 << 11;
 
456
            }
 
457
            if (!(env->sregs[SR_MSR] & MSR_EE)) {
 
458
                return;
 
459
            }
 
460
            helper_raise_exception(env, EXCP_HW_EXCP);
 
461
    }
 
462
}
 
463
 
 
464
void helper_stackprot(CPUMBState *env, uint32_t addr)
 
465
{
 
466
    if (addr < env->slr || addr > env->shr) {
 
467
        qemu_log_mask(CPU_LOG_INT, "Stack protector violation at %x %x %x\n",
 
468
                      addr, env->slr, env->shr);
 
469
        env->sregs[SR_EAR] = addr;
 
470
        env->sregs[SR_ESR] = ESR_EC_STACKPROT;
 
471
        helper_raise_exception(env, EXCP_HW_EXCP);
 
472
    }
 
473
}
 
474
 
 
475
#if !defined(CONFIG_USER_ONLY)
 
476
/* Writes/reads to the MMU's special regs end up here.  */
 
477
uint32_t helper_mmu_read(CPUMBState *env, uint32_t rn)
 
478
{
 
479
    return mmu_read(env, rn);
 
480
}
 
481
 
 
482
void helper_mmu_write(CPUMBState *env, uint32_t rn, uint32_t v)
 
483
{
 
484
    mmu_write(env, rn, v);
 
485
}
 
486
 
 
487
void mb_cpu_unassigned_access(CPUState *cs, hwaddr addr,
 
488
                              bool is_write, bool is_exec, int is_asi,
 
489
                              unsigned size)
 
490
{
 
491
    MicroBlazeCPU *cpu;
 
492
    CPUMBState *env;
 
493
 
 
494
    qemu_log_mask(CPU_LOG_INT, "Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n",
 
495
             addr, is_write ? 1 : 0, is_exec ? 1 : 0);
 
496
    if (cs == NULL) {
 
497
        return;
 
498
    }
 
499
    cpu = MICROBLAZE_CPU(cs);
 
500
    env = &cpu->env;
 
501
    if (!(env->sregs[SR_MSR] & MSR_EE)) {
 
502
        return;
 
503
    }
 
504
 
 
505
    env->sregs[SR_EAR] = addr;
 
506
    if (is_exec) {
 
507
        if ((env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) {
 
508
            env->sregs[SR_ESR] = ESR_EC_INSN_BUS;
 
509
            helper_raise_exception(env, EXCP_HW_EXCP);
 
510
        }
 
511
    } else {
 
512
        if ((env->pvr.regs[2] & PVR2_DOPB_BUS_EXC_MASK)) {
 
513
            env->sregs[SR_ESR] = ESR_EC_DATA_BUS;
 
514
            helper_raise_exception(env, EXCP_HW_EXCP);
 
515
        }
 
516
    }
 
517
}
 
518
#endif