]> git.proxmox.com Git - mirror_qemu.git/blame - target-mips/op_helper.c
Dynamically translate MIPS mfc0 instructions.
[mirror_qemu.git] / target-mips / op_helper.c
CommitLineData
6af0bf9c
FB
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 */
6af0bf9c
FB
20#include "exec.h"
21
22#define MIPS_DEBUG_DISAS
23
4ad40f36
FB
24#define GETPC() (__builtin_return_address(0))
25
6af0bf9c
FB
26/*****************************************************************************/
27/* Exceptions processing helpers */
28void cpu_loop_exit(void)
29{
30 longjmp(env->jmp_env, 1);
31}
32
6af0bf9c
FB
33void 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
6af0bf9c
FB
45void do_raise_exception (uint32_t exception)
46{
47 do_raise_exception_err(exception, 0);
48}
49
4ad40f36
FB
50void 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
59void do_raise_exception_direct (uint32_t exception)
60{
61 do_restore_state (GETPC ());
62 do_raise_exception_err (exception, 0);
63}
64
6af0bf9c
FB
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)
79static inline uint64_t get_HILO (void)
80{
81 return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
82}
83
84static inline void set_HILO (uint64_t HILO)
85{
86 env->LO = HILO & 0xFFFFFFFF;
87 env->HI = HILO >> 32;
88}
89
90void do_mult (void)
91{
4ad40f36 92 set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
6af0bf9c
FB
93}
94
95void do_multu (void)
96{
97 set_HILO((uint64_t)T0 * (uint64_t)T1);
98}
99
100void do_madd (void)
101{
102 int64_t tmp;
103
4ad40f36 104 tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
6af0bf9c
FB
105 set_HILO((int64_t)get_HILO() + tmp);
106}
107
108void 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
116void do_msub (void)
117{
118 int64_t tmp;
119
4ad40f36 120 tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
6af0bf9c
FB
121 set_HILO((int64_t)get_HILO() - tmp);
122}
123
124void 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
048f6b4d 133#if defined(CONFIG_USER_ONLY)
873eb012 134void do_mfc0_random (void)
048f6b4d 135{
873eb012 136 cpu_abort(env, "mfc0 random\n");
048f6b4d 137}
873eb012
TS
138
139void do_mfc0_count (void)
140{
141 cpu_abort(env, "mfc0 count\n");
142}
143
048f6b4d
FB
144void do_mtc0 (int reg, int sel)
145{
146 cpu_abort(env, "mtc0 reg=%d sel=%d\n", reg, sel);
147}
148
149void do_tlbwi (void)
150{
151 cpu_abort(env, "tlbwi\n");
152}
153
154void do_tlbwr (void)
155{
156 cpu_abort(env, "tlbwr\n");
157}
158
159void do_tlbp (void)
160{
161 cpu_abort(env, "tlbp\n");
162}
163
164void do_tlbr (void)
165{
166 cpu_abort(env, "tlbr\n");
167}
873eb012 168
048f6b4d
FB
169#else
170
6af0bf9c 171/* CP0 helpers */
873eb012 172void do_mfc0_random (void)
6af0bf9c 173{
873eb012
TS
174 T0 = cpu_mips_get_random(env);
175}
6af0bf9c 176
873eb012
TS
177void do_mfc0_count (void)
178{
179 T0 = cpu_mips_get_count(env);
6af0bf9c
FB
180}
181
6af0bf9c
FB
182void do_mtc0 (int reg, int sel)
183{
184 const unsigned char *rn;
185 uint32_t val, old, mask;
6af0bf9c
FB
186
187 if (sel != 0 && reg != 16 && reg != 28) {
188 val = -1;
189 old = -1;
190 rn = "invalid";
191 goto print;
192 }
193 switch (reg) {
194 case 0:
195 val = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F);
196 old = env->CP0_index;
197 env->CP0_index = val;
198 rn = "Index";
199 break;
200 case 2:
3d9fb9fe 201 val = T0 & 0x3FFFFFFF;
6af0bf9c
FB
202 old = env->CP0_EntryLo0;
203 env->CP0_EntryLo0 = val;
204 rn = "EntryLo0";
205 break;
206 case 3:
3d9fb9fe 207 val = T0 & 0x3FFFFFFF;
6af0bf9c
FB
208 old = env->CP0_EntryLo1;
209 env->CP0_EntryLo1 = val;
210 rn = "EntryLo1";
211 break;
212 case 4:
ba9a74da 213 val = (env->CP0_Context & 0xFF800000) | (T0 & 0x007FFFF0);
6af0bf9c
FB
214 old = env->CP0_Context;
215 env->CP0_Context = val;
216 rn = "Context";
217 break;
218 case 5:
219 val = T0 & 0x01FFE000;
220 old = env->CP0_PageMask;
221 env->CP0_PageMask = val;
222 rn = "PageMask";
223 break;
224 case 6:
225 val = T0 & 0x0000000F;
226 old = env->CP0_Wired;
227 env->CP0_Wired = val;
228 rn = "Wired";
229 break;
230 case 9:
231 val = T0;
232 old = cpu_mips_get_count(env);
233 cpu_mips_store_count(env, val);
234 rn = "Count";
235 break;
236 case 10:
ba9a74da 237 val = T0 & 0xFFFFE0FF;
6af0bf9c
FB
238 old = env->CP0_EntryHi;
239 env->CP0_EntryHi = val;
4ad40f36
FB
240 /* If the ASID changes, flush qemu's TLB. */
241 if ((old & 0xFF) != (val & 0xFF))
814b9a47 242 cpu_mips_tlb_flush (env, 1);
6af0bf9c
FB
243 rn = "EntryHi";
244 break;
245 case 11:
246 val = T0;
247 old = env->CP0_Compare;
248 cpu_mips_store_compare(env, val);
249 rn = "Compare";
250 break;
251 case 12:
252 val = T0 & 0xFA78FF01;
253 if (T0 & (1 << CP0St_UM))
254 env->hflags |= MIPS_HFLAG_UM;
255 else
256 env->hflags &= ~MIPS_HFLAG_UM;
257 if (T0 & (1 << CP0St_ERL))
258 env->hflags |= MIPS_HFLAG_ERL;
259 else
260 env->hflags &= ~MIPS_HFLAG_ERL;
261 if (T0 & (1 << CP0St_EXL))
262 env->hflags |= MIPS_HFLAG_EXL;
263 else
264 env->hflags &= ~MIPS_HFLAG_EXL;
265 old = env->CP0_Status;
266 env->CP0_Status = val;
267 /* If we unmasked an asserted IRQ, raise it */
ae022501 268 mask = 0x0000FF00;
6af0bf9c
FB
269 if (loglevel & CPU_LOG_TB_IN_ASM) {
270 fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n",
271 old, val, env->CP0_Cause, old & mask, val & mask,
272 env->CP0_Cause & mask);
273 }
6af0bf9c
FB
274 if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) &&
275 !(env->hflags & MIPS_HFLAG_EXL) &&
276 !(env->hflags & MIPS_HFLAG_ERL) &&
3d9fb9fe 277 !(env->hflags & MIPS_HFLAG_DM) &&
e1d9a508 278 (env->CP0_Status & env->CP0_Cause & mask)) {
6af0bf9c
FB
279 if (logfile)
280 fprintf(logfile, "Raise pending IRQs\n");
281 env->interrupt_request |= CPU_INTERRUPT_HARD;
3d9fb9fe 282 } else if (!(val & (1 << CP0St_IE)) && (old & (1 << CP0St_IE))) {
6af0bf9c
FB
283 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
284 }
6af0bf9c
FB
285 rn = "Status";
286 break;
287 case 13:
288 val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300);
289 old = env->CP0_Cause;
290 env->CP0_Cause = val;
291#if 0
e37e863f
FB
292 {
293 int i;
294 /* Check if we ever asserted a software IRQ */
295 for (i = 0; i < 2; i++) {
296 mask = 0x100 << i;
297 if ((val & mask) & !(old & mask))
298 mips_set_irq(i);
299 }
6af0bf9c
FB
300 }
301#endif
302 rn = "Cause";
303 break;
304 case 14:
305 val = T0;
306 old = env->CP0_EPC;
307 env->CP0_EPC = val;
308 rn = "EPC";
309 break;
310 case 16:
311 switch (sel) {
312 case 0:
313#if defined(MIPS_USES_R4K_TLB)
314 val = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001);
315#else
316 val = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001);
317#endif
318 old = env->CP0_Config0;
319 env->CP0_Config0 = val;
320 rn = "Config0";
321 break;
322 default:
323 val = -1;
324 old = -1;
325 rn = "bad config selector";
326 break;
327 }
328 break;
329 case 18:
330 val = T0;
331 old = env->CP0_WatchLo;
332 env->CP0_WatchLo = val;
333 rn = "WatchLo";
334 break;
335 case 19:
336 val = T0 & 0x40FF0FF8;
337 old = env->CP0_WatchHi;
338 env->CP0_WatchHi = val;
339 rn = "WatchHi";
340 break;
341 case 23:
342 val = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120);
343 if (T0 & (1 << CP0DB_DM))
344 env->hflags |= MIPS_HFLAG_DM;
345 else
346 env->hflags &= ~MIPS_HFLAG_DM;
347 old = env->CP0_Debug;
348 env->CP0_Debug = val;
349 rn = "Debug";
350 break;
351 case 24:
352 val = T0;
353 old = env->CP0_DEPC;
354 env->CP0_DEPC = val;
355 rn = "DEPC";
356 break;
357 case 28:
358 switch (sel) {
359 case 0:
360 val = T0 & 0xFFFFFCF6;
361 old = env->CP0_TagLo;
362 env->CP0_TagLo = val;
363 rn = "TagLo";
364 break;
365 default:
366 val = -1;
367 old = -1;
368 rn = "invalid sel";
369 break;
370 }
371 break;
372 case 30:
373 val = T0;
374 old = env->CP0_ErrorEPC;
375 env->CP0_ErrorEPC = val;
376 rn = "EPC";
377 break;
378 case 31:
379 val = T0;
380 old = env->CP0_DESAVE;
381 env->CP0_DESAVE = val;
382 rn = "DESAVE";
383 break;
384 default:
385 val = -1;
386 old = -1;
387 rn = "unknown";
388 break;
389 }
390 print:
391#if defined MIPS_DEBUG_DISAS
392 if (loglevel & CPU_LOG_TB_IN_ASM) {
393 fprintf(logfile, "%08x mtc0 %s %08x => %08x (%d %d %08x)\n",
394 env->PC, rn, T0, val, reg, sel, old);
395 }
396#endif
397 return;
398}
399
6ea83fed
FB
400#ifdef MIPS_USES_FPU
401#include "softfloat.h"
402
403void fpu_handle_exception(void)
404{
405#ifdef CONFIG_SOFTFLOAT
406 int flags = get_float_exception_flags(&env->fp_status);
407 unsigned int cpuflags = 0, enable, cause = 0;
408
409 enable = GET_FP_ENABLE(env->fcr31);
410
411 /* determine current flags */
412 if (flags & float_flag_invalid) {
413 cpuflags |= FP_INVALID;
414 cause |= FP_INVALID & enable;
415 }
416 if (flags & float_flag_divbyzero) {
417 cpuflags |= FP_DIV0;
418 cause |= FP_DIV0 & enable;
419 }
420 if (flags & float_flag_overflow) {
421 cpuflags |= FP_OVERFLOW;
422 cause |= FP_OVERFLOW & enable;
423 }
424 if (flags & float_flag_underflow) {
425 cpuflags |= FP_UNDERFLOW;
426 cause |= FP_UNDERFLOW & enable;
427 }
428 if (flags & float_flag_inexact) {
429 cpuflags |= FP_INEXACT;
430 cause |= FP_INEXACT & enable;
431 }
432 SET_FP_FLAGS(env->fcr31, cpuflags);
433 SET_FP_CAUSE(env->fcr31, cause);
434#else
435 SET_FP_FLAGS(env->fcr31, 0);
436 SET_FP_CAUSE(env->fcr31, 0);
437#endif
438}
439#endif /* MIPS_USES_FPU */
440
6af0bf9c
FB
441/* TLB management */
442#if defined(MIPS_USES_R4K_TLB)
814b9a47
TS
443void cpu_mips_tlb_flush (CPUState *env, int flush_global)
444{
445 /* Flush qemu's TLB and discard all shadowed entries. */
446 tlb_flush (env, flush_global);
447 env->tlb_in_use = MIPS_TLB_NB;
448}
449
450static void invalidate_tlb (int idx, int use_extra)
6af0bf9c
FB
451{
452 tlb_t *tlb;
98c1b82b 453 target_ulong addr;
483dcf53
PB
454 uint8_t ASID;
455
456 ASID = env->CP0_EntryHi & 0xFF;
6af0bf9c
FB
457
458 tlb = &env->tlb[idx];
483dcf53
PB
459 /* The qemu TLB is flushed then the ASID changes, so no need to
460 flush these entries again. */
461 if (tlb->G == 0 && tlb->ASID != ASID) {
462 return;
463 }
464
814b9a47
TS
465 if (use_extra && env->tlb_in_use < MIPS_TLB_MAX) {
466 /* For tlbwr, we can shadow the discarded entry into
467 a new (fake) TLB entry, as long as the guest can not
468 tell that it's there. */
469 env->tlb[env->tlb_in_use] = *tlb;
470 env->tlb_in_use++;
471 return;
472 }
473
98c1b82b
PB
474 if (tlb->V0) {
475 tb_invalidate_page_range(tlb->PFN[0], tlb->end - tlb->VPN);
4ad40f36
FB
476 addr = tlb->VPN;
477 while (addr < tlb->end) {
478 tlb_flush_page (env, addr);
479 addr += TARGET_PAGE_SIZE;
480 }
6af0bf9c 481 }
98c1b82b
PB
482 if (tlb->V1) {
483 tb_invalidate_page_range(tlb->PFN[1], tlb->end2 - tlb->end);
4ad40f36
FB
484 addr = tlb->end;
485 while (addr < tlb->end2) {
486 tlb_flush_page (env, addr);
487 addr += TARGET_PAGE_SIZE;
488 }
6af0bf9c
FB
489 }
490}
491
814b9a47
TS
492static void mips_tlb_flush_extra (CPUState *env, int first)
493{
494 /* Discard entries from env->tlb[first] onwards. */
495 while (env->tlb_in_use > first) {
496 invalidate_tlb(--env->tlb_in_use, 0);
497 }
498}
499
98c1b82b 500static void fill_tlb (int idx)
6af0bf9c
FB
501{
502 tlb_t *tlb;
503 int size;
504
505 /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
506 tlb = &env->tlb[idx];
507 tlb->VPN = env->CP0_EntryHi & 0xFFFFE000;
98c1b82b 508 tlb->ASID = env->CP0_EntryHi & 0xFF;
6af0bf9c
FB
509 size = env->CP0_PageMask >> 13;
510 size = 4 * (size + 1);
511 tlb->end = tlb->VPN + (1 << (8 + size));
4ad40f36 512 tlb->end2 = tlb->end + (1 << (8 + size));
6af0bf9c 513 tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
98c1b82b
PB
514 tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
515 tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
516 tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
6af0bf9c 517 tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
98c1b82b
PB
518 tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
519 tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
520 tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
6af0bf9c
FB
521 tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
522}
523
524void do_tlbwi (void)
525{
814b9a47
TS
526 /* Discard cached TLB entries. We could avoid doing this if the
527 tlbwi is just upgrading access permissions on the current entry;
528 that might be a further win. */
529 mips_tlb_flush_extra (env, MIPS_TLB_NB);
530
7a962d30
FB
531 /* Wildly undefined effects for CP0_index containing a too high value and
532 MIPS_TLB_NB not being a power of two. But so does real silicon. */
814b9a47 533 invalidate_tlb(env->CP0_index & (MIPS_TLB_NB - 1), 0);
98c1b82b 534 fill_tlb(env->CP0_index & (MIPS_TLB_NB - 1));
6af0bf9c
FB
535}
536
537void do_tlbwr (void)
538{
539 int r = cpu_mips_get_random(env);
540
814b9a47 541 invalidate_tlb(r, 1);
98c1b82b 542 fill_tlb(r);
6af0bf9c
FB
543}
544
545void do_tlbp (void)
546{
547 tlb_t *tlb;
548 target_ulong tag;
549 uint8_t ASID;
550 int i;
551
3d9fb9fe
FB
552 tag = env->CP0_EntryHi & 0xFFFFE000;
553 ASID = env->CP0_EntryHi & 0xFF;
554 for (i = 0; i < MIPS_TLB_NB; i++) {
6af0bf9c
FB
555 tlb = &env->tlb[i];
556 /* Check ASID, virtual page number & size */
557 if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) {
558 /* TLB match */
559 env->CP0_index = i;
560 break;
561 }
562 }
7a962d30 563 if (i == MIPS_TLB_NB) {
814b9a47
TS
564 /* No match. Discard any shadow entries, if any of them match. */
565 for (i = MIPS_TLB_NB; i < env->tlb_in_use; i++) {
566 tlb = &env->tlb[i];
567
568 /* Check ASID, virtual page number & size */
569 if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) {
570 mips_tlb_flush_extra (env, i);
571 break;
572 }
573 }
574
6af0bf9c
FB
575 env->CP0_index |= 0x80000000;
576 }
577}
578
579void do_tlbr (void)
580{
581 tlb_t *tlb;
09c56b84 582 uint8_t ASID;
6af0bf9c
FB
583 int size;
584
09c56b84 585 ASID = env->CP0_EntryHi & 0xFF;
7a962d30 586 tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)];
4ad40f36
FB
587
588 /* If this will change the current ASID, flush qemu's TLB. */
814b9a47
TS
589 if (ASID != tlb->ASID)
590 cpu_mips_tlb_flush (env, 1);
591
592 mips_tlb_flush_extra(env, MIPS_TLB_NB);
4ad40f36 593
6af0bf9c
FB
594 env->CP0_EntryHi = tlb->VPN | tlb->ASID;
595 size = (tlb->end - tlb->VPN) >> 12;
596 env->CP0_PageMask = (size - 1) << 13;
98c1b82b
PB
597 env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2)
598 | (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
599 env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2)
600 | (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
6af0bf9c
FB
601}
602#endif
603
048f6b4d
FB
604#endif /* !CONFIG_USER_ONLY */
605
6af0bf9c
FB
606void op_dump_ldst (const unsigned char *func)
607{
608 if (loglevel)
609 fprintf(logfile, "%s => %08x %08x\n", __func__, T0, T1);
610}
611
612void dump_sc (void)
613{
614 if (loglevel) {
615 fprintf(logfile, "%s %08x at %08x (%08x)\n", __func__,
616 T1, T0, env->CP0_LLAddr);
617 }
618}
619
620void debug_eret (void)
621{
622 if (loglevel) {
623 fprintf(logfile, "ERET: pc %08x EPC %08x ErrorEPC %08x (%d)\n",
624 env->PC, env->CP0_EPC, env->CP0_ErrorEPC,
625 env->hflags & MIPS_HFLAG_ERL ? 1 : 0);
626 }
627}
628
6af0bf9c
FB
629void do_pmon (int function)
630{
631 function /= 2;
632 switch (function) {
633 case 2: /* TODO: char inbyte(int waitflag); */
634 if (env->gpr[4] == 0)
635 env->gpr[2] = -1;
636 /* Fall through */
637 case 11: /* TODO: char inbyte (void); */
638 env->gpr[2] = -1;
639 break;
640 case 3:
641 case 12:
642 printf("%c", env->gpr[4] & 0xFF);
643 break;
644 case 17:
645 break;
646 case 158:
647 {
648 unsigned char *fmt = (void *)env->gpr[4];
649 printf("%s", fmt);
650 }
651 break;
652 }
653}
e37e863f
FB
654
655#if !defined(CONFIG_USER_ONLY)
656
4ad40f36
FB
657static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
658
e37e863f 659#define MMUSUFFIX _mmu
4ad40f36 660#define ALIGNED_ONLY
e37e863f
FB
661
662#define SHIFT 0
663#include "softmmu_template.h"
664
665#define SHIFT 1
666#include "softmmu_template.h"
667
668#define SHIFT 2
669#include "softmmu_template.h"
670
671#define SHIFT 3
672#include "softmmu_template.h"
673
4ad40f36
FB
674static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
675{
676 env->CP0_BadVAddr = addr;
677 do_restore_state (retaddr);
678 do_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
679}
680
e37e863f
FB
681void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
682{
683 TranslationBlock *tb;
684 CPUState *saved_env;
685 unsigned long pc;
686 int ret;
687
688 /* XXX: hack to restore env in all cases, even if not called from
689 generated code */
690 saved_env = env;
691 env = cpu_single_env;
692 ret = cpu_mips_handle_mmu_fault(env, addr, is_write, is_user, 1);
693 if (ret) {
694 if (retaddr) {
695 /* now we have a real cpu fault */
696 pc = (unsigned long)retaddr;
697 tb = tb_find_pc(pc);
698 if (tb) {
699 /* the PC is inside the translated code. It means that we have
700 a virtual CPU fault */
701 cpu_restore_state(tb, env, pc, NULL);
702 }
703 }
704 do_raise_exception_err(env->exception_index, env->error_code);
705 }
706 env = saved_env;
707}
708
709#endif