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