disable debug mode
[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 ((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 }