Statistics
| Branch: | Revision:

root / target-arm / op_helper.c @ b1d8e52e

History | View | Annotate | Download (12.4 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
static 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) << 3)) & 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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
515
void HELPER(neon_trn_u16)(void)
516
{
517
    uint32_t rd;
518
    uint32_t rm;
519
    rd = (T0 << 16) | (T1 & 0xffff);
520
    rm = (T1 >> 16) | (T0 & 0xffff0000);
521
    T0 = rd;
522
    T1 = rm;
523
    FORCE_RET();
524
}
525

    
526
/* Worker routines for zip and unzip.  */
527
void HELPER(neon_unzip_u8)(void)
528
{
529
    uint32_t rd;
530
    uint32_t rm;
531
    rd = (T0 & 0xff) | ((T0 >> 8) & 0xff00)
532
         | ((T1 << 16) & 0xff0000) | ((T1 << 8) & 0xff000000);
533
    rm = ((T0 >> 8) & 0xff) | ((T0 >> 16) & 0xff00)
534
         | ((T1 << 8) & 0xff0000) | (T1 & 0xff000000);
535
    T0 = rd;
536
    T1 = rm;
537
    FORCE_RET();
538
}
539

    
540
void HELPER(neon_zip_u8)(void)
541
{
542
    uint32_t rd;
543
    uint32_t rm;
544
    rd = (T0 & 0xff) | ((T1 << 8) & 0xff00)
545
         | ((T0 << 16) & 0xff0000) | ((T1 << 24) & 0xff000000);
546
    rm = ((T0 >> 16) & 0xff) | ((T1 >> 8) & 0xff00)
547
         | ((T0 >> 8) & 0xff0000) | (T1 & 0xff000000);
548
    T0 = rd;
549
    T1 = rm;
550
    FORCE_RET();
551
}
552

    
553
void HELPER(neon_zip_u16)(void)
554
{
555
    uint32_t tmp;
556

    
557
    tmp = (T0 & 0xffff) | (T1 << 16);
558
    T1 = (T1 & 0xffff0000) | (T0 >> 16);
559
    T0 = tmp;
560
    FORCE_RET();
561
}