Statistics
| Branch: | Revision:

root / target-mips / op.c @ ce2f4b3c

History | View | Annotate | Download (10.4 kB)

1
/*
2
 *  MIPS emulation micro-operations for qemu.
3
 * 
4
 *  Copyright (c) 2004-2005 Jocelyn Mayer
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

    
21
#include "config.h"
22
#include "exec.h"
23

    
24
#ifndef CALL_FROM_TB0
25
#define CALL_FROM_TB0(func) func();
26
#endif
27
#ifndef CALL_FROM_TB1
28
#define CALL_FROM_TB1(func, arg0) func(arg0);
29
#endif
30
#ifndef CALL_FROM_TB1_CONST16
31
#define CALL_FROM_TB1_CONST16(func, arg0) CALL_FROM_TB1(func, arg0);
32
#endif
33
#ifndef CALL_FROM_TB2
34
#define CALL_FROM_TB2(func, arg0, arg1) func(arg0, arg1);
35
#endif
36
#ifndef CALL_FROM_TB2_CONST16
37
#define CALL_FROM_TB2_CONST16(func, arg0, arg1)     \
38
CALL_FROM_TB2(func, arg0, arg1);
39
#endif
40
#ifndef CALL_FROM_TB3
41
#define CALL_FROM_TB3(func, arg0, arg1, arg2) func(arg0, arg1, arg2);
42
#endif
43
#ifndef CALL_FROM_TB4
44
#define CALL_FROM_TB4(func, arg0, arg1, arg2, arg3) \
45
        func(arg0, arg1, arg2, arg3);
46
#endif
47

    
48
#define REG 1
49
#include "op_template.c"
50
#undef REG
51
#define REG 2
52
#include "op_template.c"
53
#undef REG
54
#define REG 3
55
#include "op_template.c"
56
#undef REG
57
#define REG 4
58
#include "op_template.c"
59
#undef REG
60
#define REG 5
61
#include "op_template.c"
62
#undef REG
63
#define REG 6
64
#include "op_template.c"
65
#undef REG
66
#define REG 7
67
#include "op_template.c"
68
#undef REG
69
#define REG 8
70
#include "op_template.c"
71
#undef REG
72
#define REG 9
73
#include "op_template.c"
74
#undef REG
75
#define REG 10
76
#include "op_template.c"
77
#undef REG
78
#define REG 11
79
#include "op_template.c"
80
#undef REG
81
#define REG 12
82
#include "op_template.c"
83
#undef REG
84
#define REG 13
85
#include "op_template.c"
86
#undef REG
87
#define REG 14
88
#include "op_template.c"
89
#undef REG
90
#define REG 15
91
#include "op_template.c"
92
#undef REG
93
#define REG 16
94
#include "op_template.c"
95
#undef REG
96
#define REG 17
97
#include "op_template.c"
98
#undef REG
99
#define REG 18
100
#include "op_template.c"
101
#undef REG
102
#define REG 19
103
#include "op_template.c"
104
#undef REG
105
#define REG 20
106
#include "op_template.c"
107
#undef REG
108
#define REG 21
109
#include "op_template.c"
110
#undef REG
111
#define REG 22
112
#include "op_template.c"
113
#undef REG
114
#define REG 23
115
#include "op_template.c"
116
#undef REG
117
#define REG 24
118
#include "op_template.c"
119
#undef REG
120
#define REG 25
121
#include "op_template.c"
122
#undef REG
123
#define REG 26
124
#include "op_template.c"
125
#undef REG
126
#define REG 27
127
#include "op_template.c"
128
#undef REG
129
#define REG 28
130
#include "op_template.c"
131
#undef REG
132
#define REG 29
133
#include "op_template.c"
134
#undef REG
135
#define REG 30
136
#include "op_template.c"
137
#undef REG
138
#define REG 31
139
#include "op_template.c"
140
#undef REG
141

    
142
#define TN T0
143
#include "op_template.c"
144
#undef TN
145
#define TN T1
146
#include "op_template.c"
147
#undef TN
148
#define TN T2
149
#include "op_template.c"
150
#undef TN
151

    
152
void op_dup_T0 (void)
153
{
154
    T2 = T0;
155
    RETURN();
156
}
157

    
158
void op_load_HI (void)
159
{
160
    T0 = env->HI;
161
    RETURN();
162
}
163

    
164
void op_store_HI (void)
165
{
166
    env->HI = T0;
167
    RETURN();
168
}
169

    
170
void op_load_LO (void)
171
{
172
    T0 = env->LO;
173
    RETURN();
174
}
175

    
176
void op_store_LO (void)
177
{
178
    env->LO = T0;
179
    RETURN();
180
}
181

    
182
/* Load and store */
183
#define MEMSUFFIX _raw
184
#include "op_mem.c"
185
#undef MEMSUFFIX
186
#if !defined(CONFIG_USER_ONLY)
187
#define MEMSUFFIX _user
188
#include "op_mem.c"
189
#undef MEMSUFFIX
190

    
191
#define MEMSUFFIX _kernel
192
#include "op_mem.c"
193
#undef MEMSUFFIX
194
#endif
195

    
196
/* Arithmetic */
197
void op_add (void)
198
{
199
    T0 += T1;
200
    RETURN();
201
}
202

    
203
void op_addo (void)
204
{
205
    target_ulong tmp;
206

    
207
    tmp = T0;
208
    T0 += T1;
209
    if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 31) {
210
       /* operands of same sign, result different sign */
211
        CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
212
    }
213
    RETURN();
214
}
215

    
216
void op_sub (void)
217
{
218
    T0 -= T1;
219
    RETURN();
220
}
221

    
222
void op_subo (void)
223
{
224
    target_ulong tmp;
225

    
226
    tmp = T0;
227
    T0 = (int32_t)T0 - (int32_t)T1;
228
    if (((tmp ^ T1) & (tmp ^ T0)) >> 31) {
229
       /* operands of different sign, first operand and result different sign */
230
        CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
231
    }
232
    RETURN();
233
}
234

    
235
void op_mul (void)
236
{
237
    T0 = (int32_t)T0 * (int32_t)T1;
238
    RETURN();
239
}
240

    
241
void op_div (void)
242
{
243
    if (T1 != 0) {
244
        env->LO = (int32_t)T0 / (int32_t)T1;
245
        env->HI = (int32_t)T0 % (int32_t)T1;
246
    }
247
    RETURN();
248
}
249

    
250
void op_divu (void)
251
{
252
    if (T1 != 0) {
253
        env->LO = T0 / T1;
254
        env->HI = T0 % T1;
255
    }
256
    RETURN();
257
}
258

    
259
/* Logical */
260
void op_and (void)
261
{
262
    T0 &= T1;
263
    RETURN();
264
}
265

    
266
void op_nor (void)
267
{
268
    T0 = ~(T0 | T1);
269
    RETURN();
270
}
271

    
272
void op_or (void)
273
{
274
    T0 |= T1;
275
    RETURN();
276
}
277

    
278
void op_xor (void)
279
{
280
    T0 ^= T1;
281
    RETURN();
282
}
283

    
284
void op_sll (void)
285
{
286
    T0 = T0 << T1;
287
    RETURN();
288
}
289

    
290
void op_sra (void)
291
{
292
    T0 = (int32_t)T0 >> T1;
293
    RETURN();
294
}
295

    
296
void op_srl (void)
297
{
298
    T0 = T0 >> T1;
299
    RETURN();
300
}
301

    
302
void op_sllv (void)
303
{
304
    T0 = T1 << (T0 & 0x1F);
305
    RETURN();
306
}
307

    
308
void op_srav (void)
309
{
310
    T0 = (int32_t)T1 >> (T0 & 0x1F);
311
    RETURN();
312
}
313

    
314
void op_srlv (void)
315
{
316
    T0 = T1 >> (T0 & 0x1F);
317
    RETURN();
318
}
319

    
320
void op_clo (void)
321
{
322
    int n;
323

    
324
    if (T0 == (target_ulong)-1) {
325
        T0 = 32;
326
    } else {
327
        for (n = 0; n < 32; n++) {
328
            if (!(T0 & (1 << 31)))
329
                break;
330
            T0 = T0 << 1;
331
        }
332
        T0 = n;
333
    }
334
    RETURN();
335
}
336

    
337
void op_clz (void)
338
{
339
    int n;
340

    
341
    if (T0 == 0) {
342
        T0 = 32;
343
    } else {
344
        for (n = 0; n < 32; n++) {
345
            if (T0 & (1 << 31))
346
                break;
347
            T0 = T0 << 1;
348
        }
349
        T0 = n;
350
    }
351
    RETURN();
352
}
353

    
354
/* 64 bits arithmetic */
355
#if (HOST_LONG_BITS == 64)
356
static inline uint64_t get_HILO (void)
357
{
358
    return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
359
}
360

    
361
static inline void set_HILO (uint64_t HILO)
362
{
363
    env->LO = HILO & 0xFFFFFFFF;
364
    env->HI = HILO >> 32;
365
}
366

    
367
void op_mult (void)
368
{
369
    set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
370
    RETURN();
371
}
372

    
373
void op_multu (void)
374
{
375
    set_HILO((uint64_t)T0 * (uint64_t)T1);
376
    RETURN();
377
}
378

    
379
void op_madd (void)
380
{
381
    int64_t tmp;
382

    
383
    tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
384
    set_HILO((int64_t)get_HILO() + tmp);
385
    RETURN();
386
}
387

    
388
void op_maddu (void)
389
{
390
    uint64_t tmp;
391

    
392
    tmp = ((uint64_t)T0 * (uint64_t)T1);
393
    set_HILO(get_HILO() + tmp);
394
    RETURN();
395
}
396

    
397
void op_msub (void)
398
{
399
    int64_t tmp;
400

    
401
    tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
402
    set_HILO((int64_t)get_HILO() - tmp);
403
    RETURN();
404
}
405

    
406
void op_msubu (void)
407
{
408
    uint64_t tmp;
409

    
410
    tmp = ((uint64_t)T0 * (uint64_t)T1);
411
    set_HILO(get_HILO() - tmp);
412
    RETURN();
413
}
414
#else
415
void op_mult (void)
416
{
417
    CALL_FROM_TB0(do_mult);
418
    RETURN();
419
}
420

    
421
void op_multu (void)
422
{
423
    CALL_FROM_TB0(do_multu);
424
    RETURN();
425
}
426

    
427
void op_madd (void)
428
{
429
    CALL_FROM_TB0(do_madd);
430
    RETURN();
431
}
432

    
433
void op_maddu (void)
434
{
435
    CALL_FROM_TB0(do_maddu);
436
    RETURN();
437
}
438

    
439
void op_msub (void)
440
{
441
    CALL_FROM_TB0(do_msub);
442
    RETURN();
443
}
444

    
445
void op_msubu (void)
446
{
447
    CALL_FROM_TB0(do_msubu);
448
    RETURN();
449
}
450
#endif
451

    
452
/* Conditional moves */
453
void op_movn (void)
454
{
455
    if (T1 != 0)
456
        env->gpr[PARAM1] = T0;
457
    RETURN();
458
}
459

    
460
void op_movz (void)
461
{
462
    if (T1 == 0)
463
        env->gpr[PARAM1] = T0;
464
    RETURN();
465
}
466

    
467
/* Tests */
468
#define OP_COND(name, cond) \
469
void glue(op_, name) (void) \
470
{                           \
471
    if (cond) {             \
472
        T0 = 1;             \
473
    } else {                \
474
        T0 = 0;             \
475
    }                       \
476
    RETURN();               \
477
}
478

    
479
OP_COND(eq, T0 == T1);
480
OP_COND(ne, T0 != T1);
481
OP_COND(ge, (int32_t)T0 >= (int32_t)T1);
482
OP_COND(geu, T0 >= T1);
483
OP_COND(lt, (int32_t)T0 < (int32_t)T1);
484
OP_COND(ltu, T0 < T1);
485
OP_COND(gez, (int32_t)T0 >= 0);
486
OP_COND(gtz, (int32_t)T0 > 0);
487
OP_COND(lez, (int32_t)T0 <= 0);
488
OP_COND(ltz, (int32_t)T0 < 0);
489

    
490
/* Branchs */
491
//#undef USE_DIRECT_JUMP
492

    
493
void OPPROTO op_goto_tb0(void)
494
{
495
    GOTO_TB(op_goto_tb0, PARAM1, 0);
496
}
497

    
498
void OPPROTO op_goto_tb1(void)
499
{
500
    GOTO_TB(op_goto_tb1, PARAM1, 1);
501
}
502

    
503
/* Branch to register */
504
void op_save_breg_target (void)
505
{
506
    env->btarget = T2;
507
}
508

    
509
void op_restore_breg_target (void)
510
{
511
    T2 = env->btarget;
512
}
513

    
514
void op_breg (void)
515
{
516
    env->PC = T2;
517
    RETURN();
518
}
519

    
520
void op_save_btarget (void)
521
{
522
    env->btarget = PARAM1;
523
    RETURN();
524
}
525

    
526
/* Conditional branch */
527
void op_set_bcond (void)
528
{
529
    T2 = T0;
530
    RETURN();
531
}
532

    
533
void op_save_bcond (void)
534
{
535
    env->bcond = T2;
536
    RETURN();
537
}
538

    
539
void op_restore_bcond (void)
540
{
541
    T2 = env->bcond;
542
    RETURN();
543
}
544

    
545
void op_jnz_T2 (void)
546
{
547
    if (T2)
548
        GOTO_LABEL_PARAM(1);
549
    RETURN();
550
}
551

    
552
/* CP0 functions */
553
void op_mfc0 (void)
554
{
555
    CALL_FROM_TB2(do_mfc0, PARAM1, PARAM2);
556
    RETURN();
557
}
558

    
559
void op_mtc0 (void)
560
{
561
    CALL_FROM_TB2(do_mtc0, PARAM1, PARAM2);
562
    RETURN();
563
}
564

    
565
#if defined(MIPS_USES_R4K_TLB)
566
void op_tlbwi (void)
567
{
568
    CALL_FROM_TB0(do_tlbwi);
569
    RETURN();
570
}
571

    
572
void op_tlbwr (void)
573
{
574
    CALL_FROM_TB0(do_tlbwr);
575
    RETURN();
576
}
577

    
578
void op_tlbp (void)
579
{
580
    CALL_FROM_TB0(do_tlbp);
581
    RETURN();
582
}
583

    
584
void op_tlbr (void)
585
{
586
    CALL_FROM_TB0(do_tlbr);
587
    RETURN();
588
}
589
#endif
590

    
591
/* Specials */
592
void op_pmon (void)
593
{
594
    CALL_FROM_TB1(do_pmon, PARAM1);
595
}
596

    
597
void op_trap (void)
598
{
599
    if (T0) {
600
        CALL_FROM_TB1(do_raise_exception_direct, EXCP_TRAP);
601
    }
602
    RETURN();
603
}
604

    
605
void op_debug (void)
606
{
607
  CALL_FROM_TB1(do_raise_exception, EXCP_DEBUG);
608
}
609

    
610
void op_set_lladdr (void)
611
{
612
    env->CP0_LLAddr = T2;
613
}
614

    
615
void debug_eret (void);
616
void op_eret (void)
617
{
618
    CALL_FROM_TB0(debug_eret);
619
    if (env->hflags & MIPS_HFLAG_ERL) {
620
        env->PC = env->CP0_ErrorEPC;
621
        env->hflags &= ~MIPS_HFLAG_ERL;
622
    } else {
623
        env->PC = env->CP0_EPC;
624
        env->hflags &= ~MIPS_HFLAG_EXL;
625
    }
626
    env->CP0_LLAddr = 1;
627
}
628

    
629
void op_deret (void)
630
{
631
    CALL_FROM_TB0(debug_eret);
632
    env->PC = env->CP0_DEPC;
633
}
634

    
635
void op_save_state (void)
636
{
637
    env->hflags = PARAM1;
638
    RETURN();
639
}
640

    
641
void op_save_pc (void)
642
{
643
    env->PC = PARAM1;
644
    RETURN();
645
}
646

    
647
void op_raise_exception (void)
648
{
649
    CALL_FROM_TB1(do_raise_exception, PARAM1);
650
    RETURN();
651
}
652

    
653
void op_raise_exception_err (void)
654
{
655
    CALL_FROM_TB2(do_raise_exception_err, PARAM1, PARAM2);
656
    RETURN();
657
}
658

    
659
void op_exit_tb (void)
660
{
661
    EXIT_TB();
662
}
663

    
664
void op_wait (void)
665
{
666
    env->halted = 1;
667
    CALL_FROM_TB1(do_raise_exception, EXCP_HLT);
668
}