Full implementation of IEEE exceptions (Aurelien Jarno)
[qemu] / target-sparc / op_helper.c
1 #include "exec.h"
2
3 //#define DEBUG_PCALL
4 //#define DEBUG_MMU
5
6 void raise_exception(int tt)
7 {
8     env->exception_index = tt;
9     cpu_loop_exit();
10 }   
11
12 void check_ieee_exceptions()
13 {
14      T0 = get_float_exception_flags(&env->fp_status);
15      if (T0)
16      {
17         /* Copy IEEE 754 flags into FSR */
18         if (T0 & float_flag_invalid)
19             env->fsr |= FSR_NVC;
20         if (T0 & float_flag_overflow)
21             env->fsr |= FSR_OFC;
22         if (T0 & float_flag_underflow)
23             env->fsr |= FSR_UFC;
24         if (T0 & float_flag_divbyzero)
25             env->fsr |= FSR_DZC;
26         if (T0 & float_flag_inexact)
27             env->fsr |= FSR_NXC;
28
29         if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23))
30         {
31             /* Unmasked exception, generate a trap */
32             env->fsr |= FSR_FTT_IEEE_EXCP;
33             raise_exception(TT_FP_EXCP);
34         }
35         else
36         {
37             /* Accumulate exceptions */
38             env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
39         }
40      }
41 }
42
43 #ifdef USE_INT_TO_FLOAT_HELPERS
44 void do_fitos(void)
45 {
46     set_float_exception_flags(0, &env->fp_status);
47     FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status);
48     check_ieee_exceptions();
49 }
50
51 void do_fitod(void)
52 {
53     DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status);
54 }
55 #endif
56
57 void do_fabss(void)
58 {
59     FT0 = float32_abs(FT1);
60 }
61
62 #ifdef TARGET_SPARC64
63 void do_fabsd(void)
64 {
65     DT0 = float64_abs(DT1);
66 }
67 #endif
68
69 void do_fsqrts(void)
70 {
71     set_float_exception_flags(0, &env->fp_status);
72     FT0 = float32_sqrt(FT1, &env->fp_status);
73     check_ieee_exceptions();
74 }
75
76 void do_fsqrtd(void)
77 {
78     set_float_exception_flags(0, &env->fp_status);
79     DT0 = float64_sqrt(DT1, &env->fp_status);
80     check_ieee_exceptions();
81 }
82
83 #define GEN_FCMP(name, size, reg1, reg2, FS, TRAP)                      \
84     void glue(do_, name) (void)                                         \
85     {                                                                   \
86         env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                     \
87         switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) {   \
88         case float_relation_unordered:                                  \
89             T0 = (FSR_FCC1 | FSR_FCC0) << FS;                           \
90             if ((env->fsr & FSR_NVM) || TRAP) {                         \
91                 env->fsr |= T0;                                         \
92                 env->fsr |= FSR_NVC;                                    \
93                 env->fsr |= FSR_FTT_IEEE_EXCP;                          \
94                 raise_exception(TT_FP_EXCP);                            \
95             } else {                                                    \
96                 env->fsr |= FSR_NVA;                                    \
97             }                                                           \
98             break;                                                      \
99         case float_relation_less:                                       \
100             T0 = FSR_FCC0 << FS;                                        \
101             break;                                                      \
102         case float_relation_greater:                                    \
103             T0 = FSR_FCC1 << FS;                                        \
104             break;                                                      \
105         default:                                                        \
106             T0 = 0;                                                     \
107             break;                                                      \
108         }                                                               \
109         env->fsr |= T0;                                                 \
110     }
111
112 GEN_FCMP(fcmps, float32, FT0, FT1, 0, 0);
113 GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
114
115 GEN_FCMP(fcmpes, float32, FT0, FT1, 0, 1);
116 GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
117
118 #ifdef TARGET_SPARC64
119 GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22, 0);
120 GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
121
122 GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24, 0);
123 GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
124
125 GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26, 0);
126 GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
127
128 GEN_FCMP(fcmpes_fcc1, float32, FT0, FT1, 22, 1);
129 GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
130
131 GEN_FCMP(fcmpes_fcc2, float32, FT0, FT1, 24, 1);
132 GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
133
134 GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1);
135 GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
136 #endif
137
138 #if defined(CONFIG_USER_ONLY) 
139 void helper_ld_asi(int asi, int size, int sign)
140 {
141 }
142
143 void helper_st_asi(int asi, int size, int sign)
144 {
145 }
146 #else
147 #ifndef TARGET_SPARC64
148 void helper_ld_asi(int asi, int size, int sign)
149 {
150     uint32_t ret = 0;
151
152     switch (asi) {
153     case 3: /* MMU probe */
154         {
155             int mmulev;
156
157             mmulev = (T0 >> 8) & 15;
158             if (mmulev > 4)
159                 ret = 0;
160             else {
161                 ret = mmu_probe(env, T0, mmulev);
162                 //bswap32s(&ret);
163             }
164 #ifdef DEBUG_MMU
165             printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret);
166 #endif
167         }
168         break;
169     case 4: /* read MMU regs */
170         {
171             int reg = (T0 >> 8) & 0xf;
172             
173             ret = env->mmuregs[reg];
174             if (reg == 3) /* Fault status cleared on read */
175                 env->mmuregs[reg] = 0;
176 #ifdef DEBUG_MMU
177             printf("mmu_read: reg[%d] = 0x%08x\n", reg, ret);
178 #endif
179         }
180         break;
181     case 0x20 ... 0x2f: /* MMU passthrough */
182         switch(size) {
183         case 1:
184             ret = ldub_phys(T0);
185             break;
186         case 2:
187             ret = lduw_phys(T0 & ~1);
188             break;
189         default:
190         case 4:
191             ret = ldl_phys(T0 & ~3);
192             break;
193         case 8:
194             ret = ldl_phys(T0 & ~3);
195             T0 = ldl_phys((T0 + 4) & ~3);
196             break;
197         }
198         break;
199     default:
200         ret = 0;
201         break;
202     }
203     T1 = ret;
204 }
205
206 void helper_st_asi(int asi, int size, int sign)
207 {
208     switch(asi) {
209     case 3: /* MMU flush */
210         {
211             int mmulev;
212
213             mmulev = (T0 >> 8) & 15;
214 #ifdef DEBUG_MMU
215             printf("mmu flush level %d\n", mmulev);
216 #endif
217             switch (mmulev) {
218             case 0: // flush page
219                 tlb_flush_page(env, T0 & 0xfffff000);
220                 break;
221             case 1: // flush segment (256k)
222             case 2: // flush region (16M)
223             case 3: // flush context (4G)
224             case 4: // flush entire
225                 tlb_flush(env, 1);
226                 break;
227             default:
228                 break;
229             }
230 #ifdef DEBUG_MMU
231             dump_mmu(env);
232 #endif
233             return;
234         }
235     case 4: /* write MMU regs */
236         {
237             int reg = (T0 >> 8) & 0xf;
238             uint32_t oldreg;
239             
240             oldreg = env->mmuregs[reg];
241             switch(reg) {
242             case 0:
243                 env->mmuregs[reg] &= ~(MMU_E | MMU_NF);
244                 env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF);
245                 // Mappings generated during no-fault mode or MMU
246                 // disabled mode are invalid in normal mode
247                 if (oldreg != env->mmuregs[reg])
248                     tlb_flush(env, 1);
249                 break;
250             case 2:
251                 env->mmuregs[reg] = T1;
252                 if (oldreg != env->mmuregs[reg]) {
253                     /* we flush when the MMU context changes because
254                        QEMU has no MMU context support */
255                     tlb_flush(env, 1);
256                 }
257                 break;
258             case 3:
259             case 4:
260                 break;
261             default:
262                 env->mmuregs[reg] = T1;
263                 break;
264             }
265 #ifdef DEBUG_MMU
266             if (oldreg != env->mmuregs[reg]) {
267                 printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->mmuregs[reg]);
268             }
269             dump_mmu(env);
270 #endif
271             return;
272         }
273     case 0x17: /* Block copy, sta access */
274         {
275             // value (T1) = src
276             // address (T0) = dst
277             // copy 32 bytes
278             uint32_t src = T1, dst = T0;
279             uint8_t temp[32];
280             
281             tswap32s(&src);
282
283             cpu_physical_memory_read(src, (void *) &temp, 32);
284             cpu_physical_memory_write(dst, (void *) &temp, 32);
285         }
286         return;
287     case 0x1f: /* Block fill, stda access */
288         {
289             // value (T1, T2)
290             // address (T0) = dst
291             // fill 32 bytes
292             int i;
293             uint32_t dst = T0;
294             uint64_t val;
295             
296             val = (((uint64_t)T1) << 32) | T2;
297             tswap64s(&val);
298
299             for (i = 0; i < 32; i += 8, dst += 8) {
300                 cpu_physical_memory_write(dst, (void *) &val, 8);
301             }
302         }
303         return;
304     case 0x20 ... 0x2f: /* MMU passthrough */
305         {
306             switch(size) {
307             case 1:
308                 stb_phys(T0, T1);
309                 break;
310             case 2:
311                 stw_phys(T0 & ~1, T1);
312                 break;
313             case 4:
314             default:
315                 stl_phys(T0 & ~3, T1);
316                 break;
317             case 8:
318                 stl_phys(T0 & ~3, T1);
319                 stl_phys((T0 + 4) & ~3, T2);
320                 break;
321             }
322         }
323         return;
324     default:
325         return;
326     }
327 }
328
329 #else
330
331 void helper_ld_asi(int asi, int size, int sign)
332 {
333     uint64_t ret = 0;
334
335     if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
336         raise_exception(TT_PRIV_ACT);
337
338     switch (asi) {
339     case 0x14: // Bypass
340     case 0x15: // Bypass, non-cacheable
341         {
342             switch(size) {
343             case 1:
344                 ret = ldub_phys(T0);
345                 break;
346             case 2:
347                 ret = lduw_phys(T0 & ~1);
348                 break;
349             case 4:
350                 ret = ldl_phys(T0 & ~3);
351                 break;
352             default:
353             case 8:
354                 ret = ldq_phys(T0 & ~7);
355                 break;
356             }
357             break;
358         }
359     case 0x04: // Nucleus
360     case 0x0c: // Nucleus Little Endian (LE)
361     case 0x10: // As if user primary
362     case 0x11: // As if user secondary
363     case 0x18: // As if user primary LE
364     case 0x19: // As if user secondary LE
365     case 0x1c: // Bypass LE
366     case 0x1d: // Bypass, non-cacheable LE
367     case 0x24: // Nucleus quad LDD 128 bit atomic
368     case 0x2c: // Nucleus quad LDD 128 bit atomic
369     case 0x4a: // UPA config
370     case 0x82: // Primary no-fault
371     case 0x83: // Secondary no-fault
372     case 0x88: // Primary LE
373     case 0x89: // Secondary LE
374     case 0x8a: // Primary no-fault LE
375     case 0x8b: // Secondary no-fault LE
376         // XXX
377         break;
378     case 0x45: // LSU
379         ret = env->lsu;
380         break;
381     case 0x50: // I-MMU regs
382         {
383             int reg = (T0 >> 3) & 0xf;
384
385             ret = env->immuregs[reg];
386             break;
387         }
388     case 0x51: // I-MMU 8k TSB pointer
389     case 0x52: // I-MMU 64k TSB pointer
390     case 0x55: // I-MMU data access
391         // XXX
392         break;
393     case 0x56: // I-MMU tag read
394         {
395             unsigned int i;
396             
397             for (i = 0; i < 64; i++) {
398                 // Valid, ctx match, vaddr match
399                 if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0 &&
400                     env->itlb_tag[i] == T0) {
401                     ret = env->itlb_tag[i];
402                     break;
403                 }
404             }
405             break;
406         }
407     case 0x58: // D-MMU regs
408         {
409             int reg = (T0 >> 3) & 0xf;
410
411             ret = env->dmmuregs[reg];
412             break;
413         }
414     case 0x5e: // D-MMU tag read
415         {
416             unsigned int i;
417             
418             for (i = 0; i < 64; i++) {
419                 // Valid, ctx match, vaddr match
420                 if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0 &&
421                     env->dtlb_tag[i] == T0) {
422                     ret = env->dtlb_tag[i];
423                     break;
424                 }
425             }
426             break;
427         }
428     case 0x59: // D-MMU 8k TSB pointer
429     case 0x5a: // D-MMU 64k TSB pointer
430     case 0x5b: // D-MMU data pointer
431     case 0x5d: // D-MMU data access
432     case 0x48: // Interrupt dispatch, RO
433     case 0x49: // Interrupt data receive
434     case 0x7f: // Incoming interrupt vector, RO
435         // XXX
436         break;
437     case 0x54: // I-MMU data in, WO
438     case 0x57: // I-MMU demap, WO
439     case 0x5c: // D-MMU data in, WO
440     case 0x5f: // D-MMU demap, WO
441     case 0x77: // Interrupt vector, WO
442     default:
443         ret = 0;
444         break;
445     }
446     T1 = ret;
447 }
448
449 void helper_st_asi(int asi, int size, int sign)
450 {
451     if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
452         raise_exception(TT_PRIV_ACT);
453
454     switch(asi) {
455     case 0x14: // Bypass
456     case 0x15: // Bypass, non-cacheable
457         {
458             switch(size) {
459             case 1:
460                 stb_phys(T0, T1);
461                 break;
462             case 2:
463                 stw_phys(T0 & ~1, T1);
464                 break;
465             case 4:
466                 stl_phys(T0 & ~3, T1);
467                 break;
468             case 8:
469             default:
470                 stq_phys(T0 & ~7, T1);
471                 break;
472             }
473         }
474         return;
475     case 0x04: // Nucleus
476     case 0x0c: // Nucleus Little Endian (LE)
477     case 0x10: // As if user primary
478     case 0x11: // As if user secondary
479     case 0x18: // As if user primary LE
480     case 0x19: // As if user secondary LE
481     case 0x1c: // Bypass LE
482     case 0x1d: // Bypass, non-cacheable LE
483     case 0x24: // Nucleus quad LDD 128 bit atomic
484     case 0x2c: // Nucleus quad LDD 128 bit atomic
485     case 0x4a: // UPA config
486     case 0x88: // Primary LE
487     case 0x89: // Secondary LE
488         // XXX
489         return;
490     case 0x45: // LSU
491         {
492             uint64_t oldreg;
493
494             oldreg = env->lsu;
495             env->lsu = T1 & (DMMU_E | IMMU_E);
496             // Mappings generated during D/I MMU disabled mode are
497             // invalid in normal mode
498             if (oldreg != env->lsu) {
499 #ifdef DEBUG_MMU
500                 printf("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", oldreg, env->lsu);
501                 dump_mmu(env);
502 #endif
503                 tlb_flush(env, 1);
504             }
505             return;
506         }
507     case 0x50: // I-MMU regs
508         {
509             int reg = (T0 >> 3) & 0xf;
510             uint64_t oldreg;
511             
512             oldreg = env->immuregs[reg];
513             switch(reg) {
514             case 0: // RO
515             case 4:
516                 return;
517             case 1: // Not in I-MMU
518             case 2:
519             case 7:
520             case 8:
521                 return;
522             case 3: // SFSR
523                 if ((T1 & 1) == 0)
524                     T1 = 0; // Clear SFSR
525                 break;
526             case 5: // TSB access
527             case 6: // Tag access
528             default:
529                 break;
530             }
531             env->immuregs[reg] = T1;
532 #ifdef DEBUG_MMU
533             if (oldreg != env->immuregs[reg]) {
534                 printf("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
535             }
536             dump_mmu(env);
537 #endif
538             return;
539         }
540     case 0x54: // I-MMU data in
541         {
542             unsigned int i;
543
544             // Try finding an invalid entry
545             for (i = 0; i < 64; i++) {
546                 if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0) {
547                     env->itlb_tag[i] = env->immuregs[6];
548                     env->itlb_tte[i] = T1;
549                     return;
550                 }
551             }
552             // Try finding an unlocked entry
553             for (i = 0; i < 64; i++) {
554                 if ((env->itlb_tte[i] & 0x40) == 0) {
555                     env->itlb_tag[i] = env->immuregs[6];
556                     env->itlb_tte[i] = T1;
557                     return;
558                 }
559             }
560             // error state?
561             return;
562         }
563     case 0x55: // I-MMU data access
564         {
565             unsigned int i = (T0 >> 3) & 0x3f;
566
567             env->itlb_tag[i] = env->immuregs[6];
568             env->itlb_tte[i] = T1;
569             return;
570         }
571     case 0x57: // I-MMU demap
572         // XXX
573         return;
574     case 0x58: // D-MMU regs
575         {
576             int reg = (T0 >> 3) & 0xf;
577             uint64_t oldreg;
578             
579             oldreg = env->dmmuregs[reg];
580             switch(reg) {
581             case 0: // RO
582             case 4:
583                 return;
584             case 3: // SFSR
585                 if ((T1 & 1) == 0) {
586                     T1 = 0; // Clear SFSR, Fault address
587                     env->dmmuregs[4] = 0;
588                 }
589                 env->dmmuregs[reg] = T1;
590                 break;
591             case 1: // Primary context
592             case 2: // Secondary context
593             case 5: // TSB access
594             case 6: // Tag access
595             case 7: // Virtual Watchpoint
596             case 8: // Physical Watchpoint
597             default:
598                 break;
599             }
600             env->dmmuregs[reg] = T1;
601 #ifdef DEBUG_MMU
602             if (oldreg != env->dmmuregs[reg]) {
603                 printf("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
604             }
605             dump_mmu(env);
606 #endif
607             return;
608         }
609     case 0x5c: // D-MMU data in
610         {
611             unsigned int i;
612
613             // Try finding an invalid entry
614             for (i = 0; i < 64; i++) {
615                 if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0) {
616                     env->dtlb_tag[i] = env->dmmuregs[6];
617                     env->dtlb_tte[i] = T1;
618                     return;
619                 }
620             }
621             // Try finding an unlocked entry
622             for (i = 0; i < 64; i++) {
623                 if ((env->dtlb_tte[i] & 0x40) == 0) {
624                     env->dtlb_tag[i] = env->dmmuregs[6];
625                     env->dtlb_tte[i] = T1;
626                     return;
627                 }
628             }
629             // error state?
630             return;
631         }
632     case 0x5d: // D-MMU data access
633         {
634             unsigned int i = (T0 >> 3) & 0x3f;
635
636             env->dtlb_tag[i] = env->dmmuregs[6];
637             env->dtlb_tte[i] = T1;
638             return;
639         }
640     case 0x5f: // D-MMU demap
641     case 0x49: // Interrupt data receive
642         // XXX
643         return;
644     case 0x51: // I-MMU 8k TSB pointer, RO
645     case 0x52: // I-MMU 64k TSB pointer, RO
646     case 0x56: // I-MMU tag read, RO
647     case 0x59: // D-MMU 8k TSB pointer, RO
648     case 0x5a: // D-MMU 64k TSB pointer, RO
649     case 0x5b: // D-MMU data pointer, RO
650     case 0x5e: // D-MMU tag read, RO
651     case 0x48: // Interrupt dispatch, RO
652     case 0x7f: // Incoming interrupt vector, RO
653     case 0x82: // Primary no-fault, RO
654     case 0x83: // Secondary no-fault, RO
655     case 0x8a: // Primary no-fault LE, RO
656     case 0x8b: // Secondary no-fault LE, RO
657     default:
658         return;
659     }
660 }
661 #endif
662 #endif /* !CONFIG_USER_ONLY */
663
664 #ifndef TARGET_SPARC64
665 void helper_rett()
666 {
667     unsigned int cwp;
668
669     if (env->psret == 1)
670         raise_exception(TT_ILL_INSN);
671
672     env->psret = 1;
673     cwp = (env->cwp + 1) & (NWINDOWS - 1); 
674     if (env->wim & (1 << cwp)) {
675         raise_exception(TT_WIN_UNF);
676     }
677     set_cwp(cwp);
678     env->psrs = env->psrps;
679 }
680 #endif
681
682 void helper_ldfsr(void)
683 {
684     int rnd_mode;
685     switch (env->fsr & FSR_RD_MASK) {
686     case FSR_RD_NEAREST:
687         rnd_mode = float_round_nearest_even;
688         break;
689     default:
690     case FSR_RD_ZERO:
691         rnd_mode = float_round_to_zero;
692         break;
693     case FSR_RD_POS:
694         rnd_mode = float_round_up;
695         break;
696     case FSR_RD_NEG:
697         rnd_mode = float_round_down;
698         break;
699     }
700     set_float_rounding_mode(rnd_mode, &env->fp_status);
701 }
702
703 void helper_debug()
704 {
705     env->exception_index = EXCP_DEBUG;
706     cpu_loop_exit();
707 }
708
709 #ifndef TARGET_SPARC64
710 void do_wrpsr()
711 {
712     if ((T0 & PSR_CWP) >= NWINDOWS)
713         raise_exception(TT_ILL_INSN);
714     else
715         PUT_PSR(env, T0);
716 }
717
718 void do_rdpsr()
719 {
720     T0 = GET_PSR(env);
721 }
722
723 #else
724
725 void do_popc()
726 {
727     T0 = (T1 & 0x5555555555555555ULL) + ((T1 >> 1) & 0x5555555555555555ULL);
728     T0 = (T0 & 0x3333333333333333ULL) + ((T0 >> 2) & 0x3333333333333333ULL);
729     T0 = (T0 & 0x0f0f0f0f0f0f0f0fULL) + ((T0 >> 4) & 0x0f0f0f0f0f0f0f0fULL);
730     T0 = (T0 & 0x00ff00ff00ff00ffULL) + ((T0 >> 8) & 0x00ff00ff00ff00ffULL);
731     T0 = (T0 & 0x0000ffff0000ffffULL) + ((T0 >> 16) & 0x0000ffff0000ffffULL);
732     T0 = (T0 & 0x00000000ffffffffULL) + ((T0 >> 32) & 0x00000000ffffffffULL);
733 }
734
735 static inline uint64_t *get_gregset(uint64_t pstate)
736 {
737     switch (pstate) {
738     default:
739     case 0:
740         return env->bgregs;
741     case PS_AG:
742         return env->agregs;
743     case PS_MG:
744         return env->mgregs;
745     case PS_IG:
746         return env->igregs;
747     }
748 }
749
750 void do_wrpstate()
751 {
752     uint64_t new_pstate, pstate_regs, new_pstate_regs;
753     uint64_t *src, *dst;
754
755     new_pstate = T0 & 0xf3f;
756     pstate_regs = env->pstate & 0xc01;
757     new_pstate_regs = new_pstate & 0xc01;
758     if (new_pstate_regs != pstate_regs) {
759         // Switch global register bank
760         src = get_gregset(new_pstate_regs);
761         dst = get_gregset(pstate_regs);
762         memcpy32(dst, env->gregs);
763         memcpy32(env->gregs, src);
764     }
765     env->pstate = new_pstate;
766 }
767
768 void do_done(void)
769 {
770     env->tl--;
771     env->pc = env->tnpc[env->tl];
772     env->npc = env->tnpc[env->tl] + 4;
773     PUT_CCR(env, env->tstate[env->tl] >> 32);
774     env->asi = (env->tstate[env->tl] >> 24) & 0xff;
775     env->pstate = (env->tstate[env->tl] >> 8) & 0xfff;
776     set_cwp(env->tstate[env->tl] & 0xff);
777 }
778
779 void do_retry(void)
780 {
781     env->tl--;
782     env->pc = env->tpc[env->tl];
783     env->npc = env->tnpc[env->tl];
784     PUT_CCR(env, env->tstate[env->tl] >> 32);
785     env->asi = (env->tstate[env->tl] >> 24) & 0xff;
786     env->pstate = (env->tstate[env->tl] >> 8) & 0xfff;
787     set_cwp(env->tstate[env->tl] & 0xff);
788 }
789 #endif
790
791 void set_cwp(int new_cwp)
792 {
793     /* put the modified wrap registers at their proper location */
794     if (env->cwp == (NWINDOWS - 1))
795         memcpy32(env->regbase, env->regbase + NWINDOWS * 16);
796     env->cwp = new_cwp;
797     /* put the wrap registers at their temporary location */
798     if (new_cwp == (NWINDOWS - 1))
799         memcpy32(env->regbase + NWINDOWS * 16, env->regbase);
800     env->regwptr = env->regbase + (new_cwp * 16);
801     REGWPTR = env->regwptr;
802 }
803
804 void cpu_set_cwp(CPUState *env1, int new_cwp)
805 {
806     CPUState *saved_env;
807 #ifdef reg_REGWPTR
808     target_ulong *saved_regwptr;
809 #endif
810
811     saved_env = env;
812 #ifdef reg_REGWPTR
813     saved_regwptr = REGWPTR;
814 #endif
815     env = env1;
816     set_cwp(new_cwp);
817     env = saved_env;
818 #ifdef reg_REGWPTR
819     REGWPTR = saved_regwptr;
820 #endif
821 }
822
823 #ifdef TARGET_SPARC64
824 void do_interrupt(int intno)
825 {
826 #ifdef DEBUG_PCALL
827     if (loglevel & CPU_LOG_INT) {
828         static int count;
829         fprintf(logfile, "%6d: v=%04x pc=%016" PRIx64 " npc=%016" PRIx64 " SP=%016" PRIx64 "\n",
830                 count, intno,
831                 env->pc,
832                 env->npc, env->regwptr[6]);
833         cpu_dump_state(env, logfile, fprintf, 0);
834 #if 0
835         {
836             int i;
837             uint8_t *ptr;
838
839             fprintf(logfile, "       code=");
840             ptr = (uint8_t *)env->pc;
841             for(i = 0; i < 16; i++) {
842                 fprintf(logfile, " %02x", ldub(ptr + i));
843             }
844             fprintf(logfile, "\n");
845         }
846 #endif
847         count++;
848     }
849 #endif
850 #if !defined(CONFIG_USER_ONLY) 
851     if (env->tl == MAXTL) {
852         cpu_abort(env, "Trap 0x%04x while trap level is MAXTL, Error state", env->exception_index);
853         return;
854     }
855 #endif
856     env->tstate[env->tl] = ((uint64_t)GET_CCR(env) << 32) | ((env->asi & 0xff) << 24) |
857         ((env->pstate & 0xfff) << 8) | (env->cwp & 0xff);
858     env->tpc[env->tl] = env->pc;
859     env->tnpc[env->tl] = env->npc;
860     env->tt[env->tl] = intno;
861     env->pstate = PS_PEF | PS_PRIV | PS_AG;
862     env->tbr &= ~0x7fffULL;
863     env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
864     if (env->tl < MAXTL - 1) {
865         env->tl++;
866     } else {
867         env->pstate |= PS_RED;
868         if (env->tl != MAXTL)
869             env->tl++;
870     }
871     env->pc = env->tbr;
872     env->npc = env->pc + 4;
873     env->exception_index = 0;
874 }
875 #else
876 void do_interrupt(int intno)
877 {
878     int cwp;
879
880 #ifdef DEBUG_PCALL
881     if (loglevel & CPU_LOG_INT) {
882         static int count;
883         fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n",
884                 count, intno,
885                 env->pc,
886                 env->npc, env->regwptr[6]);
887         cpu_dump_state(env, logfile, fprintf, 0);
888 #if 0
889         {
890             int i;
891             uint8_t *ptr;
892
893             fprintf(logfile, "       code=");
894             ptr = (uint8_t *)env->pc;
895             for(i = 0; i < 16; i++) {
896                 fprintf(logfile, " %02x", ldub(ptr + i));
897             }
898             fprintf(logfile, "\n");
899         }
900 #endif
901         count++;
902     }
903 #endif
904 #if !defined(CONFIG_USER_ONLY) 
905     if (env->psret == 0) {
906         cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index);
907         return;
908     }
909 #endif
910     env->psret = 0;
911     cwp = (env->cwp - 1) & (NWINDOWS - 1); 
912     set_cwp(cwp);
913     env->regwptr[9] = env->pc;
914     env->regwptr[10] = env->npc;
915     env->psrps = env->psrs;
916     env->psrs = 1;
917     env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
918     env->pc = env->tbr;
919     env->npc = env->pc + 4;
920     env->exception_index = 0;
921 }
922 #endif
923
924 #if !defined(CONFIG_USER_ONLY) 
925
926 #define MMUSUFFIX _mmu
927 #define GETPC() (__builtin_return_address(0))
928
929 #define SHIFT 0
930 #include "softmmu_template.h"
931
932 #define SHIFT 1
933 #include "softmmu_template.h"
934
935 #define SHIFT 2
936 #include "softmmu_template.h"
937
938 #define SHIFT 3
939 #include "softmmu_template.h"
940
941
942 /* try to fill the TLB and return an exception if error. If retaddr is
943    NULL, it means that the function was called in C code (i.e. not
944    from generated code or from helper.c) */
945 /* XXX: fix it to restore all registers */
946 void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
947 {
948     TranslationBlock *tb;
949     int ret;
950     unsigned long pc;
951     CPUState *saved_env;
952
953     /* XXX: hack to restore env in all cases, even if not called from
954        generated code */
955     saved_env = env;
956     env = cpu_single_env;
957
958     ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, is_user, 1);
959     if (ret) {
960         if (retaddr) {
961             /* now we have a real cpu fault */
962             pc = (unsigned long)retaddr;
963             tb = tb_find_pc(pc);
964             if (tb) {
965                 /* the PC is inside the translated code. It means that we have
966                    a virtual CPU fault */
967                 cpu_restore_state(tb, env, pc, (void *)T2);
968             }
969         }
970         cpu_loop_exit();
971     }
972     env = saved_env;
973 }
974
975 #endif