fixed eret insn (Ralf Baechle)
[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 #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         env->hflags &= ~MIPS_HFLAG_ERL;
603     } else {
604         env->PC = env->CP0_EPC;
605         env->hflags &= ~MIPS_HFLAG_EXL;
606     }
607     env->CP0_LLAddr = 1;
608 }
609
610 void op_deret (void)
611 {
612     CALL_FROM_TB0(debug_eret);
613     env->PC = env->CP0_DEPC;
614 }
615
616 void op_save_state (void)
617 {
618     env->hflags = PARAM1;
619     RETURN();
620 }
621
622 void op_save_pc (void)
623 {
624     env->PC = PARAM1;
625     RETURN();
626 }
627
628 void op_raise_exception (void)
629 {
630     CALL_FROM_TB1(do_raise_exception, PARAM1);
631     RETURN();
632 }
633
634 void op_raise_exception_err (void)
635 {
636     CALL_FROM_TB2(do_raise_exception_err, PARAM1, PARAM2);
637     RETURN();
638 }
639
640 void op_exit_tb (void)
641 {
642     EXIT_TB();
643 }
644