]> git.proxmox.com Git - qemu.git/blame - target-sparc/op_helper.c
find -type f | xargs sed -i 's/[\t ]*$//g' # Yes, again. Note the star in the regex.
[qemu.git] / target-sparc / op_helper.c
CommitLineData
e8af50a3
FB
1#include "exec.h"
2
83469015 3//#define DEBUG_PCALL
e80cfcfc 4//#define DEBUG_MMU
94554550 5//#define DEBUG_UNALIGNED
6c36d3fa 6//#define DEBUG_UNASSIGNED
e80cfcfc 7
9d893301
FB
8void raise_exception(int tt)
9{
10 env->exception_index = tt;
11 cpu_loop_exit();
3b46e624 12}
9d893301 13
417454b0
BS
14void check_ieee_exceptions()
15{
16 T0 = get_float_exception_flags(&env->fp_status);
17 if (T0)
18 {
19 /* Copy IEEE 754 flags into FSR */
20 if (T0 & float_flag_invalid)
21 env->fsr |= FSR_NVC;
22 if (T0 & float_flag_overflow)
23 env->fsr |= FSR_OFC;
24 if (T0 & float_flag_underflow)
25 env->fsr |= FSR_UFC;
26 if (T0 & float_flag_divbyzero)
27 env->fsr |= FSR_DZC;
28 if (T0 & float_flag_inexact)
29 env->fsr |= FSR_NXC;
30
31 if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23))
32 {
33 /* Unmasked exception, generate a trap */
34 env->fsr |= FSR_FTT_IEEE_EXCP;
35 raise_exception(TT_FP_EXCP);
36 }
37 else
38 {
39 /* Accumulate exceptions */
40 env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
41 }
42 }
43}
44
a0c4cb4a
FB
45#ifdef USE_INT_TO_FLOAT_HELPERS
46void do_fitos(void)
47{
417454b0 48 set_float_exception_flags(0, &env->fp_status);
ec230928 49 FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status);
417454b0 50 check_ieee_exceptions();
a0c4cb4a
FB
51}
52
53void do_fitod(void)
54{
ec230928 55 DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status);
a0c4cb4a
FB
56}
57#endif
58
59void do_fabss(void)
e8af50a3 60{
7a0e1f41 61 FT0 = float32_abs(FT1);
e8af50a3
FB
62}
63
3475187d
FB
64#ifdef TARGET_SPARC64
65void do_fabsd(void)
66{
67 DT0 = float64_abs(DT1);
68}
69#endif
70
a0c4cb4a 71void do_fsqrts(void)
e8af50a3 72{
417454b0 73 set_float_exception_flags(0, &env->fp_status);
7a0e1f41 74 FT0 = float32_sqrt(FT1, &env->fp_status);
417454b0 75 check_ieee_exceptions();
e8af50a3
FB
76}
77
a0c4cb4a 78void do_fsqrtd(void)
e8af50a3 79{
417454b0 80 set_float_exception_flags(0, &env->fp_status);
7a0e1f41 81 DT0 = float64_sqrt(DT1, &env->fp_status);
417454b0 82 check_ieee_exceptions();
e8af50a3
FB
83}
84
417454b0 85#define GEN_FCMP(name, size, reg1, reg2, FS, TRAP) \
65ce8c2f
FB
86 void glue(do_, name) (void) \
87 { \
88 env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
89 switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \
90 case float_relation_unordered: \
91 T0 = (FSR_FCC1 | FSR_FCC0) << FS; \
417454b0 92 if ((env->fsr & FSR_NVM) || TRAP) { \
65ce8c2f 93 env->fsr |= T0; \
417454b0
BS
94 env->fsr |= FSR_NVC; \
95 env->fsr |= FSR_FTT_IEEE_EXCP; \
65ce8c2f
FB
96 raise_exception(TT_FP_EXCP); \
97 } else { \
98 env->fsr |= FSR_NVA; \
99 } \
100 break; \
101 case float_relation_less: \
102 T0 = FSR_FCC0 << FS; \
103 break; \
104 case float_relation_greater: \
105 T0 = FSR_FCC1 << FS; \
106 break; \
107 default: \
108 T0 = 0; \
109 break; \
110 } \
111 env->fsr |= T0; \
e8af50a3 112 }
e8af50a3 113
417454b0
BS
114GEN_FCMP(fcmps, float32, FT0, FT1, 0, 0);
115GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
116
117GEN_FCMP(fcmpes, float32, FT0, FT1, 0, 1);
118GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
3475187d
FB
119
120#ifdef TARGET_SPARC64
417454b0
BS
121GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22, 0);
122GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
123
124GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24, 0);
125GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
126
127GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26, 0);
128GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
129
130GEN_FCMP(fcmpes_fcc1, float32, FT0, FT1, 22, 1);
131GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
3475187d 132
417454b0
BS
133GEN_FCMP(fcmpes_fcc2, float32, FT0, FT1, 24, 1);
134GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
3475187d 135
417454b0
BS
136GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1);
137GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
3475187d
FB
138#endif
139
5fafdf24 140#if defined(CONFIG_USER_ONLY)
24741ef3
FB
141void helper_ld_asi(int asi, int size, int sign)
142{
143}
144
145void helper_st_asi(int asi, int size, int sign)
146{
147}
148#else
3475187d 149#ifndef TARGET_SPARC64
a0c4cb4a 150void helper_ld_asi(int asi, int size, int sign)
e8af50a3 151{
83469015 152 uint32_t ret = 0;
e80cfcfc
FB
153
154 switch (asi) {
6c36d3fa
BS
155 case 2: /* SuperSparc MXCC registers */
156 break;
e8af50a3 157 case 3: /* MMU probe */
e80cfcfc
FB
158 {
159 int mmulev;
160
161 mmulev = (T0 >> 8) & 15;
162 if (mmulev > 4)
163 ret = 0;
164 else {
ee5bbe38 165 ret = mmu_probe(env, T0, mmulev);
e80cfcfc
FB
166 //bswap32s(&ret);
167 }
168#ifdef DEBUG_MMU
169 printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret);
170#endif
171 }
172 break;
e8af50a3
FB
173 case 4: /* read MMU regs */
174 {
e80cfcfc 175 int reg = (T0 >> 8) & 0xf;
3b46e624 176
e80cfcfc 177 ret = env->mmuregs[reg];
55754d9e
FB
178 if (reg == 3) /* Fault status cleared on read */
179 env->mmuregs[reg] = 0;
180#ifdef DEBUG_MMU
181 printf("mmu_read: reg[%d] = 0x%08x\n", reg, ret);
182#endif
e8af50a3 183 }
e80cfcfc 184 break;
6c36d3fa
BS
185 case 9: /* Supervisor code access */
186 switch(size) {
187 case 1:
188 ret = ldub_code(T0);
189 break;
190 case 2:
191 ret = lduw_code(T0 & ~1);
192 break;
193 default:
194 case 4:
195 ret = ldl_code(T0 & ~3);
196 break;
197 case 8:
198 ret = ldl_code(T0 & ~3);
199 T0 = ldl_code((T0 + 4) & ~3);
200 break;
201 }
202 break;
203 case 0xc: /* I-cache tag */
204 case 0xd: /* I-cache data */
205 case 0xe: /* D-cache tag */
206 case 0xf: /* D-cache data */
207 break;
208 case 0x20: /* MMU passthrough */
02aab46a
FB
209 switch(size) {
210 case 1:
211 ret = ldub_phys(T0);
212 break;
213 case 2:
214 ret = lduw_phys(T0 & ~1);
215 break;
216 default:
217 case 4:
218 ret = ldl_phys(T0 & ~3);
219 break;
9e61bde5
FB
220 case 8:
221 ret = ldl_phys(T0 & ~3);
222 T0 = ldl_phys((T0 + 4) & ~3);
223 break;
02aab46a 224 }
e80cfcfc 225 break;
5dcb6b91
BS
226 case 0x2e: /* MMU passthrough, 0xexxxxxxxx */
227 case 0x2f: /* MMU passthrough, 0xfxxxxxxxx */
228 switch(size) {
229 case 1:
230 ret = ldub_phys((target_phys_addr_t)T0
231 | ((target_phys_addr_t)(asi & 0xf) << 32));
232 break;
233 case 2:
234 ret = lduw_phys((target_phys_addr_t)(T0 & ~1)
235 | ((target_phys_addr_t)(asi & 0xf) << 32));
236 break;
237 default:
238 case 4:
239 ret = ldl_phys((target_phys_addr_t)(T0 & ~3)
240 | ((target_phys_addr_t)(asi & 0xf) << 32));
241 break;
242 case 8:
243 ret = ldl_phys((target_phys_addr_t)(T0 & ~3)
244 | ((target_phys_addr_t)(asi & 0xf) << 32));
245 T0 = ldl_phys((target_phys_addr_t)((T0 + 4) & ~3)
246 | ((target_phys_addr_t)(asi & 0xf) << 32));
247 break;
248 }
249 break;
250 case 0x21 ... 0x2d: /* MMU passthrough, unassigned */
e8af50a3 251 default:
6c36d3fa 252 do_unassigned_access(T0, 0, 0, 1);
e80cfcfc
FB
253 ret = 0;
254 break;
e8af50a3 255 }
e80cfcfc 256 T1 = ret;
e8af50a3
FB
257}
258
a0c4cb4a 259void helper_st_asi(int asi, int size, int sign)
e8af50a3
FB
260{
261 switch(asi) {
6c36d3fa
BS
262 case 2: /* SuperSparc MXCC registers */
263 break;
e8af50a3 264 case 3: /* MMU flush */
e80cfcfc
FB
265 {
266 int mmulev;
267
268 mmulev = (T0 >> 8) & 15;
55754d9e
FB
269#ifdef DEBUG_MMU
270 printf("mmu flush level %d\n", mmulev);
271#endif
e80cfcfc
FB
272 switch (mmulev) {
273 case 0: // flush page
55754d9e 274 tlb_flush_page(env, T0 & 0xfffff000);
e80cfcfc
FB
275 break;
276 case 1: // flush segment (256k)
277 case 2: // flush region (16M)
278 case 3: // flush context (4G)
279 case 4: // flush entire
55754d9e 280 tlb_flush(env, 1);
e80cfcfc
FB
281 break;
282 default:
283 break;
284 }
55754d9e 285#ifdef DEBUG_MMU
ee5bbe38 286 dump_mmu(env);
55754d9e 287#endif
e80cfcfc
FB
288 return;
289 }
e8af50a3
FB
290 case 4: /* write MMU regs */
291 {
83469015
FB
292 int reg = (T0 >> 8) & 0xf;
293 uint32_t oldreg;
3b46e624 294
e80cfcfc 295 oldreg = env->mmuregs[reg];
55754d9e
FB
296 switch(reg) {
297 case 0:
e8af50a3
FB
298 env->mmuregs[reg] &= ~(MMU_E | MMU_NF);
299 env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF);
6f7e9aec
FB
300 // Mappings generated during no-fault mode or MMU
301 // disabled mode are invalid in normal mode
302 if (oldreg != env->mmuregs[reg])
55754d9e
FB
303 tlb_flush(env, 1);
304 break;
305 case 2:
e8af50a3 306 env->mmuregs[reg] = T1;
55754d9e
FB
307 if (oldreg != env->mmuregs[reg]) {
308 /* we flush when the MMU context changes because
309 QEMU has no MMU context support */
310 tlb_flush(env, 1);
311 }
312 break;
313 case 3:
314 case 4:
315 break;
316 default:
317 env->mmuregs[reg] = T1;
318 break;
319 }
320#ifdef DEBUG_MMU
321 if (oldreg != env->mmuregs[reg]) {
322 printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->mmuregs[reg]);
323 }
ee5bbe38 324 dump_mmu(env);
55754d9e 325#endif
e8af50a3
FB
326 return;
327 }
6c36d3fa
BS
328 case 0xc: /* I-cache tag */
329 case 0xd: /* I-cache data */
330 case 0xe: /* D-cache tag */
331 case 0xf: /* D-cache data */
332 case 0x10: /* I/D-cache flush page */
333 case 0x11: /* I/D-cache flush segment */
334 case 0x12: /* I/D-cache flush region */
335 case 0x13: /* I/D-cache flush context */
336 case 0x14: /* I/D-cache flush user */
337 break;
e80cfcfc
FB
338 case 0x17: /* Block copy, sta access */
339 {
340 // value (T1) = src
341 // address (T0) = dst
342 // copy 32 bytes
6c36d3fa
BS
343 unsigned int i;
344 uint32_t src = T1 & ~3, dst = T0 & ~3, temp;
3b46e624 345
6c36d3fa
BS
346 for (i = 0; i < 32; i += 4, src += 4, dst += 4) {
347 temp = ldl_kernel(src);
348 stl_kernel(dst, temp);
349 }
e80cfcfc
FB
350 }
351 return;
352 case 0x1f: /* Block fill, stda access */
353 {
354 // value (T1, T2)
355 // address (T0) = dst
356 // fill 32 bytes
6c36d3fa
BS
357 unsigned int i;
358 uint32_t dst = T0 & 7;
359 uint64_t val;
e80cfcfc 360
6c36d3fa
BS
361 val = (((uint64_t)T1) << 32) | T2;
362
363 for (i = 0; i < 32; i += 8, dst += 8)
364 stq_kernel(dst, val);
e80cfcfc
FB
365 }
366 return;
6c36d3fa 367 case 0x20: /* MMU passthrough */
e8af50a3 368 {
02aab46a
FB
369 switch(size) {
370 case 1:
371 stb_phys(T0, T1);
372 break;
373 case 2:
374 stw_phys(T0 & ~1, T1);
375 break;
376 case 4:
377 default:
378 stl_phys(T0 & ~3, T1);
379 break;
9e61bde5
FB
380 case 8:
381 stl_phys(T0 & ~3, T1);
382 stl_phys((T0 + 4) & ~3, T2);
383 break;
02aab46a 384 }
e8af50a3
FB
385 }
386 return;
5dcb6b91
BS
387 case 0x2e: /* MMU passthrough, 0xexxxxxxxx */
388 case 0x2f: /* MMU passthrough, 0xfxxxxxxxx */
389 {
390 switch(size) {
391 case 1:
392 stb_phys((target_phys_addr_t)T0
393 | ((target_phys_addr_t)(asi & 0xf) << 32), T1);
394 break;
395 case 2:
396 stw_phys((target_phys_addr_t)(T0 & ~1)
397 | ((target_phys_addr_t)(asi & 0xf) << 32), T1);
398 break;
399 case 4:
400 default:
401 stl_phys((target_phys_addr_t)(T0 & ~3)
402 | ((target_phys_addr_t)(asi & 0xf) << 32), T1);
403 break;
404 case 8:
405 stl_phys((target_phys_addr_t)(T0 & ~3)
406 | ((target_phys_addr_t)(asi & 0xf) << 32), T1);
407 stl_phys((target_phys_addr_t)((T0 + 4) & ~3)
408 | ((target_phys_addr_t)(asi & 0xf) << 32), T1);
409 break;
410 }
411 }
412 return;
6c36d3fa
BS
413 case 0x31: /* Ross RT620 I-cache flush */
414 case 0x36: /* I-cache flash clear */
415 case 0x37: /* D-cache flash clear */
416 break;
417 case 9: /* Supervisor code access, XXX */
5dcb6b91 418 case 0x21 ... 0x2d: /* MMU passthrough, unassigned */
e8af50a3 419 default:
6c36d3fa 420 do_unassigned_access(T0, 1, 0, 1);
e8af50a3
FB
421 return;
422 }
423}
424
3475187d
FB
425#else
426
427void helper_ld_asi(int asi, int size, int sign)
428{
83469015 429 uint64_t ret = 0;
3475187d
FB
430
431 if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
83469015 432 raise_exception(TT_PRIV_ACT);
3475187d
FB
433
434 switch (asi) {
435 case 0x14: // Bypass
436 case 0x15: // Bypass, non-cacheable
437 {
02aab46a
FB
438 switch(size) {
439 case 1:
440 ret = ldub_phys(T0);
441 break;
442 case 2:
443 ret = lduw_phys(T0 & ~1);
444 break;
445 case 4:
446 ret = ldl_phys(T0 & ~3);
447 break;
448 default:
449 case 8:
450 ret = ldq_phys(T0 & ~7);
451 break;
452 }
3475187d
FB
453 break;
454 }
83469015
FB
455 case 0x04: // Nucleus
456 case 0x0c: // Nucleus Little Endian (LE)
457 case 0x10: // As if user primary
458 case 0x11: // As if user secondary
459 case 0x18: // As if user primary LE
460 case 0x19: // As if user secondary LE
3475187d
FB
461 case 0x1c: // Bypass LE
462 case 0x1d: // Bypass, non-cacheable LE
83469015
FB
463 case 0x24: // Nucleus quad LDD 128 bit atomic
464 case 0x2c: // Nucleus quad LDD 128 bit atomic
465 case 0x4a: // UPA config
466 case 0x82: // Primary no-fault
467 case 0x83: // Secondary no-fault
468 case 0x88: // Primary LE
469 case 0x89: // Secondary LE
470 case 0x8a: // Primary no-fault LE
471 case 0x8b: // Secondary no-fault LE
3475187d
FB
472 // XXX
473 break;
474 case 0x45: // LSU
475 ret = env->lsu;
476 break;
477 case 0x50: // I-MMU regs
478 {
479 int reg = (T0 >> 3) & 0xf;
480
481 ret = env->immuregs[reg];
482 break;
483 }
484 case 0x51: // I-MMU 8k TSB pointer
485 case 0x52: // I-MMU 64k TSB pointer
486 case 0x55: // I-MMU data access
83469015 487 // XXX
3475187d 488 break;
83469015
FB
489 case 0x56: // I-MMU tag read
490 {
491 unsigned int i;
3b46e624 492
83469015
FB
493 for (i = 0; i < 64; i++) {
494 // Valid, ctx match, vaddr match
495 if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0 &&
496 env->itlb_tag[i] == T0) {
497 ret = env->itlb_tag[i];
498 break;
499 }
500 }
501 break;
502 }
3475187d
FB
503 case 0x58: // D-MMU regs
504 {
505 int reg = (T0 >> 3) & 0xf;
506
507 ret = env->dmmuregs[reg];
508 break;
509 }
83469015
FB
510 case 0x5e: // D-MMU tag read
511 {
512 unsigned int i;
3b46e624 513
83469015
FB
514 for (i = 0; i < 64; i++) {
515 // Valid, ctx match, vaddr match
516 if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0 &&
517 env->dtlb_tag[i] == T0) {
518 ret = env->dtlb_tag[i];
519 break;
520 }
521 }
522 break;
523 }
3475187d
FB
524 case 0x59: // D-MMU 8k TSB pointer
525 case 0x5a: // D-MMU 64k TSB pointer
526 case 0x5b: // D-MMU data pointer
527 case 0x5d: // D-MMU data access
83469015
FB
528 case 0x48: // Interrupt dispatch, RO
529 case 0x49: // Interrupt data receive
530 case 0x7f: // Incoming interrupt vector, RO
531 // XXX
3475187d
FB
532 break;
533 case 0x54: // I-MMU data in, WO
534 case 0x57: // I-MMU demap, WO
535 case 0x5c: // D-MMU data in, WO
536 case 0x5f: // D-MMU demap, WO
83469015 537 case 0x77: // Interrupt vector, WO
3475187d 538 default:
6c36d3fa 539 do_unassigned_access(T0, 0, 0, 1);
3475187d
FB
540 ret = 0;
541 break;
542 }
543 T1 = ret;
544}
545
546void helper_st_asi(int asi, int size, int sign)
547{
548 if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
83469015 549 raise_exception(TT_PRIV_ACT);
3475187d
FB
550
551 switch(asi) {
552 case 0x14: // Bypass
553 case 0x15: // Bypass, non-cacheable
554 {
02aab46a
FB
555 switch(size) {
556 case 1:
557 stb_phys(T0, T1);
558 break;
559 case 2:
560 stw_phys(T0 & ~1, T1);
561 break;
562 case 4:
563 stl_phys(T0 & ~3, T1);
564 break;
565 case 8:
566 default:
567 stq_phys(T0 & ~7, T1);
568 break;
569 }
3475187d
FB
570 }
571 return;
83469015
FB
572 case 0x04: // Nucleus
573 case 0x0c: // Nucleus Little Endian (LE)
574 case 0x10: // As if user primary
575 case 0x11: // As if user secondary
576 case 0x18: // As if user primary LE
577 case 0x19: // As if user secondary LE
3475187d
FB
578 case 0x1c: // Bypass LE
579 case 0x1d: // Bypass, non-cacheable LE
83469015
FB
580 case 0x24: // Nucleus quad LDD 128 bit atomic
581 case 0x2c: // Nucleus quad LDD 128 bit atomic
582 case 0x4a: // UPA config
583 case 0x88: // Primary LE
584 case 0x89: // Secondary LE
3475187d
FB
585 // XXX
586 return;
587 case 0x45: // LSU
588 {
589 uint64_t oldreg;
590
591 oldreg = env->lsu;
592 env->lsu = T1 & (DMMU_E | IMMU_E);
593 // Mappings generated during D/I MMU disabled mode are
594 // invalid in normal mode
83469015
FB
595 if (oldreg != env->lsu) {
596#ifdef DEBUG_MMU
26a76461 597 printf("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", oldreg, env->lsu);
83469015
FB
598 dump_mmu(env);
599#endif
3475187d 600 tlb_flush(env, 1);
83469015 601 }
3475187d
FB
602 return;
603 }
604 case 0x50: // I-MMU regs
605 {
606 int reg = (T0 >> 3) & 0xf;
607 uint64_t oldreg;
3b46e624 608
3475187d
FB
609 oldreg = env->immuregs[reg];
610 switch(reg) {
611 case 0: // RO
612 case 4:
613 return;
614 case 1: // Not in I-MMU
615 case 2:
616 case 7:
617 case 8:
618 return;
619 case 3: // SFSR
620 if ((T1 & 1) == 0)
621 T1 = 0; // Clear SFSR
622 break;
623 case 5: // TSB access
624 case 6: // Tag access
625 default:
626 break;
627 }
628 env->immuregs[reg] = T1;
629#ifdef DEBUG_MMU
630 if (oldreg != env->immuregs[reg]) {
26a76461 631 printf("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
3475187d 632 }
ee5bbe38 633 dump_mmu(env);
3475187d
FB
634#endif
635 return;
636 }
637 case 0x54: // I-MMU data in
638 {
639 unsigned int i;
640
641 // Try finding an invalid entry
642 for (i = 0; i < 64; i++) {
643 if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0) {
644 env->itlb_tag[i] = env->immuregs[6];
645 env->itlb_tte[i] = T1;
646 return;
647 }
648 }
649 // Try finding an unlocked entry
650 for (i = 0; i < 64; i++) {
651 if ((env->itlb_tte[i] & 0x40) == 0) {
652 env->itlb_tag[i] = env->immuregs[6];
653 env->itlb_tte[i] = T1;
654 return;
655 }
656 }
657 // error state?
658 return;
659 }
660 case 0x55: // I-MMU data access
661 {
662 unsigned int i = (T0 >> 3) & 0x3f;
663
664 env->itlb_tag[i] = env->immuregs[6];
665 env->itlb_tte[i] = T1;
666 return;
667 }
668 case 0x57: // I-MMU demap
83469015 669 // XXX
3475187d
FB
670 return;
671 case 0x58: // D-MMU regs
672 {
673 int reg = (T0 >> 3) & 0xf;
674 uint64_t oldreg;
3b46e624 675
3475187d
FB
676 oldreg = env->dmmuregs[reg];
677 switch(reg) {
678 case 0: // RO
679 case 4:
680 return;
681 case 3: // SFSR
682 if ((T1 & 1) == 0) {
683 T1 = 0; // Clear SFSR, Fault address
684 env->dmmuregs[4] = 0;
685 }
686 env->dmmuregs[reg] = T1;
687 break;
688 case 1: // Primary context
689 case 2: // Secondary context
690 case 5: // TSB access
691 case 6: // Tag access
692 case 7: // Virtual Watchpoint
693 case 8: // Physical Watchpoint
694 default:
695 break;
696 }
697 env->dmmuregs[reg] = T1;
698#ifdef DEBUG_MMU
699 if (oldreg != env->dmmuregs[reg]) {
26a76461 700 printf("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
3475187d 701 }
ee5bbe38 702 dump_mmu(env);
3475187d
FB
703#endif
704 return;
705 }
706 case 0x5c: // D-MMU data in
707 {
708 unsigned int i;
709
710 // Try finding an invalid entry
711 for (i = 0; i < 64; i++) {
712 if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0) {
713 env->dtlb_tag[i] = env->dmmuregs[6];
714 env->dtlb_tte[i] = T1;
715 return;
716 }
717 }
718 // Try finding an unlocked entry
719 for (i = 0; i < 64; i++) {
720 if ((env->dtlb_tte[i] & 0x40) == 0) {
721 env->dtlb_tag[i] = env->dmmuregs[6];
722 env->dtlb_tte[i] = T1;
723 return;
724 }
725 }
726 // error state?
727 return;
728 }
729 case 0x5d: // D-MMU data access
730 {
731 unsigned int i = (T0 >> 3) & 0x3f;
732
733 env->dtlb_tag[i] = env->dmmuregs[6];
734 env->dtlb_tte[i] = T1;
735 return;
736 }
737 case 0x5f: // D-MMU demap
83469015
FB
738 case 0x49: // Interrupt data receive
739 // XXX
3475187d
FB
740 return;
741 case 0x51: // I-MMU 8k TSB pointer, RO
742 case 0x52: // I-MMU 64k TSB pointer, RO
743 case 0x56: // I-MMU tag read, RO
744 case 0x59: // D-MMU 8k TSB pointer, RO
745 case 0x5a: // D-MMU 64k TSB pointer, RO
746 case 0x5b: // D-MMU data pointer, RO
747 case 0x5e: // D-MMU tag read, RO
83469015
FB
748 case 0x48: // Interrupt dispatch, RO
749 case 0x7f: // Incoming interrupt vector, RO
750 case 0x82: // Primary no-fault, RO
751 case 0x83: // Secondary no-fault, RO
752 case 0x8a: // Primary no-fault LE, RO
753 case 0x8b: // Secondary no-fault LE, RO
3475187d 754 default:
6c36d3fa 755 do_unassigned_access(T0, 1, 0, 1);
3475187d
FB
756 return;
757 }
758}
3475187d 759#endif
24741ef3 760#endif /* !CONFIG_USER_ONLY */
3475187d
FB
761
762#ifndef TARGET_SPARC64
a0c4cb4a 763void helper_rett()
e8af50a3 764{
af7bf89b
FB
765 unsigned int cwp;
766
d4218d99
BS
767 if (env->psret == 1)
768 raise_exception(TT_ILL_INSN);
769
e8af50a3 770 env->psret = 1;
5fafdf24 771 cwp = (env->cwp + 1) & (NWINDOWS - 1);
e8af50a3
FB
772 if (env->wim & (1 << cwp)) {
773 raise_exception(TT_WIN_UNF);
774 }
775 set_cwp(cwp);
776 env->psrs = env->psrps;
777}
3475187d 778#endif
e8af50a3 779
8d5f07fa 780void helper_ldfsr(void)
e8af50a3 781{
7a0e1f41 782 int rnd_mode;
e8af50a3
FB
783 switch (env->fsr & FSR_RD_MASK) {
784 case FSR_RD_NEAREST:
7a0e1f41 785 rnd_mode = float_round_nearest_even;
e8af50a3 786 break;
ed910241 787 default:
e8af50a3 788 case FSR_RD_ZERO:
7a0e1f41 789 rnd_mode = float_round_to_zero;
e8af50a3
FB
790 break;
791 case FSR_RD_POS:
7a0e1f41 792 rnd_mode = float_round_up;
e8af50a3
FB
793 break;
794 case FSR_RD_NEG:
7a0e1f41 795 rnd_mode = float_round_down;
e8af50a3
FB
796 break;
797 }
7a0e1f41 798 set_float_rounding_mode(rnd_mode, &env->fp_status);
e8af50a3 799}
e80cfcfc 800
e80cfcfc
FB
801void helper_debug()
802{
803 env->exception_index = EXCP_DEBUG;
804 cpu_loop_exit();
805}
af7bf89b 806
3475187d 807#ifndef TARGET_SPARC64
af7bf89b
FB
808void do_wrpsr()
809{
d4218d99
BS
810 if ((T0 & PSR_CWP) >= NWINDOWS)
811 raise_exception(TT_ILL_INSN);
812 else
813 PUT_PSR(env, T0);
af7bf89b
FB
814}
815
816void do_rdpsr()
817{
818 T0 = GET_PSR(env);
819}
3475187d
FB
820
821#else
822
823void do_popc()
824{
825 T0 = (T1 & 0x5555555555555555ULL) + ((T1 >> 1) & 0x5555555555555555ULL);
826 T0 = (T0 & 0x3333333333333333ULL) + ((T0 >> 2) & 0x3333333333333333ULL);
827 T0 = (T0 & 0x0f0f0f0f0f0f0f0fULL) + ((T0 >> 4) & 0x0f0f0f0f0f0f0f0fULL);
828 T0 = (T0 & 0x00ff00ff00ff00ffULL) + ((T0 >> 8) & 0x00ff00ff00ff00ffULL);
829 T0 = (T0 & 0x0000ffff0000ffffULL) + ((T0 >> 16) & 0x0000ffff0000ffffULL);
830 T0 = (T0 & 0x00000000ffffffffULL) + ((T0 >> 32) & 0x00000000ffffffffULL);
831}
83469015
FB
832
833static inline uint64_t *get_gregset(uint64_t pstate)
834{
835 switch (pstate) {
836 default:
837 case 0:
838 return env->bgregs;
839 case PS_AG:
840 return env->agregs;
841 case PS_MG:
842 return env->mgregs;
843 case PS_IG:
844 return env->igregs;
845 }
846}
847
8f1f22f6 848static inline void change_pstate(uint64_t new_pstate)
83469015 849{
8f1f22f6 850 uint64_t pstate_regs, new_pstate_regs;
83469015
FB
851 uint64_t *src, *dst;
852
83469015
FB
853 pstate_regs = env->pstate & 0xc01;
854 new_pstate_regs = new_pstate & 0xc01;
855 if (new_pstate_regs != pstate_regs) {
856 // Switch global register bank
857 src = get_gregset(new_pstate_regs);
858 dst = get_gregset(pstate_regs);
859 memcpy32(dst, env->gregs);
860 memcpy32(env->gregs, src);
861 }
862 env->pstate = new_pstate;
863}
864
8f1f22f6
BS
865void do_wrpstate(void)
866{
867 change_pstate(T0 & 0xf3f);
868}
869
83469015
FB
870void do_done(void)
871{
872 env->tl--;
873 env->pc = env->tnpc[env->tl];
874 env->npc = env->tnpc[env->tl] + 4;
875 PUT_CCR(env, env->tstate[env->tl] >> 32);
876 env->asi = (env->tstate[env->tl] >> 24) & 0xff;
8f1f22f6 877 change_pstate((env->tstate[env->tl] >> 8) & 0xf3f);
17d996e1 878 PUT_CWP64(env, env->tstate[env->tl] & 0xff);
83469015
FB
879}
880
881void do_retry(void)
882{
883 env->tl--;
884 env->pc = env->tpc[env->tl];
885 env->npc = env->tnpc[env->tl];
886 PUT_CCR(env, env->tstate[env->tl] >> 32);
887 env->asi = (env->tstate[env->tl] >> 24) & 0xff;
8f1f22f6 888 change_pstate((env->tstate[env->tl] >> 8) & 0xf3f);
17d996e1 889 PUT_CWP64(env, env->tstate[env->tl] & 0xff);
83469015 890}
3475187d 891#endif
ee5bbe38
FB
892
893void set_cwp(int new_cwp)
894{
895 /* put the modified wrap registers at their proper location */
896 if (env->cwp == (NWINDOWS - 1))
897 memcpy32(env->regbase, env->regbase + NWINDOWS * 16);
898 env->cwp = new_cwp;
899 /* put the wrap registers at their temporary location */
900 if (new_cwp == (NWINDOWS - 1))
901 memcpy32(env->regbase + NWINDOWS * 16, env->regbase);
902 env->regwptr = env->regbase + (new_cwp * 16);
903 REGWPTR = env->regwptr;
904}
905
906void cpu_set_cwp(CPUState *env1, int new_cwp)
907{
908 CPUState *saved_env;
909#ifdef reg_REGWPTR
910 target_ulong *saved_regwptr;
911#endif
912
913 saved_env = env;
914#ifdef reg_REGWPTR
915 saved_regwptr = REGWPTR;
916#endif
917 env = env1;
918 set_cwp(new_cwp);
919 env = saved_env;
920#ifdef reg_REGWPTR
921 REGWPTR = saved_regwptr;
922#endif
923}
924
925#ifdef TARGET_SPARC64
926void do_interrupt(int intno)
927{
928#ifdef DEBUG_PCALL
929 if (loglevel & CPU_LOG_INT) {
930 static int count;
26a76461 931 fprintf(logfile, "%6d: v=%04x pc=%016" PRIx64 " npc=%016" PRIx64 " SP=%016" PRIx64 "\n",
ee5bbe38
FB
932 count, intno,
933 env->pc,
934 env->npc, env->regwptr[6]);
935 cpu_dump_state(env, logfile, fprintf, 0);
936#if 0
937 {
938 int i;
939 uint8_t *ptr;
940
941 fprintf(logfile, " code=");
942 ptr = (uint8_t *)env->pc;
943 for(i = 0; i < 16; i++) {
944 fprintf(logfile, " %02x", ldub(ptr + i));
945 }
946 fprintf(logfile, "\n");
947 }
948#endif
949 count++;
950 }
951#endif
5fafdf24 952#if !defined(CONFIG_USER_ONLY)
83469015 953 if (env->tl == MAXTL) {
c68ea704 954 cpu_abort(env, "Trap 0x%04x while trap level is MAXTL, Error state", env->exception_index);
ee5bbe38
FB
955 return;
956 }
957#endif
958 env->tstate[env->tl] = ((uint64_t)GET_CCR(env) << 32) | ((env->asi & 0xff) << 24) |
8f1f22f6 959 ((env->pstate & 0xf3f) << 8) | GET_CWP64(env);
ee5bbe38
FB
960 env->tpc[env->tl] = env->pc;
961 env->tnpc[env->tl] = env->npc;
962 env->tt[env->tl] = intno;
8f1f22f6
BS
963 change_pstate(PS_PEF | PS_PRIV | PS_AG);
964
965 if (intno == TT_CLRWIN)
966 set_cwp((env->cwp - 1) & (NWINDOWS - 1));
967 else if ((intno & 0x1c0) == TT_SPILL)
968 set_cwp((env->cwp - env->cansave - 2) & (NWINDOWS - 1));
969 else if ((intno & 0x1c0) == TT_FILL)
970 set_cwp((env->cwp + 1) & (NWINDOWS - 1));
83469015
FB
971 env->tbr &= ~0x7fffULL;
972 env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
973 if (env->tl < MAXTL - 1) {
974 env->tl++;
975 } else {
976 env->pstate |= PS_RED;
977 if (env->tl != MAXTL)
978 env->tl++;
979 }
ee5bbe38
FB
980 env->pc = env->tbr;
981 env->npc = env->pc + 4;
982 env->exception_index = 0;
983}
984#else
985void do_interrupt(int intno)
986{
987 int cwp;
988
989#ifdef DEBUG_PCALL
990 if (loglevel & CPU_LOG_INT) {
991 static int count;
992 fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n",
993 count, intno,
994 env->pc,
995 env->npc, env->regwptr[6]);
996 cpu_dump_state(env, logfile, fprintf, 0);
997#if 0
998 {
999 int i;
1000 uint8_t *ptr;
1001
1002 fprintf(logfile, " code=");
1003 ptr = (uint8_t *)env->pc;
1004 for(i = 0; i < 16; i++) {
1005 fprintf(logfile, " %02x", ldub(ptr + i));
1006 }
1007 fprintf(logfile, "\n");
1008 }
1009#endif
1010 count++;
1011 }
1012#endif
5fafdf24 1013#if !defined(CONFIG_USER_ONLY)
ee5bbe38 1014 if (env->psret == 0) {
c68ea704 1015 cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index);
ee5bbe38
FB
1016 return;
1017 }
1018#endif
1019 env->psret = 0;
5fafdf24 1020 cwp = (env->cwp - 1) & (NWINDOWS - 1);
ee5bbe38
FB
1021 set_cwp(cwp);
1022 env->regwptr[9] = env->pc;
1023 env->regwptr[10] = env->npc;
1024 env->psrps = env->psrs;
1025 env->psrs = 1;
1026 env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
1027 env->pc = env->tbr;
1028 env->npc = env->pc + 4;
1029 env->exception_index = 0;
1030}
1031#endif
1032
5fafdf24 1033#if !defined(CONFIG_USER_ONLY)
ee5bbe38 1034
d2889a3e
BS
1035static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
1036 void *retaddr);
1037
ee5bbe38 1038#define MMUSUFFIX _mmu
d2889a3e 1039#define ALIGNED_ONLY
ee5bbe38
FB
1040#define GETPC() (__builtin_return_address(0))
1041
1042#define SHIFT 0
1043#include "softmmu_template.h"
1044
1045#define SHIFT 1
1046#include "softmmu_template.h"
1047
1048#define SHIFT 2
1049#include "softmmu_template.h"
1050
1051#define SHIFT 3
1052#include "softmmu_template.h"
1053
d2889a3e
BS
1054static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
1055 void *retaddr)
1056{
94554550
BS
1057#ifdef DEBUG_UNALIGNED
1058 printf("Unaligned access to 0x%x from 0x%x\n", addr, env->pc);
1059#endif
1060 raise_exception(TT_UNALIGNED);
d2889a3e 1061}
ee5bbe38
FB
1062
1063/* try to fill the TLB and return an exception if error. If retaddr is
1064 NULL, it means that the function was called in C code (i.e. not
1065 from generated code or from helper.c) */
1066/* XXX: fix it to restore all registers */
1067void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
1068{
1069 TranslationBlock *tb;
1070 int ret;
1071 unsigned long pc;
1072 CPUState *saved_env;
1073
1074 /* XXX: hack to restore env in all cases, even if not called from
1075 generated code */
1076 saved_env = env;
1077 env = cpu_single_env;
1078
1079 ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, is_user, 1);
1080 if (ret) {
1081 if (retaddr) {
1082 /* now we have a real cpu fault */
1083 pc = (unsigned long)retaddr;
1084 tb = tb_find_pc(pc);
1085 if (tb) {
1086 /* the PC is inside the translated code. It means that we have
1087 a virtual CPU fault */
1088 cpu_restore_state(tb, env, pc, (void *)T2);
1089 }
1090 }
1091 cpu_loop_exit();
1092 }
1093 env = saved_env;
1094}
1095
1096#endif
6c36d3fa
BS
1097
1098#ifndef TARGET_SPARC64
5dcb6b91 1099void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
6c36d3fa
BS
1100 int is_asi)
1101{
1102 CPUState *saved_env;
1103
1104 /* XXX: hack to restore env in all cases, even if not called from
1105 generated code */
1106 saved_env = env;
1107 env = cpu_single_env;
1108 if (env->mmuregs[3]) /* Fault status register */
1109 env->mmuregs[3] = 1; /* overflow (not read before another fault) */
1110 if (is_asi)
1111 env->mmuregs[3] |= 1 << 16;
1112 if (env->psrs)
1113 env->mmuregs[3] |= 1 << 5;
1114 if (is_exec)
1115 env->mmuregs[3] |= 1 << 6;
1116 if (is_write)
1117 env->mmuregs[3] |= 1 << 7;
1118 env->mmuregs[3] |= (5 << 2) | 2;
1119 env->mmuregs[4] = addr; /* Fault address register */
1120 if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
1121#ifdef DEBUG_UNASSIGNED
5dcb6b91 1122 printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx
6c36d3fa
BS
1123 "\n", addr, env->pc);
1124#endif
1b2e93c1
BS
1125 if (is_exec)
1126 raise_exception(TT_CODE_ACCESS);
1127 else
1128 raise_exception(TT_DATA_ACCESS);
6c36d3fa
BS
1129 }
1130 env = saved_env;
1131}
1132#else
5dcb6b91 1133void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec,
6c36d3fa
BS
1134 int is_asi)
1135{
1136#ifdef DEBUG_UNASSIGNED
1137 CPUState *saved_env;
1138
1139 /* XXX: hack to restore env in all cases, even if not called from
1140 generated code */
1141 saved_env = env;
1142 env = cpu_single_env;
5dcb6b91 1143 printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx "\n",
6c36d3fa
BS
1144 addr, env->pc);
1145 env = saved_env;
1146#endif
1b2e93c1
BS
1147 if (is_exec)
1148 raise_exception(TT_CODE_ACCESS);
1149 else
1150 raise_exception(TT_DATA_ACCESS);
6c36d3fa
BS
1151}
1152#endif
20c9f095
BS
1153
1154#ifdef TARGET_SPARC64
1155void do_tick_set_count(void *opaque, uint64_t count)
1156{
d8bdf5fa 1157#if !defined(CONFIG_USER_ONLY)
20c9f095 1158 ptimer_set_count(opaque, -count);
d8bdf5fa 1159#endif
20c9f095
BS
1160}
1161
1162uint64_t do_tick_get_count(void *opaque)
1163{
d8bdf5fa 1164#if !defined(CONFIG_USER_ONLY)
20c9f095 1165 return -ptimer_get_count(opaque);
d8bdf5fa
BS
1166#else
1167 return 0;
1168#endif
20c9f095
BS
1169}
1170
1171void do_tick_set_limit(void *opaque, uint64_t limit)
1172{
d8bdf5fa 1173#if !defined(CONFIG_USER_ONLY)
20c9f095 1174 ptimer_set_limit(opaque, -limit, 0);
d8bdf5fa 1175#endif
20c9f095
BS
1176}
1177#endif