]>
Commit | Line | Data |
---|---|---|
e8af50a3 FB |
1 | #include "exec.h" |
2 | ||
e80cfcfc FB |
3 | //#define DEBUG_MMU |
4 | ||
9d893301 FB |
5 | void raise_exception(int tt) |
6 | { | |
7 | env->exception_index = tt; | |
8 | cpu_loop_exit(); | |
9 | } | |
10 | ||
a0c4cb4a FB |
11 | #ifdef USE_INT_TO_FLOAT_HELPERS |
12 | void do_fitos(void) | |
13 | { | |
14 | FT0 = (float) *((int32_t *)&FT1); | |
15 | } | |
16 | ||
17 | void do_fitod(void) | |
18 | { | |
19 | DT0 = (double) *((int32_t *)&FT1); | |
20 | } | |
21 | #endif | |
22 | ||
23 | void do_fabss(void) | |
e8af50a3 | 24 | { |
7a0e1f41 | 25 | FT0 = float32_abs(FT1); |
e8af50a3 FB |
26 | } |
27 | ||
3475187d FB |
28 | #ifdef TARGET_SPARC64 |
29 | void do_fabsd(void) | |
30 | { | |
31 | DT0 = float64_abs(DT1); | |
32 | } | |
33 | #endif | |
34 | ||
a0c4cb4a | 35 | void do_fsqrts(void) |
e8af50a3 | 36 | { |
7a0e1f41 | 37 | FT0 = float32_sqrt(FT1, &env->fp_status); |
e8af50a3 FB |
38 | } |
39 | ||
a0c4cb4a | 40 | void do_fsqrtd(void) |
e8af50a3 | 41 | { |
7a0e1f41 | 42 | DT0 = float64_sqrt(DT1, &env->fp_status); |
e8af50a3 FB |
43 | } |
44 | ||
3475187d | 45 | #define FS 0 |
a0c4cb4a | 46 | void do_fcmps (void) |
e8af50a3 | 47 | { |
3475187d | 48 | env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); |
e8af50a3 | 49 | if (isnan(FT0) || isnan(FT1)) { |
3475187d | 50 | T0 = (FSR_FCC1 | FSR_FCC0) << FS; |
e80cfcfc | 51 | if (env->fsr & FSR_NVM) { |
3475187d | 52 | env->fsr |= T0; |
e80cfcfc FB |
53 | raise_exception(TT_FP_EXCP); |
54 | } else { | |
55 | env->fsr |= FSR_NVA; | |
56 | } | |
e8af50a3 | 57 | } else if (FT0 < FT1) { |
3475187d | 58 | T0 = FSR_FCC0 << FS; |
e8af50a3 | 59 | } else if (FT0 > FT1) { |
3475187d | 60 | T0 = FSR_FCC1 << FS; |
e8af50a3 FB |
61 | } else { |
62 | T0 = 0; | |
63 | } | |
3475187d | 64 | env->fsr |= T0; |
e8af50a3 FB |
65 | } |
66 | ||
a0c4cb4a | 67 | void do_fcmpd (void) |
e8af50a3 | 68 | { |
3475187d FB |
69 | env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); |
70 | if (isnan(DT0) || isnan(DT1)) { | |
71 | T0 = (FSR_FCC1 | FSR_FCC0) << FS; | |
72 | if (env->fsr & FSR_NVM) { | |
73 | env->fsr |= T0; | |
74 | raise_exception(TT_FP_EXCP); | |
75 | } else { | |
76 | env->fsr |= FSR_NVA; | |
77 | } | |
78 | } else if (DT0 < DT1) { | |
79 | T0 = FSR_FCC0 << FS; | |
80 | } else if (DT0 > DT1) { | |
81 | T0 = FSR_FCC1 << FS; | |
82 | } else { | |
83 | T0 = 0; | |
84 | } | |
85 | env->fsr |= T0; | |
86 | } | |
87 | ||
88 | #ifdef TARGET_SPARC64 | |
89 | #undef FS | |
90 | #define FS 22 | |
91 | void do_fcmps_fcc1 (void) | |
92 | { | |
93 | env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); | |
94 | if (isnan(FT0) || isnan(FT1)) { | |
95 | T0 = (FSR_FCC1 | FSR_FCC0) << FS; | |
96 | if (env->fsr & FSR_NVM) { | |
97 | env->fsr |= T0; | |
98 | raise_exception(TT_FP_EXCP); | |
99 | } else { | |
100 | env->fsr |= FSR_NVA; | |
101 | } | |
102 | } else if (FT0 < FT1) { | |
103 | T0 = FSR_FCC0 << FS; | |
104 | } else if (FT0 > FT1) { | |
105 | T0 = FSR_FCC1 << FS; | |
106 | } else { | |
107 | T0 = 0; | |
108 | } | |
109 | env->fsr |= T0; | |
110 | } | |
111 | ||
112 | void do_fcmpd_fcc1 (void) | |
113 | { | |
114 | env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); | |
115 | if (isnan(DT0) || isnan(DT1)) { | |
116 | T0 = (FSR_FCC1 | FSR_FCC0) << FS; | |
117 | if (env->fsr & FSR_NVM) { | |
118 | env->fsr |= T0; | |
119 | raise_exception(TT_FP_EXCP); | |
120 | } else { | |
121 | env->fsr |= FSR_NVA; | |
122 | } | |
123 | } else if (DT0 < DT1) { | |
124 | T0 = FSR_FCC0 << FS; | |
125 | } else if (DT0 > DT1) { | |
126 | T0 = FSR_FCC1 << FS; | |
127 | } else { | |
128 | T0 = 0; | |
129 | } | |
130 | env->fsr |= T0; | |
131 | } | |
132 | ||
133 | #undef FS | |
134 | #define FS 24 | |
135 | void do_fcmps_fcc2 (void) | |
136 | { | |
137 | env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); | |
138 | if (isnan(FT0) || isnan(FT1)) { | |
139 | T0 = (FSR_FCC1 | FSR_FCC0) << FS; | |
140 | if (env->fsr & FSR_NVM) { | |
141 | env->fsr |= T0; | |
142 | raise_exception(TT_FP_EXCP); | |
143 | } else { | |
144 | env->fsr |= FSR_NVA; | |
145 | } | |
146 | } else if (FT0 < FT1) { | |
147 | T0 = FSR_FCC0 << FS; | |
148 | } else if (FT0 > FT1) { | |
149 | T0 = FSR_FCC1 << FS; | |
150 | } else { | |
151 | T0 = 0; | |
152 | } | |
153 | env->fsr |= T0; | |
154 | } | |
155 | ||
156 | void do_fcmpd_fcc2 (void) | |
157 | { | |
158 | env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); | |
e8af50a3 | 159 | if (isnan(DT0) || isnan(DT1)) { |
3475187d | 160 | T0 = (FSR_FCC1 | FSR_FCC0) << FS; |
e80cfcfc | 161 | if (env->fsr & FSR_NVM) { |
3475187d | 162 | env->fsr |= T0; |
e80cfcfc FB |
163 | raise_exception(TT_FP_EXCP); |
164 | } else { | |
165 | env->fsr |= FSR_NVA; | |
166 | } | |
e8af50a3 | 167 | } else if (DT0 < DT1) { |
3475187d | 168 | T0 = FSR_FCC0 << FS; |
e8af50a3 | 169 | } else if (DT0 > DT1) { |
3475187d FB |
170 | T0 = FSR_FCC1 << FS; |
171 | } else { | |
172 | T0 = 0; | |
173 | } | |
174 | env->fsr |= T0; | |
175 | } | |
176 | ||
177 | #undef FS | |
178 | #define FS 26 | |
179 | void do_fcmps_fcc3 (void) | |
180 | { | |
181 | env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); | |
182 | if (isnan(FT0) || isnan(FT1)) { | |
183 | T0 = (FSR_FCC1 | FSR_FCC0) << FS; | |
184 | if (env->fsr & FSR_NVM) { | |
185 | env->fsr |= T0; | |
186 | raise_exception(TT_FP_EXCP); | |
187 | } else { | |
188 | env->fsr |= FSR_NVA; | |
189 | } | |
190 | } else if (FT0 < FT1) { | |
191 | T0 = FSR_FCC0 << FS; | |
192 | } else if (FT0 > FT1) { | |
193 | T0 = FSR_FCC1 << FS; | |
e8af50a3 FB |
194 | } else { |
195 | T0 = 0; | |
196 | } | |
3475187d | 197 | env->fsr |= T0; |
e8af50a3 FB |
198 | } |
199 | ||
3475187d FB |
200 | void do_fcmpd_fcc3 (void) |
201 | { | |
202 | env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); | |
203 | if (isnan(DT0) || isnan(DT1)) { | |
204 | T0 = (FSR_FCC1 | FSR_FCC0) << FS; | |
205 | if (env->fsr & FSR_NVM) { | |
206 | env->fsr |= T0; | |
207 | raise_exception(TT_FP_EXCP); | |
208 | } else { | |
209 | env->fsr |= FSR_NVA; | |
210 | } | |
211 | } else if (DT0 < DT1) { | |
212 | T0 = FSR_FCC0 << FS; | |
213 | } else if (DT0 > DT1) { | |
214 | T0 = FSR_FCC1 << FS; | |
215 | } else { | |
216 | T0 = 0; | |
217 | } | |
218 | env->fsr |= T0; | |
219 | } | |
220 | #undef FS | |
221 | #endif | |
222 | ||
223 | #ifndef TARGET_SPARC64 | |
a0c4cb4a | 224 | void helper_ld_asi(int asi, int size, int sign) |
e8af50a3 | 225 | { |
e80cfcfc FB |
226 | uint32_t ret; |
227 | ||
228 | switch (asi) { | |
e8af50a3 | 229 | case 3: /* MMU probe */ |
e80cfcfc FB |
230 | { |
231 | int mmulev; | |
232 | ||
233 | mmulev = (T0 >> 8) & 15; | |
234 | if (mmulev > 4) | |
235 | ret = 0; | |
236 | else { | |
ee5bbe38 | 237 | ret = mmu_probe(env, T0, mmulev); |
e80cfcfc FB |
238 | //bswap32s(&ret); |
239 | } | |
240 | #ifdef DEBUG_MMU | |
241 | printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret); | |
242 | #endif | |
243 | } | |
244 | break; | |
e8af50a3 FB |
245 | case 4: /* read MMU regs */ |
246 | { | |
e80cfcfc | 247 | int reg = (T0 >> 8) & 0xf; |
e8af50a3 | 248 | |
e80cfcfc | 249 | ret = env->mmuregs[reg]; |
55754d9e FB |
250 | if (reg == 3) /* Fault status cleared on read */ |
251 | env->mmuregs[reg] = 0; | |
252 | #ifdef DEBUG_MMU | |
253 | printf("mmu_read: reg[%d] = 0x%08x\n", reg, ret); | |
254 | #endif | |
e8af50a3 | 255 | } |
e80cfcfc | 256 | break; |
e8af50a3 | 257 | case 0x20 ... 0x2f: /* MMU passthrough */ |
e80cfcfc FB |
258 | cpu_physical_memory_read(T0, (void *) &ret, size); |
259 | if (size == 4) | |
49be8030 FB |
260 | tswap32s(&ret); |
261 | else if (size == 2) | |
262 | tswap16s((uint16_t *)&ret); | |
e80cfcfc | 263 | break; |
e8af50a3 | 264 | default: |
e80cfcfc FB |
265 | ret = 0; |
266 | break; | |
e8af50a3 | 267 | } |
e80cfcfc | 268 | T1 = ret; |
e8af50a3 FB |
269 | } |
270 | ||
a0c4cb4a | 271 | void helper_st_asi(int asi, int size, int sign) |
e8af50a3 FB |
272 | { |
273 | switch(asi) { | |
274 | case 3: /* MMU flush */ | |
e80cfcfc FB |
275 | { |
276 | int mmulev; | |
277 | ||
278 | mmulev = (T0 >> 8) & 15; | |
55754d9e FB |
279 | #ifdef DEBUG_MMU |
280 | printf("mmu flush level %d\n", mmulev); | |
281 | #endif | |
e80cfcfc FB |
282 | switch (mmulev) { |
283 | case 0: // flush page | |
55754d9e | 284 | tlb_flush_page(env, T0 & 0xfffff000); |
e80cfcfc FB |
285 | break; |
286 | case 1: // flush segment (256k) | |
287 | case 2: // flush region (16M) | |
288 | case 3: // flush context (4G) | |
289 | case 4: // flush entire | |
55754d9e | 290 | tlb_flush(env, 1); |
e80cfcfc FB |
291 | break; |
292 | default: | |
293 | break; | |
294 | } | |
55754d9e | 295 | #ifdef DEBUG_MMU |
ee5bbe38 | 296 | dump_mmu(env); |
55754d9e | 297 | #endif |
e80cfcfc FB |
298 | return; |
299 | } | |
e8af50a3 FB |
300 | case 4: /* write MMU regs */ |
301 | { | |
e80cfcfc FB |
302 | int reg = (T0 >> 8) & 0xf, oldreg; |
303 | ||
304 | oldreg = env->mmuregs[reg]; | |
55754d9e FB |
305 | switch(reg) { |
306 | case 0: | |
e8af50a3 FB |
307 | env->mmuregs[reg] &= ~(MMU_E | MMU_NF); |
308 | env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF); | |
6f7e9aec FB |
309 | // Mappings generated during no-fault mode or MMU |
310 | // disabled mode are invalid in normal mode | |
311 | if (oldreg != env->mmuregs[reg]) | |
55754d9e FB |
312 | tlb_flush(env, 1); |
313 | break; | |
314 | case 2: | |
e8af50a3 | 315 | env->mmuregs[reg] = T1; |
55754d9e FB |
316 | if (oldreg != env->mmuregs[reg]) { |
317 | /* we flush when the MMU context changes because | |
318 | QEMU has no MMU context support */ | |
319 | tlb_flush(env, 1); | |
320 | } | |
321 | break; | |
322 | case 3: | |
323 | case 4: | |
324 | break; | |
325 | default: | |
326 | env->mmuregs[reg] = T1; | |
327 | break; | |
328 | } | |
329 | #ifdef DEBUG_MMU | |
330 | if (oldreg != env->mmuregs[reg]) { | |
331 | printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->mmuregs[reg]); | |
332 | } | |
ee5bbe38 | 333 | dump_mmu(env); |
55754d9e | 334 | #endif |
e8af50a3 FB |
335 | return; |
336 | } | |
e80cfcfc FB |
337 | case 0x17: /* Block copy, sta access */ |
338 | { | |
339 | // value (T1) = src | |
340 | // address (T0) = dst | |
341 | // copy 32 bytes | |
342 | int src = T1, dst = T0; | |
343 | uint8_t temp[32]; | |
344 | ||
49be8030 | 345 | tswap32s(&src); |
e80cfcfc FB |
346 | |
347 | cpu_physical_memory_read(src, (void *) &temp, 32); | |
348 | cpu_physical_memory_write(dst, (void *) &temp, 32); | |
349 | } | |
350 | return; | |
351 | case 0x1f: /* Block fill, stda access */ | |
352 | { | |
353 | // value (T1, T2) | |
354 | // address (T0) = dst | |
355 | // fill 32 bytes | |
356 | int i, dst = T0; | |
357 | uint64_t val; | |
358 | ||
359 | val = (((uint64_t)T1) << 32) | T2; | |
49be8030 | 360 | tswap64s(&val); |
e80cfcfc FB |
361 | |
362 | for (i = 0; i < 32; i += 8, dst += 8) { | |
363 | cpu_physical_memory_write(dst, (void *) &val, 8); | |
364 | } | |
365 | } | |
366 | return; | |
e8af50a3 FB |
367 | case 0x20 ... 0x2f: /* MMU passthrough */ |
368 | { | |
369 | int temp = T1; | |
e80cfcfc | 370 | if (size == 4) |
49be8030 | 371 | tswap32s(&temp); |
e80cfcfc | 372 | else if (size == 2) |
49be8030 | 373 | tswap16s((uint16_t *)&temp); |
e8af50a3 FB |
374 | cpu_physical_memory_write(T0, (void *) &temp, size); |
375 | } | |
376 | return; | |
377 | default: | |
378 | return; | |
379 | } | |
380 | } | |
381 | ||
3475187d FB |
382 | #else |
383 | ||
384 | void helper_ld_asi(int asi, int size, int sign) | |
385 | { | |
386 | uint64_t ret; | |
387 | ||
388 | if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) | |
389 | raise_exception(TT_PRIV_INSN); | |
390 | ||
391 | switch (asi) { | |
392 | case 0x14: // Bypass | |
393 | case 0x15: // Bypass, non-cacheable | |
394 | { | |
395 | cpu_physical_memory_read(T0, (void *) &ret, size); | |
396 | if (size == 8) | |
397 | tswap64s(&ret); | |
398 | if (size == 4) | |
399 | tswap32s((uint32_t *)&ret); | |
400 | else if (size == 2) | |
401 | tswap16s((uint16_t *)&ret); | |
402 | break; | |
403 | } | |
404 | case 0x1c: // Bypass LE | |
405 | case 0x1d: // Bypass, non-cacheable LE | |
406 | // XXX | |
407 | break; | |
408 | case 0x45: // LSU | |
409 | ret = env->lsu; | |
410 | break; | |
411 | case 0x50: // I-MMU regs | |
412 | { | |
413 | int reg = (T0 >> 3) & 0xf; | |
414 | ||
415 | ret = env->immuregs[reg]; | |
416 | break; | |
417 | } | |
418 | case 0x51: // I-MMU 8k TSB pointer | |
419 | case 0x52: // I-MMU 64k TSB pointer | |
420 | case 0x55: // I-MMU data access | |
421 | case 0x56: // I-MMU tag read | |
422 | break; | |
423 | case 0x58: // D-MMU regs | |
424 | { | |
425 | int reg = (T0 >> 3) & 0xf; | |
426 | ||
427 | ret = env->dmmuregs[reg]; | |
428 | break; | |
429 | } | |
430 | case 0x59: // D-MMU 8k TSB pointer | |
431 | case 0x5a: // D-MMU 64k TSB pointer | |
432 | case 0x5b: // D-MMU data pointer | |
433 | case 0x5d: // D-MMU data access | |
434 | case 0x5e: // D-MMU tag read | |
435 | break; | |
436 | case 0x54: // I-MMU data in, WO | |
437 | case 0x57: // I-MMU demap, WO | |
438 | case 0x5c: // D-MMU data in, WO | |
439 | case 0x5f: // D-MMU demap, WO | |
440 | default: | |
441 | ret = 0; | |
442 | break; | |
443 | } | |
444 | T1 = ret; | |
445 | } | |
446 | ||
447 | void helper_st_asi(int asi, int size, int sign) | |
448 | { | |
449 | if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) | |
450 | raise_exception(TT_PRIV_INSN); | |
451 | ||
452 | switch(asi) { | |
453 | case 0x14: // Bypass | |
454 | case 0x15: // Bypass, non-cacheable | |
455 | { | |
456 | target_ulong temp = T1; | |
457 | if (size == 8) | |
458 | tswap64s(&temp); | |
459 | else if (size == 4) | |
460 | tswap32s((uint32_t *)&temp); | |
461 | else if (size == 2) | |
462 | tswap16s((uint16_t *)&temp); | |
463 | cpu_physical_memory_write(T0, (void *) &temp, size); | |
464 | } | |
465 | return; | |
466 | case 0x1c: // Bypass LE | |
467 | case 0x1d: // Bypass, non-cacheable LE | |
468 | // XXX | |
469 | return; | |
470 | case 0x45: // LSU | |
471 | { | |
472 | uint64_t oldreg; | |
473 | ||
474 | oldreg = env->lsu; | |
475 | env->lsu = T1 & (DMMU_E | IMMU_E); | |
476 | // Mappings generated during D/I MMU disabled mode are | |
477 | // invalid in normal mode | |
478 | if (oldreg != env->lsu) | |
479 | tlb_flush(env, 1); | |
480 | return; | |
481 | } | |
482 | case 0x50: // I-MMU regs | |
483 | { | |
484 | int reg = (T0 >> 3) & 0xf; | |
485 | uint64_t oldreg; | |
486 | ||
487 | oldreg = env->immuregs[reg]; | |
488 | switch(reg) { | |
489 | case 0: // RO | |
490 | case 4: | |
491 | return; | |
492 | case 1: // Not in I-MMU | |
493 | case 2: | |
494 | case 7: | |
495 | case 8: | |
496 | return; | |
497 | case 3: // SFSR | |
498 | if ((T1 & 1) == 0) | |
499 | T1 = 0; // Clear SFSR | |
500 | break; | |
501 | case 5: // TSB access | |
502 | case 6: // Tag access | |
503 | default: | |
504 | break; | |
505 | } | |
506 | env->immuregs[reg] = T1; | |
507 | #ifdef DEBUG_MMU | |
508 | if (oldreg != env->immuregs[reg]) { | |
509 | printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->immuregs[reg]); | |
510 | } | |
ee5bbe38 | 511 | dump_mmu(env); |
3475187d FB |
512 | #endif |
513 | return; | |
514 | } | |
515 | case 0x54: // I-MMU data in | |
516 | { | |
517 | unsigned int i; | |
518 | ||
519 | // Try finding an invalid entry | |
520 | for (i = 0; i < 64; i++) { | |
521 | if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0) { | |
522 | env->itlb_tag[i] = env->immuregs[6]; | |
523 | env->itlb_tte[i] = T1; | |
524 | return; | |
525 | } | |
526 | } | |
527 | // Try finding an unlocked entry | |
528 | for (i = 0; i < 64; i++) { | |
529 | if ((env->itlb_tte[i] & 0x40) == 0) { | |
530 | env->itlb_tag[i] = env->immuregs[6]; | |
531 | env->itlb_tte[i] = T1; | |
532 | return; | |
533 | } | |
534 | } | |
535 | // error state? | |
536 | return; | |
537 | } | |
538 | case 0x55: // I-MMU data access | |
539 | { | |
540 | unsigned int i = (T0 >> 3) & 0x3f; | |
541 | ||
542 | env->itlb_tag[i] = env->immuregs[6]; | |
543 | env->itlb_tte[i] = T1; | |
544 | return; | |
545 | } | |
546 | case 0x57: // I-MMU demap | |
547 | return; | |
548 | case 0x58: // D-MMU regs | |
549 | { | |
550 | int reg = (T0 >> 3) & 0xf; | |
551 | uint64_t oldreg; | |
552 | ||
553 | oldreg = env->dmmuregs[reg]; | |
554 | switch(reg) { | |
555 | case 0: // RO | |
556 | case 4: | |
557 | return; | |
558 | case 3: // SFSR | |
559 | if ((T1 & 1) == 0) { | |
560 | T1 = 0; // Clear SFSR, Fault address | |
561 | env->dmmuregs[4] = 0; | |
562 | } | |
563 | env->dmmuregs[reg] = T1; | |
564 | break; | |
565 | case 1: // Primary context | |
566 | case 2: // Secondary context | |
567 | case 5: // TSB access | |
568 | case 6: // Tag access | |
569 | case 7: // Virtual Watchpoint | |
570 | case 8: // Physical Watchpoint | |
571 | default: | |
572 | break; | |
573 | } | |
574 | env->dmmuregs[reg] = T1; | |
575 | #ifdef DEBUG_MMU | |
576 | if (oldreg != env->dmmuregs[reg]) { | |
577 | printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->dmmuregs[reg]); | |
578 | } | |
ee5bbe38 | 579 | dump_mmu(env); |
3475187d FB |
580 | #endif |
581 | return; | |
582 | } | |
583 | case 0x5c: // D-MMU data in | |
584 | { | |
585 | unsigned int i; | |
586 | ||
587 | // Try finding an invalid entry | |
588 | for (i = 0; i < 64; i++) { | |
589 | if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0) { | |
590 | env->dtlb_tag[i] = env->dmmuregs[6]; | |
591 | env->dtlb_tte[i] = T1; | |
592 | return; | |
593 | } | |
594 | } | |
595 | // Try finding an unlocked entry | |
596 | for (i = 0; i < 64; i++) { | |
597 | if ((env->dtlb_tte[i] & 0x40) == 0) { | |
598 | env->dtlb_tag[i] = env->dmmuregs[6]; | |
599 | env->dtlb_tte[i] = T1; | |
600 | return; | |
601 | } | |
602 | } | |
603 | // error state? | |
604 | return; | |
605 | } | |
606 | case 0x5d: // D-MMU data access | |
607 | { | |
608 | unsigned int i = (T0 >> 3) & 0x3f; | |
609 | ||
610 | env->dtlb_tag[i] = env->dmmuregs[6]; | |
611 | env->dtlb_tte[i] = T1; | |
612 | return; | |
613 | } | |
614 | case 0x5f: // D-MMU demap | |
615 | return; | |
616 | case 0x51: // I-MMU 8k TSB pointer, RO | |
617 | case 0x52: // I-MMU 64k TSB pointer, RO | |
618 | case 0x56: // I-MMU tag read, RO | |
619 | case 0x59: // D-MMU 8k TSB pointer, RO | |
620 | case 0x5a: // D-MMU 64k TSB pointer, RO | |
621 | case 0x5b: // D-MMU data pointer, RO | |
622 | case 0x5e: // D-MMU tag read, RO | |
623 | default: | |
624 | return; | |
625 | } | |
626 | } | |
627 | ||
628 | #endif | |
629 | ||
630 | #ifndef TARGET_SPARC64 | |
a0c4cb4a | 631 | void helper_rett() |
e8af50a3 | 632 | { |
af7bf89b FB |
633 | unsigned int cwp; |
634 | ||
e8af50a3 FB |
635 | env->psret = 1; |
636 | cwp = (env->cwp + 1) & (NWINDOWS - 1); | |
637 | if (env->wim & (1 << cwp)) { | |
638 | raise_exception(TT_WIN_UNF); | |
639 | } | |
640 | set_cwp(cwp); | |
641 | env->psrs = env->psrps; | |
642 | } | |
3475187d | 643 | #endif |
e8af50a3 | 644 | |
8d5f07fa | 645 | void helper_ldfsr(void) |
e8af50a3 | 646 | { |
7a0e1f41 | 647 | int rnd_mode; |
e8af50a3 FB |
648 | switch (env->fsr & FSR_RD_MASK) { |
649 | case FSR_RD_NEAREST: | |
7a0e1f41 | 650 | rnd_mode = float_round_nearest_even; |
e8af50a3 | 651 | break; |
ed910241 | 652 | default: |
e8af50a3 | 653 | case FSR_RD_ZERO: |
7a0e1f41 | 654 | rnd_mode = float_round_to_zero; |
e8af50a3 FB |
655 | break; |
656 | case FSR_RD_POS: | |
7a0e1f41 | 657 | rnd_mode = float_round_up; |
e8af50a3 FB |
658 | break; |
659 | case FSR_RD_NEG: | |
7a0e1f41 | 660 | rnd_mode = float_round_down; |
e8af50a3 FB |
661 | break; |
662 | } | |
7a0e1f41 | 663 | set_float_rounding_mode(rnd_mode, &env->fp_status); |
e8af50a3 | 664 | } |
e80cfcfc FB |
665 | |
666 | void cpu_get_fp64(uint64_t *pmant, uint16_t *pexp, double f) | |
667 | { | |
668 | int exptemp; | |
669 | ||
670 | *pmant = ldexp(frexp(f, &exptemp), 53); | |
671 | *pexp = exptemp; | |
672 | } | |
673 | ||
674 | double cpu_put_fp64(uint64_t mant, uint16_t exp) | |
675 | { | |
676 | return ldexp((double) mant, exp - 53); | |
677 | } | |
678 | ||
679 | void helper_debug() | |
680 | { | |
681 | env->exception_index = EXCP_DEBUG; | |
682 | cpu_loop_exit(); | |
683 | } | |
af7bf89b | 684 | |
3475187d | 685 | #ifndef TARGET_SPARC64 |
af7bf89b FB |
686 | void do_wrpsr() |
687 | { | |
688 | PUT_PSR(env, T0); | |
689 | } | |
690 | ||
691 | void do_rdpsr() | |
692 | { | |
693 | T0 = GET_PSR(env); | |
694 | } | |
3475187d FB |
695 | |
696 | #else | |
697 | ||
698 | void do_popc() | |
699 | { | |
700 | T0 = (T1 & 0x5555555555555555ULL) + ((T1 >> 1) & 0x5555555555555555ULL); | |
701 | T0 = (T0 & 0x3333333333333333ULL) + ((T0 >> 2) & 0x3333333333333333ULL); | |
702 | T0 = (T0 & 0x0f0f0f0f0f0f0f0fULL) + ((T0 >> 4) & 0x0f0f0f0f0f0f0f0fULL); | |
703 | T0 = (T0 & 0x00ff00ff00ff00ffULL) + ((T0 >> 8) & 0x00ff00ff00ff00ffULL); | |
704 | T0 = (T0 & 0x0000ffff0000ffffULL) + ((T0 >> 16) & 0x0000ffff0000ffffULL); | |
705 | T0 = (T0 & 0x00000000ffffffffULL) + ((T0 >> 32) & 0x00000000ffffffffULL); | |
706 | } | |
707 | #endif | |
ee5bbe38 FB |
708 | |
709 | void set_cwp(int new_cwp) | |
710 | { | |
711 | /* put the modified wrap registers at their proper location */ | |
712 | if (env->cwp == (NWINDOWS - 1)) | |
713 | memcpy32(env->regbase, env->regbase + NWINDOWS * 16); | |
714 | env->cwp = new_cwp; | |
715 | /* put the wrap registers at their temporary location */ | |
716 | if (new_cwp == (NWINDOWS - 1)) | |
717 | memcpy32(env->regbase + NWINDOWS * 16, env->regbase); | |
718 | env->regwptr = env->regbase + (new_cwp * 16); | |
719 | REGWPTR = env->regwptr; | |
720 | } | |
721 | ||
722 | void cpu_set_cwp(CPUState *env1, int new_cwp) | |
723 | { | |
724 | CPUState *saved_env; | |
725 | #ifdef reg_REGWPTR | |
726 | target_ulong *saved_regwptr; | |
727 | #endif | |
728 | ||
729 | saved_env = env; | |
730 | #ifdef reg_REGWPTR | |
731 | saved_regwptr = REGWPTR; | |
732 | #endif | |
733 | env = env1; | |
734 | set_cwp(new_cwp); | |
735 | env = saved_env; | |
736 | #ifdef reg_REGWPTR | |
737 | REGWPTR = saved_regwptr; | |
738 | #endif | |
739 | } | |
740 | ||
741 | #ifdef TARGET_SPARC64 | |
742 | void do_interrupt(int intno) | |
743 | { | |
744 | #ifdef DEBUG_PCALL | |
745 | if (loglevel & CPU_LOG_INT) { | |
746 | static int count; | |
747 | fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n", | |
748 | count, intno, | |
749 | env->pc, | |
750 | env->npc, env->regwptr[6]); | |
751 | cpu_dump_state(env, logfile, fprintf, 0); | |
752 | #if 0 | |
753 | { | |
754 | int i; | |
755 | uint8_t *ptr; | |
756 | ||
757 | fprintf(logfile, " code="); | |
758 | ptr = (uint8_t *)env->pc; | |
759 | for(i = 0; i < 16; i++) { | |
760 | fprintf(logfile, " %02x", ldub(ptr + i)); | |
761 | } | |
762 | fprintf(logfile, "\n"); | |
763 | } | |
764 | #endif | |
765 | count++; | |
766 | } | |
767 | #endif | |
768 | #if !defined(CONFIG_USER_ONLY) | |
769 | if (env->pstate & PS_IE) { | |
770 | cpu_abort(cpu_single_env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index); | |
771 | return; | |
772 | } | |
773 | #endif | |
774 | env->tstate[env->tl] = ((uint64_t)GET_CCR(env) << 32) | ((env->asi & 0xff) << 24) | | |
775 | ((env->pstate & 0xfff) << 8) | (env->cwp & 0xff); | |
776 | env->tpc[env->tl] = env->pc; | |
777 | env->tnpc[env->tl] = env->npc; | |
778 | env->tt[env->tl] = intno; | |
779 | env->tbr = env->tbr | (env->tl > 1) ? 1 << 14 : 0 | (intno << 4); | |
780 | env->tl++; | |
781 | env->pc = env->tbr; | |
782 | env->npc = env->pc + 4; | |
783 | env->exception_index = 0; | |
784 | } | |
785 | #else | |
786 | void do_interrupt(int intno) | |
787 | { | |
788 | int cwp; | |
789 | ||
790 | #ifdef DEBUG_PCALL | |
791 | if (loglevel & CPU_LOG_INT) { | |
792 | static int count; | |
793 | fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n", | |
794 | count, intno, | |
795 | env->pc, | |
796 | env->npc, env->regwptr[6]); | |
797 | cpu_dump_state(env, logfile, fprintf, 0); | |
798 | #if 0 | |
799 | { | |
800 | int i; | |
801 | uint8_t *ptr; | |
802 | ||
803 | fprintf(logfile, " code="); | |
804 | ptr = (uint8_t *)env->pc; | |
805 | for(i = 0; i < 16; i++) { | |
806 | fprintf(logfile, " %02x", ldub(ptr + i)); | |
807 | } | |
808 | fprintf(logfile, "\n"); | |
809 | } | |
810 | #endif | |
811 | count++; | |
812 | } | |
813 | #endif | |
814 | #if !defined(CONFIG_USER_ONLY) | |
815 | if (env->psret == 0) { | |
816 | cpu_abort(cpu_single_env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index); | |
817 | return; | |
818 | } | |
819 | #endif | |
820 | env->psret = 0; | |
821 | cwp = (env->cwp - 1) & (NWINDOWS - 1); | |
822 | set_cwp(cwp); | |
823 | env->regwptr[9] = env->pc; | |
824 | env->regwptr[10] = env->npc; | |
825 | env->psrps = env->psrs; | |
826 | env->psrs = 1; | |
827 | env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4); | |
828 | env->pc = env->tbr; | |
829 | env->npc = env->pc + 4; | |
830 | env->exception_index = 0; | |
831 | } | |
832 | #endif | |
833 | ||
834 | #if !defined(CONFIG_USER_ONLY) | |
835 | ||
836 | #define MMUSUFFIX _mmu | |
837 | #define GETPC() (__builtin_return_address(0)) | |
838 | ||
839 | #define SHIFT 0 | |
840 | #include "softmmu_template.h" | |
841 | ||
842 | #define SHIFT 1 | |
843 | #include "softmmu_template.h" | |
844 | ||
845 | #define SHIFT 2 | |
846 | #include "softmmu_template.h" | |
847 | ||
848 | #define SHIFT 3 | |
849 | #include "softmmu_template.h" | |
850 | ||
851 | ||
852 | /* try to fill the TLB and return an exception if error. If retaddr is | |
853 | NULL, it means that the function was called in C code (i.e. not | |
854 | from generated code or from helper.c) */ | |
855 | /* XXX: fix it to restore all registers */ | |
856 | void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr) | |
857 | { | |
858 | TranslationBlock *tb; | |
859 | int ret; | |
860 | unsigned long pc; | |
861 | CPUState *saved_env; | |
862 | ||
863 | /* XXX: hack to restore env in all cases, even if not called from | |
864 | generated code */ | |
865 | saved_env = env; | |
866 | env = cpu_single_env; | |
867 | ||
868 | ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, is_user, 1); | |
869 | if (ret) { | |
870 | if (retaddr) { | |
871 | /* now we have a real cpu fault */ | |
872 | pc = (unsigned long)retaddr; | |
873 | tb = tb_find_pc(pc); | |
874 | if (tb) { | |
875 | /* the PC is inside the translated code. It means that we have | |
876 | a virtual CPU fault */ | |
877 | cpu_restore_state(tb, env, pc, (void *)T2); | |
878 | } | |
879 | } | |
880 | cpu_loop_exit(); | |
881 | } | |
882 | env = saved_env; | |
883 | } | |
884 | ||
885 | #endif |