Logo Search packages:      
Sourcecode: dosbox version File versions  Download package

cache.h

class CacheBlock {
public:
      void Clear(void);
      void LinkTo(Bitu index,CacheBlock * toblock) {
            assert(toblock);
            link[index].to=toblock;
            link[index].next=toblock->link[index].from;
            toblock->link[index].from=this;
      }
      struct {
            Bit16u start,end;                   //Where the page is the original code
            CodePageHandler * handler;          //Page containing this code
      } page;
      struct {
            Bit8u * start;                            //Where in the cache are we
            Bitu size;
            CacheBlock * next;
      } cache;
      struct {
            Bitu index;
            CacheBlock * next;
      } hash;
      struct {
            CacheBlock * to;
            CacheBlock * next;
            CacheBlock * from;
      } link[2];
      CacheBlock * crossblock;
};

class CacheBlock;
static struct {
      struct {
            CacheBlock * first;
            CacheBlock * active;
            CacheBlock * free;
            CacheBlock * running;
      } block;
      Bit8u * pos;
      CodePageHandler * free_pages;
      CodePageHandler * used_pages;
      CodePageHandler * last_page;
} cache;

static Bit8u cache_code_link_blocks[2][16];
static Bit8u cache_code[CACHE_TOTAL+CACHE_MAXSIZE];
static CacheBlock cache_blocks[CACHE_BLOCKS];
static CacheBlock link_blocks[2];
class CodePageHandler :public PageHandler {
public:
      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(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) 
                              block->Clear();
                        block=nextblock;
                  }
                  index--;
            }
      }
      void writeb(PhysPt addr,Bitu 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){
            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){
            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) {
            Bitu index=1+(block->page.start>>DYN_HASH_SHIFT);
            block->hash.next=hash_map[index];
            block->hash.index=index;
            hash_map[index]=block;
            block->page.handler=this;
            active_blocks++;
      }
    void AddCrossBlock(CacheBlock * block) {
            block->hash.next=hash_map[0];
            block->hash.index=0;
            hash_map[0]=block;
            block->page.handler=this;
            active_blocks++;
      }
      void DelCacheBlock(CacheBlock * block) {
            active_blocks--;
            active_count=16;
            CacheBlock * * where=&hash_map[block->hash.index];
            while (*where!=block) {
                  where=&((*where)->hash.next);
                  //Will crash if a block isn't found, which should never happen.
            }
            *where=block->hash.next;
            for (Bitu i=block->page.start;i<=block->page.end;i++) {
                  if (write_map[i]) write_map[i]--;
            }
      }
      void Release(void) {
            MEM_SetPageHandler(phys_page,1,old_pagehandler);
            PAGING_ClearTLB();
            if (prev) prev->next=next;
            else cache.used_pages=next;
            if (next) next->prev=prev;
            else cache.last_page=prev;
            next=cache.free_pages;
            cache.free_pages=this;
            prev=0;
      }
      void ClearRelease(void) {
            for (Bitu index=0;index<(1+DYN_PAGE_HASH);index++) {
                  CacheBlock * block=hash_map[index];
                  while (block) {
                        CacheBlock * nextblock=block->hash.next;
                        block->page.handler=0;              //No need, full clear
                        block->Clear();
                        block=nextblock;
                  }
            }
            Release();
      }
      CacheBlock * FindCacheBlock(Bitu start) {
            CacheBlock * block=hash_map[1+(start>>DYN_HASH_SHIFT)];
            while (block) {
                  if (block->page.start==start) return block;
                  block=block->hash.next;
            }
            return 0;
      }
      HostPt GetHostPt(Bitu phys_page) { 
            hostmem=old_pagehandler->GetHostPt(phys_page);
            return hostmem;
      }
public:
      Bit8u write_map[4096];
      CodePageHandler * next, * prev;
private:
      PageHandler * old_pagehandler;
      CacheBlock * hash_map[1+DYN_PAGE_HASH];
      Bitu active_blocks;
      Bitu active_count;
      HostPt hostmem;   
      Bitu phys_page;
};


static 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->cache.next=cache.block.free;
      cache.block.free=block;
}

static CacheBlock * cache_getblock(void) {
      CacheBlock * ret=cache.block.free;
      if (!ret) E_Exit("Ran out of CacheBlocks" );
      cache.block.free=ret->cache.next;
      ret->cache.next=0;
      return ret;
}

void CacheBlock::Clear(void) {
      Bitu ind;
      /* Check if this is not a cross page block */
      if (hash.index) for (ind=0;ind<2;ind++) {
            CacheBlock * fromlink=link[ind].from;
            link[ind].from=0;
            while (fromlink) {
                  CacheBlock * nextlink=fromlink->link[ind].next;
                  fromlink->link[ind].next=0;
                  fromlink->link[ind].to=&link_blocks[ind];
                  fromlink=nextlink;
            }
            if (link[ind].to!=&link_blocks[ind]) {
                  CacheBlock * * wherelink=&link[ind].to->link[ind].from;
                  while (*wherelink!=this) {
                        wherelink=&(*wherelink)->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 CacheBlock * cache_openblock(void) {
      CacheBlock * block=cache.block.active;
      /* check for enough space in this block */
      Bitu size=block->cache.size;
      CacheBlock * nextblock=block->cache.next;
      if (block->page.handler) 
            block->Clear();
      while (size<CACHE_MAXSIZE) {
            if (!nextblock) 
                  goto skipresize;
            size+=nextblock->cache.size;
            CacheBlock * tempblock=nextblock->cache.next;
            if (nextblock->page.handler) 
                  nextblock->Clear();
            cache_addunsedblock(nextblock);
            nextblock=tempblock;
      }
skipresize:
      block->cache.size=size;
      block->cache.next=nextblock;
      cache.pos=block->cache.start;
      return block;
}

static void cache_closeblock(void) {
      CacheBlock * block=cache.block.active;
      block->link[0].to=&link_blocks[0];
      block->link[1].to=&link_blocks[1];
      block->link[0].from=0;
      block->link[1].from=0;
      block->link[0].next=0;
      block->link[1].next=0;
      /* Close the block with correct alignments */
      Bitu written=cache.pos-block->cache.start;
      if (written>block->cache.size) {
            if (!block->cache.next) {
                  if (written>block->cache.size+CACHE_MAXSIZE) E_Exit("CacheBlock overrun 1 %d",written-block->cache.size);   
            } else E_Exit("CacheBlock overrun 2 written %d size %d",written,block->cache.size); 
      } else {
            Bitu new_size;
            Bitu left=block->cache.size-written;
            /* Smaller than cache align then don't bother to resize */
            if (left>CACHE_ALIGN) {
                  new_size=((written-1)|(CACHE_ALIGN-1))+1;
                  CacheBlock * newblock=cache_getblock();
                  newblock->cache.start=block->cache.start+new_size;
                  newblock->cache.size=block->cache.size-new_size;
                  newblock->cache.next=block->cache.next;
                  block->cache.next=newblock;
                  block->cache.size=new_size;
            }
      }
      /* Advance the active block pointer */
      if (!block->cache.next) {
//          LOG_MSG("Cache full restarting");
            cache.block.active=cache.block.first;
      } else {
            cache.block.active=block->cache.next;
      }
}

static INLINE void cache_addb(Bit8u val) {
      *cache.pos++=val;
}

static INLINE void cache_addw(Bit16u val) {
      *(Bit16u*)cache.pos=val;
      cache.pos+=2;
}

static INLINE void cache_addd(Bit32u val) {
      *(Bit32u*)cache.pos=val;
      cache.pos+=4;
}


static void gen_return(BlockReturn retcode);

static void cache_init(void) {
      Bits i;
      memset(&cache_blocks,0,sizeof(cache_blocks));
      cache.block.free=&cache_blocks[0];
      for (i=0;i<CACHE_BLOCKS-1;i++) {
            cache_blocks[i].link[0].to=(CacheBlock *)1;
            cache_blocks[i].link[1].to=(CacheBlock *)1;
            cache_blocks[i].cache.next=&cache_blocks[i+1];
      }
      CacheBlock * block=cache_getblock();
      cache.block.first=block;
      cache.block.active=block;
      block->cache.start=&cache_code[0];
      block->cache.size=CACHE_TOTAL;
      block->cache.next=0;                                              //Last block in the list
      cache.pos=&cache_code_link_blocks[0][0];
      link_blocks[0].cache.start=cache.pos;
      gen_return(BR_Link1);
      cache.pos=&cache_code_link_blocks[1][0];
      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;
      }
}

Generated by  Doxygen 1.6.0   Back to index