/* * 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; REP_Type rep; Bitu cycles; CacheBlock * block; struct { Bitu val; Bitu mod; Bitu rm; Bitu reg; } modrm; DynReg * segprefix; } decode; static Bit8u INLINE decode_fetchb(void) { return mem_readb(decode.code++); } static Bit16u INLINE decode_fetchw(void) { decode.code+=2; return mem_readw(decode.code-2); } static Bit32u INLINE decode_fetchd(void) { decode.code+=4; return mem_readd(decode.code-4); } 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%Dl",addr,val); } static void dyn_read_word(DynReg * addr,DynReg * dst,bool dword) { if (dword) gen_call_function((void *)&mem_readd,"%Dd%Rd",addr,dst); else gen_call_function((void *)&mem_readw,"%Dd%Rw",addr,dst); } static void dyn_write_word(DynReg * addr,DynReg * val,bool dword) { if (dword) gen_call_function((void *)&mem_writed,"%Dd%Dd",addr,val); 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); gen_releasereg(DREG(CYCLES)); } static void dyn_push(DynReg * dynreg) { gen_storeflags(); 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_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_writed,"%Drd%Dd",DREG(STACK),dynreg); } else { //Can just push the whole 32-bit word as operand gen_call_function((void *)&mem_writew,"%Drd%Dd",DREG(STACK),dynreg); } gen_releasereg(DREG(STACK)); gen_restoreflags(); } static void dyn_pop(DynReg * dynreg) { gen_storeflags(); 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,"%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_releasereg(DREG(STACK)); gen_restoreflags(); } static void INLINE dyn_get_modrm(void) { decode.modrm.val=decode_fetchb(); decode.modrm.mod=(decode.modrm.val >> 6) & 3; decode.modrm.reg=(decode.modrm.val >> 3) & 7; decode.modrm.rm=(decode.modrm.val & 7); } static void dyn_fill_ea(bool addseg=true) { DynReg * segbase; if (!decode.big_addr) { Bits imm; switch (decode.modrm.mod) { case 0:imm=0;break; case 1:imm=(Bit8s)decode_fetchb();break; case 2:imm=(Bit16s)decode_fetchw();break; } switch (decode.modrm.rm) { case 0:/* BX+SI */ gen_lea(DREG(EA),DREG(EBX),DREG(ESI),0,imm); segbase=DREG(DS); break; case 1:/* BX+DI */ gen_lea(DREG(EA),DREG(EBX),DREG(EDI),0,imm); segbase=DREG(DS); break; case 2:/* BP+SI */ gen_lea(DREG(EA),DREG(EBP),DREG(ESI),0,imm); segbase=DREG(SS); break; case 3:/* BP+DI */ gen_lea(DREG(EA),DREG(EBP),DREG(EDI),0,imm); segbase=DREG(SS); break; case 4:/* SI */ gen_lea(DREG(EA),DREG(ESI),0,0,imm); segbase=DREG(DS); break; case 5:/* DI */ gen_lea(DREG(EA),DREG(EDI),0,0,imm); segbase=DREG(DS); break; case 6:/* imm/BP */ if (!decode.modrm.mod) { imm=(Bit16s)decode_fetchw(); gen_dop_word_imm(DOP_MOV,true,DREG(EA),imm); segbase=DREG(DS); } else { gen_lea(DREG(EA),DREG(EBP),0,0,imm); segbase=DREG(SS); } break; case 7: /* BX */ gen_lea(DREG(EA),DREG(EBX),0,0,imm); segbase=DREG(DS); break; } gen_extend_word(false,DREG(EA),DREG(EA)); } else { Bits imm=0; DynReg * base=0;DynReg * scaled=0;Bitu scale=0; switch (decode.modrm.rm) { case 0:base=DREG(EAX);segbase=DREG(DS);break; case 1:base=DREG(ECX);segbase=DREG(DS);break; case 2:base=DREG(EDX);segbase=DREG(DS);break; case 3:base=DREG(EBX);segbase=DREG(DS);break; case 4: /* SIB */ { Bitu sib=decode_fetchb(); switch (sib & 7) { case 0:base=DREG(EAX);segbase=DREG(DS);break; case 1:base=DREG(ECX);segbase=DREG(DS);break; case 2:base=DREG(EDX);segbase=DREG(DS);break; case 3:base=DREG(EBX);segbase=DREG(DS);break; case 4:base=DREG(ESP);segbase=DREG(SS);break; case 5: if (decode.modrm.mod) { base=DREG(EBP);segbase=DREG(SS); } else { imm=(Bit32s)decode_fetchd();segbase=DREG(DS); } break; case 6:base=DREG(ESI);segbase=DREG(DS);break; case 7:base=DREG(EDI);segbase=DREG(DS);break; } static DynReg * scaledtable[8]={ DREG(EAX),DREG(ECX),DREG(EDX),DREG(EBX), 0,DREG(EBP),DREG(ESI),DREG(EDI), }; scaled=scaledtable[(sib >> 3) &7]; scale=(sib >> 6); } break; /* SIB Break */ case 5: if (decode.modrm.mod) { base=DREG(EBP);segbase=DREG(SS); } else { imm=(Bit32s)decode_fetchd();segbase=DREG(DS); } break; case 6:base=DREG(ESI);segbase=DREG(DS);break; case 7:base=DREG(EDI);segbase=DREG(DS);break; } switch (decode.modrm.mod) { case 1:imm=(Bit8s)decode_fetchb();break; case 2:imm=(Bit32s)decode_fetchd();break; } gen_lea(DREG(EA),base,scaled,scale,imm); } if (addseg) { gen_lea(DREG(EA),DREG(EA),decode.segprefix ? decode.segprefix : segbase,0,0); } } #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) { dyn_fill_ea(); dyn_read_byte(DREG(EA),DREG(TMPB),false); gen_dop_byte(op,DREG(TMPB),0,rm_reg,decode.modrm.reg&4); dyn_write_byte(DREG(EA),DREG(TMPB),false); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPB)); } else { gen_dop_byte(op,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4,rm_reg,decode.modrm.reg&4); } } static void dyn_dop_gbeb(DualOps op) { dyn_get_modrm();DynReg * rm_reg=&DynRegs[decode.modrm.reg&3]; if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_read_byte(DREG(EA),DREG(TMPB),false); gen_dop_byte(op,rm_reg,decode.modrm.reg&4,DREG(TMPB),0); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPB)); } else { gen_dop_byte(op,rm_reg,decode.modrm.reg&4,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); } } static void dyn_mov_ebib(void) { dyn_get_modrm(); if (decode.modrm.mod<3) { //TODO Maybe not use a temp register here and call mem_writeb directly? dyn_fill_ea(); gen_dop_byte_imm(DOP_MOV,DREG(TMPB),0,decode_fetchb()); dyn_write_byte(DREG(EA),DREG(TMPB),false); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPB)); } else { gen_dop_byte_imm(DOP_MOV,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4,decode_fetchb()); } } static void dyn_mov_ebgb(void) { dyn_get_modrm(); DynReg * rm_reg=&DynRegs[decode.modrm.reg&3];Bitu rm_regi=decode.modrm.reg&4; if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_write_byte(DREG(EA),rm_reg,rm_regi); gen_releasereg(DREG(EA)); } else { gen_dop_byte(DOP_MOV,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4,rm_reg,rm_regi); } } static void dyn_mov_gbeb(void) { dyn_get_modrm(); DynReg * rm_reg=&DynRegs[decode.modrm.reg&3];Bitu rm_regi=decode.modrm.reg&4; if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_read_byte(DREG(EA),rm_reg,rm_regi); gen_releasereg(DREG(EA)); } else { gen_dop_byte(DOP_MOV,rm_reg,rm_regi,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); } } static void dyn_dop_evgv(DualOps op) { dyn_get_modrm(); DynReg * rm_reg=&DynRegs[decode.modrm.reg]; if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); gen_dop_word(op,decode.big_op,DREG(TMPW),rm_reg); dyn_write_word(DREG(EA),DREG(TMPW),decode.big_op); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPW)); } else { gen_dop_word(op,decode.big_op,&DynRegs[decode.modrm.rm],rm_reg); } } static void dyn_imul_gvev(Bitu immsize) { dyn_get_modrm();DynReg * src; DynReg * rm_reg=&DynRegs[decode.modrm.reg]; if (decode.modrm.mod<3) { dyn_fill_ea();dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); src=DREG(TMPW);gen_releasereg(DREG(EA)); } else { src=&DynRegs[decode.modrm.rm]; } switch (immsize) { case 0:gen_imul_word(decode.big_op,rm_reg,src);break; case 1:gen_imul_word_imm(decode.big_op,rm_reg,src,(Bit8s)decode_fetchb());break; case 2:gen_imul_word_imm(decode.big_op,rm_reg,src,(Bit16s)decode_fetchw());break; case 4:gen_imul_word_imm(decode.big_op,rm_reg,src,(Bit32s)decode_fetchd());break; } gen_releasereg(DREG(TMPW)); } static void dyn_dop_gvev(DualOps op) { dyn_get_modrm(); DynReg * rm_reg=&DynRegs[decode.modrm.reg]; if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); gen_dop_word(op,decode.big_op,rm_reg,DREG(TMPW)); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPW)); } else { gen_dop_word(op,decode.big_op,rm_reg,&DynRegs[decode.modrm.rm]); } } static void dyn_mov_evgv(void) { dyn_get_modrm(); DynReg * rm_reg=&DynRegs[decode.modrm.reg]; if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_write_word(DREG(EA),rm_reg,decode.big_op); gen_releasereg(DREG(EA)); } else { gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],rm_reg); } } static void dyn_mov_gvev(void) { dyn_get_modrm(); DynReg * rm_reg=&DynRegs[decode.modrm.reg]; if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_read_word(DREG(EA),rm_reg,decode.big_op); gen_releasereg(DREG(EA)); } else { gen_dop_word(DOP_MOV,decode.big_op,rm_reg,&DynRegs[decode.modrm.rm]); } } static void dyn_mov_eviv(void) { dyn_get_modrm(); if (decode.modrm.mod<3) { dyn_fill_ea(); gen_dop_word_imm(DOP_MOV,decode.big_op,DREG(TMPW),decode.big_op ? decode_fetchd() : decode_fetchw()); dyn_write_word(DREG(EA),DREG(TMPW),decode.big_op); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPW)); } else { gen_dop_word_imm(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],decode.big_op ? decode_fetchd() : decode_fetchw()); } } static void dyn_mov_ev_gb(bool sign) { dyn_get_modrm();DynReg * rm_reg=&DynRegs[decode.modrm.reg]; if (decode.modrm.mod<3) { dyn_fill_ea(); 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); } } static void dyn_mov_ev_gw(bool sign) { if (!decode.big_op) { dyn_mov_evgv(); return; } dyn_get_modrm();DynReg * rm_reg=&DynRegs[decode.modrm.reg]; if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_read_word(DREG(EA),DREG(TMPW),false); gen_releasereg(DREG(EA)); gen_extend_word(sign,rm_reg,DREG(TMPW)); } else { gen_extend_word(sign,rm_reg,&DynRegs[decode.modrm.rm]); } } static void dyn_dshift_ev_gv(bool left,bool immediate) { dyn_get_modrm(); DynReg * rm_reg=&DynRegs[decode.modrm.reg]; DynReg * ea_reg; if (decode.modrm.mod<3) { dyn_fill_ea();ea_reg=DREG(TMPW); dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); } else ea_reg=&DynRegs[decode.modrm.rm]; if (immediate) gen_dshift_imm(decode.big_op,left,ea_reg,rm_reg,decode_fetchb()); else gen_dshift_cl(decode.big_op,left,ea_reg,rm_reg,DREG(ECX)); if (decode.modrm.mod<3) { dyn_write_word(DREG(EA),DREG(TMPW),decode.big_op); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPW)); } } static DualOps grp1_table[8]={DOP_ADD,DOP_OR,DOP_ADC,DOP_SBB,DOP_AND,DOP_SUB,DOP_XOR,DOP_CMP}; static void dyn_grp1_eb_ib(void) { dyn_get_modrm(); if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_read_byte(DREG(EA),DREG(TMPB),false); gen_dop_byte_imm(grp1_table[decode.modrm.reg],DREG(TMPB),0,decode_fetchb()); if (grp1_table[decode.modrm.reg]!=DOP_CMP) dyn_write_byte(DREG(EA),DREG(TMPB),false); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPB)); } else { gen_dop_byte_imm(grp1_table[decode.modrm.reg],&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4,decode_fetchb()); } } static void dyn_grp1_ev_ivx(bool withbyte) { dyn_get_modrm(); if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); Bits imm=withbyte ? (Bit8s)decode_fetchb() : (decode.big_op ? decode_fetchd(): decode_fetchw()); gen_dop_word_imm(grp1_table[decode.modrm.reg],decode.big_op,DREG(TMPW),imm); dyn_write_word(DREG(EA),DREG(TMPW),decode.big_op); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPW)); } else { Bits imm=withbyte ? (Bit8s)decode_fetchb() : (decode.big_op ? decode_fetchd(): decode_fetchw()); gen_dop_word_imm(grp1_table[decode.modrm.reg],decode.big_op,&DynRegs[decode.modrm.rm],imm); } } static ShiftOps grp2_table[8]={ SHIFT_ROL,SHIFT_ROR,SHIFT_RCL,SHIFT_RCR, SHIFT_SHL,SHIFT_SHR,SHIFT_SHL,SHIFT_SAR }; enum grp2_types { grp2_1,grp2_imm,grp2_cl, }; static void dyn_grp2_eb(grp2_types type) { dyn_get_modrm(); if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_read_byte(DREG(EA),DREG(TMPB),false); DynReg * shift; switch (type) { case grp2_cl:shift=DREG(ECX);break; case grp2_1:shift=DREG(SHIFT);gen_dop_byte_imm(DOP_MOV,DREG(SHIFT),0,1);break; case grp2_imm:shift=DREG(SHIFT);gen_dop_byte_imm(DOP_MOV,DREG(SHIFT),0,decode_fetchb());break; } gen_shift_byte(grp2_table[decode.modrm.reg],shift,DREG(TMPB),0); dyn_write_byte(DREG(EA),DREG(TMPB),false); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPB));gen_releasereg(DREG(SHIFT)); } else { DynReg * shift; switch (type) { case grp2_cl:shift=DREG(ECX);break; case grp2_1:shift=DREG(SHIFT);gen_dop_byte_imm(DOP_MOV,DREG(SHIFT),0,1);break; case grp2_imm:shift=DREG(SHIFT);gen_dop_byte_imm(DOP_MOV,DREG(SHIFT),0,decode_fetchb());break; } gen_shift_byte(grp2_table[decode.modrm.reg],shift,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); gen_releasereg(DREG(SHIFT)); } } static void dyn_grp2_ev(grp2_types type) { dyn_get_modrm(); if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); DynReg * shift; switch (type) { case grp2_cl:shift=DREG(ECX);break; case grp2_1:shift=DREG(SHIFT);gen_dop_byte_imm(DOP_MOV,DREG(SHIFT),0,1);break; case grp2_imm:shift=DREG(SHIFT);gen_dop_byte_imm(DOP_MOV,DREG(SHIFT),0,decode_fetchb());break; } gen_shift_word(grp2_table[decode.modrm.reg],shift,decode.big_op,DREG(TMPW)); dyn_write_word(DREG(EA),DREG(TMPW),decode.big_op); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPW));gen_releasereg(DREG(SHIFT)); } else { DynReg * shift; switch (type) { case grp2_cl:shift=DREG(ECX);break; case grp2_1:shift=DREG(SHIFT);gen_dop_byte_imm(DOP_MOV,DREG(SHIFT),0,1);break; case grp2_imm:shift=DREG(SHIFT);gen_dop_byte_imm(DOP_MOV,DREG(SHIFT),0,decode_fetchb());break; } gen_shift_word(grp2_table[decode.modrm.reg],shift,decode.big_op,&DynRegs[decode.modrm.rm]); gen_releasereg(DREG(SHIFT)); } } static void dyn_grp3_eb(void) { DynState state;Bit8u * branch; dyn_get_modrm();DynReg * src;Bit8u src_i; if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_read_byte(DREG(EA),DREG(TMPB),false); src=DREG(TMPB);src_i=0; } else { src=&DynRegs[decode.modrm.rm&3]; src_i=decode.modrm.rm&4; } switch (decode.modrm.reg) { case 0x0: /* test eb,ib */ gen_dop_byte_imm(DOP_TEST,src,src_i,decode_fetchb()); goto skipsave; case 0x2: /* NOT Eb */ gen_sop_byte(SOP_NOT,src,src_i); break; case 0x3: /* NEG Eb */ gen_sop_byte(SOP_NEG,src,src_i); break; case 0x4: /* mul Eb */ gen_mul_byte(false,DREG(EAX),src,src_i); goto skipsave; case 0x5: /* imul Eb */ gen_mul_byte(true,DREG(EAX),src,src_i); goto skipsave; case 0x6: /* div Eb */ case 0x7: /* idiv Eb */ /* EAX could be used, so precache it */ if (decode.modrm.mod==3) gen_dop_byte(DOP_MOV,DREG(TMPB),0,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); gen_storeflags();gen_releasereg(DREG(EAX)); gen_call_function((decode.modrm.reg==6) ? (void *)&dyn_helper_divb : (void *)&dyn_helper_idivb, "%Rd%Drl",DREG(TMPB),DREG(TMPB)); gen_dop_word(DOP_OR,true,DREG(TMPB),DREG(TMPB)); branch=gen_create_branch(BR_Z); dyn_savestate(&state); dyn_reduce_cycles(); gen_lea(DREG(EIP),DREG(EIP),0,0,decode.op_start-decode.code_start); dyn_save_flags(true); dyn_releaseregs(); gen_call_function((void *)&CPU_Exception,"%Id%Id",0,0); dyn_load_flags(); gen_return(BR_Normal); dyn_loadstate(&state); gen_fill_branch(branch); gen_restoreflags(); goto skipsave; } /* Save the result if memory op */ if (decode.modrm.mod<3) dyn_write_byte(DREG(EA),DREG(TMPB),false); skipsave: gen_releasereg(DREG(TMPB));gen_releasereg(DREG(EA)); } static void dyn_grp3_ev(void) { DynState state;Bit8u * branch; dyn_get_modrm();DynReg * src; if (decode.modrm.mod<3) { dyn_fill_ea();src=DREG(TMPW); dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); } else src=&DynRegs[decode.modrm.rm]; switch (decode.modrm.reg) { case 0x0: /* test ev,iv */ gen_dop_word_imm(DOP_TEST,decode.big_op,src,decode.big_op ? decode_fetchd() : decode_fetchw()); goto skipsave; case 0x2: /* NOT Ev */ gen_sop_word(SOP_NOT,decode.big_op,src); break; case 0x3: /* NEG Eb */ gen_sop_word(SOP_NEG,decode.big_op,src); break; case 0x4: /* mul Eb */ gen_mul_word(false,DREG(EAX),DREG(EDX),decode.big_op,src); goto skipsave; case 0x5: /* imul Eb */ gen_mul_word(true,DREG(EAX),DREG(EDX),decode.big_op,src); goto skipsave; case 0x6: /* div Eb */ case 0x7: /* idiv Eb */ /* EAX could be used, so precache it */ if (decode.modrm.mod==3) gen_dop_word(DOP_MOV,decode.big_op,DREG(TMPW),&DynRegs[decode.modrm.rm]); gen_storeflags();gen_releasereg(DREG(EAX));gen_releasereg(DREG(EDX)); void * func=(decode.modrm.reg==6) ? (decode.big_op ? (void *)&dyn_helper_divd : (void *)&dyn_helper_divw) : (decode.big_op ? (void *)&dyn_helper_idivd : (void *)&dyn_helper_idivw); gen_call_function(func,"%Rd%Drd",DREG(TMPW),DREG(TMPW)); gen_dop_word(DOP_OR,true,DREG(TMPW),DREG(TMPW)); branch=gen_create_branch(BR_Z); dyn_savestate(&state); dyn_reduce_cycles(); gen_lea(DREG(EIP),DREG(EIP),0,0,decode.op_start-decode.code_start); dyn_save_flags(true); dyn_releaseregs(); gen_call_function((void *)&CPU_Exception,"%Id%Id",0,0); dyn_load_flags(); gen_return(BR_Normal); dyn_loadstate(&state); gen_fill_branch(branch); gen_restoreflags(); goto skipsave; } /* Save the result if memory op */ if (decode.modrm.mod<3) dyn_write_word(DREG(EA),DREG(TMPW),decode.big_op); skipsave: gen_releasereg(DREG(TMPW));gen_releasereg(DREG(EA)); } static void dyn_mov_ev_seg(void) { dyn_get_modrm(); gen_load_host(&Segs.val[decode.modrm.reg],DREG(TMPW),2); if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_write_word(DREG(EA),DREG(TMPW),false); gen_releasereg(DREG(EA)); } else { gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],DREG(TMPW)); } gen_releasereg(DREG(TMPW)); } static void dyn_load_seg(SegNames seg,DynReg * src,bool withpop) { if (cpu.pmode) { Bit8u * branch;DynState state; gen_storeflags(); gen_call_function((void *)&CPU_SetSegGeneral,"%Rd%Id%Drw",DREG(TMPB),seg,src); gen_dop_byte(DOP_OR,DREG(TMPB),0,DREG(TMPB),0); branch=gen_create_branch(BR_Z); dyn_savestate(&state); dyn_reduce_cycles(); if (withpop) gen_dop_word_imm(DOP_SUB,true,DREG(ESP),decode.big_op ? 4 : 2); gen_dop_word_imm(DOP_ADD,true,DREG(EIP),decode.op_start-decode.code_start); dyn_save_flags(true); dyn_releaseregs(); gen_call_function((void *)&CPU_StartException,""); dyn_load_flags(); gen_return(BR_Normal); dyn_loadstate(&state); gen_fill_branch(branch); gen_restoreflags(); } else { //TODO Maybe just calculate the base directly if in realmode 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) { dyn_get_modrm(); if (decode.modrm.mod<3) { 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);gen_releasereg(DREG(TMPW)); dyn_read_word(DREG(EA),&DynRegs[decode.modrm.reg],decode.big_op); gen_releasereg(DREG(EA)); } else { IllegalOption(); } } static void dyn_mov_seg_ev(void) { dyn_get_modrm(); SegNames seg=(SegNames)decode.modrm.reg; if (seg==cs) IllegalOption(); if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_read_word(DREG(EA),DREG(EA),false); dyn_load_seg(seg,DREG(EA),false); gen_releasereg(DREG(EA)); } else { dyn_load_seg(seg,&DynRegs[decode.modrm.rm],false); } } static void dyn_push_seg(SegNames seg) { gen_load_host(&Segs.val[seg],DREG(TMPW),2); dyn_push(DREG(TMPW)); gen_releasereg(DREG(TMPW)); } static void dyn_pop_seg(SegNames seg) { gen_storeflags(); dyn_pop(DREG(TMPW)); dyn_load_seg(seg,DREG(TMPW),true); gen_releasereg(DREG(TMPW)); gen_restoreflags(); } static void dyn_pop_ev(void) { gen_storeflags(); dyn_pop(DREG(TMPW)); dyn_get_modrm(); if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_write_word(DREG(EA),DREG(TMPW),decode.big_op); gen_releasereg(DREG(EA)); } else { gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],DREG(TMPW)); } gen_releasereg(DREG(TMPW)); gen_restoreflags(); } static void dyn_leave(void) { gen_storeflags(); gen_dop_word(DOP_MOV,true,DREG(TMPW),DREG(SMASK)); 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(DOP_OR,true,DREG(ESP),DREG(TMPW)); dyn_pop(DREG(EBP)); gen_releasereg(DREG(TMPW)); gen_restoreflags(); } static void dyn_segprefix(SegNames seg) { if (decode.segprefix) IllegalOption(); decode.segprefix=&DynRegs[G_ES+seg]; } static void dyn_closeblock(BlockType type) { //Shouldn't create empty block normally but let's do it like this if (decode.code>decode.code_start) decode.code--; Bitu start_page=decode.code_start >> 12; Bitu end_page=decode.code>>12; decode.block->page.start=(Bit16s)decode.code_start & 4095; decode.block->page.end=(Bit16s)((end_page-start_page)*4096+(decode.code&4095)); cache_closeblock(type); } static void dyn_normal_exit(BlockReturn code) { gen_lea(DREG(EIP),DREG(EIP),0,0,decode.code-decode.code_start); dyn_reduce_cycles(); dyn_releaseregs(); gen_return(code); dyn_closeblock(BT_Normal); } static void dyn_exit_link(bool dword,Bits eip_change) { gen_lea(DREG(EIP),DREG(EIP),0,0,(decode.code-decode.code_start)+eip_change); if (!dword) gen_extend_word(false,DREG(EIP),DREG(EIP)); dyn_reduce_cycles(); dyn_releaseregs(); // gen_return(BR_Normal); gen_jmp_ptr(&decode.block->link.to[0],offsetof(CacheBlock,cache.start)); dyn_closeblock(BT_SingleLink); } static void dyn_branched_exit(BranchTypes btype,Bit32s eip_add) { dyn_reduce_cycles(); dyn_releaseregs(); Bitu eip_base=decode.code-decode.code_start; Bit8u * data=gen_create_branch(btype); /* Branch not taken */ gen_lea(DREG(EIP),DREG(EIP),0,0,eip_base); gen_releasereg(DREG(EIP)); // gen_return(BR_Normal); gen_jmp_ptr(&decode.block->link.to[0],offsetof(CacheBlock,cache.start)); gen_fill_branch(data); /* Branch taken */ gen_lea(DREG(EIP),DREG(EIP),0,0,eip_base+eip_add); gen_releasereg(DREG(EIP)); // gen_return(BR_Normal); gen_jmp_ptr(&decode.block->link.to[1],offsetof(CacheBlock,cache.start)); dyn_closeblock(BT_DualLink); } enum LoopTypes { LOOP_NONE,LOOP_NE,LOOP_E, }; static void dyn_loop(LoopTypes type) { Bits eip_add=(Bit8s)decode_fetchb(); Bitu eip_base=decode.code-decode.code_start; gen_storeflags(); dyn_reduce_cycles(); Bit8u * branch1; Bit8u * branch2=0; gen_sop_word(SOP_DEC,decode.big_addr,DREG(ECX)); dyn_releaseregs(); branch1=gen_create_branch(BR_Z); gen_restoreflags(true); switch (type) { case LOOP_NONE: break; case LOOP_E: branch2=gen_create_branch(BR_NZ); break; case LOOP_NE: branch2=gen_create_branch(BR_Z); break; } gen_lea(DREG(EIP),DREG(EIP),0,0,eip_base+eip_add); gen_releasereg(DREG(EIP)); gen_jmp_ptr(&decode.block->link.to[0],offsetof(CacheBlock,cache.start)); gen_fill_branch(branch1); if (branch2) gen_fill_branch(branch2); /* Branch taken */ gen_restoreflags(); gen_lea(DREG(EIP),DREG(EIP),0,0,eip_base); gen_releasereg(DREG(EIP)); gen_jmp_ptr(&decode.block->link.to[1],offsetof(CacheBlock,cache.start)); dyn_closeblock(BT_DualLink); } static void dyn_ret_near(Bitu bytes) { dyn_reduce_cycles(); //TODO maybe AND eip 0xffff, but shouldn't be needed gen_storeflags(); dyn_pop(DREG(EIP)); if (bytes) gen_dop_word_imm(DOP_ADD,true,DREG(ESP),bytes); dyn_releaseregs(); gen_restoreflags(); gen_return(BR_Normal); dyn_closeblock(BT_Normal); } static void dyn_ret_far(Bitu bytes) { dyn_reduce_cycles(); //TODO maybe AND eip 0xffff, but shouldn't be needed gen_lea(DREG(EIP),DREG(EIP),0,0,decode.code-decode.code_start); dyn_save_flags(); dyn_releaseregs(); gen_call_function((void*)&CPU_RET,"%Id%Id%Id",decode.big_op,bytes,decode.code-decode.op_start); dyn_load_flags(); dyn_releaseregs();; gen_return(BR_Normal); dyn_closeblock(BT_Normal); } static void dyn_call_near_imm(void) { Bits imm; if (decode.big_op) imm=(Bit32s)decode_fetchd(); else imm=(Bit16s)decode_fetchw(); gen_lea(DREG(EIP),DREG(EIP),0,0,decode.code-decode.code_start); dyn_push(DREG(EIP)); gen_lea(DREG(EIP),DREG(EIP),0,0,imm); if (!decode.big_op) gen_extend_word(false,DREG(EIP),DREG(EIP)); dyn_reduce_cycles(); dyn_releaseregs(); gen_return(BR_Normal); // gen_jmp_ptr(&decode.block->link.to[0],offsetof(CacheBlock,cache.start)); dyn_closeblock(BT_SingleLink); } static void dyn_call_far_imm(void) { Bitu sel,off; off=decode.big_op ? decode_fetchd() : decode_fetchw(); sel=decode_fetchw(); dyn_reduce_cycles(); gen_lea(DREG(EIP),DREG(EIP),0,0,decode.code-decode.code_start); dyn_save_flags(); dyn_releaseregs(); gen_call_function((void*)&CPU_CALL,"%Id%Id%Id%Id",decode.big_op,sel,off,decode.code-decode.op_start); dyn_load_flags(); dyn_releaseregs(); gen_return(BR_Normal); dyn_closeblock(BT_Normal); } static void dyn_jmp_far_imm(void) { Bitu sel,off; off=decode.big_op ? decode_fetchd() : decode_fetchw(); sel=decode_fetchw(); dyn_reduce_cycles(); gen_lea(DREG(EIP),DREG(EIP),0,0,decode.code-decode.code_start); dyn_save_flags(); dyn_releaseregs(); gen_call_function((void*)&CPU_JMP,"%Id%Id%Id%Id",decode.big_op,sel,off,decode.code-decode.op_start); dyn_load_flags(); dyn_releaseregs(); gen_return(BR_Normal); dyn_closeblock(BT_Normal); } static void dyn_iret(void) { dyn_save_flags(); dyn_reduce_cycles(); gen_dop_word_imm(DOP_ADD,true,DREG(EIP),decode.code-decode.code_start); dyn_releaseregs(); gen_call_function((void*)&CPU_IRET,"%Id%Id",decode.big_op,decode.code-decode.op_start); dyn_load_flags(); dyn_releaseregs(); gen_return(BR_Normal); dyn_closeblock(BT_CheckFlags); } static void dyn_interrupt(Bitu num) { dyn_save_flags(); dyn_reduce_cycles(); gen_dop_word_imm(DOP_ADD,true,DREG(EIP),decode.code-decode.code_start); dyn_releaseregs(); gen_call_function((void*)&CPU_Interrupt,"%Id%Id%Id",num,CPU_INT_SOFTWARE,decode.code-decode.op_start); dyn_load_flags(); dyn_releaseregs(); gen_return(BR_Normal); dyn_closeblock(BT_Normal); } static CacheBlock * CreateCacheBlock(PhysPt start,bool big,Bitu max_opcodes) { Bits i; decode.code_start=start; decode.code=start; Bitu cycles=0; decode.block=cache_openblock(); gen_save_host_direct(&cache.block.running,(Bit32u)decode.block); for (i=0;i=G_EAX;i--) { dyn_pop((i!=G_ESP) ? &DynRegs[i] : DREG(TMPW)); } gen_restoreflags();gen_releasereg(DREG(TMPW)); break; //segprefix FS,GS case 0x64:dyn_segprefix(fs);goto restart_prefix; case 0x65:dyn_segprefix(gs);goto restart_prefix; //Push immediates //Operand size case 0x66:decode.big_op=!big;goto restart_prefix; //Address size case 0x67:decode.big_addr=!big;goto restart_prefix; case 0x68: /* PUSH Iv */ gen_dop_word_imm(DOP_MOV,decode.big_op,DREG(TMPW),decode.big_op ? decode_fetchd() : decode_fetchw()); dyn_push(DREG(TMPW)); gen_releasereg(DREG(TMPW)); break; /* Imul Ivx */ case 0x69:dyn_imul_gvev(decode.big_op ? 4 : 2);break; case 0x6a: /* PUSH Ibx */ gen_dop_word_imm(DOP_MOV,true,DREG(TMPW),(Bit8s)decode_fetchb()); dyn_push(DREG(TMPW)); gen_releasereg(DREG(TMPW)); break; /* Imul Ibx */ case 0x6b:dyn_imul_gvev(1);break; /* Short conditional jumps */ case 0x70:case 0x71:case 0x72:case 0x73:case 0x74:case 0x75:case 0x76:case 0x77: case 0x78:case 0x79:case 0x7a:case 0x7b:case 0x7c:case 0x7d:case 0x7e:case 0x7f: dyn_branched_exit((BranchTypes)(opcode&0xf),(Bit8s)decode_fetchb()); return decode.block; /* Group 1 */ case 0x80:dyn_grp1_eb_ib();break; case 0x81:dyn_grp1_ev_ivx(false);break; case 0x82:dyn_grp1_eb_ib();break; case 0x83:dyn_grp1_ev_ivx(true);break; /* TEST Gb,Eb Gv,Ev */ case 0x84:dyn_dop_gbeb(DOP_TEST);break; case 0x85:dyn_dop_gvev(DOP_TEST);break; /* XCHG Eb,Gb Ev,Gv */ case 0x86:dyn_dop_ebgb(DOP_XCHG);break; case 0x87:dyn_dop_evgv(DOP_XCHG);break; /* MOV e,g and g,e */ case 0x88:dyn_mov_ebgb();break; case 0x89:dyn_mov_evgv();break; case 0x8a:dyn_mov_gbeb();break; case 0x8b:dyn_mov_gvev();break; /* MOV ev,seg */ case 0x8c:dyn_mov_ev_seg();break; /* LEA Gv */ case 0x8d: dyn_get_modrm();dyn_fill_ea(false); gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.reg],DREG(EA)); gen_releasereg(DREG(EA)); break; /* Mov seg,ev */ case 0x8e:dyn_mov_seg_ev();break; /* POP Ev */ case 0x8f:dyn_pop_ev();break; //NOP case 0x90: break; //XCHG ax,reg case 0x91:case 0x92:case 0x93:case 0x94:case 0x95:case 0x96:case 0x97: gen_dop_word(DOP_XCHG,decode.big_op,DREG(EAX),&DynRegs[opcode&07]); break; /* CBW/CWDE */ case 0x98: /* if (decode.big_op) gen_extend_word(true,DREG(EAX),DREG(EAX)); else gen_extend_byte(true,false,DREG(EAX),DREG(EAX),0); */ gen_cbw(decode.big_op,DREG(EAX)); break; /* CWD/CDQ */ case 0x99: gen_cwd(decode.big_op,DREG(EAX),DREG(EDX)); break; /* CALL FAR Ip */ case 0x9a:dyn_call_far_imm();return decode.block; /* MOV AL,direct addresses */ case 0xa0: gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0, decode.big_addr ? decode_fetchd() : decode_fetchw()); dyn_read_byte(DREG(EA),DREG(EAX),false); gen_releasereg(DREG(EA)); break; /* MOV AX,direct addresses */ case 0xa1: gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0, decode.big_addr ? decode_fetchd() : decode_fetchw()); dyn_read_word(DREG(EA),DREG(EAX),decode.big_op); gen_releasereg(DREG(EA)); break; /* MOV direct address,AL */ case 0xa2: gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0, decode.big_addr ? decode_fetchd() : decode_fetchw()); dyn_write_byte(DREG(EA),DREG(EAX),false); gen_releasereg(DREG(EA)); break; /* MOV direct addresses,AX */ case 0xa3: gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0, decode.big_addr ? decode_fetchd() : decode_fetchw()); 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()); break; //Mov word reg imm byte,word, case 0xb8:case 0xb9:case 0xba:case 0xbb:case 0xbc:case 0xbd:case 0xbe:case 0xbf: gen_dop_word_imm(DOP_MOV,decode.big_op,&DynRegs[opcode&7],decode.big_op ? decode_fetchd() : decode_fetchw());break; break; //GRP2 Eb/Ev,Ib case 0xc0:dyn_grp2_eb(grp2_imm);break; case 0xc1:dyn_grp2_ev(grp2_imm);break; //RET near Iw / Ret case 0xc2:dyn_ret_near(decode_fetchw());return decode.block; case 0xc3:dyn_ret_near(0);return decode.block; //LES/LDS case 0xc4:dyn_load_seg_off_ea(es);break; case 0xc5:dyn_load_seg_off_ea(ds);break; // MOV Eb/Ev,Ib/Iv case 0xc6:dyn_mov_ebib();break; case 0xc7:dyn_mov_eviv();break; // LEAVE case 0xc9:dyn_leave();break; //RET far Iw / Ret case 0xca:dyn_ret_far(decode_fetchw());return decode.block; case 0xcb:dyn_ret_far(0);return decode.block; /* Interrupt */ case 0xcd:dyn_interrupt(decode_fetchb());return decode.block; /* IRET */ case 0xcf:dyn_iret();return decode.block; //GRP2 Eb/Ev,1 case 0xd0:dyn_grp2_eb(grp2_1);break; case 0xd1:dyn_grp2_ev(grp2_1);break; //GRP2 Eb/Ev,CL case 0xd2:dyn_grp2_eb(grp2_cl);break; case 0xd3:dyn_grp2_ev(grp2_cl);break; //Loop's case 0xe2:dyn_loop(LOOP_NONE);return decode.block; //IN AL/AX,imm case 0xe4:gen_call_function((void*)&IO_ReadB,"%Id%Rl",decode_fetchb(),DREG(EAX));break; case 0xe5: if (decode.big_op) { gen_call_function((void*)&IO_ReadD,"%Id%Rd",decode_fetchb(),DREG(EAX)); } else { gen_call_function((void*)&IO_ReadW,"%Id%Rw",decode_fetchb(),DREG(EAX)); } break; //OUT imm,AL case 0xe6:gen_call_function((void*)&IO_WriteB,"%Id%Dl",decode_fetchb(),DREG(EAX));break; case 0xe7: if (decode.big_op) { gen_call_function((void*)&IO_WriteD,"%Id%Dd",decode_fetchb(),DREG(EAX)); } else { gen_call_function((void*)&IO_WriteW,"%Id%Dw",decode_fetchb(),DREG(EAX)); } break; case 0xe8: /* CALL Ivx */ dyn_call_near_imm(); return decode.block; case 0xe9: /* Jmp Ivx */ dyn_exit_link(decode.big_op,decode.big_op ? (Bit32s)decode_fetchd() : (Bit16s)decode_fetchw()); return decode.block; /* CALL FAR Ip */ case 0xea:dyn_jmp_far_imm();return decode.block; /* Jmp Ibx */ case 0xeb:dyn_exit_link(decode.big_op,(Bit8s)decode_fetchb());return decode.block; /* IN AL/AX,DX*/ case 0xec:gen_call_function((void*)&IO_ReadB,"%Dw%Rl",DREG(EDX),DREG(EAX));break; case 0xed: if (decode.big_op) { gen_call_function((void*)&IO_ReadD,"%Dw%Rd",DREG(EDX),DREG(EAX)); } else { gen_call_function((void*)&IO_ReadW,"%Dw%Rw",DREG(EDX),DREG(EAX)); } break; /* OUT DX,AL/AX */ case 0xee:gen_call_function((void*)&IO_WriteB,"%Dw%Dl",DREG(EDX),DREG(EAX));break; case 0xef: if (decode.big_op) { gen_call_function((void*)&IO_WriteD,"%Dw%Dd",DREG(EDX),DREG(EAX)); } else { 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 case 0xf9: //STC cache_addb(opcode);break; /* GRP 3 Eb/EV */ case 0xf6:dyn_grp3_eb();break; case 0xf7:dyn_grp3_ev();break; /* Change interrupt flag */ case 0xfa: //CLI gen_storeflags(); gen_dop_word_imm(DOP_AND,true,DREG(FLAGS),~FLAG_IF); gen_restoreflags(); break; case 0xfb: //STI gen_storeflags(); gen_dop_word_imm(DOP_OR,true,DREG(FLAGS),FLAG_IF); gen_restoreflags(); if (max_opcodes<=0) max_opcodes=1; //Allow 1 extra opcode break; /* GRP 4 Eb and callback's */ case 0xfe: dyn_get_modrm(); switch (decode.modrm.reg) { case 0x0://INC Eb case 0x1://DEC Eb if (decode.modrm.mod<3) { dyn_fill_ea();dyn_read_byte(DREG(EA),DREG(TMPB),false); gen_sop_byte(decode.modrm.reg==0 ? SOP_INC : SOP_DEC,DREG(TMPB),0); dyn_write_byte(DREG(EA),DREG(TMPB),false); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPB)); } else { gen_sop_byte(decode.modrm.reg==0 ? SOP_INC : SOP_DEC, &DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); } break; case 0x7: //CALBACK Iw gen_save_host_direct(&core_dyn.callback,decode_fetchw()); gen_lea(DREG(EIP),DREG(EIP),0,0,decode.code-decode.code_start); dyn_reduce_cycles(); dyn_releaseregs(); gen_return(BR_CallBack); dyn_closeblock(BT_Normal); return decode.block; } break; case 0xff: { dyn_get_modrm();DynReg * src; if (decode.modrm.mod<3) { dyn_fill_ea(); dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); src=DREG(TMPW); } else src=&DynRegs[decode.modrm.rm]; switch (decode.modrm.reg) { case 0x0://INC Ev case 0x1://DEC Ev gen_sop_word(decode.modrm.reg==0 ? SOP_INC : SOP_DEC,decode.big_op,src); if (decode.modrm.mod<3){ dyn_write_word(DREG(EA),DREG(TMPW),decode.big_op); gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPW)); } break; case 0x2: /* CALL Ev */ gen_lea(DREG(EIP),DREG(EIP),0,0,decode.code-decode.code_start); dyn_push(DREG(EIP)); gen_dop_word(DOP_MOV,decode.big_op,DREG(EIP),src); goto core_close_block; case 0x4: /* JMP Ev */ gen_dop_word(DOP_MOV,decode.big_op,DREG(EIP),src); goto core_close_block; case 0x3: /* CALL Ep */ case 0x5: /* JMP Ep */ dyn_save_flags(); gen_lea(DREG(EA),DREG(EA),0,0,decode.big_op ? 4: 2); gen_lea(DREG(EIP),DREG(EIP),0,0,decode.code-decode.code_start); dyn_read_word(DREG(EA),DREG(EA),false); for (Bitu i=0;i