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 #include <stdio.h> 00020 00021 #include "dosbox.h" 00022 #include "mem.h" 00023 #include "cpu.h" 00024 #include "lazyflags.h" 00025 #include "inout.h" 00026 #include "callback.h" 00027 #include "pic.h" 00028 #include "fpu.h" 00029 #include "paging.h" 00030 #include "mmx.h" 00031 00032 #define CPU_CORE CPU_ARCHTYPE_8086 00033 #define CPU_Core_Normal_Trap_Run CPU_Core8086_Normal_Trap_Run 00034 00035 #define DoString DoString_Normal8086 00036 00037 extern bool ignore_opcode_63; 00038 00039 #if C_DEBUG 00040 extern bool mustCompleteInstruction; 00041 # include "debug.h" 00042 #else 00043 # define mustCompleteInstruction (0) 00044 #endif 00045 00046 static Bit16u last_ea86_offset; 00047 00048 /* NTS: we special case writes to seg:ffff to emulate 8086 behavior where word read/write wraps around the 64KB segment */ 00049 #if (!C_CORE_INLINE) 00050 00051 #define LoadMb(off) mem_readb(off) 00052 00053 static inline Bit16u LoadMw(Bitu off) { 00054 if (last_ea86_offset == 0xffff) 00055 return (mem_readb(off) | (mem_readb(off-0xffff) << 8)); 00056 00057 return mem_readw(off); 00058 } 00059 00060 #define LoadMd(off) mem_readd(off) 00061 00062 #define SaveMb(off,val) mem_writeb(off,val) 00063 00064 static void SaveMw(Bitu off,Bitu val) { 00065 if (last_ea86_offset == 0xffff) { 00066 mem_writeb(off,val); 00067 mem_writeb(off-0xffff,val>>8); 00068 } 00069 else { 00070 mem_writew(off,val); 00071 } 00072 } 00073 00074 #define SaveMd(off,val) mem_writed(off,val) 00075 00076 #else 00077 00078 #include "paging.h" 00079 00080 #define LoadMb(off) mem_readb_inline(off) 00081 00082 static inline Bit16u LoadMw(Bitu off) { 00083 if (last_ea86_offset == 0xffff) 00084 return (mem_readb_inline((PhysPt)off) | (mem_readb_inline((PhysPt)(off-0xffff)) << 8)); 00085 00086 return mem_readw_inline((PhysPt)off); 00087 } 00088 00089 #define LoadMd(off) mem_readd_inline(off) 00090 00091 #define SaveMb(off,val) mem_writeb_inline(off,val) 00092 00093 static void SaveMw(Bitu off,Bitu val) { 00094 if (last_ea86_offset == 0xffff) { 00095 mem_writeb_inline((PhysPt)off,(Bit8u)val); 00096 mem_writeb_inline((PhysPt)(off-0xffff),(Bit8u)(val>>8)); 00097 } 00098 else { 00099 mem_writew_inline((PhysPt)off,(Bit16u)val); 00100 } 00101 } 00102 00103 #define SaveMd(off,val) mem_writed_inline(off,val) 00104 00105 #endif 00106 00107 extern Bitu cycle_count; 00108 00109 #if C_FPU 00110 #define CPU_FPU 1u //Enable FPU escape instructions 00111 #endif 00112 00113 #define CPU_PIC_CHECK 1u 00114 #define CPU_TRAP_CHECK 1u 00115 00116 #define OPCODE_NONE 0x000u 00117 #define OPCODE_0F 0x100u 00118 00119 #define OPCODE_SIZE 0u //DISABLED 00120 00121 #define PREFIX_ADDR 0u //DISABLED 00122 00123 #define PREFIX_REP 0x2u 00124 00125 #define TEST_PREFIX_ADDR (0u) //DISABLED 00126 #define TEST_PREFIX_REP (core.prefixes & PREFIX_REP) 00127 00128 #define DO_PREFIX_SEG(_SEG) \ 00129 if (GETFLAG(IF) && CPU_Cycles <= 0 && !mustCompleteInstruction) goto prefix_out; \ 00130 BaseDS=SegBase(_SEG); \ 00131 BaseSS=SegBase(_SEG); \ 00132 core.base_val_ds=_SEG; \ 00133 goto restart_opcode; 00134 00135 // it's the core's job not to decode 0x66-0x67 when compiled for 286 00136 #define DO_PREFIX_ADDR() \ 00137 abort(); 00138 00139 #define DO_PREFIX_REP(_ZERO) \ 00140 if (GETFLAG(IF) && CPU_Cycles <= 0 && !mustCompleteInstruction) goto prefix_out; \ 00141 core.prefixes|=PREFIX_REP; \ 00142 core.rep_zero=_ZERO; \ 00143 goto restart_opcode; 00144 00145 typedef PhysPt (*GetEAHandler)(void); 00146 00147 static const Bit32u AddrMaskTable[2]={0x0000ffffu,0x0000ffffu}; 00148 00149 static struct { 00150 Bitu opcode_index; 00151 PhysPt cseip; 00152 PhysPt base_ds,base_ss; 00153 SegNames base_val_ds; 00154 bool rep_zero; 00155 Bitu prefixes; 00156 GetEAHandler * ea_table; 00157 } core; 00158 00159 /* FIXME: Someone at Microsoft tell how subtracting PhysPt - PhysPt = __int64, or PhysPt + PhysPt = __int64 */ 00160 #define GETIP ((PhysPt)(core.cseip-SegBase(cs))) 00161 #define SAVEIP reg_eip=GETIP; 00162 #define LOADIP core.cseip=((PhysPt)(SegBase(cs)+reg_eip)); 00163 00164 #define SAVEIP_PREFIX reg_eip=GETIP-1; 00165 00166 #define SegBase(c) SegPhys(c) 00167 #define BaseDS core.base_ds 00168 #define BaseSS core.base_ss 00169 00170 static INLINE void FetchDiscardb() { 00171 core.cseip+=1; 00172 } 00173 00174 static INLINE Bit8u FetchPeekb() { 00175 Bit8u temp=LoadMb(core.cseip); 00176 return temp; 00177 } 00178 00179 static INLINE Bit8u Fetchb() { 00180 Bit8u temp=LoadMb(core.cseip); 00181 core.cseip+=1; 00182 return temp; 00183 } 00184 00185 static INLINE Bit16u Fetchw() { 00186 Bit16u temp=LoadMw(core.cseip); 00187 core.cseip+=2; 00188 return temp; 00189 } 00190 00191 static INLINE Bit32u Fetchd() { 00192 Bit32u temp=LoadMd(core.cseip); 00193 core.cseip+=4; 00194 return temp; 00195 } 00196 00197 #define Push_16 CPU_Push16 00198 #define Pop_16 CPU_Pop16 00199 00200 #include "instructions.h" 00201 #include "core_normal/support.h" 00202 #include "core_normal/string.h" 00203 00204 00205 #define EALookupTable (core.ea_table) 00206 00207 Bits CPU_Core8086_Normal_Run(void) { 00208 if (CPU_Cycles <= 0) 00209 return CBRET_NONE; 00210 00211 while (CPU_Cycles-->0) { 00212 LOADIP; 00213 core.prefixes=0; 00214 core.opcode_index=0; 00215 last_ea86_offset=0; 00216 core.ea_table=&EATable[0]; 00217 BaseDS=SegBase(ds); 00218 BaseSS=SegBase(ss); 00219 core.base_val_ds=ds; 00220 #if C_DEBUG 00221 #if C_HEAVY_DEBUG 00222 if (DEBUG_HeavyIsBreakpoint()) { 00223 FillFlags(); 00224 return (Bits)debugCallback; 00225 } 00226 #endif 00227 #endif 00228 cycle_count++; 00229 restart_opcode: 00230 switch (core.opcode_index+Fetchb()) { 00231 #include "core_normal/prefix_none.h" 00232 default: 00233 illegal_opcode: 00234 #if C_DEBUG 00235 { 00236 bool ignore=false; 00237 Bitu len=(GETIP-reg_eip); 00238 LOADIP; 00239 if (len>16) len=16; 00240 char tempcode[16*2+1];char * writecode=tempcode; 00241 if (ignore_opcode_63 && mem_readb(core.cseip) == 0x63) 00242 ignore = true; 00243 for (;len>0;len--) { 00244 sprintf(writecode,"%02X",mem_readb(core.cseip++)); 00245 writecode+=2; 00246 } 00247 if (!ignore) 00248 LOG(LOG_CPU,LOG_NORMAL)("Illegal/Unhandled opcode %s",tempcode); 00249 } 00250 #endif 00251 /* there is no invalid opcode instruction. */ 00252 reg_eip += 2; 00253 continue; 00254 } 00255 SAVEIP; 00256 } 00257 FillFlags(); 00258 return CBRET_NONE; 00259 /* 8086/286 multiple prefix interrupt bug emulation. 00260 * If an instruction is interrupted, only the last prefix is restarted. 00261 * See also [https://www.pcjs.org/pubs/pc/reference/intel/8086/] and [https://www.youtube.com/watch?v=6FC-tcwMBnU] */ 00262 prefix_out: 00263 SAVEIP_PREFIX; 00264 FillFlags(); 00265 return CBRET_NONE; 00266 decode_end: 00267 SAVEIP; 00268 FillFlags(); 00269 return CBRET_NONE; 00270 } 00271 00272 Bits CPU_Core8086_Normal_Trap_Run(void) { 00273 Bits oldCycles = CPU_Cycles; 00274 CPU_Cycles = 1; 00275 cpu.trap_skip = false; 00276 00277 Bits ret=CPU_Core8086_Normal_Run(); 00278 if (!cpu.trap_skip) CPU_HW_Interrupt(1); 00279 CPU_Cycles = oldCycles-1; 00280 cpudecoder = &CPU_Core8086_Normal_Run; 00281 00282 return ret; 00283 } 00284 00285 00286 00287 void CPU_Core8086_Normal_Init(void) { 00288 00289 } 00290