1
0
Fork 0

precalculate inverted stack mask; improve dynamic core stack functions

Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@2606
This commit is contained in:
Sebastian Strohhäcker 2006-04-18 17:44:25 +00:00
parent ec58b58543
commit 2ae27a0bb9
5 changed files with 87 additions and 131 deletions

View file

@ -418,7 +418,7 @@ struct CPUBlock {
GDTDescriptorTable gdt;
DescriptorTable idt;
struct {
Bitu mask;
Bitu mask,notmask;
bool big;
} stack;
struct {

View file

@ -20,8 +20,6 @@
#if (C_DYNAMIC_X86)
#define CHECKED_MEMORY_ACCESS
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
@ -46,11 +44,7 @@
#include "paging.h"
#include "inout.h"
#ifdef CHECKED_MEMORY_ACCESS
#define CACHE_MAXSIZE (4096*2)
#else
#define CACHE_MAXSIZE (4096)
#endif
#define CACHE_PAGES (128*8)
#define CACHE_TOTAL (CACHE_PAGES*4096)
#define CACHE_BLOCKS (64*1024)
@ -73,7 +67,7 @@ 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_FLAGS,G_NEWESP,G_EIP,
G_EA,G_STACK,G_CYCLES,
G_TMPB,G_TMPW,G_SHIFT,
G_EXIT,
@ -155,7 +149,7 @@ static DynReg DynRegs[G_MAX];
#define DREG(_WHICH_) &DynRegs[G_ ## _WHICH_ ]
static struct {
Bitu ea,tmpb,tmpd,stack,shift;
Bitu ea,tmpb,tmpd,stack,shift,newesp;
} extra_regs;
static void IllegalOption(const char* msg) {
@ -326,8 +320,8 @@ void CPU_Core_Dyn_X86_Init(void) {
DynRegs[G_FLAGS].data=&reg_flags;
DynRegs[G_FLAGS].flags=DYNFLG_LOAD|DYNFLG_SAVE;
DynRegs[G_SMASK].data=&cpu.stack.mask;
DynRegs[G_SMASK].flags=DYNFLG_LOAD|DYNFLG_SAVE;
DynRegs[G_NEWESP].data=&extra_regs.newesp;
DynRegs[G_NEWESP].flags=0;
DynRegs[G_EIP].data=&reg_eip;
DynRegs[G_EIP].flags=DYNFLG_LOAD|DYNFLG_SAVE;

View file

@ -220,7 +220,6 @@ static void dyn_fill_blocks(void) {
used_save_info=0;
}
#ifdef CHECKED_MEMORY_ACCESS
static void dyn_read_byte(DynReg * addr,DynReg * dst,Bitu high) {
gen_protectflags();
gen_call_function((void *)&mem_readb_checked_x86,"%Dd%Id",addr,&core_dyn.readdata);
@ -271,50 +270,13 @@ static void dyn_write_word_release(DynReg * addr,DynReg * val,bool dword) {
else gen_call_function((void *)&mem_writew_checked_x86,"%Ddr%Dd",addr,val);
dyn_check_bool_exception_al();
}
#else
static void dyn_read_byte(DynReg * addr,DynReg * dst,Bitu high) {
if (high) gen_call_function((void *)&mem_readb,"%Dd%Rh",addr,dst);
else gen_call_function((void *)&mem_readb,"%Dd%Rl",addr,dst);
}
static void dyn_write_byte(DynReg * addr,DynReg * val,Bitu high) {
if (high) gen_call_function((void *)&mem_writeb,"%Dd%Dh",addr,val);
else gen_call_function((void *)&mem_writeb,"%Dd%Dd",addr,val);
}
static void dyn_read_word(DynReg * addr,DynReg * dst,bool dword) {
if (dword) gen_call_function((void *)&mem_readd_dyncorex86,"%Dd%Rd",addr,dst);
else gen_call_function((void *)&mem_readw_dyncorex86,"%Dd%Rw",addr,dst);
}
static void dyn_write_word(DynReg * addr,DynReg * val,bool dword) {
if (dword) gen_call_function((void *)&mem_writed_dyncorex86,"%Dd%Dd",addr,val);
else gen_call_function((void *)&mem_writew_dyncorex86,"%Dd%Dd",addr,val);
}
static void dyn_read_byte_release(DynReg * addr,DynReg * dst,Bitu high) {
if (high) gen_call_function((void *)&mem_readb,"%Ddr%Rh",addr,dst);
else gen_call_function((void *)&mem_readb,"%Ddr%Rl",addr,dst);
}
static void dyn_write_byte_release(DynReg * addr,DynReg * val,Bitu high) {
if (high) gen_call_function((void *)&mem_writeb,"%Ddr%Dh",addr,val);
else gen_call_function((void *)&mem_writeb,"%Ddr%Dd",addr,val);
}
static void dyn_read_word_release(DynReg * addr,DynReg * dst,bool dword) {
if (dword) gen_call_function((void *)&mem_readd_dyncorex86,"%Ddr%Rd",addr,dst);
else gen_call_function((void *)&mem_readw_dyncorex86,"%Ddr%Rw",addr,dst);
}
static void dyn_write_word_release(DynReg * addr,DynReg * val,bool dword) {
if (dword) gen_call_function((void *)&mem_writed_dyncorex86,"%Ddr%Dd",addr,val);
else gen_call_function((void *)&mem_writew_dyncorex86,"%Ddr%Dd",addr,val);
}
#endif
static void dyn_push_unchecked(DynReg * dynreg) {
gen_protectflags();
if (decode.big_op) {
gen_dop_word_imm(DOP_SUB,true,DREG(ESP),4);
} else {
gen_dop_word_imm(DOP_SUB,true,DREG(ESP),2);
}
gen_dop_word(DOP_AND,true,DREG(ESP),DREG(SMASK));
gen_dop_word(DOP_MOV,true,DREG(STACK),DREG(ESP));
gen_lea(DREG(STACK),DREG(ESP),0,0,decode.big_op?(-4):(-2));
gen_dop_word_var(DOP_AND,true,DREG(STACK),&cpu.stack.mask);
gen_dop_word_var(DOP_AND,true,DREG(ESP),&cpu.stack.notmask);
gen_dop_word(DOP_OR,true,DREG(ESP),DREG(STACK));
gen_dop_word(DOP_ADD,true,DREG(STACK),DREG(SS));
if (decode.big_op) {
gen_call_function((void *)&mem_writed,"%Drd%Dd",DREG(STACK),dynreg);
@ -326,13 +288,11 @@ static void dyn_push_unchecked(DynReg * dynreg) {
static void dyn_push(DynReg * dynreg) {
gen_protectflags();
gen_dop_word(DOP_MOV,true,DREG(STACK),DREG(ESP));
if (decode.big_op) {
gen_dop_word_imm(DOP_SUB,true,DREG(STACK),4);
} else {
gen_dop_word_imm(DOP_SUB,true,DREG(STACK),2);
}
gen_dop_word(DOP_AND,true,DREG(STACK),DREG(SMASK));
gen_lea(DREG(STACK),DREG(ESP),0,0,decode.big_op?(-4):(-2));
gen_dop_word(DOP_MOV,true,DREG(NEWESP),DREG(ESP));
gen_dop_word_var(DOP_AND,true,DREG(STACK),&cpu.stack.mask);
gen_dop_word_var(DOP_AND,true,DREG(NEWESP),&cpu.stack.notmask);
gen_dop_word(DOP_OR,true,DREG(NEWESP),DREG(STACK));
gen_dop_word(DOP_ADD,true,DREG(STACK),DREG(SS));
if (decode.big_op) {
gen_call_function((void *)&mem_writed_checked_x86,"%Drd%Dd",DREG(STACK),dynreg);
@ -341,54 +301,36 @@ static void dyn_push(DynReg * dynreg) {
gen_call_function((void *)&mem_writew_checked_x86,"%Drd%Dd",DREG(STACK),dynreg);
}
dyn_check_bool_exception_al();
/* everything was ok, change registers now */
if (decode.big_op) {
gen_dop_word_imm(DOP_SUB,true,DREG(ESP),4);
} else {
gen_dop_word_imm(DOP_SUB,true,DREG(ESP),2);
}
gen_dop_word(DOP_AND,true,DREG(ESP),DREG(SMASK));
/* everything was ok, change register now */
gen_dop_word(DOP_MOV,true,DREG(ESP),DREG(NEWESP));
gen_releasereg(DREG(NEWESP));
}
static void dyn_pop_unchecked(DynReg * dynreg) {
static void dyn_pop(DynReg * dynreg,bool checked=true) {
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_var(DOP_AND,true,DREG(STACK),&cpu.stack.mask);
gen_dop_word(DOP_ADD,true,DREG(STACK),DREG(SS));
if (decode.big_op) {
gen_call_function((void *)&mem_readd,"%Rd%Drd",dynreg,DREG(STACK));
if (checked) {
if (decode.big_op) {
gen_call_function((void *)&mem_readd_checked_x86,"%Drd%Id",DREG(STACK),&core_dyn.readdata);
} else {
gen_call_function((void *)&mem_readw_checked_x86,"%Drd%Id",DREG(STACK),&core_dyn.readdata);
}
dyn_check_bool_exception_al();
gen_mov_host(&core_dyn.readdata,dynreg,decode.big_op?4:2);
} else {
gen_call_function((void *)&mem_readw,"%Rw%Drd",dynreg,DREG(STACK));
if (decode.big_op) {
gen_call_function((void *)&mem_readd,"%Rd%Drd",dynreg,DREG(STACK));
} else {
gen_call_function((void *)&mem_readw,"%Rw%Drd",dynreg,DREG(STACK));
}
}
if (dynreg!=DREG(ESP)) {
if (decode.big_op) {
gen_dop_word_imm(DOP_ADD,true,DREG(ESP),4);
} else {
gen_dop_word_imm(DOP_ADD,true,DREG(ESP),2);
}
gen_dop_word(DOP_AND,true,DREG(ESP),DREG(SMASK));
}
}
static void dyn_pop(DynReg * dynreg) {
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));
if (decode.big_op) {
gen_call_function((void *)&mem_readd_checked_x86,"%Drd%Id",DREG(STACK),&core_dyn.readdata);
} else {
gen_call_function((void *)&mem_readw_checked_x86,"%Drd%Id",DREG(STACK),&core_dyn.readdata);
}
dyn_check_bool_exception_al();
gen_mov_host(&core_dyn.readdata,dynreg,decode.big_op?4:2);
if (dynreg!=DREG(ESP)) {
if (decode.big_op) {
gen_dop_word_imm(DOP_ADD,true,DREG(ESP),4);
} else {
gen_dop_word_imm(DOP_ADD,true,DREG(ESP),2);
}
gen_dop_word(DOP_AND,true,DREG(ESP),DREG(SMASK));
gen_lea(DREG(STACK),DREG(ESP),0,0,decode.big_op?4:2);
gen_dop_word_var(DOP_AND,true,DREG(STACK),&cpu.stack.mask);
gen_dop_word_var(DOP_AND,true,DREG(ESP),&cpu.stack.notmask);
gen_dop_word(DOP_OR,true,DREG(ESP),DREG(STACK));
}
}
@ -575,9 +517,7 @@ static void dyn_mov_ebib(void) {
if (decode.modrm.mod<3) {
dyn_fill_ea();
gen_call_write(DREG(EA),decode_fetchb(),1);
#ifdef CHECKED_MEMORY_ACCESS
dyn_check_bool_exception_al();
#endif
} else {
gen_dop_byte_imm(DOP_MOV,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4,decode_fetchb());
}
@ -696,9 +636,7 @@ static void dyn_mov_eviv(void) {
if (decode.modrm.mod<3) {
dyn_fill_ea();
gen_call_write(DREG(EA),decode.big_op ? decode_fetchd() : decode_fetchw(),decode.big_op?4:2);
#ifdef CHECKED_MEMORY_ACCESS
dyn_check_bool_exception_al();
#endif
} else {
gen_dop_word_imm(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],decode.big_op ? decode_fetchd() : decode_fetchw());
}
@ -985,7 +923,6 @@ static void dyn_load_seg(SegNames seg,DynReg * src) {
gen_releasereg(DREG(TMPB));
} else gen_call_function((void *)CPU_SetSegGeneral,"%Id%Drw",seg,src);
gen_releasereg(&DynRegs[G_ES+seg]);
if (seg==ss) gen_releasereg(DREG(SMASK));
}
static void dyn_load_seg_off_ea(SegNames seg) {
@ -1034,7 +971,6 @@ static void dyn_pop_seg(SegNames seg) {
gen_releasereg(DREG(TMPB));
gen_releasereg(&DynRegs[G_ES+seg]);
gen_releasereg(DREG(ESP));
if (seg==ss) gen_releasereg(DREG(SMASK));
}
}
@ -1062,13 +998,13 @@ static void dyn_enter(void) {
static void dyn_leave(void) {
gen_protectflags();
gen_dop_word(DOP_MOV,true,DREG(TMPW),DREG(SMASK));
gen_dop_word_var(DOP_MOV,true,DREG(TMPW),&cpu.stack.mask);
gen_sop_word(SOP_NOT,true,DREG(TMPW));
gen_dop_word(DOP_AND,true,DREG(ESP),DREG(TMPW));
gen_dop_word(DOP_MOV,true,DREG(TMPW),DREG(EBP));
gen_dop_word(DOP_AND,true,DREG(TMPW),DREG(SMASK));
gen_dop_word_var(DOP_AND,true,DREG(TMPW),&cpu.stack.mask);
gen_dop_word(DOP_OR,true,DREG(ESP),DREG(TMPW));
dyn_pop_unchecked(DREG(EBP));
dyn_pop(DREG(EBP),false);
gen_releasereg(DREG(TMPW));
}
@ -1444,7 +1380,7 @@ restart_prefix:
break;
case 0x61: /* POPA */
for (i=G_EDI;i>=G_EAX;i--) {
dyn_pop_unchecked((i!=G_ESP) ? &DynRegs[i] : DREG(TMPW));
dyn_pop((i!=G_ESP) ? &DynRegs[i] : DREG(TMPW),false);
}
gen_releasereg(DREG(TMPW));
break;
@ -1453,7 +1389,7 @@ restart_prefix:
case 0x65:dyn_segprefix(gs);goto restart_prefix;
//Push immediates
//Operand size
case 0x66:decode.big_op=!cpu.code.big;;goto restart_prefix;
case 0x66:decode.big_op=!cpu.code.big;goto restart_prefix;
//Address size
case 0x67:decode.big_addr=!cpu.code.big;goto restart_prefix;
case 0x68: /* PUSH Iv */

View file

@ -457,6 +457,29 @@ finish:
else cache_addw(imm);
}
static void gen_dop_word_var(DualOps op,bool dword,DynReg * dr1,void* drd) {
GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV);
Bit8u tmp;
switch (op) {
case DOP_ADD: tmp=0x03; break;
case DOP_ADC: tmp=0x13; break;
case DOP_SUB: tmp=0x2b; break;
case DOP_SBB: tmp=0x1b; break;
case DOP_CMP: tmp=0x3b; break;
case DOP_XOR: tmp=0x33; break;
case DOP_AND: tmp=0x23; break;
case DOP_OR: tmp=0x0b; break;
case DOP_TEST: tmp=0x85; break;
case DOP_MOV: tmp=0x8b; break;
case DOP_XCHG: tmp=0x87; break;
default:
IllegalOption("gen_dop_word_var");
}
if (!dword) cache_addb(0x66);
cache_addw(tmp|(0x05+((gr1->index)<<3))<<8);
cache_addd((Bit32u)drd);
}
static void gen_imul_word(bool dword,DynReg * dr1,DynReg * dr2) {
GenReg * gr1=FindDynReg(dr1);GenReg * gr2=FindDynReg(dr2);
dr1->flags|=DYNFLG_CHANGED;
@ -728,21 +751,12 @@ static void gen_call_write(DynReg * dr,Bit32u val,Bitu write_size) {
x86gen.regs[X86_REG_EDX]->Clear();
/* Do the actual call to the procedure */
cache_addb(0xe8);
#ifdef CHECKED_MEMORY_ACCESS
switch (write_size) {
case 1: cache_addd((Bit32u)mem_writeb_checked_x86 - (Bit32u)cache.pos-4); break;
case 2: cache_addd((Bit32u)mem_writew_checked_x86 - (Bit32u)cache.pos-4); break;
case 4: cache_addd((Bit32u)mem_writed_checked_x86 - (Bit32u)cache.pos-4); break;
default: IllegalOption("gen_call_write");
}
#else
switch (write_size) {
case 1: cache_addd((Bit32u)mem_writeb - (Bit32u)cache.pos-4); break;
case 2: cache_addd((Bit32u)mem_writew_dyncorex86 - (Bit32u)cache.pos-4); break;
case 4: cache_addd((Bit32u)mem_writed_dyncorex86 - (Bit32u)cache.pos-4); break;
default: IllegalOption("gen_call_write");
}
#endif
cache_addw(0xc483); //ADD ESP,8
cache_addb(2*4);

View file

@ -16,7 +16,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* $Id: cpu.cpp,v 1.79 2006-02-26 16:11:00 qbix79 Exp $ */
/* $Id: cpu.cpp,v 1.80 2006-04-18 17:44:25 c2woody Exp $ */
#include <assert.h>
#include "dosbox.h"
@ -90,26 +90,26 @@ void CPU_Core_Dyn_X86_Cache_Init(bool enable_cache);
void CPU_Push16(Bitu value) {
Bit32u new_esp=(reg_esp&~cpu.stack.mask)|((reg_esp-2)&cpu.stack.mask);
Bit32u new_esp=(reg_esp&cpu.stack.notmask)|((reg_esp-2)&cpu.stack.mask);
mem_writew(SegPhys(ss) + (new_esp & cpu.stack.mask) ,value);
reg_esp=new_esp;
}
void CPU_Push32(Bitu value) {
Bit32u new_esp=(reg_esp&~cpu.stack.mask)|((reg_esp-4)&cpu.stack.mask);
Bit32u new_esp=(reg_esp&cpu.stack.notmask)|((reg_esp-4)&cpu.stack.mask);
mem_writed(SegPhys(ss) + (new_esp & cpu.stack.mask) ,value);
reg_esp=new_esp;
}
Bitu CPU_Pop16(void) {
Bitu val=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask));
reg_esp=(reg_esp&~cpu.stack.mask)|((reg_esp+2)&cpu.stack.mask);
reg_esp=(reg_esp&cpu.stack.notmask)|((reg_esp+2)&cpu.stack.mask);
return val;
}
Bitu CPU_Pop32(void) {
Bitu val=mem_readd(SegPhys(ss) + (reg_esp & cpu.stack.mask));
reg_esp=(reg_esp&~cpu.stack.mask)|((reg_esp+4)&cpu.stack.mask);
reg_esp=(reg_esp&cpu.stack.notmask)|((reg_esp+4)&cpu.stack.mask);
return val;
}
@ -409,11 +409,11 @@ doconforming:
bool CPU_IO_Exception(Bitu port,Bitu size) {
if (cpu.pmode && ((GETFLAG_IOPL<cpu.cpl) || GETFLAG(VM))) {
if (!cpu_tss.is386) goto doexception;
PhysPt where=cpu_tss.base+0x66;
Bitu ofs=mem_readw(where);
PhysPt bwhere=cpu_tss.base+0x66;
Bitu ofs=mem_readw(bwhere);
if (ofs>cpu_tss.limit) goto doexception;
where=cpu_tss.base+ofs+(port/8);
Bitu map=mem_readw(where);
bwhere=cpu_tss.base+ofs+(port/8);
Bitu map=mem_readw(bwhere);
Bitu mask=(0xffff>>(16-size)) << (port&7);
if (map & mask) goto doexception;
}
@ -552,10 +552,12 @@ void CPU_Interrupt(Bitu num,Bitu type,Bitu oldeip) {
if (n_ss_desc.Big()) {
cpu.stack.big=true;
cpu.stack.mask=0xffffffff;
cpu.stack.notmask=0;
reg_esp=n_esp;
} else {
cpu.stack.big=false;
cpu.stack.mask=0xffff;
cpu.stack.notmask=0xffff0000;
reg_sp=n_esp & 0xffff;
}
@ -814,10 +816,12 @@ void CPU_IRET(bool use32,Bitu oldeip) {
if (n_ss_desc.Big()) {
cpu.stack.big=true;
cpu.stack.mask=0xffffffff;
cpu.stack.notmask=0;
reg_esp=n_esp;
} else {
cpu.stack.big=false;
cpu.stack.mask=0xffff;
cpu.stack.notmask=0xffff0000;
reg_sp=n_esp & 0xffff;
}
@ -1070,10 +1074,12 @@ call_code:
if (n_ss_desc.Big()) {
cpu.stack.big=true;
cpu.stack.mask=0xffffffff;
cpu.stack.notmask=0;
reg_esp=n_esp;
} else {
cpu.stack.big=false;
cpu.stack.mask=0xffff;
cpu.stack.notmask=0xffff0000;
reg_sp=n_esp & 0xffff;
}
@ -1303,10 +1309,12 @@ RET_same_level:
if (n_ss_desc.Big()) {
cpu.stack.big=true;
cpu.stack.mask=0xffffffff;
cpu.stack.notmask=0;
reg_esp=n_esp+bytes;
} else {
cpu.stack.big=false;
cpu.stack.mask=0xffff;
cpu.stack.notmask=0xffff0000;
reg_sp=(n_esp & 0xffff)+bytes;
}
@ -1712,6 +1720,7 @@ bool CPU_SetSegGeneral(SegNames seg,Bitu value) {
if (seg==ss) {
cpu.stack.big=false;
cpu.stack.mask=0xffff;
cpu.stack.notmask=0xffff0000;
}
return false;
} else {
@ -1750,9 +1759,11 @@ bool CPU_SetSegGeneral(SegNames seg,Bitu value) {
if (desc.Big()) {
cpu.stack.big=true;
cpu.stack.mask=0xffffffff;
cpu.stack.notmask=0;
} else {
cpu.stack.big=false;
cpu.stack.mask=0xffff;
cpu.stack.notmask=0xffff0000;
}
} else {
if ((value & 0xfffc)==0) {
@ -1799,7 +1810,7 @@ bool CPU_PopSeg(SegNames seg,bool use32) {
Bitu val=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask));
if (CPU_SetSegGeneral(seg,val)) return true;
Bitu addsp=use32?0x04:0x02;
reg_esp=(reg_esp&~cpu.stack.mask)|((reg_esp+addsp)&cpu.stack.mask);
reg_esp=(reg_esp&cpu.stack.notmask)|((reg_esp+addsp)&cpu.stack.mask);
return false;
}
@ -1872,7 +1883,7 @@ void CPU_ENTER(bool use32,Bitu bytes,Bitu level) {
}
}
sp_index-=bytes;
reg_esp=(reg_esp&~cpu.stack.mask)|((sp_index)&cpu.stack.mask);
reg_esp=(reg_esp&cpu.stack.notmask)|((sp_index)&cpu.stack.mask);
}
extern void GFX_SetTitle(Bits cycles ,Bits frameskip,bool paused);
@ -1938,6 +1949,7 @@ public:
CPU_SET_CRX(0,0); //Initialize
cpu.code.big=false;
cpu.stack.mask=0xffff;
cpu.stack.notmask=0xffff0000;
cpu.stack.big=false;
cpu.idt.SetBase(0);
cpu.idt.SetLimit(1023);