diff --git a/src/cpu/core_dyn_x86.cpp b/src/cpu/core_dyn_x86.cpp index e6becba8..4fa737f2 100644 --- a/src/cpu/core_dyn_x86.cpp +++ b/src/cpu/core_dyn_x86.cpp @@ -33,10 +33,11 @@ #include "paging.h" #include "inout.h" -#define CACHE_TOTAL (1024*1024*2) +#define CACHE_TOTAL (512*1024) #define CACHE_MAXSIZE (4096) -#define CACHE_BLOCKS (50*1024) +#define CACHE_BLOCKS (32*1024) #define CACHE_ALIGN (16) +#define CACHE_PAGES (128) #define DYN_HASH_SHIFT (4) #define DYN_PAGE_HASH (4096>>DYN_HASH_SHIFT) #define DYN_LINKS (16) @@ -68,8 +69,8 @@ enum DualOps { DOP_SUB,DOP_SBB, DOP_CMP,DOP_XOR, DOP_AND,DOP_OR, - DOP_MOV, DOP_TEST, + DOP_MOV, DOP_XCHG, }; @@ -87,19 +88,15 @@ enum BranchTypes { BR_L,BR_NL,BR_LE,BR_NLE }; -enum BlockType { - BT_Free=0, - BT_Normal, - BT_SingleLink, - BT_DualLink, - BT_CheckFlags, -}; enum BlockReturn { BR_Normal=0, BR_Cycles, BR_Link1,BR_Link2, BR_Opcode, +#if (C_DEBUG) + BR_OpcodeFull, +#endif BR_CallBack, }; @@ -165,9 +162,9 @@ static void dyn_load_flags(void) { gen_releasereg(DREG(FLAGS)); } -static void dyn_save_flags(bool stored=false) { +static void dyn_save_flags(void) { /* Store the host flags back in emulated ones */ - gen_save_flags(DREG(EXIT),stored); + gen_save_flags(DREG(EXIT)); gen_dop_word_imm(DOP_AND,true,DREG(EXIT),FMASK_TEST); gen_dop_word_imm(DOP_AND,true,DREG(FLAGS),~FMASK_TEST); gen_dop_word(DOP_OR,true,DREG(FLAGS),DREG(EXIT)); //flags are marked for save @@ -201,80 +198,61 @@ Bits CPU_Core_Dyn_X86_Run(void) { restart_core: PhysPt ip_point=SegPhys(cs)+reg_eip; Bitu ip_page=ip_point>>12; - mem_readb(ip_point); //Init whatever page we are in - PageHandler * handler=paging.tlb.handler[ip_page]; - CodePageHandler * chandler=0; #if C_HEAVY_DEBUG - if (DEBUG_HeavyIsBreakpoint()) return debugCallback; + if (DEBUG_HeavyIsBreakpoint()) return debugCallback; #endif - if (handler->flags & PFLAG_HASCODE) { - /* Find correct Dynamic Block to run */ - chandler=(CodePageHandler *)handler; -findblock:; - CacheBlock * block=chandler->FindCacheBlock(ip_point&4095); - if (!block) { - cache.block.running=0; - block=CreateCacheBlock(ip_point,cpu.code.big,128); -// DYN_LOG("Created block size %x type %d",block->cache.size,block->type); - chandler->AddCacheBlock(block); - if (block->page.end>=4096) { - DYN_LOG("block crosses page boundary"); - } - } -run_block: - BlockReturn ret=gen_runcode(block->cache.start); - switch (ret) { - case BR_Normal: - /* Maybe check if we staying in the same page? */ -#if C_HEAVY_DEBUG - if (DEBUG_HeavyIsBreakpoint()) return debugCallback; -#endif - goto restart_core; - case BR_Cycles: -#if C_HEAVY_DEBUG - if (DEBUG_HeavyIsBreakpoint()) return debugCallback; -#endif - return CBRET_NONE; - case BR_CallBack: - return core_dyn.callback; - case BR_Opcode: - CPU_CycleLeft+=CPU_Cycles; - CPU_Cycles=1; - return CPU_Core_Normal_Run(); - case BR_Link1: - case BR_Link2: - { - Bitu temp_ip=SegPhys(cs)+reg_eip; - Bitu temp_page=temp_ip >> 12; - CodePageHandler * temp_handler=(CodePageHandler *)paging.tlb.handler[temp_page]; - if (temp_handler->flags & PFLAG_HASCODE) { - block=temp_handler->FindCacheBlock(temp_ip & 4095); - if (!block) goto restart_core; - cache_linkblocks(cache.block.running,block,ret==BR_Link2); - goto run_block; - } - } - goto restart_core; - } - } else { - if (handler->flags & PFLAG_NOCODE) { - LOG_MSG("DYNX86:Can't run code in this page"); - return CPU_Core_Normal_Run(); - } - Bitu phys_page=ip_page; - if (!PAGING_MakePhysPage(phys_page)) { - LOG_MSG("DYNX86:Can't find physpage"); - return CPU_Core_Normal_Run(); - } - chandler=new CodePageHandler(handler); - MEM_SetPageHandler(phys_page,1,chandler); //Setup the handler - PAGING_UnlinkPages(ip_page,1); - goto findblock; + CodePageHandler * chandler=MakeCodePage(ip_page); + if (!chandler) return CPU_Core_Normal_Run(); + /* Find correct Dynamic Block to run */ + CacheBlock * block=chandler->FindCacheBlock(ip_point&4095); + if (!block) { + block=CreateCacheBlock(chandler,ip_point,32); } - return 0; +run_block: + cache.block.running=0; + BlockReturn ret=gen_runcode(block->cache.start); + switch (ret) { + case BR_Normal: + /* Maybe check if we staying in the same page? */ +#if C_HEAVY_DEBUG + if (DEBUG_HeavyIsBreakpoint()) return debugCallback; +#endif + goto restart_core; + case BR_Cycles: +#if C_HEAVY_DEBUG + if (DEBUG_HeavyIsBreakpoint()) return debugCallback; +#endif + return CBRET_NONE; + case BR_CallBack: + return core_dyn.callback; + case BR_Opcode: + CPU_CycleLeft+=CPU_Cycles; + CPU_Cycles=1; + return CPU_Core_Normal_Run(); +#if (C_DEBUG) + case BR_OpcodeFull: + CPU_CycleLeft+=CPU_Cycles; + CPU_Cycles=1; + return CPU_Core_Full_Run(); +#endif + case BR_Link1: + case BR_Link2: + { + Bitu temp_ip=SegPhys(cs)+reg_eip; + Bitu temp_page=temp_ip >> 12; + CodePageHandler * temp_handler=(CodePageHandler *)paging.tlb.handler[temp_page]; + if (temp_handler->flags & PFLAG_HASCODE) { + block=temp_handler->FindCacheBlock(temp_ip & 4095); + if (!block) goto restart_core; + cache.block.running->LinkTo(ret==BR_Link2,block); + goto run_block; + } + } + goto restart_core; + } +return 0; } - void CPU_Core_Dyn_X86_Init(void) { Bits i; /* Setup the global registers and their flags */ diff --git a/src/cpu/core_dyn_x86/cache.h b/src/cpu/core_dyn_x86/cache.h index d70644f3..348021d1 100644 --- a/src/cpu/core_dyn_x86/cache.h +++ b/src/cpu/core_dyn_x86/cache.h @@ -1,28 +1,34 @@ -struct CacheBlock { +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 { - Bit16s start,end; //Where the page is the original code - Bitu first,last; + 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; } cache; - BlockType type; - CodePageHandler * code_page; //Page containing this code - CacheBlock * page_link; //For code crossing a page boundary struct { + Bitu index; CacheBlock * next; } hash; - CacheBlock * list_next; struct { - CacheBlock * to[2]; - CacheBlock * from[DYN_LINKS]; - Bitu index; - } link; - CacheBlock * links[2]; + CacheBlock * to; + CacheBlock * next; + CacheBlock * from; + } link[2]; + CacheBlock * crossblock; }; +class CacheBlock; static struct { struct { CacheBlock * first; @@ -31,96 +37,124 @@ static struct { CacheBlock * running; } block; Bit8u * pos; - CacheBlock linkblocks[2]; + CodePageHandler * free_pages; + CodePageHandler * used_pages; + CodePageHandler * last_page; } cache; static Bit8u cache_code_link_blocks[2][16]; static Bit8u cache_code[CACHE_TOTAL+CACHE_MAXSIZE]; static CacheBlock cache_blocks[CACHE_BLOCKS]; - -static void cache_resetblock(CacheBlock * block); - +static CacheBlock link_blocks[2]; class CodePageHandler :public PageHandler { public: - CodePageHandler(PageHandler * _old_pagehandler) { + CodePageHandler() {} + 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)); } - void InvalidateRange(Bits start,Bits end) { - Bits maps=start>>DYN_HASH_SHIFT; - Bits map=maps; - Bits count=write_map[maps]; - while (map>=0 && count>0) { - CacheBlock * block=hash_map[map]; - CacheBlock * * where=&hash_map[map]; + void InvalidateRange(Bitu start,Bitu end) { + Bits index=1+(start>>DYN_HASH_SHIFT); + while (index>=0) { + Bitu map=0; + for (Bitu count=start;count<=end;count++) map+=write_map[count]; + if (!map) return; + CacheBlock * block=hash_map[index]; while (block) { CacheBlock * nextblock=block->hash.next; - if (start<=block->page.end && end>=block->page.start) { - for (Bitu i=block->page.first;i<=block->page.last;i++) write_map[i]--; - block->code_page=0; //Else resetblock will do double work - count--; - if (block==cache.block.running) LOG_MSG("Writing to current block"); - cache_resetblock(block); - *where=nextblock; - } else { - where=&block->hash.next; - } + if (start<=block->page.end && end>=block->page.start) + block->Clear(); block=nextblock; } - map--; + index--; } } void writeb(PhysPt addr,Bitu val){ - if (val!=host_readb(hostmem+(addr&4095))) { - InvalidateRange(addr&4095,addr&4095); - host_writeb(hostmem+(addr&4095),val); - } + addr&=4095; + host_writeb(hostmem+addr,val); + if (!*(Bit8u*)&write_map[addr]) { + if (active_blocks) return; + active_count--; + if (!active_count) Release(); + } else InvalidateRange(addr,addr); } void writew(PhysPt addr,Bitu val){ - if (val!=host_readw(hostmem+(addr&4095))) { - InvalidateRange(addr&4095,(addr&4095)+1); - host_writew(hostmem+(addr&4095),val); - } + addr&=4095; + host_writew(hostmem+addr,val); + if (!*(Bit16u*)&write_map[addr]) { + if (active_blocks) return; + active_count--; + if (!active_count) Release(); + } else InvalidateRange(addr,addr+1); } void writed(PhysPt addr,Bitu val){ - if (val!=host_readd(hostmem+(addr&4095))) { - InvalidateRange(addr&4095,(addr&4095)+3); - host_writed(hostmem+(addr&4095),val); - } + addr&=4095; + host_writed(hostmem+addr,val); + if (!*(Bit32u*)&write_map[addr]) { + if (active_blocks) return; + active_count--; + if (!active_count) Release(); + } else InvalidateRange(addr,addr+3); } void AddCacheBlock(CacheBlock * block) { - Bit16u first,last; - if (block->page.start<0) first=0; - else first=block->page.start>>DYN_HASH_SHIFT; - block->hash.next=hash_map[first]; - hash_map[first]=block; - if (block->page.end>=4096) last=DYN_PAGE_HASH-1; - else last=block->page.end>>DYN_HASH_SHIFT; - block->page.first=first; - block->page.last=last; - for (;first<=last;first++) { - write_map[first]++; - } - block->code_page=this; + 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) { - CacheBlock * * where=&hash_map[block->page.first]; - while (*where) { - if (*where==block) { - *where=block->hash.next; - break; - } + 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. } - for (Bitu i=block->page.first;i<=block->page.last;i++) { - write_map[i]--; + *where=block->hash.next; + 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[start>>DYN_HASH_SHIFT]; + CacheBlock * block=hash_map[1+(start>>DYN_HASH_SHIFT)]; while (block) { if (block->page.start==start) return block; block=block->hash.next; @@ -131,133 +165,153 @@ public: hostmem=old_pagehandler->GetHostPt(phys_page); return hostmem; } +public: + Bit8u write_map[4096]; + CodePageHandler * next, * prev; private: PageHandler * old_pagehandler; - CacheBlock * hash_map[DYN_PAGE_HASH]; - Bit8u write_map[DYN_PAGE_HASH]; + CacheBlock * hash_map[1+DYN_PAGE_HASH]; + Bitu active_blocks; + Bitu active_count; HostPt hostmem; + Bitu phys_page; }; +static CodePageHandler * MakeCodePage(Bitu lin_page) { + mem_readb(lin_page << 12); //Ensure page contains memory + PageHandler * handler=paging.tlb.handler[lin_page]; + if (handler->flags & PFLAG_HASCODE) return ( CodePageHandler *)handler; + if (handler->flags & PFLAG_NOCODE) { + LOG_MSG("DYNX86:Can't run code in this page"); + return 0; + } + Bitu phys_page=lin_page; + if (!PAGING_MakePhysPage(phys_page)) { + LOG_MSG("DYNX86:Can't find physpage"); + return 0; + } + /* Find a free CodePage */ + if (!cache.free_pages) { + cache.used_pages->ClearRelease(); + } + CodePageHandler * cpagehandler=cache.free_pages; + cache.free_pages=cache.free_pages->next; + cpagehandler->prev=cache.last_page; + cpagehandler->next=0; + if (cache.last_page) cache.last_page->next=cpagehandler; + cache.last_page=cpagehandler; + if (!cache.used_pages) cache.used_pages=cpagehandler; + cpagehandler->SetupAt(phys_page,handler); + MEM_SetPageHandler(phys_page,1,cpagehandler); + PAGING_UnlinkPages(lin_page,1); + return cpagehandler; +} + static INLINE void cache_addunsedblock(CacheBlock * block) { - block->list_next=cache.block.free; + 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->list_next; + cache.block.free=ret->cache.next; + ret->cache.next=0; return ret; } -static INLINE void cache_clearlinkfrom(CacheBlock * block,CacheBlock * from) { - for (Bitu i=0;ilink.from[i]==from) block->link.from[i]=0; +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)->link[ind].next; + } + *wherelink=(*wherelink)->link[ind].next; + } + } else + cache_addunsedblock(this); + if (crossblock) { + crossblock->crossblock=0; + crossblock->Clear(); + crossblock=0; + } + if (page.handler) { + page.handler->DelCacheBlock(this); + page.handler=0; } } -static INLINE void cache_clearlinkto(CacheBlock * block,CacheBlock * to) { - if (block->link.to[0]==to) block->link.to[0]=&cache.linkblocks[0]; - if (block->link.to[1]==to) block->link.to[1]=&cache.linkblocks[1]; -} - -static void cache_linkblocks(CacheBlock * from,CacheBlock * to,Bitu link) { - from->link.to[link]=to; - CacheBlock * clear=to->link.from[to->link.index]; - if (clear) { - DYN_LOG("backlink buffer full"); - cache_clearlinkto(to->link.from[to->link.index],to); - } - to->link.from[to->link.index]=from; - to->link.index++; - if (to->link.index>=DYN_LINKS) to->link.index=0; -} - -static void cache_resetblock(CacheBlock * block) { - Bits i; - DYN_LOG("Resetted block"); - block->type=BT_Free; - /* Clear all links to this block from other blocks */ - for (i=0;ilink.from[i]) cache_clearlinkto(block->link.from[i],block); - block->link.from[i]=0; - } - /* Clear all links from this block to other blocks */ - if (block->link.to[0]!=&cache.linkblocks[0]) { - cache_clearlinkfrom(block->link.to[0],block); - block->link.to[0]=&cache.linkblocks[0]; - } - if (block->link.to[1]!=&cache.linkblocks[1]) { - cache_clearlinkfrom(block->link.to[1],block); - block->link.to[1]=&cache.linkblocks[1]; - } - block->link.index=0; - if (block->code_page) block->code_page->DelCacheBlock(block); -} 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->list_next; + CacheBlock * nextblock=block->cache.next; + if (block->page.handler) + block->Clear(); while (sizecache.size; - CacheBlock * tempblock=nextblock->list_next; - if (nextblock->type!=BT_Free) cache_resetblock(nextblock); + CacheBlock * tempblock=nextblock->cache.next; + if (nextblock->page.handler) + nextblock->Clear(); cache_addunsedblock(nextblock); nextblock=tempblock; } skipresize: block->cache.size=size; - block->list_next=nextblock; + block->cache.next=nextblock; cache.pos=block->cache.start; return block; } -static void cache_closeblock(BlockType type) { +static void cache_closeblock(void) { CacheBlock * block=cache.block.active; - /* Setup some structures in the block determined by type */ - block->type=type; - switch (type) { - case BT_Normal: - break; - case BT_SingleLink: - block->link.to[0]=&cache.linkblocks[0]; - break; - case BT_DualLink: - block->link.to[0]=&cache.linkblocks[0]; - block->link.to[1]=&cache.linkblocks[1]; - break; - } + 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->list_next) { - if (written>block->cache.size+CACHE_MAXSIZE) E_Exit("CacheBlock overrun"); - } else E_Exit("CacheBlock overrun"); + 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; - } else new_size=block->cache.size; - CacheBlock * newblock=cache_getblock(); - newblock->cache.start=block->cache.start+new_size; - newblock->cache.size=block->cache.size-new_size; - newblock->list_next=block->list_next; - newblock->type=BT_Free; - block->cache.size=new_size; - block->list_next=newblock; + 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->list_next) { - DYN_LOG("Cache full restarting"); + if (!block->cache.next) { +// LOG_MSG("Cache full restarting"); cache.block.active=cache.block.first; } else { - cache.block.active=block->list_next; + cache.block.active=block->cache.next; } } @@ -283,20 +337,29 @@ static void cache_init(void) { memset(&cache_blocks,0,sizeof(cache_blocks)); cache.block.free=&cache_blocks[0]; for (i=0;icache.start=&cache_code[0]; block->cache.size=CACHE_TOTAL; - block->list_next=0; //Last block in the list + block->cache.next=0; //Last block in the list cache.pos=&cache_code_link_blocks[0][0]; - cache.linkblocks[0].cache.start=cache.pos; + link_blocks[0].cache.start=cache.pos; gen_return(BR_Link1); cache.pos=&cache_code_link_blocks[1][0]; - cache.linkblocks[1].cache.start=cache.pos; + link_blocks[1].cache.start=cache.pos; gen_return(BR_Link2); -} \ No newline at end of file + cache.free_pages=0; + cache.last_page=0; + cache.used_pages=0; + /* Setup the code pages */ + for (i=0;inext=cache.free_pages; + cache.free_pages=newpage; + } +} diff --git a/src/cpu/core_dyn_x86/decoder.h b/src/cpu/core_dyn_x86/decoder.h index cc077ec9..4212f92e 100644 --- a/src/cpu/core_dyn_x86/decoder.h +++ b/src/cpu/core_dyn_x86/decoder.h @@ -29,6 +29,13 @@ static struct DynDecode { REP_Type rep; Bitu cycles; CacheBlock * block; + CacheBlock * active_block; + struct { + CodePageHandler * code; + Bitu index; + Bit8u * wmap; + Bitu first; + } page; struct { Bitu val; Bitu mod; @@ -38,15 +45,46 @@ static struct DynDecode { DynReg * segprefix; } decode; -static Bit8u INLINE decode_fetchb(void) { - return mem_readb(decode.code++); +static Bit8u decode_fetchb(void) { + if (decode.page.index>=4096) { + /* Advance to the next page */ + decode.active_block->page.end=4095; + decode.page.code=MakeCodePage(++decode.page.first); + CacheBlock * newblock=cache_getblock(); + decode.active_block->crossblock=newblock; + newblock->crossblock=decode.active_block; + decode.active_block=newblock; + decode.active_block->page.start=0; + decode.page.code->AddCrossBlock(decode.active_block); + decode.page.wmap=decode.page.code->write_map; + decode.page.index=0; + } + decode.page.wmap[decode.page.index]+=0x01; + decode.page.index++; + decode.code+=1; + return mem_readb(decode.code-1); } -static Bit16u INLINE decode_fetchw(void) { - decode.code+=2; +static Bit16u decode_fetchw(void) { + if (decode.page.index>=4095) { + Bit16u val=decode_fetchb(); + val|=decode_fetchb() << 8; + return val; + } + *(Bit16u *)&decode.page.wmap[decode.page.index]+=0x0101; + decode.code+=2;decode.page.index+=2; return mem_readw(decode.code-2); } -static Bit32u INLINE decode_fetchd(void) { - decode.code+=4; +static Bit32u decode_fetchd(void) { + if (decode.page.index>=4093) { + Bit32u val=decode_fetchb(); + val|=decode_fetchb() << 8; + val|=decode_fetchb() << 16; + val|=decode_fetchb() << 24; + return val; + /* Advance to the next page */ + } + *(Bit32u *)&decode.page.wmap[decode.page.index]+=0x01010101; + decode.code+=4;decode.page.index+=4; return mem_readd(decode.code-4); } @@ -71,13 +109,14 @@ static void dyn_write_word(DynReg * addr,DynReg * val,bool dword) { static void dyn_reduce_cycles(void) { + if (!decode.cycles) decode.cycles++; gen_lea(DREG(CYCLES),DREG(CYCLES),0,0,-(Bits)decode.cycles); gen_releasereg(DREG(CYCLES)); } static void dyn_push(DynReg * dynreg) { - gen_storeflags(); + gen_protectflags(); if (decode.big_op) { gen_dop_word_imm(DOP_SUB,true,DREG(ESP),4); } else { @@ -93,11 +132,10 @@ static void dyn_push(DynReg * dynreg) { gen_call_function((void *)&mem_writew,"%Drd%Dd",DREG(STACK),dynreg); } gen_releasereg(DREG(STACK)); - gen_restoreflags(); } static void dyn_pop(DynReg * dynreg) { - gen_storeflags(); + gen_protectflags(); gen_dop_word(DOP_MOV,true,DREG(STACK),DREG(ESP)); gen_dop_word(DOP_AND,true,DREG(STACK),DREG(SMASK)); gen_dop_word(DOP_ADD,true,DREG(STACK),DREG(SS)); @@ -114,7 +152,6 @@ static void dyn_pop(DynReg * dynreg) { } } gen_releasereg(DREG(STACK)); - gen_restoreflags(); } static void INLINE dyn_get_modrm(void) { @@ -238,10 +275,12 @@ static void dyn_dop_ebgb(DualOps op) { if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_read_byte(DREG(EA),DREG(TMPB),false); + if (op<=DOP_TEST) gen_needflags(); gen_dop_byte(op,DREG(TMPB),0,rm_reg,decode.modrm.reg&4); dyn_write_byte(DREG(EA),DREG(TMPB),false); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPB)); } else { + if (op<=DOP_TEST) gen_needflags(); gen_dop_byte(op,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4,rm_reg,decode.modrm.reg&4); } } @@ -252,9 +291,11 @@ static void dyn_dop_gbeb(DualOps op) { if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_read_byte(DREG(EA),DREG(TMPB),false); + if (op<=DOP_TEST) gen_needflags(); gen_dop_byte(op,rm_reg,decode.modrm.reg&4,DREG(TMPB),0); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPB)); } else { + if (op<=DOP_TEST) gen_needflags(); gen_dop_byte(op,rm_reg,decode.modrm.reg&4,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); } } @@ -302,10 +343,12 @@ static void dyn_dop_evgv(DualOps op) { if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); + if (op<=DOP_TEST) gen_needflags(); gen_dop_word(op,decode.big_op,DREG(TMPW),rm_reg); dyn_write_word(DREG(EA),DREG(TMPW),decode.big_op); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPW)); } else { + if (op<=DOP_TEST) gen_needflags(); gen_dop_word(op,decode.big_op,&DynRegs[decode.modrm.rm],rm_reg); } } @@ -319,6 +362,7 @@ static void dyn_imul_gvev(Bitu immsize) { } else { src=&DynRegs[decode.modrm.rm]; } + gen_needflags(); switch (immsize) { case 0:gen_imul_word(decode.big_op,rm_reg,src);break; case 1:gen_imul_word_imm(decode.big_op,rm_reg,src,(Bit8s)decode_fetchb());break; @@ -334,9 +378,11 @@ static void dyn_dop_gvev(DualOps op) { if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); + if (op<=DOP_TEST) gen_needflags(); gen_dop_word(op,decode.big_op,rm_reg,DREG(TMPW)); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPW)); } else { + if (op<=DOP_TEST) gen_needflags(); gen_dop_word(op,decode.big_op,rm_reg,&DynRegs[decode.modrm.rm]); } } @@ -413,6 +459,7 @@ static void dyn_dshift_ev_gv(bool left,bool immediate) { dyn_fill_ea();ea_reg=DREG(TMPW); dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); } else ea_reg=&DynRegs[decode.modrm.rm]; + gen_needflags(); if (immediate) gen_dshift_imm(decode.big_op,left,ea_reg,rm_reg,decode_fetchb()); else gen_dshift_cl(decode.big_op,left,ea_reg,rm_reg,DREG(ECX)); if (decode.modrm.mod<3) { @@ -428,10 +475,12 @@ static void dyn_grp1_eb_ib(void) { if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_read_byte(DREG(EA),DREG(TMPB),false); + gen_needflags(); gen_dop_byte_imm(grp1_table[decode.modrm.reg],DREG(TMPB),0,decode_fetchb()); if (grp1_table[decode.modrm.reg]!=DOP_CMP) dyn_write_byte(DREG(EA),DREG(TMPB),false); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPB)); } else { + gen_needflags(); gen_dop_byte_imm(grp1_table[decode.modrm.reg],&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4,decode_fetchb()); } } @@ -442,11 +491,13 @@ static void dyn_grp1_ev_ivx(bool withbyte) { dyn_fill_ea(); dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); Bits imm=withbyte ? (Bit8s)decode_fetchb() : (decode.big_op ? decode_fetchd(): decode_fetchw()); + gen_needflags(); gen_dop_word_imm(grp1_table[decode.modrm.reg],decode.big_op,DREG(TMPW),imm); dyn_write_word(DREG(EA),DREG(TMPW),decode.big_op); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPW)); } else { Bits imm=withbyte ? (Bit8s)decode_fetchb() : (decode.big_op ? decode_fetchd(): decode_fetchw()); + gen_needflags(); gen_dop_word_imm(grp1_table[decode.modrm.reg],decode.big_op,&DynRegs[decode.modrm.rm],imm); } } @@ -472,6 +523,7 @@ static void dyn_grp2_eb(grp2_types type) { case grp2_1:shift=DREG(SHIFT);gen_dop_byte_imm(DOP_MOV,DREG(SHIFT),0,1);break; case grp2_imm:shift=DREG(SHIFT);gen_dop_byte_imm(DOP_MOV,DREG(SHIFT),0,decode_fetchb());break; } + gen_needflags(); gen_shift_byte(grp2_table[decode.modrm.reg],shift,DREG(TMPB),0); dyn_write_byte(DREG(EA),DREG(TMPB),false); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPB));gen_releasereg(DREG(SHIFT)); @@ -482,6 +534,7 @@ static void dyn_grp2_eb(grp2_types type) { case grp2_1:shift=DREG(SHIFT);gen_dop_byte_imm(DOP_MOV,DREG(SHIFT),0,1);break; case grp2_imm:shift=DREG(SHIFT);gen_dop_byte_imm(DOP_MOV,DREG(SHIFT),0,decode_fetchb());break; } + gen_needflags(); gen_shift_byte(grp2_table[decode.modrm.reg],shift,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); gen_releasereg(DREG(SHIFT)); } @@ -498,6 +551,7 @@ static void dyn_grp2_ev(grp2_types type) { case grp2_1:shift=DREG(SHIFT);gen_dop_byte_imm(DOP_MOV,DREG(SHIFT),0,1);break; case grp2_imm:shift=DREG(SHIFT);gen_dop_byte_imm(DOP_MOV,DREG(SHIFT),0,decode_fetchb());break; } + gen_needflags(); gen_shift_word(grp2_table[decode.modrm.reg],shift,decode.big_op,DREG(TMPW)); dyn_write_word(DREG(EA),DREG(TMPW),decode.big_op); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPW));gen_releasereg(DREG(SHIFT)); @@ -508,6 +562,7 @@ static void dyn_grp2_ev(grp2_types type) { case grp2_1:shift=DREG(SHIFT);gen_dop_byte_imm(DOP_MOV,DREG(SHIFT),0,1);break; case grp2_imm:shift=DREG(SHIFT);gen_dop_byte_imm(DOP_MOV,DREG(SHIFT),0,decode_fetchb());break; } + gen_needflags(); gen_shift_word(grp2_table[decode.modrm.reg],shift,decode.big_op,&DynRegs[decode.modrm.rm]); gen_releasereg(DREG(SHIFT)); } @@ -526,26 +581,26 @@ static void dyn_grp3_eb(void) { } switch (decode.modrm.reg) { case 0x0: /* test eb,ib */ - gen_dop_byte_imm(DOP_TEST,src,src_i,decode_fetchb()); + gen_needflags();gen_dop_byte_imm(DOP_TEST,src,src_i,decode_fetchb()); goto skipsave; case 0x2: /* NOT Eb */ - gen_sop_byte(SOP_NOT,src,src_i); + gen_needflags();gen_sop_byte(SOP_NOT,src,src_i); break; case 0x3: /* NEG Eb */ - gen_sop_byte(SOP_NEG,src,src_i); + gen_needflags();gen_sop_byte(SOP_NEG,src,src_i); break; case 0x4: /* mul Eb */ - gen_mul_byte(false,DREG(EAX),src,src_i); + gen_needflags();gen_mul_byte(false,DREG(EAX),src,src_i); goto skipsave; case 0x5: /* imul Eb */ - gen_mul_byte(true,DREG(EAX),src,src_i); + gen_needflags();gen_mul_byte(true,DREG(EAX),src,src_i); goto skipsave; case 0x6: /* div Eb */ case 0x7: /* idiv Eb */ /* EAX could be used, so precache it */ if (decode.modrm.mod==3) gen_dop_byte(DOP_MOV,DREG(TMPB),0,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); - gen_storeflags();gen_releasereg(DREG(EAX)); + gen_releasereg(DREG(EAX)); gen_call_function((decode.modrm.reg==6) ? (void *)&dyn_helper_divb : (void *)&dyn_helper_idivb, "%Rd%Drl",DREG(TMPB),DREG(TMPB)); gen_dop_word(DOP_OR,true,DREG(TMPB),DREG(TMPB)); @@ -553,14 +608,13 @@ static void dyn_grp3_eb(void) { dyn_savestate(&state); dyn_reduce_cycles(); gen_lea(DREG(EIP),DREG(EIP),0,0,decode.op_start-decode.code_start); - dyn_save_flags(true); + dyn_save_flags(); dyn_releaseregs(); gen_call_function((void *)&CPU_Exception,"%Id%Id",0,0); dyn_load_flags(); gen_return(BR_Normal); dyn_loadstate(&state); gen_fill_branch(branch); - gen_restoreflags(); goto skipsave; } /* Save the result if memory op */ @@ -578,26 +632,26 @@ static void dyn_grp3_ev(void) { } else src=&DynRegs[decode.modrm.rm]; switch (decode.modrm.reg) { case 0x0: /* test ev,iv */ - gen_dop_word_imm(DOP_TEST,decode.big_op,src,decode.big_op ? decode_fetchd() : decode_fetchw()); + gen_needflags();gen_dop_word_imm(DOP_TEST,decode.big_op,src,decode.big_op ? decode_fetchd() : decode_fetchw()); goto skipsave; case 0x2: /* NOT Ev */ - gen_sop_word(SOP_NOT,decode.big_op,src); + gen_needflags();gen_sop_word(SOP_NOT,decode.big_op,src); break; case 0x3: /* NEG Eb */ - gen_sop_word(SOP_NEG,decode.big_op,src); + gen_needflags();gen_sop_word(SOP_NEG,decode.big_op,src); break; case 0x4: /* mul Eb */ - gen_mul_word(false,DREG(EAX),DREG(EDX),decode.big_op,src); + gen_needflags();gen_mul_word(false,DREG(EAX),DREG(EDX),decode.big_op,src); goto skipsave; case 0x5: /* imul Eb */ - gen_mul_word(true,DREG(EAX),DREG(EDX),decode.big_op,src); + gen_needflags();gen_mul_word(true,DREG(EAX),DREG(EDX),decode.big_op,src); goto skipsave; case 0x6: /* div Eb */ case 0x7: /* idiv Eb */ /* EAX could be used, so precache it */ if (decode.modrm.mod==3) gen_dop_word(DOP_MOV,decode.big_op,DREG(TMPW),&DynRegs[decode.modrm.rm]); - gen_storeflags();gen_releasereg(DREG(EAX));gen_releasereg(DREG(EDX)); + gen_releasereg(DREG(EAX));gen_releasereg(DREG(EDX)); void * func=(decode.modrm.reg==6) ? (decode.big_op ? (void *)&dyn_helper_divd : (void *)&dyn_helper_divw) : (decode.big_op ? (void *)&dyn_helper_idivd : (void *)&dyn_helper_idivw); @@ -607,14 +661,13 @@ static void dyn_grp3_ev(void) { dyn_savestate(&state); dyn_reduce_cycles(); gen_lea(DREG(EIP),DREG(EIP),0,0,decode.op_start-decode.code_start); - dyn_save_flags(true); + dyn_save_flags(); dyn_releaseregs(); gen_call_function((void *)&CPU_Exception,"%Id%Id",0,0); dyn_load_flags(); gen_return(BR_Normal); dyn_loadstate(&state); gen_fill_branch(branch); - gen_restoreflags(); goto skipsave; } /* Save the result if memory op */ @@ -639,7 +692,7 @@ static void dyn_mov_ev_seg(void) { static void dyn_load_seg(SegNames seg,DynReg * src,bool withpop) { if (cpu.pmode) { Bit8u * branch;DynState state; - gen_storeflags(); + gen_protectflags(); gen_call_function((void *)&CPU_SetSegGeneral,"%Rd%Id%Drw",DREG(TMPB),seg,src); gen_dop_byte(DOP_OR,DREG(TMPB),0,DREG(TMPB),0); branch=gen_create_branch(BR_Z); @@ -647,14 +700,13 @@ static void dyn_load_seg(SegNames seg,DynReg * src,bool withpop) { dyn_reduce_cycles(); if (withpop) gen_dop_word_imm(DOP_SUB,true,DREG(ESP),decode.big_op ? 4 : 2); gen_dop_word_imm(DOP_ADD,true,DREG(EIP),decode.op_start-decode.code_start); - dyn_save_flags(true); + dyn_save_flags(); dyn_releaseregs(); gen_call_function((void *)&CPU_StartException,""); dyn_load_flags(); gen_return(BR_Normal); dyn_loadstate(&state); gen_fill_branch(branch); - gen_restoreflags(); } else { //TODO Maybe just calculate the base directly if in realmode gen_call_function((void *)&CPU_SetSegGeneral,"%Id%Drw",seg,src); @@ -698,15 +750,12 @@ static void dyn_push_seg(SegNames seg) { } static void dyn_pop_seg(SegNames seg) { - gen_storeflags(); dyn_pop(DREG(TMPW)); dyn_load_seg(seg,DREG(TMPW),true); gen_releasereg(DREG(TMPW)); - gen_restoreflags(); } static void dyn_pop_ev(void) { - gen_storeflags(); dyn_pop(DREG(TMPW)); dyn_get_modrm(); if (decode.modrm.mod<3) { @@ -717,11 +766,10 @@ static void dyn_pop_ev(void) { gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],DREG(TMPW)); } gen_releasereg(DREG(TMPW)); - gen_restoreflags(); } static void dyn_leave(void) { - gen_storeflags(); + gen_protectflags(); gen_dop_word(DOP_MOV,true,DREG(TMPW),DREG(SMASK)); gen_sop_word(SOP_NOT,true,DREG(TMPW)); gen_dop_word(DOP_AND,true,DREG(ESP),DREG(TMPW)); @@ -730,7 +778,6 @@ static void dyn_leave(void) { gen_dop_word(DOP_OR,true,DREG(ESP),DREG(TMPW)); dyn_pop(DREG(EBP)); gen_releasereg(DREG(TMPW)); - gen_restoreflags(); } static void dyn_segprefix(SegNames seg) { @@ -738,14 +785,10 @@ static void dyn_segprefix(SegNames seg) { decode.segprefix=&DynRegs[G_ES+seg]; } -static void dyn_closeblock(BlockType type) { +static void dyn_closeblock(void) { //Shouldn't create empty block normally but let's do it like this - if (decode.code>decode.code_start) decode.code--; - Bitu start_page=decode.code_start >> 12; - Bitu end_page=decode.code>>12; - decode.block->page.start=(Bit16s)decode.code_start & 4095; - decode.block->page.end=(Bit16s)((end_page-start_page)*4096+(decode.code&4095)); - cache_closeblock(type); + gen_protectflags(); + cache_closeblock(); } static void dyn_normal_exit(BlockReturn code) { @@ -753,36 +796,35 @@ static void dyn_normal_exit(BlockReturn code) { dyn_reduce_cycles(); dyn_releaseregs(); gen_return(code); - dyn_closeblock(BT_Normal); + dyn_closeblock(); } static void dyn_exit_link(bool dword,Bits eip_change) { + gen_protectflags(); gen_lea(DREG(EIP),DREG(EIP),0,0,(decode.code-decode.code_start)+eip_change); if (!dword) gen_extend_word(false,DREG(EIP),DREG(EIP)); dyn_reduce_cycles(); dyn_releaseregs(); -// gen_return(BR_Normal); - gen_jmp_ptr(&decode.block->link.to[0],offsetof(CacheBlock,cache.start)); - dyn_closeblock(BT_SingleLink); + gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start)); + dyn_closeblock(); } static void dyn_branched_exit(BranchTypes btype,Bit32s eip_add) { dyn_reduce_cycles(); dyn_releaseregs(); Bitu eip_base=decode.code-decode.code_start; + gen_needflags();gen_protectflags(); Bit8u * data=gen_create_branch(btype); /* Branch not taken */ gen_lea(DREG(EIP),DREG(EIP),0,0,eip_base); gen_releasereg(DREG(EIP)); -// gen_return(BR_Normal); - gen_jmp_ptr(&decode.block->link.to[0],offsetof(CacheBlock,cache.start)); + gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start)); gen_fill_branch(data); /* Branch taken */ gen_lea(DREG(EIP),DREG(EIP),0,0,eip_base+eip_add); gen_releasereg(DREG(EIP)); -// gen_return(BR_Normal); - gen_jmp_ptr(&decode.block->link.to[1],offsetof(CacheBlock,cache.start)); - dyn_closeblock(BT_DualLink); + gen_jmp_ptr(&decode.block->link[1].to,offsetof(CacheBlock,cache.start)); + dyn_closeblock(); } enum LoopTypes { @@ -790,16 +832,15 @@ enum LoopTypes { }; static void dyn_loop(LoopTypes type) { + gen_protectflags(); Bits eip_add=(Bit8s)decode_fetchb(); Bitu eip_base=decode.code-decode.code_start; - gen_storeflags(); dyn_reduce_cycles(); Bit8u * branch1; Bit8u * branch2=0; gen_sop_word(SOP_DEC,decode.big_addr,DREG(ECX)); dyn_releaseregs(); branch1=gen_create_branch(BR_Z); - gen_restoreflags(true); switch (type) { case LOOP_NONE: break; @@ -812,30 +853,29 @@ static void dyn_loop(LoopTypes type) { } gen_lea(DREG(EIP),DREG(EIP),0,0,eip_base+eip_add); gen_releasereg(DREG(EIP)); - gen_jmp_ptr(&decode.block->link.to[0],offsetof(CacheBlock,cache.start)); + gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start)); gen_fill_branch(branch1); if (branch2) gen_fill_branch(branch2); /* Branch taken */ - gen_restoreflags(); gen_lea(DREG(EIP),DREG(EIP),0,0,eip_base); gen_releasereg(DREG(EIP)); - gen_jmp_ptr(&decode.block->link.to[1],offsetof(CacheBlock,cache.start)); - dyn_closeblock(BT_DualLink); + gen_jmp_ptr(&decode.block->link[1].to,offsetof(CacheBlock,cache.start)); + dyn_closeblock(); } static void dyn_ret_near(Bitu bytes) { + gen_protectflags(); dyn_reduce_cycles(); //TODO maybe AND eip 0xffff, but shouldn't be needed - gen_storeflags(); dyn_pop(DREG(EIP)); if (bytes) gen_dop_word_imm(DOP_ADD,true,DREG(ESP),bytes); dyn_releaseregs(); - gen_restoreflags(); gen_return(BR_Normal); - dyn_closeblock(BT_Normal); + dyn_closeblock(); } static void dyn_ret_far(Bitu bytes) { + gen_protectflags(); dyn_reduce_cycles(); //TODO maybe AND eip 0xffff, but shouldn't be needed gen_lea(DREG(EIP),DREG(EIP),0,0,decode.code-decode.code_start); @@ -845,7 +885,7 @@ static void dyn_ret_far(Bitu bytes) { dyn_load_flags(); dyn_releaseregs();; gen_return(BR_Normal); - dyn_closeblock(BT_Normal); + dyn_closeblock(); } static void dyn_call_near_imm(void) { @@ -858,13 +898,14 @@ static void dyn_call_near_imm(void) { if (!decode.big_op) gen_extend_word(false,DREG(EIP),DREG(EIP)); dyn_reduce_cycles(); dyn_releaseregs(); - gen_return(BR_Normal); -// gen_jmp_ptr(&decode.block->link.to[0],offsetof(CacheBlock,cache.start)); - dyn_closeblock(BT_SingleLink); +// gen_return(BR_Normal); + gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start)); + dyn_closeblock(); } static void dyn_call_far_imm(void) { Bitu sel,off; + gen_protectflags(); off=decode.big_op ? decode_fetchd() : decode_fetchw(); sel=decode_fetchw(); dyn_reduce_cycles(); @@ -875,11 +916,12 @@ static void dyn_call_far_imm(void) { dyn_load_flags(); dyn_releaseregs(); gen_return(BR_Normal); - dyn_closeblock(BT_Normal); + dyn_closeblock(); } static void dyn_jmp_far_imm(void) { Bitu sel,off; + gen_protectflags(); off=decode.big_op ? decode_fetchd() : decode_fetchw(); sel=decode_fetchw(); dyn_reduce_cycles(); @@ -890,10 +932,11 @@ static void dyn_jmp_far_imm(void) { dyn_load_flags(); dyn_releaseregs(); gen_return(BR_Normal); - dyn_closeblock(BT_Normal); + dyn_closeblock(); } static void dyn_iret(void) { + gen_protectflags(); dyn_save_flags(); dyn_reduce_cycles(); gen_dop_word_imm(DOP_ADD,true,DREG(EIP),decode.code-decode.code_start); @@ -902,10 +945,11 @@ static void dyn_iret(void) { dyn_load_flags(); dyn_releaseregs(); gen_return(BR_Normal); - dyn_closeblock(BT_CheckFlags); + dyn_closeblock(); } static void dyn_interrupt(Bitu num) { + gen_protectflags(); dyn_save_flags(); dyn_reduce_cycles(); gen_dop_word_imm(DOP_ADD,true,DREG(EIP),decode.code-decode.code_start); @@ -914,15 +958,23 @@ static void dyn_interrupt(Bitu num) { dyn_load_flags(); dyn_releaseregs(); gen_return(BR_Normal); - dyn_closeblock(BT_Normal); + dyn_closeblock(); } -static CacheBlock * CreateCacheBlock(PhysPt start,bool big,Bitu max_opcodes) { +static CacheBlock * CreateCacheBlock(CodePageHandler * codepage,PhysPt start,Bitu max_opcodes) { Bits i; +/* Init a load of variables */ decode.code_start=start; decode.code=start; Bitu cycles=0; - decode.block=cache_openblock(); + decode.page.code=codepage; + decode.page.index=start&4095; + decode.page.wmap=codepage->write_map; + decode.page.first=start >> 12; + decode.active_block=decode.block=cache_openblock(); + decode.block->page.start=decode.page.index; + codepage->AddCacheBlock(decode.block); + gen_save_host_direct(&cache.block.running,(Bit32u)decode.block); for (i=0;i=G_EAX;i--) { dyn_pop((i!=G_ESP) ? &DynRegs[i] : DREG(TMPW)); } - gen_restoreflags();gen_releasereg(DREG(TMPW)); + gen_releasereg(DREG(TMPW)); break; //segprefix FS,GS case 0x64:dyn_segprefix(fs);goto restart_prefix; case 0x65:dyn_segprefix(gs);goto restart_prefix; //Push immediates //Operand size - case 0x66:decode.big_op=!big;goto restart_prefix; + case 0x66:decode.big_op=!cpu.code.big;;goto restart_prefix; //Address size - case 0x67:decode.big_addr=!big;goto restart_prefix; + case 0x67:decode.big_addr=!cpu.code.big;goto restart_prefix; case 0x68: /* PUSH Iv */ gen_dop_word_imm(DOP_MOV,decode.big_op,DREG(TMPW),decode.big_op ? decode_fetchd() : decode_fetchw()); dyn_push(DREG(TMPW)); @@ -1117,7 +1163,7 @@ restart_prefix: case 0x70:case 0x71:case 0x72:case 0x73:case 0x74:case 0x75:case 0x76:case 0x77: case 0x78:case 0x79:case 0x7a:case 0x7b:case 0x7c:case 0x7d:case 0x7e:case 0x7f: dyn_branched_exit((BranchTypes)(opcode&0xf),(Bit8s)decode_fetchb()); - return decode.block; + goto finish_block; /* Group 1 */ case 0x80:dyn_grp1_eb_ib();break; case 0x81:dyn_grp1_ev_ivx(false);break; @@ -1155,10 +1201,6 @@ restart_prefix: break; /* CBW/CWDE */ case 0x98: - /* - if (decode.big_op) gen_extend_word(true,DREG(EAX),DREG(EAX)); - else gen_extend_byte(true,false,DREG(EAX),DREG(EAX),0); - */ gen_cbw(decode.big_op,DREG(EAX)); break; /* CWD/CDQ */ @@ -1166,7 +1208,7 @@ restart_prefix: gen_cwd(decode.big_op,DREG(EAX),DREG(EDX)); break; /* CALL FAR Ip */ - case 0x9a:dyn_call_far_imm();return decode.block; + case 0x9a:dyn_call_far_imm();goto finish_block; /* MOV AL,direct addresses */ case 0xa0: gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0, @@ -1199,8 +1241,8 @@ restart_prefix: case 0xa4:dyn_string(STR_MOVSB);break; case 0xa5:dyn_string(decode.big_op ? STR_MOVSD : STR_MOVSW);break; /* TEST AL,AX Imm */ - case 0xa8:gen_dop_byte_imm(DOP_TEST,DREG(EAX),0,decode_fetchb());break; - case 0xa9:gen_dop_word_imm(DOP_TEST,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; + case 0xa8:gen_needflags();gen_dop_byte_imm(DOP_TEST,DREG(EAX),0,decode_fetchb());break; + case 0xa9:gen_needflags();gen_dop_word_imm(DOP_TEST,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; /* STOSB/W/D*/ case 0xaa:dyn_string(STR_STOSB);break; case 0xab:dyn_string(decode.big_op ? STR_STOSD : STR_STOSW);break; @@ -1215,12 +1257,13 @@ restart_prefix: case 0xb8:case 0xb9:case 0xba:case 0xbb:case 0xbc:case 0xbd:case 0xbe:case 0xbf: gen_dop_word_imm(DOP_MOV,decode.big_op,&DynRegs[opcode&7],decode.big_op ? decode_fetchd() : decode_fetchw());break; break; + //GRP2 Eb/Ev,Ib case 0xc0:dyn_grp2_eb(grp2_imm);break; case 0xc1:dyn_grp2_ev(grp2_imm);break; //RET near Iw / Ret - case 0xc2:dyn_ret_near(decode_fetchw());return decode.block; - case 0xc3:dyn_ret_near(0);return decode.block; + case 0xc2:dyn_ret_near(decode_fetchw());goto finish_block; + case 0xc3:dyn_ret_near(0);goto finish_block; //LES/LDS case 0xc4:dyn_load_seg_off_ea(es);break; case 0xc5:dyn_load_seg_off_ea(ds);break; @@ -1230,12 +1273,12 @@ restart_prefix: // LEAVE case 0xc9:dyn_leave();break; //RET far Iw / Ret - case 0xca:dyn_ret_far(decode_fetchw());return decode.block; - case 0xcb:dyn_ret_far(0);return decode.block; + case 0xca:dyn_ret_far(decode_fetchw());goto finish_block; + case 0xcb:dyn_ret_far(0);goto finish_block; /* Interrupt */ - case 0xcd:dyn_interrupt(decode_fetchb());return decode.block; + case 0xcd:dyn_interrupt(decode_fetchb());goto finish_block; /* IRET */ - case 0xcf:dyn_iret();return decode.block; + case 0xcf:dyn_iret();goto finish_block; //GRP2 Eb/Ev,1 case 0xd0:dyn_grp2_eb(grp2_1);break; case 0xd1:dyn_grp2_ev(grp2_1);break; @@ -1243,7 +1286,7 @@ restart_prefix: case 0xd2:dyn_grp2_eb(grp2_cl);break; case 0xd3:dyn_grp2_ev(grp2_cl);break; //Loop's - case 0xe2:dyn_loop(LOOP_NONE);return decode.block; + case 0xe2:dyn_loop(LOOP_NONE);goto finish_block; //IN AL/AX,imm case 0xe4:gen_call_function((void*)&IO_ReadB,"%Id%Rl",decode_fetchb(),DREG(EAX));break; case 0xe5: @@ -1264,14 +1307,15 @@ restart_prefix: break; case 0xe8: /* CALL Ivx */ dyn_call_near_imm(); - return decode.block; + goto finish_block; case 0xe9: /* Jmp Ivx */ dyn_exit_link(decode.big_op,decode.big_op ? (Bit32s)decode_fetchd() : (Bit16s)decode_fetchw()); - return decode.block; - /* CALL FAR Ip */ - case 0xea:dyn_jmp_far_imm();return decode.block; - /* Jmp Ibx */ - case 0xeb:dyn_exit_link(decode.big_op,(Bit8s)decode_fetchb());return decode.block; + goto finish_block; + case 0xea: /* JMP FAR Ip */ + dyn_jmp_far_imm(); + goto finish_block; + /* Jmp Ibx */ + case 0xeb:dyn_exit_link(decode.big_op,(Bit8s)decode_fetchb());goto finish_block; /* IN AL/AX,DX*/ case 0xec:gen_call_function((void*)&IO_ReadB,"%Dw%Rl",DREG(EDX),DREG(EAX));break; case 0xed: @@ -1290,6 +1334,7 @@ restart_prefix: gen_call_function((void*)&IO_WriteW,"%Dw%Dw",DREG(EDX),DREG(EAX)); } break; + case 0xf2: //REPNE/NZ decode.rep=REP_NZ; goto restart_prefix; @@ -1300,20 +1345,19 @@ restart_prefix: case 0xf5: //CMC case 0xf8: //CLC case 0xf9: //STC + gen_needflags(); cache_addb(opcode);break; /* GRP 3 Eb/EV */ case 0xf6:dyn_grp3_eb();break; case 0xf7:dyn_grp3_ev();break; /* Change interrupt flag */ case 0xfa: //CLI - gen_storeflags(); + gen_protectflags(); gen_dop_word_imm(DOP_AND,true,DREG(FLAGS),~FLAG_IF); - gen_restoreflags(); break; case 0xfb: //STI - gen_storeflags(); + gen_protectflags(); gen_dop_word_imm(DOP_OR,true,DREG(FLAGS),FLAG_IF); - gen_restoreflags(); if (max_opcodes<=0) max_opcodes=1; //Allow 1 extra opcode break; /* GRP 4 Eb and callback's */ @@ -1324,10 +1368,12 @@ restart_prefix: case 0x1://DEC Eb if (decode.modrm.mod<3) { dyn_fill_ea();dyn_read_byte(DREG(EA),DREG(TMPB),false); + gen_needflags(); gen_sop_byte(decode.modrm.reg==0 ? SOP_INC : SOP_DEC,DREG(TMPB),0); dyn_write_byte(DREG(EA),DREG(TMPB),false); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPB)); } else { + gen_needflags(); gen_sop_byte(decode.modrm.reg==0 ? SOP_INC : SOP_DEC, &DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); } @@ -1338,10 +1384,11 @@ restart_prefix: dyn_reduce_cycles(); dyn_releaseregs(); gen_return(BR_CallBack); - dyn_closeblock(BT_Normal); - return decode.block; + dyn_closeblock(); + goto finish_block; } break; + case 0xff: { dyn_get_modrm();DynReg * src; @@ -1353,6 +1400,7 @@ restart_prefix: switch (decode.modrm.reg) { case 0x0://INC Ev case 0x1://DEC Ev + gen_needflags(); gen_sop_word(decode.modrm.reg==0 ? SOP_INC : SOP_DEC,decode.big_op,src); if (decode.modrm.mod<3){ dyn_write_word(DREG(EA),DREG(TMPW),decode.big_op); @@ -1398,14 +1446,27 @@ core_close_block: dyn_reduce_cycles(); dyn_releaseregs(); gen_return(BR_Normal); - dyn_closeblock(BT_Normal); - return decode.block; + dyn_closeblock(); + goto finish_block; illegalopcode: - decode.code=decode.op_start; - gen_lea(DREG(EIP),DREG(EIP),0,0,decode.code-decode.code_start); + gen_lea(DREG(EIP),DREG(EIP),0,0,decode.op_start-decode.code_start); dyn_reduce_cycles(); dyn_releaseregs(); gen_return(BR_Opcode); - dyn_closeblock(BT_Normal); + dyn_closeblock(); + goto finish_block; +#if (C_DEBUG) +illegalopcodefull: + gen_lea(DREG(EIP),DREG(EIP),0,0,decode.op_start-decode.code_start); + dyn_reduce_cycles(); + dyn_releaseregs(); + gen_return(BR_OpcodeFull); + dyn_closeblock(); + goto finish_block; +#endif +finish_block: + /* Setup the correct end-address */ + decode.active_block->page.end=--decode.page.index; +// LOG_MSG("Created block size %d start %d end %d",decode.block->cache.size,decode.block->page.start,decode.block->page.end); return decode.block; } diff --git a/src/cpu/core_dyn_x86/risc_x86.h b/src/cpu/core_dyn_x86/risc_x86.h index ad1e4d74..9611e0ea 100644 --- a/src/cpu/core_dyn_x86/risc_x86.h +++ b/src/cpu/core_dyn_x86/risc_x86.h @@ -32,8 +32,8 @@ static void gen_init(void); #define X86_REG_MASK(_REG_) (1 << X86_REG_ ## _REG_) static struct { + bool flagsactive; Bitu last_used; - Bitu stored_flags; GenReg * regs[X86_REGS]; } x86gen; @@ -98,13 +98,13 @@ static BlockReturn gen_runcode(Bit8u * code) { push edi mov ebx,[reg_flags] and ebx,FMASK_TEST + push offset(return_address) push ebx - popfd - call eax + jmp eax /* Restore the flags */ - pushfd +return_address: + /* return here with flags in ecx */ and dword ptr [reg_flags],~FMASK_TEST - pop ecx and ecx,FMASK_TEST or [reg_flags],ecx pop edi @@ -114,23 +114,17 @@ static BlockReturn gen_runcode(Bit8u * code) { mov [retval],eax } #else + register Bit32u tempflags=reg_flags & FMASK_TEST; __asm__ volatile ( - "movl %1,%%esi \n" - "andl %2,%%esi \n" - "pushl %%ebp \n" - "pushl %%esi \n" - "popfl \n" - "calll *%4 \n" - "popl %%ebp \n" - "pushfl \n" - "andl %3,(%1) \n" - "popl %%esi \n" - "andl %2,%%esi \n" - "orl %%esi,(%1) \n" - :"=a" (retval) - :"m" (reg_flags), "n" (FMASK_TEST),"n" (~FMASK_TEST),"r" (code) - :"%ecx","%edx","%ebx","%edi","%esi","cc","memory" + "pushl $(run_return_adress) \n" + "pushl %2 \n" + "jmp *%3 \n" + "run_return_adress: \n" + :"=a" (retval), "=c" (tempflags) + :"r" (tempflags),"r" (code) + :"%edx","%ebx","%edi","%esi","cc","memory" ); + reg_flags=(reg_flags & ~FMASK_TEST) | (tempflags & FMASK_TEST); #endif return retval; } @@ -232,28 +226,23 @@ static void gen_synchreg(DynReg * dnew,DynReg * dsynch) { } } -static void gen_storeflags(void) { - if (!x86gen.stored_flags) { - cache_addb(0x9c); //PUSHFD +static void gen_needflags(void) { + if (!x86gen.flagsactive) { + x86gen.flagsactive=true; + cache_addb(0x9d); //POPFD } - x86gen.stored_flags++; } -static void gen_restoreflags(bool noreduce=false) { - if (noreduce) { - cache_addb(0x9d); - return; +static void gen_protectflags(void) { + if (x86gen.flagsactive) { + x86gen.flagsactive=false; + cache_addb(0x9c); //PUSHFD } - if (x86gen.stored_flags) { - x86gen.stored_flags--; - if (!x86gen.stored_flags) - cache_addb(0x9d); //POPFD - } else IllegalOption(); } static void gen_reinit(void) { x86gen.last_used=0; - x86gen.stored_flags=0; + x86gen.flagsactive=false; for (Bitu i=0;idynreg=0; } @@ -604,7 +593,7 @@ static void gen_call_function(void * func,char * ops,...) { x86gen.regs[X86_REG_EAX]->Clear(); x86gen.regs[X86_REG_EAX]->notusable=true;; /* Save the flags */ - gen_storeflags(); + gen_protectflags(); /* Scan for the amount of params */ if (ops) { va_list params; @@ -704,7 +693,6 @@ static void gen_call_function(void * func,char * ops,...) { } dynreg->flags|=DYNFLG_CHANGED; } - gen_restoreflags(); /* Restore EAX registers to be used again */ x86gen.regs[X86_REG_EAX]->notusable=false; } @@ -747,17 +735,20 @@ static void gen_jmp_ptr(void * ptr,Bits imm=0) { } } -static void gen_save_flags(DynReg * dynreg,bool stored) { +static void gen_save_flags(DynReg * dynreg) { + if (x86gen.flagsactive) IllegalOption(); GenReg * genreg=FindDynReg(dynreg); - if (!stored) cache_addb(0x9c); //Pushfd - cache_addb(0x58+genreg->index); //POP 32 REG + cache_addb(0x8b); //MOV REG,[esp] + cache_addw(0x2404+(genreg->index << 3)); dynreg->flags|=DYNFLG_CHANGED; } static void gen_load_flags(DynReg * dynreg) { + if (x86gen.flagsactive) IllegalOption(); + cache_addw(0xc483); //ADD ESP,4 + cache_addb(0x4); GenReg * genreg=FindDynReg(dynreg); cache_addb(0x50+genreg->index); //PUSH 32 - cache_addb(0x9d); //POPFD } static void gen_save_host_direct(void * data,Bits imm) { @@ -781,9 +772,11 @@ static void gen_load_host(void * data,DynReg * dr1,Bitu size) { } static void gen_return(BlockReturn retcode) { - cache_addb(0xb8); + gen_protectflags(); + cache_addb(0x59); //POP ECX, the flags + cache_addb(0xb8); //MOV EAX, retcode cache_addd(retcode); - cache_addb(0xc3); + cache_addb(0xc3); //RET } static void gen_init(void) { diff --git a/src/cpu/core_dyn_x86/string.h b/src/cpu/core_dyn_x86/string.h index 7a713d9e..443b9af0 100644 --- a/src/cpu/core_dyn_x86/string.h +++ b/src/cpu/core_dyn_x86/string.h @@ -30,7 +30,7 @@ static void dyn_string(STRING_OP op) { DynReg * si_base=decode.segprefix ? decode.segprefix : DREG(DS); DynReg * di_base=DREG(ES); DynReg * tmp_reg;bool usesi;bool usedi; - gen_storeflags(); + gen_protectflags(); if (decode.rep) { gen_dop_word_imm(DOP_SUB,true,DREG(CYCLES),decode.cycles); gen_releasereg(DREG(CYCLES)); @@ -151,7 +151,6 @@ static void dyn_string(STRING_OP op) { Bit8u * cycle_branch=gen_create_branch(BR_NLE); gen_lea(DREG(EIP),DREG(EIP),0,0,decode.op_start-decode.code_start); dyn_releaseregs(); - gen_restoreflags(true); gen_return(BR_Cycles); gen_fill_branch(cycle_branch); dyn_loadstate(&cycle_state); @@ -161,5 +160,4 @@ static void dyn_string(STRING_OP op) { gen_fill_jump(rep_ecx_jmp); } gen_releasereg(DREG(TMPW)); - gen_restoreflags(); }