DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/cpu/core_full/load.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 switch (inst.code.load) {
00020 /* General loading */
00021         case L_POPwRM:
00022                 inst_op1_w = Pop_16();
00023                 goto case_L_MODRM;
00024         case L_POPdRM:
00025                 inst_op1_d = Pop_32();
00026                 goto case_L_MODRM;
00027         case L_MODRM_NVM:
00028                 if ((reg_flags & FLAG_VM) || !cpu.pmode) goto illegalopcode;
00029                 goto case_L_MODRM;
00030 case_L_MODRM:
00031         case L_MODRM:
00032                 inst.rm=Fetchb();
00033                 inst.rm_index=(inst.rm >> 3) & 7;
00034                 inst.rm_eai=inst.rm&07;
00035                 inst.rm_mod=inst.rm>>6;
00036                 /* Decode address of mod/rm if needed */
00037                 if (inst.rm<0xc0) {
00038                         if (!(inst.prefix & PREFIX_ADDR))
00039                         #include "ea_lookup.h"
00040                 }
00041 l_MODRMswitch:
00042                 switch (inst.code.extra) {      
00043 /* Byte */
00044                 case M_Ib:
00045                         inst_op1_d=Fetchb();
00046                         break;
00047                 case M_Ebx:
00048                         if (inst.rm<0xc0) inst_op1_ds=(Bit8s)LoadMb(inst.rm_eaa);
00049                         else inst_op1_ds=(Bit8s)reg_8(inst.rm_eai);
00050                         break;
00051                 case M_EbIb:
00052                         inst_op2_d=Fetchb();
00053                 case M_Eb:
00054                         if (inst.rm<0xc0) inst_op1_d=LoadMb(inst.rm_eaa);
00055                         else inst_op1_d=reg_8(inst.rm_eai);
00056                         break;
00057                 case M_EbGb:
00058                         if (inst.rm<0xc0) inst_op1_d=LoadMb(inst.rm_eaa);
00059                         else inst_op1_d=reg_8(inst.rm_eai);
00060                         inst_op2_d=reg_8(inst.rm_index);
00061                         break;
00062                 case M_GbEb:
00063                         if (inst.rm<0xc0) inst_op2_d=LoadMb(inst.rm_eaa);
00064                         else inst_op2_d=reg_8(inst.rm_eai);
00065                 case M_Gb:
00066                         inst_op1_d=reg_8(inst.rm_index);;
00067                         break;
00068 /* Word */
00069                 case M_Iw:
00070                         inst_op1_d=Fetchw();
00071                         break;
00072                 case M_EwxGwx:
00073                         inst_op2_ds=(Bit16s)reg_16(inst.rm_index);
00074                         goto l_M_Ewx;
00075                 case M_EwxIbx:
00076                         inst_op2_ds=Fetchbs();
00077                         goto l_M_Ewx;
00078                 case M_EwxIwx:
00079                         inst_op2_ds=Fetchws();
00080 l_M_Ewx:                
00081                 case M_Ewx:
00082                         if (inst.rm<0xc0) inst_op1_ds=(Bit16s)LoadMw(inst.rm_eaa);
00083                         else inst_op1_ds=(Bit16s)reg_16(inst.rm_eai);
00084                         break;
00085                 case M_EwIb:
00086                         inst_op2_d=Fetchb();
00087                         goto l_M_Ew;
00088                 case M_EwIbx:
00089                         inst_op2_ds=Fetchbs();
00090                         goto l_M_Ew;            
00091                 case M_EwIw:
00092                         inst_op2_d=Fetchw();
00093                         goto l_M_Ew;
00094                 case M_EwGwCL:
00095                         inst_imm_d=reg_cl;
00096                         goto l_M_EwGw;
00097                 case M_EwGwIb:
00098                         inst_imm_d=Fetchb();
00099                         goto l_M_EwGw;
00100                 case M_EwGwt:
00101                         inst_op2_d=reg_16(inst.rm_index);
00102                         inst.rm_eaa+=(Bitu)(((Bit16s)inst_op2_d >> 4) * 2);
00103                         goto l_M_Ew;
00104 l_M_EwGw:                       
00105                 case M_EwGw:
00106                         inst_op2_d=reg_16(inst.rm_index);
00107 l_M_Ew:
00108                 case M_Ew:
00109                         if (inst.rm<0xc0) inst_op1_d=LoadMw(inst.rm_eaa);
00110                         else inst_op1_d=reg_16(inst.rm_eai);
00111                         break;
00112                 case M_GwEw:
00113                         if (inst.rm<0xc0) inst_op2_d=LoadMw(inst.rm_eaa);
00114                         else inst_op2_d=reg_16(inst.rm_eai);
00115                 case M_Gw:
00116                         inst_op1_d=reg_16(inst.rm_index);;
00117                         break;
00118 /* DWord */
00119                 case M_Id:
00120                         inst_op1_d=Fetchd();
00121                         break;
00122                 case M_EdxGdx:
00123                         inst_op2_ds=(Bit32s)reg_32(inst.rm_index);
00124                 case M_Edx:
00125                         if (inst.rm<0xc0) inst_op1_d=(Bit32u)((Bit32s)LoadMd(inst.rm_eaa));
00126                         else inst_op1_d=(Bit32u)((Bit32s)reg_32(inst.rm_eai));
00127                         break;
00128                 case M_EdIb:
00129                         inst_op2_d=Fetchb();
00130                         goto l_M_Ed;
00131                 case M_EdIbx:
00132                         inst_op2_ds=Fetchbs();
00133                         goto l_M_Ed;
00134                 case M_EdId:
00135                         inst_op2_d=Fetchd();
00136                         goto l_M_Ed;                    
00137                 case M_EdGdCL:
00138                         inst_imm_d=reg_cl;
00139                         goto l_M_EdGd;
00140                 case M_EdGdt:
00141                         inst_op2_d=reg_32(inst.rm_index);
00142                         inst.rm_eaa+=(Bit32u)(((Bit32s)inst_op2_d >> 5) * 4);
00143                         goto l_M_Ed;
00144                 case M_EdGdIb:
00145                         inst_imm_d=Fetchb();
00146                         goto l_M_EdGd;
00147 l_M_EdGd:
00148                 case M_EdGd:
00149                         inst_op2_d=reg_32(inst.rm_index);
00150 l_M_Ed:
00151                 case M_Ed:
00152                         if (inst.rm<0xc0) inst_op1_d=LoadMd(inst.rm_eaa);
00153                         else inst_op1_d=reg_32(inst.rm_eai);
00154                         break;
00155                 case M_GdEd:
00156                         if (inst.rm<0xc0) inst_op2_d=LoadMd(inst.rm_eaa);
00157                         else inst_op2_d=reg_32(inst.rm_eai);
00158                 case M_Gd:
00159                         inst_op1_d=reg_32(inst.rm_index);
00160                         break;
00161 /* Others */            
00162 
00163                 case M_SEG:
00164                         //TODO Check for limit
00165                         inst_op1_d=SegValue((SegNames)inst.rm_index);
00166                         break;
00167                 case M_Efw:
00168                         if (inst.rm>=0xc0) goto illegalopcode;
00169                         inst_op1_d=LoadMw(inst.rm_eaa);
00170                         inst_op2_d=LoadMw(inst.rm_eaa+2);
00171                         break;
00172                 case M_Efd:
00173                         if (inst.rm>=0xc0) goto illegalopcode;
00174                         inst_op1_d=LoadMd(inst.rm_eaa);
00175                         inst_op2_d=LoadMw(inst.rm_eaa+4);
00176                         break;
00177                 case M_EA:
00178                         inst_op1_d=inst.rm_off;
00179                         break;
00180                 case M_POPw:
00181                         inst_op1_d = Pop_16();
00182                         break;
00183                 case M_POPd:
00184                         inst_op1_d = Pop_32();
00185                         break;
00186                 case M_GRP:
00187                         inst.code=Groups[inst.code.op][inst.rm_index];
00188                         goto l_MODRMswitch;
00189                 case M_SHIFT_Ib:
00190                         inst_op2_d = Fetchb() & 0x1f;
00191                         if (!inst_op2_d)
00192                                 break;
00193                         inst.code=Groups[inst.code.op][inst.rm_index];
00194                         goto l_MODRMswitch;
00195                 case M_SHIFT_CL:
00196                         inst_op2_d = reg_cl & 0x1f;
00197                         if (!inst_op2_d)
00198                                 break;
00199                         inst.code=Groups[inst.code.op][inst.rm_index];
00200                         goto l_MODRMswitch;
00201                 case M_SHIFT_1:
00202                         inst_op2_d=1;
00203                         inst.code=Groups[inst.code.op][inst.rm_index];
00204                         goto l_MODRMswitch;
00205                 case 0:
00206                         break;
00207                 default:
00208                         LOG(LOG_CPU,LOG_ERROR)("MODRM:Unhandled load %d entry %lx",inst.code.extra,(unsigned long)inst.entry);
00209                         break;
00210                 }
00211                 break;
00212         case L_POPw:
00213                 inst_op1_d = Pop_16();
00214                 break;
00215         case L_POPd:
00216                 inst_op1_d = Pop_32();
00217                 break;
00218         case L_POPfw:
00219                 inst_op1_d = Pop_16();
00220                 inst_op2_d = Pop_16();
00221                 break;
00222         case L_POPfd:
00223                 inst_op1_d = Pop_32();
00224                 inst_op2_d = Pop_16();
00225                 break;
00226         case L_Ib:
00227                 inst_op1_d=Fetchb();
00228                 break;
00229         case L_Ibx:
00230                 inst_op1_ds=Fetchbs();
00231                 break;
00232         case L_Iw:
00233                 inst_op1_d=Fetchw();
00234                 break;
00235         case L_Iwx:
00236                 inst_op1_ds=Fetchws();
00237                 break;
00238         case L_Idx:
00239         case L_Id:
00240                 inst_op1_d=Fetchd();
00241                 break;
00242         case L_Ifw:
00243                 inst_op1_d=Fetchw();
00244                 inst_op2_d=Fetchw();
00245                 break;
00246         case L_Ifd:
00247                 inst_op1_d=Fetchd();
00248                 inst_op2_d=Fetchw();
00249                 break;
00250 /* Direct load of registers */
00251         case L_REGbIb:
00252                 inst_op2_d=Fetchb();
00253         case L_REGb:
00254                 inst_op1_d=reg_8(inst.code.extra);
00255                 break;
00256         case L_REGwIw:
00257                 inst_op2_d=Fetchw();
00258         case L_REGw:
00259                 inst_op1_d=reg_16(inst.code.extra);
00260                 break;
00261         case L_REGdId:
00262                 inst_op2_d=Fetchd();
00263         case L_REGd:
00264                 inst_op1_d=reg_32(inst.code.extra);
00265                 break;
00266         case L_SEG:
00267                 inst_op1_d=SegValue((SegNames)inst.code.extra);
00268                 break;
00269 /* Depending on addressize */
00270         case L_OP:
00271                 if (inst.prefix & PREFIX_ADDR) {
00272                         inst.rm_eaa=Fetchd();
00273                 } else {
00274                         inst.rm_eaa=Fetchw();
00275                 }
00276                 if (inst.prefix & PREFIX_SEG) {
00277                         inst.rm_eaa+=inst.seg.base;
00278                 } else {
00279                         inst.rm_eaa+=SegBase(ds);
00280                 }
00281                 break;
00282         /* Special cases */
00283         case L_DOUBLE:
00284                 inst.entry|=0x100;
00285                 goto restartopcode;
00286         case L_PRESEG:
00287                 inst.prefix|=PREFIX_SEG;
00288                 inst.seg.base=SegBase((SegNames)inst.code.extra);
00289                 goto restartopcode;
00290         case L_PREREPNE:
00291                 inst.prefix|=PREFIX_REP;
00292                 inst.repz=false;
00293                 goto restartopcode;
00294         case L_PREREP:
00295                 inst.prefix|=PREFIX_REP;
00296                 inst.repz=true;
00297                 goto restartopcode;
00298         case L_PREOP:
00299                 inst.entry=(cpu.code.big ^ 1u) * 0x200u;
00300                 goto restartopcode;
00301         case L_PREADD:
00302                 inst.prefix=(inst.prefix & ~1u) | (cpu.code.big ^ 1u);
00303                 goto restartopcode;
00304         case L_VAL:
00305                 inst_op1_d=inst.code.extra;
00306                 break;
00307         case L_INTO:
00308                 if (!get_OF()) goto nextopcode;
00309                 inst_op1_d=4;
00310                 break;
00311         case D_IRETw:
00312                 CPU_IRET(false,GetIP());
00313                 if (GETFLAG(IF) && PIC_IRQCheck) {
00314                         return CBRET_NONE;
00315                 }
00316                 continue;
00317         case D_IRETd:
00318                 CPU_IRET(true,GetIP());
00319                 if (GETFLAG(IF) && PIC_IRQCheck) 
00320                         return CBRET_NONE;
00321                 continue;
00322         case D_RETFwIw:
00323                 {
00324                         Bitu words=Fetchw();
00325                         FillFlags();    
00326                         CPU_RET(false,words,GetIP());
00327                         continue;
00328                 }
00329         case D_RETFw:
00330                 FillFlags();
00331                 CPU_RET(false,0,GetIP());
00332                 continue;
00333         case D_RETFdIw:
00334                 {
00335                         Bitu words=Fetchw();
00336                         FillFlags();    
00337                         CPU_RET(true,words,GetIP());
00338                         continue;
00339                 }
00340         case D_RETFd:
00341                 FillFlags();
00342                 CPU_RET(true,0,GetIP());
00343                 continue;
00344 /* Direct operations */
00345         case L_STRING:
00346                 #include "string.h"
00347                 goto nextopcode;
00348         case D_PUSHAw:
00349                 if (CPU_ArchitectureType<CPU_ARCHTYPE_80186) goto illegalopcode;
00350                 {
00351                         try {
00352                                 Bit16u old_sp = (CPU_ArchitectureType >= CPU_ARCHTYPE_286 ? reg_sp : (reg_sp-10));
00353                                 Push_16(reg_ax);Push_16(reg_cx);Push_16(reg_dx);Push_16(reg_bx);
00354                                 Push_16(old_sp);Push_16(reg_bp);Push_16(reg_si);Push_16(reg_di);
00355                         }
00356                         catch (GuestPageFaultException &pf) {
00357                                 (void)pf;
00358                                 LOG_MSG("PUSHA interrupted by page fault");
00359                                 reg_esp = old_esp;
00360                                 throw;
00361                         }
00362                 } goto nextopcode;
00363         case D_PUSHAd:
00364                 {
00365                         try {
00366                                 Bit32u tmpesp = reg_esp;
00367                                 Push_32(reg_eax);Push_32(reg_ecx);Push_32(reg_edx);Push_32(reg_ebx);
00368                                 Push_32(tmpesp);Push_32(reg_ebp);Push_32(reg_esi);Push_32(reg_edi);
00369                         }
00370                         catch (GuestPageFaultException &pf) {
00371                                 (void)pf;
00372                                 LOG_MSG("PUSHAD interrupted by page fault");
00373                                 reg_esp = old_esp;
00374                                 throw;
00375                         }
00376                 } goto nextopcode;
00377         case D_POPAw:
00378                 if (CPU_ArchitectureType<CPU_ARCHTYPE_80186) goto illegalopcode;
00379                 {
00380                         try {
00381                                 reg_di=Pop_16();reg_si=Pop_16();reg_bp=Pop_16();Pop_16();//Don't save SP
00382                                 reg_bx=Pop_16();reg_dx=Pop_16();reg_cx=Pop_16();reg_ax=Pop_16();
00383                         }
00384                         catch (GuestPageFaultException &pf) {
00385                                 (void)pf;
00386                                 LOG_MSG("POPA interrupted by page fault");
00387                                 reg_esp = old_esp;
00388                                 throw;
00389                         }
00390                 } goto nextopcode;
00391         case D_POPAd:
00392                 {
00393                         try {
00394                                 reg_edi=Pop_32();reg_esi=Pop_32();reg_ebp=Pop_32();Pop_32();//Don't save ESP
00395                                 reg_ebx=Pop_32();reg_edx=Pop_32();reg_ecx=Pop_32();reg_eax=Pop_32();
00396                         }
00397                         catch (GuestPageFaultException &pf) {
00398                                 (void)pf;
00399                                 LOG_MSG("POPAD interrupted by page fault");
00400                                 reg_esp = old_esp;
00401                                 throw;
00402                         }
00403                 } goto nextopcode;
00404         case D_POPSEGw:
00405                 if (CPU_PopSeg((SegNames)inst.code.extra,false)) RunException();
00406                 goto nextopcode;
00407         case D_POPSEGd:
00408                 if (CPU_PopSeg((SegNames)inst.code.extra,true)) RunException();
00409                 goto nextopcode;
00410         case D_SETALC:
00411                 reg_al = get_CF() ? 0xFF : 0;
00412                 goto nextopcode;
00413         case D_XLAT:
00414                 if (inst.prefix & PREFIX_SEG) {
00415                         if (inst.prefix & PREFIX_ADDR) {
00416                                 reg_al=LoadMb(inst.seg.base+(Bit32u)(reg_ebx+reg_al));
00417                         } else {
00418                                 reg_al=LoadMb(inst.seg.base+(Bit16u)(reg_bx+reg_al));
00419                         }
00420                 } else {
00421                         if (inst.prefix & PREFIX_ADDR) {
00422                                 reg_al=LoadMb(SegBase(ds)+(Bit32u)(reg_ebx+reg_al));
00423                         } else {
00424                                 reg_al=LoadMb(SegBase(ds)+(Bit16u)(reg_bx+reg_al));
00425                         }
00426                 }
00427                 goto nextopcode;
00428         case D_CBW:
00429                 reg_ax=(Bit16u)((Bit8s)reg_al);
00430                 goto nextopcode;
00431         case D_CWDE:
00432                 reg_eax=(Bit32u)((Bit16s)reg_ax);
00433                 goto nextopcode;
00434         case D_CWD:
00435                 if (reg_ax & 0x8000) reg_dx=0xffff;
00436                 else reg_dx=0;
00437                 goto nextopcode;
00438         case D_CDQ:
00439                 if (reg_eax & 0x80000000) reg_edx=0xffffffff;
00440                 else reg_edx=0;
00441                 goto nextopcode;
00442         case D_CLI:
00443                 if (CPU_CLI()) RunException();
00444                 goto nextopcode;
00445         case D_STI:
00446                 if (CPU_STI()) RunException();
00447                 goto nextopcode;
00448         case D_STC:
00449                 FillFlags();SETFLAGBIT(CF,true);
00450                 goto nextopcode;
00451         case D_CLC:
00452                 FillFlags();SETFLAGBIT(CF,false);
00453                 goto nextopcode;
00454         case D_CMC:
00455                 FillFlags();
00456                 SETFLAGBIT(CF,!(reg_flags & FLAG_CF));
00457                 goto nextopcode;
00458         case D_CLD:
00459                 SETFLAGBIT(DF,false);
00460                 cpu.direction=1;
00461                 goto nextopcode;
00462         case D_STD:
00463                 SETFLAGBIT(DF,true);
00464                 cpu.direction=-1;
00465                 goto nextopcode;
00466         case D_PUSHF:
00467                 if (CPU_PUSHF(inst.code.extra)) RunException();
00468                 goto nextopcode;
00469         case D_POPF:
00470                 if (CPU_POPF(inst.code.extra)) RunException();
00471                 if (GETFLAG(IF) && PIC_IRQCheck) {
00472                         SaveIP();
00473                         return CBRET_NONE;
00474                 }
00475                 goto nextopcode;
00476         case D_SAHF:
00477                 SETFLAGSb(reg_ah);
00478                 goto nextopcode;
00479         case D_LAHF:
00480                 FillFlags();
00481                 reg_ah=reg_flags&0xff;
00482                 goto nextopcode;
00483         case D_WAIT:
00484         case D_NOP:
00485                 goto nextopcode;
00486         case D_LOCK: /* FIXME: according to intel, LOCK should raise an exception if it's not followed by one of a small set of instructions;
00487                         probably doesn't matter for our purposes as it is a pentium prefix anyhow */
00488 // todo: make an option to show this
00489 //              LOG(LOG_CPU,LOG_NORMAL)("CPU:LOCK");
00490                 goto nextopcode;
00491         case D_ENTERw:
00492                 {
00493                         Bitu bytes=Fetchw();
00494                         Bitu level=Fetchb();
00495                         CPU_ENTER(false,bytes,level);
00496                         goto nextopcode;
00497                 }
00498         case D_ENTERd:
00499                 {
00500                         Bitu bytes=Fetchw();
00501                         Bitu level=Fetchb();
00502                         CPU_ENTER(true,bytes,level);
00503                         goto nextopcode;
00504                 }
00505         case D_LEAVEw:
00506                 {
00507                         reg_esp &= cpu.stack.notmask;
00508                         reg_esp |= reg_ebp&cpu.stack.mask;
00509                         try {
00510                                 reg_bp = Pop_16();
00511                         }
00512                         catch (GuestPageFaultException &pf) {
00513                                 (void)pf;
00514                                 reg_esp = old_esp;
00515                                 throw;
00516                         }
00517                 } goto nextopcode;
00518         case D_LEAVEd:
00519                 {
00520                         reg_esp &= cpu.stack.notmask;
00521                         reg_esp |= reg_ebp&cpu.stack.mask;
00522                         try {
00523                                 reg_ebp = Pop_32();
00524                         }
00525                         catch (GuestPageFaultException &pf) {
00526                                 (void)pf;
00527                                 reg_esp = old_esp;
00528                                 throw;
00529                         }
00530                 } goto nextopcode;
00531         case D_DAA:
00532                 DAA();
00533                 goto nextopcode;
00534         case D_DAS:
00535                 DAS();
00536                 goto nextopcode;
00537         case D_AAA:
00538                 AAA();
00539                 goto nextopcode;
00540         case D_AAS:
00541                 AAS();
00542                 goto nextopcode;
00543         case D_CPUID:
00544                 if (!CPU_CPUID()) goto illegalopcode;
00545                 goto nextopcode;
00546         case D_HLT:
00547                 if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
00548                 FillFlags();
00549                 CPU_HLT(GetIP());
00550                 return CBRET_NONE;
00551         case D_CLTS:
00552                 if (cpu.pmode && cpu.cpl) goto illegalopcode;
00553                 cpu.cr0&=(~CR0_TASKSWITCH);
00554                 goto nextopcode;
00555         case D_ICEBP:
00556                 CPU_SW_Interrupt_NoIOPLCheck(1,GetIP());
00557                 continue;
00558         case D_RDTSC: {
00559                 if (CPU_ArchitectureType<CPU_ARCHTYPE_PENTIUM) goto illegalopcode;
00560                 Bit64s tsc=(Bit64s)(PIC_FullIndex()*(double)(CPU_CycleAutoAdjust?70000:CPU_CycleMax));
00561                 reg_edx=(Bit32u)(tsc>>32);
00562                 reg_eax=(Bit32u)(tsc&0xffffffff);
00563                 break;
00564                 }
00565         default:
00566                 LOG(LOG_CPU,LOG_ERROR)("LOAD:Unhandled code %d opcode %lx",inst.code.load,(unsigned long)inst.entry);
00567                 goto illegalopcode;
00568 }
00569