Statistics
| Branch: | Revision:

root / target-m68k / op.c @ 36bb244b

History | View | Annotate | Download (12.3 kB)

1
/*
2
 *  m68k micro operations
3
 * 
4
 *  Copyright (c) 2006 CodeSourcery
5
 *  Written by Paul Brook
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
 * 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

    
22
#include "exec.h"
23
#include "m68k-qreg.h"
24

    
25
#ifndef offsetof
26
#define offsetof(type, field) ((size_t) &((type *)0)->field)
27
#endif
28

    
29
static long qreg_offsets[] = {
30
#define DEFO32(name, offset) offsetof(CPUState, offset),
31
#define DEFR(name, reg, mode) -1,
32
#define DEFF64(name, offset) offsetof(CPUState, offset),
33
    0,
34
#include "qregs.def"
35
};
36

    
37
#define CPU_FP_STATUS env->fp_status
38

    
39
#define RAISE_EXCEPTION(n) do { \
40
    env->exception_index = n; \
41
    cpu_loop_exit(); \
42
    } while(0)
43

    
44
#define get_op helper_get_op
45
#define set_op helper_set_op
46
#define get_opf64 helper_get_opf64
47
#define set_opf64 helper_set_opf64
48
uint32_t
49
get_op(int qreg)
50
{
51
    if (qreg == QREG_T0) {
52
        return T0;
53
    } else if (qreg < TARGET_NUM_QREGS) {
54
        return *(uint32_t *)(((long)env) + qreg_offsets[qreg]);
55
    } else {
56
        return env->qregs[qreg - TARGET_NUM_QREGS];
57
    }
58
}
59

    
60
void set_op(int qreg, uint32_t val)
61
{
62
    if (qreg == QREG_T0) {
63
        T0 = val;
64
    } else if (qreg < TARGET_NUM_QREGS) {
65
        *(uint32_t *)(((long)env) + qreg_offsets[qreg]) = val;
66
    } else {
67
        env->qregs[qreg - TARGET_NUM_QREGS] = val;
68
    }
69
}
70

    
71
float64 get_opf64(int qreg)
72
{
73
    if (qreg < TARGET_NUM_QREGS) {
74
        return *(float64 *)(((long)env) + qreg_offsets[qreg]);
75
    } else {
76
        return *(float64 *)&env->qregs[qreg - TARGET_NUM_QREGS];
77
    }
78
}
79

    
80
void set_opf64(int qreg, float64 val)
81
{
82
    if (qreg < TARGET_NUM_QREGS) {
83
        *(float64 *)(((long)env) + qreg_offsets[qreg]) = val;
84
    } else {
85
        *(float64 *)&env->qregs[qreg - TARGET_NUM_QREGS] = val;
86
    }
87
}
88

    
89
#define OP(name) void OPPROTO op_##name (void)
90

    
91
OP(mov32)
92
{
93
    set_op(PARAM1, get_op(PARAM2));
94
    FORCE_RET();
95
}
96

    
97
OP(mov32_im)
98
{
99
    set_op(PARAM1, PARAM2);
100
    FORCE_RET();
101
}
102

    
103
OP(movf64)
104
{
105
    set_opf64(PARAM1, get_opf64(PARAM2));
106
    FORCE_RET();
107
}
108

    
109
OP(zerof64)
110
{
111
    set_opf64(PARAM1, 0);
112
    FORCE_RET();
113
}
114

    
115
OP(add32)
116
{
117
    uint32_t op2 = get_op(PARAM2);
118
    uint32_t op3 = get_op(PARAM3);
119
    set_op(PARAM1, op2 + op3);
120
    FORCE_RET();
121
}
122

    
123
OP(sub32)
124
{
125
    uint32_t op2 = get_op(PARAM2);
126
    uint32_t op3 = get_op(PARAM3);
127
    set_op(PARAM1, op2 - op3);
128
    FORCE_RET();
129
}
130

    
131
OP(mul32)
132
{
133
    uint32_t op2 = get_op(PARAM2);
134
    uint32_t op3 = get_op(PARAM3);
135
    set_op(PARAM1, op2 * op3);
136
    FORCE_RET();
137
}
138

    
139
OP(not32)
140
{
141
    uint32_t arg = get_op(PARAM2);
142
    set_op(PARAM1, ~arg);
143
    FORCE_RET();
144
}
145

    
146
OP(neg32)
147
{
148
    uint32_t arg = get_op(PARAM2);
149
    set_op(PARAM1, -arg);
150
    FORCE_RET();
151
}
152

    
153
OP(bswap32)
154
{
155
    uint32_t arg = get_op(PARAM2);
156
    arg = (arg >> 24) | (arg << 24)
157
          | ((arg >> 16) & 0xff00) | ((arg << 16) & 0xff0000);
158
    set_op(PARAM1, arg);
159
    FORCE_RET();
160
}
161

    
162
OP(btest)
163
{
164
    uint32_t op1 = get_op(PARAM1);
165
    uint32_t op2 = get_op(PARAM2);
166
    if (op1 & op2)
167
        env->cc_dest &= ~CCF_Z;
168
    else
169
        env->cc_dest |= CCF_Z;
170
    FORCE_RET();
171
}
172

    
173
OP(addx_cc)
174
{
175
    uint32_t op1 = get_op(PARAM1);
176
    uint32_t op2 = get_op(PARAM2);
177
    uint32_t res;
178
    if (env->cc_x) {
179
        env->cc_x = (op1 <= op2);
180
        env->cc_op = CC_OP_SUBX;
181
        res = op1 - (op2 + 1);
182
    } else {
183
        env->cc_x = (op1 < op2);
184
        env->cc_op = CC_OP_SUB;
185
        res = op1 - op2;
186
    }
187
    set_op(PARAM1, res);
188
    FORCE_RET();
189
}
190

    
191
OP(subx_cc)
192
{
193
    uint32_t op1 = get_op(PARAM1);
194
    uint32_t op2 = get_op(PARAM2);
195
    uint32_t res;
196
    if (env->cc_x) {
197
        res = op1 + op2 + 1;
198
        env->cc_x = (res <= op2);
199
        env->cc_op = CC_OP_ADDX;
200
    } else {
201
        res = op1 + op2;
202
        env->cc_x = (res < op2);
203
        env->cc_op = CC_OP_ADD;
204
    }
205
    set_op(PARAM1, res);
206
    FORCE_RET();
207
}
208

    
209
/* Logic ops.  */
210

    
211
OP(and32)
212
{
213
    uint32_t op2 = get_op(PARAM2);
214
    uint32_t op3 = get_op(PARAM3);
215
    set_op(PARAM1, op2 & op3);
216
    FORCE_RET();
217
}
218

    
219
OP(or32)
220
{
221
    uint32_t op2 = get_op(PARAM2);
222
    uint32_t op3 = get_op(PARAM3);
223
    set_op(PARAM1, op2 | op3);
224
    FORCE_RET();
225
}
226

    
227
OP(xor32)
228
{
229
    uint32_t op2 = get_op(PARAM2);
230
    uint32_t op3 = get_op(PARAM3);
231
    set_op(PARAM1, op2 ^ op3);
232
    FORCE_RET();
233
}
234

    
235
/* Shifts.  */
236
OP(shl32)
237
{
238
    uint32_t op2 = get_op(PARAM2);
239
    uint32_t op3 = get_op(PARAM3);
240
    uint32_t result;
241
    result = op2 << op3;
242
    set_op(PARAM1, result);
243
    FORCE_RET();
244
}
245

    
246
OP(shl_cc)
247
{
248
    uint32_t op1 = get_op(PARAM1);
249
    uint32_t op2 = get_op(PARAM2);
250
    uint32_t result;
251
    result = op1 << op2;
252
    set_op(PARAM1, result);
253
    env->cc_x = (op1 << (op2 - 1)) & 1;
254
    FORCE_RET();
255
}
256

    
257
OP(shr32)
258
{
259
    uint32_t op2 = get_op(PARAM2);
260
    uint32_t op3 = get_op(PARAM3);
261
    uint32_t result;
262
    result = op2 >> op3;
263
    set_op(PARAM1, result);
264
    FORCE_RET();
265
}
266

    
267
OP(shr_cc)
268
{
269
    uint32_t op1 = get_op(PARAM1);
270
    uint32_t op2 = get_op(PARAM2);
271
    uint32_t result;
272
    result = op1 >> op2;
273
    set_op(PARAM1, result);
274
    env->cc_x = (op1 >> (op2 - 1)) & 1;
275
    FORCE_RET();
276
}
277

    
278
OP(sar_cc)
279
{
280
    int32_t op1 = get_op(PARAM1);
281
    uint32_t op2 = get_op(PARAM2);
282
    uint32_t result;
283
    result = op1 >> op2;
284
    set_op(PARAM1, result);
285
    env->cc_x = (op1 >> (op2 - 1)) & 1;
286
    FORCE_RET();
287
}
288

    
289
/* Value extend.  */
290

    
291
OP(ext8u32)
292
{
293
    uint32_t op2 = get_op(PARAM2);
294
    set_op(PARAM1, (uint8_t)op2);
295
    FORCE_RET();
296
}
297

    
298
OP(ext8s32)
299
{
300
    uint32_t op2 = get_op(PARAM2);
301
    set_op(PARAM1, (int8_t)op2);
302
    FORCE_RET();
303
}
304

    
305
OP(ext16u32)
306
{
307
    uint32_t op2 = get_op(PARAM2);
308
    set_op(PARAM1, (uint16_t)op2);
309
    FORCE_RET();
310
}
311

    
312
OP(ext16s32)
313
{
314
    uint32_t op2 = get_op(PARAM2);
315
    set_op(PARAM1, (int16_t)op2);
316
    FORCE_RET();
317
}
318

    
319
/* Load/store ops.  */
320
OP(ld8u32)
321
{
322
    uint32_t addr = get_op(PARAM2);
323
    set_op(PARAM1, ldub(addr));
324
    FORCE_RET();
325
}
326

    
327
OP(ld8s32)
328
{
329
    uint32_t addr = get_op(PARAM2);
330
    set_op(PARAM1, ldsb(addr));
331
    FORCE_RET();
332
}
333

    
334
OP(ld16u32)
335
{
336
    uint32_t addr = get_op(PARAM2);
337
    set_op(PARAM1, lduw(addr));
338
    FORCE_RET();
339
}
340

    
341
OP(ld16s32)
342
{
343
    uint32_t addr = get_op(PARAM2);
344
    set_op(PARAM1, ldsw(addr));
345
    FORCE_RET();
346
}
347

    
348
OP(ld32)
349
{
350
    uint32_t addr = get_op(PARAM2);
351
    set_op(PARAM1, ldl(addr));
352
    FORCE_RET();
353
}
354

    
355
OP(st8)
356
{
357
    uint32_t addr = get_op(PARAM1);
358
    stb(addr, get_op(PARAM2));
359
    FORCE_RET();
360
}
361

    
362
OP(st16)
363
{
364
    uint32_t addr = get_op(PARAM1);
365
    stw(addr, get_op(PARAM2));
366
    FORCE_RET();
367
}
368

    
369
OP(st32)
370
{
371
    uint32_t addr = get_op(PARAM1);
372
    stl(addr, get_op(PARAM2));
373
    FORCE_RET();
374
}
375

    
376
OP(ldf64)
377
{
378
    uint32_t addr = get_op(PARAM2);
379
    set_opf64(PARAM1, ldfq(addr));
380
    FORCE_RET();
381
}
382

    
383
OP(stf64)
384
{
385
    uint32_t addr = get_op(PARAM1);
386
    stfq(addr, get_opf64(PARAM2));
387
    FORCE_RET();
388
}
389

    
390
OP(flush_flags)
391
{
392
    int cc_op  = PARAM1;
393
    if (cc_op == CC_OP_DYNAMIC)
394
        cc_op = env->cc_op;
395
    cpu_m68k_flush_flags(env, cc_op);
396
    FORCE_RET();
397
}
398

    
399
OP(divu)
400
{
401
    uint32_t num;
402
    uint32_t den;
403
    uint32_t quot;
404
    uint32_t rem;
405
    uint32_t flags;
406
    
407
    num = env->div1;
408
    den = env->div2;
409
    /* ??? This needs to make sure the throwing location is accurate.  */
410
    if (den == 0)
411
        RAISE_EXCEPTION(EXCP_DIV0);
412
    quot = num / den;
413
    rem = num % den;
414
    flags = 0;
415
    /* Avoid using a PARAM1 of zero.  This breaks dyngen because it uses
416
       the address of a symbol, and gcc knows symbols can't have address
417
       zero.  */
418
    if (PARAM1 == 2 && quot > 0xffff)
419
        flags |= CCF_V;
420
    if (quot == 0)
421
        flags |= CCF_Z;
422
    else if ((int32_t)quot < 0)
423
        flags |= CCF_N;
424
    env->div1 = quot;
425
    env->div2 = rem;
426
    env->cc_dest = flags;
427
    FORCE_RET();
428
}
429

    
430
OP(divs)
431
{
432
    int32_t num;
433
    int32_t den;
434
    int32_t quot;
435
    int32_t rem;
436
    int32_t flags;
437
    
438
    num = env->div1;
439
    den = env->div2;
440
    if (den == 0)
441
        RAISE_EXCEPTION(EXCP_DIV0);
442
    quot = num / den;
443
    rem = num % den;
444
    flags = 0;
445
    if (PARAM1 == 2 && quot != (int16_t)quot)
446
        flags |= CCF_V;
447
    if (quot == 0)
448
        flags |= CCF_Z;
449
    else if (quot < 0)
450
        flags |= CCF_N;
451
    env->div1 = quot;
452
    env->div2 = rem;
453
    env->cc_dest = flags;
454
    FORCE_RET();
455
}
456

    
457
OP(raise_exception)
458
{
459
    RAISE_EXCEPTION(PARAM1);
460
    FORCE_RET();
461
}
462

    
463
/* Floating point comparison sets flags differently to other instructions.  */
464

    
465
OP(sub_cmpf64)
466
{
467
    float64 src0;
468
    float64 src1;
469
    src0 = get_opf64(PARAM2);
470
    src1 = get_opf64(PARAM3);
471
    set_opf64(PARAM1, helper_sub_cmpf64(env, src0, src1));
472
    FORCE_RET();
473
}
474

    
475
OP(update_xflag_tst)
476
{
477
    uint32_t op1 = get_op(PARAM1);
478
    env->cc_x = op1;
479
    FORCE_RET();
480
}
481

    
482
OP(update_xflag_lt)
483
{
484
    uint32_t op1 = get_op(PARAM1);
485
    uint32_t op2 = get_op(PARAM2);
486
    env->cc_x = (op1 < op2);
487
    FORCE_RET();
488
}
489

    
490
OP(get_xflag)
491
{
492
    set_op(PARAM1, env->cc_x);
493
    FORCE_RET();
494
}
495

    
496
OP(logic_cc)
497
{
498
    uint32_t op1 = get_op(PARAM1);
499
    env->cc_dest = op1;
500
    FORCE_RET();
501
}
502

    
503
OP(update_cc_add)
504
{
505
    uint32_t op1 = get_op(PARAM1);
506
    uint32_t op2 = get_op(PARAM2);
507
    env->cc_dest = op1;
508
    env->cc_src = op2;
509
    FORCE_RET();
510
}
511

    
512
OP(fp_result)
513
{
514
    env->fp_result = get_opf64(PARAM1);
515
    FORCE_RET();
516
}
517

    
518
OP(jmp)
519
{
520
    GOTO_LABEL_PARAM(1);
521
}
522

    
523
/* These ops involve a function call, which probably requires a stack frame
524
   and breaks things on some hosts.  */
525
OP(jmp_z32)
526
{
527
    uint32_t arg = get_op(PARAM1);
528
    if (arg == 0)
529
        GOTO_LABEL_PARAM(2);
530
    FORCE_RET();
531
}
532

    
533
OP(jmp_nz32)
534
{
535
    uint32_t arg = get_op(PARAM1);
536
    if (arg != 0)
537
        GOTO_LABEL_PARAM(2);
538
    FORCE_RET();
539
}
540

    
541
OP(jmp_s32)
542
{
543
    int32_t arg = get_op(PARAM1);
544
    if (arg < 0)
545
        GOTO_LABEL_PARAM(2);
546
    FORCE_RET();
547
}
548

    
549
OP(jmp_ns32)
550
{
551
    int32_t arg = get_op(PARAM1);
552
    if (arg >= 0)
553
        GOTO_LABEL_PARAM(2);
554
    FORCE_RET();
555
}
556

    
557
void OPPROTO op_goto_tb0(void)
558
{
559
    GOTO_TB(op_goto_tb0, PARAM1, 0);
560
}
561

    
562
void OPPROTO op_goto_tb1(void)
563
{
564
    GOTO_TB(op_goto_tb1, PARAM1, 1);
565
}
566

    
567
OP(exit_tb)
568
{
569
    EXIT_TB();
570
}
571

    
572

    
573
/* Floating point.  */
574
OP(f64_to_i32)
575
{
576
    set_op(PARAM1, float64_to_int32(get_opf64(PARAM2), &CPU_FP_STATUS));
577
    FORCE_RET();
578
}
579

    
580
OP(f64_to_f32)
581
{
582
    union {
583
        float32 f;
584
        uint32_t i;
585
    } u;
586
    u.f = float64_to_float32(get_opf64(PARAM2), &CPU_FP_STATUS);
587
    set_op(PARAM1, u.i);
588
    FORCE_RET();
589
}
590

    
591
OP(i32_to_f64)
592
{
593
    set_opf64(PARAM1, int32_to_float64(get_op(PARAM2), &CPU_FP_STATUS));
594
    FORCE_RET();
595
}
596

    
597
OP(f32_to_f64)
598
{
599
    union {
600
        float32 f;
601
        uint32_t i;
602
    } u;
603
    u.i = get_op(PARAM2);
604
    set_opf64(PARAM1, float32_to_float64(u.f, &CPU_FP_STATUS));
605
    FORCE_RET();
606
}
607

    
608
OP(absf64)
609
{
610
    float64 op0 = get_opf64(PARAM2);
611
    set_opf64(PARAM1, float64_abs(op0));
612
    FORCE_RET();
613
}
614

    
615
OP(chsf64)
616
{
617
    float64 op0 = get_opf64(PARAM2);
618
    set_opf64(PARAM1, float64_chs(op0));
619
    FORCE_RET();
620
}
621

    
622
OP(sqrtf64)
623
{
624
    float64 op0 = get_opf64(PARAM2);
625
    set_opf64(PARAM1, float64_sqrt(op0, &CPU_FP_STATUS));
626
    FORCE_RET();
627
}
628

    
629
OP(addf64)
630
{
631
    float64 op0 = get_opf64(PARAM2);
632
    float64 op1 = get_opf64(PARAM3);
633
    set_opf64(PARAM1, float64_add(op0, op1, &CPU_FP_STATUS));
634
    FORCE_RET();
635
}
636

    
637
OP(subf64)
638
{
639
    float64 op0 = get_opf64(PARAM2);
640
    float64 op1 = get_opf64(PARAM3);
641
    set_opf64(PARAM1, float64_sub(op0, op1, &CPU_FP_STATUS));
642
    FORCE_RET();
643
}
644

    
645
OP(mulf64)
646
{
647
    float64 op0 = get_opf64(PARAM2);
648
    float64 op1 = get_opf64(PARAM3);
649
    set_opf64(PARAM1, float64_mul(op0, op1, &CPU_FP_STATUS));
650
    FORCE_RET();
651
}
652

    
653
OP(divf64)
654
{
655
    float64 op0 = get_opf64(PARAM2);
656
    float64 op1 = get_opf64(PARAM3);
657
    set_opf64(PARAM1, float64_div(op0, op1, &CPU_FP_STATUS));
658
    FORCE_RET();
659
}
660

    
661
OP(iround_f64)
662
{
663
    float64 op0 = get_opf64(PARAM2);
664
    set_opf64(PARAM1, float64_round_to_int(op0, &CPU_FP_STATUS));
665
    FORCE_RET();
666
}
667

    
668
OP(itrunc_f64)
669
{
670
    float64 op0 = get_opf64(PARAM2);
671
    set_opf64(PARAM1, float64_trunc_to_int(op0, &CPU_FP_STATUS));
672
    FORCE_RET();
673
}
674

    
675
OP(compare_quietf64)
676
{
677
    float64 op0 = get_opf64(PARAM2);
678
    float64 op1 = get_opf64(PARAM3);
679
    set_op(PARAM1, float64_compare_quiet(op0, op1, &CPU_FP_STATUS));
680
    FORCE_RET();
681
}