Revision 0f8a249a target-sparc/op_helper.c
b/target-sparc/op_helper.c | ||
---|---|---|
16 | 16 |
T0 = get_float_exception_flags(&env->fp_status); |
17 | 17 |
if (T0) |
18 | 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 |
}
|
|
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 | 42 |
} |
43 | 43 |
} |
44 | 44 |
|
... | ... | |
155 | 155 |
case 2: /* SuperSparc MXCC registers */ |
156 | 156 |
break; |
157 | 157 |
case 3: /* MMU probe */ |
158 |
{
|
|
159 |
int mmulev;
|
|
160 |
|
|
161 |
mmulev = (T0 >> 8) & 15;
|
|
162 |
if (mmulev > 4)
|
|
163 |
ret = 0;
|
|
164 |
else {
|
|
165 |
ret = mmu_probe(env, T0, mmulev);
|
|
166 |
//bswap32s(&ret);
|
|
167 |
}
|
|
158 |
{
|
|
159 |
int mmulev;
|
|
160 |
|
|
161 |
mmulev = (T0 >> 8) & 15;
|
|
162 |
if (mmulev > 4)
|
|
163 |
ret = 0;
|
|
164 |
else {
|
|
165 |
ret = mmu_probe(env, T0, mmulev);
|
|
166 |
//bswap32s(&ret);
|
|
167 |
}
|
|
168 | 168 |
#ifdef DEBUG_MMU |
169 |
printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret);
|
|
169 |
printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret);
|
|
170 | 170 |
#endif |
171 |
}
|
|
172 |
break;
|
|
171 |
}
|
|
172 |
break;
|
|
173 | 173 |
case 4: /* read MMU regs */ |
174 |
{
|
|
175 |
int reg = (T0 >> 8) & 0xf;
|
|
174 |
{
|
|
175 |
int reg = (T0 >> 8) & 0xf;
|
|
176 | 176 |
|
177 |
ret = env->mmuregs[reg];
|
|
178 |
if (reg == 3) /* Fault status cleared on read */
|
|
179 |
env->mmuregs[reg] = 0;
|
|
177 |
ret = env->mmuregs[reg];
|
|
178 |
if (reg == 3) /* Fault status cleared on read */
|
|
179 |
env->mmuregs[reg] = 0;
|
|
180 | 180 |
#ifdef DEBUG_MMU |
181 |
printf("mmu_read: reg[%d] = 0x%08x\n", reg, ret);
|
|
181 |
printf("mmu_read: reg[%d] = 0x%08x\n", reg, ret);
|
|
182 | 182 |
#endif |
183 |
}
|
|
184 |
break;
|
|
183 |
}
|
|
184 |
break;
|
|
185 | 185 |
case 9: /* Supervisor code access */ |
186 | 186 |
switch(size) { |
187 | 187 |
case 1: |
... | ... | |
218 | 218 |
ret = ldl_phys(T0 & ~3); |
219 | 219 |
break; |
220 | 220 |
case 8: |
221 |
ret = ldl_phys(T0 & ~3);
|
|
222 |
T0 = ldl_phys((T0 + 4) & ~3);
|
|
223 |
break;
|
|
221 |
ret = ldl_phys(T0 & ~3);
|
|
222 |
T0 = ldl_phys((T0 + 4) & ~3);
|
|
223 |
break;
|
|
224 | 224 |
} |
225 |
break;
|
|
225 |
break;
|
|
226 | 226 |
case 0x2e: /* MMU passthrough, 0xexxxxxxxx */ |
227 | 227 |
case 0x2f: /* MMU passthrough, 0xfxxxxxxxx */ |
228 | 228 |
switch(size) { |
... | ... | |
244 | 244 |
| ((target_phys_addr_t)(asi & 0xf) << 32)); |
245 | 245 |
T0 = ldl_phys((target_phys_addr_t)((T0 + 4) & ~3) |
246 | 246 |
| ((target_phys_addr_t)(asi & 0xf) << 32)); |
247 |
break;
|
|
247 |
break;
|
|
248 | 248 |
} |
249 |
break;
|
|
249 |
break;
|
|
250 | 250 |
case 0x21 ... 0x2d: /* MMU passthrough, unassigned */ |
251 | 251 |
default: |
252 | 252 |
do_unassigned_access(T0, 0, 0, 1); |
253 |
ret = 0;
|
|
254 |
break;
|
|
253 |
ret = 0;
|
|
254 |
break;
|
|
255 | 255 |
} |
256 | 256 |
T1 = ret; |
257 | 257 |
} |
... | ... | |
262 | 262 |
case 2: /* SuperSparc MXCC registers */ |
263 | 263 |
break; |
264 | 264 |
case 3: /* MMU flush */ |
265 |
{
|
|
266 |
int mmulev;
|
|
265 |
{
|
|
266 |
int mmulev;
|
|
267 | 267 |
|
268 |
mmulev = (T0 >> 8) & 15;
|
|
268 |
mmulev = (T0 >> 8) & 15;
|
|
269 | 269 |
#ifdef DEBUG_MMU |
270 |
printf("mmu flush level %d\n", mmulev);
|
|
270 |
printf("mmu flush level %d\n", mmulev);
|
|
271 | 271 |
#endif |
272 |
switch (mmulev) {
|
|
273 |
case 0: // flush page
|
|
274 |
tlb_flush_page(env, T0 & 0xfffff000);
|
|
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
|
|
280 |
tlb_flush(env, 1);
|
|
281 |
break;
|
|
282 |
default:
|
|
283 |
break;
|
|
284 |
}
|
|
272 |
switch (mmulev) {
|
|
273 |
case 0: // flush page
|
|
274 |
tlb_flush_page(env, T0 & 0xfffff000);
|
|
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
|
|
280 |
tlb_flush(env, 1);
|
|
281 |
break;
|
|
282 |
default:
|
|
283 |
break;
|
|
284 |
}
|
|
285 | 285 |
#ifdef DEBUG_MMU |
286 |
dump_mmu(env);
|
|
286 |
dump_mmu(env);
|
|
287 | 287 |
#endif |
288 |
return;
|
|
289 |
}
|
|
288 |
return;
|
|
289 |
}
|
|
290 | 290 |
case 4: /* write MMU regs */ |
291 |
{
|
|
292 |
int reg = (T0 >> 8) & 0xf;
|
|
293 |
uint32_t oldreg;
|
|
291 |
{
|
|
292 |
int reg = (T0 >> 8) & 0xf;
|
|
293 |
uint32_t oldreg;
|
|
294 | 294 |
|
295 |
oldreg = env->mmuregs[reg];
|
|
295 |
oldreg = env->mmuregs[reg];
|
|
296 | 296 |
switch(reg) { |
297 | 297 |
case 0: |
298 |
env->mmuregs[reg] &= ~(MMU_E | MMU_NF);
|
|
299 |
env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF);
|
|
300 |
// Mappings generated during no-fault mode or MMU
|
|
301 |
// disabled mode are invalid in normal mode
|
|
298 |
env->mmuregs[reg] &= ~(MMU_E | MMU_NF);
|
|
299 |
env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF);
|
|
300 |
// Mappings generated during no-fault mode or MMU
|
|
301 |
// disabled mode are invalid in normal mode
|
|
302 | 302 |
if (oldreg != env->mmuregs[reg]) |
303 | 303 |
tlb_flush(env, 1); |
304 | 304 |
break; |
305 | 305 |
case 2: |
306 |
env->mmuregs[reg] = T1;
|
|
306 |
env->mmuregs[reg] = T1;
|
|
307 | 307 |
if (oldreg != env->mmuregs[reg]) { |
308 | 308 |
/* we flush when the MMU context changes because |
309 | 309 |
QEMU has no MMU context support */ |
... | ... | |
314 | 314 |
case 4: |
315 | 315 |
break; |
316 | 316 |
default: |
317 |
env->mmuregs[reg] = T1;
|
|
317 |
env->mmuregs[reg] = T1;
|
|
318 | 318 |
break; |
319 | 319 |
} |
320 | 320 |
#ifdef DEBUG_MMU |
321 | 321 |
if (oldreg != env->mmuregs[reg]) { |
322 | 322 |
printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->mmuregs[reg]); |
323 | 323 |
} |
324 |
dump_mmu(env);
|
|
324 |
dump_mmu(env);
|
|
325 | 325 |
#endif |
326 |
return;
|
|
327 |
}
|
|
326 |
return;
|
|
327 |
}
|
|
328 | 328 |
case 0xc: /* I-cache tag */ |
329 | 329 |
case 0xd: /* I-cache data */ |
330 | 330 |
case 0xe: /* D-cache tag */ |
... | ... | |
336 | 336 |
case 0x14: /* I/D-cache flush user */ |
337 | 337 |
break; |
338 | 338 |
case 0x17: /* Block copy, sta access */ |
339 |
{
|
|
340 |
// value (T1) = src
|
|
341 |
// address (T0) = dst
|
|
342 |
// copy 32 bytes
|
|
339 |
{
|
|
340 |
// value (T1) = src
|
|
341 |
// address (T0) = dst
|
|
342 |
// copy 32 bytes
|
|
343 | 343 |
unsigned int i; |
344 | 344 |
uint32_t src = T1 & ~3, dst = T0 & ~3, temp; |
345 | 345 |
|
... | ... | |
347 | 347 |
temp = ldl_kernel(src); |
348 | 348 |
stl_kernel(dst, temp); |
349 | 349 |
} |
350 |
}
|
|
351 |
return;
|
|
350 |
}
|
|
351 |
return;
|
|
352 | 352 |
case 0x1f: /* Block fill, stda access */ |
353 |
{
|
|
354 |
// value (T1, T2)
|
|
355 |
// address (T0) = dst
|
|
356 |
// fill 32 bytes
|
|
353 |
{
|
|
354 |
// value (T1, T2)
|
|
355 |
// address (T0) = dst
|
|
356 |
// fill 32 bytes
|
|
357 | 357 |
unsigned int i; |
358 | 358 |
uint32_t dst = T0 & 7; |
359 | 359 |
uint64_t val; |
... | ... | |
362 | 362 |
|
363 | 363 |
for (i = 0; i < 32; i += 8, dst += 8) |
364 | 364 |
stq_kernel(dst, val); |
365 |
}
|
|
366 |
return;
|
|
365 |
}
|
|
366 |
return;
|
|
367 | 367 |
case 0x20: /* MMU passthrough */ |
368 |
{
|
|
368 |
{
|
|
369 | 369 |
switch(size) { |
370 | 370 |
case 1: |
371 | 371 |
stb_phys(T0, T1); |
... | ... | |
382 | 382 |
stl_phys((T0 + 4) & ~3, T2); |
383 | 383 |
break; |
384 | 384 |
} |
385 |
}
|
|
386 |
return;
|
|
385 |
}
|
|
386 |
return;
|
|
387 | 387 |
case 0x2e: /* MMU passthrough, 0xexxxxxxxx */ |
388 | 388 |
case 0x2f: /* MMU passthrough, 0xfxxxxxxxx */ |
389 |
{
|
|
389 |
{
|
|
390 | 390 |
switch(size) { |
391 | 391 |
case 1: |
392 | 392 |
stb_phys((target_phys_addr_t)T0 |
... | ... | |
408 | 408 |
| ((target_phys_addr_t)(asi & 0xf) << 32), T1); |
409 | 409 |
break; |
410 | 410 |
} |
411 |
}
|
|
412 |
return;
|
|
411 |
}
|
|
412 |
return;
|
|
413 | 413 |
case 0x31: /* Ross RT620 I-cache flush */ |
414 | 414 |
case 0x36: /* I-cache flash clear */ |
415 | 415 |
case 0x37: /* D-cache flash clear */ |
... | ... | |
418 | 418 |
case 0x21 ... 0x2d: /* MMU passthrough, unassigned */ |
419 | 419 |
default: |
420 | 420 |
do_unassigned_access(T0, 1, 0, 1); |
421 |
return;
|
|
421 |
return;
|
|
422 | 422 |
} |
423 | 423 |
} |
424 | 424 |
|
... | ... | |
429 | 429 |
uint64_t ret = 0; |
430 | 430 |
|
431 | 431 |
if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) |
432 |
raise_exception(TT_PRIV_ACT);
|
|
432 |
raise_exception(TT_PRIV_ACT);
|
|
433 | 433 |
|
434 | 434 |
switch (asi) { |
435 | 435 |
case 0x14: // Bypass |
436 | 436 |
case 0x15: // Bypass, non-cacheable |
437 |
{
|
|
437 |
{
|
|
438 | 438 |
switch(size) { |
439 | 439 |
case 1: |
440 | 440 |
ret = ldub_phys(T0); |
... | ... | |
450 | 450 |
ret = ldq_phys(T0 & ~7); |
451 | 451 |
break; |
452 | 452 |
} |
453 |
break;
|
|
454 |
}
|
|
453 |
break;
|
|
454 |
}
|
|
455 | 455 |
case 0x04: // Nucleus |
456 | 456 |
case 0x0c: // Nucleus Little Endian (LE) |
457 | 457 |
case 0x10: // As if user primary |
... | ... | |
469 | 469 |
case 0x89: // Secondary LE |
470 | 470 |
case 0x8a: // Primary no-fault LE |
471 | 471 |
case 0x8b: // Secondary no-fault LE |
472 |
// XXX
|
|
473 |
break;
|
|
472 |
// XXX
|
|
473 |
break;
|
|
474 | 474 |
case 0x45: // LSU |
475 |
ret = env->lsu;
|
|
476 |
break;
|
|
475 |
ret = env->lsu;
|
|
476 |
break;
|
|
477 | 477 |
case 0x50: // I-MMU regs |
478 |
{
|
|
479 |
int reg = (T0 >> 3) & 0xf;
|
|
478 |
{
|
|
479 |
int reg = (T0 >> 3) & 0xf;
|
|
480 | 480 |
|
481 |
ret = env->immuregs[reg];
|
|
482 |
break;
|
|
483 |
}
|
|
481 |
ret = env->immuregs[reg];
|
|
482 |
break;
|
|
483 |
}
|
|
484 | 484 |
case 0x51: // I-MMU 8k TSB pointer |
485 | 485 |
case 0x52: // I-MMU 64k TSB pointer |
486 | 486 |
case 0x55: // I-MMU data access |
487 |
// XXX
|
|
488 |
break;
|
|
487 |
// XXX
|
|
488 |
break;
|
|
489 | 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 |
}
|
|
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 |
}
|
|
503 | 503 |
case 0x58: // D-MMU regs |
504 |
{
|
|
505 |
int reg = (T0 >> 3) & 0xf;
|
|
504 |
{
|
|
505 |
int reg = (T0 >> 3) & 0xf;
|
|
506 | 506 |
|
507 |
ret = env->dmmuregs[reg];
|
|
508 |
break;
|
|
509 |
}
|
|
507 |
ret = env->dmmuregs[reg];
|
|
508 |
break;
|
|
509 |
}
|
|
510 | 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 |
}
|
|
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 |
}
|
|
524 | 524 |
case 0x59: // D-MMU 8k TSB pointer |
525 | 525 |
case 0x5a: // D-MMU 64k TSB pointer |
526 | 526 |
case 0x5b: // D-MMU data pointer |
... | ... | |
528 | 528 |
case 0x48: // Interrupt dispatch, RO |
529 | 529 |
case 0x49: // Interrupt data receive |
530 | 530 |
case 0x7f: // Incoming interrupt vector, RO |
531 |
// XXX
|
|
532 |
break;
|
|
531 |
// XXX
|
|
532 |
break;
|
|
533 | 533 |
case 0x54: // I-MMU data in, WO |
534 | 534 |
case 0x57: // I-MMU demap, WO |
535 | 535 |
case 0x5c: // D-MMU data in, WO |
... | ... | |
537 | 537 |
case 0x77: // Interrupt vector, WO |
538 | 538 |
default: |
539 | 539 |
do_unassigned_access(T0, 0, 0, 1); |
540 |
ret = 0;
|
|
541 |
break;
|
|
540 |
ret = 0;
|
|
541 |
break;
|
|
542 | 542 |
} |
543 | 543 |
T1 = ret; |
544 | 544 |
} |
... | ... | |
546 | 546 |
void helper_st_asi(int asi, int size, int sign) |
547 | 547 |
{ |
548 | 548 |
if (asi < 0x80 && (env->pstate & PS_PRIV) == 0) |
549 |
raise_exception(TT_PRIV_ACT);
|
|
549 |
raise_exception(TT_PRIV_ACT);
|
|
550 | 550 |
|
551 | 551 |
switch(asi) { |
552 | 552 |
case 0x14: // Bypass |
553 | 553 |
case 0x15: // Bypass, non-cacheable |
554 |
{
|
|
554 |
{
|
|
555 | 555 |
switch(size) { |
556 | 556 |
case 1: |
557 | 557 |
stb_phys(T0, T1); |
... | ... | |
567 | 567 |
stq_phys(T0 & ~7, T1); |
568 | 568 |
break; |
569 | 569 |
} |
570 |
}
|
|
571 |
return;
|
|
570 |
}
|
|
571 |
return;
|
|
572 | 572 |
case 0x04: // Nucleus |
573 | 573 |
case 0x0c: // Nucleus Little Endian (LE) |
574 | 574 |
case 0x10: // As if user primary |
... | ... | |
582 | 582 |
case 0x4a: // UPA config |
583 | 583 |
case 0x88: // Primary LE |
584 | 584 |
case 0x89: // Secondary LE |
585 |
// XXX
|
|
586 |
return;
|
|
585 |
// XXX
|
|
586 |
return;
|
|
587 | 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
|
|
595 |
if (oldreg != env->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
|
|
595 |
if (oldreg != env->lsu) {
|
|
596 | 596 |
#ifdef DEBUG_MMU |
597 | 597 |
printf("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", oldreg, env->lsu); |
598 |
dump_mmu(env);
|
|
598 |
dump_mmu(env);
|
|
599 | 599 |
#endif |
600 |
tlb_flush(env, 1);
|
|
601 |
}
|
|
602 |
return;
|
|
603 |
}
|
|
600 |
tlb_flush(env, 1);
|
|
601 |
}
|
|
602 |
return;
|
|
603 |
}
|
|
604 | 604 |
case 0x50: // I-MMU regs |
605 |
{
|
|
606 |
int reg = (T0 >> 3) & 0xf;
|
|
607 |
uint64_t oldreg;
|
|
605 |
{
|
|
606 |
int reg = (T0 >> 3) & 0xf;
|
|
607 |
uint64_t oldreg;
|
|
608 | 608 |
|
609 |
oldreg = env->immuregs[reg];
|
|
609 |
oldreg = env->immuregs[reg];
|
|
610 | 610 |
switch(reg) { |
611 | 611 |
case 0: // RO |
612 | 612 |
case 4: |
... | ... | |
617 | 617 |
case 8: |
618 | 618 |
return; |
619 | 619 |
case 3: // SFSR |
620 |
if ((T1 & 1) == 0)
|
|
621 |
T1 = 0; // Clear SFSR
|
|
620 |
if ((T1 & 1) == 0)
|
|
621 |
T1 = 0; // Clear SFSR
|
|
622 | 622 |
break; |
623 | 623 |
case 5: // TSB access |
624 | 624 |
case 6: // Tag access |
625 | 625 |
default: |
626 | 626 |
break; |
627 | 627 |
} |
628 |
env->immuregs[reg] = T1;
|
|
628 |
env->immuregs[reg] = T1;
|
|
629 | 629 |
#ifdef DEBUG_MMU |
630 | 630 |
if (oldreg != env->immuregs[reg]) { |
631 | 631 |
printf("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->immuregs[reg]); |
632 | 632 |
} |
633 |
dump_mmu(env);
|
|
633 |
dump_mmu(env);
|
|
634 | 634 |
#endif |
635 |
return;
|
|
636 |
}
|
|
635 |
return;
|
|
636 |
}
|
|
637 | 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 |
}
|
|
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 | 660 |
case 0x55: // I-MMU data access |
661 |
{
|
|
662 |
unsigned int i = (T0 >> 3) & 0x3f;
|
|
661 |
{
|
|
662 |
unsigned int i = (T0 >> 3) & 0x3f;
|
|
663 | 663 |
|
664 |
env->itlb_tag[i] = env->immuregs[6];
|
|
665 |
env->itlb_tte[i] = T1;
|
|
666 |
return;
|
|
667 |
}
|
|
664 |
env->itlb_tag[i] = env->immuregs[6];
|
|
665 |
env->itlb_tte[i] = T1;
|
|
666 |
return;
|
|
667 |
}
|
|
668 | 668 |
case 0x57: // I-MMU demap |
669 |
// XXX
|
|
670 |
return;
|
|
669 |
// XXX
|
|
670 |
return;
|
|
671 | 671 |
case 0x58: // D-MMU regs |
672 |
{
|
|
673 |
int reg = (T0 >> 3) & 0xf;
|
|
674 |
uint64_t oldreg;
|
|
672 |
{
|
|
673 |
int reg = (T0 >> 3) & 0xf;
|
|
674 |
uint64_t oldreg;
|
|
675 | 675 |
|
676 |
oldreg = env->dmmuregs[reg];
|
|
676 |
oldreg = env->dmmuregs[reg];
|
|
677 | 677 |
switch(reg) { |
678 | 678 |
case 0: // RO |
679 | 679 |
case 4: |
680 | 680 |
return; |
681 | 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;
|
|
682 |
if ((T1 & 1) == 0) {
|
|
683 |
T1 = 0; // Clear SFSR, Fault address
|
|
684 |
env->dmmuregs[4] = 0;
|
|
685 |
}
|
|
686 |
env->dmmuregs[reg] = T1;
|
|
687 | 687 |
break; |
688 | 688 |
case 1: // Primary context |
689 | 689 |
case 2: // Secondary context |
... | ... | |
694 | 694 |
default: |
695 | 695 |
break; |
696 | 696 |
} |
697 |
env->dmmuregs[reg] = T1;
|
|
697 |
env->dmmuregs[reg] = T1;
|
|
698 | 698 |
#ifdef DEBUG_MMU |
699 | 699 |
if (oldreg != env->dmmuregs[reg]) { |
700 | 700 |
printf("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]); |
701 | 701 |
} |
702 |
dump_mmu(env);
|
|
702 |
dump_mmu(env);
|
|
703 | 703 |
#endif |
704 |
return;
|
|
705 |
}
|
|
704 |
return;
|
|
705 |
}
|
|
706 | 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 |
}
|
|
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 | 729 |
case 0x5d: // D-MMU data access |
730 |
{
|
|
731 |
unsigned int i = (T0 >> 3) & 0x3f;
|
|
730 |
{
|
|
731 |
unsigned int i = (T0 >> 3) & 0x3f;
|
|
732 | 732 |
|
733 |
env->dtlb_tag[i] = env->dmmuregs[6];
|
|
734 |
env->dtlb_tte[i] = T1;
|
|
735 |
return;
|
|
736 |
}
|
|
733 |
env->dtlb_tag[i] = env->dmmuregs[6];
|
|
734 |
env->dtlb_tte[i] = T1;
|
|
735 |
return;
|
|
736 |
}
|
|
737 | 737 |
case 0x5f: // D-MMU demap |
738 | 738 |
case 0x49: // Interrupt data receive |
739 |
// XXX
|
|
740 |
return;
|
|
739 |
// XXX
|
|
740 |
return;
|
|
741 | 741 |
case 0x51: // I-MMU 8k TSB pointer, RO |
742 | 742 |
case 0x52: // I-MMU 64k TSB pointer, RO |
743 | 743 |
case 0x56: // I-MMU tag read, RO |
... | ... | |
753 | 753 |
case 0x8b: // Secondary no-fault LE, RO |
754 | 754 |
default: |
755 | 755 |
do_unassigned_access(T0, 1, 0, 1); |
756 |
return;
|
|
756 |
return;
|
|
757 | 757 |
} |
758 | 758 |
} |
759 | 759 |
#endif |
... | ... | |
783 | 783 |
switch (env->fsr & FSR_RD_MASK) { |
784 | 784 |
case FSR_RD_NEAREST: |
785 | 785 |
rnd_mode = float_round_nearest_even; |
786 |
break;
|
|
786 |
break;
|
|
787 | 787 |
default: |
788 | 788 |
case FSR_RD_ZERO: |
789 | 789 |
rnd_mode = float_round_to_zero; |
790 |
break;
|
|
790 |
break;
|
|
791 | 791 |
case FSR_RD_POS: |
792 | 792 |
rnd_mode = float_round_up; |
793 |
break;
|
|
793 |
break;
|
|
794 | 794 |
case FSR_RD_NEG: |
795 | 795 |
rnd_mode = float_round_down; |
796 |
break;
|
|
796 |
break;
|
|
797 | 797 |
} |
798 | 798 |
set_float_rounding_mode(rnd_mode, &env->fp_status); |
799 | 799 |
} |
... | ... | |
835 | 835 |
switch (pstate) { |
836 | 836 |
default: |
837 | 837 |
case 0: |
838 |
return env->bgregs;
|
|
838 |
return env->bgregs;
|
|
839 | 839 |
case PS_AG: |
840 |
return env->agregs;
|
|
840 |
return env->agregs;
|
|
841 | 841 |
case PS_MG: |
842 |
return env->mgregs;
|
|
842 |
return env->mgregs;
|
|
843 | 843 |
case PS_IG: |
844 |
return env->igregs;
|
|
844 |
return env->igregs;
|
|
845 | 845 |
} |
846 | 846 |
} |
847 | 847 |
|
... | ... | |
853 | 853 |
pstate_regs = env->pstate & 0xc01; |
854 | 854 |
new_pstate_regs = new_pstate & 0xc01; |
855 | 855 |
if (new_pstate_regs != pstate_regs) { |
856 |
// Switch global register bank
|
|
857 |
src = get_gregset(new_pstate_regs);
|
|
858 |
dst = get_gregset(pstate_regs);
|
|
859 |
memcpy32(dst, env->gregs);
|
|
860 |
memcpy32(env->gregs, src);
|
|
856 |
// Switch global register bank
|
|
857 |
src = get_gregset(new_pstate_regs);
|
|
858 |
dst = get_gregset(pstate_regs);
|
|
859 |
memcpy32(dst, env->gregs);
|
|
860 |
memcpy32(env->gregs, src);
|
|
861 | 861 |
} |
862 | 862 |
env->pstate = new_pstate; |
863 | 863 |
} |
... | ... | |
927 | 927 |
{ |
928 | 928 |
#ifdef DEBUG_PCALL |
929 | 929 |
if (loglevel & CPU_LOG_INT) { |
930 |
static int count;
|
|
931 |
fprintf(logfile, "%6d: v=%04x pc=%016" PRIx64 " npc=%016" PRIx64 " SP=%016" PRIx64 "\n",
|
|
930 |
static int count;
|
|
931 |
fprintf(logfile, "%6d: v=%04x pc=%016" PRIx64 " npc=%016" PRIx64 " SP=%016" PRIx64 "\n",
|
|
932 | 932 |
count, intno, |
933 | 933 |
env->pc, |
934 | 934 |
env->npc, env->regwptr[6]); |
935 |
cpu_dump_state(env, logfile, fprintf, 0);
|
|
935 |
cpu_dump_state(env, logfile, fprintf, 0);
|
|
936 | 936 |
#if 0 |
937 |
{
|
|
938 |
int i;
|
|
939 |
uint8_t *ptr;
|
|
940 |
|
|
941 |
fprintf(logfile, " code=");
|
|
942 |
ptr = (uint8_t *)env->pc;
|
|
943 |
for(i = 0; i < 16; i++) {
|
|
944 |
fprintf(logfile, " %02x", ldub(ptr + i));
|
|
945 |
}
|
|
946 |
fprintf(logfile, "\n");
|
|
947 |
}
|
|
937 |
{
|
|
938 |
int i;
|
|
939 |
uint8_t *ptr;
|
|
940 |
|
|
941 |
fprintf(logfile, " code=");
|
|
942 |
ptr = (uint8_t *)env->pc;
|
|
943 |
for(i = 0; i < 16; i++) {
|
|
944 |
fprintf(logfile, " %02x", ldub(ptr + i));
|
|
945 |
}
|
|
946 |
fprintf(logfile, "\n");
|
|
947 |
}
|
|
948 | 948 |
#endif |
949 |
count++;
|
|
949 |
count++;
|
|
950 | 950 |
} |
951 | 951 |
#endif |
952 | 952 |
#if !defined(CONFIG_USER_ONLY) |
953 | 953 |
if (env->tl == MAXTL) { |
954 | 954 |
cpu_abort(env, "Trap 0x%04x while trap level is MAXTL, Error state", env->exception_index); |
955 |
return;
|
|
955 |
return;
|
|
956 | 956 |
} |
957 | 957 |
#endif |
958 | 958 |
env->tstate[env->tl] = ((uint64_t)GET_CCR(env) << 32) | ((env->asi & 0xff) << 24) | |
959 |
((env->pstate & 0xf3f) << 8) | GET_CWP64(env);
|
|
959 |
((env->pstate & 0xf3f) << 8) | GET_CWP64(env);
|
|
960 | 960 |
env->tpc[env->tl] = env->pc; |
961 | 961 |
env->tnpc[env->tl] = env->npc; |
962 | 962 |
env->tt[env->tl] = intno; |
... | ... | |
971 | 971 |
env->tbr &= ~0x7fffULL; |
972 | 972 |
env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5); |
973 | 973 |
if (env->tl < MAXTL - 1) { |
974 |
env->tl++;
|
|
974 |
env->tl++;
|
|
975 | 975 |
} else { |
976 |
env->pstate |= PS_RED;
|
|
977 |
if (env->tl != MAXTL)
|
|
978 |
env->tl++;
|
|
976 |
env->pstate |= PS_RED;
|
|
977 |
if (env->tl != MAXTL)
|
|
978 |
env->tl++;
|
|
979 | 979 |
} |
980 | 980 |
env->pc = env->tbr; |
981 | 981 |
env->npc = env->pc + 4; |
... | ... | |
988 | 988 |
|
989 | 989 |
#ifdef DEBUG_PCALL |
990 | 990 |
if (loglevel & CPU_LOG_INT) { |
991 |
static int count;
|
|
992 |
fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n",
|
|
991 |
static int count;
|
|
992 |
fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n",
|
|
993 | 993 |
count, intno, |
994 | 994 |
env->pc, |
995 | 995 |
env->npc, env->regwptr[6]); |
996 |
cpu_dump_state(env, logfile, fprintf, 0);
|
|
996 |
cpu_dump_state(env, logfile, fprintf, 0);
|
|
997 | 997 |
#if 0 |
998 |
{
|
|
999 |
int i;
|
|
1000 |
uint8_t *ptr;
|
|
1001 |
|
|
1002 |
fprintf(logfile, " code=");
|
|
1003 |
ptr = (uint8_t *)env->pc;
|
|
1004 |
for(i = 0; i < 16; i++) {
|
|
1005 |
fprintf(logfile, " %02x", ldub(ptr + i));
|
|
1006 |
}
|
|
1007 |
fprintf(logfile, "\n");
|
|
1008 |
}
|
|
998 |
{
|
|
999 |
int i;
|
|
1000 |
uint8_t *ptr;
|
|
1001 |
|
|
1002 |
fprintf(logfile, " code=");
|
|
1003 |
ptr = (uint8_t *)env->pc;
|
|
1004 |
for(i = 0; i < 16; i++) {
|
|
1005 |
fprintf(logfile, " %02x", ldub(ptr + i));
|
|
1006 |
}
|
|
1007 |
fprintf(logfile, "\n");
|
|
1008 |
}
|
|
1009 | 1009 |
#endif |
1010 |
count++;
|
|
1010 |
count++;
|
|
1011 | 1011 |
} |
1012 | 1012 |
#endif |
1013 | 1013 |
#if !defined(CONFIG_USER_ONLY) |
1014 | 1014 |
if (env->psret == 0) { |
1015 | 1015 |
cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index); |
1016 |
return;
|
|
1016 |
return;
|
|
1017 | 1017 |
} |
1018 | 1018 |
#endif |
1019 | 1019 |
env->psret = 0; |
... | ... | |
1106 | 1106 |
saved_env = env; |
1107 | 1107 |
env = cpu_single_env; |
1108 | 1108 |
if (env->mmuregs[3]) /* Fault status register */ |
1109 |
env->mmuregs[3] = 1; /* overflow (not read before another fault) */
|
|
1109 |
env->mmuregs[3] = 1; /* overflow (not read before another fault) */
|
|
1110 | 1110 |
if (is_asi) |
1111 | 1111 |
env->mmuregs[3] |= 1 << 16; |
1112 | 1112 |
if (env->psrs) |
Also available in: Unified diff