prim_ops.c
来自「适合KS8695X」· C语言 代码 · 共 2,262 行 · 第 1/5 页
C
2,262 行
/****************************************************************************
*
* 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);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?