summaryrefslogtreecommitdiff
path: root/target-cris/mmu.c
diff options
context:
space:
mode:
authoredgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162>2008-05-13 10:59:14 +0000
committeredgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162>2008-05-13 10:59:14 +0000
commitcf1d97f07480b6197aebc489938b4e1fed78d3e7 (patch)
treed4ae1d25078f714690f5b01761f2bffd5d57f115 /target-cris/mmu.c
parent3bd8c5e4f1fdb61a3eb8a4a8b6e5b4cf1156ba76 (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.c55
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,