|
|
1.1 root 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, 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, 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)T0 * (int64_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)T0 * (int64_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)T0 * (int64_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: #define EIP env->PC
491:
492: /* Branch to register */
493: void op_save_breg_target (void)
494: {
495: env->btarget = T2;
496: }
497:
498: void op_restore_breg_target (void)
499: {
500: T2 = env->btarget;
501: }
502:
503: void op_breg (void)
504: {
505: env->PC = T2;
506: RETURN();
507: }
508:
509: /* Unconditional branch */
510: void op_branch (void)
511: {
512: JUMP_TB(branch, PARAM1, 0, PARAM2);
513: RETURN();
514: }
515:
516: void op_save_btarget (void)
517: {
518: env->btarget = PARAM1;
519: RETURN();
520: }
521:
522: /* Conditional branch */
523: void op_set_bcond (void)
524: {
525: T2 = T0;
526: RETURN();
527: }
528:
529: void op_save_bcond (void)
530: {
531: env->bcond = T2;
532: RETURN();
533: }
534:
535: void op_restore_bcond (void)
536: {
537: T2 = env->bcond;
538: RETURN();
539: }
540:
541: void op_bcond (void)
542: {
543: if (T2) {
544: JUMP_TB(bcond, PARAM1, 0, PARAM2);
545: } else {
546: JUMP_TB(bcond, PARAM1, 1, PARAM3);
547: }
548: RETURN();
549: }
550:
551: /* Likely branch (used to skip the delay slot) */
552: void op_blikely (void)
553: {
554: /* If the test is false, skip the delay slot */
555: if (T2 == 0) {
556: env->hflags = PARAM3;
557: JUMP_TB(blikely, PARAM1, 1, PARAM2);
558: }
559: RETURN();
560: }
561:
562: /* CP0 functions */
563: void op_mfc0 (void)
564: {
565: CALL_FROM_TB2(do_mfc0, PARAM1, PARAM2);
566: RETURN();
567: }
568:
569: void op_mtc0 (void)
570: {
571: CALL_FROM_TB2(do_mtc0, PARAM1, PARAM2);
572: RETURN();
573: }
574:
575: #if defined(MIPS_USES_R4K_TLB)
576: void op_tlbwi (void)
577: {
578: CALL_FROM_TB0(do_tlbwi);
579: RETURN();
580: }
581:
582: void op_tlbwr (void)
583: {
584: CALL_FROM_TB0(do_tlbwr);
585: RETURN();
586: }
587:
588: void op_tlbp (void)
589: {
590: CALL_FROM_TB0(do_tlbp);
591: RETURN();
592: }
593:
594: void op_tlbr (void)
595: {
596: CALL_FROM_TB0(do_tlbr);
597: RETURN();
598: }
599: #endif
600:
601: /* Specials */
602: void op_pmon (void)
603: {
604: CALL_FROM_TB1(do_pmon, PARAM1);
605: }
606:
607: void op_trap (void)
608: {
609: if (T0) {
610: CALL_FROM_TB1(do_raise_exception, EXCP_TRAP);
611: }
612: RETURN();
613: }
614:
615: void op_set_lladdr (void)
616: {
617: env->CP0_LLAddr = T2;
618: }
619:
620: void debug_eret (void);
621: void op_eret (void)
622: {
623: CALL_FROM_TB0(debug_eret);
624: if (env->hflags & MIPS_HFLAG_ERL) {
625: env->PC = env->CP0_ErrorEPC;
626: env->hflags &= ~MIPS_HFLAG_ERL;
627: } else {
628: env->PC = env->CP0_EPC;
629: env->hflags &= ~MIPS_HFLAG_EXL;
630: }
631: env->CP0_LLAddr = 1;
632: }
633:
634: void op_deret (void)
635: {
636: CALL_FROM_TB0(debug_eret);
637: env->PC = env->CP0_DEPC;
638: }
639:
640: void op_save_state (void)
641: {
642: env->hflags = PARAM1;
643: RETURN();
644: }
645:
646: void op_save_pc (void)
647: {
648: env->PC = PARAM1;
649: RETURN();
650: }
651:
652: void op_raise_exception (void)
653: {
654: CALL_FROM_TB1(do_raise_exception, PARAM1);
655: RETURN();
656: }
657:
658: void op_raise_exception_err (void)
659: {
660: CALL_FROM_TB2(do_raise_exception_err, PARAM1, PARAM2);
661: RETURN();
662: }
663:
664: void op_exit_tb (void)
665: {
666: EXIT_TB();
667: }
668:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.