Statistics
| Branch: | Revision:

root / target-mips / op.c @ 1e8a7cfd

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 ((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31)) {
210
        CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
211
    }
212
    RETURN();
213
}
214

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

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

    
225
    tmp = T0;
226
    T0 = (int32_t)T0 - (int32_t)T1;
227
    if (!((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31))) {
228
        CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
229
    }
230
    RETURN();
231
}
232

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

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

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

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

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

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

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

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

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

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

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

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

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

    
318
void op_clo (void)
319
{
320
    int n;
321

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

    
335
void op_clz (void)
336
{
337
    int n;
338

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

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

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

    
365
void op_mult (void)
366
{
367
    set_HILO((int64_t)T0 * (int64_t)T1);
368
    RETURN();
369
}
370

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

    
377
void op_madd (void)
378
{
379
    int64_t tmp;
380

    
381
    tmp = ((int64_t)T0 * (int64_t)T1);
382
    set_HILO((int64_t)get_HILO() + tmp);
383
    RETURN();
384
}
385

    
386
void op_maddu (void)
387
{
388
    uint64_t tmp;
389

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

    
395
void op_msub (void)
396
{
397
    int64_t tmp;
398

    
399
    tmp = ((int64_t)T0 * (int64_t)T1);
400
    set_HILO((int64_t)get_HILO() - tmp);
401
    RETURN();
402
}
403

    
404
void op_msubu (void)
405
{
406
    uint64_t tmp;
407

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

    
419
void op_multu (void)
420
{
421
    CALL_FROM_TB0(do_multu);
422
    RETURN();
423
}
424

    
425
void op_madd (void)
426
{
427
    CALL_FROM_TB0(do_madd);
428
    RETURN();
429
}
430

    
431
void op_maddu (void)
432
{
433
    CALL_FROM_TB0(do_maddu);
434
    RETURN();
435
}
436

    
437
void op_msub (void)
438
{
439
    CALL_FROM_TB0(do_msub);
440
    RETURN();
441
}
442

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

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

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

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

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

    
488
/* Branchs */
489
//#undef USE_DIRECT_JUMP
490
#define EIP env->PC
491

    
492
/* Branch to register */
493
void op_save_breg_target (void)
494
{
495
    env->btarget = T2;
496
}
497

    
498
void op_restore_breg_target (void)
499
{
500
    T2 = env->btarget;
501
}
502

    
503
void op_breg (void)
504
{
505
    env->PC = T2;
506
    RETURN();
507
}
508

    
509
/* Unconditional branch */
510
void op_branch (void)
511
{
512
    JUMP_TB(branch, PARAM1, 0, PARAM2);
513
    RETURN();
514
}
515

    
516
void op_save_btarget (void)
517
{
518
    env->btarget = PARAM1;
519
    RETURN();
520
}
521

    
522
/* Conditional branch */
523
void op_set_bcond (void)
524
{
525
    T2 = T0;
526
    RETURN();
527
}
528

    
529
void op_save_bcond (void)
530
{
531
    env->bcond = T2;
532
    RETURN();
533
}
534

    
535
void op_restore_bcond (void)
536
{
537
    T2 = env->bcond;
538
    RETURN();
539
}
540

    
541
void op_bcond (void)
542
{
543
    if (T2) {
544
        JUMP_TB(bcond, PARAM1, 0, PARAM2);
545
    } else {
546
        JUMP_TB(bcond, PARAM1, 1, PARAM3);
547
    }
548
    RETURN();
549
}
550

    
551
/* Likely branch (used to skip the delay slot) */
552
void op_blikely (void)
553
{
554
    /* If the test is false, skip the delay slot */
555
    if (T2 == 0) {
556
        env->hflags = PARAM3;
557
        JUMP_TB(blikely, PARAM1, 1, PARAM2);
558
    }
559
    RETURN();
560
}
561

    
562
/* CP0 functions */
563
void op_mfc0 (void)
564
{
565
    CALL_FROM_TB2(do_mfc0, PARAM1, PARAM2);
566
    RETURN();
567
}
568

    
569
void op_mtc0 (void)
570
{
571
    CALL_FROM_TB2(do_mtc0, PARAM1, PARAM2);
572
    RETURN();
573
}
574

    
575
#if defined(MIPS_USES_R4K_TLB)
576
void op_tlbwi (void)
577
{
578
    CALL_FROM_TB0(do_tlbwi);
579
    RETURN();
580
}
581

    
582
void op_tlbwr (void)
583
{
584
    CALL_FROM_TB0(do_tlbwr);
585
    RETURN();
586
}
587

    
588
void op_tlbp (void)
589
{
590
    CALL_FROM_TB0(do_tlbp);
591
    RETURN();
592
}
593

    
594
void op_tlbr (void)
595
{
596
    CALL_FROM_TB0(do_tlbr);
597
    RETURN();
598
}
599
#endif
600

    
601
/* Specials */
602
void op_pmon (void)
603
{
604
    CALL_FROM_TB1(do_pmon, PARAM1);
605
}
606

    
607
void op_trap (void)
608
{
609
    if (T0) {
610
        CALL_FROM_TB1(do_raise_exception, EXCP_TRAP);
611
    }
612
    RETURN();
613
}
614

    
615
void op_set_lladdr (void)
616
{
617
    env->CP0_LLAddr = T2;
618
}
619

    
620
void debug_eret (void);
621
void op_eret (void)
622
{
623
    CALL_FROM_TB0(debug_eret);
624
    if (env->hflags & MIPS_HFLAG_ERL) {
625
        env->PC = env->CP0_ErrorEPC;
626
        env->hflags &= ~MIPS_HFLAG_ERL;
627
    } else {
628
        env->PC = env->CP0_EPC;
629
        env->hflags &= ~MIPS_HFLAG_EXL;
630
    }
631
    env->CP0_LLAddr = 1;
632
}
633

    
634
void op_deret (void)
635
{
636
    CALL_FROM_TB0(debug_eret);
637
    env->PC = env->CP0_DEPC;
638
}
639

    
640
void op_save_state (void)
641
{
642
    env->hflags = PARAM1;
643
    RETURN();
644
}
645

    
646
void op_save_pc (void)
647
{
648
    env->PC = PARAM1;
649
    RETURN();
650
}
651

    
652
void op_raise_exception (void)
653
{
654
    CALL_FROM_TB1(do_raise_exception, PARAM1);
655
    RETURN();
656
}
657

    
658
void op_raise_exception_err (void)
659
{
660
    CALL_FROM_TB2(do_raise_exception_err, PARAM1, PARAM2);
661
    RETURN();
662
}
663

    
664
void op_exit_tb (void)
665
{
666
    EXIT_TB();
667
}
668