/* * 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 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 (512*1024) #define CACHE_MAXSIZE (4096) #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) #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_TEST, DOP_MOV, DOP_XCHG, }; enum ShiftOps { SHIFT_ROL,SHIFT_ROR, SHIFT_RCL,SHIFT_RCR, SHIFT_SHL,SHIFT_SHR, SHIFT_SAL,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 BlockReturn { BR_Normal=0, BR_Cycles, BR_Link1,BR_Link2, BR_Opcode, #if (C_DEBUG) BR_OpcodeFull, #endif 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_flags_host_to_gen(void) { gen_dop_word(DOP_MOV,true,DREG(EXIT),DREG(FLAGS)); gen_dop_word_imm(DOP_AND,true,DREG(EXIT),FMASK_TEST); gen_load_flags(DREG(EXIT)); gen_releasereg(DREG(EXIT)); gen_releasereg(DREG(FLAGS)); } static void dyn_flags_gen_to_host(void) { 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 gen_releasereg(DREG(EXIT)); gen_releasereg(DREG(FLAGS)); } static void dyn_savestate(DynState * state) { 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; #if C_HEAVY_DEBUG if (DEBUG_HeavyIsBreakpoint()) return debugCallback; #endif 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); } 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 */ for (i=0;i