]> git.proxmox.com Git - qemu.git/blame - target-mips/op_helper.c
-no-fd-bootchk option (Lonnie Mendez)
[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
FB
133#if defined(CONFIG_USER_ONLY)
134void do_mfc0 (int reg, int sel)
135{
136 cpu_abort(env, "mfc0 reg=%d sel=%d\n", reg, sel);
137}
138void do_mtc0 (int reg, int sel)
139{
140 cpu_abort(env, "mtc0 reg=%d sel=%d\n", reg, sel);
141}
142
143void do_tlbwi (void)
144{
145 cpu_abort(env, "tlbwi\n");
146}
147
148void do_tlbwr (void)
149{
150 cpu_abort(env, "tlbwr\n");
151}
152
153void do_tlbp (void)
154{
155 cpu_abort(env, "tlbp\n");
156}
157
158void do_tlbr (void)
159{
160 cpu_abort(env, "tlbr\n");
161}
162#else
163
6af0bf9c 164/* CP0 helpers */
6af0bf9c
FB
165void 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)
90b37806 221 T0 |= (1 << CP0St_UM);
6af0bf9c 222 if (env->hflags & MIPS_HFLAG_ERL)
90b37806 223 T0 |= (1 << CP0St_ERL);
6af0bf9c 224 if (env->hflags & MIPS_HFLAG_EXL)
90b37806 225 T0 |= (1 << CP0St_EXL);
6af0bf9c
FB
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
6af0bf9c
FB
314void do_mtc0 (int reg, int sel)
315{
316 const unsigned char *rn;
317 uint32_t val, old, mask;
6af0bf9c
FB
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:
3d9fb9fe 333 val = T0 & 0x3FFFFFFF;
6af0bf9c
FB
334 old = env->CP0_EntryLo0;
335 env->CP0_EntryLo0 = val;
336 rn = "EntryLo0";
337 break;
338 case 3:
3d9fb9fe 339 val = T0 & 0x3FFFFFFF;
6af0bf9c
FB
340 old = env->CP0_EntryLo1;
341 env->CP0_EntryLo1 = val;
342 rn = "EntryLo1";
343 break;
344 case 4:
ba9a74da 345 val = (env->CP0_Context & 0xFF800000) | (T0 & 0x007FFFF0);
6af0bf9c
FB
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:
ba9a74da 369 val = T0 & 0xFFFFE0FF;
6af0bf9c
FB
370 old = env->CP0_EntryHi;
371 env->CP0_EntryHi = val;
4ad40f36
FB
372 /* If the ASID changes, flush qemu's TLB. */
373 if ((old & 0xFF) != (val & 0xFF))
374 tlb_flush (env, 1);
6af0bf9c
FB
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 */
ae022501 400 mask = 0x0000FF00;
6af0bf9c
FB
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 }
6af0bf9c
FB
406 if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) &&
407 !(env->hflags & MIPS_HFLAG_EXL) &&
408 !(env->hflags & MIPS_HFLAG_ERL) &&
3d9fb9fe 409 !(env->hflags & MIPS_HFLAG_DM) &&
e1d9a508 410 (env->CP0_Status & env->CP0_Cause & mask)) {
6af0bf9c
FB
411 if (logfile)
412 fprintf(logfile, "Raise pending IRQs\n");
413 env->interrupt_request |= CPU_INTERRUPT_HARD;
3d9fb9fe 414 } else if (!(val & (1 << CP0St_IE)) && (old & (1 << CP0St_IE))) {
6af0bf9c
FB
415 env->interrupt_request &= ~CPU_INTERRUPT_HARD;
416 }
6af0bf9c
FB
417 rn = "Status";
418 break;
419 case 13:
420 val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300);
421 old = env->CP0_Cause;
422 env->CP0_Cause = val;
423#if 0
e37e863f
FB
424 {
425 int i;
426 /* Check if we ever asserted a software IRQ */
427 for (i = 0; i < 2; i++) {
428 mask = 0x100 << i;
429 if ((val & mask) & !(old & mask))
430 mips_set_irq(i);
431 }
6af0bf9c
FB
432 }
433#endif
434 rn = "Cause";
435 break;
436 case 14:
437 val = T0;
438 old = env->CP0_EPC;
439 env->CP0_EPC = val;
440 rn = "EPC";
441 break;
442 case 16:
443 switch (sel) {
444 case 0:
445#if defined(MIPS_USES_R4K_TLB)
446 val = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001);
447#else
448 val = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001);
449#endif
450 old = env->CP0_Config0;
451 env->CP0_Config0 = val;
452 rn = "Config0";
453 break;
454 default:
455 val = -1;
456 old = -1;
457 rn = "bad config selector";
458 break;
459 }
460 break;
461 case 18:
462 val = T0;
463 old = env->CP0_WatchLo;
464 env->CP0_WatchLo = val;
465 rn = "WatchLo";
466 break;
467 case 19:
468 val = T0 & 0x40FF0FF8;
469 old = env->CP0_WatchHi;
470 env->CP0_WatchHi = val;
471 rn = "WatchHi";
472 break;
473 case 23:
474 val = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120);
475 if (T0 & (1 << CP0DB_DM))
476 env->hflags |= MIPS_HFLAG_DM;
477 else
478 env->hflags &= ~MIPS_HFLAG_DM;
479 old = env->CP0_Debug;
480 env->CP0_Debug = val;
481 rn = "Debug";
482 break;
483 case 24:
484 val = T0;
485 old = env->CP0_DEPC;
486 env->CP0_DEPC = val;
487 rn = "DEPC";
488 break;
489 case 28:
490 switch (sel) {
491 case 0:
492 val = T0 & 0xFFFFFCF6;
493 old = env->CP0_TagLo;
494 env->CP0_TagLo = val;
495 rn = "TagLo";
496 break;
497 default:
498 val = -1;
499 old = -1;
500 rn = "invalid sel";
501 break;
502 }
503 break;
504 case 30:
505 val = T0;
506 old = env->CP0_ErrorEPC;
507 env->CP0_ErrorEPC = val;
508 rn = "EPC";
509 break;
510 case 31:
511 val = T0;
512 old = env->CP0_DESAVE;
513 env->CP0_DESAVE = val;
514 rn = "DESAVE";
515 break;
516 default:
517 val = -1;
518 old = -1;
519 rn = "unknown";
520 break;
521 }
522 print:
523#if defined MIPS_DEBUG_DISAS
524 if (loglevel & CPU_LOG_TB_IN_ASM) {
525 fprintf(logfile, "%08x mtc0 %s %08x => %08x (%d %d %08x)\n",
526 env->PC, rn, T0, val, reg, sel, old);
527 }
528#endif
529 return;
530}
531
6ea83fed
FB
532#ifdef MIPS_USES_FPU
533#include "softfloat.h"
534
535void fpu_handle_exception(void)
536{
537#ifdef CONFIG_SOFTFLOAT
538 int flags = get_float_exception_flags(&env->fp_status);
539 unsigned int cpuflags = 0, enable, cause = 0;
540
541 enable = GET_FP_ENABLE(env->fcr31);
542
543 /* determine current flags */
544 if (flags & float_flag_invalid) {
545 cpuflags |= FP_INVALID;
546 cause |= FP_INVALID & enable;
547 }
548 if (flags & float_flag_divbyzero) {
549 cpuflags |= FP_DIV0;
550 cause |= FP_DIV0 & enable;
551 }
552 if (flags & float_flag_overflow) {
553 cpuflags |= FP_OVERFLOW;
554 cause |= FP_OVERFLOW & enable;
555 }
556 if (flags & float_flag_underflow) {
557 cpuflags |= FP_UNDERFLOW;
558 cause |= FP_UNDERFLOW & enable;
559 }
560 if (flags & float_flag_inexact) {
561 cpuflags |= FP_INEXACT;
562 cause |= FP_INEXACT & enable;
563 }
564 SET_FP_FLAGS(env->fcr31, cpuflags);
565 SET_FP_CAUSE(env->fcr31, cause);
566#else
567 SET_FP_FLAGS(env->fcr31, 0);
568 SET_FP_CAUSE(env->fcr31, 0);
569#endif
570}
571#endif /* MIPS_USES_FPU */
572
6af0bf9c
FB
573/* TLB management */
574#if defined(MIPS_USES_R4K_TLB)
98c1b82b 575static void invalidate_tlb (int idx)
6af0bf9c
FB
576{
577 tlb_t *tlb;
98c1b82b 578 target_ulong addr;
6af0bf9c
FB
579
580 tlb = &env->tlb[idx];
98c1b82b
PB
581 if (tlb->V0) {
582 tb_invalidate_page_range(tlb->PFN[0], tlb->end - tlb->VPN);
4ad40f36
FB
583 addr = tlb->VPN;
584 while (addr < tlb->end) {
585 tlb_flush_page (env, addr);
586 addr += TARGET_PAGE_SIZE;
587 }
6af0bf9c 588 }
98c1b82b
PB
589 if (tlb->V1) {
590 tb_invalidate_page_range(tlb->PFN[1], tlb->end2 - tlb->end);
4ad40f36
FB
591 addr = tlb->end;
592 while (addr < tlb->end2) {
593 tlb_flush_page (env, addr);
594 addr += TARGET_PAGE_SIZE;
595 }
6af0bf9c
FB
596 }
597}
598
98c1b82b 599static void fill_tlb (int idx)
6af0bf9c
FB
600{
601 tlb_t *tlb;
602 int size;
603
604 /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
605 tlb = &env->tlb[idx];
606 tlb->VPN = env->CP0_EntryHi & 0xFFFFE000;
98c1b82b 607 tlb->ASID = env->CP0_EntryHi & 0xFF;
6af0bf9c
FB
608 size = env->CP0_PageMask >> 13;
609 size = 4 * (size + 1);
610 tlb->end = tlb->VPN + (1 << (8 + size));
4ad40f36 611 tlb->end2 = tlb->end + (1 << (8 + size));
6af0bf9c 612 tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
98c1b82b
PB
613 tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
614 tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
615 tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
6af0bf9c 616 tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
98c1b82b
PB
617 tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
618 tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
619 tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
6af0bf9c
FB
620 tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
621}
622
623void do_tlbwi (void)
624{
7a962d30
FB
625 /* Wildly undefined effects for CP0_index containing a too high value and
626 MIPS_TLB_NB not being a power of two. But so does real silicon. */
98c1b82b
PB
627 invalidate_tlb(env->CP0_index & (MIPS_TLB_NB - 1));
628 fill_tlb(env->CP0_index & (MIPS_TLB_NB - 1));
6af0bf9c
FB
629}
630
631void do_tlbwr (void)
632{
633 int r = cpu_mips_get_random(env);
634
98c1b82b
PB
635 invalidate_tlb(r);
636 fill_tlb(r);
6af0bf9c
FB
637}
638
639void do_tlbp (void)
640{
641 tlb_t *tlb;
642 target_ulong tag;
643 uint8_t ASID;
644 int i;
645
3d9fb9fe
FB
646 tag = env->CP0_EntryHi & 0xFFFFE000;
647 ASID = env->CP0_EntryHi & 0xFF;
648 for (i = 0; i < MIPS_TLB_NB; i++) {
6af0bf9c
FB
649 tlb = &env->tlb[i];
650 /* Check ASID, virtual page number & size */
651 if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) {
652 /* TLB match */
653 env->CP0_index = i;
654 break;
655 }
656 }
7a962d30 657 if (i == MIPS_TLB_NB) {
6af0bf9c
FB
658 env->CP0_index |= 0x80000000;
659 }
660}
661
662void do_tlbr (void)
663{
664 tlb_t *tlb;
09c56b84 665 uint8_t ASID;
6af0bf9c
FB
666 int size;
667
09c56b84 668 ASID = env->CP0_EntryHi & 0xFF;
7a962d30 669 tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)];
4ad40f36
FB
670
671 /* If this will change the current ASID, flush qemu's TLB. */
09c56b84 672 if (ASID != tlb->ASID && tlb->G != 1)
4ad40f36
FB
673 tlb_flush (env, 1);
674
6af0bf9c
FB
675 env->CP0_EntryHi = tlb->VPN | tlb->ASID;
676 size = (tlb->end - tlb->VPN) >> 12;
677 env->CP0_PageMask = (size - 1) << 13;
98c1b82b
PB
678 env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2)
679 | (tlb->C0 << 3) | (tlb->PFN[0] >> 6);
680 env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2)
681 | (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
6af0bf9c
FB
682}
683#endif
684
048f6b4d
FB
685#endif /* !CONFIG_USER_ONLY */
686
6af0bf9c
FB
687void op_dump_ldst (const unsigned char *func)
688{
689 if (loglevel)
690 fprintf(logfile, "%s => %08x %08x\n", __func__, T0, T1);
691}
692
693void dump_sc (void)
694{
695 if (loglevel) {
696 fprintf(logfile, "%s %08x at %08x (%08x)\n", __func__,
697 T1, T0, env->CP0_LLAddr);
698 }
699}
700
701void debug_eret (void)
702{
703 if (loglevel) {
704 fprintf(logfile, "ERET: pc %08x EPC %08x ErrorEPC %08x (%d)\n",
705 env->PC, env->CP0_EPC, env->CP0_ErrorEPC,
706 env->hflags & MIPS_HFLAG_ERL ? 1 : 0);
707 }
708}
709
6af0bf9c
FB
710void do_pmon (int function)
711{
712 function /= 2;
713 switch (function) {
714 case 2: /* TODO: char inbyte(int waitflag); */
715 if (env->gpr[4] == 0)
716 env->gpr[2] = -1;
717 /* Fall through */
718 case 11: /* TODO: char inbyte (void); */
719 env->gpr[2] = -1;
720 break;
721 case 3:
722 case 12:
723 printf("%c", env->gpr[4] & 0xFF);
724 break;
725 case 17:
726 break;
727 case 158:
728 {
729 unsigned char *fmt = (void *)env->gpr[4];
730 printf("%s", fmt);
731 }
732 break;
733 }
734}
e37e863f
FB
735
736#if !defined(CONFIG_USER_ONLY)
737
4ad40f36
FB
738static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
739
e37e863f 740#define MMUSUFFIX _mmu
4ad40f36 741#define ALIGNED_ONLY
e37e863f
FB
742
743#define SHIFT 0
744#include "softmmu_template.h"
745
746#define SHIFT 1
747#include "softmmu_template.h"
748
749#define SHIFT 2
750#include "softmmu_template.h"
751
752#define SHIFT 3
753#include "softmmu_template.h"
754
4ad40f36
FB
755static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
756{
757 env->CP0_BadVAddr = addr;
758 do_restore_state (retaddr);
759 do_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
760}
761
e37e863f
FB
762void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
763{
764 TranslationBlock *tb;
765 CPUState *saved_env;
766 unsigned long pc;
767 int ret;
768
769 /* XXX: hack to restore env in all cases, even if not called from
770 generated code */
771 saved_env = env;
772 env = cpu_single_env;
773 ret = cpu_mips_handle_mmu_fault(env, addr, is_write, is_user, 1);
774 if (ret) {
775 if (retaddr) {
776 /* now we have a real cpu fault */
777 pc = (unsigned long)retaddr;
778 tb = tb_find_pc(pc);
779 if (tb) {
780 /* the PC is inside the translated code. It means that we have
781 a virtual CPU fault */
782 cpu_restore_state(tb, env, pc, NULL);
783 }
784 }
785 do_raise_exception_err(env->exception_index, env->error_code);
786 }
787 env = saved_env;
788}
789
790#endif