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 00020 #include <stdio.h> 00021 #include <string.h> 00022 00023 #include "dosbox.h" 00024 #include "mem.h" 00025 #include "cpu.h" 00026 #include "lazyflags.h" 00027 #include "inout.h" 00028 #include "callback.h" 00029 #include "pic.h" 00030 #include "fpu.h" 00031 #include "paging.h" 00032 #include "mmx.h" 00033 00034 using namespace std; 00035 00036 #include <algorithm> 00037 00038 #define CPU_CORE CPU_ARCHTYPE_8086 00039 #define CPU_Core_Prefetch_Trap_Run CPU_Core8086_Prefetch_Trap_Run 00040 00041 #define DoString DoString_Prefetch8086 00042 00043 extern bool ignore_opcode_63; 00044 00045 #if C_DEBUG 00046 #include "debug.h" 00047 #endif 00048 00049 static Bit16u last_ea86_offset; 00050 00051 /* NTS: we special case writes to seg:ffff to emulate 8086 behavior where word read/write wraps around the 64KB segment */ 00052 #if (!C_CORE_INLINE) 00053 00054 #define LoadMb(off) mem_readb(off) 00055 00056 static inline Bit16u LoadMw(Bitu off) { 00057 if (last_ea86_offset == 0xffff) 00058 return (mem_readb(off) | (mem_readb(off-0xffff) << 8)); 00059 00060 return mem_readw(off); 00061 } 00062 00063 #define LoadMd(off) mem_readd(off) 00064 00065 #define SaveMb(off,val) mem_writeb(off,val) 00066 00067 static void SaveMw(Bitu off,Bitu val) { 00068 if (last_ea86_offset == 0xffff) { 00069 mem_writeb(off,val); 00070 mem_writeb(off-0xffff,val>>8); 00071 } 00072 else { 00073 mem_writew(off,val); 00074 } 00075 } 00076 00077 #define SaveMd(off,val) mem_writed(off,val) 00078 00079 #else 00080 00081 #include "paging.h" 00082 00083 #define LoadMb(off) mem_readb_inline(off) 00084 00085 static inline Bit16u LoadMw(Bitu off) { 00086 if (last_ea86_offset == 0xffff) 00087 return (mem_readb_inline((PhysPt)off) | (mem_readb_inline((PhysPt)(off-0xffff)) << 8)); 00088 00089 return mem_readw_inline((PhysPt)off); 00090 } 00091 00092 #define LoadMd(off) mem_readd_inline(off) 00093 00094 #define SaveMb(off,val) mem_writeb_inline(off,val) 00095 00096 static void SaveMw(Bitu off,Bitu val) { 00097 if (last_ea86_offset == 0xffff) { 00098 mem_writeb_inline((PhysPt)off,(Bit8u)val); 00099 mem_writeb_inline((PhysPt)(off-0xffff),(Bit8u)(val>>8)); 00100 } 00101 else { 00102 mem_writew_inline((PhysPt)off,(Bit16u)val); 00103 } 00104 } 00105 00106 #define SaveMd(off,val) mem_writed_inline(off,val) 00107 00108 #endif 00109 00110 extern Bitu cycle_count; 00111 00112 #if C_FPU 00113 #define CPU_FPU 1u //Enable FPU escape instructions 00114 #endif 00115 00116 #define CPU_PIC_CHECK 1u 00117 #define CPU_TRAP_CHECK 1u 00118 00119 #define OPCODE_NONE 0x000u 00120 #define OPCODE_0F 0x100u 00121 00122 #define OPCODE_SIZE 0u //DISABLED 00123 00124 #define PREFIX_ADDR 0u //DISABLED 00125 00126 #define PREFIX_REP 0x2u 00127 00128 #define TEST_PREFIX_ADDR (0u) 00129 #define TEST_PREFIX_REP (core.prefixes & PREFIX_REP) 00130 00131 #define DO_PREFIX_SEG(_SEG) \ 00132 if (GETFLAG(IF) && CPU_Cycles <= 0) goto prefix_out; \ 00133 BaseDS=SegBase(_SEG); \ 00134 BaseSS=SegBase(_SEG); \ 00135 core.base_val_ds=_SEG; \ 00136 goto restart_opcode; 00137 00138 // it's the core's job not to decode 0x66-0x67 when compiled for 8086 00139 #define DO_PREFIX_ADDR() \ 00140 abort(); 00141 00142 #define DO_PREFIX_REP(_ZERO) \ 00143 if (GETFLAG(IF) && CPU_Cycles <= 0) goto prefix_out; \ 00144 core.prefixes|=PREFIX_REP; \ 00145 core.rep_zero=_ZERO; \ 00146 goto restart_opcode; 00147 00148 typedef PhysPt (*GetEAHandler)(void); 00149 00150 static const Bit32u AddrMaskTable[2]={0x0000ffffu,0x0000ffffu}; 00151 00152 static struct { 00153 Bitu opcode_index; 00154 PhysPt cseip; 00155 PhysPt base_ds,base_ss; 00156 SegNames base_val_ds; 00157 bool rep_zero; 00158 Bitu prefixes; 00159 GetEAHandler * ea_table; 00160 } core; 00161 00162 #define GETIP (core.cseip-SegBase(cs)) 00163 #define SAVEIP reg_eip=GETIP; 00164 #define LOADIP core.cseip=(SegBase(cs)+reg_eip); 00165 00166 #define SAVEIP_PREFIX reg_eip=GETIP-1; 00167 00168 #define SegBase(c) SegPhys(c) 00169 #define BaseDS core.base_ds 00170 #define BaseSS core.base_ss 00171 00172 //#define PREFETCH_DEBUG 00173 00174 #define MAX_PQ_SIZE 32 00175 static Bit8u prefetch_buffer[MAX_PQ_SIZE]; 00176 static bool pq_valid=false; 00177 static Bitu pq_start; 00178 static Bitu pq_fill; 00179 static Bitu pq_limit; 00180 static Bitu pq_reload; 00181 #ifdef PREFETCH_DEBUG 00182 static double pq_next_dbg=0; 00183 static unsigned int pq_hit=0,pq_miss=0; 00184 #endif 00185 00186 /* MUST BE POWER OF 2 */ 00187 #define prefetch_unit (2ul) 00188 00189 #include "core_prefetch_buf.h" 00190 00191 static INLINE void FetchDiscardb() { 00192 FetchDiscard<uint8_t>(); 00193 } 00194 00195 static INLINE Bit8u FetchPeekb() { 00196 return FetchPeek<uint8_t>(); 00197 } 00198 00199 static Bit8u Fetchb() { 00200 return Fetch<uint8_t>(); 00201 } 00202 00203 static Bit16u Fetchw() { 00204 return Fetch<uint16_t>(); 00205 } 00206 00207 static Bit32u Fetchd() { 00208 return Fetch<uint32_t>(); 00209 } 00210 00211 #define Push_16 CPU_Push16 00212 #define Pop_16 CPU_Pop16 00213 00214 #include "instructions.h" 00215 #include "core_normal/support.h" 00216 #include "core_normal/string.h" 00217 00218 00219 #define EALookupTable (core.ea_table) 00220 00221 void CPU_Core8086_Prefetch_reset(void) { 00222 pq_valid=false; 00223 prefetch_init(0); 00224 #ifdef PREFETCH_DEBUG 00225 pq_next_dbg=0; 00226 #endif 00227 } 00228 00229 Bits CPU_Core8086_Prefetch_Run(void) { 00230 bool invalidate_pq=false; 00231 00232 if (CPU_Cycles <= 0) 00233 return CBRET_NONE; 00234 00235 pq_limit = (max(CPU_PrefetchQueueSize,(unsigned int)(4ul + prefetch_unit)) + prefetch_unit - 1ul) & (~(prefetch_unit-1ul)); 00236 pq_reload = min(pq_limit,(Bitu)8u); 00237 00238 while (CPU_Cycles-->0) { 00239 if (invalidate_pq) { 00240 pq_valid=false; 00241 invalidate_pq=false; 00242 } 00243 LOADIP; 00244 core.prefixes=0; 00245 core.opcode_index=0; 00246 last_ea86_offset=0; 00247 core.ea_table=&EATable[0]; 00248 BaseDS=SegBase(ds); 00249 BaseSS=SegBase(ss); 00250 core.base_val_ds=ds; 00251 #if C_DEBUG 00252 #if C_HEAVY_DEBUG 00253 if (DEBUG_HeavyIsBreakpoint()) { 00254 FillFlags(); 00255 return (Bits)debugCallback; 00256 } 00257 #endif 00258 cycle_count++; 00259 #endif 00260 restart_opcode: 00261 Bit8u next_opcode=Fetchb(); 00262 invalidate_pq=false; 00263 if (core.opcode_index&OPCODE_0F) invalidate_pq=true; 00264 else switch (next_opcode) { 00265 case 0x70: case 0x71: case 0x72: case 0x73: 00266 case 0x74: case 0x75: case 0x76: case 0x77: 00267 case 0x78: case 0x79: case 0x7a: case 0x7b: 00268 case 0x7c: case 0x7d: case 0x7e: case 0x7f: // jcc 00269 case 0x9a: // call 00270 case 0xc2: case 0xc3: // retn 00271 case 0xc8: // enter 00272 case 0xc9: // leave 00273 case 0xca: case 0xcb: // retf 00274 case 0xcc: // int3 00275 case 0xcd: // int 00276 case 0xce: // into 00277 case 0xcf: // iret 00278 case 0xe0: // loopnz 00279 case 0xe1: // loopz 00280 case 0xe2: // loop 00281 case 0xe3: // jcxz 00282 case 0xe8: // call 00283 case 0xe9: case 0xea: case 0xeb: // jmp 00284 case 0xff: 00285 invalidate_pq=true; 00286 break; 00287 default: 00288 break; 00289 } 00290 switch (core.opcode_index+next_opcode) { 00291 #include "core_normal/prefix_none.h" 00292 default: 00293 illegal_opcode: 00294 #if C_DEBUG 00295 { 00296 bool ignore=false; 00297 Bitu len=(GETIP-reg_eip); 00298 LOADIP; 00299 if (len>16) len=16; 00300 char tempcode[16*2+1];char * writecode=tempcode; 00301 if (ignore_opcode_63 && mem_readb(core.cseip) == 0x63) 00302 ignore = true; 00303 for (;len>0;len--) { 00304 sprintf(writecode,"%02X",mem_readb(core.cseip++)); 00305 writecode+=2; 00306 } 00307 if (!ignore) 00308 LOG(LOG_CPU,LOG_NORMAL)("Illegal/Unhandled opcode %s",tempcode); 00309 } 00310 #endif 00311 /* there is no invalid opcode instruction. */ 00312 reg_eip += 2; 00313 continue; 00314 } 00315 SAVEIP; 00316 } 00317 00318 #ifdef PREFETCH_DEBUG 00319 if (PIC_FullIndex() > pq_next_dbg) { 00320 LOG_MSG("Prefetch core debug: prefetch cache hit=%u miss=%u",pq_hit,pq_miss); 00321 pq_next_dbg += 500.0; 00322 } 00323 #endif 00324 00325 FillFlags(); 00326 return CBRET_NONE; 00327 /* 8086/286 multiple prefix interrupt bug emulation. 00328 * If an instruction is interrupted, only the last prefix is restarted. 00329 * See also [https://www.pcjs.org/pubs/pc/reference/intel/8086/] and [https://www.youtube.com/watch?v=6FC-tcwMBnU] */ 00330 prefix_out: 00331 SAVEIP_PREFIX; 00332 FillFlags(); 00333 return CBRET_NONE; 00334 decode_end: 00335 SAVEIP; 00336 FillFlags(); 00337 return CBRET_NONE; 00338 } 00339 00340 Bits CPU_Core_Prefetch_Trap_Run(void) { 00341 Bits oldCycles = CPU_Cycles; 00342 CPU_Cycles = 1; 00343 cpu.trap_skip = false; 00344 00345 Bits ret=CPU_Core_Prefetch_Run(); 00346 if (!cpu.trap_skip) CPU_HW_Interrupt(1); 00347 CPU_Cycles = oldCycles-1; 00348 cpudecoder = &CPU_Core_Prefetch_Run; 00349 00350 return ret; 00351 } 00352