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