xref: /qemu/target/sh4/op_helper.c (revision c3e31eaa)
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 }
499