]> Git Repo - qemu.git/blob - target-m68k/op_helper.c
Merge remote-tracking branch 'mst/tags/for_anthony' into staging
[qemu.git] / 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, see <http://www.gnu.org/licenses/>.
18  */
19 #include "cpu.h"
20 #include "dyngen-exec.h"
21 #include "helpers.h"
22
23 #if defined(CONFIG_USER_ONLY)
24
25 void do_interrupt(CPUM68KState *env1)
26 {
27     env1->exception_index = -1;
28 }
29
30 void do_interrupt_m68k_hardirq(CPUM68KState *env1)
31 {
32 }
33
34 #else
35
36 extern int semihosting_enabled;
37
38 #include "softmmu_exec.h"
39
40 #define MMUSUFFIX _mmu
41
42 #define SHIFT 0
43 #include "softmmu_template.h"
44
45 #define SHIFT 1
46 #include "softmmu_template.h"
47
48 #define SHIFT 2
49 #include "softmmu_template.h"
50
51 #define SHIFT 3
52 #include "softmmu_template.h"
53
54 /* Try to fill the TLB and return an exception if error. If retaddr is
55    NULL, it means that the function was called in C code (i.e. not
56    from generated code or from helper.c) */
57 /* XXX: fix it to restore all registers */
58 void tlb_fill(CPUM68KState *env1, target_ulong addr, int is_write, int mmu_idx,
59               uintptr_t retaddr)
60 {
61     TranslationBlock *tb;
62     CPUM68KState *saved_env;
63     int ret;
64
65     saved_env = env;
66     env = env1;
67     ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, mmu_idx);
68     if (unlikely(ret)) {
69         if (retaddr) {
70             /* now we have a real cpu fault */
71             tb = tb_find_pc(retaddr);
72             if (tb) {
73                 /* the PC is inside the translated code. It means that we have
74                    a virtual CPU fault */
75                 cpu_restore_state(tb, env, retaddr);
76             }
77         }
78         cpu_loop_exit(env);
79     }
80     env = saved_env;
81 }
82
83 static void do_rte(void)
84 {
85     uint32_t sp;
86     uint32_t fmt;
87
88     sp = env->aregs[7];
89     fmt = ldl_kernel(sp);
90     env->pc = ldl_kernel(sp + 4);
91     sp |= (fmt >> 28) & 3;
92     env->sr = fmt & 0xffff;
93     m68k_switch_sp(env);
94     env->aregs[7] = sp + 8;
95 }
96
97 static void do_interrupt_all(int is_hw)
98 {
99     uint32_t sp;
100     uint32_t fmt;
101     uint32_t retaddr;
102     uint32_t vector;
103
104     fmt = 0;
105     retaddr = env->pc;
106
107     if (!is_hw) {
108         switch (env->exception_index) {
109         case EXCP_RTE:
110             /* Return from an exception.  */
111             do_rte();
112             return;
113         case EXCP_HALT_INSN:
114             if (semihosting_enabled
115                     && (env->sr & SR_S) != 0
116                     && (env->pc & 3) == 0
117                     && lduw_code(env->pc - 4) == 0x4e71
118                     && ldl_code(env->pc) == 0x4e7bf000) {
119                 env->pc += 4;
120                 do_m68k_semihosting(env, env->dregs[0]);
121                 return;
122             }
123             env->halted = 1;
124             env->exception_index = EXCP_HLT;
125             cpu_loop_exit(env);
126             return;
127         }
128         if (env->exception_index >= EXCP_TRAP0
129             && env->exception_index <= EXCP_TRAP15) {
130             /* Move the PC after the trap instruction.  */
131             retaddr += 2;
132         }
133     }
134
135     vector = env->exception_index << 2;
136
137     sp = env->aregs[7];
138
139     fmt |= 0x40000000;
140     fmt |= (sp & 3) << 28;
141     fmt |= vector << 16;
142     fmt |= env->sr;
143
144     env->sr |= SR_S;
145     if (is_hw) {
146         env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT);
147         env->sr &= ~SR_M;
148     }
149     m68k_switch_sp(env);
150
151     /* ??? This could cause MMU faults.  */
152     sp &= ~3;
153     sp -= 4;
154     stl_kernel(sp, retaddr);
155     sp -= 4;
156     stl_kernel(sp, fmt);
157     env->aregs[7] = sp;
158     /* Jump to vector.  */
159     env->pc = ldl_kernel(env->vbr + vector);
160 }
161
162 void do_interrupt(CPUM68KState *env1)
163 {
164     CPUM68KState *saved_env;
165
166     saved_env = env;
167     env = env1;
168     do_interrupt_all(0);
169     env = saved_env;
170 }
171
172 void do_interrupt_m68k_hardirq(CPUM68KState *env1)
173 {
174     CPUM68KState *saved_env;
175
176     saved_env = env;
177     env = env1;
178     do_interrupt_all(1);
179     env = saved_env;
180 }
181 #endif
182
183 static void raise_exception(int tt)
184 {
185     env->exception_index = tt;
186     cpu_loop_exit(env);
187 }
188
189 void HELPER(raise_exception)(uint32_t tt)
190 {
191     raise_exception(tt);
192 }
193
194 void HELPER(divu)(CPUM68KState *env, uint32_t word)
195 {
196     uint32_t num;
197     uint32_t den;
198     uint32_t quot;
199     uint32_t rem;
200     uint32_t flags;
201
202     num = env->div1;
203     den = env->div2;
204     /* ??? This needs to make sure the throwing location is accurate.  */
205     if (den == 0)
206         raise_exception(EXCP_DIV0);
207     quot = num / den;
208     rem = num % den;
209     flags = 0;
210     /* Avoid using a PARAM1 of zero.  This breaks dyngen because it uses
211        the address of a symbol, and gcc knows symbols can't have address
212        zero.  */
213     if (word && quot > 0xffff)
214         flags |= CCF_V;
215     if (quot == 0)
216         flags |= CCF_Z;
217     else if ((int32_t)quot < 0)
218         flags |= CCF_N;
219     env->div1 = quot;
220     env->div2 = rem;
221     env->cc_dest = flags;
222 }
223
224 void HELPER(divs)(CPUM68KState *env, uint32_t word)
225 {
226     int32_t num;
227     int32_t den;
228     int32_t quot;
229     int32_t rem;
230     int32_t flags;
231
232     num = env->div1;
233     den = env->div2;
234     if (den == 0)
235         raise_exception(EXCP_DIV0);
236     quot = num / den;
237     rem = num % den;
238     flags = 0;
239     if (word && quot != (int16_t)quot)
240         flags |= CCF_V;
241     if (quot == 0)
242         flags |= CCF_Z;
243     else if (quot < 0)
244         flags |= CCF_N;
245     env->div1 = quot;
246     env->div2 = rem;
247     env->cc_dest = flags;
248 }
This page took 0.039571 seconds and 4 git commands to generate.