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