diff options
author | 2011-06-16 05:38:49 +0000 | |
---|---|---|
committer | 2011-06-16 05:38:49 +0000 | |
commit | 2d60c3dba0f21894ab5f36d28d2a4ed9773ce546 (patch) | |
tree | 4363c2a85848689a22c00ff0523e48adf7ea0bfe /src/emu/cpu/i86 | |
parent | b6012aaa603334edc988f23ab0c87f3c09a47d75 (diff) |
i286 - Fix bunch of fault restarts [Carl]
Diffstat (limited to 'src/emu/cpu/i86')
-rw-r--r-- | src/emu/cpu/i86/i86priv.h | 14 | ||||
-rw-r--r-- | src/emu/cpu/i86/instr186.c | 34 | ||||
-rw-r--r-- | src/emu/cpu/i86/instr286.c | 31 | ||||
-rw-r--r-- | src/emu/cpu/i86/instr286.h | 8 | ||||
-rw-r--r-- | src/emu/cpu/i86/instr86.c | 138 |
5 files changed, 153 insertions, 72 deletions
diff --git a/src/emu/cpu/i86/i86priv.h b/src/emu/cpu/i86/i86priv.h index d62fe70d86d..a2c2f3ae42c 100644 --- a/src/emu/cpu/i86/i86priv.h +++ b/src/emu/cpu/i86/i86priv.h @@ -65,6 +65,13 @@ typedef enum { #define SUBB(dst,src) { unsigned res=dst-src; SetCFB(res); SetOFB_Sub(res,src,dst); SetAF(res,src,dst); SetSZPF_Byte(res); dst=(BYTE)res; } #define SUBW(dst,src) { unsigned res=dst-src; SetCFW(res); SetOFW_Sub(res,src,dst); SetAF(res,src,dst); SetSZPF_Word(res); dst=(WORD)res; } +// don't modify CF in case fault occurs +#define ADCB(dst,src,tmpcf) { unsigned res=dst+src; tmpcf = res & 0x100; SetOFB_Add(res,src,dst); SetAF(res,src,dst); SetSZPF_Byte(res); dst=(BYTE)res; } +#define ADCW(dst,src,tmpcf) { unsigned res=dst+src; tmpcf = res & 0x10000; SetOFW_Add(res,src,dst); SetAF(res,src,dst); SetSZPF_Word(res); dst=(WORD)res; } + +#define SBBB(dst,src,tmpcf) { unsigned res=dst-src; tmpcf = res & 0x100; SetOFB_Sub(res,src,dst); SetAF(res,src,dst); SetSZPF_Byte(res); dst=(BYTE)res; } +#define SBBW(dst,src,tmpcf) { unsigned res=dst-src; tmpcf = res & 0x10000; SetOFW_Sub(res,src,dst); SetAF(res,src,dst); SetSZPF_Word(res); dst=(WORD)res; } + #define ORB(dst,src) dst |= src; cpustate->CarryVal = cpustate->OverVal = cpustate->AuxVal = 0; SetSZPF_Byte(dst) #define ORW(dst,src) dst |= src; cpustate->CarryVal = cpustate->OverVal = cpustate->AuxVal = 0; SetSZPF_Word(dst) @@ -101,10 +108,17 @@ typedef enum { #define DefaultSeg(Seg) ((cpustate->seg_prefix && (Seg == DS || Seg == SS)) ? cpustate->prefix_seg : Seg) #define DefaultBase(Seg) ((cpustate->seg_prefix && (Seg == DS || Seg == SS)) ? cpustate->base[cpustate->prefix_seg] : cpustate->base[Seg]) +#ifdef I80286 +#define GetMemB(Seg,Off) (read_mem_byte(GetMemAddr(cpustate,Seg,Off,1,I80286_READ))) +#define GetMemW(Seg,Off) (read_mem_word(GetMemAddr(cpustate,Seg,Off,2,I80286_READ))) +#define PutMemB(Seg,Off,x) write_mem_byte(GetMemAddr(cpustate,Seg,Off,1,I80286_WRITE), (x)) +#define PutMemW(Seg,Off,x) write_mem_word(GetMemAddr(cpustate,Seg,Off,2,I80286_WRITE), (x)) +#else #define GetMemB(Seg,Off) (read_mem_byte((DefaultBase(Seg) + (Off)) & AMASK)) #define GetMemW(Seg,Off) (read_mem_word((DefaultBase(Seg) + (Off)) & AMASK)) #define PutMemB(Seg,Off,x) write_mem_byte((DefaultBase(Seg) + (Off)) & AMASK, (x)) #define PutMemW(Seg,Off,x) write_mem_word((DefaultBase(Seg) + (Off)) & AMASK, (x)) +#endif #define PEEKBYTE(ea) (read_mem_byte((ea) & AMASK)) #define ReadByte(ea) (read_mem_byte((ea) & AMASK)) diff --git a/src/emu/cpu/i86/instr186.c b/src/emu/cpu/i86/instr186.c index cc0fea3d299..8cc7e213834 100644 --- a/src/emu/cpu/i86/instr186.c +++ b/src/emu/cpu/i86/instr186.c @@ -16,6 +16,9 @@ static void PREFIX186(_pusha)(i8086_state *cpustate) /* Opcode 0x60 */ { unsigned tmp=cpustate->regs.w[SP]; +#ifdef I80286 + if(PM) i80286_check_permission(cpustate, SS, cpustate->regs.w[SP]-16, 16, I80286_WRITE); +#endif ICOUNT -= timing.pusha; PUSH(cpustate->regs.w[AX]); PUSH(cpustate->regs.w[CX]); @@ -31,6 +34,9 @@ static unsigned i186_popa_tmp; // hack around GCC 4.6 error because we need the static void PREFIX186(_popa)(i8086_state *cpustate) /* Opcode 0x61 */ { +#ifdef I80286 + if(PM) i80286_check_permission(cpustate, SS, cpustate->regs.w[SP], 16, I80286_READ); +#endif ICOUNT -= timing.popa; POP(cpustate->regs.w[DI]); POP(cpustate->regs.w[SI]); @@ -100,6 +106,9 @@ static void PREFIX186(_imul_d8)(i8086_state *cpustate) /* Opcode 0x6b */ static void PREFIX186(_insb)(i8086_state *cpustate) /* Opcode 0x6c */ { +#ifdef I80286 + if (PM && (CPL>IOPL)) throw TRAP(GENERAL_PROTECTION_FAULT, 0); +#endif ICOUNT -= timing.ins8; PutMemB(ES,cpustate->regs.w[DI],read_port_byte(cpustate->regs.w[DX])); cpustate->regs.w[DI] += cpustate->DirVal; @@ -107,6 +116,9 @@ static void PREFIX186(_insb)(i8086_state *cpustate) /* Opcode 0x6c */ static void PREFIX186(_insw)(i8086_state *cpustate) /* Opcode 0x6d */ { +#ifdef I80286 + if (PM && (CPL>IOPL)) throw TRAP(GENERAL_PROTECTION_FAULT, 0); +#endif ICOUNT -= timing.ins16; PutMemW(ES,cpustate->regs.w[DI],read_port_word(cpustate->regs.w[DX])); cpustate->regs.w[DI] += 2 * cpustate->DirVal; @@ -114,6 +126,9 @@ static void PREFIX186(_insw)(i8086_state *cpustate) /* Opcode 0x6d */ static void PREFIX186(_outsb)(i8086_state *cpustate) /* Opcode 0x6e */ { +#ifdef I80286 + if (PM && (CPL>IOPL)) throw TRAP(GENERAL_PROTECTION_FAULT, 0); +#endif ICOUNT -= timing.outs8; write_port_byte(cpustate->regs.w[DX],GetMemB(DS,cpustate->regs.w[SI])); cpustate->regs.w[SI] += cpustate->DirVal; /* GOL 11/27/01 */ @@ -121,6 +136,9 @@ static void PREFIX186(_outsb)(i8086_state *cpustate) /* Opcode 0x6e */ static void PREFIX186(_outsw)(i8086_state *cpustate) /* Opcode 0x6f */ { +#ifdef I80286 + if (PM && (CPL>IOPL)) throw TRAP(GENERAL_PROTECTION_FAULT, 0); +#endif ICOUNT -= timing.outs16; write_port_word(cpustate->regs.w[DX],GetMemW(DS,cpustate->regs.w[SI])); cpustate->regs.w[SI] += 2 * cpustate->DirVal; /* GOL 11/27/01 */ @@ -146,17 +164,25 @@ static void PREFIX186(_rotshft_wd8)(i8086_state *cpustate) /* Opcode 0xc1 */ static void PREFIX186(_enter)(i8086_state *cpustate) /* Opcode 0xc8 */ { - unsigned nb = FETCH; unsigned i,level; + unsigned nb = FETCH; + unsigned i,level; + UINT16 fp; nb += FETCH << 8; +#ifdef I80286 + level = FETCH & 0x1f; + if(PM) i80286_check_permission(cpustate, SS, cpustate->regs.w[SP]-2-(level*2), 2+(level*2), I80286_WRITE); +#else level = FETCH; +#endif ICOUNT -= (level == 0) ? timing.enter0 : (level == 1) ? timing.enter1 : timing.enter_base + level * timing.enter_count; PUSH(cpustate->regs.w[BP]); - cpustate->regs.w[BP]=cpustate->regs.w[SP]; - cpustate->regs.w[SP] -= nb; + fp = cpustate->regs.w[SP]; for (i=1;i<level;i++) PUSH(GetMemW(SS,cpustate->regs.w[BP]-i*2)); - if (level) PUSH(cpustate->regs.w[BP]); + if (level) PUSH(fp); + cpustate->regs.w[BP] = fp; + cpustate->regs.w[SP] -= nb; } static void PREFIX186(_leave)(i8086_state *cpustate) /* Opcode 0xc9 */ diff --git a/src/emu/cpu/i86/instr286.c b/src/emu/cpu/i86/instr286.c index e09396eaf47..6f6a9f1ffcc 100644 --- a/src/emu/cpu/i86/instr286.c +++ b/src/emu/cpu/i86/instr286.c @@ -152,7 +152,7 @@ static void i80286_pop_seg(i80286_state *cpustate, int reg) cpustate->regs.w[SP] += 2; } -static void i80286_data_descriptor_full(i80286_state *cpustate,int reg, UINT16 selector, int cpl, UINT32 trap) +static void i80286_data_descriptor_full(i80286_state *cpustate, int reg, UINT16 selector, int cpl, UINT32 trap, UINT16 offset, int size) { if (PM) { UINT16 desc[3]; @@ -189,6 +189,10 @@ static void i80286_data_descriptor_full(i80286_state *cpustate,int reg, UINT16 s if (CODE(r) && !READ(r)) throw trap; if (!PRES(r)) throw TRAP(SEG_NOT_PRESENT,(IDXTBL(selector)+(trap&1))); } + if (offset+size) { + if ((CODE(r) || !EXPDOWN(r)) && ((offset+size-1) > LIMIT(desc))) throw (reg==SS)?TRAP(STACK_FAULT,(trap&1)):trap; + if (!CODE(r) && EXPDOWN(r) && ((offset <= LIMIT(desc)) || ((offset+size) > 0xffff))) throw (reg==SS)?TRAP(STACK_FAULT,(trap&1)):trap; + } SET_ACC(desc); WriteWord(addr+4, desc[2]); @@ -204,7 +208,7 @@ static void i80286_data_descriptor_full(i80286_state *cpustate,int reg, UINT16 s static void i80286_data_descriptor(i80286_state *cpustate, int reg, UINT16 selector) { - i80286_data_descriptor_full(cpustate, reg, selector, CPL, TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector))); + i80286_data_descriptor_full(cpustate, reg, selector, CPL, TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(selector)), 0, 0); } static void i80286_switch_task(i80286_state *cpustate, UINT16 ntask, int type) @@ -296,7 +300,7 @@ static void i80286_switch_task(i80286_state *cpustate, UINT16 ntask, int type) if (type == CALL) cpustate->flags |= 0x4000; cpustate->msw |= 8; - i80286_data_descriptor_full(cpustate, SS, ntss[TSS_SS], RPL(ntss[TSS_CS]), TRAP(INVALID_TSS,IDXTBL(ntss[TSS_SS]))); + i80286_data_descriptor_full(cpustate, SS, ntss[TSS_SS], RPL(ntss[TSS_CS]), TRAP(INVALID_TSS,IDXTBL(ntss[TSS_SS])), 0, 0); cpustate->sregs[CS] = IDXTBL(cpustate->sregs[CS]) | RPL(ntss[TSS_CS]); // fixme try { @@ -307,8 +311,8 @@ static void i80286_switch_task(i80286_state *cpustate, UINT16 ntask, int type) throw e; } - i80286_data_descriptor_full(cpustate, ES, ntss[TSS_ES], RPL(ntss[TSS_CS]), TRAP(INVALID_TSS,IDXTBL(ntss[TSS_ES]))); - i80286_data_descriptor_full(cpustate, DS, ntss[TSS_DS], RPL(ntss[TSS_CS]), TRAP(INVALID_TSS,IDXTBL(ntss[TSS_DS]))); + i80286_data_descriptor_full(cpustate, ES, ntss[TSS_ES], RPL(ntss[TSS_CS]), TRAP(INVALID_TSS,IDXTBL(ntss[TSS_ES])), 0, 0); + i80286_data_descriptor_full(cpustate, DS, ntss[TSS_DS], RPL(ntss[TSS_CS]), TRAP(INVALID_TSS,IDXTBL(ntss[TSS_DS])), 0, 0); } static void i80286_code_descriptor(i80286_state *cpustate, UINT16 selector, UINT16 offset, int gate) @@ -360,7 +364,7 @@ static void i80286_code_descriptor(i80286_state *cpustate, UINT16 selector, UINT if (!CODE(r) || !SEGDESC(r)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(gatesel)); if (DPL(r)>CPL) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(gatesel)); if (!PRES(r)) throw TRAP(SEG_NOT_PRESENT,IDXTBL(gatesel)); - if (GATEOFF(desc) > LIMIT(gatedesc)) throw TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(gatesel)); + if (GATEOFF(desc) > LIMIT(gatedesc)) throw TRAP(GENERAL_PROTECTION_FAULT,0); if (!CONF(r)&&(DPL(r)<CPL)) { // inner call UINT16 tss_ss, tss_sp, oldss, oldsp; @@ -373,13 +377,13 @@ static void i80286_code_descriptor(i80286_state *cpustate, UINT16 selector, UINT oldss = cpustate->sregs[SS]; oldsp = cpustate->regs.w[SP]; oldstk = cpustate->base[SS] + oldsp; - i80286_data_descriptor_full(cpustate, SS, tss_ss, DPL(r), TRAP(INVALID_TSS,IDXTBL(tss_ss))); + i80286_data_descriptor_full(cpustate, SS, tss_ss, DPL(r), TRAP(INVALID_TSS,IDXTBL(tss_ss)), tss_sp-8-(GATECNT(desc)*2), 8+(GATECNT(desc)*2)); cpustate->regs.w[SP] = tss_sp; PUSH(oldss); PUSH(oldsp); for (i = GATECNT(desc)-1; i >= 0; i--) PUSH(ReadWord(oldstk+(i*2))); - } + } else i80286_check_permission(cpustate, SS, cpustate->regs.w[SP]-4, 4, I80286_READ); SET_ACC(gatedesc); WriteWord(addr+4, gatedesc[2]); cpustate->sregs[CS]=IDXTBL(gatesel) | DPL(r); @@ -448,7 +452,7 @@ static void i80286_interrupt_descriptor(i80286_state *cpustate,UINT16 number, in if (!CODE(r) || !SEGDESC(r)) throw TRAP(GENERAL_PROTECTION_FAULT,(IDXTBL(gatesel)+(hwint&&1))); if (DPL(r)>CPL) throw TRAP(GENERAL_PROTECTION_FAULT,(IDXTBL(gatesel)+(hwint&&1))); if (!PRES(r)) throw TRAP(SEG_NOT_PRESENT,(IDXTBL(gatesel)+(hwint&&1))); - if (GATEOFF(desc) > LIMIT(gatedesc)) throw TRAP(GENERAL_PROTECTION_FAULT,(IDXTBL(gatesel)+(hwint&&1))); + if (GATEOFF(desc) > LIMIT(gatedesc)) throw TRAP(GENERAL_PROTECTION_FAULT,(hwint&&1)); if (!CONF(r)&&(DPL(r)<CPL)) { // inner call UINT16 tss_ss, tss_sp, oldss, oldsp; @@ -457,11 +461,11 @@ static void i80286_interrupt_descriptor(i80286_state *cpustate,UINT16 number, in oldss = cpustate->sregs[SS]; oldsp = cpustate->regs.w[SP]; - i80286_data_descriptor_full(cpustate, SS, tss_ss, DPL(r), TRAP(INVALID_TSS,(IDXTBL(tss_ss)+(hwint&&1)))); + i80286_data_descriptor_full(cpustate, SS, tss_ss, DPL(r), TRAP(INVALID_TSS,(IDXTBL(tss_ss)+(hwint&&1))), tss_sp-((error != -1)?12:10), (error != -1)?12:10); cpustate->regs.w[SP] = tss_sp; PUSH(oldss); PUSH(oldsp); - } + } else i80286_check_permission(cpustate, SS, cpustate->regs.w[SP]-((error != -1)?8:6), (error != -1)?8:6, I80286_READ); SET_ACC(gatedesc); WriteWord(addr+4, gatedesc[2]); PREFIX(_pushf(cpustate)); @@ -776,9 +780,10 @@ static UINT16 i80286_far_return(i8086_state *cpustate, int iret, int bytes) if (!PRES(r)) throw TRAP(SEG_NOT_PRESENT,IDXTBL(sel)); if (off > LIMIT(desc)) throw TRAP(GENERAL_PROTECTION_FAULT, IDXTBL(sel)); if (CPL<RPL(sel)) { + i80286_check_permission(cpustate, SS, cpustate->regs.w[SP]+(iret?6:4)+bytes, 4, I80286_READ); newsp = ReadWord(spaddr+((iret?6:4)+bytes)); newss = ReadWord(spaddr+((iret?8:6)+bytes)); - i80286_data_descriptor_full(cpustate, SS, newss, RPL(sel), TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(newss))); + i80286_data_descriptor_full(cpustate, SS, newss, RPL(sel), TRAP(GENERAL_PROTECTION_FAULT,IDXTBL(newss)), 0, 0); cpustate->regs.w[SP] = newsp + bytes; } else cpustate->regs.w[SP] += (iret?6:4) + bytes; SET_ACC(desc); @@ -855,7 +860,7 @@ static void i80286_check_permission(i8086_state *cpustate, UINT8 check_seg, UINT rights = cpustate->rights[check_seg]; trap = i80286_verify(cpustate, cpustate->sregs[check_seg], operation, rights); if ((CODE(rights) || !EXPDOWN(rights)) && ((offset+size-1) > cpustate->limit[check_seg])) trap = GENERAL_PROTECTION_FAULT; - if (!CODE(rights) && EXPDOWN(rights) && (offset <= cpustate->limit[check_seg]) && ((offset+size) > 0xffff)) trap = GENERAL_PROTECTION_FAULT; + if (!CODE(rights) && EXPDOWN(rights) && ((offset <= cpustate->limit[check_seg]) || ((offset+size) > 0xffff))) trap = GENERAL_PROTECTION_FAULT; if ((trap == GENERAL_PROTECTION_FAULT) && (check_seg == SS)) trap = STACK_FAULT; if (trap) throw TRAP(trap, 0); diff --git a/src/emu/cpu/i86/instr286.h b/src/emu/cpu/i86/instr286.h index 814e2b7106e..f4dc0f7ffda 100644 --- a/src/emu/cpu/i86/instr286.h +++ b/src/emu/cpu/i86/instr286.h @@ -13,8 +13,8 @@ #define STACK_FAULT 12 #define GENERAL_PROTECTION_FAULT 13 -#define PM (cpustate->msw&1) #define CPL (cpustate->sregs[CS]&3) +#define PM (cpustate->msw&1) static void i80286_trap2(i80286_state *cpustate,UINT32 error); static void i80286_interrupt_descriptor(i80286_state *cpustate,UINT16 number, int trap, int error); @@ -40,3 +40,9 @@ enum i80286_operation }; static void i80286_check_permission(i8086_state *cpustate, UINT8 check_seg, UINT32 offset, int size, i80286_operation operation); + +static inline UINT32 GetMemAddr(i80286_state *cpustate, UINT16 seg, UINT16 off, UINT8 size, i80286_operation op) { + seg = DefaultSeg(seg); + if(PM) i80286_check_permission(cpustate, seg, off, size, op); + return (cpustate->base[seg] + off) & AMASK; +} diff --git a/src/emu/cpu/i86/instr86.c b/src/emu/cpu/i86/instr86.c index d5f137e7461..9c94ff6ca78 100644 --- a/src/emu/cpu/i86/instr86.c +++ b/src/emu/cpu/i86/instr86.c @@ -138,6 +138,7 @@ static void PREFIX86(_rotate_shift_Byte)(i8086_state *cpustate, unsigned ModRM, } else { + int tmpcf = CF; ICOUNT -= (ModRM >= 0xc0) ? timing.rot_reg_base + timing.rot_reg_bit : timing.rot_m8_base + timing.rot_m8_bit; switch (ModRM & 0x38) @@ -161,19 +162,21 @@ static void PREFIX86(_rotate_shift_Byte)(i8086_state *cpustate, unsigned ModRM, case 0x10: /* RCL eb,count */ for (; count > 0; count--) { - dst = (dst << 1) + CF; - SetCFB(dst); + dst = (dst << 1) + tmpcf; + tmpcf = (int)((dst & 0x100) != 0); } PutbackRMByte(ModRM,(BYTE)dst); + cpustate->CarryVal = tmpcf; break; case 0x18: /* RCR eb,count */ for (; count > 0; count--) { - dst = (CF<<8)+dst; - cpustate->CarryVal = dst & 0x01; + dst = (tmpcf<<8)+dst; + tmpcf = dst & 0x01; dst >>= 1; } PutbackRMByte(ModRM,(BYTE)dst); + cpustate->CarryVal = tmpcf; break; case 0x20: case 0x30: /* SHL eb,count */ @@ -329,6 +332,7 @@ static void PREFIX86(_rotate_shift_Word)(i8086_state *cpustate, unsigned ModRM, } else { + int tmpcf = CF; ICOUNT -= (ModRM >= 0xc0) ? timing.rot_reg_base + timing.rot_reg_bit : timing.rot_m8_base + timing.rot_m16_bit; switch (ModRM & 0x38) @@ -352,19 +356,21 @@ static void PREFIX86(_rotate_shift_Word)(i8086_state *cpustate, unsigned ModRM, case 0x10: /* RCL ew,count */ for (; count > 0; count--) { - dst = (dst << 1) + CF; - SetCFW(dst); + dst = (dst << 1) + tmpcf; + tmpcf = (int)((dst & 0x10000) != 0); } PutbackRMWord(ModRM,dst); + cpustate->CarryVal = tmpcf; break; case 0x18: /* RCR ew,count */ for (; count > 0; count--) { - dst = dst + (CF << 16); - cpustate->CarryVal = dst & 0x01; + dst = dst + (tmpcf << 16); + tmpcf = dst & 0x01; dst >>= 1; } PutbackRMWord(ModRM,dst); + cpustate->CarryVal = tmpcf; break; case 0x20: case 0x30: /* SHL ew,count */ @@ -401,7 +407,6 @@ static void PREFIX(rep)(i8086_state *cpustate,int flagval) loop to continue for CMPS and SCAS instructions. */ unsigned next = FETCHOP; - unsigned count = cpustate->regs.w[CX]; switch(next) { @@ -441,14 +446,14 @@ static void PREFIX(rep)(i8086_state *cpustate,int flagval) if (!cpustate->rep_in_progress) ICOUNT -= timing.rep_ins8_base; cpustate->rep_in_progress = FALSE; - for (; count > 0; count--) + while(cpustate->regs.w[CX]) { if (ICOUNT <= 0) { cpustate->pc = cpustate->prevpc; cpustate->rep_in_progress = TRUE; break; } PutMemB(ES,cpustate->regs.w[DI],read_port_byte(cpustate->regs.w[DX])); + cpustate->regs.w[CX]--; cpustate->regs.w[DI] += cpustate->DirVal; ICOUNT -= timing.rep_ins8_count; } - cpustate->regs.w[CX]=count; break; case 0x6d: /* REP INSW */ #ifdef I80286 @@ -457,14 +462,14 @@ static void PREFIX(rep)(i8086_state *cpustate,int flagval) if (!cpustate->rep_in_progress) ICOUNT -= timing.rep_ins16_base; cpustate->rep_in_progress = FALSE; - for (; count > 0; count--) + while(cpustate->regs.w[CX]) { if (ICOUNT <= 0) { cpustate->pc = cpustate->prevpc; cpustate->rep_in_progress = TRUE; break; } PutMemW(ES,cpustate->regs.w[DI],read_port_word(cpustate->regs.w[DX])); + cpustate->regs.w[CX]--; cpustate->regs.w[DI] += 2 * cpustate->DirVal; ICOUNT -= timing.rep_ins16_count; } - cpustate->regs.w[CX]=count; break; case 0x6e: /* REP OUTSB */ #ifdef I80286 @@ -473,14 +478,14 @@ static void PREFIX(rep)(i8086_state *cpustate,int flagval) if (!cpustate->rep_in_progress) ICOUNT -= timing.rep_outs8_base; cpustate->rep_in_progress = FALSE; - for (; count > 0; count--) + while(cpustate->regs.w[CX]) { if (ICOUNT <= 0) { cpustate->pc = cpustate->prevpc; cpustate->rep_in_progress = TRUE; break; } write_port_byte(cpustate->regs.w[DX],GetMemB(DS,cpustate->regs.w[SI])); + cpustate->regs.w[CX]--; cpustate->regs.w[SI] += cpustate->DirVal; /* GOL 11/27/01 */ ICOUNT -= timing.rep_outs8_count; } - cpustate->regs.w[CX]=count; break; case 0x6f: /* REP OUTSW */ #ifdef I80286 @@ -489,55 +494,56 @@ static void PREFIX(rep)(i8086_state *cpustate,int flagval) if (!cpustate->rep_in_progress) ICOUNT -= timing.rep_outs16_base; cpustate->rep_in_progress = FALSE; - for (; count > 0; count--) + while(cpustate->regs.w[CX]) { if (ICOUNT <= 0) { cpustate->pc = cpustate->prevpc; cpustate->rep_in_progress = TRUE; break; } write_port_word(cpustate->regs.w[DX],GetMemW(DS,cpustate->regs.w[SI])); + cpustate->regs.w[CX]--; cpustate->regs.w[SI] += 2 * cpustate->DirVal; /* GOL 11/27/01 */ ICOUNT -= timing.rep_outs16_count; } - cpustate->regs.w[CX]=count; break; #endif case 0xa4: /* REP MOVSB */ if (!cpustate->rep_in_progress) ICOUNT -= timing.rep_movs8_base; cpustate->rep_in_progress = FALSE; - for (; count > 0; count--) + while(cpustate->regs.w[CX]) { BYTE tmp; if (ICOUNT <= 0) { cpustate->pc = cpustate->prevpc; cpustate->rep_in_progress = TRUE; break; } tmp = GetMemB(DS,cpustate->regs.w[SI]); PutMemB(ES,cpustate->regs.w[DI], tmp); + cpustate->regs.w[CX]--; cpustate->regs.w[DI] += cpustate->DirVal; cpustate->regs.w[SI] += cpustate->DirVal; ICOUNT -= timing.rep_movs8_count; } - cpustate->regs.w[CX]=count; break; case 0xa5: /* REP MOVSW */ if (!cpustate->rep_in_progress) ICOUNT -= timing.rep_movs16_base; cpustate->rep_in_progress = FALSE; - for (; count > 0; count--) + while(cpustate->regs.w[CX]) { WORD tmp; if (ICOUNT <= 0) { cpustate->pc = cpustate->prevpc; cpustate->rep_in_progress = TRUE; break; } tmp = GetMemW(DS,cpustate->regs.w[SI]); PutMemW(ES,cpustate->regs.w[DI], tmp); + cpustate->regs.w[CX]--; cpustate->regs.w[DI] += 2 * cpustate->DirVal; cpustate->regs.w[SI] += 2 * cpustate->DirVal; ICOUNT -= timing.rep_movs16_count; } - cpustate->regs.w[CX]=count; break; case 0xa6: /* REP(N)E CMPSB */ if (!cpustate->rep_in_progress) ICOUNT -= timing.rep_cmps8_base; cpustate->rep_in_progress = FALSE; - for (cpustate->ZeroVal = !flagval; (ZF == flagval) && (count > 0); count--) + cpustate->ZeroVal = !flagval; + while(cpustate->regs.w[CX] && (ZF == flagval)) { unsigned dst, src; @@ -545,17 +551,18 @@ static void PREFIX(rep)(i8086_state *cpustate,int flagval) dst = GetMemB(ES, cpustate->regs.w[DI]); src = GetMemB(DS, cpustate->regs.w[SI]); SUBB(src,dst); /* opposite of the usual convention */ + cpustate->regs.w[CX]--; cpustate->regs.w[DI] += cpustate->DirVal; cpustate->regs.w[SI] += cpustate->DirVal; ICOUNT -= timing.rep_cmps8_count; } - cpustate->regs.w[CX]=count; break; case 0xa7: /* REP(N)E CMPSW */ if (!cpustate->rep_in_progress) ICOUNT -= timing.rep_cmps16_base; cpustate->rep_in_progress = FALSE; - for (cpustate->ZeroVal = !flagval; (ZF == flagval) && (count > 0); count--) + cpustate->ZeroVal = !flagval; + while(cpustate->regs.w[CX] && (ZF == flagval)) { unsigned dst, src; @@ -563,69 +570,70 @@ static void PREFIX(rep)(i8086_state *cpustate,int flagval) dst = GetMemW(ES, cpustate->regs.w[DI]); src = GetMemW(DS, cpustate->regs.w[SI]); SUBW(src,dst); /* opposite of the usual convention */ + cpustate->regs.w[CX]--; cpustate->regs.w[DI] += 2 * cpustate->DirVal; cpustate->regs.w[SI] += 2 * cpustate->DirVal; ICOUNT -= timing.rep_cmps16_count; } - cpustate->regs.w[CX]=count; break; case 0xaa: /* REP STOSB */ if (!cpustate->rep_in_progress) ICOUNT -= timing.rep_stos8_base; cpustate->rep_in_progress = FALSE; - for (; count > 0; count--) + while(cpustate->regs.w[CX]) { if (ICOUNT <= 0) { cpustate->pc = cpustate->prevpc; cpustate->rep_in_progress = TRUE; break; } PutMemB(ES,cpustate->regs.w[DI],cpustate->regs.b[AL]); + cpustate->regs.w[CX]--; cpustate->regs.w[DI] += cpustate->DirVal; ICOUNT -= timing.rep_stos8_count; } - cpustate->regs.w[CX]=count; break; case 0xab: /* REP STOSW */ if (!cpustate->rep_in_progress) ICOUNT -= timing.rep_stos16_base; cpustate->rep_in_progress = FALSE; - for (; count > 0; count--) + while(cpustate->regs.w[CX]) { if (ICOUNT <= 0) { cpustate->pc = cpustate->prevpc; cpustate->rep_in_progress = TRUE; break; } PutMemW(ES,cpustate->regs.w[DI],cpustate->regs.w[AX]); + cpustate->regs.w[CX]--; cpustate->regs.w[DI] += 2 * cpustate->DirVal; ICOUNT -= timing.rep_stos16_count; } - cpustate->regs.w[CX]=count; break; case 0xac: /* REP LODSB */ if (!cpustate->rep_in_progress) ICOUNT -= timing.rep_lods8_base; cpustate->rep_in_progress = FALSE; - for (; count > 0; count--) + while(cpustate->regs.w[CX]) { if (ICOUNT <= 0) { cpustate->pc = cpustate->prevpc; cpustate->rep_in_progress = TRUE; break; } cpustate->regs.b[AL] = GetMemB(DS,cpustate->regs.w[SI]); + cpustate->regs.w[CX]--; cpustate->regs.w[SI] += cpustate->DirVal; ICOUNT -= timing.rep_lods8_count; } - cpustate->regs.w[CX]=count; break; case 0xad: /* REP LODSW */ if (!cpustate->rep_in_progress) ICOUNT -= timing.rep_lods16_base; cpustate->rep_in_progress = FALSE; - for (; count > 0; count--) + while(cpustate->regs.w[CX]) { if (ICOUNT <= 0) { cpustate->pc = cpustate->prevpc; cpustate->rep_in_progress = TRUE; break; } cpustate->regs.w[AX] = GetMemW(DS,cpustate->regs.w[SI]); + cpustate->regs.w[CX]--; cpustate->regs.w[SI] += 2 * cpustate->DirVal; ICOUNT -= timing.rep_lods16_count; } - cpustate->regs.w[CX]=count; break; case 0xae: /* REP(N)E SCASB */ if (!cpustate->rep_in_progress) ICOUNT -= timing.rep_scas8_base; cpustate->rep_in_progress = FALSE; - for (cpustate->ZeroVal = !flagval; (ZF == flagval) && (count > 0); count--) + cpustate->ZeroVal = !flagval; + while(cpustate->regs.w[CX] && (ZF == flagval)) { unsigned src, dst; @@ -633,16 +641,17 @@ static void PREFIX(rep)(i8086_state *cpustate,int flagval) src = GetMemB(ES, cpustate->regs.w[DI]); dst = cpustate->regs.b[AL]; SUBB(dst,src); + cpustate->regs.w[CX]--; cpustate->regs.w[DI] += cpustate->DirVal; ICOUNT -= timing.rep_scas8_count; } - cpustate->regs.w[CX]=count; break; case 0xaf: /* REP(N)E SCASW */ if (!cpustate->rep_in_progress) ICOUNT -= timing.rep_scas16_base; cpustate->rep_in_progress = FALSE; - for (cpustate->ZeroVal = !flagval; (ZF == flagval) && (count > 0); count--) + cpustate->ZeroVal = !flagval; + while(cpustate->regs.w[CX] && (ZF == flagval)) { unsigned src, dst; @@ -650,10 +659,10 @@ static void PREFIX(rep)(i8086_state *cpustate,int flagval) src = GetMemW(ES, cpustate->regs.w[DI]); dst = cpustate->regs.w[AX]; SUBW(dst,src); + cpustate->regs.w[CX]--; cpustate->regs.w[DI] += 2 * cpustate->DirVal; ICOUNT -= timing.rep_scas16_count; } - cpustate->regs.w[CX]=count; break; default: PREFIX(_instruction)[next](cpustate); @@ -798,20 +807,24 @@ static void PREFIX86(_pop_cs)(i8086_state *cpustate) /* Opcode 0x0f */ static void PREFIX86(_adc_br8)(i8086_state *cpustate) /* Opcode 0x10 */ { - DEF_br8(dst,src); + int tmpcf; + DEF_br8(dst,src); ICOUNT -= (ModRM >= 0xc0) ? timing.alu_rr8 : timing.alu_mr8; src+=CF; - ADDB(dst,src); + ADCB(dst,src,tmpcf); PutbackRMByte(ModRM,dst); + cpustate->CarryVal = tmpcf; } static void PREFIX86(_adc_wr16)(i8086_state *cpustate) /* Opcode 0x11 */ { - DEF_wr16(dst,src); + int tmpcf; + DEF_wr16(dst,src); ICOUNT -= (ModRM >= 0xc0) ? timing.alu_rr16 : timing.alu_mr16; src+=CF; - ADDW(dst,src); + ADCW(dst,src,tmpcf); PutbackRMWord(ModRM,dst); + cpustate->CarryVal = tmpcf; } static void PREFIX86(_adc_r8b)(i8086_state *cpustate) /* Opcode 0x12 */ @@ -858,20 +871,24 @@ static void PREFIX86(_push_ss)(i8086_state *cpustate) /* Opcode 0x16 */ static void PREFIX86(_sbb_br8)(i8086_state *cpustate) /* Opcode 0x18 */ { - DEF_br8(dst,src); + int tmpcf; + DEF_br8(dst,src); ICOUNT -= (ModRM >= 0xc0) ? timing.alu_rr8 : timing.alu_mr8; src+=CF; - SUBB(dst,src); + SBBB(dst,src,tmpcf); PutbackRMByte(ModRM,dst); + cpustate->CarryVal = tmpcf; } static void PREFIX86(_sbb_wr16)(i8086_state *cpustate) /* Opcode 0x19 */ { + int tmpcf; DEF_wr16(dst,src); ICOUNT -= (ModRM >= 0xc0) ? timing.alu_rr16 : timing.alu_mr16; src+=CF; - SUBW(dst,src); + SBBW(dst,src,tmpcf); PutbackRMWord(ModRM,dst); + cpustate->CarryVal = tmpcf; } static void PREFIX86(_sbb_r8b)(i8086_state *cpustate) /* Opcode 0x1a */ @@ -1581,6 +1598,7 @@ static void PREFIX86(_80pre)(i8086_state *cpustate) /* Opcode 0x80 */ unsigned ModRM = FETCHOP; unsigned dst = GetRMByte(ModRM); unsigned src = FETCH; + int tmpcf; switch (ModRM & 0x38) { @@ -1596,14 +1614,16 @@ static void PREFIX86(_80pre)(i8086_state *cpustate) /* Opcode 0x80 */ break; case 0x10: /* ADC eb,d8 */ src+=CF; - ADDB(dst,src); + ADCB(dst,src,tmpcf); PutbackRMByte(ModRM,dst); + cpustate->CarryVal = tmpcf; ICOUNT -= (ModRM >= 0xc0) ? timing.alu_ri8 : timing.alu_mi8; break; case 0x18: /* SBB eb,b8 */ src+=CF; - SUBB(dst,src); + SBBB(dst,src,tmpcf); PutbackRMByte(ModRM,dst); + cpustate->CarryVal = tmpcf; ICOUNT -= (ModRM >= 0xc0) ? timing.alu_ri8 : timing.alu_mi8; break; case 0x20: /* AND eb,d8 */ @@ -1634,6 +1654,7 @@ static void PREFIX86(_81pre)(i8086_state *cpustate) /* Opcode 0x81 */ unsigned ModRM = FETCH; unsigned dst = GetRMWord(ModRM); unsigned src = FETCH; + int tmpcf; src+= (FETCH << 8); switch (ModRM & 0x38) @@ -1650,14 +1671,16 @@ static void PREFIX86(_81pre)(i8086_state *cpustate) /* Opcode 0x81 */ break; case 0x10: /* ADC ew,d16 */ src+=CF; - ADDW(dst,src); + ADCW(dst,src,tmpcf); PutbackRMWord(ModRM,dst); + cpustate->CarryVal = tmpcf; ICOUNT -= (ModRM >= 0xc0) ? timing.alu_ri16 : timing.alu_mi16; break; case 0x18: /* SBB ew,d16 */ src+=CF; - SUBW(dst,src); + SBBW(dst,src,tmpcf); PutbackRMWord(ModRM,dst); + cpustate->CarryVal = tmpcf; ICOUNT -= (ModRM >= 0xc0) ? timing.alu_ri16 : timing.alu_mi16; break; case 0x20: /* AND ew,d16 */ @@ -1687,6 +1710,7 @@ static void PREFIX86(_82pre)(i8086_state *cpustate) /* Opcode 0x82 */ unsigned ModRM = FETCH; unsigned dst = GetRMByte(ModRM); unsigned src = FETCH; + int tmpcf; switch (ModRM & 0x38) { @@ -1702,14 +1726,16 @@ static void PREFIX86(_82pre)(i8086_state *cpustate) /* Opcode 0x82 */ break; case 0x10: /* ADC eb,d8 */ src+=CF; - ADDB(dst,src); + ADCB(dst,src,tmpcf); PutbackRMByte(ModRM,dst); + cpustate->CarryVal = tmpcf; ICOUNT -= (ModRM >= 0xc0) ? timing.alu_ri8 : timing.alu_mi8; break; case 0x18: /* SBB eb,d8 */ src+=CF; - SUBB(dst,src); + SBBB(dst,src,tmpcf); PutbackRMByte(ModRM,dst); + cpustate->CarryVal = tmpcf; ICOUNT -= (ModRM >= 0xc0) ? timing.alu_ri8 : timing.alu_mi8; break; case 0x20: /* AND eb,d8 */ @@ -1739,6 +1765,7 @@ static void PREFIX86(_83pre)(i8086_state *cpustate) /* Opcode 0x83 */ unsigned ModRM = FETCH; unsigned dst = GetRMWord(ModRM); unsigned src = (WORD)((INT16)((INT8)FETCH)); + int tmpcf; switch (ModRM & 0x38) { @@ -1754,14 +1781,16 @@ static void PREFIX86(_83pre)(i8086_state *cpustate) /* Opcode 0x83 */ break; case 0x10: /* ADC ew,d16 */ src+=CF; - ADDW(dst,src); + ADCW(dst,src,tmpcf); PutbackRMWord(ModRM,dst); + cpustate->CarryVal = tmpcf; ICOUNT -= (ModRM >= 0xc0) ? timing.alu_r16i8 : timing.alu_m16i8; break; case 0x18: /* SBB ew,d16 */ src+=CF; - SUBW(dst,src); + SBBW(dst,src,tmpcf); PutbackRMWord(ModRM,dst); + cpustate->CarryVal = tmpcf; ICOUNT -= (ModRM >= 0xc0) ? timing.alu_r16i8 : timing.alu_m16i8; break; case 0x20: /* AND ew,d16 */ @@ -1804,16 +1833,16 @@ static void PREFIX86(_xchg_br8)(i8086_state *cpustate) /* Opcode 0x86 */ { DEF_br8(dst,src); ICOUNT -= (ModRM >= 0xc0) ? timing.xchg_rr8 : timing.xchg_rm8; - RegByte(ModRM)=dst; PutbackRMByte(ModRM,src); + RegByte(ModRM)=dst; } static void PREFIX86(_xchg_wr16)(i8086_state *cpustate) /* Opcode 0x87 */ { DEF_wr16(dst,src); ICOUNT -= (ModRM >= 0xc0) ? timing.xchg_rr16 : timing.xchg_rm16; - RegWord(ModRM)=dst; PutbackRMWord(ModRM,src); + RegWord(ModRM)=dst; } static void PREFIX86(_mov_br8)(i8086_state *cpustate) /* Opcode 0x88 */ @@ -2754,6 +2783,7 @@ static void PREFIX(_mov_sregw)(i8086_state *cpustate) /* Opcode 0x8e */ PREFIX(_instruction)[FETCHOP](cpustate); break; case 0x08: /* mov cs,ew */ + PREFIX(_invalid)(cpustate); break; /* doesn't do a jump far */ } #else |