1
0
Fork 0

New write map to handle write protection

New flag handling
New linking handling of blocks
Better handling of cache resetting
Some bug fixes


Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@1738
This commit is contained in:
Sjoerd van der Berg 2004-03-23 21:00:42 +00:00
parent 76d89159c9
commit a07aad49c8
5 changed files with 509 additions and 416 deletions

View file

@ -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 */

View file

@ -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;i<DYN_LINKS;i++) {
if (block->link.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;i<DYN_LINKS;i++) {
if (block->link.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 (size<CACHE_MAXSIZE) {
if (!nextblock) goto skipresize;
if (!nextblock)
goto skipresize;
size+=nextblock->cache.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;i<CACHE_BLOCKS-1;i++) {
cache_blocks[i].list_next=&cache_blocks[i+1];
cache_blocks[i].link.to[0]=&cache.linkblocks[0];
cache_blocks[i].link.to[1]=&cache.linkblocks[1];
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];
}
CacheBlock * block=cache_getblock();
cache.block.first=block;
cache.block.active=block;
block->cache.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);
}
cache.free_pages=0;
cache.last_page=0;
cache.used_pages=0;
/* Setup the code pages */
for (i=0;i<CACHE_PAGES-1;i++) {
CodePageHandler * newpage=new CodePageHandler();
newpage->next=cache.free_pages;
cache.free_pages=newpage;
}
}

View file

@ -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_MAX;i++) {
DynRegs[i].flags&=~(DYNFLG_ACTIVE|DYNFLG_CHANGED);
@ -930,19 +982,17 @@ static CacheBlock * CreateCacheBlock(PhysPt start,bool big,Bitu max_opcodes) {
}
gen_reinit();
/* Start with the cycles check */
gen_storeflags();
gen_protectflags();
gen_dop_word_imm(DOP_CMP,true,DREG(CYCLES),0);
Bit8u * cyclebranch=gen_create_branch(BR_NLE);
gen_restoreflags(true);
gen_return(BR_Cycles);
gen_fill_branch(cyclebranch);
gen_releasereg(DREG(CYCLES));
gen_restoreflags();
decode.cycles=0;
while (max_opcodes--) {
/* Init prefixes */
decode.big_addr=big;
decode.big_op=big;
decode.big_addr=cpu.code.big;
decode.big_op=cpu.code.big;
decode.segprefix=0;
decode.rep=REP_NONE;
decode.cycles++;
@ -950,13 +1000,12 @@ static CacheBlock * CreateCacheBlock(PhysPt start,bool big,Bitu max_opcodes) {
restart_prefix:
Bitu opcode=decode_fetchb();
switch (opcode) {
//Add
case 0x00:dyn_dop_ebgb(DOP_ADD);break;
case 0x01:dyn_dop_evgv(DOP_ADD);break;
case 0x02:dyn_dop_gbeb(DOP_ADD);break;
case 0x03:dyn_dop_gvev(DOP_ADD);break;
case 0x04:gen_dop_byte_imm(DOP_ADD,DREG(EAX),0,decode_fetchb());break;
case 0x05:gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
case 0x04:gen_needflags();gen_dop_byte_imm(DOP_ADD,DREG(EAX),0,decode_fetchb());break;
case 0x05:gen_needflags();gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
case 0x06:dyn_push_seg(es);break;
case 0x07:dyn_pop_seg(es);break;
@ -964,8 +1013,8 @@ restart_prefix:
case 0x09:dyn_dop_evgv(DOP_OR);break;
case 0x0a:dyn_dop_gbeb(DOP_OR);break;
case 0x0b:dyn_dop_gvev(DOP_OR);break;
case 0x0c:gen_dop_byte_imm(DOP_OR,DREG(EAX),0,decode_fetchb());break;
case 0x0d:gen_dop_word_imm(DOP_OR,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
case 0x0c:gen_needflags();gen_dop_byte_imm(DOP_OR,DREG(EAX),0,decode_fetchb());break;
case 0x0d:gen_needflags();gen_dop_word_imm(DOP_OR,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
case 0x0e:dyn_push_seg(cs);break;
case 0x0f:
{
@ -976,7 +1025,7 @@ restart_prefix:
case 0x88:case 0x89:case 0x8a:case 0x8b:case 0x8c:case 0x8d:case 0x8e:case 0x8f:
dyn_branched_exit((BranchTypes)(dual_code&0xf),
decode.big_op ? (Bit32s)decode_fetchd() : (Bit16s)decode_fetchw());
return decode.block;
goto finish_block;
/* PUSH/POP FS */
case 0xa0:dyn_push_seg(fs);break;
case 0xa1:dyn_pop_seg(fs);break;
@ -1006,63 +1055,63 @@ restart_prefix:
goto illegalopcode;
}
}break;
case 0x10:dyn_dop_ebgb(DOP_ADC);break;
case 0x11:dyn_dop_evgv(DOP_ADC);break;
case 0x12:dyn_dop_gbeb(DOP_ADC);break;
case 0x13:dyn_dop_gvev(DOP_ADC);break;
case 0x14:gen_dop_byte_imm(DOP_ADC,DREG(EAX),0,decode_fetchb());break;
case 0x15:gen_dop_word_imm(DOP_ADC,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
case 0x14:gen_needflags();gen_dop_byte_imm(DOP_ADC,DREG(EAX),0,decode_fetchb());break;
case 0x15:gen_needflags();gen_dop_word_imm(DOP_ADC,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
case 0x16:dyn_push_seg(ss);break;
case 0x17:dyn_pop_seg(ss);break;
case 0x18:dyn_dop_ebgb(DOP_SBB);break;
case 0x19:dyn_dop_evgv(DOP_SBB);break;
case 0x1a:dyn_dop_gbeb(DOP_SBB);break;
case 0x1b:dyn_dop_gvev(DOP_SBB);break;
case 0x1c:gen_dop_byte_imm(DOP_SBB,DREG(EAX),0,decode_fetchb());break;
case 0x1d:gen_dop_word_imm(DOP_SBB,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
case 0x1c:gen_needflags();gen_dop_byte_imm(DOP_SBB,DREG(EAX),0,decode_fetchb());break;
case 0x1d:gen_needflags();gen_dop_word_imm(DOP_SBB,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
case 0x1e:dyn_push_seg(ds);break;
case 0x1f:dyn_pop_seg(ds);break;
case 0x20:dyn_dop_ebgb(DOP_AND);break;
case 0x21:dyn_dop_evgv(DOP_AND);break;
case 0x22:dyn_dop_gbeb(DOP_AND);break;
case 0x23:dyn_dop_gvev(DOP_AND);break;
case 0x24:gen_dop_byte_imm(DOP_AND,DREG(EAX),0,decode_fetchb());break;
case 0x25:gen_dop_word_imm(DOP_AND,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
case 0x24:gen_needflags();gen_dop_byte_imm(DOP_AND,DREG(EAX),0,decode_fetchb());break;
case 0x25:gen_needflags();gen_dop_word_imm(DOP_AND,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
case 0x26:dyn_segprefix(es);goto restart_prefix;
case 0x28:dyn_dop_ebgb(DOP_SUB);break;
case 0x29:dyn_dop_evgv(DOP_SUB);break;
case 0x2a:dyn_dop_gbeb(DOP_SUB);break;
case 0x2b:dyn_dop_gvev(DOP_SUB);break;
case 0x2c:gen_dop_byte_imm(DOP_SUB,DREG(EAX),0,decode_fetchb());break;
case 0x2d:gen_dop_word_imm(DOP_SUB,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
case 0x2c:gen_needflags();gen_dop_byte_imm(DOP_SUB,DREG(EAX),0,decode_fetchb());break;
case 0x2d:gen_needflags();gen_dop_word_imm(DOP_SUB,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
case 0x2e:dyn_segprefix(cs);goto restart_prefix;
case 0x30:dyn_dop_ebgb(DOP_XOR);break;
case 0x31:dyn_dop_evgv(DOP_XOR);break;
case 0x32:dyn_dop_gbeb(DOP_XOR);break;
case 0x33:dyn_dop_gvev(DOP_XOR);break;
case 0x34:gen_dop_byte_imm(DOP_XOR,DREG(EAX),0,decode_fetchb());break;
case 0x35:gen_dop_word_imm(DOP_XOR,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
case 0x34:gen_needflags();gen_dop_byte_imm(DOP_XOR,DREG(EAX),0,decode_fetchb());break;
case 0x35:gen_needflags();gen_dop_word_imm(DOP_XOR,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
case 0x36:dyn_segprefix(ss);goto restart_prefix;
case 0x38:dyn_dop_ebgb(DOP_CMP);break;
case 0x39:dyn_dop_evgv(DOP_CMP);break;
case 0x3a:dyn_dop_gbeb(DOP_CMP);break;
case 0x3b:dyn_dop_gvev(DOP_CMP);break;
case 0x3c:gen_dop_byte_imm(DOP_CMP,DREG(EAX),0,decode_fetchb());break;
case 0x3d:gen_dop_word_imm(DOP_CMP,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
case 0x3c:gen_needflags();gen_dop_byte_imm(DOP_CMP,DREG(EAX),0,decode_fetchb());break;
case 0x3d:gen_needflags();gen_dop_word_imm(DOP_CMP,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
case 0x3e:dyn_segprefix(ds);goto restart_prefix;
/* INC/DEC general register */
/* INC/DEC general register */
case 0x40:case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46:case 0x47:
gen_sop_word(SOP_INC,decode.big_op,&DynRegs[opcode&7]);
gen_needflags();gen_sop_word(SOP_INC,decode.big_op,&DynRegs[opcode&7]);
break;
case 0x48:case 0x49:case 0x4a:case 0x4b:case 0x4c:case 0x4d:case 0x4e:case 0x4f:
gen_sop_word(SOP_DEC,decode.big_op,&DynRegs[opcode&7]);
gen_needflags();gen_sop_word(SOP_DEC,decode.big_op,&DynRegs[opcode&7]);
break;
/* PUSH/POP General register */
case 0x50:case 0x51:case 0x52:case 0x53:case 0x55:case 0x56:case 0x57:
dyn_push(&DynRegs[opcode&7]);
@ -1076,29 +1125,26 @@ restart_prefix:
dyn_pop(&DynRegs[opcode&7]);
break;
case 0x60: /* PUSHA */
gen_storeflags();
gen_dop_word(DOP_MOV,true,DREG(TMPW),DREG(ESP));
for (i=G_EAX;i<=G_EDI;i++) {
dyn_push((i!=G_ESP) ? &DynRegs[i] : DREG(TMPW));
}
gen_restoreflags();
gen_releasereg(DREG(TMPW));
break;
case 0x61: /* POPA */
gen_storeflags();
for (i=G_EDI;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;
}

View file

@ -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;i<X86_REGS;i++) {
x86gen.regs[i]->dynreg=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) {

View file

@ -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();
}