DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/cpu/core_prefetch.cpp
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