diff options
author | edgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-03-14 01:08:09 +0000 |
---|---|---|
committer | edgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162> | 2008-03-14 01:08:09 +0000 |
commit | 786c02f1acb73ca68ecdc4fa93911495dc1147c6 (patch) | |
tree | 0af7a4fd67683e1f6531d56c3da62a943b8ee801 /target-cris/mmu.c | |
parent | e62b5b133b97e07711741e2a4e2bf3e4dbc254f8 (diff) |
Model more parts of the ETRAX mmu (still alot missing).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4056 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-cris/mmu.c')
-rw-r--r-- | target-cris/mmu.c | 165 |
1 files changed, 142 insertions, 23 deletions
diff --git a/target-cris/mmu.c b/target-cris/mmu.c index 5fa5215bc2..84a1747e5f 100644 --- a/target-cris/mmu.c +++ b/target-cris/mmu.c @@ -30,6 +30,7 @@ #include "mmu.h" #include "exec-all.h" +#define D(x) static int cris_mmu_enabled(uint32_t rw_gc_cfg) { @@ -60,7 +61,22 @@ static uint32_t cris_mmu_translate_seg(CPUState *env, int seg) } /* Used by the tlb decoder. */ #define EXTRACT_FIELD(src, start, end) \ - (((src) >> start) & ((1 << (end - start + 1)) - 1)) + (((src) >> start) & ((1 << (end - start + 1)) - 1)) + +static inline void set_field(uint32_t *dst, unsigned int val, + unsigned int offset, unsigned int width) +{ + uint32_t mask; + + mask = (1 << width) - 1; + mask <<= offset; + val <<= offset; + + val &= mask; + D(printf ("val=%x mask=%x dst=%x\n", val, mask, *dst)); + *dst &= ~(mask); + *dst |= val; +} static int cris_mmu_translate_page(struct cris_mmu_result_t *res, CPUState *env, uint32_t vaddr, @@ -69,46 +85,149 @@ static int cris_mmu_translate_page(struct cris_mmu_result_t *res, unsigned int vpage; unsigned int idx; uint32_t lo, hi; - uint32_t vpn, pfn = 0, pid, fg, fv, fk, fw, fx; + uint32_t tlb_vpn, tlb_pfn = 0; + int tlb_pid, tlb_g, tlb_v, tlb_k, tlb_w, tlb_x; + int cfg_v, cfg_k, cfg_w, cfg_x; int i, match = 0; + uint32_t r_cause; + uint32_t r_cfg; + int rwcause; + int update_sel = 0; + + r_cause = env->sregs[SFR_R_MM_CAUSE]; + r_cfg = env->sregs[SFR_RW_MM_CFG]; + rwcause = rw ? CRIS_MMU_ERR_WRITE : CRIS_MMU_ERR_READ; vpage = vaddr >> 13; - idx = vpage & 31; - vpage >>= 4; + idx = vpage & 15; /* We know the index which to check on each set. Scan both I and D. */ +#if 0 + for (i = 0; i < 4; i++) { + int j; + for (j = 0; j < 16; j++) { + lo = env->tlbsets[1][i][j].lo; + hi = env->tlbsets[1][i][j].hi; + tlb_vpn = EXTRACT_FIELD(hi, 13, 31); + tlb_pfn = EXTRACT_FIELD(lo, 13, 31); + + printf ("TLB: [%d][%d] hi=%x lo=%x v=%x p=%x\n", + i, j, hi, lo, tlb_vpn, tlb_pfn); + } + } +#endif for (i = 0; i < 4; i++) { - lo = env->tlbsets[0][i][idx].lo; - hi = env->tlbsets[0][i][idx].hi; + lo = env->tlbsets[1][i][idx].lo; + hi = env->tlbsets[1][i][idx].hi; - vpn = EXTRACT_FIELD(hi, 13, 31); - pid = EXTRACT_FIELD(hi, 0, 7); + tlb_vpn = EXTRACT_FIELD(hi, 13, 31); + tlb_pfn = EXTRACT_FIELD(lo, 13, 31); - if (vpn == vpage - && pid == env->pregs[PR_PID]) { + D(printf ("TLB[%d][%d] tlbv=%x vpage=%x -> pfn=%x\n", + i, idx, tlb_vpn, vpage, tlb_pfn)); + if (tlb_vpn == vpage) { match = 1; break; } } if (match) { - pfn = EXTRACT_FIELD(lo, 13, 31); - fg = EXTRACT_FIELD(lo, 4, 4); - fv = EXTRACT_FIELD(lo, 3, 3); - fk = EXTRACT_FIELD(lo, 2, 2); - fw = EXTRACT_FIELD(lo, 1, 1); - fx = EXTRACT_FIELD(lo, 0, 0); + + cfg_w = EXTRACT_FIELD(r_cfg, 19, 19); + cfg_k = EXTRACT_FIELD(r_cfg, 18, 18); + cfg_x = EXTRACT_FIELD(r_cfg, 17, 17); + cfg_v = EXTRACT_FIELD(r_cfg, 16, 16); + + tlb_pid = EXTRACT_FIELD(hi, 0, 7); + tlb_pfn = EXTRACT_FIELD(lo, 13, 31); + tlb_g = EXTRACT_FIELD(lo, 4, 4); + tlb_v = EXTRACT_FIELD(lo, 3, 3); + tlb_k = EXTRACT_FIELD(lo, 2, 2); + tlb_w = EXTRACT_FIELD(lo, 1, 1); + tlb_x = EXTRACT_FIELD(lo, 0, 0); + + /* + set_exception_vector(0x04, i_mmu_refill); + set_exception_vector(0x05, i_mmu_invalid); + set_exception_vector(0x06, i_mmu_access); + set_exception_vector(0x07, i_mmu_execute); + set_exception_vector(0x08, d_mmu_refill); + set_exception_vector(0x09, d_mmu_invalid); + set_exception_vector(0x0a, d_mmu_access); + set_exception_vector(0x0b, d_mmu_write); + */ + if (cfg_v && !tlb_v) { + printf ("tlb: invalid\n"); + set_field(&r_cause, rwcause, 8, 9); + match = 0; + res->bf_vec = 0x9; + update_sel = 1; + } + else if (!tlb_g + && tlb_pid != 0xff + && tlb_pid != env->pregs[PR_PID] + && cfg_w && !tlb_w) { + printf ("tlb: wrong pid\n"); + match = 0; + res->bf_vec = 0xa; + } + else if (rw && cfg_w && !tlb_w) { + printf ("tlb: write protected\n"); + match = 0; + res->bf_vec = 0xb; + } + } else + update_sel = 1; + + if (update_sel) { + /* miss. */ + env->sregs[SFR_RW_MM_TLB_SEL] = 0; + D(printf ("tlb: miss %x vp=%x\n", + env->sregs[SFR_RW_MM_TLB_SEL], vpage & 15)); + set_field(&env->sregs[SFR_RW_MM_TLB_SEL], vpage & 15, 0, 4); + set_field(&env->sregs[SFR_RW_MM_TLB_SEL], 0, 4, 5); + res->bf_vec = 0x8; + } + + if (!match) { + set_field(&r_cause, rwcause, 8, 9); + set_field(&r_cause, vpage, 13, 19); + set_field(&r_cause, env->pregs[PR_PID], 0, 8); + env->sregs[SFR_R_MM_CAUSE] = r_cause; } - printf ("%s match=%d vaddr=%x vpage=%x vpn=%x pfn=%x pid=%x %x\n", - __func__, match, - vaddr, vpage, - vpn, pfn, pid, env->pregs[PR_PID]); - res->pfn = pfn; + D(printf ("%s mtch=%d pc=%x va=%x vpn=%x tlbvpn=%x pfn=%x pid=%x" + " %x cause=%x sel=%x r13=%x\n", + __func__, match, env->pc, + vaddr, vpage, + tlb_vpn, tlb_pfn, tlb_pid, + env->pregs[PR_PID], + r_cause, + env->sregs[SFR_RW_MM_TLB_SEL], + env->regs[13])); + + res->pfn = tlb_pfn; return !match; } +/* Give us the vaddr corresponding to the latest TLB update. */ +target_ulong cris_mmu_tlb_latest_update(CPUState *env, uint32_t new_lo) +{ + 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; +} + int cris_mmu_translate(struct cris_mmu_result_t *res, CPUState *env, uint32_t vaddr, int rw, int mmu_idx) @@ -116,7 +235,7 @@ int cris_mmu_translate(struct cris_mmu_result_t *res, uint32_t phy = vaddr; int seg; int miss = 0; - int is_user = mmu_idx == MMU_USER_IDX; + int is_user = mmu_idx == MMU_USER_IDX; if (!cris_mmu_enabled(env->sregs[SFR_RW_GC_CFG])) { res->phy = vaddr; @@ -142,7 +261,7 @@ int cris_mmu_translate(struct cris_mmu_result_t *res, res->phy = phy; } } -// printf ("miss=%d v=%x -> p=%x\n", miss, vaddr, phy); + D(printf ("miss=%d v=%x -> p=%x\n", miss, vaddr, phy)); return miss; } #endif |