diff --git a/include/cpu.h b/include/cpu.h index 06d03589..5544f93f 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2007 The DOSBox Team + * Copyright (C) 2002-2008 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: cpu.h,v 1.52 2008-01-16 20:16:31 c2woody Exp $ */ +/* $Id: cpu.h,v 1.53 2008-05-18 13:10:42 c2woody Exp $ */ #ifndef DOSBOX_CPU_H #define DOSBOX_CPU_H @@ -40,6 +40,14 @@ #define CPU_CYCLES_LOWER_LIMIT 100 + +#define CPU_ARCHTYPE_MIXED 0xff +#define CPU_ARCHTYPE_386SLOW 0x30 +#define CPU_ARCHTYPE_386FAST 0x35 +#define CPU_ARCHTYPE_486OLDSLOW 0x40 +#define CPU_ARCHTYPE_486NEWSLOW 0x45 +#define CPU_ARCHTYPE_PENTIUMSLOW 0x50 + /* CPU Cycle Timing */ extern Bit32s CPU_Cycles; extern Bit32s CPU_CycleLeft; @@ -52,6 +60,8 @@ extern bool CPU_CycleAutoAdjust; extern bool CPU_SkipCycleAutoAdjust; extern Bitu CPU_AutoDetermineMode; +extern Bitu CPU_ArchitectureType; + /* Some common Defines */ /* A CPU Handler */ typedef Bits (CPU_Decoder)(void); @@ -146,7 +156,7 @@ void CPU_Exception(Bitu which,Bitu error=0); bool CPU_SetSegGeneral(SegNames seg,Bitu value); bool CPU_PopSeg(SegNames seg,bool use32); -void CPU_CPUID(void); +bool CPU_CPUID(void); Bitu CPU_Pop16(void); Bitu CPU_Pop32(void); void CPU_Push16(Bitu value); diff --git a/src/cpu/core_dyn_x86/decoder.h b/src/cpu/core_dyn_x86/decoder.h index 4f23c0ad..56ebfb52 100644 --- a/src/cpu/core_dyn_x86/decoder.h +++ b/src/cpu/core_dyn_x86/decoder.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2007 The DOSBox Team + * Copyright (C) 2002-2008 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 @@ -16,6 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $Id: decoder.h,v 1.55 2008-05-18 13:11:14 c2woody Exp $ */ + #define X86_DYNFPU_DH_ENABLED #define X86_INLINED_MEMACCESS @@ -1329,6 +1331,68 @@ static void dyn_mov_ev_gw(bool sign) { } } +static void dyn_cmpxchg_evgv(void) { + dyn_get_modrm(); + DynReg * rm_reg=&DynRegs[decode.modrm.reg]; + gen_protectflags(); + if (decode.modrm.mod<3) { + gen_releasereg(DREG(EAX)); + gen_releasereg(DREG(TMPB)); + gen_releasereg(rm_reg); + + dyn_fill_ea(); + dyn_read_word(DREG(EA),DREG(TMPB),decode.big_op); + gen_dop_word(DOP_CMP,decode.big_op,DREG(EAX),DREG(TMPB)); + Bit8u * branch=gen_create_branch(BR_NZ); + + // eax==mem -> mem:=rm_reg + dyn_write_word_release(DREG(EA),rm_reg,decode.big_op); + gen_setzeroflag(); + gen_releasereg(DREG(EAX)); + gen_releasereg(DREG(TMPB)); + gen_releasereg(rm_reg); + + Bit8u * jump=gen_create_jump(); + + gen_fill_branch(branch); + // eax!=mem -> eax:=mem + dyn_write_word_release(DREG(EA),DREG(TMPB),decode.big_op); // cmpxchg always issues write + gen_dop_word(DOP_MOV,decode.big_op,DREG(EAX),DREG(TMPB)); + gen_clearzeroflag(); + gen_releasereg(DREG(EAX)); + gen_releasereg(DREG(TMPB)); + gen_releasereg(rm_reg); + + gen_fill_jump(jump); + } else { + gen_releasereg(DREG(EAX)); + gen_releasereg(&DynRegs[decode.modrm.rm]); + gen_releasereg(rm_reg); + + gen_dop_word(DOP_CMP,decode.big_op,DREG(EAX),&DynRegs[decode.modrm.rm]); + Bit8u * branch=gen_create_branch(BR_NZ); + + // eax==rm -> rm:=rm_reg + gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],rm_reg); + gen_setzeroflag(); + gen_releasereg(DREG(EAX)); + gen_releasereg(&DynRegs[decode.modrm.rm]); + gen_releasereg(rm_reg); + + Bit8u * jump=gen_create_jump(); + + gen_fill_branch(branch); + // eax!=rm -> eax:=rm + gen_dop_word(DOP_MOV,decode.big_op,DREG(EAX),&DynRegs[decode.modrm.rm]); + gen_clearzeroflag(); + gen_releasereg(DREG(EAX)); + gen_releasereg(&DynRegs[decode.modrm.rm]); + gen_releasereg(rm_reg); + + gen_fill_jump(jump); + } +} + static void dyn_dshift_ev_gv(bool left,bool immediate) { dyn_get_modrm(); DynReg * rm_reg=&DynRegs[decode.modrm.reg]; @@ -1995,6 +2059,8 @@ restart_prefix: case 0xad:dyn_dshift_ev_gv(false,false);break; /* Imul Ev,Gv */ case 0xaf:dyn_imul_gvev(0);break; + /* CMPXCHG */ + case 0xb1:dyn_cmpxchg_evgv();break; /* LFS,LGS */ case 0xb4: dyn_get_modrm(); diff --git a/src/cpu/core_dyn_x86/risc_x86.h b/src/cpu/core_dyn_x86/risc_x86.h index 709cf6b6..b091c384 100644 --- a/src/cpu/core_dyn_x86/risc_x86.h +++ b/src/cpu/core_dyn_x86/risc_x86.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2007 The DOSBox Team + * Copyright (C) 2002-2008 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 @@ -16,6 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $Id: risc_x86.h,v 1.30 2008-05-18 13:11:14 c2woody Exp $ */ + static void gen_init(void); /* End of needed */ @@ -268,6 +270,18 @@ static void gen_needcarry(void) { } } +static void gen_setzeroflag(void) { + if (x86gen.flagsactive) IllegalOption("gen_setzeroflag"); + cache_addw(0x0c83); //OR DWORD [ESP],0x40 + cache_addw(0x4024); +} + +static void gen_clearzeroflag(void) { + if (x86gen.flagsactive) IllegalOption("gen_clearzeroflag"); + cache_addw(0x2483); //AND DWORD [ESP],~0x40 + cache_addw(0xbf24); +} + static bool skip_flags=false; static void set_skipflags(bool state) { diff --git a/src/cpu/core_full/load.h b/src/cpu/core_full/load.h index a0c1ca47..a5e7adeb 100644 --- a/src/cpu/core_full/load.h +++ b/src/cpu/core_full/load.h @@ -468,7 +468,7 @@ l_M_Ed: AAS(); goto nextopcode; case D_CPUID: - CPU_CPUID(); + if (!CPU_CPUID()) goto illegalopcode; goto nextopcode; case D_HLT: if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); diff --git a/src/cpu/core_full/op.h b/src/cpu/core_full/op.h index 67ae2c9a..bfcb90d1 100644 --- a/src/cpu/core_full/op.h +++ b/src/cpu/core_full/op.h @@ -585,8 +585,22 @@ switch (inst.code.op) { inst_op1_d&=~(1 << (inst_op2_d & 31)); break; case O_BSWAP: + if (CPU_ArchitectureType=0xc0) << 3) | inst.code.save) { diff --git a/src/cpu/core_full/optable.h b/src/cpu/core_full/optable.h index fcdb1508..39907e0e 100644 --- a/src/cpu/core_full/optable.h +++ b/src/cpu/core_full/optable.h @@ -661,7 +661,7 @@ static OpCode OpCodeTable[1024]={ {0 ,0 ,0 ,0 },{L_MODRM ,O_IMULRd ,S_Gd ,M_EdxGdx }, /* 0x3b0 - 0x3b7 */ -{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{L_MODRM ,O_CMPXCHG ,S_Ed ,M_Ed }, {L_MODRM ,O_SEGSS ,S_SEGGd,M_Efd },{L_MODRM ,O_BTRd ,S_Ed ,M_EdGdt }, {L_MODRM ,O_SEGFS ,S_SEGGd,M_Efd },{L_MODRM ,O_SEGGS ,S_SEGGd,M_Efd }, {L_MODRM ,0 ,S_Gd ,M_Eb },{L_MODRM ,0 ,S_Gd ,M_Ew }, diff --git a/src/cpu/core_full/support.h b/src/cpu/core_full/support.h index cde08ebc..32b92620 100644 --- a/src/cpu/core_full/support.h +++ b/src/cpu/core_full/support.h @@ -94,7 +94,7 @@ enum { O_BTd,O_BTSd,O_BTRd,O_BTCd, O_BSFw,O_BSRw,O_BSFd,O_BSRd, - O_BSWAP, + O_BSWAP,O_CMPXCHG, O_FPU, diff --git a/src/cpu/core_normal/prefix_0f.h b/src/cpu/core_normal/prefix_0f.h index 16397144..388c15c2 100644 --- a/src/cpu/core_normal/prefix_0f.h +++ b/src/cpu/core_normal/prefix_0f.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2007 The DOSBox Team + * Copyright (C) 2002-2008 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 @@ -142,6 +142,11 @@ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); cpu.cr0&=(~CR0_TASKSWITCH); break; + CASE_0F_B(0x08) /* INVD */ + CASE_0F_B(0x09) /* WBINVD */ + if (CPU_ArchitectureType>32); + reg_eax=(Bit32u)(tsc&0xffffffff); + } + break; CASE_0F_W(0x80) /* JO */ JumpCond16_w(TFLG_O);break; CASE_0F_W(0x81) /* JNO */ @@ -291,7 +304,8 @@ if (CPU_PopSeg(fs,false)) RUNEXCEPTION(); break; CASE_0F_B(0xa2) /* CPUID */ - CPU_CPUID();break; + if (!CPU_CPUID()) goto illegal_opcode; + break; CASE_0F_W(0xa3) /* BT Ew,Gw */ { FillFlags();GetRMrw; @@ -503,6 +517,7 @@ } CASE_0F_B(0xc0) /* XADD Gb,Eb */ { + if (CPU_ArchitectureType= 0xc0 ) {GetEArb;*rmrb=*earb;*earb+=oldrmrb;} else {GetEAa;*rmrb=LoadMb(eaa);SaveMb(eaa,LoadMb(eaa)+oldrmrb);} @@ -510,25 +525,34 @@ } CASE_0F_W(0xc1) /* XADD Gw,Ew */ { + if (CPU_ArchitectureType= 0xc0 ) {GetEArw;*rmrw=*earw;*earw+=oldrmrw;} else {GetEAa;*rmrw=LoadMw(eaa);SaveMw(eaa,LoadMw(eaa)+oldrmrw);} break; } CASE_0F_B(0xc8) /* BSWAP EAX */ + if (CPU_ArchitectureType= 0xc0) { + GetEArd; + if (*eard==reg_eax) { + *eard=*rmrd; + SETFLAGBIT(ZF,1); + } else { + reg_eax=*eard; + SETFLAGBIT(ZF,0); + } + } else { + GetEAa; + Bit32u val=LoadMd(eaa); + if (val==reg_eax) { + SaveMd(eaa,*rmrd); + SETFLAGBIT(ZF,1); + } else { + SaveMd(eaa,val); + reg_eax=val; + SETFLAGBIT(ZF,0); + } + } + break; + } CASE_0F_D(0xb2) /* LSS Ed */ { GetRMrd; @@ -405,6 +433,7 @@ } CASE_0F_D(0xc1) /* XADD Gd,Ed */ { + if (CPU_ArchitectureType= 0xc0 ) {GetEArd;*rmrd=*eard;*eard+=oldrmrd;} else {GetEAa;*rmrd=LoadMd(eaa);SaveMd(eaa,LoadMd(eaa)+oldrmrd);} diff --git a/src/cpu/cpu.cpp b/src/cpu/cpu.cpp index 2fa38733..e5c8991a 100644 --- a/src/cpu/cpu.cpp +++ b/src/cpu/cpu.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: cpu.cpp,v 1.110 2008-05-05 13:29:04 qbix79 Exp $ */ +/* $Id: cpu.cpp,v 1.111 2008-05-18 13:11:14 c2woody Exp $ */ #include #include @@ -61,6 +61,10 @@ bool CPU_CycleAutoAdjust = false; bool CPU_SkipCycleAutoAdjust = false; Bitu CPU_AutoDetermineMode = 0; +Bitu CPU_ArchitectureType = CPU_ARCHTYPE_MIXED; + +Bitu CPU_flag_id_toggle=0; + void CPU_Core_Full_Init(void); void CPU_Core_Normal_Init(void); void CPU_Core_Simple_Init(void); @@ -161,8 +165,10 @@ PhysPt SelBase(Bitu sel) { } } + void CPU_SetFlags(Bitu word,Bitu mask) { - reg_flags=(reg_flags & ~mask)|(word & mask)|2|FLAG_ID; + mask|=CPU_flag_id_toggle; // ID-flag can be toggled on cpuid-supporting CPUs + reg_flags=(reg_flags & ~mask)|(word & mask)|2; cpu.direction=1-((reg_flags & FLAG_DF) >> 9); } @@ -1569,6 +1575,9 @@ bool CPU_WRITE_CRX(Bitu cr,Bitu value) { /* Check if privileged to access control registers */ if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0); if ((cr==1) || (cr>4)) return CPU_PrepareException(EXCEPTION_UD,0); + if (CPU_ArchitectureType=CPU_ARCHTYPE_PENTIUMSLOW) return cpu.cr0; + else if (CPU_ArchitectureType>=CPU_ARCHTYPE_486OLDSLOW) return (cpu.cr0 & 0xe005003f); + else return (cpu.cr0 | 0x7ffffff0); case 2: return paging.cr2; case 3: @@ -1613,7 +1624,11 @@ bool CPU_WRITE_DRX(Bitu dr,Bitu value) { break; case 5: case 7: - cpu.drx[7]=(value|0x400) & 0xffff2fff; + if (CPU_ArchitectureTypeGet_int("cycleup"); CPU_CycleDown=section->Get_int("cycledown"); - std::string core(section->Get_string("core")); + std::string core(section->Get_string("core")); cpudecoder=&CPU_Core_Normal_Run; if (core == "normal") { cpudecoder=&CPU_Core_Normal_Run; @@ -2271,7 +2306,25 @@ public: #elif (C_DYNREC) CPU_Core_Dynrec_Cache_Init( core == "dynamic" ); #endif - + + CPU_ArchitectureType = CPU_ARCHTYPE_MIXED; + std::string cputype(section->Get_string("cputype")); + if (cputype == "auto") { + CPU_ArchitectureType = CPU_ARCHTYPE_MIXED; + } else if (cputype == "386") { + CPU_ArchitectureType = CPU_ARCHTYPE_386FAST; + } else if (cputype == "386_slow") { + CPU_ArchitectureType = CPU_ARCHTYPE_386SLOW; + } else if (cputype == "486_slow") { + CPU_ArchitectureType = CPU_ARCHTYPE_486NEWSLOW; + } else if (cputype == "pentium_slow") { + CPU_ArchitectureType = CPU_ARCHTYPE_PENTIUMSLOW; + } + + if (CPU_ArchitectureType>=CPU_ARCHTYPE_486NEWSLOW) CPU_flag_id_toggle=FLAG_ID; + else CPU_flag_id_toggle=0; + + if(CPU_CycleMax <= 0) CPU_CycleMax = 3000; if(CPU_CycleUp <= 0) CPU_CycleUp = 500; if(CPU_CycleDown <= 0) CPU_CycleDown = 20; diff --git a/src/cpu/paging.cpp b/src/cpu/paging.cpp index fc7bfa85..7bbc97a6 100644 --- a/src/cpu/paging.cpp +++ b/src/cpu/paging.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: paging.cpp,v 1.33 2008-01-05 21:05:06 c2woody Exp $ */ +/* $Id: paging.cpp,v 1.34 2008-05-18 13:11:14 c2woody Exp $ */ #include #include @@ -34,7 +34,6 @@ #define LINK_TOTAL (64*1024) #define USERWRITE_PROHIBITED ((cpu.cpl&cpu.mpl)==3) -#define USERACCESS_PROHIBITED(u1,u2) (((u1)==0) && ((u2)==0)) PagingBlock paging; @@ -228,6 +227,20 @@ static INLINE bool InitPageCheckPresence_CheckOnly(PhysPt lin_addr,bool writing, return true; } +static INLINE bool InitPage_CheckUseraccess(Bitu u1,Bitu u2) { + switch (CPU_ArchitectureType) { + case CPU_ARCHTYPE_MIXED: + case CPU_ARCHTYPE_386SLOW: + case CPU_ARCHTYPE_386FAST: + default: + return ((u1)==0) && ((u2)==0); + case CPU_ARCHTYPE_486OLDSLOW: + case CPU_ARCHTYPE_486NEWSLOW: + case CPU_ARCHTYPE_PENTIUMSLOW: + return ((u1)==0) || ((u2)==0); + } +} + class InitPageHandler : public PageHandler { public: @@ -316,12 +329,40 @@ public: // 2: can (but currently does not) fail a write privilege check // 3: fails a privilege check Bitu priv_check=0; - if (USERACCESS_PROHIBITED(entry.block.us,table.block.us)) { + if (InitPage_CheckUseraccess(entry.block.us,table.block.us)) { if ((cpu.cpl&cpu.mpl)==3) priv_check=3; - else priv_check=1; + else { + switch (CPU_ArchitectureType) { + case CPU_ARCHTYPE_MIXED: + case CPU_ARCHTYPE_386FAST: + default: +// priv_check=0; // default + break; + case CPU_ARCHTYPE_386SLOW: + case CPU_ARCHTYPE_486OLDSLOW: + case CPU_ARCHTYPE_486NEWSLOW: + case CPU_ARCHTYPE_PENTIUMSLOW: + priv_check=1; + break; + } + } } if ((entry.block.wr==0) || (table.block.wr==0)) { - if (priv_check==0) priv_check=2; + if (priv_check==0) { + switch (CPU_ArchitectureType) { + case CPU_ARCHTYPE_MIXED: + case CPU_ARCHTYPE_386FAST: + default: +// priv_check=0; // default + break; + case CPU_ARCHTYPE_386SLOW: + case CPU_ARCHTYPE_486OLDSLOW: + case CPU_ARCHTYPE_486NEWSLOW: + case CPU_ARCHTYPE_PENTIUMSLOW: + priv_check=2; + break; + } + } if (writing && USERWRITE_PROHIBITED) priv_check=3; } if (priv_check==3) { @@ -374,7 +415,7 @@ public: if (!USERWRITE_PROHIBITED) return true; - if (USERACCESS_PROHIBITED(entry.block.us,table.block.us) || + if (InitPage_CheckUseraccess(entry.block.us,table.block.us) || (((entry.block.wr==0) || (table.block.wr==0)) && writing)) { LOG(LOG_PAGING,LOG_NORMAL)("Page access denied: cpl=%i, %x:%x:%x:%x", cpu.cpl,entry.block.us,table.block.us,entry.block.wr,table.block.wr); @@ -507,7 +548,7 @@ public: X86PageEntry entry; if (!InitPageCheckPresence_CheckOnly(lin_addr,true,table,entry)) return 0; - if (USERACCESS_PROHIBITED(entry.block.us,table.block.us) || (((entry.block.wr==0) || (table.block.wr==0)))) { + if (InitPage_CheckUseraccess(entry.block.us,table.block.us) || (((entry.block.wr==0) || (table.block.wr==0)))) { LOG(LOG_PAGING,LOG_NORMAL)("Page access denied: cpl=%i, %x:%x:%x:%x", cpu.cpl,entry.block.us,table.block.us,entry.block.wr,table.block.wr); paging.cr2=lin_addr; diff --git a/src/dosbox.cpp b/src/dosbox.cpp index e3374a08..81975831 100644 --- a/src/dosbox.cpp +++ b/src/dosbox.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dosbox.cpp,v 1.135 2008-05-10 17:33:27 c2woody Exp $ */ +/* $Id: dosbox.cpp,v 1.136 2008-05-18 13:10:42 c2woody Exp $ */ #include #include @@ -393,6 +393,12 @@ void DOSBOX_Init(void) { Pstring->Set_values(cores); Pstring->Set_help("CPU Core used in emulation. auto will switch to dynamic if available and appropriate."); + const char* cputype_values[] = { "auto", "386", "386_slow", "486_slow", "pentium_slow", 0}; + Pstring = secprop->Add_string("cputype",Property::Changeable::Always,"auto"); + Pstring->Set_values(cputype_values); + Pstring->Set_help("CPU Type used in emulation. auto is the fastest choice."); + + Pmulti_remain = secprop->Add_multiremain("cycles",Property::Changeable::Always," "); Pmulti_remain->Set_help( "Amount of instructions DOSBox tries to emulate each millisecond. Setting this value too high results in sound dropouts and lags. Cycles can be set in 3 ways:\n"