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