xref: /qemu/target/sparc/helper.c (revision 3b8b030a280f3b496602dc7d2ee5c68e480ec10b)
1e8af50a3Sbellard /*
2e8af50a3Sbellard  *  sparc helpers
3e8af50a3Sbellard  *
483469015Sbellard  *  Copyright (c) 2003-2005 Fabrice Bellard
5e8af50a3Sbellard  *
6e8af50a3Sbellard  * This library is free software; you can redistribute it and/or
7e8af50a3Sbellard  * modify it under the terms of the GNU Lesser General Public
8e8af50a3Sbellard  * License as published by the Free Software Foundation; either
9e8af50a3Sbellard  * version 2 of the License, or (at your option) any later version.
10e8af50a3Sbellard  *
11e8af50a3Sbellard  * This library is distributed in the hope that it will be useful,
12e8af50a3Sbellard  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13e8af50a3Sbellard  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14e8af50a3Sbellard  * Lesser General Public License for more details.
15e8af50a3Sbellard  *
16e8af50a3Sbellard  * You should have received a copy of the GNU Lesser General Public
178167ee88SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18e8af50a3Sbellard  */
19ee5bbe38Sbellard #include <stdarg.h>
20ee5bbe38Sbellard #include <stdlib.h>
21ee5bbe38Sbellard #include <stdio.h>
22ee5bbe38Sbellard #include <string.h>
23ee5bbe38Sbellard #include <inttypes.h>
24ee5bbe38Sbellard 
25ee5bbe38Sbellard #include "cpu.h"
26ca10f867Saurel32 #include "qemu-common.h"
27e8af50a3Sbellard 
28e80cfcfcSbellard //#define DEBUG_MMU
2964a88d5dSblueswir1 //#define DEBUG_FEATURES
30e8af50a3Sbellard 
31b8e9fc06SIgor V. Kovalenko #ifdef DEBUG_MMU
32b8e9fc06SIgor V. Kovalenko #define DPRINTF_MMU(fmt, ...) \
33b8e9fc06SIgor V. Kovalenko     do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
34b8e9fc06SIgor V. Kovalenko #else
35b8e9fc06SIgor V. Kovalenko #define DPRINTF_MMU(fmt, ...) do {} while (0)
36b8e9fc06SIgor V. Kovalenko #endif
37b8e9fc06SIgor V. Kovalenko 
3822548760Sblueswir1 static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
39c48fcb47Sblueswir1 
40e8af50a3Sbellard /* Sparc MMU emulation */
41e8af50a3Sbellard 
429d893301Sbellard #if defined(CONFIG_USER_ONLY)
439d893301Sbellard 
4422548760Sblueswir1 int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
456ebbf390Sj_mayer                                int mmu_idx, int is_softmmu)
469d893301Sbellard {
47878d3096Sbellard     if (rw & 2)
4822548760Sblueswir1         env1->exception_index = TT_TFAULT;
49878d3096Sbellard     else
5022548760Sblueswir1         env1->exception_index = TT_DFAULT;
519d893301Sbellard     return 1;
529d893301Sbellard }
539d893301Sbellard 
549d893301Sbellard #else
55e8af50a3Sbellard 
563475187dSbellard #ifndef TARGET_SPARC64
5783469015Sbellard /*
5883469015Sbellard  * Sparc V8 Reference MMU (SRMMU)
5983469015Sbellard  */
60e8af50a3Sbellard static const int access_table[8][8] = {
61a764a566Sblueswir1     { 0, 0, 0, 0, 8, 0, 12, 12 },
62a764a566Sblueswir1     { 0, 0, 0, 0, 8, 0, 0, 0 },
63a764a566Sblueswir1     { 8, 8, 0, 0, 0, 8, 12, 12 },
64a764a566Sblueswir1     { 8, 8, 0, 0, 0, 8, 0, 0 },
65a764a566Sblueswir1     { 8, 0, 8, 0, 8, 8, 12, 12 },
66a764a566Sblueswir1     { 8, 0, 8, 0, 8, 0, 8, 0 },
67a764a566Sblueswir1     { 8, 8, 8, 0, 8, 8, 12, 12 },
68a764a566Sblueswir1     { 8, 8, 8, 0, 8, 8, 8, 0 }
69e8af50a3Sbellard };
70e8af50a3Sbellard 
71227671c9Sbellard static const int perm_table[2][8] = {
72227671c9Sbellard     {
73227671c9Sbellard         PAGE_READ,
74227671c9Sbellard         PAGE_READ | PAGE_WRITE,
75227671c9Sbellard         PAGE_READ | PAGE_EXEC,
76227671c9Sbellard         PAGE_READ | PAGE_WRITE | PAGE_EXEC,
77227671c9Sbellard         PAGE_EXEC,
78227671c9Sbellard         PAGE_READ | PAGE_WRITE,
79227671c9Sbellard         PAGE_READ | PAGE_EXEC,
80227671c9Sbellard         PAGE_READ | PAGE_WRITE | PAGE_EXEC
81227671c9Sbellard     },
82227671c9Sbellard     {
83227671c9Sbellard         PAGE_READ,
84227671c9Sbellard         PAGE_READ | PAGE_WRITE,
85227671c9Sbellard         PAGE_READ | PAGE_EXEC,
86227671c9Sbellard         PAGE_READ | PAGE_WRITE | PAGE_EXEC,
87227671c9Sbellard         PAGE_EXEC,
88227671c9Sbellard         PAGE_READ,
89227671c9Sbellard         0,
90227671c9Sbellard         0,
91227671c9Sbellard     }
92e8af50a3Sbellard };
93e8af50a3Sbellard 
94c227f099SAnthony Liguori static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
95c48fcb47Sblueswir1                                 int *prot, int *access_index,
96d4c430a8SPaul Brook                                 target_ulong address, int rw, int mmu_idx,
97d4c430a8SPaul Brook                                 target_ulong *page_size)
98e8af50a3Sbellard {
99e80cfcfcSbellard     int access_perms = 0;
100c227f099SAnthony Liguori     target_phys_addr_t pde_ptr;
101af7bf89bSbellard     uint32_t pde;
1026ebbf390Sj_mayer     int error_code = 0, is_dirty, is_user;
103e80cfcfcSbellard     unsigned long page_offset;
104e8af50a3Sbellard 
1056ebbf390Sj_mayer     is_user = mmu_idx == MMU_USER_IDX;
10640ce0a9aSblueswir1 
107e8af50a3Sbellard     if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
108d4c430a8SPaul Brook         *page_size = TARGET_PAGE_SIZE;
10940ce0a9aSblueswir1         // Boot mode: instruction fetches are taken from PROM
1105578ceabSblueswir1         if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
11158a770f3Sblueswir1             *physical = env->prom_addr | (address & 0x7ffffULL);
11240ce0a9aSblueswir1             *prot = PAGE_READ | PAGE_EXEC;
11340ce0a9aSblueswir1             return 0;
11440ce0a9aSblueswir1         }
115e80cfcfcSbellard         *physical = address;
116227671c9Sbellard         *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
117e80cfcfcSbellard         return 0;
118e8af50a3Sbellard     }
119e8af50a3Sbellard 
1207483750dSbellard     *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
1215dcb6b91Sblueswir1     *physical = 0xffffffffffff0000ULL;
1227483750dSbellard 
123e8af50a3Sbellard     /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
124e8af50a3Sbellard     /* Context base + context number */
1253deaeab7Sblueswir1     pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
12649be8030Sbellard     pde = ldl_phys(pde_ptr);
127e8af50a3Sbellard 
128e8af50a3Sbellard     /* Ctx pde */
129e8af50a3Sbellard     switch (pde & PTE_ENTRYTYPE_MASK) {
130e80cfcfcSbellard     default:
131e8af50a3Sbellard     case 0: /* Invalid */
1327483750dSbellard         return 1 << 2;
133e80cfcfcSbellard     case 2: /* L0 PTE, maybe should not happen? */
134e8af50a3Sbellard     case 3: /* Reserved */
1357483750dSbellard         return 4 << 2;
136e80cfcfcSbellard     case 1: /* L0 PDE */
137e80cfcfcSbellard         pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
13849be8030Sbellard         pde = ldl_phys(pde_ptr);
139e80cfcfcSbellard 
140e80cfcfcSbellard         switch (pde & PTE_ENTRYTYPE_MASK) {
141e80cfcfcSbellard         default:
142e80cfcfcSbellard         case 0: /* Invalid */
1437483750dSbellard             return (1 << 8) | (1 << 2);
144e80cfcfcSbellard         case 3: /* Reserved */
1457483750dSbellard             return (1 << 8) | (4 << 2);
146e8af50a3Sbellard         case 1: /* L1 PDE */
147e80cfcfcSbellard             pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
14849be8030Sbellard             pde = ldl_phys(pde_ptr);
149e8af50a3Sbellard 
150e8af50a3Sbellard             switch (pde & PTE_ENTRYTYPE_MASK) {
151e80cfcfcSbellard             default:
152e8af50a3Sbellard             case 0: /* Invalid */
1537483750dSbellard                 return (2 << 8) | (1 << 2);
154e8af50a3Sbellard             case 3: /* Reserved */
1557483750dSbellard                 return (2 << 8) | (4 << 2);
156e8af50a3Sbellard             case 1: /* L2 PDE */
157e80cfcfcSbellard                 pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
15849be8030Sbellard                 pde = ldl_phys(pde_ptr);
159e8af50a3Sbellard 
160e8af50a3Sbellard                 switch (pde & PTE_ENTRYTYPE_MASK) {
161e80cfcfcSbellard                 default:
162e8af50a3Sbellard                 case 0: /* Invalid */
1637483750dSbellard                     return (3 << 8) | (1 << 2);
164e8af50a3Sbellard                 case 1: /* PDE, should not happen */
165e8af50a3Sbellard                 case 3: /* Reserved */
1667483750dSbellard                     return (3 << 8) | (4 << 2);
167e8af50a3Sbellard                 case 2: /* L3 PTE */
16877f193daSblueswir1                     page_offset = (address & TARGET_PAGE_MASK) &
16977f193daSblueswir1                         (TARGET_PAGE_SIZE - 1);
170e8af50a3Sbellard                 }
171d4c430a8SPaul Brook                 *page_size = TARGET_PAGE_SIZE;
172e8af50a3Sbellard                 break;
173e8af50a3Sbellard             case 2: /* L2 PTE */
174e8af50a3Sbellard                 page_offset = address & 0x3ffff;
175d4c430a8SPaul Brook                 *page_size = 0x40000;
176e8af50a3Sbellard             }
177e8af50a3Sbellard             break;
178e8af50a3Sbellard         case 2: /* L1 PTE */
179e8af50a3Sbellard             page_offset = address & 0xffffff;
180d4c430a8SPaul Brook             *page_size = 0x1000000;
181e8af50a3Sbellard         }
182e8af50a3Sbellard     }
183e8af50a3Sbellard 
184698235aaSArtyom Tarasenko     /* check access */
185698235aaSArtyom Tarasenko     access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
186698235aaSArtyom Tarasenko     error_code = access_table[*access_index][access_perms];
187698235aaSArtyom Tarasenko     if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user))
188698235aaSArtyom Tarasenko         return error_code;
189698235aaSArtyom Tarasenko 
190e8af50a3Sbellard     /* update page modified and dirty bits */
191b769d8feSbellard     is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
192e8af50a3Sbellard     if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
193e8af50a3Sbellard         pde |= PG_ACCESSED_MASK;
194e8af50a3Sbellard         if (is_dirty)
195e8af50a3Sbellard             pde |= PG_MODIFIED_MASK;
19649be8030Sbellard         stl_phys_notdirty(pde_ptr, pde);
197e8af50a3Sbellard     }
198e8af50a3Sbellard 
199e8af50a3Sbellard     /* the page can be put in the TLB */
200227671c9Sbellard     *prot = perm_table[is_user][access_perms];
201227671c9Sbellard     if (!(pde & PG_MODIFIED_MASK)) {
202e8af50a3Sbellard         /* only set write access if already dirty... otherwise wait
203e8af50a3Sbellard            for dirty access */
204227671c9Sbellard         *prot &= ~PAGE_WRITE;
205e8af50a3Sbellard     }
206e8af50a3Sbellard 
207e8af50a3Sbellard     /* Even if large ptes, we map only one 4KB page in the cache to
208e8af50a3Sbellard        avoid filling it too fast */
209c227f099SAnthony Liguori     *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
2106f7e9aecSbellard     return error_code;
211e80cfcfcSbellard }
212e80cfcfcSbellard 
213e80cfcfcSbellard /* Perform address translation */
214af7bf89bSbellard int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
2156ebbf390Sj_mayer                               int mmu_idx, int is_softmmu)
216e80cfcfcSbellard {
217c227f099SAnthony Liguori     target_phys_addr_t paddr;
2185dcb6b91Sblueswir1     target_ulong vaddr;
219d4c430a8SPaul Brook     target_ulong page_size;
220d4c430a8SPaul Brook     int error_code = 0, prot, access_index;
221e80cfcfcSbellard 
22277f193daSblueswir1     error_code = get_physical_address(env, &paddr, &prot, &access_index,
223d4c430a8SPaul Brook                                       address, rw, mmu_idx, &page_size);
224e80cfcfcSbellard     if (error_code == 0) {
2259e61bde5Sbellard         vaddr = address & TARGET_PAGE_MASK;
2269e61bde5Sbellard         paddr &= TARGET_PAGE_MASK;
2279e61bde5Sbellard #ifdef DEBUG_MMU
2285dcb6b91Sblueswir1         printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
2295dcb6b91Sblueswir1                TARGET_FMT_lx "\n", address, paddr, vaddr);
2309e61bde5Sbellard #endif
231d4c430a8SPaul Brook         tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
232d4c430a8SPaul Brook         return 0;
233e80cfcfcSbellard     }
234e8af50a3Sbellard 
235e8af50a3Sbellard     if (env->mmuregs[3]) /* Fault status register */
236e8af50a3Sbellard         env->mmuregs[3] = 1; /* overflow (not read before another fault) */
2377483750dSbellard     env->mmuregs[3] |= (access_index << 5) | error_code | 2;
238e8af50a3Sbellard     env->mmuregs[4] = address; /* Fault address register */
239e8af50a3Sbellard 
240878d3096Sbellard     if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
2416f7e9aecSbellard         // No fault mode: if a mapping is available, just override
2426f7e9aecSbellard         // permissions. If no mapping is available, redirect accesses to
2436f7e9aecSbellard         // neverland. Fake/overridden mappings will be flushed when
2446f7e9aecSbellard         // switching to normal mode.
2457483750dSbellard         vaddr = address & TARGET_PAGE_MASK;
246227671c9Sbellard         prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
247d4c430a8SPaul Brook         tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
248d4c430a8SPaul Brook         return 0;
2497483750dSbellard     } else {
250878d3096Sbellard         if (rw & 2)
251878d3096Sbellard             env->exception_index = TT_TFAULT;
252878d3096Sbellard         else
253878d3096Sbellard             env->exception_index = TT_DFAULT;
254878d3096Sbellard         return 1;
255e8af50a3Sbellard     }
2567483750dSbellard }
25724741ef3Sbellard 
25824741ef3Sbellard target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
25924741ef3Sbellard {
260c227f099SAnthony Liguori     target_phys_addr_t pde_ptr;
26124741ef3Sbellard     uint32_t pde;
26224741ef3Sbellard 
26324741ef3Sbellard     /* Context base + context number */
264c227f099SAnthony Liguori     pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
2655dcb6b91Sblueswir1         (env->mmuregs[2] << 2);
26624741ef3Sbellard     pde = ldl_phys(pde_ptr);
26724741ef3Sbellard 
26824741ef3Sbellard     switch (pde & PTE_ENTRYTYPE_MASK) {
26924741ef3Sbellard     default:
27024741ef3Sbellard     case 0: /* Invalid */
27124741ef3Sbellard     case 2: /* PTE, maybe should not happen? */
27224741ef3Sbellard     case 3: /* Reserved */
27324741ef3Sbellard         return 0;
27424741ef3Sbellard     case 1: /* L1 PDE */
27524741ef3Sbellard         if (mmulev == 3)
27624741ef3Sbellard             return pde;
27724741ef3Sbellard         pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
27824741ef3Sbellard         pde = ldl_phys(pde_ptr);
27924741ef3Sbellard 
28024741ef3Sbellard         switch (pde & PTE_ENTRYTYPE_MASK) {
28124741ef3Sbellard         default:
28224741ef3Sbellard         case 0: /* Invalid */
28324741ef3Sbellard         case 3: /* Reserved */
28424741ef3Sbellard             return 0;
28524741ef3Sbellard         case 2: /* L1 PTE */
28624741ef3Sbellard             return pde;
28724741ef3Sbellard         case 1: /* L2 PDE */
28824741ef3Sbellard             if (mmulev == 2)
28924741ef3Sbellard                 return pde;
29024741ef3Sbellard             pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
29124741ef3Sbellard             pde = ldl_phys(pde_ptr);
29224741ef3Sbellard 
29324741ef3Sbellard             switch (pde & PTE_ENTRYTYPE_MASK) {
29424741ef3Sbellard             default:
29524741ef3Sbellard             case 0: /* Invalid */
29624741ef3Sbellard             case 3: /* Reserved */
29724741ef3Sbellard                 return 0;
29824741ef3Sbellard             case 2: /* L2 PTE */
29924741ef3Sbellard                 return pde;
30024741ef3Sbellard             case 1: /* L3 PDE */
30124741ef3Sbellard                 if (mmulev == 1)
30224741ef3Sbellard                     return pde;
30324741ef3Sbellard                 pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
30424741ef3Sbellard                 pde = ldl_phys(pde_ptr);
30524741ef3Sbellard 
30624741ef3Sbellard                 switch (pde & PTE_ENTRYTYPE_MASK) {
30724741ef3Sbellard                 default:
30824741ef3Sbellard                 case 0: /* Invalid */
30924741ef3Sbellard                 case 1: /* PDE, should not happen */
31024741ef3Sbellard                 case 3: /* Reserved */
31124741ef3Sbellard                     return 0;
31224741ef3Sbellard                 case 2: /* L3 PTE */
31324741ef3Sbellard                     return pde;
31424741ef3Sbellard                 }
31524741ef3Sbellard             }
31624741ef3Sbellard         }
31724741ef3Sbellard     }
31824741ef3Sbellard     return 0;
31924741ef3Sbellard }
32024741ef3Sbellard 
321d41160a3SBlue Swirl void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
32224741ef3Sbellard {
32324741ef3Sbellard     target_ulong va, va1, va2;
32424741ef3Sbellard     unsigned int n, m, o;
325c227f099SAnthony Liguori     target_phys_addr_t pde_ptr, pa;
32624741ef3Sbellard     uint32_t pde;
32724741ef3Sbellard 
32824741ef3Sbellard     pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
32924741ef3Sbellard     pde = ldl_phys(pde_ptr);
330d41160a3SBlue Swirl     (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
331c227f099SAnthony Liguori                    (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
33224741ef3Sbellard     for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
3335dcb6b91Sblueswir1         pde = mmu_probe(env, va, 2);
3345dcb6b91Sblueswir1         if (pde) {
33524741ef3Sbellard             pa = cpu_get_phys_page_debug(env, va);
336d41160a3SBlue Swirl             (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
3375dcb6b91Sblueswir1                            " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
33824741ef3Sbellard             for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
3395dcb6b91Sblueswir1                 pde = mmu_probe(env, va1, 1);
3405dcb6b91Sblueswir1                 if (pde) {
34124741ef3Sbellard                     pa = cpu_get_phys_page_debug(env, va1);
342d41160a3SBlue Swirl                     (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
343d41160a3SBlue Swirl                                    TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
344d41160a3SBlue Swirl                                    va1, pa, pde);
34524741ef3Sbellard                     for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
3465dcb6b91Sblueswir1                         pde = mmu_probe(env, va2, 0);
3475dcb6b91Sblueswir1                         if (pde) {
34824741ef3Sbellard                             pa = cpu_get_phys_page_debug(env, va2);
349d41160a3SBlue Swirl                             (*cpu_fprintf)(f, "  VA: " TARGET_FMT_lx ", PA: "
350d41160a3SBlue Swirl                                            TARGET_FMT_plx " PTE: "
351d41160a3SBlue Swirl                                            TARGET_FMT_lx "\n",
3525dcb6b91Sblueswir1                                            va2, pa, pde);
35324741ef3Sbellard                         }
35424741ef3Sbellard                     }
35524741ef3Sbellard                 }
35624741ef3Sbellard             }
35724741ef3Sbellard         }
35824741ef3Sbellard     }
35924741ef3Sbellard }
36024741ef3Sbellard 
36124741ef3Sbellard #else /* !TARGET_SPARC64 */
362e8807b14SIgor Kovalenko 
363e8807b14SIgor Kovalenko // 41 bit physical address space
364c227f099SAnthony Liguori static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
365e8807b14SIgor Kovalenko {
366e8807b14SIgor Kovalenko     return x & 0x1ffffffffffULL;
367e8807b14SIgor Kovalenko }
368e8807b14SIgor Kovalenko 
36983469015Sbellard /*
37083469015Sbellard  * UltraSparc IIi I/DMMUs
37183469015Sbellard  */
3723475187dSbellard 
373536ba015SIgor Kovalenko // Returns true if TTE tag is valid and matches virtual address value in context
374536ba015SIgor Kovalenko // requires virtual address mask value calculated from TTE entry size
3756e8e7d4cSIgor Kovalenko static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
376536ba015SIgor Kovalenko                                        uint64_t address, uint64_t context,
377299b520cSIgor V. Kovalenko                                        target_phys_addr_t *physical)
378536ba015SIgor Kovalenko {
379536ba015SIgor Kovalenko     uint64_t mask;
380536ba015SIgor Kovalenko 
38106e12b65STsuneo Saito     switch (TTE_PGSIZE(tlb->tte)) {
3823475187dSbellard     default:
38383469015Sbellard     case 0x0: // 8k
3843475187dSbellard         mask = 0xffffffffffffe000ULL;
3853475187dSbellard         break;
38683469015Sbellard     case 0x1: // 64k
3873475187dSbellard         mask = 0xffffffffffff0000ULL;
3883475187dSbellard         break;
38983469015Sbellard     case 0x2: // 512k
3903475187dSbellard         mask = 0xfffffffffff80000ULL;
3913475187dSbellard         break;
39283469015Sbellard     case 0x3: // 4M
3933475187dSbellard         mask = 0xffffffffffc00000ULL;
3943475187dSbellard         break;
3953475187dSbellard     }
396536ba015SIgor Kovalenko 
397536ba015SIgor Kovalenko     // valid, context match, virtual address match?
398f707726eSIgor Kovalenko     if (TTE_IS_VALID(tlb->tte) &&
399299b520cSIgor V. Kovalenko         (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
4002a90358fSBlue Swirl         && compare_masked(address, tlb->tag, mask))
401536ba015SIgor Kovalenko     {
402536ba015SIgor Kovalenko         // decode physical address
4036e8e7d4cSIgor Kovalenko         *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
404536ba015SIgor Kovalenko         return 1;
405536ba015SIgor Kovalenko     }
406536ba015SIgor Kovalenko 
407536ba015SIgor Kovalenko     return 0;
408536ba015SIgor Kovalenko }
409536ba015SIgor Kovalenko 
410536ba015SIgor Kovalenko static int get_physical_address_data(CPUState *env,
411c227f099SAnthony Liguori                                      target_phys_addr_t *physical, int *prot,
4122065061eSIgor V. Kovalenko                                      target_ulong address, int rw, int mmu_idx)
413536ba015SIgor Kovalenko {
414536ba015SIgor Kovalenko     unsigned int i;
415536ba015SIgor Kovalenko     uint64_t context;
416ccc76c24STsuneo Saito     uint64_t sfsr = 0;
417536ba015SIgor Kovalenko 
4182065061eSIgor V. Kovalenko     int is_user = (mmu_idx == MMU_USER_IDX ||
4192065061eSIgor V. Kovalenko                    mmu_idx == MMU_USER_SECONDARY_IDX);
4202065061eSIgor V. Kovalenko 
421536ba015SIgor Kovalenko     if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
422536ba015SIgor Kovalenko         *physical = ultrasparc_truncate_physical(address);
423536ba015SIgor Kovalenko         *prot = PAGE_READ | PAGE_WRITE;
424536ba015SIgor Kovalenko         return 0;
425536ba015SIgor Kovalenko     }
426536ba015SIgor Kovalenko 
4272065061eSIgor V. Kovalenko     switch(mmu_idx) {
4282065061eSIgor V. Kovalenko     case MMU_USER_IDX:
4292065061eSIgor V. Kovalenko     case MMU_KERNEL_IDX:
4306e8e7d4cSIgor Kovalenko         context = env->dmmu.mmu_primary_context & 0x1fff;
431ccc76c24STsuneo Saito         sfsr |= SFSR_CT_PRIMARY;
4322065061eSIgor V. Kovalenko         break;
4332065061eSIgor V. Kovalenko     case MMU_USER_SECONDARY_IDX:
4342065061eSIgor V. Kovalenko     case MMU_KERNEL_SECONDARY_IDX:
4352065061eSIgor V. Kovalenko         context = env->dmmu.mmu_secondary_context & 0x1fff;
436ccc76c24STsuneo Saito         sfsr |= SFSR_CT_SECONDARY;
4372065061eSIgor V. Kovalenko         break;
4382065061eSIgor V. Kovalenko     case MMU_NUCLEUS_IDX:
439ccc76c24STsuneo Saito         sfsr |= SFSR_CT_NUCLEUS;
440ccc76c24STsuneo Saito         /* FALLTHRU */
44144505216SBlue Swirl     default:
442299b520cSIgor V. Kovalenko         context = 0;
4432065061eSIgor V. Kovalenko         break;
444299b520cSIgor V. Kovalenko     }
445536ba015SIgor Kovalenko 
446ccc76c24STsuneo Saito     if (rw == 1) {
447ccc76c24STsuneo Saito         sfsr |= SFSR_WRITE_BIT;
448d1afc48bSTsuneo Saito     } else if (rw == 4) {
449d1afc48bSTsuneo Saito         sfsr |= SFSR_NF_BIT;
450ccc76c24STsuneo Saito     }
451ccc76c24STsuneo Saito 
452536ba015SIgor Kovalenko     for (i = 0; i < 64; i++) {
453afdf8109Sblueswir1         // ctx match, vaddr match, valid?
454b8e9fc06SIgor V. Kovalenko         if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
455d1afc48bSTsuneo Saito             int do_fault = 0;
456b8e9fc06SIgor V. Kovalenko 
457b8e9fc06SIgor V. Kovalenko             // access ok?
458d1afc48bSTsuneo Saito             /* multiple bits in SFSR.FT may be set on TT_DFAULT */
45906e12b65STsuneo Saito             if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
460d1afc48bSTsuneo Saito                 do_fault = 1;
461ccc76c24STsuneo Saito                 sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */
462b8e9fc06SIgor V. Kovalenko 
463b8e9fc06SIgor V. Kovalenko                 DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64
464b8e9fc06SIgor V. Kovalenko                             " mmu_idx=%d tl=%d\n",
465b8e9fc06SIgor V. Kovalenko                             address, context, mmu_idx, env->tl);
466d1afc48bSTsuneo Saito             }
467d1afc48bSTsuneo Saito             if (rw == 4) {
468d1afc48bSTsuneo Saito                 if (TTE_IS_SIDEEFFECT(env->dtlb[i].tte)) {
469d1afc48bSTsuneo Saito                     do_fault = 1;
470d1afc48bSTsuneo Saito                     sfsr |= SFSR_FT_NF_E_BIT;
471d1afc48bSTsuneo Saito                 }
472d1afc48bSTsuneo Saito             } else {
473d1afc48bSTsuneo Saito                 if (TTE_IS_NFO(env->dtlb[i].tte)) {
474d1afc48bSTsuneo Saito                     do_fault = 1;
475d1afc48bSTsuneo Saito                     sfsr |= SFSR_FT_NFO_BIT;
476d1afc48bSTsuneo Saito                 }
477d1afc48bSTsuneo Saito             }
478d1afc48bSTsuneo Saito 
479d1afc48bSTsuneo Saito             if (do_fault) {
480d1afc48bSTsuneo Saito                 /* faults above are reported with TT_DFAULT. */
481d1afc48bSTsuneo Saito                 env->exception_index = TT_DFAULT;
48206e12b65STsuneo Saito             } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) {
483d1afc48bSTsuneo Saito                 do_fault = 1;
484b8e9fc06SIgor V. Kovalenko                 env->exception_index = TT_DPROT;
485b8e9fc06SIgor V. Kovalenko 
486b8e9fc06SIgor V. Kovalenko                 DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64
487b8e9fc06SIgor V. Kovalenko                             " mmu_idx=%d tl=%d\n",
488b8e9fc06SIgor V. Kovalenko                             address, context, mmu_idx, env->tl);
489d1afc48bSTsuneo Saito             }
490d1afc48bSTsuneo Saito 
491d1afc48bSTsuneo Saito             if (!do_fault) {
492b8e9fc06SIgor V. Kovalenko                 *prot = PAGE_READ;
49306e12b65STsuneo Saito                 if (TTE_IS_W_OK(env->dtlb[i].tte)) {
494b8e9fc06SIgor V. Kovalenko                     *prot |= PAGE_WRITE;
49506e12b65STsuneo Saito                 }
496b8e9fc06SIgor V. Kovalenko 
497b8e9fc06SIgor V. Kovalenko                 TTE_SET_USED(env->dtlb[i].tte);
498b8e9fc06SIgor V. Kovalenko 
499b8e9fc06SIgor V. Kovalenko                 return 0;
5006e8e7d4cSIgor Kovalenko             }
5016e8e7d4cSIgor Kovalenko 
502ccc76c24STsuneo Saito             if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
503ccc76c24STsuneo Saito                 sfsr |= SFSR_OW_BIT; /* overflow (not read before
50477f193daSblueswir1                                         another fault) */
505ccc76c24STsuneo Saito             }
5066e8e7d4cSIgor Kovalenko 
507ccc76c24STsuneo Saito             if (env->pstate & PS_PRIV) {
508ccc76c24STsuneo Saito                 sfsr |= SFSR_PR_BIT;
509ccc76c24STsuneo Saito             }
5106e8e7d4cSIgor Kovalenko 
511ccc76c24STsuneo Saito             /* FIXME: ASI field in SFSR must be set */
512ccc76c24STsuneo Saito             env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
5136e8e7d4cSIgor Kovalenko 
5146e8e7d4cSIgor Kovalenko             env->dmmu.sfar = address; /* Fault address register */
5159168b3a5SIgor V. Kovalenko 
5169168b3a5SIgor V. Kovalenko             env->dmmu.tag_access = (address & ~0x1fffULL) | context;
5179168b3a5SIgor V. Kovalenko 
5183475187dSbellard             return 1;
5193475187dSbellard         }
5203475187dSbellard     }
521b8e9fc06SIgor V. Kovalenko 
522b8e9fc06SIgor V. Kovalenko     DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n",
523b8e9fc06SIgor V. Kovalenko                 address, context);
524b8e9fc06SIgor V. Kovalenko 
525ccc76c24STsuneo Saito     /*
526ccc76c24STsuneo Saito      * On MMU misses:
527ccc76c24STsuneo Saito      * - UltraSPARC IIi: SFSR and SFAR unmodified
528ccc76c24STsuneo Saito      * - JPS1: SFAR updated and some fields of SFSR updated
529ccc76c24STsuneo Saito      */
5306e8e7d4cSIgor Kovalenko     env->dmmu.tag_access = (address & ~0x1fffULL) | context;
53183469015Sbellard     env->exception_index = TT_DMISS;
5323475187dSbellard     return 1;
5333475187dSbellard }
5343475187dSbellard 
53577f193daSblueswir1 static int get_physical_address_code(CPUState *env,
536c227f099SAnthony Liguori                                      target_phys_addr_t *physical, int *prot,
5372065061eSIgor V. Kovalenko                                      target_ulong address, int mmu_idx)
5383475187dSbellard {
5393475187dSbellard     unsigned int i;
540536ba015SIgor Kovalenko     uint64_t context;
5413475187dSbellard 
5422065061eSIgor V. Kovalenko     int is_user = (mmu_idx == MMU_USER_IDX ||
5432065061eSIgor V. Kovalenko                    mmu_idx == MMU_USER_SECONDARY_IDX);
5442065061eSIgor V. Kovalenko 
545e8807b14SIgor Kovalenko     if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
546e8807b14SIgor Kovalenko         /* IMMU disabled */
547e8807b14SIgor Kovalenko         *physical = ultrasparc_truncate_physical(address);
548227671c9Sbellard         *prot = PAGE_EXEC;
5493475187dSbellard         return 0;
5503475187dSbellard     }
55183469015Sbellard 
552299b520cSIgor V. Kovalenko     if (env->tl == 0) {
5532065061eSIgor V. Kovalenko         /* PRIMARY context */
5546e8e7d4cSIgor Kovalenko         context = env->dmmu.mmu_primary_context & 0x1fff;
555299b520cSIgor V. Kovalenko     } else {
5562065061eSIgor V. Kovalenko         /* NUCLEUS context */
557299b520cSIgor V. Kovalenko         context = 0;
558299b520cSIgor V. Kovalenko     }
559536ba015SIgor Kovalenko 
5603475187dSbellard     for (i = 0; i < 64; i++) {
561afdf8109Sblueswir1         // ctx match, vaddr match, valid?
5626e8e7d4cSIgor Kovalenko         if (ultrasparc_tag_match(&env->itlb[i],
563299b520cSIgor V. Kovalenko                                  address, context, physical)) {
564afdf8109Sblueswir1             // access ok?
56506e12b65STsuneo Saito             if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
566ccc76c24STsuneo Saito                 /* Fault status register */
567ccc76c24STsuneo Saito                 if (env->immu.sfsr & SFSR_VALID_BIT) {
568ccc76c24STsuneo Saito                     env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
56977f193daSblueswir1                                                      another fault) */
570ccc76c24STsuneo Saito                 } else {
571ccc76c24STsuneo Saito                     env->immu.sfsr = 0;
572ccc76c24STsuneo Saito                 }
573ccc76c24STsuneo Saito                 if (env->pstate & PS_PRIV) {
574ccc76c24STsuneo Saito                     env->immu.sfsr |= SFSR_PR_BIT;
575ccc76c24STsuneo Saito                 }
576ccc76c24STsuneo Saito                 if (env->tl > 0) {
577ccc76c24STsuneo Saito                     env->immu.sfsr |= SFSR_CT_NUCLEUS;
578ccc76c24STsuneo Saito                 }
579ccc76c24STsuneo Saito 
580ccc76c24STsuneo Saito                 /* FIXME: ASI field in SFSR must be set */
581ccc76c24STsuneo Saito                 env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
5823475187dSbellard                 env->exception_index = TT_TFAULT;
583b8e9fc06SIgor V. Kovalenko 
5849168b3a5SIgor V. Kovalenko                 env->immu.tag_access = (address & ~0x1fffULL) | context;
5859168b3a5SIgor V. Kovalenko 
586b8e9fc06SIgor V. Kovalenko                 DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n",
587b8e9fc06SIgor V. Kovalenko                             address, context);
588b8e9fc06SIgor V. Kovalenko 
5893475187dSbellard                 return 1;
5903475187dSbellard             }
591227671c9Sbellard             *prot = PAGE_EXEC;
592f707726eSIgor Kovalenko             TTE_SET_USED(env->itlb[i].tte);
5933475187dSbellard             return 0;
5943475187dSbellard         }
5953475187dSbellard     }
596b8e9fc06SIgor V. Kovalenko 
597b8e9fc06SIgor V. Kovalenko     DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n",
598b8e9fc06SIgor V. Kovalenko                 address, context);
599b8e9fc06SIgor V. Kovalenko 
6007ab463cbSBlue Swirl     /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
6016e8e7d4cSIgor Kovalenko     env->immu.tag_access = (address & ~0x1fffULL) | context;
60283469015Sbellard     env->exception_index = TT_TMISS;
6033475187dSbellard     return 1;
6043475187dSbellard }
6053475187dSbellard 
606c227f099SAnthony Liguori static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
607c48fcb47Sblueswir1                                 int *prot, int *access_index,
608d4c430a8SPaul Brook                                 target_ulong address, int rw, int mmu_idx,
609d4c430a8SPaul Brook                                 target_ulong *page_size)
6103475187dSbellard {
611d4c430a8SPaul Brook     /* ??? We treat everything as a small page, then explicitly flush
612d4c430a8SPaul Brook        everything when an entry is evicted.  */
613d4c430a8SPaul Brook     *page_size = TARGET_PAGE_SIZE;
6149fd1ae3aSIgor V. Kovalenko 
6159fd1ae3aSIgor V. Kovalenko #if defined (DEBUG_MMU)
6169fd1ae3aSIgor V. Kovalenko     /* safety net to catch wrong softmmu index use from dynamic code */
6179fd1ae3aSIgor V. Kovalenko     if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
6189fd1ae3aSIgor V. Kovalenko         DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d"
6199fd1ae3aSIgor V. Kovalenko                     " primary context=%" PRIx64
6209fd1ae3aSIgor V. Kovalenko                     " secondary context=%" PRIx64
6219fd1ae3aSIgor V. Kovalenko                 " address=%" PRIx64
6229fd1ae3aSIgor V. Kovalenko                 "\n",
6239fd1ae3aSIgor V. Kovalenko                 (rw == 2 ? "CODE" : "DATA"),
6249fd1ae3aSIgor V. Kovalenko                 env->tl, mmu_idx,
6259fd1ae3aSIgor V. Kovalenko                 env->dmmu.mmu_primary_context,
6269fd1ae3aSIgor V. Kovalenko                 env->dmmu.mmu_secondary_context,
6279fd1ae3aSIgor V. Kovalenko                 address);
6289fd1ae3aSIgor V. Kovalenko     }
6299fd1ae3aSIgor V. Kovalenko #endif
6309fd1ae3aSIgor V. Kovalenko 
6313475187dSbellard     if (rw == 2)
63222548760Sblueswir1         return get_physical_address_code(env, physical, prot, address,
6332065061eSIgor V. Kovalenko                                          mmu_idx);
6343475187dSbellard     else
63522548760Sblueswir1         return get_physical_address_data(env, physical, prot, address, rw,
6362065061eSIgor V. Kovalenko                                          mmu_idx);
6373475187dSbellard }
6383475187dSbellard 
6393475187dSbellard /* Perform address translation */
6403475187dSbellard int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
6416ebbf390Sj_mayer                               int mmu_idx, int is_softmmu)
6423475187dSbellard {
64383469015Sbellard     target_ulong virt_addr, vaddr;
644c227f099SAnthony Liguori     target_phys_addr_t paddr;
645d4c430a8SPaul Brook     target_ulong page_size;
646d4c430a8SPaul Brook     int error_code = 0, prot, access_index;
6473475187dSbellard 
64877f193daSblueswir1     error_code = get_physical_address(env, &paddr, &prot, &access_index,
649d4c430a8SPaul Brook                                       address, rw, mmu_idx, &page_size);
6503475187dSbellard     if (error_code == 0) {
6513475187dSbellard         virt_addr = address & TARGET_PAGE_MASK;
65277f193daSblueswir1         vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
65377f193daSblueswir1                              (TARGET_PAGE_SIZE - 1));
654b8e9fc06SIgor V. Kovalenko 
655b8e9fc06SIgor V. Kovalenko         DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 ","
656b8e9fc06SIgor V. Kovalenko                     " vaddr %" PRIx64
657b8e9fc06SIgor V. Kovalenko                     " mmu_idx=%d"
658b8e9fc06SIgor V. Kovalenko                     " tl=%d"
659b8e9fc06SIgor V. Kovalenko                     " primary context=%" PRIx64
660b8e9fc06SIgor V. Kovalenko                     " secondary context=%" PRIx64
661b8e9fc06SIgor V. Kovalenko                     "\n",
662b8e9fc06SIgor V. Kovalenko                     address, paddr, vaddr, mmu_idx, env->tl,
663b8e9fc06SIgor V. Kovalenko                     env->dmmu.mmu_primary_context,
664b8e9fc06SIgor V. Kovalenko                     env->dmmu.mmu_secondary_context);
665b8e9fc06SIgor V. Kovalenko 
666d4c430a8SPaul Brook         tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
667d4c430a8SPaul Brook         return 0;
6683475187dSbellard     }
6693475187dSbellard     // XXX
6703475187dSbellard     return 1;
6713475187dSbellard }
6723475187dSbellard 
673d41160a3SBlue Swirl void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
67483469015Sbellard {
67583469015Sbellard     unsigned int i;
67683469015Sbellard     const char *mask;
67783469015Sbellard 
678d41160a3SBlue Swirl     (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
679d41160a3SBlue Swirl                    PRId64 "\n",
680d41160a3SBlue Swirl                    env->dmmu.mmu_primary_context,
681d41160a3SBlue Swirl                    env->dmmu.mmu_secondary_context);
68283469015Sbellard     if ((env->lsu & DMMU_E) == 0) {
683d41160a3SBlue Swirl         (*cpu_fprintf)(f, "DMMU disabled\n");
68483469015Sbellard     } else {
685d41160a3SBlue Swirl         (*cpu_fprintf)(f, "DMMU dump\n");
68683469015Sbellard         for (i = 0; i < 64; i++) {
68706e12b65STsuneo Saito             switch (TTE_PGSIZE(env->dtlb[i].tte)) {
68883469015Sbellard             default:
68983469015Sbellard             case 0x0:
69083469015Sbellard                 mask = "  8k";
69183469015Sbellard                 break;
69283469015Sbellard             case 0x1:
69383469015Sbellard                 mask = " 64k";
69483469015Sbellard                 break;
69583469015Sbellard             case 0x2:
69683469015Sbellard                 mask = "512k";
69783469015Sbellard                 break;
69883469015Sbellard             case 0x3:
69983469015Sbellard                 mask = "  4M";
70083469015Sbellard                 break;
70183469015Sbellard             }
70206e12b65STsuneo Saito             if (TTE_IS_VALID(env->dtlb[i].tte)) {
7033b8b030aSStefan Weil                 (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
7042a90358fSBlue Swirl                                ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
7056e8e7d4cSIgor Kovalenko                                i,
70631a68d57SBlue Swirl                                env->dtlb[i].tag & (uint64_t)~0x1fffULL,
70706e12b65STsuneo Saito                                TTE_PA(env->dtlb[i].tte),
70883469015Sbellard                                mask,
70906e12b65STsuneo Saito                                TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user",
71006e12b65STsuneo Saito                                TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO",
71106e12b65STsuneo Saito                                TTE_IS_LOCKED(env->dtlb[i].tte) ?
71206e12b65STsuneo Saito                                "locked" : "unlocked",
7132a90358fSBlue Swirl                                env->dtlb[i].tag & (uint64_t)0x1fffULL,
714d41160a3SBlue Swirl                                TTE_IS_GLOBAL(env->dtlb[i].tte)?
715d41160a3SBlue Swirl                                "global" : "local");
71683469015Sbellard             }
71783469015Sbellard         }
71883469015Sbellard     }
71983469015Sbellard     if ((env->lsu & IMMU_E) == 0) {
720d41160a3SBlue Swirl         (*cpu_fprintf)(f, "IMMU disabled\n");
72183469015Sbellard     } else {
722d41160a3SBlue Swirl         (*cpu_fprintf)(f, "IMMU dump\n");
72383469015Sbellard         for (i = 0; i < 64; i++) {
72406e12b65STsuneo Saito             switch (TTE_PGSIZE(env->itlb[i].tte)) {
72583469015Sbellard             default:
72683469015Sbellard             case 0x0:
72783469015Sbellard                 mask = "  8k";
72883469015Sbellard                 break;
72983469015Sbellard             case 0x1:
73083469015Sbellard                 mask = " 64k";
73183469015Sbellard                 break;
73283469015Sbellard             case 0x2:
73383469015Sbellard                 mask = "512k";
73483469015Sbellard                 break;
73583469015Sbellard             case 0x3:
73683469015Sbellard                 mask = "  4M";
73783469015Sbellard                 break;
73883469015Sbellard             }
73906e12b65STsuneo Saito             if (TTE_IS_VALID(env->itlb[i].tte)) {
7403b8b030aSStefan Weil                 (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %llx"
7412a90358fSBlue Swirl                                ", %s, %s, %s, ctx %" PRId64 " %s\n",
7426e8e7d4cSIgor Kovalenko                                i,
7436e8e7d4cSIgor Kovalenko                                env->itlb[i].tag & (uint64_t)~0x1fffULL,
74406e12b65STsuneo Saito                                TTE_PA(env->itlb[i].tte),
74583469015Sbellard                                mask,
74606e12b65STsuneo Saito                                TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user",
74706e12b65STsuneo Saito                                TTE_IS_LOCKED(env->itlb[i].tte) ?
74806e12b65STsuneo Saito                                "locked" : "unlocked",
7492a90358fSBlue Swirl                                env->itlb[i].tag & (uint64_t)0x1fffULL,
750d41160a3SBlue Swirl                                TTE_IS_GLOBAL(env->itlb[i].tte)?
751d41160a3SBlue Swirl                                "global" : "local");
75283469015Sbellard             }
75383469015Sbellard         }
75483469015Sbellard     }
75583469015Sbellard }
75624741ef3Sbellard 
75724741ef3Sbellard #endif /* TARGET_SPARC64 */
75824741ef3Sbellard #endif /* !CONFIG_USER_ONLY */
75924741ef3Sbellard 
760c48fcb47Sblueswir1 
7614fcc562bSPaul Brook #if !defined(CONFIG_USER_ONLY)
762321365abSTsuneo Saito static int cpu_sparc_get_phys_page(CPUState *env, target_phys_addr_t *phys,
763321365abSTsuneo Saito                                    target_ulong addr, int rw, int mmu_idx)
764321365abSTsuneo Saito {
765321365abSTsuneo Saito     target_ulong page_size;
766321365abSTsuneo Saito     int prot, access_index;
767321365abSTsuneo Saito 
768321365abSTsuneo Saito     return get_physical_address(env, phys, &prot, &access_index, addr, rw,
769321365abSTsuneo Saito                                 mmu_idx, &page_size);
770321365abSTsuneo Saito }
771321365abSTsuneo Saito 
772b64b6436STsuneo Saito #if defined(TARGET_SPARC64)
7732065061eSIgor V. Kovalenko target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
7742065061eSIgor V. Kovalenko                                            int mmu_idx)
775c48fcb47Sblueswir1 {
776c227f099SAnthony Liguori     target_phys_addr_t phys_addr;
777c48fcb47Sblueswir1 
778d1afc48bSTsuneo Saito     if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 4, mmu_idx) != 0) {
779c48fcb47Sblueswir1         return -1;
780321365abSTsuneo Saito     }
781c48fcb47Sblueswir1     return phys_addr;
782c48fcb47Sblueswir1 }
783b64b6436STsuneo Saito #endif
7842065061eSIgor V. Kovalenko 
7852065061eSIgor V. Kovalenko target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
7862065061eSIgor V. Kovalenko {
787b64b6436STsuneo Saito     target_phys_addr_t phys_addr;
788b64b6436STsuneo Saito     int mmu_idx = cpu_mmu_index(env);
789b64b6436STsuneo Saito 
790b64b6436STsuneo Saito     if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 2, mmu_idx) != 0) {
791b64b6436STsuneo Saito         if (cpu_sparc_get_phys_page(env, &phys_addr, addr, 0, mmu_idx) != 0) {
792b64b6436STsuneo Saito             return -1;
793b64b6436STsuneo Saito         }
794b64b6436STsuneo Saito     }
795b64b6436STsuneo Saito     if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED) {
796b64b6436STsuneo Saito         return -1;
797b64b6436STsuneo Saito     }
798b64b6436STsuneo Saito     return phys_addr;
7992065061eSIgor V. Kovalenko }
800c48fcb47Sblueswir1 #endif
801c48fcb47Sblueswir1 
802e67768d0SBlue Swirl #ifdef TARGET_SPARC64
803e67768d0SBlue Swirl #ifdef DEBUG_PCALL
804e67768d0SBlue Swirl static const char * const excp_names[0x80] = {
805e67768d0SBlue Swirl     [TT_TFAULT] = "Instruction Access Fault",
806e67768d0SBlue Swirl     [TT_TMISS] = "Instruction Access MMU Miss",
807e67768d0SBlue Swirl     [TT_CODE_ACCESS] = "Instruction Access Error",
808e67768d0SBlue Swirl     [TT_ILL_INSN] = "Illegal Instruction",
809e67768d0SBlue Swirl     [TT_PRIV_INSN] = "Privileged Instruction",
810e67768d0SBlue Swirl     [TT_NFPU_INSN] = "FPU Disabled",
811e67768d0SBlue Swirl     [TT_FP_EXCP] = "FPU Exception",
812e67768d0SBlue Swirl     [TT_TOVF] = "Tag Overflow",
813e67768d0SBlue Swirl     [TT_CLRWIN] = "Clean Windows",
814e67768d0SBlue Swirl     [TT_DIV_ZERO] = "Division By Zero",
815e67768d0SBlue Swirl     [TT_DFAULT] = "Data Access Fault",
816e67768d0SBlue Swirl     [TT_DMISS] = "Data Access MMU Miss",
817e67768d0SBlue Swirl     [TT_DATA_ACCESS] = "Data Access Error",
818e67768d0SBlue Swirl     [TT_DPROT] = "Data Protection Error",
819e67768d0SBlue Swirl     [TT_UNALIGNED] = "Unaligned Memory Access",
820e67768d0SBlue Swirl     [TT_PRIV_ACT] = "Privileged Action",
821e67768d0SBlue Swirl     [TT_EXTINT | 0x1] = "External Interrupt 1",
822e67768d0SBlue Swirl     [TT_EXTINT | 0x2] = "External Interrupt 2",
823e67768d0SBlue Swirl     [TT_EXTINT | 0x3] = "External Interrupt 3",
824e67768d0SBlue Swirl     [TT_EXTINT | 0x4] = "External Interrupt 4",
825e67768d0SBlue Swirl     [TT_EXTINT | 0x5] = "External Interrupt 5",
826e67768d0SBlue Swirl     [TT_EXTINT | 0x6] = "External Interrupt 6",
827e67768d0SBlue Swirl     [TT_EXTINT | 0x7] = "External Interrupt 7",
828e67768d0SBlue Swirl     [TT_EXTINT | 0x8] = "External Interrupt 8",
829e67768d0SBlue Swirl     [TT_EXTINT | 0x9] = "External Interrupt 9",
830e67768d0SBlue Swirl     [TT_EXTINT | 0xa] = "External Interrupt 10",
831e67768d0SBlue Swirl     [TT_EXTINT | 0xb] = "External Interrupt 11",
832e67768d0SBlue Swirl     [TT_EXTINT | 0xc] = "External Interrupt 12",
833e67768d0SBlue Swirl     [TT_EXTINT | 0xd] = "External Interrupt 13",
834e67768d0SBlue Swirl     [TT_EXTINT | 0xe] = "External Interrupt 14",
835e67768d0SBlue Swirl     [TT_EXTINT | 0xf] = "External Interrupt 15",
836e67768d0SBlue Swirl };
837e67768d0SBlue Swirl #endif
838e67768d0SBlue Swirl 
839e67768d0SBlue Swirl void do_interrupt(CPUState *env)
840e67768d0SBlue Swirl {
841e67768d0SBlue Swirl     int intno = env->exception_index;
842e67768d0SBlue Swirl     trap_state *tsptr;
843e67768d0SBlue Swirl 
844e67768d0SBlue Swirl #ifdef DEBUG_PCALL
845e67768d0SBlue Swirl     if (qemu_loglevel_mask(CPU_LOG_INT)) {
846e67768d0SBlue Swirl         static int count;
847e67768d0SBlue Swirl         const char *name;
848e67768d0SBlue Swirl 
849e67768d0SBlue Swirl         if (intno < 0 || intno >= 0x180) {
850e67768d0SBlue Swirl             name = "Unknown";
851e67768d0SBlue Swirl         } else if (intno >= 0x100) {
852e67768d0SBlue Swirl             name = "Trap Instruction";
853e67768d0SBlue Swirl         } else if (intno >= 0xc0) {
854e67768d0SBlue Swirl             name = "Window Fill";
855e67768d0SBlue Swirl         } else if (intno >= 0x80) {
856e67768d0SBlue Swirl             name = "Window Spill";
857e67768d0SBlue Swirl         } else {
858e67768d0SBlue Swirl             name = excp_names[intno];
859e67768d0SBlue Swirl             if (!name) {
860e67768d0SBlue Swirl                 name = "Unknown";
861e67768d0SBlue Swirl             }
862e67768d0SBlue Swirl         }
863e67768d0SBlue Swirl 
864e67768d0SBlue Swirl         qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64
865e67768d0SBlue Swirl                 " SP=%016" PRIx64 "\n",
866e67768d0SBlue Swirl                 count, name, intno,
867e67768d0SBlue Swirl                 env->pc,
868e67768d0SBlue Swirl                 env->npc, env->regwptr[6]);
869e67768d0SBlue Swirl         log_cpu_state(env, 0);
870e67768d0SBlue Swirl #if 0
871e67768d0SBlue Swirl         {
872e67768d0SBlue Swirl             int i;
873e67768d0SBlue Swirl             uint8_t *ptr;
874e67768d0SBlue Swirl 
875e67768d0SBlue Swirl             qemu_log("       code=");
876e67768d0SBlue Swirl             ptr = (uint8_t *)env->pc;
877e67768d0SBlue Swirl             for (i = 0; i < 16; i++) {
878e67768d0SBlue Swirl                 qemu_log(" %02x", ldub(ptr + i));
879e67768d0SBlue Swirl             }
880e67768d0SBlue Swirl             qemu_log("\n");
881e67768d0SBlue Swirl         }
882e67768d0SBlue Swirl #endif
883e67768d0SBlue Swirl         count++;
884e67768d0SBlue Swirl     }
885e67768d0SBlue Swirl #endif
886e67768d0SBlue Swirl #if !defined(CONFIG_USER_ONLY)
887e67768d0SBlue Swirl     if (env->tl >= env->maxtl) {
888e67768d0SBlue Swirl         cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
889e67768d0SBlue Swirl                   " Error state", env->exception_index, env->tl, env->maxtl);
890e67768d0SBlue Swirl         return;
891e67768d0SBlue Swirl     }
892e67768d0SBlue Swirl #endif
893e67768d0SBlue Swirl     if (env->tl < env->maxtl - 1) {
894e67768d0SBlue Swirl         env->tl++;
895e67768d0SBlue Swirl     } else {
896e67768d0SBlue Swirl         env->pstate |= PS_RED;
897e67768d0SBlue Swirl         if (env->tl < env->maxtl) {
898e67768d0SBlue Swirl             env->tl++;
899e67768d0SBlue Swirl         }
900e67768d0SBlue Swirl     }
901e67768d0SBlue Swirl     tsptr = cpu_tsptr(env);
902e67768d0SBlue Swirl 
903e67768d0SBlue Swirl     tsptr->tstate = (cpu_get_ccr(env) << 32) |
904e67768d0SBlue Swirl         ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
905e67768d0SBlue Swirl         cpu_get_cwp64(env);
906e67768d0SBlue Swirl     tsptr->tpc = env->pc;
907e67768d0SBlue Swirl     tsptr->tnpc = env->npc;
908e67768d0SBlue Swirl     tsptr->tt = intno;
909e67768d0SBlue Swirl 
910e67768d0SBlue Swirl     switch (intno) {
911e67768d0SBlue Swirl     case TT_IVEC:
912e67768d0SBlue Swirl         cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
913e67768d0SBlue Swirl         break;
914e67768d0SBlue Swirl     case TT_TFAULT:
915e67768d0SBlue Swirl     case TT_DFAULT:
916e67768d0SBlue Swirl     case TT_TMISS ... TT_TMISS + 3:
917e67768d0SBlue Swirl     case TT_DMISS ... TT_DMISS + 3:
918e67768d0SBlue Swirl     case TT_DPROT ... TT_DPROT + 3:
919e67768d0SBlue Swirl         cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG);
920e67768d0SBlue Swirl         break;
921e67768d0SBlue Swirl     default:
922e67768d0SBlue Swirl         cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG);
923e67768d0SBlue Swirl         break;
924e67768d0SBlue Swirl     }
925e67768d0SBlue Swirl 
926e67768d0SBlue Swirl     if (intno == TT_CLRWIN) {
927e67768d0SBlue Swirl         cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1));
928e67768d0SBlue Swirl     } else if ((intno & 0x1c0) == TT_SPILL) {
929e67768d0SBlue Swirl         cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
930e67768d0SBlue Swirl     } else if ((intno & 0x1c0) == TT_FILL) {
931e67768d0SBlue Swirl         cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
932e67768d0SBlue Swirl     }
933e67768d0SBlue Swirl     env->tbr &= ~0x7fffULL;
934e67768d0SBlue Swirl     env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
935e67768d0SBlue Swirl     env->pc = env->tbr;
936e67768d0SBlue Swirl     env->npc = env->pc + 4;
937e67768d0SBlue Swirl     env->exception_index = -1;
938e67768d0SBlue Swirl }
939e67768d0SBlue Swirl #else
940e67768d0SBlue Swirl #ifdef DEBUG_PCALL
941e67768d0SBlue Swirl static const char * const excp_names[0x80] = {
942e67768d0SBlue Swirl     [TT_TFAULT] = "Instruction Access Fault",
943e67768d0SBlue Swirl     [TT_ILL_INSN] = "Illegal Instruction",
944e67768d0SBlue Swirl     [TT_PRIV_INSN] = "Privileged Instruction",
945e67768d0SBlue Swirl     [TT_NFPU_INSN] = "FPU Disabled",
946e67768d0SBlue Swirl     [TT_WIN_OVF] = "Window Overflow",
947e67768d0SBlue Swirl     [TT_WIN_UNF] = "Window Underflow",
948e67768d0SBlue Swirl     [TT_UNALIGNED] = "Unaligned Memory Access",
949e67768d0SBlue Swirl     [TT_FP_EXCP] = "FPU Exception",
950e67768d0SBlue Swirl     [TT_DFAULT] = "Data Access Fault",
951e67768d0SBlue Swirl     [TT_TOVF] = "Tag Overflow",
952e67768d0SBlue Swirl     [TT_EXTINT | 0x1] = "External Interrupt 1",
953e67768d0SBlue Swirl     [TT_EXTINT | 0x2] = "External Interrupt 2",
954e67768d0SBlue Swirl     [TT_EXTINT | 0x3] = "External Interrupt 3",
955e67768d0SBlue Swirl     [TT_EXTINT | 0x4] = "External Interrupt 4",
956e67768d0SBlue Swirl     [TT_EXTINT | 0x5] = "External Interrupt 5",
957e67768d0SBlue Swirl     [TT_EXTINT | 0x6] = "External Interrupt 6",
958e67768d0SBlue Swirl     [TT_EXTINT | 0x7] = "External Interrupt 7",
959e67768d0SBlue Swirl     [TT_EXTINT | 0x8] = "External Interrupt 8",
960e67768d0SBlue Swirl     [TT_EXTINT | 0x9] = "External Interrupt 9",
961e67768d0SBlue Swirl     [TT_EXTINT | 0xa] = "External Interrupt 10",
962e67768d0SBlue Swirl     [TT_EXTINT | 0xb] = "External Interrupt 11",
963e67768d0SBlue Swirl     [TT_EXTINT | 0xc] = "External Interrupt 12",
964e67768d0SBlue Swirl     [TT_EXTINT | 0xd] = "External Interrupt 13",
965e67768d0SBlue Swirl     [TT_EXTINT | 0xe] = "External Interrupt 14",
966e67768d0SBlue Swirl     [TT_EXTINT | 0xf] = "External Interrupt 15",
967e67768d0SBlue Swirl     [TT_TOVF] = "Tag Overflow",
968e67768d0SBlue Swirl     [TT_CODE_ACCESS] = "Instruction Access Error",
969e67768d0SBlue Swirl     [TT_DATA_ACCESS] = "Data Access Error",
970e67768d0SBlue Swirl     [TT_DIV_ZERO] = "Division By Zero",
971e67768d0SBlue Swirl     [TT_NCP_INSN] = "Coprocessor Disabled",
972e67768d0SBlue Swirl };
973e67768d0SBlue Swirl #endif
974e67768d0SBlue Swirl 
975e67768d0SBlue Swirl void do_interrupt(CPUState *env)
976e67768d0SBlue Swirl {
977e67768d0SBlue Swirl     int cwp, intno = env->exception_index;
978e67768d0SBlue Swirl 
979e67768d0SBlue Swirl #ifdef DEBUG_PCALL
980e67768d0SBlue Swirl     if (qemu_loglevel_mask(CPU_LOG_INT)) {
981e67768d0SBlue Swirl         static int count;
982e67768d0SBlue Swirl         const char *name;
983e67768d0SBlue Swirl 
984e67768d0SBlue Swirl         if (intno < 0 || intno >= 0x100) {
985e67768d0SBlue Swirl             name = "Unknown";
986e67768d0SBlue Swirl         } else if (intno >= 0x80) {
987e67768d0SBlue Swirl             name = "Trap Instruction";
988e67768d0SBlue Swirl         } else {
989e67768d0SBlue Swirl             name = excp_names[intno];
990e67768d0SBlue Swirl             if (!name) {
991e67768d0SBlue Swirl                 name = "Unknown";
992e67768d0SBlue Swirl             }
993e67768d0SBlue Swirl         }
994e67768d0SBlue Swirl 
995e67768d0SBlue Swirl         qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n",
996e67768d0SBlue Swirl                 count, name, intno,
997e67768d0SBlue Swirl                 env->pc,
998e67768d0SBlue Swirl                 env->npc, env->regwptr[6]);
999e67768d0SBlue Swirl         log_cpu_state(env, 0);
1000e67768d0SBlue Swirl #if 0
1001e67768d0SBlue Swirl         {
1002e67768d0SBlue Swirl             int i;
1003e67768d0SBlue Swirl             uint8_t *ptr;
1004e67768d0SBlue Swirl 
1005e67768d0SBlue Swirl             qemu_log("       code=");
1006e67768d0SBlue Swirl             ptr = (uint8_t *)env->pc;
1007e67768d0SBlue Swirl             for (i = 0; i < 16; i++) {
1008e67768d0SBlue Swirl                 qemu_log(" %02x", ldub(ptr + i));
1009e67768d0SBlue Swirl             }
1010e67768d0SBlue Swirl             qemu_log("\n");
1011e67768d0SBlue Swirl         }
1012e67768d0SBlue Swirl #endif
1013e67768d0SBlue Swirl         count++;
1014e67768d0SBlue Swirl     }
1015e67768d0SBlue Swirl #endif
1016e67768d0SBlue Swirl #if !defined(CONFIG_USER_ONLY)
1017e67768d0SBlue Swirl     if (env->psret == 0) {
1018e67768d0SBlue Swirl         cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state",
1019e67768d0SBlue Swirl                   env->exception_index);
1020e67768d0SBlue Swirl         return;
1021e67768d0SBlue Swirl     }
1022e67768d0SBlue Swirl #endif
1023e67768d0SBlue Swirl     env->psret = 0;
1024e67768d0SBlue Swirl     cwp = cpu_cwp_dec(env, env->cwp - 1);
1025e67768d0SBlue Swirl     cpu_set_cwp(env, cwp);
1026e67768d0SBlue Swirl     env->regwptr[9] = env->pc;
1027e67768d0SBlue Swirl     env->regwptr[10] = env->npc;
1028e67768d0SBlue Swirl     env->psrps = env->psrs;
1029e67768d0SBlue Swirl     env->psrs = 1;
1030e67768d0SBlue Swirl     env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
1031e67768d0SBlue Swirl     env->pc = env->tbr;
1032e67768d0SBlue Swirl     env->npc = env->pc + 4;
1033e67768d0SBlue Swirl     env->exception_index = -1;
1034e67768d0SBlue Swirl 
1035e67768d0SBlue Swirl #if !defined(CONFIG_USER_ONLY)
1036e67768d0SBlue Swirl     /* IRQ acknowledgment */
1037e67768d0SBlue Swirl     if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
1038e67768d0SBlue Swirl         env->qemu_irq_ack(env->irq_manager, intno);
1039e67768d0SBlue Swirl     }
1040e67768d0SBlue Swirl #endif
1041e67768d0SBlue Swirl }
1042e67768d0SBlue Swirl #endif
1043e67768d0SBlue Swirl 
1044c48fcb47Sblueswir1 void cpu_reset(CPUSPARCState *env)
1045c48fcb47Sblueswir1 {
1046eca1bdf4Saliguori     if (qemu_loglevel_mask(CPU_LOG_RESET)) {
1047eca1bdf4Saliguori         qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
1048eca1bdf4Saliguori         log_cpu_state(env, 0);
1049eca1bdf4Saliguori     }
1050eca1bdf4Saliguori 
1051c48fcb47Sblueswir1     tlb_flush(env, 1);
1052c48fcb47Sblueswir1     env->cwp = 0;
10535210977aSIgor Kovalenko #ifndef TARGET_SPARC64
1054c48fcb47Sblueswir1     env->wim = 1;
10555210977aSIgor Kovalenko #endif
1056c48fcb47Sblueswir1     env->regwptr = env->regbase + (env->cwp * 16);
10576b743278SBlue Swirl     CC_OP = CC_OP_FLAGS;
1058c48fcb47Sblueswir1 #if defined(CONFIG_USER_ONLY)
1059c48fcb47Sblueswir1 #ifdef TARGET_SPARC64
10601a14026eSblueswir1     env->cleanwin = env->nwindows - 2;
10611a14026eSblueswir1     env->cansave = env->nwindows - 2;
1062c48fcb47Sblueswir1     env->pstate = PS_RMO | PS_PEF | PS_IE;
1063c48fcb47Sblueswir1     env->asi = 0x82; // Primary no-fault
1064c48fcb47Sblueswir1 #endif
1065c48fcb47Sblueswir1 #else
10665210977aSIgor Kovalenko #if !defined(TARGET_SPARC64)
1067c48fcb47Sblueswir1     env->psret = 0;
1068c48fcb47Sblueswir1     env->psrs = 1;
1069c48fcb47Sblueswir1     env->psrps = 1;
10702aae2b8eSIgor V. Kovalenko #endif
1071c48fcb47Sblueswir1 #ifdef TARGET_SPARC64
10728194f35aSIgor Kovalenko     env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
10732aae2b8eSIgor V. Kovalenko     env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
10748194f35aSIgor Kovalenko     env->tl = env->maxtl;
10758194f35aSIgor Kovalenko     cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
1076415fc906Sblueswir1     env->lsu = 0;
1077c48fcb47Sblueswir1 #else
1078c48fcb47Sblueswir1     env->mmuregs[0] &= ~(MMU_E | MMU_NF);
10795578ceabSblueswir1     env->mmuregs[0] |= env->def->mmu_bm;
1080c48fcb47Sblueswir1 #endif
1081e87231d4Sblueswir1     env->pc = 0;
1082c48fcb47Sblueswir1     env->npc = env->pc + 4;
1083c48fcb47Sblueswir1 #endif
1084b04d9890SFabien Chouteau     env->cache_control = 0;
1085c48fcb47Sblueswir1 }
1086c48fcb47Sblueswir1 
108764a88d5dSblueswir1 static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
1088c48fcb47Sblueswir1 {
108964a88d5dSblueswir1     sparc_def_t def1, *def = &def1;
1090c48fcb47Sblueswir1 
109164a88d5dSblueswir1     if (cpu_sparc_find_by_name(def, cpu_model) < 0)
109264a88d5dSblueswir1         return -1;
1093c48fcb47Sblueswir1 
10945578ceabSblueswir1     env->def = qemu_mallocz(sizeof(*def));
10955578ceabSblueswir1     memcpy(env->def, def, sizeof(*def));
10965578ceabSblueswir1 #if defined(CONFIG_USER_ONLY)
10975578ceabSblueswir1     if ((env->def->features & CPU_FEATURE_FLOAT))
10985578ceabSblueswir1         env->def->features |= CPU_FEATURE_FLOAT128;
10995578ceabSblueswir1 #endif
1100c48fcb47Sblueswir1     env->cpu_model_str = cpu_model;
1101c48fcb47Sblueswir1     env->version = def->iu_version;
1102c48fcb47Sblueswir1     env->fsr = def->fpu_version;
11031a14026eSblueswir1     env->nwindows = def->nwindows;
1104c48fcb47Sblueswir1 #if !defined(TARGET_SPARC64)
1105c48fcb47Sblueswir1     env->mmuregs[0] |= def->mmu_version;
1106c48fcb47Sblueswir1     cpu_sparc_set_id(env, 0);
1107963262deSblueswir1     env->mxccregs[7] |= def->mxcc_version;
11081a14026eSblueswir1 #else
1109fb79ceb9Sblueswir1     env->mmu_version = def->mmu_version;
1110c19148bdSblueswir1     env->maxtl = def->maxtl;
1111c19148bdSblueswir1     env->version |= def->maxtl << 8;
11121a14026eSblueswir1     env->version |= def->nwindows - 1;
1113c48fcb47Sblueswir1 #endif
111464a88d5dSblueswir1     return 0;
111564a88d5dSblueswir1 }
111664a88d5dSblueswir1 
111764a88d5dSblueswir1 static void cpu_sparc_close(CPUSPARCState *env)
111864a88d5dSblueswir1 {
11195578ceabSblueswir1     free(env->def);
112064a88d5dSblueswir1     free(env);
112164a88d5dSblueswir1 }
112264a88d5dSblueswir1 
112364a88d5dSblueswir1 CPUSPARCState *cpu_sparc_init(const char *cpu_model)
112464a88d5dSblueswir1 {
112564a88d5dSblueswir1     CPUSPARCState *env;
112664a88d5dSblueswir1 
112764a88d5dSblueswir1     env = qemu_mallocz(sizeof(CPUSPARCState));
112864a88d5dSblueswir1     cpu_exec_init(env);
1129c48fcb47Sblueswir1 
1130c48fcb47Sblueswir1     gen_intermediate_code_init(env);
1131c48fcb47Sblueswir1 
113264a88d5dSblueswir1     if (cpu_sparc_register(env, cpu_model) < 0) {
113364a88d5dSblueswir1         cpu_sparc_close(env);
113464a88d5dSblueswir1         return NULL;
113564a88d5dSblueswir1     }
11360bf46a40Saliguori     qemu_init_vcpu(env);
1137c48fcb47Sblueswir1 
1138c48fcb47Sblueswir1     return env;
1139c48fcb47Sblueswir1 }
1140c48fcb47Sblueswir1 
1141c48fcb47Sblueswir1 void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
1142c48fcb47Sblueswir1 {
1143c48fcb47Sblueswir1 #if !defined(TARGET_SPARC64)
1144c48fcb47Sblueswir1     env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
1145c48fcb47Sblueswir1 #endif
1146c48fcb47Sblueswir1 }
1147c48fcb47Sblueswir1 
1148c48fcb47Sblueswir1 static const sparc_def_t sparc_defs[] = {
1149c48fcb47Sblueswir1 #ifdef TARGET_SPARC64
1150c48fcb47Sblueswir1     {
1151c48fcb47Sblueswir1         .name = "Fujitsu Sparc64",
1152c19148bdSblueswir1         .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
1153c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1154fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11551a14026eSblueswir1         .nwindows = 4,
1156c19148bdSblueswir1         .maxtl = 4,
115764a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1158c48fcb47Sblueswir1     },
1159c48fcb47Sblueswir1     {
1160c48fcb47Sblueswir1         .name = "Fujitsu Sparc64 III",
1161c19148bdSblueswir1         .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
1162c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1163fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11641a14026eSblueswir1         .nwindows = 5,
1165c19148bdSblueswir1         .maxtl = 4,
116664a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1167c48fcb47Sblueswir1     },
1168c48fcb47Sblueswir1     {
1169c48fcb47Sblueswir1         .name = "Fujitsu Sparc64 IV",
1170c19148bdSblueswir1         .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
1171c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1172fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11731a14026eSblueswir1         .nwindows = 8,
1174c19148bdSblueswir1         .maxtl = 5,
117564a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1176c48fcb47Sblueswir1     },
1177c48fcb47Sblueswir1     {
1178c48fcb47Sblueswir1         .name = "Fujitsu Sparc64 V",
1179c19148bdSblueswir1         .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
1180c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1181fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11821a14026eSblueswir1         .nwindows = 8,
1183c19148bdSblueswir1         .maxtl = 5,
118464a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1185c48fcb47Sblueswir1     },
1186c48fcb47Sblueswir1     {
1187c48fcb47Sblueswir1         .name = "TI UltraSparc I",
1188c19148bdSblueswir1         .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
1189c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1190fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11911a14026eSblueswir1         .nwindows = 8,
1192c19148bdSblueswir1         .maxtl = 5,
119364a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1194c48fcb47Sblueswir1     },
1195c48fcb47Sblueswir1     {
1196c48fcb47Sblueswir1         .name = "TI UltraSparc II",
1197c19148bdSblueswir1         .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
1198c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1199fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12001a14026eSblueswir1         .nwindows = 8,
1201c19148bdSblueswir1         .maxtl = 5,
120264a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1203c48fcb47Sblueswir1     },
1204c48fcb47Sblueswir1     {
1205c48fcb47Sblueswir1         .name = "TI UltraSparc IIi",
1206c19148bdSblueswir1         .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
1207c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1208fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12091a14026eSblueswir1         .nwindows = 8,
1210c19148bdSblueswir1         .maxtl = 5,
121164a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1212c48fcb47Sblueswir1     },
1213c48fcb47Sblueswir1     {
1214c48fcb47Sblueswir1         .name = "TI UltraSparc IIe",
1215c19148bdSblueswir1         .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
1216c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1217fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12181a14026eSblueswir1         .nwindows = 8,
1219c19148bdSblueswir1         .maxtl = 5,
122064a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1221c48fcb47Sblueswir1     },
1222c48fcb47Sblueswir1     {
1223c48fcb47Sblueswir1         .name = "Sun UltraSparc III",
1224c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
1225c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1226fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12271a14026eSblueswir1         .nwindows = 8,
1228c19148bdSblueswir1         .maxtl = 5,
122964a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1230c48fcb47Sblueswir1     },
1231c48fcb47Sblueswir1     {
1232c48fcb47Sblueswir1         .name = "Sun UltraSparc III Cu",
1233c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
1234c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1235fb79ceb9Sblueswir1         .mmu_version = mmu_us_3,
12361a14026eSblueswir1         .nwindows = 8,
1237c19148bdSblueswir1         .maxtl = 5,
123864a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1239c48fcb47Sblueswir1     },
1240c48fcb47Sblueswir1     {
1241c48fcb47Sblueswir1         .name = "Sun UltraSparc IIIi",
1242c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
1243c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1244fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12451a14026eSblueswir1         .nwindows = 8,
1246c19148bdSblueswir1         .maxtl = 5,
124764a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1248c48fcb47Sblueswir1     },
1249c48fcb47Sblueswir1     {
1250c48fcb47Sblueswir1         .name = "Sun UltraSparc IV",
1251c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
1252c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1253fb79ceb9Sblueswir1         .mmu_version = mmu_us_4,
12541a14026eSblueswir1         .nwindows = 8,
1255c19148bdSblueswir1         .maxtl = 5,
125664a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1257c48fcb47Sblueswir1     },
1258c48fcb47Sblueswir1     {
1259c48fcb47Sblueswir1         .name = "Sun UltraSparc IV+",
1260c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
1261c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1262fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12631a14026eSblueswir1         .nwindows = 8,
1264c19148bdSblueswir1         .maxtl = 5,
1265fb79ceb9Sblueswir1         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
1266c48fcb47Sblueswir1     },
1267c48fcb47Sblueswir1     {
1268c48fcb47Sblueswir1         .name = "Sun UltraSparc IIIi+",
1269c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
1270c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1271fb79ceb9Sblueswir1         .mmu_version = mmu_us_3,
12721a14026eSblueswir1         .nwindows = 8,
1273c19148bdSblueswir1         .maxtl = 5,
127464a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1275c48fcb47Sblueswir1     },
1276c48fcb47Sblueswir1     {
1277c7ba218dSblueswir1         .name = "Sun UltraSparc T1",
1278c7ba218dSblueswir1         // defined in sparc_ifu_fdp.v and ctu.h
1279c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
1280c7ba218dSblueswir1         .fpu_version = 0x00000000,
1281c7ba218dSblueswir1         .mmu_version = mmu_sun4v,
1282c7ba218dSblueswir1         .nwindows = 8,
1283c19148bdSblueswir1         .maxtl = 6,
1284c7ba218dSblueswir1         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
1285c7ba218dSblueswir1         | CPU_FEATURE_GL,
1286c7ba218dSblueswir1     },
1287c7ba218dSblueswir1     {
1288c7ba218dSblueswir1         .name = "Sun UltraSparc T2",
1289c7ba218dSblueswir1         // defined in tlu_asi_ctl.v and n2_revid_cust.v
1290c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
1291c7ba218dSblueswir1         .fpu_version = 0x00000000,
1292c7ba218dSblueswir1         .mmu_version = mmu_sun4v,
1293c7ba218dSblueswir1         .nwindows = 8,
1294c19148bdSblueswir1         .maxtl = 6,
1295c7ba218dSblueswir1         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
1296c7ba218dSblueswir1         | CPU_FEATURE_GL,
1297c7ba218dSblueswir1     },
1298c7ba218dSblueswir1     {
1299c48fcb47Sblueswir1         .name = "NEC UltraSparc I",
1300c19148bdSblueswir1         .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
1301c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1302fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
13031a14026eSblueswir1         .nwindows = 8,
1304c19148bdSblueswir1         .maxtl = 5,
130564a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1306c48fcb47Sblueswir1     },
1307c48fcb47Sblueswir1 #else
1308c48fcb47Sblueswir1     {
1309c48fcb47Sblueswir1         .name = "Fujitsu MB86900",
1310c48fcb47Sblueswir1         .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
1311c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1312c48fcb47Sblueswir1         .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
1313c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1314c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1315c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1316c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1317c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
13181a14026eSblueswir1         .nwindows = 7,
1319e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
1320c48fcb47Sblueswir1     },
1321c48fcb47Sblueswir1     {
1322c48fcb47Sblueswir1         .name = "Fujitsu MB86904",
1323c48fcb47Sblueswir1         .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
1324c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1325c48fcb47Sblueswir1         .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
1326c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1327c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x00ffffc0,
1328c48fcb47Sblueswir1         .mmu_cxr_mask = 0x000000ff,
1329c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016fff,
1330c48fcb47Sblueswir1         .mmu_trcr_mask = 0x00ffffff,
13311a14026eSblueswir1         .nwindows = 8,
133264a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1333c48fcb47Sblueswir1     },
1334c48fcb47Sblueswir1     {
1335c48fcb47Sblueswir1         .name = "Fujitsu MB86907",
1336c48fcb47Sblueswir1         .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
1337c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1338c48fcb47Sblueswir1         .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
1339c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1340c48fcb47Sblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1341c48fcb47Sblueswir1         .mmu_cxr_mask = 0x000000ff,
1342c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016fff,
1343c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
13441a14026eSblueswir1         .nwindows = 8,
134564a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1346c48fcb47Sblueswir1     },
1347c48fcb47Sblueswir1     {
1348c48fcb47Sblueswir1         .name = "LSI L64811",
1349c48fcb47Sblueswir1         .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
1350c48fcb47Sblueswir1         .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
1351c48fcb47Sblueswir1         .mmu_version = 0x10 << 24,
1352c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1353c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1354c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1355c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1356c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
13571a14026eSblueswir1         .nwindows = 8,
1358e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1359e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1360c48fcb47Sblueswir1     },
1361c48fcb47Sblueswir1     {
1362c48fcb47Sblueswir1         .name = "Cypress CY7C601",
1363c48fcb47Sblueswir1         .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
1364c48fcb47Sblueswir1         .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
1365c48fcb47Sblueswir1         .mmu_version = 0x10 << 24,
1366c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1367c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1368c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1369c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1370c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
13711a14026eSblueswir1         .nwindows = 8,
1372e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1373e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1374c48fcb47Sblueswir1     },
1375c48fcb47Sblueswir1     {
1376c48fcb47Sblueswir1         .name = "Cypress CY7C611",
1377c48fcb47Sblueswir1         .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
1378c48fcb47Sblueswir1         .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
1379c48fcb47Sblueswir1         .mmu_version = 0x10 << 24,
1380c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1381c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1382c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1383c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1384c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
13851a14026eSblueswir1         .nwindows = 8,
1386e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1387e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1388c48fcb47Sblueswir1     },
1389c48fcb47Sblueswir1     {
1390c48fcb47Sblueswir1         .name = "TI MicroSparc I",
1391c48fcb47Sblueswir1         .iu_version = 0x41000000,
1392c48fcb47Sblueswir1         .fpu_version = 4 << 17,
1393c48fcb47Sblueswir1         .mmu_version = 0x41000000,
1394c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1395c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1396c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1397c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016fff,
1398c48fcb47Sblueswir1         .mmu_trcr_mask = 0x0000003f,
13991a14026eSblueswir1         .nwindows = 7,
1400e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
1401e30b4678Sblueswir1         CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
1402e30b4678Sblueswir1         CPU_FEATURE_FMUL,
1403c48fcb47Sblueswir1     },
1404c48fcb47Sblueswir1     {
1405c48fcb47Sblueswir1         .name = "TI MicroSparc II",
1406c48fcb47Sblueswir1         .iu_version = 0x42000000,
1407c48fcb47Sblueswir1         .fpu_version = 4 << 17,
1408c48fcb47Sblueswir1         .mmu_version = 0x02000000,
1409c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1410c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x00ffffc0,
1411c48fcb47Sblueswir1         .mmu_cxr_mask = 0x000000ff,
1412c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016fff,
1413c48fcb47Sblueswir1         .mmu_trcr_mask = 0x00ffffff,
14141a14026eSblueswir1         .nwindows = 8,
141564a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1416c48fcb47Sblueswir1     },
1417c48fcb47Sblueswir1     {
1418c48fcb47Sblueswir1         .name = "TI MicroSparc IIep",
1419c48fcb47Sblueswir1         .iu_version = 0x42000000,
1420c48fcb47Sblueswir1         .fpu_version = 4 << 17,
1421c48fcb47Sblueswir1         .mmu_version = 0x04000000,
1422c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1423c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x00ffffc0,
1424c48fcb47Sblueswir1         .mmu_cxr_mask = 0x000000ff,
1425c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016bff,
1426c48fcb47Sblueswir1         .mmu_trcr_mask = 0x00ffffff,
14271a14026eSblueswir1         .nwindows = 8,
142864a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1429c48fcb47Sblueswir1     },
1430c48fcb47Sblueswir1     {
1431b5154bdeSblueswir1         .name = "TI SuperSparc 40", // STP1020NPGA
1432963262deSblueswir1         .iu_version = 0x41000000, // SuperSPARC 2.x
1433b5154bdeSblueswir1         .fpu_version = 0 << 17,
1434963262deSblueswir1         .mmu_version = 0x00000800, // SuperSPARC 2.x, no MXCC
1435b5154bdeSblueswir1         .mmu_bm = 0x00002000,
1436b5154bdeSblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1437b5154bdeSblueswir1         .mmu_cxr_mask = 0x0000ffff,
1438b5154bdeSblueswir1         .mmu_sfsr_mask = 0xffffffff,
1439b5154bdeSblueswir1         .mmu_trcr_mask = 0xffffffff,
14401a14026eSblueswir1         .nwindows = 8,
1441b5154bdeSblueswir1         .features = CPU_DEFAULT_FEATURES,
1442b5154bdeSblueswir1     },
1443b5154bdeSblueswir1     {
1444b5154bdeSblueswir1         .name = "TI SuperSparc 50", // STP1020PGA
1445963262deSblueswir1         .iu_version = 0x40000000, // SuperSPARC 3.x
1446b5154bdeSblueswir1         .fpu_version = 0 << 17,
1447963262deSblueswir1         .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
1448b5154bdeSblueswir1         .mmu_bm = 0x00002000,
1449b5154bdeSblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1450b5154bdeSblueswir1         .mmu_cxr_mask = 0x0000ffff,
1451b5154bdeSblueswir1         .mmu_sfsr_mask = 0xffffffff,
1452b5154bdeSblueswir1         .mmu_trcr_mask = 0xffffffff,
14531a14026eSblueswir1         .nwindows = 8,
1454b5154bdeSblueswir1         .features = CPU_DEFAULT_FEATURES,
1455b5154bdeSblueswir1     },
1456b5154bdeSblueswir1     {
1457c48fcb47Sblueswir1         .name = "TI SuperSparc 51",
1458963262deSblueswir1         .iu_version = 0x40000000, // SuperSPARC 3.x
1459c48fcb47Sblueswir1         .fpu_version = 0 << 17,
1460963262deSblueswir1         .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
1461c48fcb47Sblueswir1         .mmu_bm = 0x00002000,
1462c48fcb47Sblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1463c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000ffff,
1464c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1465c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
1466963262deSblueswir1         .mxcc_version = 0x00000104,
14671a14026eSblueswir1         .nwindows = 8,
146864a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1469c48fcb47Sblueswir1     },
1470c48fcb47Sblueswir1     {
1471b5154bdeSblueswir1         .name = "TI SuperSparc 60", // STP1020APGA
1472963262deSblueswir1         .iu_version = 0x40000000, // SuperSPARC 3.x
1473b5154bdeSblueswir1         .fpu_version = 0 << 17,
1474963262deSblueswir1         .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
1475b5154bdeSblueswir1         .mmu_bm = 0x00002000,
1476b5154bdeSblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1477b5154bdeSblueswir1         .mmu_cxr_mask = 0x0000ffff,
1478b5154bdeSblueswir1         .mmu_sfsr_mask = 0xffffffff,
1479b5154bdeSblueswir1         .mmu_trcr_mask = 0xffffffff,
14801a14026eSblueswir1         .nwindows = 8,
1481b5154bdeSblueswir1         .features = CPU_DEFAULT_FEATURES,
1482b5154bdeSblueswir1     },
1483b5154bdeSblueswir1     {
1484c48fcb47Sblueswir1         .name = "TI SuperSparc 61",
1485963262deSblueswir1         .iu_version = 0x44000000, // SuperSPARC 3.x
1486c48fcb47Sblueswir1         .fpu_version = 0 << 17,
1487963262deSblueswir1         .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
1488c48fcb47Sblueswir1         .mmu_bm = 0x00002000,
1489c48fcb47Sblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1490c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000ffff,
1491c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1492c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
1493963262deSblueswir1         .mxcc_version = 0x00000104,
1494963262deSblueswir1         .nwindows = 8,
1495963262deSblueswir1         .features = CPU_DEFAULT_FEATURES,
1496963262deSblueswir1     },
1497963262deSblueswir1     {
1498963262deSblueswir1         .name = "TI SuperSparc II",
1499963262deSblueswir1         .iu_version = 0x40000000, // SuperSPARC II 1.x
1500963262deSblueswir1         .fpu_version = 0 << 17,
1501963262deSblueswir1         .mmu_version = 0x08000000, // SuperSPARC II 1.x, MXCC
1502963262deSblueswir1         .mmu_bm = 0x00002000,
1503963262deSblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1504963262deSblueswir1         .mmu_cxr_mask = 0x0000ffff,
1505963262deSblueswir1         .mmu_sfsr_mask = 0xffffffff,
1506963262deSblueswir1         .mmu_trcr_mask = 0xffffffff,
1507963262deSblueswir1         .mxcc_version = 0x00000104,
15081a14026eSblueswir1         .nwindows = 8,
150964a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1510c48fcb47Sblueswir1     },
1511c48fcb47Sblueswir1     {
1512c48fcb47Sblueswir1         .name = "Ross RT625",
1513c48fcb47Sblueswir1         .iu_version = 0x1e000000,
1514c48fcb47Sblueswir1         .fpu_version = 1 << 17,
1515c48fcb47Sblueswir1         .mmu_version = 0x1e000000,
1516c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1517c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1518c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1519c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1520c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
15211a14026eSblueswir1         .nwindows = 8,
152264a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1523c48fcb47Sblueswir1     },
1524c48fcb47Sblueswir1     {
1525c48fcb47Sblueswir1         .name = "Ross RT620",
1526c48fcb47Sblueswir1         .iu_version = 0x1f000000,
1527c48fcb47Sblueswir1         .fpu_version = 1 << 17,
1528c48fcb47Sblueswir1         .mmu_version = 0x1f000000,
1529c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1530c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1531c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1532c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1533c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
15341a14026eSblueswir1         .nwindows = 8,
153564a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1536c48fcb47Sblueswir1     },
1537c48fcb47Sblueswir1     {
1538c48fcb47Sblueswir1         .name = "BIT B5010",
1539c48fcb47Sblueswir1         .iu_version = 0x20000000,
1540c48fcb47Sblueswir1         .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
1541c48fcb47Sblueswir1         .mmu_version = 0x20000000,
1542c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1543c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1544c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1545c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1546c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
15471a14026eSblueswir1         .nwindows = 8,
1548e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1549e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1550c48fcb47Sblueswir1     },
1551c48fcb47Sblueswir1     {
1552c48fcb47Sblueswir1         .name = "Matsushita MN10501",
1553c48fcb47Sblueswir1         .iu_version = 0x50000000,
1554c48fcb47Sblueswir1         .fpu_version = 0 << 17,
1555c48fcb47Sblueswir1         .mmu_version = 0x50000000,
1556c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1557c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1558c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1559c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1560c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
15611a14026eSblueswir1         .nwindows = 8,
1562e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
1563e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1564c48fcb47Sblueswir1     },
1565c48fcb47Sblueswir1     {
1566c48fcb47Sblueswir1         .name = "Weitek W8601",
1567c48fcb47Sblueswir1         .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
1568c48fcb47Sblueswir1         .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
1569c48fcb47Sblueswir1         .mmu_version = 0x10 << 24,
1570c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1571c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1572c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1573c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1574c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
15751a14026eSblueswir1         .nwindows = 8,
157664a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1577c48fcb47Sblueswir1     },
1578c48fcb47Sblueswir1     {
1579c48fcb47Sblueswir1         .name = "LEON2",
1580c48fcb47Sblueswir1         .iu_version = 0xf2000000,
1581c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1582c48fcb47Sblueswir1         .mmu_version = 0xf2000000,
1583c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1584c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1585c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1586c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1587c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
15881a14026eSblueswir1         .nwindows = 8,
1589b04d9890SFabien Chouteau         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
1590c48fcb47Sblueswir1     },
1591c48fcb47Sblueswir1     {
1592c48fcb47Sblueswir1         .name = "LEON3",
1593c48fcb47Sblueswir1         .iu_version = 0xf3000000,
1594c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1595c48fcb47Sblueswir1         .mmu_version = 0xf3000000,
1596b04d9890SFabien Chouteau         .mmu_bm = 0x00000000,
1597c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1598c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1599c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1600c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
16011a14026eSblueswir1         .nwindows = 8,
16024a2ba232SFabien Chouteau         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
160360f356e8SFabien Chouteau         CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
1604c48fcb47Sblueswir1     },
1605c48fcb47Sblueswir1 #endif
1606c48fcb47Sblueswir1 };
1607c48fcb47Sblueswir1 
160864a88d5dSblueswir1 static const char * const feature_name[] = {
160964a88d5dSblueswir1     "float",
161064a88d5dSblueswir1     "float128",
161164a88d5dSblueswir1     "swap",
161264a88d5dSblueswir1     "mul",
161364a88d5dSblueswir1     "div",
161464a88d5dSblueswir1     "flush",
161564a88d5dSblueswir1     "fsqrt",
161664a88d5dSblueswir1     "fmul",
161764a88d5dSblueswir1     "vis1",
161864a88d5dSblueswir1     "vis2",
1619e30b4678Sblueswir1     "fsmuld",
1620fb79ceb9Sblueswir1     "hypv",
1621fb79ceb9Sblueswir1     "cmt",
1622fb79ceb9Sblueswir1     "gl",
162364a88d5dSblueswir1 };
162464a88d5dSblueswir1 
16259a78eeadSStefan Weil static void print_features(FILE *f, fprintf_function cpu_fprintf,
162664a88d5dSblueswir1                            uint32_t features, const char *prefix)
1627c48fcb47Sblueswir1 {
1628c48fcb47Sblueswir1     unsigned int i;
1629c48fcb47Sblueswir1 
163064a88d5dSblueswir1     for (i = 0; i < ARRAY_SIZE(feature_name); i++)
163164a88d5dSblueswir1         if (feature_name[i] && (features & (1 << i))) {
163264a88d5dSblueswir1             if (prefix)
163364a88d5dSblueswir1                 (*cpu_fprintf)(f, "%s", prefix);
163464a88d5dSblueswir1             (*cpu_fprintf)(f, "%s ", feature_name[i]);
163564a88d5dSblueswir1         }
163664a88d5dSblueswir1 }
163764a88d5dSblueswir1 
163864a88d5dSblueswir1 static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
163964a88d5dSblueswir1 {
164064a88d5dSblueswir1     unsigned int i;
164164a88d5dSblueswir1 
164264a88d5dSblueswir1     for (i = 0; i < ARRAY_SIZE(feature_name); i++)
164364a88d5dSblueswir1         if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
164464a88d5dSblueswir1             *features |= 1 << i;
164564a88d5dSblueswir1             return;
164664a88d5dSblueswir1         }
164764a88d5dSblueswir1     fprintf(stderr, "CPU feature %s not found\n", flagname);
164864a88d5dSblueswir1 }
164964a88d5dSblueswir1 
165022548760Sblueswir1 static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
165164a88d5dSblueswir1 {
165264a88d5dSblueswir1     unsigned int i;
165364a88d5dSblueswir1     const sparc_def_t *def = NULL;
165464a88d5dSblueswir1     char *s = strdup(cpu_model);
165564a88d5dSblueswir1     char *featurestr, *name = strtok(s, ",");
165664a88d5dSblueswir1     uint32_t plus_features = 0;
165764a88d5dSblueswir1     uint32_t minus_features = 0;
16580bfcd599SBlue Swirl     uint64_t iu_version;
16591a14026eSblueswir1     uint32_t fpu_version, mmu_version, nwindows;
166064a88d5dSblueswir1 
1661b1503cdaSmalc     for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
1662c48fcb47Sblueswir1         if (strcasecmp(name, sparc_defs[i].name) == 0) {
166364a88d5dSblueswir1             def = &sparc_defs[i];
1664c48fcb47Sblueswir1         }
1665c48fcb47Sblueswir1     }
166664a88d5dSblueswir1     if (!def)
166764a88d5dSblueswir1         goto error;
166864a88d5dSblueswir1     memcpy(cpu_def, def, sizeof(*def));
166964a88d5dSblueswir1 
167064a88d5dSblueswir1     featurestr = strtok(NULL, ",");
167164a88d5dSblueswir1     while (featurestr) {
167264a88d5dSblueswir1         char *val;
167364a88d5dSblueswir1 
167464a88d5dSblueswir1         if (featurestr[0] == '+') {
167564a88d5dSblueswir1             add_flagname_to_bitmaps(featurestr + 1, &plus_features);
167664a88d5dSblueswir1         } else if (featurestr[0] == '-') {
167764a88d5dSblueswir1             add_flagname_to_bitmaps(featurestr + 1, &minus_features);
167864a88d5dSblueswir1         } else if ((val = strchr(featurestr, '='))) {
167964a88d5dSblueswir1             *val = 0; val++;
168064a88d5dSblueswir1             if (!strcmp(featurestr, "iu_version")) {
168164a88d5dSblueswir1                 char *err;
168264a88d5dSblueswir1 
168364a88d5dSblueswir1                 iu_version = strtoll(val, &err, 0);
168464a88d5dSblueswir1                 if (!*val || *err) {
168564a88d5dSblueswir1                     fprintf(stderr, "bad numerical value %s\n", val);
168664a88d5dSblueswir1                     goto error;
168764a88d5dSblueswir1                 }
168864a88d5dSblueswir1                 cpu_def->iu_version = iu_version;
168964a88d5dSblueswir1 #ifdef DEBUG_FEATURES
16900bfcd599SBlue Swirl                 fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
169164a88d5dSblueswir1 #endif
169264a88d5dSblueswir1             } else if (!strcmp(featurestr, "fpu_version")) {
169364a88d5dSblueswir1                 char *err;
169464a88d5dSblueswir1 
169564a88d5dSblueswir1                 fpu_version = strtol(val, &err, 0);
169664a88d5dSblueswir1                 if (!*val || *err) {
169764a88d5dSblueswir1                     fprintf(stderr, "bad numerical value %s\n", val);
169864a88d5dSblueswir1                     goto error;
169964a88d5dSblueswir1                 }
170064a88d5dSblueswir1                 cpu_def->fpu_version = fpu_version;
170164a88d5dSblueswir1 #ifdef DEBUG_FEATURES
17020bf9e31aSBlue Swirl                 fprintf(stderr, "fpu_version %x\n", fpu_version);
170364a88d5dSblueswir1 #endif
170464a88d5dSblueswir1             } else if (!strcmp(featurestr, "mmu_version")) {
170564a88d5dSblueswir1                 char *err;
170664a88d5dSblueswir1 
170764a88d5dSblueswir1                 mmu_version = strtol(val, &err, 0);
170864a88d5dSblueswir1                 if (!*val || *err) {
170964a88d5dSblueswir1                     fprintf(stderr, "bad numerical value %s\n", val);
171064a88d5dSblueswir1                     goto error;
171164a88d5dSblueswir1                 }
171264a88d5dSblueswir1                 cpu_def->mmu_version = mmu_version;
171364a88d5dSblueswir1 #ifdef DEBUG_FEATURES
17140bf9e31aSBlue Swirl                 fprintf(stderr, "mmu_version %x\n", mmu_version);
171564a88d5dSblueswir1 #endif
17161a14026eSblueswir1             } else if (!strcmp(featurestr, "nwindows")) {
17171a14026eSblueswir1                 char *err;
17181a14026eSblueswir1 
17191a14026eSblueswir1                 nwindows = strtol(val, &err, 0);
17201a14026eSblueswir1                 if (!*val || *err || nwindows > MAX_NWINDOWS ||
17211a14026eSblueswir1                     nwindows < MIN_NWINDOWS) {
17221a14026eSblueswir1                     fprintf(stderr, "bad numerical value %s\n", val);
17231a14026eSblueswir1                     goto error;
17241a14026eSblueswir1                 }
17251a14026eSblueswir1                 cpu_def->nwindows = nwindows;
17261a14026eSblueswir1 #ifdef DEBUG_FEATURES
17271a14026eSblueswir1                 fprintf(stderr, "nwindows %d\n", nwindows);
17281a14026eSblueswir1 #endif
172964a88d5dSblueswir1             } else {
173064a88d5dSblueswir1                 fprintf(stderr, "unrecognized feature %s\n", featurestr);
173164a88d5dSblueswir1                 goto error;
173264a88d5dSblueswir1             }
173364a88d5dSblueswir1         } else {
173477f193daSblueswir1             fprintf(stderr, "feature string `%s' not in format "
173577f193daSblueswir1                     "(+feature|-feature|feature=xyz)\n", featurestr);
173664a88d5dSblueswir1             goto error;
173764a88d5dSblueswir1         }
173864a88d5dSblueswir1         featurestr = strtok(NULL, ",");
173964a88d5dSblueswir1     }
174064a88d5dSblueswir1     cpu_def->features |= plus_features;
174164a88d5dSblueswir1     cpu_def->features &= ~minus_features;
174264a88d5dSblueswir1 #ifdef DEBUG_FEATURES
174364a88d5dSblueswir1     print_features(stderr, fprintf, cpu_def->features, NULL);
174464a88d5dSblueswir1 #endif
174564a88d5dSblueswir1     free(s);
174664a88d5dSblueswir1     return 0;
174764a88d5dSblueswir1 
174864a88d5dSblueswir1  error:
174964a88d5dSblueswir1     free(s);
175064a88d5dSblueswir1     return -1;
1751c48fcb47Sblueswir1 }
1752c48fcb47Sblueswir1 
17539a78eeadSStefan Weil void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
1754c48fcb47Sblueswir1 {
1755c48fcb47Sblueswir1     unsigned int i;
1756c48fcb47Sblueswir1 
1757b1503cdaSmalc     for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
17581a14026eSblueswir1         (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x NWINS %d ",
1759c48fcb47Sblueswir1                        sparc_defs[i].name,
1760c48fcb47Sblueswir1                        sparc_defs[i].iu_version,
1761c48fcb47Sblueswir1                        sparc_defs[i].fpu_version,
17621a14026eSblueswir1                        sparc_defs[i].mmu_version,
17631a14026eSblueswir1                        sparc_defs[i].nwindows);
176477f193daSblueswir1         print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
176577f193daSblueswir1                        ~sparc_defs[i].features, "-");
176677f193daSblueswir1         print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
176777f193daSblueswir1                        sparc_defs[i].features, "+");
176864a88d5dSblueswir1         (*cpu_fprintf)(f, "\n");
1769c48fcb47Sblueswir1     }
1770f76981b1Sblueswir1     (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
1771f76981b1Sblueswir1     print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
177264a88d5dSblueswir1     (*cpu_fprintf)(f, "\n");
1773f76981b1Sblueswir1     (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
1774f76981b1Sblueswir1     print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
1775f76981b1Sblueswir1     (*cpu_fprintf)(f, "\n");
1776f76981b1Sblueswir1     (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
1777f76981b1Sblueswir1                    "fpu_version mmu_version nwindows\n");
1778c48fcb47Sblueswir1 }
1779c48fcb47Sblueswir1 
17809a78eeadSStefan Weil static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
178143bb98bfSBlue Swirl                          uint32_t cc)
178243bb98bfSBlue Swirl {
178343bb98bfSBlue Swirl     cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG? 'N' : '-',
178443bb98bfSBlue Swirl                 cc & PSR_ZERO? 'Z' : '-', cc & PSR_OVF? 'V' : '-',
178543bb98bfSBlue Swirl                 cc & PSR_CARRY? 'C' : '-');
178643bb98bfSBlue Swirl }
178743bb98bfSBlue Swirl 
178843bb98bfSBlue Swirl #ifdef TARGET_SPARC64
178943bb98bfSBlue Swirl #define REGS_PER_LINE 4
179043bb98bfSBlue Swirl #else
179143bb98bfSBlue Swirl #define REGS_PER_LINE 8
179243bb98bfSBlue Swirl #endif
179343bb98bfSBlue Swirl 
17949a78eeadSStefan Weil void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
1795c48fcb47Sblueswir1                     int flags)
1796c48fcb47Sblueswir1 {
1797c48fcb47Sblueswir1     int i, x;
1798c48fcb47Sblueswir1 
179977f193daSblueswir1     cpu_fprintf(f, "pc: " TARGET_FMT_lx "  npc: " TARGET_FMT_lx "\n", env->pc,
180077f193daSblueswir1                 env->npc);
1801c48fcb47Sblueswir1     cpu_fprintf(f, "General Registers:\n");
180243bb98bfSBlue Swirl 
180343bb98bfSBlue Swirl     for (i = 0; i < 8; i++) {
180443bb98bfSBlue Swirl         if (i % REGS_PER_LINE == 0) {
180543bb98bfSBlue Swirl             cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
180643bb98bfSBlue Swirl         }
180743bb98bfSBlue Swirl         cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
180843bb98bfSBlue Swirl         if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
1809c48fcb47Sblueswir1             cpu_fprintf(f, "\n");
1810c48fcb47Sblueswir1         }
181143bb98bfSBlue Swirl     }
181243bb98bfSBlue Swirl     cpu_fprintf(f, "\nCurrent Register Window:\n");
181343bb98bfSBlue Swirl     for (x = 0; x < 3; x++) {
181443bb98bfSBlue Swirl         for (i = 0; i < 8; i++) {
181543bb98bfSBlue Swirl             if (i % REGS_PER_LINE == 0) {
181643bb98bfSBlue Swirl                 cpu_fprintf(f, "%%%c%d-%d: ",
181743bb98bfSBlue Swirl                             x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
181843bb98bfSBlue Swirl                             i, i + REGS_PER_LINE - 1);
181943bb98bfSBlue Swirl             }
182043bb98bfSBlue Swirl             cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
182143bb98bfSBlue Swirl             if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
182243bb98bfSBlue Swirl                 cpu_fprintf(f, "\n");
182343bb98bfSBlue Swirl             }
182443bb98bfSBlue Swirl         }
182543bb98bfSBlue Swirl     }
1826c48fcb47Sblueswir1     cpu_fprintf(f, "\nFloating Point Registers:\n");
182743bb98bfSBlue Swirl     for (i = 0; i < TARGET_FPREGS; i++) {
1828c48fcb47Sblueswir1         if ((i & 3) == 0)
1829c48fcb47Sblueswir1             cpu_fprintf(f, "%%f%02d:", i);
1830a37ee56cSblueswir1         cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
1831c48fcb47Sblueswir1         if ((i & 3) == 3)
1832c48fcb47Sblueswir1             cpu_fprintf(f, "\n");
1833c48fcb47Sblueswir1     }
1834c48fcb47Sblueswir1 #ifdef TARGET_SPARC64
183543bb98bfSBlue Swirl     cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
1836113c6106SStefan Weil                 (unsigned)cpu_get_ccr(env));
18375a834bb4SBlue Swirl     cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
183843bb98bfSBlue Swirl     cpu_fprintf(f, " xcc: ");
18395a834bb4SBlue Swirl     cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
184043bb98bfSBlue Swirl     cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
184143bb98bfSBlue Swirl                 env->psrpil);
184243bb98bfSBlue Swirl     cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
184343bb98bfSBlue Swirl                 "cleanwin: %d cwp: %d\n",
1844c48fcb47Sblueswir1                 env->cansave, env->canrestore, env->otherwin, env->wstate,
18451a14026eSblueswir1                 env->cleanwin, env->nwindows - 1 - env->cwp);
184643bb98bfSBlue Swirl     cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
184743bb98bfSBlue Swirl                 TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
1848c48fcb47Sblueswir1 #else
18495a834bb4SBlue Swirl     cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
18505a834bb4SBlue Swirl     cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
185143bb98bfSBlue Swirl     cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs? 'S' : '-',
185243bb98bfSBlue Swirl                 env->psrps? 'P' : '-', env->psret? 'E' : '-',
185343bb98bfSBlue Swirl                 env->wim);
185443bb98bfSBlue Swirl     cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
185543bb98bfSBlue Swirl                 env->fsr, env->y);
1856c48fcb47Sblueswir1 #endif
1857c48fcb47Sblueswir1 }
1858