diff options
author | edgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-05-13 10:59:14 +0000 |
---|---|---|
committer | edgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-05-13 10:59:14 +0000 |
commit | cf1d97f07480b6197aebc489938b4e1fed78d3e7 (patch) | |
tree | d4ae1d25078f714690f5b01761f2bffd5d57f115 /target-cris/mmu.c | |
parent | 3bd8c5e4f1fdb61a3eb8a4a8b6e5b4cf1156ba76 (diff) |
CRIS: Improve TLB management and handle delayslots at page boundaries.
* Dont flush the entire qemu tlb when the $pid changes. Instead we go through
the guests TLB and choose entries that need to be flushed.
* Add env->dslot and handle delayslots at pageboundaries.
* Remove some unused code.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4450 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-cris/mmu.c')
-rw-r--r-- | target-cris/mmu.c | 55 |
1 files changed, 38 insertions, 17 deletions
diff --git a/target-cris/mmu.c b/target-cris/mmu.c index bec89e685b..86f625b753 100644 --- a/target-cris/mmu.c +++ b/target-cris/mmu.c @@ -174,8 +174,9 @@ static int cris_mmu_translate_page(struct cris_mmu_result_t *res, tlb_pfn = EXTRACT_FIELD(lo, 13, 31); tlb_g = EXTRACT_FIELD(lo, 4, 4); - D(printf("TLB[%d][%d] v=%x vpage=%x -> pfn=%x lo=%x hi=%x\n", - i, idx, tlb_vpn, vpage, tlb_pfn, lo, hi)); + D(fprintf(logfile, + "TLB[%d][%d][%d] v=%x vpage=%x->pfn=%x lo=%x hi=%x\n", + mmu, set, idx, tlb_vpn, vpage, tlb_pfn, lo, hi)); if ((tlb_g || (tlb_pid == (env->pregs[PR_PID] & 0xff))) && tlb_vpn == vpage) { match = 1; @@ -224,7 +225,6 @@ static int cris_mmu_translate_page(struct cris_mmu_result_t *res, res->bf_vec = vect_base + 3; } else if (cfg_v && !tlb_v) { D(printf ("tlb: invalid %x\n", vaddr)); - set_field(&r_cause, rwcause, 8, 9); match = 0; res->bf_vec = vect_base + 1; } @@ -287,21 +287,42 @@ static int cris_mmu_translate_page(struct cris_mmu_result_t *res, return !match; } -/* Give us the vaddr corresponding to the latest TLB update. */ -target_ulong cris_mmu_tlb_latest_update(CPUState *env) +void cris_mmu_flush_pid(CPUState *env, uint32_t pid) { - uint32_t sel = env->sregs[SFR_RW_MM_TLB_SEL]; - uint32_t vaddr; - uint32_t hi; - int set; - int idx; - - idx = EXTRACT_FIELD(sel, 0, 4); - set = EXTRACT_FIELD(sel, 4, 5); - - hi = env->tlbsets[1][set][idx].hi; - vaddr = EXTRACT_FIELD(hi, 13, 31); - return vaddr << TARGET_PAGE_BITS; + target_ulong vaddr; + unsigned int idx; + uint32_t lo, hi; + uint32_t tlb_vpn; + int tlb_pid, tlb_g, tlb_v, tlb_k; + unsigned int set; + unsigned int mmu; + + pid &= 0xff; + for (mmu = 0; mmu < 2; mmu++) { + for (set = 0; set < 4; set++) + { + for (idx = 0; idx < 16; idx++) { + lo = env->tlbsets[mmu][set][idx].lo; + hi = env->tlbsets[mmu][set][idx].hi; + + tlb_vpn = EXTRACT_FIELD(hi, 13, 31); + tlb_pid = EXTRACT_FIELD(hi, 0, 7); + tlb_g = EXTRACT_FIELD(lo, 4, 4); + tlb_v = EXTRACT_FIELD(lo, 3, 3); + tlb_k = EXTRACT_FIELD(lo, 2, 2); + + /* Kernel protected areas need to be flushed + as well. */ + if (tlb_v && !tlb_g) { + vaddr = tlb_vpn << TARGET_PAGE_BITS; + D(fprintf(logfile, + "flush pid=%x vaddr=%x\n", + pid, vaddr)); + tlb_flush_page(env, vaddr); + } + } + } + } } int cris_mmu_translate(struct cris_mmu_result_t *res, |