typedef enum { ES, CS, SS, DS } SREGS; typedef enum { AW, CW, DW, BW, SP, BP, IX, IY } WREGS; #define NEC_NMI_INT_VECTOR 2 #ifdef LSB_FIRST typedef enum { AL,AH,CL,CH,DL,DH,BL,BH,SPL,SPH,BPL,BPH,IXL,IXH,IYL,IYH } BREGS; #else typedef enum { AH,AL,CH,CL,DH,DL,BH,BL,SPH,SPL,BPH,BPL,IXH,IXL,IYH,IYL } BREGS; #endif /* parameter x = result, y = source 1, z = source 2 */ #define SetTF(x) (cpustate->TF = (x)) #define SetIF(x) (cpustate->IF = (x)) #define SetDF(x) (cpustate->DF = (x)) #define SetMD(x) (cpustate->MF = (x)) /* OB [19.07.99] Mode Flag V30 */ #define SetCFB(x) (cpustate->CarryVal = (x) & 0x100) #define SetCFW(x) (cpustate->CarryVal = (x) & 0x10000) #define SetAF(x,y,z) (cpustate->AuxVal = ((x) ^ ((y) ^ (z))) & 0x10) #define SetSF(x) (cpustate->SignVal = (x)) #define SetZF(x) (cpustate->ZeroVal = (x)) #define SetPF(x) (cpustate->ParityVal = (x)) #define SetSZPF_Byte(x) (cpustate->SignVal=cpustate->ZeroVal=cpustate->ParityVal=(INT8)(x)) #define SetSZPF_Word(x) (cpustate->SignVal=cpustate->ZeroVal=cpustate->ParityVal=(INT16)(x)) #define SetOFW_Add(x,y,z) (cpustate->OverVal = ((x) ^ (y)) & ((x) ^ (z)) & 0x8000) #define SetOFB_Add(x,y,z) (cpustate->OverVal = ((x) ^ (y)) & ((x) ^ (z)) & 0x80) #define SetOFW_Sub(x,y,z) (cpustate->OverVal = ((z) ^ (y)) & ((z) ^ (x)) & 0x8000) #define SetOFB_Sub(x,y,z) (cpustate->OverVal = ((z) ^ (y)) & ((z) ^ (x)) & 0x80) #define ADDB { UINT32 res=dst+src; SetCFB(res); SetOFB_Add(res,src,dst); SetAF(res,src,dst); SetSZPF_Byte(res); dst=(BYTE)res; } #define ADDW { UINT32 res=dst+src; SetCFW(res); SetOFW_Add(res,src,dst); SetAF(res,src,dst); SetSZPF_Word(res); dst=(WORD)res; } #define SUBB { UINT32 res=dst-src; SetCFB(res); SetOFB_Sub(res,src,dst); SetAF(res,src,dst); SetSZPF_Byte(res); dst=(BYTE)res; } #define SUBW { UINT32 res=dst-src; SetCFW(res); SetOFW_Sub(res,src,dst); SetAF(res,src,dst); SetSZPF_Word(res); dst=(WORD)res; } #define ORB dst|=src; cpustate->CarryVal=cpustate->OverVal=cpustate->AuxVal=0; SetSZPF_Byte(dst) #define ORW dst|=src; cpustate->CarryVal=cpustate->OverVal=cpustate->AuxVal=0; SetSZPF_Word(dst) #define ANDB dst&=src; cpustate->CarryVal=cpustate->OverVal=cpustate->AuxVal=0; SetSZPF_Byte(dst) #define ANDW dst&=src; cpustate->CarryVal=cpustate->OverVal=cpustate->AuxVal=0; SetSZPF_Word(dst) #define XORB dst^=src; cpustate->CarryVal=cpustate->OverVal=cpustate->AuxVal=0; SetSZPF_Byte(dst) #define XORW dst^=src; cpustate->CarryVal=cpustate->OverVal=cpustate->AuxVal=0; SetSZPF_Word(dst) #define CF (cpustate->CarryVal!=0) #define SF (cpustate->SignVal<0) #define ZF (cpustate->ZeroVal==0) #define PF parity_table[(BYTE)cpustate->ParityVal] #define AF (cpustate->AuxVal!=0) #define OF (cpustate->OverVal!=0) #define MD (cpustate->MF!=0) /************************************************************************/ #define SegBase(Seg) (cpustate->sregs[Seg] << 4) #define DefaultBase(Seg) ((cpustate->seg_prefix && (Seg==DS || Seg==SS)) ? cpustate->prefix_base : cpustate->sregs[Seg] << 4) #define GetMemB(Seg,Off) ((UINT8)memory_read_byte_8le(cpustate->program, (DefaultBase(Seg)+(Off)))) #define GetMemW(Seg,Off) ((UINT16) memory_read_byte_8le(cpustate->program, (DefaultBase(Seg)+(Off))) + (memory_read_byte_8le(cpustate->program, (DefaultBase(Seg)+((Off)+1)))<<8) ) #define PutMemB(Seg,Off,x) { memory_write_byte_8le(cpustate->program, (DefaultBase(Seg)+(Off)),(x)); } #define PutMemW(Seg,Off,x) { PutMemB(Seg,Off,(x)&0xff); PutMemB(Seg,(Off)+1,(BYTE)((x)>>8)); } /* Todo: Remove these later - plus readword could overflow */ #define ReadByte(ea) ((BYTE)memory_read_byte_8le(cpustate->program, (ea))) #define ReadWord(ea) (memory_read_byte_8le(cpustate->program, (ea))+(memory_read_byte_8le(cpustate->program, ((ea)+1))<<8)) #define WriteByte(ea,val) { memory_write_byte_8le(cpustate->program, (ea),val); } #define WriteWord(ea,val) { memory_write_byte_8le(cpustate->program, (ea),(BYTE)(val)); memory_write_byte_8le(cpustate->program, ((ea)+1),(val)>>8); } #define read_port(port) memory_read_byte_8le(cpustate->io, port) #define write_port(port,val) memory_write_byte_8le(cpustate->io, port,val) #define FETCH (memory_raw_read_byte(cpustate->program, (cpustate->sregs[CS]<<4)+cpustate->ip++)) #define FETCHOP (memory_decrypted_read_byte(cpustate->program, (cpustate->sregs[CS]<<4)+cpustate->ip++)) #define FETCHWORD(var) { var=memory_raw_read_byte(cpustate->program, (((cpustate->sregs[CS]<<4)+cpustate->ip)))+(memory_raw_read_byte(cpustate->program, (((cpustate->sregs[CS]<<4)+cpustate->ip+1)))<<8); cpustate->ip+=2; } #define PUSH(val) { cpustate->regs.w[SP]-=2; WriteWord((((cpustate->sregs[SS]<<4)+cpustate->regs.w[SP])),val); } #define POP(var) { var = ReadWord((((cpustate->sregs[SS]<<4)+cpustate->regs.w[SP]))); cpustate->regs.w[SP]+=2; } #define PEEK(addr) ((BYTE)memory_raw_read_byte(cpustate->program, addr)) #define PEEKOP(addr) ((BYTE)memory_decrypted_read_byte(cpustate->program, addr)) #define GetModRM UINT32 ModRM=memory_raw_read_byte(cpustate->program, (cpustate->sregs[CS]<<4)+cpustate->ip++) /* Cycle count macros: CLK - cycle count is the same on all processors CLKS - cycle count differs between processors, list all counts CLKW - cycle count for word read/write differs for odd/even source/destination address CLKM - cycle count for reg/mem instructions CLKR - cycle count for reg/mem instructions with different counts for odd/even addresses Prefetch & buswait time is not emulated. Extra cycles for PUSH'ing or POP'ing registers to odd addresses is not emulated. */ #define CLK(v30mz) { cpustate->icount-=v30mz; } #define CLKM(v30mz,v30mzm) { cpustate->icount-=( ModRM >=0xc0 )?v30mz:v30mzm; } /************************************************************************/ #define CompressFlags() (WORD)(CF | (PF << 2) | (AF << 4) | (ZF << 6) \ | (SF << 7) | (cpustate->TF << 8) | (cpustate->IF << 9) \ | (cpustate->DF << 10) | (OF << 11)| (MD << 15)) #define ExpandFlags(f) \ { \ cpustate->CarryVal = (f) & 1; \ cpustate->ParityVal = !((f) & 4); \ cpustate->AuxVal = (f) & 16; \ cpustate->ZeroVal = !((f) & 64); \ cpustate->SignVal = (f) & 128 ? -1 : 0; \ cpustate->TF = ((f) & 256) == 256; \ cpustate->IF = ((f) & 512) == 512; \ cpustate->DF = ((f) & 1024) == 1024; \ cpustate->OverVal = (f) & 2048; \ cpustate->MF = ((f) & 0x8000) == 0x8000; \ } #define IncWordReg(Reg) \ unsigned tmp = (unsigned)cpustate->regs.w[Reg]; \ unsigned tmp1 = tmp+1; \ cpustate->OverVal = (tmp == 0x7fff); \ SetAF(tmp1,tmp,1); \ SetSZPF_Word(tmp1); \ cpustate->regs.w[Reg]=tmp1 #define DecWordReg(Reg) \ unsigned tmp = (unsigned)cpustate->regs.w[Reg]; \ unsigned tmp1 = tmp-1; \ cpustate->OverVal = (tmp == 0x8000); \ SetAF(tmp1,tmp,1); \ SetSZPF_Word(tmp1); \ cpustate->regs.w[Reg]=tmp1 #define JMP(flag) \ int tmp = (int)((INT8)FETCH); \ if (flag) \ { \ cpustate->ip = (WORD)(cpustate->ip+tmp); \ cpustate->icount-=10; \ return; \ } #define ADJ4(param1,param2) \ if (AF || ((cpustate->regs.b[AL] & 0xf) > 9)) \ { \ UINT16 tmp; \ tmp = cpustate->regs.b[AL] + param1; \ cpustate->regs.b[AL] = tmp; \ cpustate->AuxVal = 1; \ cpustate->CarryVal |= tmp & 0x100; \ } \ if (CF || (cpustate->regs.b[AL]>0x9f)) \ { \ cpustate->regs.b[AL] += param2; \ cpustate->CarryVal = 1; \ } \ SetSZPF_Byte(cpustate->regs.b[AL]) #define ADJB(param1,param2) \ if (AF || ((cpustate->regs.b[AL] & 0xf) > 9)) \ { \ cpustate->regs.b[AL] += param1; \ cpustate->regs.b[AH] += param2; \ cpustate->AuxVal = 1; \ cpustate->CarryVal = 1; \ } \ else \ { \ cpustate->AuxVal = 0; \ cpustate->CarryVal = 0; \ } \ cpustate->regs.b[AL] &= 0x0F #define BITOP_BYTE \ ModRM = FETCH; \ if (ModRM >= 0xc0) { \ tmp=cpustate->regs.b[Mod_RM.RM.b[ModRM]]; \ } \ else { \ (*GetEA[ModRM])(cpustate); \ tmp=ReadByte(cpustate->ea); \ } #define BITOP_WORD \ ModRM = FETCH; \ if (ModRM >= 0xc0) { \ tmp=cpustate->regs.w[Mod_RM.RM.w[ModRM]]; \ } \ else { \ (*GetEA[ModRM])(cpustate); \ tmp=ReadWord(cpustate->ea); \ } #define BIT_NOT \ if (tmp & (1<regs.w[Reg]; \ cpustate->regs.w[Reg] = cpustate->regs.w[AW]; \ cpustate->regs.w[AW] = tmp #define ROL_BYTE cpustate->CarryVal = dst & 0x80; dst = (dst << 1)+CF #define ROL_WORD cpustate->CarryVal = dst & 0x8000; dst = (dst << 1)+CF #define ROR_BYTE cpustate->CarryVal = dst & 0x1; dst = (dst >> 1)+(CF<<7) #define ROR_WORD cpustate->CarryVal = dst & 0x1; dst = (dst >> 1)+(CF<<15) #define ROLC_BYTE dst = (dst << 1) + CF; SetCFB(dst) #define ROLC_WORD dst = (dst << 1) + CF; SetCFW(dst) #define RORC_BYTE dst = (CF<<8)+dst; cpustate->CarryVal = dst & 0x01; dst >>= 1 #define RORC_WORD dst = (CF<<16)+dst; cpustate->CarryVal = dst & 0x01; dst >>= 1 #define SHL_BYTE(c) cpustate->icount-=c; dst <<= c; SetCFB(dst); SetSZPF_Byte(dst); PutbackRMByte(ModRM,(BYTE)dst) #define SHL_WORD(c) cpustate->icount-=c; dst <<= c; SetCFW(dst); SetSZPF_Word(dst); PutbackRMWord(ModRM,(WORD)dst) #define SHR_BYTE(c) cpustate->icount-=c; dst >>= c-1; cpustate->CarryVal = dst & 0x1; dst >>= 1; SetSZPF_Byte(dst); PutbackRMByte(ModRM,(BYTE)dst) #define SHR_WORD(c) cpustate->icount-=c; dst >>= c-1; cpustate->CarryVal = dst & 0x1; dst >>= 1; SetSZPF_Word(dst); PutbackRMWord(ModRM,(WORD)dst) #define SHRA_BYTE(c) cpustate->icount-=c; dst = ((INT8)dst) >> (c-1); cpustate->CarryVal = dst & 0x1; dst = ((INT8)((BYTE)dst)) >> 1; SetSZPF_Byte(dst); PutbackRMByte(ModRM,(BYTE)dst) #define SHRA_WORD(c) cpustate->icount-=c; dst = ((INT16)dst) >> (c-1); cpustate->CarryVal = dst & 0x1; dst = ((INT16)((WORD)dst)) >> 1; SetSZPF_Word(dst); PutbackRMWord(ModRM,(WORD)dst) #define DIVUB \ uresult = cpustate->regs.w[AW]; \ uresult2 = uresult % tmp; \ if ((uresult /= tmp) > 0xff) { \ nec_interrupt(cpustate,0,0); break; \ } else { \ cpustate->regs.b[AL] = uresult; \ cpustate->regs.b[AH] = uresult2; \ } #define DIVB \ result = (INT16)cpustate->regs.w[AW]; \ result2 = result % (INT16)((INT8)tmp); \ if ((result /= (INT16)((INT8)tmp)) > 0xff) { \ nec_interrupt(cpustate,0,0); break; \ } else { \ cpustate->regs.b[AL] = result; \ cpustate->regs.b[AH] = result2; \ } #define DIVUW \ uresult = (((UINT32)cpustate->regs.w[DW]) << 16) | cpustate->regs.w[AW];\ uresult2 = uresult % tmp; \ if ((uresult /= tmp) > 0xffff) { \ nec_interrupt(cpustate,0,0); break; \ } else { \ cpustate->regs.w[AW]=uresult; \ cpustate->regs.w[DW]=uresult2; \ } #define DIVW \ result = ((UINT32)cpustate->regs.w[DW] << 16) + cpustate->regs.w[AW]; \ result2 = result % (INT32)((INT16)tmp); \ if ((result /= (INT32)((INT16)tmp)) > 0xffff) { \ nec_interrupt(cpustate,0,0); break; \ } else { \ cpustate->regs.w[AW]=result; \ cpustate->regs.w[DW]=result2; \ } #define ADD4S { \ int i,v1,v2,result; \ int count = (cpustate->regs.b[CL]+1)/2; \ unsigned di = cpustate->regs.w[IY]; \ unsigned si = cpustate->regs.w[IX]; \ if (cpustate->seg_prefix) logerror("%06x: Warning: seg_prefix defined for add4s\n",PC(cpustate)); \ cpustate->ZeroVal = cpustate->CarryVal = 0; \ for (i=0;iicount-=19; \ tmp = GetMemB(DS, si); \ tmp2 = GetMemB(ES, di); \ v1 = (tmp>>4)*10 + (tmp&0xf); \ v2 = (tmp2>>4)*10 + (tmp2&0xf); \ result = v1+v2+cpustate->CarryVal; \ cpustate->CarryVal = result > 99 ? 1 : 0; \ result = result % 100; \ v1 = ((result/10)<<4) | (result % 10); \ PutMemB(ES, di,v1); \ if (v1) cpustate->ZeroVal = 1; \ si++; \ di++; \ } \ } #define SUB4S { \ int count = (cpustate->regs.b[CL]+1)/2; \ int i,v1,v2,result; \ unsigned di = cpustate->regs.w[IY]; \ unsigned si = cpustate->regs.w[IX]; \ if (cpustate->seg_prefix) logerror("%06x: Warning: seg_prefix defined for sub4s\n",PC(cpustate)); \ cpustate->ZeroVal = cpustate->CarryVal = 0; \ for (i=0;iicount-=19; \ tmp = GetMemB(ES, di); \ tmp2 = GetMemB(DS, si); \ v1 = (tmp>>4)*10 + (tmp&0xf); \ v2 = (tmp2>>4)*10 + (tmp2&0xf); \ if (v1 < (v2+cpustate->CarryVal)) { \ v1+=100; \ result = v1-(v2+cpustate->CarryVal); \ cpustate->CarryVal = 1; \ } else { \ result = v1-(v2+cpustate->CarryVal); \ cpustate->CarryVal = 0; \ } \ v1 = ((result/10)<<4) | (result % 10); \ PutMemB(ES, di,v1); \ if (v1) cpustate->ZeroVal = 1; \ si++; \ di++; \ } \ } #define CMP4S { \ int count = (cpustate->regs.b[CL]+1)/2; \ int i,v1,v2,result; \ unsigned di = cpustate->regs.w[IY]; \ unsigned si = cpustate->regs.w[IX]; \ if (cpustate->seg_prefix) logerror("%06x: Warning: seg_prefix defined for cmp4s\n",PC(cpustate)); \ cpustate->ZeroVal = cpustate->CarryVal = 0; \ for (i=0;iicount-=19; \ tmp = GetMemB(ES, di); \ tmp2 = GetMemB(DS, si); \ v1 = (tmp>>4)*10 + (tmp&0xf); \ v2 = (tmp2>>4)*10 + (tmp2&0xf); \ if (v1 < (v2+cpustate->CarryVal)) { \ v1+=100; \ result = v1-(v2+cpustate->CarryVal); \ cpustate->CarryVal = 1; \ } else { \ result = v1-(v2+cpustate->CarryVal); \ cpustate->CarryVal = 0; \ } \ v1 = ((result/10)<<4) | (result % 10); \ if (v1) cpustate->ZeroVal = 1; \ si++; \ di++; \ } \ }