Update SeaBIOS to 0.6.1.2
[qemu.git] / target-sparc / helper.c
blobb2d4d70a11fe887ba993ab23d56d7844c8b30616
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>
24 #include <signal.h>
26 #include "cpu.h"
27 #include "exec-all.h"
28 #include "qemu-common.h"
30 //#define DEBUG_MMU
31 //#define DEBUG_FEATURES
33 #ifdef DEBUG_MMU
34 #define DPRINTF_MMU(fmt, ...) \
35 do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
36 #else
37 #define DPRINTF_MMU(fmt, ...) do {} while (0)
38 #endif
40 static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
42 /* Sparc MMU emulation */
44 #if defined(CONFIG_USER_ONLY)
46 int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
47 int mmu_idx, int is_softmmu)
49 if (rw & 2)
50 env1->exception_index = TT_TFAULT;
51 else
52 env1->exception_index = TT_DFAULT;
53 return 1;
56 #else
58 #ifndef TARGET_SPARC64
60 * Sparc V8 Reference MMU (SRMMU)
62 static const int access_table[8][8] = {
63 { 0, 0, 0, 0, 8, 0, 12, 12 },
64 { 0, 0, 0, 0, 8, 0, 0, 0 },
65 { 8, 8, 0, 0, 0, 8, 12, 12 },
66 { 8, 8, 0, 0, 0, 8, 0, 0 },
67 { 8, 0, 8, 0, 8, 8, 12, 12 },
68 { 8, 0, 8, 0, 8, 0, 8, 0 },
69 { 8, 8, 8, 0, 8, 8, 12, 12 },
70 { 8, 8, 8, 0, 8, 8, 8, 0 }
73 static const int perm_table[2][8] = {
75 PAGE_READ,
76 PAGE_READ | PAGE_WRITE,
77 PAGE_READ | PAGE_EXEC,
78 PAGE_READ | PAGE_WRITE | PAGE_EXEC,
79 PAGE_EXEC,
80 PAGE_READ | PAGE_WRITE,
81 PAGE_READ | PAGE_EXEC,
82 PAGE_READ | PAGE_WRITE | PAGE_EXEC
85 PAGE_READ,
86 PAGE_READ | PAGE_WRITE,
87 PAGE_READ | PAGE_EXEC,
88 PAGE_READ | PAGE_WRITE | PAGE_EXEC,
89 PAGE_EXEC,
90 PAGE_READ,
96 static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
97 int *prot, int *access_index,
98 target_ulong address, int rw, int mmu_idx,
99 target_ulong *page_size)
101 int access_perms = 0;
102 target_phys_addr_t pde_ptr;
103 uint32_t pde;
104 int error_code = 0, is_dirty, is_user;
105 unsigned long page_offset;
107 is_user = mmu_idx == MMU_USER_IDX;
109 if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
110 *page_size = TARGET_PAGE_SIZE;
111 // Boot mode: instruction fetches are taken from PROM
112 if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
113 *physical = env->prom_addr | (address & 0x7ffffULL);
114 *prot = PAGE_READ | PAGE_EXEC;
115 return 0;
117 *physical = address;
118 *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
119 return 0;
122 *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
123 *physical = 0xffffffffffff0000ULL;
125 /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
126 /* Context base + context number */
127 pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
128 pde = ldl_phys(pde_ptr);
130 /* Ctx pde */
131 switch (pde & PTE_ENTRYTYPE_MASK) {
132 default:
133 case 0: /* Invalid */
134 return 1 << 2;
135 case 2: /* L0 PTE, maybe should not happen? */
136 case 3: /* Reserved */
137 return 4 << 2;
138 case 1: /* L0 PDE */
139 pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
140 pde = ldl_phys(pde_ptr);
142 switch (pde & PTE_ENTRYTYPE_MASK) {
143 default:
144 case 0: /* Invalid */
145 return (1 << 8) | (1 << 2);
146 case 3: /* Reserved */
147 return (1 << 8) | (4 << 2);
148 case 1: /* L1 PDE */
149 pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
150 pde = ldl_phys(pde_ptr);
152 switch (pde & PTE_ENTRYTYPE_MASK) {
153 default:
154 case 0: /* Invalid */
155 return (2 << 8) | (1 << 2);
156 case 3: /* Reserved */
157 return (2 << 8) | (4 << 2);
158 case 1: /* L2 PDE */
159 pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
160 pde = ldl_phys(pde_ptr);
162 switch (pde & PTE_ENTRYTYPE_MASK) {
163 default:
164 case 0: /* Invalid */
165 return (3 << 8) | (1 << 2);
166 case 1: /* PDE, should not happen */
167 case 3: /* Reserved */
168 return (3 << 8) | (4 << 2);
169 case 2: /* L3 PTE */
170 page_offset = (address & TARGET_PAGE_MASK) &
171 (TARGET_PAGE_SIZE - 1);
173 *page_size = TARGET_PAGE_SIZE;
174 break;
175 case 2: /* L2 PTE */
176 page_offset = address & 0x3ffff;
177 *page_size = 0x40000;
179 break;
180 case 2: /* L1 PTE */
181 page_offset = address & 0xffffff;
182 *page_size = 0x1000000;
186 /* check access */
187 access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
188 error_code = access_table[*access_index][access_perms];
189 if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user))
190 return error_code;
192 /* update page modified and dirty bits */
193 is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
194 if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
195 pde |= PG_ACCESSED_MASK;
196 if (is_dirty)
197 pde |= PG_MODIFIED_MASK;
198 stl_phys_notdirty(pde_ptr, pde);
201 /* the page can be put in the TLB */
202 *prot = perm_table[is_user][access_perms];
203 if (!(pde & PG_MODIFIED_MASK)) {
204 /* only set write access if already dirty... otherwise wait
205 for dirty access */
206 *prot &= ~PAGE_WRITE;
209 /* Even if large ptes, we map only one 4KB page in the cache to
210 avoid filling it too fast */
211 *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
212 return error_code;
215 /* Perform address translation */
216 int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
217 int mmu_idx, int is_softmmu)
219 target_phys_addr_t paddr;
220 target_ulong vaddr;
221 target_ulong page_size;
222 int error_code = 0, prot, access_index;
224 error_code = get_physical_address(env, &paddr, &prot, &access_index,
225 address, rw, mmu_idx, &page_size);
226 if (error_code == 0) {
227 vaddr = address & TARGET_PAGE_MASK;
228 paddr &= TARGET_PAGE_MASK;
229 #ifdef DEBUG_MMU
230 printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
231 TARGET_FMT_lx "\n", address, paddr, vaddr);
232 #endif
233 tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
234 return 0;
237 if (env->mmuregs[3]) /* Fault status register */
238 env->mmuregs[3] = 1; /* overflow (not read before another fault) */
239 env->mmuregs[3] |= (access_index << 5) | error_code | 2;
240 env->mmuregs[4] = address; /* Fault address register */
242 if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) {
243 // No fault mode: if a mapping is available, just override
244 // permissions. If no mapping is available, redirect accesses to
245 // neverland. Fake/overridden mappings will be flushed when
246 // switching to normal mode.
247 vaddr = address & TARGET_PAGE_MASK;
248 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
249 tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
250 return 0;
251 } else {
252 if (rw & 2)
253 env->exception_index = TT_TFAULT;
254 else
255 env->exception_index = TT_DFAULT;
256 return 1;
260 target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
262 target_phys_addr_t pde_ptr;
263 uint32_t pde;
265 /* Context base + context number */
266 pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
267 (env->mmuregs[2] << 2);
268 pde = ldl_phys(pde_ptr);
270 switch (pde & PTE_ENTRYTYPE_MASK) {
271 default:
272 case 0: /* Invalid */
273 case 2: /* PTE, maybe should not happen? */
274 case 3: /* Reserved */
275 return 0;
276 case 1: /* L1 PDE */
277 if (mmulev == 3)
278 return pde;
279 pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
280 pde = ldl_phys(pde_ptr);
282 switch (pde & PTE_ENTRYTYPE_MASK) {
283 default:
284 case 0: /* Invalid */
285 case 3: /* Reserved */
286 return 0;
287 case 2: /* L1 PTE */
288 return pde;
289 case 1: /* L2 PDE */
290 if (mmulev == 2)
291 return pde;
292 pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
293 pde = ldl_phys(pde_ptr);
295 switch (pde & PTE_ENTRYTYPE_MASK) {
296 default:
297 case 0: /* Invalid */
298 case 3: /* Reserved */
299 return 0;
300 case 2: /* L2 PTE */
301 return pde;
302 case 1: /* L3 PDE */
303 if (mmulev == 1)
304 return pde;
305 pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
306 pde = ldl_phys(pde_ptr);
308 switch (pde & PTE_ENTRYTYPE_MASK) {
309 default:
310 case 0: /* Invalid */
311 case 1: /* PDE, should not happen */
312 case 3: /* Reserved */
313 return 0;
314 case 2: /* L3 PTE */
315 return pde;
320 return 0;
323 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
325 target_ulong va, va1, va2;
326 unsigned int n, m, o;
327 target_phys_addr_t pde_ptr, pa;
328 uint32_t pde;
330 pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
331 pde = ldl_phys(pde_ptr);
332 (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
333 (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
334 for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
335 pde = mmu_probe(env, va, 2);
336 if (pde) {
337 pa = cpu_get_phys_page_debug(env, va);
338 (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
339 " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
340 for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
341 pde = mmu_probe(env, va1, 1);
342 if (pde) {
343 pa = cpu_get_phys_page_debug(env, va1);
344 (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
345 TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
346 va1, pa, pde);
347 for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
348 pde = mmu_probe(env, va2, 0);
349 if (pde) {
350 pa = cpu_get_phys_page_debug(env, va2);
351 (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
352 TARGET_FMT_plx " PTE: "
353 TARGET_FMT_lx "\n",
354 va2, pa, pde);
363 #else /* !TARGET_SPARC64 */
365 // 41 bit physical address space
366 static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
368 return x & 0x1ffffffffffULL;
372 * UltraSparc IIi I/DMMUs
375 // Returns true if TTE tag is valid and matches virtual address value in context
376 // requires virtual address mask value calculated from TTE entry size
377 static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
378 uint64_t address, uint64_t context,
379 target_phys_addr_t *physical)
381 uint64_t mask;
383 switch ((tlb->tte >> 61) & 3) {
384 default:
385 case 0x0: // 8k
386 mask = 0xffffffffffffe000ULL;
387 break;
388 case 0x1: // 64k
389 mask = 0xffffffffffff0000ULL;
390 break;
391 case 0x2: // 512k
392 mask = 0xfffffffffff80000ULL;
393 break;
394 case 0x3: // 4M
395 mask = 0xffffffffffc00000ULL;
396 break;
399 // valid, context match, virtual address match?
400 if (TTE_IS_VALID(tlb->tte) &&
401 (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
402 && compare_masked(address, tlb->tag, mask))
404 // decode physical address
405 *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
406 return 1;
409 return 0;
412 static int get_physical_address_data(CPUState *env,
413 target_phys_addr_t *physical, int *prot,
414 target_ulong address, int rw, int mmu_idx)
416 unsigned int i;
417 uint64_t context;
419 int is_user = (mmu_idx == MMU_USER_IDX ||
420 mmu_idx == MMU_USER_SECONDARY_IDX);
422 if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
423 *physical = ultrasparc_truncate_physical(address);
424 *prot = PAGE_READ | PAGE_WRITE;
425 return 0;
428 switch(mmu_idx) {
429 case MMU_USER_IDX:
430 case MMU_KERNEL_IDX:
431 context = env->dmmu.mmu_primary_context & 0x1fff;
432 break;
433 case MMU_USER_SECONDARY_IDX:
434 case MMU_KERNEL_SECONDARY_IDX:
435 context = env->dmmu.mmu_secondary_context & 0x1fff;
436 break;
437 case MMU_NUCLEUS_IDX:
438 default:
439 context = 0;
440 break;
443 for (i = 0; i < 64; i++) {
444 // ctx match, vaddr match, valid?
445 if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
447 uint8_t fault_type = 0;
449 // access ok?
450 if ((env->dtlb[i].tte & 0x4) && is_user) {
451 fault_type |= 1; /* privilege violation */
452 env->exception_index = TT_DFAULT;
454 DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64
455 " mmu_idx=%d tl=%d\n",
456 address, context, mmu_idx, env->tl);
457 } else if (!(env->dtlb[i].tte & 0x2) && (rw == 1)) {
458 env->exception_index = TT_DPROT;
460 DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64
461 " mmu_idx=%d tl=%d\n",
462 address, context, mmu_idx, env->tl);
463 } else {
464 *prot = PAGE_READ;
465 if (env->dtlb[i].tte & 0x2)
466 *prot |= PAGE_WRITE;
468 TTE_SET_USED(env->dtlb[i].tte);
470 return 0;
473 if (env->dmmu.sfsr & 1) /* Fault status register */
474 env->dmmu.sfsr = 2; /* overflow (not read before
475 another fault) */
477 env->dmmu.sfsr |= (is_user << 3) | ((rw == 1) << 2) | 1;
479 env->dmmu.sfsr |= (fault_type << 7);
481 env->dmmu.sfar = address; /* Fault address register */
483 env->dmmu.tag_access = (address & ~0x1fffULL) | context;
485 return 1;
489 DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n",
490 address, context);
492 env->dmmu.tag_access = (address & ~0x1fffULL) | context;
493 env->exception_index = TT_DMISS;
494 return 1;
497 static int get_physical_address_code(CPUState *env,
498 target_phys_addr_t *physical, int *prot,
499 target_ulong address, int mmu_idx)
501 unsigned int i;
502 uint64_t context;
504 int is_user = (mmu_idx == MMU_USER_IDX ||
505 mmu_idx == MMU_USER_SECONDARY_IDX);
507 if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
508 /* IMMU disabled */
509 *physical = ultrasparc_truncate_physical(address);
510 *prot = PAGE_EXEC;
511 return 0;
514 if (env->tl == 0) {
515 /* PRIMARY context */
516 context = env->dmmu.mmu_primary_context & 0x1fff;
517 } else {
518 /* NUCLEUS context */
519 context = 0;
522 for (i = 0; i < 64; i++) {
523 // ctx match, vaddr match, valid?
524 if (ultrasparc_tag_match(&env->itlb[i],
525 address, context, physical)) {
526 // access ok?
527 if ((env->itlb[i].tte & 0x4) && is_user) {
528 if (env->immu.sfsr) /* Fault status register */
529 env->immu.sfsr = 2; /* overflow (not read before
530 another fault) */
531 env->immu.sfsr |= (is_user << 3) | 1;
532 env->exception_index = TT_TFAULT;
534 env->immu.tag_access = (address & ~0x1fffULL) | context;
536 DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n",
537 address, context);
539 return 1;
541 *prot = PAGE_EXEC;
542 TTE_SET_USED(env->itlb[i].tte);
543 return 0;
547 DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n",
548 address, context);
550 /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
551 env->immu.tag_access = (address & ~0x1fffULL) | context;
552 env->exception_index = TT_TMISS;
553 return 1;
556 static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
557 int *prot, int *access_index,
558 target_ulong address, int rw, int mmu_idx,
559 target_ulong *page_size)
561 /* ??? We treat everything as a small page, then explicitly flush
562 everything when an entry is evicted. */
563 *page_size = TARGET_PAGE_SIZE;
565 #if defined (DEBUG_MMU)
566 /* safety net to catch wrong softmmu index use from dynamic code */
567 if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
568 DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d"
569 " primary context=%" PRIx64
570 " secondary context=%" PRIx64
571 " address=%" PRIx64
572 "\n",
573 (rw == 2 ? "CODE" : "DATA"),
574 env->tl, mmu_idx,
575 env->dmmu.mmu_primary_context,
576 env->dmmu.mmu_secondary_context,
577 address);
579 #endif
581 if (rw == 2)
582 return get_physical_address_code(env, physical, prot, address,
583 mmu_idx);
584 else
585 return get_physical_address_data(env, physical, prot, address, rw,
586 mmu_idx);
589 /* Perform address translation */
590 int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
591 int mmu_idx, int is_softmmu)
593 target_ulong virt_addr, vaddr;
594 target_phys_addr_t paddr;
595 target_ulong page_size;
596 int error_code = 0, prot, access_index;
598 error_code = get_physical_address(env, &paddr, &prot, &access_index,
599 address, rw, mmu_idx, &page_size);
600 if (error_code == 0) {
601 virt_addr = address & TARGET_PAGE_MASK;
602 vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
603 (TARGET_PAGE_SIZE - 1));
605 DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 ","
606 " vaddr %" PRIx64
607 " mmu_idx=%d"
608 " tl=%d"
609 " primary context=%" PRIx64
610 " secondary context=%" PRIx64
611 "\n",
612 address, paddr, vaddr, mmu_idx, env->tl,
613 env->dmmu.mmu_primary_context,
614 env->dmmu.mmu_secondary_context);
616 tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
617 return 0;
619 // XXX
620 return 1;
623 void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
625 unsigned int i;
626 const char *mask;
628 (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
629 PRId64 "\n",
630 env->dmmu.mmu_primary_context,
631 env->dmmu.mmu_secondary_context);
632 if ((env->lsu & DMMU_E) == 0) {
633 (*cpu_fprintf)(f, "DMMU disabled\n");
634 } else {
635 (*cpu_fprintf)(f, "DMMU dump\n");
636 for (i = 0; i < 64; i++) {
637 switch ((env->dtlb[i].tte >> 61) & 3) {
638 default:
639 case 0x0:
640 mask = " 8k";
641 break;
642 case 0x1:
643 mask = " 64k";
644 break;
645 case 0x2:
646 mask = "512k";
647 break;
648 case 0x3:
649 mask = " 4M";
650 break;
652 if ((env->dtlb[i].tte & 0x8000000000000000ULL) != 0) {
653 (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %" PRIx64
654 ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
656 env->dtlb[i].tag & (uint64_t)~0x1fffULL,
657 env->dtlb[i].tte & (uint64_t)0x1ffffffe000ULL,
658 mask,
659 env->dtlb[i].tte & 0x4? "priv": "user",
660 env->dtlb[i].tte & 0x2? "RW": "RO",
661 env->dtlb[i].tte & 0x40? "locked": "unlocked",
662 env->dtlb[i].tag & (uint64_t)0x1fffULL,
663 TTE_IS_GLOBAL(env->dtlb[i].tte)?
664 "global" : "local");
668 if ((env->lsu & IMMU_E) == 0) {
669 (*cpu_fprintf)(f, "IMMU disabled\n");
670 } else {
671 (*cpu_fprintf)(f, "IMMU dump\n");
672 for (i = 0; i < 64; i++) {
673 switch ((env->itlb[i].tte >> 61) & 3) {
674 default:
675 case 0x0:
676 mask = " 8k";
677 break;
678 case 0x1:
679 mask = " 64k";
680 break;
681 case 0x2:
682 mask = "512k";
683 break;
684 case 0x3:
685 mask = " 4M";
686 break;
688 if ((env->itlb[i].tte & 0x8000000000000000ULL) != 0) {
689 (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %" PRIx64
690 ", %s, %s, %s, ctx %" PRId64 " %s\n",
692 env->itlb[i].tag & (uint64_t)~0x1fffULL,
693 env->itlb[i].tte & (uint64_t)0x1ffffffe000ULL,
694 mask,
695 env->itlb[i].tte & 0x4? "priv": "user",
696 env->itlb[i].tte & 0x40? "locked": "unlocked",
697 env->itlb[i].tag & (uint64_t)0x1fffULL,
698 TTE_IS_GLOBAL(env->itlb[i].tte)?
699 "global" : "local");
705 #endif /* TARGET_SPARC64 */
706 #endif /* !CONFIG_USER_ONLY */
709 #if !defined(CONFIG_USER_ONLY)
710 target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
711 int mmu_idx)
713 target_phys_addr_t phys_addr;
714 target_ulong page_size;
715 int prot, access_index;
717 if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2,
718 mmu_idx, &page_size) != 0)
719 if (get_physical_address(env, &phys_addr, &prot, &access_index, addr,
720 0, mmu_idx, &page_size) != 0)
721 return -1;
722 if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED)
723 return -1;
724 return phys_addr;
727 target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
729 return cpu_get_phys_page_nofault(env, addr, cpu_mmu_index(env));
731 #endif
733 void cpu_reset(CPUSPARCState *env)
735 if (qemu_loglevel_mask(CPU_LOG_RESET)) {
736 qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
737 log_cpu_state(env, 0);
740 tlb_flush(env, 1);
741 env->cwp = 0;
742 #ifndef TARGET_SPARC64
743 env->wim = 1;
744 #endif
745 env->regwptr = env->regbase + (env->cwp * 16);
746 CC_OP = CC_OP_FLAGS;
747 #if defined(CONFIG_USER_ONLY)
748 #ifdef TARGET_SPARC64
749 env->cleanwin = env->nwindows - 2;
750 env->cansave = env->nwindows - 2;
751 env->pstate = PS_RMO | PS_PEF | PS_IE;
752 env->asi = 0x82; // Primary no-fault
753 #endif
754 #else
755 #if !defined(TARGET_SPARC64)
756 env->psret = 0;
757 env->psrs = 1;
758 env->psrps = 1;
759 #endif
760 #ifdef TARGET_SPARC64
761 env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
762 env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
763 env->tl = env->maxtl;
764 cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
765 env->lsu = 0;
766 #else
767 env->mmuregs[0] &= ~(MMU_E | MMU_NF);
768 env->mmuregs[0] |= env->def->mmu_bm;
769 #endif
770 env->pc = 0;
771 env->npc = env->pc + 4;
772 #endif
773 env->cache_control = 0;
776 static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
778 sparc_def_t def1, *def = &def1;
780 if (cpu_sparc_find_by_name(def, cpu_model) < 0)
781 return -1;
783 env->def = qemu_mallocz(sizeof(*def));
784 memcpy(env->def, def, sizeof(*def));
785 #if defined(CONFIG_USER_ONLY)
786 if ((env->def->features & CPU_FEATURE_FLOAT))
787 env->def->features |= CPU_FEATURE_FLOAT128;
788 #endif
789 env->cpu_model_str = cpu_model;
790 env->version = def->iu_version;
791 env->fsr = def->fpu_version;
792 env->nwindows = def->nwindows;
793 #if !defined(TARGET_SPARC64)
794 env->mmuregs[0] |= def->mmu_version;
795 cpu_sparc_set_id(env, 0);
796 env->mxccregs[7] |= def->mxcc_version;
797 #else
798 env->mmu_version = def->mmu_version;
799 env->maxtl = def->maxtl;
800 env->version |= def->maxtl << 8;
801 env->version |= def->nwindows - 1;
802 #endif
803 return 0;
806 static void cpu_sparc_close(CPUSPARCState *env)
808 free(env->def);
809 free(env);
812 CPUSPARCState *cpu_sparc_init(const char *cpu_model)
814 CPUSPARCState *env;
816 env = qemu_mallocz(sizeof(CPUSPARCState));
817 cpu_exec_init(env);
819 gen_intermediate_code_init(env);
821 if (cpu_sparc_register(env, cpu_model) < 0) {
822 cpu_sparc_close(env);
823 return NULL;
825 qemu_init_vcpu(env);
827 return env;
830 void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
832 #if !defined(TARGET_SPARC64)
833 env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
834 #endif
837 static const sparc_def_t sparc_defs[] = {
838 #ifdef TARGET_SPARC64
840 .name = "Fujitsu Sparc64",
841 .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
842 .fpu_version = 0x00000000,
843 .mmu_version = mmu_us_12,
844 .nwindows = 4,
845 .maxtl = 4,
846 .features = CPU_DEFAULT_FEATURES,
849 .name = "Fujitsu Sparc64 III",
850 .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
851 .fpu_version = 0x00000000,
852 .mmu_version = mmu_us_12,
853 .nwindows = 5,
854 .maxtl = 4,
855 .features = CPU_DEFAULT_FEATURES,
858 .name = "Fujitsu Sparc64 IV",
859 .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
860 .fpu_version = 0x00000000,
861 .mmu_version = mmu_us_12,
862 .nwindows = 8,
863 .maxtl = 5,
864 .features = CPU_DEFAULT_FEATURES,
867 .name = "Fujitsu Sparc64 V",
868 .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
869 .fpu_version = 0x00000000,
870 .mmu_version = mmu_us_12,
871 .nwindows = 8,
872 .maxtl = 5,
873 .features = CPU_DEFAULT_FEATURES,
876 .name = "TI UltraSparc I",
877 .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
878 .fpu_version = 0x00000000,
879 .mmu_version = mmu_us_12,
880 .nwindows = 8,
881 .maxtl = 5,
882 .features = CPU_DEFAULT_FEATURES,
885 .name = "TI UltraSparc II",
886 .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
887 .fpu_version = 0x00000000,
888 .mmu_version = mmu_us_12,
889 .nwindows = 8,
890 .maxtl = 5,
891 .features = CPU_DEFAULT_FEATURES,
894 .name = "TI UltraSparc IIi",
895 .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
896 .fpu_version = 0x00000000,
897 .mmu_version = mmu_us_12,
898 .nwindows = 8,
899 .maxtl = 5,
900 .features = CPU_DEFAULT_FEATURES,
903 .name = "TI UltraSparc IIe",
904 .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
905 .fpu_version = 0x00000000,
906 .mmu_version = mmu_us_12,
907 .nwindows = 8,
908 .maxtl = 5,
909 .features = CPU_DEFAULT_FEATURES,
912 .name = "Sun UltraSparc III",
913 .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
914 .fpu_version = 0x00000000,
915 .mmu_version = mmu_us_12,
916 .nwindows = 8,
917 .maxtl = 5,
918 .features = CPU_DEFAULT_FEATURES,
921 .name = "Sun UltraSparc III Cu",
922 .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
923 .fpu_version = 0x00000000,
924 .mmu_version = mmu_us_3,
925 .nwindows = 8,
926 .maxtl = 5,
927 .features = CPU_DEFAULT_FEATURES,
930 .name = "Sun UltraSparc IIIi",
931 .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
932 .fpu_version = 0x00000000,
933 .mmu_version = mmu_us_12,
934 .nwindows = 8,
935 .maxtl = 5,
936 .features = CPU_DEFAULT_FEATURES,
939 .name = "Sun UltraSparc IV",
940 .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
941 .fpu_version = 0x00000000,
942 .mmu_version = mmu_us_4,
943 .nwindows = 8,
944 .maxtl = 5,
945 .features = CPU_DEFAULT_FEATURES,
948 .name = "Sun UltraSparc IV+",
949 .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
950 .fpu_version = 0x00000000,
951 .mmu_version = mmu_us_12,
952 .nwindows = 8,
953 .maxtl = 5,
954 .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
957 .name = "Sun UltraSparc IIIi+",
958 .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
959 .fpu_version = 0x00000000,
960 .mmu_version = mmu_us_3,
961 .nwindows = 8,
962 .maxtl = 5,
963 .features = CPU_DEFAULT_FEATURES,
966 .name = "Sun UltraSparc T1",
967 // defined in sparc_ifu_fdp.v and ctu.h
968 .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
969 .fpu_version = 0x00000000,
970 .mmu_version = mmu_sun4v,
971 .nwindows = 8,
972 .maxtl = 6,
973 .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
974 | CPU_FEATURE_GL,
977 .name = "Sun UltraSparc T2",
978 // defined in tlu_asi_ctl.v and n2_revid_cust.v
979 .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
980 .fpu_version = 0x00000000,
981 .mmu_version = mmu_sun4v,
982 .nwindows = 8,
983 .maxtl = 6,
984 .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
985 | CPU_FEATURE_GL,
988 .name = "NEC UltraSparc I",
989 .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
990 .fpu_version = 0x00000000,
991 .mmu_version = mmu_us_12,
992 .nwindows = 8,
993 .maxtl = 5,
994 .features = CPU_DEFAULT_FEATURES,
996 #else
998 .name = "Fujitsu MB86900",
999 .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
1000 .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1001 .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
1002 .mmu_bm = 0x00004000,
1003 .mmu_ctpr_mask = 0x007ffff0,
1004 .mmu_cxr_mask = 0x0000003f,
1005 .mmu_sfsr_mask = 0xffffffff,
1006 .mmu_trcr_mask = 0xffffffff,
1007 .nwindows = 7,
1008 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
1011 .name = "Fujitsu MB86904",
1012 .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
1013 .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1014 .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
1015 .mmu_bm = 0x00004000,
1016 .mmu_ctpr_mask = 0x00ffffc0,
1017 .mmu_cxr_mask = 0x000000ff,
1018 .mmu_sfsr_mask = 0x00016fff,
1019 .mmu_trcr_mask = 0x00ffffff,
1020 .nwindows = 8,
1021 .features = CPU_DEFAULT_FEATURES,
1024 .name = "Fujitsu MB86907",
1025 .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
1026 .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1027 .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
1028 .mmu_bm = 0x00004000,
1029 .mmu_ctpr_mask = 0xffffffc0,
1030 .mmu_cxr_mask = 0x000000ff,
1031 .mmu_sfsr_mask = 0x00016fff,
1032 .mmu_trcr_mask = 0xffffffff,
1033 .nwindows = 8,
1034 .features = CPU_DEFAULT_FEATURES,
1037 .name = "LSI L64811",
1038 .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
1039 .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
1040 .mmu_version = 0x10 << 24,
1041 .mmu_bm = 0x00004000,
1042 .mmu_ctpr_mask = 0x007ffff0,
1043 .mmu_cxr_mask = 0x0000003f,
1044 .mmu_sfsr_mask = 0xffffffff,
1045 .mmu_trcr_mask = 0xffffffff,
1046 .nwindows = 8,
1047 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1048 CPU_FEATURE_FSMULD,
1051 .name = "Cypress CY7C601",
1052 .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
1053 .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
1054 .mmu_version = 0x10 << 24,
1055 .mmu_bm = 0x00004000,
1056 .mmu_ctpr_mask = 0x007ffff0,
1057 .mmu_cxr_mask = 0x0000003f,
1058 .mmu_sfsr_mask = 0xffffffff,
1059 .mmu_trcr_mask = 0xffffffff,
1060 .nwindows = 8,
1061 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1062 CPU_FEATURE_FSMULD,
1065 .name = "Cypress CY7C611",
1066 .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
1067 .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
1068 .mmu_version = 0x10 << 24,
1069 .mmu_bm = 0x00004000,
1070 .mmu_ctpr_mask = 0x007ffff0,
1071 .mmu_cxr_mask = 0x0000003f,
1072 .mmu_sfsr_mask = 0xffffffff,
1073 .mmu_trcr_mask = 0xffffffff,
1074 .nwindows = 8,
1075 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1076 CPU_FEATURE_FSMULD,
1079 .name = "TI MicroSparc I",
1080 .iu_version = 0x41000000,
1081 .fpu_version = 4 << 17,
1082 .mmu_version = 0x41000000,
1083 .mmu_bm = 0x00004000,
1084 .mmu_ctpr_mask = 0x007ffff0,
1085 .mmu_cxr_mask = 0x0000003f,
1086 .mmu_sfsr_mask = 0x00016fff,
1087 .mmu_trcr_mask = 0x0000003f,
1088 .nwindows = 7,
1089 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
1090 CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
1091 CPU_FEATURE_FMUL,
1094 .name = "TI MicroSparc II",
1095 .iu_version = 0x42000000,
1096 .fpu_version = 4 << 17,
1097 .mmu_version = 0x02000000,
1098 .mmu_bm = 0x00004000,
1099 .mmu_ctpr_mask = 0x00ffffc0,
1100 .mmu_cxr_mask = 0x000000ff,
1101 .mmu_sfsr_mask = 0x00016fff,
1102 .mmu_trcr_mask = 0x00ffffff,
1103 .nwindows = 8,
1104 .features = CPU_DEFAULT_FEATURES,
1107 .name = "TI MicroSparc IIep",
1108 .iu_version = 0x42000000,
1109 .fpu_version = 4 << 17,
1110 .mmu_version = 0x04000000,
1111 .mmu_bm = 0x00004000,
1112 .mmu_ctpr_mask = 0x00ffffc0,
1113 .mmu_cxr_mask = 0x000000ff,
1114 .mmu_sfsr_mask = 0x00016bff,
1115 .mmu_trcr_mask = 0x00ffffff,
1116 .nwindows = 8,
1117 .features = CPU_DEFAULT_FEATURES,
1120 .name = "TI SuperSparc 40", // STP1020NPGA
1121 .iu_version = 0x41000000, // SuperSPARC 2.x
1122 .fpu_version = 0 << 17,
1123 .mmu_version = 0x00000800, // SuperSPARC 2.x, no MXCC
1124 .mmu_bm = 0x00002000,
1125 .mmu_ctpr_mask = 0xffffffc0,
1126 .mmu_cxr_mask = 0x0000ffff,
1127 .mmu_sfsr_mask = 0xffffffff,
1128 .mmu_trcr_mask = 0xffffffff,
1129 .nwindows = 8,
1130 .features = CPU_DEFAULT_FEATURES,
1133 .name = "TI SuperSparc 50", // STP1020PGA
1134 .iu_version = 0x40000000, // SuperSPARC 3.x
1135 .fpu_version = 0 << 17,
1136 .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
1137 .mmu_bm = 0x00002000,
1138 .mmu_ctpr_mask = 0xffffffc0,
1139 .mmu_cxr_mask = 0x0000ffff,
1140 .mmu_sfsr_mask = 0xffffffff,
1141 .mmu_trcr_mask = 0xffffffff,
1142 .nwindows = 8,
1143 .features = CPU_DEFAULT_FEATURES,
1146 .name = "TI SuperSparc 51",
1147 .iu_version = 0x40000000, // SuperSPARC 3.x
1148 .fpu_version = 0 << 17,
1149 .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
1150 .mmu_bm = 0x00002000,
1151 .mmu_ctpr_mask = 0xffffffc0,
1152 .mmu_cxr_mask = 0x0000ffff,
1153 .mmu_sfsr_mask = 0xffffffff,
1154 .mmu_trcr_mask = 0xffffffff,
1155 .mxcc_version = 0x00000104,
1156 .nwindows = 8,
1157 .features = CPU_DEFAULT_FEATURES,
1160 .name = "TI SuperSparc 60", // STP1020APGA
1161 .iu_version = 0x40000000, // SuperSPARC 3.x
1162 .fpu_version = 0 << 17,
1163 .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
1164 .mmu_bm = 0x00002000,
1165 .mmu_ctpr_mask = 0xffffffc0,
1166 .mmu_cxr_mask = 0x0000ffff,
1167 .mmu_sfsr_mask = 0xffffffff,
1168 .mmu_trcr_mask = 0xffffffff,
1169 .nwindows = 8,
1170 .features = CPU_DEFAULT_FEATURES,
1173 .name = "TI SuperSparc 61",
1174 .iu_version = 0x44000000, // SuperSPARC 3.x
1175 .fpu_version = 0 << 17,
1176 .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
1177 .mmu_bm = 0x00002000,
1178 .mmu_ctpr_mask = 0xffffffc0,
1179 .mmu_cxr_mask = 0x0000ffff,
1180 .mmu_sfsr_mask = 0xffffffff,
1181 .mmu_trcr_mask = 0xffffffff,
1182 .mxcc_version = 0x00000104,
1183 .nwindows = 8,
1184 .features = CPU_DEFAULT_FEATURES,
1187 .name = "TI SuperSparc II",
1188 .iu_version = 0x40000000, // SuperSPARC II 1.x
1189 .fpu_version = 0 << 17,
1190 .mmu_version = 0x08000000, // SuperSPARC II 1.x, MXCC
1191 .mmu_bm = 0x00002000,
1192 .mmu_ctpr_mask = 0xffffffc0,
1193 .mmu_cxr_mask = 0x0000ffff,
1194 .mmu_sfsr_mask = 0xffffffff,
1195 .mmu_trcr_mask = 0xffffffff,
1196 .mxcc_version = 0x00000104,
1197 .nwindows = 8,
1198 .features = CPU_DEFAULT_FEATURES,
1201 .name = "Ross RT625",
1202 .iu_version = 0x1e000000,
1203 .fpu_version = 1 << 17,
1204 .mmu_version = 0x1e000000,
1205 .mmu_bm = 0x00004000,
1206 .mmu_ctpr_mask = 0x007ffff0,
1207 .mmu_cxr_mask = 0x0000003f,
1208 .mmu_sfsr_mask = 0xffffffff,
1209 .mmu_trcr_mask = 0xffffffff,
1210 .nwindows = 8,
1211 .features = CPU_DEFAULT_FEATURES,
1214 .name = "Ross RT620",
1215 .iu_version = 0x1f000000,
1216 .fpu_version = 1 << 17,
1217 .mmu_version = 0x1f000000,
1218 .mmu_bm = 0x00004000,
1219 .mmu_ctpr_mask = 0x007ffff0,
1220 .mmu_cxr_mask = 0x0000003f,
1221 .mmu_sfsr_mask = 0xffffffff,
1222 .mmu_trcr_mask = 0xffffffff,
1223 .nwindows = 8,
1224 .features = CPU_DEFAULT_FEATURES,
1227 .name = "BIT B5010",
1228 .iu_version = 0x20000000,
1229 .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
1230 .mmu_version = 0x20000000,
1231 .mmu_bm = 0x00004000,
1232 .mmu_ctpr_mask = 0x007ffff0,
1233 .mmu_cxr_mask = 0x0000003f,
1234 .mmu_sfsr_mask = 0xffffffff,
1235 .mmu_trcr_mask = 0xffffffff,
1236 .nwindows = 8,
1237 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1238 CPU_FEATURE_FSMULD,
1241 .name = "Matsushita MN10501",
1242 .iu_version = 0x50000000,
1243 .fpu_version = 0 << 17,
1244 .mmu_version = 0x50000000,
1245 .mmu_bm = 0x00004000,
1246 .mmu_ctpr_mask = 0x007ffff0,
1247 .mmu_cxr_mask = 0x0000003f,
1248 .mmu_sfsr_mask = 0xffffffff,
1249 .mmu_trcr_mask = 0xffffffff,
1250 .nwindows = 8,
1251 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
1252 CPU_FEATURE_FSMULD,
1255 .name = "Weitek W8601",
1256 .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
1257 .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
1258 .mmu_version = 0x10 << 24,
1259 .mmu_bm = 0x00004000,
1260 .mmu_ctpr_mask = 0x007ffff0,
1261 .mmu_cxr_mask = 0x0000003f,
1262 .mmu_sfsr_mask = 0xffffffff,
1263 .mmu_trcr_mask = 0xffffffff,
1264 .nwindows = 8,
1265 .features = CPU_DEFAULT_FEATURES,
1268 .name = "LEON2",
1269 .iu_version = 0xf2000000,
1270 .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1271 .mmu_version = 0xf2000000,
1272 .mmu_bm = 0x00004000,
1273 .mmu_ctpr_mask = 0x007ffff0,
1274 .mmu_cxr_mask = 0x0000003f,
1275 .mmu_sfsr_mask = 0xffffffff,
1276 .mmu_trcr_mask = 0xffffffff,
1277 .nwindows = 8,
1278 .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
1281 .name = "LEON3",
1282 .iu_version = 0xf3000000,
1283 .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1284 .mmu_version = 0xf3000000,
1285 .mmu_bm = 0x00000000,
1286 .mmu_ctpr_mask = 0x007ffff0,
1287 .mmu_cxr_mask = 0x0000003f,
1288 .mmu_sfsr_mask = 0xffffffff,
1289 .mmu_trcr_mask = 0xffffffff,
1290 .nwindows = 8,
1291 .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
1292 CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
1294 #endif
1297 static const char * const feature_name[] = {
1298 "float",
1299 "float128",
1300 "swap",
1301 "mul",
1302 "div",
1303 "flush",
1304 "fsqrt",
1305 "fmul",
1306 "vis1",
1307 "vis2",
1308 "fsmuld",
1309 "hypv",
1310 "cmt",
1311 "gl",
1314 static void print_features(FILE *f, fprintf_function cpu_fprintf,
1315 uint32_t features, const char *prefix)
1317 unsigned int i;
1319 for (i = 0; i < ARRAY_SIZE(feature_name); i++)
1320 if (feature_name[i] && (features & (1 << i))) {
1321 if (prefix)
1322 (*cpu_fprintf)(f, "%s", prefix);
1323 (*cpu_fprintf)(f, "%s ", feature_name[i]);
1327 static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
1329 unsigned int i;
1331 for (i = 0; i < ARRAY_SIZE(feature_name); i++)
1332 if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
1333 *features |= 1 << i;
1334 return;
1336 fprintf(stderr, "CPU feature %s not found\n", flagname);
1339 static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
1341 unsigned int i;
1342 const sparc_def_t *def = NULL;
1343 char *s = strdup(cpu_model);
1344 char *featurestr, *name = strtok(s, ",");
1345 uint32_t plus_features = 0;
1346 uint32_t minus_features = 0;
1347 uint64_t iu_version;
1348 uint32_t fpu_version, mmu_version, nwindows;
1350 for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
1351 if (strcasecmp(name, sparc_defs[i].name) == 0) {
1352 def = &sparc_defs[i];
1355 if (!def)
1356 goto error;
1357 memcpy(cpu_def, def, sizeof(*def));
1359 featurestr = strtok(NULL, ",");
1360 while (featurestr) {
1361 char *val;
1363 if (featurestr[0] == '+') {
1364 add_flagname_to_bitmaps(featurestr + 1, &plus_features);
1365 } else if (featurestr[0] == '-') {
1366 add_flagname_to_bitmaps(featurestr + 1, &minus_features);
1367 } else if ((val = strchr(featurestr, '='))) {
1368 *val = 0; val++;
1369 if (!strcmp(featurestr, "iu_version")) {
1370 char *err;
1372 iu_version = strtoll(val, &err, 0);
1373 if (!*val || *err) {
1374 fprintf(stderr, "bad numerical value %s\n", val);
1375 goto error;
1377 cpu_def->iu_version = iu_version;
1378 #ifdef DEBUG_FEATURES
1379 fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
1380 #endif
1381 } else if (!strcmp(featurestr, "fpu_version")) {
1382 char *err;
1384 fpu_version = strtol(val, &err, 0);
1385 if (!*val || *err) {
1386 fprintf(stderr, "bad numerical value %s\n", val);
1387 goto error;
1389 cpu_def->fpu_version = fpu_version;
1390 #ifdef DEBUG_FEATURES
1391 fprintf(stderr, "fpu_version %x\n", fpu_version);
1392 #endif
1393 } else if (!strcmp(featurestr, "mmu_version")) {
1394 char *err;
1396 mmu_version = strtol(val, &err, 0);
1397 if (!*val || *err) {
1398 fprintf(stderr, "bad numerical value %s\n", val);
1399 goto error;
1401 cpu_def->mmu_version = mmu_version;
1402 #ifdef DEBUG_FEATURES
1403 fprintf(stderr, "mmu_version %x\n", mmu_version);
1404 #endif
1405 } else if (!strcmp(featurestr, "nwindows")) {
1406 char *err;
1408 nwindows = strtol(val, &err, 0);
1409 if (!*val || *err || nwindows > MAX_NWINDOWS ||
1410 nwindows < MIN_NWINDOWS) {
1411 fprintf(stderr, "bad numerical value %s\n", val);
1412 goto error;
1414 cpu_def->nwindows = nwindows;
1415 #ifdef DEBUG_FEATURES
1416 fprintf(stderr, "nwindows %d\n", nwindows);
1417 #endif
1418 } else {
1419 fprintf(stderr, "unrecognized feature %s\n", featurestr);
1420 goto error;
1422 } else {
1423 fprintf(stderr, "feature string `%s' not in format "
1424 "(+feature|-feature|feature=xyz)\n", featurestr);
1425 goto error;
1427 featurestr = strtok(NULL, ",");
1429 cpu_def->features |= plus_features;
1430 cpu_def->features &= ~minus_features;
1431 #ifdef DEBUG_FEATURES
1432 print_features(stderr, fprintf, cpu_def->features, NULL);
1433 #endif
1434 free(s);
1435 return 0;
1437 error:
1438 free(s);
1439 return -1;
1442 void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
1444 unsigned int i;
1446 for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
1447 (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x NWINS %d ",
1448 sparc_defs[i].name,
1449 sparc_defs[i].iu_version,
1450 sparc_defs[i].fpu_version,
1451 sparc_defs[i].mmu_version,
1452 sparc_defs[i].nwindows);
1453 print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
1454 ~sparc_defs[i].features, "-");
1455 print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
1456 sparc_defs[i].features, "+");
1457 (*cpu_fprintf)(f, "\n");
1459 (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
1460 print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
1461 (*cpu_fprintf)(f, "\n");
1462 (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
1463 print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
1464 (*cpu_fprintf)(f, "\n");
1465 (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
1466 "fpu_version mmu_version nwindows\n");
1469 static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
1470 uint32_t cc)
1472 cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG? 'N' : '-',
1473 cc & PSR_ZERO? 'Z' : '-', cc & PSR_OVF? 'V' : '-',
1474 cc & PSR_CARRY? 'C' : '-');
1477 #ifdef TARGET_SPARC64
1478 #define REGS_PER_LINE 4
1479 #else
1480 #define REGS_PER_LINE 8
1481 #endif
1483 void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
1484 int flags)
1486 int i, x;
1488 cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc,
1489 env->npc);
1490 cpu_fprintf(f, "General Registers:\n");
1492 for (i = 0; i < 8; i++) {
1493 if (i % REGS_PER_LINE == 0) {
1494 cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
1496 cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
1497 if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
1498 cpu_fprintf(f, "\n");
1501 cpu_fprintf(f, "\nCurrent Register Window:\n");
1502 for (x = 0; x < 3; x++) {
1503 for (i = 0; i < 8; i++) {
1504 if (i % REGS_PER_LINE == 0) {
1505 cpu_fprintf(f, "%%%c%d-%d: ",
1506 x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
1507 i, i + REGS_PER_LINE - 1);
1509 cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
1510 if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
1511 cpu_fprintf(f, "\n");
1515 cpu_fprintf(f, "\nFloating Point Registers:\n");
1516 for (i = 0; i < TARGET_FPREGS; i++) {
1517 if ((i & 3) == 0)
1518 cpu_fprintf(f, "%%f%02d:", i);
1519 cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
1520 if ((i & 3) == 3)
1521 cpu_fprintf(f, "\n");
1523 #ifdef TARGET_SPARC64
1524 cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
1525 (unsigned)cpu_get_ccr(env));
1526 cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
1527 cpu_fprintf(f, " xcc: ");
1528 cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
1529 cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
1530 env->psrpil);
1531 cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
1532 "cleanwin: %d cwp: %d\n",
1533 env->cansave, env->canrestore, env->otherwin, env->wstate,
1534 env->cleanwin, env->nwindows - 1 - env->cwp);
1535 cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
1536 TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
1537 #else
1538 cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
1539 cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
1540 cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs? 'S' : '-',
1541 env->psrps? 'P' : '-', env->psret? 'E' : '-',
1542 env->wim);
1543 cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
1544 env->fsr, env->y);
1545 #endif