Statistics
| Branch: | Revision:

root / target-arm / op_helper.c @ 8984bd2e

History | View | Annotate | Download (9.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, 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
void raise_exception(int tt)
24
{
25
    env->exception_index = tt;
26
    cpu_loop_exit();
27
}
28

    
29
/* thread support */
30

    
31
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
32

    
33
void cpu_lock(void)
34
{
35
    spin_lock(&global_cpu_lock);
36
}
37

    
38
void cpu_unlock(void)
39
{
40
    spin_unlock(&global_cpu_lock);
41
}
42

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

    
66
#if !defined(CONFIG_USER_ONLY)
67

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

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

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

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

    
84
#define SHIFT 3
85
#include "softmmu_template.h"
86

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

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

    
120
#define SIGNBIT (uint32_t)0x80000000
121
uint32_t HELPER(add_setq)(uint32_t a, uint32_t b)
122
{
123
    uint32_t res = a + b;
124
    if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT))
125
        env->QF = 1;
126
    return res;
127
}
128

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
361
/* Similarly for variable shift instructions.  */
362

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

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

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

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

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

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

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

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