Statistics
| Branch: | Revision:

root / target-arm / op.c @ d9ba4830

History | View | Annotate | Download (13.4 kB)

1
/*
2
 *  ARM micro operations
3
 *
4
 *  Copyright (c) 2003 Fabrice Bellard
5
 *  Copyright (c) 2005-2007 CodeSourcery, LLC
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2 of the License, or (at your option) any later version.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 */
21
#include "exec.h"
22

    
23
void OPPROTO op_addl_T0_T1_cc(void)
24
{
25
    unsigned int src1;
26
    src1 = T0;
27
    T0 += T1;
28
    env->NZF = T0;
29
    env->CF = T0 < src1;
30
    env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0);
31
}
32

    
33
void OPPROTO op_adcl_T0_T1_cc(void)
34
{
35
    unsigned int src1;
36
    src1 = T0;
37
    if (!env->CF) {
38
        T0 += T1;
39
        env->CF = T0 < src1;
40
    } else {
41
        T0 += T1 + 1;
42
        env->CF = T0 <= src1;
43
    }
44
    env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0);
45
    env->NZF = T0;
46
    FORCE_RET();
47
}
48

    
49
#define OPSUB(sub, sbc, res, T0, T1)            \
50
                                                \
51
void OPPROTO op_ ## sub ## l_T0_T1_cc(void)     \
52
{                                               \
53
    unsigned int src1;                          \
54
    src1 = T0;                                  \
55
    T0 -= T1;                                   \
56
    env->NZF = T0;                              \
57
    env->CF = src1 >= T1;                       \
58
    env->VF = (src1 ^ T1) & (src1 ^ T0);        \
59
    res = T0;                                   \
60
}                                               \
61
                                                \
62
void OPPROTO op_ ## sbc ## l_T0_T1_cc(void)     \
63
{                                               \
64
    unsigned int src1;                          \
65
    src1 = T0;                                  \
66
    if (!env->CF) {                             \
67
        T0 = T0 - T1 - 1;                       \
68
        env->CF = src1 > T1;                    \
69
    } else {                                    \
70
        T0 = T0 - T1;                           \
71
        env->CF = src1 >= T1;                   \
72
    }                                           \
73
    env->VF = (src1 ^ T1) & (src1 ^ T0);        \
74
    env->NZF = T0;                              \
75
    res = T0;                                   \
76
    FORCE_RET();                                \
77
}
78

    
79
OPSUB(sub, sbc, T0, T0, T1)
80

    
81
OPSUB(rsb, rsc, T0, T1, T0)
82

    
83
void OPPROTO op_addq_T0_T1(void)
84
{
85
    uint64_t res;
86
    res = ((uint64_t)T1 << 32) | T0;
87
    res += ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]);
88
    T1 = res >> 32;
89
    T0 = res;
90
}
91

    
92
void OPPROTO op_addq_lo_T0_T1(void)
93
{
94
    uint64_t res;
95
    res = ((uint64_t)T1 << 32) | T0;
96
    res += (uint64_t)(env->regs[PARAM1]);
97
    T1 = res >> 32;
98
    T0 = res;
99
}
100

    
101
/* Dual 16-bit accumulate.  */
102
void OPPROTO op_addq_T0_T1_dual(void)
103
{
104
  uint64_t res;
105
  res = ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]);
106
  res += (int32_t)T0;
107
  res += (int32_t)T1;
108
  env->regs[PARAM1] = (uint32_t)res;
109
  env->regs[PARAM2] = res >> 32;
110
}
111

    
112
/* Dual 16-bit subtract accumulate.  */
113
void OPPROTO op_subq_T0_T1_dual(void)
114
{
115
  uint64_t res;
116
  res = ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]);
117
  res += (int32_t)T0;
118
  res -= (int32_t)T1;
119
  env->regs[PARAM1] = (uint32_t)res;
120
  env->regs[PARAM2] = res >> 32;
121
}
122

    
123
void OPPROTO op_logicq_cc(void)
124
{
125
    env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0);
126
}
127

    
128
/* memory access */
129

    
130
#define MEMSUFFIX _raw
131
#include "op_mem.h"
132

    
133
#if !defined(CONFIG_USER_ONLY)
134
#define MEMSUFFIX _user
135
#include "op_mem.h"
136
#define MEMSUFFIX _kernel
137
#include "op_mem.h"
138
#endif
139

    
140
void OPPROTO op_clrex(void)
141
{
142
    cpu_lock();
143
    helper_clrex(env);
144
    cpu_unlock();
145
}
146

    
147
/* T1 based, use T0 as shift count */
148

    
149
void OPPROTO op_shll_T1_T0(void)
150
{
151
    int shift;
152
    shift = T0 & 0xff;
153
    if (shift >= 32)
154
        T1 = 0;
155
    else
156
        T1 = T1 << shift;
157
    FORCE_RET();
158
}
159

    
160
void OPPROTO op_shrl_T1_T0(void)
161
{
162
    int shift;
163
    shift = T0 & 0xff;
164
    if (shift >= 32)
165
        T1 = 0;
166
    else
167
        T1 = (uint32_t)T1 >> shift;
168
    FORCE_RET();
169
}
170

    
171
void OPPROTO op_sarl_T1_T0(void)
172
{
173
    int shift;
174
    shift = T0 & 0xff;
175
    if (shift >= 32)
176
        shift = 31;
177
    T1 = (int32_t)T1 >> shift;
178
}
179

    
180
void OPPROTO op_rorl_T1_T0(void)
181
{
182
    int shift;
183
    shift = T0 & 0x1f;
184
    if (shift) {
185
        T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
186
    }
187
    FORCE_RET();
188
}
189

    
190
/* T1 based, use T0 as shift count and compute CF */
191

    
192
void OPPROTO op_shll_T1_T0_cc(void)
193
{
194
    int shift;
195
    shift = T0 & 0xff;
196
    if (shift >= 32) {
197
        if (shift == 32)
198
            env->CF = T1 & 1;
199
        else
200
            env->CF = 0;
201
        T1 = 0;
202
    } else if (shift != 0) {
203
        env->CF = (T1 >> (32 - shift)) & 1;
204
        T1 = T1 << shift;
205
    }
206
    FORCE_RET();
207
}
208

    
209
void OPPROTO op_shrl_T1_T0_cc(void)
210
{
211
    int shift;
212
    shift = T0 & 0xff;
213
    if (shift >= 32) {
214
        if (shift == 32)
215
            env->CF = (T1 >> 31) & 1;
216
        else
217
            env->CF = 0;
218
        T1 = 0;
219
    } else if (shift != 0) {
220
        env->CF = (T1 >> (shift - 1)) & 1;
221
        T1 = (uint32_t)T1 >> shift;
222
    }
223
    FORCE_RET();
224
}
225

    
226
void OPPROTO op_sarl_T1_T0_cc(void)
227
{
228
    int shift;
229
    shift = T0 & 0xff;
230
    if (shift >= 32) {
231
        env->CF = (T1 >> 31) & 1;
232
        T1 = (int32_t)T1 >> 31;
233
    } else if (shift != 0) {
234
        env->CF = (T1 >> (shift - 1)) & 1;
235
        T1 = (int32_t)T1 >> shift;
236
    }
237
    FORCE_RET();
238
}
239

    
240
void OPPROTO op_rorl_T1_T0_cc(void)
241
{
242
    int shift1, shift;
243
    shift1 = T0 & 0xff;
244
    shift = shift1 & 0x1f;
245
    if (shift == 0) {
246
        if (shift1 != 0)
247
            env->CF = (T1 >> 31) & 1;
248
    } else {
249
        env->CF = (T1 >> (shift - 1)) & 1;
250
        T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift));
251
    }
252
    FORCE_RET();
253
}
254

    
255
/* VFP support.  We follow the convention used for VFP instrunctions:
256
   Single precition routines have a "s" suffix, double precision a
257
   "d" suffix.  */
258

    
259
#define VFP_OP(name, p) void OPPROTO op_vfp_##name##p(void)
260

    
261
#define VFP_BINOP(name) \
262
VFP_OP(name, s)             \
263
{                           \
264
    FT0s = float32_ ## name (FT0s, FT1s, &env->vfp.fp_status);    \
265
}                           \
266
VFP_OP(name, d)             \
267
{                           \
268
    FT0d = float64_ ## name (FT0d, FT1d, &env->vfp.fp_status);    \
269
}
270
VFP_BINOP(add)
271
VFP_BINOP(sub)
272
VFP_BINOP(mul)
273
VFP_BINOP(div)
274
#undef VFP_BINOP
275

    
276
#define VFP_HELPER(name)  \
277
VFP_OP(name, s)           \
278
{                         \
279
    do_vfp_##name##s();    \
280
}                         \
281
VFP_OP(name, d)           \
282
{                         \
283
    do_vfp_##name##d();    \
284
}
285
VFP_HELPER(abs)
286
VFP_HELPER(sqrt)
287
VFP_HELPER(cmp)
288
VFP_HELPER(cmpe)
289
#undef VFP_HELPER
290

    
291
/* XXX: Will this do the right thing for NANs.  Should invert the signbit
292
   without looking at the rest of the value.  */
293
VFP_OP(neg, s)
294
{
295
    FT0s = float32_chs(FT0s);
296
}
297

    
298
VFP_OP(neg, d)
299
{
300
    FT0d = float64_chs(FT0d);
301
}
302

    
303
VFP_OP(F1_ld0, s)
304
{
305
    union {
306
        uint32_t i;
307
        float32 s;
308
    } v;
309
    v.i = 0;
310
    FT1s = v.s;
311
}
312

    
313
VFP_OP(F1_ld0, d)
314
{
315
    union {
316
        uint64_t i;
317
        float64 d;
318
    } v;
319
    v.i = 0;
320
    FT1d = v.d;
321
}
322

    
323
/* Helper routines to perform bitwise copies between float and int.  */
324
static inline float32 vfp_itos(uint32_t i)
325
{
326
    union {
327
        uint32_t i;
328
        float32 s;
329
    } v;
330

    
331
    v.i = i;
332
    return v.s;
333
}
334

    
335
static inline uint32_t vfp_stoi(float32 s)
336
{
337
    union {
338
        uint32_t i;
339
        float32 s;
340
    } v;
341

    
342
    v.s = s;
343
    return v.i;
344
}
345

    
346
static inline float64 vfp_itod(uint64_t i)
347
{
348
    union {
349
        uint64_t i;
350
        float64 d;
351
    } v;
352

    
353
    v.i = i;
354
    return v.d;
355
}
356

    
357
static inline uint64_t vfp_dtoi(float64 d)
358
{
359
    union {
360
        uint64_t i;
361
        float64 d;
362
    } v;
363

    
364
    v.d = d;
365
    return v.i;
366
}
367

    
368
/* Integer to float conversion.  */
369
VFP_OP(uito, s)
370
{
371
    FT0s = uint32_to_float32(vfp_stoi(FT0s), &env->vfp.fp_status);
372
}
373

    
374
VFP_OP(uito, d)
375
{
376
    FT0d = uint32_to_float64(vfp_stoi(FT0s), &env->vfp.fp_status);
377
}
378

    
379
VFP_OP(sito, s)
380
{
381
    FT0s = int32_to_float32(vfp_stoi(FT0s), &env->vfp.fp_status);
382
}
383

    
384
VFP_OP(sito, d)
385
{
386
    FT0d = int32_to_float64(vfp_stoi(FT0s), &env->vfp.fp_status);
387
}
388

    
389
/* Float to integer conversion.  */
390
VFP_OP(toui, s)
391
{
392
    FT0s = vfp_itos(float32_to_uint32(FT0s, &env->vfp.fp_status));
393
}
394

    
395
VFP_OP(toui, d)
396
{
397
    FT0s = vfp_itos(float64_to_uint32(FT0d, &env->vfp.fp_status));
398
}
399

    
400
VFP_OP(tosi, s)
401
{
402
    FT0s = vfp_itos(float32_to_int32(FT0s, &env->vfp.fp_status));
403
}
404

    
405
VFP_OP(tosi, d)
406
{
407
    FT0s = vfp_itos(float64_to_int32(FT0d, &env->vfp.fp_status));
408
}
409

    
410
/* TODO: Set rounding mode properly.  */
411
VFP_OP(touiz, s)
412
{
413
    FT0s = vfp_itos(float32_to_uint32_round_to_zero(FT0s, &env->vfp.fp_status));
414
}
415

    
416
VFP_OP(touiz, d)
417
{
418
    FT0s = vfp_itos(float64_to_uint32_round_to_zero(FT0d, &env->vfp.fp_status));
419
}
420

    
421
VFP_OP(tosiz, s)
422
{
423
    FT0s = vfp_itos(float32_to_int32_round_to_zero(FT0s, &env->vfp.fp_status));
424
}
425

    
426
VFP_OP(tosiz, d)
427
{
428
    FT0s = vfp_itos(float64_to_int32_round_to_zero(FT0d, &env->vfp.fp_status));
429
}
430

    
431
/* floating point conversion */
432
VFP_OP(fcvtd, s)
433
{
434
    FT0d = float32_to_float64(FT0s, &env->vfp.fp_status);
435
}
436

    
437
VFP_OP(fcvts, d)
438
{
439
    FT0s = float64_to_float32(FT0d, &env->vfp.fp_status);
440
}
441

    
442
/* VFP3 fixed point conversion.  */
443
#define VFP_CONV_FIX(name, p, ftype, itype, sign) \
444
VFP_OP(name##to, p) \
445
{ \
446
    ftype tmp; \
447
    tmp = sign##int32_to_##ftype ((itype)vfp_##p##toi(FT0##p), \
448
                                  &env->vfp.fp_status); \
449
    FT0##p = ftype##_scalbn(tmp, PARAM1, &env->vfp.fp_status); \
450
} \
451
VFP_OP(to##name, p) \
452
{ \
453
    ftype tmp; \
454
    tmp = ftype##_scalbn(FT0##p, PARAM1, &env->vfp.fp_status); \
455
    FT0##p = vfp_ito##p((itype)ftype##_to_##sign##int32_round_to_zero(tmp, \
456
            &env->vfp.fp_status)); \
457
}
458

    
459
VFP_CONV_FIX(sh, d, float64, int16, )
460
VFP_CONV_FIX(sl, d, float64, int32, )
461
VFP_CONV_FIX(uh, d, float64, uint16, u)
462
VFP_CONV_FIX(ul, d, float64, uint32, u)
463
VFP_CONV_FIX(sh, s, float32, int16, )
464
VFP_CONV_FIX(sl, s, float32, int32, )
465
VFP_CONV_FIX(uh, s, float32, uint16, u)
466
VFP_CONV_FIX(ul, s, float32, uint32, u)
467

    
468
/* Get and Put values from registers.  */
469
VFP_OP(getreg_F0, d)
470
{
471
  FT0d = *(float64 *)((char *) env + PARAM1);
472
}
473

    
474
VFP_OP(getreg_F0, s)
475
{
476
  FT0s = *(float32 *)((char *) env + PARAM1);
477
}
478

    
479
VFP_OP(getreg_F1, d)
480
{
481
  FT1d = *(float64 *)((char *) env + PARAM1);
482
}
483

    
484
VFP_OP(getreg_F1, s)
485
{
486
  FT1s = *(float32 *)((char *) env + PARAM1);
487
}
488

    
489
VFP_OP(setreg_F0, d)
490
{
491
  *(float64 *)((char *) env + PARAM1) = FT0d;
492
}
493

    
494
VFP_OP(setreg_F0, s)
495
{
496
  *(float32 *)((char *) env + PARAM1) = FT0s;
497
}
498

    
499
void OPPROTO op_vfp_movl_T0_fpscr(void)
500
{
501
    do_vfp_get_fpscr ();
502
}
503

    
504
void OPPROTO op_vfp_movl_T0_fpscr_flags(void)
505
{
506
    T0 = env->vfp.xregs[ARM_VFP_FPSCR] & (0xf << 28);
507
}
508

    
509
void OPPROTO op_vfp_movl_fpscr_T0(void)
510
{
511
    do_vfp_set_fpscr();
512
}
513

    
514
void OPPROTO op_vfp_movl_T0_xreg(void)
515
{
516
    T0 = env->vfp.xregs[PARAM1];
517
}
518

    
519
void OPPROTO op_vfp_movl_xreg_T0(void)
520
{
521
    env->vfp.xregs[PARAM1] = T0;
522
}
523

    
524
/* Move between FT0s to T0  */
525
void OPPROTO op_vfp_mrs(void)
526
{
527
    T0 = vfp_stoi(FT0s);
528
}
529

    
530
void OPPROTO op_vfp_msr(void)
531
{
532
    FT0s = vfp_itos(T0);
533
}
534

    
535
/* Move between FT0d and {T0,T1} */
536
void OPPROTO op_vfp_mrrd(void)
537
{
538
    CPU_DoubleU u;
539

    
540
    u.d = FT0d;
541
    T0 = u.l.lower;
542
    T1 = u.l.upper;
543
}
544

    
545
void OPPROTO op_vfp_mdrr(void)
546
{
547
    CPU_DoubleU u;
548

    
549
    u.l.lower = T0;
550
    u.l.upper = T1;
551
    FT0d = u.d;
552
}
553

    
554
/* Load immediate.  PARAM1 is the 32 most significant bits of the value.  */
555
void OPPROTO op_vfp_fconstd(void)
556
{
557
    CPU_DoubleU u;
558
    u.l.upper = PARAM1;
559
    u.l.lower = 0;
560
    FT0d = u.d;
561
}
562

    
563
void OPPROTO op_vfp_fconsts(void)
564
{
565
    FT0s = vfp_itos(PARAM1);
566
}
567

    
568
void OPPROTO op_movl_cp_T0(void)
569
{
570
    helper_set_cp(env, PARAM1, T0);
571
    FORCE_RET();
572
}
573

    
574
void OPPROTO op_movl_T0_cp(void)
575
{
576
    T0 = helper_get_cp(env, PARAM1);
577
    FORCE_RET();
578
}
579

    
580
void OPPROTO op_movl_cp15_T0(void)
581
{
582
    helper_set_cp15(env, PARAM1, T0);
583
    FORCE_RET();
584
}
585

    
586
void OPPROTO op_movl_T0_cp15(void)
587
{
588
    T0 = helper_get_cp15(env, PARAM1);
589
    FORCE_RET();
590
}
591

    
592
/* Access to user mode registers from privileged modes.  */
593
void OPPROTO op_movl_T0_user(void)
594
{
595
    int regno = PARAM1;
596
    if (regno == 13) {
597
        T0 = env->banked_r13[0];
598
    } else if (regno == 14) {
599
        T0 = env->banked_r14[0];
600
    } else if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
601
        T0 = env->usr_regs[regno - 8];
602
    } else {
603
        T0 = env->regs[regno];
604
    }
605
    FORCE_RET();
606
}
607

    
608

    
609
void OPPROTO op_movl_user_T0(void)
610
{
611
    int regno = PARAM1;
612
    if (regno == 13) {
613
        env->banked_r13[0] = T0;
614
    } else if (regno == 14) {
615
        env->banked_r14[0] = T0;
616
    } else if ((env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_FIQ) {
617
        env->usr_regs[regno - 8] = T0;
618
    } else {
619
        env->regs[regno] = T0;
620
    }
621
    FORCE_RET();
622
}
623

    
624
void OPPROTO op_movl_T1_r13_banked(void)
625
{
626
    T1 = helper_get_r13_banked(env, PARAM1);
627
}
628

    
629
void OPPROTO op_movl_r13_T1_banked(void)
630
{
631
    helper_set_r13_banked(env, PARAM1, T1);
632
}
633

    
634
void OPPROTO op_v7m_mrs_T0(void)
635
{
636
    T0 = helper_v7m_mrs(env, PARAM1);
637
}
638

    
639
void OPPROTO op_v7m_msr_T0(void)
640
{
641
    helper_v7m_msr(env, PARAM1, T0);
642
}
643

    
644
void OPPROTO op_movl_T0_sp(void)
645
{
646
    if (PARAM1 == env->v7m.current_sp)
647
        T0 = env->regs[13];
648
    else
649
        T0 = env->v7m.other_sp;
650
    FORCE_RET();
651
}
652

    
653
#include "op_neon.h"
654

    
655
/* iwMMXt support */
656
#include "op_iwmmxt.c"