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
This commit is contained in:
edgar_igl
2008-05-13 10:59:14 +00:00
parent 3bd8c5e4f1
commit cf1d97f074
8 changed files with 194 additions and 138 deletions
+1
View File
@@ -261,6 +261,7 @@ static inline TranslationBlock *tb_find_fast(void)
pc = env->pc;
#elif defined(TARGET_CRIS)
flags = env->pregs[PR_CCS] & U_FLAG;
flags |= env->dslot;
cs_base = 0;
pc = env->pc;
#else
+3 -13
View File
@@ -107,11 +107,10 @@ typedef struct CPUCRISState {
/* Pseudo register for the kernel stack. */
uint32_t ksp;
/* These are setup up by the guest code just before transfering the
control back to the host. */
int jmp;
uint32_t btarget;
/* Branch. */
int dslot;
int btaken;
uint32_t btarget;
/* Condition flag tracking. */
uint32_t cc_op;
@@ -119,10 +118,8 @@ typedef struct CPUCRISState {
uint32_t cc_dest;
uint32_t cc_src;
uint32_t cc_result;
/* size of the operation, 1 = byte, 2 = word, 4 = dword. */
int cc_size;
/* Extended arithmetics. */
int cc_x_live;
int cc_x;
@@ -137,13 +134,6 @@ typedef struct CPUCRISState {
uint32_t debug2;
uint32_t debug3;
struct
{
int exec_insns;
int exec_loads;
int exec_stores;
} stats;
/* FIXME: add a check in the translator to avoid writing to support
register sets beyond the 4th. The ISA allows up to 256! but in
practice there is no core that implements more than 4.
+13 -6
View File
@@ -97,9 +97,10 @@ int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
r = tlb_set_page(env, address, phy, prot, mmu_idx, is_softmmu);
}
if (r > 0)
D(fprintf(logfile, "%s returns %d irqreq=%x addr=%x ismmu=%d vec=%x\n",
__func__, r, env->interrupt_request,
address, is_softmmu, res.bf_vec));
D(fprintf(logfile, "%s returns %d irqreq=%x addr=%x"
" phy=%x ismmu=%d vec=%x pc=%x\n",
__func__, r, env->interrupt_request,
address, res.phy, is_softmmu, res.bf_vec, env->pc));
return r;
}
@@ -138,13 +139,19 @@ void do_interrupt(CPUState *env)
break;
}
if ((env->pregs[PR_CCS] & U_FLAG)) {
D(fprintf(logfile, "excp isr=%x PC=%x SP=%x ERP=%x pid=%x ccs=%x cc=%d %x\n",
ex_vec, env->pc,
if (env->dslot) {
D(fprintf(logfile, "excp isr=%x PC=%x ds=%d SP=%x"
" ERP=%x pid=%x ccs=%x cc=%d %x\n",
ex_vec, env->pc, env->dslot,
env->regs[R_SP],
env->pregs[PR_ERP], env->pregs[PR_PID],
env->pregs[PR_CCS],
env->cc_op, env->cc_mask));
/* We loose the btarget, btaken state here so rexec the
branch. */
env->pregs[PR_ERP] -= env->dslot;
/* Exception starts with dslot cleared. */
env->dslot = 0;
}
env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4);
+1
View File
@@ -1,6 +1,7 @@
#define TCG_HELPER_PROTO
void TCG_HELPER_PROTO helper_raise_exception(uint32_t index);
void TCG_HELPER_PROTO helper_tlb_flush_pid(uint32_t pid);
void TCG_HELPER_PROTO helper_tlb_flush(void);
void TCG_HELPER_PROTO helper_dump(uint32_t a0, uint32_t a1, uint32_t a2);
void TCG_HELPER_PROTO helper_dummy(void);
+36 -15
View File
@@ -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;
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;
idx = EXTRACT_FIELD(sel, 0, 4);
set = EXTRACT_FIELD(sel, 4, 5);
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);
hi = env->tlbsets[1][set][idx].hi;
vaddr = EXTRACT_FIELD(hi, 13, 31);
return vaddr << TARGET_PAGE_BITS;
/* 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,
+1 -1
View File
@@ -11,7 +11,7 @@ struct cris_mmu_result_t
int bf_vec;
};
target_ulong cris_mmu_tlb_latest_update(CPUState *env);
void cris_mmu_flush_pid(CPUState *env, uint32_t pid);
int cris_mmu_translate(struct cris_mmu_result_t *res,
CPUState *env, uint32_t vaddr,
int rw, int mmu_idx);
+23 -4
View File
@@ -85,6 +85,13 @@ void helper_raise_exception(uint32_t index)
cpu_loop_exit();
}
void helper_tlb_flush_pid(uint32_t pid)
{
#if !defined(CONFIG_USER_ONLY)
cris_mmu_flush_pid(env, pid);
#endif
}
void helper_tlb_flush(void)
{
tlb_flush(env, 1);
@@ -100,6 +107,10 @@ void helper_dummy(void)
}
/* Used by the tlb decoder. */
#define EXTRACT_FIELD(src, start, end) \
(((src) >> start) & ((1 << (end - start + 1)) - 1))
void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg)
{
uint32_t srs;
@@ -120,10 +131,7 @@ void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg)
uint32_t idx;
uint32_t lo, hi;
uint32_t vaddr;
vaddr = cris_mmu_tlb_latest_update(env);
D(fprintf(logfile, "tlb flush vaddr=%x\n", vaddr));
tlb_flush_page(env, vaddr);
int tlb_v;
idx = set = env->sregs[SFR_RW_MM_TLB_SEL];
set >>= 4;
@@ -134,8 +142,19 @@ void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg)
lo = env->sregs[SFR_RW_MM_TLB_LO];
/* Writes are done via r_mm_cause. */
hi = env->sregs[SFR_R_MM_CAUSE];
vaddr = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].hi,
13, 31);
vaddr <<= TARGET_PAGE_BITS;
tlb_v = EXTRACT_FIELD(env->tlbsets[srs-1][set][idx].lo,
3, 3);
env->tlbsets[srs - 1][set][idx].lo = lo;
env->tlbsets[srs - 1][set][idx].hi = hi;
D(fprintf(logfile,
"tlb flush vaddr=%x v=%d pc=%x\n",
vaddr, tlb_v, env->pc));
tlb_flush_page(env, vaddr);
}
}
#endif
+116 -99
View File
File diff suppressed because it is too large Load Diff