m68k/ColdFire system emulation.
[qemu] / target-m68k / op_helper.c
1 /*
2  *  M68K helper routines
3  * 
4  *  Copyright (c) 2007 CodeSourcery
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 #if defined(CONFIG_USER_ONLY)
23
24 void do_interrupt(int is_hw)
25 {
26     env->exception_index = -1;
27 }
28
29 #else
30
31 #define MMUSUFFIX _mmu
32 #define GETPC() (__builtin_return_address(0))
33
34 #define SHIFT 0
35 #include "softmmu_template.h"
36
37 #define SHIFT 1
38 #include "softmmu_template.h"
39
40 #define SHIFT 2
41 #include "softmmu_template.h"
42
43 #define SHIFT 3
44 #include "softmmu_template.h"
45
46 /* Try to fill the TLB and return an exception if error. If retaddr is
47    NULL, it means that the function was called in C code (i.e. not
48    from generated code or from helper.c) */
49 /* XXX: fix it to restore all registers */
50 void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
51 {
52     TranslationBlock *tb;
53     CPUState *saved_env;
54     target_phys_addr_t pc;
55     int ret;
56
57     /* XXX: hack to restore env in all cases, even if not called from
58        generated code */
59     saved_env = env;
60     env = cpu_single_env;
61     ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, is_user, 1);
62     if (__builtin_expect(ret, 0)) {
63         if (retaddr) {
64             /* now we have a real cpu fault */
65             pc = (target_phys_addr_t)retaddr;
66             tb = tb_find_pc(pc);
67             if (tb) {
68                 /* the PC is inside the translated code. It means that we have
69                    a virtual CPU fault */
70                 cpu_restore_state(tb, env, pc, NULL);
71             }
72         }
73         cpu_loop_exit();
74     }
75     env = saved_env;
76 }
77
78 static void do_rte(void)
79 {
80     uint32_t sp;
81     uint32_t fmt;
82
83     sp = env->aregs[7];
84     fmt = ldl_kernel(sp);
85     env->pc = ldl_kernel(sp + 4);
86     sp |= (fmt >> 28) & 3;
87     env->sr = fmt & 0xffff;
88     env->aregs[7] = sp + 8;
89 }
90
91 void do_interrupt(int is_hw)
92 {
93     uint32_t sp;
94     uint32_t fmt;
95     uint32_t retaddr;
96     uint32_t vector;
97
98     fmt = 0;
99     retaddr = env->pc;
100
101     if (!is_hw) {
102         switch (env->exception_index) {
103         case EXCP_RTE:
104             /* Return from an exception.  */
105             do_rte();
106             return;
107         }
108         if (env->exception_index >= EXCP_TRAP0
109             && env->exception_index <= EXCP_TRAP15) {
110             /* Move the PC after the trap instruction.  */
111             retaddr += 2;
112         }
113     }
114
115     /* TODO: Implement USP.  */
116     sp = env->aregs[7];
117
118     vector = env->exception_index << 2;
119
120     fmt |= 0x40000000;
121     fmt |= (sp & 3) << 28;
122     fmt |= vector << 16;
123     fmt |= env->sr;
124
125     /* ??? This could cause MMU faults.  */
126     sp &= ~3;
127     sp -= 4;
128     stl_kernel(sp, retaddr);
129     sp -= 4;
130     stl_kernel(sp, fmt);
131     env->aregs[7] = sp;
132     env->sr |= SR_S;
133     if (is_hw) {
134         env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT);
135     }
136     /* Jump to vector.  */
137     env->pc = ldl_kernel(env->vbr + vector);
138 }
139
140 #endif