mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
@@ -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
@@ -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
@@ -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,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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user