]>
git.proxmox.com Git - mirror_qemu.git/blob - target-sparc/op_helper.c
5 void raise_exception(int tt
)
7 env
->exception_index
= tt
;
11 #ifdef USE_INT_TO_FLOAT_HELPERS
14 FT0
= (float) *((int32_t *)&FT1
);
19 DT0
= (double) *((int32_t *)&FT1
);
25 FT0
= float32_abs(FT1
);
31 DT0
= float64_abs(DT1
);
37 FT0
= float32_sqrt(FT1
, &env
->fp_status
);
42 DT0
= float64_sqrt(DT1
, &env
->fp_status
);
48 env
->fsr
&= ~((FSR_FCC1
| FSR_FCC0
) << FS
);
49 if (isnan(FT0
) || isnan(FT1
)) {
50 T0
= (FSR_FCC1
| FSR_FCC0
) << FS
;
51 if (env
->fsr
& FSR_NVM
) {
53 raise_exception(TT_FP_EXCP
);
57 } else if (FT0
< FT1
) {
59 } else if (FT0
> FT1
) {
69 env
->fsr
&= ~((FSR_FCC1
| FSR_FCC0
) << FS
);
70 if (isnan(DT0
) || isnan(DT1
)) {
71 T0
= (FSR_FCC1
| FSR_FCC0
) << FS
;
72 if (env
->fsr
& FSR_NVM
) {
74 raise_exception(TT_FP_EXCP
);
78 } else if (DT0
< DT1
) {
80 } else if (DT0
> DT1
) {
91 void do_fcmps_fcc1 (void)
93 env
->fsr
&= ~((FSR_FCC1
| FSR_FCC0
) << FS
);
94 if (isnan(FT0
) || isnan(FT1
)) {
95 T0
= (FSR_FCC1
| FSR_FCC0
) << FS
;
96 if (env
->fsr
& FSR_NVM
) {
98 raise_exception(TT_FP_EXCP
);
102 } else if (FT0
< FT1
) {
104 } else if (FT0
> FT1
) {
112 void do_fcmpd_fcc1 (void)
114 env
->fsr
&= ~((FSR_FCC1
| FSR_FCC0
) << FS
);
115 if (isnan(DT0
) || isnan(DT1
)) {
116 T0
= (FSR_FCC1
| FSR_FCC0
) << FS
;
117 if (env
->fsr
& FSR_NVM
) {
119 raise_exception(TT_FP_EXCP
);
123 } else if (DT0
< DT1
) {
125 } else if (DT0
> DT1
) {
135 void do_fcmps_fcc2 (void)
137 env
->fsr
&= ~((FSR_FCC1
| FSR_FCC0
) << FS
);
138 if (isnan(FT0
) || isnan(FT1
)) {
139 T0
= (FSR_FCC1
| FSR_FCC0
) << FS
;
140 if (env
->fsr
& FSR_NVM
) {
142 raise_exception(TT_FP_EXCP
);
146 } else if (FT0
< FT1
) {
148 } else if (FT0
> FT1
) {
156 void do_fcmpd_fcc2 (void)
158 env
->fsr
&= ~((FSR_FCC1
| FSR_FCC0
) << FS
);
159 if (isnan(DT0
) || isnan(DT1
)) {
160 T0
= (FSR_FCC1
| FSR_FCC0
) << FS
;
161 if (env
->fsr
& FSR_NVM
) {
163 raise_exception(TT_FP_EXCP
);
167 } else if (DT0
< DT1
) {
169 } else if (DT0
> DT1
) {
179 void do_fcmps_fcc3 (void)
181 env
->fsr
&= ~((FSR_FCC1
| FSR_FCC0
) << FS
);
182 if (isnan(FT0
) || isnan(FT1
)) {
183 T0
= (FSR_FCC1
| FSR_FCC0
) << FS
;
184 if (env
->fsr
& FSR_NVM
) {
186 raise_exception(TT_FP_EXCP
);
190 } else if (FT0
< FT1
) {
192 } else if (FT0
> FT1
) {
200 void do_fcmpd_fcc3 (void)
202 env
->fsr
&= ~((FSR_FCC1
| FSR_FCC0
) << FS
);
203 if (isnan(DT0
) || isnan(DT1
)) {
204 T0
= (FSR_FCC1
| FSR_FCC0
) << FS
;
205 if (env
->fsr
& FSR_NVM
) {
207 raise_exception(TT_FP_EXCP
);
211 } else if (DT0
< DT1
) {
213 } else if (DT0
> DT1
) {
223 #ifndef TARGET_SPARC64
224 void helper_ld_asi(int asi
, int size
, int sign
)
229 case 3: /* MMU probe */
233 mmulev
= (T0
>> 8) & 15;
237 ret
= mmu_probe(env
, T0
, mmulev
);
241 printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0
, mmulev
, ret
);
245 case 4: /* read MMU regs */
247 int reg
= (T0
>> 8) & 0xf;
249 ret
= env
->mmuregs
[reg
];
250 if (reg
== 3) /* Fault status cleared on read */
251 env
->mmuregs
[reg
] = 0;
253 printf("mmu_read: reg[%d] = 0x%08x\n", reg
, ret
);
257 case 0x20 ... 0x2f: /* MMU passthrough */
258 cpu_physical_memory_read(T0
, (void *) &ret
, size
);
262 tswap16s((uint16_t *)&ret
);
271 void helper_st_asi(int asi
, int size
, int sign
)
274 case 3: /* MMU flush */
278 mmulev
= (T0
>> 8) & 15;
280 printf("mmu flush level %d\n", mmulev
);
283 case 0: // flush page
284 tlb_flush_page(env
, T0
& 0xfffff000);
286 case 1: // flush segment (256k)
287 case 2: // flush region (16M)
288 case 3: // flush context (4G)
289 case 4: // flush entire
300 case 4: /* write MMU regs */
302 int reg
= (T0
>> 8) & 0xf, oldreg
;
304 oldreg
= env
->mmuregs
[reg
];
307 env
->mmuregs
[reg
] &= ~(MMU_E
| MMU_NF
);
308 env
->mmuregs
[reg
] |= T1
& (MMU_E
| MMU_NF
);
309 // Mappings generated during no-fault mode or MMU
310 // disabled mode are invalid in normal mode
311 if (oldreg
!= env
->mmuregs
[reg
])
315 env
->mmuregs
[reg
] = T1
;
316 if (oldreg
!= env
->mmuregs
[reg
]) {
317 /* we flush when the MMU context changes because
318 QEMU has no MMU context support */
326 env
->mmuregs
[reg
] = T1
;
330 if (oldreg
!= env
->mmuregs
[reg
]) {
331 printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg
, oldreg
, env
->mmuregs
[reg
]);
337 case 0x17: /* Block copy, sta access */
340 // address (T0) = dst
342 int src
= T1
, dst
= T0
;
347 cpu_physical_memory_read(src
, (void *) &temp
, 32);
348 cpu_physical_memory_write(dst
, (void *) &temp
, 32);
351 case 0x1f: /* Block fill, stda access */
354 // address (T0) = dst
359 val
= (((uint64_t)T1
) << 32) | T2
;
362 for (i
= 0; i
< 32; i
+= 8, dst
+= 8) {
363 cpu_physical_memory_write(dst
, (void *) &val
, 8);
367 case 0x20 ... 0x2f: /* MMU passthrough */
373 tswap16s((uint16_t *)&temp
);
374 cpu_physical_memory_write(T0
, (void *) &temp
, size
);
384 void helper_ld_asi(int asi
, int size
, int sign
)
388 if (asi
< 0x80 && (env
->pstate
& PS_PRIV
) == 0)
389 raise_exception(TT_PRIV_INSN
);
393 case 0x15: // Bypass, non-cacheable
395 cpu_physical_memory_read(T0
, (void *) &ret
, size
);
399 tswap32s((uint32_t *)&ret
);
401 tswap16s((uint16_t *)&ret
);
404 case 0x1c: // Bypass LE
405 case 0x1d: // Bypass, non-cacheable LE
411 case 0x50: // I-MMU regs
413 int reg
= (T0
>> 3) & 0xf;
415 ret
= env
->immuregs
[reg
];
418 case 0x51: // I-MMU 8k TSB pointer
419 case 0x52: // I-MMU 64k TSB pointer
420 case 0x55: // I-MMU data access
421 case 0x56: // I-MMU tag read
423 case 0x58: // D-MMU regs
425 int reg
= (T0
>> 3) & 0xf;
427 ret
= env
->dmmuregs
[reg
];
430 case 0x59: // D-MMU 8k TSB pointer
431 case 0x5a: // D-MMU 64k TSB pointer
432 case 0x5b: // D-MMU data pointer
433 case 0x5d: // D-MMU data access
434 case 0x5e: // D-MMU tag read
436 case 0x54: // I-MMU data in, WO
437 case 0x57: // I-MMU demap, WO
438 case 0x5c: // D-MMU data in, WO
439 case 0x5f: // D-MMU demap, WO
447 void helper_st_asi(int asi
, int size
, int sign
)
449 if (asi
< 0x80 && (env
->pstate
& PS_PRIV
) == 0)
450 raise_exception(TT_PRIV_INSN
);
454 case 0x15: // Bypass, non-cacheable
456 target_ulong temp
= T1
;
460 tswap32s((uint32_t *)&temp
);
462 tswap16s((uint16_t *)&temp
);
463 cpu_physical_memory_write(T0
, (void *) &temp
, size
);
466 case 0x1c: // Bypass LE
467 case 0x1d: // Bypass, non-cacheable LE
475 env
->lsu
= T1
& (DMMU_E
| IMMU_E
);
476 // Mappings generated during D/I MMU disabled mode are
477 // invalid in normal mode
478 if (oldreg
!= env
->lsu
)
482 case 0x50: // I-MMU regs
484 int reg
= (T0
>> 3) & 0xf;
487 oldreg
= env
->immuregs
[reg
];
492 case 1: // Not in I-MMU
499 T1
= 0; // Clear SFSR
501 case 5: // TSB access
502 case 6: // Tag access
506 env
->immuregs
[reg
] = T1
;
508 if (oldreg
!= env
->immuregs
[reg
]) {
509 printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg
, oldreg
, env
->immuregs
[reg
]);
515 case 0x54: // I-MMU data in
519 // Try finding an invalid entry
520 for (i
= 0; i
< 64; i
++) {
521 if ((env
->itlb_tte
[i
] & 0x8000000000000000ULL
) == 0) {
522 env
->itlb_tag
[i
] = env
->immuregs
[6];
523 env
->itlb_tte
[i
] = T1
;
527 // Try finding an unlocked entry
528 for (i
= 0; i
< 64; i
++) {
529 if ((env
->itlb_tte
[i
] & 0x40) == 0) {
530 env
->itlb_tag
[i
] = env
->immuregs
[6];
531 env
->itlb_tte
[i
] = T1
;
538 case 0x55: // I-MMU data access
540 unsigned int i
= (T0
>> 3) & 0x3f;
542 env
->itlb_tag
[i
] = env
->immuregs
[6];
543 env
->itlb_tte
[i
] = T1
;
546 case 0x57: // I-MMU demap
548 case 0x58: // D-MMU regs
550 int reg
= (T0
>> 3) & 0xf;
553 oldreg
= env
->dmmuregs
[reg
];
560 T1
= 0; // Clear SFSR, Fault address
561 env
->dmmuregs
[4] = 0;
563 env
->dmmuregs
[reg
] = T1
;
565 case 1: // Primary context
566 case 2: // Secondary context
567 case 5: // TSB access
568 case 6: // Tag access
569 case 7: // Virtual Watchpoint
570 case 8: // Physical Watchpoint
574 env
->dmmuregs
[reg
] = T1
;
576 if (oldreg
!= env
->dmmuregs
[reg
]) {
577 printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg
, oldreg
, env
->dmmuregs
[reg
]);
583 case 0x5c: // D-MMU data in
587 // Try finding an invalid entry
588 for (i
= 0; i
< 64; i
++) {
589 if ((env
->dtlb_tte
[i
] & 0x8000000000000000ULL
) == 0) {
590 env
->dtlb_tag
[i
] = env
->dmmuregs
[6];
591 env
->dtlb_tte
[i
] = T1
;
595 // Try finding an unlocked entry
596 for (i
= 0; i
< 64; i
++) {
597 if ((env
->dtlb_tte
[i
] & 0x40) == 0) {
598 env
->dtlb_tag
[i
] = env
->dmmuregs
[6];
599 env
->dtlb_tte
[i
] = T1
;
606 case 0x5d: // D-MMU data access
608 unsigned int i
= (T0
>> 3) & 0x3f;
610 env
->dtlb_tag
[i
] = env
->dmmuregs
[6];
611 env
->dtlb_tte
[i
] = T1
;
614 case 0x5f: // D-MMU demap
616 case 0x51: // I-MMU 8k TSB pointer, RO
617 case 0x52: // I-MMU 64k TSB pointer, RO
618 case 0x56: // I-MMU tag read, RO
619 case 0x59: // D-MMU 8k TSB pointer, RO
620 case 0x5a: // D-MMU 64k TSB pointer, RO
621 case 0x5b: // D-MMU data pointer, RO
622 case 0x5e: // D-MMU tag read, RO
630 #ifndef TARGET_SPARC64
636 cwp
= (env
->cwp
+ 1) & (NWINDOWS
- 1);
637 if (env
->wim
& (1 << cwp
)) {
638 raise_exception(TT_WIN_UNF
);
641 env
->psrs
= env
->psrps
;
645 void helper_ldfsr(void)
648 switch (env
->fsr
& FSR_RD_MASK
) {
650 rnd_mode
= float_round_nearest_even
;
654 rnd_mode
= float_round_to_zero
;
657 rnd_mode
= float_round_up
;
660 rnd_mode
= float_round_down
;
663 set_float_rounding_mode(rnd_mode
, &env
->fp_status
);
666 void cpu_get_fp64(uint64_t *pmant
, uint16_t *pexp
, double f
)
670 *pmant
= ldexp(frexp(f
, &exptemp
), 53);
674 double cpu_put_fp64(uint64_t mant
, uint16_t exp
)
676 return ldexp((double) mant
, exp
- 53);
681 env
->exception_index
= EXCP_DEBUG
;
685 #ifndef TARGET_SPARC64
700 T0
= (T1
& 0x5555555555555555ULL
) + ((T1
>> 1) & 0x5555555555555555ULL
);
701 T0
= (T0
& 0x3333333333333333ULL
) + ((T0
>> 2) & 0x3333333333333333ULL
);
702 T0
= (T0
& 0x0f0f0f0f0f0f0f0fULL
) + ((T0
>> 4) & 0x0f0f0f0f0f0f0f0fULL
);
703 T0
= (T0
& 0x00ff00ff00ff00ffULL
) + ((T0
>> 8) & 0x00ff00ff00ff00ffULL
);
704 T0
= (T0
& 0x0000ffff0000ffffULL
) + ((T0
>> 16) & 0x0000ffff0000ffffULL
);
705 T0
= (T0
& 0x00000000ffffffffULL
) + ((T0
>> 32) & 0x00000000ffffffffULL
);
709 void set_cwp(int new_cwp
)
711 /* put the modified wrap registers at their proper location */
712 if (env
->cwp
== (NWINDOWS
- 1))
713 memcpy32(env
->regbase
, env
->regbase
+ NWINDOWS
* 16);
715 /* put the wrap registers at their temporary location */
716 if (new_cwp
== (NWINDOWS
- 1))
717 memcpy32(env
->regbase
+ NWINDOWS
* 16, env
->regbase
);
718 env
->regwptr
= env
->regbase
+ (new_cwp
* 16);
719 REGWPTR
= env
->regwptr
;
722 void cpu_set_cwp(CPUState
*env1
, int new_cwp
)
726 target_ulong
*saved_regwptr
;
731 saved_regwptr
= REGWPTR
;
737 REGWPTR
= saved_regwptr
;
741 #ifdef TARGET_SPARC64
742 void do_interrupt(int intno
)
745 if (loglevel
& CPU_LOG_INT
) {
747 fprintf(logfile
, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n",
750 env
->npc
, env
->regwptr
[6]);
751 cpu_dump_state(env
, logfile
, fprintf
, 0);
757 fprintf(logfile
, " code=");
758 ptr
= (uint8_t *)env
->pc
;
759 for(i
= 0; i
< 16; i
++) {
760 fprintf(logfile
, " %02x", ldub(ptr
+ i
));
762 fprintf(logfile
, "\n");
768 #if !defined(CONFIG_USER_ONLY)
769 if (env
->pstate
& PS_IE
) {
770 cpu_abort(cpu_single_env
, "Trap 0x%02x while interrupts disabled, Error state", env
->exception_index
);
774 env
->tstate
[env
->tl
] = ((uint64_t)GET_CCR(env
) << 32) | ((env
->asi
& 0xff) << 24) |
775 ((env
->pstate
& 0xfff) << 8) | (env
->cwp
& 0xff);
776 env
->tpc
[env
->tl
] = env
->pc
;
777 env
->tnpc
[env
->tl
] = env
->npc
;
778 env
->tt
[env
->tl
] = intno
;
779 env
->tbr
= env
->tbr
| (env
->tl
> 1) ? 1 << 14 : 0 | (intno
<< 4);
782 env
->npc
= env
->pc
+ 4;
783 env
->exception_index
= 0;
786 void do_interrupt(int intno
)
791 if (loglevel
& CPU_LOG_INT
) {
793 fprintf(logfile
, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n",
796 env
->npc
, env
->regwptr
[6]);
797 cpu_dump_state(env
, logfile
, fprintf
, 0);
803 fprintf(logfile
, " code=");
804 ptr
= (uint8_t *)env
->pc
;
805 for(i
= 0; i
< 16; i
++) {
806 fprintf(logfile
, " %02x", ldub(ptr
+ i
));
808 fprintf(logfile
, "\n");
814 #if !defined(CONFIG_USER_ONLY)
815 if (env
->psret
== 0) {
816 cpu_abort(cpu_single_env
, "Trap 0x%02x while interrupts disabled, Error state", env
->exception_index
);
821 cwp
= (env
->cwp
- 1) & (NWINDOWS
- 1);
823 env
->regwptr
[9] = env
->pc
;
824 env
->regwptr
[10] = env
->npc
;
825 env
->psrps
= env
->psrs
;
827 env
->tbr
= (env
->tbr
& TBR_BASE_MASK
) | (intno
<< 4);
829 env
->npc
= env
->pc
+ 4;
830 env
->exception_index
= 0;
834 #if !defined(CONFIG_USER_ONLY)
836 #define MMUSUFFIX _mmu
837 #define GETPC() (__builtin_return_address(0))
840 #include "softmmu_template.h"
843 #include "softmmu_template.h"
846 #include "softmmu_template.h"
849 #include "softmmu_template.h"
852 /* try to fill the TLB and return an exception if error. If retaddr is
853 NULL, it means that the function was called in C code (i.e. not
854 from generated code or from helper.c) */
855 /* XXX: fix it to restore all registers */
856 void tlb_fill(target_ulong addr
, int is_write
, int is_user
, void *retaddr
)
858 TranslationBlock
*tb
;
863 /* XXX: hack to restore env in all cases, even if not called from
866 env
= cpu_single_env
;
868 ret
= cpu_sparc_handle_mmu_fault(env
, addr
, is_write
, is_user
, 1);
871 /* now we have a real cpu fault */
872 pc
= (unsigned long)retaddr
;
875 /* the PC is inside the translated code. It means that we have
876 a virtual CPU fault */
877 cpu_restore_state(tb
, env
, pc
, (void *)T2
);