Add qemu 2.4.0
[kvmfornfv.git] / 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, see <http://www.gnu.org/licenses/>.
18  */
19 #include <assert.h>
20 #include <stdlib.h>
21 #include "cpu.h"
22 #include "exec/helper-proto.h"
23 #include "exec/cpu_ldst.h"
24
25 #ifndef CONFIG_USER_ONLY
26
27 void tlb_fill(CPUState *cs, target_ulong addr, int is_write, int mmu_idx,
28               uintptr_t retaddr)
29 {
30     int ret;
31
32     ret = superh_cpu_handle_mmu_fault(cs, addr, is_write, mmu_idx);
33     if (ret) {
34         /* now we have a real cpu fault */
35         if (retaddr) {
36             cpu_restore_state(cs, retaddr);
37         }
38         cpu_loop_exit(cs);
39     }
40 }
41
42 #endif
43
44 void helper_ldtlb(CPUSH4State *env)
45 {
46 #ifdef CONFIG_USER_ONLY
47     SuperHCPU *cpu = sh_env_get_cpu(env);
48
49     /* XXXXX */
50     cpu_abort(CPU(cpu), "Unhandled ldtlb");
51 #else
52     cpu_load_tlb(env);
53 #endif
54 }
55
56 static inline void QEMU_NORETURN raise_exception(CPUSH4State *env, int index,
57                                                  uintptr_t retaddr)
58 {
59     CPUState *cs = CPU(sh_env_get_cpu(env));
60
61     cs->exception_index = index;
62     if (retaddr) {
63         cpu_restore_state(cs, retaddr);
64     }
65     cpu_loop_exit(cs);
66 }
67
68 void helper_raise_illegal_instruction(CPUSH4State *env)
69 {
70     raise_exception(env, 0x180, 0);
71 }
72
73 void helper_raise_slot_illegal_instruction(CPUSH4State *env)
74 {
75     raise_exception(env, 0x1a0, 0);
76 }
77
78 void helper_raise_fpu_disable(CPUSH4State *env)
79 {
80     raise_exception(env, 0x800, 0);
81 }
82
83 void helper_raise_slot_fpu_disable(CPUSH4State *env)
84 {
85     raise_exception(env, 0x820, 0);
86 }
87
88 void helper_debug(CPUSH4State *env)
89 {
90     raise_exception(env, EXCP_DEBUG, 0);
91 }
92
93 void helper_sleep(CPUSH4State *env)
94 {
95     CPUState *cs = CPU(sh_env_get_cpu(env));
96
97     cs->halted = 1;
98     env->in_sleep = 1;
99     raise_exception(env, EXCP_HLT, 0);
100 }
101
102 void helper_trapa(CPUSH4State *env, uint32_t tra)
103 {
104     env->tra = tra << 2;
105     raise_exception(env, 0x160, 0);
106 }
107
108 void helper_movcal(CPUSH4State *env, uint32_t address, uint32_t value)
109 {
110     if (cpu_sh4_is_cached (env, address))
111     {
112         memory_content *r = malloc (sizeof(memory_content));
113         r->address = address;
114         r->value = value;
115         r->next = NULL;
116
117         *(env->movcal_backup_tail) = r;
118         env->movcal_backup_tail = &(r->next);
119     }
120 }
121
122 void helper_discard_movcal_backup(CPUSH4State *env)
123 {
124     memory_content *current = env->movcal_backup;
125
126     while(current)
127     {
128         memory_content *next = current->next;
129         free (current);
130         env->movcal_backup = current = next;
131         if (current == NULL)
132             env->movcal_backup_tail = &(env->movcal_backup);
133     } 
134 }
135
136 void helper_ocbi(CPUSH4State *env, uint32_t address)
137 {
138     memory_content **current = &(env->movcal_backup);
139     while (*current)
140     {
141         uint32_t a = (*current)->address;
142         if ((a & ~0x1F) == (address & ~0x1F))
143         {
144             memory_content *next = (*current)->next;
145             cpu_stl_data(env, a, (*current)->value);
146             
147             if (next == NULL)
148             {
149                 env->movcal_backup_tail = current;
150             }
151
152             free (*current);
153             *current = next;
154             break;
155         }
156     }
157 }
158
159 void helper_macl(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
160 {
161     int64_t res;
162
163     res = ((uint64_t) env->mach << 32) | env->macl;
164     res += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1;
165     env->mach = (res >> 32) & 0xffffffff;
166     env->macl = res & 0xffffffff;
167     if (env->sr & (1u << SR_S)) {
168         if (res < 0)
169             env->mach |= 0xffff0000;
170         else
171             env->mach &= 0x00007fff;
172     }
173 }
174
175 void helper_macw(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
176 {
177     int64_t res;
178
179     res = ((uint64_t) env->mach << 32) | env->macl;
180     res += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1;
181     env->mach = (res >> 32) & 0xffffffff;
182     env->macl = res & 0xffffffff;
183     if (env->sr & (1u << SR_S)) {
184         if (res < -0x80000000) {
185             env->mach = 1;
186             env->macl = 0x80000000;
187         } else if (res > 0x000000007fffffff) {
188             env->mach = 1;
189             env->macl = 0x7fffffff;
190         }
191     }
192 }
193
194 void helper_ld_fpscr(CPUSH4State *env, uint32_t val)
195 {
196     env->fpscr = val & FPSCR_MASK;
197     if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) {
198         set_float_rounding_mode(float_round_to_zero, &env->fp_status);
199     } else {
200         set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
201     }
202     set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status);
203 }
204
205 static void update_fpscr(CPUSH4State *env, uintptr_t retaddr)
206 {
207     int xcpt, cause, enable;
208
209     xcpt = get_float_exception_flags(&env->fp_status);
210
211     /* Clear the flag entries */
212     env->fpscr &= ~FPSCR_FLAG_MASK;
213
214     if (unlikely(xcpt)) {
215         if (xcpt & float_flag_invalid) {
216             env->fpscr |= FPSCR_FLAG_V;
217         }
218         if (xcpt & float_flag_divbyzero) {
219             env->fpscr |= FPSCR_FLAG_Z;
220         }
221         if (xcpt & float_flag_overflow) {
222             env->fpscr |= FPSCR_FLAG_O;
223         }
224         if (xcpt & float_flag_underflow) {
225             env->fpscr |= FPSCR_FLAG_U;
226         }
227         if (xcpt & float_flag_inexact) {
228             env->fpscr |= FPSCR_FLAG_I;
229         }
230
231         /* Accumulate in cause entries */
232         env->fpscr |= (env->fpscr & FPSCR_FLAG_MASK)
233                       << (FPSCR_CAUSE_SHIFT - FPSCR_FLAG_SHIFT);
234
235         /* Generate an exception if enabled */
236         cause = (env->fpscr & FPSCR_CAUSE_MASK) >> FPSCR_CAUSE_SHIFT;
237         enable = (env->fpscr & FPSCR_ENABLE_MASK) >> FPSCR_ENABLE_SHIFT;
238         if (cause & enable) {
239             raise_exception(env, 0x120, retaddr);
240         }
241     }
242 }
243
244 float32 helper_fabs_FT(float32 t0)
245 {
246     return float32_abs(t0);
247 }
248
249 float64 helper_fabs_DT(float64 t0)
250 {
251     return float64_abs(t0);
252 }
253
254 float32 helper_fadd_FT(CPUSH4State *env, float32 t0, float32 t1)
255 {
256     set_float_exception_flags(0, &env->fp_status);
257     t0 = float32_add(t0, t1, &env->fp_status);
258     update_fpscr(env, GETPC());
259     return t0;
260 }
261
262 float64 helper_fadd_DT(CPUSH4State *env, float64 t0, float64 t1)
263 {
264     set_float_exception_flags(0, &env->fp_status);
265     t0 = float64_add(t0, t1, &env->fp_status);
266     update_fpscr(env, GETPC());
267     return t0;
268 }
269
270 void helper_fcmp_eq_FT(CPUSH4State *env, float32 t0, float32 t1)
271 {
272     int relation;
273
274     set_float_exception_flags(0, &env->fp_status);
275     relation = float32_compare(t0, t1, &env->fp_status);
276     if (unlikely(relation == float_relation_unordered)) {
277         update_fpscr(env, GETPC());
278     } else {
279         env->sr_t = (relation == float_relation_equal);
280     }
281 }
282
283 void helper_fcmp_eq_DT(CPUSH4State *env, float64 t0, float64 t1)
284 {
285     int relation;
286
287     set_float_exception_flags(0, &env->fp_status);
288     relation = float64_compare(t0, t1, &env->fp_status);
289     if (unlikely(relation == float_relation_unordered)) {
290         update_fpscr(env, GETPC());
291     } else {
292         env->sr_t = (relation == float_relation_equal);
293     }
294 }
295
296 void helper_fcmp_gt_FT(CPUSH4State *env, float32 t0, float32 t1)
297 {
298     int relation;
299
300     set_float_exception_flags(0, &env->fp_status);
301     relation = float32_compare(t0, t1, &env->fp_status);
302     if (unlikely(relation == float_relation_unordered)) {
303         update_fpscr(env, GETPC());
304     } else {
305         env->sr_t = (relation == float_relation_greater);
306     }
307 }
308
309 void helper_fcmp_gt_DT(CPUSH4State *env, float64 t0, float64 t1)
310 {
311     int relation;
312
313     set_float_exception_flags(0, &env->fp_status);
314     relation = float64_compare(t0, t1, &env->fp_status);
315     if (unlikely(relation == float_relation_unordered)) {
316         update_fpscr(env, GETPC());
317     } else {
318         env->sr_t = (relation == float_relation_greater);
319     }
320 }
321
322 float64 helper_fcnvsd_FT_DT(CPUSH4State *env, float32 t0)
323 {
324     float64 ret;
325     set_float_exception_flags(0, &env->fp_status);
326     ret = float32_to_float64(t0, &env->fp_status);
327     update_fpscr(env, GETPC());
328     return ret;
329 }
330
331 float32 helper_fcnvds_DT_FT(CPUSH4State *env, float64 t0)
332 {
333     float32 ret;
334     set_float_exception_flags(0, &env->fp_status);
335     ret = float64_to_float32(t0, &env->fp_status);
336     update_fpscr(env, GETPC());
337     return ret;
338 }
339
340 float32 helper_fdiv_FT(CPUSH4State *env, float32 t0, float32 t1)
341 {
342     set_float_exception_flags(0, &env->fp_status);
343     t0 = float32_div(t0, t1, &env->fp_status);
344     update_fpscr(env, GETPC());
345     return t0;
346 }
347
348 float64 helper_fdiv_DT(CPUSH4State *env, float64 t0, float64 t1)
349 {
350     set_float_exception_flags(0, &env->fp_status);
351     t0 = float64_div(t0, t1, &env->fp_status);
352     update_fpscr(env, GETPC());
353     return t0;
354 }
355
356 float32 helper_float_FT(CPUSH4State *env, uint32_t t0)
357 {
358     float32 ret;
359     set_float_exception_flags(0, &env->fp_status);
360     ret = int32_to_float32(t0, &env->fp_status);
361     update_fpscr(env, GETPC());
362     return ret;
363 }
364
365 float64 helper_float_DT(CPUSH4State *env, uint32_t t0)
366 {
367     float64 ret;
368     set_float_exception_flags(0, &env->fp_status);
369     ret = int32_to_float64(t0, &env->fp_status);
370     update_fpscr(env, GETPC());
371     return ret;
372 }
373
374 float32 helper_fmac_FT(CPUSH4State *env, float32 t0, float32 t1, float32 t2)
375 {
376     set_float_exception_flags(0, &env->fp_status);
377     t0 = float32_muladd(t0, t1, t2, 0, &env->fp_status);
378     update_fpscr(env, GETPC());
379     return t0;
380 }
381
382 float32 helper_fmul_FT(CPUSH4State *env, float32 t0, float32 t1)
383 {
384     set_float_exception_flags(0, &env->fp_status);
385     t0 = float32_mul(t0, t1, &env->fp_status);
386     update_fpscr(env, GETPC());
387     return t0;
388 }
389
390 float64 helper_fmul_DT(CPUSH4State *env, float64 t0, float64 t1)
391 {
392     set_float_exception_flags(0, &env->fp_status);
393     t0 = float64_mul(t0, t1, &env->fp_status);
394     update_fpscr(env, GETPC());
395     return t0;
396 }
397
398 float32 helper_fneg_T(float32 t0)
399 {
400     return float32_chs(t0);
401 }
402
403 float32 helper_fsqrt_FT(CPUSH4State *env, float32 t0)
404 {
405     set_float_exception_flags(0, &env->fp_status);
406     t0 = float32_sqrt(t0, &env->fp_status);
407     update_fpscr(env, GETPC());
408     return t0;
409 }
410
411 float64 helper_fsqrt_DT(CPUSH4State *env, float64 t0)
412 {
413     set_float_exception_flags(0, &env->fp_status);
414     t0 = float64_sqrt(t0, &env->fp_status);
415     update_fpscr(env, GETPC());
416     return t0;
417 }
418
419 float32 helper_fsub_FT(CPUSH4State *env, float32 t0, float32 t1)
420 {
421     set_float_exception_flags(0, &env->fp_status);
422     t0 = float32_sub(t0, t1, &env->fp_status);
423     update_fpscr(env, GETPC());
424     return t0;
425 }
426
427 float64 helper_fsub_DT(CPUSH4State *env, float64 t0, float64 t1)
428 {
429     set_float_exception_flags(0, &env->fp_status);
430     t0 = float64_sub(t0, t1, &env->fp_status);
431     update_fpscr(env, GETPC());
432     return t0;
433 }
434
435 uint32_t helper_ftrc_FT(CPUSH4State *env, float32 t0)
436 {
437     uint32_t ret;
438     set_float_exception_flags(0, &env->fp_status);
439     ret = float32_to_int32_round_to_zero(t0, &env->fp_status);
440     update_fpscr(env, GETPC());
441     return ret;
442 }
443
444 uint32_t helper_ftrc_DT(CPUSH4State *env, float64 t0)
445 {
446     uint32_t ret;
447     set_float_exception_flags(0, &env->fp_status);
448     ret = float64_to_int32_round_to_zero(t0, &env->fp_status);
449     update_fpscr(env, GETPC());
450     return ret;
451 }
452
453 void helper_fipr(CPUSH4State *env, uint32_t m, uint32_t n)
454 {
455     int bank, i;
456     float32 r, p;
457
458     bank = (env->sr & FPSCR_FR) ? 16 : 0;
459     r = float32_zero;
460     set_float_exception_flags(0, &env->fp_status);
461
462     for (i = 0 ; i < 4 ; i++) {
463         p = float32_mul(env->fregs[bank + m + i],
464                         env->fregs[bank + n + i],
465                         &env->fp_status);
466         r = float32_add(r, p, &env->fp_status);
467     }
468     update_fpscr(env, GETPC());
469
470     env->fregs[bank + n + 3] = r;
471 }
472
473 void helper_ftrv(CPUSH4State *env, uint32_t n)
474 {
475     int bank_matrix, bank_vector;
476     int i, j;
477     float32 r[4];
478     float32 p;
479
480     bank_matrix = (env->sr & FPSCR_FR) ? 0 : 16;
481     bank_vector = (env->sr & FPSCR_FR) ? 16 : 0;
482     set_float_exception_flags(0, &env->fp_status);
483     for (i = 0 ; i < 4 ; i++) {
484         r[i] = float32_zero;
485         for (j = 0 ; j < 4 ; j++) {
486             p = float32_mul(env->fregs[bank_matrix + 4 * j + i],
487                             env->fregs[bank_vector + j],
488                             &env->fp_status);
489             r[i] = float32_add(r[i], p, &env->fp_status);
490         }
491     }
492     update_fpscr(env, GETPC());
493
494     for (i = 0 ; i < 4 ; i++) {
495         env->fregs[bank_vector + i] = r[i];
496     }
497 }