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.1 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 "accel/tcg/cpu-ldst.h"
23 #include "fpu/softfloat.h"
24
25 #ifndef CONFIG_USER_ONLY
26
superh_cpu_do_unaligned_access(CPUState * cs,vaddr addr,MMUAccessType access_type,int mmu_idx,uintptr_t retaddr)27 void superh_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
28 MMUAccessType access_type,
29 int mmu_idx, uintptr_t retaddr)
30 {
31 cpu_env(cs)->tea = addr;
32 switch (access_type) {
33 case MMU_INST_FETCH:
34 case MMU_DATA_LOAD:
35 cs->exception_index = 0x0e0;
36 break;
37 case MMU_DATA_STORE:
38 cs->exception_index = 0x100;
39 break;
40 default:
41 g_assert_not_reached();
42 }
43 cpu_loop_exit_restore(cs, retaddr);
44 }
45
46 #endif
47
helper_ldtlb(CPUSH4State * env)48 void helper_ldtlb(CPUSH4State *env)
49 {
50 #ifdef CONFIG_USER_ONLY
51 cpu_abort(env_cpu(env), "Unhandled ldtlb");
52 #else
53 cpu_load_tlb(env);
54 #endif
55 }
56
57 static inline G_NORETURN
raise_exception(CPUSH4State * env,int index,uintptr_t retaddr)58 void raise_exception(CPUSH4State *env, int index,
59 uintptr_t retaddr)
60 {
61 CPUState *cs = env_cpu(env);
62
63 cs->exception_index = index;
64 cpu_loop_exit_restore(cs, retaddr);
65 }
66
helper_raise_illegal_instruction(CPUSH4State * env)67 void helper_raise_illegal_instruction(CPUSH4State *env)
68 {
69 raise_exception(env, 0x180, 0);
70 }
71
helper_raise_slot_illegal_instruction(CPUSH4State * env)72 void helper_raise_slot_illegal_instruction(CPUSH4State *env)
73 {
74 raise_exception(env, 0x1a0, 0);
75 }
76
helper_raise_fpu_disable(CPUSH4State * env)77 void helper_raise_fpu_disable(CPUSH4State *env)
78 {
79 raise_exception(env, 0x800, 0);
80 }
81
helper_raise_slot_fpu_disable(CPUSH4State * env)82 void helper_raise_slot_fpu_disable(CPUSH4State *env)
83 {
84 raise_exception(env, 0x820, 0);
85 }
86
helper_sleep(CPUSH4State * env)87 void helper_sleep(CPUSH4State *env)
88 {
89 CPUState *cs = env_cpu(env);
90
91 cs->halted = 1;
92 env->in_sleep = 1;
93 raise_exception(env, EXCP_HLT, 0);
94 }
95
helper_trapa(CPUSH4State * env,uint32_t tra)96 void helper_trapa(CPUSH4State *env, uint32_t tra)
97 {
98 env->tra = tra << 2;
99 raise_exception(env, 0x160, 0);
100 }
101
helper_exclusive(CPUSH4State * env)102 void helper_exclusive(CPUSH4State *env)
103 {
104 /* We do not want cpu_restore_state to run. */
105 cpu_loop_exit_atomic(env_cpu(env), 0);
106 }
107
helper_movcal(CPUSH4State * env,uint32_t address,uint32_t value)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
helper_discard_movcal_backup(CPUSH4State * env)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
helper_ocbi(CPUSH4State * env,uint32_t address)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
helper_macl(CPUSH4State * env,int32_t arg0,int32_t arg1)160 void helper_macl(CPUSH4State *env, int32_t arg0, int32_t arg1)
161 {
162 const int64_t min = -(1ll << 47);
163 const int64_t max = (1ll << 47) - 1;
164 int64_t mul = (int64_t)arg0 * arg1;
165 int64_t mac = env->mac;
166 int64_t res;
167
168 if (!(env->sr & (1u << SR_S))) {
169 res = mac + mul;
170 } else if (sadd64_overflow(mac, mul, &res)) {
171 res = mac < 0 ? min : max;
172 } else {
173 res = MIN(MAX(res, min), max);
174 }
175
176 env->mac = res;
177 }
178
helper_macw(CPUSH4State * env,int32_t arg0,int32_t arg1)179 void helper_macw(CPUSH4State *env, int32_t arg0, int32_t arg1)
180 {
181 /* Inputs are already sign-extended from 16 bits. */
182 int32_t mul = arg0 * arg1;
183
184 if (env->sr & (1u << SR_S)) {
185 /*
186 * In saturation arithmetic mode, the accumulator is 32-bit
187 * with carry. MACH is not considered during the addition
188 * operation nor the 32-bit saturation logic.
189 */
190 int32_t res, macl = env->macl;
191
192 if (sadd32_overflow(macl, mul, &res)) {
193 res = macl < 0 ? INT32_MIN : INT32_MAX;
194 /* If overflow occurs, the MACH register is set to 1. */
195 env->mach = 1;
196 }
197 env->macl = res;
198 } else {
199 /* In non-saturation arithmetic mode, the accumulator is 64-bit */
200 env->mac += mul;
201 }
202 }
203
helper_ld_fpscr(CPUSH4State * env,uint32_t val)204 void helper_ld_fpscr(CPUSH4State *env, uint32_t val)
205 {
206 env->fpscr = val & FPSCR_MASK;
207 if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) {
208 set_float_rounding_mode(float_round_to_zero, &env->fp_status);
209 } else {
210 set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
211 }
212 set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status);
213 }
214
update_fpscr(CPUSH4State * env,uintptr_t retaddr)215 static void update_fpscr(CPUSH4State *env, uintptr_t retaddr)
216 {
217 int xcpt, cause, enable;
218
219 xcpt = get_float_exception_flags(&env->fp_status);
220
221 /* Clear the cause entries */
222 env->fpscr &= ~FPSCR_CAUSE_MASK;
223
224 if (unlikely(xcpt)) {
225 if (xcpt & float_flag_invalid) {
226 env->fpscr |= FPSCR_CAUSE_V;
227 }
228 if (xcpt & float_flag_divbyzero) {
229 env->fpscr |= FPSCR_CAUSE_Z;
230 }
231 if (xcpt & float_flag_overflow) {
232 env->fpscr |= FPSCR_CAUSE_O;
233 }
234 if (xcpt & float_flag_underflow) {
235 env->fpscr |= FPSCR_CAUSE_U;
236 }
237 if (xcpt & float_flag_inexact) {
238 env->fpscr |= FPSCR_CAUSE_I;
239 }
240
241 /* Accumulate in flag entries */
242 env->fpscr |= (env->fpscr & FPSCR_CAUSE_MASK)
243 >> (FPSCR_CAUSE_SHIFT - FPSCR_FLAG_SHIFT);
244
245 /* Generate an exception if enabled */
246 cause = (env->fpscr & FPSCR_CAUSE_MASK) >> FPSCR_CAUSE_SHIFT;
247 enable = (env->fpscr & FPSCR_ENABLE_MASK) >> FPSCR_ENABLE_SHIFT;
248 if (cause & enable) {
249 raise_exception(env, 0x120, retaddr);
250 }
251 }
252 }
253
helper_fadd_FT(CPUSH4State * env,float32 t0,float32 t1)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
helper_fadd_DT(CPUSH4State * env,float64 t0,float64 t1)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
helper_fcmp_eq_FT(CPUSH4State * env,float32 t0,float32 t1)270 uint32_t 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 update_fpscr(env, GETPC());
277 return relation == float_relation_equal;
278 }
279
helper_fcmp_eq_DT(CPUSH4State * env,float64 t0,float64 t1)280 uint32_t helper_fcmp_eq_DT(CPUSH4State *env, float64 t0, float64 t1)
281 {
282 int relation;
283
284 set_float_exception_flags(0, &env->fp_status);
285 relation = float64_compare(t0, t1, &env->fp_status);
286 update_fpscr(env, GETPC());
287 return relation == float_relation_equal;
288 }
289
helper_fcmp_gt_FT(CPUSH4State * env,float32 t0,float32 t1)290 uint32_t helper_fcmp_gt_FT(CPUSH4State *env, float32 t0, float32 t1)
291 {
292 int relation;
293
294 set_float_exception_flags(0, &env->fp_status);
295 relation = float32_compare(t0, t1, &env->fp_status);
296 update_fpscr(env, GETPC());
297 return relation == float_relation_greater;
298 }
299
helper_fcmp_gt_DT(CPUSH4State * env,float64 t0,float64 t1)300 uint32_t helper_fcmp_gt_DT(CPUSH4State *env, float64 t0, float64 t1)
301 {
302 int relation;
303
304 set_float_exception_flags(0, &env->fp_status);
305 relation = float64_compare(t0, t1, &env->fp_status);
306 update_fpscr(env, GETPC());
307 return relation == float_relation_greater;
308 }
309
helper_fcnvsd_FT_DT(CPUSH4State * env,float32 t0)310 float64 helper_fcnvsd_FT_DT(CPUSH4State *env, float32 t0)
311 {
312 float64 ret;
313 set_float_exception_flags(0, &env->fp_status);
314 ret = float32_to_float64(t0, &env->fp_status);
315 update_fpscr(env, GETPC());
316 return ret;
317 }
318
helper_fcnvds_DT_FT(CPUSH4State * env,float64 t0)319 float32 helper_fcnvds_DT_FT(CPUSH4State *env, float64 t0)
320 {
321 float32 ret;
322 set_float_exception_flags(0, &env->fp_status);
323 ret = float64_to_float32(t0, &env->fp_status);
324 update_fpscr(env, GETPC());
325 return ret;
326 }
327
helper_fdiv_FT(CPUSH4State * env,float32 t0,float32 t1)328 float32 helper_fdiv_FT(CPUSH4State *env, float32 t0, float32 t1)
329 {
330 set_float_exception_flags(0, &env->fp_status);
331 t0 = float32_div(t0, t1, &env->fp_status);
332 update_fpscr(env, GETPC());
333 return t0;
334 }
335
helper_fdiv_DT(CPUSH4State * env,float64 t0,float64 t1)336 float64 helper_fdiv_DT(CPUSH4State *env, float64 t0, float64 t1)
337 {
338 set_float_exception_flags(0, &env->fp_status);
339 t0 = float64_div(t0, t1, &env->fp_status);
340 update_fpscr(env, GETPC());
341 return t0;
342 }
343
helper_float_FT(CPUSH4State * env,uint32_t t0)344 float32 helper_float_FT(CPUSH4State *env, uint32_t t0)
345 {
346 float32 ret;
347 set_float_exception_flags(0, &env->fp_status);
348 ret = int32_to_float32(t0, &env->fp_status);
349 update_fpscr(env, GETPC());
350 return ret;
351 }
352
helper_float_DT(CPUSH4State * env,uint32_t t0)353 float64 helper_float_DT(CPUSH4State *env, uint32_t t0)
354 {
355 float64 ret;
356 set_float_exception_flags(0, &env->fp_status);
357 ret = int32_to_float64(t0, &env->fp_status);
358 update_fpscr(env, GETPC());
359 return ret;
360 }
361
helper_fmac_FT(CPUSH4State * env,float32 t0,float32 t1,float32 t2)362 float32 helper_fmac_FT(CPUSH4State *env, float32 t0, float32 t1, float32 t2)
363 {
364 set_float_exception_flags(0, &env->fp_status);
365 t0 = float32_muladd(t0, t1, t2, 0, &env->fp_status);
366 update_fpscr(env, GETPC());
367 return t0;
368 }
369
helper_fmul_FT(CPUSH4State * env,float32 t0,float32 t1)370 float32 helper_fmul_FT(CPUSH4State *env, float32 t0, float32 t1)
371 {
372 set_float_exception_flags(0, &env->fp_status);
373 t0 = float32_mul(t0, t1, &env->fp_status);
374 update_fpscr(env, GETPC());
375 return t0;
376 }
377
helper_fmul_DT(CPUSH4State * env,float64 t0,float64 t1)378 float64 helper_fmul_DT(CPUSH4State *env, float64 t0, float64 t1)
379 {
380 set_float_exception_flags(0, &env->fp_status);
381 t0 = float64_mul(t0, t1, &env->fp_status);
382 update_fpscr(env, GETPC());
383 return t0;
384 }
385
helper_fsqrt_FT(CPUSH4State * env,float32 t0)386 float32 helper_fsqrt_FT(CPUSH4State *env, float32 t0)
387 {
388 set_float_exception_flags(0, &env->fp_status);
389 t0 = float32_sqrt(t0, &env->fp_status);
390 update_fpscr(env, GETPC());
391 return t0;
392 }
393
helper_fsqrt_DT(CPUSH4State * env,float64 t0)394 float64 helper_fsqrt_DT(CPUSH4State *env, float64 t0)
395 {
396 set_float_exception_flags(0, &env->fp_status);
397 t0 = float64_sqrt(t0, &env->fp_status);
398 update_fpscr(env, GETPC());
399 return t0;
400 }
401
helper_fsrra_FT(CPUSH4State * env,float32 t0)402 float32 helper_fsrra_FT(CPUSH4State *env, float32 t0)
403 {
404 set_float_exception_flags(0, &env->fp_status);
405 /* "Approximate" 1/sqrt(x) via actual computation. */
406 t0 = float32_sqrt(t0, &env->fp_status);
407 t0 = float32_div(float32_one, t0, &env->fp_status);
408 /*
409 * Since this is supposed to be an approximation, an imprecision
410 * exception is required. One supposes this also follows the usual
411 * IEEE rule that other exceptions take precedence.
412 */
413 if (get_float_exception_flags(&env->fp_status) == 0) {
414 set_float_exception_flags(float_flag_inexact, &env->fp_status);
415 }
416 update_fpscr(env, GETPC());
417 return t0;
418 }
419
helper_fsub_FT(CPUSH4State * env,float32 t0,float32 t1)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
helper_fsub_DT(CPUSH4State * env,float64 t0,float64 t1)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
helper_ftrc_FT(CPUSH4State * env,float32 t0)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
helper_ftrc_DT(CPUSH4State * env,float64 t0)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
helper_fipr(CPUSH4State * env,uint32_t m,uint32_t n)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
helper_ftrv(CPUSH4State * env,uint32_t n)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