sun4m: avoid structure holes spotted by pahole
[qemu/mdroth.git] / target-sparc / helper.c
blob1fe1f074efa5b70d86ac0273c30271ca1940f4f8
1 /*
2 * sparc helpers
4 * Copyright (c) 2003-2005 Fabrice Bellard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 #include <stdarg.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <inttypes.h>
25 #include "cpu.h"
26 #include "qemu-common.h"
28 //#define DEBUG_MMU
29 //#define DEBUG_FEATURES
31 #ifdef DEBUG_MMU
32 #define DPRINTF_MMU(fmt, ...) \
33 do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
34 #else
35 #define DPRINTF_MMU(fmt, ...) do {} while (0)
36 #endif
38 static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
40 /* Sparc MMU emulation */
42 #if defined(CONFIG_USER_ONLY)
44 int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
45 int mmu_idx)
47 if (rw & 2)
48 env1->exception_index = TT_TFAULT;
49 else
50 env1->exception_index = TT_DFAULT;
51 return 1;
54 #else
56 #ifndef TARGET_SPARC64
58 * Sparc V8 Reference MMU (SRMMU)
60 static const int access_table[8][8] = {
61 { 0, 0, 0, 0, 8, 0, 12, 12 },
62 { 0, 0, 0, 0, 8, 0, 0, 0 },
63 { 8, 8, 0, 0, 0, 8, 12, 12 },
64 { 8, 8, 0, 0, 0, 8, 0, 0 },
65 { 8, 0, 8, 0, 8, 8, 12, 12 },
66 { 8, 0, 8, 0, 8, 0, 8, 0 },
67 { 8, 8, 8, 0, 8, 8, 12, 12 },
68 { 8, 8, 8, 0, 8, 8, 8, 0 }
71 static const int perm_table[2][8] = {
73 PAGE_READ,
74 PAGE_READ | PAGE_WRITE,
75 PAGE_READ | PAGE_EXEC,
76 PAGE_READ | PAGE_WRITE | PAGE_EXEC,
77 PAGE_EXEC,
78 PAGE_READ | PAGE_WRITE,
79 PAGE_READ | PAGE_EXEC,
80 PAGE_READ | PAGE_WRITE | PAGE_EXEC
83 PAGE_READ,
84 PAGE_READ | PAGE_WRITE,
85 PAGE_READ | PAGE_EXEC,
86 PAGE_READ | PAGE_WRITE | PAGE_EXEC,
87 PAGE_EXEC,
88 PAGE_READ,
94 static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
95 int *prot, int *access_index,
96 target_ulong address, int rw, int mmu_idx,
97 target_ulong *page_size)
99 int access_perms = 0;
100 target_phys_addr_t pde_ptr;
101 uint32_t pde;
102 int error_code = 0, is_dirty, is_user;
103 unsigned long page_offset;
105 is_user = mmu_idx == MMU_USER_IDX;
107 if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
108 *page_size = TARGET_PAGE_SIZE;
109 // Boot mode: instruction fetches are taken from PROM
110 if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
111 *physical = env->prom_addr | (address & 0x7ffffULL);
112 *prot = PAGE_READ | PAGE_EXEC;
113 return 0;
115 *physical = address;
116 *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
117 return 0;
120 *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
121 *physical = 0xffffffffffff0000ULL;
123 /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
124 /* Context base + context number */
125 pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
126 pde = ldl_phys(pde_ptr);
128 /* Ctx pde */
129 switch (pde & PTE_ENTRYTYPE_MASK) {
130 default:
131 case 0: /* Invalid */
132 return 1 << 2;
133 case 2: /* L0 PTE, maybe should not happen? */
134 case 3: /* Reserved */
135 return 4 << 2;
136 case 1: /* L0 PDE */
137 pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
138 pde = ldl_phys(pde_ptr);
140 switch (pde & PTE_ENTRYTYPE_MASK) {
141 default:
142 case 0: /* Invalid */
143 return (1 << 8) | (1 << 2);
144 case 3: /* Reserved */
145 return (1 << 8) | (4 << 2);
146 case 1: /* L1 PDE */
147 pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
148 pde = ldl_phys(pde_ptr);
150 switch (pde & PTE_ENTRYTYPE_MASK) {
151 default:
152 case 0: /* Invalid */
153 return (2 << 8) | (1 << 2);
154 case 3: /* Reserved */
155 return (2 << 8) | (4 << 2);
156 case 1: /* L2 PDE */
157 pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
158 pde = ldl_phys(pde_ptr);
160 switch (pde & PTE_ENTRYTYPE_MASK) {
161 default:
162 case 0: /* Invalid */
163 return (3 << 8) | (1 << 2);
164 case 1: /* PDE, should not happen */
165 case 3: /* Reserved */
166 return (3 << 8) | (4 << 2);
167 case 2: /* L3 PTE */
168 page_offset = (address & TARGET_PAGE_MASK) &
169 (TARGET_PAGE_SIZE - 1);
171 *page_size = TARGET_PAGE_SIZE;
172 break;
173 case 2: /* L2 PTE */
174 page_offset = address & 0x3ffff;
175 *page_size = 0x40000;
177 break;
178 case 2: /* L1 PTE */
179 page_offset = address & 0xffffff;
180 *page_size = 0x1000000;
184 /* check access */
185 access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
186 error_code = access_table[*access_index][access_perms];
187 if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user))
188 return error_code;
190 /* update page modified and dirty bits */
191 is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
192 if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
193 pde |= PG_ACCESSED_MASK;
194 if (is_dirty)
195 pde |= PG_MODIFIED_MASK;
196 stl_phys_notdirty(pde_ptr, pde);
199 /* the page can be put in the TLB */
200 *prot = perm_table[is_user][access_perms];
201 if (!(pde & PG_MODIFIED_MASK)) {
202 /* only set write access if already dirty... otherwise wait
203 for dirty access */
204 *prot &= ~PAGE_WRITE;
207 /* Even if large ptes, we map only one 4KB page in the cache to
208 avoid filling it too fast */
209 *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
210 return error_code;
213 /* Perform address translation */
214 int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
215 int mmu_idx)
217 target_phys_addr_t paddr;
218 target_ulong vaddr;
219 target_ulong page_size;
220 int error_code = 0, prot, access_index;
222 error_code = get_physical_address(env, &paddr, &prot, &access_index,
223 address, rw, mmu_idx, &page_size);
224 if (error_code == 0) {
225 vaddr = address & TARGET_PAGE_MASK;
226 paddr &= TARGET_PAGE_MASK;
227 #ifdef DEBUG_MMU
228 printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
229 TARGET_FMT_lx "\n", address, paddr, vaddr);
230 #endif
231 tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
232 return 0;
235 if (env->mmuregs[3]) /* Fault status register */
236 env->mmuregs[3] = 1; /* overflow (not read before another fault) */
237 env->mmuregs[3] |= (access_index << 5) | error_code | 2;
238 env->mmuregs[4] = address; /* Fault address register */
240 if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) {
241 // No fault mode: if a mapping is available, just override
242 // permissions. If no mapping is available, redirect accesses to
243 // neverland. Fake/overridden mappings will be flushed when
244 // switching to normal mode.
245 vaddr = address & TARGET_PAGE_MASK;
246 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
247 tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
248 return 0;
249 } else {
250 if (rw & 2)
251 env->exception_index = TT_TFAULT;
252 else
253 env->exception_index = TT_DFAULT;
254 return 1;
258 target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
260 target_phys_addr_t pde_ptr;
261 uint32_t pde;
263 /* Context base + context number */
264 pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
265 (env->mmuregs[2] << 2);
266 pde = ldl_phys(pde_ptr);
268 switch (pde & PTE_ENTRYTYPE_MASK) {
269 default:
270 case 0: /* Invalid */
271 case 2: /* PTE, maybe should not happen? */
272 case 3: /* Reserved */
273 return 0;
274 case 1: /* L1 PDE */
275 if (mmulev == 3)
276 return pde;
277 pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
278 pde = ldl_phys(pde_ptr);
280 switch (pde & PTE_ENTRYTYPE_MASK) {
281 default:
282 case 0: /* Invalid */
283 case 3: /* Reserved */
284 return 0;
285 case 2: /* L1 PTE */
286 return pde;
287 case 1: /* L2 PDE */
288 if (mmulev == 2)
289 return pde;
290 pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
291 pde = ldl_phys(pde_ptr);
293 switch (pde & PTE_ENTRYTYPE_MASK) {
294 default:
295 case 0: /* Invalid */
296 case 3: /* Reserved */
297 return 0;
298 case 2: /* L2 PTE */
299 return pde;
300 case 1: /* L3 PDE */
301 if (mmulev == 1)
302 return pde;
303 pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
304 pde = ldl_phys(pde_ptr);
306 switch (pde & PTE_ENTRYTYPE_MASK) {
307 default:
308 case 0: /* Invalid */
309 case 1: /* PDE, should not happen */
310 case 3: /* Reserved */
311 return 0;
312 case 2: /* L3 PTE */
313 return pde;
318 return 0;
321 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
323 target_ulong va, va1, va2;
324 unsigned int n, m, o;
325 target_phys_addr_t pde_ptr, pa;
326 uint32_t pde;
328 pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
329 pde = ldl_phys(pde_ptr);
330 (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
331 (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
332 for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
333 pde = mmu_probe(env, va, 2);
334 if (pde) {
335 pa = cpu_get_phys_page_debug(env, va);
336 (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
337 " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
338 for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
339 pde = mmu_probe(env, va1, 1);
340 if (pde) {
341 pa = cpu_get_phys_page_debug(env, va1);
342 (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
343 TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
344 va1, pa, pde);
345 for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
346 pde = mmu_probe(env, va2, 0);
347 if (pde) {
348 pa = cpu_get_phys_page_debug(env, va2);
349 (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
350 TARGET_FMT_plx " PTE: "
351 TARGET_FMT_lx "\n",
352 va2, pa, pde);
361 #else /* !TARGET_SPARC64 */
363 // 41 bit physical address space
364 static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
366 return x & 0x1ffffffffffULL;
370 * UltraSparc IIi I/DMMUs
373 // Returns true if TTE tag is valid and matches virtual address value in context
374 // requires virtual address mask value calculated from TTE entry size
375 static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
376 uint64_t address, uint64_t context,
377 target_phys_addr_t *physical)
379 uint64_t mask;
381 switch (TTE_PGSIZE(tlb->tte)) {
382 default:
383 case 0x0: // 8k
384 mask = 0xffffffffffffe000ULL;
385 break;
386 case 0x1: // 64k
387 mask = 0xffffffffffff0000ULL;
388 break;
389 case 0x2: // 512k
390 mask = 0xfffffffffff80000ULL;
391 break;
392 case 0x3: // 4M
393 mask = 0xffffffffffc00000ULL;
394 break;
397 // valid, context match, virtual address match?
398 if (TTE_IS_VALID(tlb->tte) &&
399 (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
400 && compare_masked(address, tlb->tag, mask))
402 // decode physical address
403 *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
404 return 1;
407 return 0;
410 static int get_physical_address_data(CPUState *env,
411 target_phys_addr_t *physical, int *prot,
412 target_ulong address, int rw, int mmu_idx)
414 unsigned int i;
415 uint64_t context;
416 uint64_t sfsr = 0;
418 int is_user = (mmu_idx == MMU_USER_IDX ||
419 mmu_idx == MMU_USER_SECONDARY_IDX);
421 if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
422 *physical = ultrasparc_truncate_physical(address);
423 *prot = PAGE_READ | PAGE_WRITE;
424 return 0;
427 switch(mmu_idx) {
428 case MMU_USER_IDX:
429 case MMU_KERNEL_IDX:
430 context = env->dmmu.mmu_primary_context & 0x1fff;
431 sfsr |= SFSR_CT_PRIMARY;
432 break;
433 case MMU_USER_SECONDARY_IDX:
434 case MMU_KERNEL_SECONDARY_IDX:
435 context = env->dmmu.mmu_secondary_context & 0x1fff;
436 sfsr |= SFSR_CT_SECONDARY;
437 break;
438 case MMU_NUCLEUS_IDX:
439 sfsr |= SFSR_CT_NUCLEUS;
440 /* FALLTHRU */
441 default:
442 context = 0;
443 break;
446 if (rw == 1) {
447 sfsr |= SFSR_WRITE_BIT;
448 } else if (rw == 4) {
449 sfsr |= SFSR_NF_BIT;
452 for (i = 0; i < 64; i++) {
453 // ctx match, vaddr match, valid?
454 if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
455 int do_fault = 0;
457 // access ok?
458 /* multiple bits in SFSR.FT may be set on TT_DFAULT */
459 if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
460 do_fault = 1;
461 sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */
463 DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64
464 " mmu_idx=%d tl=%d\n",
465 address, context, mmu_idx, env->tl);
467 if (rw == 4) {
468 if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) {
469 do_fault = 1;
470 sfsr |= SFSR_FT_NF_E_BIT;
472 } else {
473 if (TTE_IS_NFO(env->dtlb[i].tte)) {
474 do_fault = 1;
475 sfsr |= SFSR_FT_NFO_BIT;
479 if (do_fault) {
480 /* faults above are reported with TT_DFAULT. */
481 env->exception_index = TT_DFAULT;
482 } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) {
483 do_fault = 1;
484 env->exception_index = TT_DPROT;
486 DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64
487 " mmu_idx=%d tl=%d\n",
488 address, context, mmu_idx, env->tl);
491 if (!do_fault) {
492 *prot = PAGE_READ;
493 if (TTE_IS_W_OK(env->dtlb[i].tte)) {
494 *prot |= PAGE_WRITE;
497 TTE_SET_USED(env->dtlb[i].tte);
499 return 0;
502 if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
503 sfsr |= SFSR_OW_BIT; /* overflow (not read before
504 another fault) */
507 if (env->pstate & PS_PRIV) {
508 sfsr |= SFSR_PR_BIT;
511 /* FIXME: ASI field in SFSR must be set */
512 env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
514 env->dmmu.sfar = address; /* Fault address register */
516 env->dmmu.tag_access = (address & ~0x1fffULL) | context;
518 return 1;
522 DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n",
523 address, context);
526 * On MMU misses:
527 * - UltraSPARC IIi: SFSR and SFAR unmodified
528 * - JPS1: SFAR updated and some fields of SFSR updated
530 env->dmmu.tag_access = (address & ~0x1fffULL) | context;
531 env->exception_index = TT_DMISS;
532 return 1;
535 static int get_physical_address_code(CPUState *env,
536 target_phys_addr_t *physical, int *prot,
537 target_ulong address, int mmu_idx)
539 unsigned int i;
540 uint64_t context;
542 int is_user = (mmu_idx == MMU_USER_IDX ||
543 mmu_idx == MMU_USER_SECONDARY_IDX);
545 if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
546 /* IMMU disabled */
547 *physical = ultrasparc_truncate_physical(address);
548 *prot = PAGE_EXEC;
549 return 0;
552 if (env->tl == 0) {
553 /* PRIMARY context */
554 context = env->dmmu.mmu_primary_context & 0x1fff;
555 } else {
556 /* NUCLEUS context */
557 context = 0;
560 for (i = 0; i < 64; i++) {
561 // ctx match, vaddr match, valid?
562 if (ultrasparc_tag_match(&env->itlb[i],
563 address, context, physical)) {
564 // access ok?
565 if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
566 /* Fault status register */
567 if (env->immu.sfsr & SFSR_VALID_BIT) {
568 env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
569 another fault) */
570 } else {
571 env->immu.sfsr = 0;
573 if (env->pstate & PS_PRIV) {
574 env->immu.sfsr |= SFSR_PR_BIT;
576 if (env->tl > 0) {
577 env->immu.sfsr |= SFSR_CT_NUCLEUS;
580 /* FIXME: ASI field in SFSR must be set */
581 env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
582 env->exception_index = TT_TFAULT;
584 env->immu.tag_access = (address & ~0x1fffULL) | context;
586 DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n",
587 address, context);
589 return 1;
591 *prot = PAGE_EXEC;
592 TTE_SET_USED(env->itlb[i].tte);
593 return 0;
597 DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n",
598 address, context);
600 /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
601 env->immu.tag_access = (address & ~0x1fffULL) | context;
602 env->exception_index = TT_TMISS;
603 return 1;
606 static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
607 int *prot, int *access_index,
608 target_ulong address, int rw, int mmu_idx,
609 target_ulong *page_size)
611 /* ??? We treat everything as a small page, then explicitly flush
612 everything when an entry is evicted. */
613 *page_size = TARGET_PAGE_SIZE;
615 #if defined (DEBUG_MMU)
616 /* safety net to catch wrong softmmu index use from dynamic code */
617 if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
618 DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d"
619 " primary context=%" PRIx64
620 " secondary context=%" PRIx64
621 " address=%" PRIx64
622 "\n",
623 (rw == 2 ? "CODE" : "DATA"),
624 env->tl, mmu_idx,
625 env->dmmu.mmu_primary_context,
626 env->dmmu.mmu_secondary_context,
627 address);
629 #endif
631 if (rw == 2)
632 return get_physical_address_code(env, physical, prot, address,
633 mmu_idx);
634 else
635 return get_physical_address_data(env, physical, prot, address, rw,
636 mmu_idx);
639 /* Perform address translation */
640 int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
641 int mmu_idx)
643 target_ulong virt_addr, vaddr;
644 target_phys_addr_t paddr;
645 target_ulong page_size;
646 int error_code = 0, prot, access_index;
648 error_code = get_physical_address(env, &paddr, &prot, &access_index,
649 address, rw, mmu_idx, &page_size);
650 if (error_code == 0) {
651 virt_addr = address & TARGET_PAGE_MASK;
652 vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
653 (TARGET_PAGE_SIZE - 1));
655 DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 ","
656 " vaddr %" PRIx64
657 " mmu_idx=%d"
658 " tl=%d"
659 " primary context=%" PRIx64
660 " secondary context=%" PRIx64
661 "\n",
662 address, paddr, vaddr, mmu_idx, env->tl,
663 env->dmmu.mmu_primary_context,
664 env->dmmu.mmu_secondary_context);
666 tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
667 return 0;
669 // XXX
670 return 1;
673 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
675 unsigned int i;
676 const char *mask;
678 (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
679 PRId64 "\n",
680 env->dmmu.mmu_primary_context,
681 env->dmmu.mmu_secondary_context);
682 if ((env->lsu & DMMU_E) == 0) {
683 (*cpu_fprintf)(f, "DMMU disabled\n");
684 } else {
685 (*cpu_fprintf)(f, "DMMU dump\n");
686 for (i = 0; i < 64; i++) {
687 switch (TTE_PGSIZE(env->dtlb[i].tte)) {
688 default:
689 case 0x0:
690 mask = " 8k";
691 break;
692 case 0x1:
693 mask = " 64k";
694 break;
695 case 0x2:
696 mask = "512k";
697 break;
698 case 0x3:
699 mask = " 4M";
700 break;
702 if (TTE_IS_VALID(env->dtlb[i].tte)) {
703 (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
704 ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
706 env->dtlb[i].tag & (uint64_t)~0x1fffULL,
707 TTE_PA(env->dtlb[i].tte),
708 mask,
709 TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user",
710 TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO",
711 TTE_IS_LOCKED(env->dtlb[i].tte) ?
712 "locked" : "unlocked",
713 env->dtlb[i].tag & (uint64_t)0x1fffULL,
714 TTE_IS_GLOBAL(env->dtlb[i].tte)?
715 "global" : "local");
719 if ((env->lsu & IMMU_E) == 0) {
720 (*cpu_fprintf)(f, "IMMU disabled\n");
721 } else {
722 (*cpu_fprintf)(f, "IMMU dump\n");
723 for (i = 0; i < 64; i++) {
724 switch (TTE_PGSIZE(env->itlb[i].tte)) {
725 default:
726 case 0x0:
727 mask = " 8k";
728 break;
729 case 0x1:
730 mask = " 64k";
731 break;
732 case 0x2:
733 mask = "512k";
734 break;
735 case 0x3:
736 mask = " 4M";
737 break;
739 if (TTE_IS_VALID(env->itlb[i].tte)) {
740 (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
741 ", %s, %s, %s, ctx %" PRId64 " %s\n",
743 env->itlb[i].tag & (uint64_t)~0x1fffULL,
744 TTE_PA(env->itlb[i].tte),
745 mask,
746 TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user",
747 TTE_IS_LOCKED(env->itlb[i].tte) ?
748 "locked" : "unlocked",
749 env->itlb[i].tag & (uint64_t)0x1fffULL,
750 TTE_IS_GLOBAL(env->itlb[i].tte)?
751 "global" : "local");
757 #endif /* TARGET_SPARC64 */
758 #endif /* !CONFIG_USER_ONLY */
761 #if !defined(CONFIG_USER_ONLY)
762 static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys,
763 target_ulong addr, int rw, int mmu_idx)
765 target_ulong page_size;
766 int prot, access_index;
768 return get_physical_address(env, phys, &prot, &access_index, addr, rw,
769 mmu_idx, &page_size);
772 #if defined(TARGET_SPARC64)
773 target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
774 int mmu_idx)
776 target_phys_addr_t phys_addr;
778 if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) {
779 return -1;
781 return phys_addr;
783 #endif
785 target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
787 target_phys_addr_t phys_addr;
788 int mmu_idx = cpu_mmu_index(env);
790 if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) {
791 if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) {
792 return -1;
795 if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) {
796 return -1;
798 return phys_addr;
800 #endif
802 #ifdef TARGET_SPARC64
803 #ifdef DEBUG_PCALL
804 static const char * const excp_names[0x80] = {
805 [TT_TFAULT] = "Instruction Access Fault",
806 [TT_TMISS] = "Instruction Access MMU Miss",
807 [TT_CODE_ACCESS] = "Instruction Access Error",
808 [TT_ILL_INSN] = "Illegal Instruction",
809 [TT_PRIV_INSN] = "Privileged Instruction",
810 [TT_NFPU_INSN] = "FPU Disabled",
811 [TT_FP_EXCP] = "FPU Exception",
812 [TT_TOVF] = "Tag Overflow",
813 [TT_CLRWIN] = "Clean Windows",
814 [TT_DIV_ZERO] = "Division By Zero",
815 [TT_DFAULT] = "Data Access Fault",
816 [TT_DMISS] = "Data Access MMU Miss",
817 [TT_DATA_ACCESS] = "Data Access Error",
818 [TT_DPROT] = "Data Protection Error",
819 [TT_UNALIGNED] = "Unaligned Memory Access",
820 [TT_PRIV_ACT] = "Privileged Action",
821 [TT_EXTINT | 0x1] = "External Interrupt 1",
822 [TT_EXTINT | 0x2] = "External Interrupt 2",
823 [TT_EXTINT | 0x3] = "External Interrupt 3",
824 [TT_EXTINT | 0x4] = "External Interrupt 4",
825 [TT_EXTINT | 0x5] = "External Interrupt 5",
826 [TT_EXTINT | 0x6] = "External Interrupt 6",
827 [TT_EXTINT | 0x7] = "External Interrupt 7",
828 [TT_EXTINT | 0x8] = "External Interrupt 8",
829 [TT_EXTINT | 0x9] = "External Interrupt 9",
830 [TT_EXTINT | 0xa] = "External Interrupt 10",
831 [TT_EXTINT | 0xb] = "External Interrupt 11",
832 [TT_EXTINT | 0xc] = "External Interrupt 12",
833 [TT_EXTINT | 0xd] = "External Interrupt 13",
834 [TT_EXTINT | 0xe] = "External Interrupt 14",
835 [TT_EXTINT | 0xf] = "External Interrupt 15",
837 #endif
839 void do_interrupt(CPUState *env)
841 int intno = env->exception_index;
842 trap_state *tsptr;
844 #ifdef DEBUG_PCALL
845 if (qemu_loglevel_mask(CPU_LOG_INT)) {
846 static int count;
847 const char *name;
849 if (intno < 0 || intno >= 0x180) {
850 name = "Unknown";
851 } else if (intno >= 0x100) {
852 name = "Trap Instruction";
853 } else if (intno >= 0xc0) {
854 name = "Window Fill";
855 } else if (intno >= 0x80) {
856 name = "Window Spill";
857 } else {
858 name = excp_names[intno];
859 if (!name) {
860 name = "Unknown";
864 qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64
865 " SP=%016" PRIx64 "\n",
866 count, name, intno,
867 env->pc,
868 env->npc, env->regwptr[6]);
869 log_cpu_state(env, 0);
870 #if 0
872 int i;
873 uint8_t *ptr;
875 qemu_log(" code=");
876 ptr = (uint8_t *)env->pc;
877 for (i = 0; i < 16; i++) {
878 qemu_log(" %02x", ldub(ptr + i));
880 qemu_log("\n");
882 #endif
883 count++;
885 #endif
886 #if !defined(CONFIG_USER_ONLY)
887 if (env->tl >= env->maxtl) {
888 cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
889 " Error state", env->exception_index, env->tl, env->maxtl);
890 return;
892 #endif
893 if (env->tl < env->maxtl - 1) {
894 env->tl++;
895 } else {
896 env->pstate |= PS_RED;
897 if (env->tl < env->maxtl) {
898 env->tl++;
901 tsptr = cpu_tsptr(env);
903 tsptr->tstate = (cpu_get_ccr(env) << 32) |
904 ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
905 cpu_get_cwp64(env);
906 tsptr->tpc = env->pc;
907 tsptr->tnpc = env->npc;
908 tsptr->tt = intno;
910 switch (intno) {
911 case TT_IVEC:
912 cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
913 break;
914 case TT_TFAULT:
915 case TT_DFAULT:
916 case TT_TMISS ... TT_TMISS + 3:
917 case TT_DMISS ... TT_DMISS + 3:
918 case TT_DPROT ... TT_DPROT + 3:
919 cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG);
920 break;
921 default:
922 cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG);
923 break;
926 if (intno == TT_CLRWIN) {
927 cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1));
928 } else if ((intno & 0x1c0) == TT_SPILL) {
929 cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
930 } else if ((intno & 0x1c0) == TT_FILL) {
931 cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
933 env->tbr &= ~0x7fffULL;
934 env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
935 env->pc = env->tbr;
936 env->npc = env->pc + 4;
937 env->exception_index = -1;
939 #else
940 #ifdef DEBUG_PCALL
941 static const char * const excp_names[0x80] = {
942 [TT_TFAULT] = "Instruction Access Fault",
943 [TT_ILL_INSN] = "Illegal Instruction",
944 [TT_PRIV_INSN] = "Privileged Instruction",
945 [TT_NFPU_INSN] = "FPU Disabled",
946 [TT_WIN_OVF] = "Window Overflow",
947 [TT_WIN_UNF] = "Window Underflow",
948 [TT_UNALIGNED] = "Unaligned Memory Access",
949 [TT_FP_EXCP] = "FPU Exception",
950 [TT_DFAULT] = "Data Access Fault",
951 [TT_TOVF] = "Tag Overflow",
952 [TT_EXTINT | 0x1] = "External Interrupt 1",
953 [TT_EXTINT | 0x2] = "External Interrupt 2",
954 [TT_EXTINT | 0x3] = "External Interrupt 3",
955 [TT_EXTINT | 0x4] = "External Interrupt 4",
956 [TT_EXTINT | 0x5] = "External Interrupt 5",
957 [TT_EXTINT | 0x6] = "External Interrupt 6",
958 [TT_EXTINT | 0x7] = "External Interrupt 7",
959 [TT_EXTINT | 0x8] = "External Interrupt 8",
960 [TT_EXTINT | 0x9] = "External Interrupt 9",
961 [TT_EXTINT | 0xa] = "External Interrupt 10",
962 [TT_EXTINT | 0xb] = "External Interrupt 11",
963 [TT_EXTINT | 0xc] = "External Interrupt 12",
964 [TT_EXTINT | 0xd] = "External Interrupt 13",
965 [TT_EXTINT | 0xe] = "External Interrupt 14",
966 [TT_EXTINT | 0xf] = "External Interrupt 15",
967 [TT_TOVF] = "Tag Overflow",
968 [TT_CODE_ACCESS] = "Instruction Access Error",
969 [TT_DATA_ACCESS] = "Data Access Error",
970 [TT_DIV_ZERO] = "Division By Zero",
971 [TT_NCP_INSN] = "Coprocessor Disabled",
973 #endif
975 void do_interrupt(CPUState *env)
977 int cwp, intno = env->exception_index;
979 #ifdef DEBUG_PCALL
980 if (qemu_loglevel_mask(CPU_LOG_INT)) {
981 static int count;
982 const char *name;
984 if (intno < 0 || intno >= 0x100) {
985 name = "Unknown";
986 } else if (intno >= 0x80) {
987 name = "Trap Instruction";
988 } else {
989 name = excp_names[intno];
990 if (!name) {
991 name = "Unknown";
995 qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n",
996 count, name, intno,
997 env->pc,
998 env->npc, env->regwptr[6]);
999 log_cpu_state(env, 0);
1000 #if 0
1002 int i;
1003 uint8_t *ptr;
1005 qemu_log(" code=");
1006 ptr = (uint8_t *)env->pc;
1007 for (i = 0; i < 16; i++) {
1008 qemu_log(" %02x", ldub(ptr + i));
1010 qemu_log("\n");
1012 #endif
1013 count++;
1015 #endif
1016 #if !defined(CONFIG_USER_ONLY)
1017 if (env->psret == 0) {
1018 cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state",
1019 env->exception_index);
1020 return;
1022 #endif
1023 env->psret = 0;
1024 cwp = cpu_cwp_dec(env, env->cwp - 1);
1025 cpu_set_cwp(env, cwp);
1026 env->regwptr[9] = env->pc;
1027 env->regwptr[10] = env->npc;
1028 env->psrps = env->psrs;
1029 env->psrs = 1;
1030 env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
1031 env->pc = env->tbr;
1032 env->npc = env->pc + 4;
1033 env->exception_index = -1;
1035 #if !defined(CONFIG_USER_ONLY)
1036 /* IRQ acknowledgment */
1037 if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
1038 env->qemu_irq_ack(env->irq_manager, intno);
1040 #endif
1042 #endif
1044 void cpu_reset(CPUSPARCState *env)
1046 if (qemu_loglevel_mask(CPU_LOG_RESET)) {
1047 qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
1048 log_cpu_state(env, 0);
1051 tlb_flush(env, 1);
1052 env->cwp = 0;
1053 #ifndef TARGET_SPARC64
1054 env->wim = 1;
1055 #endif
1056 env->regwptr = env->regbase + (env->cwp * 16);
1057 CC_OP = CC_OP_FLAGS;
1058 #if defined(CONFIG_USER_ONLY)
1059 #ifdef TARGET_SPARC64
1060 env->cleanwin = env->nwindows - 2;
1061 env->cansave = env->nwindows - 2;
1062 env->pstate = PS_RMO | PS_PEF | PS_IE;
1063 env->asi = 0x82; // Primary no-fault
1064 #endif
1065 #else
1066 #if !defined(TARGET_SPARC64)
1067 env->psret = 0;
1068 env->psrs = 1;
1069 env->psrps = 1;
1070 #endif
1071 #ifdef TARGET_SPARC64
1072 env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
1073 env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
1074 env->tl = env->maxtl;
1075 cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
1076 env->lsu = 0;
1077 #else
1078 env->mmuregs[0] &= ~(MMU_E | MMU_NF);
1079 env->mmuregs[0] |= env->def->mmu_bm;
1080 #endif
1081 env->pc = 0;
1082 env->npc = env->pc + 4;
1083 #endif
1084 env->cache_control = 0;
1087 static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
1089 sparc_def_t def1, *def = &def1;
1091 if (cpu_sparc_find_by_name(def, cpu_model) < 0)
1092 return -1;
1094 env->def = g_malloc0(sizeof(*def));
1095 memcpy(env->def, def, sizeof(*def));
1096 #if defined(CONFIG_USER_ONLY)
1097 if ((env->def->features & CPU_FEATURE_FLOAT))
1098 env->def->features |= CPU_FEATURE_FLOAT128;
1099 #endif
1100 env->cpu_model_str = cpu_model;
1101 env->version = def->iu_version;
1102 env->fsr = def->fpu_version;
1103 env->nwindows = def->nwindows;
1104 #if !defined(TARGET_SPARC64)
1105 env->mmuregs[0] |= def->mmu_version;
1106 cpu_sparc_set_id(env, 0);
1107 env->mxccregs[7] |= def->mxcc_version;
1108 #else
1109 env->mmu_version = def->mmu_version;
1110 env->maxtl = def->maxtl;
1111 env->version |= def->maxtl << 8;
1112 env->version |= def->nwindows - 1;
1113 #endif
1114 return 0;
1117 static void cpu_sparc_close(CPUSPARCState *env)
1119 free(env->def);
1120 free(env);
1123 CPUSPARCState *cpu_sparc_init(const char *cpu_model)
1125 CPUSPARCState *env;
1127 env = g_malloc0(sizeof(CPUSPARCState));
1128 cpu_exec_init(env);
1130 gen_intermediate_code_init(env);
1132 if (cpu_sparc_register(env, cpu_model) < 0) {
1133 cpu_sparc_close(env);
1134 return NULL;
1136 qemu_init_vcpu(env);
1138 return env;
1141 void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
1143 #if !defined(TARGET_SPARC64)
1144 env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
1145 #endif
1148 static const sparc_def_t sparc_defs[] = {
1149 #ifdef TARGET_SPARC64
1151 .name = "Fujitsu Sparc64",
1152 .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
1153 .fpu_version = 0x00000000,
1154 .mmu_version = mmu_us_12,
1155 .nwindows = 4,
1156 .maxtl = 4,
1157 .features = CPU_DEFAULT_FEATURES,
1160 .name = "Fujitsu Sparc64 III",
1161 .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
1162 .fpu_version = 0x00000000,
1163 .mmu_version = mmu_us_12,
1164 .nwindows = 5,
1165 .maxtl = 4,
1166 .features = CPU_DEFAULT_FEATURES,
1169 .name = "Fujitsu Sparc64 IV",
1170 .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
1171 .fpu_version = 0x00000000,
1172 .mmu_version = mmu_us_12,
1173 .nwindows = 8,
1174 .maxtl = 5,
1175 .features = CPU_DEFAULT_FEATURES,
1178 .name = "Fujitsu Sparc64 V",
1179 .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
1180 .fpu_version = 0x00000000,
1181 .mmu_version = mmu_us_12,
1182 .nwindows = 8,
1183 .maxtl = 5,
1184 .features = CPU_DEFAULT_FEATURES,
1187 .name = "TI UltraSparc I",
1188 .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
1189 .fpu_version = 0x00000000,
1190 .mmu_version = mmu_us_12,
1191 .nwindows = 8,
1192 .maxtl = 5,
1193 .features = CPU_DEFAULT_FEATURES,
1196 .name = "TI UltraSparc II",
1197 .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
1198 .fpu_version = 0x00000000,
1199 .mmu_version = mmu_us_12,
1200 .nwindows = 8,
1201 .maxtl = 5,
1202 .features = CPU_DEFAULT_FEATURES,
1205 .name = "TI UltraSparc IIi",
1206 .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
1207 .fpu_version = 0x00000000,
1208 .mmu_version = mmu_us_12,
1209 .nwindows = 8,
1210 .maxtl = 5,
1211 .features = CPU_DEFAULT_FEATURES,
1214 .name = "TI UltraSparc IIe",
1215 .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
1216 .fpu_version = 0x00000000,
1217 .mmu_version = mmu_us_12,
1218 .nwindows = 8,
1219 .maxtl = 5,
1220 .features = CPU_DEFAULT_FEATURES,
1223 .name = "Sun UltraSparc III",
1224 .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
1225 .fpu_version = 0x00000000,
1226 .mmu_version = mmu_us_12,
1227 .nwindows = 8,
1228 .maxtl = 5,
1229 .features = CPU_DEFAULT_FEATURES,
1232 .name = "Sun UltraSparc III Cu",
1233 .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
1234 .fpu_version = 0x00000000,
1235 .mmu_version = mmu_us_3,
1236 .nwindows = 8,
1237 .maxtl = 5,
1238 .features = CPU_DEFAULT_FEATURES,
1241 .name = "Sun UltraSparc IIIi",
1242 .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
1243 .fpu_version = 0x00000000,
1244 .mmu_version = mmu_us_12,
1245 .nwindows = 8,
1246 .maxtl = 5,
1247 .features = CPU_DEFAULT_FEATURES,
1250 .name = "Sun UltraSparc IV",
1251 .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
1252 .fpu_version = 0x00000000,
1253 .mmu_version = mmu_us_4,
1254 .nwindows = 8,
1255 .maxtl = 5,
1256 .features = CPU_DEFAULT_FEATURES,
1259 .name = "Sun UltraSparc IV+",
1260 .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
1261 .fpu_version = 0x00000000,
1262 .mmu_version = mmu_us_12,
1263 .nwindows = 8,
1264 .maxtl = 5,
1265 .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
1268 .name = "Sun UltraSparc IIIi+",
1269 .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
1270 .fpu_version = 0x00000000,
1271 .mmu_version = mmu_us_3,
1272 .nwindows = 8,
1273 .maxtl = 5,
1274 .features = CPU_DEFAULT_FEATURES,
1277 .name = "Sun UltraSparc T1",
1278 // defined in sparc_ifu_fdp.v and ctu.h
1279 .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
1280 .fpu_version = 0x00000000,
1281 .mmu_version = mmu_sun4v,
1282 .nwindows = 8,
1283 .maxtl = 6,
1284 .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
1285 | CPU_FEATURE_GL,
1288 .name = "Sun UltraSparc T2",
1289 // defined in tlu_asi_ctl.v and n2_revid_cust.v
1290 .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
1291 .fpu_version = 0x00000000,
1292 .mmu_version = mmu_sun4v,
1293 .nwindows = 8,
1294 .maxtl = 6,
1295 .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
1296 | CPU_FEATURE_GL,
1299 .name = "NEC UltraSparc I",
1300 .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
1301 .fpu_version = 0x00000000,
1302 .mmu_version = mmu_us_12,
1303 .nwindows = 8,
1304 .maxtl = 5,
1305 .features = CPU_DEFAULT_FEATURES,
1307 #else
1309 .name = "Fujitsu MB86900",
1310 .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
1311 .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1312 .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
1313 .mmu_bm = 0x00004000,
1314 .mmu_ctpr_mask = 0x007ffff0,
1315 .mmu_cxr_mask = 0x0000003f,
1316 .mmu_sfsr_mask = 0xffffffff,
1317 .mmu_trcr_mask = 0xffffffff,
1318 .nwindows = 7,
1319 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
1322 .name = "Fujitsu MB86904",
1323 .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
1324 .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1325 .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
1326 .mmu_bm = 0x00004000,
1327 .mmu_ctpr_mask = 0x00ffffc0,
1328 .mmu_cxr_mask = 0x000000ff,
1329 .mmu_sfsr_mask = 0x00016fff,
1330 .mmu_trcr_mask = 0x00ffffff,
1331 .nwindows = 8,
1332 .features = CPU_DEFAULT_FEATURES,
1335 .name = "Fujitsu MB86907",
1336 .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
1337 .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1338 .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
1339 .mmu_bm = 0x00004000,
1340 .mmu_ctpr_mask = 0xffffffc0,
1341 .mmu_cxr_mask = 0x000000ff,
1342 .mmu_sfsr_mask = 0x00016fff,
1343 .mmu_trcr_mask = 0xffffffff,
1344 .nwindows = 8,
1345 .features = CPU_DEFAULT_FEATURES,
1348 .name = "LSI L64811",
1349 .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
1350 .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
1351 .mmu_version = 0x10 << 24,
1352 .mmu_bm = 0x00004000,
1353 .mmu_ctpr_mask = 0x007ffff0,
1354 .mmu_cxr_mask = 0x0000003f,
1355 .mmu_sfsr_mask = 0xffffffff,
1356 .mmu_trcr_mask = 0xffffffff,
1357 .nwindows = 8,
1358 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1359 CPU_FEATURE_FSMULD,
1362 .name = "Cypress CY7C601",
1363 .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
1364 .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
1365 .mmu_version = 0x10 << 24,
1366 .mmu_bm = 0x00004000,
1367 .mmu_ctpr_mask = 0x007ffff0,
1368 .mmu_cxr_mask = 0x0000003f,
1369 .mmu_sfsr_mask = 0xffffffff,
1370 .mmu_trcr_mask = 0xffffffff,
1371 .nwindows = 8,
1372 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1373 CPU_FEATURE_FSMULD,
1376 .name = "Cypress CY7C611",
1377 .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
1378 .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
1379 .mmu_version = 0x10 << 24,
1380 .mmu_bm = 0x00004000,
1381 .mmu_ctpr_mask = 0x007ffff0,
1382 .mmu_cxr_mask = 0x0000003f,
1383 .mmu_sfsr_mask = 0xffffffff,
1384 .mmu_trcr_mask = 0xffffffff,
1385 .nwindows = 8,
1386 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1387 CPU_FEATURE_FSMULD,
1390 .name = "TI MicroSparc I",
1391 .iu_version = 0x41000000,
1392 .fpu_version = 4 << 17,
1393 .mmu_version = 0x41000000,
1394 .mmu_bm = 0x00004000,
1395 .mmu_ctpr_mask = 0x007ffff0,
1396 .mmu_cxr_mask = 0x0000003f,
1397 .mmu_sfsr_mask = 0x00016fff,
1398 .mmu_trcr_mask = 0x0000003f,
1399 .nwindows = 7,
1400 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
1401 CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
1402 CPU_FEATURE_FMUL,
1405 .name = "TI MicroSparc II",
1406 .iu_version = 0x42000000,
1407 .fpu_version = 4 << 17,
1408 .mmu_version = 0x02000000,
1409 .mmu_bm = 0x00004000,
1410 .mmu_ctpr_mask = 0x00ffffc0,
1411 .mmu_cxr_mask = 0x000000ff,
1412 .mmu_sfsr_mask = 0x00016fff,
1413 .mmu_trcr_mask = 0x00ffffff,
1414 .nwindows = 8,
1415 .features = CPU_DEFAULT_FEATURES,
1418 .name = "TI MicroSparc IIep",
1419 .iu_version = 0x42000000,
1420 .fpu_version = 4 << 17,
1421 .mmu_version = 0x04000000,
1422 .mmu_bm = 0x00004000,
1423 .mmu_ctpr_mask = 0x00ffffc0,
1424 .mmu_cxr_mask = 0x000000ff,
1425 .mmu_sfsr_mask = 0x00016bff,
1426 .mmu_trcr_mask = 0x00ffffff,
1427 .nwindows = 8,
1428 .features = CPU_DEFAULT_FEATURES,
1431 .name = "TI SuperSparc 40", // STP1020NPGA
1432 .iu_version = 0x41000000, // SuperSPARC 2.x
1433 .fpu_version = 0 << 17,
1434 .mmu_version = 0x00000800, // SuperSPARC 2.x, no MXCC
1435 .mmu_bm = 0x00002000,
1436 .mmu_ctpr_mask = 0xffffffc0,
1437 .mmu_cxr_mask = 0x0000ffff,
1438 .mmu_sfsr_mask = 0xffffffff,
1439 .mmu_trcr_mask = 0xffffffff,
1440 .nwindows = 8,
1441 .features = CPU_DEFAULT_FEATURES,
1444 .name = "TI SuperSparc 50", // STP1020PGA
1445 .iu_version = 0x40000000, // SuperSPARC 3.x
1446 .fpu_version = 0 << 17,
1447 .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
1448 .mmu_bm = 0x00002000,
1449 .mmu_ctpr_mask = 0xffffffc0,
1450 .mmu_cxr_mask = 0x0000ffff,
1451 .mmu_sfsr_mask = 0xffffffff,
1452 .mmu_trcr_mask = 0xffffffff,
1453 .nwindows = 8,
1454 .features = CPU_DEFAULT_FEATURES,
1457 .name = "TI SuperSparc 51",
1458 .iu_version = 0x40000000, // SuperSPARC 3.x
1459 .fpu_version = 0 << 17,
1460 .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
1461 .mmu_bm = 0x00002000,
1462 .mmu_ctpr_mask = 0xffffffc0,
1463 .mmu_cxr_mask = 0x0000ffff,
1464 .mmu_sfsr_mask = 0xffffffff,
1465 .mmu_trcr_mask = 0xffffffff,
1466 .mxcc_version = 0x00000104,
1467 .nwindows = 8,
1468 .features = CPU_DEFAULT_FEATURES,
1471 .name = "TI SuperSparc 60", // STP1020APGA
1472 .iu_version = 0x40000000, // SuperSPARC 3.x
1473 .fpu_version = 0 << 17,
1474 .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
1475 .mmu_bm = 0x00002000,
1476 .mmu_ctpr_mask = 0xffffffc0,
1477 .mmu_cxr_mask = 0x0000ffff,
1478 .mmu_sfsr_mask = 0xffffffff,
1479 .mmu_trcr_mask = 0xffffffff,
1480 .nwindows = 8,
1481 .features = CPU_DEFAULT_FEATURES,
1484 .name = "TI SuperSparc 61",
1485 .iu_version = 0x44000000, // SuperSPARC 3.x
1486 .fpu_version = 0 << 17,
1487 .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
1488 .mmu_bm = 0x00002000,
1489 .mmu_ctpr_mask = 0xffffffc0,
1490 .mmu_cxr_mask = 0x0000ffff,
1491 .mmu_sfsr_mask = 0xffffffff,
1492 .mmu_trcr_mask = 0xffffffff,
1493 .mxcc_version = 0x00000104,
1494 .nwindows = 8,
1495 .features = CPU_DEFAULT_FEATURES,
1498 .name = "TI SuperSparc II",
1499 .iu_version = 0x40000000, // SuperSPARC II 1.x
1500 .fpu_version = 0 << 17,
1501 .mmu_version = 0x08000000, // SuperSPARC II 1.x, MXCC
1502 .mmu_bm = 0x00002000,
1503 .mmu_ctpr_mask = 0xffffffc0,
1504 .mmu_cxr_mask = 0x0000ffff,
1505 .mmu_sfsr_mask = 0xffffffff,
1506 .mmu_trcr_mask = 0xffffffff,
1507 .mxcc_version = 0x00000104,
1508 .nwindows = 8,
1509 .features = CPU_DEFAULT_FEATURES,
1512 .name = "Ross RT625",
1513 .iu_version = 0x1e000000,
1514 .fpu_version = 1 << 17,
1515 .mmu_version = 0x1e000000,
1516 .mmu_bm = 0x00004000,
1517 .mmu_ctpr_mask = 0x007ffff0,
1518 .mmu_cxr_mask = 0x0000003f,
1519 .mmu_sfsr_mask = 0xffffffff,
1520 .mmu_trcr_mask = 0xffffffff,
1521 .nwindows = 8,
1522 .features = CPU_DEFAULT_FEATURES,
1525 .name = "Ross RT620",
1526 .iu_version = 0x1f000000,
1527 .fpu_version = 1 << 17,
1528 .mmu_version = 0x1f000000,
1529 .mmu_bm = 0x00004000,
1530 .mmu_ctpr_mask = 0x007ffff0,
1531 .mmu_cxr_mask = 0x0000003f,
1532 .mmu_sfsr_mask = 0xffffffff,
1533 .mmu_trcr_mask = 0xffffffff,
1534 .nwindows = 8,
1535 .features = CPU_DEFAULT_FEATURES,
1538 .name = "BIT B5010",
1539 .iu_version = 0x20000000,
1540 .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
1541 .mmu_version = 0x20000000,
1542 .mmu_bm = 0x00004000,
1543 .mmu_ctpr_mask = 0x007ffff0,
1544 .mmu_cxr_mask = 0x0000003f,
1545 .mmu_sfsr_mask = 0xffffffff,
1546 .mmu_trcr_mask = 0xffffffff,
1547 .nwindows = 8,
1548 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1549 CPU_FEATURE_FSMULD,
1552 .name = "Matsushita MN10501",
1553 .iu_version = 0x50000000,
1554 .fpu_version = 0 << 17,
1555 .mmu_version = 0x50000000,
1556 .mmu_bm = 0x00004000,
1557 .mmu_ctpr_mask = 0x007ffff0,
1558 .mmu_cxr_mask = 0x0000003f,
1559 .mmu_sfsr_mask = 0xffffffff,
1560 .mmu_trcr_mask = 0xffffffff,
1561 .nwindows = 8,
1562 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
1563 CPU_FEATURE_FSMULD,
1566 .name = "Weitek W8601",
1567 .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
1568 .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
1569 .mmu_version = 0x10 << 24,
1570 .mmu_bm = 0x00004000,
1571 .mmu_ctpr_mask = 0x007ffff0,
1572 .mmu_cxr_mask = 0x0000003f,
1573 .mmu_sfsr_mask = 0xffffffff,
1574 .mmu_trcr_mask = 0xffffffff,
1575 .nwindows = 8,
1576 .features = CPU_DEFAULT_FEATURES,
1579 .name = "LEON2",
1580 .iu_version = 0xf2000000,
1581 .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1582 .mmu_version = 0xf2000000,
1583 .mmu_bm = 0x00004000,
1584 .mmu_ctpr_mask = 0x007ffff0,
1585 .mmu_cxr_mask = 0x0000003f,
1586 .mmu_sfsr_mask = 0xffffffff,
1587 .mmu_trcr_mask = 0xffffffff,
1588 .nwindows = 8,
1589 .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
1592 .name = "LEON3",
1593 .iu_version = 0xf3000000,
1594 .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1595 .mmu_version = 0xf3000000,
1596 .mmu_bm = 0x00000000,
1597 .mmu_ctpr_mask = 0x007ffff0,
1598 .mmu_cxr_mask = 0x0000003f,
1599 .mmu_sfsr_mask = 0xffffffff,
1600 .mmu_trcr_mask = 0xffffffff,
1601 .nwindows = 8,
1602 .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
1603 CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
1605 #endif
1608 static const char * const feature_name[] = {
1609 "float",
1610 "float128",
1611 "swap",
1612 "mul",
1613 "div",
1614 "flush",
1615 "fsqrt",
1616 "fmul",
1617 "vis1",
1618 "vis2",
1619 "fsmuld",
1620 "hypv",
1621 "cmt",
1622 "gl",
1625 static void print_features(FILE *f, fprintf_function cpu_fprintf,
1626 uint32_t features, const char *prefix)
1628 unsigned int i;
1630 for (i = 0; i < ARRAY_SIZE(feature_name); i++)
1631 if (feature_name[i] && (features & (1 << i))) {
1632 if (prefix)
1633 (*cpu_fprintf)(f, "%s", prefix);
1634 (*cpu_fprintf)(f, "%s ", feature_name[i]);
1638 static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
1640 unsigned int i;
1642 for (i = 0; i < ARRAY_SIZE(feature_name); i++)
1643 if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
1644 *features |= 1 << i;
1645 return;
1647 fprintf(stderr, "CPU feature %s not found\n", flagname);
1650 static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
1652 unsigned int i;
1653 const sparc_def_t *def = NULL;
1654 char *s = strdup(cpu_model);
1655 char *featurestr, *name = strtok(s, ",");
1656 uint32_t plus_features = 0;
1657 uint32_t minus_features = 0;
1658 uint64_t iu_version;
1659 uint32_t fpu_version, mmu_version, nwindows;
1661 for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
1662 if (strcasecmp(name, sparc_defs[i].name) == 0) {
1663 def = &sparc_defs[i];
1666 if (!def)
1667 goto error;
1668 memcpy(cpu_def, def, sizeof(*def));
1670 featurestr = strtok(NULL, ",");
1671 while (featurestr) {
1672 char *val;
1674 if (featurestr[0] == '+') {
1675 add_flagname_to_bitmaps(featurestr + 1, &plus_features);
1676 } else if (featurestr[0] == '-') {
1677 add_flagname_to_bitmaps(featurestr + 1, &minus_features);
1678 } else if ((val = strchr(featurestr, '='))) {
1679 *val = 0; val++;
1680 if (!strcmp(featurestr, "iu_version")) {
1681 char *err;
1683 iu_version = strtoll(val, &err, 0);
1684 if (!*val || *err) {
1685 fprintf(stderr, "bad numerical value %s\n", val);
1686 goto error;
1688 cpu_def->iu_version = iu_version;
1689 #ifdef DEBUG_FEATURES
1690 fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
1691 #endif
1692 } else if (!strcmp(featurestr, "fpu_version")) {
1693 char *err;
1695 fpu_version = strtol(val, &err, 0);
1696 if (!*val || *err) {
1697 fprintf(stderr, "bad numerical value %s\n", val);
1698 goto error;
1700 cpu_def->fpu_version = fpu_version;
1701 #ifdef DEBUG_FEATURES
1702 fprintf(stderr, "fpu_version %x\n", fpu_version);
1703 #endif
1704 } else if (!strcmp(featurestr, "mmu_version")) {
1705 char *err;
1707 mmu_version = strtol(val, &err, 0);
1708 if (!*val || *err) {
1709 fprintf(stderr, "bad numerical value %s\n", val);
1710 goto error;
1712 cpu_def->mmu_version = mmu_version;
1713 #ifdef DEBUG_FEATURES
1714 fprintf(stderr, "mmu_version %x\n", mmu_version);
1715 #endif
1716 } else if (!strcmp(featurestr, "nwindows")) {
1717 char *err;
1719 nwindows = strtol(val, &err, 0);
1720 if (!*val || *err || nwindows > MAX_NWINDOWS ||
1721 nwindows < MIN_NWINDOWS) {
1722 fprintf(stderr, "bad numerical value %s\n", val);
1723 goto error;
1725 cpu_def->nwindows = nwindows;
1726 #ifdef DEBUG_FEATURES
1727 fprintf(stderr, "nwindows %d\n", nwindows);
1728 #endif
1729 } else {
1730 fprintf(stderr, "unrecognized feature %s\n", featurestr);
1731 goto error;
1733 } else {
1734 fprintf(stderr, "feature string `%s' not in format "
1735 "(+feature|-feature|feature=xyz)\n", featurestr);
1736 goto error;
1738 featurestr = strtok(NULL, ",");
1740 cpu_def->features |= plus_features;
1741 cpu_def->features &= ~minus_features;
1742 #ifdef DEBUG_FEATURES
1743 print_features(stderr, fprintf, cpu_def->features, NULL);
1744 #endif
1745 free(s);
1746 return 0;
1748 error:
1749 free(s);
1750 return -1;
1753 void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
1755 unsigned int i;
1757 for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
1758 (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x NWINS %d ",
1759 sparc_defs[i].name,
1760 sparc_defs[i].iu_version,
1761 sparc_defs[i].fpu_version,
1762 sparc_defs[i].mmu_version,
1763 sparc_defs[i].nwindows);
1764 print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
1765 ~sparc_defs[i].features, "-");
1766 print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
1767 sparc_defs[i].features, "+");
1768 (*cpu_fprintf)(f, "\n");
1770 (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
1771 print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
1772 (*cpu_fprintf)(f, "\n");
1773 (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
1774 print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
1775 (*cpu_fprintf)(f, "\n");
1776 (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
1777 "fpu_version mmu_version nwindows\n");
1780 static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
1781 uint32_t cc)
1783 cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG? 'N' : '-',
1784 cc & PSR_ZERO? 'Z' : '-', cc & PSR_OVF? 'V' : '-',
1785 cc & PSR_CARRY? 'C' : '-');
1788 #ifdef TARGET_SPARC64
1789 #define REGS_PER_LINE 4
1790 #else
1791 #define REGS_PER_LINE 8
1792 #endif
1794 void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
1795 int flags)
1797 int i, x;
1799 cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc,
1800 env->npc);
1801 cpu_fprintf(f, "General Registers:\n");
1803 for (i = 0; i < 8; i++) {
1804 if (i % REGS_PER_LINE == 0) {
1805 cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
1807 cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
1808 if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
1809 cpu_fprintf(f, "\n");
1812 cpu_fprintf(f, "\nCurrent Register Window:\n");
1813 for (x = 0; x < 3; x++) {
1814 for (i = 0; i < 8; i++) {
1815 if (i % REGS_PER_LINE == 0) {
1816 cpu_fprintf(f, "%%%c%d-%d: ",
1817 x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
1818 i, i + REGS_PER_LINE - 1);
1820 cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
1821 if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
1822 cpu_fprintf(f, "\n");
1826 cpu_fprintf(f, "\nFloating Point Registers:\n");
1827 for (i = 0; i < TARGET_FPREGS; i++) {
1828 if ((i & 3) == 0)
1829 cpu_fprintf(f, "%%f%02d:", i);
1830 cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
1831 if ((i & 3) == 3)
1832 cpu_fprintf(f, "\n");
1834 #ifdef TARGET_SPARC64
1835 cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
1836 (unsigned)cpu_get_ccr(env));
1837 cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
1838 cpu_fprintf(f, " xcc: ");
1839 cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
1840 cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
1841 env->psrpil);
1842 cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
1843 "cleanwin: %d cwp: %d\n",
1844 env->cansave, env->canrestore, env->otherwin, env->wstate,
1845 env->cleanwin, env->nwindows - 1 - env->cwp);
1846 cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
1847 TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
1848 #else
1849 cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
1850 cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
1851 cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs? 'S' : '-',
1852 env->psrps? 'P' : '-', env->psret? 'E' : '-',
1853 env->wim);
1854 cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
1855 env->fsr, env->y);
1856 #endif