BGR_FORMAT fix
[qemu] / target-mips / op.c
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 }