]> rtime.felk.cvut.cz Git - lisovros/qemu_apohw.git/blob - target-sh4/op_helper.c
03633f0ee8ab48080e4b8dad044fdce972ffc2e5
[lisovros/qemu_apohw.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, see <http://www.gnu.org/licenses/>.
18  */
19 #include <assert.h>
20 #include <stdlib.h>
21 #include "cpu.h"
22 #include "helper.h"
23
24 #ifndef CONFIG_USER_ONLY
25 #include "exec/softmmu_exec.h"
26
27 #define MMUSUFFIX _mmu
28
29 #define SHIFT 0
30 #include "exec/softmmu_template.h"
31
32 #define SHIFT 1
33 #include "exec/softmmu_template.h"
34
35 #define SHIFT 2
36 #include "exec/softmmu_template.h"
37
38 #define SHIFT 3
39 #include "exec/softmmu_template.h"
40
41 void tlb_fill(CPUSH4State *env, target_ulong addr, int is_write, int mmu_idx,
42               uintptr_t retaddr)
43 {
44     SuperHCPU *cpu = sh_env_get_cpu(env);
45     int ret;
46
47     ret = superh_cpu_handle_mmu_fault(CPU(cpu), addr, is_write, mmu_idx);
48     if (ret) {
49         /* now we have a real cpu fault */
50         if (retaddr) {
51             cpu_restore_state(env, retaddr);
52         }
53         cpu_loop_exit(env);
54     }
55 }
56
57 #endif
58
59 void helper_ldtlb(CPUSH4State *env)
60 {
61 #ifdef CONFIG_USER_ONLY
62     /* XXXXX */
63     cpu_abort(env, "Unhandled ldtlb");
64 #else
65     cpu_load_tlb(env);
66 #endif
67 }
68
69 static inline void QEMU_NORETURN raise_exception(CPUSH4State *env, int index,
70                                                  uintptr_t retaddr)
71 {
72     CPUState *cs = CPU(sh_env_get_cpu(env));
73
74     cs->exception_index = index;
75     if (retaddr) {
76         cpu_restore_state(env, retaddr);
77     }
78     cpu_loop_exit(env);
79 }
80
81 void helper_raise_illegal_instruction(CPUSH4State *env)
82 {
83     raise_exception(env, 0x180, 0);
84 }
85
86 void helper_raise_slot_illegal_instruction(CPUSH4State *env)
87 {
88     raise_exception(env, 0x1a0, 0);
89 }
90
91 void helper_raise_fpu_disable(CPUSH4State *env)
92 {
93     raise_exception(env, 0x800, 0);
94 }
95
96 void helper_raise_slot_fpu_disable(CPUSH4State *env)
97 {
98     raise_exception(env, 0x820, 0);
99 }
100
101 void helper_debug(CPUSH4State *env)
102 {
103     raise_exception(env, EXCP_DEBUG, 0);
104 }
105
106 void helper_sleep(CPUSH4State *env)
107 {
108     CPUState *cs = CPU(sh_env_get_cpu(env));
109
110     cs->halted = 1;
111     env->in_sleep = 1;
112     raise_exception(env, EXCP_HLT, 0);
113 }
114
115 void helper_trapa(CPUSH4State *env, uint32_t tra)
116 {
117     env->tra = tra << 2;
118     raise_exception(env, 0x160, 0);
119 }
120
121 void helper_movcal(CPUSH4State *env, uint32_t address, uint32_t value)
122 {
123     if (cpu_sh4_is_cached (env, address))
124     {
125         memory_content *r = malloc (sizeof(memory_content));
126         r->address = address;
127         r->value = value;
128         r->next = NULL;
129
130         *(env->movcal_backup_tail) = r;
131         env->movcal_backup_tail = &(r->next);
132     }
133 }
134
135 void helper_discard_movcal_backup(CPUSH4State *env)
136 {
137     memory_content *current = env->movcal_backup;
138
139     while(current)
140     {
141         memory_content *next = current->next;
142         free (current);
143         env->movcal_backup = current = next;
144         if (current == NULL)
145             env->movcal_backup_tail = &(env->movcal_backup);
146     } 
147 }
148
149 void helper_ocbi(CPUSH4State *env, uint32_t address)
150 {
151     memory_content **current = &(env->movcal_backup);
152     while (*current)
153     {
154         uint32_t a = (*current)->address;
155         if ((a & ~0x1F) == (address & ~0x1F))
156         {
157             memory_content *next = (*current)->next;
158             cpu_stl_data(env, a, (*current)->value);
159             
160             if (next == NULL)
161             {
162                 env->movcal_backup_tail = current;
163             }
164
165             free (*current);
166             *current = next;
167             break;
168         }
169     }
170 }
171
172 #define T (env->sr & SR_T)
173 #define Q (env->sr & SR_Q ? 1 : 0)
174 #define M (env->sr & SR_M ? 1 : 0)
175 #define SETT env->sr |= SR_T
176 #define CLRT env->sr &= ~SR_T
177 #define SETQ env->sr |= SR_Q
178 #define CLRQ env->sr &= ~SR_Q
179 #define SETM env->sr |= SR_M
180 #define CLRM env->sr &= ~SR_M
181
182 uint32_t helper_div1(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
183 {
184     uint32_t tmp0, tmp2;
185     uint8_t old_q, tmp1 = 0xff;
186
187     //printf("div1 arg0=0x%08x arg1=0x%08x M=%d Q=%d T=%d\n", arg0, arg1, M, Q, T);
188     old_q = Q;
189     if ((0x80000000 & arg1) != 0)
190         SETQ;
191     else
192         CLRQ;
193     tmp2 = arg0;
194     arg1 <<= 1;
195     arg1 |= T;
196     switch (old_q) {
197     case 0:
198         switch (M) {
199         case 0:
200             tmp0 = arg1;
201             arg1 -= tmp2;
202             tmp1 = arg1 > tmp0;
203             switch (Q) {
204             case 0:
205                 if (tmp1)
206                     SETQ;
207                 else
208                     CLRQ;
209                 break;
210             case 1:
211                 if (tmp1 == 0)
212                     SETQ;
213                 else
214                     CLRQ;
215                 break;
216             }
217             break;
218         case 1:
219             tmp0 = arg1;
220             arg1 += tmp2;
221             tmp1 = arg1 < tmp0;
222             switch (Q) {
223             case 0:
224                 if (tmp1 == 0)
225                     SETQ;
226                 else
227                     CLRQ;
228                 break;
229             case 1:
230                 if (tmp1)
231                     SETQ;
232                 else
233                     CLRQ;
234                 break;
235             }
236             break;
237         }
238         break;
239     case 1:
240         switch (M) {
241         case 0:
242             tmp0 = arg1;
243             arg1 += tmp2;
244             tmp1 = arg1 < tmp0;
245             switch (Q) {
246             case 0:
247                 if (tmp1)
248                     SETQ;
249                 else
250                     CLRQ;
251                 break;
252             case 1:
253                 if (tmp1 == 0)
254                     SETQ;
255                 else
256                     CLRQ;
257                 break;
258             }
259             break;
260         case 1:
261             tmp0 = arg1;
262             arg1 -= tmp2;
263             tmp1 = arg1 > tmp0;
264             switch (Q) {
265             case 0:
266                 if (tmp1 == 0)
267                     SETQ;
268                 else
269                     CLRQ;
270                 break;
271             case 1:
272                 if (tmp1)
273                     SETQ;
274                 else
275                     CLRQ;
276                 break;
277             }
278             break;
279         }
280         break;
281     }
282     if (Q == M)
283         SETT;
284     else
285         CLRT;
286     //printf("Output: arg1=0x%08x M=%d Q=%d T=%d\n", arg1, M, Q, T);
287     return arg1;
288 }
289
290 void helper_macl(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
291 {
292     int64_t res;
293
294     res = ((uint64_t) env->mach << 32) | env->macl;
295     res += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1;
296     env->mach = (res >> 32) & 0xffffffff;
297     env->macl = res & 0xffffffff;
298     if (env->sr & SR_S) {
299         if (res < 0)
300             env->mach |= 0xffff0000;
301         else
302             env->mach &= 0x00007fff;
303     }
304 }
305
306 void helper_macw(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
307 {
308     int64_t res;
309
310     res = ((uint64_t) env->mach << 32) | env->macl;
311     res += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1;
312     env->mach = (res >> 32) & 0xffffffff;
313     env->macl = res & 0xffffffff;
314     if (env->sr & SR_S) {
315         if (res < -0x80000000) {
316             env->mach = 1;
317             env->macl = 0x80000000;
318         } else if (res > 0x000000007fffffff) {
319             env->mach = 1;
320             env->macl = 0x7fffffff;
321         }
322     }
323 }
324
325 static inline void set_t(CPUSH4State *env)
326 {
327     env->sr |= SR_T;
328 }
329
330 static inline void clr_t(CPUSH4State *env)
331 {
332     env->sr &= ~SR_T;
333 }
334
335 void helper_ld_fpscr(CPUSH4State *env, uint32_t val)
336 {
337     env->fpscr = val & FPSCR_MASK;
338     if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) {
339         set_float_rounding_mode(float_round_to_zero, &env->fp_status);
340     } else {
341         set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
342     }
343     set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status);
344 }
345
346 static void update_fpscr(CPUSH4State *env, uintptr_t retaddr)
347 {
348     int xcpt, cause, enable;
349
350     xcpt = get_float_exception_flags(&env->fp_status);
351
352     /* Clear the flag entries */
353     env->fpscr &= ~FPSCR_FLAG_MASK;
354
355     if (unlikely(xcpt)) {
356         if (xcpt & float_flag_invalid) {
357             env->fpscr |= FPSCR_FLAG_V;
358         }
359         if (xcpt & float_flag_divbyzero) {
360             env->fpscr |= FPSCR_FLAG_Z;
361         }
362         if (xcpt & float_flag_overflow) {
363             env->fpscr |= FPSCR_FLAG_O;
364         }
365         if (xcpt & float_flag_underflow) {
366             env->fpscr |= FPSCR_FLAG_U;
367         }
368         if (xcpt & float_flag_inexact) {
369             env->fpscr |= FPSCR_FLAG_I;
370         }
371
372         /* Accumulate in cause entries */
373         env->fpscr |= (env->fpscr & FPSCR_FLAG_MASK)
374                       << (FPSCR_CAUSE_SHIFT - FPSCR_FLAG_SHIFT);
375
376         /* Generate an exception if enabled */
377         cause = (env->fpscr & FPSCR_CAUSE_MASK) >> FPSCR_CAUSE_SHIFT;
378         enable = (env->fpscr & FPSCR_ENABLE_MASK) >> FPSCR_ENABLE_SHIFT;
379         if (cause & enable) {
380             raise_exception(env, 0x120, retaddr);
381         }
382     }
383 }
384
385 float32 helper_fabs_FT(float32 t0)
386 {
387     return float32_abs(t0);
388 }
389
390 float64 helper_fabs_DT(float64 t0)
391 {
392     return float64_abs(t0);
393 }
394
395 float32 helper_fadd_FT(CPUSH4State *env, float32 t0, float32 t1)
396 {
397     set_float_exception_flags(0, &env->fp_status);
398     t0 = float32_add(t0, t1, &env->fp_status);
399     update_fpscr(env, GETPC());
400     return t0;
401 }
402
403 float64 helper_fadd_DT(CPUSH4State *env, float64 t0, float64 t1)
404 {
405     set_float_exception_flags(0, &env->fp_status);
406     t0 = float64_add(t0, t1, &env->fp_status);
407     update_fpscr(env, GETPC());
408     return t0;
409 }
410
411 void helper_fcmp_eq_FT(CPUSH4State *env, float32 t0, float32 t1)
412 {
413     int relation;
414
415     set_float_exception_flags(0, &env->fp_status);
416     relation = float32_compare(t0, t1, &env->fp_status);
417     if (unlikely(relation == float_relation_unordered)) {
418         update_fpscr(env, GETPC());
419     } else if (relation == float_relation_equal) {
420         set_t(env);
421     } else {
422         clr_t(env);
423     }
424 }
425
426 void helper_fcmp_eq_DT(CPUSH4State *env, float64 t0, float64 t1)
427 {
428     int relation;
429
430     set_float_exception_flags(0, &env->fp_status);
431     relation = float64_compare(t0, t1, &env->fp_status);
432     if (unlikely(relation == float_relation_unordered)) {
433         update_fpscr(env, GETPC());
434     } else if (relation == float_relation_equal) {
435         set_t(env);
436     } else {
437         clr_t(env);
438     }
439 }
440
441 void helper_fcmp_gt_FT(CPUSH4State *env, float32 t0, float32 t1)
442 {
443     int relation;
444
445     set_float_exception_flags(0, &env->fp_status);
446     relation = float32_compare(t0, t1, &env->fp_status);
447     if (unlikely(relation == float_relation_unordered)) {
448         update_fpscr(env, GETPC());
449     } else if (relation == float_relation_greater) {
450         set_t(env);
451     } else {
452         clr_t(env);
453     }
454 }
455
456 void helper_fcmp_gt_DT(CPUSH4State *env, float64 t0, float64 t1)
457 {
458     int relation;
459
460     set_float_exception_flags(0, &env->fp_status);
461     relation = float64_compare(t0, t1, &env->fp_status);
462     if (unlikely(relation == float_relation_unordered)) {
463         update_fpscr(env, GETPC());
464     } else if (relation == float_relation_greater) {
465         set_t(env);
466     } else {
467         clr_t(env);
468     }
469 }
470
471 float64 helper_fcnvsd_FT_DT(CPUSH4State *env, float32 t0)
472 {
473     float64 ret;
474     set_float_exception_flags(0, &env->fp_status);
475     ret = float32_to_float64(t0, &env->fp_status);
476     update_fpscr(env, GETPC());
477     return ret;
478 }
479
480 float32 helper_fcnvds_DT_FT(CPUSH4State *env, float64 t0)
481 {
482     float32 ret;
483     set_float_exception_flags(0, &env->fp_status);
484     ret = float64_to_float32(t0, &env->fp_status);
485     update_fpscr(env, GETPC());
486     return ret;
487 }
488
489 float32 helper_fdiv_FT(CPUSH4State *env, float32 t0, float32 t1)
490 {
491     set_float_exception_flags(0, &env->fp_status);
492     t0 = float32_div(t0, t1, &env->fp_status);
493     update_fpscr(env, GETPC());
494     return t0;
495 }
496
497 float64 helper_fdiv_DT(CPUSH4State *env, float64 t0, float64 t1)
498 {
499     set_float_exception_flags(0, &env->fp_status);
500     t0 = float64_div(t0, t1, &env->fp_status);
501     update_fpscr(env, GETPC());
502     return t0;
503 }
504
505 float32 helper_float_FT(CPUSH4State *env, uint32_t t0)
506 {
507     float32 ret;
508     set_float_exception_flags(0, &env->fp_status);
509     ret = int32_to_float32(t0, &env->fp_status);
510     update_fpscr(env, GETPC());
511     return ret;
512 }
513
514 float64 helper_float_DT(CPUSH4State *env, uint32_t t0)
515 {
516     float64 ret;
517     set_float_exception_flags(0, &env->fp_status);
518     ret = int32_to_float64(t0, &env->fp_status);
519     update_fpscr(env, GETPC());
520     return ret;
521 }
522
523 float32 helper_fmac_FT(CPUSH4State *env, float32 t0, float32 t1, float32 t2)
524 {
525     set_float_exception_flags(0, &env->fp_status);
526     t0 = float32_muladd(t0, t1, t2, 0, &env->fp_status);
527     update_fpscr(env, GETPC());
528     return t0;
529 }
530
531 float32 helper_fmul_FT(CPUSH4State *env, float32 t0, float32 t1)
532 {
533     set_float_exception_flags(0, &env->fp_status);
534     t0 = float32_mul(t0, t1, &env->fp_status);
535     update_fpscr(env, GETPC());
536     return t0;
537 }
538
539 float64 helper_fmul_DT(CPUSH4State *env, float64 t0, float64 t1)
540 {
541     set_float_exception_flags(0, &env->fp_status);
542     t0 = float64_mul(t0, t1, &env->fp_status);
543     update_fpscr(env, GETPC());
544     return t0;
545 }
546
547 float32 helper_fneg_T(float32 t0)
548 {
549     return float32_chs(t0);
550 }
551
552 float32 helper_fsqrt_FT(CPUSH4State *env, float32 t0)
553 {
554     set_float_exception_flags(0, &env->fp_status);
555     t0 = float32_sqrt(t0, &env->fp_status);
556     update_fpscr(env, GETPC());
557     return t0;
558 }
559
560 float64 helper_fsqrt_DT(CPUSH4State *env, float64 t0)
561 {
562     set_float_exception_flags(0, &env->fp_status);
563     t0 = float64_sqrt(t0, &env->fp_status);
564     update_fpscr(env, GETPC());
565     return t0;
566 }
567
568 float32 helper_fsub_FT(CPUSH4State *env, float32 t0, float32 t1)
569 {
570     set_float_exception_flags(0, &env->fp_status);
571     t0 = float32_sub(t0, t1, &env->fp_status);
572     update_fpscr(env, GETPC());
573     return t0;
574 }
575
576 float64 helper_fsub_DT(CPUSH4State *env, float64 t0, float64 t1)
577 {
578     set_float_exception_flags(0, &env->fp_status);
579     t0 = float64_sub(t0, t1, &env->fp_status);
580     update_fpscr(env, GETPC());
581     return t0;
582 }
583
584 uint32_t helper_ftrc_FT(CPUSH4State *env, float32 t0)
585 {
586     uint32_t ret;
587     set_float_exception_flags(0, &env->fp_status);
588     ret = float32_to_int32_round_to_zero(t0, &env->fp_status);
589     update_fpscr(env, GETPC());
590     return ret;
591 }
592
593 uint32_t helper_ftrc_DT(CPUSH4State *env, float64 t0)
594 {
595     uint32_t ret;
596     set_float_exception_flags(0, &env->fp_status);
597     ret = float64_to_int32_round_to_zero(t0, &env->fp_status);
598     update_fpscr(env, GETPC());
599     return ret;
600 }
601
602 void helper_fipr(CPUSH4State *env, uint32_t m, uint32_t n)
603 {
604     int bank, i;
605     float32 r, p;
606
607     bank = (env->sr & FPSCR_FR) ? 16 : 0;
608     r = float32_zero;
609     set_float_exception_flags(0, &env->fp_status);
610
611     for (i = 0 ; i < 4 ; i++) {
612         p = float32_mul(env->fregs[bank + m + i],
613                         env->fregs[bank + n + i],
614                         &env->fp_status);
615         r = float32_add(r, p, &env->fp_status);
616     }
617     update_fpscr(env, GETPC());
618
619     env->fregs[bank + n + 3] = r;
620 }
621
622 void helper_ftrv(CPUSH4State *env, uint32_t n)
623 {
624     int bank_matrix, bank_vector;
625     int i, j;
626     float32 r[4];
627     float32 p;
628
629     bank_matrix = (env->sr & FPSCR_FR) ? 0 : 16;
630     bank_vector = (env->sr & FPSCR_FR) ? 16 : 0;
631     set_float_exception_flags(0, &env->fp_status);
632     for (i = 0 ; i < 4 ; i++) {
633         r[i] = float32_zero;
634         for (j = 0 ; j < 4 ; j++) {
635             p = float32_mul(env->fregs[bank_matrix + 4 * j + i],
636                             env->fregs[bank_vector + j],
637                             &env->fp_status);
638             r[i] = float32_add(r[i], p, &env->fp_status);
639         }
640     }
641     update_fpscr(env, GETPC());
642
643     for (i = 0 ; i < 4 ; i++) {
644         env->fregs[bank_vector + i] = r[i];
645     }
646 }