Statistics
| Branch: | Revision:

root / target-arm / op_helper.c @ 06e80fc9

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
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

    
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 (__builtin_expect(ret, 0)) {
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
    shift = PARAM1;
189
    top = val >> shift;
190
    mask = (1u << shift) - 1;
191
    if (top > 0) {
192
        env->QF = 1;
193
        return mask;
194
    } else if (top < -1) {
195
        env->QF = 1;
196
        return ~mask;
197
    }
198
    return val;
199
}
200

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
359
/* Similarly for variable shift instructions.  */
360

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

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

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

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

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

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

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

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

    
453
uint64_t HELPER(neon_add_saturate_s64)(uint64_t src1, uint64_t src2)
454
{
455
    uint64_t res;
456

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

    
465
uint64_t HELPER(neon_add_saturate_u64)(uint64_t src1, uint64_t src2)
466
{
467
    uint64_t res;
468

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

    
477
uint64_t HELPER(neon_sub_saturate_s64)(uint64_t src1, uint64_t src2)
478
{
479
    uint64_t res;
480

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

    
489
uint64_t HELPER(neon_sub_saturate_u64)(uint64_t src1, uint64_t src2)
490
{
491
    uint64_t res;
492

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

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

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

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

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

    
555
void HELPER(neon_zip_u16)(void)
556
{
557
    uint32_t tmp;
558

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