|
|
1.1 root 1: /*
2: * sparc helpers
1.1.1.4 root 3: *
1.1 root 4: * Copyright (c) 2003-2005 Fabrice Bellard
5: *
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.
10: *
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.
15: *
16: * You should have received a copy of the GNU Lesser General Public
1.1.1.6 root 17: * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1.1 root 18: */
19: #include <stdarg.h>
20: #include <stdlib.h>
21: #include <stdio.h>
22: #include <string.h>
23: #include <inttypes.h>
24: #include <signal.h>
25:
26: #include "cpu.h"
27: #include "exec-all.h"
1.1.1.5 root 28: #include "qemu-common.h"
1.1 root 29:
30: //#define DEBUG_MMU
1.1.1.5 root 31: //#define DEBUG_FEATURES
32:
33: static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
1.1 root 34:
35: /* Sparc MMU emulation */
36:
37: /* thread support */
38:
1.1.1.5 root 39: static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
1.1 root 40:
41: void cpu_lock(void)
42: {
43: spin_lock(&global_cpu_lock);
44: }
45:
46: void cpu_unlock(void)
47: {
48: spin_unlock(&global_cpu_lock);
49: }
50:
1.1.1.4 root 51: #if defined(CONFIG_USER_ONLY)
1.1 root 52:
1.1.1.5 root 53: int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
1.1.1.4 root 54: int mmu_idx, int is_softmmu)
1.1 root 55: {
56: if (rw & 2)
1.1.1.5 root 57: env1->exception_index = TT_TFAULT;
1.1 root 58: else
1.1.1.5 root 59: env1->exception_index = TT_DFAULT;
1.1 root 60: return 1;
61: }
62:
63: #else
64:
65: #ifndef TARGET_SPARC64
66: /*
67: * Sparc V8 Reference MMU (SRMMU)
68: */
69: static const int access_table[8][8] = {
1.1.1.5 root 70: { 0, 0, 0, 0, 8, 0, 12, 12 },
71: { 0, 0, 0, 0, 8, 0, 0, 0 },
72: { 8, 8, 0, 0, 0, 8, 12, 12 },
73: { 8, 8, 0, 0, 0, 8, 0, 0 },
74: { 8, 0, 8, 0, 8, 8, 12, 12 },
75: { 8, 0, 8, 0, 8, 0, 8, 0 },
76: { 8, 8, 8, 0, 8, 8, 12, 12 },
77: { 8, 8, 8, 0, 8, 8, 8, 0 }
1.1 root 78: };
79:
1.1.1.2 root 80: static const int perm_table[2][8] = {
81: {
82: PAGE_READ,
83: PAGE_READ | PAGE_WRITE,
84: PAGE_READ | PAGE_EXEC,
85: PAGE_READ | PAGE_WRITE | PAGE_EXEC,
86: PAGE_EXEC,
87: PAGE_READ | PAGE_WRITE,
88: PAGE_READ | PAGE_EXEC,
89: PAGE_READ | PAGE_WRITE | PAGE_EXEC
90: },
91: {
92: PAGE_READ,
93: PAGE_READ | PAGE_WRITE,
94: PAGE_READ | PAGE_EXEC,
95: PAGE_READ | PAGE_WRITE | PAGE_EXEC,
96: PAGE_EXEC,
97: PAGE_READ,
98: 0,
99: 0,
100: }
1.1 root 101: };
102:
1.1.1.5 root 103: static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
104: int *prot, int *access_index,
105: target_ulong address, int rw, int mmu_idx)
1.1 root 106: {
107: int access_perms = 0;
108: target_phys_addr_t pde_ptr;
109: uint32_t pde;
110: target_ulong virt_addr;
1.1.1.4 root 111: int error_code = 0, is_dirty, is_user;
1.1 root 112: unsigned long page_offset;
113:
1.1.1.4 root 114: is_user = mmu_idx == MMU_USER_IDX;
1.1 root 115: virt_addr = address & TARGET_PAGE_MASK;
1.1.1.4 root 116:
1.1 root 117: if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
1.1.1.4 root 118: // Boot mode: instruction fetches are taken from PROM
1.1.1.5 root 119: if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
1.1.1.4 root 120: *physical = env->prom_addr | (address & 0x7ffffULL);
121: *prot = PAGE_READ | PAGE_EXEC;
122: return 0;
123: }
124: *physical = address;
1.1.1.2 root 125: *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
1.1 root 126: return 0;
127: }
128:
129: *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
1.1.1.4 root 130: *physical = 0xffffffffffff0000ULL;
1.1 root 131:
132: /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
133: /* Context base + context number */
1.1.1.5 root 134: pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
1.1 root 135: pde = ldl_phys(pde_ptr);
136:
137: /* Ctx pde */
138: switch (pde & PTE_ENTRYTYPE_MASK) {
139: default:
140: case 0: /* Invalid */
1.1.1.4 root 141: return 1 << 2;
1.1 root 142: case 2: /* L0 PTE, maybe should not happen? */
143: case 3: /* Reserved */
144: return 4 << 2;
145: case 1: /* L0 PDE */
1.1.1.4 root 146: pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
1.1 root 147: pde = ldl_phys(pde_ptr);
148:
1.1.1.4 root 149: switch (pde & PTE_ENTRYTYPE_MASK) {
150: default:
151: case 0: /* Invalid */
152: return (1 << 8) | (1 << 2);
153: case 3: /* Reserved */
154: return (1 << 8) | (4 << 2);
155: case 1: /* L1 PDE */
156: pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
1.1 root 157: pde = ldl_phys(pde_ptr);
158:
1.1.1.4 root 159: switch (pde & PTE_ENTRYTYPE_MASK) {
160: default:
161: case 0: /* Invalid */
162: return (2 << 8) | (1 << 2);
163: case 3: /* Reserved */
164: return (2 << 8) | (4 << 2);
165: case 1: /* L2 PDE */
166: pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
1.1 root 167: pde = ldl_phys(pde_ptr);
168:
1.1.1.4 root 169: switch (pde & PTE_ENTRYTYPE_MASK) {
170: default:
171: case 0: /* Invalid */
172: return (3 << 8) | (1 << 2);
173: case 1: /* PDE, should not happen */
174: case 3: /* Reserved */
175: return (3 << 8) | (4 << 2);
176: case 2: /* L3 PTE */
177: virt_addr = address & TARGET_PAGE_MASK;
1.1.1.5 root 178: page_offset = (address & TARGET_PAGE_MASK) &
179: (TARGET_PAGE_SIZE - 1);
1.1.1.4 root 180: }
181: break;
182: case 2: /* L2 PTE */
183: virt_addr = address & ~0x3ffff;
184: page_offset = address & 0x3ffff;
185: }
186: break;
187: case 2: /* L1 PTE */
188: virt_addr = address & ~0xffffff;
189: page_offset = address & 0xffffff;
190: }
1.1 root 191: }
192:
193: /* update page modified and dirty bits */
194: is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
195: if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
1.1.1.4 root 196: pde |= PG_ACCESSED_MASK;
197: if (is_dirty)
198: pde |= PG_MODIFIED_MASK;
1.1 root 199: stl_phys_notdirty(pde_ptr, pde);
200: }
201: /* check access */
202: access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
203: error_code = access_table[*access_index][access_perms];
1.1.1.3 root 204: if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user))
1.1.1.4 root 205: return error_code;
1.1 root 206:
207: /* the page can be put in the TLB */
1.1.1.2 root 208: *prot = perm_table[is_user][access_perms];
209: if (!(pde & PG_MODIFIED_MASK)) {
1.1 root 210: /* only set write access if already dirty... otherwise wait
211: for dirty access */
1.1.1.2 root 212: *prot &= ~PAGE_WRITE;
1.1 root 213: }
214:
215: /* Even if large ptes, we map only one 4KB page in the cache to
216: avoid filling it too fast */
1.1.1.4 root 217: *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
1.1 root 218: return error_code;
219: }
220:
221: /* Perform address translation */
222: int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
1.1.1.4 root 223: int mmu_idx, int is_softmmu)
1.1 root 224: {
225: target_phys_addr_t paddr;
1.1.1.4 root 226: target_ulong vaddr;
1.1 root 227: int error_code = 0, prot, ret = 0, access_index;
228:
1.1.1.5 root 229: error_code = get_physical_address(env, &paddr, &prot, &access_index,
230: address, rw, mmu_idx);
1.1 root 231: if (error_code == 0) {
1.1.1.4 root 232: vaddr = address & TARGET_PAGE_MASK;
233: paddr &= TARGET_PAGE_MASK;
1.1.1.2 root 234: #ifdef DEBUG_MMU
1.1.1.4 root 235: printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
236: TARGET_FMT_lx "\n", address, paddr, vaddr);
1.1.1.2 root 237: #endif
1.1.1.4 root 238: ret = tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu);
239: return ret;
1.1 root 240: }
241:
242: if (env->mmuregs[3]) /* Fault status register */
1.1.1.4 root 243: env->mmuregs[3] = 1; /* overflow (not read before another fault) */
1.1 root 244: env->mmuregs[3] |= (access_index << 5) | error_code | 2;
245: env->mmuregs[4] = address; /* Fault address register */
246:
247: if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) {
248: // No fault mode: if a mapping is available, just override
249: // permissions. If no mapping is available, redirect accesses to
250: // neverland. Fake/overridden mappings will be flushed when
251: // switching to normal mode.
1.1.1.4 root 252: vaddr = address & TARGET_PAGE_MASK;
1.1.1.2 root 253: prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
1.1.1.4 root 254: ret = tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu);
255: return ret;
1.1 root 256: } else {
257: if (rw & 2)
258: env->exception_index = TT_TFAULT;
259: else
260: env->exception_index = TT_DFAULT;
261: return 1;
262: }
263: }
1.1.1.2 root 264:
265: target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
266: {
267: target_phys_addr_t pde_ptr;
268: uint32_t pde;
269:
270: /* Context base + context number */
1.1.1.4 root 271: pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
272: (env->mmuregs[2] << 2);
1.1.1.2 root 273: pde = ldl_phys(pde_ptr);
274:
275: switch (pde & PTE_ENTRYTYPE_MASK) {
276: default:
277: case 0: /* Invalid */
278: case 2: /* PTE, maybe should not happen? */
279: case 3: /* Reserved */
1.1.1.4 root 280: return 0;
1.1.1.2 root 281: case 1: /* L1 PDE */
1.1.1.4 root 282: if (mmulev == 3)
283: return pde;
284: pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
1.1.1.2 root 285: pde = ldl_phys(pde_ptr);
286:
1.1.1.4 root 287: switch (pde & PTE_ENTRYTYPE_MASK) {
288: default:
289: case 0: /* Invalid */
290: case 3: /* Reserved */
291: return 0;
292: case 2: /* L1 PTE */
293: return pde;
294: case 1: /* L2 PDE */
295: if (mmulev == 2)
296: return pde;
297: pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
1.1.1.2 root 298: pde = ldl_phys(pde_ptr);
299:
1.1.1.4 root 300: switch (pde & PTE_ENTRYTYPE_MASK) {
301: default:
302: case 0: /* Invalid */
303: case 3: /* Reserved */
304: return 0;
305: case 2: /* L2 PTE */
306: return pde;
307: case 1: /* L3 PDE */
308: if (mmulev == 1)
309: return pde;
310: pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
1.1.1.2 root 311: pde = ldl_phys(pde_ptr);
312:
1.1.1.4 root 313: switch (pde & PTE_ENTRYTYPE_MASK) {
314: default:
315: case 0: /* Invalid */
316: case 1: /* PDE, should not happen */
317: case 3: /* Reserved */
318: return 0;
319: case 2: /* L3 PTE */
320: return pde;
321: }
322: }
323: }
1.1.1.2 root 324: }
325: return 0;
326: }
327:
328: #ifdef DEBUG_MMU
329: void dump_mmu(CPUState *env)
330: {
1.1.1.4 root 331: target_ulong va, va1, va2;
332: unsigned int n, m, o;
333: target_phys_addr_t pde_ptr, pa;
1.1.1.2 root 334: uint32_t pde;
335:
336: printf("MMU dump:\n");
337: pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
338: pde = ldl_phys(pde_ptr);
1.1.1.4 root 339: printf("Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
340: (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
1.1.1.2 root 341: for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
1.1.1.4 root 342: pde = mmu_probe(env, va, 2);
343: if (pde) {
344: pa = cpu_get_phys_page_debug(env, va);
345: printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
346: " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
347: for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
348: pde = mmu_probe(env, va1, 1);
349: if (pde) {
350: pa = cpu_get_phys_page_debug(env, va1);
351: printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
352: " PDE: " TARGET_FMT_lx "\n", va1, pa, pde);
353: for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
354: pde = mmu_probe(env, va2, 0);
355: if (pde) {
356: pa = cpu_get_phys_page_debug(env, va2);
357: printf(" VA: " TARGET_FMT_lx ", PA: "
358: TARGET_FMT_plx " PTE: " TARGET_FMT_lx "\n",
359: va2, pa, pde);
360: }
361: }
362: }
363: }
364: }
1.1.1.2 root 365: }
366: printf("MMU dump ends\n");
367: }
368: #endif /* DEBUG_MMU */
369:
370: #else /* !TARGET_SPARC64 */
1.1.1.6 root 371:
372: // 41 bit physical address space
373: static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
374: {
375: return x & 0x1ffffffffffULL;
376: }
377:
1.1 root 378: /*
379: * UltraSparc IIi I/DMMUs
380: */
1.1.1.6 root 381:
382: static inline int compare_masked(uint64_t x, uint64_t y, uint64_t mask)
383: {
384: return (x & mask) == (y & mask);
385: }
386:
387: // Returns true if TTE tag is valid and matches virtual address value in context
388: // requires virtual address mask value calculated from TTE entry size
1.1.1.7 ! root 389: static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
1.1.1.6 root 390: uint64_t address, uint64_t context,
1.1.1.7 ! root 391: target_phys_addr_t *physical,
! 392: int is_nucleus)
1.1.1.6 root 393: {
394: uint64_t mask;
395:
1.1.1.7 ! root 396: switch ((tlb->tte >> 61) & 3) {
1.1.1.6 root 397: default:
398: case 0x0: // 8k
399: mask = 0xffffffffffffe000ULL;
400: break;
401: case 0x1: // 64k
402: mask = 0xffffffffffff0000ULL;
403: break;
404: case 0x2: // 512k
405: mask = 0xfffffffffff80000ULL;
406: break;
407: case 0x3: // 4M
408: mask = 0xffffffffffc00000ULL;
409: break;
410: }
411:
412: // valid, context match, virtual address match?
1.1.1.7 ! root 413: if (TTE_IS_VALID(tlb->tte) &&
! 414: ((is_nucleus && compare_masked(0, tlb->tag, 0x1fff))
! 415: || TTE_IS_GLOBAL(tlb->tte) || compare_masked(context, tlb->tag, 0x1fff))
! 416: && compare_masked(address, tlb->tag, mask))
1.1.1.6 root 417: {
418: // decode physical address
1.1.1.7 ! root 419: *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
1.1.1.6 root 420: return 1;
421: }
422:
423: return 0;
424: }
425:
1.1.1.5 root 426: static int get_physical_address_data(CPUState *env,
427: target_phys_addr_t *physical, int *prot,
428: target_ulong address, int rw, int is_user)
1.1 root 429: {
430: unsigned int i;
1.1.1.6 root 431: uint64_t context;
1.1.1.7 ! root 432: int is_nucleus;
1.1 root 433:
434: if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
1.1.1.6 root 435: *physical = ultrasparc_truncate_physical(address);
1.1.1.4 root 436: *prot = PAGE_READ | PAGE_WRITE;
1.1 root 437: return 0;
438: }
439:
1.1.1.7 ! root 440: context = env->dmmu.mmu_primary_context & 0x1fff;
! 441: is_nucleus = env->tl > 0;
1.1.1.6 root 442:
1.1 root 443: for (i = 0; i < 64; i++) {
1.1.1.5 root 444: // ctx match, vaddr match, valid?
1.1.1.7 ! root 445: if (ultrasparc_tag_match(&env->dtlb[i],
! 446: address, context, physical,
! 447: is_nucleus)) {
1.1.1.5 root 448: // access ok?
1.1.1.7 ! root 449: if (((env->dtlb[i].tte & 0x4) && is_user) ||
! 450: (!(env->dtlb[i].tte & 0x2) && (rw == 1))) {
! 451: uint8_t fault_type = 0;
! 452:
! 453: if ((env->dtlb[i].tte & 0x4) && is_user) {
! 454: fault_type |= 1; /* privilege violation */
! 455: }
! 456:
! 457: if (env->dmmu.sfsr & 1) /* Fault status register */
! 458: env->dmmu.sfsr = 2; /* overflow (not read before
1.1.1.5 root 459: another fault) */
1.1.1.7 ! root 460:
! 461: env->dmmu.sfsr |= (is_user << 3) | ((rw == 1) << 2) | 1;
! 462:
! 463: env->dmmu.sfsr |= (fault_type << 7);
! 464:
! 465: env->dmmu.sfar = address; /* Fault address register */
1.1.1.4 root 466: env->exception_index = TT_DFAULT;
1.1 root 467: #ifdef DEBUG_MMU
1.1.1.4 root 468: printf("DFAULT at 0x%" PRIx64 "\n", address);
1.1 root 469: #endif
1.1.1.4 root 470: return 1;
471: }
472: *prot = PAGE_READ;
1.1.1.7 ! root 473: if (env->dtlb[i].tte & 0x2)
1.1.1.4 root 474: *prot |= PAGE_WRITE;
1.1.1.7 ! root 475: TTE_SET_USED(env->dtlb[i].tte);
1.1.1.4 root 476: return 0;
477: }
1.1 root 478: }
479: #ifdef DEBUG_MMU
1.1.1.3 root 480: printf("DMISS at 0x%" PRIx64 "\n", address);
1.1 root 481: #endif
1.1.1.7 ! root 482: env->dmmu.tag_access = (address & ~0x1fffULL) | context;
1.1 root 483: env->exception_index = TT_DMISS;
484: return 1;
485: }
486:
1.1.1.5 root 487: static int get_physical_address_code(CPUState *env,
488: target_phys_addr_t *physical, int *prot,
489: target_ulong address, int is_user)
1.1 root 490: {
491: unsigned int i;
1.1.1.6 root 492: uint64_t context;
1.1.1.7 ! root 493: int is_nucleus;
1.1 root 494:
1.1.1.6 root 495: if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
496: /* IMMU disabled */
497: *physical = ultrasparc_truncate_physical(address);
1.1.1.4 root 498: *prot = PAGE_EXEC;
1.1 root 499: return 0;
500: }
501:
1.1.1.7 ! root 502: context = env->dmmu.mmu_primary_context & 0x1fff;
! 503: is_nucleus = env->tl > 0;
1.1.1.6 root 504:
1.1 root 505: for (i = 0; i < 64; i++) {
1.1.1.5 root 506: // ctx match, vaddr match, valid?
1.1.1.7 ! root 507: if (ultrasparc_tag_match(&env->itlb[i],
! 508: address, context, physical,
! 509: is_nucleus)) {
1.1.1.5 root 510: // access ok?
1.1.1.7 ! root 511: if ((env->itlb[i].tte & 0x4) && is_user) {
! 512: if (env->immu.sfsr) /* Fault status register */
! 513: env->immu.sfsr = 2; /* overflow (not read before
1.1.1.5 root 514: another fault) */
1.1.1.7 ! root 515: env->immu.sfsr |= (is_user << 3) | 1;
1.1.1.4 root 516: env->exception_index = TT_TFAULT;
1.1 root 517: #ifdef DEBUG_MMU
1.1.1.4 root 518: printf("TFAULT at 0x%" PRIx64 "\n", address);
1.1 root 519: #endif
1.1.1.4 root 520: return 1;
521: }
522: *prot = PAGE_EXEC;
1.1.1.7 ! root 523: TTE_SET_USED(env->itlb[i].tte);
1.1.1.4 root 524: return 0;
525: }
1.1 root 526: }
527: #ifdef DEBUG_MMU
1.1.1.3 root 528: printf("TMISS at 0x%" PRIx64 "\n", address);
1.1 root 529: #endif
1.1.1.6 root 530: /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
1.1.1.7 ! root 531: env->immu.tag_access = (address & ~0x1fffULL) | context;
1.1 root 532: env->exception_index = TT_TMISS;
533: return 1;
534: }
535:
1.1.1.5 root 536: static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
537: int *prot, int *access_index,
538: target_ulong address, int rw, int mmu_idx)
1.1 root 539: {
1.1.1.4 root 540: int is_user = mmu_idx == MMU_USER_IDX;
541:
1.1 root 542: if (rw == 2)
1.1.1.5 root 543: return get_physical_address_code(env, physical, prot, address,
544: is_user);
1.1 root 545: else
1.1.1.5 root 546: return get_physical_address_data(env, physical, prot, address, rw,
547: is_user);
1.1 root 548: }
549:
550: /* Perform address translation */
551: int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
1.1.1.4 root 552: int mmu_idx, int is_softmmu)
1.1 root 553: {
554: target_ulong virt_addr, vaddr;
555: target_phys_addr_t paddr;
556: int error_code = 0, prot, ret = 0, access_index;
557:
1.1.1.5 root 558: error_code = get_physical_address(env, &paddr, &prot, &access_index,
559: address, rw, mmu_idx);
1.1 root 560: if (error_code == 0) {
1.1.1.4 root 561: virt_addr = address & TARGET_PAGE_MASK;
1.1.1.5 root 562: vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
563: (TARGET_PAGE_SIZE - 1));
1.1 root 564: #ifdef DEBUG_MMU
1.1.1.5 root 565: printf("Translate at 0x%" PRIx64 " -> 0x%" PRIx64 ", vaddr 0x%" PRIx64
566: "\n", address, paddr, vaddr);
1.1 root 567: #endif
1.1.1.4 root 568: ret = tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu);
569: return ret;
1.1 root 570: }
571: // XXX
572: return 1;
573: }
574:
575: #ifdef DEBUG_MMU
576: void dump_mmu(CPUState *env)
577: {
578: unsigned int i;
579: const char *mask;
580:
1.1.1.5 root 581: printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" PRId64 "\n",
1.1.1.7 ! root 582: env->dmmu.mmu_primary_context, env->dmmu.mmu_secondary_context);
1.1 root 583: if ((env->lsu & DMMU_E) == 0) {
1.1.1.4 root 584: printf("DMMU disabled\n");
1.1 root 585: } else {
1.1.1.4 root 586: printf("DMMU dump:\n");
587: for (i = 0; i < 64; i++) {
1.1.1.7 ! root 588: switch ((env->dtlb[i].tte >> 61) & 3) {
1.1.1.4 root 589: default:
590: case 0x0:
591: mask = " 8k";
592: break;
593: case 0x1:
594: mask = " 64k";
595: break;
596: case 0x2:
597: mask = "512k";
598: break;
599: case 0x3:
600: mask = " 4M";
601: break;
602: }
1.1.1.7 ! root 603: if ((env->dtlb[i].tte & 0x8000000000000000ULL) != 0) {
! 604: printf("[%02u] VA: %" PRIx64 ", PA: %" PRIx64
! 605: ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
! 606: i,
! 607: env->dtlb[i].tag & (uint64_t)~0x1fffULL,
! 608: env->dtlb[i].tte & (uint64_t)0x1ffffffe000ULL,
1.1.1.4 root 609: mask,
1.1.1.7 ! root 610: env->dtlb[i].tte & 0x4? "priv": "user",
! 611: env->dtlb[i].tte & 0x2? "RW": "RO",
! 612: env->dtlb[i].tte & 0x40? "locked": "unlocked",
! 613: env->dtlb[i].tag & (uint64_t)0x1fffULL,
! 614: TTE_IS_GLOBAL(env->dtlb[i].tag)? "global" : "local");
1.1.1.4 root 615: }
616: }
1.1 root 617: }
618: if ((env->lsu & IMMU_E) == 0) {
1.1.1.4 root 619: printf("IMMU disabled\n");
1.1 root 620: } else {
1.1.1.4 root 621: printf("IMMU dump:\n");
622: for (i = 0; i < 64; i++) {
1.1.1.7 ! root 623: switch ((env->itlb[i].tte >> 61) & 3) {
1.1.1.4 root 624: default:
625: case 0x0:
626: mask = " 8k";
627: break;
628: case 0x1:
629: mask = " 64k";
630: break;
631: case 0x2:
632: mask = "512k";
633: break;
634: case 0x3:
635: mask = " 4M";
636: break;
637: }
1.1.1.7 ! root 638: if ((env->itlb[i].tte & 0x8000000000000000ULL) != 0) {
! 639: printf("[%02u] VA: %" PRIx64 ", PA: %" PRIx64
! 640: ", %s, %s, %s, ctx %" PRId64 " %s\n",
! 641: i,
! 642: env->itlb[i].tag & (uint64_t)~0x1fffULL,
! 643: env->itlb[i].tte & (uint64_t)0x1ffffffe000ULL,
1.1.1.4 root 644: mask,
1.1.1.7 ! root 645: env->itlb[i].tte & 0x4? "priv": "user",
! 646: env->itlb[i].tte & 0x40? "locked": "unlocked",
! 647: env->itlb[i].tag & (uint64_t)0x1fffULL,
! 648: TTE_IS_GLOBAL(env->itlb[i].tag)? "global" : "local");
1.1.1.4 root 649: }
650: }
1.1 root 651: }
652: }
1.1.1.2 root 653: #endif /* DEBUG_MMU */
654:
655: #endif /* TARGET_SPARC64 */
656: #endif /* !CONFIG_USER_ONLY */
657:
1.1.1.5 root 658:
659: #if defined(CONFIG_USER_ONLY)
660: target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
1.1.1.2 root 661: {
1.1.1.5 root 662: return addr;
1.1.1.2 root 663: }
1.1.1.4 root 664:
1.1.1.5 root 665: #else
666: target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
667: {
668: target_phys_addr_t phys_addr;
669: int prot, access_index;
670:
671: if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2,
672: MMU_KERNEL_IDX) != 0)
673: if (get_physical_address(env, &phys_addr, &prot, &access_index, addr,
674: 0, MMU_KERNEL_IDX) != 0)
675: return -1;
676: if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED)
677: return -1;
678: return phys_addr;
679: }
1.1.1.4 root 680: #endif
681:
1.1.1.5 root 682: void cpu_reset(CPUSPARCState *env)
1.1.1.4 root 683: {
1.1.1.5 root 684: if (qemu_loglevel_mask(CPU_LOG_RESET)) {
685: qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
686: log_cpu_state(env, 0);
687: }
688:
689: tlb_flush(env, 1);
690: env->cwp = 0;
1.1.1.6 root 691: #ifndef TARGET_SPARC64
1.1.1.5 root 692: env->wim = 1;
1.1.1.6 root 693: #endif
1.1.1.5 root 694: env->regwptr = env->regbase + (env->cwp * 16);
1.1.1.7 ! root 695: CC_OP = CC_OP_FLAGS;
1.1.1.5 root 696: #if defined(CONFIG_USER_ONLY)
697: #ifdef TARGET_SPARC64
698: env->cleanwin = env->nwindows - 2;
699: env->cansave = env->nwindows - 2;
700: env->pstate = PS_RMO | PS_PEF | PS_IE;
701: env->asi = 0x82; // Primary no-fault
702: #endif
703: #else
1.1.1.6 root 704: #if !defined(TARGET_SPARC64)
1.1.1.5 root 705: env->psret = 0;
1.1.1.6 root 706: #endif
1.1.1.5 root 707: env->psrs = 1;
708: env->psrps = 1;
709: #ifdef TARGET_SPARC64
1.1.1.7 ! root 710: env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
1.1.1.5 root 711: env->hpstate = HS_PRIV;
1.1.1.7 ! root 712: env->tl = env->maxtl;
! 713: cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
1.1.1.5 root 714: env->lsu = 0;
715: #else
716: env->mmuregs[0] &= ~(MMU_E | MMU_NF);
717: env->mmuregs[0] |= env->def->mmu_bm;
718: #endif
719: env->pc = 0;
720: env->npc = env->pc + 4;
1.1.1.4 root 721: #endif
722: }
723:
1.1.1.5 root 724: static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
1.1.1.4 root 725: {
1.1.1.5 root 726: sparc_def_t def1, *def = &def1;
727:
728: if (cpu_sparc_find_by_name(def, cpu_model) < 0)
729: return -1;
730:
731: env->def = qemu_mallocz(sizeof(*def));
732: memcpy(env->def, def, sizeof(*def));
733: #if defined(CONFIG_USER_ONLY)
734: if ((env->def->features & CPU_FEATURE_FLOAT))
735: env->def->features |= CPU_FEATURE_FLOAT128;
736: #endif
737: env->cpu_model_str = cpu_model;
738: env->version = def->iu_version;
739: env->fsr = def->fpu_version;
740: env->nwindows = def->nwindows;
741: #if !defined(TARGET_SPARC64)
742: env->mmuregs[0] |= def->mmu_version;
743: cpu_sparc_set_id(env, 0);
744: env->mxccregs[7] |= def->mxcc_version;
1.1.1.4 root 745: #else
1.1.1.5 root 746: env->mmu_version = def->mmu_version;
747: env->maxtl = def->maxtl;
748: env->version |= def->maxtl << 8;
749: env->version |= def->nwindows - 1;
750: #endif
1.1.1.4 root 751: return 0;
1.1.1.5 root 752: }
753:
754: static void cpu_sparc_close(CPUSPARCState *env)
755: {
756: free(env->def);
757: free(env);
758: }
759:
760: CPUSPARCState *cpu_sparc_init(const char *cpu_model)
761: {
762: CPUSPARCState *env;
763:
764: env = qemu_mallocz(sizeof(CPUSPARCState));
765: cpu_exec_init(env);
766:
767: gen_intermediate_code_init(env);
768:
769: if (cpu_sparc_register(env, cpu_model) < 0) {
770: cpu_sparc_close(env);
771: return NULL;
772: }
1.1.1.6 root 773: qemu_init_vcpu(env);
1.1.1.5 root 774:
775: return env;
776: }
777:
778: void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
779: {
780: #if !defined(TARGET_SPARC64)
781: env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
782: #endif
783: }
784:
785: static const sparc_def_t sparc_defs[] = {
786: #ifdef TARGET_SPARC64
787: {
788: .name = "Fujitsu Sparc64",
789: .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
790: .fpu_version = 0x00000000,
791: .mmu_version = mmu_us_12,
792: .nwindows = 4,
793: .maxtl = 4,
794: .features = CPU_DEFAULT_FEATURES,
795: },
796: {
797: .name = "Fujitsu Sparc64 III",
798: .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
799: .fpu_version = 0x00000000,
800: .mmu_version = mmu_us_12,
801: .nwindows = 5,
802: .maxtl = 4,
803: .features = CPU_DEFAULT_FEATURES,
804: },
805: {
806: .name = "Fujitsu Sparc64 IV",
807: .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
808: .fpu_version = 0x00000000,
809: .mmu_version = mmu_us_12,
810: .nwindows = 8,
811: .maxtl = 5,
812: .features = CPU_DEFAULT_FEATURES,
813: },
814: {
815: .name = "Fujitsu Sparc64 V",
816: .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
817: .fpu_version = 0x00000000,
818: .mmu_version = mmu_us_12,
819: .nwindows = 8,
820: .maxtl = 5,
821: .features = CPU_DEFAULT_FEATURES,
822: },
823: {
824: .name = "TI UltraSparc I",
825: .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
826: .fpu_version = 0x00000000,
827: .mmu_version = mmu_us_12,
828: .nwindows = 8,
829: .maxtl = 5,
830: .features = CPU_DEFAULT_FEATURES,
831: },
832: {
833: .name = "TI UltraSparc II",
834: .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
835: .fpu_version = 0x00000000,
836: .mmu_version = mmu_us_12,
837: .nwindows = 8,
838: .maxtl = 5,
839: .features = CPU_DEFAULT_FEATURES,
840: },
841: {
842: .name = "TI UltraSparc IIi",
843: .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
844: .fpu_version = 0x00000000,
845: .mmu_version = mmu_us_12,
846: .nwindows = 8,
847: .maxtl = 5,
848: .features = CPU_DEFAULT_FEATURES,
849: },
850: {
851: .name = "TI UltraSparc IIe",
852: .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
853: .fpu_version = 0x00000000,
854: .mmu_version = mmu_us_12,
855: .nwindows = 8,
856: .maxtl = 5,
857: .features = CPU_DEFAULT_FEATURES,
858: },
859: {
860: .name = "Sun UltraSparc III",
861: .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
862: .fpu_version = 0x00000000,
863: .mmu_version = mmu_us_12,
864: .nwindows = 8,
865: .maxtl = 5,
866: .features = CPU_DEFAULT_FEATURES,
867: },
868: {
869: .name = "Sun UltraSparc III Cu",
870: .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
871: .fpu_version = 0x00000000,
872: .mmu_version = mmu_us_3,
873: .nwindows = 8,
874: .maxtl = 5,
875: .features = CPU_DEFAULT_FEATURES,
876: },
877: {
878: .name = "Sun UltraSparc IIIi",
879: .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
880: .fpu_version = 0x00000000,
881: .mmu_version = mmu_us_12,
882: .nwindows = 8,
883: .maxtl = 5,
884: .features = CPU_DEFAULT_FEATURES,
885: },
886: {
887: .name = "Sun UltraSparc IV",
888: .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
889: .fpu_version = 0x00000000,
890: .mmu_version = mmu_us_4,
891: .nwindows = 8,
892: .maxtl = 5,
893: .features = CPU_DEFAULT_FEATURES,
894: },
895: {
896: .name = "Sun UltraSparc IV+",
897: .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
898: .fpu_version = 0x00000000,
899: .mmu_version = mmu_us_12,
900: .nwindows = 8,
901: .maxtl = 5,
902: .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
903: },
904: {
905: .name = "Sun UltraSparc IIIi+",
906: .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
907: .fpu_version = 0x00000000,
908: .mmu_version = mmu_us_3,
909: .nwindows = 8,
910: .maxtl = 5,
911: .features = CPU_DEFAULT_FEATURES,
912: },
913: {
914: .name = "Sun UltraSparc T1",
915: // defined in sparc_ifu_fdp.v and ctu.h
916: .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
917: .fpu_version = 0x00000000,
918: .mmu_version = mmu_sun4v,
919: .nwindows = 8,
920: .maxtl = 6,
921: .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
922: | CPU_FEATURE_GL,
923: },
924: {
925: .name = "Sun UltraSparc T2",
926: // defined in tlu_asi_ctl.v and n2_revid_cust.v
927: .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
928: .fpu_version = 0x00000000,
929: .mmu_version = mmu_sun4v,
930: .nwindows = 8,
931: .maxtl = 6,
932: .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
933: | CPU_FEATURE_GL,
934: },
935: {
936: .name = "NEC UltraSparc I",
937: .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
938: .fpu_version = 0x00000000,
939: .mmu_version = mmu_us_12,
940: .nwindows = 8,
941: .maxtl = 5,
942: .features = CPU_DEFAULT_FEATURES,
943: },
944: #else
945: {
946: .name = "Fujitsu MB86900",
947: .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
948: .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
949: .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
950: .mmu_bm = 0x00004000,
951: .mmu_ctpr_mask = 0x007ffff0,
952: .mmu_cxr_mask = 0x0000003f,
953: .mmu_sfsr_mask = 0xffffffff,
954: .mmu_trcr_mask = 0xffffffff,
955: .nwindows = 7,
956: .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
957: },
958: {
959: .name = "Fujitsu MB86904",
960: .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
961: .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
962: .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
963: .mmu_bm = 0x00004000,
964: .mmu_ctpr_mask = 0x00ffffc0,
965: .mmu_cxr_mask = 0x000000ff,
966: .mmu_sfsr_mask = 0x00016fff,
967: .mmu_trcr_mask = 0x00ffffff,
968: .nwindows = 8,
969: .features = CPU_DEFAULT_FEATURES,
970: },
971: {
972: .name = "Fujitsu MB86907",
973: .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
974: .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
975: .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
976: .mmu_bm = 0x00004000,
977: .mmu_ctpr_mask = 0xffffffc0,
978: .mmu_cxr_mask = 0x000000ff,
979: .mmu_sfsr_mask = 0x00016fff,
980: .mmu_trcr_mask = 0xffffffff,
981: .nwindows = 8,
982: .features = CPU_DEFAULT_FEATURES,
983: },
984: {
985: .name = "LSI L64811",
986: .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
987: .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
988: .mmu_version = 0x10 << 24,
989: .mmu_bm = 0x00004000,
990: .mmu_ctpr_mask = 0x007ffff0,
991: .mmu_cxr_mask = 0x0000003f,
992: .mmu_sfsr_mask = 0xffffffff,
993: .mmu_trcr_mask = 0xffffffff,
994: .nwindows = 8,
995: .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
996: CPU_FEATURE_FSMULD,
997: },
998: {
999: .name = "Cypress CY7C601",
1000: .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
1001: .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
1002: .mmu_version = 0x10 << 24,
1003: .mmu_bm = 0x00004000,
1004: .mmu_ctpr_mask = 0x007ffff0,
1005: .mmu_cxr_mask = 0x0000003f,
1006: .mmu_sfsr_mask = 0xffffffff,
1007: .mmu_trcr_mask = 0xffffffff,
1008: .nwindows = 8,
1009: .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1010: CPU_FEATURE_FSMULD,
1011: },
1012: {
1013: .name = "Cypress CY7C611",
1014: .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
1015: .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
1016: .mmu_version = 0x10 << 24,
1017: .mmu_bm = 0x00004000,
1018: .mmu_ctpr_mask = 0x007ffff0,
1019: .mmu_cxr_mask = 0x0000003f,
1020: .mmu_sfsr_mask = 0xffffffff,
1021: .mmu_trcr_mask = 0xffffffff,
1022: .nwindows = 8,
1023: .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1024: CPU_FEATURE_FSMULD,
1025: },
1026: {
1027: .name = "TI MicroSparc I",
1028: .iu_version = 0x41000000,
1029: .fpu_version = 4 << 17,
1030: .mmu_version = 0x41000000,
1031: .mmu_bm = 0x00004000,
1032: .mmu_ctpr_mask = 0x007ffff0,
1033: .mmu_cxr_mask = 0x0000003f,
1034: .mmu_sfsr_mask = 0x00016fff,
1035: .mmu_trcr_mask = 0x0000003f,
1036: .nwindows = 7,
1037: .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
1038: CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
1039: CPU_FEATURE_FMUL,
1040: },
1041: {
1042: .name = "TI MicroSparc II",
1043: .iu_version = 0x42000000,
1044: .fpu_version = 4 << 17,
1045: .mmu_version = 0x02000000,
1046: .mmu_bm = 0x00004000,
1047: .mmu_ctpr_mask = 0x00ffffc0,
1048: .mmu_cxr_mask = 0x000000ff,
1049: .mmu_sfsr_mask = 0x00016fff,
1050: .mmu_trcr_mask = 0x00ffffff,
1051: .nwindows = 8,
1052: .features = CPU_DEFAULT_FEATURES,
1053: },
1054: {
1055: .name = "TI MicroSparc IIep",
1056: .iu_version = 0x42000000,
1057: .fpu_version = 4 << 17,
1058: .mmu_version = 0x04000000,
1059: .mmu_bm = 0x00004000,
1060: .mmu_ctpr_mask = 0x00ffffc0,
1061: .mmu_cxr_mask = 0x000000ff,
1062: .mmu_sfsr_mask = 0x00016bff,
1063: .mmu_trcr_mask = 0x00ffffff,
1064: .nwindows = 8,
1065: .features = CPU_DEFAULT_FEATURES,
1066: },
1067: {
1068: .name = "TI SuperSparc 40", // STP1020NPGA
1069: .iu_version = 0x41000000, // SuperSPARC 2.x
1070: .fpu_version = 0 << 17,
1071: .mmu_version = 0x00000800, // SuperSPARC 2.x, no MXCC
1072: .mmu_bm = 0x00002000,
1073: .mmu_ctpr_mask = 0xffffffc0,
1074: .mmu_cxr_mask = 0x0000ffff,
1075: .mmu_sfsr_mask = 0xffffffff,
1076: .mmu_trcr_mask = 0xffffffff,
1077: .nwindows = 8,
1078: .features = CPU_DEFAULT_FEATURES,
1079: },
1080: {
1081: .name = "TI SuperSparc 50", // STP1020PGA
1082: .iu_version = 0x40000000, // SuperSPARC 3.x
1083: .fpu_version = 0 << 17,
1084: .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
1085: .mmu_bm = 0x00002000,
1086: .mmu_ctpr_mask = 0xffffffc0,
1087: .mmu_cxr_mask = 0x0000ffff,
1088: .mmu_sfsr_mask = 0xffffffff,
1089: .mmu_trcr_mask = 0xffffffff,
1090: .nwindows = 8,
1091: .features = CPU_DEFAULT_FEATURES,
1092: },
1093: {
1094: .name = "TI SuperSparc 51",
1095: .iu_version = 0x40000000, // SuperSPARC 3.x
1096: .fpu_version = 0 << 17,
1097: .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
1098: .mmu_bm = 0x00002000,
1099: .mmu_ctpr_mask = 0xffffffc0,
1100: .mmu_cxr_mask = 0x0000ffff,
1101: .mmu_sfsr_mask = 0xffffffff,
1102: .mmu_trcr_mask = 0xffffffff,
1103: .mxcc_version = 0x00000104,
1104: .nwindows = 8,
1105: .features = CPU_DEFAULT_FEATURES,
1106: },
1107: {
1108: .name = "TI SuperSparc 60", // STP1020APGA
1109: .iu_version = 0x40000000, // SuperSPARC 3.x
1110: .fpu_version = 0 << 17,
1111: .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
1112: .mmu_bm = 0x00002000,
1113: .mmu_ctpr_mask = 0xffffffc0,
1114: .mmu_cxr_mask = 0x0000ffff,
1115: .mmu_sfsr_mask = 0xffffffff,
1116: .mmu_trcr_mask = 0xffffffff,
1117: .nwindows = 8,
1118: .features = CPU_DEFAULT_FEATURES,
1119: },
1120: {
1121: .name = "TI SuperSparc 61",
1122: .iu_version = 0x44000000, // SuperSPARC 3.x
1123: .fpu_version = 0 << 17,
1124: .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
1125: .mmu_bm = 0x00002000,
1126: .mmu_ctpr_mask = 0xffffffc0,
1127: .mmu_cxr_mask = 0x0000ffff,
1128: .mmu_sfsr_mask = 0xffffffff,
1129: .mmu_trcr_mask = 0xffffffff,
1130: .mxcc_version = 0x00000104,
1131: .nwindows = 8,
1132: .features = CPU_DEFAULT_FEATURES,
1133: },
1134: {
1135: .name = "TI SuperSparc II",
1136: .iu_version = 0x40000000, // SuperSPARC II 1.x
1137: .fpu_version = 0 << 17,
1138: .mmu_version = 0x08000000, // SuperSPARC II 1.x, MXCC
1139: .mmu_bm = 0x00002000,
1140: .mmu_ctpr_mask = 0xffffffc0,
1141: .mmu_cxr_mask = 0x0000ffff,
1142: .mmu_sfsr_mask = 0xffffffff,
1143: .mmu_trcr_mask = 0xffffffff,
1144: .mxcc_version = 0x00000104,
1145: .nwindows = 8,
1146: .features = CPU_DEFAULT_FEATURES,
1147: },
1148: {
1149: .name = "Ross RT625",
1150: .iu_version = 0x1e000000,
1151: .fpu_version = 1 << 17,
1152: .mmu_version = 0x1e000000,
1153: .mmu_bm = 0x00004000,
1154: .mmu_ctpr_mask = 0x007ffff0,
1155: .mmu_cxr_mask = 0x0000003f,
1156: .mmu_sfsr_mask = 0xffffffff,
1157: .mmu_trcr_mask = 0xffffffff,
1158: .nwindows = 8,
1159: .features = CPU_DEFAULT_FEATURES,
1160: },
1161: {
1162: .name = "Ross RT620",
1163: .iu_version = 0x1f000000,
1164: .fpu_version = 1 << 17,
1165: .mmu_version = 0x1f000000,
1166: .mmu_bm = 0x00004000,
1167: .mmu_ctpr_mask = 0x007ffff0,
1168: .mmu_cxr_mask = 0x0000003f,
1169: .mmu_sfsr_mask = 0xffffffff,
1170: .mmu_trcr_mask = 0xffffffff,
1171: .nwindows = 8,
1172: .features = CPU_DEFAULT_FEATURES,
1173: },
1174: {
1175: .name = "BIT B5010",
1176: .iu_version = 0x20000000,
1177: .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
1178: .mmu_version = 0x20000000,
1179: .mmu_bm = 0x00004000,
1180: .mmu_ctpr_mask = 0x007ffff0,
1181: .mmu_cxr_mask = 0x0000003f,
1182: .mmu_sfsr_mask = 0xffffffff,
1183: .mmu_trcr_mask = 0xffffffff,
1184: .nwindows = 8,
1185: .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1186: CPU_FEATURE_FSMULD,
1187: },
1188: {
1189: .name = "Matsushita MN10501",
1190: .iu_version = 0x50000000,
1191: .fpu_version = 0 << 17,
1192: .mmu_version = 0x50000000,
1193: .mmu_bm = 0x00004000,
1194: .mmu_ctpr_mask = 0x007ffff0,
1195: .mmu_cxr_mask = 0x0000003f,
1196: .mmu_sfsr_mask = 0xffffffff,
1197: .mmu_trcr_mask = 0xffffffff,
1198: .nwindows = 8,
1199: .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
1200: CPU_FEATURE_FSMULD,
1201: },
1202: {
1203: .name = "Weitek W8601",
1204: .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
1205: .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
1206: .mmu_version = 0x10 << 24,
1207: .mmu_bm = 0x00004000,
1208: .mmu_ctpr_mask = 0x007ffff0,
1209: .mmu_cxr_mask = 0x0000003f,
1210: .mmu_sfsr_mask = 0xffffffff,
1211: .mmu_trcr_mask = 0xffffffff,
1212: .nwindows = 8,
1213: .features = CPU_DEFAULT_FEATURES,
1214: },
1215: {
1216: .name = "LEON2",
1217: .iu_version = 0xf2000000,
1218: .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1219: .mmu_version = 0xf2000000,
1220: .mmu_bm = 0x00004000,
1221: .mmu_ctpr_mask = 0x007ffff0,
1222: .mmu_cxr_mask = 0x0000003f,
1223: .mmu_sfsr_mask = 0xffffffff,
1224: .mmu_trcr_mask = 0xffffffff,
1225: .nwindows = 8,
1226: .features = CPU_DEFAULT_FEATURES,
1227: },
1228: {
1229: .name = "LEON3",
1230: .iu_version = 0xf3000000,
1231: .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1232: .mmu_version = 0xf3000000,
1233: .mmu_bm = 0x00004000,
1234: .mmu_ctpr_mask = 0x007ffff0,
1235: .mmu_cxr_mask = 0x0000003f,
1236: .mmu_sfsr_mask = 0xffffffff,
1237: .mmu_trcr_mask = 0xffffffff,
1238: .nwindows = 8,
1239: .features = CPU_DEFAULT_FEATURES,
1240: },
1.1.1.4 root 1241: #endif
1.1.1.5 root 1242: };
1243:
1244: static const char * const feature_name[] = {
1245: "float",
1246: "float128",
1247: "swap",
1248: "mul",
1249: "div",
1250: "flush",
1251: "fsqrt",
1252: "fmul",
1253: "vis1",
1254: "vis2",
1255: "fsmuld",
1256: "hypv",
1257: "cmt",
1258: "gl",
1259: };
1260:
1261: static void print_features(FILE *f,
1262: int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
1263: uint32_t features, const char *prefix)
1264: {
1265: unsigned int i;
1266:
1267: for (i = 0; i < ARRAY_SIZE(feature_name); i++)
1268: if (feature_name[i] && (features & (1 << i))) {
1269: if (prefix)
1270: (*cpu_fprintf)(f, "%s", prefix);
1271: (*cpu_fprintf)(f, "%s ", feature_name[i]);
1272: }
1.1.1.4 root 1273: }
1274:
1.1.1.5 root 1275: static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
1.1.1.4 root 1276: {
1.1.1.5 root 1277: unsigned int i;
1278:
1279: for (i = 0; i < ARRAY_SIZE(feature_name); i++)
1280: if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
1281: *features |= 1 << i;
1282: return;
1283: }
1284: fprintf(stderr, "CPU feature %s not found\n", flagname);
1285: }
1286:
1287: static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
1288: {
1289: unsigned int i;
1290: const sparc_def_t *def = NULL;
1291: char *s = strdup(cpu_model);
1292: char *featurestr, *name = strtok(s, ",");
1293: uint32_t plus_features = 0;
1294: uint32_t minus_features = 0;
1295: long long iu_version;
1296: uint32_t fpu_version, mmu_version, nwindows;
1297:
1298: for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
1299: if (strcasecmp(name, sparc_defs[i].name) == 0) {
1300: def = &sparc_defs[i];
1301: }
1302: }
1303: if (!def)
1304: goto error;
1305: memcpy(cpu_def, def, sizeof(*def));
1306:
1307: featurestr = strtok(NULL, ",");
1308: while (featurestr) {
1309: char *val;
1310:
1311: if (featurestr[0] == '+') {
1312: add_flagname_to_bitmaps(featurestr + 1, &plus_features);
1313: } else if (featurestr[0] == '-') {
1314: add_flagname_to_bitmaps(featurestr + 1, &minus_features);
1315: } else if ((val = strchr(featurestr, '='))) {
1316: *val = 0; val++;
1317: if (!strcmp(featurestr, "iu_version")) {
1318: char *err;
1319:
1320: iu_version = strtoll(val, &err, 0);
1321: if (!*val || *err) {
1322: fprintf(stderr, "bad numerical value %s\n", val);
1323: goto error;
1324: }
1325: cpu_def->iu_version = iu_version;
1326: #ifdef DEBUG_FEATURES
1327: fprintf(stderr, "iu_version %llx\n", iu_version);
1328: #endif
1329: } else if (!strcmp(featurestr, "fpu_version")) {
1330: char *err;
1331:
1332: fpu_version = strtol(val, &err, 0);
1333: if (!*val || *err) {
1334: fprintf(stderr, "bad numerical value %s\n", val);
1335: goto error;
1336: }
1337: cpu_def->fpu_version = fpu_version;
1338: #ifdef DEBUG_FEATURES
1.1.1.6 root 1339: fprintf(stderr, "fpu_version %x\n", fpu_version);
1.1.1.5 root 1340: #endif
1341: } else if (!strcmp(featurestr, "mmu_version")) {
1342: char *err;
1343:
1344: mmu_version = strtol(val, &err, 0);
1345: if (!*val || *err) {
1346: fprintf(stderr, "bad numerical value %s\n", val);
1347: goto error;
1348: }
1349: cpu_def->mmu_version = mmu_version;
1350: #ifdef DEBUG_FEATURES
1.1.1.6 root 1351: fprintf(stderr, "mmu_version %x\n", mmu_version);
1.1.1.5 root 1352: #endif
1353: } else if (!strcmp(featurestr, "nwindows")) {
1354: char *err;
1355:
1356: nwindows = strtol(val, &err, 0);
1357: if (!*val || *err || nwindows > MAX_NWINDOWS ||
1358: nwindows < MIN_NWINDOWS) {
1359: fprintf(stderr, "bad numerical value %s\n", val);
1360: goto error;
1361: }
1362: cpu_def->nwindows = nwindows;
1363: #ifdef DEBUG_FEATURES
1364: fprintf(stderr, "nwindows %d\n", nwindows);
1.1.1.4 root 1365: #endif
1.1.1.5 root 1366: } else {
1367: fprintf(stderr, "unrecognized feature %s\n", featurestr);
1368: goto error;
1369: }
1370: } else {
1371: fprintf(stderr, "feature string `%s' not in format "
1372: "(+feature|-feature|feature=xyz)\n", featurestr);
1373: goto error;
1374: }
1375: featurestr = strtok(NULL, ",");
1376: }
1377: cpu_def->features |= plus_features;
1378: cpu_def->features &= ~minus_features;
1379: #ifdef DEBUG_FEATURES
1380: print_features(stderr, fprintf, cpu_def->features, NULL);
1381: #endif
1382: free(s);
1383: return 0;
1384:
1385: error:
1386: free(s);
1387: return -1;
1.1.1.4 root 1388: }
1.1.1.5 root 1389:
1390: void sparc_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
1391: {
1392: unsigned int i;
1393:
1394: for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
1395: (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x NWINS %d ",
1396: sparc_defs[i].name,
1397: sparc_defs[i].iu_version,
1398: sparc_defs[i].fpu_version,
1399: sparc_defs[i].mmu_version,
1400: sparc_defs[i].nwindows);
1401: print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
1402: ~sparc_defs[i].features, "-");
1403: print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
1404: sparc_defs[i].features, "+");
1405: (*cpu_fprintf)(f, "\n");
1406: }
1407: (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
1408: print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
1409: (*cpu_fprintf)(f, "\n");
1410: (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
1411: print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
1412: (*cpu_fprintf)(f, "\n");
1413: (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
1414: "fpu_version mmu_version nwindows\n");
1415: }
1416:
1417: void cpu_dump_state(CPUState *env, FILE *f,
1418: int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
1419: int flags)
1420: {
1421: int i, x;
1422:
1423: cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc,
1424: env->npc);
1425: cpu_fprintf(f, "General Registers:\n");
1426: for (i = 0; i < 4; i++)
1427: cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]);
1428: cpu_fprintf(f, "\n");
1429: for (; i < 8; i++)
1430: cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]);
1431: cpu_fprintf(f, "\nCurrent Register Window:\n");
1432: for (x = 0; x < 3; x++) {
1433: for (i = 0; i < 4; i++)
1434: cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t",
1435: (x == 0 ? 'o' : (x == 1 ? 'l' : 'i')), i,
1436: env->regwptr[i + x * 8]);
1437: cpu_fprintf(f, "\n");
1438: for (; i < 8; i++)
1439: cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t",
1440: (x == 0 ? 'o' : x == 1 ? 'l' : 'i'), i,
1441: env->regwptr[i + x * 8]);
1442: cpu_fprintf(f, "\n");
1443: }
1444: cpu_fprintf(f, "\nFloating Point Registers:\n");
1445: for (i = 0; i < 32; i++) {
1446: if ((i & 3) == 0)
1447: cpu_fprintf(f, "%%f%02d:", i);
1448: cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
1449: if ((i & 3) == 3)
1450: cpu_fprintf(f, "\n");
1451: }
1452: #ifdef TARGET_SPARC64
1453: cpu_fprintf(f, "pstate: 0x%08x ccr: 0x%02x asi: 0x%02x tl: %d fprs: %d\n",
1454: env->pstate, GET_CCR(env), env->asi, env->tl, env->fprs);
1455: cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate %d "
1456: "cleanwin %d cwp %d\n",
1457: env->cansave, env->canrestore, env->otherwin, env->wstate,
1458: env->cleanwin, env->nwindows - 1 - env->cwp);
1459: #else
1.1.1.6 root 1460:
1461: #define GET_FLAG(a,b) ((env->psr & a)?b:'-')
1462:
1.1.1.5 root 1463: cpu_fprintf(f, "psr: 0x%08x -> %c%c%c%c %c%c%c wim: 0x%08x\n",
1464: GET_PSR(env), GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'),
1465: GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'),
1466: env->psrs?'S':'-', env->psrps?'P':'-',
1467: env->psret?'E':'-', env->wim);
1.1.1.4 root 1468: #endif
1.1.1.5 root 1469: cpu_fprintf(f, "fsr: 0x%08x\n", env->fsr);
1470: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.