Statistics
| Branch: | Revision:

root / target-mips / op.c @ d2ec1774

History | View | Annotate | Download (10.3 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_direct, 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_direct, 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)(int32_t)T0 * (int64_t)(int32_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)(int32_t)T0 * (int64_t)(int32_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)(int32_t)T0 * (int64_t)(int32_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

    
491
void OPPROTO op_goto_tb0(void)
492
{
493
    GOTO_TB(op_goto_tb0, PARAM1, 0);
494
}
495

    
496
void OPPROTO op_goto_tb1(void)
497
{
498
    GOTO_TB(op_goto_tb1, PARAM1, 1);
499
}
500

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

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

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

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

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

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

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

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

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

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

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

    
570
void op_tlbwr (void)
571
{
572
    CALL_FROM_TB0(do_tlbwr);
573
    RETURN();
574
}
575

    
576
void op_tlbp (void)
577
{
578
    CALL_FROM_TB0(do_tlbp);
579
    RETURN();
580
}
581

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

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

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

    
603
void op_debug (void)
604
{
605
  CALL_FROM_TB1(do_raise_exception_direct, EXCP_DEBUG);
606
}
607

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

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

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

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

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

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

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

    
657
void op_exit_tb (void)
658
{
659
    EXIT_TB();
660
}
661

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