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 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