]>
Commit | Line | Data |
---|---|---|
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 |
8 | void raise_exception(int tt) |
9 | { | |
10 | env->exception_index = tt; | |
11 | cpu_loop_exit(); | |
12 | } | |
13 | ||
417454b0 BS |
14 | void 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 |
46 | void 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 | ||
53 | void do_fitod(void) | |
54 | { | |
ec230928 | 55 | DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status); |
a0c4cb4a FB |
56 | } |
57 | #endif | |
58 | ||
59 | void do_fabss(void) | |
e8af50a3 | 60 | { |
7a0e1f41 | 61 | FT0 = float32_abs(FT1); |
e8af50a3 FB |
62 | } |
63 | ||
3475187d FB |
64 | #ifdef TARGET_SPARC64 |
65 | void do_fabsd(void) | |
66 | { | |
67 | DT0 = float64_abs(DT1); | |
68 | } | |
69 | #endif | |
70 | ||
a0c4cb4a | 71 | void 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 | 78 | void 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 |
114 | GEN_FCMP(fcmps, float32, FT0, FT1, 0, 0); |
115 | GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0); | |
116 | ||
117 | GEN_FCMP(fcmpes, float32, FT0, FT1, 0, 1); | |
118 | GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1); | |
3475187d FB |
119 | |
120 | #ifdef TARGET_SPARC64 | |
417454b0 BS |
121 | GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22, 0); |
122 | GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0); | |
123 | ||
124 | GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24, 0); | |
125 | GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0); | |
126 | ||
127 | GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26, 0); | |
128 | GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0); | |
129 | ||
130 | GEN_FCMP(fcmpes_fcc1, float32, FT0, FT1, 22, 1); | |
131 | GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1); | |
3475187d | 132 | |
417454b0 BS |
133 | GEN_FCMP(fcmpes_fcc2, float32, FT0, FT1, 24, 1); |
134 | GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1); | |
3475187d | 135 | |
417454b0 BS |
136 | GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1); |
137 | GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1); | |
3475187d FB |
138 | #endif |
139 | ||
24741ef3 FB |
140 | #if defined(CONFIG_USER_ONLY) |
141 | void helper_ld_asi(int asi, int size, int sign) | |
142 | { | |
143 | } | |
144 | ||
145 | void helper_st_asi(int asi, int size, int sign) | |
146 | { | |
147 | } | |
148 | #else | |
3475187d | 149 | #ifndef TARGET_SPARC64 |
a0c4cb4a | 150 | void 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; |
e8af50a3 | 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 | 259 | void 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; | |
e80cfcfc FB |
294 | |
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; | |
e80cfcfc | 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 | ||
427 | void 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; | |
492 | ||
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; | |
513 | ||
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 | ||
546 | void 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; | |
608 | ||
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; | |
675 | ||
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 | 763 | void 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 FB |
770 | env->psret = 1; |
771 | cwp = (env->cwp + 1) & (NWINDOWS - 1); | |
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 | 780 | void 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 |
801 | void helper_debug() |
802 | { | |
803 | env->exception_index = EXCP_DEBUG; | |
804 | cpu_loop_exit(); | |
805 | } | |
af7bf89b | 806 | |
3475187d | 807 | #ifndef TARGET_SPARC64 |
af7bf89b FB |
808 | void 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 | ||
816 | void do_rdpsr() | |
817 | { | |
818 | T0 = GET_PSR(env); | |
819 | } | |
3475187d FB |
820 | |
821 | #else | |
822 | ||
823 | void 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 | |
833 | static 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 | ||
848 | void do_wrpstate() | |
849 | { | |
850 | uint64_t new_pstate, pstate_regs, new_pstate_regs; | |
851 | uint64_t *src, *dst; | |
852 | ||
853 | new_pstate = T0 & 0xf3f; | |
854 | pstate_regs = env->pstate & 0xc01; | |
855 | new_pstate_regs = new_pstate & 0xc01; | |
856 | if (new_pstate_regs != pstate_regs) { | |
857 | // Switch global register bank | |
858 | src = get_gregset(new_pstate_regs); | |
859 | dst = get_gregset(pstate_regs); | |
860 | memcpy32(dst, env->gregs); | |
861 | memcpy32(env->gregs, src); | |
862 | } | |
863 | env->pstate = new_pstate; | |
864 | } | |
865 | ||
866 | void do_done(void) | |
867 | { | |
868 | env->tl--; | |
869 | env->pc = env->tnpc[env->tl]; | |
870 | env->npc = env->tnpc[env->tl] + 4; | |
871 | PUT_CCR(env, env->tstate[env->tl] >> 32); | |
872 | env->asi = (env->tstate[env->tl] >> 24) & 0xff; | |
873 | env->pstate = (env->tstate[env->tl] >> 8) & 0xfff; | |
17d996e1 | 874 | PUT_CWP64(env, env->tstate[env->tl] & 0xff); |
83469015 FB |
875 | } |
876 | ||
877 | void do_retry(void) | |
878 | { | |
879 | env->tl--; | |
880 | env->pc = env->tpc[env->tl]; | |
881 | env->npc = env->tnpc[env->tl]; | |
882 | PUT_CCR(env, env->tstate[env->tl] >> 32); | |
883 | env->asi = (env->tstate[env->tl] >> 24) & 0xff; | |
884 | env->pstate = (env->tstate[env->tl] >> 8) & 0xfff; | |
17d996e1 | 885 | PUT_CWP64(env, env->tstate[env->tl] & 0xff); |
83469015 | 886 | } |
3475187d | 887 | #endif |
ee5bbe38 FB |
888 | |
889 | void set_cwp(int new_cwp) | |
890 | { | |
891 | /* put the modified wrap registers at their proper location */ | |
892 | if (env->cwp == (NWINDOWS - 1)) | |
893 | memcpy32(env->regbase, env->regbase + NWINDOWS * 16); | |
894 | env->cwp = new_cwp; | |
895 | /* put the wrap registers at their temporary location */ | |
896 | if (new_cwp == (NWINDOWS - 1)) | |
897 | memcpy32(env->regbase + NWINDOWS * 16, env->regbase); | |
898 | env->regwptr = env->regbase + (new_cwp * 16); | |
899 | REGWPTR = env->regwptr; | |
900 | } | |
901 | ||
902 | void cpu_set_cwp(CPUState *env1, int new_cwp) | |
903 | { | |
904 | CPUState *saved_env; | |
905 | #ifdef reg_REGWPTR | |
906 | target_ulong *saved_regwptr; | |
907 | #endif | |
908 | ||
909 | saved_env = env; | |
910 | #ifdef reg_REGWPTR | |
911 | saved_regwptr = REGWPTR; | |
912 | #endif | |
913 | env = env1; | |
914 | set_cwp(new_cwp); | |
915 | env = saved_env; | |
916 | #ifdef reg_REGWPTR | |
917 | REGWPTR = saved_regwptr; | |
918 | #endif | |
919 | } | |
920 | ||
921 | #ifdef TARGET_SPARC64 | |
922 | void do_interrupt(int intno) | |
923 | { | |
924 | #ifdef DEBUG_PCALL | |
925 | if (loglevel & CPU_LOG_INT) { | |
926 | static int count; | |
26a76461 | 927 | fprintf(logfile, "%6d: v=%04x pc=%016" PRIx64 " npc=%016" PRIx64 " SP=%016" PRIx64 "\n", |
ee5bbe38 FB |
928 | count, intno, |
929 | env->pc, | |
930 | env->npc, env->regwptr[6]); | |
931 | cpu_dump_state(env, logfile, fprintf, 0); | |
932 | #if 0 | |
933 | { | |
934 | int i; | |
935 | uint8_t *ptr; | |
936 | ||
937 | fprintf(logfile, " code="); | |
938 | ptr = (uint8_t *)env->pc; | |
939 | for(i = 0; i < 16; i++) { | |
940 | fprintf(logfile, " %02x", ldub(ptr + i)); | |
941 | } | |
942 | fprintf(logfile, "\n"); | |
943 | } | |
944 | #endif | |
945 | count++; | |
946 | } | |
947 | #endif | |
948 | #if !defined(CONFIG_USER_ONLY) | |
83469015 | 949 | if (env->tl == MAXTL) { |
c68ea704 | 950 | cpu_abort(env, "Trap 0x%04x while trap level is MAXTL, Error state", env->exception_index); |
ee5bbe38 FB |
951 | return; |
952 | } | |
953 | #endif | |
954 | env->tstate[env->tl] = ((uint64_t)GET_CCR(env) << 32) | ((env->asi & 0xff) << 24) | | |
17d996e1 | 955 | ((env->pstate & 0xfff) << 8) | GET_CWP64(env); |
ee5bbe38 FB |
956 | env->tpc[env->tl] = env->pc; |
957 | env->tnpc[env->tl] = env->npc; | |
958 | env->tt[env->tl] = intno; | |
83469015 FB |
959 | env->pstate = PS_PEF | PS_PRIV | PS_AG; |
960 | env->tbr &= ~0x7fffULL; | |
961 | env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5); | |
962 | if (env->tl < MAXTL - 1) { | |
963 | env->tl++; | |
964 | } else { | |
965 | env->pstate |= PS_RED; | |
966 | if (env->tl != MAXTL) | |
967 | env->tl++; | |
968 | } | |
ee5bbe38 FB |
969 | env->pc = env->tbr; |
970 | env->npc = env->pc + 4; | |
971 | env->exception_index = 0; | |
972 | } | |
973 | #else | |
974 | void do_interrupt(int intno) | |
975 | { | |
976 | int cwp; | |
977 | ||
978 | #ifdef DEBUG_PCALL | |
979 | if (loglevel & CPU_LOG_INT) { | |
980 | static int count; | |
981 | fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n", | |
982 | count, intno, | |
983 | env->pc, | |
984 | env->npc, env->regwptr[6]); | |
985 | cpu_dump_state(env, logfile, fprintf, 0); | |
986 | #if 0 | |
987 | { | |
988 | int i; | |
989 | uint8_t *ptr; | |
990 | ||
991 | fprintf(logfile, " code="); | |
992 | ptr = (uint8_t *)env->pc; | |
993 | for(i = 0; i < 16; i++) { | |
994 | fprintf(logfile, " %02x", ldub(ptr + i)); | |
995 | } | |
996 | fprintf(logfile, "\n"); | |
997 | } | |
998 | #endif | |
999 | count++; | |
1000 | } | |
1001 | #endif | |
1002 | #if !defined(CONFIG_USER_ONLY) | |
1003 | if (env->psret == 0) { | |
c68ea704 | 1004 | cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index); |
ee5bbe38 FB |
1005 | return; |
1006 | } | |
1007 | #endif | |
1008 | env->psret = 0; | |
1009 | cwp = (env->cwp - 1) & (NWINDOWS - 1); | |
1010 | set_cwp(cwp); | |
1011 | env->regwptr[9] = env->pc; | |
1012 | env->regwptr[10] = env->npc; | |
1013 | env->psrps = env->psrs; | |
1014 | env->psrs = 1; | |
1015 | env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4); | |
1016 | env->pc = env->tbr; | |
1017 | env->npc = env->pc + 4; | |
1018 | env->exception_index = 0; | |
1019 | } | |
1020 | #endif | |
1021 | ||
1022 | #if !defined(CONFIG_USER_ONLY) | |
1023 | ||
d2889a3e BS |
1024 | static void do_unaligned_access(target_ulong addr, int is_write, int is_user, |
1025 | void *retaddr); | |
1026 | ||
ee5bbe38 | 1027 | #define MMUSUFFIX _mmu |
d2889a3e | 1028 | #define ALIGNED_ONLY |
ee5bbe38 FB |
1029 | #define GETPC() (__builtin_return_address(0)) |
1030 | ||
1031 | #define SHIFT 0 | |
1032 | #include "softmmu_template.h" | |
1033 | ||
1034 | #define SHIFT 1 | |
1035 | #include "softmmu_template.h" | |
1036 | ||
1037 | #define SHIFT 2 | |
1038 | #include "softmmu_template.h" | |
1039 | ||
1040 | #define SHIFT 3 | |
1041 | #include "softmmu_template.h" | |
1042 | ||
d2889a3e BS |
1043 | static void do_unaligned_access(target_ulong addr, int is_write, int is_user, |
1044 | void *retaddr) | |
1045 | { | |
94554550 BS |
1046 | #ifdef DEBUG_UNALIGNED |
1047 | printf("Unaligned access to 0x%x from 0x%x\n", addr, env->pc); | |
1048 | #endif | |
1049 | raise_exception(TT_UNALIGNED); | |
d2889a3e | 1050 | } |
ee5bbe38 FB |
1051 | |
1052 | /* try to fill the TLB and return an exception if error. If retaddr is | |
1053 | NULL, it means that the function was called in C code (i.e. not | |
1054 | from generated code or from helper.c) */ | |
1055 | /* XXX: fix it to restore all registers */ | |
1056 | void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) | |
1057 | { | |
1058 | TranslationBlock *tb; | |
1059 | int ret; | |
1060 | unsigned long pc; | |
1061 | CPUState *saved_env; | |
1062 | ||
1063 | /* XXX: hack to restore env in all cases, even if not called from | |
1064 | generated code */ | |
1065 | saved_env = env; | |
1066 | env = cpu_single_env; | |
1067 | ||
1068 | ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, is_user, 1); | |
1069 | if (ret) { | |
1070 | if (retaddr) { | |
1071 | /* now we have a real cpu fault */ | |
1072 | pc = (unsigned long)retaddr; | |
1073 | tb = tb_find_pc(pc); | |
1074 | if (tb) { | |
1075 | /* the PC is inside the translated code. It means that we have | |
1076 | a virtual CPU fault */ | |
1077 | cpu_restore_state(tb, env, pc, (void *)T2); | |
1078 | } | |
1079 | } | |
1080 | cpu_loop_exit(); | |
1081 | } | |
1082 | env = saved_env; | |
1083 | } | |
1084 | ||
1085 | #endif | |
6c36d3fa BS |
1086 | |
1087 | #ifndef TARGET_SPARC64 | |
5dcb6b91 | 1088 | void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, |
6c36d3fa BS |
1089 | int is_asi) |
1090 | { | |
1091 | CPUState *saved_env; | |
1092 | ||
1093 | /* XXX: hack to restore env in all cases, even if not called from | |
1094 | generated code */ | |
1095 | saved_env = env; | |
1096 | env = cpu_single_env; | |
1097 | if (env->mmuregs[3]) /* Fault status register */ | |
1098 | env->mmuregs[3] = 1; /* overflow (not read before another fault) */ | |
1099 | if (is_asi) | |
1100 | env->mmuregs[3] |= 1 << 16; | |
1101 | if (env->psrs) | |
1102 | env->mmuregs[3] |= 1 << 5; | |
1103 | if (is_exec) | |
1104 | env->mmuregs[3] |= 1 << 6; | |
1105 | if (is_write) | |
1106 | env->mmuregs[3] |= 1 << 7; | |
1107 | env->mmuregs[3] |= (5 << 2) | 2; | |
1108 | env->mmuregs[4] = addr; /* Fault address register */ | |
1109 | if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) { | |
1110 | #ifdef DEBUG_UNASSIGNED | |
5dcb6b91 | 1111 | printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx |
6c36d3fa BS |
1112 | "\n", addr, env->pc); |
1113 | #endif | |
1b2e93c1 BS |
1114 | if (is_exec) |
1115 | raise_exception(TT_CODE_ACCESS); | |
1116 | else | |
1117 | raise_exception(TT_DATA_ACCESS); | |
6c36d3fa BS |
1118 | } |
1119 | env = saved_env; | |
1120 | } | |
1121 | #else | |
5dcb6b91 | 1122 | void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, |
6c36d3fa BS |
1123 | int is_asi) |
1124 | { | |
1125 | #ifdef DEBUG_UNASSIGNED | |
1126 | CPUState *saved_env; | |
1127 | ||
1128 | /* XXX: hack to restore env in all cases, even if not called from | |
1129 | generated code */ | |
1130 | saved_env = env; | |
1131 | env = cpu_single_env; | |
5dcb6b91 | 1132 | printf("Unassigned mem access to " TARGET_FMT_plx " from " TARGET_FMT_lx "\n", |
6c36d3fa BS |
1133 | addr, env->pc); |
1134 | env = saved_env; | |
1135 | #endif | |
1b2e93c1 BS |
1136 | if (is_exec) |
1137 | raise_exception(TT_CODE_ACCESS); | |
1138 | else | |
1139 | raise_exception(TT_DATA_ACCESS); | |
6c36d3fa BS |
1140 | } |
1141 | #endif | |
20c9f095 BS |
1142 | |
1143 | #ifdef TARGET_SPARC64 | |
1144 | void do_tick_set_count(void *opaque, uint64_t count) | |
1145 | { | |
d8bdf5fa | 1146 | #if !defined(CONFIG_USER_ONLY) |
20c9f095 | 1147 | ptimer_set_count(opaque, -count); |
d8bdf5fa | 1148 | #endif |
20c9f095 BS |
1149 | } |
1150 | ||
1151 | uint64_t do_tick_get_count(void *opaque) | |
1152 | { | |
d8bdf5fa | 1153 | #if !defined(CONFIG_USER_ONLY) |
20c9f095 | 1154 | return -ptimer_get_count(opaque); |
d8bdf5fa BS |
1155 | #else |
1156 | return 0; | |
1157 | #endif | |
20c9f095 BS |
1158 | } |
1159 | ||
1160 | void do_tick_set_limit(void *opaque, uint64_t limit) | |
1161 | { | |
d8bdf5fa | 1162 | #if !defined(CONFIG_USER_ONLY) |
20c9f095 | 1163 | ptimer_set_limit(opaque, -limit, 0); |
d8bdf5fa | 1164 | #endif |
20c9f095 BS |
1165 | } |
1166 | #endif |