]> git.proxmox.com Git - mirror_qemu.git/blob - target-sh4/op_helper.c
cpu: Turn cpu_handle_mmu_fault() into a CPUClass hook
[mirror_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 <assert.h>
20 #include <stdlib.h>
21 #include "cpu.h"
22 #include "helper.h"
23
24 #ifndef CONFIG_USER_ONLY
25 #include "exec/softmmu_exec.h"
26
27 #define MMUSUFFIX _mmu
28
29 #define SHIFT 0
30 #include "exec/softmmu_template.h"
31
32 #define SHIFT 1
33 #include "exec/softmmu_template.h"
34
35 #define SHIFT 2
36 #include "exec/softmmu_template.h"
37
38 #define SHIFT 3
39 #include "exec/softmmu_template.h"
40
41 void tlb_fill(CPUSH4State *env, target_ulong addr, int is_write, int mmu_idx,
42 uintptr_t retaddr)
43 {
44 SuperHCPU *cpu = sh_env_get_cpu(env);
45 int ret;
46
47 ret = superh_cpu_handle_mmu_fault(CPU(cpu), addr, is_write, mmu_idx);
48 if (ret) {
49 /* now we have a real cpu fault */
50 if (retaddr) {
51 cpu_restore_state(env, retaddr);
52 }
53 cpu_loop_exit(env);
54 }
55 }
56
57 #endif
58
59 void helper_ldtlb(CPUSH4State *env)
60 {
61 #ifdef CONFIG_USER_ONLY
62 /* XXXXX */
63 cpu_abort(env, "Unhandled ldtlb");
64 #else
65 cpu_load_tlb(env);
66 #endif
67 }
68
69 static inline void QEMU_NORETURN raise_exception(CPUSH4State *env, int index,
70 uintptr_t retaddr)
71 {
72 env->exception_index = index;
73 if (retaddr) {
74 cpu_restore_state(env, retaddr);
75 }
76 cpu_loop_exit(env);
77 }
78
79 void helper_raise_illegal_instruction(CPUSH4State *env)
80 {
81 raise_exception(env, 0x180, 0);
82 }
83
84 void helper_raise_slot_illegal_instruction(CPUSH4State *env)
85 {
86 raise_exception(env, 0x1a0, 0);
87 }
88
89 void helper_raise_fpu_disable(CPUSH4State *env)
90 {
91 raise_exception(env, 0x800, 0);
92 }
93
94 void helper_raise_slot_fpu_disable(CPUSH4State *env)
95 {
96 raise_exception(env, 0x820, 0);
97 }
98
99 void helper_debug(CPUSH4State *env)
100 {
101 raise_exception(env, EXCP_DEBUG, 0);
102 }
103
104 void helper_sleep(CPUSH4State *env)
105 {
106 CPUState *cs = CPU(sh_env_get_cpu(env));
107
108 cs->halted = 1;
109 env->in_sleep = 1;
110 raise_exception(env, EXCP_HLT, 0);
111 }
112
113 void helper_trapa(CPUSH4State *env, uint32_t tra)
114 {
115 env->tra = tra << 2;
116 raise_exception(env, 0x160, 0);
117 }
118
119 void helper_movcal(CPUSH4State *env, uint32_t address, uint32_t value)
120 {
121 if (cpu_sh4_is_cached (env, address))
122 {
123 memory_content *r = malloc (sizeof(memory_content));
124 r->address = address;
125 r->value = value;
126 r->next = NULL;
127
128 *(env->movcal_backup_tail) = r;
129 env->movcal_backup_tail = &(r->next);
130 }
131 }
132
133 void helper_discard_movcal_backup(CPUSH4State *env)
134 {
135 memory_content *current = env->movcal_backup;
136
137 while(current)
138 {
139 memory_content *next = current->next;
140 free (current);
141 env->movcal_backup = current = next;
142 if (current == NULL)
143 env->movcal_backup_tail = &(env->movcal_backup);
144 }
145 }
146
147 void helper_ocbi(CPUSH4State *env, uint32_t address)
148 {
149 memory_content **current = &(env->movcal_backup);
150 while (*current)
151 {
152 uint32_t a = (*current)->address;
153 if ((a & ~0x1F) == (address & ~0x1F))
154 {
155 memory_content *next = (*current)->next;
156 cpu_stl_data(env, a, (*current)->value);
157
158 if (next == NULL)
159 {
160 env->movcal_backup_tail = current;
161 }
162
163 free (*current);
164 *current = next;
165 break;
166 }
167 }
168 }
169
170 #define T (env->sr & SR_T)
171 #define Q (env->sr & SR_Q ? 1 : 0)
172 #define M (env->sr & SR_M ? 1 : 0)
173 #define SETT env->sr |= SR_T
174 #define CLRT env->sr &= ~SR_T
175 #define SETQ env->sr |= SR_Q
176 #define CLRQ env->sr &= ~SR_Q
177 #define SETM env->sr |= SR_M
178 #define CLRM env->sr &= ~SR_M
179
180 uint32_t helper_div1(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
181 {
182 uint32_t tmp0, tmp2;
183 uint8_t old_q, tmp1 = 0xff;
184
185 //printf("div1 arg0=0x%08x arg1=0x%08x M=%d Q=%d T=%d\n", arg0, arg1, M, Q, T);
186 old_q = Q;
187 if ((0x80000000 & arg1) != 0)
188 SETQ;
189 else
190 CLRQ;
191 tmp2 = arg0;
192 arg1 <<= 1;
193 arg1 |= T;
194 switch (old_q) {
195 case 0:
196 switch (M) {
197 case 0:
198 tmp0 = arg1;
199 arg1 -= tmp2;
200 tmp1 = arg1 > tmp0;
201 switch (Q) {
202 case 0:
203 if (tmp1)
204 SETQ;
205 else
206 CLRQ;
207 break;
208 case 1:
209 if (tmp1 == 0)
210 SETQ;
211 else
212 CLRQ;
213 break;
214 }
215 break;
216 case 1:
217 tmp0 = arg1;
218 arg1 += tmp2;
219 tmp1 = arg1 < tmp0;
220 switch (Q) {
221 case 0:
222 if (tmp1 == 0)
223 SETQ;
224 else
225 CLRQ;
226 break;
227 case 1:
228 if (tmp1)
229 SETQ;
230 else
231 CLRQ;
232 break;
233 }
234 break;
235 }
236 break;
237 case 1:
238 switch (M) {
239 case 0:
240 tmp0 = arg1;
241 arg1 += tmp2;
242 tmp1 = arg1 < tmp0;
243 switch (Q) {
244 case 0:
245 if (tmp1)
246 SETQ;
247 else
248 CLRQ;
249 break;
250 case 1:
251 if (tmp1 == 0)
252 SETQ;
253 else
254 CLRQ;
255 break;
256 }
257 break;
258 case 1:
259 tmp0 = arg1;
260 arg1 -= tmp2;
261 tmp1 = arg1 > tmp0;
262 switch (Q) {
263 case 0:
264 if (tmp1 == 0)
265 SETQ;
266 else
267 CLRQ;
268 break;
269 case 1:
270 if (tmp1)
271 SETQ;
272 else
273 CLRQ;
274 break;
275 }
276 break;
277 }
278 break;
279 }
280 if (Q == M)
281 SETT;
282 else
283 CLRT;
284 //printf("Output: arg1=0x%08x M=%d Q=%d T=%d\n", arg1, M, Q, T);
285 return arg1;
286 }
287
288 void helper_macl(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
289 {
290 int64_t res;
291
292 res = ((uint64_t) env->mach << 32) | env->macl;
293 res += (int64_t) (int32_t) arg0 *(int64_t) (int32_t) arg1;
294 env->mach = (res >> 32) & 0xffffffff;
295 env->macl = res & 0xffffffff;
296 if (env->sr & SR_S) {
297 if (res < 0)
298 env->mach |= 0xffff0000;
299 else
300 env->mach &= 0x00007fff;
301 }
302 }
303
304 void helper_macw(CPUSH4State *env, uint32_t arg0, uint32_t arg1)
305 {
306 int64_t res;
307
308 res = ((uint64_t) env->mach << 32) | env->macl;
309 res += (int64_t) (int16_t) arg0 *(int64_t) (int16_t) arg1;
310 env->mach = (res >> 32) & 0xffffffff;
311 env->macl = res & 0xffffffff;
312 if (env->sr & SR_S) {
313 if (res < -0x80000000) {
314 env->mach = 1;
315 env->macl = 0x80000000;
316 } else if (res > 0x000000007fffffff) {
317 env->mach = 1;
318 env->macl = 0x7fffffff;
319 }
320 }
321 }
322
323 static inline void set_t(CPUSH4State *env)
324 {
325 env->sr |= SR_T;
326 }
327
328 static inline void clr_t(CPUSH4State *env)
329 {
330 env->sr &= ~SR_T;
331 }
332
333 void helper_ld_fpscr(CPUSH4State *env, uint32_t val)
334 {
335 env->fpscr = val & FPSCR_MASK;
336 if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) {
337 set_float_rounding_mode(float_round_to_zero, &env->fp_status);
338 } else {
339 set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
340 }
341 set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status);
342 }
343
344 static void update_fpscr(CPUSH4State *env, uintptr_t retaddr)
345 {
346 int xcpt, cause, enable;
347
348 xcpt = get_float_exception_flags(&env->fp_status);
349
350 /* Clear the flag entries */
351 env->fpscr &= ~FPSCR_FLAG_MASK;
352
353 if (unlikely(xcpt)) {
354 if (xcpt & float_flag_invalid) {
355 env->fpscr |= FPSCR_FLAG_V;
356 }
357 if (xcpt & float_flag_divbyzero) {
358 env->fpscr |= FPSCR_FLAG_Z;
359 }
360 if (xcpt & float_flag_overflow) {
361 env->fpscr |= FPSCR_FLAG_O;
362 }
363 if (xcpt & float_flag_underflow) {
364 env->fpscr |= FPSCR_FLAG_U;
365 }
366 if (xcpt & float_flag_inexact) {
367 env->fpscr |= FPSCR_FLAG_I;
368 }
369
370 /* Accumulate in cause entries */
371 env->fpscr |= (env->fpscr & FPSCR_FLAG_MASK)
372 << (FPSCR_CAUSE_SHIFT - FPSCR_FLAG_SHIFT);
373
374 /* Generate an exception if enabled */
375 cause = (env->fpscr & FPSCR_CAUSE_MASK) >> FPSCR_CAUSE_SHIFT;
376 enable = (env->fpscr & FPSCR_ENABLE_MASK) >> FPSCR_ENABLE_SHIFT;
377 if (cause & enable) {
378 raise_exception(env, 0x120, retaddr);
379 }
380 }
381 }
382
383 float32 helper_fabs_FT(float32 t0)
384 {
385 return float32_abs(t0);
386 }
387
388 float64 helper_fabs_DT(float64 t0)
389 {
390 return float64_abs(t0);
391 }
392
393 float32 helper_fadd_FT(CPUSH4State *env, float32 t0, float32 t1)
394 {
395 set_float_exception_flags(0, &env->fp_status);
396 t0 = float32_add(t0, t1, &env->fp_status);
397 update_fpscr(env, GETPC());
398 return t0;
399 }
400
401 float64 helper_fadd_DT(CPUSH4State *env, float64 t0, float64 t1)
402 {
403 set_float_exception_flags(0, &env->fp_status);
404 t0 = float64_add(t0, t1, &env->fp_status);
405 update_fpscr(env, GETPC());
406 return t0;
407 }
408
409 void helper_fcmp_eq_FT(CPUSH4State *env, float32 t0, float32 t1)
410 {
411 int relation;
412
413 set_float_exception_flags(0, &env->fp_status);
414 relation = float32_compare(t0, t1, &env->fp_status);
415 if (unlikely(relation == float_relation_unordered)) {
416 update_fpscr(env, GETPC());
417 } else if (relation == float_relation_equal) {
418 set_t(env);
419 } else {
420 clr_t(env);
421 }
422 }
423
424 void helper_fcmp_eq_DT(CPUSH4State *env, float64 t0, float64 t1)
425 {
426 int relation;
427
428 set_float_exception_flags(0, &env->fp_status);
429 relation = float64_compare(t0, t1, &env->fp_status);
430 if (unlikely(relation == float_relation_unordered)) {
431 update_fpscr(env, GETPC());
432 } else if (relation == float_relation_equal) {
433 set_t(env);
434 } else {
435 clr_t(env);
436 }
437 }
438
439 void helper_fcmp_gt_FT(CPUSH4State *env, float32 t0, float32 t1)
440 {
441 int relation;
442
443 set_float_exception_flags(0, &env->fp_status);
444 relation = float32_compare(t0, t1, &env->fp_status);
445 if (unlikely(relation == float_relation_unordered)) {
446 update_fpscr(env, GETPC());
447 } else if (relation == float_relation_greater) {
448 set_t(env);
449 } else {
450 clr_t(env);
451 }
452 }
453
454 void helper_fcmp_gt_DT(CPUSH4State *env, float64 t0, float64 t1)
455 {
456 int relation;
457
458 set_float_exception_flags(0, &env->fp_status);
459 relation = float64_compare(t0, t1, &env->fp_status);
460 if (unlikely(relation == float_relation_unordered)) {
461 update_fpscr(env, GETPC());
462 } else if (relation == float_relation_greater) {
463 set_t(env);
464 } else {
465 clr_t(env);
466 }
467 }
468
469 float64 helper_fcnvsd_FT_DT(CPUSH4State *env, float32 t0)
470 {
471 float64 ret;
472 set_float_exception_flags(0, &env->fp_status);
473 ret = float32_to_float64(t0, &env->fp_status);
474 update_fpscr(env, GETPC());
475 return ret;
476 }
477
478 float32 helper_fcnvds_DT_FT(CPUSH4State *env, float64 t0)
479 {
480 float32 ret;
481 set_float_exception_flags(0, &env->fp_status);
482 ret = float64_to_float32(t0, &env->fp_status);
483 update_fpscr(env, GETPC());
484 return ret;
485 }
486
487 float32 helper_fdiv_FT(CPUSH4State *env, float32 t0, float32 t1)
488 {
489 set_float_exception_flags(0, &env->fp_status);
490 t0 = float32_div(t0, t1, &env->fp_status);
491 update_fpscr(env, GETPC());
492 return t0;
493 }
494
495 float64 helper_fdiv_DT(CPUSH4State *env, float64 t0, float64 t1)
496 {
497 set_float_exception_flags(0, &env->fp_status);
498 t0 = float64_div(t0, t1, &env->fp_status);
499 update_fpscr(env, GETPC());
500 return t0;
501 }
502
503 float32 helper_float_FT(CPUSH4State *env, uint32_t t0)
504 {
505 float32 ret;
506 set_float_exception_flags(0, &env->fp_status);
507 ret = int32_to_float32(t0, &env->fp_status);
508 update_fpscr(env, GETPC());
509 return ret;
510 }
511
512 float64 helper_float_DT(CPUSH4State *env, uint32_t t0)
513 {
514 float64 ret;
515 set_float_exception_flags(0, &env->fp_status);
516 ret = int32_to_float64(t0, &env->fp_status);
517 update_fpscr(env, GETPC());
518 return ret;
519 }
520
521 float32 helper_fmac_FT(CPUSH4State *env, float32 t0, float32 t1, float32 t2)
522 {
523 set_float_exception_flags(0, &env->fp_status);
524 t0 = float32_muladd(t0, t1, t2, 0, &env->fp_status);
525 update_fpscr(env, GETPC());
526 return t0;
527 }
528
529 float32 helper_fmul_FT(CPUSH4State *env, float32 t0, float32 t1)
530 {
531 set_float_exception_flags(0, &env->fp_status);
532 t0 = float32_mul(t0, t1, &env->fp_status);
533 update_fpscr(env, GETPC());
534 return t0;
535 }
536
537 float64 helper_fmul_DT(CPUSH4State *env, float64 t0, float64 t1)
538 {
539 set_float_exception_flags(0, &env->fp_status);
540 t0 = float64_mul(t0, t1, &env->fp_status);
541 update_fpscr(env, GETPC());
542 return t0;
543 }
544
545 float32 helper_fneg_T(float32 t0)
546 {
547 return float32_chs(t0);
548 }
549
550 float32 helper_fsqrt_FT(CPUSH4State *env, float32 t0)
551 {
552 set_float_exception_flags(0, &env->fp_status);
553 t0 = float32_sqrt(t0, &env->fp_status);
554 update_fpscr(env, GETPC());
555 return t0;
556 }
557
558 float64 helper_fsqrt_DT(CPUSH4State *env, float64 t0)
559 {
560 set_float_exception_flags(0, &env->fp_status);
561 t0 = float64_sqrt(t0, &env->fp_status);
562 update_fpscr(env, GETPC());
563 return t0;
564 }
565
566 float32 helper_fsub_FT(CPUSH4State *env, float32 t0, float32 t1)
567 {
568 set_float_exception_flags(0, &env->fp_status);
569 t0 = float32_sub(t0, t1, &env->fp_status);
570 update_fpscr(env, GETPC());
571 return t0;
572 }
573
574 float64 helper_fsub_DT(CPUSH4State *env, float64 t0, float64 t1)
575 {
576 set_float_exception_flags(0, &env->fp_status);
577 t0 = float64_sub(t0, t1, &env->fp_status);
578 update_fpscr(env, GETPC());
579 return t0;
580 }
581
582 uint32_t helper_ftrc_FT(CPUSH4State *env, float32 t0)
583 {
584 uint32_t ret;
585 set_float_exception_flags(0, &env->fp_status);
586 ret = float32_to_int32_round_to_zero(t0, &env->fp_status);
587 update_fpscr(env, GETPC());
588 return ret;
589 }
590
591 uint32_t helper_ftrc_DT(CPUSH4State *env, float64 t0)
592 {
593 uint32_t ret;
594 set_float_exception_flags(0, &env->fp_status);
595 ret = float64_to_int32_round_to_zero(t0, &env->fp_status);
596 update_fpscr(env, GETPC());
597 return ret;
598 }
599
600 void helper_fipr(CPUSH4State *env, uint32_t m, uint32_t n)
601 {
602 int bank, i;
603 float32 r, p;
604
605 bank = (env->sr & FPSCR_FR) ? 16 : 0;
606 r = float32_zero;
607 set_float_exception_flags(0, &env->fp_status);
608
609 for (i = 0 ; i < 4 ; i++) {
610 p = float32_mul(env->fregs[bank + m + i],
611 env->fregs[bank + n + i],
612 &env->fp_status);
613 r = float32_add(r, p, &env->fp_status);
614 }
615 update_fpscr(env, GETPC());
616
617 env->fregs[bank + n + 3] = r;
618 }
619
620 void helper_ftrv(CPUSH4State *env, uint32_t n)
621 {
622 int bank_matrix, bank_vector;
623 int i, j;
624 float32 r[4];
625 float32 p;
626
627 bank_matrix = (env->sr & FPSCR_FR) ? 0 : 16;
628 bank_vector = (env->sr & FPSCR_FR) ? 16 : 0;
629 set_float_exception_flags(0, &env->fp_status);
630 for (i = 0 ; i < 4 ; i++) {
631 r[i] = float32_zero;
632 for (j = 0 ; j < 4 ; j++) {
633 p = float32_mul(env->fregs[bank_matrix + 4 * j + i],
634 env->fregs[bank_vector + j],
635 &env->fp_status);
636 r[i] = float32_add(r[i], p, &env->fp_status);
637 }
638 }
639 update_fpscr(env, GETPC());
640
641 for (i = 0 ; i < 4 ; i++) {
642 env->fregs[bank_vector + i] = r[i];
643 }
644 }