/* * Copyright (C) 2002-2004 The DOSBox Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "dosbox.h" #if (C_DYNAMIC_X86) #include #include #include #include #include "callback.h" #include "regs.h" #include "mem.h" #include "cpu.h" #include "debug.h" #include "paging.h" #include "inout.h" #define CACHE_TOTAL (1024*1024*2) #define CACHE_MAXSIZE (4096) #define CACHE_BLOCKS (50*1024) #define CACHE_ALIGN (16) #define DYN_HASH_SHIFT (4) #define DYN_PAGE_HASH (4096>>DYN_HASH_SHIFT) #define DYN_LINKS (16) #if 0 #define DYN_LOG LOG_MSG #else #define DYN_LOG #endif enum { G_EAX,G_ECX,G_EDX,G_EBX, G_ESP,G_EBP,G_ESI,G_EDI, G_ES,G_CS,G_SS,G_DS,G_FS,G_GS, G_FLAGS,G_SMASK,G_EIP, G_EA,G_STACK,G_CYCLES, G_TMPB,G_TMPW,G_SHIFT, G_EXIT, G_MAX, }; enum SingleOps { SOP_INC,SOP_DEC, SOP_NOT,SOP_NEG, }; enum DualOps { DOP_ADD,DOP_ADC, DOP_SUB,DOP_SBB, DOP_CMP,DOP_XOR, DOP_AND,DOP_OR, DOP_MOV, DOP_TEST, DOP_XCHG, }; enum ShiftOps { SHIFT_ROL,SHIFT_ROR, SHIFT_RCL,SHIFT_RCR, SHIFT_SHL,SHIFT_SHR, SHIFT_SAR, }; enum BranchTypes { BR_O,BR_NO,BR_B,BR_NB, BR_Z,BR_NZ,BR_BE,BR_NBE, BR_S,BR_NS,BR_P,BR_NP, 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, BR_CallBack, }; #define DYNFLG_HAS16 0x1 //Would like 8-bit host reg support #define DYNFLG_HAS8 0x2 //Would like 16-bit host reg support #define DYNFLG_LOAD 0x4 //Load value when accessed #define DYNFLG_SAVE 0x8 //Needs to be saved back at the end of block #define DYNFLG_CHANGED 0x10 //Value is in a register and changed from load #define DYNFLG_ACTIVE 0x20 //Register has an active value class GenReg; class CodePageHandler; struct DynReg { Bitu flags; GenReg * genreg; void * data; }; enum DynAccess { DA_d,DA_w, DA_bh,DA_bl }; enum ByteCombo { BC_ll,BC_lh, BC_hl,BC_hh, }; static DynReg DynRegs[G_MAX]; #define DREG(_WHICH_) &DynRegs[G_ ## _WHICH_ ] static struct { Bitu ea,tmpb,tmpd,stack,shift; } extra_regs; static void IllegalOption(void) { E_Exit("Illegal option"); } #include "core_dyn_x86/cache.h" static struct { Bitu callback; } core_dyn; #include "core_dyn_x86/risc_x86.h" struct DynState { DynReg regs[G_MAX]; }; static void dyn_releaseregs(void) { for (Bitu i=0;iregs[i].flags=DynRegs[i].flags; state->regs[i].genreg=DynRegs[i].genreg; } } static void dyn_loadstate(DynState * state) { for (Bitu i=0;iregs[i]); } } static void dyn_synchstate(DynState * state) { for (Bitu i=0;iregs[i]); } } #include "core_dyn_x86/decoder.h" Bits CPU_Core_Dyn_X86_Run(void) { /* Determine the linear address of CS:EIP */ 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; #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; } return 0; } void CPU_Core_Dyn_X86_Init(void) { Bits i; /* Setup the global registers and their flags */ for (i=0;i