|
|
1.1 root 1: /*
2: * MIPS emulation helpers 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: #include <math.h>
21: #include "exec.h"
22:
23: #define MIPS_DEBUG_DISAS
24:
1.1.1.2 ! root 25: #define GETPC() (__builtin_return_address(0))
! 26:
1.1 root 27: /*****************************************************************************/
28: /* Exceptions processing helpers */
29: void cpu_loop_exit(void)
30: {
31: longjmp(env->jmp_env, 1);
32: }
33:
34: void do_raise_exception_err (uint32_t exception, int error_code)
35: {
36: #if 1
37: if (logfile && exception < 0x100)
38: fprintf(logfile, "%s: %d %d\n", __func__, exception, error_code);
39: #endif
40: env->exception_index = exception;
41: env->error_code = error_code;
42: T0 = 0;
43: cpu_loop_exit();
44: }
45:
46: void do_raise_exception (uint32_t exception)
47: {
48: do_raise_exception_err(exception, 0);
49: }
50:
1.1.1.2 ! root 51: void do_restore_state (void *pc_ptr)
! 52: {
! 53: TranslationBlock *tb;
! 54: unsigned long pc = (unsigned long) pc_ptr;
! 55:
! 56: tb = tb_find_pc (pc);
! 57: cpu_restore_state (tb, env, pc, NULL);
! 58: }
! 59:
! 60: void do_raise_exception_direct (uint32_t exception)
! 61: {
! 62: do_restore_state (GETPC ());
! 63: do_raise_exception_err (exception, 0);
! 64: }
! 65:
1.1 root 66: #define MEMSUFFIX _raw
67: #include "op_helper_mem.c"
68: #undef MEMSUFFIX
69: #if !defined(CONFIG_USER_ONLY)
70: #define MEMSUFFIX _user
71: #include "op_helper_mem.c"
72: #undef MEMSUFFIX
73: #define MEMSUFFIX _kernel
74: #include "op_helper_mem.c"
75: #undef MEMSUFFIX
76: #endif
77:
78: /* 64 bits arithmetic for 32 bits hosts */
79: #if (HOST_LONG_BITS == 32)
80: static inline uint64_t get_HILO (void)
81: {
82: return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
83: }
84:
85: static inline void set_HILO (uint64_t HILO)
86: {
87: env->LO = HILO & 0xFFFFFFFF;
88: env->HI = HILO >> 32;
89: }
90:
91: void do_mult (void)
92: {
1.1.1.2 ! root 93: set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
1.1 root 94: }
95:
96: void do_multu (void)
97: {
98: set_HILO((uint64_t)T0 * (uint64_t)T1);
99: }
100:
101: void do_madd (void)
102: {
103: int64_t tmp;
104:
1.1.1.2 ! root 105: tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
1.1 root 106: set_HILO((int64_t)get_HILO() + tmp);
107: }
108:
109: void do_maddu (void)
110: {
111: uint64_t tmp;
112:
113: tmp = ((uint64_t)T0 * (uint64_t)T1);
114: set_HILO(get_HILO() + tmp);
115: }
116:
117: void do_msub (void)
118: {
119: int64_t tmp;
120:
1.1.1.2 ! root 121: tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
1.1 root 122: set_HILO((int64_t)get_HILO() - tmp);
123: }
124:
125: void do_msubu (void)
126: {
127: uint64_t tmp;
128:
129: tmp = ((uint64_t)T0 * (uint64_t)T1);
130: set_HILO(get_HILO() - tmp);
131: }
132: #endif
133:
1.1.1.2 ! root 134: #if defined(CONFIG_USER_ONLY)
! 135: void do_mfc0 (int reg, int sel)
! 136: {
! 137: cpu_abort(env, "mfc0 reg=%d sel=%d\n", reg, sel);
! 138: }
! 139: void do_mtc0 (int reg, int sel)
! 140: {
! 141: cpu_abort(env, "mtc0 reg=%d sel=%d\n", reg, sel);
! 142: }
! 143:
! 144: void do_tlbwi (void)
! 145: {
! 146: cpu_abort(env, "tlbwi\n");
! 147: }
! 148:
! 149: void do_tlbwr (void)
! 150: {
! 151: cpu_abort(env, "tlbwr\n");
! 152: }
! 153:
! 154: void do_tlbp (void)
! 155: {
! 156: cpu_abort(env, "tlbp\n");
! 157: }
! 158:
! 159: void do_tlbr (void)
! 160: {
! 161: cpu_abort(env, "tlbr\n");
! 162: }
! 163: #else
! 164:
1.1 root 165: /* CP0 helpers */
166: void do_mfc0 (int reg, int sel)
167: {
168: const unsigned char *rn;
169:
170: if (sel != 0 && reg != 16 && reg != 28) {
171: rn = "invalid";
172: goto print;
173: }
174: switch (reg) {
175: case 0:
176: T0 = env->CP0_index;
177: rn = "Index";
178: break;
179: case 1:
180: T0 = cpu_mips_get_random(env);
181: rn = "Random";
182: break;
183: case 2:
184: T0 = env->CP0_EntryLo0;
185: rn = "EntryLo0";
186: break;
187: case 3:
188: T0 = env->CP0_EntryLo1;
189: rn = "EntryLo1";
190: break;
191: case 4:
192: T0 = env->CP0_Context;
193: rn = "Context";
194: break;
195: case 5:
196: T0 = env->CP0_PageMask;
197: rn = "PageMask";
198: break;
199: case 6:
200: T0 = env->CP0_Wired;
201: rn = "Wired";
202: break;
203: case 8:
204: T0 = env->CP0_BadVAddr;
205: rn = "BadVaddr";
206: break;
207: case 9:
208: T0 = cpu_mips_get_count(env);
209: rn = "Count";
210: break;
211: case 10:
212: T0 = env->CP0_EntryHi;
213: rn = "EntryHi";
214: break;
215: case 11:
216: T0 = env->CP0_Compare;
217: rn = "Compare";
218: break;
219: case 12:
220: T0 = env->CP0_Status;
221: if (env->hflags & MIPS_HFLAG_UM)
222: T0 |= (1 << CP0St_UM);
223: if (env->hflags & MIPS_HFLAG_ERL)
224: T0 |= (1 << CP0St_ERL);
225: if (env->hflags & MIPS_HFLAG_EXL)
226: T0 |= (1 << CP0St_EXL);
227: rn = "Status";
228: break;
229: case 13:
230: T0 = env->CP0_Cause;
231: rn = "Cause";
232: break;
233: case 14:
234: T0 = env->CP0_EPC;
235: rn = "EPC";
236: break;
237: case 15:
238: T0 = env->CP0_PRid;
239: rn = "PRid";
240: break;
241: case 16:
242: switch (sel) {
243: case 0:
244: T0 = env->CP0_Config0;
245: rn = "Config";
246: break;
247: case 1:
248: T0 = env->CP0_Config1;
249: rn = "Config1";
250: break;
251: default:
252: rn = "Unknown config register";
253: break;
254: }
255: break;
256: case 17:
257: T0 = env->CP0_LLAddr >> 4;
258: rn = "LLAddr";
259: break;
260: case 18:
261: T0 = env->CP0_WatchLo;
262: rn = "WatchLo";
263: break;
264: case 19:
265: T0 = env->CP0_WatchHi;
266: rn = "WatchHi";
267: break;
268: case 23:
269: T0 = env->CP0_Debug;
270: if (env->hflags & MIPS_HFLAG_DM)
271: T0 |= 1 << CP0DB_DM;
272: rn = "Debug";
273: break;
274: case 24:
275: T0 = env->CP0_DEPC;
276: rn = "DEPC";
277: break;
278: case 28:
279: switch (sel) {
280: case 0:
281: T0 = env->CP0_TagLo;
282: rn = "TagLo";
283: break;
284: case 1:
285: T0 = env->CP0_DataLo;
286: rn = "DataLo";
287: break;
288: default:
289: rn = "unknown sel";
290: break;
291: }
292: break;
293: case 30:
294: T0 = env->CP0_ErrorEPC;
295: rn = "ErrorEPC";
296: break;
297: case 31:
298: T0 = env->CP0_DESAVE;
299: rn = "DESAVE";
300: break;
301: default:
302: rn = "unknown";
303: break;
304: }
305: print:
306: #if defined MIPS_DEBUG_DISAS
307: if (loglevel & CPU_LOG_TB_IN_ASM) {
308: fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
309: env->PC, rn, T0, reg, sel);
310: }
311: #endif
312: return;
313: }
314:
315: void do_mtc0 (int reg, int sel)
316: {
317: const unsigned char *rn;
318: uint32_t val, old, mask;
319:
320: if (sel != 0 && reg != 16 && reg != 28) {
321: val = -1;
322: old = -1;
323: rn = "invalid";
324: goto print;
325: }
326: switch (reg) {
327: case 0:
328: val = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F);
329: old = env->CP0_index;
330: env->CP0_index = val;
331: rn = "Index";
332: break;
333: case 2:
334: val = T0 & 0x03FFFFFFF;
335: old = env->CP0_EntryLo0;
336: env->CP0_EntryLo0 = val;
337: rn = "EntryLo0";
338: break;
339: case 3:
340: val = T0 & 0x03FFFFFFF;
341: old = env->CP0_EntryLo1;
342: env->CP0_EntryLo1 = val;
343: rn = "EntryLo1";
344: break;
345: case 4:
346: val = (env->CP0_Context & 0xFF000000) | (T0 & 0x00FFFFF0);
347: old = env->CP0_Context;
348: env->CP0_Context = val;
349: rn = "Context";
350: break;
351: case 5:
352: val = T0 & 0x01FFE000;
353: old = env->CP0_PageMask;
354: env->CP0_PageMask = val;
355: rn = "PageMask";
356: break;
357: case 6:
358: val = T0 & 0x0000000F;
359: old = env->CP0_Wired;
360: env->CP0_Wired = val;
361: rn = "Wired";
362: break;
363: case 9:
364: val = T0;
365: old = cpu_mips_get_count(env);
366: cpu_mips_store_count(env, val);
367: rn = "Count";
368: break;
369: case 10:
370: val = T0 & 0xFFFFF0FF;
371: old = env->CP0_EntryHi;
372: env->CP0_EntryHi = val;
1.1.1.2 ! root 373: /* If the ASID changes, flush qemu's TLB. */
! 374: if ((old & 0xFF) != (val & 0xFF))
! 375: tlb_flush (env, 1);
1.1 root 376: rn = "EntryHi";
377: break;
378: case 11:
379: val = T0;
380: old = env->CP0_Compare;
381: cpu_mips_store_compare(env, val);
382: rn = "Compare";
383: break;
384: case 12:
385: val = T0 & 0xFA78FF01;
386: if (T0 & (1 << CP0St_UM))
387: env->hflags |= MIPS_HFLAG_UM;
388: else
389: env->hflags &= ~MIPS_HFLAG_UM;
390: if (T0 & (1 << CP0St_ERL))
391: env->hflags |= MIPS_HFLAG_ERL;
392: else
393: env->hflags &= ~MIPS_HFLAG_ERL;
394: if (T0 & (1 << CP0St_EXL))
395: env->hflags |= MIPS_HFLAG_EXL;
396: else
397: env->hflags &= ~MIPS_HFLAG_EXL;
398: old = env->CP0_Status;
399: env->CP0_Status = val;
400: /* If we unmasked an asserted IRQ, raise it */
401: mask = 0x0000FF00;
402: if (loglevel & CPU_LOG_TB_IN_ASM) {
403: fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n",
404: old, val, env->CP0_Cause, old & mask, val & mask,
405: env->CP0_Cause & mask);
406: }
407: #if 1
408: if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) &&
409: !(env->hflags & MIPS_HFLAG_EXL) &&
410: !(env->hflags & MIPS_HFLAG_ERL) &&
411: !(env->hflags & MIPS_HFLAG_DM) &&
412: (env->CP0_Status & env->CP0_Cause & mask)) {
413: if (logfile)
414: fprintf(logfile, "Raise pending IRQs\n");
415: env->interrupt_request |= CPU_INTERRUPT_HARD;
416: do_raise_exception(EXCP_EXT_INTERRUPT);
417: } else if (!(val & 0x00000001) && (old & 0x00000001)) {
418: env->interrupt_request &= ~CPU_INTERRUPT_HARD;
419: }
420: #endif
421: rn = "Status";
422: break;
423: case 13:
424: val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300);
425: old = env->CP0_Cause;
426: env->CP0_Cause = val;
427: #if 0
428: {
429: int i;
430: /* Check if we ever asserted a software IRQ */
431: for (i = 0; i < 2; i++) {
432: mask = 0x100 << i;
433: if ((val & mask) & !(old & mask))
434: mips_set_irq(i);
435: }
436: }
437: #endif
438: rn = "Cause";
439: break;
440: case 14:
441: val = T0;
442: old = env->CP0_EPC;
443: env->CP0_EPC = val;
444: rn = "EPC";
445: break;
446: case 16:
447: switch (sel) {
448: case 0:
449: #if defined(MIPS_USES_R4K_TLB)
450: val = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001);
451: #else
452: val = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001);
453: #endif
454: old = env->CP0_Config0;
455: env->CP0_Config0 = val;
456: rn = "Config0";
457: break;
458: default:
459: val = -1;
460: old = -1;
461: rn = "bad config selector";
462: break;
463: }
464: break;
465: case 18:
466: val = T0;
467: old = env->CP0_WatchLo;
468: env->CP0_WatchLo = val;
469: rn = "WatchLo";
470: break;
471: case 19:
472: val = T0 & 0x40FF0FF8;
473: old = env->CP0_WatchHi;
474: env->CP0_WatchHi = val;
475: rn = "WatchHi";
476: break;
477: case 23:
478: val = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120);
479: if (T0 & (1 << CP0DB_DM))
480: env->hflags |= MIPS_HFLAG_DM;
481: else
482: env->hflags &= ~MIPS_HFLAG_DM;
483: old = env->CP0_Debug;
484: env->CP0_Debug = val;
485: rn = "Debug";
486: break;
487: case 24:
488: val = T0;
489: old = env->CP0_DEPC;
490: env->CP0_DEPC = val;
491: rn = "DEPC";
492: break;
493: case 28:
494: switch (sel) {
495: case 0:
496: val = T0 & 0xFFFFFCF6;
497: old = env->CP0_TagLo;
498: env->CP0_TagLo = val;
499: rn = "TagLo";
500: break;
501: default:
502: val = -1;
503: old = -1;
504: rn = "invalid sel";
505: break;
506: }
507: break;
508: case 30:
509: val = T0;
510: old = env->CP0_ErrorEPC;
511: env->CP0_ErrorEPC = val;
512: rn = "EPC";
513: break;
514: case 31:
515: val = T0;
516: old = env->CP0_DESAVE;
517: env->CP0_DESAVE = val;
518: rn = "DESAVE";
519: break;
520: default:
521: val = -1;
522: old = -1;
523: rn = "unknown";
524: break;
525: }
526: print:
527: #if defined MIPS_DEBUG_DISAS
528: if (loglevel & CPU_LOG_TB_IN_ASM) {
529: fprintf(logfile, "%08x mtc0 %s %08x => %08x (%d %d %08x)\n",
530: env->PC, rn, T0, val, reg, sel, old);
531: }
532: #endif
533: return;
534: }
535:
536: /* TLB management */
537: #if defined(MIPS_USES_R4K_TLB)
538: static void invalidate_tb (int idx)
539: {
540: tlb_t *tlb;
541: target_ulong addr, end;
542:
543: tlb = &env->tlb[idx];
544: if (tlb->V[0]) {
545: addr = tlb->PFN[0];
546: end = addr + (tlb->end - tlb->VPN);
547: tb_invalidate_page_range(addr, end);
1.1.1.2 ! root 548: /* FIXME: Might be faster to just invalidate the whole "tlb" here
! 549: and refill it on demand from our simulated TLB. */
! 550: addr = tlb->VPN;
! 551: while (addr < tlb->end) {
! 552: tlb_flush_page (env, addr);
! 553: addr += TARGET_PAGE_SIZE;
! 554: }
1.1 root 555: }
556: if (tlb->V[1]) {
557: addr = tlb->PFN[1];
558: end = addr + (tlb->end - tlb->VPN);
559: tb_invalidate_page_range(addr, end);
1.1.1.2 ! root 560: /* FIXME: Might be faster to just invalidate the whole "tlb" here
! 561: and refill it on demand from our simulated TLB. */
! 562: addr = tlb->end;
! 563: while (addr < tlb->end2) {
! 564: tlb_flush_page (env, addr);
! 565: addr += TARGET_PAGE_SIZE;
! 566: }
1.1 root 567: }
568: }
569:
570: static void fill_tb (int idx)
571: {
572: tlb_t *tlb;
573: int size;
574:
575: /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
576: tlb = &env->tlb[idx];
577: tlb->VPN = env->CP0_EntryHi & 0xFFFFE000;
578: tlb->ASID = env->CP0_EntryHi & 0x000000FF;
579: size = env->CP0_PageMask >> 13;
580: size = 4 * (size + 1);
581: tlb->end = tlb->VPN + (1 << (8 + size));
1.1.1.2 ! root 582: tlb->end2 = tlb->end + (1 << (8 + size));
1.1 root 583: tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
584: tlb->V[0] = env->CP0_EntryLo0 & 2;
585: tlb->D[0] = env->CP0_EntryLo0 & 4;
586: tlb->C[0] = (env->CP0_EntryLo0 >> 3) & 0x7;
587: tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
588: tlb->V[1] = env->CP0_EntryLo1 & 2;
589: tlb->D[1] = env->CP0_EntryLo1 & 4;
590: tlb->C[1] = (env->CP0_EntryLo1 >> 3) & 0x7;
591: tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
592: }
593:
594: void do_tlbwi (void)
595: {
596: /* Wildly undefined effects for CP0_index containing a too high value and
597: MIPS_TLB_NB not being a power of two. But so does real silicon. */
598: invalidate_tb(env->CP0_index & (MIPS_TLB_NB - 1));
599: fill_tb(env->CP0_index & (MIPS_TLB_NB - 1));
600: }
601:
602: void do_tlbwr (void)
603: {
604: int r = cpu_mips_get_random(env);
605:
606: invalidate_tb(r);
607: fill_tb(r);
608: }
609:
610: void do_tlbp (void)
611: {
612: tlb_t *tlb;
613: target_ulong tag;
614: uint8_t ASID;
615: int i;
616:
617: tag = (env->CP0_EntryHi & 0xFFFFE000);
618: ASID = env->CP0_EntryHi & 0x000000FF;
619: for (i = 0; i < MIPS_TLB_NB; i++) {
620: tlb = &env->tlb[i];
621: /* Check ASID, virtual page number & size */
622: if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) {
623: /* TLB match */
624: env->CP0_index = i;
625: break;
626: }
627: }
628: if (i == MIPS_TLB_NB) {
629: env->CP0_index |= 0x80000000;
630: }
631: }
632:
633: void do_tlbr (void)
634: {
635: tlb_t *tlb;
636: int size;
637:
638: tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)];
1.1.1.2 ! root 639:
! 640: /* If this will change the current ASID, flush qemu's TLB. */
! 641: /* FIXME: Could avoid flushing things which match global entries... */
! 642: if ((env->CP0_EntryHi & 0xFF) != tlb->ASID)
! 643: tlb_flush (env, 1);
! 644:
1.1 root 645: env->CP0_EntryHi = tlb->VPN | tlb->ASID;
646: size = (tlb->end - tlb->VPN) >> 12;
647: env->CP0_PageMask = (size - 1) << 13;
648: env->CP0_EntryLo0 = tlb->V[0] | tlb->D[0] | (tlb->C[0] << 3) |
649: (tlb->PFN[0] >> 6);
650: env->CP0_EntryLo1 = tlb->V[1] | tlb->D[1] | (tlb->C[1] << 3) |
651: (tlb->PFN[1] >> 6);
652: }
653: #endif
654:
1.1.1.2 ! root 655: #endif /* !CONFIG_USER_ONLY */
! 656:
1.1 root 657: void op_dump_ldst (const unsigned char *func)
658: {
659: if (loglevel)
660: fprintf(logfile, "%s => %08x %08x\n", __func__, T0, T1);
661: }
662:
663: void dump_sc (void)
664: {
665: if (loglevel) {
666: fprintf(logfile, "%s %08x at %08x (%08x)\n", __func__,
667: T1, T0, env->CP0_LLAddr);
668: }
669: }
670:
671: void debug_eret (void)
672: {
673: if (loglevel) {
674: fprintf(logfile, "ERET: pc %08x EPC %08x ErrorEPC %08x (%d)\n",
675: env->PC, env->CP0_EPC, env->CP0_ErrorEPC,
676: env->hflags & MIPS_HFLAG_ERL ? 1 : 0);
677: }
678: }
679:
680: void do_pmon (int function)
681: {
682: function /= 2;
683: switch (function) {
684: case 2: /* TODO: char inbyte(int waitflag); */
685: if (env->gpr[4] == 0)
686: env->gpr[2] = -1;
687: /* Fall through */
688: case 11: /* TODO: char inbyte (void); */
689: env->gpr[2] = -1;
690: break;
691: case 3:
692: case 12:
693: printf("%c", env->gpr[4] & 0xFF);
694: break;
695: case 17:
696: break;
697: case 158:
698: {
699: unsigned char *fmt = (void *)env->gpr[4];
700: printf("%s", fmt);
701: }
702: break;
703: }
704: }
705:
706: #if !defined(CONFIG_USER_ONLY)
707:
1.1.1.2 ! root 708: static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
! 709:
1.1 root 710: #define MMUSUFFIX _mmu
1.1.1.2 ! root 711: #define ALIGNED_ONLY
1.1 root 712:
713: #define SHIFT 0
714: #include "softmmu_template.h"
715:
716: #define SHIFT 1
717: #include "softmmu_template.h"
718:
719: #define SHIFT 2
720: #include "softmmu_template.h"
721:
722: #define SHIFT 3
723: #include "softmmu_template.h"
724:
1.1.1.2 ! root 725: static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
! 726: {
! 727: env->CP0_BadVAddr = addr;
! 728: do_restore_state (retaddr);
! 729: do_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
! 730: }
! 731:
1.1 root 732: void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
733: {
734: TranslationBlock *tb;
735: CPUState *saved_env;
736: unsigned long pc;
737: int ret;
738:
739: /* XXX: hack to restore env in all cases, even if not called from
740: generated code */
741: saved_env = env;
742: env = cpu_single_env;
743: ret = cpu_mips_handle_mmu_fault(env, addr, is_write, is_user, 1);
744: if (ret) {
745: if (retaddr) {
746: /* now we have a real cpu fault */
747: pc = (unsigned long)retaddr;
748: tb = tb_find_pc(pc);
749: if (tb) {
750: /* the PC is inside the translated code. It means that we have
751: a virtual CPU fault */
752: cpu_restore_state(tb, env, pc, NULL);
753: }
754: }
755: do_raise_exception_err(env->exception_index, env->error_code);
756: }
757: env = saved_env;
758: }
759:
760: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.