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

📄 cache.h

📁 DOSBox emulates a full x86 pc with sound and dos. Its main use is to run old dosgames on platforms w
💻 H
字号:
class CacheBlock {public:	void Clear(void);	void LinkTo(Bitu index,CacheBlock * toblock) {		assert(toblock);		link[index].to=toblock;		link[index].next=toblock->link[index].from;		toblock->link[index].from=this;	}	struct {		Bit16u start,end;				//Where the page is the original code		CodePageHandler * handler;		//Page containing this code	} page;	struct {		Bit8u * start;					//Where in the cache are we		Bitu size;		CacheBlock * next;		Bit8u * wmapmask;		Bit16u maskstart;		Bit16u masklen;	} cache;	struct {		Bitu index;		CacheBlock * next;	} hash;	struct {		CacheBlock * to;		CacheBlock * next;		CacheBlock * from;	} link[2];	CacheBlock * crossblock;};static struct {	struct {		CacheBlock * first;		CacheBlock * active;		CacheBlock * free;		CacheBlock * running;	} block;	Bit8u * pos;	CodePageHandler * free_pages;	CodePageHandler * used_pages;	CodePageHandler * last_page;} cache;static CacheBlock link_blocks[2];class CodePageHandler : public PageHandler {public:	CodePageHandler() {		invalidation_map=NULL;	}	void SetupAt(Bitu _phys_page,PageHandler * _old_pagehandler) {		phys_page=_phys_page;		old_pagehandler=_old_pagehandler;		flags=old_pagehandler->flags|PFLAG_HASCODE;		flags&=~PFLAG_WRITEABLE;		active_blocks=0;		active_count=16;		memset(&hash_map,0,sizeof(hash_map));		memset(&write_map,0,sizeof(write_map));		if (invalidation_map!=NULL) {			free(invalidation_map);			invalidation_map=NULL;		}	}	bool InvalidateRange(Bitu start,Bitu end) {		Bits index=1+(start>>DYN_HASH_SHIFT);		bool is_current_block=false;		Bit32u ip_point=SegPhys(cs)+reg_eip;		ip_point=((paging.tlb.phys_page[ip_point>>12]-phys_page)<<12)+(ip_point&0xfff);		while (index>=0) {			Bitu map=0;			for (Bitu count=start;count<=end;count++) map+=write_map[count];			if (!map) return is_current_block;			CacheBlock * block=hash_map[index];			while (block) {				CacheBlock * nextblock=block->hash.next;				if (start<=block->page.end && end>=block->page.start) {					if (ip_point<=block->page.end && ip_point>=block->page.start) is_current_block=true;					block->Clear();				}				block=nextblock;			}			index--;		}		return is_current_block;	}	void writeb(PhysPt addr,Bitu val){		addr&=4095;		if (host_readb(hostmem+addr)==(Bit8u)val) return;		host_writeb(hostmem+addr,val);		if (!*(Bit8u*)&write_map[addr]) {			if (active_blocks) return;			active_count--;			if (!active_count) Release();			return;		} else if (!invalidation_map) {			invalidation_map=(Bit8u*)malloc(4096);			memset(invalidation_map,0,4096);		}		invalidation_map[addr]++;		InvalidateRange(addr,addr);	}	void writew(PhysPt addr,Bitu val){		addr&=4095;		if (host_readw(hostmem+addr)==(Bit16u)val) return;		host_writew(hostmem+addr,val);		if (!*(Bit16u*)&write_map[addr]) {			if (active_blocks) return;			active_count--;			if (!active_count) Release();			return;		} else if (!invalidation_map) {			invalidation_map=(Bit8u*)malloc(4096);			memset(invalidation_map,0,4096);		}		(*(Bit16u*)&invalidation_map[addr])+=0x101;		InvalidateRange(addr,addr+1);	}	void writed(PhysPt addr,Bitu val){		addr&=4095;		if (host_readd(hostmem+addr)==(Bit32u)val) return;		host_writed(hostmem+addr,val);		if (!*(Bit32u*)&write_map[addr]) {			if (active_blocks) return;			active_count--;			if (!active_count) Release();			return;		} else if (!invalidation_map) {			invalidation_map=(Bit8u*)malloc(4096);			memset(invalidation_map,0,4096);		}		(*(Bit32u*)&invalidation_map[addr])+=0x1010101;		InvalidateRange(addr,addr+3);	}	bool writeb_checked(PhysPt addr,Bitu val) {		addr&=4095;		if (host_readb(hostmem+addr)==(Bit8u)val) return false;		if (!*(Bit8u*)&write_map[addr]) {			if (!active_blocks) {				active_count--;				if (!active_count) Release();			}		} else {			if (!invalidation_map) {				invalidation_map=(Bit8u*)malloc(4096);				memset(invalidation_map,0,4096);			}			invalidation_map[addr]++;			if (InvalidateRange(addr,addr)) {				cpu.exception.which=SMC_CURRENT_BLOCK;				return true;			}		}		host_writeb(hostmem+addr,val);		return false;	}	bool writew_checked(PhysPt addr,Bitu val) {		addr&=4095;		if (host_readw(hostmem+addr)==(Bit16u)val) return false;		if (!*(Bit16u*)&write_map[addr]) {			if (!active_blocks) {				active_count--;				if (!active_count) Release();			}		} else {			if (!invalidation_map) {				invalidation_map=(Bit8u*)malloc(4096);				memset(invalidation_map,0,4096);			}			(*(Bit16u*)&invalidation_map[addr])+=0x101;			if (InvalidateRange(addr,addr+1)) {				cpu.exception.which=SMC_CURRENT_BLOCK;				return true;			}		}		host_writew(hostmem+addr,val);		return false;	}	bool writed_checked(PhysPt addr,Bitu val) {		addr&=4095;		if (host_readd(hostmem+addr)==(Bit32u)val) return false;		if (!*(Bit32u*)&write_map[addr]) {			if (!active_blocks) {				active_count--;				if (!active_count) Release();			}		} else {			if (!invalidation_map) {				invalidation_map=(Bit8u*)malloc(4096);				memset(invalidation_map,0,4096);			}			(*(Bit32u*)&invalidation_map[addr])+=0x1010101;			if (InvalidateRange(addr,addr+3)) {				cpu.exception.which=SMC_CURRENT_BLOCK;				return true;			}		}		host_writed(hostmem+addr,val);		return false;	}    void AddCacheBlock(CacheBlock * block) {		Bitu index=1+(block->page.start>>DYN_HASH_SHIFT);		block->hash.next=hash_map[index];		block->hash.index=index;		hash_map[index]=block;		block->page.handler=this;		active_blocks++;	}    void AddCrossBlock(CacheBlock * block) {		block->hash.next=hash_map[0];		block->hash.index=0;		hash_map[0]=block;		block->page.handler=this;		active_blocks++;	}	void DelCacheBlock(CacheBlock * block) {		active_blocks--;		active_count=16;		CacheBlock * * where=&hash_map[block->hash.index];		while (*where!=block) {			where=&((*where)->hash.next);			//Will crash if a block isn't found, which should never happen.		}		*where=block->hash.next;		if (GCC_UNLIKELY(block->cache.wmapmask!=NULL)) {			for (Bitu i=block->page.start;i<block->cache.maskstart;i++) {				if (write_map[i]) write_map[i]--;			}			Bitu maskct=0;			for (Bitu i=block->cache.maskstart;i<=block->page.end;i++,maskct++) {				if (write_map[i]) {					if ((maskct>=block->cache.masklen) || (!block->cache.wmapmask[maskct])) write_map[i]--;				}			}			free(block->cache.wmapmask);			block->cache.wmapmask=NULL;		} else {			for (Bitu i=block->page.start;i<=block->page.end;i++) {				if (write_map[i]) write_map[i]--;			}		}	}	void Release(void) {		MEM_SetPageHandler(phys_page,1,old_pagehandler);		PAGING_ClearTLB();		if (prev) prev->next=next;		else cache.used_pages=next;		if (next) next->prev=prev;		else cache.last_page=prev;		next=cache.free_pages;		cache.free_pages=this;		prev=0;	}	void ClearRelease(void) {		for (Bitu index=0;index<(1+DYN_PAGE_HASH);index++) {			CacheBlock * block=hash_map[index];			while (block) {				CacheBlock * nextblock=block->hash.next;				block->page.handler=0;			//No need, full clear				block->Clear();				block=nextblock;			}		}		Release();	}	CacheBlock * FindCacheBlock(Bitu start) {		CacheBlock * block=hash_map[1+(start>>DYN_HASH_SHIFT)];		while (block) {			if (block->page.start==start) return block;			block=block->hash.next;		}		return 0;	}	HostPt GetHostReadPt(Bitu phys_page) { 		hostmem=old_pagehandler->GetHostReadPt(phys_page);		return hostmem;	}	HostPt GetHostWritePt(Bitu phys_page) { 		return GetHostReadPt( phys_page );	}public:	Bit8u write_map[4096];	Bit8u * invalidation_map;	CodePageHandler * next, * prev;private:	PageHandler * old_pagehandler;	CacheBlock * hash_map[1+DYN_PAGE_HASH];	Bitu active_blocks;	Bitu active_count;	HostPt hostmem;		Bitu phys_page;};static INLINE void cache_addunsedblock(CacheBlock * block) {	block->cache.next=cache.block.free;	cache.block.free=block;}static CacheBlock * cache_getblock(void) {	CacheBlock * ret=cache.block.free;	if (!ret) E_Exit("Ran out of CacheBlocks" );	cache.block.free=ret->cache.next;	ret->cache.next=0;	return ret;}void CacheBlock::Clear(void) {	Bitu ind;	/* Check if this is not a cross page block */	if (hash.index) for (ind=0;ind<2;ind++) {		CacheBlock * fromlink=link[ind].from;		link[ind].from=0;		while (fromlink) {			CacheBlock * nextlink=fromlink->link[ind].next;			fromlink->link[ind].next=0;			fromlink->link[ind].to=&link_blocks[ind];			fromlink=nextlink;		}		if (link[ind].to!=&link_blocks[ind]) {			CacheBlock * * wherelink=&link[ind].to->link[ind].from;			while (*wherelink != this && *wherelink) {				wherelink = &(*wherelink)->link[ind].next;			}			if(*wherelink) 				*wherelink = (*wherelink)->link[ind].next;			else				LOG(LOG_CPU,LOG_ERROR)("Cache anomaly. please investigate");		}	} else 		cache_addunsedblock(this);	if (crossblock) {		crossblock->crossblock=0;		crossblock->Clear();		crossblock=0;	}	if (page.handler) {		page.handler->DelCacheBlock(this);		page.handler=0;	}	if (cache.wmapmask){		free(cache.wmapmask);		cache.wmapmask=NULL;	}}static CacheBlock * cache_openblock(void) {	CacheBlock * block=cache.block.active;	/* check for enough space in this block */	Bitu size=block->cache.size;	CacheBlock * nextblock=block->cache.next;	if (block->page.handler) 		block->Clear();	while (size<CACHE_MAXSIZE) {		if (!nextblock) 			goto skipresize;		size+=nextblock->cache.size;		CacheBlock * tempblock=nextblock->cache.next;		if (nextblock->page.handler) 			nextblock->Clear();		cache_addunsedblock(nextblock);		nextblock=tempblock;	}skipresize:	block->cache.size=size;	block->cache.next=nextblock;	cache.pos=block->cache.start;	return block;}static void cache_closeblock(void) {	CacheBlock * block=cache.block.active;	block->link[0].to=&link_blocks[0];	block->link[1].to=&link_blocks[1];	block->link[0].from=0;	block->link[1].from=0;	block->link[0].next=0;	block->link[1].next=0;	/* Close the block with correct alignments */	Bitu written=cache.pos-block->cache.start;	if (written>block->cache.size) {		if (!block->cache.next) {			if (written>block->cache.size+CACHE_MAXSIZE) E_Exit("CacheBlock overrun 1 %d",written-block->cache.size);			} else E_Exit("CacheBlock overrun 2 written %d size %d",written,block->cache.size);		} else {		Bitu new_size;		Bitu left=block->cache.size-written;		/* Smaller than cache align then don't bother to resize */		if (left>CACHE_ALIGN) {			new_size=((written-1)|(CACHE_ALIGN-1))+1;			CacheBlock * newblock=cache_getblock();			newblock->cache.start=block->cache.start+new_size;			newblock->cache.size=block->cache.size-new_size;			newblock->cache.next=block->cache.next;			block->cache.next=newblock;			block->cache.size=new_size;		}	}	/* Advance the active block pointer */	if (!block->cache.next) {//		LOG_MSG("Cache full restarting");		cache.block.active=cache.block.first;	} else {		cache.block.active=block->cache.next;	}}static INLINE void cache_addb(Bit8u val) {	*cache.pos++=val;}static INLINE void cache_addw(Bit16u val) {	*(Bit16u*)cache.pos=val;	cache.pos+=2;}static INLINE void cache_addd(Bit32u val) {	*(Bit32u*)cache.pos=val;	cache.pos+=4;}static void gen_return(BlockReturn retcode);static Bit8u * cache_code_start_ptr=NULL;static Bit8u * cache_code=NULL;static Bit8u * cache_code_link_blocks=NULL;static CacheBlock * cache_blocks=NULL;/* Define temporary pagesize so the MPROTECT case and the regular case share as much code as possible */#if (C_HAVE_MPROTECT)#define PAGESIZE_TEMP PAGESIZE#else #define PAGESIZE_TEMP 4096#endifstatic bool cache_initialized = false;static void cache_init(bool enable) {	Bits i;	if (enable) {		if (cache_initialized) return;		cache_initialized = true;		if (cache_blocks == NULL) {			cache_blocks=(CacheBlock*)malloc(CACHE_BLOCKS*sizeof(CacheBlock));			if(!cache_blocks) E_Exit("Allocating cache_blocks has failed");			memset(cache_blocks,0,sizeof(CacheBlock)*CACHE_BLOCKS);			cache.block.free=&cache_blocks[0];			for (i=0;i<CACHE_BLOCKS-1;i++) {				cache_blocks[i].link[0].to=(CacheBlock *)1;				cache_blocks[i].link[1].to=(CacheBlock *)1;				cache_blocks[i].cache.next=&cache_blocks[i+1];			}		}		if (cache_code_start_ptr==NULL) {			cache_code_start_ptr=(Bit8u*)malloc(CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP);			if(!cache_code_start_ptr) E_Exit("Allocating dynamic cache failed");			cache_code=(Bit8u*)(((int)cache_code_start_ptr + PAGESIZE_TEMP-1) & ~(PAGESIZE_TEMP-1)); //MEM LEAK. store old pointer if you want to free it.			cache_code_link_blocks=cache_code;			cache_code+=PAGESIZE_TEMP;#if (C_HAVE_MPROTECT)			if(mprotect(cache_code_link_blocks,CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP,PROT_WRITE|PROT_READ|PROT_EXEC))				LOG_MSG("Setting excute permission on the code cache has failed!");#endif			CacheBlock * block=cache_getblock();			cache.block.first=block;			cache.block.active=block;			block->cache.start=&cache_code[0];			block->cache.size=CACHE_TOTAL;			block->cache.next=0;								//Last block in the list		}		/* Setup the default blocks for block linkage returns */		cache.pos=&cache_code_link_blocks[0];		link_blocks[0].cache.start=cache.pos;		gen_return(BR_Link1);		cache.pos=&cache_code_link_blocks[32];		link_blocks[1].cache.start=cache.pos;		gen_return(BR_Link2);		cache.free_pages=0;		cache.last_page=0;		cache.used_pages=0;		/* Setup the code pages */		for (i=0;i<CACHE_PAGES;i++) {			CodePageHandler * newpage=new CodePageHandler();			newpage->next=cache.free_pages;			cache.free_pages=newpage;		}	}}static void cache_close(void) {/*	for (;;) {		if (cache.used_pages) {			CodePageHandler * cpage=cache.used_pages;			CodePageHandler * npage=cache.used_pages->next;			cpage->ClearRelease();			delete cpage;			cache.used_pages=npage;		} else break;	}	if (cache_blocks != NULL) {		free(cache_blocks);		cache_blocks = NULL;	}	if (cache_code_start_ptr != NULL) {		free(cache_code_start_ptr);		cache_code_start_ptr = NULL;	}	cache_code = NULL;	cache_code_link_blocks = NULL;	cache_initialized = false; */}

⌨️ 快捷键说明

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