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