Merge remote-tracking branch 'qemu/master'
[qemu/ar7.git] / target-sh4 / op_helper.c
blobf9aa0b4eda1a9c252b9ae7c25bdbd3a4dad58887
1 /*
2 * SH4 emulation
4 * Copyright (c) 2005 Samuel Tardieu
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.
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.
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/>.
20 #include "cpu.h"
21 #include "exec/helper-proto.h"
22 #include "exec/cpu_ldst.h"
24 #ifndef CONFIG_USER_ONLY
26 void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
27 uintptr_t retaddr)
29 int ret;
31 ret = superh_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
32 if (ret) {
33 /* now we have a real cpu fault */
34 if (retaddr) {
35 cpu_restore_state(cs, retaddr);
37 cpu_loop_exit(cs);
41 #endif
43 #ifdef CONFIG_USER_ONLY
44 void QEMU_NORETURN helper_ldtlb(CPUSH4State *env)
45 #else
46 void helper_ldtlb(CPUSH4State *env)
47 #endif
49 #ifdef CONFIG_USER_ONLY
50 SuperHCPU *cpu = sh_env_get_cpu(env);
52 /* XXXXX */
53 cpu_abort(CPU(cpu), "Unhandled ldtlb");
54 #else
55 cpu_load_tlb(env);
56 #endif
59 static inline void QEMU_NORETURN raise_exception(CPUSH4State *env, int index,
60 uintptr_t retaddr)
62 CPUState *cs = CPU(sh_env_get_cpu(env));
64 cs->exception_index = index;
65 if (retaddr) {
66 cpu_restore_state(cs, retaddr);
68 cpu_loop_exit(cs);
71 void QEMU_NORETURN helper_raise_illegal_instruction(CPUSH4State *env)
73 raise_exception(env, 0x180, 0);
76 void QEMU_NORETURN helper_raise_slot_illegal_instruction(CPUSH4State *env)
78 raise_exception(env, 0x1a0, 0);
81 void QEMU_NORETURN helper_raise_fpu_disable(CPUSH4State *env)
83 raise_exception(env, 0x800, 0);
86 void QEMU_NORETURN helper_raise_slot_fpu_disable(CPUSH4State *env)
88 raise_exception(env, 0x820, 0);
91 void QEMU_NORETURN helper_debug(CPUSH4State *env)
93 raise_exception(env, EXCP_DEBUG, 0);
96 void QEMU_NORETURN helper_sleep(CPUSH4State *env)
98 CPUState *cs = CPU(sh_env_get_cpu(env));
100 cs->halted = 1;
101 env->in_sleep = 1;
102 raise_exception(env, EXCP_HLT, 0);
105 void QEMU_NORETURN helper_trapa(CPUSH4State *env, uint32_t tra)
107 env->tra = tra << 2;
108 raise_exception(env, 0x160, 0);
111 void helper_movcal(CPUSH4State *env, uint32_t address, uint32_t value)
113 if (cpu_sh4_is_cached (env, address))
115 memory_content *r = malloc (sizeof(memory_content));
116 r->address = address;
117 r->value = value;
118 r->next = NULL;
120 *(env->movcal_backup_tail) = r;
121 env->movcal_backup_tail = &(r->next);
125 void helper_discard_movcal_backup(CPUSH4State *env)
127 memory_content *current = env->movcal_backup;
129 while(current)
131 memory_content *next = current->next;
132 free (current);
133 env->movcal_backup = current = next;
134 if (current == NULL)
135 env->movcal_backup_tail = &(env->movcal_backup);
139 void helper_ocbi(CPUSH4State *env, uint32_t address)
141 memory_content **current = &(env->movcal_backup);
142 while (*current)
144 uint32_t a = (*current)->address;
145 if ((a & ~0x1F) == (address & ~0x1F))
147 memory_content *next = (*current)->next;
148 cpu_stl_data(env, a, (*current)->value);
150 if (next == NULL)
152 env->movcal_backup_tail = current;
155 free (*current);
156 *current = next;
157 break;
162 #define T (env->sr & SR_T)
163 #define Q (env->sr & SR_Q ? 1 : 0)
164 #define M (env->sr & SR_M ? 1 : 0)
165 #define SETT env->sr |= SR_T
166 #define CLRT env->sr &= ~SR_T
167 #define SETQ env->sr |= SR_Q
168 #define CLRQ env->sr &= ~SR_Q
169 #define SETM env->sr |= SR_M
170 #define CLRM env->sr &= ~SR_M
172 uint32_t helper_div1(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
174 uint32_t tmp0, tmp2;
175 uint8_t old_q, tmp1 = 0xff;
177 //printf("div1 arg0=0x%08x arg1=0x%08x M=%d Q=%d T=%d\n", arg0, arg1, M, Q, T);
178 old_q = Q;
179 if ((0x80000000 & arg1) != 0)
180 SETQ;
181 else
182 CLRQ;
183 tmp2 = arg0;
184 arg1 <<= 1;
185 arg1 |= T;
186 switch (old_q) {
187 case 0:
188 switch (M) {
189 case 0:
190 tmp0 = arg1;
191 arg1 -= tmp2;
192 tmp1 = arg1 > tmp0;
193 switch (Q) {
194 case 0:
195 if (tmp1)
196 SETQ;
197 else
198 CLRQ;
199 break;
200 case 1:
201 if (tmp1 == 0)
202 SETQ;
203 else
204 CLRQ;
205 break;
207 break;
208 case 1:
209 tmp0 = arg1;
210 arg1 += tmp2;
211 tmp1 = arg1 < tmp0;
212 switch (Q) {
213 case 0:
214 if (tmp1 == 0)
215 SETQ;
216 else
217 CLRQ;
218 break;
219 case 1:
220 if (tmp1)
221 SETQ;
222 else
223 CLRQ;
224 break;
226 break;
228 break;
229 case 1:
230 switch (M) {
231 case 0:
232 tmp0 = arg1;
233 arg1 += tmp2;
234 tmp1 = arg1 < tmp0;
235 switch (Q) {
236 case 0:
237 if (tmp1)
238 SETQ;
239 else
240 CLRQ;
241 break;
242 case 1:
243 if (tmp1 == 0)
244 SETQ;
245 else
246 CLRQ;
247 break;
249 break;
250 case 1:
251 tmp0 = arg1;
252 arg1 -= tmp2;
253 tmp1 = arg1 > tmp0;
254 switch (Q) {
255 case 0:
256 if (tmp1 == 0)
257 SETQ;
258 else
259 CLRQ;
260 break;
261 case 1:
262 if (tmp1)
263 SETQ;
264 else
265 CLRQ;
266 break;
268 break;
270 break;
272 if (Q == M)
273 SETT;
274 else
275 CLRT;
276 //printf("Output: arg1=0x%08x M=%d Q=%d T=%d\n", arg1, M, Q, T);
277 return arg1;
280 void helper_macl(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
282 int64_t res;
284 res = ((uint64_t) env->mach << 32) | env->macl;
285 res += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1;
286 env->mach = (res >> 32) & 0xffffffff;
287 env->macl = res & 0xffffffff;
288 if (env->sr & SR_S) {
289 if (res < 0)
290 env->mach |= 0xffff0000;
291 else
292 env->mach &= 0x00007fff;
296 void helper_macw(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
298 int64_t res;
300 res = ((uint64_t) env->mach << 32) | env->macl;
301 res += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1;
302 env->mach = (res >> 32) & 0xffffffff;
303 env->macl = res & 0xffffffff;
304 if (env->sr & SR_S) {
305 if (res < -0x80000000) {
306 env->mach = 1;
307 env->macl = 0x80000000;
308 } else if (res > 0x000000007fffffff) {
309 env->mach = 1;
310 env->macl = 0x7fffffff;
315 static inline void set_t(CPUSH4State *env)
317 env->sr |= SR_T;
320 static inline void clr_t(CPUSH4State *env)
322 env->sr &= ~SR_T;
325 void helper_ld_fpscr(CPUSH4State *env, uint32_t val)
327 env->fpscr = val & FPSCR_MASK;
328 if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) {
329 set_float_rounding_mode(float_round_to_zero, &env->fp_status);
330 } else {
331 set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
333 set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status);
336 static void update_fpscr(CPUSH4State *env, uintptr_t retaddr)
338 int xcpt, cause, enable;
340 xcpt = get_float_exception_flags(&env->fp_status);
342 /* Clear the flag entries */
343 env->fpscr &= ~FPSCR_FLAG_MASK;
345 if (unlikely(xcpt)) {
346 if (xcpt & float_flag_invalid) {
347 env->fpscr |= FPSCR_FLAG_V;
349 if (xcpt & float_flag_divbyzero) {
350 env->fpscr |= FPSCR_FLAG_Z;
352 if (xcpt & float_flag_overflow) {
353 env->fpscr |= FPSCR_FLAG_O;
355 if (xcpt & float_flag_underflow) {
356 env->fpscr |= FPSCR_FLAG_U;
358 if (xcpt & float_flag_inexact) {
359 env->fpscr |= FPSCR_FLAG_I;
362 /* Accumulate in cause entries */
363 env->fpscr |= (env->fpscr & FPSCR_FLAG_MASK)
364 << (FPSCR_CAUSE_SHIFT - FPSCR_FLAG_SHIFT);
366 /* Generate an exception if enabled */
367 cause = (env->fpscr & FPSCR_CAUSE_MASK) >> FPSCR_CAUSE_SHIFT;
368 enable = (env->fpscr & FPSCR_ENABLE_MASK) >> FPSCR_ENABLE_SHIFT;
369 if (cause & enable) {
370 raise_exception(env, 0x120, retaddr);
375 float32 helper_fabs_FT(float32 t0)
377 return float32_abs(t0);
380 float64 helper_fabs_DT(float64 t0)
382 return float64_abs(t0);
385 float32 helper_fadd_FT(CPUSH4State *env, float32 t0, float32 t1)
387 set_float_exception_flags(0, &env->fp_status);
388 t0 = float32_add(t0, t1, &env->fp_status);
389 update_fpscr(env, GETPC());
390 return t0;
393 float64 helper_fadd_DT(CPUSH4State *env, float64 t0, float64 t1)
395 set_float_exception_flags(0, &env->fp_status);
396 t0 = float64_add(t0, t1, &env->fp_status);
397 update_fpscr(env, GETPC());
398 return t0;
401 void helper_fcmp_eq_FT(CPUSH4State *env, float32 t0, float32 t1)
403 int relation;
405 set_float_exception_flags(0, &env->fp_status);
406 relation = float32_compare(t0, t1, &env->fp_status);
407 if (unlikely(relation == float_relation_unordered)) {
408 update_fpscr(env, GETPC());
409 } else if (relation == float_relation_equal) {
410 set_t(env);
411 } else {
412 clr_t(env);
416 void helper_fcmp_eq_DT(CPUSH4State *env, float64 t0, float64 t1)
418 int relation;
420 set_float_exception_flags(0, &env->fp_status);
421 relation = float64_compare(t0, t1, &env->fp_status);
422 if (unlikely(relation == float_relation_unordered)) {
423 update_fpscr(env, GETPC());
424 } else if (relation == float_relation_equal) {
425 set_t(env);
426 } else {
427 clr_t(env);
431 void helper_fcmp_gt_FT(CPUSH4State *env, float32 t0, float32 t1)
433 int relation;
435 set_float_exception_flags(0, &env->fp_status);
436 relation = float32_compare(t0, t1, &env->fp_status);
437 if (unlikely(relation == float_relation_unordered)) {
438 update_fpscr(env, GETPC());
439 } else if (relation == float_relation_greater) {
440 set_t(env);
441 } else {
442 clr_t(env);
446 void helper_fcmp_gt_DT(CPUSH4State *env, float64 t0, float64 t1)
448 int relation;
450 set_float_exception_flags(0, &env->fp_status);
451 relation = float64_compare(t0, t1, &env->fp_status);
452 if (unlikely(relation == float_relation_unordered)) {
453 update_fpscr(env, GETPC());
454 } else if (relation == float_relation_greater) {
455 set_t(env);
456 } else {
457 clr_t(env);
461 float64 helper_fcnvsd_FT_DT(CPUSH4State *env, float32 t0)
463 float64 ret;
464 set_float_exception_flags(0, &env->fp_status);
465 ret = float32_to_float64(t0, &env->fp_status);
466 update_fpscr(env, GETPC());
467 return ret;
470 float32 helper_fcnvds_DT_FT(CPUSH4State *env, float64 t0)
472 float32 ret;
473 set_float_exception_flags(0, &env->fp_status);
474 ret = float64_to_float32(t0, &env->fp_status);
475 update_fpscr(env, GETPC());
476 return ret;
479 float32 helper_fdiv_FT(CPUSH4State *env, float32 t0, float32 t1)
481 set_float_exception_flags(0, &env->fp_status);
482 t0 = float32_div(t0, t1, &env->fp_status);
483 update_fpscr(env, GETPC());
484 return t0;
487 float64 helper_fdiv_DT(CPUSH4State *env, float64 t0, float64 t1)
489 set_float_exception_flags(0, &env->fp_status);
490 t0 = float64_div(t0, t1, &env->fp_status);
491 update_fpscr(env, GETPC());
492 return t0;
495 float32 helper_float_FT(CPUSH4State *env, uint32_t t0)
497 float32 ret;
498 set_float_exception_flags(0, &env->fp_status);
499 ret = int32_to_float32(t0, &env->fp_status);
500 update_fpscr(env, GETPC());
501 return ret;
504 float64 helper_float_DT(CPUSH4State *env, uint32_t t0)
506 float64 ret;
507 set_float_exception_flags(0, &env->fp_status);
508 ret = int32_to_float64(t0, &env->fp_status);
509 update_fpscr(env, GETPC());
510 return ret;
513 float32 helper_fmac_FT(CPUSH4State *env, float32 t0, float32 t1, float32 t2)
515 set_float_exception_flags(0, &env->fp_status);
516 t0 = float32_muladd(t0, t1, t2, 0, &env->fp_status);
517 update_fpscr(env, GETPC());
518 return t0;
521 float32 helper_fmul_FT(CPUSH4State *env, float32 t0, float32 t1)
523 set_float_exception_flags(0, &env->fp_status);
524 t0 = float32_mul(t0, t1, &env->fp_status);
525 update_fpscr(env, GETPC());
526 return t0;
529 float64 helper_fmul_DT(CPUSH4State *env, float64 t0, float64 t1)
531 set_float_exception_flags(0, &env->fp_status);
532 t0 = float64_mul(t0, t1, &env->fp_status);
533 update_fpscr(env, GETPC());
534 return t0;
537 float32 helper_fneg_T(float32 t0)
539 return float32_chs(t0);
542 float32 helper_fsqrt_FT(CPUSH4State *env, float32 t0)
544 set_float_exception_flags(0, &env->fp_status);
545 t0 = float32_sqrt(t0, &env->fp_status);
546 update_fpscr(env, GETPC());
547 return t0;
550 float64 helper_fsqrt_DT(CPUSH4State *env, float64 t0)
552 set_float_exception_flags(0, &env->fp_status);
553 t0 = float64_sqrt(t0, &env->fp_status);
554 update_fpscr(env, GETPC());
555 return t0;
558 float32 helper_fsub_FT(CPUSH4State *env, float32 t0, float32 t1)
560 set_float_exception_flags(0, &env->fp_status);
561 t0 = float32_sub(t0, t1, &env->fp_status);
562 update_fpscr(env, GETPC());
563 return t0;
566 float64 helper_fsub_DT(CPUSH4State *env, float64 t0, float64 t1)
568 set_float_exception_flags(0, &env->fp_status);
569 t0 = float64_sub(t0, t1, &env->fp_status);
570 update_fpscr(env, GETPC());
571 return t0;
574 uint32_t helper_ftrc_FT(CPUSH4State *env, float32 t0)
576 uint32_t ret;
577 set_float_exception_flags(0, &env->fp_status);
578 ret = float32_to_int32_round_to_zero(t0, &env->fp_status);
579 update_fpscr(env, GETPC());
580 return ret;
583 uint32_t helper_ftrc_DT(CPUSH4State *env, float64 t0)
585 uint32_t ret;
586 set_float_exception_flags(0, &env->fp_status);
587 ret = float64_to_int32_round_to_zero(t0, &env->fp_status);
588 update_fpscr(env, GETPC());
589 return ret;
592 void helper_fipr(CPUSH4State *env, uint32_t m, uint32_t n)
594 int bank, i;
595 float32 r, p;
597 bank = (env->sr & FPSCR_FR) ? 16 : 0;
598 r = float32_zero;
599 set_float_exception_flags(0, &env->fp_status);
601 for (i = 0 ; i < 4 ; i++) {
602 p = float32_mul(env->fregs[bank + m + i],
603 env->fregs[bank + n + i],
604 &env->fp_status);
605 r = float32_add(r, p, &env->fp_status);
607 update_fpscr(env, GETPC());
609 env->fregs[bank + n + 3] = r;
612 void helper_ftrv(CPUSH4State *env, uint32_t n)
614 int bank_matrix, bank_vector;
615 int i, j;
616 float32 r[4];
617 float32 p;
619 bank_matrix = (env->sr & FPSCR_FR) ? 0 : 16;
620 bank_vector = (env->sr & FPSCR_FR) ? 16 : 0;
621 set_float_exception_flags(0, &env->fp_status);
622 for (i = 0 ; i < 4 ; i++) {
623 r[i] = float32_zero;
624 for (j = 0 ; j < 4 ; j++) {
625 p = float32_mul(env->fregs[bank_matrix + 4 * j + i],
626 env->fregs[bank_vector + j],
627 &env->fp_status);
628 r[i] = float32_add(r[i], p, &env->fp_status);
631 update_fpscr(env, GETPC());
633 for (i = 0 ; i < 4 ; i++) {
634 env->fregs[bank_vector + i] = r[i];