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