|
|
1.1 root 1: #include "exec.h"
1.1.1.5 root 2: #include "host-utils.h"
1.1.1.6 root 3: #include "helper.h"
1.1 root 4:
5: //#define DEBUG_MMU
1.1.1.5 root 6: //#define DEBUG_MXCC
7: //#define DEBUG_UNALIGNED
8: //#define DEBUG_UNASSIGNED
9: //#define DEBUG_ASI
1.1.1.6 root 10: //#define DEBUG_PCALL
1.1.1.9 ! root 11: //#define DEBUG_PSTATE
1.1.1.5 root 12:
13: #ifdef DEBUG_MMU
1.1.1.7 root 14: #define DPRINTF_MMU(fmt, ...) \
15: do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
1.1.1.5 root 16: #else
1.1.1.7 root 17: #define DPRINTF_MMU(fmt, ...) do {} while (0)
1.1.1.5 root 18: #endif
19:
20: #ifdef DEBUG_MXCC
1.1.1.7 root 21: #define DPRINTF_MXCC(fmt, ...) \
22: do { printf("MXCC: " fmt , ## __VA_ARGS__); } while (0)
1.1.1.5 root 23: #else
1.1.1.7 root 24: #define DPRINTF_MXCC(fmt, ...) do {} while (0)
1.1.1.5 root 25: #endif
26:
27: #ifdef DEBUG_ASI
1.1.1.7 root 28: #define DPRINTF_ASI(fmt, ...) \
29: do { printf("ASI: " fmt , ## __VA_ARGS__); } while (0)
1.1.1.6 root 30: #endif
31:
1.1.1.9 ! root 32: #ifdef DEBUG_PSTATE
! 33: #define DPRINTF_PSTATE(fmt, ...) \
! 34: do { printf("PSTATE: " fmt , ## __VA_ARGS__); } while (0)
! 35: #else
! 36: #define DPRINTF_PSTATE(fmt, ...) do {} while (0)
! 37: #endif
! 38:
1.1.1.6 root 39: #ifdef TARGET_SPARC64
40: #ifndef TARGET_ABI32
41: #define AM_CHECK(env1) ((env1)->pstate & PS_AM)
42: #else
43: #define AM_CHECK(env1) (1)
44: #endif
1.1.1.5 root 45: #endif
1.1 root 46:
1.1.1.9 ! root 47: #define DT0 (env->dt0)
! 48: #define DT1 (env->dt1)
! 49: #define QT0 (env->qt0)
! 50: #define QT1 (env->qt1)
! 51:
! 52: #if defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64)
! 53: static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
! 54: int is_asi, int size);
! 55: #endif
! 56:
1.1.1.7 root 57: #if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
58: // Calculates TSB pointer value for fault page size 8k or 64k
59: static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register,
60: uint64_t tag_access_register,
61: int page_size)
62: {
63: uint64_t tsb_base = tsb_register & ~0x1fffULL;
1.1.1.8 root 64: int tsb_split = (tsb_register & 0x1000ULL) ? 1 : 0;
65: int tsb_size = tsb_register & 0xf;
1.1.1.7 root 66:
67: // discard lower 13 bits which hold tag access context
68: uint64_t tag_access_va = tag_access_register & ~0x1fffULL;
69:
70: // now reorder bits
71: uint64_t tsb_base_mask = ~0x1fffULL;
72: uint64_t va = tag_access_va;
73:
74: // move va bits to correct position
75: if (page_size == 8*1024) {
76: va >>= 9;
77: } else if (page_size == 64*1024) {
78: va >>= 12;
79: }
80:
81: if (tsb_size) {
82: tsb_base_mask <<= tsb_size;
83: }
84:
85: // calculate tsb_base mask and adjust va if split is in use
86: if (tsb_split) {
87: if (page_size == 8*1024) {
88: va &= ~(1ULL << (13 + tsb_size));
89: } else if (page_size == 64*1024) {
90: va |= (1ULL << (13 + tsb_size));
91: }
92: tsb_base_mask <<= 1;
93: }
94:
95: return ((tsb_base & tsb_base_mask) | (va & ~tsb_base_mask)) & ~0xfULL;
96: }
97:
98: // Calculates tag target register value by reordering bits
99: // in tag access register
100: static uint64_t ultrasparc_tag_target(uint64_t tag_access_register)
101: {
102: return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22);
103: }
104:
1.1.1.8 root 105: static void replace_tlb_entry(SparcTLBEntry *tlb,
106: uint64_t tlb_tag, uint64_t tlb_tte,
107: CPUState *env1)
108: {
109: target_ulong mask, size, va, offset;
110:
111: // flush page range if translation is valid
112: if (TTE_IS_VALID(tlb->tte)) {
113:
114: mask = 0xffffffffffffe000ULL;
115: mask <<= 3 * ((tlb->tte >> 61) & 3);
116: size = ~mask + 1;
117:
118: va = tlb->tag & mask;
119:
120: for (offset = 0; offset < size; offset += TARGET_PAGE_SIZE) {
121: tlb_flush_page(env1, va + offset);
122: }
123: }
124:
125: tlb->tag = tlb_tag;
126: tlb->tte = tlb_tte;
127: }
128:
129: static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr,
130: const char* strmmu, CPUState *env1)
131: {
132: unsigned int i;
133: target_ulong mask;
1.1.1.9 ! root 134: uint64_t context;
! 135:
! 136: int is_demap_context = (demap_addr >> 6) & 1;
! 137:
! 138: // demap context
! 139: switch ((demap_addr >> 4) & 3) {
! 140: case 0: // primary
! 141: context = env1->dmmu.mmu_primary_context;
! 142: break;
! 143: case 1: // secondary
! 144: context = env1->dmmu.mmu_secondary_context;
! 145: break;
! 146: case 2: // nucleus
! 147: context = 0;
! 148: break;
! 149: case 3: // reserved
! 150: default:
! 151: return;
! 152: }
1.1.1.8 root 153:
154: for (i = 0; i < 64; i++) {
155: if (TTE_IS_VALID(tlb[i].tte)) {
156:
1.1.1.9 ! root 157: if (is_demap_context) {
! 158: // will remove non-global entries matching context value
! 159: if (TTE_IS_GLOBAL(tlb[i].tte) ||
! 160: !tlb_compare_context(&tlb[i], context)) {
! 161: continue;
! 162: }
! 163: } else {
! 164: // demap page
! 165: // will remove any entry matching VA
! 166: mask = 0xffffffffffffe000ULL;
! 167: mask <<= 3 * ((tlb[i].tte >> 61) & 3);
! 168:
! 169: if (!compare_masked(demap_addr, tlb[i].tag, mask)) {
! 170: continue;
! 171: }
1.1.1.8 root 172:
1.1.1.9 ! root 173: // entry should be global or matching context value
! 174: if (!TTE_IS_GLOBAL(tlb[i].tte) &&
! 175: !tlb_compare_context(&tlb[i], context)) {
! 176: continue;
! 177: }
! 178: }
! 179:
! 180: replace_tlb_entry(&tlb[i], 0, 0, env1);
1.1.1.8 root 181: #ifdef DEBUG_MMU
1.1.1.9 ! root 182: DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i);
! 183: dump_mmu(env1);
1.1.1.8 root 184: #endif
185: }
186: }
187: }
188:
189: static void replace_tlb_1bit_lru(SparcTLBEntry *tlb,
190: uint64_t tlb_tag, uint64_t tlb_tte,
191: const char* strmmu, CPUState *env1)
192: {
193: unsigned int i, replace_used;
194:
195: // Try replacing invalid entry
196: for (i = 0; i < 64; i++) {
197: if (!TTE_IS_VALID(tlb[i].tte)) {
198: replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
199: #ifdef DEBUG_MMU
200: DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i);
201: dump_mmu(env1);
202: #endif
203: return;
204: }
205: }
206:
207: // All entries are valid, try replacing unlocked entry
208:
209: for (replace_used = 0; replace_used < 2; ++replace_used) {
210:
211: // Used entries are not replaced on first pass
212:
213: for (i = 0; i < 64; i++) {
214: if (!TTE_IS_LOCKED(tlb[i].tte) && !TTE_IS_USED(tlb[i].tte)) {
215:
216: replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1);
217: #ifdef DEBUG_MMU
218: DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n",
219: strmmu, (replace_used?"used":"unused"), i);
220: dump_mmu(env1);
221: #endif
222: return;
223: }
224: }
225:
226: // Now reset used bit and search for unused entries again
227:
228: for (i = 0; i < 64; i++) {
229: TTE_SET_UNUSED(tlb[i].tte);
230: }
231: }
232:
233: #ifdef DEBUG_MMU
234: DPRINTF_MMU("%s lru replacement failed: no entries available\n", strmmu);
235: #endif
236: // error state?
237: }
238:
1.1.1.7 root 239: #endif
240:
1.1.1.9 ! root 241: static inline target_ulong address_mask(CPUState *env1, target_ulong addr)
1.1.1.6 root 242: {
243: #ifdef TARGET_SPARC64
244: if (AM_CHECK(env1))
1.1.1.9 ! root 245: addr &= 0xffffffffULL;
1.1.1.6 root 246: #endif
1.1.1.9 ! root 247: return addr;
! 248: }
! 249:
! 250: /* returns true if access using this ASI is to have address translated by MMU
! 251: otherwise access is to raw physical address */
! 252: static inline int is_translating_asi(int asi)
! 253: {
! 254: #ifdef TARGET_SPARC64
! 255: /* Ultrasparc IIi translating asi
! 256: - note this list is defined by cpu implementation
! 257: */
! 258: switch (asi) {
! 259: case 0x04 ... 0x11:
! 260: case 0x18 ... 0x19:
! 261: case 0x24 ... 0x2C:
! 262: case 0x70 ... 0x73:
! 263: case 0x78 ... 0x79:
! 264: case 0x80 ... 0xFF:
! 265: return 1;
! 266:
! 267: default:
! 268: return 0;
! 269: }
! 270: #else
! 271: /* TODO: check sparc32 bits */
! 272: return 0;
! 273: #endif
! 274: }
! 275:
! 276: static inline target_ulong asi_address_mask(CPUState *env1,
! 277: int asi, target_ulong addr)
! 278: {
! 279: if (is_translating_asi(asi)) {
! 280: return address_mask(env, addr);
! 281: } else {
! 282: return addr;
! 283: }
1.1.1.6 root 284: }
285:
286: static void raise_exception(int tt)
1.1 root 287: {
288: env->exception_index = tt;
289: cpu_loop_exit();
1.1.1.5 root 290: }
291:
1.1.1.6 root 292: void HELPER(raise_exception)(int tt)
1.1.1.5 root 293: {
1.1.1.6 root 294: raise_exception(tt);
295: }
1.1.1.5 root 296:
1.1.1.6 root 297: void helper_check_align(target_ulong addr, uint32_t align)
1.1 root 298: {
1.1.1.6 root 299: if (addr & align) {
300: #ifdef DEBUG_UNALIGNED
301: printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
302: "\n", addr, env->pc);
303: #endif
304: raise_exception(TT_UNALIGNED);
305: }
306: }
307:
308: #define F_HELPER(name, p) void helper_f##name##p(void)
309:
310: #define F_BINOP(name) \
311: float32 helper_f ## name ## s (float32 src1, float32 src2) \
312: { \
313: return float32_ ## name (src1, src2, &env->fp_status); \
314: } \
315: F_HELPER(name, d) \
316: { \
317: DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \
318: } \
319: F_HELPER(name, q) \
320: { \
321: QT0 = float128_ ## name (QT0, QT1, &env->fp_status); \
322: }
323:
324: F_BINOP(add);
325: F_BINOP(sub);
326: F_BINOP(mul);
327: F_BINOP(div);
328: #undef F_BINOP
329:
330: void helper_fsmuld(float32 src1, float32 src2)
331: {
332: DT0 = float64_mul(float32_to_float64(src1, &env->fp_status),
333: float32_to_float64(src2, &env->fp_status),
334: &env->fp_status);
335: }
336:
337: void helper_fdmulq(void)
338: {
339: QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status),
340: float64_to_float128(DT1, &env->fp_status),
341: &env->fp_status);
342: }
343:
344: float32 helper_fnegs(float32 src)
345: {
346: return float32_chs(src);
1.1 root 347: }
348:
1.1.1.6 root 349: #ifdef TARGET_SPARC64
350: F_HELPER(neg, d)
1.1 root 351: {
1.1.1.6 root 352: DT0 = float64_chs(DT1);
1.1 root 353: }
1.1.1.5 root 354:
1.1.1.6 root 355: F_HELPER(neg, q)
1.1.1.5 root 356: {
1.1.1.6 root 357: QT0 = float128_chs(QT1);
1.1.1.5 root 358: }
359: #endif
360:
1.1.1.6 root 361: /* Integer to float conversion. */
362: float32 helper_fitos(int32_t src)
363: {
364: return int32_to_float32(src, &env->fp_status);
365: }
366:
367: void helper_fitod(int32_t src)
368: {
369: DT0 = int32_to_float64(src, &env->fp_status);
370: }
371:
372: void helper_fitoq(int32_t src)
373: {
374: QT0 = int32_to_float128(src, &env->fp_status);
375: }
376:
1.1.1.5 root 377: #ifdef TARGET_SPARC64
1.1.1.6 root 378: float32 helper_fxtos(void)
1.1.1.5 root 379: {
1.1.1.6 root 380: return int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
1.1.1.5 root 381: }
382:
1.1.1.6 root 383: F_HELPER(xto, d)
1.1.1.5 root 384: {
385: DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
386: }
387:
1.1.1.6 root 388: F_HELPER(xto, q)
1.1.1.5 root 389: {
1.1.1.6 root 390: QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status);
1.1.1.5 root 391: }
392: #endif
1.1.1.6 root 393: #undef F_HELPER
394:
395: /* floating point conversion */
396: float32 helper_fdtos(void)
397: {
398: return float64_to_float32(DT1, &env->fp_status);
399: }
400:
401: void helper_fstod(float32 src)
402: {
403: DT0 = float32_to_float64(src, &env->fp_status);
404: }
405:
406: float32 helper_fqtos(void)
407: {
408: return float128_to_float32(QT1, &env->fp_status);
409: }
410:
411: void helper_fstoq(float32 src)
412: {
413: QT0 = float32_to_float128(src, &env->fp_status);
414: }
415:
416: void helper_fqtod(void)
417: {
418: DT0 = float128_to_float64(QT1, &env->fp_status);
419: }
420:
421: void helper_fdtoq(void)
422: {
423: QT0 = float64_to_float128(DT1, &env->fp_status);
424: }
425:
426: /* Float to integer conversion. */
427: int32_t helper_fstoi(float32 src)
428: {
429: return float32_to_int32_round_to_zero(src, &env->fp_status);
430: }
431:
432: int32_t helper_fdtoi(void)
433: {
434: return float64_to_int32_round_to_zero(DT1, &env->fp_status);
435: }
436:
437: int32_t helper_fqtoi(void)
438: {
439: return float128_to_int32_round_to_zero(QT1, &env->fp_status);
440: }
441:
442: #ifdef TARGET_SPARC64
443: void helper_fstox(float32 src)
444: {
445: *((int64_t *)&DT0) = float32_to_int64_round_to_zero(src, &env->fp_status);
446: }
447:
448: void helper_fdtox(void)
449: {
450: *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status);
451: }
452:
453: void helper_fqtox(void)
454: {
455: *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status);
456: }
457:
458: void helper_faligndata(void)
459: {
460: uint64_t tmp;
461:
462: tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8);
463: /* on many architectures a shift of 64 does nothing */
464: if ((env->gsr & 7) != 0) {
465: tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8);
466: }
467: *((uint64_t *)&DT0) = tmp;
468: }
469:
1.1.1.8 root 470: #ifdef HOST_WORDS_BIGENDIAN
1.1.1.6 root 471: #define VIS_B64(n) b[7 - (n)]
472: #define VIS_W64(n) w[3 - (n)]
473: #define VIS_SW64(n) sw[3 - (n)]
474: #define VIS_L64(n) l[1 - (n)]
475: #define VIS_B32(n) b[3 - (n)]
476: #define VIS_W32(n) w[1 - (n)]
477: #else
478: #define VIS_B64(n) b[n]
479: #define VIS_W64(n) w[n]
480: #define VIS_SW64(n) sw[n]
481: #define VIS_L64(n) l[n]
482: #define VIS_B32(n) b[n]
483: #define VIS_W32(n) w[n]
484: #endif
485:
486: typedef union {
487: uint8_t b[8];
488: uint16_t w[4];
489: int16_t sw[4];
490: uint32_t l[2];
491: float64 d;
492: } vis64;
493:
494: typedef union {
495: uint8_t b[4];
496: uint16_t w[2];
497: uint32_t l;
498: float32 f;
499: } vis32;
500:
501: void helper_fpmerge(void)
502: {
503: vis64 s, d;
504:
505: s.d = DT0;
506: d.d = DT1;
507:
508: // Reverse calculation order to handle overlap
509: d.VIS_B64(7) = s.VIS_B64(3);
510: d.VIS_B64(6) = d.VIS_B64(3);
511: d.VIS_B64(5) = s.VIS_B64(2);
512: d.VIS_B64(4) = d.VIS_B64(2);
513: d.VIS_B64(3) = s.VIS_B64(1);
514: d.VIS_B64(2) = d.VIS_B64(1);
515: d.VIS_B64(1) = s.VIS_B64(0);
516: //d.VIS_B64(0) = d.VIS_B64(0);
517:
518: DT0 = d.d;
519: }
520:
521: void helper_fmul8x16(void)
522: {
523: vis64 s, d;
524: uint32_t tmp;
525:
526: s.d = DT0;
527: d.d = DT1;
528:
529: #define PMUL(r) \
530: tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r); \
531: if ((tmp & 0xff) > 0x7f) \
532: tmp += 0x100; \
533: d.VIS_W64(r) = tmp >> 8;
534:
535: PMUL(0);
536: PMUL(1);
537: PMUL(2);
538: PMUL(3);
539: #undef PMUL
540:
541: DT0 = d.d;
542: }
543:
544: void helper_fmul8x16al(void)
545: {
546: vis64 s, d;
547: uint32_t tmp;
548:
549: s.d = DT0;
550: d.d = DT1;
551:
552: #define PMUL(r) \
553: tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r); \
554: if ((tmp & 0xff) > 0x7f) \
555: tmp += 0x100; \
556: d.VIS_W64(r) = tmp >> 8;
557:
558: PMUL(0);
559: PMUL(1);
560: PMUL(2);
561: PMUL(3);
562: #undef PMUL
563:
564: DT0 = d.d;
565: }
566:
567: void helper_fmul8x16au(void)
568: {
569: vis64 s, d;
570: uint32_t tmp;
571:
572: s.d = DT0;
573: d.d = DT1;
574:
575: #define PMUL(r) \
576: tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r); \
577: if ((tmp & 0xff) > 0x7f) \
578: tmp += 0x100; \
579: d.VIS_W64(r) = tmp >> 8;
580:
581: PMUL(0);
582: PMUL(1);
583: PMUL(2);
584: PMUL(3);
585: #undef PMUL
586:
587: DT0 = d.d;
588: }
589:
590: void helper_fmul8sux16(void)
591: {
592: vis64 s, d;
593: uint32_t tmp;
594:
595: s.d = DT0;
596: d.d = DT1;
597:
598: #define PMUL(r) \
599: tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \
600: if ((tmp & 0xff) > 0x7f) \
601: tmp += 0x100; \
602: d.VIS_W64(r) = tmp >> 8;
603:
604: PMUL(0);
605: PMUL(1);
606: PMUL(2);
607: PMUL(3);
608: #undef PMUL
609:
610: DT0 = d.d;
611: }
612:
613: void helper_fmul8ulx16(void)
614: {
615: vis64 s, d;
616: uint32_t tmp;
617:
618: s.d = DT0;
619: d.d = DT1;
620:
621: #define PMUL(r) \
622: tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \
623: if ((tmp & 0xff) > 0x7f) \
624: tmp += 0x100; \
625: d.VIS_W64(r) = tmp >> 8;
626:
627: PMUL(0);
628: PMUL(1);
629: PMUL(2);
630: PMUL(3);
631: #undef PMUL
632:
633: DT0 = d.d;
634: }
635:
636: void helper_fmuld8sux16(void)
637: {
638: vis64 s, d;
639: uint32_t tmp;
640:
641: s.d = DT0;
642: d.d = DT1;
643:
644: #define PMUL(r) \
645: tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \
646: if ((tmp & 0xff) > 0x7f) \
647: tmp += 0x100; \
648: d.VIS_L64(r) = tmp;
649:
650: // Reverse calculation order to handle overlap
651: PMUL(1);
652: PMUL(0);
653: #undef PMUL
654:
655: DT0 = d.d;
656: }
657:
658: void helper_fmuld8ulx16(void)
659: {
660: vis64 s, d;
661: uint32_t tmp;
662:
663: s.d = DT0;
664: d.d = DT1;
665:
666: #define PMUL(r) \
667: tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \
668: if ((tmp & 0xff) > 0x7f) \
669: tmp += 0x100; \
670: d.VIS_L64(r) = tmp;
671:
672: // Reverse calculation order to handle overlap
673: PMUL(1);
674: PMUL(0);
675: #undef PMUL
676:
677: DT0 = d.d;
678: }
679:
680: void helper_fexpand(void)
681: {
682: vis32 s;
683: vis64 d;
684:
685: s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff);
686: d.d = DT1;
687: d.VIS_W64(0) = s.VIS_B32(0) << 4;
688: d.VIS_W64(1) = s.VIS_B32(1) << 4;
689: d.VIS_W64(2) = s.VIS_B32(2) << 4;
690: d.VIS_W64(3) = s.VIS_B32(3) << 4;
691:
692: DT0 = d.d;
693: }
694:
695: #define VIS_HELPER(name, F) \
696: void name##16(void) \
697: { \
698: vis64 s, d; \
699: \
700: s.d = DT0; \
701: d.d = DT1; \
702: \
703: d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0)); \
704: d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1)); \
705: d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2)); \
706: d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3)); \
707: \
708: DT0 = d.d; \
709: } \
710: \
711: uint32_t name##16s(uint32_t src1, uint32_t src2) \
712: { \
713: vis32 s, d; \
714: \
715: s.l = src1; \
716: d.l = src2; \
717: \
718: d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0)); \
719: d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1)); \
720: \
721: return d.l; \
722: } \
723: \
724: void name##32(void) \
725: { \
726: vis64 s, d; \
727: \
728: s.d = DT0; \
729: d.d = DT1; \
730: \
731: d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0)); \
732: d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1)); \
733: \
734: DT0 = d.d; \
735: } \
736: \
737: uint32_t name##32s(uint32_t src1, uint32_t src2) \
738: { \
739: vis32 s, d; \
740: \
741: s.l = src1; \
742: d.l = src2; \
743: \
744: d.l = F(d.l, s.l); \
745: \
746: return d.l; \
747: }
748:
749: #define FADD(a, b) ((a) + (b))
750: #define FSUB(a, b) ((a) - (b))
751: VIS_HELPER(helper_fpadd, FADD)
752: VIS_HELPER(helper_fpsub, FSUB)
753:
754: #define VIS_CMPHELPER(name, F) \
755: void name##16(void) \
756: { \
757: vis64 s, d; \
758: \
759: s.d = DT0; \
760: d.d = DT1; \
761: \
762: d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0))? 1: 0; \
763: d.VIS_W64(0) |= F(d.VIS_W64(1), s.VIS_W64(1))? 2: 0; \
764: d.VIS_W64(0) |= F(d.VIS_W64(2), s.VIS_W64(2))? 4: 0; \
765: d.VIS_W64(0) |= F(d.VIS_W64(3), s.VIS_W64(3))? 8: 0; \
766: \
767: DT0 = d.d; \
768: } \
769: \
770: void name##32(void) \
771: { \
772: vis64 s, d; \
773: \
774: s.d = DT0; \
775: d.d = DT1; \
776: \
777: d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0))? 1: 0; \
778: d.VIS_L64(0) |= F(d.VIS_L64(1), s.VIS_L64(1))? 2: 0; \
779: \
780: DT0 = d.d; \
781: }
782:
783: #define FCMPGT(a, b) ((a) > (b))
784: #define FCMPEQ(a, b) ((a) == (b))
785: #define FCMPLE(a, b) ((a) <= (b))
786: #define FCMPNE(a, b) ((a) != (b))
787:
788: VIS_CMPHELPER(helper_fcmpgt, FCMPGT)
789: VIS_CMPHELPER(helper_fcmpeq, FCMPEQ)
790: VIS_CMPHELPER(helper_fcmple, FCMPLE)
791: VIS_CMPHELPER(helper_fcmpne, FCMPNE)
1.1.1.5 root 792: #endif
1.1 root 793:
1.1.1.6 root 794: void helper_check_ieee_exceptions(void)
795: {
796: target_ulong status;
797:
798: status = get_float_exception_flags(&env->fp_status);
799: if (status) {
800: /* Copy IEEE 754 flags into FSR */
801: if (status & float_flag_invalid)
802: env->fsr |= FSR_NVC;
803: if (status & float_flag_overflow)
804: env->fsr |= FSR_OFC;
805: if (status & float_flag_underflow)
806: env->fsr |= FSR_UFC;
807: if (status & float_flag_divbyzero)
808: env->fsr |= FSR_DZC;
809: if (status & float_flag_inexact)
810: env->fsr |= FSR_NXC;
811:
812: if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) {
813: /* Unmasked exception, generate a trap */
814: env->fsr |= FSR_FTT_IEEE_EXCP;
815: raise_exception(TT_FP_EXCP);
816: } else {
817: /* Accumulate exceptions */
818: env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
819: }
820: }
821: }
822:
823: void helper_clear_float_exceptions(void)
824: {
825: set_float_exception_flags(0, &env->fp_status);
826: }
827:
828: float32 helper_fabss(float32 src)
1.1 root 829: {
1.1.1.6 root 830: return float32_abs(src);
1.1 root 831: }
832:
833: #ifdef TARGET_SPARC64
1.1.1.6 root 834: void helper_fabsd(void)
1.1 root 835: {
836: DT0 = float64_abs(DT1);
837: }
1.1.1.5 root 838:
1.1.1.6 root 839: void helper_fabsq(void)
1.1.1.5 root 840: {
841: QT0 = float128_abs(QT1);
842: }
843: #endif
1.1 root 844:
1.1.1.6 root 845: float32 helper_fsqrts(float32 src)
1.1 root 846: {
1.1.1.6 root 847: return float32_sqrt(src, &env->fp_status);
1.1 root 848: }
849:
1.1.1.6 root 850: void helper_fsqrtd(void)
1.1 root 851: {
852: DT0 = float64_sqrt(DT1, &env->fp_status);
853: }
854:
1.1.1.6 root 855: void helper_fsqrtq(void)
1.1.1.5 root 856: {
857: QT0 = float128_sqrt(QT1, &env->fp_status);
858: }
859:
860: #define GEN_FCMP(name, size, reg1, reg2, FS, TRAP) \
1.1.1.6 root 861: void glue(helper_, name) (void) \
1.1.1.3 root 862: { \
1.1.1.6 root 863: target_ulong new_fsr; \
864: \
1.1.1.3 root 865: env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
866: switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \
867: case float_relation_unordered: \
1.1.1.6 root 868: new_fsr = (FSR_FCC1 | FSR_FCC0) << FS; \
869: if ((env->fsr & FSR_NVM) || TRAP) { \
870: env->fsr |= new_fsr; \
871: env->fsr |= FSR_NVC; \
872: env->fsr |= FSR_FTT_IEEE_EXCP; \
873: raise_exception(TT_FP_EXCP); \
874: } else { \
875: env->fsr |= FSR_NVA; \
876: } \
877: break; \
878: case float_relation_less: \
879: new_fsr = FSR_FCC0 << FS; \
880: break; \
881: case float_relation_greater: \
882: new_fsr = FSR_FCC1 << FS; \
883: break; \
884: default: \
885: new_fsr = 0; \
886: break; \
887: } \
888: env->fsr |= new_fsr; \
889: }
890: #define GEN_FCMPS(name, size, FS, TRAP) \
891: void glue(helper_, name)(float32 src1, float32 src2) \
892: { \
893: target_ulong new_fsr; \
894: \
895: env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
896: switch (glue(size, _compare) (src1, src2, &env->fp_status)) { \
897: case float_relation_unordered: \
898: new_fsr = (FSR_FCC1 | FSR_FCC0) << FS; \
1.1.1.5 root 899: if ((env->fsr & FSR_NVM) || TRAP) { \
1.1.1.6 root 900: env->fsr |= new_fsr; \
1.1.1.5 root 901: env->fsr |= FSR_NVC; \
902: env->fsr |= FSR_FTT_IEEE_EXCP; \
1.1.1.3 root 903: raise_exception(TT_FP_EXCP); \
904: } else { \
905: env->fsr |= FSR_NVA; \
906: } \
907: break; \
908: case float_relation_less: \
1.1.1.6 root 909: new_fsr = FSR_FCC0 << FS; \
1.1.1.3 root 910: break; \
911: case float_relation_greater: \
1.1.1.6 root 912: new_fsr = FSR_FCC1 << FS; \
1.1.1.3 root 913: break; \
914: default: \
1.1.1.6 root 915: new_fsr = 0; \
1.1.1.3 root 916: break; \
917: } \
1.1.1.6 root 918: env->fsr |= new_fsr; \
1.1 root 919: }
920:
1.1.1.6 root 921: GEN_FCMPS(fcmps, float32, 0, 0);
1.1.1.5 root 922: GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
923:
1.1.1.6 root 924: GEN_FCMPS(fcmpes, float32, 0, 1);
1.1.1.5 root 925: GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
926:
927: GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0);
928: GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1);
1.1 root 929:
1.1.1.7 root 930: static uint32_t compute_all_flags(void)
931: {
932: return env->psr & PSR_ICC;
933: }
934:
935: static uint32_t compute_C_flags(void)
936: {
937: return env->psr & PSR_CARRY;
938: }
939:
1.1.1.9 ! root 940: static inline uint32_t get_NZ_icc(int32_t dst)
1.1.1.7 root 941: {
942: uint32_t ret = 0;
943:
1.1.1.9 ! root 944: if (dst == 0) {
! 945: ret = PSR_ZERO;
! 946: } else if (dst < 0) {
! 947: ret = PSR_NEG;
! 948: }
1.1.1.7 root 949: return ret;
950: }
951:
952: #ifdef TARGET_SPARC64
953: static uint32_t compute_all_flags_xcc(void)
954: {
955: return env->xcc & PSR_ICC;
956: }
957:
958: static uint32_t compute_C_flags_xcc(void)
959: {
960: return env->xcc & PSR_CARRY;
961: }
962:
1.1.1.9 ! root 963: static inline uint32_t get_NZ_xcc(target_long dst)
1.1.1.7 root 964: {
965: uint32_t ret = 0;
966:
1.1.1.9 ! root 967: if (!dst) {
! 968: ret = PSR_ZERO;
! 969: } else if (dst < 0) {
! 970: ret = PSR_NEG;
! 971: }
1.1.1.7 root 972: return ret;
973: }
974: #endif
975:
976: static inline uint32_t get_V_div_icc(target_ulong src2)
977: {
978: uint32_t ret = 0;
979:
1.1.1.9 ! root 980: if (src2 != 0) {
! 981: ret = PSR_OVF;
! 982: }
1.1.1.7 root 983: return ret;
984: }
985:
986: static uint32_t compute_all_div(void)
987: {
988: uint32_t ret;
989:
990: ret = get_NZ_icc(CC_DST);
991: ret |= get_V_div_icc(CC_SRC2);
992: return ret;
993: }
994:
995: static uint32_t compute_C_div(void)
996: {
997: return 0;
998: }
999:
1.1.1.9 ! root 1000: static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1)
1.1.1.7 root 1001: {
1002: uint32_t ret = 0;
1003:
1.1.1.9 ! root 1004: if (dst < src1) {
! 1005: ret = PSR_CARRY;
! 1006: }
1.1.1.7 root 1007: return ret;
1008: }
1009:
1.1.1.9 ! root 1010: static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1,
! 1011: uint32_t src2)
! 1012: {
! 1013: uint32_t ret = 0;
! 1014:
! 1015: if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) {
! 1016: ret = PSR_CARRY;
! 1017: }
! 1018: return ret;
! 1019: }
! 1020:
! 1021: static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1,
! 1022: uint32_t src2)
1.1.1.7 root 1023: {
1024: uint32_t ret = 0;
1025:
1.1.1.9 ! root 1026: if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) {
! 1027: ret = PSR_OVF;
! 1028: }
1.1.1.7 root 1029: return ret;
1030: }
1031:
1032: #ifdef TARGET_SPARC64
1033: static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1)
1034: {
1035: uint32_t ret = 0;
1036:
1.1.1.9 ! root 1037: if (dst < src1) {
! 1038: ret = PSR_CARRY;
! 1039: }
! 1040: return ret;
! 1041: }
! 1042:
! 1043: static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1,
! 1044: target_ulong src2)
! 1045: {
! 1046: uint32_t ret = 0;
! 1047:
! 1048: if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) {
! 1049: ret = PSR_CARRY;
! 1050: }
1.1.1.7 root 1051: return ret;
1052: }
1053:
1054: static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1,
1055: target_ulong src2)
1056: {
1057: uint32_t ret = 0;
1058:
1.1.1.9 ! root 1059: if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) {
! 1060: ret = PSR_OVF;
! 1061: }
1.1.1.7 root 1062: return ret;
1063: }
1064:
1065: static uint32_t compute_all_add_xcc(void)
1066: {
1067: uint32_t ret;
1068:
1069: ret = get_NZ_xcc(CC_DST);
1070: ret |= get_C_add_xcc(CC_DST, CC_SRC);
1071: ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
1072: return ret;
1073: }
1074:
1075: static uint32_t compute_C_add_xcc(void)
1076: {
1077: return get_C_add_xcc(CC_DST, CC_SRC);
1078: }
1079: #endif
1080:
1.1.1.8 root 1081: static uint32_t compute_all_add(void)
1.1.1.7 root 1082: {
1083: uint32_t ret;
1084:
1085: ret = get_NZ_icc(CC_DST);
1.1.1.9 ! root 1086: ret |= get_C_add_icc(CC_DST, CC_SRC);
1.1.1.7 root 1087: ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
1088: return ret;
1089: }
1090:
1.1.1.8 root 1091: static uint32_t compute_C_add(void)
1.1.1.7 root 1092: {
1.1.1.9 ! root 1093: return get_C_add_icc(CC_DST, CC_SRC);
1.1.1.7 root 1094: }
1095:
1096: #ifdef TARGET_SPARC64
1097: static uint32_t compute_all_addx_xcc(void)
1098: {
1099: uint32_t ret;
1100:
1101: ret = get_NZ_xcc(CC_DST);
1.1.1.9 ! root 1102: ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
1.1.1.7 root 1103: ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2);
1104: return ret;
1105: }
1106:
1107: static uint32_t compute_C_addx_xcc(void)
1108: {
1109: uint32_t ret;
1110:
1.1.1.9 ! root 1111: ret = get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2);
1.1.1.7 root 1112: return ret;
1113: }
1114: #endif
1115:
1.1.1.9 ! root 1116: static uint32_t compute_all_addx(void)
! 1117: {
! 1118: uint32_t ret;
! 1119:
! 1120: ret = get_NZ_icc(CC_DST);
! 1121: ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
! 1122: ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
! 1123: return ret;
! 1124: }
! 1125:
! 1126: static uint32_t compute_C_addx(void)
! 1127: {
! 1128: uint32_t ret;
! 1129:
! 1130: ret = get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2);
! 1131: return ret;
! 1132: }
! 1133:
1.1.1.7 root 1134: static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2)
1135: {
1136: uint32_t ret = 0;
1137:
1.1.1.9 ! root 1138: if ((src1 | src2) & 0x3) {
! 1139: ret = PSR_OVF;
! 1140: }
1.1.1.7 root 1141: return ret;
1142: }
1143:
1144: static uint32_t compute_all_tadd(void)
1145: {
1146: uint32_t ret;
1147:
1148: ret = get_NZ_icc(CC_DST);
1.1.1.9 ! root 1149: ret |= get_C_add_icc(CC_DST, CC_SRC);
1.1.1.7 root 1150: ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2);
1151: ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
1152: return ret;
1153: }
1154:
1155: static uint32_t compute_all_taddtv(void)
1156: {
1157: uint32_t ret;
1158:
1159: ret = get_NZ_icc(CC_DST);
1.1.1.9 ! root 1160: ret |= get_C_add_icc(CC_DST, CC_SRC);
1.1.1.7 root 1161: return ret;
1162: }
1163:
1.1.1.9 ! root 1164: static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2)
1.1.1.7 root 1165: {
1.1.1.9 ! root 1166: uint32_t ret = 0;
! 1167:
! 1168: if (src1 < src2) {
! 1169: ret = PSR_CARRY;
! 1170: }
! 1171: return ret;
1.1.1.7 root 1172: }
1173:
1.1.1.9 ! root 1174: static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1,
! 1175: uint32_t src2)
1.1.1.7 root 1176: {
1177: uint32_t ret = 0;
1178:
1.1.1.9 ! root 1179: if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) {
! 1180: ret = PSR_CARRY;
! 1181: }
1.1.1.7 root 1182: return ret;
1183: }
1184:
1.1.1.9 ! root 1185: static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1,
! 1186: uint32_t src2)
1.1.1.7 root 1187: {
1188: uint32_t ret = 0;
1189:
1.1.1.9 ! root 1190: if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) {
! 1191: ret = PSR_OVF;
! 1192: }
1.1.1.7 root 1193: return ret;
1194: }
1195:
1196:
1197: #ifdef TARGET_SPARC64
1198: static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2)
1199: {
1200: uint32_t ret = 0;
1201:
1.1.1.9 ! root 1202: if (src1 < src2) {
! 1203: ret = PSR_CARRY;
! 1204: }
! 1205: return ret;
! 1206: }
! 1207:
! 1208: static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1,
! 1209: target_ulong src2)
! 1210: {
! 1211: uint32_t ret = 0;
! 1212:
! 1213: if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) {
! 1214: ret = PSR_CARRY;
! 1215: }
1.1.1.7 root 1216: return ret;
1217: }
1218:
1219: static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1,
1220: target_ulong src2)
1221: {
1222: uint32_t ret = 0;
1223:
1.1.1.9 ! root 1224: if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) {
! 1225: ret = PSR_OVF;
! 1226: }
1.1.1.7 root 1227: return ret;
1228: }
1229:
1230: static uint32_t compute_all_sub_xcc(void)
1231: {
1232: uint32_t ret;
1233:
1234: ret = get_NZ_xcc(CC_DST);
1235: ret |= get_C_sub_xcc(CC_SRC, CC_SRC2);
1236: ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
1237: return ret;
1238: }
1239:
1240: static uint32_t compute_C_sub_xcc(void)
1241: {
1242: return get_C_sub_xcc(CC_SRC, CC_SRC2);
1243: }
1244: #endif
1245:
1.1.1.8 root 1246: static uint32_t compute_all_sub(void)
1.1.1.7 root 1247: {
1248: uint32_t ret;
1249:
1250: ret = get_NZ_icc(CC_DST);
1.1.1.9 ! root 1251: ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
1.1.1.7 root 1252: ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
1253: return ret;
1254: }
1255:
1.1.1.8 root 1256: static uint32_t compute_C_sub(void)
1.1.1.7 root 1257: {
1.1.1.9 ! root 1258: return get_C_sub_icc(CC_SRC, CC_SRC2);
1.1.1.7 root 1259: }
1260:
1261: #ifdef TARGET_SPARC64
1262: static uint32_t compute_all_subx_xcc(void)
1263: {
1264: uint32_t ret;
1265:
1266: ret = get_NZ_xcc(CC_DST);
1.1.1.9 ! root 1267: ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
1.1.1.7 root 1268: ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2);
1269: return ret;
1270: }
1271:
1272: static uint32_t compute_C_subx_xcc(void)
1273: {
1274: uint32_t ret;
1275:
1.1.1.9 ! root 1276: ret = get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2);
1.1.1.7 root 1277: return ret;
1278: }
1279: #endif
1280:
1.1.1.9 ! root 1281: static uint32_t compute_all_subx(void)
1.1.1.7 root 1282: {
1283: uint32_t ret;
1284:
1285: ret = get_NZ_icc(CC_DST);
1.1.1.9 ! root 1286: ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
1.1.1.7 root 1287: ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
1288: return ret;
1289: }
1290:
1.1.1.9 ! root 1291: static uint32_t compute_C_subx(void)
1.1.1.7 root 1292: {
1.1.1.9 ! root 1293: uint32_t ret;
! 1294:
! 1295: ret = get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2);
! 1296: return ret;
1.1.1.7 root 1297: }
1298:
1.1.1.9 ! root 1299: static uint32_t compute_all_tsub(void)
1.1.1.7 root 1300: {
1301: uint32_t ret;
1302:
1303: ret = get_NZ_icc(CC_DST);
1.1.1.9 ! root 1304: ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
! 1305: ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2);
! 1306: ret |= get_V_tag_icc(CC_SRC, CC_SRC2);
1.1.1.7 root 1307: return ret;
1308: }
1309:
1.1.1.9 ! root 1310: static uint32_t compute_all_tsubtv(void)
1.1.1.7 root 1311: {
1.1.1.9 ! root 1312: uint32_t ret;
! 1313:
! 1314: ret = get_NZ_icc(CC_DST);
! 1315: ret |= get_C_sub_icc(CC_SRC, CC_SRC2);
! 1316: return ret;
1.1.1.7 root 1317: }
1318:
1319: static uint32_t compute_all_logic(void)
1320: {
1321: return get_NZ_icc(CC_DST);
1322: }
1323:
1324: static uint32_t compute_C_logic(void)
1325: {
1326: return 0;
1327: }
1328:
1329: #ifdef TARGET_SPARC64
1330: static uint32_t compute_all_logic_xcc(void)
1331: {
1332: return get_NZ_xcc(CC_DST);
1333: }
1334: #endif
1335:
1336: typedef struct CCTable {
1337: uint32_t (*compute_all)(void); /* return all the flags */
1338: uint32_t (*compute_c)(void); /* return the C flag */
1339: } CCTable;
1340:
1341: static const CCTable icc_table[CC_OP_NB] = {
1342: /* CC_OP_DYNAMIC should never happen */
1343: [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags },
1344: [CC_OP_DIV] = { compute_all_div, compute_C_div },
1345: [CC_OP_ADD] = { compute_all_add, compute_C_add },
1.1.1.9 ! root 1346: [CC_OP_ADDX] = { compute_all_addx, compute_C_addx },
! 1347: [CC_OP_TADD] = { compute_all_tadd, compute_C_add },
! 1348: [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add },
1.1.1.7 root 1349: [CC_OP_SUB] = { compute_all_sub, compute_C_sub },
1.1.1.9 ! root 1350: [CC_OP_SUBX] = { compute_all_subx, compute_C_subx },
! 1351: [CC_OP_TSUB] = { compute_all_tsub, compute_C_sub },
! 1352: [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub },
1.1.1.7 root 1353: [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic },
1354: };
1355:
1356: #ifdef TARGET_SPARC64
1357: static const CCTable xcc_table[CC_OP_NB] = {
1358: /* CC_OP_DYNAMIC should never happen */
1359: [CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc },
1360: [CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic },
1361: [CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc },
1362: [CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc },
1363: [CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc },
1364: [CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc },
1365: [CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
1366: [CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc },
1367: [CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc },
1368: [CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc },
1369: [CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic },
1370: };
1371: #endif
1372:
1373: void helper_compute_psr(void)
1374: {
1375: uint32_t new_psr;
1376:
1377: new_psr = icc_table[CC_OP].compute_all();
1378: env->psr = new_psr;
1379: #ifdef TARGET_SPARC64
1380: new_psr = xcc_table[CC_OP].compute_all();
1381: env->xcc = new_psr;
1382: #endif
1383: CC_OP = CC_OP_FLAGS;
1384: }
1385:
1386: uint32_t helper_compute_C_icc(void)
1387: {
1388: uint32_t ret;
1389:
1390: ret = icc_table[CC_OP].compute_c() >> PSR_CARRY_SHIFT;
1391: return ret;
1392: }
1393:
1.1.1.9 ! root 1394: static inline void memcpy32(target_ulong *dst, const target_ulong *src)
! 1395: {
! 1396: dst[0] = src[0];
! 1397: dst[1] = src[1];
! 1398: dst[2] = src[2];
! 1399: dst[3] = src[3];
! 1400: dst[4] = src[4];
! 1401: dst[5] = src[5];
! 1402: dst[6] = src[6];
! 1403: dst[7] = src[7];
! 1404: }
! 1405:
! 1406: static void set_cwp(int new_cwp)
! 1407: {
! 1408: /* put the modified wrap registers at their proper location */
! 1409: if (env->cwp == env->nwindows - 1) {
! 1410: memcpy32(env->regbase, env->regbase + env->nwindows * 16);
! 1411: }
! 1412: env->cwp = new_cwp;
! 1413:
! 1414: /* put the wrap registers at their temporary location */
! 1415: if (new_cwp == env->nwindows - 1) {
! 1416: memcpy32(env->regbase + env->nwindows * 16, env->regbase);
! 1417: }
! 1418: env->regwptr = env->regbase + (new_cwp * 16);
! 1419: }
! 1420:
! 1421: void cpu_set_cwp(CPUState *env1, int new_cwp)
! 1422: {
! 1423: CPUState *saved_env;
! 1424:
! 1425: saved_env = env;
! 1426: env = env1;
! 1427: set_cwp(new_cwp);
! 1428: env = saved_env;
! 1429: }
! 1430:
! 1431: static target_ulong get_psr(void)
! 1432: {
! 1433: helper_compute_psr();
! 1434:
! 1435: #if !defined (TARGET_SPARC64)
! 1436: return env->version | (env->psr & PSR_ICC) |
! 1437: (env->psref? PSR_EF : 0) |
! 1438: (env->psrpil << 8) |
! 1439: (env->psrs? PSR_S : 0) |
! 1440: (env->psrps? PSR_PS : 0) |
! 1441: (env->psret? PSR_ET : 0) | env->cwp;
! 1442: #else
! 1443: return env->psr & PSR_ICC;
! 1444: #endif
! 1445: }
! 1446:
! 1447: target_ulong cpu_get_psr(CPUState *env1)
! 1448: {
! 1449: CPUState *saved_env;
! 1450: target_ulong ret;
! 1451:
! 1452: saved_env = env;
! 1453: env = env1;
! 1454: ret = get_psr();
! 1455: env = saved_env;
! 1456: return ret;
! 1457: }
! 1458:
! 1459: static void put_psr(target_ulong val)
! 1460: {
! 1461: env->psr = val & PSR_ICC;
! 1462: #if !defined (TARGET_SPARC64)
! 1463: env->psref = (val & PSR_EF)? 1 : 0;
! 1464: env->psrpil = (val & PSR_PIL) >> 8;
! 1465: #endif
! 1466: #if ((!defined (TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY))
! 1467: cpu_check_irqs(env);
! 1468: #endif
! 1469: #if !defined (TARGET_SPARC64)
! 1470: env->psrs = (val & PSR_S)? 1 : 0;
! 1471: env->psrps = (val & PSR_PS)? 1 : 0;
! 1472: env->psret = (val & PSR_ET)? 1 : 0;
! 1473: set_cwp(val & PSR_CWP);
! 1474: #endif
! 1475: env->cc_op = CC_OP_FLAGS;
! 1476: }
! 1477:
! 1478: void cpu_put_psr(CPUState *env1, target_ulong val)
! 1479: {
! 1480: CPUState *saved_env;
! 1481:
! 1482: saved_env = env;
! 1483: env = env1;
! 1484: put_psr(val);
! 1485: env = saved_env;
! 1486: }
! 1487:
! 1488: static int cwp_inc(int cwp)
! 1489: {
! 1490: if (unlikely(cwp >= env->nwindows)) {
! 1491: cwp -= env->nwindows;
! 1492: }
! 1493: return cwp;
! 1494: }
! 1495:
! 1496: int cpu_cwp_inc(CPUState *env1, int cwp)
! 1497: {
! 1498: CPUState *saved_env;
! 1499: target_ulong ret;
! 1500:
! 1501: saved_env = env;
! 1502: env = env1;
! 1503: ret = cwp_inc(cwp);
! 1504: env = saved_env;
! 1505: return ret;
! 1506: }
! 1507:
! 1508: static int cwp_dec(int cwp)
! 1509: {
! 1510: if (unlikely(cwp < 0)) {
! 1511: cwp += env->nwindows;
! 1512: }
! 1513: return cwp;
! 1514: }
! 1515:
! 1516: int cpu_cwp_dec(CPUState *env1, int cwp)
! 1517: {
! 1518: CPUState *saved_env;
! 1519: target_ulong ret;
! 1520:
! 1521: saved_env = env;
! 1522: env = env1;
! 1523: ret = cwp_dec(cwp);
! 1524: env = saved_env;
! 1525: return ret;
! 1526: }
! 1527:
1.1 root 1528: #ifdef TARGET_SPARC64
1.1.1.6 root 1529: GEN_FCMPS(fcmps_fcc1, float32, 22, 0);
1.1.1.5 root 1530: GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
1.1.1.6 root 1531: GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0);
1.1 root 1532:
1.1.1.6 root 1533: GEN_FCMPS(fcmps_fcc2, float32, 24, 0);
1.1.1.5 root 1534: GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
1.1.1.6 root 1535: GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0);
1.1 root 1536:
1.1.1.6 root 1537: GEN_FCMPS(fcmps_fcc3, float32, 26, 0);
1.1.1.5 root 1538: GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
1.1.1.6 root 1539: GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0);
1.1.1.5 root 1540:
1.1.1.6 root 1541: GEN_FCMPS(fcmpes_fcc1, float32, 22, 1);
1.1.1.5 root 1542: GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
1.1.1.6 root 1543: GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1);
1.1.1.5 root 1544:
1.1.1.6 root 1545: GEN_FCMPS(fcmpes_fcc2, float32, 24, 1);
1.1.1.5 root 1546: GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
1.1.1.6 root 1547: GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1);
1.1.1.5 root 1548:
1.1.1.6 root 1549: GEN_FCMPS(fcmpes_fcc3, float32, 26, 1);
1.1.1.5 root 1550: GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
1551: GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1);
1552: #endif
1.1.1.6 root 1553: #undef GEN_FCMPS
1.1.1.5 root 1554:
1.1.1.6 root 1555: #if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && \
1556: defined(DEBUG_MXCC)
1.1.1.5 root 1557: static void dump_mxcc(CPUState *env)
1.1.1.2 root 1558: {
1.1.1.7 root 1559: printf("mxccdata: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
1560: "\n",
1.1.1.6 root 1561: env->mxccdata[0], env->mxccdata[1],
1562: env->mxccdata[2], env->mxccdata[3]);
1.1.1.7 root 1563: printf("mxccregs: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
1564: "\n"
1565: " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64
1566: "\n",
1.1.1.6 root 1567: env->mxccregs[0], env->mxccregs[1],
1568: env->mxccregs[2], env->mxccregs[3],
1569: env->mxccregs[4], env->mxccregs[5],
1570: env->mxccregs[6], env->mxccregs[7]);
1.1.1.2 root 1571: }
1.1.1.5 root 1572: #endif
1.1.1.2 root 1573:
1.1.1.6 root 1574: #if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)) \
1575: && defined(DEBUG_ASI)
1576: static void dump_asi(const char *txt, target_ulong addr, int asi, int size,
1577: uint64_t r1)
1.1.1.5 root 1578: {
1579: switch (size)
1580: {
1581: case 1:
1.1.1.6 root 1582: DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt,
1583: addr, asi, r1 & 0xff);
1.1.1.5 root 1584: break;
1585: case 2:
1.1.1.6 root 1586: DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %04" PRIx64 "\n", txt,
1587: addr, asi, r1 & 0xffff);
1.1.1.5 root 1588: break;
1589: case 4:
1.1.1.6 root 1590: DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %08" PRIx64 "\n", txt,
1591: addr, asi, r1 & 0xffffffff);
1.1.1.5 root 1592: break;
1593: case 8:
1.1.1.6 root 1594: DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %016" PRIx64 "\n", txt,
1595: addr, asi, r1);
1.1.1.5 root 1596: break;
1597: }
1.1.1.2 root 1598: }
1.1.1.5 root 1599: #endif
1600:
1.1.1.6 root 1601: #ifndef TARGET_SPARC64
1602: #ifndef CONFIG_USER_ONLY
1603: uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
1.1 root 1604: {
1.1.1.6 root 1605: uint64_t ret = 0;
1.1.1.5 root 1606: #if defined(DEBUG_MXCC) || defined(DEBUG_ASI)
1.1.1.6 root 1607: uint32_t last_addr = addr;
1.1.1.5 root 1608: #endif
1.1 root 1609:
1.1.1.6 root 1610: helper_check_align(addr, size - 1);
1.1 root 1611: switch (asi) {
1.1.1.5 root 1612: case 2: /* SuperSparc MXCC registers */
1.1.1.6 root 1613: switch (addr) {
1.1.1.5 root 1614: case 0x01c00a00: /* MXCC control register */
1.1.1.6 root 1615: if (size == 8)
1616: ret = env->mxccregs[3];
1617: else
1618: DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
1619: size);
1.1.1.5 root 1620: break;
1621: case 0x01c00a04: /* MXCC control register */
1622: if (size == 4)
1623: ret = env->mxccregs[3];
1624: else
1.1.1.6 root 1625: DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
1626: size);
1.1.1.5 root 1627: break;
1628: case 0x01c00c00: /* Module reset register */
1629: if (size == 8) {
1.1.1.6 root 1630: ret = env->mxccregs[5];
1.1.1.5 root 1631: // should we do something here?
1632: } else
1.1.1.6 root 1633: DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
1634: size);
1.1.1.5 root 1635: break;
1636: case 0x01c00f00: /* MBus port address register */
1.1.1.6 root 1637: if (size == 8)
1638: ret = env->mxccregs[7];
1639: else
1640: DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
1641: size);
1.1.1.5 root 1642: break;
1643: default:
1.1.1.6 root 1644: DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
1645: size);
1.1.1.5 root 1646: break;
1647: }
1.1.1.6 root 1648: DPRINTF_MXCC("asi = %d, size = %d, sign = %d, "
1649: "addr = %08x -> ret = %" PRIx64 ","
1650: "addr = %08x\n", asi, size, sign, last_addr, ret, addr);
1.1.1.5 root 1651: #ifdef DEBUG_MXCC
1652: dump_mxcc(env);
1653: #endif
1654: break;
1.1 root 1655: case 3: /* MMU probe */
1.1.1.5 root 1656: {
1657: int mmulev;
1.1 root 1658:
1.1.1.6 root 1659: mmulev = (addr >> 8) & 15;
1.1.1.5 root 1660: if (mmulev > 4)
1661: ret = 0;
1.1.1.6 root 1662: else
1663: ret = mmu_probe(env, addr, mmulev);
1664: DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n",
1665: addr, mmulev, ret);
1.1.1.5 root 1666: }
1667: break;
1.1 root 1668: case 4: /* read MMU regs */
1.1.1.5 root 1669: {
1.1.1.6 root 1670: int reg = (addr >> 8) & 0x1f;
1.1.1.5 root 1671:
1672: ret = env->mmuregs[reg];
1673: if (reg == 3) /* Fault status cleared on read */
1674: env->mmuregs[3] = 0;
1675: else if (reg == 0x13) /* Fault status read */
1676: ret = env->mmuregs[3];
1677: else if (reg == 0x14) /* Fault address read */
1678: ret = env->mmuregs[4];
1.1.1.6 root 1679: DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret);
1.1.1.5 root 1680: }
1681: break;
1682: case 5: // Turbosparc ITLB Diagnostic
1683: case 6: // Turbosparc DTLB Diagnostic
1684: case 7: // Turbosparc IOTLB Diagnostic
1685: break;
1686: case 9: /* Supervisor code access */
1687: switch(size) {
1688: case 1:
1.1.1.6 root 1689: ret = ldub_code(addr);
1.1.1.5 root 1690: break;
1691: case 2:
1.1.1.6 root 1692: ret = lduw_code(addr);
1.1.1.5 root 1693: break;
1694: default:
1695: case 4:
1.1.1.6 root 1696: ret = ldl_code(addr);
1.1.1.5 root 1697: break;
1698: case 8:
1.1.1.6 root 1699: ret = ldq_code(addr);
1.1.1.5 root 1700: break;
1701: }
1702: break;
1703: case 0xa: /* User data access */
1704: switch(size) {
1705: case 1:
1.1.1.6 root 1706: ret = ldub_user(addr);
1.1.1.5 root 1707: break;
1708: case 2:
1.1.1.6 root 1709: ret = lduw_user(addr);
1.1.1.5 root 1710: break;
1711: default:
1712: case 4:
1.1.1.6 root 1713: ret = ldl_user(addr);
1.1.1.5 root 1714: break;
1715: case 8:
1.1.1.6 root 1716: ret = ldq_user(addr);
1.1.1.5 root 1717: break;
1718: }
1719: break;
1720: case 0xb: /* Supervisor data access */
1721: switch(size) {
1722: case 1:
1.1.1.6 root 1723: ret = ldub_kernel(addr);
1.1.1.5 root 1724: break;
1725: case 2:
1.1.1.6 root 1726: ret = lduw_kernel(addr);
1.1.1.5 root 1727: break;
1728: default:
1729: case 4:
1.1.1.6 root 1730: ret = ldl_kernel(addr);
1.1.1.5 root 1731: break;
1732: case 8:
1.1.1.6 root 1733: ret = ldq_kernel(addr);
1.1.1.5 root 1734: break;
1735: }
1736: break;
1737: case 0xc: /* I-cache tag */
1738: case 0xd: /* I-cache data */
1739: case 0xe: /* D-cache tag */
1740: case 0xf: /* D-cache data */
1741: break;
1742: case 0x20: /* MMU passthrough */
1.1.1.2 root 1743: switch(size) {
1744: case 1:
1.1.1.6 root 1745: ret = ldub_phys(addr);
1.1.1.2 root 1746: break;
1747: case 2:
1.1.1.6 root 1748: ret = lduw_phys(addr);
1.1.1.2 root 1749: break;
1750: default:
1751: case 4:
1.1.1.6 root 1752: ret = ldl_phys(addr);
1.1.1.2 root 1753: break;
1754: case 8:
1.1.1.6 root 1755: ret = ldq_phys(addr);
1.1.1.5 root 1756: break;
1.1.1.2 root 1757: }
1.1.1.5 root 1758: break;
1759: case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
1760: switch(size) {
1761: case 1:
1.1.1.6 root 1762: ret = ldub_phys((target_phys_addr_t)addr
1.1.1.5 root 1763: | ((target_phys_addr_t)(asi & 0xf) << 32));
1764: break;
1765: case 2:
1.1.1.6 root 1766: ret = lduw_phys((target_phys_addr_t)addr
1.1.1.5 root 1767: | ((target_phys_addr_t)(asi & 0xf) << 32));
1768: break;
1769: default:
1770: case 4:
1.1.1.6 root 1771: ret = ldl_phys((target_phys_addr_t)addr
1.1.1.5 root 1772: | ((target_phys_addr_t)(asi & 0xf) << 32));
1773: break;
1774: case 8:
1.1.1.6 root 1775: ret = ldq_phys((target_phys_addr_t)addr
1.1.1.5 root 1776: | ((target_phys_addr_t)(asi & 0xf) << 32));
1777: break;
1778: }
1779: break;
1780: case 0x30: // Turbosparc secondary cache diagnostic
1781: case 0x31: // Turbosparc RAM snoop
1782: case 0x32: // Turbosparc page table descriptor diagnostic
1783: case 0x39: /* data cache diagnostic register */
1.1.1.9 ! root 1784: case 0x4c: /* SuperSPARC MMU Breakpoint Action register */
1.1.1.5 root 1785: ret = 0;
1786: break;
1.1.1.6 root 1787: case 0x38: /* SuperSPARC MMU Breakpoint Control Registers */
1788: {
1789: int reg = (addr >> 8) & 3;
1790:
1791: switch(reg) {
1792: case 0: /* Breakpoint Value (Addr) */
1793: ret = env->mmubpregs[reg];
1794: break;
1795: case 1: /* Breakpoint Mask */
1796: ret = env->mmubpregs[reg];
1797: break;
1798: case 2: /* Breakpoint Control */
1799: ret = env->mmubpregs[reg];
1800: break;
1801: case 3: /* Breakpoint Status */
1802: ret = env->mmubpregs[reg];
1803: env->mmubpregs[reg] = 0ULL;
1804: break;
1805: }
1.1.1.7 root 1806: DPRINTF_MMU("read breakpoint reg[%d] 0x%016" PRIx64 "\n", reg,
1807: ret);
1.1.1.6 root 1808: }
1809: break;
1.1.1.5 root 1810: case 8: /* User code access, XXX */
1.1 root 1811: default:
1.1.1.6 root 1812: do_unassigned_access(addr, 0, 0, asi, size);
1.1.1.5 root 1813: ret = 0;
1814: break;
1.1 root 1815: }
1.1.1.5 root 1816: if (sign) {
1817: switch(size) {
1818: case 1:
1.1.1.6 root 1819: ret = (int8_t) ret;
1.1.1.5 root 1820: break;
1821: case 2:
1.1.1.6 root 1822: ret = (int16_t) ret;
1823: break;
1824: case 4:
1825: ret = (int32_t) ret;
1.1.1.5 root 1826: break;
1827: default:
1828: break;
1829: }
1830: }
1831: #ifdef DEBUG_ASI
1.1.1.6 root 1832: dump_asi("read ", last_addr, asi, size, ret);
1.1.1.5 root 1833: #endif
1.1.1.6 root 1834: return ret;
1.1 root 1835: }
1836:
1.1.1.6 root 1837: void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size)
1.1 root 1838: {
1.1.1.6 root 1839: helper_check_align(addr, size - 1);
1.1 root 1840: switch(asi) {
1.1.1.5 root 1841: case 2: /* SuperSparc MXCC registers */
1.1.1.6 root 1842: switch (addr) {
1.1.1.5 root 1843: case 0x01c00000: /* MXCC stream data register 0 */
1844: if (size == 8)
1.1.1.6 root 1845: env->mxccdata[0] = val;
1.1.1.5 root 1846: else
1.1.1.6 root 1847: DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
1848: size);
1.1.1.5 root 1849: break;
1850: case 0x01c00008: /* MXCC stream data register 1 */
1851: if (size == 8)
1.1.1.6 root 1852: env->mxccdata[1] = val;
1.1.1.5 root 1853: else
1.1.1.6 root 1854: DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
1855: size);
1.1.1.5 root 1856: break;
1857: case 0x01c00010: /* MXCC stream data register 2 */
1858: if (size == 8)
1.1.1.6 root 1859: env->mxccdata[2] = val;
1.1.1.5 root 1860: else
1.1.1.6 root 1861: DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
1862: size);
1.1.1.5 root 1863: break;
1864: case 0x01c00018: /* MXCC stream data register 3 */
1865: if (size == 8)
1.1.1.6 root 1866: env->mxccdata[3] = val;
1.1.1.5 root 1867: else
1.1.1.6 root 1868: DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
1869: size);
1.1.1.5 root 1870: break;
1871: case 0x01c00100: /* MXCC stream source */
1872: if (size == 8)
1.1.1.6 root 1873: env->mxccregs[0] = val;
1.1.1.5 root 1874: else
1.1.1.6 root 1875: DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
1876: size);
1877: env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
1878: 0);
1879: env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
1880: 8);
1881: env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
1882: 16);
1883: env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) +
1884: 24);
1.1.1.5 root 1885: break;
1886: case 0x01c00200: /* MXCC stream destination */
1887: if (size == 8)
1.1.1.6 root 1888: env->mxccregs[1] = val;
1.1.1.5 root 1889: else
1.1.1.6 root 1890: DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
1891: size);
1892: stq_phys((env->mxccregs[1] & 0xffffffffULL) + 0,
1893: env->mxccdata[0]);
1894: stq_phys((env->mxccregs[1] & 0xffffffffULL) + 8,
1895: env->mxccdata[1]);
1896: stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16,
1897: env->mxccdata[2]);
1898: stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24,
1899: env->mxccdata[3]);
1.1.1.5 root 1900: break;
1901: case 0x01c00a00: /* MXCC control register */
1902: if (size == 8)
1.1.1.6 root 1903: env->mxccregs[3] = val;
1.1.1.5 root 1904: else
1.1.1.6 root 1905: DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
1906: size);
1.1.1.5 root 1907: break;
1908: case 0x01c00a04: /* MXCC control register */
1909: if (size == 4)
1.1.1.6 root 1910: env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL)
1911: | val;
1.1.1.5 root 1912: else
1.1.1.6 root 1913: DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
1914: size);
1.1.1.5 root 1915: break;
1916: case 0x01c00e00: /* MXCC error register */
1917: // writing a 1 bit clears the error
1918: if (size == 8)
1.1.1.6 root 1919: env->mxccregs[6] &= ~val;
1.1.1.5 root 1920: else
1.1.1.6 root 1921: DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
1922: size);
1.1.1.5 root 1923: break;
1924: case 0x01c00f00: /* MBus port address register */
1925: if (size == 8)
1.1.1.6 root 1926: env->mxccregs[7] = val;
1.1.1.5 root 1927: else
1.1.1.6 root 1928: DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr,
1929: size);
1.1.1.5 root 1930: break;
1931: default:
1.1.1.6 root 1932: DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr,
1933: size);
1.1.1.5 root 1934: break;
1935: }
1.1.1.6 root 1936: DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %" PRIx64 "\n",
1937: asi, size, addr, val);
1.1.1.5 root 1938: #ifdef DEBUG_MXCC
1939: dump_mxcc(env);
1940: #endif
1941: break;
1.1 root 1942: case 3: /* MMU flush */
1.1.1.5 root 1943: {
1944: int mmulev;
1.1 root 1945:
1.1.1.6 root 1946: mmulev = (addr >> 8) & 15;
1.1.1.5 root 1947: DPRINTF_MMU("mmu flush level %d\n", mmulev);
1948: switch (mmulev) {
1949: case 0: // flush page
1.1.1.6 root 1950: tlb_flush_page(env, addr & 0xfffff000);
1.1.1.5 root 1951: break;
1952: case 1: // flush segment (256k)
1953: case 2: // flush region (16M)
1954: case 3: // flush context (4G)
1955: case 4: // flush entire
1956: tlb_flush(env, 1);
1957: break;
1958: default:
1959: break;
1960: }
1.1 root 1961: #ifdef DEBUG_MMU
1.1.1.5 root 1962: dump_mmu(env);
1.1 root 1963: #endif
1.1.1.5 root 1964: }
1965: break;
1.1 root 1966: case 4: /* write MMU regs */
1.1.1.5 root 1967: {
1.1.1.6 root 1968: int reg = (addr >> 8) & 0x1f;
1.1.1.5 root 1969: uint32_t oldreg;
1970:
1971: oldreg = env->mmuregs[reg];
1.1 root 1972: switch(reg) {
1.1.1.6 root 1973: case 0: // Control Register
1.1.1.5 root 1974: env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) |
1.1.1.6 root 1975: (val & 0x00ffffff);
1.1.1.5 root 1976: // Mappings generated during no-fault mode or MMU
1977: // disabled mode are invalid in normal mode
1.1.1.6 root 1978: if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) !=
1979: (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm)))
1.1 root 1980: tlb_flush(env, 1);
1981: break;
1.1.1.6 root 1982: case 1: // Context Table Pointer Register
1983: env->mmuregs[reg] = val & env->def->mmu_ctpr_mask;
1984: break;
1985: case 2: // Context Register
1986: env->mmuregs[reg] = val & env->def->mmu_cxr_mask;
1.1 root 1987: if (oldreg != env->mmuregs[reg]) {
1988: /* we flush when the MMU context changes because
1989: QEMU has no MMU context support */
1990: tlb_flush(env, 1);
1991: }
1992: break;
1.1.1.6 root 1993: case 3: // Synchronous Fault Status Register with Clear
1994: case 4: // Synchronous Fault Address Register
1.1 root 1995: break;
1.1.1.6 root 1996: case 0x10: // TLB Replacement Control Register
1997: env->mmuregs[reg] = val & env->def->mmu_trcr_mask;
1.1.1.5 root 1998: break;
1.1.1.6 root 1999: case 0x13: // Synchronous Fault Status Register with Read and Clear
2000: env->mmuregs[3] = val & env->def->mmu_sfsr_mask;
2001: break;
2002: case 0x14: // Synchronous Fault Address Register
2003: env->mmuregs[4] = val;
1.1.1.5 root 2004: break;
1.1 root 2005: default:
1.1.1.6 root 2006: env->mmuregs[reg] = val;
1.1 root 2007: break;
2008: }
2009: if (oldreg != env->mmuregs[reg]) {
1.1.1.6 root 2010: DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n",
2011: reg, oldreg, env->mmuregs[reg]);
1.1 root 2012: }
1.1.1.5 root 2013: #ifdef DEBUG_MMU
2014: dump_mmu(env);
1.1 root 2015: #endif
1.1.1.5 root 2016: }
2017: break;
2018: case 5: // Turbosparc ITLB Diagnostic
2019: case 6: // Turbosparc DTLB Diagnostic
2020: case 7: // Turbosparc IOTLB Diagnostic
2021: break;
2022: case 0xa: /* User data access */
2023: switch(size) {
2024: case 1:
1.1.1.6 root 2025: stb_user(addr, val);
1.1.1.5 root 2026: break;
2027: case 2:
1.1.1.6 root 2028: stw_user(addr, val);
1.1.1.5 root 2029: break;
2030: default:
2031: case 4:
1.1.1.6 root 2032: stl_user(addr, val);
1.1.1.5 root 2033: break;
2034: case 8:
1.1.1.6 root 2035: stq_user(addr, val);
1.1.1.5 root 2036: break;
2037: }
2038: break;
2039: case 0xb: /* Supervisor data access */
2040: switch(size) {
2041: case 1:
1.1.1.6 root 2042: stb_kernel(addr, val);
1.1.1.5 root 2043: break;
2044: case 2:
1.1.1.6 root 2045: stw_kernel(addr, val);
1.1.1.5 root 2046: break;
2047: default:
2048: case 4:
1.1.1.6 root 2049: stl_kernel(addr, val);
1.1.1.5 root 2050: break;
2051: case 8:
1.1.1.6 root 2052: stq_kernel(addr, val);
1.1.1.5 root 2053: break;
2054: }
2055: break;
2056: case 0xc: /* I-cache tag */
2057: case 0xd: /* I-cache data */
2058: case 0xe: /* D-cache tag */
2059: case 0xf: /* D-cache data */
2060: case 0x10: /* I/D-cache flush page */
2061: case 0x11: /* I/D-cache flush segment */
2062: case 0x12: /* I/D-cache flush region */
2063: case 0x13: /* I/D-cache flush context */
2064: case 0x14: /* I/D-cache flush user */
2065: break;
1.1 root 2066: case 0x17: /* Block copy, sta access */
1.1.1.5 root 2067: {
1.1.1.6 root 2068: // val = src
2069: // addr = dst
1.1.1.5 root 2070: // copy 32 bytes
2071: unsigned int i;
1.1.1.6 root 2072: uint32_t src = val & ~3, dst = addr & ~3, temp;
1.1.1.5 root 2073:
2074: for (i = 0; i < 32; i += 4, src += 4, dst += 4) {
2075: temp = ldl_kernel(src);
2076: stl_kernel(dst, temp);
2077: }
2078: }
2079: break;
1.1 root 2080: case 0x1f: /* Block fill, stda access */
1.1.1.5 root 2081: {
1.1.1.6 root 2082: // addr = dst
2083: // fill 32 bytes with val
1.1.1.5 root 2084: unsigned int i;
1.1.1.6 root 2085: uint32_t dst = addr & 7;
1.1.1.5 root 2086:
2087: for (i = 0; i < 32; i += 8, dst += 8)
2088: stq_kernel(dst, val);
2089: }
2090: break;
2091: case 0x20: /* MMU passthrough */
2092: {
2093: switch(size) {
2094: case 1:
1.1.1.6 root 2095: stb_phys(addr, val);
1.1.1.5 root 2096: break;
2097: case 2:
1.1.1.6 root 2098: stw_phys(addr, val);
1.1.1.5 root 2099: break;
2100: case 4:
2101: default:
1.1.1.6 root 2102: stl_phys(addr, val);
1.1.1.5 root 2103: break;
2104: case 8:
1.1.1.6 root 2105: stq_phys(addr, val);
1.1.1.5 root 2106: break;
2107: }
2108: }
2109: break;
2110: case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */
2111: {
2112: switch(size) {
2113: case 1:
1.1.1.6 root 2114: stb_phys((target_phys_addr_t)addr
2115: | ((target_phys_addr_t)(asi & 0xf) << 32), val);
1.1.1.5 root 2116: break;
2117: case 2:
1.1.1.6 root 2118: stw_phys((target_phys_addr_t)addr
2119: | ((target_phys_addr_t)(asi & 0xf) << 32), val);
1.1.1.5 root 2120: break;
2121: case 4:
2122: default:
1.1.1.6 root 2123: stl_phys((target_phys_addr_t)addr
2124: | ((target_phys_addr_t)(asi & 0xf) << 32), val);
1.1.1.5 root 2125: break;
2126: case 8:
1.1.1.6 root 2127: stq_phys((target_phys_addr_t)addr
2128: | ((target_phys_addr_t)(asi & 0xf) << 32), val);
1.1.1.5 root 2129: break;
2130: }
2131: }
2132: break;
2133: case 0x30: // store buffer tags or Turbosparc secondary cache diagnostic
2134: case 0x31: // store buffer data, Ross RT620 I-cache flush or
2135: // Turbosparc snoop RAM
1.1.1.6 root 2136: case 0x32: // store buffer control or Turbosparc page table
2137: // descriptor diagnostic
1.1.1.5 root 2138: case 0x36: /* I-cache flash clear */
2139: case 0x37: /* D-cache flash clear */
2140: case 0x4c: /* breakpoint action */
2141: break;
1.1.1.6 root 2142: case 0x38: /* SuperSPARC MMU Breakpoint Control Registers*/
2143: {
2144: int reg = (addr >> 8) & 3;
2145:
2146: switch(reg) {
2147: case 0: /* Breakpoint Value (Addr) */
2148: env->mmubpregs[reg] = (val & 0xfffffffffULL);
2149: break;
2150: case 1: /* Breakpoint Mask */
2151: env->mmubpregs[reg] = (val & 0xfffffffffULL);
2152: break;
2153: case 2: /* Breakpoint Control */
2154: env->mmubpregs[reg] = (val & 0x7fULL);
2155: break;
2156: case 3: /* Breakpoint Status */
2157: env->mmubpregs[reg] = (val & 0xfULL);
2158: break;
2159: }
1.1.1.7 root 2160: DPRINTF_MMU("write breakpoint reg[%d] 0x%016x\n", reg,
1.1.1.6 root 2161: env->mmuregs[reg]);
2162: }
2163: break;
1.1.1.5 root 2164: case 8: /* User code access, XXX */
2165: case 9: /* Supervisor code access, XXX */
2166: default:
1.1.1.6 root 2167: do_unassigned_access(addr, 1, 0, asi, size);
1.1.1.5 root 2168: break;
2169: }
2170: #ifdef DEBUG_ASI
1.1.1.6 root 2171: dump_asi("write", addr, asi, size, val);
1.1.1.5 root 2172: #endif
2173: }
2174:
2175: #endif /* CONFIG_USER_ONLY */
2176: #else /* TARGET_SPARC64 */
2177:
2178: #ifdef CONFIG_USER_ONLY
1.1.1.6 root 2179: uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
1.1.1.5 root 2180: {
2181: uint64_t ret = 0;
1.1.1.6 root 2182: #if defined(DEBUG_ASI)
2183: target_ulong last_addr = addr;
2184: #endif
1.1.1.5 root 2185:
2186: if (asi < 0x80)
2187: raise_exception(TT_PRIV_ACT);
2188:
1.1.1.6 root 2189: helper_check_align(addr, size - 1);
1.1.1.9 ! root 2190: addr = asi_address_mask(env, asi, addr);
1.1.1.6 root 2191:
1.1.1.5 root 2192: switch (asi) {
2193: case 0x82: // Primary no-fault
2194: case 0x8a: // Primary no-fault LE
1.1.1.6 root 2195: if (page_check_range(addr, size, PAGE_READ) == -1) {
2196: #ifdef DEBUG_ASI
2197: dump_asi("read ", last_addr, asi, size, ret);
2198: #endif
2199: return 0;
2200: }
2201: // Fall through
2202: case 0x80: // Primary
2203: case 0x88: // Primary LE
1.1.1.5 root 2204: {
2205: switch(size) {
2206: case 1:
1.1.1.6 root 2207: ret = ldub_raw(addr);
1.1.1.5 root 2208: break;
2209: case 2:
1.1.1.6 root 2210: ret = lduw_raw(addr);
1.1.1.5 root 2211: break;
2212: case 4:
1.1.1.6 root 2213: ret = ldl_raw(addr);
1.1.1.5 root 2214: break;
2215: default:
2216: case 8:
1.1.1.6 root 2217: ret = ldq_raw(addr);
1.1.1.5 root 2218: break;
2219: }
2220: }
2221: break;
2222: case 0x83: // Secondary no-fault
2223: case 0x8b: // Secondary no-fault LE
1.1.1.6 root 2224: if (page_check_range(addr, size, PAGE_READ) == -1) {
2225: #ifdef DEBUG_ASI
2226: dump_asi("read ", last_addr, asi, size, ret);
2227: #endif
2228: return 0;
2229: }
2230: // Fall through
2231: case 0x81: // Secondary
2232: case 0x89: // Secondary LE
1.1.1.5 root 2233: // XXX
2234: break;
2235: default:
2236: break;
2237: }
2238:
2239: /* Convert from little endian */
2240: switch (asi) {
2241: case 0x88: // Primary LE
2242: case 0x89: // Secondary LE
2243: case 0x8a: // Primary no-fault LE
2244: case 0x8b: // Secondary no-fault LE
2245: switch(size) {
2246: case 2:
2247: ret = bswap16(ret);
2248: break;
2249: case 4:
2250: ret = bswap32(ret);
2251: break;
2252: case 8:
2253: ret = bswap64(ret);
2254: break;
2255: default:
2256: break;
2257: }
2258: default:
2259: break;
2260: }
2261:
2262: /* Convert to signed number */
2263: if (sign) {
2264: switch(size) {
2265: case 1:
2266: ret = (int8_t) ret;
2267: break;
2268: case 2:
2269: ret = (int16_t) ret;
2270: break;
2271: case 4:
2272: ret = (int32_t) ret;
2273: break;
2274: default:
2275: break;
2276: }
2277: }
1.1.1.6 root 2278: #ifdef DEBUG_ASI
2279: dump_asi("read ", last_addr, asi, size, ret);
2280: #endif
2281: return ret;
1.1.1.5 root 2282: }
2283:
1.1.1.6 root 2284: void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
1.1.1.5 root 2285: {
1.1.1.6 root 2286: #ifdef DEBUG_ASI
2287: dump_asi("write", addr, asi, size, val);
2288: #endif
1.1.1.5 root 2289: if (asi < 0x80)
2290: raise_exception(TT_PRIV_ACT);
2291:
1.1.1.6 root 2292: helper_check_align(addr, size - 1);
1.1.1.9 ! root 2293: addr = asi_address_mask(env, asi, addr);
1.1.1.6 root 2294:
1.1.1.5 root 2295: /* Convert to little endian */
2296: switch (asi) {
2297: case 0x88: // Primary LE
2298: case 0x89: // Secondary LE
2299: switch(size) {
2300: case 2:
1.1.1.7 root 2301: val = bswap16(val);
1.1.1.5 root 2302: break;
2303: case 4:
1.1.1.7 root 2304: val = bswap32(val);
1.1.1.5 root 2305: break;
2306: case 8:
1.1.1.7 root 2307: val = bswap64(val);
1.1.1.5 root 2308: break;
2309: default:
2310: break;
2311: }
2312: default:
2313: break;
2314: }
2315:
2316: switch(asi) {
2317: case 0x80: // Primary
2318: case 0x88: // Primary LE
2319: {
1.1.1.2 root 2320: switch(size) {
2321: case 1:
1.1.1.6 root 2322: stb_raw(addr, val);
1.1.1.2 root 2323: break;
2324: case 2:
1.1.1.6 root 2325: stw_raw(addr, val);
1.1.1.2 root 2326: break;
2327: case 4:
1.1.1.6 root 2328: stl_raw(addr, val);
1.1.1.2 root 2329: break;
2330: case 8:
1.1.1.5 root 2331: default:
1.1.1.6 root 2332: stq_raw(addr, val);
1.1.1.2 root 2333: break;
2334: }
1.1.1.5 root 2335: }
2336: break;
2337: case 0x81: // Secondary
2338: case 0x89: // Secondary LE
2339: // XXX
2340: return;
2341:
2342: case 0x82: // Primary no-fault, RO
2343: case 0x83: // Secondary no-fault, RO
2344: case 0x8a: // Primary no-fault LE, RO
2345: case 0x8b: // Secondary no-fault LE, RO
1.1 root 2346: default:
1.1.1.6 root 2347: do_unassigned_access(addr, 1, 0, 1, size);
1.1.1.5 root 2348: return;
1.1 root 2349: }
2350: }
2351:
1.1.1.5 root 2352: #else /* CONFIG_USER_ONLY */
1.1 root 2353:
1.1.1.6 root 2354: uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
1.1 root 2355: {
2356: uint64_t ret = 0;
1.1.1.6 root 2357: #if defined(DEBUG_ASI)
2358: target_ulong last_addr = addr;
2359: #endif
1.1 root 2360:
1.1.1.8 root 2361: asi &= 0xff;
2362:
1.1.1.5 root 2363: if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
1.1.1.9 ! root 2364: || (cpu_has_hypervisor(env)
1.1.1.6 root 2365: && asi >= 0x30 && asi < 0x80
2366: && !(env->hpstate & HS_PRIV)))
1.1.1.5 root 2367: raise_exception(TT_PRIV_ACT);
1.1 root 2368:
1.1.1.6 root 2369: helper_check_align(addr, size - 1);
1.1.1.9 ! root 2370: addr = asi_address_mask(env, asi, addr);
! 2371:
1.1 root 2372: switch (asi) {
1.1.1.6 root 2373: case 0x82: // Primary no-fault
2374: case 0x8a: // Primary no-fault LE
1.1.1.9 ! root 2375: case 0x83: // Secondary no-fault
! 2376: case 0x8b: // Secondary no-fault LE
! 2377: {
! 2378: /* secondary space access has lowest asi bit equal to 1 */
! 2379: int access_mmu_idx = ( asi & 1 ) ? MMU_KERNEL_IDX
! 2380: : MMU_KERNEL_SECONDARY_IDX;
! 2381:
! 2382: if (cpu_get_phys_page_nofault(env, addr, access_mmu_idx) == -1ULL) {
1.1.1.6 root 2383: #ifdef DEBUG_ASI
1.1.1.9 ! root 2384: dump_asi("read ", last_addr, asi, size, ret);
1.1.1.6 root 2385: #endif
1.1.1.9 ! root 2386: return 0;
! 2387: }
1.1.1.6 root 2388: }
2389: // Fall through
1.1.1.5 root 2390: case 0x10: // As if user primary
1.1.1.9 ! root 2391: case 0x11: // As if user secondary
1.1.1.5 root 2392: case 0x18: // As if user primary LE
1.1.1.9 ! root 2393: case 0x19: // As if user secondary LE
1.1.1.5 root 2394: case 0x80: // Primary
1.1.1.9 ! root 2395: case 0x81: // Secondary
1.1.1.5 root 2396: case 0x88: // Primary LE
1.1.1.9 ! root 2397: case 0x89: // Secondary LE
1.1.1.6 root 2398: case 0xe2: // UA2007 Primary block init
2399: case 0xe3: // UA2007 Secondary block init
1.1.1.5 root 2400: if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
1.1.1.9 ! root 2401: if (cpu_hypervisor_mode(env)) {
1.1.1.5 root 2402: switch(size) {
2403: case 1:
1.1.1.6 root 2404: ret = ldub_hypv(addr);
1.1.1.5 root 2405: break;
2406: case 2:
1.1.1.6 root 2407: ret = lduw_hypv(addr);
1.1.1.5 root 2408: break;
2409: case 4:
1.1.1.6 root 2410: ret = ldl_hypv(addr);
1.1.1.5 root 2411: break;
2412: default:
2413: case 8:
1.1.1.6 root 2414: ret = ldq_hypv(addr);
1.1.1.5 root 2415: break;
2416: }
2417: } else {
1.1.1.9 ! root 2418: /* secondary space access has lowest asi bit equal to 1 */
! 2419: if (asi & 1) {
! 2420: switch(size) {
! 2421: case 1:
! 2422: ret = ldub_kernel_secondary(addr);
! 2423: break;
! 2424: case 2:
! 2425: ret = lduw_kernel_secondary(addr);
! 2426: break;
! 2427: case 4:
! 2428: ret = ldl_kernel_secondary(addr);
! 2429: break;
! 2430: default:
! 2431: case 8:
! 2432: ret = ldq_kernel_secondary(addr);
! 2433: break;
! 2434: }
! 2435: } else {
! 2436: switch(size) {
! 2437: case 1:
! 2438: ret = ldub_kernel(addr);
! 2439: break;
! 2440: case 2:
! 2441: ret = lduw_kernel(addr);
! 2442: break;
! 2443: case 4:
! 2444: ret = ldl_kernel(addr);
! 2445: break;
! 2446: default:
! 2447: case 8:
! 2448: ret = ldq_kernel(addr);
! 2449: break;
! 2450: }
! 2451: }
! 2452: }
! 2453: } else {
! 2454: /* secondary space access has lowest asi bit equal to 1 */
! 2455: if (asi & 1) {
1.1.1.5 root 2456: switch(size) {
2457: case 1:
1.1.1.9 ! root 2458: ret = ldub_user_secondary(addr);
1.1.1.5 root 2459: break;
2460: case 2:
1.1.1.9 ! root 2461: ret = lduw_user_secondary(addr);
1.1.1.5 root 2462: break;
2463: case 4:
1.1.1.9 ! root 2464: ret = ldl_user_secondary(addr);
1.1.1.5 root 2465: break;
2466: default:
2467: case 8:
1.1.1.9 ! root 2468: ret = ldq_user_secondary(addr);
! 2469: break;
! 2470: }
! 2471: } else {
! 2472: switch(size) {
! 2473: case 1:
! 2474: ret = ldub_user(addr);
! 2475: break;
! 2476: case 2:
! 2477: ret = lduw_user(addr);
! 2478: break;
! 2479: case 4:
! 2480: ret = ldl_user(addr);
! 2481: break;
! 2482: default:
! 2483: case 8:
! 2484: ret = ldq_user(addr);
1.1.1.5 root 2485: break;
2486: }
2487: }
2488: }
2489: break;
1.1 root 2490: case 0x14: // Bypass
2491: case 0x15: // Bypass, non-cacheable
1.1.1.5 root 2492: case 0x1c: // Bypass LE
2493: case 0x1d: // Bypass, non-cacheable LE
2494: {
1.1.1.2 root 2495: switch(size) {
2496: case 1:
1.1.1.6 root 2497: ret = ldub_phys(addr);
1.1.1.2 root 2498: break;
2499: case 2:
1.1.1.6 root 2500: ret = lduw_phys(addr);
1.1.1.2 root 2501: break;
2502: case 4:
1.1.1.6 root 2503: ret = ldl_phys(addr);
1.1.1.2 root 2504: break;
2505: default:
2506: case 8:
1.1.1.6 root 2507: ret = ldq_phys(addr);
1.1.1.2 root 2508: break;
2509: }
1.1.1.5 root 2510: break;
2511: }
1.1.1.6 root 2512: case 0x24: // Nucleus quad LDD 128 bit atomic
2513: case 0x2c: // Nucleus quad LDD 128 bit atomic LE
2514: // Only ldda allowed
2515: raise_exception(TT_ILL_INSN);
2516: return 0;
1.1 root 2517: case 0x04: // Nucleus
2518: case 0x0c: // Nucleus Little Endian (LE)
1.1.1.9 ! root 2519: {
! 2520: switch(size) {
! 2521: case 1:
! 2522: ret = ldub_nucleus(addr);
! 2523: break;
! 2524: case 2:
! 2525: ret = lduw_nucleus(addr);
! 2526: break;
! 2527: case 4:
! 2528: ret = ldl_nucleus(addr);
! 2529: break;
! 2530: default:
! 2531: case 8:
! 2532: ret = ldq_nucleus(addr);
! 2533: break;
! 2534: }
! 2535: break;
! 2536: }
1.1 root 2537: case 0x4a: // UPA config
1.1.1.5 root 2538: // XXX
2539: break;
1.1 root 2540: case 0x45: // LSU
1.1.1.5 root 2541: ret = env->lsu;
2542: break;
1.1 root 2543: case 0x50: // I-MMU regs
1.1.1.5 root 2544: {
1.1.1.6 root 2545: int reg = (addr >> 3) & 0xf;
1.1 root 2546:
1.1.1.7 root 2547: if (reg == 0) {
2548: // I-TSB Tag Target register
1.1.1.8 root 2549: ret = ultrasparc_tag_target(env->immu.tag_access);
1.1.1.7 root 2550: } else {
2551: ret = env->immuregs[reg];
2552: }
2553:
1.1.1.5 root 2554: break;
2555: }
1.1 root 2556: case 0x51: // I-MMU 8k TSB pointer
1.1.1.7 root 2557: {
2558: // env->immuregs[5] holds I-MMU TSB register value
2559: // env->immuregs[6] holds I-MMU Tag Access register value
1.1.1.8 root 2560: ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
1.1.1.7 root 2561: 8*1024);
2562: break;
2563: }
1.1 root 2564: case 0x52: // I-MMU 64k TSB pointer
1.1.1.7 root 2565: {
2566: // env->immuregs[5] holds I-MMU TSB register value
2567: // env->immuregs[6] holds I-MMU Tag Access register value
1.1.1.8 root 2568: ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access,
1.1.1.7 root 2569: 64*1024);
2570: break;
2571: }
1.1.1.6 root 2572: case 0x55: // I-MMU data access
2573: {
2574: int reg = (addr >> 3) & 0x3f;
2575:
1.1.1.8 root 2576: ret = env->itlb[reg].tte;
1.1.1.6 root 2577: break;
2578: }
1.1 root 2579: case 0x56: // I-MMU tag read
1.1.1.5 root 2580: {
1.1.1.6 root 2581: int reg = (addr >> 3) & 0x3f;
1.1.1.5 root 2582:
1.1.1.8 root 2583: ret = env->itlb[reg].tag;
1.1.1.5 root 2584: break;
2585: }
1.1 root 2586: case 0x58: // D-MMU regs
1.1.1.5 root 2587: {
1.1.1.6 root 2588: int reg = (addr >> 3) & 0xf;
1.1 root 2589:
1.1.1.7 root 2590: if (reg == 0) {
2591: // D-TSB Tag Target register
1.1.1.8 root 2592: ret = ultrasparc_tag_target(env->dmmu.tag_access);
1.1.1.7 root 2593: } else {
2594: ret = env->dmmuregs[reg];
2595: }
2596: break;
2597: }
2598: case 0x59: // D-MMU 8k TSB pointer
2599: {
2600: // env->dmmuregs[5] holds D-MMU TSB register value
2601: // env->dmmuregs[6] holds D-MMU Tag Access register value
1.1.1.8 root 2602: ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
1.1.1.7 root 2603: 8*1024);
2604: break;
2605: }
2606: case 0x5a: // D-MMU 64k TSB pointer
2607: {
2608: // env->dmmuregs[5] holds D-MMU TSB register value
2609: // env->dmmuregs[6] holds D-MMU Tag Access register value
1.1.1.8 root 2610: ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access,
1.1.1.7 root 2611: 64*1024);
1.1.1.5 root 2612: break;
2613: }
1.1.1.6 root 2614: case 0x5d: // D-MMU data access
2615: {
2616: int reg = (addr >> 3) & 0x3f;
2617:
1.1.1.8 root 2618: ret = env->dtlb[reg].tte;
1.1.1.6 root 2619: break;
2620: }
1.1 root 2621: case 0x5e: // D-MMU tag read
1.1.1.5 root 2622: {
1.1.1.6 root 2623: int reg = (addr >> 3) & 0x3f;
1.1.1.5 root 2624:
1.1.1.8 root 2625: ret = env->dtlb[reg].tag;
1.1.1.5 root 2626: break;
2627: }
1.1.1.6 root 2628: case 0x46: // D-cache data
2629: case 0x47: // D-cache tag access
2630: case 0x4b: // E-cache error enable
2631: case 0x4c: // E-cache asynchronous fault status
2632: case 0x4d: // E-cache asynchronous fault address
2633: case 0x4e: // E-cache tag data
2634: case 0x66: // I-cache instruction access
2635: case 0x67: // I-cache tag access
2636: case 0x6e: // I-cache predecode
2637: case 0x6f: // I-cache LRU etc.
2638: case 0x76: // E-cache tag
2639: case 0x7e: // E-cache tag
2640: break;
1.1 root 2641: case 0x5b: // D-MMU data pointer
2642: case 0x48: // Interrupt dispatch, RO
2643: case 0x49: // Interrupt data receive
2644: case 0x7f: // Incoming interrupt vector, RO
1.1.1.5 root 2645: // XXX
2646: break;
1.1 root 2647: case 0x54: // I-MMU data in, WO
2648: case 0x57: // I-MMU demap, WO
2649: case 0x5c: // D-MMU data in, WO
2650: case 0x5f: // D-MMU demap, WO
2651: case 0x77: // Interrupt vector, WO
2652: default:
1.1.1.6 root 2653: do_unassigned_access(addr, 0, 0, 1, size);
1.1.1.5 root 2654: ret = 0;
2655: break;
2656: }
2657:
2658: /* Convert from little endian */
2659: switch (asi) {
2660: case 0x0c: // Nucleus Little Endian (LE)
2661: case 0x18: // As if user primary LE
2662: case 0x19: // As if user secondary LE
2663: case 0x1c: // Bypass LE
2664: case 0x1d: // Bypass, non-cacheable LE
2665: case 0x88: // Primary LE
2666: case 0x89: // Secondary LE
2667: case 0x8a: // Primary no-fault LE
2668: case 0x8b: // Secondary no-fault LE
2669: switch(size) {
2670: case 2:
2671: ret = bswap16(ret);
2672: break;
2673: case 4:
2674: ret = bswap32(ret);
2675: break;
2676: case 8:
2677: ret = bswap64(ret);
2678: break;
2679: default:
2680: break;
2681: }
2682: default:
2683: break;
2684: }
2685:
2686: /* Convert to signed number */
2687: if (sign) {
2688: switch(size) {
2689: case 1:
2690: ret = (int8_t) ret;
2691: break;
2692: case 2:
2693: ret = (int16_t) ret;
2694: break;
2695: case 4:
2696: ret = (int32_t) ret;
2697: break;
2698: default:
2699: break;
2700: }
1.1 root 2701: }
1.1.1.6 root 2702: #ifdef DEBUG_ASI
2703: dump_asi("read ", last_addr, asi, size, ret);
2704: #endif
2705: return ret;
1.1 root 2706: }
2707:
1.1.1.6 root 2708: void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
1.1 root 2709: {
1.1.1.6 root 2710: #ifdef DEBUG_ASI
2711: dump_asi("write", addr, asi, size, val);
2712: #endif
1.1.1.8 root 2713:
2714: asi &= 0xff;
2715:
1.1.1.5 root 2716: if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
1.1.1.9 ! root 2717: || (cpu_has_hypervisor(env)
1.1.1.6 root 2718: && asi >= 0x30 && asi < 0x80
2719: && !(env->hpstate & HS_PRIV)))
1.1.1.5 root 2720: raise_exception(TT_PRIV_ACT);
2721:
1.1.1.6 root 2722: helper_check_align(addr, size - 1);
1.1.1.9 ! root 2723: addr = asi_address_mask(env, asi, addr);
! 2724:
1.1.1.5 root 2725: /* Convert to little endian */
2726: switch (asi) {
2727: case 0x0c: // Nucleus Little Endian (LE)
2728: case 0x18: // As if user primary LE
2729: case 0x19: // As if user secondary LE
2730: case 0x1c: // Bypass LE
2731: case 0x1d: // Bypass, non-cacheable LE
2732: case 0x88: // Primary LE
2733: case 0x89: // Secondary LE
2734: switch(size) {
2735: case 2:
1.1.1.7 root 2736: val = bswap16(val);
1.1.1.5 root 2737: break;
2738: case 4:
1.1.1.7 root 2739: val = bswap32(val);
1.1.1.5 root 2740: break;
2741: case 8:
1.1.1.7 root 2742: val = bswap64(val);
1.1.1.5 root 2743: break;
2744: default:
2745: break;
2746: }
2747: default:
2748: break;
2749: }
1.1 root 2750:
2751: switch(asi) {
1.1.1.5 root 2752: case 0x10: // As if user primary
1.1.1.9 ! root 2753: case 0x11: // As if user secondary
1.1.1.5 root 2754: case 0x18: // As if user primary LE
1.1.1.9 ! root 2755: case 0x19: // As if user secondary LE
1.1.1.5 root 2756: case 0x80: // Primary
1.1.1.9 ! root 2757: case 0x81: // Secondary
1.1.1.5 root 2758: case 0x88: // Primary LE
1.1.1.9 ! root 2759: case 0x89: // Secondary LE
1.1.1.6 root 2760: case 0xe2: // UA2007 Primary block init
2761: case 0xe3: // UA2007 Secondary block init
1.1.1.5 root 2762: if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
1.1.1.9 ! root 2763: if (cpu_hypervisor_mode(env)) {
1.1.1.5 root 2764: switch(size) {
2765: case 1:
1.1.1.6 root 2766: stb_hypv(addr, val);
1.1.1.5 root 2767: break;
2768: case 2:
1.1.1.6 root 2769: stw_hypv(addr, val);
1.1.1.5 root 2770: break;
2771: case 4:
1.1.1.6 root 2772: stl_hypv(addr, val);
1.1.1.5 root 2773: break;
2774: case 8:
2775: default:
1.1.1.6 root 2776: stq_hypv(addr, val);
1.1.1.5 root 2777: break;
2778: }
2779: } else {
1.1.1.9 ! root 2780: /* secondary space access has lowest asi bit equal to 1 */
! 2781: if (asi & 1) {
! 2782: switch(size) {
! 2783: case 1:
! 2784: stb_kernel_secondary(addr, val);
! 2785: break;
! 2786: case 2:
! 2787: stw_kernel_secondary(addr, val);
! 2788: break;
! 2789: case 4:
! 2790: stl_kernel_secondary(addr, val);
! 2791: break;
! 2792: case 8:
! 2793: default:
! 2794: stq_kernel_secondary(addr, val);
! 2795: break;
! 2796: }
! 2797: } else {
! 2798: switch(size) {
! 2799: case 1:
! 2800: stb_kernel(addr, val);
! 2801: break;
! 2802: case 2:
! 2803: stw_kernel(addr, val);
! 2804: break;
! 2805: case 4:
! 2806: stl_kernel(addr, val);
! 2807: break;
! 2808: case 8:
! 2809: default:
! 2810: stq_kernel(addr, val);
! 2811: break;
! 2812: }
! 2813: }
! 2814: }
! 2815: } else {
! 2816: /* secondary space access has lowest asi bit equal to 1 */
! 2817: if (asi & 1) {
1.1.1.5 root 2818: switch(size) {
2819: case 1:
1.1.1.9 ! root 2820: stb_user_secondary(addr, val);
1.1.1.5 root 2821: break;
2822: case 2:
1.1.1.9 ! root 2823: stw_user_secondary(addr, val);
1.1.1.5 root 2824: break;
2825: case 4:
1.1.1.9 ! root 2826: stl_user_secondary(addr, val);
1.1.1.5 root 2827: break;
2828: case 8:
2829: default:
1.1.1.9 ! root 2830: stq_user_secondary(addr, val);
! 2831: break;
! 2832: }
! 2833: } else {
! 2834: switch(size) {
! 2835: case 1:
! 2836: stb_user(addr, val);
! 2837: break;
! 2838: case 2:
! 2839: stw_user(addr, val);
! 2840: break;
! 2841: case 4:
! 2842: stl_user(addr, val);
! 2843: break;
! 2844: case 8:
! 2845: default:
! 2846: stq_user(addr, val);
1.1.1.5 root 2847: break;
2848: }
2849: }
2850: }
2851: break;
1.1 root 2852: case 0x14: // Bypass
2853: case 0x15: // Bypass, non-cacheable
1.1.1.5 root 2854: case 0x1c: // Bypass LE
2855: case 0x1d: // Bypass, non-cacheable LE
2856: {
1.1.1.2 root 2857: switch(size) {
2858: case 1:
1.1.1.6 root 2859: stb_phys(addr, val);
1.1.1.2 root 2860: break;
2861: case 2:
1.1.1.6 root 2862: stw_phys(addr, val);
1.1.1.2 root 2863: break;
2864: case 4:
1.1.1.6 root 2865: stl_phys(addr, val);
1.1.1.2 root 2866: break;
2867: case 8:
2868: default:
1.1.1.6 root 2869: stq_phys(addr, val);
1.1.1.2 root 2870: break;
2871: }
1.1.1.5 root 2872: }
2873: return;
1.1.1.6 root 2874: case 0x24: // Nucleus quad LDD 128 bit atomic
2875: case 0x2c: // Nucleus quad LDD 128 bit atomic LE
2876: // Only ldda allowed
2877: raise_exception(TT_ILL_INSN);
2878: return;
1.1 root 2879: case 0x04: // Nucleus
2880: case 0x0c: // Nucleus Little Endian (LE)
1.1.1.9 ! root 2881: {
! 2882: switch(size) {
! 2883: case 1:
! 2884: stb_nucleus(addr, val);
! 2885: break;
! 2886: case 2:
! 2887: stw_nucleus(addr, val);
! 2888: break;
! 2889: case 4:
! 2890: stl_nucleus(addr, val);
! 2891: break;
! 2892: default:
! 2893: case 8:
! 2894: stq_nucleus(addr, val);
! 2895: break;
! 2896: }
! 2897: break;
! 2898: }
! 2899:
1.1 root 2900: case 0x4a: // UPA config
1.1.1.5 root 2901: // XXX
2902: return;
1.1 root 2903: case 0x45: // LSU
1.1.1.5 root 2904: {
2905: uint64_t oldreg;
1.1 root 2906:
1.1.1.5 root 2907: oldreg = env->lsu;
1.1.1.6 root 2908: env->lsu = val & (DMMU_E | IMMU_E);
1.1.1.5 root 2909: // Mappings generated during D/I MMU disabled mode are
2910: // invalid in normal mode
2911: if (oldreg != env->lsu) {
1.1.1.6 root 2912: DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n",
2913: oldreg, env->lsu);
1.1 root 2914: #ifdef DEBUG_MMU
1.1.1.5 root 2915: dump_mmu(env);
1.1 root 2916: #endif
1.1.1.5 root 2917: tlb_flush(env, 1);
2918: }
2919: return;
2920: }
1.1 root 2921: case 0x50: // I-MMU regs
1.1.1.5 root 2922: {
1.1.1.6 root 2923: int reg = (addr >> 3) & 0xf;
1.1.1.5 root 2924: uint64_t oldreg;
2925:
2926: oldreg = env->immuregs[reg];
1.1 root 2927: switch(reg) {
2928: case 0: // RO
2929: return;
2930: case 1: // Not in I-MMU
2931: case 2:
2932: return;
2933: case 3: // SFSR
1.1.1.6 root 2934: if ((val & 1) == 0)
2935: val = 0; // Clear SFSR
1.1.1.8 root 2936: env->immu.sfsr = val;
1.1 root 2937: break;
1.1.1.8 root 2938: case 4: // RO
2939: return;
1.1 root 2940: case 5: // TSB access
1.1.1.8 root 2941: DPRINTF_MMU("immu TSB write: 0x%016" PRIx64 " -> 0x%016"
2942: PRIx64 "\n", env->immu.tsb, val);
2943: env->immu.tsb = val;
2944: break;
1.1 root 2945: case 6: // Tag access
1.1.1.8 root 2946: env->immu.tag_access = val;
2947: break;
2948: case 7:
2949: case 8:
2950: return;
1.1 root 2951: default:
2952: break;
2953: }
1.1.1.8 root 2954:
1.1 root 2955: if (oldreg != env->immuregs[reg]) {
1.1.1.8 root 2956: DPRINTF_MMU("immu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
1.1.1.6 root 2957: PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
1.1 root 2958: }
1.1.1.5 root 2959: #ifdef DEBUG_MMU
2960: dump_mmu(env);
1.1 root 2961: #endif
1.1.1.5 root 2962: return;
2963: }
1.1 root 2964: case 0x54: // I-MMU data in
1.1.1.8 root 2965: replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env);
2966: return;
1.1 root 2967: case 0x55: // I-MMU data access
1.1.1.5 root 2968: {
1.1.1.6 root 2969: // TODO: auto demap
2970:
2971: unsigned int i = (addr >> 3) & 0x3f;
1.1 root 2972:
1.1.1.8 root 2973: replace_tlb_entry(&env->itlb[i], env->immu.tag_access, val, env);
2974:
2975: #ifdef DEBUG_MMU
2976: DPRINTF_MMU("immu data access replaced entry [%i]\n", i);
2977: dump_mmu(env);
2978: #endif
1.1.1.5 root 2979: return;
2980: }
1.1 root 2981: case 0x57: // I-MMU demap
1.1.1.9 ! root 2982: demap_tlb(env->itlb, addr, "immu", env);
1.1.1.5 root 2983: return;
1.1 root 2984: case 0x58: // D-MMU regs
1.1.1.5 root 2985: {
1.1.1.6 root 2986: int reg = (addr >> 3) & 0xf;
1.1.1.5 root 2987: uint64_t oldreg;
2988:
2989: oldreg = env->dmmuregs[reg];
1.1 root 2990: switch(reg) {
2991: case 0: // RO
2992: case 4:
2993: return;
2994: case 3: // SFSR
1.1.1.6 root 2995: if ((val & 1) == 0) {
2996: val = 0; // Clear SFSR, Fault address
1.1.1.8 root 2997: env->dmmu.sfar = 0;
1.1.1.5 root 2998: }
1.1.1.8 root 2999: env->dmmu.sfsr = val;
1.1 root 3000: break;
3001: case 1: // Primary context
1.1.1.8 root 3002: env->dmmu.mmu_primary_context = val;
1.1.1.9 ! root 3003: /* can be optimized to only flush MMU_USER_IDX
! 3004: and MMU_KERNEL_IDX entries */
! 3005: tlb_flush(env, 1);
1.1.1.8 root 3006: break;
1.1 root 3007: case 2: // Secondary context
1.1.1.8 root 3008: env->dmmu.mmu_secondary_context = val;
1.1.1.9 ! root 3009: /* can be optimized to only flush MMU_USER_SECONDARY_IDX
! 3010: and MMU_KERNEL_SECONDARY_IDX entries */
! 3011: tlb_flush(env, 1);
1.1.1.8 root 3012: break;
1.1 root 3013: case 5: // TSB access
1.1.1.8 root 3014: DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016"
3015: PRIx64 "\n", env->dmmu.tsb, val);
3016: env->dmmu.tsb = val;
3017: break;
1.1 root 3018: case 6: // Tag access
1.1.1.8 root 3019: env->dmmu.tag_access = val;
3020: break;
1.1 root 3021: case 7: // Virtual Watchpoint
3022: case 8: // Physical Watchpoint
3023: default:
1.1.1.8 root 3024: env->dmmuregs[reg] = val;
1.1 root 3025: break;
3026: }
1.1.1.8 root 3027:
1.1 root 3028: if (oldreg != env->dmmuregs[reg]) {
1.1.1.8 root 3029: DPRINTF_MMU("dmmu change reg[%d]: 0x%016" PRIx64 " -> 0x%016"
1.1.1.6 root 3030: PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
1.1 root 3031: }
1.1.1.5 root 3032: #ifdef DEBUG_MMU
3033: dump_mmu(env);
1.1 root 3034: #endif
1.1.1.5 root 3035: return;
3036: }
1.1 root 3037: case 0x5c: // D-MMU data in
1.1.1.8 root 3038: replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env);
3039: return;
1.1 root 3040: case 0x5d: // D-MMU data access
1.1.1.5 root 3041: {
1.1.1.6 root 3042: unsigned int i = (addr >> 3) & 0x3f;
1.1 root 3043:
1.1.1.8 root 3044: replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, val, env);
3045:
3046: #ifdef DEBUG_MMU
3047: DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i);
3048: dump_mmu(env);
3049: #endif
1.1.1.5 root 3050: return;
3051: }
1.1 root 3052: case 0x5f: // D-MMU demap
1.1.1.9 ! root 3053: demap_tlb(env->dtlb, addr, "dmmu", env);
1.1.1.6 root 3054: return;
1.1 root 3055: case 0x49: // Interrupt data receive
1.1.1.5 root 3056: // XXX
3057: return;
1.1.1.6 root 3058: case 0x46: // D-cache data
3059: case 0x47: // D-cache tag access
3060: case 0x4b: // E-cache error enable
3061: case 0x4c: // E-cache asynchronous fault status
3062: case 0x4d: // E-cache asynchronous fault address
3063: case 0x4e: // E-cache tag data
3064: case 0x66: // I-cache instruction access
3065: case 0x67: // I-cache tag access
3066: case 0x6e: // I-cache predecode
3067: case 0x6f: // I-cache LRU etc.
3068: case 0x76: // E-cache tag
3069: case 0x7e: // E-cache tag
3070: return;
1.1 root 3071: case 0x51: // I-MMU 8k TSB pointer, RO
3072: case 0x52: // I-MMU 64k TSB pointer, RO
3073: case 0x56: // I-MMU tag read, RO
3074: case 0x59: // D-MMU 8k TSB pointer, RO
3075: case 0x5a: // D-MMU 64k TSB pointer, RO
3076: case 0x5b: // D-MMU data pointer, RO
3077: case 0x5e: // D-MMU tag read, RO
3078: case 0x48: // Interrupt dispatch, RO
3079: case 0x7f: // Incoming interrupt vector, RO
3080: case 0x82: // Primary no-fault, RO
3081: case 0x83: // Secondary no-fault, RO
3082: case 0x8a: // Primary no-fault LE, RO
3083: case 0x8b: // Secondary no-fault LE, RO
3084: default:
1.1.1.6 root 3085: do_unassigned_access(addr, 1, 0, 1, size);
1.1.1.5 root 3086: return;
3087: }
3088: }
3089: #endif /* CONFIG_USER_ONLY */
3090:
1.1.1.6 root 3091: void helper_ldda_asi(target_ulong addr, int asi, int rd)
3092: {
3093: if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0)
1.1.1.9 ! root 3094: || (cpu_has_hypervisor(env)
1.1.1.6 root 3095: && asi >= 0x30 && asi < 0x80
3096: && !(env->hpstate & HS_PRIV)))
3097: raise_exception(TT_PRIV_ACT);
3098:
1.1.1.9 ! root 3099: addr = asi_address_mask(env, asi, addr);
! 3100:
1.1.1.6 root 3101: switch (asi) {
1.1.1.9 ! root 3102: #if !defined(CONFIG_USER_ONLY)
1.1.1.6 root 3103: case 0x24: // Nucleus quad LDD 128 bit atomic
3104: case 0x2c: // Nucleus quad LDD 128 bit atomic LE
3105: helper_check_align(addr, 0xf);
3106: if (rd == 0) {
1.1.1.9 ! root 3107: env->gregs[1] = ldq_nucleus(addr + 8);
1.1.1.6 root 3108: if (asi == 0x2c)
3109: bswap64s(&env->gregs[1]);
3110: } else if (rd < 8) {
1.1.1.9 ! root 3111: env->gregs[rd] = ldq_nucleus(addr);
! 3112: env->gregs[rd + 1] = ldq_nucleus(addr + 8);
1.1.1.6 root 3113: if (asi == 0x2c) {
3114: bswap64s(&env->gregs[rd]);
3115: bswap64s(&env->gregs[rd + 1]);
3116: }
3117: } else {
1.1.1.9 ! root 3118: env->regwptr[rd] = ldq_nucleus(addr);
! 3119: env->regwptr[rd + 1] = ldq_nucleus(addr + 8);
1.1.1.6 root 3120: if (asi == 0x2c) {
3121: bswap64s(&env->regwptr[rd]);
3122: bswap64s(&env->regwptr[rd + 1]);
3123: }
3124: }
3125: break;
1.1.1.9 ! root 3126: #endif
1.1.1.6 root 3127: default:
3128: helper_check_align(addr, 0x3);
3129: if (rd == 0)
3130: env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0);
3131: else if (rd < 8) {
3132: env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0);
3133: env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
3134: } else {
3135: env->regwptr[rd] = helper_ld_asi(addr, asi, 4, 0);
3136: env->regwptr[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0);
3137: }
3138: break;
3139: }
3140: }
3141:
3142: void helper_ldf_asi(target_ulong addr, int asi, int size, int rd)
1.1.1.5 root 3143: {
3144: unsigned int i;
1.1.1.6 root 3145: target_ulong val;
1.1.1.5 root 3146:
1.1.1.6 root 3147: helper_check_align(addr, 3);
1.1.1.9 ! root 3148: addr = asi_address_mask(env, asi, addr);
! 3149:
1.1.1.5 root 3150: switch (asi) {
3151: case 0xf0: // Block load primary
3152: case 0xf1: // Block load secondary
3153: case 0xf8: // Block load primary LE
3154: case 0xf9: // Block load secondary LE
3155: if (rd & 7) {
3156: raise_exception(TT_ILL_INSN);
3157: return;
3158: }
1.1.1.6 root 3159: helper_check_align(addr, 0x3f);
1.1.1.5 root 3160: for (i = 0; i < 16; i++) {
1.1.1.6 root 3161: *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x8f, 4,
3162: 0);
3163: addr += 4;
1.1.1.5 root 3164: }
3165:
3166: return;
1.1.1.9 ! root 3167: case 0x70: // Block load primary, user privilege
! 3168: case 0x71: // Block load secondary, user privilege
! 3169: if (rd & 7) {
! 3170: raise_exception(TT_ILL_INSN);
! 3171: return;
! 3172: }
! 3173: helper_check_align(addr, 0x3f);
! 3174: for (i = 0; i < 16; i++) {
! 3175: *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x1f, 4,
! 3176: 0);
! 3177: addr += 4;
! 3178: }
! 3179:
! 3180: return;
1.1.1.5 root 3181: default:
3182: break;
3183: }
3184:
1.1.1.6 root 3185: val = helper_ld_asi(addr, asi, size, 0);
1.1.1.5 root 3186: switch(size) {
3187: default:
3188: case 4:
1.1.1.6 root 3189: *((uint32_t *)&env->fpr[rd]) = val;
1.1.1.5 root 3190: break;
3191: case 8:
1.1.1.6 root 3192: *((int64_t *)&DT0) = val;
1.1.1.5 root 3193: break;
3194: case 16:
3195: // XXX
3196: break;
1.1 root 3197: }
3198: }
1.1.1.5 root 3199:
1.1.1.6 root 3200: void helper_stf_asi(target_ulong addr, int asi, int size, int rd)
1.1.1.5 root 3201: {
3202: unsigned int i;
1.1.1.6 root 3203: target_ulong val = 0;
1.1.1.5 root 3204:
1.1.1.6 root 3205: helper_check_align(addr, 3);
1.1.1.9 ! root 3206: addr = asi_address_mask(env, asi, addr);
! 3207:
1.1.1.5 root 3208: switch (asi) {
1.1.1.6 root 3209: case 0xe0: // UA2007 Block commit store primary (cache flush)
3210: case 0xe1: // UA2007 Block commit store secondary (cache flush)
1.1.1.5 root 3211: case 0xf0: // Block store primary
3212: case 0xf1: // Block store secondary
3213: case 0xf8: // Block store primary LE
3214: case 0xf9: // Block store secondary LE
3215: if (rd & 7) {
3216: raise_exception(TT_ILL_INSN);
3217: return;
3218: }
1.1.1.6 root 3219: helper_check_align(addr, 0x3f);
1.1.1.5 root 3220: for (i = 0; i < 16; i++) {
1.1.1.6 root 3221: val = *(uint32_t *)&env->fpr[rd++];
3222: helper_st_asi(addr, val, asi & 0x8f, 4);
3223: addr += 4;
1.1.1.5 root 3224: }
3225:
3226: return;
1.1.1.9 ! root 3227: case 0x70: // Block store primary, user privilege
! 3228: case 0x71: // Block store secondary, user privilege
! 3229: if (rd & 7) {
! 3230: raise_exception(TT_ILL_INSN);
! 3231: return;
! 3232: }
! 3233: helper_check_align(addr, 0x3f);
! 3234: for (i = 0; i < 16; i++) {
! 3235: val = *(uint32_t *)&env->fpr[rd++];
! 3236: helper_st_asi(addr, val, asi & 0x1f, 4);
! 3237: addr += 4;
! 3238: }
! 3239:
! 3240: return;
1.1.1.5 root 3241: default:
3242: break;
3243: }
3244:
3245: switch(size) {
3246: default:
3247: case 4:
1.1.1.6 root 3248: val = *((uint32_t *)&env->fpr[rd]);
1.1.1.5 root 3249: break;
3250: case 8:
1.1.1.6 root 3251: val = *((int64_t *)&DT0);
1.1.1.5 root 3252: break;
3253: case 16:
3254: // XXX
3255: break;
3256: }
1.1.1.6 root 3257: helper_st_asi(addr, val, asi, size);
3258: }
3259:
3260: target_ulong helper_cas_asi(target_ulong addr, target_ulong val1,
3261: target_ulong val2, uint32_t asi)
3262: {
3263: target_ulong ret;
3264:
3265: val2 &= 0xffffffffUL;
3266: ret = helper_ld_asi(addr, asi, 4, 0);
3267: ret &= 0xffffffffUL;
3268: if (val2 == ret)
3269: helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4);
3270: return ret;
1.1.1.5 root 3271: }
3272:
1.1.1.6 root 3273: target_ulong helper_casx_asi(target_ulong addr, target_ulong val1,
3274: target_ulong val2, uint32_t asi)
3275: {
3276: target_ulong ret;
3277:
3278: ret = helper_ld_asi(addr, asi, 8, 0);
3279: if (val2 == ret)
3280: helper_st_asi(addr, val1, asi, 8);
3281: return ret;
3282: }
1.1.1.5 root 3283: #endif /* TARGET_SPARC64 */
1.1 root 3284:
3285: #ifndef TARGET_SPARC64
1.1.1.6 root 3286: void helper_rett(void)
1.1 root 3287: {
3288: unsigned int cwp;
3289:
1.1.1.5 root 3290: if (env->psret == 1)
3291: raise_exception(TT_ILL_INSN);
3292:
1.1 root 3293: env->psret = 1;
1.1.1.9 ! root 3294: cwp = cwp_inc(env->cwp + 1) ;
1.1 root 3295: if (env->wim & (1 << cwp)) {
3296: raise_exception(TT_WIN_UNF);
3297: }
3298: set_cwp(cwp);
3299: env->psrs = env->psrps;
3300: }
3301: #endif
3302:
1.1.1.6 root 3303: target_ulong helper_udiv(target_ulong a, target_ulong b)
3304: {
3305: uint64_t x0;
3306: uint32_t x1;
3307:
3308: x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
1.1.1.9 ! root 3309: x1 = (b & 0xffffffff);
1.1.1.6 root 3310:
3311: if (x1 == 0) {
3312: raise_exception(TT_DIV_ZERO);
3313: }
3314:
3315: x0 = x0 / x1;
3316: if (x0 > 0xffffffff) {
3317: env->cc_src2 = 1;
3318: return 0xffffffff;
3319: } else {
3320: env->cc_src2 = 0;
3321: return x0;
3322: }
3323: }
3324:
3325: target_ulong helper_sdiv(target_ulong a, target_ulong b)
3326: {
3327: int64_t x0;
3328: int32_t x1;
3329:
3330: x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32);
1.1.1.9 ! root 3331: x1 = (b & 0xffffffff);
1.1.1.6 root 3332:
3333: if (x1 == 0) {
3334: raise_exception(TT_DIV_ZERO);
3335: }
3336:
3337: x0 = x0 / x1;
3338: if ((int32_t) x0 != x0) {
3339: env->cc_src2 = 1;
3340: return x0 < 0? 0x80000000: 0x7fffffff;
3341: } else {
3342: env->cc_src2 = 0;
3343: return x0;
3344: }
3345: }
3346:
3347: void helper_stdf(target_ulong addr, int mem_idx)
3348: {
3349: helper_check_align(addr, 7);
3350: #if !defined(CONFIG_USER_ONLY)
3351: switch (mem_idx) {
1.1.1.9 ! root 3352: case MMU_USER_IDX:
1.1.1.6 root 3353: stfq_user(addr, DT0);
3354: break;
1.1.1.9 ! root 3355: case MMU_KERNEL_IDX:
1.1.1.6 root 3356: stfq_kernel(addr, DT0);
3357: break;
3358: #ifdef TARGET_SPARC64
1.1.1.9 ! root 3359: case MMU_HYPV_IDX:
1.1.1.6 root 3360: stfq_hypv(addr, DT0);
3361: break;
3362: #endif
3363: default:
1.1.1.9 ! root 3364: DPRINTF_MMU("helper_stdf: need to check MMU idx %d\n", mem_idx);
1.1.1.6 root 3365: break;
3366: }
3367: #else
1.1.1.9 ! root 3368: stfq_raw(address_mask(env, addr), DT0);
1.1.1.6 root 3369: #endif
3370: }
3371:
3372: void helper_lddf(target_ulong addr, int mem_idx)
3373: {
3374: helper_check_align(addr, 7);
3375: #if !defined(CONFIG_USER_ONLY)
3376: switch (mem_idx) {
1.1.1.9 ! root 3377: case MMU_USER_IDX:
1.1.1.6 root 3378: DT0 = ldfq_user(addr);
3379: break;
1.1.1.9 ! root 3380: case MMU_KERNEL_IDX:
1.1.1.6 root 3381: DT0 = ldfq_kernel(addr);
3382: break;
3383: #ifdef TARGET_SPARC64
1.1.1.9 ! root 3384: case MMU_HYPV_IDX:
1.1.1.6 root 3385: DT0 = ldfq_hypv(addr);
3386: break;
3387: #endif
3388: default:
1.1.1.9 ! root 3389: DPRINTF_MMU("helper_lddf: need to check MMU idx %d\n", mem_idx);
1.1.1.6 root 3390: break;
3391: }
3392: #else
1.1.1.9 ! root 3393: DT0 = ldfq_raw(address_mask(env, addr));
1.1.1.6 root 3394: #endif
3395: }
3396:
3397: void helper_ldqf(target_ulong addr, int mem_idx)
3398: {
3399: // XXX add 128 bit load
3400: CPU_QuadU u;
3401:
3402: helper_check_align(addr, 7);
3403: #if !defined(CONFIG_USER_ONLY)
3404: switch (mem_idx) {
1.1.1.9 ! root 3405: case MMU_USER_IDX:
1.1.1.6 root 3406: u.ll.upper = ldq_user(addr);
3407: u.ll.lower = ldq_user(addr + 8);
3408: QT0 = u.q;
3409: break;
1.1.1.9 ! root 3410: case MMU_KERNEL_IDX:
1.1.1.6 root 3411: u.ll.upper = ldq_kernel(addr);
3412: u.ll.lower = ldq_kernel(addr + 8);
3413: QT0 = u.q;
3414: break;
3415: #ifdef TARGET_SPARC64
1.1.1.9 ! root 3416: case MMU_HYPV_IDX:
1.1.1.6 root 3417: u.ll.upper = ldq_hypv(addr);
3418: u.ll.lower = ldq_hypv(addr + 8);
3419: QT0 = u.q;
3420: break;
3421: #endif
3422: default:
1.1.1.9 ! root 3423: DPRINTF_MMU("helper_ldqf: need to check MMU idx %d\n", mem_idx);
1.1.1.6 root 3424: break;
3425: }
3426: #else
1.1.1.9 ! root 3427: u.ll.upper = ldq_raw(address_mask(env, addr));
! 3428: u.ll.lower = ldq_raw(address_mask(env, addr + 8));
1.1.1.6 root 3429: QT0 = u.q;
3430: #endif
3431: }
3432:
3433: void helper_stqf(target_ulong addr, int mem_idx)
3434: {
3435: // XXX add 128 bit store
3436: CPU_QuadU u;
3437:
3438: helper_check_align(addr, 7);
3439: #if !defined(CONFIG_USER_ONLY)
3440: switch (mem_idx) {
1.1.1.9 ! root 3441: case MMU_USER_IDX:
1.1.1.6 root 3442: u.q = QT0;
3443: stq_user(addr, u.ll.upper);
3444: stq_user(addr + 8, u.ll.lower);
3445: break;
1.1.1.9 ! root 3446: case MMU_KERNEL_IDX:
1.1.1.6 root 3447: u.q = QT0;
3448: stq_kernel(addr, u.ll.upper);
3449: stq_kernel(addr + 8, u.ll.lower);
3450: break;
3451: #ifdef TARGET_SPARC64
1.1.1.9 ! root 3452: case MMU_HYPV_IDX:
1.1.1.6 root 3453: u.q = QT0;
3454: stq_hypv(addr, u.ll.upper);
3455: stq_hypv(addr + 8, u.ll.lower);
3456: break;
3457: #endif
3458: default:
1.1.1.9 ! root 3459: DPRINTF_MMU("helper_stqf: need to check MMU idx %d\n", mem_idx);
1.1.1.6 root 3460: break;
3461: }
3462: #else
3463: u.q = QT0;
1.1.1.9 ! root 3464: stq_raw(address_mask(env, addr), u.ll.upper);
! 3465: stq_raw(address_mask(env, addr + 8), u.ll.lower);
1.1.1.6 root 3466: #endif
3467: }
3468:
3469: static inline void set_fsr(void)
1.1 root 3470: {
3471: int rnd_mode;
1.1.1.6 root 3472:
1.1 root 3473: switch (env->fsr & FSR_RD_MASK) {
3474: case FSR_RD_NEAREST:
3475: rnd_mode = float_round_nearest_even;
1.1.1.5 root 3476: break;
1.1 root 3477: default:
3478: case FSR_RD_ZERO:
3479: rnd_mode = float_round_to_zero;
1.1.1.5 root 3480: break;
1.1 root 3481: case FSR_RD_POS:
3482: rnd_mode = float_round_up;
1.1.1.5 root 3483: break;
1.1 root 3484: case FSR_RD_NEG:
3485: rnd_mode = float_round_down;
1.1.1.5 root 3486: break;
1.1 root 3487: }
3488: set_float_rounding_mode(rnd_mode, &env->fp_status);
3489: }
3490:
1.1.1.6 root 3491: void helper_ldfsr(uint32_t new_fsr)
3492: {
3493: env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK);
3494: set_fsr();
3495: }
3496:
3497: #ifdef TARGET_SPARC64
3498: void helper_ldxfsr(uint64_t new_fsr)
3499: {
3500: env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK);
3501: set_fsr();
3502: }
3503: #endif
3504:
3505: void helper_debug(void)
1.1 root 3506: {
3507: env->exception_index = EXCP_DEBUG;
3508: cpu_loop_exit();
3509: }
3510:
3511: #ifndef TARGET_SPARC64
1.1.1.6 root 3512: /* XXX: use another pointer for %iN registers to avoid slow wrapping
3513: handling ? */
3514: void helper_save(void)
3515: {
3516: uint32_t cwp;
3517:
1.1.1.9 ! root 3518: cwp = cwp_dec(env->cwp - 1);
1.1.1.6 root 3519: if (env->wim & (1 << cwp)) {
3520: raise_exception(TT_WIN_OVF);
3521: }
3522: set_cwp(cwp);
3523: }
3524:
3525: void helper_restore(void)
3526: {
3527: uint32_t cwp;
3528:
1.1.1.9 ! root 3529: cwp = cwp_inc(env->cwp + 1);
1.1.1.6 root 3530: if (env->wim & (1 << cwp)) {
3531: raise_exception(TT_WIN_UNF);
3532: }
3533: set_cwp(cwp);
3534: }
3535:
3536: void helper_wrpsr(target_ulong new_psr)
1.1 root 3537: {
1.1.1.9 ! root 3538: if ((new_psr & PSR_CWP) >= env->nwindows) {
1.1.1.5 root 3539: raise_exception(TT_ILL_INSN);
1.1.1.9 ! root 3540: } else {
! 3541: cpu_put_psr(env, new_psr);
! 3542: }
1.1 root 3543: }
3544:
1.1.1.6 root 3545: target_ulong helper_rdpsr(void)
1.1 root 3546: {
1.1.1.9 ! root 3547: return get_psr();
1.1 root 3548: }
3549:
3550: #else
1.1.1.6 root 3551: /* XXX: use another pointer for %iN registers to avoid slow wrapping
3552: handling ? */
3553: void helper_save(void)
3554: {
3555: uint32_t cwp;
3556:
1.1.1.9 ! root 3557: cwp = cwp_dec(env->cwp - 1);
1.1.1.6 root 3558: if (env->cansave == 0) {
3559: raise_exception(TT_SPILL | (env->otherwin != 0 ?
3560: (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
3561: ((env->wstate & 0x7) << 2)));
3562: } else {
3563: if (env->cleanwin - env->canrestore == 0) {
3564: // XXX Clean windows without trap
3565: raise_exception(TT_CLRWIN);
3566: } else {
3567: env->cansave--;
3568: env->canrestore++;
3569: set_cwp(cwp);
3570: }
3571: }
3572: }
3573:
3574: void helper_restore(void)
3575: {
3576: uint32_t cwp;
3577:
1.1.1.9 ! root 3578: cwp = cwp_inc(env->cwp + 1);
1.1.1.6 root 3579: if (env->canrestore == 0) {
3580: raise_exception(TT_FILL | (env->otherwin != 0 ?
3581: (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
3582: ((env->wstate & 0x7) << 2)));
3583: } else {
3584: env->cansave++;
3585: env->canrestore--;
3586: set_cwp(cwp);
3587: }
3588: }
3589:
3590: void helper_flushw(void)
3591: {
3592: if (env->cansave != env->nwindows - 2) {
3593: raise_exception(TT_SPILL | (env->otherwin != 0 ?
3594: (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
3595: ((env->wstate & 0x7) << 2)));
3596: }
3597: }
3598:
3599: void helper_saved(void)
3600: {
3601: env->cansave++;
3602: if (env->otherwin == 0)
3603: env->canrestore--;
3604: else
3605: env->otherwin--;
3606: }
1.1 root 3607:
1.1.1.6 root 3608: void helper_restored(void)
1.1 root 3609: {
1.1.1.6 root 3610: env->canrestore++;
3611: if (env->cleanwin < env->nwindows - 1)
3612: env->cleanwin++;
3613: if (env->otherwin == 0)
3614: env->cansave--;
3615: else
3616: env->otherwin--;
3617: }
3618:
1.1.1.9 ! root 3619: static target_ulong get_ccr(void)
! 3620: {
! 3621: target_ulong psr;
! 3622:
! 3623: psr = get_psr();
! 3624:
! 3625: return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20);
! 3626: }
! 3627:
! 3628: target_ulong cpu_get_ccr(CPUState *env1)
! 3629: {
! 3630: CPUState *saved_env;
! 3631: target_ulong ret;
! 3632:
! 3633: saved_env = env;
! 3634: env = env1;
! 3635: ret = get_ccr();
! 3636: env = saved_env;
! 3637: return ret;
! 3638: }
! 3639:
! 3640: static void put_ccr(target_ulong val)
! 3641: {
! 3642: target_ulong tmp = val;
! 3643:
! 3644: env->xcc = (tmp >> 4) << 20;
! 3645: env->psr = (tmp & 0xf) << 20;
! 3646: CC_OP = CC_OP_FLAGS;
! 3647: }
! 3648:
! 3649: void cpu_put_ccr(CPUState *env1, target_ulong val)
! 3650: {
! 3651: CPUState *saved_env;
! 3652:
! 3653: saved_env = env;
! 3654: env = env1;
! 3655: put_ccr(val);
! 3656: env = saved_env;
! 3657: }
! 3658:
! 3659: static target_ulong get_cwp64(void)
! 3660: {
! 3661: return env->nwindows - 1 - env->cwp;
! 3662: }
! 3663:
! 3664: target_ulong cpu_get_cwp64(CPUState *env1)
! 3665: {
! 3666: CPUState *saved_env;
! 3667: target_ulong ret;
! 3668:
! 3669: saved_env = env;
! 3670: env = env1;
! 3671: ret = get_cwp64();
! 3672: env = saved_env;
! 3673: return ret;
! 3674: }
! 3675:
! 3676: static void put_cwp64(int cwp)
! 3677: {
! 3678: if (unlikely(cwp >= env->nwindows || cwp < 0)) {
! 3679: cwp %= env->nwindows;
! 3680: }
! 3681: set_cwp(env->nwindows - 1 - cwp);
! 3682: }
! 3683:
! 3684: void cpu_put_cwp64(CPUState *env1, int cwp)
! 3685: {
! 3686: CPUState *saved_env;
! 3687:
! 3688: saved_env = env;
! 3689: env = env1;
! 3690: put_cwp64(cwp);
! 3691: env = saved_env;
! 3692: }
! 3693:
1.1.1.6 root 3694: target_ulong helper_rdccr(void)
3695: {
1.1.1.9 ! root 3696: return get_ccr();
1.1.1.6 root 3697: }
3698:
3699: void helper_wrccr(target_ulong new_ccr)
3700: {
1.1.1.9 ! root 3701: put_ccr(new_ccr);
1.1.1.6 root 3702: }
3703:
3704: // CWP handling is reversed in V9, but we still use the V8 register
3705: // order.
3706: target_ulong helper_rdcwp(void)
3707: {
1.1.1.9 ! root 3708: return get_cwp64();
1.1.1.6 root 3709: }
3710:
3711: void helper_wrcwp(target_ulong new_cwp)
3712: {
1.1.1.9 ! root 3713: put_cwp64(new_cwp);
1.1.1.6 root 3714: }
3715:
3716: // This function uses non-native bit order
3717: #define GET_FIELD(X, FROM, TO) \
3718: ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1))
3719:
3720: // This function uses the order in the manuals, i.e. bit 0 is 2^0
3721: #define GET_FIELD_SP(X, FROM, TO) \
3722: GET_FIELD(X, 63 - (TO), 63 - (FROM))
3723:
3724: target_ulong helper_array8(target_ulong pixel_addr, target_ulong cubesize)
3725: {
3726: return (GET_FIELD_SP(pixel_addr, 60, 63) << (17 + 2 * cubesize)) |
3727: (GET_FIELD_SP(pixel_addr, 39, 39 + cubesize - 1) << (17 + cubesize)) |
3728: (GET_FIELD_SP(pixel_addr, 17 + cubesize - 1, 17) << 17) |
3729: (GET_FIELD_SP(pixel_addr, 56, 59) << 13) |
3730: (GET_FIELD_SP(pixel_addr, 35, 38) << 9) |
3731: (GET_FIELD_SP(pixel_addr, 13, 16) << 5) |
3732: (((pixel_addr >> 55) & 1) << 4) |
3733: (GET_FIELD_SP(pixel_addr, 33, 34) << 2) |
3734: GET_FIELD_SP(pixel_addr, 11, 12);
3735: }
3736:
3737: target_ulong helper_alignaddr(target_ulong addr, target_ulong offset)
3738: {
3739: uint64_t tmp;
3740:
3741: tmp = addr + offset;
3742: env->gsr &= ~7ULL;
3743: env->gsr |= tmp & 7ULL;
3744: return tmp & ~7ULL;
3745: }
3746:
3747: target_ulong helper_popc(target_ulong val)
3748: {
3749: return ctpop64(val);
1.1 root 3750: }
3751:
1.1.1.9 ! root 3752: static inline uint64_t *get_gregset(uint32_t pstate)
1.1 root 3753: {
3754: switch (pstate) {
3755: default:
1.1.1.9 ! root 3756: DPRINTF_PSTATE("ERROR in get_gregset: active pstate bits=%x%s%s%s\n",
! 3757: pstate,
! 3758: (pstate & PS_IG) ? " IG" : "",
! 3759: (pstate & PS_MG) ? " MG" : "",
! 3760: (pstate & PS_AG) ? " AG" : "");
! 3761: /* pass through to normal set of global registers */
1.1 root 3762: case 0:
1.1.1.5 root 3763: return env->bgregs;
1.1 root 3764: case PS_AG:
1.1.1.5 root 3765: return env->agregs;
1.1 root 3766: case PS_MG:
1.1.1.5 root 3767: return env->mgregs;
1.1 root 3768: case PS_IG:
1.1.1.5 root 3769: return env->igregs;
1.1 root 3770: }
3771: }
3772:
1.1.1.9 ! root 3773: static inline void change_pstate(uint32_t new_pstate)
1.1 root 3774: {
1.1.1.9 ! root 3775: uint32_t pstate_regs, new_pstate_regs;
1.1 root 3776: uint64_t *src, *dst;
3777:
1.1.1.7 root 3778: if (env->def->features & CPU_FEATURE_GL) {
3779: // PS_AG is not implemented in this case
3780: new_pstate &= ~PS_AG;
3781: }
3782:
1.1 root 3783: pstate_regs = env->pstate & 0xc01;
3784: new_pstate_regs = new_pstate & 0xc01;
1.1.1.7 root 3785:
1.1 root 3786: if (new_pstate_regs != pstate_regs) {
1.1.1.9 ! root 3787: DPRINTF_PSTATE("change_pstate: switching regs old=%x new=%x\n",
! 3788: pstate_regs, new_pstate_regs);
1.1.1.5 root 3789: // Switch global register bank
3790: src = get_gregset(new_pstate_regs);
3791: dst = get_gregset(pstate_regs);
3792: memcpy32(dst, env->gregs);
3793: memcpy32(env->gregs, src);
1.1 root 3794: }
1.1.1.9 ! root 3795: else {
! 3796: DPRINTF_PSTATE("change_pstate: regs new=%x (unchanged)\n",
! 3797: new_pstate_regs);
! 3798: }
1.1 root 3799: env->pstate = new_pstate;
3800: }
3801:
1.1.1.6 root 3802: void helper_wrpstate(target_ulong new_state)
1.1.1.5 root 3803: {
1.1.1.7 root 3804: change_pstate(new_state & 0xf3f);
1.1.1.9 ! root 3805:
! 3806: #if !defined(CONFIG_USER_ONLY)
! 3807: if (cpu_interrupts_enabled(env)) {
! 3808: cpu_check_irqs(env);
! 3809: }
! 3810: #endif
! 3811: }
! 3812:
! 3813: void helper_wrpil(target_ulong new_pil)
! 3814: {
! 3815: #if !defined(CONFIG_USER_ONLY)
! 3816: DPRINTF_PSTATE("helper_wrpil old=%x new=%x\n",
! 3817: env->psrpil, (uint32_t)new_pil);
! 3818:
! 3819: env->psrpil = new_pil;
! 3820:
! 3821: if (cpu_interrupts_enabled(env)) {
! 3822: cpu_check_irqs(env);
! 3823: }
! 3824: #endif
1.1.1.5 root 3825: }
3826:
1.1.1.6 root 3827: void helper_done(void)
1.1 root 3828: {
1.1.1.8 root 3829: trap_state* tsptr = cpu_tsptr(env);
3830:
3831: env->pc = tsptr->tnpc;
3832: env->npc = tsptr->tnpc + 4;
1.1.1.9 ! root 3833: put_ccr(tsptr->tstate >> 32);
1.1.1.8 root 3834: env->asi = (tsptr->tstate >> 24) & 0xff;
3835: change_pstate((tsptr->tstate >> 8) & 0xf3f);
1.1.1.9 ! root 3836: put_cwp64(tsptr->tstate & 0xff);
1.1 root 3837: env->tl--;
1.1.1.9 ! root 3838:
! 3839: DPRINTF_PSTATE("... helper_done tl=%d\n", env->tl);
! 3840:
! 3841: #if !defined(CONFIG_USER_ONLY)
! 3842: if (cpu_interrupts_enabled(env)) {
! 3843: cpu_check_irqs(env);
! 3844: }
! 3845: #endif
1.1 root 3846: }
3847:
1.1.1.6 root 3848: void helper_retry(void)
1.1 root 3849: {
1.1.1.8 root 3850: trap_state* tsptr = cpu_tsptr(env);
3851:
3852: env->pc = tsptr->tpc;
3853: env->npc = tsptr->tnpc;
1.1.1.9 ! root 3854: put_ccr(tsptr->tstate >> 32);
1.1.1.8 root 3855: env->asi = (tsptr->tstate >> 24) & 0xff;
3856: change_pstate((tsptr->tstate >> 8) & 0xf3f);
1.1.1.9 ! root 3857: put_cwp64(tsptr->tstate & 0xff);
1.1 root 3858: env->tl--;
1.1.1.9 ! root 3859:
! 3860: DPRINTF_PSTATE("... helper_retry tl=%d\n", env->tl);
! 3861:
! 3862: #if !defined(CONFIG_USER_ONLY)
! 3863: if (cpu_interrupts_enabled(env)) {
! 3864: cpu_check_irqs(env);
! 3865: }
! 3866: #endif
! 3867: }
! 3868:
! 3869: static void do_modify_softint(const char* operation, uint32_t value)
! 3870: {
! 3871: if (env->softint != value) {
! 3872: env->softint = value;
! 3873: DPRINTF_PSTATE(": %s new %08x\n", operation, env->softint);
! 3874: #if !defined(CONFIG_USER_ONLY)
! 3875: if (cpu_interrupts_enabled(env)) {
! 3876: cpu_check_irqs(env);
! 3877: }
! 3878: #endif
! 3879: }
1.1 root 3880: }
3881:
1.1.1.6 root 3882: void helper_set_softint(uint64_t value)
1.1 root 3883: {
1.1.1.9 ! root 3884: do_modify_softint("helper_set_softint", env->softint | (uint32_t)value);
1.1 root 3885: }
3886:
1.1.1.6 root 3887: void helper_clear_softint(uint64_t value)
1.1 root 3888: {
1.1.1.9 ! root 3889: do_modify_softint("helper_clear_softint", env->softint & (uint32_t)~value);
1.1.1.6 root 3890: }
1.1 root 3891:
1.1.1.6 root 3892: void helper_write_softint(uint64_t value)
3893: {
1.1.1.9 ! root 3894: do_modify_softint("helper_write_softint", (uint32_t)value);
1.1.1.6 root 3895: }
1.1 root 3896: #endif
1.1.1.6 root 3897:
3898: void helper_flush(target_ulong addr)
3899: {
3900: addr &= ~7;
3901: tb_invalidate_page_range(addr, addr + 8);
1.1 root 3902: }
3903:
3904: #ifdef TARGET_SPARC64
1.1.1.5 root 3905: #ifdef DEBUG_PCALL
1.1.1.6 root 3906: static const char * const excp_names[0x80] = {
1.1.1.5 root 3907: [TT_TFAULT] = "Instruction Access Fault",
3908: [TT_TMISS] = "Instruction Access MMU Miss",
3909: [TT_CODE_ACCESS] = "Instruction Access Error",
3910: [TT_ILL_INSN] = "Illegal Instruction",
3911: [TT_PRIV_INSN] = "Privileged Instruction",
3912: [TT_NFPU_INSN] = "FPU Disabled",
3913: [TT_FP_EXCP] = "FPU Exception",
3914: [TT_TOVF] = "Tag Overflow",
3915: [TT_CLRWIN] = "Clean Windows",
3916: [TT_DIV_ZERO] = "Division By Zero",
3917: [TT_DFAULT] = "Data Access Fault",
3918: [TT_DMISS] = "Data Access MMU Miss",
3919: [TT_DATA_ACCESS] = "Data Access Error",
3920: [TT_DPROT] = "Data Protection Error",
3921: [TT_UNALIGNED] = "Unaligned Memory Access",
3922: [TT_PRIV_ACT] = "Privileged Action",
3923: [TT_EXTINT | 0x1] = "External Interrupt 1",
3924: [TT_EXTINT | 0x2] = "External Interrupt 2",
3925: [TT_EXTINT | 0x3] = "External Interrupt 3",
3926: [TT_EXTINT | 0x4] = "External Interrupt 4",
3927: [TT_EXTINT | 0x5] = "External Interrupt 5",
3928: [TT_EXTINT | 0x6] = "External Interrupt 6",
3929: [TT_EXTINT | 0x7] = "External Interrupt 7",
3930: [TT_EXTINT | 0x8] = "External Interrupt 8",
3931: [TT_EXTINT | 0x9] = "External Interrupt 9",
3932: [TT_EXTINT | 0xa] = "External Interrupt 10",
3933: [TT_EXTINT | 0xb] = "External Interrupt 11",
3934: [TT_EXTINT | 0xc] = "External Interrupt 12",
3935: [TT_EXTINT | 0xd] = "External Interrupt 13",
3936: [TT_EXTINT | 0xe] = "External Interrupt 14",
3937: [TT_EXTINT | 0xf] = "External Interrupt 15",
3938: };
3939: #endif
3940:
1.1.1.8 root 3941: trap_state* cpu_tsptr(CPUState* env)
3942: {
3943: return &env->ts[env->tl & MAXTL_MASK];
3944: }
3945:
1.1.1.6 root 3946: void do_interrupt(CPUState *env)
1.1 root 3947: {
1.1.1.6 root 3948: int intno = env->exception_index;
1.1.1.8 root 3949: trap_state* tsptr;
1.1.1.6 root 3950:
1.1 root 3951: #ifdef DEBUG_PCALL
1.1.1.6 root 3952: if (qemu_loglevel_mask(CPU_LOG_INT)) {
1.1.1.5 root 3953: static int count;
3954: const char *name;
3955:
1.1.1.6 root 3956: if (intno < 0 || intno >= 0x180)
1.1.1.5 root 3957: name = "Unknown";
3958: else if (intno >= 0x100)
3959: name = "Trap Instruction";
3960: else if (intno >= 0xc0)
3961: name = "Window Fill";
3962: else if (intno >= 0x80)
3963: name = "Window Spill";
3964: else {
3965: name = excp_names[intno];
3966: if (!name)
3967: name = "Unknown";
3968: }
3969:
1.1.1.6 root 3970: qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64
1.1.1.5 root 3971: " SP=%016" PRIx64 "\n",
3972: count, name, intno,
1.1 root 3973: env->pc,
3974: env->npc, env->regwptr[6]);
1.1.1.6 root 3975: log_cpu_state(env, 0);
1.1 root 3976: #if 0
1.1.1.5 root 3977: {
3978: int i;
3979: uint8_t *ptr;
3980:
1.1.1.6 root 3981: qemu_log(" code=");
1.1.1.5 root 3982: ptr = (uint8_t *)env->pc;
3983: for(i = 0; i < 16; i++) {
1.1.1.6 root 3984: qemu_log(" %02x", ldub(ptr + i));
1.1.1.5 root 3985: }
1.1.1.6 root 3986: qemu_log("\n");
1.1.1.5 root 3987: }
1.1 root 3988: #endif
1.1.1.5 root 3989: count++;
1.1 root 3990: }
3991: #endif
1.1.1.5 root 3992: #if !defined(CONFIG_USER_ONLY)
1.1.1.6 root 3993: if (env->tl >= env->maxtl) {
3994: cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
3995: " Error state", env->exception_index, env->tl, env->maxtl);
1.1.1.5 root 3996: return;
1.1 root 3997: }
3998: #endif
1.1.1.6 root 3999: if (env->tl < env->maxtl - 1) {
1.1.1.5 root 4000: env->tl++;
1.1 root 4001: } else {
1.1.1.5 root 4002: env->pstate |= PS_RED;
1.1.1.6 root 4003: if (env->tl < env->maxtl)
1.1.1.5 root 4004: env->tl++;
1.1 root 4005: }
1.1.1.8 root 4006: tsptr = cpu_tsptr(env);
4007:
1.1.1.9 ! root 4008: tsptr->tstate = (get_ccr() << 32) |
1.1.1.6 root 4009: ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
1.1.1.9 ! root 4010: get_cwp64();
1.1.1.8 root 4011: tsptr->tpc = env->pc;
4012: tsptr->tnpc = env->npc;
4013: tsptr->tt = intno;
1.1.1.7 root 4014:
4015: switch (intno) {
4016: case TT_IVEC:
4017: change_pstate(PS_PEF | PS_PRIV | PS_IG);
4018: break;
4019: case TT_TFAULT:
4020: case TT_DFAULT:
1.1.1.9 ! root 4021: case TT_TMISS ... TT_TMISS + 3:
! 4022: case TT_DMISS ... TT_DMISS + 3:
! 4023: case TT_DPROT ... TT_DPROT + 3:
1.1.1.7 root 4024: change_pstate(PS_PEF | PS_PRIV | PS_MG);
4025: break;
4026: default:
4027: change_pstate(PS_PEF | PS_PRIV | PS_AG);
4028: break;
1.1.1.6 root 4029: }
1.1.1.7 root 4030:
1.1.1.9 ! root 4031: if (intno == TT_CLRWIN) {
! 4032: set_cwp(cwp_dec(env->cwp - 1));
! 4033: } else if ((intno & 0x1c0) == TT_SPILL) {
! 4034: set_cwp(cwp_dec(env->cwp - env->cansave - 2));
! 4035: } else if ((intno & 0x1c0) == TT_FILL) {
! 4036: set_cwp(cwp_inc(env->cwp + 1));
! 4037: }
1.1.1.6 root 4038: env->tbr &= ~0x7fffULL;
4039: env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
1.1 root 4040: env->pc = env->tbr;
4041: env->npc = env->pc + 4;
1.1.1.9 ! root 4042: env->exception_index = -1;
1.1 root 4043: }
4044: #else
1.1.1.5 root 4045: #ifdef DEBUG_PCALL
4046: static const char * const excp_names[0x80] = {
4047: [TT_TFAULT] = "Instruction Access Fault",
4048: [TT_ILL_INSN] = "Illegal Instruction",
4049: [TT_PRIV_INSN] = "Privileged Instruction",
4050: [TT_NFPU_INSN] = "FPU Disabled",
4051: [TT_WIN_OVF] = "Window Overflow",
4052: [TT_WIN_UNF] = "Window Underflow",
4053: [TT_UNALIGNED] = "Unaligned Memory Access",
4054: [TT_FP_EXCP] = "FPU Exception",
4055: [TT_DFAULT] = "Data Access Fault",
4056: [TT_TOVF] = "Tag Overflow",
4057: [TT_EXTINT | 0x1] = "External Interrupt 1",
4058: [TT_EXTINT | 0x2] = "External Interrupt 2",
4059: [TT_EXTINT | 0x3] = "External Interrupt 3",
4060: [TT_EXTINT | 0x4] = "External Interrupt 4",
4061: [TT_EXTINT | 0x5] = "External Interrupt 5",
4062: [TT_EXTINT | 0x6] = "External Interrupt 6",
4063: [TT_EXTINT | 0x7] = "External Interrupt 7",
4064: [TT_EXTINT | 0x8] = "External Interrupt 8",
4065: [TT_EXTINT | 0x9] = "External Interrupt 9",
4066: [TT_EXTINT | 0xa] = "External Interrupt 10",
4067: [TT_EXTINT | 0xb] = "External Interrupt 11",
4068: [TT_EXTINT | 0xc] = "External Interrupt 12",
4069: [TT_EXTINT | 0xd] = "External Interrupt 13",
4070: [TT_EXTINT | 0xe] = "External Interrupt 14",
4071: [TT_EXTINT | 0xf] = "External Interrupt 15",
4072: [TT_TOVF] = "Tag Overflow",
4073: [TT_CODE_ACCESS] = "Instruction Access Error",
4074: [TT_DATA_ACCESS] = "Data Access Error",
4075: [TT_DIV_ZERO] = "Division By Zero",
4076: [TT_NCP_INSN] = "Coprocessor Disabled",
4077: };
4078: #endif
4079:
1.1.1.6 root 4080: void do_interrupt(CPUState *env)
1.1 root 4081: {
1.1.1.6 root 4082: int cwp, intno = env->exception_index;
1.1 root 4083:
4084: #ifdef DEBUG_PCALL
1.1.1.6 root 4085: if (qemu_loglevel_mask(CPU_LOG_INT)) {
1.1.1.5 root 4086: static int count;
4087: const char *name;
4088:
4089: if (intno < 0 || intno >= 0x100)
4090: name = "Unknown";
4091: else if (intno >= 0x80)
4092: name = "Trap Instruction";
4093: else {
4094: name = excp_names[intno];
4095: if (!name)
4096: name = "Unknown";
4097: }
4098:
1.1.1.6 root 4099: qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n",
1.1.1.5 root 4100: count, name, intno,
1.1 root 4101: env->pc,
4102: env->npc, env->regwptr[6]);
1.1.1.6 root 4103: log_cpu_state(env, 0);
1.1 root 4104: #if 0
1.1.1.5 root 4105: {
4106: int i;
4107: uint8_t *ptr;
4108:
1.1.1.6 root 4109: qemu_log(" code=");
1.1.1.5 root 4110: ptr = (uint8_t *)env->pc;
4111: for(i = 0; i < 16; i++) {
1.1.1.6 root 4112: qemu_log(" %02x", ldub(ptr + i));
1.1.1.5 root 4113: }
1.1.1.6 root 4114: qemu_log("\n");
1.1.1.5 root 4115: }
1.1 root 4116: #endif
1.1.1.5 root 4117: count++;
1.1 root 4118: }
4119: #endif
1.1.1.5 root 4120: #if !defined(CONFIG_USER_ONLY)
1.1 root 4121: if (env->psret == 0) {
1.1.1.6 root 4122: cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state",
4123: env->exception_index);
1.1.1.5 root 4124: return;
1.1 root 4125: }
4126: #endif
4127: env->psret = 0;
1.1.1.9 ! root 4128: cwp = cwp_dec(env->cwp - 1);
! 4129: set_cwp(cwp);
1.1 root 4130: env->regwptr[9] = env->pc;
4131: env->regwptr[10] = env->npc;
4132: env->psrps = env->psrs;
4133: env->psrs = 1;
4134: env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
4135: env->pc = env->tbr;
4136: env->npc = env->pc + 4;
1.1.1.9 ! root 4137: env->exception_index = -1;
1.1 root 4138: }
4139: #endif
4140:
1.1.1.5 root 4141: #if !defined(CONFIG_USER_ONLY)
4142:
4143: static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
4144: void *retaddr);
1.1 root 4145:
4146: #define MMUSUFFIX _mmu
1.1.1.5 root 4147: #define ALIGNED_ONLY
1.1 root 4148:
4149: #define SHIFT 0
4150: #include "softmmu_template.h"
4151:
4152: #define SHIFT 1
4153: #include "softmmu_template.h"
4154:
4155: #define SHIFT 2
4156: #include "softmmu_template.h"
4157:
4158: #define SHIFT 3
4159: #include "softmmu_template.h"
4160:
1.1.1.6 root 4161: /* XXX: make it generic ? */
4162: static void cpu_restore_state2(void *retaddr)
4163: {
4164: TranslationBlock *tb;
4165: unsigned long pc;
4166:
4167: if (retaddr) {
4168: /* now we have a real cpu fault */
4169: pc = (unsigned long)retaddr;
4170: tb = tb_find_pc(pc);
4171: if (tb) {
4172: /* the PC is inside the translated code. It means that we have
4173: a virtual CPU fault */
4174: cpu_restore_state(tb, env, pc, (void *)(long)env->cond);
4175: }
4176: }
4177: }
4178:
1.1.1.5 root 4179: static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
4180: void *retaddr)
4181: {
4182: #ifdef DEBUG_UNALIGNED
1.1.1.6 root 4183: printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx
4184: "\n", addr, env->pc);
1.1.1.5 root 4185: #endif
1.1.1.6 root 4186: cpu_restore_state2(retaddr);
1.1.1.5 root 4187: raise_exception(TT_UNALIGNED);
4188: }
1.1 root 4189:
4190: /* try to fill the TLB and return an exception if error. If retaddr is
4191: NULL, it means that the function was called in C code (i.e. not
4192: from generated code or from helper.c) */
4193: /* XXX: fix it to restore all registers */
1.1.1.5 root 4194: void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
1.1 root 4195: {
4196: int ret;
4197: CPUState *saved_env;
4198:
4199: /* XXX: hack to restore env in all cases, even if not called from
4200: generated code */
4201: saved_env = env;
4202: env = cpu_single_env;
4203:
1.1.1.5 root 4204: ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
1.1 root 4205: if (ret) {
1.1.1.6 root 4206: cpu_restore_state2(retaddr);
1.1 root 4207: cpu_loop_exit();
4208: }
4209: env = saved_env;
4210: }
4211:
1.1.1.9 ! root 4212: #endif /* !CONFIG_USER_ONLY */
1.1.1.5 root 4213:
4214: #ifndef TARGET_SPARC64
1.1.1.9 ! root 4215: #if !defined(CONFIG_USER_ONLY)
1.1.1.5 root 4216: void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
1.1.1.6 root 4217: int is_asi, int size)
1.1.1.5 root 4218: {
4219: CPUState *saved_env;
1.1.1.9 ! root 4220: int fault_type;
1.1.1.5 root 4221:
4222: /* XXX: hack to restore env in all cases, even if not called from
4223: generated code */
4224: saved_env = env;
4225: env = cpu_single_env;
4226: #ifdef DEBUG_UNASSIGNED
4227: if (is_asi)
1.1.1.6 root 4228: printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
4229: " asi 0x%02x from " TARGET_FMT_lx "\n",
4230: is_exec ? "exec" : is_write ? "write" : "read", size,
4231: size == 1 ? "" : "s", addr, is_asi, env->pc);
1.1.1.5 root 4232: else
1.1.1.6 root 4233: printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx
4234: " from " TARGET_FMT_lx "\n",
4235: is_exec ? "exec" : is_write ? "write" : "read", size,
4236: size == 1 ? "" : "s", addr, env->pc);
1.1.1.5 root 4237: #endif
1.1.1.9 ! root 4238: /* Don't overwrite translation and access faults */
! 4239: fault_type = (env->mmuregs[3] & 0x1c) >> 2;
! 4240: if ((fault_type > 4) || (fault_type == 0)) {
! 4241: env->mmuregs[3] = 0; /* Fault status register */
! 4242: if (is_asi)
! 4243: env->mmuregs[3] |= 1 << 16;
! 4244: if (env->psrs)
! 4245: env->mmuregs[3] |= 1 << 5;
! 4246: if (is_exec)
! 4247: env->mmuregs[3] |= 1 << 6;
! 4248: if (is_write)
! 4249: env->mmuregs[3] |= 1 << 7;
! 4250: env->mmuregs[3] |= (5 << 2) | 2;
! 4251: /* SuperSPARC will never place instruction fault addresses in the FAR */
! 4252: if (!is_exec) {
! 4253: env->mmuregs[4] = addr; /* Fault address register */
! 4254: }
! 4255: }
! 4256: /* overflow (same type fault was not read before another fault) */
! 4257: if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) {
! 4258: env->mmuregs[3] |= 1;
! 4259: }
! 4260:
1.1.1.5 root 4261: if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
4262: if (is_exec)
4263: raise_exception(TT_CODE_ACCESS);
4264: else
4265: raise_exception(TT_DATA_ACCESS);
4266: }
1.1.1.9 ! root 4267:
! 4268: /* flush neverland mappings created during no-fault mode,
! 4269: so the sequential MMU faults report proper fault types */
! 4270: if (env->mmuregs[0] & MMU_NF) {
! 4271: tlb_flush(env, 1);
! 4272: }
! 4273:
1.1.1.5 root 4274: env = saved_env;
4275: }
1.1.1.9 ! root 4276: #endif
! 4277: #else
! 4278: #if defined(CONFIG_USER_ONLY)
! 4279: static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
! 4280: int is_asi, int size)
1.1.1.5 root 4281: #else
4282: void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
1.1.1.6 root 4283: int is_asi, int size)
1.1.1.9 ! root 4284: #endif
1.1.1.5 root 4285: {
4286: CPUState *saved_env;
4287:
4288: /* XXX: hack to restore env in all cases, even if not called from
4289: generated code */
4290: saved_env = env;
4291: env = cpu_single_env;
1.1.1.9 ! root 4292:
! 4293: #ifdef DEBUG_UNASSIGNED
1.1.1.6 root 4294: printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
4295: "\n", addr, env->pc);
1.1.1.5 root 4296: #endif
1.1.1.9 ! root 4297:
1.1.1.5 root 4298: if (is_exec)
4299: raise_exception(TT_CODE_ACCESS);
4300: else
4301: raise_exception(TT_DATA_ACCESS);
1.1.1.9 ! root 4302:
! 4303: env = saved_env;
1.1.1.5 root 4304: }
4305: #endif
4306:
1.1.1.9 ! root 4307:
1.1.1.6 root 4308: #ifdef TARGET_SPARC64
4309: void helper_tick_set_count(void *opaque, uint64_t count)
4310: {
4311: #if !defined(CONFIG_USER_ONLY)
4312: cpu_tick_set_count(opaque, count);
4313: #endif
4314: }
4315:
4316: uint64_t helper_tick_get_count(void *opaque)
4317: {
4318: #if !defined(CONFIG_USER_ONLY)
4319: return cpu_tick_get_count(opaque);
4320: #else
4321: return 0;
4322: #endif
4323: }
4324:
4325: void helper_tick_set_limit(void *opaque, uint64_t limit)
4326: {
4327: #if !defined(CONFIG_USER_ONLY)
4328: cpu_tick_set_limit(opaque, limit);
4329: #endif
4330: }
4331: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.