⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 armmmu.cpp

📁 這是一個arm模擬器 以C++實做 主要模擬ARM9架構
💻 CPP
📖 第 1 页 / 共 2 页
字号:
		case MMU_TRANSLATION_TABLE_BASE:			data = translation_table_base;			break;		case MMU_DOMAIN_ACCESS_CONTROL:			data = domain_access_control;			break;		case MMU_FAULT_STATUS:			data = fault_status;			break;		case MMU_FAULT_ADDRESS:			data = fault_address;			break;		case MMU_PID:			data = process_id;			break; //no break in Skyeye		default:			data = 0;			fprintf (stderr, "cp15_mrc read UNKNOWN - reg %d, pc 0x\n", creg);			exit (-1);			break;	}	return data;}void arm_mmu::invalidate_tlb(word_t opcode_2,word_t CRm,word_t value) {				if (opcode_2 == 0 && CRm == 0x7) {		FLUSH_MMU_PAGE_TABLE(i_table);				FLUSH_MMU_PAGE_TABLE(d_table);				i_tlb->invalidate_all ();		d_tlb->invalidate_all ();	}	else if (opcode_2 == 0 && CRm == 0x5) {		FLUSH_MMU_PAGE_TABLE(i_table);				i_tlb->invalidate_all ();	}	else if (opcode_2 == 1 && CRm == 0x5) {		FLUSH_MMU_PAGE_TABLE(i_table);				i_tlb->invalidate_entry (value);	}	else if (opcode_2 == 0 && CRm == 0x6) {		FLUSH_MMU_PAGE_TABLE(d_table);				d_tlb->invalidate_all ();	}	else if (opcode_2 == 1 && CRm == 0x6) {		FLUSH_MMU_PAGE_TABLE(d_table);				d_tlb->invalidate_entry (value);	}	else {		fprintf (stderr,"Unknow OPC_2 = 0x%x CRm = 0x%x,Reg[15] 0x\n",				opcode_2, CRm);		exit (-1);	}}void arm_mmu::mcr(word_t instr, word_t value){	unsigned opcode_2 = (instr>>5)&7;	unsigned CRm = (instr>>0)&15;	unsigned creg = (instr>>16)&15;	switch (creg) {		case MMU_CONTROL:			set_control((value | 0x70) & 0xFFFD);			break;		case MMU_TRANSLATION_TABLE_BASE:			translation_table_base = value & 0xFFFFC000;			FLUSH_MMU_PAGE_TABLE(i_table);					FLUSH_MMU_PAGE_TABLE(d_table);								break;		case MMU_DOMAIN_ACCESS_CONTROL:			set_domain_access_control(value);			break;		case MMU_FAULT_STATUS:			fault_status = value & 0xFF;			break;		case MMU_FAULT_ADDRESS:			fault_address = value;			break;		case MMU_CACHE_OPS:			/*cache is not implemented*/			//xscale_cp15_cache_ops (state, instr, value);			break;		case MMU_TLB_OPS:			invalidate_tlb(opcode_2,CRm,value);					break;		case MMU_SA_RB_OPS:			// no read buffer			break;		case MMU_SA_DEBUG:			break;		case MMU_SA_CP15_R15:			break;		case MMU_PID:			set_process_id(value);			break;		default:			fprintf(stderr,				"cp15_mcr wrote UNKNOWN - reg %d, reg15 0x\n", creg);			break;	}}int arm_mmu::check_perms (int ap, mmu_access_t read) const{	static const byte_t perms[] = {	//	  !u    !u    !u    !u			0, 0, 0, 0, 0, 0, 0, 0,		//ap == 0		0, 0, 0, 1, 1, 1, 1, 1,		//ap == 0 read		0, 1, 0, 1, 0, 1, 0, 1,		//ap == 1			0, 1, 0, 1, 0, 1, 0, 1,		//ap == 1 read		0, 1, 0, 1, 0, 1, 0, 1,		//ap == 2 		1, 1, 1, 1, 1, 1, 1, 1,		//ap == 2 read		1, 1, 1, 1, 1, 1, 1, 1,		//ap == 3		1, 1, 1, 1, 1, 1, 1, 1		//ap == 3 read	//				r  r  r	 r	//        s  s        s  s	};				/* ap:read:rs_flag:user */	int	pack = ap | read | rs_flag | emu->is_privilege_mode();	return perms[pack];	}mmu_fault_t arm_mmu::check_access (word_t virt_addr, tlb_entry_t * tlb_e,	mmu_access_t read){	int access;	access = domain_access_array[tlb_e->domain];	if(access == 1) {		/* client access - check perms */		int subpage, ap;		switch (tlb_e->mapping) {		case TLB_ESMALLPAGE:	//xj			ap = tlb_e->perms  & 48;			break;		case TLB_TINYPAGE:			ap = tlb_e->perms  & 48;			break;		case TLB_SMALLPAGE:			ap = (tlb_e->perms >> ((virt_addr >> 9) & 6)) & 48;			break;		case TLB_LARGEPAGE:			ap = (tlb_e->perms >> ((virt_addr >> 13) & 6)) & 48;			break;		case TLB_SECTION:			ap = (tlb_e->perms >> 6 ) & 48;			break;		default:			assert (0);			subpage = 0;	/* cleans a warning */		}		if (!check_perms (ap, read)) {			last_domain= tlb_e->domain;			if (tlb_e->mapping == TLB_SECTION) {				return SECTION_PERMISSION_FAULT;			}			else {				return SUBPAGE_PERMISSION_FAULT;			}		}		return NO_FAULT;	}	if (access == 3) {			/* access == 3 */		/* manager access - don't check perms */		return NO_FAULT;	}//	if ((access == 0) || (access == 2)) {		/* It's unclear from the documentation whether this		   should always raise a section domain fault, or if		   it should be a page domain fault in the case of an		   L1 that describes a page table.  In the ARM710T		   datasheets, "Figure 8-9: Sequence for checking faults"		   seems to indicate the former, while "Table 8-4: Priority		   encoding of fault status" gives a value for FS[3210] in		   the event of a domain fault for a page.  Hmm. */		return SECTION_DOMAIN_FAULT;//	}}mmu_fault_t arm_mmu::translation_walk (word_t virt_addr, tlb_entry_t *tlb_e){	/* walk the translation tables */	int ap[4];	int fast_access = 1;	word_t L1addr, L1desc;	tlb_entry_t entry = *tlb_e;			L1addr = translation_table_base & 0xFFFFC000;	L1addr = (L1addr | (virt_addr >> 18)) & ~3;	MEM_READ_WORD (L1addr, &L1desc);	switch (L1desc & 3) {	case 0:		//SBZ		{			return PAGE_TRANSLATION_FAULT;		}	case 3:		/* fine page table */		{			word_t L2addr, L2desc;			L2addr = L1desc & 0xFFFFF000;			L2addr = (L2addr | ((virt_addr & 0x000FFC00) >> 8)) & ~3;			MEM_READ_WORD (L2addr, &L2desc);			entry.virt_addr = virt_addr;			entry.phys_addr = L2desc;			entry.perms = L2desc & 0x00000FFC;			entry.domain = (L1desc >> 5) & 0x0000000F;			ap[3]=(entry.perms>>10) & 3;			ap[2]=(entry.perms>>8) & 3;			ap[1]=(entry.perms>>6) & 3;			ap[0]=(entry.perms>>4) & 3;			switch (L2desc & 3) {				case 0:					last_domain = entry.domain;					return PAGE_TRANSLATION_FAULT;				case 3:					entry.mapping = TLB_TINYPAGE;					break;				case 1:					entry.mapping = TLB_LARGEPAGE;					/*check every sub-page ap-bit in order to group into 					one ap-bit*/					if(ap[3] != ap[2] || ap[2]!=ap[1] || ap[1] != ap[0] ) {						fast_access =0;						}					break;				case 2:					entry.mapping = TLB_SMALLPAGE;					/*check every sub-page ap-bit in order to group into 					one ap-bit*/					if(ap[3] != ap[2] || ap[2]!=ap[1] || ap[1] != ap[0] ) {						fast_access =0;						}					break;			}		}		break;	case 1:		/* coarse page table */		{			word_t L2addr, L2desc;			L2addr = L1desc & 0xFFFFFC00;			L2addr = (L2addr | ((virt_addr & 0x000FF000) >> 10)) & ~3;			MEM_READ_WORD (L2addr, &L2desc);			entry.virt_addr = virt_addr;			entry.phys_addr = L2desc;			entry.perms = L2desc & 0x00000FFC;			entry.domain = (L1desc >> 5) & 0x0000000F;			ap[3]=(entry.perms>>10) & 3;			ap[2]=(entry.perms>>8) & 3;			ap[1]=(entry.perms>>6) & 3;			ap[0]=(entry.perms>>4) & 3;			switch (L2desc & 3) {				case 0:					last_domain = entry.domain;					return PAGE_TRANSLATION_FAULT;				case 3:					if (emu->is_xscale()) {						entry.mapping = TLB_ESMALLPAGE;	//xj						break;					}					else {						last_domain = entry.domain;						return PAGE_TRANSLATION_FAULT;					}				case 1:					entry.mapping = TLB_LARGEPAGE;					/*check every sub-page ap-bit in order to group into 					one ap-bit*/					if(ap[3] != ap[2] || ap[2]!=ap[1] || ap[1] != ap[0] ) {						fast_access =0;						}					break;				case 2:					entry.mapping = TLB_SMALLPAGE;					/*check every sub-page ap-bit in order to group into 					one ap-bit*/					if(ap[3] != ap[2] || ap[2]!=ap[1] || ap[1] != ap[0] ) {						fast_access =0;						}					break;				}		}		break;	case 2:		/* section */		entry.virt_addr = virt_addr;		entry.phys_addr = L1desc;		entry.perms = L1desc & 0x00000C0C;		entry.domain = (L1desc >> 5) & 0x0000000F;		entry.mapping = TLB_SECTION;		break;	}	entry.mask = tlb_masks[entry.mapping];  	/*		Masking bits for both physical address and virtual address consumes 	more time. The better way is to subtract physical page-base with 	virtual page-base before hand and the time to convert address will 	be less 		The non-optimized function should be like this code.		entry.nmask = ~tlb_masks[entry.mapping];  	entry.phys_addr &= entry.mask;	*/	entry.phys_addr = (entry.phys_addr & entry.mask) -						(entry.virt_addr & entry.mask); 	/*	Compute the memory access permision of this tlb entry(page entry)	for both read access and write access	*/	evaluate_access_entry(fast_access,&entry);	/* commit the change */	*tlb_e = entry;	return NO_FAULT;}void arm_mmu::evaluate_access_all(void){ 		int fast_access;	tlb_entry_t *tlb_e;			FLUSH_MMU_PAGE_TABLE(i_table);			FLUSH_MMU_PAGE_TABLE(d_table);						/*Compute the memory access permision of all entries in ITLB*/	for(int i=0;i< MMU_ITLB_SIZE;i++) {		tlb_e =i_tlb->get_entry(i);		fast_access =1;			if (tlb_e->mapping == TLB_INVALID) continue;		else if (tlb_e->read_fault == SLOW_ACCESS_CHECKING) fast_access = 0;				evaluate_access_entry(fast_access,tlb_e);	}		/*Compute the memory access permision of all entries in ITLB*/	for(int i=0;i< MMU_DTLB_SIZE ;i++) {		tlb_e =d_tlb->get_entry(i);		fast_access =1;			if (tlb_e->mapping == TLB_INVALID) continue;		else if (tlb_e->read_fault == SLOW_ACCESS_CHECKING) fast_access = 0;				evaluate_access_entry(fast_access,tlb_e);	}}void arm_mmu::evaluate_access_entry (int fast_access,tlb_entry_t *tlb_e){	if (tlb_e->mapping == TLB_INVALID) return;	if (fast_access) {	/*fast access checking means that this page has one ap-bit 	  or same ap-bit for each sub-page*/		tlb_e->read_fault = check_access(0,tlb_e,MMU_READ);		tlb_e->write_fault = check_access(0,tlb_e,MMU_WRITE);	}	else{	/*slow access checking means that this page has difference	  ap-bit for each sub-page*/		tlb_e->read_fault = SLOW_ACCESS_CHECKING;		tlb_e->write_fault = SLOW_ACCESS_CHECKING;					}}word_t arm_mmu::xscale_mrc (word_t instr){	word_t data;	unsigned creg = (instr>>16)&15;	unsigned opcode_2 = (instr>>5)&7;	//unsigned CRm = (instr>>0)&15;		switch (creg) {		case MMU_ID:			data = (opcode_2 ? cache_type : emu->get_cpu_id());			break;		case MMU_CONTROL:			data = (opcode_2 ? aux_control : control);			break;		case MMU_TRANSLATION_TABLE_BASE:			data = translation_table_base;			break;		case MMU_DOMAIN_ACCESS_CONTROL:			data = domain_access_control;			break;		case MMU_FAULT_STATUS:			data = fault_status;			break;		case MMU_FAULT_ADDRESS:			data = fault_address;			break;		case MMU_PID:			data = process_id;			break; //no break in Skyeye		case XSCALE_CP15_COPRO_ACCESS:			//printf("xscale cp15 read coprocessor access\n");			data = copro_access;			break;		default:			data = 0;			fprintf (stderr, "cp15_mrc read UNKNOWN - reg %d, pc 0x\n", creg);			exit (-1);			break;	}	return data;}void arm_mmu::xscale_mcr(word_t instr, word_t value){	unsigned opcode_2 = (instr>>5)&7;	unsigned CRm = (instr>>0)&15;	unsigned creg = (instr>>16)&15;	switch (creg) {		case MMU_CONTROL:			set_control(opcode_2 ? (value & 0x33) : (value & 0x3FFF));			break;		case MMU_TRANSLATION_TABLE_BASE:			translation_table_base = value & 0xFFFFC000;			FLUSH_MMU_PAGE_TABLE(i_table);					FLUSH_MMU_PAGE_TABLE(d_table);								break;		case MMU_DOMAIN_ACCESS_CONTROL:			set_domain_access_control(value);			break;		case MMU_FAULT_STATUS:			fault_status = value & 0x6FF;			break;		case MMU_FAULT_ADDRESS:			fault_address = value;			break;		case MMU_CACHE_OPS:			/*cache is not implemented*/			//xscale_cp15_cache_ops (state, instr, value);			break;		case MMU_TLB_OPS:			invalidate_tlb(opcode_2,CRm,value);					break;		case MMU_PID:			set_process_id(value);			break;		case XSCALE_CP15_COPRO_ACCESS:			//printf("xscale cp15 write coprocessor access  val 0x %x\n",value);			copro_access = value & 0x3ff;			break;		default:			fprintf(stderr,				"cp15_mcr wrote UNKNOWN - reg %d, reg15 0x\n", creg);			break;	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -