]>
Commit | Line | Data |
---|---|---|
3e457172 BS |
1 | #include "cpu.h" |
2 | #include "dyngen-exec.h" | |
1a2fb1c0 | 3 | #include "helper.h" |
e8af50a3 | 4 | |
3e457172 BS |
5 | #if !defined(CONFIG_USER_ONLY) |
6 | #include "softmmu_exec.h" | |
7 | #endif | |
8 | ||
e80cfcfc | 9 | //#define DEBUG_MMU |
952a328f | 10 | //#define DEBUG_MXCC |
94554550 | 11 | //#define DEBUG_UNALIGNED |
6c36d3fa | 12 | //#define DEBUG_UNASSIGNED |
8543e2cf | 13 | //#define DEBUG_ASI |
7e8695ed | 14 | //#define DEBUG_PSTATE |
b04d9890 | 15 | //#define DEBUG_CACHE_CONTROL |
e80cfcfc | 16 | |
952a328f | 17 | #ifdef DEBUG_MMU |
001faf32 BS |
18 | #define DPRINTF_MMU(fmt, ...) \ |
19 | do { printf("MMU: " fmt , ## __VA_ARGS__); } while (0) | |
952a328f | 20 | #else |
001faf32 | 21 | #define DPRINTF_MMU(fmt, ...) do {} while (0) |
952a328f BS |
22 | #endif |
23 | ||
24 | #ifdef DEBUG_MXCC | |
001faf32 BS |
25 | #define DPRINTF_MXCC(fmt, ...) \ |
26 | do { printf("MXCC: " fmt , ## __VA_ARGS__); } while (0) | |
952a328f | 27 | #else |
001faf32 | 28 | #define DPRINTF_MXCC(fmt, ...) do {} while (0) |
952a328f BS |
29 | #endif |
30 | ||
8543e2cf | 31 | #ifdef DEBUG_ASI |
001faf32 BS |
32 | #define DPRINTF_ASI(fmt, ...) \ |
33 | do { printf("ASI: " fmt , ## __VA_ARGS__); } while (0) | |
8543e2cf BS |
34 | #endif |
35 | ||
7e8695ed | 36 | #ifdef DEBUG_PSTATE |
99ca0219 | 37 | #define DPRINTF_PSTATE(fmt, ...) \ |
7e8695ed IK |
38 | do { printf("PSTATE: " fmt , ## __VA_ARGS__); } while (0) |
39 | #else | |
40 | #define DPRINTF_PSTATE(fmt, ...) do {} while (0) | |
41 | #endif | |
42 | ||
b04d9890 | 43 | #ifdef DEBUG_CACHE_CONTROL |
99ca0219 | 44 | #define DPRINTF_CACHE_CONTROL(fmt, ...) \ |
b04d9890 FC |
45 | do { printf("CACHE_CONTROL: " fmt , ## __VA_ARGS__); } while (0) |
46 | #else | |
47 | #define DPRINTF_CACHE_CONTROL(fmt, ...) do {} while (0) | |
48 | #endif | |
49 | ||
2cade6a3 BS |
50 | #ifdef TARGET_SPARC64 |
51 | #ifndef TARGET_ABI32 | |
52 | #define AM_CHECK(env1) ((env1)->pstate & PS_AM) | |
c2bc0e38 | 53 | #else |
2cade6a3 BS |
54 | #define AM_CHECK(env1) (1) |
55 | #endif | |
c2bc0e38 BS |
56 | #endif |
57 | ||
21ffd181 BS |
58 | #define DT0 (env->dt0) |
59 | #define DT1 (env->dt1) | |
60 | #define QT0 (env->qt0) | |
61 | #define QT1 (env->qt1) | |
62 | ||
b04d9890 FC |
63 | /* Leon3 cache control */ |
64 | ||
65 | /* Cache control: emulate the behavior of cache control registers but without | |
66 | any effect on the emulated */ | |
67 | ||
68 | #define CACHE_STATE_MASK 0x3 | |
69 | #define CACHE_DISABLED 0x0 | |
70 | #define CACHE_FROZEN 0x1 | |
71 | #define CACHE_ENABLED 0x3 | |
72 | ||
73 | /* Cache Control register fields */ | |
74 | ||
75 | #define CACHE_CTRL_IF (1 << 4) /* Instruction Cache Freeze on Interrupt */ | |
76 | #define CACHE_CTRL_DF (1 << 5) /* Data Cache Freeze on Interrupt */ | |
77 | #define CACHE_CTRL_DP (1 << 14) /* Data cache flush pending */ | |
78 | #define CACHE_CTRL_IP (1 << 15) /* Instruction cache flush pending */ | |
79 | #define CACHE_CTRL_IB (1 << 16) /* Instruction burst fetch */ | |
80 | #define CACHE_CTRL_FI (1 << 21) /* Flush Instruction cache (Write only) */ | |
81 | #define CACHE_CTRL_FD (1 << 22) /* Flush Data cache (Write only) */ | |
82 | #define CACHE_CTRL_DS (1 << 23) /* Data cache snoop enable */ | |
83 | ||
b14ef7c9 BS |
84 | #if !defined(CONFIG_USER_ONLY) |
85 | static void do_unassigned_access(target_phys_addr_t addr, int is_write, | |
86 | int is_exec, int is_asi, int size); | |
87 | #else | |
88 | #ifdef TARGET_SPARC64 | |
3c7b48b7 | 89 | static void do_unassigned_access(target_ulong addr, int is_write, int is_exec, |
b14ef7c9 BS |
90 | int is_asi, int size); |
91 | #endif | |
3c7b48b7 PB |
92 | #endif |
93 | ||
9c22a623 | 94 | #if defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) |
99ca0219 | 95 | /* Calculates TSB pointer value for fault page size 8k or 64k */ |
697a77e6 IK |
96 | static uint64_t ultrasparc_tsb_pointer(uint64_t tsb_register, |
97 | uint64_t tag_access_register, | |
98 | int page_size) | |
99 | { | |
100 | uint64_t tsb_base = tsb_register & ~0x1fffULL; | |
6e8e7d4c IK |
101 | int tsb_split = (tsb_register & 0x1000ULL) ? 1 : 0; |
102 | int tsb_size = tsb_register & 0xf; | |
697a77e6 | 103 | |
99ca0219 | 104 | /* discard lower 13 bits which hold tag access context */ |
697a77e6 IK |
105 | uint64_t tag_access_va = tag_access_register & ~0x1fffULL; |
106 | ||
99ca0219 | 107 | /* now reorder bits */ |
697a77e6 IK |
108 | uint64_t tsb_base_mask = ~0x1fffULL; |
109 | uint64_t va = tag_access_va; | |
110 | ||
99ca0219 | 111 | /* move va bits to correct position */ |
697a77e6 IK |
112 | if (page_size == 8*1024) { |
113 | va >>= 9; | |
114 | } else if (page_size == 64*1024) { | |
115 | va >>= 12; | |
116 | } | |
117 | ||
118 | if (tsb_size) { | |
119 | tsb_base_mask <<= tsb_size; | |
120 | } | |
121 | ||
99ca0219 | 122 | /* calculate tsb_base mask and adjust va if split is in use */ |
697a77e6 IK |
123 | if (tsb_split) { |
124 | if (page_size == 8*1024) { | |
125 | va &= ~(1ULL << (13 + tsb_size)); | |
126 | } else if (page_size == 64*1024) { | |
127 | va |= (1ULL << (13 + tsb_size)); | |
128 | } | |
129 | tsb_base_mask <<= 1; | |
130 | } | |
131 | ||
132 | return ((tsb_base & tsb_base_mask) | (va & ~tsb_base_mask)) & ~0xfULL; | |
133 | } | |
134 | ||
99ca0219 BS |
135 | /* Calculates tag target register value by reordering bits |
136 | in tag access register */ | |
697a77e6 IK |
137 | static uint64_t ultrasparc_tag_target(uint64_t tag_access_register) |
138 | { | |
139 | return ((tag_access_register & 0x1fff) << 48) | (tag_access_register >> 22); | |
140 | } | |
141 | ||
f707726e IK |
142 | static void replace_tlb_entry(SparcTLBEntry *tlb, |
143 | uint64_t tlb_tag, uint64_t tlb_tte, | |
144 | CPUState *env1) | |
6e8e7d4c IK |
145 | { |
146 | target_ulong mask, size, va, offset; | |
147 | ||
99ca0219 | 148 | /* flush page range if translation is valid */ |
f707726e | 149 | if (TTE_IS_VALID(tlb->tte)) { |
6e8e7d4c IK |
150 | |
151 | mask = 0xffffffffffffe000ULL; | |
152 | mask <<= 3 * ((tlb->tte >> 61) & 3); | |
153 | size = ~mask + 1; | |
154 | ||
155 | va = tlb->tag & mask; | |
156 | ||
157 | for (offset = 0; offset < size; offset += TARGET_PAGE_SIZE) { | |
158 | tlb_flush_page(env1, va + offset); | |
159 | } | |
160 | } | |
161 | ||
162 | tlb->tag = tlb_tag; | |
163 | tlb->tte = tlb_tte; | |
164 | } | |
165 | ||
166 | static void demap_tlb(SparcTLBEntry *tlb, target_ulong demap_addr, | |
99ca0219 | 167 | const char *strmmu, CPUState *env1) |
6e8e7d4c IK |
168 | { |
169 | unsigned int i; | |
170 | target_ulong mask; | |
299b520c IK |
171 | uint64_t context; |
172 | ||
173 | int is_demap_context = (demap_addr >> 6) & 1; | |
174 | ||
99ca0219 | 175 | /* demap context */ |
299b520c | 176 | switch ((demap_addr >> 4) & 3) { |
99ca0219 | 177 | case 0: /* primary */ |
299b520c IK |
178 | context = env1->dmmu.mmu_primary_context; |
179 | break; | |
99ca0219 | 180 | case 1: /* secondary */ |
299b520c IK |
181 | context = env1->dmmu.mmu_secondary_context; |
182 | break; | |
99ca0219 | 183 | case 2: /* nucleus */ |
299b520c IK |
184 | context = 0; |
185 | break; | |
99ca0219 | 186 | case 3: /* reserved */ |
299b520c IK |
187 | default: |
188 | return; | |
189 | } | |
6e8e7d4c IK |
190 | |
191 | for (i = 0; i < 64; i++) { | |
f707726e | 192 | if (TTE_IS_VALID(tlb[i].tte)) { |
6e8e7d4c | 193 | |
299b520c | 194 | if (is_demap_context) { |
99ca0219 | 195 | /* will remove non-global entries matching context value */ |
299b520c IK |
196 | if (TTE_IS_GLOBAL(tlb[i].tte) || |
197 | !tlb_compare_context(&tlb[i], context)) { | |
198 | continue; | |
199 | } | |
200 | } else { | |
99ca0219 BS |
201 | /* demap page |
202 | will remove any entry matching VA */ | |
299b520c IK |
203 | mask = 0xffffffffffffe000ULL; |
204 | mask <<= 3 * ((tlb[i].tte >> 61) & 3); | |
205 | ||
206 | if (!compare_masked(demap_addr, tlb[i].tag, mask)) { | |
207 | continue; | |
208 | } | |
209 | ||
99ca0219 | 210 | /* entry should be global or matching context value */ |
299b520c IK |
211 | if (!TTE_IS_GLOBAL(tlb[i].tte) && |
212 | !tlb_compare_context(&tlb[i], context)) { | |
213 | continue; | |
214 | } | |
215 | } | |
6e8e7d4c | 216 | |
299b520c | 217 | replace_tlb_entry(&tlb[i], 0, 0, env1); |
6e8e7d4c | 218 | #ifdef DEBUG_MMU |
299b520c | 219 | DPRINTF_MMU("%s demap invalidated entry [%02u]\n", strmmu, i); |
d41160a3 | 220 | dump_mmu(stdout, fprintf, env1); |
6e8e7d4c | 221 | #endif |
6e8e7d4c IK |
222 | } |
223 | } | |
6e8e7d4c IK |
224 | } |
225 | ||
f707726e IK |
226 | static void replace_tlb_1bit_lru(SparcTLBEntry *tlb, |
227 | uint64_t tlb_tag, uint64_t tlb_tte, | |
99ca0219 | 228 | const char *strmmu, CPUState *env1) |
f707726e IK |
229 | { |
230 | unsigned int i, replace_used; | |
231 | ||
99ca0219 | 232 | /* Try replacing invalid entry */ |
f707726e IK |
233 | for (i = 0; i < 64; i++) { |
234 | if (!TTE_IS_VALID(tlb[i].tte)) { | |
235 | replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1); | |
236 | #ifdef DEBUG_MMU | |
237 | DPRINTF_MMU("%s lru replaced invalid entry [%i]\n", strmmu, i); | |
d41160a3 | 238 | dump_mmu(stdout, fprintf, env1); |
f707726e IK |
239 | #endif |
240 | return; | |
241 | } | |
242 | } | |
243 | ||
99ca0219 | 244 | /* All entries are valid, try replacing unlocked entry */ |
f707726e IK |
245 | |
246 | for (replace_used = 0; replace_used < 2; ++replace_used) { | |
247 | ||
99ca0219 | 248 | /* Used entries are not replaced on first pass */ |
f707726e IK |
249 | |
250 | for (i = 0; i < 64; i++) { | |
251 | if (!TTE_IS_LOCKED(tlb[i].tte) && !TTE_IS_USED(tlb[i].tte)) { | |
252 | ||
253 | replace_tlb_entry(&tlb[i], tlb_tag, tlb_tte, env1); | |
254 | #ifdef DEBUG_MMU | |
255 | DPRINTF_MMU("%s lru replaced unlocked %s entry [%i]\n", | |
99ca0219 | 256 | strmmu, (replace_used ? "used" : "unused"), i); |
d41160a3 | 257 | dump_mmu(stdout, fprintf, env1); |
f707726e IK |
258 | #endif |
259 | return; | |
260 | } | |
261 | } | |
262 | ||
99ca0219 | 263 | /* Now reset used bit and search for unused entries again */ |
f707726e IK |
264 | |
265 | for (i = 0; i < 64; i++) { | |
266 | TTE_SET_UNUSED(tlb[i].tte); | |
267 | } | |
268 | } | |
269 | ||
270 | #ifdef DEBUG_MMU | |
271 | DPRINTF_MMU("%s lru replacement failed: no entries available\n", strmmu); | |
272 | #endif | |
99ca0219 | 273 | /* error state? */ |
f707726e IK |
274 | } |
275 | ||
697a77e6 IK |
276 | #endif |
277 | ||
41db525e | 278 | static inline target_ulong address_mask(CPUState *env1, target_ulong addr) |
2cade6a3 BS |
279 | { |
280 | #ifdef TARGET_SPARC64 | |
99ca0219 | 281 | if (AM_CHECK(env1)) { |
41db525e | 282 | addr &= 0xffffffffULL; |
99ca0219 | 283 | } |
2cade6a3 | 284 | #endif |
41db525e | 285 | return addr; |
2cade6a3 BS |
286 | } |
287 | ||
1295001c IK |
288 | /* returns true if access using this ASI is to have address translated by MMU |
289 | otherwise access is to raw physical address */ | |
290 | static inline int is_translating_asi(int asi) | |
291 | { | |
292 | #ifdef TARGET_SPARC64 | |
293 | /* Ultrasparc IIi translating asi | |
294 | - note this list is defined by cpu implementation | |
99ca0219 | 295 | */ |
1295001c IK |
296 | switch (asi) { |
297 | case 0x04 ... 0x11: | |
b5176d27 TS |
298 | case 0x16 ... 0x19: |
299 | case 0x1E ... 0x1F: | |
1295001c IK |
300 | case 0x24 ... 0x2C: |
301 | case 0x70 ... 0x73: | |
302 | case 0x78 ... 0x79: | |
303 | case 0x80 ... 0xFF: | |
304 | return 1; | |
305 | ||
306 | default: | |
307 | return 0; | |
308 | } | |
309 | #else | |
310 | /* TODO: check sparc32 bits */ | |
311 | return 0; | |
312 | #endif | |
313 | } | |
314 | ||
315 | static inline target_ulong asi_address_mask(CPUState *env1, | |
316 | int asi, target_ulong addr) | |
317 | { | |
318 | if (is_translating_asi(asi)) { | |
319 | return address_mask(env, addr); | |
320 | } else { | |
321 | return addr; | |
322 | } | |
323 | } | |
324 | ||
2b29924f BS |
325 | void helper_check_align(target_ulong addr, uint32_t align) |
326 | { | |
c2bc0e38 BS |
327 | if (addr & align) { |
328 | #ifdef DEBUG_UNALIGNED | |
99ca0219 BS |
329 | printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx |
330 | "\n", addr, env->pc); | |
c2bc0e38 | 331 | #endif |
bc265319 | 332 | helper_raise_exception(env, TT_UNALIGNED); |
c2bc0e38 | 333 | } |
2b29924f BS |
334 | } |
335 | ||
8393617c BS |
336 | static uint32_t compute_all_flags(void) |
337 | { | |
338 | return env->psr & PSR_ICC; | |
339 | } | |
340 | ||
341 | static uint32_t compute_C_flags(void) | |
342 | { | |
343 | return env->psr & PSR_CARRY; | |
344 | } | |
345 | ||
5a4bb580 | 346 | static inline uint32_t get_NZ_icc(int32_t dst) |
bdf9f35d BS |
347 | { |
348 | uint32_t ret = 0; | |
349 | ||
5a4bb580 RH |
350 | if (dst == 0) { |
351 | ret = PSR_ZERO; | |
352 | } else if (dst < 0) { | |
353 | ret = PSR_NEG; | |
354 | } | |
bdf9f35d BS |
355 | return ret; |
356 | } | |
357 | ||
8393617c BS |
358 | #ifdef TARGET_SPARC64 |
359 | static uint32_t compute_all_flags_xcc(void) | |
360 | { | |
361 | return env->xcc & PSR_ICC; | |
362 | } | |
363 | ||
364 | static uint32_t compute_C_flags_xcc(void) | |
365 | { | |
366 | return env->xcc & PSR_CARRY; | |
367 | } | |
368 | ||
5a4bb580 | 369 | static inline uint32_t get_NZ_xcc(target_long dst) |
bdf9f35d BS |
370 | { |
371 | uint32_t ret = 0; | |
372 | ||
5a4bb580 RH |
373 | if (!dst) { |
374 | ret = PSR_ZERO; | |
375 | } else if (dst < 0) { | |
376 | ret = PSR_NEG; | |
377 | } | |
bdf9f35d BS |
378 | return ret; |
379 | } | |
380 | #endif | |
381 | ||
6c78ea32 BS |
382 | static inline uint32_t get_V_div_icc(target_ulong src2) |
383 | { | |
384 | uint32_t ret = 0; | |
385 | ||
5a4bb580 RH |
386 | if (src2 != 0) { |
387 | ret = PSR_OVF; | |
388 | } | |
6c78ea32 BS |
389 | return ret; |
390 | } | |
391 | ||
392 | static uint32_t compute_all_div(void) | |
393 | { | |
394 | uint32_t ret; | |
395 | ||
396 | ret = get_NZ_icc(CC_DST); | |
397 | ret |= get_V_div_icc(CC_SRC2); | |
398 | return ret; | |
399 | } | |
400 | ||
401 | static uint32_t compute_C_div(void) | |
402 | { | |
403 | return 0; | |
404 | } | |
405 | ||
5a4bb580 | 406 | static inline uint32_t get_C_add_icc(uint32_t dst, uint32_t src1) |
bdf9f35d BS |
407 | { |
408 | uint32_t ret = 0; | |
409 | ||
5a4bb580 RH |
410 | if (dst < src1) { |
411 | ret = PSR_CARRY; | |
412 | } | |
bdf9f35d BS |
413 | return ret; |
414 | } | |
415 | ||
5a4bb580 RH |
416 | static inline uint32_t get_C_addx_icc(uint32_t dst, uint32_t src1, |
417 | uint32_t src2) | |
bdf9f35d BS |
418 | { |
419 | uint32_t ret = 0; | |
420 | ||
5a4bb580 RH |
421 | if (((src1 & src2) | (~dst & (src1 | src2))) & (1U << 31)) { |
422 | ret = PSR_CARRY; | |
423 | } | |
424 | return ret; | |
425 | } | |
426 | ||
427 | static inline uint32_t get_V_add_icc(uint32_t dst, uint32_t src1, | |
428 | uint32_t src2) | |
429 | { | |
430 | uint32_t ret = 0; | |
431 | ||
432 | if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1U << 31)) { | |
433 | ret = PSR_OVF; | |
434 | } | |
bdf9f35d BS |
435 | return ret; |
436 | } | |
437 | ||
bdf9f35d BS |
438 | #ifdef TARGET_SPARC64 |
439 | static inline uint32_t get_C_add_xcc(target_ulong dst, target_ulong src1) | |
440 | { | |
441 | uint32_t ret = 0; | |
442 | ||
5a4bb580 RH |
443 | if (dst < src1) { |
444 | ret = PSR_CARRY; | |
445 | } | |
446 | return ret; | |
447 | } | |
448 | ||
449 | static inline uint32_t get_C_addx_xcc(target_ulong dst, target_ulong src1, | |
450 | target_ulong src2) | |
451 | { | |
452 | uint32_t ret = 0; | |
453 | ||
454 | if (((src1 & src2) | (~dst & (src1 | src2))) & (1ULL << 63)) { | |
455 | ret = PSR_CARRY; | |
456 | } | |
bdf9f35d BS |
457 | return ret; |
458 | } | |
459 | ||
460 | static inline uint32_t get_V_add_xcc(target_ulong dst, target_ulong src1, | |
99ca0219 | 461 | target_ulong src2) |
bdf9f35d BS |
462 | { |
463 | uint32_t ret = 0; | |
464 | ||
5a4bb580 RH |
465 | if (((src1 ^ src2 ^ -1) & (src1 ^ dst)) & (1ULL << 63)) { |
466 | ret = PSR_OVF; | |
467 | } | |
bdf9f35d BS |
468 | return ret; |
469 | } | |
470 | ||
471 | static uint32_t compute_all_add_xcc(void) | |
472 | { | |
473 | uint32_t ret; | |
474 | ||
475 | ret = get_NZ_xcc(CC_DST); | |
476 | ret |= get_C_add_xcc(CC_DST, CC_SRC); | |
477 | ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2); | |
478 | return ret; | |
479 | } | |
480 | ||
481 | static uint32_t compute_C_add_xcc(void) | |
482 | { | |
483 | return get_C_add_xcc(CC_DST, CC_SRC); | |
484 | } | |
8393617c BS |
485 | #endif |
486 | ||
3e6ba503 | 487 | static uint32_t compute_all_add(void) |
789c91ef BS |
488 | { |
489 | uint32_t ret; | |
490 | ||
491 | ret = get_NZ_icc(CC_DST); | |
5a4bb580 | 492 | ret |= get_C_add_icc(CC_DST, CC_SRC); |
789c91ef BS |
493 | ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2); |
494 | return ret; | |
495 | } | |
496 | ||
3e6ba503 | 497 | static uint32_t compute_C_add(void) |
789c91ef | 498 | { |
5a4bb580 | 499 | return get_C_add_icc(CC_DST, CC_SRC); |
789c91ef BS |
500 | } |
501 | ||
502 | #ifdef TARGET_SPARC64 | |
503 | static uint32_t compute_all_addx_xcc(void) | |
504 | { | |
505 | uint32_t ret; | |
506 | ||
507 | ret = get_NZ_xcc(CC_DST); | |
5a4bb580 | 508 | ret |= get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2); |
789c91ef BS |
509 | ret |= get_V_add_xcc(CC_DST, CC_SRC, CC_SRC2); |
510 | return ret; | |
511 | } | |
512 | ||
513 | static uint32_t compute_C_addx_xcc(void) | |
514 | { | |
515 | uint32_t ret; | |
516 | ||
5a4bb580 | 517 | ret = get_C_addx_xcc(CC_DST, CC_SRC, CC_SRC2); |
789c91ef BS |
518 | return ret; |
519 | } | |
520 | #endif | |
521 | ||
5a4bb580 RH |
522 | static uint32_t compute_all_addx(void) |
523 | { | |
524 | uint32_t ret; | |
525 | ||
526 | ret = get_NZ_icc(CC_DST); | |
527 | ret |= get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2); | |
528 | ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2); | |
529 | return ret; | |
530 | } | |
531 | ||
532 | static uint32_t compute_C_addx(void) | |
533 | { | |
534 | uint32_t ret; | |
535 | ||
536 | ret = get_C_addx_icc(CC_DST, CC_SRC, CC_SRC2); | |
537 | return ret; | |
538 | } | |
539 | ||
3b2d1e92 BS |
540 | static inline uint32_t get_V_tag_icc(target_ulong src1, target_ulong src2) |
541 | { | |
542 | uint32_t ret = 0; | |
543 | ||
5a4bb580 RH |
544 | if ((src1 | src2) & 0x3) { |
545 | ret = PSR_OVF; | |
546 | } | |
3b2d1e92 BS |
547 | return ret; |
548 | } | |
549 | ||
550 | static uint32_t compute_all_tadd(void) | |
551 | { | |
552 | uint32_t ret; | |
553 | ||
554 | ret = get_NZ_icc(CC_DST); | |
5a4bb580 | 555 | ret |= get_C_add_icc(CC_DST, CC_SRC); |
3b2d1e92 BS |
556 | ret |= get_V_add_icc(CC_DST, CC_SRC, CC_SRC2); |
557 | ret |= get_V_tag_icc(CC_SRC, CC_SRC2); | |
558 | return ret; | |
559 | } | |
560 | ||
3b2d1e92 BS |
561 | static uint32_t compute_all_taddtv(void) |
562 | { | |
563 | uint32_t ret; | |
564 | ||
565 | ret = get_NZ_icc(CC_DST); | |
5a4bb580 | 566 | ret |= get_C_add_icc(CC_DST, CC_SRC); |
3b2d1e92 BS |
567 | return ret; |
568 | } | |
569 | ||
5a4bb580 | 570 | static inline uint32_t get_C_sub_icc(uint32_t src1, uint32_t src2) |
3b2d1e92 | 571 | { |
5a4bb580 RH |
572 | uint32_t ret = 0; |
573 | ||
574 | if (src1 < src2) { | |
575 | ret = PSR_CARRY; | |
576 | } | |
577 | return ret; | |
3b2d1e92 BS |
578 | } |
579 | ||
5a4bb580 RH |
580 | static inline uint32_t get_C_subx_icc(uint32_t dst, uint32_t src1, |
581 | uint32_t src2) | |
d4b0d468 BS |
582 | { |
583 | uint32_t ret = 0; | |
584 | ||
5a4bb580 RH |
585 | if (((~src1 & src2) | (dst & (~src1 | src2))) & (1U << 31)) { |
586 | ret = PSR_CARRY; | |
587 | } | |
d4b0d468 BS |
588 | return ret; |
589 | } | |
590 | ||
5a4bb580 RH |
591 | static inline uint32_t get_V_sub_icc(uint32_t dst, uint32_t src1, |
592 | uint32_t src2) | |
d4b0d468 BS |
593 | { |
594 | uint32_t ret = 0; | |
595 | ||
5a4bb580 RH |
596 | if (((src1 ^ src2) & (src1 ^ dst)) & (1U << 31)) { |
597 | ret = PSR_OVF; | |
598 | } | |
d4b0d468 BS |
599 | return ret; |
600 | } | |
601 | ||
d4b0d468 BS |
602 | |
603 | #ifdef TARGET_SPARC64 | |
604 | static inline uint32_t get_C_sub_xcc(target_ulong src1, target_ulong src2) | |
605 | { | |
606 | uint32_t ret = 0; | |
607 | ||
5a4bb580 RH |
608 | if (src1 < src2) { |
609 | ret = PSR_CARRY; | |
610 | } | |
611 | return ret; | |
612 | } | |
613 | ||
614 | static inline uint32_t get_C_subx_xcc(target_ulong dst, target_ulong src1, | |
615 | target_ulong src2) | |
616 | { | |
617 | uint32_t ret = 0; | |
618 | ||
619 | if (((~src1 & src2) | (dst & (~src1 | src2))) & (1ULL << 63)) { | |
620 | ret = PSR_CARRY; | |
621 | } | |
d4b0d468 BS |
622 | return ret; |
623 | } | |
624 | ||
625 | static inline uint32_t get_V_sub_xcc(target_ulong dst, target_ulong src1, | |
626 | target_ulong src2) | |
627 | { | |
628 | uint32_t ret = 0; | |
629 | ||
5a4bb580 RH |
630 | if (((src1 ^ src2) & (src1 ^ dst)) & (1ULL << 63)) { |
631 | ret = PSR_OVF; | |
632 | } | |
d4b0d468 BS |
633 | return ret; |
634 | } | |
635 | ||
636 | static uint32_t compute_all_sub_xcc(void) | |
637 | { | |
638 | uint32_t ret; | |
639 | ||
640 | ret = get_NZ_xcc(CC_DST); | |
641 | ret |= get_C_sub_xcc(CC_SRC, CC_SRC2); | |
642 | ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2); | |
643 | return ret; | |
644 | } | |
645 | ||
646 | static uint32_t compute_C_sub_xcc(void) | |
647 | { | |
648 | return get_C_sub_xcc(CC_SRC, CC_SRC2); | |
649 | } | |
650 | #endif | |
651 | ||
3e6ba503 | 652 | static uint32_t compute_all_sub(void) |
2ca1d92b BS |
653 | { |
654 | uint32_t ret; | |
655 | ||
656 | ret = get_NZ_icc(CC_DST); | |
5a4bb580 | 657 | ret |= get_C_sub_icc(CC_SRC, CC_SRC2); |
2ca1d92b BS |
658 | ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2); |
659 | return ret; | |
660 | } | |
661 | ||
3e6ba503 | 662 | static uint32_t compute_C_sub(void) |
2ca1d92b | 663 | { |
5a4bb580 | 664 | return get_C_sub_icc(CC_SRC, CC_SRC2); |
2ca1d92b BS |
665 | } |
666 | ||
667 | #ifdef TARGET_SPARC64 | |
668 | static uint32_t compute_all_subx_xcc(void) | |
669 | { | |
670 | uint32_t ret; | |
671 | ||
672 | ret = get_NZ_xcc(CC_DST); | |
5a4bb580 | 673 | ret |= get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2); |
2ca1d92b BS |
674 | ret |= get_V_sub_xcc(CC_DST, CC_SRC, CC_SRC2); |
675 | return ret; | |
676 | } | |
677 | ||
678 | static uint32_t compute_C_subx_xcc(void) | |
679 | { | |
680 | uint32_t ret; | |
681 | ||
5a4bb580 | 682 | ret = get_C_subx_xcc(CC_DST, CC_SRC, CC_SRC2); |
2ca1d92b BS |
683 | return ret; |
684 | } | |
685 | #endif | |
686 | ||
5a4bb580 | 687 | static uint32_t compute_all_subx(void) |
3b2d1e92 BS |
688 | { |
689 | uint32_t ret; | |
690 | ||
691 | ret = get_NZ_icc(CC_DST); | |
5a4bb580 | 692 | ret |= get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2); |
3b2d1e92 | 693 | ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2); |
3b2d1e92 BS |
694 | return ret; |
695 | } | |
696 | ||
5a4bb580 | 697 | static uint32_t compute_C_subx(void) |
3b2d1e92 | 698 | { |
5a4bb580 RH |
699 | uint32_t ret; |
700 | ||
701 | ret = get_C_subx_icc(CC_DST, CC_SRC, CC_SRC2); | |
702 | return ret; | |
3b2d1e92 BS |
703 | } |
704 | ||
5a4bb580 | 705 | static uint32_t compute_all_tsub(void) |
3b2d1e92 BS |
706 | { |
707 | uint32_t ret; | |
708 | ||
709 | ret = get_NZ_icc(CC_DST); | |
5a4bb580 RH |
710 | ret |= get_C_sub_icc(CC_SRC, CC_SRC2); |
711 | ret |= get_V_sub_icc(CC_DST, CC_SRC, CC_SRC2); | |
712 | ret |= get_V_tag_icc(CC_SRC, CC_SRC2); | |
3b2d1e92 BS |
713 | return ret; |
714 | } | |
715 | ||
5a4bb580 | 716 | static uint32_t compute_all_tsubtv(void) |
3b2d1e92 | 717 | { |
5a4bb580 RH |
718 | uint32_t ret; |
719 | ||
720 | ret = get_NZ_icc(CC_DST); | |
721 | ret |= get_C_sub_icc(CC_SRC, CC_SRC2); | |
722 | return ret; | |
3b2d1e92 BS |
723 | } |
724 | ||
38482a77 BS |
725 | static uint32_t compute_all_logic(void) |
726 | { | |
727 | return get_NZ_icc(CC_DST); | |
728 | } | |
729 | ||
730 | static uint32_t compute_C_logic(void) | |
731 | { | |
732 | return 0; | |
733 | } | |
734 | ||
735 | #ifdef TARGET_SPARC64 | |
736 | static uint32_t compute_all_logic_xcc(void) | |
737 | { | |
738 | return get_NZ_xcc(CC_DST); | |
739 | } | |
740 | #endif | |
741 | ||
8393617c BS |
742 | typedef struct CCTable { |
743 | uint32_t (*compute_all)(void); /* return all the flags */ | |
744 | uint32_t (*compute_c)(void); /* return the C flag */ | |
745 | } CCTable; | |
746 | ||
747 | static const CCTable icc_table[CC_OP_NB] = { | |
748 | /* CC_OP_DYNAMIC should never happen */ | |
749 | [CC_OP_FLAGS] = { compute_all_flags, compute_C_flags }, | |
6c78ea32 | 750 | [CC_OP_DIV] = { compute_all_div, compute_C_div }, |
bdf9f35d | 751 | [CC_OP_ADD] = { compute_all_add, compute_C_add }, |
5a4bb580 RH |
752 | [CC_OP_ADDX] = { compute_all_addx, compute_C_addx }, |
753 | [CC_OP_TADD] = { compute_all_tadd, compute_C_add }, | |
754 | [CC_OP_TADDTV] = { compute_all_taddtv, compute_C_add }, | |
d4b0d468 | 755 | [CC_OP_SUB] = { compute_all_sub, compute_C_sub }, |
5a4bb580 RH |
756 | [CC_OP_SUBX] = { compute_all_subx, compute_C_subx }, |
757 | [CC_OP_TSUB] = { compute_all_tsub, compute_C_sub }, | |
758 | [CC_OP_TSUBTV] = { compute_all_tsubtv, compute_C_sub }, | |
38482a77 | 759 | [CC_OP_LOGIC] = { compute_all_logic, compute_C_logic }, |
8393617c BS |
760 | }; |
761 | ||
762 | #ifdef TARGET_SPARC64 | |
763 | static const CCTable xcc_table[CC_OP_NB] = { | |
764 | /* CC_OP_DYNAMIC should never happen */ | |
765 | [CC_OP_FLAGS] = { compute_all_flags_xcc, compute_C_flags_xcc }, | |
6c78ea32 | 766 | [CC_OP_DIV] = { compute_all_logic_xcc, compute_C_logic }, |
bdf9f35d | 767 | [CC_OP_ADD] = { compute_all_add_xcc, compute_C_add_xcc }, |
789c91ef | 768 | [CC_OP_ADDX] = { compute_all_addx_xcc, compute_C_addx_xcc }, |
3b2d1e92 BS |
769 | [CC_OP_TADD] = { compute_all_add_xcc, compute_C_add_xcc }, |
770 | [CC_OP_TADDTV] = { compute_all_add_xcc, compute_C_add_xcc }, | |
d4b0d468 | 771 | [CC_OP_SUB] = { compute_all_sub_xcc, compute_C_sub_xcc }, |
2ca1d92b | 772 | [CC_OP_SUBX] = { compute_all_subx_xcc, compute_C_subx_xcc }, |
3b2d1e92 BS |
773 | [CC_OP_TSUB] = { compute_all_sub_xcc, compute_C_sub_xcc }, |
774 | [CC_OP_TSUBTV] = { compute_all_sub_xcc, compute_C_sub_xcc }, | |
38482a77 | 775 | [CC_OP_LOGIC] = { compute_all_logic_xcc, compute_C_logic }, |
8393617c BS |
776 | }; |
777 | #endif | |
778 | ||
779 | void helper_compute_psr(void) | |
780 | { | |
781 | uint32_t new_psr; | |
782 | ||
783 | new_psr = icc_table[CC_OP].compute_all(); | |
784 | env->psr = new_psr; | |
785 | #ifdef TARGET_SPARC64 | |
786 | new_psr = xcc_table[CC_OP].compute_all(); | |
787 | env->xcc = new_psr; | |
788 | #endif | |
789 | CC_OP = CC_OP_FLAGS; | |
790 | } | |
791 | ||
70c48285 | 792 | uint32_t helper_compute_C_icc(void) |
8393617c BS |
793 | { |
794 | uint32_t ret; | |
795 | ||
796 | ret = icc_table[CC_OP].compute_c() >> PSR_CARRY_SHIFT; | |
797 | return ret; | |
798 | } | |
799 | ||
5a834bb4 BS |
800 | static inline void memcpy32(target_ulong *dst, const target_ulong *src) |
801 | { | |
802 | dst[0] = src[0]; | |
803 | dst[1] = src[1]; | |
804 | dst[2] = src[2]; | |
805 | dst[3] = src[3]; | |
806 | dst[4] = src[4]; | |
807 | dst[5] = src[5]; | |
808 | dst[6] = src[6]; | |
809 | dst[7] = src[7]; | |
810 | } | |
811 | ||
812 | static void set_cwp(int new_cwp) | |
813 | { | |
814 | /* put the modified wrap registers at their proper location */ | |
815 | if (env->cwp == env->nwindows - 1) { | |
816 | memcpy32(env->regbase, env->regbase + env->nwindows * 16); | |
817 | } | |
818 | env->cwp = new_cwp; | |
819 | ||
820 | /* put the wrap registers at their temporary location */ | |
821 | if (new_cwp == env->nwindows - 1) { | |
822 | memcpy32(env->regbase + env->nwindows * 16, env->regbase); | |
823 | } | |
824 | env->regwptr = env->regbase + (new_cwp * 16); | |
825 | } | |
826 | ||
827 | void cpu_set_cwp(CPUState *env1, int new_cwp) | |
828 | { | |
829 | CPUState *saved_env; | |
830 | ||
831 | saved_env = env; | |
832 | env = env1; | |
833 | set_cwp(new_cwp); | |
834 | env = saved_env; | |
835 | } | |
836 | ||
837 | static target_ulong get_psr(void) | |
838 | { | |
839 | helper_compute_psr(); | |
840 | ||
841 | #if !defined (TARGET_SPARC64) | |
842 | return env->version | (env->psr & PSR_ICC) | | |
99ca0219 | 843 | (env->psref ? PSR_EF : 0) | |
5a834bb4 | 844 | (env->psrpil << 8) | |
99ca0219 BS |
845 | (env->psrs ? PSR_S : 0) | |
846 | (env->psrps ? PSR_PS : 0) | | |
847 | (env->psret ? PSR_ET : 0) | env->cwp; | |
5a834bb4 | 848 | #else |
2aae2b8e | 849 | return env->psr & PSR_ICC; |
5a834bb4 BS |
850 | #endif |
851 | } | |
852 | ||
853 | target_ulong cpu_get_psr(CPUState *env1) | |
854 | { | |
855 | CPUState *saved_env; | |
856 | target_ulong ret; | |
857 | ||
858 | saved_env = env; | |
859 | env = env1; | |
860 | ret = get_psr(); | |
861 | env = saved_env; | |
862 | return ret; | |
863 | } | |
864 | ||
865 | static void put_psr(target_ulong val) | |
866 | { | |
867 | env->psr = val & PSR_ICC; | |
2aae2b8e | 868 | #if !defined (TARGET_SPARC64) |
99ca0219 | 869 | env->psref = (val & PSR_EF) ? 1 : 0; |
5a834bb4 | 870 | env->psrpil = (val & PSR_PIL) >> 8; |
2aae2b8e | 871 | #endif |
5a834bb4 BS |
872 | #if ((!defined (TARGET_SPARC64)) && !defined(CONFIG_USER_ONLY)) |
873 | cpu_check_irqs(env); | |
874 | #endif | |
2aae2b8e | 875 | #if !defined (TARGET_SPARC64) |
99ca0219 BS |
876 | env->psrs = (val & PSR_S) ? 1 : 0; |
877 | env->psrps = (val & PSR_PS) ? 1 : 0; | |
878 | env->psret = (val & PSR_ET) ? 1 : 0; | |
5a834bb4 | 879 | set_cwp(val & PSR_CWP); |
2aae2b8e | 880 | #endif |
5a834bb4 BS |
881 | env->cc_op = CC_OP_FLAGS; |
882 | } | |
883 | ||
884 | void cpu_put_psr(CPUState *env1, target_ulong val) | |
885 | { | |
886 | CPUState *saved_env; | |
887 | ||
888 | saved_env = env; | |
889 | env = env1; | |
890 | put_psr(val); | |
891 | env = saved_env; | |
892 | } | |
893 | ||
894 | static int cwp_inc(int cwp) | |
895 | { | |
896 | if (unlikely(cwp >= env->nwindows)) { | |
897 | cwp -= env->nwindows; | |
898 | } | |
899 | return cwp; | |
900 | } | |
901 | ||
902 | int cpu_cwp_inc(CPUState *env1, int cwp) | |
903 | { | |
904 | CPUState *saved_env; | |
905 | target_ulong ret; | |
906 | ||
907 | saved_env = env; | |
908 | env = env1; | |
909 | ret = cwp_inc(cwp); | |
910 | env = saved_env; | |
911 | return ret; | |
912 | } | |
913 | ||
914 | static int cwp_dec(int cwp) | |
915 | { | |
916 | if (unlikely(cwp < 0)) { | |
917 | cwp += env->nwindows; | |
918 | } | |
919 | return cwp; | |
920 | } | |
921 | ||
922 | int cpu_cwp_dec(CPUState *env1, int cwp) | |
923 | { | |
924 | CPUState *saved_env; | |
925 | target_ulong ret; | |
926 | ||
927 | saved_env = env; | |
928 | env = env1; | |
929 | ret = cwp_dec(cwp); | |
930 | env = saved_env; | |
931 | return ret; | |
932 | } | |
933 | ||
99ca0219 | 934 | #if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && \ |
77f193da | 935 | defined(DEBUG_MXCC) |
952a328f BS |
936 | static void dump_mxcc(CPUState *env) |
937 | { | |
0bf9e31a BS |
938 | printf("mxccdata: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 |
939 | "\n", | |
77f193da BS |
940 | env->mxccdata[0], env->mxccdata[1], |
941 | env->mxccdata[2], env->mxccdata[3]); | |
0bf9e31a BS |
942 | printf("mxccregs: %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 |
943 | "\n" | |
944 | " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 " %016" PRIx64 | |
945 | "\n", | |
77f193da BS |
946 | env->mxccregs[0], env->mxccregs[1], |
947 | env->mxccregs[2], env->mxccregs[3], | |
948 | env->mxccregs[4], env->mxccregs[5], | |
949 | env->mxccregs[6], env->mxccregs[7]); | |
952a328f BS |
950 | } |
951 | #endif | |
952 | ||
99ca0219 | 953 | #if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)) \ |
1a2fb1c0 BS |
954 | && defined(DEBUG_ASI) |
955 | static void dump_asi(const char *txt, target_ulong addr, int asi, int size, | |
956 | uint64_t r1) | |
8543e2cf | 957 | { |
99ca0219 | 958 | switch (size) { |
8543e2cf | 959 | case 1: |
1a2fb1c0 BS |
960 | DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt, |
961 | addr, asi, r1 & 0xff); | |
8543e2cf BS |
962 | break; |
963 | case 2: | |
1a2fb1c0 BS |
964 | DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %04" PRIx64 "\n", txt, |
965 | addr, asi, r1 & 0xffff); | |
8543e2cf BS |
966 | break; |
967 | case 4: | |
1a2fb1c0 BS |
968 | DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %08" PRIx64 "\n", txt, |
969 | addr, asi, r1 & 0xffffffff); | |
8543e2cf BS |
970 | break; |
971 | case 8: | |
1a2fb1c0 BS |
972 | DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %016" PRIx64 "\n", txt, |
973 | addr, asi, r1); | |
8543e2cf BS |
974 | break; |
975 | } | |
976 | } | |
977 | #endif | |
978 | ||
1a2fb1c0 BS |
979 | #ifndef TARGET_SPARC64 |
980 | #ifndef CONFIG_USER_ONLY | |
b04d9890 FC |
981 | |
982 | ||
983 | /* Leon3 cache control */ | |
984 | ||
60f356e8 | 985 | static void leon3_cache_control_int(void) |
b04d9890 FC |
986 | { |
987 | uint32_t state = 0; | |
988 | ||
989 | if (env->cache_control & CACHE_CTRL_IF) { | |
990 | /* Instruction cache state */ | |
991 | state = env->cache_control & CACHE_STATE_MASK; | |
992 | if (state == CACHE_ENABLED) { | |
993 | state = CACHE_FROZEN; | |
994 | DPRINTF_CACHE_CONTROL("Instruction cache: freeze\n"); | |
995 | } | |
996 | ||
997 | env->cache_control &= ~CACHE_STATE_MASK; | |
998 | env->cache_control |= state; | |
999 | } | |
1000 | ||
1001 | if (env->cache_control & CACHE_CTRL_DF) { | |
1002 | /* Data cache state */ | |
1003 | state = (env->cache_control >> 2) & CACHE_STATE_MASK; | |
1004 | if (state == CACHE_ENABLED) { | |
1005 | state = CACHE_FROZEN; | |
1006 | DPRINTF_CACHE_CONTROL("Data cache: freeze\n"); | |
1007 | } | |
1008 | ||
1009 | env->cache_control &= ~(CACHE_STATE_MASK << 2); | |
1010 | env->cache_control |= (state << 2); | |
1011 | } | |
1012 | } | |
1013 | ||
1014 | static void leon3_cache_control_st(target_ulong addr, uint64_t val, int size) | |
1015 | { | |
1016 | DPRINTF_CACHE_CONTROL("st addr:%08x, val:%" PRIx64 ", size:%d\n", | |
1017 | addr, val, size); | |
1018 | ||
1019 | if (size != 4) { | |
1020 | DPRINTF_CACHE_CONTROL("32bits only\n"); | |
1021 | return; | |
1022 | } | |
1023 | ||
1024 | switch (addr) { | |
1025 | case 0x00: /* Cache control */ | |
1026 | ||
1027 | /* These values must always be read as zeros */ | |
1028 | val &= ~CACHE_CTRL_FD; | |
1029 | val &= ~CACHE_CTRL_FI; | |
1030 | val &= ~CACHE_CTRL_IB; | |
1031 | val &= ~CACHE_CTRL_IP; | |
1032 | val &= ~CACHE_CTRL_DP; | |
1033 | ||
1034 | env->cache_control = val; | |
1035 | break; | |
1036 | case 0x04: /* Instruction cache configuration */ | |
1037 | case 0x08: /* Data cache configuration */ | |
1038 | /* Read Only */ | |
1039 | break; | |
1040 | default: | |
1041 | DPRINTF_CACHE_CONTROL("write unknown register %08x\n", addr); | |
1042 | break; | |
1043 | }; | |
1044 | } | |
1045 | ||
1046 | static uint64_t leon3_cache_control_ld(target_ulong addr, int size) | |
1047 | { | |
1048 | uint64_t ret = 0; | |
1049 | ||
1050 | if (size != 4) { | |
1051 | DPRINTF_CACHE_CONTROL("32bits only\n"); | |
1052 | return 0; | |
1053 | } | |
1054 | ||
1055 | switch (addr) { | |
1056 | case 0x00: /* Cache control */ | |
1057 | ret = env->cache_control; | |
1058 | break; | |
1059 | ||
1060 | /* Configuration registers are read and only always keep those | |
1061 | predefined values */ | |
1062 | ||
1063 | case 0x04: /* Instruction cache configuration */ | |
1064 | ret = 0x10220000; | |
1065 | break; | |
1066 | case 0x08: /* Data cache configuration */ | |
1067 | ret = 0x18220000; | |
1068 | break; | |
1069 | default: | |
1070 | DPRINTF_CACHE_CONTROL("read unknown register %08x\n", addr); | |
1071 | break; | |
1072 | }; | |
60f356e8 | 1073 | DPRINTF_CACHE_CONTROL("ld addr:%08x, ret:0x%" PRIx64 ", size:%d\n", |
b04d9890 FC |
1074 | addr, ret, size); |
1075 | return ret; | |
1076 | } | |
1077 | ||
60f356e8 FC |
1078 | void leon3_irq_manager(void *irq_manager, int intno) |
1079 | { | |
1080 | leon3_irq_ack(irq_manager, intno); | |
1081 | leon3_cache_control_int(); | |
1082 | } | |
1083 | ||
1a2fb1c0 | 1084 | uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) |
e8af50a3 | 1085 | { |
1a2fb1c0 | 1086 | uint64_t ret = 0; |
8543e2cf | 1087 | #if defined(DEBUG_MXCC) || defined(DEBUG_ASI) |
1a2fb1c0 | 1088 | uint32_t last_addr = addr; |
952a328f | 1089 | #endif |
e80cfcfc | 1090 | |
c2bc0e38 | 1091 | helper_check_align(addr, size - 1); |
e80cfcfc | 1092 | switch (asi) { |
b04d9890 | 1093 | case 2: /* SuperSparc MXCC registers and Leon3 cache control */ |
1a2fb1c0 | 1094 | switch (addr) { |
b04d9890 FC |
1095 | case 0x00: /* Leon3 Cache Control */ |
1096 | case 0x08: /* Leon3 Instruction Cache config */ | |
1097 | case 0x0C: /* Leon3 Date Cache config */ | |
60f356e8 FC |
1098 | if (env->def->features & CPU_FEATURE_CACHE_CTRL) { |
1099 | ret = leon3_cache_control_ld(addr, size); | |
1100 | } | |
b04d9890 | 1101 | break; |
952a328f | 1102 | case 0x01c00a00: /* MXCC control register */ |
99ca0219 | 1103 | if (size == 8) { |
1a2fb1c0 | 1104 | ret = env->mxccregs[3]; |
99ca0219 | 1105 | } else { |
77f193da BS |
1106 | DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
1107 | size); | |
99ca0219 | 1108 | } |
952a328f BS |
1109 | break; |
1110 | case 0x01c00a04: /* MXCC control register */ | |
99ca0219 | 1111 | if (size == 4) { |
952a328f | 1112 | ret = env->mxccregs[3]; |
99ca0219 | 1113 | } else { |
77f193da BS |
1114 | DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
1115 | size); | |
99ca0219 | 1116 | } |
952a328f | 1117 | break; |
295db113 BS |
1118 | case 0x01c00c00: /* Module reset register */ |
1119 | if (size == 8) { | |
1a2fb1c0 | 1120 | ret = env->mxccregs[5]; |
99ca0219 BS |
1121 | /* should we do something here? */ |
1122 | } else { | |
77f193da BS |
1123 | DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
1124 | size); | |
99ca0219 | 1125 | } |
295db113 | 1126 | break; |
952a328f | 1127 | case 0x01c00f00: /* MBus port address register */ |
99ca0219 | 1128 | if (size == 8) { |
1a2fb1c0 | 1129 | ret = env->mxccregs[7]; |
99ca0219 | 1130 | } else { |
77f193da BS |
1131 | DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
1132 | size); | |
99ca0219 | 1133 | } |
952a328f BS |
1134 | break; |
1135 | default: | |
77f193da BS |
1136 | DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr, |
1137 | size); | |
952a328f BS |
1138 | break; |
1139 | } | |
77f193da | 1140 | DPRINTF_MXCC("asi = %d, size = %d, sign = %d, " |
9827e450 | 1141 | "addr = %08x -> ret = %" PRIx64 "," |
1a2fb1c0 | 1142 | "addr = %08x\n", asi, size, sign, last_addr, ret, addr); |
952a328f BS |
1143 | #ifdef DEBUG_MXCC |
1144 | dump_mxcc(env); | |
1145 | #endif | |
6c36d3fa | 1146 | break; |
e8af50a3 | 1147 | case 3: /* MMU probe */ |
0f8a249a BS |
1148 | { |
1149 | int mmulev; | |
1150 | ||
1a2fb1c0 | 1151 | mmulev = (addr >> 8) & 15; |
99ca0219 | 1152 | if (mmulev > 4) { |
0f8a249a | 1153 | ret = 0; |
99ca0219 | 1154 | } else { |
1a2fb1c0 | 1155 | ret = mmu_probe(env, addr, mmulev); |
99ca0219 | 1156 | } |
1a2fb1c0 BS |
1157 | DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n", |
1158 | addr, mmulev, ret); | |
0f8a249a BS |
1159 | } |
1160 | break; | |
e8af50a3 | 1161 | case 4: /* read MMU regs */ |
0f8a249a | 1162 | { |
1a2fb1c0 | 1163 | int reg = (addr >> 8) & 0x1f; |
3b46e624 | 1164 | |
0f8a249a | 1165 | ret = env->mmuregs[reg]; |
99ca0219 | 1166 | if (reg == 3) { /* Fault status cleared on read */ |
3dd9a152 | 1167 | env->mmuregs[3] = 0; |
99ca0219 | 1168 | } else if (reg == 0x13) { /* Fault status read */ |
3dd9a152 | 1169 | ret = env->mmuregs[3]; |
99ca0219 | 1170 | } else if (reg == 0x14) { /* Fault address read */ |
3dd9a152 | 1171 | ret = env->mmuregs[4]; |
99ca0219 | 1172 | } |
1a2fb1c0 | 1173 | DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret); |
0f8a249a BS |
1174 | } |
1175 | break; | |
99ca0219 BS |
1176 | case 5: /* Turbosparc ITLB Diagnostic */ |
1177 | case 6: /* Turbosparc DTLB Diagnostic */ | |
1178 | case 7: /* Turbosparc IOTLB Diagnostic */ | |
045380be | 1179 | break; |
6c36d3fa | 1180 | case 9: /* Supervisor code access */ |
99ca0219 | 1181 | switch (size) { |
6c36d3fa | 1182 | case 1: |
1a2fb1c0 | 1183 | ret = ldub_code(addr); |
6c36d3fa BS |
1184 | break; |
1185 | case 2: | |
a4e7dd52 | 1186 | ret = lduw_code(addr); |
6c36d3fa BS |
1187 | break; |
1188 | default: | |
1189 | case 4: | |
a4e7dd52 | 1190 | ret = ldl_code(addr); |
6c36d3fa BS |
1191 | break; |
1192 | case 8: | |
a4e7dd52 | 1193 | ret = ldq_code(addr); |
6c36d3fa BS |
1194 | break; |
1195 | } | |
1196 | break; | |
81ad8ba2 | 1197 | case 0xa: /* User data access */ |
99ca0219 | 1198 | switch (size) { |
81ad8ba2 | 1199 | case 1: |
1a2fb1c0 | 1200 | ret = ldub_user(addr); |
81ad8ba2 BS |
1201 | break; |
1202 | case 2: | |
a4e7dd52 | 1203 | ret = lduw_user(addr); |
81ad8ba2 BS |
1204 | break; |
1205 | default: | |
1206 | case 4: | |
a4e7dd52 | 1207 | ret = ldl_user(addr); |
81ad8ba2 BS |
1208 | break; |
1209 | case 8: | |
a4e7dd52 | 1210 | ret = ldq_user(addr); |
81ad8ba2 BS |
1211 | break; |
1212 | } | |
1213 | break; | |
1214 | case 0xb: /* Supervisor data access */ | |
99ca0219 | 1215 | switch (size) { |
81ad8ba2 | 1216 | case 1: |
1a2fb1c0 | 1217 | ret = ldub_kernel(addr); |
81ad8ba2 BS |
1218 | break; |
1219 | case 2: | |
a4e7dd52 | 1220 | ret = lduw_kernel(addr); |
81ad8ba2 BS |
1221 | break; |
1222 | default: | |
1223 | case 4: | |
a4e7dd52 | 1224 | ret = ldl_kernel(addr); |
81ad8ba2 BS |
1225 | break; |
1226 | case 8: | |
a4e7dd52 | 1227 | ret = ldq_kernel(addr); |
81ad8ba2 BS |
1228 | break; |
1229 | } | |
1230 | break; | |
6c36d3fa BS |
1231 | case 0xc: /* I-cache tag */ |
1232 | case 0xd: /* I-cache data */ | |
1233 | case 0xe: /* D-cache tag */ | |
1234 | case 0xf: /* D-cache data */ | |
1235 | break; | |
1236 | case 0x20: /* MMU passthrough */ | |
99ca0219 | 1237 | switch (size) { |
02aab46a | 1238 | case 1: |
1a2fb1c0 | 1239 | ret = ldub_phys(addr); |
02aab46a FB |
1240 | break; |
1241 | case 2: | |
a4e7dd52 | 1242 | ret = lduw_phys(addr); |
02aab46a FB |
1243 | break; |
1244 | default: | |
1245 | case 4: | |
a4e7dd52 | 1246 | ret = ldl_phys(addr); |
02aab46a | 1247 | break; |
9e61bde5 | 1248 | case 8: |
a4e7dd52 | 1249 | ret = ldq_phys(addr); |
0f8a249a | 1250 | break; |
02aab46a | 1251 | } |
0f8a249a | 1252 | break; |
7d85892b | 1253 | case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */ |
99ca0219 | 1254 | switch (size) { |
5dcb6b91 | 1255 | case 1: |
c227f099 AL |
1256 | ret = ldub_phys((target_phys_addr_t)addr |
1257 | | ((target_phys_addr_t)(asi & 0xf) << 32)); | |
5dcb6b91 BS |
1258 | break; |
1259 | case 2: | |
c227f099 AL |
1260 | ret = lduw_phys((target_phys_addr_t)addr |
1261 | | ((target_phys_addr_t)(asi & 0xf) << 32)); | |
5dcb6b91 BS |
1262 | break; |
1263 | default: | |
1264 | case 4: | |
c227f099 AL |
1265 | ret = ldl_phys((target_phys_addr_t)addr |
1266 | | ((target_phys_addr_t)(asi & 0xf) << 32)); | |
5dcb6b91 BS |
1267 | break; |
1268 | case 8: | |
c227f099 AL |
1269 | ret = ldq_phys((target_phys_addr_t)addr |
1270 | | ((target_phys_addr_t)(asi & 0xf) << 32)); | |
0f8a249a | 1271 | break; |
5dcb6b91 | 1272 | } |
0f8a249a | 1273 | break; |
99ca0219 BS |
1274 | case 0x30: /* Turbosparc secondary cache diagnostic */ |
1275 | case 0x31: /* Turbosparc RAM snoop */ | |
1276 | case 0x32: /* Turbosparc page table descriptor diagnostic */ | |
666c87aa BS |
1277 | case 0x39: /* data cache diagnostic register */ |
1278 | ret = 0; | |
1279 | break; | |
4017190e BS |
1280 | case 0x38: /* SuperSPARC MMU Breakpoint Control Registers */ |
1281 | { | |
1282 | int reg = (addr >> 8) & 3; | |
1283 | ||
99ca0219 | 1284 | switch (reg) { |
4017190e BS |
1285 | case 0: /* Breakpoint Value (Addr) */ |
1286 | ret = env->mmubpregs[reg]; | |
1287 | break; | |
1288 | case 1: /* Breakpoint Mask */ | |
1289 | ret = env->mmubpregs[reg]; | |
1290 | break; | |
1291 | case 2: /* Breakpoint Control */ | |
1292 | ret = env->mmubpregs[reg]; | |
1293 | break; | |
1294 | case 3: /* Breakpoint Status */ | |
1295 | ret = env->mmubpregs[reg]; | |
1296 | env->mmubpregs[reg] = 0ULL; | |
1297 | break; | |
1298 | } | |
0bf9e31a BS |
1299 | DPRINTF_MMU("read breakpoint reg[%d] 0x%016" PRIx64 "\n", reg, |
1300 | ret); | |
4017190e BS |
1301 | } |
1302 | break; | |
4d2c2b77 BS |
1303 | case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */ |
1304 | ret = env->mmubpctrv; | |
1305 | break; | |
1306 | case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */ | |
1307 | ret = env->mmubpctrc; | |
1308 | break; | |
1309 | case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */ | |
1310 | ret = env->mmubpctrs; | |
1311 | break; | |
1312 | case 0x4c: /* SuperSPARC MMU Breakpoint Action */ | |
1313 | ret = env->mmubpaction; | |
1314 | break; | |
045380be | 1315 | case 8: /* User code access, XXX */ |
e8af50a3 | 1316 | default: |
e18231a3 | 1317 | do_unassigned_access(addr, 0, 0, asi, size); |
0f8a249a BS |
1318 | ret = 0; |
1319 | break; | |
e8af50a3 | 1320 | } |
81ad8ba2 | 1321 | if (sign) { |
99ca0219 | 1322 | switch (size) { |
81ad8ba2 | 1323 | case 1: |
1a2fb1c0 | 1324 | ret = (int8_t) ret; |
e32664fb | 1325 | break; |
81ad8ba2 | 1326 | case 2: |
1a2fb1c0 BS |
1327 | ret = (int16_t) ret; |
1328 | break; | |
1329 | case 4: | |
1330 | ret = (int32_t) ret; | |
e32664fb | 1331 | break; |
81ad8ba2 | 1332 | default: |
81ad8ba2 BS |
1333 | break; |
1334 | } | |
1335 | } | |
8543e2cf | 1336 | #ifdef DEBUG_ASI |
1a2fb1c0 | 1337 | dump_asi("read ", last_addr, asi, size, ret); |
8543e2cf | 1338 | #endif |
1a2fb1c0 | 1339 | return ret; |
e8af50a3 FB |
1340 | } |
1341 | ||
1a2fb1c0 | 1342 | void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) |
e8af50a3 | 1343 | { |
c2bc0e38 | 1344 | helper_check_align(addr, size - 1); |
99ca0219 | 1345 | switch (asi) { |
b04d9890 | 1346 | case 2: /* SuperSparc MXCC registers and Leon3 cache control */ |
1a2fb1c0 | 1347 | switch (addr) { |
b04d9890 FC |
1348 | case 0x00: /* Leon3 Cache Control */ |
1349 | case 0x08: /* Leon3 Instruction Cache config */ | |
1350 | case 0x0C: /* Leon3 Date Cache config */ | |
60f356e8 FC |
1351 | if (env->def->features & CPU_FEATURE_CACHE_CTRL) { |
1352 | leon3_cache_control_st(addr, val, size); | |
1353 | } | |
b04d9890 FC |
1354 | break; |
1355 | ||
952a328f | 1356 | case 0x01c00000: /* MXCC stream data register 0 */ |
99ca0219 | 1357 | if (size == 8) { |
1a2fb1c0 | 1358 | env->mxccdata[0] = val; |
99ca0219 | 1359 | } else { |
77f193da BS |
1360 | DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
1361 | size); | |
99ca0219 | 1362 | } |
952a328f BS |
1363 | break; |
1364 | case 0x01c00008: /* MXCC stream data register 1 */ | |
99ca0219 | 1365 | if (size == 8) { |
1a2fb1c0 | 1366 | env->mxccdata[1] = val; |
99ca0219 | 1367 | } else { |
77f193da BS |
1368 | DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
1369 | size); | |
99ca0219 | 1370 | } |
952a328f BS |
1371 | break; |
1372 | case 0x01c00010: /* MXCC stream data register 2 */ | |
99ca0219 | 1373 | if (size == 8) { |
1a2fb1c0 | 1374 | env->mxccdata[2] = val; |
99ca0219 | 1375 | } else { |
77f193da BS |
1376 | DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
1377 | size); | |
99ca0219 | 1378 | } |
952a328f BS |
1379 | break; |
1380 | case 0x01c00018: /* MXCC stream data register 3 */ | |
99ca0219 | 1381 | if (size == 8) { |
1a2fb1c0 | 1382 | env->mxccdata[3] = val; |
99ca0219 | 1383 | } else { |
77f193da BS |
1384 | DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
1385 | size); | |
99ca0219 | 1386 | } |
952a328f BS |
1387 | break; |
1388 | case 0x01c00100: /* MXCC stream source */ | |
99ca0219 | 1389 | if (size == 8) { |
1a2fb1c0 | 1390 | env->mxccregs[0] = val; |
99ca0219 | 1391 | } else { |
77f193da BS |
1392 | DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
1393 | size); | |
99ca0219 | 1394 | } |
77f193da BS |
1395 | env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + |
1396 | 0); | |
1397 | env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + | |
1398 | 8); | |
1399 | env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + | |
1400 | 16); | |
1401 | env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + | |
1402 | 24); | |
952a328f BS |
1403 | break; |
1404 | case 0x01c00200: /* MXCC stream destination */ | |
99ca0219 | 1405 | if (size == 8) { |
1a2fb1c0 | 1406 | env->mxccregs[1] = val; |
99ca0219 | 1407 | } else { |
77f193da BS |
1408 | DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
1409 | size); | |
99ca0219 | 1410 | } |
77f193da BS |
1411 | stq_phys((env->mxccregs[1] & 0xffffffffULL) + 0, |
1412 | env->mxccdata[0]); | |
1413 | stq_phys((env->mxccregs[1] & 0xffffffffULL) + 8, | |
1414 | env->mxccdata[1]); | |
1415 | stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16, | |
1416 | env->mxccdata[2]); | |
1417 | stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24, | |
1418 | env->mxccdata[3]); | |
952a328f BS |
1419 | break; |
1420 | case 0x01c00a00: /* MXCC control register */ | |
99ca0219 | 1421 | if (size == 8) { |
1a2fb1c0 | 1422 | env->mxccregs[3] = val; |
99ca0219 | 1423 | } else { |
77f193da BS |
1424 | DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
1425 | size); | |
99ca0219 | 1426 | } |
952a328f BS |
1427 | break; |
1428 | case 0x01c00a04: /* MXCC control register */ | |
99ca0219 | 1429 | if (size == 4) { |
9f4576f0 | 1430 | env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL) |
77f193da | 1431 | | val; |
99ca0219 | 1432 | } else { |
77f193da BS |
1433 | DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
1434 | size); | |
99ca0219 | 1435 | } |
952a328f BS |
1436 | break; |
1437 | case 0x01c00e00: /* MXCC error register */ | |
99ca0219 BS |
1438 | /* writing a 1 bit clears the error */ |
1439 | if (size == 8) { | |
1a2fb1c0 | 1440 | env->mxccregs[6] &= ~val; |
99ca0219 | 1441 | } else { |
77f193da BS |
1442 | DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
1443 | size); | |
99ca0219 | 1444 | } |
952a328f BS |
1445 | break; |
1446 | case 0x01c00f00: /* MBus port address register */ | |
99ca0219 | 1447 | if (size == 8) { |
1a2fb1c0 | 1448 | env->mxccregs[7] = val; |
99ca0219 | 1449 | } else { |
77f193da BS |
1450 | DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
1451 | size); | |
99ca0219 | 1452 | } |
952a328f BS |
1453 | break; |
1454 | default: | |
77f193da BS |
1455 | DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr, |
1456 | size); | |
952a328f BS |
1457 | break; |
1458 | } | |
9827e450 BS |
1459 | DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %" PRIx64 "\n", |
1460 | asi, size, addr, val); | |
952a328f BS |
1461 | #ifdef DEBUG_MXCC |
1462 | dump_mxcc(env); | |
1463 | #endif | |
6c36d3fa | 1464 | break; |
e8af50a3 | 1465 | case 3: /* MMU flush */ |
0f8a249a BS |
1466 | { |
1467 | int mmulev; | |
e80cfcfc | 1468 | |
1a2fb1c0 | 1469 | mmulev = (addr >> 8) & 15; |
952a328f | 1470 | DPRINTF_MMU("mmu flush level %d\n", mmulev); |
0f8a249a | 1471 | switch (mmulev) { |
99ca0219 | 1472 | case 0: /* flush page */ |
1a2fb1c0 | 1473 | tlb_flush_page(env, addr & 0xfffff000); |
0f8a249a | 1474 | break; |
99ca0219 BS |
1475 | case 1: /* flush segment (256k) */ |
1476 | case 2: /* flush region (16M) */ | |
1477 | case 3: /* flush context (4G) */ | |
1478 | case 4: /* flush entire */ | |
0f8a249a BS |
1479 | tlb_flush(env, 1); |
1480 | break; | |
1481 | default: | |
1482 | break; | |
1483 | } | |
55754d9e | 1484 | #ifdef DEBUG_MMU |
d41160a3 | 1485 | dump_mmu(stdout, fprintf, env); |
55754d9e | 1486 | #endif |
0f8a249a | 1487 | } |
8543e2cf | 1488 | break; |
e8af50a3 | 1489 | case 4: /* write MMU regs */ |
0f8a249a | 1490 | { |
1a2fb1c0 | 1491 | int reg = (addr >> 8) & 0x1f; |
0f8a249a | 1492 | uint32_t oldreg; |
3b46e624 | 1493 | |
0f8a249a | 1494 | oldreg = env->mmuregs[reg]; |
99ca0219 BS |
1495 | switch (reg) { |
1496 | case 0: /* Control Register */ | |
3dd9a152 | 1497 | env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) | |
99ca0219 BS |
1498 | (val & 0x00ffffff); |
1499 | /* Mappings generated during no-fault mode or MMU | |
1500 | disabled mode are invalid in normal mode */ | |
5578ceab | 1501 | if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) != |
99ca0219 | 1502 | (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm))) { |
55754d9e | 1503 | tlb_flush(env, 1); |
99ca0219 | 1504 | } |
55754d9e | 1505 | break; |
99ca0219 | 1506 | case 1: /* Context Table Pointer Register */ |
5578ceab | 1507 | env->mmuregs[reg] = val & env->def->mmu_ctpr_mask; |
3deaeab7 | 1508 | break; |
99ca0219 | 1509 | case 2: /* Context Register */ |
5578ceab | 1510 | env->mmuregs[reg] = val & env->def->mmu_cxr_mask; |
55754d9e FB |
1511 | if (oldreg != env->mmuregs[reg]) { |
1512 | /* we flush when the MMU context changes because | |
1513 | QEMU has no MMU context support */ | |
1514 | tlb_flush(env, 1); | |
1515 | } | |
1516 | break; | |
99ca0219 BS |
1517 | case 3: /* Synchronous Fault Status Register with Clear */ |
1518 | case 4: /* Synchronous Fault Address Register */ | |
3deaeab7 | 1519 | break; |
99ca0219 | 1520 | case 0x10: /* TLB Replacement Control Register */ |
5578ceab | 1521 | env->mmuregs[reg] = val & env->def->mmu_trcr_mask; |
55754d9e | 1522 | break; |
99ca0219 BS |
1523 | case 0x13: /* Synchronous Fault Status Register with Read |
1524 | and Clear */ | |
5578ceab | 1525 | env->mmuregs[3] = val & env->def->mmu_sfsr_mask; |
3dd9a152 | 1526 | break; |
99ca0219 | 1527 | case 0x14: /* Synchronous Fault Address Register */ |
1a2fb1c0 | 1528 | env->mmuregs[4] = val; |
3dd9a152 | 1529 | break; |
55754d9e | 1530 | default: |
1a2fb1c0 | 1531 | env->mmuregs[reg] = val; |
55754d9e FB |
1532 | break; |
1533 | } | |
55754d9e | 1534 | if (oldreg != env->mmuregs[reg]) { |
77f193da BS |
1535 | DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n", |
1536 | reg, oldreg, env->mmuregs[reg]); | |
55754d9e | 1537 | } |
952a328f | 1538 | #ifdef DEBUG_MMU |
d41160a3 | 1539 | dump_mmu(stdout, fprintf, env); |
55754d9e | 1540 | #endif |
0f8a249a | 1541 | } |
8543e2cf | 1542 | break; |
99ca0219 BS |
1543 | case 5: /* Turbosparc ITLB Diagnostic */ |
1544 | case 6: /* Turbosparc DTLB Diagnostic */ | |
1545 | case 7: /* Turbosparc IOTLB Diagnostic */ | |
045380be | 1546 | break; |
81ad8ba2 | 1547 | case 0xa: /* User data access */ |
99ca0219 | 1548 | switch (size) { |
81ad8ba2 | 1549 | case 1: |
1a2fb1c0 | 1550 | stb_user(addr, val); |
81ad8ba2 BS |
1551 | break; |
1552 | case 2: | |
a4e7dd52 | 1553 | stw_user(addr, val); |
81ad8ba2 BS |
1554 | break; |
1555 | default: | |
1556 | case 4: | |
a4e7dd52 | 1557 | stl_user(addr, val); |
81ad8ba2 BS |
1558 | break; |
1559 | case 8: | |
a4e7dd52 | 1560 | stq_user(addr, val); |
81ad8ba2 BS |
1561 | break; |
1562 | } | |
1563 | break; | |
1564 | case 0xb: /* Supervisor data access */ | |
99ca0219 | 1565 | switch (size) { |
81ad8ba2 | 1566 | case 1: |
1a2fb1c0 | 1567 | stb_kernel(addr, val); |
81ad8ba2 BS |
1568 | break; |
1569 | case 2: | |
a4e7dd52 | 1570 | stw_kernel(addr, val); |
81ad8ba2 BS |
1571 | break; |
1572 | default: | |
1573 | case 4: | |
a4e7dd52 | 1574 | stl_kernel(addr, val); |
81ad8ba2 BS |
1575 | break; |
1576 | case 8: | |
a4e7dd52 | 1577 | stq_kernel(addr, val); |
81ad8ba2 BS |
1578 | break; |
1579 | } | |
1580 | break; | |
6c36d3fa BS |
1581 | case 0xc: /* I-cache tag */ |
1582 | case 0xd: /* I-cache data */ | |
1583 | case 0xe: /* D-cache tag */ | |
1584 | case 0xf: /* D-cache data */ | |
1585 | case 0x10: /* I/D-cache flush page */ | |
1586 | case 0x11: /* I/D-cache flush segment */ | |
1587 | case 0x12: /* I/D-cache flush region */ | |
1588 | case 0x13: /* I/D-cache flush context */ | |
1589 | case 0x14: /* I/D-cache flush user */ | |
1590 | break; | |
e80cfcfc | 1591 | case 0x17: /* Block copy, sta access */ |
0f8a249a | 1592 | { |
99ca0219 BS |
1593 | /* val = src |
1594 | addr = dst | |
1595 | copy 32 bytes */ | |
6c36d3fa | 1596 | unsigned int i; |
1a2fb1c0 | 1597 | uint32_t src = val & ~3, dst = addr & ~3, temp; |
3b46e624 | 1598 | |
6c36d3fa BS |
1599 | for (i = 0; i < 32; i += 4, src += 4, dst += 4) { |
1600 | temp = ldl_kernel(src); | |
1601 | stl_kernel(dst, temp); | |
1602 | } | |
0f8a249a | 1603 | } |
8543e2cf | 1604 | break; |
e80cfcfc | 1605 | case 0x1f: /* Block fill, stda access */ |
0f8a249a | 1606 | { |
99ca0219 BS |
1607 | /* addr = dst |
1608 | fill 32 bytes with val */ | |
6c36d3fa | 1609 | unsigned int i; |
1a2fb1c0 | 1610 | uint32_t dst = addr & 7; |
6c36d3fa | 1611 | |
99ca0219 | 1612 | for (i = 0; i < 32; i += 8, dst += 8) { |
6c36d3fa | 1613 | stq_kernel(dst, val); |
99ca0219 | 1614 | } |
0f8a249a | 1615 | } |
8543e2cf | 1616 | break; |
6c36d3fa | 1617 | case 0x20: /* MMU passthrough */ |
0f8a249a | 1618 | { |
99ca0219 | 1619 | switch (size) { |
02aab46a | 1620 | case 1: |
1a2fb1c0 | 1621 | stb_phys(addr, val); |
02aab46a FB |
1622 | break; |
1623 | case 2: | |
a4e7dd52 | 1624 | stw_phys(addr, val); |
02aab46a FB |
1625 | break; |
1626 | case 4: | |
1627 | default: | |
a4e7dd52 | 1628 | stl_phys(addr, val); |
02aab46a | 1629 | break; |
9e61bde5 | 1630 | case 8: |
a4e7dd52 | 1631 | stq_phys(addr, val); |
9e61bde5 | 1632 | break; |
02aab46a | 1633 | } |
0f8a249a | 1634 | } |
8543e2cf | 1635 | break; |
045380be | 1636 | case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */ |
0f8a249a | 1637 | { |
99ca0219 | 1638 | switch (size) { |
5dcb6b91 | 1639 | case 1: |
c227f099 AL |
1640 | stb_phys((target_phys_addr_t)addr |
1641 | | ((target_phys_addr_t)(asi & 0xf) << 32), val); | |
5dcb6b91 BS |
1642 | break; |
1643 | case 2: | |
c227f099 AL |
1644 | stw_phys((target_phys_addr_t)addr |
1645 | | ((target_phys_addr_t)(asi & 0xf) << 32), val); | |
5dcb6b91 BS |
1646 | break; |
1647 | case 4: | |
1648 | default: | |
c227f099 AL |
1649 | stl_phys((target_phys_addr_t)addr |
1650 | | ((target_phys_addr_t)(asi & 0xf) << 32), val); | |
5dcb6b91 BS |
1651 | break; |
1652 | case 8: | |
c227f099 AL |
1653 | stq_phys((target_phys_addr_t)addr |
1654 | | ((target_phys_addr_t)(asi & 0xf) << 32), val); | |
5dcb6b91 BS |
1655 | break; |
1656 | } | |
0f8a249a | 1657 | } |
8543e2cf | 1658 | break; |
99ca0219 BS |
1659 | case 0x30: /* store buffer tags or Turbosparc secondary cache diagnostic */ |
1660 | case 0x31: /* store buffer data, Ross RT620 I-cache flush or | |
1661 | Turbosparc snoop RAM */ | |
1662 | case 0x32: /* store buffer control or Turbosparc page table | |
1663 | descriptor diagnostic */ | |
6c36d3fa BS |
1664 | case 0x36: /* I-cache flash clear */ |
1665 | case 0x37: /* D-cache flash clear */ | |
1666 | break; | |
4017190e BS |
1667 | case 0x38: /* SuperSPARC MMU Breakpoint Control Registers*/ |
1668 | { | |
1669 | int reg = (addr >> 8) & 3; | |
1670 | ||
99ca0219 | 1671 | switch (reg) { |
4017190e BS |
1672 | case 0: /* Breakpoint Value (Addr) */ |
1673 | env->mmubpregs[reg] = (val & 0xfffffffffULL); | |
1674 | break; | |
1675 | case 1: /* Breakpoint Mask */ | |
1676 | env->mmubpregs[reg] = (val & 0xfffffffffULL); | |
1677 | break; | |
1678 | case 2: /* Breakpoint Control */ | |
1679 | env->mmubpregs[reg] = (val & 0x7fULL); | |
1680 | break; | |
1681 | case 3: /* Breakpoint Status */ | |
1682 | env->mmubpregs[reg] = (val & 0xfULL); | |
1683 | break; | |
1684 | } | |
0bf9e31a | 1685 | DPRINTF_MMU("write breakpoint reg[%d] 0x%016x\n", reg, |
4017190e BS |
1686 | env->mmuregs[reg]); |
1687 | } | |
1688 | break; | |
4d2c2b77 BS |
1689 | case 0x49: /* SuperSPARC MMU Counter Breakpoint Value */ |
1690 | env->mmubpctrv = val & 0xffffffff; | |
1691 | break; | |
1692 | case 0x4a: /* SuperSPARC MMU Counter Breakpoint Control */ | |
1693 | env->mmubpctrc = val & 0x3; | |
1694 | break; | |
1695 | case 0x4b: /* SuperSPARC MMU Counter Breakpoint Status */ | |
1696 | env->mmubpctrs = val & 0x3; | |
1697 | break; | |
1698 | case 0x4c: /* SuperSPARC MMU Breakpoint Action */ | |
1699 | env->mmubpaction = val & 0x1fff; | |
1700 | break; | |
045380be | 1701 | case 8: /* User code access, XXX */ |
6c36d3fa | 1702 | case 9: /* Supervisor code access, XXX */ |
e8af50a3 | 1703 | default: |
e18231a3 | 1704 | do_unassigned_access(addr, 1, 0, asi, size); |
8543e2cf | 1705 | break; |
e8af50a3 | 1706 | } |
8543e2cf | 1707 | #ifdef DEBUG_ASI |
1a2fb1c0 | 1708 | dump_asi("write", addr, asi, size, val); |
8543e2cf | 1709 | #endif |
e8af50a3 FB |
1710 | } |
1711 | ||
81ad8ba2 BS |
1712 | #endif /* CONFIG_USER_ONLY */ |
1713 | #else /* TARGET_SPARC64 */ | |
1714 | ||
1715 | #ifdef CONFIG_USER_ONLY | |
1a2fb1c0 | 1716 | uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) |
81ad8ba2 BS |
1717 | { |
1718 | uint64_t ret = 0; | |
1a2fb1c0 BS |
1719 | #if defined(DEBUG_ASI) |
1720 | target_ulong last_addr = addr; | |
1721 | #endif | |
81ad8ba2 | 1722 | |
99ca0219 | 1723 | if (asi < 0x80) { |
bc265319 | 1724 | helper_raise_exception(env, TT_PRIV_ACT); |
99ca0219 | 1725 | } |
81ad8ba2 | 1726 | |
c2bc0e38 | 1727 | helper_check_align(addr, size - 1); |
1295001c | 1728 | addr = asi_address_mask(env, asi, addr); |
c2bc0e38 | 1729 | |
81ad8ba2 | 1730 | switch (asi) { |
99ca0219 BS |
1731 | case 0x82: /* Primary no-fault */ |
1732 | case 0x8a: /* Primary no-fault LE */ | |
e83ce550 BS |
1733 | if (page_check_range(addr, size, PAGE_READ) == -1) { |
1734 | #ifdef DEBUG_ASI | |
1735 | dump_asi("read ", last_addr, asi, size, ret); | |
1736 | #endif | |
1737 | return 0; | |
1738 | } | |
99ca0219 BS |
1739 | /* Fall through */ |
1740 | case 0x80: /* Primary */ | |
1741 | case 0x88: /* Primary LE */ | |
81ad8ba2 | 1742 | { |
99ca0219 | 1743 | switch (size) { |
81ad8ba2 | 1744 | case 1: |
1a2fb1c0 | 1745 | ret = ldub_raw(addr); |
81ad8ba2 BS |
1746 | break; |
1747 | case 2: | |
a4e7dd52 | 1748 | ret = lduw_raw(addr); |
81ad8ba2 BS |
1749 | break; |
1750 | case 4: | |
a4e7dd52 | 1751 | ret = ldl_raw(addr); |
81ad8ba2 BS |
1752 | break; |
1753 | default: | |
1754 | case 8: | |
a4e7dd52 | 1755 | ret = ldq_raw(addr); |
81ad8ba2 BS |
1756 | break; |
1757 | } | |
1758 | } | |
1759 | break; | |
99ca0219 BS |
1760 | case 0x83: /* Secondary no-fault */ |
1761 | case 0x8b: /* Secondary no-fault LE */ | |
e83ce550 BS |
1762 | if (page_check_range(addr, size, PAGE_READ) == -1) { |
1763 | #ifdef DEBUG_ASI | |
1764 | dump_asi("read ", last_addr, asi, size, ret); | |
1765 | #endif | |
1766 | return 0; | |
1767 | } | |
99ca0219 BS |
1768 | /* Fall through */ |
1769 | case 0x81: /* Secondary */ | |
1770 | case 0x89: /* Secondary LE */ | |
1771 | /* XXX */ | |
81ad8ba2 BS |
1772 | break; |
1773 | default: | |
1774 | break; | |
1775 | } | |
1776 | ||
1777 | /* Convert from little endian */ | |
1778 | switch (asi) { | |
99ca0219 BS |
1779 | case 0x88: /* Primary LE */ |
1780 | case 0x89: /* Secondary LE */ | |
1781 | case 0x8a: /* Primary no-fault LE */ | |
1782 | case 0x8b: /* Secondary no-fault LE */ | |
1783 | switch (size) { | |
81ad8ba2 BS |
1784 | case 2: |
1785 | ret = bswap16(ret); | |
e32664fb | 1786 | break; |
81ad8ba2 BS |
1787 | case 4: |
1788 | ret = bswap32(ret); | |
e32664fb | 1789 | break; |
81ad8ba2 BS |
1790 | case 8: |
1791 | ret = bswap64(ret); | |
e32664fb | 1792 | break; |
81ad8ba2 BS |
1793 | default: |
1794 | break; | |
1795 | } | |
1796 | default: | |
1797 | break; | |
1798 | } | |
1799 | ||
1800 | /* Convert to signed number */ | |
1801 | if (sign) { | |
99ca0219 | 1802 | switch (size) { |
81ad8ba2 BS |
1803 | case 1: |
1804 | ret = (int8_t) ret; | |
e32664fb | 1805 | break; |
81ad8ba2 BS |
1806 | case 2: |
1807 | ret = (int16_t) ret; | |
e32664fb | 1808 | break; |
81ad8ba2 BS |
1809 | case 4: |
1810 | ret = (int32_t) ret; | |
e32664fb | 1811 | break; |
81ad8ba2 BS |
1812 | default: |
1813 | break; | |
1814 | } | |
1815 | } | |
1a2fb1c0 BS |
1816 | #ifdef DEBUG_ASI |
1817 | dump_asi("read ", last_addr, asi, size, ret); | |
1818 | #endif | |
1819 | return ret; | |
81ad8ba2 BS |
1820 | } |
1821 | ||
1a2fb1c0 | 1822 | void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) |
81ad8ba2 | 1823 | { |
1a2fb1c0 BS |
1824 | #ifdef DEBUG_ASI |
1825 | dump_asi("write", addr, asi, size, val); | |
1826 | #endif | |
99ca0219 | 1827 | if (asi < 0x80) { |
bc265319 | 1828 | helper_raise_exception(env, TT_PRIV_ACT); |
99ca0219 | 1829 | } |
81ad8ba2 | 1830 | |
c2bc0e38 | 1831 | helper_check_align(addr, size - 1); |
1295001c | 1832 | addr = asi_address_mask(env, asi, addr); |
c2bc0e38 | 1833 | |
81ad8ba2 BS |
1834 | /* Convert to little endian */ |
1835 | switch (asi) { | |
99ca0219 BS |
1836 | case 0x88: /* Primary LE */ |
1837 | case 0x89: /* Secondary LE */ | |
1838 | switch (size) { | |
81ad8ba2 | 1839 | case 2: |
5b0f0bec | 1840 | val = bswap16(val); |
e32664fb | 1841 | break; |
81ad8ba2 | 1842 | case 4: |
5b0f0bec | 1843 | val = bswap32(val); |
e32664fb | 1844 | break; |
81ad8ba2 | 1845 | case 8: |
5b0f0bec | 1846 | val = bswap64(val); |
e32664fb | 1847 | break; |
81ad8ba2 BS |
1848 | default: |
1849 | break; | |
1850 | } | |
1851 | default: | |
1852 | break; | |
1853 | } | |
1854 | ||
99ca0219 BS |
1855 | switch (asi) { |
1856 | case 0x80: /* Primary */ | |
1857 | case 0x88: /* Primary LE */ | |
81ad8ba2 | 1858 | { |
99ca0219 | 1859 | switch (size) { |
81ad8ba2 | 1860 | case 1: |
1a2fb1c0 | 1861 | stb_raw(addr, val); |
81ad8ba2 BS |
1862 | break; |
1863 | case 2: | |
a4e7dd52 | 1864 | stw_raw(addr, val); |
81ad8ba2 BS |
1865 | break; |
1866 | case 4: | |
a4e7dd52 | 1867 | stl_raw(addr, val); |
81ad8ba2 BS |
1868 | break; |
1869 | case 8: | |
1870 | default: | |
a4e7dd52 | 1871 | stq_raw(addr, val); |
81ad8ba2 BS |
1872 | break; |
1873 | } | |
1874 | } | |
1875 | break; | |
99ca0219 BS |
1876 | case 0x81: /* Secondary */ |
1877 | case 0x89: /* Secondary LE */ | |
1878 | /* XXX */ | |
81ad8ba2 BS |
1879 | return; |
1880 | ||
99ca0219 BS |
1881 | case 0x82: /* Primary no-fault, RO */ |
1882 | case 0x83: /* Secondary no-fault, RO */ | |
1883 | case 0x8a: /* Primary no-fault LE, RO */ | |
1884 | case 0x8b: /* Secondary no-fault LE, RO */ | |
81ad8ba2 | 1885 | default: |
e18231a3 | 1886 | do_unassigned_access(addr, 1, 0, 1, size); |
81ad8ba2 BS |
1887 | return; |
1888 | } | |
1889 | } | |
1890 | ||
1891 | #else /* CONFIG_USER_ONLY */ | |
3475187d | 1892 | |
1a2fb1c0 | 1893 | uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) |
3475187d | 1894 | { |
83469015 | 1895 | uint64_t ret = 0; |
1a2fb1c0 BS |
1896 | #if defined(DEBUG_ASI) |
1897 | target_ulong last_addr = addr; | |
1898 | #endif | |
3475187d | 1899 | |
01b5d4e5 IK |
1900 | asi &= 0xff; |
1901 | ||
6f27aba6 | 1902 | if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) |
2aae2b8e | 1903 | || (cpu_has_hypervisor(env) |
5578ceab | 1904 | && asi >= 0x30 && asi < 0x80 |
99ca0219 | 1905 | && !(env->hpstate & HS_PRIV))) { |
bc265319 | 1906 | helper_raise_exception(env, TT_PRIV_ACT); |
99ca0219 | 1907 | } |
3475187d | 1908 | |
c2bc0e38 | 1909 | helper_check_align(addr, size - 1); |
1295001c IK |
1910 | addr = asi_address_mask(env, asi, addr); |
1911 | ||
b7785d20 TS |
1912 | /* process nonfaulting loads first */ |
1913 | if ((asi & 0xf6) == 0x82) { | |
1914 | int mmu_idx; | |
1915 | ||
1916 | /* secondary space access has lowest asi bit equal to 1 */ | |
1917 | if (env->pstate & PS_PRIV) { | |
1918 | mmu_idx = (asi & 1) ? MMU_KERNEL_SECONDARY_IDX : MMU_KERNEL_IDX; | |
1919 | } else { | |
1920 | mmu_idx = (asi & 1) ? MMU_USER_SECONDARY_IDX : MMU_USER_IDX; | |
1921 | } | |
2065061e | 1922 | |
b7785d20 | 1923 | if (cpu_get_phys_page_nofault(env, addr, mmu_idx) == -1ULL) { |
e83ce550 | 1924 | #ifdef DEBUG_ASI |
b7785d20 | 1925 | dump_asi("read ", last_addr, asi, size, ret); |
e83ce550 | 1926 | #endif |
b7785d20 | 1927 | /* env->exception_index is set in get_physical_address_data(). */ |
bc265319 | 1928 | helper_raise_exception(env, env->exception_index); |
e83ce550 | 1929 | } |
b7785d20 TS |
1930 | |
1931 | /* convert nonfaulting load ASIs to normal load ASIs */ | |
1932 | asi &= ~0x02; | |
1933 | } | |
1934 | ||
1935 | switch (asi) { | |
99ca0219 BS |
1936 | case 0x10: /* As if user primary */ |
1937 | case 0x11: /* As if user secondary */ | |
1938 | case 0x18: /* As if user primary LE */ | |
1939 | case 0x19: /* As if user secondary LE */ | |
1940 | case 0x80: /* Primary */ | |
1941 | case 0x81: /* Secondary */ | |
1942 | case 0x88: /* Primary LE */ | |
1943 | case 0x89: /* Secondary LE */ | |
1944 | case 0xe2: /* UA2007 Primary block init */ | |
1945 | case 0xe3: /* UA2007 Secondary block init */ | |
81ad8ba2 | 1946 | if ((asi & 0x80) && (env->pstate & PS_PRIV)) { |
2aae2b8e | 1947 | if (cpu_hypervisor_mode(env)) { |
99ca0219 | 1948 | switch (size) { |
6f27aba6 | 1949 | case 1: |
1a2fb1c0 | 1950 | ret = ldub_hypv(addr); |
6f27aba6 BS |
1951 | break; |
1952 | case 2: | |
a4e7dd52 | 1953 | ret = lduw_hypv(addr); |
6f27aba6 BS |
1954 | break; |
1955 | case 4: | |
a4e7dd52 | 1956 | ret = ldl_hypv(addr); |
6f27aba6 BS |
1957 | break; |
1958 | default: | |
1959 | case 8: | |
a4e7dd52 | 1960 | ret = ldq_hypv(addr); |
6f27aba6 BS |
1961 | break; |
1962 | } | |
1963 | } else { | |
2065061e IK |
1964 | /* secondary space access has lowest asi bit equal to 1 */ |
1965 | if (asi & 1) { | |
99ca0219 | 1966 | switch (size) { |
2065061e IK |
1967 | case 1: |
1968 | ret = ldub_kernel_secondary(addr); | |
1969 | break; | |
1970 | case 2: | |
1971 | ret = lduw_kernel_secondary(addr); | |
1972 | break; | |
1973 | case 4: | |
1974 | ret = ldl_kernel_secondary(addr); | |
1975 | break; | |
1976 | default: | |
1977 | case 8: | |
1978 | ret = ldq_kernel_secondary(addr); | |
1979 | break; | |
1980 | } | |
1981 | } else { | |
99ca0219 | 1982 | switch (size) { |
2065061e IK |
1983 | case 1: |
1984 | ret = ldub_kernel(addr); | |
1985 | break; | |
1986 | case 2: | |
1987 | ret = lduw_kernel(addr); | |
1988 | break; | |
1989 | case 4: | |
1990 | ret = ldl_kernel(addr); | |
1991 | break; | |
1992 | default: | |
1993 | case 8: | |
1994 | ret = ldq_kernel(addr); | |
1995 | break; | |
1996 | } | |
1997 | } | |
1998 | } | |
1999 | } else { | |
2000 | /* secondary space access has lowest asi bit equal to 1 */ | |
2001 | if (asi & 1) { | |
99ca0219 | 2002 | switch (size) { |
6f27aba6 | 2003 | case 1: |
2065061e | 2004 | ret = ldub_user_secondary(addr); |
6f27aba6 BS |
2005 | break; |
2006 | case 2: | |
2065061e | 2007 | ret = lduw_user_secondary(addr); |
6f27aba6 BS |
2008 | break; |
2009 | case 4: | |
2065061e | 2010 | ret = ldl_user_secondary(addr); |
6f27aba6 BS |
2011 | break; |
2012 | default: | |
2013 | case 8: | |
2065061e IK |
2014 | ret = ldq_user_secondary(addr); |
2015 | break; | |
2016 | } | |
2017 | } else { | |
99ca0219 | 2018 | switch (size) { |
2065061e IK |
2019 | case 1: |
2020 | ret = ldub_user(addr); | |
2021 | break; | |
2022 | case 2: | |
2023 | ret = lduw_user(addr); | |
2024 | break; | |
2025 | case 4: | |
2026 | ret = ldl_user(addr); | |
2027 | break; | |
2028 | default: | |
2029 | case 8: | |
2030 | ret = ldq_user(addr); | |
6f27aba6 BS |
2031 | break; |
2032 | } | |
81ad8ba2 BS |
2033 | } |
2034 | } | |
2035 | break; | |
99ca0219 BS |
2036 | case 0x14: /* Bypass */ |
2037 | case 0x15: /* Bypass, non-cacheable */ | |
2038 | case 0x1c: /* Bypass LE */ | |
2039 | case 0x1d: /* Bypass, non-cacheable LE */ | |
0f8a249a | 2040 | { |
99ca0219 | 2041 | switch (size) { |
02aab46a | 2042 | case 1: |
1a2fb1c0 | 2043 | ret = ldub_phys(addr); |
02aab46a FB |
2044 | break; |
2045 | case 2: | |
a4e7dd52 | 2046 | ret = lduw_phys(addr); |
02aab46a FB |
2047 | break; |
2048 | case 4: | |
a4e7dd52 | 2049 | ret = ldl_phys(addr); |
02aab46a FB |
2050 | break; |
2051 | default: | |
2052 | case 8: | |
a4e7dd52 | 2053 | ret = ldq_phys(addr); |
02aab46a FB |
2054 | break; |
2055 | } | |
0f8a249a BS |
2056 | break; |
2057 | } | |
99ca0219 BS |
2058 | case 0x24: /* Nucleus quad LDD 128 bit atomic */ |
2059 | case 0x2c: /* Nucleus quad LDD 128 bit atomic LE | |
2060 | Only ldda allowed */ | |
bc265319 | 2061 | helper_raise_exception(env, TT_ILL_INSN); |
db166940 | 2062 | return 0; |
99ca0219 BS |
2063 | case 0x04: /* Nucleus */ |
2064 | case 0x0c: /* Nucleus Little Endian (LE) */ | |
2065 | { | |
2066 | switch (size) { | |
2067 | case 1: | |
2068 | ret = ldub_nucleus(addr); | |
2069 | break; | |
2070 | case 2: | |
2071 | ret = lduw_nucleus(addr); | |
2072 | break; | |
2073 | case 4: | |
2074 | ret = ldl_nucleus(addr); | |
2075 | break; | |
2076 | default: | |
2077 | case 8: | |
2078 | ret = ldq_nucleus(addr); | |
2079 | break; | |
2080 | } | |
2065061e IK |
2081 | break; |
2082 | } | |
99ca0219 BS |
2083 | case 0x4a: /* UPA config */ |
2084 | /* XXX */ | |
2065061e | 2085 | break; |
99ca0219 | 2086 | case 0x45: /* LSU */ |
0f8a249a BS |
2087 | ret = env->lsu; |
2088 | break; | |
99ca0219 | 2089 | case 0x50: /* I-MMU regs */ |
0f8a249a | 2090 | { |
1a2fb1c0 | 2091 | int reg = (addr >> 3) & 0xf; |
3475187d | 2092 | |
697a77e6 | 2093 | if (reg == 0) { |
99ca0219 | 2094 | /* I-TSB Tag Target register */ |
6e8e7d4c | 2095 | ret = ultrasparc_tag_target(env->immu.tag_access); |
697a77e6 IK |
2096 | } else { |
2097 | ret = env->immuregs[reg]; | |
2098 | } | |
2099 | ||
0f8a249a BS |
2100 | break; |
2101 | } | |
99ca0219 | 2102 | case 0x51: /* I-MMU 8k TSB pointer */ |
697a77e6 | 2103 | { |
99ca0219 BS |
2104 | /* env->immuregs[5] holds I-MMU TSB register value |
2105 | env->immuregs[6] holds I-MMU Tag Access register value */ | |
6e8e7d4c | 2106 | ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access, |
697a77e6 IK |
2107 | 8*1024); |
2108 | break; | |
2109 | } | |
99ca0219 | 2110 | case 0x52: /* I-MMU 64k TSB pointer */ |
697a77e6 | 2111 | { |
99ca0219 BS |
2112 | /* env->immuregs[5] holds I-MMU TSB register value |
2113 | env->immuregs[6] holds I-MMU Tag Access register value */ | |
6e8e7d4c | 2114 | ret = ultrasparc_tsb_pointer(env->immu.tsb, env->immu.tag_access, |
697a77e6 IK |
2115 | 64*1024); |
2116 | break; | |
2117 | } | |
99ca0219 | 2118 | case 0x55: /* I-MMU data access */ |
a5a52cf2 BS |
2119 | { |
2120 | int reg = (addr >> 3) & 0x3f; | |
2121 | ||
6e8e7d4c | 2122 | ret = env->itlb[reg].tte; |
a5a52cf2 BS |
2123 | break; |
2124 | } | |
99ca0219 | 2125 | case 0x56: /* I-MMU tag read */ |
0f8a249a | 2126 | { |
43e9e742 | 2127 | int reg = (addr >> 3) & 0x3f; |
0f8a249a | 2128 | |
6e8e7d4c | 2129 | ret = env->itlb[reg].tag; |
0f8a249a BS |
2130 | break; |
2131 | } | |
99ca0219 | 2132 | case 0x58: /* D-MMU regs */ |
0f8a249a | 2133 | { |
1a2fb1c0 | 2134 | int reg = (addr >> 3) & 0xf; |
3475187d | 2135 | |
697a77e6 | 2136 | if (reg == 0) { |
99ca0219 | 2137 | /* D-TSB Tag Target register */ |
6e8e7d4c | 2138 | ret = ultrasparc_tag_target(env->dmmu.tag_access); |
697a77e6 IK |
2139 | } else { |
2140 | ret = env->dmmuregs[reg]; | |
2141 | } | |
2142 | break; | |
2143 | } | |
99ca0219 | 2144 | case 0x59: /* D-MMU 8k TSB pointer */ |
697a77e6 | 2145 | { |
99ca0219 BS |
2146 | /* env->dmmuregs[5] holds D-MMU TSB register value |
2147 | env->dmmuregs[6] holds D-MMU Tag Access register value */ | |
6e8e7d4c | 2148 | ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access, |
697a77e6 IK |
2149 | 8*1024); |
2150 | break; | |
2151 | } | |
99ca0219 | 2152 | case 0x5a: /* D-MMU 64k TSB pointer */ |
697a77e6 | 2153 | { |
99ca0219 BS |
2154 | /* env->dmmuregs[5] holds D-MMU TSB register value |
2155 | env->dmmuregs[6] holds D-MMU Tag Access register value */ | |
6e8e7d4c | 2156 | ret = ultrasparc_tsb_pointer(env->dmmu.tsb, env->dmmu.tag_access, |
697a77e6 | 2157 | 64*1024); |
0f8a249a BS |
2158 | break; |
2159 | } | |
99ca0219 | 2160 | case 0x5d: /* D-MMU data access */ |
a5a52cf2 BS |
2161 | { |
2162 | int reg = (addr >> 3) & 0x3f; | |
2163 | ||
6e8e7d4c | 2164 | ret = env->dtlb[reg].tte; |
a5a52cf2 BS |
2165 | break; |
2166 | } | |
99ca0219 | 2167 | case 0x5e: /* D-MMU tag read */ |
0f8a249a | 2168 | { |
43e9e742 | 2169 | int reg = (addr >> 3) & 0x3f; |
0f8a249a | 2170 | |
6e8e7d4c | 2171 | ret = env->dtlb[reg].tag; |
0f8a249a BS |
2172 | break; |
2173 | } | |
99ca0219 BS |
2174 | case 0x46: /* D-cache data */ |
2175 | case 0x47: /* D-cache tag access */ | |
2176 | case 0x4b: /* E-cache error enable */ | |
2177 | case 0x4c: /* E-cache asynchronous fault status */ | |
2178 | case 0x4d: /* E-cache asynchronous fault address */ | |
2179 | case 0x4e: /* E-cache tag data */ | |
2180 | case 0x66: /* I-cache instruction access */ | |
2181 | case 0x67: /* I-cache tag access */ | |
2182 | case 0x6e: /* I-cache predecode */ | |
2183 | case 0x6f: /* I-cache LRU etc. */ | |
2184 | case 0x76: /* E-cache tag */ | |
2185 | case 0x7e: /* E-cache tag */ | |
f7350b47 | 2186 | break; |
99ca0219 BS |
2187 | case 0x5b: /* D-MMU data pointer */ |
2188 | case 0x48: /* Interrupt dispatch, RO */ | |
2189 | case 0x49: /* Interrupt data receive */ | |
2190 | case 0x7f: /* Incoming interrupt vector, RO */ | |
2191 | /* XXX */ | |
0f8a249a | 2192 | break; |
99ca0219 BS |
2193 | case 0x54: /* I-MMU data in, WO */ |
2194 | case 0x57: /* I-MMU demap, WO */ | |
2195 | case 0x5c: /* D-MMU data in, WO */ | |
2196 | case 0x5f: /* D-MMU demap, WO */ | |
2197 | case 0x77: /* Interrupt vector, WO */ | |
3475187d | 2198 | default: |
e18231a3 | 2199 | do_unassigned_access(addr, 0, 0, 1, size); |
0f8a249a BS |
2200 | ret = 0; |
2201 | break; | |
3475187d | 2202 | } |
81ad8ba2 BS |
2203 | |
2204 | /* Convert from little endian */ | |
2205 | switch (asi) { | |
99ca0219 BS |
2206 | case 0x0c: /* Nucleus Little Endian (LE) */ |
2207 | case 0x18: /* As if user primary LE */ | |
2208 | case 0x19: /* As if user secondary LE */ | |
2209 | case 0x1c: /* Bypass LE */ | |
2210 | case 0x1d: /* Bypass, non-cacheable LE */ | |
2211 | case 0x88: /* Primary LE */ | |
2212 | case 0x89: /* Secondary LE */ | |
81ad8ba2 BS |
2213 | switch(size) { |
2214 | case 2: | |
2215 | ret = bswap16(ret); | |
e32664fb | 2216 | break; |
81ad8ba2 BS |
2217 | case 4: |
2218 | ret = bswap32(ret); | |
e32664fb | 2219 | break; |
81ad8ba2 BS |
2220 | case 8: |
2221 | ret = bswap64(ret); | |
e32664fb | 2222 | break; |
81ad8ba2 BS |
2223 | default: |
2224 | break; | |
2225 | } | |
2226 | default: | |
2227 | break; | |
2228 | } | |
2229 | ||
2230 | /* Convert to signed number */ | |
2231 | if (sign) { | |
99ca0219 | 2232 | switch (size) { |
81ad8ba2 BS |
2233 | case 1: |
2234 | ret = (int8_t) ret; | |
e32664fb | 2235 | break; |
81ad8ba2 BS |
2236 | case 2: |
2237 | ret = (int16_t) ret; | |
e32664fb | 2238 | break; |
81ad8ba2 BS |
2239 | case 4: |
2240 | ret = (int32_t) ret; | |
e32664fb | 2241 | break; |
81ad8ba2 BS |
2242 | default: |
2243 | break; | |
2244 | } | |
2245 | } | |
1a2fb1c0 BS |
2246 | #ifdef DEBUG_ASI |
2247 | dump_asi("read ", last_addr, asi, size, ret); | |
2248 | #endif | |
2249 | return ret; | |
3475187d FB |
2250 | } |
2251 | ||
1a2fb1c0 | 2252 | void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) |
3475187d | 2253 | { |
1a2fb1c0 BS |
2254 | #ifdef DEBUG_ASI |
2255 | dump_asi("write", addr, asi, size, val); | |
2256 | #endif | |
01b5d4e5 IK |
2257 | |
2258 | asi &= 0xff; | |
2259 | ||
6f27aba6 | 2260 | if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) |
2aae2b8e | 2261 | || (cpu_has_hypervisor(env) |
5578ceab | 2262 | && asi >= 0x30 && asi < 0x80 |
99ca0219 | 2263 | && !(env->hpstate & HS_PRIV))) { |
bc265319 | 2264 | helper_raise_exception(env, TT_PRIV_ACT); |
99ca0219 | 2265 | } |
3475187d | 2266 | |
c2bc0e38 | 2267 | helper_check_align(addr, size - 1); |
1295001c IK |
2268 | addr = asi_address_mask(env, asi, addr); |
2269 | ||
81ad8ba2 BS |
2270 | /* Convert to little endian */ |
2271 | switch (asi) { | |
99ca0219 BS |
2272 | case 0x0c: /* Nucleus Little Endian (LE) */ |
2273 | case 0x18: /* As if user primary LE */ | |
2274 | case 0x19: /* As if user secondary LE */ | |
2275 | case 0x1c: /* Bypass LE */ | |
2276 | case 0x1d: /* Bypass, non-cacheable LE */ | |
2277 | case 0x88: /* Primary LE */ | |
2278 | case 0x89: /* Secondary LE */ | |
2279 | switch (size) { | |
81ad8ba2 | 2280 | case 2: |
5b0f0bec | 2281 | val = bswap16(val); |
e32664fb | 2282 | break; |
81ad8ba2 | 2283 | case 4: |
5b0f0bec | 2284 | val = bswap32(val); |
e32664fb | 2285 | break; |
81ad8ba2 | 2286 | case 8: |
5b0f0bec | 2287 | val = bswap64(val); |
e32664fb | 2288 | break; |
81ad8ba2 BS |
2289 | default: |
2290 | break; | |
2291 | } | |
2292 | default: | |
2293 | break; | |
2294 | } | |
2295 | ||
99ca0219 BS |
2296 | switch (asi) { |
2297 | case 0x10: /* As if user primary */ | |
2298 | case 0x11: /* As if user secondary */ | |
2299 | case 0x18: /* As if user primary LE */ | |
2300 | case 0x19: /* As if user secondary LE */ | |
2301 | case 0x80: /* Primary */ | |
2302 | case 0x81: /* Secondary */ | |
2303 | case 0x88: /* Primary LE */ | |
2304 | case 0x89: /* Secondary LE */ | |
2305 | case 0xe2: /* UA2007 Primary block init */ | |
2306 | case 0xe3: /* UA2007 Secondary block init */ | |
81ad8ba2 | 2307 | if ((asi & 0x80) && (env->pstate & PS_PRIV)) { |
2aae2b8e | 2308 | if (cpu_hypervisor_mode(env)) { |
99ca0219 | 2309 | switch (size) { |
6f27aba6 | 2310 | case 1: |
1a2fb1c0 | 2311 | stb_hypv(addr, val); |
6f27aba6 BS |
2312 | break; |
2313 | case 2: | |
a4e7dd52 | 2314 | stw_hypv(addr, val); |
6f27aba6 BS |
2315 | break; |
2316 | case 4: | |
a4e7dd52 | 2317 | stl_hypv(addr, val); |
6f27aba6 BS |
2318 | break; |
2319 | case 8: | |
2320 | default: | |
a4e7dd52 | 2321 | stq_hypv(addr, val); |
6f27aba6 BS |
2322 | break; |
2323 | } | |
2324 | } else { | |
2065061e IK |
2325 | /* secondary space access has lowest asi bit equal to 1 */ |
2326 | if (asi & 1) { | |
99ca0219 | 2327 | switch (size) { |
2065061e IK |
2328 | case 1: |
2329 | stb_kernel_secondary(addr, val); | |
2330 | break; | |
2331 | case 2: | |
2332 | stw_kernel_secondary(addr, val); | |
2333 | break; | |
2334 | case 4: | |
2335 | stl_kernel_secondary(addr, val); | |
2336 | break; | |
2337 | case 8: | |
2338 | default: | |
2339 | stq_kernel_secondary(addr, val); | |
2340 | break; | |
2341 | } | |
2342 | } else { | |
99ca0219 | 2343 | switch (size) { |
2065061e IK |
2344 | case 1: |
2345 | stb_kernel(addr, val); | |
2346 | break; | |
2347 | case 2: | |
2348 | stw_kernel(addr, val); | |
2349 | break; | |
2350 | case 4: | |
2351 | stl_kernel(addr, val); | |
2352 | break; | |
2353 | case 8: | |
2354 | default: | |
2355 | stq_kernel(addr, val); | |
2356 | break; | |
2357 | } | |
2358 | } | |
2359 | } | |
2360 | } else { | |
2361 | /* secondary space access has lowest asi bit equal to 1 */ | |
2362 | if (asi & 1) { | |
99ca0219 | 2363 | switch (size) { |
6f27aba6 | 2364 | case 1: |
2065061e | 2365 | stb_user_secondary(addr, val); |
6f27aba6 BS |
2366 | break; |
2367 | case 2: | |
2065061e | 2368 | stw_user_secondary(addr, val); |
6f27aba6 BS |
2369 | break; |
2370 | case 4: | |
2065061e | 2371 | stl_user_secondary(addr, val); |
6f27aba6 BS |
2372 | break; |
2373 | case 8: | |
2374 | default: | |
2065061e IK |
2375 | stq_user_secondary(addr, val); |
2376 | break; | |
2377 | } | |
2378 | } else { | |
99ca0219 | 2379 | switch (size) { |
2065061e IK |
2380 | case 1: |
2381 | stb_user(addr, val); | |
2382 | break; | |
2383 | case 2: | |
2384 | stw_user(addr, val); | |
2385 | break; | |
2386 | case 4: | |
2387 | stl_user(addr, val); | |
2388 | break; | |
2389 | case 8: | |
2390 | default: | |
2391 | stq_user(addr, val); | |
6f27aba6 BS |
2392 | break; |
2393 | } | |
81ad8ba2 BS |
2394 | } |
2395 | } | |
2396 | break; | |
99ca0219 BS |
2397 | case 0x14: /* Bypass */ |
2398 | case 0x15: /* Bypass, non-cacheable */ | |
2399 | case 0x1c: /* Bypass LE */ | |
2400 | case 0x1d: /* Bypass, non-cacheable LE */ | |
0f8a249a | 2401 | { |
99ca0219 | 2402 | switch (size) { |
02aab46a | 2403 | case 1: |
1a2fb1c0 | 2404 | stb_phys(addr, val); |
02aab46a FB |
2405 | break; |
2406 | case 2: | |
a4e7dd52 | 2407 | stw_phys(addr, val); |
02aab46a FB |
2408 | break; |
2409 | case 4: | |
a4e7dd52 | 2410 | stl_phys(addr, val); |
02aab46a FB |
2411 | break; |
2412 | case 8: | |
2413 | default: | |
a4e7dd52 | 2414 | stq_phys(addr, val); |
02aab46a FB |
2415 | break; |
2416 | } | |
0f8a249a BS |
2417 | } |
2418 | return; | |
99ca0219 BS |
2419 | case 0x24: /* Nucleus quad LDD 128 bit atomic */ |
2420 | case 0x2c: /* Nucleus quad LDD 128 bit atomic LE | |
2421 | Only ldda allowed */ | |
bc265319 | 2422 | helper_raise_exception(env, TT_ILL_INSN); |
db166940 | 2423 | return; |
99ca0219 BS |
2424 | case 0x04: /* Nucleus */ |
2425 | case 0x0c: /* Nucleus Little Endian (LE) */ | |
2426 | { | |
2427 | switch (size) { | |
2428 | case 1: | |
2429 | stb_nucleus(addr, val); | |
2430 | break; | |
2431 | case 2: | |
2432 | stw_nucleus(addr, val); | |
2433 | break; | |
2434 | case 4: | |
2435 | stl_nucleus(addr, val); | |
2436 | break; | |
2437 | default: | |
2438 | case 8: | |
2439 | stq_nucleus(addr, val); | |
2440 | break; | |
2441 | } | |
2065061e IK |
2442 | break; |
2443 | } | |
2065061e | 2444 | |
99ca0219 BS |
2445 | case 0x4a: /* UPA config */ |
2446 | /* XXX */ | |
0f8a249a | 2447 | return; |
99ca0219 | 2448 | case 0x45: /* LSU */ |
0f8a249a BS |
2449 | { |
2450 | uint64_t oldreg; | |
2451 | ||
2452 | oldreg = env->lsu; | |
1a2fb1c0 | 2453 | env->lsu = val & (DMMU_E | IMMU_E); |
99ca0219 BS |
2454 | /* Mappings generated during D/I MMU disabled mode are |
2455 | invalid in normal mode */ | |
0f8a249a | 2456 | if (oldreg != env->lsu) { |
77f193da BS |
2457 | DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", |
2458 | oldreg, env->lsu); | |
83469015 | 2459 | #ifdef DEBUG_MMU |
d41160a3 | 2460 | dump_mmu(stdout, fprintf, env1); |
83469015 | 2461 | #endif |
0f8a249a BS |
2462 | tlb_flush(env, 1); |
2463 | } | |
2464 | return; | |
2465 | } | |
99ca0219 | 2466 | case 0x50: /* I-MMU regs */ |
0f8a249a | 2467 | { |
1a2fb1c0 | 2468 | int reg = (addr >> 3) & 0xf; |
0f8a249a | 2469 | uint64_t oldreg; |
3b46e624 | 2470 | |
0f8a249a | 2471 | oldreg = env->immuregs[reg]; |
99ca0219 BS |
2472 | switch (reg) { |
2473 | case 0: /* RO */ | |
3475187d | 2474 | return; |
99ca0219 | 2475 | case 1: /* Not in I-MMU */ |
3475187d | 2476 | case 2: |
3475187d | 2477 | return; |
99ca0219 BS |
2478 | case 3: /* SFSR */ |
2479 | if ((val & 1) == 0) { | |
2480 | val = 0; /* Clear SFSR */ | |
2481 | } | |
6e8e7d4c | 2482 | env->immu.sfsr = val; |
3475187d | 2483 | break; |
99ca0219 | 2484 | case 4: /* RO */ |
6e8e7d4c | 2485 | return; |
99ca0219 | 2486 | case 5: /* TSB access */ |
6e8e7d4c IK |
2487 | DPRINTF_MMU("immu TSB write: 0x%016" PRIx64 " -> 0x%016" |
2488 | PRIx64 "\n", env->immu.tsb, val); | |
2489 | env->immu.tsb = val; | |
2490 | break; | |
99ca0219 | 2491 | case 6: /* Tag access */ |
6e8e7d4c IK |
2492 | env->immu.tag_access = val; |
2493 | break; | |
2494 | case 7: | |
2495 | case 8: | |
2496 | return; | |
3475187d FB |
2497 | default: |
2498 | break; | |
2499 | } | |
6e8e7d4c | 2500 | |
3475187d | 2501 | if (oldreg != env->immuregs[reg]) { |
6e8e7d4c | 2502 | DPRINTF_MMU("immu change reg[%d]: 0x%016" PRIx64 " -> 0x%016" |
77f193da | 2503 | PRIx64 "\n", reg, oldreg, env->immuregs[reg]); |
3475187d | 2504 | } |
952a328f | 2505 | #ifdef DEBUG_MMU |
d41160a3 | 2506 | dump_mmu(stdout, fprintf, env); |
3475187d | 2507 | #endif |
0f8a249a BS |
2508 | return; |
2509 | } | |
99ca0219 | 2510 | case 0x54: /* I-MMU data in */ |
f707726e IK |
2511 | replace_tlb_1bit_lru(env->itlb, env->immu.tag_access, val, "immu", env); |
2512 | return; | |
99ca0219 | 2513 | case 0x55: /* I-MMU data access */ |
0f8a249a | 2514 | { |
99ca0219 | 2515 | /* TODO: auto demap */ |
cc6747f4 | 2516 | |
1a2fb1c0 | 2517 | unsigned int i = (addr >> 3) & 0x3f; |
3475187d | 2518 | |
f707726e | 2519 | replace_tlb_entry(&env->itlb[i], env->immu.tag_access, val, env); |
6e8e7d4c IK |
2520 | |
2521 | #ifdef DEBUG_MMU | |
f707726e | 2522 | DPRINTF_MMU("immu data access replaced entry [%i]\n", i); |
d41160a3 | 2523 | dump_mmu(stdout, fprintf, env); |
6e8e7d4c | 2524 | #endif |
0f8a249a BS |
2525 | return; |
2526 | } | |
99ca0219 | 2527 | case 0x57: /* I-MMU demap */ |
170f4c55 | 2528 | demap_tlb(env->itlb, addr, "immu", env); |
0f8a249a | 2529 | return; |
99ca0219 | 2530 | case 0x58: /* D-MMU regs */ |
0f8a249a | 2531 | { |
1a2fb1c0 | 2532 | int reg = (addr >> 3) & 0xf; |
0f8a249a | 2533 | uint64_t oldreg; |
3b46e624 | 2534 | |
0f8a249a | 2535 | oldreg = env->dmmuregs[reg]; |
99ca0219 BS |
2536 | switch (reg) { |
2537 | case 0: /* RO */ | |
3475187d FB |
2538 | case 4: |
2539 | return; | |
99ca0219 | 2540 | case 3: /* SFSR */ |
1a2fb1c0 | 2541 | if ((val & 1) == 0) { |
99ca0219 | 2542 | val = 0; /* Clear SFSR, Fault address */ |
6e8e7d4c | 2543 | env->dmmu.sfar = 0; |
0f8a249a | 2544 | } |
6e8e7d4c | 2545 | env->dmmu.sfsr = val; |
3475187d | 2546 | break; |
99ca0219 | 2547 | case 1: /* Primary context */ |
6e8e7d4c | 2548 | env->dmmu.mmu_primary_context = val; |
664a65b0 IK |
2549 | /* can be optimized to only flush MMU_USER_IDX |
2550 | and MMU_KERNEL_IDX entries */ | |
2551 | tlb_flush(env, 1); | |
6e8e7d4c | 2552 | break; |
99ca0219 | 2553 | case 2: /* Secondary context */ |
6e8e7d4c | 2554 | env->dmmu.mmu_secondary_context = val; |
664a65b0 IK |
2555 | /* can be optimized to only flush MMU_USER_SECONDARY_IDX |
2556 | and MMU_KERNEL_SECONDARY_IDX entries */ | |
2557 | tlb_flush(env, 1); | |
6e8e7d4c | 2558 | break; |
99ca0219 | 2559 | case 5: /* TSB access */ |
6e8e7d4c IK |
2560 | DPRINTF_MMU("dmmu TSB write: 0x%016" PRIx64 " -> 0x%016" |
2561 | PRIx64 "\n", env->dmmu.tsb, val); | |
2562 | env->dmmu.tsb = val; | |
2563 | break; | |
99ca0219 | 2564 | case 6: /* Tag access */ |
6e8e7d4c IK |
2565 | env->dmmu.tag_access = val; |
2566 | break; | |
99ca0219 BS |
2567 | case 7: /* Virtual Watchpoint */ |
2568 | case 8: /* Physical Watchpoint */ | |
3475187d | 2569 | default: |
6e8e7d4c | 2570 | env->dmmuregs[reg] = val; |
3475187d FB |
2571 | break; |
2572 | } | |
6e8e7d4c | 2573 | |
3475187d | 2574 | if (oldreg != env->dmmuregs[reg]) { |
6e8e7d4c | 2575 | DPRINTF_MMU("dmmu change reg[%d]: 0x%016" PRIx64 " -> 0x%016" |
77f193da | 2576 | PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]); |
3475187d | 2577 | } |
952a328f | 2578 | #ifdef DEBUG_MMU |
d41160a3 | 2579 | dump_mmu(stdout, fprintf, env); |
3475187d | 2580 | #endif |
0f8a249a BS |
2581 | return; |
2582 | } | |
99ca0219 | 2583 | case 0x5c: /* D-MMU data in */ |
f707726e IK |
2584 | replace_tlb_1bit_lru(env->dtlb, env->dmmu.tag_access, val, "dmmu", env); |
2585 | return; | |
99ca0219 | 2586 | case 0x5d: /* D-MMU data access */ |
0f8a249a | 2587 | { |
1a2fb1c0 | 2588 | unsigned int i = (addr >> 3) & 0x3f; |
3475187d | 2589 | |
f707726e IK |
2590 | replace_tlb_entry(&env->dtlb[i], env->dmmu.tag_access, val, env); |
2591 | ||
6e8e7d4c | 2592 | #ifdef DEBUG_MMU |
f707726e | 2593 | DPRINTF_MMU("dmmu data access replaced entry [%i]\n", i); |
d41160a3 | 2594 | dump_mmu(stdout, fprintf, env); |
6e8e7d4c | 2595 | #endif |
0f8a249a BS |
2596 | return; |
2597 | } | |
99ca0219 | 2598 | case 0x5f: /* D-MMU demap */ |
170f4c55 | 2599 | demap_tlb(env->dtlb, addr, "dmmu", env); |
cc6747f4 | 2600 | return; |
99ca0219 BS |
2601 | case 0x49: /* Interrupt data receive */ |
2602 | /* XXX */ | |
0f8a249a | 2603 | return; |
99ca0219 BS |
2604 | case 0x46: /* D-cache data */ |
2605 | case 0x47: /* D-cache tag access */ | |
2606 | case 0x4b: /* E-cache error enable */ | |
2607 | case 0x4c: /* E-cache asynchronous fault status */ | |
2608 | case 0x4d: /* E-cache asynchronous fault address */ | |
2609 | case 0x4e: /* E-cache tag data */ | |
2610 | case 0x66: /* I-cache instruction access */ | |
2611 | case 0x67: /* I-cache tag access */ | |
2612 | case 0x6e: /* I-cache predecode */ | |
2613 | case 0x6f: /* I-cache LRU etc. */ | |
2614 | case 0x76: /* E-cache tag */ | |
2615 | case 0x7e: /* E-cache tag */ | |
f7350b47 | 2616 | return; |
99ca0219 BS |
2617 | case 0x51: /* I-MMU 8k TSB pointer, RO */ |
2618 | case 0x52: /* I-MMU 64k TSB pointer, RO */ | |
2619 | case 0x56: /* I-MMU tag read, RO */ | |
2620 | case 0x59: /* D-MMU 8k TSB pointer, RO */ | |
2621 | case 0x5a: /* D-MMU 64k TSB pointer, RO */ | |
2622 | case 0x5b: /* D-MMU data pointer, RO */ | |
2623 | case 0x5e: /* D-MMU tag read, RO */ | |
2624 | case 0x48: /* Interrupt dispatch, RO */ | |
2625 | case 0x7f: /* Incoming interrupt vector, RO */ | |
2626 | case 0x82: /* Primary no-fault, RO */ | |
2627 | case 0x83: /* Secondary no-fault, RO */ | |
2628 | case 0x8a: /* Primary no-fault LE, RO */ | |
2629 | case 0x8b: /* Secondary no-fault LE, RO */ | |
3475187d | 2630 | default: |
e18231a3 | 2631 | do_unassigned_access(addr, 1, 0, 1, size); |
0f8a249a | 2632 | return; |
3475187d FB |
2633 | } |
2634 | } | |
81ad8ba2 | 2635 | #endif /* CONFIG_USER_ONLY */ |
3391c818 | 2636 | |
db166940 BS |
2637 | void helper_ldda_asi(target_ulong addr, int asi, int rd) |
2638 | { | |
db166940 | 2639 | if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) |
2aae2b8e | 2640 | || (cpu_has_hypervisor(env) |
5578ceab | 2641 | && asi >= 0x30 && asi < 0x80 |
99ca0219 | 2642 | && !(env->hpstate & HS_PRIV))) { |
bc265319 | 2643 | helper_raise_exception(env, TT_PRIV_ACT); |
99ca0219 | 2644 | } |
db166940 | 2645 | |
1295001c IK |
2646 | addr = asi_address_mask(env, asi, addr); |
2647 | ||
db166940 | 2648 | switch (asi) { |
03ae77d6 | 2649 | #if !defined(CONFIG_USER_ONLY) |
99ca0219 BS |
2650 | case 0x24: /* Nucleus quad LDD 128 bit atomic */ |
2651 | case 0x2c: /* Nucleus quad LDD 128 bit atomic LE */ | |
db166940 BS |
2652 | helper_check_align(addr, 0xf); |
2653 | if (rd == 0) { | |
54a3c0f0 | 2654 | env->gregs[1] = ldq_nucleus(addr + 8); |
99ca0219 | 2655 | if (asi == 0x2c) { |
db166940 | 2656 | bswap64s(&env->gregs[1]); |
99ca0219 | 2657 | } |
db166940 | 2658 | } else if (rd < 8) { |
54a3c0f0 IK |
2659 | env->gregs[rd] = ldq_nucleus(addr); |
2660 | env->gregs[rd + 1] = ldq_nucleus(addr + 8); | |
db166940 BS |
2661 | if (asi == 0x2c) { |
2662 | bswap64s(&env->gregs[rd]); | |
2663 | bswap64s(&env->gregs[rd + 1]); | |
2664 | } | |
2665 | } else { | |
54a3c0f0 IK |
2666 | env->regwptr[rd] = ldq_nucleus(addr); |
2667 | env->regwptr[rd + 1] = ldq_nucleus(addr + 8); | |
db166940 BS |
2668 | if (asi == 0x2c) { |
2669 | bswap64s(&env->regwptr[rd]); | |
2670 | bswap64s(&env->regwptr[rd + 1]); | |
2671 | } | |
2672 | } | |
2673 | break; | |
03ae77d6 | 2674 | #endif |
db166940 BS |
2675 | default: |
2676 | helper_check_align(addr, 0x3); | |
99ca0219 | 2677 | if (rd == 0) { |
db166940 | 2678 | env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0); |
99ca0219 | 2679 | } else if (rd < 8) { |
db166940 BS |
2680 | env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0); |
2681 | env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0); | |
2682 | } else { | |
2683 | env->regwptr[rd] = helper_ld_asi(addr, asi, 4, 0); | |
2684 | env->regwptr[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0); | |
2685 | } | |
2686 | break; | |
2687 | } | |
2688 | } | |
2689 | ||
1a2fb1c0 | 2690 | void helper_ldf_asi(target_ulong addr, int asi, int size, int rd) |
3391c818 | 2691 | { |
3391c818 | 2692 | unsigned int i; |
4183f36d | 2693 | CPU_DoubleU u; |
3391c818 | 2694 | |
c2bc0e38 | 2695 | helper_check_align(addr, 3); |
1295001c IK |
2696 | addr = asi_address_mask(env, asi, addr); |
2697 | ||
3391c818 | 2698 | switch (asi) { |
d8e586ff TS |
2699 | case 0xf0: /* UA2007/JPS1 Block load primary */ |
2700 | case 0xf1: /* UA2007/JPS1 Block load secondary */ | |
2701 | case 0xf8: /* UA2007/JPS1 Block load primary LE */ | |
2702 | case 0xf9: /* UA2007/JPS1 Block load secondary LE */ | |
51996525 | 2703 | if (rd & 7) { |
bc265319 | 2704 | helper_raise_exception(env, TT_ILL_INSN); |
51996525 BS |
2705 | return; |
2706 | } | |
c2bc0e38 | 2707 | helper_check_align(addr, 0x3f); |
51996525 | 2708 | for (i = 0; i < 16; i++) { |
77f193da BS |
2709 | *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x8f, 4, |
2710 | 0); | |
1a2fb1c0 | 2711 | addr += 4; |
3391c818 | 2712 | } |
3391c818 | 2713 | |
0e2fa9ca | 2714 | return; |
41317e2e TS |
2715 | case 0x16: /* UA2007 Block load primary, user privilege */ |
2716 | case 0x17: /* UA2007 Block load secondary, user privilege */ | |
2717 | case 0x1e: /* UA2007 Block load primary LE, user privilege */ | |
2718 | case 0x1f: /* UA2007 Block load secondary LE, user privilege */ | |
d8e586ff TS |
2719 | case 0x70: /* JPS1 Block load primary, user privilege */ |
2720 | case 0x71: /* JPS1 Block load secondary, user privilege */ | |
d920bde9 TS |
2721 | case 0x78: /* JPS1 Block load primary LE, user privilege */ |
2722 | case 0x79: /* JPS1 Block load secondary LE, user privilege */ | |
0e2fa9ca | 2723 | if (rd & 7) { |
bc265319 | 2724 | helper_raise_exception(env, TT_ILL_INSN); |
0e2fa9ca IK |
2725 | return; |
2726 | } | |
2727 | helper_check_align(addr, 0x3f); | |
2728 | for (i = 0; i < 16; i++) { | |
41317e2e | 2729 | *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x19, 4, |
0e2fa9ca IK |
2730 | 0); |
2731 | addr += 4; | |
2732 | } | |
2733 | ||
3391c818 BS |
2734 | return; |
2735 | default: | |
2736 | break; | |
2737 | } | |
2738 | ||
99ca0219 | 2739 | switch (size) { |
3391c818 BS |
2740 | default: |
2741 | case 4: | |
4183f36d | 2742 | *((uint32_t *)&env->fpr[rd]) = helper_ld_asi(addr, asi, size, 0); |
3391c818 BS |
2743 | break; |
2744 | case 8: | |
4183f36d TS |
2745 | u.ll = helper_ld_asi(addr, asi, size, 0); |
2746 | *((uint32_t *)&env->fpr[rd++]) = u.l.upper; | |
2747 | *((uint32_t *)&env->fpr[rd++]) = u.l.lower; | |
3391c818 | 2748 | break; |
1f587329 | 2749 | case 16: |
4183f36d TS |
2750 | u.ll = helper_ld_asi(addr, asi, 8, 0); |
2751 | *((uint32_t *)&env->fpr[rd++]) = u.l.upper; | |
2752 | *((uint32_t *)&env->fpr[rd++]) = u.l.lower; | |
2753 | u.ll = helper_ld_asi(addr + 8, asi, 8, 0); | |
2754 | *((uint32_t *)&env->fpr[rd++]) = u.l.upper; | |
2755 | *((uint32_t *)&env->fpr[rd++]) = u.l.lower; | |
1f587329 | 2756 | break; |
3391c818 | 2757 | } |
3391c818 BS |
2758 | } |
2759 | ||
1a2fb1c0 | 2760 | void helper_stf_asi(target_ulong addr, int asi, int size, int rd) |
3391c818 | 2761 | { |
3391c818 | 2762 | unsigned int i; |
1a2fb1c0 | 2763 | target_ulong val = 0; |
e1ef36c4 | 2764 | CPU_DoubleU u; |
3391c818 | 2765 | |
c2bc0e38 | 2766 | helper_check_align(addr, 3); |
1295001c IK |
2767 | addr = asi_address_mask(env, asi, addr); |
2768 | ||
3391c818 | 2769 | switch (asi) { |
d8e586ff TS |
2770 | case 0xe0: /* UA2007/JPS1 Block commit store primary (cache flush) */ |
2771 | case 0xe1: /* UA2007/JPS1 Block commit store secondary (cache flush) */ | |
2772 | case 0xf0: /* UA2007/JPS1 Block store primary */ | |
2773 | case 0xf1: /* UA2007/JPS1 Block store secondary */ | |
2774 | case 0xf8: /* UA2007/JPS1 Block store primary LE */ | |
2775 | case 0xf9: /* UA2007/JPS1 Block store secondary LE */ | |
51996525 | 2776 | if (rd & 7) { |
bc265319 | 2777 | helper_raise_exception(env, TT_ILL_INSN); |
51996525 BS |
2778 | return; |
2779 | } | |
c2bc0e38 | 2780 | helper_check_align(addr, 0x3f); |
51996525 | 2781 | for (i = 0; i < 16; i++) { |
1a2fb1c0 BS |
2782 | val = *(uint32_t *)&env->fpr[rd++]; |
2783 | helper_st_asi(addr, val, asi & 0x8f, 4); | |
2784 | addr += 4; | |
3391c818 | 2785 | } |
3391c818 | 2786 | |
0e2fa9ca | 2787 | return; |
073a0444 TS |
2788 | case 0x16: /* UA2007 Block load primary, user privilege */ |
2789 | case 0x17: /* UA2007 Block load secondary, user privilege */ | |
2790 | case 0x1e: /* UA2007 Block load primary LE, user privilege */ | |
2791 | case 0x1f: /* UA2007 Block load secondary LE, user privilege */ | |
d8e586ff TS |
2792 | case 0x70: /* JPS1 Block store primary, user privilege */ |
2793 | case 0x71: /* JPS1 Block store secondary, user privilege */ | |
d920bde9 TS |
2794 | case 0x78: /* JPS1 Block load primary LE, user privilege */ |
2795 | case 0x79: /* JPS1 Block load secondary LE, user privilege */ | |
0e2fa9ca | 2796 | if (rd & 7) { |
bc265319 | 2797 | helper_raise_exception(env, TT_ILL_INSN); |
0e2fa9ca IK |
2798 | return; |
2799 | } | |
2800 | helper_check_align(addr, 0x3f); | |
2801 | for (i = 0; i < 16; i++) { | |
2802 | val = *(uint32_t *)&env->fpr[rd++]; | |
073a0444 | 2803 | helper_st_asi(addr, val, asi & 0x19, 4); |
0e2fa9ca IK |
2804 | addr += 4; |
2805 | } | |
2806 | ||
3391c818 BS |
2807 | return; |
2808 | default: | |
2809 | break; | |
2810 | } | |
2811 | ||
99ca0219 | 2812 | switch (size) { |
3391c818 BS |
2813 | default: |
2814 | case 4: | |
e1ef36c4 | 2815 | helper_st_asi(addr, *(uint32_t *)&env->fpr[rd], asi, size); |
3391c818 BS |
2816 | break; |
2817 | case 8: | |
e1ef36c4 TS |
2818 | u.l.upper = *(uint32_t *)&env->fpr[rd++]; |
2819 | u.l.lower = *(uint32_t *)&env->fpr[rd++]; | |
2820 | helper_st_asi(addr, u.ll, asi, size); | |
3391c818 | 2821 | break; |
1f587329 | 2822 | case 16: |
e1ef36c4 TS |
2823 | u.l.upper = *(uint32_t *)&env->fpr[rd++]; |
2824 | u.l.lower = *(uint32_t *)&env->fpr[rd++]; | |
2825 | helper_st_asi(addr, u.ll, asi, 8); | |
2826 | u.l.upper = *(uint32_t *)&env->fpr[rd++]; | |
2827 | u.l.lower = *(uint32_t *)&env->fpr[rd++]; | |
2828 | helper_st_asi(addr + 8, u.ll, asi, 8); | |
1f587329 | 2829 | break; |
3391c818 | 2830 | } |
1a2fb1c0 BS |
2831 | } |
2832 | ||
2833 | target_ulong helper_cas_asi(target_ulong addr, target_ulong val1, | |
2834 | target_ulong val2, uint32_t asi) | |
2835 | { | |
2836 | target_ulong ret; | |
2837 | ||
1121f879 | 2838 | val2 &= 0xffffffffUL; |
1a2fb1c0 BS |
2839 | ret = helper_ld_asi(addr, asi, 4, 0); |
2840 | ret &= 0xffffffffUL; | |
99ca0219 | 2841 | if (val2 == ret) { |
1121f879 | 2842 | helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4); |
99ca0219 | 2843 | } |
1a2fb1c0 | 2844 | return ret; |
3391c818 BS |
2845 | } |
2846 | ||
1a2fb1c0 BS |
2847 | target_ulong helper_casx_asi(target_ulong addr, target_ulong val1, |
2848 | target_ulong val2, uint32_t asi) | |
2849 | { | |
2850 | target_ulong ret; | |
2851 | ||
2852 | ret = helper_ld_asi(addr, asi, 8, 0); | |
99ca0219 | 2853 | if (val2 == ret) { |
1121f879 | 2854 | helper_st_asi(addr, val1, asi, 8); |
99ca0219 | 2855 | } |
1a2fb1c0 BS |
2856 | return ret; |
2857 | } | |
81ad8ba2 | 2858 | #endif /* TARGET_SPARC64 */ |
3475187d FB |
2859 | |
2860 | #ifndef TARGET_SPARC64 | |
1a2fb1c0 | 2861 | void helper_rett(void) |
e8af50a3 | 2862 | { |
af7bf89b FB |
2863 | unsigned int cwp; |
2864 | ||
99ca0219 | 2865 | if (env->psret == 1) { |
bc265319 | 2866 | helper_raise_exception(env, TT_ILL_INSN); |
99ca0219 | 2867 | } |
d4218d99 | 2868 | |
e8af50a3 | 2869 | env->psret = 1; |
5a834bb4 | 2870 | cwp = cwp_inc(env->cwp + 1) ; |
e8af50a3 | 2871 | if (env->wim & (1 << cwp)) { |
bc265319 | 2872 | helper_raise_exception(env, TT_WIN_UNF); |
e8af50a3 FB |
2873 | } |
2874 | set_cwp(cwp); | |
2875 | env->psrs = env->psrps; | |
2876 | } | |
3475187d | 2877 | #endif |
e8af50a3 | 2878 | |
0fcec41e | 2879 | static target_ulong helper_udiv_common(target_ulong a, target_ulong b, int cc) |
3b89f26c | 2880 | { |
0fcec41e | 2881 | int overflow = 0; |
3b89f26c BS |
2882 | uint64_t x0; |
2883 | uint32_t x1; | |
2884 | ||
7621a90d | 2885 | x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32); |
09487205 | 2886 | x1 = (b & 0xffffffff); |
3b89f26c BS |
2887 | |
2888 | if (x1 == 0) { | |
bc265319 | 2889 | helper_raise_exception(env, TT_DIV_ZERO); |
3b89f26c BS |
2890 | } |
2891 | ||
2892 | x0 = x0 / x1; | |
2893 | if (x0 > 0xffffffff) { | |
0fcec41e AJ |
2894 | x0 = 0xffffffff; |
2895 | overflow = 1; | |
2896 | } | |
2897 | ||
2898 | if (cc) { | |
2899 | env->cc_dst = x0; | |
2900 | env->cc_src2 = overflow; | |
2901 | env->cc_op = CC_OP_DIV; | |
3b89f26c | 2902 | } |
0fcec41e | 2903 | return x0; |
3b89f26c BS |
2904 | } |
2905 | ||
0fcec41e AJ |
2906 | target_ulong helper_udiv(target_ulong a, target_ulong b) |
2907 | { | |
2908 | return helper_udiv_common(a, b, 0); | |
2909 | } | |
2910 | ||
2911 | target_ulong helper_udiv_cc(target_ulong a, target_ulong b) | |
2912 | { | |
2913 | return helper_udiv_common(a, b, 1); | |
2914 | } | |
2915 | ||
2916 | static target_ulong helper_sdiv_common(target_ulong a, target_ulong b, int cc) | |
3b89f26c | 2917 | { |
0fcec41e | 2918 | int overflow = 0; |
3b89f26c BS |
2919 | int64_t x0; |
2920 | int32_t x1; | |
2921 | ||
7621a90d | 2922 | x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32); |
09487205 | 2923 | x1 = (b & 0xffffffff); |
3b89f26c BS |
2924 | |
2925 | if (x1 == 0) { | |
bc265319 | 2926 | helper_raise_exception(env, TT_DIV_ZERO); |
3b89f26c BS |
2927 | } |
2928 | ||
2929 | x0 = x0 / x1; | |
2930 | if ((int32_t) x0 != x0) { | |
99ca0219 | 2931 | x0 = x0 < 0 ? 0x80000000 : 0x7fffffff; |
0fcec41e AJ |
2932 | overflow = 1; |
2933 | } | |
2934 | ||
2935 | if (cc) { | |
2936 | env->cc_dst = x0; | |
2937 | env->cc_src2 = overflow; | |
2938 | env->cc_op = CC_OP_DIV; | |
3b89f26c | 2939 | } |
0fcec41e AJ |
2940 | return x0; |
2941 | } | |
2942 | ||
2943 | target_ulong helper_sdiv(target_ulong a, target_ulong b) | |
2944 | { | |
2945 | return helper_sdiv_common(a, b, 0); | |
2946 | } | |
2947 | ||
2948 | target_ulong helper_sdiv_cc(target_ulong a, target_ulong b) | |
2949 | { | |
2950 | return helper_sdiv_common(a, b, 1); | |
3b89f26c BS |
2951 | } |
2952 | ||
7fa76c0b BS |
2953 | void helper_stdf(target_ulong addr, int mem_idx) |
2954 | { | |
c2bc0e38 | 2955 | helper_check_align(addr, 7); |
7fa76c0b BS |
2956 | #if !defined(CONFIG_USER_ONLY) |
2957 | switch (mem_idx) { | |
b219094a | 2958 | case MMU_USER_IDX: |
c2bc0e38 | 2959 | stfq_user(addr, DT0); |
7fa76c0b | 2960 | break; |
b219094a | 2961 | case MMU_KERNEL_IDX: |
c2bc0e38 | 2962 | stfq_kernel(addr, DT0); |
7fa76c0b BS |
2963 | break; |
2964 | #ifdef TARGET_SPARC64 | |
b219094a | 2965 | case MMU_HYPV_IDX: |
c2bc0e38 | 2966 | stfq_hypv(addr, DT0); |
7fa76c0b BS |
2967 | break; |
2968 | #endif | |
2969 | default: | |
b219094a | 2970 | DPRINTF_MMU("helper_stdf: need to check MMU idx %d\n", mem_idx); |
7fa76c0b BS |
2971 | break; |
2972 | } | |
2973 | #else | |
41db525e | 2974 | stfq_raw(address_mask(env, addr), DT0); |
7fa76c0b BS |
2975 | #endif |
2976 | } | |
2977 | ||
2978 | void helper_lddf(target_ulong addr, int mem_idx) | |
2979 | { | |
c2bc0e38 | 2980 | helper_check_align(addr, 7); |
7fa76c0b BS |
2981 | #if !defined(CONFIG_USER_ONLY) |
2982 | switch (mem_idx) { | |
b219094a | 2983 | case MMU_USER_IDX: |
c2bc0e38 | 2984 | DT0 = ldfq_user(addr); |
7fa76c0b | 2985 | break; |
b219094a | 2986 | case MMU_KERNEL_IDX: |
c2bc0e38 | 2987 | DT0 = ldfq_kernel(addr); |
7fa76c0b BS |
2988 | break; |
2989 | #ifdef TARGET_SPARC64 | |
b219094a | 2990 | case MMU_HYPV_IDX: |
c2bc0e38 | 2991 | DT0 = ldfq_hypv(addr); |
7fa76c0b BS |
2992 | break; |
2993 | #endif | |
2994 | default: | |
b219094a | 2995 | DPRINTF_MMU("helper_lddf: need to check MMU idx %d\n", mem_idx); |
7fa76c0b BS |
2996 | break; |
2997 | } | |
2998 | #else | |
41db525e | 2999 | DT0 = ldfq_raw(address_mask(env, addr)); |
7fa76c0b BS |
3000 | #endif |
3001 | } | |
3002 | ||
64a88d5d | 3003 | void helper_ldqf(target_ulong addr, int mem_idx) |
7fa76c0b | 3004 | { |
99ca0219 | 3005 | /* XXX add 128 bit load */ |
7fa76c0b BS |
3006 | CPU_QuadU u; |
3007 | ||
c2bc0e38 | 3008 | helper_check_align(addr, 7); |
64a88d5d BS |
3009 | #if !defined(CONFIG_USER_ONLY) |
3010 | switch (mem_idx) { | |
b219094a | 3011 | case MMU_USER_IDX: |
c2bc0e38 BS |
3012 | u.ll.upper = ldq_user(addr); |
3013 | u.ll.lower = ldq_user(addr + 8); | |
64a88d5d BS |
3014 | QT0 = u.q; |
3015 | break; | |
b219094a | 3016 | case MMU_KERNEL_IDX: |
c2bc0e38 BS |
3017 | u.ll.upper = ldq_kernel(addr); |
3018 | u.ll.lower = ldq_kernel(addr + 8); | |
64a88d5d BS |
3019 | QT0 = u.q; |
3020 | break; | |
3021 | #ifdef TARGET_SPARC64 | |
b219094a | 3022 | case MMU_HYPV_IDX: |
c2bc0e38 BS |
3023 | u.ll.upper = ldq_hypv(addr); |
3024 | u.ll.lower = ldq_hypv(addr + 8); | |
64a88d5d BS |
3025 | QT0 = u.q; |
3026 | break; | |
3027 | #endif | |
3028 | default: | |
b219094a | 3029 | DPRINTF_MMU("helper_ldqf: need to check MMU idx %d\n", mem_idx); |
64a88d5d BS |
3030 | break; |
3031 | } | |
3032 | #else | |
41db525e RH |
3033 | u.ll.upper = ldq_raw(address_mask(env, addr)); |
3034 | u.ll.lower = ldq_raw(address_mask(env, addr + 8)); | |
7fa76c0b | 3035 | QT0 = u.q; |
64a88d5d | 3036 | #endif |
7fa76c0b BS |
3037 | } |
3038 | ||
64a88d5d | 3039 | void helper_stqf(target_ulong addr, int mem_idx) |
7fa76c0b | 3040 | { |
99ca0219 | 3041 | /* XXX add 128 bit store */ |
7fa76c0b BS |
3042 | CPU_QuadU u; |
3043 | ||
c2bc0e38 | 3044 | helper_check_align(addr, 7); |
64a88d5d BS |
3045 | #if !defined(CONFIG_USER_ONLY) |
3046 | switch (mem_idx) { | |
b219094a | 3047 | case MMU_USER_IDX: |
64a88d5d | 3048 | u.q = QT0; |
c2bc0e38 BS |
3049 | stq_user(addr, u.ll.upper); |
3050 | stq_user(addr + 8, u.ll.lower); | |
64a88d5d | 3051 | break; |
b219094a | 3052 | case MMU_KERNEL_IDX: |
64a88d5d | 3053 | u.q = QT0; |
c2bc0e38 BS |
3054 | stq_kernel(addr, u.ll.upper); |
3055 | stq_kernel(addr + 8, u.ll.lower); | |
64a88d5d BS |
3056 | break; |
3057 | #ifdef TARGET_SPARC64 | |
b219094a | 3058 | case MMU_HYPV_IDX: |
64a88d5d | 3059 | u.q = QT0; |
c2bc0e38 BS |
3060 | stq_hypv(addr, u.ll.upper); |
3061 | stq_hypv(addr + 8, u.ll.lower); | |
64a88d5d BS |
3062 | break; |
3063 | #endif | |
3064 | default: | |
b219094a | 3065 | DPRINTF_MMU("helper_stqf: need to check MMU idx %d\n", mem_idx); |
64a88d5d BS |
3066 | break; |
3067 | } | |
3068 | #else | |
7fa76c0b | 3069 | u.q = QT0; |
41db525e RH |
3070 | stq_raw(address_mask(env, addr), u.ll.upper); |
3071 | stq_raw(address_mask(env, addr + 8), u.ll.lower); | |
7fa76c0b | 3072 | #endif |
64a88d5d | 3073 | } |
7fa76c0b | 3074 | |
3475187d | 3075 | #ifndef TARGET_SPARC64 |
72a9747b BS |
3076 | /* XXX: use another pointer for %iN registers to avoid slow wrapping |
3077 | handling ? */ | |
3078 | void helper_save(void) | |
3079 | { | |
3080 | uint32_t cwp; | |
3081 | ||
5a834bb4 | 3082 | cwp = cwp_dec(env->cwp - 1); |
72a9747b | 3083 | if (env->wim & (1 << cwp)) { |
bc265319 | 3084 | helper_raise_exception(env, TT_WIN_OVF); |
72a9747b BS |
3085 | } |
3086 | set_cwp(cwp); | |
3087 | } | |
3088 | ||
3089 | void helper_restore(void) | |
3090 | { | |
3091 | uint32_t cwp; | |
3092 | ||
5a834bb4 | 3093 | cwp = cwp_inc(env->cwp + 1); |
72a9747b | 3094 | if (env->wim & (1 << cwp)) { |
bc265319 | 3095 | helper_raise_exception(env, TT_WIN_UNF); |
72a9747b BS |
3096 | } |
3097 | set_cwp(cwp); | |
3098 | } | |
3099 | ||
1a2fb1c0 | 3100 | void helper_wrpsr(target_ulong new_psr) |
af7bf89b | 3101 | { |
5a834bb4 | 3102 | if ((new_psr & PSR_CWP) >= env->nwindows) { |
bc265319 | 3103 | helper_raise_exception(env, TT_ILL_INSN); |
5a834bb4 BS |
3104 | } else { |
3105 | cpu_put_psr(env, new_psr); | |
3106 | } | |
af7bf89b FB |
3107 | } |
3108 | ||
1a2fb1c0 | 3109 | target_ulong helper_rdpsr(void) |
af7bf89b | 3110 | { |
5a834bb4 | 3111 | return get_psr(); |
af7bf89b | 3112 | } |
3475187d FB |
3113 | |
3114 | #else | |
72a9747b BS |
3115 | /* XXX: use another pointer for %iN registers to avoid slow wrapping |
3116 | handling ? */ | |
3117 | void helper_save(void) | |
3118 | { | |
3119 | uint32_t cwp; | |
3120 | ||
5a834bb4 | 3121 | cwp = cwp_dec(env->cwp - 1); |
72a9747b | 3122 | if (env->cansave == 0) { |
bc265319 BS |
3123 | helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ? |
3124 | (TT_WOTHER | | |
3125 | ((env->wstate & 0x38) >> 1)) : | |
3126 | ((env->wstate & 0x7) << 2))); | |
72a9747b BS |
3127 | } else { |
3128 | if (env->cleanwin - env->canrestore == 0) { | |
99ca0219 | 3129 | /* XXX Clean windows without trap */ |
bc265319 | 3130 | helper_raise_exception(env, TT_CLRWIN); |
72a9747b BS |
3131 | } else { |
3132 | env->cansave--; | |
3133 | env->canrestore++; | |
3134 | set_cwp(cwp); | |
3135 | } | |
3136 | } | |
3137 | } | |
3138 | ||
3139 | void helper_restore(void) | |
3140 | { | |
3141 | uint32_t cwp; | |
3142 | ||
5a834bb4 | 3143 | cwp = cwp_inc(env->cwp + 1); |
72a9747b | 3144 | if (env->canrestore == 0) { |
bc265319 BS |
3145 | helper_raise_exception(env, TT_FILL | (env->otherwin != 0 ? |
3146 | (TT_WOTHER | | |
3147 | ((env->wstate & 0x38) >> 1)) : | |
3148 | ((env->wstate & 0x7) << 2))); | |
72a9747b BS |
3149 | } else { |
3150 | env->cansave++; | |
3151 | env->canrestore--; | |
3152 | set_cwp(cwp); | |
3153 | } | |
3154 | } | |
3155 | ||
3156 | void helper_flushw(void) | |
3157 | { | |
1a14026e | 3158 | if (env->cansave != env->nwindows - 2) { |
bc265319 BS |
3159 | helper_raise_exception(env, TT_SPILL | (env->otherwin != 0 ? |
3160 | (TT_WOTHER | | |
3161 | ((env->wstate & 0x38) >> 1)) : | |
3162 | ((env->wstate & 0x7) << 2))); | |
72a9747b BS |
3163 | } |
3164 | } | |
3165 | ||
3166 | void helper_saved(void) | |
3167 | { | |
3168 | env->cansave++; | |
99ca0219 | 3169 | if (env->otherwin == 0) { |
72a9747b | 3170 | env->canrestore--; |
99ca0219 | 3171 | } else { |
72a9747b | 3172 | env->otherwin--; |
99ca0219 | 3173 | } |
72a9747b BS |
3174 | } |
3175 | ||
3176 | void helper_restored(void) | |
3177 | { | |
3178 | env->canrestore++; | |
99ca0219 | 3179 | if (env->cleanwin < env->nwindows - 1) { |
72a9747b | 3180 | env->cleanwin++; |
99ca0219 BS |
3181 | } |
3182 | if (env->otherwin == 0) { | |
72a9747b | 3183 | env->cansave--; |
99ca0219 | 3184 | } else { |
72a9747b | 3185 | env->otherwin--; |
99ca0219 | 3186 | } |
72a9747b BS |
3187 | } |
3188 | ||
5a834bb4 BS |
3189 | static target_ulong get_ccr(void) |
3190 | { | |
3191 | target_ulong psr; | |
3192 | ||
3193 | psr = get_psr(); | |
3194 | ||
3195 | return ((env->xcc >> 20) << 4) | ((psr & PSR_ICC) >> 20); | |
3196 | } | |
3197 | ||
3198 | target_ulong cpu_get_ccr(CPUState *env1) | |
3199 | { | |
3200 | CPUState *saved_env; | |
3201 | target_ulong ret; | |
3202 | ||
3203 | saved_env = env; | |
3204 | env = env1; | |
3205 | ret = get_ccr(); | |
3206 | env = saved_env; | |
3207 | return ret; | |
3208 | } | |
3209 | ||
3210 | static void put_ccr(target_ulong val) | |
3211 | { | |
de18f87e BS |
3212 | env->xcc = (val >> 4) << 20; |
3213 | env->psr = (val & 0xf) << 20; | |
5a834bb4 BS |
3214 | CC_OP = CC_OP_FLAGS; |
3215 | } | |
3216 | ||
3217 | void cpu_put_ccr(CPUState *env1, target_ulong val) | |
3218 | { | |
3219 | CPUState *saved_env; | |
3220 | ||
3221 | saved_env = env; | |
3222 | env = env1; | |
3223 | put_ccr(val); | |
3224 | env = saved_env; | |
3225 | } | |
3226 | ||
3227 | static target_ulong get_cwp64(void) | |
3228 | { | |
3229 | return env->nwindows - 1 - env->cwp; | |
3230 | } | |
3231 | ||
3232 | target_ulong cpu_get_cwp64(CPUState *env1) | |
3233 | { | |
3234 | CPUState *saved_env; | |
3235 | target_ulong ret; | |
3236 | ||
3237 | saved_env = env; | |
3238 | env = env1; | |
3239 | ret = get_cwp64(); | |
3240 | env = saved_env; | |
3241 | return ret; | |
3242 | } | |
3243 | ||
3244 | static void put_cwp64(int cwp) | |
3245 | { | |
3246 | if (unlikely(cwp >= env->nwindows || cwp < 0)) { | |
3247 | cwp %= env->nwindows; | |
3248 | } | |
3249 | set_cwp(env->nwindows - 1 - cwp); | |
3250 | } | |
3251 | ||
3252 | void cpu_put_cwp64(CPUState *env1, int cwp) | |
3253 | { | |
3254 | CPUState *saved_env; | |
3255 | ||
3256 | saved_env = env; | |
3257 | env = env1; | |
3258 | put_cwp64(cwp); | |
3259 | env = saved_env; | |
3260 | } | |
3261 | ||
d35527d9 BS |
3262 | target_ulong helper_rdccr(void) |
3263 | { | |
5a834bb4 | 3264 | return get_ccr(); |
d35527d9 BS |
3265 | } |
3266 | ||
3267 | void helper_wrccr(target_ulong new_ccr) | |
3268 | { | |
5a834bb4 | 3269 | put_ccr(new_ccr); |
d35527d9 BS |
3270 | } |
3271 | ||
99ca0219 BS |
3272 | /* CWP handling is reversed in V9, but we still use the V8 register |
3273 | order. */ | |
d35527d9 BS |
3274 | target_ulong helper_rdcwp(void) |
3275 | { | |
5a834bb4 | 3276 | return get_cwp64(); |
d35527d9 BS |
3277 | } |
3278 | ||
3279 | void helper_wrcwp(target_ulong new_cwp) | |
3280 | { | |
5a834bb4 | 3281 | put_cwp64(new_cwp); |
d35527d9 | 3282 | } |
3475187d | 3283 | |
d780a466 | 3284 | static inline uint64_t *get_gregset(uint32_t pstate) |
83469015 FB |
3285 | { |
3286 | switch (pstate) { | |
3287 | default: | |
7e8695ed | 3288 | DPRINTF_PSTATE("ERROR in get_gregset: active pstate bits=%x%s%s%s\n", |
99ca0219 BS |
3289 | pstate, |
3290 | (pstate & PS_IG) ? " IG" : "", | |
3291 | (pstate & PS_MG) ? " MG" : "", | |
3292 | (pstate & PS_AG) ? " AG" : ""); | |
7e8695ed | 3293 | /* pass through to normal set of global registers */ |
83469015 | 3294 | case 0: |
0f8a249a | 3295 | return env->bgregs; |
83469015 | 3296 | case PS_AG: |
0f8a249a | 3297 | return env->agregs; |
83469015 | 3298 | case PS_MG: |
0f8a249a | 3299 | return env->mgregs; |
83469015 | 3300 | case PS_IG: |
0f8a249a | 3301 | return env->igregs; |
83469015 FB |
3302 | } |
3303 | } | |
3304 | ||
d780a466 | 3305 | static inline void change_pstate(uint32_t new_pstate) |
83469015 | 3306 | { |
d780a466 | 3307 | uint32_t pstate_regs, new_pstate_regs; |
83469015 FB |
3308 | uint64_t *src, *dst; |
3309 | ||
5210977a | 3310 | if (env->def->features & CPU_FEATURE_GL) { |
99ca0219 | 3311 | /* PS_AG is not implemented in this case */ |
5210977a IK |
3312 | new_pstate &= ~PS_AG; |
3313 | } | |
3314 | ||
83469015 FB |
3315 | pstate_regs = env->pstate & 0xc01; |
3316 | new_pstate_regs = new_pstate & 0xc01; | |
5210977a | 3317 | |
83469015 | 3318 | if (new_pstate_regs != pstate_regs) { |
7e8695ed IK |
3319 | DPRINTF_PSTATE("change_pstate: switching regs old=%x new=%x\n", |
3320 | pstate_regs, new_pstate_regs); | |
99ca0219 | 3321 | /* Switch global register bank */ |
0f8a249a BS |
3322 | src = get_gregset(new_pstate_regs); |
3323 | dst = get_gregset(pstate_regs); | |
3324 | memcpy32(dst, env->gregs); | |
3325 | memcpy32(env->gregs, src); | |
99ca0219 | 3326 | } else { |
7e8695ed IK |
3327 | DPRINTF_PSTATE("change_pstate: regs new=%x (unchanged)\n", |
3328 | new_pstate_regs); | |
3329 | } | |
83469015 FB |
3330 | env->pstate = new_pstate; |
3331 | } | |
3332 | ||
1a2fb1c0 | 3333 | void helper_wrpstate(target_ulong new_state) |
8f1f22f6 | 3334 | { |
5210977a | 3335 | change_pstate(new_state & 0xf3f); |
4dc28134 IK |
3336 | |
3337 | #if !defined(CONFIG_USER_ONLY) | |
3338 | if (cpu_interrupts_enabled(env)) { | |
3339 | cpu_check_irqs(env); | |
3340 | } | |
3341 | #endif | |
8f1f22f6 BS |
3342 | } |
3343 | ||
e67768d0 BS |
3344 | void cpu_change_pstate(CPUState *env1, uint32_t new_pstate) |
3345 | { | |
3346 | CPUState *saved_env; | |
3347 | ||
3348 | saved_env = env; | |
3349 | env = env1; | |
3350 | change_pstate(new_pstate); | |
3351 | env = saved_env; | |
3352 | } | |
3353 | ||
1fae7b70 IK |
3354 | void helper_wrpil(target_ulong new_pil) |
3355 | { | |
3356 | #if !defined(CONFIG_USER_ONLY) | |
3357 | DPRINTF_PSTATE("helper_wrpil old=%x new=%x\n", | |
3358 | env->psrpil, (uint32_t)new_pil); | |
3359 | ||
3360 | env->psrpil = new_pil; | |
3361 | ||
3362 | if (cpu_interrupts_enabled(env)) { | |
3363 | cpu_check_irqs(env); | |
3364 | } | |
3365 | #endif | |
3366 | } | |
3367 | ||
1a2fb1c0 | 3368 | void helper_done(void) |
83469015 | 3369 | { |
99ca0219 | 3370 | trap_state *tsptr = cpu_tsptr(env); |
8194f35a | 3371 | |
3723cd09 | 3372 | env->pc = tsptr->tnpc; |
8194f35a | 3373 | env->npc = tsptr->tnpc + 4; |
5a834bb4 | 3374 | put_ccr(tsptr->tstate >> 32); |
8194f35a IK |
3375 | env->asi = (tsptr->tstate >> 24) & 0xff; |
3376 | change_pstate((tsptr->tstate >> 8) & 0xf3f); | |
5a834bb4 | 3377 | put_cwp64(tsptr->tstate & 0xff); |
e6bf7d70 | 3378 | env->tl--; |
4dc28134 IK |
3379 | |
3380 | DPRINTF_PSTATE("... helper_done tl=%d\n", env->tl); | |
3381 | ||
3382 | #if !defined(CONFIG_USER_ONLY) | |
3383 | if (cpu_interrupts_enabled(env)) { | |
3384 | cpu_check_irqs(env); | |
3385 | } | |
3386 | #endif | |
83469015 FB |
3387 | } |
3388 | ||
1a2fb1c0 | 3389 | void helper_retry(void) |
83469015 | 3390 | { |
99ca0219 | 3391 | trap_state *tsptr = cpu_tsptr(env); |
8194f35a IK |
3392 | |
3393 | env->pc = tsptr->tpc; | |
3394 | env->npc = tsptr->tnpc; | |
5a834bb4 | 3395 | put_ccr(tsptr->tstate >> 32); |
8194f35a IK |
3396 | env->asi = (tsptr->tstate >> 24) & 0xff; |
3397 | change_pstate((tsptr->tstate >> 8) & 0xf3f); | |
5a834bb4 | 3398 | put_cwp64(tsptr->tstate & 0xff); |
e6bf7d70 | 3399 | env->tl--; |
4dc28134 IK |
3400 | |
3401 | DPRINTF_PSTATE("... helper_retry tl=%d\n", env->tl); | |
3402 | ||
3403 | #if !defined(CONFIG_USER_ONLY) | |
3404 | if (cpu_interrupts_enabled(env)) { | |
3405 | cpu_check_irqs(env); | |
3406 | } | |
3407 | #endif | |
3408 | } | |
3409 | ||
99ca0219 | 3410 | static void do_modify_softint(const char *operation, uint32_t value) |
4dc28134 IK |
3411 | { |
3412 | if (env->softint != value) { | |
3413 | env->softint = value; | |
3414 | DPRINTF_PSTATE(": %s new %08x\n", operation, env->softint); | |
3415 | #if !defined(CONFIG_USER_ONLY) | |
3416 | if (cpu_interrupts_enabled(env)) { | |
3417 | cpu_check_irqs(env); | |
3418 | } | |
3419 | #endif | |
3420 | } | |
83469015 | 3421 | } |
9d926598 BS |
3422 | |
3423 | void helper_set_softint(uint64_t value) | |
3424 | { | |
4dc28134 | 3425 | do_modify_softint("helper_set_softint", env->softint | (uint32_t)value); |
9d926598 BS |
3426 | } |
3427 | ||
3428 | void helper_clear_softint(uint64_t value) | |
3429 | { | |
4dc28134 | 3430 | do_modify_softint("helper_clear_softint", env->softint & (uint32_t)~value); |
9d926598 BS |
3431 | } |
3432 | ||
3433 | void helper_write_softint(uint64_t value) | |
3434 | { | |
4dc28134 | 3435 | do_modify_softint("helper_write_softint", (uint32_t)value); |
9d926598 | 3436 | } |
3475187d | 3437 | #endif |
ee5bbe38 | 3438 | |
5fafdf24 | 3439 | #if !defined(CONFIG_USER_ONLY) |
ee5bbe38 | 3440 | |
d2889a3e BS |
3441 | static void do_unaligned_access(target_ulong addr, int is_write, int is_user, |
3442 | void *retaddr); | |
3443 | ||
ee5bbe38 | 3444 | #define MMUSUFFIX _mmu |
d2889a3e | 3445 | #define ALIGNED_ONLY |
ee5bbe38 FB |
3446 | |
3447 | #define SHIFT 0 | |
3448 | #include "softmmu_template.h" | |
3449 | ||
3450 | #define SHIFT 1 | |
3451 | #include "softmmu_template.h" | |
3452 | ||
3453 | #define SHIFT 2 | |
3454 | #include "softmmu_template.h" | |
3455 | ||
3456 | #define SHIFT 3 | |
3457 | #include "softmmu_template.h" | |
3458 | ||
c2bc0e38 BS |
3459 | /* XXX: make it generic ? */ |
3460 | static void cpu_restore_state2(void *retaddr) | |
3461 | { | |
3462 | TranslationBlock *tb; | |
3463 | unsigned long pc; | |
3464 | ||
3465 | if (retaddr) { | |
3466 | /* now we have a real cpu fault */ | |
3467 | pc = (unsigned long)retaddr; | |
3468 | tb = tb_find_pc(pc); | |
3469 | if (tb) { | |
3470 | /* the PC is inside the translated code. It means that we have | |
3471 | a virtual CPU fault */ | |
618ba8e6 | 3472 | cpu_restore_state(tb, env, pc); |
c2bc0e38 BS |
3473 | } |
3474 | } | |
3475 | } | |
3476 | ||
d2889a3e BS |
3477 | static void do_unaligned_access(target_ulong addr, int is_write, int is_user, |
3478 | void *retaddr) | |
3479 | { | |
94554550 | 3480 | #ifdef DEBUG_UNALIGNED |
c2bc0e38 BS |
3481 | printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx |
3482 | "\n", addr, env->pc); | |
94554550 | 3483 | #endif |
c2bc0e38 | 3484 | cpu_restore_state2(retaddr); |
bc265319 | 3485 | helper_raise_exception(env, TT_UNALIGNED); |
d2889a3e | 3486 | } |
ee5bbe38 FB |
3487 | |
3488 | /* try to fill the TLB and return an exception if error. If retaddr is | |
3489 | NULL, it means that the function was called in C code (i.e. not | |
3490 | from generated code or from helper.c) */ | |
3491 | /* XXX: fix it to restore all registers */ | |
bccd9ec5 BS |
3492 | void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx, |
3493 | void *retaddr) | |
ee5bbe38 | 3494 | { |
ee5bbe38 | 3495 | int ret; |
ee5bbe38 FB |
3496 | CPUState *saved_env; |
3497 | ||
ee5bbe38 | 3498 | saved_env = env; |
bccd9ec5 | 3499 | env = env1; |
ee5bbe38 | 3500 | |
97b348e7 | 3501 | ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx); |
ee5bbe38 | 3502 | if (ret) { |
c2bc0e38 | 3503 | cpu_restore_state2(retaddr); |
1162c041 | 3504 | cpu_loop_exit(env); |
ee5bbe38 FB |
3505 | } |
3506 | env = saved_env; | |
3507 | } | |
3508 | ||
3c7b48b7 | 3509 | #endif /* !CONFIG_USER_ONLY */ |
6c36d3fa BS |
3510 | |
3511 | #ifndef TARGET_SPARC64 | |
3c7b48b7 | 3512 | #if !defined(CONFIG_USER_ONLY) |
b14ef7c9 BS |
3513 | static void do_unassigned_access(target_phys_addr_t addr, int is_write, |
3514 | int is_exec, int is_asi, int size) | |
6c36d3fa | 3515 | { |
576c2cdc | 3516 | int fault_type; |
6c36d3fa | 3517 | |
8543e2cf | 3518 | #ifdef DEBUG_UNASSIGNED |
99ca0219 | 3519 | if (is_asi) { |
e18231a3 | 3520 | printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx |
77f193da | 3521 | " asi 0x%02x from " TARGET_FMT_lx "\n", |
e18231a3 BS |
3522 | is_exec ? "exec" : is_write ? "write" : "read", size, |
3523 | size == 1 ? "" : "s", addr, is_asi, env->pc); | |
99ca0219 | 3524 | } else { |
e18231a3 BS |
3525 | printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx |
3526 | " from " TARGET_FMT_lx "\n", | |
3527 | is_exec ? "exec" : is_write ? "write" : "read", size, | |
3528 | size == 1 ? "" : "s", addr, env->pc); | |
99ca0219 | 3529 | } |
8543e2cf | 3530 | #endif |
576c2cdc AT |
3531 | /* Don't overwrite translation and access faults */ |
3532 | fault_type = (env->mmuregs[3] & 0x1c) >> 2; | |
3533 | if ((fault_type > 4) || (fault_type == 0)) { | |
3534 | env->mmuregs[3] = 0; /* Fault status register */ | |
99ca0219 | 3535 | if (is_asi) { |
576c2cdc | 3536 | env->mmuregs[3] |= 1 << 16; |
99ca0219 BS |
3537 | } |
3538 | if (env->psrs) { | |
576c2cdc | 3539 | env->mmuregs[3] |= 1 << 5; |
99ca0219 BS |
3540 | } |
3541 | if (is_exec) { | |
576c2cdc | 3542 | env->mmuregs[3] |= 1 << 6; |
99ca0219 BS |
3543 | } |
3544 | if (is_write) { | |
576c2cdc | 3545 | env->mmuregs[3] |= 1 << 7; |
99ca0219 | 3546 | } |
576c2cdc AT |
3547 | env->mmuregs[3] |= (5 << 2) | 2; |
3548 | /* SuperSPARC will never place instruction fault addresses in the FAR */ | |
3549 | if (!is_exec) { | |
3550 | env->mmuregs[4] = addr; /* Fault address register */ | |
3551 | } | |
3552 | } | |
3553 | /* overflow (same type fault was not read before another fault) */ | |
3554 | if (fault_type == ((env->mmuregs[3] & 0x1c)) >> 2) { | |
3555 | env->mmuregs[3] |= 1; | |
3556 | } | |
3557 | ||
6c36d3fa | 3558 | if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) { |
99ca0219 | 3559 | if (is_exec) { |
bc265319 | 3560 | helper_raise_exception(env, TT_CODE_ACCESS); |
99ca0219 | 3561 | } else { |
bc265319 | 3562 | helper_raise_exception(env, TT_DATA_ACCESS); |
99ca0219 | 3563 | } |
6c36d3fa | 3564 | } |
576c2cdc AT |
3565 | |
3566 | /* flush neverland mappings created during no-fault mode, | |
3567 | so the sequential MMU faults report proper fault types */ | |
3568 | if (env->mmuregs[0] & MMU_NF) { | |
3569 | tlb_flush(env, 1); | |
3570 | } | |
6c36d3fa | 3571 | } |
3c7b48b7 PB |
3572 | #endif |
3573 | #else | |
3574 | #if defined(CONFIG_USER_ONLY) | |
3575 | static void do_unassigned_access(target_ulong addr, int is_write, int is_exec, | |
99ca0219 | 3576 | int is_asi, int size) |
6c36d3fa | 3577 | #else |
b14ef7c9 BS |
3578 | static void do_unassigned_access(target_phys_addr_t addr, int is_write, |
3579 | int is_exec, int is_asi, int size) | |
3c7b48b7 | 3580 | #endif |
6c36d3fa | 3581 | { |
dffbe217 | 3582 | #ifdef DEBUG_UNASSIGNED |
77f193da BS |
3583 | printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx |
3584 | "\n", addr, env->pc); | |
6c36d3fa | 3585 | #endif |
dffbe217 | 3586 | |
99ca0219 | 3587 | if (is_exec) { |
bc265319 | 3588 | helper_raise_exception(env, TT_CODE_ACCESS); |
99ca0219 | 3589 | } else { |
bc265319 | 3590 | helper_raise_exception(env, TT_DATA_ACCESS); |
99ca0219 | 3591 | } |
6c36d3fa BS |
3592 | } |
3593 | #endif | |
20c9f095 | 3594 | |
b14ef7c9 BS |
3595 | #if !defined(CONFIG_USER_ONLY) |
3596 | void cpu_unassigned_access(CPUState *env1, target_phys_addr_t addr, | |
3597 | int is_write, int is_exec, int is_asi, int size) | |
3598 | { | |
67494323 BS |
3599 | CPUState *saved_env; |
3600 | ||
3601 | saved_env = env; | |
b14ef7c9 | 3602 | env = env1; |
67494323 BS |
3603 | /* Ignore unassigned accesses outside of CPU context */ |
3604 | if (env1) { | |
3605 | do_unassigned_access(addr, is_write, is_exec, is_asi, size); | |
3606 | } | |
3607 | env = saved_env; | |
b14ef7c9 BS |
3608 | } |
3609 | #endif |