Statistics
| Branch: | Revision:

root / target-arm / op_helper.c @ 1ffc346f

History | View | Annotate | Download (12.6 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, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 */
20
#include "exec.h"
21
#include "helpers.h"
22

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

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

    
32
/* thread support */
33

    
34
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
35

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

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

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

    
68
#if !defined(CONFIG_USER_ONLY)
69

    
70
#define MMUSUFFIX _mmu
71
#ifdef __s390__
72
# define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL))
73
#else
74
# define GETPC() (__builtin_return_address(0))
75
#endif
76

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

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

    
83
#define SHIFT 2
84
#include "softmmu_template.h"
85

    
86
#define SHIFT 3
87
#include "softmmu_template.h"
88

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

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

    
122
/* FIXME: Pass an axplicit pointer to QF to CPUState, and move saturating
123
   instructions into helper.c  */
124
uint32_t HELPER(add_setq)(uint32_t a, uint32_t b)
125
{
126
    uint32_t res = a + b;
127
    if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT))
128
        env->QF = 1;
129
    return res;
130
}
131

    
132
uint32_t HELPER(add_saturate)(uint32_t a, uint32_t b)
133
{
134
    uint32_t res = a + b;
135
    if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) {
136
        env->QF = 1;
137
        res = ~(((int32_t)a >> 31) ^ SIGNBIT);
138
    }
139
    return res;
140
}
141

    
142
uint32_t HELPER(sub_saturate)(uint32_t a, uint32_t b)
143
{
144
    uint32_t res = a - b;
145
    if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) {
146
        env->QF = 1;
147
        res = ~(((int32_t)a >> 31) ^ SIGNBIT);
148
    }
149
    return res;
150
}
151

    
152
uint32_t HELPER(double_saturate)(int32_t val)
153
{
154
    uint32_t res;
155
    if (val >= 0x40000000) {
156
        res = ~SIGNBIT;
157
        env->QF = 1;
158
    } else if (val <= (int32_t)0xc0000000) {
159
        res = SIGNBIT;
160
        env->QF = 1;
161
    } else {
162
        res = val << 1;
163
    }
164
    return res;
165
}
166

    
167
uint32_t HELPER(add_usaturate)(uint32_t a, uint32_t b)
168
{
169
    uint32_t res = a + b;
170
    if (res < a) {
171
        env->QF = 1;
172
        res = ~0;
173
    }
174
    return res;
175
}
176

    
177
uint32_t HELPER(sub_usaturate)(uint32_t a, uint32_t b)
178
{
179
    uint32_t res = a - b;
180
    if (res > a) {
181
        env->QF = 1;
182
        res = 0;
183
    }
184
    return res;
185
}
186

    
187
/* Signed saturation.  */
188
static inline uint32_t do_ssat(int32_t val, int shift)
189
{
190
    int32_t top;
191
    uint32_t mask;
192

    
193
    shift = PARAM1;
194
    top = val >> shift;
195
    mask = (1u << shift) - 1;
196
    if (top > 0) {
197
        env->QF = 1;
198
        return mask;
199
    } else if (top < -1) {
200
        env->QF = 1;
201
        return ~mask;
202
    }
203
    return val;
204
}
205

    
206
/* Unsigned saturation.  */
207
static inline uint32_t do_usat(int32_t val, int shift)
208
{
209
    uint32_t max;
210

    
211
    shift = PARAM1;
212
    max = (1u << shift) - 1;
213
    if (val < 0) {
214
        env->QF = 1;
215
        return 0;
216
    } else if (val > max) {
217
        env->QF = 1;
218
        return max;
219
    }
220
    return val;
221
}
222

    
223
/* Signed saturate.  */
224
uint32_t HELPER(ssat)(uint32_t x, uint32_t shift)
225
{
226
    return do_ssat(x, shift);
227
}
228

    
229
/* Dual halfword signed saturate.  */
230
uint32_t HELPER(ssat16)(uint32_t x, uint32_t shift)
231
{
232
    uint32_t res;
233

    
234
    res = (uint16_t)do_ssat((int16_t)x, shift);
235
    res |= do_ssat(((int32_t)x) >> 16, shift) << 16;
236
    return res;
237
}
238

    
239
/* Unsigned saturate.  */
240
uint32_t HELPER(usat)(uint32_t x, uint32_t shift)
241
{
242
    return do_usat(x, shift);
243
}
244

    
245
/* Dual halfword unsigned saturate.  */
246
uint32_t HELPER(usat16)(uint32_t x, uint32_t shift)
247
{
248
    uint32_t res;
249

    
250
    res = (uint16_t)do_usat((int16_t)x, shift);
251
    res |= do_usat(((int32_t)x) >> 16, shift) << 16;
252
    return res;
253
}
254

    
255
void HELPER(wfi)(void)
256
{
257
    env->exception_index = EXCP_HLT;
258
    env->halted = 1;
259
    cpu_loop_exit();
260
}
261

    
262
void HELPER(exception)(uint32_t excp)
263
{
264
    env->exception_index = excp;
265
    cpu_loop_exit();
266
}
267

    
268
uint32_t HELPER(cpsr_read)(void)
269
{
270
    return cpsr_read(env) & ~CPSR_EXEC;
271
}
272

    
273
void HELPER(cpsr_write)(uint32_t val, uint32_t mask)
274
{
275
    cpsr_write(env, val, mask);
276
}
277

    
278
/* Access to user mode registers from privileged modes.  */
279
uint32_t HELPER(get_user_reg)(uint32_t regno)
280
{
281
    uint32_t val;
282

    
283
    if (regno == 13) {
284
        val = env->banked_r13[0];
285
    } else if (regno == 14) {
286
        val = env->banked_r14[0];
287
    } else if (regno >= 8
288
               && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
289
        val = env->usr_regs[regno - 8];
290
    } else {
291
        val = env->regs[regno];
292
    }
293
    return val;
294
}
295

    
296
void HELPER(set_user_reg)(uint32_t regno, uint32_t val)
297
{
298
    if (regno == 13) {
299
        env->banked_r13[0] = val;
300
    } else if (regno == 14) {
301
        env->banked_r14[0] = val;
302
    } else if (regno >= 8
303
               && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
304
        env->usr_regs[regno - 8] = val;
305
    } else {
306
        env->regs[regno] = val;
307
    }
308
}
309

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

    
314
uint32_t HELPER (add_cc)(uint32_t a, uint32_t b)
315
{
316
    uint32_t result;
317
    result = T0 + T1;
318
    env->NF = env->ZF = result;
319
    env->CF = result < a;
320
    env->VF = (a ^ b ^ -1) & (a ^ result);
321
    return result;
322
}
323

    
324
uint32_t HELPER(adc_cc)(uint32_t a, uint32_t b)
325
{
326
    uint32_t result;
327
    if (!env->CF) {
328
        result = a + b;
329
        env->CF = result < a;
330
    } else {
331
        result = a + b + 1;
332
        env->CF = result <= a;
333
    }
334
    env->VF = (a ^ b ^ -1) & (a ^ result);
335
    env->NF = env->ZF = result;
336
    return result;
337
}
338

    
339
uint32_t HELPER(sub_cc)(uint32_t a, uint32_t b)
340
{
341
    uint32_t result;
342
    result = a - b;
343
    env->NF = env->ZF = result;
344
    env->CF = a >= b;
345
    env->VF = (a ^ b) & (a ^ result);
346
    return result;
347
}
348

    
349
uint32_t HELPER(sbc_cc)(uint32_t a, uint32_t b)
350
{
351
    uint32_t result;
352
    if (!env->CF) {
353
        result = a - b - 1;
354
        env->CF = a > b;
355
    } else {
356
        result = a - b;
357
        env->CF = a >= b;
358
    }
359
    env->VF = (a ^ b) & (a ^ result);
360
    env->NF = env->ZF = result;
361
    return result;
362
}
363

    
364
/* Similarly for variable shift instructions.  */
365

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

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

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

    
390
uint32_t HELPER(ror)(uint32_t x, uint32_t i)
391
{
392
    int shift = i & 0xff;
393
    if (shift == 0)
394
        return x;
395
    return (x >> shift) | (x << (32 - shift));
396
}
397

    
398
uint32_t HELPER(shl_cc)(uint32_t x, uint32_t i)
399
{
400
    int shift = i & 0xff;
401
    if (shift >= 32) {
402
        if (shift == 32)
403
            env->CF = x & 1;
404
        else
405
            env->CF = 0;
406
        return 0;
407
    } else if (shift != 0) {
408
        env->CF = (x >> (32 - shift)) & 1;
409
        return x << shift;
410
    }
411
    return x;
412
}
413

    
414
uint32_t HELPER(shr_cc)(uint32_t x, uint32_t i)
415
{
416
    int shift = i & 0xff;
417
    if (shift >= 32) {
418
        if (shift == 32)
419
            env->CF = (x >> 31) & 1;
420
        else
421
            env->CF = 0;
422
        return 0;
423
    } else if (shift != 0) {
424
        env->CF = (x >> (shift - 1)) & 1;
425
        return x >> shift;
426
    }
427
    return x;
428
}
429

    
430
uint32_t HELPER(sar_cc)(uint32_t x, uint32_t i)
431
{
432
    int shift = i & 0xff;
433
    if (shift >= 32) {
434
        env->CF = (x >> 31) & 1;
435
        return (int32_t)x >> 31;
436
    } else if (shift != 0) {
437
        env->CF = (x >> (shift - 1)) & 1;
438
        return (int32_t)x >> shift;
439
    }
440
    return x;
441
}
442

    
443
uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i)
444
{
445
    int shift1, shift;
446
    shift1 = i & 0xff;
447
    shift = shift1 & 0x1f;
448
    if (shift == 0) {
449
        if (shift1 != 0)
450
            env->CF = (x >> 31) & 1;
451
        return x;
452
    } else {
453
        env->CF = (x >> (shift - 1)) & 1;
454
        return ((uint32_t)x >> shift) | (x << (32 - shift));
455
    }
456
}
457

    
458
uint64_t HELPER(neon_add_saturate_s64)(uint64_t src1, uint64_t src2)
459
{
460
    uint64_t res;
461

    
462
    res = src1 + src2;
463
    if (((res ^ src1) & SIGNBIT64) && !((src1 ^ src2) & SIGNBIT64)) {
464
        env->QF = 1;
465
        res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64;
466
    }
467
    return res;
468
}
469

    
470
uint64_t HELPER(neon_add_saturate_u64)(uint64_t src1, uint64_t src2)
471
{
472
    uint64_t res;
473

    
474
    res = src1 + src2;
475
    if (res < src1) {
476
        env->QF = 1;
477
        res = ~(uint64_t)0;
478
    }
479
    return res;
480
}
481

    
482
uint64_t HELPER(neon_sub_saturate_s64)(uint64_t src1, uint64_t src2)
483
{
484
    uint64_t res;
485

    
486
    res = src1 - src2;
487
    if (((res ^ src1) & SIGNBIT64) && ((src1 ^ src2) & SIGNBIT64)) {
488
        env->QF = 1;
489
        res = ((int64_t)src1 >> 63) ^ ~SIGNBIT64;
490
    }
491
    return res;
492
}
493

    
494
uint64_t HELPER(neon_sub_saturate_u64)(uint64_t src1, uint64_t src2)
495
{
496
    uint64_t res;
497

    
498
    if (src1 < src2) {
499
        env->QF = 1;
500
        res = 0;
501
    } else {
502
        res = src1 - src2;
503
    }
504
    return res;
505
}
506

    
507
/* These need to return a pair of value, so still use T0/T1.  */
508
/* Transpose.  Argument order is rather strange to avoid special casing
509
   the tranlation code.
510
   On input T0 = rm, T1 = rd.  On output T0 = rd, T1 = rm  */
511
void HELPER(neon_trn_u8)(void)
512
{
513
    uint32_t rd;
514
    uint32_t rm;
515
    rd = ((T0 & 0x00ff00ff) << 8) | (T1 & 0x00ff00ff);
516
    rm = ((T1 & 0xff00ff00) >> 8) | (T0 & 0xff00ff00);
517
    T0 = rd;
518
    T1 = rm;
519
    FORCE_RET();
520
}
521

    
522
void HELPER(neon_trn_u16)(void)
523
{
524
    uint32_t rd;
525
    uint32_t rm;
526
    rd = (T0 << 16) | (T1 & 0xffff);
527
    rm = (T1 >> 16) | (T0 & 0xffff0000);
528
    T0 = rd;
529
    T1 = rm;
530
    FORCE_RET();
531
}
532

    
533
/* Worker routines for zip and unzip.  */
534
void HELPER(neon_unzip_u8)(void)
535
{
536
    uint32_t rd;
537
    uint32_t rm;
538
    rd = (T0 & 0xff) | ((T0 >> 8) & 0xff00)
539
         | ((T1 << 16) & 0xff0000) | ((T1 << 8) & 0xff000000);
540
    rm = ((T0 >> 8) & 0xff) | ((T0 >> 16) & 0xff00)
541
         | ((T1 << 8) & 0xff0000) | (T1 & 0xff000000);
542
    T0 = rd;
543
    T1 = rm;
544
    FORCE_RET();
545
}
546

    
547
void HELPER(neon_zip_u8)(void)
548
{
549
    uint32_t rd;
550
    uint32_t rm;
551
    rd = (T0 & 0xff) | ((T1 << 8) & 0xff00)
552
         | ((T0 << 16) & 0xff0000) | ((T1 << 24) & 0xff000000);
553
    rm = ((T0 >> 16) & 0xff) | ((T1 >> 8) & 0xff00)
554
         | ((T0 >> 8) & 0xff0000) | (T1 & 0xff000000);
555
    T0 = rd;
556
    T1 = rm;
557
    FORCE_RET();
558
}
559

    
560
void HELPER(neon_zip_u16)(void)
561
{
562
    uint32_t tmp;
563

    
564
    tmp = (T0 & 0xffff) | (T1 << 16);
565
    T1 = (T1 & 0xffff0000) | (T0 >> 16);
566
    T0 = tmp;
567
    FORCE_RET();
568
}