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:
parent
76d89159c9
commit
a07aad49c8
5 changed files with 509 additions and 416 deletions
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue