Statistics
| Branch: | Revision:

root / target-mips / op.c @ 6af0bf9c

History | View | Annotate | Download (9.6 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
#define REG 1
25
#include "op_template.c"
26
#undef REG
27
#define REG 2
28
#include "op_template.c"
29
#undef REG
30
#define REG 3
31
#include "op_template.c"
32
#undef REG
33
#define REG 4
34
#include "op_template.c"
35
#undef REG
36
#define REG 5
37
#include "op_template.c"
38
#undef REG
39
#define REG 6
40
#include "op_template.c"
41
#undef REG
42
#define REG 7
43
#include "op_template.c"
44
#undef REG
45
#define REG 8
46
#include "op_template.c"
47
#undef REG
48
#define REG 9
49
#include "op_template.c"
50
#undef REG
51
#define REG 10
52
#include "op_template.c"
53
#undef REG
54
#define REG 11
55
#include "op_template.c"
56
#undef REG
57
#define REG 12
58
#include "op_template.c"
59
#undef REG
60
#define REG 13
61
#include "op_template.c"
62
#undef REG
63
#define REG 14
64
#include "op_template.c"
65
#undef REG
66
#define REG 15
67
#include "op_template.c"
68
#undef REG
69
#define REG 16
70
#include "op_template.c"
71
#undef REG
72
#define REG 17
73
#include "op_template.c"
74
#undef REG
75
#define REG 18
76
#include "op_template.c"
77
#undef REG
78
#define REG 19
79
#include "op_template.c"
80
#undef REG
81
#define REG 20
82
#include "op_template.c"
83
#undef REG
84
#define REG 21
85
#include "op_template.c"
86
#undef REG
87
#define REG 22
88
#include "op_template.c"
89
#undef REG
90
#define REG 23
91
#include "op_template.c"
92
#undef REG
93
#define REG 24
94
#include "op_template.c"
95
#undef REG
96
#define REG 25
97
#include "op_template.c"
98
#undef REG
99
#define REG 26
100
#include "op_template.c"
101
#undef REG
102
#define REG 27
103
#include "op_template.c"
104
#undef REG
105
#define REG 28
106
#include "op_template.c"
107
#undef REG
108
#define REG 29
109
#include "op_template.c"
110
#undef REG
111
#define REG 30
112
#include "op_template.c"
113
#undef REG
114
#define REG 31
115
#include "op_template.c"
116
#undef REG
117

    
118
#define TN T0
119
#include "op_template.c"
120
#undef TN
121
#define TN T1
122
#include "op_template.c"
123
#undef TN
124
#define TN T2
125
#include "op_template.c"
126
#undef TN
127

    
128
void op_dup_T0 (void)
129
{
130
    T2 = T0;
131
    RETURN();
132
}
133

    
134
void op_load_HI (void)
135
{
136
    T0 = env->HI;
137
    RETURN();
138
}
139

    
140
void op_store_HI (void)
141
{
142
    env->HI = T0;
143
    RETURN();
144
}
145

    
146
void op_load_LO (void)
147
{
148
    T0 = env->LO;
149
    RETURN();
150
}
151

    
152
void op_store_LO (void)
153
{
154
    env->LO = T0;
155
    RETURN();
156
}
157

    
158
/* Load and store */
159
#define MEMSUFFIX _raw
160
#include "op_mem.c"
161
#undef MEMSUFFIX
162
#if !defined(CONFIG_USER_ONLY)
163
#define MEMSUFFIX _user
164
#include "op_mem.c"
165
#undef MEMSUFFIX
166

    
167
#define MEMSUFFIX _kernel
168
#include "op_mem.c"
169
#undef MEMSUFFIX
170
#endif
171

    
172
/* Arithmetic */
173
void op_add (void)
174
{
175
    T0 += T1;
176
    RETURN();
177
}
178

    
179
void op_addo (void)
180
{
181
    target_ulong tmp;
182

    
183
    tmp = T0;
184
    T0 += T1;
185
    if ((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31)) {
186
        CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
187
    }
188
    RETURN();
189
}
190

    
191
void op_sub (void)
192
{
193
    T0 -= T1;
194
    RETURN();
195
}
196

    
197
void op_subo (void)
198
{
199
    target_ulong tmp;
200

    
201
    tmp = T0;
202
    T0 = (int32_t)T0 - (int32_t)T1;
203
    if (!((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31))) {
204
        CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
205
    }
206
    RETURN();
207
}
208

    
209
void op_mul (void)
210
{
211
    T0 = (int32_t)T0 * (int32_t)T1;
212
    RETURN();
213
}
214

    
215
void op_div (void)
216
{
217
    if (T1 != 0) {
218
        env->LO = (int32_t)T0 / (int32_t)T1;
219
        env->HI = (int32_t)T0 % (int32_t)T1;
220
    }
221
    RETURN();
222
}
223

    
224
void op_divu (void)
225
{
226
    if (T1 != 0) {
227
        env->LO = T0 / T1;
228
        env->HI = T0 % T1;
229
    }
230
    RETURN();
231
}
232

    
233
/* Logical */
234
void op_and (void)
235
{
236
    T0 &= T1;
237
    RETURN();
238
}
239

    
240
void op_nor (void)
241
{
242
    T0 = ~(T0 | T1);
243
    RETURN();
244
}
245

    
246
void op_or (void)
247
{
248
    T0 |= T1;
249
    RETURN();
250
}
251

    
252
void op_xor (void)
253
{
254
    T0 ^= T1;
255
    RETURN();
256
}
257

    
258
void op_sll (void)
259
{
260
    T0 = T0 << T1;
261
    RETURN();
262
}
263

    
264
void op_sra (void)
265
{
266
    T0 = (int32_t)T0 >> T1;
267
    RETURN();
268
}
269

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

    
276
void op_sllv (void)
277
{
278
    T0 = T1 << (T0 & 0x1F);
279
    RETURN();
280
}
281

    
282
void op_srav (void)
283
{
284
    T0 = (int32_t)T1 >> (T0 & 0x1F);
285
    RETURN();
286
}
287

    
288
void op_srlv (void)
289
{
290
    T0 = T1 >> (T0 & 0x1F);
291
    RETURN();
292
}
293

    
294
void op_clo (void)
295
{
296
    int n;
297

    
298
    if (T0 == (target_ulong)-1) {
299
        T0 = 32;
300
    } else {
301
        for (n = 0; n < 32; n++) {
302
            if (!(T0 & (1 << 31)))
303
                break;
304
            T0 = T0 << 1;
305
        }
306
        T0 = n;
307
    }
308
    RETURN();
309
}
310

    
311
void op_clz (void)
312
{
313
    int n;
314

    
315
    if (T0 == 0) {
316
        T0 = 32;
317
    } else {
318
        for (n = 0; n < 32; n++) {
319
            if (T0 & (1 << 31))
320
                break;
321
            T0 = T0 << 1;
322
        }
323
        T0 = n;
324
    }
325
    RETURN();
326
}
327

    
328
/* 64 bits arithmetic */
329
#if (HOST_LONG_BITS == 64)
330
static inline uint64_t get_HILO (void)
331
{
332
    return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
333
}
334

    
335
static inline void set_HILO (uint64_t HILO)
336
{
337
    env->LO = HILO & 0xFFFFFFFF;
338
    env->HI = HILO >> 32;
339
}
340

    
341
void op_mult (void)
342
{
343
    set_HILO((int64_t)T0 * (int64_t)T1);
344
    RETURN();
345
}
346

    
347
void op_multu (void)
348
{
349
    set_HILO((uint64_t)T0 * (uint64_t)T1);
350
    RETURN();
351
}
352

    
353
void op_madd (void)
354
{
355
    int64_t tmp;
356

    
357
    tmp = ((int64_t)T0 * (int64_t)T1);
358
    set_HILO((int64_t)get_HILO() + tmp);
359
    RETURN();
360
}
361

    
362
void op_maddu (void)
363
{
364
    uint64_t tmp;
365

    
366
    tmp = ((uint64_t)T0 * (uint64_t)T1);
367
    set_HILO(get_HILO() + tmp);
368
    RETURN();
369
}
370

    
371
void op_msub (void)
372
{
373
    int64_t tmp;
374

    
375
    tmp = ((int64_t)T0 * (int64_t)T1);
376
    set_HILO((int64_t)get_HILO() - tmp);
377
    RETURN();
378
}
379

    
380
void op_msubu (void)
381
{
382
    uint64_t tmp;
383

    
384
    tmp = ((uint64_t)T0 * (uint64_t)T1);
385
    set_HILO(get_HILO() - tmp);
386
    RETURN();
387
}
388
#else
389
void op_mult (void)
390
{
391
    CALL_FROM_TB0(do_mult);
392
    RETURN();
393
}
394

    
395
void op_multu (void)
396
{
397
    CALL_FROM_TB0(do_multu);
398
    RETURN();
399
}
400

    
401
void op_madd (void)
402
{
403
    CALL_FROM_TB0(do_madd);
404
    RETURN();
405
}
406

    
407
void op_maddu (void)
408
{
409
    CALL_FROM_TB0(do_maddu);
410
    RETURN();
411
}
412

    
413
void op_msub (void)
414
{
415
    CALL_FROM_TB0(do_msub);
416
    RETURN();
417
}
418

    
419
void op_msubu (void)
420
{
421
    CALL_FROM_TB0(do_msubu);
422
    RETURN();
423
}
424
#endif
425

    
426
/* Conditional moves */
427
void op_movn (void)
428
{
429
    if (T1 != 0)
430
        env->gpr[PARAM1] = T0;
431
    RETURN();
432
}
433

    
434
void op_movz (void)
435
{
436
    if (T1 == 0)
437
        env->gpr[PARAM1] = T0;
438
    RETURN();
439
}
440

    
441
/* Tests */
442
#define OP_COND(name, cond) \
443
void glue(op_, name) (void) \
444
{                           \
445
    if (cond) {             \
446
        T0 = 1;             \
447
    } else {                \
448
        T0 = 0;             \
449
    }                       \
450
    RETURN();               \
451
}
452

    
453
OP_COND(eq, T0 == T1);
454
OP_COND(ne, T0 != T1);
455
OP_COND(ge, (int32_t)T0 >= (int32_t)T1);
456
OP_COND(geu, T0 >= T1);
457
OP_COND(lt, (int32_t)T0 < (int32_t)T1);
458
OP_COND(ltu, T0 < T1);
459
OP_COND(gez, (int32_t)T0 >= 0);
460
OP_COND(gtz, (int32_t)T0 > 0);
461
OP_COND(lez, (int32_t)T0 <= 0);
462
OP_COND(ltz, (int32_t)T0 < 0);
463

    
464
/* Branchs */
465
//#undef USE_DIRECT_JUMP
466
#define EIP env->PC
467

    
468
/* Branch to register */
469
void op_save_breg_target (void)
470
{
471
    env->btarget = T2;
472
}
473

    
474
void op_restore_breg_target (void)
475
{
476
    T2 = env->btarget;
477
}
478

    
479
void op_breg (void)
480
{
481
    env->PC = T2;
482
    RETURN();
483
}
484

    
485
/* Unconditional branch */
486
void op_branch (void)
487
{
488
    JUMP_TB(branch, PARAM1, 0, PARAM2);
489
    RETURN();
490
}
491

    
492
void op_save_btarget (void)
493
{
494
    env->btarget = PARAM1;
495
    RETURN();
496
}
497

    
498
/* Conditional branch */
499
void op_set_bcond (void)
500
{
501
    T2 = T0;
502
    RETURN();
503
}
504

    
505
void op_save_bcond (void)
506
{
507
    env->bcond = T2;
508
    RETURN();
509
}
510

    
511
void op_restore_bcond (void)
512
{
513
    T2 = env->bcond;
514
    RETURN();
515
}
516

    
517
void op_bcond (void)
518
{
519
    if (T2) {
520
        JUMP_TB(bcond, PARAM1, 0, PARAM2);
521
    } else {
522
        JUMP_TB(bcond, PARAM1, 1, PARAM3);
523
    }
524
    RETURN();
525
}
526

    
527
/* Likely branch (used to skip the delay slot) */
528
void op_blikely (void)
529
{
530
    /* If the test is false, skip the delay slot */
531
    if (T2 == 0) {
532
        env->hflags = PARAM3;
533
        JUMP_TB(blikely, PARAM1, 1, PARAM2);
534
    }
535
    RETURN();
536
}
537

    
538
/* CP0 functions */
539
void op_mfc0 (void)
540
{
541
    CALL_FROM_TB2(do_mfc0, PARAM1, PARAM2);
542
    RETURN();
543
}
544

    
545
void op_mtc0 (void)
546
{
547
    CALL_FROM_TB2(do_mtc0, PARAM1, PARAM2);
548
    RETURN();
549
}
550

    
551
#if defined(MIPS_USES_R4K_TLB)
552
void op_tlbwi (void)
553
{
554
    CALL_FROM_TB0(do_tlbwi);
555
    RETURN();
556
}
557

    
558
void op_tlbwr (void)
559
{
560
    CALL_FROM_TB0(do_tlbwr);
561
    RETURN();
562
}
563

    
564
void op_tlbp (void)
565
{
566
    CALL_FROM_TB0(do_tlbp);
567
    RETURN();
568
}
569

    
570
void op_tlbr (void)
571
{
572
    CALL_FROM_TB0(do_tlbr);
573
    RETURN();
574
}
575
#endif
576

    
577
/* Specials */
578
void op_pmon (void)
579
{
580
    CALL_FROM_TB1(do_pmon, PARAM1);
581
}
582

    
583
void op_trap (void)
584
{
585
    if (T0) {
586
        CALL_FROM_TB1(do_raise_exception, EXCP_TRAP);
587
    }
588
    RETURN();
589
}
590

    
591
void op_set_lladdr (void)
592
{
593
    env->CP0_LLAddr = T2;
594
}
595

    
596
void debug_eret (void);
597
void op_eret (void)
598
{
599
    CALL_FROM_TB0(debug_eret);
600
    if (env->hflags & MIPS_HFLAG_ERL)
601
        env->PC = env->CP0_ErrorEPC;
602
    else
603
        env->PC = env->CP0_EPC;
604
    env->CP0_LLAddr = 1;
605
}
606

    
607
void op_deret (void)
608
{
609
    CALL_FROM_TB0(debug_eret);
610
    env->PC = env->CP0_DEPC;
611
}
612

    
613
void op_save_state (void)
614
{
615
    env->hflags = PARAM1;
616
    RETURN();
617
}
618

    
619
void op_save_pc (void)
620
{
621
    env->PC = PARAM1;
622
    RETURN();
623
}
624

    
625
void op_raise_exception (void)
626
{
627
    CALL_FROM_TB1(do_raise_exception, PARAM1);
628
    RETURN();
629
}
630

    
631
void op_raise_exception_err (void)
632
{
633
    CALL_FROM_TB2(do_raise_exception_err, PARAM1, PARAM2);
634
    RETURN();
635
}
636

    
637
void op_exit_tb (void)
638
{
639
    EXIT_TB();
640
}
641