1
0
Fork 0

Add string operations for MOVS,STOS,LODS

Change the way temporary registers are handled with loading and saving


Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@1560
This commit is contained in:
Sjoerd van der Berg 2004-01-11 12:24:56 +00:00
parent 449d45643c
commit 2394f38514
4 changed files with 274 additions and 21 deletions

View file

@ -70,7 +70,6 @@ enum DualOps {
DOP_AND,DOP_OR,
DOP_MOV,
DOP_TEST,
DOP_IMUL,
DOP_XCHG,
};
@ -108,8 +107,8 @@ enum BlockReturn {
#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 //Load value only once because of save
#define DYNFLG_LOADONCE 0x20 //Load value only once because of save
#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;
@ -325,7 +324,7 @@ void CPU_Core_Dyn_X86_Init(void) {
DynRegs[G_STACK].data=&extra_regs.stack;
DynRegs[G_STACK].flags=0;
DynRegs[G_CYCLES].data=&CPU_Cycles;
DynRegs[G_CYCLES].flags=DYNFLG_LOAD|DYNFLG_SAVE;;
DynRegs[G_CYCLES].flags=DYNFLG_LOAD|DYNFLG_SAVE;
DynRegs[G_TMPB].data=&extra_regs.tmpb;
DynRegs[G_TMPB].flags=DYNFLG_HAS8|DYNFLG_HAS16;
DynRegs[G_TMPW].data=&extra_regs.tmpd;

View file

@ -1,10 +1,32 @@
/*
* 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.
*/
enum REP_Type {
REP_NONE=0,REP_NZ,REP_Z
};
static struct DynDecode {
PhysPt code;
PhysPt code_start;
PhysPt op_start;
bool big_op;
bool big_addr;
bool rep;
REP_Type rep;
Bitu cycles;
CacheBlock * block;
struct {
@ -16,8 +38,6 @@ static struct DynDecode {
DynReg * segprefix;
} decode;
#include "helpers.h"
static Bit8u INLINE decode_fetchb(void) {
return mem_readb(decode.code++);
}
@ -49,6 +69,7 @@ static void dyn_write_word(DynReg * addr,DynReg * val,bool dword) {
else gen_call_function((void *)&mem_writew,"%Dd%Dw",addr,val);
}
static void dyn_reduce_cycles(void) {
if (!decode.cycles) decode.cycles++;
gen_lea(DREG(CYCLES),DREG(CYCLES),0,0,-(Bits)decode.cycles);
@ -209,6 +230,9 @@ static void dyn_fill_ea(bool addseg=true) {
}
}
#include "helpers.h"
#include "string.h"
static void dyn_dop_ebgb(DualOps op) {
dyn_get_modrm();DynReg * rm_reg=&DynRegs[decode.modrm.reg&3];
if (decode.modrm.mod<3) {
@ -359,6 +383,7 @@ static void dyn_mov_ev_gb(bool sign) {
dyn_read_byte(DREG(EA),DREG(TMPB),false);
gen_releasereg(DREG(EA));
gen_extend_byte(sign,decode.big_op,rm_reg,DREG(TMPB),0);
gen_releasereg(DREG(TMPB));
} else {
gen_extend_byte(sign,decode.big_op,rm_reg,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4);
}
@ -644,7 +669,7 @@ static void dyn_load_seg_off_ea(SegNames seg) {
dyn_fill_ea();
gen_lea(DREG(TMPW),DREG(EA),0,0,decode.big_op ? 4:2);
dyn_read_word(DREG(TMPW),DREG(TMPW),false);
dyn_load_seg(seg,DREG(TMPW),false);
dyn_load_seg(seg,DREG(TMPW),false);gen_releasereg(DREG(TMPW));
dyn_read_word(DREG(EA),&DynRegs[decode.modrm.reg],decode.big_op);
gen_releasereg(DREG(EA));
} else {
@ -900,7 +925,7 @@ static CacheBlock * CreateCacheBlock(PhysPt start,bool big,Bitu max_opcodes) {
decode.block=cache_openblock();
gen_save_host_direct(&cache.block.running,(Bit32u)decode.block);
for (i=0;i<G_MAX;i++) {
DynRegs[i].flags&=~(DYNFLG_LOADONCE|DYNFLG_CHANGED);
DynRegs[i].flags&=~(DYNFLG_ACTIVE|DYNFLG_CHANGED);
DynRegs[i].genreg=0;
}
gen_reinit();
@ -919,7 +944,7 @@ static CacheBlock * CreateCacheBlock(PhysPt start,bool big,Bitu max_opcodes) {
decode.big_addr=big;
decode.big_op=big;
decode.segprefix=0;
decode.rep=false;
decode.rep=REP_NONE;
decode.cycles++;
decode.op_start=decode.code;
restart_prefix:
@ -1170,10 +1195,18 @@ restart_prefix:
dyn_write_word(DREG(EA),DREG(EAX),decode.big_op);
gen_releasereg(DREG(EA));
break;
/* MOVSB/W/D*/
case 0xa4:dyn_string(STR_MOVSB);break;
case 0xa5:dyn_string(decode.big_op ? STR_MOVSD : STR_MOVSW);break;
/* TEST AL,AX Imm */
case 0xa8:gen_dop_byte_imm(DOP_TEST,DREG(EAX),0,decode_fetchb());break;
case 0xa9:gen_dop_word_imm(DOP_TEST,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break;
/* STOSB/W/D*/
case 0xaa:dyn_string(STR_STOSB);break;
case 0xab:dyn_string(decode.big_op ? STR_STOSD : STR_STOSW);break;
/* LODSB/W/D*/
case 0xac:dyn_string(STR_LODSB);break;
case 0xad:dyn_string(decode.big_op ? STR_LODSD : STR_LODSW);break;
//Mov Byte reg,Imm byte
case 0xb0:case 0xb1:case 0xb2:case 0xb3:case 0xb4:case 0xb5:case 0xb6:case 0xb7:
gen_dop_byte_imm(DOP_MOV,&DynRegs[opcode&3],opcode&4,decode_fetchb());
@ -1257,6 +1290,12 @@ restart_prefix:
gen_call_function((void*)&IO_WriteW,"%Dw%Dw",DREG(EDX),DREG(EAX));
}
break;
case 0xf2: //REPNE/NZ
decode.rep=REP_NZ;
goto restart_prefix;
case 0xf3: //REPE/Z
decode.rep=REP_Z;
goto restart_prefix;
/* Change carry flag */
case 0xf5: //CMC
case 0xf8: //CLC

View file

@ -1,4 +1,20 @@
#define GEN_HAS_IMM 1
/*
* 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.
*/
static void gen_init(void);
@ -39,11 +55,11 @@ public:
last_used=x86gen.last_used;
dynreg->flags&=~DYNFLG_CHANGED;
dynreg->genreg=this;
if (dynreg->flags & (DYNFLG_LOAD|DYNFLG_LOADONCE)) {
dynreg->flags&=~DYNFLG_LOADONCE;
if (dynreg->flags & (DYNFLG_LOAD|DYNFLG_ACTIVE)) {
cache_addw(0x058b+(index << (8+3))); //Mov reg,[data]
cache_addd((Bit32u)dynreg->data);
}
dynreg->flags|=DYNFLG_ACTIVE;
}
void Save(void) {
if (!dynreg) IllegalOption();
@ -56,13 +72,12 @@ public:
if (dynreg->flags&DYNFLG_CHANGED && dynreg->flags&DYNFLG_SAVE) {
Save();
}
dynreg->flags&=~(DYNFLG_CHANGED|DYNFLG_LOADONCE);
dynreg->flags&=~(DYNFLG_CHANGED|DYNFLG_ACTIVE);
dynreg->genreg=0;dynreg=0;
}
void Clear(void) {
if (!dynreg) return;
if (dynreg->flags&DYNFLG_CHANGED) {
dynreg->flags|=DYNFLG_LOADONCE;
Save();
}
dynreg->genreg=0;dynreg=0;
@ -176,10 +191,15 @@ static GenReg * ForceDynReg(GenReg * genreg,DynReg * dynreg) {
genreg->Load(dynreg);
return genreg;
}
static void gen_preloadreg(DynReg * dynreg) {
FindDynReg(dynreg);
}
static void gen_releasereg(DynReg * dynreg) {
GenReg * genreg=dynreg->genreg;
if (genreg) genreg->Release();
else dynreg->flags&=~(DYNFLG_LOADONCE|DYNFLG_CHANGED);
else dynreg->flags&=~(DYNFLG_ACTIVE|DYNFLG_CHANGED);
}
static void gen_setupreg(DynReg * dnew,DynReg * dsetup) {
@ -203,12 +223,12 @@ static void gen_synchreg(DynReg * dnew,DynReg * dsynch) {
}
}
/* Always use the loadonce flag from either state */
dnew->flags|=(dsynch->flags & dnew->flags&DYNFLG_LOADONCE);
dnew->flags|=(dsynch->flags & dnew->flags&DYNFLG_ACTIVE);
if ((dnew->flags ^ dsynch->flags) & DYNFLG_CHANGED) {
/* Ensure the changed value gets saved */
if (dnew->flags & DYNFLG_CHANGED) {
dnew->genreg->Save();
}
} else dnew->flags|=DYNFLG_CHANGED;
}
}
@ -498,6 +518,24 @@ static void gen_shift_word(ShiftOps op,DynReg * drecx,bool dword,DynReg * dr1) {
dr1->flags|=DYNFLG_CHANGED;
}
static void gen_shift_word_imm(ShiftOps op,bool dword,DynReg * dr1,Bit8u imm) {
GenReg * gr1=FindDynReg(dr1);
if (!dword) cache_addb(0x66);
switch (op) {
case SHIFT_ROL:cache_addw(0xc0c1+((gr1->index)<<8));break;
case SHIFT_ROR:cache_addw(0xc8c1+((gr1->index)<<8));break;
case SHIFT_RCL:cache_addw(0xd0c1+((gr1->index)<<8));break;
case SHIFT_RCR:cache_addw(0xd8c1+((gr1->index)<<8));break;
case SHIFT_SHL:cache_addw(0xe0c1+((gr1->index)<<8));break;
case SHIFT_SHR:cache_addw(0xe8c1+((gr1->index)<<8));break;
case SHIFT_SAR:cache_addw(0xf8c1+((gr1->index)<<8));break;
default:
IllegalOption();
}
cache_addb(imm);
dr1->flags|=DYNFLG_CHANGED;
}
static void gen_cbw(bool dword,DynReg * dyn_ax) {
ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax);
if (!dword) cache_addb(0x66);
@ -678,10 +716,22 @@ static Bit8u * gen_create_branch(BranchTypes type) {
return (cache.pos-1);
}
static void gen_fill_branch(Bit8u * data) {
*data=(cache.pos-data-1);
static void gen_fill_branch(Bit8u * data,Bit8u * from=cache.pos) {
*data=(from-data-1);
}
static Bit8u * gen_create_jump(Bit8u * to=0) {
/* First free all registers */
cache_addb(0xe9);
cache_addd(to-(cache.pos+4));
return (cache.pos-4);
}
static void gen_fill_jump(Bit8u * data,Bit8u * to=cache.pos) {
*(Bit32u*)data=(to-data-4);
}
static void gen_jmp_ptr(void * ptr,Bits imm=0) {
cache_addb(0xa1);
cache_addd((Bit32u)ptr);

View file

@ -0,0 +1,165 @@
/*
* 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.
*/
enum STRING_OP {
STR_OUTSB=0,STR_OUTSW,STR_OUTSD,
STR_INSB=4,STR_INSW,STR_INSD,
STR_MOVSB=8,STR_MOVSW,STR_MOVSD,
STR_LODSB=12,STR_LODSW,STR_LODSD,
STR_STOSB=16,STR_STOSW,STR_STOSD,
STR_SCASB=20,STR_SCASW,STR_SCASD,
STR_CMPSB=24,STR_CMPSW,STR_CMPSD,
};
static void dyn_string(STRING_OP op) {
DynReg * si_base=decode.segprefix ? decode.segprefix : DREG(DS);
DynReg * di_base=DREG(ES);
DynReg * tmp_reg;bool usesi;bool usedi;
gen_storeflags();
if (decode.rep) {
gen_dop_word_imm(DOP_SUB,true,DREG(CYCLES),decode.cycles);
gen_releasereg(DREG(CYCLES));
decode.cycles=0;
}
/* Check what each string operation will be using */
switch (op) {
case STR_MOVSB: case STR_MOVSW: case STR_MOVSD:
case STR_CMPSB: case STR_CMPSW: case STR_CMPSD:
tmp_reg=DREG(TMPB);usesi=true;usedi=true;break;
case STR_LODSB: case STR_LODSW: case STR_LODSD:
tmp_reg=DREG(EAX);usesi=true;usedi=false;break;
case STR_OUTSB: case STR_OUTSW: case STR_OUTSD:
tmp_reg=DREG(TMPB);usesi=true;usedi=false;break;
case STR_SCASB: case STR_SCASW: case STR_SCASD:
case STR_STOSB: case STR_STOSW: case STR_STOSD:
tmp_reg=DREG(EAX);usesi=false;usedi=true;break;
case STR_INSB: case STR_INSW: case STR_INSD:
tmp_reg=DREG(TMPB);usesi=false;usedi=true;break;
default:
IllegalOption();
}
gen_load_host(&cpu.direction,DREG(TMPW),4);
switch (op & 3) {
case 0:break;
case 1:gen_shift_word_imm(SHIFT_SHL,true,DREG(TMPW),1);break;
case 2:gen_shift_word_imm(SHIFT_SHL,true,DREG(TMPW),2);break;
default:
IllegalOption();
}
if (usesi) {
gen_preloadreg(DREG(ESI));
DynRegs[G_ESI].flags|=DYNFLG_CHANGED;
gen_preloadreg(si_base);
}
if (usedi) {
gen_preloadreg(DREG(EDI));
DynRegs[G_EDI].flags|=DYNFLG_CHANGED;
gen_preloadreg(di_base);
}
if (decode.rep) {
gen_preloadreg(DREG(ECX));
DynRegs[G_ECX].flags|=DYNFLG_CHANGED;
}
DynState rep_state;
dyn_savestate(&rep_state);
Bit8u * rep_start=cache.pos;
Bit8u * rep_ecx_jmp;
/* Check if ECX!=zero and decrease it */
if (decode.rep) {
gen_dop_word(DOP_OR,decode.big_addr,DREG(ECX),DREG(ECX));
Bit8u * branch_ecx=gen_create_branch(BR_NZ);
rep_ecx_jmp=gen_create_jump();
gen_fill_branch(branch_ecx);
gen_sop_word(SOP_DEC,decode.big_addr,DREG(ECX));
}
if (usesi) {
if (!decode.big_addr) {
gen_extend_word(false,DREG(EA),DREG(ESI));
gen_lea(DREG(EA),si_base,DREG(EA),0,0);
} else {
gen_lea(DREG(EA),si_base,DREG(ESI),0,0);
}
gen_dop_word(DOP_ADD,decode.big_addr,DREG(ESI),DREG(TMPW));
switch (op&3) {
case 0:dyn_read_byte(DREG(EA),tmp_reg,false);break;
case 1:dyn_read_word(DREG(EA),tmp_reg,false);break;
case 2:dyn_read_word(DREG(EA),tmp_reg,true);break;
}
switch (op) {
case STR_OUTSB:
gen_call_function((void*)&IO_WriteB,"%Id%Dl",DREG(EDX),tmp_reg);break;
case STR_OUTSW:
gen_call_function((void*)&IO_WriteW,"%Id%Dw",DREG(EDX),tmp_reg);break;
case STR_OUTSD:
gen_call_function((void*)&IO_WriteD,"%Id%Dd",DREG(EDX),tmp_reg);break;
}
}
if (usedi) {
if (!decode.big_addr) {
gen_extend_word(false,DREG(EA),DREG(EDI));
gen_lea(DREG(EA),di_base,DREG(EA),0,0);
} else {
gen_lea(DREG(EA),di_base,DREG(EDI),0,0);
}
gen_dop_word(DOP_ADD,decode.big_addr,DREG(EDI),DREG(TMPW));
/* Maybe something special to be done to fill the value */
switch (op) {
case STR_INSB:
gen_call_function((void*)&IO_ReadB,"%Dw%Rl",DREG(EDX),tmp_reg);
case STR_MOVSB:
case STR_STOSB:
dyn_write_byte(DREG(EA),tmp_reg,false);
break;
case STR_INSW:
gen_call_function((void*)&IO_ReadW,"%Dw%Rw",DREG(EDX),tmp_reg);
case STR_MOVSW:
case STR_STOSW:
dyn_write_word(DREG(EA),tmp_reg,false);
break;
case STR_INSD:
gen_call_function((void*)&IO_ReadD,"%Dw%Rd",DREG(EDX),tmp_reg);
case STR_MOVSD:
case STR_STOSD:
dyn_write_word(DREG(EA),tmp_reg,true);
break;
default:
IllegalOption();
}
}
gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPB));
if (decode.rep) {
DynState cycle_state;
gen_sop_word(SOP_DEC,true,DREG(CYCLES));
gen_releasereg(DREG(CYCLES));
dyn_savestate(&cycle_state);
Bit8u * cycle_branch=gen_create_branch(BR_NLE);
gen_lea(DREG(EIP),DREG(EIP),0,0,decode.op_start-decode.code_start);
dyn_releaseregs();
gen_restoreflags(true);
gen_return(BR_Cycles);
gen_fill_branch(cycle_branch);
dyn_loadstate(&cycle_state);
dyn_synchstate(&rep_state);
/* Jump back to start of ECX check */
gen_create_jump(rep_start);
gen_fill_jump(rep_ecx_jmp);
}
gen_releasereg(DREG(TMPW));
gen_restoreflags();
}