CRIS updates:
* Support both the I and D MMUs and improve the accuracy of the MMU model. * Handle the automatic user/kernel stack pointer switching when leaving or entering user mode. * Move the CCS evaluation into helper funcs. * Make sure user-mode cannot change flags only writeable in kernel mode. * More conversion of the translator into TCG. * Handle exceptions while in a delayslot. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4299 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
		
							parent
							
								
									ff56ff7a07
								
							
						
					
					
						commit
						b41f7df018
					
				| @ -257,7 +257,7 @@ static inline TranslationBlock *tb_find_fast(void) | ||||
|     cs_base = 0; | ||||
|     pc = env->pc; | ||||
| #elif defined(TARGET_CRIS) | ||||
|     flags = 0; | ||||
|     flags = env->pregs[PR_CCS]; | ||||
|     cs_base = 0; | ||||
|     pc = env->pc; | ||||
| #else | ||||
|  | ||||
| @ -38,6 +38,28 @@ | ||||
| #define EXCP_MMU_FAULT   4 | ||||
| #define EXCP_BREAK      16 /* trap.  */ | ||||
| 
 | ||||
| /* Register aliases. R0 - R15 */ | ||||
| #define R_FP  8 | ||||
| #define R_SP  14 | ||||
| #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_EXS 5 | ||||
| #define PR_EDA 6 | ||||
| #define PR_MOF 7 | ||||
| #define PR_DZ  8 | ||||
| #define PR_EBP 9 | ||||
| #define PR_ERP 10 | ||||
| #define PR_SRP 11 | ||||
| #define PR_CCS 13 | ||||
| #define PR_USP 14 | ||||
| #define PR_SPC 15 | ||||
| 
 | ||||
| /* CPU flags.  */ | ||||
| #define S_FLAG 0x200 | ||||
| #define R_FLAG 0x100 | ||||
| @ -77,27 +99,16 @@ | ||||
| #define NB_MMU_MODES 2 | ||||
| 
 | ||||
| typedef struct CPUCRISState { | ||||
| 	uint32_t debug1; | ||||
| 	uint32_t debug2; | ||||
| 	uint32_t debug3; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * We just store the stores to the tlbset here for later evaluation | ||||
| 	 * when the hw needs access to them. | ||||
| 	 * | ||||
| 	 * One for I and another for D. | ||||
| 	 */ | ||||
| 	struct | ||||
| 	{ | ||||
| 		uint32_t hi; | ||||
| 		uint32_t lo; | ||||
| 	} tlbsets[2][4][16]; | ||||
| 
 | ||||
| 	uint32_t sregs[256][16]; /* grrr why so many??  */ | ||||
| 	uint32_t regs[16]; | ||||
| 	/* P0 - P15 are referred to as special registers in the docs.  */ | ||||
| 	uint32_t pregs[16]; | ||||
| 
 | ||||
| 	/* Pseudo register for the PC. Not directly accessable on CRIS.  */ | ||||
| 	uint32_t pc; | ||||
| 
 | ||||
| 	/* 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; | ||||
| @ -114,20 +125,19 @@ typedef struct CPUCRISState { | ||||
| 	/* size of the operation, 1 = byte, 2 = word, 4 = dword.  */ | ||||
| 	int cc_size; | ||||
| 
 | ||||
| 	/* extended arithmetics.  */ | ||||
| 	/* Extended arithmetics.  */ | ||||
| 	int cc_x_live; | ||||
| 	int cc_x; | ||||
| 
 | ||||
| 	int features; | ||||
| 
 | ||||
| 	int exception_index; | ||||
| 	int interrupt_request; | ||||
| 	int interrupt_vector; | ||||
| 	int fault_vector; | ||||
| 	int trap_vector; | ||||
| 
 | ||||
| 	int user_mode_only; | ||||
| 	int halted; | ||||
| 	uint32_t debug1; | ||||
| 	uint32_t debug2; | ||||
| 	uint32_t debug3; | ||||
| 
 | ||||
| 	struct | ||||
| 	{ | ||||
| @ -136,6 +146,31 @@ typedef struct CPUCRISState { | ||||
| 		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. | ||||
| 
 | ||||
| 	   Support function registers are used to control units close to the | ||||
| 	   core. Accesses do not pass down the normal hierarchy. | ||||
| 	*/ | ||||
| 	uint32_t sregs[4][16]; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * We just store the stores to the tlbset here for later evaluation | ||||
| 	 * when the hw needs access to them. | ||||
| 	 * | ||||
| 	 * One for I and another for D. | ||||
| 	 */ | ||||
| 	struct | ||||
| 	{ | ||||
| 		uint32_t hi; | ||||
| 		uint32_t lo; | ||||
| 	} tlbsets[2][4][16]; | ||||
| 
 | ||||
| 	int features; | ||||
| 	int user_mode_only; | ||||
| 	int halted; | ||||
| 
 | ||||
| 	jmp_buf jmp_env; | ||||
| 	CPU_COMMON | ||||
| } CPUCRISState; | ||||
| @ -225,40 +260,20 @@ void register_cris_insns (CPUCRISState *env); | ||||
| #define MMU_MODE0_SUFFIX _kernel | ||||
| #define MMU_MODE1_SUFFIX _user | ||||
| #define MMU_USER_IDX 1 | ||||
| /* CRIS FIXME: I guess we want to validate supervisor mode acceses here.  */ | ||||
| static inline int cpu_mmu_index (CPUState *env) | ||||
| { | ||||
|     return 0; | ||||
| 	return !!(env->pregs[PR_CCS] & U_FLAG); | ||||
| } | ||||
| 
 | ||||
| #include "cpu-all.h" | ||||
| 
 | ||||
| /* Register aliases. R0 - R15 */ | ||||
| #define R_FP  8 | ||||
| #define R_SP  14 | ||||
| #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 | ||||
| #define PR_CCS 13 | ||||
| 
 | ||||
| /* Support function regs.  */ | ||||
| #define SFR_RW_GC_CFG      0][0 | ||||
| #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 | ||||
| #define SFR_RW_MM_CFG      env->pregs[PR_SRS]][0 | ||||
| #define SFR_RW_MM_KBASE_LO env->pregs[PR_SRS]][1 | ||||
| #define SFR_RW_MM_KBASE_HI env->pregs[PR_SRS]][2 | ||||
| #define SFR_R_MM_CAUSE     env->pregs[PR_SRS]][3 | ||||
| #define SFR_RW_MM_TLB_SEL  env->pregs[PR_SRS]][4 | ||||
| #define SFR_RW_MM_TLB_LO   env->pregs[PR_SRS]][5 | ||||
| #define SFR_RW_MM_TLB_HI   env->pregs[PR_SRS]][6 | ||||
| 
 | ||||
| #include "cpu-all.h" | ||||
| #endif | ||||
|  | ||||
| @ -61,7 +61,7 @@ static void cris_shift_ccs(CPUState *env) | ||||
| 	uint32_t ccs; | ||||
| 	/* Apply the ccs shift.  */ | ||||
| 	ccs = env->pregs[PR_CCS]; | ||||
| 	ccs = (ccs & 0xc0000000) | ((ccs << 12) >> 2); | ||||
| 	ccs = ((ccs & 0xc0000000) | ((ccs << 12) >> 2)) & ~0x3ff; | ||||
| 	env->pregs[PR_CCS] = ccs; | ||||
| } | ||||
| 
 | ||||
| @ -73,7 +73,7 @@ int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw, | ||||
| 	int r = -1; | ||||
| 	target_ulong phy; | ||||
| 
 | ||||
| 	D(printf ("%s addr=%x pc=%x\n", __func__, address, env->pc)); | ||||
| 	D(printf ("%s addr=%x pc=%x rw=%x\n", __func__, address, env->pc, rw)); | ||||
| 	address &= TARGET_PAGE_MASK; | ||||
| 	prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; | ||||
| 	miss = cris_mmu_translate(&res, env, address, rw, mmu_idx); | ||||
| @ -86,12 +86,14 @@ int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw, | ||||
| 	else | ||||
| 	{ | ||||
| 		phy = res.phy; | ||||
| 		prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; | ||||
| 		prot = res.prot; | ||||
| 		address &= TARGET_PAGE_MASK; | ||||
| 		r = tlb_set_page(env, address, phy, prot, mmu_idx, is_softmmu); | ||||
| 	} | ||||
| 	D(printf("%s returns %d irqreq=%x addr=%x ismmu=%d\n",  | ||||
| 			__func__, r, env->interrupt_request,  | ||||
| 			address, 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)); | ||||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| @ -100,8 +102,8 @@ void do_interrupt(CPUState *env) | ||||
| 	int ex_vec = -1; | ||||
| 
 | ||||
| 	D(fprintf (stderr, "exception index=%d interrupt_req=%d\n", | ||||
| 		 env->exception_index, | ||||
| 		 env->interrupt_request)); | ||||
| 		   env->exception_index, | ||||
| 		   env->interrupt_request)); | ||||
| 
 | ||||
| 	switch (env->exception_index) | ||||
| 	{ | ||||
| @ -113,40 +115,46 @@ void do_interrupt(CPUState *env) | ||||
| 			break; | ||||
| 
 | ||||
| 		case EXCP_MMU_FAULT: | ||||
| 			/* ERP is already setup by translate-all.c through
 | ||||
| 			   re-translation of the aborted TB combined with  | ||||
| 			   pc searching.  */ | ||||
| 			ex_vec = env->fault_vector; | ||||
| 			env->pregs[PR_ERP] = env->pc; | ||||
| 			break; | ||||
| 
 | ||||
| 		default: | ||||
| 		{ | ||||
| 			/* Maybe the irq was acked by sw before we got a
 | ||||
| 			   change to take it.  */ | ||||
| 			if (env->interrupt_request & CPU_INTERRUPT_HARD) { | ||||
| 				/* Vectors below 0x30 are internal
 | ||||
| 				   exceptions, i.e not interrupt requests | ||||
| 				   from the interrupt controller.  */ | ||||
| 				if (env->interrupt_vector < 0x30) | ||||
| 					return; | ||||
| 				/* Is the core accepting interrupts?  */ | ||||
| 				if (!(env->pregs[PR_CCS] & I_FLAG)) { | ||||
| 					return; | ||||
| 				} | ||||
| 				/* The interrupt controller gives us the
 | ||||
| 				   vector.  */ | ||||
| 				ex_vec = env->interrupt_vector; | ||||
| 				/* Normal interrupts are taken between
 | ||||
| 				   TB's.  env->pc is valid here.  */ | ||||
| 				env->pregs[PR_ERP] = env->pc; | ||||
| 			} | ||||
| 		} | ||||
| 		break; | ||||
| 			/* Is the core accepting interrupts?  */ | ||||
| 			if (!(env->pregs[PR_CCS] & I_FLAG)) | ||||
| 				return; | ||||
| 			/* The interrupt controller gives us the
 | ||||
| 			   vector.  */ | ||||
| 			ex_vec = env->interrupt_vector; | ||||
| 			/* Normal interrupts are taken between
 | ||||
| 			   TB's.  env->pc is valid here.  */ | ||||
| 			env->pregs[PR_ERP] = env->pc; | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	if ((env->pregs[PR_CCS] & U_FLAG)) { | ||||
| 		D(fprintf(logfile, "excp isr=%x PC=%x ERP=%x pid=%x ccs=%x cc=%d %x\n", | ||||
| 			  ex_vec, env->pc, | ||||
| 			  env->pregs[PR_ERP], env->pregs[PR_PID], | ||||
| 			  env->pregs[PR_CCS], | ||||
| 			  env->cc_op, env->cc_mask)); | ||||
| 	} | ||||
| 	 | ||||
| 	env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4); | ||||
| 	/* Apply the CRIS CCS shift.  */ | ||||
| 
 | ||||
| 	if (env->pregs[PR_CCS] & U_FLAG) { | ||||
| 		/* Swap stack pointers.  */ | ||||
| 		env->pregs[PR_USP] = env->regs[R_SP]; | ||||
| 		env->regs[R_SP] = env->ksp; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Apply the CRIS CCS shift. Clears U if set.  */ | ||||
| 	cris_shift_ccs(env); | ||||
| 	D(printf ("%s ebp=%x isr=%x vec=%x\n", __func__, ebp, isr, ex_vec)); | ||||
| 	D(fprintf (logfile, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",  | ||||
| 		   __func__, env->pc, ex_vec,  | ||||
| 		   env->pregs[PR_CCS], | ||||
| 		   env->pregs[PR_PID],  | ||||
| 		   env->pregs[PR_ERP])); | ||||
| } | ||||
| 
 | ||||
| target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) | ||||
|  | ||||
| @ -1,3 +1,15 @@ | ||||
| #define TCG_HELPER_PROTO | ||||
| void TCG_HELPER_PROTO helper_tlb_update(uint32_t T0); | ||||
| 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); | ||||
| void TCG_HELPER_PROTO helper_rfe(void); | ||||
| void TCG_HELPER_PROTO helper_store(uint32_t a0); | ||||
| 
 | ||||
| void TCG_HELPER_PROTO helper_evaluate_flags_muls(void); | ||||
| void TCG_HELPER_PROTO helper_evaluate_flags_mulu(void); | ||||
| void TCG_HELPER_PROTO helper_evaluate_flags_mcp(void); | ||||
| void TCG_HELPER_PROTO helper_evaluate_flags_alu_4(void); | ||||
| void TCG_HELPER_PROTO helper_evaluate_flags_move_4 (void); | ||||
| void TCG_HELPER_PROTO helper_evaluate_flags_move_2 (void); | ||||
| void TCG_HELPER_PROTO helper_evaluate_flags (void); | ||||
|  | ||||
| @ -73,11 +73,30 @@ static inline void set_field(uint32_t *dst, unsigned int val, | ||||
| 	val <<= offset; | ||||
| 
 | ||||
| 	val &= mask; | ||||
| 	D(printf ("val=%x mask=%x dst=%x\n", val, mask, *dst)); | ||||
| 	*dst &= ~(mask); | ||||
| 	*dst |= val; | ||||
| } | ||||
| 
 | ||||
| static void dump_tlb(CPUState *env, int mmu) | ||||
| { | ||||
| 	int set; | ||||
| 	int idx; | ||||
| 	uint32_t hi, lo, tlb_vpn, tlb_pfn; | ||||
| 
 | ||||
| 	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_pfn = EXTRACT_FIELD(lo, 13, 31); | ||||
| 
 | ||||
| 			printf ("TLB: [%d][%d] hi=%x lo=%x v=%x p=%x\n",  | ||||
| 					set, idx, hi, lo, tlb_vpn, tlb_pfn); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /* rw 0 = read, 1 = write, 2 = exec.  */ | ||||
| static int cris_mmu_translate_page(struct cris_mmu_result_t *res, | ||||
| 				   CPUState *env, uint32_t vaddr, | ||||
| 				   int rw, int usermode) | ||||
| @ -88,53 +107,63 @@ static int cris_mmu_translate_page(struct cris_mmu_result_t *res, | ||||
| 	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; | ||||
| 	int set, match = 0; | ||||
| 	uint32_t r_cause; | ||||
| 	uint32_t r_cfg; | ||||
| 	int rwcause; | ||||
| 	int update_sel = 0; | ||||
| 	int mmu = 1; /* Data mmu is default.  */ | ||||
| 	int vect_base; | ||||
| 
 | ||||
| 	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; | ||||
| 
 | ||||
| 	switch (rw) { | ||||
| 		case 2: rwcause = CRIS_MMU_ERR_EXEC; mmu = 0; break; | ||||
| 		case 1: rwcause = CRIS_MMU_ERR_WRITE; break; | ||||
| 		default: | ||||
| 		case 0: rwcause = CRIS_MMU_ERR_READ; break; | ||||
| 	} | ||||
| 
 | ||||
| 	/* I exception vectors 4 - 7, D 8 - 11.  */ | ||||
| 	vect_base = (mmu + 1) * 4; | ||||
| 
 | ||||
| 	vpage = vaddr >> 13; | ||||
| 	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; | ||||
| 	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_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); | ||||
| 					set, idx, hi, lo, tlb_vpn, tlb_pfn); | ||||
| 		} | ||||
| 	} | ||||
| #endif | ||||
| 	for (i = 0; i < 4; i++) | ||||
| 
 | ||||
| 	idx = vpage & 15; | ||||
| 	for (set = 0; set < 4; set++) | ||||
| 	{ | ||||
| 		lo = env->tlbsets[1][i][idx].lo; | ||||
| 		hi = env->tlbsets[1][i][idx].hi; | ||||
| 		lo = env->tlbsets[mmu][set][idx].lo; | ||||
| 		hi = env->tlbsets[mmu][set][idx].hi; | ||||
| 
 | ||||
| 		tlb_vpn = EXTRACT_FIELD(hi, 13, 31); | ||||
| 		tlb_pfn = EXTRACT_FIELD(lo, 13, 31); | ||||
| 
 | ||||
| 		D(printf ("TLB[%d][%d] tlbv=%x vpage=%x -> pfn=%x\n",  | ||||
| 				i, idx, tlb_vpn, vpage, tlb_pfn)); | ||||
| 		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)); | ||||
| 		if (tlb_vpn == vpage) { | ||||
| 			match = 1; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	res->bf_vec = vect_base; | ||||
| 	if (match) { | ||||
| 
 | ||||
| 		cfg_w  = EXTRACT_FIELD(r_cfg, 19, 19); | ||||
| 		cfg_k  = EXTRACT_FIELD(r_cfg, 18, 18); | ||||
| 		cfg_x  = EXTRACT_FIELD(r_cfg, 17, 17); | ||||
| @ -158,54 +187,67 @@ static int cris_mmu_translate_page(struct cris_mmu_result_t *res, | ||||
| 		set_exception_vector(0x0a, d_mmu_access); | ||||
| 		set_exception_vector(0x0b, d_mmu_write); | ||||
| 		*/ | ||||
| 		if (cfg_v && !tlb_v) { | ||||
| 			printf ("tlb: invalid\n"); | ||||
| 		if (!tlb_g  | ||||
| 		    && tlb_pid != (env->pregs[PR_PID] & 0xff)) { | ||||
| 			D(printf ("tlb: wrong pid %x %x pc=%x\n",  | ||||
| 				 tlb_pid, env->pregs[PR_PID], env->pc)); | ||||
| 			match = 0; | ||||
| 			res->bf_vec = vect_base; | ||||
| 		} else if (rw == 1 && cfg_w && !tlb_w) { | ||||
| 			D(printf ("tlb: write protected %x lo=%x\n",  | ||||
| 				vaddr, lo)); | ||||
| 			match = 0; | ||||
| 			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 = 0x9; | ||||
| 			update_sel = 1; | ||||
| 			res->bf_vec = vect_base + 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; | ||||
| 		res->prot = 0; | ||||
| 		if (match) { | ||||
| 			res->prot |= PAGE_READ; | ||||
| 			if (tlb_w) | ||||
| 				res->prot |= PAGE_WRITE; | ||||
| 			if (tlb_x) | ||||
| 				res->prot |= PAGE_EXEC; | ||||
| 		} | ||||
| 		else | ||||
| 			D(dump_tlb(env, mmu)); | ||||
| 
 | ||||
| 		env->sregs[SFR_RW_MM_TLB_HI] = hi; | ||||
| 		env->sregs[SFR_RW_MM_TLB_LO] = lo; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!match) { | ||||
| 		set_field(&r_cause, rwcause, 8, 9); | ||||
| 		/* miss.  */ | ||||
| 		idx = vpage & 15; | ||||
| 		set = 0; | ||||
| 
 | ||||
| 		/* Update RW_MM_TLB_SEL.  */ | ||||
| 		env->sregs[SFR_RW_MM_TLB_SEL] = 0; | ||||
| 		set_field(&env->sregs[SFR_RW_MM_TLB_SEL], idx, 0, 4); | ||||
| 		set_field(&env->sregs[SFR_RW_MM_TLB_SEL], set, 4, 5); | ||||
| 
 | ||||
| 		/* Update RW_MM_CAUSE.  */ | ||||
| 		set_field(&r_cause, rwcause, 8, 2); | ||||
| 		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; | ||||
| 		D(printf("refill vaddr=%x pc=%x\n", vaddr, env->pc)); | ||||
| 	} | ||||
| 	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, | ||||
| 
 | ||||
| 
 | ||||
| 	D(printf ("%s rw=%d mtch=%d pc=%x va=%x vpn=%x tlbvpn=%x pfn=%x pid=%x" | ||||
| 		  " %x cause=%x sel=%x sp=%x %x %x\n", | ||||
| 		  __func__, rw, 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])); | ||||
| 		  env->regs[R_SP], env->pregs[PR_USP], env->ksp)); | ||||
| 
 | ||||
| 	res->pfn = tlb_pfn; | ||||
| 	return !match; | ||||
| @ -236,10 +278,17 @@ int cris_mmu_translate(struct cris_mmu_result_t *res, | ||||
| 	int seg; | ||||
| 	int miss = 0; | ||||
| 	int is_user = mmu_idx == MMU_USER_IDX; | ||||
| 	uint32_t old_srs; | ||||
| 
 | ||||
| 	old_srs= env->pregs[PR_SRS]; | ||||
| 
 | ||||
| 	/* rw == 2 means exec, map the access to the insn mmu.  */ | ||||
| 	env->pregs[PR_SRS] = rw == 2 ? 1 : 2; | ||||
| 
 | ||||
| 	if (!cris_mmu_enabled(env->sregs[SFR_RW_GC_CFG])) { | ||||
| 		res->phy = vaddr; | ||||
| 		return 0; | ||||
| 		res->prot = PAGE_BITS;		 | ||||
| 		goto done; | ||||
| 	} | ||||
| 
 | ||||
| 	seg = vaddr >> 28; | ||||
| @ -251,17 +300,16 @@ int cris_mmu_translate(struct cris_mmu_result_t *res, | ||||
| 		base = cris_mmu_translate_seg(env, seg); | ||||
| 		phy = base | (0x0fffffff & vaddr); | ||||
| 		res->phy = phy; | ||||
| 		res->prot = PAGE_BITS;		 | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		miss = cris_mmu_translate_page(res, env, vaddr, rw, is_user); | ||||
| 		if (!miss) { | ||||
| 			phy &= 8191; | ||||
| 			phy |= (res->pfn << 13); | ||||
| 			res->phy = phy; | ||||
| 		} | ||||
| 		phy = (res->pfn << 13); | ||||
| 		res->phy = phy; | ||||
| 	} | ||||
| 	D(printf ("miss=%d v=%x -> p=%x\n", miss, vaddr, phy)); | ||||
|   done: | ||||
| 	env->pregs[PR_SRS] = old_srs; | ||||
| 	return miss; | ||||
| } | ||||
| #endif | ||||
|  | ||||
| @ -7,6 +7,7 @@ struct cris_mmu_result_t | ||||
| { | ||||
| 	uint32_t phy; | ||||
| 	uint32_t pfn; | ||||
| 	int prot; | ||||
| 	int bf_vec; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										397
									
								
								target-cris/op.c
									
									
									
									
									
								
							
							
						
						
									
										397
									
								
								target-cris/op.c
									
									
									
									
									
								
							| @ -192,17 +192,32 @@ void OPPROTO op_ccs_lshift (void) | ||||
| } | ||||
| void OPPROTO op_ccs_rshift (void) | ||||
| { | ||||
| 	uint32_t ccs; | ||||
| 	register uint32_t ccs; | ||||
| 
 | ||||
| 	/* Apply the ccs shift.  */ | ||||
| 	ccs = env->pregs[PR_CCS]; | ||||
| 	ccs = (ccs & 0xc0000000) | ((ccs & 0x0fffffff) >> 10); | ||||
| 	if (ccs & U_FLAG) | ||||
| 	{ | ||||
| 		/* Enter user mode.  */ | ||||
| 		env->ksp = env->regs[R_SP]; | ||||
| 		env->regs[R_SP] = env->pregs[PR_USP]; | ||||
| 	} | ||||
| 
 | ||||
| 	env->pregs[PR_CCS] = ccs; | ||||
| 
 | ||||
| 	RETURN(); | ||||
| } | ||||
| 
 | ||||
| void OPPROTO op_setf (void) | ||||
| { | ||||
| 	if (!(env->pregs[PR_CCS] & U_FLAG) && (PARAM1 & U_FLAG)) | ||||
| 	{ | ||||
| 		/* Enter user mode.  */ | ||||
| 		env->ksp = env->regs[R_SP]; | ||||
| 		env->regs[R_SP] = env->pregs[PR_USP]; | ||||
| 	} | ||||
| 
 | ||||
| 	env->pregs[PR_CCS] |= PARAM1; | ||||
| 	RETURN(); | ||||
| } | ||||
| @ -265,7 +280,11 @@ void OPPROTO op_movl_flags_T0 (void) | ||||
| 
 | ||||
| void OPPROTO op_movl_sreg_T0 (void) | ||||
| { | ||||
| 	env->sregs[env->pregs[PR_SRS]][PARAM1] = T0; | ||||
| 	uint32_t srs; | ||||
| 	srs = env->pregs[PR_SRS]; | ||||
| 	srs &= 3; | ||||
| 
 | ||||
| 	env->sregs[srs][PARAM1] = T0; | ||||
| 	RETURN(); | ||||
| } | ||||
| 
 | ||||
| @ -285,7 +304,10 @@ void OPPROTO op_movl_tlb_hi_T0 (void) | ||||
| void OPPROTO op_movl_tlb_lo_T0 (void) | ||||
| { | ||||
| 	uint32_t srs; | ||||
| 
 | ||||
| 	env->pregs[PR_SRS] &= 3; | ||||
| 	srs = env->pregs[PR_SRS]; | ||||
| 
 | ||||
| 	if (srs == 1 || srs == 2) | ||||
| 	{ | ||||
| 		uint32_t set; | ||||
| @ -309,7 +331,28 @@ void OPPROTO op_movl_tlb_lo_T0 (void) | ||||
| 
 | ||||
| void OPPROTO op_movl_T0_sreg (void) | ||||
| { | ||||
| 	T0 = env->sregs[env->pregs[PR_SRS]][PARAM1]; | ||||
| 	uint32_t srs; | ||||
| 	env->pregs[PR_SRS] &= 3; | ||||
| 	srs = env->pregs[PR_SRS]; | ||||
| 	 | ||||
| 	if (srs == 1 || srs == 2) | ||||
| 	{ | ||||
| 		uint32_t set; | ||||
| 		uint32_t idx; | ||||
| 		uint32_t lo, hi; | ||||
| 
 | ||||
| 		idx = set = env->sregs[SFR_RW_MM_TLB_SEL]; | ||||
| 		set >>= 4; | ||||
| 		set &= 3; | ||||
| 		idx &= 15; | ||||
| 
 | ||||
| 		/* Update the mirror regs.  */ | ||||
| 		hi = env->tlbsets[srs - 1][set][idx].hi; | ||||
| 		lo = env->tlbsets[srs - 1][set][idx].lo; | ||||
| 		env->sregs[SFR_RW_MM_TLB_HI] = hi; | ||||
| 		env->sregs[SFR_RW_MM_TLB_LO] = lo; | ||||
| 	} | ||||
| 	T0 = env->sregs[srs][PARAM1]; | ||||
| 	RETURN(); | ||||
| } | ||||
| 
 | ||||
| @ -363,340 +406,6 @@ void OPPROTO op_update_cc_x (void) | ||||
| 	RETURN(); | ||||
| } | ||||
| 
 | ||||
| /* FIXME: is this allowed?  */ | ||||
| extern inline void evaluate_flags_writeback(uint32_t flags) | ||||
| { | ||||
| 	int x; | ||||
| 
 | ||||
| 	/* Extended arithmetics, leave the z flag alone.  */ | ||||
| 	env->debug3 = env->pregs[PR_CCS]; | ||||
| 
 | ||||
| 	if (env->cc_x_live) | ||||
| 		x = env->cc_x; | ||||
| 	else | ||||
| 		x = env->pregs[PR_CCS] & X_FLAG; | ||||
| 
 | ||||
| 	if ((x || env->cc_op == CC_OP_ADDC) | ||||
| 	    && flags & Z_FLAG) | ||||
| 		env->cc_mask &= ~Z_FLAG; | ||||
| 
 | ||||
| 	/* all insn clear the x-flag except setf or clrf.  */ | ||||
| 	env->pregs[PR_CCS] &= ~(env->cc_mask | X_FLAG); | ||||
| 	flags &= env->cc_mask; | ||||
| 	env->pregs[PR_CCS] |= flags; | ||||
| 	RETURN(); | ||||
| } | ||||
| 
 | ||||
| void OPPROTO op_evaluate_flags_muls(void) | ||||
| { | ||||
| 	uint32_t src; | ||||
| 	uint32_t dst; | ||||
| 	uint32_t res; | ||||
| 	uint32_t flags = 0; | ||||
| 	/* were gonna have to redo the muls.  */ | ||||
| 	int64_t tmp, t0 ,t1; | ||||
| 	int32_t mof; | ||||
| 	int dneg; | ||||
| 
 | ||||
| 	src = env->cc_src; | ||||
| 	dst = env->cc_dest; | ||||
| 	res = env->cc_result; | ||||
| 
 | ||||
| 
 | ||||
| 	/* cast into signed values to make GCC sign extend.  */ | ||||
| 	t0 = (int32_t)src; | ||||
| 	t1 = (int32_t)dst; | ||||
| 	dneg = ((int32_t)res) < 0; | ||||
| 
 | ||||
| 	tmp = t0 * t1; | ||||
| 	mof = tmp >> 32; | ||||
| 	if (tmp == 0) | ||||
| 		flags |= Z_FLAG; | ||||
| 	else if (tmp < 0) | ||||
| 		flags |= N_FLAG; | ||||
| 	if ((dneg && mof != -1) | ||||
| 	    || (!dneg && mof != 0)) | ||||
| 		flags |= V_FLAG; | ||||
| 	evaluate_flags_writeback(flags); | ||||
| 	RETURN(); | ||||
| } | ||||
| 
 | ||||
| void OPPROTO op_evaluate_flags_mulu(void) | ||||
| { | ||||
| 	uint32_t src; | ||||
| 	uint32_t dst; | ||||
| 	uint32_t res; | ||||
| 	uint32_t flags = 0; | ||||
| 	/* were gonna have to redo the muls.  */ | ||||
| 	uint64_t tmp, t0 ,t1; | ||||
| 	uint32_t mof; | ||||
| 
 | ||||
| 	src = env->cc_src; | ||||
| 	dst = env->cc_dest; | ||||
| 	res = env->cc_result; | ||||
| 
 | ||||
| 
 | ||||
| 	/* cast into signed values to make GCC sign extend.  */ | ||||
| 	t0 = src; | ||||
| 	t1 = dst; | ||||
| 
 | ||||
| 	tmp = t0 * t1; | ||||
| 	mof = tmp >> 32; | ||||
| 	if (tmp == 0) | ||||
| 		flags |= Z_FLAG; | ||||
| 	else if (tmp >> 63) | ||||
| 		flags |= N_FLAG; | ||||
| 	if (mof) | ||||
| 		flags |= V_FLAG; | ||||
| 
 | ||||
| 	evaluate_flags_writeback(flags); | ||||
| 	RETURN(); | ||||
| } | ||||
| 
 | ||||
| void OPPROTO op_evaluate_flags_mcp(void) | ||||
| { | ||||
| 	uint32_t src; | ||||
| 	uint32_t dst; | ||||
| 	uint32_t res; | ||||
| 	uint32_t flags = 0; | ||||
| 
 | ||||
| 	src = env->cc_src; | ||||
| 	dst = env->cc_dest; | ||||
| 	res = env->cc_result; | ||||
| 
 | ||||
| 	if ((res & 0x80000000L) != 0L) | ||||
| 	{ | ||||
| 		flags |= N_FLAG; | ||||
| 		if (((src & 0x80000000L) == 0L) | ||||
| 		    && ((dst & 0x80000000L) == 0L)) | ||||
| 		{ | ||||
| 			flags |= V_FLAG; | ||||
| 		} | ||||
| 		else if (((src & 0x80000000L) != 0L) && | ||||
| 			 ((dst & 0x80000000L) != 0L)) | ||||
| 		{ | ||||
| 			flags |= R_FLAG; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if (res == 0L) | ||||
| 			flags |= Z_FLAG; | ||||
| 		if (((src & 0x80000000L) != 0L) | ||||
| 		    && ((dst & 0x80000000L) != 0L)) | ||||
| 			flags |= V_FLAG; | ||||
| 		if ((dst & 0x80000000L) != 0L | ||||
| 		    || (src & 0x80000000L) != 0L) | ||||
| 			flags |= R_FLAG; | ||||
| 	} | ||||
| 
 | ||||
| 	evaluate_flags_writeback(flags); | ||||
| 	RETURN(); | ||||
| } | ||||
| 
 | ||||
| void OPPROTO op_evaluate_flags_alu_4(void) | ||||
| { | ||||
| 	uint32_t src; | ||||
| 	uint32_t dst; | ||||
| 	uint32_t res; | ||||
| 	uint32_t flags = 0; | ||||
| 
 | ||||
| 	src = env->cc_src; | ||||
| 	dst = env->cc_dest; | ||||
| 	res = env->cc_result; | ||||
| 
 | ||||
| 	if ((res & 0x80000000L) != 0L) | ||||
| 	{ | ||||
| 		flags |= N_FLAG; | ||||
| 		if (((src & 0x80000000L) == 0L) | ||||
| 		    && ((dst & 0x80000000L) == 0L)) | ||||
| 		{ | ||||
| 			flags |= V_FLAG; | ||||
| 		} | ||||
| 		else if (((src & 0x80000000L) != 0L) && | ||||
| 			 ((dst & 0x80000000L) != 0L)) | ||||
| 		{ | ||||
| 			flags |= C_FLAG; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if (res == 0L) | ||||
| 			flags |= Z_FLAG; | ||||
| 		if (((src & 0x80000000L) != 0L) | ||||
| 		    && ((dst & 0x80000000L) != 0L)) | ||||
| 			flags |= V_FLAG; | ||||
| 		if ((dst & 0x80000000L) != 0L | ||||
| 		    || (src & 0x80000000L) != 0L) | ||||
| 			flags |= C_FLAG; | ||||
| 	} | ||||
| 
 | ||||
| 	if (env->cc_op == CC_OP_SUB | ||||
| 	    || env->cc_op == CC_OP_CMP) { | ||||
| 		flags ^= C_FLAG; | ||||
| 	} | ||||
| 	evaluate_flags_writeback(flags); | ||||
| 	RETURN(); | ||||
| } | ||||
| 
 | ||||
| void OPPROTO op_evaluate_flags_move_4 (void) | ||||
| { | ||||
| 	uint32_t src; | ||||
| 	uint32_t res; | ||||
| 	uint32_t flags = 0; | ||||
| 
 | ||||
| 	src = env->cc_src; | ||||
| 	res = env->cc_result; | ||||
| 
 | ||||
| 	if ((int32_t)res < 0) | ||||
| 		flags |= N_FLAG; | ||||
| 	else if (res == 0L) | ||||
| 		flags |= Z_FLAG; | ||||
| 
 | ||||
| 	evaluate_flags_writeback(flags); | ||||
| 	RETURN(); | ||||
| } | ||||
| void OPPROTO op_evaluate_flags_move_2 (void) | ||||
| { | ||||
| 	uint32_t src; | ||||
| 	uint32_t flags = 0; | ||||
| 	uint16_t res; | ||||
| 
 | ||||
| 	src = env->cc_src; | ||||
| 	res = env->cc_result; | ||||
| 
 | ||||
| 	if ((int16_t)res < 0L) | ||||
| 		flags |= N_FLAG; | ||||
| 	else if (res == 0) | ||||
| 		flags |= Z_FLAG; | ||||
| 
 | ||||
| 	evaluate_flags_writeback(flags); | ||||
| 	RETURN(); | ||||
| } | ||||
| 
 | ||||
| /* TODO: This is expensive. We could split things up and only evaluate part of
 | ||||
|    CCR on a need to know basis. For now, we simply re-evaluate everything.  */ | ||||
| void OPPROTO op_evaluate_flags (void) | ||||
| { | ||||
| 	uint32_t src; | ||||
| 	uint32_t dst; | ||||
| 	uint32_t res; | ||||
| 	uint32_t flags = 0; | ||||
| 
 | ||||
| 	src = env->cc_src; | ||||
| 	dst = env->cc_dest; | ||||
| 	res = env->cc_result; | ||||
| 
 | ||||
| 
 | ||||
| 	/* Now, evaluate the flags. This stuff is based on
 | ||||
| 	   Per Zander's CRISv10 simulator.  */ | ||||
| 	switch (env->cc_size) | ||||
| 	{ | ||||
| 		case 1: | ||||
| 			if ((res & 0x80L) != 0L) | ||||
| 			{ | ||||
| 				flags |= N_FLAG; | ||||
| 				if (((src & 0x80L) == 0L) | ||||
| 				    && ((dst & 0x80L) == 0L)) | ||||
| 				{ | ||||
| 					flags |= V_FLAG; | ||||
| 				} | ||||
| 				else if (((src & 0x80L) != 0L) | ||||
| 					 && ((dst & 0x80L) != 0L)) | ||||
| 				{ | ||||
| 					flags |= C_FLAG; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				if ((res & 0xFFL) == 0L) | ||||
| 				{ | ||||
| 					flags |= Z_FLAG; | ||||
| 				} | ||||
| 				if (((src & 0x80L) != 0L) | ||||
| 				    && ((dst & 0x80L) != 0L)) | ||||
| 				{ | ||||
| 					flags |= V_FLAG; | ||||
| 				} | ||||
| 				if ((dst & 0x80L) != 0L | ||||
| 				    || (src & 0x80L) != 0L) | ||||
| 				{ | ||||
| 					flags |= C_FLAG; | ||||
| 				} | ||||
| 			} | ||||
| 			break; | ||||
| 		case 2: | ||||
| 			if ((res & 0x8000L) != 0L) | ||||
| 			{ | ||||
| 				flags |= N_FLAG; | ||||
| 				if (((src & 0x8000L) == 0L) | ||||
| 				    && ((dst & 0x8000L) == 0L)) | ||||
| 				{ | ||||
| 					flags |= V_FLAG; | ||||
| 				} | ||||
| 				else if (((src & 0x8000L) != 0L) | ||||
| 					 && ((dst & 0x8000L) != 0L)) | ||||
| 				{ | ||||
| 					flags |= C_FLAG; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				if ((res & 0xFFFFL) == 0L) | ||||
| 				{ | ||||
| 					flags |= Z_FLAG; | ||||
| 				} | ||||
| 				if (((src & 0x8000L) != 0L) | ||||
| 				    && ((dst & 0x8000L) != 0L)) | ||||
| 				{ | ||||
| 					flags |= V_FLAG; | ||||
| 				} | ||||
| 				if ((dst & 0x8000L) != 0L | ||||
| 				    || (src & 0x8000L) != 0L) | ||||
| 				{ | ||||
| 					flags |= C_FLAG; | ||||
| 				} | ||||
| 			} | ||||
| 			break; | ||||
| 		case 4: | ||||
| 			if ((res & 0x80000000L) != 0L) | ||||
| 			{ | ||||
| 				flags |= N_FLAG; | ||||
| 				if (((src & 0x80000000L) == 0L) | ||||
| 				    && ((dst & 0x80000000L) == 0L)) | ||||
| 				{ | ||||
| 					flags |= V_FLAG; | ||||
| 				} | ||||
| 				else if (((src & 0x80000000L) != 0L) && | ||||
| 					 ((dst & 0x80000000L) != 0L)) | ||||
| 				{ | ||||
| 					flags |= C_FLAG; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				if (res == 0L) | ||||
| 					flags |= Z_FLAG; | ||||
| 				if (((src & 0x80000000L) != 0L) | ||||
| 				    && ((dst & 0x80000000L) != 0L)) | ||||
| 					flags |= V_FLAG; | ||||
| 				if ((dst & 0x80000000L) != 0L | ||||
| 				    || (src & 0x80000000L) != 0L) | ||||
| 					flags |= C_FLAG; | ||||
| 			} | ||||
| 			break; | ||||
| 		default: | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	if (env->cc_op == CC_OP_SUB | ||||
| 	    || env->cc_op == CC_OP_CMP) { | ||||
| 		flags ^= C_FLAG; | ||||
| 	} | ||||
| 	evaluate_flags_writeback(flags); | ||||
| 	RETURN(); | ||||
| } | ||||
| 
 | ||||
| void OPPROTO op_extb_T0_T0 (void) | ||||
| { | ||||
| 	T0 = ((int8_t)T0); | ||||
| @ -1274,17 +983,3 @@ void OPPROTO op_jmp1 (void) | ||||
| 	env->pc = env->btarget; | ||||
| 	RETURN(); | ||||
| } | ||||
| 
 | ||||
| /* Load and store */ | ||||
| #define MEMSUFFIX _raw | ||||
| #include "op_mem.c" | ||||
| #undef MEMSUFFIX | ||||
| #if !defined(CONFIG_USER_ONLY) | ||||
| #define MEMSUFFIX _user | ||||
| #include "op_mem.c" | ||||
| #undef MEMSUFFIX | ||||
| 
 | ||||
| #define MEMSUFFIX _kernel | ||||
| #include "op_mem.c" | ||||
| #undef MEMSUFFIX | ||||
| #endif | ||||
|  | ||||
| @ -59,6 +59,9 @@ void tlb_fill (target_ulong addr, int is_write, int mmu_idx, void *retaddr) | ||||
|        generated code */ | ||||
|     saved_env = env; | ||||
|     env = cpu_single_env; | ||||
| 
 | ||||
|     D(fprintf(logfile, "%s ra=%x acr=%x %x\n", __func__, retaddr, | ||||
| 	    env->regs[R_ACR], saved_env->regs[R_ACR])); | ||||
|     ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); | ||||
|     if (__builtin_expect(ret, 0)) { | ||||
|         if (retaddr) { | ||||
| @ -80,16 +83,380 @@ void helper_tlb_update(uint32_t T0) | ||||
| { | ||||
| #if !defined(CONFIG_USER_ONLY) | ||||
| 	uint32_t vaddr; | ||||
| 	uint32_t srs = env->pregs[PR_SRS]; | ||||
| 
 | ||||
| 	if (srs != 1 && srs != 2) | ||||
| 		return; | ||||
| 
 | ||||
| 	vaddr = cris_mmu_tlb_latest_update(env, T0); | ||||
| 	D(printf("flush vaddr %x\n", vaddr)); | ||||
| 	D(printf("flush old_vaddr=%x vaddr=%x T0=%x\n", vaddr,  | ||||
| 		 env->sregs[SFR_R_MM_CAUSE] & TARGET_PAGE_MASK, T0)); | ||||
| 	tlb_flush_page(env, vaddr); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| void helper_tlb_flush(void) | ||||
| { | ||||
| 	tlb_flush(env, 1); | ||||
| } | ||||
| 
 | ||||
| void helper_dump(uint32_t a0, uint32_t a1) | ||||
| { | ||||
| 	(fprintf(logfile, "%s: a0=%x a1=%x\n", __func__, a0, a1));  | ||||
| } | ||||
| 
 | ||||
| void helper_dummy(void) | ||||
| { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| /* Only used for debugging at the moment.  */ | ||||
| void helper_rfe(void) | ||||
| { | ||||
| 	D(fprintf(logfile, "rfe: erp=%x pid=%x ccs=%x btarget=%x\n",  | ||||
| 		 env->pregs[PR_ERP], env->pregs[PR_PID], | ||||
| 		 env->pregs[PR_CCS], | ||||
| 		 env->btarget)); | ||||
| } | ||||
| 
 | ||||
| void helper_store(uint32_t a0) | ||||
| { | ||||
| 	if (env->pregs[PR_CCS] & P_FLAG ) | ||||
| 	{ | ||||
| 		cpu_abort(env, "cond_store_failed! pc=%x a0=%x\n", | ||||
| 			  env->pc, a0); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 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)); | ||||
| } | ||||
| 
 | ||||
| static void evaluate_flags_writeback(uint32_t flags) | ||||
| { | ||||
| 	int x; | ||||
| 
 | ||||
| 	/* Extended arithmetics, leave the z flag alone.  */ | ||||
| 	env->debug3 = env->pregs[PR_CCS]; | ||||
| 
 | ||||
| 	if (env->cc_x_live) | ||||
| 		x = env->cc_x; | ||||
| 	else | ||||
| 		x = env->pregs[PR_CCS] & X_FLAG; | ||||
| 
 | ||||
| 	if ((x || env->cc_op == CC_OP_ADDC) | ||||
| 	    && flags & Z_FLAG) | ||||
| 		env->cc_mask &= ~Z_FLAG; | ||||
| 
 | ||||
| 	/* all insn clear the x-flag except setf or clrf.  */ | ||||
| 	env->pregs[PR_CCS] &= ~(env->cc_mask | X_FLAG); | ||||
| 	flags &= env->cc_mask; | ||||
| 	env->pregs[PR_CCS] |= flags; | ||||
| 	RETURN(); | ||||
| } | ||||
| 
 | ||||
| void helper_evaluate_flags_muls(void) | ||||
| { | ||||
| 	uint32_t src; | ||||
| 	uint32_t dst; | ||||
| 	uint32_t res; | ||||
| 	uint32_t flags = 0; | ||||
| 	/* were gonna have to redo the muls.  */ | ||||
| 	int64_t tmp, t0 ,t1; | ||||
| 	int32_t mof; | ||||
| 	int dneg; | ||||
| 
 | ||||
| 	src = env->cc_src; | ||||
| 	dst = env->cc_dest; | ||||
| 	res = env->cc_result; | ||||
| 
 | ||||
| 
 | ||||
| 	/* cast into signed values to make GCC sign extend.  */ | ||||
| 	t0 = (int32_t)src; | ||||
| 	t1 = (int32_t)dst; | ||||
| 	dneg = ((int32_t)res) < 0; | ||||
| 
 | ||||
| 	tmp = t0 * t1; | ||||
| 	mof = tmp >> 32; | ||||
| 	if (tmp == 0) | ||||
| 		flags |= Z_FLAG; | ||||
| 	else if (tmp < 0) | ||||
| 		flags |= N_FLAG; | ||||
| 	if ((dneg && mof != -1) | ||||
| 	    || (!dneg && mof != 0)) | ||||
| 		flags |= V_FLAG; | ||||
| 	evaluate_flags_writeback(flags); | ||||
| } | ||||
| 
 | ||||
| void  helper_evaluate_flags_mulu(void) | ||||
| { | ||||
| 	uint32_t src; | ||||
| 	uint32_t dst; | ||||
| 	uint32_t res; | ||||
| 	uint32_t flags = 0; | ||||
| 	/* were gonna have to redo the muls.  */ | ||||
| 	uint64_t tmp, t0 ,t1; | ||||
| 	uint32_t mof; | ||||
| 
 | ||||
| 	src = env->cc_src; | ||||
| 	dst = env->cc_dest; | ||||
| 	res = env->cc_result; | ||||
| 
 | ||||
| 
 | ||||
| 	/* cast into signed values to make GCC sign extend.  */ | ||||
| 	t0 = src; | ||||
| 	t1 = dst; | ||||
| 
 | ||||
| 	tmp = t0 * t1; | ||||
| 	mof = tmp >> 32; | ||||
| 	if (tmp == 0) | ||||
| 		flags |= Z_FLAG; | ||||
| 	else if (tmp >> 63) | ||||
| 		flags |= N_FLAG; | ||||
| 	if (mof) | ||||
| 		flags |= V_FLAG; | ||||
| 
 | ||||
| 	evaluate_flags_writeback(flags); | ||||
| } | ||||
| 
 | ||||
| void  helper_evaluate_flags_mcp(void) | ||||
| { | ||||
| 	uint32_t src; | ||||
| 	uint32_t dst; | ||||
| 	uint32_t res; | ||||
| 	uint32_t flags = 0; | ||||
| 
 | ||||
| 	src = env->cc_src; | ||||
| 	dst = env->cc_dest; | ||||
| 	res = env->cc_result; | ||||
| 
 | ||||
| 	if ((res & 0x80000000L) != 0L) | ||||
| 	{ | ||||
| 		flags |= N_FLAG; | ||||
| 		if (((src & 0x80000000L) == 0L) | ||||
| 		    && ((dst & 0x80000000L) == 0L)) | ||||
| 		{ | ||||
| 			flags |= V_FLAG; | ||||
| 		} | ||||
| 		else if (((src & 0x80000000L) != 0L) && | ||||
| 			 ((dst & 0x80000000L) != 0L)) | ||||
| 		{ | ||||
| 			flags |= R_FLAG; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if (res == 0L) | ||||
| 			flags |= Z_FLAG; | ||||
| 		if (((src & 0x80000000L) != 0L) | ||||
| 		    && ((dst & 0x80000000L) != 0L)) | ||||
| 			flags |= V_FLAG; | ||||
| 		if ((dst & 0x80000000L) != 0L | ||||
| 		    || (src & 0x80000000L) != 0L) | ||||
| 			flags |= R_FLAG; | ||||
| 	} | ||||
| 
 | ||||
| 	evaluate_flags_writeback(flags); | ||||
| } | ||||
| 
 | ||||
| void  helper_evaluate_flags_alu_4(void) | ||||
| { | ||||
| 	uint32_t src; | ||||
| 	uint32_t dst; | ||||
| 	uint32_t res; | ||||
| 	uint32_t flags = 0; | ||||
| 
 | ||||
| 	src = env->cc_src; | ||||
| 	dst = env->cc_dest; | ||||
| 	res = env->cc_result; | ||||
| 
 | ||||
| 	if ((res & 0x80000000L) != 0L) | ||||
| 	{ | ||||
| 		flags |= N_FLAG; | ||||
| 		if (((src & 0x80000000L) == 0L) | ||||
| 		    && ((dst & 0x80000000L) == 0L)) | ||||
| 		{ | ||||
| 			flags |= V_FLAG; | ||||
| 		} | ||||
| 		else if (((src & 0x80000000L) != 0L) && | ||||
| 			 ((dst & 0x80000000L) != 0L)) | ||||
| 		{ | ||||
| 			flags |= C_FLAG; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		if (res == 0L) | ||||
| 			flags |= Z_FLAG; | ||||
| 		if (((src & 0x80000000L) != 0L) | ||||
| 		    && ((dst & 0x80000000L) != 0L)) | ||||
| 			flags |= V_FLAG; | ||||
| 		if ((dst & 0x80000000L) != 0L | ||||
| 		    || (src & 0x80000000L) != 0L) | ||||
| 			flags |= C_FLAG; | ||||
| 	} | ||||
| 
 | ||||
| 	if (env->cc_op == CC_OP_SUB | ||||
| 	    || env->cc_op == CC_OP_CMP) { | ||||
| 		flags ^= C_FLAG; | ||||
| 	} | ||||
| 	evaluate_flags_writeback(flags); | ||||
| } | ||||
| 
 | ||||
| void  helper_evaluate_flags_move_4 (void) | ||||
| { | ||||
| 	uint32_t src; | ||||
| 	uint32_t res; | ||||
| 	uint32_t flags = 0; | ||||
| 
 | ||||
| 	src = env->cc_src; | ||||
| 	res = env->cc_result; | ||||
| 
 | ||||
| 	if ((int32_t)res < 0) | ||||
| 		flags |= N_FLAG; | ||||
| 	else if (res == 0L) | ||||
| 		flags |= Z_FLAG; | ||||
| 
 | ||||
| 	evaluate_flags_writeback(flags); | ||||
| } | ||||
| void  helper_evaluate_flags_move_2 (void) | ||||
| { | ||||
| 	uint32_t src; | ||||
| 	uint32_t flags = 0; | ||||
| 	uint16_t res; | ||||
| 
 | ||||
| 	src = env->cc_src; | ||||
| 	res = env->cc_result; | ||||
| 
 | ||||
| 	if ((int16_t)res < 0L) | ||||
| 		flags |= N_FLAG; | ||||
| 	else if (res == 0) | ||||
| 		flags |= Z_FLAG; | ||||
| 
 | ||||
| 	evaluate_flags_writeback(flags); | ||||
| } | ||||
| 
 | ||||
| /* TODO: This is expensive. We could split things up and only evaluate part of
 | ||||
|    CCR on a need to know basis. For now, we simply re-evaluate everything.  */ | ||||
| void helper_evaluate_flags (void) | ||||
| { | ||||
| 	uint32_t src; | ||||
| 	uint32_t dst; | ||||
| 	uint32_t res; | ||||
| 	uint32_t flags = 0; | ||||
| 
 | ||||
| 	src = env->cc_src; | ||||
| 	dst = env->cc_dest; | ||||
| 	res = env->cc_result; | ||||
| 
 | ||||
| 
 | ||||
| 	/* Now, evaluate the flags. This stuff is based on
 | ||||
| 	   Per Zander's CRISv10 simulator.  */ | ||||
| 	switch (env->cc_size) | ||||
| 	{ | ||||
| 		case 1: | ||||
| 			if ((res & 0x80L) != 0L) | ||||
| 			{ | ||||
| 				flags |= N_FLAG; | ||||
| 				if (((src & 0x80L) == 0L) | ||||
| 				    && ((dst & 0x80L) == 0L)) | ||||
| 				{ | ||||
| 					flags |= V_FLAG; | ||||
| 				} | ||||
| 				else if (((src & 0x80L) != 0L) | ||||
| 					 && ((dst & 0x80L) != 0L)) | ||||
| 				{ | ||||
| 					flags |= C_FLAG; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				if ((res & 0xFFL) == 0L) | ||||
| 				{ | ||||
| 					flags |= Z_FLAG; | ||||
| 				} | ||||
| 				if (((src & 0x80L) != 0L) | ||||
| 				    && ((dst & 0x80L) != 0L)) | ||||
| 				{ | ||||
| 					flags |= V_FLAG; | ||||
| 				} | ||||
| 				if ((dst & 0x80L) != 0L | ||||
| 				    || (src & 0x80L) != 0L) | ||||
| 				{ | ||||
| 					flags |= C_FLAG; | ||||
| 				} | ||||
| 			} | ||||
| 			break; | ||||
| 		case 2: | ||||
| 			if ((res & 0x8000L) != 0L) | ||||
| 			{ | ||||
| 				flags |= N_FLAG; | ||||
| 				if (((src & 0x8000L) == 0L) | ||||
| 				    && ((dst & 0x8000L) == 0L)) | ||||
| 				{ | ||||
| 					flags |= V_FLAG; | ||||
| 				} | ||||
| 				else if (((src & 0x8000L) != 0L) | ||||
| 					 && ((dst & 0x8000L) != 0L)) | ||||
| 				{ | ||||
| 					flags |= C_FLAG; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				if ((res & 0xFFFFL) == 0L) | ||||
| 				{ | ||||
| 					flags |= Z_FLAG; | ||||
| 				} | ||||
| 				if (((src & 0x8000L) != 0L) | ||||
| 				    && ((dst & 0x8000L) != 0L)) | ||||
| 				{ | ||||
| 					flags |= V_FLAG; | ||||
| 				} | ||||
| 				if ((dst & 0x8000L) != 0L | ||||
| 				    || (src & 0x8000L) != 0L) | ||||
| 				{ | ||||
| 					flags |= C_FLAG; | ||||
| 				} | ||||
| 			} | ||||
| 			break; | ||||
| 		case 4: | ||||
| 			if ((res & 0x80000000L) != 0L) | ||||
| 			{ | ||||
| 				flags |= N_FLAG; | ||||
| 				if (((src & 0x80000000L) == 0L) | ||||
| 				    && ((dst & 0x80000000L) == 0L)) | ||||
| 				{ | ||||
| 					flags |= V_FLAG; | ||||
| 				} | ||||
| 				else if (((src & 0x80000000L) != 0L) && | ||||
| 					 ((dst & 0x80000000L) != 0L)) | ||||
| 				{ | ||||
| 					flags |= C_FLAG; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				if (res == 0L) | ||||
| 					flags |= Z_FLAG; | ||||
| 				if (((src & 0x80000000L) != 0L) | ||||
| 				    && ((dst & 0x80000000L) != 0L)) | ||||
| 					flags |= V_FLAG; | ||||
| 				if ((dst & 0x80000000L) != 0L | ||||
| 				    || (src & 0x80000000L) != 0L) | ||||
| 					flags |= C_FLAG; | ||||
| 			} | ||||
| 			break; | ||||
| 		default: | ||||
| 			break; | ||||
| 	} | ||||
| 
 | ||||
| 	if (env->cc_op == CC_OP_SUB | ||||
| 	    || env->cc_op == CC_OP_CMP) { | ||||
| 		flags ^= C_FLAG; | ||||
| 	} | ||||
| 	evaluate_flags_writeback(flags); | ||||
| } | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 edgar_igl
						edgar_igl