From 786c02f1acb73ca68ecdc4fa93911495dc1147c6 Mon Sep 17 00:00:00 2001 From: edgar_igl Date: Fri, 14 Mar 2008 01:08:09 +0000 Subject: [PATCH] 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 --- target-cris/cpu.h | 30 +++++---- target-cris/helper.h | 3 + target-cris/mmu.c | 165 ++++++++++++++++++++++++++++++++++++++++------- target-cris/mmu.h | 8 +-- target-cris/op.c | 29 ++++++--- target-cris/op_helper.c | 17 ++++- 6 files changed, 201 insertions(+), 51 deletions(-) create mode 100644 target-cris/helper.h diff --git a/target-cris/cpu.h b/target-cris/cpu.h index 4e92f18..31ebaa6 100644 --- a/target-cris/cpu.h +++ b/target-cris/cpu.h @@ -35,7 +35,7 @@ #define EXCP_MMU_READ 1 #define EXCP_MMU_WRITE 2 #define EXCP_MMU_FLUSH 3 -#define EXCP_MMU_MISS 4 +#define EXCP_MMU_FAULT 4 #define EXCP_BREAK 16 /* trap. */ /* CPU flags. */ @@ -110,9 +110,6 @@ typedef struct CPUCRISState { uint32_t btarget; int btaken; - /* for traps. */ - int trapnr; - /* Condition flag tracking. */ uint32_t cc_op; uint32_t cc_mask; @@ -129,9 +126,12 @@ typedef struct CPUCRISState { int features; - uint64_t pending_interrupts; - int interrupt_request; int exception_index; + int interrupt_request; + int interrupt_vector; + int fault_vector; + int trap_vector; + int user_mode_only; int halted; @@ -245,9 +245,13 @@ static inline int cpu_mmu_index (CPUState *env) #define R_ACR 15 /* Support regs, P0 - P15 */ +#define PR_BZ 0 +#define PR_VR 1 #define PR_PID 2 #define PR_SRS 3 +#define PR_WZ 4 #define PR_MOF 7 +#define PR_DZ 8 #define PR_EBP 9 #define PR_ERP 10 #define PR_SRP 11 @@ -255,12 +259,12 @@ static inline int cpu_mmu_index (CPUState *env) /* Support function regs. */ #define SFR_RW_GC_CFG 0][0 -#define SFR_RW_MM_CFG 1][0 -#define SFR_RW_MM_KBASE_LO 1][1 -#define SFR_RW_MM_KBASE_HI 1][2 -#define SFR_R_MM_CAUSE 1][3 -#define SFR_RW_MM_TLB_SEL 1][4 -#define SFR_RW_MM_TLB_LO 1][5 -#define SFR_RW_MM_TLB_HI 1][6 +#define SFR_RW_MM_CFG 2][0 +#define SFR_RW_MM_KBASE_LO 2][1 +#define SFR_RW_MM_KBASE_HI 2][2 +#define SFR_R_MM_CAUSE 2][3 +#define SFR_RW_MM_TLB_SEL 2][4 +#define SFR_RW_MM_TLB_LO 2][5 +#define SFR_RW_MM_TLB_HI 2][6 #endif diff --git a/target-cris/helper.h b/target-cris/helper.h new file mode 100644 index 0000000..c2af326 --- /dev/null +++ b/target-cris/helper.h @@ -0,0 +1,3 @@ +#define TCG_HELPER_PROTO +void TCG_HELPER_PROTO helper_tlb_update(uint32_t T0); + diff --git a/target-cris/mmu.c b/target-cris/mmu.c index 5fa5215..84a1747 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 diff --git a/target-cris/mmu.h b/target-cris/mmu.h index 519c0fc..aef8c1b 100644 --- a/target-cris/mmu.h +++ b/target-cris/mmu.h @@ -7,14 +7,10 @@ struct cris_mmu_result_t { uint32_t phy; uint32_t pfn; - int g:1; - int v:1; - int k:1; - int w:1; - int e:1; - int cause_op; + int bf_vec; }; +target_ulong cris_mmu_tlb_latest_update(CPUState *env, uint32_t new_lo); int cris_mmu_translate(struct cris_mmu_result_t *res, CPUState *env, uint32_t vaddr, int rw, int mmu_idx); diff --git a/target-cris/op.c b/target-cris/op.c index aeb80de..d44185c 100644 --- a/target-cris/op.c +++ b/target-cris/op.c @@ -153,7 +153,7 @@ void OPPROTO op_break_im(void) { - env->trapnr = PARAM1; + env->trap_vector = PARAM1; env->exception_index = EXCP_BREAK; cpu_loop_exit(); } @@ -196,7 +196,7 @@ void OPPROTO op_ccs_rshift (void) /* Apply the ccs shift. */ ccs = env->pregs[PR_CCS]; - ccs = (ccs & 0xc0000000) | (ccs >> 10); + ccs = (ccs & 0xc0000000) | ((ccs & 0x0fffffff) >> 10); env->pregs[PR_CCS] = ccs; RETURN(); } @@ -269,28 +269,41 @@ void OPPROTO op_movl_sreg_T0 (void) RETURN(); } +void OPPROTO op_movl_tlb_hi_T0 (void) +{ + uint32_t srs; + srs = env->pregs[PR_SRS]; + if (srs == 1 || srs == 2) + { + /* Writes to tlb-hi write to mm_cause as a side effect. */ + env->sregs[SFR_RW_MM_TLB_HI] = T0; + env->sregs[SFR_R_MM_CAUSE] = T0; + } + RETURN(); +} + void OPPROTO op_movl_tlb_lo_T0 (void) { - int srs; + uint32_t srs; srs = env->pregs[PR_SRS]; if (srs == 1 || srs == 2) { - int set; - int idx; + uint32_t set; + uint32_t idx; uint32_t lo, hi; idx = set = env->sregs[SFR_RW_MM_TLB_SEL]; set >>= 4; set &= 3; - idx &= 31; + idx &= 15; /* We've just made a write to tlb_lo. */ lo = env->sregs[SFR_RW_MM_TLB_LO]; - hi = env->sregs[SFR_RW_MM_TLB_HI]; + /* Writes are done via r_mm_cause. */ + hi = env->sregs[SFR_R_MM_CAUSE]; env->tlbsets[srs - 1][set][idx].lo = lo; env->tlbsets[srs - 1][set][idx].hi = hi; } - RETURN(); } diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c index 458b058..701c835 100644 --- a/target-cris/op_helper.c +++ b/target-cris/op_helper.c @@ -21,6 +21,7 @@ #include #include "exec.h" +#include "mmu.h" #define MMUSUFFIX _mmu #ifdef __s390__ @@ -41,6 +42,8 @@ #define SHIFT 3 #include "softmmu_template.h" +#define D(x) + /* Try to fill the TLB and return an exception if error. If retaddr is NULL, it means that the function was called in C code (i.e. not from generated code or from helper.c) */ @@ -73,8 +76,20 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) env = saved_env; } +void helper_tlb_update(uint32_t T0) +{ +#if !defined(CONFIG_USER_ONLY) + uint32_t vaddr; + + vaddr = cris_mmu_tlb_latest_update(env, T0); + D(printf("flush vaddr %x\n", vaddr)); + tlb_flush_page(env, vaddr); +#endif +} + void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, int is_asi) { - + D(printf("%s addr=%x w=%d ex=%d asi=%d\n", + __func__, addr, is_write, is_exec, is_asi)); } -- 1.7.9.5