From: Toni Wilen Date: Mon, 27 Jul 2015 16:24:15 +0000 (+0300) Subject: x86 bridgeboard: DOSBox x86 CPU core and mainboard support chip emulation. X-Git-Tag: 3200~127 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=b12931b6cbf3afc2564d3893a034911a40dc7876;p=francis%2Fwinuae.git x86 bridgeboard: DOSBox x86 CPU core and mainboard support chip emulation. --- diff --git a/dosbox/callback.h b/dosbox/callback.h new file mode 100644 index 00000000..c4e6fa6e --- /dev/null +++ b/dosbox/callback.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id: callback.h,v 1.26 2009-08-23 17:24:54 c2woody Exp $ */ + +#ifndef DOSBOX_CALLBACK_H +#define DOSBOX_CALLBACK_H + +#ifndef DOSBOX_MEM_H +#include "mem.h" +#endif + +typedef Bitu (*CallBack_Handler)(void); +extern CallBack_Handler CallBack_Handlers[]; + +enum { CB_RETN,CB_RETF,CB_RETF8,CB_IRET,CB_IRETD,CB_IRET_STI,CB_IRET_EOI_PIC1, + CB_IRQ0,CB_IRQ1,CB_IRQ9,CB_IRQ12,CB_IRQ12_RET,CB_IRQ6_PCJR,CB_MOUSE, + CB_INT29,CB_INT16,CB_HOOKABLE,CB_TDE_IRET,CB_IPXESR,CB_IPXESR_RET, + CB_INT21 }; + +#define CB_MAX 128 +#define CB_SIZE 32 +#define CB_SEG 0xF000 +#define CB_SOFFSET 0x1000 + +enum { + CBRET_NONE=0,CBRET_STOP=1 +}; + +extern Bit8u lastint; + +static INLINE RealPt CALLBACK_RealPointer(Bitu callback) { + return RealMake(CB_SEG,(Bit16u)(CB_SOFFSET+callback*CB_SIZE)); +} +static INLINE PhysPt CALLBACK_PhysPointer(Bitu callback) { + return PhysMake(CB_SEG,(Bit16u)(CB_SOFFSET+callback*CB_SIZE)); +} + +static INLINE PhysPt CALLBACK_GetBase(void) { + return (CB_SEG << 4) + CB_SOFFSET; +} + +Bitu CALLBACK_Allocate(); + +void CALLBACK_Idle(void); + + +void CALLBACK_RunRealInt(Bit8u intnum); +void CALLBACK_RunRealFar(Bit16u seg,Bit16u off); + +bool CALLBACK_Setup(Bitu callback,CallBack_Handler handler,Bitu type,const char* descr); +Bitu CALLBACK_Setup(Bitu callback,CallBack_Handler handler,Bitu type,PhysPt addr,const char* descr); + +const char* CALLBACK_GetDescription(Bitu callback); +bool CALLBACK_Free(Bitu callback); + +void CALLBACK_SCF(bool val); +void CALLBACK_SZF(bool val); +void CALLBACK_SIF(bool val); + +extern Bitu call_priv_io; + + +class CALLBACK_HandlerObject{ +private: + bool installed; + Bitu m_callback; + enum {NONE,SETUP,SETUPAT} m_type; + struct { + RealPt old_vector; + Bit8u interrupt; + bool installed; + } vectorhandler; +public: + CALLBACK_HandlerObject():installed(false),m_type(NONE) { + vectorhandler.installed=false; + } + ~CALLBACK_HandlerObject(); + + //Install and allocate a callback. + void Install(CallBack_Handler handler,Bitu type,const char* description); + void Install(CallBack_Handler handler,Bitu type,PhysPt addr,const char* description); + + //Only allocate a callback number + void Allocate(CallBack_Handler handler,const char* description=0); + Bit16u Get_callback() { + return (Bit16u)m_callback; + } + RealPt Get_RealPointer() { + return CALLBACK_RealPointer(m_callback); + } + void Set_RealVec(Bit8u vec); +}; +#endif diff --git a/dosbox/cmos.cpp b/dosbox/cmos.cpp new file mode 100644 index 00000000..bf3d67ef --- /dev/null +++ b/dosbox/cmos.cpp @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id: cmos.cpp,v 1.29 2009-06-16 18:19:18 qbix79 Exp $ */ + +#include +#include + +#include "dosbox.h" +//#include "timer.h" +#include "pic.h" +#include "inout.h" +#include "mem.h" +//#include "bios_disk.h" +#include "setup.h" +//#include "cross.h" //fmod on certain platforms + +static struct { + Bit8u regs[0x40]; + bool nmi; + bool bcd; + Bit8u reg; + struct { + bool enabled; + Bit8u div; + float delay; + bool acknowledged; + } timer; + struct { + double timer; + double ended; + double alarm; + } last; + bool update_ended; +} cmos; + +Bit8u *x86_cmos_regs(Bit8u *regs) +{ + if (regs) { + memcpy(cmos.regs, regs, 0x40); + } + return cmos.regs; +} + +static void cmos_timerevent(Bitu val) { + if (cmos.timer.acknowledged) { + cmos.timer.acknowledged=false; + PIC_ActivateIRQ(8); + } + if (cmos.timer.enabled) { +// PIC_AddEvent(cmos_timerevent,cmos.timer.delay); + cmos.regs[0xc] = 0xC0;//Contraption Zack (music) + } +} + +static void cmos_checktimer(void) { + //PIC_RemoveEvents(cmos_timerevent); + if (cmos.timer.div<=2) cmos.timer.div+=7; + cmos.timer.delay=(1000.0f/(32768.0f / (1 << (cmos.timer.div - 1)))); + if (!cmos.timer.div || !cmos.timer.enabled) return; + LOG(LOG_PIT,LOG_NORMAL)("RTC Timer at %.2f hz",1000.0/cmos.timer.delay); +// PIC_AddEvent(cmos_timerevent,cmos.timer.delay); + /* A rtc is always running */ + double remd=fmod(PIC_FullIndex(),(double)cmos.timer.delay); + //PIC_AddEvent(cmos_timerevent,(float)((double)cmos.timer.delay-remd)); //Should be more like a real pc. Check +// status reg A reading with this (and with other delays actually) +} + +void cmos_selreg(Bitu port,Bitu val,Bitu iolen) { + cmos.reg=val & 0x3f; + cmos.nmi=(val & 0x80)>0; +} + +void cmos_writereg(Bitu port,Bitu val,Bitu iolen) +{ + switch (cmos.reg) + { + case 0x00: /* Seconds */ + case 0x02: /* Minutes */ + case 0x04: /* Hours */ + case 0x06: /* Day of week */ + case 0x07: /* Date of month */ + case 0x08: /* Month */ + case 0x09: /* Year */ + case 0x32: /* Century */ + /* Ignore writes to change alarm */ + break; + case 0x01: /* Seconds Alarm */ + case 0x03: /* Minutes Alarm */ + case 0x05: /* Hours Alarm */ + LOG(LOG_BIOS,LOG_NORMAL)("CMOS:Trying to set alarm"); + cmos.regs[cmos.reg]=val; + break; + case 0x0a: /* Status reg A */ + cmos.regs[cmos.reg]=val & 0x7f; + if ((val & 0x70)!=0x20) LOG(LOG_BIOS,LOG_ERROR)("CMOS Illegal 22 stage divider value"); + cmos.timer.div=(val & 0xf); + cmos_checktimer(); + break; + case 0x0b: /* Status reg B */ + cmos.bcd=!(val & 0x4); + cmos.regs[cmos.reg]=val & 0x7f; + cmos.timer.enabled=(val & 0x40)>0; + if (val&0x10) LOG(LOG_BIOS,LOG_ERROR)("CMOS:Updated ended interrupt not supported yet"); + cmos_checktimer(); + break; + case 0x0d:/* Status reg D */ + cmos.regs[cmos.reg]=val & 0x80; /*Bit 7=1:RTC Pown on*/ + break; + case 0x0f: /* Shutdown status byte */ + cmos.regs[cmos.reg]=val;// & 0x7f; + break; + default: + cmos.regs[cmos.reg]=val; // & 0x7f; + LOG(LOG_BIOS,LOG_ERROR)("CMOS:WRite to unhandled register %x",cmos.reg); + } +} + + +#define MAKE_RETURN(_VAL) (cmos.bcd ? ((((_VAL) / 10) << 4) | ((_VAL) % 10)) : (_VAL)); + +Bitu cmos_readreg(Bitu port,Bitu iolen) { + if (cmos.reg>0x3f) { + LOG(LOG_BIOS,LOG_ERROR)("CMOS:Read from illegal register %x",cmos.reg); + return 0xff; + } + Bitu drive_a, drive_b; + Bit8u hdparm; + time_t curtime; + struct tm *loctime; + /* Get the current time. */ + curtime = time (NULL); + + /* Convert it to local time representation. */ + loctime = localtime (&curtime); + + switch (cmos.reg) { + case 0x00: /* Seconds */ + return MAKE_RETURN(loctime->tm_sec); + case 0x02: /* Minutes */ + return MAKE_RETURN(loctime->tm_min); + case 0x04: /* Hours */ + return MAKE_RETURN(loctime->tm_hour); + case 0x06: /* Day of week */ + return MAKE_RETURN(loctime->tm_wday + 1); + case 0x07: /* Date of month */ + return MAKE_RETURN(loctime->tm_mday); + case 0x08: /* Month */ + return MAKE_RETURN(loctime->tm_mon + 1); + case 0x09: /* Year */ + return MAKE_RETURN(loctime->tm_year % 100); + case 0x32: /* Century */ + return MAKE_RETURN(loctime->tm_year / 100 + 19); + case 0x01: /* Seconds Alarm */ + case 0x03: /* Minutes Alarm */ + case 0x05: /* Hours Alarm */ + return cmos.regs[cmos.reg]; + case 0x0a: /* Status register A */ + if (0 && PIC_TickIndex()<0.002) { + return (cmos.regs[0x0a]&0x7f) | 0x80; + } else { + return (cmos.regs[0x0a]&0x7f); + } + case 0x0c: /* Status register C */ + cmos.timer.acknowledged=true; + if (cmos.timer.enabled) { + /* In periodic interrupt mode only care for those flags */ + Bit8u val=cmos.regs[0xc]; + cmos.regs[0xc]=0; + return val; + } else { + /* Give correct values at certain times */ + Bit8u val=0; + double index=PIC_FullIndex(); + if (index>=(cmos.last.timer+cmos.timer.delay)) { + cmos.last.timer=index; + val|=0x40; + } + if (index>=(cmos.last.ended+1000)) { + cmos.last.ended=index; + val|=0x10; + } + return val; + } +#if 0 + case 0x10: /* Floppy size */ + drive_a = 0; + drive_b = 0; + if(imageDiskList[0] != NULL) drive_a = imageDiskList[0]->GetBiosType(); + if(imageDiskList[1] != NULL) drive_b = imageDiskList[1]->GetBiosType(); + return ((drive_a << 4) | (drive_b)); + /* First harddrive info */ + case 0x12: + hdparm = 0; + if(imageDiskList[2] != NULL) hdparm |= 0xf; + if(imageDiskList[3] != NULL) hdparm |= 0xf0; + return hdparm; + case 0x19: + if(imageDiskList[2] != NULL) return 47; /* User defined type */ + return 0; + case 0x1b: + if(imageDiskList[2] != NULL) return (imageDiskList[2]->cylinders & 0xff); + return 0; + case 0x1c: + if(imageDiskList[2] != NULL) return ((imageDiskList[2]->cylinders & 0xff00)>>8); + return 0; + case 0x1d: + if(imageDiskList[2] != NULL) return (imageDiskList[2]->heads); + return 0; + case 0x1e: + if(imageDiskList[2] != NULL) return 0xff; + return 0; + case 0x1f: + if(imageDiskList[2] != NULL) return 0xff; + return 0; + case 0x20: + if(imageDiskList[2] != NULL) return (0xc0 | (((imageDiskList[2]->heads) > 8) << 3)); + return 0; + case 0x21: + if(imageDiskList[2] != NULL) return (imageDiskList[2]->cylinders & 0xff); + return 0; + case 0x22: + if(imageDiskList[2] != NULL) return ((imageDiskList[2]->cylinders & 0xff00)>>8); + return 0; + case 0x23: + if(imageDiskList[2] != NULL) return (imageDiskList[2]->sectors); + return 0; + /* Second harddrive info */ + case 0x1a: + if(imageDiskList[3] != NULL) return 47; /* User defined type */ + return 0; + case 0x24: + if(imageDiskList[3] != NULL) return (imageDiskList[3]->cylinders & 0xff); + return 0; + case 0x25: + if(imageDiskList[3] != NULL) return ((imageDiskList[3]->cylinders & 0xff00)>>8); + return 0; + case 0x26: + if(imageDiskList[3] != NULL) return (imageDiskList[3]->heads); + return 0; + case 0x27: + if(imageDiskList[3] != NULL) return 0xff; + return 0; + case 0x28: + if(imageDiskList[3] != NULL) return 0xff; + return 0; + case 0x29: + if(imageDiskList[3] != NULL) return (0xc0 | (((imageDiskList[3]->heads) > 8) << 3)); + return 0; + case 0x2a: + if(imageDiskList[3] != NULL) return (imageDiskList[3]->cylinders & 0xff); + return 0; + case 0x2b: + if(imageDiskList[3] != NULL) return ((imageDiskList[3]->cylinders & 0xff00)>>8); + return 0; + case 0x2c: + if(imageDiskList[3] != NULL) return (imageDiskList[3]->sectors); + return 0; +#endif + case 0x39: + return 0; + case 0x3a: + return 0; + + + case 0x0b: /* Status register B */ + case 0x0d: /* Status register D */ + case 0x0f: /* Shutdown status byte */ + case 0x14: /* Equipment */ + case 0x15: /* Base Memory KB Low Byte */ + case 0x16: /* Base Memory KB High Byte */ + case 0x17: /* Extended memory in KB Low Byte */ + case 0x18: /* Extended memory in KB High Byte */ + case 0x30: /* Extended memory in KB Low Byte */ + case 0x31: /* Extended memory in KB High Byte */ +// LOG(LOG_BIOS,LOG_NORMAL)("CMOS:Read from reg %X : %04X",cmos.reg,cmos.regs[cmos.reg]); + return cmos.regs[cmos.reg]; + default: + LOG(LOG_BIOS,LOG_NORMAL)("CMOS:Read from reg %X",cmos.reg); + return cmos.regs[cmos.reg]; + } +} + +void CMOS_SetRegister(Bitu regNr, Bit8u val) { + cmos.regs[regNr] = val; +} + + +class CMOS:public Module_base{ +private: +// IO_ReadHandleObject ReadHandler[2]; +// IO_WriteHandleObject WriteHandler[2]; +public: + CMOS(Section* configuration):Module_base(configuration){ +// WriteHandler[0].Install(0x70,cmos_selreg,IO_MB); +// WriteHandler[1].Install(0x71,cmos_writereg,IO_MB); +// ReadHandler[0].Install(0x71,cmos_readreg,IO_MB); + cmos.timer.enabled=false; + cmos.timer.acknowledged=true; + cmos.reg=0xa; + cmos_writereg(0x71,0x26,1); + cmos.reg=0xb; + cmos_writereg(0x71,0x2,1); //Struct tm *loctime is of 24 hour format, + cmos.reg=0xd; + cmos_writereg(0x71,0x80,1); /* RTC power on */ + // Equipment is updated from bios.cpp and bios_disk.cpp + /* Fill in base memory size, it is 640K always */ + cmos.regs[0x15]=(Bit8u)0x80; + cmos.regs[0x16]=(Bit8u)0x02; + /* Fill in extended memory size */ + Bitu exsize=(MEM_TotalPages()*4)-1024; + cmos.regs[0x17]=(Bit8u)exsize; + cmos.regs[0x18]=(Bit8u)(exsize >> 8); + cmos.regs[0x30]=(Bit8u)exsize; + cmos.regs[0x31]=(Bit8u)(exsize >> 8); + } +}; + +static CMOS* test; + +void CMOS_Destroy(Section* sec){ + delete test; +} + +void CMOS_Init(Section* sec) { + test = new CMOS(sec); + sec->AddDestroyFunction(&CMOS_Destroy,true); +} diff --git a/dosbox/core_full.cpp b/dosbox/core_full.cpp new file mode 100644 index 00000000..fe2f2d36 --- /dev/null +++ b/dosbox/core_full.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "dosbox.h" + +#include "pic.h" +#include "regs.h" +#include "cpu.h" +#include "lazyflags.h" +#include "paging.h" +#include "fpu.h" +//#include "debug.h" +#include "inout.h" +#include "callback.h" + + +typedef PhysPt EAPoint; +#define SegBase(c) SegPhys(c) + +#define LoadMb(off) mem_readb_inline(off) +#define LoadMw(off) mem_readw_inline(off) +#define LoadMd(off) mem_readd_inline(off) + +#define LoadMbs(off) (Bit8s)(LoadMb(off)) +#define LoadMws(off) (Bit16s)(LoadMw(off)) +#define LoadMds(off) (Bit32s)(LoadMd(off)) + +#define SaveMb(off,val) mem_writeb_inline(off,val) +#define SaveMw(off,val) mem_writew_inline(off,val) +#define SaveMd(off,val) mem_writed_inline(off,val) + +#define LoadD(reg) reg +#define SaveD(reg,val) reg=val + + + +#include "core_full/loadwrite.h" +#include "core_full/support.h" +#include "core_full/optable.h" +#include "instructions.h" + +#define EXCEPTION(blah) \ + { \ + Bit8u new_num=blah; \ + CPU_Exception(new_num,0); \ + continue; \ + } + +Bits CPU_Core_Full_Run(void) { + FullData inst; + while (CPU_Cycles-->0) { +#if C_DEBUG + cycle_count++; +#if C_HEAVY_DEBUG + if (DEBUG_HeavyIsBreakpoint()) { + FillFlags(); + return debugCallback; + }; +#endif +#endif + LoadIP(); + inst.entry=cpu.code.big*0x200; + inst.prefix=cpu.code.big; +restartopcode: + inst.entry=(inst.entry & 0xffffff00) | Fetchb(); + inst.code=OpCodeTable[inst.entry]; + #include "core_full/load.h" + #include "core_full/op.h" + #include "core_full/save.h" +nextopcode:; + SaveIP(); + continue; +illegalopcode: + LOG(LOG_CPU,LOG_NORMAL)("Illegal opcode"); + CPU_Exception(0x6,0); + } + FillFlags(); + return CBRET_NONE; +} + + +void CPU_Core_Full_Init(void) { + +} diff --git a/dosbox/core_full/ea_lookup.h b/dosbox/core_full/ea_lookup.h new file mode 100644 index 00000000..cd8834e0 --- /dev/null +++ b/dosbox/core_full/ea_lookup.h @@ -0,0 +1,237 @@ +{ + EAPoint seg_base; + Bit16u off; + switch ((inst.rm_mod<<3)|inst.rm_eai) { + case 0x00: + off=reg_bx+reg_si; + seg_base=SegBase(ds); + break; + case 0x01: + off=reg_bx+reg_di; + seg_base=SegBase(ds); + break; + case 0x02: + off=reg_bp+reg_si; + seg_base=SegBase(ss); + break; + case 0x03: + off=reg_bp+reg_di; + seg_base=SegBase(ss); + break; + case 0x04: + off=reg_si; + seg_base=SegBase(ds); + break; + case 0x05: + off=reg_di; + seg_base=SegBase(ds); + break; + case 0x06: + off=Fetchw(); + seg_base=SegBase(ds); + break; + case 0x07: + off=reg_bx; + seg_base=SegBase(ds); + break; + + case 0x08: + off=reg_bx+reg_si+Fetchbs(); + seg_base=SegBase(ds); + break; + case 0x09: + off=reg_bx+reg_di+Fetchbs(); + seg_base=SegBase(ds); + break; + case 0x0a: + off=reg_bp+reg_si+Fetchbs(); + seg_base=SegBase(ss); + break; + case 0x0b: + off=reg_bp+reg_di+Fetchbs(); + seg_base=SegBase(ss); + break; + case 0x0c: + off=reg_si+Fetchbs(); + seg_base=SegBase(ds); + break; + case 0x0d: + off=reg_di+Fetchbs(); + seg_base=SegBase(ds); + break; + case 0x0e: + off=reg_bp+Fetchbs(); + seg_base=SegBase(ss); + break; + case 0x0f: + off=reg_bx+Fetchbs(); + seg_base=SegBase(ds); + break; + + case 0x10: + off=reg_bx+reg_si+Fetchws(); + seg_base=SegBase(ds); + break; + case 0x11: + off=reg_bx+reg_di+Fetchws(); + seg_base=SegBase(ds); + break; + case 0x12: + off=reg_bp+reg_si+Fetchws(); + seg_base=SegBase(ss); + break; + case 0x13: + off=reg_bp+reg_di+Fetchws(); + seg_base=SegBase(ss); + break; + case 0x14: + off=reg_si+Fetchws(); + seg_base=SegBase(ds); + break; + case 0x15: + off=reg_di+Fetchws(); + seg_base=SegBase(ds); + break; + case 0x16: + off=reg_bp+Fetchws(); + seg_base=SegBase(ss); + break; + case 0x17: + off=reg_bx+Fetchws(); + seg_base=SegBase(ds); + break; + } + inst.rm_off=off; + if (inst.prefix & PREFIX_SEG) { + inst.rm_eaa=inst.seg.base+off; + } else { + inst.rm_eaa=seg_base+off; + } +} else { + + +#define SIB(MODE) { \ + Bitu sib=Fetchb(); \ + switch (sib&7) { \ + case 0:seg_base=SegBase(ds);off=reg_eax;break; \ + case 1:seg_base=SegBase(ds);off=reg_ecx;break; \ + case 2:seg_base=SegBase(ds);off=reg_edx;break; \ + case 3:seg_base=SegBase(ds);off=reg_ebx;break; \ + case 4:seg_base=SegBase(ss);off=reg_esp;break; \ + case 5:if (!MODE) { seg_base=SegBase(ds);off=Fetchd();break; \ + } else { seg_base=SegBase(ss);off=reg_ebp;break;} \ + case 6:seg_base=SegBase(ds);off=reg_esi;break; \ + case 7:seg_base=SegBase(ds);off=reg_edi;break; \ + } \ + off+=*SIBIndex[(sib >> 3) &7] << (sib >> 6); \ +}; + static Bit32u SIBZero=0; + static Bit32u * SIBIndex[8]= { ®_eax,®_ecx,®_edx,®_ebx,&SIBZero,®_ebp,®_esi,®_edi }; + EAPoint seg_base; + Bit32u off; + switch ((inst.rm_mod<<3)|inst.rm_eai) { + case 0x00: + off=reg_eax; + seg_base=SegBase(ds); + break; + case 0x01: + off=reg_ecx; + seg_base=SegBase(ds); + break; + case 0x02: + off=reg_edx; + seg_base=SegBase(ds); + break; + case 0x03: + off=reg_ebx; + seg_base=SegBase(ds); + break; + case 0x04: + SIB(0); + break; + case 0x05: + off=Fetchd(); + seg_base=SegBase(ds); + break; + case 0x06: + off=reg_esi; + seg_base=SegBase(ds); + break; + case 0x07: + off=reg_edi; + seg_base=SegBase(ds); + break; + + case 0x08: + off=reg_eax+Fetchbs(); + seg_base=SegBase(ds); + break; + case 0x09: + off=reg_ecx+Fetchbs(); + seg_base=SegBase(ds); + break; + case 0x0a: + off=reg_edx+Fetchbs(); + seg_base=SegBase(ds); + break; + case 0x0b: + off=reg_ebx+Fetchbs(); + seg_base=SegBase(ds); + break; + case 0x0c: + SIB(1); + off+=Fetchbs(); + break; + case 0x0d: + off=reg_ebp+Fetchbs(); + seg_base=SegBase(ss); + break; + case 0x0e: + off=reg_esi+Fetchbs(); + seg_base=SegBase(ds); + break; + case 0x0f: + off=reg_edi+Fetchbs(); + seg_base=SegBase(ds); + break; + + case 0x10: + off=reg_eax+Fetchds(); + seg_base=SegBase(ds); + break; + case 0x11: + off=reg_ecx+Fetchds(); + seg_base=SegBase(ds); + break; + case 0x12: + off=reg_edx+Fetchds(); + seg_base=SegBase(ds); + break; + case 0x13: + off=reg_ebx+Fetchds(); + seg_base=SegBase(ds); + break; + case 0x14: + SIB(1); + off+=Fetchds(); + break; + case 0x15: + off=reg_ebp+Fetchds(); + seg_base=SegBase(ss); + break; + case 0x16: + off=reg_esi+Fetchds(); + seg_base=SegBase(ds); + break; + case 0x17: + off=reg_edi+Fetchds(); + seg_base=SegBase(ds); + break; + } + inst.rm_off=off; + if (inst.prefix & PREFIX_SEG) { + inst.rm_eaa=inst.seg.base+off; + } else { + inst.rm_eaa=seg_base+off; + } +} diff --git a/dosbox/core_full/load.h b/dosbox/core_full/load.h new file mode 100644 index 00000000..a5e7adeb --- /dev/null +++ b/dosbox/core_full/load.h @@ -0,0 +1,489 @@ +switch (inst.code.load) { +/* General loading */ + case L_POPwRM: + inst_op1_w = Pop_16(); + goto case_L_MODRM; + case L_POPdRM: + inst_op1_d = Pop_32(); + goto case_L_MODRM; + case L_MODRM_NVM: + if ((reg_flags & FLAG_VM) || !cpu.pmode) goto illegalopcode; + goto case_L_MODRM; +case_L_MODRM: + case L_MODRM: + inst.rm=Fetchb(); + inst.rm_index=(inst.rm >> 3) & 7; + inst.rm_eai=inst.rm&07; + inst.rm_mod=inst.rm>>6; + /* Decode address of mod/rm if needed */ + if (inst.rm<0xc0) { + if (!(inst.prefix & PREFIX_ADDR)) + #include "ea_lookup.h" + } +l_MODRMswitch: + switch (inst.code.extra) { +/* Byte */ + case M_Ib: + inst_op1_d=Fetchb(); + break; + case M_Ebx: + if (inst.rm<0xc0) inst_op1_ds=(Bit8s)LoadMb(inst.rm_eaa); + else inst_op1_ds=(Bit8s)reg_8(inst.rm_eai); + break; + case M_EbIb: + inst_op2_d=Fetchb(); + case M_Eb: + if (inst.rm<0xc0) inst_op1_d=LoadMb(inst.rm_eaa); + else inst_op1_d=reg_8(inst.rm_eai); + break; + case M_EbGb: + if (inst.rm<0xc0) inst_op1_d=LoadMb(inst.rm_eaa); + else inst_op1_d=reg_8(inst.rm_eai); + inst_op2_d=reg_8(inst.rm_index); + break; + case M_GbEb: + if (inst.rm<0xc0) inst_op2_d=LoadMb(inst.rm_eaa); + else inst_op2_d=reg_8(inst.rm_eai); + case M_Gb: + inst_op1_d=reg_8(inst.rm_index);; + break; +/* Word */ + case M_Iw: + inst_op1_d=Fetchw(); + break; + case M_EwxGwx: + inst_op2_ds=(Bit16s)reg_16(inst.rm_index); + goto l_M_Ewx; + case M_EwxIbx: + inst_op2_ds=Fetchbs(); + goto l_M_Ewx; + case M_EwxIwx: + inst_op2_ds=Fetchws(); +l_M_Ewx: + case M_Ewx: + if (inst.rm<0xc0) inst_op1_ds=(Bit16s)LoadMw(inst.rm_eaa); + else inst_op1_ds=(Bit16s)reg_16(inst.rm_eai); + break; + case M_EwIb: + inst_op2_d=Fetchb(); + goto l_M_Ew; + case M_EwIbx: + inst_op2_ds=Fetchbs(); + goto l_M_Ew; + case M_EwIw: + inst_op2_d=Fetchw(); + goto l_M_Ew; + case M_EwGwCL: + inst_imm_d=reg_cl; + goto l_M_EwGw; + case M_EwGwIb: + inst_imm_d=Fetchb(); + goto l_M_EwGw; + case M_EwGwt: + inst_op2_d=reg_16(inst.rm_index); + inst.rm_eaa+=((Bit16s)inst_op2_d >> 4) * 2; + goto l_M_Ew; +l_M_EwGw: + case M_EwGw: + inst_op2_d=reg_16(inst.rm_index); +l_M_Ew: + case M_Ew: + if (inst.rm<0xc0) inst_op1_d=LoadMw(inst.rm_eaa); + else inst_op1_d=reg_16(inst.rm_eai); + break; + case M_GwEw: + if (inst.rm<0xc0) inst_op2_d=LoadMw(inst.rm_eaa); + else inst_op2_d=reg_16(inst.rm_eai); + case M_Gw: + inst_op1_d=reg_16(inst.rm_index);; + break; +/* DWord */ + case M_Id: + inst_op1_d=Fetchd(); + break; + case M_EdxGdx: + inst_op2_ds=(Bit32s)reg_32(inst.rm_index); + case M_Edx: + if (inst.rm<0xc0) inst_op1_d=(Bit32s)LoadMd(inst.rm_eaa); + else inst_op1_d=(Bit32s)reg_32(inst.rm_eai); + break; + case M_EdIb: + inst_op2_d=Fetchb(); + goto l_M_Ed; + case M_EdIbx: + inst_op2_ds=Fetchbs(); + goto l_M_Ed; + case M_EdId: + inst_op2_d=Fetchd(); + goto l_M_Ed; + case M_EdGdCL: + inst_imm_d=reg_cl; + goto l_M_EdGd; + case M_EdGdt: + inst_op2_d=reg_32(inst.rm_index); + inst.rm_eaa+=((Bit32s)inst_op2_d >> 5) * 4; + goto l_M_Ed; + case M_EdGdIb: + inst_imm_d=Fetchb(); + goto l_M_EdGd; +l_M_EdGd: + case M_EdGd: + inst_op2_d=reg_32(inst.rm_index); +l_M_Ed: + case M_Ed: + if (inst.rm<0xc0) inst_op1_d=LoadMd(inst.rm_eaa); + else inst_op1_d=reg_32(inst.rm_eai); + break; + case M_GdEd: + if (inst.rm<0xc0) inst_op2_d=LoadMd(inst.rm_eaa); + else inst_op2_d=reg_32(inst.rm_eai); + case M_Gd: + inst_op1_d=reg_32(inst.rm_index); + break; +/* Others */ + + case M_SEG: + //TODO Check for limit + inst_op1_d=SegValue((SegNames)inst.rm_index); + break; + case M_Efw: + if (inst.rm>=0xc0) goto illegalopcode; + inst_op1_d=LoadMw(inst.rm_eaa); + inst_op2_d=LoadMw(inst.rm_eaa+2); + break; + case M_Efd: + if (inst.rm>=0xc0) goto illegalopcode; + inst_op1_d=LoadMd(inst.rm_eaa); + inst_op2_d=LoadMw(inst.rm_eaa+4); + break; + case M_EA: + inst_op1_d=inst.rm_off; + break; + case M_POPw: + inst_op1_d = Pop_16(); + break; + case M_POPd: + inst_op1_d = Pop_32(); + break; + case M_GRP: + inst.code=Groups[inst.code.op][inst.rm_index]; + goto l_MODRMswitch; + case M_GRP_Ib: + inst_op2_d=Fetchb(); + inst.code=Groups[inst.code.op][inst.rm_index]; + goto l_MODRMswitch; + case M_GRP_CL: + inst_op2_d=reg_cl; + inst.code=Groups[inst.code.op][inst.rm_index]; + goto l_MODRMswitch; + case M_GRP_1: + inst_op2_d=1; + inst.code=Groups[inst.code.op][inst.rm_index]; + goto l_MODRMswitch; + case 0: + break; + default: + LOG(LOG_CPU,LOG_ERROR)("MODRM:Unhandled load %d entry %x",inst.code.extra,inst.entry); + break; + } + break; + case L_POPw: + inst_op1_d = Pop_16(); + break; + case L_POPd: + inst_op1_d = Pop_32(); + break; + case L_POPfw: + inst_op1_d = Pop_16(); + inst_op2_d = Pop_16(); + break; + case L_POPfd: + inst_op1_d = Pop_32(); + inst_op2_d = Pop_16(); + break; + case L_Ib: + inst_op1_d=Fetchb(); + break; + case L_Ibx: + inst_op1_ds=Fetchbs(); + break; + case L_Iw: + inst_op1_d=Fetchw(); + break; + case L_Iwx: + inst_op1_ds=Fetchws(); + break; + case L_Idx: + case L_Id: + inst_op1_d=Fetchd(); + break; + case L_Ifw: + inst_op1_d=Fetchw(); + inst_op2_d=Fetchw(); + break; + case L_Ifd: + inst_op1_d=Fetchd(); + inst_op2_d=Fetchw(); + break; +/* Direct load of registers */ + case L_REGbIb: + inst_op2_d=Fetchb(); + case L_REGb: + inst_op1_d=reg_8(inst.code.extra); + break; + case L_REGwIw: + inst_op2_d=Fetchw(); + case L_REGw: + inst_op1_d=reg_16(inst.code.extra); + break; + case L_REGdId: + inst_op2_d=Fetchd(); + case L_REGd: + inst_op1_d=reg_32(inst.code.extra); + break; + case L_SEG: + inst_op1_d=SegValue((SegNames)inst.code.extra); + break; +/* Depending on addressize */ + case L_OP: + if (inst.prefix & PREFIX_ADDR) { + inst.rm_eaa=Fetchd(); + } else { + inst.rm_eaa=Fetchw(); + } + if (inst.prefix & PREFIX_SEG) { + inst.rm_eaa+=inst.seg.base; + } else { + inst.rm_eaa+=SegBase(ds); + } + break; + /* Special cases */ + case L_DOUBLE: + inst.entry|=0x100; + goto restartopcode; + case L_PRESEG: + inst.prefix|=PREFIX_SEG; + inst.seg.base=SegBase((SegNames)inst.code.extra); + goto restartopcode; + case L_PREREPNE: + inst.prefix|=PREFIX_REP; + inst.repz=false; + goto restartopcode; + case L_PREREP: + inst.prefix|=PREFIX_REP; + inst.repz=true; + goto restartopcode; + case L_PREOP: + inst.entry=(cpu.code.big ^1) * 0x200; + goto restartopcode; + case L_PREADD: + inst.prefix=(inst.prefix & ~1) | (cpu.code.big ^ 1); + goto restartopcode; + case L_VAL: + inst_op1_d=inst.code.extra; + break; + case L_INTO: + if (!get_OF()) goto nextopcode; + inst_op1_d=4; + break; + case D_IRETw: + CPU_IRET(false,GetIP()); + if (GETFLAG(IF) && PIC_IRQCheck) { + return CBRET_NONE; + } + continue; + case D_IRETd: + CPU_IRET(true,GetIP()); + if (GETFLAG(IF) && PIC_IRQCheck) + return CBRET_NONE; + continue; + case D_RETFwIw: + { + Bitu words=Fetchw(); + FillFlags(); + CPU_RET(false,words,GetIP()); + continue; + } + case D_RETFw: + FillFlags(); + CPU_RET(false,0,GetIP()); + continue; + case D_RETFdIw: + { + Bitu words=Fetchw(); + FillFlags(); + CPU_RET(true,words,GetIP()); + continue; + } + case D_RETFd: + FillFlags(); + CPU_RET(true,0,GetIP()); + continue; +/* Direct operations */ + case L_STRING: + #include "string.h" + goto nextopcode; + case D_PUSHAw: + { + Bit16u old_sp=reg_sp; + Push_16(reg_ax);Push_16(reg_cx);Push_16(reg_dx);Push_16(reg_bx); + Push_16(old_sp);Push_16(reg_bp);Push_16(reg_si);Push_16(reg_di); + } + goto nextopcode; + case D_PUSHAd: + { + Bit32u old_esp=reg_esp; + Push_32(reg_eax);Push_32(reg_ecx);Push_32(reg_edx);Push_32(reg_ebx); + Push_32(old_esp);Push_32(reg_ebp);Push_32(reg_esi);Push_32(reg_edi); + } + goto nextopcode; + case D_POPAw: + reg_di=Pop_16();reg_si=Pop_16();reg_bp=Pop_16();Pop_16();//Don't save SP + reg_bx=Pop_16();reg_dx=Pop_16();reg_cx=Pop_16();reg_ax=Pop_16(); + goto nextopcode; + case D_POPAd: + reg_edi=Pop_32();reg_esi=Pop_32();reg_ebp=Pop_32();Pop_32();//Don't save ESP + reg_ebx=Pop_32();reg_edx=Pop_32();reg_ecx=Pop_32();reg_eax=Pop_32(); + goto nextopcode; + case D_POPSEGw: + if (CPU_PopSeg((SegNames)inst.code.extra,false)) RunException(); + goto nextopcode; + case D_POPSEGd: + if (CPU_PopSeg((SegNames)inst.code.extra,true)) RunException(); + goto nextopcode; + case D_SETALC: + reg_al = get_CF() ? 0xFF : 0; + goto nextopcode; + case D_XLAT: + if (inst.prefix & PREFIX_SEG) { + if (inst.prefix & PREFIX_ADDR) { + reg_al=LoadMb(inst.seg.base+(Bit32u)(reg_ebx+reg_al)); + } else { + reg_al=LoadMb(inst.seg.base+(Bit16u)(reg_bx+reg_al)); + } + } else { + if (inst.prefix & PREFIX_ADDR) { + reg_al=LoadMb(SegBase(ds)+(Bit32u)(reg_ebx+reg_al)); + } else { + reg_al=LoadMb(SegBase(ds)+(Bit16u)(reg_bx+reg_al)); + } + } + goto nextopcode; + case D_CBW: + reg_ax=(Bit8s)reg_al; + goto nextopcode; + case D_CWDE: + reg_eax=(Bit16s)reg_ax; + goto nextopcode; + case D_CWD: + if (reg_ax & 0x8000) reg_dx=0xffff; + else reg_dx=0; + goto nextopcode; + case D_CDQ: + if (reg_eax & 0x80000000) reg_edx=0xffffffff; + else reg_edx=0; + goto nextopcode; + case D_CLI: + if (CPU_CLI()) RunException(); + goto nextopcode; + case D_STI: + if (CPU_STI()) RunException(); + goto nextopcode; + case D_STC: + FillFlags();SETFLAGBIT(CF,true); + goto nextopcode; + case D_CLC: + FillFlags();SETFLAGBIT(CF,false); + goto nextopcode; + case D_CMC: + FillFlags(); + SETFLAGBIT(CF,!(reg_flags & FLAG_CF)); + goto nextopcode; + case D_CLD: + SETFLAGBIT(DF,false); + cpu.direction=1; + goto nextopcode; + case D_STD: + SETFLAGBIT(DF,true); + cpu.direction=-1; + goto nextopcode; + case D_PUSHF: + if (CPU_PUSHF(inst.code.extra)) RunException(); + goto nextopcode; + case D_POPF: + if (CPU_POPF(inst.code.extra)) RunException(); + if (GETFLAG(IF) && PIC_IRQCheck) { + SaveIP(); + return CBRET_NONE; + } + goto nextopcode; + case D_SAHF: + SETFLAGSb(reg_ah); + goto nextopcode; + case D_LAHF: + FillFlags(); + reg_ah=reg_flags&0xff; + goto nextopcode; + case D_WAIT: + case D_NOP: + goto nextopcode; + case D_LOCK: /* FIXME: according to intel, LOCK should raise an exception if it's not followed by one of a small set of instructions; + probably doesn't matter for our purposes as it is a pentium prefix anyhow */ + LOG(LOG_CPU,LOG_NORMAL)("CPU:LOCK"); + goto nextopcode; + case D_ENTERw: + { + Bitu bytes=Fetchw(); + Bitu level=Fetchb(); + CPU_ENTER(false,bytes,level); + goto nextopcode; + } + case D_ENTERd: + { + Bitu bytes=Fetchw(); + Bitu level=Fetchb(); + CPU_ENTER(true,bytes,level); + goto nextopcode; + } + case D_LEAVEw: + reg_esp&=cpu.stack.notmask; + reg_esp|=(reg_ebp&cpu.stack.mask); + reg_bp=Pop_16(); + goto nextopcode; + case D_LEAVEd: + reg_esp&=cpu.stack.notmask; + reg_esp|=(reg_ebp&cpu.stack.mask); + reg_ebp=Pop_32(); + goto nextopcode; + case D_DAA: + DAA(); + goto nextopcode; + case D_DAS: + DAS(); + goto nextopcode; + case D_AAA: + AAA(); + goto nextopcode; + case D_AAS: + AAS(); + goto nextopcode; + case D_CPUID: + if (!CPU_CPUID()) goto illegalopcode; + goto nextopcode; + case D_HLT: + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + FillFlags(); + CPU_HLT(GetIP()); + return CBRET_NONE; + case D_CLTS: + if (cpu.pmode && cpu.cpl) goto illegalopcode; + cpu.cr0&=(~CR0_TASKSWITCH); + goto nextopcode; + case D_ICEBP: + CPU_SW_Interrupt_NoIOPLCheck(1,GetIP()); + continue; + default: + LOG(LOG_CPU,LOG_ERROR)("LOAD:Unhandled code %d opcode %X",inst.code.load,inst.entry); + goto illegalopcode; +} + diff --git a/dosbox/core_full/loadwrite.h b/dosbox/core_full/loadwrite.h new file mode 100644 index 00000000..aca53c49 --- /dev/null +++ b/dosbox/core_full/loadwrite.h @@ -0,0 +1,39 @@ +#define SaveIP() reg_eip=(Bit32u)(inst.cseip-SegBase(cs)); +#define LoadIP() inst.cseip=SegBase(cs)+reg_eip; +#define GetIP() (inst.cseip-SegBase(cs)) + +#define RunException() { \ + CPU_Exception(cpu.exception.which,cpu.exception.error); \ + continue; \ +} + +static INLINE Bit8u the_Fetchb(EAPoint & loc) { + Bit8u temp=LoadMb(loc); + loc+=1; + return temp; +} + +static INLINE Bit16u the_Fetchw(EAPoint & loc) { + Bit16u temp=LoadMw(loc); + loc+=2; + return temp; +} +static INLINE Bit32u the_Fetchd(EAPoint & loc) { + Bit32u temp=LoadMd(loc); + loc+=4; + return temp; +} + +#define Fetchb() the_Fetchb(inst.cseip) +#define Fetchw() the_Fetchw(inst.cseip) +#define Fetchd() the_Fetchd(inst.cseip) + +#define Fetchbs() (Bit8s)the_Fetchb(inst.cseip) +#define Fetchws() (Bit16s)the_Fetchw(inst.cseip) +#define Fetchds() (Bit32s)the_Fetchd(inst.cseip) + +#define Push_16 CPU_Push16 +#define Push_32 CPU_Push32 +#define Pop_16 CPU_Pop16 +#define Pop_32 CPU_Pop32 + diff --git a/dosbox/core_full/op.h b/dosbox/core_full/op.h new file mode 100644 index 00000000..5e4114eb --- /dev/null +++ b/dosbox/core_full/op.h @@ -0,0 +1,651 @@ +/* Do the actual opcode */ +switch (inst.code.op) { + case t_ADDb: case t_ADDw: case t_ADDd: + lf_var1d=inst_op1_d; + lf_var2d=inst_op2_d; + inst_op1_d=lf_resd=lf_var1d + lf_var2d; + lflags.type=inst.code.op; + break; + case t_CMPb: case t_CMPw: case t_CMPd: + case t_SUBb: case t_SUBw: case t_SUBd: + lf_var1d=inst_op1_d; + lf_var2d=inst_op2_d; + inst_op1_d=lf_resd=lf_var1d - lf_var2d; + lflags.type=inst.code.op; + break; + case t_ORb: case t_ORw: case t_ORd: + lf_var1d=inst_op1_d; + lf_var2d=inst_op2_d; + inst_op1_d=lf_resd=lf_var1d | lf_var2d; + lflags.type=inst.code.op; + break; + case t_XORb: case t_XORw: case t_XORd: + lf_var1d=inst_op1_d; + lf_var2d=inst_op2_d; + inst_op1_d=lf_resd=lf_var1d ^ lf_var2d; + lflags.type=inst.code.op; + break; + case t_TESTb: case t_TESTw: case t_TESTd: + case t_ANDb: case t_ANDw: case t_ANDd: + lf_var1d=inst_op1_d; + lf_var2d=inst_op2_d; + inst_op1_d=lf_resd=lf_var1d & lf_var2d; + lflags.type=inst.code.op; + break; + case t_ADCb: case t_ADCw: case t_ADCd: + lflags.oldcf=(get_CF()!=0); + lf_var1d=inst_op1_d; + lf_var2d=inst_op2_d; + inst_op1_d=lf_resd=lf_var1d + lf_var2d + lflags.oldcf; + lflags.type=inst.code.op; + break; + case t_SBBb: case t_SBBw: case t_SBBd: + lflags.oldcf=(get_CF()!=0); + lf_var1d=inst_op1_d; + lf_var2d=inst_op2_d; + inst_op1_d=lf_resd=lf_var1d - lf_var2d - lflags.oldcf; + lflags.type=inst.code.op; + break; + case t_INCb: case t_INCw: case t_INCd: + LoadCF; + lf_var1d=inst_op1_d; + inst_op1_d=lf_resd=inst_op1_d+1; + lflags.type=inst.code.op; + break; + case t_DECb: case t_DECw: case t_DECd: + LoadCF; + lf_var1d=inst_op1_d; + inst_op1_d=lf_resd=inst_op1_d-1; + lflags.type=inst.code.op; + break; +/* Using the instructions.h defines */ + case t_ROLb: + ROLB(inst_op1_b,inst_op2_b,LoadD,SaveD); + break; + case t_ROLw: + ROLW(inst_op1_w,inst_op2_b,LoadD,SaveD); + break; + case t_ROLd: + ROLD(inst_op1_d,inst_op2_b,LoadD,SaveD); + break; + + case t_RORb: + RORB(inst_op1_b,inst_op2_b,LoadD,SaveD); + break; + case t_RORw: + RORW(inst_op1_w,inst_op2_b,LoadD,SaveD); + break; + case t_RORd: + RORD(inst_op1_d,inst_op2_b,LoadD,SaveD); + break; + + case t_RCLb: + RCLB(inst_op1_b,inst_op2_b,LoadD,SaveD); + break; + case t_RCLw: + RCLW(inst_op1_w,inst_op2_b,LoadD,SaveD); + break; + case t_RCLd: + RCLD(inst_op1_d,inst_op2_b,LoadD,SaveD); + break; + + case t_RCRb: + RCRB(inst_op1_b,inst_op2_b,LoadD,SaveD); + break; + case t_RCRw: + RCRW(inst_op1_w,inst_op2_b,LoadD,SaveD); + break; + case t_RCRd: + RCRD(inst_op1_d,inst_op2_b,LoadD,SaveD); + break; + + case t_SHLb: + SHLB(inst_op1_b,inst_op2_b,LoadD,SaveD); + break; + case t_SHLw: + SHLW(inst_op1_w,inst_op2_b,LoadD,SaveD); + break; + case t_SHLd: + SHLD(inst_op1_d,inst_op2_b,LoadD,SaveD); + break; + + case t_SHRb: + SHRB(inst_op1_b,inst_op2_b,LoadD,SaveD); + break; + case t_SHRw: + SHRW(inst_op1_w,inst_op2_b,LoadD,SaveD); + break; + case t_SHRd: + SHRD(inst_op1_d,inst_op2_b,LoadD,SaveD); + break; + + case t_SARb: + SARB(inst_op1_b,inst_op2_b,LoadD,SaveD); + break; + case t_SARw: + SARW(inst_op1_w,inst_op2_b,LoadD,SaveD); + break; + case t_SARd: + SARD(inst_op1_d,inst_op2_b,LoadD,SaveD); + break; + + case O_DSHLw: + { + DSHLW(inst_op1_w,inst_op2_w,inst_imm_b,LoadD,SaveD); + break; + } + case O_DSHRw: + { + DSHRW(inst_op1_w,inst_op2_w,inst_imm_b,LoadD,SaveD); + break; + } + case O_DSHLd: + { + DSHLD(inst_op1_d,inst_op2_d,inst_imm_b,LoadD,SaveD); + break; + } + case O_DSHRd: + { + DSHRD(inst_op1_d,inst_op2_d,inst_imm_b,LoadD,SaveD); + break; + } + + case t_NEGb: + lf_var1b=inst_op1_b; + inst_op1_b=lf_resb=0-inst_op1_b; + lflags.type=t_NEGb; + break; + case t_NEGw: + lf_var1w=inst_op1_w; + inst_op1_w=lf_resw=0-inst_op1_w; + lflags.type=t_NEGw; + break; + case t_NEGd: + lf_var1d=inst_op1_d; + inst_op1_d=lf_resd=0-inst_op1_d; + lflags.type=t_NEGd; + break; + + case O_NOT: + inst_op1_d=~inst_op1_d; + break; + + /* Special instructions */ + case O_IMULRw: + DIMULW(inst_op1_ws,inst_op1_ws,inst_op2_ws,LoadD,SaveD); + break; + case O_IMULRd: + DIMULD(inst_op1_ds,inst_op1_ds,inst_op2_ds,LoadD,SaveD); + break; + case O_MULb: + MULB(inst_op1_b,LoadD,0); + goto nextopcode; + case O_MULw: + MULW(inst_op1_w,LoadD,0); + goto nextopcode; + case O_MULd: + MULD(inst_op1_d,LoadD,0); + goto nextopcode; + case O_IMULb: + IMULB(inst_op1_b,LoadD,0); + goto nextopcode; + case O_IMULw: + IMULW(inst_op1_w,LoadD,0); + goto nextopcode; + case O_IMULd: + IMULD(inst_op1_d,LoadD,0); + goto nextopcode; + case O_DIVb: + DIVB(inst_op1_b,LoadD,0); + goto nextopcode; + case O_DIVw: + DIVW(inst_op1_w,LoadD,0); + goto nextopcode; + case O_DIVd: + DIVD(inst_op1_d,LoadD,0); + goto nextopcode; + case O_IDIVb: + IDIVB(inst_op1_b,LoadD,0); + goto nextopcode; + case O_IDIVw: + IDIVW(inst_op1_w,LoadD,0); + goto nextopcode; + case O_IDIVd: + IDIVD(inst_op1_d,LoadD,0); + goto nextopcode; + case O_AAM: + AAM(inst_op1_b); + goto nextopcode; + case O_AAD: + AAD(inst_op1_b); + goto nextopcode; + + case O_C_O: inst.cond=TFLG_O; break; + case O_C_NO: inst.cond=TFLG_NO; break; + case O_C_B: inst.cond=TFLG_B; break; + case O_C_NB: inst.cond=TFLG_NB; break; + case O_C_Z: inst.cond=TFLG_Z; break; + case O_C_NZ: inst.cond=TFLG_NZ; break; + case O_C_BE: inst.cond=TFLG_BE; break; + case O_C_NBE: inst.cond=TFLG_NBE; break; + case O_C_S: inst.cond=TFLG_S; break; + case O_C_NS: inst.cond=TFLG_NS; break; + case O_C_P: inst.cond=TFLG_P; break; + case O_C_NP: inst.cond=TFLG_NP; break; + case O_C_L: inst.cond=TFLG_L; break; + case O_C_NL: inst.cond=TFLG_NL; break; + case O_C_LE: inst.cond=TFLG_LE; break; + case O_C_NLE: inst.cond=TFLG_NLE; break; + + case O_ALOP: + reg_al=LoadMb(inst.rm_eaa); + goto nextopcode; + case O_AXOP: + reg_ax=LoadMw(inst.rm_eaa); + goto nextopcode; + case O_EAXOP: + reg_eax=LoadMd(inst.rm_eaa); + goto nextopcode; + case O_OPAL: + SaveMb(inst.rm_eaa,reg_al); + goto nextopcode; + case O_OPAX: + SaveMw(inst.rm_eaa,reg_ax); + goto nextopcode; + case O_OPEAX: + SaveMd(inst.rm_eaa,reg_eax); + goto nextopcode; + case O_SEGDS: + inst.code.extra=ds; + break; + case O_SEGES: + inst.code.extra=es; + break; + case O_SEGFS: + inst.code.extra=fs; + break; + case O_SEGGS: + inst.code.extra=gs; + break; + case O_SEGSS: + inst.code.extra=ss; + break; + + case O_LOOP: + if (inst.prefix & PREFIX_ADDR) { + if (--reg_ecx) break; + } else { + if (--reg_cx) break; + } + goto nextopcode; + case O_LOOPZ: + if (inst.prefix & PREFIX_ADDR) { + if (--reg_ecx && get_ZF()) break; + } else { + if (--reg_cx && get_ZF()) break; + } + goto nextopcode; + case O_LOOPNZ: + if (inst.prefix & PREFIX_ADDR) { + if (--reg_ecx && !get_ZF()) break; + } else { + if (--reg_cx && !get_ZF()) break; + } + goto nextopcode; + case O_JCXZ: + if (inst.prefix & PREFIX_ADDR) { + if (reg_ecx) goto nextopcode; + } else { + if (reg_cx) goto nextopcode; + } + break; + case O_XCHG_AX: + { + Bit16u temp=reg_ax; + reg_ax=inst_op1_w; + inst_op1_w=temp; + break; + } + case O_XCHG_EAX: + { + Bit32u temp=reg_eax; + reg_eax=inst_op1_d; + inst_op1_d=temp; + break; + } + case O_CALLNw: + SaveIP(); + Push_16(reg_ip); + break; + case O_CALLNd: + SaveIP(); + Push_32(reg_eip); + break; + case O_CALLFw: + FillFlags(); + CPU_CALL(false,inst_op2_d,inst_op1_d,GetIP()); + continue; + case O_CALLFd: + FillFlags(); + CPU_CALL(true,inst_op2_d,inst_op1_d,GetIP()); + continue; + case O_JMPFw: + FillFlags(); + CPU_JMP(false,inst_op2_d,inst_op1_d,GetIP()); + continue; + case O_JMPFd: + FillFlags(); + CPU_JMP(true,inst_op2_d,inst_op1_d,GetIP()); + continue; + case O_INT: +#if C_DEBUG + FillFlags(); + if (((inst.entry & 0xFF)==0xcc) && DEBUG_Breakpoint()) + return debugCallback; + else if (DEBUG_IntBreakpoint(inst_op1_b)) + return debugCallback; +#endif + CPU_SW_Interrupt(inst_op1_b,GetIP()); + continue; + case O_INb: + if (CPU_IO_Exception(inst_op1_d,1)) RunException(); + reg_al=IO_ReadB(inst_op1_d); + goto nextopcode; + case O_INw: + if (CPU_IO_Exception(inst_op1_d,2)) RunException(); + reg_ax=IO_ReadW(inst_op1_d); + goto nextopcode; + case O_INd: + if (CPU_IO_Exception(inst_op1_d,4)) RunException(); + reg_eax=IO_ReadD(inst_op1_d); + goto nextopcode; + case O_OUTb: + if (CPU_IO_Exception(inst_op1_d,1)) RunException(); + IO_WriteB(inst_op1_d,reg_al); + goto nextopcode; + case O_OUTw: + if (CPU_IO_Exception(inst_op1_d,2)) RunException(); + IO_WriteW(inst_op1_d,reg_ax); + goto nextopcode; + case O_OUTd: + if (CPU_IO_Exception(inst_op1_d,4)) RunException(); + IO_WriteD(inst_op1_d,reg_eax); + goto nextopcode; + case O_CBACK: + FillFlags();SaveIP(); + return inst_op1_d; + case O_GRP6w: + case O_GRP6d: + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegalopcode; + switch (inst.rm_index) { + case 0x00: /* SLDT */ + inst_op1_d=(Bit32u)CPU_SLDT(); + break; + case 0x01: /* STR */ + inst_op1_d=(Bit32u)CPU_STR(); + break; + case 0x02: /* LLDT */ + if (cpu.cpl) EXCEPTION(EXCEPTION_GP); + if (CPU_LLDT(inst_op1_d)) RunException(); + goto nextopcode; /* Else value will saved */ + case 0x03: /* LTR */ + if (cpu.cpl) EXCEPTION(EXCEPTION_GP); + if (CPU_LTR(inst_op1_d)) RunException(); + goto nextopcode; /* Else value will saved */ + case 0x04: /* VERR */ + CPU_VERR(inst_op1_d); + goto nextopcode; /* Else value will saved */ + case 0x05: /* VERW */ + CPU_VERW(inst_op1_d); + goto nextopcode; /* Else value will saved */ + default: + LOG(LOG_CPU,LOG_ERROR)("Group 6 Illegal subfunction %X",inst.rm_index); + goto illegalopcode; + } + break; + case O_GRP7w: + case O_GRP7d: + switch (inst.rm_index) { + case 0: /* SGDT */ + SaveMw(inst.rm_eaa,CPU_SGDT_limit()); + SaveMd(inst.rm_eaa+2,CPU_SGDT_base()); + goto nextopcode; + case 1: /* SIDT */ + SaveMw(inst.rm_eaa,CPU_SIDT_limit()); + SaveMd(inst.rm_eaa+2,CPU_SIDT_base()); + goto nextopcode; + case 2: /* LGDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + CPU_LGDT(LoadMw(inst.rm_eaa),LoadMd(inst.rm_eaa+2)&((inst.code.op == O_GRP7w) ? 0xFFFFFF : 0xFFFFFFFF)); + goto nextopcode; + case 3: /* LIDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + CPU_LIDT(LoadMw(inst.rm_eaa),LoadMd(inst.rm_eaa+2)&((inst.code.op == O_GRP7w) ? 0xFFFFFF : 0xFFFFFFFF)); + goto nextopcode; + case 4: /* SMSW */ + inst_op1_d=CPU_SMSW(); + break; + case 6: /* LMSW */ + FillFlags(); + if (CPU_LMSW(inst_op1_w)) RunException(); + goto nextopcode; + case 7: /* INVLPG */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + FillFlags(); + PAGING_ClearTLB(); + goto nextopcode; + default: + LOG(LOG_CPU,LOG_ERROR)("Group 7 Illegal subfunction %X",inst.rm_index); + goto illegalopcode; + } + break; + case O_M_CRx_Rd: + if (CPU_WRITE_CRX(inst.rm_index,inst_op1_d)) RunException(); + break; + case O_M_Rd_CRx: + if (CPU_READ_CRX(inst.rm_index,inst_op1_d)) RunException(); + break; + case O_M_DRx_Rd: + if (CPU_WRITE_DRX(inst.rm_index,inst_op1_d)) RunException(); + break; + case O_M_Rd_DRx: + if (CPU_READ_DRX(inst.rm_index,inst_op1_d)) RunException(); + break; + case O_M_TRx_Rd: + if (CPU_WRITE_TRX(inst.rm_index,inst_op1_d)) RunException(); + break; + case O_M_Rd_TRx: + if (CPU_READ_TRX(inst.rm_index,inst_op1_d)) RunException(); + break; + case O_LAR: + { + Bitu ar=inst_op2_d; + CPU_LAR(inst_op1_w,ar); + inst_op1_d=(Bit32u)ar; + } + break; + case O_LSL: + { + Bitu limit=inst_op2_d; + CPU_LSL(inst_op1_w,limit); + inst_op1_d=(Bit32u)limit; + } + break; + case O_ARPL: + { + Bitu new_sel=inst_op1_d; + CPU_ARPL(new_sel,inst_op2_d); + inst_op1_d=(Bit32u)new_sel; + } + break; + case O_BSFw: + { + FillFlags(); + if (!inst_op1_w) { + SETFLAGBIT(ZF,true); + goto nextopcode; + } else { + Bitu count=0; + while (1) { + if (inst_op1_w & 0x1) break; + count++;inst_op1_w>>=1; + } + inst_op1_d=count; + SETFLAGBIT(ZF,false); + } + } + break; + case O_BSFd: + { + FillFlags(); + if (!inst_op1_d) { + SETFLAGBIT(ZF,true); + goto nextopcode; + } else { + Bitu count=0; + while (1) { + if (inst_op1_d & 0x1) break; + count++;inst_op1_d>>=1; + } + inst_op1_d=count; + SETFLAGBIT(ZF,false); + } + } + break; + case O_BSRw: + { + FillFlags(); + if (!inst_op1_w) { + SETFLAGBIT(ZF,true); + goto nextopcode; + } else { + Bitu count=15; + while (1) { + if (inst_op1_w & 0x8000) break; + count--;inst_op1_w<<=1; + } + inst_op1_d=count; + SETFLAGBIT(ZF,false); + } + } + break; + case O_BSRd: + { + FillFlags(); + if (!inst_op1_d) { + SETFLAGBIT(ZF,true); + goto nextopcode; + } else { + Bitu count=31; + while (1) { + if (inst_op1_d & 0x80000000) break; + count--;inst_op1_d<<=1; + } + inst_op1_d=count; + SETFLAGBIT(ZF,false); + } + } + break; + case O_BTw: + FillFlags(); + SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 15)))); + break; + case O_BTSw: + FillFlags(); + SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 15)))); + inst_op1_d|=(1 << (inst_op2_d & 15)); + break; + case O_BTCw: + FillFlags(); + SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 15)))); + inst_op1_d^=(1 << (inst_op2_d & 15)); + break; + case O_BTRw: + FillFlags(); + SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 15)))); + inst_op1_d&=~(1 << (inst_op2_d & 15)); + break; + case O_BTd: + FillFlags(); + SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 31)))); + break; + case O_BTSd: + FillFlags(); + SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 31)))); + inst_op1_d|=(1 << (inst_op2_d & 31)); + break; + case O_BTCd: + FillFlags(); + SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 31)))); + inst_op1_d^=(1 << (inst_op2_d & 31)); + break; + case O_BTRd: + FillFlags(); + SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 31)))); + inst_op1_d&=~(1 << (inst_op2_d & 31)); + break; + case O_BSWAPw: + if (CPU_ArchitectureType=0xc0) << 3) | inst.code.save) { + case 0x00: FPU_ESC0_EA(inst.rm,inst.rm_eaa);break; + case 0x01: FPU_ESC1_EA(inst.rm,inst.rm_eaa);break; + case 0x02: FPU_ESC2_EA(inst.rm,inst.rm_eaa);break; + case 0x03: FPU_ESC3_EA(inst.rm,inst.rm_eaa);break; + case 0x04: FPU_ESC4_EA(inst.rm,inst.rm_eaa);break; + case 0x05: FPU_ESC5_EA(inst.rm,inst.rm_eaa);break; + case 0x06: FPU_ESC6_EA(inst.rm,inst.rm_eaa);break; + case 0x07: FPU_ESC7_EA(inst.rm,inst.rm_eaa);break; + + case 0x08: FPU_ESC0_Normal(inst.rm);break; + case 0x09: FPU_ESC1_Normal(inst.rm);break; + case 0x0a: FPU_ESC2_Normal(inst.rm);break; + case 0x0b: FPU_ESC3_Normal(inst.rm);break; + case 0x0c: FPU_ESC4_Normal(inst.rm);break; + case 0x0d: FPU_ESC5_Normal(inst.rm);break; + case 0x0e: FPU_ESC6_Normal(inst.rm);break; + case 0x0f: FPU_ESC7_Normal(inst.rm);break; + } + } + goto nextopcode; +#else + LOG(LOG_CPU,LOG_ERROR)("Unhandled FPU ESCAPE %d",inst.code.save); + goto nextopcode; +#endif + case O_BOUNDw: + { + Bit16s bound_min, bound_max; + bound_min=LoadMw(inst.rm_eaa); + bound_max=LoadMw(inst.rm_eaa+2); + if ( (((Bit16s)inst_op1_w) < bound_min) || (((Bit16s)inst_op1_w) > bound_max) ) { + EXCEPTION(5); + } + } + break; + case 0: + break; + default: + LOG(LOG_CPU,LOG_ERROR)("OP:Unhandled code %d entry %X",inst.code.op,inst.entry); + +} diff --git a/dosbox/core_full/optable.h b/dosbox/core_full/optable.h new file mode 100644 index 00000000..a938a8fe --- /dev/null +++ b/dosbox/core_full/optable.h @@ -0,0 +1,814 @@ +/* Big ass opcode table normal,double, 66 normal, 66 double */ +static OpCode OpCodeTable[1024]={ +/* 0x00 - 0x07 */ +{L_MODRM ,t_ADDb ,S_Eb ,M_EbGb },{L_MODRM ,t_ADDw ,S_Ew ,M_EwGw }, +{L_MODRM ,t_ADDb ,S_Gb ,M_GbEb },{L_MODRM ,t_ADDw ,S_Gw ,M_GwEw }, +{L_REGbIb ,t_ADDb ,S_REGb ,REGI_AL },{L_REGwIw ,t_ADDw ,S_REGw ,REGI_AX }, +{L_SEG ,0 ,S_PUSHw,es },{D_POPSEGw,0 ,0 ,es }, +/* 0x08 - 0x0f */ +{L_MODRM ,t_ORb ,S_Eb ,M_EbGb },{L_MODRM ,t_ORw ,S_Ew ,M_EwGw }, +{L_MODRM ,t_ORb ,S_Gb ,M_GbEb },{L_MODRM ,t_ORw ,S_Gw ,M_GwEw }, +{L_REGbIb ,t_ORb ,S_REGb ,REGI_AL },{L_REGwIw ,t_ORw ,S_REGw ,REGI_AX }, +{L_SEG ,0 ,S_PUSHw,cs },{L_DOUBLE ,0 ,0 ,0 }, + +/* 0x10 - 0x17 */ +{L_MODRM ,t_ADCb ,S_Eb ,M_EbGb },{L_MODRM ,t_ADCw ,S_Ew ,M_EwGw }, +{L_MODRM ,t_ADCb ,S_Gb ,M_GbEb },{L_MODRM ,t_ADCw ,S_Gw ,M_GwEw }, +{L_REGbIb ,t_ADCb ,S_REGb ,REGI_AL },{L_REGwIw ,t_ADCw ,S_REGw ,REGI_AX }, +{L_SEG ,0 ,S_PUSHw,ss },{D_POPSEGw,0 ,0 ,ss }, +/* 0x18 - 0x1f */ +{L_MODRM ,t_SBBb ,S_Eb ,M_EbGb },{L_MODRM ,t_SBBw ,S_Ew ,M_EwGw }, +{L_MODRM ,t_SBBb ,S_Gb ,M_GbEb },{L_MODRM ,t_SBBw ,S_Gw ,M_GwEw }, +{L_REGbIb ,t_SBBb ,S_REGb ,REGI_AL },{L_REGwIw ,t_SBBw ,S_REGw ,REGI_AX }, +{L_SEG ,0 ,S_PUSHw,ds },{D_POPSEGw,0 ,0 ,ds }, + +/* 0x20 - 0x27 */ +{L_MODRM ,t_ANDb ,S_Eb ,M_EbGb },{L_MODRM ,t_ANDw ,S_Ew ,M_EwGw }, +{L_MODRM ,t_ANDb ,S_Gb ,M_GbEb },{L_MODRM ,t_ANDw ,S_Gw ,M_GwEw }, +{L_REGbIb ,t_ANDb ,S_REGb ,REGI_AL },{L_REGwIw ,t_ANDw ,S_REGw ,REGI_AX }, +{L_PRESEG ,0 ,0 ,es },{D_DAA ,0 ,0 ,0 }, +/* 0x28 - 0x2f */ +{L_MODRM ,t_SUBb ,S_Eb ,M_EbGb },{L_MODRM ,t_SUBw ,S_Ew ,M_EwGw }, +{L_MODRM ,t_SUBb ,S_Gb ,M_GbEb },{L_MODRM ,t_SUBw ,S_Gw ,M_GwEw }, +{L_REGbIb ,t_SUBb ,S_REGb ,REGI_AL },{L_REGwIw ,t_SUBw ,S_REGw ,REGI_AX }, +{L_PRESEG ,0 ,0 ,cs },{D_DAS ,0 ,0 ,0 }, + +/* 0x30 - 0x37 */ +{L_MODRM ,t_XORb ,S_Eb ,M_EbGb },{L_MODRM ,t_XORw ,S_Ew ,M_EwGw }, +{L_MODRM ,t_XORb ,S_Gb ,M_GbEb },{L_MODRM ,t_XORw ,S_Gw ,M_GwEw }, +{L_REGbIb ,t_XORb ,S_REGb ,REGI_AL },{L_REGwIw ,t_XORw ,S_REGw ,REGI_AX }, +{L_PRESEG ,0 ,0 ,ss },{D_AAA ,0 ,0 ,0 }, +/* 0x38 - 0x3f */ +{L_MODRM ,t_CMPb ,0 ,M_EbGb },{L_MODRM ,t_CMPw ,0 ,M_EwGw }, +{L_MODRM ,t_CMPb ,0 ,M_GbEb },{L_MODRM ,t_CMPw ,0 ,M_GwEw }, +{L_REGbIb ,t_CMPb ,0 ,REGI_AL },{L_REGwIw ,t_CMPw ,0 ,REGI_AX }, +{L_PRESEG ,0 ,0 ,ds },{D_AAS ,0 ,0 ,0 }, + +/* 0x40 - 0x47 */ +{L_REGw ,t_INCw ,S_REGw ,REGI_AX},{L_REGw ,t_INCw ,S_REGw ,REGI_CX}, +{L_REGw ,t_INCw ,S_REGw ,REGI_DX},{L_REGw ,t_INCw ,S_REGw ,REGI_BX}, +{L_REGw ,t_INCw ,S_REGw ,REGI_SP},{L_REGw ,t_INCw ,S_REGw ,REGI_BP}, +{L_REGw ,t_INCw ,S_REGw ,REGI_SI},{L_REGw ,t_INCw ,S_REGw ,REGI_DI}, +/* 0x48 - 0x4f */ +{L_REGw ,t_DECw ,S_REGw ,REGI_AX},{L_REGw ,t_DECw ,S_REGw ,REGI_CX}, +{L_REGw ,t_DECw ,S_REGw ,REGI_DX},{L_REGw ,t_DECw ,S_REGw ,REGI_BX}, +{L_REGw ,t_DECw ,S_REGw ,REGI_SP},{L_REGw ,t_DECw ,S_REGw ,REGI_BP}, +{L_REGw ,t_DECw ,S_REGw ,REGI_SI},{L_REGw ,t_DECw ,S_REGw ,REGI_DI}, + +/* 0x50 - 0x57 */ +{L_REGw ,0 ,S_PUSHw,REGI_AX},{L_REGw ,0 ,S_PUSHw,REGI_CX}, +{L_REGw ,0 ,S_PUSHw,REGI_DX},{L_REGw ,0 ,S_PUSHw,REGI_BX}, +{L_REGw ,0 ,S_PUSHw,REGI_SP},{L_REGw ,0 ,S_PUSHw,REGI_BP}, +{L_REGw ,0 ,S_PUSHw,REGI_SI},{L_REGw ,0 ,S_PUSHw,REGI_DI}, +/* 0x58 - 0x5f */ +{L_POPw ,0 ,S_REGw ,REGI_AX},{L_POPw ,0 ,S_REGw ,REGI_CX}, +{L_POPw ,0 ,S_REGw ,REGI_DX},{L_POPw ,0 ,S_REGw ,REGI_BX}, +{L_POPw ,0 ,S_REGw ,REGI_SP},{L_POPw ,0 ,S_REGw ,REGI_BP}, +{L_POPw ,0 ,S_REGw ,REGI_SI},{L_POPw ,0 ,S_REGw ,REGI_DI}, + + +/* 0x60 - 0x67 */ +{D_PUSHAw ,0 ,0 ,0 },{D_POPAw ,0 ,0 ,0 }, +{L_MODRM ,O_BOUNDw ,0 ,M_Gw },{L_MODRM_NVM ,O_ARPL ,S_Ew ,M_EwGw }, +{L_PRESEG ,0 ,0 ,fs },{L_PRESEG ,0 ,0 ,gs }, +{L_PREOP ,0 ,0 ,0 },{L_PREADD ,0 ,0 ,0 }, +/* 0x68 - 0x6f */ +{L_Iw ,0 ,S_PUSHw,0 },{L_MODRM ,O_IMULRw ,S_Gw ,M_EwxIwx}, +{L_Ibx ,0 ,S_PUSHw,0 },{L_MODRM ,O_IMULRw ,S_Gw ,M_EwxIbx}, +{L_STRING ,R_INSB ,0 ,0 },{L_STRING ,R_INSW ,0 ,0 }, +{L_STRING ,R_OUTSB ,0 ,0 },{L_STRING ,R_OUTSW ,0 ,0 }, + + +/* 0x70 - 0x77 */ +{L_Ibx ,O_C_O ,S_C_AIPw,0 },{L_Ibx ,O_C_NO ,S_C_AIPw,0 }, +{L_Ibx ,O_C_B ,S_C_AIPw,0 },{L_Ibx ,O_C_NB ,S_C_AIPw,0 }, +{L_Ibx ,O_C_Z ,S_C_AIPw,0 },{L_Ibx ,O_C_NZ ,S_C_AIPw,0 }, +{L_Ibx ,O_C_BE ,S_C_AIPw,0 },{L_Ibx ,O_C_NBE ,S_C_AIPw,0 }, +/* 0x78 - 0x7f */ +{L_Ibx ,O_C_S ,S_C_AIPw,0 },{L_Ibx ,O_C_NS ,S_C_AIPw,0 }, +{L_Ibx ,O_C_P ,S_C_AIPw,0 },{L_Ibx ,O_C_NP ,S_C_AIPw,0 }, +{L_Ibx ,O_C_L ,S_C_AIPw,0 },{L_Ibx ,O_C_NL ,S_C_AIPw,0 }, +{L_Ibx ,O_C_LE ,S_C_AIPw,0 },{L_Ibx ,O_C_NLE ,S_C_AIPw,0 }, + + +/* 0x80 - 0x87 */ +{L_MODRM ,0 ,0 ,M_GRP },{L_MODRM ,1 ,0 ,M_GRP }, +{L_MODRM ,0 ,0 ,M_GRP },{L_MODRM ,3 ,0 ,M_GRP }, +{L_MODRM ,t_TESTb ,0 ,M_EbGb },{L_MODRM ,t_TESTw ,0 ,M_EwGw }, +{L_MODRM ,0 ,S_EbGb ,M_GbEb },{L_MODRM ,0 ,S_EwGw ,M_GwEw }, +/* 0x88 - 0x8f */ +{L_MODRM ,0 ,S_Eb ,M_Gb },{L_MODRM ,0 ,S_Ew ,M_Gw }, +{L_MODRM ,0 ,S_Gb ,M_Eb },{L_MODRM ,0 ,S_Gw ,M_Ew }, +{L_MODRM ,0 ,S_Ew ,M_SEG },{L_MODRM ,0 ,S_Gw ,M_EA }, +{L_MODRM ,0 ,S_SEGm ,M_Ew },{L_POPwRM ,0 ,S_Ew ,M_None }, + +/* 0x90 - 0x97 */ +{D_NOP ,0 ,0 ,0 },{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_CX}, +{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_DX},{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_BX}, +{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_SP},{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_BP}, +{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_SI},{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_DI}, +/* 0x98 - 0x9f */ +{D_CBW ,0 ,0 ,0 },{D_CWD ,0 ,0 ,0 }, +{L_Ifw ,O_CALLFw ,0 ,0 },{D_WAIT ,0 ,0 ,0 }, +{D_PUSHF ,0 ,0 ,0 },{D_POPF ,0 ,0 ,0 }, +{D_SAHF ,0 ,0 ,0 },{D_LAHF ,0 ,0 ,0 }, + + +/* 0xa0 - 0xa7 */ +{L_OP ,O_ALOP ,0 ,0 },{L_OP ,O_AXOP ,0 ,0 }, +{L_OP ,O_OPAL ,0 ,0 },{L_OP ,O_OPAX ,0 ,0 }, +{L_STRING ,R_MOVSB ,0 ,0 },{L_STRING ,R_MOVSW ,0 ,0 }, +{L_STRING ,R_CMPSB ,0 ,0 },{L_STRING ,R_CMPSW ,0 ,0 }, +/* 0xa8 - 0xaf */ +{L_REGbIb ,t_TESTb ,0 ,REGI_AL},{L_REGwIw ,t_TESTw ,0 ,REGI_AX}, +{L_STRING ,R_STOSB ,0 ,0 },{L_STRING ,R_STOSW ,0 ,0 }, +{L_STRING ,R_LODSB ,0 ,0 },{L_STRING ,R_LODSW ,0 ,0 }, +{L_STRING ,R_SCASB ,0 ,0 },{L_STRING ,R_SCASW ,0 ,0 }, + +/* 0xb0 - 0xb7 */ +{L_Ib ,0 ,S_REGb ,REGI_AL},{L_Ib ,0 ,S_REGb ,REGI_CL}, +{L_Ib ,0 ,S_REGb ,REGI_DL},{L_Ib ,0 ,S_REGb ,REGI_BL}, +{L_Ib ,0 ,S_REGb ,REGI_AH},{L_Ib ,0 ,S_REGb ,REGI_CH}, +{L_Ib ,0 ,S_REGb ,REGI_DH},{L_Ib ,0 ,S_REGb ,REGI_BH}, +/* 0xb8 - 0xbf */ +{L_Iw ,0 ,S_REGw ,REGI_AX},{L_Iw ,0 ,S_REGw ,REGI_CX}, +{L_Iw ,0 ,S_REGw ,REGI_DX},{L_Iw ,0 ,S_REGw ,REGI_BX}, +{L_Iw ,0 ,S_REGw ,REGI_SP},{L_Iw ,0 ,S_REGw ,REGI_BP}, +{L_Iw ,0 ,S_REGw ,REGI_SI},{L_Iw ,0 ,S_REGw ,REGI_DI}, + +/* 0xc0 - 0xc7 */ +{L_MODRM ,5 ,0 ,M_GRP_Ib },{L_MODRM ,6 ,0 ,M_GRP_Ib }, +{L_POPw ,0 ,S_IPIw ,0 },{L_POPw ,0 ,S_IP ,0 }, +{L_MODRM ,O_SEGES ,S_SEGGw,M_Efw },{L_MODRM ,O_SEGDS ,S_SEGGw,M_Efw }, +{L_MODRM ,0 ,S_Eb ,M_Ib },{L_MODRM ,0 ,S_Ew ,M_Iw }, +/* 0xc8 - 0xcf */ +{D_ENTERw ,0 ,0 ,0 },{D_LEAVEw ,0 ,0 ,0 }, +{D_RETFwIw ,0 ,0 ,0 },{D_RETFw ,0 ,0 ,0 }, +{L_VAL ,O_INT ,0 ,3 },{L_Ib ,O_INT ,0 ,0 }, +{L_INTO ,O_INT ,0 ,0 },{D_IRETw ,0 ,0 ,0 }, + +/* 0xd0 - 0xd7 */ +{L_MODRM ,5 ,0 ,M_GRP_1 },{L_MODRM ,6 ,0 ,M_GRP_1 }, +{L_MODRM ,5 ,0 ,M_GRP_CL },{L_MODRM ,6 ,0 ,M_GRP_CL }, +{L_Ib ,O_AAM ,0 ,0 },{L_Ib ,O_AAD ,0 ,0 }, +{D_SETALC ,0 ,0 ,0 },{D_XLAT ,0 ,0 ,0 }, +//TODO FPU +/* 0xd8 - 0xdf */ +{L_MODRM ,O_FPU ,0 ,0 },{L_MODRM ,O_FPU ,1 ,0 }, +{L_MODRM ,O_FPU ,2 ,0 },{L_MODRM ,O_FPU ,3 ,0 }, +{L_MODRM ,O_FPU ,4 ,0 },{L_MODRM ,O_FPU ,5 ,0 }, +{L_MODRM ,O_FPU ,6 ,0 },{L_MODRM ,O_FPU ,7 ,0 }, + +/* 0xe0 - 0xe7 */ +{L_Ibx ,O_LOOPNZ ,S_AIPw ,0 },{L_Ibx ,O_LOOPZ ,S_AIPw ,0 }, +{L_Ibx ,O_LOOP ,S_AIPw ,0 },{L_Ibx ,O_JCXZ ,S_AIPw ,0 }, +{L_Ib ,O_INb ,0 ,0 },{L_Ib ,O_INw ,0 ,0 }, +{L_Ib ,O_OUTb ,0 ,0 },{L_Ib ,O_OUTw ,0 ,0 }, +/* 0xe8 - 0xef */ +{L_Iw ,O_CALLNw ,S_AIPw ,0 },{L_Iwx ,0 ,S_AIPw ,0 }, +{L_Ifw ,O_JMPFw ,0 ,0 },{L_Ibx ,0 ,S_AIPw ,0 }, +{L_REGw ,O_INb ,0 ,REGI_DX},{L_REGw ,O_INw ,0 ,REGI_DX}, +{L_REGw ,O_OUTb ,0 ,REGI_DX},{L_REGw ,O_OUTw ,0 ,REGI_DX}, + +/* 0xf0 - 0xf7 */ +{D_LOCK ,0 ,0 ,0 },{D_ICEBP ,0 ,0 ,0 }, +{L_PREREPNE ,0 ,0 ,0 },{L_PREREP ,0 ,0 ,0 }, +{D_HLT ,0 ,0 ,0 },{D_CMC ,0 ,0 ,0 }, +{L_MODRM ,8 ,0 ,M_GRP },{L_MODRM ,9 ,0 ,M_GRP }, +/* 0xf8 - 0xff */ +{D_CLC ,0 ,0 ,0 },{D_STC ,0 ,0 ,0 }, +{D_CLI ,0 ,0 ,0 },{D_STI ,0 ,0 ,0 }, +{D_CLD ,0 ,0 ,0 },{D_STD ,0 ,0 ,0 }, +{L_MODRM ,0xb ,0 ,M_GRP },{L_MODRM ,0xc ,0 ,M_GRP }, + +/* 0x100 - 0x107 */ +{L_MODRM ,O_GRP6w ,S_Ew ,M_Ew },{L_MODRM ,O_GRP7w ,S_Ew ,M_Ew }, +{L_MODRM_NVM ,O_LAR ,S_Gw ,M_EwGw },{L_MODRM_NVM ,O_LSL ,S_Gw ,M_EwGw }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{D_CLTS ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x108 - 0x10f */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +/* 0x110 - 0x117 */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x118 - 0x11f */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +/* 0x120 - 0x127 */ +{L_MODRM ,O_M_Rd_CRx ,S_Ed ,0 },{L_MODRM ,O_M_Rd_DRx ,S_Ed ,0 }, +{L_MODRM ,O_M_CRx_Rd ,0 ,M_Ed },{L_MODRM ,O_M_DRx_Rd ,0 ,M_Ed }, +{L_MODRM ,O_M_Rd_TRx ,S_Ed ,0 },{0 ,0 ,0 ,0 }, +{L_MODRM ,O_M_TRx_Rd ,0 ,M_Ed },{0 ,0 ,0 ,0 }, + +/* 0x128 - 0x12f */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +/* 0x130 - 0x137 */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x138 - 0x13f */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +/* 0x140 - 0x147 */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x148 - 0x14f */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +/* 0x150 - 0x157 */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x158 - 0x15f */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +/* 0x160 - 0x167 */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x168 - 0x16f */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + + +/* 0x170 - 0x177 */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x178 - 0x17f */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +/* 0x180 - 0x187 */ +{L_Iwx ,O_C_O ,S_C_AIPw,0 },{L_Iwx ,O_C_NO ,S_C_AIPw,0 }, +{L_Iwx ,O_C_B ,S_C_AIPw,0 },{L_Iwx ,O_C_NB ,S_C_AIPw,0 }, +{L_Iwx ,O_C_Z ,S_C_AIPw,0 },{L_Iwx ,O_C_NZ ,S_C_AIPw,0 }, +{L_Iwx ,O_C_BE ,S_C_AIPw,0 },{L_Iwx ,O_C_NBE ,S_C_AIPw,0 }, +/* 0x188 - 0x18f */ +{L_Iwx ,O_C_S ,S_C_AIPw,0 },{L_Iwx ,O_C_NS ,S_C_AIPw,0 }, +{L_Iwx ,O_C_P ,S_C_AIPw,0 },{L_Iwx ,O_C_NP ,S_C_AIPw,0 }, +{L_Iwx ,O_C_L ,S_C_AIPw,0 },{L_Iwx ,O_C_NL ,S_C_AIPw,0 }, +{L_Iwx ,O_C_LE ,S_C_AIPw,0 },{L_Iwx ,O_C_NLE ,S_C_AIPw,0 }, + +/* 0x190 - 0x197 */ +{L_MODRM ,O_C_O ,S_C_Eb,0 },{L_MODRM ,O_C_NO ,S_C_Eb,0 }, +{L_MODRM ,O_C_B ,S_C_Eb,0 },{L_MODRM ,O_C_NB ,S_C_Eb,0 }, +{L_MODRM ,O_C_Z ,S_C_Eb,0 },{L_MODRM ,O_C_NZ ,S_C_Eb,0 }, +{L_MODRM ,O_C_BE ,S_C_Eb,0 },{L_MODRM ,O_C_NBE ,S_C_Eb,0 }, +/* 0x198 - 0x19f */ +{L_MODRM ,O_C_S ,S_C_Eb,0 },{L_MODRM ,O_C_NS ,S_C_Eb,0 }, +{L_MODRM ,O_C_P ,S_C_Eb,0 },{L_MODRM ,O_C_NP ,S_C_Eb,0 }, +{L_MODRM ,O_C_L ,S_C_Eb,0 },{L_MODRM ,O_C_NL ,S_C_Eb,0 }, +{L_MODRM ,O_C_LE ,S_C_Eb,0 },{L_MODRM ,O_C_NLE ,S_C_Eb,0 }, + +/* 0x1a0 - 0x1a7 */ +{L_SEG ,0 ,S_PUSHw ,fs },{D_POPSEGw,0 ,0 ,fs }, +{D_CPUID ,0 ,0 ,0 },{L_MODRM ,O_BTw ,S_Ew ,M_EwGwt }, +{L_MODRM ,O_DSHLw ,S_Ew,M_EwGwIb },{L_MODRM ,O_DSHLw ,S_Ew ,M_EwGwCL }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x1a8 - 0x1af */ +{L_SEG ,0 ,S_PUSHw ,gs },{D_POPSEGw,0 ,0 ,gs }, +{0 ,0 ,0 ,0 },{L_MODRM ,O_BTSw ,S_Ew ,M_EwGwt }, +{L_MODRM ,O_DSHRw ,S_Ew,M_EwGwIb },{L_MODRM ,O_DSHRw ,S_Ew ,M_EwGwCL }, +{0 ,0 ,0 ,0 },{L_MODRM ,O_IMULRw ,S_Gw ,M_EwxGwx }, + +/* 0x1b0 - 0x1b7 */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{L_MODRM ,O_SEGSS ,S_SEGGw,M_Efw },{L_MODRM ,O_BTRw ,S_Ew ,M_EwGwt }, +{L_MODRM ,O_SEGFS ,S_SEGGw,M_Efw },{L_MODRM ,O_SEGGS ,S_SEGGw,M_Efw }, +{L_MODRM ,0 ,S_Gw ,M_Eb },{L_MODRM ,0 ,S_Gw ,M_Ew }, +/* 0x1b8 - 0x1bf */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{L_MODRM ,0xe ,0 ,M_GRP },{L_MODRM ,O_BTCw ,S_Ew ,M_EwGwt }, +{L_MODRM ,O_BSFw ,S_Gw ,M_Ew },{L_MODRM ,O_BSRw ,S_Gw ,M_Ew }, +{L_MODRM ,0 ,S_Gw ,M_Ebx },{L_MODRM ,0 ,S_Gw ,M_Ewx }, + +/* 0x1c0 - 0x1cc */ +{L_MODRM ,t_ADDb ,S_EbGb ,M_GbEb },{L_MODRM ,t_ADDw ,S_EwGw ,M_GwEw }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x1c8 - 0x1cf */ +{L_REGw ,O_BSWAPw ,S_REGw ,REGI_AX},{L_REGw ,O_BSWAPw ,S_REGw ,REGI_CX}, +{L_REGw ,O_BSWAPw ,S_REGw ,REGI_DX},{L_REGw ,O_BSWAPw ,S_REGw ,REGI_BX}, +{L_REGw ,O_BSWAPw ,S_REGw ,REGI_SP},{L_REGw ,O_BSWAPw ,S_REGw ,REGI_BP}, +{L_REGw ,O_BSWAPw ,S_REGw ,REGI_SI},{L_REGw ,O_BSWAPw ,S_REGw ,REGI_DI}, + +/* 0x1d0 - 0x1d7 */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x1d8 - 0x1df */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +/* 0x1e0 - 0x1ee */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x1e8 - 0x1ef */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +/* 0x1f0 - 0x1fc */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x1f8 - 0x1ff */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + + +/* 0x200 - 0x207 */ +{L_MODRM ,t_ADDb ,S_Eb ,M_EbGb },{L_MODRM ,t_ADDd ,S_Ed ,M_EdGd }, +{L_MODRM ,t_ADDb ,S_Gb ,M_GbEb },{L_MODRM ,t_ADDd ,S_Gd ,M_GdEd }, +{L_REGbIb ,t_ADDb ,S_REGb ,REGI_AL },{L_REGdId ,t_ADDd ,S_REGd ,REGI_AX }, +{L_SEG ,0 ,S_PUSHd,es },{D_POPSEGd,0 ,0 ,es }, +/* 0x208 - 0x20f */ +{L_MODRM ,t_ORb ,S_Eb ,M_EbGb },{L_MODRM ,t_ORd ,S_Ed ,M_EdGd }, +{L_MODRM ,t_ORb ,S_Gb ,M_GbEb },{L_MODRM ,t_ORd ,S_Gd ,M_GdEd }, +{L_REGbIb ,t_ORb ,S_REGb ,REGI_AL },{L_REGdId ,t_ORd ,S_REGd ,REGI_AX }, +{L_SEG ,0 ,S_PUSHd,cs },{L_DOUBLE ,0 ,0 ,0 }, + +/* 0x210 - 0x217 */ +{L_MODRM ,t_ADCb ,S_Eb ,M_EbGb },{L_MODRM ,t_ADCd ,S_Ed ,M_EdGd }, +{L_MODRM ,t_ADCb ,S_Gb ,M_GbEb },{L_MODRM ,t_ADCd ,S_Gd ,M_GdEd }, +{L_REGbIb ,t_ADCb ,S_REGb ,REGI_AL },{L_REGdId ,t_ADCd ,S_REGd ,REGI_AX }, +{L_SEG ,0 ,S_PUSHd,ss },{D_POPSEGd,0 ,0 ,ss }, +/* 0x218 - 0x21f */ +{L_MODRM ,t_SBBb ,S_Eb ,M_EbGb },{L_MODRM ,t_SBBd ,S_Ed ,M_EdGd }, +{L_MODRM ,t_SBBb ,S_Gb ,M_GbEb },{L_MODRM ,t_SBBd ,S_Gd ,M_GdEd }, +{L_REGbIb ,t_SBBb ,S_REGb ,REGI_AL },{L_REGdId ,t_SBBd ,S_REGd ,REGI_AX }, +{L_SEG ,0 ,S_PUSHd,ds },{D_POPSEGd,0 ,0 ,ds }, + +/* 0x220 - 0x227 */ +{L_MODRM ,t_ANDb ,S_Eb ,M_EbGb },{L_MODRM ,t_ANDd ,S_Ed ,M_EdGd }, +{L_MODRM ,t_ANDb ,S_Gb ,M_GbEb },{L_MODRM ,t_ANDd ,S_Gd ,M_GdEd }, +{L_REGbIb ,t_ANDb ,S_REGb ,REGI_AL },{L_REGdId ,t_ANDd ,S_REGd ,REGI_AX }, +{L_PRESEG ,0 ,0 ,es },{D_DAA ,0 ,0 ,0 }, +/* 0x228 - 0x22f */ +{L_MODRM ,t_SUBb ,S_Eb ,M_EbGb },{L_MODRM ,t_SUBd ,S_Ed ,M_EdGd }, +{L_MODRM ,t_SUBb ,S_Gb ,M_GbEb },{L_MODRM ,t_SUBd ,S_Gd ,M_GdEd }, +{L_REGbIb ,t_SUBb ,S_REGb ,REGI_AL },{L_REGdId ,t_SUBd ,S_REGd ,REGI_AX }, +{L_PRESEG ,0 ,0 ,cs },{D_DAS ,0 ,0 ,0 }, + +/* 0x230 - 0x237 */ +{L_MODRM ,t_XORb ,S_Eb ,M_EbGb },{L_MODRM ,t_XORd ,S_Ed ,M_EdGd }, +{L_MODRM ,t_XORb ,S_Gb ,M_GbEb },{L_MODRM ,t_XORd ,S_Gd ,M_GdEd }, +{L_REGbIb ,t_XORb ,S_REGb ,REGI_AL },{L_REGdId ,t_XORd ,S_REGd ,REGI_AX }, +{L_PRESEG ,0 ,0 ,ss },{D_AAA ,0 ,0 ,0 }, +/* 0x238 - 0x23f */ +{L_MODRM ,t_CMPb ,0 ,M_EbGb },{L_MODRM ,t_CMPd ,0 ,M_EdGd }, +{L_MODRM ,t_CMPb ,0 ,M_GbEb },{L_MODRM ,t_CMPd ,0 ,M_GdEd }, +{L_REGbIb ,t_CMPb ,0 ,REGI_AL },{L_REGdId ,t_CMPd ,0 ,REGI_AX }, +{L_PRESEG ,0 ,0 ,ds },{D_AAS ,0 ,0 ,0 }, + +/* 0x240 - 0x247 */ +{L_REGd ,t_INCd ,S_REGd ,REGI_AX},{L_REGd ,t_INCd ,S_REGd ,REGI_CX}, +{L_REGd ,t_INCd ,S_REGd ,REGI_DX},{L_REGd ,t_INCd ,S_REGd ,REGI_BX}, +{L_REGd ,t_INCd ,S_REGd ,REGI_SP},{L_REGd ,t_INCd ,S_REGd ,REGI_BP}, +{L_REGd ,t_INCd ,S_REGd ,REGI_SI},{L_REGd ,t_INCd ,S_REGd ,REGI_DI}, +/* 0x248 - 0x24f */ +{L_REGd ,t_DECd ,S_REGd ,REGI_AX},{L_REGd ,t_DECd ,S_REGd ,REGI_CX}, +{L_REGd ,t_DECd ,S_REGd ,REGI_DX},{L_REGd ,t_DECd ,S_REGd ,REGI_BX}, +{L_REGd ,t_DECd ,S_REGd ,REGI_SP},{L_REGd ,t_DECd ,S_REGd ,REGI_BP}, +{L_REGd ,t_DECd ,S_REGd ,REGI_SI},{L_REGd ,t_DECd ,S_REGd ,REGI_DI}, + +/* 0x250 - 0x257 */ +{L_REGd ,0 ,S_PUSHd,REGI_AX},{L_REGd ,0 ,S_PUSHd,REGI_CX}, +{L_REGd ,0 ,S_PUSHd,REGI_DX},{L_REGd ,0 ,S_PUSHd,REGI_BX}, +{L_REGd ,0 ,S_PUSHd,REGI_SP},{L_REGd ,0 ,S_PUSHd,REGI_BP}, +{L_REGd ,0 ,S_PUSHd,REGI_SI},{L_REGd ,0 ,S_PUSHd,REGI_DI}, +/* 0x258 - 0x25f */ +{L_POPd ,0 ,S_REGd ,REGI_AX},{L_POPd ,0 ,S_REGd ,REGI_CX}, +{L_POPd ,0 ,S_REGd ,REGI_DX},{L_POPd ,0 ,S_REGd ,REGI_BX}, +{L_POPd ,0 ,S_REGd ,REGI_SP},{L_POPd ,0 ,S_REGd ,REGI_BP}, +{L_POPd ,0 ,S_REGd ,REGI_SI},{L_POPd ,0 ,S_REGd ,REGI_DI}, + +/* 0x260 - 0x267 */ +{D_PUSHAd ,0 ,0 ,0 },{D_POPAd ,0 ,0 ,0 }, +{L_MODRM ,O_BOUNDd ,0 ,0 },{0 ,0 ,0 ,0 }, +{L_PRESEG ,0 ,0 ,fs },{L_PRESEG ,0 ,0 ,gs }, +{L_PREOP ,0 ,0 ,0 },{L_PREADD ,0 ,0 ,0 }, +/* 0x268 - 0x26f */ +{L_Id ,0 ,S_PUSHd,0 },{L_MODRM ,O_IMULRd ,S_Gd ,M_EdId}, +{L_Ibx ,0 ,S_PUSHd,0 },{L_MODRM ,O_IMULRd ,S_Gd ,M_EdIbx}, +{L_STRING ,R_INSB ,0 ,0 },{L_STRING ,R_INSD ,0 ,0 }, +{L_STRING ,R_OUTSB ,0 ,0 },{L_STRING ,R_OUTSD ,0 ,0 }, + +/* 0x270 - 0x277 */ +{L_Ibx ,O_C_O ,S_C_AIPd,0 },{L_Ibx ,O_C_NO ,S_C_AIPd,0 }, +{L_Ibx ,O_C_B ,S_C_AIPd,0 },{L_Ibx ,O_C_NB ,S_C_AIPd,0 }, +{L_Ibx ,O_C_Z ,S_C_AIPd,0 },{L_Ibx ,O_C_NZ ,S_C_AIPd,0 }, +{L_Ibx ,O_C_BE ,S_C_AIPd,0 },{L_Ibx ,O_C_NBE ,S_C_AIPd,0 }, +/* 0x278 - 0x27f */ +{L_Ibx ,O_C_S ,S_C_AIPd,0 },{L_Ibx ,O_C_NS ,S_C_AIPd,0 }, +{L_Ibx ,O_C_P ,S_C_AIPd,0 },{L_Ibx ,O_C_NP ,S_C_AIPd,0 }, +{L_Ibx ,O_C_L ,S_C_AIPd,0 },{L_Ibx ,O_C_NL ,S_C_AIPd,0 }, +{L_Ibx ,O_C_LE ,S_C_AIPd,0 },{L_Ibx ,O_C_NLE ,S_C_AIPd,0 }, + +/* 0x280 - 0x287 */ +{L_MODRM ,0 ,0 ,M_GRP },{L_MODRM ,2 ,0 ,M_GRP }, +{L_MODRM ,0 ,0 ,M_GRP },{L_MODRM ,4 ,0 ,M_GRP }, +{L_MODRM ,t_TESTb ,0 ,M_EbGb },{L_MODRM ,t_TESTd ,0 ,M_EdGd }, +{L_MODRM ,0 ,S_EbGb ,M_GbEb },{L_MODRM ,0 ,S_EdGd ,M_GdEd }, +/* 0x288 - 0x28f */ +{L_MODRM ,0 ,S_Eb ,M_Gb },{L_MODRM ,0 ,S_Ed ,M_Gd }, +{L_MODRM ,0 ,S_Gb ,M_Eb },{L_MODRM ,0 ,S_Gd ,M_Ed }, +{L_MODRM ,0 ,S_EdMw ,M_SEG },{L_MODRM ,0 ,S_Gd ,M_EA }, +{L_MODRM ,0 ,S_SEGm ,M_Ew },{L_POPdRM ,0 ,S_Ed ,M_None }, + +/* 0x290 - 0x297 */ +{D_NOP ,0 ,0 ,0 },{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_CX}, +{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_DX},{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_BX}, +{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_SP},{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_BP}, +{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_SI},{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_DI}, +/* 0x298 - 0x29f */ +{D_CWDE ,0 ,0 ,0 },{D_CDQ ,0 ,0 ,0 }, +{L_Ifd ,O_CALLFd ,0 ,0 },{D_WAIT ,0 ,0 ,0 }, +{D_PUSHF ,0 ,0 ,true },{D_POPF ,0 ,0 ,true }, +{D_SAHF ,0 ,0 ,0 },{D_LAHF ,0 ,0 ,0 }, + +/* 0x2a0 - 0x2a7 */ +{L_OP ,O_ALOP ,0 ,0 },{L_OP ,O_EAXOP ,0 ,0 }, +{L_OP ,O_OPAL ,0 ,0 },{L_OP ,O_OPEAX ,0 ,0 }, +{L_STRING ,R_MOVSB ,0 ,0 },{L_STRING ,R_MOVSD ,0 ,0 }, +{L_STRING ,R_CMPSB ,0 ,0 },{L_STRING ,R_CMPSD ,0 ,0 }, +/* 0x2a8 - 0x2af */ +{L_REGbIb ,t_TESTb ,0 ,REGI_AL},{L_REGdId ,t_TESTd ,0 ,REGI_AX}, +{L_STRING ,R_STOSB ,0 ,0 },{L_STRING ,R_STOSD ,0 ,0 }, +{L_STRING ,R_LODSB ,0 ,0 },{L_STRING ,R_LODSD ,0 ,0 }, +{L_STRING ,R_SCASB ,0 ,0 },{L_STRING ,R_SCASD ,0 ,0 }, + +/* 0x2b0 - 0x2b7 */ +{L_Ib ,0 ,S_REGb ,REGI_AL},{L_Ib ,0 ,S_REGb ,REGI_CL}, +{L_Ib ,0 ,S_REGb ,REGI_DL},{L_Ib ,0 ,S_REGb ,REGI_BL}, +{L_Ib ,0 ,S_REGb ,REGI_AH},{L_Ib ,0 ,S_REGb ,REGI_CH}, +{L_Ib ,0 ,S_REGb ,REGI_DH},{L_Ib ,0 ,S_REGb ,REGI_BH}, +/* 0x2b8 - 0x2bf */ +{L_Id ,0 ,S_REGd ,REGI_AX},{L_Id ,0 ,S_REGd ,REGI_CX}, +{L_Id ,0 ,S_REGd ,REGI_DX},{L_Id ,0 ,S_REGd ,REGI_BX}, +{L_Id ,0 ,S_REGd ,REGI_SP},{L_Id ,0 ,S_REGd ,REGI_BP}, +{L_Id ,0 ,S_REGd ,REGI_SI},{L_Id ,0 ,S_REGd ,REGI_DI}, + +/* 0x2c0 - 0x2c7 */ +{L_MODRM ,5 ,0 ,M_GRP_Ib },{L_MODRM ,7 ,0 ,M_GRP_Ib }, +{L_POPd ,0 ,S_IPIw ,0 },{L_POPd ,0 ,S_IP ,0 }, +{L_MODRM ,O_SEGES ,S_SEGGd,M_Efd },{L_MODRM ,O_SEGDS ,S_SEGGd,M_Efd }, +{L_MODRM ,0 ,S_Eb ,M_Ib },{L_MODRM ,0 ,S_Ed ,M_Id }, +/* 0x2c8 - 0x2cf */ +{D_ENTERd ,0 ,0 ,0 },{D_LEAVEd ,0 ,0 ,0 }, +{D_RETFdIw ,0 ,0 ,0 },{D_RETFd ,0 ,0 ,0 }, +{L_VAL ,O_INT ,0 ,3 },{L_Ib ,O_INT ,0 ,0 }, +{L_INTO ,O_INT ,0 ,0 },{D_IRETd ,0 ,0 ,0 }, + +/* 0x2d0 - 0x2d7 */ +{L_MODRM ,5 ,0 ,M_GRP_1 },{L_MODRM ,7 ,0 ,M_GRP_1 }, +{L_MODRM ,5 ,0 ,M_GRP_CL },{L_MODRM ,7 ,0 ,M_GRP_CL }, +{L_Ib ,O_AAM ,0 ,0 },{L_Ib ,O_AAD ,0 ,0 }, +{D_SETALC ,0 ,0 ,0 },{D_XLAT ,0 ,0 ,0 }, +/* 0x2d8 - 0x2df */ +{L_MODRM ,O_FPU ,0 ,0 },{L_MODRM ,O_FPU ,1 ,0 }, +{L_MODRM ,O_FPU ,2 ,0 },{L_MODRM ,O_FPU ,3 ,0 }, +{L_MODRM ,O_FPU ,4 ,0 },{L_MODRM ,O_FPU ,5 ,0 }, +{L_MODRM ,O_FPU ,6 ,0 },{L_MODRM ,O_FPU ,7 ,0 }, + +/* 0x2e0 - 0x2e7 */ +{L_Ibx ,O_LOOPNZ ,S_AIPd ,0 },{L_Ibx ,O_LOOPZ ,S_AIPd ,0 }, +{L_Ibx ,O_LOOP ,S_AIPd ,0 },{L_Ibx ,O_JCXZ ,S_AIPd ,0 }, +{L_Ib ,O_INb ,0 ,0 },{L_Ib ,O_INd ,0 ,0 }, +{L_Ib ,O_OUTb ,0 ,0 },{L_Ib ,O_OUTd ,0 ,0 }, +/* 0x2e8 - 0x2ef */ +{L_Id ,O_CALLNd ,S_AIPd ,0 },{L_Idx ,0 ,S_AIPd ,0 }, +{L_Ifd ,O_JMPFd ,0 ,0 },{L_Ibx ,0 ,S_AIPd ,0 }, +{L_REGw ,O_INb ,0 ,REGI_DX},{L_REGw ,O_INd ,0 ,REGI_DX}, +{L_REGw ,O_OUTb ,0 ,REGI_DX},{L_REGw ,O_OUTd ,0 ,REGI_DX}, + +/* 0x2f0 - 0x2f7 */ +{D_LOCK ,0 ,0 ,0 },{D_ICEBP ,0 ,0 ,0 }, +{L_PREREPNE ,0 ,0 ,0 },{L_PREREP ,0 ,0 ,0 }, +{D_HLT ,0 ,0 ,0 },{D_CMC ,0 ,0 ,0 }, +{L_MODRM ,8 ,0 ,M_GRP },{L_MODRM ,0xa ,0 ,M_GRP }, +/* 0x2f8 - 0x2ff */ +{D_CLC ,0 ,0 ,0 },{D_STC ,0 ,0 ,0 }, +{D_CLI ,0 ,0 ,0 },{D_STI ,0 ,0 ,0 }, +{D_CLD ,0 ,0 ,0 },{D_STD ,0 ,0 ,0 }, +{L_MODRM ,0xb ,0 ,M_GRP },{L_MODRM ,0xd ,0 ,M_GRP }, + + +/* 0x300 - 0x307 */ +{L_MODRM ,O_GRP6d ,S_Ew ,M_Ew },{L_MODRM ,O_GRP7d ,S_Ew ,M_Ew }, +{L_MODRM_NVM ,O_LAR ,S_Gd ,M_EdGd },{L_MODRM_NVM ,O_LSL ,S_Gd ,M_EdGd }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{D_CLTS ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x308 - 0x30f */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +/* 0x310 - 0x317 */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x318 - 0x31f */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +/* 0x320 - 0x327 */ +{L_MODRM ,O_M_Rd_CRx ,S_Ed ,0 },{L_MODRM ,O_M_Rd_DRx ,S_Ed ,0 }, +{L_MODRM ,O_M_CRx_Rd ,0 ,M_Ed },{L_MODRM ,O_M_DRx_Rd ,0 ,M_Ed }, +{L_MODRM ,O_M_Rd_TRx ,S_Ed ,0 },{0 ,0 ,0 ,0 }, +{L_MODRM ,O_M_TRx_Rd ,0 ,M_Ed },{0 ,0 ,0 ,0 }, + +/* 0x328 - 0x32f */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +/* 0x330 - 0x337 */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x338 - 0x33f */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +/* 0x340 - 0x347 */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x348 - 0x34f */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +/* 0x350 - 0x357 */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x358 - 0x35f */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +/* 0x360 - 0x367 */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x368 - 0x36f */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + + +/* 0x370 - 0x377 */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x378 - 0x37f */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +/* 0x380 - 0x387 */ +{L_Idx ,O_C_O ,S_C_AIPd,0 },{L_Idx ,O_C_NO ,S_C_AIPd,0 }, +{L_Idx ,O_C_B ,S_C_AIPd,0 },{L_Idx ,O_C_NB ,S_C_AIPd,0 }, +{L_Idx ,O_C_Z ,S_C_AIPd,0 },{L_Idx ,O_C_NZ ,S_C_AIPd,0 }, +{L_Idx ,O_C_BE ,S_C_AIPd,0 },{L_Idx ,O_C_NBE ,S_C_AIPd,0 }, +/* 0x388 - 0x38f */ +{L_Idx ,O_C_S ,S_C_AIPd,0 },{L_Idx ,O_C_NS ,S_C_AIPd,0 }, +{L_Idx ,O_C_P ,S_C_AIPd,0 },{L_Idx ,O_C_NP ,S_C_AIPd,0 }, +{L_Idx ,O_C_L ,S_C_AIPd,0 },{L_Idx ,O_C_NL ,S_C_AIPd,0 }, +{L_Idx ,O_C_LE ,S_C_AIPd,0 },{L_Idx ,O_C_NLE ,S_C_AIPd,0 }, + +/* 0x390 - 0x397 */ +{L_MODRM ,O_C_O ,S_C_Eb,0 },{L_MODRM ,O_C_NO ,S_C_Eb,0 }, +{L_MODRM ,O_C_B ,S_C_Eb,0 },{L_MODRM ,O_C_NB ,S_C_Eb,0 }, +{L_MODRM ,O_C_Z ,S_C_Eb,0 },{L_MODRM ,O_C_NZ ,S_C_Eb,0 }, +{L_MODRM ,O_C_BE ,S_C_Eb,0 },{L_MODRM ,O_C_NBE ,S_C_Eb,0 }, +/* 0x398 - 0x39f */ +{L_MODRM ,O_C_S ,S_C_Eb,0 },{L_MODRM ,O_C_NS ,S_C_Eb,0 }, +{L_MODRM ,O_C_P ,S_C_Eb,0 },{L_MODRM ,O_C_NP ,S_C_Eb,0 }, +{L_MODRM ,O_C_L ,S_C_Eb,0 },{L_MODRM ,O_C_NL ,S_C_Eb,0 }, +{L_MODRM ,O_C_LE ,S_C_Eb,0 },{L_MODRM ,O_C_NLE ,S_C_Eb,0 }, + +/* 0x3a0 - 0x3a7 */ +{L_SEG ,0 ,S_PUSHd ,fs },{D_POPSEGd,0 ,0 ,fs }, +{D_CPUID ,0 ,0 ,0 },{L_MODRM ,O_BTd ,S_Ed ,M_EdGdt }, +{L_MODRM ,O_DSHLd ,S_Ed,M_EdGdIb },{L_MODRM ,O_DSHLd ,S_Ed ,M_EdGdCL }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x3a8 - 0x3af */ +{L_SEG ,0 ,S_PUSHd ,gs },{D_POPSEGd,0 ,0 ,gs }, +{0 ,0 ,0 ,0 },{L_MODRM ,O_BTSd ,S_Ed ,M_EdGdt }, +{L_MODRM ,O_DSHRd ,S_Ed,M_EdGdIb },{L_MODRM ,O_DSHRd ,S_Ed ,M_EdGdCL }, +{0 ,0 ,0 ,0 },{L_MODRM ,O_IMULRd ,S_Gd ,M_EdxGdx }, + +/* 0x3b0 - 0x3b7 */ +{0 ,0 ,0 ,0 },{L_MODRM ,O_CMPXCHG ,S_Ed ,M_Ed }, +{L_MODRM ,O_SEGSS ,S_SEGGd,M_Efd },{L_MODRM ,O_BTRd ,S_Ed ,M_EdGdt }, +{L_MODRM ,O_SEGFS ,S_SEGGd,M_Efd },{L_MODRM ,O_SEGGS ,S_SEGGd,M_Efd }, +{L_MODRM ,0 ,S_Gd ,M_Eb },{L_MODRM ,0 ,S_Gd ,M_Ew }, +/* 0x3b8 - 0x3bf */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{L_MODRM ,0xf ,0 ,M_GRP },{L_MODRM ,O_BTCd ,S_Ed ,M_EdGdt }, +{L_MODRM ,O_BSFd ,S_Gd ,M_Ed },{L_MODRM ,O_BSRd ,S_Gd ,M_Ed }, +{L_MODRM ,0 ,S_Gd ,M_Ebx },{L_MODRM ,0 ,S_Gd ,M_Ewx }, + +/* 0x3c0 - 0x3cc */ +{L_MODRM ,t_ADDb ,S_EbGb ,M_GbEb },{L_MODRM ,t_ADDd ,S_EdGd ,M_GdEd }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x3c8 - 0x3cf */ +{L_REGd ,O_BSWAPd ,S_REGd ,REGI_AX},{L_REGd ,O_BSWAPd ,S_REGd ,REGI_CX}, +{L_REGd ,O_BSWAPd ,S_REGd ,REGI_DX},{L_REGd ,O_BSWAPd ,S_REGd ,REGI_BX}, +{L_REGd ,O_BSWAPd ,S_REGd ,REGI_SP},{L_REGd ,O_BSWAPd ,S_REGd ,REGI_BP}, +{L_REGd ,O_BSWAPd ,S_REGd ,REGI_SI},{L_REGd ,O_BSWAPd ,S_REGd ,REGI_DI}, + +/* 0x3d0 - 0x3d7 */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x3d8 - 0x3df */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +/* 0x3e0 - 0x3ee */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x3e8 - 0x3ef */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +/* 0x3f0 - 0x3fc */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +/* 0x3f8 - 0x3ff */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, + +}; + +static OpCode Groups[16][8]={ +{ /* 0x00 Group 1 Eb,Ib */ +{0 ,t_ADDb ,S_Eb ,M_EbIb },{0 ,t_ORb ,S_Eb ,M_EbIb }, +{0 ,t_ADCb ,S_Eb ,M_EbIb },{0 ,t_SBBb ,S_Eb ,M_EbIb }, +{0 ,t_ANDb ,S_Eb ,M_EbIb },{0 ,t_SUBb ,S_Eb ,M_EbIb }, +{0 ,t_XORb ,S_Eb ,M_EbIb },{0 ,t_CMPb ,0 ,M_EbIb }, +},{ /* 0x01 Group 1 Ew,Iw */ +{0 ,t_ADDw ,S_Ew ,M_EwIw },{0 ,t_ORw ,S_Ew ,M_EwIw }, +{0 ,t_ADCw ,S_Ew ,M_EwIw },{0 ,t_SBBw ,S_Ew ,M_EwIw }, +{0 ,t_ANDw ,S_Ew ,M_EwIw },{0 ,t_SUBw ,S_Ew ,M_EwIw }, +{0 ,t_XORw ,S_Ew ,M_EwIw },{0 ,t_CMPw ,0 ,M_EwIw }, +},{ /* 0x02 Group 1 Ed,Id */ +{0 ,t_ADDd ,S_Ed ,M_EdId },{0 ,t_ORd ,S_Ed ,M_EdId }, +{0 ,t_ADCd ,S_Ed ,M_EdId },{0 ,t_SBBd ,S_Ed ,M_EdId }, +{0 ,t_ANDd ,S_Ed ,M_EdId },{0 ,t_SUBd ,S_Ed ,M_EdId }, +{0 ,t_XORd ,S_Ed ,M_EdId },{0 ,t_CMPd ,0 ,M_EdId }, +},{ /* 0x03 Group 1 Ew,Ibx */ +{0 ,t_ADDw ,S_Ew ,M_EwIbx },{0 ,t_ORw ,S_Ew ,M_EwIbx }, +{0 ,t_ADCw ,S_Ew ,M_EwIbx },{0 ,t_SBBw ,S_Ew ,M_EwIbx }, +{0 ,t_ANDw ,S_Ew ,M_EwIbx },{0 ,t_SUBw ,S_Ew ,M_EwIbx }, +{0 ,t_XORw ,S_Ew ,M_EwIbx },{0 ,t_CMPw ,0 ,M_EwIbx }, +},{ /* 0x04 Group 1 Ed,Ibx */ +{0 ,t_ADDd ,S_Ed ,M_EdIbx },{0 ,t_ORd ,S_Ed ,M_EdIbx }, +{0 ,t_ADCd ,S_Ed ,M_EdIbx },{0 ,t_SBBd ,S_Ed ,M_EdIbx }, +{0 ,t_ANDd ,S_Ed ,M_EdIbx },{0 ,t_SUBd ,S_Ed ,M_EdIbx }, +{0 ,t_XORd ,S_Ed ,M_EdIbx },{0 ,t_CMPd ,0 ,M_EdIbx }, + +},{ /* 0x05 Group 2 Eb,XXX */ +{0 ,t_ROLb ,S_Eb ,M_Eb },{0 ,t_RORb ,S_Eb ,M_Eb }, +{0 ,t_RCLb ,S_Eb ,M_Eb },{0 ,t_RCRb ,S_Eb ,M_Eb }, +{0 ,t_SHLb ,S_Eb ,M_Eb },{0 ,t_SHRb ,S_Eb ,M_Eb }, +{0 ,t_SHLb ,S_Eb ,M_Eb },{0 ,t_SARb ,S_Eb ,M_Eb }, +},{ /* 0x06 Group 2 Ew,XXX */ +{0 ,t_ROLw ,S_Ew ,M_Ew },{0 ,t_RORw ,S_Ew ,M_Ew }, +{0 ,t_RCLw ,S_Ew ,M_Ew },{0 ,t_RCRw ,S_Ew ,M_Ew }, +{0 ,t_SHLw ,S_Ew ,M_Ew },{0 ,t_SHRw ,S_Ew ,M_Ew }, +{0 ,t_SHLw ,S_Ew ,M_Ew },{0 ,t_SARw ,S_Ew ,M_Ew }, +},{ /* 0x07 Group 2 Ed,XXX */ +{0 ,t_ROLd ,S_Ed ,M_Ed },{0 ,t_RORd ,S_Ed ,M_Ed }, +{0 ,t_RCLd ,S_Ed ,M_Ed },{0 ,t_RCRd ,S_Ed ,M_Ed }, +{0 ,t_SHLd ,S_Ed ,M_Ed },{0 ,t_SHRd ,S_Ed ,M_Ed }, +{0 ,t_SHLd ,S_Ed ,M_Ed },{0 ,t_SARd ,S_Ed ,M_Ed }, + + +},{ /* 0x08 Group 3 Eb */ +{0 ,t_TESTb ,0 ,M_EbIb },{0 ,t_TESTb ,0 ,M_EbIb }, +{0 ,O_NOT ,S_Eb ,M_Eb },{0 ,t_NEGb ,S_Eb ,M_Eb }, +{0 ,O_MULb ,0 ,M_Eb },{0 ,O_IMULb ,0 ,M_Eb }, +{0 ,O_DIVb ,0 ,M_Eb },{0 ,O_IDIVb ,0 ,M_Eb }, +},{ /* 0x09 Group 3 Ew */ +{0 ,t_TESTw ,0 ,M_EwIw },{0 ,t_TESTw ,0 ,M_EwIw }, +{0 ,O_NOT ,S_Ew ,M_Ew },{0 ,t_NEGw ,S_Ew ,M_Ew }, +{0 ,O_MULw ,0 ,M_Ew },{0 ,O_IMULw ,0 ,M_Ew }, +{0 ,O_DIVw ,0 ,M_Ew },{0 ,O_IDIVw ,0 ,M_Ew }, +},{ /* 0x0a Group 3 Ed */ +{0 ,t_TESTd ,0 ,M_EdId },{0 ,t_TESTd ,0 ,M_EdId }, +{0 ,O_NOT ,S_Ed ,M_Ed },{0 ,t_NEGd ,S_Ed ,M_Ed }, +{0 ,O_MULd ,0 ,M_Ed },{0 ,O_IMULd ,0 ,M_Ed }, +{0 ,O_DIVd ,0 ,M_Ed },{0 ,O_IDIVd ,0 ,M_Ed }, + +},{ /* 0x0b Group 4 Eb */ +{0 ,t_INCb ,S_Eb ,M_Eb },{0 ,t_DECb ,S_Eb ,M_Eb }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,O_CBACK ,0 ,M_Iw }, +},{ /* 0x0c Group 5 Ew */ +{0 ,t_INCw ,S_Ew ,M_Ew },{0 ,t_DECw ,S_Ew ,M_Ew }, +{0 ,O_CALLNw ,S_IP ,M_Ew },{0 ,O_CALLFw ,0 ,M_Efw }, +{0 ,0 ,S_IP ,M_Ew },{0 ,O_JMPFw ,0 ,M_Efw }, +{0 ,0 ,S_PUSHw,M_Ew },{0 ,0 ,0 ,0 }, +},{ /* 0x0d Group 5 Ed */ +{0 ,t_INCd ,S_Ed ,M_Ed },{0 ,t_DECd ,S_Ed ,M_Ed }, +{0 ,O_CALLNd ,S_IP ,M_Ed },{0 ,O_CALLFd ,0 ,M_Efd }, +{0 ,0 ,S_IP ,M_Ed },{0 ,O_JMPFd ,0 ,M_Efd }, +{0 ,0 ,S_PUSHd,M_Ed },{0 ,0 ,0 ,0 }, + + +},{ /* 0x0e Group 8 Ew */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,O_BTw ,S_Ew ,M_EwIb },{0 ,O_BTSw ,S_Ew ,M_EwIb }, +{0 ,O_BTRw ,S_Ew ,M_EwIb },{0 ,O_BTCw ,S_Ew ,M_EwIb }, +},{ /* 0x0f Group 8 Ed */ +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{0 ,O_BTd ,S_Ed ,M_EdIb },{0 ,O_BTSd ,S_Ed ,M_EdIb }, +{0 ,O_BTRd ,S_Ed ,M_EdIb },{0 ,O_BTCd ,S_Ed ,M_EdIb }, + + + +} +}; + + + diff --git a/dosbox/core_full/save.h b/dosbox/core_full/save.h new file mode 100644 index 00000000..4e10db12 --- /dev/null +++ b/dosbox/core_full/save.h @@ -0,0 +1,99 @@ +/* Write the data from the opcode */ +switch (inst.code.save) { +/* Byte */ + case S_C_Eb: + inst_op1_b=inst.cond ? 1 : 0; + case S_Eb: + if (inst.rm<0xc0) SaveMb(inst.rm_eaa,inst_op1_b); + else reg_8(inst.rm_eai)=inst_op1_b; + break; + case S_Gb: + reg_8(inst.rm_index)=inst_op1_b; + break; + case S_EbGb: + if (inst.rm<0xc0) SaveMb(inst.rm_eaa,inst_op1_b); + else reg_8(inst.rm_eai)=inst_op1_b; + reg_8(inst.rm_index)=inst_op2_b; + break; +/* Word */ + case S_Ew: + if (inst.rm<0xc0) SaveMw(inst.rm_eaa,inst_op1_w); + else reg_16(inst.rm_eai)=inst_op1_w; + break; + case S_Gw: + reg_16(inst.rm_index)=inst_op1_w; + break; + case S_EwGw: + if (inst.rm<0xc0) SaveMw(inst.rm_eaa,inst_op1_w); + else reg_16(inst.rm_eai)=inst_op1_w; + reg_16(inst.rm_index)=inst_op2_w; + break; +/* Dword */ + case S_Ed: + if (inst.rm<0xc0) SaveMd(inst.rm_eaa,inst_op1_d); + else reg_32(inst.rm_eai)=inst_op1_d; + break; + case S_EdMw: /* Special one 16 to memory, 32 zero extend to reg */ + if (inst.rm<0xc0) SaveMw(inst.rm_eaa,inst_op1_w); + else reg_32(inst.rm_eai)=inst_op1_d; + break; + case S_Gd: + reg_32(inst.rm_index)=inst_op1_d; + break; + case S_EdGd: + if (inst.rm<0xc0) SaveMd(inst.rm_eaa,inst_op1_d); + else reg_32(inst.rm_eai)=inst_op1_d; + reg_32(inst.rm_index)=inst_op2_d; + break; + + case S_REGb: + reg_8(inst.code.extra)=inst_op1_b; + break; + case S_REGw: + reg_16(inst.code.extra)=inst_op1_w; + break; + case S_REGd: + reg_32(inst.code.extra)=inst_op1_d; + break; + case S_SEGm: + if (CPU_SetSegGeneral((SegNames)inst.rm_index,inst_op1_w)) RunException(); + break; + case S_SEGGw: + if (CPU_SetSegGeneral((SegNames)inst.code.extra,inst_op2_w)) RunException(); + reg_16(inst.rm_index)=inst_op1_w; + break; + case S_SEGGd: + if (CPU_SetSegGeneral((SegNames)inst.code.extra,inst_op2_w)) RunException(); + reg_32(inst.rm_index)=inst_op1_d; + break; + case S_PUSHw: + Push_16(inst_op1_w); + break; + case S_PUSHd: + Push_32(inst_op1_d); + break; + + case S_C_AIPw: + if (!inst.cond) goto nextopcode; + case S_AIPw: + SaveIP(); + reg_eip+=inst_op1_d; + reg_eip&=0xffff; + continue; + case S_C_AIPd: + if (!inst.cond) goto nextopcode; + case S_AIPd: + SaveIP(); + reg_eip+=inst_op1_d; + continue; + case S_IPIw: + reg_esp+=Fetchw(); + case S_IP: + SaveIP(); + reg_eip=inst_op1_d; + continue; + case 0: + break; + default: + LOG(LOG_CPU,LOG_ERROR)("SAVE:Unhandled code %d entry %X",inst.code.save,inst.entry); +} diff --git a/dosbox/core_full/string.h b/dosbox/core_full/string.h new file mode 100644 index 00000000..5da65b10 --- /dev/null +++ b/dosbox/core_full/string.h @@ -0,0 +1,227 @@ +{ + EAPoint si_base,di_base; + Bitu si_index,di_index; + Bitu add_mask; + Bitu count,count_left; + Bits add_index; + + if (inst.prefix & PREFIX_SEG) si_base=inst.seg.base; + else si_base=SegBase(ds); + di_base=SegBase(es); + if (inst.prefix & PREFIX_ADDR) { + add_mask=0xFFFFFFFF; + si_index=reg_esi; + di_index=reg_edi; + count=reg_ecx; + } else { + add_mask=0xFFFF; + si_index=reg_si; + di_index=reg_di; + count=reg_cx; + } + if (!(inst.prefix & PREFIX_REP)) { + count=1; + } else { + /* Calculate amount of ops to do before cycles run out */ + CPU_Cycles++; + if ((count>(Bitu)CPU_Cycles) && (inst.code.op0;count--) { + IO_WriteB(reg_dx,LoadMb(si_base+si_index)); + si_index=(si_index+add_index) & add_mask; + } + break; + case R_OUTSW: + add_index<<=1; + for (;count>0;count--) { + IO_WriteW(reg_dx,LoadMw(si_base+si_index)); + si_index=(si_index+add_index) & add_mask; + } + break; + case R_OUTSD: + add_index<<=2; + for (;count>0;count--) { + IO_WriteD(reg_dx,LoadMd(si_base+si_index)); + si_index=(si_index+add_index) & add_mask; + } + break; + case R_INSB: + for (;count>0;count--) { + SaveMb(di_base+di_index,IO_ReadB(reg_dx)); + di_index=(di_index+add_index) & add_mask; + } + break; + case R_INSW: + add_index<<=1; + for (;count>0;count--) { + SaveMw(di_base+di_index,IO_ReadW(reg_dx)); + di_index=(di_index+add_index) & add_mask; + } + break; + case R_STOSB: + for (;count>0;count--) { + SaveMb(di_base+di_index,reg_al); + di_index=(di_index+add_index) & add_mask; + } + break; + case R_STOSW: + add_index<<=1; + for (;count>0;count--) { + SaveMw(di_base+di_index,reg_ax); + di_index=(di_index+add_index) & add_mask; + } + break; + case R_STOSD: + add_index<<=2; + for (;count>0;count--) { + SaveMd(di_base+di_index,reg_eax); + di_index=(di_index+add_index) & add_mask; + } + break; + case R_MOVSB: + for (;count>0;count--) { + SaveMb(di_base+di_index,LoadMb(si_base+si_index)); + di_index=(di_index+add_index) & add_mask; + si_index=(si_index+add_index) & add_mask; + } + break; + case R_MOVSW: + add_index<<=1; + for (;count>0;count--) { + SaveMw(di_base+di_index,LoadMw(si_base+si_index)); + di_index=(di_index+add_index) & add_mask; + si_index=(si_index+add_index) & add_mask; + } + break; + case R_MOVSD: + add_index<<=2; + for (;count>0;count--) { + SaveMd(di_base+di_index,LoadMd(si_base+si_index)); + di_index=(di_index+add_index) & add_mask; + si_index=(si_index+add_index) & add_mask; + } + break; + case R_LODSB: + for (;count>0;count--) { + reg_al=LoadMb(si_base+si_index); + si_index=(si_index+add_index) & add_mask; + } + break; + case R_LODSW: + add_index<<=1; + for (;count>0;count--) { + reg_ax=LoadMw(si_base+si_index); + si_index=(si_index+add_index) & add_mask; + } + break; + case R_LODSD: + add_index<<=2; + for (;count>0;count--) { + reg_eax=LoadMd(si_base+si_index); + si_index=(si_index+add_index) & add_mask; + } + break; + case R_SCASB: + { + Bit8u val2; + for (;count>0;) { + count--;CPU_Cycles--; + val2=LoadMb(di_base+di_index); + di_index=(di_index+add_index) & add_mask; + if ((reg_al==val2)!=inst.repz) break; + } + CMPB(reg_al,val2,LoadD,0); + } + break; + case R_SCASW: + { + add_index<<=1;Bit16u val2; + for (;count>0;) { + count--;CPU_Cycles--; + val2=LoadMw(di_base+di_index); + di_index=(di_index+add_index) & add_mask; + if ((reg_ax==val2)!=inst.repz) break; + } + CMPW(reg_ax,val2,LoadD,0); + } + break; + case R_SCASD: + { + add_index<<=2;Bit32u val2; + for (;count>0;) { + count--;CPU_Cycles--; + val2=LoadMd(di_base+di_index); + di_index=(di_index+add_index) & add_mask; + if ((reg_eax==val2)!=inst.repz) break; + } + CMPD(reg_eax,val2,LoadD,0); + } + break; + case R_CMPSB: + { + Bit8u val1,val2; + for (;count>0;) { + count--;CPU_Cycles--; + val1=LoadMb(si_base+si_index); + val2=LoadMb(di_base+di_index); + si_index=(si_index+add_index) & add_mask; + di_index=(di_index+add_index) & add_mask; + if ((val1==val2)!=inst.repz) break; + } + CMPB(val1,val2,LoadD,0); + } + break; + case R_CMPSW: + { + add_index<<=1;Bit16u val1,val2; + for (;count>0;) { + count--;CPU_Cycles--; + val1=LoadMw(si_base+si_index); + val2=LoadMw(di_base+di_index); + si_index=(si_index+add_index) & add_mask; + di_index=(di_index+add_index) & add_mask; + if ((val1==val2)!=inst.repz) break; + } + CMPW(val1,val2,LoadD,0); + } + break; + case R_CMPSD: + { + add_index<<=2;Bit32u val1,val2; + for (;count>0;) { + count--;CPU_Cycles--; + val1=LoadMd(si_base+si_index); + val2=LoadMd(di_base+di_index); + si_index=(si_index+add_index) & add_mask; + di_index=(di_index+add_index) & add_mask; + if ((val1==val2)!=inst.repz) break; + } + CMPD(val1,val2,LoadD,0); + } + break; + default: + LOG(LOG_CPU,LOG_ERROR)("Unhandled string %d entry %X",inst.code.op,inst.entry); + } + /* Clean up after certain amount of instructions */ + reg_esi&=(~add_mask); + reg_esi|=(si_index & add_mask); + reg_edi&=(~add_mask); + reg_edi|=(di_index & add_mask); + if (inst.prefix & PREFIX_REP) { + count+=count_left; + reg_ecx&=(~add_mask); + reg_ecx|=(count & add_mask); + } +} diff --git a/dosbox/core_full/support.h b/dosbox/core_full/support.h new file mode 100644 index 00000000..7a0c4dc2 --- /dev/null +++ b/dosbox/core_full/support.h @@ -0,0 +1,249 @@ +enum { + L_N=0, + L_SKIP, + /* Grouped ones using MOD/RM */ + L_MODRM,L_MODRM_NVM,L_POPwRM,L_POPdRM, + + L_Ib,L_Iw,L_Id, + L_Ibx,L_Iwx,L_Idx, //Sign extend + L_Ifw,L_Ifd, + L_OP, + + L_REGb,L_REGw,L_REGd, + L_REGbIb,L_REGwIw,L_REGdId, + L_POPw,L_POPd, + L_POPfw,L_POPfd, + L_SEG, + + L_INTO, + + L_VAL, + L_PRESEG, + L_DOUBLE, + L_PREOP,L_PREADD,L_PREREP,L_PREREPNE, + L_STRING, + +/* Direct ones */ + D_IRETw,D_IRETd, + D_PUSHAw,D_PUSHAd, + D_POPAw,D_POPAd, + D_POPSEGw,D_POPSEGd, + D_DAA,D_DAS, + D_AAA,D_AAS, + D_CBW,D_CWDE, + D_CWD,D_CDQ, + D_SETALC, + D_XLAT, + D_CLI,D_STI,D_STC,D_CLC,D_CMC,D_CLD,D_STD, + D_NOP,D_WAIT, + D_ENTERw,D_ENTERd, + D_LEAVEw,D_LEAVEd, + + D_RETFw,D_RETFd, + D_RETFwIw,D_RETFdIw, + D_POPF,D_PUSHF, + D_SAHF,D_LAHF, + D_CPUID, + D_HLT,D_CLTS, + D_LOCK,D_ICEBP, + L_ERROR +}; + + +enum { + O_N=t_LASTFLAG, + O_COND, + O_XCHG_AX,O_XCHG_EAX, + O_IMULRw,O_IMULRd, + O_BOUNDw,O_BOUNDd, + O_CALLNw,O_CALLNd, + O_CALLFw,O_CALLFd, + O_JMPFw,O_JMPFd, + + O_OPAL,O_ALOP, + O_OPAX,O_AXOP, + O_OPEAX,O_EAXOP, + O_INT, + O_SEGDS,O_SEGES,O_SEGFS,O_SEGGS,O_SEGSS, + O_LOOP,O_LOOPZ,O_LOOPNZ,O_JCXZ, + O_INb,O_INw,O_INd, + O_OUTb,O_OUTw,O_OUTd, + + O_NOT,O_AAM,O_AAD, + O_MULb,O_MULw,O_MULd, + O_IMULb,O_IMULw,O_IMULd, + O_DIVb,O_DIVw,O_DIVd, + O_IDIVb,O_IDIVw,O_IDIVd, + O_CBACK, + + + O_DSHLw,O_DSHLd, + O_DSHRw,O_DSHRd, + O_C_O ,O_C_NO ,O_C_B ,O_C_NB ,O_C_Z ,O_C_NZ ,O_C_BE ,O_C_NBE, + O_C_S ,O_C_NS ,O_C_P ,O_C_NP ,O_C_L ,O_C_NL ,O_C_LE ,O_C_NLE, + + O_GRP6w,O_GRP6d, + O_GRP7w,O_GRP7d, + O_M_CRx_Rd,O_M_Rd_CRx, + O_M_DRx_Rd,O_M_Rd_DRx, + O_M_TRx_Rd,O_M_Rd_TRx, + O_LAR,O_LSL, + O_ARPL, + + O_BTw,O_BTSw,O_BTRw,O_BTCw, + O_BTd,O_BTSd,O_BTRd,O_BTCd, + O_BSFw,O_BSRw,O_BSFd,O_BSRd, + + O_BSWAPw, O_BSWAPd, + O_CMPXCHG, + O_FPU + + +}; + +enum { + S_N=0, + S_C_Eb, + S_Eb,S_Gb,S_EbGb, + S_Ew,S_Gw,S_EwGw, + S_Ed,S_Gd,S_EdGd,S_EdMw, + + + S_REGb,S_REGw,S_REGd, + S_PUSHw,S_PUSHd, + S_SEGm, + S_SEGGw,S_SEGGd, + + + S_AIPw,S_C_AIPw, + S_AIPd,S_C_AIPd, + + S_IP,S_IPIw +}; + +enum { + R_OUTSB,R_OUTSW,R_OUTSD, + R_INSB,R_INSW,R_INSD, + R_MOVSB,R_MOVSW,R_MOVSD, + R_LODSB,R_LODSW,R_LODSD, + R_STOSB,R_STOSW,R_STOSD, + R_SCASB,R_SCASW,R_SCASD, + R_CMPSB,R_CMPSW,R_CMPSD +}; + +enum { + M_None=0, + M_Ebx,M_Eb,M_Gb,M_EbGb,M_GbEb, + M_Ewx,M_Ew,M_Gw,M_EwGw,M_GwEw,M_EwxGwx,M_EwGwt, + M_Edx,M_Ed,M_Gd,M_EdGd,M_GdEd,M_EdxGdx,M_EdGdt, + + M_EbIb,M_EwIb,M_EdIb, + M_EwIw,M_EwIbx,M_EwxIbx,M_EwxIwx,M_EwGwIb,M_EwGwCL, + M_EdId,M_EdIbx,M_EdGdIb,M_EdGdCL, + + M_Efw,M_Efd, + + M_Ib,M_Iw,M_Id, + + + M_SEG,M_EA, + M_GRP, + M_GRP_Ib,M_GRP_CL,M_GRP_1, + + M_POPw,M_POPd +}; + +struct OpCode { + Bit8u load,op,save,extra; +}; + +struct FullData { + Bitu entry; + Bitu rm; + EAPoint rm_eaa; + Bitu rm_off; + Bitu rm_eai; + Bitu rm_index; + Bitu rm_mod; + OpCode code; + EAPoint cseip; +#ifdef WORDS_BIGENDIAN + union { + Bit32u dword[1]; + Bit32s dwords[1]; + Bit16u word[2]; + Bit16s words[2]; + Bit8u byte[4]; + Bit8s bytes[4]; + } blah1,blah2,blah_imm; +#else + union { + Bit8u b;Bit8s bs; + Bit16u w;Bit16s ws; + Bit32u d;Bit32s ds; + } op1,op2,imm; +#endif + Bitu new_flags; + struct { + EAPoint base; + } seg; + Bitu cond; + bool repz; + Bitu prefix; +}; + +/* Some defines to get the names correct. */ +#ifdef WORDS_BIGENDIAN + +#define inst_op1_b inst.blah1.byte[3] +#define inst_op1_bs inst.blah1.bytes[3] +#define inst_op1_w inst.blah1.word[1] +#define inst_op1_ws inst.blah1.words[1] +#define inst_op1_d inst.blah1.dword[0] +#define inst_op1_ds inst.blah1.dwords[0] + +#define inst_op2_b inst.blah2.byte[3] +#define inst_op2_bs inst.blah2.bytes[3] +#define inst_op2_w inst.blah2.word[1] +#define inst_op2_ws inst.blah2.words[1] +#define inst_op2_d inst.blah2.dword[0] +#define inst_op2_ds inst.blah2.dwords[0] + +#define inst_imm_b inst.blah_imm.byte[3] +#define inst_imm_bs inst.blah_imm.bytes[3] +#define inst_imm_w inst.blah_imm.word[1] +#define inst_imm_ws inst.blah_imm.words[1] +#define inst_imm_d inst.blah_imm.dword[0] +#define inst_imm_ds inst.blah_imm.dwords[0] + +#else + +#define inst_op1_b inst.op1.b +#define inst_op1_bs inst.op1.bs +#define inst_op1_w inst.op1.w +#define inst_op1_ws inst.op1.ws +#define inst_op1_d inst.op1.d +#define inst_op1_ds inst.op1.ds + +#define inst_op2_b inst.op2.b +#define inst_op2_bs inst.op2.bs +#define inst_op2_w inst.op2.w +#define inst_op2_ws inst.op2.ws +#define inst_op2_d inst.op2.d +#define inst_op2_ds inst.op2.ds + +#define inst_imm_b inst.imm.b +#define inst_imm_bs inst.imm.bs +#define inst_imm_w inst.imm.w +#define inst_imm_ws inst.imm.ws +#define inst_imm_d inst.imm.d +#define inst_imm_ds inst.imm.ds + +#endif + + +#define PREFIX_NONE 0x0 +#define PREFIX_ADDR 0x1 +#define PREFIX_SEG 0x2 +#define PREFIX_REP 0x4 + diff --git a/dosbox/core_normal.cpp b/dosbox/core_normal.cpp new file mode 100644 index 00000000..7f3b25b7 --- /dev/null +++ b/dosbox/core_normal.cpp @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include + +#include "dosbox.h" +#include "mem.h" +#include "cpu.h" +#include "lazyflags.h" +#include "inout.h" +#include "callback.h" +#include "pic.h" +#include "fpu.h" +#include "paging.h" + +#if C_DEBUG +#include "debug.h" +#endif + +#if (!C_CORE_INLINE) +#define LoadMb(off) mem_readb(off) +#define LoadMw(off) mem_readw(off) +#define LoadMd(off) mem_readd(off) +#define SaveMb(off,val) mem_writeb(off,val) +#define SaveMw(off,val) mem_writew(off,val) +#define SaveMd(off,val) mem_writed(off,val) +#else +#include "paging.h" +#define LoadMb(off) mem_readb_inline(off) +#define LoadMw(off) mem_readw_inline(off) +#define LoadMd(off) mem_readd_inline(off) +#define SaveMb(off,val) mem_writeb_inline(off,val) +#define SaveMw(off,val) mem_writew_inline(off,val) +#define SaveMd(off,val) mem_writed_inline(off,val) +#endif + +extern Bitu cycle_count; + +#if C_FPU +#define CPU_FPU 1 //Enable FPU escape instructions +#endif + +#define CPU_PIC_CHECK 1 +#define CPU_TRAP_CHECK 1 + +#define OPCODE_NONE 0x000 +#define OPCODE_0F 0x100 +#define OPCODE_SIZE 0x200 + +#define PREFIX_ADDR 0x1 +#define PREFIX_REP 0x2 + +#define TEST_PREFIX_ADDR (core.prefixes & PREFIX_ADDR) +#define TEST_PREFIX_REP (core.prefixes & PREFIX_REP) + +#define DO_PREFIX_SEG(_SEG) \ + BaseDS=SegBase(_SEG); \ + BaseSS=SegBase(_SEG); \ + core.base_val_ds=_SEG; \ + goto restart_opcode; + +#define DO_PREFIX_ADDR() \ + core.prefixes=(core.prefixes & ~PREFIX_ADDR) | \ + (cpu.code.big ^ PREFIX_ADDR); \ + core.ea_table=&EATable[(core.prefixes&1) * 256]; \ + goto restart_opcode; + +#define DO_PREFIX_REP(_ZERO) \ + core.prefixes|=PREFIX_REP; \ + core.rep_zero=_ZERO; \ + goto restart_opcode; + +typedef PhysPt (*GetEAHandler)(void); + +static const Bit32u AddrMaskTable[2]={0x0000ffff,0xffffffff}; + +static struct { + Bitu opcode_index; + PhysPt cseip; + PhysPt base_ds,base_ss; + SegNames base_val_ds; + bool rep_zero; + Bitu prefixes; + GetEAHandler * ea_table; +} core; + +#define GETIP (core.cseip-SegBase(cs)) +#define SAVEIP reg_eip=GETIP; +#define LOADIP core.cseip=(SegBase(cs)+reg_eip); + +#define SegBase(c) SegPhys(c) +#define BaseDS core.base_ds +#define BaseSS core.base_ss + +static INLINE Bit8u Fetchb() { + Bit8u temp=LoadMb(core.cseip); + core.cseip+=1; + return temp; +} + +static INLINE Bit16u Fetchw() { + Bit16u temp=LoadMw(core.cseip); + core.cseip+=2; + return temp; +} +static INLINE Bit32u Fetchd() { + Bit32u temp=LoadMd(core.cseip); + core.cseip+=4; + return temp; +} + +#define Push_16 CPU_Push16 +#define Push_32 CPU_Push32 +#define Pop_16 CPU_Pop16 +#define Pop_32 CPU_Pop32 + +#include "instructions.h" +#include "core_normal/support.h" +#include "core_normal/string.h" + + +#define EALookupTable (core.ea_table) + +Bits CPU_Core_Normal_Run(void) { + while (CPU_Cycles-->0) { + LOADIP; + core.opcode_index=cpu.code.big*0x200; + core.prefixes=cpu.code.big; + core.ea_table=&EATable[cpu.code.big*256]; + BaseDS=SegBase(ds); + BaseSS=SegBase(ss); + core.base_val_ds=ds; +#if C_DEBUG +#if C_HEAVY_DEBUG + if (DEBUG_HeavyIsBreakpoint()) { + FillFlags(); + return debugCallback; + }; +#endif + cycle_count++; +#endif +restart_opcode: + switch (core.opcode_index+Fetchb()) { + #include "core_normal/prefix_none.h" + #include "core_normal/prefix_0f.h" + #include "core_normal/prefix_66.h" + #include "core_normal/prefix_66_0f.h" + default: + illegal_opcode: +#if C_DEBUG + { + Bitu len=(GETIP-reg_eip); + LOADIP; + if (len>16) len=16; + char tempcode[16*2+1];char * writecode=tempcode; + for (;len>0;len--) { + sprintf(writecode,"%02X",mem_readb(core.cseip++)); + writecode+=2; + } + LOG(LOG_CPU,LOG_NORMAL)("Illegal/Unhandled opcode %s",tempcode); + } +#endif + CPU_Exception(6,0); + continue; + } + SAVEIP; + } + FillFlags(); + return CBRET_NONE; +decode_end: + SAVEIP; + FillFlags(); + return CBRET_NONE; +} + +Bits CPU_Core_Normal_Trap_Run(void) { + Bits oldCycles = CPU_Cycles; + CPU_Cycles = 1; + cpu.trap_skip = false; + + Bits ret=CPU_Core_Normal_Run(); + if (!cpu.trap_skip) CPU_HW_Interrupt(1); + CPU_Cycles = oldCycles-1; + cpudecoder = &CPU_Core_Normal_Run; + + return ret; +} + + + +void CPU_Core_Normal_Init(void) { + +} + diff --git a/dosbox/core_normal/helpers.h b/dosbox/core_normal/helpers.h new file mode 100644 index 00000000..f0fb75c2 --- /dev/null +++ b/dosbox/core_normal/helpers.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#define GetEAa \ + PhysPt eaa=EALookupTable[rm](); + +#define GetRMEAa \ + GetRM; \ + GetEAa; + + +#define RMEbGb(inst) \ + { \ + GetRMrb; \ + if (rm >= 0xc0 ) {GetEArb;inst(*earb,*rmrb,LoadRb,SaveRb);} \ + else {GetEAa;inst(eaa,*rmrb,LoadMb,SaveMb);} \ + } + +#define RMGbEb(inst) \ + { \ + GetRMrb; \ + if (rm >= 0xc0 ) {GetEArb;inst(*rmrb,*earb,LoadRb,SaveRb);} \ + else {GetEAa;inst(*rmrb,LoadMb(eaa),LoadRb,SaveRb);} \ + } + +#define RMEb(inst) \ + { \ + if (rm >= 0xc0 ) {GetEArb;inst(*earb,LoadRb,SaveRb);} \ + else {GetEAa;inst(eaa,LoadMb,SaveMb);} \ + } + +#define RMEwGw(inst) \ + { \ + GetRMrw; \ + if (rm >= 0xc0 ) {GetEArw;inst(*earw,*rmrw,LoadRw,SaveRw);} \ + else {GetEAa;inst(eaa,*rmrw,LoadMw,SaveMw);} \ + } + +#define RMEwGwOp3(inst,op3) \ + { \ + GetRMrw; \ + if (rm >= 0xc0 ) {GetEArw;inst(*earw,*rmrw,op3,LoadRw,SaveRw);} \ + else {GetEAa;inst(eaa,*rmrw,op3,LoadMw,SaveMw);} \ + } + +#define RMGwEw(inst) \ + { \ + GetRMrw; \ + if (rm >= 0xc0 ) {GetEArw;inst(*rmrw,*earw,LoadRw,SaveRw);} \ + else {GetEAa;inst(*rmrw,LoadMw(eaa),LoadRw,SaveRw);} \ + } + +#define RMGwEwOp3(inst,op3) \ + { \ + GetRMrw; \ + if (rm >= 0xc0 ) {GetEArw;inst(*rmrw,*earw,op3,LoadRw,SaveRw);} \ + else {GetEAa;inst(*rmrw,LoadMw(eaa),op3,LoadRw,SaveRw);} \ + } + +#define RMEw(inst) \ + { \ + if (rm >= 0xc0 ) {GetEArw;inst(*earw,LoadRw,SaveRw);} \ + else {GetEAa;inst(eaa,LoadMw,SaveMw);} \ + } + +#define RMEdGd(inst) \ + { \ + GetRMrd; \ + if (rm >= 0xc0 ) {GetEArd;inst(*eard,*rmrd,LoadRd,SaveRd);} \ + else {GetEAa;inst(eaa,*rmrd,LoadMd,SaveMd);} \ + } + +#define RMEdGdOp3(inst,op3) \ + { \ + GetRMrd; \ + if (rm >= 0xc0 ) {GetEArd;inst(*eard,*rmrd,op3,LoadRd,SaveRd);} \ + else {GetEAa;inst(eaa,*rmrd,op3,LoadMd,SaveMd);} \ + } + + +#define RMGdEd(inst) \ + { \ + GetRMrd; \ + if (rm >= 0xc0 ) {GetEArd;inst(*rmrd,*eard,LoadRd,SaveRd);} \ + else {GetEAa;inst(*rmrd,LoadMd(eaa),LoadRd,SaveRd);} \ + } + +#define RMGdEdOp3(inst,op3) \ + { \ + GetRMrd; \ + if (rm >= 0xc0 ) {GetEArd;inst(*rmrd,*eard,op3,LoadRd,SaveRd);} \ + else {GetEAa;inst(*rmrd,LoadMd(eaa),op3,LoadRd,SaveRd);} \ + } + + + + +#define RMEw(inst) \ + { \ + if (rm >= 0xc0 ) {GetEArw;inst(*earw,LoadRw,SaveRw);} \ + else {GetEAa;inst(eaa,LoadMw,SaveMw);} \ + } + +#define RMEd(inst) \ + { \ + if (rm >= 0xc0 ) {GetEArd;inst(*eard,LoadRd,SaveRd);} \ + else {GetEAa;inst(eaa,LoadMd,SaveMd);} \ + } + +#define ALIb(inst) \ + { inst(reg_al,Fetchb(),LoadRb,SaveRb)} + +#define AXIw(inst) \ + { inst(reg_ax,Fetchw(),LoadRw,SaveRw);} + +#define EAXId(inst) \ + { inst(reg_eax,Fetchd(),LoadRd,SaveRd);} + +#define FPU_ESC(code) { \ + Bit8u rm=Fetchb(); \ + if (rm >= 0xc0) { \ + FPU_ESC ## code ## _Normal(rm); \ + } else { \ + GetEAa;FPU_ESC ## code ## _EA(rm,eaa); \ + } \ +} + +#define CASE_W(_WHICH) \ + case (OPCODE_NONE+_WHICH): + +#define CASE_D(_WHICH) \ + case (OPCODE_SIZE+_WHICH): + +#define CASE_B(_WHICH) \ + CASE_W(_WHICH) \ + CASE_D(_WHICH) + +#define CASE_0F_W(_WHICH) \ + case ((OPCODE_0F|OPCODE_NONE)+_WHICH): + +#define CASE_0F_D(_WHICH) \ + case ((OPCODE_0F|OPCODE_SIZE)+_WHICH): + +#define CASE_0F_B(_WHICH) \ + CASE_0F_W(_WHICH) \ + CASE_0F_D(_WHICH) diff --git a/dosbox/core_normal/prefix_0f.h b/dosbox/core_normal/prefix_0f.h new file mode 100644 index 00000000..1c191b51 --- /dev/null +++ b/dosbox/core_normal/prefix_0f.h @@ -0,0 +1,615 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + CASE_0F_W(0x00) /* GRP 6 Exxx */ + { + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode; + GetRM;Bitu which=(rm>>3)&7; + switch (which) { + case 0x00: /* SLDT */ + case 0x01: /* STR */ + { + Bitu saveval; + if (!which) saveval=CPU_SLDT(); + else saveval=CPU_STR(); + if (rm >= 0xc0) {GetEArw;*earw=saveval;} + else {GetEAa;SaveMw(eaa,saveval);} + } + break; + case 0x02:case 0x03:case 0x04:case 0x05: + { + Bitu loadval; + if (rm >= 0xc0 ) {GetEArw;loadval=*earw;} + else {GetEAa;loadval=LoadMw(eaa);} + switch (which) { + case 0x02: + if (cpu.cpl) EXCEPTION(EXCEPTION_GP); + if (CPU_LLDT(loadval)) RUNEXCEPTION(); + break; + case 0x03: + if (cpu.cpl) EXCEPTION(EXCEPTION_GP); + if (CPU_LTR(loadval)) RUNEXCEPTION(); + break; + case 0x04: + CPU_VERR(loadval); + break; + case 0x05: + CPU_VERW(loadval); + break; + } + } + break; + default: + goto illegal_opcode; + } + } + break; + CASE_0F_W(0x01) /* Group 7 Ew */ + { + GetRM;Bitu which=(rm>>3)&7; + if (rm < 0xc0) { //First ones all use EA + GetEAa;Bitu limit; + switch (which) { + case 0x00: /* SGDT */ + SaveMw(eaa,CPU_SGDT_limit()); + SaveMd(eaa+2,CPU_SGDT_base()); + break; + case 0x01: /* SIDT */ + SaveMw(eaa,CPU_SIDT_limit()); + SaveMd(eaa+2,CPU_SIDT_base()); + break; + case 0x02: /* LGDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + CPU_LGDT(LoadMw(eaa),LoadMd(eaa+2) & 0xFFFFFF); + break; + case 0x03: /* LIDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + CPU_LIDT(LoadMw(eaa),LoadMd(eaa+2) & 0xFFFFFF); + break; + case 0x04: /* SMSW */ + SaveMw(eaa,CPU_SMSW()); + break; + case 0x06: /* LMSW */ + limit=LoadMw(eaa); + if (CPU_LMSW(limit)) RUNEXCEPTION(); + break; + case 0x07: /* INVLPG */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + PAGING_ClearTLB(); + break; + } + } else { + GetEArw; + switch (which) { + case 0x02: /* LGDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + goto illegal_opcode; + case 0x03: /* LIDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + goto illegal_opcode; + case 0x04: /* SMSW */ + *earw=CPU_SMSW(); + break; + case 0x06: /* LMSW */ + if (CPU_LMSW(*earw)) RUNEXCEPTION(); + break; + default: + goto illegal_opcode; + } + } + } + break; + CASE_0F_W(0x02) /* LAR Gw,Ew */ + { + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode; + GetRMrw;Bitu ar=*rmrw; + if (rm >= 0xc0) { + GetEArw;CPU_LAR(*earw,ar); + } else { + GetEAa;CPU_LAR(LoadMw(eaa),ar); + } + *rmrw=(Bit16u)ar; + } + break; + CASE_0F_W(0x03) /* LSL Gw,Ew */ + { + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode; + GetRMrw;Bitu limit=*rmrw; + if (rm >= 0xc0) { + GetEArw;CPU_LSL(*earw,limit); + } else { + GetEAa;CPU_LSL(LoadMw(eaa),limit); + } + *rmrw=(Bit16u)limit; + } + break; + CASE_0F_B(0x06) /* CLTS */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + cpu.cr0&=(~CR0_TASKSWITCH); + break; + CASE_0F_B(0x08) /* INVD */ + CASE_0F_B(0x09) /* WBINVD */ + if (CPU_ArchitectureType> 3) & 7; + if (rm < 0xc0 ) { + rm |= 0xc0; + LOG(LOG_CPU,LOG_ERROR)("MOV XXX,CR%u with non-register",which); + } + GetEArd; + Bit32u crx_value; + if (CPU_READ_CRX(which,crx_value)) RUNEXCEPTION(); + *eard=crx_value; + } + break; + CASE_0F_B(0x21) /* MOV Rd,DRx */ + { + GetRM; + Bitu which=(rm >> 3) & 7; + if (rm < 0xc0 ) { + rm |= 0xc0; + LOG(LOG_CPU,LOG_ERROR)("MOV XXX,DR%u with non-register",which); + } + GetEArd; + Bit32u drx_value; + if (CPU_READ_DRX(which,drx_value)) RUNEXCEPTION(); + *eard=drx_value; + } + break; + CASE_0F_B(0x22) /* MOV CRx,Rd */ + { + GetRM; + Bitu which=(rm >> 3) & 7; + if (rm < 0xc0 ) { + rm |= 0xc0; + LOG(LOG_CPU,LOG_ERROR)("MOV XXX,CR%u with non-register",which); + } + GetEArd; + if (CPU_WRITE_CRX(which,*eard)) RUNEXCEPTION(); + } + break; + CASE_0F_B(0x23) /* MOV DRx,Rd */ + { + GetRM; + Bitu which=(rm >> 3) & 7; + if (rm < 0xc0 ) { + rm |= 0xc0; + LOG(LOG_CPU,LOG_ERROR)("MOV DR%u,XXX with non-register",which); + } + GetEArd; + if (CPU_WRITE_DRX(which,*eard)) RUNEXCEPTION(); + } + break; + CASE_0F_B(0x24) /* MOV Rd,TRx */ + { + GetRM; + Bitu which=(rm >> 3) & 7; + if (rm < 0xc0 ) { + rm |= 0xc0; + LOG(LOG_CPU,LOG_ERROR)("MOV XXX,TR%u with non-register",which); + } + GetEArd; + Bit32u trx_value; + if (CPU_READ_TRX(which,trx_value)) RUNEXCEPTION(); + *eard=trx_value; + } + break; + CASE_0F_B(0x26) /* MOV TRx,Rd */ + { + GetRM; + Bitu which=(rm >> 3) & 7; + if (rm < 0xc0 ) { + rm |= 0xc0; + LOG(LOG_CPU,LOG_ERROR)("MOV TR%u,XXX with non-register",which); + } + GetEArd; + if (CPU_WRITE_TRX(which,*eard)) RUNEXCEPTION(); + } + break; + CASE_0F_B(0x31) /* RDTSC */ + { + if (CPU_ArchitectureType>32); + reg_eax=(Bit32u)(tsc&0xffffffff); + } + break; + CASE_0F_W(0x80) /* JO */ + JumpCond16_w(TFLG_O);break; + CASE_0F_W(0x81) /* JNO */ + JumpCond16_w(TFLG_NO);break; + CASE_0F_W(0x82) /* JB */ + JumpCond16_w(TFLG_B);break; + CASE_0F_W(0x83) /* JNB */ + JumpCond16_w(TFLG_NB);break; + CASE_0F_W(0x84) /* JZ */ + JumpCond16_w(TFLG_Z);break; + CASE_0F_W(0x85) /* JNZ */ + JumpCond16_w(TFLG_NZ);break; + CASE_0F_W(0x86) /* JBE */ + JumpCond16_w(TFLG_BE);break; + CASE_0F_W(0x87) /* JNBE */ + JumpCond16_w(TFLG_NBE);break; + CASE_0F_W(0x88) /* JS */ + JumpCond16_w(TFLG_S);break; + CASE_0F_W(0x89) /* JNS */ + JumpCond16_w(TFLG_NS);break; + CASE_0F_W(0x8a) /* JP */ + JumpCond16_w(TFLG_P);break; + CASE_0F_W(0x8b) /* JNP */ + JumpCond16_w(TFLG_NP);break; + CASE_0F_W(0x8c) /* JL */ + JumpCond16_w(TFLG_L);break; + CASE_0F_W(0x8d) /* JNL */ + JumpCond16_w(TFLG_NL);break; + CASE_0F_W(0x8e) /* JLE */ + JumpCond16_w(TFLG_LE);break; + CASE_0F_W(0x8f) /* JNLE */ + JumpCond16_w(TFLG_NLE);break; + CASE_0F_B(0x90) /* SETO */ + SETcc(TFLG_O);break; + CASE_0F_B(0x91) /* SETNO */ + SETcc(TFLG_NO);break; + CASE_0F_B(0x92) /* SETB */ + SETcc(TFLG_B);break; + CASE_0F_B(0x93) /* SETNB */ + SETcc(TFLG_NB);break; + CASE_0F_B(0x94) /* SETZ */ + SETcc(TFLG_Z);break; + CASE_0F_B(0x95) /* SETNZ */ + SETcc(TFLG_NZ); break; + CASE_0F_B(0x96) /* SETBE */ + SETcc(TFLG_BE);break; + CASE_0F_B(0x97) /* SETNBE */ + SETcc(TFLG_NBE);break; + CASE_0F_B(0x98) /* SETS */ + SETcc(TFLG_S);break; + CASE_0F_B(0x99) /* SETNS */ + SETcc(TFLG_NS);break; + CASE_0F_B(0x9a) /* SETP */ + SETcc(TFLG_P);break; + CASE_0F_B(0x9b) /* SETNP */ + SETcc(TFLG_NP);break; + CASE_0F_B(0x9c) /* SETL */ + SETcc(TFLG_L);break; + CASE_0F_B(0x9d) /* SETNL */ + SETcc(TFLG_NL);break; + CASE_0F_B(0x9e) /* SETLE */ + SETcc(TFLG_LE);break; + CASE_0F_B(0x9f) /* SETNLE */ + SETcc(TFLG_NLE);break; + + CASE_0F_W(0xa0) /* PUSH FS */ + Push_16(SegValue(fs));break; + CASE_0F_W(0xa1) /* POP FS */ + if (CPU_PopSeg(fs,false)) RUNEXCEPTION(); + break; + CASE_0F_B(0xa2) /* CPUID */ + if (!CPU_CPUID()) goto illegal_opcode; + break; + CASE_0F_W(0xa3) /* BT Ew,Gw */ + { + FillFlags();GetRMrw; + Bit16u mask=1 << (*rmrw & 15); + if (rm >= 0xc0 ) { + GetEArw; + SETFLAGBIT(CF,(*earw & mask)); + } else { + GetEAa;eaa+=(((Bit16s)*rmrw)>>4)*2; + Bit16u old=LoadMw(eaa); + SETFLAGBIT(CF,(old & mask)); + } + break; + } + CASE_0F_W(0xa4) /* SHLD Ew,Gw,Ib */ + RMEwGwOp3(DSHLW,Fetchb()); + break; + CASE_0F_W(0xa5) /* SHLD Ew,Gw,CL */ + RMEwGwOp3(DSHLW,reg_cl); + break; + CASE_0F_W(0xa8) /* PUSH GS */ + Push_16(SegValue(gs));break; + CASE_0F_W(0xa9) /* POP GS */ + if (CPU_PopSeg(gs,false)) RUNEXCEPTION(); + break; + CASE_0F_W(0xab) /* BTS Ew,Gw */ + { + FillFlags();GetRMrw; + Bit16u mask=1 << (*rmrw & 15); + if (rm >= 0xc0 ) { + GetEArw; + SETFLAGBIT(CF,(*earw & mask)); + *earw|=mask; + } else { + GetEAa;eaa+=(((Bit16s)*rmrw)>>4)*2; + Bit16u old=LoadMw(eaa); + SETFLAGBIT(CF,(old & mask)); + SaveMw(eaa,old | mask); + } + break; + } + CASE_0F_W(0xac) /* SHRD Ew,Gw,Ib */ + RMEwGwOp3(DSHRW,Fetchb()); + break; + CASE_0F_W(0xad) /* SHRD Ew,Gw,CL */ + RMEwGwOp3(DSHRW,reg_cl); + break; + CASE_0F_W(0xaf) /* IMUL Gw,Ew */ + RMGwEwOp3(DIMULW,*rmrw); + break; + CASE_0F_B(0xb0) /* cmpxchg Eb,Gb */ + { + if (CPU_ArchitectureType= 0xc0 ) { + GetEArb; + if (reg_al == *earb) { + *earb=*rmrb; + SETFLAGBIT(ZF,1); + } else { + reg_al = *earb; + SETFLAGBIT(ZF,0); + } + } else { + GetEAa; + Bit8u val = LoadMb(eaa); + if (reg_al == val) { + SaveMb(eaa,*rmrb); + SETFLAGBIT(ZF,1); + } else { + SaveMb(eaa,val); // cmpxchg always issues a write + reg_al = val; + SETFLAGBIT(ZF,0); + } + } + break; + } + CASE_0F_W(0xb1) /* cmpxchg Ew,Gw */ + { + if (CPU_ArchitectureType= 0xc0 ) { + GetEArw; + if(reg_ax == *earw) { + *earw = *rmrw; + SETFLAGBIT(ZF,1); + } else { + reg_ax = *earw; + SETFLAGBIT(ZF,0); + } + } else { + GetEAa; + Bit16u val = LoadMw(eaa); + if(reg_ax == val) { + SaveMw(eaa,*rmrw); + SETFLAGBIT(ZF,1); + } else { + SaveMw(eaa,val); // cmpxchg always issues a write + reg_ax = val; + SETFLAGBIT(ZF,0); + } + } + break; + } + + CASE_0F_W(0xb2) /* LSS Ew */ + { + GetRMrw; + if (rm >= 0xc0) goto illegal_opcode; + GetEAa; + if (CPU_SetSegGeneral(ss,LoadMw(eaa+2))) RUNEXCEPTION(); + *rmrw=LoadMw(eaa); + break; + } + CASE_0F_W(0xb3) /* BTR Ew,Gw */ + { + FillFlags();GetRMrw; + Bit16u mask=1 << (*rmrw & 15); + if (rm >= 0xc0 ) { + GetEArw; + SETFLAGBIT(CF,(*earw & mask)); + *earw&= ~mask; + } else { + GetEAa;eaa+=(((Bit16s)*rmrw)>>4)*2; + Bit16u old=LoadMw(eaa); + SETFLAGBIT(CF,(old & mask)); + SaveMw(eaa,old & ~mask); + } + break; + } + CASE_0F_W(0xb4) /* LFS Ew */ + { + GetRMrw; + if (rm >= 0xc0) goto illegal_opcode; + GetEAa; + if (CPU_SetSegGeneral(fs,LoadMw(eaa+2))) RUNEXCEPTION(); + *rmrw=LoadMw(eaa); + break; + } + CASE_0F_W(0xb5) /* LGS Ew */ + { + GetRMrw; + if (rm >= 0xc0) goto illegal_opcode; + GetEAa; + if (CPU_SetSegGeneral(gs,LoadMw(eaa+2))) RUNEXCEPTION(); + *rmrw=LoadMw(eaa); + break; + } + CASE_0F_W(0xb6) /* MOVZX Gw,Eb */ + { + GetRMrw; + if (rm >= 0xc0 ) {GetEArb;*rmrw=*earb;} + else {GetEAa;*rmrw=LoadMb(eaa);} + break; + } + CASE_0F_W(0xb7) /* MOVZX Gw,Ew */ + CASE_0F_W(0xbf) /* MOVSX Gw,Ew */ + { + GetRMrw; + if (rm >= 0xc0 ) {GetEArw;*rmrw=*earw;} + else {GetEAa;*rmrw=LoadMw(eaa);} + break; + } + CASE_0F_W(0xba) /* GRP8 Ew,Ib */ + { + FillFlags();GetRM; + if (rm >= 0xc0 ) { + GetEArw; + Bit16u mask=1 << (Fetchb() & 15); + SETFLAGBIT(CF,(*earw & mask)); + switch (rm & 0x38) { + case 0x20: /* BT */ + break; + case 0x28: /* BTS */ + *earw|=mask; + break; + case 0x30: /* BTR */ + *earw&= ~mask; + break; + case 0x38: /* BTC */ + *earw^=mask; + break; + default: + E_Exit("CPU:0F:BA:Illegal subfunction %X",rm & 0x38); + } + } else { + GetEAa;Bit16u old=LoadMw(eaa); + Bit16u mask=1 << (Fetchb() & 15); + SETFLAGBIT(CF,(old & mask)); + switch (rm & 0x38) { + case 0x20: /* BT */ + break; + case 0x28: /* BTS */ + SaveMw(eaa,old|mask); + break; + case 0x30: /* BTR */ + SaveMw(eaa,old & ~mask); + break; + case 0x38: /* BTC */ + SaveMw(eaa,old ^ mask); + break; + default: + E_Exit("CPU:0F:BA:Illegal subfunction %X",rm & 0x38); + } + } + break; + } + CASE_0F_W(0xbb) /* BTC Ew,Gw */ + { + FillFlags();GetRMrw; + Bit16u mask=1 << (*rmrw & 15); + if (rm >= 0xc0 ) { + GetEArw; + SETFLAGBIT(CF,(*earw & mask)); + *earw^=mask; + } else { + GetEAa;eaa+=(((Bit16s)*rmrw)>>4)*2; + Bit16u old=LoadMw(eaa); + SETFLAGBIT(CF,(old & mask)); + SaveMw(eaa,old ^ mask); + } + break; + } + CASE_0F_W(0xbc) /* BSF Gw,Ew */ + { + GetRMrw; + Bit16u result,value; + if (rm >= 0xc0) { GetEArw; value=*earw; } + else { GetEAa; value=LoadMw(eaa); } + if (value==0) { + SETFLAGBIT(ZF,true); + } else { + result = 0; + while ((value & 0x01)==0) { result++; value>>=1; } + SETFLAGBIT(ZF,false); + *rmrw = result; + } + lflags.type=t_UNKNOWN; + break; + } + CASE_0F_W(0xbd) /* BSR Gw,Ew */ + { + GetRMrw; + Bit16u result,value; + if (rm >= 0xc0) { GetEArw; value=*earw; } + else { GetEAa; value=LoadMw(eaa); } + if (value==0) { + SETFLAGBIT(ZF,true); + } else { + result = 15; // Operandsize-1 + while ((value & 0x8000)==0) { result--; value<<=1; } + SETFLAGBIT(ZF,false); + *rmrw = result; + } + lflags.type=t_UNKNOWN; + break; + } + CASE_0F_W(0xbe) /* MOVSX Gw,Eb */ + { + GetRMrw; + if (rm >= 0xc0 ) {GetEArb;*rmrw=*(Bit8s *)earb;} + else {GetEAa;*rmrw=LoadMbs(eaa);} + break; + } + CASE_0F_B(0xc0) /* XADD Gb,Eb */ + { + if (CPU_ArchitectureType= 0xc0 ) {GetEArb;*rmrb=*earb;*earb+=oldrmrb;} + else {GetEAa;*rmrb=LoadMb(eaa);SaveMb(eaa,LoadMb(eaa)+oldrmrb);} + break; + } + CASE_0F_W(0xc1) /* XADD Gw,Ew */ + { + if (CPU_ArchitectureType= 0xc0 ) {GetEArw;*rmrw=*earw;*earw+=oldrmrw;} + else {GetEAa;*rmrw=LoadMw(eaa);SaveMw(eaa,LoadMw(eaa)+oldrmrw);} + break; + } + CASE_0F_W(0xc8) /* BSWAP AX */ + if (CPU_ArchitectureType bound_max) ) { + EXCEPTION(5); + } + } + break; + CASE_D(0x63) /* ARPL Ed,Rd */ + { + if (((cpu.pmode) && (reg_flags & FLAG_VM)) || (!cpu.pmode)) goto illegal_opcode; + GetRMrw; + if (rm >= 0xc0 ) { + GetEArd;Bitu new_sel=(Bit16u)*eard; + CPU_ARPL(new_sel,*rmrw); + *eard=(Bit32u)new_sel; + } else { + GetEAa;Bitu new_sel=LoadMw(eaa); + CPU_ARPL(new_sel,*rmrw); + SaveMd(eaa,(Bit32u)new_sel); + } + } + break; + CASE_D(0x68) /* PUSH Id */ + Push_32(Fetchd());break; + CASE_D(0x69) /* IMUL Gd,Ed,Id */ + RMGdEdOp3(DIMULD,Fetchds()); + break; + CASE_D(0x6a) /* PUSH Ib */ + Push_32(Fetchbs());break; + CASE_D(0x6b) /* IMUL Gd,Ed,Ib */ + RMGdEdOp3(DIMULD,Fetchbs()); + break; + CASE_D(0x6d) /* INSD */ + if (CPU_IO_Exception(reg_dx,4)) RUNEXCEPTION(); + DoString(R_INSD);break; + CASE_D(0x6f) /* OUTSD */ + if (CPU_IO_Exception(reg_dx,4)) RUNEXCEPTION(); + DoString(R_OUTSD);break; + CASE_D(0x70) /* JO */ + JumpCond32_b(TFLG_O);break; + CASE_D(0x71) /* JNO */ + JumpCond32_b(TFLG_NO);break; + CASE_D(0x72) /* JB */ + JumpCond32_b(TFLG_B);break; + CASE_D(0x73) /* JNB */ + JumpCond32_b(TFLG_NB);break; + CASE_D(0x74) /* JZ */ + JumpCond32_b(TFLG_Z);break; + CASE_D(0x75) /* JNZ */ + JumpCond32_b(TFLG_NZ);break; + CASE_D(0x76) /* JBE */ + JumpCond32_b(TFLG_BE);break; + CASE_D(0x77) /* JNBE */ + JumpCond32_b(TFLG_NBE);break; + CASE_D(0x78) /* JS */ + JumpCond32_b(TFLG_S);break; + CASE_D(0x79) /* JNS */ + JumpCond32_b(TFLG_NS);break; + CASE_D(0x7a) /* JP */ + JumpCond32_b(TFLG_P);break; + CASE_D(0x7b) /* JNP */ + JumpCond32_b(TFLG_NP);break; + CASE_D(0x7c) /* JL */ + JumpCond32_b(TFLG_L);break; + CASE_D(0x7d) /* JNL */ + JumpCond32_b(TFLG_NL);break; + CASE_D(0x7e) /* JLE */ + JumpCond32_b(TFLG_LE);break; + CASE_D(0x7f) /* JNLE */ + JumpCond32_b(TFLG_NLE);break; + CASE_D(0x81) /* Grpl Ed,Id */ + { + GetRM;Bitu which=(rm>>3)&7; + if (rm >= 0xc0) { + GetEArd;Bit32u id=Fetchd(); + switch (which) { + case 0x00:ADDD(*eard,id,LoadRd,SaveRd);break; + case 0x01: ORD(*eard,id,LoadRd,SaveRd);break; + case 0x02:ADCD(*eard,id,LoadRd,SaveRd);break; + case 0x03:SBBD(*eard,id,LoadRd,SaveRd);break; + case 0x04:ANDD(*eard,id,LoadRd,SaveRd);break; + case 0x05:SUBD(*eard,id,LoadRd,SaveRd);break; + case 0x06:XORD(*eard,id,LoadRd,SaveRd);break; + case 0x07:CMPD(*eard,id,LoadRd,SaveRd);break; + } + } else { + GetEAa;Bit32u id=Fetchd(); + switch (which) { + case 0x00:ADDD(eaa,id,LoadMd,SaveMd);break; + case 0x01: ORD(eaa,id,LoadMd,SaveMd);break; + case 0x02:ADCD(eaa,id,LoadMd,SaveMd);break; + case 0x03:SBBD(eaa,id,LoadMd,SaveMd);break; + case 0x04:ANDD(eaa,id,LoadMd,SaveMd);break; + case 0x05:SUBD(eaa,id,LoadMd,SaveMd);break; + case 0x06:XORD(eaa,id,LoadMd,SaveMd);break; + case 0x07:CMPD(eaa,id,LoadMd,SaveMd);break; + } + } + } + break; + CASE_D(0x83) /* Grpl Ed,Ix */ + { + GetRM;Bitu which=(rm>>3)&7; + if (rm >= 0xc0) { + GetEArd;Bit32u id=(Bit32s)Fetchbs(); + switch (which) { + case 0x00:ADDD(*eard,id,LoadRd,SaveRd);break; + case 0x01: ORD(*eard,id,LoadRd,SaveRd);break; + case 0x02:ADCD(*eard,id,LoadRd,SaveRd);break; + case 0x03:SBBD(*eard,id,LoadRd,SaveRd);break; + case 0x04:ANDD(*eard,id,LoadRd,SaveRd);break; + case 0x05:SUBD(*eard,id,LoadRd,SaveRd);break; + case 0x06:XORD(*eard,id,LoadRd,SaveRd);break; + case 0x07:CMPD(*eard,id,LoadRd,SaveRd);break; + } + } else { + GetEAa;Bit32u id=(Bit32s)Fetchbs(); + switch (which) { + case 0x00:ADDD(eaa,id,LoadMd,SaveMd);break; + case 0x01: ORD(eaa,id,LoadMd,SaveMd);break; + case 0x02:ADCD(eaa,id,LoadMd,SaveMd);break; + case 0x03:SBBD(eaa,id,LoadMd,SaveMd);break; + case 0x04:ANDD(eaa,id,LoadMd,SaveMd);break; + case 0x05:SUBD(eaa,id,LoadMd,SaveMd);break; + case 0x06:XORD(eaa,id,LoadMd,SaveMd);break; + case 0x07:CMPD(eaa,id,LoadMd,SaveMd);break; + } + } + } + break; + CASE_D(0x85) /* TEST Ed,Gd */ + RMEdGd(TESTD);break; + CASE_D(0x87) /* XCHG Ed,Gd */ + { + GetRMrd;Bit32u oldrmrd=*rmrd; + if (rm >= 0xc0 ) {GetEArd;*rmrd=*eard;*eard=oldrmrd;} + else {GetEAa;*rmrd=LoadMd(eaa);SaveMd(eaa,oldrmrd);} + break; + } + CASE_D(0x89) /* MOV Ed,Gd */ + { + GetRMrd; + if (rm >= 0xc0 ) {GetEArd;*eard=*rmrd;} + else {GetEAa;SaveMd(eaa,*rmrd);} + break; + } + CASE_D(0x8b) /* MOV Gd,Ed */ + { + GetRMrd; + if (rm >= 0xc0 ) {GetEArd;*rmrd=*eard;} + else {GetEAa;*rmrd=LoadMd(eaa);} + break; + } + CASE_D(0x8c) /* Mov Ew,Sw */ + { + GetRM;Bit16u val;Bitu which=(rm>>3)&7; + switch (which) { + case 0x00: /* MOV Ew,ES */ + val=SegValue(es);break; + case 0x01: /* MOV Ew,CS */ + val=SegValue(cs);break; + case 0x02: /* MOV Ew,SS */ + val=SegValue(ss);break; + case 0x03: /* MOV Ew,DS */ + val=SegValue(ds);break; + case 0x04: /* MOV Ew,FS */ + val=SegValue(fs);break; + case 0x05: /* MOV Ew,GS */ + val=SegValue(gs);break; + default: + LOG(LOG_CPU,LOG_ERROR)("CPU:8c:Illegal RM Byte"); + goto illegal_opcode; + } + if (rm >= 0xc0 ) {GetEArd;*eard=val;} + else {GetEAa;SaveMw(eaa,val);} + break; + } + CASE_D(0x8d) /* LEA Gd */ + { + //Little hack to always use segprefixed version + GetRMrd; + BaseDS=BaseSS=0; + if (TEST_PREFIX_ADDR) { + *rmrd=(Bit32u)(*EATable[256+rm])(); + } else { + *rmrd=(Bit32u)(*EATable[rm])(); + } + break; + } + CASE_D(0x8f) /* POP Ed */ + { + Bit32u val=Pop_32(); + GetRM; + if (rm >= 0xc0 ) {GetEArd;*eard=val;} + else {GetEAa;SaveMd(eaa,val);} + break; + } + CASE_D(0x91) /* XCHG ECX,EAX */ + { Bit32u temp=reg_eax;reg_eax=reg_ecx;reg_ecx=temp;break;} + CASE_D(0x92) /* XCHG EDX,EAX */ + { Bit32u temp=reg_eax;reg_eax=reg_edx;reg_edx=temp;break;} + break; + CASE_D(0x93) /* XCHG EBX,EAX */ + { Bit32u temp=reg_eax;reg_eax=reg_ebx;reg_ebx=temp;break;} + break; + CASE_D(0x94) /* XCHG ESP,EAX */ + { Bit32u temp=reg_eax;reg_eax=reg_esp;reg_esp=temp;break;} + break; + CASE_D(0x95) /* XCHG EBP,EAX */ + { Bit32u temp=reg_eax;reg_eax=reg_ebp;reg_ebp=temp;break;} + break; + CASE_D(0x96) /* XCHG ESI,EAX */ + { Bit32u temp=reg_eax;reg_eax=reg_esi;reg_esi=temp;break;} + break; + CASE_D(0x97) /* XCHG EDI,EAX */ + { Bit32u temp=reg_eax;reg_eax=reg_edi;reg_edi=temp;break;} + break; + CASE_D(0x98) /* CWDE */ + reg_eax=(Bit16s)reg_ax;break; + CASE_D(0x99) /* CDQ */ + if (reg_eax & 0x80000000) reg_edx=0xffffffff; + else reg_edx=0; + break; + CASE_D(0x9a) /* CALL FAR Ad */ + { + Bit32u newip=Fetchd();Bit16u newcs=Fetchw(); + FillFlags(); + CPU_CALL(true,newcs,newip,GETIP); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + return CBRET_NONE; + } +#endif + continue; + } + CASE_D(0x9c) /* PUSHFD */ + if (CPU_PUSHF(true)) RUNEXCEPTION(); + break; + CASE_D(0x9d) /* POPFD */ + if (CPU_POPF(true)) RUNEXCEPTION(); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + goto decode_end; + } +#endif +#if CPU_PIC_CHECK + if (GETFLAG(IF) && PIC_IRQCheck) goto decode_end; +#endif + break; + CASE_D(0xa1) /* MOV EAX,Od */ + { + GetEADirect; + reg_eax=LoadMd(eaa); + } + break; + CASE_D(0xa3) /* MOV Od,EAX */ + { + GetEADirect; + SaveMd(eaa,reg_eax); + } + break; + CASE_D(0xa5) /* MOVSD */ + DoString(R_MOVSD);break; + CASE_D(0xa7) /* CMPSD */ + DoString(R_CMPSD);break; + CASE_D(0xa9) /* TEST EAX,Id */ + EAXId(TESTD);break; + CASE_D(0xab) /* STOSD */ + DoString(R_STOSD);break; + CASE_D(0xad) /* LODSD */ + DoString(R_LODSD);break; + CASE_D(0xaf) /* SCASD */ + DoString(R_SCASD);break; + CASE_D(0xb8) /* MOV EAX,Id */ + reg_eax=Fetchd();break; + CASE_D(0xb9) /* MOV ECX,Id */ + reg_ecx=Fetchd();break; + CASE_D(0xba) /* MOV EDX,Iw */ + reg_edx=Fetchd();break; + CASE_D(0xbb) /* MOV EBX,Id */ + reg_ebx=Fetchd();break; + CASE_D(0xbc) /* MOV ESP,Id */ + reg_esp=Fetchd();break; + CASE_D(0xbd) /* MOV EBP.Id */ + reg_ebp=Fetchd();break; + CASE_D(0xbe) /* MOV ESI,Id */ + reg_esi=Fetchd();break; + CASE_D(0xbf) /* MOV EDI,Id */ + reg_edi=Fetchd();break; + CASE_D(0xc1) /* GRP2 Ed,Ib */ + GRP2D(Fetchb());break; + CASE_D(0xc2) /* RETN Iw */ + reg_eip=Pop_32(); + reg_esp+=Fetchw(); + continue; + CASE_D(0xc3) /* RETN */ + reg_eip=Pop_32(); + continue; + CASE_D(0xc4) /* LES */ + { + GetRMrd; + if (rm >= 0xc0) goto illegal_opcode; + GetEAa; + if (CPU_SetSegGeneral(es,LoadMw(eaa+4))) RUNEXCEPTION(); + *rmrd=LoadMd(eaa); + break; + } + CASE_D(0xc5) /* LDS */ + { + GetRMrd; + if (rm >= 0xc0) goto illegal_opcode; + GetEAa; + if (CPU_SetSegGeneral(ds,LoadMw(eaa+4))) RUNEXCEPTION(); + *rmrd=LoadMd(eaa); + break; + } + CASE_D(0xc7) /* MOV Ed,Id */ + { + GetRM; + if (rm >= 0xc0) {GetEArd;*eard=Fetchd();} + else {GetEAa;SaveMd(eaa,Fetchd());} + break; + } + CASE_D(0xc8) /* ENTER Iw,Ib */ + { + Bitu bytes=Fetchw(); + Bitu level=Fetchb(); + CPU_ENTER(true,bytes,level); + } + break; + CASE_D(0xc9) /* LEAVE */ + reg_esp&=cpu.stack.notmask; + reg_esp|=(reg_ebp&cpu.stack.mask); + reg_ebp=Pop_32(); + break; + CASE_D(0xca) /* RETF Iw */ + { + Bitu words=Fetchw(); + FillFlags(); + CPU_RET(true,words,GETIP); + continue; + } + CASE_D(0xcb) /* RETF */ + { + FillFlags(); + CPU_RET(true,0,GETIP); + continue; + } + CASE_D(0xcf) /* IRET */ + { + CPU_IRET(true,GETIP); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + return CBRET_NONE; + } +#endif +#if CPU_PIC_CHECK + if (GETFLAG(IF) && PIC_IRQCheck) return CBRET_NONE; +#endif + continue; + } + CASE_D(0xd1) /* GRP2 Ed,1 */ + GRP2D(1);break; + CASE_D(0xd3) /* GRP2 Ed,CL */ + GRP2D(reg_cl);break; + CASE_D(0xe0) /* LOOPNZ */ + if (TEST_PREFIX_ADDR) { + JumpCond32_b(--reg_ecx && !get_ZF()); + } else { + JumpCond32_b(--reg_cx && !get_ZF()); + } + break; + CASE_D(0xe1) /* LOOPZ */ + if (TEST_PREFIX_ADDR) { + JumpCond32_b(--reg_ecx && get_ZF()); + } else { + JumpCond32_b(--reg_cx && get_ZF()); + } + break; + CASE_D(0xe2) /* LOOP */ + if (TEST_PREFIX_ADDR) { + JumpCond32_b(--reg_ecx); + } else { + JumpCond32_b(--reg_cx); + } + break; + CASE_D(0xe3) /* JCXZ */ + JumpCond32_b(!(reg_ecx & AddrMaskTable[core.prefixes& PREFIX_ADDR])); + break; + CASE_D(0xe5) /* IN EAX,Ib */ + { + Bitu port=Fetchb(); + if (CPU_IO_Exception(port,4)) RUNEXCEPTION(); + reg_eax=IO_ReadD(port); + break; + } + CASE_D(0xe7) /* OUT Ib,EAX */ + { + Bitu port=Fetchb(); + if (CPU_IO_Exception(port,4)) RUNEXCEPTION(); + IO_WriteD(port,reg_eax); + break; + } + CASE_D(0xe8) /* CALL Jd */ + { + Bit32s addip=Fetchds(); + SAVEIP; + Push_32(reg_eip); + reg_eip+=addip; + continue; + } + CASE_D(0xe9) /* JMP Jd */ + { + Bit32s addip=Fetchds(); + SAVEIP; + reg_eip+=addip; + continue; + } + CASE_D(0xea) /* JMP Ad */ + { + Bit32u newip=Fetchd(); + Bit16u newcs=Fetchw(); + FillFlags(); + CPU_JMP(true,newcs,newip,GETIP); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + return CBRET_NONE; + } +#endif + continue; + } + CASE_D(0xeb) /* JMP Jb */ + { + Bit32s addip=Fetchbs(); + SAVEIP; + reg_eip+=addip; + continue; + } + CASE_D(0xed) /* IN EAX,DX */ + reg_eax=IO_ReadD(reg_dx); + break; + CASE_D(0xef) /* OUT DX,EAX */ + IO_WriteD(reg_dx,reg_eax); + break; + CASE_D(0xf7) /* GRP3 Ed(,Id) */ + { + GetRM;Bitu which=(rm>>3)&7; + switch (which) { + case 0x00: /* TEST Ed,Id */ + case 0x01: /* TEST Ed,Id Undocumented*/ + { + if (rm >= 0xc0 ) {GetEArd;TESTD(*eard,Fetchd(),LoadRd,SaveRd);} + else {GetEAa;TESTD(eaa,Fetchd(),LoadMd,SaveMd);} + break; + } + case 0x02: /* NOT Ed */ + { + if (rm >= 0xc0 ) {GetEArd;*eard=~*eard;} + else {GetEAa;SaveMd(eaa,~LoadMd(eaa));} + break; + } + case 0x03: /* NEG Ed */ + { + lflags.type=t_NEGd; + if (rm >= 0xc0 ) { + GetEArd;lf_var1d=*eard;lf_resd=0-lf_var1d; + *eard=lf_resd; + } else { + GetEAa;lf_var1d=LoadMd(eaa);lf_resd=0-lf_var1d; + SaveMd(eaa,lf_resd); + } + break; + } + case 0x04: /* MUL EAX,Ed */ + RMEd(MULD); + break; + case 0x05: /* IMUL EAX,Ed */ + RMEd(IMULD); + break; + case 0x06: /* DIV Ed */ + RMEd(DIVD); + break; + case 0x07: /* IDIV Ed */ + RMEd(IDIVD); + break; + } + break; + } + CASE_D(0xff) /* GRP 5 Ed */ + { + GetRM;Bitu which=(rm>>3)&7; + switch (which) { + case 0x00: /* INC Ed */ + RMEd(INCD); + break; + case 0x01: /* DEC Ed */ + RMEd(DECD); + break; + case 0x02: /* CALL NEAR Ed */ + if (rm >= 0xc0 ) {GetEArd;reg_eip=*eard;} + else {GetEAa;reg_eip=LoadMd(eaa);} + Push_32(GETIP); + continue; + case 0x03: /* CALL FAR Ed */ + { + if (rm >= 0xc0) goto illegal_opcode; + GetEAa; + Bit32u newip=LoadMd(eaa); + Bit16u newcs=LoadMw(eaa+4); + FillFlags(); + CPU_CALL(true,newcs,newip,GETIP); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + return CBRET_NONE; + } +#endif + continue; + } + case 0x04: /* JMP NEAR Ed */ + if (rm >= 0xc0 ) {GetEArd;reg_eip=*eard;} + else {GetEAa;reg_eip=LoadMd(eaa);} + continue; + case 0x05: /* JMP FAR Ed */ + { + if (rm >= 0xc0) goto illegal_opcode; + GetEAa; + Bit32u newip=LoadMd(eaa); + Bit16u newcs=LoadMw(eaa+4); + FillFlags(); + CPU_JMP(true,newcs,newip,GETIP); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + return CBRET_NONE; + } +#endif + continue; + } + break; + case 0x06: /* Push Ed */ + if (rm >= 0xc0 ) {GetEArd;Push_32(*eard);} + else {GetEAa;Push_32(LoadMd(eaa));} + break; + default: + LOG(LOG_CPU,LOG_ERROR)("CPU:66:GRP5:Illegal call %2X",which); + goto illegal_opcode; + } + break; + } + + diff --git a/dosbox/core_normal/prefix_66_0f.h b/dosbox/core_normal/prefix_66_0f.h new file mode 100644 index 00000000..eed5bac8 --- /dev/null +++ b/dosbox/core_normal/prefix_66_0f.h @@ -0,0 +1,465 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + CASE_0F_D(0x00) /* GRP 6 Exxx */ + { + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode; + GetRM;Bitu which=(rm>>3)&7; + switch (which) { + case 0x00: /* SLDT */ + case 0x01: /* STR */ + { + Bitu saveval; + if (!which) saveval=CPU_SLDT(); + else saveval=CPU_STR(); + if (rm >= 0xc0) {GetEArw;*earw=(Bit16u)saveval;} + else {GetEAa;SaveMw(eaa,saveval);} + } + break; + case 0x02:case 0x03:case 0x04:case 0x05: + { + /* Just use 16-bit loads since were only using selectors */ + Bitu loadval; + if (rm >= 0xc0 ) {GetEArw;loadval=*earw;} + else {GetEAa;loadval=LoadMw(eaa);} + switch (which) { + case 0x02: + if (cpu.cpl) EXCEPTION(EXCEPTION_GP); + if (CPU_LLDT(loadval)) RUNEXCEPTION(); + break; + case 0x03: + if (cpu.cpl) EXCEPTION(EXCEPTION_GP); + if (CPU_LTR(loadval)) RUNEXCEPTION(); + break; + case 0x04: + CPU_VERR(loadval); + break; + case 0x05: + CPU_VERW(loadval); + break; + } + } + break; + default: + LOG(LOG_CPU,LOG_ERROR)("GRP6:Illegal call %2X",which); + goto illegal_opcode; + } + } + break; + CASE_0F_D(0x01) /* Group 7 Ed */ + { + GetRM;Bitu which=(rm>>3)&7; + if (rm < 0xc0) { //First ones all use EA + GetEAa;Bitu limit; + switch (which) { + case 0x00: /* SGDT */ + SaveMw(eaa,(Bit16u)CPU_SGDT_limit()); + SaveMd(eaa+2,(Bit32u)CPU_SGDT_base()); + break; + case 0x01: /* SIDT */ + SaveMw(eaa,(Bit16u)CPU_SIDT_limit()); + SaveMd(eaa+2,(Bit32u)CPU_SIDT_base()); + break; + case 0x02: /* LGDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + CPU_LGDT(LoadMw(eaa),LoadMd(eaa+2)); + break; + case 0x03: /* LIDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + CPU_LIDT(LoadMw(eaa),LoadMd(eaa+2)); + break; + case 0x04: /* SMSW */ + SaveMw(eaa,(Bit16u)CPU_SMSW()); + break; + case 0x06: /* LMSW */ + limit=LoadMw(eaa); + if (CPU_LMSW((Bit16u)limit)) RUNEXCEPTION(); + break; + case 0x07: /* INVLPG */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + PAGING_ClearTLB(); + break; + } + } else { + GetEArd; + switch (which) { + case 0x02: /* LGDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + goto illegal_opcode; + case 0x03: /* LIDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + goto illegal_opcode; + case 0x04: /* SMSW */ + *eard=(Bit32u)CPU_SMSW(); + break; + case 0x06: /* LMSW */ + if (CPU_LMSW(*eard)) RUNEXCEPTION(); + break; + default: + LOG(LOG_CPU,LOG_ERROR)("Illegal group 7 RM subfunction %d",which); + goto illegal_opcode; + break; + } + + } + } + break; + CASE_0F_D(0x02) /* LAR Gd,Ed */ + { + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode; + GetRMrd;Bitu ar=*rmrd; + if (rm >= 0xc0) { + GetEArw;CPU_LAR(*earw,ar); + } else { + GetEAa;CPU_LAR(LoadMw(eaa),ar); + } + *rmrd=(Bit32u)ar; + } + break; + CASE_0F_D(0x03) /* LSL Gd,Ew */ + { + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode; + GetRMrd;Bitu limit=*rmrd; + /* Just load 16-bit values for selectors */ + if (rm >= 0xc0) { + GetEArw;CPU_LSL(*earw,limit); + } else { + GetEAa;CPU_LSL(LoadMw(eaa),limit); + } + *rmrd=(Bit32u)limit; + } + break; + CASE_0F_D(0x80) /* JO */ + JumpCond32_d(TFLG_O);break; + CASE_0F_D(0x81) /* JNO */ + JumpCond32_d(TFLG_NO);break; + CASE_0F_D(0x82) /* JB */ + JumpCond32_d(TFLG_B);break; + CASE_0F_D(0x83) /* JNB */ + JumpCond32_d(TFLG_NB);break; + CASE_0F_D(0x84) /* JZ */ + JumpCond32_d(TFLG_Z);break; + CASE_0F_D(0x85) /* JNZ */ + JumpCond32_d(TFLG_NZ);break; + CASE_0F_D(0x86) /* JBE */ + JumpCond32_d(TFLG_BE);break; + CASE_0F_D(0x87) /* JNBE */ + JumpCond32_d(TFLG_NBE);break; + CASE_0F_D(0x88) /* JS */ + JumpCond32_d(TFLG_S);break; + CASE_0F_D(0x89) /* JNS */ + JumpCond32_d(TFLG_NS);break; + CASE_0F_D(0x8a) /* JP */ + JumpCond32_d(TFLG_P);break; + CASE_0F_D(0x8b) /* JNP */ + JumpCond32_d(TFLG_NP);break; + CASE_0F_D(0x8c) /* JL */ + JumpCond32_d(TFLG_L);break; + CASE_0F_D(0x8d) /* JNL */ + JumpCond32_d(TFLG_NL);break; + CASE_0F_D(0x8e) /* JLE */ + JumpCond32_d(TFLG_LE);break; + CASE_0F_D(0x8f) /* JNLE */ + JumpCond32_d(TFLG_NLE);break; + + CASE_0F_D(0xa0) /* PUSH FS */ + Push_32(SegValue(fs));break; + CASE_0F_D(0xa1) /* POP FS */ + if (CPU_PopSeg(fs,true)) RUNEXCEPTION(); + break; + CASE_0F_D(0xa3) /* BT Ed,Gd */ + { + FillFlags();GetRMrd; + Bit32u mask=1 << (*rmrd & 31); + if (rm >= 0xc0 ) { + GetEArd; + SETFLAGBIT(CF,(*eard & mask)); + } else { + GetEAa;eaa+=(((Bit32s)*rmrd)>>5)*4; + Bit32u old=LoadMd(eaa); + SETFLAGBIT(CF,(old & mask)); + } + break; + } + CASE_0F_D(0xa4) /* SHLD Ed,Gd,Ib */ + RMEdGdOp3(DSHLD,Fetchb()); + break; + CASE_0F_D(0xa5) /* SHLD Ed,Gd,CL */ + RMEdGdOp3(DSHLD,reg_cl); + break; + CASE_0F_D(0xa8) /* PUSH GS */ + Push_32(SegValue(gs));break; + CASE_0F_D(0xa9) /* POP GS */ + if (CPU_PopSeg(gs,true)) RUNEXCEPTION(); + break; + CASE_0F_D(0xab) /* BTS Ed,Gd */ + { + FillFlags();GetRMrd; + Bit32u mask=1 << (*rmrd & 31); + if (rm >= 0xc0 ) { + GetEArd; + SETFLAGBIT(CF,(*eard & mask)); + *eard|=mask; + } else { + GetEAa;eaa+=(((Bit32s)*rmrd)>>5)*4; + Bit32u old=LoadMd(eaa); + SETFLAGBIT(CF,(old & mask)); + SaveMd(eaa,old | mask); + } + break; + } + + CASE_0F_D(0xac) /* SHRD Ed,Gd,Ib */ + RMEdGdOp3(DSHRD,Fetchb()); + break; + CASE_0F_D(0xad) /* SHRD Ed,Gd,CL */ + RMEdGdOp3(DSHRD,reg_cl); + break; + CASE_0F_D(0xaf) /* IMUL Gd,Ed */ + { + RMGdEdOp3(DIMULD,*rmrd); + break; + } + CASE_0F_D(0xb1) /* CMPXCHG Ed,Gd */ + { + if (CPU_ArchitectureType= 0xc0) { + GetEArd; + if (*eard==reg_eax) { + *eard=*rmrd; + SETFLAGBIT(ZF,1); + } else { + reg_eax=*eard; + SETFLAGBIT(ZF,0); + } + } else { + GetEAa; + Bit32u val=LoadMd(eaa); + if (val==reg_eax) { + SaveMd(eaa,*rmrd); + SETFLAGBIT(ZF,1); + } else { + SaveMd(eaa,val); // cmpxchg always issues a write + reg_eax=val; + SETFLAGBIT(ZF,0); + } + } + break; + } + CASE_0F_D(0xb2) /* LSS Ed */ + { + GetRMrd; + if (rm >= 0xc0) goto illegal_opcode; + GetEAa; + if (CPU_SetSegGeneral(ss,LoadMw(eaa+4))) RUNEXCEPTION(); + *rmrd=LoadMd(eaa); + break; + } + CASE_0F_D(0xb3) /* BTR Ed,Gd */ + { + FillFlags();GetRMrd; + Bit32u mask=1 << (*rmrd & 31); + if (rm >= 0xc0 ) { + GetEArd; + SETFLAGBIT(CF,(*eard & mask)); + *eard&= ~mask; + } else { + GetEAa;eaa+=(((Bit32s)*rmrd)>>5)*4; + Bit32u old=LoadMd(eaa); + SETFLAGBIT(CF,(old & mask)); + SaveMd(eaa,old & ~mask); + } + break; + } + CASE_0F_D(0xb4) /* LFS Ed */ + { + GetRMrd; + if (rm >= 0xc0) goto illegal_opcode; + GetEAa; + if (CPU_SetSegGeneral(fs,LoadMw(eaa+4))) RUNEXCEPTION(); + *rmrd=LoadMd(eaa); + break; + } + CASE_0F_D(0xb5) /* LGS Ed */ + { + GetRMrd; + if (rm >= 0xc0) goto illegal_opcode; + GetEAa; + if (CPU_SetSegGeneral(gs,LoadMw(eaa+4))) RUNEXCEPTION(); + *rmrd=LoadMd(eaa); + break; + } + CASE_0F_D(0xb6) /* MOVZX Gd,Eb */ + { + GetRMrd; + if (rm >= 0xc0 ) {GetEArb;*rmrd=*earb;} + else {GetEAa;*rmrd=LoadMb(eaa);} + break; + } + CASE_0F_D(0xb7) /* MOVXZ Gd,Ew */ + { + GetRMrd; + if (rm >= 0xc0 ) {GetEArw;*rmrd=*earw;} + else {GetEAa;*rmrd=LoadMw(eaa);} + break; + } + CASE_0F_D(0xba) /* GRP8 Ed,Ib */ + { + FillFlags();GetRM; + if (rm >= 0xc0 ) { + GetEArd; + Bit32u mask=1 << (Fetchb() & 31); + SETFLAGBIT(CF,(*eard & mask)); + switch (rm & 0x38) { + case 0x20: /* BT */ + break; + case 0x28: /* BTS */ + *eard|=mask; + break; + case 0x30: /* BTR */ + *eard&=~mask; + break; + case 0x38: /* BTC */ + if (GETFLAG(CF)) *eard&=~mask; + else *eard|=mask; + break; + default: + E_Exit("CPU:66:0F:BA:Illegal subfunction %X",rm & 0x38); + } + } else { + GetEAa;Bit32u old=LoadMd(eaa); + Bit32u mask=1 << (Fetchb() & 31); + SETFLAGBIT(CF,(old & mask)); + switch (rm & 0x38) { + case 0x20: /* BT */ + break; + case 0x28: /* BTS */ + SaveMd(eaa,old|mask); + break; + case 0x30: /* BTR */ + SaveMd(eaa,old & ~mask); + break; + case 0x38: /* BTC */ + if (GETFLAG(CF)) old&=~mask; + else old|=mask; + SaveMd(eaa,old); + break; + default: + E_Exit("CPU:66:0F:BA:Illegal subfunction %X",rm & 0x38); + } + } + break; + } + CASE_0F_D(0xbb) /* BTC Ed,Gd */ + { + FillFlags();GetRMrd; + Bit32u mask=1 << (*rmrd & 31); + if (rm >= 0xc0 ) { + GetEArd; + SETFLAGBIT(CF,(*eard & mask)); + *eard^=mask; + } else { + GetEAa;eaa+=(((Bit32s)*rmrd)>>5)*4; + Bit32u old=LoadMd(eaa); + SETFLAGBIT(CF,(old & mask)); + SaveMd(eaa,old ^ mask); + } + break; + } + CASE_0F_D(0xbc) /* BSF Gd,Ed */ + { + GetRMrd; + Bit32u result,value; + if (rm >= 0xc0) { GetEArd; value=*eard; } + else { GetEAa; value=LoadMd(eaa); } + if (value==0) { + SETFLAGBIT(ZF,true); + } else { + result = 0; + while ((value & 0x01)==0) { result++; value>>=1; } + SETFLAGBIT(ZF,false); + *rmrd = result; + } + lflags.type=t_UNKNOWN; + break; + } + CASE_0F_D(0xbd) /* BSR Gd,Ed */ + { + GetRMrd; + Bit32u result,value; + if (rm >= 0xc0) { GetEArd; value=*eard; } + else { GetEAa; value=LoadMd(eaa); } + if (value==0) { + SETFLAGBIT(ZF,true); + } else { + result = 31; // Operandsize-1 + while ((value & 0x80000000)==0) { result--; value<<=1; } + SETFLAGBIT(ZF,false); + *rmrd = result; + } + lflags.type=t_UNKNOWN; + break; + } + CASE_0F_D(0xbe) /* MOVSX Gd,Eb */ + { + GetRMrd; + if (rm >= 0xc0 ) {GetEArb;*rmrd=*(Bit8s *)earb;} + else {GetEAa;*rmrd=LoadMbs(eaa);} + break; + } + CASE_0F_D(0xbf) /* MOVSX Gd,Ew */ + { + GetRMrd; + if (rm >= 0xc0 ) {GetEArw;*rmrd=*(Bit16s *)earw;} + else {GetEAa;*rmrd=LoadMws(eaa);} + break; + } + CASE_0F_D(0xc1) /* XADD Gd,Ed */ + { + if (CPU_ArchitectureType= 0xc0 ) {GetEArd;*rmrd=*eard;*eard+=oldrmrd;} + else {GetEAa;*rmrd=LoadMd(eaa);SaveMd(eaa,LoadMd(eaa)+oldrmrd);} + break; + } + CASE_0F_D(0xc8) /* BSWAP EAX */ + if (CPU_ArchitectureType bound_max) ) { + EXCEPTION(5); + } + } + break; + CASE_W(0x63) /* ARPL Ew,Rw */ + { + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode; + GetRMrw; + if (rm >= 0xc0 ) { + GetEArw;Bitu new_sel=*earw; + CPU_ARPL(new_sel,*rmrw); + *earw=(Bit16u)new_sel; + } else { + GetEAa;Bitu new_sel=LoadMw(eaa); + CPU_ARPL(new_sel,*rmrw); + SaveMw(eaa,(Bit16u)new_sel); + } + } + break; + CASE_B(0x64) /* SEG FS: */ + DO_PREFIX_SEG(fs);break; + CASE_B(0x65) /* SEG GS: */ + DO_PREFIX_SEG(gs);break; + CASE_B(0x66) /* Operand Size Prefix */ + core.opcode_index=(cpu.code.big^0x1)*0x200; + goto restart_opcode; + CASE_B(0x67) /* Address Size Prefix */ + DO_PREFIX_ADDR(); + CASE_W(0x68) /* PUSH Iw */ + Push_16(Fetchw());break; + CASE_W(0x69) /* IMUL Gw,Ew,Iw */ + RMGwEwOp3(DIMULW,Fetchws()); + break; + CASE_W(0x6a) /* PUSH Ib */ + Push_16(Fetchbs()); + break; + CASE_W(0x6b) /* IMUL Gw,Ew,Ib */ + RMGwEwOp3(DIMULW,Fetchbs()); + break; + CASE_B(0x6c) /* INSB */ + if (CPU_IO_Exception(reg_dx,1)) RUNEXCEPTION(); + DoString(R_INSB);break; + CASE_W(0x6d) /* INSW */ + if (CPU_IO_Exception(reg_dx,2)) RUNEXCEPTION(); + DoString(R_INSW);break; + CASE_B(0x6e) /* OUTSB */ + if (CPU_IO_Exception(reg_dx,1)) RUNEXCEPTION(); + DoString(R_OUTSB);break; + CASE_W(0x6f) /* OUTSW */ + if (CPU_IO_Exception(reg_dx,2)) RUNEXCEPTION(); + DoString(R_OUTSW);break; + CASE_W(0x70) /* JO */ + JumpCond16_b(TFLG_O);break; + CASE_W(0x71) /* JNO */ + JumpCond16_b(TFLG_NO);break; + CASE_W(0x72) /* JB */ + JumpCond16_b(TFLG_B);break; + CASE_W(0x73) /* JNB */ + JumpCond16_b(TFLG_NB);break; + CASE_W(0x74) /* JZ */ + JumpCond16_b(TFLG_Z);break; + CASE_W(0x75) /* JNZ */ + JumpCond16_b(TFLG_NZ);break; + CASE_W(0x76) /* JBE */ + JumpCond16_b(TFLG_BE);break; + CASE_W(0x77) /* JNBE */ + JumpCond16_b(TFLG_NBE);break; + CASE_W(0x78) /* JS */ + JumpCond16_b(TFLG_S);break; + CASE_W(0x79) /* JNS */ + JumpCond16_b(TFLG_NS);break; + CASE_W(0x7a) /* JP */ + JumpCond16_b(TFLG_P);break; + CASE_W(0x7b) /* JNP */ + JumpCond16_b(TFLG_NP);break; + CASE_W(0x7c) /* JL */ + JumpCond16_b(TFLG_L);break; + CASE_W(0x7d) /* JNL */ + JumpCond16_b(TFLG_NL);break; + CASE_W(0x7e) /* JLE */ + JumpCond16_b(TFLG_LE);break; + CASE_W(0x7f) /* JNLE */ + JumpCond16_b(TFLG_NLE);break; + CASE_B(0x80) /* Grpl Eb,Ib */ + CASE_B(0x82) /* Grpl Eb,Ib Mirror instruction*/ + { + GetRM;Bitu which=(rm>>3)&7; + if (rm>= 0xc0) { + GetEArb;Bit8u ib=Fetchb(); + switch (which) { + case 0x00:ADDB(*earb,ib,LoadRb,SaveRb);break; + case 0x01: ORB(*earb,ib,LoadRb,SaveRb);break; + case 0x02:ADCB(*earb,ib,LoadRb,SaveRb);break; + case 0x03:SBBB(*earb,ib,LoadRb,SaveRb);break; + case 0x04:ANDB(*earb,ib,LoadRb,SaveRb);break; + case 0x05:SUBB(*earb,ib,LoadRb,SaveRb);break; + case 0x06:XORB(*earb,ib,LoadRb,SaveRb);break; + case 0x07:CMPB(*earb,ib,LoadRb,SaveRb);break; + } + } else { + GetEAa;Bit8u ib=Fetchb(); + switch (which) { + case 0x00:ADDB(eaa,ib,LoadMb,SaveMb);break; + case 0x01: ORB(eaa,ib,LoadMb,SaveMb);break; + case 0x02:ADCB(eaa,ib,LoadMb,SaveMb);break; + case 0x03:SBBB(eaa,ib,LoadMb,SaveMb);break; + case 0x04:ANDB(eaa,ib,LoadMb,SaveMb);break; + case 0x05:SUBB(eaa,ib,LoadMb,SaveMb);break; + case 0x06:XORB(eaa,ib,LoadMb,SaveMb);break; + case 0x07:CMPB(eaa,ib,LoadMb,SaveMb);break; + } + } + break; + } + CASE_W(0x81) /* Grpl Ew,Iw */ + { + GetRM;Bitu which=(rm>>3)&7; + if (rm>= 0xc0) { + GetEArw;Bit16u iw=Fetchw(); + switch (which) { + case 0x00:ADDW(*earw,iw,LoadRw,SaveRw);break; + case 0x01: ORW(*earw,iw,LoadRw,SaveRw);break; + case 0x02:ADCW(*earw,iw,LoadRw,SaveRw);break; + case 0x03:SBBW(*earw,iw,LoadRw,SaveRw);break; + case 0x04:ANDW(*earw,iw,LoadRw,SaveRw);break; + case 0x05:SUBW(*earw,iw,LoadRw,SaveRw);break; + case 0x06:XORW(*earw,iw,LoadRw,SaveRw);break; + case 0x07:CMPW(*earw,iw,LoadRw,SaveRw);break; + } + } else { + GetEAa;Bit16u iw=Fetchw(); + switch (which) { + case 0x00:ADDW(eaa,iw,LoadMw,SaveMw);break; + case 0x01: ORW(eaa,iw,LoadMw,SaveMw);break; + case 0x02:ADCW(eaa,iw,LoadMw,SaveMw);break; + case 0x03:SBBW(eaa,iw,LoadMw,SaveMw);break; + case 0x04:ANDW(eaa,iw,LoadMw,SaveMw);break; + case 0x05:SUBW(eaa,iw,LoadMw,SaveMw);break; + case 0x06:XORW(eaa,iw,LoadMw,SaveMw);break; + case 0x07:CMPW(eaa,iw,LoadMw,SaveMw);break; + } + } + break; + } + CASE_W(0x83) /* Grpl Ew,Ix */ + { + GetRM;Bitu which=(rm>>3)&7; + if (rm>= 0xc0) { + GetEArw;Bit16u iw=(Bit16s)Fetchbs(); + switch (which) { + case 0x00:ADDW(*earw,iw,LoadRw,SaveRw);break; + case 0x01: ORW(*earw,iw,LoadRw,SaveRw);break; + case 0x02:ADCW(*earw,iw,LoadRw,SaveRw);break; + case 0x03:SBBW(*earw,iw,LoadRw,SaveRw);break; + case 0x04:ANDW(*earw,iw,LoadRw,SaveRw);break; + case 0x05:SUBW(*earw,iw,LoadRw,SaveRw);break; + case 0x06:XORW(*earw,iw,LoadRw,SaveRw);break; + case 0x07:CMPW(*earw,iw,LoadRw,SaveRw);break; + } + } else { + GetEAa;Bit16u iw=(Bit16s)Fetchbs(); + switch (which) { + case 0x00:ADDW(eaa,iw,LoadMw,SaveMw);break; + case 0x01: ORW(eaa,iw,LoadMw,SaveMw);break; + case 0x02:ADCW(eaa,iw,LoadMw,SaveMw);break; + case 0x03:SBBW(eaa,iw,LoadMw,SaveMw);break; + case 0x04:ANDW(eaa,iw,LoadMw,SaveMw);break; + case 0x05:SUBW(eaa,iw,LoadMw,SaveMw);break; + case 0x06:XORW(eaa,iw,LoadMw,SaveMw);break; + case 0x07:CMPW(eaa,iw,LoadMw,SaveMw);break; + } + } + break; + } + CASE_B(0x84) /* TEST Eb,Gb */ + RMEbGb(TESTB); + break; + CASE_W(0x85) /* TEST Ew,Gw */ + RMEwGw(TESTW); + break; + CASE_B(0x86) /* XCHG Eb,Gb */ + { + GetRMrb;Bit8u oldrmrb=*rmrb; + if (rm >= 0xc0 ) {GetEArb;*rmrb=*earb;*earb=oldrmrb;} + else {GetEAa;*rmrb=LoadMb(eaa);SaveMb(eaa,oldrmrb);} + break; + } + CASE_W(0x87) /* XCHG Ew,Gw */ + { + GetRMrw;Bit16u oldrmrw=*rmrw; + if (rm >= 0xc0 ) {GetEArw;*rmrw=*earw;*earw=oldrmrw;} + else {GetEAa;*rmrw=LoadMw(eaa);SaveMw(eaa,oldrmrw);} + break; + } + CASE_B(0x88) /* MOV Eb,Gb */ + { + GetRMrb; + if (rm >= 0xc0 ) {GetEArb;*earb=*rmrb;} + else { + if (cpu.pmode) { + if (GCC_UNLIKELY((rm==0x05) && (!cpu.code.big))) { + Descriptor desc; + cpu.gdt.GetDescriptor(SegValue(core.base_val_ds),desc); + if ((desc.Type()==DESC_CODE_R_NC_A) || (desc.Type()==DESC_CODE_R_NC_NA)) { + CPU_Exception(EXCEPTION_GP,SegValue(core.base_val_ds) & 0xfffc); + continue; + } + } + } + GetEAa;SaveMb(eaa,*rmrb); + } + break; + } + CASE_W(0x89) /* MOV Ew,Gw */ + { + GetRMrw; + if (rm >= 0xc0 ) {GetEArw;*earw=*rmrw;} + else {GetEAa;SaveMw(eaa,*rmrw);} + break; + } + CASE_B(0x8a) /* MOV Gb,Eb */ + { + GetRMrb; + if (rm >= 0xc0 ) {GetEArb;*rmrb=*earb;} + else {GetEAa;*rmrb=LoadMb(eaa);} + break; + } + CASE_W(0x8b) /* MOV Gw,Ew */ + { + GetRMrw; + if (rm >= 0xc0 ) {GetEArw;*rmrw=*earw;} + else {GetEAa;*rmrw=LoadMw(eaa);} + break; + } + CASE_W(0x8c) /* Mov Ew,Sw */ + { + GetRM;Bit16u val;Bitu which=(rm>>3)&7; + switch (which) { + case 0x00: /* MOV Ew,ES */ + val=SegValue(es);break; + case 0x01: /* MOV Ew,CS */ + val=SegValue(cs);break; + case 0x02: /* MOV Ew,SS */ + val=SegValue(ss);break; + case 0x03: /* MOV Ew,DS */ + val=SegValue(ds);break; + case 0x04: /* MOV Ew,FS */ + val=SegValue(fs);break; + case 0x05: /* MOV Ew,GS */ + val=SegValue(gs);break; + default: + LOG(LOG_CPU,LOG_ERROR)("CPU:8c:Illegal RM Byte"); + goto illegal_opcode; + } + if (rm >= 0xc0 ) {GetEArw;*earw=val;} + else {GetEAa;SaveMw(eaa,val);} + break; + } + CASE_W(0x8d) /* LEA Gw */ + { + //Little hack to always use segprefixed version + BaseDS=BaseSS=0; + GetRMrw; + if (TEST_PREFIX_ADDR) { + *rmrw=(Bit16u)(*EATable[256+rm])(); + } else { + *rmrw=(Bit16u)(*EATable[rm])(); + } + break; + } + CASE_B(0x8e) /* MOV Sw,Ew */ + { + GetRM;Bit16u val;Bitu which=(rm>>3)&7; + if (rm >= 0xc0 ) {GetEArw;val=*earw;} + else {GetEAa;val=LoadMw(eaa);} + switch (which) { + case 0x02: /* MOV SS,Ew */ + CPU_Cycles++; //Always do another instruction + case 0x00: /* MOV ES,Ew */ + case 0x03: /* MOV DS,Ew */ + case 0x05: /* MOV GS,Ew */ + case 0x04: /* MOV FS,Ew */ + if (CPU_SetSegGeneral((SegNames)which,val)) RUNEXCEPTION(); + break; + default: + goto illegal_opcode; + } + break; + } + CASE_W(0x8f) /* POP Ew */ + { + Bit16u val=Pop_16(); + GetRM; + if (rm >= 0xc0 ) {GetEArw;*earw=val;} + else {GetEAa;SaveMw(eaa,val);} + break; + } + CASE_B(0x90) /* NOP */ + break; + CASE_W(0x91) /* XCHG CX,AX */ + { Bit16u temp=reg_ax;reg_ax=reg_cx;reg_cx=temp; } + break; + CASE_W(0x92) /* XCHG DX,AX */ + { Bit16u temp=reg_ax;reg_ax=reg_dx;reg_dx=temp; } + break; + CASE_W(0x93) /* XCHG BX,AX */ + { Bit16u temp=reg_ax;reg_ax=reg_bx;reg_bx=temp; } + break; + CASE_W(0x94) /* XCHG SP,AX */ + { Bit16u temp=reg_ax;reg_ax=reg_sp;reg_sp=temp; } + break; + CASE_W(0x95) /* XCHG BP,AX */ + { Bit16u temp=reg_ax;reg_ax=reg_bp;reg_bp=temp; } + break; + CASE_W(0x96) /* XCHG SI,AX */ + { Bit16u temp=reg_ax;reg_ax=reg_si;reg_si=temp; } + break; + CASE_W(0x97) /* XCHG DI,AX */ + { Bit16u temp=reg_ax;reg_ax=reg_di;reg_di=temp; } + break; + CASE_W(0x98) /* CBW */ + reg_ax=(Bit8s)reg_al;break; + CASE_W(0x99) /* CWD */ + if (reg_ax & 0x8000) reg_dx=0xffff;else reg_dx=0; + break; + CASE_W(0x9a) /* CALL Ap */ + { + FillFlags(); + Bit16u newip=Fetchw();Bit16u newcs=Fetchw(); + CPU_CALL(false,newcs,newip,GETIP); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + return CBRET_NONE; + } +#endif + continue; + } + CASE_B(0x9b) /* WAIT */ + break; /* No waiting here */ + CASE_W(0x9c) /* PUSHF */ + if (CPU_PUSHF(false)) RUNEXCEPTION(); + break; + CASE_W(0x9d) /* POPF */ + if (CPU_POPF(false)) RUNEXCEPTION(); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + goto decode_end; + } +#endif +#if CPU_PIC_CHECK + if (GETFLAG(IF) && PIC_IRQCheck) goto decode_end; +#endif + break; + CASE_B(0x9e) /* SAHF */ + SETFLAGSb(reg_ah); + break; + CASE_B(0x9f) /* LAHF */ + FillFlags(); + reg_ah=reg_flags&0xff; + break; + CASE_B(0xa0) /* MOV AL,Ob */ + { + GetEADirect; + reg_al=LoadMb(eaa); + } + break; + CASE_W(0xa1) /* MOV AX,Ow */ + { + GetEADirect; + reg_ax=LoadMw(eaa); + } + break; + CASE_B(0xa2) /* MOV Ob,AL */ + { + GetEADirect; + SaveMb(eaa,reg_al); + } + break; + CASE_W(0xa3) /* MOV Ow,AX */ + { + GetEADirect; + SaveMw(eaa,reg_ax); + } + break; + CASE_B(0xa4) /* MOVSB */ + DoString(R_MOVSB);break; + CASE_W(0xa5) /* MOVSW */ + DoString(R_MOVSW);break; + CASE_B(0xa6) /* CMPSB */ + DoString(R_CMPSB);break; + CASE_W(0xa7) /* CMPSW */ + DoString(R_CMPSW);break; + CASE_B(0xa8) /* TEST AL,Ib */ + ALIb(TESTB);break; + CASE_W(0xa9) /* TEST AX,Iw */ + AXIw(TESTW);break; + CASE_B(0xaa) /* STOSB */ + DoString(R_STOSB);break; + CASE_W(0xab) /* STOSW */ + DoString(R_STOSW);break; + CASE_B(0xac) /* LODSB */ + DoString(R_LODSB);break; + CASE_W(0xad) /* LODSW */ + DoString(R_LODSW);break; + CASE_B(0xae) /* SCASB */ + DoString(R_SCASB);break; + CASE_W(0xaf) /* SCASW */ + DoString(R_SCASW);break; + CASE_B(0xb0) /* MOV AL,Ib */ + reg_al=Fetchb();break; + CASE_B(0xb1) /* MOV CL,Ib */ + reg_cl=Fetchb();break; + CASE_B(0xb2) /* MOV DL,Ib */ + reg_dl=Fetchb();break; + CASE_B(0xb3) /* MOV BL,Ib */ + reg_bl=Fetchb();break; + CASE_B(0xb4) /* MOV AH,Ib */ + reg_ah=Fetchb();break; + CASE_B(0xb5) /* MOV CH,Ib */ + reg_ch=Fetchb();break; + CASE_B(0xb6) /* MOV DH,Ib */ + reg_dh=Fetchb();break; + CASE_B(0xb7) /* MOV BH,Ib */ + reg_bh=Fetchb();break; + CASE_W(0xb8) /* MOV AX,Iw */ + reg_ax=Fetchw();break; + CASE_W(0xb9) /* MOV CX,Iw */ + reg_cx=Fetchw();break; + CASE_W(0xba) /* MOV DX,Iw */ + reg_dx=Fetchw();break; + CASE_W(0xbb) /* MOV BX,Iw */ + reg_bx=Fetchw();break; + CASE_W(0xbc) /* MOV SP,Iw */ + reg_sp=Fetchw();break; + CASE_W(0xbd) /* MOV BP.Iw */ + reg_bp=Fetchw();break; + CASE_W(0xbe) /* MOV SI,Iw */ + reg_si=Fetchw();break; + CASE_W(0xbf) /* MOV DI,Iw */ + reg_di=Fetchw();break; + CASE_B(0xc0) /* GRP2 Eb,Ib */ + GRP2B(Fetchb());break; + CASE_W(0xc1) /* GRP2 Ew,Ib */ + GRP2W(Fetchb());break; + CASE_W(0xc2) /* RETN Iw */ + reg_eip=Pop_16(); + reg_esp+=Fetchw(); + continue; + CASE_W(0xc3) /* RETN */ + reg_eip=Pop_16(); + continue; + CASE_W(0xc4) /* LES */ + { + GetRMrw; + if (rm >= 0xc0) goto illegal_opcode; + GetEAa; + if (CPU_SetSegGeneral(es,LoadMw(eaa+2))) RUNEXCEPTION(); + *rmrw=LoadMw(eaa); + break; + } + CASE_W(0xc5) /* LDS */ + { + GetRMrw; + if (rm >= 0xc0) goto illegal_opcode; + GetEAa; + if (CPU_SetSegGeneral(ds,LoadMw(eaa+2))) RUNEXCEPTION(); + *rmrw=LoadMw(eaa); + break; + } + CASE_B(0xc6) /* MOV Eb,Ib */ + { + GetRM; + if (rm >= 0xc0) {GetEArb;*earb=Fetchb();} + else {GetEAa;SaveMb(eaa,Fetchb());} + break; + } + CASE_W(0xc7) /* MOV EW,Iw */ + { + GetRM; + if (rm >= 0xc0) {GetEArw;*earw=Fetchw();} + else {GetEAa;SaveMw(eaa,Fetchw());} + break; + } + CASE_W(0xc8) /* ENTER Iw,Ib */ + { + Bitu bytes=Fetchw(); + Bitu level=Fetchb(); + CPU_ENTER(false,bytes,level); + } + break; + CASE_W(0xc9) /* LEAVE */ + reg_esp&=cpu.stack.notmask; + reg_esp|=(reg_ebp&cpu.stack.mask); + reg_bp=Pop_16(); + break; + CASE_W(0xca) /* RETF Iw */ + { + Bitu words=Fetchw(); + FillFlags(); + CPU_RET(false,words,GETIP); + continue; + } + CASE_W(0xcb) /* RETF */ + FillFlags(); + CPU_RET(false,0,GETIP); + continue; + CASE_B(0xcc) /* INT3 */ +#if C_DEBUG + FillFlags(); + if (DEBUG_Breakpoint()) + return debugCallback; +#endif + CPU_SW_Interrupt_NoIOPLCheck(3,GETIP); +#if CPU_TRAP_CHECK + cpu.trap_skip=true; +#endif + continue; + CASE_B(0xcd) /* INT Ib */ + { + Bit8u num=Fetchb(); +#if C_DEBUG + FillFlags(); + if (DEBUG_IntBreakpoint(num)) { + return debugCallback; + } +#endif + CPU_SW_Interrupt(num,GETIP); +#if CPU_TRAP_CHECK + cpu.trap_skip=true; +#endif + continue; + } + CASE_B(0xce) /* INTO */ + if (get_OF()) { + CPU_SW_Interrupt(4,GETIP); +#if CPU_TRAP_CHECK + cpu.trap_skip=true; +#endif + continue; + } + break; + CASE_W(0xcf) /* IRET */ + { + CPU_IRET(false,GETIP); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + return CBRET_NONE; + } +#endif +#if CPU_PIC_CHECK + if (GETFLAG(IF) && PIC_IRQCheck) return CBRET_NONE; +#endif + continue; + } + CASE_B(0xd0) /* GRP2 Eb,1 */ + GRP2B(1);break; + CASE_W(0xd1) /* GRP2 Ew,1 */ + GRP2W(1);break; + CASE_B(0xd2) /* GRP2 Eb,CL */ + GRP2B(reg_cl);break; + CASE_W(0xd3) /* GRP2 Ew,CL */ + GRP2W(reg_cl);break; + CASE_B(0xd4) /* AAM Ib */ + AAM(Fetchb());break; + CASE_B(0xd5) /* AAD Ib */ + AAD(Fetchb());break; + CASE_B(0xd6) /* SALC */ + reg_al = get_CF() ? 0xFF : 0; + break; + CASE_B(0xd7) /* XLAT */ + if (TEST_PREFIX_ADDR) { + reg_al=LoadMb(BaseDS+(Bit32u)(reg_ebx+reg_al)); + } else { + reg_al=LoadMb(BaseDS+(Bit16u)(reg_bx+reg_al)); + } + break; +#ifdef CPU_FPU + CASE_B(0xd8) /* FPU ESC 0 */ + if (x86_fpu_enabled) { + FPU_ESC(0); + } else { + Bit8u rm = Fetchb(); + if (rm<0xc0) GetEAa; + } + break; + CASE_B(0xd9) /* FPU ESC 1 */ + if (x86_fpu_enabled) { + FPU_ESC(1); + } else { + Bit8u rm = Fetchb(); + if (rm<0xc0) GetEAa; + } + break; + CASE_B(0xda) /* FPU ESC 2 */ + if (x86_fpu_enabled) { + FPU_ESC(2); + } else { + Bit8u rm = Fetchb(); + if (rm<0xc0) GetEAa; + } + break; + CASE_B(0xdb) /* FPU ESC 3 */ + if (x86_fpu_enabled) { + FPU_ESC(3); + } else { + Bit8u rm = Fetchb(); + if (rm<0xc0) GetEAa; + } + break; + CASE_B(0xdc) /* FPU ESC 4 */ + if (x86_fpu_enabled) { + FPU_ESC(4); + } else { + Bit8u rm = Fetchb(); + if (rm<0xc0) GetEAa; + } + break; + CASE_B(0xdd) /* FPU ESC 5 */ + if (x86_fpu_enabled) { + FPU_ESC(5); + } else { + Bit8u rm = Fetchb(); + if (rm<0xc0) GetEAa; + } + break; + CASE_B(0xde) /* FPU ESC 6 */ + if (x86_fpu_enabled) { + FPU_ESC(6); + } else { + Bit8u rm = Fetchb(); + if (rm<0xc0) GetEAa; + } + break; + CASE_B(0xdf) /* FPU ESC 7 */ + if (x86_fpu_enabled) { + FPU_ESC(7); + } else { + Bit8u rm = Fetchb(); + if (rm<0xc0) GetEAa; + } + break; +#else + CASE_B(0xd8) /* FPU ESC 0 */ + CASE_B(0xd9) /* FPU ESC 1 */ + CASE_B(0xda) /* FPU ESC 2 */ + CASE_B(0xdb) /* FPU ESC 3 */ + CASE_B(0xdc) /* FPU ESC 4 */ + CASE_B(0xdd) /* FPU ESC 5 */ + CASE_B(0xde) /* FPU ESC 6 */ + CASE_B(0xdf) /* FPU ESC 7 */ + { + LOG(LOG_CPU,LOG_NORMAL)("FPU used"); + Bit8u rm=Fetchb(); + if (rm<0xc0) GetEAa; + } + break; +#endif + CASE_W(0xe0) /* LOOPNZ */ + if (TEST_PREFIX_ADDR) { + JumpCond16_b(--reg_ecx && !get_ZF()); + } else { + JumpCond16_b(--reg_cx && !get_ZF()); + } + break; + CASE_W(0xe1) /* LOOPZ */ + if (TEST_PREFIX_ADDR) { + JumpCond16_b(--reg_ecx && get_ZF()); + } else { + JumpCond16_b(--reg_cx && get_ZF()); + } + break; + CASE_W(0xe2) /* LOOP */ + if (TEST_PREFIX_ADDR) { + JumpCond16_b(--reg_ecx); + } else { + JumpCond16_b(--reg_cx); + } + break; + CASE_W(0xe3) /* JCXZ */ + JumpCond16_b(!(reg_ecx & AddrMaskTable[core.prefixes& PREFIX_ADDR])); + break; + CASE_B(0xe4) /* IN AL,Ib */ + { + Bitu port=Fetchb(); + if (CPU_IO_Exception(port,1)) RUNEXCEPTION(); + reg_al=IO_ReadB(port); + break; + } + CASE_W(0xe5) /* IN AX,Ib */ + { + Bitu port=Fetchb(); + if (CPU_IO_Exception(port,2)) RUNEXCEPTION(); + reg_al=IO_ReadW(port); + break; + } + CASE_B(0xe6) /* OUT Ib,AL */ + { + Bitu port=Fetchb(); + if (CPU_IO_Exception(port,1)) RUNEXCEPTION(); + IO_WriteB(port,reg_al); + break; + } + CASE_W(0xe7) /* OUT Ib,AX */ + { + Bitu port=Fetchb(); + if (CPU_IO_Exception(port,2)) RUNEXCEPTION(); + IO_WriteW(port,reg_ax); + break; + } + CASE_W(0xe8) /* CALL Jw */ + { + Bit16u addip=Fetchws(); + SAVEIP; + Push_16(reg_eip); + reg_eip=(Bit16u)(reg_eip+addip); + continue; + } + CASE_W(0xe9) /* JMP Jw */ + { + Bit16u addip=Fetchws(); + SAVEIP; + reg_eip=(Bit16u)(reg_eip+addip); + continue; + } + CASE_W(0xea) /* JMP Ap */ + { + Bit16u newip=Fetchw(); + Bit16u newcs=Fetchw(); + FillFlags(); + CPU_JMP(false,newcs,newip,GETIP); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + return CBRET_NONE; + } +#endif + continue; + } + CASE_W(0xeb) /* JMP Jb */ + { + Bit16s addip=Fetchbs(); + SAVEIP; + reg_eip=(Bit16u)(reg_eip+addip); + continue; + } + CASE_B(0xec) /* IN AL,DX */ + if (CPU_IO_Exception(reg_dx,1)) RUNEXCEPTION(); + reg_al=IO_ReadB(reg_dx); + break; + CASE_W(0xed) /* IN AX,DX */ + if (CPU_IO_Exception(reg_dx,2)) RUNEXCEPTION(); + reg_ax=IO_ReadW(reg_dx); + break; + CASE_B(0xee) /* OUT DX,AL */ + if (CPU_IO_Exception(reg_dx,1)) RUNEXCEPTION(); + IO_WriteB(reg_dx,reg_al); + break; + CASE_W(0xef) /* OUT DX,AX */ + if (CPU_IO_Exception(reg_dx,2)) RUNEXCEPTION(); + IO_WriteW(reg_dx,reg_ax); + break; + CASE_B(0xf0) /* LOCK */ + LOG(LOG_CPU,LOG_NORMAL)("CPU:LOCK"); /* FIXME: see case D_LOCK in core_full/load.h */ + break; + CASE_B(0xf1) /* ICEBP */ + CPU_SW_Interrupt_NoIOPLCheck(1,GETIP); +#if CPU_TRAP_CHECK + cpu.trap_skip=true; +#endif + continue; + CASE_B(0xf2) /* REPNZ */ + DO_PREFIX_REP(false); + break; + CASE_B(0xf3) /* REPZ */ + DO_PREFIX_REP(true); + break; + CASE_B(0xf4) /* HLT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + FillFlags(); + CPU_HLT(GETIP); + return CBRET_NONE; //Needs to return for hlt cpu core + CASE_B(0xf5) /* CMC */ + FillFlags(); + SETFLAGBIT(CF,!(reg_flags & FLAG_CF)); + break; + CASE_B(0xf6) /* GRP3 Eb(,Ib) */ + { + GetRM;Bitu which=(rm>>3)&7; + switch (which) { + case 0x00: /* TEST Eb,Ib */ + case 0x01: /* TEST Eb,Ib Undocumented*/ + { + if (rm >= 0xc0 ) {GetEArb;TESTB(*earb,Fetchb(),LoadRb,0)} + else {GetEAa;TESTB(eaa,Fetchb(),LoadMb,0);} + break; + } + case 0x02: /* NOT Eb */ + { + if (rm >= 0xc0 ) {GetEArb;*earb=~*earb;} + else {GetEAa;SaveMb(eaa,~LoadMb(eaa));} + break; + } + case 0x03: /* NEG Eb */ + { + lflags.type=t_NEGb; + if (rm >= 0xc0 ) { + GetEArb;lf_var1b=*earb;lf_resb=0-lf_var1b; + *earb=lf_resb; + } else { + GetEAa;lf_var1b=LoadMb(eaa);lf_resb=0-lf_var1b; + SaveMb(eaa,lf_resb); + } + break; + } + case 0x04: /* MUL AL,Eb */ + RMEb(MULB); + break; + case 0x05: /* IMUL AL,Eb */ + RMEb(IMULB); + break; + case 0x06: /* DIV Eb */ + RMEb(DIVB); + break; + case 0x07: /* IDIV Eb */ + RMEb(IDIVB); + break; + } + break; + } + CASE_W(0xf7) /* GRP3 Ew(,Iw) */ + { + GetRM;Bitu which=(rm>>3)&7; + switch (which) { + case 0x00: /* TEST Ew,Iw */ + case 0x01: /* TEST Ew,Iw Undocumented*/ + { + if (rm >= 0xc0 ) {GetEArw;TESTW(*earw,Fetchw(),LoadRw,SaveRw);} + else {GetEAa;TESTW(eaa,Fetchw(),LoadMw,SaveMw);} + break; + } + case 0x02: /* NOT Ew */ + { + if (rm >= 0xc0 ) {GetEArw;*earw=~*earw;} + else {GetEAa;SaveMw(eaa,~LoadMw(eaa));} + break; + } + case 0x03: /* NEG Ew */ + { + lflags.type=t_NEGw; + if (rm >= 0xc0 ) { + GetEArw;lf_var1w=*earw;lf_resw=0-lf_var1w; + *earw=lf_resw; + } else { + GetEAa;lf_var1w=LoadMw(eaa);lf_resw=0-lf_var1w; + SaveMw(eaa,lf_resw); + } + break; + } + case 0x04: /* MUL AX,Ew */ + RMEw(MULW); + break; + case 0x05: /* IMUL AX,Ew */ + RMEw(IMULW) + break; + case 0x06: /* DIV Ew */ + RMEw(DIVW) + break; + case 0x07: /* IDIV Ew */ + RMEw(IDIVW) + break; + } + break; + } + CASE_B(0xf8) /* CLC */ + FillFlags(); + SETFLAGBIT(CF,false); + break; + CASE_B(0xf9) /* STC */ + FillFlags(); + SETFLAGBIT(CF,true); + break; + CASE_B(0xfa) /* CLI */ + if (CPU_CLI()) RUNEXCEPTION(); + break; + CASE_B(0xfb) /* STI */ + if (CPU_STI()) RUNEXCEPTION(); +#if CPU_PIC_CHECK + if (GETFLAG(IF) && PIC_IRQCheck) goto decode_end; +#endif + break; + CASE_B(0xfc) /* CLD */ + SETFLAGBIT(DF,false); + cpu.direction=1; + break; + CASE_B(0xfd) /* STD */ + SETFLAGBIT(DF,true); + cpu.direction=-1; + break; + CASE_B(0xfe) /* GRP4 Eb */ + { + GetRM;Bitu which=(rm>>3)&7; + switch (which) { + case 0x00: /* INC Eb */ + RMEb(INCB); + break; + case 0x01: /* DEC Eb */ + RMEb(DECB); + break; + case 0x07: /* CallBack */ + { + Bitu cb=Fetchw(); + FillFlags();SAVEIP; + return cb; + } + default: + E_Exit("Illegal GRP4 Call %d",(rm>>3) & 7); + break; + } + break; + } + CASE_W(0xff) /* GRP5 Ew */ + { + GetRM;Bitu which=(rm>>3)&7; + switch (which) { + case 0x00: /* INC Ew */ + RMEw(INCW); + break; + case 0x01: /* DEC Ew */ + RMEw(DECW); + break; + case 0x02: /* CALL Ev */ + if (rm >= 0xc0 ) {GetEArw;reg_eip=*earw;} + else {GetEAa;reg_eip=LoadMw(eaa);} + Push_16(GETIP); + continue; + case 0x03: /* CALL Ep */ + { + if (rm >= 0xc0) goto illegal_opcode; + GetEAa; + Bit16u newip=LoadMw(eaa); + Bit16u newcs=LoadMw(eaa+2); + FillFlags(); + CPU_CALL(false,newcs,newip,GETIP); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + return CBRET_NONE; + } +#endif + continue; + } + break; + case 0x04: /* JMP Ev */ + if (rm >= 0xc0 ) {GetEArw;reg_eip=*earw;} + else {GetEAa;reg_eip=LoadMw(eaa);} + continue; + case 0x05: /* JMP Ep */ + { + if (rm >= 0xc0) goto illegal_opcode; + GetEAa; + Bit16u newip=LoadMw(eaa); + Bit16u newcs=LoadMw(eaa+2); + FillFlags(); + CPU_JMP(false,newcs,newip,GETIP); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + return CBRET_NONE; + } +#endif + continue; + } + break; + case 0x06: /* PUSH Ev */ + if (rm >= 0xc0 ) {GetEArw;Push_16(*earw);} + else {GetEAa;Push_16(LoadMw(eaa));} + break; + default: + LOG(LOG_CPU,LOG_ERROR)("CPU:GRP5:Illegal Call %2X",which); + goto illegal_opcode; + } + break; + } + + + + diff --git a/dosbox/core_normal/string.h b/dosbox/core_normal/string.h new file mode 100644 index 00000000..6fdfc7bd --- /dev/null +++ b/dosbox/core_normal/string.h @@ -0,0 +1,232 @@ +enum STRING_OP { + R_OUTSB,R_OUTSW,R_OUTSD, + R_INSB,R_INSW,R_INSD, + R_MOVSB,R_MOVSW,R_MOVSD, + R_LODSB,R_LODSW,R_LODSD, + R_STOSB,R_STOSW,R_STOSD, + R_SCASB,R_SCASW,R_SCASD, + R_CMPSB,R_CMPSW,R_CMPSD +}; + +#define LoadD(_BLAH) _BLAH + +static void DoString(STRING_OP type) { + PhysPt si_base,di_base; + Bitu si_index,di_index; + Bitu add_mask; + Bitu count,count_left; + Bits add_index; + + si_base=BaseDS; + di_base=SegBase(es); + add_mask=AddrMaskTable[core.prefixes & PREFIX_ADDR]; + si_index=reg_esi & add_mask; + di_index=reg_edi & add_mask; + count=reg_ecx & add_mask; + if (!TEST_PREFIX_REP) { + count=1; + } else { + CPU_Cycles++; + /* Calculate amount of ops to do before cycles run out */ + if ((count>(Bitu)CPU_Cycles) && (type0;count--) { + IO_WriteB(reg_dx,LoadMb(si_base+si_index)); + si_index=(si_index+add_index) & add_mask; + } + break; + case R_OUTSW: + add_index<<=1; + for (;count>0;count--) { + IO_WriteW(reg_dx,LoadMw(si_base+si_index)); + si_index=(si_index+add_index) & add_mask; + } + break; + case R_OUTSD: + add_index<<=2; + for (;count>0;count--) { + IO_WriteD(reg_dx,LoadMd(si_base+si_index)); + si_index=(si_index+add_index) & add_mask; + } + break; + case R_INSB: + for (;count>0;count--) { + SaveMb(di_base+di_index,IO_ReadB(reg_dx)); + di_index=(di_index+add_index) & add_mask; + } + break; + case R_INSW: + add_index<<=1; + for (;count>0;count--) { + SaveMw(di_base+di_index,IO_ReadW(reg_dx)); + di_index=(di_index+add_index) & add_mask; + } + break; + case R_STOSB: + for (;count>0;count--) { + SaveMb(di_base+di_index,reg_al); + di_index=(di_index+add_index) & add_mask; + } + break; + case R_STOSW: + add_index<<=1; + for (;count>0;count--) { + SaveMw(di_base+di_index,reg_ax); + di_index=(di_index+add_index) & add_mask; + } + break; + case R_STOSD: + add_index<<=2; + for (;count>0;count--) { + SaveMd(di_base+di_index,reg_eax); + di_index=(di_index+add_index) & add_mask; + } + break; + case R_MOVSB: + for (;count>0;count--) { + SaveMb(di_base+di_index,LoadMb(si_base+si_index)); + di_index=(di_index+add_index) & add_mask; + si_index=(si_index+add_index) & add_mask; + } + break; + case R_MOVSW: + add_index<<=1; + for (;count>0;count--) { + SaveMw(di_base+di_index,LoadMw(si_base+si_index)); + di_index=(di_index+add_index) & add_mask; + si_index=(si_index+add_index) & add_mask; + } + break; + case R_MOVSD: + add_index<<=2; + for (;count>0;count--) { + SaveMd(di_base+di_index,LoadMd(si_base+si_index)); + di_index=(di_index+add_index) & add_mask; + si_index=(si_index+add_index) & add_mask; + } + break; + case R_LODSB: + for (;count>0;count--) { + reg_al=LoadMb(si_base+si_index); + si_index=(si_index+add_index) & add_mask; + } + break; + case R_LODSW: + add_index<<=1; + for (;count>0;count--) { + reg_ax=LoadMw(si_base+si_index); + si_index=(si_index+add_index) & add_mask; + } + break; + case R_LODSD: + add_index<<=2; + for (;count>0;count--) { + reg_eax=LoadMd(si_base+si_index); + si_index=(si_index+add_index) & add_mask; + } + break; + case R_SCASB: + { + Bit8u val2; + for (;count>0;) { + count--;CPU_Cycles--; + val2=LoadMb(di_base+di_index); + di_index=(di_index+add_index) & add_mask; + if ((reg_al==val2)!=core.rep_zero) break; + } + CMPB(reg_al,val2,LoadD,0); + } + break; + case R_SCASW: + { + add_index<<=1;Bit16u val2; + for (;count>0;) { + count--;CPU_Cycles--; + val2=LoadMw(di_base+di_index); + di_index=(di_index+add_index) & add_mask; + if ((reg_ax==val2)!=core.rep_zero) break; + } + CMPW(reg_ax,val2,LoadD,0); + } + break; + case R_SCASD: + { + add_index<<=2;Bit32u val2; + for (;count>0;) { + count--;CPU_Cycles--; + val2=LoadMd(di_base+di_index); + di_index=(di_index+add_index) & add_mask; + if ((reg_eax==val2)!=core.rep_zero) break; + } + CMPD(reg_eax,val2,LoadD,0); + } + break; + case R_CMPSB: + { + Bit8u val1,val2; + for (;count>0;) { + count--;CPU_Cycles--; + val1=LoadMb(si_base+si_index); + val2=LoadMb(di_base+di_index); + si_index=(si_index+add_index) & add_mask; + di_index=(di_index+add_index) & add_mask; + if ((val1==val2)!=core.rep_zero) break; + } + CMPB(val1,val2,LoadD,0); + } + break; + case R_CMPSW: + { + add_index<<=1;Bit16u val1,val2; + for (;count>0;) { + count--;CPU_Cycles--; + val1=LoadMw(si_base+si_index); + val2=LoadMw(di_base+di_index); + si_index=(si_index+add_index) & add_mask; + di_index=(di_index+add_index) & add_mask; + if ((val1==val2)!=core.rep_zero) break; + } + CMPW(val1,val2,LoadD,0); + } + break; + case R_CMPSD: + { + add_index<<=2;Bit32u val1,val2; + for (;count>0;) { + count--;CPU_Cycles--; + val1=LoadMd(si_base+si_index); + val2=LoadMd(di_base+di_index); + si_index=(si_index+add_index) & add_mask; + di_index=(di_index+add_index) & add_mask; + if ((val1==val2)!=core.rep_zero) break; + } + CMPD(val1,val2,LoadD,0); + } + break; + default: + LOG(LOG_CPU,LOG_ERROR)("Unhandled string op %d",type); + } + /* Clean up after certain amount of instructions */ + reg_esi&=(~add_mask); + reg_esi|=(si_index & add_mask); + reg_edi&=(~add_mask); + reg_edi|=(di_index & add_mask); + if (TEST_PREFIX_REP) { + count+=count_left; + reg_ecx&=(~add_mask); + reg_ecx|=(count & add_mask); + } +} diff --git a/dosbox/core_normal/support.h b/dosbox/core_normal/support.h new file mode 100644 index 00000000..9b230816 --- /dev/null +++ b/dosbox/core_normal/support.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#define LoadMbs(off) (Bit8s)(LoadMb(off)) +#define LoadMws(off) (Bit16s)(LoadMw(off)) +#define LoadMds(off) (Bit32s)(LoadMd(off)) + +#define LoadRb(reg) reg +#define LoadRw(reg) reg +#define LoadRd(reg) reg + +#define SaveRb(reg,val) reg=val +#define SaveRw(reg,val) reg=val +#define SaveRd(reg,val) reg=val + +static INLINE Bit8s Fetchbs() { + return Fetchb(); +} +static INLINE Bit16s Fetchws() { + return Fetchw(); +} + +static INLINE Bit32s Fetchds() { + return Fetchd(); +} + + +#define RUNEXCEPTION() { \ + CPU_Exception(cpu.exception.which,cpu.exception.error); \ + continue; \ +} + +#define EXCEPTION(blah) \ + { \ + CPU_Exception(blah); \ + continue; \ + } + +//TODO Could probably make all byte operands fast? +#define JumpCond16_b(COND) { \ + SAVEIP; \ + if (COND) reg_ip+=Fetchbs(); \ + reg_ip+=1; \ + continue; \ +} + +#define JumpCond16_w(COND) { \ + SAVEIP; \ + if (COND) reg_ip+=Fetchws(); \ + reg_ip+=2; \ + continue; \ +} + +#define JumpCond32_b(COND) { \ + SAVEIP; \ + if (COND) reg_eip+=Fetchbs(); \ + reg_eip+=1; \ + continue; \ +} + +#define JumpCond32_d(COND) { \ + SAVEIP; \ + if (COND) reg_eip+=Fetchds(); \ + reg_eip+=4; \ + continue; \ +} + + +#define SETcc(cc) \ + { \ + GetRM; \ + if (rm >= 0xc0 ) {GetEArb;*earb=(cc) ? 1 : 0;} \ + else {GetEAa;SaveMb(eaa,(cc) ? 1 : 0);} \ + } + +#include "helpers.h" +#include "table_ea.h" +#include "../modrm.h" + + diff --git a/dosbox/core_normal/table_ea.h b/dosbox/core_normal/table_ea.h new file mode 100644 index 00000000..08d46132 --- /dev/null +++ b/dosbox/core_normal/table_ea.h @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +typedef PhysPt (*EA_LookupHandler)(void); + +/* The MOD/RM Decoder for EA for this decoder's addressing modes */ +static PhysPt EA_16_00_n(void) { return BaseDS+(Bit16u)(reg_bx+(Bit16s)reg_si); } +static PhysPt EA_16_01_n(void) { return BaseDS+(Bit16u)(reg_bx+(Bit16s)reg_di); } +static PhysPt EA_16_02_n(void) { return BaseSS+(Bit16u)(reg_bp+(Bit16s)reg_si); } +static PhysPt EA_16_03_n(void) { return BaseSS+(Bit16u)(reg_bp+(Bit16s)reg_di); } +static PhysPt EA_16_04_n(void) { return BaseDS+(Bit16u)(reg_si); } +static PhysPt EA_16_05_n(void) { return BaseDS+(Bit16u)(reg_di); } +static PhysPt EA_16_06_n(void) { return BaseDS+(Bit16u)(Fetchw());} +static PhysPt EA_16_07_n(void) { return BaseDS+(Bit16u)(reg_bx); } + +static PhysPt EA_16_40_n(void) { return BaseDS+(Bit16u)(reg_bx+(Bit16s)reg_si+Fetchbs()); } +static PhysPt EA_16_41_n(void) { return BaseDS+(Bit16u)(reg_bx+(Bit16s)reg_di+Fetchbs()); } +static PhysPt EA_16_42_n(void) { return BaseSS+(Bit16u)(reg_bp+(Bit16s)reg_si+Fetchbs()); } +static PhysPt EA_16_43_n(void) { return BaseSS+(Bit16u)(reg_bp+(Bit16s)reg_di+Fetchbs()); } +static PhysPt EA_16_44_n(void) { return BaseDS+(Bit16u)(reg_si+Fetchbs()); } +static PhysPt EA_16_45_n(void) { return BaseDS+(Bit16u)(reg_di+Fetchbs()); } +static PhysPt EA_16_46_n(void) { return BaseSS+(Bit16u)(reg_bp+Fetchbs()); } +static PhysPt EA_16_47_n(void) { return BaseDS+(Bit16u)(reg_bx+Fetchbs()); } + +static PhysPt EA_16_80_n(void) { return BaseDS+(Bit16u)(reg_bx+(Bit16s)reg_si+Fetchws()); } +static PhysPt EA_16_81_n(void) { return BaseDS+(Bit16u)(reg_bx+(Bit16s)reg_di+Fetchws()); } +static PhysPt EA_16_82_n(void) { return BaseSS+(Bit16u)(reg_bp+(Bit16s)reg_si+Fetchws()); } +static PhysPt EA_16_83_n(void) { return BaseSS+(Bit16u)(reg_bp+(Bit16s)reg_di+Fetchws()); } +static PhysPt EA_16_84_n(void) { return BaseDS+(Bit16u)(reg_si+Fetchws()); } +static PhysPt EA_16_85_n(void) { return BaseDS+(Bit16u)(reg_di+Fetchws()); } +static PhysPt EA_16_86_n(void) { return BaseSS+(Bit16u)(reg_bp+Fetchws()); } +static PhysPt EA_16_87_n(void) { return BaseDS+(Bit16u)(reg_bx+Fetchws()); } + +static Bit32u SIBZero=0; +static Bit32u * SIBIndex[8]= { ®_eax,®_ecx,®_edx,®_ebx,&SIBZero,®_ebp,®_esi,®_edi }; + +static INLINE PhysPt Sib(Bitu mode) { + Bit8u sib=Fetchb(); + PhysPt base; + switch (sib&7) { + case 0: /* EAX Base */ + base=BaseDS+reg_eax;break; + case 1: /* ECX Base */ + base=BaseDS+reg_ecx;break; + case 2: /* EDX Base */ + base=BaseDS+reg_edx;break; + case 3: /* EBX Base */ + base=BaseDS+reg_ebx;break; + case 4: /* ESP Base */ + base=BaseSS+reg_esp;break; + case 5: /* #1 Base */ + if (!mode) { + base=BaseDS+Fetchd();break; + } else { + base=BaseSS+reg_ebp;break; + } + case 6: /* ESI Base */ + base=BaseDS+reg_esi;break; + case 7: /* EDI Base */ + base=BaseDS+reg_edi;break; + } + base+=*SIBIndex[(sib >> 3) &7] << (sib >> 6); + return base; +} + +static PhysPt EA_32_00_n(void) { return BaseDS+reg_eax; } +static PhysPt EA_32_01_n(void) { return BaseDS+reg_ecx; } +static PhysPt EA_32_02_n(void) { return BaseDS+reg_edx; } +static PhysPt EA_32_03_n(void) { return BaseDS+reg_ebx; } +static PhysPt EA_32_04_n(void) { return Sib(0);} +static PhysPt EA_32_05_n(void) { return BaseDS+Fetchd(); } +static PhysPt EA_32_06_n(void) { return BaseDS+reg_esi; } +static PhysPt EA_32_07_n(void) { return BaseDS+reg_edi; } + +static PhysPt EA_32_40_n(void) { return BaseDS+reg_eax+Fetchbs(); } +static PhysPt EA_32_41_n(void) { return BaseDS+reg_ecx+Fetchbs(); } +static PhysPt EA_32_42_n(void) { return BaseDS+reg_edx+Fetchbs(); } +static PhysPt EA_32_43_n(void) { return BaseDS+reg_ebx+Fetchbs(); } +static PhysPt EA_32_44_n(void) { PhysPt temp=Sib(1);return temp+Fetchbs();} +//static PhysPt EA_32_44_n(void) { return Sib(1)+Fetchbs();} +static PhysPt EA_32_45_n(void) { return BaseSS+reg_ebp+Fetchbs(); } +static PhysPt EA_32_46_n(void) { return BaseDS+reg_esi+Fetchbs(); } +static PhysPt EA_32_47_n(void) { return BaseDS+reg_edi+Fetchbs(); } + +static PhysPt EA_32_80_n(void) { return BaseDS+reg_eax+Fetchds(); } +static PhysPt EA_32_81_n(void) { return BaseDS+reg_ecx+Fetchds(); } +static PhysPt EA_32_82_n(void) { return BaseDS+reg_edx+Fetchds(); } +static PhysPt EA_32_83_n(void) { return BaseDS+reg_ebx+Fetchds(); } +static PhysPt EA_32_84_n(void) { PhysPt temp=Sib(2);return temp+Fetchds();} +//static PhysPt EA_32_84_n(void) { return Sib(2)+Fetchds();} +static PhysPt EA_32_85_n(void) { return BaseSS+reg_ebp+Fetchds(); } +static PhysPt EA_32_86_n(void) { return BaseDS+reg_esi+Fetchds(); } +static PhysPt EA_32_87_n(void) { return BaseDS+reg_edi+Fetchds(); } + +static GetEAHandler EATable[512]={ +/* 00 */ + EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n, + EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n, + EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n, + EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n, + EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n, + EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n, + EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n, + EA_16_00_n,EA_16_01_n,EA_16_02_n,EA_16_03_n,EA_16_04_n,EA_16_05_n,EA_16_06_n,EA_16_07_n, +/* 01 */ + EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n, + EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n, + EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n, + EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n, + EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n, + EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n, + EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n, + EA_16_40_n,EA_16_41_n,EA_16_42_n,EA_16_43_n,EA_16_44_n,EA_16_45_n,EA_16_46_n,EA_16_47_n, +/* 10 */ + EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n, + EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n, + EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n, + EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n, + EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n, + EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n, + EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n, + EA_16_80_n,EA_16_81_n,EA_16_82_n,EA_16_83_n,EA_16_84_n,EA_16_85_n,EA_16_86_n,EA_16_87_n, +/* 11 These are illegal so make em 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 00 */ + EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n, + EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n, + EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n, + EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n, + EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n, + EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n, + EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n, + EA_32_00_n,EA_32_01_n,EA_32_02_n,EA_32_03_n,EA_32_04_n,EA_32_05_n,EA_32_06_n,EA_32_07_n, +/* 01 */ + EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n, + EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n, + EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n, + EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n, + EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n, + EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n, + EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n, + EA_32_40_n,EA_32_41_n,EA_32_42_n,EA_32_43_n,EA_32_44_n,EA_32_45_n,EA_32_46_n,EA_32_47_n, +/* 10 */ + EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n, + EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n, + EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n, + EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n, + EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n, + EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n, + EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n, + EA_32_80_n,EA_32_81_n,EA_32_82_n,EA_32_83_n,EA_32_84_n,EA_32_85_n,EA_32_86_n,EA_32_87_n, +/* 11 These are illegal so make em 0 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +#define GetEADirect \ + PhysPt eaa; \ + if (TEST_PREFIX_ADDR) { \ + eaa=BaseDS+Fetchd(); \ + } else { \ + eaa=BaseDS+Fetchw(); \ + } \ + + diff --git a/dosbox/core_simple.cpp b/dosbox/core_simple.cpp new file mode 100644 index 00000000..2d026b94 --- /dev/null +++ b/dosbox/core_simple.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include + +#include "dosbox.h" +#include "mem.h" +#include "cpu.h" +#include "lazyflags.h" +#include "inout.h" +#include "callback.h" +#include "pic.h" +#include "fpu.h" + +#if C_DEBUG +#include "debug.h" +#endif + +#include "paging.h" +#define SegBase(c) SegPhys(c) +#define LoadMb(off) mem_readb(off) +#define LoadMw(off) mem_readw(off) +#define LoadMd(off) mem_readd(off) + +#define SaveMb(off,val) mem_writeb(off,val) +#define SaveMw(off,val) mem_writew(off,val) +#define SaveMd(off,val) mem_writed(off,val) + +extern Bitu cycle_count; + +#if C_FPU +#define CPU_FPU 1 //Enable FPU escape instructions +#endif + +#define CPU_PIC_CHECK 1 +#define CPU_TRAP_CHECK 1 + +#define OPCODE_NONE 0x000 +#define OPCODE_0F 0x100 +#define OPCODE_SIZE 0x200 + +#define PREFIX_ADDR 0x1 +#define PREFIX_REP 0x2 + +#define TEST_PREFIX_ADDR (core.prefixes & PREFIX_ADDR) +#define TEST_PREFIX_REP (core.prefixes & PREFIX_REP) + +#define DO_PREFIX_SEG(_SEG) \ + BaseDS=SegBase(_SEG); \ + BaseSS=SegBase(_SEG); \ + core.base_val_ds=_SEG; \ + goto restart_opcode; + +#define DO_PREFIX_ADDR() \ + core.prefixes=(core.prefixes & ~PREFIX_ADDR) | \ + (cpu.code.big ^ PREFIX_ADDR); \ + core.ea_table=&EATable[(core.prefixes&1) * 256]; \ + goto restart_opcode; + +#define DO_PREFIX_REP(_ZERO) \ + core.prefixes|=PREFIX_REP; \ + core.rep_zero=_ZERO; \ + goto restart_opcode; + +typedef PhysPt (*GetEAHandler)(void); + +static const Bit32u AddrMaskTable[2]={0x0000ffff,0xffffffff}; + +static struct { + Bitu opcode_index; +#if defined (_MSC_VER) + volatile HostPt cseip; +#else + HostPt cseip; +#endif + PhysPt base_ds,base_ss; + SegNames base_val_ds; + bool rep_zero; + Bitu prefixes; + GetEAHandler * ea_table; +} core; + +#define GETIP (core.cseip-SegBase(cs)-MemBase) +#define SAVEIP reg_eip=GETIP; +#define LOADIP core.cseip=(MemBase+SegBase(cs)+reg_eip); + +#define SegBase(c) SegPhys(c) +#define BaseDS core.base_ds +#define BaseSS core.base_ss + +static INLINE Bit8u Fetchb() { + Bit8u temp=host_readb(core.cseip); + core.cseip+=1; + return temp; +} + +static INLINE Bit16u Fetchw() { + Bit16u temp=host_readw(core.cseip); + core.cseip+=2; + return temp; +} +static INLINE Bit32u Fetchd() { + Bit32u temp=host_readd(core.cseip); + core.cseip+=4; + return temp; +} + +#define Push_16 CPU_Push16 +#define Push_32 CPU_Push32 +#define Pop_16 CPU_Pop16 +#define Pop_32 CPU_Pop32 + +#include "instructions.h" +#include "core_normal/support.h" +#include "core_normal/string.h" + + +#define EALookupTable (core.ea_table) + +Bits CPU_Core_Simple_Run(void) { + while (CPU_Cycles-->0) { + LOADIP; + core.opcode_index=cpu.code.big*0x200; + core.prefixes=cpu.code.big; + core.ea_table=&EATable[cpu.code.big*256]; + BaseDS=SegBase(ds); + BaseSS=SegBase(ss); + core.base_val_ds=ds; +#if C_DEBUG +#if C_HEAVY_DEBUG + if (DEBUG_HeavyIsBreakpoint()) { + FillFlags(); + return debugCallback; + }; +#endif + cycle_count++; +#endif +restart_opcode: + switch (core.opcode_index+Fetchb()) { + + #include "core_normal/prefix_none.h" + #include "core_normal/prefix_0f.h" + #include "core_normal/prefix_66.h" + #include "core_normal/prefix_66_0f.h" + default: + illegal_opcode: +#if C_DEBUG + { + Bitu len=(GETIP-reg_eip); + LOADIP; + if (len>16) len=16; + char tempcode[16*2+1];char * writecode=tempcode; + for (;len>0;len--) { +// sprintf(writecode,"%X",mem_readb(core.cseip++)); + writecode+=2; + } + LOG(LOG_CPU,LOG_NORMAL)("Illegal/Unhandled opcode %s",tempcode); + } +#endif + CPU_Exception(6,0); + continue; + } + SAVEIP; + } + FillFlags(); + return CBRET_NONE; +decode_end: + SAVEIP; + FillFlags(); + return CBRET_NONE; +} + +// not really used +Bits CPU_Core_Simple_Trap_Run(void) { + Bits oldCycles = CPU_Cycles; + CPU_Cycles = 1; + cpu.trap_skip = false; + + Bits ret=CPU_Core_Normal_Run(); + if (!cpu.trap_skip) CPU_HW_Interrupt(1); + CPU_Cycles = oldCycles-1; + cpudecoder = &CPU_Core_Simple_Run; + + return ret; +} + + + +void CPU_Core_Simple_Init(void) { + +} diff --git a/dosbox/cpu.cpp b/dosbox/cpu.cpp new file mode 100644 index 00000000..ea037e3f --- /dev/null +++ b/dosbox/cpu.cpp @@ -0,0 +1,2428 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id: cpu.cpp,v 1.116 2009-03-16 18:10:08 c2woody Exp $ */ + +#include +#include +#include "dosbox.h" +#include "cpu.h" +//#include "memory.h" +//#include "debug.h" +//#include "mapper.h" +#include "setup.h" +//#include "programs.h" +#include "paging.h" +#include "lazyflags.h" +#include "support.h" + +Bitu DEBUG_EnableDebugger(void); +extern void GFX_SetTitle(Bit32s cycles ,Bits frameskip,bool paused); + +#if 1 +#undef LOG +#if defined (_MSC_VER) +#define LOG(X,Y) +#else +#define LOG(X,Y) CPU_LOG +#define CPU_LOG(...) +#endif +#endif + +CPU_Regs cpu_regs; +CPUBlock cpu; +Segments Segs; + +Bit32s CPU_Cycles = 0; +Bit32s CPU_CycleLeft = 3000; +Bit32s CPU_CycleMax = 3000; +Bit32s CPU_OldCycleMax = 3000; +Bit32s CPU_CyclePercUsed = 100; +Bit32s CPU_CycleLimit = -1; +Bit32s CPU_CycleUp = 0; +Bit32s CPU_CycleDown = 0; +Bit64s CPU_IODelayRemoved = 0; +CPU_Decoder * cpudecoder; +bool CPU_CycleAutoAdjust = false; +bool CPU_SkipCycleAutoAdjust = false; +Bitu CPU_AutoDetermineMode = 0; + +Bitu CPU_ArchitectureType = CPU_ARCHTYPE_MIXED; + +Bitu CPU_flag_id_toggle=0; + +Bitu CPU_PrefetchQueueSize=0; + +void CPU_Core_Full_Init(void); +void CPU_Core_Normal_Init(void); +void CPU_Core_Simple_Init(void); +#if (C_DYNAMIC_X86) +void CPU_Core_Dyn_X86_Init(void); +void CPU_Core_Dyn_X86_Cache_Init(bool enable_cache); +void CPU_Core_Dyn_X86_Cache_Close(void); +void CPU_Core_Dyn_X86_SetFPUMode(bool dh_fpu); +#elif (C_DYNREC) +void CPU_Core_Dynrec_Init(void); +void CPU_Core_Dynrec_Cache_Init(bool enable_cache); +void CPU_Core_Dynrec_Cache_Close(void); +#endif + +/* In debug mode exceptions are tested and dosbox exits when + * a unhandled exception state is detected. + * USE CHECK_EXCEPT to raise an exception in that case to see if that exception + * solves the problem. + * + * In non-debug mode dosbox doesn't do detection (and hence doesn't crash at + * that point). (game might crash later due to the unhandled exception) */ + +#if C_DEBUG +// #define CPU_CHECK_EXCEPT 1 +// #define CPU_CHECK_IGNORE 1 + /* Use CHECK_EXCEPT when something doesn't work to see if a exception is + * needed that isn't enabled by default.*/ +#else +/* NORMAL NO CHECKING => More Speed */ +#define CPU_CHECK_IGNORE 1 +#endif /* C_DEBUG */ + +#if defined(CPU_CHECK_IGNORE) +#define CPU_CHECK_COND(cond,msg,exc,sel) { \ + if (cond) do {} while (0); \ +} +#elif defined(CPU_CHECK_EXCEPT) +#define CPU_CHECK_COND(cond,msg,exc,sel) { \ + if (cond) { \ + CPU_Exception(exc,sel); \ + return; \ + } \ +} +#else +#define CPU_CHECK_COND(cond,msg,exc,sel) { \ + if (cond) E_Exit(msg); \ +} +#endif + + +void Descriptor::Load(PhysPt address) { + cpu.mpl=0; + Bit32u* data = (Bit32u*)&saved; + *data = mem_readd(address); + *(data+1) = mem_readd(address+4); + cpu.mpl=3; +} +void Descriptor:: Save(PhysPt address) { + cpu.mpl=0; + Bit32u* data = (Bit32u*)&saved; + mem_writed(address,*data); + mem_writed(address+4,*(data+1)); + cpu.mpl=03; +} + + +void CPU_Push16(Bitu value) { + Bit32u new_esp=(reg_esp&cpu.stack.notmask)|((reg_esp-2)&cpu.stack.mask); + mem_writew(SegPhys(ss) + (new_esp & cpu.stack.mask) ,value); + reg_esp=new_esp; +} + +void CPU_Push32(Bitu value) { + Bit32u new_esp=(reg_esp&cpu.stack.notmask)|((reg_esp-4)&cpu.stack.mask); + mem_writed(SegPhys(ss) + (new_esp & cpu.stack.mask) ,value); + reg_esp=new_esp; +} + +Bitu CPU_Pop16(void) { + Bitu val=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask)); + reg_esp=(reg_esp&cpu.stack.notmask)|((reg_esp+2)&cpu.stack.mask); + return val; +} + +Bitu CPU_Pop32(void) { + Bitu val=mem_readd(SegPhys(ss) + (reg_esp & cpu.stack.mask)); + reg_esp=(reg_esp&cpu.stack.notmask)|((reg_esp+4)&cpu.stack.mask); + return val; +} + +PhysPt SelBase(Bitu sel) { + if (cpu.cr0 & CR0_PROTECTION) { + Descriptor desc; + cpu.gdt.GetDescriptor(sel,desc); + return desc.GetBase(); + } else { + return sel<<4; + } +} + + +void CPU_SetFlags(Bitu word,Bitu mask) { + mask|=CPU_flag_id_toggle; // ID-flag can be toggled on cpuid-supporting CPUs + reg_flags=(reg_flags & ~mask)|(word & mask)|2; + cpu.direction=1-((reg_flags & FLAG_DF) >> 9); +} + +bool CPU_PrepareException(Bitu which,Bitu error) { + cpu.exception.which=which; + cpu.exception.error=error; + return true; +} + +bool CPU_CLI(void) { + if (cpu.pmode && ((!GETFLAG(VM) && (GETFLAG_IOPL0)) mask &= (~FLAG_IOPL); + if (cpu.pmode && !GETFLAG(VM) && (GETFLAG_IOPLdesc.DPL()) needs_invalidation=true; break; + default: break; } + if (needs_invalidation) CPU_SetSegGeneral(es,0); + + needs_invalidation=false; + if (!cpu.gdt.GetDescriptor(SegValue(ds),desc)) needs_invalidation=true; + else switch (desc.Type()) { + case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A: case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A: case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: + if (cpu.cpl>desc.DPL()) needs_invalidation=true; break; + default: break; } + if (needs_invalidation) CPU_SetSegGeneral(ds,0); + + needs_invalidation=false; + if (!cpu.gdt.GetDescriptor(SegValue(fs),desc)) needs_invalidation=true; + else switch (desc.Type()) { + case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A: case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A: case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: + if (cpu.cpl>desc.DPL()) needs_invalidation=true; break; + default: break; } + if (needs_invalidation) CPU_SetSegGeneral(fs,0); + + needs_invalidation=false; + if (!cpu.gdt.GetDescriptor(SegValue(gs),desc)) needs_invalidation=true; + else switch (desc.Type()) { + case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A: case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A: case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: + if (cpu.cpl>desc.DPL()) needs_invalidation=true; break; + default: break; } + if (needs_invalidation) CPU_SetSegGeneral(gs,0); +} + + +class TaskStateSegment { +public: + TaskStateSegment() { + valid=false; + } + bool IsValid(void) { + return valid; + } + Bitu Get_back(void) { + cpu.mpl=0; + Bit16u backlink=mem_readw(base); + cpu.mpl=3; + return backlink; + } + void SaveSelector(void) { + cpu.gdt.SetDescriptor(selector,desc); + } + void Get_SSx_ESPx(Bitu level,Bitu & _ss,Bitu & _esp) { + cpu.mpl=0; + if (is386) { + PhysPt where=base+offsetof(TSS_32,esp0)+level*8; + _esp=mem_readd(where); + _ss=mem_readw(where+4); + } else { + PhysPt where=base+offsetof(TSS_16,sp0)+level*4; + _esp=mem_readw(where); + _ss=mem_readw(where+2); + } + cpu.mpl=3; + } + bool SetSelector(Bitu new_sel) { + valid=false; + if ((new_sel & 0xfffc)==0) { + selector=0; + base=0; + limit=0; + is386=1; + return true; + } + if (new_sel&4) return false; + if (!cpu.gdt.GetDescriptor(new_sel,desc)) return false; + switch (desc.Type()) { + case DESC_286_TSS_A: case DESC_286_TSS_B: + case DESC_386_TSS_A: case DESC_386_TSS_B: + break; + default: + return false; + } + if (!desc.saved.seg.p) return false; + selector=new_sel; + valid=true; + base=desc.GetBase(); + limit=desc.GetLimit(); + is386=desc.Is386(); + return true; + } + TSS_Descriptor desc; + Bitu selector; + PhysPt base; + Bitu limit; + Bitu is386; + bool valid; +}; + +TaskStateSegment cpu_tss; + +enum TSwitchType { + TSwitch_JMP,TSwitch_CALL_INT,TSwitch_IRET +}; + +bool CPU_SwitchTask(Bitu new_tss_selector,TSwitchType tstype,Bitu old_eip) { + FillFlags(); + TaskStateSegment new_tss; + if (!new_tss.SetSelector(new_tss_selector)) + E_Exit("Illegal TSS for switch, selector=%x, switchtype=%x",new_tss_selector,tstype); + if (tstype==TSwitch_IRET) { + if (!new_tss.desc.IsBusy()) + E_Exit("TSS not busy for IRET"); + } else { + if (new_tss.desc.IsBusy()) + E_Exit("TSS busy for JMP/CALL/INT"); + } + Bitu new_cr3=0; + Bitu new_eax,new_ebx,new_ecx,new_edx,new_esp,new_ebp,new_esi,new_edi; + Bitu new_es,new_cs,new_ss,new_ds,new_fs,new_gs; + Bitu new_ldt,new_eip,new_eflags; + /* Read new context from new TSS */ + if (new_tss.is386) { + new_cr3=mem_readd(new_tss.base+offsetof(TSS_32,cr3)); + new_eip=mem_readd(new_tss.base+offsetof(TSS_32,eip)); + new_eflags=mem_readd(new_tss.base+offsetof(TSS_32,eflags)); + new_eax=mem_readd(new_tss.base+offsetof(TSS_32,eax)); + new_ecx=mem_readd(new_tss.base+offsetof(TSS_32,ecx)); + new_edx=mem_readd(new_tss.base+offsetof(TSS_32,edx)); + new_ebx=mem_readd(new_tss.base+offsetof(TSS_32,ebx)); + new_esp=mem_readd(new_tss.base+offsetof(TSS_32,esp)); + new_ebp=mem_readd(new_tss.base+offsetof(TSS_32,ebp)); + new_edi=mem_readd(new_tss.base+offsetof(TSS_32,edi)); + new_esi=mem_readd(new_tss.base+offsetof(TSS_32,esi)); + + new_es=mem_readw(new_tss.base+offsetof(TSS_32,es)); + new_cs=mem_readw(new_tss.base+offsetof(TSS_32,cs)); + new_ss=mem_readw(new_tss.base+offsetof(TSS_32,ss)); + new_ds=mem_readw(new_tss.base+offsetof(TSS_32,ds)); + new_fs=mem_readw(new_tss.base+offsetof(TSS_32,fs)); + new_gs=mem_readw(new_tss.base+offsetof(TSS_32,gs)); + new_ldt=mem_readw(new_tss.base+offsetof(TSS_32,ldt)); + } else { + E_Exit("286 task switch"); + new_cr3=0; + new_eip=0; + new_eflags=0; + new_eax=0; new_ecx=0; new_edx=0; new_ebx=0; + new_esp=0; new_ebp=0; new_edi=0; new_esi=0; + + new_es=0; new_cs=0; new_ss=0; new_ds=0; new_fs=0; new_gs=0; + new_ldt=0; + } + + /* Check if we need to clear busy bit of old TASK */ + if (tstype==TSwitch_JMP || tstype==TSwitch_IRET) { + cpu_tss.desc.SetBusy(false); + cpu_tss.SaveSelector(); + } + Bit32u old_flags = reg_flags; + if (tstype==TSwitch_IRET) old_flags &= (~FLAG_NT); + + /* Save current context in current TSS */ + if (cpu_tss.is386) { + mem_writed(cpu_tss.base+offsetof(TSS_32,eflags),old_flags); + mem_writed(cpu_tss.base+offsetof(TSS_32,eip),old_eip); + + mem_writed(cpu_tss.base+offsetof(TSS_32,eax),reg_eax); + mem_writed(cpu_tss.base+offsetof(TSS_32,ecx),reg_ecx); + mem_writed(cpu_tss.base+offsetof(TSS_32,edx),reg_edx); + mem_writed(cpu_tss.base+offsetof(TSS_32,ebx),reg_ebx); + mem_writed(cpu_tss.base+offsetof(TSS_32,esp),reg_esp); + mem_writed(cpu_tss.base+offsetof(TSS_32,ebp),reg_ebp); + mem_writed(cpu_tss.base+offsetof(TSS_32,esi),reg_esi); + mem_writed(cpu_tss.base+offsetof(TSS_32,edi),reg_edi); + + mem_writed(cpu_tss.base+offsetof(TSS_32,es),SegValue(es)); + mem_writed(cpu_tss.base+offsetof(TSS_32,cs),SegValue(cs)); + mem_writed(cpu_tss.base+offsetof(TSS_32,ss),SegValue(ss)); + mem_writed(cpu_tss.base+offsetof(TSS_32,ds),SegValue(ds)); + mem_writed(cpu_tss.base+offsetof(TSS_32,fs),SegValue(fs)); + mem_writed(cpu_tss.base+offsetof(TSS_32,gs),SegValue(gs)); + } else { + E_Exit("286 task switch"); + } + + /* Setup a back link to the old TSS in new TSS */ + if (tstype==TSwitch_CALL_INT) { + if (new_tss.is386) { + mem_writed(new_tss.base+offsetof(TSS_32,back),cpu_tss.selector); + } else { + mem_writew(new_tss.base+offsetof(TSS_16,back),cpu_tss.selector); + } + /* And make the new task's eflag have the nested task bit */ + new_eflags|=FLAG_NT; + } + /* Set the busy bit in the new task */ + if (tstype==TSwitch_JMP || tstype==TSwitch_CALL_INT) { + new_tss.desc.SetBusy(true); + new_tss.SaveSelector(); + } + +// cpu.cr0|=CR0_TASKSWITCHED; + if (new_tss_selector == cpu_tss.selector) { + reg_eip = old_eip; + new_cs = SegValue(cs); + new_ss = SegValue(ss); + new_ds = SegValue(ds); + new_es = SegValue(es); + new_fs = SegValue(fs); + new_gs = SegValue(gs); + } else { + + /* Setup the new cr3 */ + PAGING_SetDirBase(new_cr3); + + /* Load new context */ + if (new_tss.is386) { + reg_eip=new_eip; + CPU_SetFlags(new_eflags,FMASK_ALL | FLAG_VM); + reg_eax=new_eax; + reg_ecx=new_ecx; + reg_edx=new_edx; + reg_ebx=new_ebx; + reg_esp=new_esp; + reg_ebp=new_ebp; + reg_edi=new_edi; + reg_esi=new_esi; + +// new_cs=mem_readw(new_tss.base+offsetof(TSS_32,cs)); + } else { + E_Exit("286 task switch"); + } + } + /* Load the new selectors */ + if (reg_flags & FLAG_VM) { + SegSet16(cs,new_cs); + cpu.code.big=false; + cpu.cpl=3; //We don't have segment caches so this will do + } else { + /* Protected mode task */ + if (new_ldt!=0) CPU_LLDT(new_ldt); + /* Load the new CS*/ + Descriptor cs_desc; + cpu.cpl=new_cs & 3; + if (!cpu.gdt.GetDescriptor(new_cs,cs_desc)) + E_Exit("Task switch with CS beyond limits"); + if (!cs_desc.saved.seg.p) + E_Exit("Task switch with non present code-segment"); + switch (cs_desc.Type()) { + case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: + case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: + if (cpu.cpl != cs_desc.DPL()) E_Exit("Task CS RPL != DPL"); + goto doconforming; + case DESC_CODE_N_C_A: case DESC_CODE_N_C_NA: + case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA: + if (cpu.cpl < cs_desc.DPL()) E_Exit("Task CS RPL < DPL"); +doconforming: + Segs.phys[cs]=cs_desc.GetBase(); + cpu.code.big=cs_desc.Big()>0; + Segs.val[cs]=new_cs; + break; + default: + E_Exit("Task switch CS Type %d",cs_desc.Type()); + } + } + CPU_SetSegGeneral(es,new_es); + CPU_SetSegGeneral(ss,new_ss); + CPU_SetSegGeneral(ds,new_ds); + CPU_SetSegGeneral(fs,new_fs); + CPU_SetSegGeneral(gs,new_gs); + if (!cpu_tss.SetSelector(new_tss_selector)) { + LOG(LOG_CPU,LOG_NORMAL)("TaskSwitch: set tss selector %X failed",new_tss_selector); + } +// cpu_tss.desc.SetBusy(true); +// cpu_tss.SaveSelector(); +// LOG_MSG("Task CPL %X CS:%X IP:%X SS:%X SP:%X eflags %x",cpu.cpl,SegValue(cs),reg_eip,SegValue(ss),reg_esp,reg_flags); + return true; +} + +bool CPU_IO_Exception(Bitu port,Bitu size) { + if (cpu.pmode && ((GETFLAG_IOPLcpu_tss.limit) goto doexception; + bwhere=cpu_tss.base+ofs+(port/8); + Bitu map=mem_readw(bwhere); + Bitu mask=(0xffff>>(16-size)) << (port&7); + if (map & mask) goto doexception; + cpu.mpl=3; + } + return false; +doexception: + cpu.mpl=3; + LOG(LOG_CPU,LOG_NORMAL)("IO Exception port %X",port); + return CPU_PrepareException(EXCEPTION_GP,0); +} + +void CPU_Exception(Bitu which,Bitu error ) { +// LOG_MSG("Exception %d error %x",which,error); + cpu.exception.error=error; + CPU_Interrupt(which,CPU_INT_EXCEPTION | ((which>=8) ? CPU_INT_HAS_ERROR : 0),reg_eip); +} + +Bit8u lastint; +void CPU_Interrupt(Bitu num,Bitu type,Bitu oldeip) { + lastint=num; + FillFlags(); +#if C_DEBUG + switch (num) { + case 0xcd: +#if C_HEAVY_DEBUG + LOG(LOG_CPU,LOG_ERROR)("Call to interrupt 0xCD this is BAD"); + DEBUG_HeavyWriteLogInstruction(); + E_Exit("Call to interrupt 0xCD this is BAD"); +#endif + break; + case 0x03: + if (DEBUG_Breakpoint()) { + CPU_Cycles=0; + return; + } + }; +#endif + if (!cpu.pmode) { + /* Save everything on a 16-bit stack */ + CPU_Push16(reg_flags & 0xffff); + CPU_Push16(SegValue(cs)); + CPU_Push16(oldeip); + SETFLAGBIT(IF,false); + SETFLAGBIT(TF,false); + /* Get the new CS:IP from vector table */ + PhysPt base=cpu.idt.GetBase(); + reg_eip=mem_readw(base+(num << 2)); + Segs.val[cs]=mem_readw(base+(num << 2)+2); + Segs.phys[cs]=Segs.val[cs]<<4; + cpu.code.big=false; + return; + } else { + /* Protected Mode Interrupt */ + if ((reg_flags & FLAG_VM) && (type&CPU_INT_SOFTWARE) && !(type&CPU_INT_NOIOPLCHECK)) { +// LOG_MSG("Software int in v86, AH %X IOPL %x",reg_ah,(reg_flags & FLAG_IOPL) >>12); + if ((reg_flags & FLAG_IOPL)!=FLAG_IOPL) { + CPU_Exception(EXCEPTION_GP,0); + return; + } + } + + Descriptor gate; + if (!cpu.idt.GetDescriptor(num<<3,gate)) { + // zone66 + CPU_Exception(EXCEPTION_GP,num*8+2+(type&CPU_INT_SOFTWARE)?0:1); + return; + } + + if ((type&CPU_INT_SOFTWARE) && (gate.DPL()cpu.cpl, + "Interrupt to higher privilege", + EXCEPTION_GP,(gate_sel & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1) + switch (cs_desc.Type()) { + case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: + case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: + if (cs_dpl0", + EXCEPTION_GP,gate_sel & 0xfffc) + + Bitu n_ss,n_esp; + Bitu o_ss,o_esp; + o_ss=SegValue(ss); + o_esp=reg_esp; + cpu_tss.Get_SSx_ESPx(cs_dpl,n_ss,n_esp); + CPU_CHECK_COND((n_ss & 0xfffc)==0, + "INT:Gate with SS zero selector", + EXCEPTION_TS,(type&CPU_INT_SOFTWARE)?0:1) + Descriptor n_ss_desc; + CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_ss,n_ss_desc), + "INT:Gate with SS beyond limit", + EXCEPTION_TS,(n_ss & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1) + CPU_CHECK_COND(((n_ss & 3)!=cs_dpl) || (n_ss_desc.DPL()!=cs_dpl), + "INT:Inner level with CS_DPL!=SS_DPL and SS_RPL", + EXCEPTION_TS,(n_ss & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1) + + // check if stack segment is a writable data segment + switch (n_ss_desc.Type()) { + case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + break; + default: + E_Exit("INT:Inner level:Stack segment not writable."); // or #TS(ss_sel+EXT) + } + CPU_CHECK_COND(!n_ss_desc.saved.seg.p, + "INT:Inner level with nonpresent SS", + EXCEPTION_SS,(n_ss & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1) + + // commit point + Segs.phys[ss]=n_ss_desc.GetBase(); + Segs.val[ss]=n_ss; + if (n_ss_desc.Big()) { + cpu.stack.big=true; + cpu.stack.mask=0xffffffff; + cpu.stack.notmask=0; + reg_esp=n_esp; + } else { + cpu.stack.big=false; + cpu.stack.mask=0xffff; + cpu.stack.notmask=0xffff0000; + reg_sp=n_esp & 0xffff; + } + + cpu.cpl=cs_dpl; + if (gate.Type() & 0x8) { /* 32-bit Gate */ + if (reg_flags & FLAG_VM) { + CPU_Push32(SegValue(gs));SegSet16(gs,0x0); + CPU_Push32(SegValue(fs));SegSet16(fs,0x0); + CPU_Push32(SegValue(ds));SegSet16(ds,0x0); + CPU_Push32(SegValue(es));SegSet16(es,0x0); + } + CPU_Push32(o_ss); + CPU_Push32(o_esp); + } else { /* 16-bit Gate */ + if (reg_flags & FLAG_VM) E_Exit("V86 to 16-bit gate"); + CPU_Push16(o_ss); + CPU_Push16(o_esp); + } +// LOG_MSG("INT:Gate to inner level SS:%X SP:%X",n_ss,n_esp); + goto do_interrupt; + } + if (cs_dpl!=cpu.cpl) + E_Exit("Non-conforming intra privilege INT with DPL!=CPL"); + case DESC_CODE_N_C_A: case DESC_CODE_N_C_NA: + case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA: + /* Prepare stack for gate to same priviledge */ + CPU_CHECK_COND(!cs_desc.saved.seg.p, + "INT:Same level:CS segment not present", + EXCEPTION_NP,(gate_sel & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1) + if ((reg_flags & FLAG_VM) && (cs_dpl0; + reg_eip=gate_off; + + if (!(gate.Type()&1)) { + SETFLAGBIT(IF,false); + } + SETFLAGBIT(TF,false); + SETFLAGBIT(NT,false); + SETFLAGBIT(VM,false); + LOG(LOG_CPU,LOG_NORMAL)("INT:Gate to %X:%X big %d %s",gate_sel,gate_off,cs_desc.Big(),gate.Type() & 0x8 ? "386" : "286"); + return; + } + case DESC_TASK_GATE: + CPU_CHECK_COND(!gate.saved.seg.p, + "INT:Gate segment not present", + EXCEPTION_NP,num*8+2+(type&CPU_INT_SOFTWARE)?0:1) + + CPU_SwitchTask(gate.GetSelector(),TSwitch_CALL_INT,oldeip); + if (type & CPU_INT_HAS_ERROR) { + //TODO Be sure about this, seems somewhat unclear + if (cpu_tss.is386) CPU_Push32(cpu.exception.error); + else CPU_Push16(cpu.exception.error); + } + return; + default: + E_Exit("Illegal descriptor type %X for int %X",gate.Type(),num); + } + } + assert(1); + return ; // make compiler happy +} + + +void CPU_IRET(bool use32,Bitu oldeip) { + if (!cpu.pmode) { /* RealMode IRET */ + if (use32) { + reg_eip=CPU_Pop32(); + SegSet16(cs,CPU_Pop32()); + CPU_SetFlags(CPU_Pop32(),FMASK_ALL); + } else { + reg_eip=CPU_Pop16(); + SegSet16(cs,CPU_Pop16()); + CPU_SetFlags(CPU_Pop16(),FMASK_ALL & 0xffff); + } + cpu.code.big=false; + DestroyConditionFlags(); + return; + } else { /* Protected mode IRET */ + if (reg_flags & FLAG_VM) { + if ((reg_flags & FLAG_IOPL)!=FLAG_IOPL) { + // win3.x e + CPU_Exception(EXCEPTION_GP,0); + return; + } else { + if (use32) { + Bit32u new_eip=mem_readd(SegPhys(ss) + (reg_esp & cpu.stack.mask)); + Bit32u tempesp=(reg_esp&cpu.stack.notmask)|((reg_esp+4)&cpu.stack.mask); + Bit32u new_cs=mem_readd(SegPhys(ss) + (tempesp & cpu.stack.mask)); + tempesp=(tempesp&cpu.stack.notmask)|((tempesp+4)&cpu.stack.mask); + Bit32u new_flags=mem_readd(SegPhys(ss) + (tempesp & cpu.stack.mask)); + reg_esp=(tempesp&cpu.stack.notmask)|((tempesp+4)&cpu.stack.mask); + + reg_eip=new_eip; + SegSet16(cs,(Bit16u)(new_cs&0xffff)); + /* IOPL can not be modified in v86 mode by IRET */ + CPU_SetFlags(new_flags,FMASK_NORMAL|FLAG_NT); + } else { + Bit16u new_eip=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask)); + Bit32u tempesp=(reg_esp&cpu.stack.notmask)|((reg_esp+2)&cpu.stack.mask); + Bit16u new_cs=mem_readw(SegPhys(ss) + (tempesp & cpu.stack.mask)); + tempesp=(tempesp&cpu.stack.notmask)|((tempesp+2)&cpu.stack.mask); + Bit16u new_flags=mem_readw(SegPhys(ss) + (tempesp & cpu.stack.mask)); + reg_esp=(tempesp&cpu.stack.notmask)|((tempesp+2)&cpu.stack.mask); + + reg_eip=(Bit32u)new_eip; + SegSet16(cs,new_cs); + /* IOPL can not be modified in v86 mode by IRET */ + CPU_SetFlags(new_flags,FMASK_NORMAL|FLAG_NT); + } + cpu.code.big=false; + DestroyConditionFlags(); + return; + } + } + /* Check if this is task IRET */ + if (GETFLAG(NT)) { + if (GETFLAG(VM)) E_Exit("Pmode IRET with VM bit set"); + CPU_CHECK_COND(!cpu_tss.IsValid(), + "TASK Iret without valid TSS", + EXCEPTION_TS,cpu_tss.selector & 0xfffc) + if (!cpu_tss.desc.IsBusy()) { + LOG(LOG_CPU,LOG_ERROR)("TASK Iret:TSS not busy"); + } + Bitu back_link=cpu_tss.Get_back(); + CPU_SwitchTask(back_link,TSwitch_IRET,oldeip); + return; + } + Bitu n_cs_sel,n_eip,n_flags; + Bit32u tempesp; + if (use32) { + n_eip=mem_readd(SegPhys(ss) + (reg_esp & cpu.stack.mask)); + tempesp=(reg_esp&cpu.stack.notmask)|((reg_esp+4)&cpu.stack.mask); + n_cs_sel=mem_readd(SegPhys(ss) + (tempesp & cpu.stack.mask)) & 0xffff; + tempesp=(tempesp&cpu.stack.notmask)|((tempesp+4)&cpu.stack.mask); + n_flags=mem_readd(SegPhys(ss) + (tempesp & cpu.stack.mask)); + tempesp=(tempesp&cpu.stack.notmask)|((tempesp+4)&cpu.stack.mask); + + if ((n_flags & FLAG_VM) && (cpu.cpl==0)) { + // commit point + reg_esp=tempesp; + reg_eip=n_eip & 0xffff; + Bitu n_ss,n_esp,n_es,n_ds,n_fs,n_gs; + n_esp=CPU_Pop32(); + n_ss=CPU_Pop32() & 0xffff; + n_es=CPU_Pop32() & 0xffff; + n_ds=CPU_Pop32() & 0xffff; + n_fs=CPU_Pop32() & 0xffff; + n_gs=CPU_Pop32() & 0xffff; + + CPU_SetFlags(n_flags,FMASK_ALL | FLAG_VM); + DestroyConditionFlags(); + cpu.cpl=3; + + CPU_SetSegGeneral(ss,n_ss); + CPU_SetSegGeneral(es,n_es); + CPU_SetSegGeneral(ds,n_ds); + CPU_SetSegGeneral(fs,n_fs); + CPU_SetSegGeneral(gs,n_gs); + reg_esp=n_esp; + cpu.code.big=false; + SegSet16(cs,n_cs_sel); + LOG(LOG_CPU,LOG_NORMAL)("IRET:Back to V86: CS:%X IP %X SS:%X SP %X FLAGS:%X",SegValue(cs),reg_eip,SegValue(ss),reg_esp,reg_flags); + return; + } + if (n_flags & FLAG_VM) E_Exit("IRET from pmode to v86 with CPL!=0"); + } else { + n_eip=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask)); + tempesp=(reg_esp&cpu.stack.notmask)|((reg_esp+2)&cpu.stack.mask); + n_cs_sel=mem_readw(SegPhys(ss) + (tempesp & cpu.stack.mask)); + tempesp=(tempesp&cpu.stack.notmask)|((tempesp+2)&cpu.stack.mask); + n_flags=mem_readw(SegPhys(ss) + (tempesp & cpu.stack.mask)); + n_flags|=(reg_flags & 0xffff0000); + tempesp=(tempesp&cpu.stack.notmask)|((tempesp+2)&cpu.stack.mask); + + if (n_flags & FLAG_VM) E_Exit("VM Flag in 16-bit iret"); + } + CPU_CHECK_COND((n_cs_sel & 0xfffc)==0, + "IRET:CS selector zero", + EXCEPTION_GP,0) + Bitu n_cs_rpl=n_cs_sel & 3; + Descriptor n_cs_desc; + CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_cs_sel,n_cs_desc), + "IRET:CS selector beyond limits", + EXCEPTION_GP,n_cs_sel & 0xfffc) + CPU_CHECK_COND(n_cs_rpln_cs_rpl, + "IRET:C:DPL>RPL", + EXCEPTION_GP,n_cs_sel & 0xfffc) + break; + default: + E_Exit("IRET:Illegal descriptor type %X",n_cs_desc.Type()); + } + CPU_CHECK_COND(!n_cs_desc.saved.seg.p, + "IRET with nonpresent code segment", + EXCEPTION_NP,n_cs_sel & 0xfffc) + + if (n_cs_rpl==cpu.cpl) { + /* Return to same level */ + + // commit point + reg_esp=tempesp; + Segs.phys[cs]=n_cs_desc.GetBase(); + cpu.code.big=n_cs_desc.Big()>0; + Segs.val[cs]=n_cs_sel; + reg_eip=n_eip; + + Bitu mask=cpu.cpl ? (FMASK_NORMAL | FLAG_NT) : FMASK_ALL; + if (GETFLAG_IOPL0; + Segs.val[cs]=n_cs_sel; + + Bitu mask=cpu.cpl ? (FMASK_NORMAL | FLAG_NT) : FMASK_ALL; + if (GETFLAG_IOPLcpu.cpl, + "JMP:NC:RPL>CPL", + EXCEPTION_GP,selector & 0xfffc) + CPU_CHECK_COND(cpu.cpl!=desc.DPL(), + "JMP:NC:RPL != DPL", + EXCEPTION_GP,selector & 0xfffc) + LOG(LOG_CPU,LOG_NORMAL)("JMP:Code:NC to %X:%X big %d",selector,offset,desc.Big()); + goto CODE_jmp; + case DESC_CODE_N_C_A: case DESC_CODE_N_C_NA: + case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA: + LOG(LOG_CPU,LOG_NORMAL)("JMP:Code:C to %X:%X big %d",selector,offset,desc.Big()); + CPU_CHECK_COND(cpu.cpl0; + Segs.val[cs]=(selector & 0xfffc) | cpu.cpl; + reg_eip=offset; + return; + case DESC_386_TSS_A: + CPU_CHECK_COND(desc.DPL()cpu.cpl, + "CALL:CODE:NC:RPL>CPL", + EXCEPTION_GP,selector & 0xfffc) + CPU_CHECK_COND(call.DPL()!=cpu.cpl, + "CALL:CODE:NC:DPL!=CPL", + EXCEPTION_GP,selector & 0xfffc) + LOG(LOG_CPU,LOG_NORMAL)("CALL:CODE:NC to %X:%X",selector,offset); + goto call_code; + case DESC_CODE_N_C_A:case DESC_CODE_N_C_NA: + case DESC_CODE_R_C_A:case DESC_CODE_R_C_NA: + CPU_CHECK_COND(call.DPL()>cpu.cpl, + "CALL:CODE:C:DPL>CPL", + EXCEPTION_GP,selector & 0xfffc) + LOG(LOG_CPU,LOG_NORMAL)("CALL:CODE:C to %X:%X",selector,offset); +call_code: + if (!call.saved.seg.p) { + // borland extender (RTM) + CPU_Exception(EXCEPTION_NP,selector & 0xfffc); + return; + } + // commit point + if (!use32) { + CPU_Push16(SegValue(cs)); + CPU_Push16(oldeip); + reg_eip=offset & 0xffff; + } else { + CPU_Push32(SegValue(cs)); + CPU_Push32(oldeip); + reg_eip=offset; + } + Segs.phys[cs]=call.GetBase(); + cpu.code.big=call.Big()>0; + Segs.val[cs]=(selector & 0xfffc) | cpu.cpl; + return; + case DESC_386_CALL_GATE: + case DESC_286_CALL_GATE: + { + CPU_CHECK_COND(call.DPL()cpu.cpl, + "CALL:Gate:CS DPL>CPL", + EXCEPTION_GP,n_cs_sel & 0xfffc) + + CPU_CHECK_COND(!n_cs_desc.saved.seg.p, + "CALL:Gate:CS not present", + EXCEPTION_NP,n_cs_sel & 0xfffc) + + Bitu n_eip = call.GetOffset(); + switch (n_cs_desc.Type()) { + case DESC_CODE_N_NC_A:case DESC_CODE_N_NC_NA: + case DESC_CODE_R_NC_A:case DESC_CODE_R_NC_NA: + /* Check if we goto inner priviledge */ + if (n_cs_dpl < cpu.cpl) { + /* Get new SS:ESP out of TSS */ + Bitu n_ss_sel,n_esp; + Descriptor n_ss_desc; + cpu_tss.Get_SSx_ESPx(n_cs_dpl,n_ss_sel,n_esp); + CPU_CHECK_COND((n_ss_sel & 0xfffc)==0, + "CALL:Gate:NC:SS selector zero", + EXCEPTION_TS,0) + CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_ss_sel,n_ss_desc), + "CALL:Gate:Invalid SS selector", + EXCEPTION_TS,n_ss_sel & 0xfffc) + CPU_CHECK_COND(((n_ss_sel & 3)!=n_cs_desc.DPL()) || (n_ss_desc.DPL()!=n_cs_desc.DPL()), + "CALL:Gate:Invalid SS selector privileges", + EXCEPTION_TS,n_ss_sel & 0xfffc) + + switch (n_ss_desc.Type()) { + case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + // writable data segment + break; + default: + E_Exit("Call:Gate:SS no writable data segment"); // or #TS(ss_sel) + } + CPU_CHECK_COND(!n_ss_desc.saved.seg.p, + "CALL:Gate:Stack segment not present", + EXCEPTION_SS,n_ss_sel & 0xfffc) + + /* Load the new SS:ESP and save data on it */ + Bitu o_esp = reg_esp; + Bitu o_ss = SegValue(ss); + PhysPt o_stack = SegPhys(ss)+(reg_esp & cpu.stack.mask); + + + // catch pagefaults + if (call.saved.gate.paramcount&31) { + if (call.Type()==DESC_386_CALL_GATE) { + for (Bits i=(call.saved.gate.paramcount&31)-1;i>=0;i--) + mem_readd(o_stack+i*4); + } else { + for (Bits i=(call.saved.gate.paramcount&31)-1;i>=0;i--) + mem_readw(o_stack+i*2); + } + } + + // commit point + Segs.val[ss]=n_ss_sel; + Segs.phys[ss]=n_ss_desc.GetBase(); + if (n_ss_desc.Big()) { + cpu.stack.big=true; + cpu.stack.mask=0xffffffff; + cpu.stack.notmask=0; + reg_esp=n_esp; + } else { + cpu.stack.big=false; + cpu.stack.mask=0xffff; + cpu.stack.notmask=0xffff0000; + reg_sp=n_esp & 0xffff; + } + + cpu.cpl = n_cs_desc.DPL(); + Bit16u oldcs = SegValue(cs); + /* Switch to new CS:EIP */ + Segs.phys[cs] = n_cs_desc.GetBase(); + Segs.val[cs] = (n_cs_sel & 0xfffc) | cpu.cpl; + cpu.code.big = n_cs_desc.Big()>0; + reg_eip = n_eip; + if (!use32) reg_eip&=0xffff; + + if (call.Type()==DESC_386_CALL_GATE) { + CPU_Push32(o_ss); //save old stack + CPU_Push32(o_esp); + if (call.saved.gate.paramcount&31) + for (Bits i=(call.saved.gate.paramcount&31)-1;i>=0;i--) + CPU_Push32(mem_readd(o_stack+i*4)); + CPU_Push32(oldcs); + CPU_Push32(oldeip); + } else { + CPU_Push16(o_ss); //save old stack + CPU_Push16(o_esp); + if (call.saved.gate.paramcount&31) + for (Bits i=(call.saved.gate.paramcount&31)-1;i>=0;i--) + CPU_Push16(mem_readw(o_stack+i*2)); + CPU_Push16(oldcs); + CPU_Push16(oldeip); + } + + break; + } else if (n_cs_dpl > cpu.cpl) + E_Exit("CALL:GATE:CS DPL>CPL"); // or #GP(sel) + case DESC_CODE_N_C_A:case DESC_CODE_N_C_NA: + case DESC_CODE_R_C_A:case DESC_CODE_R_C_NA: + // zrdx extender + + if (call.Type()==DESC_386_CALL_GATE) { + CPU_Push32(SegValue(cs)); + CPU_Push32(oldeip); + } else { + CPU_Push16(SegValue(cs)); + CPU_Push16(oldeip); + } + + /* Switch to new CS:EIP */ + Segs.phys[cs] = n_cs_desc.GetBase(); + Segs.val[cs] = (n_cs_sel & 0xfffc) | cpu.cpl; + cpu.code.big = n_cs_desc.Big()>0; + reg_eip = n_eip; + if (!use32) reg_eip&=0xffff; + break; + default: + E_Exit("CALL:GATE:CS no executable segment"); + } + } /* Call Gates */ + break; + case DESC_386_TSS_A: + CPU_CHECK_COND(call.DPL()cpu.cpl, + "RET to C segment of higher privilege", + EXCEPTION_GP,selector & 0xfffc) + break; + default: + E_Exit("RET from illegal descriptor type %X",desc.Type()); + } +RET_same_level: + if (!desc.saved.seg.p) { + // borland extender (RTM) + CPU_Exception(EXCEPTION_NP,selector & 0xfffc); + return; + } + + // commit point + if (!use32) { + offset=CPU_Pop16(); + selector=CPU_Pop16(); + } else { + offset=CPU_Pop32(); + selector=CPU_Pop32() & 0xffff; + } + + Segs.phys[cs]=desc.GetBase(); + cpu.code.big=desc.Big()>0; + Segs.val[cs]=selector; + reg_eip=offset; + if (cpu.stack.big) { + reg_esp+=bytes; + } else { + reg_sp+=bytes; + } + LOG(LOG_CPU,LOG_NORMAL)("RET - Same level to %X:%X RPL %X DPL %X",selector,offset,rpl,desc.DPL()); + return; + } else { + /* Return to outer level */ + switch (desc.Type()) { + case DESC_CODE_N_NC_A:case DESC_CODE_N_NC_NA: + case DESC_CODE_R_NC_A:case DESC_CODE_R_NC_NA: + CPU_CHECK_COND(desc.DPL()!=rpl, + "RET to outer NC segment with DPL!=RPL", + EXCEPTION_GP,selector & 0xfffc) + break; + case DESC_CODE_N_C_A:case DESC_CODE_N_C_NA: + case DESC_CODE_R_C_A:case DESC_CODE_R_C_NA: + CPU_CHECK_COND(desc.DPL()>rpl, + "RET to outer C segment with DPL>RPL", + EXCEPTION_GP,selector & 0xfffc) + break; + default: + E_Exit("RET from illegal descriptor type %X",desc.Type()); // or #GP(selector) + } + + CPU_CHECK_COND(!desc.saved.seg.p, + "RET:Outer level:CS not present", + EXCEPTION_NP,selector & 0xfffc) + + // commit point + Bitu n_esp,n_ss; + if (use32) { + offset=CPU_Pop32(); + selector=CPU_Pop32() & 0xffff; + reg_esp+=bytes; + n_esp = CPU_Pop32(); + n_ss = CPU_Pop32() & 0xffff; + } else { + offset=CPU_Pop16(); + selector=CPU_Pop16(); + reg_esp+=bytes; + n_esp = CPU_Pop16(); + n_ss = CPU_Pop16(); + } + + CPU_CHECK_COND((n_ss & 0xfffc)==0, + "RET to outer level with SS selector zero", + EXCEPTION_GP,0) + + Descriptor n_ss_desc; + CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_ss,n_ss_desc), + "RET:SS beyond limits", + EXCEPTION_GP,n_ss & 0xfffc) + + CPU_CHECK_COND(((n_ss & 3)!=rpl) || (n_ss_desc.DPL()!=rpl), + "RET to outer segment with invalid SS privileges", + EXCEPTION_GP,n_ss & 0xfffc) + switch (n_ss_desc.Type()) { + case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + break; + default: + E_Exit("RET:SS selector type no writable data segment"); // or #GP(selector) + } + CPU_CHECK_COND(!n_ss_desc.saved.seg.p, + "RET:Stack segment not present", + EXCEPTION_SS,n_ss & 0xfffc) + + cpu.cpl = rpl; + Segs.phys[cs]=desc.GetBase(); + cpu.code.big=desc.Big()>0; + Segs.val[cs]=(selector&0xfffc) | cpu.cpl; + reg_eip=offset; + + Segs.val[ss]=n_ss; + Segs.phys[ss]=n_ss_desc.GetBase(); + if (n_ss_desc.Big()) { + cpu.stack.big=true; + cpu.stack.mask=0xffffffff; + cpu.stack.notmask=0; + reg_esp=n_esp+bytes; + } else { + cpu.stack.big=false; + cpu.stack.mask=0xffff; + cpu.stack.notmask=0xffff0000; + reg_sp=(n_esp & 0xffff)+bytes; + } + + CPU_CheckSegments(); + +// LOG(LOG_MISC,LOG_ERROR)("RET - Higher level to %X:%X RPL %X DPL %X",selector,offset,rpl,desc.DPL()); + return; + } + LOG(LOG_CPU,LOG_NORMAL)("Prot ret %X:%X",selector,offset); + return; + } + assert(1); +} + + +Bitu CPU_SLDT(void) { + return cpu.gdt.SLDT(); +} + +bool CPU_LLDT(Bitu selector) { + if (!cpu.gdt.LLDT(selector)) { + LOG(LOG_CPU,LOG_ERROR)("LLDT failed, selector=%X",selector); + return true; + } + LOG(LOG_CPU,LOG_NORMAL)("LDT Set to %X",selector); + return false; +} + +Bitu CPU_STR(void) { + return cpu_tss.selector; +} + +bool CPU_LTR(Bitu selector) { + if ((selector & 0xfffc)==0) { + cpu_tss.SetSelector(selector); + return false; + } + TSS_Descriptor desc; + if ((selector & 4) || (!cpu.gdt.GetDescriptor(selector,desc))) { + LOG(LOG_CPU,LOG_ERROR)("LTR failed, selector=%X",selector); + return CPU_PrepareException(EXCEPTION_GP,selector); + } + + if ((desc.Type()==DESC_286_TSS_A) || (desc.Type()==DESC_386_TSS_A)) { + if (!desc.saved.seg.p) { + LOG(LOG_CPU,LOG_ERROR)("LTR failed, selector=%X (not present)",selector); + return CPU_PrepareException(EXCEPTION_NP,selector); + } + if (!cpu_tss.SetSelector(selector)) E_Exit("LTR failed, selector=%X",selector); + cpu_tss.desc.SetBusy(true); + cpu_tss.SaveSelector(); + } else { + /* Descriptor was no available TSS descriptor */ + LOG(LOG_CPU,LOG_NORMAL)("LTR failed, selector=%X (type=%X)",selector,desc.Type()); + return CPU_PrepareException(EXCEPTION_GP,selector); + } + return false; +} + +void CPU_LGDT(Bitu limit,Bitu base) { + LOG(LOG_CPU,LOG_NORMAL)("GDT Set to base:%X limit:%X",base,limit); + cpu.gdt.SetLimit(limit); + cpu.gdt.SetBase(base); +} + +void CPU_LIDT(Bitu limit,Bitu base) { + LOG(LOG_CPU,LOG_NORMAL)("IDT Set to base:%X limit:%X",base,limit); + cpu.idt.SetLimit(limit); + cpu.idt.SetBase(base); +} + +Bitu CPU_SGDT_base(void) { + return cpu.gdt.GetBase(); +} +Bitu CPU_SGDT_limit(void) { + return cpu.gdt.GetLimit(); +} + +Bitu CPU_SIDT_base(void) { + return cpu.idt.GetBase(); +} +Bitu CPU_SIDT_limit(void) { + return cpu.idt.GetLimit(); +} + +static bool printed_cycles_auto_info = false; +void CPU_SET_CRX(Bitu cr,Bitu value) { + switch (cr) { + case 0: + { + Bitu changed=cpu.cr0 ^ value; + if (!changed) return; + cpu.cr0=value; + if (value & CR0_PROTECTION) { + cpu.pmode=true; + LOG(LOG_CPU,LOG_NORMAL)("Protected mode"); + PAGING_Enable((value & CR0_PAGING)>0); + + if (!(CPU_AutoDetermineMode&CPU_AUTODETERMINE_MASK)) break; + + if (CPU_AutoDetermineMode&CPU_AUTODETERMINE_CYCLES) { + CPU_CycleAutoAdjust=true; + CPU_CycleLeft=0; + CPU_Cycles=0; + CPU_OldCycleMax=CPU_CycleMax; + GFX_SetTitle(CPU_CyclePercUsed,-1,false); + if(!printed_cycles_auto_info) { + printed_cycles_auto_info = true; + LOG_MSG("DOSBox switched to max cycles, because of the setting: cycles=auto. If the game runs too fast try a fixed cycles amount in DOSBox's options."); + } + } else { + GFX_SetTitle(-1,-1,false); + } +#if (C_DYNAMIC_X86) + if (CPU_AutoDetermineMode&CPU_AUTODETERMINE_CORE) { + CPU_Core_Dyn_X86_Cache_Init(true); + cpudecoder=&CPU_Core_Dyn_X86_Run; + } +#elif (C_DYNREC) + if (CPU_AutoDetermineMode&CPU_AUTODETERMINE_CORE) { + CPU_Core_Dynrec_Cache_Init(true); + cpudecoder=&CPU_Core_Dynrec_Run; + } +#endif + CPU_AutoDetermineMode<<=CPU_AUTODETERMINE_SHIFT; + } else { + cpu.pmode=false; + if (value & CR0_PAGING) LOG_MSG("Paging requested without PE=1"); + PAGING_Enable(false); + LOG(LOG_CPU,LOG_NORMAL)("Real mode"); + } + break; + } + case 2: + paging.cr2=value; + break; + case 3: + PAGING_SetDirBase(value); + break; + default: + LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV CR%d,%X",cr,value); + break; + } +} + +bool CPU_WRITE_CRX(Bitu cr,Bitu value) { + /* Check if privileged to access control registers */ + if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0); + if ((cr==1) || (cr>4)) return CPU_PrepareException(EXCEPTION_UD,0); + if (CPU_ArchitectureType=CPU_ARCHTYPE_PENTIUMSLOW) return cpu.cr0; + else if (CPU_ArchitectureType>=CPU_ARCHTYPE_486OLDSLOW) return (cpu.cr0 & 0xe005003f); + else return (cpu.cr0 | 0x7ffffff0); + case 2: + return paging.cr2; + case 3: + return PAGING_GetDirBase() & 0xfffff000; + default: + LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV XXX, CR%d",cr); + break; + } + return 0; +} + +bool CPU_READ_CRX(Bitu cr,Bit32u & retvalue) { + /* Check if privileged to access control registers */ + if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0); + if ((cr==1) || (cr>4)) return CPU_PrepareException(EXCEPTION_UD,0); + retvalue=CPU_GET_CRX(cr); + return false; +} + + +bool CPU_WRITE_DRX(Bitu dr,Bitu value) { + /* Check if privileged to access control registers */ + if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0); + switch (dr) { + case 0: + case 1: + case 2: + case 3: + cpu.drx[dr]=value; + break; + case 4: + case 6: + cpu.drx[6]=(value|0xffff0ff0) & 0xffffefff; + break; + case 5: + case 7: + if (CPU_ArchitectureType0)) return CPU_PrepareException(EXCEPTION_GP,0); + switch (dr) { + case 0: + case 1: + case 2: + case 3: + case 6: + case 7: + retvalue=cpu.drx[dr]; + break; + case 4: + retvalue=cpu.drx[6]; + break; + case 5: + retvalue=cpu.drx[7]; + break; + default: + LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV XXX, DR%d",dr); + retvalue=0; + break; + } + return false; +} + +bool CPU_WRITE_TRX(Bitu tr,Bitu value) { + /* Check if privileged to access control registers */ + if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0); + switch (tr) { +// case 3: + case 6: + case 7: + cpu.trx[tr]=value; + return false; + default: + LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV TR%d,%X",tr,value); + break; + } + return CPU_PrepareException(EXCEPTION_UD,0); +} + +bool CPU_READ_TRX(Bitu tr,Bit32u & retvalue) { + /* Check if privileged to access control registers */ + if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0); + switch (tr) { +// case 3: + case 6: + case 7: + retvalue=cpu.trx[tr]; + return false; + default: + LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV XXX, TR%d",tr); + break; + } + return CPU_PrepareException(EXCEPTION_UD,0); +} + + +Bitu CPU_SMSW(void) { + return cpu.cr0; +} + +bool CPU_LMSW(Bitu word) { + if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0); + word&=0xf; + if (cpu.cr0 & 1) word|=1; + word|=(cpu.cr0&0xfffffff0); + CPU_SET_CRX(0,word); + return false; +} + +void CPU_ARPL(Bitu & dest_sel,Bitu src_sel) { + FillFlags(); + if ((dest_sel & 3) < (src_sel & 3)) { + dest_sel=(dest_sel & 0xfffc) + (src_sel & 3); +// dest_sel|=0xff3f0000; + SETFLAGBIT(ZF,true); + } else { + SETFLAGBIT(ZF,false); + } +} + +void CPU_LAR(Bitu selector,Bitu & ar) { + FillFlags(); + if (selector == 0) { + SETFLAGBIT(ZF,false); + return; + } + Descriptor desc;Bitu rpl=selector & 3; + if (!cpu.gdt.GetDescriptor(selector,desc)){ + SETFLAGBIT(ZF,false); + return; + } + switch (desc.Type()){ + case DESC_CODE_N_C_A: case DESC_CODE_N_C_NA: + case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA: + break; + + case DESC_286_INT_GATE: case DESC_286_TRAP_GATE: { + case DESC_386_INT_GATE: case DESC_386_TRAP_GATE: + SETFLAGBIT(ZF,false); + return; + } + + case DESC_LDT: + case DESC_TASK_GATE: + + case DESC_286_TSS_A: case DESC_286_TSS_B: + case DESC_286_CALL_GATE: + + case DESC_386_TSS_A: case DESC_386_TSS_B: + case DESC_386_CALL_GATE: + + + case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A: + case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A: + case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: + case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: + if (desc.DPL()desc.DPL()) || (cpu.cpl>desc.DPL())) { + // extreme pinball + return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc); + } + break; + case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA: + break; + default: + // gabriel knight + return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc); + + } + if (!desc.saved.seg.p) { + // win + return CPU_PrepareException(EXCEPTION_NP,value & 0xfffc); + } + + Segs.val[seg]=value; + Segs.phys[seg]=desc.GetBase(); + } + + return false; + } +} + +bool CPU_PopSeg(SegNames seg,bool use32) { + Bitu val=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask)); + if (CPU_SetSegGeneral(seg,val)) return true; + Bitu addsp=use32?0x04:0x02; + reg_esp=(reg_esp&cpu.stack.notmask)|((reg_esp+addsp)&cpu.stack.mask); + return false; +} + +bool CPU_CPUID(void) { + if (CPU_ArchitectureType105) CPU_CyclePercUsed=105; + LOG_MSG("CPU speed: max %d percent.",CPU_CyclePercUsed); + GFX_SetTitle(CPU_CyclePercUsed,-1,false); + } else { + Bit32s old_cycles=CPU_CycleMax; + if (CPU_CycleUp < 100) { + CPU_CycleMax = (Bit32s)(CPU_CycleMax * (1 + (float)CPU_CycleUp / 100.0)); + } else { + CPU_CycleMax = (Bit32s)(CPU_CycleMax + CPU_CycleUp); + } + + CPU_CycleLeft=0;CPU_Cycles=0; + if (CPU_CycleMax==old_cycles) CPU_CycleMax++; + if(CPU_CycleMax > 15000 ) + LOG_MSG("CPU speed: fixed %d cycles. If you need more than 20000, try core=dynamic in DOSBox's options.",CPU_CycleMax); + else + LOG_MSG("CPU speed: fixed %d cycles.",CPU_CycleMax); + GFX_SetTitle(CPU_CycleMax,-1,false); + } +} + +static void CPU_CycleDecrease(bool pressed) { + if (!pressed) return; + if (CPU_CycleAutoAdjust) { + CPU_CyclePercUsed-=5; + if (CPU_CyclePercUsed<=0) CPU_CyclePercUsed=1; + if(CPU_CyclePercUsed <=70) + LOG_MSG("CPU speed: max %d percent. If the game runs too fast, try a fixed cycles amount in DOSBox's options.",CPU_CyclePercUsed); + else + LOG_MSG("CPU speed: max %d percent.",CPU_CyclePercUsed); + GFX_SetTitle(CPU_CyclePercUsed,-1,false); + } else { + if (CPU_CycleDown < 100) { + CPU_CycleMax = (Bit32s)(CPU_CycleMax / (1 + (float)CPU_CycleDown / 100.0)); + } else { + CPU_CycleMax = (Bit32s)(CPU_CycleMax - CPU_CycleDown); + } + CPU_CycleLeft=0;CPU_Cycles=0; + if (CPU_CycleMax <= 0) CPU_CycleMax=1; + LOG_MSG("CPU speed: fixed %d cycles.",CPU_CycleMax); + GFX_SetTitle(CPU_CycleMax,-1,false); + } +} + +void CPU_Enable_SkipAutoAdjust(void) { + if (CPU_CycleAutoAdjust) { + CPU_CycleMax /= 2; + if (CPU_CycleMax < CPU_CYCLES_LOWER_LIMIT) + CPU_CycleMax = CPU_CYCLES_LOWER_LIMIT; + } + CPU_SkipCycleAutoAdjust=true; +} + +void CPU_Disable_SkipAutoAdjust(void) { + CPU_SkipCycleAutoAdjust=false; +} + + +extern Bit32s ticksDone; +extern Bit32u ticksScheduled; + +void CPU_Reset_AutoAdjust(void) { + CPU_IODelayRemoved = 0; + ticksDone = 0; + ticksScheduled = 0; +} + +class CPU: public Module_base { +private: + static bool inited; +public: + CPU(Section* configuration):Module_base(configuration) { +// if(inited) { +// Change_Config(configuration); +// return; +// } +// Section_prop * section=static_cast(configuration); + inited=true; + reg_eax=0; + reg_ebx=0; + reg_ecx=0; + reg_edx=0; + reg_edi=0; + reg_esi=0; + reg_ebp=0; + reg_esp=0; + + SegSet16(cs,0); + SegSet16(ds,0); + SegSet16(es,0); + SegSet16(fs,0); + SegSet16(gs,0); + SegSet16(ss,0); + + CPU_SetFlags(FLAG_IF,FMASK_ALL); //Enable interrupts + cpu.cr0=0xffffffff; + CPU_SET_CRX(0,0); //Initialize + cpu.code.big=false; + cpu.stack.mask=0xffff; + cpu.stack.notmask=0xffff0000; + cpu.stack.big=false; + cpu.trap_skip=false; + cpu.idt.SetBase(0); + cpu.idt.SetLimit(1023); + + for (Bitu i=0; i<7; i++) { + cpu.drx[i]=0; + cpu.trx[i]=0; + } + if (CPU_ArchitectureType==CPU_ARCHTYPE_PENTIUMSLOW) { + cpu.drx[6]=0xffff0ff0; + } else { + cpu.drx[6]=0xffff1ff0; + } + cpu.drx[7]=0x00000400; + + /* Init the cpu cores */ + CPU_Core_Normal_Init(); + CPU_Core_Simple_Init(); + CPU_Core_Full_Init(); +#if (C_DYNAMIC_X86) + CPU_Core_Dyn_X86_Init(); +#elif (C_DYNREC) + CPU_Core_Dynrec_Init(); +#endif + MAPPER_AddHandler(CPU_CycleDecrease,MK_f11,MMOD1,"cycledown","Dec Cycles"); + MAPPER_AddHandler(CPU_CycleIncrease,MK_f12,MMOD1,"cycleup" ,"Inc Cycles"); + Change_Config(configuration); + CPU_JMP(false,0,0,0); //Setup the first cpu core + } + bool Change_Config(Section* newconfig){ + Section_prop * section=static_cast(newconfig); + CPU_AutoDetermineMode=CPU_AUTODETERMINE_NONE; + //CPU_CycleLeft=0;//needed ? + CPU_Cycles=0; + CPU_SkipCycleAutoAdjust=false; + +#if 0 + Prop_multival* p = section->Get_multival("cycles"); + std::string type = p->GetSection()->Get_string("type"); + std::string str ; + CommandLine cmd(0,p->GetSection()->Get_string("parameters")); +#endif + CommandLine cmd(0, NULL); + std::string str; + std::string type = "max"; + if (type=="max") { + CPU_CycleMax=0; + CPU_CyclePercUsed=100; + CPU_CycleAutoAdjust=true; + CPU_CycleLimit=-1; + for (Bitu cmdnum=1; cmdnum<=cmd.GetCount(); cmdnum++) { + if (cmd.FindCommand(cmdnum,str)) { + if (str.find('%')==str.length()-1) { + str.erase(str.find('%')); + int percval=0; + std::istringstream stream(str); + stream >> percval; + if ((percval>0) && (percval<=105)) CPU_CyclePercUsed=(Bit32s)percval; + } else if (str=="limit") { + cmdnum++; + if (cmd.FindCommand(cmdnum,str)) { + int cyclimit=0; + std::istringstream stream(str); + stream >> cyclimit; + if (cyclimit>0) CPU_CycleLimit=cyclimit; + } + } + } + } + } else { + if (type=="auto") { + CPU_AutoDetermineMode|=CPU_AUTODETERMINE_CYCLES; + CPU_CycleMax=3000; + CPU_OldCycleMax=3000; + CPU_CyclePercUsed=100; + for (Bitu cmdnum=0; cmdnum<=cmd.GetCount(); cmdnum++) { + if (cmd.FindCommand(cmdnum,str)) { + if (str.find('%')==str.length()-1) { + str.erase(str.find('%')); + int percval=0; + std::istringstream stream(str); + stream >> percval; + if ((percval>0) && (percval<=105)) CPU_CyclePercUsed=(Bit32s)percval; + } else if (str=="limit") { + cmdnum++; + if (cmd.FindCommand(cmdnum,str)) { + int cyclimit=0; + std::istringstream stream(str); + stream >> cyclimit; + if (cyclimit>0) CPU_CycleLimit=cyclimit; + } + } else { + int rmdval=0; + std::istringstream stream(str); + stream >> rmdval; + if (rmdval>0) { + CPU_CycleMax=(Bit32s)rmdval; + CPU_OldCycleMax=(Bit32s)rmdval; + } + } + } + } + } else if(type =="fixed") { + cmd.FindCommand(1,str); + int rmdval=0; + std::istringstream stream(str); + stream >> rmdval; + CPU_CycleMax=(Bit32s)rmdval; + } else { + std::istringstream stream(type); + int rmdval=0; + stream >> rmdval; + if(rmdval) CPU_CycleMax=(Bit32s)rmdval; + } + CPU_CycleAutoAdjust=false; + } + + CPU_CycleUp=section->Get_int("cycleup"); + CPU_CycleDown=section->Get_int("cycledown"); + //std::string core(section->Get_string("core")); + std::string core = "simple"; + cpudecoder=&CPU_Core_Normal_Run; + if (core == "normal") { + cpudecoder=&CPU_Core_Normal_Run; + } else if (core =="simple") { + cpudecoder=&CPU_Core_Simple_Run; + } else if (core == "full") { + cpudecoder=&CPU_Core_Full_Run; + } else if (core == "auto") { + cpudecoder=&CPU_Core_Normal_Run; +#if (C_DYNAMIC_X86) + CPU_AutoDetermineMode|=CPU_AUTODETERMINE_CORE; + } + else if (core == "dynamic") { + cpudecoder=&CPU_Core_Dyn_X86_Run; + CPU_Core_Dyn_X86_SetFPUMode(true); + } else if (core == "dynamic_nodhfpu") { + cpudecoder=&CPU_Core_Dyn_X86_Run; + CPU_Core_Dyn_X86_SetFPUMode(false); +#elif (C_DYNREC) + CPU_AutoDetermineMode|=CPU_AUTODETERMINE_CORE; + } + else if (core == "dynamic") { + cpudecoder=&CPU_Core_Dynrec_Run; +#else + +#endif + } + +#if (C_DYNAMIC_X86) + CPU_Core_Dyn_X86_Cache_Init((core == "dynamic") || (core == "dynamic_nodhfpu")); +#elif (C_DYNREC) + CPU_Core_Dynrec_Cache_Init( core == "dynamic" ); +#endif + + CPU_ArchitectureType = CPU_ARCHTYPE_MIXED; + //std::string cputype(section->Get_string("cputype")); + std::string cputype = "auto"; + if (cputype == "auto") { + CPU_ArchitectureType = CPU_ARCHTYPE_MIXED; + } else if (cputype == "386") { + CPU_ArchitectureType = CPU_ARCHTYPE_386FAST; + } else if (cputype == "386_prefetch") { + CPU_ArchitectureType = CPU_ARCHTYPE_386FAST; + if (core == "normal") { + cpudecoder=&CPU_Core_Prefetch_Run; + CPU_PrefetchQueueSize = 16; + } else if (core == "auto") { + cpudecoder=&CPU_Core_Prefetch_Run; + CPU_PrefetchQueueSize = 16; + CPU_AutoDetermineMode&=(~CPU_AUTODETERMINE_CORE); + } else { + E_Exit("prefetch queue emulation requires the normal core setting."); + } + } else if (cputype == "386_slow") { + CPU_ArchitectureType = CPU_ARCHTYPE_386SLOW; + } else if (cputype == "486_slow") { + CPU_ArchitectureType = CPU_ARCHTYPE_486NEWSLOW; + } else if (cputype == "486_prefetch") { + CPU_ArchitectureType = CPU_ARCHTYPE_486NEWSLOW; + if (core == "normal") { + cpudecoder=&CPU_Core_Prefetch_Run; + CPU_PrefetchQueueSize = 32; + } else if (core == "auto") { + cpudecoder=&CPU_Core_Prefetch_Run; + CPU_PrefetchQueueSize = 32; + CPU_AutoDetermineMode&=(~CPU_AUTODETERMINE_CORE); + } else { + E_Exit("prefetch queue emulation requires the normal core setting."); + } + } else if (cputype == "pentium_slow") { + CPU_ArchitectureType = CPU_ARCHTYPE_PENTIUMSLOW; + } + + if (CPU_ArchitectureType>=CPU_ARCHTYPE_486NEWSLOW) CPU_flag_id_toggle=FLAG_ID; + else CPU_flag_id_toggle=0; + + + if(CPU_CycleMax <= 0) CPU_CycleMax = 3000; + if(CPU_CycleUp <= 0) CPU_CycleUp = 500; + if(CPU_CycleDown <= 0) CPU_CycleDown = 20; + if (CPU_CycleAutoAdjust) GFX_SetTitle(CPU_CyclePercUsed,-1,false); + else GFX_SetTitle(CPU_CycleMax,-1,false); + return true; + } + ~CPU(){ /* empty */}; +}; + +static CPU * test; + +void CPU_ShutDown(Section* sec) { +#if (C_DYNAMIC_X86) + CPU_Core_Dyn_X86_Cache_Close(); +#elif (C_DYNREC) + CPU_Core_Dynrec_Cache_Close(); +#endif + delete test; + test = NULL; +} + +void CPU_Init(Section* sec) { + test = new CPU(sec); + sec->AddDestroyFunction(&CPU_ShutDown,true); +} +//initialize static members +bool CPU::inited=false; diff --git a/dosbox/cpu.h b/dosbox/cpu.h new file mode 100644 index 00000000..d18caa2f --- /dev/null +++ b/dosbox/cpu.h @@ -0,0 +1,492 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id: cpu.h,v 1.57 2009-05-27 09:15:40 qbix79 Exp $ */ + +#ifndef DOSBOX_CPU_H +#define DOSBOX_CPU_H + +#ifndef DOSBOX_DOSBOX_H +#include "dosbox.h" +#endif +#ifndef DOSBOX_REGS_H +#include "regs.h" +#endif +#ifndef DOSBOX_MEM_H +#include "mem.h" +#endif + +#define CPU_AUTODETERMINE_NONE 0x00 +#define CPU_AUTODETERMINE_CORE 0x01 +#define CPU_AUTODETERMINE_CYCLES 0x02 + +#define CPU_AUTODETERMINE_SHIFT 0x02 +#define CPU_AUTODETERMINE_MASK 0x03 + +#define CPU_CYCLES_LOWER_LIMIT 100 + + +#define CPU_ARCHTYPE_MIXED 0xff +#define CPU_ARCHTYPE_386SLOW 0x30 +#define CPU_ARCHTYPE_386FAST 0x35 +#define CPU_ARCHTYPE_486OLDSLOW 0x40 +#define CPU_ARCHTYPE_486NEWSLOW 0x45 +#define CPU_ARCHTYPE_PENTIUMSLOW 0x50 + +/* CPU Cycle Timing */ +extern Bit32s CPU_Cycles; +extern Bit32s CPU_CycleLeft; +extern Bit32s CPU_CycleMax; +extern Bit32s CPU_OldCycleMax; +extern Bit32s CPU_CyclePercUsed; +extern Bit32s CPU_CycleLimit; +extern Bit64s CPU_IODelayRemoved; +extern bool CPU_CycleAutoAdjust; +extern bool CPU_SkipCycleAutoAdjust; +extern Bitu CPU_AutoDetermineMode; + +extern Bitu CPU_ArchitectureType; + +extern Bitu CPU_PrefetchQueueSize; + +/* Some common Defines */ +/* A CPU Handler */ +typedef Bits (CPU_Decoder)(void); +extern CPU_Decoder * cpudecoder; + +Bits CPU_Core_Normal_Run(void); +Bits CPU_Core_Normal_Trap_Run(void); +Bits CPU_Core_Simple_Run(void); +Bits CPU_Core_Full_Run(void); +Bits CPU_Core_Dyn_X86_Run(void); +Bits CPU_Core_Dyn_X86_Trap_Run(void); +Bits CPU_Core_Dynrec_Run(void); +Bits CPU_Core_Dynrec_Trap_Run(void); +Bits CPU_Core_Prefetch_Run(void); +Bits CPU_Core_Prefetch_Trap_Run(void); + +void CPU_Enable_SkipAutoAdjust(void); +void CPU_Disable_SkipAutoAdjust(void); +void CPU_Reset_AutoAdjust(void); + + +//CPU Stuff + +extern Bit16u parity_lookup[256]; + +bool CPU_LLDT(Bitu selector); +bool CPU_LTR(Bitu selector); +void CPU_LIDT(Bitu limit,Bitu base); +void CPU_LGDT(Bitu limit,Bitu base); + +Bitu CPU_STR(void); +Bitu CPU_SLDT(void); +Bitu CPU_SIDT_base(void); +Bitu CPU_SIDT_limit(void); +Bitu CPU_SGDT_base(void); +Bitu CPU_SGDT_limit(void); + +void CPU_ARPL(Bitu & dest_sel,Bitu src_sel); +void CPU_LAR(Bitu selector,Bitu & ar); +void CPU_LSL(Bitu selector,Bitu & limit); + +void CPU_SET_CRX(Bitu cr,Bitu value); +bool CPU_WRITE_CRX(Bitu cr,Bitu value); +Bitu CPU_GET_CRX(Bitu cr); +bool CPU_READ_CRX(Bitu cr,Bit32u & retvalue); + +bool CPU_WRITE_DRX(Bitu dr,Bitu value); +bool CPU_READ_DRX(Bitu dr,Bit32u & retvalue); + +bool CPU_WRITE_TRX(Bitu dr,Bitu value); +bool CPU_READ_TRX(Bitu dr,Bit32u & retvalue); + +Bitu CPU_SMSW(void); +bool CPU_LMSW(Bitu word); + +void CPU_VERR(Bitu selector); +void CPU_VERW(Bitu selector); + +void CPU_JMP(bool use32,Bitu selector,Bitu offset,Bitu oldeip); +void CPU_CALL(bool use32,Bitu selector,Bitu offset,Bitu oldeip); +void CPU_RET(bool use32,Bitu bytes,Bitu oldeip); +void CPU_IRET(bool use32,Bitu oldeip); +void CPU_HLT(Bitu oldeip); + +bool CPU_POPF(Bitu use32); +bool CPU_PUSHF(Bitu use32); +bool CPU_CLI(void); +bool CPU_STI(void); + +bool CPU_IO_Exception(Bitu port,Bitu size); +void CPU_RunException(void); + +void CPU_ENTER(bool use32,Bitu bytes,Bitu level); + +#define CPU_INT_SOFTWARE 0x1 +#define CPU_INT_EXCEPTION 0x2 +#define CPU_INT_HAS_ERROR 0x4 +#define CPU_INT_NOIOPLCHECK 0x8 + +void CPU_Interrupt(Bitu num,Bitu type,Bitu oldeip); +static INLINE void CPU_HW_Interrupt(Bitu num) { + CPU_Interrupt(num,0,reg_eip); +} +static INLINE void CPU_SW_Interrupt(Bitu num,Bitu oldeip) { + CPU_Interrupt(num,CPU_INT_SOFTWARE,oldeip); +} +static INLINE void CPU_SW_Interrupt_NoIOPLCheck(Bitu num,Bitu oldeip) { + CPU_Interrupt(num,CPU_INT_SOFTWARE|CPU_INT_NOIOPLCHECK,oldeip); +} + +bool CPU_PrepareException(Bitu which,Bitu error); +void CPU_Exception(Bitu which,Bitu error=0); + +bool CPU_SetSegGeneral(SegNames seg,Bitu value); +bool CPU_PopSeg(SegNames seg,bool use32); + +bool CPU_CPUID(void); +Bitu CPU_Pop16(void); +Bitu CPU_Pop32(void); +void CPU_Push16(Bitu value); +void CPU_Push32(Bitu value); + +void CPU_SetFlags(Bitu word,Bitu mask); + + +#define EXCEPTION_UD 6 +#define EXCEPTION_TS 10 +#define EXCEPTION_NP 11 +#define EXCEPTION_SS 12 +#define EXCEPTION_GP 13 +#define EXCEPTION_PF 14 + +#define CR0_PROTECTION 0x00000001 +#define CR0_MONITORPROCESSOR 0x00000002 +#define CR0_FPUEMULATION 0x00000004 +#define CR0_TASKSWITCH 0x00000008 +#define CR0_FPUPRESENT 0x00000010 +#define CR0_PAGING 0x80000000 + + +// ********************************************************************* +// Descriptor +// ********************************************************************* + +#define DESC_INVALID 0x00 +#define DESC_286_TSS_A 0x01 +#define DESC_LDT 0x02 +#define DESC_286_TSS_B 0x03 +#define DESC_286_CALL_GATE 0x04 +#define DESC_TASK_GATE 0x05 +#define DESC_286_INT_GATE 0x06 +#define DESC_286_TRAP_GATE 0x07 + +#define DESC_386_TSS_A 0x09 +#define DESC_386_TSS_B 0x0b +#define DESC_386_CALL_GATE 0x0c +#define DESC_386_INT_GATE 0x0e +#define DESC_386_TRAP_GATE 0x0f + +/* EU/ED Expand UP/DOWN RO/RW Read Only/Read Write NA/A Accessed */ +#define DESC_DATA_EU_RO_NA 0x10 +#define DESC_DATA_EU_RO_A 0x11 +#define DESC_DATA_EU_RW_NA 0x12 +#define DESC_DATA_EU_RW_A 0x13 +#define DESC_DATA_ED_RO_NA 0x14 +#define DESC_DATA_ED_RO_A 0x15 +#define DESC_DATA_ED_RW_NA 0x16 +#define DESC_DATA_ED_RW_A 0x17 + +/* N/R Readable NC/C Confirming A/NA Accessed */ +#define DESC_CODE_N_NC_A 0x18 +#define DESC_CODE_N_NC_NA 0x19 +#define DESC_CODE_R_NC_A 0x1a +#define DESC_CODE_R_NC_NA 0x1b +#define DESC_CODE_N_C_A 0x1c +#define DESC_CODE_N_C_NA 0x1d +#define DESC_CODE_R_C_A 0x1e +#define DESC_CODE_R_C_NA 0x1f + +#ifdef _MSC_VER +#pragma pack (1) +#endif + +struct S_Descriptor { +#ifdef WORDS_BIGENDIAN + Bit32u base_0_15 :16; + Bit32u limit_0_15 :16; + Bit32u base_24_31 :8; + Bit32u g :1; + Bit32u big :1; + Bit32u r :1; + Bit32u avl :1; + Bit32u limit_16_19 :4; + Bit32u p :1; + Bit32u dpl :2; + Bit32u type :5; + Bit32u base_16_23 :8; +#else + Bit32u limit_0_15 :16; + Bit32u base_0_15 :16; + Bit32u base_16_23 :8; + Bit32u type :5; + Bit32u dpl :2; + Bit32u p :1; + Bit32u limit_16_19 :4; + Bit32u avl :1; + Bit32u r :1; + Bit32u big :1; + Bit32u g :1; + Bit32u base_24_31 :8; +#endif +}GCC_ATTRIBUTE(packed); + +struct G_Descriptor { +#ifdef WORDS_BIGENDIAN + Bit32u selector: 16; + Bit32u offset_0_15 :16; + Bit32u offset_16_31 :16; + Bit32u p :1; + Bit32u dpl :2; + Bit32u type :5; + Bit32u reserved :3; + Bit32u paramcount :5; +#else + Bit32u offset_0_15 :16; + Bit32u selector :16; + Bit32u paramcount :5; + Bit32u reserved :3; + Bit32u type :5; + Bit32u dpl :2; + Bit32u p :1; + Bit32u offset_16_31 :16; +#endif +} GCC_ATTRIBUTE(packed); + +struct TSS_16 { + Bit16u back; /* Back link to other task */ + Bit16u sp0; /* The CK stack pointer */ + Bit16u ss0; /* The CK stack selector */ + Bit16u sp1; /* The parent KL stack pointer */ + Bit16u ss1; /* The parent KL stack selector */ + Bit16u sp2; /* Unused */ + Bit16u ss2; /* Unused */ + Bit16u ip; /* The instruction pointer */ + Bit16u flags; /* The flags */ + Bit16u ax, cx, dx, bx; /* The general purpose registers */ + Bit16u sp, bp, si, di; /* The special purpose registers */ + Bit16u es; /* The extra selector */ + Bit16u cs; /* The code selector */ + Bit16u ss; /* The application stack selector */ + Bit16u ds; /* The data selector */ + Bit16u ldt; /* The local descriptor table */ +} GCC_ATTRIBUTE(packed); + +struct TSS_32 { + Bit32u back; /* Back link to other task */ + Bit32u esp0; /* The CK stack pointer */ + Bit32u ss0; /* The CK stack selector */ + Bit32u esp1; /* The parent KL stack pointer */ + Bit32u ss1; /* The parent KL stack selector */ + Bit32u esp2; /* Unused */ + Bit32u ss2; /* Unused */ + Bit32u cr3; /* The page directory pointer */ + Bit32u eip; /* The instruction pointer */ + Bit32u eflags; /* The flags */ + Bit32u eax, ecx, edx, ebx; /* The general purpose registers */ + Bit32u esp, ebp, esi, edi; /* The special purpose registers */ + Bit32u es; /* The extra selector */ + Bit32u cs; /* The code selector */ + Bit32u ss; /* The application stack selector */ + Bit32u ds; /* The data selector */ + Bit32u fs; /* And another extra selector */ + Bit32u gs; /* ... and another one */ + Bit32u ldt; /* The local descriptor table */ +} GCC_ATTRIBUTE(packed); + +#ifdef _MSC_VER +#pragma pack() +#endif +class Descriptor +{ +public: + Descriptor() { saved.fill[0]=saved.fill[1]=0; } + + void Load(PhysPt address); + void Save(PhysPt address); + + PhysPt GetBase (void) { + return (saved.seg.base_24_31<<24) | (saved.seg.base_16_23<<16) | saved.seg.base_0_15; + } + Bitu GetLimit (void) { + Bitu limit = (saved.seg.limit_16_19<<16) | saved.seg.limit_0_15; + if (saved.seg.g) return (limit<<12) | 0xFFF; + return limit; + } + Bitu GetOffset(void) { + return (saved.gate.offset_16_31 << 16) | saved.gate.offset_0_15; + } + Bitu GetSelector(void) { + return saved.gate.selector; + } + Bitu Type(void) { + return saved.seg.type; + } + Bitu Conforming(void) { + return saved.seg.type & 8; + } + Bitu DPL(void) { + return saved.seg.dpl; + } + Bitu Big(void) { + return saved.seg.big; + } +public: + union { + S_Descriptor seg; + G_Descriptor gate; + Bit32u fill[2]; + } saved; +}; + +class DescriptorTable { +public: + PhysPt GetBase (void) { return table_base; } + Bitu GetLimit (void) { return table_limit; } + void SetBase (PhysPt _base) { table_base = _base; } + void SetLimit (Bitu _limit) { table_limit= _limit; } + + bool GetDescriptor (Bitu selector, Descriptor& desc) { + selector&=~7; + if (selector>=table_limit) return false; + desc.Load(table_base+(selector)); + return true; + } +protected: + PhysPt table_base; + Bitu table_limit; +}; + +class GDTDescriptorTable : public DescriptorTable { +public: + bool GetDescriptor(Bitu selector, Descriptor& desc) { + Bitu address=selector & ~7; + if (selector & 4) { + if (address>=ldt_limit) return false; + desc.Load(ldt_base+address); + return true; + } else { + if (address>=table_limit) return false; + desc.Load(table_base+address); + return true; + } + } + bool SetDescriptor(Bitu selector, Descriptor& desc) { + Bitu address=selector & ~7; + if (selector & 4) { + if (address>=ldt_limit) return false; + desc.Save(ldt_base+address); + return true; + } else { + if (address>=table_limit) return false; + desc.Save(table_base+address); + return true; + } + } + Bitu SLDT(void) { + return ldt_value; + } + bool LLDT(Bitu value) { + if ((value&0xfffc)==0) { + ldt_value=0; + ldt_base=0; + ldt_limit=0; + return true; + } + Descriptor desc; + if (!GetDescriptor(value,desc)) return !CPU_PrepareException(EXCEPTION_GP,value); + if (desc.Type()!=DESC_LDT) return !CPU_PrepareException(EXCEPTION_GP,value); + if (!desc.saved.seg.p) return !CPU_PrepareException(EXCEPTION_NP,value); + ldt_base=desc.GetBase(); + ldt_limit=desc.GetLimit(); + ldt_value=value; + return true; + } +private: + PhysPt ldt_base; + Bitu ldt_limit; + Bitu ldt_value; +}; + +class TSS_Descriptor : public Descriptor { +public: + Bitu IsBusy(void) { + return saved.seg.type & 2; + } + Bitu Is386(void) { + return saved.seg.type & 8; + } + void SetBusy(bool busy) { + if (busy) saved.seg.type|=2; + else saved.seg.type&=~2; + } +}; + + +struct CPUBlock { + Bitu cpl; /* Current Privilege */ + Bitu mpl; + Bitu cr0; + bool pmode; /* Is Protected mode enabled */ + GDTDescriptorTable gdt; + DescriptorTable idt; + struct { + Bitu mask,notmask; + bool big; + } stack; + struct { + bool big; + } code; + struct { + Bitu cs,eip; + CPU_Decoder * old_decoder; + } hlt; + struct { + Bitu which,error; + } exception; + Bits direction; + bool trap_skip; + Bit32u drx[8]; + Bit32u trx[8]; +}; + +extern CPUBlock cpu; + +static INLINE void CPU_SetFlagsd(Bitu word) { + Bitu mask=cpu.cpl ? FMASK_NORMAL : FMASK_ALL; + CPU_SetFlags(word,mask); +} + +static INLINE void CPU_SetFlagsw(Bitu word) { + Bitu mask=(cpu.cpl ? FMASK_NORMAL : FMASK_ALL) & 0xffff; + CPU_SetFlags(word,mask); +} + + +#endif diff --git a/dosbox/db_memory.cpp b/dosbox/db_memory.cpp new file mode 100644 index 00000000..4bb885d8 --- /dev/null +++ b/dosbox/db_memory.cpp @@ -0,0 +1,629 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id: memory.cpp,v 1.56 2009-05-27 09:15:41 qbix79 Exp $ */ + +#include "dosbox.h" +#include "mem.h" +#include "inout.h" +#include "setup.h" +#include "paging.h" +#include "regs.h" + +#include + +#define PAGES_IN_BLOCK ((1024*1024)/MEM_PAGE_SIZE) +#define SAFE_MEMORY 32 +#define MAX_MEMORY 64 +#define MAX_PAGE_ENTRIES (MAX_MEMORY*1024*1024/4096) +#define LFB_PAGES 512 +#define MAX_LINKS ((MAX_MEMORY*1024/4)+4096) //Hopefully enough + +struct LinkBlock { + Bitu used; + Bit32u pages[MAX_LINKS]; +}; + +static struct MemoryBlock { + Bitu pages; + PageHandler * * phandlers; + MemHandle * mhandles; + LinkBlock links; + struct { + Bitu start_page; + Bitu end_page; + Bitu pages; + PageHandler *handler; + PageHandler *mmiohandler; + } lfb; + struct { + bool enabled; + Bit8u controlport; + } a20; +} memory; + +HostPt MemBase; + +class IllegalPageHandler : public PageHandler { +public: + IllegalPageHandler() { + flags=PFLAG_INIT|PFLAG_NOCODE; + } + Bitu readb(PhysPt addr) { +#if C_DEBUG + LOG_MSG("Illegal read from %x, CS:IP %8x:%8x",addr,SegValue(cs),reg_eip); +#else + static Bits lcount=0; + if (lcount<1000) { + lcount++; + LOG_MSG("Illegal read from %x, CS:IP %8x:%8x",addr,SegValue(cs),reg_eip); + } +#endif + return 0; + } + void writeb(PhysPt addr,Bitu val) { +#if C_DEBUG + LOG_MSG("Illegal write to %x, CS:IP %8x:%8x",addr,SegValue(cs),reg_eip); +#else + static Bits lcount=0; + if (lcount<1000) { + lcount++; + LOG_MSG("Illegal write to %x, CS:IP %8x:%8x",addr,SegValue(cs),reg_eip); + } +#endif + } +}; + +class RAMPageHandler : public PageHandler { +public: + RAMPageHandler() { + flags=PFLAG_READABLE|PFLAG_WRITEABLE; + } + HostPt GetHostReadPt(Bitu phys_page) { + return MemBase+phys_page*MEM_PAGESIZE; + } + HostPt GetHostWritePt(Bitu phys_page) { + return MemBase+phys_page*MEM_PAGESIZE; + } +}; + +class ROMPageHandler : public RAMPageHandler { +public: + ROMPageHandler() { + flags=PFLAG_READABLE|PFLAG_HASROM; + } + void writeb(PhysPt addr,Bitu val){ + LOG(LOG_CPU,LOG_ERROR)("Write %x to rom at %x",val,addr); + } + void writew(PhysPt addr,Bitu val){ + LOG(LOG_CPU,LOG_ERROR)("Write %x to rom at %x",val,addr); + } + void writed(PhysPt addr,Bitu val){ + LOG(LOG_CPU,LOG_ERROR)("Write %x to rom at %x",val,addr); + } +}; + + + +static IllegalPageHandler illegal_page_handler; +static RAMPageHandler ram_page_handler; +static ROMPageHandler rom_page_handler; + +void MEM_SetLFB(Bitu page, Bitu pages, PageHandler *handler, PageHandler *mmiohandler) { + memory.lfb.handler=handler; + memory.lfb.mmiohandler=mmiohandler; + memory.lfb.start_page=page; + memory.lfb.end_page=page+pages; + memory.lfb.pages=pages; + PAGING_ClearTLB(); +} + +PageHandler * MEM_GetPageHandler(Bitu phys_page) { + if (phys_page=memory.lfb.start_page) && (phys_page=memory.lfb.start_page+0x01000000/4096) && + (phys_page0;pages--) { + memory.phandlers[phys_page]=handler; + phys_page++; + } +} + +void MEM_ResetPageHandler(Bitu phys_page, Bitu pages) { + for (;pages>0;pages--) { + memory.phandlers[phys_page]=&ram_page_handler; + phys_page++; + } +} + +Bitu mem_strlen(PhysPt pt) { + Bitu x=0; + while (x<1024) { + if (!mem_readb_inline(pt+x)) return x; + x++; + } + return 0; //Hope this doesn't happen +} + +void mem_strcpy(PhysPt dest,PhysPt src) { + Bit8u r; + while ( (r = mem_readb(src++)) ) mem_writeb_inline(dest++,r); + mem_writeb_inline(dest,0); +} + +void mem_memcpy(PhysPt dest,PhysPt src,Bitu size) { + while (size--) mem_writeb_inline(dest++,mem_readb_inline(src++)); +} + +void MEM_BlockRead(PhysPt pt,void * data,Bitu size) { + Bit8u * write=reinterpret_cast(data); + while (size--) { + *write++=mem_readb_inline(pt++); + } +} + +void MEM_BlockWrite(PhysPt pt,void const * const data,Bitu size) { + Bit8u const * read = reinterpret_cast(data); + while (size--) { + mem_writeb_inline(pt++,*read++); + } +} + +void MEM_BlockCopy(PhysPt dest,PhysPt src,Bitu size) { + mem_memcpy(dest,src,size); +} + +void MEM_StrCopy(PhysPt pt,char * data,Bitu size) { + while (size--) { + Bit8u r=mem_readb_inline(pt++); + if (!r) break; + *data++=r; + } + *data=0; +} + +Bitu MEM_TotalPages(void) { + return memory.pages; +} + +Bitu MEM_FreeLargest(void) { + Bitu size=0;Bitu largest=0; + Bitu index=XMS_START; + while (indexlargest) largest=size; + size=0; + } + index++; + } + if (size>largest) largest=size; + return largest; +} + +Bitu MEM_FreeTotal(void) { + Bitu free=0; + Bitu index=XMS_START; + while (index0) { + pages++; + handle=memory.mhandles[handle]; + } + return pages; +} + +//TODO Maybe some protection for this whole allocation scheme + +INLINE Bitu BestMatch(Bitu size) { + Bitu index=XMS_START; + Bitu first=0; + Bitu best=0xfffffff; + Bitu best_first=0; + while (indexsize) { + if (pages=size) && (index-first0) { + MemHandle next=memory.mhandles[handle]; + memory.mhandles[handle]=0; + handle=next; + } +} + +bool MEM_ReAllocatePages(MemHandle & handle,Bitu pages,bool sequence) { + if (handle<=0) { + if (!pages) return true; + handle=MEM_AllocatePages(pages,sequence); + return (handle>0); + } + if (!pages) { + MEM_ReleasePages(handle); + handle=-1; + return true; + } + MemHandle index=handle; + MemHandle last;Bitu old_pages=0; + while (index>0) { + old_pages++; + last=index; + index=memory.mhandles[index]; + } + if (old_pages == pages) return true; + if (old_pages > pages) { + /* Decrease size */ + pages--;index=handle;old_pages--; + while (pages) { + index=memory.mhandles[index]; + pages--;old_pages--; + } + MemHandle next=memory.mhandles[index]; + memory.mhandles[index]=-1; + index=next; + while (old_pages) { + next=memory.mhandles[index]; + memory.mhandles[index]=0; + index=next; + old_pages--; + } + return true; + } else { + /* Increase size, check for enough free space */ + Bitu need=pages-old_pages; + if (sequence) { + index=last+1; + Bitu free=0; + while ((index<(MemHandle)memory.pages) && !memory.mhandles[index]) { + index++;free++; + } + if (free>=need) { + /* Enough space allocate more pages */ + index=last; + while (need) { + memory.mhandles[index]=index+1; + need--;index++; + } + memory.mhandles[index]=-1; + return true; + } else { + /* Not Enough space allocate new block and copy */ + MemHandle newhandle=MEM_AllocatePages(pages,true); + if (!newhandle) return false; + MEM_BlockCopy(newhandle*4096,handle*4096,old_pages*4096); + MEM_ReleasePages(handle); + handle=newhandle; + return true; + } + } else { + MemHandle rem=MEM_AllocatePages(need,false); + if (!rem) return false; + memory.mhandles[last]=rem; + return true; + } + } + return 0; +} + +MemHandle MEM_NextHandle(MemHandle handle) { + return memory.mhandles[handle]; +} + +MemHandle MEM_NextHandleAt(MemHandle handle,Bitu where) { + while (where) { + where--; + handle=memory.mhandles[handle]; + } + return handle; +} + + +/* + A20 line handling, + Basically maps the 4 pages at the 1mb to 0mb in the default page directory +*/ +bool MEM_A20_Enabled(void) { + return memory.a20.enabled; +} + +void MEM_A20_Enable(bool enabled) { + Bitu phys_base=enabled ? (1024/4) : 0; + for (Bitu i=0;i<16;i++) PAGING_MapPage((1024/4)+i,phys_base+i); + memory.a20.enabled=enabled; +} + + +/* Memory access functions */ +Bit16u mem_unalignedreadw(PhysPt address) { + return mem_readb_inline(address) | + mem_readb_inline(address+1) << 8; +} + +Bit32u mem_unalignedreadd(PhysPt address) { + return mem_readb_inline(address) | + (mem_readb_inline(address+1) << 8) | + (mem_readb_inline(address+2) << 16) | + (mem_readb_inline(address+3) << 24); +} + + +void mem_unalignedwritew(PhysPt address,Bit16u val) { + mem_writeb_inline(address,(Bit8u)val);val>>=8; + mem_writeb_inline(address+1,(Bit8u)val); +} + +void mem_unalignedwrited(PhysPt address,Bit32u val) { + mem_writeb_inline(address,(Bit8u)val);val>>=8; + mem_writeb_inline(address+1,(Bit8u)val);val>>=8; + mem_writeb_inline(address+2,(Bit8u)val);val>>=8; + mem_writeb_inline(address+3,(Bit8u)val); +} + + +bool mem_unalignedreadw_checked(PhysPt address, Bit16u * val) { + Bit8u rval1,rval2; + if (mem_readb_checked(address+0, &rval1)) return true; + if (mem_readb_checked(address+1, &rval2)) return true; + *val=(Bit16u)(((Bit8u)rval1) | (((Bit8u)rval2) << 8)); + return false; +} + +bool mem_unalignedreadd_checked(PhysPt address, Bit32u * val) { + Bit8u rval1,rval2,rval3,rval4; + if (mem_readb_checked(address+0, &rval1)) return true; + if (mem_readb_checked(address+1, &rval2)) return true; + if (mem_readb_checked(address+2, &rval3)) return true; + if (mem_readb_checked(address+3, &rval4)) return true; + *val=(Bit32u)(((Bit8u)rval1) | (((Bit8u)rval2) << 8) | (((Bit8u)rval3) << 16) | (((Bit8u)rval4) << 24)); + return false; +} + +bool mem_unalignedwritew_checked(PhysPt address,Bit16u val) { + if (mem_writeb_checked(address,(Bit8u)(val & 0xff))) return true;val>>=8; + if (mem_writeb_checked(address+1,(Bit8u)(val & 0xff))) return true; + return false; +} + +bool mem_unalignedwrited_checked(PhysPt address,Bit32u val) { + if (mem_writeb_checked(address,(Bit8u)(val & 0xff))) return true;val>>=8; + if (mem_writeb_checked(address+1,(Bit8u)(val & 0xff))) return true;val>>=8; + if (mem_writeb_checked(address+2,(Bit8u)(val & 0xff))) return true;val>>=8; + if (mem_writeb_checked(address+3,(Bit8u)(val & 0xff))) return true; + return false; +} + +Bit8u mem_readb(PhysPt address) { + return mem_readb_inline(address); +} + +Bit16u mem_readw(PhysPt address) { + return mem_readw_inline(address); +} + +Bit32u mem_readd(PhysPt address) { + return mem_readd_inline(address); +} + +void mem_writeb(PhysPt address,Bit8u val) { + mem_writeb_inline(address,val); +} + +void mem_writew(PhysPt address,Bit16u val) { + mem_writew_inline(address,val); +} + +void mem_writed(PhysPt address,Bit32u val) { + mem_writed_inline(address,val); +} + +static void write_p92(Bitu port,Bitu val,Bitu iolen) { + // Bit 0 = system reset (switch back to real mode) + if (val&1) E_Exit("XMS: CPU reset via port 0x92 not supported."); + memory.a20.controlport = val & ~2; + MEM_A20_Enable((val & 2)>0); +} + +static Bitu read_p92(Bitu port,Bitu iolen) { + return memory.a20.controlport | (memory.a20.enabled ? 0x02 : 0); +} + +void RemoveEMSPageFrame(void) { + /* Setup rom at 0xe0000-0xf0000 */ + for (Bitu ct=0xe0;ct<0xf0;ct++) { + memory.phandlers[ct] = &rom_page_handler; + } +} + +void PreparePCJRCartRom(void) { + /* Setup rom at 0xd0000-0xe0000 */ + for (Bitu ct=0xd0;ct<0xe0;ct++) { + memory.phandlers[ct] = &rom_page_handler; + } +} + +HostPt GetMemBase(void) { return MemBase; } + +extern int x86_memsize; +extern int x86_biosstart; + +class MEMORY:public Module_base{ +#if 0 +private: + IO_ReadHandleObject ReadHandler; + IO_WriteHandleObject WriteHandler; +#endif +public: + MEMORY(Section* configuration):Module_base(configuration){ + Bitu i; + Section_prop * section=static_cast(configuration); + + /* Setup the Physical Page Links */ +#if 0 + Bitu memsize=section->Get_int("memsize"); +#else + Bitu memsize = x86_memsize / (1024 * 1024); +#endif + if (memsize < 1) memsize = 1; + /* max 63 to solve problems with certain xms handlers */ + if (memsize > MAX_MEMORY-1) { + LOG_MSG("Maximum memory size is %d MB",MAX_MEMORY - 1); + memsize = MAX_MEMORY-1; + } + if (memsize > SAFE_MEMORY-1) { + LOG_MSG("Memory sizes above %d MB are NOT recommended.",SAFE_MEMORY - 1); + LOG_MSG("Stick with the default values unless you are absolutely certain."); + } +#if 0 + MemBase = new Bit8u[memsize*1024*1024]; + if (!MemBase) E_Exit("Can't allocate main memory of %d MB",memsize); + /* Clear the memory, as new doesn't always give zeroed memory + * (Visual C debug mode). We want zeroed memory though. */ + memset((void*)MemBase,0,memsize*1024*1024); +#endif + memory.pages = (memsize*1024*1024)/4096; + /* Allocate the data for the different page information blocks */ + memory.phandlers=new PageHandler * [memory.pages]; + memory.mhandles=new MemHandle [memory.pages]; + for (i = 0;i < memory.pages;i++) { + memory.phandlers[i] = &ram_page_handler; + memory.mhandles[i] = 0; //Set to 0 for memory allocation + } +#if 0 + /* Setup rom at 0xc0000-0xc8000 */ + for (i=0xc0;i<0xc8;i++) { + memory.phandlers[i] = &rom_page_handler; + } +#endif + /* Setup rom at 0xf0000-0x100000 */ + for (i= (x86_biosstart >> 12);i<0x100;i++) { + memory.phandlers[i] = &rom_page_handler; + } +#if 0 + if (machine==MCH_PCJR) { + /* Setup cartridge rom at 0xe0000-0xf0000 */ + for (i=0xe0;i<0xf0;i++) { + memory.phandlers[i] = &rom_page_handler; + } + } +#endif + /* Reset some links */ + memory.links.used = 0; +#if 0 + // A20 Line - PS/2 system control port A + WriteHandler.Install(0x92,write_p92,IO_MB); + ReadHandler.Install(0x92,read_p92,IO_MB); +#endif + MEM_A20_Enable(false); + } + ~MEMORY(){ + //delete [] MemBase; + delete [] memory.phandlers; + delete [] memory.mhandles; + } +}; + + +static MEMORY* test; + +void MEM_ShutDown(Section * sec) { + delete test; +} + +void MEM_Init(Section * sec) { + /* shutdown function */ + test = new MEMORY(sec); + sec->AddDestroyFunction(&MEM_ShutDown); +} diff --git a/dosbox/dosbox.h b/dosbox/dosbox.h new file mode 100644 index 00000000..e76e0c9e --- /dev/null +++ b/dosbox/dosbox.h @@ -0,0 +1,76 @@ +#ifndef DOSBOX_H +#define DOSBOX_H + +#ifndef CH_LIST +#define CH_LIST +#include +#endif + +#ifndef CH_STRING +#define CH_STRING +#include +#endif + +#define C_FPU 1 + +typedef unsigned char Bit8u; +typedef signed char Bit8s; +typedef unsigned short Bit16u; +typedef signed short Bit16s; +typedef unsigned long Bit32u; +typedef signed long Bit32s; +#if defined(_MSC_VER) +typedef unsigned __int64 Bit64u; +typedef signed __int64 Bit64s; +#else +typedef unsigned long long int Bit64u; +typedef signed long long int Bit64s; +#endif +typedef Bit32u Bitu; +typedef Bit32s Bits; +typedef double Real64; + +#define LONGTYPE(a) a##LL + +#define INLINE __inline + +#define GCC_ATTRIBUTE(x) + +#include "logging.h" + +extern void E_Exit(char*,...); +extern void DOSBOX_RunMachine(void); + +#define GCC_UNLIKELY(x) x +#define GCC_LIKELY(x) x + +#define MAPPER_AddHandler(x1,x2,x3,x4,x5) + +class CommandLine { +public: + CommandLine(int argc, char const * const argv[]); + CommandLine(char const * const name, char const * const cmdline); + const char * GetFileName() { return file_name.c_str(); } + + bool FindExist(char const * const name, bool remove = false); + bool FindHex(char const * const name, int & value, bool remove = false); + bool FindInt(char const * const name, int & value, bool remove = false); + bool FindString(char const * const name, std::string & value, bool remove = false); + bool FindCommand(unsigned int which, std::string & value); + bool FindStringBegin(char const * const begin, std::string & value, bool remove = false); + bool FindStringRemain(char const * const name, std::string & value); + bool GetStringRemain(std::string & value); + unsigned int GetCount(void); + void Shift(unsigned int amount = 1); + Bit16u Get_arglength(); + +private: + typedef std::list::iterator cmd_it; + std::list cmds; + std::string file_name; + bool FindEntry(char const * const name, cmd_it & it, bool neednext = false); +}; + +extern int x86_fpu_enabled; + +#endif diff --git a/dosbox/flags.cpp b/dosbox/flags.cpp new file mode 100644 index 00000000..2e9532f5 --- /dev/null +++ b/dosbox/flags.cpp @@ -0,0 +1,1188 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + Lazy flag system was designed after the same kind of system used in Bochs. + Probably still some bugs left in here. +*/ + +#include "dosbox.h" +#include "cpu.h" +#include "lazyflags.h" +#include "pic.h" + +LazyFlags lflags; + +/* CF Carry Flag -- Set on high-order bit carry or borrow; cleared + otherwise. +*/ +Bit32u get_CF(void) { + + switch (lflags.type) { + case t_UNKNOWN: + case t_INCb: + case t_INCw: + case t_INCd: + case t_DECb: + case t_DECw: + case t_DECd: + case t_MUL: + return GETFLAG(CF); + case t_ADDb: + return (lf_resb8) return false; + else return (lf_var1b >> (8-lf_var2b)) & 1; + case t_SHLw: + if (lf_var2b>16) return false; + else return (lf_var1w >> (16-lf_var2b)) & 1; + case t_SHLd: + case t_DSHLw: /* Hmm this is not correct for shift higher than 16 */ + case t_DSHLd: + return (lf_var1d >> (32 - lf_var2b)) & 1; + case t_RCRb: + case t_SHRb: + return (lf_var1b >> (lf_var2b - 1)) & 1; + case t_RCRw: + case t_SHRw: + return (lf_var1w >> (lf_var2b - 1)) & 1; + case t_RCRd: + case t_SHRd: + case t_DSHRw: /* Hmm this is not correct for shift higher than 16 */ + case t_DSHRd: + return (lf_var1d >> (lf_var2b - 1)) & 1; + case t_SARb: + return (((Bit8s) lf_var1b) >> (lf_var2b - 1)) & 1; + case t_SARw: + return (((Bit16s) lf_var1w) >> (lf_var2b - 1)) & 1; + case t_SARd: + return (((Bit32s) lf_var1d) >> (lf_var2b - 1)) & 1; + case t_NEGb: + return lf_var1b; + case t_NEGw: + return lf_var1w; + case t_NEGd: + return lf_var1d; + case t_ORb: + case t_ORw: + case t_ORd: + case t_ANDb: + case t_ANDw: + case t_ANDd: + case t_XORb: + case t_XORw: + case t_XORd: + case t_TESTb: + case t_TESTw: + case t_TESTd: + return false; /* Set to false */ + case t_DIV: + return false; /* Unkown */ + default: + LOG(LOG_CPU,LOG_ERROR)("get_CF Unknown %d",lflags.type); + } + return 0; +} + +/* AF Adjust flag -- Set on carry from or borrow to the low order + four bits of AL; cleared otherwise. Used for decimal + arithmetic. +*/ +Bit32u get_AF(void) { + Bitu type=lflags.type; + switch (type) { + case t_UNKNOWN: + return GETFLAG(AF); + case t_ADDb: + case t_ADCb: + case t_SBBb: + case t_SUBb: + case t_CMPb: + return ((lf_var1b ^ lf_var2b) ^ lf_resb) & 0x10; + case t_ADDw: + case t_ADCw: + case t_SBBw: + case t_SUBw: + case t_CMPw: + return ((lf_var1w ^ lf_var2w) ^ lf_resw) & 0x10; + case t_ADCd: + case t_ADDd: + case t_SBBd: + case t_SUBd: + case t_CMPd: + return ((lf_var1d ^ lf_var2d) ^ lf_resd) & 0x10; + case t_INCb: + return (lf_resb & 0x0f) == 0; + case t_INCw: + return (lf_resw & 0x0f) == 0; + case t_INCd: + return (lf_resd & 0x0f) == 0; + case t_DECb: + return (lf_resb & 0x0f) == 0x0f; + case t_DECw: + return (lf_resw & 0x0f) == 0x0f; + case t_DECd: + return (lf_resd & 0x0f) == 0x0f; + case t_NEGb: + return lf_var1b & 0x0f; + case t_NEGw: + return lf_var1w & 0x0f; + case t_NEGd: + return lf_var1d & 0x0f; + case t_SHLb: + case t_SHRb: + case t_SARb: + return lf_var2b & 0x1f; + case t_SHLw: + case t_SHRw: + case t_SARw: + return lf_var2w & 0x1f; + case t_SHLd: + case t_SHRd: + case t_SARd: + return lf_var2d & 0x1f; + case t_ORb: + case t_ORw: + case t_ORd: + case t_ANDb: + case t_ANDw: + case t_ANDd: + case t_XORb: + case t_XORw: + case t_XORd: + case t_TESTb: + case t_TESTw: + case t_TESTd: + case t_DSHLw: + case t_DSHLd: + case t_DSHRw: + case t_DSHRd: + case t_DIV: + case t_MUL: + return false; /* Unkown */ + default: + LOG(LOG_CPU,LOG_ERROR)("get_AF Unknown %d",lflags.type); + } + return 0; +} + +/* ZF Zero Flag -- Set if result is zero; cleared otherwise. +*/ + +Bit32u get_ZF(void) { + Bitu type=lflags.type; + switch (type) { + case t_UNKNOWN: + return GETFLAG(ZF); + case t_ADDb: + case t_ORb: + case t_ADCb: + case t_SBBb: + case t_ANDb: + case t_XORb: + case t_SUBb: + case t_CMPb: + case t_INCb: + case t_DECb: + case t_TESTb: + case t_SHLb: + case t_SHRb: + case t_SARb: + case t_NEGb: + return (lf_resb==0); + case t_ADDw: + case t_ORw: + case t_ADCw: + case t_SBBw: + case t_ANDw: + case t_XORw: + case t_SUBw: + case t_CMPw: + case t_INCw: + case t_DECw: + case t_TESTw: + case t_SHLw: + case t_SHRw: + case t_SARw: + case t_DSHLw: + case t_DSHRw: + case t_NEGw: + return (lf_resw==0); + case t_ADDd: + case t_ORd: + case t_ADCd: + case t_SBBd: + case t_ANDd: + case t_XORd: + case t_SUBd: + case t_CMPd: + case t_INCd: + case t_DECd: + case t_TESTd: + case t_SHLd: + case t_SHRd: + case t_SARd: + case t_DSHLd: + case t_DSHRd: + case t_NEGd: + return (lf_resd==0); + case t_DIV: + case t_MUL: + return false; /* Unkown */ + default: + LOG(LOG_CPU,LOG_ERROR)("get_ZF Unknown %d",lflags.type); + } + return false; +} +/* SF Sign Flag -- Set equal to high-order bit of result (0 is + positive, 1 if negative). +*/ +Bit32u get_SF(void) { + Bitu type=lflags.type; + switch (type) { + case t_UNKNOWN: + return GETFLAG(SF); + case t_ADDb: + case t_ORb: + case t_ADCb: + case t_SBBb: + case t_ANDb: + case t_XORb: + case t_SUBb: + case t_CMPb: + case t_INCb: + case t_DECb: + case t_TESTb: + case t_SHLb: + case t_SHRb: + case t_SARb: + case t_NEGb: + return (lf_resb&0x80); + case t_ADDw: + case t_ORw: + case t_ADCw: + case t_SBBw: + case t_ANDw: + case t_XORw: + case t_SUBw: + case t_CMPw: + case t_INCw: + case t_DECw: + case t_TESTw: + case t_SHLw: + case t_SHRw: + case t_SARw: + case t_DSHLw: + case t_DSHRw: + case t_NEGw: + return (lf_resw&0x8000); + case t_ADDd: + case t_ORd: + case t_ADCd: + case t_SBBd: + case t_ANDd: + case t_XORd: + case t_SUBd: + case t_CMPd: + case t_INCd: + case t_DECd: + case t_TESTd: + case t_SHLd: + case t_SHRd: + case t_SARd: + case t_DSHLd: + case t_DSHRd: + case t_NEGd: + return (lf_resd&0x80000000); + case t_DIV: + case t_MUL: + return false; /* Unkown */ + default: + LOG(LOG_CPU,LOG_ERROR)("get_SF Unkown %d",lflags.type); + } + return false; + +} +Bit32u get_OF(void) { + Bitu type=lflags.type; + switch (type) { + case t_UNKNOWN: + case t_MUL: + return GETFLAG(OF); + case t_ADDb: + case t_ADCb: + return ((lf_var1b ^ lf_var2b ^ 0x80) & (lf_resb ^ lf_var2b)) & 0x80; + case t_ADDw: + case t_ADCw: + return ((lf_var1w ^ lf_var2w ^ 0x8000) & (lf_resw ^ lf_var2w)) & 0x8000; + case t_ADDd: + case t_ADCd: + return ((lf_var1d ^ lf_var2d ^ 0x80000000) & (lf_resd ^ lf_var2d)) & 0x80000000; + case t_SBBb: + case t_SUBb: + case t_CMPb: + return ((lf_var1b ^ lf_var2b) & (lf_var1b ^ lf_resb)) & 0x80; + case t_SBBw: + case t_SUBw: + case t_CMPw: + return ((lf_var1w ^ lf_var2w) & (lf_var1w ^ lf_resw)) & 0x8000; + case t_SBBd: + case t_SUBd: + case t_CMPd: + return ((lf_var1d ^ lf_var2d) & (lf_var1d ^ lf_resd)) & 0x80000000; + case t_INCb: + return (lf_resb == 0x80); + case t_INCw: + return (lf_resw == 0x8000); + case t_INCd: + return (lf_resd == 0x80000000); + case t_DECb: + return (lf_resb == 0x7f); + case t_DECw: + return (lf_resw == 0x7fff); + case t_DECd: + return (lf_resd == 0x7fffffff); + case t_NEGb: + return (lf_var1b == 0x80); + case t_NEGw: + return (lf_var1w == 0x8000); + case t_NEGd: + return (lf_var1d == 0x80000000); + case t_SHLb: + return (lf_resb ^ lf_var1b) & 0x80; + case t_SHLw: + case t_DSHRw: + case t_DSHLw: + return (lf_resw ^ lf_var1w) & 0x8000; + case t_SHLd: + case t_DSHRd: + case t_DSHLd: + return (lf_resd ^ lf_var1d) & 0x80000000; + case t_SHRb: + if ((lf_var2b&0x1f)==1) return (lf_var1b > 0x80); + else return false; + case t_SHRw: + if ((lf_var2b&0x1f)==1) return (lf_var1w > 0x8000); + else return false; + case t_SHRd: + if ((lf_var2b&0x1f)==1) return (lf_var1d > 0x80000000); + else return false; + case t_ORb: + case t_ORw: + case t_ORd: + case t_ANDb: + case t_ANDw: + case t_ANDd: + case t_XORb: + case t_XORw: + case t_XORd: + case t_TESTb: + case t_TESTw: + case t_TESTd: + case t_SARb: + case t_SARw: + case t_SARd: + return false; /* Return false */ + case t_DIV: + return false; /* Unkown */ + default: + LOG(LOG_CPU,LOG_ERROR)("get_OF Unkown %d",lflags.type); + } + return false; +} + +Bit16u parity_lookup[256] = { + FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, + 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, + 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, + FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, + 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, + FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, + FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, + 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, + 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, + FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, + FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, + 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, + FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, + 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, + 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, + FLAG_PF, 0, 0, FLAG_PF, 0, FLAG_PF, FLAG_PF, 0, 0, FLAG_PF, FLAG_PF, 0, FLAG_PF, 0, 0, FLAG_PF + }; + +Bit32u get_PF(void) { + switch (lflags.type) { + case t_UNKNOWN: + return GETFLAG(PF); + default: + return (parity_lookup[lf_resb]); + }; + return 0; +} + + +#if 0 + +Bitu FillFlags(void) { +// if (lflags.type==t_UNKNOWN) return reg_flags; + Bitu new_word=(reg_flags & ~FLAG_MASK); + if (get_CF()) new_word|=FLAG_CF; + if (get_PF()) new_word|=FLAG_PF; + if (get_AF()) new_word|=FLAG_AF; + if (get_ZF()) new_word|=FLAG_ZF; + if (get_SF()) new_word|=FLAG_SF; + if (get_OF()) new_word|=FLAG_OF; + reg_flags=new_word; + lflags.type=t_UNKNOWN; + return reg_flags; +} + +#else + +#define DOFLAG_PF reg_flags=(reg_flags & ~FLAG_PF) | parity_lookup[lf_resb]; + +#define DOFLAG_AF reg_flags=(reg_flags & ~FLAG_AF) | (((lf_var1b ^ lf_var2b) ^ lf_resb) & 0x10); + +#define DOFLAG_ZFb SETFLAGBIT(ZF,lf_resb==0); +#define DOFLAG_ZFw SETFLAGBIT(ZF,lf_resw==0); +#define DOFLAG_ZFd SETFLAGBIT(ZF,lf_resd==0); + +#define DOFLAG_SFb reg_flags=(reg_flags & ~FLAG_SF) | ((lf_resb & 0x80) >> 0); +#define DOFLAG_SFw reg_flags=(reg_flags & ~FLAG_SF) | ((lf_resw & 0x8000) >> 8); +#define DOFLAG_SFd reg_flags=(reg_flags & ~FLAG_SF) | ((lf_resd & 0x80000000) >> 24); + +#define SETCF(NEWBIT) reg_flags=(reg_flags & ~FLAG_CF)|(NEWBIT); + +#define SET_FLAG SETFLAGBIT + +Bitu FillFlags(void) { + switch (lflags.type) { + case t_UNKNOWN: + break; + case t_ADDb: + SET_FLAG(CF,(lf_resb8) SET_FLAG(CF,false); + else SET_FLAG(CF,(lf_var1b >> (8-lf_var2b)) & 1); + DOFLAG_ZFb; + DOFLAG_SFb; + SET_FLAG(OF,(lf_resb ^ lf_var1b) & 0x80); + DOFLAG_PF; + SET_FLAG(AF,(lf_var2b&0x1f)); + break; + case t_SHLw: + if (lf_var2b>16) SET_FLAG(CF,false); + else SET_FLAG(CF,(lf_var1w >> (16-lf_var2b)) & 1); + DOFLAG_ZFw; + DOFLAG_SFw; + SET_FLAG(OF,(lf_resw ^ lf_var1w) & 0x8000); + DOFLAG_PF; + SET_FLAG(AF,(lf_var2w&0x1f)); + break; + case t_SHLd: + SET_FLAG(CF,(lf_var1d >> (32 - lf_var2b)) & 1); + DOFLAG_ZFd; + DOFLAG_SFd; + SET_FLAG(OF,(lf_resd ^ lf_var1d) & 0x80000000); + DOFLAG_PF; + SET_FLAG(AF,(lf_var2d&0x1f)); + break; + + + case t_DSHLw: + SET_FLAG(CF,(lf_var1d >> (32 - lf_var2b)) & 1); + DOFLAG_ZFw; + DOFLAG_SFw; + SET_FLAG(OF,(lf_resw ^ lf_var1w) & 0x8000); + DOFLAG_PF; + break; + case t_DSHLd: + SET_FLAG(CF,(lf_var1d >> (32 - lf_var2b)) & 1); + DOFLAG_ZFd; + DOFLAG_SFd; + SET_FLAG(OF,(lf_resd ^ lf_var1d) & 0x80000000); + DOFLAG_PF; + break; + + + case t_SHRb: + SET_FLAG(CF,(lf_var1b >> (lf_var2b - 1)) & 1); + DOFLAG_ZFb; + DOFLAG_SFb; + if ((lf_var2b&0x1f)==1) SET_FLAG(OF,(lf_var1b >= 0x80)); + else SET_FLAG(OF,false); + DOFLAG_PF; + SET_FLAG(AF,(lf_var2b&0x1f)); + break; + case t_SHRw: + SET_FLAG(CF,(lf_var1w >> (lf_var2b - 1)) & 1); + DOFLAG_ZFw; + DOFLAG_SFw; + if ((lf_var2w&0x1f)==1) SET_FLAG(OF,(lf_var1w >= 0x8000)); + else SET_FLAG(OF,false); + DOFLAG_PF; + SET_FLAG(AF,(lf_var2w&0x1f)); + break; + case t_SHRd: + SET_FLAG(CF,(lf_var1d >> (lf_var2b - 1)) & 1); + DOFLAG_ZFd; + DOFLAG_SFd; + if ((lf_var2d&0x1f)==1) SET_FLAG(OF,(lf_var1d >= 0x80000000)); + else SET_FLAG(OF,false); + DOFLAG_PF; + SET_FLAG(AF,(lf_var2d&0x1f)); + break; + + + case t_DSHRw: /* Hmm this is not correct for shift higher than 16 */ + SET_FLAG(CF,(lf_var1d >> (lf_var2b - 1)) & 1); + DOFLAG_ZFw; + DOFLAG_SFw; + SET_FLAG(OF,(lf_resw ^ lf_var1w) & 0x8000); + DOFLAG_PF; + break; + case t_DSHRd: + SET_FLAG(CF,(lf_var1d >> (lf_var2b - 1)) & 1); + DOFLAG_ZFd; + DOFLAG_SFd; + SET_FLAG(OF,(lf_resd ^ lf_var1d) & 0x80000000); + DOFLAG_PF; + break; + + + case t_SARb: + SET_FLAG(CF,(((Bit8s) lf_var1b) >> (lf_var2b - 1)) & 1); + DOFLAG_ZFb; + DOFLAG_SFb; + SET_FLAG(OF,false); + DOFLAG_PF; + SET_FLAG(AF,(lf_var2b&0x1f)); + break; + case t_SARw: + SET_FLAG(CF,(((Bit16s) lf_var1w) >> (lf_var2b - 1)) & 1); + DOFLAG_ZFw; + DOFLAG_SFw; + SET_FLAG(OF,false); + DOFLAG_PF; + SET_FLAG(AF,(lf_var2w&0x1f)); + break; + case t_SARd: + SET_FLAG(CF,(((Bit32s) lf_var1d) >> (lf_var2b - 1)) & 1); + DOFLAG_ZFd; + DOFLAG_SFd; + SET_FLAG(OF,false); + DOFLAG_PF; + SET_FLAG(AF,(lf_var2d&0x1f)); + break; + + case t_INCb: + SET_FLAG(AF,(lf_resb & 0x0f) == 0); + DOFLAG_ZFb; + DOFLAG_SFb; + SET_FLAG(OF,(lf_resb == 0x80)); + DOFLAG_PF; + break; + case t_INCw: + SET_FLAG(AF,(lf_resw & 0x0f) == 0); + DOFLAG_ZFw; + DOFLAG_SFw; + SET_FLAG(OF,(lf_resw == 0x8000)); + DOFLAG_PF; + break; + case t_INCd: + SET_FLAG(AF,(lf_resd & 0x0f) == 0); + DOFLAG_ZFd; + DOFLAG_SFd; + SET_FLAG(OF,(lf_resd == 0x80000000)); + DOFLAG_PF; + break; + + case t_DECb: + SET_FLAG(AF,(lf_resb & 0x0f) == 0x0f); + DOFLAG_ZFb; + DOFLAG_SFb; + SET_FLAG(OF,(lf_resb == 0x7f)); + DOFLAG_PF; + break; + case t_DECw: + SET_FLAG(AF,(lf_resw & 0x0f) == 0x0f); + DOFLAG_ZFw; + DOFLAG_SFw; + SET_FLAG(OF,(lf_resw == 0x7fff)); + DOFLAG_PF; + break; + case t_DECd: + SET_FLAG(AF,(lf_resd & 0x0f) == 0x0f); + DOFLAG_ZFd; + DOFLAG_SFd; + SET_FLAG(OF,(lf_resd == 0x7fffffff)); + DOFLAG_PF; + break; + + case t_NEGb: + SET_FLAG(CF,(lf_var1b!=0)); + SET_FLAG(AF,(lf_resb & 0x0f) != 0); + DOFLAG_ZFb; + DOFLAG_SFb; + SET_FLAG(OF,(lf_var1b == 0x80)); + DOFLAG_PF; + break; + case t_NEGw: + SET_FLAG(CF,(lf_var1w!=0)); + SET_FLAG(AF,(lf_resw & 0x0f) != 0); + DOFLAG_ZFw; + DOFLAG_SFw; + SET_FLAG(OF,(lf_var1w == 0x8000)); + DOFLAG_PF; + break; + case t_NEGd: + SET_FLAG(CF,(lf_var1d!=0)); + SET_FLAG(AF,(lf_resd & 0x0f) != 0); + DOFLAG_ZFd; + DOFLAG_SFd; + SET_FLAG(OF,(lf_var1d == 0x80000000)); + DOFLAG_PF; + break; + + + case t_DIV: + case t_MUL: + break; + + default: + LOG(LOG_CPU,LOG_ERROR)("Unhandled flag type %d",lflags.type); + return 0; + } + lflags.type=t_UNKNOWN; + return reg_flags; +} + +void FillFlagsNoCFOF(void) { + switch (lflags.type) { + case t_UNKNOWN: + return; + case t_ADDb: + DOFLAG_AF; + DOFLAG_ZFb; + DOFLAG_SFb; + DOFLAG_PF; + break; + case t_ADDw: + DOFLAG_AF; + DOFLAG_ZFw; + DOFLAG_SFw; + DOFLAG_PF; + break; + case t_ADDd: + DOFLAG_AF; + DOFLAG_ZFd; + DOFLAG_SFd; + DOFLAG_PF; + break; + case t_ADCb: + DOFLAG_AF; + DOFLAG_ZFb; + DOFLAG_SFb; + DOFLAG_PF; + break; + case t_ADCw: + DOFLAG_AF; + DOFLAG_ZFw; + DOFLAG_SFw; + DOFLAG_PF; + break; + case t_ADCd: + DOFLAG_AF; + DOFLAG_ZFd; + DOFLAG_SFd; + DOFLAG_PF; + break; + + + case t_SBBb: + DOFLAG_AF; + DOFLAG_ZFb; + DOFLAG_SFb; + DOFLAG_PF; + break; + case t_SBBw: + DOFLAG_AF; + DOFLAG_ZFw; + DOFLAG_SFw; + DOFLAG_PF; + break; + case t_SBBd: + DOFLAG_AF; + DOFLAG_ZFd; + DOFLAG_SFd; + DOFLAG_PF; + break; + + + case t_SUBb: + case t_CMPb: + DOFLAG_AF; + DOFLAG_ZFb; + DOFLAG_SFb; + DOFLAG_PF; + break; + case t_SUBw: + case t_CMPw: + DOFLAG_AF; + DOFLAG_ZFw; + DOFLAG_SFw; + DOFLAG_PF; + break; + case t_SUBd: + case t_CMPd: + DOFLAG_AF; + DOFLAG_ZFd; + DOFLAG_SFd; + DOFLAG_PF; + break; + + + case t_ORb: + SET_FLAG(AF,false); + DOFLAG_ZFb; + DOFLAG_SFb; + DOFLAG_PF; + break; + case t_ORw: + SET_FLAG(AF,false); + DOFLAG_ZFw; + DOFLAG_SFw; + DOFLAG_PF; + break; + case t_ORd: + SET_FLAG(AF,false); + DOFLAG_ZFd; + DOFLAG_SFd; + DOFLAG_PF; + break; + + + case t_TESTb: + case t_ANDb: + SET_FLAG(AF,false); + DOFLAG_ZFb; + DOFLAG_SFb; + DOFLAG_PF; + break; + case t_TESTw: + case t_ANDw: + SET_FLAG(AF,false); + DOFLAG_ZFw; + DOFLAG_SFw; + DOFLAG_PF; + break; + case t_TESTd: + case t_ANDd: + SET_FLAG(AF,false); + DOFLAG_ZFd; + DOFLAG_SFd; + DOFLAG_PF; + break; + + + case t_XORb: + SET_FLAG(AF,false); + DOFLAG_ZFb; + DOFLAG_SFb; + DOFLAG_PF; + break; + case t_XORw: + SET_FLAG(AF,false); + DOFLAG_ZFw; + DOFLAG_SFw; + DOFLAG_PF; + break; + case t_XORd: + SET_FLAG(AF,false); + DOFLAG_ZFd; + DOFLAG_SFd; + DOFLAG_PF; + break; + + + case t_SHLb: + DOFLAG_ZFb; + DOFLAG_SFb; + DOFLAG_PF; + SET_FLAG(AF,(lf_var2b&0x1f)); + break; + case t_SHLw: + DOFLAG_ZFw; + DOFLAG_SFw; + DOFLAG_PF; + SET_FLAG(AF,(lf_var2w&0x1f)); + break; + case t_SHLd: + DOFLAG_ZFd; + DOFLAG_SFd; + DOFLAG_PF; + SET_FLAG(AF,(lf_var2d&0x1f)); + break; + + + case t_DSHLw: + DOFLAG_ZFw; + DOFLAG_SFw; + DOFLAG_PF; + break; + case t_DSHLd: + DOFLAG_ZFd; + DOFLAG_SFd; + DOFLAG_PF; + break; + + + case t_SHRb: + DOFLAG_ZFb; + DOFLAG_SFb; + DOFLAG_PF; + SET_FLAG(AF,(lf_var2b&0x1f)); + break; + case t_SHRw: + DOFLAG_ZFw; + DOFLAG_SFw; + DOFLAG_PF; + SET_FLAG(AF,(lf_var2w&0x1f)); + break; + case t_SHRd: + DOFLAG_ZFd; + DOFLAG_SFd; + DOFLAG_PF; + SET_FLAG(AF,(lf_var2d&0x1f)); + break; + + + case t_DSHRw: /* Hmm this is not correct for shift higher than 16 */ + DOFLAG_ZFw; + DOFLAG_SFw; + DOFLAG_PF; + break; + case t_DSHRd: + DOFLAG_ZFd; + DOFLAG_SFd; + DOFLAG_PF; + break; + + + case t_SARb: + DOFLAG_ZFb; + DOFLAG_SFb; + DOFLAG_PF; + SET_FLAG(AF,(lf_var2b&0x1f)); + break; + case t_SARw: + DOFLAG_ZFw; + DOFLAG_SFw; + DOFLAG_PF; + SET_FLAG(AF,(lf_var2w&0x1f)); + break; + case t_SARd: + DOFLAG_ZFd; + DOFLAG_SFd; + DOFLAG_PF; + SET_FLAG(AF,(lf_var2d&0x1f)); + break; + + case t_INCb: + SET_FLAG(AF,(lf_resb & 0x0f) == 0); + DOFLAG_ZFb; + DOFLAG_SFb; + DOFLAG_PF; + break; + case t_INCw: + SET_FLAG(AF,(lf_resw & 0x0f) == 0); + DOFLAG_ZFw; + DOFLAG_SFw; + DOFLAG_PF; + break; + case t_INCd: + SET_FLAG(AF,(lf_resd & 0x0f) == 0); + DOFLAG_ZFd; + DOFLAG_SFd; + DOFLAG_PF; + break; + + case t_DECb: + SET_FLAG(AF,(lf_resb & 0x0f) == 0x0f); + DOFLAG_ZFb; + DOFLAG_SFb; + DOFLAG_PF; + break; + case t_DECw: + SET_FLAG(AF,(lf_resw & 0x0f) == 0x0f); + DOFLAG_ZFw; + DOFLAG_SFw; + DOFLAG_PF; + break; + case t_DECd: + SET_FLAG(AF,(lf_resd & 0x0f) == 0x0f); + DOFLAG_ZFd; + DOFLAG_SFd; + DOFLAG_PF; + break; + + case t_NEGb: + SET_FLAG(AF,(lf_resb & 0x0f) != 0); + DOFLAG_ZFb; + DOFLAG_SFb; + DOFLAG_PF; + break; + case t_NEGw: + SET_FLAG(AF,(lf_resw & 0x0f) != 0); + DOFLAG_ZFw; + DOFLAG_SFw; + DOFLAG_PF; + break; + case t_NEGd: + SET_FLAG(AF,(lf_resd & 0x0f) != 0); + DOFLAG_ZFd; + DOFLAG_SFd; + DOFLAG_PF; + break; + + + case t_DIV: + case t_MUL: + break; + + default: + LOG(LOG_CPU,LOG_ERROR)("Unhandled flag type %d",lflags.type); + break; + } + lflags.type=t_UNKNOWN; +} + +void DestroyConditionFlags(void) { + lflags.type=t_UNKNOWN; +} + +#endif diff --git a/dosbox/fpu.cpp b/dosbox/fpu.cpp new file mode 100644 index 00000000..6a0cc80a --- /dev/null +++ b/dosbox/fpu.cpp @@ -0,0 +1,632 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id: fpu.cpp,v 1.31 2009-09-16 18:01:53 qbix79 Exp $ */ + +#include "dosbox.h" +#if C_FPU + +#include +#include +#include "setup.h" +//#include "cross.h" +#include "mem.h" +#include "fpu.h" +#include "cpu.h" + +FPU_rec fpu; + +void FPU_FLDCW(PhysPt addr){ + Bit16u temp = mem_readw(addr); + FPU_SetCW(temp); +} + +Bit16u FPU_GetTag(void){ + Bit16u tag=0; + for(Bitu i=0;i<8;i++) + tag |= ( (fpu.tags[i]&3) <<(2*i)); + return tag; +} + +#if C_FPU_X86 +#include "fpu_instructions_x86.h" +#else +#include "fpu_instructions.h" +#endif + +/* WATCHIT : ALWAYS UPDATE REGISTERS BEFORE AND AFTER USING THEM + STATUS WORD => FPU_SET_TOP(TOP) BEFORE a read + TOP=FPU_GET_TOP() after a write; + */ + +static void EATREE(Bitu _rm){ + Bitu group=(_rm >> 3) & 7; + switch(group){ + case 0x00: /* FADD */ + FPU_FADD_EA(TOP); + break; + case 0x01: /* FMUL */ + FPU_FMUL_EA(TOP); + break; + case 0x02: /* FCOM */ + FPU_FCOM_EA(TOP); + break; + case 0x03: /* FCOMP */ + FPU_FCOM_EA(TOP); + FPU_FPOP(); + break; + case 0x04: /* FSUB */ + FPU_FSUB_EA(TOP); + break; + case 0x05: /* FSUBR */ + FPU_FSUBR_EA(TOP); + break; + case 0x06: /* FDIV */ + FPU_FDIV_EA(TOP); + break; + case 0x07: /* FDIVR */ + FPU_FDIVR_EA(TOP); + break; + default: + break; + } +} + +void FPU_ESC0_EA(Bitu rm,PhysPt addr) { + /* REGULAR TREE WITH 32 BITS REALS */ + FPU_FLD_F32_EA(addr); + EATREE(rm); +} + +void FPU_ESC0_Normal(Bitu rm) { + Bitu group=(rm >> 3) & 7; + Bitu sub=(rm & 7); + switch (group){ + case 0x00: /* FADD ST,STi */ + FPU_FADD(TOP,STV(sub)); + break; + case 0x01: /* FMUL ST,STi */ + FPU_FMUL(TOP,STV(sub)); + break; + case 0x02: /* FCOM STi */ + FPU_FCOM(TOP,STV(sub)); + break; + case 0x03: /* FCOMP STi */ + FPU_FCOM(TOP,STV(sub)); + FPU_FPOP(); + break; + case 0x04: /* FSUB ST,STi */ + FPU_FSUB(TOP,STV(sub)); + break; + case 0x05: /* FSUBR ST,STi */ + FPU_FSUBR(TOP,STV(sub)); + break; + case 0x06: /* FDIV ST,STi */ + FPU_FDIV(TOP,STV(sub)); + break; + case 0x07: /* FDIVR ST,STi */ + FPU_FDIVR(TOP,STV(sub)); + break; + default: + break; + } +} + +void FPU_ESC1_EA(Bitu rm,PhysPt addr) { +// floats + Bitu group=(rm >> 3) & 7; + Bitu sub=(rm & 7); + switch(group){ + case 0x00: /* FLD float*/ + FPU_PREP_PUSH(); + FPU_FLD_F32(addr,TOP); + break; + case 0x01: /* UNKNOWN */ + LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub); + break; + case 0x02: /* FST float*/ + FPU_FST_F32(addr); + break; + case 0x03: /* FSTP float*/ + FPU_FST_F32(addr); + FPU_FPOP(); + break; + case 0x04: /* FLDENV */ + FPU_FLDENV(addr); + break; + case 0x05: /* FLDCW */ + FPU_FLDCW(addr); + break; + case 0x06: /* FSTENV */ + FPU_FSTENV(addr); + break; + case 0x07: /* FNSTCW*/ + mem_writew(addr,fpu.cw); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub); + break; + } +} + +void FPU_ESC1_Normal(Bitu rm) { + Bitu group=(rm >> 3) & 7; + Bitu sub=(rm & 7); + switch (group){ + case 0x00: /* FLD STi */ + { + Bitu reg_from=STV(sub); + FPU_PREP_PUSH(); + FPU_FST(reg_from, TOP); + break; + } + case 0x01: /* FXCH STi */ + FPU_FXCH(TOP,STV(sub)); + break; + case 0x02: /* FNOP */ + FPU_FNOP(); + break; + case 0x03: /* FSTP STi */ + FPU_FST(TOP,STV(sub)); + FPU_FPOP(); + break; + case 0x04: + switch(sub){ + case 0x00: /* FCHS */ + FPU_FCHS(); + break; + case 0x01: /* FABS */ + FPU_FABS(); + break; + case 0x02: /* UNKNOWN */ + case 0x03: /* ILLEGAL */ + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); + break; + case 0x04: /* FTST */ + FPU_FTST(); + break; + case 0x05: /* FXAM */ + FPU_FXAM(); + break; + case 0x06: /* FTSTP (cyrix)*/ + case 0x07: /* UNKNOWN */ + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); + break; + } + break; + case 0x05: + switch(sub){ + case 0x00: /* FLD1 */ + FPU_FLD1(); + break; + case 0x01: /* FLDL2T */ + FPU_FLDL2T(); + break; + case 0x02: /* FLDL2E */ + FPU_FLDL2E(); + break; + case 0x03: /* FLDPI */ + FPU_FLDPI(); + break; + case 0x04: /* FLDLG2 */ + FPU_FLDLG2(); + break; + case 0x05: /* FLDLN2 */ + FPU_FLDLN2(); + break; + case 0x06: /* FLDZ*/ + FPU_FLDZ(); + break; + case 0x07: /* ILLEGAL */ + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); + break; + } + break; + case 0x06: + switch(sub){ + case 0x00: /* F2XM1 */ + FPU_F2XM1(); + break; + case 0x01: /* FYL2X */ + FPU_FYL2X(); + break; + case 0x02: /* FPTAN */ + FPU_FPTAN(); + break; + case 0x03: /* FPATAN */ + FPU_FPATAN(); + break; + case 0x04: /* FXTRACT */ + FPU_FXTRACT(); + break; + case 0x05: /* FPREM1 */ + FPU_FPREM1(); + break; + case 0x06: /* FDECSTP */ + TOP = (TOP - 1) & 7; + break; + case 0x07: /* FINCSTP */ + TOP = (TOP + 1) & 7; + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); + break; + } + break; + case 0x07: + switch(sub){ + case 0x00: /* FPREM */ + FPU_FPREM(); + break; + case 0x01: /* FYL2XP1 */ + FPU_FYL2XP1(); + break; + case 0x02: /* FSQRT */ + FPU_FSQRT(); + break; + case 0x03: /* FSINCOS */ + FPU_FSINCOS(); + break; + case 0x04: /* FRNDINT */ + FPU_FRNDINT(); + break; + case 0x05: /* FSCALE */ + FPU_FSCALE(); + break; + case 0x06: /* FSIN */ + FPU_FSIN(); + break; + case 0x07: /* FCOS */ + FPU_FCOS(); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); + break; + } + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); + } +} + + +void FPU_ESC2_EA(Bitu rm,PhysPt addr) { + /* 32 bits integer operants */ + FPU_FLD_I32_EA(addr); + EATREE(rm); +} + +void FPU_ESC2_Normal(Bitu rm) { + Bitu group=(rm >> 3) & 7; + Bitu sub=(rm & 7); + switch(group){ + case 0x05: + switch(sub){ + case 0x01: /* FUCOMPP */ + FPU_FUCOM(TOP,STV(1)); + FPU_FPOP(); + FPU_FPOP(); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 2:Unhandled group %d subfunction %d",group,sub); + break; + } + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 2:Unhandled group %d subfunction %d",group,sub); + break; + } +} + + +void FPU_ESC3_EA(Bitu rm,PhysPt addr) { + Bitu group=(rm >> 3) & 7; + Bitu sub=(rm & 7); + switch(group){ + case 0x00: /* FILD */ + FPU_PREP_PUSH(); + FPU_FLD_I32(addr,TOP); + break; + case 0x01: /* FISTTP */ + LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",group,sub); + break; + case 0x02: /* FIST */ + FPU_FST_I32(addr); + break; + case 0x03: /* FISTP */ + FPU_FST_I32(addr); + FPU_FPOP(); + break; + case 0x05: /* FLD 80 Bits Real */ + FPU_PREP_PUSH(); + FPU_FLD_F80(addr); + break; + case 0x07: /* FSTP 80 Bits Real */ + FPU_FST_F80(addr); + FPU_FPOP(); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",group,sub); + } +} + +void FPU_ESC3_Normal(Bitu rm) { + Bitu group=(rm >> 3) & 7; + Bitu sub=(rm & 7); + switch (group) { + case 0x04: + switch (sub) { + case 0x00: //FNENI + case 0x01: //FNDIS + LOG(LOG_FPU,LOG_ERROR)("8087 only fpu code used esc 3: group 4: subfuntion :%d",sub); + break; + case 0x02: //FNCLEX FCLEX + FPU_FCLEX(); + break; + case 0x03: //FNINIT FINIT + FPU_FINIT(); + break; + case 0x04: //FNSETPM + case 0x05: //FRSTPM +// LOG(LOG_FPU,LOG_ERROR)("80267 protected mode (un)set. Nothing done"); + FPU_FNOP(); + break; + default: + E_Exit("ESC 3:ILLEGAL OPCODE group %d subfunction %d",group,sub); + } + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 3:Unhandled group %d subfunction %d",group,sub); + break; + } + return; +} + + +void FPU_ESC4_EA(Bitu rm,PhysPt addr) { + /* REGULAR TREE WITH 64 BITS REALS */ + FPU_FLD_F64_EA(addr); + EATREE(rm); +} + +void FPU_ESC4_Normal(Bitu rm) { + /* LOOKS LIKE number 6 without popping */ + Bitu group=(rm >> 3) & 7; + Bitu sub=(rm & 7); + switch(group){ + case 0x00: /* FADD STi,ST*/ + FPU_FADD(STV(sub),TOP); + break; + case 0x01: /* FMUL STi,ST*/ + FPU_FMUL(STV(sub),TOP); + break; + case 0x02: /* FCOM*/ + FPU_FCOM(TOP,STV(sub)); + break; + case 0x03: /* FCOMP*/ + FPU_FCOM(TOP,STV(sub)); + FPU_FPOP(); + break; + case 0x04: /* FSUBR STi,ST*/ + FPU_FSUBR(STV(sub),TOP); + break; + case 0x05: /* FSUB STi,ST*/ + FPU_FSUB(STV(sub),TOP); + break; + case 0x06: /* FDIVR STi,ST*/ + FPU_FDIVR(STV(sub),TOP); + break; + case 0x07: /* FDIV STi,ST*/ + FPU_FDIV(STV(sub),TOP); + break; + default: + break; + } +} + +void FPU_ESC5_EA(Bitu rm,PhysPt addr) { + Bitu group=(rm >> 3) & 7; + Bitu sub=(rm & 7); + switch(group){ + case 0x00: /* FLD double real*/ + FPU_PREP_PUSH(); + FPU_FLD_F64(addr,TOP); + break; + case 0x01: /* FISTTP longint*/ + LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",group,sub); + break; + case 0x02: /* FST double real*/ + FPU_FST_F64(addr); + break; + case 0x03: /* FSTP double real*/ + FPU_FST_F64(addr); + FPU_FPOP(); + break; + case 0x04: /* FRSTOR */ + FPU_FRSTOR(addr); + break; + case 0x06: /* FSAVE */ + FPU_FSAVE(addr); + break; + case 0x07: /*FNSTSW NG DISAGREES ON THIS*/ + FPU_SET_TOP(TOP); + mem_writew(addr,fpu.sw); + //seems to break all dos4gw games :) + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",group,sub); + } +} + +void FPU_ESC5_Normal(Bitu rm) { + Bitu group=(rm >> 3) & 7; + Bitu sub=(rm & 7); + switch(group){ + case 0x00: /* FFREE STi */ + fpu.tags[STV(sub)]=TAG_Empty; + break; + case 0x01: /* FXCH STi*/ + FPU_FXCH(TOP,STV(sub)); + break; + case 0x02: /* FST STi */ + FPU_FST(TOP,STV(sub)); + break; + case 0x03: /* FSTP STi*/ + FPU_FST(TOP,STV(sub)); + FPU_FPOP(); + break; + case 0x04: /* FUCOM STi */ + FPU_FUCOM(TOP,STV(sub)); + break; + case 0x05: /*FUCOMP STi */ + FPU_FUCOM(TOP,STV(sub)); + FPU_FPOP(); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 5:Unhandled group %d subfunction %d",group,sub); + break; + } +} + +void FPU_ESC6_EA(Bitu rm,PhysPt addr) { + /* 16 bit (word integer) operants */ + FPU_FLD_I16_EA(addr); + EATREE(rm); +} + +void FPU_ESC6_Normal(Bitu rm) { + /* all P variants working only on registers */ + /* get top before switch and pop afterwards */ + Bitu group=(rm >> 3) & 7; + Bitu sub=(rm & 7); + switch(group){ + case 0x00: /*FADDP STi,ST*/ + FPU_FADD(STV(sub),TOP); + break; + case 0x01: /* FMULP STi,ST*/ + FPU_FMUL(STV(sub),TOP); + break; + case 0x02: /* FCOMP5*/ + FPU_FCOM(TOP,STV(sub)); + break; /* TODO IS THIS ALLRIGHT ????????? */ + case 0x03: /*FCOMPP*/ + if(sub != 1) { + LOG(LOG_FPU,LOG_WARN)("ESC 6:Unhandled group %d subfunction %d",group,sub); + return; + } + FPU_FCOM(TOP,STV(1)); + FPU_FPOP(); /* extra pop at the bottom*/ + break; + case 0x04: /* FSUBRP STi,ST*/ + FPU_FSUBR(STV(sub),TOP); + break; + case 0x05: /* FSUBP STi,ST*/ + FPU_FSUB(STV(sub),TOP); + break; + case 0x06: /* FDIVRP STi,ST*/ + FPU_FDIVR(STV(sub),TOP); + break; + case 0x07: /* FDIVP STi,ST*/ + FPU_FDIV(STV(sub),TOP); + break; + default: + break; + } + FPU_FPOP(); +} + + +void FPU_ESC7_EA(Bitu rm,PhysPt addr) { + Bitu group=(rm >> 3) & 7; + Bitu sub=(rm & 7); + switch(group){ + case 0x00: /* FILD Bit16s */ + FPU_PREP_PUSH(); + FPU_FLD_I16(addr,TOP); + break; + case 0x01: + LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",group,sub); + break; + case 0x02: /* FIST Bit16s */ + FPU_FST_I16(addr); + break; + case 0x03: /* FISTP Bit16s */ + FPU_FST_I16(addr); + FPU_FPOP(); + break; + case 0x04: /* FBLD packed BCD */ + FPU_PREP_PUSH(); + FPU_FBLD(addr,TOP); + break; + case 0x05: /* FILD Bit64s */ + FPU_PREP_PUSH(); + FPU_FLD_I64(addr,TOP); + break; + case 0x06: /* FBSTP packed BCD */ + FPU_FBST(addr); + FPU_FPOP(); + break; + case 0x07: /* FISTP Bit64s */ + FPU_FST_I64(addr); + FPU_FPOP(); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",group,sub); + break; + } +} + +void FPU_ESC7_Normal(Bitu rm) { + Bitu group=(rm >> 3) & 7; + Bitu sub=(rm & 7); + switch (group){ + case 0x00: /* FFREEP STi*/ + fpu.tags[STV(sub)]=TAG_Empty; + FPU_FPOP(); + break; + case 0x01: /* FXCH STi*/ + FPU_FXCH(TOP,STV(sub)); + break; + case 0x02: /* FSTP STi*/ + case 0x03: /* FSTP STi*/ + FPU_FST(TOP,STV(sub)); + FPU_FPOP(); + break; + case 0x04: + switch(sub){ + case 0x00: /* FNSTSW AX*/ + FPU_SET_TOP(TOP); + reg_ax = fpu.sw; + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub); + break; + } + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub); + break; + } +} + + +void FPU_Init(Section*) { + FPU_FINIT(); +} + +#endif diff --git a/dosbox/fpu.h b/dosbox/fpu.h new file mode 100644 index 00000000..67f7db41 --- /dev/null +++ b/dosbox/fpu.h @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef DOSBOX_FPU_H +#define DOSBOX_FPU_H + +#ifndef DOSBOX_MEM_H +#include "mem.h" +#endif + +void FPU_ESC0_Normal(Bitu rm); +void FPU_ESC0_EA(Bitu func,PhysPt ea); +void FPU_ESC1_Normal(Bitu rm); +void FPU_ESC1_EA(Bitu func,PhysPt ea); +void FPU_ESC2_Normal(Bitu rm); +void FPU_ESC2_EA(Bitu func,PhysPt ea); +void FPU_ESC3_Normal(Bitu rm); +void FPU_ESC3_EA(Bitu func,PhysPt ea); +void FPU_ESC4_Normal(Bitu rm); +void FPU_ESC4_EA(Bitu func,PhysPt ea); +void FPU_ESC5_Normal(Bitu rm); +void FPU_ESC5_EA(Bitu func,PhysPt ea); +void FPU_ESC6_Normal(Bitu rm); +void FPU_ESC6_EA(Bitu func,PhysPt ea); +void FPU_ESC7_Normal(Bitu rm); +void FPU_ESC7_EA(Bitu func,PhysPt ea); + + +typedef union { + double d; +#ifndef WORDS_BIGENDIAN + struct { + Bit32u lower; + Bit32s upper; + } l; +#else + struct { + Bit32s upper; + Bit32u lower; + } l; +#endif + Bit64s ll; +} FPU_Reg; + +typedef struct { + Bit32u m1; + Bit32u m2; + Bit16u m3; + + Bit16u d1; + Bit32u d2; +} FPU_P_Reg; + +enum FPU_Tag { + TAG_Valid = 0, + TAG_Zero = 1, + TAG_Weird = 2, + TAG_Empty = 3 +}; + +enum FPU_Round { + ROUND_Nearest = 0, + ROUND_Down = 1, + ROUND_Up = 2, + ROUND_Chop = 3 +}; + +typedef struct { + FPU_Reg regs[9]; + FPU_P_Reg p_regs[9]; + FPU_Tag tags[9]; + Bit16u cw,cw_mask_all; + Bit16u sw; + Bitu top; + FPU_Round round; +} FPU_rec; + + +//get pi from a real library +#define PI 3.14159265358979323846 +#define L2E 1.4426950408889634 +#define L2T 3.3219280948873623 +#define LN2 0.69314718055994531 +#define LG2 0.3010299956639812 + + +extern FPU_rec fpu; + +#define TOP fpu.top +#define STV(i) ( (fpu.top+ (i) ) & 7 ) + + +Bit16u FPU_GetTag(void); +void FPU_FLDCW(PhysPt addr); + +static INLINE void FPU_SetTag(Bit16u tag){ + for(Bitu i=0;i<8;i++) + fpu.tags[i] = static_cast((tag >>(2*i))&3); +} + +static INLINE void FPU_SetCW(Bitu word){ + fpu.cw = (Bit16u)word; + fpu.cw_mask_all = (Bit16u)(word | 0x3f); + fpu.round = (FPU_Round)((word >> 10) & 3); +} + + +static INLINE Bitu FPU_GET_TOP(void) { + return (fpu.sw & 0x3800)>>11; +} + +static INLINE void FPU_SET_TOP(Bitu val){ + fpu.sw &= ~0x3800; + fpu.sw |= (val&7)<<11; +} + + +static INLINE void FPU_SET_C0(Bitu C){ + fpu.sw &= ~0x0100; + if(C) fpu.sw |= 0x0100; +} + +static INLINE void FPU_SET_C1(Bitu C){ + fpu.sw &= ~0x0200; + if(C) fpu.sw |= 0x0200; +} + +static INLINE void FPU_SET_C2(Bitu C){ + fpu.sw &= ~0x0400; + if(C) fpu.sw |= 0x0400; +} + +static INLINE void FPU_SET_C3(Bitu C){ + fpu.sw &= ~0x4000; + if(C) fpu.sw |= 0x4000; +} + + +#endif diff --git a/dosbox/fpu_instructions.h b/dosbox/fpu_instructions.h new file mode 100644 index 00000000..9a505a2b --- /dev/null +++ b/dosbox/fpu_instructions.h @@ -0,0 +1,600 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id: fpu_instructions.h,v 1.33 2009-05-27 09:15:41 qbix79 Exp $ */ + + +static void FPU_FINIT(void) { + FPU_SetCW(0x37F); + fpu.sw = 0; + TOP=FPU_GET_TOP(); + fpu.tags[0] = TAG_Empty; + fpu.tags[1] = TAG_Empty; + fpu.tags[2] = TAG_Empty; + fpu.tags[3] = TAG_Empty; + fpu.tags[4] = TAG_Empty; + fpu.tags[5] = TAG_Empty; + fpu.tags[6] = TAG_Empty; + fpu.tags[7] = TAG_Empty; + fpu.tags[8] = TAG_Valid; // is only used by us +} + +static void FPU_FCLEX(void){ + fpu.sw &= 0x7f00; //should clear exceptions +} + +static void FPU_FNOP(void){ + return; +} + +static void FPU_PUSH(double in){ + TOP = (TOP - 1) &7; + //actually check if empty + fpu.tags[TOP] = TAG_Valid; + fpu.regs[TOP].d = in; +// LOG(LOG_FPU,LOG_ERROR)("Pushed at %d %g to the stack",newtop,in); + return; +} + +static void FPU_PREP_PUSH(void){ + TOP = (TOP - 1) &7; + fpu.tags[TOP] = TAG_Valid; +} + +static void FPU_FPOP(void){ + fpu.tags[TOP]=TAG_Empty; + //maybe set zero in it as well + TOP = ((TOP+1)&7); +// LOG(LOG_FPU,LOG_ERROR)("popped from %d %g off the stack",top,fpu.regs[top].d); + return; +} + +static double FROUND(double in){ + switch(fpu.round){ + case ROUND_Nearest: + if (in-floor(in)>0.5) return (floor(in)+1); + else if (in-floor(in)<0.5) return (floor(in)); + else return (((static_cast(floor(in)))&1)!=0)?(floor(in)+1):(floor(in)); + break; + case ROUND_Down: + return (floor(in)); + break; + case ROUND_Up: + return (ceil(in)); + break; + case ROUND_Chop: + return in; //the cast afterwards will do it right maybe cast here + break; + default: + return in; + break; + } +} + +#define BIAS80 16383 +#define BIAS64 1023 + +static Real64 FPU_FLD80(PhysPt addr) { + struct { + Bit16s begin; + FPU_Reg eind; + } test; + test.eind.l.lower = mem_readd(addr); + test.eind.l.upper = mem_readd(addr+4); + test.begin = mem_readw(addr+8); + + Bit64s exp64 = (((test.begin&0x7fff) - BIAS80)); + Bit64s blah = ((exp64 >0)?exp64:-exp64)&0x3ff; + Bit64s exp64final = ((exp64 >0)?blah:-blah) +BIAS64; + + Bit64s mant64 = (test.eind.ll >> 11) & LONGTYPE(0xfffffffffffff); + Bit64s sign = (test.begin&0x8000)?1:0; + FPU_Reg result; + result.ll = (sign <<63)|(exp64final << 52)| mant64; + return result.d; + + //mant64= test.mant80/2***64 * 2 **53 +} + +static void FPU_ST80(PhysPt addr,Bitu reg) { + struct { + Bit16s begin; + FPU_Reg eind; + } test; + Bit64s sign80 = (fpu.regs[reg].ll&LONGTYPE(0x8000000000000000))?1:0; + Bit64s exp80 = fpu.regs[reg].ll&LONGTYPE(0x7ff0000000000000); + Bit64s exp80final = (exp80>>52); + Bit64s mant80 = fpu.regs[reg].ll&LONGTYPE(0x000fffffffffffff); + Bit64s mant80final = (mant80 << 11); + if(fpu.regs[reg].d != 0){ //Zero is a special case + // Elvira wants the 8 and tcalc doesn't + mant80final |= LONGTYPE(0x8000000000000000); + //Ca-cyber doesn't like this when result is zero. + exp80final += (BIAS80 - BIAS64); + } + test.begin = (static_cast(sign80)<<15)| static_cast(exp80final); + test.eind.ll = mant80final; + mem_writed(addr,test.eind.l.lower); + mem_writed(addr+4,test.eind.l.upper); + mem_writew(addr+8,test.begin); +} + + +static void FPU_FLD_F32(PhysPt addr,Bitu store_to) { + union { + float f; + Bit32u l; + } blah; + blah.l = mem_readd(addr); + fpu.regs[store_to].d = static_cast(blah.f); +} + +static void FPU_FLD_F64(PhysPt addr,Bitu store_to) { + fpu.regs[store_to].l.lower = mem_readd(addr); + fpu.regs[store_to].l.upper = mem_readd(addr+4); +} + +static void FPU_FLD_F80(PhysPt addr) { + fpu.regs[TOP].d = FPU_FLD80(addr); +} + +static void FPU_FLD_I16(PhysPt addr,Bitu store_to) { + Bit16s blah = mem_readw(addr); + fpu.regs[store_to].d = static_cast(blah); +} + +static void FPU_FLD_I32(PhysPt addr,Bitu store_to) { + Bit32s blah = mem_readd(addr); + fpu.regs[store_to].d = static_cast(blah); +} + +static void FPU_FLD_I64(PhysPt addr,Bitu store_to) { + FPU_Reg blah; + blah.l.lower = mem_readd(addr); + blah.l.upper = mem_readd(addr+4); + fpu.regs[store_to].d = static_cast(blah.ll); +} + +static void FPU_FBLD(PhysPt addr,Bitu store_to) { + Bit64u val = 0; + Bitu in = 0; + Bit64u base = 1; + for(Bitu i = 0;i < 9;i++){ + in = mem_readb(addr + i); + val += ( (in&0xf) * base); //in&0xf shouldn't be higher then 9 + base *= 10; + val += ((( in>>4)&0xf) * base); + base *= 10; + } + + //last number, only now convert to float in order to get + //the best signification + Real64 temp = static_cast(val); + in = mem_readb(addr + 9); + temp += ( (in&0xf) * base ); + if(in&0x80) temp *= -1.0; + fpu.regs[store_to].d = temp; +} + + +static INLINE void FPU_FLD_F32_EA(PhysPt addr) { + FPU_FLD_F32(addr,8); +} +static INLINE void FPU_FLD_F64_EA(PhysPt addr) { + FPU_FLD_F64(addr,8); +} +static INLINE void FPU_FLD_I32_EA(PhysPt addr) { + FPU_FLD_I32(addr,8); +} +static INLINE void FPU_FLD_I16_EA(PhysPt addr) { + FPU_FLD_I16(addr,8); +} + + +static void FPU_FST_F32(PhysPt addr) { + union { + float f; + Bit32u l; + } blah; + //should depend on rounding method + blah.f = static_cast(fpu.regs[TOP].d); + mem_writed(addr,blah.l); +} + +static void FPU_FST_F64(PhysPt addr) { + mem_writed(addr,fpu.regs[TOP].l.lower); + mem_writed(addr+4,fpu.regs[TOP].l.upper); +} + +static void FPU_FST_F80(PhysPt addr) { + FPU_ST80(addr,TOP); +} + +static void FPU_FST_I16(PhysPt addr) { + mem_writew(addr,static_cast(FROUND(fpu.regs[TOP].d))); +} + +static void FPU_FST_I32(PhysPt addr) { + mem_writed(addr,static_cast(FROUND(fpu.regs[TOP].d))); +} + +static void FPU_FST_I64(PhysPt addr) { + FPU_Reg blah; + blah.ll = static_cast(FROUND(fpu.regs[TOP].d)); + mem_writed(addr,blah.l.lower); + mem_writed(addr+4,blah.l.upper); +} + +static void FPU_FBST(PhysPt addr) { + FPU_Reg val = fpu.regs[TOP]; + bool sign = false; + if(fpu.regs[TOP].ll & LONGTYPE(0x8000000000000000)) { //sign + sign=true; + val.d=-val.d; + } + //numbers from back to front + Real64 temp=val.d; + Bitu p; + for(Bitu i=0;i<9;i++){ + val.d=temp; + temp = static_cast(static_cast(floor(val.d/10.0))); + p = static_cast(val.d - 10.0*temp); + val.d=temp; + temp = static_cast(static_cast(floor(val.d/10.0))); + p |= (static_cast(val.d - 10.0*temp)<<4); + + mem_writeb(addr+i,p); + } + val.d=temp; + temp = static_cast(static_cast(floor(val.d/10.0))); + p = static_cast(val.d - 10.0*temp); + if(sign) + p|=0x80; + mem_writeb(addr+9,p); +} + +static void FPU_FADD(Bitu op1, Bitu op2){ + fpu.regs[op1].d+=fpu.regs[op2].d; + //flags and such :) + return; +} + +static void FPU_FSIN(void){ + fpu.regs[TOP].d = sin(fpu.regs[TOP].d); + FPU_SET_C2(0); + //flags and such :) + return; +} + +static void FPU_FSINCOS(void){ + Real64 temp = fpu.regs[TOP].d; + fpu.regs[TOP].d = sin(temp); + FPU_PUSH(cos(temp)); + FPU_SET_C2(0); + //flags and such :) + return; +} + +static void FPU_FCOS(void){ + fpu.regs[TOP].d = cos(fpu.regs[TOP].d); + FPU_SET_C2(0); + //flags and such :) + return; +} + +static void FPU_FSQRT(void){ + fpu.regs[TOP].d = sqrt(fpu.regs[TOP].d); + //flags and such :) + return; +} +static void FPU_FPATAN(void){ + fpu.regs[STV(1)].d = atan2(fpu.regs[STV(1)].d,fpu.regs[TOP].d); + FPU_FPOP(); + //flags and such :) + return; +} +static void FPU_FPTAN(void){ + fpu.regs[TOP].d = tan(fpu.regs[TOP].d); + FPU_PUSH(1.0); + FPU_SET_C2(0); + //flags and such :) + return; +} +static void FPU_FDIV(Bitu st, Bitu other){ + fpu.regs[st].d= fpu.regs[st].d/fpu.regs[other].d; + //flags and such :) + return; +} + +static void FPU_FDIVR(Bitu st, Bitu other){ + fpu.regs[st].d= fpu.regs[other].d/fpu.regs[st].d; + // flags and such :) + return; +} + +static void FPU_FMUL(Bitu st, Bitu other){ + fpu.regs[st].d*=fpu.regs[other].d; + //flags and such :) + return; +} + +static void FPU_FSUB(Bitu st, Bitu other){ + fpu.regs[st].d = fpu.regs[st].d - fpu.regs[other].d; + //flags and such :) + return; +} + +static void FPU_FSUBR(Bitu st, Bitu other){ + fpu.regs[st].d= fpu.regs[other].d - fpu.regs[st].d; + //flags and such :) + return; +} + +static void FPU_FXCH(Bitu st, Bitu other){ + FPU_Tag tag = fpu.tags[other]; + FPU_Reg reg = fpu.regs[other]; + fpu.tags[other] = fpu.tags[st]; + fpu.regs[other] = fpu.regs[st]; + fpu.tags[st] = tag; + fpu.regs[st] = reg; +} + +static void FPU_FST(Bitu st, Bitu other){ + fpu.tags[other] = fpu.tags[st]; + fpu.regs[other] = fpu.regs[st]; +} + + +static void FPU_FCOM(Bitu st, Bitu other){ + if(((fpu.tags[st] != TAG_Valid) && (fpu.tags[st] != TAG_Zero)) || + ((fpu.tags[other] != TAG_Valid) && (fpu.tags[other] != TAG_Zero))){ + FPU_SET_C3(1);FPU_SET_C2(1);FPU_SET_C0(1);return; + } + if(fpu.regs[st].d == fpu.regs[other].d){ + FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(0);return; + } + if(fpu.regs[st].d < fpu.regs[other].d){ + FPU_SET_C3(0);FPU_SET_C2(0);FPU_SET_C0(1);return; + } + // st > other + FPU_SET_C3(0);FPU_SET_C2(0);FPU_SET_C0(0);return; +} + +static void FPU_FUCOM(Bitu st, Bitu other){ + //does atm the same as fcom + FPU_FCOM(st,other); +} + +static void FPU_FRNDINT(void){ + Bit64s temp= static_cast(FROUND(fpu.regs[TOP].d)); + fpu.regs[TOP].d=static_cast(temp); +} + +static void FPU_FPREM(void){ + Real64 valtop = fpu.regs[TOP].d; + Real64 valdiv = fpu.regs[STV(1)].d; + Bit64s ressaved = static_cast( (valtop/valdiv) ); +// Some backups +// Real64 res=valtop - ressaved*valdiv; +// res= fmod(valtop,valdiv); + fpu.regs[TOP].d = valtop - ressaved*valdiv; + FPU_SET_C0(static_cast(ressaved&4)); + FPU_SET_C3(static_cast(ressaved&2)); + FPU_SET_C1(static_cast(ressaved&1)); + FPU_SET_C2(0); +} + +static void FPU_FPREM1(void){ + Real64 valtop = fpu.regs[TOP].d; + Real64 valdiv = fpu.regs[STV(1)].d; + double quot = valtop/valdiv; + double quotf = floor(quot); + Bit64s ressaved; + if (quot-quotf>0.5) ressaved = static_cast(quotf+1); + else if (quot-quotf<0.5) ressaved = static_cast(quotf); + else ressaved = static_cast((((static_cast(quotf))&1)!=0)?(quotf+1):(quotf)); + fpu.regs[TOP].d = valtop - ressaved*valdiv; + FPU_SET_C0(static_cast(ressaved&4)); + FPU_SET_C3(static_cast(ressaved&2)); + FPU_SET_C1(static_cast(ressaved&1)); + FPU_SET_C2(0); +} + +static void FPU_FXAM(void){ + if(fpu.regs[TOP].ll & LONGTYPE(0x8000000000000000)) //sign + { + FPU_SET_C1(1); + } + else + { + FPU_SET_C1(0); + } + if(fpu.tags[TOP] == TAG_Empty) + { + FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(1); + return; + } + if(fpu.regs[TOP].d == 0.0) //zero or normalized number. + { + FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(0); + } + else + { + FPU_SET_C3(0);FPU_SET_C2(1);FPU_SET_C0(0); + } +} + + +static void FPU_F2XM1(void){ + fpu.regs[TOP].d = pow(2.0,fpu.regs[TOP].d) - 1; + return; +} + +static void FPU_FYL2X(void){ + fpu.regs[STV(1)].d*=log(fpu.regs[TOP].d)/log(static_cast(2.0)); + FPU_FPOP(); + return; +} + +static void FPU_FYL2XP1(void){ + fpu.regs[STV(1)].d*=log(fpu.regs[TOP].d+1.0)/log(static_cast(2.0)); + FPU_FPOP(); + return; +} + +static void FPU_FSCALE(void){ + fpu.regs[TOP].d *= pow(2.0,static_cast(static_cast(fpu.regs[STV(1)].d))); + return; //2^x where x is chopped. +} + +static void FPU_FSTENV(PhysPt addr){ + FPU_SET_TOP(TOP); + if(!cpu.code.big) { + mem_writew(addr+0,static_cast(fpu.cw)); + mem_writew(addr+2,static_cast(fpu.sw)); + mem_writew(addr+4,static_cast(FPU_GetTag())); + } else { + mem_writed(addr+0,static_cast(fpu.cw)); + mem_writed(addr+4,static_cast(fpu.sw)); + mem_writed(addr+8,static_cast(FPU_GetTag())); + } +} + +static void FPU_FLDENV(PhysPt addr){ + Bit16u tag; + Bit32u tagbig; + Bitu cw; + if(!cpu.code.big) { + cw = mem_readw(addr+0); + fpu.sw = mem_readw(addr+2); + tag = mem_readw(addr+4); + } else { + cw = mem_readd(addr+0); + fpu.sw = (Bit16u)mem_readd(addr+4); + tagbig = mem_readd(addr+8); + tag = static_cast(tagbig); + } + FPU_SetTag(tag); + FPU_SetCW(cw); + TOP = FPU_GET_TOP(); +} + +static void FPU_FSAVE(PhysPt addr){ + FPU_FSTENV(addr); + Bitu start = (cpu.code.big?28:14); + for(Bitu i = 0;i < 8;i++){ + FPU_ST80(addr+start,STV(i)); + start += 10; + } + FPU_FINIT(); +} + +static void FPU_FRSTOR(PhysPt addr){ + FPU_FLDENV(addr); + Bitu start = (cpu.code.big?28:14); + for(Bitu i = 0;i < 8;i++){ + fpu.regs[STV(i)].d = FPU_FLD80(addr+start); + start += 10; + } +} + +static void FPU_FXTRACT(void) { + // function stores real bias in st and + // pushes the significant number onto the stack + // if double ever uses a different base please correct this function + + FPU_Reg test = fpu.regs[TOP]; + Bit64s exp80 = test.ll&LONGTYPE(0x7ff0000000000000); + Bit64s exp80final = (exp80>>52) - BIAS64; + Real64 mant = test.d / (pow(2.0,static_cast(exp80final))); + fpu.regs[TOP].d = static_cast(exp80final); + FPU_PUSH(mant); +} + +static void FPU_FCHS(void){ + fpu.regs[TOP].d = -1.0*(fpu.regs[TOP].d); +} + +static void FPU_FABS(void){ + fpu.regs[TOP].d = fabs(fpu.regs[TOP].d); +} + +static void FPU_FTST(void){ + fpu.regs[8].d = 0.0; + FPU_FCOM(TOP,8); +} + +static void FPU_FLD1(void){ + FPU_PREP_PUSH(); + fpu.regs[TOP].d = 1.0; +} + +static void FPU_FLDL2T(void){ + FPU_PREP_PUSH(); + fpu.regs[TOP].d = L2T; +} + +static void FPU_FLDL2E(void){ + FPU_PREP_PUSH(); + fpu.regs[TOP].d = L2E; +} + +static void FPU_FLDPI(void){ + FPU_PREP_PUSH(); + fpu.regs[TOP].d = PI; +} + +static void FPU_FLDLG2(void){ + FPU_PREP_PUSH(); + fpu.regs[TOP].d = LG2; +} + +static void FPU_FLDLN2(void){ + FPU_PREP_PUSH(); + fpu.regs[TOP].d = LN2; +} + +static void FPU_FLDZ(void){ + FPU_PREP_PUSH(); + fpu.regs[TOP].d = 0.0; + fpu.tags[TOP] = TAG_Zero; +} + + +static INLINE void FPU_FADD_EA(Bitu op1){ + FPU_FADD(op1,8); +} +static INLINE void FPU_FMUL_EA(Bitu op1){ + FPU_FMUL(op1,8); +} +static INLINE void FPU_FSUB_EA(Bitu op1){ + FPU_FSUB(op1,8); +} +static INLINE void FPU_FSUBR_EA(Bitu op1){ + FPU_FSUBR(op1,8); +} +static INLINE void FPU_FDIV_EA(Bitu op1){ + FPU_FDIV(op1,8); +} +static INLINE void FPU_FDIVR_EA(Bitu op1){ + FPU_FDIVR(op1,8); +} +static INLINE void FPU_FCOM_EA(Bitu op1){ + FPU_FCOM(op1,8); +} + diff --git a/dosbox/fpu_instructions_x86.h b/dosbox/fpu_instructions_x86.h new file mode 100644 index 00000000..16d96d66 --- /dev/null +++ b/dosbox/fpu_instructions_x86.h @@ -0,0 +1,1489 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id: fpu_instructions_x86.h,v 1.7 2009-05-27 09:15:41 qbix79 Exp $ */ + + +// #define WEAK_EXCEPTIONS + + +#if defined (_MSC_VER) + +#ifdef WEAK_EXCEPTIONS +#define clx +#else +#define clx fclex +#endif + +#ifdef WEAK_EXCEPTIONS +#define FPUD_LOAD(op,szI,szA) \ + __asm { \ + __asm mov ebx, store_to \ + __asm shl ebx, 4 \ + __asm op szI PTR fpu.p_regs[128].m1 \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + } +#else +#define FPUD_LOAD(op,szI,szA) \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, 8 \ + __asm shl eax, 4 \ + __asm mov ebx, store_to \ + __asm shl ebx, 4 \ + __asm fclex \ + __asm op szI PTR fpu.p_regs[eax].m1 \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + } \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); +#endif + +#ifdef WEAK_EXCEPTIONS +#define FPUD_LOAD_EA(op,szI,szA) \ + __asm { \ + __asm op szI PTR fpu.p_regs[128].m1 \ + } +#else +#define FPUD_LOAD_EA(op,szI,szA) \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, 8 \ + __asm shl eax, 4 \ + __asm fclex \ + __asm op szI PTR fpu.p_regs[eax].m1 \ + __asm fnstsw new_sw \ + } \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); +#endif + +#ifdef WEAK_EXCEPTIONS +#define FPUD_STORE(op,szI,szA) \ + Bit16u save_cw; \ + __asm { \ + __asm fnstcw save_cw \ + __asm mov eax, TOP \ + __asm fldcw fpu.cw_mask_all \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm op szI PTR fpu.p_regs[128].m1 \ + __asm fldcw save_cw \ + } +#else +#define FPUD_STORE(op,szI,szA) \ + Bit16u new_sw,save_cw; \ + __asm { \ + __asm fnstcw save_cw \ + __asm fldcw fpu.cw_mask_all \ + __asm mov eax, TOP \ + __asm shl eax, 4 \ + __asm mov ebx, 8 \ + __asm shl ebx, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm clx \ + __asm op szI PTR fpu.p_regs[ebx].m1 \ + __asm fnstsw new_sw \ + __asm fldcw save_cw \ + } \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); +#endif + +// handles fsin,fcos,f2xm1,fchs,fabs +#define FPUD_TRIG(op) \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, TOP \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm clx \ + __asm op \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + } \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fsincos +#define FPUD_SINCOS() \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, TOP \ + __asm mov ebx, eax \ + __asm dec ebx \ + __asm and ebx, 7 \ + __asm shl eax, 4 \ + __asm shl ebx, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm clx \ + __asm fsincos \ + __asm fnstsw new_sw \ + __asm mov cx, new_sw \ + __asm and ch, 0x04 \ + __asm jnz argument_too_large1 \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm jmp end_sincos \ + __asm argument_too_large1: \ + __asm fstp st(0) \ + __asm end_sincos: \ + } \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); \ + if ((new_sw&0x0400)==0) FPU_PREP_PUSH(); + +// handles fptan +#define FPUD_PTAN() \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, TOP \ + __asm mov ebx, eax \ + __asm dec ebx \ + __asm and ebx, 7 \ + __asm shl eax, 4 \ + __asm shl ebx, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm clx \ + __asm fptan \ + __asm fnstsw new_sw \ + __asm mov cx, new_sw \ + __asm and ch, 0x04 \ + __asm jnz argument_too_large2 \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm jmp end_ptan \ + __asm argument_too_large2: \ + __asm fstp st(0) \ + __asm end_ptan: \ + } \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); \ + if ((new_sw&0x0400)==0) FPU_PREP_PUSH(); + +// handles fxtract +#ifdef WEAK_EXCEPTIONS +#define FPUD_XTRACT \ + __asm { \ + __asm mov eax, TOP \ + __asm mov ebx, eax \ + __asm dec ebx \ + __asm and ebx, 7 \ + __asm shl eax, 4 \ + __asm shl ebx, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fxtract \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + } \ + FPU_PREP_PUSH(); +#else +#define FPUD_XTRACT \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, TOP \ + __asm mov ebx, eax \ + __asm dec ebx \ + __asm and ebx, 7 \ + __asm shl eax, 4 \ + __asm shl ebx, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fclex \ + __asm fxtract \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + } \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); \ + FPU_PREP_PUSH(); +#endif + +// handles fadd,fmul,fsub,fsubr +#ifdef WEAK_EXCEPTIONS +#define FPUD_ARITH1(op) \ + Bit16u save_cw; \ + __asm { \ + __asm fnstcw save_cw \ + __asm mov eax, op1 \ + __asm shl eax, 4 \ + __asm fldcw fpu.cw_mask_all \ + __asm mov ebx, op2 \ + __asm shl ebx, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm op st(1), st(0) \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fldcw save_cw \ + } +#else +#define FPUD_ARITH1(op) \ + Bit16u new_sw,save_cw; \ + __asm { \ + __asm fnstcw save_cw \ + __asm fldcw fpu.cw_mask_all \ + __asm mov eax, op1 \ + __asm shl eax, 4 \ + __asm mov ebx, op2 \ + __asm shl ebx, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm clx \ + __asm op st(1), st(0) \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fldcw save_cw \ + } \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); +#endif + +// handles fadd,fmul,fsub,fsubr +#ifdef WEAK_EXCEPTIONS +#define FPUD_ARITH1_EA(op) \ + Bit16u save_cw; \ + __asm { \ + __asm fnstcw save_cw \ + __asm mov eax, op1 \ + __asm fldcw fpu.cw_mask_all \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fxch \ + __asm op st(1), st(0) \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fldcw save_cw \ + } +#else +#define FPUD_ARITH1_EA(op) \ + Bit16u new_sw,save_cw; \ + __asm { \ + __asm fnstcw save_cw \ + __asm fldcw fpu.cw_mask_all \ + __asm mov eax, op1 \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fxch \ + __asm clx \ + __asm op st(1), st(0) \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fldcw save_cw \ + } \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); +#endif + +// handles fsqrt,frndint +#ifdef WEAK_EXCEPTIONS +#define FPUD_ARITH2(op) \ + Bit16u save_cw; \ + __asm { \ + __asm fnstcw save_cw \ + __asm mov eax, TOP \ + __asm fldcw fpu.cw_mask_all \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm op \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fldcw save_cw \ + } +#else +#define FPUD_ARITH2(op) \ + Bit16u new_sw,save_cw; \ + __asm { \ + __asm fnstcw save_cw \ + __asm fldcw fpu.cw_mask_all \ + __asm mov eax, TOP \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm clx \ + __asm op \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fldcw save_cw \ + } \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); +#endif + +// handles fdiv,fdivr +#ifdef WEAK_EXCEPTIONS +#define FPUD_ARITH3(op) \ + Bit16u save_cw; \ + __asm { \ + __asm fnstcw save_cw \ + __asm mov eax, op1 \ + __asm shl eax, 4 \ + __asm fldcw fpu.cw_mask_all \ + __asm mov ebx, op2 \ + __asm shl ebx, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm op st(1), st(0) \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fldcw save_cw \ + } +#else +#define FPUD_ARITH3(op) \ + Bit16u new_sw,save_cw; \ + __asm { \ + __asm fnstcw save_cw \ + __asm fldcw fpu.cw_mask_all \ + __asm mov eax, op1 \ + __asm shl eax, 4 \ + __asm mov ebx, op2 \ + __asm shl ebx, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fclex \ + __asm op st(1), st(0) \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fldcw save_cw \ + } \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); +#endif + +// handles fdiv,fdivr +#ifdef WEAK_EXCEPTIONS +#define FPUD_ARITH3_EA(op) \ + Bit16u save_cw; \ + __asm { \ + __asm fnstcw save_cw \ + __asm mov eax, op1 \ + __asm fldcw fpu.cw_mask_all \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fxch \ + __asm op st(1), st(0) \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fldcw save_cw \ + } +#else +#define FPUD_ARITH3_EA(op) \ + Bit16u new_sw,save_cw; \ + __asm { \ + __asm fnstcw save_cw \ + __asm mov eax, op1 \ + __asm fldcw fpu.cw_mask_all \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fxch \ + __asm fclex \ + __asm op st(1), st(0) \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fldcw save_cw \ + } \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); +#endif + +// handles fprem,fprem1,fscale +#define FPUD_REMINDER(op) \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, TOP \ + __asm mov ebx, eax \ + __asm inc ebx \ + __asm and ebx, 7 \ + __asm shl ebx, 4 \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fclex \ + __asm op \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fstp st(0) \ + } \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); + +// handles fcom,fucom +#define FPUD_COMPARE(op) \ + Bit16u new_sw; \ + __asm { \ + __asm mov ebx, op2 \ + __asm mov eax, op1 \ + __asm shl ebx, 4 \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm clx \ + __asm op \ + __asm fnstsw new_sw \ + } \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +#define FPUD_COMPARE_EA(op) \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, op1 \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm clx \ + __asm op \ + __asm fnstsw new_sw \ + } \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fxam,ftst +#define FPUD_EXAMINE(op) \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, TOP \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm clx \ + __asm op \ + __asm fnstsw new_sw \ + __asm fstp st(0) \ + } \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fpatan,fyl2xp1 +#ifdef WEAK_EXCEPTIONS +#define FPUD_WITH_POP(op) \ + __asm { \ + __asm mov eax, TOP \ + __asm mov ebx, eax \ + __asm inc ebx \ + __asm and ebx, 7 \ + __asm shl ebx, 4 \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm op \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + } \ + FPU_FPOP(); +#else +#define FPUD_WITH_POP(op) \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, TOP \ + __asm mov ebx, eax \ + __asm inc ebx \ + __asm and ebx, 7 \ + __asm shl ebx, 4 \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fclex \ + __asm op \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + } \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); \ + FPU_FPOP(); +#endif + +// handles fyl2x +#ifdef WEAK_EXCEPTIONS +#define FPUD_FYL2X(op) \ + __asm { \ + __asm mov eax, TOP \ + __asm mov ebx, eax \ + __asm inc ebx \ + __asm and ebx, 7 \ + __asm shl ebx, 4 \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm op \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + } \ + FPU_FPOP(); +#else +#define FPUD_FYL2X(op) \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, TOP \ + __asm mov ebx, eax \ + __asm inc ebx \ + __asm and ebx, 7 \ + __asm shl ebx, 4 \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fclex \ + __asm op \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + } \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); \ + FPU_FPOP(); +#endif + +// load math constants +#define FPUD_LOAD_CONST(op) \ + FPU_PREP_PUSH(); \ + __asm { \ + __asm mov eax, TOP \ + __asm shl eax, 4 \ + __asm clx \ + __asm op \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + } \ + +#else + +#ifdef WEAK_EXCEPTIONS +#define clx +#else +#define clx "fclex" +#endif + +#ifdef WEAK_EXCEPTIONS +#define FPUD_LOAD(op,szI,szA) \ + __asm__ volatile ( \ + "movl $128, %%eax \n" \ + "shl $4, %0 \n" \ + #op #szA " (%1, %%eax) \n" \ + "fstpt (%1, %0) " \ + : \ + : "r" (store_to), "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); +#else +#define FPUD_LOAD(op,szI,szA) \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "movl $8, %%eax \n" \ + "shl $4, %%eax \n" \ + "shl $4, %1 \n" \ + "fclex \n" \ + #op #szA " (%2, %%eax) \n" \ + "fnstsw %0 \n" \ + "fstpt (%2, %1) " \ + : "=m" (new_sw) \ + : "r" (store_to), "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); +#endif + +#ifdef WEAK_EXCEPTIONS +#define FPUD_LOAD_EA(op,szI,szA) \ + __asm__ volatile ( \ + "movl $128, %%eax \n" \ + #op #szA " (%0, %%eax) \n" \ + : \ + : "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); +#else +#define FPUD_LOAD_EA(op,szI,szA) \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "movl $8, %%eax \n" \ + "shl $4, %%eax \n" \ + "fclex \n" \ + #op #szA " (%1, %%eax) \n" \ + "fnstsw %0 \n" \ + : "=m" (new_sw) \ + : "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); +#endif + +#ifdef WEAK_EXCEPTIONS +#define FPUD_STORE(op,szI,szA) \ + Bit16u save_cw; \ + __asm__ volatile ( \ + "fnstcw %0 \n" \ + "shll $4, %1 \n" \ + "fldcw %3 \n" \ + "movl $128, %%eax \n" \ + "fldt (%2, %1) \n" \ + #op #szA " (%2, %%eax) \n" \ + "fldcw %0 " \ + : "=m" (save_cw) \ + : "r" (TOP), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ + : "eax", "memory" \ + ); +#else +#define FPUD_STORE(op,szI,szA) \ + Bit16u new_sw,save_cw; \ + __asm__ volatile ( \ + "fnstcw %1 \n" \ + "fldcw %4 \n" \ + "shll $4, %2 \n" \ + "movl $8, %%eax \n" \ + "shl $4, %%eax \n" \ + "fldt (%3, %2) \n" \ + clx" \n" \ + #op #szA " (%3, %%eax) \n" \ + "fnstsw %0 \n" \ + "fldcw %1 " \ + : "=m" (new_sw), "=m" (save_cw) \ + : "r" (TOP), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ + : "eax", "memory" \ + ); \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); +#endif + +// handles fsin,fcos,f2xm1,fchs,fabs +#define FPUD_TRIG(op) \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "shll $4, %1 \n" \ + "fldt (%2, %1) \n" \ + clx" \n" \ + #op" \n" \ + "fnstsw %0 \n" \ + "fstpt (%2, %1) " \ + : "=m" (new_sw) \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "memory" \ + ); \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fsincos +#define FPUD_SINCOS() \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "movl %1, %%eax \n" \ + "shll $4, %1 \n" \ + "decl %%eax \n" \ + "andl $7, %%eax \n" \ + "shll $4, %%eax \n" \ + "fldt (%2, %1) \n" \ + clx" \n" \ + "fsincos \n" \ + "fnstsw %0 \n" \ + "fstpt (%2, %%eax) \n" \ + "movw %0, %%ax \n" \ + "sahf \n" \ + "jp argument_too_large1 \n" \ + "fstpt (%2, %1) \n" \ + "argument_too_large1: " \ + : "=m" (new_sw) \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "eax", "cc", "memory" \ + ); \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); \ + if ((new_sw&0x0400)==0) FPU_PREP_PUSH(); + +// handles fptan +#define FPUD_PTAN() \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "movl %1, %%eax \n" \ + "shll $4, %1 \n" \ + "decl %%eax \n" \ + "andl $7, %%eax \n" \ + "shll $4, %%eax \n" \ + "fldt (%2, %1) \n" \ + clx" \n" \ + "fptan \n" \ + "fnstsw %0 \n" \ + "fstpt (%2, %%eax) \n" \ + "movw %0, %%ax \n" \ + "sahf \n" \ + "jp argument_too_large2 \n" \ + "fstpt (%2, %1) \n" \ + "argument_too_large2: " \ + : "=m" (new_sw) \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "eax", "cc", "memory" \ + ); \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); \ + if ((new_sw&0x0400)==0) FPU_PREP_PUSH(); + +// handles fxtract +#ifdef WEAK_EXCEPTIONS +#define FPUD_XTRACT \ + __asm__ volatile ( \ + "movl %0, %%eax \n" \ + "shll $4, %0 \n" \ + "decl %%eax \n" \ + "andl $7, %%eax \n" \ + "shll $4, %%eax \n" \ + "fldt (%1, %0) \n" \ + "fxtract \n" \ + "fstpt (%1, %%eax) \n" \ + "fstpt (%1, %0) " \ + : \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); \ + FPU_PREP_PUSH(); +#else +#define FPUD_XTRACT \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "movl %1, %%eax \n" \ + "shll $4, %1 \n" \ + "decl %%eax \n" \ + "andl $7, %%eax \n" \ + "shll $4, %%eax \n" \ + "fldt (%2, %1) \n" \ + "fclex \n" \ + "fxtract \n" \ + "fnstsw %0 \n" \ + "fstpt (%2, %%eax) \n" \ + "fstpt (%2, %1) " \ + : "=m" (new_sw) \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); \ + FPU_PREP_PUSH(); +#endif + +// handles fadd,fmul,fsub,fsubr +#ifdef WEAK_EXCEPTIONS +#define FPUD_ARITH1(op) \ + Bit16u save_cw; \ + __asm__ volatile ( \ + "fnstcw %0 \n" \ + "fldcw %4 \n" \ + "shll $4, %2 \n" \ + "shll $4, %1 \n" \ + "fldt (%3, %2) \n" \ + "fldt (%3, %1) \n" \ + #op" \n" \ + "fstpt (%3, %1) \n" \ + "fldcw %0 " \ + : "=m" (save_cw) \ + : "r" (op1), "r" (op2), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ + : "memory" \ + ); +#else +#define FPUD_ARITH1(op) \ + Bit16u new_sw,save_cw; \ + __asm__ volatile ( \ + "fnstcw %1 \n" \ + "fldcw %5 \n" \ + "shll $4, %3 \n" \ + "shll $4, %2 \n" \ + "fldt (%4, %3) \n" \ + "fldt (%4, %2) \n" \ + clx" \n" \ + #op" \n" \ + "fnstsw %0 \n" \ + "fstpt (%4, %2) \n" \ + "fldcw %1 " \ + : "=m" (new_sw), "=m" (save_cw) \ + : "r" (op1), "r" (op2), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ + : "memory" \ + ); \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); +#endif + +// handles fadd,fmul,fsub,fsubr +#ifdef WEAK_EXCEPTIONS +#define FPUD_ARITH1_EA(op) \ + Bit16u save_cw; \ + __asm__ volatile ( \ + "fnstcw %0 \n" \ + "fldcw %3 \n" \ + "shll $4, %1 \n" \ + "fldt (%2, %1) \n" \ + #op" \n" \ + "fstpt (%2, %1) \n" \ + "fldcw %0 " \ + : "=m" (save_cw) \ + : "r" (op1), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ + : "memory" \ + ); +#else +#define FPUD_ARITH1_EA(op) \ + Bit16u new_sw,save_cw; \ + __asm__ volatile ( \ + "fnstcw %1 \n" \ + "fldcw %4 \n" \ + "shll $4, %2 \n" \ + "fldt (%3, %2) \n" \ + clx" \n" \ + #op" \n" \ + "fnstsw %0 \n" \ + "fstpt (%3, %2) \n" \ + "fldcw %1 " \ + : "=m" (new_sw), "=m" (save_cw) \ + : "r" (op1), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ + : "memory" \ + ); \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); +#endif + +// handles fsqrt,frndint +#ifdef WEAK_EXCEPTIONS +#define FPUD_ARITH2(op) \ + Bit16u save_cw; \ + __asm__ volatile ( \ + "fnstcw %0 \n" \ + "fldcw %3 \n" \ + "shll $4, %1 \n" \ + "fldt (%2, %1) \n" \ + #op" \n" \ + "fstpt (%2, %1) \n" \ + "fldcw %0 " \ + : "=m" (save_cw) \ + : "r" (TOP), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ + : "memory" \ + ); +#else +#define FPUD_ARITH2(op) \ + Bit16u new_sw,save_cw; \ + __asm__ volatile ( \ + "fnstcw %1 \n" \ + "fldcw %4 \n" \ + "shll $4, %2 \n" \ + "fldt (%3, %2) \n" \ + clx" \n" \ + #op" \n" \ + "fnstsw %0 \n" \ + "fstpt (%3, %2) \n" \ + "fldcw %1 " \ + : "=m" (new_sw), "=m" (save_cw) \ + : "r" (TOP), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ + : "memory" \ + ); \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); +#endif + +// handles fdiv,fdivr +#ifdef WEAK_EXCEPTIONS +#define FPUD_ARITH3(op) \ + Bit16u save_cw; \ + __asm__ volatile ( \ + "fnstcw %0 \n" \ + "fldcw %4 \n" \ + "shll $4, %2 \n" \ + "shll $4, %1 \n" \ + "fldt (%3, %2) \n" \ + "fldt (%3, %1) \n" \ + #op" \n" \ + "fstpt (%3, %1) \n" \ + "fldcw %0 " \ + : "=m" (save_cw) \ + : "r" (op1), "r" (op2), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ + : "memory" \ + ); +#else +#define FPUD_ARITH3(op) \ + Bit16u new_sw,save_cw; \ + __asm__ volatile ( \ + "fnstcw %1 \n" \ + "fldcw %5 \n" \ + "shll $4, %3 \n" \ + "shll $4, %2 \n" \ + "fldt (%4, %3) \n" \ + "fldt (%4, %2) \n" \ + "fclex \n" \ + #op" \n" \ + "fnstsw %0 \n" \ + "fstpt (%4, %2) \n" \ + "fldcw %1 " \ + : "=m" (new_sw), "=m" (save_cw) \ + : "r" (op1), "r" (op2), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ + : "memory" \ + ); \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); +#endif + +// handles fdiv,fdivr +#ifdef WEAK_EXCEPTIONS +#define FPUD_ARITH3_EA(op) \ + Bit16u save_cw; \ + __asm__ volatile ( \ + "fnstcw %0 \n" \ + "fldcw %3 \n" \ + "shll $4, %1 \n" \ + "fldt (%2, %1) \n" \ + #op" \n" \ + "fstpt (%2, %1) \n" \ + "fldcw %0 " \ + : "=m" (save_cw) \ + : "r" (op1), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ + : "memory" \ + ); +#else +#define FPUD_ARITH3_EA(op) \ + Bit16u new_sw,save_cw; \ + __asm__ volatile ( \ + "fnstcw %1 \n" \ + "fldcw %4 \n" \ + "shll $4, %2 \n" \ + "fldt (%3, %2) \n" \ + "fclex \n" \ + #op" \n" \ + "fnstsw %0 \n" \ + "fstpt (%3, %2) \n" \ + "fldcw %1 " \ + : "=m" (new_sw), "=m" (save_cw) \ + : "r" (op1), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ + : "memory" \ + ); \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); +#endif + +// handles fprem,fprem1,fscale +#define FPUD_REMINDER(op) \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "movl %1, %%eax \n" \ + "incl %%eax \n" \ + "andl $7, %%eax \n" \ + "shll $4, %%eax \n" \ + "shll $4, %1 \n" \ + "fldt (%2, %%eax) \n" \ + "fldt (%2, %1) \n" \ + "fclex \n" \ + #op" \n" \ + "fnstsw %0 \n" \ + "fstpt (%2, %1) \n" \ + "fstp %%st(0) " \ + : "=m" (new_sw) \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); + +// handles fcom,fucom +#define FPUD_COMPARE(op) \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "shll $4, %2 \n" \ + "shll $4, %1 \n" \ + "fldt (%3, %2) \n" \ + "fldt (%3, %1) \n" \ + clx" \n" \ + #op" \n" \ + "fnstsw %0 " \ + : "=m" (new_sw) \ + : "r" (op1), "r" (op2), "r" (fpu.p_regs) \ + : "memory" \ + ); \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fcom,fucom +#define FPUD_COMPARE_EA(op) \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "shll $4, %1 \n" \ + "fldt (%2, %1) \n" \ + clx" \n" \ + #op" \n" \ + "fnstsw %0 " \ + : "=m" (new_sw) \ + : "r" (op1), "r" (fpu.p_regs) \ + : "memory" \ + ); \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fxam,ftst +#define FPUD_EXAMINE(op) \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "shll $4, %1 \n" \ + "fldt (%2, %1) \n" \ + clx" \n" \ + #op" \n" \ + "fnstsw %0 \n" \ + "fstp %%st(0) " \ + : "=m" (new_sw) \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "memory" \ + ); \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fpatan,fyl2xp1 +#ifdef WEAK_EXCEPTIONS +#define FPUD_WITH_POP(op) \ + __asm__ volatile ( \ + "movl %0, %%eax \n" \ + "incl %%eax \n" \ + "andl $7, %%eax \n" \ + "shll $4, %%eax \n" \ + "shll $4, %0 \n" \ + "fldt (%1, %%eax) \n" \ + "fldt (%1, %0) \n" \ + #op" \n" \ + "fstpt (%1, %%eax) \n" \ + : \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); \ + FPU_FPOP(); +#else +#define FPUD_WITH_POP(op) \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "movl %1, %%eax \n" \ + "incl %%eax \n" \ + "andl $7, %%eax \n" \ + "shll $4, %%eax \n" \ + "shll $4, %1 \n" \ + "fldt (%2, %%eax) \n" \ + "fldt (%2, %1) \n" \ + "fclex \n" \ + #op" \n" \ + "fnstsw %0 \n" \ + "fstpt (%2, %%eax) \n" \ + : "=m" (new_sw) \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); \ + FPU_FPOP(); +#endif + +// handles fyl2x +#ifdef WEAK_EXCEPTIONS +#define FPUD_FYL2X(op) \ + __asm__ volatile ( \ + "movl %0, %%eax \n" \ + "incl %%eax \n" \ + "andl $7, %%eax \n" \ + "shll $4, %%eax \n" \ + "shll $4, %0 \n" \ + "fldt (%1, %%eax) \n" \ + "fldt (%1, %0) \n" \ + #op" \n" \ + "fstpt (%1, %%eax) \n" \ + : \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); \ + FPU_FPOP(); +#else +#define FPUD_FYL2X(op) \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "movl %1, %%eax \n" \ + "incl %%eax \n" \ + "andl $7, %%eax \n" \ + "shll $4, %%eax \n" \ + "shll $4, %1 \n" \ + "fldt (%2, %%eax) \n" \ + "fldt (%2, %1) \n" \ + "fclex \n" \ + #op" \n" \ + "fnstsw %0 \n" \ + "fstpt (%2, %%eax) \n" \ + : "=m" (new_sw) \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); \ + FPU_FPOP(); +#endif + +// load math constants +#define FPUD_LOAD_CONST(op) \ + FPU_PREP_PUSH(); \ + __asm__ volatile ( \ + "shll $4, %0 \n" \ + clx" \n" \ + #op" \n" \ + "fstpt (%1, %0) \n" \ + : \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "memory" \ + ); + +#endif + +#ifdef WEAK_EXCEPTIONS +const Bit16u exc_mask=0x7f00; +#else +const Bit16u exc_mask=0xffbf; +#endif + +static void FPU_FINIT(void) { + FPU_SetCW(0x37F); + fpu.sw=0; + TOP=FPU_GET_TOP(); + fpu.tags[0]=TAG_Empty; + fpu.tags[1]=TAG_Empty; + fpu.tags[2]=TAG_Empty; + fpu.tags[3]=TAG_Empty; + fpu.tags[4]=TAG_Empty; + fpu.tags[5]=TAG_Empty; + fpu.tags[6]=TAG_Empty; + fpu.tags[7]=TAG_Empty; + fpu.tags[8]=TAG_Valid; // is only used by us +} + +static void FPU_FCLEX(void){ + fpu.sw&=0x7f00; //should clear exceptions +} + +static void FPU_FNOP(void){ +} + +static void FPU_PREP_PUSH(void){ + TOP = (TOP - 1) &7; + fpu.tags[TOP]=TAG_Valid; +} + +static void FPU_FPOP(void){ + fpu.tags[TOP]=TAG_Empty; + TOP = ((TOP+1)&7); +} + +static void FPU_FLD_F32(PhysPt addr,Bitu store_to) { + fpu.p_regs[8].m1 = mem_readd(addr); + FPUD_LOAD(fld,DWORD,s) +} + +static void FPU_FLD_F32_EA(PhysPt addr) { + fpu.p_regs[8].m1 = mem_readd(addr); + FPUD_LOAD_EA(fld,DWORD,s) +} + +static void FPU_FLD_F64(PhysPt addr,Bitu store_to) { + fpu.p_regs[8].m1 = mem_readd(addr); + fpu.p_regs[8].m2 = mem_readd(addr+4); + FPUD_LOAD(fld,QWORD,l) +} + +static void FPU_FLD_F64_EA(PhysPt addr) { + fpu.p_regs[8].m1 = mem_readd(addr); + fpu.p_regs[8].m2 = mem_readd(addr+4); + FPUD_LOAD_EA(fld,QWORD,l) +} + +static void FPU_FLD_F80(PhysPt addr) { + fpu.p_regs[TOP].m1 = mem_readd(addr); + fpu.p_regs[TOP].m2 = mem_readd(addr+4); + fpu.p_regs[TOP].m3 = mem_readw(addr+8); + FPU_SET_C1(0); +} + +static void FPU_FLD_I16(PhysPt addr,Bitu store_to) { + fpu.p_regs[8].m1 = (Bit32u)mem_readw(addr); + FPUD_LOAD(fild,WORD,) +} + +static void FPU_FLD_I16_EA(PhysPt addr) { + fpu.p_regs[8].m1 = (Bit32u)mem_readw(addr); + FPUD_LOAD_EA(fild,WORD,) +} + +static void FPU_FLD_I32(PhysPt addr,Bitu store_to) { + fpu.p_regs[8].m1 = mem_readd(addr); + FPUD_LOAD(fild,DWORD,l) +} + +static void FPU_FLD_I32_EA(PhysPt addr) { + fpu.p_regs[8].m1 = mem_readd(addr); + FPUD_LOAD_EA(fild,DWORD,l) +} + +static void FPU_FLD_I64(PhysPt addr,Bitu store_to) { + fpu.p_regs[8].m1 = mem_readd(addr); + fpu.p_regs[8].m2 = mem_readd(addr+4); + FPUD_LOAD(fild,QWORD,q) +} + +static void FPU_FBLD(PhysPt addr,Bitu store_to) { + fpu.p_regs[8].m1 = mem_readd(addr); + fpu.p_regs[8].m2 = mem_readd(addr+4); + fpu.p_regs[8].m3 = mem_readw(addr+8); + FPUD_LOAD(fbld,TBYTE,) +} + +static void FPU_FST_F32(PhysPt addr) { + FPUD_STORE(fstp,DWORD,s) + mem_writed(addr,fpu.p_regs[8].m1); +} + +static void FPU_FST_F64(PhysPt addr) { + FPUD_STORE(fstp,QWORD,l) + mem_writed(addr,fpu.p_regs[8].m1); + mem_writed(addr+4,fpu.p_regs[8].m2); +} + +static void FPU_FST_F80(PhysPt addr) { + mem_writed(addr,fpu.p_regs[TOP].m1); + mem_writed(addr+4,fpu.p_regs[TOP].m2); + mem_writew(addr+8,fpu.p_regs[TOP].m3); + FPU_SET_C1(0); +} + +static void FPU_FST_I16(PhysPt addr) { + FPUD_STORE(fistp,WORD,) + mem_writew(addr,(Bit16u)fpu.p_regs[8].m1); +} + +static void FPU_FST_I32(PhysPt addr) { + FPUD_STORE(fistp,DWORD,l) + mem_writed(addr,fpu.p_regs[8].m1); +} + +static void FPU_FST_I64(PhysPt addr) { + FPUD_STORE(fistp,QWORD,q) + mem_writed(addr,fpu.p_regs[8].m1); + mem_writed(addr+4,fpu.p_regs[8].m2); +} + +static void FPU_FBST(PhysPt addr) { + FPUD_STORE(fbstp,TBYTE,) + mem_writed(addr,fpu.p_regs[8].m1); + mem_writed(addr+4,fpu.p_regs[8].m2); + mem_writew(addr+8,fpu.p_regs[8].m3); +} + + +static void FPU_FSIN(void){ + FPUD_TRIG(fsin) +} + +static void FPU_FSINCOS(void){ + FPUD_SINCOS() +} + +static void FPU_FCOS(void){ + FPUD_TRIG(fcos) +} + +static void FPU_FSQRT(void){ + FPUD_ARITH2(fsqrt) +} + +static void FPU_FPATAN(void){ + FPUD_WITH_POP(fpatan) +} + +static void FPU_FPTAN(void){ + FPUD_PTAN() +} + + +static void FPU_FADD(Bitu op1, Bitu op2){ + FPUD_ARITH1(faddp) +} + +static void FPU_FADD_EA(Bitu op1){ + FPUD_ARITH1_EA(faddp) +} + +static void FPU_FDIV(Bitu op1, Bitu op2){ + FPUD_ARITH3(fdivp) +} + +static void FPU_FDIV_EA(Bitu op1){ + FPUD_ARITH3_EA(fdivp) +} + +static void FPU_FDIVR(Bitu op1, Bitu op2){ + FPUD_ARITH3(fdivrp) +} + +static void FPU_FDIVR_EA(Bitu op1){ + FPUD_ARITH3_EA(fdivrp) +} + +static void FPU_FMUL(Bitu op1, Bitu op2){ + FPUD_ARITH1(fmulp) +} + +static void FPU_FMUL_EA(Bitu op1){ + FPUD_ARITH1_EA(fmulp) +} + +static void FPU_FSUB(Bitu op1, Bitu op2){ + FPUD_ARITH1(fsubp) +} + +static void FPU_FSUB_EA(Bitu op1){ + FPUD_ARITH1_EA(fsubp) +} + +static void FPU_FSUBR(Bitu op1, Bitu op2){ + FPUD_ARITH1(fsubrp) +} + +static void FPU_FSUBR_EA(Bitu op1){ + FPUD_ARITH1_EA(fsubrp) +} + +static void FPU_FXCH(Bitu stv, Bitu other){ + FPU_Tag tag = fpu.tags[other]; + fpu.tags[other] = fpu.tags[stv]; + fpu.tags[stv] = tag; + + Bit32u m1s = fpu.p_regs[other].m1; + Bit32u m2s = fpu.p_regs[other].m2; + Bit16u m3s = fpu.p_regs[other].m3; + fpu.p_regs[other].m1 = fpu.p_regs[stv].m1; + fpu.p_regs[other].m2 = fpu.p_regs[stv].m2; + fpu.p_regs[other].m3 = fpu.p_regs[stv].m3; + fpu.p_regs[stv].m1 = m1s; + fpu.p_regs[stv].m2 = m2s; + fpu.p_regs[stv].m3 = m3s; + + FPU_SET_C1(0); +} + +static void FPU_FST(Bitu stv, Bitu other){ + fpu.tags[other] = fpu.tags[stv]; + + fpu.p_regs[other].m1 = fpu.p_regs[stv].m1; + fpu.p_regs[other].m2 = fpu.p_regs[stv].m2; + fpu.p_regs[other].m3 = fpu.p_regs[stv].m3; + + FPU_SET_C1(0); +} + + +static void FPU_FCOM(Bitu op1, Bitu op2){ + FPUD_COMPARE(fcompp) +} + +static void FPU_FCOM_EA(Bitu op1){ + FPUD_COMPARE_EA(fcompp) +} + +static void FPU_FUCOM(Bitu op1, Bitu op2){ + FPUD_COMPARE(fucompp) +} + +static void FPU_FRNDINT(void){ + FPUD_ARITH2(frndint) +} + +static void FPU_FPREM(void){ + FPUD_REMINDER(fprem) +} + +static void FPU_FPREM1(void){ + FPUD_REMINDER(fprem1) +} + +static void FPU_FXAM(void){ + FPUD_EXAMINE(fxam) + // handle empty registers (C1 set to sign in any way!) + if(fpu.tags[TOP] == TAG_Empty) { + FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(1); + return; + } +} + +static void FPU_F2XM1(void){ + FPUD_TRIG(f2xm1) +} + +static void FPU_FYL2X(void){ + FPUD_FYL2X(fyl2x) +} + +static void FPU_FYL2XP1(void){ + FPUD_WITH_POP(fyl2xp1) +} + +static void FPU_FSCALE(void){ + FPUD_REMINDER(fscale) +} + + +static void FPU_FSTENV(PhysPt addr){ + FPU_SET_TOP(TOP); + if(!cpu.code.big) { + mem_writew(addr+0,static_cast(fpu.cw)); + mem_writew(addr+2,static_cast(fpu.sw)); + mem_writew(addr+4,static_cast(FPU_GetTag())); + } else { + mem_writed(addr+0,static_cast(fpu.cw)); + mem_writed(addr+4,static_cast(fpu.sw)); + mem_writed(addr+8,static_cast(FPU_GetTag())); + } +} + +static void FPU_FLDENV(PhysPt addr){ + Bit16u tag; + Bit32u tagbig; + Bitu cw; + if(!cpu.code.big) { + cw = mem_readw(addr+0); + fpu.sw = mem_readw(addr+2); + tag = mem_readw(addr+4); + } else { + cw = mem_readd(addr+0); + fpu.sw = (Bit16u)mem_readd(addr+4); + tagbig = mem_readd(addr+8); + tag = static_cast(tagbig); + } + FPU_SetTag(tag); + FPU_SetCW(cw); + TOP=FPU_GET_TOP(); +} + +static void FPU_FSAVE(PhysPt addr){ + FPU_FSTENV(addr); + Bitu start=(cpu.code.big?28:14); + for(Bitu i=0;i<8;i++){ + mem_writed(addr+start,fpu.p_regs[STV(i)].m1); + mem_writed(addr+start+4,fpu.p_regs[STV(i)].m2); + mem_writew(addr+start+8,fpu.p_regs[STV(i)].m3); + start+=10; + } + FPU_FINIT(); +} + +static void FPU_FRSTOR(PhysPt addr){ + FPU_FLDENV(addr); + Bitu start=(cpu.code.big?28:14); + for(Bitu i=0;i<8;i++){ + fpu.p_regs[STV(i)].m1 = mem_readd(addr+start); + fpu.p_regs[STV(i)].m2 = mem_readd(addr+start+4); + fpu.p_regs[STV(i)].m3 = mem_readw(addr+start+8); + start+=10; + } +} + + +static void FPU_FXTRACT(void) { + FPUD_XTRACT +} + +static void FPU_FCHS(void){ + FPUD_TRIG(fchs) +} + +static void FPU_FABS(void){ + FPUD_TRIG(fabs) +} + +static void FPU_FTST(void){ + FPUD_EXAMINE(ftst) +} + +static void FPU_FLD1(void){ + FPUD_LOAD_CONST(fld1) +} + +static void FPU_FLDL2T(void){ + FPUD_LOAD_CONST(fldl2t) +} + +static void FPU_FLDL2E(void){ + FPUD_LOAD_CONST(fldl2e) +} + +static void FPU_FLDPI(void){ + FPUD_LOAD_CONST(fldpi) +} + +static void FPU_FLDLG2(void){ + FPUD_LOAD_CONST(fldlg2) +} + +static void FPU_FLDLN2(void){ + FPUD_LOAD_CONST(fldln2) +} + +static void FPU_FLDZ(void){ + FPUD_LOAD_CONST(fldz) + fpu.tags[TOP]=TAG_Zero; +} diff --git a/dosbox/inout.h b/dosbox/inout.h new file mode 100644 index 00000000..798e9db9 --- /dev/null +++ b/dosbox/inout.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id: inout.h,v 1.13 2009-05-27 09:15:41 qbix79 Exp $ */ + +#ifndef DOSBOX_INOUT_H +#define DOSBOX_INOUT_H + +#define IO_MAX (64*1024+3) + +#define IO_MB 0x1 +#define IO_MW 0x2 +#define IO_MD 0x4 +#define IO_MA (IO_MB | IO_MW | IO_MD ) + +typedef Bitu IO_ReadHandler(Bitu port,Bitu iolen); +typedef void IO_WriteHandler(Bitu port,Bitu val,Bitu iolen); + +extern IO_WriteHandler * io_writehandlers[3][IO_MAX]; +extern IO_ReadHandler * io_readhandlers[3][IO_MAX]; + +void IO_RegisterReadHandler(Bitu port,IO_ReadHandler * handler,Bitu mask,Bitu range=1); +void IO_RegisterWriteHandler(Bitu port,IO_WriteHandler * handler,Bitu mask,Bitu range=1); + +void IO_FreeReadHandler(Bitu port,Bitu mask,Bitu range=1); +void IO_FreeWriteHandler(Bitu port,Bitu mask,Bitu range=1); + +void IO_WriteB(Bitu port,Bitu val); +void IO_WriteW(Bitu port,Bitu val); +void IO_WriteD(Bitu port,Bitu val); + +Bitu IO_ReadB(Bitu port); +Bitu IO_ReadW(Bitu port); +Bitu IO_ReadD(Bitu port); + +/* Classes to manage the IO objects created by the various devices. + * The io objects will remove itself on destruction.*/ +class IO_Base{ +protected: + bool installed; + Bitu m_port, m_mask,m_range; +public: + IO_Base():installed(false){}; +}; +class IO_ReadHandleObject: private IO_Base{ +public: + void Install(Bitu port,IO_ReadHandler * handler,Bitu mask,Bitu range=1); + ~IO_ReadHandleObject(); +}; +class IO_WriteHandleObject: private IO_Base{ +public: + void Install(Bitu port,IO_WriteHandler * handler,Bitu mask,Bitu range=1); + ~IO_WriteHandleObject(); +}; + +static INLINE void IO_Write(Bitu port,Bit8u val) { + IO_WriteB(port,val); +} +static INLINE Bit8u IO_Read(Bitu port){ + return (Bit8u)IO_ReadB(port); +} + +#endif diff --git a/dosbox/instructions.h b/dosbox/instructions.h new file mode 100644 index 00000000..1696997c --- /dev/null +++ b/dosbox/instructions.h @@ -0,0 +1,963 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* Jumps */ + +/* All Byte general instructions */ +#define ADDB(op1,op2,load,save) \ + lf_var1b=load(op1);lf_var2b=op2; \ + lf_resb=lf_var1b+lf_var2b; \ + save(op1,lf_resb); \ + lflags.type=t_ADDb; + +#define ADCB(op1,op2,load,save) \ + lflags.oldcf=get_CF()!=0; \ + lf_var1b=load(op1);lf_var2b=op2; \ + lf_resb=lf_var1b+lf_var2b+lflags.oldcf; \ + save(op1,lf_resb); \ + lflags.type=t_ADCb; + +#define SBBB(op1,op2,load,save) \ + lflags.oldcf=get_CF()!=0; \ + lf_var1b=load(op1);lf_var2b=op2; \ + lf_resb=lf_var1b-(lf_var2b+lflags.oldcf); \ + save(op1,lf_resb); \ + lflags.type=t_SBBb; + +#define SUBB(op1,op2,load,save) \ + lf_var1b=load(op1);lf_var2b=op2; \ + lf_resb=lf_var1b-lf_var2b; \ + save(op1,lf_resb); \ + lflags.type=t_SUBb; + +#define ORB(op1,op2,load,save) \ + lf_var1b=load(op1);lf_var2b=op2; \ + lf_resb=lf_var1b | lf_var2b; \ + save(op1,lf_resb); \ + lflags.type=t_ORb; + +#define XORB(op1,op2,load,save) \ + lf_var1b=load(op1);lf_var2b=op2; \ + lf_resb=lf_var1b ^ lf_var2b; \ + save(op1,lf_resb); \ + lflags.type=t_XORb; + +#define ANDB(op1,op2,load,save) \ + lf_var1b=load(op1);lf_var2b=op2; \ + lf_resb=lf_var1b & lf_var2b; \ + save(op1,lf_resb); \ + lflags.type=t_ANDb; + +#define CMPB(op1,op2,load,save) \ + lf_var1b=load(op1);lf_var2b=op2; \ + lf_resb=lf_var1b-lf_var2b; \ + lflags.type=t_CMPb; + +#define TESTB(op1,op2,load,save) \ + lf_var1b=load(op1);lf_var2b=op2; \ + lf_resb=lf_var1b & lf_var2b; \ + lflags.type=t_TESTb; + +/* All Word General instructions */ + +#define ADDW(op1,op2,load,save) \ + lf_var1w=load(op1);lf_var2w=op2; \ + lf_resw=lf_var1w+lf_var2w; \ + save(op1,lf_resw); \ + lflags.type=t_ADDw; + +#define ADCW(op1,op2,load,save) \ + lflags.oldcf=get_CF()!=0; \ + lf_var1w=load(op1);lf_var2w=op2; \ + lf_resw=lf_var1w+lf_var2w+lflags.oldcf; \ + save(op1,lf_resw); \ + lflags.type=t_ADCw; + +#define SBBW(op1,op2,load,save) \ + lflags.oldcf=get_CF()!=0; \ + lf_var1w=load(op1);lf_var2w=op2; \ + lf_resw=lf_var1w-(lf_var2w+lflags.oldcf); \ + save(op1,lf_resw); \ + lflags.type=t_SBBw; + +#define SUBW(op1,op2,load,save) \ + lf_var1w=load(op1);lf_var2w=op2; \ + lf_resw=lf_var1w-lf_var2w; \ + save(op1,lf_resw); \ + lflags.type=t_SUBw; + +#define ORW(op1,op2,load,save) \ + lf_var1w=load(op1);lf_var2w=op2; \ + lf_resw=lf_var1w | lf_var2w; \ + save(op1,lf_resw); \ + lflags.type=t_ORw; + +#define XORW(op1,op2,load,save) \ + lf_var1w=load(op1);lf_var2w=op2; \ + lf_resw=lf_var1w ^ lf_var2w; \ + save(op1,lf_resw); \ + lflags.type=t_XORw; + +#define ANDW(op1,op2,load,save) \ + lf_var1w=load(op1);lf_var2w=op2; \ + lf_resw=lf_var1w & lf_var2w; \ + save(op1,lf_resw); \ + lflags.type=t_ANDw; + +#define CMPW(op1,op2,load,save) \ + lf_var1w=load(op1);lf_var2w=op2; \ + lf_resw=lf_var1w-lf_var2w; \ + lflags.type=t_CMPw; + +#define TESTW(op1,op2,load,save) \ + lf_var1w=load(op1);lf_var2w=op2; \ + lf_resw=lf_var1w & lf_var2w; \ + lflags.type=t_TESTw; + +/* All DWORD General Instructions */ + +#define ADDD(op1,op2,load,save) \ + lf_var1d=load(op1);lf_var2d=op2; \ + lf_resd=lf_var1d+lf_var2d; \ + save(op1,lf_resd); \ + lflags.type=t_ADDd; + +#define ADCD(op1,op2,load,save) \ + lflags.oldcf=get_CF()!=0; \ + lf_var1d=load(op1);lf_var2d=op2; \ + lf_resd=lf_var1d+lf_var2d+lflags.oldcf; \ + save(op1,lf_resd); \ + lflags.type=t_ADCd; + +#define SBBD(op1,op2,load,save) \ + lflags.oldcf=get_CF()!=0; \ + lf_var1d=load(op1);lf_var2d=op2; \ + lf_resd=lf_var1d-(lf_var2d+lflags.oldcf); \ + save(op1,lf_resd); \ + lflags.type=t_SBBd; + +#define SUBD(op1,op2,load,save) \ + lf_var1d=load(op1);lf_var2d=op2; \ + lf_resd=lf_var1d-lf_var2d; \ + save(op1,lf_resd); \ + lflags.type=t_SUBd; + +#define ORD(op1,op2,load,save) \ + lf_var1d=load(op1);lf_var2d=op2; \ + lf_resd=lf_var1d | lf_var2d; \ + save(op1,lf_resd); \ + lflags.type=t_ORd; + +#define XORD(op1,op2,load,save) \ + lf_var1d=load(op1);lf_var2d=op2; \ + lf_resd=lf_var1d ^ lf_var2d; \ + save(op1,lf_resd); \ + lflags.type=t_XORd; + +#define ANDD(op1,op2,load,save) \ + lf_var1d=load(op1);lf_var2d=op2; \ + lf_resd=lf_var1d & lf_var2d; \ + save(op1,lf_resd); \ + lflags.type=t_ANDd; + +#define CMPD(op1,op2,load,save) \ + lf_var1d=load(op1);lf_var2d=op2; \ + lf_resd=lf_var1d-lf_var2d; \ + lflags.type=t_CMPd; + + +#define TESTD(op1,op2,load,save) \ + lf_var1d=load(op1);lf_var2d=op2; \ + lf_resd=lf_var1d & lf_var2d; \ + lflags.type=t_TESTd; + + + + +#define INCB(op1,load,save) \ + LoadCF;lf_var1b=load(op1); \ + lf_resb=lf_var1b+1; \ + save(op1,lf_resb); \ + lflags.type=t_INCb; \ + +#define INCW(op1,load,save) \ + LoadCF;lf_var1w=load(op1); \ + lf_resw=lf_var1w+1; \ + save(op1,lf_resw); \ + lflags.type=t_INCw; + +#define INCD(op1,load,save) \ + LoadCF;lf_var1d=load(op1); \ + lf_resd=lf_var1d+1; \ + save(op1,lf_resd); \ + lflags.type=t_INCd; + +#define DECB(op1,load,save) \ + LoadCF;lf_var1b=load(op1); \ + lf_resb=lf_var1b-1; \ + save(op1,lf_resb); \ + lflags.type=t_DECb; + +#define DECW(op1,load,save) \ + LoadCF;lf_var1w=load(op1); \ + lf_resw=lf_var1w-1; \ + save(op1,lf_resw); \ + lflags.type=t_DECw; + +#define DECD(op1,load,save) \ + LoadCF;lf_var1d=load(op1); \ + lf_resd=lf_var1d-1; \ + save(op1,lf_resd); \ + lflags.type=t_DECd; + + + +#define ROLB(op1,op2,load,save) \ + if (!(op2&0x7)) { \ + if (op2&0x18) { \ + FillFlagsNoCFOF(); \ + SETFLAGBIT(CF,op1 & 1); \ + SETFLAGBIT(OF,(op1 & 1) ^ (op1 >> 7)); \ + } \ + break; \ + } \ + FillFlagsNoCFOF(); \ + lf_var1b=load(op1); \ + lf_var2b=op2&0x07; \ + lf_resb=(lf_var1b << lf_var2b) | \ + (lf_var1b >> (8-lf_var2b)); \ + save(op1,lf_resb); \ + SETFLAGBIT(CF,lf_resb & 1); \ + SETFLAGBIT(OF,(lf_resb & 1) ^ (lf_resb >> 7)); + +#define ROLW(op1,op2,load,save) \ + if (!(op2&0xf)) { \ + if (op2&0x10) { \ + FillFlagsNoCFOF(); \ + SETFLAGBIT(CF,op1 & 1); \ + SETFLAGBIT(OF,(op1 & 1) ^ (op1 >> 15)); \ + } \ + break; \ + } \ + FillFlagsNoCFOF(); \ + lf_var1w=load(op1); \ + lf_var2b=op2&0xf; \ + lf_resw=(lf_var1w << lf_var2b) | \ + (lf_var1w >> (16-lf_var2b)); \ + save(op1,lf_resw); \ + SETFLAGBIT(CF,lf_resw & 1); \ + SETFLAGBIT(OF,(lf_resw & 1) ^ (lf_resw >> 15)); + +#define ROLD(op1,op2,load,save) \ + if (!op2) break; \ + FillFlagsNoCFOF(); \ + lf_var1d=load(op1); \ + lf_var2b=op2; \ + lf_resd=(lf_var1d << lf_var2b) | \ + (lf_var1d >> (32-lf_var2b)); \ + save(op1,lf_resd); \ + SETFLAGBIT(CF,lf_resd & 1); \ + SETFLAGBIT(OF,(lf_resd & 1) ^ (lf_resd >> 31)); + + +#define RORB(op1,op2,load,save) \ + if (!(op2&0x7)) { \ + if (op2&0x18) { \ + FillFlagsNoCFOF(); \ + SETFLAGBIT(CF,op1>>7); \ + SETFLAGBIT(OF,(op1>>7) ^ ((op1>>6) & 1)); \ + } \ + break; \ + } \ + FillFlagsNoCFOF(); \ + lf_var1b=load(op1); \ + lf_var2b=op2&0x07; \ + lf_resb=(lf_var1b >> lf_var2b) | \ + (lf_var1b << (8-lf_var2b)); \ + save(op1,lf_resb); \ + SETFLAGBIT(CF,lf_resb & 0x80); \ + SETFLAGBIT(OF,(lf_resb ^ (lf_resb<<1)) & 0x80); + +#define RORW(op1,op2,load,save) \ + if (!(op2&0xf)) { \ + if (op2&0x10) { \ + FillFlagsNoCFOF(); \ + SETFLAGBIT(CF,op1>>15); \ + SETFLAGBIT(OF,(op1>>15) ^ ((op1>>14) & 1)); \ + } \ + break; \ + } \ + FillFlagsNoCFOF(); \ + lf_var1w=load(op1); \ + lf_var2b=op2&0xf; \ + lf_resw=(lf_var1w >> lf_var2b) | \ + (lf_var1w << (16-lf_var2b)); \ + save(op1,lf_resw); \ + SETFLAGBIT(CF,lf_resw & 0x8000); \ + SETFLAGBIT(OF,(lf_resw ^ (lf_resw<<1)) & 0x8000); + +#define RORD(op1,op2,load,save) \ + if (!op2) break; \ + FillFlagsNoCFOF(); \ + lf_var1d=load(op1); \ + lf_var2b=op2; \ + lf_resd=(lf_var1d >> lf_var2b) | \ + (lf_var1d << (32-lf_var2b)); \ + save(op1,lf_resd); \ + SETFLAGBIT(CF,lf_resd & 0x80000000); \ + SETFLAGBIT(OF,(lf_resd ^ (lf_resd<<1)) & 0x80000000); + + +#define RCLB(op1,op2,load,save) \ + if (!(op2%9)) break; \ +{ Bit8u cf=(Bit8u)FillFlags()&0x1; \ + lf_var1b=load(op1); \ + lf_var2b=op2%9; \ + lf_resb=(lf_var1b << lf_var2b) | \ + (cf << (lf_var2b-1)) | \ + (lf_var1b >> (9-lf_var2b)); \ + save(op1,lf_resb); \ + SETFLAGBIT(CF,((lf_var1b >> (8-lf_var2b)) & 1)); \ + SETFLAGBIT(OF,(reg_flags & 1) ^ (lf_resb >> 7)); \ +} + +#define RCLW(op1,op2,load,save) \ + if (!(op2%17)) break; \ +{ Bit16u cf=(Bit16u)FillFlags()&0x1; \ + lf_var1w=load(op1); \ + lf_var2b=op2%17; \ + lf_resw=(lf_var1w << lf_var2b) | \ + (cf << (lf_var2b-1)) | \ + (lf_var1w >> (17-lf_var2b)); \ + save(op1,lf_resw); \ + SETFLAGBIT(CF,((lf_var1w >> (16-lf_var2b)) & 1)); \ + SETFLAGBIT(OF,(reg_flags & 1) ^ (lf_resw >> 15)); \ +} + +#define RCLD(op1,op2,load,save) \ + if (!op2) break; \ +{ Bit32u cf=(Bit32u)FillFlags()&0x1; \ + lf_var1d=load(op1); \ + lf_var2b=op2; \ + if (lf_var2b==1) { \ + lf_resd=(lf_var1d << 1) | cf; \ + } else { \ + lf_resd=(lf_var1d << lf_var2b) | \ + (cf << (lf_var2b-1)) | \ + (lf_var1d >> (33-lf_var2b)); \ + } \ + save(op1,lf_resd); \ + SETFLAGBIT(CF,((lf_var1d >> (32-lf_var2b)) & 1)); \ + SETFLAGBIT(OF,(reg_flags & 1) ^ (lf_resd >> 31)); \ +} + + + +#define RCRB(op1,op2,load,save) \ + if (op2%9) { \ + Bit8u cf=(Bit8u)FillFlags()&0x1; \ + lf_var1b=load(op1); \ + lf_var2b=op2%9; \ + lf_resb=(lf_var1b >> lf_var2b) | \ + (cf << (8-lf_var2b)) | \ + (lf_var1b << (9-lf_var2b)); \ + save(op1,lf_resb); \ + SETFLAGBIT(CF,(lf_var1b >> (lf_var2b - 1)) & 1); \ + SETFLAGBIT(OF,(lf_resb ^ (lf_resb<<1)) & 0x80); \ + } + +#define RCRW(op1,op2,load,save) \ + if (op2%17) { \ + Bit16u cf=(Bit16u)FillFlags()&0x1; \ + lf_var1w=load(op1); \ + lf_var2b=op2%17; \ + lf_resw=(lf_var1w >> lf_var2b) | \ + (cf << (16-lf_var2b)) | \ + (lf_var1w << (17-lf_var2b)); \ + save(op1,lf_resw); \ + SETFLAGBIT(CF,(lf_var1w >> (lf_var2b - 1)) & 1); \ + SETFLAGBIT(OF,(lf_resw ^ (lf_resw<<1)) & 0x8000); \ + } + +#define RCRD(op1,op2,load,save) \ + if (op2) { \ + Bit32u cf=(Bit32u)FillFlags()&0x1; \ + lf_var1d=load(op1); \ + lf_var2b=op2; \ + if (lf_var2b==1) { \ + lf_resd=lf_var1d >> 1 | cf << 31; \ + } else { \ + lf_resd=(lf_var1d >> lf_var2b) | \ + (cf << (32-lf_var2b)) | \ + (lf_var1d << (33-lf_var2b)); \ + } \ + save(op1,lf_resd); \ + SETFLAGBIT(CF,(lf_var1d >> (lf_var2b - 1)) & 1); \ + SETFLAGBIT(OF,(lf_resd ^ (lf_resd<<1)) & 0x80000000); \ + } + + +#define SHLB(op1,op2,load,save) \ + if (!op2) break; \ + lf_var1b=load(op1);lf_var2b=op2; \ + lf_resb=lf_var1b << lf_var2b; \ + save(op1,lf_resb); \ + lflags.type=t_SHLb; + +#define SHLW(op1,op2,load,save) \ + if (!op2) break; \ + lf_var1w=load(op1);lf_var2b=op2 ; \ + lf_resw=lf_var1w << lf_var2b; \ + save(op1,lf_resw); \ + lflags.type=t_SHLw; + +#define SHLD(op1,op2,load,save) \ + if (!op2) break; \ + lf_var1d=load(op1);lf_var2b=op2; \ + lf_resd=lf_var1d << lf_var2b; \ + save(op1,lf_resd); \ + lflags.type=t_SHLd; + + +#define SHRB(op1,op2,load,save) \ + if (!op2) break; \ + lf_var1b=load(op1);lf_var2b=op2; \ + lf_resb=lf_var1b >> lf_var2b; \ + save(op1,lf_resb); \ + lflags.type=t_SHRb; + +#define SHRW(op1,op2,load,save) \ + if (!op2) break; \ + lf_var1w=load(op1);lf_var2b=op2; \ + lf_resw=lf_var1w >> lf_var2b; \ + save(op1,lf_resw); \ + lflags.type=t_SHRw; + +#define SHRD(op1,op2,load,save) \ + if (!op2) break; \ + lf_var1d=load(op1);lf_var2b=op2; \ + lf_resd=lf_var1d >> lf_var2b; \ + save(op1,lf_resd); \ + lflags.type=t_SHRd; + + +#define SARB(op1,op2,load,save) \ + if (!op2) break; \ + lf_var1b=load(op1);lf_var2b=op2; \ + if (lf_var2b>8) lf_var2b=8; \ + if (lf_var1b & 0x80) { \ + lf_resb=(lf_var1b >> lf_var2b)| \ + (0xff << (8 - lf_var2b)); \ + } else { \ + lf_resb=lf_var1b >> lf_var2b; \ + } \ + save(op1,lf_resb); \ + lflags.type=t_SARb; + +#define SARW(op1,op2,load,save) \ + if (!op2) break; \ + lf_var1w=load(op1);lf_var2b=op2; \ + if (lf_var2b>16) lf_var2b=16; \ + if (lf_var1w & 0x8000) { \ + lf_resw=(lf_var1w >> lf_var2b)| \ + (0xffff << (16 - lf_var2b)); \ + } else { \ + lf_resw=lf_var1w >> lf_var2b; \ + } \ + save(op1,lf_resw); \ + lflags.type=t_SARw; + +#define SARD(op1,op2,load,save) \ + if (!op2) break; \ + lf_var2b=op2;lf_var1d=load(op1); \ + if (lf_var1d & 0x80000000) { \ + lf_resd=(lf_var1d >> lf_var2b)| \ + (0xffffffff << (32 - lf_var2b)); \ + } else { \ + lf_resd=lf_var1d >> lf_var2b; \ + } \ + save(op1,lf_resd); \ + lflags.type=t_SARd; + + + +#define DAA() \ + if (((reg_al & 0x0F)>0x09) || get_AF()) { \ + if ((reg_al > 0x99) || get_CF()) { \ + reg_al+=0x60; \ + SETFLAGBIT(CF,true); \ + } else { \ + SETFLAGBIT(CF,false); \ + } \ + reg_al+=0x06; \ + SETFLAGBIT(AF,true); \ + } else { \ + if ((reg_al > 0x99) || get_CF()) { \ + reg_al+=0x60; \ + SETFLAGBIT(CF,true); \ + } else { \ + SETFLAGBIT(CF,false); \ + } \ + SETFLAGBIT(AF,false); \ + } \ + SETFLAGBIT(SF,(reg_al&0x80)); \ + SETFLAGBIT(ZF,(reg_al==0)); \ + SETFLAGBIT(PF,parity_lookup[reg_al]); \ + lflags.type=t_UNKNOWN; + + +#define DAS() \ +{ \ + Bit8u osigned=reg_al & 0x80; \ + if (((reg_al & 0x0f) > 9) || get_AF()) { \ + if ((reg_al>0x99) || get_CF()) { \ + reg_al-=0x60; \ + SETFLAGBIT(CF,true); \ + } else { \ + SETFLAGBIT(CF,(reg_al<=0x05)); \ + } \ + reg_al-=6; \ + SETFLAGBIT(AF,true); \ + } else { \ + if ((reg_al>0x99) || get_CF()) { \ + reg_al-=0x60; \ + SETFLAGBIT(CF,true); \ + } else { \ + SETFLAGBIT(CF,false); \ + } \ + SETFLAGBIT(AF,false); \ + } \ + SETFLAGBIT(OF,osigned && ((reg_al&0x80)==0)); \ + SETFLAGBIT(SF,(reg_al&0x80)); \ + SETFLAGBIT(ZF,(reg_al==0)); \ + SETFLAGBIT(PF,parity_lookup[reg_al]); \ + lflags.type=t_UNKNOWN; \ +} + + +#define AAA() \ + SETFLAGBIT(SF,((reg_al>=0x7a) && (reg_al<=0xf9))); \ + if ((reg_al & 0xf) > 9) { \ + SETFLAGBIT(OF,(reg_al&0xf0)==0x70); \ + reg_ax += 0x106; \ + SETFLAGBIT(CF,true); \ + SETFLAGBIT(ZF,(reg_al == 0)); \ + SETFLAGBIT(AF,true); \ + } else if (get_AF()) { \ + reg_ax += 0x106; \ + SETFLAGBIT(OF,false); \ + SETFLAGBIT(CF,true); \ + SETFLAGBIT(ZF,false); \ + SETFLAGBIT(AF,true); \ + } else { \ + SETFLAGBIT(OF,false); \ + SETFLAGBIT(CF,false); \ + SETFLAGBIT(ZF,(reg_al == 0)); \ + SETFLAGBIT(AF,false); \ + } \ + SETFLAGBIT(PF,parity_lookup[reg_al]); \ + reg_al &= 0x0F; \ + lflags.type=t_UNKNOWN; + +#define AAS() \ + if ((reg_al & 0x0f)>9) { \ + SETFLAGBIT(SF,(reg_al>0x85)); \ + reg_ax -= 0x106; \ + SETFLAGBIT(OF,false); \ + SETFLAGBIT(CF,true); \ + SETFLAGBIT(AF,true); \ + } else if (get_AF()) { \ + SETFLAGBIT(OF,((reg_al>=0x80) && (reg_al<=0x85))); \ + SETFLAGBIT(SF,(reg_al<0x06) || (reg_al>0x85)); \ + reg_ax -= 0x106; \ + SETFLAGBIT(CF,true); \ + SETFLAGBIT(AF,true); \ + } else { \ + SETFLAGBIT(SF,(reg_al>=0x80)); \ + SETFLAGBIT(OF,false); \ + SETFLAGBIT(CF,false); \ + SETFLAGBIT(AF,false); \ + } \ + SETFLAGBIT(ZF,(reg_al == 0)); \ + SETFLAGBIT(PF,parity_lookup[reg_al]); \ + reg_al &= 0x0F; \ + lflags.type=t_UNKNOWN; + +#define AAM(op1) \ +{ \ + Bit8u dv=op1; \ + if (dv!=0) { \ + reg_ah=reg_al / dv; \ + reg_al=reg_al % dv; \ + SETFLAGBIT(SF,(reg_al & 0x80)); \ + SETFLAGBIT(ZF,(reg_al == 0)); \ + SETFLAGBIT(PF,parity_lookup[reg_al]); \ + SETFLAGBIT(CF,false); \ + SETFLAGBIT(OF,false); \ + SETFLAGBIT(AF,false); \ + lflags.type=t_UNKNOWN; \ + } else EXCEPTION(0); \ +} + + +//Took this from bochs, i seriously hate these weird bcd opcodes +#define AAD(op1) \ + { \ + Bit16u ax1 = reg_ah * op1; \ + Bit16u ax2 = ax1 + reg_al; \ + reg_al = (Bit8u) ax2; \ + reg_ah = 0; \ + SETFLAGBIT(CF,false); \ + SETFLAGBIT(OF,false); \ + SETFLAGBIT(AF,false); \ + SETFLAGBIT(SF,reg_al >= 0x80); \ + SETFLAGBIT(ZF,reg_al == 0); \ + SETFLAGBIT(PF,parity_lookup[reg_al]); \ + lflags.type=t_UNKNOWN; \ + } + +#define MULB(op1,load,save) \ + reg_ax=reg_al*load(op1); \ + FillFlagsNoCFOF(); \ + SETFLAGBIT(ZF,reg_al == 0); \ + if (reg_ax & 0xff00) { \ + SETFLAGBIT(CF,true);SETFLAGBIT(OF,true); \ + } else { \ + SETFLAGBIT(CF,false);SETFLAGBIT(OF,false); \ + } + +#define MULW(op1,load,save) \ +{ \ + Bitu tempu=(Bitu)reg_ax*(Bitu)(load(op1)); \ + reg_ax=(Bit16u)(tempu); \ + reg_dx=(Bit16u)(tempu >> 16); \ + FillFlagsNoCFOF(); \ + SETFLAGBIT(ZF,reg_ax == 0); \ + if (reg_dx) { \ + SETFLAGBIT(CF,true);SETFLAGBIT(OF,true); \ + } else { \ + SETFLAGBIT(CF,false);SETFLAGBIT(OF,false); \ + } \ +} + +#define MULD(op1,load,save) \ +{ \ + Bit64u tempu=(Bit64u)reg_eax*(Bit64u)(load(op1)); \ + reg_eax=(Bit32u)(tempu); \ + reg_edx=(Bit32u)(tempu >> 32); \ + FillFlagsNoCFOF(); \ + SETFLAGBIT(ZF,reg_eax == 0); \ + if (reg_edx) { \ + SETFLAGBIT(CF,true);SETFLAGBIT(OF,true); \ + } else { \ + SETFLAGBIT(CF,false);SETFLAGBIT(OF,false); \ + } \ +} + +#define DIVB(op1,load,save) \ +{ \ + Bitu val=load(op1); \ + if (val==0) EXCEPTION(0); \ + Bitu quo=reg_ax / val; \ + Bit8u rem=(Bit8u)(reg_ax % val); \ + Bit8u quo8=(Bit8u)(quo&0xff); \ + if (quo>0xff) EXCEPTION(0); \ + reg_ah=rem; \ + reg_al=quo8; \ +} + + +#define DIVW(op1,load,save) \ +{ \ + Bitu val=load(op1); \ + if (val==0) EXCEPTION(0); \ + Bitu num=((Bit32u)reg_dx<<16)|reg_ax; \ + Bitu quo=num/val; \ + Bit16u rem=(Bit16u)(num % val); \ + Bit16u quo16=(Bit16u)(quo&0xffff); \ + if (quo!=(Bit32u)quo16) EXCEPTION(0); \ + reg_dx=rem; \ + reg_ax=quo16; \ +} + +#define DIVD(op1,load,save) \ +{ \ + Bitu val=load(op1); \ + if (val==0) EXCEPTION(0); \ + Bit64u num=(((Bit64u)reg_edx)<<32)|reg_eax; \ + Bit64u quo=num/val; \ + Bit32u rem=(Bit32u)(num % val); \ + Bit32u quo32=(Bit32u)(quo&0xffffffff); \ + if (quo!=(Bit64u)quo32) EXCEPTION(0); \ + reg_edx=rem; \ + reg_eax=quo32; \ +} + + +#define IDIVB(op1,load,save) \ +{ \ + Bits val=(Bit8s)(load(op1)); \ + if (val==0) EXCEPTION(0); \ + Bits quo=((Bit16s)reg_ax) / val; \ + Bit8s rem=(Bit8s)((Bit16s)reg_ax % val); \ + Bit8s quo8s=(Bit8s)(quo&0xff); \ + if (quo!=(Bit16s)quo8s) EXCEPTION(0); \ + reg_ah=rem; \ + reg_al=quo8s; \ +} + + +#define IDIVW(op1,load,save) \ +{ \ + Bits val=(Bit16s)(load(op1)); \ + if (val==0) EXCEPTION(0); \ + Bits num=(Bit32s)((reg_dx<<16)|reg_ax); \ + Bits quo=num/val; \ + Bit16s rem=(Bit16s)(num % val); \ + Bit16s quo16s=(Bit16s)quo; \ + if (quo!=(Bit32s)quo16s) EXCEPTION(0); \ + reg_dx=rem; \ + reg_ax=quo16s; \ +} + +#define IDIVD(op1,load,save) \ +{ \ + Bits val=(Bit32s)(load(op1)); \ + if (val==0) EXCEPTION(0); \ + Bit64s num=(((Bit64u)reg_edx)<<32)|reg_eax; \ + Bit64s quo=num/val; \ + Bit32s rem=(Bit32s)(num % val); \ + Bit32s quo32s=(Bit32s)(quo&0xffffffff); \ + if (quo!=(Bit64s)quo32s) EXCEPTION(0); \ + reg_edx=rem; \ + reg_eax=quo32s; \ +} + +#define IMULB(op1,load,save) \ +{ \ + reg_ax=((Bit8s)reg_al) * ((Bit8s)(load(op1))); \ + FillFlagsNoCFOF(); \ + if ((reg_ax & 0xff80)==0xff80 || \ + (reg_ax & 0xff80)==0x0000) { \ + SETFLAGBIT(CF,false);SETFLAGBIT(OF,false); \ + } else { \ + SETFLAGBIT(CF,true);SETFLAGBIT(OF,true); \ + } \ +} + + +#define IMULW(op1,load,save) \ +{ \ + Bits temps=((Bit16s)reg_ax)*((Bit16s)(load(op1))); \ + reg_ax=(Bit16s)(temps); \ + reg_dx=(Bit16s)(temps >> 16); \ + FillFlagsNoCFOF(); \ + if (((temps & 0xffff8000)==0xffff8000 || \ + (temps & 0xffff8000)==0x0000)) { \ + SETFLAGBIT(CF,false);SETFLAGBIT(OF,false); \ + } else { \ + SETFLAGBIT(CF,true);SETFLAGBIT(OF,true); \ + } \ +} + +#define IMULD(op1,load,save) \ +{ \ + Bit64s temps=((Bit64s)((Bit32s)reg_eax))* \ + ((Bit64s)((Bit32s)(load(op1)))); \ + reg_eax=(Bit32u)(temps); \ + reg_edx=(Bit32u)(temps >> 32); \ + FillFlagsNoCFOF(); \ + if ((reg_edx==0xffffffff) && \ + (reg_eax & 0x80000000) ) { \ + SETFLAGBIT(CF,false);SETFLAGBIT(OF,false); \ + } else if ( (reg_edx==0x00000000) && \ + (reg_eax< 0x80000000) ) { \ + SETFLAGBIT(CF,false);SETFLAGBIT(OF,false); \ + } else { \ + SETFLAGBIT(CF,true);SETFLAGBIT(OF,true); \ + } \ +} + +#define DIMULW(op1,op2,op3,load,save) \ +{ \ + Bits res=((Bit16s)op2) * ((Bit16s)op3); \ + save(op1,res & 0xffff); \ + FillFlagsNoCFOF(); \ + if ((res> -32768) && (res<32767)) { \ + SETFLAGBIT(CF,false);SETFLAGBIT(OF,false); \ + } else { \ + SETFLAGBIT(CF,true);SETFLAGBIT(OF,true); \ + } \ +} + +#define DIMULD(op1,op2,op3,load,save) \ +{ \ + Bit64s res=((Bit64s)((Bit32s)op2))*((Bit64s)((Bit32s)op3)); \ + save(op1,(Bit32s)res); \ + FillFlagsNoCFOF(); \ + if ((res>-((Bit64s)(2147483647)+1)) && \ + (res<(Bit64s)2147483647)) { \ + SETFLAGBIT(CF,false);SETFLAGBIT(OF,false); \ + } else { \ + SETFLAGBIT(CF,true);SETFLAGBIT(OF,true); \ + } \ +} + +#define GRP2B(blah) \ +{ \ + GetRM;Bitu which=(rm>>3)&7; \ + if (rm >= 0xc0) { \ + GetEArb; \ + Bit8u val=blah & 0x1f; \ + switch (which) { \ + case 0x00:ROLB(*earb,val,LoadRb,SaveRb);break; \ + case 0x01:RORB(*earb,val,LoadRb,SaveRb);break; \ + case 0x02:RCLB(*earb,val,LoadRb,SaveRb);break; \ + case 0x03:RCRB(*earb,val,LoadRb,SaveRb);break; \ + case 0x04:/* SHL and SAL are the same */ \ + case 0x06:SHLB(*earb,val,LoadRb,SaveRb);break; \ + case 0x05:SHRB(*earb,val,LoadRb,SaveRb);break; \ + case 0x07:SARB(*earb,val,LoadRb,SaveRb);break; \ + } \ + } else { \ + GetEAa; \ + Bit8u val=blah & 0x1f; \ + switch (which) { \ + case 0x00:ROLB(eaa,val,LoadMb,SaveMb);break; \ + case 0x01:RORB(eaa,val,LoadMb,SaveMb);break; \ + case 0x02:RCLB(eaa,val,LoadMb,SaveMb);break; \ + case 0x03:RCRB(eaa,val,LoadMb,SaveMb);break; \ + case 0x04:/* SHL and SAL are the same */ \ + case 0x06:SHLB(eaa,val,LoadMb,SaveMb);break; \ + case 0x05:SHRB(eaa,val,LoadMb,SaveMb);break; \ + case 0x07:SARB(eaa,val,LoadMb,SaveMb);break; \ + } \ + } \ +} + + + +#define GRP2W(blah) \ +{ \ + GetRM;Bitu which=(rm>>3)&7; \ + if (rm >= 0xc0) { \ + GetEArw; \ + Bit8u val=blah & 0x1f; \ + switch (which) { \ + case 0x00:ROLW(*earw,val,LoadRw,SaveRw);break; \ + case 0x01:RORW(*earw,val,LoadRw,SaveRw);break; \ + case 0x02:RCLW(*earw,val,LoadRw,SaveRw);break; \ + case 0x03:RCRW(*earw,val,LoadRw,SaveRw);break; \ + case 0x04:/* SHL and SAL are the same */ \ + case 0x06:SHLW(*earw,val,LoadRw,SaveRw);break; \ + case 0x05:SHRW(*earw,val,LoadRw,SaveRw);break; \ + case 0x07:SARW(*earw,val,LoadRw,SaveRw);break; \ + } \ + } else { \ + GetEAa; \ + Bit8u val=blah & 0x1f; \ + switch (which) { \ + case 0x00:ROLW(eaa,val,LoadMw,SaveMw);break; \ + case 0x01:RORW(eaa,val,LoadMw,SaveMw);break; \ + case 0x02:RCLW(eaa,val,LoadMw,SaveMw);break; \ + case 0x03:RCRW(eaa,val,LoadMw,SaveMw);break; \ + case 0x04:/* SHL and SAL are the same */ \ + case 0x06:SHLW(eaa,val,LoadMw,SaveMw);break; \ + case 0x05:SHRW(eaa,val,LoadMw,SaveMw);break; \ + case 0x07:SARW(eaa,val,LoadMw,SaveMw);break; \ + } \ + } \ +} + + +#define GRP2D(blah) \ +{ \ + GetRM;Bitu which=(rm>>3)&7; \ + if (rm >= 0xc0) { \ + GetEArd; \ + Bit8u val=blah & 0x1f; \ + switch (which) { \ + case 0x00:ROLD(*eard,val,LoadRd,SaveRd);break; \ + case 0x01:RORD(*eard,val,LoadRd,SaveRd);break; \ + case 0x02:RCLD(*eard,val,LoadRd,SaveRd);break; \ + case 0x03:RCRD(*eard,val,LoadRd,SaveRd);break; \ + case 0x04:/* SHL and SAL are the same */ \ + case 0x06:SHLD(*eard,val,LoadRd,SaveRd);break; \ + case 0x05:SHRD(*eard,val,LoadRd,SaveRd);break; \ + case 0x07:SARD(*eard,val,LoadRd,SaveRd);break; \ + } \ + } else { \ + GetEAa; \ + Bit8u val=blah & 0x1f; \ + switch (which) { \ + case 0x00:ROLD(eaa,val,LoadMd,SaveMd);break; \ + case 0x01:RORD(eaa,val,LoadMd,SaveMd);break; \ + case 0x02:RCLD(eaa,val,LoadMd,SaveMd);break; \ + case 0x03:RCRD(eaa,val,LoadMd,SaveMd);break; \ + case 0x04:/* SHL and SAL are the same */ \ + case 0x06:SHLD(eaa,val,LoadMd,SaveMd);break; \ + case 0x05:SHRD(eaa,val,LoadMd,SaveMd);break; \ + case 0x07:SARD(eaa,val,LoadMd,SaveMd);break; \ + } \ + } \ +} + +/* let's hope bochs has it correct with the higher than 16 shifts */ +/* double-precision shift left has low bits in second argument */ +#define DSHLW(op1,op2,op3,load,save) \ + Bit8u val=op3 & 0x1F; \ + if (!val) break; \ + lf_var2b=val;lf_var1d=(load(op1)<<16)|op2; \ + Bit32u tempd=lf_var1d << lf_var2b; \ + if (lf_var2b>16) tempd |= (op2 << (lf_var2b - 16)); \ + lf_resw=(Bit16u)(tempd >> 16); \ + save(op1,lf_resw); \ + lflags.type=t_DSHLw; + +#define DSHLD(op1,op2,op3,load,save) \ + Bit8u val=op3 & 0x1F; \ + if (!val) break; \ + lf_var2b=val;lf_var1d=load(op1); \ + lf_resd=(lf_var1d << lf_var2b) | (op2 >> (32-lf_var2b)); \ + save(op1,lf_resd); \ + lflags.type=t_DSHLd; + +/* double-precision shift right has high bits in second argument */ +#define DSHRW(op1,op2,op3,load,save) \ + Bit8u val=op3 & 0x1F; \ + if (!val) break; \ + lf_var2b=val;lf_var1d=(op2<<16)|load(op1); \ + Bit32u tempd=lf_var1d >> lf_var2b; \ + if (lf_var2b>16) tempd |= (op2 << (32-lf_var2b )); \ + lf_resw=(Bit16u)(tempd); \ + save(op1,lf_resw); \ + lflags.type=t_DSHRw; + +#define DSHRD(op1,op2,op3,load,save) \ + Bit8u val=op3 & 0x1F; \ + if (!val) break; \ + lf_var2b=val;lf_var1d=load(op1); \ + lf_resd=(lf_var1d >> lf_var2b) | (op2 << (32-lf_var2b)); \ + save(op1,lf_resd); \ + lflags.type=t_DSHRd; + +#define BSWAPW(op1) \ + op1 = 0; + +#define BSWAPD(op1) \ + op1 = (op1>>24)|((op1>>8)&0xFF00)|((op1<<8)&0xFF0000)|((op1<<24)&0xFF000000); diff --git a/dosbox/keyboard.cpp b/dosbox/keyboard.cpp new file mode 100644 index 00000000..5f86de02 --- /dev/null +++ b/dosbox/keyboard.cpp @@ -0,0 +1,478 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id: keyboard.cpp,v 1.41 2009-05-27 09:15:41 qbix79 Exp $ */ + +#include "dosbox.h" +#include "keyboard.h" +#include "inout.h" +#include "pic.h" +#include "mem.h" +#include "setup.h" +//#include "mixer.h" +//#include "timer.h" + +extern void write_log(const char*,...); + +#define KEYBUFSIZE 32 +#define KEYDELAY 0.300f //Considering 20-30 khz serial clock and 11 bits/char + +enum KeyCommands { + CMD_NONE, + CMD_SETLEDS, + CMD_SETTYPERATE, + CMD_SETOUTPORT, + CMD_JUMPERS +}; + +static struct { + Bit8u buffer[KEYBUFSIZE]; + Bitu used; + Bitu pos; + struct { +// KBD_KEYS key; + Bitu wait; + Bitu pause,rate; + } repeat; + KeyCommands command; + Bit8u p60data; + bool p60changed; + bool active; + bool scanning; + bool scheduled; + Bit8u outport; +} keyb; + +extern void x86_doirq(unsigned char); + +bool x86_is_keyboard(void) +{ + return keyb.p60changed; +} + +static void KEYBOARD_SetPort60(Bit8u val) { + keyb.p60changed=true; + keyb.p60data=val; +// if (machine==MCH_PCJR) +// PIC_ActivateIRQ(6); +// else +// PIC_ActivateIRQ(1); + x86_doirq(1); +} + +static void KEYBOARD_TransferBuffer(Bitu val) { + keyb.scheduled=false; + if (!keyb.used) { + LOG(LOG_KEYBOARD,LOG_NORMAL)("Transfer started with empty buffer"); + return; + } + KEYBOARD_SetPort60(keyb.buffer[keyb.pos]); + if (++keyb.pos>=KEYBUFSIZE) keyb.pos-=KEYBUFSIZE; + keyb.used--; +} + + +void KEYBOARD_ClrBuffer(void) { + keyb.used=0; + keyb.pos=0; +// PIC_RemoveEvents(KEYBOARD_TransferBuffer); + keyb.scheduled=false; +} + +void KEYBOARD_AddBuffer(Bit8u data) { + if (keyb.used>=KEYBUFSIZE) { + LOG(LOG_KEYBOARD,LOG_NORMAL)("Buffer full, dropping code"); + return; + } + Bitu start=keyb.pos+keyb.used; + if (start>=KEYBUFSIZE) start-=KEYBUFSIZE; + keyb.buffer[start]=data; + keyb.used++; + /* Start up an event to start the first IRQ */ + if (!keyb.scheduled && !keyb.p60changed) { + keyb.scheduled=true; + KEYBOARD_TransferBuffer(0); +// PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY); + } +} + + +static Bitu read_p60(Bitu port,Bitu iolen) { + keyb.p60changed=false; + if (!keyb.scheduled && keyb.used) { + keyb.scheduled=true; + KEYBOARD_TransferBuffer(0); +// PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY); + } + return keyb.p60data; +} + +void x86_init_reset(void); +uint8_t x86_get_jumpers(void); + +static void write_p60(Bitu port,Bitu val,Bitu iolen) { + switch (keyb.command) { + case CMD_NONE: /* None */ + /* No active command this would normally get sent to the keyboard then */ + KEYBOARD_ClrBuffer(); + switch (val) { + case 0xed: /* Set Leds */ + keyb.command=CMD_SETLEDS; + KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ + break; + case 0xee: /* Echo */ + KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ + break; + case 0xf2: /* Identify keyboard */ + /* AT's just send acknowledge */ + KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ + break; + case 0xf3: /* Typematic rate programming */ + keyb.command=CMD_SETTYPERATE; + KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ + break; + case 0xf4: /* Enable keyboard,clear buffer, start scanning */ + LOG(LOG_KEYBOARD,LOG_NORMAL)("Clear buffer,enable Scaning"); + KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ + keyb.scanning=true; + break; + case 0xf5: /* Reset keyboard and disable scanning */ + LOG(LOG_KEYBOARD,LOG_NORMAL)("Reset, disable scanning"); + keyb.scanning=false; + KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ + break; + case 0xf6: /* Reset keyboard and enable scanning */ + LOG(LOG_KEYBOARD,LOG_NORMAL)("Reset, enable scanning"); + KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ + keyb.scanning=false; + break; + case 0xff: + KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ + KEYBOARD_AddBuffer(0xaa); + break; + default: + /* Just always acknowledge strange commands */ + LOG(LOG_KEYBOARD,LOG_ERROR)("60:Unhandled command %X",val); + KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ + } + return; + case CMD_SETOUTPORT: + MEM_A20_Enable((val & 2)>0); + keyb.outport = val; + if (!(val & 1)) { + x86_init_reset(); + } + keyb.command = CMD_NONE; + break; + case CMD_SETTYPERATE: + { + static const int delay[] = { 250, 500, 750, 1000 }; + static const int repeat[] = + { 33,37,42,46,50,54,58,63,67,75,83,92,100, + 109,118,125,133,149,167,182,200,217,233, + 250,270,303,333,370,400,435,476,500 }; + keyb.repeat.pause = delay[(val>>5)&3]; + keyb.repeat.rate = repeat[val&0x1f]; + keyb.command=CMD_NONE; + } + /* Fallthrough! as setleds does what we want */ + case CMD_SETLEDS: + keyb.command=CMD_NONE; + KEYBOARD_ClrBuffer(); + KEYBOARD_AddBuffer(0xfa); /* Acknowledge */ + break; + } +} + +static Bit8u port_61_data = 0; +static Bitu read_p61(Bitu port,Bitu iolen) { + port_61_data^=0x20; + port_61_data^=0x10; + return port_61_data; +} + +extern void TIMER_SetGate2(bool); +static void write_p61(Bitu port,Bitu val,Bitu iolen) { + if ((port_61_data ^ val) & 3) { + if((port_61_data ^ val) & 1) + TIMER_SetGate2(val&0x1); +// PCSPEAKER_SetType(val & 3); + } + port_61_data = val; +} + +static void write_p64(Bitu port,Bitu val,Bitu iolen) { + switch (val) { + case 0xae: /* Activate keyboard */ + keyb.active=true; + if (keyb.used && !keyb.scheduled && !keyb.p60changed) { + keyb.scheduled=true; + KEYBOARD_TransferBuffer(0); + //PIC_AddEvent(KEYBOARD_TransferBuffer,KEYDELAY); + } + LOG(LOG_KEYBOARD,LOG_NORMAL)("Activated"); + break; + case 0xad: /* Deactivate keyboard */ + keyb.active=false; + LOG(LOG_KEYBOARD,LOG_NORMAL)("De-Activated"); + break; + case 0xc0: // read config jumpers + KEYBOARD_SetPort60(x86_get_jumpers()); + break; + case 0xd0: /* Outport on buffer */ + KEYBOARD_SetPort60(MEM_A20_Enabled() ? 0x02 : 0); + break; + case 0xd1: /* Write to outport */ + keyb.command=CMD_SETOUTPORT; + break; + case 0xaa: + KEYBOARD_SetPort60(0x55); + break; + case 0xe0: + // bit 0 = clock line state, 1 = data line state + KEYBOARD_SetPort60((keyb.outport & 30) ? 2 : 3); + break; + case 0xfe: // pulse reset pin + case 0xfc: + case 0xfa: + case 0xf8: + case 0xf6: + case 0xf4: + case 0xf2: + case 0xf0: + x86_init_reset(); + break; + default: + LOG(LOG_KEYBOARD,LOG_ERROR)("Port 64 write with val %d",val); + break; + } +} + +static Bitu read_p64(Bitu port,Bitu iolen) { + Bit8u status= (keyb.outport & 0x7c) | (keyb.p60changed ? 0x1 : 0x0); + return status; +} + +Bitu x86_in_keyboard(Bitu port) +{ + Bitu v = 0xff; + switch (port) { + case 0x60: + v = read_p60(port, 1); + break; + case 0x61: + v = read_p61(port, 1); + break; + case 0x64: + v = read_p64(port, 1); + break; + } + //write_log("read %02x %02x\n", port, v); + return v; +} + +void x86_out_keyboard(Bitu port, Bitu val) +{ + //write_log("write %02x %02x\n", port, val); + switch(port) + { + case 0x60: + write_p60(port, val, 1); + break; + case 0x61: + write_p61(port, val, 1); + break; + case 0x64: + write_p64(port, val, 1); + break; + } +} + +#if 0 +void KEYBOARD_AddKey(KBD_KEYS keytype,bool pressed) { + Bit8u ret=0;bool extend=false; + switch (keytype) { + case KBD_esc:ret=1;break; + case KBD_1:ret=2;break; + case KBD_2:ret=3;break; + case KBD_3:ret=4;break; + case KBD_4:ret=5;break; + case KBD_5:ret=6;break; + case KBD_6:ret=7;break; + case KBD_7:ret=8;break; + case KBD_8:ret=9;break; + case KBD_9:ret=10;break; + case KBD_0:ret=11;break; + + case KBD_minus:ret=12;break; + case KBD_equals:ret=13;break; + case KBD_backspace:ret=14;break; + case KBD_tab:ret=15;break; + + case KBD_q:ret=16;break; + case KBD_w:ret=17;break; + case KBD_e:ret=18;break; + case KBD_r:ret=19;break; + case KBD_t:ret=20;break; + case KBD_y:ret=21;break; + case KBD_u:ret=22;break; + case KBD_i:ret=23;break; + case KBD_o:ret=24;break; + case KBD_p:ret=25;break; + + case KBD_leftbracket:ret=26;break; + case KBD_rightbracket:ret=27;break; + case KBD_enter:ret=28;break; + case KBD_leftctrl:ret=29;break; + + case KBD_a:ret=30;break; + case KBD_s:ret=31;break; + case KBD_d:ret=32;break; + case KBD_f:ret=33;break; + case KBD_g:ret=34;break; + case KBD_h:ret=35;break; + case KBD_j:ret=36;break; + case KBD_k:ret=37;break; + case KBD_l:ret=38;break; + + case KBD_semicolon:ret=39;break; + case KBD_quote:ret=40;break; + case KBD_grave:ret=41;break; + case KBD_leftshift:ret=42;break; + case KBD_backslash:ret=43;break; + case KBD_z:ret=44;break; + case KBD_x:ret=45;break; + case KBD_c:ret=46;break; + case KBD_v:ret=47;break; + case KBD_b:ret=48;break; + case KBD_n:ret=49;break; + case KBD_m:ret=50;break; + + case KBD_comma:ret=51;break; + case KBD_period:ret=52;break; + case KBD_slash:ret=53;break; + case KBD_rightshift:ret=54;break; + case KBD_kpmultiply:ret=55;break; + case KBD_leftalt:ret=56;break; + case KBD_space:ret=57;break; + case KBD_capslock:ret=58;break; + + case KBD_f1:ret=59;break; + case KBD_f2:ret=60;break; + case KBD_f3:ret=61;break; + case KBD_f4:ret=62;break; + case KBD_f5:ret=63;break; + case KBD_f6:ret=64;break; + case KBD_f7:ret=65;break; + case KBD_f8:ret=66;break; + case KBD_f9:ret=67;break; + case KBD_f10:ret=68;break; + + case KBD_numlock:ret=69;break; + case KBD_scrolllock:ret=70;break; + + case KBD_kp7:ret=71;break; + case KBD_kp8:ret=72;break; + case KBD_kp9:ret=73;break; + case KBD_kpminus:ret=74;break; + case KBD_kp4:ret=75;break; + case KBD_kp5:ret=76;break; + case KBD_kp6:ret=77;break; + case KBD_kpplus:ret=78;break; + case KBD_kp1:ret=79;break; + case KBD_kp2:ret=80;break; + case KBD_kp3:ret=81;break; + case KBD_kp0:ret=82;break; + case KBD_kpperiod:ret=83;break; + + case KBD_extra_lt_gt:ret=86;break; + case KBD_f11:ret=87;break; + case KBD_f12:ret=88;break; + + //The Extended keys + + case KBD_kpenter:extend=true;ret=28;break; + case KBD_rightctrl:extend=true;ret=29;break; + case KBD_kpdivide:extend=true;ret=53;break; + case KBD_rightalt:extend=true;ret=56;break; + case KBD_home:extend=true;ret=71;break; + case KBD_up:extend=true;ret=72;break; + case KBD_pageup:extend=true;ret=73;break; + case KBD_left:extend=true;ret=75;break; + case KBD_right:extend=true;ret=77;break; + case KBD_end:extend=true;ret=79;break; + case KBD_down:extend=true;ret=80;break; + case KBD_pagedown:extend=true;ret=81;break; + case KBD_insert:extend=true;ret=82;break; + case KBD_delete:extend=true;ret=83;break; + case KBD_pause: + KEYBOARD_AddBuffer(0xe1); + KEYBOARD_AddBuffer(29|(pressed?0:0x80)); + KEYBOARD_AddBuffer(69|(pressed?0:0x80)); + return; + case KBD_printscreen: + /* Not handled yet. But usuable in mapper for special events */ + return; + default: + E_Exit("Unsupported key press"); + break; + } + /* Add the actual key in the keyboard queue */ + if (pressed) { + if (keyb.repeat.key==keytype) keyb.repeat.wait=keyb.repeat.rate; + else keyb.repeat.wait=keyb.repeat.pause; + keyb.repeat.key=keytype; + } else { + keyb.repeat.key=KBD_NONE; + keyb.repeat.wait=0; + ret+=128; + } + if (extend) KEYBOARD_AddBuffer(0xe0); + KEYBOARD_AddBuffer(ret); +} + +static void KEYBOARD_TickHandler(void) { + if (keyb.repeat.wait) { + keyb.repeat.wait--; + if (!keyb.repeat.wait) KEYBOARD_AddKey(keyb.repeat.key,true); + } +} +#endif + +void KEYBOARD_Init(Section* sec) { +#if 0 + IO_RegisterWriteHandler(0x60,write_p60,IO_MB); + IO_RegisterReadHandler(0x60,read_p60,IO_MB); + IO_RegisterWriteHandler(0x61,write_p61,IO_MB); + IO_RegisterReadHandler(0x61,read_p61,IO_MB); + IO_RegisterWriteHandler(0x64,write_p64,IO_MB); + IO_RegisterReadHandler(0x64,read_p64,IO_MB); +#endif +// TIMER_AddTickHandler(&KEYBOARD_TickHandler); + write_p61(0,0,0); + /* Init the keyb struct */ + keyb.active=true; + keyb.scanning=true; + keyb.command=CMD_NONE; + keyb.p60changed=false; +// keyb.repeat.key=KBD_NONE; + keyb.repeat.pause=500; + keyb.repeat.rate=33; + keyb.repeat.wait=0; + KEYBOARD_ClrBuffer(); +} diff --git a/dosbox/lazyflags.h b/dosbox/lazyflags.h new file mode 100644 index 00000000..a2a031d7 --- /dev/null +++ b/dosbox/lazyflags.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#if !defined __LAZYFLAGS_H +#define __LAZYFLAG_H + +//Flag Handling +Bit32u get_CF(void); +Bit32u get_AF(void); +Bit32u get_ZF(void); +Bit32u get_SF(void); +Bit32u get_OF(void); +Bit32u get_PF(void); + +Bitu FillFlags(void); +void FillFlagsNoCFOF(void); +void DestroyConditionFlags(void); + +#include "regs.h" + +struct LazyFlags { + GenReg32 var1,var2,res; + Bitu type; + Bitu prev_type; + Bitu oldcf; +}; + +extern LazyFlags lfags; + +#define lf_var1b lflags.var1.byte[BL_INDEX] +#define lf_var2b lflags.var2.byte[BL_INDEX] +#define lf_resb lflags.res.byte[BL_INDEX] + +#define lf_var1w lflags.var1.word[W_INDEX] +#define lf_var2w lflags.var2.word[W_INDEX] +#define lf_resw lflags.res.word[W_INDEX] + +#define lf_var1d lflags.var1.dword[DW_INDEX] +#define lf_var2d lflags.var2.dword[DW_INDEX] +#define lf_resd lflags.res.dword[DW_INDEX] + + +extern LazyFlags lflags; + +#define SETFLAGSb(FLAGB) \ +{ \ + SETFLAGBIT(OF,get_OF()); \ + lflags.type=t_UNKNOWN; \ + CPU_SetFlags(FLAGB,FMASK_NORMAL & 0xff); \ +} + +#define SETFLAGSw(FLAGW) \ +{ \ + lflags.type=t_UNKNOWN; \ + CPU_SetFlagsw(FLAGW); \ +} + +#define SETFLAGSd(FLAGD) \ +{ \ + lflags.type=t_UNKNOWN; \ + CPU_SetFlagsd(FLAGD); \ +} + +#define LoadCF SETFLAGBIT(CF,get_CF()); +#define LoadZF SETFLAGBIT(ZF,get_ZF()); +#define LoadSF SETFLAGBIT(SF,get_SF()); +#define LoadOF SETFLAGBIT(OF,get_OF()); +#define LoadAF SETFLAGBIT(AF,get_AF()); + +#define TFLG_O (get_OF()) +#define TFLG_NO (!get_OF()) +#define TFLG_B (get_CF()) +#define TFLG_NB (!get_CF()) +#define TFLG_Z (get_ZF()) +#define TFLG_NZ (!get_ZF()) +#define TFLG_BE (get_CF() || get_ZF()) +#define TFLG_NBE (!get_CF() && !get_ZF()) +#define TFLG_S (get_SF()) +#define TFLG_NS (!get_SF()) +#define TFLG_P (get_PF()) +#define TFLG_NP (!get_PF()) +#define TFLG_L ((get_SF()!=0) != (get_OF()!=0)) +#define TFLG_NL ((get_SF()!=0) == (get_OF()!=0)) +#define TFLG_LE (get_ZF() || ((get_SF()!=0) != (get_OF()!=0))) +#define TFLG_NLE (!get_ZF() && ((get_SF()!=0) == (get_OF()!=0))) + +//Types of Flag changing instructions +enum { + t_UNKNOWN=0, + t_ADDb,t_ADDw,t_ADDd, + t_ORb,t_ORw,t_ORd, + t_ADCb,t_ADCw,t_ADCd, + t_SBBb,t_SBBw,t_SBBd, + t_ANDb,t_ANDw,t_ANDd, + t_SUBb,t_SUBw,t_SUBd, + t_XORb,t_XORw,t_XORd, + t_CMPb,t_CMPw,t_CMPd, + t_INCb,t_INCw,t_INCd, + t_DECb,t_DECw,t_DECd, + t_TESTb,t_TESTw,t_TESTd, + t_SHLb,t_SHLw,t_SHLd, + t_SHRb,t_SHRw,t_SHRd, + t_SARb,t_SARw,t_SARd, + t_ROLb,t_ROLw,t_ROLd, + t_RORb,t_RORw,t_RORd, + t_RCLb,t_RCLw,t_RCLd, + t_RCRb,t_RCRw,t_RCRd, + t_NEGb,t_NEGw,t_NEGd, + + t_DSHLw,t_DSHLd, + t_DSHRw,t_DSHRd, + t_MUL,t_DIV, + t_NOTDONE, + t_LASTFLAG +}; + +#endif diff --git a/dosbox/logging.h b/dosbox/logging.h new file mode 100644 index 00000000..ae3daae9 --- /dev/null +++ b/dosbox/logging.h @@ -0,0 +1,67 @@ +#ifndef DOSBOX_LOGGING_H +#define DOSBOX_LOGGING_H +enum LOG_TYPES { + LOG_ALL, + LOG_VGA, LOG_VGAGFX,LOG_VGAMISC,LOG_INT10, + LOG_SB,LOG_DMACONTROL, + LOG_FPU,LOG_CPU,LOG_PAGING, + LOG_FCB,LOG_FILES,LOG_IOCTL,LOG_EXEC,LOG_DOSMISC, + LOG_PIT,LOG_KEYBOARD,LOG_PIC, + LOG_MOUSE,LOG_BIOS,LOG_GUI,LOG_MISC, + LOG_IO, + LOG_MAX +}; + +enum LOG_SEVERITIES { + LOG_NORMAL, + LOG_WARN, + LOG_ERROR +}; + +#if C_DEBUG +class LOG +{ + LOG_TYPES d_type; + LOG_SEVERITIES d_severity; +public: + + LOG (LOG_TYPES type , LOG_SEVERITIES severity): + d_type(type), + d_severity(severity) + {} + void operator() (char const* buf, ...) GCC_ATTRIBUTE(__format__(__printf__, 2, 3)); //../src/debug/debug_gui.cpp + +}; + +void DEBUG_ShowMsg(char const* format,...) GCC_ATTRIBUTE(__format__(__printf__, 1, 2)); +#define LOG_MSG DEBUG_ShowMsg + +#else //C_DEBUG + +struct LOG +{ + LOG(LOG_TYPES , LOG_SEVERITIES ) { } + void operator()(char const* ) { } + void operator()(char const* , double ) { } + void operator()(char const* , double , double ) { } + void operator()(char const* , double , double , double ) { } + void operator()(char const* , double , double , double , double ) { } + void operator()(char const* , double , double , double , double , double ) { } + + void operator()(char const* , char const* ) { } + void operator()(char const* , char const* , double ) { } + void operator()(char const* , char const* , double ,double ) { } + void operator()(char const* , double , char const* ) { } + void operator()(char const* , double , double, char const* ) { } + void operator()(char const* , char const*, char const*) { } + + +}; //add missing operators to here + //try to avoid anything smaller than bit32... +void GFX_ShowMsg(char const* format,...) GCC_ATTRIBUTE(__format__(__printf__, 1, 2)); +#define LOG_MSG GFX_ShowMsg + +#endif //C_DEBUG + + +#endif //DOSBOX_LOGGING_H diff --git a/dosbox/mem.h b/dosbox/mem.h new file mode 100644 index 00000000..c0226268 --- /dev/null +++ b/dosbox/mem.h @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef DOSBOX_MEM_H +#define DOSBOX_MEM_H + +#ifndef DOSBOX_DOSBOX_H +#include "dosbox.h" +#endif + +typedef Bit32u PhysPt; +typedef Bit8u * HostPt; +typedef Bit32u RealPt; + +typedef Bit32s MemHandle; + +#define MEM_PAGESIZE 4096 + +extern HostPt MemBase; +HostPt GetMemBase(void); + +bool MEM_A20_Enabled(void); +void MEM_A20_Enable(bool enable); + +/* Memory management / EMS mapping */ +HostPt MEM_GetBlockPage(void); +Bitu MEM_FreeTotal(void); //Free 4 kb pages +Bitu MEM_FreeLargest(void); //Largest free 4 kb pages block +Bitu MEM_TotalPages(void); //Total amount of 4 kb pages +Bitu MEM_AllocatedPages(MemHandle handle); // amount of allocated pages of handle +MemHandle MEM_AllocatePages(Bitu pages,bool sequence); +MemHandle MEM_GetNextFreePage(void); +PhysPt MEM_AllocatePage(void); +void MEM_ReleasePages(MemHandle handle); +bool MEM_ReAllocatePages(MemHandle & handle,Bitu pages,bool sequence); + +MemHandle MEM_NextHandle(MemHandle handle); +MemHandle MEM_NextHandleAt(MemHandle handle,Bitu where); + +/* + The folowing six functions are used everywhere in the end so these should be changed for + Working on big or little endian machines +*/ + +#if defined(WORDS_BIGENDIAN) || !defined(C_UNALIGNED_MEMORY) + +void bridge_mono_hit(void); +void bridge_color_hit(void); +extern HostPt mono_start, mono_end, color_start, color_end; +static INLINE void bridge_special_addr_check(HostPt off) +{ + if (off >= mono_start && off < mono_end) + bridge_mono_hit(); + if (off >= color_start && off < color_end) + bridge_color_hit(); +} + +static INLINE Bit8u host_readb(HostPt off) { + return off[0]; +} +static INLINE Bit16u host_readw(HostPt off) { + return off[0] | (off[1] << 8); +} +static INLINE Bit32u host_readd(HostPt off) { + return off[0] | (off[1] << 8) | (off[2] << 16) | (off[3] << 24); +} +static INLINE void host_writeb(HostPt off,Bit8u val) { + bridge_special_addr_check(off); + off[0]=val; +} +static INLINE void host_writew(HostPt off,Bit16u val) { + bridge_special_addr_check(off); + off[0]=(Bit8u)(val); + off[1]=(Bit8u)(val >> 8); +} +static INLINE void host_writed(HostPt off,Bit32u val) { + bridge_special_addr_check(off); + off[0]=(Bit8u)(val); + off[1]=(Bit8u)(val >> 8); + off[2]=(Bit8u)(val >> 16); + off[3]=(Bit8u)(val >> 24); +} + +#else + +static INLINE Bit8u host_readb(HostPt off) { + return *(Bit8u *)off; +} +static INLINE Bit16u host_readw(HostPt off) { + return *(Bit16u *)off; +} +static INLINE Bit32u host_readd(HostPt off) { + return *(Bit32u *)off; +} +static INLINE void host_writeb(HostPt off,Bit8u val) { + *(Bit8u *)(off)=val; +} +static INLINE void host_writew(HostPt off,Bit16u val) { + *(Bit16u *)(off)=val; +} +static INLINE void host_writed(HostPt off,Bit32u val) { + *(Bit32u *)(off)=val; +} + +#endif + + +static INLINE void var_write(Bit8u * var, Bit8u val) { + host_writeb((HostPt)var, val); +} + +static INLINE void var_write(Bit16u * var, Bit16u val) { + host_writew((HostPt)var, val); +} + +static INLINE void var_write(Bit32u * var, Bit32u val) { + host_writed((HostPt)var, val); +} + +/* The Folowing six functions are slower but they recognize the paged memory system */ + +Bit8u mem_readb(PhysPt pt); +Bit16u mem_readw(PhysPt pt); +Bit32u mem_readd(PhysPt pt); + +void mem_writeb(PhysPt pt,Bit8u val); +void mem_writew(PhysPt pt,Bit16u val); +void mem_writed(PhysPt pt,Bit32u val); + +static INLINE void phys_writeb(PhysPt addr,Bit8u val) { + host_writeb(MemBase+addr,val); +} +static INLINE void phys_writew(PhysPt addr,Bit16u val){ + host_writew(MemBase+addr,val); +} +static INLINE void phys_writed(PhysPt addr,Bit32u val){ + host_writed(MemBase+addr,val); +} + +static INLINE Bit8u phys_readb(PhysPt addr) { + return host_readb(MemBase+addr); +} +static INLINE Bit16u phys_readw(PhysPt addr){ + return host_readw(MemBase+addr); +} +static INLINE Bit32u phys_readd(PhysPt addr){ + return host_readd(MemBase+addr); +} + +/* These don't check for alignment, better be sure it's correct */ + +void MEM_BlockWrite(PhysPt pt,void const * const data,Bitu size); +void MEM_BlockRead(PhysPt pt,void * data,Bitu size); +void MEM_BlockCopy(PhysPt dest,PhysPt src,Bitu size); +void MEM_StrCopy(PhysPt pt,char * data,Bitu size); + +void mem_memcpy(PhysPt dest,PhysPt src,Bitu size); +Bitu mem_strlen(PhysPt pt); +void mem_strcpy(PhysPt dest,PhysPt src); + +/* The folowing functions are all shortcuts to the above functions using physical addressing */ + +static INLINE Bit8u real_readb(Bit16u seg,Bit16u off) { + return mem_readb((seg<<4)+off); +} +static INLINE Bit16u real_readw(Bit16u seg,Bit16u off) { + return mem_readw((seg<<4)+off); +} +static INLINE Bit32u real_readd(Bit16u seg,Bit16u off) { + return mem_readd((seg<<4)+off); +} + +static INLINE void real_writeb(Bit16u seg,Bit16u off,Bit8u val) { + mem_writeb(((seg<<4)+off),val); +} +static INLINE void real_writew(Bit16u seg,Bit16u off,Bit16u val) { + mem_writew(((seg<<4)+off),val); +} +static INLINE void real_writed(Bit16u seg,Bit16u off,Bit32u val) { + mem_writed(((seg<<4)+off),val); +} + + +static INLINE Bit16u RealSeg(RealPt pt) { + return (Bit16u)(pt>>16); +} + +static INLINE Bit16u RealOff(RealPt pt) { + return (Bit16u)(pt&0xffff); +} + +static INLINE PhysPt Real2Phys(RealPt pt) { + return (RealSeg(pt)<<4) +RealOff(pt); +} + +static INLINE PhysPt PhysMake(Bit16u seg,Bit16u off) { + return (seg<<4)+off; +} + +static INLINE RealPt RealMake(Bit16u seg,Bit16u off) { + return (seg<<16)+off; +} + +static INLINE void RealSetVec(Bit8u vec,RealPt pt) { + mem_writed(vec<<2,pt); +} + +static INLINE void RealSetVec(Bit8u vec,RealPt pt,RealPt &old) { + old = mem_readd(vec<<2); + mem_writed(vec<<2,pt); +} + +static INLINE RealPt RealGetVec(Bit8u vec) { + return mem_readd(vec<<2); +} + +#endif + diff --git a/dosbox/modrm.cpp b/dosbox/modrm.cpp new file mode 100644 index 00000000..bbac41e0 --- /dev/null +++ b/dosbox/modrm.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "cpu.h" + + +Bit8u * lookupRMregb[]= +{ + ®_al,®_al,®_al,®_al,®_al,®_al,®_al,®_al, + ®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,®_cl, + ®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,®_dl, + ®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,®_bl, + ®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,®_ah, + ®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,®_ch, + ®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,®_dh, + ®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,®_bh, + + ®_al,®_al,®_al,®_al,®_al,®_al,®_al,®_al, + ®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,®_cl, + ®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,®_dl, + ®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,®_bl, + ®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,®_ah, + ®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,®_ch, + ®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,®_dh, + ®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,®_bh, + + ®_al,®_al,®_al,®_al,®_al,®_al,®_al,®_al, + ®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,®_cl, + ®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,®_dl, + ®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,®_bl, + ®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,®_ah, + ®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,®_ch, + ®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,®_dh, + ®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,®_bh, + + ®_al,®_al,®_al,®_al,®_al,®_al,®_al,®_al, + ®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,®_cl,®_cl, + ®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,®_dl,®_dl, + ®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,®_bl,®_bl, + ®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,®_ah,®_ah, + ®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,®_ch,®_ch, + ®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,®_dh,®_dh, + ®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,®_bh,®_bh +}; + +Bit16u * lookupRMregw[]={ + ®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,®_ax, + ®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,®_cx, + ®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,®_dx, + ®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,®_bx, + ®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,®_sp, + ®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,®_bp, + ®_si,®_si,®_si,®_si,®_si,®_si,®_si,®_si, + ®_di,®_di,®_di,®_di,®_di,®_di,®_di,®_di, + + ®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,®_ax, + ®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,®_cx, + ®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,®_dx, + ®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,®_bx, + ®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,®_sp, + ®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,®_bp, + ®_si,®_si,®_si,®_si,®_si,®_si,®_si,®_si, + ®_di,®_di,®_di,®_di,®_di,®_di,®_di,®_di, + + ®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,®_ax, + ®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,®_cx, + ®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,®_dx, + ®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,®_bx, + ®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,®_sp, + ®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,®_bp, + ®_si,®_si,®_si,®_si,®_si,®_si,®_si,®_si, + ®_di,®_di,®_di,®_di,®_di,®_di,®_di,®_di, + + ®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,®_ax,®_ax, + ®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,®_cx,®_cx, + ®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,®_dx,®_dx, + ®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,®_bx,®_bx, + ®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,®_sp,®_sp, + ®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,®_bp,®_bp, + ®_si,®_si,®_si,®_si,®_si,®_si,®_si,®_si, + ®_di,®_di,®_di,®_di,®_di,®_di,®_di,®_di +}; + +Bit32u * lookupRMregd[256]={ + ®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,®_eax, + ®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx, + ®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,®_edx, + ®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx, + ®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,®_esp, + ®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp, + ®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,®_esi, + ®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,®_edi, + + ®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,®_eax, + ®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx, + ®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,®_edx, + ®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx, + ®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,®_esp, + ®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp, + ®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,®_esi, + ®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,®_edi, + + ®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,®_eax, + ®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx, + ®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,®_edx, + ®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx, + ®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,®_esp, + ®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp, + ®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,®_esi, + ®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,®_edi, + + ®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,®_eax,®_eax, + ®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx,®_ecx, + ®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,®_edx,®_edx, + ®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx,®_ebx, + ®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,®_esp,®_esp, + ®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp,®_ebp, + ®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,®_esi,®_esi, + ®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,®_edi,®_edi +}; + + +Bit8u * lookupRMEAregb[256]={ +/* 12 lines of 16*0 should give nice errors when used */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ®_al,®_cl,®_dl,®_bl,®_ah,®_ch,®_dh,®_bh, + ®_al,®_cl,®_dl,®_bl,®_ah,®_ch,®_dh,®_bh, + ®_al,®_cl,®_dl,®_bl,®_ah,®_ch,®_dh,®_bh, + ®_al,®_cl,®_dl,®_bl,®_ah,®_ch,®_dh,®_bh, + ®_al,®_cl,®_dl,®_bl,®_ah,®_ch,®_dh,®_bh, + ®_al,®_cl,®_dl,®_bl,®_ah,®_ch,®_dh,®_bh, + ®_al,®_cl,®_dl,®_bl,®_ah,®_ch,®_dh,®_bh, + ®_al,®_cl,®_dl,®_bl,®_ah,®_ch,®_dh,®_bh +}; + +Bit16u * lookupRMEAregw[256]={ +/* 12 lines of 16*0 should give nice errors when used */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ®_ax,®_cx,®_dx,®_bx,®_sp,®_bp,®_si,®_di, + ®_ax,®_cx,®_dx,®_bx,®_sp,®_bp,®_si,®_di, + ®_ax,®_cx,®_dx,®_bx,®_sp,®_bp,®_si,®_di, + ®_ax,®_cx,®_dx,®_bx,®_sp,®_bp,®_si,®_di, + ®_ax,®_cx,®_dx,®_bx,®_sp,®_bp,®_si,®_di, + ®_ax,®_cx,®_dx,®_bx,®_sp,®_bp,®_si,®_di, + ®_ax,®_cx,®_dx,®_bx,®_sp,®_bp,®_si,®_di, + ®_ax,®_cx,®_dx,®_bx,®_sp,®_bp,®_si,®_di +}; + +Bit32u * lookupRMEAregd[256]={ +/* 12 lines of 16*0 should give nice errors when used */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ®_eax,®_ecx,®_edx,®_ebx,®_esp,®_ebp,®_esi,®_edi, + ®_eax,®_ecx,®_edx,®_ebx,®_esp,®_ebp,®_esi,®_edi, + ®_eax,®_ecx,®_edx,®_ebx,®_esp,®_ebp,®_esi,®_edi, + ®_eax,®_ecx,®_edx,®_ebx,®_esp,®_ebp,®_esi,®_edi, + ®_eax,®_ecx,®_edx,®_ebx,®_esp,®_ebp,®_esi,®_edi, + ®_eax,®_ecx,®_edx,®_ebx,®_esp,®_ebp,®_esi,®_edi, + ®_eax,®_ecx,®_edx,®_ebx,®_esp,®_ebp,®_esi,®_edi, + ®_eax,®_ecx,®_edx,®_ebx,®_esp,®_ebp,®_esi,®_edi +}; + + diff --git a/dosbox/modrm.h b/dosbox/modrm.h new file mode 100644 index 00000000..60482bf9 --- /dev/null +++ b/dosbox/modrm.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +extern Bit8u * lookupRMregb[]; +extern Bit16u * lookupRMregw[]; +extern Bit32u * lookupRMregd[]; +extern Bit8u * lookupRMEAregb[256]; +extern Bit16u * lookupRMEAregw[256]; +extern Bit32u * lookupRMEAregd[256]; + +#define GetRM \ + Bit8u rm=Fetchb(); + +#define Getrb \ + Bit8u * rmrb; \ + rmrb=lookupRMregb[rm]; + +#define Getrw \ + Bit16u * rmrw; \ + rmrw=lookupRMregw[rm]; + +#define Getrd \ + Bit32u * rmrd; \ + rmrd=lookupRMregd[rm]; + + +#define GetRMrb \ + GetRM; \ + Getrb; + +#define GetRMrw \ + GetRM; \ + Getrw; + +#define GetRMrd \ + GetRM; \ + Getrd; + + +#define GetEArb \ + Bit8u * earb=lookupRMEAregb[rm]; + +#define GetEArw \ + Bit16u * earw=lookupRMEAregw[rm]; + +#define GetEArd \ + Bit32u * eard=lookupRMEAregd[rm]; + + diff --git a/dosbox/paging.cpp b/dosbox/paging.cpp new file mode 100644 index 00000000..e3088edb --- /dev/null +++ b/dosbox/paging.cpp @@ -0,0 +1,891 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id: paging.cpp,v 1.36 2009-05-27 09:15:41 qbix79 Exp $ */ + +#include +#include +#include + +#include "dosbox.h" +#include "mem.h" +#include "paging.h" +#include "regs.h" +#include "lazyflags.h" +#include "cpu.h" +//#include "debug.h" +#include "setup.h" + +#define LINK_TOTAL (64*1024) + +#define USERWRITE_PROHIBITED ((cpu.cpl&cpu.mpl)==3) + + +PagingBlock paging; + + +Bitu PageHandler::readb(PhysPt addr) { + E_Exit("No byte handler for read from %d",addr); + return 0; +} +Bitu PageHandler::readw(PhysPt addr) { + return + (readb(addr+0) << 0) | + (readb(addr+1) << 8); +} +Bitu PageHandler::readd(PhysPt addr) { + return + (readb(addr+0) << 0) | + (readb(addr+1) << 8) | + (readb(addr+2) << 16) | + (readb(addr+3) << 24); +} + +void PageHandler::writeb(PhysPt addr,Bitu /*val*/) { + E_Exit("No byte handler for write to %d",addr); +} + +void PageHandler::writew(PhysPt addr,Bitu val) { + writeb(addr+0,(Bit8u) (val >> 0)); + writeb(addr+1,(Bit8u) (val >> 8)); +} +void PageHandler::writed(PhysPt addr,Bitu val) { + writeb(addr+0,(Bit8u) (val >> 0)); + writeb(addr+1,(Bit8u) (val >> 8)); + writeb(addr+2,(Bit8u) (val >> 16)); + writeb(addr+3,(Bit8u) (val >> 24)); +} + +HostPt PageHandler::GetHostReadPt(Bitu /*phys_page*/) { + return 0; +} + +HostPt PageHandler::GetHostWritePt(Bitu /*phys_page*/) { + return 0; +} + +bool PageHandler::readb_checked(PhysPt addr, Bit8u * val) { + *val=(Bit8u)readb(addr); return false; +} +bool PageHandler::readw_checked(PhysPt addr, Bit16u * val) { + *val=(Bit16u)readw(addr); return false; +} +bool PageHandler::readd_checked(PhysPt addr, Bit32u * val) { + *val=(Bit32u)readd(addr); return false; +} +bool PageHandler::writeb_checked(PhysPt addr,Bitu val) { + writeb(addr,val); return false; +} +bool PageHandler::writew_checked(PhysPt addr,Bitu val) { + writew(addr,val); return false; +} +bool PageHandler::writed_checked(PhysPt addr,Bitu val) { + writed(addr,val); return false; +} + + + +struct PF_Entry { + Bitu cs; + Bitu eip; + Bitu page_addr; + Bitu mpl; +}; + +#define PF_QUEUESIZE 16 +static struct { + Bitu used; + PF_Entry entries[PF_QUEUESIZE]; +} pf_queue; + +static Bits PageFaultCore(void) { + CPU_CycleLeft+=CPU_Cycles; + CPU_Cycles=1; + Bits ret=CPU_Core_Full_Run(); + CPU_CycleLeft+=CPU_Cycles; + if (ret<0) E_Exit("Got a dosbox close machine in pagefault core?"); + if (ret) + return ret; + if (!pf_queue.used) E_Exit("PF Core without PF"); + PF_Entry * entry=&pf_queue.entries[pf_queue.used-1]; + X86PageEntry pentry; + pentry.load=phys_readd(entry->page_addr); + if (pentry.block.p && entry->cs == SegValue(cs) && entry->eip==reg_eip) { + cpu.mpl=entry->mpl; + return -1; + } + return 0; +} +#if C_DEBUG +Bitu DEBUG_EnableDebugger(void); +#endif + +bool first=false; + +void PAGING_PageFault(PhysPt lin_addr,Bitu page_addr,Bitu faultcode) { + /* Save the state of the cpu cores */ + LazyFlags old_lflags; + memcpy(&old_lflags,&lflags,sizeof(LazyFlags)); + CPU_Decoder * old_cpudecoder; + old_cpudecoder=cpudecoder; + cpudecoder=&PageFaultCore; + paging.cr2=lin_addr; + PF_Entry * entry=&pf_queue.entries[pf_queue.used++]; + LOG(LOG_PAGING,LOG_NORMAL)("PageFault at %X type [%x] queue %d",lin_addr,faultcode,pf_queue.used); +// LOG_MSG("EAX:%04X ECX:%04X EDX:%04X EBX:%04X",reg_eax,reg_ecx,reg_edx,reg_ebx); +// LOG_MSG("CS:%04X EIP:%08X SS:%04x SP:%08X",SegValue(cs),reg_eip,SegValue(ss),reg_esp); + entry->cs=SegValue(cs); + entry->eip=reg_eip; + entry->page_addr=page_addr; + entry->mpl=cpu.mpl; + cpu.mpl=3; + + CPU_Exception(EXCEPTION_PF,faultcode); +#if C_DEBUG +// DEBUG_EnableDebugger(); +#endif + DOSBOX_RunMachine(); + pf_queue.used--; + LOG(LOG_PAGING,LOG_NORMAL)("Left PageFault for %x queue %d",lin_addr,pf_queue.used); + memcpy(&lflags,&old_lflags,sizeof(LazyFlags)); + cpudecoder=old_cpudecoder; +// LOG_MSG("SS:%04x SP:%08X",SegValue(ss),reg_esp); +} + +static INLINE void InitPageUpdateLink(Bitu relink,PhysPt addr) { + if (relink==0) return; + if (paging.links.used) { + if (paging.links.entries[paging.links.used-1]==(addr>>12)) { + paging.links.used--; + PAGING_UnlinkPages(addr>>12,1); + } + } + if (relink>1) PAGING_LinkPage_ReadOnly(addr>>12,relink); +} + +static INLINE void InitPageCheckPresence(PhysPt lin_addr,bool writing,X86PageEntry& table,X86PageEntry& entry) { + Bitu lin_page=lin_addr >> 12; + Bitu d_index=lin_page >> 10; + Bitu t_index=lin_page & 0x3ff; + Bitu table_addr=(paging.base.page<<12)+d_index*4; + table.load=phys_readd(table_addr); + if (!table.block.p) { + LOG(LOG_PAGING,LOG_NORMAL)("NP Table"); + PAGING_PageFault(lin_addr,table_addr, + (writing?0x02:0x00) | (((cpu.cpl&cpu.mpl)==0)?0x00:0x04)); + table.load=phys_readd(table_addr); + if (GCC_UNLIKELY(!table.block.p)) + E_Exit("Pagefault didn't correct table"); + } + Bitu entry_addr=(table.block.base<<12)+t_index*4; + entry.load=phys_readd(entry_addr); + if (!entry.block.p) { +// LOG(LOG_PAGING,LOG_NORMAL)("NP Page"); + PAGING_PageFault(lin_addr,entry_addr, + (writing?0x02:0x00) | (((cpu.cpl&cpu.mpl)==0)?0x00:0x04)); + entry.load=phys_readd(entry_addr); + if (GCC_UNLIKELY(!entry.block.p)) + E_Exit("Pagefault didn't correct page"); + } +} + +static INLINE bool InitPageCheckPresence_CheckOnly(PhysPt lin_addr,bool writing,X86PageEntry& table,X86PageEntry& entry) { + Bitu lin_page=lin_addr >> 12; + Bitu d_index=lin_page >> 10; + Bitu t_index=lin_page & 0x3ff; + Bitu table_addr=(paging.base.page<<12)+d_index*4; + table.load=phys_readd(table_addr); + if (!table.block.p) { + paging.cr2=lin_addr; + cpu.exception.which=EXCEPTION_PF; + cpu.exception.error=(writing?0x02:0x00) | (((cpu.cpl&cpu.mpl)==0)?0x00:0x04); + return false; + } + Bitu entry_addr=(table.block.base<<12)+t_index*4; + entry.load=phys_readd(entry_addr); + if (!entry.block.p) { + paging.cr2=lin_addr; + cpu.exception.which=EXCEPTION_PF; + cpu.exception.error=(writing?0x02:0x00) | (((cpu.cpl&cpu.mpl)==0)?0x00:0x04); + return false; + } + return true; +} + +// check if a user-level memory access would trigger a privilege page fault +static INLINE bool InitPage_CheckUseraccess(Bitu u1,Bitu u2) { + switch (CPU_ArchitectureType) { + case CPU_ARCHTYPE_MIXED: + case CPU_ARCHTYPE_386SLOW: + case CPU_ARCHTYPE_386FAST: + default: + return ((u1)==0) && ((u2)==0); + case CPU_ARCHTYPE_486OLDSLOW: + case CPU_ARCHTYPE_486NEWSLOW: + case CPU_ARCHTYPE_PENTIUMSLOW: + return ((u1)==0) || ((u2)==0); + } +} + + +class InitPageHandler : public PageHandler { +public: + InitPageHandler() { + flags=PFLAG_INIT|PFLAG_NOCODE; + } + Bitu readb(PhysPt addr) { + Bitu needs_reset=InitPage(addr,false); + Bit8u val=mem_readb(addr); + InitPageUpdateLink(needs_reset,addr); + return val; + } + Bitu readw(PhysPt addr) { + Bitu needs_reset=InitPage(addr,false); + Bit16u val=mem_readw(addr); + InitPageUpdateLink(needs_reset,addr); + return val; + } + Bitu readd(PhysPt addr) { + Bitu needs_reset=InitPage(addr,false); + Bit32u val=mem_readd(addr); + InitPageUpdateLink(needs_reset,addr); + return val; + } + void writeb(PhysPt addr,Bitu val) { + Bitu needs_reset=InitPage(addr,true); + mem_writeb(addr,val); + InitPageUpdateLink(needs_reset,addr); + } + void writew(PhysPt addr,Bitu val) { + Bitu needs_reset=InitPage(addr,true); + mem_writew(addr,val); + InitPageUpdateLink(needs_reset,addr); + } + void writed(PhysPt addr,Bitu val) { + Bitu needs_reset=InitPage(addr,true); + mem_writed(addr,val); + InitPageUpdateLink(needs_reset,addr); + } + bool readb_checked(PhysPt addr, Bit8u * val) { + if (InitPageCheckOnly(addr,false)) { + *val=mem_readb(addr); + return false; + } else return true; + } + bool readw_checked(PhysPt addr, Bit16u * val) { + if (InitPageCheckOnly(addr,false)){ + *val=mem_readw(addr); + return false; + } else return true; + } + bool readd_checked(PhysPt addr, Bit32u * val) { + if (InitPageCheckOnly(addr,false)) { + *val=mem_readd(addr); + return false; + } else return true; + } + bool writeb_checked(PhysPt addr,Bitu val) { + if (InitPageCheckOnly(addr,true)) { + mem_writeb(addr,val); + return false; + } else return true; + } + bool writew_checked(PhysPt addr,Bitu val) { + if (InitPageCheckOnly(addr,true)) { + mem_writew(addr,val); + return false; + } else return true; + } + bool writed_checked(PhysPt addr,Bitu val) { + if (InitPageCheckOnly(addr,true)) { + mem_writed(addr,val); + return false; + } else return true; + } + Bitu InitPage(Bitu lin_addr,bool writing) { + Bitu lin_page=lin_addr >> 12; + Bitu phys_page; + if (paging.enabled) { + X86PageEntry table; + X86PageEntry entry; + InitPageCheckPresence(lin_addr,writing,table,entry); + + // 0: no action + // 1: can (but currently does not) fail a user-level access privilege check + // 2: can (but currently does not) fail a write privilege check + // 3: fails a privilege check + Bitu priv_check=0; + if (InitPage_CheckUseraccess(entry.block.us,table.block.us)) { + if ((cpu.cpl&cpu.mpl)==3) priv_check=3; + else { + switch (CPU_ArchitectureType) { + case CPU_ARCHTYPE_MIXED: + case CPU_ARCHTYPE_386FAST: + default: +// priv_check=0; // default + break; + case CPU_ARCHTYPE_386SLOW: + case CPU_ARCHTYPE_486OLDSLOW: + case CPU_ARCHTYPE_486NEWSLOW: + case CPU_ARCHTYPE_PENTIUMSLOW: + priv_check=1; + break; + } + } + } + if ((entry.block.wr==0) || (table.block.wr==0)) { + // page is write-protected for user mode + if (priv_check==0) { + switch (CPU_ArchitectureType) { + case CPU_ARCHTYPE_MIXED: + case CPU_ARCHTYPE_386FAST: + default: +// priv_check=0; // default + break; + case CPU_ARCHTYPE_386SLOW: + case CPU_ARCHTYPE_486OLDSLOW: + case CPU_ARCHTYPE_486NEWSLOW: + case CPU_ARCHTYPE_PENTIUMSLOW: + priv_check=2; + break; + } + } + // check if actually failing the write-protected check + if (writing && USERWRITE_PROHIBITED) priv_check=3; + } + if (priv_check==3) { + LOG(LOG_PAGING,LOG_NORMAL)("Page access denied: cpl=%i, %x:%x:%x:%x", + cpu.cpl,entry.block.us,table.block.us,entry.block.wr,table.block.wr); + PAGING_PageFault(lin_addr,(table.block.base<<12)+(lin_page & 0x3ff)*4,0x05 | (writing?0x02:0x00)); + priv_check=0; + } + + if (!table.block.a) { + table.block.a=1; // set page table accessed + phys_writed((paging.base.page<<12)+(lin_page >> 10)*4,table.load); + } + if ((!entry.block.a) || (!entry.block.d)) { + entry.block.a=1; // set page accessed + + // page is dirty if we're writing to it, or if we're reading but the + // page will be fully linked so we can't track later writes + if (writing || (priv_check==0)) entry.block.d=1; // mark page as dirty + + phys_writed((table.block.base<<12)+(lin_page & 0x3ff)*4,entry.load); + } + + phys_page=entry.block.base; + + // now see how the page should be linked best, if we need to catch privilege + // checks later on it should be linked as read-only page + if (priv_check==0) { + // if reading we could link the page as read-only to later cacth writes, + // will slow down pretty much but allows catching all dirty events + PAGING_LinkPage(lin_page,phys_page); + } else { + if (priv_check==1) { + PAGING_LinkPage(lin_page,phys_page); + return 1; + } else if (writing) { + PageHandler * handler=MEM_GetPageHandler(phys_page); + PAGING_LinkPage(lin_page,phys_page); + if (!(handler->flags & PFLAG_READABLE)) return 1; + if (!(handler->flags & PFLAG_WRITEABLE)) return 1; + if (get_tlb_read(lin_addr)!=get_tlb_write(lin_addr)) return 1; + if (phys_page>1) return phys_page; + else return 1; + } else { + PAGING_LinkPage_ReadOnly(lin_page,phys_page); + } + } + } else { + if (lin_page> 12; + if (paging.enabled) { + X86PageEntry table; + X86PageEntry entry; + if (!InitPageCheckPresence_CheckOnly(lin_addr,writing,table,entry)) return false; + + if (!USERWRITE_PROHIBITED) return true; + + if (InitPage_CheckUseraccess(entry.block.us,table.block.us) || + (((entry.block.wr==0) || (table.block.wr==0)) && writing)) { + LOG(LOG_PAGING,LOG_NORMAL)("Page access denied: cpl=%i, %x:%x:%x:%x", + cpu.cpl,entry.block.us,table.block.us,entry.block.wr,table.block.wr); + paging.cr2=lin_addr; + cpu.exception.which=EXCEPTION_PF; + cpu.exception.error=0x05 | (writing?0x02:0x00); + return false; + } + } else { + Bitu phys_page; + if (lin_page> 12; + Bitu phys_page; + if (paging.enabled) { + X86PageEntry table; + X86PageEntry entry; + InitPageCheckPresence(lin_addr,false,table,entry); + + if (!table.block.a) { + table.block.a=1; //Set access + phys_writed((paging.base.page<<12)+(lin_page >> 10)*4,table.load); + } + if (!entry.block.a) { + entry.block.a=1; //Set access + phys_writed((table.block.base<<12)+(lin_page & 0x3ff)*4,entry.load); + } + phys_page=entry.block.base; + // maybe use read-only page here if possible + } else { + if (lin_page1) tlb_addr=get_tlb_read(addr); + else tlb_addr=get_tlb_write(addr); + host_writeb(tlb_addr+addr,(Bit8u)(val&0xff)); + return false; + } + return true; + } + bool writew_checked(PhysPt addr,Bitu val) { + Bitu writecode=InitPageCheckOnly(addr,(Bit16u)(val&0xffff)); + if (writecode) { + HostPt tlb_addr; + if (writecode>1) tlb_addr=get_tlb_read(addr); + else tlb_addr=get_tlb_write(addr); + host_writew(tlb_addr+addr,(Bit16u)(val&0xffff)); + return false; + } + return true; + } + bool writed_checked(PhysPt addr,Bitu val) { + Bitu writecode=InitPageCheckOnly(addr,(Bit32u)val); + if (writecode) { + HostPt tlb_addr; + if (writecode>1) tlb_addr=get_tlb_read(addr); + else tlb_addr=get_tlb_write(addr); + host_writed(tlb_addr+addr,(Bit32u)val); + return false; + } + return true; + } + void InitPage(Bitu lin_addr,Bitu val) { + Bitu lin_page=lin_addr >> 12; + Bitu phys_page; + if (paging.enabled) { + if (!USERWRITE_PROHIBITED) return; + + X86PageEntry table; + X86PageEntry entry; + InitPageCheckPresence(lin_addr,true,table,entry); + + LOG(LOG_PAGING,LOG_NORMAL)("Page access denied: cpl=%i, %x:%x:%x:%x", + cpu.cpl,entry.block.us,table.block.us,entry.block.wr,table.block.wr); + PAGING_PageFault(lin_addr,(table.block.base<<12)+(lin_page & 0x3ff)*4,0x07); + + if (!table.block.a) { + table.block.a=1; //Set access + phys_writed((paging.base.page<<12)+(lin_page >> 10)*4,table.load); + } + if ((!entry.block.a) || (!entry.block.d)) { + entry.block.a=1; //Set access + entry.block.d=1; //Set dirty + phys_writed((table.block.base<<12)+(lin_page & 0x3ff)*4,entry.load); + } + phys_page=entry.block.base; + PAGING_LinkPage(lin_page,phys_page); + } else { + if (lin_page> 12; + if (paging.enabled) { + if (!USERWRITE_PROHIBITED) return 2; + + X86PageEntry table; + X86PageEntry entry; + if (!InitPageCheckPresence_CheckOnly(lin_addr,true,table,entry)) return 0; + + if (InitPage_CheckUseraccess(entry.block.us,table.block.us) || (((entry.block.wr==0) || (table.block.wr==0)))) { + LOG(LOG_PAGING,LOG_NORMAL)("Page access denied: cpl=%i, %x:%x:%x:%x", + cpu.cpl,entry.block.us,table.block.us,entry.block.wr,table.block.wr); + paging.cr2=lin_addr; + cpu.exception.which=EXCEPTION_PF; + cpu.exception.error=0x07; + return 0; + } + PAGING_LinkPage(lin_page,entry.block.base); + } else { + Bitu phys_page; + if (lin_page> 12; + Bitu phys_page; + if (paging.enabled) { + X86PageEntry table; + X86PageEntry entry; + InitPageCheckPresence(lin_addr,true,table,entry); + + if (!table.block.a) { + table.block.a=1; //Set access + phys_writed((paging.base.page<<12)+(lin_page >> 10)*4,table.load); + } + if (!entry.block.a) { + entry.block.a=1; //Set access + phys_writed((table.block.base<<12)+(lin_page & 0x3ff)*4,entry.load); + } + phys_page=entry.block.base; + } else { + if (lin_page> 10; + Bitu t_index=page & 0x3ff; + X86PageEntry table; + table.load=phys_readd((paging.base.page<<12)+d_index*4); + if (!table.block.p) return false; + X86PageEntry entry; + entry.load=phys_readd((table.block.base<<12)+t_index*4); + if (!entry.block.p) return false; + page=entry.block.base; + } else { + if (page>12,1); + init_page_handler_userro.InitPageForced(lin_addr); + return true; + } + return false; +} + +#if defined(USE_FULL_TLB) +void PAGING_InitTLB(void) { + for (Bitu i=0;i0;paging.links.used--) { + Bitu page=*entries++; + paging.tlb.read[page]=0; + paging.tlb.write[page]=0; + paging.tlb.readhandler[page]=&init_page_handler; + paging.tlb.writehandler[page]=&init_page_handler; + } + paging.links.used=0; +} + +void PAGING_UnlinkPages(Bitu lin_page,Bitu pages) { + for (;pages>0;pages--) { + paging.tlb.read[lin_page]=0; + paging.tlb.write[lin_page]=0; + paging.tlb.readhandler[lin_page]=&init_page_handler; + paging.tlb.writehandler[lin_page]=&init_page_handler; + lin_page++; + } +} + +void PAGING_MapPage(Bitu lin_page,Bitu phys_page) { + if (lin_page=TLB_SIZE || phys_page>=TLB_SIZE) + E_Exit("Illegal page"); + + if (paging.links.used>=PAGING_LINKS) { + LOG(LOG_PAGING,LOG_NORMAL)("Not enough paging links, resetting cache"); + PAGING_ClearTLB(); + } + + paging.tlb.phys_page[lin_page]=phys_page; + if (handler->flags & PFLAG_READABLE) paging.tlb.read[lin_page]=handler->GetHostReadPt(phys_page)-lin_base; + else paging.tlb.read[lin_page]=0; + if (handler->flags & PFLAG_WRITEABLE) paging.tlb.write[lin_page]=handler->GetHostWritePt(phys_page)-lin_base; + else paging.tlb.write[lin_page]=0; + + paging.links.entries[paging.links.used++]=lin_page; + paging.tlb.readhandler[lin_page]=handler; + paging.tlb.writehandler[lin_page]=handler; +} + +void PAGING_LinkPage_ReadOnly(Bitu lin_page,Bitu phys_page) { + PageHandler * handler=MEM_GetPageHandler(phys_page); + Bitu lin_base=lin_page << 12; + if (lin_page>=TLB_SIZE || phys_page>=TLB_SIZE) + E_Exit("Illegal page"); + + if (paging.links.used>=PAGING_LINKS) { + LOG(LOG_PAGING,LOG_NORMAL)("Not enough paging links, resetting cache"); + PAGING_ClearTLB(); + } + + paging.tlb.phys_page[lin_page]=phys_page; + if (handler->flags & PFLAG_READABLE) paging.tlb.read[lin_page]=handler->GetHostReadPt(phys_page)-lin_base; + else paging.tlb.read[lin_page]=0; + paging.tlb.write[lin_page]=0; + + paging.links.entries[paging.links.used++]=lin_page; + paging.tlb.readhandler[lin_page]=handler; + paging.tlb.writehandler[lin_page]=&init_page_handler_userro; +} + +#else + +static INLINE void InitTLBInt(tlb_entry *bank) { + for (Bitu i=0;i0;paging.links.used--) { + Bitu page=*entries++; + tlb_entry *entry = get_tlb_entry(page<<12); + entry->read=0; + entry->write=0; + entry->readhandler=&init_page_handler; + entry->writehandler=&init_page_handler; + } + paging.links.used=0; +} + +void PAGING_UnlinkPages(Bitu lin_page,Bitu pages) { + for (;pages>0;pages--) { + tlb_entry *entry = get_tlb_entry(lin_page<<12); + entry->read=0; + entry->write=0; + entry->readhandler=&init_page_handler; + entry->writehandler=&init_page_handler; + lin_page++; + } +} + +void PAGING_MapPage(Bitu lin_page,Bitu phys_page) { + if (lin_page=(TLB_SIZE*(TLB_BANKS+1)) || phys_page>=(TLB_SIZE*(TLB_BANKS+1))) + E_Exit("Illegal page"); + + if (paging.links.used>=PAGING_LINKS) { + LOG(LOG_PAGING,LOG_NORMAL)("Not enough paging links, resetting cache"); + PAGING_ClearTLB(); + } + + tlb_entry *entry = get_tlb_entry(lin_base); + entry->phys_page=phys_page; + if (handler->flags & PFLAG_READABLE) entry->read=handler->GetHostReadPt(phys_page)-lin_base; + else entry->read=0; + if (handler->flags & PFLAG_WRITEABLE) entry->write=handler->GetHostWritePt(phys_page)-lin_base; + else entry->write=0; + + paging.links.entries[paging.links.used++]=lin_page; + entry->readhandler=handler; + entry->writehandler=handler; +} + +void PAGING_LinkPage_ReadOnly(Bitu lin_page,Bitu phys_page) { + PageHandler * handler=MEM_GetPageHandler(phys_page); + Bitu lin_base=lin_page << 12; + if (lin_page>=(TLB_SIZE*(TLB_BANKS+1)) || phys_page>=(TLB_SIZE*(TLB_BANKS+1))) + E_Exit("Illegal page"); + + if (paging.links.used>=PAGING_LINKS) { + LOG(LOG_PAGING,LOG_NORMAL)("Not enough paging links, resetting cache"); + PAGING_ClearTLB(); + } + + tlb_entry *entry = get_tlb_entry(lin_base); + entry->phys_page=phys_page; + if (handler->flags & PFLAG_READABLE) entry->read=handler->GetHostReadPt(phys_page)-lin_base; + else entry->read=0; + entry->write=0; + + paging.links.entries[paging.links.used++]=lin_page; + entry->readhandler=handler; + entry->writehandler=&init_page_handler_userro; +} + +#endif + + +void PAGING_SetDirBase(Bitu cr3) { + paging.cr3=cr3; + + paging.base.page=cr3 >> 12; + paging.base.addr=cr3 & ~4095; +// LOG(LOG_PAGING,LOG_NORMAL)("CR3:%X Base %X",cr3,paging.base.page); + if (paging.enabled) { + PAGING_ClearTLB(); + } +} + +void PAGING_Enable(bool enabled) { + /* If paging is disable we work from a default paging table */ + if (paging.enabled==enabled) return; + paging.enabled=enabled; + if (enabled) { + if (GCC_UNLIKELY(cpudecoder==CPU_Core_Simple_Run)) { +// LOG_MSG("CPU core simple won't run this game,switching to normal"); + cpudecoder=CPU_Core_Normal_Run; + CPU_CycleLeft+=CPU_Cycles; + CPU_Cycles=0; + } +// LOG(LOG_PAGING,LOG_NORMAL)("Enabled"); + PAGING_SetDirBase(paging.cr3); + } + PAGING_ClearTLB(); +} + +bool PAGING_Enabled(void) { + return paging.enabled; +} + +class PAGING:public Module_base{ +public: + PAGING(Section* configuration):Module_base(configuration){ + /* Setup default Page Directory, force it to update */ + paging.enabled=false; + PAGING_InitTLB(); + Bitu i; + for (i=0;i>12]; +} +static INLINE HostPt get_tlb_write(PhysPt address) { + return paging.tlb.write[address>>12]; +} +static INLINE PageHandler* get_tlb_readhandler(PhysPt address) { + return paging.tlb.readhandler[address>>12]; +} +static INLINE PageHandler* get_tlb_writehandler(PhysPt address) { + return paging.tlb.writehandler[address>>12]; +} + +/* Use these helper functions to access linear addresses in readX/writeX functions */ +static INLINE PhysPt PAGING_GetPhysicalPage(PhysPt linePage) { + return (paging.tlb.phys_page[linePage>>12]<<12); +} + +static INLINE PhysPt PAGING_GetPhysicalAddress(PhysPt linAddr) { + return (paging.tlb.phys_page[linAddr>>12]<<12)|(linAddr&0xfff); +} + +#else + +void PAGING_InitTLBBank(tlb_entry **bank); + +static INLINE tlb_entry *get_tlb_entry(PhysPt address) { + Bitu index=(address>>12); + if (TLB_BANKS && (index > TLB_SIZE)) { + Bitu bank=(address>>BANK_SHIFT) - 1; + if (!paging.tlbh_banks[bank]) + PAGING_InitTLBBank(&paging.tlbh_banks[bank]); + return &paging.tlbh_banks[bank][index & BANK_MASK]; + } + return &paging.tlbh[index]; +} + +static INLINE HostPt get_tlb_read(PhysPt address) { + return get_tlb_entry(address)->read; +} +static INLINE HostPt get_tlb_write(PhysPt address) { + return get_tlb_entry(address)->write; +} +static INLINE PageHandler* get_tlb_readhandler(PhysPt address) { + return get_tlb_entry(address)->readhandler; +} +static INLINE PageHandler* get_tlb_writehandler(PhysPt address) { + return get_tlb_entry(address)->writehandler; +} + +/* Use these helper functions to access linear addresses in readX/writeX functions */ +static INLINE PhysPt PAGING_GetPhysicalPage(PhysPt linePage) { + tlb_entry *entry = get_tlb_entry(linePage); + return (entry->phys_page<<12); +} + +static INLINE PhysPt PAGING_GetPhysicalAddress(PhysPt linAddr) { + tlb_entry *entry = get_tlb_entry(linAddr); + return (entry->phys_page<<12)|(linAddr&0xfff); +} +#endif + +/* Special inlined memory reading/writing */ + +static INLINE Bit8u mem_readb_inline(PhysPt address) { + HostPt tlb_addr=get_tlb_read(address); + if (tlb_addr) return host_readb(tlb_addr+address); + else return (Bit8u)(get_tlb_readhandler(address))->readb(address); +} + +static INLINE Bit16u mem_readw_inline(PhysPt address) { + if ((address & 0xfff)<0xfff) { + HostPt tlb_addr=get_tlb_read(address); + if (tlb_addr) return host_readw(tlb_addr+address); + else return (Bit16u)(get_tlb_readhandler(address))->readw(address); + } else return mem_unalignedreadw(address); +} + +static INLINE Bit32u mem_readd_inline(PhysPt address) { + if ((address & 0xfff)<0xffd) { + HostPt tlb_addr=get_tlb_read(address); + if (tlb_addr) return host_readd(tlb_addr+address); + else return (get_tlb_readhandler(address))->readd(address); + } else return mem_unalignedreadd(address); +} + +static INLINE void mem_writeb_inline(PhysPt address,Bit8u val) { + HostPt tlb_addr=get_tlb_write(address); + if (tlb_addr) host_writeb(tlb_addr+address,val); + else (get_tlb_writehandler(address))->writeb(address,val); +} + +static INLINE void mem_writew_inline(PhysPt address,Bit16u val) { + if ((address & 0xfff)<0xfff) { + HostPt tlb_addr=get_tlb_write(address); + if (tlb_addr) host_writew(tlb_addr+address,val); + else (get_tlb_writehandler(address))->writew(address,val); + } else mem_unalignedwritew(address,val); +} + +static INLINE void mem_writed_inline(PhysPt address,Bit32u val) { + if ((address & 0xfff)<0xffd) { + HostPt tlb_addr=get_tlb_write(address); + if (tlb_addr) host_writed(tlb_addr+address,val); + else (get_tlb_writehandler(address))->writed(address,val); + } else mem_unalignedwrited(address,val); +} + + +static INLINE bool mem_readb_checked(PhysPt address, Bit8u * val) { + HostPt tlb_addr=get_tlb_read(address); + if (tlb_addr) { + *val=host_readb(tlb_addr+address); + return false; + } else return (get_tlb_readhandler(address))->readb_checked(address, val); +} + +static INLINE bool mem_readw_checked(PhysPt address, Bit16u * val) { + if ((address & 0xfff)<0xfff) { + HostPt tlb_addr=get_tlb_read(address); + if (tlb_addr) { + *val=host_readw(tlb_addr+address); + return false; + } else return (get_tlb_readhandler(address))->readw_checked(address, val); + } else return mem_unalignedreadw_checked(address, val); +} + +static INLINE bool mem_readd_checked(PhysPt address, Bit32u * val) { + if ((address & 0xfff)<0xffd) { + HostPt tlb_addr=get_tlb_read(address); + if (tlb_addr) { + *val=host_readd(tlb_addr+address); + return false; + } else return (get_tlb_readhandler(address))->readd_checked(address, val); + } else return mem_unalignedreadd_checked(address, val); +} + +static INLINE bool mem_writeb_checked(PhysPt address,Bit8u val) { + HostPt tlb_addr=get_tlb_write(address); + if (tlb_addr) { + host_writeb(tlb_addr+address,val); + return false; + } else return (get_tlb_writehandler(address))->writeb_checked(address,val); +} + +static INLINE bool mem_writew_checked(PhysPt address,Bit16u val) { + if ((address & 0xfff)<0xfff) { + HostPt tlb_addr=get_tlb_write(address); + if (tlb_addr) { + host_writew(tlb_addr+address,val); + return false; + } else return (get_tlb_writehandler(address))->writew_checked(address,val); + } else return mem_unalignedwritew_checked(address,val); +} + +static INLINE bool mem_writed_checked(PhysPt address,Bit32u val) { + if ((address & 0xfff)<0xffd) { + HostPt tlb_addr=get_tlb_write(address); + if (tlb_addr) { + host_writed(tlb_addr+address,val); + return false; + } else return (get_tlb_writehandler(address))->writed_checked(address,val); + } else return mem_unalignedwrited_checked(address,val); +} + + +#endif diff --git a/dosbox/pic.cpp b/dosbox/pic.cpp new file mode 100644 index 00000000..f6c1801a --- /dev/null +++ b/dosbox/pic.cpp @@ -0,0 +1,652 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id: pic.cpp,v 1.44 2009-05-27 09:15:41 qbix79 Exp $ */ + +#include + +#include "dosbox.h" +#include "inout.h" +#include "cpu.h" +#include "callback.h" +#include "pic.h" +//#include "timer.h" +#include "setup.h" + +#define PIC_QUEUESIZE 512 + +struct IRQ_Block { + bool masked; + bool active; + bool inservice; + Bitu vector; +}; + +struct PIC_Controller { + Bitu icw_words; + Bitu icw_index; + Bitu masked; + + bool special; + bool auto_eoi; + bool rotate_on_auto_eoi; + bool single; + bool request_issr; + Bit8u vector_base; +}; + +Bitu PIC_Ticks=0; +Bitu PIC_IRQCheck; +Bitu PIC_IRQOnSecondPicActive; +Bitu PIC_IRQActive; + + +static IRQ_Block irqs[16]; +static PIC_Controller pics[2]; +static bool PIC_Special_Mode = false; //Saves one compare in the pic_run_irqloop +struct PICEntry { + float index; + Bitu value; + PIC_EventHandler pic_event; + PICEntry * next; +}; + +static struct { + PICEntry entries[PIC_QUEUESIZE]; + PICEntry * free_entry; + PICEntry * next_entry; +} pic_queue; + +void x86_ack_keyboard(void); + +static void write_command(Bitu port,Bitu val,Bitu iolen) { + PIC_Controller * pic=&pics[port==0x20 ? 0 : 1]; + Bitu irq_base=port==0x20 ? 0 : 8; + Bitu i; + static Bit16u IRQ_priority_table[16] = + { 0,1,2,8,9,10,11,12,13,14,15,3,4,5,6,7 }; + if (GCC_UNLIKELY(val&0x10)) { // ICW1 issued + if (val&0x04) E_Exit("PIC: 4 byte interval not handled"); + if (val&0x08) E_Exit("PIC: level triggered mode not handled"); + if (val&0xe0) E_Exit("PIC: 8080/8085 mode not handled"); + pic->single=(val&0x02)==0x02; + pic->icw_index=1; // next is ICW2 + pic->icw_words=2 + (val&0x01); // =3 if ICW4 needed + } else if (GCC_UNLIKELY(val&0x08)) { // OCW3 issued + if (val&0x04) E_Exit("PIC: poll command not handled"); + if (val&0x02) { // function select + if (val&0x01) pic->request_issr=true; /* select read interrupt in-service register */ + else pic->request_issr=false; /* select read interrupt request register */ + } + if (val&0x40) { // special mask select + if (val&0x20) pic->special=true; + else pic->special=false; + if(pic[0].special || pics[1].special) + PIC_Special_Mode = true; else + PIC_Special_Mode = false; + if (PIC_IRQCheck) { //Recheck irqs + CPU_CycleLeft += CPU_Cycles; + CPU_Cycles = 0; + } + LOG(LOG_PIC,LOG_NORMAL)("port %X : special mask %s",port,(pic->special)?"ON":"OFF"); + } + } else { // OCW2 issued + if (val&0x20) { // EOI commands + if (GCC_UNLIKELY(val&0x80)) E_Exit("rotate mode not supported"); + if (val&0x40) { // specific EOI + if (PIC_IRQActive==(irq_base+val-0x60U)) { + irqs[PIC_IRQActive].inservice=false; + if (PIC_IRQActive == 1) + x86_ack_keyboard(); + PIC_IRQActive=PIC_NOIRQ; + for (i=0; i<=15; i++) { + if (irqs[IRQ_priority_table[i]].inservice) { + PIC_IRQActive=IRQ_priority_table[i]; + break; + } + } + } +// if (val&0x80); // perform rotation + } else { // nonspecific EOI + if (PIC_IRQActive<(irq_base+8)) { + irqs[PIC_IRQActive].inservice=false; + if (PIC_IRQActive == 1) + x86_ack_keyboard(); + PIC_IRQActive=PIC_NOIRQ; + for (i=0; i<=15; i++){ + if(GCC_UNLIKELY(irqs[IRQ_priority_table[i]].inservice)) { + PIC_IRQActive=IRQ_priority_table[i]; + break; + } + } + } +// if (val&0x80); // perform rotation + } + } else { + if ((val&0x40)==0) { // rotate in auto EOI mode + if (val&0x80) pic->rotate_on_auto_eoi=true; + else pic->rotate_on_auto_eoi=false; + } else if (val&0x80) { + LOG(LOG_PIC,LOG_NORMAL)("set priority command not handled"); + } // else NOP command + } + } // end OCW2 +} + +static void write_data(Bitu port,Bitu val,Bitu iolen) { + PIC_Controller * pic=&pics[port==0x21 ? 0 : 1]; + Bitu irq_base=(port==0x21) ? 0 : 8; + Bitu i; + bool old_irq2_mask = irqs[2].masked; + switch(pic->icw_index) { + case 0: /* mask register */ + LOG(LOG_PIC,LOG_NORMAL)("%d mask %X",port==0x21 ? 0 : 1,val); + for (i=0;i<=7;i++) { + irqs[i+irq_base].masked=(val&(1<0; + if(port==0x21) { + if (irqs[i+irq_base].active && !irqs[i+irq_base].masked) PIC_IRQCheck|=(1 << (i+irq_base)); + else PIC_IRQCheck&=~(1 << (i+irq_base)); + } else { + if (irqs[i+irq_base].active && !irqs[i+irq_base].masked && !irqs[2].masked) PIC_IRQCheck|=(1 << (i+irq_base)); + else PIC_IRQCheck&=~(1 << (i+irq_base)); + } + } +#if 0 + if (machine==MCH_PCJR) { + /* irq6 cannot be disabled as it serves as pseudo-NMI */ + irqs[6].masked=false; + } +#endif + if(irqs[2].masked != old_irq2_mask) { + /* Irq 2 mask has changed recheck second pic */ + for(i=8;i<=15;i++) { + if (irqs[i].active && !irqs[i].masked && !irqs[2].masked) PIC_IRQCheck|=(1 << (i)); + else PIC_IRQCheck&=~(1 << (i)); + } + } + if (PIC_IRQCheck) { + CPU_CycleLeft+=CPU_Cycles; + CPU_Cycles=0; + } + break; + case 1: /* icw2 */ + LOG(LOG_PIC,LOG_NORMAL)("%d:Base vector %X",port==0x21 ? 0 : 1,val); + for (i=0;i<=7;i++) { + irqs[i+irq_base].vector=(val&0xf8)+i; + }; + if(pic->icw_index++ >= pic->icw_words) pic->icw_index=0; + else if(pic->single) pic->icw_index=3; /* skip ICW3 in single mode */ + break; + case 2: /* icw 3 */ + LOG(LOG_PIC,LOG_NORMAL)("%d:ICW 3 %X",port==0x21 ? 0 : 1,val); + if(pic->icw_index++ >= pic->icw_words) pic->icw_index=0; + break; + case 3: /* icw 4 */ + /* + 0 1 8086/8080 0 mcs-8085 mode + 1 1 Auto EOI 0 Normal EOI + 2-3 0x Non buffer Mode + 10 Buffer Mode Slave + 11 Buffer mode Master + 4 Special/Not Special nested mode + */ + pic->auto_eoi=(val & 0x2)>0; + + LOG(LOG_PIC,LOG_NORMAL)("%d:ICW 4 %X",port==0x21 ? 0 : 1,val); + + if ((val&0x01)==0) E_Exit("PIC:ICW4: %x, 8085 mode not handled",val); + if ((val&0x10)!=0) LOG_MSG("PIC:ICW4: %x, special fully-nested mode not handled",val); + + if(pic->icw_index++ >= pic->icw_words) pic->icw_index=0; + break; + default: + LOG(LOG_PIC,LOG_NORMAL)("ICW HUH? %X",val); + break; + } +} + + +static Bitu read_command(Bitu port,Bitu iolen) { + PIC_Controller * pic=&pics[port==0x20 ? 0 : 1]; + Bitu irq_base=(port==0x20) ? 0 : 8; + Bitu i;Bit8u ret=0;Bit8u b=1; + if (pic->request_issr) { + for (i=irq_base;i 7 && irqs[2].masked) return false; + irqs[i].active = false; + PIC_IRQCheck&= ~(1 << i); + PIC_IRQOnSecondPicActive&= ~(1 << i); + CPU_HW_Interrupt(irqs[i].vector); + Bitu pic=(i&8)>>3; + if (!pics[pic].auto_eoi) { //irq 0-7 => pic 0 else pic 1 + PIC_IRQActive = i; + irqs[i].inservice = true; + } else if (GCC_UNLIKELY(pics[pic].rotate_on_auto_eoi)) { + E_Exit("rotate on auto EOI not handled"); + } + return true; +} + +void PIC_runIRQs(void) { + if (!GETFLAG(IF)) return; + if (GCC_UNLIKELY(!PIC_IRQCheck)) return; + if (GCC_UNLIKELY(cpudecoder==CPU_Core_Normal_Trap_Run)) return; + + static Bitu IRQ_priority_order[16] = + { 0,1,2,8,9,10,11,12,13,14,15,3,4,5,6,7 }; + static Bit16u IRQ_priority_lookup[17] = + { 0,1,2,11,12,13,14,15,3,4,5,6,7,8,9,10,16 }; + Bit16u activeIRQ = PIC_IRQActive; + if (activeIRQ == PIC_NOIRQ) activeIRQ = 16; + /* Get the priority of the active irq */ + Bit16u Priority_Active_IRQ = IRQ_priority_lookup[activeIRQ]; + + Bitu i,j; + /* j is the priority (walker) + * i is the irq at the current priority */ + + /* If one of the pics is in special mode use a check that cares for that. */ + if(!PIC_Special_Mode) { + for (j = 0; j < Priority_Active_IRQ; j++) { + i = IRQ_priority_order[j]; + if (!irqs[i].masked && irqs[i].active) { + if(GCC_LIKELY(PIC_startIRQ(i))) return; + } + } + } else { /* Special mode variant */ + for (j = 0; j<= 15; j++) { + i = IRQ_priority_order[j]; + if ( (j < Priority_Active_IRQ) || (pics[ ((i&8)>>3) ].special) ) { + if (!irqs[i].masked && irqs[i].active) { + /* the irq line is active. it's not masked and + * the irq is allowed priority wise. So let's start it */ + /* If started successfully return, else go for the next */ + if(PIC_startIRQ(i)) return; + } + } + } + } +} + +void PIC_SetIRQMask(Bitu irq, bool masked) { + if(irqs[irq].masked == masked) return; /* Do nothing if mask doesn't change */ + bool old_irq2_mask = irqs[2].masked; + irqs[irq].masked=masked; + if(irq < 8) { + if (irqs[irq].active && !irqs[irq].masked) { + PIC_IRQCheck|=(1 << (irq)); + } else { + PIC_IRQCheck&=~(1 << (irq)); + } + } else { + if (irqs[irq].active && !irqs[irq].masked && !irqs[2].masked) { + PIC_IRQCheck|=(1 << (irq)); + } else { + PIC_IRQCheck&=~(1 << (irq)); + } + } + if(irqs[2].masked != old_irq2_mask) { + /* Irq 2 mask has changed recheck second pic */ + for(Bitu i=8;i<=15;i++) { + if (irqs[i].active && !irqs[i].masked && !irqs[2].masked) PIC_IRQCheck|=(1 << (i)); + else PIC_IRQCheck&=~(1 << (i)); + } + } + if (PIC_IRQCheck) { + CPU_CycleLeft+=CPU_Cycles; + CPU_Cycles=0; + } +} + +static void AddEntry(PICEntry * entry) { + PICEntry * find_entry=pic_queue.next_entry; + if (GCC_UNLIKELY(find_entry ==0)) { + entry->next=0; + pic_queue.next_entry=entry; + } else if (find_entry->index>entry->index) { + pic_queue.next_entry=entry; + entry->next=find_entry; + } else while (find_entry) { + if (find_entry->next) { + /* See if the next index comes later than this one */ + if (find_entry->next->index > entry->index) { + entry->next=find_entry->next; + find_entry->next=entry; + break; + } else { + find_entry=find_entry->next; + } + } else { + entry->next=find_entry->next; + find_entry->next=entry; + break; + } + } + Bits cycles=PIC_MakeCycles(pic_queue.next_entry->index-PIC_TickIndex()); + if (cyclesindex = delay + srv_lag; + else entry->index = delay + PIC_TickIndex(); + + entry->pic_event=handler; + entry->value=val; + pic_queue.free_entry=pic_queue.free_entry->next; + AddEntry(entry); +} + +void PIC_RemoveSpecificEvents(PIC_EventHandler handler, Bitu val) { + PICEntry * entry=pic_queue.next_entry; + PICEntry * prev_entry; + prev_entry = 0; + while (entry) { + if (GCC_UNLIKELY((entry->pic_event == handler)) && (entry->value == val)) { + if (prev_entry) { + prev_entry->next=entry->next; + entry->next=pic_queue.free_entry; + pic_queue.free_entry=entry; + entry=prev_entry->next; + continue; + } else { + pic_queue.next_entry=entry->next; + entry->next=pic_queue.free_entry; + pic_queue.free_entry=entry; + entry=pic_queue.next_entry; + continue; + } + } + prev_entry=entry; + entry=entry->next; + } +} + +void PIC_RemoveEvents(PIC_EventHandler handler) { + PICEntry * entry=pic_queue.next_entry; + PICEntry * prev_entry; + prev_entry=0; + while (entry) { + if (GCC_UNLIKELY(entry->pic_event==handler)) { + if (prev_entry) { + prev_entry->next=entry->next; + entry->next=pic_queue.free_entry; + pic_queue.free_entry=entry; + entry=prev_entry->next; + continue; + } else { + pic_queue.next_entry=entry->next; + entry->next=pic_queue.free_entry; + pic_queue.free_entry=entry; + entry=pic_queue.next_entry; + continue; + } + } + prev_entry=entry; + entry=entry->next; + } +} + + +bool PIC_RunQueue(void) { + /* Check to see if a new milisecond needs to be started */ + CPU_CycleLeft+=CPU_Cycles; + CPU_Cycles=0; + if (CPU_CycleLeft<=0) { + return false; + } + /* Check the queue for an entry */ + Bits index_nd=PIC_TickIndexND(); + InEventService = true; + while (pic_queue.next_entry && (pic_queue.next_entry->index*CPU_CycleMax<=index_nd)) { + PICEntry * entry=pic_queue.next_entry; + pic_queue.next_entry=entry->next; + + srv_lag = entry->index; + (entry->pic_event)(entry->value); // call the event handler + + /* Put the entry in the free list */ + entry->next=pic_queue.free_entry; + pic_queue.free_entry=entry; + } + InEventService = false; + + /* Check when to set the new cycle end */ + if (pic_queue.next_entry) { + Bits cycles=(Bits)(pic_queue.next_entry->index*CPU_CycleMax-index_nd); + if (GCC_UNLIKELY(!cycles)) cycles=1; + if (cycleshandler==handler) { + *tick_where=ticker->next; + delete ticker; + return; + } + tick_where=&ticker->next; + ticker=ticker->next; + } +} + +void TIMER_AddTickHandler(TIMER_TickHandler handler) { + TickerBlock * newticker=new TickerBlock; + newticker->next=firstticker; + newticker->handler=handler; + firstticker=newticker; +} + +void TIMER_AddTick(void) { + /* Setup new amount of cycles for PIC */ + CPU_CycleLeft=CPU_CycleMax; + CPU_Cycles=0; + PIC_Ticks++; + /* Go through the list of scheduled events and lower their index with 1000 */ + PICEntry * entry=pic_queue.next_entry; + while (entry) { + entry->index -= 1.0; + entry=entry->next; + } + /* Call our list of ticker handlers */ + TickerBlock * ticker=firstticker; + while (ticker) { + TickerBlock * nextticker=ticker->next; + ticker->handler(); + ticker=nextticker; + } +} +#endif + +void x86_pic_write(Bitu port, Bitu val) +{ + switch(port) + { + case 0x20: + case 0xa0: + write_command(port, val, 1); + break; + case 0x21: + case 0xa1: + write_data(port, val, 1); + break; + } +} +Bitu x86_pic_read(Bitu port) +{ + switch (port) + { + case 0x20: + case 0xa0: + return read_command(port, 1); + case 0x21: + case 0xa1: + return read_data(port, 1); + break; + } + return 0; +} + +class PIC:public Module_base{ +private: +// IO_ReadHandleObject ReadHandler[4]; +// IO_WriteHandleObject WriteHandler[4]; +public: + PIC(Section* configuration):Module_base(configuration){ + /* Setup pic0 and pic1 with initial values like DOS has normally */ + PIC_IRQCheck=0; + PIC_IRQActive=PIC_NOIRQ; + PIC_Ticks=0; + Bitu i; + for (i=0;i<2;i++) { + pics[i].masked=0xff; + pics[i].auto_eoi=false; + pics[i].rotate_on_auto_eoi=false; + pics[i].request_issr=false; + pics[i].special=false; + pics[i].single=false; + pics[i].icw_index=0; + pics[i].icw_words=0; + } + for (i=0;i<=7;i++) { + irqs[i].active=false; + irqs[i].masked=true; + irqs[i].inservice=false; + irqs[i+8].active=false; + irqs[i+8].masked=true; + irqs[i+8].inservice=false; + irqs[i].vector=0x8+i; + irqs[i+8].vector=0x70+i; + } + irqs[0].masked=false; /* Enable system timer */ + irqs[1].masked=false; /* Enable Keyboard IRQ */ + irqs[2].masked=false; /* Enable second pic */ + irqs[8].masked=false; /* Enable RTC IRQ */ +#if 0 + if (machine==MCH_PCJR) { + /* Enable IRQ6 (replacement for the NMI for PCJr) */ + irqs[6].masked=false; + } + ReadHandler[0].Install(0x20,read_command,IO_MB); + ReadHandler[1].Install(0x21,read_data,IO_MB); + WriteHandler[0].Install(0x20,write_command,IO_MB); + WriteHandler[1].Install(0x21,write_data,IO_MB); + ReadHandler[2].Install(0xa0,read_command,IO_MB); + ReadHandler[3].Install(0xa1,read_data,IO_MB); + WriteHandler[2].Install(0xa0,write_command,IO_MB); + WriteHandler[3].Install(0xa1,write_data,IO_MB); +#endif + /* Initialize the pic queue */ + for (i=0;iAddDestroyFunction(&PIC_Destroy); +} diff --git a/dosbox/pic.h b/dosbox/pic.h new file mode 100644 index 00000000..8b6e2f4d --- /dev/null +++ b/dosbox/pic.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef DOSBOX_PIC_H +#define DOSBOX_PIC_H + + +/* CPU Cycle Timing */ +extern Bit32s CPU_Cycles; +extern Bit32s CPU_CycleLeft; +extern Bit32s CPU_CycleMax; + +typedef void (PIC_EOIHandler) (void); +typedef void (* PIC_EventHandler)(Bitu val); + + +#define PIC_MAXIRQ 15 +#define PIC_NOIRQ 0xFF + +extern Bitu PIC_IRQCheck; +extern Bitu PIC_IRQActive; +extern Bitu PIC_Ticks; + +static INLINE float PIC_TickIndex(void) { + return (CPU_CycleMax-CPU_CycleLeft-CPU_Cycles)/(float)CPU_CycleMax; +} + +static INLINE Bits PIC_TickIndexND(void) { + return CPU_CycleMax-CPU_CycleLeft-CPU_Cycles; +} + +static INLINE Bits PIC_MakeCycles(double amount) { + return (Bits)(CPU_CycleMax*amount); +} + +static INLINE double PIC_FullIndex(void) { + return PIC_Ticks+(double)PIC_TickIndex(); +} + +void PIC_ActivateIRQ(Bitu irq); +void PIC_DeActivateIRQ(Bitu irq); + +void PIC_runIRQs(void); +bool PIC_RunQueue(void); + +//Delay in milliseconds +void PIC_AddEvent(PIC_EventHandler handler,float delay,Bitu val=0); +void PIC_RemoveEvents(PIC_EventHandler handler); +void PIC_RemoveSpecificEvents(PIC_EventHandler handler, Bitu val); + +void PIC_SetIRQMask(Bitu irq, bool masked); +#endif diff --git a/dosbox/regs.h b/dosbox/regs.h new file mode 100644 index 00000000..13da9233 --- /dev/null +++ b/dosbox/regs.h @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef DOSBOX_REGS_H +#define DOSBOX_REGS_H + +#ifndef DOSBOX_MEM_H +#include "mem.h" +#endif + +#define FLAG_CF 0x00000001 +#define FLAG_PF 0x00000004 +#define FLAG_AF 0x00000010 +#define FLAG_ZF 0x00000040 +#define FLAG_SF 0x00000080 +#define FLAG_OF 0x00000800 + +#define FLAG_TF 0x00000100 +#define FLAG_IF 0x00000200 +#define FLAG_DF 0x00000400 + +#define FLAG_IOPL 0x00003000 +#define FLAG_NT 0x00004000 +#define FLAG_VM 0x00020000 +#define FLAG_AC 0x00040000 +#define FLAG_ID 0x00200000 + +#define FMASK_TEST (FLAG_CF | FLAG_PF | FLAG_AF | FLAG_ZF | FLAG_SF | FLAG_OF) +#define FMASK_NORMAL (FMASK_TEST | FLAG_DF | FLAG_TF | FLAG_IF | FLAG_AC ) +#define FMASK_ALL (FMASK_NORMAL | FLAG_IOPL | FLAG_NT) + +#define SETFLAGBIT(TYPE,TEST) if (TEST) reg_flags|=FLAG_ ## TYPE; else reg_flags&=~FLAG_ ## TYPE + +#define GETFLAG(TYPE) (reg_flags & FLAG_ ## TYPE) +#define GETFLAGBOOL(TYPE) ((reg_flags & FLAG_ ## TYPE) ? true : false ) + +#define GETFLAG_IOPL ((reg_flags & FLAG_IOPL) >> 12) + +struct Segment { + Bit16u val; + PhysPt phys; /* The phyiscal address start in emulated machine */ +}; + +enum SegNames { es=0,cs,ss,ds,fs,gs}; + +struct Segments { + Bitu val[8]; + PhysPt phys[8]; +}; + +union GenReg32 { + Bit32u dword[1]; + Bit16u word[2]; + Bit8u byte[4]; +}; + +#ifdef WORDS_BIGENDIAN + +#define DW_INDEX 0 +#define W_INDEX 1 +#define BH_INDEX 2 +#define BL_INDEX 3 + +#else + +#define DW_INDEX 0 +#define W_INDEX 0 +#define BH_INDEX 1 +#define BL_INDEX 0 + +#endif + +struct CPU_Regs { + GenReg32 regs[8],ip; + Bitu flags; +}; + +extern Segments Segs; +extern CPU_Regs cpu_regs; + +static INLINE PhysPt SegPhys(SegNames index) { + return Segs.phys[index]; +} + +static INLINE Bit16u SegValue(SegNames index) { + return (Bit16u)Segs.val[index]; +} + +static INLINE RealPt RealMakeSeg(SegNames index,Bit16u off) { + return RealMake(SegValue(index),off); +} + + +static INLINE void SegSet16(Bitu index,Bit16u val) { + Segs.val[index]=val; + Segs.phys[index]=val << 4; +} + +enum { + REGI_AX, REGI_CX, REGI_DX, REGI_BX, + REGI_SP, REGI_BP, REGI_SI, REGI_DI +}; + +enum { + REGI_AL, REGI_CL, REGI_DL, REGI_BL, + REGI_AH, REGI_CH, REGI_DH, REGI_BH +}; + + +//macros to convert a 3-bit register index to the correct register +#define reg_8l(reg) (cpu_regs.regs[(reg)].byte[BL_INDEX]) +#define reg_8h(reg) (cpu_regs.regs[(reg)].byte[BH_INDEX]) +#define reg_8(reg) ((reg) & 4 ? reg_8h((reg) & 3) : reg_8l((reg) & 3)) +#define reg_16(reg) (cpu_regs.regs[(reg)].word[W_INDEX]) +#define reg_32(reg) (cpu_regs.regs[(reg)].dword[DW_INDEX]) + +#define reg_al cpu_regs.regs[REGI_AX].byte[BL_INDEX] +#define reg_ah cpu_regs.regs[REGI_AX].byte[BH_INDEX] +#define reg_ax cpu_regs.regs[REGI_AX].word[W_INDEX] +#define reg_eax cpu_regs.regs[REGI_AX].dword[DW_INDEX] + +#define reg_bl cpu_regs.regs[REGI_BX].byte[BL_INDEX] +#define reg_bh cpu_regs.regs[REGI_BX].byte[BH_INDEX] +#define reg_bx cpu_regs.regs[REGI_BX].word[W_INDEX] +#define reg_ebx cpu_regs.regs[REGI_BX].dword[DW_INDEX] + +#define reg_cl cpu_regs.regs[REGI_CX].byte[BL_INDEX] +#define reg_ch cpu_regs.regs[REGI_CX].byte[BH_INDEX] +#define reg_cx cpu_regs.regs[REGI_CX].word[W_INDEX] +#define reg_ecx cpu_regs.regs[REGI_CX].dword[DW_INDEX] + +#define reg_dl cpu_regs.regs[REGI_DX].byte[BL_INDEX] +#define reg_dh cpu_regs.regs[REGI_DX].byte[BH_INDEX] +#define reg_dx cpu_regs.regs[REGI_DX].word[W_INDEX] +#define reg_edx cpu_regs.regs[REGI_DX].dword[DW_INDEX] + +#define reg_si cpu_regs.regs[REGI_SI].word[W_INDEX] +#define reg_esi cpu_regs.regs[REGI_SI].dword[DW_INDEX] + +#define reg_di cpu_regs.regs[REGI_DI].word[W_INDEX] +#define reg_edi cpu_regs.regs[REGI_DI].dword[DW_INDEX] + +#define reg_sp cpu_regs.regs[REGI_SP].word[W_INDEX] +#define reg_esp cpu_regs.regs[REGI_SP].dword[DW_INDEX] + +#define reg_bp cpu_regs.regs[REGI_BP].word[W_INDEX] +#define reg_ebp cpu_regs.regs[REGI_BP].dword[DW_INDEX] + +#define reg_ip cpu_regs.ip.word[W_INDEX] +#define reg_eip cpu_regs.ip.dword[DW_INDEX] + +#define reg_flags cpu_regs.flags + +#endif diff --git a/dosbox/setup.h b/dosbox/setup.h new file mode 100644 index 00000000..db75ada8 --- /dev/null +++ b/dosbox/setup.h @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id: setup.h,v 1.41 2009-05-27 09:15:41 qbix79 Exp $ */ + +#ifndef DOSBOX_SETUP_H +#define DOSBOX_SETUP_H + +#ifdef _MSC_VER +#pragma warning ( disable : 4786 ) +#pragma warning ( disable : 4290 ) +#endif + + +#ifndef CH_LIST +#define CH_LIST +#include +#endif + +#ifndef CH_VECTOR +#define CH_VECTOR +#include +#endif + +#ifndef CH_STRING +#define CH_STRING +#include +#endif + + +class Hex { +private: + int _hex; +public: + Hex(int in):_hex(in) { }; + Hex():_hex(0) { }; + bool operator==(Hex const& other) {return _hex == other._hex;} + operator int () const { return _hex; } + +}; + +class Value { +/* + * Multitype storage container that is aware of the currently stored type in it. + * Value st = "hello"; + * Value in = 1; + * st = 12 //Exception + * in = 12 //works + */ +private: + Hex _hex; + bool _bool; + int _int; + std::string* _string; + double _double; +public: + class WrongType { }; // Conversion error class + enum Etype { V_NONE, V_HEX, V_BOOL, V_INT, V_STRING, V_DOUBLE,V_CURRENT} type; + + /* Constructors */ + Value() :_string(0), type(V_NONE) { }; + Value(Hex in) :_hex(in), type(V_HEX) { }; + Value(int in) :_int(in), type(V_INT) { }; + Value(bool in) :_bool(in), type(V_BOOL) { }; + Value(double in) :_double(in), type(V_DOUBLE) { }; + Value(std::string const& in) :_string(new std::string(in)),type(V_STRING) { }; + Value(char const * const in) :_string(new std::string(in)),type(V_STRING) { }; + Value(Value const& in):_string(0) {plaincopy(in);} + ~Value() { destroy();}; + Value(std::string const& in,Etype _t) :_string(0),type(V_NONE) {SetValue(in,_t);} + + /* Assigment operators */ + Value& operator= (Hex in) throw(WrongType) { return copy(Value(in));} + Value& operator= (int in) throw(WrongType) { return copy(Value(in));} + Value& operator= (bool in) throw(WrongType) { return copy(Value(in));} + Value& operator= (double in) throw(WrongType) { return copy(Value(in));} + Value& operator= (std::string const& in) throw(WrongType) { return copy(Value(in));} + Value& operator= (char const * const in) throw(WrongType) { return copy(Value(in));} + Value& operator= (Value const& in) throw(WrongType) { return copy(Value(in));} + + bool operator== (Value const & other); + operator bool () const throw(WrongType); + operator Hex () const throw(WrongType); + operator int () const throw(WrongType); + operator double () const throw(WrongType); + operator char const* () const throw(WrongType); + void SetValue(std::string const& in,Etype _type = V_CURRENT) throw(WrongType); + std::string ToString() const; + +private: + void destroy() throw(); + Value& copy(Value const& in) throw(WrongType); + void plaincopy(Value const& in) throw(); + void set_hex(std::string const& in); + void set_int(std::string const&in); + void set_bool(std::string const& in); + void set_string(std::string const& in); + void set_double(std::string const& in); +}; + +class Property { +public: + struct Changeable { enum Value {Always, WhenIdle,OnlyAtStart};}; + const std::string propname; + + Property(std::string const& _propname, Changeable::Value when):propname(_propname),change(when) { } + void Set_values(const char * const * in); + void Set_help(std::string const& str); + char const* Get_help(); + virtual void SetValue(std::string const& str)=0; + Value const& GetValue() const { return value;} + Value const& Get_Default_Value() const { return default_value; } + //CheckValue returns true if value is in suggested_values; + //Type specific properties are encouraged to override this and check for type + //specific features. + virtual bool CheckValue(Value const& in, bool warn); + //Set interval value to in or default if in is invalid. force always sets the value. + void SetVal(Value const& in, bool forced,bool warn=true) {if(forced || CheckValue(in,warn)) value = in; else value = default_value;} + virtual ~Property(){ } + virtual const std::vector& GetValues() const; + Value::Etype Get_type(){return default_value.type;} + +protected: + Value value; + std::vector suggested_values; + typedef std::vector::iterator iter; + Value default_value; + const Changeable::Value change; +}; + +class Prop_int:public Property { +public: + Prop_int(std::string const& _propname,Changeable::Value when, int _value) + :Property(_propname,when) { + default_value = value = _value; + min = max = -1; + } + Prop_int(std::string const& _propname,Changeable::Value when, int _min,int _max,int _value) + :Property(_propname,when) { + default_value = value = _value; + min = _min; + max = _max; + } + void SetMinMax(Value const& min,Value const& max) {this->min = min; this->max=max;} + void SetValue(std::string const& in); + ~Prop_int(){ } + virtual bool CheckValue(Value const& in, bool warn); +private: + Value min,max; +}; + +class Prop_double:public Property { +public: + Prop_double(std::string const & _propname, Changeable::Value when, double _value) + :Property(_propname,when){ + default_value = value = _value; + } + void SetValue(std::string const& input); + ~Prop_double(){ } +}; + +class Prop_bool:public Property { +public: + Prop_bool(std::string const& _propname, Changeable::Value when, bool _value) + :Property(_propname,when) { + default_value = value = _value; + } + void SetValue(std::string const& in); + ~Prop_bool(){ } +}; + +class Prop_string:public Property{ +public: + Prop_string(std::string const& _propname, Changeable::Value when, char const * const _value) + :Property(_propname,when) { + default_value = value = _value; + } + void SetValue(std::string const& in); + virtual bool CheckValue(Value const& in, bool warn); + ~Prop_string(){ } +}; +class Prop_path:public Prop_string{ +public: + std::string realpath; + Prop_path(std::string const& _propname, Changeable::Value when, char const * const _value) + :Prop_string(_propname,when,_value) { + default_value = value = _value; + realpath = _value; + } + void SetValue(std::string const& in); + ~Prop_path(){ } +}; + +class Prop_hex:public Property { +public: + Prop_hex(std::string const& _propname, Changeable::Value when, Hex _value) + :Property(_propname,when) { + default_value = value = _value; + } + void SetValue(std::string const& in); + ~Prop_hex(){ } +}; + +#define NO_SUCH_PROPERTY "PROP_NOT_EXIST" +class Section { +private: + typedef void (*SectionFunction)(Section*); + /* Wrapper class around startup and shutdown functions. the variable + * canchange indicates it can be called on configuration changes */ + struct Function_wrapper { + SectionFunction function; + bool canchange; + Function_wrapper(SectionFunction const _fun,bool _ch){ + function=_fun; + canchange=_ch; + } + }; + std::list initfunctions; + std::list destroyfunctions; + std::string sectionname; +public: + Section(std::string const& _sectionname):sectionname(_sectionname) { } + + void AddInitFunction(SectionFunction func,bool canchange=false); + void AddDestroyFunction(SectionFunction func,bool canchange=false); + void ExecuteInit(bool initall=true); + void ExecuteDestroy(bool destroyall=true); + const char* GetName() const {return sectionname.c_str();} + + virtual std::string GetPropValue(std::string const& _property) const =0; + virtual void HandleInputline(std::string const& _line)=0; + virtual void PrintData(FILE* outfile) const =0; + virtual ~Section() { /*Children must call executedestroy ! */} +}; + +class Prop_multival; +class Prop_multival_remain; +class Section_prop:public Section { +private: + std::list properties; + typedef std::list::iterator it; + typedef std::list::const_iterator const_it; + +public: + Section_prop(std::string const& _sectionname):Section(_sectionname){} + Prop_int* Add_int(std::string const& _propname, Property::Changeable::Value when, int _value=0); + Prop_string* Add_string(std::string const& _propname, Property::Changeable::Value when, char const * const _value=NULL); + Prop_path* Add_path(std::string const& _propname, Property::Changeable::Value when, char const * const _value=NULL); + Prop_bool* Add_bool(std::string const& _propname, Property::Changeable::Value when, bool _value=false); + Prop_hex* Add_hex(std::string const& _propname, Property::Changeable::Value when, Hex _value=0); +// void Add_double(char const * const _propname, double _value=0.0); + Prop_multival *Add_multi(std::string const& _propname, Property::Changeable::Value when,std::string const& sep); + Prop_multival_remain *Add_multiremain(std::string const& _propname, Property::Changeable::Value when,std::string const& sep); + + Property* Get_prop(int index); + int Get_int(std::string const& _propname) const; + const char* Get_string(std::string const& _propname) const; + bool Get_bool(std::string const& _propname) const; + Hex Get_hex(std::string const& _propname) const; + double Get_double(std::string const& _propname) const; + Prop_path* Get_path(std::string const& _propname) const; + Prop_multival* Get_multival(std::string const& _propname) const; + Prop_multival_remain* Get_multivalremain(std::string const& _propname) const; + void HandleInputline(std::string const& gegevens); + void PrintData(FILE* outfile) const; + virtual std::string GetPropValue(std::string const& _property) const; + //ExecuteDestroy should be here else the destroy functions use destroyed properties + virtual ~Section_prop(); +}; + +class Prop_multival:public Property{ +protected: + Section_prop* section; + std::string seperator; + void make_default_value(); +public: + Prop_multival(std::string const& _propname, Changeable::Value when,std::string const& sep):Property(_propname,when), section(new Section_prop("")),seperator(sep) { + default_value = value = ""; + } + Section_prop *GetSection() { return section; } + const Section_prop *GetSection() const { return section; } + virtual void SetValue(std::string const& input); + virtual const std::vector& GetValues() const; + ~Prop_multival() { delete section; } +}; //value bevat totale string. setvalue zet elk van de sub properties en checked die. + +class Prop_multival_remain:public Prop_multival{ +public: + Prop_multival_remain(std::string const& _propname, Changeable::Value when,std::string const& sep):Prop_multival(_propname,when,sep){ } + + virtual void SetValue(std::string const& input); +}; + + +class Section_line: public Section{ +public: + Section_line(std::string const& _sectionname):Section(_sectionname){} + ~Section_line(){ExecuteDestroy(true);} + void HandleInputline(std::string const& gegevens); + void PrintData(FILE* outfile) const; + virtual std::string GetPropValue(std::string const& _property) const; + std::string data; +}; + +class Module_base { + /* Base for all hardware and software "devices" */ +protected: + Section* m_configuration; +public: + Module_base(Section* configuration){m_configuration=configuration;}; +// Module_base(Section* configuration, SaveState* state) {}; + virtual ~Module_base(){/*LOG_MSG("executed")*/;};//Destructors are required + /* Returns true if succesful.*/ + virtual bool Change_Config(Section* /*newconfig*/) {return false;} ; +}; +#endif diff --git a/dosbox/support.h b/dosbox/support.h new file mode 100644 index 00000000..32e1e202 --- /dev/null +++ b/dosbox/support.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* $Id: support.h,v 1.18 2009-05-27 09:15:41 qbix79 Exp $ */ + +#ifndef DOSBOX_SUPPORT_H +#define DOSBOX_SUPPORT_H + +#include +#include +#include +#ifndef DOSBOX_DOSBOX_H +#include "dosbox.h" +#endif + +#if defined (_MSC_VER) /* MS Visual C++ */ +#define strcasecmp(a,b) stricmp(a,b) +#define strncasecmp(a,b,n) _strnicmp(a,b,n) +#endif + +#define safe_strncpy(a,b,n) do { strncpy((a),(b),(n)-1); (a)[(n)-1] = 0; } while (0) + +#ifdef HAVE_STRINGS_H +#include +#endif + +void strreplace(char * str,char o,char n); +char *ltrim(char *str); +char *rtrim(char *str); +char *trim(char * str); +char * upcase(char * str); +char * lowcase(char * str); + +bool ScanCMDBool(char * cmd,char const * const check); +char * ScanCMDRemain(char * cmd); +char * StripWord(char *&cmd); +bool IsDecWord(char * word); +bool IsHexWord(char * word); +Bits ConvDecWord(char * word); +Bits ConvHexWord(char * word); + +void upcase(std::string &str); +void lowcase(std::string &str); + +#endif