Revision 29e179bc target-sh4/helper.c
b/target-sh4/helper.c | ||
---|---|---|
282 | 282 |
return match; |
283 | 283 |
} |
284 | 284 |
|
285 |
static int same_tlb_entry_exists(const tlb_t * haystack, uint8_t nbtlb, |
|
286 |
const tlb_t * needle) |
|
287 |
{ |
|
288 |
int i; |
|
289 |
for (i = 0; i < nbtlb; i++) |
|
290 |
if (!memcmp(&haystack[i], needle, sizeof(tlb_t))) |
|
291 |
return 1; |
|
292 |
return 0; |
|
293 |
} |
|
294 |
|
|
295 |
static void increment_urc(CPUState * env) |
|
296 |
{ |
|
297 |
uint8_t urb, urc; |
|
298 |
|
|
299 |
/* Increment URC */ |
|
300 |
urb = ((env->mmucr) >> 18) & 0x3f; |
|
301 |
urc = ((env->mmucr) >> 10) & 0x3f; |
|
302 |
urc++; |
|
303 |
if (urc == urb || urc == UTLB_SIZE - 1) |
|
304 |
urc = 0; |
|
305 |
env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10); |
|
306 |
} |
|
307 |
|
|
285 | 308 |
/* Find itlb entry - update itlb from utlb if necessary and asked for |
286 | 309 |
Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE |
287 | 310 |
Update the itlb from utlb if update is not 0 |
... | ... | |
313 | 336 |
Return entry, MMU_DTLB_MISS, MMU_DTLB_MULTIPLE */ |
314 | 337 |
int find_utlb_entry(CPUState * env, target_ulong address, int use_asid) |
315 | 338 |
{ |
316 |
uint8_t urb, urc; |
|
317 |
|
|
318 |
/* Increment URC */ |
|
319 |
urb = ((env->mmucr) >> 18) & 0x3f; |
|
320 |
urc = ((env->mmucr) >> 10) & 0x3f; |
|
321 |
urc++; |
|
322 |
if (urc == urb || urc == UTLB_SIZE - 1) |
|
323 |
urc = 0; |
|
324 |
env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10); |
|
339 |
/* per utlb access */ |
|
340 |
increment_urc(env); |
|
325 | 341 |
|
326 | 342 |
/* Return entry */ |
327 | 343 |
return find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid); |
... | ... | |
407 | 423 |
return (rw & PAGE_WRITE) ? MMU_DTLB_MISS_WRITE : |
408 | 424 |
MMU_DTLB_MISS_READ; |
409 | 425 |
} |
410 |
/* Mask upper 3 bits */ |
|
411 |
*physical = address & 0x1FFFFFFF; |
|
426 |
if (address >= 0x80000000 && address < 0xc0000000) { |
|
427 |
/* Mask upper 3 bits for P1 and P2 areas */ |
|
428 |
*physical = address & 0x1fffffff; |
|
429 |
} else if (address >= 0xfc000000) { |
|
430 |
/* |
|
431 |
* Mask upper 3 bits for control registers in P4 area, |
|
432 |
* to unify access to control registers via P0-P3 area. |
|
433 |
* The addresses for cache store queue, TLB address array |
|
434 |
* are not masked. |
|
435 |
*/ |
|
436 |
*physical = address & 0x1fffffff; |
|
437 |
} else { |
|
438 |
/* access to cache store queue, or TLB address array. */ |
|
439 |
*physical = address; |
|
440 |
} |
|
412 | 441 |
*prot = PAGE_READ | PAGE_WRITE; |
413 | 442 |
return MMU_OK; |
414 | 443 |
} |
... | ... | |
543 | 572 |
entry->tc = (uint8_t)cpu_ptea_tc(env->ptea); |
544 | 573 |
} |
545 | 574 |
|
575 |
void cpu_sh4_write_mmaped_utlb_addr(CPUSH4State *s, target_phys_addr_t addr, |
|
576 |
uint32_t mem_value) |
|
577 |
{ |
|
578 |
int associate = addr & 0x0000080; |
|
579 |
uint32_t vpn = (mem_value & 0xfffffc00) >> 10; |
|
580 |
uint8_t d = (uint8_t)((mem_value & 0x00000200) >> 9); |
|
581 |
uint8_t v = (uint8_t)((mem_value & 0x00000100) >> 8); |
|
582 |
uint8_t asid = (uint8_t)(mem_value & 0x000000ff); |
|
583 |
|
|
584 |
if (associate) { |
|
585 |
int i; |
|
586 |
tlb_t * utlb_match_entry = NULL; |
|
587 |
int needs_tlb_flush = 0; |
|
588 |
|
|
589 |
/* search UTLB */ |
|
590 |
for (i = 0; i < UTLB_SIZE; i++) { |
|
591 |
tlb_t * entry = &s->utlb[i]; |
|
592 |
if (!entry->v) |
|
593 |
continue; |
|
594 |
|
|
595 |
if (entry->vpn == vpn && entry->asid == asid) { |
|
596 |
if (utlb_match_entry) { |
|
597 |
/* Multiple TLB Exception */ |
|
598 |
s->exception_index = 0x140; |
|
599 |
s->tea = addr; |
|
600 |
break; |
|
601 |
} |
|
602 |
if (entry->v && !v) |
|
603 |
needs_tlb_flush = 1; |
|
604 |
entry->v = v; |
|
605 |
entry->d = d; |
|
606 |
utlb_match_entry = entry; |
|
607 |
} |
|
608 |
increment_urc(s); /* per utlb access */ |
|
609 |
} |
|
610 |
|
|
611 |
/* search ITLB */ |
|
612 |
for (i = 0; i < ITLB_SIZE; i++) { |
|
613 |
tlb_t * entry = &s->itlb[i]; |
|
614 |
if (entry->vpn == vpn && entry->asid == asid) { |
|
615 |
if (entry->v && !v) |
|
616 |
needs_tlb_flush = 1; |
|
617 |
if (utlb_match_entry) |
|
618 |
*entry = *utlb_match_entry; |
|
619 |
else |
|
620 |
entry->v = v; |
|
621 |
break; |
|
622 |
} |
|
623 |
} |
|
624 |
|
|
625 |
if (needs_tlb_flush) |
|
626 |
tlb_flush_page(s, vpn << 10); |
|
627 |
|
|
628 |
} else { |
|
629 |
int index = (addr & 0x00003f00) >> 8; |
|
630 |
tlb_t * entry = &s->utlb[index]; |
|
631 |
if (entry->v) { |
|
632 |
/* Overwriting valid entry in utlb. */ |
|
633 |
target_ulong address = entry->vpn << 10; |
|
634 |
if (!same_tlb_entry_exists(s->itlb, ITLB_SIZE, entry)) { |
|
635 |
tlb_flush_page(s, address); |
|
636 |
} |
|
637 |
} |
|
638 |
entry->asid = asid; |
|
639 |
entry->vpn = vpn; |
|
640 |
entry->d = d; |
|
641 |
entry->v = v; |
|
642 |
increment_urc(s); |
|
643 |
} |
|
644 |
} |
|
645 |
|
|
546 | 646 |
#endif |
Also available in: Unified diff