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

📄 cache.c

📁 模拟嵌入式硬件平台的软件源代码
💻 C
字号:
#include "armdefs.h"/* mmu cache init * * @cache_t :cache_t to init * @width	:cache line width in byte * @way		:way of each cache set * @set		:cache set num * * $ -1: error * 	 0: sucess */intmmu_cache_init(cache_t *cache_t, int width, int way, int set, int w_mode){	int i,j;	cache_set_t *sets;	cache_line_t *lines;	/*alloc cache set*/	sets= NULL;	lines=NULL;	//fprintf(stderr, "mmu_cache_init: mallloc beg size %d,sets 0x%x\n", sizeof(cache_set_t) * set,sets);	//exit(-1);   	sets = (cache_set_t *)malloc(sizeof(cache_set_t) * set);	if (sets == NULL){		err_msg("set malloc\n");		goto sets_error;	}	//fprintf(stderr, "mmu_cache_init: mallloc end sets 0x%x\n", sets);	cache_t->sets = sets;	/*init cache set*/	for (i = 0; i < set; i++){		/*alloc cache line*/		lines = (cache_line_t *)malloc(sizeof(cache_line_t) * way);		if (lines == NULL){			err_msg("line malloc\n");			goto lines_error;		}		/*init cache line*/		for (j = 0; j < way; j++){			lines[j].tag = 0;	//invalid			lines[j].data = (ARMword *)malloc(width);			if (lines[j].data == NULL){				err_msg("data alloc\n");				goto data_error;			}		}		sets[i].lines = lines;		sets[i].cycle = 0;	}	cache_t->width = width;	cache_t->set = set;	cache_t->way = way;	cache_t->w_mode = w_mode;	return 0;data_error:	/*free data*/	while(j-- > 0)		free(lines[j].data);	/*free data error line*/	free(lines);lines_error:	/*free lines already alloced*/	while(i-- > 0){		for(j = 0; j < way; j++)			free(sets[i].lines[j].data);		free(sets[i].lines);	}	/*free sets*/	free(sets);sets_error:	return -1;};/* free a cache_t's inner data, the ptr self is not freed, * when needed do like below: * 		mmu_cache_exit(cache); * 		free(cache_t); * * @cache_t : the cache_t to free */voidmmu_cache_exit(cache_t *cache_t){	int i, j;	cache_set_t *sets, *set;	cache_line_t *lines, *line;	/*free all set*/	sets = cache_t->sets;	for (set = sets, i = 0; i < cache_t->set; i++, set++){		/*free all line*/		lines = set->lines;		for (line = lines, j = 0; j < cache_t->way; j++, line++)			free(line->data);		free(lines);	}	free(sets);}/* mmu cache search * * @state	:ARMul_State * @cache_t	:cache_t to search * @va		:virtual address * * $	NULL:	no cache match * 		cache	:cache matched */cache_line_t *mmu_cache_search(ARMul_State *state, cache_t *cache_t, ARMword va){	int i;	int set = va_cache_set(va, cache_t);	ARMword tag = va_cache_align(va, cache_t);	cache_line_t *cache;	cache_set_t *cache_set = cache_t->sets + set;	for (i = 0, cache = cache_set->lines; i < cache_t->way; i++, cache++){		if ((cache->tag & TAG_VALID_FLAG)			&& (tag == va_cache_align(cache->tag, cache_t)))			return cache;	}	return NULL;}/* mmu cache search by set/index * * @state	:ARMul_State * @cache_t	:cache_t to search * @index	:set/index value.  * * $	NULL:	no cache match * 		cache	:cache matched */cache_line_t *mmu_cache_search_by_index(ARMul_State *state, cache_t *cache_t, ARMword index){	int way = cache_t->way;	int set_v = index_cache_set(index, cache_t);	int i = 0, index_v = 0;	cache_set_t *set;	while((way >>= 1) >= 1)		i++;	index_v = index >> (32 - i);	set = cache_t->sets + set_v;	return set->lines + index_v;}/* mmu cache alloc * * @state :ARMul_State * @cache_t	:cache_t to alloc from * @va		:virtual address that require cache alloc, need not cache aligned * @pa		:physical address of va * * $	cache_alloced, always alloc OK */cache_line_t *mmu_cache_alloc(ARMul_State *state, cache_t *cache_t, ARMword va, ARMword pa){	cache_line_t *cache;	cache_set_t *set;	int i;	va = va_cache_align(va, cache_t);	pa = va_cache_align(pa, cache_t);	set = &cache_t->sets[va_cache_set(va, cache_t)];	/*robin-round*/	cache = &set->lines[set->cycle++];	if (set->cycle == cache_t->way)		set->cycle = 0;	if (cache_t->w_mode == CACHE_WRITE_BACK){		ARMword t;				/*if cache valid, try to write back*/		if (cache->tag & TAG_VALID_FLAG){			mmu_cache_write_back(state, cache_t, cache);		}		/*read in cache_line*/		t = pa;		for (i = 0; i < (cache_t->width >> WORD_SHT); i++, t+= WORD_SIZE){			cache->data[i] = mem_read_word(state, t);		}	}	/*store tag and pa*/	cache->tag = va | TAG_VALID_FLAG;	cache->pa = pa;		return cache;};/* mmu_cache_write_back write cache data to memory * @state * @cache_t :cache_t of the cache line * @cache : cache line */voidmmu_cache_write_back(ARMul_State *state, cache_t *cache_t, cache_line_t *cache){	ARMword pa = cache->pa;	int		nw = cache_t->width >> WORD_SHT;	ARMword	*data = cache->data;	int i;	int t0, t1, t2;		if ((cache->tag & 1) == 0)		return;		switch(cache->tag & ~1 & (TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY)){		case 0:			return;		case TAG_FIRST_HALF_DIRTY:			nw /= 2;			break;		case TAG_LAST_HALF_DIRTY:			nw  /= 2;			pa += nw << WORD_SHT;			data += nw;			break;		case TAG_FIRST_HALF_DIRTY|TAG_LAST_HALF_DIRTY:			break;	}	for (i = 0; i < nw; i++, data++, pa += WORD_SIZE)		mem_write_word(state, pa, *data);	cache->tag &= ~(TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY);};/* mmu_cache_clean: clean a cache of va in cache_t * * @state	:ARMul_State * @cache_t	:cache_t to clean * @va		:virtaul address */voidmmu_cache_clean(ARMul_State *state, cache_t *cache_t, ARMword va){	cache_line_t *cache;	cache = mmu_cache_search(state, cache_t, va);	if (cache)		mmu_cache_write_back(state, cache_t, cache);}/* mmu_cache_clean_by_index: clean a cache by set/index format value * * @state	:ARMul_State * @cache_t	:cache_t to clean * @va		:set/index format value */voidmmu_cache_clean_by_index(ARMul_State *state, cache_t *cache_t, ARMword index){	cache_line_t *cache;	cache = mmu_cache_search_by_index(state, cache_t, index);	if (cache)		mmu_cache_write_back(state, cache_t, cache);}/* mmu_cache_invalidate : invalidate a cache of va * * @state	:ARMul_State * @cache_t	:cache_t to invalid * @va		:virt_addr to invalid */voidmmu_cache_invalidate(ARMul_State *state, cache_t *cache_t, ARMword va){	cache_line_t *cache;	cache = mmu_cache_search(state, cache_t, va);	if (cache){		mmu_cache_write_back(state, cache_t, cache);		cache->tag = 0;	}}/* mmu_cache_invalidate_by_index : invalidate a cache by index format * * @state	:ARMul_State * @cache_t	:cache_t to invalid * @index	:set/index data */voidmmu_cache_invalidate_by_index(ARMul_State *state, cache_t *cache_t, ARMword index){	cache_line_t *cache;	cache = mmu_cache_search_by_index(state, cache_t, index);	if (cache){		mmu_cache_write_back(state, cache_t, cache);		cache->tag = 0;	}}/* mmu_cache_invalidate_all * * @state: * @cache_t * */voidmmu_cache_invalidate_all(ARMul_State *state, cache_t *cache_t){	int i,j;	cache_set_t *set;	cache_line_t *cache;	set = cache_t->sets;	for (i = 0; i < cache_t->set; i++, set++){		cache = set->lines;		for (j = 0; j < cache_t->way; j++, cache++){			mmu_cache_write_back(state, cache_t, cache);			cache->tag = 0;		}	}};voidmmu_cache_soft_flush(ARMul_State *state, cache_t *cache_t, ARMword pa){	ARMword set, way;	cache_line_t *cache;	pa = (pa / cache_t->width);	way = pa & (cache_t->way - 1);	set = (pa / cache_t->way) & (cache_t->set - 1);	cache = &cache_t->sets[set].lines[way];		mmu_cache_write_back(state, cache_t, cache);	cache->tag = 0;}

⌨️ 快捷键说明

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