DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/cpu/core_dyn_x86/string.h
00001 /*
00002  *  Copyright (C) 2002-2013  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 enum STRING_OP {
00020         STR_OUTSB=0,STR_OUTSW,STR_OUTSD,
00021         STR_INSB=4,STR_INSW,STR_INSD,
00022         STR_MOVSB=8,STR_MOVSW,STR_MOVSD,
00023         STR_LODSB=12,STR_LODSW,STR_LODSD,
00024         STR_STOSB=16,STR_STOSW,STR_STOSD,
00025         STR_SCASB=20,STR_SCASW,STR_SCASD,
00026         STR_CMPSB=24,STR_CMPSW,STR_CMPSD
00027 };
00028 
00029 static void dyn_string(STRING_OP op) {
00030         DynReg * si_base=decode.segprefix ? decode.segprefix : DREG(DS);
00031         DynReg * di_base=DREG(ES);
00032         DynReg * tmp_reg;bool usesi;bool usedi;
00033         gen_protectflags();
00034         if (decode.rep) {
00035                 gen_dop_word_imm(DOP_SUB,true,DREG(CYCLES),decode.cycles);
00036                 gen_releasereg(DREG(CYCLES));
00037                 decode.cycles=0;
00038         }
00039         /* Check what each string operation will be using */
00040         switch (op) {
00041         case STR_MOVSB: case STR_MOVSW: case STR_MOVSD:
00042         case STR_CMPSB: case STR_CMPSW: case STR_CMPSD:
00043                 tmp_reg=DREG(TMPB);usesi=true;usedi=true;break;
00044         case STR_LODSB: case STR_LODSW: case STR_LODSD:
00045                 tmp_reg=DREG(EAX);usesi=true;usedi=false;break;
00046         case STR_OUTSB: case STR_OUTSW: case STR_OUTSD:
00047                 tmp_reg=DREG(TMPB);usesi=true;usedi=false;break;
00048         case STR_SCASB: case STR_SCASW: case STR_SCASD:
00049         case STR_STOSB: case STR_STOSW: case STR_STOSD:
00050                 tmp_reg=DREG(EAX);usesi=false;usedi=true;break;
00051         case STR_INSB:  case STR_INSW:  case STR_INSD:
00052                 tmp_reg=DREG(TMPB);usesi=false;usedi=true;break;
00053         default:
00054                 IllegalOption("dyn_string op");
00055         }
00056         gen_load_host(&cpu.direction,DREG(TMPW),4);
00057         switch (op & 3) {
00058         case 0:break;
00059         case 1:gen_shift_word_imm(SHIFT_SHL,true,DREG(TMPW),1);break;
00060         case 2:gen_shift_word_imm(SHIFT_SHL,true,DREG(TMPW),2);break;
00061         default:
00062                 IllegalOption("dyn_string shift");
00063 
00064         }
00065         if (usesi) {
00066                 gen_preloadreg(DREG(ESI));
00067                 DynRegs[G_ESI].flags|=DYNFLG_CHANGED;
00068                 gen_preloadreg(si_base);
00069         }
00070         if (usedi) {
00071                 gen_preloadreg(DREG(EDI));
00072                 DynRegs[G_EDI].flags|=DYNFLG_CHANGED;
00073                 gen_preloadreg(di_base);
00074         }
00075         if (decode.rep) {
00076                 gen_preloadreg(DREG(ECX));
00077                 DynRegs[G_ECX].flags|=DYNFLG_CHANGED;
00078         }
00079         DynState rep_state;
00080         dyn_savestate(&rep_state);
00081         Bit8u * rep_start=cache.pos;
00082         Bit8u * rep_ecx_jmp=NULL;
00083         /* Check if ECX!=zero */
00084         if (decode.rep) {
00085                 gen_dop_word(DOP_OR,decode.big_addr,DREG(ECX),DREG(ECX));
00086                 rep_ecx_jmp=gen_create_branch_long(BR_Z);
00087         }
00088         if (usesi) {
00089                 if (!decode.big_addr) {
00090                         gen_extend_word(false,DREG(EA),DREG(ESI));
00091                         gen_lea(DREG(EA),si_base,DREG(EA),0,0);
00092                 } else {
00093                         gen_lea(DREG(EA),si_base,DREG(ESI),0,0);
00094                 }
00095                 switch (op&3) {
00096                         case 0:dyn_read_byte(DREG(EA),tmp_reg,false);break;
00097                         case 1:dyn_read_word(DREG(EA),tmp_reg,false);break;
00098                         case 2:dyn_read_word(DREG(EA),tmp_reg,true);break;
00099                 }
00100                 switch (op) {
00101                         case STR_OUTSB:
00102                                 gen_call_function((void*)&IO_WriteB,"%Id%Dl",DREG(EDX),tmp_reg);break;
00103                         case STR_OUTSW:
00104                                 gen_call_function((void*)&IO_WriteW,"%Id%Dw",DREG(EDX),tmp_reg);break;
00105                         case STR_OUTSD:
00106                                 gen_call_function((void*)&IO_WriteD,"%Id%Dd",DREG(EDX),tmp_reg);break;
00107                         default:
00108                                 break;
00109                 }
00110         }
00111         if (usedi) {
00112                 if (!decode.big_addr) {
00113                         gen_extend_word(false,DREG(EA),DREG(EDI));
00114                         gen_lea(DREG(EA),di_base,DREG(EA),0,0);
00115                 } else {
00116                         gen_lea(DREG(EA),di_base,DREG(EDI),0,0);
00117                 }
00118                 /* Maybe something special to be done to fill the value */
00119                 switch (op) {
00120                 case STR_INSB:
00121                         gen_call_function((void*)&IO_ReadB,"%Dw%Rl",DREG(EDX),tmp_reg);
00122                 case STR_MOVSB:
00123                 case STR_STOSB:
00124                         dyn_write_byte(DREG(EA),tmp_reg,false);
00125                         break;
00126                 case STR_INSW:
00127                         gen_call_function((void*)&IO_ReadW,"%Dw%Rw",DREG(EDX),tmp_reg);
00128                 case STR_MOVSW:
00129                 case STR_STOSW:
00130                         dyn_write_word(DREG(EA),tmp_reg,false);
00131                         break;
00132                 case STR_INSD:
00133                         gen_call_function((void*)&IO_ReadD,"%Dw%Rd",DREG(EDX),tmp_reg);
00134                 case STR_MOVSD:
00135                 case STR_STOSD:
00136                         dyn_write_word(DREG(EA),tmp_reg,true);
00137                         break;
00138                 default:
00139                         IllegalOption("dyn_string op");
00140                 }
00141         }
00142         gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPB));
00143 
00144         /* update registers */
00145         if (usesi) gen_dop_word(DOP_ADD,decode.big_addr,DREG(ESI),DREG(TMPW));
00146         if (usedi) gen_dop_word(DOP_ADD,decode.big_addr,DREG(EDI),DREG(TMPW));
00147 
00148         if (decode.rep) {
00149                 gen_sop_word(SOP_DEC,decode.big_addr,DREG(ECX));
00150                 gen_sop_word(SOP_DEC,true,DREG(CYCLES));
00151                 gen_releasereg(DREG(CYCLES));
00152                 dyn_savestate(&save_info[used_save_info].state);
00153                 save_info[used_save_info].branch_pos=gen_create_branch_long(BR_LE);
00154                 save_info[used_save_info].eip_change=decode.op_start-decode.code_start;
00155                 save_info[used_save_info].type=normal;
00156                 used_save_info++;
00157 
00158                 /* Jump back to start of ECX check */
00159                 dyn_synchstate(&rep_state);
00160                 gen_create_jump(rep_start);
00161 
00162                 dyn_loadstate(&rep_state);
00163                 gen_fill_branch_long(rep_ecx_jmp);
00164         }
00165         gen_releasereg(DREG(TMPW));
00166 }