]> git.proxmox.com Git - qemu.git/blame - target-sparc/helper.c
sparc64: generate data access exception on RW violation
[qemu.git] / target-sparc / helper.c
CommitLineData
e8af50a3
FB
1/*
2 * sparc helpers
5fafdf24 3 *
83469015 4 * Copyright (c) 2003-2005 Fabrice Bellard
e8af50a3
FB
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
8167ee88 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
e8af50a3 18 */
ee5bbe38
FB
19#include <stdarg.h>
20#include <stdlib.h>
21#include <stdio.h>
22#include <string.h>
23#include <inttypes.h>
24#include <signal.h>
ee5bbe38
FB
25
26#include "cpu.h"
27#include "exec-all.h"
ca10f867 28#include "qemu-common.h"
e8af50a3 29
e80cfcfc 30//#define DEBUG_MMU
64a88d5d 31//#define DEBUG_FEATURES
e8af50a3 32
b8e9fc06
IK
33#ifdef DEBUG_MMU
34#define DPRINTF_MMU(fmt, ...) \
35 do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0)
36#else
37#define DPRINTF_MMU(fmt, ...) do {} while (0)
38#endif
39
22548760 40static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model);
c48fcb47 41
e8af50a3 42/* Sparc MMU emulation */
e8af50a3 43
e8af50a3
FB
44/* thread support */
45
c227f099 46static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
e8af50a3
FB
47
48void cpu_lock(void)
49{
50 spin_lock(&global_cpu_lock);
51}
52
53void cpu_unlock(void)
54{
55 spin_unlock(&global_cpu_lock);
56}
57
5fafdf24 58#if defined(CONFIG_USER_ONLY)
9d893301 59
22548760 60int cpu_sparc_handle_mmu_fault(CPUState *env1, target_ulong address, int rw,
6ebbf390 61 int mmu_idx, int is_softmmu)
9d893301 62{
878d3096 63 if (rw & 2)
22548760 64 env1->exception_index = TT_TFAULT;
878d3096 65 else
22548760 66 env1->exception_index = TT_DFAULT;
9d893301
FB
67 return 1;
68}
69
70#else
e8af50a3 71
3475187d 72#ifndef TARGET_SPARC64
83469015
FB
73/*
74 * Sparc V8 Reference MMU (SRMMU)
75 */
e8af50a3 76static const int access_table[8][8] = {
a764a566
BS
77 { 0, 0, 0, 0, 8, 0, 12, 12 },
78 { 0, 0, 0, 0, 8, 0, 0, 0 },
79 { 8, 8, 0, 0, 0, 8, 12, 12 },
80 { 8, 8, 0, 0, 0, 8, 0, 0 },
81 { 8, 0, 8, 0, 8, 8, 12, 12 },
82 { 8, 0, 8, 0, 8, 0, 8, 0 },
83 { 8, 8, 8, 0, 8, 8, 12, 12 },
84 { 8, 8, 8, 0, 8, 8, 8, 0 }
e8af50a3
FB
85};
86
227671c9
FB
87static const int perm_table[2][8] = {
88 {
89 PAGE_READ,
90 PAGE_READ | PAGE_WRITE,
91 PAGE_READ | PAGE_EXEC,
92 PAGE_READ | PAGE_WRITE | PAGE_EXEC,
93 PAGE_EXEC,
94 PAGE_READ | PAGE_WRITE,
95 PAGE_READ | PAGE_EXEC,
96 PAGE_READ | PAGE_WRITE | PAGE_EXEC
97 },
98 {
99 PAGE_READ,
100 PAGE_READ | PAGE_WRITE,
101 PAGE_READ | PAGE_EXEC,
102 PAGE_READ | PAGE_WRITE | PAGE_EXEC,
103 PAGE_EXEC,
104 PAGE_READ,
105 0,
106 0,
107 }
e8af50a3
FB
108};
109
c227f099 110static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
c48fcb47 111 int *prot, int *access_index,
d4c430a8
PB
112 target_ulong address, int rw, int mmu_idx,
113 target_ulong *page_size)
e8af50a3 114{
e80cfcfc 115 int access_perms = 0;
c227f099 116 target_phys_addr_t pde_ptr;
af7bf89b 117 uint32_t pde;
6ebbf390 118 int error_code = 0, is_dirty, is_user;
e80cfcfc 119 unsigned long page_offset;
e8af50a3 120
6ebbf390 121 is_user = mmu_idx == MMU_USER_IDX;
40ce0a9a 122
e8af50a3 123 if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
d4c430a8 124 *page_size = TARGET_PAGE_SIZE;
40ce0a9a 125 // Boot mode: instruction fetches are taken from PROM
5578ceab 126 if (rw == 2 && (env->mmuregs[0] & env->def->mmu_bm)) {
58a770f3 127 *physical = env->prom_addr | (address & 0x7ffffULL);
40ce0a9a
BS
128 *prot = PAGE_READ | PAGE_EXEC;
129 return 0;
130 }
0f8a249a 131 *physical = address;
227671c9 132 *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
e80cfcfc 133 return 0;
e8af50a3
FB
134 }
135
7483750d 136 *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
5dcb6b91 137 *physical = 0xffffffffffff0000ULL;
7483750d 138
e8af50a3
FB
139 /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
140 /* Context base + context number */
3deaeab7 141 pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
49be8030 142 pde = ldl_phys(pde_ptr);
e8af50a3
FB
143
144 /* Ctx pde */
145 switch (pde & PTE_ENTRYTYPE_MASK) {
e80cfcfc 146 default:
e8af50a3 147 case 0: /* Invalid */
0f8a249a 148 return 1 << 2;
e80cfcfc 149 case 2: /* L0 PTE, maybe should not happen? */
e8af50a3 150 case 3: /* Reserved */
7483750d 151 return 4 << 2;
e80cfcfc 152 case 1: /* L0 PDE */
0f8a249a 153 pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
49be8030 154 pde = ldl_phys(pde_ptr);
e8af50a3 155
0f8a249a
BS
156 switch (pde & PTE_ENTRYTYPE_MASK) {
157 default:
158 case 0: /* Invalid */
159 return (1 << 8) | (1 << 2);
160 case 3: /* Reserved */
161 return (1 << 8) | (4 << 2);
162 case 1: /* L1 PDE */
163 pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
49be8030 164 pde = ldl_phys(pde_ptr);
e8af50a3 165
0f8a249a
BS
166 switch (pde & PTE_ENTRYTYPE_MASK) {
167 default:
168 case 0: /* Invalid */
169 return (2 << 8) | (1 << 2);
170 case 3: /* Reserved */
171 return (2 << 8) | (4 << 2);
172 case 1: /* L2 PDE */
173 pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
49be8030 174 pde = ldl_phys(pde_ptr);
e8af50a3 175
0f8a249a
BS
176 switch (pde & PTE_ENTRYTYPE_MASK) {
177 default:
178 case 0: /* Invalid */
179 return (3 << 8) | (1 << 2);
180 case 1: /* PDE, should not happen */
181 case 3: /* Reserved */
182 return (3 << 8) | (4 << 2);
183 case 2: /* L3 PTE */
77f193da
BS
184 page_offset = (address & TARGET_PAGE_MASK) &
185 (TARGET_PAGE_SIZE - 1);
0f8a249a 186 }
d4c430a8 187 *page_size = TARGET_PAGE_SIZE;
0f8a249a
BS
188 break;
189 case 2: /* L2 PTE */
0f8a249a 190 page_offset = address & 0x3ffff;
d4c430a8 191 *page_size = 0x40000;
0f8a249a
BS
192 }
193 break;
194 case 2: /* L1 PTE */
0f8a249a 195 page_offset = address & 0xffffff;
d4c430a8 196 *page_size = 0x1000000;
0f8a249a 197 }
e8af50a3
FB
198 }
199
698235aa
AT
200 /* check access */
201 access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
202 error_code = access_table[*access_index][access_perms];
203 if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user))
204 return error_code;
205
e8af50a3 206 /* update page modified and dirty bits */
b769d8fe 207 is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
e8af50a3 208 if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
0f8a249a
BS
209 pde |= PG_ACCESSED_MASK;
210 if (is_dirty)
211 pde |= PG_MODIFIED_MASK;
49be8030 212 stl_phys_notdirty(pde_ptr, pde);
e8af50a3 213 }
e8af50a3
FB
214
215 /* the page can be put in the TLB */
227671c9
FB
216 *prot = perm_table[is_user][access_perms];
217 if (!(pde & PG_MODIFIED_MASK)) {
e8af50a3
FB
218 /* only set write access if already dirty... otherwise wait
219 for dirty access */
227671c9 220 *prot &= ~PAGE_WRITE;
e8af50a3
FB
221 }
222
223 /* Even if large ptes, we map only one 4KB page in the cache to
224 avoid filling it too fast */
c227f099 225 *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
6f7e9aec 226 return error_code;
e80cfcfc
FB
227}
228
229/* Perform address translation */
af7bf89b 230int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
6ebbf390 231 int mmu_idx, int is_softmmu)
e80cfcfc 232{
c227f099 233 target_phys_addr_t paddr;
5dcb6b91 234 target_ulong vaddr;
d4c430a8
PB
235 target_ulong page_size;
236 int error_code = 0, prot, access_index;
e8af50a3 237
77f193da 238 error_code = get_physical_address(env, &paddr, &prot, &access_index,
d4c430a8 239 address, rw, mmu_idx, &page_size);
e80cfcfc 240 if (error_code == 0) {
0f8a249a
BS
241 vaddr = address & TARGET_PAGE_MASK;
242 paddr &= TARGET_PAGE_MASK;
9e61bde5 243#ifdef DEBUG_MMU
0f8a249a 244 printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
5dcb6b91 245 TARGET_FMT_lx "\n", address, paddr, vaddr);
9e61bde5 246#endif
d4c430a8
PB
247 tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
248 return 0;
e80cfcfc 249 }
e8af50a3 250
e8af50a3 251 if (env->mmuregs[3]) /* Fault status register */
0f8a249a 252 env->mmuregs[3] = 1; /* overflow (not read before another fault) */
7483750d 253 env->mmuregs[3] |= (access_index << 5) | error_code | 2;
e8af50a3
FB
254 env->mmuregs[4] = address; /* Fault address register */
255
878d3096 256 if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) {
6f7e9aec
FB
257 // No fault mode: if a mapping is available, just override
258 // permissions. If no mapping is available, redirect accesses to
259 // neverland. Fake/overridden mappings will be flushed when
260 // switching to normal mode.
0f8a249a 261 vaddr = address & TARGET_PAGE_MASK;
227671c9 262 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
d4c430a8
PB
263 tlb_set_page(env, vaddr, paddr, prot, mmu_idx, TARGET_PAGE_SIZE);
264 return 0;
7483750d
FB
265 } else {
266 if (rw & 2)
267 env->exception_index = TT_TFAULT;
268 else
269 env->exception_index = TT_DFAULT;
270 return 1;
878d3096 271 }
e8af50a3 272}
24741ef3
FB
273
274target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
275{
c227f099 276 target_phys_addr_t pde_ptr;
24741ef3
FB
277 uint32_t pde;
278
279 /* Context base + context number */
c227f099 280 pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
5dcb6b91 281 (env->mmuregs[2] << 2);
24741ef3
FB
282 pde = ldl_phys(pde_ptr);
283
284 switch (pde & PTE_ENTRYTYPE_MASK) {
285 default:
286 case 0: /* Invalid */
287 case 2: /* PTE, maybe should not happen? */
288 case 3: /* Reserved */
0f8a249a 289 return 0;
24741ef3 290 case 1: /* L1 PDE */
0f8a249a
BS
291 if (mmulev == 3)
292 return pde;
293 pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
24741ef3
FB
294 pde = ldl_phys(pde_ptr);
295
0f8a249a
BS
296 switch (pde & PTE_ENTRYTYPE_MASK) {
297 default:
298 case 0: /* Invalid */
299 case 3: /* Reserved */
300 return 0;
301 case 2: /* L1 PTE */
302 return pde;
303 case 1: /* L2 PDE */
304 if (mmulev == 2)
305 return pde;
306 pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
24741ef3
FB
307 pde = ldl_phys(pde_ptr);
308
0f8a249a
BS
309 switch (pde & PTE_ENTRYTYPE_MASK) {
310 default:
311 case 0: /* Invalid */
312 case 3: /* Reserved */
313 return 0;
314 case 2: /* L2 PTE */
315 return pde;
316 case 1: /* L3 PDE */
317 if (mmulev == 1)
318 return pde;
319 pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
24741ef3
FB
320 pde = ldl_phys(pde_ptr);
321
0f8a249a
BS
322 switch (pde & PTE_ENTRYTYPE_MASK) {
323 default:
324 case 0: /* Invalid */
325 case 1: /* PDE, should not happen */
326 case 3: /* Reserved */
327 return 0;
328 case 2: /* L3 PTE */
329 return pde;
330 }
331 }
332 }
24741ef3
FB
333 }
334 return 0;
335}
336
337#ifdef DEBUG_MMU
338void dump_mmu(CPUState *env)
339{
5dcb6b91
BS
340 target_ulong va, va1, va2;
341 unsigned int n, m, o;
c227f099 342 target_phys_addr_t pde_ptr, pa;
24741ef3
FB
343 uint32_t pde;
344
345 printf("MMU dump:\n");
346 pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
347 pde = ldl_phys(pde_ptr);
5dcb6b91 348 printf("Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
c227f099 349 (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
24741ef3 350 for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
0f8a249a
BS
351 pde = mmu_probe(env, va, 2);
352 if (pde) {
353 pa = cpu_get_phys_page_debug(env, va);
354 printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
5dcb6b91 355 " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
0f8a249a
BS
356 for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
357 pde = mmu_probe(env, va1, 1);
358 if (pde) {
359 pa = cpu_get_phys_page_debug(env, va1);
360 printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
5dcb6b91 361 " PDE: " TARGET_FMT_lx "\n", va1, pa, pde);
0f8a249a
BS
362 for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
363 pde = mmu_probe(env, va2, 0);
364 if (pde) {
365 pa = cpu_get_phys_page_debug(env, va2);
366 printf(" VA: " TARGET_FMT_lx ", PA: "
5dcb6b91
BS
367 TARGET_FMT_plx " PTE: " TARGET_FMT_lx "\n",
368 va2, pa, pde);
0f8a249a
BS
369 }
370 }
371 }
372 }
373 }
24741ef3
FB
374 }
375 printf("MMU dump ends\n");
376}
377#endif /* DEBUG_MMU */
378
379#else /* !TARGET_SPARC64 */
e8807b14
IK
380
381// 41 bit physical address space
c227f099 382static inline target_phys_addr_t ultrasparc_truncate_physical(uint64_t x)
e8807b14
IK
383{
384 return x & 0x1ffffffffffULL;
385}
386
83469015
FB
387/*
388 * UltraSparc IIi I/DMMUs
389 */
536ba015 390
536ba015
IK
391// Returns true if TTE tag is valid and matches virtual address value in context
392// requires virtual address mask value calculated from TTE entry size
6e8e7d4c 393static inline int ultrasparc_tag_match(SparcTLBEntry *tlb,
536ba015 394 uint64_t address, uint64_t context,
299b520c 395 target_phys_addr_t *physical)
536ba015
IK
396{
397 uint64_t mask;
398
6e8e7d4c 399 switch ((tlb->tte >> 61) & 3) {
536ba015
IK
400 default:
401 case 0x0: // 8k
402 mask = 0xffffffffffffe000ULL;
403 break;
404 case 0x1: // 64k
405 mask = 0xffffffffffff0000ULL;
406 break;
407 case 0x2: // 512k
408 mask = 0xfffffffffff80000ULL;
409 break;
410 case 0x3: // 4M
411 mask = 0xffffffffffc00000ULL;
412 break;
413 }
414
415 // valid, context match, virtual address match?
f707726e 416 if (TTE_IS_VALID(tlb->tte) &&
299b520c 417 (TTE_IS_GLOBAL(tlb->tte) || tlb_compare_context(tlb, context))
2a90358f 418 && compare_masked(address, tlb->tag, mask))
536ba015
IK
419 {
420 // decode physical address
6e8e7d4c 421 *physical = ((tlb->tte & mask) | (address & ~mask)) & 0x1ffffffe000ULL;
536ba015
IK
422 return 1;
423 }
424
425 return 0;
426}
427
77f193da 428static int get_physical_address_data(CPUState *env,
c227f099 429 target_phys_addr_t *physical, int *prot,
2065061e 430 target_ulong address, int rw, int mmu_idx)
3475187d 431{
3475187d 432 unsigned int i;
536ba015 433 uint64_t context;
3475187d 434
2065061e
IK
435 int is_user = (mmu_idx == MMU_USER_IDX ||
436 mmu_idx == MMU_USER_SECONDARY_IDX);
437
3475187d 438 if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
e8807b14 439 *physical = ultrasparc_truncate_physical(address);
0f8a249a 440 *prot = PAGE_READ | PAGE_WRITE;
3475187d
FB
441 return 0;
442 }
443
2065061e
IK
444 switch(mmu_idx) {
445 case MMU_USER_IDX:
446 case MMU_KERNEL_IDX:
299b520c 447 context = env->dmmu.mmu_primary_context & 0x1fff;
2065061e
IK
448 break;
449 case MMU_USER_SECONDARY_IDX:
450 case MMU_KERNEL_SECONDARY_IDX:
451 context = env->dmmu.mmu_secondary_context & 0x1fff;
452 break;
453 case MMU_NUCLEUS_IDX:
44505216 454 default:
299b520c 455 context = 0;
2065061e 456 break;
299b520c 457 }
536ba015 458
3475187d 459 for (i = 0; i < 64; i++) {
afdf8109 460 // ctx match, vaddr match, valid?
b8e9fc06
IK
461 if (ultrasparc_tag_match(&env->dtlb[i], address, context, physical)) {
462
463 uint8_t fault_type = 0;
464
afdf8109 465 // access ok?
b8e9fc06
IK
466 if ((env->dtlb[i].tte & 0x4) && is_user) {
467 fault_type |= 1; /* privilege violation */
468 env->exception_index = TT_DFAULT;
6e8e7d4c 469
b8e9fc06
IK
470 DPRINTF_MMU("DFAULT at %" PRIx64 " context %" PRIx64
471 " mmu_idx=%d tl=%d\n",
472 address, context, mmu_idx, env->tl);
473 } else if (!(env->dtlb[i].tte & 0x2) && (rw == 1)) {
474 env->exception_index = TT_DPROT;
6e8e7d4c 475
b8e9fc06
IK
476 DPRINTF_MMU("DPROT at %" PRIx64 " context %" PRIx64
477 " mmu_idx=%d tl=%d\n",
478 address, context, mmu_idx, env->tl);
479 } else {
480 *prot = PAGE_READ;
481 if (env->dtlb[i].tte & 0x2)
482 *prot |= PAGE_WRITE;
483
484 TTE_SET_USED(env->dtlb[i].tte);
485
486 return 0;
487 }
488
489 if (env->dmmu.sfsr & 1) /* Fault status register */
490 env->dmmu.sfsr = 2; /* overflow (not read before
77f193da 491 another fault) */
6e8e7d4c 492
b8e9fc06 493 env->dmmu.sfsr |= (is_user << 3) | ((rw == 1) << 2) | 1;
6e8e7d4c 494
b8e9fc06 495 env->dmmu.sfsr |= (fault_type << 7);
6e8e7d4c 496
b8e9fc06
IK
497 env->dmmu.sfar = address; /* Fault address register */
498 return 1;
0f8a249a 499 }
3475187d 500 }
b8e9fc06
IK
501
502 DPRINTF_MMU("DMISS at %" PRIx64 " context %" PRIx64 "\n",
503 address, context);
504
6e8e7d4c 505 env->dmmu.tag_access = (address & ~0x1fffULL) | context;
83469015 506 env->exception_index = TT_DMISS;
3475187d
FB
507 return 1;
508}
509
77f193da 510static int get_physical_address_code(CPUState *env,
c227f099 511 target_phys_addr_t *physical, int *prot,
2065061e 512 target_ulong address, int mmu_idx)
3475187d 513{
3475187d 514 unsigned int i;
536ba015 515 uint64_t context;
3475187d 516
2065061e
IK
517 int is_user = (mmu_idx == MMU_USER_IDX ||
518 mmu_idx == MMU_USER_SECONDARY_IDX);
519
e8807b14
IK
520 if ((env->lsu & IMMU_E) == 0 || (env->pstate & PS_RED) != 0) {
521 /* IMMU disabled */
522 *physical = ultrasparc_truncate_physical(address);
0f8a249a 523 *prot = PAGE_EXEC;
3475187d
FB
524 return 0;
525 }
83469015 526
299b520c 527 if (env->tl == 0) {
2065061e 528 /* PRIMARY context */
299b520c
IK
529 context = env->dmmu.mmu_primary_context & 0x1fff;
530 } else {
2065061e 531 /* NUCLEUS context */
299b520c
IK
532 context = 0;
533 }
536ba015 534
3475187d 535 for (i = 0; i < 64; i++) {
afdf8109 536 // ctx match, vaddr match, valid?
6e8e7d4c 537 if (ultrasparc_tag_match(&env->itlb[i],
299b520c 538 address, context, physical)) {
afdf8109 539 // access ok?
6e8e7d4c
IK
540 if ((env->itlb[i].tte & 0x4) && is_user) {
541 if (env->immu.sfsr) /* Fault status register */
542 env->immu.sfsr = 2; /* overflow (not read before
77f193da 543 another fault) */
6e8e7d4c 544 env->immu.sfsr |= (is_user << 3) | 1;
0f8a249a 545 env->exception_index = TT_TFAULT;
b8e9fc06
IK
546
547 DPRINTF_MMU("TFAULT at %" PRIx64 " context %" PRIx64 "\n",
548 address, context);
549
0f8a249a
BS
550 return 1;
551 }
0f8a249a 552 *prot = PAGE_EXEC;
f707726e 553 TTE_SET_USED(env->itlb[i].tte);
0f8a249a
BS
554 return 0;
555 }
3475187d 556 }
b8e9fc06
IK
557
558 DPRINTF_MMU("TMISS at %" PRIx64 " context %" PRIx64 "\n",
559 address, context);
560
7ab463cb 561 /* Context is stored in DMMU (dmmuregs[1]) also for IMMU */
6e8e7d4c 562 env->immu.tag_access = (address & ~0x1fffULL) | context;
83469015 563 env->exception_index = TT_TMISS;
3475187d
FB
564 return 1;
565}
566
c227f099 567static int get_physical_address(CPUState *env, target_phys_addr_t *physical,
c48fcb47 568 int *prot, int *access_index,
d4c430a8
PB
569 target_ulong address, int rw, int mmu_idx,
570 target_ulong *page_size)
3475187d 571{
d4c430a8
PB
572 /* ??? We treat everything as a small page, then explicitly flush
573 everything when an entry is evicted. */
574 *page_size = TARGET_PAGE_SIZE;
3475187d 575 if (rw == 2)
22548760 576 return get_physical_address_code(env, physical, prot, address,
2065061e 577 mmu_idx);
3475187d 578 else
22548760 579 return get_physical_address_data(env, physical, prot, address, rw,
2065061e 580 mmu_idx);
3475187d
FB
581}
582
583/* Perform address translation */
584int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
6ebbf390 585 int mmu_idx, int is_softmmu)
3475187d 586{
83469015 587 target_ulong virt_addr, vaddr;
c227f099 588 target_phys_addr_t paddr;
d4c430a8
PB
589 target_ulong page_size;
590 int error_code = 0, prot, access_index;
3475187d 591
77f193da 592 error_code = get_physical_address(env, &paddr, &prot, &access_index,
d4c430a8 593 address, rw, mmu_idx, &page_size);
3475187d 594 if (error_code == 0) {
0f8a249a 595 virt_addr = address & TARGET_PAGE_MASK;
77f193da
BS
596 vaddr = virt_addr + ((address & TARGET_PAGE_MASK) &
597 (TARGET_PAGE_SIZE - 1));
b8e9fc06
IK
598
599 DPRINTF_MMU("Translate at %" PRIx64 " -> %" PRIx64 ","
600 " vaddr %" PRIx64
601 " mmu_idx=%d"
602 " tl=%d"
603 " primary context=%" PRIx64
604 " secondary context=%" PRIx64
605 "\n",
606 address, paddr, vaddr, mmu_idx, env->tl,
607 env->dmmu.mmu_primary_context,
608 env->dmmu.mmu_secondary_context);
609
d4c430a8
PB
610 tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
611 return 0;
3475187d
FB
612 }
613 // XXX
614 return 1;
615}
616
83469015
FB
617#ifdef DEBUG_MMU
618void dump_mmu(CPUState *env)
619{
620 unsigned int i;
621 const char *mask;
622
77f193da 623 printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" PRId64 "\n",
6e8e7d4c 624 env->dmmu.mmu_primary_context, env->dmmu.mmu_secondary_context);
83469015 625 if ((env->lsu & DMMU_E) == 0) {
0f8a249a 626 printf("DMMU disabled\n");
83469015 627 } else {
0f8a249a
BS
628 printf("DMMU dump:\n");
629 for (i = 0; i < 64; i++) {
31a68d57 630 switch ((env->dtlb[i].tte >> 61) & 3) {
0f8a249a
BS
631 default:
632 case 0x0:
633 mask = " 8k";
634 break;
635 case 0x1:
636 mask = " 64k";
637 break;
638 case 0x2:
639 mask = "512k";
640 break;
641 case 0x3:
642 mask = " 4M";
643 break;
644 }
31a68d57
BS
645 if ((env->dtlb[i].tte & 0x8000000000000000ULL) != 0) {
646 printf("[%02u] VA: %" PRIx64 ", PA: %" PRIx64
2a90358f 647 ", %s, %s, %s, %s, ctx %" PRId64 " %s\n",
6e8e7d4c 648 i,
31a68d57
BS
649 env->dtlb[i].tag & (uint64_t)~0x1fffULL,
650 env->dtlb[i].tte & (uint64_t)0x1ffffffe000ULL,
0f8a249a 651 mask,
31a68d57
BS
652 env->dtlb[i].tte & 0x4? "priv": "user",
653 env->dtlb[i].tte & 0x2? "RW": "RO",
654 env->dtlb[i].tte & 0x40? "locked": "unlocked",
2a90358f
BS
655 env->dtlb[i].tag & (uint64_t)0x1fffULL,
656 TTE_IS_GLOBAL(env->dtlb[i].tag)? "global" : "local");
0f8a249a
BS
657 }
658 }
83469015
FB
659 }
660 if ((env->lsu & IMMU_E) == 0) {
0f8a249a 661 printf("IMMU disabled\n");
83469015 662 } else {
0f8a249a
BS
663 printf("IMMU dump:\n");
664 for (i = 0; i < 64; i++) {
31a68d57 665 switch ((env->itlb[i].tte >> 61) & 3) {
0f8a249a
BS
666 default:
667 case 0x0:
668 mask = " 8k";
669 break;
670 case 0x1:
671 mask = " 64k";
672 break;
673 case 0x2:
674 mask = "512k";
675 break;
676 case 0x3:
677 mask = " 4M";
678 break;
679 }
31a68d57
BS
680 if ((env->itlb[i].tte & 0x8000000000000000ULL) != 0) {
681 printf("[%02u] VA: %" PRIx64 ", PA: %" PRIx64
2a90358f 682 ", %s, %s, %s, ctx %" PRId64 " %s\n",
6e8e7d4c
IK
683 i,
684 env->itlb[i].tag & (uint64_t)~0x1fffULL,
31a68d57 685 env->itlb[i].tte & (uint64_t)0x1ffffffe000ULL,
0f8a249a 686 mask,
31a68d57
BS
687 env->itlb[i].tte & 0x4? "priv": "user",
688 env->itlb[i].tte & 0x40? "locked": "unlocked",
2a90358f
BS
689 env->itlb[i].tag & (uint64_t)0x1fffULL,
690 TTE_IS_GLOBAL(env->itlb[i].tag)? "global" : "local");
0f8a249a
BS
691 }
692 }
83469015
FB
693 }
694}
24741ef3
FB
695#endif /* DEBUG_MMU */
696
697#endif /* TARGET_SPARC64 */
698#endif /* !CONFIG_USER_ONLY */
699
c48fcb47 700
4fcc562b 701#if !defined(CONFIG_USER_ONLY)
2065061e
IK
702target_phys_addr_t cpu_get_phys_page_nofault(CPUState *env, target_ulong addr,
703 int mmu_idx)
c48fcb47 704{
c227f099 705 target_phys_addr_t phys_addr;
d4c430a8 706 target_ulong page_size;
c48fcb47
BS
707 int prot, access_index;
708
709 if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2,
2065061e 710 mmu_idx, &page_size) != 0)
c48fcb47 711 if (get_physical_address(env, &phys_addr, &prot, &access_index, addr,
2065061e 712 0, mmu_idx, &page_size) != 0)
c48fcb47
BS
713 return -1;
714 if (cpu_get_physical_page_desc(phys_addr) == IO_MEM_UNASSIGNED)
715 return -1;
716 return phys_addr;
717}
2065061e
IK
718
719target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
720{
721 return cpu_get_phys_page_nofault(env, addr, MMU_KERNEL_IDX);
722}
c48fcb47
BS
723#endif
724
c48fcb47
BS
725void cpu_reset(CPUSPARCState *env)
726{
eca1bdf4
AL
727 if (qemu_loglevel_mask(CPU_LOG_RESET)) {
728 qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
729 log_cpu_state(env, 0);
730 }
731
c48fcb47
BS
732 tlb_flush(env, 1);
733 env->cwp = 0;
5210977a 734#ifndef TARGET_SPARC64
c48fcb47 735 env->wim = 1;
5210977a 736#endif
c48fcb47 737 env->regwptr = env->regbase + (env->cwp * 16);
6b743278 738 CC_OP = CC_OP_FLAGS;
c48fcb47 739#if defined(CONFIG_USER_ONLY)
c48fcb47 740#ifdef TARGET_SPARC64
1a14026e
BS
741 env->cleanwin = env->nwindows - 2;
742 env->cansave = env->nwindows - 2;
c48fcb47
BS
743 env->pstate = PS_RMO | PS_PEF | PS_IE;
744 env->asi = 0x82; // Primary no-fault
745#endif
746#else
5210977a 747#if !defined(TARGET_SPARC64)
c48fcb47 748 env->psret = 0;
5210977a 749#endif
c48fcb47
BS
750 env->psrs = 1;
751 env->psrps = 1;
752#ifdef TARGET_SPARC64
8194f35a 753 env->pstate = PS_PRIV|PS_RED|PS_PEF|PS_AG;
c48fcb47 754 env->hpstate = HS_PRIV;
8194f35a
IK
755 env->tl = env->maxtl;
756 cpu_tsptr(env)->tt = TT_POWER_ON_RESET;
415fc906 757 env->lsu = 0;
c48fcb47 758#else
c48fcb47 759 env->mmuregs[0] &= ~(MMU_E | MMU_NF);
5578ceab 760 env->mmuregs[0] |= env->def->mmu_bm;
c48fcb47 761#endif
e87231d4 762 env->pc = 0;
c48fcb47
BS
763 env->npc = env->pc + 4;
764#endif
765}
766
64a88d5d 767static int cpu_sparc_register(CPUSPARCState *env, const char *cpu_model)
c48fcb47 768{
64a88d5d 769 sparc_def_t def1, *def = &def1;
c48fcb47 770
64a88d5d
BS
771 if (cpu_sparc_find_by_name(def, cpu_model) < 0)
772 return -1;
c48fcb47 773
5578ceab
BS
774 env->def = qemu_mallocz(sizeof(*def));
775 memcpy(env->def, def, sizeof(*def));
776#if defined(CONFIG_USER_ONLY)
777 if ((env->def->features & CPU_FEATURE_FLOAT))
778 env->def->features |= CPU_FEATURE_FLOAT128;
779#endif
c48fcb47
BS
780 env->cpu_model_str = cpu_model;
781 env->version = def->iu_version;
782 env->fsr = def->fpu_version;
1a14026e 783 env->nwindows = def->nwindows;
c48fcb47 784#if !defined(TARGET_SPARC64)
c48fcb47
BS
785 env->mmuregs[0] |= def->mmu_version;
786 cpu_sparc_set_id(env, 0);
963262de 787 env->mxccregs[7] |= def->mxcc_version;
1a14026e 788#else
fb79ceb9 789 env->mmu_version = def->mmu_version;
c19148bd
BS
790 env->maxtl = def->maxtl;
791 env->version |= def->maxtl << 8;
1a14026e 792 env->version |= def->nwindows - 1;
c48fcb47 793#endif
64a88d5d
BS
794 return 0;
795}
796
797static void cpu_sparc_close(CPUSPARCState *env)
798{
5578ceab 799 free(env->def);
64a88d5d
BS
800 free(env);
801}
802
803CPUSPARCState *cpu_sparc_init(const char *cpu_model)
804{
805 CPUSPARCState *env;
806
807 env = qemu_mallocz(sizeof(CPUSPARCState));
64a88d5d 808 cpu_exec_init(env);
c48fcb47
BS
809
810 gen_intermediate_code_init(env);
811
64a88d5d
BS
812 if (cpu_sparc_register(env, cpu_model) < 0) {
813 cpu_sparc_close(env);
814 return NULL;
815 }
0bf46a40 816 qemu_init_vcpu(env);
c48fcb47
BS
817
818 return env;
819}
820
821void cpu_sparc_set_id(CPUSPARCState *env, unsigned int cpu)
822{
823#if !defined(TARGET_SPARC64)
824 env->mxccregs[7] = ((cpu + 8) & 0xf) << 24;
825#endif
826}
827
828static const sparc_def_t sparc_defs[] = {
829#ifdef TARGET_SPARC64
830 {
831 .name = "Fujitsu Sparc64",
c19148bd 832 .iu_version = ((0x04ULL << 48) | (0x02ULL << 32) | (0ULL << 24)),
c48fcb47 833 .fpu_version = 0x00000000,
fb79ceb9 834 .mmu_version = mmu_us_12,
1a14026e 835 .nwindows = 4,
c19148bd 836 .maxtl = 4,
64a88d5d 837 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
838 },
839 {
840 .name = "Fujitsu Sparc64 III",
c19148bd 841 .iu_version = ((0x04ULL << 48) | (0x03ULL << 32) | (0ULL << 24)),
c48fcb47 842 .fpu_version = 0x00000000,
fb79ceb9 843 .mmu_version = mmu_us_12,
1a14026e 844 .nwindows = 5,
c19148bd 845 .maxtl = 4,
64a88d5d 846 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
847 },
848 {
849 .name = "Fujitsu Sparc64 IV",
c19148bd 850 .iu_version = ((0x04ULL << 48) | (0x04ULL << 32) | (0ULL << 24)),
c48fcb47 851 .fpu_version = 0x00000000,
fb79ceb9 852 .mmu_version = mmu_us_12,
1a14026e 853 .nwindows = 8,
c19148bd 854 .maxtl = 5,
64a88d5d 855 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
856 },
857 {
858 .name = "Fujitsu Sparc64 V",
c19148bd 859 .iu_version = ((0x04ULL << 48) | (0x05ULL << 32) | (0x51ULL << 24)),
c48fcb47 860 .fpu_version = 0x00000000,
fb79ceb9 861 .mmu_version = mmu_us_12,
1a14026e 862 .nwindows = 8,
c19148bd 863 .maxtl = 5,
64a88d5d 864 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
865 },
866 {
867 .name = "TI UltraSparc I",
c19148bd 868 .iu_version = ((0x17ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
c48fcb47 869 .fpu_version = 0x00000000,
fb79ceb9 870 .mmu_version = mmu_us_12,
1a14026e 871 .nwindows = 8,
c19148bd 872 .maxtl = 5,
64a88d5d 873 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
874 },
875 {
876 .name = "TI UltraSparc II",
c19148bd 877 .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0x20ULL << 24)),
c48fcb47 878 .fpu_version = 0x00000000,
fb79ceb9 879 .mmu_version = mmu_us_12,
1a14026e 880 .nwindows = 8,
c19148bd 881 .maxtl = 5,
64a88d5d 882 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
883 },
884 {
885 .name = "TI UltraSparc IIi",
c19148bd 886 .iu_version = ((0x17ULL << 48) | (0x12ULL << 32) | (0x91ULL << 24)),
c48fcb47 887 .fpu_version = 0x00000000,
fb79ceb9 888 .mmu_version = mmu_us_12,
1a14026e 889 .nwindows = 8,
c19148bd 890 .maxtl = 5,
64a88d5d 891 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
892 },
893 {
894 .name = "TI UltraSparc IIe",
c19148bd 895 .iu_version = ((0x17ULL << 48) | (0x13ULL << 32) | (0x14ULL << 24)),
c48fcb47 896 .fpu_version = 0x00000000,
fb79ceb9 897 .mmu_version = mmu_us_12,
1a14026e 898 .nwindows = 8,
c19148bd 899 .maxtl = 5,
64a88d5d 900 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
901 },
902 {
903 .name = "Sun UltraSparc III",
c19148bd 904 .iu_version = ((0x3eULL << 48) | (0x14ULL << 32) | (0x34ULL << 24)),
c48fcb47 905 .fpu_version = 0x00000000,
fb79ceb9 906 .mmu_version = mmu_us_12,
1a14026e 907 .nwindows = 8,
c19148bd 908 .maxtl = 5,
64a88d5d 909 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
910 },
911 {
912 .name = "Sun UltraSparc III Cu",
c19148bd 913 .iu_version = ((0x3eULL << 48) | (0x15ULL << 32) | (0x41ULL << 24)),
c48fcb47 914 .fpu_version = 0x00000000,
fb79ceb9 915 .mmu_version = mmu_us_3,
1a14026e 916 .nwindows = 8,
c19148bd 917 .maxtl = 5,
64a88d5d 918 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
919 },
920 {
921 .name = "Sun UltraSparc IIIi",
c19148bd 922 .iu_version = ((0x3eULL << 48) | (0x16ULL << 32) | (0x34ULL << 24)),
c48fcb47 923 .fpu_version = 0x00000000,
fb79ceb9 924 .mmu_version = mmu_us_12,
1a14026e 925 .nwindows = 8,
c19148bd 926 .maxtl = 5,
64a88d5d 927 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
928 },
929 {
930 .name = "Sun UltraSparc IV",
c19148bd 931 .iu_version = ((0x3eULL << 48) | (0x18ULL << 32) | (0x31ULL << 24)),
c48fcb47 932 .fpu_version = 0x00000000,
fb79ceb9 933 .mmu_version = mmu_us_4,
1a14026e 934 .nwindows = 8,
c19148bd 935 .maxtl = 5,
64a88d5d 936 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
937 },
938 {
939 .name = "Sun UltraSparc IV+",
c19148bd 940 .iu_version = ((0x3eULL << 48) | (0x19ULL << 32) | (0x22ULL << 24)),
c48fcb47 941 .fpu_version = 0x00000000,
fb79ceb9 942 .mmu_version = mmu_us_12,
1a14026e 943 .nwindows = 8,
c19148bd 944 .maxtl = 5,
fb79ceb9 945 .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_CMT,
c48fcb47
BS
946 },
947 {
948 .name = "Sun UltraSparc IIIi+",
c19148bd 949 .iu_version = ((0x3eULL << 48) | (0x22ULL << 32) | (0ULL << 24)),
c48fcb47 950 .fpu_version = 0x00000000,
fb79ceb9 951 .mmu_version = mmu_us_3,
1a14026e 952 .nwindows = 8,
c19148bd 953 .maxtl = 5,
64a88d5d 954 .features = CPU_DEFAULT_FEATURES,
c48fcb47 955 },
c7ba218d
BS
956 {
957 .name = "Sun UltraSparc T1",
958 // defined in sparc_ifu_fdp.v and ctu.h
c19148bd 959 .iu_version = ((0x3eULL << 48) | (0x23ULL << 32) | (0x02ULL << 24)),
c7ba218d
BS
960 .fpu_version = 0x00000000,
961 .mmu_version = mmu_sun4v,
962 .nwindows = 8,
c19148bd 963 .maxtl = 6,
c7ba218d
BS
964 .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
965 | CPU_FEATURE_GL,
966 },
967 {
968 .name = "Sun UltraSparc T2",
969 // defined in tlu_asi_ctl.v and n2_revid_cust.v
c19148bd 970 .iu_version = ((0x3eULL << 48) | (0x24ULL << 32) | (0x02ULL << 24)),
c7ba218d
BS
971 .fpu_version = 0x00000000,
972 .mmu_version = mmu_sun4v,
973 .nwindows = 8,
c19148bd 974 .maxtl = 6,
c7ba218d
BS
975 .features = CPU_DEFAULT_FEATURES | CPU_FEATURE_HYPV | CPU_FEATURE_CMT
976 | CPU_FEATURE_GL,
977 },
c48fcb47
BS
978 {
979 .name = "NEC UltraSparc I",
c19148bd 980 .iu_version = ((0x22ULL << 48) | (0x10ULL << 32) | (0x40ULL << 24)),
c48fcb47 981 .fpu_version = 0x00000000,
fb79ceb9 982 .mmu_version = mmu_us_12,
1a14026e 983 .nwindows = 8,
c19148bd 984 .maxtl = 5,
64a88d5d 985 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
986 },
987#else
988 {
989 .name = "Fujitsu MB86900",
990 .iu_version = 0x00 << 24, /* Impl 0, ver 0 */
991 .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
992 .mmu_version = 0x00 << 24, /* Impl 0, ver 0 */
993 .mmu_bm = 0x00004000,
994 .mmu_ctpr_mask = 0x007ffff0,
995 .mmu_cxr_mask = 0x0000003f,
996 .mmu_sfsr_mask = 0xffffffff,
997 .mmu_trcr_mask = 0xffffffff,
1a14026e 998 .nwindows = 7,
e30b4678 999 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_FSMULD,
c48fcb47
BS
1000 },
1001 {
1002 .name = "Fujitsu MB86904",
1003 .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
1004 .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1005 .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
1006 .mmu_bm = 0x00004000,
1007 .mmu_ctpr_mask = 0x00ffffc0,
1008 .mmu_cxr_mask = 0x000000ff,
1009 .mmu_sfsr_mask = 0x00016fff,
1010 .mmu_trcr_mask = 0x00ffffff,
1a14026e 1011 .nwindows = 8,
64a88d5d 1012 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
1013 },
1014 {
1015 .name = "Fujitsu MB86907",
1016 .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
1017 .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1018 .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
1019 .mmu_bm = 0x00004000,
1020 .mmu_ctpr_mask = 0xffffffc0,
1021 .mmu_cxr_mask = 0x000000ff,
1022 .mmu_sfsr_mask = 0x00016fff,
1023 .mmu_trcr_mask = 0xffffffff,
1a14026e 1024 .nwindows = 8,
64a88d5d 1025 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
1026 },
1027 {
1028 .name = "LSI L64811",
1029 .iu_version = 0x10 << 24, /* Impl 1, ver 0 */
1030 .fpu_version = 1 << 17, /* FPU version 1 (LSI L64814) */
1031 .mmu_version = 0x10 << 24,
1032 .mmu_bm = 0x00004000,
1033 .mmu_ctpr_mask = 0x007ffff0,
1034 .mmu_cxr_mask = 0x0000003f,
1035 .mmu_sfsr_mask = 0xffffffff,
1036 .mmu_trcr_mask = 0xffffffff,
1a14026e 1037 .nwindows = 8,
e30b4678
BS
1038 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1039 CPU_FEATURE_FSMULD,
c48fcb47
BS
1040 },
1041 {
1042 .name = "Cypress CY7C601",
1043 .iu_version = 0x11 << 24, /* Impl 1, ver 1 */
1044 .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
1045 .mmu_version = 0x10 << 24,
1046 .mmu_bm = 0x00004000,
1047 .mmu_ctpr_mask = 0x007ffff0,
1048 .mmu_cxr_mask = 0x0000003f,
1049 .mmu_sfsr_mask = 0xffffffff,
1050 .mmu_trcr_mask = 0xffffffff,
1a14026e 1051 .nwindows = 8,
e30b4678
BS
1052 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1053 CPU_FEATURE_FSMULD,
c48fcb47
BS
1054 },
1055 {
1056 .name = "Cypress CY7C611",
1057 .iu_version = 0x13 << 24, /* Impl 1, ver 3 */
1058 .fpu_version = 3 << 17, /* FPU version 3 (Cypress CY7C602) */
1059 .mmu_version = 0x10 << 24,
1060 .mmu_bm = 0x00004000,
1061 .mmu_ctpr_mask = 0x007ffff0,
1062 .mmu_cxr_mask = 0x0000003f,
1063 .mmu_sfsr_mask = 0xffffffff,
1064 .mmu_trcr_mask = 0xffffffff,
1a14026e 1065 .nwindows = 8,
e30b4678
BS
1066 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1067 CPU_FEATURE_FSMULD,
c48fcb47 1068 },
c48fcb47
BS
1069 {
1070 .name = "TI MicroSparc I",
1071 .iu_version = 0x41000000,
1072 .fpu_version = 4 << 17,
1073 .mmu_version = 0x41000000,
1074 .mmu_bm = 0x00004000,
1075 .mmu_ctpr_mask = 0x007ffff0,
1076 .mmu_cxr_mask = 0x0000003f,
1077 .mmu_sfsr_mask = 0x00016fff,
1078 .mmu_trcr_mask = 0x0000003f,
1a14026e 1079 .nwindows = 7,
e30b4678
BS
1080 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_MUL |
1081 CPU_FEATURE_DIV | CPU_FEATURE_FLUSH | CPU_FEATURE_FSQRT |
1082 CPU_FEATURE_FMUL,
c48fcb47
BS
1083 },
1084 {
1085 .name = "TI MicroSparc II",
1086 .iu_version = 0x42000000,
1087 .fpu_version = 4 << 17,
1088 .mmu_version = 0x02000000,
1089 .mmu_bm = 0x00004000,
1090 .mmu_ctpr_mask = 0x00ffffc0,
1091 .mmu_cxr_mask = 0x000000ff,
1092 .mmu_sfsr_mask = 0x00016fff,
1093 .mmu_trcr_mask = 0x00ffffff,
1a14026e 1094 .nwindows = 8,
64a88d5d 1095 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
1096 },
1097 {
1098 .name = "TI MicroSparc IIep",
1099 .iu_version = 0x42000000,
1100 .fpu_version = 4 << 17,
1101 .mmu_version = 0x04000000,
1102 .mmu_bm = 0x00004000,
1103 .mmu_ctpr_mask = 0x00ffffc0,
1104 .mmu_cxr_mask = 0x000000ff,
1105 .mmu_sfsr_mask = 0x00016bff,
1106 .mmu_trcr_mask = 0x00ffffff,
1a14026e 1107 .nwindows = 8,
64a88d5d 1108 .features = CPU_DEFAULT_FEATURES,
c48fcb47 1109 },
b5154bde
BS
1110 {
1111 .name = "TI SuperSparc 40", // STP1020NPGA
963262de 1112 .iu_version = 0x41000000, // SuperSPARC 2.x
b5154bde 1113 .fpu_version = 0 << 17,
963262de 1114 .mmu_version = 0x00000800, // SuperSPARC 2.x, no MXCC
b5154bde
BS
1115 .mmu_bm = 0x00002000,
1116 .mmu_ctpr_mask = 0xffffffc0,
1117 .mmu_cxr_mask = 0x0000ffff,
1118 .mmu_sfsr_mask = 0xffffffff,
1119 .mmu_trcr_mask = 0xffffffff,
1a14026e 1120 .nwindows = 8,
b5154bde
BS
1121 .features = CPU_DEFAULT_FEATURES,
1122 },
1123 {
1124 .name = "TI SuperSparc 50", // STP1020PGA
963262de 1125 .iu_version = 0x40000000, // SuperSPARC 3.x
b5154bde 1126 .fpu_version = 0 << 17,
963262de 1127 .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
b5154bde
BS
1128 .mmu_bm = 0x00002000,
1129 .mmu_ctpr_mask = 0xffffffc0,
1130 .mmu_cxr_mask = 0x0000ffff,
1131 .mmu_sfsr_mask = 0xffffffff,
1132 .mmu_trcr_mask = 0xffffffff,
1a14026e 1133 .nwindows = 8,
b5154bde
BS
1134 .features = CPU_DEFAULT_FEATURES,
1135 },
c48fcb47
BS
1136 {
1137 .name = "TI SuperSparc 51",
963262de 1138 .iu_version = 0x40000000, // SuperSPARC 3.x
c48fcb47 1139 .fpu_version = 0 << 17,
963262de 1140 .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
c48fcb47
BS
1141 .mmu_bm = 0x00002000,
1142 .mmu_ctpr_mask = 0xffffffc0,
1143 .mmu_cxr_mask = 0x0000ffff,
1144 .mmu_sfsr_mask = 0xffffffff,
1145 .mmu_trcr_mask = 0xffffffff,
963262de 1146 .mxcc_version = 0x00000104,
1a14026e 1147 .nwindows = 8,
64a88d5d 1148 .features = CPU_DEFAULT_FEATURES,
c48fcb47 1149 },
b5154bde
BS
1150 {
1151 .name = "TI SuperSparc 60", // STP1020APGA
963262de 1152 .iu_version = 0x40000000, // SuperSPARC 3.x
b5154bde 1153 .fpu_version = 0 << 17,
963262de 1154 .mmu_version = 0x01000800, // SuperSPARC 3.x, no MXCC
b5154bde
BS
1155 .mmu_bm = 0x00002000,
1156 .mmu_ctpr_mask = 0xffffffc0,
1157 .mmu_cxr_mask = 0x0000ffff,
1158 .mmu_sfsr_mask = 0xffffffff,
1159 .mmu_trcr_mask = 0xffffffff,
1a14026e 1160 .nwindows = 8,
b5154bde
BS
1161 .features = CPU_DEFAULT_FEATURES,
1162 },
c48fcb47
BS
1163 {
1164 .name = "TI SuperSparc 61",
963262de 1165 .iu_version = 0x44000000, // SuperSPARC 3.x
c48fcb47 1166 .fpu_version = 0 << 17,
963262de
BS
1167 .mmu_version = 0x01000000, // SuperSPARC 3.x, MXCC
1168 .mmu_bm = 0x00002000,
1169 .mmu_ctpr_mask = 0xffffffc0,
1170 .mmu_cxr_mask = 0x0000ffff,
1171 .mmu_sfsr_mask = 0xffffffff,
1172 .mmu_trcr_mask = 0xffffffff,
1173 .mxcc_version = 0x00000104,
1174 .nwindows = 8,
1175 .features = CPU_DEFAULT_FEATURES,
1176 },
1177 {
1178 .name = "TI SuperSparc II",
1179 .iu_version = 0x40000000, // SuperSPARC II 1.x
1180 .fpu_version = 0 << 17,
1181 .mmu_version = 0x08000000, // SuperSPARC II 1.x, MXCC
c48fcb47
BS
1182 .mmu_bm = 0x00002000,
1183 .mmu_ctpr_mask = 0xffffffc0,
1184 .mmu_cxr_mask = 0x0000ffff,
1185 .mmu_sfsr_mask = 0xffffffff,
1186 .mmu_trcr_mask = 0xffffffff,
963262de 1187 .mxcc_version = 0x00000104,
1a14026e 1188 .nwindows = 8,
64a88d5d 1189 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
1190 },
1191 {
1192 .name = "Ross RT625",
1193 .iu_version = 0x1e000000,
1194 .fpu_version = 1 << 17,
1195 .mmu_version = 0x1e000000,
1196 .mmu_bm = 0x00004000,
1197 .mmu_ctpr_mask = 0x007ffff0,
1198 .mmu_cxr_mask = 0x0000003f,
1199 .mmu_sfsr_mask = 0xffffffff,
1200 .mmu_trcr_mask = 0xffffffff,
1a14026e 1201 .nwindows = 8,
64a88d5d 1202 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
1203 },
1204 {
1205 .name = "Ross RT620",
1206 .iu_version = 0x1f000000,
1207 .fpu_version = 1 << 17,
1208 .mmu_version = 0x1f000000,
1209 .mmu_bm = 0x00004000,
1210 .mmu_ctpr_mask = 0x007ffff0,
1211 .mmu_cxr_mask = 0x0000003f,
1212 .mmu_sfsr_mask = 0xffffffff,
1213 .mmu_trcr_mask = 0xffffffff,
1a14026e 1214 .nwindows = 8,
64a88d5d 1215 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
1216 },
1217 {
1218 .name = "BIT B5010",
1219 .iu_version = 0x20000000,
1220 .fpu_version = 0 << 17, /* B5010/B5110/B5120/B5210 */
1221 .mmu_version = 0x20000000,
1222 .mmu_bm = 0x00004000,
1223 .mmu_ctpr_mask = 0x007ffff0,
1224 .mmu_cxr_mask = 0x0000003f,
1225 .mmu_sfsr_mask = 0xffffffff,
1226 .mmu_trcr_mask = 0xffffffff,
1a14026e 1227 .nwindows = 8,
e30b4678
BS
1228 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_SWAP | CPU_FEATURE_FSQRT |
1229 CPU_FEATURE_FSMULD,
c48fcb47
BS
1230 },
1231 {
1232 .name = "Matsushita MN10501",
1233 .iu_version = 0x50000000,
1234 .fpu_version = 0 << 17,
1235 .mmu_version = 0x50000000,
1236 .mmu_bm = 0x00004000,
1237 .mmu_ctpr_mask = 0x007ffff0,
1238 .mmu_cxr_mask = 0x0000003f,
1239 .mmu_sfsr_mask = 0xffffffff,
1240 .mmu_trcr_mask = 0xffffffff,
1a14026e 1241 .nwindows = 8,
e30b4678
BS
1242 .features = CPU_FEATURE_FLOAT | CPU_FEATURE_MUL | CPU_FEATURE_FSQRT |
1243 CPU_FEATURE_FSMULD,
c48fcb47
BS
1244 },
1245 {
1246 .name = "Weitek W8601",
1247 .iu_version = 0x90 << 24, /* Impl 9, ver 0 */
1248 .fpu_version = 3 << 17, /* FPU version 3 (Weitek WTL3170/2) */
1249 .mmu_version = 0x10 << 24,
1250 .mmu_bm = 0x00004000,
1251 .mmu_ctpr_mask = 0x007ffff0,
1252 .mmu_cxr_mask = 0x0000003f,
1253 .mmu_sfsr_mask = 0xffffffff,
1254 .mmu_trcr_mask = 0xffffffff,
1a14026e 1255 .nwindows = 8,
64a88d5d 1256 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
1257 },
1258 {
1259 .name = "LEON2",
1260 .iu_version = 0xf2000000,
1261 .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1262 .mmu_version = 0xf2000000,
1263 .mmu_bm = 0x00004000,
1264 .mmu_ctpr_mask = 0x007ffff0,
1265 .mmu_cxr_mask = 0x0000003f,
1266 .mmu_sfsr_mask = 0xffffffff,
1267 .mmu_trcr_mask = 0xffffffff,
1a14026e 1268 .nwindows = 8,
64a88d5d 1269 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
1270 },
1271 {
1272 .name = "LEON3",
1273 .iu_version = 0xf3000000,
1274 .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
1275 .mmu_version = 0xf3000000,
1276 .mmu_bm = 0x00004000,
1277 .mmu_ctpr_mask = 0x007ffff0,
1278 .mmu_cxr_mask = 0x0000003f,
1279 .mmu_sfsr_mask = 0xffffffff,
1280 .mmu_trcr_mask = 0xffffffff,
1a14026e 1281 .nwindows = 8,
64a88d5d 1282 .features = CPU_DEFAULT_FEATURES,
c48fcb47
BS
1283 },
1284#endif
1285};
1286
64a88d5d
BS
1287static const char * const feature_name[] = {
1288 "float",
1289 "float128",
1290 "swap",
1291 "mul",
1292 "div",
1293 "flush",
1294 "fsqrt",
1295 "fmul",
1296 "vis1",
1297 "vis2",
e30b4678 1298 "fsmuld",
fb79ceb9
BS
1299 "hypv",
1300 "cmt",
1301 "gl",
64a88d5d
BS
1302};
1303
1304static void print_features(FILE *f,
1305 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
1306 uint32_t features, const char *prefix)
c48fcb47
BS
1307{
1308 unsigned int i;
1309
64a88d5d
BS
1310 for (i = 0; i < ARRAY_SIZE(feature_name); i++)
1311 if (feature_name[i] && (features & (1 << i))) {
1312 if (prefix)
1313 (*cpu_fprintf)(f, "%s", prefix);
1314 (*cpu_fprintf)(f, "%s ", feature_name[i]);
1315 }
1316}
1317
1318static void add_flagname_to_bitmaps(const char *flagname, uint32_t *features)
1319{
1320 unsigned int i;
1321
1322 for (i = 0; i < ARRAY_SIZE(feature_name); i++)
1323 if (feature_name[i] && !strcmp(flagname, feature_name[i])) {
1324 *features |= 1 << i;
1325 return;
1326 }
1327 fprintf(stderr, "CPU feature %s not found\n", flagname);
1328}
1329
22548760 1330static int cpu_sparc_find_by_name(sparc_def_t *cpu_def, const char *cpu_model)
64a88d5d
BS
1331{
1332 unsigned int i;
1333 const sparc_def_t *def = NULL;
1334 char *s = strdup(cpu_model);
1335 char *featurestr, *name = strtok(s, ",");
1336 uint32_t plus_features = 0;
1337 uint32_t minus_features = 0;
0bfcd599 1338 uint64_t iu_version;
1a14026e 1339 uint32_t fpu_version, mmu_version, nwindows;
64a88d5d 1340
b1503cda 1341 for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
c48fcb47 1342 if (strcasecmp(name, sparc_defs[i].name) == 0) {
64a88d5d 1343 def = &sparc_defs[i];
c48fcb47
BS
1344 }
1345 }
64a88d5d
BS
1346 if (!def)
1347 goto error;
1348 memcpy(cpu_def, def, sizeof(*def));
1349
1350 featurestr = strtok(NULL, ",");
1351 while (featurestr) {
1352 char *val;
1353
1354 if (featurestr[0] == '+') {
1355 add_flagname_to_bitmaps(featurestr + 1, &plus_features);
1356 } else if (featurestr[0] == '-') {
1357 add_flagname_to_bitmaps(featurestr + 1, &minus_features);
1358 } else if ((val = strchr(featurestr, '='))) {
1359 *val = 0; val++;
1360 if (!strcmp(featurestr, "iu_version")) {
1361 char *err;
1362
1363 iu_version = strtoll(val, &err, 0);
1364 if (!*val || *err) {
1365 fprintf(stderr, "bad numerical value %s\n", val);
1366 goto error;
1367 }
1368 cpu_def->iu_version = iu_version;
1369#ifdef DEBUG_FEATURES
0bfcd599 1370 fprintf(stderr, "iu_version %" PRIx64 "\n", iu_version);
64a88d5d
BS
1371#endif
1372 } else if (!strcmp(featurestr, "fpu_version")) {
1373 char *err;
1374
1375 fpu_version = strtol(val, &err, 0);
1376 if (!*val || *err) {
1377 fprintf(stderr, "bad numerical value %s\n", val);
1378 goto error;
1379 }
1380 cpu_def->fpu_version = fpu_version;
1381#ifdef DEBUG_FEATURES
0bf9e31a 1382 fprintf(stderr, "fpu_version %x\n", fpu_version);
64a88d5d
BS
1383#endif
1384 } else if (!strcmp(featurestr, "mmu_version")) {
1385 char *err;
1386
1387 mmu_version = strtol(val, &err, 0);
1388 if (!*val || *err) {
1389 fprintf(stderr, "bad numerical value %s\n", val);
1390 goto error;
1391 }
1392 cpu_def->mmu_version = mmu_version;
1393#ifdef DEBUG_FEATURES
0bf9e31a 1394 fprintf(stderr, "mmu_version %x\n", mmu_version);
1a14026e
BS
1395#endif
1396 } else if (!strcmp(featurestr, "nwindows")) {
1397 char *err;
1398
1399 nwindows = strtol(val, &err, 0);
1400 if (!*val || *err || nwindows > MAX_NWINDOWS ||
1401 nwindows < MIN_NWINDOWS) {
1402 fprintf(stderr, "bad numerical value %s\n", val);
1403 goto error;
1404 }
1405 cpu_def->nwindows = nwindows;
1406#ifdef DEBUG_FEATURES
1407 fprintf(stderr, "nwindows %d\n", nwindows);
64a88d5d
BS
1408#endif
1409 } else {
1410 fprintf(stderr, "unrecognized feature %s\n", featurestr);
1411 goto error;
1412 }
1413 } else {
77f193da
BS
1414 fprintf(stderr, "feature string `%s' not in format "
1415 "(+feature|-feature|feature=xyz)\n", featurestr);
64a88d5d
BS
1416 goto error;
1417 }
1418 featurestr = strtok(NULL, ",");
1419 }
1420 cpu_def->features |= plus_features;
1421 cpu_def->features &= ~minus_features;
1422#ifdef DEBUG_FEATURES
1423 print_features(stderr, fprintf, cpu_def->features, NULL);
1424#endif
1425 free(s);
1426 return 0;
1427
1428 error:
1429 free(s);
1430 return -1;
c48fcb47
BS
1431}
1432
77f193da 1433void sparc_cpu_list(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
c48fcb47
BS
1434{
1435 unsigned int i;
1436
b1503cda 1437 for (i = 0; i < ARRAY_SIZE(sparc_defs); i++) {
1a14026e 1438 (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x NWINS %d ",
c48fcb47
BS
1439 sparc_defs[i].name,
1440 sparc_defs[i].iu_version,
1441 sparc_defs[i].fpu_version,
1a14026e
BS
1442 sparc_defs[i].mmu_version,
1443 sparc_defs[i].nwindows);
77f193da
BS
1444 print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES &
1445 ~sparc_defs[i].features, "-");
1446 print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES &
1447 sparc_defs[i].features, "+");
64a88d5d 1448 (*cpu_fprintf)(f, "\n");
c48fcb47 1449 }
f76981b1
BS
1450 (*cpu_fprintf)(f, "Default CPU feature flags (use '-' to remove): ");
1451 print_features(f, cpu_fprintf, CPU_DEFAULT_FEATURES, NULL);
64a88d5d 1452 (*cpu_fprintf)(f, "\n");
f76981b1
BS
1453 (*cpu_fprintf)(f, "Available CPU feature flags (use '+' to add): ");
1454 print_features(f, cpu_fprintf, ~CPU_DEFAULT_FEATURES, NULL);
1455 (*cpu_fprintf)(f, "\n");
1456 (*cpu_fprintf)(f, "Numerical features (use '=' to set): iu_version "
1457 "fpu_version mmu_version nwindows\n");
c48fcb47
BS
1458}
1459
43bb98bf
BS
1460static void cpu_print_cc(FILE *f,
1461 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
1462 uint32_t cc)
1463{
1464 cpu_fprintf(f, "%c%c%c%c", cc & PSR_NEG? 'N' : '-',
1465 cc & PSR_ZERO? 'Z' : '-', cc & PSR_OVF? 'V' : '-',
1466 cc & PSR_CARRY? 'C' : '-');
1467}
1468
1469#ifdef TARGET_SPARC64
1470#define REGS_PER_LINE 4
1471#else
1472#define REGS_PER_LINE 8
1473#endif
1474
c48fcb47
BS
1475void cpu_dump_state(CPUState *env, FILE *f,
1476 int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
1477 int flags)
1478{
1479 int i, x;
1480
77f193da
BS
1481 cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc,
1482 env->npc);
c48fcb47 1483 cpu_fprintf(f, "General Registers:\n");
43bb98bf
BS
1484
1485 for (i = 0; i < 8; i++) {
1486 if (i % REGS_PER_LINE == 0) {
1487 cpu_fprintf(f, "%%g%d-%d:", i, i + REGS_PER_LINE - 1);
1488 }
1489 cpu_fprintf(f, " " TARGET_FMT_lx, env->gregs[i]);
1490 if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
1491 cpu_fprintf(f, "\n");
1492 }
1493 }
c48fcb47
BS
1494 cpu_fprintf(f, "\nCurrent Register Window:\n");
1495 for (x = 0; x < 3; x++) {
43bb98bf
BS
1496 for (i = 0; i < 8; i++) {
1497 if (i % REGS_PER_LINE == 0) {
1498 cpu_fprintf(f, "%%%c%d-%d: ",
1499 x == 0 ? 'o' : (x == 1 ? 'l' : 'i'),
1500 i, i + REGS_PER_LINE - 1);
1501 }
1502 cpu_fprintf(f, TARGET_FMT_lx " ", env->regwptr[i + x * 8]);
1503 if (i % REGS_PER_LINE == REGS_PER_LINE - 1) {
1504 cpu_fprintf(f, "\n");
1505 }
1506 }
c48fcb47
BS
1507 }
1508 cpu_fprintf(f, "\nFloating Point Registers:\n");
43bb98bf 1509 for (i = 0; i < TARGET_FPREGS; i++) {
c48fcb47
BS
1510 if ((i & 3) == 0)
1511 cpu_fprintf(f, "%%f%02d:", i);
a37ee56c 1512 cpu_fprintf(f, " %016f", *(float *)&env->fpr[i]);
c48fcb47
BS
1513 if ((i & 3) == 3)
1514 cpu_fprintf(f, "\n");
1515 }
1516#ifdef TARGET_SPARC64
43bb98bf 1517 cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
113c6106 1518 (unsigned)cpu_get_ccr(env));
5a834bb4 1519 cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
43bb98bf 1520 cpu_fprintf(f, " xcc: ");
5a834bb4 1521 cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
43bb98bf
BS
1522 cpu_fprintf(f, ") asi: %02x tl: %d pil: %x\n", env->asi, env->tl,
1523 env->psrpil);
1524 cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate: %d "
1525 "cleanwin: %d cwp: %d\n",
c48fcb47 1526 env->cansave, env->canrestore, env->otherwin, env->wstate,
1a14026e 1527 env->cleanwin, env->nwindows - 1 - env->cwp);
43bb98bf
BS
1528 cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx " fprs: "
1529 TARGET_FMT_lx "\n", env->fsr, env->y, env->fprs);
c48fcb47 1530#else
5a834bb4
BS
1531 cpu_fprintf(f, "psr: %08x (icc: ", cpu_get_psr(env));
1532 cpu_print_cc(f, cpu_fprintf, cpu_get_psr(env));
43bb98bf
BS
1533 cpu_fprintf(f, " SPE: %c%c%c) wim: %08x\n", env->psrs? 'S' : '-',
1534 env->psrps? 'P' : '-', env->psret? 'E' : '-',
1535 env->wim);
1536 cpu_fprintf(f, "fsr: " TARGET_FMT_lx " y: " TARGET_FMT_lx "\n",
1537 env->fsr, env->y);
c48fcb47 1538#endif
c48fcb47 1539}