Statistics
| Branch: | Revision:

root / target-arm / op_helper.c @ 19457615

History | View | Annotate | Download (10.9 kB)

1
/*
2
 *  ARM helper routines
3
 *
4
 *  Copyright (c) 2005-2007 CodeSourcery, LLC
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 "exec.h"
20
#include "helpers.h"
21

    
22
#define SIGNBIT (uint32_t)0x80000000
23
#define SIGNBIT64 ((uint64_t)1 << 63)
24

    
25
void raise_exception(int tt)
26
{
27
    env->exception_index = tt;
28
    cpu_loop_exit();
29
}
30

    
31
/* thread support */
32

    
33
static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
34

    
35
void cpu_lock(void)
36
{
37
    spin_lock(&global_cpu_lock);
38
}
39

    
40
void cpu_unlock(void)
41
{
42
    spin_unlock(&global_cpu_lock);
43
}
44

    
45
uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def,
46
                          uint32_t rn, uint32_t maxindex)
47
{
48
    uint32_t val;
49
    uint32_t tmp;
50
    int index;
51
    int shift;
52
    uint64_t *table;
53
    table = (uint64_t *)&env->vfp.regs[rn];
54
    val = 0;
55
    for (shift = 0; shift < 32; shift += 8) {
56
        index = (ireg >> shift) & 0xff;
57
        if (index < maxindex) {
58
            tmp = (table[index >> 3] >> ((index & 7) << 3)) & 0xff;
59
            val |= tmp << shift;
60
        } else {
61
            val |= def & (0xff << shift);
62
        }
63
    }
64
    return val;
65
}
66

    
67
#if !defined(CONFIG_USER_ONLY)
68

    
69
#define MMUSUFFIX _mmu
70

    
71
#define SHIFT 0
72
#include "softmmu_template.h"
73

    
74
#define SHIFT 1
75
#include "softmmu_template.h"
76

    
77
#define SHIFT 2
78
#include "softmmu_template.h"
79

    
80
#define SHIFT 3
81
#include "softmmu_template.h"
82

    
83
/* try to fill the TLB and return an exception if error. If retaddr is
84
   NULL, it means that the function was called in C code (i.e. not
85
   from generated code or from helper.c) */
86
/* XXX: fix it to restore all registers */
87
void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
88
{
89
    TranslationBlock *tb;
90
    CPUState *saved_env;
91
    unsigned long pc;
92
    int ret;
93

    
94
    /* XXX: hack to restore env in all cases, even if not called from
95
       generated code */
96
    saved_env = env;
97
    env = cpu_single_env;
98
    ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
99
    if (unlikely(ret)) {
100
        if (retaddr) {
101
            /* now we have a real cpu fault */
102
            pc = (unsigned long)retaddr;
103
            tb = tb_find_pc(pc);
104
            if (tb) {
105
                /* the PC is inside the translated code. It means that we have
106
                   a virtual CPU fault */
107
                cpu_restore_state(tb, env, pc, NULL);
108
            }
109
        }
110
        raise_exception(env->exception_index);
111
    }
112
    env = saved_env;
113
}
114
#endif
115

    
116
/* FIXME: Pass an axplicit pointer to QF to CPUState, and move saturating
117
   instructions into helper.c  */
118
uint32_t HELPER(add_setq)(uint32_t a, uint32_t b)
119
{
120
    uint32_t res = a + b;
121
    if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT))
122
        env->QF = 1;
123
    return res;
124
}
125

    
126
uint32_t HELPER(add_saturate)(uint32_t a, uint32_t b)
127
{
128
    uint32_t res = a + b;
129
    if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) {
130
        env->QF = 1;
131
        res = ~(((int32_t)a >> 31) ^ SIGNBIT);
132
    }
133
    return res;
134
}
135

    
136
uint32_t HELPER(sub_saturate)(uint32_t a, uint32_t b)
137
{
138
    uint32_t res = a - b;
139
    if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) {
140
        env->QF = 1;
141
        res = ~(((int32_t)a >> 31) ^ SIGNBIT);
142
    }
143
    return res;
144
}
145

    
146
uint32_t HELPER(double_saturate)(int32_t val)
147
{
148
    uint32_t res;
149
    if (val >= 0x40000000) {
150
        res = ~SIGNBIT;
151
        env->QF = 1;
152
    } else if (val <= (int32_t)0xc0000000) {
153
        res = SIGNBIT;
154
        env->QF = 1;
155
    } else {
156
        res = val << 1;
157
    }
158
    return res;
159
}
160

    
161
uint32_t HELPER(add_usaturate)(uint32_t a, uint32_t b)
162
{
163
    uint32_t res = a + b;
164
    if (res < a) {
165
        env->QF = 1;
166
        res = ~0;
167
    }
168
    return res;
169
}
170

    
171
uint32_t HELPER(sub_usaturate)(uint32_t a, uint32_t b)
172
{
173
    uint32_t res = a - b;
174
    if (res > a) {
175
        env->QF = 1;
176
        res = 0;
177
    }
178
    return res;
179
}
180

    
181
/* Signed saturation.  */
182
static inline uint32_t do_ssat(int32_t val, int shift)
183
{
184
    int32_t top;
185
    uint32_t mask;
186

    
187
    top = val >> shift;
188
    mask = (1u << shift) - 1;
189
    if (top > 0) {
190
        env->QF = 1;
191
        return mask;
192
    } else if (top < -1) {
193
        env->QF = 1;
194
        return ~mask;
195
    }
196
    return val;
197
}
198

    
199
/* Unsigned saturation.  */
200
static inline uint32_t do_usat(int32_t val, int shift)
201
{
202
    uint32_t max;
203

    
204
    max = (1u << shift) - 1;
205
    if (val < 0) {
206
        env->QF = 1;
207
        return 0;
208
    } else if (val > max) {
209
        env->QF = 1;
210
        return max;
211
    }
212
    return val;
213
}
214

    
215
/* Signed saturate.  */
216
uint32_t HELPER(ssat)(uint32_t x, uint32_t shift)
217
{
218
    return do_ssat(x, shift);
219
}
220

    
221
/* Dual halfword signed saturate.  */
222
uint32_t HELPER(ssat16)(uint32_t x, uint32_t shift)
223
{
224
    uint32_t res;
225

    
226
    res = (uint16_t)do_ssat((int16_t)x, shift);
227
    res |= do_ssat(((int32_t)x) >> 16, shift) << 16;
228
    return res;
229
}
230

    
231
/* Unsigned saturate.  */
232
uint32_t HELPER(usat)(uint32_t x, uint32_t shift)
233
{
234
    return do_usat(x, shift);
235
}
236

    
237
/* Dual halfword unsigned saturate.  */
238
uint32_t HELPER(usat16)(uint32_t x, uint32_t shift)
239
{
240
    uint32_t res;
241

    
242
    res = (uint16_t)do_usat((int16_t)x, shift);
243
    res |= do_usat(((int32_t)x) >> 16, shift) << 16;
244
    return res;
245
}
246

    
247
void HELPER(wfi)(void)
248
{
249
    env->exception_index = EXCP_HLT;
250
    env->halted = 1;
251
    cpu_loop_exit();
252
}
253

    
254
void HELPER(exception)(uint32_t excp)
255
{
256
    env->exception_index = excp;
257
    cpu_loop_exit();
258
}
259

    
260
uint32_t HELPER(cpsr_read)(void)
261
{
262
    return cpsr_read(env) & ~CPSR_EXEC;
263
}
264

    
265
void HELPER(cpsr_write)(uint32_t val, uint32_t mask)
266
{
267
    cpsr_write(env, val, mask);
268
}
269

    
270
/* Access to user mode registers from privileged modes.  */
271
uint32_t HELPER(get_user_reg)(uint32_t regno)
272
{
273
    uint32_t val;
274

    
275
    if (regno == 13) {
276
        val = env->banked_r13[0];
277
    } else if (regno == 14) {
278
        val = env->banked_r14[0];
279
    } else if (regno >= 8
280
               && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
281
        val = env->usr_regs[regno - 8];
282
    } else {
283
        val = env->regs[regno];
284
    }
285
    return val;
286
}
287

    
288
void HELPER(set_user_reg)(uint32_t regno, uint32_t val)
289
{
290
    if (regno == 13) {
291
        env->banked_r13[0] = val;
292
    } else if (regno == 14) {
293
        env->banked_r14[0] = val;
294
    } else if (regno >= 8
295
               && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
296
        env->usr_regs[regno - 8] = val;
297
    } else {
298
        env->regs[regno] = val;
299
    }
300
}
301

    
302
/* ??? Flag setting arithmetic is awkward because we need to do comparisons.
303
   The only way to do that in TCG is a conditional branch, which clobbers
304
   all our temporaries.  For now implement these as helper functions.  */
305

    
306
uint32_t HELPER (add_cc)(uint32_t a, uint32_t b)
307
{
308
    uint32_t result;
309
    result = a + b;
310
    env->NF = env->ZF = result;
311
    env->CF = result < a;
312
    env->VF = (a ^ b ^ -1) & (a ^ result);
313
    return result;
314
}
315

    
316
uint32_t HELPER(adc_cc)(uint32_t a, uint32_t b)
317
{
318
    uint32_t result;
319
    if (!env->CF) {
320
        result = a + b;
321
        env->CF = result < a;
322
    } else {
323
        result = a + b + 1;
324
        env->CF = result <= a;
325
    }
326
    env->VF = (a ^ b ^ -1) & (a ^ result);
327
    env->NF = env->ZF = result;
328
    return result;
329
}
330

    
331
uint32_t HELPER(sub_cc)(uint32_t a, uint32_t b)
332
{
333
    uint32_t result;
334
    result = a - b;
335
    env->NF = env->ZF = result;
336
    env->CF = a >= b;
337
    env->VF = (a ^ b) & (a ^ result);
338
    return result;
339
}
340

    
341
uint32_t HELPER(sbc_cc)(uint32_t a, uint32_t b)
342
{
343
    uint32_t result;
344
    if (!env->CF) {
345
        result = a - b - 1;
346
        env->CF = a > b;
347
    } else {
348
        result = a - b;
349
        env->CF = a >= b;
350
    }
351
    env->VF = (a ^ b) & (a ^ result);
352
    env->NF = env->ZF = result;
353
    return result;
354
}
355

    
356
/* Similarly for variable shift instructions.  */
357

    
358
uint32_t HELPER(shl)(uint32_t x, uint32_t i)
359
{
360
    int shift = i & 0xff;
361
    if (shift >= 32)
362
        return 0;
363
    return x << shift;
364
}
365

    
366
uint32_t HELPER(shr)(uint32_t x, uint32_t i)
367
{
368
    int shift = i & 0xff;
369
    if (shift >= 32)
370
        return 0;
371
    return (uint32_t)x >> shift;
372
}
373

    
374
uint32_t HELPER(sar)(uint32_t x, uint32_t i)
375
{
376
    int shift = i & 0xff;
377
    if (shift >= 32)
378
        shift = 31;
379
    return (int32_t)x >> shift;
380
}
381

    
382
uint32_t HELPER(ror)(uint32_t x, uint32_t i)
383
{
384
    int shift = i & 0xff;
385
    if (shift == 0)
386
        return x;
387
    return (x >> shift) | (x << (32 - shift));
388
}
389

    
390
uint32_t HELPER(shl_cc)(uint32_t x, uint32_t i)
391
{
392
    int shift = i & 0xff;
393
    if (shift >= 32) {
394
        if (shift == 32)
395
            env->CF = x & 1;
396
        else
397
            env->CF = 0;
398
        return 0;
399
    } else if (shift != 0) {
400
        env->CF = (x >> (32 - shift)) & 1;
401
        return x << shift;
402
    }
403
    return x;
404
}
405

    
406
uint32_t HELPER(shr_cc)(uint32_t x, uint32_t i)
407
{
408
    int shift = i & 0xff;
409
    if (shift >= 32) {
410
        if (shift == 32)
411
            env->CF = (x >> 31) & 1;
412
        else
413
            env->CF = 0;
414
        return 0;
415
    } else if (shift != 0) {
416
        env->CF = (x >> (shift - 1)) & 1;
417
        return x >> shift;
418
    }
419
    return x;
420
}
421

    
422
uint32_t HELPER(sar_cc)(uint32_t x, uint32_t i)
423
{
424
    int shift = i & 0xff;
425
    if (shift >= 32) {
426
        env->CF = (x >> 31) & 1;
427
        return (int32_t)x >> 31;
428
    } else if (shift != 0) {
429
        env->CF = (x >> (shift - 1)) & 1;
430
        return (int32_t)x >> shift;
431
    }
432
    return x;
433
}
434

    
435
uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i)
436
{
437
    int shift1, shift;
438
    shift1 = i & 0xff;
439
    shift = shift1 & 0x1f;
440
    if (shift == 0) {
441
        if (shift1 != 0)
442
            env->CF = (x >> 31) & 1;
443
        return x;
444
    } else {
445
        env->CF = (x >> (shift - 1)) & 1;
446
        return ((uint32_t)x >> shift) | (x << (32 - shift));
447
    }
448
}
449

    
450
uint64_t HELPER(neon_add_saturate_s64)(uint64_t src1, uint64_t src2)
451
{
452
    uint64_t res;
453

    
454
    res = src1 + src2;
455
    if (((res ^ src1) & SIGNBIT64) && !((src1 ^ src2) & SIGNBIT64)) {
456
        env->QF = 1;
457
        res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64;
458
    }
459
    return res;
460
}
461

    
462
uint64_t HELPER(neon_add_saturate_u64)(uint64_t src1, uint64_t src2)
463
{
464
    uint64_t res;
465

    
466
    res = src1 + src2;
467
    if (res < src1) {
468
        env->QF = 1;
469
        res = ~(uint64_t)0;
470
    }
471
    return res;
472
}
473

    
474
uint64_t HELPER(neon_sub_saturate_s64)(uint64_t src1, uint64_t src2)
475
{
476
    uint64_t res;
477

    
478
    res = src1 - src2;
479
    if (((res ^ src1) & SIGNBIT64) && ((src1 ^ src2) & SIGNBIT64)) {
480
        env->QF = 1;
481
        res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64;
482
    }
483
    return res;
484
}
485

    
486
uint64_t HELPER(neon_sub_saturate_u64)(uint64_t src1, uint64_t src2)
487
{
488
    uint64_t res;
489

    
490
    if (src1 < src2) {
491
        env->QF = 1;
492
        res = 0;
493
    } else {
494
        res = src1 - src2;
495
    }
496
    return res;
497
}