80ec89040f15626e76b6bc86c995f69a2ee27df1
[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 extern int semihosting_enabled;
32
33 #define MMUSUFFIX _mmu
34 #ifdef __s390__
35 # define GETPC() ((void*)((unsigned long)__builtin_return_address(0) & 0x7fffffffUL))
36 #else
37 # define GETPC() (__builtin_return_address(0))
38 #endif
39
40 #define SHIFT 0
41 #include "softmmu_template.h"
42
43 #define SHIFT 1
44 #include "softmmu_template.h"
45
46 #define SHIFT 2
47 #include "softmmu_template.h"
48
49 #define SHIFT 3
50 #include "softmmu_template.h"
51
52 /* Try to fill the TLB and return an exception if error. If retaddr is
53    NULL, it means that the function was called in C code (i.e. not
54    from generated code or from helper.c) */
55 /* XXX: fix it to restore all registers */
56 void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr)
57 {
58     TranslationBlock *tb;
59     CPUState *saved_env;
60     target_phys_addr_t pc;
61     int ret;
62
63     /* XXX: hack to restore env in all cases, even if not called from
64        generated code */
65     saved_env = env;
66     env = cpu_single_env;
67     ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
68     if (__builtin_expect(ret, 0)) {
69         if (retaddr) {
70             /* now we have a real cpu fault */
71             pc = (target_phys_addr_t)retaddr;
72             tb = tb_find_pc(pc);
73             if (tb) {
74                 /* the PC is inside the translated code. It means that we have
75                    a virtual CPU fault */
76                 cpu_restore_state(tb, env, pc, NULL);
77             }
78         }
79         cpu_loop_exit();
80     }
81     env = saved_env;
82 }
83
84 static void do_rte(void)
85 {
86     uint32_t sp;
87     uint32_t fmt;
88
89     sp = env->aregs[7];
90     fmt = ldl_kernel(sp);
91     env->pc = ldl_kernel(sp + 4);
92     sp |= (fmt >> 28) & 3;
93     env->sr = fmt & 0xffff;
94     m68k_switch_sp(env);
95     env->aregs[7] = sp + 8;
96 }
97
98 void do_interrupt(int is_hw)
99 {
100     uint32_t sp;
101     uint32_t fmt;
102     uint32_t retaddr;
103     uint32_t vector;
104
105     fmt = 0;
106     retaddr = env->pc;
107
108     if (!is_hw) {
109         switch (env->exception_index) {
110         case EXCP_RTE:
111             /* Return from an exception.  */
112             do_rte();
113             return;
114         case EXCP_HALT_INSN:
115             if (semihosting_enabled
116                     && (env->sr & SR_S) != 0
117                     && (env->pc & 3) == 0
118                     && lduw_code(env->pc - 4) == 0x4e71
119                     && ldl_code(env->pc) == 0x4e7bf000) {
120                 env->pc += 4;
121                 do_m68k_semihosting(env, env->dregs[0]);
122                 return;
123             }
124             env->halted = 1;
125             env->exception_index = EXCP_HLT;
126             cpu_loop_exit();
127             return;
128         }
129         if (env->exception_index >= EXCP_TRAP0
130             && env->exception_index <= EXCP_TRAP15) {
131             /* Move the PC after the trap instruction.  */
132             retaddr += 2;
133         }
134     }
135
136     vector = env->exception_index << 2;
137
138     sp = env->aregs[7];
139
140     fmt |= 0x40000000;
141     fmt |= (sp & 3) << 28;
142     fmt |= vector << 16;
143     fmt |= env->sr;
144
145     env->sr |= SR_S;
146     if (is_hw) {
147         env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT);
148         env->sr &= ~SR_M;
149     }
150     m68k_switch_sp(env);
151
152     /* ??? This could cause MMU faults.  */
153     sp &= ~3;
154     sp -= 4;
155     stl_kernel(sp, retaddr);
156     sp -= 4;
157     stl_kernel(sp, fmt);
158     env->aregs[7] = sp;
159     /* Jump to vector.  */
160     env->pc = ldl_kernel(env->vbr + vector);
161 }
162
163 #endif