📄 prim_ops.c
字号:
/****************************************************************************** Realmode X86 Emulator Library** Copyright (C) 1996-1999 SciTech Software, Inc.* Copyright (C) David Mosberger-Tang* Copyright (C) 1999 Egbert Eich** ========================================================================** Permission to use, copy, modify, distribute, and sell this software and* its documentation for any purpose is hereby granted without fee,* provided that the above copyright notice appear in all copies and that* both that copyright notice and this permission notice appear in* supporting documentation, and that the name of the authors not be used* in advertising or publicity pertaining to distribution of the software* without specific, written prior permission. The authors makes no* representations about the suitability of this software for any purpose.* It is provided "as is" without express or implied warranty.** THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR* PERFORMANCE OF THIS SOFTWARE.** ========================================================================** Language: ANSI C* Environment: Any* Developer: Kendall Bennett** Description: This file contains the code to implement the primitive* machine operations used by the emulation code in ops.c** Carry Chain Calculation** This represents a somewhat expensive calculation which is* apparently required to emulate the setting of the OF and AF flag.* The latter is not so important, but the former is. The overflow* flag is the XOR of the top two bits of the carry chain for an* addition (similar for subtraction). Since we do not want to* simulate the addition in a bitwise manner, we try to calculate the* carry chain given the two operands and the result.** So, given the following table, which represents the addition of two* bits, we can derive a formula for the carry chain.** a b cin r cout* 0 0 0 0 0* 0 0 1 1 0* 0 1 0 1 0* 0 1 1 0 1* 1 0 0 1 0* 1 0 1 0 1* 1 1 0 0 1* 1 1 1 1 1** Construction of table for cout:** ab* r \ 00 01 11 10* |------------------* 0 | 0 1 1 1* 1 | 0 0 1 0** By inspection, one gets: cc = ab + r'(a + b)** That represents alot of operations, but NO CHOICE....** Borrow Chain Calculation.** The following table represents the subtraction of two bits, from* which we can derive a formula for the borrow chain.** a b bin r bout* 0 0 0 0 0* 0 0 1 1 1* 0 1 0 1 1* 0 1 1 0 1* 1 0 0 1 0* 1 0 1 0 0* 1 1 0 0 0* 1 1 1 1 1** Construction of table for cout:** ab* r \ 00 01 11 10* |------------------* 0 | 0 1 0 0* 1 | 1 1 1 0** By inspection, one gets: bc = a'b + r(a' + b)*****************************************************************************/#define PRIM_OPS_NO_REDEFINE_ASM#include "x86emu/x86emui.h"/*------------------------- Global Variables ------------------------------*/#ifndef __HAVE_INLINE_ASSEMBLER__static u32 x86emu_parity_tab[8] ={ 0x96696996, 0x69969669, 0x69969669, 0x96696996, 0x69969669, 0x96696996, 0x96696996, 0x69969669,};#endif#define PARITY(x) (((x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)#define XOR2(x) (((x) ^ ((x)>>1)) & 0x1)/*----------------------------- Implementation ----------------------------*/#ifndef __HAVE_INLINE_ASSEMBLER__/****************************************************************************REMARKS:Implements the AAA instruction and side effects.****************************************************************************/u16 aaa_word(u16 d){ u16 res; if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) { d += 0x6; d += 0x100; SET_FLAG(F_AF); SET_FLAG(F_CF); } else { CLEAR_FLAG(F_CF); CLEAR_FLAG(F_AF); } res = (u16)(d & 0xFF0F); CLEAR_FLAG(F_SF); CONDITIONAL_SET_FLAG(res == 0, F_ZF); CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); return res;}/****************************************************************************REMARKS:Implements the AAA instruction and side effects.****************************************************************************/u16 aas_word(u16 d){ u16 res; if ((d & 0xf) > 0x9 || ACCESS_FLAG(F_AF)) { d -= 0x6; d -= 0x100; SET_FLAG(F_AF); SET_FLAG(F_CF); } else { CLEAR_FLAG(F_CF); CLEAR_FLAG(F_AF); } res = (u16)(d & 0xFF0F); CLEAR_FLAG(F_SF); CONDITIONAL_SET_FLAG(res == 0, F_ZF); CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); return res;}/****************************************************************************REMARKS:Implements the AAD instruction and side effects.****************************************************************************/u16 aad_word(u16 d){ u16 l; u8 hb, lb; hb = (u8)((d >> 8) & 0xff); lb = (u8)((d & 0xff)); l = (u16)((lb + 10 * hb) & 0xFF); CLEAR_FLAG(F_CF); CLEAR_FLAG(F_AF); CLEAR_FLAG(F_OF); CONDITIONAL_SET_FLAG(l & 0x80, F_SF); CONDITIONAL_SET_FLAG(l == 0, F_ZF); CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF); return l;}/****************************************************************************REMARKS:Implements the AAM instruction and side effects.****************************************************************************/u16 aam_word(u8 d){ u16 h, l; h = (u16)(d / 10); l = (u16)(d % 10); l |= (u16)(h << 8); CLEAR_FLAG(F_CF); CLEAR_FLAG(F_AF); CLEAR_FLAG(F_OF); CONDITIONAL_SET_FLAG(l & 0x80, F_SF); CONDITIONAL_SET_FLAG(l == 0, F_ZF); CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF); return l;}/****************************************************************************REMARKS:Implements the ADC instruction and side effects.****************************************************************************/u8 adc_byte(u8 d, u8 s){ register u32 res; /* all operands in native machine order */ register u32 cc; if (ACCESS_FLAG(F_CF)) res = 1 + d + s; else res = d + s; CONDITIONAL_SET_FLAG(res & 0x100, F_CF); CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); CONDITIONAL_SET_FLAG(res & 0x80, F_SF); CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); /* calculate the carry chain SEE NOTE AT TOP. */ cc = (s & d) | ((~res) & (s | d)); CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF); CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); return (u8)res;}/****************************************************************************REMARKS:Implements the ADC instruction and side effects.****************************************************************************/u16 adc_word(u16 d, u16 s){ register u32 res; /* all operands in native machine order */ register u32 cc; if (ACCESS_FLAG(F_CF)) res = 1 + d + s; else res = d + s; CONDITIONAL_SET_FLAG(res & 0x10000, F_CF); CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); /* calculate the carry chain SEE NOTE AT TOP. */ cc = (s & d) | ((~res) & (s | d)); CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF); CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); return (u16)res;}/****************************************************************************REMARKS:Implements the ADC instruction and side effects.****************************************************************************/u32 adc_long(u32 d, u32 s){ register u32 lo; /* all operands in native machine order */ register u32 hi; register u32 res; register u32 cc; if (ACCESS_FLAG(F_CF)) { lo = 1 + (d & 0xFFFF) + (s & 0xFFFF); res = 1 + d + s; } else { lo = (d & 0xFFFF) + (s & 0xFFFF); res = d + s; } hi = (lo >> 16) + (d >> 16) + (s >> 16); CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF); CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); /* calculate the carry chain SEE NOTE AT TOP. */ cc = (s & d) | ((~res) & (s | d)); CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF); CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); return res;}/****************************************************************************REMARKS:Implements the ADD instruction and side effects.****************************************************************************/u8 add_byte(u8 d, u8 s){ register u32 res; /* all operands in native machine order */ register u32 cc; res = d + s; CONDITIONAL_SET_FLAG(res & 0x100, F_CF); CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); CONDITIONAL_SET_FLAG(res & 0x80, F_SF); CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); /* calculate the carry chain SEE NOTE AT TOP. */ cc = (s & d) | ((~res) & (s | d)); CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF); CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); return (u8)res;}/****************************************************************************REMARKS:Implements the ADD instruction and side effects.****************************************************************************/u16 add_word(u16 d, u16 s){ register u32 res; /* all operands in native machine order */ register u32 cc; res = d + s; CONDITIONAL_SET_FLAG(res & 0x10000, F_CF); CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); /* calculate the carry chain SEE NOTE AT TOP. */ cc = (s & d) | ((~res) & (s | d)); CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF); CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); return (u16)res;}/****************************************************************************REMARKS:Implements the ADD instruction and side effects.****************************************************************************/u32 add_long(u32 d, u32 s){ register u32 lo; /* all operands in native machine order */ register u32 hi; register u32 res; register u32 cc; lo = (d & 0xFFFF) + (s & 0xFFFF); res = d + s; hi = (lo >> 16) + (d >> 16) + (s >> 16); CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF); CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF); CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); /* calculate the carry chain SEE NOTE AT TOP. */ cc = (s & d) | ((~res) & (s | d)); CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF); CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); return res;}/****************************************************************************REMARKS:Implements the AND instruction and side effects.****************************************************************************/u8 and_byte(u8 d, u8 s){ register u8 res; /* all operands in native machine order */ res = d & s; /* set the flags */ CLEAR_FLAG(F_OF); CLEAR_FLAG(F_CF); CLEAR_FLAG(F_AF); CONDITIONAL_SET_FLAG(res & 0x80, F_SF); CONDITIONAL_SET_FLAG(res == 0, F_ZF); CONDITIONAL_SET_FLAG(PARITY(res), F_PF); return res;}/****************************************************************************REMARKS:Implements the AND instruction and side effects.****************************************************************************/u16 and_word(u16 d, u16 s){ register u16 res; /* all operands in native machine order */ res = d & s; /* set the flags */ CLEAR_FLAG(F_OF); CLEAR_FLAG(F_CF); CLEAR_FLAG(F_AF); CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); CONDITIONAL_SET_FLAG(res == 0, F_ZF); CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); return res;}/****************************************************************************REMARKS:Implements the AND instruction and side effects.****************************************************************************/u32 and_long(u32 d, u32 s){ register u32 res; /* all operands in native machine order */ res = d & s; /* set the flags */ CLEAR_FLAG(F_OF); CLEAR_FLAG(F_CF); CLEAR_FLAG(F_AF); CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); CONDITIONAL_SET_FLAG(res == 0, F_ZF); CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); return res;}/****************************************************************************REMARKS:Implements the CMP instruction and side effects.****************************************************************************/u8 cmp_byte(u8 d, u8 s){ register u32 res; /* all operands in native machine order */ register u32 bc; res = d - s; CLEAR_FLAG(F_CF); CONDITIONAL_SET_FLAG(res & 0x80, F_SF); CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF); CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); /* calculate the borrow chain. See note at top */ bc = (res & (~d | s)) | (~d & s); CONDITIONAL_SET_FLAG(bc & 0x80, F_CF); CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF); CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); return d;}/****************************************************************************REMARKS:Implements the CMP instruction and side effects.****************************************************************************/u16 cmp_word(u16 d, u16 s){ register u32 res; /* all operands in native machine order */ register u32 bc; res = d - s; CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF); CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF); /* calculate the borrow chain. See note at top */ bc = (res & (~d | s)) | (~d & s); CONDITIONAL_SET_FLAG(bc & 0x8000, F_CF); CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -