--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 <time.h>
+#include <math.h>
+
+#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);
+}
--- /dev/null
+/*
+ * 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) {
+
+}
--- /dev/null
+{
+ 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;
+ }
+}
--- /dev/null
+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;
+}
+
--- /dev/null
+#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
+
--- /dev/null
+/* 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<CPU_ARCHTYPE_486OLDSLOW) goto illegalopcode;
+ BSWAPW(inst_op1_w);
+ break;
+ case O_BSWAPd:
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegalopcode;
+ BSWAPD(inst_op1_d);
+ break;
+ case O_CMPXCHG:
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486NEWSLOW) goto illegalopcode;
+ FillFlags();
+ if (inst_op1_d==reg_eax) {
+ inst_op1_d=reg_32(inst.rm_index);
+ if (inst.rm<0xc0) SaveMd(inst.rm_eaa,inst_op1_d); // early write-pf
+ SETFLAGBIT(ZF,1);
+ } else {
+ if (inst.rm<0xc0) SaveMd(inst.rm_eaa,inst_op1_d); // early write-pf
+ reg_eax=inst_op1_d;
+ SETFLAGBIT(ZF,0);
+ }
+ break;
+ case O_FPU:
+#if C_FPU
+ if (x86_fpu_enabled) {
+ switch (((inst.rm>=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);
+
+}
--- /dev/null
+/* 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 },
+
+
+
+}
+};
+
+
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+{
+ 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.op<R_SCASB)) {
+ count_left=count-CPU_Cycles;
+ count=CPU_Cycles;
+ CPU_Cycles=0;
+ LoadIP();
+ } else {
+ /* Won't interrupt scas and cmps instruction since they can interrupt themselves */
+ if (inst.code.op<R_SCASB) CPU_Cycles-=count;
+ count_left=0;
+ }
+ }
+ add_index=cpu.direction;
+ if (count) switch (inst.code.op) {
+ case R_OUTSB:
+ for (;count>0;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);
+ }
+}
--- /dev/null
+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
+
--- /dev/null
+/*
+ * 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 <stdio.h>
+
+#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) {
+
+}
+
--- /dev/null
+/*
+ * 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)
--- /dev/null
+/*
+ * 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<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
+ break;
+ CASE_0F_B(0x20) /* MOV Rd.CRx */
+ {
+ 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;
+ 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<CPU_ARCHTYPE_PENTIUMSLOW) goto illegal_opcode;
+ Bit64s tsc=(Bit64s)(PIC_FullIndex()*(double)CPU_CycleMax);
+ reg_edx=(Bit32u)(tsc>>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<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ FillFlags();
+ GetRMrb;
+ if (rm >= 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<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ FillFlags();
+ GetRMrw;
+ if (rm >= 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<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ GetRMrb;Bit8u oldrmrb=*rmrb;
+ if (rm >= 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<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ GetRMrw;Bit16u oldrmrw=*rmrw;
+ if (rm >= 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<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPW(reg_ax);break;
+ CASE_0F_W(0xc9) /* BSWAP CX */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPW(reg_cx);break;
+ CASE_0F_W(0xca) /* BSWAP DX */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPW(reg_dx);break;
+ CASE_0F_W(0xcb) /* BSWAP BX */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPW(reg_bx);break;
+ CASE_0F_W(0xcc) /* BSWAP SP */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPW(reg_sp);break;
+ CASE_0F_W(0xcd) /* BSWAP BP */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPW(reg_bp);break;
+ CASE_0F_W(0xce) /* BSWAP SI */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPW(reg_si);break;
+ CASE_0F_W(0xcf) /* BSWAP DI */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPW(reg_di);break;
+
--- /dev/null
+/*
+ * 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_D(0x01) /* ADD Ed,Gd */
+ RMEdGd(ADDD);break;
+ CASE_D(0x03) /* ADD Gd,Ed */
+ RMGdEd(ADDD);break;
+ CASE_D(0x05) /* ADD EAX,Id */
+ EAXId(ADDD);break;
+ CASE_D(0x06) /* PUSH ES */
+ Push_32(SegValue(es));break;
+ CASE_D(0x07) /* POP ES */
+ if (CPU_PopSeg(es,true)) RUNEXCEPTION();
+ break;
+ CASE_D(0x09) /* OR Ed,Gd */
+ RMEdGd(ORD);break;
+ CASE_D(0x0b) /* OR Gd,Ed */
+ RMGdEd(ORD);break;
+ CASE_D(0x0d) /* OR EAX,Id */
+ EAXId(ORD);break;
+ CASE_D(0x0e) /* PUSH CS */
+ Push_32(SegValue(cs));break;
+ CASE_D(0x11) /* ADC Ed,Gd */
+ RMEdGd(ADCD);break;
+ CASE_D(0x13) /* ADC Gd,Ed */
+ RMGdEd(ADCD);break;
+ CASE_D(0x15) /* ADC EAX,Id */
+ EAXId(ADCD);break;
+ CASE_D(0x16) /* PUSH SS */
+ Push_32(SegValue(ss));break;
+ CASE_D(0x17) /* POP SS */
+ if (CPU_PopSeg(ss,true)) RUNEXCEPTION();
+ CPU_Cycles++;
+ break;
+ CASE_D(0x19) /* SBB Ed,Gd */
+ RMEdGd(SBBD);break;
+ CASE_D(0x1b) /* SBB Gd,Ed */
+ RMGdEd(SBBD);break;
+ CASE_D(0x1d) /* SBB EAX,Id */
+ EAXId(SBBD);break;
+ CASE_D(0x1e) /* PUSH DS */
+ Push_32(SegValue(ds));break;
+ CASE_D(0x1f) /* POP DS */
+ if (CPU_PopSeg(ds,true)) RUNEXCEPTION();
+ break;
+ CASE_D(0x21) /* AND Ed,Gd */
+ RMEdGd(ANDD);break;
+ CASE_D(0x23) /* AND Gd,Ed */
+ RMGdEd(ANDD);break;
+ CASE_D(0x25) /* AND EAX,Id */
+ EAXId(ANDD);break;
+ CASE_D(0x29) /* SUB Ed,Gd */
+ RMEdGd(SUBD);break;
+ CASE_D(0x2b) /* SUB Gd,Ed */
+ RMGdEd(SUBD);break;
+ CASE_D(0x2d) /* SUB EAX,Id */
+ EAXId(SUBD);break;
+ CASE_D(0x31) /* XOR Ed,Gd */
+ RMEdGd(XORD);break;
+ CASE_D(0x33) /* XOR Gd,Ed */
+ RMGdEd(XORD);break;
+ CASE_D(0x35) /* XOR EAX,Id */
+ EAXId(XORD);break;
+ CASE_D(0x39) /* CMP Ed,Gd */
+ RMEdGd(CMPD);break;
+ CASE_D(0x3b) /* CMP Gd,Ed */
+ RMGdEd(CMPD);break;
+ CASE_D(0x3d) /* CMP EAX,Id */
+ EAXId(CMPD);break;
+ CASE_D(0x40) /* INC EAX */
+ INCD(reg_eax,LoadRd,SaveRd);break;
+ CASE_D(0x41) /* INC ECX */
+ INCD(reg_ecx,LoadRd,SaveRd);break;
+ CASE_D(0x42) /* INC EDX */
+ INCD(reg_edx,LoadRd,SaveRd);break;
+ CASE_D(0x43) /* INC EBX */
+ INCD(reg_ebx,LoadRd,SaveRd);break;
+ CASE_D(0x44) /* INC ESP */
+ INCD(reg_esp,LoadRd,SaveRd);break;
+ CASE_D(0x45) /* INC EBP */
+ INCD(reg_ebp,LoadRd,SaveRd);break;
+ CASE_D(0x46) /* INC ESI */
+ INCD(reg_esi,LoadRd,SaveRd);break;
+ CASE_D(0x47) /* INC EDI */
+ INCD(reg_edi,LoadRd,SaveRd);break;
+ CASE_D(0x48) /* DEC EAX */
+ DECD(reg_eax,LoadRd,SaveRd);break;
+ CASE_D(0x49) /* DEC ECX */
+ DECD(reg_ecx,LoadRd,SaveRd);break;
+ CASE_D(0x4a) /* DEC EDX */
+ DECD(reg_edx,LoadRd,SaveRd);break;
+ CASE_D(0x4b) /* DEC EBX */
+ DECD(reg_ebx,LoadRd,SaveRd);break;
+ CASE_D(0x4c) /* DEC ESP */
+ DECD(reg_esp,LoadRd,SaveRd);break;
+ CASE_D(0x4d) /* DEC EBP */
+ DECD(reg_ebp,LoadRd,SaveRd);break;
+ CASE_D(0x4e) /* DEC ESI */
+ DECD(reg_esi,LoadRd,SaveRd);break;
+ CASE_D(0x4f) /* DEC EDI */
+ DECD(reg_edi,LoadRd,SaveRd);break;
+ CASE_D(0x50) /* PUSH EAX */
+ Push_32(reg_eax);break;
+ CASE_D(0x51) /* PUSH ECX */
+ Push_32(reg_ecx);break;
+ CASE_D(0x52) /* PUSH EDX */
+ Push_32(reg_edx);break;
+ CASE_D(0x53) /* PUSH EBX */
+ Push_32(reg_ebx);break;
+ CASE_D(0x54) /* PUSH ESP */
+ Push_32(reg_esp);break;
+ CASE_D(0x55) /* PUSH EBP */
+ Push_32(reg_ebp);break;
+ CASE_D(0x56) /* PUSH ESI */
+ Push_32(reg_esi);break;
+ CASE_D(0x57) /* PUSH EDI */
+ Push_32(reg_edi);break;
+ CASE_D(0x58) /* POP EAX */
+ reg_eax=Pop_32();break;
+ CASE_D(0x59) /* POP ECX */
+ reg_ecx=Pop_32();break;
+ CASE_D(0x5a) /* POP EDX */
+ reg_edx=Pop_32();break;
+ CASE_D(0x5b) /* POP EBX */
+ reg_ebx=Pop_32();break;
+ CASE_D(0x5c) /* POP ESP */
+ reg_esp=Pop_32();break;
+ CASE_D(0x5d) /* POP EBP */
+ reg_ebp=Pop_32();break;
+ CASE_D(0x5e) /* POP ESI */
+ reg_esi=Pop_32();break;
+ CASE_D(0x5f) /* POP EDI */
+ reg_edi=Pop_32();break;
+ CASE_D(0x60) /* PUSHAD */
+ {
+ Bitu tmpesp = reg_esp;
+ Push_32(reg_eax);Push_32(reg_ecx);Push_32(reg_edx);Push_32(reg_ebx);
+ Push_32(tmpesp);Push_32(reg_ebp);Push_32(reg_esi);Push_32(reg_edi);
+ }; break;
+ CASE_D(0x61) /* 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();
+ break;
+ CASE_D(0x62) /* BOUND Ed */
+ {
+ Bit32s bound_min, bound_max;
+ GetRMrd;GetEAa;
+ bound_min=LoadMd(eaa);
+ bound_max=LoadMd(eaa+4);
+ if ( (((Bit32s)*rmrd) < bound_min) || (((Bit32s)*rmrd) > 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;
+ }
+
+
--- /dev/null
+/*
+ * 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<CPU_ARCHTYPE_486NEWSLOW) goto illegal_opcode;
+ FillFlags();
+ GetRMrd;
+ if (rm >= 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<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ GetRMrd;Bit32u oldrmrd=*rmrd;
+ if (rm >= 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<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPD(reg_eax);break;
+ CASE_0F_D(0xc9) /* BSWAP ECX */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPD(reg_ecx);break;
+ CASE_0F_D(0xca) /* BSWAP EDX */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPD(reg_edx);break;
+ CASE_0F_D(0xcb) /* BSWAP EBX */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPD(reg_ebx);break;
+ CASE_0F_D(0xcc) /* BSWAP ESP */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPD(reg_esp);break;
+ CASE_0F_D(0xcd) /* BSWAP EBP */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPD(reg_ebp);break;
+ CASE_0F_D(0xce) /* BSWAP ESI */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPD(reg_esi);break;
+ CASE_0F_D(0xcf) /* BSWAP EDI */
+ if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
+ BSWAPD(reg_edi);break;
--- /dev/null
+/*
+ * 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_B(0x00) /* ADD Eb,Gb */
+ RMEbGb(ADDB);break;
+ CASE_W(0x01) /* ADD Ew,Gw */
+ RMEwGw(ADDW);break;
+ CASE_B(0x02) /* ADD Gb,Eb */
+ RMGbEb(ADDB);break;
+ CASE_W(0x03) /* ADD Gw,Ew */
+ RMGwEw(ADDW);break;
+ CASE_B(0x04) /* ADD AL,Ib */
+ ALIb(ADDB);break;
+ CASE_W(0x05) /* ADD AX,Iw */
+ AXIw(ADDW);break;
+ CASE_W(0x06) /* PUSH ES */
+ Push_16(SegValue(es));break;
+ CASE_W(0x07) /* POP ES */
+ if (CPU_PopSeg(es,false)) RUNEXCEPTION();
+ break;
+ CASE_B(0x08) /* OR Eb,Gb */
+ RMEbGb(ORB);break;
+ CASE_W(0x09) /* OR Ew,Gw */
+ RMEwGw(ORW);break;
+ CASE_B(0x0a) /* OR Gb,Eb */
+ RMGbEb(ORB);break;
+ CASE_W(0x0b) /* OR Gw,Ew */
+ RMGwEw(ORW);break;
+ CASE_B(0x0c) /* OR AL,Ib */
+ ALIb(ORB);break;
+ CASE_W(0x0d) /* OR AX,Iw */
+ AXIw(ORW);break;
+ CASE_W(0x0e) /* PUSH CS */
+ Push_16(SegValue(cs));break;
+ CASE_B(0x0f) /* 2 byte opcodes*/
+ core.opcode_index|=OPCODE_0F;
+ goto restart_opcode;
+ break;
+ CASE_B(0x10) /* ADC Eb,Gb */
+ RMEbGb(ADCB);break;
+ CASE_W(0x11) /* ADC Ew,Gw */
+ RMEwGw(ADCW);break;
+ CASE_B(0x12) /* ADC Gb,Eb */
+ RMGbEb(ADCB);break;
+ CASE_W(0x13) /* ADC Gw,Ew */
+ RMGwEw(ADCW);break;
+ CASE_B(0x14) /* ADC AL,Ib */
+ ALIb(ADCB);break;
+ CASE_W(0x15) /* ADC AX,Iw */
+ AXIw(ADCW);break;
+ CASE_W(0x16) /* PUSH SS */
+ Push_16(SegValue(ss));break;
+ CASE_W(0x17) /* POP SS */
+ if (CPU_PopSeg(ss,false)) RUNEXCEPTION();
+ CPU_Cycles++; //Always do another instruction
+ break;
+ CASE_B(0x18) /* SBB Eb,Gb */
+ RMEbGb(SBBB);break;
+ CASE_W(0x19) /* SBB Ew,Gw */
+ RMEwGw(SBBW);break;
+ CASE_B(0x1a) /* SBB Gb,Eb */
+ RMGbEb(SBBB);break;
+ CASE_W(0x1b) /* SBB Gw,Ew */
+ RMGwEw(SBBW);break;
+ CASE_B(0x1c) /* SBB AL,Ib */
+ ALIb(SBBB);break;
+ CASE_W(0x1d) /* SBB AX,Iw */
+ AXIw(SBBW);break;
+ CASE_W(0x1e) /* PUSH DS */
+ Push_16(SegValue(ds));break;
+ CASE_W(0x1f) /* POP DS */
+ if (CPU_PopSeg(ds,false)) RUNEXCEPTION();
+ break;
+ CASE_B(0x20) /* AND Eb,Gb */
+ RMEbGb(ANDB);break;
+ CASE_W(0x21) /* AND Ew,Gw */
+ RMEwGw(ANDW);break;
+ CASE_B(0x22) /* AND Gb,Eb */
+ RMGbEb(ANDB);break;
+ CASE_W(0x23) /* AND Gw,Ew */
+ RMGwEw(ANDW);break;
+ CASE_B(0x24) /* AND AL,Ib */
+ ALIb(ANDB);break;
+ CASE_W(0x25) /* AND AX,Iw */
+ AXIw(ANDW);break;
+ CASE_B(0x26) /* SEG ES: */
+ DO_PREFIX_SEG(es);break;
+ CASE_B(0x27) /* DAA */
+ DAA();break;
+ CASE_B(0x28) /* SUB Eb,Gb */
+ RMEbGb(SUBB);break;
+ CASE_W(0x29) /* SUB Ew,Gw */
+ RMEwGw(SUBW);break;
+ CASE_B(0x2a) /* SUB Gb,Eb */
+ RMGbEb(SUBB);break;
+ CASE_W(0x2b) /* SUB Gw,Ew */
+ RMGwEw(SUBW);break;
+ CASE_B(0x2c) /* SUB AL,Ib */
+ ALIb(SUBB);break;
+ CASE_W(0x2d) /* SUB AX,Iw */
+ AXIw(SUBW);break;
+ CASE_B(0x2e) /* SEG CS: */
+ DO_PREFIX_SEG(cs);break;
+ CASE_B(0x2f) /* DAS */
+ DAS();break;
+ CASE_B(0x30) /* XOR Eb,Gb */
+ RMEbGb(XORB);break;
+ CASE_W(0x31) /* XOR Ew,Gw */
+ RMEwGw(XORW);break;
+ CASE_B(0x32) /* XOR Gb,Eb */
+ RMGbEb(XORB);break;
+ CASE_W(0x33) /* XOR Gw,Ew */
+ RMGwEw(XORW);break;
+ CASE_B(0x34) /* XOR AL,Ib */
+ ALIb(XORB);break;
+ CASE_W(0x35) /* XOR AX,Iw */
+ AXIw(XORW);break;
+ CASE_B(0x36) /* SEG SS: */
+ DO_PREFIX_SEG(ss);break;
+ CASE_B(0x37) /* AAA */
+ AAA();break;
+ CASE_B(0x38) /* CMP Eb,Gb */
+ RMEbGb(CMPB);break;
+ CASE_W(0x39) /* CMP Ew,Gw */
+ RMEwGw(CMPW);break;
+ CASE_B(0x3a) /* CMP Gb,Eb */
+ RMGbEb(CMPB);break;
+ CASE_W(0x3b) /* CMP Gw,Ew */
+ RMGwEw(CMPW);break;
+ CASE_B(0x3c) /* CMP AL,Ib */
+ ALIb(CMPB);break;
+ CASE_W(0x3d) /* CMP AX,Iw */
+ AXIw(CMPW);break;
+ CASE_B(0x3e) /* SEG DS: */
+ DO_PREFIX_SEG(ds);break;
+ CASE_B(0x3f) /* AAS */
+ AAS();break;
+ CASE_W(0x40) /* INC AX */
+ INCW(reg_ax,LoadRw,SaveRw);break;
+ CASE_W(0x41) /* INC CX */
+ INCW(reg_cx,LoadRw,SaveRw);break;
+ CASE_W(0x42) /* INC DX */
+ INCW(reg_dx,LoadRw,SaveRw);break;
+ CASE_W(0x43) /* INC BX */
+ INCW(reg_bx,LoadRw,SaveRw);break;
+ CASE_W(0x44) /* INC SP */
+ INCW(reg_sp,LoadRw,SaveRw);break;
+ CASE_W(0x45) /* INC BP */
+ INCW(reg_bp,LoadRw,SaveRw);break;
+ CASE_W(0x46) /* INC SI */
+ INCW(reg_si,LoadRw,SaveRw);break;
+ CASE_W(0x47) /* INC DI */
+ INCW(reg_di,LoadRw,SaveRw);break;
+ CASE_W(0x48) /* DEC AX */
+ DECW(reg_ax,LoadRw,SaveRw);break;
+ CASE_W(0x49) /* DEC CX */
+ DECW(reg_cx,LoadRw,SaveRw);break;
+ CASE_W(0x4a) /* DEC DX */
+ DECW(reg_dx,LoadRw,SaveRw);break;
+ CASE_W(0x4b) /* DEC BX */
+ DECW(reg_bx,LoadRw,SaveRw);break;
+ CASE_W(0x4c) /* DEC SP */
+ DECW(reg_sp,LoadRw,SaveRw);break;
+ CASE_W(0x4d) /* DEC BP */
+ DECW(reg_bp,LoadRw,SaveRw);break;
+ CASE_W(0x4e) /* DEC SI */
+ DECW(reg_si,LoadRw,SaveRw);break;
+ CASE_W(0x4f) /* DEC DI */
+ DECW(reg_di,LoadRw,SaveRw);break;
+ CASE_W(0x50) /* PUSH AX */
+ Push_16(reg_ax);break;
+ CASE_W(0x51) /* PUSH CX */
+ Push_16(reg_cx);break;
+ CASE_W(0x52) /* PUSH DX */
+ Push_16(reg_dx);break;
+ CASE_W(0x53) /* PUSH BX */
+ Push_16(reg_bx);break;
+ CASE_W(0x54) /* PUSH SP */
+ Push_16(reg_sp);break;
+ CASE_W(0x55) /* PUSH BP */
+ Push_16(reg_bp);break;
+ CASE_W(0x56) /* PUSH SI */
+ Push_16(reg_si);break;
+ CASE_W(0x57) /* PUSH DI */
+ Push_16(reg_di);break;
+ CASE_W(0x58) /* POP AX */
+ reg_ax=Pop_16();break;
+ CASE_W(0x59) /* POP CX */
+ reg_cx=Pop_16();break;
+ CASE_W(0x5a) /* POP DX */
+ reg_dx=Pop_16();break;
+ CASE_W(0x5b) /* POP BX */
+ reg_bx=Pop_16();break;
+ CASE_W(0x5c) /* POP SP */
+ reg_sp=Pop_16();break;
+ CASE_W(0x5d) /* POP BP */
+ reg_bp=Pop_16();break;
+ CASE_W(0x5e) /* POP SI */
+ reg_si=Pop_16();break;
+ CASE_W(0x5f) /* POP DI */
+ reg_di=Pop_16();break;
+ CASE_W(0x60) /* PUSHA */
+ {
+ 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);
+ }
+ break;
+ CASE_W(0x61) /* POPA */
+ 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();
+ break;
+ CASE_W(0x62) /* BOUND */
+ {
+ Bit16s bound_min, bound_max;
+ GetRMrw;GetEAa;
+ bound_min=LoadMw(eaa);
+ bound_max=LoadMw(eaa+2);
+ if ( (((Bit16s)*rmrw) < bound_min) || (((Bit16s)*rmrw) > 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;
+ }
+
+
+
+
--- /dev/null
+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) && (type<R_SCASB)) {
+ count_left=count-CPU_Cycles;
+ count=CPU_Cycles;
+ CPU_Cycles=0;
+ LOADIP; //RESET IP to the start
+ } else {
+ /* Won't interrupt scas and cmps instruction since they can interrupt themselves */
+ if ((count<=1) && (CPU_Cycles<=1)) CPU_Cycles--;
+ else if (type<R_SCASB) CPU_Cycles-=count;
+ count_left=0;
+ }
+ }
+ add_index=cpu.direction;
+ if (count) switch (type) {
+ case R_OUTSB:
+ for (;count>0;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);
+ }
+}
--- /dev/null
+/*
+ * 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"
+
+
--- /dev/null
+/*
+ * 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(); \
+ } \
+
+
--- /dev/null
+/*
+ * 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 <stdio.h>
+
+#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) {
+
+}
--- /dev/null
+/*
+ * 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 <assert.h>
+#include <sstream>
+#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_IOPL<cpu.cpl)) || (GETFLAG(VM) && (GETFLAG_IOPL<3)))) {
+ return CPU_PrepareException(EXCEPTION_GP,0);
+ } else {
+ SETFLAGBIT(IF,false);
+ return false;
+ }
+}
+
+bool CPU_STI(void) {
+ if (cpu.pmode && ((!GETFLAG(VM) && (GETFLAG_IOPL<cpu.cpl)) || (GETFLAG(VM) && (GETFLAG_IOPL<3)))) {
+ return CPU_PrepareException(EXCEPTION_GP,0);
+ } else {
+ SETFLAGBIT(IF,true);
+ return false;
+ }
+}
+
+bool CPU_POPF(Bitu use32) {
+ if (cpu.pmode && GETFLAG(VM) && (GETFLAG(IOPL)!=FLAG_IOPL)) {
+ /* Not enough privileges to execute POPF */
+ return CPU_PrepareException(EXCEPTION_GP,0);
+ }
+ Bitu mask=FMASK_ALL;
+ /* IOPL field can only be modified when CPL=0 or in real mode: */
+ if (cpu.pmode && (cpu.cpl>0)) mask &= (~FLAG_IOPL);
+ if (cpu.pmode && !GETFLAG(VM) && (GETFLAG_IOPL<cpu.cpl)) mask &= (~FLAG_IF);
+ if (use32)
+ CPU_SetFlags(CPU_Pop32(),mask);
+ else CPU_SetFlags(CPU_Pop16(),mask & 0xffff);
+ DestroyConditionFlags();
+ return false;
+}
+
+bool CPU_PUSHF(Bitu use32) {
+ if (cpu.pmode && GETFLAG(VM) && (GETFLAG(IOPL)!=FLAG_IOPL)) {
+ /* Not enough privileges to execute PUSHF */
+ return CPU_PrepareException(EXCEPTION_GP,0);
+ }
+ FillFlags();
+ if (use32)
+ CPU_Push32(reg_flags & 0xfcffff);
+ else CPU_Push16(reg_flags);
+ return false;
+}
+
+void CPU_CheckSegments(void) {
+ bool needs_invalidation=false;
+ Descriptor desc;
+ if (!cpu.gdt.GetDescriptor(SegValue(es),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(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_IOPL<cpu.cpl) || GETFLAG(VM))) {
+ cpu.mpl=0;
+ if (!cpu_tss.is386) goto doexception;
+ PhysPt bwhere=cpu_tss.base+0x66;
+ Bitu ofs=mem_readw(bwhere);
+ if (ofs>cpu_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)) {
+ // zone66, win3.x e
+ CPU_Exception(EXCEPTION_GP,num*8+2);
+ return;
+ }
+
+
+ switch (gate.Type()) {
+ case DESC_286_INT_GATE: case DESC_386_INT_GATE:
+ case DESC_286_TRAP_GATE: case DESC_386_TRAP_GATE:
+ {
+ CPU_CHECK_COND(!gate.saved.seg.p,
+ "INT:Gate segment not present",
+ EXCEPTION_NP,num*8+2+(type&CPU_INT_SOFTWARE)?0:1)
+
+ Descriptor cs_desc;
+ Bitu gate_sel=gate.GetSelector();
+ Bitu gate_off=gate.GetOffset();
+ CPU_CHECK_COND((gate_sel & 0xfffc)==0,
+ "INT:Gate with CS zero selector",
+ EXCEPTION_GP,(type&CPU_INT_SOFTWARE)?0:1)
+ CPU_CHECK_COND(!cpu.gdt.GetDescriptor(gate_sel,cs_desc),
+ "INT:Gate with CS beyond limit",
+ EXCEPTION_GP,(gate_sel & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1)
+
+ Bitu cs_dpl=cs_desc.DPL();
+ CPU_CHECK_COND(cs_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_dpl<cpu.cpl) {
+ /* Prepare for gate to inner level */
+ CPU_CHECK_COND(!cs_desc.saved.seg.p,
+ "INT:Inner level:CS segment not present",
+ EXCEPTION_NP,(gate_sel & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1)
+ CPU_CHECK_COND((reg_flags & FLAG_VM) && (cs_dpl!=0),
+ "V86 interrupt calling codesegment with DPL>0",
+ 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_dpl<cpu.cpl))
+ E_Exit("V86 interrupt doesn't change to pl0"); // or #GP(cs_sel)
+
+ // commit point
+do_interrupt:
+ if (gate.Type() & 0x8) { /* 32-bit Gate */
+ CPU_Push32(reg_flags);
+ CPU_Push32(SegValue(cs));
+ CPU_Push32(oldeip);
+ if (type & CPU_INT_HAS_ERROR) CPU_Push32(cpu.exception.error);
+ } else { /* 16-bit gate */
+ CPU_Push16(reg_flags & 0xffff);
+ CPU_Push16(SegValue(cs));
+ CPU_Push16(oldeip);
+ if (type & CPU_INT_HAS_ERROR) CPU_Push16(cpu.exception.error);
+ }
+ break;
+ default:
+ E_Exit("INT:Gate Selector points to illegal descriptor with type %x",cs_desc.Type());
+ }
+
+ Segs.val[cs]=(gate_sel&0xfffc) | cpu.cpl;
+ Segs.phys[cs]=cs_desc.GetBase();
+ cpu.code.big=cs_desc.Big()>0;
+ 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_rpl<cpu.cpl,
+ "IRET to lower privilege",
+ EXCEPTION_GP,n_cs_sel & 0xfffc)
+
+ 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:
+ CPU_CHECK_COND(n_cs_rpl!=n_cs_desc.DPL(),
+ "IRET:NC:DPL!=RPL",
+ EXCEPTION_GP,n_cs_sel & 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(n_cs_desc.DPL()>n_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_IOPL<cpu.cpl) mask &= (~FLAG_IF);
+ CPU_SetFlags(n_flags,mask);
+ DestroyConditionFlags();
+ LOG(LOG_CPU,LOG_NORMAL)("IRET:Same level:%X:%X big %d",n_cs_sel,n_eip,cpu.code.big);
+ } else {
+ /* Return to outer level */
+ Bitu n_ss,n_esp;
+ if (use32) {
+ n_esp=mem_readd(SegPhys(ss) + (tempesp & cpu.stack.mask));
+ tempesp=(tempesp&cpu.stack.notmask)|((tempesp+4)&cpu.stack.mask);
+ n_ss=mem_readd(SegPhys(ss) + (tempesp & cpu.stack.mask)) & 0xffff;
+ } else {
+ n_esp=mem_readw(SegPhys(ss) + (tempesp & cpu.stack.mask));
+ tempesp=(tempesp&cpu.stack.notmask)|((tempesp+2)&cpu.stack.mask);
+ n_ss=mem_readw(SegPhys(ss) + (tempesp & cpu.stack.mask));
+ }
+ CPU_CHECK_COND((n_ss & 0xfffc)==0,
+ "IRET:Outer level:SS selector zero",
+ EXCEPTION_GP,0)
+ CPU_CHECK_COND((n_ss & 3)!=n_cs_rpl,
+ "IRET:Outer level:SS rpl!=CS rpl",
+ EXCEPTION_GP,n_ss & 0xfffc)
+ Descriptor n_ss_desc;
+ CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_ss,n_ss_desc),
+ "IRET:Outer level:SS beyond limit",
+ EXCEPTION_GP,n_ss & 0xfffc)
+ CPU_CHECK_COND(n_ss_desc.DPL()!=n_cs_rpl,
+ "IRET:Outer level:SS dpl!=CS rpl",
+ EXCEPTION_GP,n_ss & 0xfffc)
+
+ // 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("IRET:Outer level:Stack segment not writable"); // or #GP(ss_sel)
+ }
+ CPU_CHECK_COND(!n_ss_desc.saved.seg.p,
+ "IRET:Outer level:Stack segment not present",
+ EXCEPTION_NP,n_ss & 0xfffc)
+
+ // commit point
+
+ Segs.phys[cs]=n_cs_desc.GetBase();
+ cpu.code.big=n_cs_desc.Big()>0;
+ Segs.val[cs]=n_cs_sel;
+
+ Bitu mask=cpu.cpl ? (FMASK_NORMAL | FLAG_NT) : FMASK_ALL;
+ if (GETFLAG_IOPL<cpu.cpl) mask &= (~FLAG_IF);
+ CPU_SetFlags(n_flags,mask);
+ DestroyConditionFlags();
+
+ cpu.cpl=n_cs_rpl;
+ reg_eip=n_eip;
+
+ 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;
+ } else {
+ cpu.stack.big=false;
+ cpu.stack.mask=0xffff;
+ cpu.stack.notmask=0xffff0000;
+ reg_sp=n_esp & 0xffff;
+ }
+
+ // borland extender, zrdx
+ CPU_CheckSegments();
+
+ LOG(LOG_CPU,LOG_NORMAL)("IRET:Outer level:%X:%X big %d",n_cs_sel,n_eip,cpu.code.big);
+ }
+ return;
+ }
+}
+
+
+void CPU_JMP(bool use32,Bitu selector,Bitu offset,Bitu oldeip) {
+ if (!cpu.pmode || (reg_flags & FLAG_VM)) {
+ if (!use32) {
+ reg_eip=offset&0xffff;
+ } else {
+ reg_eip=offset;
+ }
+ SegSet16(cs,selector);
+ cpu.code.big=false;
+ return;
+ } else {
+ CPU_CHECK_COND((selector & 0xfffc)==0,
+ "JMP:CS selector zero",
+ EXCEPTION_GP,0)
+ Bitu rpl=selector & 3;
+ Descriptor desc;
+ CPU_CHECK_COND(!cpu.gdt.GetDescriptor(selector,desc),
+ "JMP:CS beyond limits",
+ EXCEPTION_GP,selector & 0xfffc)
+ 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(rpl>cpu.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.cpl<desc.DPL(),
+ "JMP:C:CPL < DPL",
+ EXCEPTION_GP,selector & 0xfffc)
+CODE_jmp:
+ if (!desc.saved.seg.p) {
+ // win
+ CPU_Exception(EXCEPTION_NP,selector & 0xfffc);
+ return;
+ }
+
+ /* Normal jump to another selector:offset */
+ Segs.phys[cs]=desc.GetBase();
+ cpu.code.big=desc.Big()>0;
+ Segs.val[cs]=(selector & 0xfffc) | cpu.cpl;
+ reg_eip=offset;
+ return;
+ case DESC_386_TSS_A:
+ CPU_CHECK_COND(desc.DPL()<cpu.cpl,
+ "JMP:TSS:dpl<cpl",
+ EXCEPTION_GP,selector & 0xfffc)
+ CPU_CHECK_COND(desc.DPL()<rpl,
+ "JMP:TSS:dpl<rpl",
+ EXCEPTION_GP,selector & 0xfffc)
+ LOG(LOG_CPU,LOG_NORMAL)("JMP:TSS to %X",selector);
+ CPU_SwitchTask(selector,TSwitch_JMP,oldeip);
+ break;
+ default:
+ E_Exit("JMP Illegal descriptor type %X",desc.Type());
+ }
+ }
+ assert(1);
+}
+
+
+void CPU_CALL(bool use32,Bitu selector,Bitu offset,Bitu oldeip) {
+ if (!cpu.pmode || (reg_flags & FLAG_VM)) {
+ if (!use32) {
+ CPU_Push16(SegValue(cs));
+ CPU_Push16(oldeip);
+ reg_eip=offset&0xffff;
+ } else {
+ CPU_Push32(SegValue(cs));
+ CPU_Push32(oldeip);
+ reg_eip=offset;
+ }
+ cpu.code.big=false;
+ SegSet16(cs,selector);
+ return;
+ } else {
+ CPU_CHECK_COND((selector & 0xfffc)==0,
+ "CALL:CS selector zero",
+ EXCEPTION_GP,0)
+ Bitu rpl=selector & 3;
+ Descriptor call;
+ CPU_CHECK_COND(!cpu.gdt.GetDescriptor(selector,call),
+ "CALL:CS beyond limits",
+ EXCEPTION_GP,selector & 0xfffc)
+ /* Check for type of far call */
+ switch (call.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(rpl>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:Gate DPL<CPL",
+ EXCEPTION_GP,selector & 0xfffc)
+ CPU_CHECK_COND(call.DPL()<rpl,
+ "CALL:Gate:Gate DPL<RPL",
+ EXCEPTION_GP,selector & 0xfffc)
+ CPU_CHECK_COND(!call.saved.seg.p,
+ "CALL:Gate:Segment not present",
+ EXCEPTION_NP,selector & 0xfffc)
+ Descriptor n_cs_desc;
+ Bitu n_cs_sel=call.GetSelector();
+
+ CPU_CHECK_COND((n_cs_sel & 0xfffc)==0,
+ "CALL:Gate:CS selector zero",
+ EXCEPTION_GP,0)
+ CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_cs_sel,n_cs_desc),
+ "CALL:Gate:CS beyond limits",
+ EXCEPTION_GP,n_cs_sel & 0xfffc)
+ Bitu n_cs_dpl = n_cs_desc.DPL();
+ CPU_CHECK_COND(n_cs_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,
+ "CALL:TSS:dpl<cpl",
+ EXCEPTION_GP,selector & 0xfffc)
+ CPU_CHECK_COND(call.DPL()<rpl,
+ "CALL:TSS:dpl<rpl",
+ EXCEPTION_GP,selector & 0xfffc)
+
+ CPU_CHECK_COND(!call.saved.seg.p,
+ "CALL:TSS:Segment not present",
+ EXCEPTION_NP,selector & 0xfffc)
+
+ LOG(LOG_CPU,LOG_NORMAL)("CALL:TSS to %X",selector);
+ CPU_SwitchTask(selector,TSwitch_CALL_INT,oldeip);
+ break;
+ case DESC_DATA_EU_RW_NA: // vbdos
+ case DESC_INVALID: // used by some installers
+ CPU_Exception(EXCEPTION_GP,selector & 0xfffc);
+ return;
+ default:
+ E_Exit("CALL:Descriptor type %x unsupported",call.Type());
+ }
+ }
+ assert(1);
+}
+
+
+void CPU_RET(bool use32,Bitu bytes,Bitu oldeip) {
+ if (!cpu.pmode || (reg_flags & FLAG_VM)) {
+ Bitu new_ip,new_cs;
+ if (!use32) {
+ new_ip=CPU_Pop16();
+ new_cs=CPU_Pop16();
+ } else {
+ new_ip=CPU_Pop32();
+ new_cs=CPU_Pop32() & 0xffff;
+ }
+ reg_esp+=bytes;
+ SegSet16(cs,new_cs);
+ reg_eip=new_ip;
+ cpu.code.big=false;
+ return;
+ } else {
+ Bitu offset,selector;
+ if (!use32) selector = mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask) + 2);
+ else selector = mem_readd(SegPhys(ss) + (reg_esp & cpu.stack.mask) + 4) & 0xffff;
+
+ Descriptor desc;
+ Bitu rpl=selector & 3;
+ if(rpl < cpu.cpl) {
+ // win setup
+ CPU_Exception(EXCEPTION_GP,selector & 0xfffc);
+ return;
+ }
+
+ CPU_CHECK_COND((selector & 0xfffc)==0,
+ "RET:CS selector zero",
+ EXCEPTION_GP,0)
+ CPU_CHECK_COND(!cpu.gdt.GetDescriptor(selector,desc),
+ "RET:CS beyond limits",
+ EXCEPTION_GP,selector & 0xfffc)
+
+ if (cpu.cpl==rpl) {
+ /* Return to same 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(cpu.cpl!=desc.DPL(),
+ "RET to NC segment of other privilege",
+ EXCEPTION_GP,selector & 0xfffc)
+ goto RET_same_level;
+ 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()>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_486OLDSLOW) {
+ if (cr==4) return CPU_PrepareException(EXCEPTION_UD,0);
+ }
+ CPU_SET_CRX(cr,value);
+ return false;
+}
+
+Bitu CPU_GET_CRX(Bitu cr) {
+ switch (cr) {
+ case 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_ArchitectureType<CPU_ARCHTYPE_PENTIUMSLOW) {
+ cpu.drx[7]=(value|0x400) & 0xffff2fff;
+ } else {
+ cpu.drx[7]=(value|0x400);
+ }
+ break;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV DR%d,%X",dr,value);
+ break;
+ }
+ return false;
+}
+
+bool CPU_READ_DRX(Bitu dr,Bit32u & retvalue) {
+ /* 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:
+ 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()<cpu.cpl || desc.DPL() < rpl) {
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ break;
+ default:
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ /* Valid descriptor */
+ ar=desc.saved.fill[1] & 0x00ffff00;
+ SETFLAGBIT(ZF,true);
+}
+
+void CPU_LSL(Bitu selector,Bitu & limit) {
+ 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_LDT:
+ case DESC_286_TSS_A:
+ case DESC_286_TSS_B:
+
+ case DESC_386_TSS_A:
+ case DESC_386_TSS_B:
+
+ 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()<cpu.cpl || desc.DPL() < rpl) {
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ break;
+ default:
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ limit=desc.GetLimit();
+ SETFLAGBIT(ZF,true);
+}
+
+void CPU_VERR(Bitu selector) {
+ 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_R_C_A: case DESC_CODE_R_C_NA:
+ //Conforming readable code segments can be always read
+ break;
+ 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_R_NC_A: case DESC_CODE_R_NC_NA:
+ if (desc.DPL()<cpu.cpl || desc.DPL() < rpl) {
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ break;
+ default:
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ SETFLAGBIT(ZF,true);
+}
+
+void CPU_VERW(Bitu selector) {
+ 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_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A:
+ case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A:
+ if (desc.DPL()<cpu.cpl || desc.DPL() < rpl) {
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ break;
+ default:
+ SETFLAGBIT(ZF,false);
+ return;
+ }
+ SETFLAGBIT(ZF,true);
+}
+
+bool CPU_SetSegGeneral(SegNames seg,Bitu value) {
+ value &= 0xffff;
+ if (!cpu.pmode || (reg_flags & FLAG_VM)) {
+ Segs.val[seg]=value;
+ Segs.phys[seg]=value << 4;
+ if (seg==ss) {
+ cpu.stack.big=false;
+ cpu.stack.mask=0xffff;
+ cpu.stack.notmask=0xffff0000;
+ }
+ return false;
+ } else {
+ if (seg==ss) {
+ // Stack needs to be non-zero
+ if ((value & 0xfffc)==0) {
+ E_Exit("CPU_SetSegGeneral: Stack segment zero");
+// return CPU_PrepareException(EXCEPTION_GP,0);
+ }
+ Descriptor desc;
+ if (!cpu.gdt.GetDescriptor(value,desc)) {
+ E_Exit("CPU_SetSegGeneral: Stack segment beyond limits");
+// return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc);
+ }
+ if (((value & 3)!=cpu.cpl) || (desc.DPL()!=cpu.cpl)) {
+ E_Exit("CPU_SetSegGeneral: Stack segment with invalid privileges");
+// return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc);
+ }
+
+ switch (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:
+ //Earth Siege 1
+ return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc);
+ }
+
+ if (!desc.saved.seg.p) {
+// E_Exit("CPU_SetSegGeneral: Stack segment not present"); // or #SS(sel)
+ return CPU_PrepareException(EXCEPTION_SS,value & 0xfffc);
+ }
+
+ Segs.val[seg]=value;
+ Segs.phys[seg]=desc.GetBase();
+ if (desc.Big()) {
+ cpu.stack.big=true;
+ cpu.stack.mask=0xffffffff;
+ cpu.stack.notmask=0;
+ } else {
+ cpu.stack.big=false;
+ cpu.stack.mask=0xffff;
+ cpu.stack.notmask=0xffff0000;
+ }
+ } else {
+ if ((value & 0xfffc)==0) {
+ Segs.val[seg]=value;
+ Segs.phys[seg]=0; // ??
+ return false;
+ }
+ Descriptor desc;
+ if (!cpu.gdt.GetDescriptor(value,desc)) {
+ return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc);
+ }
+ 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_R_NC_A: case DESC_CODE_R_NC_NA:
+ if (((value & 3)>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_ArchitectureType<CPU_ARCHTYPE_486NEWSLOW) return false;
+ switch (reg_eax) {
+ case 0: /* Vendor ID String and maximum level? */
+ reg_eax=1; /* Maximum level */
+ reg_ebx='G' | ('e' << 8) | ('n' << 16) | ('u'<< 24);
+ reg_edx='i' | ('n' << 8) | ('e' << 16) | ('I'<< 24);
+ reg_ecx='n' | ('t' << 8) | ('e' << 16) | ('l'<< 24);
+ break;
+ case 1: /* get processor type/family/model/stepping and feature flags */
+ if ((CPU_ArchitectureType==CPU_ARCHTYPE_486NEWSLOW) ||
+ (CPU_ArchitectureType==CPU_ARCHTYPE_MIXED)) {
+ reg_eax=0x402; /* intel 486dx */
+ reg_ebx=0; /* Not Supported */
+ reg_ecx=0; /* No features */
+ reg_edx=0x00000001; /* FPU */
+ } else if (CPU_ArchitectureType==CPU_ARCHTYPE_PENTIUMSLOW) {
+ reg_eax=0x513; /* intel pentium */
+ reg_ebx=0; /* Not Supported */
+ reg_ecx=0; /* No features */
+ reg_edx=0x00000011; /* FPU+TimeStamp/RDTSC */
+ } else {
+ return false;
+ }
+ break;
+ default:
+ LOG(LOG_CPU,LOG_ERROR)("Unhandled CPUID Function %x",reg_eax);
+ reg_eax=0;
+ reg_ebx=0;
+ reg_ecx=0;
+ reg_edx=0;
+ break;
+ }
+ return true;
+}
+
+static Bits HLT_Decode(void) {
+ /* Once an interrupt occurs, it should change cpu core */
+ if (reg_eip!=cpu.hlt.eip || SegValue(cs) != cpu.hlt.cs) {
+ cpudecoder=cpu.hlt.old_decoder;
+ } else {
+ CPU_Cycles=0;
+ }
+ return 0;
+}
+
+void CPU_HLT(Bitu oldeip) {
+ reg_eip=oldeip;
+ CPU_Cycles=0;
+ cpu.hlt.cs=SegValue(cs);
+ cpu.hlt.eip=reg_eip;
+ cpu.hlt.old_decoder=cpudecoder;
+ cpudecoder=&HLT_Decode;
+}
+
+void CPU_ENTER(bool use32,Bitu bytes,Bitu level) {
+ level&=0x1f;
+ Bitu sp_index=reg_esp&cpu.stack.mask;
+ Bitu bp_index=reg_ebp&cpu.stack.mask;
+ if (!use32) {
+ sp_index-=2;
+ mem_writew(SegPhys(ss)+sp_index,reg_bp);
+ reg_bp=(Bit16u)(reg_esp-2);
+ if (level) {
+ for (Bitu i=1;i<level;i++) {
+ sp_index-=2;bp_index-=2;
+ mem_writew(SegPhys(ss)+sp_index,mem_readw(SegPhys(ss)+bp_index));
+ }
+ sp_index-=2;
+ mem_writew(SegPhys(ss)+sp_index,reg_bp);
+ }
+ } else {
+ sp_index-=4;
+ mem_writed(SegPhys(ss)+sp_index,reg_ebp);
+ reg_ebp=(reg_esp-4);
+ if (level) {
+ for (Bitu i=1;i<level;i++) {
+ sp_index-=4;bp_index-=4;
+ mem_writed(SegPhys(ss)+sp_index,mem_readd(SegPhys(ss)+bp_index));
+ }
+ sp_index-=4;
+ mem_writed(SegPhys(ss)+sp_index,reg_ebp);
+ }
+ }
+ sp_index-=bytes;
+ reg_esp=(reg_esp&cpu.stack.notmask)|((sp_index)&cpu.stack.mask);
+}
+
+static void CPU_CycleIncrease(bool pressed) {
+ if (!pressed) return;
+ if (CPU_CycleAutoAdjust) {
+ CPU_CyclePercUsed+=5;
+ if (CPU_CyclePercUsed>105) 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<Section_prop *>(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<Section_prop *>(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;
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 <string.h>
+
+#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.pages) {
+ return memory.phandlers[phys_page];
+ } else if ((phys_page>=memory.lfb.start_page) && (phys_page<memory.lfb.end_page)) {
+ return memory.lfb.handler;
+ } else if ((phys_page>=memory.lfb.start_page+0x01000000/4096) &&
+ (phys_page<memory.lfb.start_page+0x01000000/4096+16)) {
+ return memory.lfb.mmiohandler;
+ }
+ return &illegal_page_handler;
+}
+
+void MEM_SetPageHandler(Bitu phys_page,Bitu pages,PageHandler * handler) {
+ for (;pages>0;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<Bit8u *>(data);
+ while (size--) {
+ *write++=mem_readb_inline(pt++);
+ }
+}
+
+void MEM_BlockWrite(PhysPt pt,void const * const data,Bitu size) {
+ Bit8u const * read = reinterpret_cast<Bit8u const * const>(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 (index<memory.pages) {
+ if (!memory.mhandles[index]) {
+ size++;
+ } else {
+ if (size>largest) largest=size;
+ size=0;
+ }
+ index++;
+ }
+ if (size>largest) largest=size;
+ return largest;
+}
+
+Bitu MEM_FreeTotal(void) {
+ Bitu free=0;
+ Bitu index=XMS_START;
+ while (index<memory.pages) {
+ if (!memory.mhandles[index]) free++;
+ index++;
+ }
+ return free;
+}
+
+Bitu MEM_AllocatedPages(MemHandle handle)
+{
+ Bitu pages = 0;
+ while (handle>0) {
+ 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 (index<memory.pages) {
+ /* Check if we are searching for first free page */
+ if (!first) {
+ /* Check if this is a free page */
+ if (!memory.mhandles[index]) {
+ first=index;
+ }
+ } else {
+ /* Check if this still is used page */
+ if (memory.mhandles[index]) {
+ Bitu pages=index-first;
+ if (pages==size) {
+ return first;
+ } else if (pages>size) {
+ if (pages<best) {
+ best=pages;
+ best_first=first;
+ }
+ }
+ first=0; //Always reset for new search
+ }
+ }
+ index++;
+ }
+ /* Check for the final block if we can */
+ if (first && (index-first>=size) && (index-first<best)) {
+ return first;
+ }
+ return best_first;
+}
+
+MemHandle MEM_AllocatePages(Bitu pages,bool sequence) {
+ MemHandle ret;
+ if (!pages) return 0;
+ if (sequence) {
+ Bitu index=BestMatch(pages);
+ if (!index) return 0;
+ MemHandle * next=&ret;
+ while (pages) {
+ *next=index;
+ next=&memory.mhandles[index];
+ index++;pages--;
+ }
+ *next=-1;
+ } else {
+ if (MEM_FreeTotal()<pages) return 0;
+ MemHandle * next=&ret;
+ while (pages) {
+ Bitu index=BestMatch(1);
+ if (!index) E_Exit("MEM:corruption during allocate");
+ while (pages && (!memory.mhandles[index])) {
+ *next=index;
+ next=&memory.mhandles[index];
+ index++;pages--;
+ }
+ *next=-1; //Invalidate it in case we need another match
+ }
+ }
+ return ret;
+}
+
+MemHandle MEM_GetNextFreePage(void) {
+ return (MemHandle)BestMatch(1);
+}
+
+void MEM_ReleasePages(MemHandle handle) {
+ while (handle>0) {
+ 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<Section_prop *>(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);
+}
--- /dev/null
+#ifndef DOSBOX_H
+#define DOSBOX_H
+
+#ifndef CH_LIST
+#define CH_LIST
+#include <list>
+#endif
+
+#ifndef CH_STRING
+#define CH_STRING
+#include <string>
+#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<std::string>::iterator cmd_it;
+ std::list<std::string> cmds;
+ std::string file_name;
+ bool FindEntry(char const * const name, cmd_it & it, bool neednext = false);
+};
+
+extern int x86_fpu_enabled;
+
+#endif
--- /dev/null
+/*
+ * 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_resb<lf_var1b);
+ case t_ADDw:
+ return (lf_resw<lf_var1w);
+ case t_ADDd:
+ return (lf_resd<lf_var1d);
+ case t_ADCb:
+ return (lf_resb < lf_var1b) || (lflags.oldcf && (lf_resb == lf_var1b));
+ case t_ADCw:
+ return (lf_resw < lf_var1w) || (lflags.oldcf && (lf_resw == lf_var1w));
+ case t_ADCd:
+ return (lf_resd < lf_var1d) || (lflags.oldcf && (lf_resd == lf_var1d));
+ case t_SBBb:
+ return (lf_var1b < lf_resb) || (lflags.oldcf && (lf_var2b==0xff));
+ case t_SBBw:
+ return (lf_var1w < lf_resw) || (lflags.oldcf && (lf_var2w==0xffff));
+ case t_SBBd:
+ return (lf_var1d < lf_resd) || (lflags.oldcf && (lf_var2d==0xffffffff));
+ case t_SUBb:
+ case t_CMPb:
+ return (lf_var1b<lf_var2b);
+ case t_SUBw:
+ case t_CMPw:
+ return (lf_var1w<lf_var2w);
+ case t_SUBd:
+ case t_CMPd:
+ return (lf_var1d<lf_var2d);
+ case t_SHLb:
+ if (lf_var2b>8) 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_resb<lf_var1b));
+ DOFLAG_AF;
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,((lf_var1b ^ lf_var2b ^ 0x80) & (lf_resb ^ lf_var1b)) & 0x80);
+ DOFLAG_PF;
+ break;
+ case t_ADDw:
+ SET_FLAG(CF,(lf_resw<lf_var1w));
+ DOFLAG_AF;
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,((lf_var1w ^ lf_var2w ^ 0x8000) & (lf_resw ^ lf_var1w)) & 0x8000);
+ DOFLAG_PF;
+ break;
+ case t_ADDd:
+ SET_FLAG(CF,(lf_resd<lf_var1d));
+ DOFLAG_AF;
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,((lf_var1d ^ lf_var2d ^ 0x80000000) & (lf_resd ^ lf_var1d)) & 0x80000000);
+ DOFLAG_PF;
+ break;
+ case t_ADCb:
+ SET_FLAG(CF,(lf_resb < lf_var1b) || (lflags.oldcf && (lf_resb == lf_var1b)));
+ DOFLAG_AF;
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,((lf_var1b ^ lf_var2b ^ 0x80) & (lf_resb ^ lf_var1b)) & 0x80);
+ DOFLAG_PF;
+ break;
+ case t_ADCw:
+ SET_FLAG(CF,(lf_resw < lf_var1w) || (lflags.oldcf && (lf_resw == lf_var1w)));
+ DOFLAG_AF;
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,((lf_var1w ^ lf_var2w ^ 0x8000) & (lf_resw ^ lf_var1w)) & 0x8000);
+ DOFLAG_PF;
+ break;
+ case t_ADCd:
+ SET_FLAG(CF,(lf_resd < lf_var1d) || (lflags.oldcf && (lf_resd == lf_var1d)));
+ DOFLAG_AF;
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,((lf_var1d ^ lf_var2d ^ 0x80000000) & (lf_resd ^ lf_var1d)) & 0x80000000);
+ DOFLAG_PF;
+ break;
+
+
+ case t_SBBb:
+ SET_FLAG(CF,(lf_var1b < lf_resb) || (lflags.oldcf && (lf_var2b==0xff)));
+ DOFLAG_AF;
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,(lf_var1b ^ lf_var2b) & (lf_var1b ^ lf_resb) & 0x80);
+ DOFLAG_PF;
+ break;
+ case t_SBBw:
+ SET_FLAG(CF,(lf_var1w < lf_resw) || (lflags.oldcf && (lf_var2w==0xffff)));
+ DOFLAG_AF;
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,(lf_var1w ^ lf_var2w) & (lf_var1w ^ lf_resw) & 0x8000);
+ DOFLAG_PF;
+ break;
+ case t_SBBd:
+ SET_FLAG(CF,(lf_var1d < lf_resd) || (lflags.oldcf && (lf_var2d==0xffffffff)));
+ DOFLAG_AF;
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,(lf_var1d ^ lf_var2d) & (lf_var1d ^ lf_resd) & 0x80000000);
+ DOFLAG_PF;
+ break;
+
+
+ case t_SUBb:
+ case t_CMPb:
+ SET_FLAG(CF,(lf_var1b<lf_var2b));
+ DOFLAG_AF;
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,(lf_var1b ^ lf_var2b) & (lf_var1b ^ lf_resb) & 0x80);
+ DOFLAG_PF;
+ break;
+ case t_SUBw:
+ case t_CMPw:
+ SET_FLAG(CF,(lf_var1w<lf_var2w));
+ DOFLAG_AF;
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,(lf_var1w ^ lf_var2w) & (lf_var1w ^ lf_resw) & 0x8000);
+ DOFLAG_PF;
+ break;
+ case t_SUBd:
+ case t_CMPd:
+ SET_FLAG(CF,(lf_var1d<lf_var2d));
+ DOFLAG_AF;
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,(lf_var1d ^ lf_var2d) & (lf_var1d ^ lf_resd) & 0x80000000);
+ DOFLAG_PF;
+ break;
+
+
+ case t_ORb:
+ SET_FLAG(CF,false);
+ SET_FLAG(AF,false);
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ break;
+ case t_ORw:
+ SET_FLAG(CF,false);
+ SET_FLAG(AF,false);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ break;
+ case t_ORd:
+ SET_FLAG(CF,false);
+ SET_FLAG(AF,false);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ break;
+
+
+ case t_TESTb:
+ case t_ANDb:
+ SET_FLAG(CF,false);
+ SET_FLAG(AF,false);
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ break;
+ case t_TESTw:
+ case t_ANDw:
+ SET_FLAG(CF,false);
+ SET_FLAG(AF,false);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ break;
+ case t_TESTd:
+ case t_ANDd:
+ SET_FLAG(CF,false);
+ SET_FLAG(AF,false);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ break;
+
+
+ case t_XORb:
+ SET_FLAG(CF,false);
+ SET_FLAG(AF,false);
+ DOFLAG_ZFb;
+ DOFLAG_SFb;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ break;
+ case t_XORw:
+ SET_FLAG(CF,false);
+ SET_FLAG(AF,false);
+ DOFLAG_ZFw;
+ DOFLAG_SFw;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ break;
+ case t_XORd:
+ SET_FLAG(CF,false);
+ SET_FLAG(AF,false);
+ DOFLAG_ZFd;
+ DOFLAG_SFd;
+ SET_FLAG(OF,false);
+ DOFLAG_PF;
+ break;
+
+
+ case t_SHLb:
+ if (lf_var2b>8) 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
--- /dev/null
+/*
+ * 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 <math.h>
+#include <float.h>
+#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
--- /dev/null
+/*
+ * 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<FPU_Tag>((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
--- /dev/null
+/*
+ * 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<Bit64s>(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<Bit16s>(sign80)<<15)| static_cast<Bit16s>(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<Real64>(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<Real64>(blah);
+}
+
+static void FPU_FLD_I32(PhysPt addr,Bitu store_to) {
+ Bit32s blah = mem_readd(addr);
+ fpu.regs[store_to].d = static_cast<Real64>(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<Real64>(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<Real64>(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<float>(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<Bit16s>(FROUND(fpu.regs[TOP].d)));
+}
+
+static void FPU_FST_I32(PhysPt addr) {
+ mem_writed(addr,static_cast<Bit32s>(FROUND(fpu.regs[TOP].d)));
+}
+
+static void FPU_FST_I64(PhysPt addr) {
+ FPU_Reg blah;
+ blah.ll = static_cast<Bit64s>(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<Real64>(static_cast<Bit64s>(floor(val.d/10.0)));
+ p = static_cast<Bitu>(val.d - 10.0*temp);
+ val.d=temp;
+ temp = static_cast<Real64>(static_cast<Bit64s>(floor(val.d/10.0)));
+ p |= (static_cast<Bitu>(val.d - 10.0*temp)<<4);
+
+ mem_writeb(addr+i,p);
+ }
+ val.d=temp;
+ temp = static_cast<Real64>(static_cast<Bit64s>(floor(val.d/10.0)));
+ p = static_cast<Bitu>(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<Bit64s>(FROUND(fpu.regs[TOP].d));
+ fpu.regs[TOP].d=static_cast<double>(temp);
+}
+
+static void FPU_FPREM(void){
+ Real64 valtop = fpu.regs[TOP].d;
+ Real64 valdiv = fpu.regs[STV(1)].d;
+ Bit64s ressaved = static_cast<Bit64s>( (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<Bitu>(ressaved&4));
+ FPU_SET_C3(static_cast<Bitu>(ressaved&2));
+ FPU_SET_C1(static_cast<Bitu>(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<Bit64s>(quotf+1);
+ else if (quot-quotf<0.5) ressaved = static_cast<Bit64s>(quotf);
+ else ressaved = static_cast<Bit64s>((((static_cast<Bit64s>(quotf))&1)!=0)?(quotf+1):(quotf));
+ fpu.regs[TOP].d = valtop - ressaved*valdiv;
+ FPU_SET_C0(static_cast<Bitu>(ressaved&4));
+ FPU_SET_C3(static_cast<Bitu>(ressaved&2));
+ FPU_SET_C1(static_cast<Bitu>(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<Real64>(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<Real64>(2.0));
+ FPU_FPOP();
+ return;
+}
+
+static void FPU_FSCALE(void){
+ fpu.regs[TOP].d *= pow(2.0,static_cast<Real64>(static_cast<Bit64s>(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<Bit16u>(fpu.cw));
+ mem_writew(addr+2,static_cast<Bit16u>(fpu.sw));
+ mem_writew(addr+4,static_cast<Bit16u>(FPU_GetTag()));
+ } else {
+ mem_writed(addr+0,static_cast<Bit32u>(fpu.cw));
+ mem_writed(addr+4,static_cast<Bit32u>(fpu.sw));
+ mem_writed(addr+8,static_cast<Bit32u>(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<Bit16u>(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<Real64>(exp80final)));
+ fpu.regs[TOP].d = static_cast<Real64>(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);
+}
+
--- /dev/null
+/*
+ * 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<Bit16u>(fpu.cw));
+ mem_writew(addr+2,static_cast<Bit16u>(fpu.sw));
+ mem_writew(addr+4,static_cast<Bit16u>(FPU_GetTag()));
+ } else {
+ mem_writed(addr+0,static_cast<Bit32u>(fpu.cw));
+ mem_writed(addr+4,static_cast<Bit32u>(fpu.sw));
+ mem_writed(addr+8,static_cast<Bit32u>(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<Bit16u>(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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+#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
--- /dev/null
+/*
+ * 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
+
--- /dev/null
+/*
+ * 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
+};
+
+
--- /dev/null
+/*
+ * 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];
+
+
--- /dev/null
+/*
+ * 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 <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#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<LINK_START) phys_page=paging.firstmb[lin_page];
+ else phys_page=lin_page;
+ PAGING_LinkPage(lin_page,phys_page);
+ }
+ return 0;
+ }
+ bool InitPageCheckOnly(Bitu lin_addr,bool writing) {
+ Bitu lin_page=lin_addr >> 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<LINK_START) phys_page=paging.firstmb[lin_page];
+ else phys_page=lin_page;
+ PAGING_LinkPage(lin_page,phys_page);
+ }
+ return true;
+ }
+ void InitPageForced(Bitu lin_addr) {
+ Bitu lin_page=lin_addr >> 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_page<LINK_START) phys_page=paging.firstmb[lin_page];
+ else phys_page=lin_page;
+ }
+ PAGING_LinkPage(lin_page,phys_page);
+ }
+};
+
+class InitPageUserROHandler : public PageHandler {
+public:
+ InitPageUserROHandler() {
+ flags=PFLAG_INIT|PFLAG_NOCODE;
+ }
+ void writeb(PhysPt addr,Bitu val) {
+ InitPage(addr,(Bit8u)(val&0xff));
+ host_writeb(get_tlb_read(addr)+addr,(Bit8u)(val&0xff));
+ }
+ void writew(PhysPt addr,Bitu val) {
+ InitPage(addr,(Bit16u)(val&0xffff));
+ host_writew(get_tlb_read(addr)+addr,(Bit16u)(val&0xffff));
+ }
+ void writed(PhysPt addr,Bitu val) {
+ InitPage(addr,(Bit32u)val);
+ host_writed(get_tlb_read(addr)+addr,(Bit32u)val);
+ }
+ bool writeb_checked(PhysPt addr,Bitu val) {
+ Bitu writecode=InitPageCheckOnly(addr,(Bit8u)(val&0xff));
+ if (writecode) {
+ HostPt tlb_addr;
+ if (writecode>1) 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<LINK_START) phys_page=paging.firstmb[lin_page];
+ else phys_page=lin_page;
+ PAGING_LinkPage(lin_page,phys_page);
+ }
+ }
+ Bitu InitPageCheckOnly(Bitu lin_addr,Bitu val) {
+ Bitu lin_page=lin_addr >> 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<LINK_START) phys_page=paging.firstmb[lin_page];
+ else phys_page=lin_page;
+ PAGING_LinkPage(lin_page,phys_page);
+ }
+ return 1;
+ }
+ void InitPageForced(Bitu lin_addr) {
+ Bitu lin_page=lin_addr >> 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<LINK_START) phys_page=paging.firstmb[lin_page];
+ else phys_page=lin_page;
+ }
+ PAGING_LinkPage(lin_page,phys_page);
+ }
+};
+
+
+bool PAGING_MakePhysPage(Bitu & page) {
+ if (paging.enabled) {
+ Bitu d_index=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<LINK_START) page=paging.firstmb[page];
+ //Else keep it the same
+ }
+ return true;
+}
+
+static InitPageHandler init_page_handler;
+static InitPageUserROHandler init_page_handler_userro;
+
+
+Bitu PAGING_GetDirBase(void) {
+ return paging.cr3;
+}
+
+bool PAGING_ForcePageInit(Bitu lin_addr) {
+ PageHandler * handler=get_tlb_readhandler(lin_addr);
+ if (handler==&init_page_handler) {
+ init_page_handler.InitPageForced(lin_addr);
+ return true;
+ } else if (handler==&init_page_handler_userro) {
+ PAGING_UnlinkPages(lin_addr>>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;i<TLB_SIZE;i++) {
+ paging.tlb.read[i]=0;
+ paging.tlb.write[i]=0;
+ paging.tlb.readhandler[i]=&init_page_handler;
+ paging.tlb.writehandler[i]=&init_page_handler;
+ }
+ paging.links.used=0;
+}
+
+void PAGING_ClearTLB(void) {
+ Bit32u * entries=&paging.links.entries[0];
+ for (;paging.links.used>0;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<LINK_START) {
+ paging.firstmb[lin_page]=phys_page;
+ 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;
+ } else {
+ PAGING_LinkPage(lin_page,phys_page);
+ }
+}
+
+void PAGING_LinkPage(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;
+ 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;i<TLB_SIZE;i++) {
+ bank[i].read=0;
+ bank[i].write=0;
+ bank[i].readhandler=&init_page_handler;
+ bank[i].writehandler=&init_page_handler;
+ }
+}
+
+void PAGING_InitTLBBank(tlb_entry **bank) {
+ *bank = (tlb_entry *)malloc(sizeof(tlb_entry)*TLB_SIZE);
+ if(!*bank) E_Exit("Out of Memory");
+ InitTLBInt(*bank);
+}
+
+void PAGING_InitTLB(void) {
+ InitTLBInt(paging.tlbh);
+ paging.links.used=0;
+}
+
+void PAGING_ClearTLB(void) {
+ Bit32u * entries=&paging.links.entries[0];
+ for (;paging.links.used>0;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<LINK_START) {
+ paging.firstmb[lin_page]=phys_page;
+ paging.tlbh[lin_page].read=0;
+ paging.tlbh[lin_page].write=0;
+ paging.tlbh[lin_page].readhandler=&init_page_handler;
+ paging.tlbh[lin_page].writehandler=&init_page_handler;
+ } else {
+ PAGING_LinkPage(lin_page,phys_page);
+ }
+}
+
+void PAGING_LinkPage(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;
+ 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<LINK_START;i++) {
+ paging.firstmb[i]=i;
+ }
+ pf_queue.used=0;
+ }
+ ~PAGING(){}
+};
+
+static PAGING* test;
+void PAGING_Init(Section * sec) {
+ test = new PAGING(sec);
+}
--- /dev/null
+/*
+ * 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.h,v 1.33 2009-05-27 09:15:41 qbix79 Exp $ */
+
+#ifndef DOSBOX_PAGING_H
+#define DOSBOX_PAGING_H
+
+#ifndef DOSBOX_DOSBOX_H
+#include "dosbox.h"
+#endif
+#ifndef DOSBOX_MEM_H
+#include "mem.h"
+#endif
+
+// disable this to reduce the size of the TLB
+// NOTE: does not work with the dynamic core (dynrec is fine)
+#define USE_FULL_TLB
+
+class PageDirectory;
+
+#define MEM_PAGE_SIZE (4096)
+#define XMS_START (0x110)
+
+#if defined(USE_FULL_TLB)
+#define TLB_SIZE (1024*1024)
+#else
+#define TLB_SIZE 65536 // This must a power of 2 and greater then LINK_START
+#define BANK_SHIFT 28
+#define BANK_MASK 0xffff // always the same as TLB_SIZE-1?
+#define TLB_BANKS ((1024*1024/TLB_SIZE)-1)
+#endif
+
+#define PFLAG_READABLE 0x1
+#define PFLAG_WRITEABLE 0x2
+#define PFLAG_HASROM 0x4
+#define PFLAG_HASCODE 0x8 //Page contains dynamic code
+#define PFLAG_NOCODE 0x10 //No dynamic code can be generated here
+#define PFLAG_INIT 0x20 //No dynamic code can be generated here
+
+#define LINK_START ((1024+64)/4) //Start right after the HMA
+
+//Allow 128 mb of memory to be linked
+#define PAGING_LINKS (128*1024/4)
+
+class PageHandler {
+public:
+ virtual ~PageHandler(void) { }
+ virtual Bitu readb(PhysPt addr);
+ virtual Bitu readw(PhysPt addr);
+ virtual Bitu readd(PhysPt addr);
+ virtual void writeb(PhysPt addr,Bitu val);
+ virtual void writew(PhysPt addr,Bitu val);
+ virtual void writed(PhysPt addr,Bitu val);
+ virtual HostPt GetHostReadPt(Bitu phys_page);
+ virtual HostPt GetHostWritePt(Bitu phys_page);
+ virtual bool readb_checked(PhysPt addr,Bit8u * val);
+ virtual bool readw_checked(PhysPt addr,Bit16u * val);
+ virtual bool readd_checked(PhysPt addr,Bit32u * val);
+ virtual bool writeb_checked(PhysPt addr,Bitu val);
+ virtual bool writew_checked(PhysPt addr,Bitu val);
+ virtual bool writed_checked(PhysPt addr,Bitu val);
+ Bitu flags;
+};
+
+/* Some other functions */
+void PAGING_Enable(bool enabled);
+bool PAGING_Enabled(void);
+
+Bitu PAGING_GetDirBase(void);
+void PAGING_SetDirBase(Bitu cr3);
+void PAGING_InitTLB(void);
+void PAGING_ClearTLB(void);
+
+void PAGING_LinkPage(Bitu lin_page,Bitu phys_page);
+void PAGING_LinkPage_ReadOnly(Bitu lin_page,Bitu phys_page);
+void PAGING_UnlinkPages(Bitu lin_page,Bitu pages);
+/* This maps the page directly, only use when paging is disabled */
+void PAGING_MapPage(Bitu lin_page,Bitu phys_page);
+bool PAGING_MakePhysPage(Bitu & page);
+bool PAGING_ForcePageInit(Bitu lin_addr);
+
+void MEM_SetLFB(Bitu page, Bitu pages, PageHandler *handler, PageHandler *mmiohandler);
+void MEM_SetPageHandler(Bitu phys_page, Bitu pages, PageHandler * handler);
+void MEM_ResetPageHandler(Bitu phys_page, Bitu pages);
+
+
+#ifdef _MSC_VER
+#pragma pack (1)
+#endif
+struct X86_PageEntryBlock{
+#ifdef WORDS_BIGENDIAN
+ Bit32u base:20;
+ Bit32u avl:3;
+ Bit32u g:1;
+ Bit32u pat:1;
+ Bit32u d:1;
+ Bit32u a:1;
+ Bit32u pcd:1;
+ Bit32u pwt:1;
+ Bit32u us:1;
+ Bit32u wr:1;
+ Bit32u p:1;
+#else
+ Bit32u p:1;
+ Bit32u wr:1;
+ Bit32u us:1;
+ Bit32u pwt:1;
+ Bit32u pcd:1;
+ Bit32u a:1;
+ Bit32u d:1;
+ Bit32u pat:1;
+ Bit32u g:1;
+ Bit32u avl:3;
+ Bit32u base:20;
+#endif
+} GCC_ATTRIBUTE(packed);
+#ifdef _MSC_VER
+#pragma pack ()
+#endif
+
+
+union X86PageEntry {
+ Bit32u load;
+ X86_PageEntryBlock block;
+};
+
+#if !defined(USE_FULL_TLB)
+typedef struct {
+ HostPt read;
+ HostPt write;
+ PageHandler * readhandler;
+ PageHandler * writehandler;
+ Bit32u phys_page;
+} tlb_entry;
+#endif
+
+struct PagingBlock {
+ Bitu cr3;
+ Bitu cr2;
+ struct {
+ Bitu page;
+ PhysPt addr;
+ } base;
+#if defined(USE_FULL_TLB)
+ struct {
+ HostPt read[TLB_SIZE];
+ HostPt write[TLB_SIZE];
+ PageHandler * readhandler[TLB_SIZE];
+ PageHandler * writehandler[TLB_SIZE];
+ Bit32u phys_page[TLB_SIZE];
+ } tlb;
+#else
+ tlb_entry tlbh[TLB_SIZE];
+ tlb_entry *tlbh_banks[TLB_BANKS];
+#endif
+ struct {
+ Bitu used;
+ Bit32u entries[PAGING_LINKS];
+ } links;
+ Bit32u firstmb[LINK_START];
+ bool enabled;
+};
+
+extern PagingBlock paging;
+
+/* Some support functions */
+
+PageHandler * MEM_GetPageHandler(Bitu phys_page);
+
+
+/* Unaligned address handlers */
+Bit16u mem_unalignedreadw(PhysPt address);
+Bit32u mem_unalignedreadd(PhysPt address);
+void mem_unalignedwritew(PhysPt address,Bit16u val);
+void mem_unalignedwrited(PhysPt address,Bit32u val);
+
+bool mem_unalignedreadw_checked(PhysPt address,Bit16u * val);
+bool mem_unalignedreadd_checked(PhysPt address,Bit32u * val);
+bool mem_unalignedwritew_checked(PhysPt address,Bit16u val);
+bool mem_unalignedwrited_checked(PhysPt address,Bit32u val);
+
+#if defined(USE_FULL_TLB)
+
+static INLINE HostPt get_tlb_read(PhysPt address) {
+ return paging.tlb.read[address>>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
--- /dev/null
+/*
+ * 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 <list>
+
+#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<<i))>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<irq_base+8;i++) {
+ if (irqs[i].inservice) ret|=b;
+ b <<= 1;
+ }
+ } else {
+ for (i=irq_base;i<irq_base+8;i++) {
+ if (irqs[i].active) ret|=b;
+ b <<= 1;
+ }
+ if (irq_base==0 && (PIC_IRQCheck&0xff00)) ret |=4;
+ }
+ return ret;
+}
+
+static Bitu read_data(Bitu port,Bitu iolen) {
+ Bitu irq_base=(port==0x21) ? 0 : 8;
+ Bitu i;Bit8u ret=0;Bit8u b=1;
+ for (i=irq_base;i<=irq_base+7;i++) {
+ if (irqs[i].masked) ret|=b;
+ b <<= 1;
+ }
+ return ret;
+}
+
+
+void PIC_ActivateIRQ(Bitu irq) {
+ if( irq < 8 ) {
+ irqs[irq].active = true;
+ if (!irqs[irq].masked) {
+ PIC_IRQCheck|=(1 << irq);
+ }
+ } else if (irq < 16) {
+ irqs[irq].active = true;
+ PIC_IRQOnSecondPicActive|=(1 << irq);
+ if (!irqs[irq].masked && !irqs[2].masked) {
+ PIC_IRQCheck|=(1 << irq);
+ }
+ }
+}
+
+void PIC_DeActivateIRQ(Bitu irq) {
+ if (irq<16) {
+ irqs[irq].active=false;
+ PIC_IRQCheck&=~(1 << irq);
+ PIC_IRQOnSecondPicActive&=~(1 << irq);
+ }
+}
+static inline bool PIC_startIRQ(Bitu i) {
+ /* irqs on second pic only if irq 2 isn't masked */
+ if( 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 (cycles<CPU_Cycles) {
+ CPU_CycleLeft+=CPU_Cycles;
+ CPU_Cycles=0;
+ }
+}
+static bool InEventService = false;
+static float srv_lag = 0;
+
+void PIC_AddEvent(PIC_EventHandler handler,float delay,Bitu val) {
+ if (GCC_UNLIKELY(!pic_queue.free_entry)) {
+ LOG(LOG_PIC,LOG_ERROR)("Event queue full");
+ return;
+ }
+ PICEntry * entry=pic_queue.free_entry;
+ if(InEventService) entry->index = 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 (cycles<CPU_CycleLeft) {
+ CPU_Cycles=cycles;
+ } else {
+ CPU_Cycles=CPU_CycleLeft;
+ }
+ } else CPU_Cycles=CPU_CycleLeft;
+ CPU_CycleLeft-=CPU_Cycles;
+ if (PIC_IRQCheck) PIC_runIRQs();
+ return true;
+}
+
+#if 0
+/* The TIMER Part */
+struct TickerBlock {
+ TIMER_TickHandler handler;
+ TickerBlock * next;
+};
+
+static TickerBlock * firstticker=0;
+
+
+void TIMER_DelTickHandler(TIMER_TickHandler handler) {
+ TickerBlock * ticker=firstticker;
+ TickerBlock * * tick_where=&firstticker;
+ while (ticker) {
+ if (ticker->handler==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;i<PIC_QUEUESIZE-1;i++) {
+ pic_queue.entries[i].next=&pic_queue.entries[i+1];
+ }
+ pic_queue.entries[PIC_QUEUESIZE-1].next=0;
+ pic_queue.free_entry=&pic_queue.entries[0];
+ pic_queue.next_entry=0;
+ }
+ ~PIC(){
+ }
+};
+
+static PIC* test;
+
+void PIC_Destroy(Section* sec){
+ delete test;
+}
+
+void PIC_Init(Section* sec) {
+ test = new PIC(sec);
+ sec->AddDestroyFunction(&PIC_Destroy);
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 <list>
+#endif
+
+#ifndef CH_VECTOR
+#define CH_VECTOR
+#include <vector>
+#endif
+
+#ifndef CH_STRING
+#define CH_STRING
+#include <string>
+#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<Value>& GetValues() const;
+ Value::Etype Get_type(){return default_value.type;}
+
+protected:
+ Value value;
+ std::vector<Value> suggested_values;
+ typedef std::vector<Value>::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<Function_wrapper> initfunctions;
+ std::list<Function_wrapper> 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<Property*> properties;
+ typedef std::list<Property*>::iterator it;
+ typedef std::list<Property*>::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<Value>& 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
--- /dev/null
+/*
+ * 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 <string.h>
+#include <string>
+#include <ctype.h>
+#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 <strings.h>
+#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