DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/cpu/core_full/string.h
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