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

📄 armmmu.cpp

📁 這是一個arm模擬器 以C++實做 主要模擬ARM9架構
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*************************************************************************    Copyright (C) 2002 - 2007 Wei Qin    See file COPYING for more information.    This program is free software; you can redistribute it and/or modify        it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.*************************************************************************//*    armmmu.c - Memory Management Unit emulation.    ARMulator extensions for the ARM7100 family.    Copyright (C) 1999  Ben Williamson    This program is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation; either version 2 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program; if not, write to the Free Software    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA*/#include "armmmu.h"#include "arm_io.h"#include <cassert>#include <cstring>#include <iostream>#include <csignal>/*Macro defines for MMU state*/#define MMU_CTL       (control)#define MMU_Enabled   (control & CONTROL_MMU)#define MMU_Disabled  (!(MMU_Enabled))#define MMU_Aligned   (control & CONTROL_ALIGN_FAULT)#define MMU_ICacheEnabled  (MMU_CTL & CONTROL_INSTRUCTION_CACHE)#define MMU_ICacheDisabled (!(MMU_ICacheDisabled))#define MMU_DCacheEnabled  (MMU_CTL & CONTROL_DATA_CACHE)#define MMU_DCacheDisabled (!(MMU_DCacheEnabled))#define MMU_CacheEnabled   (MMU_CTL & CONTROL_CACHE)#define MMU_CacheDisabled  (!(MMU_CacheEnabled))#define MMU_WBEnabled      (MMU_CTL & CONTROL_WRITE_BUFFER)#define MMU_WBDisabled     (!(MMU_WBEnabled))#define FLUSH_MMU_PAGE_TABLE(a_) \	memset(a_, 0xff, (sizeof(mmu_page_table_entry_t) * MMU_HASH_SIZE))#define FLUSH_MMU_PAGE_ENTRY(a_) \	memset(a_, 0xff, sizeof(mmu_page_table_entry_t))using namespace simit;static word_t tlb_masks[] = {	0x00000000,		/* TLB_INVALID */	0xFFFFF000,		/* TLB_SMALLPAGE */	0xFFFF0000,		/* TLB_LARGEPAGE */	0xFFF00000,		/* TLB_SECTION */	0xFFFFF000,		/* TLB_ESMALLPAGE, have TEX attirbute, only for XScale */	0xFFFFFC00		/* TLB_TINYPAGE */};		static word_t tlb_va_to_pa(tlb_entry_t * tlb_e, word_t va) {	/*		The non-optimized function should be like this code. For more 	information see the code at the bottom of translation_walk function.		return (tlb_e->phys_addr & tlb_e->mask) | (va & tlb_e->nmask);	*/	return tlb_e->phys_addr + va;}arm_mmu::arm_mmu (arm_emulator *emula) : emu(emula) {	i_tlb = new tlb<MMU_ITLB_SIZE>;	d_tlb = new tlb<MMU_DTLB_SIZE>;	/* suppress valgrind complaints */	control = 0;	rs_flag = 0;	domain_access_control = 0;		set_control(0x70);    set_domain_access_control( 0xDEADC0DE);    translation_table_base = 0xDEADC0DE;    fault_status = 0;    fault_address = 0;    process_id = 0;		fault_count = 0;	dummy_entry.mapping = TLB_SMALLPAGE;	dummy_entry.read_fault = NO_FAULT;	dummy_entry.write_fault = NO_FAULT;		register_write_checker(NULL,NULL,NULL);}arm_mmu::~arm_mmu () {	delete i_tlb;	delete d_tlb;}void arm_mmu::reset () {	i_tlb->reset();	d_tlb->reset();}		/*set the value of control register*/void arm_mmu::set_control(word_t value) {		if( (control &1) != (value & 1)) {		FLUSH_MMU_PAGE_TABLE(i_table);				FLUSH_MMU_PAGE_TABLE(d_table);			}					if(rs_flag !=( (value >> 7) & 6) ) {		rs_flag =( (value >> 7) & 6);		evaluate_access_all();	}				if (MMU_Aligned) {		mask_array[MMU_BYTE - 1] = MMU_HASH_MASK;		mask_array[MMU_HALF - 1] = 0xFFFFF001;		mask_array[MMU_WORD - 1] = 0xFFFFF003;	}	else{		mask_array[MMU_BYTE - 1] = MMU_HASH_MASK;		mask_array[MMU_HALF - 1] = MMU_HASH_MASK;		mask_array[MMU_WORD - 1] = MMU_HASH_MASK;	}		control = value;}void arm_mmu::set_process_id (word_t value){	value &= MMU_PID_VA_MAP_MASK;	if (process_id != value) {		process_id = value;		int i;		for(i=0; i < MMU_HASH_SIZE; i++)			if ( ( i_table[i].phys_addr != 0xFFFFFFFF) &&				 ( (i_table[i].read_tag & MMU_PID_VA_MAP_MASK) == 0 ||					(i_table[i].write_tag & MMU_PID_VA_MAP_MASK) == 0 ))				FLUSH_MMU_PAGE_ENTRY(&i_table[i]);		for(i=0; i < MMU_HASH_SIZE; i++)			if ( ( d_table[i].phys_addr != 0xFFFFFFFF) &&				 ( (d_table[i].read_tag & MMU_PID_VA_MAP_MASK) == 0 ||					(d_table[i].write_tag & MMU_PID_VA_MAP_MASK) == 0 ))				FLUSH_MMU_PAGE_ENTRY(&d_table[i]);					}}	void arm_mmu::add_mmu_page_entry(mmu_page_table_entry_t *x_table,	tlb_entry_t *tlb_e,word_t phys_addr,word_t virt_addr){	byte_t *ptr = emu->mem->translate(phys_addr); 	if (ptr != NULL && tlb_e->mapping != TLB_TINYPAGE) {		mmu_page_table_entry_t *pte = x_table + MMU_HASH_INDEX(virt_addr);				if (tlb_e->read_fault == NO_FAULT)			pte->read_tag = (virt_addr & MMU_HASH_MASK);		else 			pte->read_tag = 0xffffffff;				if (x_table == d_table) {			if (tlb_e->write_fault == NO_FAULT)				pte->write_tag = (virt_addr & MMU_HASH_MASK);			else 				pte->write_tag = 0xffffffff;			if(fcheck && fcheck(wchecker, phys_addr))				pte->write_tag = 0xffffffff;		}		pte->phys_addr = (phys_addr & MMU_HASH_MASK) - (virt_addr & MMU_HASH_MASK);		pte->ptr =	ptr + (phys_addr & MMU_HASH_MASK); //get host address 		pte->ptr -= (virt_addr & MMU_HASH_MASK); //prepare to converse virtual address to host address			}}		void arm_mmu::remove_mmu_page_entry(mmu_page_table_entry_t *x_table,	tlb_entry_t *tlb_e){	FLUSH_MMU_PAGE_ENTRY(x_table + MMU_HASH_INDEX(tlb_e->virt_addr));	if (tlb_e->mapping == TLB_SECTION || tlb_e->mapping == TLB_LARGEPAGE)		FLUSH_MMU_PAGE_TABLE(x_table);			/*		for(int i=0; i < MMU_HASH_SIZE; i++)			if ( x_table[i].phys_addr != 0xFFFFFFFF)				if ( ( (x_table[i].read_tag & tlb_e->mask) == tlb_e->virt_addr)				||( (x_table[i].write_tag & tlb_e->mask) == tlb_e->virt_addr) )   				FLUSH_MMU_PAGE_ENTRY(x_table + i);	*/			}		#ifdef RECORD_TLB_MISS			#define D_TRANS(_a, _e) \	if ((_e=d_tlb->search(_a))==NULL) {\		_e = d_tlb->next();\		remove_mmu_page_entry(d_table,_e);\		fault = translation_walk(_a, _e); \	} \	else \		fault = NO_FAULT;		#define I_TRANS(_a, _e) \	if ((_e=i_tlb->search(_a))==NULL) {\		_e = i_tlb->next();\		remove_mmu_page_entry(i_table,_e);\		fault = translation_walk(_a, _e); \	} \	else \		fault = NO_FAULT;#else#define D_TRANS(_a, _e) \	if ((_e=d_tlb->search(_a))==NULL) {\		_e = d_tlb->next(),	fault = translation_walk(_a, _e); \	} \	else \		fault = NO_FAULT;		#define I_TRANS(_a, _e) \	if ((_e=i_tlb->search(_a))==NULL) {\		_e = i_tlb->next(),	fault = translation_walk(_a, _e); \	} \	else \		fault = NO_FAULT;#endifmmu_fault_t arm_mmu::translate_data_addr_slow (word_t virt_addr,	mmu_access_t read, mmu_size_t size, word_t *phys_addr){	mmu_fault_t fault;	tlb_entry_t *entry;	word_t va = mmu_pid_va_map (virt_addr);		if (MMU_Disabled) {		*phys_addr = va;				/*Cache Translation Process*/		add_mmu_page_entry(d_table ,&dummy_entry,*phys_addr,virt_addr);			return NO_FAULT;	}	if (MMU_Aligned && (va & (size-1))) {		return ALIGNMENT_FAULT;	}	/*Search for maching TLB entry*/	D_TRANS(va, entry);	if (fault) {/*Translation fault*/		return fault;	}	/*Check access permission*/	fault = (read == MMU_READ)? entry->read_fault : entry->write_fault;	if (fault) {		fault = check_access(va, entry, read);		if(fault) {/*Access fault*/			return fault;		}	}	/*Convert virtual address to physical address*/	*phys_addr = tlb_va_to_pa (entry, va);		/*Cache Translation Process*/	add_mmu_page_entry(d_table,entry,*phys_addr,virt_addr);		return NO_FAULT;}	mmu_fault_t arm_mmu::read_byte_slow (word_t virt_addr, byte_t * data){	mmu_fault_t fault;    word_t pa;	fault = translate_data_addr_slow (virt_addr, MMU_READ, MMU_BYTE, &pa);	if (fault) {		update_fsr_far (fault,virt_addr);		return fault;	}	MEM_READ_BYTE(pa, data);	return NO_FAULT;}mmu_fault_t arm_mmu::read_hword_slow (word_t virt_addr, hword_t *data){	mmu_fault_t fault;    word_t pa;	fault = translate_data_addr_slow (virt_addr, MMU_READ, MMU_HALF, &pa);	if (fault) { 		update_fsr_far (fault,virt_addr);		return fault;	}	MEM_READ_HALF_WORD(pa, data);	return NO_FAULT;}mmu_fault_t arm_mmu::read_word_slow	(word_t virt_addr, word_t * data){	mmu_fault_t fault;    word_t pa;	fault = translate_data_addr_slow (virt_addr, MMU_READ, MMU_WORD, &pa);	if (fault) {		update_fsr_far (fault,virt_addr);		return fault;	}	MEM_READ_WORD(pa, data);	return NO_FAULT;}mmu_fault_t arm_mmu::write_byte_slow	(word_t virt_addr, byte_t data){	mmu_fault_t fault;    word_t pa;	fault = translate_data_addr_slow (virt_addr, MMU_WRITE, MMU_BYTE, &pa);	if (fault) { 		update_fsr_far (fault,virt_addr);		return fault;	}	if(falarm && falarm(wchecker, pa)) {		return JIT_ALARM_FAULT;	}		MEM_WRITE_BYTE(pa, data);	return NO_FAULT;}mmu_fault_t arm_mmu::write_hword_slow	(word_t virt_addr, hword_t data){	mmu_fault_t fault;    word_t pa;	fault = translate_data_addr_slow (virt_addr, MMU_WRITE, MMU_HALF, &pa);	if (fault) { 		update_fsr_far (fault,virt_addr);		return fault;	}	if(falarm && falarm(wchecker, pa)) {		return JIT_ALARM_FAULT;	}		MEM_WRITE_HALF_WORD(pa, data);	return NO_FAULT;}mmu_fault_t arm_mmu::write_word_slow	(word_t virt_addr, word_t data){	mmu_fault_t fault;    word_t pa;	fault = translate_data_addr_slow (virt_addr, MMU_WRITE, MMU_WORD, &pa);	if (fault) { 		update_fsr_far (fault,virt_addr);		return fault;	}	if(falarm && falarm(wchecker, pa)) {		return JIT_ALARM_FAULT;	}		MEM_WRITE_WORD (pa, data);	return NO_FAULT;}mmu_fault_t arm_mmu::translate_instr_addr_slow (word_t virt_addr, word_t *phys_addr){	mmu_fault_t fault;    tlb_entry_t *entry; 	word_t va = mmu_pid_va_map (virt_addr);		if (MMU_Disabled) {		*phys_addr = va;		add_mmu_page_entry(i_table,&dummy_entry,*phys_addr,virt_addr);		return NO_FAULT;	}	/*Search for maching TLB entry*/	I_TRANS(va, entry);	if (fault) {/*Translation fault*/		return fault;	}	/*Check read access permission*/	if (entry->read_fault) {		fault = check_access(va, entry, MMU_READ);		if(fault) {/*access fault*/			return fault;		}	}	/*Convert virtual address to physical address*/	*phys_addr = tlb_va_to_pa (entry, va);	/*Cache Translation Process*/	add_mmu_page_entry(i_table,entry,*phys_addr,virt_addr);	return NO_FAULT;}mmu_fault_t arm_mmu::load_instr_slow (word_t virt_addr, word_t * instr){	mmu_fault_t fault;    word_t pa;	fault = translate_instr_addr_slow (virt_addr, &pa);	if (fault) return fault;	MEM_READ_WORD(pa, instr);	return NO_FAULT;}word_t arm_mmu::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 =  emu->get_cpu_id();			break;		case MMU_CONTROL:			data =  control;			break;

⌨️ 快捷键说明

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