xref: /qemu/target/sparc/helper.c (revision b64b64361413808bee8e6213095e2e3a18b3358f)
1e8af50a3Sbellard /*
2e8af50a3Sbellard  *  sparc helpers
3e8af50a3Sbellard  *
483469015Sbellard  *  Copyright (c) 2003-2005 Fabrice Bellard
5e8af50a3Sbellard  *
6e8af50a3Sbellard  * This library is free software; you can redistribute it and/or
7e8af50a3Sbellard  * modify it under the terms of the GNU Lesser General Public
8e8af50a3Sbellard  * License as published by the Free Software Foundation; either
9e8af50a3Sbellard  * version 2 of the License, or (at your option) any later version.
10e8af50a3Sbellard  *
11e8af50a3Sbellard  * This library is distributed in the hope that it will be useful,
12e8af50a3Sbellard  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13e8af50a3Sbellard  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14e8af50a3Sbellard  * Lesser General Public License for more details.
15e8af50a3Sbellard  *
16e8af50a3Sbellard  * You should have received a copy of the GNU Lesser General Public
178167ee88SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18e8af50a3Sbellard  */
19ee5bbe38Sbellard #include <stdarg.h>
20ee5bbe38Sbellard #include <stdlib.h>
21ee5bbe38Sbellard #include <stdio.h>
22ee5bbe38Sbellard #include <string.h>
23ee5bbe38Sbellard #include <inttypes.h>
24ee5bbe38Sbellard 
25ee5bbe38Sbellard #include "cpu.h"
26ca10f867Saurel32 #include "qemu-common.h"
27e8af50a3Sbellard 
28e80cfcfcSbellard //#define DEBUG_MMU
2964a88d5dSblueswir1 //#define DEBUG_FEATURES
30e8af50a3Sbellard 
31b8e9fc06SIgor V. Kovalenko #ifdef DEBUG_MMU
32b8e9fc06SIgor V. Kovalenko #define DPRINTF_MMU(fmt, ...) \
33b8e9fc06SIgor V. Kovalenko     do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
34b8e9fc06SIgor V. Kovalenko #else
35b8e9fc06SIgor V. Kovalenko #define DPRINTF_MMU(fmt, ...) do {} while (0)
36b8e9fc06SIgor V. Kovalenko #endif
37b8e9fc06SIgor V. Kovalenko 
3822548760Sblueswir1 static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
39c48fcb47Sblueswir1 
40e8af50a3Sbellard /* Sparc MMU emulation */
41e8af50a3Sbellard 
429d893301Sbellard #if defined(CONFIG_USER_ONLY)
439d893301Sbellard 
4422548760Sblueswir1 int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
456ebbf390Sj_mayer                                int mmu_idx, int is_softmmu)
469d893301Sbellard {
47878d3096Sbellard     if (rw & 2)
4822548760Sblueswir1         env1->exception_index = TT_TFAULT;
49878d3096Sbellard     else
5022548760Sblueswir1         env1->exception_index = TT_DFAULT;
519d893301Sbellard     return 1;
529d893301Sbellard }
539d893301Sbellard 
549d893301Sbellard #else
55e8af50a3Sbellard 
563475187dSbellard #ifndef TARGET_SPARC64
5783469015Sbellard /*
5883469015Sbellard  * Sparc V8 Reference MMU (SRMMU)
5983469015Sbellard  */
60e8af50a3Sbellard static const int access_table[8][8] = {
61a764a566Sblueswir1     { 0, 0, 0, 0, 8, 0, 12, 12 },
62a764a566Sblueswir1     { 0, 0, 0, 0, 8, 0, 0, 0 },
63a764a566Sblueswir1     { 8, 8, 0, 0, 0, 8, 12, 12 },
64a764a566Sblueswir1     { 8, 8, 0, 0, 0, 8, 0, 0 },
65a764a566Sblueswir1     { 8, 0, 8, 0, 8, 8, 12, 12 },
66a764a566Sblueswir1     { 8, 0, 8, 0, 8, 0, 8, 0 },
67a764a566Sblueswir1     { 8, 8, 8, 0, 8, 8, 12, 12 },
68a764a566Sblueswir1     { 8, 8, 8, 0, 8, 8, 8, 0 }
69e8af50a3Sbellard };
70e8af50a3Sbellard 
71227671c9Sbellard static const int perm_table[2][8] = {
72227671c9Sbellard     {
73227671c9Sbellard         PAGE_READ,
74227671c9Sbellard         PAGE_READ | PAGE_WRITE,
75227671c9Sbellard         PAGE_READ | PAGE_EXEC,
76227671c9Sbellard         PAGE_READ | PAGE_WRITE | PAGE_EXEC,
77227671c9Sbellard         PAGE_EXEC,
78227671c9Sbellard         PAGE_READ | PAGE_WRITE,
79227671c9Sbellard         PAGE_READ | PAGE_EXEC,
80227671c9Sbellard         PAGE_READ | PAGE_WRITE | PAGE_EXEC
81227671c9Sbellard     },
82227671c9Sbellard     {
83227671c9Sbellard         PAGE_READ,
84227671c9Sbellard         PAGE_READ | PAGE_WRITE,
85227671c9Sbellard         PAGE_READ | PAGE_EXEC,
86227671c9Sbellard         PAGE_READ | PAGE_WRITE | PAGE_EXEC,
87227671c9Sbellard         PAGE_EXEC,
88227671c9Sbellard         PAGE_READ,
89227671c9Sbellard         0,
90227671c9Sbellard         0,
91227671c9Sbellard     }
92e8af50a3Sbellard };
93e8af50a3Sbellard 
94c227f099SAnthony Liguori static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
95c48fcb47Sblueswir1                                 int *prot, int *access_index,
96d4c430a8SPaul Brook                                 target_ulong address, int rw, int mmu_idx,
97d4c430a8SPaul Brook                                 target_ulong *page_size)
98e8af50a3Sbellard {
99e80cfcfcSbellard     int access_perms = 0;
100c227f099SAnthony Liguori     target_phys_addr_t pde_ptr;
101af7bf89bSbellard     uint32_t pde;
1026ebbf390Sj_mayer     int error_code = 0, is_dirty, is_user;
103e80cfcfcSbellard     unsigned long page_offset;
104e8af50a3Sbellard 
1056ebbf390Sj_mayer     is_user = mmu_idx == MMU_USER_IDX;
10640ce0a9aSblueswir1 
107e8af50a3Sbellard     if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
108d4c430a8SPaul Brook         *page_size = TARGET_PAGE_SIZE;
10940ce0a9aSblueswir1         // Boot mode: instruction fetches are taken from PROM
1105578ceabSblueswir1         if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
11158a770f3Sblueswir1             *physical = env->prom_addr | (address & 0x7ffffULL);
11240ce0a9aSblueswir1             *prot = PAGE_READ | PAGE_EXEC;
11340ce0a9aSblueswir1             return 0;
11440ce0a9aSblueswir1         }
115e80cfcfcSbellard         *physical = address;
116227671c9Sbellard         *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
117e80cfcfcSbellard         return 0;
118e8af50a3Sbellard     }
119e8af50a3Sbellard 
1207483750dSbellard     *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
1215dcb6b91Sblueswir1     *physical = 0xffffffffffff0000ULL;
1227483750dSbellard 
123e8af50a3Sbellard     /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
124e8af50a3Sbellard     /* Context base + context number */
1253deaeab7Sblueswir1     pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
12649be8030Sbellard     pde = ldl_phys(pde_ptr);
127e8af50a3Sbellard 
128e8af50a3Sbellard     /* Ctx pde */
129e8af50a3Sbellard     switch (pde & PTE_ENTRYTYPE_MASK) {
130e80cfcfcSbellard     default:
131e8af50a3Sbellard     case 0: /* Invalid */
1327483750dSbellard         return 1 << 2;
133e80cfcfcSbellard     case 2: /* L0 PTE, maybe should not happen? */
134e8af50a3Sbellard     case 3: /* Reserved */
1357483750dSbellard         return 4 << 2;
136e80cfcfcSbellard     case 1: /* L0 PDE */
137e80cfcfcSbellard         pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
13849be8030Sbellard         pde = ldl_phys(pde_ptr);
139e80cfcfcSbellard 
140e80cfcfcSbellard         switch (pde & PTE_ENTRYTYPE_MASK) {
141e80cfcfcSbellard         default:
142e80cfcfcSbellard         case 0: /* Invalid */
1437483750dSbellard             return (1 << 8) | (1 << 2);
144e80cfcfcSbellard         case 3: /* Reserved */
1457483750dSbellard             return (1 << 8) | (4 << 2);
146e8af50a3Sbellard         case 1: /* L1 PDE */
147e80cfcfcSbellard             pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
14849be8030Sbellard             pde = ldl_phys(pde_ptr);
149e8af50a3Sbellard 
150e8af50a3Sbellard             switch (pde & PTE_ENTRYTYPE_MASK) {
151e80cfcfcSbellard             default:
152e8af50a3Sbellard             case 0: /* Invalid */
1537483750dSbellard                 return (2 << 8) | (1 << 2);
154e8af50a3Sbellard             case 3: /* Reserved */
1557483750dSbellard                 return (2 << 8) | (4 << 2);
156e8af50a3Sbellard             case 1: /* L2 PDE */
157e80cfcfcSbellard                 pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
15849be8030Sbellard                 pde = ldl_phys(pde_ptr);
159e8af50a3Sbellard 
160e8af50a3Sbellard                 switch (pde & PTE_ENTRYTYPE_MASK) {
161e80cfcfcSbellard                 default:
162e8af50a3Sbellard                 case 0: /* Invalid */
1637483750dSbellard                     return (3 << 8) | (1 << 2);
164e8af50a3Sbellard                 case 1: /* PDE, should not happen */
165e8af50a3Sbellard                 case 3: /* Reserved */
1667483750dSbellard                     return (3 << 8) | (4 << 2);
167e8af50a3Sbellard                 case 2: /* L3 PTE */
16877f193daSblueswir1                     page_offset = (address & TARGET_PAGE_MASK) &
16977f193daSblueswir1                         (TARGET_PAGE_SIZE - 1);
170e8af50a3Sbellard                 }
171d4c430a8SPaul Brook                 *page_size = TARGET_PAGE_SIZE;
172e8af50a3Sbellard                 break;
173e8af50a3Sbellard             case 2: /* L2 PTE */
174e8af50a3Sbellard                 page_offset = address & 0x3ffff;
175d4c430a8SPaul Brook                 *page_size = 0x40000;
176e8af50a3Sbellard             }
177e8af50a3Sbellard             break;
178e8af50a3Sbellard         case 2: /* L1 PTE */
179e8af50a3Sbellard             page_offset = address & 0xffffff;
180d4c430a8SPaul Brook             *page_size = 0x1000000;
181e8af50a3Sbellard         }
182e8af50a3Sbellard     }
183e8af50a3Sbellard 
184698235aaSArtyom Tarasenko     /* check access */
185698235aaSArtyom Tarasenko     access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
186698235aaSArtyom Tarasenko     error_code = access_table[*access_index][access_perms];
187698235aaSArtyom Tarasenko     if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user))
188698235aaSArtyom Tarasenko         return error_code;
189698235aaSArtyom Tarasenko 
190e8af50a3Sbellard     /* update page modified and dirty bits */
191b769d8feSbellard     is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
192e8af50a3Sbellard     if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
193e8af50a3Sbellard         pde |= PG_ACCESSED_MASK;
194e8af50a3Sbellard         if (is_dirty)
195e8af50a3Sbellard             pde |= PG_MODIFIED_MASK;
19649be8030Sbellard         stl_phys_notdirty(pde_ptr, pde);
197e8af50a3Sbellard     }
198e8af50a3Sbellard 
199e8af50a3Sbellard     /* the page can be put in the TLB */
200227671c9Sbellard     *prot = perm_table[is_user][access_perms];
201227671c9Sbellard     if (!(pde & PG_MODIFIED_MASK)) {
202e8af50a3Sbellard         /* only set write access if already dirty... otherwise wait
203e8af50a3Sbellard            for dirty access */
204227671c9Sbellard         *prot &= ~PAGE_WRITE;
205e8af50a3Sbellard     }
206e8af50a3Sbellard 
207e8af50a3Sbellard     /* Even if large ptes, we map only one 4KB page in the cache to
208e8af50a3Sbellard        avoid filling it too fast */
209c227f099SAnthony Liguori     *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
2106f7e9aecSbellard     return error_code;
211e80cfcfcSbellard }
212e80cfcfcSbellard 
213e80cfcfcSbellard /* Perform address translation */
214af7bf89bSbellard int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
2156ebbf390Sj_mayer                               int mmu_idx, int is_softmmu)
216e80cfcfcSbellard {
217c227f099SAnthony Liguori     target_phys_addr_t paddr;
2185dcb6b91Sblueswir1     target_ulong vaddr;
219d4c430a8SPaul Brook     target_ulong page_size;
220d4c430a8SPaul Brook     int error_code = 0, prot, access_index;
221e80cfcfcSbellard 
22277f193daSblueswir1     error_code = get_physical_address(env, &paddr, &prot, &access_index,
223d4c430a8SPaul Brook                                       address, rw, mmu_idx, &page_size);
224e80cfcfcSbellard     if (error_code == 0) {
2259e61bde5Sbellard         vaddr = address & TARGET_PAGE_MASK;
2269e61bde5Sbellard         paddr &= TARGET_PAGE_MASK;
2279e61bde5Sbellard #ifdef DEBUG_MMU
2285dcb6b91Sblueswir1         printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
2295dcb6b91Sblueswir1                TARGET_FMT_lx "\n", address, paddr, vaddr);
2309e61bde5Sbellard #endif
231d4c430a8SPaul Brook         tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
232d4c430a8SPaul Brook         return 0;
233e80cfcfcSbellard     }
234e8af50a3Sbellard 
235e8af50a3Sbellard     if (env->mmuregs[3]) /* Fault status register */
236e8af50a3Sbellard         env->mmuregs[3] = 1; /* overflow (not read before another fault) */
2377483750dSbellard     env->mmuregs[3] |= (access_index << 5) | error_code | 2;
238e8af50a3Sbellard     env->mmuregs[4] = address; /* Fault address register */
239e8af50a3Sbellard 
240878d3096Sbellard     if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
2416f7e9aecSbellard         // No fault mode: if a mapping is available, just override
2426f7e9aecSbellard         // permissions. If no mapping is available, redirect accesses to
2436f7e9aecSbellard         // neverland. Fake/overridden mappings will be flushed when
2446f7e9aecSbellard         // switching to normal mode.
2457483750dSbellard         vaddr = address & TARGET_PAGE_MASK;
246227671c9Sbellard         prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
247d4c430a8SPaul Brook         tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
248d4c430a8SPaul Brook         return 0;
2497483750dSbellard     } else {
250878d3096Sbellard         if (rw & 2)
251878d3096Sbellard             env->exception_index = TT_TFAULT;
252878d3096Sbellard         else
253878d3096Sbellard             env->exception_index = TT_DFAULT;
254878d3096Sbellard         return 1;
255e8af50a3Sbellard     }
2567483750dSbellard }
25724741ef3Sbellard 
25824741ef3Sbellard target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
25924741ef3Sbellard {
260c227f099SAnthony Liguori     target_phys_addr_t pde_ptr;
26124741ef3Sbellard     uint32_t pde;
26224741ef3Sbellard 
26324741ef3Sbellard     /* Context base + context number */
264c227f099SAnthony Liguori     pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
2655dcb6b91Sblueswir1         (env->mmuregs[2] << 2);
26624741ef3Sbellard     pde = ldl_phys(pde_ptr);
26724741ef3Sbellard 
26824741ef3Sbellard     switch (pde & PTE_ENTRYTYPE_MASK) {
26924741ef3Sbellard     default:
27024741ef3Sbellard     case 0: /* Invalid */
27124741ef3Sbellard     case 2: /* PTE, maybe should not happen? */
27224741ef3Sbellard     case 3: /* Reserved */
27324741ef3Sbellard         return 0;
27424741ef3Sbellard     case 1: /* L1 PDE */
27524741ef3Sbellard         if (mmulev == 3)
27624741ef3Sbellard             return pde;
27724741ef3Sbellard         pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
27824741ef3Sbellard         pde = ldl_phys(pde_ptr);
27924741ef3Sbellard 
28024741ef3Sbellard         switch (pde & PTE_ENTRYTYPE_MASK) {
28124741ef3Sbellard         default:
28224741ef3Sbellard         case 0: /* Invalid */
28324741ef3Sbellard         case 3: /* Reserved */
28424741ef3Sbellard             return 0;
28524741ef3Sbellard         case 2: /* L1 PTE */
28624741ef3Sbellard             return pde;
28724741ef3Sbellard         case 1: /* L2 PDE */
28824741ef3Sbellard             if (mmulev == 2)
28924741ef3Sbellard                 return pde;
29024741ef3Sbellard             pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
29124741ef3Sbellard             pde = ldl_phys(pde_ptr);
29224741ef3Sbellard 
29324741ef3Sbellard             switch (pde & PTE_ENTRYTYPE_MASK) {
29424741ef3Sbellard             default:
29524741ef3Sbellard             case 0: /* Invalid */
29624741ef3Sbellard             case 3: /* Reserved */
29724741ef3Sbellard                 return 0;
29824741ef3Sbellard             case 2: /* L2 PTE */
29924741ef3Sbellard                 return pde;
30024741ef3Sbellard             case 1: /* L3 PDE */
30124741ef3Sbellard                 if (mmulev == 1)
30224741ef3Sbellard                     return pde;
30324741ef3Sbellard                 pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
30424741ef3Sbellard                 pde = ldl_phys(pde_ptr);
30524741ef3Sbellard 
30624741ef3Sbellard                 switch (pde & PTE_ENTRYTYPE_MASK) {
30724741ef3Sbellard                 default:
30824741ef3Sbellard                 case 0: /* Invalid */
30924741ef3Sbellard                 case 1: /* PDE, should not happen */
31024741ef3Sbellard                 case 3: /* Reserved */
31124741ef3Sbellard                     return 0;
31224741ef3Sbellard                 case 2: /* L3 PTE */
31324741ef3Sbellard                     return pde;
31424741ef3Sbellard                 }
31524741ef3Sbellard             }
31624741ef3Sbellard         }
31724741ef3Sbellard     }
31824741ef3Sbellard     return 0;
31924741ef3Sbellard }
32024741ef3Sbellard 
321d41160a3SBlue Swirl void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
32224741ef3Sbellard {
32324741ef3Sbellard     target_ulong va, va1, va2;
32424741ef3Sbellard     unsigned int n, m, o;
325c227f099SAnthony Liguori     target_phys_addr_t pde_ptr, pa;
32624741ef3Sbellard     uint32_t pde;
32724741ef3Sbellard 
32824741ef3Sbellard     pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
32924741ef3Sbellard     pde = ldl_phys(pde_ptr);
330d41160a3SBlue Swirl     (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
331c227f099SAnthony Liguori                    (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
33224741ef3Sbellard     for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
3335dcb6b91Sblueswir1         pde = mmu_probe(env, va, 2);
3345dcb6b91Sblueswir1         if (pde) {
33524741ef3Sbellard             pa = cpu_get_phys_page_debug(env, va);
336d41160a3SBlue Swirl             (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
3375dcb6b91Sblueswir1                            " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
33824741ef3Sbellard             for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
3395dcb6b91Sblueswir1                 pde = mmu_probe(env, va1, 1);
3405dcb6b91Sblueswir1                 if (pde) {
34124741ef3Sbellard                     pa = cpu_get_phys_page_debug(env, va1);
342d41160a3SBlue Swirl                     (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
343d41160a3SBlue Swirl                                    TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
344d41160a3SBlue Swirl                                    va1, pa, pde);
34524741ef3Sbellard                     for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
3465dcb6b91Sblueswir1                         pde = mmu_probe(env, va2, 0);
3475dcb6b91Sblueswir1                         if (pde) {
34824741ef3Sbellard                             pa = cpu_get_phys_page_debug(env, va2);
349d41160a3SBlue Swirl                             (*cpu_fprintf)(f, "  VA: " TARGET_FMT_lx ", PA: "
350d41160a3SBlue Swirl                                            TARGET_FMT_plx " PTE: "
351d41160a3SBlue Swirl                                            TARGET_FMT_lx "\n",
3525dcb6b91Sblueswir1                                            va2, pa, pde);
35324741ef3Sbellard                         }
35424741ef3Sbellard                     }
35524741ef3Sbellard                 }
35624741ef3Sbellard             }
35724741ef3Sbellard         }
35824741ef3Sbellard     }
35924741ef3Sbellard }
36024741ef3Sbellard 
36124741ef3Sbellard #else /* !TARGET_SPARC64 */
362e8807b14SIgor Kovalenko 
363e8807b14SIgor Kovalenko // 41 bit physical address space
364c227f099SAnthony Liguori static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
365e8807b14SIgor Kovalenko {
366e8807b14SIgor Kovalenko     return x & 0x1ffffffffffULL;
367e8807b14SIgor Kovalenko }
368e8807b14SIgor Kovalenko 
36983469015Sbellard /*
37083469015Sbellard  * UltraSparc IIi I/DMMUs
37183469015Sbellard  */
3723475187dSbellard 
373536ba015SIgor Kovalenko // Returns true if TTE tag is valid and matches virtual address value in context
374536ba015SIgor Kovalenko // requires virtual address mask value calculated from TTE entry size
3756e8e7d4cSIgor Kovalenko static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
376536ba015SIgor Kovalenko                                        uint64_t address, uint64_t context,
377299b520cSIgor V. Kovalenko                                        target_phys_addr_t *physical)
378536ba015SIgor Kovalenko {
379536ba015SIgor Kovalenko     uint64_t mask;
380536ba015SIgor Kovalenko 
38106e12b65STsuneo Saito     switch (TTE_PGSIZE(tlb->tte)) {
3823475187dSbellard     default:
38383469015Sbellard     case 0x0: // 8k
3843475187dSbellard         mask = 0xffffffffffffe000ULL;
3853475187dSbellard         break;
38683469015Sbellard     case 0x1: // 64k
3873475187dSbellard         mask = 0xffffffffffff0000ULL;
3883475187dSbellard         break;
38983469015Sbellard     case 0x2: // 512k
3903475187dSbellard         mask = 0xfffffffffff80000ULL;
3913475187dSbellard         break;
39283469015Sbellard     case 0x3: // 4M
3933475187dSbellard         mask = 0xffffffffffc00000ULL;
3943475187dSbellard         break;
3953475187dSbellard     }
396536ba015SIgor Kovalenko 
397536ba015SIgor Kovalenko     // valid, context match, virtual address match?
398f707726eSIgor Kovalenko     if (TTE_IS_VALID(tlb->tte) &&
399299b520cSIgor V. Kovalenko         (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
4002a90358fSBlue Swirl         && compare_masked(address, tlb->tag, mask))
401536ba015SIgor Kovalenko     {
402536ba015SIgor Kovalenko         // decode physical address
4036e8e7d4cSIgor Kovalenko         *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
404536ba015SIgor Kovalenko         return 1;
405536ba015SIgor Kovalenko     }
406536ba015SIgor Kovalenko 
407536ba015SIgor Kovalenko     return 0;
408536ba015SIgor Kovalenko }
409536ba015SIgor Kovalenko 
410536ba015SIgor Kovalenko static int get_physical_address_data(CPUState *env,
411c227f099SAnthony Liguori                                      target_phys_addr_t *physical, int *prot,
4122065061eSIgor V. Kovalenko                                      target_ulong address, int rw, int mmu_idx)
413536ba015SIgor Kovalenko {
414536ba015SIgor Kovalenko     unsigned int i;
415536ba015SIgor Kovalenko     uint64_t context;
416ccc76c24STsuneo Saito     uint64_t sfsr = 0;
417536ba015SIgor Kovalenko 
4182065061eSIgor V. Kovalenko     int is_user = (mmu_idx == MMU_USER_IDX ||
4192065061eSIgor V. Kovalenko                    mmu_idx == MMU_USER_SECONDARY_IDX);
4202065061eSIgor V. Kovalenko 
421536ba015SIgor Kovalenko     if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
422536ba015SIgor Kovalenko         *physical = ultrasparc_truncate_physical(address);
423536ba015SIgor Kovalenko         *prot = PAGE_READ | PAGE_WRITE;
424536ba015SIgor Kovalenko         return 0;
425536ba015SIgor Kovalenko     }
426536ba015SIgor Kovalenko 
4272065061eSIgor V. Kovalenko     switch(mmu_idx) {
4282065061eSIgor V. Kovalenko     case MMU_USER_IDX:
4292065061eSIgor V. Kovalenko     case MMU_KERNEL_IDX:
4306e8e7d4cSIgor Kovalenko         context = env->dmmu.mmu_primary_context & 0x1fff;
431ccc76c24STsuneo Saito         sfsr |= SFSR_CT_PRIMARY;
4322065061eSIgor V. Kovalenko         break;
4332065061eSIgor V. Kovalenko     case MMU_USER_SECONDARY_IDX:
4342065061eSIgor V. Kovalenko     case MMU_KERNEL_SECONDARY_IDX:
4352065061eSIgor V. Kovalenko         context = env->dmmu.mmu_secondary_context & 0x1fff;
436ccc76c24STsuneo Saito         sfsr |= SFSR_CT_SECONDARY;
4372065061eSIgor V. Kovalenko         break;
4382065061eSIgor V. Kovalenko     case MMU_NUCLEUS_IDX:
439ccc76c24STsuneo Saito         sfsr |= SFSR_CT_NUCLEUS;
440ccc76c24STsuneo Saito         /* FALLTHRU */
44144505216SBlue Swirl     default:
442299b520cSIgor V. Kovalenko         context = 0;
4432065061eSIgor V. Kovalenko         break;
444299b520cSIgor V. Kovalenko     }
445536ba015SIgor Kovalenko 
446ccc76c24STsuneo Saito     if (rw == 1) {
447ccc76c24STsuneo Saito         sfsr |= SFSR_WRITE_BIT;
448ccc76c24STsuneo Saito     }
449ccc76c24STsuneo Saito 
450536ba015SIgor Kovalenko     for (i = 0; i < 64; i++) {
451afdf8109Sblueswir1         // ctx match, vaddr match, valid?
452b8e9fc06SIgor V. Kovalenko         if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
453b8e9fc06SIgor V. Kovalenko 
454b8e9fc06SIgor V. Kovalenko             // access ok?
45506e12b65STsuneo Saito             if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
456ccc76c24STsuneo Saito                 sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */
457b8e9fc06SIgor V. Kovalenko                 env->exception_index = TT_DFAULT;
458b8e9fc06SIgor V. Kovalenko 
459b8e9fc06SIgor V. Kovalenko                 DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64
460b8e9fc06SIgor V. Kovalenko                             " mmu_idx=%d tl=%d\n",
461b8e9fc06SIgor V. Kovalenko                             address, context, mmu_idx, env->tl);
46206e12b65STsuneo Saito             } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) {
463b8e9fc06SIgor V. Kovalenko                 env->exception_index = TT_DPROT;
464b8e9fc06SIgor V. Kovalenko 
465b8e9fc06SIgor V. Kovalenko                 DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64
466b8e9fc06SIgor V. Kovalenko                             " mmu_idx=%d tl=%d\n",
467b8e9fc06SIgor V. Kovalenko                             address, context, mmu_idx, env->tl);
468b8e9fc06SIgor V. Kovalenko             } else {
469b8e9fc06SIgor V. Kovalenko                 *prot = PAGE_READ;
47006e12b65STsuneo Saito                 if (TTE_IS_W_OK(env->dtlb[i].tte)) {
471b8e9fc06SIgor V. Kovalenko                     *prot |= PAGE_WRITE;
47206e12b65STsuneo Saito                 }
473b8e9fc06SIgor V. Kovalenko 
474b8e9fc06SIgor V. Kovalenko                 TTE_SET_USED(env->dtlb[i].tte);
475b8e9fc06SIgor V. Kovalenko 
476b8e9fc06SIgor V. Kovalenko                 return 0;
4776e8e7d4cSIgor Kovalenko             }
4786e8e7d4cSIgor Kovalenko 
479ccc76c24STsuneo Saito             if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
480ccc76c24STsuneo Saito                 sfsr |= SFSR_OW_BIT; /* overflow (not read before
48177f193daSblueswir1                                         another fault) */
482ccc76c24STsuneo Saito             }
4836e8e7d4cSIgor Kovalenko 
484ccc76c24STsuneo Saito             if (env->pstate & PS_PRIV) {
485ccc76c24STsuneo Saito                 sfsr |= SFSR_PR_BIT;
486ccc76c24STsuneo Saito             }
4876e8e7d4cSIgor Kovalenko 
488ccc76c24STsuneo Saito             /* FIXME: ASI field in SFSR must be set */
489ccc76c24STsuneo Saito             env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
4906e8e7d4cSIgor Kovalenko 
4916e8e7d4cSIgor Kovalenko             env->dmmu.sfar = address; /* Fault address register */
4929168b3a5SIgor V. Kovalenko 
4939168b3a5SIgor V. Kovalenko             env->dmmu.tag_access = (address & ~0x1fffULL) | context;
4949168b3a5SIgor V. Kovalenko 
4953475187dSbellard             return 1;
4963475187dSbellard         }
4973475187dSbellard     }
498b8e9fc06SIgor V. Kovalenko 
499b8e9fc06SIgor V. Kovalenko     DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n",
500b8e9fc06SIgor V. Kovalenko                 address, context);
501b8e9fc06SIgor V. Kovalenko 
502ccc76c24STsuneo Saito     /*
503ccc76c24STsuneo Saito      * On MMU misses:
504ccc76c24STsuneo Saito      * - UltraSPARC IIi: SFSR and SFAR unmodified
505ccc76c24STsuneo Saito      * - JPS1: SFAR updated and some fields of SFSR updated
506ccc76c24STsuneo Saito      */
5076e8e7d4cSIgor Kovalenko     env->dmmu.tag_access = (address & ~0x1fffULL) | context;
50883469015Sbellard     env->exception_index = TT_DMISS;
5093475187dSbellard     return 1;
5103475187dSbellard }
5113475187dSbellard 
51277f193daSblueswir1 static int get_physical_address_code(CPUState *env,
513c227f099SAnthony Liguori                                      target_phys_addr_t *physical, int *prot,
5142065061eSIgor V. Kovalenko                                      target_ulong address, int mmu_idx)
5153475187dSbellard {
5163475187dSbellard     unsigned int i;
517536ba015SIgor Kovalenko     uint64_t context;
5183475187dSbellard 
5192065061eSIgor V. Kovalenko     int is_user = (mmu_idx == MMU_USER_IDX ||
5202065061eSIgor V. Kovalenko                    mmu_idx == MMU_USER_SECONDARY_IDX);
5212065061eSIgor V. Kovalenko 
522e8807b14SIgor Kovalenko     if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
523e8807b14SIgor Kovalenko         /* IMMU disabled */
524e8807b14SIgor Kovalenko         *physical = ultrasparc_truncate_physical(address);
525227671c9Sbellard         *prot = PAGE_EXEC;
5263475187dSbellard         return 0;
5273475187dSbellard     }
52883469015Sbellard 
529299b520cSIgor V. Kovalenko     if (env->tl == 0) {
5302065061eSIgor V. Kovalenko         /* PRIMARY context */
5316e8e7d4cSIgor Kovalenko         context = env->dmmu.mmu_primary_context & 0x1fff;
532299b520cSIgor V. Kovalenko     } else {
5332065061eSIgor V. Kovalenko         /* NUCLEUS context */
534299b520cSIgor V. Kovalenko         context = 0;
535299b520cSIgor V. Kovalenko     }
536536ba015SIgor Kovalenko 
5373475187dSbellard     for (i = 0; i < 64; i++) {
538afdf8109Sblueswir1         // ctx match, vaddr match, valid?
5396e8e7d4cSIgor Kovalenko         if (ultrasparc_tag_match(&env->itlb[i],
540299b520cSIgor V. Kovalenko                                  address, context, physical)) {
541afdf8109Sblueswir1             // access ok?
54206e12b65STsuneo Saito             if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
543ccc76c24STsuneo Saito                 /* Fault status register */
544ccc76c24STsuneo Saito                 if (env->immu.sfsr & SFSR_VALID_BIT) {
545ccc76c24STsuneo Saito                     env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
54677f193daSblueswir1                                                      another fault) */
547ccc76c24STsuneo Saito                 } else {
548ccc76c24STsuneo Saito                     env->immu.sfsr = 0;
549ccc76c24STsuneo Saito                 }
550ccc76c24STsuneo Saito                 if (env->pstate & PS_PRIV) {
551ccc76c24STsuneo Saito                     env->immu.sfsr |= SFSR_PR_BIT;
552ccc76c24STsuneo Saito                 }
553ccc76c24STsuneo Saito                 if (env->tl > 0) {
554ccc76c24STsuneo Saito                     env->immu.sfsr |= SFSR_CT_NUCLEUS;
555ccc76c24STsuneo Saito                 }
556ccc76c24STsuneo Saito 
557ccc76c24STsuneo Saito                 /* FIXME: ASI field in SFSR must be set */
558ccc76c24STsuneo Saito                 env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
5593475187dSbellard                 env->exception_index = TT_TFAULT;
560b8e9fc06SIgor V. Kovalenko 
5619168b3a5SIgor V. Kovalenko                 env->immu.tag_access = (address & ~0x1fffULL) | context;
5629168b3a5SIgor V. Kovalenko 
563b8e9fc06SIgor V. Kovalenko                 DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n",
564b8e9fc06SIgor V. Kovalenko                             address, context);
565b8e9fc06SIgor V. Kovalenko 
5663475187dSbellard                 return 1;
5673475187dSbellard             }
568227671c9Sbellard             *prot = PAGE_EXEC;
569f707726eSIgor Kovalenko             TTE_SET_USED(env->itlb[i].tte);
5703475187dSbellard             return 0;
5713475187dSbellard         }
5723475187dSbellard     }
573b8e9fc06SIgor V. Kovalenko 
574b8e9fc06SIgor V. Kovalenko     DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n",
575b8e9fc06SIgor V. Kovalenko                 address, context);
576b8e9fc06SIgor V. Kovalenko 
5777ab463cbSBlue Swirl     /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
5786e8e7d4cSIgor Kovalenko     env->immu.tag_access = (address & ~0x1fffULL) | context;
57983469015Sbellard     env->exception_index = TT_TMISS;
5803475187dSbellard     return 1;
5813475187dSbellard }
5823475187dSbellard 
583c227f099SAnthony Liguori static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
584c48fcb47Sblueswir1                                 int *prot, int *access_index,
585d4c430a8SPaul Brook                                 target_ulong address, int rw, int mmu_idx,
586d4c430a8SPaul Brook                                 target_ulong *page_size)
5873475187dSbellard {
588d4c430a8SPaul Brook     /* ??? We treat everything as a small page, then explicitly flush
589d4c430a8SPaul Brook        everything when an entry is evicted.  */
590d4c430a8SPaul Brook     *page_size = TARGET_PAGE_SIZE;
5919fd1ae3aSIgor V. Kovalenko 
5929fd1ae3aSIgor V. Kovalenko #if defined (DEBUG_MMU)
5939fd1ae3aSIgor V. Kovalenko     /* safety net to catch wrong softmmu index use from dynamic code */
5949fd1ae3aSIgor V. Kovalenko     if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
5959fd1ae3aSIgor V. Kovalenko         DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d"
5969fd1ae3aSIgor V. Kovalenko                     " primary context=%" PRIx64
5979fd1ae3aSIgor V. Kovalenko                     " secondary context=%" PRIx64
5989fd1ae3aSIgor V. Kovalenko                 " address=%" PRIx64
5999fd1ae3aSIgor V. Kovalenko                 "\n",
6009fd1ae3aSIgor V. Kovalenko                 (rw == 2 ? "CODE" : "DATA"),
6019fd1ae3aSIgor V. Kovalenko                 env->tl, mmu_idx,
6029fd1ae3aSIgor V. Kovalenko                 env->dmmu.mmu_primary_context,
6039fd1ae3aSIgor V. Kovalenko                 env->dmmu.mmu_secondary_context,
6049fd1ae3aSIgor V. Kovalenko                 address);
6059fd1ae3aSIgor V. Kovalenko     }
6069fd1ae3aSIgor V. Kovalenko #endif
6079fd1ae3aSIgor V. Kovalenko 
6083475187dSbellard     if (rw == 2)
60922548760Sblueswir1         return get_physical_address_code(env, physical, prot, address,
6102065061eSIgor V. Kovalenko                                          mmu_idx);
6113475187dSbellard     else
61222548760Sblueswir1         return get_physical_address_data(env, physical, prot, address, rw,
6132065061eSIgor V. Kovalenko                                          mmu_idx);
6143475187dSbellard }
6153475187dSbellard 
6163475187dSbellard /* Perform address translation */
6173475187dSbellard int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
6186ebbf390Sj_mayer                               int mmu_idx, int is_softmmu)
6193475187dSbellard {
62083469015Sbellard     target_ulong virt_addr, vaddr;
621c227f099SAnthony Liguori     target_phys_addr_t paddr;
622d4c430a8SPaul Brook     target_ulong page_size;
623d4c430a8SPaul Brook     int error_code = 0, prot, access_index;
6243475187dSbellard 
62577f193daSblueswir1     error_code = get_physical_address(env, &paddr, &prot, &access_index,
626d4c430a8SPaul Brook                                       address, rw, mmu_idx, &page_size);
6273475187dSbellard     if (error_code == 0) {
6283475187dSbellard         virt_addr = address & TARGET_PAGE_MASK;
62977f193daSblueswir1         vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
63077f193daSblueswir1                              (TARGET_PAGE_SIZE - 1));
631b8e9fc06SIgor V. Kovalenko 
632b8e9fc06SIgor V. Kovalenko         DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 ","
633b8e9fc06SIgor V. Kovalenko                     " vaddr %" PRIx64
634b8e9fc06SIgor V. Kovalenko                     " mmu_idx=%d"
635b8e9fc06SIgor V. Kovalenko                     " tl=%d"
636b8e9fc06SIgor V. Kovalenko                     " primary context=%" PRIx64
637b8e9fc06SIgor V. Kovalenko                     " secondary context=%" PRIx64
638b8e9fc06SIgor V. Kovalenko                     "\n",
639b8e9fc06SIgor V. Kovalenko                     address, paddr, vaddr, mmu_idx, env->tl,
640b8e9fc06SIgor V. Kovalenko                     env->dmmu.mmu_primary_context,
641b8e9fc06SIgor V. Kovalenko                     env->dmmu.mmu_secondary_context);
642b8e9fc06SIgor V. Kovalenko 
643d4c430a8SPaul Brook         tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
644d4c430a8SPaul Brook         return 0;
6453475187dSbellard     }
6463475187dSbellard     // XXX
6473475187dSbellard     return 1;
6483475187dSbellard }
6493475187dSbellard 
650d41160a3SBlue Swirl void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
65183469015Sbellard {
65283469015Sbellard     unsigned int i;
65383469015Sbellard     const char *mask;
65483469015Sbellard 
655d41160a3SBlue Swirl     (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
656d41160a3SBlue Swirl                    PRId64 "\n",
657d41160a3SBlue Swirl                    env->dmmu.mmu_primary_context,
658d41160a3SBlue Swirl                    env->dmmu.mmu_secondary_context);
65983469015Sbellard     if ((env->lsu & DMMU_E) == 0) {
660d41160a3SBlue Swirl         (*cpu_fprintf)(f, "DMMU disabled\n");
66183469015Sbellard     } else {
662d41160a3SBlue Swirl         (*cpu_fprintf)(f, "DMMU dump\n");
66383469015Sbellard         for (i = 0; i < 64; i++) {
66406e12b65STsuneo Saito             switch (TTE_PGSIZE(env->dtlb[i].tte)) {
66583469015Sbellard             default:
66683469015Sbellard             case 0x0:
66783469015Sbellard                 mask = "  8k";
66883469015Sbellard                 break;
66983469015Sbellard             case 0x1:
67083469015Sbellard                 mask = " 64k";
67183469015Sbellard                 break;
67283469015Sbellard             case 0x2:
67383469015Sbellard                 mask = "512k";
67483469015Sbellard                 break;
67583469015Sbellard             case 0x3:
67683469015Sbellard                 mask = "  4M";
67783469015Sbellard                 break;
67883469015Sbellard             }
67906e12b65STsuneo Saito             if (TTE_IS_VALID(env->dtlb[i].tte)) {
680d41160a3SBlue Swirl                 (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %" PRIx64
6812a90358fSBlue Swirl                                ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
6826e8e7d4cSIgor Kovalenko                                i,
68331a68d57SBlue Swirl                                env->dtlb[i].tag & (uint64_t)~0x1fffULL,
68406e12b65STsuneo Saito                                TTE_PA(env->dtlb[i].tte),
68583469015Sbellard                                mask,
68606e12b65STsuneo Saito                                TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user",
68706e12b65STsuneo Saito                                TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO",
68806e12b65STsuneo Saito                                TTE_IS_LOCKED(env->dtlb[i].tte) ?
68906e12b65STsuneo Saito                                "locked" : "unlocked",
6902a90358fSBlue Swirl                                env->dtlb[i].tag & (uint64_t)0x1fffULL,
691d41160a3SBlue Swirl                                TTE_IS_GLOBAL(env->dtlb[i].tte)?
692d41160a3SBlue Swirl                                "global" : "local");
69383469015Sbellard             }
69483469015Sbellard         }
69583469015Sbellard     }
69683469015Sbellard     if ((env->lsu & IMMU_E) == 0) {
697d41160a3SBlue Swirl         (*cpu_fprintf)(f, "IMMU disabled\n");
69883469015Sbellard     } else {
699d41160a3SBlue Swirl         (*cpu_fprintf)(f, "IMMU dump\n");
70083469015Sbellard         for (i = 0; i < 64; i++) {
70106e12b65STsuneo Saito             switch (TTE_PGSIZE(env->itlb[i].tte)) {
70283469015Sbellard             default:
70383469015Sbellard             case 0x0:
70483469015Sbellard                 mask = "  8k";
70583469015Sbellard                 break;
70683469015Sbellard             case 0x1:
70783469015Sbellard                 mask = " 64k";
70883469015Sbellard                 break;
70983469015Sbellard             case 0x2:
71083469015Sbellard                 mask = "512k";
71183469015Sbellard                 break;
71283469015Sbellard             case 0x3:
71383469015Sbellard                 mask = "  4M";
71483469015Sbellard                 break;
71583469015Sbellard             }
71606e12b65STsuneo Saito             if (TTE_IS_VALID(env->itlb[i].tte)) {
717d41160a3SBlue Swirl                 (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %" PRIx64
7182a90358fSBlue Swirl                                ", %s, %s, %s, ctx %" PRId64 " %s\n",
7196e8e7d4cSIgor Kovalenko                                i,
7206e8e7d4cSIgor Kovalenko                                env->itlb[i].tag & (uint64_t)~0x1fffULL,
72106e12b65STsuneo Saito                                TTE_PA(env->itlb[i].tte),
72283469015Sbellard                                mask,
72306e12b65STsuneo Saito                                TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user",
72406e12b65STsuneo Saito                                TTE_IS_LOCKED(env->itlb[i].tte) ?
72506e12b65STsuneo Saito                                "locked" : "unlocked",
7262a90358fSBlue Swirl                                env->itlb[i].tag & (uint64_t)0x1fffULL,
727d41160a3SBlue Swirl                                TTE_IS_GLOBAL(env->itlb[i].tte)?
728d41160a3SBlue Swirl                                "global" : "local");
72983469015Sbellard             }
73083469015Sbellard         }
73183469015Sbellard     }
73283469015Sbellard }
73324741ef3Sbellard 
73424741ef3Sbellard #endif /* TARGET_SPARC64 */
73524741ef3Sbellard #endif /* !CONFIG_USER_ONLY */
73624741ef3Sbellard 
737c48fcb47Sblueswir1 
7384fcc562bSPaul Brook #if !defined(CONFIG_USER_ONLY)
739321365abSTsuneo Saito static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys,
740321365abSTsuneo Saito                                    target_ulong addr, int rw, int mmu_idx)
741321365abSTsuneo Saito {
742321365abSTsuneo Saito     target_ulong page_size;
743321365abSTsuneo Saito     int prot, access_index;
744321365abSTsuneo Saito 
745321365abSTsuneo Saito     return get_physical_address(env, phys, &prot, &access_index, addr, rw,
746321365abSTsuneo Saito                                 mmu_idx, &page_size);
747321365abSTsuneo Saito }
748321365abSTsuneo Saito 
749b64b6436STsuneo Saito #if defined(TARGET_SPARC64)
7502065061eSIgor V. Kovalenko target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
7512065061eSIgor V. Kovalenko                                            int mmu_idx)
752c48fcb47Sblueswir1 {
753c227f099SAnthony Liguori     target_phys_addr_t phys_addr;
754c48fcb47Sblueswir1 
755321365abSTsuneo Saito     if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) {
756321365abSTsuneo Saito         if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) {
757c48fcb47Sblueswir1             return -1;
758321365abSTsuneo Saito         }
759321365abSTsuneo Saito     }
760c48fcb47Sblueswir1     if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED)
761c48fcb47Sblueswir1         return -1;
762c48fcb47Sblueswir1     return phys_addr;
763c48fcb47Sblueswir1 }
764b64b6436STsuneo Saito #endif
7652065061eSIgor V. Kovalenko 
7662065061eSIgor V. Kovalenko target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
7672065061eSIgor V. Kovalenko {
768b64b6436STsuneo Saito     target_phys_addr_t phys_addr;
769b64b6436STsuneo Saito     int mmu_idx = cpu_mmu_index(env);
770b64b6436STsuneo Saito 
771b64b6436STsuneo Saito     if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) {
772b64b6436STsuneo Saito         if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) {
773b64b6436STsuneo Saito             return -1;
774b64b6436STsuneo Saito         }
775b64b6436STsuneo Saito     }
776b64b6436STsuneo Saito     if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) {
777b64b6436STsuneo Saito         return -1;
778b64b6436STsuneo Saito     }
779b64b6436STsuneo Saito     return phys_addr;
7802065061eSIgor V. Kovalenko }
781c48fcb47Sblueswir1 #endif
782c48fcb47Sblueswir1 
783e67768d0SBlue Swirl #ifdef TARGET_SPARC64
784e67768d0SBlue Swirl #ifdef DEBUG_PCALL
785e67768d0SBlue Swirl static const char * const excp_names[0x80] = {
786e67768d0SBlue Swirl     [TT_TFAULT] = "Instruction Access Fault",
787e67768d0SBlue Swirl     [TT_TMISS] = "Instruction Access MMU Miss",
788e67768d0SBlue Swirl     [TT_CODE_ACCESS] = "Instruction Access Error",
789e67768d0SBlue Swirl     [TT_ILL_INSN] = "Illegal Instruction",
790e67768d0SBlue Swirl     [TT_PRIV_INSN] = "Privileged Instruction",
791e67768d0SBlue Swirl     [TT_NFPU_INSN] = "FPU Disabled",
792e67768d0SBlue Swirl     [TT_FP_EXCP] = "FPU Exception",
793e67768d0SBlue Swirl     [TT_TOVF] = "Tag Overflow",
794e67768d0SBlue Swirl     [TT_CLRWIN] = "Clean Windows",
795e67768d0SBlue Swirl     [TT_DIV_ZERO] = "Division By Zero",
796e67768d0SBlue Swirl     [TT_DFAULT] = "Data Access Fault",
797e67768d0SBlue Swirl     [TT_DMISS] = "Data Access MMU Miss",
798e67768d0SBlue Swirl     [TT_DATA_ACCESS] = "Data Access Error",
799e67768d0SBlue Swirl     [TT_DPROT] = "Data Protection Error",
800e67768d0SBlue Swirl     [TT_UNALIGNED] = "Unaligned Memory Access",
801e67768d0SBlue Swirl     [TT_PRIV_ACT] = "Privileged Action",
802e67768d0SBlue Swirl     [TT_EXTINT | 0x1] = "External Interrupt 1",
803e67768d0SBlue Swirl     [TT_EXTINT | 0x2] = "External Interrupt 2",
804e67768d0SBlue Swirl     [TT_EXTINT | 0x3] = "External Interrupt 3",
805e67768d0SBlue Swirl     [TT_EXTINT | 0x4] = "External Interrupt 4",
806e67768d0SBlue Swirl     [TT_EXTINT | 0x5] = "External Interrupt 5",
807e67768d0SBlue Swirl     [TT_EXTINT | 0x6] = "External Interrupt 6",
808e67768d0SBlue Swirl     [TT_EXTINT | 0x7] = "External Interrupt 7",
809e67768d0SBlue Swirl     [TT_EXTINT | 0x8] = "External Interrupt 8",
810e67768d0SBlue Swirl     [TT_EXTINT | 0x9] = "External Interrupt 9",
811e67768d0SBlue Swirl     [TT_EXTINT | 0xa] = "External Interrupt 10",
812e67768d0SBlue Swirl     [TT_EXTINT | 0xb] = "External Interrupt 11",
813e67768d0SBlue Swirl     [TT_EXTINT | 0xc] = "External Interrupt 12",
814e67768d0SBlue Swirl     [TT_EXTINT | 0xd] = "External Interrupt 13",
815e67768d0SBlue Swirl     [TT_EXTINT | 0xe] = "External Interrupt 14",
816e67768d0SBlue Swirl     [TT_EXTINT | 0xf] = "External Interrupt 15",
817e67768d0SBlue Swirl };
818e67768d0SBlue Swirl #endif
819e67768d0SBlue Swirl 
820e67768d0SBlue Swirl void do_interrupt(CPUState *env)
821e67768d0SBlue Swirl {
822e67768d0SBlue Swirl     int intno = env->exception_index;
823e67768d0SBlue Swirl     trap_state *tsptr;
824e67768d0SBlue Swirl 
825e67768d0SBlue Swirl #ifdef DEBUG_PCALL
826e67768d0SBlue Swirl     if (qemu_loglevel_mask(CPU_LOG_INT)) {
827e67768d0SBlue Swirl         static int count;
828e67768d0SBlue Swirl         const char *name;
829e67768d0SBlue Swirl 
830e67768d0SBlue Swirl         if (intno < 0 || intno >= 0x180) {
831e67768d0SBlue Swirl             name = "Unknown";
832e67768d0SBlue Swirl         } else if (intno >= 0x100) {
833e67768d0SBlue Swirl             name = "Trap Instruction";
834e67768d0SBlue Swirl         } else if (intno >= 0xc0) {
835e67768d0SBlue Swirl             name = "Window Fill";
836e67768d0SBlue Swirl         } else if (intno >= 0x80) {
837e67768d0SBlue Swirl             name = "Window Spill";
838e67768d0SBlue Swirl         } else {
839e67768d0SBlue Swirl             name = excp_names[intno];
840e67768d0SBlue Swirl             if (!name) {
841e67768d0SBlue Swirl                 name = "Unknown";
842e67768d0SBlue Swirl             }
843e67768d0SBlue Swirl         }
844e67768d0SBlue Swirl 
845e67768d0SBlue Swirl         qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64
846e67768d0SBlue Swirl                 " SP=%016" PRIx64 "\n",
847e67768d0SBlue Swirl                 count, name, intno,
848e67768d0SBlue Swirl                 env->pc,
849e67768d0SBlue Swirl                 env->npc, env->regwptr[6]);
850e67768d0SBlue Swirl         log_cpu_state(env, 0);
851e67768d0SBlue Swirl #if 0
852e67768d0SBlue Swirl         {
853e67768d0SBlue Swirl             int i;
854e67768d0SBlue Swirl             uint8_t *ptr;
855e67768d0SBlue Swirl 
856e67768d0SBlue Swirl             qemu_log("       code=");
857e67768d0SBlue Swirl             ptr = (uint8_t *)env->pc;
858e67768d0SBlue Swirl             for (i = 0; i < 16; i++) {
859e67768d0SBlue Swirl                 qemu_log(" %02x", ldub(ptr + i));
860e67768d0SBlue Swirl             }
861e67768d0SBlue Swirl             qemu_log("\n");
862e67768d0SBlue Swirl         }
863e67768d0SBlue Swirl #endif
864e67768d0SBlue Swirl         count++;
865e67768d0SBlue Swirl     }
866e67768d0SBlue Swirl #endif
867e67768d0SBlue Swirl #if !defined(CONFIG_USER_ONLY)
868e67768d0SBlue Swirl     if (env->tl >= env->maxtl) {
869e67768d0SBlue Swirl         cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
870e67768d0SBlue Swirl                   " Error state", env->exception_index, env->tl, env->maxtl);
871e67768d0SBlue Swirl         return;
872e67768d0SBlue Swirl     }
873e67768d0SBlue Swirl #endif
874e67768d0SBlue Swirl     if (env->tl < env->maxtl - 1) {
875e67768d0SBlue Swirl         env->tl++;
876e67768d0SBlue Swirl     } else {
877e67768d0SBlue Swirl         env->pstate |= PS_RED;
878e67768d0SBlue Swirl         if (env->tl < env->maxtl) {
879e67768d0SBlue Swirl             env->tl++;
880e67768d0SBlue Swirl         }
881e67768d0SBlue Swirl     }
882e67768d0SBlue Swirl     tsptr = cpu_tsptr(env);
883e67768d0SBlue Swirl 
884e67768d0SBlue Swirl     tsptr->tstate = (cpu_get_ccr(env) << 32) |
885e67768d0SBlue Swirl         ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
886e67768d0SBlue Swirl         cpu_get_cwp64(env);
887e67768d0SBlue Swirl     tsptr->tpc = env->pc;
888e67768d0SBlue Swirl     tsptr->tnpc = env->npc;
889e67768d0SBlue Swirl     tsptr->tt = intno;
890e67768d0SBlue Swirl 
891e67768d0SBlue Swirl     switch (intno) {
892e67768d0SBlue Swirl     case TT_IVEC:
893e67768d0SBlue Swirl         cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
894e67768d0SBlue Swirl         break;
895e67768d0SBlue Swirl     case TT_TFAULT:
896e67768d0SBlue Swirl     case TT_DFAULT:
897e67768d0SBlue Swirl     case TT_TMISS ... TT_TMISS + 3:
898e67768d0SBlue Swirl     case TT_DMISS ... TT_DMISS + 3:
899e67768d0SBlue Swirl     case TT_DPROT ... TT_DPROT + 3:
900e67768d0SBlue Swirl         cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG);
901e67768d0SBlue Swirl         break;
902e67768d0SBlue Swirl     default:
903e67768d0SBlue Swirl         cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG);
904e67768d0SBlue Swirl         break;
905e67768d0SBlue Swirl     }
906e67768d0SBlue Swirl 
907e67768d0SBlue Swirl     if (intno == TT_CLRWIN) {
908e67768d0SBlue Swirl         cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1));
909e67768d0SBlue Swirl     } else if ((intno & 0x1c0) == TT_SPILL) {
910e67768d0SBlue Swirl         cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
911e67768d0SBlue Swirl     } else if ((intno & 0x1c0) == TT_FILL) {
912e67768d0SBlue Swirl         cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
913e67768d0SBlue Swirl     }
914e67768d0SBlue Swirl     env->tbr &= ~0x7fffULL;
915e67768d0SBlue Swirl     env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
916e67768d0SBlue Swirl     env->pc = env->tbr;
917e67768d0SBlue Swirl     env->npc = env->pc + 4;
918e67768d0SBlue Swirl     env->exception_index = -1;
919e67768d0SBlue Swirl }
920e67768d0SBlue Swirl #else
921e67768d0SBlue Swirl #ifdef DEBUG_PCALL
922e67768d0SBlue Swirl static const char * const excp_names[0x80] = {
923e67768d0SBlue Swirl     [TT_TFAULT] = "Instruction Access Fault",
924e67768d0SBlue Swirl     [TT_ILL_INSN] = "Illegal Instruction",
925e67768d0SBlue Swirl     [TT_PRIV_INSN] = "Privileged Instruction",
926e67768d0SBlue Swirl     [TT_NFPU_INSN] = "FPU Disabled",
927e67768d0SBlue Swirl     [TT_WIN_OVF] = "Window Overflow",
928e67768d0SBlue Swirl     [TT_WIN_UNF] = "Window Underflow",
929e67768d0SBlue Swirl     [TT_UNALIGNED] = "Unaligned Memory Access",
930e67768d0SBlue Swirl     [TT_FP_EXCP] = "FPU Exception",
931e67768d0SBlue Swirl     [TT_DFAULT] = "Data Access Fault",
932e67768d0SBlue Swirl     [TT_TOVF] = "Tag Overflow",
933e67768d0SBlue Swirl     [TT_EXTINT | 0x1] = "External Interrupt 1",
934e67768d0SBlue Swirl     [TT_EXTINT | 0x2] = "External Interrupt 2",
935e67768d0SBlue Swirl     [TT_EXTINT | 0x3] = "External Interrupt 3",
936e67768d0SBlue Swirl     [TT_EXTINT | 0x4] = "External Interrupt 4",
937e67768d0SBlue Swirl     [TT_EXTINT | 0x5] = "External Interrupt 5",
938e67768d0SBlue Swirl     [TT_EXTINT | 0x6] = "External Interrupt 6",
939e67768d0SBlue Swirl     [TT_EXTINT | 0x7] = "External Interrupt 7",
940e67768d0SBlue Swirl     [TT_EXTINT | 0x8] = "External Interrupt 8",
941e67768d0SBlue Swirl     [TT_EXTINT | 0x9] = "External Interrupt 9",
942e67768d0SBlue Swirl     [TT_EXTINT | 0xa] = "External Interrupt 10",
943e67768d0SBlue Swirl     [TT_EXTINT | 0xb] = "External Interrupt 11",
944e67768d0SBlue Swirl     [TT_EXTINT | 0xc] = "External Interrupt 12",
945e67768d0SBlue Swirl     [TT_EXTINT | 0xd] = "External Interrupt 13",
946e67768d0SBlue Swirl     [TT_EXTINT | 0xe] = "External Interrupt 14",
947e67768d0SBlue Swirl     [TT_EXTINT | 0xf] = "External Interrupt 15",
948e67768d0SBlue Swirl     [TT_TOVF] = "Tag Overflow",
949e67768d0SBlue Swirl     [TT_CODE_ACCESS] = "Instruction Access Error",
950e67768d0SBlue Swirl     [TT_DATA_ACCESS] = "Data Access Error",
951e67768d0SBlue Swirl     [TT_DIV_ZERO] = "Division By Zero",
952e67768d0SBlue Swirl     [TT_NCP_INSN] = "Coprocessor Disabled",
953e67768d0SBlue Swirl };
954e67768d0SBlue Swirl #endif
955e67768d0SBlue Swirl 
956e67768d0SBlue Swirl void do_interrupt(CPUState *env)
957e67768d0SBlue Swirl {
958e67768d0SBlue Swirl     int cwp, intno = env->exception_index;
959e67768d0SBlue Swirl 
960e67768d0SBlue Swirl #ifdef DEBUG_PCALL
961e67768d0SBlue Swirl     if (qemu_loglevel_mask(CPU_LOG_INT)) {
962e67768d0SBlue Swirl         static int count;
963e67768d0SBlue Swirl         const char *name;
964e67768d0SBlue Swirl 
965e67768d0SBlue Swirl         if (intno < 0 || intno >= 0x100) {
966e67768d0SBlue Swirl             name = "Unknown";
967e67768d0SBlue Swirl         } else if (intno >= 0x80) {
968e67768d0SBlue Swirl             name = "Trap Instruction";
969e67768d0SBlue Swirl         } else {
970e67768d0SBlue Swirl             name = excp_names[intno];
971e67768d0SBlue Swirl             if (!name) {
972e67768d0SBlue Swirl                 name = "Unknown";
973e67768d0SBlue Swirl             }
974e67768d0SBlue Swirl         }
975e67768d0SBlue Swirl 
976e67768d0SBlue Swirl         qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n",
977e67768d0SBlue Swirl                 count, name, intno,
978e67768d0SBlue Swirl                 env->pc,
979e67768d0SBlue Swirl                 env->npc, env->regwptr[6]);
980e67768d0SBlue Swirl         log_cpu_state(env, 0);
981e67768d0SBlue Swirl #if 0
982e67768d0SBlue Swirl         {
983e67768d0SBlue Swirl             int i;
984e67768d0SBlue Swirl             uint8_t *ptr;
985e67768d0SBlue Swirl 
986e67768d0SBlue Swirl             qemu_log("       code=");
987e67768d0SBlue Swirl             ptr = (uint8_t *)env->pc;
988e67768d0SBlue Swirl             for (i = 0; i < 16; i++) {
989e67768d0SBlue Swirl                 qemu_log(" %02x", ldub(ptr + i));
990e67768d0SBlue Swirl             }
991e67768d0SBlue Swirl             qemu_log("\n");
992e67768d0SBlue Swirl         }
993e67768d0SBlue Swirl #endif
994e67768d0SBlue Swirl         count++;
995e67768d0SBlue Swirl     }
996e67768d0SBlue Swirl #endif
997e67768d0SBlue Swirl #if !defined(CONFIG_USER_ONLY)
998e67768d0SBlue Swirl     if (env->psret == 0) {
999e67768d0SBlue Swirl         cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state",
1000e67768d0SBlue Swirl                   env->exception_index);
1001e67768d0SBlue Swirl         return;
1002e67768d0SBlue Swirl     }
1003e67768d0SBlue Swirl #endif
1004e67768d0SBlue Swirl     env->psret = 0;
1005e67768d0SBlue Swirl     cwp = cpu_cwp_dec(env, env->cwp - 1);
1006e67768d0SBlue Swirl     cpu_set_cwp(env, cwp);
1007e67768d0SBlue Swirl     env->regwptr[9] = env->pc;
1008e67768d0SBlue Swirl     env->regwptr[10] = env->npc;
1009e67768d0SBlue Swirl     env->psrps = env->psrs;
1010e67768d0SBlue Swirl     env->psrs = 1;
1011e67768d0SBlue Swirl     env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
1012e67768d0SBlue Swirl     env->pc = env->tbr;
1013e67768d0SBlue Swirl     env->npc = env->pc + 4;
1014e67768d0SBlue Swirl     env->exception_index = -1;
1015e67768d0SBlue Swirl 
1016e67768d0SBlue Swirl #if !defined(CONFIG_USER_ONLY)
1017e67768d0SBlue Swirl     /* IRQ acknowledgment */
1018e67768d0SBlue Swirl     if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
1019e67768d0SBlue Swirl         env->qemu_irq_ack(env->irq_manager, intno);
1020e67768d0SBlue Swirl     }
1021e67768d0SBlue Swirl #endif
1022e67768d0SBlue Swirl }
1023e67768d0SBlue Swirl #endif
1024e67768d0SBlue Swirl 
1025c48fcb47Sblueswir1 void cpu_reset(CPUSPARCState *env)
1026c48fcb47Sblueswir1 {
1027eca1bdf4Saliguori     if (qemu_loglevel_mask(CPU_LOG_RESET)) {
1028eca1bdf4Saliguori         qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
1029eca1bdf4Saliguori         log_cpu_state(env, 0);
1030eca1bdf4Saliguori     }
1031eca1bdf4Saliguori 
1032c48fcb47Sblueswir1     tlb_flush(env, 1);
1033c48fcb47Sblueswir1     env->cwp = 0;
10345210977aSIgor Kovalenko #ifndef TARGET_SPARC64
1035c48fcb47Sblueswir1     env->wim = 1;
10365210977aSIgor Kovalenko #endif
1037c48fcb47Sblueswir1     env->regwptr = env->regbase + (env->cwp * 16);
10386b743278SBlue Swirl     CC_OP = CC_OP_FLAGS;
1039c48fcb47Sblueswir1 #if defined(CONFIG_USER_ONLY)
1040c48fcb47Sblueswir1 #ifdef TARGET_SPARC64
10411a14026eSblueswir1     env->cleanwin = env->nwindows - 2;
10421a14026eSblueswir1     env->cansave = env->nwindows - 2;
1043c48fcb47Sblueswir1     env->pstate = PS_RMO | PS_PEF | PS_IE;
1044c48fcb47Sblueswir1     env->asi = 0x82; // Primary no-fault
1045c48fcb47Sblueswir1 #endif
1046c48fcb47Sblueswir1 #else
10475210977aSIgor Kovalenko #if !defined(TARGET_SPARC64)
1048c48fcb47Sblueswir1     env->psret = 0;
1049c48fcb47Sblueswir1     env->psrs = 1;
1050c48fcb47Sblueswir1     env->psrps = 1;
10512aae2b8eSIgor V. Kovalenko #endif
1052c48fcb47Sblueswir1 #ifdef TARGET_SPARC64
10538194f35aSIgor Kovalenko     env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
10542aae2b8eSIgor V. Kovalenko     env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
10558194f35aSIgor Kovalenko     env->tl = env->maxtl;
10568194f35aSIgor Kovalenko     cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
1057415fc906Sblueswir1     env->lsu = 0;
1058c48fcb47Sblueswir1 #else
1059c48fcb47Sblueswir1     env->mmuregs[0] &= ~(MMU_E | MMU_NF);
10605578ceabSblueswir1     env->mmuregs[0] |= env->def->mmu_bm;
1061c48fcb47Sblueswir1 #endif
1062e87231d4Sblueswir1     env->pc = 0;
1063c48fcb47Sblueswir1     env->npc = env->pc + 4;
1064c48fcb47Sblueswir1 #endif
1065b04d9890SFabien Chouteau     env->cache_control = 0;
1066c48fcb47Sblueswir1 }
1067c48fcb47Sblueswir1 
106864a88d5dSblueswir1 static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
1069c48fcb47Sblueswir1 {
107064a88d5dSblueswir1     sparc_def_t def1, *def = &def1;
1071c48fcb47Sblueswir1 
107264a88d5dSblueswir1     if (cpu_sparc_find_by_name(def, cpu_model) < 0)
107364a88d5dSblueswir1         return -1;
1074c48fcb47Sblueswir1 
10755578ceabSblueswir1     env->def = qemu_mallocz(sizeof(*def));
10765578ceabSblueswir1     memcpy(env->def, def, sizeof(*def));
10775578ceabSblueswir1 #if defined(CONFIG_USER_ONLY)
10785578ceabSblueswir1     if ((env->def->features & CPU_FEATURE_FLOAT))
10795578ceabSblueswir1         env->def->features |= CPU_FEATURE_FLOAT128;
10805578ceabSblueswir1 #endif
1081c48fcb47Sblueswir1     env->cpu_model_str = cpu_model;
1082c48fcb47Sblueswir1     env->version = def->iu_version;
1083c48fcb47Sblueswir1     env->fsr = def->fpu_version;
10841a14026eSblueswir1     env->nwindows = def->nwindows;
1085c48fcb47Sblueswir1 #if !defined(TARGET_SPARC64)
1086c48fcb47Sblueswir1     env->mmuregs[0] |= def->mmu_version;
1087c48fcb47Sblueswir1     cpu_sparc_set_id(env, 0);
1088963262deSblueswir1     env->mxccregs[7] |= def->mxcc_version;
10891a14026eSblueswir1 #else
1090fb79ceb9Sblueswir1     env->mmu_version = def->mmu_version;
1091c19148bdSblueswir1     env->maxtl = def->maxtl;
1092c19148bdSblueswir1     env->version |= def->maxtl << 8;
10931a14026eSblueswir1     env->version |= def->nwindows - 1;
1094c48fcb47Sblueswir1 #endif
109564a88d5dSblueswir1     return 0;
109664a88d5dSblueswir1 }
109764a88d5dSblueswir1 
109864a88d5dSblueswir1 static void cpu_sparc_close(CPUSPARCState *env)
109964a88d5dSblueswir1 {
11005578ceabSblueswir1     free(env->def);
110164a88d5dSblueswir1     free(env);
110264a88d5dSblueswir1 }
110364a88d5dSblueswir1 
110464a88d5dSblueswir1 CPUSPARCState *cpu_sparc_init(const char *cpu_model)
110564a88d5dSblueswir1 {
110664a88d5dSblueswir1     CPUSPARCState *env;
110764a88d5dSblueswir1 
110864a88d5dSblueswir1     env = qemu_mallocz(sizeof(CPUSPARCState));
110964a88d5dSblueswir1     cpu_exec_init(env);
1110c48fcb47Sblueswir1 
1111c48fcb47Sblueswir1     gen_intermediate_code_init(env);
1112c48fcb47Sblueswir1 
111364a88d5dSblueswir1     if (cpu_sparc_register(env, cpu_model) < 0) {
111464a88d5dSblueswir1         cpu_sparc_close(env);
111564a88d5dSblueswir1         return NULL;
111664a88d5dSblueswir1     }
11170bf46a40Saliguori     qemu_init_vcpu(env);
1118c48fcb47Sblueswir1 
1119c48fcb47Sblueswir1     return env;
1120c48fcb47Sblueswir1 }
1121c48fcb47Sblueswir1 
1122c48fcb47Sblueswir1 void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
1123c48fcb47Sblueswir1 {
1124c48fcb47Sblueswir1 #if !defined(TARGET_SPARC64)
1125c48fcb47Sblueswir1     env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
1126c48fcb47Sblueswir1 #endif
1127c48fcb47Sblueswir1 }
1128c48fcb47Sblueswir1 
1129c48fcb47Sblueswir1 static const sparc_def_t sparc_defs[] = {
1130c48fcb47Sblueswir1 #ifdef TARGET_SPARC64
1131c48fcb47Sblueswir1     {
1132c48fcb47Sblueswir1         .name = "Fujitsu Sparc64",
1133c19148bdSblueswir1         .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
1134c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1135fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11361a14026eSblueswir1         .nwindows = 4,
1137c19148bdSblueswir1         .maxtl = 4,
113864a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1139c48fcb47Sblueswir1     },
1140c48fcb47Sblueswir1     {
1141c48fcb47Sblueswir1         .name = "Fujitsu Sparc64 III",
1142c19148bdSblueswir1         .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
1143c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1144fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11451a14026eSblueswir1         .nwindows = 5,
1146c19148bdSblueswir1         .maxtl = 4,
114764a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1148c48fcb47Sblueswir1     },
1149c48fcb47Sblueswir1     {
1150c48fcb47Sblueswir1         .name = "Fujitsu Sparc64 IV",
1151c19148bdSblueswir1         .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
1152c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1153fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11541a14026eSblueswir1         .nwindows = 8,
1155c19148bdSblueswir1         .maxtl = 5,
115664a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1157c48fcb47Sblueswir1     },
1158c48fcb47Sblueswir1     {
1159c48fcb47Sblueswir1         .name = "Fujitsu Sparc64 V",
1160c19148bdSblueswir1         .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
1161c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1162fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11631a14026eSblueswir1         .nwindows = 8,
1164c19148bdSblueswir1         .maxtl = 5,
116564a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1166c48fcb47Sblueswir1     },
1167c48fcb47Sblueswir1     {
1168c48fcb47Sblueswir1         .name = "TI UltraSparc I",
1169c19148bdSblueswir1         .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
1170c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1171fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11721a14026eSblueswir1         .nwindows = 8,
1173c19148bdSblueswir1         .maxtl = 5,
117464a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1175c48fcb47Sblueswir1     },
1176c48fcb47Sblueswir1     {
1177c48fcb47Sblueswir1         .name = "TI UltraSparc II",
1178c19148bdSblueswir1         .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
1179c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1180fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11811a14026eSblueswir1         .nwindows = 8,
1182c19148bdSblueswir1         .maxtl = 5,
118364a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1184c48fcb47Sblueswir1     },
1185c48fcb47Sblueswir1     {
1186c48fcb47Sblueswir1         .name = "TI UltraSparc IIi",
1187c19148bdSblueswir1         .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
1188c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1189fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11901a14026eSblueswir1         .nwindows = 8,
1191c19148bdSblueswir1         .maxtl = 5,
119264a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1193c48fcb47Sblueswir1     },
1194c48fcb47Sblueswir1     {
1195c48fcb47Sblueswir1         .name = "TI UltraSparc IIe",
1196c19148bdSblueswir1         .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
1197c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1198fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11991a14026eSblueswir1         .nwindows = 8,
1200c19148bdSblueswir1         .maxtl = 5,
120164a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1202c48fcb47Sblueswir1     },
1203c48fcb47Sblueswir1     {
1204c48fcb47Sblueswir1         .name = "Sun UltraSparc III",
1205c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
1206c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1207fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12081a14026eSblueswir1         .nwindows = 8,
1209c19148bdSblueswir1         .maxtl = 5,
121064a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1211c48fcb47Sblueswir1     },
1212c48fcb47Sblueswir1     {
1213c48fcb47Sblueswir1         .name = "Sun UltraSparc III Cu",
1214c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
1215c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1216fb79ceb9Sblueswir1         .mmu_version = mmu_us_3,
12171a14026eSblueswir1         .nwindows = 8,
1218c19148bdSblueswir1         .maxtl = 5,
121964a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1220c48fcb47Sblueswir1     },
1221c48fcb47Sblueswir1     {
1222c48fcb47Sblueswir1         .name = "Sun UltraSparc IIIi",
1223c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
1224c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1225fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12261a14026eSblueswir1         .nwindows = 8,
1227c19148bdSblueswir1         .maxtl = 5,
122864a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1229c48fcb47Sblueswir1     },
1230c48fcb47Sblueswir1     {
1231c48fcb47Sblueswir1         .name = "Sun UltraSparc IV",
1232c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
1233c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1234fb79ceb9Sblueswir1         .mmu_version = mmu_us_4,
12351a14026eSblueswir1         .nwindows = 8,
1236c19148bdSblueswir1         .maxtl = 5,
123764a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1238c48fcb47Sblueswir1     },
1239c48fcb47Sblueswir1     {
1240c48fcb47Sblueswir1         .name = "Sun UltraSparc IV+",
1241c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
1242c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1243fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12441a14026eSblueswir1         .nwindows = 8,
1245c19148bdSblueswir1         .maxtl = 5,
1246fb79ceb9Sblueswir1         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
1247c48fcb47Sblueswir1     },
1248c48fcb47Sblueswir1     {
1249c48fcb47Sblueswir1         .name = "Sun UltraSparc IIIi+",
1250c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
1251c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1252fb79ceb9Sblueswir1         .mmu_version = mmu_us_3,
12531a14026eSblueswir1         .nwindows = 8,
1254c19148bdSblueswir1         .maxtl = 5,
125564a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1256c48fcb47Sblueswir1     },
1257c48fcb47Sblueswir1     {
1258c7ba218dSblueswir1         .name = "Sun UltraSparc T1",
1259c7ba218dSblueswir1         // defined in sparc_ifu_fdp.v and ctu.h
1260c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
1261c7ba218dSblueswir1         .fpu_version = 0x00000000,
1262c7ba218dSblueswir1         .mmu_version = mmu_sun4v,
1263c7ba218dSblueswir1         .nwindows = 8,
1264c19148bdSblueswir1         .maxtl = 6,
1265c7ba218dSblueswir1         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
1266c7ba218dSblueswir1         | CPU_FEATURE_GL,
1267c7ba218dSblueswir1     },
1268c7ba218dSblueswir1     {
1269c7ba218dSblueswir1         .name = "Sun UltraSparc T2",
1270c7ba218dSblueswir1         // defined in tlu_asi_ctl.v and n2_revid_cust.v
1271c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
1272c7ba218dSblueswir1         .fpu_version = 0x00000000,
1273c7ba218dSblueswir1         .mmu_version = mmu_sun4v,
1274c7ba218dSblueswir1         .nwindows = 8,
1275c19148bdSblueswir1         .maxtl = 6,
1276c7ba218dSblueswir1         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
1277c7ba218dSblueswir1         | CPU_FEATURE_GL,
1278c7ba218dSblueswir1     },
1279c7ba218dSblueswir1     {
1280c48fcb47Sblueswir1         .name = "NEC UltraSparc I",
1281c19148bdSblueswir1         .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
1282c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1283fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12841a14026eSblueswir1         .nwindows = 8,
1285c19148bdSblueswir1         .maxtl = 5,
128664a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1287c48fcb47Sblueswir1     },
1288c48fcb47Sblueswir1 #else
1289c48fcb47Sblueswir1     {
1290c48fcb47Sblueswir1         .name = "Fujitsu MB86900",
1291c48fcb47Sblueswir1         .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
1292c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1293c48fcb47Sblueswir1         .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
1294c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1295c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1296c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1297c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1298c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
12991a14026eSblueswir1         .nwindows = 7,
1300e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
1301c48fcb47Sblueswir1     },
1302c48fcb47Sblueswir1     {
1303c48fcb47Sblueswir1         .name = "Fujitsu MB86904",
1304c48fcb47Sblueswir1         .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
1305c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1306c48fcb47Sblueswir1         .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
1307c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1308c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x00ffffc0,
1309c48fcb47Sblueswir1         .mmu_cxr_mask = 0x000000ff,
1310c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016fff,
1311c48fcb47Sblueswir1         .mmu_trcr_mask = 0x00ffffff,
13121a14026eSblueswir1         .nwindows = 8,
131364a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1314c48fcb47Sblueswir1     },
1315c48fcb47Sblueswir1     {
1316c48fcb47Sblueswir1         .name = "Fujitsu MB86907",
1317c48fcb47Sblueswir1         .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
1318c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1319c48fcb47Sblueswir1         .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
1320c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1321c48fcb47Sblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1322c48fcb47Sblueswir1         .mmu_cxr_mask = 0x000000ff,
1323c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016fff,
1324c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
13251a14026eSblueswir1         .nwindows = 8,
132664a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1327c48fcb47Sblueswir1     },
1328c48fcb47Sblueswir1     {
1329c48fcb47Sblueswir1         .name = "LSI L64811",
1330c48fcb47Sblueswir1         .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
1331c48fcb47Sblueswir1         .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
1332c48fcb47Sblueswir1         .mmu_version = 0x10 << 24,
1333c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1334c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1335c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1336c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1337c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
13381a14026eSblueswir1         .nwindows = 8,
1339e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1340e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1341c48fcb47Sblueswir1     },
1342c48fcb47Sblueswir1     {
1343c48fcb47Sblueswir1         .name = "Cypress CY7C601",
1344c48fcb47Sblueswir1         .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
1345c48fcb47Sblueswir1         .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
1346c48fcb47Sblueswir1         .mmu_version = 0x10 << 24,
1347c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1348c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1349c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1350c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1351c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
13521a14026eSblueswir1         .nwindows = 8,
1353e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1354e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1355c48fcb47Sblueswir1     },
1356c48fcb47Sblueswir1     {
1357c48fcb47Sblueswir1         .name = "Cypress CY7C611",
1358c48fcb47Sblueswir1         .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
1359c48fcb47Sblueswir1         .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
1360c48fcb47Sblueswir1         .mmu_version = 0x10 << 24,
1361c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1362c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1363c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1364c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1365c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
13661a14026eSblueswir1         .nwindows = 8,
1367e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1368e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1369c48fcb47Sblueswir1     },
1370c48fcb47Sblueswir1     {
1371c48fcb47Sblueswir1         .name = "TI MicroSparc I",
1372c48fcb47Sblueswir1         .iu_version = 0x41000000,
1373c48fcb47Sblueswir1         .fpu_version = 4 << 17,
1374c48fcb47Sblueswir1         .mmu_version = 0x41000000,
1375c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1376c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1377c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1378c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016fff,
1379c48fcb47Sblueswir1         .mmu_trcr_mask = 0x0000003f,
13801a14026eSblueswir1         .nwindows = 7,
1381e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
1382e30b4678Sblueswir1         CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
1383e30b4678Sblueswir1         CPU_FEATURE_FMUL,
1384c48fcb47Sblueswir1     },
1385c48fcb47Sblueswir1     {
1386c48fcb47Sblueswir1         .name = "TI MicroSparc II",
1387c48fcb47Sblueswir1         .iu_version = 0x42000000,
1388c48fcb47Sblueswir1         .fpu_version = 4 << 17,
1389c48fcb47Sblueswir1         .mmu_version = 0x02000000,
1390c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1391c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x00ffffc0,
1392c48fcb47Sblueswir1         .mmu_cxr_mask = 0x000000ff,
1393c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016fff,
1394c48fcb47Sblueswir1         .mmu_trcr_mask = 0x00ffffff,
13951a14026eSblueswir1         .nwindows = 8,
139664a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1397c48fcb47Sblueswir1     },
1398c48fcb47Sblueswir1     {
1399c48fcb47Sblueswir1         .name = "TI MicroSparc IIep",
1400c48fcb47Sblueswir1         .iu_version = 0x42000000,
1401c48fcb47Sblueswir1         .fpu_version = 4 << 17,
1402c48fcb47Sblueswir1         .mmu_version = 0x04000000,
1403c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1404c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x00ffffc0,
1405c48fcb47Sblueswir1         .mmu_cxr_mask = 0x000000ff,
1406c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016bff,
1407c48fcb47Sblueswir1         .mmu_trcr_mask = 0x00ffffff,
14081a14026eSblueswir1         .nwindows = 8,
140964a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1410c48fcb47Sblueswir1     },
1411c48fcb47Sblueswir1     {
1412b5154bdeSblueswir1         .name = "TI SuperSparc 40", // STP1020NPGA
1413963262deSblueswir1         .iu_version = 0x41000000, // SuperSPARC 2.x
1414b5154bdeSblueswir1         .fpu_version = 0 << 17,
1415963262deSblueswir1         .mmu_version = 0x00000800, // SuperSPARC 2.x, no MXCC
1416b5154bdeSblueswir1         .mmu_bm = 0x00002000,
1417b5154bdeSblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1418b5154bdeSblueswir1         .mmu_cxr_mask = 0x0000ffff,
1419b5154bdeSblueswir1         .mmu_sfsr_mask = 0xffffffff,
1420b5154bdeSblueswir1         .mmu_trcr_mask = 0xffffffff,
14211a14026eSblueswir1         .nwindows = 8,
1422b5154bdeSblueswir1         .features = CPU_DEFAULT_FEATURES,
1423b5154bdeSblueswir1     },
1424b5154bdeSblueswir1     {
1425b5154bdeSblueswir1         .name = "TI SuperSparc 50", // STP1020PGA
1426963262deSblueswir1         .iu_version = 0x40000000, // SuperSPARC 3.x
1427b5154bdeSblueswir1         .fpu_version = 0 << 17,
1428963262deSblueswir1         .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
1429b5154bdeSblueswir1         .mmu_bm = 0x00002000,
1430b5154bdeSblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1431b5154bdeSblueswir1         .mmu_cxr_mask = 0x0000ffff,
1432b5154bdeSblueswir1         .mmu_sfsr_mask = 0xffffffff,
1433b5154bdeSblueswir1         .mmu_trcr_mask = 0xffffffff,
14341a14026eSblueswir1         .nwindows = 8,
1435b5154bdeSblueswir1         .features = CPU_DEFAULT_FEATURES,
1436b5154bdeSblueswir1     },
1437b5154bdeSblueswir1     {
1438c48fcb47Sblueswir1         .name = "TI SuperSparc 51",
1439963262deSblueswir1         .iu_version = 0x40000000, // SuperSPARC 3.x
1440c48fcb47Sblueswir1         .fpu_version = 0 << 17,
1441963262deSblueswir1         .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
1442c48fcb47Sblueswir1         .mmu_bm = 0x00002000,
1443c48fcb47Sblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1444c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000ffff,
1445c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1446c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
1447963262deSblueswir1         .mxcc_version = 0x00000104,
14481a14026eSblueswir1         .nwindows = 8,
144964a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1450c48fcb47Sblueswir1     },
1451c48fcb47Sblueswir1     {
1452b5154bdeSblueswir1         .name = "TI SuperSparc 60", // STP1020APGA
1453963262deSblueswir1         .iu_version = 0x40000000, // SuperSPARC 3.x
1454b5154bdeSblueswir1         .fpu_version = 0 << 17,
1455963262deSblueswir1         .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
1456b5154bdeSblueswir1         .mmu_bm = 0x00002000,
1457b5154bdeSblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1458b5154bdeSblueswir1         .mmu_cxr_mask = 0x0000ffff,
1459b5154bdeSblueswir1         .mmu_sfsr_mask = 0xffffffff,
1460b5154bdeSblueswir1         .mmu_trcr_mask = 0xffffffff,
14611a14026eSblueswir1         .nwindows = 8,
1462b5154bdeSblueswir1         .features = CPU_DEFAULT_FEATURES,
1463b5154bdeSblueswir1     },
1464b5154bdeSblueswir1     {
1465c48fcb47Sblueswir1         .name = "TI SuperSparc 61",
1466963262deSblueswir1         .iu_version = 0x44000000, // SuperSPARC 3.x
1467c48fcb47Sblueswir1         .fpu_version = 0 << 17,
1468963262deSblueswir1         .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
1469c48fcb47Sblueswir1         .mmu_bm = 0x00002000,
1470c48fcb47Sblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1471c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000ffff,
1472c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1473c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
1474963262deSblueswir1         .mxcc_version = 0x00000104,
1475963262deSblueswir1         .nwindows = 8,
1476963262deSblueswir1         .features = CPU_DEFAULT_FEATURES,
1477963262deSblueswir1     },
1478963262deSblueswir1     {
1479963262deSblueswir1         .name = "TI SuperSparc II",
1480963262deSblueswir1         .iu_version = 0x40000000, // SuperSPARC II 1.x
1481963262deSblueswir1         .fpu_version = 0 << 17,
1482963262deSblueswir1         .mmu_version = 0x08000000, // SuperSPARC II 1.x, MXCC
1483963262deSblueswir1         .mmu_bm = 0x00002000,
1484963262deSblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1485963262deSblueswir1         .mmu_cxr_mask = 0x0000ffff,
1486963262deSblueswir1         .mmu_sfsr_mask = 0xffffffff,
1487963262deSblueswir1         .mmu_trcr_mask = 0xffffffff,
1488963262deSblueswir1         .mxcc_version = 0x00000104,
14891a14026eSblueswir1         .nwindows = 8,
149064a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1491c48fcb47Sblueswir1     },
1492c48fcb47Sblueswir1     {
1493c48fcb47Sblueswir1         .name = "Ross RT625",
1494c48fcb47Sblueswir1         .iu_version = 0x1e000000,
1495c48fcb47Sblueswir1         .fpu_version = 1 << 17,
1496c48fcb47Sblueswir1         .mmu_version = 0x1e000000,
1497c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1498c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1499c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1500c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1501c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
15021a14026eSblueswir1         .nwindows = 8,
150364a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1504c48fcb47Sblueswir1     },
1505c48fcb47Sblueswir1     {
1506c48fcb47Sblueswir1         .name = "Ross RT620",
1507c48fcb47Sblueswir1         .iu_version = 0x1f000000,
1508c48fcb47Sblueswir1         .fpu_version = 1 << 17,
1509c48fcb47Sblueswir1         .mmu_version = 0x1f000000,
1510c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1511c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1512c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1513c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1514c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
15151a14026eSblueswir1         .nwindows = 8,
151664a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1517c48fcb47Sblueswir1     },
1518c48fcb47Sblueswir1     {
1519c48fcb47Sblueswir1         .name = "BIT B5010",
1520c48fcb47Sblueswir1         .iu_version = 0x20000000,
1521c48fcb47Sblueswir1         .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
1522c48fcb47Sblueswir1         .mmu_version = 0x20000000,
1523c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1524c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1525c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1526c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1527c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
15281a14026eSblueswir1         .nwindows = 8,
1529e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1530e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1531c48fcb47Sblueswir1     },
1532c48fcb47Sblueswir1     {
1533c48fcb47Sblueswir1         .name = "Matsushita MN10501",
1534c48fcb47Sblueswir1         .iu_version = 0x50000000,
1535c48fcb47Sblueswir1         .fpu_version = 0 << 17,
1536c48fcb47Sblueswir1         .mmu_version = 0x50000000,
1537c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1538c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1539c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1540c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1541c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
15421a14026eSblueswir1         .nwindows = 8,
1543e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
1544e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1545c48fcb47Sblueswir1     },
1546c48fcb47Sblueswir1     {
1547c48fcb47Sblueswir1         .name = "Weitek W8601",
1548c48fcb47Sblueswir1         .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
1549c48fcb47Sblueswir1         .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
1550c48fcb47Sblueswir1         .mmu_version = 0x10 << 24,
1551c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1552c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1553c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1554c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1555c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
15561a14026eSblueswir1         .nwindows = 8,
155764a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1558c48fcb47Sblueswir1     },
1559c48fcb47Sblueswir1     {
1560c48fcb47Sblueswir1         .name = "LEON2",
1561c48fcb47Sblueswir1         .iu_version = 0xf2000000,
1562c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1563c48fcb47Sblueswir1         .mmu_version = 0xf2000000,
1564c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1565c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1566c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1567c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1568c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
15691a14026eSblueswir1         .nwindows = 8,
1570b04d9890SFabien Chouteau         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
1571c48fcb47Sblueswir1     },
1572c48fcb47Sblueswir1     {
1573c48fcb47Sblueswir1         .name = "LEON3",
1574c48fcb47Sblueswir1         .iu_version = 0xf3000000,
1575c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1576c48fcb47Sblueswir1         .mmu_version = 0xf3000000,
1577b04d9890SFabien Chouteau         .mmu_bm = 0x00000000,
1578c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1579c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1580c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1581c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
15821a14026eSblueswir1         .nwindows = 8,
15834a2ba232SFabien Chouteau         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
158460f356e8SFabien Chouteau         CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
1585c48fcb47Sblueswir1     },
1586c48fcb47Sblueswir1 #endif
1587c48fcb47Sblueswir1 };
1588c48fcb47Sblueswir1 
158964a88d5dSblueswir1 static const char * const feature_name[] = {
159064a88d5dSblueswir1     "float",
159164a88d5dSblueswir1     "float128",
159264a88d5dSblueswir1     "swap",
159364a88d5dSblueswir1     "mul",
159464a88d5dSblueswir1     "div",
159564a88d5dSblueswir1     "flush",
159664a88d5dSblueswir1     "fsqrt",
159764a88d5dSblueswir1     "fmul",
159864a88d5dSblueswir1     "vis1",
159964a88d5dSblueswir1     "vis2",
1600e30b4678Sblueswir1     "fsmuld",
1601fb79ceb9Sblueswir1     "hypv",
1602fb79ceb9Sblueswir1     "cmt",
1603fb79ceb9Sblueswir1     "gl",
160464a88d5dSblueswir1 };
160564a88d5dSblueswir1 
16069a78eeadSStefan Weil static void print_features(FILE *f, fprintf_function cpu_fprintf,
160764a88d5dSblueswir1                            uint32_t features, const char *prefix)
1608c48fcb47Sblueswir1 {
1609c48fcb47Sblueswir1     unsigned int i;
1610c48fcb47Sblueswir1 
161164a88d5dSblueswir1     for (i = 0; i < ARRAY_SIZE(feature_name); i++)
161264a88d5dSblueswir1         if (feature_name[i] && (features & (1 << i))) {
161364a88d5dSblueswir1             if (prefix)
161464a88d5dSblueswir1                 (*cpu_fprintf)(f, "%s", prefix);
161564a88d5dSblueswir1             (*cpu_fprintf)(f, "%s ", feature_name[i]);
161664a88d5dSblueswir1         }
161764a88d5dSblueswir1 }
161864a88d5dSblueswir1 
161964a88d5dSblueswir1 static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
162064a88d5dSblueswir1 {
162164a88d5dSblueswir1     unsigned int i;
162264a88d5dSblueswir1 
162364a88d5dSblueswir1     for (i = 0; i < ARRAY_SIZE(feature_name); i++)
162464a88d5dSblueswir1         if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
162564a88d5dSblueswir1             *features |= 1 << i;
162664a88d5dSblueswir1             return;
162764a88d5dSblueswir1         }
162864a88d5dSblueswir1     fprintf(stderr, "CPU feature %s not found\n", flagname);
162964a88d5dSblueswir1 }
163064a88d5dSblueswir1 
163122548760Sblueswir1 static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
163264a88d5dSblueswir1 {
163364a88d5dSblueswir1     unsigned int i;
163464a88d5dSblueswir1     const sparc_def_t *def = NULL;
163564a88d5dSblueswir1     char *s = strdup(cpu_model);
163664a88d5dSblueswir1     char *featurestr, *name = strtok(s, ",");
163764a88d5dSblueswir1     uint32_t plus_features = 0;
163864a88d5dSblueswir1     uint32_t minus_features = 0;
16390bfcd599SBlue Swirl     uint64_t iu_version;
16401a14026eSblueswir1     uint32_t fpu_version, mmu_version, nwindows;
164164a88d5dSblueswir1 
1642b1503cdaSmalc     for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
1643c48fcb47Sblueswir1         if (strcasecmp(name, sparc_defs[i].name) == 0) {
164464a88d5dSblueswir1             def = &sparc_defs[i];
1645c48fcb47Sblueswir1         }
1646c48fcb47Sblueswir1     }
164764a88d5dSblueswir1     if (!def)
164864a88d5dSblueswir1         goto error;
164964a88d5dSblueswir1     memcpy(cpu_def, def, sizeof(*def));
165064a88d5dSblueswir1 
165164a88d5dSblueswir1     featurestr = strtok(NULL, ",");
165264a88d5dSblueswir1     while (featurestr) {
165364a88d5dSblueswir1         char *val;
165464a88d5dSblueswir1 
165564a88d5dSblueswir1         if (featurestr[0] == '+') {
165664a88d5dSblueswir1             add_flagname_to_bitmaps(featurestr + 1, &plus_features);
165764a88d5dSblueswir1         } else if (featurestr[0] == '-') {
165864a88d5dSblueswir1             add_flagname_to_bitmaps(featurestr + 1, &minus_features);
165964a88d5dSblueswir1         } else if ((val = strchr(featurestr, '='))) {
166064a88d5dSblueswir1             *val = 0; val++;
166164a88d5dSblueswir1             if (!strcmp(featurestr, "iu_version")) {
166264a88d5dSblueswir1                 char *err;
166364a88d5dSblueswir1 
166464a88d5dSblueswir1                 iu_version = strtoll(val, &err, 0);
166564a88d5dSblueswir1                 if (!*val || *err) {
166664a88d5dSblueswir1                     fprintf(stderr, "bad numerical value %s\n", val);
166764a88d5dSblueswir1                     goto error;
166864a88d5dSblueswir1                 }
166964a88d5dSblueswir1                 cpu_def->iu_version = iu_version;
167064a88d5dSblueswir1 #ifdef DEBUG_FEATURES
16710bfcd599SBlue Swirl                 fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
167264a88d5dSblueswir1 #endif
167364a88d5dSblueswir1             } else if (!strcmp(featurestr, "fpu_version")) {
167464a88d5dSblueswir1                 char *err;
167564a88d5dSblueswir1 
167664a88d5dSblueswir1                 fpu_version = strtol(val, &err, 0);
167764a88d5dSblueswir1                 if (!*val || *err) {
167864a88d5dSblueswir1                     fprintf(stderr, "bad numerical value %s\n", val);
167964a88d5dSblueswir1                     goto error;
168064a88d5dSblueswir1                 }
168164a88d5dSblueswir1                 cpu_def->fpu_version = fpu_version;
168264a88d5dSblueswir1 #ifdef DEBUG_FEATURES
16830bf9e31aSBlue Swirl                 fprintf(stderr, "fpu_version %x\n", fpu_version);
168464a88d5dSblueswir1 #endif
168564a88d5dSblueswir1             } else if (!strcmp(featurestr, "mmu_version")) {
168664a88d5dSblueswir1                 char *err;
168764a88d5dSblueswir1 
168864a88d5dSblueswir1                 mmu_version = strtol(val, &err, 0);
168964a88d5dSblueswir1                 if (!*val || *err) {
169064a88d5dSblueswir1                     fprintf(stderr, "bad numerical value %s\n", val);
169164a88d5dSblueswir1                     goto error;
169264a88d5dSblueswir1                 }
169364a88d5dSblueswir1                 cpu_def->mmu_version = mmu_version;
169464a88d5dSblueswir1 #ifdef DEBUG_FEATURES
16950bf9e31aSBlue Swirl                 fprintf(stderr, "mmu_version %x\n", mmu_version);
169664a88d5dSblueswir1 #endif
16971a14026eSblueswir1             } else if (!strcmp(featurestr, "nwindows")) {
16981a14026eSblueswir1                 char *err;
16991a14026eSblueswir1 
17001a14026eSblueswir1                 nwindows = strtol(val, &err, 0);
17011a14026eSblueswir1                 if (!*val || *err || nwindows > MAX_NWINDOWS ||
17021a14026eSblueswir1                     nwindows < MIN_NWINDOWS) {
17031a14026eSblueswir1                     fprintf(stderr, "bad numerical value %s\n", val);
17041a14026eSblueswir1                     goto error;
17051a14026eSblueswir1                 }
17061a14026eSblueswir1                 cpu_def->nwindows = nwindows;
17071a14026eSblueswir1 #ifdef DEBUG_FEATURES
17081a14026eSblueswir1                 fprintf(stderr, "nwindows %d\n", nwindows);
17091a14026eSblueswir1 #endif
171064a88d5dSblueswir1             } else {
171164a88d5dSblueswir1                 fprintf(stderr, "unrecognized feature %s\n", featurestr);
171264a88d5dSblueswir1                 goto error;
171364a88d5dSblueswir1             }
171464a88d5dSblueswir1         } else {
171577f193daSblueswir1             fprintf(stderr, "feature string `%s' not in format "
171677f193daSblueswir1                     "(+feature|-feature|feature=xyz)\n", featurestr);
171764a88d5dSblueswir1             goto error;
171864a88d5dSblueswir1         }
171964a88d5dSblueswir1         featurestr = strtok(NULL, ",");
172064a88d5dSblueswir1     }
172164a88d5dSblueswir1     cpu_def->features |= plus_features;
172264a88d5dSblueswir1     cpu_def->features &= ~minus_features;
172364a88d5dSblueswir1 #ifdef DEBUG_FEATURES
172464a88d5dSblueswir1     print_features(stderr, fprintf, cpu_def->features, NULL);
172564a88d5dSblueswir1 #endif
172664a88d5dSblueswir1     free(s);
172764a88d5dSblueswir1     return 0;
172864a88d5dSblueswir1 
172964a88d5dSblueswir1  error:
173064a88d5dSblueswir1     free(s);
173164a88d5dSblueswir1     return -1;
1732c48fcb47Sblueswir1 }
1733c48fcb47Sblueswir1 
17349a78eeadSStefan Weil void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
1735c48fcb47Sblueswir1 {
1736c48fcb47Sblueswir1     unsigned int i;
1737c48fcb47Sblueswir1 
1738b1503cdaSmalc     for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
17391a14026eSblueswir1         (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x NWINS %d ",
1740c48fcb47Sblueswir1                        sparc_defs[i].name,
1741c48fcb47Sblueswir1                        sparc_defs[i].iu_version,
1742c48fcb47Sblueswir1                        sparc_defs[i].fpu_version,
17431a14026eSblueswir1                        sparc_defs[i].mmu_version,
17441a14026eSblueswir1                        sparc_defs[i].nwindows);
174577f193daSblueswir1         print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
174677f193daSblueswir1                        ~sparc_defs[i].features, "-");
174777f193daSblueswir1         print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
174877f193daSblueswir1                        sparc_defs[i].features, "+");
174964a88d5dSblueswir1         (*cpu_fprintf)(f, "\n");
1750c48fcb47Sblueswir1     }
1751f76981b1Sblueswir1     (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
1752f76981b1Sblueswir1     print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
175364a88d5dSblueswir1     (*cpu_fprintf)(f, "\n");
1754f76981b1Sblueswir1     (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
1755f76981b1Sblueswir1     print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
1756f76981b1Sblueswir1     (*cpu_fprintf)(f, "\n");
1757f76981b1Sblueswir1     (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
1758f76981b1Sblueswir1                    "fpu_version mmu_version nwindows\n");
1759c48fcb47Sblueswir1 }
1760c48fcb47Sblueswir1 
17619a78eeadSStefan Weil static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
176243bb98bfSBlue Swirl                          uint32_t cc)
176343bb98bfSBlue Swirl {
176443bb98bfSBlue Swirl     cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG? 'N' : '-',
176543bb98bfSBlue Swirl                 cc & PSR_ZERO? 'Z' : '-', cc & PSR_OVF? 'V' : '-',
176643bb98bfSBlue Swirl                 cc & PSR_CARRY? 'C' : '-');
176743bb98bfSBlue Swirl }
176843bb98bfSBlue Swirl 
176943bb98bfSBlue Swirl #ifdef TARGET_SPARC64
177043bb98bfSBlue Swirl #define REGS_PER_LINE 4
177143bb98bfSBlue Swirl #else
177243bb98bfSBlue Swirl #define REGS_PER_LINE 8
177343bb98bfSBlue Swirl #endif
177443bb98bfSBlue Swirl 
17759a78eeadSStefan Weil void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
1776c48fcb47Sblueswir1                     int flags)
1777c48fcb47Sblueswir1 {
1778c48fcb47Sblueswir1     int i, x;
1779c48fcb47Sblueswir1 
178077f193daSblueswir1     cpu_fprintf(f, "pc: " TARGET_FMT_lx "  npc: " TARGET_FMT_lx "\n", env->pc,
178177f193daSblueswir1                 env->npc);
1782c48fcb47Sblueswir1     cpu_fprintf(f, "General Registers:\n");
178343bb98bfSBlue Swirl 
178443bb98bfSBlue Swirl     for (i = 0; i < 8; i++) {
178543bb98bfSBlue Swirl         if (i % REGS_PER_LINE == 0) {
178643bb98bfSBlue Swirl             cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
178743bb98bfSBlue Swirl         }
178843bb98bfSBlue Swirl         cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
178943bb98bfSBlue Swirl         if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
1790c48fcb47Sblueswir1             cpu_fprintf(f, "\n");
1791c48fcb47Sblueswir1         }
179243bb98bfSBlue Swirl     }
179343bb98bfSBlue Swirl     cpu_fprintf(f, "\nCurrent Register Window:\n");
179443bb98bfSBlue Swirl     for (x = 0; x < 3; x++) {
179543bb98bfSBlue Swirl         for (i = 0; i < 8; i++) {
179643bb98bfSBlue Swirl             if (i % REGS_PER_LINE == 0) {
179743bb98bfSBlue Swirl                 cpu_fprintf(f, "%%%c%d-%d: ",
179843bb98bfSBlue Swirl                             x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
179943bb98bfSBlue Swirl                             i, i + REGS_PER_LINE - 1);
180043bb98bfSBlue Swirl             }
180143bb98bfSBlue Swirl             cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
180243bb98bfSBlue Swirl             if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
180343bb98bfSBlue Swirl                 cpu_fprintf(f, "\n");
180443bb98bfSBlue Swirl             }
180543bb98bfSBlue Swirl         }
180643bb98bfSBlue Swirl     }
1807c48fcb47Sblueswir1     cpu_fprintf(f, "\nFloating Point Registers:\n");
180843bb98bfSBlue Swirl     for (i = 0; i < TARGET_FPREGS; i++) {
1809c48fcb47Sblueswir1         if ((i & 3) == 0)
1810c48fcb47Sblueswir1             cpu_fprintf(f, "%%f%02d:", i);
1811a37ee56cSblueswir1         cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
1812c48fcb47Sblueswir1         if ((i & 3) == 3)
1813c48fcb47Sblueswir1             cpu_fprintf(f, "\n");
1814c48fcb47Sblueswir1     }
1815c48fcb47Sblueswir1 #ifdef TARGET_SPARC64
181643bb98bfSBlue Swirl     cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
1817113c6106SStefan Weil                 (unsigned)cpu_get_ccr(env));
18185a834bb4SBlue Swirl     cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
181943bb98bfSBlue Swirl     cpu_fprintf(f, " xcc: ");
18205a834bb4SBlue Swirl     cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
182143bb98bfSBlue Swirl     cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
182243bb98bfSBlue Swirl                 env->psrpil);
182343bb98bfSBlue Swirl     cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
182443bb98bfSBlue Swirl                 "cleanwin: %d cwp: %d\n",
1825c48fcb47Sblueswir1                 env->cansave, env->canrestore, env->otherwin, env->wstate,
18261a14026eSblueswir1                 env->cleanwin, env->nwindows - 1 - env->cwp);
182743bb98bfSBlue Swirl     cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
182843bb98bfSBlue Swirl                 TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
1829c48fcb47Sblueswir1 #else
18305a834bb4SBlue Swirl     cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
18315a834bb4SBlue Swirl     cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
183243bb98bfSBlue Swirl     cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs? 'S' : '-',
183343bb98bfSBlue Swirl                 env->psrps? 'P' : '-', env->psret? 'E' : '-',
183443bb98bfSBlue Swirl                 env->wim);
183543bb98bfSBlue Swirl     cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
183643bb98bfSBlue Swirl                 env->fsr, env->y);
1837c48fcb47Sblueswir1 #endif
1838c48fcb47Sblueswir1 }
1839