xref: /qemu/target/sparc/helper.c (revision 44520db10b1b92f272348ab7028e7afc68ac3edf)
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,
4597b348e7SBlue Swirl                                int mmu_idx)
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,
21597b348e7SBlue Swirl                               int mmu_idx)
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 
36144520db1SFabien Chouteau #if !defined(CONFIG_USER_ONLY)
36244520db1SFabien Chouteau 
36344520db1SFabien Chouteau /* Gdb expects all registers windows to be flushed in ram. This function handles
36444520db1SFabien Chouteau  * reads (and only reads) in stack frames as if windows were flushed. We assume
36544520db1SFabien Chouteau  * that the sparc ABI is followed.
36644520db1SFabien Chouteau  */
36744520db1SFabien Chouteau int target_memory_rw_debug(CPUState *env, target_ulong addr,
36844520db1SFabien Chouteau                            uint8_t *buf, int len, int is_write)
36944520db1SFabien Chouteau {
37044520db1SFabien Chouteau     int i;
37144520db1SFabien Chouteau     int len1;
37244520db1SFabien Chouteau     int cwp = env->cwp;
37344520db1SFabien Chouteau 
37444520db1SFabien Chouteau     if (!is_write) {
37544520db1SFabien Chouteau         for (i = 0; i < env->nwindows; i++) {
37644520db1SFabien Chouteau             int off;
37744520db1SFabien Chouteau             target_ulong fp = env->regbase[cwp * 16 + 22];
37844520db1SFabien Chouteau 
37944520db1SFabien Chouteau             /* Assume fp == 0 means end of frame.  */
38044520db1SFabien Chouteau             if (fp == 0) {
38144520db1SFabien Chouteau                 break;
38244520db1SFabien Chouteau             }
38344520db1SFabien Chouteau 
38444520db1SFabien Chouteau             cwp = cpu_cwp_inc(env, cwp + 1);
38544520db1SFabien Chouteau 
38644520db1SFabien Chouteau             /* Invalid window ? */
38744520db1SFabien Chouteau             if (env->wim & (1 << cwp)) {
38844520db1SFabien Chouteau                 break;
38944520db1SFabien Chouteau             }
39044520db1SFabien Chouteau 
39144520db1SFabien Chouteau             /* According to the ABI, the stack is growing downward.  */
39244520db1SFabien Chouteau             if (addr + len < fp) {
39344520db1SFabien Chouteau                 break;
39444520db1SFabien Chouteau             }
39544520db1SFabien Chouteau 
39644520db1SFabien Chouteau             /* Not in this frame.  */
39744520db1SFabien Chouteau             if (addr > fp + 64) {
39844520db1SFabien Chouteau                 continue;
39944520db1SFabien Chouteau             }
40044520db1SFabien Chouteau 
40144520db1SFabien Chouteau             /* Handle access before this window.  */
40244520db1SFabien Chouteau             if (addr < fp) {
40344520db1SFabien Chouteau                 len1 = fp - addr;
40444520db1SFabien Chouteau                 if (cpu_memory_rw_debug(env, addr, buf, len1, is_write) != 0) {
40544520db1SFabien Chouteau                     return -1;
40644520db1SFabien Chouteau                 }
40744520db1SFabien Chouteau                 addr += len1;
40844520db1SFabien Chouteau                 len -= len1;
40944520db1SFabien Chouteau                 buf += len1;
41044520db1SFabien Chouteau             }
41144520db1SFabien Chouteau 
41244520db1SFabien Chouteau             /* Access byte per byte to registers. Not very efficient but speed
41344520db1SFabien Chouteau              * is not critical.
41444520db1SFabien Chouteau              */
41544520db1SFabien Chouteau             off = addr - fp;
41644520db1SFabien Chouteau             len1 = 64 - off;
41744520db1SFabien Chouteau 
41844520db1SFabien Chouteau             if (len1 > len) {
41944520db1SFabien Chouteau                 len1 = len;
42044520db1SFabien Chouteau             }
42144520db1SFabien Chouteau 
42244520db1SFabien Chouteau             for (; len1; len1--) {
42344520db1SFabien Chouteau                 int reg = cwp * 16 + 8 + (off >> 2);
42444520db1SFabien Chouteau                 union {
42544520db1SFabien Chouteau                     uint32_t v;
42644520db1SFabien Chouteau                     uint8_t c[4];
42744520db1SFabien Chouteau                 } u;
42844520db1SFabien Chouteau                 u.v = cpu_to_be32(env->regbase[reg]);
42944520db1SFabien Chouteau                 *buf++ = u.c[off & 3];
43044520db1SFabien Chouteau                 addr++;
43144520db1SFabien Chouteau                 len--;
43244520db1SFabien Chouteau                 off++;
43344520db1SFabien Chouteau             }
43444520db1SFabien Chouteau 
43544520db1SFabien Chouteau             if (len == 0) {
43644520db1SFabien Chouteau                 return 0;
43744520db1SFabien Chouteau             }
43844520db1SFabien Chouteau         }
43944520db1SFabien Chouteau     }
44044520db1SFabien Chouteau     return cpu_memory_rw_debug(env, addr, buf, len, is_write);
44144520db1SFabien Chouteau }
44244520db1SFabien Chouteau 
44344520db1SFabien Chouteau #endif  /* !defined(CONFIG_USER_ONLY) */
44444520db1SFabien Chouteau 
44524741ef3Sbellard #else /* !TARGET_SPARC64 */
446e8807b14SIgor Kovalenko 
447e8807b14SIgor Kovalenko // 41 bit physical address space
448c227f099SAnthony Liguori static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
449e8807b14SIgor Kovalenko {
450e8807b14SIgor Kovalenko     return x & 0x1ffffffffffULL;
451e8807b14SIgor Kovalenko }
452e8807b14SIgor Kovalenko 
45383469015Sbellard /*
45483469015Sbellard  * UltraSparc IIi I/DMMUs
45583469015Sbellard  */
4563475187dSbellard 
457536ba015SIgor Kovalenko // Returns true if TTE tag is valid and matches virtual address value in context
458536ba015SIgor Kovalenko // requires virtual address mask value calculated from TTE entry size
4596e8e7d4cSIgor Kovalenko static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
460536ba015SIgor Kovalenko                                        uint64_t address, uint64_t context,
461299b520cSIgor V. Kovalenko                                        target_phys_addr_t *physical)
462536ba015SIgor Kovalenko {
463536ba015SIgor Kovalenko     uint64_t mask;
464536ba015SIgor Kovalenko 
46506e12b65STsuneo Saito     switch (TTE_PGSIZE(tlb->tte)) {
4663475187dSbellard     default:
46783469015Sbellard     case 0x0: // 8k
4683475187dSbellard         mask = 0xffffffffffffe000ULL;
4693475187dSbellard         break;
47083469015Sbellard     case 0x1: // 64k
4713475187dSbellard         mask = 0xffffffffffff0000ULL;
4723475187dSbellard         break;
47383469015Sbellard     case 0x2: // 512k
4743475187dSbellard         mask = 0xfffffffffff80000ULL;
4753475187dSbellard         break;
47683469015Sbellard     case 0x3: // 4M
4773475187dSbellard         mask = 0xffffffffffc00000ULL;
4783475187dSbellard         break;
4793475187dSbellard     }
480536ba015SIgor Kovalenko 
481536ba015SIgor Kovalenko     // valid, context match, virtual address match?
482f707726eSIgor Kovalenko     if (TTE_IS_VALID(tlb->tte) &&
483299b520cSIgor V. Kovalenko         (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
4842a90358fSBlue Swirl         && compare_masked(address, tlb->tag, mask))
485536ba015SIgor Kovalenko     {
486536ba015SIgor Kovalenko         // decode physical address
4876e8e7d4cSIgor Kovalenko         *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
488536ba015SIgor Kovalenko         return 1;
489536ba015SIgor Kovalenko     }
490536ba015SIgor Kovalenko 
491536ba015SIgor Kovalenko     return 0;
492536ba015SIgor Kovalenko }
493536ba015SIgor Kovalenko 
494536ba015SIgor Kovalenko static int get_physical_address_data(CPUState *env,
495c227f099SAnthony Liguori                                      target_phys_addr_t *physical, int *prot,
4962065061eSIgor V. Kovalenko                                      target_ulong address, int rw, int mmu_idx)
497536ba015SIgor Kovalenko {
498536ba015SIgor Kovalenko     unsigned int i;
499536ba015SIgor Kovalenko     uint64_t context;
500ccc76c24STsuneo Saito     uint64_t sfsr = 0;
501536ba015SIgor Kovalenko 
5022065061eSIgor V. Kovalenko     int is_user = (mmu_idx == MMU_USER_IDX ||
5032065061eSIgor V. Kovalenko                    mmu_idx == MMU_USER_SECONDARY_IDX);
5042065061eSIgor V. Kovalenko 
505536ba015SIgor Kovalenko     if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
506536ba015SIgor Kovalenko         *physical = ultrasparc_truncate_physical(address);
507536ba015SIgor Kovalenko         *prot = PAGE_READ | PAGE_WRITE;
508536ba015SIgor Kovalenko         return 0;
509536ba015SIgor Kovalenko     }
510536ba015SIgor Kovalenko 
5112065061eSIgor V. Kovalenko     switch(mmu_idx) {
5122065061eSIgor V. Kovalenko     case MMU_USER_IDX:
5132065061eSIgor V. Kovalenko     case MMU_KERNEL_IDX:
5146e8e7d4cSIgor Kovalenko         context = env->dmmu.mmu_primary_context & 0x1fff;
515ccc76c24STsuneo Saito         sfsr |= SFSR_CT_PRIMARY;
5162065061eSIgor V. Kovalenko         break;
5172065061eSIgor V. Kovalenko     case MMU_USER_SECONDARY_IDX:
5182065061eSIgor V. Kovalenko     case MMU_KERNEL_SECONDARY_IDX:
5192065061eSIgor V. Kovalenko         context = env->dmmu.mmu_secondary_context & 0x1fff;
520ccc76c24STsuneo Saito         sfsr |= SFSR_CT_SECONDARY;
5212065061eSIgor V. Kovalenko         break;
5222065061eSIgor V. Kovalenko     case MMU_NUCLEUS_IDX:
523ccc76c24STsuneo Saito         sfsr |= SFSR_CT_NUCLEUS;
524ccc76c24STsuneo Saito         /* FALLTHRU */
52544505216SBlue Swirl     default:
526299b520cSIgor V. Kovalenko         context = 0;
5272065061eSIgor V. Kovalenko         break;
528299b520cSIgor V. Kovalenko     }
529536ba015SIgor Kovalenko 
530ccc76c24STsuneo Saito     if (rw == 1) {
531ccc76c24STsuneo Saito         sfsr |= SFSR_WRITE_BIT;
532d1afc48bSTsuneo Saito     } else if (rw == 4) {
533d1afc48bSTsuneo Saito         sfsr |= SFSR_NF_BIT;
534ccc76c24STsuneo Saito     }
535ccc76c24STsuneo Saito 
536536ba015SIgor Kovalenko     for (i = 0; i < 64; i++) {
537afdf8109Sblueswir1         // ctx match, vaddr match, valid?
538b8e9fc06SIgor V. Kovalenko         if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
539d1afc48bSTsuneo Saito             int do_fault = 0;
540b8e9fc06SIgor V. Kovalenko 
541b8e9fc06SIgor V. Kovalenko             // access ok?
542d1afc48bSTsuneo Saito             /* multiple bits in SFSR.FT may be set on TT_DFAULT */
54306e12b65STsuneo Saito             if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
544d1afc48bSTsuneo Saito                 do_fault = 1;
545ccc76c24STsuneo Saito                 sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */
546b8e9fc06SIgor V. Kovalenko 
547b8e9fc06SIgor V. Kovalenko                 DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64
548b8e9fc06SIgor V. Kovalenko                             " mmu_idx=%d tl=%d\n",
549b8e9fc06SIgor V. Kovalenko                             address, context, mmu_idx, env->tl);
550d1afc48bSTsuneo Saito             }
551d1afc48bSTsuneo Saito             if (rw == 4) {
552d1afc48bSTsuneo Saito                 if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) {
553d1afc48bSTsuneo Saito                     do_fault = 1;
554d1afc48bSTsuneo Saito                     sfsr |= SFSR_FT_NF_E_BIT;
555d1afc48bSTsuneo Saito                 }
556d1afc48bSTsuneo Saito             } else {
557d1afc48bSTsuneo Saito                 if (TTE_IS_NFO(env->dtlb[i].tte)) {
558d1afc48bSTsuneo Saito                     do_fault = 1;
559d1afc48bSTsuneo Saito                     sfsr |= SFSR_FT_NFO_BIT;
560d1afc48bSTsuneo Saito                 }
561d1afc48bSTsuneo Saito             }
562d1afc48bSTsuneo Saito 
563d1afc48bSTsuneo Saito             if (do_fault) {
564d1afc48bSTsuneo Saito                 /* faults above are reported with TT_DFAULT. */
565d1afc48bSTsuneo Saito                 env->exception_index = TT_DFAULT;
56606e12b65STsuneo Saito             } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) {
567d1afc48bSTsuneo Saito                 do_fault = 1;
568b8e9fc06SIgor V. Kovalenko                 env->exception_index = TT_DPROT;
569b8e9fc06SIgor V. Kovalenko 
570b8e9fc06SIgor V. Kovalenko                 DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64
571b8e9fc06SIgor V. Kovalenko                             " mmu_idx=%d tl=%d\n",
572b8e9fc06SIgor V. Kovalenko                             address, context, mmu_idx, env->tl);
573d1afc48bSTsuneo Saito             }
574d1afc48bSTsuneo Saito 
575d1afc48bSTsuneo Saito             if (!do_fault) {
576b8e9fc06SIgor V. Kovalenko                 *prot = PAGE_READ;
57706e12b65STsuneo Saito                 if (TTE_IS_W_OK(env->dtlb[i].tte)) {
578b8e9fc06SIgor V. Kovalenko                     *prot |= PAGE_WRITE;
57906e12b65STsuneo Saito                 }
580b8e9fc06SIgor V. Kovalenko 
581b8e9fc06SIgor V. Kovalenko                 TTE_SET_USED(env->dtlb[i].tte);
582b8e9fc06SIgor V. Kovalenko 
583b8e9fc06SIgor V. Kovalenko                 return 0;
5846e8e7d4cSIgor Kovalenko             }
5856e8e7d4cSIgor Kovalenko 
586ccc76c24STsuneo Saito             if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
587ccc76c24STsuneo Saito                 sfsr |= SFSR_OW_BIT; /* overflow (not read before
58877f193daSblueswir1                                         another fault) */
589ccc76c24STsuneo Saito             }
5906e8e7d4cSIgor Kovalenko 
591ccc76c24STsuneo Saito             if (env->pstate & PS_PRIV) {
592ccc76c24STsuneo Saito                 sfsr |= SFSR_PR_BIT;
593ccc76c24STsuneo Saito             }
5946e8e7d4cSIgor Kovalenko 
595ccc76c24STsuneo Saito             /* FIXME: ASI field in SFSR must be set */
596ccc76c24STsuneo Saito             env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
5976e8e7d4cSIgor Kovalenko 
5986e8e7d4cSIgor Kovalenko             env->dmmu.sfar = address; /* Fault address register */
5999168b3a5SIgor V. Kovalenko 
6009168b3a5SIgor V. Kovalenko             env->dmmu.tag_access = (address & ~0x1fffULL) | context;
6019168b3a5SIgor V. Kovalenko 
6023475187dSbellard             return 1;
6033475187dSbellard         }
6043475187dSbellard     }
605b8e9fc06SIgor V. Kovalenko 
606b8e9fc06SIgor V. Kovalenko     DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n",
607b8e9fc06SIgor V. Kovalenko                 address, context);
608b8e9fc06SIgor V. Kovalenko 
609ccc76c24STsuneo Saito     /*
610ccc76c24STsuneo Saito      * On MMU misses:
611ccc76c24STsuneo Saito      * - UltraSPARC IIi: SFSR and SFAR unmodified
612ccc76c24STsuneo Saito      * - JPS1: SFAR updated and some fields of SFSR updated
613ccc76c24STsuneo Saito      */
6146e8e7d4cSIgor Kovalenko     env->dmmu.tag_access = (address & ~0x1fffULL) | context;
61583469015Sbellard     env->exception_index = TT_DMISS;
6163475187dSbellard     return 1;
6173475187dSbellard }
6183475187dSbellard 
61977f193daSblueswir1 static int get_physical_address_code(CPUState *env,
620c227f099SAnthony Liguori                                      target_phys_addr_t *physical, int *prot,
6212065061eSIgor V. Kovalenko                                      target_ulong address, int mmu_idx)
6223475187dSbellard {
6233475187dSbellard     unsigned int i;
624536ba015SIgor Kovalenko     uint64_t context;
6253475187dSbellard 
6262065061eSIgor V. Kovalenko     int is_user = (mmu_idx == MMU_USER_IDX ||
6272065061eSIgor V. Kovalenko                    mmu_idx == MMU_USER_SECONDARY_IDX);
6282065061eSIgor V. Kovalenko 
629e8807b14SIgor Kovalenko     if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
630e8807b14SIgor Kovalenko         /* IMMU disabled */
631e8807b14SIgor Kovalenko         *physical = ultrasparc_truncate_physical(address);
632227671c9Sbellard         *prot = PAGE_EXEC;
6333475187dSbellard         return 0;
6343475187dSbellard     }
63583469015Sbellard 
636299b520cSIgor V. Kovalenko     if (env->tl == 0) {
6372065061eSIgor V. Kovalenko         /* PRIMARY context */
6386e8e7d4cSIgor Kovalenko         context = env->dmmu.mmu_primary_context & 0x1fff;
639299b520cSIgor V. Kovalenko     } else {
6402065061eSIgor V. Kovalenko         /* NUCLEUS context */
641299b520cSIgor V. Kovalenko         context = 0;
642299b520cSIgor V. Kovalenko     }
643536ba015SIgor Kovalenko 
6443475187dSbellard     for (i = 0; i < 64; i++) {
645afdf8109Sblueswir1         // ctx match, vaddr match, valid?
6466e8e7d4cSIgor Kovalenko         if (ultrasparc_tag_match(&env->itlb[i],
647299b520cSIgor V. Kovalenko                                  address, context, physical)) {
648afdf8109Sblueswir1             // access ok?
64906e12b65STsuneo Saito             if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
650ccc76c24STsuneo Saito                 /* Fault status register */
651ccc76c24STsuneo Saito                 if (env->immu.sfsr & SFSR_VALID_BIT) {
652ccc76c24STsuneo Saito                     env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
65377f193daSblueswir1                                                      another fault) */
654ccc76c24STsuneo Saito                 } else {
655ccc76c24STsuneo Saito                     env->immu.sfsr = 0;
656ccc76c24STsuneo Saito                 }
657ccc76c24STsuneo Saito                 if (env->pstate & PS_PRIV) {
658ccc76c24STsuneo Saito                     env->immu.sfsr |= SFSR_PR_BIT;
659ccc76c24STsuneo Saito                 }
660ccc76c24STsuneo Saito                 if (env->tl > 0) {
661ccc76c24STsuneo Saito                     env->immu.sfsr |= SFSR_CT_NUCLEUS;
662ccc76c24STsuneo Saito                 }
663ccc76c24STsuneo Saito 
664ccc76c24STsuneo Saito                 /* FIXME: ASI field in SFSR must be set */
665ccc76c24STsuneo Saito                 env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
6663475187dSbellard                 env->exception_index = TT_TFAULT;
667b8e9fc06SIgor V. Kovalenko 
6689168b3a5SIgor V. Kovalenko                 env->immu.tag_access = (address & ~0x1fffULL) | context;
6699168b3a5SIgor V. Kovalenko 
670b8e9fc06SIgor V. Kovalenko                 DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n",
671b8e9fc06SIgor V. Kovalenko                             address, context);
672b8e9fc06SIgor V. Kovalenko 
6733475187dSbellard                 return 1;
6743475187dSbellard             }
675227671c9Sbellard             *prot = PAGE_EXEC;
676f707726eSIgor Kovalenko             TTE_SET_USED(env->itlb[i].tte);
6773475187dSbellard             return 0;
6783475187dSbellard         }
6793475187dSbellard     }
680b8e9fc06SIgor V. Kovalenko 
681b8e9fc06SIgor V. Kovalenko     DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n",
682b8e9fc06SIgor V. Kovalenko                 address, context);
683b8e9fc06SIgor V. Kovalenko 
6847ab463cbSBlue Swirl     /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
6856e8e7d4cSIgor Kovalenko     env->immu.tag_access = (address & ~0x1fffULL) | context;
68683469015Sbellard     env->exception_index = TT_TMISS;
6873475187dSbellard     return 1;
6883475187dSbellard }
6893475187dSbellard 
690c227f099SAnthony Liguori static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
691c48fcb47Sblueswir1                                 int *prot, int *access_index,
692d4c430a8SPaul Brook                                 target_ulong address, int rw, int mmu_idx,
693d4c430a8SPaul Brook                                 target_ulong *page_size)
6943475187dSbellard {
695d4c430a8SPaul Brook     /* ??? We treat everything as a small page, then explicitly flush
696d4c430a8SPaul Brook        everything when an entry is evicted.  */
697d4c430a8SPaul Brook     *page_size = TARGET_PAGE_SIZE;
6989fd1ae3aSIgor V. Kovalenko 
6999fd1ae3aSIgor V. Kovalenko #if defined (DEBUG_MMU)
7009fd1ae3aSIgor V. Kovalenko     /* safety net to catch wrong softmmu index use from dynamic code */
7019fd1ae3aSIgor V. Kovalenko     if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
7029fd1ae3aSIgor V. Kovalenko         DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d"
7039fd1ae3aSIgor V. Kovalenko                     " primary context=%" PRIx64
7049fd1ae3aSIgor V. Kovalenko                     " secondary context=%" PRIx64
7059fd1ae3aSIgor V. Kovalenko                 " address=%" PRIx64
7069fd1ae3aSIgor V. Kovalenko                 "\n",
7079fd1ae3aSIgor V. Kovalenko                 (rw == 2 ? "CODE" : "DATA"),
7089fd1ae3aSIgor V. Kovalenko                 env->tl, mmu_idx,
7099fd1ae3aSIgor V. Kovalenko                 env->dmmu.mmu_primary_context,
7109fd1ae3aSIgor V. Kovalenko                 env->dmmu.mmu_secondary_context,
7119fd1ae3aSIgor V. Kovalenko                 address);
7129fd1ae3aSIgor V. Kovalenko     }
7139fd1ae3aSIgor V. Kovalenko #endif
7149fd1ae3aSIgor V. Kovalenko 
7153475187dSbellard     if (rw == 2)
71622548760Sblueswir1         return get_physical_address_code(env, physical, prot, address,
7172065061eSIgor V. Kovalenko                                          mmu_idx);
7183475187dSbellard     else
71922548760Sblueswir1         return get_physical_address_data(env, physical, prot, address, rw,
7202065061eSIgor V. Kovalenko                                          mmu_idx);
7213475187dSbellard }
7223475187dSbellard 
7233475187dSbellard /* Perform address translation */
7243475187dSbellard int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
72597b348e7SBlue Swirl                               int mmu_idx)
7263475187dSbellard {
72783469015Sbellard     target_ulong virt_addr, vaddr;
728c227f099SAnthony Liguori     target_phys_addr_t paddr;
729d4c430a8SPaul Brook     target_ulong page_size;
730d4c430a8SPaul Brook     int error_code = 0, prot, access_index;
7313475187dSbellard 
73277f193daSblueswir1     error_code = get_physical_address(env, &paddr, &prot, &access_index,
733d4c430a8SPaul Brook                                       address, rw, mmu_idx, &page_size);
7343475187dSbellard     if (error_code == 0) {
7353475187dSbellard         virt_addr = address & TARGET_PAGE_MASK;
73677f193daSblueswir1         vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
73777f193daSblueswir1                              (TARGET_PAGE_SIZE - 1));
738b8e9fc06SIgor V. Kovalenko 
739b8e9fc06SIgor V. Kovalenko         DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 ","
740b8e9fc06SIgor V. Kovalenko                     " vaddr %" PRIx64
741b8e9fc06SIgor V. Kovalenko                     " mmu_idx=%d"
742b8e9fc06SIgor V. Kovalenko                     " tl=%d"
743b8e9fc06SIgor V. Kovalenko                     " primary context=%" PRIx64
744b8e9fc06SIgor V. Kovalenko                     " secondary context=%" PRIx64
745b8e9fc06SIgor V. Kovalenko                     "\n",
746b8e9fc06SIgor V. Kovalenko                     address, paddr, vaddr, mmu_idx, env->tl,
747b8e9fc06SIgor V. Kovalenko                     env->dmmu.mmu_primary_context,
748b8e9fc06SIgor V. Kovalenko                     env->dmmu.mmu_secondary_context);
749b8e9fc06SIgor V. Kovalenko 
750d4c430a8SPaul Brook         tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
751d4c430a8SPaul Brook         return 0;
7523475187dSbellard     }
7533475187dSbellard     // XXX
7543475187dSbellard     return 1;
7553475187dSbellard }
7563475187dSbellard 
757d41160a3SBlue Swirl void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
75883469015Sbellard {
75983469015Sbellard     unsigned int i;
76083469015Sbellard     const char *mask;
76183469015Sbellard 
762d41160a3SBlue Swirl     (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
763d41160a3SBlue Swirl                    PRId64 "\n",
764d41160a3SBlue Swirl                    env->dmmu.mmu_primary_context,
765d41160a3SBlue Swirl                    env->dmmu.mmu_secondary_context);
76683469015Sbellard     if ((env->lsu & DMMU_E) == 0) {
767d41160a3SBlue Swirl         (*cpu_fprintf)(f, "DMMU disabled\n");
76883469015Sbellard     } else {
769d41160a3SBlue Swirl         (*cpu_fprintf)(f, "DMMU dump\n");
77083469015Sbellard         for (i = 0; i < 64; i++) {
77106e12b65STsuneo Saito             switch (TTE_PGSIZE(env->dtlb[i].tte)) {
77283469015Sbellard             default:
77383469015Sbellard             case 0x0:
77483469015Sbellard                 mask = "  8k";
77583469015Sbellard                 break;
77683469015Sbellard             case 0x1:
77783469015Sbellard                 mask = " 64k";
77883469015Sbellard                 break;
77983469015Sbellard             case 0x2:
78083469015Sbellard                 mask = "512k";
78183469015Sbellard                 break;
78283469015Sbellard             case 0x3:
78383469015Sbellard                 mask = "  4M";
78483469015Sbellard                 break;
78583469015Sbellard             }
78606e12b65STsuneo Saito             if (TTE_IS_VALID(env->dtlb[i].tte)) {
7873b8b030aSStefan Weil                 (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
7882a90358fSBlue Swirl                                ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
7896e8e7d4cSIgor Kovalenko                                i,
79031a68d57SBlue Swirl                                env->dtlb[i].tag & (uint64_t)~0x1fffULL,
79106e12b65STsuneo Saito                                TTE_PA(env->dtlb[i].tte),
79283469015Sbellard                                mask,
79306e12b65STsuneo Saito                                TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user",
79406e12b65STsuneo Saito                                TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO",
79506e12b65STsuneo Saito                                TTE_IS_LOCKED(env->dtlb[i].tte) ?
79606e12b65STsuneo Saito                                "locked" : "unlocked",
7972a90358fSBlue Swirl                                env->dtlb[i].tag & (uint64_t)0x1fffULL,
798d41160a3SBlue Swirl                                TTE_IS_GLOBAL(env->dtlb[i].tte)?
799d41160a3SBlue Swirl                                "global" : "local");
80083469015Sbellard             }
80183469015Sbellard         }
80283469015Sbellard     }
80383469015Sbellard     if ((env->lsu & IMMU_E) == 0) {
804d41160a3SBlue Swirl         (*cpu_fprintf)(f, "IMMU disabled\n");
80583469015Sbellard     } else {
806d41160a3SBlue Swirl         (*cpu_fprintf)(f, "IMMU dump\n");
80783469015Sbellard         for (i = 0; i < 64; i++) {
80806e12b65STsuneo Saito             switch (TTE_PGSIZE(env->itlb[i].tte)) {
80983469015Sbellard             default:
81083469015Sbellard             case 0x0:
81183469015Sbellard                 mask = "  8k";
81283469015Sbellard                 break;
81383469015Sbellard             case 0x1:
81483469015Sbellard                 mask = " 64k";
81583469015Sbellard                 break;
81683469015Sbellard             case 0x2:
81783469015Sbellard                 mask = "512k";
81883469015Sbellard                 break;
81983469015Sbellard             case 0x3:
82083469015Sbellard                 mask = "  4M";
82183469015Sbellard                 break;
82283469015Sbellard             }
82306e12b65STsuneo Saito             if (TTE_IS_VALID(env->itlb[i].tte)) {
8243b8b030aSStefan Weil                 (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
8252a90358fSBlue Swirl                                ", %s, %s, %s, ctx %" PRId64 " %s\n",
8266e8e7d4cSIgor Kovalenko                                i,
8276e8e7d4cSIgor Kovalenko                                env->itlb[i].tag & (uint64_t)~0x1fffULL,
82806e12b65STsuneo Saito                                TTE_PA(env->itlb[i].tte),
82983469015Sbellard                                mask,
83006e12b65STsuneo Saito                                TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user",
83106e12b65STsuneo Saito                                TTE_IS_LOCKED(env->itlb[i].tte) ?
83206e12b65STsuneo Saito                                "locked" : "unlocked",
8332a90358fSBlue Swirl                                env->itlb[i].tag & (uint64_t)0x1fffULL,
834d41160a3SBlue Swirl                                TTE_IS_GLOBAL(env->itlb[i].tte)?
835d41160a3SBlue Swirl                                "global" : "local");
83683469015Sbellard             }
83783469015Sbellard         }
83883469015Sbellard     }
83983469015Sbellard }
84024741ef3Sbellard 
84124741ef3Sbellard #endif /* TARGET_SPARC64 */
84224741ef3Sbellard #endif /* !CONFIG_USER_ONLY */
84324741ef3Sbellard 
844c48fcb47Sblueswir1 
8454fcc562bSPaul Brook #if !defined(CONFIG_USER_ONLY)
846321365abSTsuneo Saito static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys,
847321365abSTsuneo Saito                                    target_ulong addr, int rw, int mmu_idx)
848321365abSTsuneo Saito {
849321365abSTsuneo Saito     target_ulong page_size;
850321365abSTsuneo Saito     int prot, access_index;
851321365abSTsuneo Saito 
852321365abSTsuneo Saito     return get_physical_address(env, phys, &prot, &access_index, addr, rw,
853321365abSTsuneo Saito                                 mmu_idx, &page_size);
854321365abSTsuneo Saito }
855321365abSTsuneo Saito 
856b64b6436STsuneo Saito #if defined(TARGET_SPARC64)
8572065061eSIgor V. Kovalenko target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
8582065061eSIgor V. Kovalenko                                            int mmu_idx)
859c48fcb47Sblueswir1 {
860c227f099SAnthony Liguori     target_phys_addr_t phys_addr;
861c48fcb47Sblueswir1 
862d1afc48bSTsuneo Saito     if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) {
863c48fcb47Sblueswir1         return -1;
864321365abSTsuneo Saito     }
865c48fcb47Sblueswir1     return phys_addr;
866c48fcb47Sblueswir1 }
867b64b6436STsuneo Saito #endif
8682065061eSIgor V. Kovalenko 
8692065061eSIgor V. Kovalenko target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
8702065061eSIgor V. Kovalenko {
871b64b6436STsuneo Saito     target_phys_addr_t phys_addr;
872b64b6436STsuneo Saito     int mmu_idx = cpu_mmu_index(env);
873b64b6436STsuneo Saito 
874b64b6436STsuneo Saito     if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) {
875b64b6436STsuneo Saito         if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) {
876b64b6436STsuneo Saito             return -1;
877b64b6436STsuneo Saito         }
878b64b6436STsuneo Saito     }
879b64b6436STsuneo Saito     if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) {
880b64b6436STsuneo Saito         return -1;
881b64b6436STsuneo Saito     }
882b64b6436STsuneo Saito     return phys_addr;
8832065061eSIgor V. Kovalenko }
884c48fcb47Sblueswir1 #endif
885c48fcb47Sblueswir1 
886e67768d0SBlue Swirl #ifdef TARGET_SPARC64
887e67768d0SBlue Swirl #ifdef DEBUG_PCALL
888e67768d0SBlue Swirl static const char * const excp_names[0x80] = {
889e67768d0SBlue Swirl     [TT_TFAULT] = "Instruction Access Fault",
890e67768d0SBlue Swirl     [TT_TMISS] = "Instruction Access MMU Miss",
891e67768d0SBlue Swirl     [TT_CODE_ACCESS] = "Instruction Access Error",
892e67768d0SBlue Swirl     [TT_ILL_INSN] = "Illegal Instruction",
893e67768d0SBlue Swirl     [TT_PRIV_INSN] = "Privileged Instruction",
894e67768d0SBlue Swirl     [TT_NFPU_INSN] = "FPU Disabled",
895e67768d0SBlue Swirl     [TT_FP_EXCP] = "FPU Exception",
896e67768d0SBlue Swirl     [TT_TOVF] = "Tag Overflow",
897e67768d0SBlue Swirl     [TT_CLRWIN] = "Clean Windows",
898e67768d0SBlue Swirl     [TT_DIV_ZERO] = "Division By Zero",
899e67768d0SBlue Swirl     [TT_DFAULT] = "Data Access Fault",
900e67768d0SBlue Swirl     [TT_DMISS] = "Data Access MMU Miss",
901e67768d0SBlue Swirl     [TT_DATA_ACCESS] = "Data Access Error",
902e67768d0SBlue Swirl     [TT_DPROT] = "Data Protection Error",
903e67768d0SBlue Swirl     [TT_UNALIGNED] = "Unaligned Memory Access",
904e67768d0SBlue Swirl     [TT_PRIV_ACT] = "Privileged Action",
905e67768d0SBlue Swirl     [TT_EXTINT | 0x1] = "External Interrupt 1",
906e67768d0SBlue Swirl     [TT_EXTINT | 0x2] = "External Interrupt 2",
907e67768d0SBlue Swirl     [TT_EXTINT | 0x3] = "External Interrupt 3",
908e67768d0SBlue Swirl     [TT_EXTINT | 0x4] = "External Interrupt 4",
909e67768d0SBlue Swirl     [TT_EXTINT | 0x5] = "External Interrupt 5",
910e67768d0SBlue Swirl     [TT_EXTINT | 0x6] = "External Interrupt 6",
911e67768d0SBlue Swirl     [TT_EXTINT | 0x7] = "External Interrupt 7",
912e67768d0SBlue Swirl     [TT_EXTINT | 0x8] = "External Interrupt 8",
913e67768d0SBlue Swirl     [TT_EXTINT | 0x9] = "External Interrupt 9",
914e67768d0SBlue Swirl     [TT_EXTINT | 0xa] = "External Interrupt 10",
915e67768d0SBlue Swirl     [TT_EXTINT | 0xb] = "External Interrupt 11",
916e67768d0SBlue Swirl     [TT_EXTINT | 0xc] = "External Interrupt 12",
917e67768d0SBlue Swirl     [TT_EXTINT | 0xd] = "External Interrupt 13",
918e67768d0SBlue Swirl     [TT_EXTINT | 0xe] = "External Interrupt 14",
919e67768d0SBlue Swirl     [TT_EXTINT | 0xf] = "External Interrupt 15",
920e67768d0SBlue Swirl };
921e67768d0SBlue Swirl #endif
922e67768d0SBlue Swirl 
923e67768d0SBlue Swirl void do_interrupt(CPUState *env)
924e67768d0SBlue Swirl {
925e67768d0SBlue Swirl     int intno = env->exception_index;
926e67768d0SBlue Swirl     trap_state *tsptr;
927e67768d0SBlue Swirl 
928e67768d0SBlue Swirl #ifdef DEBUG_PCALL
929e67768d0SBlue Swirl     if (qemu_loglevel_mask(CPU_LOG_INT)) {
930e67768d0SBlue Swirl         static int count;
931e67768d0SBlue Swirl         const char *name;
932e67768d0SBlue Swirl 
933e67768d0SBlue Swirl         if (intno < 0 || intno >= 0x180) {
934e67768d0SBlue Swirl             name = "Unknown";
935e67768d0SBlue Swirl         } else if (intno >= 0x100) {
936e67768d0SBlue Swirl             name = "Trap Instruction";
937e67768d0SBlue Swirl         } else if (intno >= 0xc0) {
938e67768d0SBlue Swirl             name = "Window Fill";
939e67768d0SBlue Swirl         } else if (intno >= 0x80) {
940e67768d0SBlue Swirl             name = "Window Spill";
941e67768d0SBlue Swirl         } else {
942e67768d0SBlue Swirl             name = excp_names[intno];
943e67768d0SBlue Swirl             if (!name) {
944e67768d0SBlue Swirl                 name = "Unknown";
945e67768d0SBlue Swirl             }
946e67768d0SBlue Swirl         }
947e67768d0SBlue Swirl 
948e67768d0SBlue Swirl         qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64
949e67768d0SBlue Swirl                 " SP=%016" PRIx64 "\n",
950e67768d0SBlue Swirl                 count, name, intno,
951e67768d0SBlue Swirl                 env->pc,
952e67768d0SBlue Swirl                 env->npc, env->regwptr[6]);
953e67768d0SBlue Swirl         log_cpu_state(env, 0);
954e67768d0SBlue Swirl #if 0
955e67768d0SBlue Swirl         {
956e67768d0SBlue Swirl             int i;
957e67768d0SBlue Swirl             uint8_t *ptr;
958e67768d0SBlue Swirl 
959e67768d0SBlue Swirl             qemu_log("       code=");
960e67768d0SBlue Swirl             ptr = (uint8_t *)env->pc;
961e67768d0SBlue Swirl             for (i = 0; i < 16; i++) {
962e67768d0SBlue Swirl                 qemu_log(" %02x", ldub(ptr + i));
963e67768d0SBlue Swirl             }
964e67768d0SBlue Swirl             qemu_log("\n");
965e67768d0SBlue Swirl         }
966e67768d0SBlue Swirl #endif
967e67768d0SBlue Swirl         count++;
968e67768d0SBlue Swirl     }
969e67768d0SBlue Swirl #endif
970e67768d0SBlue Swirl #if !defined(CONFIG_USER_ONLY)
971e67768d0SBlue Swirl     if (env->tl >= env->maxtl) {
972e67768d0SBlue Swirl         cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
973e67768d0SBlue Swirl                   " Error state", env->exception_index, env->tl, env->maxtl);
974e67768d0SBlue Swirl         return;
975e67768d0SBlue Swirl     }
976e67768d0SBlue Swirl #endif
977e67768d0SBlue Swirl     if (env->tl < env->maxtl - 1) {
978e67768d0SBlue Swirl         env->tl++;
979e67768d0SBlue Swirl     } else {
980e67768d0SBlue Swirl         env->pstate |= PS_RED;
981e67768d0SBlue Swirl         if (env->tl < env->maxtl) {
982e67768d0SBlue Swirl             env->tl++;
983e67768d0SBlue Swirl         }
984e67768d0SBlue Swirl     }
985e67768d0SBlue Swirl     tsptr = cpu_tsptr(env);
986e67768d0SBlue Swirl 
987e67768d0SBlue Swirl     tsptr->tstate = (cpu_get_ccr(env) << 32) |
988e67768d0SBlue Swirl         ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
989e67768d0SBlue Swirl         cpu_get_cwp64(env);
990e67768d0SBlue Swirl     tsptr->tpc = env->pc;
991e67768d0SBlue Swirl     tsptr->tnpc = env->npc;
992e67768d0SBlue Swirl     tsptr->tt = intno;
993e67768d0SBlue Swirl 
994e67768d0SBlue Swirl     switch (intno) {
995e67768d0SBlue Swirl     case TT_IVEC:
996e67768d0SBlue Swirl         cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
997e67768d0SBlue Swirl         break;
998e67768d0SBlue Swirl     case TT_TFAULT:
999e67768d0SBlue Swirl     case TT_DFAULT:
1000e67768d0SBlue Swirl     case TT_TMISS ... TT_TMISS + 3:
1001e67768d0SBlue Swirl     case TT_DMISS ... TT_DMISS + 3:
1002e67768d0SBlue Swirl     case TT_DPROT ... TT_DPROT + 3:
1003e67768d0SBlue Swirl         cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG);
1004e67768d0SBlue Swirl         break;
1005e67768d0SBlue Swirl     default:
1006e67768d0SBlue Swirl         cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG);
1007e67768d0SBlue Swirl         break;
1008e67768d0SBlue Swirl     }
1009e67768d0SBlue Swirl 
1010e67768d0SBlue Swirl     if (intno == TT_CLRWIN) {
1011e67768d0SBlue Swirl         cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1));
1012e67768d0SBlue Swirl     } else if ((intno & 0x1c0) == TT_SPILL) {
1013e67768d0SBlue Swirl         cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
1014e67768d0SBlue Swirl     } else if ((intno & 0x1c0) == TT_FILL) {
1015e67768d0SBlue Swirl         cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
1016e67768d0SBlue Swirl     }
1017e67768d0SBlue Swirl     env->tbr &= ~0x7fffULL;
1018e67768d0SBlue Swirl     env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
1019e67768d0SBlue Swirl     env->pc = env->tbr;
1020e67768d0SBlue Swirl     env->npc = env->pc + 4;
1021e67768d0SBlue Swirl     env->exception_index = -1;
1022e67768d0SBlue Swirl }
1023e67768d0SBlue Swirl #else
1024e67768d0SBlue Swirl #ifdef DEBUG_PCALL
1025e67768d0SBlue Swirl static const char * const excp_names[0x80] = {
1026e67768d0SBlue Swirl     [TT_TFAULT] = "Instruction Access Fault",
1027e67768d0SBlue Swirl     [TT_ILL_INSN] = "Illegal Instruction",
1028e67768d0SBlue Swirl     [TT_PRIV_INSN] = "Privileged Instruction",
1029e67768d0SBlue Swirl     [TT_NFPU_INSN] = "FPU Disabled",
1030e67768d0SBlue Swirl     [TT_WIN_OVF] = "Window Overflow",
1031e67768d0SBlue Swirl     [TT_WIN_UNF] = "Window Underflow",
1032e67768d0SBlue Swirl     [TT_UNALIGNED] = "Unaligned Memory Access",
1033e67768d0SBlue Swirl     [TT_FP_EXCP] = "FPU Exception",
1034e67768d0SBlue Swirl     [TT_DFAULT] = "Data Access Fault",
1035e67768d0SBlue Swirl     [TT_TOVF] = "Tag Overflow",
1036e67768d0SBlue Swirl     [TT_EXTINT | 0x1] = "External Interrupt 1",
1037e67768d0SBlue Swirl     [TT_EXTINT | 0x2] = "External Interrupt 2",
1038e67768d0SBlue Swirl     [TT_EXTINT | 0x3] = "External Interrupt 3",
1039e67768d0SBlue Swirl     [TT_EXTINT | 0x4] = "External Interrupt 4",
1040e67768d0SBlue Swirl     [TT_EXTINT | 0x5] = "External Interrupt 5",
1041e67768d0SBlue Swirl     [TT_EXTINT | 0x6] = "External Interrupt 6",
1042e67768d0SBlue Swirl     [TT_EXTINT | 0x7] = "External Interrupt 7",
1043e67768d0SBlue Swirl     [TT_EXTINT | 0x8] = "External Interrupt 8",
1044e67768d0SBlue Swirl     [TT_EXTINT | 0x9] = "External Interrupt 9",
1045e67768d0SBlue Swirl     [TT_EXTINT | 0xa] = "External Interrupt 10",
1046e67768d0SBlue Swirl     [TT_EXTINT | 0xb] = "External Interrupt 11",
1047e67768d0SBlue Swirl     [TT_EXTINT | 0xc] = "External Interrupt 12",
1048e67768d0SBlue Swirl     [TT_EXTINT | 0xd] = "External Interrupt 13",
1049e67768d0SBlue Swirl     [TT_EXTINT | 0xe] = "External Interrupt 14",
1050e67768d0SBlue Swirl     [TT_EXTINT | 0xf] = "External Interrupt 15",
1051e67768d0SBlue Swirl     [TT_TOVF] = "Tag Overflow",
1052e67768d0SBlue Swirl     [TT_CODE_ACCESS] = "Instruction Access Error",
1053e67768d0SBlue Swirl     [TT_DATA_ACCESS] = "Data Access Error",
1054e67768d0SBlue Swirl     [TT_DIV_ZERO] = "Division By Zero",
1055e67768d0SBlue Swirl     [TT_NCP_INSN] = "Coprocessor Disabled",
1056e67768d0SBlue Swirl };
1057e67768d0SBlue Swirl #endif
1058e67768d0SBlue Swirl 
1059e67768d0SBlue Swirl void do_interrupt(CPUState *env)
1060e67768d0SBlue Swirl {
1061e67768d0SBlue Swirl     int cwp, intno = env->exception_index;
1062e67768d0SBlue Swirl 
1063e67768d0SBlue Swirl #ifdef DEBUG_PCALL
1064e67768d0SBlue Swirl     if (qemu_loglevel_mask(CPU_LOG_INT)) {
1065e67768d0SBlue Swirl         static int count;
1066e67768d0SBlue Swirl         const char *name;
1067e67768d0SBlue Swirl 
1068e67768d0SBlue Swirl         if (intno < 0 || intno >= 0x100) {
1069e67768d0SBlue Swirl             name = "Unknown";
1070e67768d0SBlue Swirl         } else if (intno >= 0x80) {
1071e67768d0SBlue Swirl             name = "Trap Instruction";
1072e67768d0SBlue Swirl         } else {
1073e67768d0SBlue Swirl             name = excp_names[intno];
1074e67768d0SBlue Swirl             if (!name) {
1075e67768d0SBlue Swirl                 name = "Unknown";
1076e67768d0SBlue Swirl             }
1077e67768d0SBlue Swirl         }
1078e67768d0SBlue Swirl 
1079e67768d0SBlue Swirl         qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n",
1080e67768d0SBlue Swirl                 count, name, intno,
1081e67768d0SBlue Swirl                 env->pc,
1082e67768d0SBlue Swirl                 env->npc, env->regwptr[6]);
1083e67768d0SBlue Swirl         log_cpu_state(env, 0);
1084e67768d0SBlue Swirl #if 0
1085e67768d0SBlue Swirl         {
1086e67768d0SBlue Swirl             int i;
1087e67768d0SBlue Swirl             uint8_t *ptr;
1088e67768d0SBlue Swirl 
1089e67768d0SBlue Swirl             qemu_log("       code=");
1090e67768d0SBlue Swirl             ptr = (uint8_t *)env->pc;
1091e67768d0SBlue Swirl             for (i = 0; i < 16; i++) {
1092e67768d0SBlue Swirl                 qemu_log(" %02x", ldub(ptr + i));
1093e67768d0SBlue Swirl             }
1094e67768d0SBlue Swirl             qemu_log("\n");
1095e67768d0SBlue Swirl         }
1096e67768d0SBlue Swirl #endif
1097e67768d0SBlue Swirl         count++;
1098e67768d0SBlue Swirl     }
1099e67768d0SBlue Swirl #endif
1100e67768d0SBlue Swirl #if !defined(CONFIG_USER_ONLY)
1101e67768d0SBlue Swirl     if (env->psret == 0) {
1102e67768d0SBlue Swirl         cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state",
1103e67768d0SBlue Swirl                   env->exception_index);
1104e67768d0SBlue Swirl         return;
1105e67768d0SBlue Swirl     }
1106e67768d0SBlue Swirl #endif
1107e67768d0SBlue Swirl     env->psret = 0;
1108e67768d0SBlue Swirl     cwp = cpu_cwp_dec(env, env->cwp - 1);
1109e67768d0SBlue Swirl     cpu_set_cwp(env, cwp);
1110e67768d0SBlue Swirl     env->regwptr[9] = env->pc;
1111e67768d0SBlue Swirl     env->regwptr[10] = env->npc;
1112e67768d0SBlue Swirl     env->psrps = env->psrs;
1113e67768d0SBlue Swirl     env->psrs = 1;
1114e67768d0SBlue Swirl     env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
1115e67768d0SBlue Swirl     env->pc = env->tbr;
1116e67768d0SBlue Swirl     env->npc = env->pc + 4;
1117e67768d0SBlue Swirl     env->exception_index = -1;
1118e67768d0SBlue Swirl 
1119e67768d0SBlue Swirl #if !defined(CONFIG_USER_ONLY)
1120e67768d0SBlue Swirl     /* IRQ acknowledgment */
1121e67768d0SBlue Swirl     if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
1122e67768d0SBlue Swirl         env->qemu_irq_ack(env->irq_manager, intno);
1123e67768d0SBlue Swirl     }
1124e67768d0SBlue Swirl #endif
1125e67768d0SBlue Swirl }
1126e67768d0SBlue Swirl #endif
1127e67768d0SBlue Swirl 
1128c48fcb47Sblueswir1 void cpu_reset(CPUSPARCState *env)
1129c48fcb47Sblueswir1 {
1130eca1bdf4Saliguori     if (qemu_loglevel_mask(CPU_LOG_RESET)) {
1131eca1bdf4Saliguori         qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
1132eca1bdf4Saliguori         log_cpu_state(env, 0);
1133eca1bdf4Saliguori     }
1134eca1bdf4Saliguori 
1135c48fcb47Sblueswir1     tlb_flush(env, 1);
1136c48fcb47Sblueswir1     env->cwp = 0;
11375210977aSIgor Kovalenko #ifndef TARGET_SPARC64
1138c48fcb47Sblueswir1     env->wim = 1;
11395210977aSIgor Kovalenko #endif
1140c48fcb47Sblueswir1     env->regwptr = env->regbase + (env->cwp * 16);
11416b743278SBlue Swirl     CC_OP = CC_OP_FLAGS;
1142c48fcb47Sblueswir1 #if defined(CONFIG_USER_ONLY)
1143c48fcb47Sblueswir1 #ifdef TARGET_SPARC64
11441a14026eSblueswir1     env->cleanwin = env->nwindows - 2;
11451a14026eSblueswir1     env->cansave = env->nwindows - 2;
1146c48fcb47Sblueswir1     env->pstate = PS_RMO | PS_PEF | PS_IE;
1147c48fcb47Sblueswir1     env->asi = 0x82; // Primary no-fault
1148c48fcb47Sblueswir1 #endif
1149c48fcb47Sblueswir1 #else
11505210977aSIgor Kovalenko #if !defined(TARGET_SPARC64)
1151c48fcb47Sblueswir1     env->psret = 0;
1152c48fcb47Sblueswir1     env->psrs = 1;
1153c48fcb47Sblueswir1     env->psrps = 1;
11542aae2b8eSIgor V. Kovalenko #endif
1155c48fcb47Sblueswir1 #ifdef TARGET_SPARC64
11568194f35aSIgor Kovalenko     env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
11572aae2b8eSIgor V. Kovalenko     env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
11588194f35aSIgor Kovalenko     env->tl = env->maxtl;
11598194f35aSIgor Kovalenko     cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
1160415fc906Sblueswir1     env->lsu = 0;
1161c48fcb47Sblueswir1 #else
1162c48fcb47Sblueswir1     env->mmuregs[0] &= ~(MMU_E | MMU_NF);
11635578ceabSblueswir1     env->mmuregs[0] |= env->def->mmu_bm;
1164c48fcb47Sblueswir1 #endif
1165e87231d4Sblueswir1     env->pc = 0;
1166c48fcb47Sblueswir1     env->npc = env->pc + 4;
1167c48fcb47Sblueswir1 #endif
1168b04d9890SFabien Chouteau     env->cache_control = 0;
1169c48fcb47Sblueswir1 }
1170c48fcb47Sblueswir1 
117164a88d5dSblueswir1 static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
1172c48fcb47Sblueswir1 {
117364a88d5dSblueswir1     sparc_def_t def1, *def = &def1;
1174c48fcb47Sblueswir1 
117564a88d5dSblueswir1     if (cpu_sparc_find_by_name(def, cpu_model) < 0)
117664a88d5dSblueswir1         return -1;
1177c48fcb47Sblueswir1 
11787267c094SAnthony Liguori     env->def = g_malloc0(sizeof(*def));
11795578ceabSblueswir1     memcpy(env->def, def, sizeof(*def));
11805578ceabSblueswir1 #if defined(CONFIG_USER_ONLY)
11815578ceabSblueswir1     if ((env->def->features & CPU_FEATURE_FLOAT))
11825578ceabSblueswir1         env->def->features |= CPU_FEATURE_FLOAT128;
11835578ceabSblueswir1 #endif
1184c48fcb47Sblueswir1     env->cpu_model_str = cpu_model;
1185c48fcb47Sblueswir1     env->version = def->iu_version;
1186c48fcb47Sblueswir1     env->fsr = def->fpu_version;
11871a14026eSblueswir1     env->nwindows = def->nwindows;
1188c48fcb47Sblueswir1 #if !defined(TARGET_SPARC64)
1189c48fcb47Sblueswir1     env->mmuregs[0] |= def->mmu_version;
1190c48fcb47Sblueswir1     cpu_sparc_set_id(env, 0);
1191963262deSblueswir1     env->mxccregs[7] |= def->mxcc_version;
11921a14026eSblueswir1 #else
1193fb79ceb9Sblueswir1     env->mmu_version = def->mmu_version;
1194c19148bdSblueswir1     env->maxtl = def->maxtl;
1195c19148bdSblueswir1     env->version |= def->maxtl << 8;
11961a14026eSblueswir1     env->version |= def->nwindows - 1;
1197c48fcb47Sblueswir1 #endif
119864a88d5dSblueswir1     return 0;
119964a88d5dSblueswir1 }
120064a88d5dSblueswir1 
120164a88d5dSblueswir1 static void cpu_sparc_close(CPUSPARCState *env)
120264a88d5dSblueswir1 {
12035578ceabSblueswir1     free(env->def);
120464a88d5dSblueswir1     free(env);
120564a88d5dSblueswir1 }
120664a88d5dSblueswir1 
120764a88d5dSblueswir1 CPUSPARCState *cpu_sparc_init(const char *cpu_model)
120864a88d5dSblueswir1 {
120964a88d5dSblueswir1     CPUSPARCState *env;
121064a88d5dSblueswir1 
12117267c094SAnthony Liguori     env = g_malloc0(sizeof(CPUSPARCState));
121264a88d5dSblueswir1     cpu_exec_init(env);
1213c48fcb47Sblueswir1 
1214c48fcb47Sblueswir1     gen_intermediate_code_init(env);
1215c48fcb47Sblueswir1 
121664a88d5dSblueswir1     if (cpu_sparc_register(env, cpu_model) < 0) {
121764a88d5dSblueswir1         cpu_sparc_close(env);
121864a88d5dSblueswir1         return NULL;
121964a88d5dSblueswir1     }
12200bf46a40Saliguori     qemu_init_vcpu(env);
1221c48fcb47Sblueswir1 
1222c48fcb47Sblueswir1     return env;
1223c48fcb47Sblueswir1 }
1224c48fcb47Sblueswir1 
1225c48fcb47Sblueswir1 void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
1226c48fcb47Sblueswir1 {
1227c48fcb47Sblueswir1 #if !defined(TARGET_SPARC64)
1228c48fcb47Sblueswir1     env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
1229c48fcb47Sblueswir1 #endif
1230c48fcb47Sblueswir1 }
1231c48fcb47Sblueswir1 
1232c48fcb47Sblueswir1 static const sparc_def_t sparc_defs[] = {
1233c48fcb47Sblueswir1 #ifdef TARGET_SPARC64
1234c48fcb47Sblueswir1     {
1235c48fcb47Sblueswir1         .name = "Fujitsu Sparc64",
1236c19148bdSblueswir1         .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
1237c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1238fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12391a14026eSblueswir1         .nwindows = 4,
1240c19148bdSblueswir1         .maxtl = 4,
124164a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1242c48fcb47Sblueswir1     },
1243c48fcb47Sblueswir1     {
1244c48fcb47Sblueswir1         .name = "Fujitsu Sparc64 III",
1245c19148bdSblueswir1         .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
1246c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1247fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12481a14026eSblueswir1         .nwindows = 5,
1249c19148bdSblueswir1         .maxtl = 4,
125064a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1251c48fcb47Sblueswir1     },
1252c48fcb47Sblueswir1     {
1253c48fcb47Sblueswir1         .name = "Fujitsu Sparc64 IV",
1254c19148bdSblueswir1         .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
1255c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1256fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12571a14026eSblueswir1         .nwindows = 8,
1258c19148bdSblueswir1         .maxtl = 5,
125964a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1260c48fcb47Sblueswir1     },
1261c48fcb47Sblueswir1     {
1262c48fcb47Sblueswir1         .name = "Fujitsu Sparc64 V",
1263c19148bdSblueswir1         .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
1264c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1265fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12661a14026eSblueswir1         .nwindows = 8,
1267c19148bdSblueswir1         .maxtl = 5,
126864a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1269c48fcb47Sblueswir1     },
1270c48fcb47Sblueswir1     {
1271c48fcb47Sblueswir1         .name = "TI UltraSparc I",
1272c19148bdSblueswir1         .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
1273c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1274fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12751a14026eSblueswir1         .nwindows = 8,
1276c19148bdSblueswir1         .maxtl = 5,
127764a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1278c48fcb47Sblueswir1     },
1279c48fcb47Sblueswir1     {
1280c48fcb47Sblueswir1         .name = "TI UltraSparc II",
1281c19148bdSblueswir1         .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
1282c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1283fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12841a14026eSblueswir1         .nwindows = 8,
1285c19148bdSblueswir1         .maxtl = 5,
128664a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1287c48fcb47Sblueswir1     },
1288c48fcb47Sblueswir1     {
1289c48fcb47Sblueswir1         .name = "TI UltraSparc IIi",
1290c19148bdSblueswir1         .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
1291c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1292fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12931a14026eSblueswir1         .nwindows = 8,
1294c19148bdSblueswir1         .maxtl = 5,
129564a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1296c48fcb47Sblueswir1     },
1297c48fcb47Sblueswir1     {
1298c48fcb47Sblueswir1         .name = "TI UltraSparc IIe",
1299c19148bdSblueswir1         .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
1300c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1301fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
13021a14026eSblueswir1         .nwindows = 8,
1303c19148bdSblueswir1         .maxtl = 5,
130464a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1305c48fcb47Sblueswir1     },
1306c48fcb47Sblueswir1     {
1307c48fcb47Sblueswir1         .name = "Sun UltraSparc III",
1308c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
1309c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1310fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
13111a14026eSblueswir1         .nwindows = 8,
1312c19148bdSblueswir1         .maxtl = 5,
131364a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1314c48fcb47Sblueswir1     },
1315c48fcb47Sblueswir1     {
1316c48fcb47Sblueswir1         .name = "Sun UltraSparc III Cu",
1317c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
1318c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1319fb79ceb9Sblueswir1         .mmu_version = mmu_us_3,
13201a14026eSblueswir1         .nwindows = 8,
1321c19148bdSblueswir1         .maxtl = 5,
132264a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1323c48fcb47Sblueswir1     },
1324c48fcb47Sblueswir1     {
1325c48fcb47Sblueswir1         .name = "Sun UltraSparc IIIi",
1326c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
1327c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1328fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
13291a14026eSblueswir1         .nwindows = 8,
1330c19148bdSblueswir1         .maxtl = 5,
133164a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1332c48fcb47Sblueswir1     },
1333c48fcb47Sblueswir1     {
1334c48fcb47Sblueswir1         .name = "Sun UltraSparc IV",
1335c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
1336c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1337fb79ceb9Sblueswir1         .mmu_version = mmu_us_4,
13381a14026eSblueswir1         .nwindows = 8,
1339c19148bdSblueswir1         .maxtl = 5,
134064a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1341c48fcb47Sblueswir1     },
1342c48fcb47Sblueswir1     {
1343c48fcb47Sblueswir1         .name = "Sun UltraSparc IV+",
1344c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
1345c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1346fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
13471a14026eSblueswir1         .nwindows = 8,
1348c19148bdSblueswir1         .maxtl = 5,
1349fb79ceb9Sblueswir1         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
1350c48fcb47Sblueswir1     },
1351c48fcb47Sblueswir1     {
1352c48fcb47Sblueswir1         .name = "Sun UltraSparc IIIi+",
1353c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
1354c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1355fb79ceb9Sblueswir1         .mmu_version = mmu_us_3,
13561a14026eSblueswir1         .nwindows = 8,
1357c19148bdSblueswir1         .maxtl = 5,
135864a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1359c48fcb47Sblueswir1     },
1360c48fcb47Sblueswir1     {
1361c7ba218dSblueswir1         .name = "Sun UltraSparc T1",
1362c7ba218dSblueswir1         // defined in sparc_ifu_fdp.v and ctu.h
1363c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
1364c7ba218dSblueswir1         .fpu_version = 0x00000000,
1365c7ba218dSblueswir1         .mmu_version = mmu_sun4v,
1366c7ba218dSblueswir1         .nwindows = 8,
1367c19148bdSblueswir1         .maxtl = 6,
1368c7ba218dSblueswir1         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
1369c7ba218dSblueswir1         | CPU_FEATURE_GL,
1370c7ba218dSblueswir1     },
1371c7ba218dSblueswir1     {
1372c7ba218dSblueswir1         .name = "Sun UltraSparc T2",
1373c7ba218dSblueswir1         // defined in tlu_asi_ctl.v and n2_revid_cust.v
1374c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
1375c7ba218dSblueswir1         .fpu_version = 0x00000000,
1376c7ba218dSblueswir1         .mmu_version = mmu_sun4v,
1377c7ba218dSblueswir1         .nwindows = 8,
1378c19148bdSblueswir1         .maxtl = 6,
1379c7ba218dSblueswir1         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
1380c7ba218dSblueswir1         | CPU_FEATURE_GL,
1381c7ba218dSblueswir1     },
1382c7ba218dSblueswir1     {
1383c48fcb47Sblueswir1         .name = "NEC UltraSparc I",
1384c19148bdSblueswir1         .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
1385c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1386fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
13871a14026eSblueswir1         .nwindows = 8,
1388c19148bdSblueswir1         .maxtl = 5,
138964a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1390c48fcb47Sblueswir1     },
1391c48fcb47Sblueswir1 #else
1392c48fcb47Sblueswir1     {
1393c48fcb47Sblueswir1         .name = "Fujitsu MB86900",
1394c48fcb47Sblueswir1         .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
1395c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1396c48fcb47Sblueswir1         .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
1397c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1398c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1399c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1400c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1401c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
14021a14026eSblueswir1         .nwindows = 7,
1403e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
1404c48fcb47Sblueswir1     },
1405c48fcb47Sblueswir1     {
1406c48fcb47Sblueswir1         .name = "Fujitsu MB86904",
1407c48fcb47Sblueswir1         .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
1408c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1409c48fcb47Sblueswir1         .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
1410c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1411c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x00ffffc0,
1412c48fcb47Sblueswir1         .mmu_cxr_mask = 0x000000ff,
1413c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016fff,
1414c48fcb47Sblueswir1         .mmu_trcr_mask = 0x00ffffff,
14151a14026eSblueswir1         .nwindows = 8,
141664a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1417c48fcb47Sblueswir1     },
1418c48fcb47Sblueswir1     {
1419c48fcb47Sblueswir1         .name = "Fujitsu MB86907",
1420c48fcb47Sblueswir1         .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
1421c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1422c48fcb47Sblueswir1         .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
1423c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1424c48fcb47Sblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1425c48fcb47Sblueswir1         .mmu_cxr_mask = 0x000000ff,
1426c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016fff,
1427c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
14281a14026eSblueswir1         .nwindows = 8,
142964a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1430c48fcb47Sblueswir1     },
1431c48fcb47Sblueswir1     {
1432c48fcb47Sblueswir1         .name = "LSI L64811",
1433c48fcb47Sblueswir1         .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
1434c48fcb47Sblueswir1         .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
1435c48fcb47Sblueswir1         .mmu_version = 0x10 << 24,
1436c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1437c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1438c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1439c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1440c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
14411a14026eSblueswir1         .nwindows = 8,
1442e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1443e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1444c48fcb47Sblueswir1     },
1445c48fcb47Sblueswir1     {
1446c48fcb47Sblueswir1         .name = "Cypress CY7C601",
1447c48fcb47Sblueswir1         .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
1448c48fcb47Sblueswir1         .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
1449c48fcb47Sblueswir1         .mmu_version = 0x10 << 24,
1450c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1451c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1452c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1453c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1454c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
14551a14026eSblueswir1         .nwindows = 8,
1456e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1457e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1458c48fcb47Sblueswir1     },
1459c48fcb47Sblueswir1     {
1460c48fcb47Sblueswir1         .name = "Cypress CY7C611",
1461c48fcb47Sblueswir1         .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
1462c48fcb47Sblueswir1         .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
1463c48fcb47Sblueswir1         .mmu_version = 0x10 << 24,
1464c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1465c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1466c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1467c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1468c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
14691a14026eSblueswir1         .nwindows = 8,
1470e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1471e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1472c48fcb47Sblueswir1     },
1473c48fcb47Sblueswir1     {
1474c48fcb47Sblueswir1         .name = "TI MicroSparc I",
1475c48fcb47Sblueswir1         .iu_version = 0x41000000,
1476c48fcb47Sblueswir1         .fpu_version = 4 << 17,
1477c48fcb47Sblueswir1         .mmu_version = 0x41000000,
1478c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1479c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1480c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1481c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016fff,
1482c48fcb47Sblueswir1         .mmu_trcr_mask = 0x0000003f,
14831a14026eSblueswir1         .nwindows = 7,
1484e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
1485e30b4678Sblueswir1         CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
1486e30b4678Sblueswir1         CPU_FEATURE_FMUL,
1487c48fcb47Sblueswir1     },
1488c48fcb47Sblueswir1     {
1489c48fcb47Sblueswir1         .name = "TI MicroSparc II",
1490c48fcb47Sblueswir1         .iu_version = 0x42000000,
1491c48fcb47Sblueswir1         .fpu_version = 4 << 17,
1492c48fcb47Sblueswir1         .mmu_version = 0x02000000,
1493c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1494c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x00ffffc0,
1495c48fcb47Sblueswir1         .mmu_cxr_mask = 0x000000ff,
1496c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016fff,
1497c48fcb47Sblueswir1         .mmu_trcr_mask = 0x00ffffff,
14981a14026eSblueswir1         .nwindows = 8,
149964a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1500c48fcb47Sblueswir1     },
1501c48fcb47Sblueswir1     {
1502c48fcb47Sblueswir1         .name = "TI MicroSparc IIep",
1503c48fcb47Sblueswir1         .iu_version = 0x42000000,
1504c48fcb47Sblueswir1         .fpu_version = 4 << 17,
1505c48fcb47Sblueswir1         .mmu_version = 0x04000000,
1506c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1507c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x00ffffc0,
1508c48fcb47Sblueswir1         .mmu_cxr_mask = 0x000000ff,
1509c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016bff,
1510c48fcb47Sblueswir1         .mmu_trcr_mask = 0x00ffffff,
15111a14026eSblueswir1         .nwindows = 8,
151264a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1513c48fcb47Sblueswir1     },
1514c48fcb47Sblueswir1     {
1515b5154bdeSblueswir1         .name = "TI SuperSparc 40", // STP1020NPGA
1516963262deSblueswir1         .iu_version = 0x41000000, // SuperSPARC 2.x
1517b5154bdeSblueswir1         .fpu_version = 0 << 17,
1518963262deSblueswir1         .mmu_version = 0x00000800, // SuperSPARC 2.x, no MXCC
1519b5154bdeSblueswir1         .mmu_bm = 0x00002000,
1520b5154bdeSblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1521b5154bdeSblueswir1         .mmu_cxr_mask = 0x0000ffff,
1522b5154bdeSblueswir1         .mmu_sfsr_mask = 0xffffffff,
1523b5154bdeSblueswir1         .mmu_trcr_mask = 0xffffffff,
15241a14026eSblueswir1         .nwindows = 8,
1525b5154bdeSblueswir1         .features = CPU_DEFAULT_FEATURES,
1526b5154bdeSblueswir1     },
1527b5154bdeSblueswir1     {
1528b5154bdeSblueswir1         .name = "TI SuperSparc 50", // STP1020PGA
1529963262deSblueswir1         .iu_version = 0x40000000, // SuperSPARC 3.x
1530b5154bdeSblueswir1         .fpu_version = 0 << 17,
1531963262deSblueswir1         .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
1532b5154bdeSblueswir1         .mmu_bm = 0x00002000,
1533b5154bdeSblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1534b5154bdeSblueswir1         .mmu_cxr_mask = 0x0000ffff,
1535b5154bdeSblueswir1         .mmu_sfsr_mask = 0xffffffff,
1536b5154bdeSblueswir1         .mmu_trcr_mask = 0xffffffff,
15371a14026eSblueswir1         .nwindows = 8,
1538b5154bdeSblueswir1         .features = CPU_DEFAULT_FEATURES,
1539b5154bdeSblueswir1     },
1540b5154bdeSblueswir1     {
1541c48fcb47Sblueswir1         .name = "TI SuperSparc 51",
1542963262deSblueswir1         .iu_version = 0x40000000, // SuperSPARC 3.x
1543c48fcb47Sblueswir1         .fpu_version = 0 << 17,
1544963262deSblueswir1         .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
1545c48fcb47Sblueswir1         .mmu_bm = 0x00002000,
1546c48fcb47Sblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1547c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000ffff,
1548c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1549c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
1550963262deSblueswir1         .mxcc_version = 0x00000104,
15511a14026eSblueswir1         .nwindows = 8,
155264a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1553c48fcb47Sblueswir1     },
1554c48fcb47Sblueswir1     {
1555b5154bdeSblueswir1         .name = "TI SuperSparc 60", // STP1020APGA
1556963262deSblueswir1         .iu_version = 0x40000000, // SuperSPARC 3.x
1557b5154bdeSblueswir1         .fpu_version = 0 << 17,
1558963262deSblueswir1         .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
1559b5154bdeSblueswir1         .mmu_bm = 0x00002000,
1560b5154bdeSblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1561b5154bdeSblueswir1         .mmu_cxr_mask = 0x0000ffff,
1562b5154bdeSblueswir1         .mmu_sfsr_mask = 0xffffffff,
1563b5154bdeSblueswir1         .mmu_trcr_mask = 0xffffffff,
15641a14026eSblueswir1         .nwindows = 8,
1565b5154bdeSblueswir1         .features = CPU_DEFAULT_FEATURES,
1566b5154bdeSblueswir1     },
1567b5154bdeSblueswir1     {
1568c48fcb47Sblueswir1         .name = "TI SuperSparc 61",
1569963262deSblueswir1         .iu_version = 0x44000000, // SuperSPARC 3.x
1570c48fcb47Sblueswir1         .fpu_version = 0 << 17,
1571963262deSblueswir1         .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
1572c48fcb47Sblueswir1         .mmu_bm = 0x00002000,
1573c48fcb47Sblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1574c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000ffff,
1575c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1576c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
1577963262deSblueswir1         .mxcc_version = 0x00000104,
1578963262deSblueswir1         .nwindows = 8,
1579963262deSblueswir1         .features = CPU_DEFAULT_FEATURES,
1580963262deSblueswir1     },
1581963262deSblueswir1     {
1582963262deSblueswir1         .name = "TI SuperSparc II",
1583963262deSblueswir1         .iu_version = 0x40000000, // SuperSPARC II 1.x
1584963262deSblueswir1         .fpu_version = 0 << 17,
1585963262deSblueswir1         .mmu_version = 0x08000000, // SuperSPARC II 1.x, MXCC
1586963262deSblueswir1         .mmu_bm = 0x00002000,
1587963262deSblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1588963262deSblueswir1         .mmu_cxr_mask = 0x0000ffff,
1589963262deSblueswir1         .mmu_sfsr_mask = 0xffffffff,
1590963262deSblueswir1         .mmu_trcr_mask = 0xffffffff,
1591963262deSblueswir1         .mxcc_version = 0x00000104,
15921a14026eSblueswir1         .nwindows = 8,
159364a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1594c48fcb47Sblueswir1     },
1595c48fcb47Sblueswir1     {
1596c48fcb47Sblueswir1         .name = "Ross RT625",
1597c48fcb47Sblueswir1         .iu_version = 0x1e000000,
1598c48fcb47Sblueswir1         .fpu_version = 1 << 17,
1599c48fcb47Sblueswir1         .mmu_version = 0x1e000000,
1600c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1601c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1602c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1603c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1604c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
16051a14026eSblueswir1         .nwindows = 8,
160664a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1607c48fcb47Sblueswir1     },
1608c48fcb47Sblueswir1     {
1609c48fcb47Sblueswir1         .name = "Ross RT620",
1610c48fcb47Sblueswir1         .iu_version = 0x1f000000,
1611c48fcb47Sblueswir1         .fpu_version = 1 << 17,
1612c48fcb47Sblueswir1         .mmu_version = 0x1f000000,
1613c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1614c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1615c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1616c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1617c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
16181a14026eSblueswir1         .nwindows = 8,
161964a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1620c48fcb47Sblueswir1     },
1621c48fcb47Sblueswir1     {
1622c48fcb47Sblueswir1         .name = "BIT B5010",
1623c48fcb47Sblueswir1         .iu_version = 0x20000000,
1624c48fcb47Sblueswir1         .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
1625c48fcb47Sblueswir1         .mmu_version = 0x20000000,
1626c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1627c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1628c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1629c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1630c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
16311a14026eSblueswir1         .nwindows = 8,
1632e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1633e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1634c48fcb47Sblueswir1     },
1635c48fcb47Sblueswir1     {
1636c48fcb47Sblueswir1         .name = "Matsushita MN10501",
1637c48fcb47Sblueswir1         .iu_version = 0x50000000,
1638c48fcb47Sblueswir1         .fpu_version = 0 << 17,
1639c48fcb47Sblueswir1         .mmu_version = 0x50000000,
1640c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1641c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1642c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1643c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1644c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
16451a14026eSblueswir1         .nwindows = 8,
1646e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
1647e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1648c48fcb47Sblueswir1     },
1649c48fcb47Sblueswir1     {
1650c48fcb47Sblueswir1         .name = "Weitek W8601",
1651c48fcb47Sblueswir1         .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
1652c48fcb47Sblueswir1         .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
1653c48fcb47Sblueswir1         .mmu_version = 0x10 << 24,
1654c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1655c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1656c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1657c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1658c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
16591a14026eSblueswir1         .nwindows = 8,
166064a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1661c48fcb47Sblueswir1     },
1662c48fcb47Sblueswir1     {
1663c48fcb47Sblueswir1         .name = "LEON2",
1664c48fcb47Sblueswir1         .iu_version = 0xf2000000,
1665c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1666c48fcb47Sblueswir1         .mmu_version = 0xf2000000,
1667c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1668c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1669c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1670c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1671c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
16721a14026eSblueswir1         .nwindows = 8,
1673b04d9890SFabien Chouteau         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
1674c48fcb47Sblueswir1     },
1675c48fcb47Sblueswir1     {
1676c48fcb47Sblueswir1         .name = "LEON3",
1677c48fcb47Sblueswir1         .iu_version = 0xf3000000,
1678c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1679c48fcb47Sblueswir1         .mmu_version = 0xf3000000,
1680b04d9890SFabien Chouteau         .mmu_bm = 0x00000000,
1681c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1682c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1683c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1684c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
16851a14026eSblueswir1         .nwindows = 8,
16864a2ba232SFabien Chouteau         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
168760f356e8SFabien Chouteau         CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
1688c48fcb47Sblueswir1     },
1689c48fcb47Sblueswir1 #endif
1690c48fcb47Sblueswir1 };
1691c48fcb47Sblueswir1 
169264a88d5dSblueswir1 static const char * const feature_name[] = {
169364a88d5dSblueswir1     "float",
169464a88d5dSblueswir1     "float128",
169564a88d5dSblueswir1     "swap",
169664a88d5dSblueswir1     "mul",
169764a88d5dSblueswir1     "div",
169864a88d5dSblueswir1     "flush",
169964a88d5dSblueswir1     "fsqrt",
170064a88d5dSblueswir1     "fmul",
170164a88d5dSblueswir1     "vis1",
170264a88d5dSblueswir1     "vis2",
1703e30b4678Sblueswir1     "fsmuld",
1704fb79ceb9Sblueswir1     "hypv",
1705fb79ceb9Sblueswir1     "cmt",
1706fb79ceb9Sblueswir1     "gl",
170764a88d5dSblueswir1 };
170864a88d5dSblueswir1 
17099a78eeadSStefan Weil static void print_features(FILE *f, fprintf_function cpu_fprintf,
171064a88d5dSblueswir1                            uint32_t features, const char *prefix)
1711c48fcb47Sblueswir1 {
1712c48fcb47Sblueswir1     unsigned int i;
1713c48fcb47Sblueswir1 
171464a88d5dSblueswir1     for (i = 0; i < ARRAY_SIZE(feature_name); i++)
171564a88d5dSblueswir1         if (feature_name[i] && (features & (1 << i))) {
171664a88d5dSblueswir1             if (prefix)
171764a88d5dSblueswir1                 (*cpu_fprintf)(f, "%s", prefix);
171864a88d5dSblueswir1             (*cpu_fprintf)(f, "%s ", feature_name[i]);
171964a88d5dSblueswir1         }
172064a88d5dSblueswir1 }
172164a88d5dSblueswir1 
172264a88d5dSblueswir1 static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
172364a88d5dSblueswir1 {
172464a88d5dSblueswir1     unsigned int i;
172564a88d5dSblueswir1 
172664a88d5dSblueswir1     for (i = 0; i < ARRAY_SIZE(feature_name); i++)
172764a88d5dSblueswir1         if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
172864a88d5dSblueswir1             *features |= 1 << i;
172964a88d5dSblueswir1             return;
173064a88d5dSblueswir1         }
173164a88d5dSblueswir1     fprintf(stderr, "CPU feature %s not found\n", flagname);
173264a88d5dSblueswir1 }
173364a88d5dSblueswir1 
173422548760Sblueswir1 static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
173564a88d5dSblueswir1 {
173664a88d5dSblueswir1     unsigned int i;
173764a88d5dSblueswir1     const sparc_def_t *def = NULL;
173864a88d5dSblueswir1     char *s = strdup(cpu_model);
173964a88d5dSblueswir1     char *featurestr, *name = strtok(s, ",");
174064a88d5dSblueswir1     uint32_t plus_features = 0;
174164a88d5dSblueswir1     uint32_t minus_features = 0;
17420bfcd599SBlue Swirl     uint64_t iu_version;
17431a14026eSblueswir1     uint32_t fpu_version, mmu_version, nwindows;
174464a88d5dSblueswir1 
1745b1503cdaSmalc     for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
1746c48fcb47Sblueswir1         if (strcasecmp(name, sparc_defs[i].name) == 0) {
174764a88d5dSblueswir1             def = &sparc_defs[i];
1748c48fcb47Sblueswir1         }
1749c48fcb47Sblueswir1     }
175064a88d5dSblueswir1     if (!def)
175164a88d5dSblueswir1         goto error;
175264a88d5dSblueswir1     memcpy(cpu_def, def, sizeof(*def));
175364a88d5dSblueswir1 
175464a88d5dSblueswir1     featurestr = strtok(NULL, ",");
175564a88d5dSblueswir1     while (featurestr) {
175664a88d5dSblueswir1         char *val;
175764a88d5dSblueswir1 
175864a88d5dSblueswir1         if (featurestr[0] == '+') {
175964a88d5dSblueswir1             add_flagname_to_bitmaps(featurestr + 1, &plus_features);
176064a88d5dSblueswir1         } else if (featurestr[0] == '-') {
176164a88d5dSblueswir1             add_flagname_to_bitmaps(featurestr + 1, &minus_features);
176264a88d5dSblueswir1         } else if ((val = strchr(featurestr, '='))) {
176364a88d5dSblueswir1             *val = 0; val++;
176464a88d5dSblueswir1             if (!strcmp(featurestr, "iu_version")) {
176564a88d5dSblueswir1                 char *err;
176664a88d5dSblueswir1 
176764a88d5dSblueswir1                 iu_version = strtoll(val, &err, 0);
176864a88d5dSblueswir1                 if (!*val || *err) {
176964a88d5dSblueswir1                     fprintf(stderr, "bad numerical value %s\n", val);
177064a88d5dSblueswir1                     goto error;
177164a88d5dSblueswir1                 }
177264a88d5dSblueswir1                 cpu_def->iu_version = iu_version;
177364a88d5dSblueswir1 #ifdef DEBUG_FEATURES
17740bfcd599SBlue Swirl                 fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
177564a88d5dSblueswir1 #endif
177664a88d5dSblueswir1             } else if (!strcmp(featurestr, "fpu_version")) {
177764a88d5dSblueswir1                 char *err;
177864a88d5dSblueswir1 
177964a88d5dSblueswir1                 fpu_version = strtol(val, &err, 0);
178064a88d5dSblueswir1                 if (!*val || *err) {
178164a88d5dSblueswir1                     fprintf(stderr, "bad numerical value %s\n", val);
178264a88d5dSblueswir1                     goto error;
178364a88d5dSblueswir1                 }
178464a88d5dSblueswir1                 cpu_def->fpu_version = fpu_version;
178564a88d5dSblueswir1 #ifdef DEBUG_FEATURES
17860bf9e31aSBlue Swirl                 fprintf(stderr, "fpu_version %x\n", fpu_version);
178764a88d5dSblueswir1 #endif
178864a88d5dSblueswir1             } else if (!strcmp(featurestr, "mmu_version")) {
178964a88d5dSblueswir1                 char *err;
179064a88d5dSblueswir1 
179164a88d5dSblueswir1                 mmu_version = strtol(val, &err, 0);
179264a88d5dSblueswir1                 if (!*val || *err) {
179364a88d5dSblueswir1                     fprintf(stderr, "bad numerical value %s\n", val);
179464a88d5dSblueswir1                     goto error;
179564a88d5dSblueswir1                 }
179664a88d5dSblueswir1                 cpu_def->mmu_version = mmu_version;
179764a88d5dSblueswir1 #ifdef DEBUG_FEATURES
17980bf9e31aSBlue Swirl                 fprintf(stderr, "mmu_version %x\n", mmu_version);
179964a88d5dSblueswir1 #endif
18001a14026eSblueswir1             } else if (!strcmp(featurestr, "nwindows")) {
18011a14026eSblueswir1                 char *err;
18021a14026eSblueswir1 
18031a14026eSblueswir1                 nwindows = strtol(val, &err, 0);
18041a14026eSblueswir1                 if (!*val || *err || nwindows > MAX_NWINDOWS ||
18051a14026eSblueswir1                     nwindows < MIN_NWINDOWS) {
18061a14026eSblueswir1                     fprintf(stderr, "bad numerical value %s\n", val);
18071a14026eSblueswir1                     goto error;
18081a14026eSblueswir1                 }
18091a14026eSblueswir1                 cpu_def->nwindows = nwindows;
18101a14026eSblueswir1 #ifdef DEBUG_FEATURES
18111a14026eSblueswir1                 fprintf(stderr, "nwindows %d\n", nwindows);
18121a14026eSblueswir1 #endif
181364a88d5dSblueswir1             } else {
181464a88d5dSblueswir1                 fprintf(stderr, "unrecognized feature %s\n", featurestr);
181564a88d5dSblueswir1                 goto error;
181664a88d5dSblueswir1             }
181764a88d5dSblueswir1         } else {
181877f193daSblueswir1             fprintf(stderr, "feature string `%s' not in format "
181977f193daSblueswir1                     "(+feature|-feature|feature=xyz)\n", featurestr);
182064a88d5dSblueswir1             goto error;
182164a88d5dSblueswir1         }
182264a88d5dSblueswir1         featurestr = strtok(NULL, ",");
182364a88d5dSblueswir1     }
182464a88d5dSblueswir1     cpu_def->features |= plus_features;
182564a88d5dSblueswir1     cpu_def->features &= ~minus_features;
182664a88d5dSblueswir1 #ifdef DEBUG_FEATURES
182764a88d5dSblueswir1     print_features(stderr, fprintf, cpu_def->features, NULL);
182864a88d5dSblueswir1 #endif
182964a88d5dSblueswir1     free(s);
183064a88d5dSblueswir1     return 0;
183164a88d5dSblueswir1 
183264a88d5dSblueswir1  error:
183364a88d5dSblueswir1     free(s);
183464a88d5dSblueswir1     return -1;
1835c48fcb47Sblueswir1 }
1836c48fcb47Sblueswir1 
18379a78eeadSStefan Weil void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
1838c48fcb47Sblueswir1 {
1839c48fcb47Sblueswir1     unsigned int i;
1840c48fcb47Sblueswir1 
1841b1503cdaSmalc     for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
18421a14026eSblueswir1         (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x NWINS %d ",
1843c48fcb47Sblueswir1                        sparc_defs[i].name,
1844c48fcb47Sblueswir1                        sparc_defs[i].iu_version,
1845c48fcb47Sblueswir1                        sparc_defs[i].fpu_version,
18461a14026eSblueswir1                        sparc_defs[i].mmu_version,
18471a14026eSblueswir1                        sparc_defs[i].nwindows);
184877f193daSblueswir1         print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
184977f193daSblueswir1                        ~sparc_defs[i].features, "-");
185077f193daSblueswir1         print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
185177f193daSblueswir1                        sparc_defs[i].features, "+");
185264a88d5dSblueswir1         (*cpu_fprintf)(f, "\n");
1853c48fcb47Sblueswir1     }
1854f76981b1Sblueswir1     (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
1855f76981b1Sblueswir1     print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
185664a88d5dSblueswir1     (*cpu_fprintf)(f, "\n");
1857f76981b1Sblueswir1     (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
1858f76981b1Sblueswir1     print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
1859f76981b1Sblueswir1     (*cpu_fprintf)(f, "\n");
1860f76981b1Sblueswir1     (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
1861f76981b1Sblueswir1                    "fpu_version mmu_version nwindows\n");
1862c48fcb47Sblueswir1 }
1863c48fcb47Sblueswir1 
18649a78eeadSStefan Weil static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
186543bb98bfSBlue Swirl                          uint32_t cc)
186643bb98bfSBlue Swirl {
186743bb98bfSBlue Swirl     cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG? 'N' : '-',
186843bb98bfSBlue Swirl                 cc & PSR_ZERO? 'Z' : '-', cc & PSR_OVF? 'V' : '-',
186943bb98bfSBlue Swirl                 cc & PSR_CARRY? 'C' : '-');
187043bb98bfSBlue Swirl }
187143bb98bfSBlue Swirl 
187243bb98bfSBlue Swirl #ifdef TARGET_SPARC64
187343bb98bfSBlue Swirl #define REGS_PER_LINE 4
187443bb98bfSBlue Swirl #else
187543bb98bfSBlue Swirl #define REGS_PER_LINE 8
187643bb98bfSBlue Swirl #endif
187743bb98bfSBlue Swirl 
18789a78eeadSStefan Weil void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
1879c48fcb47Sblueswir1                     int flags)
1880c48fcb47Sblueswir1 {
1881c48fcb47Sblueswir1     int i, x;
1882c48fcb47Sblueswir1 
188377f193daSblueswir1     cpu_fprintf(f, "pc: " TARGET_FMT_lx "  npc: " TARGET_FMT_lx "\n", env->pc,
188477f193daSblueswir1                 env->npc);
1885c48fcb47Sblueswir1     cpu_fprintf(f, "General Registers:\n");
188643bb98bfSBlue Swirl 
188743bb98bfSBlue Swirl     for (i = 0; i < 8; i++) {
188843bb98bfSBlue Swirl         if (i % REGS_PER_LINE == 0) {
188943bb98bfSBlue Swirl             cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
189043bb98bfSBlue Swirl         }
189143bb98bfSBlue Swirl         cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
189243bb98bfSBlue Swirl         if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
1893c48fcb47Sblueswir1             cpu_fprintf(f, "\n");
1894c48fcb47Sblueswir1         }
189543bb98bfSBlue Swirl     }
189643bb98bfSBlue Swirl     cpu_fprintf(f, "\nCurrent Register Window:\n");
189743bb98bfSBlue Swirl     for (x = 0; x < 3; x++) {
189843bb98bfSBlue Swirl         for (i = 0; i < 8; i++) {
189943bb98bfSBlue Swirl             if (i % REGS_PER_LINE == 0) {
190043bb98bfSBlue Swirl                 cpu_fprintf(f, "%%%c%d-%d: ",
190143bb98bfSBlue Swirl                             x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
190243bb98bfSBlue Swirl                             i, i + REGS_PER_LINE - 1);
190343bb98bfSBlue Swirl             }
190443bb98bfSBlue Swirl             cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
190543bb98bfSBlue Swirl             if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
190643bb98bfSBlue Swirl                 cpu_fprintf(f, "\n");
190743bb98bfSBlue Swirl             }
190843bb98bfSBlue Swirl         }
190943bb98bfSBlue Swirl     }
1910c48fcb47Sblueswir1     cpu_fprintf(f, "\nFloating Point Registers:\n");
191143bb98bfSBlue Swirl     for (i = 0; i < TARGET_FPREGS; i++) {
1912c48fcb47Sblueswir1         if ((i & 3) == 0)
1913c48fcb47Sblueswir1             cpu_fprintf(f, "%%f%02d:", i);
1914a37ee56cSblueswir1         cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
1915c48fcb47Sblueswir1         if ((i & 3) == 3)
1916c48fcb47Sblueswir1             cpu_fprintf(f, "\n");
1917c48fcb47Sblueswir1     }
1918c48fcb47Sblueswir1 #ifdef TARGET_SPARC64
191943bb98bfSBlue Swirl     cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
1920113c6106SStefan Weil                 (unsigned)cpu_get_ccr(env));
19215a834bb4SBlue Swirl     cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
192243bb98bfSBlue Swirl     cpu_fprintf(f, " xcc: ");
19235a834bb4SBlue Swirl     cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
192443bb98bfSBlue Swirl     cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
192543bb98bfSBlue Swirl                 env->psrpil);
192643bb98bfSBlue Swirl     cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
192743bb98bfSBlue Swirl                 "cleanwin: %d cwp: %d\n",
1928c48fcb47Sblueswir1                 env->cansave, env->canrestore, env->otherwin, env->wstate,
19291a14026eSblueswir1                 env->cleanwin, env->nwindows - 1 - env->cwp);
193043bb98bfSBlue Swirl     cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
193143bb98bfSBlue Swirl                 TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
1932c48fcb47Sblueswir1 #else
19335a834bb4SBlue Swirl     cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
19345a834bb4SBlue Swirl     cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
193543bb98bfSBlue Swirl     cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs? 'S' : '-',
193643bb98bfSBlue Swirl                 env->psrps? 'P' : '-', env->psret? 'E' : '-',
193743bb98bfSBlue Swirl                 env->wim);
193843bb98bfSBlue Swirl     cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
193943bb98bfSBlue Swirl                 env->fsr, env->y);
1940c48fcb47Sblueswir1 #endif
1941c48fcb47Sblueswir1 }
1942