summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--target-cris/cpu.h30
-rw-r--r--target-cris/helper.h3
-rw-r--r--target-cris/mmu.c165
-rw-r--r--target-cris/mmu.h8
-rw-r--r--target-cris/op.c29
-rw-r--r--target-cris/op_helper.c17
6 files changed, 201 insertions, 51 deletions
diff --git a/target-cris/cpu.h b/target-cris/cpu.h
index 4e92f18d81..31ebaa62ea 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 0000000000..c2af3261db
--- /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 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
diff --git a/target-cris/mmu.h b/target-cris/mmu.h
index 519c0fc819..aef8c1b0e9 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 aeb80de4a3..d44185c4d4 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 458b0585de..701c835be1 100644
--- a/target-cris/op_helper.c
+++ b/target-cris/op_helper.c
@@ -21,6 +21,7 @@
#include <assert.h>
#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));
}