Statistics
| Branch: | Revision:

root / target-arm / op_helper.c @ 49b4c31e

History | View | Annotate | Download (9.2 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 "cpu.h"
20
#include "helper.h"
21

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

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

    
31
uint32_t HELPER(neon_tbl)(CPUARMState *env, uint32_t ireg, uint32_t def,
32
                          uint32_t rn, uint32_t maxindex)
33
{
34
    uint32_t val;
35
    uint32_t tmp;
36
    int index;
37
    int shift;
38
    uint64_t *table;
39
    table = (uint64_t *)&env->vfp.regs[rn];
40
    val = 0;
41
    for (shift = 0; shift < 32; shift += 8) {
42
        index = (ireg >> shift) & 0xff;
43
        if (index < maxindex) {
44
            tmp = (table[index >> 3] >> ((index & 7) << 3)) & 0xff;
45
            val |= tmp << shift;
46
        } else {
47
            val |= def & (0xff << shift);
48
        }
49
    }
50
    return val;
51
}
52

    
53
#if !defined(CONFIG_USER_ONLY)
54

    
55
#include "exec/softmmu_exec.h"
56

    
57
#define MMUSUFFIX _mmu
58

    
59
#define SHIFT 0
60
#include "exec/softmmu_template.h"
61

    
62
#define SHIFT 1
63
#include "exec/softmmu_template.h"
64

    
65
#define SHIFT 2
66
#include "exec/softmmu_template.h"
67

    
68
#define SHIFT 3
69
#include "exec/softmmu_template.h"
70

    
71
/* try to fill the TLB and return an exception if error. If retaddr is
72
   NULL, it means that the function was called in C code (i.e. not
73
   from generated code or from helper.c) */
74
void tlb_fill(CPUARMState *env, target_ulong addr, int is_write, int mmu_idx,
75
              uintptr_t retaddr)
76
{
77
    int ret;
78

    
79
    ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx);
80
    if (unlikely(ret)) {
81
        if (retaddr) {
82
            /* now we have a real cpu fault */
83
            cpu_restore_state(env, retaddr);
84
        }
85
        raise_exception(env, env->exception_index);
86
    }
87
}
88
#endif
89

    
90
uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b)
91
{
92
    uint32_t res = a + b;
93
    if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT))
94
        env->QF = 1;
95
    return res;
96
}
97

    
98
uint32_t HELPER(add_saturate)(CPUARMState *env, uint32_t a, uint32_t b)
99
{
100
    uint32_t res = a + b;
101
    if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) {
102
        env->QF = 1;
103
        res = ~(((int32_t)a >> 31) ^ SIGNBIT);
104
    }
105
    return res;
106
}
107

    
108
uint32_t HELPER(sub_saturate)(CPUARMState *env, uint32_t a, uint32_t b)
109
{
110
    uint32_t res = a - b;
111
    if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) {
112
        env->QF = 1;
113
        res = ~(((int32_t)a >> 31) ^ SIGNBIT);
114
    }
115
    return res;
116
}
117

    
118
uint32_t HELPER(double_saturate)(CPUARMState *env, int32_t val)
119
{
120
    uint32_t res;
121
    if (val >= 0x40000000) {
122
        res = ~SIGNBIT;
123
        env->QF = 1;
124
    } else if (val <= (int32_t)0xc0000000) {
125
        res = SIGNBIT;
126
        env->QF = 1;
127
    } else {
128
        res = val << 1;
129
    }
130
    return res;
131
}
132

    
133
uint32_t HELPER(add_usaturate)(CPUARMState *env, uint32_t a, uint32_t b)
134
{
135
    uint32_t res = a + b;
136
    if (res < a) {
137
        env->QF = 1;
138
        res = ~0;
139
    }
140
    return res;
141
}
142

    
143
uint32_t HELPER(sub_usaturate)(CPUARMState *env, uint32_t a, uint32_t b)
144
{
145
    uint32_t res = a - b;
146
    if (res > a) {
147
        env->QF = 1;
148
        res = 0;
149
    }
150
    return res;
151
}
152

    
153
/* Signed saturation.  */
154
static inline uint32_t do_ssat(CPUARMState *env, int32_t val, int shift)
155
{
156
    int32_t top;
157
    uint32_t mask;
158

    
159
    top = val >> shift;
160
    mask = (1u << shift) - 1;
161
    if (top > 0) {
162
        env->QF = 1;
163
        return mask;
164
    } else if (top < -1) {
165
        env->QF = 1;
166
        return ~mask;
167
    }
168
    return val;
169
}
170

    
171
/* Unsigned saturation.  */
172
static inline uint32_t do_usat(CPUARMState *env, int32_t val, int shift)
173
{
174
    uint32_t max;
175

    
176
    max = (1u << shift) - 1;
177
    if (val < 0) {
178
        env->QF = 1;
179
        return 0;
180
    } else if (val > max) {
181
        env->QF = 1;
182
        return max;
183
    }
184
    return val;
185
}
186

    
187
/* Signed saturate.  */
188
uint32_t HELPER(ssat)(CPUARMState *env, uint32_t x, uint32_t shift)
189
{
190
    return do_ssat(env, x, shift);
191
}
192

    
193
/* Dual halfword signed saturate.  */
194
uint32_t HELPER(ssat16)(CPUARMState *env, uint32_t x, uint32_t shift)
195
{
196
    uint32_t res;
197

    
198
    res = (uint16_t)do_ssat(env, (int16_t)x, shift);
199
    res |= do_ssat(env, ((int32_t)x) >> 16, shift) << 16;
200
    return res;
201
}
202

    
203
/* Unsigned saturate.  */
204
uint32_t HELPER(usat)(CPUARMState *env, uint32_t x, uint32_t shift)
205
{
206
    return do_usat(env, x, shift);
207
}
208

    
209
/* Dual halfword unsigned saturate.  */
210
uint32_t HELPER(usat16)(CPUARMState *env, uint32_t x, uint32_t shift)
211
{
212
    uint32_t res;
213

    
214
    res = (uint16_t)do_usat(env, (int16_t)x, shift);
215
    res |= do_usat(env, ((int32_t)x) >> 16, shift) << 16;
216
    return res;
217
}
218

    
219
void HELPER(wfi)(CPUARMState *env)
220
{
221
    env->exception_index = EXCP_HLT;
222
    env->halted = 1;
223
    cpu_loop_exit(env);
224
}
225

    
226
void HELPER(exception)(CPUARMState *env, uint32_t excp)
227
{
228
    env->exception_index = excp;
229
    cpu_loop_exit(env);
230
}
231

    
232
uint32_t HELPER(cpsr_read)(CPUARMState *env)
233
{
234
    return cpsr_read(env) & ~CPSR_EXEC;
235
}
236

    
237
void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask)
238
{
239
    cpsr_write(env, val, mask);
240
}
241

    
242
/* Access to user mode registers from privileged modes.  */
243
uint32_t HELPER(get_user_reg)(CPUARMState *env, uint32_t regno)
244
{
245
    uint32_t val;
246

    
247
    if (regno == 13) {
248
        val = env->banked_r13[0];
249
    } else if (regno == 14) {
250
        val = env->banked_r14[0];
251
    } else if (regno >= 8
252
               && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
253
        val = env->usr_regs[regno - 8];
254
    } else {
255
        val = env->regs[regno];
256
    }
257
    return val;
258
}
259

    
260
void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val)
261
{
262
    if (regno == 13) {
263
        env->banked_r13[0] = val;
264
    } else if (regno == 14) {
265
        env->banked_r14[0] = val;
266
    } else if (regno >= 8
267
               && (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
268
        env->usr_regs[regno - 8] = val;
269
    } else {
270
        env->regs[regno] = val;
271
    }
272
}
273

    
274
void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value)
275
{
276
    const ARMCPRegInfo *ri = rip;
277
    int excp = ri->writefn(env, ri, value);
278
    if (excp) {
279
        raise_exception(env, excp);
280
    }
281
}
282

    
283
uint32_t HELPER(get_cp_reg)(CPUARMState *env, void *rip)
284
{
285
    const ARMCPRegInfo *ri = rip;
286
    uint64_t value;
287
    int excp = ri->readfn(env, ri, &value);
288
    if (excp) {
289
        raise_exception(env, excp);
290
    }
291
    return value;
292
}
293

    
294
void HELPER(set_cp_reg64)(CPUARMState *env, void *rip, uint64_t value)
295
{
296
    const ARMCPRegInfo *ri = rip;
297
    int excp = ri->writefn(env, ri, value);
298
    if (excp) {
299
        raise_exception(env, excp);
300
    }
301
}
302

    
303
uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip)
304
{
305
    const ARMCPRegInfo *ri = rip;
306
    uint64_t value;
307
    int excp = ri->readfn(env, ri, &value);
308
    if (excp) {
309
        raise_exception(env, excp);
310
    }
311
    return value;
312
}
313

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

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

    
333
/* Similarly for variable shift instructions.  */
334

    
335
uint32_t HELPER(shl_cc)(CPUARMState *env, uint32_t x, uint32_t i)
336
{
337
    int shift = i & 0xff;
338
    if (shift >= 32) {
339
        if (shift == 32)
340
            env->CF = x & 1;
341
        else
342
            env->CF = 0;
343
        return 0;
344
    } else if (shift != 0) {
345
        env->CF = (x >> (32 - shift)) & 1;
346
        return x << shift;
347
    }
348
    return x;
349
}
350

    
351
uint32_t HELPER(shr_cc)(CPUARMState *env, uint32_t x, uint32_t i)
352
{
353
    int shift = i & 0xff;
354
    if (shift >= 32) {
355
        if (shift == 32)
356
            env->CF = (x >> 31) & 1;
357
        else
358
            env->CF = 0;
359
        return 0;
360
    } else if (shift != 0) {
361
        env->CF = (x >> (shift - 1)) & 1;
362
        return x >> shift;
363
    }
364
    return x;
365
}
366

    
367
uint32_t HELPER(sar_cc)(CPUARMState *env, uint32_t x, uint32_t i)
368
{
369
    int shift = i & 0xff;
370
    if (shift >= 32) {
371
        env->CF = (x >> 31) & 1;
372
        return (int32_t)x >> 31;
373
    } else if (shift != 0) {
374
        env->CF = (x >> (shift - 1)) & 1;
375
        return (int32_t)x >> shift;
376
    }
377
    return x;
378
}
379

    
380
uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i)
381
{
382
    int shift1, shift;
383
    shift1 = i & 0xff;
384
    shift = shift1 & 0x1f;
385
    if (shift == 0) {
386
        if (shift1 != 0)
387
            env->CF = (x >> 31) & 1;
388
        return x;
389
    } else {
390
        env->CF = (x >> (shift - 1)) & 1;
391
        return ((uint32_t)x >> shift) | (x << (32 - shift));
392
    }
393
}