]>
git.proxmox.com Git - qemu.git/blob - target-sparc/op_helper.c
6 void raise_exception(int tt
)
8 env
->exception_index
= tt
;
12 #ifdef USE_INT_TO_FLOAT_HELPERS
15 FT0
= (float) *((int32_t *)&FT1
);
20 DT0
= (double) *((int32_t *)&FT1
);
26 FT0
= float32_abs(FT1
);
32 DT0
= float64_abs(DT1
);
38 FT0
= float32_sqrt(FT1
, &env
->fp_status
);
43 DT0
= float64_sqrt(DT1
, &env
->fp_status
);
49 env
->fsr
&= ~((FSR_FCC1
| FSR_FCC0
) << FS
);
50 if (isnan(FT0
) || isnan(FT1
)) {
51 T0
= (FSR_FCC1
| FSR_FCC0
) << FS
;
52 if (env
->fsr
& FSR_NVM
) {
54 raise_exception(TT_FP_EXCP
);
58 } else if (FT0
< FT1
) {
60 } else if (FT0
> FT1
) {
70 env
->fsr
&= ~((FSR_FCC1
| FSR_FCC0
) << FS
);
71 if (isnan(DT0
) || isnan(DT1
)) {
72 T0
= (FSR_FCC1
| FSR_FCC0
) << FS
;
73 if (env
->fsr
& FSR_NVM
) {
75 raise_exception(TT_FP_EXCP
);
79 } else if (DT0
< DT1
) {
81 } else if (DT0
> DT1
) {
92 void do_fcmps_fcc1 (void)
94 env
->fsr
&= ~((FSR_FCC1
| FSR_FCC0
) << FS
);
95 if (isnan(FT0
) || isnan(FT1
)) {
96 T0
= (FSR_FCC1
| FSR_FCC0
) << FS
;
97 if (env
->fsr
& FSR_NVM
) {
99 raise_exception(TT_FP_EXCP
);
103 } else if (FT0
< FT1
) {
105 } else if (FT0
> FT1
) {
113 void do_fcmpd_fcc1 (void)
115 env
->fsr
&= ~((FSR_FCC1
| FSR_FCC0
) << FS
);
116 if (isnan(DT0
) || isnan(DT1
)) {
117 T0
= (FSR_FCC1
| FSR_FCC0
) << FS
;
118 if (env
->fsr
& FSR_NVM
) {
120 raise_exception(TT_FP_EXCP
);
124 } else if (DT0
< DT1
) {
126 } else if (DT0
> DT1
) {
136 void do_fcmps_fcc2 (void)
138 env
->fsr
&= ~((FSR_FCC1
| FSR_FCC0
) << FS
);
139 if (isnan(FT0
) || isnan(FT1
)) {
140 T0
= (FSR_FCC1
| FSR_FCC0
) << FS
;
141 if (env
->fsr
& FSR_NVM
) {
143 raise_exception(TT_FP_EXCP
);
147 } else if (FT0
< FT1
) {
149 } else if (FT0
> FT1
) {
157 void do_fcmpd_fcc2 (void)
159 env
->fsr
&= ~((FSR_FCC1
| FSR_FCC0
) << FS
);
160 if (isnan(DT0
) || isnan(DT1
)) {
161 T0
= (FSR_FCC1
| FSR_FCC0
) << FS
;
162 if (env
->fsr
& FSR_NVM
) {
164 raise_exception(TT_FP_EXCP
);
168 } else if (DT0
< DT1
) {
170 } else if (DT0
> DT1
) {
180 void do_fcmps_fcc3 (void)
182 env
->fsr
&= ~((FSR_FCC1
| FSR_FCC0
) << FS
);
183 if (isnan(FT0
) || isnan(FT1
)) {
184 T0
= (FSR_FCC1
| FSR_FCC0
) << FS
;
185 if (env
->fsr
& FSR_NVM
) {
187 raise_exception(TT_FP_EXCP
);
191 } else if (FT0
< FT1
) {
193 } else if (FT0
> FT1
) {
201 void do_fcmpd_fcc3 (void)
203 env
->fsr
&= ~((FSR_FCC1
| FSR_FCC0
) << FS
);
204 if (isnan(DT0
) || isnan(DT1
)) {
205 T0
= (FSR_FCC1
| FSR_FCC0
) << FS
;
206 if (env
->fsr
& FSR_NVM
) {
208 raise_exception(TT_FP_EXCP
);
212 } else if (DT0
< DT1
) {
214 } else if (DT0
> DT1
) {
224 #ifndef TARGET_SPARC64
225 void helper_ld_asi(int asi
, int size
, int sign
)
230 case 3: /* MMU probe */
234 mmulev
= (T0
>> 8) & 15;
238 ret
= mmu_probe(env
, T0
, mmulev
);
242 printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0
, mmulev
, ret
);
246 case 4: /* read MMU regs */
248 int reg
= (T0
>> 8) & 0xf;
250 ret
= env
->mmuregs
[reg
];
251 if (reg
== 3) /* Fault status cleared on read */
252 env
->mmuregs
[reg
] = 0;
254 printf("mmu_read: reg[%d] = 0x%08x\n", reg
, ret
);
258 case 0x20 ... 0x2f: /* MMU passthrough */
264 ret
= lduw_phys(T0
& ~1);
268 ret
= ldl_phys(T0
& ~3);
279 void helper_st_asi(int asi
, int size
, int sign
)
282 case 3: /* MMU flush */
286 mmulev
= (T0
>> 8) & 15;
288 printf("mmu flush level %d\n", mmulev
);
291 case 0: // flush page
292 tlb_flush_page(env
, T0
& 0xfffff000);
294 case 1: // flush segment (256k)
295 case 2: // flush region (16M)
296 case 3: // flush context (4G)
297 case 4: // flush entire
308 case 4: /* write MMU regs */
310 int reg
= (T0
>> 8) & 0xf;
313 oldreg
= env
->mmuregs
[reg
];
316 env
->mmuregs
[reg
] &= ~(MMU_E
| MMU_NF
);
317 env
->mmuregs
[reg
] |= T1
& (MMU_E
| MMU_NF
);
318 // Mappings generated during no-fault mode or MMU
319 // disabled mode are invalid in normal mode
320 if (oldreg
!= env
->mmuregs
[reg
])
324 env
->mmuregs
[reg
] = T1
;
325 if (oldreg
!= env
->mmuregs
[reg
]) {
326 /* we flush when the MMU context changes because
327 QEMU has no MMU context support */
335 env
->mmuregs
[reg
] = T1
;
339 if (oldreg
!= env
->mmuregs
[reg
]) {
340 printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg
, oldreg
, env
->mmuregs
[reg
]);
346 case 0x17: /* Block copy, sta access */
349 // address (T0) = dst
351 uint32_t src
= T1
, dst
= T0
;
356 cpu_physical_memory_read(src
, (void *) &temp
, 32);
357 cpu_physical_memory_write(dst
, (void *) &temp
, 32);
360 case 0x1f: /* Block fill, stda access */
363 // address (T0) = dst
369 val
= (((uint64_t)T1
) << 32) | T2
;
372 for (i
= 0; i
< 32; i
+= 8, dst
+= 8) {
373 cpu_physical_memory_write(dst
, (void *) &val
, 8);
377 case 0x20 ... 0x2f: /* MMU passthrough */
384 stw_phys(T0
& ~1, T1
);
388 stl_phys(T0
& ~3, T1
);
400 void helper_ld_asi(int asi
, int size
, int sign
)
404 if (asi
< 0x80 && (env
->pstate
& PS_PRIV
) == 0)
405 raise_exception(TT_PRIV_ACT
);
409 case 0x15: // Bypass, non-cacheable
416 ret
= lduw_phys(T0
& ~1);
419 ret
= ldl_phys(T0
& ~3);
423 ret
= ldq_phys(T0
& ~7);
428 case 0x04: // Nucleus
429 case 0x0c: // Nucleus Little Endian (LE)
430 case 0x10: // As if user primary
431 case 0x11: // As if user secondary
432 case 0x18: // As if user primary LE
433 case 0x19: // As if user secondary LE
434 case 0x1c: // Bypass LE
435 case 0x1d: // Bypass, non-cacheable LE
436 case 0x24: // Nucleus quad LDD 128 bit atomic
437 case 0x2c: // Nucleus quad LDD 128 bit atomic
438 case 0x4a: // UPA config
439 case 0x82: // Primary no-fault
440 case 0x83: // Secondary no-fault
441 case 0x88: // Primary LE
442 case 0x89: // Secondary LE
443 case 0x8a: // Primary no-fault LE
444 case 0x8b: // Secondary no-fault LE
450 case 0x50: // I-MMU regs
452 int reg
= (T0
>> 3) & 0xf;
454 ret
= env
->immuregs
[reg
];
457 case 0x51: // I-MMU 8k TSB pointer
458 case 0x52: // I-MMU 64k TSB pointer
459 case 0x55: // I-MMU data access
462 case 0x56: // I-MMU tag read
466 for (i
= 0; i
< 64; i
++) {
467 // Valid, ctx match, vaddr match
468 if ((env
->itlb_tte
[i
] & 0x8000000000000000ULL
) != 0 &&
469 env
->itlb_tag
[i
] == T0
) {
470 ret
= env
->itlb_tag
[i
];
476 case 0x58: // D-MMU regs
478 int reg
= (T0
>> 3) & 0xf;
480 ret
= env
->dmmuregs
[reg
];
483 case 0x5e: // D-MMU tag read
487 for (i
= 0; i
< 64; i
++) {
488 // Valid, ctx match, vaddr match
489 if ((env
->dtlb_tte
[i
] & 0x8000000000000000ULL
) != 0 &&
490 env
->dtlb_tag
[i
] == T0
) {
491 ret
= env
->dtlb_tag
[i
];
497 case 0x59: // D-MMU 8k TSB pointer
498 case 0x5a: // D-MMU 64k TSB pointer
499 case 0x5b: // D-MMU data pointer
500 case 0x5d: // D-MMU data access
501 case 0x48: // Interrupt dispatch, RO
502 case 0x49: // Interrupt data receive
503 case 0x7f: // Incoming interrupt vector, RO
506 case 0x54: // I-MMU data in, WO
507 case 0x57: // I-MMU demap, WO
508 case 0x5c: // D-MMU data in, WO
509 case 0x5f: // D-MMU demap, WO
510 case 0x77: // Interrupt vector, WO
518 void helper_st_asi(int asi
, int size
, int sign
)
520 if (asi
< 0x80 && (env
->pstate
& PS_PRIV
) == 0)
521 raise_exception(TT_PRIV_ACT
);
525 case 0x15: // Bypass, non-cacheable
532 stw_phys(T0
& ~1, T1
);
535 stl_phys(T0
& ~3, T1
);
539 stq_phys(T0
& ~7, T1
);
544 case 0x04: // Nucleus
545 case 0x0c: // Nucleus Little Endian (LE)
546 case 0x10: // As if user primary
547 case 0x11: // As if user secondary
548 case 0x18: // As if user primary LE
549 case 0x19: // As if user secondary LE
550 case 0x1c: // Bypass LE
551 case 0x1d: // Bypass, non-cacheable LE
552 case 0x24: // Nucleus quad LDD 128 bit atomic
553 case 0x2c: // Nucleus quad LDD 128 bit atomic
554 case 0x4a: // UPA config
555 case 0x88: // Primary LE
556 case 0x89: // Secondary LE
564 env
->lsu
= T1
& (DMMU_E
| IMMU_E
);
565 // Mappings generated during D/I MMU disabled mode are
566 // invalid in normal mode
567 if (oldreg
!= env
->lsu
) {
569 printf("LSU change: 0x%llx -> 0x%llx\n", oldreg
, env
->lsu
);
576 case 0x50: // I-MMU regs
578 int reg
= (T0
>> 3) & 0xf;
581 oldreg
= env
->immuregs
[reg
];
586 case 1: // Not in I-MMU
593 T1
= 0; // Clear SFSR
595 case 5: // TSB access
596 case 6: // Tag access
600 env
->immuregs
[reg
] = T1
;
602 if (oldreg
!= env
->immuregs
[reg
]) {
603 printf("mmu change reg[%d]: 0x%08llx -> 0x%08llx\n", reg
, oldreg
, env
->immuregs
[reg
]);
609 case 0x54: // I-MMU data in
613 // Try finding an invalid entry
614 for (i
= 0; i
< 64; i
++) {
615 if ((env
->itlb_tte
[i
] & 0x8000000000000000ULL
) == 0) {
616 env
->itlb_tag
[i
] = env
->immuregs
[6];
617 env
->itlb_tte
[i
] = T1
;
621 // Try finding an unlocked entry
622 for (i
= 0; i
< 64; i
++) {
623 if ((env
->itlb_tte
[i
] & 0x40) == 0) {
624 env
->itlb_tag
[i
] = env
->immuregs
[6];
625 env
->itlb_tte
[i
] = T1
;
632 case 0x55: // I-MMU data access
634 unsigned int i
= (T0
>> 3) & 0x3f;
636 env
->itlb_tag
[i
] = env
->immuregs
[6];
637 env
->itlb_tte
[i
] = T1
;
640 case 0x57: // I-MMU demap
643 case 0x58: // D-MMU regs
645 int reg
= (T0
>> 3) & 0xf;
648 oldreg
= env
->dmmuregs
[reg
];
655 T1
= 0; // Clear SFSR, Fault address
656 env
->dmmuregs
[4] = 0;
658 env
->dmmuregs
[reg
] = T1
;
660 case 1: // Primary context
661 case 2: // Secondary context
662 case 5: // TSB access
663 case 6: // Tag access
664 case 7: // Virtual Watchpoint
665 case 8: // Physical Watchpoint
669 env
->dmmuregs
[reg
] = T1
;
671 if (oldreg
!= env
->dmmuregs
[reg
]) {
672 printf("mmu change reg[%d]: 0x%08llx -> 0x%08llx\n", reg
, oldreg
, env
->dmmuregs
[reg
]);
678 case 0x5c: // D-MMU data in
682 // Try finding an invalid entry
683 for (i
= 0; i
< 64; i
++) {
684 if ((env
->dtlb_tte
[i
] & 0x8000000000000000ULL
) == 0) {
685 env
->dtlb_tag
[i
] = env
->dmmuregs
[6];
686 env
->dtlb_tte
[i
] = T1
;
690 // Try finding an unlocked entry
691 for (i
= 0; i
< 64; i
++) {
692 if ((env
->dtlb_tte
[i
] & 0x40) == 0) {
693 env
->dtlb_tag
[i
] = env
->dmmuregs
[6];
694 env
->dtlb_tte
[i
] = T1
;
701 case 0x5d: // D-MMU data access
703 unsigned int i
= (T0
>> 3) & 0x3f;
705 env
->dtlb_tag
[i
] = env
->dmmuregs
[6];
706 env
->dtlb_tte
[i
] = T1
;
709 case 0x5f: // D-MMU demap
710 case 0x49: // Interrupt data receive
713 case 0x51: // I-MMU 8k TSB pointer, RO
714 case 0x52: // I-MMU 64k TSB pointer, RO
715 case 0x56: // I-MMU tag read, RO
716 case 0x59: // D-MMU 8k TSB pointer, RO
717 case 0x5a: // D-MMU 64k TSB pointer, RO
718 case 0x5b: // D-MMU data pointer, RO
719 case 0x5e: // D-MMU tag read, RO
720 case 0x48: // Interrupt dispatch, RO
721 case 0x7f: // Incoming interrupt vector, RO
722 case 0x82: // Primary no-fault, RO
723 case 0x83: // Secondary no-fault, RO
724 case 0x8a: // Primary no-fault LE, RO
725 case 0x8b: // Secondary no-fault LE, RO
733 #ifndef TARGET_SPARC64
739 cwp
= (env
->cwp
+ 1) & (NWINDOWS
- 1);
740 if (env
->wim
& (1 << cwp
)) {
741 raise_exception(TT_WIN_UNF
);
744 env
->psrs
= env
->psrps
;
748 void helper_ldfsr(void)
751 switch (env
->fsr
& FSR_RD_MASK
) {
753 rnd_mode
= float_round_nearest_even
;
757 rnd_mode
= float_round_to_zero
;
760 rnd_mode
= float_round_up
;
763 rnd_mode
= float_round_down
;
766 set_float_rounding_mode(rnd_mode
, &env
->fp_status
);
769 void cpu_get_fp64(uint64_t *pmant
, uint16_t *pexp
, double f
)
773 *pmant
= ldexp(frexp(f
, &exptemp
), 53);
777 double cpu_put_fp64(uint64_t mant
, uint16_t exp
)
779 return ldexp((double) mant
, exp
- 53);
784 env
->exception_index
= EXCP_DEBUG
;
788 #ifndef TARGET_SPARC64
803 T0
= (T1
& 0x5555555555555555ULL
) + ((T1
>> 1) & 0x5555555555555555ULL
);
804 T0
= (T0
& 0x3333333333333333ULL
) + ((T0
>> 2) & 0x3333333333333333ULL
);
805 T0
= (T0
& 0x0f0f0f0f0f0f0f0fULL
) + ((T0
>> 4) & 0x0f0f0f0f0f0f0f0fULL
);
806 T0
= (T0
& 0x00ff00ff00ff00ffULL
) + ((T0
>> 8) & 0x00ff00ff00ff00ffULL
);
807 T0
= (T0
& 0x0000ffff0000ffffULL
) + ((T0
>> 16) & 0x0000ffff0000ffffULL
);
808 T0
= (T0
& 0x00000000ffffffffULL
) + ((T0
>> 32) & 0x00000000ffffffffULL
);
811 static inline uint64_t *get_gregset(uint64_t pstate
)
828 uint64_t new_pstate
, pstate_regs
, new_pstate_regs
;
831 new_pstate
= T0
& 0xf3f;
832 pstate_regs
= env
->pstate
& 0xc01;
833 new_pstate_regs
= new_pstate
& 0xc01;
834 if (new_pstate_regs
!= pstate_regs
) {
835 // Switch global register bank
836 src
= get_gregset(new_pstate_regs
);
837 dst
= get_gregset(pstate_regs
);
838 memcpy32(dst
, env
->gregs
);
839 memcpy32(env
->gregs
, src
);
841 env
->pstate
= new_pstate
;
847 env
->pc
= env
->tnpc
[env
->tl
];
848 env
->npc
= env
->tnpc
[env
->tl
] + 4;
849 PUT_CCR(env
, env
->tstate
[env
->tl
] >> 32);
850 env
->asi
= (env
->tstate
[env
->tl
] >> 24) & 0xff;
851 env
->pstate
= (env
->tstate
[env
->tl
] >> 8) & 0xfff;
852 set_cwp(env
->tstate
[env
->tl
] & 0xff);
858 env
->pc
= env
->tpc
[env
->tl
];
859 env
->npc
= env
->tnpc
[env
->tl
];
860 PUT_CCR(env
, env
->tstate
[env
->tl
] >> 32);
861 env
->asi
= (env
->tstate
[env
->tl
] >> 24) & 0xff;
862 env
->pstate
= (env
->tstate
[env
->tl
] >> 8) & 0xfff;
863 set_cwp(env
->tstate
[env
->tl
] & 0xff);
867 void set_cwp(int new_cwp
)
869 /* put the modified wrap registers at their proper location */
870 if (env
->cwp
== (NWINDOWS
- 1))
871 memcpy32(env
->regbase
, env
->regbase
+ NWINDOWS
* 16);
873 /* put the wrap registers at their temporary location */
874 if (new_cwp
== (NWINDOWS
- 1))
875 memcpy32(env
->regbase
+ NWINDOWS
* 16, env
->regbase
);
876 env
->regwptr
= env
->regbase
+ (new_cwp
* 16);
877 REGWPTR
= env
->regwptr
;
880 void cpu_set_cwp(CPUState
*env1
, int new_cwp
)
884 target_ulong
*saved_regwptr
;
889 saved_regwptr
= REGWPTR
;
895 REGWPTR
= saved_regwptr
;
899 #ifdef TARGET_SPARC64
900 void do_interrupt(int intno
)
903 if (loglevel
& CPU_LOG_INT
) {
905 fprintf(logfile
, "%6d: v=%04x pc=%016llx npc=%016llx SP=%016llx\n",
908 env
->npc
, env
->regwptr
[6]);
909 cpu_dump_state(env
, logfile
, fprintf
, 0);
915 fprintf(logfile
, " code=");
916 ptr
= (uint8_t *)env
->pc
;
917 for(i
= 0; i
< 16; i
++) {
918 fprintf(logfile
, " %02x", ldub(ptr
+ i
));
920 fprintf(logfile
, "\n");
926 #if !defined(CONFIG_USER_ONLY)
927 if (env
->tl
== MAXTL
) {
928 cpu_abort(cpu_single_env
, "Trap 0x%04x while trap level is MAXTL, Error state", env
->exception_index
);
932 env
->tstate
[env
->tl
] = ((uint64_t)GET_CCR(env
) << 32) | ((env
->asi
& 0xff) << 24) |
933 ((env
->pstate
& 0xfff) << 8) | (env
->cwp
& 0xff);
934 env
->tpc
[env
->tl
] = env
->pc
;
935 env
->tnpc
[env
->tl
] = env
->npc
;
936 env
->tt
[env
->tl
] = intno
;
937 env
->pstate
= PS_PEF
| PS_PRIV
| PS_AG
;
938 env
->tbr
&= ~0x7fffULL
;
939 env
->tbr
|= ((env
->tl
> 1) ? 1 << 14 : 0) | (intno
<< 5);
940 if (env
->tl
< MAXTL
- 1) {
943 env
->pstate
|= PS_RED
;
944 if (env
->tl
!= MAXTL
)
948 env
->npc
= env
->pc
+ 4;
949 env
->exception_index
= 0;
952 void do_interrupt(int intno
)
957 if (loglevel
& CPU_LOG_INT
) {
959 fprintf(logfile
, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n",
962 env
->npc
, env
->regwptr
[6]);
963 cpu_dump_state(env
, logfile
, fprintf
, 0);
969 fprintf(logfile
, " code=");
970 ptr
= (uint8_t *)env
->pc
;
971 for(i
= 0; i
< 16; i
++) {
972 fprintf(logfile
, " %02x", ldub(ptr
+ i
));
974 fprintf(logfile
, "\n");
980 #if !defined(CONFIG_USER_ONLY)
981 if (env
->psret
== 0) {
982 cpu_abort(cpu_single_env
, "Trap 0x%02x while interrupts disabled, Error state", env
->exception_index
);
987 cwp
= (env
->cwp
- 1) & (NWINDOWS
- 1);
989 env
->regwptr
[9] = env
->pc
;
990 env
->regwptr
[10] = env
->npc
;
991 env
->psrps
= env
->psrs
;
993 env
->tbr
= (env
->tbr
& TBR_BASE_MASK
) | (intno
<< 4);
995 env
->npc
= env
->pc
+ 4;
996 env
->exception_index
= 0;
1000 #if !defined(CONFIG_USER_ONLY)
1002 #define MMUSUFFIX _mmu
1003 #define GETPC() (__builtin_return_address(0))
1006 #include "softmmu_template.h"
1009 #include "softmmu_template.h"
1012 #include "softmmu_template.h"
1015 #include "softmmu_template.h"
1018 /* try to fill the TLB and return an exception if error. If retaddr is
1019 NULL, it means that the function was called in C code (i.e. not
1020 from generated code or from helper.c) */
1021 /* XXX: fix it to restore all registers */
1022 void tlb_fill(target_ulong addr
, int is_write
, int is_user
, void *retaddr
)
1024 TranslationBlock
*tb
;
1027 CPUState
*saved_env
;
1029 /* XXX: hack to restore env in all cases, even if not called from
1032 env
= cpu_single_env
;
1034 ret
= cpu_sparc_handle_mmu_fault(env
, addr
, is_write
, is_user
, 1);
1037 /* now we have a real cpu fault */
1038 pc
= (unsigned long)retaddr
;
1039 tb
= tb_find_pc(pc
);
1041 /* the PC is inside the translated code. It means that we have
1042 a virtual CPU fault */
1043 cpu_restore_state(tb
, env
, pc
, (void *)T2
);