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