diff --git a/src/cpu/core_full.cpp b/src/cpu/core_full.cpp new file mode 100644 index 00000000..b4a0146b --- /dev/null +++ b/src/cpu/core_full.cpp @@ -0,0 +1,75 @@ +#include "dosbox.h" + +#include "pic.h" +#include "regs.h" +#include "cpu.h" +#include "debug.h" +#include "inout.h" +#include "callback.h" + +typedef PhysPt EAPoint; +#define SegBase(c) SegPhys(c) +#define LoadMb(off) mem_readb(off) +#define LoadMw(off) mem_readw(off) +#define LoadMd(off) mem_readd(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(off,val) +#define SaveMw(off,val) mem_writew(off,val) +#define SaveMd(off,val) mem_writed(off,val) + +#define LoadD(reg) reg +#define SaveD(reg,val) reg=val + +static EAPoint IPPoint; + +#include "core_full/loadwrite.h" +#include "core_full/support.h" +#include "core_full/optable.h" +#include "core_full/ea_lookup.h" +#include "instructions.h" + +static bool had_code[16][16]; + +static INLINE void DecodeModRM(void) { + 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) inst.rm_eaa=RMAddress(); +} + + +Bitu Full_DeCode(void) { + LoadIP(); + while (CPU_Cycles>0) { +#if C_DEBUG + cycle_count++; +#endif + CPU_Cycles--; +restartopcode: + inst.entry=(inst.entry & 0xffffff00) | Fetchb(); + if (inst.entry<0x100) { + *(bool *)(&had_code[0][0]+inst.entry)=true; + } + + inst.code=OpCodeTable[inst.entry]; + #include "core_full/load.h" + #include "core_full/op.h" + #include "core_full/save.h" +nextopcode: + inst.prefix=0; + inst.entry=0; + } + SaveIP(); + return 0; +} + + +void CPU_Core_Full_Start(void) { + cpudecoder=&Full_DeCode; +} \ No newline at end of file diff --git a/src/cpu/core_full/ea_lookup.h b/src/cpu/core_full/ea_lookup.h new file mode 100644 index 00000000..c9b8d62c --- /dev/null +++ b/src/cpu/core_full/ea_lookup.h @@ -0,0 +1,115 @@ + + + +static EAPoint RMAddress(void) { + 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) { + return inst.seg.base+off; + }else return seg_base+off; +} + + + + diff --git a/src/cpu/core_full/load.h b/src/cpu/core_full/load.h new file mode 100644 index 00000000..c3c8a23a --- /dev/null +++ b/src/cpu/core_full/load.h @@ -0,0 +1,397 @@ +switch (inst.code.load) { +/* General loading */ + case L_MODRM: + DecodeModRM(); +l_MODRMswitch: + switch (inst.code.extra) { +/* Byte */ + case M_Ib: + inst.op1.d=Fetchb(); + 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: + 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_EwIbx: + inst.op2.ds=Fetchbs(); + goto l_M_Ew; + case M_EwIw: + inst.op2.d=Fetchw(); + goto l_M_Ew; + 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_EdIbx: + inst.op2.ds=Fetchbs(); + goto l_M_Ed; + case M_EdId: + inst.op2.d=Fetchd(); + goto l_M_Ed; + 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) { + LOG(LOG_CPU|LOG_ERROR,"MODRM:Illegal M_Efw "); + goto nextopcode; + } + inst.op1.d=LoadMw(inst.rm_eaa); + inst.op2.d=LoadMw(inst.rm_eaa+2); + break; + case M_Efd: + if (inst.rm>=0xc0) { + LOG(LOG_CPU|LOG_ERROR,"MODRM:Illegal M_Efw "); + goto nextopcode; + } + 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; + + /* Should continue with normal handler afterwards */ + case 0: + LOG(LOG_CPU|LOG_ERROR,"MODRM:Unhandled load %d entry %x",inst.code.extra,inst.entry); + 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; + +/* 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_FLG: + inst.op1.d= (get_CF() << 0) | (get_PF() << 2) | (get_AF() << 4) | + (get_ZF() << 6) | (get_SF() << 7) | (flags.tf << 8) | + (flags.intf << 9) |(flags.df << 10) | (get_OF() << 11) | + (flags.io << 12) | (flags.nt <<14); + 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|=0x200; + 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 L_IRETw: + inst.op1.d=Pop_16(); + inst.op2.d=Pop_16(); + { + Bitu temp=Pop_16(); + Save_Flagsw(temp); + } + break; +/* Direct operations */ + case L_STRING: + #include "string.h" + goto nextopcode; + case D_PUSHAw: + Push_16(reg_ax);Push_16(reg_cx);Push_16(reg_dx);Push_16(reg_bx); + Push_16(reg_sp);Push_16(reg_bp);Push_16(reg_si);Push_16(reg_di); + goto nextopcode; + case D_PUSHAd: + Push_32(reg_eax);Push_32(reg_ecx);Push_32(reg_edx);Push_32(reg_ebx); + Push_32(reg_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_SETALC: + reg_al = get_CF() ? 0xFF : 0; + goto nextopcode; + case D_XLAT: + if (inst.prefix & PREFIX_SEG) reg_al=LoadMb(inst.seg.base+reg_bx+reg_al); + else reg_al=LoadMb(SegBase(ds)+reg_bx+reg_al); + goto nextopcode; + case D_CBW: + reg_ax=(Bit8s)reg_al; + 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: + flags.intf=false; + goto nextopcode; + case D_STI: + flags.intf=true; + if (flags.intf && PIC_IRQCheck) { + SaveIP(); + PIC_runIRQs(); + LoadIP(); + } + goto nextopcode; + case D_STC: + flags.cf=true; + if (flags.type!=t_CF) flags.prev_type=flags.type; + flags.type=t_CF; + goto nextopcode; + case D_CLC: + flags.cf=false; + if (flags.type!=t_CF) flags.prev_type=flags.type; + flags.type=t_CF; + goto nextopcode; + case D_CMC: + flags.cf=!get_CF(); + if (flags.type!=t_CF) flags.prev_type=flags.type; + flags.type=t_CF; + goto nextopcode; + case D_CLD: + flags.df=false; + goto nextopcode; + case D_STD: + flags.df=true; + goto nextopcode; + case D_NOP: + goto nextopcode; + case D_ENTERw: + { + Bit16u bytes=Fetchw();Bit8u level=Fetchb(); + Push_16(reg_bp);reg_bp=reg_sp;reg_sp-=bytes; + EAPoint reader=SegBase(ss)+reg_bp; + for (Bit8u i=1;i0x09) || get_AF()) { + reg_al+=0x06; + flags.af=true; + } else { + flags.af=false; + } + flags.cf=get_CF(); + if ((reg_al > 0x9F) || flags.cf) { + reg_al+=0x60; + flags.cf=true; + } else { + flags.cf=false; + } + flags.sf=(reg_al&0x80)>0; + flags.zf=(reg_al==0); + flags.type=t_UNKNOWN; + goto nextopcode; + case D_DAS: + if (((reg_al & 0x0f) > 9) || get_AF()) { + reg_al-=6; + flags.af=true; + } else { + flags.af=false; + } + if ((reg_al>0x9f) || get_CF()) { + reg_al-=0x60; + flags.cf=true; + } else { + flags.cf=false; + } + flags.type=t_UNKNOWN; + goto nextopcode; + case D_AAA: + if (get_AF() || ((reg_al & 0xf) > 9)) + { + reg_al += 6; + reg_ah += 1; + flags.af=true; + flags.cf=true; + } else { + flags.af=false; + flags.cf=false; + } + reg_al &= 0x0F; + flags.type=t_UNKNOWN; + goto nextopcode; + case D_AAS: + if (((reg_al & 0x0f)>9) || get_AF()) { + reg_ah--; + if (reg_al < 6) reg_ah--; + reg_al=(reg_al-6) & 0xF; + flags.af=flags.cf=true; + } else { + flags.af=flags.cf=false; + } + reg_al&=0xf; + flags.type=t_UNKNOWN; + goto nextopcode; + default: + LOG(LOG_CPU|LOG_ERROR,"LOAD:Unhandled code %d opcode %X",inst.code.load,inst.entry); + break; +} + diff --git a/src/cpu/core_full/loadwrite.h b/src/cpu/core_full/loadwrite.h new file mode 100644 index 00000000..1b165da8 --- /dev/null +++ b/src/cpu/core_full/loadwrite.h @@ -0,0 +1,72 @@ +static INLINE void SaveIP(void) { + Bitu left=IPPoint-SegBase(cs); + reg_eip=left; +} + +static INLINE void LoadIP(void) { + IPPoint=SegBase(cs)+reg_eip; +} + + +static INLINE Bit8u Fetchb() { + Bit8u temp=LoadMb(IPPoint); + IPPoint+=1; + return temp; +} + +static INLINE Bit16u Fetchw() { + Bit16u temp=LoadMw(IPPoint); + IPPoint+=2; + return temp; +} +static INLINE Bit32u Fetchd() { + Bit32u temp=LoadMd(IPPoint); + IPPoint+=4; + return temp; +} + +static INLINE Bit8s Fetchbs() { + return Fetchb(); +} +static INLINE Bit16s Fetchws() { + return Fetchw(); +} + +static INLINE Bit32s Fetchds() { + return Fetchd(); +} + +static INLINE void Push_16(Bit16u blah) { + reg_sp-=2; + SaveMw(SegBase(ss)+reg_sp,blah); +}; + +static INLINE void Push_32(Bit32u blah) { + reg_sp-=4; + SaveMd(SegBase(ss)+reg_sp,blah); +}; + +static INLINE Bit16u Pop_16() { + Bit16u temp=LoadMw(SegBase(ss)+reg_sp); + reg_sp+=2; + return temp; +}; + +static INLINE Bit32u Pop_32() { + Bit32u temp=LoadMd(SegBase(ss)+reg_sp); + reg_sp+=4; + return temp; +}; + + +#define Save_Flagsw(FLAGW) \ +{ \ + flags.type=t_UNKNOWN; \ + flags.cf =(FLAGW & 0x001)>0;flags.pf =(FLAGW & 0x004)>0; \ + flags.af =(FLAGW & 0x010)>0;flags.zf =(FLAGW & 0x040)>0; \ + flags.sf =(FLAGW & 0x080)>0;flags.tf =(FLAGW & 0x100)>0; \ + flags.intf =(FLAGW & 0x200)>0; \ + flags.df =(FLAGW & 0x400)>0;flags.of =(FLAGW & 0x800)>0; \ + \ +} + diff --git a/src/cpu/core_full/main.h b/src/cpu/core_full/main.h new file mode 100644 index 00000000..e69de29b diff --git a/src/cpu/core_full/op.h b/src/cpu/core_full/op.h new file mode 100644 index 00000000..b2800dcf --- /dev/null +++ b/src/cpu/core_full/op.h @@ -0,0 +1,403 @@ +/* Do the actual opcode */ +switch (inst.code.op) { + case t_ADDb: case t_ADDw: case t_ADDd: + flags.var1.d=inst.op1.d; + flags.var2.d=inst.op2.d; + inst.op1.d=flags.result.d=flags.var1.d + flags.var2.d; + flags.type=inst.code.op; + break; + case t_CMPb: case t_CMPw: case t_CMPd: + case t_SUBb: case t_SUBw: case t_SUBd: + flags.var1.d=inst.op1.d; + flags.var2.d=inst.op2.d; + inst.op1.d=flags.result.d=flags.var1.d - flags.var2.d; + flags.type=inst.code.op; + break; + case t_ORb: case t_ORw: case t_ORd: + flags.var1.d=inst.op1.d; + flags.var2.d=inst.op2.d; + inst.op1.d=flags.result.d=flags.var1.d | flags.var2.d; + flags.type=inst.code.op; + break; + case t_XORb: case t_XORw: case t_XORd: + flags.var1.d=inst.op1.d; + flags.var2.d=inst.op2.d; + inst.op1.d=flags.result.d=flags.var1.d ^ flags.var2.d; + flags.type=inst.code.op; + break; + case t_TESTb: case t_TESTw: case t_TESTd: + case t_ANDb: case t_ANDw: case t_ANDd: + flags.var1.d=inst.op1.d; + flags.var2.d=inst.op2.d; + inst.op1.d=flags.result.d=flags.var1.d & flags.var2.d; + flags.type=inst.code.op; + break; + case t_ADCb: case t_ADCw: case t_ADCd: + flags.oldcf=get_CF(); + flags.var1.d=inst.op1.d; + flags.var2.d=inst.op2.d; + inst.op1.d=flags.result.d=flags.var1.d + flags.var2.d + flags.oldcf; + flags.type=inst.code.op; + break; + case t_SBBb: case t_SBBw: case t_SBBd: + flags.oldcf=get_CF(); + flags.var1.d=inst.op1.d; + flags.var2.d=inst.op2.d; + inst.op1.d=flags.result.d=flags.var1.d - flags.var2.d - flags.oldcf; + flags.type=inst.code.op; + break; + case t_INCb: case t_INCw: case t_INCd: + flags.cf=get_CF(); + inst.op1.d=flags.result.d=inst.op1.d+1; + flags.type=inst.code.op; + break; + case t_DECb: case t_DECw: case t_DECd: + flags.cf=get_CF(); + inst.op1.d=flags.result.d=inst.op1.d-1; + flags.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 t_NEGb: + flags.var1.b=inst.op1.b; + inst.op1.b=flags.result.b=0-inst.op1.b; + flags.type=t_NEGb; + break; + case t_NEGw: + flags.var1.w=inst.op1.w; + inst.op1.w=flags.result.w=0-inst.op1.w; + flags.type=t_NEGw; + break; + case t_NEGd: + flags.var1.d=inst.op1.d; + inst.op1.d=flags.result.d=0-inst.op1.d; + flags.type=t_NEGd; + break; + + case O_NOT: + inst.op1.d=~inst.op1.d; + break; + + /* Special instructions */ + case O_IMULRw: + inst.op1.ds=inst.op1.ds*inst.op2.ds; + flags.type=t_MUL; + if ((inst.op1.ds> -32768) && (inst.op1.ds<32767)) { + flags.cf=false;flags.of=false; + } else { + flags.cf=true;flags.of=true; + } + break; + case O_MULb: + flags.type=t_MUL; + reg_ax=reg_al*inst.op1.b; + flags.cf=flags.of=((reg_ax & 0xff00) !=0); + goto nextopcode; + case O_MULw: + { + Bit32u tempu=(Bit32u)reg_ax*(Bit32u)inst.op1.w; + reg_ax=(Bit16u)(tempu); + reg_dx=(Bit16u)(tempu >> 16); + flags.type=t_MUL; + flags.cf=flags.of=(reg_dx !=0); + goto nextopcode; + } + case O_MULd: + { + Bit64u tempu=(Bit64u)reg_eax*(Bit64u)inst.op1.d; + reg_eax=(Bit32u)(tempu); + reg_edx=(Bit32u)(tempu >> 32); + flags.type=t_MUL; + flags.cf=flags.of=(reg_edx !=0); + goto nextopcode; + } + case O_IMULb: + flags.type=t_MUL; + reg_ax=((Bit8s)reg_al)*inst.op1.bs; + flags.cf=flags.of=!((reg_ax & 0xff80)==0xff80 || (reg_ax & 0xff80)==0x0000); + goto nextopcode; + case O_IMULw: + { + Bit32s temps=(Bit16s)reg_ax*inst.op1.ws; + reg_ax=(Bit16s)(temps); + reg_dx=(Bit16s)(temps >> 16); + flags.type=t_MUL; + flags.cf=flags.of=!((temps & 0xffffff80)==0xffffff80 || (temps & 0xffffff80)==0x0000); + goto nextopcode; + } + case O_IMULd: + { + Bit64s temps=(Bit64s)reg_eax*(Bit64s)inst.op1.ds; + reg_eax=(Bit32s)(temps); + reg_edx=(Bit32s)(temps >> 32); + flags.type=t_MUL; + if ( (reg_edx==0xffffffff) && (reg_eax & 0x80000000) ) { + flags.cf=flags.of=false; + } else if ( (reg_edx==0x00000000) && (reg_eax<0x80000000) ) { + flags.cf=flags.of=false; + } else { + flags.cf=flags.of=true; + } + goto nextopcode; + } + case O_DIVb: + { + if (!inst.op1.b) goto doint; + Bitu val=reg_ax;Bitu quo=val/inst.op1.b; + reg_ah=(Bit8u)(val % inst.op1.b); + reg_al=(Bit8u)quo; + if (quo!=reg_al) { inst.op1.b=0;goto doint;} + goto nextopcode; + } + case O_DIVw: + { + if (!inst.op1.w) goto doint; + Bitu val=(reg_dx<<16)|reg_ax;Bitu quo=val/inst.op1.w; + reg_dx=(Bit16u)(val % inst.op1.w); + reg_ax=(Bit16u)quo; + if (quo!=reg_ax) { inst.op1.b=0;goto doint;} + goto nextopcode; + } + case O_IDIVb: + { + if (!inst.op1.b) goto doint; + Bits val=(Bit16s)reg_ax;Bits quo=val/inst.op1.bs; + reg_ah=(Bit8s)(val % inst.op1.bs); + reg_al=(Bit8s)quo; + if (quo!=(Bit8s)reg_al) { inst.op1.b=0;goto doint;} + goto nextopcode; + } + case O_IDIVw: + { + if (!inst.op1.w) goto doint; + Bits val=(Bit32s)((reg_dx<<16)|reg_ax);Bits quo=val/inst.op1.ws; + reg_dx=(Bit16u)(val % inst.op1.ws); + reg_ax=(Bit16s)quo; + if (quo!=(Bit16s)reg_ax) { inst.op1.b=0;goto doint;} + goto nextopcode; + } + case O_AAM: + reg_ah=reg_al / inst.op1.b; + reg_al=reg_al % inst.op1.b; + flags.type=t_UNKNOWN; + flags.sf=(reg_ah & 0x80) > 0; + flags.zf=(reg_ax == 0); + //TODO PF + flags.pf=0; + goto nextopcode; + case O_AAD: + reg_al=reg_ah*inst.op1.b+reg_al; + reg_ah=0; + flags.cf=(reg_al>=0x80); + flags.zf=(reg_al==0); + //TODO PF + flags.type=t_UNKNOWN; + goto nextopcode; + + case O_C_O: inst.cond=get_OF(); break; + case O_C_NO: inst.cond=!get_OF(); break; + case O_C_B: inst.cond=get_CF(); break; + case O_C_NB: inst.cond=!get_CF(); break; + case O_C_Z: inst.cond=get_ZF(); break; + case O_C_NZ: inst.cond=!get_ZF(); break; + case O_C_BE: inst.cond=get_CF() || get_ZF(); break; + case O_C_NBE: inst.cond=!get_CF() && !get_ZF(); break; + case O_C_S: inst.cond=get_SF(); break; + case O_C_NS: inst.cond=!get_SF(); break; + case O_C_P: inst.cond=get_PF(); break; + case O_C_NP: inst.cond=!get_PF(); break; + case O_C_L: inst.cond=get_SF() != get_OF(); break; + case O_C_NL: inst.cond=get_SF() == get_OF(); break; + case O_C_LE: inst.cond=get_ZF() || (get_SF() != get_OF()); break; + case O_C_NLE: inst.cond=(get_SF() == get_OF()) && !get_ZF(); 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_LOOP: + if (--reg_cx) break; + goto nextopcode; + case O_LOOPZ: + if (--reg_cx && !get_ZF()) break; + goto nextopcode; + case O_LOOPNZ: + if (--reg_cx && get_ZF()) break; + goto nextopcode; + case O_JCXZ: + 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_CALL_N: + SaveIP(); + Push_16(reg_ip); + break; + case O_CALL_F: + Push_16(SegValue(cs)); + SaveIP(); + Push_16(reg_ip); + break; +doint: + case O_INT: + SaveIP(); +#if C_DEBUG + if (inst.entry==0xcc) if (DEBUG_Breakpoint()) return 1; + else if (DEBUG_IntBreakpoint(inst.op1.b)) return 1; +#endif + Interrupt(inst.op1.b); + LoadIP(); + break; + case O_INb: + reg_al=IO_Read(inst.op1.d); + goto nextopcode; + case O_INw: + reg_ax=IO_Read(inst.op1.d) | (IO_Read(inst.op1.d+1) << 8); + goto nextopcode; + case O_INd: + reg_eax=IO_Read(inst.op1.d) | (IO_Read(inst.op1.d+1) << 8) | (IO_Read(inst.op1.d+2) << 16) | (IO_Read(inst.op1.d+3) << 24); + goto nextopcode; + case O_OUTb: + IO_Write(inst.op1.d,reg_al); + goto nextopcode; + case O_OUTw: + IO_Write(inst.op1.d+0,(Bit8u)reg_ax); + IO_Write(inst.op1.d+1,(Bit8u)(reg_ax >> 8)); + goto nextopcode; + case O_OUTd: + IO_Write(inst.op1.d+0,(Bit8u)reg_eax); + IO_Write(inst.op1.d+1,(Bit8u)(reg_eax >> 8)); + IO_Write(inst.op1.d+2,(Bit8u)(reg_eax >> 16)); + IO_Write(inst.op1.d+3,(Bit8u)(reg_eax >> 24)); + goto nextopcode; + case O_CBACK: + if (inst.op1.d0;flags.pf =(inst.op1.d & 0x004)>0; \ + flags.af =(inst.op1.d & 0x010)>0;flags.zf =(inst.op1.d & 0x040)>0; \ + flags.sf =(inst.op1.d & 0x080)>0; + break; + case S_FLGw: + Save_Flagsw(inst.op1.w); + break; + case 0: + break; + default: + LOG(LOG_ERROR|LOG_CPU,"SAVE:Unhandled code %d entry %X",inst.code.save,inst.entry); +} diff --git a/src/cpu/core_full/string.h b/src/cpu/core_full/string.h new file mode 100644 index 00000000..8c42542e --- /dev/null +++ b/src/cpu/core_full/string.h @@ -0,0 +1,169 @@ +{ + EAPoint si_base,di_base; + Bitu si_index,di_index; + Bitu add_mask; + Bitu count,count_max; + Bits add_index; + bool restart=false; + + 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=0; + 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; + } + + add_index=flags.df ? -1 : 1; + if (count) switch (inst.code.op) { + case R_OUTSB: + for (;count>0;count--) { + IO_Write(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_Write(reg_dx,LoadMb(si_base+si_index)); + IO_Write(reg_dx+1,LoadMb(si_base+si_index+1)); + si_index=(si_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--; + 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--; + 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_CMPSB: + { + Bit8u val1,val2; + for (;count>0;) { + count--; + 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--; + 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; + 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) { + reg_ecx&=(~add_mask); + reg_ecx|=(count & add_mask); + } +} diff --git a/src/cpu/core_full/support.h b/src/cpu/core_full/support.h new file mode 100644 index 00000000..7dcee792 --- /dev/null +++ b/src/cpu/core_full/support.h @@ -0,0 +1,159 @@ +enum { + L_N=0, + L_SKIP, + /* Grouped ones using MOD/RM */ + L_MODRM, + + 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_FLG,L_INTO, + + L_VAL, + L_PRESEG, + L_DOUBLE, + L_PREOP,L_PREADD,L_PREREP,L_PREREPNE, + L_STRING, + + L_IRETw,L_IRETd, +/* Direct ones */ + D_PUSHAw,D_PUSHAd, + D_POPAw,D_POPAd, + D_DAA,D_DAS, + D_AAA,D_AAS, + D_CBW,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_ENTERw,D_ENTERd, + D_LEAVEw,D_LEAVEd, + L_ERROR, +}; + + +enum { + O_N=t_LASTFLAG, + O_COND, + O_XCHG_AX,O_XCHG_EAX, + O_IMULRw,O_IMULRd, + O_BOUNDw,O_BOUNDd, + O_CALL_N,O_CALL_F, + O_OPAL,O_ALOP, + O_OPAX,O_AXOP, + O_OPEAX,O_EAXOP, + O_INT, + O_SEGDS,O_SEGES,O_SEGFS,O_SEGGS, + 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_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, +}; + +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_REGb,S_REGw,S_REGd, + S_PUSHw,S_PUSHd, + S_SEGI, + S_SEGm, + S_SEGGw,S_SEGGd, + + + S_ADDIP,S_C_ADDIP, + + S_FLGb,S_FLGw,S_FLGd, + S_IP,S_IPIw, + S_CSIP,S_CSIPIw, + +}; + +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_Eb,M_Gb,M_EbGb,M_GbEb, + M_Ew,M_Gw,M_EwGw,M_GwEw,M_EwxGwx, + M_Ed,M_Gd,M_EdGd,M_GdEd, + M_EbIb, + M_EwIw,M_EwIbx,M_EwxIbx,M_EwxIwx, + M_EdId,M_EdIbx, + + 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; +}; + +static struct { + Bitu entry; + Bitu entry_default; + Bit8u rm; + EAPoint rm_eaa; + Bitu rm_off; + Bitu rm_eai; + Bitu rm_index; + Bitu rm_mod; + OpCode code; + union { + Bit8u b;Bit8s bs; + Bit16u w;Bit16s ws; + Bit32u d;Bit32s ds; + } op1,op2; + Bitu new_flags; + struct { + EAPoint base; + } seg; + bool cond; + bool repz; + Bitu prefix; +} inst; + + +#define PREFIX_NONE 0x0 +#define PREFIX_SEG 0x1 +#define PREFIX_ADDR 0x2 +#define PREFIX_REP 0x4 + diff --git a/src/cpu/cpu.cpp b/src/cpu/cpu.cpp index 854d3834..2a44b651 100644 --- a/src/cpu/cpu.cpp +++ b/src/cpu/cpu.cpp @@ -23,7 +23,34 @@ #include "keyboard.h" #include "setup.h" -//Regs regs; +#pragma pack(1) +struct Descriptor { + 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 d :1; + Bit32u g :1; + Bit32u base_24_31 :8; +}; +#pragma pack() + +struct CPUBlock { + + + struct { + PhysPt phys_base; + Bit32u base; + Bit16u limit; + } gdt,idt; +}; + + Flag_Info flags; @@ -136,9 +163,13 @@ void Interrupt(Bit8u num) { void CPU_Real_16_Slow_Start(void); +void CPU_Core_Full_Start(void); + + void SetCPU16bit() { CPU_Real_16_Slow_Start(); +// CPU_Core_Full_Start(); }