]> git.proxmox.com Git - qemu.git/blob - target-sh4/op_helper.c
Fix off-by-one unwinding error.
[qemu.git] / target-sh4 / op_helper.c
1 /*
2 * SH4 emulation
3 *
4 * Copyright (c) 2005 Samuel Tardieu
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 <assert.h>
21 #include "exec.h"
22
23 void do_raise_exception(void)
24 {
25 cpu_loop_exit();
26 }
27
28 #ifndef CONFIG_USER_ONLY
29
30 #define MMUSUFFIX _mmu
31
32 #define SHIFT 0
33 #include "softmmu_template.h"
34
35 #define SHIFT 1
36 #include "softmmu_template.h"
37
38 #define SHIFT 2
39 #include "softmmu_template.h"
40
41 #define SHIFT 3
42 #include "softmmu_template.h"
43
44 void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
45 {
46 TranslationBlock *tb;
47 CPUState *saved_env;
48 unsigned long pc;
49 int ret;
50
51 /* XXX: hack to restore env in all cases, even if not called from
52 generated code */
53 saved_env = env;
54 env = cpu_single_env;
55 ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
56 if (ret) {
57 if (retaddr) {
58 /* now we have a real cpu fault */
59 pc = (unsigned long) retaddr;
60 tb = tb_find_pc(pc);
61 if (tb) {
62 /* the PC is inside the translated code. It means that we have
63 a virtual CPU fault */
64 cpu_restore_state(tb, env, pc, NULL);
65 }
66 }
67 do_raise_exception();
68 }
69 env = saved_env;
70 }
71
72 #endif
73
74 void helper_ldtlb(void)
75 {
76 #ifdef CONFIG_USER_ONLY
77 /* XXXXX */
78 assert(0);
79 #else
80 cpu_load_tlb(env);
81 #endif
82 }
83
84 void helper_addc_T0_T1(void)
85 {
86 uint32_t tmp0, tmp1;
87
88 tmp1 = T0 + T1;
89 tmp0 = T1;
90 T1 = tmp1 + (env->sr & 1);
91 if (tmp0 > tmp1)
92 env->sr |= SR_T;
93 else
94 env->sr &= ~SR_T;
95 if (tmp1 > T1)
96 env->sr |= SR_T;
97 }
98
99 void helper_addv_T0_T1(void)
100 {
101 uint32_t dest, src, ans;
102
103 if ((int32_t) T1 >= 0)
104 dest = 0;
105 else
106 dest = 1;
107 if ((int32_t) T0 >= 0)
108 src = 0;
109 else
110 src = 1;
111 src += dest;
112 T1 += T0;
113 if ((int32_t) T1 >= 0)
114 ans = 0;
115 else
116 ans = 1;
117 ans += dest;
118 if (src == 0 || src == 2) {
119 if (ans == 1)
120 env->sr |= SR_T;
121 else
122 env->sr &= ~SR_T;
123 } else
124 env->sr &= ~SR_T;
125 }
126
127 #define T (env->sr & SR_T)
128 #define Q (env->sr & SR_Q ? 1 : 0)
129 #define M (env->sr & SR_M ? 1 : 0)
130 #define SETT env->sr |= SR_T
131 #define CLRT env->sr &= ~SR_T
132 #define SETQ env->sr |= SR_Q
133 #define CLRQ env->sr &= ~SR_Q
134 #define SETM env->sr |= SR_M
135 #define CLRM env->sr &= ~SR_M
136
137 void helper_div1_T0_T1(void)
138 {
139 uint32_t tmp0, tmp2;
140 uint8_t old_q, tmp1 = 0xff;
141
142 //printf("div1 T0=0x%08x T1=0x%08x M=%d Q=%d T=%d\n", T0, T1, M, Q, T);
143 old_q = Q;
144 if ((0x80000000 & T1) != 0)
145 SETQ;
146 else
147 CLRQ;
148 tmp2 = T0;
149 T1 <<= 1;
150 T1 |= T;
151 switch (old_q) {
152 case 0:
153 switch (M) {
154 case 0:
155 tmp0 = T1;
156 T1 -= tmp2;
157 tmp1 = T1 > tmp0;
158 switch (Q) {
159 case 0:
160 if (tmp1)
161 SETQ;
162 else
163 CLRQ;
164 break;
165 case 1:
166 if (tmp1 == 0)
167 SETQ;
168 else
169 CLRQ;
170 break;
171 }
172 break;
173 case 1:
174 tmp0 = T1;
175 T1 += tmp2;
176 tmp1 = T1 < tmp0;
177 switch (Q) {
178 case 0:
179 if (tmp1 == 0)
180 SETQ;
181 else
182 CLRQ;
183 break;
184 case 1:
185 if (tmp1)
186 SETQ;
187 else
188 CLRQ;
189 break;
190 }
191 break;
192 }
193 break;
194 case 1:
195 switch (M) {
196 case 0:
197 tmp0 = T1;
198 T1 += tmp2;
199 tmp1 = T1 < tmp0;
200 switch (Q) {
201 case 0:
202 if (tmp1)
203 SETQ;
204 else
205 CLRQ;
206 break;
207 case 1:
208 if (tmp1 == 0)
209 SETQ;
210 else
211 CLRQ;
212 break;
213 }
214 break;
215 case 1:
216 tmp0 = T1;
217 T1 -= tmp2;
218 tmp1 = T1 > tmp0;
219 switch (Q) {
220 case 0:
221 if (tmp1 == 0)
222 SETQ;
223 else
224 CLRQ;
225 break;
226 case 1:
227 if (tmp1)
228 SETQ;
229 else
230 CLRQ;
231 break;
232 }
233 break;
234 }
235 break;
236 }
237 if (Q == M)
238 SETT;
239 else
240 CLRT;
241 //printf("Output: T1=0x%08x M=%d Q=%d T=%d\n", T1, M, Q, T);
242 }
243
244 void helper_dmulsl_T0_T1()
245 {
246 int64_t res;
247
248 res = (int64_t) (int32_t) T0 *(int64_t) (int32_t) T1;
249 env->mach = (res >> 32) & 0xffffffff;
250 env->macl = res & 0xffffffff;
251 }
252
253 void helper_dmulul_T0_T1()
254 {
255 uint64_t res;
256
257 res = (uint64_t) (uint32_t) T0 *(uint64_t) (uint32_t) T1;
258 env->mach = (res >> 32) & 0xffffffff;
259 env->macl = res & 0xffffffff;
260 }
261
262 void helper_macl_T0_T1()
263 {
264 int64_t res;
265
266 res = ((uint64_t) env->mach << 32) | env->macl;
267 res += (int64_t) (int32_t) T0 *(int64_t) (int32_t) T1;
268 env->mach = (res >> 32) & 0xffffffff;
269 env->macl = res & 0xffffffff;
270 if (env->sr & SR_S) {
271 if (res < 0)
272 env->mach |= 0xffff0000;
273 else
274 env->mach &= 0x00007fff;
275 }
276 }
277
278 void helper_macw_T0_T1()
279 {
280 int64_t res;
281
282 res = ((uint64_t) env->mach << 32) | env->macl;
283 res += (int64_t) (int16_t) T0 *(int64_t) (int16_t) T1;
284 env->mach = (res >> 32) & 0xffffffff;
285 env->macl = res & 0xffffffff;
286 if (env->sr & SR_S) {
287 if (res < -0x80000000) {
288 env->mach = 1;
289 env->macl = 0x80000000;
290 } else if (res > 0x000000007fffffff) {
291 env->mach = 1;
292 env->macl = 0x7fffffff;
293 }
294 }
295 }
296
297 void helper_negc_T0()
298 {
299 uint32_t temp;
300
301 temp = -T0;
302 T0 = temp - (env->sr & SR_T);
303 if (0 < temp)
304 env->sr |= SR_T;
305 else
306 env->sr &= ~SR_T;
307 if (temp < T0)
308 env->sr |= SR_T;
309 }
310
311 void helper_subc_T0_T1()
312 {
313 uint32_t tmp0, tmp1;
314
315 tmp1 = T1 - T0;
316 tmp0 = T1;
317 T1 = tmp1 - (env->sr & SR_T);
318 if (tmp0 < tmp1)
319 env->sr |= SR_T;
320 else
321 env->sr &= ~SR_T;
322 if (tmp1 < T1)
323 env->sr |= SR_T;
324 }
325
326 void helper_subv_T0_T1()
327 {
328 int32_t dest, src, ans;
329
330 if ((int32_t) T1 >= 0)
331 dest = 0;
332 else
333 dest = 1;
334 if ((int32_t) T0 >= 0)
335 src = 0;
336 else
337 src = 1;
338 src += dest;
339 T1 -= T0;
340 if ((int32_t) T1 >= 0)
341 ans = 0;
342 else
343 ans = 1;
344 ans += dest;
345 if (src == 1) {
346 if (ans == 1)
347 env->sr |= SR_T;
348 else
349 env->sr &= ~SR_T;
350 } else
351 env->sr &= ~SR_T;
352 }
353
354 void helper_rotcl(uint32_t * addr)
355 {
356 uint32_t new;
357
358 new = (*addr << 1) | (env->sr & SR_T);
359 if (*addr & 0x80000000)
360 env->sr |= SR_T;
361 else
362 env->sr &= ~SR_T;
363 *addr = new;
364 }
365
366 void helper_rotcr(uint32_t * addr)
367 {
368 uint32_t new;
369
370 new = (*addr >> 1) | ((env->sr & SR_T) ? 0x80000000 : 0);
371 if (*addr & 1)
372 env->sr |= SR_T;
373 else
374 env->sr &= ~SR_T;
375 *addr = new;
376 }