|
1 #include "exec.h" |
|
2 #include "host-utils.h" |
|
3 #include "helper.h" |
|
4 #if !defined(CONFIG_USER_ONLY) |
|
5 #include "softmmu_exec.h" |
|
6 #endif /* !defined(CONFIG_USER_ONLY) */ |
|
7 |
|
8 //#define DEBUG_MMU |
|
9 //#define DEBUG_MXCC |
|
10 //#define DEBUG_UNALIGNED |
|
11 //#define DEBUG_UNASSIGNED |
|
12 //#define DEBUG_ASI |
|
13 //#define DEBUG_PCALL |
|
14 |
|
15 #ifdef DEBUG_MMU |
|
16 #define DPRINTF_MMU(fmt, args...) \ |
|
17 do { printf("MMU: " fmt , ##args); } while (0) |
|
18 #else |
|
19 #define DPRINTF_MMU(fmt, args...) do {} while (0) |
|
20 #endif |
|
21 |
|
22 #ifdef DEBUG_MXCC |
|
23 #define DPRINTF_MXCC(fmt, args...) \ |
|
24 do { printf("MXCC: " fmt , ##args); } while (0) |
|
25 #else |
|
26 #define DPRINTF_MXCC(fmt, args...) do {} while (0) |
|
27 #endif |
|
28 |
|
29 #ifdef DEBUG_ASI |
|
30 #define DPRINTF_ASI(fmt, args...) \ |
|
31 do { printf("ASI: " fmt , ##args); } while (0) |
|
32 #else |
|
33 #define DPRINTF_ASI(fmt, args...) do {} while (0) |
|
34 #endif |
|
35 |
|
36 #ifdef TARGET_SPARC64 |
|
37 #ifndef TARGET_ABI32 |
|
38 #define AM_CHECK(env1) ((env1)->pstate & PS_AM) |
|
39 #else |
|
40 #define AM_CHECK(env1) (1) |
|
41 #endif |
|
42 #endif |
|
43 |
|
44 static inline void address_mask(CPUState *env1, target_ulong *addr) |
|
45 { |
|
46 #ifdef TARGET_SPARC64 |
|
47 if (AM_CHECK(env1)) |
|
48 *addr &= 0xffffffffULL; |
|
49 #endif |
|
50 } |
|
51 |
|
52 static void raise_exception(int tt) |
|
53 { |
|
54 env->exception_index = tt; |
|
55 cpu_loop_exit(); |
|
56 } |
|
57 |
|
58 void HELPER(raise_exception)(int tt) |
|
59 { |
|
60 raise_exception(tt); |
|
61 } |
|
62 |
|
63 static inline void set_cwp(int new_cwp) |
|
64 { |
|
65 cpu_set_cwp(env, new_cwp); |
|
66 } |
|
67 |
|
68 void helper_check_align(target_ulong addr, uint32_t align) |
|
69 { |
|
70 if (addr & align) { |
|
71 #ifdef DEBUG_UNALIGNED |
|
72 printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx |
|
73 "\n", addr, env->pc); |
|
74 #endif |
|
75 raise_exception(TT_UNALIGNED); |
|
76 } |
|
77 } |
|
78 |
|
79 #define F_HELPER(name, p) void helper_f##name##p(void) |
|
80 |
|
81 #define F_BINOP(name) \ |
|
82 float32 helper_f ## name ## s (float32 src1, float32 src2) \ |
|
83 { \ |
|
84 return float32_ ## name (src1, src2, &env->fp_status); \ |
|
85 } \ |
|
86 F_HELPER(name, d) \ |
|
87 { \ |
|
88 DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \ |
|
89 } \ |
|
90 F_HELPER(name, q) \ |
|
91 { \ |
|
92 QT0 = float128_ ## name (QT0, QT1, &env->fp_status); \ |
|
93 } |
|
94 |
|
95 F_BINOP(add); |
|
96 F_BINOP(sub); |
|
97 F_BINOP(mul); |
|
98 F_BINOP(div); |
|
99 #undef F_BINOP |
|
100 |
|
101 void helper_fsmuld(float32 src1, float32 src2) |
|
102 { |
|
103 DT0 = float64_mul(float32_to_float64(src1, &env->fp_status), |
|
104 float32_to_float64(src2, &env->fp_status), |
|
105 &env->fp_status); |
|
106 } |
|
107 |
|
108 void helper_fdmulq(void) |
|
109 { |
|
110 QT0 = float128_mul(float64_to_float128(DT0, &env->fp_status), |
|
111 float64_to_float128(DT1, &env->fp_status), |
|
112 &env->fp_status); |
|
113 } |
|
114 |
|
115 float32 helper_fnegs(float32 src) |
|
116 { |
|
117 return float32_chs(src); |
|
118 } |
|
119 |
|
120 #ifdef TARGET_SPARC64 |
|
121 F_HELPER(neg, d) |
|
122 { |
|
123 DT0 = float64_chs(DT1); |
|
124 } |
|
125 |
|
126 F_HELPER(neg, q) |
|
127 { |
|
128 QT0 = float128_chs(QT1); |
|
129 } |
|
130 #endif |
|
131 |
|
132 /* Integer to float conversion. */ |
|
133 float32 helper_fitos(int32_t src) |
|
134 { |
|
135 return int32_to_float32(src, &env->fp_status); |
|
136 } |
|
137 |
|
138 void helper_fitod(int32_t src) |
|
139 { |
|
140 DT0 = int32_to_float64(src, &env->fp_status); |
|
141 } |
|
142 |
|
143 void helper_fitoq(int32_t src) |
|
144 { |
|
145 QT0 = int32_to_float128(src, &env->fp_status); |
|
146 } |
|
147 |
|
148 #ifdef TARGET_SPARC64 |
|
149 float32 helper_fxtos(void) |
|
150 { |
|
151 return int64_to_float32(*((int64_t *)&DT1), &env->fp_status); |
|
152 } |
|
153 |
|
154 F_HELPER(xto, d) |
|
155 { |
|
156 DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status); |
|
157 } |
|
158 |
|
159 F_HELPER(xto, q) |
|
160 { |
|
161 QT0 = int64_to_float128(*((int64_t *)&DT1), &env->fp_status); |
|
162 } |
|
163 #endif |
|
164 #undef F_HELPER |
|
165 |
|
166 /* floating point conversion */ |
|
167 float32 helper_fdtos(void) |
|
168 { |
|
169 return float64_to_float32(DT1, &env->fp_status); |
|
170 } |
|
171 |
|
172 void helper_fstod(float32 src) |
|
173 { |
|
174 DT0 = float32_to_float64(src, &env->fp_status); |
|
175 } |
|
176 |
|
177 float32 helper_fqtos(void) |
|
178 { |
|
179 return float128_to_float32(QT1, &env->fp_status); |
|
180 } |
|
181 |
|
182 void helper_fstoq(float32 src) |
|
183 { |
|
184 QT0 = float32_to_float128(src, &env->fp_status); |
|
185 } |
|
186 |
|
187 void helper_fqtod(void) |
|
188 { |
|
189 DT0 = float128_to_float64(QT1, &env->fp_status); |
|
190 } |
|
191 |
|
192 void helper_fdtoq(void) |
|
193 { |
|
194 QT0 = float64_to_float128(DT1, &env->fp_status); |
|
195 } |
|
196 |
|
197 /* Float to integer conversion. */ |
|
198 int32_t helper_fstoi(float32 src) |
|
199 { |
|
200 return float32_to_int32_round_to_zero(src, &env->fp_status); |
|
201 } |
|
202 |
|
203 int32_t helper_fdtoi(void) |
|
204 { |
|
205 return float64_to_int32_round_to_zero(DT1, &env->fp_status); |
|
206 } |
|
207 |
|
208 int32_t helper_fqtoi(void) |
|
209 { |
|
210 return float128_to_int32_round_to_zero(QT1, &env->fp_status); |
|
211 } |
|
212 |
|
213 #ifdef TARGET_SPARC64 |
|
214 void helper_fstox(float32 src) |
|
215 { |
|
216 *((int64_t *)&DT0) = float32_to_int64_round_to_zero(src, &env->fp_status); |
|
217 } |
|
218 |
|
219 void helper_fdtox(void) |
|
220 { |
|
221 *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status); |
|
222 } |
|
223 |
|
224 void helper_fqtox(void) |
|
225 { |
|
226 *((int64_t *)&DT0) = float128_to_int64_round_to_zero(QT1, &env->fp_status); |
|
227 } |
|
228 |
|
229 void helper_faligndata(void) |
|
230 { |
|
231 uint64_t tmp; |
|
232 |
|
233 tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8); |
|
234 /* on many architectures a shift of 64 does nothing */ |
|
235 if ((env->gsr & 7) != 0) { |
|
236 tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8); |
|
237 } |
|
238 *((uint64_t *)&DT0) = tmp; |
|
239 } |
|
240 |
|
241 #ifdef WORDS_BIGENDIAN |
|
242 #define VIS_B64(n) b[7 - (n)] |
|
243 #define VIS_W64(n) w[3 - (n)] |
|
244 #define VIS_SW64(n) sw[3 - (n)] |
|
245 #define VIS_L64(n) l[1 - (n)] |
|
246 #define VIS_B32(n) b[3 - (n)] |
|
247 #define VIS_W32(n) w[1 - (n)] |
|
248 #else |
|
249 #define VIS_B64(n) b[n] |
|
250 #define VIS_W64(n) w[n] |
|
251 #define VIS_SW64(n) sw[n] |
|
252 #define VIS_L64(n) l[n] |
|
253 #define VIS_B32(n) b[n] |
|
254 #define VIS_W32(n) w[n] |
|
255 #endif |
|
256 |
|
257 typedef union { |
|
258 uint8_t b[8]; |
|
259 uint16_t w[4]; |
|
260 int16_t sw[4]; |
|
261 uint32_t l[2]; |
|
262 float64 d; |
|
263 } vis64; |
|
264 |
|
265 typedef union { |
|
266 uint8_t b[4]; |
|
267 uint16_t w[2]; |
|
268 uint32_t l; |
|
269 float32 f; |
|
270 } vis32; |
|
271 |
|
272 void helper_fpmerge(void) |
|
273 { |
|
274 vis64 s, d; |
|
275 |
|
276 s.d = DT0; |
|
277 d.d = DT1; |
|
278 |
|
279 // Reverse calculation order to handle overlap |
|
280 d.VIS_B64(7) = s.VIS_B64(3); |
|
281 d.VIS_B64(6) = d.VIS_B64(3); |
|
282 d.VIS_B64(5) = s.VIS_B64(2); |
|
283 d.VIS_B64(4) = d.VIS_B64(2); |
|
284 d.VIS_B64(3) = s.VIS_B64(1); |
|
285 d.VIS_B64(2) = d.VIS_B64(1); |
|
286 d.VIS_B64(1) = s.VIS_B64(0); |
|
287 //d.VIS_B64(0) = d.VIS_B64(0); |
|
288 |
|
289 DT0 = d.d; |
|
290 } |
|
291 |
|
292 void helper_fmul8x16(void) |
|
293 { |
|
294 vis64 s, d; |
|
295 uint32_t tmp; |
|
296 |
|
297 s.d = DT0; |
|
298 d.d = DT1; |
|
299 |
|
300 #define PMUL(r) \ |
|
301 tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r); \ |
|
302 if ((tmp & 0xff) > 0x7f) \ |
|
303 tmp += 0x100; \ |
|
304 d.VIS_W64(r) = tmp >> 8; |
|
305 |
|
306 PMUL(0); |
|
307 PMUL(1); |
|
308 PMUL(2); |
|
309 PMUL(3); |
|
310 #undef PMUL |
|
311 |
|
312 DT0 = d.d; |
|
313 } |
|
314 |
|
315 void helper_fmul8x16al(void) |
|
316 { |
|
317 vis64 s, d; |
|
318 uint32_t tmp; |
|
319 |
|
320 s.d = DT0; |
|
321 d.d = DT1; |
|
322 |
|
323 #define PMUL(r) \ |
|
324 tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r); \ |
|
325 if ((tmp & 0xff) > 0x7f) \ |
|
326 tmp += 0x100; \ |
|
327 d.VIS_W64(r) = tmp >> 8; |
|
328 |
|
329 PMUL(0); |
|
330 PMUL(1); |
|
331 PMUL(2); |
|
332 PMUL(3); |
|
333 #undef PMUL |
|
334 |
|
335 DT0 = d.d; |
|
336 } |
|
337 |
|
338 void helper_fmul8x16au(void) |
|
339 { |
|
340 vis64 s, d; |
|
341 uint32_t tmp; |
|
342 |
|
343 s.d = DT0; |
|
344 d.d = DT1; |
|
345 |
|
346 #define PMUL(r) \ |
|
347 tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r); \ |
|
348 if ((tmp & 0xff) > 0x7f) \ |
|
349 tmp += 0x100; \ |
|
350 d.VIS_W64(r) = tmp >> 8; |
|
351 |
|
352 PMUL(0); |
|
353 PMUL(1); |
|
354 PMUL(2); |
|
355 PMUL(3); |
|
356 #undef PMUL |
|
357 |
|
358 DT0 = d.d; |
|
359 } |
|
360 |
|
361 void helper_fmul8sux16(void) |
|
362 { |
|
363 vis64 s, d; |
|
364 uint32_t tmp; |
|
365 |
|
366 s.d = DT0; |
|
367 d.d = DT1; |
|
368 |
|
369 #define PMUL(r) \ |
|
370 tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \ |
|
371 if ((tmp & 0xff) > 0x7f) \ |
|
372 tmp += 0x100; \ |
|
373 d.VIS_W64(r) = tmp >> 8; |
|
374 |
|
375 PMUL(0); |
|
376 PMUL(1); |
|
377 PMUL(2); |
|
378 PMUL(3); |
|
379 #undef PMUL |
|
380 |
|
381 DT0 = d.d; |
|
382 } |
|
383 |
|
384 void helper_fmul8ulx16(void) |
|
385 { |
|
386 vis64 s, d; |
|
387 uint32_t tmp; |
|
388 |
|
389 s.d = DT0; |
|
390 d.d = DT1; |
|
391 |
|
392 #define PMUL(r) \ |
|
393 tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \ |
|
394 if ((tmp & 0xff) > 0x7f) \ |
|
395 tmp += 0x100; \ |
|
396 d.VIS_W64(r) = tmp >> 8; |
|
397 |
|
398 PMUL(0); |
|
399 PMUL(1); |
|
400 PMUL(2); |
|
401 PMUL(3); |
|
402 #undef PMUL |
|
403 |
|
404 DT0 = d.d; |
|
405 } |
|
406 |
|
407 void helper_fmuld8sux16(void) |
|
408 { |
|
409 vis64 s, d; |
|
410 uint32_t tmp; |
|
411 |
|
412 s.d = DT0; |
|
413 d.d = DT1; |
|
414 |
|
415 #define PMUL(r) \ |
|
416 tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \ |
|
417 if ((tmp & 0xff) > 0x7f) \ |
|
418 tmp += 0x100; \ |
|
419 d.VIS_L64(r) = tmp; |
|
420 |
|
421 // Reverse calculation order to handle overlap |
|
422 PMUL(1); |
|
423 PMUL(0); |
|
424 #undef PMUL |
|
425 |
|
426 DT0 = d.d; |
|
427 } |
|
428 |
|
429 void helper_fmuld8ulx16(void) |
|
430 { |
|
431 vis64 s, d; |
|
432 uint32_t tmp; |
|
433 |
|
434 s.d = DT0; |
|
435 d.d = DT1; |
|
436 |
|
437 #define PMUL(r) \ |
|
438 tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \ |
|
439 if ((tmp & 0xff) > 0x7f) \ |
|
440 tmp += 0x100; \ |
|
441 d.VIS_L64(r) = tmp; |
|
442 |
|
443 // Reverse calculation order to handle overlap |
|
444 PMUL(1); |
|
445 PMUL(0); |
|
446 #undef PMUL |
|
447 |
|
448 DT0 = d.d; |
|
449 } |
|
450 |
|
451 void helper_fexpand(void) |
|
452 { |
|
453 vis32 s; |
|
454 vis64 d; |
|
455 |
|
456 s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff); |
|
457 d.d = DT1; |
|
458 d.VIS_W64(0) = s.VIS_B32(0) << 4; |
|
459 d.VIS_W64(1) = s.VIS_B32(1) << 4; |
|
460 d.VIS_W64(2) = s.VIS_B32(2) << 4; |
|
461 d.VIS_W64(3) = s.VIS_B32(3) << 4; |
|
462 |
|
463 DT0 = d.d; |
|
464 } |
|
465 |
|
466 #define VIS_HELPER(name, F) \ |
|
467 void name##16(void) \ |
|
468 { \ |
|
469 vis64 s, d; \ |
|
470 \ |
|
471 s.d = DT0; \ |
|
472 d.d = DT1; \ |
|
473 \ |
|
474 d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0)); \ |
|
475 d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1)); \ |
|
476 d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2)); \ |
|
477 d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3)); \ |
|
478 \ |
|
479 DT0 = d.d; \ |
|
480 } \ |
|
481 \ |
|
482 uint32_t name##16s(uint32_t src1, uint32_t src2) \ |
|
483 { \ |
|
484 vis32 s, d; \ |
|
485 \ |
|
486 s.l = src1; \ |
|
487 d.l = src2; \ |
|
488 \ |
|
489 d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0)); \ |
|
490 d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1)); \ |
|
491 \ |
|
492 return d.l; \ |
|
493 } \ |
|
494 \ |
|
495 void name##32(void) \ |
|
496 { \ |
|
497 vis64 s, d; \ |
|
498 \ |
|
499 s.d = DT0; \ |
|
500 d.d = DT1; \ |
|
501 \ |
|
502 d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0)); \ |
|
503 d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1)); \ |
|
504 \ |
|
505 DT0 = d.d; \ |
|
506 } \ |
|
507 \ |
|
508 uint32_t name##32s(uint32_t src1, uint32_t src2) \ |
|
509 { \ |
|
510 vis32 s, d; \ |
|
511 \ |
|
512 s.l = src1; \ |
|
513 d.l = src2; \ |
|
514 \ |
|
515 d.l = F(d.l, s.l); \ |
|
516 \ |
|
517 return d.l; \ |
|
518 } |
|
519 |
|
520 #define FADD(a, b) ((a) + (b)) |
|
521 #define FSUB(a, b) ((a) - (b)) |
|
522 VIS_HELPER(helper_fpadd, FADD) |
|
523 VIS_HELPER(helper_fpsub, FSUB) |
|
524 |
|
525 #define VIS_CMPHELPER(name, F) \ |
|
526 void name##16(void) \ |
|
527 { \ |
|
528 vis64 s, d; \ |
|
529 \ |
|
530 s.d = DT0; \ |
|
531 d.d = DT1; \ |
|
532 \ |
|
533 d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0))? 1: 0; \ |
|
534 d.VIS_W64(0) |= F(d.VIS_W64(1), s.VIS_W64(1))? 2: 0; \ |
|
535 d.VIS_W64(0) |= F(d.VIS_W64(2), s.VIS_W64(2))? 4: 0; \ |
|
536 d.VIS_W64(0) |= F(d.VIS_W64(3), s.VIS_W64(3))? 8: 0; \ |
|
537 \ |
|
538 DT0 = d.d; \ |
|
539 } \ |
|
540 \ |
|
541 void name##32(void) \ |
|
542 { \ |
|
543 vis64 s, d; \ |
|
544 \ |
|
545 s.d = DT0; \ |
|
546 d.d = DT1; \ |
|
547 \ |
|
548 d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0))? 1: 0; \ |
|
549 d.VIS_L64(0) |= F(d.VIS_L64(1), s.VIS_L64(1))? 2: 0; \ |
|
550 \ |
|
551 DT0 = d.d; \ |
|
552 } |
|
553 |
|
554 #define FCMPGT(a, b) ((a) > (b)) |
|
555 #define FCMPEQ(a, b) ((a) == (b)) |
|
556 #define FCMPLE(a, b) ((a) <= (b)) |
|
557 #define FCMPNE(a, b) ((a) != (b)) |
|
558 |
|
559 VIS_CMPHELPER(helper_fcmpgt, FCMPGT) |
|
560 VIS_CMPHELPER(helper_fcmpeq, FCMPEQ) |
|
561 VIS_CMPHELPER(helper_fcmple, FCMPLE) |
|
562 VIS_CMPHELPER(helper_fcmpne, FCMPNE) |
|
563 #endif |
|
564 |
|
565 void helper_check_ieee_exceptions(void) |
|
566 { |
|
567 target_ulong status; |
|
568 |
|
569 status = get_float_exception_flags(&env->fp_status); |
|
570 if (status) { |
|
571 /* Copy IEEE 754 flags into FSR */ |
|
572 if (status & float_flag_invalid) |
|
573 env->fsr |= FSR_NVC; |
|
574 if (status & float_flag_overflow) |
|
575 env->fsr |= FSR_OFC; |
|
576 if (status & float_flag_underflow) |
|
577 env->fsr |= FSR_UFC; |
|
578 if (status & float_flag_divbyzero) |
|
579 env->fsr |= FSR_DZC; |
|
580 if (status & float_flag_inexact) |
|
581 env->fsr |= FSR_NXC; |
|
582 |
|
583 if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23)) { |
|
584 /* Unmasked exception, generate a trap */ |
|
585 env->fsr |= FSR_FTT_IEEE_EXCP; |
|
586 raise_exception(TT_FP_EXCP); |
|
587 } else { |
|
588 /* Accumulate exceptions */ |
|
589 env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5; |
|
590 } |
|
591 } |
|
592 } |
|
593 |
|
594 void helper_clear_float_exceptions(void) |
|
595 { |
|
596 set_float_exception_flags(0, &env->fp_status); |
|
597 } |
|
598 |
|
599 float32 helper_fabss(float32 src) |
|
600 { |
|
601 return float32_abs(src); |
|
602 } |
|
603 |
|
604 #ifdef TARGET_SPARC64 |
|
605 void helper_fabsd(void) |
|
606 { |
|
607 DT0 = float64_abs(DT1); |
|
608 } |
|
609 |
|
610 void helper_fabsq(void) |
|
611 { |
|
612 QT0 = float128_abs(QT1); |
|
613 } |
|
614 #endif |
|
615 |
|
616 float32 helper_fsqrts(float32 src) |
|
617 { |
|
618 return float32_sqrt(src, &env->fp_status); |
|
619 } |
|
620 |
|
621 void helper_fsqrtd(void) |
|
622 { |
|
623 DT0 = float64_sqrt(DT1, &env->fp_status); |
|
624 } |
|
625 |
|
626 void helper_fsqrtq(void) |
|
627 { |
|
628 QT0 = float128_sqrt(QT1, &env->fp_status); |
|
629 } |
|
630 |
|
631 #define GEN_FCMP(name, size, reg1, reg2, FS, TRAP) \ |
|
632 void glue(helper_, name) (void) \ |
|
633 { \ |
|
634 target_ulong new_fsr; \ |
|
635 \ |
|
636 env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ |
|
637 switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \ |
|
638 case float_relation_unordered: \ |
|
639 new_fsr = (FSR_FCC1 | FSR_FCC0) << FS; \ |
|
640 if ((env->fsr & FSR_NVM) || TRAP) { \ |
|
641 env->fsr |= new_fsr; \ |
|
642 env->fsr |= FSR_NVC; \ |
|
643 env->fsr |= FSR_FTT_IEEE_EXCP; \ |
|
644 raise_exception(TT_FP_EXCP); \ |
|
645 } else { \ |
|
646 env->fsr |= FSR_NVA; \ |
|
647 } \ |
|
648 break; \ |
|
649 case float_relation_less: \ |
|
650 new_fsr = FSR_FCC0 << FS; \ |
|
651 break; \ |
|
652 case float_relation_greater: \ |
|
653 new_fsr = FSR_FCC1 << FS; \ |
|
654 break; \ |
|
655 default: \ |
|
656 new_fsr = 0; \ |
|
657 break; \ |
|
658 } \ |
|
659 env->fsr |= new_fsr; \ |
|
660 } |
|
661 #define GEN_FCMPS(name, size, FS, TRAP) \ |
|
662 void glue(helper_, name)(float32 src1, float32 src2) \ |
|
663 { \ |
|
664 target_ulong new_fsr; \ |
|
665 \ |
|
666 env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ |
|
667 switch (glue(size, _compare) (src1, src2, &env->fp_status)) { \ |
|
668 case float_relation_unordered: \ |
|
669 new_fsr = (FSR_FCC1 | FSR_FCC0) << FS; \ |
|
670 if ((env->fsr & FSR_NVM) || TRAP) { \ |
|
671 env->fsr |= new_fsr; \ |
|
672 env->fsr |= FSR_NVC; \ |
|
673 env->fsr |= FSR_FTT_IEEE_EXCP; \ |
|
674 raise_exception(TT_FP_EXCP); \ |
|
675 } else { \ |
|
676 env->fsr |= FSR_NVA; \ |
|
677 } \ |
|
678 break; \ |
|
679 case float_relation_less: \ |
|
680 new_fsr = FSR_FCC0 << FS; \ |
|
681 break; \ |
|
682 case float_relation_greater: \ |
|
683 new_fsr = FSR_FCC1 << FS; \ |
|
684 break; \ |
|
685 default: \ |
|
686 new_fsr = 0; \ |
|
687 break; \ |
|
688 } \ |
|
689 env->fsr |= new_fsr; \ |
|
690 } |
|
691 |
|
692 GEN_FCMPS(fcmps, float32, 0, 0); |
|
693 GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0); |
|
694 |
|
695 GEN_FCMPS(fcmpes, float32, 0, 1); |
|
696 GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1); |
|
697 |
|
698 GEN_FCMP(fcmpq, float128, QT0, QT1, 0, 0); |
|
699 GEN_FCMP(fcmpeq, float128, QT0, QT1, 0, 1); |
|
700 |
|
701 #ifdef TARGET_SPARC64 |
|
702 GEN_FCMPS(fcmps_fcc1, float32, 22, 0); |
|
703 GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0); |
|
704 GEN_FCMP(fcmpq_fcc1, float128, QT0, QT1, 22, 0); |
|
705 |
|
706 GEN_FCMPS(fcmps_fcc2, float32, 24, 0); |
|
707 GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0); |
|
708 GEN_FCMP(fcmpq_fcc2, float128, QT0, QT1, 24, 0); |
|
709 |
|
710 GEN_FCMPS(fcmps_fcc3, float32, 26, 0); |
|
711 GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0); |
|
712 GEN_FCMP(fcmpq_fcc3, float128, QT0, QT1, 26, 0); |
|
713 |
|
714 GEN_FCMPS(fcmpes_fcc1, float32, 22, 1); |
|
715 GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1); |
|
716 GEN_FCMP(fcmpeq_fcc1, float128, QT0, QT1, 22, 1); |
|
717 |
|
718 GEN_FCMPS(fcmpes_fcc2, float32, 24, 1); |
|
719 GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1); |
|
720 GEN_FCMP(fcmpeq_fcc2, float128, QT0, QT1, 24, 1); |
|
721 |
|
722 GEN_FCMPS(fcmpes_fcc3, float32, 26, 1); |
|
723 GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1); |
|
724 GEN_FCMP(fcmpeq_fcc3, float128, QT0, QT1, 26, 1); |
|
725 #endif |
|
726 #undef GEN_FCMPS |
|
727 |
|
728 #if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY) && \ |
|
729 defined(DEBUG_MXCC) |
|
730 static void dump_mxcc(CPUState *env) |
|
731 { |
|
732 printf("mxccdata: %016llx %016llx %016llx %016llx\n", |
|
733 env->mxccdata[0], env->mxccdata[1], |
|
734 env->mxccdata[2], env->mxccdata[3]); |
|
735 printf("mxccregs: %016llx %016llx %016llx %016llx\n" |
|
736 " %016llx %016llx %016llx %016llx\n", |
|
737 env->mxccregs[0], env->mxccregs[1], |
|
738 env->mxccregs[2], env->mxccregs[3], |
|
739 env->mxccregs[4], env->mxccregs[5], |
|
740 env->mxccregs[6], env->mxccregs[7]); |
|
741 } |
|
742 #endif |
|
743 |
|
744 #if (defined(TARGET_SPARC64) || !defined(CONFIG_USER_ONLY)) \ |
|
745 && defined(DEBUG_ASI) |
|
746 static void dump_asi(const char *txt, target_ulong addr, int asi, int size, |
|
747 uint64_t r1) |
|
748 { |
|
749 switch (size) |
|
750 { |
|
751 case 1: |
|
752 DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %02" PRIx64 "\n", txt, |
|
753 addr, asi, r1 & 0xff); |
|
754 break; |
|
755 case 2: |
|
756 DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %04" PRIx64 "\n", txt, |
|
757 addr, asi, r1 & 0xffff); |
|
758 break; |
|
759 case 4: |
|
760 DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %08" PRIx64 "\n", txt, |
|
761 addr, asi, r1 & 0xffffffff); |
|
762 break; |
|
763 case 8: |
|
764 DPRINTF_ASI("%s "TARGET_FMT_lx " asi 0x%02x = %016" PRIx64 "\n", txt, |
|
765 addr, asi, r1); |
|
766 break; |
|
767 } |
|
768 } |
|
769 #endif |
|
770 |
|
771 #ifndef TARGET_SPARC64 |
|
772 #ifndef CONFIG_USER_ONLY |
|
773 uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) |
|
774 { |
|
775 uint64_t ret = 0; |
|
776 #if defined(DEBUG_MXCC) || defined(DEBUG_ASI) |
|
777 uint32_t last_addr = addr; |
|
778 #endif |
|
779 |
|
780 helper_check_align(addr, size - 1); |
|
781 switch (asi) { |
|
782 case 2: /* SuperSparc MXCC registers */ |
|
783 switch (addr) { |
|
784 case 0x01c00a00: /* MXCC control register */ |
|
785 if (size == 8) |
|
786 ret = env->mxccregs[3]; |
|
787 else |
|
788 DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
|
789 size); |
|
790 break; |
|
791 case 0x01c00a04: /* MXCC control register */ |
|
792 if (size == 4) |
|
793 ret = env->mxccregs[3]; |
|
794 else |
|
795 DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
|
796 size); |
|
797 break; |
|
798 case 0x01c00c00: /* Module reset register */ |
|
799 if (size == 8) { |
|
800 ret = env->mxccregs[5]; |
|
801 // should we do something here? |
|
802 } else |
|
803 DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
|
804 size); |
|
805 break; |
|
806 case 0x01c00f00: /* MBus port address register */ |
|
807 if (size == 8) |
|
808 ret = env->mxccregs[7]; |
|
809 else |
|
810 DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
|
811 size); |
|
812 break; |
|
813 default: |
|
814 DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr, |
|
815 size); |
|
816 break; |
|
817 } |
|
818 DPRINTF_MXCC("asi = %d, size = %d, sign = %d, " |
|
819 "addr = %08x -> ret = %" PRIx64 "," |
|
820 "addr = %08x\n", asi, size, sign, last_addr, ret, addr); |
|
821 #ifdef DEBUG_MXCC |
|
822 dump_mxcc(env); |
|
823 #endif |
|
824 break; |
|
825 case 3: /* MMU probe */ |
|
826 { |
|
827 int mmulev; |
|
828 |
|
829 mmulev = (addr >> 8) & 15; |
|
830 if (mmulev > 4) |
|
831 ret = 0; |
|
832 else |
|
833 ret = mmu_probe(env, addr, mmulev); |
|
834 DPRINTF_MMU("mmu_probe: 0x%08x (lev %d) -> 0x%08" PRIx64 "\n", |
|
835 addr, mmulev, ret); |
|
836 } |
|
837 break; |
|
838 case 4: /* read MMU regs */ |
|
839 { |
|
840 int reg = (addr >> 8) & 0x1f; |
|
841 |
|
842 ret = env->mmuregs[reg]; |
|
843 if (reg == 3) /* Fault status cleared on read */ |
|
844 env->mmuregs[3] = 0; |
|
845 else if (reg == 0x13) /* Fault status read */ |
|
846 ret = env->mmuregs[3]; |
|
847 else if (reg == 0x14) /* Fault address read */ |
|
848 ret = env->mmuregs[4]; |
|
849 DPRINTF_MMU("mmu_read: reg[%d] = 0x%08" PRIx64 "\n", reg, ret); |
|
850 } |
|
851 break; |
|
852 case 5: // Turbosparc ITLB Diagnostic |
|
853 case 6: // Turbosparc DTLB Diagnostic |
|
854 case 7: // Turbosparc IOTLB Diagnostic |
|
855 break; |
|
856 case 9: /* Supervisor code access */ |
|
857 switch(size) { |
|
858 case 1: |
|
859 ret = ldub_code(addr); |
|
860 break; |
|
861 case 2: |
|
862 ret = lduw_code(addr); |
|
863 break; |
|
864 default: |
|
865 case 4: |
|
866 ret = ldl_code(addr); |
|
867 break; |
|
868 case 8: |
|
869 ret = ldq_code(addr); |
|
870 break; |
|
871 } |
|
872 break; |
|
873 case 0xa: /* User data access */ |
|
874 switch(size) { |
|
875 case 1: |
|
876 ret = ldub_user(addr); |
|
877 break; |
|
878 case 2: |
|
879 ret = lduw_user(addr); |
|
880 break; |
|
881 default: |
|
882 case 4: |
|
883 ret = ldl_user(addr); |
|
884 break; |
|
885 case 8: |
|
886 ret = ldq_user(addr); |
|
887 break; |
|
888 } |
|
889 break; |
|
890 case 0xb: /* Supervisor data access */ |
|
891 switch(size) { |
|
892 case 1: |
|
893 ret = ldub_kernel(addr); |
|
894 break; |
|
895 case 2: |
|
896 ret = lduw_kernel(addr); |
|
897 break; |
|
898 default: |
|
899 case 4: |
|
900 ret = ldl_kernel(addr); |
|
901 break; |
|
902 case 8: |
|
903 ret = ldq_kernel(addr); |
|
904 break; |
|
905 } |
|
906 break; |
|
907 case 0xc: /* I-cache tag */ |
|
908 case 0xd: /* I-cache data */ |
|
909 case 0xe: /* D-cache tag */ |
|
910 case 0xf: /* D-cache data */ |
|
911 break; |
|
912 case 0x20: /* MMU passthrough */ |
|
913 switch(size) { |
|
914 case 1: |
|
915 ret = ldub_phys(addr); |
|
916 break; |
|
917 case 2: |
|
918 ret = lduw_phys(addr); |
|
919 break; |
|
920 default: |
|
921 case 4: |
|
922 ret = ldl_phys(addr); |
|
923 break; |
|
924 case 8: |
|
925 ret = ldq_phys(addr); |
|
926 break; |
|
927 } |
|
928 break; |
|
929 case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */ |
|
930 switch(size) { |
|
931 case 1: |
|
932 ret = ldub_phys((target_phys_addr_t)addr |
|
933 | ((target_phys_addr_t)(asi & 0xf) << 32)); |
|
934 break; |
|
935 case 2: |
|
936 ret = lduw_phys((target_phys_addr_t)addr |
|
937 | ((target_phys_addr_t)(asi & 0xf) << 32)); |
|
938 break; |
|
939 default: |
|
940 case 4: |
|
941 ret = ldl_phys((target_phys_addr_t)addr |
|
942 | ((target_phys_addr_t)(asi & 0xf) << 32)); |
|
943 break; |
|
944 case 8: |
|
945 ret = ldq_phys((target_phys_addr_t)addr |
|
946 | ((target_phys_addr_t)(asi & 0xf) << 32)); |
|
947 break; |
|
948 } |
|
949 break; |
|
950 case 0x30: // Turbosparc secondary cache diagnostic |
|
951 case 0x31: // Turbosparc RAM snoop |
|
952 case 0x32: // Turbosparc page table descriptor diagnostic |
|
953 case 0x39: /* data cache diagnostic register */ |
|
954 ret = 0; |
|
955 break; |
|
956 case 0x38: /* SuperSPARC MMU Breakpoint Control Registers */ |
|
957 { |
|
958 int reg = (addr >> 8) & 3; |
|
959 |
|
960 switch(reg) { |
|
961 case 0: /* Breakpoint Value (Addr) */ |
|
962 ret = env->mmubpregs[reg]; |
|
963 break; |
|
964 case 1: /* Breakpoint Mask */ |
|
965 ret = env->mmubpregs[reg]; |
|
966 break; |
|
967 case 2: /* Breakpoint Control */ |
|
968 ret = env->mmubpregs[reg]; |
|
969 break; |
|
970 case 3: /* Breakpoint Status */ |
|
971 ret = env->mmubpregs[reg]; |
|
972 env->mmubpregs[reg] = 0ULL; |
|
973 break; |
|
974 } |
|
975 DPRINTF_MMU("read breakpoint reg[%d] 0x%016llx\n", reg, ret); |
|
976 } |
|
977 break; |
|
978 case 8: /* User code access, XXX */ |
|
979 default: |
|
980 do_unassigned_access(addr, 0, 0, asi, size); |
|
981 ret = 0; |
|
982 break; |
|
983 } |
|
984 if (sign) { |
|
985 switch(size) { |
|
986 case 1: |
|
987 ret = (int8_t) ret; |
|
988 break; |
|
989 case 2: |
|
990 ret = (int16_t) ret; |
|
991 break; |
|
992 case 4: |
|
993 ret = (int32_t) ret; |
|
994 break; |
|
995 default: |
|
996 break; |
|
997 } |
|
998 } |
|
999 #ifdef DEBUG_ASI |
|
1000 dump_asi("read ", last_addr, asi, size, ret); |
|
1001 #endif |
|
1002 return ret; |
|
1003 } |
|
1004 |
|
1005 void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) |
|
1006 { |
|
1007 helper_check_align(addr, size - 1); |
|
1008 switch(asi) { |
|
1009 case 2: /* SuperSparc MXCC registers */ |
|
1010 switch (addr) { |
|
1011 case 0x01c00000: /* MXCC stream data register 0 */ |
|
1012 if (size == 8) |
|
1013 env->mxccdata[0] = val; |
|
1014 else |
|
1015 DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
|
1016 size); |
|
1017 break; |
|
1018 case 0x01c00008: /* MXCC stream data register 1 */ |
|
1019 if (size == 8) |
|
1020 env->mxccdata[1] = val; |
|
1021 else |
|
1022 DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
|
1023 size); |
|
1024 break; |
|
1025 case 0x01c00010: /* MXCC stream data register 2 */ |
|
1026 if (size == 8) |
|
1027 env->mxccdata[2] = val; |
|
1028 else |
|
1029 DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
|
1030 size); |
|
1031 break; |
|
1032 case 0x01c00018: /* MXCC stream data register 3 */ |
|
1033 if (size == 8) |
|
1034 env->mxccdata[3] = val; |
|
1035 else |
|
1036 DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
|
1037 size); |
|
1038 break; |
|
1039 case 0x01c00100: /* MXCC stream source */ |
|
1040 if (size == 8) |
|
1041 env->mxccregs[0] = val; |
|
1042 else |
|
1043 DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
|
1044 size); |
|
1045 env->mxccdata[0] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + |
|
1046 0); |
|
1047 env->mxccdata[1] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + |
|
1048 8); |
|
1049 env->mxccdata[2] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + |
|
1050 16); |
|
1051 env->mxccdata[3] = ldq_phys((env->mxccregs[0] & 0xffffffffULL) + |
|
1052 24); |
|
1053 break; |
|
1054 case 0x01c00200: /* MXCC stream destination */ |
|
1055 if (size == 8) |
|
1056 env->mxccregs[1] = val; |
|
1057 else |
|
1058 DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
|
1059 size); |
|
1060 stq_phys((env->mxccregs[1] & 0xffffffffULL) + 0, |
|
1061 env->mxccdata[0]); |
|
1062 stq_phys((env->mxccregs[1] & 0xffffffffULL) + 8, |
|
1063 env->mxccdata[1]); |
|
1064 stq_phys((env->mxccregs[1] & 0xffffffffULL) + 16, |
|
1065 env->mxccdata[2]); |
|
1066 stq_phys((env->mxccregs[1] & 0xffffffffULL) + 24, |
|
1067 env->mxccdata[3]); |
|
1068 break; |
|
1069 case 0x01c00a00: /* MXCC control register */ |
|
1070 if (size == 8) |
|
1071 env->mxccregs[3] = val; |
|
1072 else |
|
1073 DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
|
1074 size); |
|
1075 break; |
|
1076 case 0x01c00a04: /* MXCC control register */ |
|
1077 if (size == 4) |
|
1078 env->mxccregs[3] = (env->mxccregs[3] & 0xffffffff00000000ULL) |
|
1079 | val; |
|
1080 else |
|
1081 DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
|
1082 size); |
|
1083 break; |
|
1084 case 0x01c00e00: /* MXCC error register */ |
|
1085 // writing a 1 bit clears the error |
|
1086 if (size == 8) |
|
1087 env->mxccregs[6] &= ~val; |
|
1088 else |
|
1089 DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
|
1090 size); |
|
1091 break; |
|
1092 case 0x01c00f00: /* MBus port address register */ |
|
1093 if (size == 8) |
|
1094 env->mxccregs[7] = val; |
|
1095 else |
|
1096 DPRINTF_MXCC("%08x: unimplemented access size: %d\n", addr, |
|
1097 size); |
|
1098 break; |
|
1099 default: |
|
1100 DPRINTF_MXCC("%08x: unimplemented address, size: %d\n", addr, |
|
1101 size); |
|
1102 break; |
|
1103 } |
|
1104 DPRINTF_MXCC("asi = %d, size = %d, addr = %08x, val = %" PRIx64 "\n", |
|
1105 asi, size, addr, val); |
|
1106 #ifdef DEBUG_MXCC |
|
1107 dump_mxcc(env); |
|
1108 #endif |
|
1109 break; |
|
1110 case 3: /* MMU flush */ |
|
1111 { |
|
1112 int mmulev; |
|
1113 |
|
1114 mmulev = (addr >> 8) & 15; |
|
1115 DPRINTF_MMU("mmu flush level %d\n", mmulev); |
|
1116 switch (mmulev) { |
|
1117 case 0: // flush page |
|
1118 tlb_flush_page(env, addr & 0xfffff000); |
|
1119 break; |
|
1120 case 1: // flush segment (256k) |
|
1121 case 2: // flush region (16M) |
|
1122 case 3: // flush context (4G) |
|
1123 case 4: // flush entire |
|
1124 tlb_flush(env, 1); |
|
1125 break; |
|
1126 default: |
|
1127 break; |
|
1128 } |
|
1129 #ifdef DEBUG_MMU |
|
1130 dump_mmu(env); |
|
1131 #endif |
|
1132 } |
|
1133 break; |
|
1134 case 4: /* write MMU regs */ |
|
1135 { |
|
1136 int reg = (addr >> 8) & 0x1f; |
|
1137 uint32_t oldreg; |
|
1138 |
|
1139 oldreg = env->mmuregs[reg]; |
|
1140 switch(reg) { |
|
1141 case 0: // Control Register |
|
1142 env->mmuregs[reg] = (env->mmuregs[reg] & 0xff000000) | |
|
1143 (val & 0x00ffffff); |
|
1144 // Mappings generated during no-fault mode or MMU |
|
1145 // disabled mode are invalid in normal mode |
|
1146 if ((oldreg & (MMU_E | MMU_NF | env->def->mmu_bm)) != |
|
1147 (env->mmuregs[reg] & (MMU_E | MMU_NF | env->def->mmu_bm))) |
|
1148 tlb_flush(env, 1); |
|
1149 break; |
|
1150 case 1: // Context Table Pointer Register |
|
1151 env->mmuregs[reg] = val & env->def->mmu_ctpr_mask; |
|
1152 break; |
|
1153 case 2: // Context Register |
|
1154 env->mmuregs[reg] = val & env->def->mmu_cxr_mask; |
|
1155 if (oldreg != env->mmuregs[reg]) { |
|
1156 /* we flush when the MMU context changes because |
|
1157 QEMU has no MMU context support */ |
|
1158 tlb_flush(env, 1); |
|
1159 } |
|
1160 break; |
|
1161 case 3: // Synchronous Fault Status Register with Clear |
|
1162 case 4: // Synchronous Fault Address Register |
|
1163 break; |
|
1164 case 0x10: // TLB Replacement Control Register |
|
1165 env->mmuregs[reg] = val & env->def->mmu_trcr_mask; |
|
1166 break; |
|
1167 case 0x13: // Synchronous Fault Status Register with Read and Clear |
|
1168 env->mmuregs[3] = val & env->def->mmu_sfsr_mask; |
|
1169 break; |
|
1170 case 0x14: // Synchronous Fault Address Register |
|
1171 env->mmuregs[4] = val; |
|
1172 break; |
|
1173 default: |
|
1174 env->mmuregs[reg] = val; |
|
1175 break; |
|
1176 } |
|
1177 if (oldreg != env->mmuregs[reg]) { |
|
1178 DPRINTF_MMU("mmu change reg[%d]: 0x%08x -> 0x%08x\n", |
|
1179 reg, oldreg, env->mmuregs[reg]); |
|
1180 } |
|
1181 #ifdef DEBUG_MMU |
|
1182 dump_mmu(env); |
|
1183 #endif |
|
1184 } |
|
1185 break; |
|
1186 case 5: // Turbosparc ITLB Diagnostic |
|
1187 case 6: // Turbosparc DTLB Diagnostic |
|
1188 case 7: // Turbosparc IOTLB Diagnostic |
|
1189 break; |
|
1190 case 0xa: /* User data access */ |
|
1191 switch(size) { |
|
1192 case 1: |
|
1193 stb_user(addr, val); |
|
1194 break; |
|
1195 case 2: |
|
1196 stw_user(addr, val); |
|
1197 break; |
|
1198 default: |
|
1199 case 4: |
|
1200 stl_user(addr, val); |
|
1201 break; |
|
1202 case 8: |
|
1203 stq_user(addr, val); |
|
1204 break; |
|
1205 } |
|
1206 break; |
|
1207 case 0xb: /* Supervisor data access */ |
|
1208 switch(size) { |
|
1209 case 1: |
|
1210 stb_kernel(addr, val); |
|
1211 break; |
|
1212 case 2: |
|
1213 stw_kernel(addr, val); |
|
1214 break; |
|
1215 default: |
|
1216 case 4: |
|
1217 stl_kernel(addr, val); |
|
1218 break; |
|
1219 case 8: |
|
1220 stq_kernel(addr, val); |
|
1221 break; |
|
1222 } |
|
1223 break; |
|
1224 case 0xc: /* I-cache tag */ |
|
1225 case 0xd: /* I-cache data */ |
|
1226 case 0xe: /* D-cache tag */ |
|
1227 case 0xf: /* D-cache data */ |
|
1228 case 0x10: /* I/D-cache flush page */ |
|
1229 case 0x11: /* I/D-cache flush segment */ |
|
1230 case 0x12: /* I/D-cache flush region */ |
|
1231 case 0x13: /* I/D-cache flush context */ |
|
1232 case 0x14: /* I/D-cache flush user */ |
|
1233 break; |
|
1234 case 0x17: /* Block copy, sta access */ |
|
1235 { |
|
1236 // val = src |
|
1237 // addr = dst |
|
1238 // copy 32 bytes |
|
1239 unsigned int i; |
|
1240 uint32_t src = val & ~3, dst = addr & ~3, temp; |
|
1241 |
|
1242 for (i = 0; i < 32; i += 4, src += 4, dst += 4) { |
|
1243 temp = ldl_kernel(src); |
|
1244 stl_kernel(dst, temp); |
|
1245 } |
|
1246 } |
|
1247 break; |
|
1248 case 0x1f: /* Block fill, stda access */ |
|
1249 { |
|
1250 // addr = dst |
|
1251 // fill 32 bytes with val |
|
1252 unsigned int i; |
|
1253 uint32_t dst = addr & 7; |
|
1254 |
|
1255 for (i = 0; i < 32; i += 8, dst += 8) |
|
1256 stq_kernel(dst, val); |
|
1257 } |
|
1258 break; |
|
1259 case 0x20: /* MMU passthrough */ |
|
1260 { |
|
1261 switch(size) { |
|
1262 case 1: |
|
1263 stb_phys(addr, val); |
|
1264 break; |
|
1265 case 2: |
|
1266 stw_phys(addr, val); |
|
1267 break; |
|
1268 case 4: |
|
1269 default: |
|
1270 stl_phys(addr, val); |
|
1271 break; |
|
1272 case 8: |
|
1273 stq_phys(addr, val); |
|
1274 break; |
|
1275 } |
|
1276 } |
|
1277 break; |
|
1278 case 0x21 ... 0x2f: /* MMU passthrough, 0x100000000 to 0xfffffffff */ |
|
1279 { |
|
1280 switch(size) { |
|
1281 case 1: |
|
1282 stb_phys((target_phys_addr_t)addr |
|
1283 | ((target_phys_addr_t)(asi & 0xf) << 32), val); |
|
1284 break; |
|
1285 case 2: |
|
1286 stw_phys((target_phys_addr_t)addr |
|
1287 | ((target_phys_addr_t)(asi & 0xf) << 32), val); |
|
1288 break; |
|
1289 case 4: |
|
1290 default: |
|
1291 stl_phys((target_phys_addr_t)addr |
|
1292 | ((target_phys_addr_t)(asi & 0xf) << 32), val); |
|
1293 break; |
|
1294 case 8: |
|
1295 stq_phys((target_phys_addr_t)addr |
|
1296 | ((target_phys_addr_t)(asi & 0xf) << 32), val); |
|
1297 break; |
|
1298 } |
|
1299 } |
|
1300 break; |
|
1301 case 0x30: // store buffer tags or Turbosparc secondary cache diagnostic |
|
1302 case 0x31: // store buffer data, Ross RT620 I-cache flush or |
|
1303 // Turbosparc snoop RAM |
|
1304 case 0x32: // store buffer control or Turbosparc page table |
|
1305 // descriptor diagnostic |
|
1306 case 0x36: /* I-cache flash clear */ |
|
1307 case 0x37: /* D-cache flash clear */ |
|
1308 case 0x4c: /* breakpoint action */ |
|
1309 break; |
|
1310 case 0x38: /* SuperSPARC MMU Breakpoint Control Registers*/ |
|
1311 { |
|
1312 int reg = (addr >> 8) & 3; |
|
1313 |
|
1314 switch(reg) { |
|
1315 case 0: /* Breakpoint Value (Addr) */ |
|
1316 env->mmubpregs[reg] = (val & 0xfffffffffULL); |
|
1317 break; |
|
1318 case 1: /* Breakpoint Mask */ |
|
1319 env->mmubpregs[reg] = (val & 0xfffffffffULL); |
|
1320 break; |
|
1321 case 2: /* Breakpoint Control */ |
|
1322 env->mmubpregs[reg] = (val & 0x7fULL); |
|
1323 break; |
|
1324 case 3: /* Breakpoint Status */ |
|
1325 env->mmubpregs[reg] = (val & 0xfULL); |
|
1326 break; |
|
1327 } |
|
1328 DPRINTF_MMU("write breakpoint reg[%d] 0x%016llx\n", reg, |
|
1329 env->mmuregs[reg]); |
|
1330 } |
|
1331 break; |
|
1332 case 8: /* User code access, XXX */ |
|
1333 case 9: /* Supervisor code access, XXX */ |
|
1334 default: |
|
1335 do_unassigned_access(addr, 1, 0, asi, size); |
|
1336 break; |
|
1337 } |
|
1338 #ifdef DEBUG_ASI |
|
1339 dump_asi("write", addr, asi, size, val); |
|
1340 #endif |
|
1341 } |
|
1342 |
|
1343 #endif /* CONFIG_USER_ONLY */ |
|
1344 #else /* TARGET_SPARC64 */ |
|
1345 |
|
1346 #ifdef CONFIG_USER_ONLY |
|
1347 uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) |
|
1348 { |
|
1349 uint64_t ret = 0; |
|
1350 #if defined(DEBUG_ASI) |
|
1351 target_ulong last_addr = addr; |
|
1352 #endif |
|
1353 |
|
1354 if (asi < 0x80) |
|
1355 raise_exception(TT_PRIV_ACT); |
|
1356 |
|
1357 helper_check_align(addr, size - 1); |
|
1358 address_mask(env, &addr); |
|
1359 |
|
1360 switch (asi) { |
|
1361 case 0x82: // Primary no-fault |
|
1362 case 0x8a: // Primary no-fault LE |
|
1363 if (page_check_range(addr, size, PAGE_READ) == -1) { |
|
1364 #ifdef DEBUG_ASI |
|
1365 dump_asi("read ", last_addr, asi, size, ret); |
|
1366 #endif |
|
1367 return 0; |
|
1368 } |
|
1369 // Fall through |
|
1370 case 0x80: // Primary |
|
1371 case 0x88: // Primary LE |
|
1372 { |
|
1373 switch(size) { |
|
1374 case 1: |
|
1375 ret = ldub_raw(addr); |
|
1376 break; |
|
1377 case 2: |
|
1378 ret = lduw_raw(addr); |
|
1379 break; |
|
1380 case 4: |
|
1381 ret = ldl_raw(addr); |
|
1382 break; |
|
1383 default: |
|
1384 case 8: |
|
1385 ret = ldq_raw(addr); |
|
1386 break; |
|
1387 } |
|
1388 } |
|
1389 break; |
|
1390 case 0x83: // Secondary no-fault |
|
1391 case 0x8b: // Secondary no-fault LE |
|
1392 if (page_check_range(addr, size, PAGE_READ) == -1) { |
|
1393 #ifdef DEBUG_ASI |
|
1394 dump_asi("read ", last_addr, asi, size, ret); |
|
1395 #endif |
|
1396 return 0; |
|
1397 } |
|
1398 // Fall through |
|
1399 case 0x81: // Secondary |
|
1400 case 0x89: // Secondary LE |
|
1401 // XXX |
|
1402 break; |
|
1403 default: |
|
1404 break; |
|
1405 } |
|
1406 |
|
1407 /* Convert from little endian */ |
|
1408 switch (asi) { |
|
1409 case 0x88: // Primary LE |
|
1410 case 0x89: // Secondary LE |
|
1411 case 0x8a: // Primary no-fault LE |
|
1412 case 0x8b: // Secondary no-fault LE |
|
1413 switch(size) { |
|
1414 case 2: |
|
1415 ret = bswap16(ret); |
|
1416 break; |
|
1417 case 4: |
|
1418 ret = bswap32(ret); |
|
1419 break; |
|
1420 case 8: |
|
1421 ret = bswap64(ret); |
|
1422 break; |
|
1423 default: |
|
1424 break; |
|
1425 } |
|
1426 default: |
|
1427 break; |
|
1428 } |
|
1429 |
|
1430 /* Convert to signed number */ |
|
1431 if (sign) { |
|
1432 switch(size) { |
|
1433 case 1: |
|
1434 ret = (int8_t) ret; |
|
1435 break; |
|
1436 case 2: |
|
1437 ret = (int16_t) ret; |
|
1438 break; |
|
1439 case 4: |
|
1440 ret = (int32_t) ret; |
|
1441 break; |
|
1442 default: |
|
1443 break; |
|
1444 } |
|
1445 } |
|
1446 #ifdef DEBUG_ASI |
|
1447 dump_asi("read ", last_addr, asi, size, ret); |
|
1448 #endif |
|
1449 return ret; |
|
1450 } |
|
1451 |
|
1452 void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) |
|
1453 { |
|
1454 #ifdef DEBUG_ASI |
|
1455 dump_asi("write", addr, asi, size, val); |
|
1456 #endif |
|
1457 if (asi < 0x80) |
|
1458 raise_exception(TT_PRIV_ACT); |
|
1459 |
|
1460 helper_check_align(addr, size - 1); |
|
1461 address_mask(env, &addr); |
|
1462 |
|
1463 /* Convert to little endian */ |
|
1464 switch (asi) { |
|
1465 case 0x88: // Primary LE |
|
1466 case 0x89: // Secondary LE |
|
1467 switch(size) { |
|
1468 case 2: |
|
1469 addr = bswap16(addr); |
|
1470 break; |
|
1471 case 4: |
|
1472 addr = bswap32(addr); |
|
1473 break; |
|
1474 case 8: |
|
1475 addr = bswap64(addr); |
|
1476 break; |
|
1477 default: |
|
1478 break; |
|
1479 } |
|
1480 default: |
|
1481 break; |
|
1482 } |
|
1483 |
|
1484 switch(asi) { |
|
1485 case 0x80: // Primary |
|
1486 case 0x88: // Primary LE |
|
1487 { |
|
1488 switch(size) { |
|
1489 case 1: |
|
1490 stb_raw(addr, val); |
|
1491 break; |
|
1492 case 2: |
|
1493 stw_raw(addr, val); |
|
1494 break; |
|
1495 case 4: |
|
1496 stl_raw(addr, val); |
|
1497 break; |
|
1498 case 8: |
|
1499 default: |
|
1500 stq_raw(addr, val); |
|
1501 break; |
|
1502 } |
|
1503 } |
|
1504 break; |
|
1505 case 0x81: // Secondary |
|
1506 case 0x89: // Secondary LE |
|
1507 // XXX |
|
1508 return; |
|
1509 |
|
1510 case 0x82: // Primary no-fault, RO |
|
1511 case 0x83: // Secondary no-fault, RO |
|
1512 case 0x8a: // Primary no-fault LE, RO |
|
1513 case 0x8b: // Secondary no-fault LE, RO |
|
1514 default: |
|
1515 do_unassigned_access(addr, 1, 0, 1, size); |
|
1516 return; |
|
1517 } |
|
1518 } |
|
1519 |
|
1520 #else /* CONFIG_USER_ONLY */ |
|
1521 |
|
1522 uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign) |
|
1523 { |
|
1524 uint64_t ret = 0; |
|
1525 #if defined(DEBUG_ASI) |
|
1526 target_ulong last_addr = addr; |
|
1527 #endif |
|
1528 |
|
1529 if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) |
|
1530 || ((env->def->features & CPU_FEATURE_HYPV) |
|
1531 && asi >= 0x30 && asi < 0x80 |
|
1532 && !(env->hpstate & HS_PRIV))) |
|
1533 raise_exception(TT_PRIV_ACT); |
|
1534 |
|
1535 helper_check_align(addr, size - 1); |
|
1536 switch (asi) { |
|
1537 case 0x82: // Primary no-fault |
|
1538 case 0x8a: // Primary no-fault LE |
|
1539 if (cpu_get_phys_page_debug(env, addr) == -1ULL) { |
|
1540 #ifdef DEBUG_ASI |
|
1541 dump_asi("read ", last_addr, asi, size, ret); |
|
1542 #endif |
|
1543 return 0; |
|
1544 } |
|
1545 // Fall through |
|
1546 case 0x10: // As if user primary |
|
1547 case 0x18: // As if user primary LE |
|
1548 case 0x80: // Primary |
|
1549 case 0x88: // Primary LE |
|
1550 case 0xe2: // UA2007 Primary block init |
|
1551 case 0xe3: // UA2007 Secondary block init |
|
1552 if ((asi & 0x80) && (env->pstate & PS_PRIV)) { |
|
1553 if ((env->def->features & CPU_FEATURE_HYPV) |
|
1554 && env->hpstate & HS_PRIV) { |
|
1555 switch(size) { |
|
1556 case 1: |
|
1557 ret = ldub_hypv(addr); |
|
1558 break; |
|
1559 case 2: |
|
1560 ret = lduw_hypv(addr); |
|
1561 break; |
|
1562 case 4: |
|
1563 ret = ldl_hypv(addr); |
|
1564 break; |
|
1565 default: |
|
1566 case 8: |
|
1567 ret = ldq_hypv(addr); |
|
1568 break; |
|
1569 } |
|
1570 } else { |
|
1571 switch(size) { |
|
1572 case 1: |
|
1573 ret = ldub_kernel(addr); |
|
1574 break; |
|
1575 case 2: |
|
1576 ret = lduw_kernel(addr); |
|
1577 break; |
|
1578 case 4: |
|
1579 ret = ldl_kernel(addr); |
|
1580 break; |
|
1581 default: |
|
1582 case 8: |
|
1583 ret = ldq_kernel(addr); |
|
1584 break; |
|
1585 } |
|
1586 } |
|
1587 } else { |
|
1588 switch(size) { |
|
1589 case 1: |
|
1590 ret = ldub_user(addr); |
|
1591 break; |
|
1592 case 2: |
|
1593 ret = lduw_user(addr); |
|
1594 break; |
|
1595 case 4: |
|
1596 ret = ldl_user(addr); |
|
1597 break; |
|
1598 default: |
|
1599 case 8: |
|
1600 ret = ldq_user(addr); |
|
1601 break; |
|
1602 } |
|
1603 } |
|
1604 break; |
|
1605 case 0x14: // Bypass |
|
1606 case 0x15: // Bypass, non-cacheable |
|
1607 case 0x1c: // Bypass LE |
|
1608 case 0x1d: // Bypass, non-cacheable LE |
|
1609 { |
|
1610 switch(size) { |
|
1611 case 1: |
|
1612 ret = ldub_phys(addr); |
|
1613 break; |
|
1614 case 2: |
|
1615 ret = lduw_phys(addr); |
|
1616 break; |
|
1617 case 4: |
|
1618 ret = ldl_phys(addr); |
|
1619 break; |
|
1620 default: |
|
1621 case 8: |
|
1622 ret = ldq_phys(addr); |
|
1623 break; |
|
1624 } |
|
1625 break; |
|
1626 } |
|
1627 case 0x24: // Nucleus quad LDD 128 bit atomic |
|
1628 case 0x2c: // Nucleus quad LDD 128 bit atomic LE |
|
1629 // Only ldda allowed |
|
1630 raise_exception(TT_ILL_INSN); |
|
1631 return 0; |
|
1632 case 0x83: // Secondary no-fault |
|
1633 case 0x8b: // Secondary no-fault LE |
|
1634 if (cpu_get_phys_page_debug(env, addr) == -1ULL) { |
|
1635 #ifdef DEBUG_ASI |
|
1636 dump_asi("read ", last_addr, asi, size, ret); |
|
1637 #endif |
|
1638 return 0; |
|
1639 } |
|
1640 // Fall through |
|
1641 case 0x04: // Nucleus |
|
1642 case 0x0c: // Nucleus Little Endian (LE) |
|
1643 case 0x11: // As if user secondary |
|
1644 case 0x19: // As if user secondary LE |
|
1645 case 0x4a: // UPA config |
|
1646 case 0x81: // Secondary |
|
1647 case 0x89: // Secondary LE |
|
1648 // XXX |
|
1649 break; |
|
1650 case 0x45: // LSU |
|
1651 ret = env->lsu; |
|
1652 break; |
|
1653 case 0x50: // I-MMU regs |
|
1654 { |
|
1655 int reg = (addr >> 3) & 0xf; |
|
1656 |
|
1657 ret = env->immuregs[reg]; |
|
1658 break; |
|
1659 } |
|
1660 case 0x51: // I-MMU 8k TSB pointer |
|
1661 case 0x52: // I-MMU 64k TSB pointer |
|
1662 // XXX |
|
1663 break; |
|
1664 case 0x55: // I-MMU data access |
|
1665 { |
|
1666 int reg = (addr >> 3) & 0x3f; |
|
1667 |
|
1668 ret = env->itlb_tte[reg]; |
|
1669 break; |
|
1670 } |
|
1671 case 0x56: // I-MMU tag read |
|
1672 { |
|
1673 int reg = (addr >> 3) & 0x3f; |
|
1674 |
|
1675 ret = env->itlb_tag[reg]; |
|
1676 break; |
|
1677 } |
|
1678 case 0x58: // D-MMU regs |
|
1679 { |
|
1680 int reg = (addr >> 3) & 0xf; |
|
1681 |
|
1682 ret = env->dmmuregs[reg]; |
|
1683 break; |
|
1684 } |
|
1685 case 0x5d: // D-MMU data access |
|
1686 { |
|
1687 int reg = (addr >> 3) & 0x3f; |
|
1688 |
|
1689 ret = env->dtlb_tte[reg]; |
|
1690 break; |
|
1691 } |
|
1692 case 0x5e: // D-MMU tag read |
|
1693 { |
|
1694 int reg = (addr >> 3) & 0x3f; |
|
1695 |
|
1696 ret = env->dtlb_tag[reg]; |
|
1697 break; |
|
1698 } |
|
1699 case 0x46: // D-cache data |
|
1700 case 0x47: // D-cache tag access |
|
1701 case 0x4b: // E-cache error enable |
|
1702 case 0x4c: // E-cache asynchronous fault status |
|
1703 case 0x4d: // E-cache asynchronous fault address |
|
1704 case 0x4e: // E-cache tag data |
|
1705 case 0x66: // I-cache instruction access |
|
1706 case 0x67: // I-cache tag access |
|
1707 case 0x6e: // I-cache predecode |
|
1708 case 0x6f: // I-cache LRU etc. |
|
1709 case 0x76: // E-cache tag |
|
1710 case 0x7e: // E-cache tag |
|
1711 break; |
|
1712 case 0x59: // D-MMU 8k TSB pointer |
|
1713 case 0x5a: // D-MMU 64k TSB pointer |
|
1714 case 0x5b: // D-MMU data pointer |
|
1715 case 0x48: // Interrupt dispatch, RO |
|
1716 case 0x49: // Interrupt data receive |
|
1717 case 0x7f: // Incoming interrupt vector, RO |
|
1718 // XXX |
|
1719 break; |
|
1720 case 0x54: // I-MMU data in, WO |
|
1721 case 0x57: // I-MMU demap, WO |
|
1722 case 0x5c: // D-MMU data in, WO |
|
1723 case 0x5f: // D-MMU demap, WO |
|
1724 case 0x77: // Interrupt vector, WO |
|
1725 default: |
|
1726 do_unassigned_access(addr, 0, 0, 1, size); |
|
1727 ret = 0; |
|
1728 break; |
|
1729 } |
|
1730 |
|
1731 /* Convert from little endian */ |
|
1732 switch (asi) { |
|
1733 case 0x0c: // Nucleus Little Endian (LE) |
|
1734 case 0x18: // As if user primary LE |
|
1735 case 0x19: // As if user secondary LE |
|
1736 case 0x1c: // Bypass LE |
|
1737 case 0x1d: // Bypass, non-cacheable LE |
|
1738 case 0x88: // Primary LE |
|
1739 case 0x89: // Secondary LE |
|
1740 case 0x8a: // Primary no-fault LE |
|
1741 case 0x8b: // Secondary no-fault LE |
|
1742 switch(size) { |
|
1743 case 2: |
|
1744 ret = bswap16(ret); |
|
1745 break; |
|
1746 case 4: |
|
1747 ret = bswap32(ret); |
|
1748 break; |
|
1749 case 8: |
|
1750 ret = bswap64(ret); |
|
1751 break; |
|
1752 default: |
|
1753 break; |
|
1754 } |
|
1755 default: |
|
1756 break; |
|
1757 } |
|
1758 |
|
1759 /* Convert to signed number */ |
|
1760 if (sign) { |
|
1761 switch(size) { |
|
1762 case 1: |
|
1763 ret = (int8_t) ret; |
|
1764 break; |
|
1765 case 2: |
|
1766 ret = (int16_t) ret; |
|
1767 break; |
|
1768 case 4: |
|
1769 ret = (int32_t) ret; |
|
1770 break; |
|
1771 default: |
|
1772 break; |
|
1773 } |
|
1774 } |
|
1775 #ifdef DEBUG_ASI |
|
1776 dump_asi("read ", last_addr, asi, size, ret); |
|
1777 #endif |
|
1778 return ret; |
|
1779 } |
|
1780 |
|
1781 void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size) |
|
1782 { |
|
1783 #ifdef DEBUG_ASI |
|
1784 dump_asi("write", addr, asi, size, val); |
|
1785 #endif |
|
1786 if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) |
|
1787 || ((env->def->features & CPU_FEATURE_HYPV) |
|
1788 && asi >= 0x30 && asi < 0x80 |
|
1789 && !(env->hpstate & HS_PRIV))) |
|
1790 raise_exception(TT_PRIV_ACT); |
|
1791 |
|
1792 helper_check_align(addr, size - 1); |
|
1793 /* Convert to little endian */ |
|
1794 switch (asi) { |
|
1795 case 0x0c: // Nucleus Little Endian (LE) |
|
1796 case 0x18: // As if user primary LE |
|
1797 case 0x19: // As if user secondary LE |
|
1798 case 0x1c: // Bypass LE |
|
1799 case 0x1d: // Bypass, non-cacheable LE |
|
1800 case 0x88: // Primary LE |
|
1801 case 0x89: // Secondary LE |
|
1802 switch(size) { |
|
1803 case 2: |
|
1804 addr = bswap16(addr); |
|
1805 break; |
|
1806 case 4: |
|
1807 addr = bswap32(addr); |
|
1808 break; |
|
1809 case 8: |
|
1810 addr = bswap64(addr); |
|
1811 break; |
|
1812 default: |
|
1813 break; |
|
1814 } |
|
1815 default: |
|
1816 break; |
|
1817 } |
|
1818 |
|
1819 switch(asi) { |
|
1820 case 0x10: // As if user primary |
|
1821 case 0x18: // As if user primary LE |
|
1822 case 0x80: // Primary |
|
1823 case 0x88: // Primary LE |
|
1824 case 0xe2: // UA2007 Primary block init |
|
1825 case 0xe3: // UA2007 Secondary block init |
|
1826 if ((asi & 0x80) && (env->pstate & PS_PRIV)) { |
|
1827 if ((env->def->features & CPU_FEATURE_HYPV) |
|
1828 && env->hpstate & HS_PRIV) { |
|
1829 switch(size) { |
|
1830 case 1: |
|
1831 stb_hypv(addr, val); |
|
1832 break; |
|
1833 case 2: |
|
1834 stw_hypv(addr, val); |
|
1835 break; |
|
1836 case 4: |
|
1837 stl_hypv(addr, val); |
|
1838 break; |
|
1839 case 8: |
|
1840 default: |
|
1841 stq_hypv(addr, val); |
|
1842 break; |
|
1843 } |
|
1844 } else { |
|
1845 switch(size) { |
|
1846 case 1: |
|
1847 stb_kernel(addr, val); |
|
1848 break; |
|
1849 case 2: |
|
1850 stw_kernel(addr, val); |
|
1851 break; |
|
1852 case 4: |
|
1853 stl_kernel(addr, val); |
|
1854 break; |
|
1855 case 8: |
|
1856 default: |
|
1857 stq_kernel(addr, val); |
|
1858 break; |
|
1859 } |
|
1860 } |
|
1861 } else { |
|
1862 switch(size) { |
|
1863 case 1: |
|
1864 stb_user(addr, val); |
|
1865 break; |
|
1866 case 2: |
|
1867 stw_user(addr, val); |
|
1868 break; |
|
1869 case 4: |
|
1870 stl_user(addr, val); |
|
1871 break; |
|
1872 case 8: |
|
1873 default: |
|
1874 stq_user(addr, val); |
|
1875 break; |
|
1876 } |
|
1877 } |
|
1878 break; |
|
1879 case 0x14: // Bypass |
|
1880 case 0x15: // Bypass, non-cacheable |
|
1881 case 0x1c: // Bypass LE |
|
1882 case 0x1d: // Bypass, non-cacheable LE |
|
1883 { |
|
1884 switch(size) { |
|
1885 case 1: |
|
1886 stb_phys(addr, val); |
|
1887 break; |
|
1888 case 2: |
|
1889 stw_phys(addr, val); |
|
1890 break; |
|
1891 case 4: |
|
1892 stl_phys(addr, val); |
|
1893 break; |
|
1894 case 8: |
|
1895 default: |
|
1896 stq_phys(addr, val); |
|
1897 break; |
|
1898 } |
|
1899 } |
|
1900 return; |
|
1901 case 0x24: // Nucleus quad LDD 128 bit atomic |
|
1902 case 0x2c: // Nucleus quad LDD 128 bit atomic LE |
|
1903 // Only ldda allowed |
|
1904 raise_exception(TT_ILL_INSN); |
|
1905 return; |
|
1906 case 0x04: // Nucleus |
|
1907 case 0x0c: // Nucleus Little Endian (LE) |
|
1908 case 0x11: // As if user secondary |
|
1909 case 0x19: // As if user secondary LE |
|
1910 case 0x4a: // UPA config |
|
1911 case 0x81: // Secondary |
|
1912 case 0x89: // Secondary LE |
|
1913 // XXX |
|
1914 return; |
|
1915 case 0x45: // LSU |
|
1916 { |
|
1917 uint64_t oldreg; |
|
1918 |
|
1919 oldreg = env->lsu; |
|
1920 env->lsu = val & (DMMU_E | IMMU_E); |
|
1921 // Mappings generated during D/I MMU disabled mode are |
|
1922 // invalid in normal mode |
|
1923 if (oldreg != env->lsu) { |
|
1924 DPRINTF_MMU("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", |
|
1925 oldreg, env->lsu); |
|
1926 #ifdef DEBUG_MMU |
|
1927 dump_mmu(env); |
|
1928 #endif |
|
1929 tlb_flush(env, 1); |
|
1930 } |
|
1931 return; |
|
1932 } |
|
1933 case 0x50: // I-MMU regs |
|
1934 { |
|
1935 int reg = (addr >> 3) & 0xf; |
|
1936 uint64_t oldreg; |
|
1937 |
|
1938 oldreg = env->immuregs[reg]; |
|
1939 switch(reg) { |
|
1940 case 0: // RO |
|
1941 case 4: |
|
1942 return; |
|
1943 case 1: // Not in I-MMU |
|
1944 case 2: |
|
1945 case 7: |
|
1946 case 8: |
|
1947 return; |
|
1948 case 3: // SFSR |
|
1949 if ((val & 1) == 0) |
|
1950 val = 0; // Clear SFSR |
|
1951 break; |
|
1952 case 5: // TSB access |
|
1953 case 6: // Tag access |
|
1954 default: |
|
1955 break; |
|
1956 } |
|
1957 env->immuregs[reg] = val; |
|
1958 if (oldreg != env->immuregs[reg]) { |
|
1959 DPRINTF_MMU("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" |
|
1960 PRIx64 "\n", reg, oldreg, env->immuregs[reg]); |
|
1961 } |
|
1962 #ifdef DEBUG_MMU |
|
1963 dump_mmu(env); |
|
1964 #endif |
|
1965 return; |
|
1966 } |
|
1967 case 0x54: // I-MMU data in |
|
1968 { |
|
1969 unsigned int i; |
|
1970 |
|
1971 // Try finding an invalid entry |
|
1972 for (i = 0; i < 64; i++) { |
|
1973 if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0) { |
|
1974 env->itlb_tag[i] = env->immuregs[6]; |
|
1975 env->itlb_tte[i] = val; |
|
1976 return; |
|
1977 } |
|
1978 } |
|
1979 // Try finding an unlocked entry |
|
1980 for (i = 0; i < 64; i++) { |
|
1981 if ((env->itlb_tte[i] & 0x40) == 0) { |
|
1982 env->itlb_tag[i] = env->immuregs[6]; |
|
1983 env->itlb_tte[i] = val; |
|
1984 return; |
|
1985 } |
|
1986 } |
|
1987 // error state? |
|
1988 return; |
|
1989 } |
|
1990 case 0x55: // I-MMU data access |
|
1991 { |
|
1992 // TODO: auto demap |
|
1993 |
|
1994 unsigned int i = (addr >> 3) & 0x3f; |
|
1995 |
|
1996 env->itlb_tag[i] = env->immuregs[6]; |
|
1997 env->itlb_tte[i] = val; |
|
1998 return; |
|
1999 } |
|
2000 case 0x57: // I-MMU demap |
|
2001 { |
|
2002 unsigned int i; |
|
2003 |
|
2004 for (i = 0; i < 64; i++) { |
|
2005 if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) { |
|
2006 target_ulong mask = 0xffffffffffffe000ULL; |
|
2007 |
|
2008 mask <<= 3 * ((env->itlb_tte[i] >> 61) & 3); |
|
2009 if ((val & mask) == (env->itlb_tag[i] & mask)) { |
|
2010 env->itlb_tag[i] = 0; |
|
2011 env->itlb_tte[i] = 0; |
|
2012 } |
|
2013 return; |
|
2014 } |
|
2015 } |
|
2016 } |
|
2017 return; |
|
2018 case 0x58: // D-MMU regs |
|
2019 { |
|
2020 int reg = (addr >> 3) & 0xf; |
|
2021 uint64_t oldreg; |
|
2022 |
|
2023 oldreg = env->dmmuregs[reg]; |
|
2024 switch(reg) { |
|
2025 case 0: // RO |
|
2026 case 4: |
|
2027 return; |
|
2028 case 3: // SFSR |
|
2029 if ((val & 1) == 0) { |
|
2030 val = 0; // Clear SFSR, Fault address |
|
2031 env->dmmuregs[4] = 0; |
|
2032 } |
|
2033 env->dmmuregs[reg] = val; |
|
2034 break; |
|
2035 case 1: // Primary context |
|
2036 case 2: // Secondary context |
|
2037 case 5: // TSB access |
|
2038 case 6: // Tag access |
|
2039 case 7: // Virtual Watchpoint |
|
2040 case 8: // Physical Watchpoint |
|
2041 default: |
|
2042 break; |
|
2043 } |
|
2044 env->dmmuregs[reg] = val; |
|
2045 if (oldreg != env->dmmuregs[reg]) { |
|
2046 DPRINTF_MMU("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" |
|
2047 PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]); |
|
2048 } |
|
2049 #ifdef DEBUG_MMU |
|
2050 dump_mmu(env); |
|
2051 #endif |
|
2052 return; |
|
2053 } |
|
2054 case 0x5c: // D-MMU data in |
|
2055 { |
|
2056 unsigned int i; |
|
2057 |
|
2058 // Try finding an invalid entry |
|
2059 for (i = 0; i < 64; i++) { |
|
2060 if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0) { |
|
2061 env->dtlb_tag[i] = env->dmmuregs[6]; |
|
2062 env->dtlb_tte[i] = val; |
|
2063 return; |
|
2064 } |
|
2065 } |
|
2066 // Try finding an unlocked entry |
|
2067 for (i = 0; i < 64; i++) { |
|
2068 if ((env->dtlb_tte[i] & 0x40) == 0) { |
|
2069 env->dtlb_tag[i] = env->dmmuregs[6]; |
|
2070 env->dtlb_tte[i] = val; |
|
2071 return; |
|
2072 } |
|
2073 } |
|
2074 // error state? |
|
2075 return; |
|
2076 } |
|
2077 case 0x5d: // D-MMU data access |
|
2078 { |
|
2079 unsigned int i = (addr >> 3) & 0x3f; |
|
2080 |
|
2081 env->dtlb_tag[i] = env->dmmuregs[6]; |
|
2082 env->dtlb_tte[i] = val; |
|
2083 return; |
|
2084 } |
|
2085 case 0x5f: // D-MMU demap |
|
2086 { |
|
2087 unsigned int i; |
|
2088 |
|
2089 for (i = 0; i < 64; i++) { |
|
2090 if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) { |
|
2091 target_ulong mask = 0xffffffffffffe000ULL; |
|
2092 |
|
2093 mask <<= 3 * ((env->dtlb_tte[i] >> 61) & 3); |
|
2094 if ((val & mask) == (env->dtlb_tag[i] & mask)) { |
|
2095 env->dtlb_tag[i] = 0; |
|
2096 env->dtlb_tte[i] = 0; |
|
2097 } |
|
2098 return; |
|
2099 } |
|
2100 } |
|
2101 } |
|
2102 return; |
|
2103 case 0x49: // Interrupt data receive |
|
2104 // XXX |
|
2105 return; |
|
2106 case 0x46: // D-cache data |
|
2107 case 0x47: // D-cache tag access |
|
2108 case 0x4b: // E-cache error enable |
|
2109 case 0x4c: // E-cache asynchronous fault status |
|
2110 case 0x4d: // E-cache asynchronous fault address |
|
2111 case 0x4e: // E-cache tag data |
|
2112 case 0x66: // I-cache instruction access |
|
2113 case 0x67: // I-cache tag access |
|
2114 case 0x6e: // I-cache predecode |
|
2115 case 0x6f: // I-cache LRU etc. |
|
2116 case 0x76: // E-cache tag |
|
2117 case 0x7e: // E-cache tag |
|
2118 return; |
|
2119 case 0x51: // I-MMU 8k TSB pointer, RO |
|
2120 case 0x52: // I-MMU 64k TSB pointer, RO |
|
2121 case 0x56: // I-MMU tag read, RO |
|
2122 case 0x59: // D-MMU 8k TSB pointer, RO |
|
2123 case 0x5a: // D-MMU 64k TSB pointer, RO |
|
2124 case 0x5b: // D-MMU data pointer, RO |
|
2125 case 0x5e: // D-MMU tag read, RO |
|
2126 case 0x48: // Interrupt dispatch, RO |
|
2127 case 0x7f: // Incoming interrupt vector, RO |
|
2128 case 0x82: // Primary no-fault, RO |
|
2129 case 0x83: // Secondary no-fault, RO |
|
2130 case 0x8a: // Primary no-fault LE, RO |
|
2131 case 0x8b: // Secondary no-fault LE, RO |
|
2132 default: |
|
2133 do_unassigned_access(addr, 1, 0, 1, size); |
|
2134 return; |
|
2135 } |
|
2136 } |
|
2137 #endif /* CONFIG_USER_ONLY */ |
|
2138 |
|
2139 void helper_ldda_asi(target_ulong addr, int asi, int rd) |
|
2140 { |
|
2141 if ((asi < 0x80 && (env->pstate & PS_PRIV) == 0) |
|
2142 || ((env->def->features & CPU_FEATURE_HYPV) |
|
2143 && asi >= 0x30 && asi < 0x80 |
|
2144 && !(env->hpstate & HS_PRIV))) |
|
2145 raise_exception(TT_PRIV_ACT); |
|
2146 |
|
2147 switch (asi) { |
|
2148 case 0x24: // Nucleus quad LDD 128 bit atomic |
|
2149 case 0x2c: // Nucleus quad LDD 128 bit atomic LE |
|
2150 helper_check_align(addr, 0xf); |
|
2151 if (rd == 0) { |
|
2152 env->gregs[1] = ldq_kernel(addr + 8); |
|
2153 if (asi == 0x2c) |
|
2154 bswap64s(&env->gregs[1]); |
|
2155 } else if (rd < 8) { |
|
2156 env->gregs[rd] = ldq_kernel(addr); |
|
2157 env->gregs[rd + 1] = ldq_kernel(addr + 8); |
|
2158 if (asi == 0x2c) { |
|
2159 bswap64s(&env->gregs[rd]); |
|
2160 bswap64s(&env->gregs[rd + 1]); |
|
2161 } |
|
2162 } else { |
|
2163 env->regwptr[rd] = ldq_kernel(addr); |
|
2164 env->regwptr[rd + 1] = ldq_kernel(addr + 8); |
|
2165 if (asi == 0x2c) { |
|
2166 bswap64s(&env->regwptr[rd]); |
|
2167 bswap64s(&env->regwptr[rd + 1]); |
|
2168 } |
|
2169 } |
|
2170 break; |
|
2171 default: |
|
2172 helper_check_align(addr, 0x3); |
|
2173 if (rd == 0) |
|
2174 env->gregs[1] = helper_ld_asi(addr + 4, asi, 4, 0); |
|
2175 else if (rd < 8) { |
|
2176 env->gregs[rd] = helper_ld_asi(addr, asi, 4, 0); |
|
2177 env->gregs[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0); |
|
2178 } else { |
|
2179 env->regwptr[rd] = helper_ld_asi(addr, asi, 4, 0); |
|
2180 env->regwptr[rd + 1] = helper_ld_asi(addr + 4, asi, 4, 0); |
|
2181 } |
|
2182 break; |
|
2183 } |
|
2184 } |
|
2185 |
|
2186 void helper_ldf_asi(target_ulong addr, int asi, int size, int rd) |
|
2187 { |
|
2188 unsigned int i; |
|
2189 target_ulong val; |
|
2190 |
|
2191 helper_check_align(addr, 3); |
|
2192 switch (asi) { |
|
2193 case 0xf0: // Block load primary |
|
2194 case 0xf1: // Block load secondary |
|
2195 case 0xf8: // Block load primary LE |
|
2196 case 0xf9: // Block load secondary LE |
|
2197 if (rd & 7) { |
|
2198 raise_exception(TT_ILL_INSN); |
|
2199 return; |
|
2200 } |
|
2201 helper_check_align(addr, 0x3f); |
|
2202 for (i = 0; i < 16; i++) { |
|
2203 *(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x8f, 4, |
|
2204 0); |
|
2205 addr += 4; |
|
2206 } |
|
2207 |
|
2208 return; |
|
2209 default: |
|
2210 break; |
|
2211 } |
|
2212 |
|
2213 val = helper_ld_asi(addr, asi, size, 0); |
|
2214 switch(size) { |
|
2215 default: |
|
2216 case 4: |
|
2217 *((uint32_t *)&env->fpr[rd]) = val; |
|
2218 break; |
|
2219 case 8: |
|
2220 *((int64_t *)&DT0) = val; |
|
2221 break; |
|
2222 case 16: |
|
2223 // XXX |
|
2224 break; |
|
2225 } |
|
2226 } |
|
2227 |
|
2228 void helper_stf_asi(target_ulong addr, int asi, int size, int rd) |
|
2229 { |
|
2230 unsigned int i; |
|
2231 target_ulong val = 0; |
|
2232 |
|
2233 helper_check_align(addr, 3); |
|
2234 switch (asi) { |
|
2235 case 0xe0: // UA2007 Block commit store primary (cache flush) |
|
2236 case 0xe1: // UA2007 Block commit store secondary (cache flush) |
|
2237 case 0xf0: // Block store primary |
|
2238 case 0xf1: // Block store secondary |
|
2239 case 0xf8: // Block store primary LE |
|
2240 case 0xf9: // Block store secondary LE |
|
2241 if (rd & 7) { |
|
2242 raise_exception(TT_ILL_INSN); |
|
2243 return; |
|
2244 } |
|
2245 helper_check_align(addr, 0x3f); |
|
2246 for (i = 0; i < 16; i++) { |
|
2247 val = *(uint32_t *)&env->fpr[rd++]; |
|
2248 helper_st_asi(addr, val, asi & 0x8f, 4); |
|
2249 addr += 4; |
|
2250 } |
|
2251 |
|
2252 return; |
|
2253 default: |
|
2254 break; |
|
2255 } |
|
2256 |
|
2257 switch(size) { |
|
2258 default: |
|
2259 case 4: |
|
2260 val = *((uint32_t *)&env->fpr[rd]); |
|
2261 break; |
|
2262 case 8: |
|
2263 val = *((int64_t *)&DT0); |
|
2264 break; |
|
2265 case 16: |
|
2266 // XXX |
|
2267 break; |
|
2268 } |
|
2269 helper_st_asi(addr, val, asi, size); |
|
2270 } |
|
2271 |
|
2272 target_ulong helper_cas_asi(target_ulong addr, target_ulong val1, |
|
2273 target_ulong val2, uint32_t asi) |
|
2274 { |
|
2275 target_ulong ret; |
|
2276 |
|
2277 val2 &= 0xffffffffUL; |
|
2278 ret = helper_ld_asi(addr, asi, 4, 0); |
|
2279 ret &= 0xffffffffUL; |
|
2280 if (val2 == ret) |
|
2281 helper_st_asi(addr, val1 & 0xffffffffUL, asi, 4); |
|
2282 return ret; |
|
2283 } |
|
2284 |
|
2285 target_ulong helper_casx_asi(target_ulong addr, target_ulong val1, |
|
2286 target_ulong val2, uint32_t asi) |
|
2287 { |
|
2288 target_ulong ret; |
|
2289 |
|
2290 ret = helper_ld_asi(addr, asi, 8, 0); |
|
2291 if (val2 == ret) |
|
2292 helper_st_asi(addr, val1, asi, 8); |
|
2293 return ret; |
|
2294 } |
|
2295 #endif /* TARGET_SPARC64 */ |
|
2296 |
|
2297 #ifndef TARGET_SPARC64 |
|
2298 void helper_rett(void) |
|
2299 { |
|
2300 unsigned int cwp; |
|
2301 |
|
2302 if (env->psret == 1) |
|
2303 raise_exception(TT_ILL_INSN); |
|
2304 |
|
2305 env->psret = 1; |
|
2306 cwp = cpu_cwp_inc(env, env->cwp + 1) ; |
|
2307 if (env->wim & (1 << cwp)) { |
|
2308 raise_exception(TT_WIN_UNF); |
|
2309 } |
|
2310 set_cwp(cwp); |
|
2311 env->psrs = env->psrps; |
|
2312 } |
|
2313 #endif |
|
2314 |
|
2315 target_ulong helper_udiv(target_ulong a, target_ulong b) |
|
2316 { |
|
2317 uint64_t x0; |
|
2318 uint32_t x1; |
|
2319 |
|
2320 x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32); |
|
2321 x1 = b; |
|
2322 |
|
2323 if (x1 == 0) { |
|
2324 raise_exception(TT_DIV_ZERO); |
|
2325 } |
|
2326 |
|
2327 x0 = x0 / x1; |
|
2328 if (x0 > 0xffffffff) { |
|
2329 env->cc_src2 = 1; |
|
2330 return 0xffffffff; |
|
2331 } else { |
|
2332 env->cc_src2 = 0; |
|
2333 return x0; |
|
2334 } |
|
2335 } |
|
2336 |
|
2337 target_ulong helper_sdiv(target_ulong a, target_ulong b) |
|
2338 { |
|
2339 int64_t x0; |
|
2340 int32_t x1; |
|
2341 |
|
2342 x0 = (a & 0xffffffff) | ((int64_t) (env->y) << 32); |
|
2343 x1 = b; |
|
2344 |
|
2345 if (x1 == 0) { |
|
2346 raise_exception(TT_DIV_ZERO); |
|
2347 } |
|
2348 |
|
2349 x0 = x0 / x1; |
|
2350 if ((int32_t) x0 != x0) { |
|
2351 env->cc_src2 = 1; |
|
2352 return x0 < 0? 0x80000000: 0x7fffffff; |
|
2353 } else { |
|
2354 env->cc_src2 = 0; |
|
2355 return x0; |
|
2356 } |
|
2357 } |
|
2358 |
|
2359 void helper_stdf(target_ulong addr, int mem_idx) |
|
2360 { |
|
2361 helper_check_align(addr, 7); |
|
2362 #if !defined(CONFIG_USER_ONLY) |
|
2363 switch (mem_idx) { |
|
2364 case 0: |
|
2365 stfq_user(addr, DT0); |
|
2366 break; |
|
2367 case 1: |
|
2368 stfq_kernel(addr, DT0); |
|
2369 break; |
|
2370 #ifdef TARGET_SPARC64 |
|
2371 case 2: |
|
2372 stfq_hypv(addr, DT0); |
|
2373 break; |
|
2374 #endif |
|
2375 default: |
|
2376 break; |
|
2377 } |
|
2378 #else |
|
2379 address_mask(env, &addr); |
|
2380 stfq_raw(addr, DT0); |
|
2381 #endif |
|
2382 } |
|
2383 |
|
2384 void helper_lddf(target_ulong addr, int mem_idx) |
|
2385 { |
|
2386 helper_check_align(addr, 7); |
|
2387 #if !defined(CONFIG_USER_ONLY) |
|
2388 switch (mem_idx) { |
|
2389 case 0: |
|
2390 DT0 = ldfq_user(addr); |
|
2391 break; |
|
2392 case 1: |
|
2393 DT0 = ldfq_kernel(addr); |
|
2394 break; |
|
2395 #ifdef TARGET_SPARC64 |
|
2396 case 2: |
|
2397 DT0 = ldfq_hypv(addr); |
|
2398 break; |
|
2399 #endif |
|
2400 default: |
|
2401 break; |
|
2402 } |
|
2403 #else |
|
2404 address_mask(env, &addr); |
|
2405 DT0 = ldfq_raw(addr); |
|
2406 #endif |
|
2407 } |
|
2408 |
|
2409 void helper_ldqf(target_ulong addr, int mem_idx) |
|
2410 { |
|
2411 // XXX add 128 bit load |
|
2412 CPU_QuadU u; |
|
2413 |
|
2414 helper_check_align(addr, 7); |
|
2415 #if !defined(CONFIG_USER_ONLY) |
|
2416 switch (mem_idx) { |
|
2417 case 0: |
|
2418 u.ll.upper = ldq_user(addr); |
|
2419 u.ll.lower = ldq_user(addr + 8); |
|
2420 QT0 = u.q; |
|
2421 break; |
|
2422 case 1: |
|
2423 u.ll.upper = ldq_kernel(addr); |
|
2424 u.ll.lower = ldq_kernel(addr + 8); |
|
2425 QT0 = u.q; |
|
2426 break; |
|
2427 #ifdef TARGET_SPARC64 |
|
2428 case 2: |
|
2429 u.ll.upper = ldq_hypv(addr); |
|
2430 u.ll.lower = ldq_hypv(addr + 8); |
|
2431 QT0 = u.q; |
|
2432 break; |
|
2433 #endif |
|
2434 default: |
|
2435 break; |
|
2436 } |
|
2437 #else |
|
2438 address_mask(env, &addr); |
|
2439 u.ll.upper = ldq_raw(addr); |
|
2440 u.ll.lower = ldq_raw((addr + 8) & 0xffffffffULL); |
|
2441 QT0 = u.q; |
|
2442 #endif |
|
2443 } |
|
2444 |
|
2445 void helper_stqf(target_ulong addr, int mem_idx) |
|
2446 { |
|
2447 // XXX add 128 bit store |
|
2448 CPU_QuadU u; |
|
2449 |
|
2450 helper_check_align(addr, 7); |
|
2451 #if !defined(CONFIG_USER_ONLY) |
|
2452 switch (mem_idx) { |
|
2453 case 0: |
|
2454 u.q = QT0; |
|
2455 stq_user(addr, u.ll.upper); |
|
2456 stq_user(addr + 8, u.ll.lower); |
|
2457 break; |
|
2458 case 1: |
|
2459 u.q = QT0; |
|
2460 stq_kernel(addr, u.ll.upper); |
|
2461 stq_kernel(addr + 8, u.ll.lower); |
|
2462 break; |
|
2463 #ifdef TARGET_SPARC64 |
|
2464 case 2: |
|
2465 u.q = QT0; |
|
2466 stq_hypv(addr, u.ll.upper); |
|
2467 stq_hypv(addr + 8, u.ll.lower); |
|
2468 break; |
|
2469 #endif |
|
2470 default: |
|
2471 break; |
|
2472 } |
|
2473 #else |
|
2474 u.q = QT0; |
|
2475 address_mask(env, &addr); |
|
2476 stq_raw(addr, u.ll.upper); |
|
2477 stq_raw((addr + 8) & 0xffffffffULL, u.ll.lower); |
|
2478 #endif |
|
2479 } |
|
2480 |
|
2481 static inline void set_fsr(void) |
|
2482 { |
|
2483 int rnd_mode; |
|
2484 |
|
2485 switch (env->fsr & FSR_RD_MASK) { |
|
2486 case FSR_RD_NEAREST: |
|
2487 rnd_mode = float_round_nearest_even; |
|
2488 break; |
|
2489 default: |
|
2490 case FSR_RD_ZERO: |
|
2491 rnd_mode = float_round_to_zero; |
|
2492 break; |
|
2493 case FSR_RD_POS: |
|
2494 rnd_mode = float_round_up; |
|
2495 break; |
|
2496 case FSR_RD_NEG: |
|
2497 rnd_mode = float_round_down; |
|
2498 break; |
|
2499 } |
|
2500 set_float_rounding_mode(rnd_mode, &env->fp_status); |
|
2501 } |
|
2502 |
|
2503 void helper_ldfsr(uint32_t new_fsr) |
|
2504 { |
|
2505 env->fsr = (new_fsr & FSR_LDFSR_MASK) | (env->fsr & FSR_LDFSR_OLDMASK); |
|
2506 set_fsr(); |
|
2507 } |
|
2508 |
|
2509 #ifdef TARGET_SPARC64 |
|
2510 void helper_ldxfsr(uint64_t new_fsr) |
|
2511 { |
|
2512 env->fsr = (new_fsr & FSR_LDXFSR_MASK) | (env->fsr & FSR_LDXFSR_OLDMASK); |
|
2513 set_fsr(); |
|
2514 } |
|
2515 #endif |
|
2516 |
|
2517 void helper_debug(void) |
|
2518 { |
|
2519 env->exception_index = EXCP_DEBUG; |
|
2520 cpu_loop_exit(); |
|
2521 } |
|
2522 |
|
2523 #ifndef TARGET_SPARC64 |
|
2524 /* XXX: use another pointer for %iN registers to avoid slow wrapping |
|
2525 handling ? */ |
|
2526 void helper_save(void) |
|
2527 { |
|
2528 uint32_t cwp; |
|
2529 |
|
2530 cwp = cpu_cwp_dec(env, env->cwp - 1); |
|
2531 if (env->wim & (1 << cwp)) { |
|
2532 raise_exception(TT_WIN_OVF); |
|
2533 } |
|
2534 set_cwp(cwp); |
|
2535 } |
|
2536 |
|
2537 void helper_restore(void) |
|
2538 { |
|
2539 uint32_t cwp; |
|
2540 |
|
2541 cwp = cpu_cwp_inc(env, env->cwp + 1); |
|
2542 if (env->wim & (1 << cwp)) { |
|
2543 raise_exception(TT_WIN_UNF); |
|
2544 } |
|
2545 set_cwp(cwp); |
|
2546 } |
|
2547 |
|
2548 void helper_wrpsr(target_ulong new_psr) |
|
2549 { |
|
2550 if ((new_psr & PSR_CWP) >= env->nwindows) |
|
2551 raise_exception(TT_ILL_INSN); |
|
2552 else |
|
2553 PUT_PSR(env, new_psr); |
|
2554 } |
|
2555 |
|
2556 target_ulong helper_rdpsr(void) |
|
2557 { |
|
2558 return GET_PSR(env); |
|
2559 } |
|
2560 |
|
2561 #else |
|
2562 /* XXX: use another pointer for %iN registers to avoid slow wrapping |
|
2563 handling ? */ |
|
2564 void helper_save(void) |
|
2565 { |
|
2566 uint32_t cwp; |
|
2567 |
|
2568 cwp = cpu_cwp_dec(env, env->cwp - 1); |
|
2569 if (env->cansave == 0) { |
|
2570 raise_exception(TT_SPILL | (env->otherwin != 0 ? |
|
2571 (TT_WOTHER | ((env->wstate & 0x38) >> 1)): |
|
2572 ((env->wstate & 0x7) << 2))); |
|
2573 } else { |
|
2574 if (env->cleanwin - env->canrestore == 0) { |
|
2575 // XXX Clean windows without trap |
|
2576 raise_exception(TT_CLRWIN); |
|
2577 } else { |
|
2578 env->cansave--; |
|
2579 env->canrestore++; |
|
2580 set_cwp(cwp); |
|
2581 } |
|
2582 } |
|
2583 } |
|
2584 |
|
2585 void helper_restore(void) |
|
2586 { |
|
2587 uint32_t cwp; |
|
2588 |
|
2589 cwp = cpu_cwp_inc(env, env->cwp + 1); |
|
2590 if (env->canrestore == 0) { |
|
2591 raise_exception(TT_FILL | (env->otherwin != 0 ? |
|
2592 (TT_WOTHER | ((env->wstate & 0x38) >> 1)): |
|
2593 ((env->wstate & 0x7) << 2))); |
|
2594 } else { |
|
2595 env->cansave++; |
|
2596 env->canrestore--; |
|
2597 set_cwp(cwp); |
|
2598 } |
|
2599 } |
|
2600 |
|
2601 void helper_flushw(void) |
|
2602 { |
|
2603 if (env->cansave != env->nwindows - 2) { |
|
2604 raise_exception(TT_SPILL | (env->otherwin != 0 ? |
|
2605 (TT_WOTHER | ((env->wstate & 0x38) >> 1)): |
|
2606 ((env->wstate & 0x7) << 2))); |
|
2607 } |
|
2608 } |
|
2609 |
|
2610 void helper_saved(void) |
|
2611 { |
|
2612 env->cansave++; |
|
2613 if (env->otherwin == 0) |
|
2614 env->canrestore--; |
|
2615 else |
|
2616 env->otherwin--; |
|
2617 } |
|
2618 |
|
2619 void helper_restored(void) |
|
2620 { |
|
2621 env->canrestore++; |
|
2622 if (env->cleanwin < env->nwindows - 1) |
|
2623 env->cleanwin++; |
|
2624 if (env->otherwin == 0) |
|
2625 env->cansave--; |
|
2626 else |
|
2627 env->otherwin--; |
|
2628 } |
|
2629 |
|
2630 target_ulong helper_rdccr(void) |
|
2631 { |
|
2632 return GET_CCR(env); |
|
2633 } |
|
2634 |
|
2635 void helper_wrccr(target_ulong new_ccr) |
|
2636 { |
|
2637 PUT_CCR(env, new_ccr); |
|
2638 } |
|
2639 |
|
2640 // CWP handling is reversed in V9, but we still use the V8 register |
|
2641 // order. |
|
2642 target_ulong helper_rdcwp(void) |
|
2643 { |
|
2644 return GET_CWP64(env); |
|
2645 } |
|
2646 |
|
2647 void helper_wrcwp(target_ulong new_cwp) |
|
2648 { |
|
2649 PUT_CWP64(env, new_cwp); |
|
2650 } |
|
2651 |
|
2652 // This function uses non-native bit order |
|
2653 #define GET_FIELD(X, FROM, TO) \ |
|
2654 ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1)) |
|
2655 |
|
2656 // This function uses the order in the manuals, i.e. bit 0 is 2^0 |
|
2657 #define GET_FIELD_SP(X, FROM, TO) \ |
|
2658 GET_FIELD(X, 63 - (TO), 63 - (FROM)) |
|
2659 |
|
2660 target_ulong helper_array8(target_ulong pixel_addr, target_ulong cubesize) |
|
2661 { |
|
2662 return (GET_FIELD_SP(pixel_addr, 60, 63) << (17 + 2 * cubesize)) | |
|
2663 (GET_FIELD_SP(pixel_addr, 39, 39 + cubesize - 1) << (17 + cubesize)) | |
|
2664 (GET_FIELD_SP(pixel_addr, 17 + cubesize - 1, 17) << 17) | |
|
2665 (GET_FIELD_SP(pixel_addr, 56, 59) << 13) | |
|
2666 (GET_FIELD_SP(pixel_addr, 35, 38) << 9) | |
|
2667 (GET_FIELD_SP(pixel_addr, 13, 16) << 5) | |
|
2668 (((pixel_addr >> 55) & 1) << 4) | |
|
2669 (GET_FIELD_SP(pixel_addr, 33, 34) << 2) | |
|
2670 GET_FIELD_SP(pixel_addr, 11, 12); |
|
2671 } |
|
2672 |
|
2673 target_ulong helper_alignaddr(target_ulong addr, target_ulong offset) |
|
2674 { |
|
2675 uint64_t tmp; |
|
2676 |
|
2677 tmp = addr + offset; |
|
2678 env->gsr &= ~7ULL; |
|
2679 env->gsr |= tmp & 7ULL; |
|
2680 return tmp & ~7ULL; |
|
2681 } |
|
2682 |
|
2683 target_ulong helper_popc(target_ulong val) |
|
2684 { |
|
2685 return ctpop64(val); |
|
2686 } |
|
2687 |
|
2688 static inline uint64_t *get_gregset(uint64_t pstate) |
|
2689 { |
|
2690 switch (pstate) { |
|
2691 default: |
|
2692 case 0: |
|
2693 return env->bgregs; |
|
2694 case PS_AG: |
|
2695 return env->agregs; |
|
2696 case PS_MG: |
|
2697 return env->mgregs; |
|
2698 case PS_IG: |
|
2699 return env->igregs; |
|
2700 } |
|
2701 } |
|
2702 |
|
2703 static inline void change_pstate(uint64_t new_pstate) |
|
2704 { |
|
2705 uint64_t pstate_regs, new_pstate_regs; |
|
2706 uint64_t *src, *dst; |
|
2707 |
|
2708 pstate_regs = env->pstate & 0xc01; |
|
2709 new_pstate_regs = new_pstate & 0xc01; |
|
2710 if (new_pstate_regs != pstate_regs) { |
|
2711 // Switch global register bank |
|
2712 src = get_gregset(new_pstate_regs); |
|
2713 dst = get_gregset(pstate_regs); |
|
2714 memcpy32(dst, env->gregs); |
|
2715 memcpy32(env->gregs, src); |
|
2716 } |
|
2717 env->pstate = new_pstate; |
|
2718 } |
|
2719 |
|
2720 void helper_wrpstate(target_ulong new_state) |
|
2721 { |
|
2722 if (!(env->def->features & CPU_FEATURE_GL)) |
|
2723 change_pstate(new_state & 0xf3f); |
|
2724 } |
|
2725 |
|
2726 void helper_done(void) |
|
2727 { |
|
2728 env->pc = env->tsptr->tpc; |
|
2729 env->npc = env->tsptr->tnpc + 4; |
|
2730 PUT_CCR(env, env->tsptr->tstate >> 32); |
|
2731 env->asi = (env->tsptr->tstate >> 24) & 0xff; |
|
2732 change_pstate((env->tsptr->tstate >> 8) & 0xf3f); |
|
2733 PUT_CWP64(env, env->tsptr->tstate & 0xff); |
|
2734 env->tl--; |
|
2735 env->tsptr = &env->ts[env->tl & MAXTL_MASK]; |
|
2736 } |
|
2737 |
|
2738 void helper_retry(void) |
|
2739 { |
|
2740 env->pc = env->tsptr->tpc; |
|
2741 env->npc = env->tsptr->tnpc; |
|
2742 PUT_CCR(env, env->tsptr->tstate >> 32); |
|
2743 env->asi = (env->tsptr->tstate >> 24) & 0xff; |
|
2744 change_pstate((env->tsptr->tstate >> 8) & 0xf3f); |
|
2745 PUT_CWP64(env, env->tsptr->tstate & 0xff); |
|
2746 env->tl--; |
|
2747 env->tsptr = &env->ts[env->tl & MAXTL_MASK]; |
|
2748 } |
|
2749 |
|
2750 void helper_set_softint(uint64_t value) |
|
2751 { |
|
2752 env->softint |= (uint32_t)value; |
|
2753 } |
|
2754 |
|
2755 void helper_clear_softint(uint64_t value) |
|
2756 { |
|
2757 env->softint &= (uint32_t)~value; |
|
2758 } |
|
2759 |
|
2760 void helper_write_softint(uint64_t value) |
|
2761 { |
|
2762 env->softint = (uint32_t)value; |
|
2763 } |
|
2764 #endif |
|
2765 |
|
2766 void helper_flush(target_ulong addr) |
|
2767 { |
|
2768 addr &= ~7; |
|
2769 tb_invalidate_page_range(addr, addr + 8); |
|
2770 } |
|
2771 |
|
2772 #ifdef TARGET_SPARC64 |
|
2773 #ifdef DEBUG_PCALL |
|
2774 static const char * const excp_names[0x80] = { |
|
2775 [TT_TFAULT] = "Instruction Access Fault", |
|
2776 [TT_TMISS] = "Instruction Access MMU Miss", |
|
2777 [TT_CODE_ACCESS] = "Instruction Access Error", |
|
2778 [TT_ILL_INSN] = "Illegal Instruction", |
|
2779 [TT_PRIV_INSN] = "Privileged Instruction", |
|
2780 [TT_NFPU_INSN] = "FPU Disabled", |
|
2781 [TT_FP_EXCP] = "FPU Exception", |
|
2782 [TT_TOVF] = "Tag Overflow", |
|
2783 [TT_CLRWIN] = "Clean Windows", |
|
2784 [TT_DIV_ZERO] = "Division By Zero", |
|
2785 [TT_DFAULT] = "Data Access Fault", |
|
2786 [TT_DMISS] = "Data Access MMU Miss", |
|
2787 [TT_DATA_ACCESS] = "Data Access Error", |
|
2788 [TT_DPROT] = "Data Protection Error", |
|
2789 [TT_UNALIGNED] = "Unaligned Memory Access", |
|
2790 [TT_PRIV_ACT] = "Privileged Action", |
|
2791 [TT_EXTINT | 0x1] = "External Interrupt 1", |
|
2792 [TT_EXTINT | 0x2] = "External Interrupt 2", |
|
2793 [TT_EXTINT | 0x3] = "External Interrupt 3", |
|
2794 [TT_EXTINT | 0x4] = "External Interrupt 4", |
|
2795 [TT_EXTINT | 0x5] = "External Interrupt 5", |
|
2796 [TT_EXTINT | 0x6] = "External Interrupt 6", |
|
2797 [TT_EXTINT | 0x7] = "External Interrupt 7", |
|
2798 [TT_EXTINT | 0x8] = "External Interrupt 8", |
|
2799 [TT_EXTINT | 0x9] = "External Interrupt 9", |
|
2800 [TT_EXTINT | 0xa] = "External Interrupt 10", |
|
2801 [TT_EXTINT | 0xb] = "External Interrupt 11", |
|
2802 [TT_EXTINT | 0xc] = "External Interrupt 12", |
|
2803 [TT_EXTINT | 0xd] = "External Interrupt 13", |
|
2804 [TT_EXTINT | 0xe] = "External Interrupt 14", |
|
2805 [TT_EXTINT | 0xf] = "External Interrupt 15", |
|
2806 }; |
|
2807 #endif |
|
2808 |
|
2809 void do_interrupt(CPUState *env) |
|
2810 { |
|
2811 int intno = env->exception_index; |
|
2812 |
|
2813 #ifdef DEBUG_PCALL |
|
2814 if (loglevel & CPU_LOG_INT) { |
|
2815 static int count; |
|
2816 const char *name; |
|
2817 |
|
2818 if (intno < 0 || intno >= 0x180) |
|
2819 name = "Unknown"; |
|
2820 else if (intno >= 0x100) |
|
2821 name = "Trap Instruction"; |
|
2822 else if (intno >= 0xc0) |
|
2823 name = "Window Fill"; |
|
2824 else if (intno >= 0x80) |
|
2825 name = "Window Spill"; |
|
2826 else { |
|
2827 name = excp_names[intno]; |
|
2828 if (!name) |
|
2829 name = "Unknown"; |
|
2830 } |
|
2831 |
|
2832 fprintf(logfile, "%6d: %s (v=%04x) pc=%016" PRIx64 " npc=%016" PRIx64 |
|
2833 " SP=%016" PRIx64 "\n", |
|
2834 count, name, intno, |
|
2835 env->pc, |
|
2836 env->npc, env->regwptr[6]); |
|
2837 cpu_dump_state(env, logfile, fprintf, 0); |
|
2838 #if 0 |
|
2839 { |
|
2840 int i; |
|
2841 uint8_t *ptr; |
|
2842 |
|
2843 fprintf(logfile, " code="); |
|
2844 ptr = (uint8_t *)env->pc; |
|
2845 for(i = 0; i < 16; i++) { |
|
2846 fprintf(logfile, " %02x", ldub(ptr + i)); |
|
2847 } |
|
2848 fprintf(logfile, "\n"); |
|
2849 } |
|
2850 #endif |
|
2851 count++; |
|
2852 } |
|
2853 #endif |
|
2854 #if !defined(CONFIG_USER_ONLY) |
|
2855 if (env->tl >= env->maxtl) { |
|
2856 cpu_abort(env, "Trap 0x%04x while trap level (%d) >= MAXTL (%d)," |
|
2857 " Error state", env->exception_index, env->tl, env->maxtl); |
|
2858 return; |
|
2859 } |
|
2860 #endif |
|
2861 if (env->tl < env->maxtl - 1) { |
|
2862 env->tl++; |
|
2863 } else { |
|
2864 env->pstate |= PS_RED; |
|
2865 if (env->tl < env->maxtl) |
|
2866 env->tl++; |
|
2867 } |
|
2868 env->tsptr = &env->ts[env->tl & MAXTL_MASK]; |
|
2869 env->tsptr->tstate = ((uint64_t)GET_CCR(env) << 32) | |
|
2870 ((env->asi & 0xff) << 24) | ((env->pstate & 0xf3f) << 8) | |
|
2871 GET_CWP64(env); |
|
2872 env->tsptr->tpc = env->pc; |
|
2873 env->tsptr->tnpc = env->npc; |
|
2874 env->tsptr->tt = intno; |
|
2875 if (!(env->def->features & CPU_FEATURE_GL)) { |
|
2876 switch (intno) { |
|
2877 case TT_IVEC: |
|
2878 change_pstate(PS_PEF | PS_PRIV | PS_IG); |
|
2879 break; |
|
2880 case TT_TFAULT: |
|
2881 case TT_TMISS: |
|
2882 case TT_DFAULT: |
|
2883 case TT_DMISS: |
|
2884 case TT_DPROT: |
|
2885 change_pstate(PS_PEF | PS_PRIV | PS_MG); |
|
2886 break; |
|
2887 default: |
|
2888 change_pstate(PS_PEF | PS_PRIV | PS_AG); |
|
2889 break; |
|
2890 } |
|
2891 } |
|
2892 if (intno == TT_CLRWIN) |
|
2893 cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - 1)); |
|
2894 else if ((intno & 0x1c0) == TT_SPILL) |
|
2895 cpu_set_cwp(env, cpu_cwp_dec(env, env->cwp - env->cansave - 2)); |
|
2896 else if ((intno & 0x1c0) == TT_FILL) |
|
2897 cpu_set_cwp(env, cpu_cwp_inc(env, env->cwp + 1)); |
|
2898 env->tbr &= ~0x7fffULL; |
|
2899 env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5); |
|
2900 env->pc = env->tbr; |
|
2901 env->npc = env->pc + 4; |
|
2902 env->exception_index = 0; |
|
2903 } |
|
2904 #else |
|
2905 #ifdef DEBUG_PCALL |
|
2906 static const char * const excp_names[0x80] = { |
|
2907 [TT_TFAULT] = "Instruction Access Fault", |
|
2908 [TT_ILL_INSN] = "Illegal Instruction", |
|
2909 [TT_PRIV_INSN] = "Privileged Instruction", |
|
2910 [TT_NFPU_INSN] = "FPU Disabled", |
|
2911 [TT_WIN_OVF] = "Window Overflow", |
|
2912 [TT_WIN_UNF] = "Window Underflow", |
|
2913 [TT_UNALIGNED] = "Unaligned Memory Access", |
|
2914 [TT_FP_EXCP] = "FPU Exception", |
|
2915 [TT_DFAULT] = "Data Access Fault", |
|
2916 [TT_TOVF] = "Tag Overflow", |
|
2917 [TT_EXTINT | 0x1] = "External Interrupt 1", |
|
2918 [TT_EXTINT | 0x2] = "External Interrupt 2", |
|
2919 [TT_EXTINT | 0x3] = "External Interrupt 3", |
|
2920 [TT_EXTINT | 0x4] = "External Interrupt 4", |
|
2921 [TT_EXTINT | 0x5] = "External Interrupt 5", |
|
2922 [TT_EXTINT | 0x6] = "External Interrupt 6", |
|
2923 [TT_EXTINT | 0x7] = "External Interrupt 7", |
|
2924 [TT_EXTINT | 0x8] = "External Interrupt 8", |
|
2925 [TT_EXTINT | 0x9] = "External Interrupt 9", |
|
2926 [TT_EXTINT | 0xa] = "External Interrupt 10", |
|
2927 [TT_EXTINT | 0xb] = "External Interrupt 11", |
|
2928 [TT_EXTINT | 0xc] = "External Interrupt 12", |
|
2929 [TT_EXTINT | 0xd] = "External Interrupt 13", |
|
2930 [TT_EXTINT | 0xe] = "External Interrupt 14", |
|
2931 [TT_EXTINT | 0xf] = "External Interrupt 15", |
|
2932 [TT_TOVF] = "Tag Overflow", |
|
2933 [TT_CODE_ACCESS] = "Instruction Access Error", |
|
2934 [TT_DATA_ACCESS] = "Data Access Error", |
|
2935 [TT_DIV_ZERO] = "Division By Zero", |
|
2936 [TT_NCP_INSN] = "Coprocessor Disabled", |
|
2937 }; |
|
2938 #endif |
|
2939 |
|
2940 void do_interrupt(CPUState *env) |
|
2941 { |
|
2942 int cwp, intno = env->exception_index; |
|
2943 |
|
2944 #ifdef DEBUG_PCALL |
|
2945 if (loglevel & CPU_LOG_INT) { |
|
2946 static int count; |
|
2947 const char *name; |
|
2948 |
|
2949 if (intno < 0 || intno >= 0x100) |
|
2950 name = "Unknown"; |
|
2951 else if (intno >= 0x80) |
|
2952 name = "Trap Instruction"; |
|
2953 else { |
|
2954 name = excp_names[intno]; |
|
2955 if (!name) |
|
2956 name = "Unknown"; |
|
2957 } |
|
2958 |
|
2959 fprintf(logfile, "%6d: %s (v=%02x) pc=%08x npc=%08x SP=%08x\n", |
|
2960 count, name, intno, |
|
2961 env->pc, |
|
2962 env->npc, env->regwptr[6]); |
|
2963 cpu_dump_state(env, logfile, fprintf, 0); |
|
2964 #if 0 |
|
2965 { |
|
2966 int i; |
|
2967 uint8_t *ptr; |
|
2968 |
|
2969 fprintf(logfile, " code="); |
|
2970 ptr = (uint8_t *)env->pc; |
|
2971 for(i = 0; i < 16; i++) { |
|
2972 fprintf(logfile, " %02x", ldub(ptr + i)); |
|
2973 } |
|
2974 fprintf(logfile, "\n"); |
|
2975 } |
|
2976 #endif |
|
2977 count++; |
|
2978 } |
|
2979 #endif |
|
2980 #if !defined(CONFIG_USER_ONLY) |
|
2981 if (env->psret == 0) { |
|
2982 cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state", |
|
2983 env->exception_index); |
|
2984 return; |
|
2985 } |
|
2986 #endif |
|
2987 env->psret = 0; |
|
2988 cwp = cpu_cwp_dec(env, env->cwp - 1); |
|
2989 cpu_set_cwp(env, cwp); |
|
2990 env->regwptr[9] = env->pc; |
|
2991 env->regwptr[10] = env->npc; |
|
2992 env->psrps = env->psrs; |
|
2993 env->psrs = 1; |
|
2994 env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4); |
|
2995 env->pc = env->tbr; |
|
2996 env->npc = env->pc + 4; |
|
2997 env->exception_index = 0; |
|
2998 } |
|
2999 #endif |
|
3000 |
|
3001 #if !defined(CONFIG_USER_ONLY) |
|
3002 |
|
3003 static void do_unaligned_access(target_ulong addr, int is_write, int is_user, |
|
3004 void *retaddr); |
|
3005 |
|
3006 #define MMUSUFFIX _mmu |
|
3007 #define ALIGNED_ONLY |
|
3008 |
|
3009 #define SHIFT 0 |
|
3010 #include "softmmu_template.h" |
|
3011 |
|
3012 #define SHIFT 1 |
|
3013 #include "softmmu_template.h" |
|
3014 |
|
3015 #define SHIFT 2 |
|
3016 #include "softmmu_template.h" |
|
3017 |
|
3018 #define SHIFT 3 |
|
3019 #include "softmmu_template.h" |
|
3020 |
|
3021 /* XXX: make it generic ? */ |
|
3022 static void cpu_restore_state2(void *retaddr) |
|
3023 { |
|
3024 TranslationBlock *tb; |
|
3025 unsigned long pc; |
|
3026 |
|
3027 if (retaddr) { |
|
3028 /* now we have a real cpu fault */ |
|
3029 pc = (unsigned long)retaddr; |
|
3030 tb = tb_find_pc(pc); |
|
3031 if (tb) { |
|
3032 /* the PC is inside the translated code. It means that we have |
|
3033 a virtual CPU fault */ |
|
3034 cpu_restore_state(tb, env, pc, (void *)(long)env->cond); |
|
3035 } |
|
3036 } |
|
3037 } |
|
3038 |
|
3039 static void do_unaligned_access(target_ulong addr, int is_write, int is_user, |
|
3040 void *retaddr) |
|
3041 { |
|
3042 #ifdef DEBUG_UNALIGNED |
|
3043 printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx |
|
3044 "\n", addr, env->pc); |
|
3045 #endif |
|
3046 cpu_restore_state2(retaddr); |
|
3047 raise_exception(TT_UNALIGNED); |
|
3048 } |
|
3049 |
|
3050 /* try to fill the TLB and return an exception if error. If retaddr is |
|
3051 NULL, it means that the function was called in C code (i.e. not |
|
3052 from generated code or from helper.c) */ |
|
3053 /* XXX: fix it to restore all registers */ |
|
3054 void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) |
|
3055 { |
|
3056 int ret; |
|
3057 CPUState *saved_env; |
|
3058 |
|
3059 /* XXX: hack to restore env in all cases, even if not called from |
|
3060 generated code */ |
|
3061 saved_env = env; |
|
3062 env = cpu_single_env; |
|
3063 |
|
3064 ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); |
|
3065 if (ret) { |
|
3066 cpu_restore_state2(retaddr); |
|
3067 cpu_loop_exit(); |
|
3068 } |
|
3069 env = saved_env; |
|
3070 } |
|
3071 |
|
3072 #endif |
|
3073 |
|
3074 #ifndef TARGET_SPARC64 |
|
3075 void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, |
|
3076 int is_asi, int size) |
|
3077 { |
|
3078 CPUState *saved_env; |
|
3079 |
|
3080 /* XXX: hack to restore env in all cases, even if not called from |
|
3081 generated code */ |
|
3082 saved_env = env; |
|
3083 env = cpu_single_env; |
|
3084 #ifdef DEBUG_UNASSIGNED |
|
3085 if (is_asi) |
|
3086 printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx |
|
3087 " asi 0x%02x from " TARGET_FMT_lx "\n", |
|
3088 is_exec ? "exec" : is_write ? "write" : "read", size, |
|
3089 size == 1 ? "" : "s", addr, is_asi, env->pc); |
|
3090 else |
|
3091 printf("Unassigned mem %s access of %d byte%s to " TARGET_FMT_plx |
|
3092 " from " TARGET_FMT_lx "\n", |
|
3093 is_exec ? "exec" : is_write ? "write" : "read", size, |
|
3094 size == 1 ? "" : "s", addr, env->pc); |
|
3095 #endif |
|
3096 if (env->mmuregs[3]) /* Fault status register */ |
|
3097 env->mmuregs[3] = 1; /* overflow (not read before another fault) */ |
|
3098 if (is_asi) |
|
3099 env->mmuregs[3] |= 1 << 16; |
|
3100 if (env->psrs) |
|
3101 env->mmuregs[3] |= 1 << 5; |
|
3102 if (is_exec) |
|
3103 env->mmuregs[3] |= 1 << 6; |
|
3104 if (is_write) |
|
3105 env->mmuregs[3] |= 1 << 7; |
|
3106 env->mmuregs[3] |= (5 << 2) | 2; |
|
3107 env->mmuregs[4] = addr; /* Fault address register */ |
|
3108 if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) { |
|
3109 if (is_exec) |
|
3110 raise_exception(TT_CODE_ACCESS); |
|
3111 else |
|
3112 raise_exception(TT_DATA_ACCESS); |
|
3113 } |
|
3114 env = saved_env; |
|
3115 } |
|
3116 #else |
|
3117 void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, |
|
3118 int is_asi, int size) |
|
3119 { |
|
3120 #ifdef DEBUG_UNASSIGNED |
|
3121 CPUState *saved_env; |
|
3122 |
|
3123 /* XXX: hack to restore env in all cases, even if not called from |
|
3124 generated code */ |
|
3125 saved_env = env; |
|
3126 env = cpu_single_env; |
|
3127 printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx |
|
3128 "\n", addr, env->pc); |
|
3129 env = saved_env; |
|
3130 #endif |
|
3131 if (is_exec) |
|
3132 raise_exception(TT_CODE_ACCESS); |
|
3133 else |
|
3134 raise_exception(TT_DATA_ACCESS); |
|
3135 } |
|
3136 #endif |
|
3137 |
|
3138 #ifdef TARGET_SPARC64 |
|
3139 void helper_tick_set_count(void *opaque, uint64_t count) |
|
3140 { |
|
3141 #if !defined(CONFIG_USER_ONLY) |
|
3142 cpu_tick_set_count(opaque, count); |
|
3143 #endif |
|
3144 } |
|
3145 |
|
3146 uint64_t helper_tick_get_count(void *opaque) |
|
3147 { |
|
3148 #if !defined(CONFIG_USER_ONLY) |
|
3149 return cpu_tick_get_count(opaque); |
|
3150 #else |
|
3151 return 0; |
|
3152 #endif |
|
3153 } |
|
3154 |
|
3155 void helper_tick_set_limit(void *opaque, uint64_t limit) |
|
3156 { |
|
3157 #if !defined(CONFIG_USER_ONLY) |
|
3158 cpu_tick_set_limit(opaque, limit); |
|
3159 #endif |
|
3160 } |
|
3161 #endif |