xref: /qemu/target/sparc/helper.c (revision ccc76c24efdb06b895b8ff3d0a932c905ff483d4)
1e8af50a3Sbellard /*
2e8af50a3Sbellard  *  sparc helpers
3e8af50a3Sbellard  *
483469015Sbellard  *  Copyright (c) 2003-2005 Fabrice Bellard
5e8af50a3Sbellard  *
6e8af50a3Sbellard  * This library is free software; you can redistribute it and/or
7e8af50a3Sbellard  * modify it under the terms of the GNU Lesser General Public
8e8af50a3Sbellard  * License as published by the Free Software Foundation; either
9e8af50a3Sbellard  * version 2 of the License, or (at your option) any later version.
10e8af50a3Sbellard  *
11e8af50a3Sbellard  * This library is distributed in the hope that it will be useful,
12e8af50a3Sbellard  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13e8af50a3Sbellard  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14e8af50a3Sbellard  * Lesser General Public License for more details.
15e8af50a3Sbellard  *
16e8af50a3Sbellard  * You should have received a copy of the GNU Lesser General Public
178167ee88SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18e8af50a3Sbellard  */
19ee5bbe38Sbellard #include <stdarg.h>
20ee5bbe38Sbellard #include <stdlib.h>
21ee5bbe38Sbellard #include <stdio.h>
22ee5bbe38Sbellard #include <string.h>
23ee5bbe38Sbellard #include <inttypes.h>
24ee5bbe38Sbellard 
25ee5bbe38Sbellard #include "cpu.h"
26ca10f867Saurel32 #include "qemu-common.h"
27e8af50a3Sbellard 
28e80cfcfcSbellard //#define DEBUG_MMU
2964a88d5dSblueswir1 //#define DEBUG_FEATURES
30e8af50a3Sbellard 
31b8e9fc06SIgor V. Kovalenko #ifdef DEBUG_MMU
32b8e9fc06SIgor V. Kovalenko #define DPRINTF_MMU(fmt, ...) \
33b8e9fc06SIgor V. Kovalenko     do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
34b8e9fc06SIgor V. Kovalenko #else
35b8e9fc06SIgor V. Kovalenko #define DPRINTF_MMU(fmt, ...) do {} while (0)
36b8e9fc06SIgor V. Kovalenko #endif
37b8e9fc06SIgor V. Kovalenko 
3822548760Sblueswir1 static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
39c48fcb47Sblueswir1 
40e8af50a3Sbellard /* Sparc MMU emulation */
41e8af50a3Sbellard 
429d893301Sbellard #if defined(CONFIG_USER_ONLY)
439d893301Sbellard 
4422548760Sblueswir1 int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
456ebbf390Sj_mayer                                int mmu_idx, int is_softmmu)
469d893301Sbellard {
47878d3096Sbellard     if (rw & 2)
4822548760Sblueswir1         env1->exception_index = TT_TFAULT;
49878d3096Sbellard     else
5022548760Sblueswir1         env1->exception_index = TT_DFAULT;
519d893301Sbellard     return 1;
529d893301Sbellard }
539d893301Sbellard 
549d893301Sbellard #else
55e8af50a3Sbellard 
563475187dSbellard #ifndef TARGET_SPARC64
5783469015Sbellard /*
5883469015Sbellard  * Sparc V8 Reference MMU (SRMMU)
5983469015Sbellard  */
60e8af50a3Sbellard static const int access_table[8][8] = {
61a764a566Sblueswir1     { 0, 0, 0, 0, 8, 0, 12, 12 },
62a764a566Sblueswir1     { 0, 0, 0, 0, 8, 0, 0, 0 },
63a764a566Sblueswir1     { 8, 8, 0, 0, 0, 8, 12, 12 },
64a764a566Sblueswir1     { 8, 8, 0, 0, 0, 8, 0, 0 },
65a764a566Sblueswir1     { 8, 0, 8, 0, 8, 8, 12, 12 },
66a764a566Sblueswir1     { 8, 0, 8, 0, 8, 0, 8, 0 },
67a764a566Sblueswir1     { 8, 8, 8, 0, 8, 8, 12, 12 },
68a764a566Sblueswir1     { 8, 8, 8, 0, 8, 8, 8, 0 }
69e8af50a3Sbellard };
70e8af50a3Sbellard 
71227671c9Sbellard static const int perm_table[2][8] = {
72227671c9Sbellard     {
73227671c9Sbellard         PAGE_READ,
74227671c9Sbellard         PAGE_READ | PAGE_WRITE,
75227671c9Sbellard         PAGE_READ | PAGE_EXEC,
76227671c9Sbellard         PAGE_READ | PAGE_WRITE | PAGE_EXEC,
77227671c9Sbellard         PAGE_EXEC,
78227671c9Sbellard         PAGE_READ | PAGE_WRITE,
79227671c9Sbellard         PAGE_READ | PAGE_EXEC,
80227671c9Sbellard         PAGE_READ | PAGE_WRITE | PAGE_EXEC
81227671c9Sbellard     },
82227671c9Sbellard     {
83227671c9Sbellard         PAGE_READ,
84227671c9Sbellard         PAGE_READ | PAGE_WRITE,
85227671c9Sbellard         PAGE_READ | PAGE_EXEC,
86227671c9Sbellard         PAGE_READ | PAGE_WRITE | PAGE_EXEC,
87227671c9Sbellard         PAGE_EXEC,
88227671c9Sbellard         PAGE_READ,
89227671c9Sbellard         0,
90227671c9Sbellard         0,
91227671c9Sbellard     }
92e8af50a3Sbellard };
93e8af50a3Sbellard 
94c227f099SAnthony Liguori static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
95c48fcb47Sblueswir1                                 int *prot, int *access_index,
96d4c430a8SPaul Brook                                 target_ulong address, int rw, int mmu_idx,
97d4c430a8SPaul Brook                                 target_ulong *page_size)
98e8af50a3Sbellard {
99e80cfcfcSbellard     int access_perms = 0;
100c227f099SAnthony Liguori     target_phys_addr_t pde_ptr;
101af7bf89bSbellard     uint32_t pde;
1026ebbf390Sj_mayer     int error_code = 0, is_dirty, is_user;
103e80cfcfcSbellard     unsigned long page_offset;
104e8af50a3Sbellard 
1056ebbf390Sj_mayer     is_user = mmu_idx == MMU_USER_IDX;
10640ce0a9aSblueswir1 
107e8af50a3Sbellard     if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
108d4c430a8SPaul Brook         *page_size = TARGET_PAGE_SIZE;
10940ce0a9aSblueswir1         // Boot mode: instruction fetches are taken from PROM
1105578ceabSblueswir1         if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
11158a770f3Sblueswir1             *physical = env->prom_addr | (address & 0x7ffffULL);
11240ce0a9aSblueswir1             *prot = PAGE_READ | PAGE_EXEC;
11340ce0a9aSblueswir1             return 0;
11440ce0a9aSblueswir1         }
115e80cfcfcSbellard         *physical = address;
116227671c9Sbellard         *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
117e80cfcfcSbellard         return 0;
118e8af50a3Sbellard     }
119e8af50a3Sbellard 
1207483750dSbellard     *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
1215dcb6b91Sblueswir1     *physical = 0xffffffffffff0000ULL;
1227483750dSbellard 
123e8af50a3Sbellard     /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
124e8af50a3Sbellard     /* Context base + context number */
1253deaeab7Sblueswir1     pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
12649be8030Sbellard     pde = ldl_phys(pde_ptr);
127e8af50a3Sbellard 
128e8af50a3Sbellard     /* Ctx pde */
129e8af50a3Sbellard     switch (pde & PTE_ENTRYTYPE_MASK) {
130e80cfcfcSbellard     default:
131e8af50a3Sbellard     case 0: /* Invalid */
1327483750dSbellard         return 1 << 2;
133e80cfcfcSbellard     case 2: /* L0 PTE, maybe should not happen? */
134e8af50a3Sbellard     case 3: /* Reserved */
1357483750dSbellard         return 4 << 2;
136e80cfcfcSbellard     case 1: /* L0 PDE */
137e80cfcfcSbellard         pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
13849be8030Sbellard         pde = ldl_phys(pde_ptr);
139e80cfcfcSbellard 
140e80cfcfcSbellard         switch (pde & PTE_ENTRYTYPE_MASK) {
141e80cfcfcSbellard         default:
142e80cfcfcSbellard         case 0: /* Invalid */
1437483750dSbellard             return (1 << 8) | (1 << 2);
144e80cfcfcSbellard         case 3: /* Reserved */
1457483750dSbellard             return (1 << 8) | (4 << 2);
146e8af50a3Sbellard         case 1: /* L1 PDE */
147e80cfcfcSbellard             pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
14849be8030Sbellard             pde = ldl_phys(pde_ptr);
149e8af50a3Sbellard 
150e8af50a3Sbellard             switch (pde & PTE_ENTRYTYPE_MASK) {
151e80cfcfcSbellard             default:
152e8af50a3Sbellard             case 0: /* Invalid */
1537483750dSbellard                 return (2 << 8) | (1 << 2);
154e8af50a3Sbellard             case 3: /* Reserved */
1557483750dSbellard                 return (2 << 8) | (4 << 2);
156e8af50a3Sbellard             case 1: /* L2 PDE */
157e80cfcfcSbellard                 pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
15849be8030Sbellard                 pde = ldl_phys(pde_ptr);
159e8af50a3Sbellard 
160e8af50a3Sbellard                 switch (pde & PTE_ENTRYTYPE_MASK) {
161e80cfcfcSbellard                 default:
162e8af50a3Sbellard                 case 0: /* Invalid */
1637483750dSbellard                     return (3 << 8) | (1 << 2);
164e8af50a3Sbellard                 case 1: /* PDE, should not happen */
165e8af50a3Sbellard                 case 3: /* Reserved */
1667483750dSbellard                     return (3 << 8) | (4 << 2);
167e8af50a3Sbellard                 case 2: /* L3 PTE */
16877f193daSblueswir1                     page_offset = (address & TARGET_PAGE_MASK) &
16977f193daSblueswir1                         (TARGET_PAGE_SIZE - 1);
170e8af50a3Sbellard                 }
171d4c430a8SPaul Brook                 *page_size = TARGET_PAGE_SIZE;
172e8af50a3Sbellard                 break;
173e8af50a3Sbellard             case 2: /* L2 PTE */
174e8af50a3Sbellard                 page_offset = address & 0x3ffff;
175d4c430a8SPaul Brook                 *page_size = 0x40000;
176e8af50a3Sbellard             }
177e8af50a3Sbellard             break;
178e8af50a3Sbellard         case 2: /* L1 PTE */
179e8af50a3Sbellard             page_offset = address & 0xffffff;
180d4c430a8SPaul Brook             *page_size = 0x1000000;
181e8af50a3Sbellard         }
182e8af50a3Sbellard     }
183e8af50a3Sbellard 
184698235aaSArtyom Tarasenko     /* check access */
185698235aaSArtyom Tarasenko     access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
186698235aaSArtyom Tarasenko     error_code = access_table[*access_index][access_perms];
187698235aaSArtyom Tarasenko     if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user))
188698235aaSArtyom Tarasenko         return error_code;
189698235aaSArtyom Tarasenko 
190e8af50a3Sbellard     /* update page modified and dirty bits */
191b769d8feSbellard     is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
192e8af50a3Sbellard     if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
193e8af50a3Sbellard         pde |= PG_ACCESSED_MASK;
194e8af50a3Sbellard         if (is_dirty)
195e8af50a3Sbellard             pde |= PG_MODIFIED_MASK;
19649be8030Sbellard         stl_phys_notdirty(pde_ptr, pde);
197e8af50a3Sbellard     }
198e8af50a3Sbellard 
199e8af50a3Sbellard     /* the page can be put in the TLB */
200227671c9Sbellard     *prot = perm_table[is_user][access_perms];
201227671c9Sbellard     if (!(pde & PG_MODIFIED_MASK)) {
202e8af50a3Sbellard         /* only set write access if already dirty... otherwise wait
203e8af50a3Sbellard            for dirty access */
204227671c9Sbellard         *prot &= ~PAGE_WRITE;
205e8af50a3Sbellard     }
206e8af50a3Sbellard 
207e8af50a3Sbellard     /* Even if large ptes, we map only one 4KB page in the cache to
208e8af50a3Sbellard        avoid filling it too fast */
209c227f099SAnthony Liguori     *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
2106f7e9aecSbellard     return error_code;
211e80cfcfcSbellard }
212e80cfcfcSbellard 
213e80cfcfcSbellard /* Perform address translation */
214af7bf89bSbellard int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
2156ebbf390Sj_mayer                               int mmu_idx, int is_softmmu)
216e80cfcfcSbellard {
217c227f099SAnthony Liguori     target_phys_addr_t paddr;
2185dcb6b91Sblueswir1     target_ulong vaddr;
219d4c430a8SPaul Brook     target_ulong page_size;
220d4c430a8SPaul Brook     int error_code = 0, prot, access_index;
221e80cfcfcSbellard 
22277f193daSblueswir1     error_code = get_physical_address(env, &paddr, &prot, &access_index,
223d4c430a8SPaul Brook                                       address, rw, mmu_idx, &page_size);
224e80cfcfcSbellard     if (error_code == 0) {
2259e61bde5Sbellard         vaddr = address & TARGET_PAGE_MASK;
2269e61bde5Sbellard         paddr &= TARGET_PAGE_MASK;
2279e61bde5Sbellard #ifdef DEBUG_MMU
2285dcb6b91Sblueswir1         printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
2295dcb6b91Sblueswir1                TARGET_FMT_lx "\n", address, paddr, vaddr);
2309e61bde5Sbellard #endif
231d4c430a8SPaul Brook         tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
232d4c430a8SPaul Brook         return 0;
233e80cfcfcSbellard     }
234e8af50a3Sbellard 
235e8af50a3Sbellard     if (env->mmuregs[3]) /* Fault status register */
236e8af50a3Sbellard         env->mmuregs[3] = 1; /* overflow (not read before another fault) */
2377483750dSbellard     env->mmuregs[3] |= (access_index << 5) | error_code | 2;
238e8af50a3Sbellard     env->mmuregs[4] = address; /* Fault address register */
239e8af50a3Sbellard 
240878d3096Sbellard     if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
2416f7e9aecSbellard         // No fault mode: if a mapping is available, just override
2426f7e9aecSbellard         // permissions. If no mapping is available, redirect accesses to
2436f7e9aecSbellard         // neverland. Fake/overridden mappings will be flushed when
2446f7e9aecSbellard         // switching to normal mode.
2457483750dSbellard         vaddr = address & TARGET_PAGE_MASK;
246227671c9Sbellard         prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
247d4c430a8SPaul Brook         tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
248d4c430a8SPaul Brook         return 0;
2497483750dSbellard     } else {
250878d3096Sbellard         if (rw & 2)
251878d3096Sbellard             env->exception_index = TT_TFAULT;
252878d3096Sbellard         else
253878d3096Sbellard             env->exception_index = TT_DFAULT;
254878d3096Sbellard         return 1;
255e8af50a3Sbellard     }
2567483750dSbellard }
25724741ef3Sbellard 
25824741ef3Sbellard target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
25924741ef3Sbellard {
260c227f099SAnthony Liguori     target_phys_addr_t pde_ptr;
26124741ef3Sbellard     uint32_t pde;
26224741ef3Sbellard 
26324741ef3Sbellard     /* Context base + context number */
264c227f099SAnthony Liguori     pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
2655dcb6b91Sblueswir1         (env->mmuregs[2] << 2);
26624741ef3Sbellard     pde = ldl_phys(pde_ptr);
26724741ef3Sbellard 
26824741ef3Sbellard     switch (pde & PTE_ENTRYTYPE_MASK) {
26924741ef3Sbellard     default:
27024741ef3Sbellard     case 0: /* Invalid */
27124741ef3Sbellard     case 2: /* PTE, maybe should not happen? */
27224741ef3Sbellard     case 3: /* Reserved */
27324741ef3Sbellard         return 0;
27424741ef3Sbellard     case 1: /* L1 PDE */
27524741ef3Sbellard         if (mmulev == 3)
27624741ef3Sbellard             return pde;
27724741ef3Sbellard         pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
27824741ef3Sbellard         pde = ldl_phys(pde_ptr);
27924741ef3Sbellard 
28024741ef3Sbellard         switch (pde & PTE_ENTRYTYPE_MASK) {
28124741ef3Sbellard         default:
28224741ef3Sbellard         case 0: /* Invalid */
28324741ef3Sbellard         case 3: /* Reserved */
28424741ef3Sbellard             return 0;
28524741ef3Sbellard         case 2: /* L1 PTE */
28624741ef3Sbellard             return pde;
28724741ef3Sbellard         case 1: /* L2 PDE */
28824741ef3Sbellard             if (mmulev == 2)
28924741ef3Sbellard                 return pde;
29024741ef3Sbellard             pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
29124741ef3Sbellard             pde = ldl_phys(pde_ptr);
29224741ef3Sbellard 
29324741ef3Sbellard             switch (pde & PTE_ENTRYTYPE_MASK) {
29424741ef3Sbellard             default:
29524741ef3Sbellard             case 0: /* Invalid */
29624741ef3Sbellard             case 3: /* Reserved */
29724741ef3Sbellard                 return 0;
29824741ef3Sbellard             case 2: /* L2 PTE */
29924741ef3Sbellard                 return pde;
30024741ef3Sbellard             case 1: /* L3 PDE */
30124741ef3Sbellard                 if (mmulev == 1)
30224741ef3Sbellard                     return pde;
30324741ef3Sbellard                 pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
30424741ef3Sbellard                 pde = ldl_phys(pde_ptr);
30524741ef3Sbellard 
30624741ef3Sbellard                 switch (pde & PTE_ENTRYTYPE_MASK) {
30724741ef3Sbellard                 default:
30824741ef3Sbellard                 case 0: /* Invalid */
30924741ef3Sbellard                 case 1: /* PDE, should not happen */
31024741ef3Sbellard                 case 3: /* Reserved */
31124741ef3Sbellard                     return 0;
31224741ef3Sbellard                 case 2: /* L3 PTE */
31324741ef3Sbellard                     return pde;
31424741ef3Sbellard                 }
31524741ef3Sbellard             }
31624741ef3Sbellard         }
31724741ef3Sbellard     }
31824741ef3Sbellard     return 0;
31924741ef3Sbellard }
32024741ef3Sbellard 
321d41160a3SBlue Swirl void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
32224741ef3Sbellard {
32324741ef3Sbellard     target_ulong va, va1, va2;
32424741ef3Sbellard     unsigned int n, m, o;
325c227f099SAnthony Liguori     target_phys_addr_t pde_ptr, pa;
32624741ef3Sbellard     uint32_t pde;
32724741ef3Sbellard 
32824741ef3Sbellard     pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
32924741ef3Sbellard     pde = ldl_phys(pde_ptr);
330d41160a3SBlue Swirl     (*cpu_fprintf)(f, "Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
331c227f099SAnthony Liguori                    (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
33224741ef3Sbellard     for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
3335dcb6b91Sblueswir1         pde = mmu_probe(env, va, 2);
3345dcb6b91Sblueswir1         if (pde) {
33524741ef3Sbellard             pa = cpu_get_phys_page_debug(env, va);
336d41160a3SBlue Swirl             (*cpu_fprintf)(f, "VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
3375dcb6b91Sblueswir1                            " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
33824741ef3Sbellard             for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
3395dcb6b91Sblueswir1                 pde = mmu_probe(env, va1, 1);
3405dcb6b91Sblueswir1                 if (pde) {
34124741ef3Sbellard                     pa = cpu_get_phys_page_debug(env, va1);
342d41160a3SBlue Swirl                     (*cpu_fprintf)(f, " VA: " TARGET_FMT_lx ", PA: "
343d41160a3SBlue Swirl                                    TARGET_FMT_plx " PDE: " TARGET_FMT_lx "\n",
344d41160a3SBlue Swirl                                    va1, pa, pde);
34524741ef3Sbellard                     for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
3465dcb6b91Sblueswir1                         pde = mmu_probe(env, va2, 0);
3475dcb6b91Sblueswir1                         if (pde) {
34824741ef3Sbellard                             pa = cpu_get_phys_page_debug(env, va2);
349d41160a3SBlue Swirl                             (*cpu_fprintf)(f, "  VA: " TARGET_FMT_lx ", PA: "
350d41160a3SBlue Swirl                                            TARGET_FMT_plx " PTE: "
351d41160a3SBlue Swirl                                            TARGET_FMT_lx "\n",
3525dcb6b91Sblueswir1                                            va2, pa, pde);
35324741ef3Sbellard                         }
35424741ef3Sbellard                     }
35524741ef3Sbellard                 }
35624741ef3Sbellard             }
35724741ef3Sbellard         }
35824741ef3Sbellard     }
35924741ef3Sbellard }
36024741ef3Sbellard 
36124741ef3Sbellard #else /* !TARGET_SPARC64 */
362e8807b14SIgor Kovalenko 
363e8807b14SIgor Kovalenko // 41 bit physical address space
364c227f099SAnthony Liguori static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
365e8807b14SIgor Kovalenko {
366e8807b14SIgor Kovalenko     return x & 0x1ffffffffffULL;
367e8807b14SIgor Kovalenko }
368e8807b14SIgor Kovalenko 
36983469015Sbellard /*
37083469015Sbellard  * UltraSparc IIi I/DMMUs
37183469015Sbellard  */
3723475187dSbellard 
373536ba015SIgor Kovalenko // Returns true if TTE tag is valid and matches virtual address value in context
374536ba015SIgor Kovalenko // requires virtual address mask value calculated from TTE entry size
3756e8e7d4cSIgor Kovalenko static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
376536ba015SIgor Kovalenko                                        uint64_t address, uint64_t context,
377299b520cSIgor V. Kovalenko                                        target_phys_addr_t *physical)
378536ba015SIgor Kovalenko {
379536ba015SIgor Kovalenko     uint64_t mask;
380536ba015SIgor Kovalenko 
38106e12b65STsuneo Saito     switch (TTE_PGSIZE(tlb->tte)) {
3823475187dSbellard     default:
38383469015Sbellard     case 0x0: // 8k
3843475187dSbellard         mask = 0xffffffffffffe000ULL;
3853475187dSbellard         break;
38683469015Sbellard     case 0x1: // 64k
3873475187dSbellard         mask = 0xffffffffffff0000ULL;
3883475187dSbellard         break;
38983469015Sbellard     case 0x2: // 512k
3903475187dSbellard         mask = 0xfffffffffff80000ULL;
3913475187dSbellard         break;
39283469015Sbellard     case 0x3: // 4M
3933475187dSbellard         mask = 0xffffffffffc00000ULL;
3943475187dSbellard         break;
3953475187dSbellard     }
396536ba015SIgor Kovalenko 
397536ba015SIgor Kovalenko     // valid, context match, virtual address match?
398f707726eSIgor Kovalenko     if (TTE_IS_VALID(tlb->tte) &&
399299b520cSIgor V. Kovalenko         (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
4002a90358fSBlue Swirl         && compare_masked(address, tlb->tag, mask))
401536ba015SIgor Kovalenko     {
402536ba015SIgor Kovalenko         // decode physical address
4036e8e7d4cSIgor Kovalenko         *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
404536ba015SIgor Kovalenko         return 1;
405536ba015SIgor Kovalenko     }
406536ba015SIgor Kovalenko 
407536ba015SIgor Kovalenko     return 0;
408536ba015SIgor Kovalenko }
409536ba015SIgor Kovalenko 
410536ba015SIgor Kovalenko static int get_physical_address_data(CPUState *env,
411c227f099SAnthony Liguori                                      target_phys_addr_t *physical, int *prot,
4122065061eSIgor V. Kovalenko                                      target_ulong address, int rw, int mmu_idx)
413536ba015SIgor Kovalenko {
414536ba015SIgor Kovalenko     unsigned int i;
415536ba015SIgor Kovalenko     uint64_t context;
416ccc76c24STsuneo Saito     uint64_t sfsr = 0;
417536ba015SIgor Kovalenko 
4182065061eSIgor V. Kovalenko     int is_user = (mmu_idx == MMU_USER_IDX ||
4192065061eSIgor V. Kovalenko                    mmu_idx == MMU_USER_SECONDARY_IDX);
4202065061eSIgor V. Kovalenko 
421536ba015SIgor Kovalenko     if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
422536ba015SIgor Kovalenko         *physical = ultrasparc_truncate_physical(address);
423536ba015SIgor Kovalenko         *prot = PAGE_READ | PAGE_WRITE;
424536ba015SIgor Kovalenko         return 0;
425536ba015SIgor Kovalenko     }
426536ba015SIgor Kovalenko 
4272065061eSIgor V. Kovalenko     switch(mmu_idx) {
4282065061eSIgor V. Kovalenko     case MMU_USER_IDX:
4292065061eSIgor V. Kovalenko     case MMU_KERNEL_IDX:
4306e8e7d4cSIgor Kovalenko         context = env->dmmu.mmu_primary_context & 0x1fff;
431ccc76c24STsuneo Saito         sfsr |= SFSR_CT_PRIMARY;
4322065061eSIgor V. Kovalenko         break;
4332065061eSIgor V. Kovalenko     case MMU_USER_SECONDARY_IDX:
4342065061eSIgor V. Kovalenko     case MMU_KERNEL_SECONDARY_IDX:
4352065061eSIgor V. Kovalenko         context = env->dmmu.mmu_secondary_context & 0x1fff;
436ccc76c24STsuneo Saito         sfsr |= SFSR_CT_SECONDARY;
4372065061eSIgor V. Kovalenko         break;
4382065061eSIgor V. Kovalenko     case MMU_NUCLEUS_IDX:
439ccc76c24STsuneo Saito         sfsr |= SFSR_CT_NUCLEUS;
440ccc76c24STsuneo Saito         /* FALLTHRU */
44144505216SBlue Swirl     default:
442299b520cSIgor V. Kovalenko         context = 0;
4432065061eSIgor V. Kovalenko         break;
444299b520cSIgor V. Kovalenko     }
445536ba015SIgor Kovalenko 
446ccc76c24STsuneo Saito     if (rw == 1) {
447ccc76c24STsuneo Saito         sfsr |= SFSR_WRITE_BIT;
448ccc76c24STsuneo Saito     }
449ccc76c24STsuneo Saito 
450536ba015SIgor Kovalenko     for (i = 0; i < 64; i++) {
451afdf8109Sblueswir1         // ctx match, vaddr match, valid?
452b8e9fc06SIgor V. Kovalenko         if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
453b8e9fc06SIgor V. Kovalenko 
454b8e9fc06SIgor V. Kovalenko             // access ok?
45506e12b65STsuneo Saito             if (TTE_IS_PRIV(env->dtlb[i].tte) && is_user) {
456ccc76c24STsuneo Saito                 sfsr |= SFSR_FT_PRIV_BIT; /* privilege violation */
457b8e9fc06SIgor V. Kovalenko                 env->exception_index = TT_DFAULT;
458b8e9fc06SIgor V. Kovalenko 
459b8e9fc06SIgor V. Kovalenko                 DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64
460b8e9fc06SIgor V. Kovalenko                             " mmu_idx=%d tl=%d\n",
461b8e9fc06SIgor V. Kovalenko                             address, context, mmu_idx, env->tl);
46206e12b65STsuneo Saito             } else if (!TTE_IS_W_OK(env->dtlb[i].tte) && (rw == 1)) {
463b8e9fc06SIgor V. Kovalenko                 env->exception_index = TT_DPROT;
464b8e9fc06SIgor V. Kovalenko 
465b8e9fc06SIgor V. Kovalenko                 DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64
466b8e9fc06SIgor V. Kovalenko                             " mmu_idx=%d tl=%d\n",
467b8e9fc06SIgor V. Kovalenko                             address, context, mmu_idx, env->tl);
468b8e9fc06SIgor V. Kovalenko             } else {
469b8e9fc06SIgor V. Kovalenko                 *prot = PAGE_READ;
47006e12b65STsuneo Saito                 if (TTE_IS_W_OK(env->dtlb[i].tte)) {
471b8e9fc06SIgor V. Kovalenko                     *prot |= PAGE_WRITE;
47206e12b65STsuneo Saito                 }
473b8e9fc06SIgor V. Kovalenko 
474b8e9fc06SIgor V. Kovalenko                 TTE_SET_USED(env->dtlb[i].tte);
475b8e9fc06SIgor V. Kovalenko 
476b8e9fc06SIgor V. Kovalenko                 return 0;
4776e8e7d4cSIgor Kovalenko             }
4786e8e7d4cSIgor Kovalenko 
479ccc76c24STsuneo Saito             if (env->dmmu.sfsr & SFSR_VALID_BIT) { /* Fault status register */
480ccc76c24STsuneo Saito                 sfsr |= SFSR_OW_BIT; /* overflow (not read before
48177f193daSblueswir1                                         another fault) */
482ccc76c24STsuneo Saito             }
4836e8e7d4cSIgor Kovalenko 
484ccc76c24STsuneo Saito             if (env->pstate & PS_PRIV) {
485ccc76c24STsuneo Saito                 sfsr |= SFSR_PR_BIT;
486ccc76c24STsuneo Saito             }
4876e8e7d4cSIgor Kovalenko 
488ccc76c24STsuneo Saito             /* FIXME: ASI field in SFSR must be set */
489ccc76c24STsuneo Saito             env->dmmu.sfsr = sfsr | SFSR_VALID_BIT;
4906e8e7d4cSIgor Kovalenko 
4916e8e7d4cSIgor Kovalenko             env->dmmu.sfar = address; /* Fault address register */
4929168b3a5SIgor V. Kovalenko 
4939168b3a5SIgor V. Kovalenko             env->dmmu.tag_access = (address & ~0x1fffULL) | context;
4949168b3a5SIgor V. Kovalenko 
4953475187dSbellard             return 1;
4963475187dSbellard         }
4973475187dSbellard     }
498b8e9fc06SIgor V. Kovalenko 
499b8e9fc06SIgor V. Kovalenko     DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n",
500b8e9fc06SIgor V. Kovalenko                 address, context);
501b8e9fc06SIgor V. Kovalenko 
502ccc76c24STsuneo Saito     /*
503ccc76c24STsuneo Saito      * On MMU misses:
504ccc76c24STsuneo Saito      * - UltraSPARC IIi: SFSR and SFAR unmodified
505ccc76c24STsuneo Saito      * - JPS1: SFAR updated and some fields of SFSR updated
506ccc76c24STsuneo Saito      */
5076e8e7d4cSIgor Kovalenko     env->dmmu.tag_access = (address & ~0x1fffULL) | context;
50883469015Sbellard     env->exception_index = TT_DMISS;
5093475187dSbellard     return 1;
5103475187dSbellard }
5113475187dSbellard 
51277f193daSblueswir1 static int get_physical_address_code(CPUState *env,
513c227f099SAnthony Liguori                                      target_phys_addr_t *physical, int *prot,
5142065061eSIgor V. Kovalenko                                      target_ulong address, int mmu_idx)
5153475187dSbellard {
5163475187dSbellard     unsigned int i;
517536ba015SIgor Kovalenko     uint64_t context;
5183475187dSbellard 
5192065061eSIgor V. Kovalenko     int is_user = (mmu_idx == MMU_USER_IDX ||
5202065061eSIgor V. Kovalenko                    mmu_idx == MMU_USER_SECONDARY_IDX);
5212065061eSIgor V. Kovalenko 
522e8807b14SIgor Kovalenko     if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
523e8807b14SIgor Kovalenko         /* IMMU disabled */
524e8807b14SIgor Kovalenko         *physical = ultrasparc_truncate_physical(address);
525227671c9Sbellard         *prot = PAGE_EXEC;
5263475187dSbellard         return 0;
5273475187dSbellard     }
52883469015Sbellard 
529299b520cSIgor V. Kovalenko     if (env->tl == 0) {
5302065061eSIgor V. Kovalenko         /* PRIMARY context */
5316e8e7d4cSIgor Kovalenko         context = env->dmmu.mmu_primary_context & 0x1fff;
532299b520cSIgor V. Kovalenko     } else {
5332065061eSIgor V. Kovalenko         /* NUCLEUS context */
534299b520cSIgor V. Kovalenko         context = 0;
535299b520cSIgor V. Kovalenko     }
536536ba015SIgor Kovalenko 
5373475187dSbellard     for (i = 0; i < 64; i++) {
538afdf8109Sblueswir1         // ctx match, vaddr match, valid?
5396e8e7d4cSIgor Kovalenko         if (ultrasparc_tag_match(&env->itlb[i],
540299b520cSIgor V. Kovalenko                                  address, context, physical)) {
541afdf8109Sblueswir1             // access ok?
54206e12b65STsuneo Saito             if (TTE_IS_PRIV(env->itlb[i].tte) && is_user) {
543ccc76c24STsuneo Saito                 /* Fault status register */
544ccc76c24STsuneo Saito                 if (env->immu.sfsr & SFSR_VALID_BIT) {
545ccc76c24STsuneo Saito                     env->immu.sfsr = SFSR_OW_BIT; /* overflow (not read before
54677f193daSblueswir1                                                      another fault) */
547ccc76c24STsuneo Saito                 } else {
548ccc76c24STsuneo Saito                     env->immu.sfsr = 0;
549ccc76c24STsuneo Saito                 }
550ccc76c24STsuneo Saito                 if (env->pstate & PS_PRIV) {
551ccc76c24STsuneo Saito                     env->immu.sfsr |= SFSR_PR_BIT;
552ccc76c24STsuneo Saito                 }
553ccc76c24STsuneo Saito                 if (env->tl > 0) {
554ccc76c24STsuneo Saito                     env->immu.sfsr |= SFSR_CT_NUCLEUS;
555ccc76c24STsuneo Saito                 }
556ccc76c24STsuneo Saito 
557ccc76c24STsuneo Saito                 /* FIXME: ASI field in SFSR must be set */
558ccc76c24STsuneo Saito                 env->immu.sfsr |= SFSR_FT_PRIV_BIT | SFSR_VALID_BIT;
5593475187dSbellard                 env->exception_index = TT_TFAULT;
560b8e9fc06SIgor V. Kovalenko 
5619168b3a5SIgor V. Kovalenko                 env->immu.tag_access = (address & ~0x1fffULL) | context;
5629168b3a5SIgor V. Kovalenko 
563b8e9fc06SIgor V. Kovalenko                 DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n",
564b8e9fc06SIgor V. Kovalenko                             address, context);
565b8e9fc06SIgor V. Kovalenko 
5663475187dSbellard                 return 1;
5673475187dSbellard             }
568227671c9Sbellard             *prot = PAGE_EXEC;
569f707726eSIgor Kovalenko             TTE_SET_USED(env->itlb[i].tte);
5703475187dSbellard             return 0;
5713475187dSbellard         }
5723475187dSbellard     }
573b8e9fc06SIgor V. Kovalenko 
574b8e9fc06SIgor V. Kovalenko     DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n",
575b8e9fc06SIgor V. Kovalenko                 address, context);
576b8e9fc06SIgor V. Kovalenko 
5777ab463cbSBlue Swirl     /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
5786e8e7d4cSIgor Kovalenko     env->immu.tag_access = (address & ~0x1fffULL) | context;
57983469015Sbellard     env->exception_index = TT_TMISS;
5803475187dSbellard     return 1;
5813475187dSbellard }
5823475187dSbellard 
583c227f099SAnthony Liguori static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
584c48fcb47Sblueswir1                                 int *prot, int *access_index,
585d4c430a8SPaul Brook                                 target_ulong address, int rw, int mmu_idx,
586d4c430a8SPaul Brook                                 target_ulong *page_size)
5873475187dSbellard {
588d4c430a8SPaul Brook     /* ??? We treat everything as a small page, then explicitly flush
589d4c430a8SPaul Brook        everything when an entry is evicted.  */
590d4c430a8SPaul Brook     *page_size = TARGET_PAGE_SIZE;
5919fd1ae3aSIgor V. Kovalenko 
5929fd1ae3aSIgor V. Kovalenko #if defined (DEBUG_MMU)
5939fd1ae3aSIgor V. Kovalenko     /* safety net to catch wrong softmmu index use from dynamic code */
5949fd1ae3aSIgor V. Kovalenko     if (env->tl > 0 && mmu_idx != MMU_NUCLEUS_IDX) {
5959fd1ae3aSIgor V. Kovalenko         DPRINTF_MMU("get_physical_address %s tl=%d mmu_idx=%d"
5969fd1ae3aSIgor V. Kovalenko                     " primary context=%" PRIx64
5979fd1ae3aSIgor V. Kovalenko                     " secondary context=%" PRIx64
5989fd1ae3aSIgor V. Kovalenko                 " address=%" PRIx64
5999fd1ae3aSIgor V. Kovalenko                 "\n",
6009fd1ae3aSIgor V. Kovalenko                 (rw == 2 ? "CODE" : "DATA"),
6019fd1ae3aSIgor V. Kovalenko                 env->tl, mmu_idx,
6029fd1ae3aSIgor V. Kovalenko                 env->dmmu.mmu_primary_context,
6039fd1ae3aSIgor V. Kovalenko                 env->dmmu.mmu_secondary_context,
6049fd1ae3aSIgor V. Kovalenko                 address);
6059fd1ae3aSIgor V. Kovalenko     }
6069fd1ae3aSIgor V. Kovalenko #endif
6079fd1ae3aSIgor V. Kovalenko 
6083475187dSbellard     if (rw == 2)
60922548760Sblueswir1         return get_physical_address_code(env, physical, prot, address,
6102065061eSIgor V. Kovalenko                                          mmu_idx);
6113475187dSbellard     else
61222548760Sblueswir1         return get_physical_address_data(env, physical, prot, address, rw,
6132065061eSIgor V. Kovalenko                                          mmu_idx);
6143475187dSbellard }
6153475187dSbellard 
6163475187dSbellard /* Perform address translation */
6173475187dSbellard int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
6186ebbf390Sj_mayer                               int mmu_idx, int is_softmmu)
6193475187dSbellard {
62083469015Sbellard     target_ulong virt_addr, vaddr;
621c227f099SAnthony Liguori     target_phys_addr_t paddr;
622d4c430a8SPaul Brook     target_ulong page_size;
623d4c430a8SPaul Brook     int error_code = 0, prot, access_index;
6243475187dSbellard 
62577f193daSblueswir1     error_code = get_physical_address(env, &paddr, &prot, &access_index,
626d4c430a8SPaul Brook                                       address, rw, mmu_idx, &page_size);
6273475187dSbellard     if (error_code == 0) {
6283475187dSbellard         virt_addr = address & TARGET_PAGE_MASK;
62977f193daSblueswir1         vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
63077f193daSblueswir1                              (TARGET_PAGE_SIZE - 1));
631b8e9fc06SIgor V. Kovalenko 
632b8e9fc06SIgor V. Kovalenko         DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 ","
633b8e9fc06SIgor V. Kovalenko                     " vaddr %" PRIx64
634b8e9fc06SIgor V. Kovalenko                     " mmu_idx=%d"
635b8e9fc06SIgor V. Kovalenko                     " tl=%d"
636b8e9fc06SIgor V. Kovalenko                     " primary context=%" PRIx64
637b8e9fc06SIgor V. Kovalenko                     " secondary context=%" PRIx64
638b8e9fc06SIgor V. Kovalenko                     "\n",
639b8e9fc06SIgor V. Kovalenko                     address, paddr, vaddr, mmu_idx, env->tl,
640b8e9fc06SIgor V. Kovalenko                     env->dmmu.mmu_primary_context,
641b8e9fc06SIgor V. Kovalenko                     env->dmmu.mmu_secondary_context);
642b8e9fc06SIgor V. Kovalenko 
643d4c430a8SPaul Brook         tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
644d4c430a8SPaul Brook         return 0;
6453475187dSbellard     }
6463475187dSbellard     // XXX
6473475187dSbellard     return 1;
6483475187dSbellard }
6493475187dSbellard 
650d41160a3SBlue Swirl void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUState *env)
65183469015Sbellard {
65283469015Sbellard     unsigned int i;
65383469015Sbellard     const char *mask;
65483469015Sbellard 
655d41160a3SBlue Swirl     (*cpu_fprintf)(f, "MMU contexts: Primary: %" PRId64 ", Secondary: %"
656d41160a3SBlue Swirl                    PRId64 "\n",
657d41160a3SBlue Swirl                    env->dmmu.mmu_primary_context,
658d41160a3SBlue Swirl                    env->dmmu.mmu_secondary_context);
65983469015Sbellard     if ((env->lsu & DMMU_E) == 0) {
660d41160a3SBlue Swirl         (*cpu_fprintf)(f, "DMMU disabled\n");
66183469015Sbellard     } else {
662d41160a3SBlue Swirl         (*cpu_fprintf)(f, "DMMU dump\n");
66383469015Sbellard         for (i = 0; i < 64; i++) {
66406e12b65STsuneo Saito             switch (TTE_PGSIZE(env->dtlb[i].tte)) {
66583469015Sbellard             default:
66683469015Sbellard             case 0x0:
66783469015Sbellard                 mask = "  8k";
66883469015Sbellard                 break;
66983469015Sbellard             case 0x1:
67083469015Sbellard                 mask = " 64k";
67183469015Sbellard                 break;
67283469015Sbellard             case 0x2:
67383469015Sbellard                 mask = "512k";
67483469015Sbellard                 break;
67583469015Sbellard             case 0x3:
67683469015Sbellard                 mask = "  4M";
67783469015Sbellard                 break;
67883469015Sbellard             }
67906e12b65STsuneo Saito             if (TTE_IS_VALID(env->dtlb[i].tte)) {
680d41160a3SBlue Swirl                 (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %" PRIx64
6812a90358fSBlue Swirl                                ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
6826e8e7d4cSIgor Kovalenko                                i,
68331a68d57SBlue Swirl                                env->dtlb[i].tag & (uint64_t)~0x1fffULL,
68406e12b65STsuneo Saito                                TTE_PA(env->dtlb[i].tte),
68583469015Sbellard                                mask,
68606e12b65STsuneo Saito                                TTE_IS_PRIV(env->dtlb[i].tte) ? "priv" : "user",
68706e12b65STsuneo Saito                                TTE_IS_W_OK(env->dtlb[i].tte) ? "RW" : "RO",
68806e12b65STsuneo Saito                                TTE_IS_LOCKED(env->dtlb[i].tte) ?
68906e12b65STsuneo Saito                                "locked" : "unlocked",
6902a90358fSBlue Swirl                                env->dtlb[i].tag & (uint64_t)0x1fffULL,
691d41160a3SBlue Swirl                                TTE_IS_GLOBAL(env->dtlb[i].tte)?
692d41160a3SBlue Swirl                                "global" : "local");
69383469015Sbellard             }
69483469015Sbellard         }
69583469015Sbellard     }
69683469015Sbellard     if ((env->lsu & IMMU_E) == 0) {
697d41160a3SBlue Swirl         (*cpu_fprintf)(f, "IMMU disabled\n");
69883469015Sbellard     } else {
699d41160a3SBlue Swirl         (*cpu_fprintf)(f, "IMMU dump\n");
70083469015Sbellard         for (i = 0; i < 64; i++) {
70106e12b65STsuneo Saito             switch (TTE_PGSIZE(env->itlb[i].tte)) {
70283469015Sbellard             default:
70383469015Sbellard             case 0x0:
70483469015Sbellard                 mask = "  8k";
70583469015Sbellard                 break;
70683469015Sbellard             case 0x1:
70783469015Sbellard                 mask = " 64k";
70883469015Sbellard                 break;
70983469015Sbellard             case 0x2:
71083469015Sbellard                 mask = "512k";
71183469015Sbellard                 break;
71283469015Sbellard             case 0x3:
71383469015Sbellard                 mask = "  4M";
71483469015Sbellard                 break;
71583469015Sbellard             }
71606e12b65STsuneo Saito             if (TTE_IS_VALID(env->itlb[i].tte)) {
717d41160a3SBlue Swirl                 (*cpu_fprintf)(f, "[%02u] VA: %" PRIx64 ", PA: %" PRIx64
7182a90358fSBlue Swirl                                ", %s, %s, %s, ctx %" PRId64 " %s\n",
7196e8e7d4cSIgor Kovalenko                                i,
7206e8e7d4cSIgor Kovalenko                                env->itlb[i].tag & (uint64_t)~0x1fffULL,
72106e12b65STsuneo Saito                                TTE_PA(env->itlb[i].tte),
72283469015Sbellard                                mask,
72306e12b65STsuneo Saito                                TTE_IS_PRIV(env->itlb[i].tte) ? "priv" : "user",
72406e12b65STsuneo Saito                                TTE_IS_LOCKED(env->itlb[i].tte) ?
72506e12b65STsuneo Saito                                "locked" : "unlocked",
7262a90358fSBlue Swirl                                env->itlb[i].tag & (uint64_t)0x1fffULL,
727d41160a3SBlue Swirl                                TTE_IS_GLOBAL(env->itlb[i].tte)?
728d41160a3SBlue Swirl                                "global" : "local");
72983469015Sbellard             }
73083469015Sbellard         }
73183469015Sbellard     }
73283469015Sbellard }
73324741ef3Sbellard 
73424741ef3Sbellard #endif /* TARGET_SPARC64 */
73524741ef3Sbellard #endif /* !CONFIG_USER_ONLY */
73624741ef3Sbellard 
737c48fcb47Sblueswir1 
7384fcc562bSPaul Brook #if !defined(CONFIG_USER_ONLY)
7392065061eSIgor V. Kovalenko target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
7402065061eSIgor V. Kovalenko                                            int mmu_idx)
741c48fcb47Sblueswir1 {
742c227f099SAnthony Liguori     target_phys_addr_t phys_addr;
743d4c430a8SPaul Brook     target_ulong page_size;
744c48fcb47Sblueswir1     int prot, access_index;
745c48fcb47Sblueswir1 
746c48fcb47Sblueswir1     if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2,
7472065061eSIgor V. Kovalenko                              mmu_idx, &page_size) != 0)
748c48fcb47Sblueswir1         if (get_physical_address(env, &phys_addr, &prot, &access_index, addr,
7492065061eSIgor V. Kovalenko                                  0, mmu_idx, &page_size) != 0)
750c48fcb47Sblueswir1             return -1;
751c48fcb47Sblueswir1     if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED)
752c48fcb47Sblueswir1         return -1;
753c48fcb47Sblueswir1     return phys_addr;
754c48fcb47Sblueswir1 }
7552065061eSIgor V. Kovalenko 
7562065061eSIgor V. Kovalenko target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
7572065061eSIgor V. Kovalenko {
7589fd1ae3aSIgor V. Kovalenko     return cpu_get_phys_page_nofault(env, addr, cpu_mmu_index(env));
7592065061eSIgor V. Kovalenko }
760c48fcb47Sblueswir1 #endif
761c48fcb47Sblueswir1 
762e67768d0SBlue Swirl #ifdef TARGET_SPARC64
763e67768d0SBlue Swirl #ifdef DEBUG_PCALL
764e67768d0SBlue Swirl static const char * const excp_names[0x80] = {
765e67768d0SBlue Swirl     [TT_TFAULT] = "Instruction Access Fault",
766e67768d0SBlue Swirl     [TT_TMISS] = "Instruction Access MMU Miss",
767e67768d0SBlue Swirl     [TT_CODE_ACCESS] = "Instruction Access Error",
768e67768d0SBlue Swirl     [TT_ILL_INSN] = "Illegal Instruction",
769e67768d0SBlue Swirl     [TT_PRIV_INSN] = "Privileged Instruction",
770e67768d0SBlue Swirl     [TT_NFPU_INSN] = "FPU Disabled",
771e67768d0SBlue Swirl     [TT_FP_EXCP] = "FPU Exception",
772e67768d0SBlue Swirl     [TT_TOVF] = "Tag Overflow",
773e67768d0SBlue Swirl     [TT_CLRWIN] = "Clean Windows",
774e67768d0SBlue Swirl     [TT_DIV_ZERO] = "Division By Zero",
775e67768d0SBlue Swirl     [TT_DFAULT] = "Data Access Fault",
776e67768d0SBlue Swirl     [TT_DMISS] = "Data Access MMU Miss",
777e67768d0SBlue Swirl     [TT_DATA_ACCESS] = "Data Access Error",
778e67768d0SBlue Swirl     [TT_DPROT] = "Data Protection Error",
779e67768d0SBlue Swirl     [TT_UNALIGNED] = "Unaligned Memory Access",
780e67768d0SBlue Swirl     [TT_PRIV_ACT] = "Privileged Action",
781e67768d0SBlue Swirl     [TT_EXTINT | 0x1] = "External Interrupt 1",
782e67768d0SBlue Swirl     [TT_EXTINT | 0x2] = "External Interrupt 2",
783e67768d0SBlue Swirl     [TT_EXTINT | 0x3] = "External Interrupt 3",
784e67768d0SBlue Swirl     [TT_EXTINT | 0x4] = "External Interrupt 4",
785e67768d0SBlue Swirl     [TT_EXTINT | 0x5] = "External Interrupt 5",
786e67768d0SBlue Swirl     [TT_EXTINT | 0x6] = "External Interrupt 6",
787e67768d0SBlue Swirl     [TT_EXTINT | 0x7] = "External Interrupt 7",
788e67768d0SBlue Swirl     [TT_EXTINT | 0x8] = "External Interrupt 8",
789e67768d0SBlue Swirl     [TT_EXTINT | 0x9] = "External Interrupt 9",
790e67768d0SBlue Swirl     [TT_EXTINT | 0xa] = "External Interrupt 10",
791e67768d0SBlue Swirl     [TT_EXTINT | 0xb] = "External Interrupt 11",
792e67768d0SBlue Swirl     [TT_EXTINT | 0xc] = "External Interrupt 12",
793e67768d0SBlue Swirl     [TT_EXTINT | 0xd] = "External Interrupt 13",
794e67768d0SBlue Swirl     [TT_EXTINT | 0xe] = "External Interrupt 14",
795e67768d0SBlue Swirl     [TT_EXTINT | 0xf] = "External Interrupt 15",
796e67768d0SBlue Swirl };
797e67768d0SBlue Swirl #endif
798e67768d0SBlue Swirl 
799e67768d0SBlue Swirl void do_interrupt(CPUState *env)
800e67768d0SBlue Swirl {
801e67768d0SBlue Swirl     int intno = env->exception_index;
802e67768d0SBlue Swirl     trap_state *tsptr;
803e67768d0SBlue Swirl 
804e67768d0SBlue Swirl #ifdef DEBUG_PCALL
805e67768d0SBlue Swirl     if (qemu_loglevel_mask(CPU_LOG_INT)) {
806e67768d0SBlue Swirl         static int count;
807e67768d0SBlue Swirl         const char *name;
808e67768d0SBlue Swirl 
809e67768d0SBlue Swirl         if (intno < 0 || intno >= 0x180) {
810e67768d0SBlue Swirl             name = "Unknown";
811e67768d0SBlue Swirl         } else if (intno >= 0x100) {
812e67768d0SBlue Swirl             name = "Trap Instruction";
813e67768d0SBlue Swirl         } else if (intno >= 0xc0) {
814e67768d0SBlue Swirl             name = "Window Fill";
815e67768d0SBlue Swirl         } else if (intno >= 0x80) {
816e67768d0SBlue Swirl             name = "Window Spill";
817e67768d0SBlue Swirl         } else {
818e67768d0SBlue Swirl             name = excp_names[intno];
819e67768d0SBlue Swirl             if (!name) {
820e67768d0SBlue Swirl                 name = "Unknown";
821e67768d0SBlue Swirl             }
822e67768d0SBlue Swirl         }
823e67768d0SBlue Swirl 
824e67768d0SBlue Swirl         qemu_log("%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64
825e67768d0SBlue Swirl                 " SP=%016" PRIx64 "\n",
826e67768d0SBlue Swirl                 count, name, intno,
827e67768d0SBlue Swirl                 env->pc,
828e67768d0SBlue Swirl                 env->npc, env->regwptr[6]);
829e67768d0SBlue Swirl         log_cpu_state(env, 0);
830e67768d0SBlue Swirl #if 0
831e67768d0SBlue Swirl         {
832e67768d0SBlue Swirl             int i;
833e67768d0SBlue Swirl             uint8_t *ptr;
834e67768d0SBlue Swirl 
835e67768d0SBlue Swirl             qemu_log("       code=");
836e67768d0SBlue Swirl             ptr = (uint8_t *)env->pc;
837e67768d0SBlue Swirl             for (i = 0; i < 16; i++) {
838e67768d0SBlue Swirl                 qemu_log(" %02x", ldub(ptr + i));
839e67768d0SBlue Swirl             }
840e67768d0SBlue Swirl             qemu_log("\n");
841e67768d0SBlue Swirl         }
842e67768d0SBlue Swirl #endif
843e67768d0SBlue Swirl         count++;
844e67768d0SBlue Swirl     }
845e67768d0SBlue Swirl #endif
846e67768d0SBlue Swirl #if !defined(CONFIG_USER_ONLY)
847e67768d0SBlue Swirl     if (env->tl >= env->maxtl) {
848e67768d0SBlue Swirl         cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d),"
849e67768d0SBlue Swirl                   " Error state", env->exception_index, env->tl, env->maxtl);
850e67768d0SBlue Swirl         return;
851e67768d0SBlue Swirl     }
852e67768d0SBlue Swirl #endif
853e67768d0SBlue Swirl     if (env->tl < env->maxtl - 1) {
854e67768d0SBlue Swirl         env->tl++;
855e67768d0SBlue Swirl     } else {
856e67768d0SBlue Swirl         env->pstate |= PS_RED;
857e67768d0SBlue Swirl         if (env->tl < env->maxtl) {
858e67768d0SBlue Swirl             env->tl++;
859e67768d0SBlue Swirl         }
860e67768d0SBlue Swirl     }
861e67768d0SBlue Swirl     tsptr = cpu_tsptr(env);
862e67768d0SBlue Swirl 
863e67768d0SBlue Swirl     tsptr->tstate = (cpu_get_ccr(env) << 32) |
864e67768d0SBlue Swirl         ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) |
865e67768d0SBlue Swirl         cpu_get_cwp64(env);
866e67768d0SBlue Swirl     tsptr->tpc = env->pc;
867e67768d0SBlue Swirl     tsptr->tnpc = env->npc;
868e67768d0SBlue Swirl     tsptr->tt = intno;
869e67768d0SBlue Swirl 
870e67768d0SBlue Swirl     switch (intno) {
871e67768d0SBlue Swirl     case TT_IVEC:
872e67768d0SBlue Swirl         cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_IG);
873e67768d0SBlue Swirl         break;
874e67768d0SBlue Swirl     case TT_TFAULT:
875e67768d0SBlue Swirl     case TT_DFAULT:
876e67768d0SBlue Swirl     case TT_TMISS ... TT_TMISS + 3:
877e67768d0SBlue Swirl     case TT_DMISS ... TT_DMISS + 3:
878e67768d0SBlue Swirl     case TT_DPROT ... TT_DPROT + 3:
879e67768d0SBlue Swirl         cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_MG);
880e67768d0SBlue Swirl         break;
881e67768d0SBlue Swirl     default:
882e67768d0SBlue Swirl         cpu_change_pstate(env, PS_PEF | PS_PRIV | PS_AG);
883e67768d0SBlue Swirl         break;
884e67768d0SBlue Swirl     }
885e67768d0SBlue Swirl 
886e67768d0SBlue Swirl     if (intno == TT_CLRWIN) {
887e67768d0SBlue Swirl         cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1));
888e67768d0SBlue Swirl     } else if ((intno & 0x1c0) == TT_SPILL) {
889e67768d0SBlue Swirl         cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2));
890e67768d0SBlue Swirl     } else if ((intno & 0x1c0) == TT_FILL) {
891e67768d0SBlue Swirl         cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1));
892e67768d0SBlue Swirl     }
893e67768d0SBlue Swirl     env->tbr &= ~0x7fffULL;
894e67768d0SBlue Swirl     env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
895e67768d0SBlue Swirl     env->pc = env->tbr;
896e67768d0SBlue Swirl     env->npc = env->pc + 4;
897e67768d0SBlue Swirl     env->exception_index = -1;
898e67768d0SBlue Swirl }
899e67768d0SBlue Swirl #else
900e67768d0SBlue Swirl #ifdef DEBUG_PCALL
901e67768d0SBlue Swirl static const char * const excp_names[0x80] = {
902e67768d0SBlue Swirl     [TT_TFAULT] = "Instruction Access Fault",
903e67768d0SBlue Swirl     [TT_ILL_INSN] = "Illegal Instruction",
904e67768d0SBlue Swirl     [TT_PRIV_INSN] = "Privileged Instruction",
905e67768d0SBlue Swirl     [TT_NFPU_INSN] = "FPU Disabled",
906e67768d0SBlue Swirl     [TT_WIN_OVF] = "Window Overflow",
907e67768d0SBlue Swirl     [TT_WIN_UNF] = "Window Underflow",
908e67768d0SBlue Swirl     [TT_UNALIGNED] = "Unaligned Memory Access",
909e67768d0SBlue Swirl     [TT_FP_EXCP] = "FPU Exception",
910e67768d0SBlue Swirl     [TT_DFAULT] = "Data Access Fault",
911e67768d0SBlue Swirl     [TT_TOVF] = "Tag Overflow",
912e67768d0SBlue Swirl     [TT_EXTINT | 0x1] = "External Interrupt 1",
913e67768d0SBlue Swirl     [TT_EXTINT | 0x2] = "External Interrupt 2",
914e67768d0SBlue Swirl     [TT_EXTINT | 0x3] = "External Interrupt 3",
915e67768d0SBlue Swirl     [TT_EXTINT | 0x4] = "External Interrupt 4",
916e67768d0SBlue Swirl     [TT_EXTINT | 0x5] = "External Interrupt 5",
917e67768d0SBlue Swirl     [TT_EXTINT | 0x6] = "External Interrupt 6",
918e67768d0SBlue Swirl     [TT_EXTINT | 0x7] = "External Interrupt 7",
919e67768d0SBlue Swirl     [TT_EXTINT | 0x8] = "External Interrupt 8",
920e67768d0SBlue Swirl     [TT_EXTINT | 0x9] = "External Interrupt 9",
921e67768d0SBlue Swirl     [TT_EXTINT | 0xa] = "External Interrupt 10",
922e67768d0SBlue Swirl     [TT_EXTINT | 0xb] = "External Interrupt 11",
923e67768d0SBlue Swirl     [TT_EXTINT | 0xc] = "External Interrupt 12",
924e67768d0SBlue Swirl     [TT_EXTINT | 0xd] = "External Interrupt 13",
925e67768d0SBlue Swirl     [TT_EXTINT | 0xe] = "External Interrupt 14",
926e67768d0SBlue Swirl     [TT_EXTINT | 0xf] = "External Interrupt 15",
927e67768d0SBlue Swirl     [TT_TOVF] = "Tag Overflow",
928e67768d0SBlue Swirl     [TT_CODE_ACCESS] = "Instruction Access Error",
929e67768d0SBlue Swirl     [TT_DATA_ACCESS] = "Data Access Error",
930e67768d0SBlue Swirl     [TT_DIV_ZERO] = "Division By Zero",
931e67768d0SBlue Swirl     [TT_NCP_INSN] = "Coprocessor Disabled",
932e67768d0SBlue Swirl };
933e67768d0SBlue Swirl #endif
934e67768d0SBlue Swirl 
935e67768d0SBlue Swirl void do_interrupt(CPUState *env)
936e67768d0SBlue Swirl {
937e67768d0SBlue Swirl     int cwp, intno = env->exception_index;
938e67768d0SBlue Swirl 
939e67768d0SBlue Swirl #ifdef DEBUG_PCALL
940e67768d0SBlue Swirl     if (qemu_loglevel_mask(CPU_LOG_INT)) {
941e67768d0SBlue Swirl         static int count;
942e67768d0SBlue Swirl         const char *name;
943e67768d0SBlue Swirl 
944e67768d0SBlue Swirl         if (intno < 0 || intno >= 0x100) {
945e67768d0SBlue Swirl             name = "Unknown";
946e67768d0SBlue Swirl         } else if (intno >= 0x80) {
947e67768d0SBlue Swirl             name = "Trap Instruction";
948e67768d0SBlue Swirl         } else {
949e67768d0SBlue Swirl             name = excp_names[intno];
950e67768d0SBlue Swirl             if (!name) {
951e67768d0SBlue Swirl                 name = "Unknown";
952e67768d0SBlue Swirl             }
953e67768d0SBlue Swirl         }
954e67768d0SBlue Swirl 
955e67768d0SBlue Swirl         qemu_log("%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n",
956e67768d0SBlue Swirl                 count, name, intno,
957e67768d0SBlue Swirl                 env->pc,
958e67768d0SBlue Swirl                 env->npc, env->regwptr[6]);
959e67768d0SBlue Swirl         log_cpu_state(env, 0);
960e67768d0SBlue Swirl #if 0
961e67768d0SBlue Swirl         {
962e67768d0SBlue Swirl             int i;
963e67768d0SBlue Swirl             uint8_t *ptr;
964e67768d0SBlue Swirl 
965e67768d0SBlue Swirl             qemu_log("       code=");
966e67768d0SBlue Swirl             ptr = (uint8_t *)env->pc;
967e67768d0SBlue Swirl             for (i = 0; i < 16; i++) {
968e67768d0SBlue Swirl                 qemu_log(" %02x", ldub(ptr + i));
969e67768d0SBlue Swirl             }
970e67768d0SBlue Swirl             qemu_log("\n");
971e67768d0SBlue Swirl         }
972e67768d0SBlue Swirl #endif
973e67768d0SBlue Swirl         count++;
974e67768d0SBlue Swirl     }
975e67768d0SBlue Swirl #endif
976e67768d0SBlue Swirl #if !defined(CONFIG_USER_ONLY)
977e67768d0SBlue Swirl     if (env->psret == 0) {
978e67768d0SBlue Swirl         cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state",
979e67768d0SBlue Swirl                   env->exception_index);
980e67768d0SBlue Swirl         return;
981e67768d0SBlue Swirl     }
982e67768d0SBlue Swirl #endif
983e67768d0SBlue Swirl     env->psret = 0;
984e67768d0SBlue Swirl     cwp = cpu_cwp_dec(env, env->cwp - 1);
985e67768d0SBlue Swirl     cpu_set_cwp(env, cwp);
986e67768d0SBlue Swirl     env->regwptr[9] = env->pc;
987e67768d0SBlue Swirl     env->regwptr[10] = env->npc;
988e67768d0SBlue Swirl     env->psrps = env->psrs;
989e67768d0SBlue Swirl     env->psrs = 1;
990e67768d0SBlue Swirl     env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
991e67768d0SBlue Swirl     env->pc = env->tbr;
992e67768d0SBlue Swirl     env->npc = env->pc + 4;
993e67768d0SBlue Swirl     env->exception_index = -1;
994e67768d0SBlue Swirl 
995e67768d0SBlue Swirl #if !defined(CONFIG_USER_ONLY)
996e67768d0SBlue Swirl     /* IRQ acknowledgment */
997e67768d0SBlue Swirl     if ((intno & ~15) == TT_EXTINT && env->qemu_irq_ack != NULL) {
998e67768d0SBlue Swirl         env->qemu_irq_ack(env->irq_manager, intno);
999e67768d0SBlue Swirl     }
1000e67768d0SBlue Swirl #endif
1001e67768d0SBlue Swirl }
1002e67768d0SBlue Swirl #endif
1003e67768d0SBlue Swirl 
1004c48fcb47Sblueswir1 void cpu_reset(CPUSPARCState *env)
1005c48fcb47Sblueswir1 {
1006eca1bdf4Saliguori     if (qemu_loglevel_mask(CPU_LOG_RESET)) {
1007eca1bdf4Saliguori         qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
1008eca1bdf4Saliguori         log_cpu_state(env, 0);
1009eca1bdf4Saliguori     }
1010eca1bdf4Saliguori 
1011c48fcb47Sblueswir1     tlb_flush(env, 1);
1012c48fcb47Sblueswir1     env->cwp = 0;
10135210977aSIgor Kovalenko #ifndef TARGET_SPARC64
1014c48fcb47Sblueswir1     env->wim = 1;
10155210977aSIgor Kovalenko #endif
1016c48fcb47Sblueswir1     env->regwptr = env->regbase + (env->cwp * 16);
10176b743278SBlue Swirl     CC_OP = CC_OP_FLAGS;
1018c48fcb47Sblueswir1 #if defined(CONFIG_USER_ONLY)
1019c48fcb47Sblueswir1 #ifdef TARGET_SPARC64
10201a14026eSblueswir1     env->cleanwin = env->nwindows - 2;
10211a14026eSblueswir1     env->cansave = env->nwindows - 2;
1022c48fcb47Sblueswir1     env->pstate = PS_RMO | PS_PEF | PS_IE;
1023c48fcb47Sblueswir1     env->asi = 0x82; // Primary no-fault
1024c48fcb47Sblueswir1 #endif
1025c48fcb47Sblueswir1 #else
10265210977aSIgor Kovalenko #if !defined(TARGET_SPARC64)
1027c48fcb47Sblueswir1     env->psret = 0;
1028c48fcb47Sblueswir1     env->psrs = 1;
1029c48fcb47Sblueswir1     env->psrps = 1;
10302aae2b8eSIgor V. Kovalenko #endif
1031c48fcb47Sblueswir1 #ifdef TARGET_SPARC64
10328194f35aSIgor Kovalenko     env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
10332aae2b8eSIgor V. Kovalenko     env->hpstate = cpu_has_hypervisor(env) ? HS_PRIV : 0;
10348194f35aSIgor Kovalenko     env->tl = env->maxtl;
10358194f35aSIgor Kovalenko     cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
1036415fc906Sblueswir1     env->lsu = 0;
1037c48fcb47Sblueswir1 #else
1038c48fcb47Sblueswir1     env->mmuregs[0] &= ~(MMU_E | MMU_NF);
10395578ceabSblueswir1     env->mmuregs[0] |= env->def->mmu_bm;
1040c48fcb47Sblueswir1 #endif
1041e87231d4Sblueswir1     env->pc = 0;
1042c48fcb47Sblueswir1     env->npc = env->pc + 4;
1043c48fcb47Sblueswir1 #endif
1044b04d9890SFabien Chouteau     env->cache_control = 0;
1045c48fcb47Sblueswir1 }
1046c48fcb47Sblueswir1 
104764a88d5dSblueswir1 static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
1048c48fcb47Sblueswir1 {
104964a88d5dSblueswir1     sparc_def_t def1, *def = &def1;
1050c48fcb47Sblueswir1 
105164a88d5dSblueswir1     if (cpu_sparc_find_by_name(def, cpu_model) < 0)
105264a88d5dSblueswir1         return -1;
1053c48fcb47Sblueswir1 
10545578ceabSblueswir1     env->def = qemu_mallocz(sizeof(*def));
10555578ceabSblueswir1     memcpy(env->def, def, sizeof(*def));
10565578ceabSblueswir1 #if defined(CONFIG_USER_ONLY)
10575578ceabSblueswir1     if ((env->def->features & CPU_FEATURE_FLOAT))
10585578ceabSblueswir1         env->def->features |= CPU_FEATURE_FLOAT128;
10595578ceabSblueswir1 #endif
1060c48fcb47Sblueswir1     env->cpu_model_str = cpu_model;
1061c48fcb47Sblueswir1     env->version = def->iu_version;
1062c48fcb47Sblueswir1     env->fsr = def->fpu_version;
10631a14026eSblueswir1     env->nwindows = def->nwindows;
1064c48fcb47Sblueswir1 #if !defined(TARGET_SPARC64)
1065c48fcb47Sblueswir1     env->mmuregs[0] |= def->mmu_version;
1066c48fcb47Sblueswir1     cpu_sparc_set_id(env, 0);
1067963262deSblueswir1     env->mxccregs[7] |= def->mxcc_version;
10681a14026eSblueswir1 #else
1069fb79ceb9Sblueswir1     env->mmu_version = def->mmu_version;
1070c19148bdSblueswir1     env->maxtl = def->maxtl;
1071c19148bdSblueswir1     env->version |= def->maxtl << 8;
10721a14026eSblueswir1     env->version |= def->nwindows - 1;
1073c48fcb47Sblueswir1 #endif
107464a88d5dSblueswir1     return 0;
107564a88d5dSblueswir1 }
107664a88d5dSblueswir1 
107764a88d5dSblueswir1 static void cpu_sparc_close(CPUSPARCState *env)
107864a88d5dSblueswir1 {
10795578ceabSblueswir1     free(env->def);
108064a88d5dSblueswir1     free(env);
108164a88d5dSblueswir1 }
108264a88d5dSblueswir1 
108364a88d5dSblueswir1 CPUSPARCState *cpu_sparc_init(const char *cpu_model)
108464a88d5dSblueswir1 {
108564a88d5dSblueswir1     CPUSPARCState *env;
108664a88d5dSblueswir1 
108764a88d5dSblueswir1     env = qemu_mallocz(sizeof(CPUSPARCState));
108864a88d5dSblueswir1     cpu_exec_init(env);
1089c48fcb47Sblueswir1 
1090c48fcb47Sblueswir1     gen_intermediate_code_init(env);
1091c48fcb47Sblueswir1 
109264a88d5dSblueswir1     if (cpu_sparc_register(env, cpu_model) < 0) {
109364a88d5dSblueswir1         cpu_sparc_close(env);
109464a88d5dSblueswir1         return NULL;
109564a88d5dSblueswir1     }
10960bf46a40Saliguori     qemu_init_vcpu(env);
1097c48fcb47Sblueswir1 
1098c48fcb47Sblueswir1     return env;
1099c48fcb47Sblueswir1 }
1100c48fcb47Sblueswir1 
1101c48fcb47Sblueswir1 void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
1102c48fcb47Sblueswir1 {
1103c48fcb47Sblueswir1 #if !defined(TARGET_SPARC64)
1104c48fcb47Sblueswir1     env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
1105c48fcb47Sblueswir1 #endif
1106c48fcb47Sblueswir1 }
1107c48fcb47Sblueswir1 
1108c48fcb47Sblueswir1 static const sparc_def_t sparc_defs[] = {
1109c48fcb47Sblueswir1 #ifdef TARGET_SPARC64
1110c48fcb47Sblueswir1     {
1111c48fcb47Sblueswir1         .name = "Fujitsu Sparc64",
1112c19148bdSblueswir1         .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
1113c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1114fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11151a14026eSblueswir1         .nwindows = 4,
1116c19148bdSblueswir1         .maxtl = 4,
111764a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1118c48fcb47Sblueswir1     },
1119c48fcb47Sblueswir1     {
1120c48fcb47Sblueswir1         .name = "Fujitsu Sparc64 III",
1121c19148bdSblueswir1         .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
1122c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1123fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11241a14026eSblueswir1         .nwindows = 5,
1125c19148bdSblueswir1         .maxtl = 4,
112664a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1127c48fcb47Sblueswir1     },
1128c48fcb47Sblueswir1     {
1129c48fcb47Sblueswir1         .name = "Fujitsu Sparc64 IV",
1130c19148bdSblueswir1         .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
1131c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1132fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11331a14026eSblueswir1         .nwindows = 8,
1134c19148bdSblueswir1         .maxtl = 5,
113564a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1136c48fcb47Sblueswir1     },
1137c48fcb47Sblueswir1     {
1138c48fcb47Sblueswir1         .name = "Fujitsu Sparc64 V",
1139c19148bdSblueswir1         .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
1140c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1141fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11421a14026eSblueswir1         .nwindows = 8,
1143c19148bdSblueswir1         .maxtl = 5,
114464a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1145c48fcb47Sblueswir1     },
1146c48fcb47Sblueswir1     {
1147c48fcb47Sblueswir1         .name = "TI UltraSparc I",
1148c19148bdSblueswir1         .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
1149c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1150fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11511a14026eSblueswir1         .nwindows = 8,
1152c19148bdSblueswir1         .maxtl = 5,
115364a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1154c48fcb47Sblueswir1     },
1155c48fcb47Sblueswir1     {
1156c48fcb47Sblueswir1         .name = "TI UltraSparc II",
1157c19148bdSblueswir1         .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
1158c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1159fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11601a14026eSblueswir1         .nwindows = 8,
1161c19148bdSblueswir1         .maxtl = 5,
116264a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1163c48fcb47Sblueswir1     },
1164c48fcb47Sblueswir1     {
1165c48fcb47Sblueswir1         .name = "TI UltraSparc IIi",
1166c19148bdSblueswir1         .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
1167c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1168fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11691a14026eSblueswir1         .nwindows = 8,
1170c19148bdSblueswir1         .maxtl = 5,
117164a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1172c48fcb47Sblueswir1     },
1173c48fcb47Sblueswir1     {
1174c48fcb47Sblueswir1         .name = "TI UltraSparc IIe",
1175c19148bdSblueswir1         .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
1176c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1177fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11781a14026eSblueswir1         .nwindows = 8,
1179c19148bdSblueswir1         .maxtl = 5,
118064a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1181c48fcb47Sblueswir1     },
1182c48fcb47Sblueswir1     {
1183c48fcb47Sblueswir1         .name = "Sun UltraSparc III",
1184c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
1185c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1186fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
11871a14026eSblueswir1         .nwindows = 8,
1188c19148bdSblueswir1         .maxtl = 5,
118964a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1190c48fcb47Sblueswir1     },
1191c48fcb47Sblueswir1     {
1192c48fcb47Sblueswir1         .name = "Sun UltraSparc III Cu",
1193c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
1194c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1195fb79ceb9Sblueswir1         .mmu_version = mmu_us_3,
11961a14026eSblueswir1         .nwindows = 8,
1197c19148bdSblueswir1         .maxtl = 5,
119864a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1199c48fcb47Sblueswir1     },
1200c48fcb47Sblueswir1     {
1201c48fcb47Sblueswir1         .name = "Sun UltraSparc IIIi",
1202c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
1203c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1204fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12051a14026eSblueswir1         .nwindows = 8,
1206c19148bdSblueswir1         .maxtl = 5,
120764a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1208c48fcb47Sblueswir1     },
1209c48fcb47Sblueswir1     {
1210c48fcb47Sblueswir1         .name = "Sun UltraSparc IV",
1211c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
1212c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1213fb79ceb9Sblueswir1         .mmu_version = mmu_us_4,
12141a14026eSblueswir1         .nwindows = 8,
1215c19148bdSblueswir1         .maxtl = 5,
121664a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1217c48fcb47Sblueswir1     },
1218c48fcb47Sblueswir1     {
1219c48fcb47Sblueswir1         .name = "Sun UltraSparc IV+",
1220c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
1221c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1222fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12231a14026eSblueswir1         .nwindows = 8,
1224c19148bdSblueswir1         .maxtl = 5,
1225fb79ceb9Sblueswir1         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
1226c48fcb47Sblueswir1     },
1227c48fcb47Sblueswir1     {
1228c48fcb47Sblueswir1         .name = "Sun UltraSparc IIIi+",
1229c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
1230c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1231fb79ceb9Sblueswir1         .mmu_version = mmu_us_3,
12321a14026eSblueswir1         .nwindows = 8,
1233c19148bdSblueswir1         .maxtl = 5,
123464a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1235c48fcb47Sblueswir1     },
1236c48fcb47Sblueswir1     {
1237c7ba218dSblueswir1         .name = "Sun UltraSparc T1",
1238c7ba218dSblueswir1         // defined in sparc_ifu_fdp.v and ctu.h
1239c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
1240c7ba218dSblueswir1         .fpu_version = 0x00000000,
1241c7ba218dSblueswir1         .mmu_version = mmu_sun4v,
1242c7ba218dSblueswir1         .nwindows = 8,
1243c19148bdSblueswir1         .maxtl = 6,
1244c7ba218dSblueswir1         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
1245c7ba218dSblueswir1         | CPU_FEATURE_GL,
1246c7ba218dSblueswir1     },
1247c7ba218dSblueswir1     {
1248c7ba218dSblueswir1         .name = "Sun UltraSparc T2",
1249c7ba218dSblueswir1         // defined in tlu_asi_ctl.v and n2_revid_cust.v
1250c19148bdSblueswir1         .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
1251c7ba218dSblueswir1         .fpu_version = 0x00000000,
1252c7ba218dSblueswir1         .mmu_version = mmu_sun4v,
1253c7ba218dSblueswir1         .nwindows = 8,
1254c19148bdSblueswir1         .maxtl = 6,
1255c7ba218dSblueswir1         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
1256c7ba218dSblueswir1         | CPU_FEATURE_GL,
1257c7ba218dSblueswir1     },
1258c7ba218dSblueswir1     {
1259c48fcb47Sblueswir1         .name = "NEC UltraSparc I",
1260c19148bdSblueswir1         .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
1261c48fcb47Sblueswir1         .fpu_version = 0x00000000,
1262fb79ceb9Sblueswir1         .mmu_version = mmu_us_12,
12631a14026eSblueswir1         .nwindows = 8,
1264c19148bdSblueswir1         .maxtl = 5,
126564a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1266c48fcb47Sblueswir1     },
1267c48fcb47Sblueswir1 #else
1268c48fcb47Sblueswir1     {
1269c48fcb47Sblueswir1         .name = "Fujitsu MB86900",
1270c48fcb47Sblueswir1         .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
1271c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1272c48fcb47Sblueswir1         .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
1273c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1274c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1275c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1276c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1277c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
12781a14026eSblueswir1         .nwindows = 7,
1279e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
1280c48fcb47Sblueswir1     },
1281c48fcb47Sblueswir1     {
1282c48fcb47Sblueswir1         .name = "Fujitsu MB86904",
1283c48fcb47Sblueswir1         .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
1284c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1285c48fcb47Sblueswir1         .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
1286c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1287c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x00ffffc0,
1288c48fcb47Sblueswir1         .mmu_cxr_mask = 0x000000ff,
1289c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016fff,
1290c48fcb47Sblueswir1         .mmu_trcr_mask = 0x00ffffff,
12911a14026eSblueswir1         .nwindows = 8,
129264a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1293c48fcb47Sblueswir1     },
1294c48fcb47Sblueswir1     {
1295c48fcb47Sblueswir1         .name = "Fujitsu MB86907",
1296c48fcb47Sblueswir1         .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
1297c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1298c48fcb47Sblueswir1         .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
1299c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1300c48fcb47Sblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1301c48fcb47Sblueswir1         .mmu_cxr_mask = 0x000000ff,
1302c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016fff,
1303c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
13041a14026eSblueswir1         .nwindows = 8,
130564a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1306c48fcb47Sblueswir1     },
1307c48fcb47Sblueswir1     {
1308c48fcb47Sblueswir1         .name = "LSI L64811",
1309c48fcb47Sblueswir1         .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
1310c48fcb47Sblueswir1         .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
1311c48fcb47Sblueswir1         .mmu_version = 0x10 << 24,
1312c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1313c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1314c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1315c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1316c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
13171a14026eSblueswir1         .nwindows = 8,
1318e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1319e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1320c48fcb47Sblueswir1     },
1321c48fcb47Sblueswir1     {
1322c48fcb47Sblueswir1         .name = "Cypress CY7C601",
1323c48fcb47Sblueswir1         .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
1324c48fcb47Sblueswir1         .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
1325c48fcb47Sblueswir1         .mmu_version = 0x10 << 24,
1326c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1327c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1328c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1329c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1330c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
13311a14026eSblueswir1         .nwindows = 8,
1332e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1333e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1334c48fcb47Sblueswir1     },
1335c48fcb47Sblueswir1     {
1336c48fcb47Sblueswir1         .name = "Cypress CY7C611",
1337c48fcb47Sblueswir1         .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
1338c48fcb47Sblueswir1         .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
1339c48fcb47Sblueswir1         .mmu_version = 0x10 << 24,
1340c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1341c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1342c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1343c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1344c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
13451a14026eSblueswir1         .nwindows = 8,
1346e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1347e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1348c48fcb47Sblueswir1     },
1349c48fcb47Sblueswir1     {
1350c48fcb47Sblueswir1         .name = "TI MicroSparc I",
1351c48fcb47Sblueswir1         .iu_version = 0x41000000,
1352c48fcb47Sblueswir1         .fpu_version = 4 << 17,
1353c48fcb47Sblueswir1         .mmu_version = 0x41000000,
1354c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1355c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1356c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1357c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016fff,
1358c48fcb47Sblueswir1         .mmu_trcr_mask = 0x0000003f,
13591a14026eSblueswir1         .nwindows = 7,
1360e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
1361e30b4678Sblueswir1         CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
1362e30b4678Sblueswir1         CPU_FEATURE_FMUL,
1363c48fcb47Sblueswir1     },
1364c48fcb47Sblueswir1     {
1365c48fcb47Sblueswir1         .name = "TI MicroSparc II",
1366c48fcb47Sblueswir1         .iu_version = 0x42000000,
1367c48fcb47Sblueswir1         .fpu_version = 4 << 17,
1368c48fcb47Sblueswir1         .mmu_version = 0x02000000,
1369c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1370c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x00ffffc0,
1371c48fcb47Sblueswir1         .mmu_cxr_mask = 0x000000ff,
1372c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016fff,
1373c48fcb47Sblueswir1         .mmu_trcr_mask = 0x00ffffff,
13741a14026eSblueswir1         .nwindows = 8,
137564a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1376c48fcb47Sblueswir1     },
1377c48fcb47Sblueswir1     {
1378c48fcb47Sblueswir1         .name = "TI MicroSparc IIep",
1379c48fcb47Sblueswir1         .iu_version = 0x42000000,
1380c48fcb47Sblueswir1         .fpu_version = 4 << 17,
1381c48fcb47Sblueswir1         .mmu_version = 0x04000000,
1382c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1383c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x00ffffc0,
1384c48fcb47Sblueswir1         .mmu_cxr_mask = 0x000000ff,
1385c48fcb47Sblueswir1         .mmu_sfsr_mask = 0x00016bff,
1386c48fcb47Sblueswir1         .mmu_trcr_mask = 0x00ffffff,
13871a14026eSblueswir1         .nwindows = 8,
138864a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1389c48fcb47Sblueswir1     },
1390c48fcb47Sblueswir1     {
1391b5154bdeSblueswir1         .name = "TI SuperSparc 40", // STP1020NPGA
1392963262deSblueswir1         .iu_version = 0x41000000, // SuperSPARC 2.x
1393b5154bdeSblueswir1         .fpu_version = 0 << 17,
1394963262deSblueswir1         .mmu_version = 0x00000800, // SuperSPARC 2.x, no MXCC
1395b5154bdeSblueswir1         .mmu_bm = 0x00002000,
1396b5154bdeSblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1397b5154bdeSblueswir1         .mmu_cxr_mask = 0x0000ffff,
1398b5154bdeSblueswir1         .mmu_sfsr_mask = 0xffffffff,
1399b5154bdeSblueswir1         .mmu_trcr_mask = 0xffffffff,
14001a14026eSblueswir1         .nwindows = 8,
1401b5154bdeSblueswir1         .features = CPU_DEFAULT_FEATURES,
1402b5154bdeSblueswir1     },
1403b5154bdeSblueswir1     {
1404b5154bdeSblueswir1         .name = "TI SuperSparc 50", // STP1020PGA
1405963262deSblueswir1         .iu_version = 0x40000000, // SuperSPARC 3.x
1406b5154bdeSblueswir1         .fpu_version = 0 << 17,
1407963262deSblueswir1         .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
1408b5154bdeSblueswir1         .mmu_bm = 0x00002000,
1409b5154bdeSblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1410b5154bdeSblueswir1         .mmu_cxr_mask = 0x0000ffff,
1411b5154bdeSblueswir1         .mmu_sfsr_mask = 0xffffffff,
1412b5154bdeSblueswir1         .mmu_trcr_mask = 0xffffffff,
14131a14026eSblueswir1         .nwindows = 8,
1414b5154bdeSblueswir1         .features = CPU_DEFAULT_FEATURES,
1415b5154bdeSblueswir1     },
1416b5154bdeSblueswir1     {
1417c48fcb47Sblueswir1         .name = "TI SuperSparc 51",
1418963262deSblueswir1         .iu_version = 0x40000000, // SuperSPARC 3.x
1419c48fcb47Sblueswir1         .fpu_version = 0 << 17,
1420963262deSblueswir1         .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
1421c48fcb47Sblueswir1         .mmu_bm = 0x00002000,
1422c48fcb47Sblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1423c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000ffff,
1424c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1425c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
1426963262deSblueswir1         .mxcc_version = 0x00000104,
14271a14026eSblueswir1         .nwindows = 8,
142864a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1429c48fcb47Sblueswir1     },
1430c48fcb47Sblueswir1     {
1431b5154bdeSblueswir1         .name = "TI SuperSparc 60", // STP1020APGA
1432963262deSblueswir1         .iu_version = 0x40000000, // SuperSPARC 3.x
1433b5154bdeSblueswir1         .fpu_version = 0 << 17,
1434963262deSblueswir1         .mmu_version = 0x01000800, // SuperSPARC 3.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     {
1444c48fcb47Sblueswir1         .name = "TI SuperSparc 61",
1445963262deSblueswir1         .iu_version = 0x44000000, // SuperSPARC 3.x
1446c48fcb47Sblueswir1         .fpu_version = 0 << 17,
1447963262deSblueswir1         .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
1448c48fcb47Sblueswir1         .mmu_bm = 0x00002000,
1449c48fcb47Sblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1450c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000ffff,
1451c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1452c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
1453963262deSblueswir1         .mxcc_version = 0x00000104,
1454963262deSblueswir1         .nwindows = 8,
1455963262deSblueswir1         .features = CPU_DEFAULT_FEATURES,
1456963262deSblueswir1     },
1457963262deSblueswir1     {
1458963262deSblueswir1         .name = "TI SuperSparc II",
1459963262deSblueswir1         .iu_version = 0x40000000, // SuperSPARC II 1.x
1460963262deSblueswir1         .fpu_version = 0 << 17,
1461963262deSblueswir1         .mmu_version = 0x08000000, // SuperSPARC II 1.x, MXCC
1462963262deSblueswir1         .mmu_bm = 0x00002000,
1463963262deSblueswir1         .mmu_ctpr_mask = 0xffffffc0,
1464963262deSblueswir1         .mmu_cxr_mask = 0x0000ffff,
1465963262deSblueswir1         .mmu_sfsr_mask = 0xffffffff,
1466963262deSblueswir1         .mmu_trcr_mask = 0xffffffff,
1467963262deSblueswir1         .mxcc_version = 0x00000104,
14681a14026eSblueswir1         .nwindows = 8,
146964a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1470c48fcb47Sblueswir1     },
1471c48fcb47Sblueswir1     {
1472c48fcb47Sblueswir1         .name = "Ross RT625",
1473c48fcb47Sblueswir1         .iu_version = 0x1e000000,
1474c48fcb47Sblueswir1         .fpu_version = 1 << 17,
1475c48fcb47Sblueswir1         .mmu_version = 0x1e000000,
1476c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1477c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1478c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1479c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1480c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
14811a14026eSblueswir1         .nwindows = 8,
148264a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1483c48fcb47Sblueswir1     },
1484c48fcb47Sblueswir1     {
1485c48fcb47Sblueswir1         .name = "Ross RT620",
1486c48fcb47Sblueswir1         .iu_version = 0x1f000000,
1487c48fcb47Sblueswir1         .fpu_version = 1 << 17,
1488c48fcb47Sblueswir1         .mmu_version = 0x1f000000,
1489c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1490c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1491c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1492c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1493c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
14941a14026eSblueswir1         .nwindows = 8,
149564a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1496c48fcb47Sblueswir1     },
1497c48fcb47Sblueswir1     {
1498c48fcb47Sblueswir1         .name = "BIT B5010",
1499c48fcb47Sblueswir1         .iu_version = 0x20000000,
1500c48fcb47Sblueswir1         .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
1501c48fcb47Sblueswir1         .mmu_version = 0x20000000,
1502c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1503c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1504c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1505c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1506c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
15071a14026eSblueswir1         .nwindows = 8,
1508e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1509e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1510c48fcb47Sblueswir1     },
1511c48fcb47Sblueswir1     {
1512c48fcb47Sblueswir1         .name = "Matsushita MN10501",
1513c48fcb47Sblueswir1         .iu_version = 0x50000000,
1514c48fcb47Sblueswir1         .fpu_version = 0 << 17,
1515c48fcb47Sblueswir1         .mmu_version = 0x50000000,
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,
1522e30b4678Sblueswir1         .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
1523e30b4678Sblueswir1         CPU_FEATURE_FSMULD,
1524c48fcb47Sblueswir1     },
1525c48fcb47Sblueswir1     {
1526c48fcb47Sblueswir1         .name = "Weitek W8601",
1527c48fcb47Sblueswir1         .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
1528c48fcb47Sblueswir1         .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
1529c48fcb47Sblueswir1         .mmu_version = 0x10 << 24,
1530c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1531c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1532c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1533c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1534c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
15351a14026eSblueswir1         .nwindows = 8,
153664a88d5dSblueswir1         .features = CPU_DEFAULT_FEATURES,
1537c48fcb47Sblueswir1     },
1538c48fcb47Sblueswir1     {
1539c48fcb47Sblueswir1         .name = "LEON2",
1540c48fcb47Sblueswir1         .iu_version = 0xf2000000,
1541c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1542c48fcb47Sblueswir1         .mmu_version = 0xf2000000,
1543c48fcb47Sblueswir1         .mmu_bm = 0x00004000,
1544c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1545c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1546c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1547c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
15481a14026eSblueswir1         .nwindows = 8,
1549b04d9890SFabien Chouteau         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN,
1550c48fcb47Sblueswir1     },
1551c48fcb47Sblueswir1     {
1552c48fcb47Sblueswir1         .name = "LEON3",
1553c48fcb47Sblueswir1         .iu_version = 0xf3000000,
1554c48fcb47Sblueswir1         .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1555c48fcb47Sblueswir1         .mmu_version = 0xf3000000,
1556b04d9890SFabien Chouteau         .mmu_bm = 0x00000000,
1557c48fcb47Sblueswir1         .mmu_ctpr_mask = 0x007ffff0,
1558c48fcb47Sblueswir1         .mmu_cxr_mask = 0x0000003f,
1559c48fcb47Sblueswir1         .mmu_sfsr_mask = 0xffffffff,
1560c48fcb47Sblueswir1         .mmu_trcr_mask = 0xffffffff,
15611a14026eSblueswir1         .nwindows = 8,
15624a2ba232SFabien Chouteau         .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_TA0_SHUTDOWN |
156360f356e8SFabien Chouteau         CPU_FEATURE_ASR17 | CPU_FEATURE_CACHE_CTRL,
1564c48fcb47Sblueswir1     },
1565c48fcb47Sblueswir1 #endif
1566c48fcb47Sblueswir1 };
1567c48fcb47Sblueswir1 
156864a88d5dSblueswir1 static const char * const feature_name[] = {
156964a88d5dSblueswir1     "float",
157064a88d5dSblueswir1     "float128",
157164a88d5dSblueswir1     "swap",
157264a88d5dSblueswir1     "mul",
157364a88d5dSblueswir1     "div",
157464a88d5dSblueswir1     "flush",
157564a88d5dSblueswir1     "fsqrt",
157664a88d5dSblueswir1     "fmul",
157764a88d5dSblueswir1     "vis1",
157864a88d5dSblueswir1     "vis2",
1579e30b4678Sblueswir1     "fsmuld",
1580fb79ceb9Sblueswir1     "hypv",
1581fb79ceb9Sblueswir1     "cmt",
1582fb79ceb9Sblueswir1     "gl",
158364a88d5dSblueswir1 };
158464a88d5dSblueswir1 
15859a78eeadSStefan Weil static void print_features(FILE *f, fprintf_function cpu_fprintf,
158664a88d5dSblueswir1                            uint32_t features, const char *prefix)
1587c48fcb47Sblueswir1 {
1588c48fcb47Sblueswir1     unsigned int i;
1589c48fcb47Sblueswir1 
159064a88d5dSblueswir1     for (i = 0; i < ARRAY_SIZE(feature_name); i++)
159164a88d5dSblueswir1         if (feature_name[i] && (features & (1 << i))) {
159264a88d5dSblueswir1             if (prefix)
159364a88d5dSblueswir1                 (*cpu_fprintf)(f, "%s", prefix);
159464a88d5dSblueswir1             (*cpu_fprintf)(f, "%s ", feature_name[i]);
159564a88d5dSblueswir1         }
159664a88d5dSblueswir1 }
159764a88d5dSblueswir1 
159864a88d5dSblueswir1 static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
159964a88d5dSblueswir1 {
160064a88d5dSblueswir1     unsigned int i;
160164a88d5dSblueswir1 
160264a88d5dSblueswir1     for (i = 0; i < ARRAY_SIZE(feature_name); i++)
160364a88d5dSblueswir1         if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
160464a88d5dSblueswir1             *features |= 1 << i;
160564a88d5dSblueswir1             return;
160664a88d5dSblueswir1         }
160764a88d5dSblueswir1     fprintf(stderr, "CPU feature %s not found\n", flagname);
160864a88d5dSblueswir1 }
160964a88d5dSblueswir1 
161022548760Sblueswir1 static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
161164a88d5dSblueswir1 {
161264a88d5dSblueswir1     unsigned int i;
161364a88d5dSblueswir1     const sparc_def_t *def = NULL;
161464a88d5dSblueswir1     char *s = strdup(cpu_model);
161564a88d5dSblueswir1     char *featurestr, *name = strtok(s, ",");
161664a88d5dSblueswir1     uint32_t plus_features = 0;
161764a88d5dSblueswir1     uint32_t minus_features = 0;
16180bfcd599SBlue Swirl     uint64_t iu_version;
16191a14026eSblueswir1     uint32_t fpu_version, mmu_version, nwindows;
162064a88d5dSblueswir1 
1621b1503cdaSmalc     for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
1622c48fcb47Sblueswir1         if (strcasecmp(name, sparc_defs[i].name) == 0) {
162364a88d5dSblueswir1             def = &sparc_defs[i];
1624c48fcb47Sblueswir1         }
1625c48fcb47Sblueswir1     }
162664a88d5dSblueswir1     if (!def)
162764a88d5dSblueswir1         goto error;
162864a88d5dSblueswir1     memcpy(cpu_def, def, sizeof(*def));
162964a88d5dSblueswir1 
163064a88d5dSblueswir1     featurestr = strtok(NULL, ",");
163164a88d5dSblueswir1     while (featurestr) {
163264a88d5dSblueswir1         char *val;
163364a88d5dSblueswir1 
163464a88d5dSblueswir1         if (featurestr[0] == '+') {
163564a88d5dSblueswir1             add_flagname_to_bitmaps(featurestr + 1, &plus_features);
163664a88d5dSblueswir1         } else if (featurestr[0] == '-') {
163764a88d5dSblueswir1             add_flagname_to_bitmaps(featurestr + 1, &minus_features);
163864a88d5dSblueswir1         } else if ((val = strchr(featurestr, '='))) {
163964a88d5dSblueswir1             *val = 0; val++;
164064a88d5dSblueswir1             if (!strcmp(featurestr, "iu_version")) {
164164a88d5dSblueswir1                 char *err;
164264a88d5dSblueswir1 
164364a88d5dSblueswir1                 iu_version = strtoll(val, &err, 0);
164464a88d5dSblueswir1                 if (!*val || *err) {
164564a88d5dSblueswir1                     fprintf(stderr, "bad numerical value %s\n", val);
164664a88d5dSblueswir1                     goto error;
164764a88d5dSblueswir1                 }
164864a88d5dSblueswir1                 cpu_def->iu_version = iu_version;
164964a88d5dSblueswir1 #ifdef DEBUG_FEATURES
16500bfcd599SBlue Swirl                 fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
165164a88d5dSblueswir1 #endif
165264a88d5dSblueswir1             } else if (!strcmp(featurestr, "fpu_version")) {
165364a88d5dSblueswir1                 char *err;
165464a88d5dSblueswir1 
165564a88d5dSblueswir1                 fpu_version = strtol(val, &err, 0);
165664a88d5dSblueswir1                 if (!*val || *err) {
165764a88d5dSblueswir1                     fprintf(stderr, "bad numerical value %s\n", val);
165864a88d5dSblueswir1                     goto error;
165964a88d5dSblueswir1                 }
166064a88d5dSblueswir1                 cpu_def->fpu_version = fpu_version;
166164a88d5dSblueswir1 #ifdef DEBUG_FEATURES
16620bf9e31aSBlue Swirl                 fprintf(stderr, "fpu_version %x\n", fpu_version);
166364a88d5dSblueswir1 #endif
166464a88d5dSblueswir1             } else if (!strcmp(featurestr, "mmu_version")) {
166564a88d5dSblueswir1                 char *err;
166664a88d5dSblueswir1 
166764a88d5dSblueswir1                 mmu_version = strtol(val, &err, 0);
166864a88d5dSblueswir1                 if (!*val || *err) {
166964a88d5dSblueswir1                     fprintf(stderr, "bad numerical value %s\n", val);
167064a88d5dSblueswir1                     goto error;
167164a88d5dSblueswir1                 }
167264a88d5dSblueswir1                 cpu_def->mmu_version = mmu_version;
167364a88d5dSblueswir1 #ifdef DEBUG_FEATURES
16740bf9e31aSBlue Swirl                 fprintf(stderr, "mmu_version %x\n", mmu_version);
167564a88d5dSblueswir1 #endif
16761a14026eSblueswir1             } else if (!strcmp(featurestr, "nwindows")) {
16771a14026eSblueswir1                 char *err;
16781a14026eSblueswir1 
16791a14026eSblueswir1                 nwindows = strtol(val, &err, 0);
16801a14026eSblueswir1                 if (!*val || *err || nwindows > MAX_NWINDOWS ||
16811a14026eSblueswir1                     nwindows < MIN_NWINDOWS) {
16821a14026eSblueswir1                     fprintf(stderr, "bad numerical value %s\n", val);
16831a14026eSblueswir1                     goto error;
16841a14026eSblueswir1                 }
16851a14026eSblueswir1                 cpu_def->nwindows = nwindows;
16861a14026eSblueswir1 #ifdef DEBUG_FEATURES
16871a14026eSblueswir1                 fprintf(stderr, "nwindows %d\n", nwindows);
16881a14026eSblueswir1 #endif
168964a88d5dSblueswir1             } else {
169064a88d5dSblueswir1                 fprintf(stderr, "unrecognized feature %s\n", featurestr);
169164a88d5dSblueswir1                 goto error;
169264a88d5dSblueswir1             }
169364a88d5dSblueswir1         } else {
169477f193daSblueswir1             fprintf(stderr, "feature string `%s' not in format "
169577f193daSblueswir1                     "(+feature|-feature|feature=xyz)\n", featurestr);
169664a88d5dSblueswir1             goto error;
169764a88d5dSblueswir1         }
169864a88d5dSblueswir1         featurestr = strtok(NULL, ",");
169964a88d5dSblueswir1     }
170064a88d5dSblueswir1     cpu_def->features |= plus_features;
170164a88d5dSblueswir1     cpu_def->features &= ~minus_features;
170264a88d5dSblueswir1 #ifdef DEBUG_FEATURES
170364a88d5dSblueswir1     print_features(stderr, fprintf, cpu_def->features, NULL);
170464a88d5dSblueswir1 #endif
170564a88d5dSblueswir1     free(s);
170664a88d5dSblueswir1     return 0;
170764a88d5dSblueswir1 
170864a88d5dSblueswir1  error:
170964a88d5dSblueswir1     free(s);
171064a88d5dSblueswir1     return -1;
1711c48fcb47Sblueswir1 }
1712c48fcb47Sblueswir1 
17139a78eeadSStefan Weil void sparc_cpu_list(FILE *f, fprintf_function cpu_fprintf)
1714c48fcb47Sblueswir1 {
1715c48fcb47Sblueswir1     unsigned int i;
1716c48fcb47Sblueswir1 
1717b1503cdaSmalc     for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
17181a14026eSblueswir1         (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x NWINS %d ",
1719c48fcb47Sblueswir1                        sparc_defs[i].name,
1720c48fcb47Sblueswir1                        sparc_defs[i].iu_version,
1721c48fcb47Sblueswir1                        sparc_defs[i].fpu_version,
17221a14026eSblueswir1                        sparc_defs[i].mmu_version,
17231a14026eSblueswir1                        sparc_defs[i].nwindows);
172477f193daSblueswir1         print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
172577f193daSblueswir1                        ~sparc_defs[i].features, "-");
172677f193daSblueswir1         print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
172777f193daSblueswir1                        sparc_defs[i].features, "+");
172864a88d5dSblueswir1         (*cpu_fprintf)(f, "\n");
1729c48fcb47Sblueswir1     }
1730f76981b1Sblueswir1     (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
1731f76981b1Sblueswir1     print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
173264a88d5dSblueswir1     (*cpu_fprintf)(f, "\n");
1733f76981b1Sblueswir1     (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
1734f76981b1Sblueswir1     print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
1735f76981b1Sblueswir1     (*cpu_fprintf)(f, "\n");
1736f76981b1Sblueswir1     (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
1737f76981b1Sblueswir1                    "fpu_version mmu_version nwindows\n");
1738c48fcb47Sblueswir1 }
1739c48fcb47Sblueswir1 
17409a78eeadSStefan Weil static void cpu_print_cc(FILE *f, fprintf_function cpu_fprintf,
174143bb98bfSBlue Swirl                          uint32_t cc)
174243bb98bfSBlue Swirl {
174343bb98bfSBlue Swirl     cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG? 'N' : '-',
174443bb98bfSBlue Swirl                 cc & PSR_ZERO? 'Z' : '-', cc & PSR_OVF? 'V' : '-',
174543bb98bfSBlue Swirl                 cc & PSR_CARRY? 'C' : '-');
174643bb98bfSBlue Swirl }
174743bb98bfSBlue Swirl 
174843bb98bfSBlue Swirl #ifdef TARGET_SPARC64
174943bb98bfSBlue Swirl #define REGS_PER_LINE 4
175043bb98bfSBlue Swirl #else
175143bb98bfSBlue Swirl #define REGS_PER_LINE 8
175243bb98bfSBlue Swirl #endif
175343bb98bfSBlue Swirl 
17549a78eeadSStefan Weil void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
1755c48fcb47Sblueswir1                     int flags)
1756c48fcb47Sblueswir1 {
1757c48fcb47Sblueswir1     int i, x;
1758c48fcb47Sblueswir1 
175977f193daSblueswir1     cpu_fprintf(f, "pc: " TARGET_FMT_lx "  npc: " TARGET_FMT_lx "\n", env->pc,
176077f193daSblueswir1                 env->npc);
1761c48fcb47Sblueswir1     cpu_fprintf(f, "General Registers:\n");
176243bb98bfSBlue Swirl 
176343bb98bfSBlue Swirl     for (i = 0; i < 8; i++) {
176443bb98bfSBlue Swirl         if (i % REGS_PER_LINE == 0) {
176543bb98bfSBlue Swirl             cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
176643bb98bfSBlue Swirl         }
176743bb98bfSBlue Swirl         cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
176843bb98bfSBlue Swirl         if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
1769c48fcb47Sblueswir1             cpu_fprintf(f, "\n");
1770c48fcb47Sblueswir1         }
177143bb98bfSBlue Swirl     }
177243bb98bfSBlue Swirl     cpu_fprintf(f, "\nCurrent Register Window:\n");
177343bb98bfSBlue Swirl     for (x = 0; x < 3; x++) {
177443bb98bfSBlue Swirl         for (i = 0; i < 8; i++) {
177543bb98bfSBlue Swirl             if (i % REGS_PER_LINE == 0) {
177643bb98bfSBlue Swirl                 cpu_fprintf(f, "%%%c%d-%d: ",
177743bb98bfSBlue Swirl                             x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
177843bb98bfSBlue Swirl                             i, i + REGS_PER_LINE - 1);
177943bb98bfSBlue Swirl             }
178043bb98bfSBlue Swirl             cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
178143bb98bfSBlue Swirl             if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
178243bb98bfSBlue Swirl                 cpu_fprintf(f, "\n");
178343bb98bfSBlue Swirl             }
178443bb98bfSBlue Swirl         }
178543bb98bfSBlue Swirl     }
1786c48fcb47Sblueswir1     cpu_fprintf(f, "\nFloating Point Registers:\n");
178743bb98bfSBlue Swirl     for (i = 0; i < TARGET_FPREGS; i++) {
1788c48fcb47Sblueswir1         if ((i & 3) == 0)
1789c48fcb47Sblueswir1             cpu_fprintf(f, "%%f%02d:", i);
1790a37ee56cSblueswir1         cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
1791c48fcb47Sblueswir1         if ((i & 3) == 3)
1792c48fcb47Sblueswir1             cpu_fprintf(f, "\n");
1793c48fcb47Sblueswir1     }
1794c48fcb47Sblueswir1 #ifdef TARGET_SPARC64
179543bb98bfSBlue Swirl     cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
1796113c6106SStefan Weil                 (unsigned)cpu_get_ccr(env));
17975a834bb4SBlue Swirl     cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
179843bb98bfSBlue Swirl     cpu_fprintf(f, " xcc: ");
17995a834bb4SBlue Swirl     cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
180043bb98bfSBlue Swirl     cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
180143bb98bfSBlue Swirl                 env->psrpil);
180243bb98bfSBlue Swirl     cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
180343bb98bfSBlue Swirl                 "cleanwin: %d cwp: %d\n",
1804c48fcb47Sblueswir1                 env->cansave, env->canrestore, env->otherwin, env->wstate,
18051a14026eSblueswir1                 env->cleanwin, env->nwindows - 1 - env->cwp);
180643bb98bfSBlue Swirl     cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
180743bb98bfSBlue Swirl                 TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
1808c48fcb47Sblueswir1 #else
18095a834bb4SBlue Swirl     cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
18105a834bb4SBlue Swirl     cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
181143bb98bfSBlue Swirl     cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs? 'S' : '-',
181243bb98bfSBlue Swirl                 env->psrps? 'P' : '-', env->psret? 'E' : '-',
181343bb98bfSBlue Swirl                 env->wim);
181443bb98bfSBlue Swirl     cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
181543bb98bfSBlue Swirl                 env->fsr, env->y);
1816c48fcb47Sblueswir1 #endif
1817c48fcb47Sblueswir1 }
1818