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