|
|
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:
25: #include "cpu.h"
1.1.1.5 root 26: #include "qemu-common.h"
1.1 root 27:
28: //#define DEBUG_MMU
1.1.1.5 root 29: //#define DEBUG_FEATURES
30:
1.1.1.8 root 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
37:
1.1.1.5 root 38: static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
1.1 root 39:
40: /* Sparc MMU emulation */
41:
1.1.1.4 root 42: #if defined(CONFIG_USER_ONLY)
1.1 root 43:
1.1.1.5 root 44: int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
1.1.1.4 root 45: int mmu_idx, int is_softmmu)
1.1 root 46: {
47: if (rw & 2)
1.1.1.5 root 48: env1->exception_index = TT_TFAULT;
1.1 root 49: else
1.1.1.5 root 50: env1->exception_index = TT_DFAULT;
1.1 root 51: return 1;
52: }
53:
54: #else
55:
56: #ifndef TARGET_SPARC64
57: /*
58: * Sparc V8 Reference MMU (SRMMU)
59: */
60: static const int access_table[8][8] = {
1.1.1.5 root 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 }
1.1 root 69: };
70:
1.1.1.2 root 71: static const int perm_table[2][8] = {
72: {
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
81: },
82: {
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,
89: 0,
90: 0,
91: }
1.1 root 92: };
93:
1.1.1.5 root 94: static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
95: int *prot, int *access_index,
1.1.1.8 root 96: target_ulong address, int rw, int mmu_idx,
97: target_ulong *page_size)
1.1 root 98: {
99: int access_perms = 0;
100: target_phys_addr_t pde_ptr;
101: uint32_t pde;
1.1.1.4 root 102: int error_code = 0, is_dirty, is_user;
1.1 root 103: unsigned long page_offset;
104:
1.1.1.4 root 105: is_user = mmu_idx == MMU_USER_IDX;
106:
1.1 root 107: if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
1.1.1.8 root 108: *page_size = TARGET_PAGE_SIZE;
1.1.1.4 root 109: // Boot mode: instruction fetches are taken from PROM
1.1.1.5 root 110: if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
1.1.1.4 root 111: *physical = env->prom_addr | (address & 0x7ffffULL);
112: *prot = PAGE_READ | PAGE_EXEC;
113: return 0;
114: }
115: *physical = address;
1.1.1.2 root 116: *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
1.1 root 117: return 0;
118: }
119:
120: *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
1.1.1.4 root 121: *physical = 0xffffffffffff0000ULL;
1.1 root 122:
123: /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
124: /* Context base + context number */
1.1.1.5 root 125: pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
1.1 root 126: pde = ldl_phys(pde_ptr);
127:
128: /* Ctx pde */
129: switch (pde & PTE_ENTRYTYPE_MASK) {
130: default:
131: case 0: /* Invalid */
1.1.1.4 root 132: return 1 << 2;
1.1 root 133: case 2: /* L0 PTE, maybe should not happen? */
134: case 3: /* Reserved */
135: return 4 << 2;
136: case 1: /* L0 PDE */
1.1.1.4 root 137: pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
1.1 root 138: pde = ldl_phys(pde_ptr);
139:
1.1.1.4 root 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);
1.1 root 148: pde = ldl_phys(pde_ptr);
149:
1.1.1.4 root 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);
1.1 root 158: pde = ldl_phys(pde_ptr);
159:
1.1.1.4 root 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 */
1.1.1.5 root 168: page_offset = (address & TARGET_PAGE_MASK) &
169: (TARGET_PAGE_SIZE - 1);
1.1.1.4 root 170: }
1.1.1.8 root 171: *page_size = TARGET_PAGE_SIZE;
1.1.1.4 root 172: break;
173: case 2: /* L2 PTE */
174: page_offset = address & 0x3ffff;
1.1.1.8 root 175: *page_size = 0x40000;
1.1.1.4 root 176: }
177: break;
178: case 2: /* L1 PTE */
179: page_offset = address & 0xffffff;
1.1.1.8 root 180: *page_size = 0x1000000;
1.1.1.4 root 181: }
1.1 root 182: }
183:
1.1.1.8 root 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;
189:
1.1 root 190: /* update page modified and dirty bits */
191: is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
192: if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
1.1.1.4 root 193: pde |= PG_ACCESSED_MASK;
194: if (is_dirty)
195: pde |= PG_MODIFIED_MASK;
1.1 root 196: stl_phys_notdirty(pde_ptr, pde);
197: }
198:
199: /* the page can be put in the TLB */
1.1.1.2 root 200: *prot = perm_table[is_user][access_perms];
201: if (!(pde & PG_MODIFIED_MASK)) {
1.1 root 202: /* only set write access if already dirty... otherwise wait
203: for dirty access */
1.1.1.2 root 204: *prot &= ~PAGE_WRITE;
1.1 root 205: }
206:
207: /* Even if large ptes, we map only one 4KB page in the cache to
208: avoid filling it too fast */
1.1.1.4 root 209: *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
1.1 root 210: return error_code;
211: }
212:
213: /* Perform address translation */
214: int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
1.1.1.4 root 215: int mmu_idx, int is_softmmu)
1.1 root 216: {
217: target_phys_addr_t paddr;
1.1.1.4 root 218: target_ulong vaddr;
1.1.1.8 root 219: target_ulong page_size;
220: int error_code = 0, prot, access_index;
1.1 root 221:
1.1.1.5 root 222: error_code = get_physical_address(env, &paddr, &prot, &access_index,
1.1.1.8 root 223: address, rw, mmu_idx, &page_size);
1.1 root 224: if (error_code == 0) {
1.1.1.4 root 225: vaddr = address & TARGET_PAGE_MASK;
226: paddr &= TARGET_PAGE_MASK;
1.1.1.2 root 227: #ifdef DEBUG_MMU
1.1.1.4 root 228: printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
229: TARGET_FMT_lx "\n", address, paddr, vaddr);
1.1.1.2 root 230: #endif
1.1.1.8 root 231: tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
232: return 0;
1.1 root 233: }
234:
235: if (env->mmuregs[3]) /* Fault status register */
1.1.1.4 root 236: env->mmuregs[3] = 1; /* overflow (not read before another fault) */
1.1 root 237: env->mmuregs[3] |= (access_index << 5) | error_code | 2;
238: env->mmuregs[4] = address; /* Fault address register */
239:
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.
1.1.1.4 root 245: vaddr = address & TARGET_PAGE_MASK;
1.1.1.2 root 246: prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
1.1.1.8 root 247: tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
248: return 0;
1.1 root 249: } else {
250: if (rw & 2)
251: env->exception_index = TT_TFAULT;
252: else
253: env->exception_index = TT_DFAULT;
254: return 1;
255: }
256: }
1.1.1.2 root 257:
258: target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
259: {
260: target_phys_addr_t pde_ptr;
261: uint32_t pde;
262:
263: /* Context base + context number */
1.1.1.4 root 264: pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
265: (env->mmuregs[2] << 2);
1.1.1.2 root 266: pde = ldl_phys(pde_ptr);
267:
268: switch (pde & PTE_ENTRYTYPE_MASK) {
269: default:
270: case 0: /* Invalid */
271: case 2: /* PTE, maybe should not happen? */
272: case 3: /* Reserved */
1.1.1.4 root 273: return 0;
1.1.1.2 root 274: case 1: /* L1 PDE */
1.1.1.4 root 275: if (mmulev == 3)
276: return pde;
277: pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
1.1.1.2 root 278: pde = ldl_phys(pde_ptr);
279:
1.1.1.4 root 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);
1.1.1.2 root 291: pde = ldl_phys(pde_ptr);
292:
1.1.1.4 root 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);
1.1.1.2 root 304: pde = ldl_phys(pde_ptr);
305:
1.1.1.4 root 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;
314: }
315: }
316: }
1.1.1.2 root 317: }
318: return 0;
319: }
320:
1.1.1.9 root 321: void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
1.1.1.2 root 322: {
1.1.1.4 root 323: target_ulong va, va1, va2;
324: unsigned int n, m, o;
325: target_phys_addr_t pde_ptr, pa;
1.1.1.2 root 326: uint32_t pde;
327:
328: pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
329: pde = ldl_phys(pde_ptr);
1.1.1.9 root 330: (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
331: (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
1.1.1.2 root 332: for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
1.1.1.4 root 333: pde = mmu_probe(env, va, 2);
334: if (pde) {
335: pa = cpu_get_phys_page_debug(env, va);
1.1.1.9 root 336: (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
337: " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
1.1.1.4 root 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);
1.1.1.9 root 342: (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
343: TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
344: va1, pa, pde);
1.1.1.4 root 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);
1.1.1.9 root 349: (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
350: TARGET_FMT_plx " PTE: "
351: TARGET_FMT_lx "\n",
352: va2, pa, pde);
1.1.1.4 root 353: }
354: }
355: }
356: }
357: }
1.1.1.2 root 358: }
359: }
360:
361: #else /* !TARGET_SPARC64 */
1.1.1.6 root 362:
363: // 41 bit physical address space
364: static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
365: {
366: return x & 0x1ffffffffffULL;
367: }
368:
1.1 root 369: /*
370: * UltraSparc IIi I/DMMUs
371: */
1.1.1.6 root 372:
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
1.1.1.7 root 375: static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
1.1.1.6 root 376: uint64_t address, uint64_t context,
1.1.1.8 root 377: target_phys_addr_t *physical)
1.1.1.6 root 378: {
379: uint64_t mask;
380:
1.1.1.10! root 381: switch (TTE_PGSIZE(tlb->tte)) {
1.1.1.6 root 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;
395: }
396:
397: // valid, context match, virtual address match?
1.1.1.7 root 398: if (TTE_IS_VALID(tlb->tte) &&
1.1.1.8 root 399: (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
1.1.1.7 root 400: && compare_masked(address, tlb->tag, mask))
1.1.1.6 root 401: {
402: // decode physical address
1.1.1.7 root 403: *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
1.1.1.6 root 404: return 1;
405: }
406:
407: return 0;
408: }
409:
1.1.1.5 root 410: static int get_physical_address_data(CPUState *env,
411: target_phys_addr_t *physical, int *prot,
1.1.1.8 root 412: target_ulong address, int rw, int mmu_idx)
1.1 root 413: {
414: unsigned int i;
1.1.1.6 root 415: uint64_t context;
1.1.1.10! root 416: uint64_t sfsr = 0;
1.1.1.8 root 417:
418: int is_user = (mmu_idx == MMU_USER_IDX ||
419: mmu_idx == MMU_USER_SECONDARY_IDX);
1.1 root 420:
421: if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
1.1.1.6 root 422: *physical = ultrasparc_truncate_physical(address);
1.1.1.4 root 423: *prot = PAGE_READ | PAGE_WRITE;
1.1 root 424: return 0;
425: }
426:
1.1.1.8 root 427: switch(mmu_idx) {
428: case MMU_USER_IDX:
429: case MMU_KERNEL_IDX:
430: context = env->dmmu.mmu_primary_context & 0x1fff;
1.1.1.10! root 431: sfsr |= SFSR_CT_PRIMARY;
1.1.1.8 root 432: break;
433: case MMU_USER_SECONDARY_IDX:
434: case MMU_KERNEL_SECONDARY_IDX:
435: context = env->dmmu.mmu_secondary_context & 0x1fff;
1.1.1.10! root 436: sfsr |= SFSR_CT_SECONDARY;
1.1.1.8 root 437: break;
438: case MMU_NUCLEUS_IDX:
1.1.1.10! root 439: sfsr |= SFSR_CT_NUCLEUS;
! 440: /* FALLTHRU */
1.1.1.8 root 441: default:
442: context = 0;
443: break;
444: }
1.1.1.6 root 445:
1.1.1.10! root 446: if (rw == 1) {
! 447: sfsr |= SFSR_WRITE_BIT;
! 448: } else if (rw == 4) {
! 449: sfsr |= SFSR_NF_BIT;
! 450: }
! 451:
1.1 root 452: for (i = 0; i < 64; i++) {
1.1.1.5 root 453: // ctx match, vaddr match, valid?
1.1.1.8 root 454: if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
1.1.1.10! root 455: int do_fault = 0;
1.1.1.8 root 456:
1.1.1.5 root 457: // access ok?
1.1.1.10! root 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 */
1.1.1.7 root 462:
1.1.1.8 root 463: DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64
464: " mmu_idx=%d tl=%d\n",
465: address, context, mmu_idx, env->tl);
1.1.1.10! root 466: }
! 467: if (rw == 4) {
! 468: if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) {
! 469: do_fault = 1;
! 470: sfsr |= SFSR_FT_NF_E_BIT;
! 471: }
! 472: } else {
! 473: if (TTE_IS_NFO(env->dtlb[i].tte)) {
! 474: do_fault = 1;
! 475: sfsr |= SFSR_FT_NFO_BIT;
! 476: }
! 477: }
! 478:
! 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;
1.1.1.8 root 484: env->exception_index = TT_DPROT;
485:
486: DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64
487: " mmu_idx=%d tl=%d\n",
488: address, context, mmu_idx, env->tl);
1.1.1.10! root 489: }
! 490:
! 491: if (!do_fault) {
1.1.1.8 root 492: *prot = PAGE_READ;
1.1.1.10! root 493: if (TTE_IS_W_OK(env->dtlb[i].tte)) {
1.1.1.8 root 494: *prot |= PAGE_WRITE;
1.1.1.10! root 495: }
1.1.1.8 root 496:
497: TTE_SET_USED(env->dtlb[i].tte);
498:
499: return 0;
500: }
1.1.1.7 root 501:
1.1.1.10! root 502: if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
! 503: sfsr |= SFSR_OW_BIT; /* overflow (not read before
! 504: another fault) */
! 505: }
1.1.1.7 root 506:
1.1.1.10! root 507: if (env->pstate & PS_PRIV) {
! 508: sfsr |= SFSR_PR_BIT;
! 509: }
1.1.1.7 root 510:
1.1.1.10! root 511: /* FIXME: ASI field in SFSR must be set */
! 512: env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
1.1.1.7 root 513:
1.1.1.8 root 514: env->dmmu.sfar = address; /* Fault address register */
515:
516: env->dmmu.tag_access = (address & ~0x1fffULL) | context;
517:
518: return 1;
1.1.1.4 root 519: }
1.1 root 520: }
1.1.1.8 root 521:
522: DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n",
523: address, context);
524:
1.1.1.10! root 525: /*
! 526: * On MMU misses:
! 527: * - UltraSPARC IIi: SFSR and SFAR unmodified
! 528: * - JPS1: SFAR updated and some fields of SFSR updated
! 529: */
1.1.1.7 root 530: env->dmmu.tag_access = (address & ~0x1fffULL) | context;
1.1 root 531: env->exception_index = TT_DMISS;
532: return 1;
533: }
534:
1.1.1.5 root 535: static int get_physical_address_code(CPUState *env,
536: target_phys_addr_t *physical, int *prot,
1.1.1.8 root 537: target_ulong address, int mmu_idx)
1.1 root 538: {
539: unsigned int i;
1.1.1.6 root 540: uint64_t context;
1.1.1.8 root 541:
542: int is_user = (mmu_idx == MMU_USER_IDX ||
543: mmu_idx == MMU_USER_SECONDARY_IDX);
1.1 root 544:
1.1.1.6 root 545: if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
546: /* IMMU disabled */
547: *physical = ultrasparc_truncate_physical(address);
1.1.1.4 root 548: *prot = PAGE_EXEC;
1.1 root 549: return 0;
550: }
551:
1.1.1.8 root 552: if (env->tl == 0) {
553: /* PRIMARY context */
554: context = env->dmmu.mmu_primary_context & 0x1fff;
555: } else {
556: /* NUCLEUS context */
557: context = 0;
558: }
1.1.1.6 root 559:
1.1 root 560: for (i = 0; i < 64; i++) {
1.1.1.5 root 561: // ctx match, vaddr match, valid?
1.1.1.7 root 562: if (ultrasparc_tag_match(&env->itlb[i],
1.1.1.8 root 563: address, context, physical)) {
1.1.1.5 root 564: // access ok?
1.1.1.10! root 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;
! 572: }
! 573: if (env->pstate & PS_PRIV) {
! 574: env->immu.sfsr |= SFSR_PR_BIT;
! 575: }
! 576: if (env->tl > 0) {
! 577: env->immu.sfsr |= SFSR_CT_NUCLEUS;
! 578: }
! 579:
! 580: /* FIXME: ASI field in SFSR must be set */
! 581: env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
1.1.1.4 root 582: env->exception_index = TT_TFAULT;
1.1.1.8 root 583:
584: env->immu.tag_access = (address & ~0x1fffULL) | context;
585:
586: DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n",
587: address, context);
588:
1.1.1.4 root 589: return 1;
590: }
591: *prot = PAGE_EXEC;
1.1.1.7 root 592: TTE_SET_USED(env->itlb[i].tte);
1.1.1.4 root 593: return 0;
594: }
1.1 root 595: }
1.1.1.8 root 596:
597: DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n",
598: address, context);
599:
1.1.1.6 root 600: /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
1.1.1.7 root 601: env->immu.tag_access = (address & ~0x1fffULL) | context;
1.1 root 602: env->exception_index = TT_TMISS;
603: return 1;
604: }
605:
1.1.1.5 root 606: static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
607: int *prot, int *access_index,
1.1.1.8 root 608: target_ulong address, int rw, int mmu_idx,
609: target_ulong *page_size)
1.1 root 610: {
1.1.1.8 root 611: /* ??? We treat everything as a small page, then explicitly flush
612: everything when an entry is evicted. */
613: *page_size = TARGET_PAGE_SIZE;
614:
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);
628: }
629: #endif
1.1.1.4 root 630:
1.1 root 631: if (rw == 2)
1.1.1.5 root 632: return get_physical_address_code(env, physical, prot, address,
1.1.1.8 root 633: mmu_idx);
1.1 root 634: else
1.1.1.5 root 635: return get_physical_address_data(env, physical, prot, address, rw,
1.1.1.8 root 636: mmu_idx);
1.1 root 637: }
638:
639: /* Perform address translation */
640: int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
1.1.1.4 root 641: int mmu_idx, int is_softmmu)
1.1 root 642: {
643: target_ulong virt_addr, vaddr;
644: target_phys_addr_t paddr;
1.1.1.8 root 645: target_ulong page_size;
646: int error_code = 0, prot, access_index;
1.1 root 647:
1.1.1.5 root 648: error_code = get_physical_address(env, &paddr, &prot, &access_index,
1.1.1.8 root 649: address, rw, mmu_idx, &page_size);
1.1 root 650: if (error_code == 0) {
1.1.1.4 root 651: virt_addr = address & TARGET_PAGE_MASK;
1.1.1.5 root 652: vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
653: (TARGET_PAGE_SIZE - 1));
1.1.1.8 root 654:
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);
665:
666: tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
667: return 0;
1.1 root 668: }
669: // XXX
670: return 1;
671: }
672:
1.1.1.9 root 673: void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
1.1 root 674: {
675: unsigned int i;
676: const char *mask;
677:
1.1.1.9 root 678: (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
679: PRId64 "\n",
680: env->dmmu.mmu_primary_context,
681: env->dmmu.mmu_secondary_context);
1.1 root 682: if ((env->lsu & DMMU_E) == 0) {
1.1.1.9 root 683: (*cpu_fprintf)(f, "DMMU disabled\n");
1.1 root 684: } else {
1.1.1.9 root 685: (*cpu_fprintf)(f, "DMMU dump\n");
1.1.1.4 root 686: for (i = 0; i < 64; i++) {
1.1.1.10! root 687: switch (TTE_PGSIZE(env->dtlb[i].tte)) {
1.1.1.4 root 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;
701: }
1.1.1.10! root 702: if (TTE_IS_VALID(env->dtlb[i].tte)) {
! 703: (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
1.1.1.9 root 704: ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
705: i,
706: env->dtlb[i].tag & (uint64_t)~0x1fffULL,
1.1.1.10! root 707: TTE_PA(env->dtlb[i].tte),
1.1.1.9 root 708: mask,
1.1.1.10! root 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",
1.1.1.9 root 713: env->dtlb[i].tag & (uint64_t)0x1fffULL,
714: TTE_IS_GLOBAL(env->dtlb[i].tte)?
715: "global" : "local");
1.1.1.4 root 716: }
717: }
1.1 root 718: }
719: if ((env->lsu & IMMU_E) == 0) {
1.1.1.9 root 720: (*cpu_fprintf)(f, "IMMU disabled\n");
1.1 root 721: } else {
1.1.1.9 root 722: (*cpu_fprintf)(f, "IMMU dump\n");
1.1.1.4 root 723: for (i = 0; i < 64; i++) {
1.1.1.10! root 724: switch (TTE_PGSIZE(env->itlb[i].tte)) {
1.1.1.4 root 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;
738: }
1.1.1.10! root 739: if (TTE_IS_VALID(env->itlb[i].tte)) {
! 740: (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
1.1.1.9 root 741: ", %s, %s, %s, ctx %" PRId64 " %s\n",
742: i,
743: env->itlb[i].tag & (uint64_t)~0x1fffULL,
1.1.1.10! root 744: TTE_PA(env->itlb[i].tte),
1.1.1.9 root 745: mask,
1.1.1.10! root 746: TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user",
! 747: TTE_IS_LOCKED(env->itlb[i].tte) ?
! 748: "locked" : "unlocked",
1.1.1.9 root 749: env->itlb[i].tag & (uint64_t)0x1fffULL,
750: TTE_IS_GLOBAL(env->itlb[i].tte)?
751: "global" : "local");
1.1.1.4 root 752: }
753: }
1.1 root 754: }
755: }
1.1.1.2 root 756:
757: #endif /* TARGET_SPARC64 */
758: #endif /* !CONFIG_USER_ONLY */
759:
1.1.1.5 root 760:
1.1.1.8 root 761: #if !defined(CONFIG_USER_ONLY)
1.1.1.10! root 762: static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys,
! 763: target_ulong addr, int rw, int mmu_idx)
! 764: {
! 765: target_ulong page_size;
! 766: int prot, access_index;
! 767:
! 768: return get_physical_address(env, phys, &prot, &access_index, addr, rw,
! 769: mmu_idx, &page_size);
! 770: }
! 771:
! 772: #if defined(TARGET_SPARC64)
1.1.1.8 root 773: target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
774: int mmu_idx)
1.1.1.5 root 775: {
776: target_phys_addr_t phys_addr;
777:
1.1.1.10! root 778: if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) {
1.1.1.5 root 779: return -1;
1.1.1.10! root 780: }
1.1.1.5 root 781: return phys_addr;
782: }
1.1.1.10! root 783: #endif
1.1.1.8 root 784:
785: target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
786: {
1.1.1.10! root 787: target_phys_addr_t phys_addr;
! 788: int mmu_idx = cpu_mmu_index(env);
! 789:
! 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;
! 793: }
! 794: }
! 795: if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) {
! 796: return -1;
! 797: }
! 798: return phys_addr;
! 799: }
! 800: #endif
! 801:
! 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",
! 836: };
! 837: #endif
! 838:
! 839: void do_interrupt(CPUState *env)
! 840: {
! 841: int intno = env->exception_index;
! 842: trap_state *tsptr;
! 843:
! 844: #ifdef DEBUG_PCALL
! 845: if (qemu_loglevel_mask(CPU_LOG_INT)) {
! 846: static int count;
! 847: const char *name;
! 848:
! 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";
! 861: }
! 862: }
! 863:
! 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
! 871: {
! 872: int i;
! 873: uint8_t *ptr;
! 874:
! 875: qemu_log(" code=");
! 876: ptr = (uint8_t *)env->pc;
! 877: for (i = 0; i < 16; i++) {
! 878: qemu_log(" %02x", ldub(ptr + i));
! 879: }
! 880: qemu_log("\n");
! 881: }
! 882: #endif
! 883: count++;
! 884: }
! 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;
! 891: }
! 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++;
! 899: }
! 900: }
! 901: tsptr = cpu_tsptr(env);
! 902:
! 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;
! 909:
! 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;
! 924: }
! 925:
! 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));
! 932: }
! 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;
! 938: }
! 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",
! 972: };
! 973: #endif
! 974:
! 975: void do_interrupt(CPUState *env)
! 976: {
! 977: int cwp, intno = env->exception_index;
! 978:
! 979: #ifdef DEBUG_PCALL
! 980: if (qemu_loglevel_mask(CPU_LOG_INT)) {
! 981: static int count;
! 982: const char *name;
! 983:
! 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";
! 992: }
! 993: }
! 994:
! 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
! 1001: {
! 1002: int i;
! 1003: uint8_t *ptr;
! 1004:
! 1005: qemu_log(" code=");
! 1006: ptr = (uint8_t *)env->pc;
! 1007: for (i = 0; i < 16; i++) {
! 1008: qemu_log(" %02x", ldub(ptr + i));
! 1009: }
! 1010: qemu_log("\n");
! 1011: }
! 1012: #endif
! 1013: count++;
! 1014: }
! 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;
! 1021: }
! 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;
! 1034:
! 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);
! 1039: }
! 1040: #endif
1.1.1.8 root 1041: }
1.1.1.4 root 1042: #endif
1043:
1.1.1.5 root 1044: void cpu_reset(CPUSPARCState *env)
1.1.1.4 root 1045: {
1.1.1.5 root 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);
1049: }
1050:
1051: tlb_flush(env, 1);
1052: env->cwp = 0;
1.1.1.6 root 1053: #ifndef TARGET_SPARC64
1.1.1.5 root 1054: env->wim = 1;
1.1.1.6 root 1055: #endif
1.1.1.5 root 1056: env->regwptr = env->regbase + (env->cwp * 16);
1.1.1.7 root 1057: CC_OP = CC_OP_FLAGS;
1.1.1.5 root 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
1.1.1.6 root 1066: #if !defined(TARGET_SPARC64)
1.1.1.5 root 1067: env->psret = 0;
1068: env->psrs = 1;
1069: env->psrps = 1;
1.1.1.8 root 1070: #endif
1.1.1.5 root 1071: #ifdef TARGET_SPARC64
1.1.1.7 root 1072: env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
1.1.1.8 root 1073: env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
1.1.1.7 root 1074: env->tl = env->maxtl;
1075: cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
1.1.1.5 root 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;
1.1.1.4 root 1083: #endif
1.1.1.9 root 1084: env->cache_control = 0;
1.1.1.4 root 1085: }
1086:
1.1.1.5 root 1087: static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
1.1.1.4 root 1088: {
1.1.1.5 root 1089: sparc_def_t def1, *def = &def1;
1090:
1091: if (cpu_sparc_find_by_name(def, cpu_model) < 0)
1092: return -1;
1093:
1094: env->def = qemu_mallocz(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;
1.1.1.4 root 1108: #else
1.1.1.5 root 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
1.1.1.4 root 1114: return 0;
1.1.1.5 root 1115: }
1116:
1117: static void cpu_sparc_close(CPUSPARCState *env)
1118: {
1119: free(env->def);
1120: free(env);
1121: }
1122:
1123: CPUSPARCState *cpu_sparc_init(const char *cpu_model)
1124: {
1125: CPUSPARCState *env;
1126:
1127: env = qemu_mallocz(sizeof(CPUSPARCState));
1128: cpu_exec_init(env);
1129:
1130: gen_intermediate_code_init(env);
1131:
1132: if (cpu_sparc_register(env, cpu_model) < 0) {
1133: cpu_sparc_close(env);
1134: return NULL;
1135: }
1.1.1.6 root 1136: qemu_init_vcpu(env);
1.1.1.5 root 1137:
1138: return env;
1139: }
1140:
1141: void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
1142: {
1143: #if !defined(TARGET_SPARC64)
1144: env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
1145: #endif
1146: }
1147:
1148: static const sparc_def_t sparc_defs[] = {
1149: #ifdef TARGET_SPARC64
1150: {
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,
1158: },
1159: {
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,
1167: },
1168: {
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,
1176: },
1177: {
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,
1185: },
1186: {
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,
1194: },
1195: {
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,
1203: },
1204: {
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,
1212: },
1213: {
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,
1221: },
1222: {
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,
1230: },
1231: {
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,
1239: },
1240: {
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,
1248: },
1249: {
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,
1257: },
1258: {
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,
1266: },
1267: {
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,
1275: },
1276: {
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,
1286: },
1287: {
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,
1297: },
1298: {
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,
1306: },
1307: #else
1308: {
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,
1320: },
1321: {
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,
1333: },
1334: {
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,
1346: },
1347: {
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,
1360: },
1361: {
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,
1374: },
1375: {
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,
1388: },
1389: {
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,
1403: },
1404: {
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,
1416: },
1417: {
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,
1429: },
1430: {
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,
1442: },
1443: {
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,
1455: },
1456: {
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,
1469: },
1470: {
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,
1482: },
1483: {
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,
1496: },
1497: {
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,
1510: },
1511: {
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,
1523: },
1524: {
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,
1536: },
1537: {
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,
1550: },
1551: {
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,
1564: },
1565: {
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,
1577: },
1578: {
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,
1.1.1.9 root 1589: .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
1.1.1.5 root 1590: },
1591: {
1592: .name = "LEON3",
1593: .iu_version = 0xf3000000,
1594: .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1595: .mmu_version = 0xf3000000,
1.1.1.9 root 1596: .mmu_bm = 0x00000000,
1.1.1.5 root 1597: .mmu_ctpr_mask = 0x007ffff0,
1598: .mmu_cxr_mask = 0x0000003f,
1599: .mmu_sfsr_mask = 0xffffffff,
1600: .mmu_trcr_mask = 0xffffffff,
1601: .nwindows = 8,
1.1.1.9 root 1602: .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
1603: CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
1.1.1.5 root 1604: },
1.1.1.4 root 1605: #endif
1.1.1.5 root 1606: };
1607:
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",
1623: };
1624:
1.1.1.9 root 1625: static void print_features(FILE *f, fprintf_function cpu_fprintf,
1.1.1.5 root 1626: uint32_t features, const char *prefix)
1627: {
1628: unsigned int i;
1629:
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]);
1635: }
1.1.1.4 root 1636: }
1637:
1.1.1.5 root 1638: static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
1.1.1.4 root 1639: {
1.1.1.5 root 1640: unsigned int i;
1641:
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;
1646: }
1647: fprintf(stderr, "CPU feature %s not found\n", flagname);
1648: }
1649:
1650: static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
1651: {
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;
1.1.1.8 root 1658: uint64_t iu_version;
1.1.1.5 root 1659: uint32_t fpu_version, mmu_version, nwindows;
1660:
1661: for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
1662: if (strcasecmp(name, sparc_defs[i].name) == 0) {
1663: def = &sparc_defs[i];
1664: }
1665: }
1666: if (!def)
1667: goto error;
1668: memcpy(cpu_def, def, sizeof(*def));
1669:
1670: featurestr = strtok(NULL, ",");
1671: while (featurestr) {
1672: char *val;
1673:
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;
1682:
1683: iu_version = strtoll(val, &err, 0);
1684: if (!*val || *err) {
1685: fprintf(stderr, "bad numerical value %s\n", val);
1686: goto error;
1687: }
1688: cpu_def->iu_version = iu_version;
1689: #ifdef DEBUG_FEATURES
1.1.1.8 root 1690: fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
1.1.1.5 root 1691: #endif
1692: } else if (!strcmp(featurestr, "fpu_version")) {
1693: char *err;
1694:
1695: fpu_version = strtol(val, &err, 0);
1696: if (!*val || *err) {
1697: fprintf(stderr, "bad numerical value %s\n", val);
1698: goto error;
1699: }
1700: cpu_def->fpu_version = fpu_version;
1701: #ifdef DEBUG_FEATURES
1.1.1.6 root 1702: fprintf(stderr, "fpu_version %x\n", fpu_version);
1.1.1.5 root 1703: #endif
1704: } else if (!strcmp(featurestr, "mmu_version")) {
1705: char *err;
1706:
1707: mmu_version = strtol(val, &err, 0);
1708: if (!*val || *err) {
1709: fprintf(stderr, "bad numerical value %s\n", val);
1710: goto error;
1711: }
1712: cpu_def->mmu_version = mmu_version;
1713: #ifdef DEBUG_FEATURES
1.1.1.6 root 1714: fprintf(stderr, "mmu_version %x\n", mmu_version);
1.1.1.5 root 1715: #endif
1716: } else if (!strcmp(featurestr, "nwindows")) {
1717: char *err;
1718:
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;
1724: }
1725: cpu_def->nwindows = nwindows;
1726: #ifdef DEBUG_FEATURES
1727: fprintf(stderr, "nwindows %d\n", nwindows);
1.1.1.4 root 1728: #endif
1.1.1.5 root 1729: } else {
1730: fprintf(stderr, "unrecognized feature %s\n", featurestr);
1731: goto error;
1732: }
1733: } else {
1734: fprintf(stderr, "feature string `%s' not in format "
1735: "(+feature|-feature|feature=xyz)\n", featurestr);
1736: goto error;
1737: }
1738: featurestr = strtok(NULL, ",");
1739: }
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;
1747:
1748: error:
1749: free(s);
1750: return -1;
1.1.1.4 root 1751: }
1.1.1.5 root 1752:
1.1.1.9 root 1753: void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
1.1.1.5 root 1754: {
1755: unsigned int i;
1756:
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");
1769: }
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");
1778: }
1779:
1.1.1.9 root 1780: static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
1.1.1.8 root 1781: uint32_t cc)
1782: {
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' : '-');
1786: }
1787:
1788: #ifdef TARGET_SPARC64
1789: #define REGS_PER_LINE 4
1790: #else
1791: #define REGS_PER_LINE 8
1792: #endif
1793:
1.1.1.9 root 1794: void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
1.1.1.5 root 1795: int flags)
1796: {
1797: int i, x;
1798:
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");
1.1.1.8 root 1802:
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);
1806: }
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");
1810: }
1811: }
1.1.1.5 root 1812: cpu_fprintf(f, "\nCurrent Register Window:\n");
1813: for (x = 0; x < 3; x++) {
1.1.1.8 root 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);
1819: }
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");
1823: }
1824: }
1.1.1.5 root 1825: }
1826: cpu_fprintf(f, "\nFloating Point Registers:\n");
1.1.1.8 root 1827: for (i = 0; i < TARGET_FPREGS; i++) {
1.1.1.5 root 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");
1833: }
1834: #ifdef TARGET_SPARC64
1.1.1.8 root 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",
1.1.1.5 root 1844: env->cansave, env->canrestore, env->otherwin, env->wstate,
1845: env->cleanwin, env->nwindows - 1 - env->cwp);
1.1.1.8 root 1846: cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
1847: TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
1.1.1.5 root 1848: #else
1.1.1.8 root 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);
1.1.1.4 root 1856: #endif
1.1.1.5 root 1857: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.