DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 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 along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 { 00020 extern int cpu_rep_max; 00021 static PhysPt si_base,di_base; 00022 static Bit32u si_index,di_index; 00023 static Bit32u add_mask; 00024 static Bitu count,count_left; 00025 static Bits add_index; 00026 00027 count_left=0; 00028 00029 add_index=cpu.direction; 00030 if (inst.prefix & PREFIX_SEG) si_base=inst.seg.base; 00031 else si_base=SegBase(ds); 00032 di_base=SegBase(es); 00033 00034 if (inst.prefix & PREFIX_ADDR) { 00035 add_mask=0xFFFFFFFF; 00036 si_index=reg_esi; 00037 di_index=reg_edi; 00038 count=reg_ecx; 00039 } else { 00040 add_mask=0xFFFF; 00041 si_index=reg_si; 00042 di_index=reg_di; 00043 count=reg_cx; 00044 } 00045 00046 if (!(inst.prefix & PREFIX_REP)) { 00047 count=1; 00048 } else { 00049 /* we allow the user to cap our count as a way of making REP string operations interruptable (and at what granularity) */ 00050 /* NTS: This condition is less important now that the loops themselves break when CPU_Cycles <= 0. when this code was 00051 * initially implemented the string ops stubbornly counted through the bytes regardless of pending interrupts and 00052 * it caused problems with code that needed fine timing i.e. demos that played music through the LPT DAC while 00053 * using REP OUTSB to the VGA palette suffered from audio quality problems. at this phase of implementation the 00054 * "interruptible string ops" parameter is now merely a testing parameter that can be used to verify this code 00055 * breaks and restarts string ops correctly. */ 00056 if (cpu_rep_max > 0 && count > (unsigned int)cpu_rep_max) { 00057 count_left+=count-(unsigned int)cpu_rep_max; 00058 count=(unsigned int)cpu_rep_max; 00059 } 00060 } 00061 00062 if (count != 0) { 00063 try { 00064 switch (inst.code.op) { 00065 case R_OUTSB: 00066 do { 00067 IO_WriteB(reg_dx,LoadMb(si_base+si_index)); 00068 si_index=(si_index+(Bitu)add_index) & add_mask; 00069 count--; 00070 00071 if ((--CPU_Cycles) <= 0) break; 00072 } while (count != 0); break; 00073 case R_OUTSW: 00074 add_index<<=1; 00075 do { 00076 IO_WriteW(reg_dx,LoadMw(si_base+si_index)); 00077 si_index=(si_index+(Bitu)add_index) & add_mask; 00078 count--; 00079 00080 if ((--CPU_Cycles) <= 0) break; 00081 } while (count != 0); break; 00082 case R_OUTSD: 00083 add_index<<=2; 00084 do { 00085 IO_WriteD(reg_dx,LoadMd(si_base+si_index)); 00086 si_index=(si_index+(Bitu)add_index) & add_mask; 00087 count--; 00088 00089 if ((--CPU_Cycles) <= 0) break; 00090 } while (count != 0); break; 00091 00092 case R_INSB: 00093 do { 00094 SaveMb(di_base+di_index,IO_ReadB(reg_dx)); 00095 di_index=(di_index+(Bitu)add_index) & add_mask; 00096 count--; 00097 00098 if ((--CPU_Cycles) <= 0) break; 00099 } while (count != 0); break; 00100 case R_INSW: 00101 add_index<<=1; 00102 do { 00103 SaveMw(di_base+di_index,IO_ReadW(reg_dx)); 00104 di_index=(di_index+(Bitu)add_index) & add_mask; 00105 count--; 00106 00107 if ((--CPU_Cycles) <= 0) break; 00108 } while (count != 0); break; 00109 case R_INSD: 00110 add_index<<=2; 00111 do { 00112 SaveMd(di_base+di_index,IO_ReadD(reg_dx)); 00113 di_index=(di_index+(Bitu)add_index) & add_mask; 00114 count--; 00115 00116 if ((--CPU_Cycles) <= 0) break; 00117 } while (count != 0); break; 00118 00119 case R_STOSB: 00120 do { 00121 SaveMb(di_base+di_index,reg_al); 00122 di_index=(di_index+(Bitu)add_index) & add_mask; 00123 count--; 00124 00125 if ((--CPU_Cycles) <= 0) break; 00126 } while (count != 0); break; 00127 case R_STOSW: 00128 add_index<<=1; 00129 do { 00130 SaveMw(di_base+di_index,reg_ax); 00131 di_index=(di_index+(Bitu)add_index) & add_mask; 00132 count--; 00133 00134 if ((--CPU_Cycles) <= 0) break; 00135 } while (count != 0); break; 00136 case R_STOSD: 00137 add_index<<=2; 00138 do { 00139 SaveMd(di_base+di_index,reg_eax); 00140 di_index=(di_index+(Bitu)add_index) & add_mask; 00141 count--; 00142 00143 if ((--CPU_Cycles) <= 0) break; 00144 } while (count != 0); break; 00145 00146 case R_MOVSB: 00147 do { 00148 SaveMb(di_base+di_index,LoadMb(si_base+si_index)); 00149 di_index=(di_index+(Bitu)add_index) & add_mask; 00150 si_index=(si_index+(Bitu)add_index) & add_mask; 00151 count--; 00152 00153 if ((--CPU_Cycles) <= 0) break; 00154 } while (count != 0); break; 00155 case R_MOVSW: 00156 add_index<<=1; 00157 do { 00158 SaveMw(di_base+di_index,LoadMw(si_base+si_index)); 00159 di_index=(di_index+(Bitu)add_index) & add_mask; 00160 si_index=(si_index+(Bitu)add_index) & add_mask; 00161 count--; 00162 00163 if ((--CPU_Cycles) <= 0) break; 00164 } while (count != 0); break; 00165 case R_MOVSD: 00166 add_index<<=2; 00167 do { 00168 SaveMd(di_base+di_index,LoadMd(si_base+si_index)); 00169 di_index=(di_index+(Bitu)add_index) & add_mask; 00170 si_index=(si_index+(Bitu)add_index) & add_mask; 00171 count--; 00172 00173 if ((--CPU_Cycles) <= 0) break; 00174 } while (count != 0); break; 00175 00176 case R_LODSB: 00177 do { 00178 reg_al=LoadMb(si_base+si_index); 00179 si_index=(si_index+(Bitu)add_index) & add_mask; 00180 count--; 00181 00182 if ((--CPU_Cycles) <= 0) break; 00183 } while (count != 0); break; 00184 case R_LODSW: 00185 add_index<<=1; 00186 do { 00187 reg_ax=LoadMw(si_base+si_index); 00188 si_index=(si_index+(Bitu)add_index) & add_mask; 00189 count--; 00190 00191 if ((--CPU_Cycles) <= 0) break; 00192 } while (count != 0); break; 00193 case R_LODSD: 00194 add_index<<=2; 00195 do { 00196 reg_eax=LoadMd(si_base+si_index); 00197 si_index=(si_index+(Bitu)add_index) & add_mask; 00198 count--; 00199 00200 if ((--CPU_Cycles) <= 0) break; 00201 } while (count != 0); break; 00202 00203 case R_SCASB: 00204 { 00205 Bit8u val2; 00206 do { 00207 val2=LoadMb(di_base+di_index); 00208 di_index=(di_index+(Bitu)add_index) & add_mask; 00209 count--; 00210 00211 if ((--CPU_Cycles) <= 0) break; 00212 if ((reg_al==val2)!=inst.repz) break; 00213 } while (count != 0); 00214 CMPB(reg_al,val2,LoadD,0); 00215 } 00216 break; 00217 case R_SCASW: 00218 add_index<<=1; 00219 { 00220 Bit16u val2; 00221 do { 00222 val2=LoadMw(di_base+di_index); 00223 di_index=(di_index+(Bitu)add_index) & add_mask; 00224 count--; 00225 00226 if ((--CPU_Cycles) <= 0) break; 00227 if ((reg_ax==val2)!=inst.repz) break; 00228 } while (count != 0); 00229 CMPW(reg_ax,val2,LoadD,0); 00230 } 00231 break; 00232 case R_SCASD: 00233 add_index<<=2; 00234 { 00235 Bit32u val2; 00236 do { 00237 val2=LoadMd(di_base+di_index); 00238 di_index=(di_index+(Bitu)add_index) & add_mask; 00239 count--; 00240 00241 if ((--CPU_Cycles) <= 0) break; 00242 if ((reg_eax==val2)!=inst.repz) break; 00243 } while (count != 0); 00244 CMPD(reg_eax,val2,LoadD,0); 00245 } 00246 break; 00247 00248 case R_CMPSB: 00249 { 00250 Bit8u val1,val2; 00251 do { 00252 val1=LoadMb(si_base+si_index); 00253 val2=LoadMb(di_base+di_index); 00254 si_index=(si_index+(Bitu)add_index) & add_mask; 00255 di_index=(di_index+(Bitu)add_index) & add_mask; 00256 count--; 00257 00258 if ((--CPU_Cycles) <= 0) break; 00259 if ((val1==val2)!=inst.repz) break; 00260 } while (count != 0); 00261 CMPB(val1,val2,LoadD,0); 00262 } 00263 break; 00264 case R_CMPSW: 00265 add_index<<=1; 00266 { 00267 Bit16u val1,val2; 00268 do { 00269 val1=LoadMw(si_base+si_index); 00270 val2=LoadMw(di_base+di_index); 00271 si_index=(si_index+(Bitu)add_index) & add_mask; 00272 di_index=(di_index+(Bitu)add_index) & add_mask; 00273 count--; 00274 00275 if ((--CPU_Cycles) <= 0) break; 00276 if ((val1==val2)!=inst.repz) break; 00277 } while (count != 0); 00278 CMPW(val1,val2,LoadD,0); 00279 } 00280 break; 00281 case R_CMPSD: 00282 add_index<<=2; 00283 { 00284 Bit32u val1,val2; 00285 do { 00286 val1=LoadMd(si_base+si_index); 00287 val2=LoadMd(di_base+di_index); 00288 si_index=(si_index+(Bitu)add_index) & add_mask; 00289 di_index=(di_index+(Bitu)add_index) & add_mask; 00290 count--; 00291 00292 if ((--CPU_Cycles) <= 0) break; 00293 if ((val1==val2)!=inst.repz) break; 00294 } while (count != 0); 00295 CMPD(val1,val2,LoadD,0); 00296 } 00297 break; 00298 00299 default: 00300 LOG(LOG_CPU,LOG_ERROR)("Unhandled string op %d",inst.code.op); 00301 } 00302 00303 /* Clean up after certain amount of instructions */ 00304 reg_esi&=(~add_mask); 00305 reg_esi|=(si_index & add_mask); 00306 reg_edi&=(~add_mask); 00307 reg_edi|=(di_index & add_mask); 00308 if (inst.prefix & PREFIX_REP) { 00309 count+=count_left; 00310 reg_ecx&=(~add_mask); 00311 reg_ecx|=(count & add_mask); 00312 00313 /* if the count is still nonzero, then there is still work to do and the 00314 * instruction has not finished executing---it needs to be restarted. 00315 * if the string op was REP CMPSB or REP SCASB then it also matters 00316 * whether the ZF flag matches the REP condition on whether or not we 00317 * restart the instruction. */ 00318 if (count != 0) { 00319 if (inst.code.op < R_SCASB) { 00320 /* if count != 0 then restart the instruction */ 00321 LoadIP(); 00322 } 00323 else { 00324 /* if ZF matches the REP condition, restart the instruction */ 00325 if ((get_ZF()?1:0) == (inst.repz?1:0)) { 00326 LoadIP(); 00327 } 00328 } 00329 } 00330 } 00331 } 00332 catch (GuestPageFaultException &pf) { 00333 (void)pf; 00334 /* Clean up after certain amount of instructions */ 00335 reg_esi&=(~add_mask); 00336 reg_esi|=(si_index & add_mask); 00337 reg_edi&=(~add_mask); 00338 reg_edi|=(di_index & add_mask); 00339 if (inst.prefix & PREFIX_REP) { 00340 count+=count_left; 00341 reg_ecx&=(~add_mask); 00342 reg_ecx|=(count & add_mask); 00343 } 00344 00345 /* rethrow the exception. 00346 * NOTE: this means the normal core has no chance to execute SAVEIP, therefore 00347 * when the guest OS has finished handling the page fault the instruction 00348 * pointer will come right back to the string op that caused the fault 00349 * and the string op will restart where it left off. */ 00350 throw; 00351 } 00352 } 00353 } 00354