You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2860 lines
81 KiB
C
2860 lines
81 KiB
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 a lot 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)
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include <stdlib.h>
|
|
|
|
#define PRIM_OPS_NO_REDEFINE_ASM
|
|
#include "x86emu/x86emui.h"
|
|
|
|
#if defined(__GNUC__)
|
|
#if defined (__i386__) || defined(__i386) || defined(__AMD64__) || defined(__amd64__)
|
|
#include "x86emu/prim_x86_gcc.h"
|
|
#endif
|
|
#endif
|
|
|
|
/*------------------------- Global Variables ------------------------------*/
|
|
|
|
static u32 x86emu_parity_tab[8] = {
|
|
0x96696996,
|
|
0x69969669,
|
|
0x69969669,
|
|
0x96696996,
|
|
0x69969669,
|
|
0x96696996,
|
|
0x96696996,
|
|
0x69969669,
|
|
};
|
|
|
|
#define PARITY(x) (((x86emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)
|
|
#define XOR2(x) (((x) ^ ((x)>>1)) & 0x1)
|
|
|
|
/*----------------------------- Implementation ----------------------------*/
|
|
|
|
/****************************************************************************
|
|
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);
|
|
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
|
return d;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the CMP instruction and side effects.
|
|
****************************************************************************/
|
|
u32
|
|
cmp_long(u32 d, u32 s)
|
|
{
|
|
register u32 res; /* all operands in native machine order */
|
|
register u32 bc;
|
|
|
|
res = d - s;
|
|
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
|
|
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 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 & 0x80000000, F_CF);
|
|
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
|
|
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
|
return d;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the DAA instruction and side effects.
|
|
****************************************************************************/
|
|
u8
|
|
daa_byte(u8 d)
|
|
{
|
|
u32 res = d;
|
|
|
|
if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
|
|
res += 6;
|
|
SET_FLAG(F_AF);
|
|
}
|
|
if (res > 0x9F || ACCESS_FLAG(F_CF)) {
|
|
res += 0x60;
|
|
SET_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);
|
|
return (u8) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the DAS instruction and side effects.
|
|
****************************************************************************/
|
|
u8
|
|
das_byte(u8 d)
|
|
{
|
|
if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
|
|
d -= 6;
|
|
SET_FLAG(F_AF);
|
|
}
|
|
if (d > 0x9F || ACCESS_FLAG(F_CF)) {
|
|
d -= 0x60;
|
|
SET_FLAG(F_CF);
|
|
}
|
|
CONDITIONAL_SET_FLAG(d & 0x80, F_SF);
|
|
CONDITIONAL_SET_FLAG(d == 0, F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(d & 0xff), F_PF);
|
|
return d;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the DEC instruction and side effects.
|
|
****************************************************************************/
|
|
u8
|
|
dec_byte(u8 d)
|
|
{
|
|
register u32 res; /* all operands in native machine order */
|
|
register u32 bc;
|
|
|
|
res = d - 1;
|
|
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 */
|
|
/* based on sub_byte, uses s==1. */
|
|
bc = (res & (~d | 1)) | (~d & 1);
|
|
/* carry flag unchanged */
|
|
CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
|
|
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
|
return (u8) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the DEC instruction and side effects.
|
|
****************************************************************************/
|
|
u16
|
|
dec_word(u16 d)
|
|
{
|
|
register u32 res; /* all operands in native machine order */
|
|
register u32 bc;
|
|
|
|
res = d - 1;
|
|
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 */
|
|
/* based on the sub_byte routine, with s==1 */
|
|
bc = (res & (~d | 1)) | (~d & 1);
|
|
/* carry flag unchanged */
|
|
CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
|
|
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
|
return (u16) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the DEC instruction and side effects.
|
|
****************************************************************************/
|
|
u32
|
|
dec_long(u32 d)
|
|
{
|
|
register u32 res; /* all operands in native machine order */
|
|
register u32 bc;
|
|
|
|
res = d - 1;
|
|
|
|
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
|
|
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
|
|
|
/* calculate the borrow chain. See note at top */
|
|
bc = (res & (~d | 1)) | (~d & 1);
|
|
/* carry flag unchanged */
|
|
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
|
|
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the INC instruction and side effects.
|
|
****************************************************************************/
|
|
u8
|
|
inc_byte(u8 d)
|
|
{
|
|
register u32 res; /* all operands in native machine order */
|
|
register u32 cc;
|
|
|
|
res = d + 1;
|
|
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 = ((1 & d) | (~res)) & (1 | d);
|
|
CONDITIONAL_SET_FLAG(XOR2(cc >> 6), F_OF);
|
|
CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
|
|
return (u8) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the INC instruction and side effects.
|
|
****************************************************************************/
|
|
u16
|
|
inc_word(u16 d)
|
|
{
|
|
register u32 res; /* all operands in native machine order */
|
|
register u32 cc;
|
|
|
|
res = d + 1;
|
|
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 = (1 & d) | ((~res) & (1 | d));
|
|
CONDITIONAL_SET_FLAG(XOR2(cc >> 14), F_OF);
|
|
CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
|
|
return (u16) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the INC instruction and side effects.
|
|
****************************************************************************/
|
|
u32
|
|
inc_long(u32 d)
|
|
{
|
|
register u32 res; /* all operands in native machine order */
|
|
register u32 cc;
|
|
|
|
res = d + 1;
|
|
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 = (1 & d) | ((~res) & (1 | d));
|
|
CONDITIONAL_SET_FLAG(XOR2(cc >> 30), F_OF);
|
|
CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the OR instruction and side effects.
|
|
****************************************************************************/
|
|
u8
|
|
or_byte(u8 d, u8 s)
|
|
{
|
|
register u8 res; /* all operands in native machine order */
|
|
|
|
res = d | s;
|
|
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 OR instruction and side effects.
|
|
****************************************************************************/
|
|
u16
|
|
or_word(u16 d, u16 s)
|
|
{
|
|
register u16 res; /* all operands in native machine order */
|
|
|
|
res = d | s;
|
|
/* set the carry flag to be bit 8 */
|
|
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 OR instruction and side effects.
|
|
****************************************************************************/
|
|
u32
|
|
or_long(u32 d, u32 s)
|
|
{
|
|
register u32 res; /* all operands in native machine order */
|
|
|
|
res = d | s;
|
|
|
|
/* set the carry flag to be bit 8 */
|
|
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 OR instruction and side effects.
|
|
****************************************************************************/
|
|
u8
|
|
neg_byte(u8 s)
|
|
{
|
|
register u8 res;
|
|
register u8 bc;
|
|
|
|
CONDITIONAL_SET_FLAG(s != 0, F_CF);
|
|
res = (u8) - s;
|
|
CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
|
|
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
|
|
/* calculate the borrow chain --- modified such that d=0.
|
|
substitutiing d=0 into bc= res&(~d|s)|(~d&s);
|
|
(the one used for sub) and simplifying, since ~d=0xff...,
|
|
~d|s == 0xffff..., and res&0xfff... == res. Similarly
|
|
~d&s == s. So the simplified result is: */
|
|
bc = res | s;
|
|
CONDITIONAL_SET_FLAG(XOR2(bc >> 6), F_OF);
|
|
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the OR instruction and side effects.
|
|
****************************************************************************/
|
|
u16
|
|
neg_word(u16 s)
|
|
{
|
|
register u16 res;
|
|
register u16 bc;
|
|
|
|
CONDITIONAL_SET_FLAG(s != 0, F_CF);
|
|
res = (u16) - s;
|
|
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 borrow chain --- modified such that d=0.
|
|
substitutiing d=0 into bc= res&(~d|s)|(~d&s);
|
|
(the one used for sub) and simplifying, since ~d=0xff...,
|
|
~d|s == 0xffff..., and res&0xfff... == res. Similarly
|
|
~d&s == s. So the simplified result is: */
|
|
bc = res | s;
|
|
CONDITIONAL_SET_FLAG(XOR2(bc >> 14), F_OF);
|
|
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the OR instruction and side effects.
|
|
****************************************************************************/
|
|
u32
|
|
neg_long(u32 s)
|
|
{
|
|
register u32 res;
|
|
register u32 bc;
|
|
|
|
CONDITIONAL_SET_FLAG(s != 0, F_CF);
|
|
res = (u32) - s;
|
|
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 borrow chain --- modified such that d=0.
|
|
substitutiing d=0 into bc= res&(~d|s)|(~d&s);
|
|
(the one used for sub) and simplifying, since ~d=0xff...,
|
|
~d|s == 0xffff..., and res&0xfff... == res. Similarly
|
|
~d&s == s. So the simplified result is: */
|
|
bc = res | s;
|
|
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
|
|
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the NOT instruction and side effects.
|
|
****************************************************************************/
|
|
u8
|
|
not_byte(u8 s)
|
|
{
|
|
return ~s;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the NOT instruction and side effects.
|
|
****************************************************************************/
|
|
u16
|
|
not_word(u16 s)
|
|
{
|
|
return ~s;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the NOT instruction and side effects.
|
|
****************************************************************************/
|
|
u32
|
|
not_long(u32 s)
|
|
{
|
|
return ~s;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the RCL instruction and side effects.
|
|
****************************************************************************/
|
|
u8
|
|
rcl_byte(u8 d, u8 s)
|
|
{
|
|
register unsigned int res, cnt, mask, cf;
|
|
|
|
/* s is the rotate distance. It varies from 0 - 8. */
|
|
/* have
|
|
|
|
CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0
|
|
|
|
want to rotate through the carry by "s" bits. We could
|
|
loop, but that's inefficient. So the width is 9,
|
|
and we split into three parts:
|
|
|
|
The new carry flag (was B_n)
|
|
the stuff in B_n-1 .. B_0
|
|
the stuff in B_7 .. B_n+1
|
|
|
|
The new rotate is done mod 9, and given this,
|
|
for a rotation of n bits (mod 9) the new carry flag is
|
|
then located n bits from the MSB. The low part is
|
|
then shifted up cnt bits, and the high part is or'd
|
|
in. Using CAPS for new values, and lowercase for the
|
|
original values, this can be expressed as:
|
|
|
|
IF n > 0
|
|
1) CF <- b_(8-n)
|
|
2) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0
|
|
3) B_(n-1) <- cf
|
|
4) B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1))
|
|
*/
|
|
res = d;
|
|
if ((cnt = s % 9) != 0) {
|
|
/* extract the new CARRY FLAG. */
|
|
/* CF <- b_(8-n) */
|
|
cf = (d >> (8 - cnt)) & 0x1;
|
|
|
|
/* get the low stuff which rotated
|
|
into the range B_7 .. B_cnt */
|
|
/* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_0 */
|
|
/* note that the right hand side done by the mask */
|
|
res = (d << cnt) & 0xff;
|
|
|
|
/* now the high stuff which rotated around
|
|
into the positions B_cnt-2 .. B_0 */
|
|
/* B_(n-2) .. B_0 <- b_7 .. b_(8-(n-1)) */
|
|
/* shift it downward, 7-(n-2) = 9-n positions.
|
|
and mask off the result before or'ing in.
|
|
*/
|
|
mask = (1 << (cnt - 1)) - 1;
|
|
res |= (d >> (9 - cnt)) & mask;
|
|
|
|
/* if the carry flag was set, or it in. */
|
|
if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
|
|
/* B_(n-1) <- cf */
|
|
res |= 1 << (cnt - 1);
|
|
}
|
|
/* set the new carry flag, based on the variable "cf" */
|
|
CONDITIONAL_SET_FLAG(cf, F_CF);
|
|
/* OVERFLOW is set *IFF* cnt==1, then it is the
|
|
xor of CF and the most significant bit. Blecck. */
|
|
/* parenthesized this expression since it appears to
|
|
be causing OF to be misset */
|
|
CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 6) & 0x2)), F_OF);
|
|
|
|
}
|
|
return (u8) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the RCL instruction and side effects.
|
|
****************************************************************************/
|
|
u16
|
|
rcl_word(u16 d, u8 s)
|
|
{
|
|
register unsigned int res, cnt, mask, cf;
|
|
|
|
res = d;
|
|
if ((cnt = s % 17) != 0) {
|
|
cf = (d >> (16 - cnt)) & 0x1;
|
|
res = (d << cnt) & 0xffff;
|
|
mask = (1 << (cnt - 1)) - 1;
|
|
res |= (d >> (17 - cnt)) & mask;
|
|
if (ACCESS_FLAG(F_CF)) {
|
|
res |= 1 << (cnt - 1);
|
|
}
|
|
CONDITIONAL_SET_FLAG(cf, F_CF);
|
|
CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 14) & 0x2)), F_OF);
|
|
}
|
|
return (u16) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the RCL instruction and side effects.
|
|
****************************************************************************/
|
|
u32
|
|
rcl_long(u32 d, u8 s)
|
|
{
|
|
register u32 res, cnt, mask, cf;
|
|
|
|
res = d;
|
|
if ((cnt = s % 33) != 0) {
|
|
cf = (d >> (32 - cnt)) & 0x1;
|
|
res = (d << cnt) & 0xffffffff;
|
|
mask = (1 << (cnt - 1)) - 1;
|
|
res |= (d >> (33 - cnt)) & mask;
|
|
if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
|
|
res |= 1 << (cnt - 1);
|
|
}
|
|
CONDITIONAL_SET_FLAG(cf, F_CF);
|
|
CONDITIONAL_SET_FLAG(cnt == 1 && XOR2(cf + ((res >> 30) & 0x2)), F_OF);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the RCR instruction and side effects.
|
|
****************************************************************************/
|
|
u8
|
|
rcr_byte(u8 d, u8 s)
|
|
{
|
|
u32 res, cnt;
|
|
u32 mask, cf, ocf = 0;
|
|
|
|
/* rotate right through carry */
|
|
/*
|
|
s is the rotate distance. It varies from 0 - 8.
|
|
d is the byte object rotated.
|
|
|
|
have
|
|
|
|
CF B_7 B_6 B_5 B_4 B_3 B_2 B_1 B_0
|
|
|
|
The new rotate is done mod 9, and given this,
|
|
for a rotation of n bits (mod 9) the new carry flag is
|
|
then located n bits from the LSB. The low part is
|
|
then shifted up cnt bits, and the high part is or'd
|
|
in. Using CAPS for new values, and lowercase for the
|
|
original values, this can be expressed as:
|
|
|
|
IF n > 0
|
|
1) CF <- b_(n-1)
|
|
2) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n)
|
|
3) B_(8-n) <- cf
|
|
4) B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0)
|
|
*/
|
|
res = d;
|
|
if ((cnt = s % 9) != 0) {
|
|
/* extract the new CARRY FLAG. */
|
|
/* CF <- b_(n-1) */
|
|
if (cnt == 1) {
|
|
cf = d & 0x1;
|
|
/* note hackery here. Access_flag(..) evaluates to either
|
|
0 if flag not set
|
|
non-zero if flag is set.
|
|
doing access_flag(..) != 0 casts that into either
|
|
0..1 in any representation of the flags register
|
|
(i.e. packed bit array or unpacked.)
|
|
*/
|
|
ocf = ACCESS_FLAG(F_CF) != 0;
|
|
}
|
|
else
|
|
cf = (d >> (cnt - 1)) & 0x1;
|
|
|
|
/* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_n */
|
|
/* note that the right hand side done by the mask
|
|
This is effectively done by shifting the
|
|
object to the right. The result must be masked,
|
|
in case the object came in and was treated
|
|
as a negative number. Needed??? */
|
|
|
|
mask = (1 << (8 - cnt)) - 1;
|
|
res = (d >> cnt) & mask;
|
|
|
|
/* now the high stuff which rotated around
|
|
into the positions B_cnt-2 .. B_0 */
|
|
/* B_(7) .. B_(8-(n-1)) <- b_(n-2) .. b_(0) */
|
|
/* shift it downward, 7-(n-2) = 9-n positions.
|
|
and mask off the result before or'ing in.
|
|
*/
|
|
res |= (d << (9 - cnt));
|
|
|
|
/* if the carry flag was set, or it in. */
|
|
if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
|
|
/* B_(8-n) <- cf */
|
|
res |= 1 << (8 - cnt);
|
|
}
|
|
/* set the new carry flag, based on the variable "cf" */
|
|
CONDITIONAL_SET_FLAG(cf, F_CF);
|
|
/* OVERFLOW is set *IFF* cnt==1, then it is the
|
|
xor of CF and the most significant bit. Blecck. */
|
|
/* parenthesized... */
|
|
if (cnt == 1) {
|
|
CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 6) & 0x2)), F_OF);
|
|
}
|
|
}
|
|
return (u8) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the RCR instruction and side effects.
|
|
****************************************************************************/
|
|
u16
|
|
rcr_word(u16 d, u8 s)
|
|
{
|
|
u32 res, cnt;
|
|
u32 mask, cf, ocf = 0;
|
|
|
|
/* rotate right through carry */
|
|
res = d;
|
|
if ((cnt = s % 17) != 0) {
|
|
if (cnt == 1) {
|
|
cf = d & 0x1;
|
|
ocf = ACCESS_FLAG(F_CF) != 0;
|
|
}
|
|
else
|
|
cf = (d >> (cnt - 1)) & 0x1;
|
|
mask = (1 << (16 - cnt)) - 1;
|
|
res = (d >> cnt) & mask;
|
|
res |= (d << (17 - cnt));
|
|
if (ACCESS_FLAG(F_CF)) {
|
|
res |= 1 << (16 - cnt);
|
|
}
|
|
CONDITIONAL_SET_FLAG(cf, F_CF);
|
|
if (cnt == 1) {
|
|
CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 14) & 0x2)), F_OF);
|
|
}
|
|
}
|
|
return (u16) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the RCR instruction and side effects.
|
|
****************************************************************************/
|
|
u32
|
|
rcr_long(u32 d, u8 s)
|
|
{
|
|
u32 res, cnt;
|
|
u32 mask, cf, ocf = 0;
|
|
|
|
/* rotate right through carry */
|
|
res = d;
|
|
if ((cnt = s % 33) != 0) {
|
|
if (cnt == 1) {
|
|
cf = d & 0x1;
|
|
ocf = ACCESS_FLAG(F_CF) != 0;
|
|
}
|
|
else
|
|
cf = (d >> (cnt - 1)) & 0x1;
|
|
mask = (1 << (32 - cnt)) - 1;
|
|
res = (d >> cnt) & mask;
|
|
if (cnt != 1)
|
|
res |= (d << (33 - cnt));
|
|
if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
|
|
res |= 1 << (32 - cnt);
|
|
}
|
|
CONDITIONAL_SET_FLAG(cf, F_CF);
|
|
if (cnt == 1) {
|
|
CONDITIONAL_SET_FLAG(XOR2(ocf + ((d >> 30) & 0x2)), F_OF);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the ROL instruction and side effects.
|
|
****************************************************************************/
|
|
u8
|
|
rol_byte(u8 d, u8 s)
|
|
{
|
|
register unsigned int res, cnt, mask;
|
|
|
|
/* rotate left */
|
|
/*
|
|
s is the rotate distance. It varies from 0 - 8.
|
|
d is the byte object rotated.
|
|
|
|
have
|
|
|
|
CF B_7 ... B_0
|
|
|
|
The new rotate is done mod 8.
|
|
Much simpler than the "rcl" or "rcr" operations.
|
|
|
|
IF n > 0
|
|
1) B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0)
|
|
2) B_(n-1) .. B_(0) <- b_(7) .. b_(8-n)
|
|
*/
|
|
res = d;
|
|
if ((cnt = s % 8) != 0) {
|
|
/* B_(7) .. B_(n) <- b_(8-(n+1)) .. b_(0) */
|
|
res = (d << cnt);
|
|
|
|
/* B_(n-1) .. B_(0) <- b_(7) .. b_(8-n) */
|
|
mask = (1 << cnt) - 1;
|
|
res |= (d >> (8 - cnt)) & mask;
|
|
|
|
/* set the new carry flag, Note that it is the low order
|
|
bit of the result!!! */
|
|
CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
|
|
/* OVERFLOW is set *IFF* s==1, then it is the
|
|
xor of CF and the most significant bit. Blecck. */
|
|
CONDITIONAL_SET_FLAG(s == 1 &&
|
|
XOR2((res & 0x1) + ((res >> 6) & 0x2)), F_OF);
|
|
}
|
|
if (s != 0) {
|
|
/* set the new carry flag, Note that it is the low order
|
|
bit of the result!!! */
|
|
CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
|
|
}
|
|
return (u8) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the ROL instruction and side effects.
|
|
****************************************************************************/
|
|
u16
|
|
rol_word(u16 d, u8 s)
|
|
{
|
|
register unsigned int res, cnt, mask;
|
|
|
|
res = d;
|
|
if ((cnt = s % 16) != 0) {
|
|
res = (d << cnt);
|
|
mask = (1 << cnt) - 1;
|
|
res |= (d >> (16 - cnt)) & mask;
|
|
CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
|
|
CONDITIONAL_SET_FLAG(s == 1 &&
|
|
XOR2((res & 0x1) + ((res >> 14) & 0x2)), F_OF);
|
|
}
|
|
if (s != 0) {
|
|
/* set the new carry flag, Note that it is the low order
|
|
bit of the result!!! */
|
|
CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
|
|
}
|
|
return (u16) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the ROL instruction and side effects.
|
|
****************************************************************************/
|
|
u32
|
|
rol_long(u32 d, u8 s)
|
|
{
|
|
register u32 res, cnt, mask;
|
|
|
|
res = d;
|
|
if ((cnt = s % 32) != 0) {
|
|
res = (d << cnt);
|
|
mask = (1 << cnt) - 1;
|
|
res |= (d >> (32 - cnt)) & mask;
|
|
CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
|
|
CONDITIONAL_SET_FLAG(s == 1 &&
|
|
XOR2((res & 0x1) + ((res >> 30) & 0x2)), F_OF);
|
|
}
|
|
if (s != 0) {
|
|
/* set the new carry flag, Note that it is the low order
|
|
bit of the result!!! */
|
|
CONDITIONAL_SET_FLAG(res & 0x1, F_CF);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the ROR instruction and side effects.
|
|
****************************************************************************/
|
|
u8
|
|
ror_byte(u8 d, u8 s)
|
|
{
|
|
register unsigned int res, cnt, mask;
|
|
|
|
/* rotate right */
|
|
/*
|
|
s is the rotate distance. It varies from 0 - 8.
|
|
d is the byte object rotated.
|
|
|
|
have
|
|
|
|
B_7 ... B_0
|
|
|
|
The rotate is done mod 8.
|
|
|
|
IF n > 0
|
|
1) B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n)
|
|
2) B_(7) .. B_(8-n) <- b_(n-1) .. b_(0)
|
|
*/
|
|
res = d;
|
|
if ((cnt = s % 8) != 0) { /* not a typo, do nada if cnt==0 */
|
|
/* B_(7) .. B_(8-n) <- b_(n-1) .. b_(0) */
|
|
res = (d << (8 - cnt));
|
|
|
|
/* B_(8-(n+1)) .. B_(0) <- b_(7) .. b_(n) */
|
|
mask = (1 << (8 - cnt)) - 1;
|
|
res |= (d >> (cnt)) & mask;
|
|
|
|
/* set the new carry flag, Note that it is the low order
|
|
bit of the result!!! */
|
|
CONDITIONAL_SET_FLAG(res & 0x80, F_CF);
|
|
/* OVERFLOW is set *IFF* s==1, then it is the
|
|
xor of the two most significant bits. Blecck. */
|
|
CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 6), F_OF);
|
|
}
|
|
else if (s != 0) {
|
|
/* set the new carry flag, Note that it is the low order
|
|
bit of the result!!! */
|
|
CONDITIONAL_SET_FLAG(res & 0x80, F_CF);
|
|
}
|
|
return (u8) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the ROR instruction and side effects.
|
|
****************************************************************************/
|
|
u16
|
|
ror_word(u16 d, u8 s)
|
|
{
|
|
register unsigned int res, cnt, mask;
|
|
|
|
res = d;
|
|
if ((cnt = s % 16) != 0) {
|
|
res = (d << (16 - cnt));
|
|
mask = (1 << (16 - cnt)) - 1;
|
|
res |= (d >> (cnt)) & mask;
|
|
CONDITIONAL_SET_FLAG(res & 0x8000, F_CF);
|
|
CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 14), F_OF);
|
|
}
|
|
else if (s != 0) {
|
|
/* set the new carry flag, Note that it is the low order
|
|
bit of the result!!! */
|
|
CONDITIONAL_SET_FLAG(res & 0x8000, F_CF);
|
|
}
|
|
return (u16) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the ROR instruction and side effects.
|
|
****************************************************************************/
|
|
u32
|
|
ror_long(u32 d, u8 s)
|
|
{
|
|
register u32 res, cnt, mask;
|
|
|
|
res = d;
|
|
if ((cnt = s % 32) != 0) {
|
|
res = (d << (32 - cnt));
|
|
mask = (1 << (32 - cnt)) - 1;
|
|
res |= (d >> (cnt)) & mask;
|
|
CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF);
|
|
CONDITIONAL_SET_FLAG(s == 1 && XOR2(res >> 30), F_OF);
|
|
}
|
|
else if (s != 0) {
|
|
/* set the new carry flag, Note that it is the low order
|
|
bit of the result!!! */
|
|
CONDITIONAL_SET_FLAG(res & 0x80000000, F_CF);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SHL instruction and side effects.
|
|
****************************************************************************/
|
|
u8
|
|
shl_byte(u8 d, u8 s)
|
|
{
|
|
unsigned int cnt, res, cf;
|
|
|
|
if (s < 8) {
|
|
cnt = s % 8;
|
|
|
|
/* last bit shifted out goes into carry flag */
|
|
if (cnt > 0) {
|
|
res = d << cnt;
|
|
cf = d & (1 << (8 - cnt));
|
|
CONDITIONAL_SET_FLAG(cf, 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);
|
|
}
|
|
else {
|
|
res = (u8) d;
|
|
}
|
|
|
|
if (cnt == 1) {
|
|
/* Needs simplification. */
|
|
CONDITIONAL_SET_FLAG((((res & 0x80) == 0x80) ^
|
|
(ACCESS_FLAG(F_CF) != 0)),
|
|
/* was (M.x86.R_FLG&F_CF)==F_CF)), */
|
|
F_OF);
|
|
}
|
|
else {
|
|
CLEAR_FLAG(F_OF);
|
|
}
|
|
}
|
|
else {
|
|
res = 0;
|
|
CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x80, F_CF);
|
|
CLEAR_FLAG(F_OF);
|
|
CLEAR_FLAG(F_SF);
|
|
SET_FLAG(F_PF);
|
|
SET_FLAG(F_ZF);
|
|
}
|
|
return (u8) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SHL instruction and side effects.
|
|
****************************************************************************/
|
|
u16
|
|
shl_word(u16 d, u8 s)
|
|
{
|
|
unsigned int cnt, res, cf;
|
|
|
|
if (s < 16) {
|
|
cnt = s % 16;
|
|
if (cnt > 0) {
|
|
res = d << cnt;
|
|
cf = d & (1 << (16 - cnt));
|
|
CONDITIONAL_SET_FLAG(cf, 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);
|
|
}
|
|
else {
|
|
res = (u16) d;
|
|
}
|
|
|
|
if (cnt == 1) {
|
|
CONDITIONAL_SET_FLAG((((res & 0x8000) == 0x8000) ^
|
|
(ACCESS_FLAG(F_CF) != 0)), F_OF);
|
|
}
|
|
else {
|
|
CLEAR_FLAG(F_OF);
|
|
}
|
|
}
|
|
else {
|
|
res = 0;
|
|
CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x8000, F_CF);
|
|
CLEAR_FLAG(F_OF);
|
|
CLEAR_FLAG(F_SF);
|
|
SET_FLAG(F_PF);
|
|
SET_FLAG(F_ZF);
|
|
}
|
|
return (u16) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SHL instruction and side effects.
|
|
****************************************************************************/
|
|
u32
|
|
shl_long(u32 d, u8 s)
|
|
{
|
|
unsigned int cnt, res, cf;
|
|
|
|
if (s < 32) {
|
|
cnt = s % 32;
|
|
if (cnt > 0) {
|
|
res = d << cnt;
|
|
cf = d & (1 << (32 - cnt));
|
|
CONDITIONAL_SET_FLAG(cf, 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);
|
|
}
|
|
else {
|
|
res = d;
|
|
}
|
|
if (cnt == 1) {
|
|
CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^
|
|
(ACCESS_FLAG(F_CF) != 0)), F_OF);
|
|
}
|
|
else {
|
|
CLEAR_FLAG(F_OF);
|
|
}
|
|
}
|
|
else {
|
|
res = 0;
|
|
CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x80000000, F_CF);
|
|
CLEAR_FLAG(F_OF);
|
|
CLEAR_FLAG(F_SF);
|
|
SET_FLAG(F_PF);
|
|
SET_FLAG(F_ZF);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SHR instruction and side effects.
|
|
****************************************************************************/
|
|
u8
|
|
shr_byte(u8 d, u8 s)
|
|
{
|
|
unsigned int cnt, res, cf;
|
|
|
|
if (s < 8) {
|
|
cnt = s % 8;
|
|
if (cnt > 0) {
|
|
cf = d & (1 << (cnt - 1));
|
|
res = d >> cnt;
|
|
CONDITIONAL_SET_FLAG(cf, 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);
|
|
}
|
|
else {
|
|
res = (u8) d;
|
|
}
|
|
|
|
if (cnt == 1) {
|
|
CONDITIONAL_SET_FLAG(XOR2(res >> 6), F_OF);
|
|
}
|
|
else {
|
|
CLEAR_FLAG(F_OF);
|
|
}
|
|
}
|
|
else {
|
|
res = 0;
|
|
CONDITIONAL_SET_FLAG((d >> (s - 1)) & 0x1, F_CF);
|
|
CLEAR_FLAG(F_OF);
|
|
CLEAR_FLAG(F_SF);
|
|
SET_FLAG(F_PF);
|
|
SET_FLAG(F_ZF);
|
|
}
|
|
return (u8) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SHR instruction and side effects.
|
|
****************************************************************************/
|
|
u16
|
|
shr_word(u16 d, u8 s)
|
|
{
|
|
unsigned int cnt, res, cf;
|
|
|
|
if (s < 16) {
|
|
cnt = s % 16;
|
|
if (cnt > 0) {
|
|
cf = d & (1 << (cnt - 1));
|
|
res = d >> cnt;
|
|
CONDITIONAL_SET_FLAG(cf, 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);
|
|
}
|
|
else {
|
|
res = d;
|
|
}
|
|
|
|
if (cnt == 1) {
|
|
CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF);
|
|
}
|
|
else {
|
|
CLEAR_FLAG(F_OF);
|
|
}
|
|
}
|
|
else {
|
|
res = 0;
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_OF);
|
|
SET_FLAG(F_ZF);
|
|
CLEAR_FLAG(F_SF);
|
|
CLEAR_FLAG(F_PF);
|
|
}
|
|
return (u16) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SHR instruction and side effects.
|
|
****************************************************************************/
|
|
u32
|
|
shr_long(u32 d, u8 s)
|
|
{
|
|
unsigned int cnt, res, cf;
|
|
|
|
if (s < 32) {
|
|
cnt = s % 32;
|
|
if (cnt > 0) {
|
|
cf = d & (1 << (cnt - 1));
|
|
res = d >> cnt;
|
|
CONDITIONAL_SET_FLAG(cf, 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);
|
|
}
|
|
else {
|
|
res = d;
|
|
}
|
|
if (cnt == 1) {
|
|
CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF);
|
|
}
|
|
else {
|
|
CLEAR_FLAG(F_OF);
|
|
}
|
|
}
|
|
else {
|
|
res = 0;
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_OF);
|
|
SET_FLAG(F_ZF);
|
|
CLEAR_FLAG(F_SF);
|
|
CLEAR_FLAG(F_PF);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SAR instruction and side effects.
|
|
****************************************************************************/
|
|
u8
|
|
sar_byte(u8 d, u8 s)
|
|
{
|
|
unsigned int cnt, res, cf, mask, sf;
|
|
|
|
res = d;
|
|
sf = d & 0x80;
|
|
cnt = s % 8;
|
|
if (cnt > 0 && cnt < 8) {
|
|
mask = (1 << (8 - cnt)) - 1;
|
|
cf = d & (1 << (cnt - 1));
|
|
res = (d >> cnt) & mask;
|
|
CONDITIONAL_SET_FLAG(cf, F_CF);
|
|
if (sf) {
|
|
res |= ~mask;
|
|
}
|
|
CONDITIONAL_SET_FLAG((res & 0xff) == 0, F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
|
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
|
|
}
|
|
else if (cnt >= 8) {
|
|
if (sf) {
|
|
res = 0xff;
|
|
SET_FLAG(F_CF);
|
|
CLEAR_FLAG(F_ZF);
|
|
SET_FLAG(F_SF);
|
|
SET_FLAG(F_PF);
|
|
}
|
|
else {
|
|
res = 0;
|
|
CLEAR_FLAG(F_CF);
|
|
SET_FLAG(F_ZF);
|
|
CLEAR_FLAG(F_SF);
|
|
CLEAR_FLAG(F_PF);
|
|
}
|
|
}
|
|
return (u8) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SAR instruction and side effects.
|
|
****************************************************************************/
|
|
u16
|
|
sar_word(u16 d, u8 s)
|
|
{
|
|
unsigned int cnt, res, cf, mask, sf;
|
|
|
|
sf = d & 0x8000;
|
|
cnt = s % 16;
|
|
res = d;
|
|
if (cnt > 0 && cnt < 16) {
|
|
mask = (1 << (16 - cnt)) - 1;
|
|
cf = d & (1 << (cnt - 1));
|
|
res = (d >> cnt) & mask;
|
|
CONDITIONAL_SET_FLAG(cf, F_CF);
|
|
if (sf) {
|
|
res |= ~mask;
|
|
}
|
|
CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
|
|
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
|
}
|
|
else if (cnt >= 16) {
|
|
if (sf) {
|
|
res = 0xffff;
|
|
SET_FLAG(F_CF);
|
|
CLEAR_FLAG(F_ZF);
|
|
SET_FLAG(F_SF);
|
|
SET_FLAG(F_PF);
|
|
}
|
|
else {
|
|
res = 0;
|
|
CLEAR_FLAG(F_CF);
|
|
SET_FLAG(F_ZF);
|
|
CLEAR_FLAG(F_SF);
|
|
CLEAR_FLAG(F_PF);
|
|
}
|
|
}
|
|
return (u16) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SAR instruction and side effects.
|
|
****************************************************************************/
|
|
u32
|
|
sar_long(u32 d, u8 s)
|
|
{
|
|
u32 cnt, res, cf, mask, sf;
|
|
|
|
sf = d & 0x80000000;
|
|
cnt = s % 32;
|
|
res = d;
|
|
if (cnt > 0 && cnt < 32) {
|
|
mask = (1 << (32 - cnt)) - 1;
|
|
cf = d & (1 << (cnt - 1));
|
|
res = (d >> cnt) & mask;
|
|
CONDITIONAL_SET_FLAG(cf, F_CF);
|
|
if (sf) {
|
|
res |= ~mask;
|
|
}
|
|
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 0, F_ZF);
|
|
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
|
}
|
|
else if (cnt >= 32) {
|
|
if (sf) {
|
|
res = 0xffffffff;
|
|
SET_FLAG(F_CF);
|
|
CLEAR_FLAG(F_ZF);
|
|
SET_FLAG(F_SF);
|
|
SET_FLAG(F_PF);
|
|
}
|
|
else {
|
|
res = 0;
|
|
CLEAR_FLAG(F_CF);
|
|
SET_FLAG(F_ZF);
|
|
CLEAR_FLAG(F_SF);
|
|
CLEAR_FLAG(F_PF);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SHLD instruction and side effects.
|
|
****************************************************************************/
|
|
u16
|
|
shld_word(u16 d, u16 fill, u8 s)
|
|
{
|
|
unsigned int cnt, res, cf;
|
|
|
|
if (s < 16) {
|
|
cnt = s % 16;
|
|
if (cnt > 0) {
|
|
res = (d << cnt) | (fill >> (16 - cnt));
|
|
cf = d & (1 << (16 - cnt));
|
|
CONDITIONAL_SET_FLAG(cf, 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);
|
|
}
|
|
else {
|
|
res = d;
|
|
}
|
|
if (cnt == 1) {
|
|
CONDITIONAL_SET_FLAG((((res & 0x8000) == 0x8000) ^
|
|
(ACCESS_FLAG(F_CF) != 0)), F_OF);
|
|
}
|
|
else {
|
|
CLEAR_FLAG(F_OF);
|
|
}
|
|
}
|
|
else {
|
|
res = 0;
|
|
CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x8000, F_CF);
|
|
CLEAR_FLAG(F_OF);
|
|
CLEAR_FLAG(F_SF);
|
|
SET_FLAG(F_PF);
|
|
SET_FLAG(F_ZF);
|
|
}
|
|
return (u16) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SHLD instruction and side effects.
|
|
****************************************************************************/
|
|
u32
|
|
shld_long(u32 d, u32 fill, u8 s)
|
|
{
|
|
unsigned int cnt, res, cf;
|
|
|
|
if (s < 32) {
|
|
cnt = s % 32;
|
|
if (cnt > 0) {
|
|
res = (d << cnt) | (fill >> (32 - cnt));
|
|
cf = d & (1 << (32 - cnt));
|
|
CONDITIONAL_SET_FLAG(cf, 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);
|
|
}
|
|
else {
|
|
res = d;
|
|
}
|
|
if (cnt == 1) {
|
|
CONDITIONAL_SET_FLAG((((res & 0x80000000) == 0x80000000) ^
|
|
(ACCESS_FLAG(F_CF) != 0)), F_OF);
|
|
}
|
|
else {
|
|
CLEAR_FLAG(F_OF);
|
|
}
|
|
}
|
|
else {
|
|
res = 0;
|
|
CONDITIONAL_SET_FLAG((d << (s - 1)) & 0x80000000, F_CF);
|
|
CLEAR_FLAG(F_OF);
|
|
CLEAR_FLAG(F_SF);
|
|
SET_FLAG(F_PF);
|
|
SET_FLAG(F_ZF);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SHRD instruction and side effects.
|
|
****************************************************************************/
|
|
u16
|
|
shrd_word(u16 d, u16 fill, u8 s)
|
|
{
|
|
unsigned int cnt, res, cf;
|
|
|
|
if (s < 16) {
|
|
cnt = s % 16;
|
|
if (cnt > 0) {
|
|
cf = d & (1 << (cnt - 1));
|
|
res = (d >> cnt) | (fill << (16 - cnt));
|
|
CONDITIONAL_SET_FLAG(cf, 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);
|
|
}
|
|
else {
|
|
res = d;
|
|
}
|
|
|
|
if (cnt == 1) {
|
|
CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF);
|
|
}
|
|
else {
|
|
CLEAR_FLAG(F_OF);
|
|
}
|
|
}
|
|
else {
|
|
res = 0;
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_OF);
|
|
SET_FLAG(F_ZF);
|
|
CLEAR_FLAG(F_SF);
|
|
CLEAR_FLAG(F_PF);
|
|
}
|
|
return (u16) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SHRD instruction and side effects.
|
|
****************************************************************************/
|
|
u32
|
|
shrd_long(u32 d, u32 fill, u8 s)
|
|
{
|
|
unsigned int cnt, res, cf;
|
|
|
|
if (s < 32) {
|
|
cnt = s % 32;
|
|
if (cnt > 0) {
|
|
cf = d & (1 << (cnt - 1));
|
|
res = (d >> cnt) | (fill << (32 - cnt));
|
|
CONDITIONAL_SET_FLAG(cf, 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);
|
|
}
|
|
else {
|
|
res = d;
|
|
}
|
|
if (cnt == 1) {
|
|
CONDITIONAL_SET_FLAG(XOR2(res >> 30), F_OF);
|
|
}
|
|
else {
|
|
CLEAR_FLAG(F_OF);
|
|
}
|
|
}
|
|
else {
|
|
res = 0;
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_OF);
|
|
SET_FLAG(F_ZF);
|
|
CLEAR_FLAG(F_SF);
|
|
CLEAR_FLAG(F_PF);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SBB instruction and side effects.
|
|
****************************************************************************/
|
|
u8
|
|
sbb_byte(u8 d, u8 s)
|
|
{
|
|
register u32 res; /* all operands in native machine order */
|
|
register u32 bc;
|
|
|
|
if (ACCESS_FLAG(F_CF))
|
|
res = d - s - 1;
|
|
else
|
|
res = d - s;
|
|
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 (u8) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SBB instruction and side effects.
|
|
****************************************************************************/
|
|
u16
|
|
sbb_word(u16 d, u16 s)
|
|
{
|
|
register u32 res; /* all operands in native machine order */
|
|
register u32 bc;
|
|
|
|
if (ACCESS_FLAG(F_CF))
|
|
res = d - s - 1;
|
|
else
|
|
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);
|
|
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
|
return (u16) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SBB instruction and side effects.
|
|
****************************************************************************/
|
|
u32
|
|
sbb_long(u32 d, u32 s)
|
|
{
|
|
register u32 res; /* all operands in native machine order */
|
|
register u32 bc;
|
|
|
|
if (ACCESS_FLAG(F_CF))
|
|
res = d - s - 1;
|
|
else
|
|
res = d - s;
|
|
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
|
|
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 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 & 0x80000000, F_CF);
|
|
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
|
|
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SUB instruction and side effects.
|
|
****************************************************************************/
|
|
u8
|
|
sub_byte(u8 d, u8 s)
|
|
{
|
|
register u32 res; /* all operands in native machine order */
|
|
register u32 bc;
|
|
|
|
res = d - s;
|
|
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 (u8) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SUB instruction and side effects.
|
|
****************************************************************************/
|
|
u16
|
|
sub_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);
|
|
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
|
return (u16) res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SUB instruction and side effects.
|
|
****************************************************************************/
|
|
u32
|
|
sub_long(u32 d, u32 s)
|
|
{
|
|
register u32 res; /* all operands in native machine order */
|
|
register u32 bc;
|
|
|
|
res = d - s;
|
|
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
|
|
CONDITIONAL_SET_FLAG((res & 0xffffffff) == 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 & 0x80000000, F_CF);
|
|
CONDITIONAL_SET_FLAG(XOR2(bc >> 30), F_OF);
|
|
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the TEST instruction and side effects.
|
|
****************************************************************************/
|
|
void
|
|
test_byte(u8 d, u8 s)
|
|
{
|
|
register u32 res; /* all operands in native machine order */
|
|
|
|
res = d & s;
|
|
|
|
CLEAR_FLAG(F_OF);
|
|
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
|
|
CONDITIONAL_SET_FLAG(res == 0, F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
|
/* AF == don't care */
|
|
CLEAR_FLAG(F_CF);
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the TEST instruction and side effects.
|
|
****************************************************************************/
|
|
void
|
|
test_word(u16 d, u16 s)
|
|
{
|
|
register u32 res; /* all operands in native machine order */
|
|
|
|
res = d & s;
|
|
|
|
CLEAR_FLAG(F_OF);
|
|
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
|
|
CONDITIONAL_SET_FLAG(res == 0, F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
|
/* AF == don't care */
|
|
CLEAR_FLAG(F_CF);
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the TEST instruction and side effects.
|
|
****************************************************************************/
|
|
void
|
|
test_long(u32 d, u32 s)
|
|
{
|
|
register u32 res; /* all operands in native machine order */
|
|
|
|
res = d & s;
|
|
|
|
CLEAR_FLAG(F_OF);
|
|
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
|
|
CONDITIONAL_SET_FLAG(res == 0, F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
|
/* AF == don't care */
|
|
CLEAR_FLAG(F_CF);
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the XOR instruction and side effects.
|
|
****************************************************************************/
|
|
u8
|
|
xor_byte(u8 d, u8 s)
|
|
{
|
|
register u8 res; /* all operands in native machine order */
|
|
|
|
res = d ^ s;
|
|
CLEAR_FLAG(F_OF);
|
|
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
|
|
CONDITIONAL_SET_FLAG(res == 0, F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res), F_PF);
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_AF);
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the XOR instruction and side effects.
|
|
****************************************************************************/
|
|
u16
|
|
xor_word(u16 d, u16 s)
|
|
{
|
|
register u16 res; /* all operands in native machine order */
|
|
|
|
res = d ^ s;
|
|
CLEAR_FLAG(F_OF);
|
|
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
|
|
CONDITIONAL_SET_FLAG(res == 0, F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_AF);
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the XOR instruction and side effects.
|
|
****************************************************************************/
|
|
u32
|
|
xor_long(u32 d, u32 s)
|
|
{
|
|
register u32 res; /* all operands in native machine order */
|
|
|
|
res = d ^ s;
|
|
CLEAR_FLAG(F_OF);
|
|
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
|
|
CONDITIONAL_SET_FLAG(res == 0, F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_AF);
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the IMUL instruction and side effects.
|
|
****************************************************************************/
|
|
void
|
|
imul_byte(u8 s)
|
|
{
|
|
s16 res = (s16) ((s8) M.x86.R_AL * (s8) s);
|
|
|
|
M.x86.R_AX = res;
|
|
if (((M.x86.R_AL & 0x80) == 0 && M.x86.R_AH == 0x00) ||
|
|
((M.x86.R_AL & 0x80) != 0 && M.x86.R_AH == 0xFF)) {
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_OF);
|
|
}
|
|
else {
|
|
SET_FLAG(F_CF);
|
|
SET_FLAG(F_OF);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the IMUL instruction and side effects.
|
|
****************************************************************************/
|
|
void
|
|
imul_word(u16 s)
|
|
{
|
|
s32 res = (s16) M.x86.R_AX * (s16) s;
|
|
|
|
M.x86.R_AX = (u16) res;
|
|
M.x86.R_DX = (u16) (res >> 16);
|
|
if (((M.x86.R_AX & 0x8000) == 0 && M.x86.R_DX == 0x00) ||
|
|
((M.x86.R_AX & 0x8000) != 0 && M.x86.R_DX == 0xFF)) {
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_OF);
|
|
}
|
|
else {
|
|
SET_FLAG(F_CF);
|
|
SET_FLAG(F_OF);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the IMUL instruction and side effects.
|
|
****************************************************************************/
|
|
void
|
|
imul_long_direct(u32 * res_lo, u32 * res_hi, u32 d, u32 s)
|
|
{
|
|
#ifdef __HAS_LONG_LONG__
|
|
s64 res = (s64) (s32) d * (s32) s;
|
|
|
|
*res_lo = (u32) res;
|
|
*res_hi = (u32) (res >> 32);
|
|
#else
|
|
u32 d_lo, d_hi, d_sign;
|
|
u32 s_lo, s_hi, s_sign;
|
|
u32 rlo_lo, rlo_hi, rhi_lo;
|
|
|
|
if ((d_sign = d & 0x80000000) != 0)
|
|
d = -d;
|
|
d_lo = d & 0xFFFF;
|
|
d_hi = d >> 16;
|
|
if ((s_sign = s & 0x80000000) != 0)
|
|
s = -s;
|
|
s_lo = s & 0xFFFF;
|
|
s_hi = s >> 16;
|
|
rlo_lo = d_lo * s_lo;
|
|
rlo_hi = (d_hi * s_lo + d_lo * s_hi) + (rlo_lo >> 16);
|
|
rhi_lo = d_hi * s_hi + (rlo_hi >> 16);
|
|
*res_lo = (rlo_hi << 16) | (rlo_lo & 0xFFFF);
|
|
*res_hi = rhi_lo;
|
|
if (d_sign != s_sign) {
|
|
d = ~*res_lo;
|
|
s = (((d & 0xFFFF) + 1) >> 16) + (d >> 16);
|
|
*res_lo = ~*res_lo + 1;
|
|
*res_hi = ~*res_hi + (s >> 16);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the IMUL instruction and side effects.
|
|
****************************************************************************/
|
|
void
|
|
imul_long(u32 s)
|
|
{
|
|
imul_long_direct(&M.x86.R_EAX, &M.x86.R_EDX, M.x86.R_EAX, s);
|
|
if (((M.x86.R_EAX & 0x80000000) == 0 && M.x86.R_EDX == 0x00) ||
|
|
((M.x86.R_EAX & 0x80000000) != 0 && M.x86.R_EDX == 0xFF)) {
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_OF);
|
|
}
|
|
else {
|
|
SET_FLAG(F_CF);
|
|
SET_FLAG(F_OF);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the MUL instruction and side effects.
|
|
****************************************************************************/
|
|
void
|
|
mul_byte(u8 s)
|
|
{
|
|
u16 res = (u16) (M.x86.R_AL * s);
|
|
|
|
M.x86.R_AX = res;
|
|
if (M.x86.R_AH == 0) {
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_OF);
|
|
}
|
|
else {
|
|
SET_FLAG(F_CF);
|
|
SET_FLAG(F_OF);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the MUL instruction and side effects.
|
|
****************************************************************************/
|
|
void
|
|
mul_word(u16 s)
|
|
{
|
|
u32 res = M.x86.R_AX * s;
|
|
|
|
M.x86.R_AX = (u16) res;
|
|
M.x86.R_DX = (u16) (res >> 16);
|
|
if (M.x86.R_DX == 0) {
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_OF);
|
|
}
|
|
else {
|
|
SET_FLAG(F_CF);
|
|
SET_FLAG(F_OF);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the MUL instruction and side effects.
|
|
****************************************************************************/
|
|
void
|
|
mul_long(u32 s)
|
|
{
|
|
#ifdef __HAS_LONG_LONG__
|
|
u64 res = (u64) M.x86.R_EAX * s;
|
|
|
|
M.x86.R_EAX = (u32) res;
|
|
M.x86.R_EDX = (u32) (res >> 32);
|
|
#else
|
|
u32 a, a_lo, a_hi;
|
|
u32 s_lo, s_hi;
|
|
u32 rlo_lo, rlo_hi, rhi_lo;
|
|
|
|
a = M.x86.R_EAX;
|
|
a_lo = a & 0xFFFF;
|
|
a_hi = a >> 16;
|
|
s_lo = s & 0xFFFF;
|
|
s_hi = s >> 16;
|
|
rlo_lo = a_lo * s_lo;
|
|
rlo_hi = (a_hi * s_lo + a_lo * s_hi) + (rlo_lo >> 16);
|
|
rhi_lo = a_hi * s_hi + (rlo_hi >> 16);
|
|
M.x86.R_EAX = (rlo_hi << 16) | (rlo_lo & 0xFFFF);
|
|
M.x86.R_EDX = rhi_lo;
|
|
#endif
|
|
|
|
if (M.x86.R_EDX == 0) {
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_OF);
|
|
}
|
|
else {
|
|
SET_FLAG(F_CF);
|
|
SET_FLAG(F_OF);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the IDIV instruction and side effects.
|
|
****************************************************************************/
|
|
void
|
|
idiv_byte(u8 s)
|
|
{
|
|
s32 dvd, div, mod;
|
|
|
|
dvd = (s16) M.x86.R_AX;
|
|
if (s == 0) {
|
|
x86emu_intr_raise(0);
|
|
return;
|
|
}
|
|
div = dvd / (s8) s;
|
|
mod = dvd % (s8) s;
|
|
if (abs(div) > 0x7f) {
|
|
x86emu_intr_raise(0);
|
|
return;
|
|
}
|
|
M.x86.R_AL = (s8) div;
|
|
M.x86.R_AH = (s8) mod;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the IDIV instruction and side effects.
|
|
****************************************************************************/
|
|
void
|
|
idiv_word(u16 s)
|
|
{
|
|
s32 dvd, div, mod;
|
|
|
|
dvd = (((s32) M.x86.R_DX) << 16) | M.x86.R_AX;
|
|
if (s == 0) {
|
|
x86emu_intr_raise(0);
|
|
return;
|
|
}
|
|
div = dvd / (s16) s;
|
|
mod = dvd % (s16) s;
|
|
if (abs(div) > 0x7fff) {
|
|
x86emu_intr_raise(0);
|
|
return;
|
|
}
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_SF);
|
|
CONDITIONAL_SET_FLAG(div == 0, F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
|
|
|
|
M.x86.R_AX = (u16) div;
|
|
M.x86.R_DX = (u16) mod;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the IDIV instruction and side effects.
|
|
****************************************************************************/
|
|
void
|
|
idiv_long(u32 s)
|
|
{
|
|
#ifdef __HAS_LONG_LONG__
|
|
s64 dvd, div, mod;
|
|
|
|
dvd = (((s64) M.x86.R_EDX) << 32) | M.x86.R_EAX;
|
|
if (s == 0) {
|
|
x86emu_intr_raise(0);
|
|
return;
|
|
}
|
|
div = dvd / (s32) s;
|
|
mod = dvd % (s32) s;
|
|
if (abs(div) > 0x7fffffff) {
|
|
x86emu_intr_raise(0);
|
|
return;
|
|
}
|
|
#else
|
|
s32 div = 0, mod;
|
|
s32 h_dvd = M.x86.R_EDX;
|
|
u32 l_dvd = M.x86.R_EAX;
|
|
u32 abs_s = s & 0x7FFFFFFF;
|
|
u32 abs_h_dvd = h_dvd & 0x7FFFFFFF;
|
|
u32 h_s = abs_s >> 1;
|
|
u32 l_s = abs_s << 31;
|
|
int counter = 31;
|
|
int carry;
|
|
|
|
if (s == 0) {
|
|
x86emu_intr_raise(0);
|
|
return;
|
|
}
|
|
do {
|
|
div <<= 1;
|
|
carry = (l_dvd >= l_s) ? 0 : 1;
|
|
|
|
if (abs_h_dvd < (h_s + carry)) {
|
|
h_s >>= 1;
|
|
l_s = abs_s << (--counter);
|
|
continue;
|
|
}
|
|
else {
|
|
abs_h_dvd -= (h_s + carry);
|
|
l_dvd = carry ? ((0xFFFFFFFF - l_s) + l_dvd + 1)
|
|
: (l_dvd - l_s);
|
|
h_s >>= 1;
|
|
l_s = abs_s << (--counter);
|
|
div |= 1;
|
|
continue;
|
|
}
|
|
|
|
} while (counter > -1);
|
|
/* overflow */
|
|
if (abs_h_dvd || (l_dvd > abs_s)) {
|
|
x86emu_intr_raise(0);
|
|
return;
|
|
}
|
|
/* sign */
|
|
div |= ((h_dvd & 0x10000000) ^ (s & 0x10000000));
|
|
mod = l_dvd;
|
|
|
|
#endif
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_AF);
|
|
CLEAR_FLAG(F_SF);
|
|
SET_FLAG(F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
|
|
|
|
M.x86.R_EAX = (u32) div;
|
|
M.x86.R_EDX = (u32) mod;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the DIV instruction and side effects.
|
|
****************************************************************************/
|
|
void
|
|
div_byte(u8 s)
|
|
{
|
|
u32 dvd, div, mod;
|
|
|
|
dvd = M.x86.R_AX;
|
|
if (s == 0) {
|
|
x86emu_intr_raise(0);
|
|
return;
|
|
}
|
|
div = dvd / (u8) s;
|
|
mod = dvd % (u8) s;
|
|
if (abs(div) > 0xff) {
|
|
x86emu_intr_raise(0);
|
|
return;
|
|
}
|
|
M.x86.R_AL = (u8) div;
|
|
M.x86.R_AH = (u8) mod;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the DIV instruction and side effects.
|
|
****************************************************************************/
|
|
void
|
|
div_word(u16 s)
|
|
{
|
|
u32 dvd, div, mod;
|
|
|
|
dvd = (((u32) M.x86.R_DX) << 16) | M.x86.R_AX;
|
|
if (s == 0) {
|
|
x86emu_intr_raise(0);
|
|
return;
|
|
}
|
|
div = dvd / (u16) s;
|
|
mod = dvd % (u16) s;
|
|
if (abs(div) > 0xffff) {
|
|
x86emu_intr_raise(0);
|
|
return;
|
|
}
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_SF);
|
|
CONDITIONAL_SET_FLAG(div == 0, F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
|
|
|
|
M.x86.R_AX = (u16) div;
|
|
M.x86.R_DX = (u16) mod;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the DIV instruction and side effects.
|
|
****************************************************************************/
|
|
void
|
|
div_long(u32 s)
|
|
{
|
|
#ifdef __HAS_LONG_LONG__
|
|
u64 dvd, div, mod;
|
|
|
|
dvd = (((u64) M.x86.R_EDX) << 32) | M.x86.R_EAX;
|
|
if (s == 0) {
|
|
x86emu_intr_raise(0);
|
|
return;
|
|
}
|
|
div = dvd / (u32) s;
|
|
mod = dvd % (u32) s;
|
|
if (abs(div) > 0xffffffff) {
|
|
x86emu_intr_raise(0);
|
|
return;
|
|
}
|
|
#else
|
|
s32 div = 0, mod;
|
|
s32 h_dvd = M.x86.R_EDX;
|
|
u32 l_dvd = M.x86.R_EAX;
|
|
|
|
u32 h_s = s;
|
|
u32 l_s = 0;
|
|
int counter = 32;
|
|
int carry;
|
|
|
|
if (s == 0) {
|
|
x86emu_intr_raise(0);
|
|
return;
|
|
}
|
|
do {
|
|
div <<= 1;
|
|
carry = (l_dvd >= l_s) ? 0 : 1;
|
|
|
|
if (h_dvd < (h_s + carry)) {
|
|
h_s >>= 1;
|
|
l_s = s << (--counter);
|
|
continue;
|
|
}
|
|
else {
|
|
h_dvd -= (h_s + carry);
|
|
l_dvd = carry ? ((0xFFFFFFFF - l_s) + l_dvd + 1)
|
|
: (l_dvd - l_s);
|
|
h_s >>= 1;
|
|
l_s = s << (--counter);
|
|
div |= 1;
|
|
continue;
|
|
}
|
|
|
|
} while (counter > -1);
|
|
/* overflow */
|
|
if (h_dvd || (l_dvd > s)) {
|
|
x86emu_intr_raise(0);
|
|
return;
|
|
}
|
|
mod = l_dvd;
|
|
#endif
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_AF);
|
|
CLEAR_FLAG(F_SF);
|
|
SET_FLAG(F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(mod & 0xff), F_PF);
|
|
|
|
M.x86.R_EAX = (u32) div;
|
|
M.x86.R_EDX = (u32) mod;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the IN string instruction and side effects.
|
|
****************************************************************************/
|
|
void
|
|
ins(int size)
|
|
{
|
|
int inc = size;
|
|
|
|
if (ACCESS_FLAG(F_DF)) {
|
|
inc = -size;
|
|
}
|
|
if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
|
|
/* don't care whether REPE or REPNE */
|
|
/* in until CX is ZERO. */
|
|
u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ?
|
|
M.x86.R_ECX : M.x86.R_CX);
|
|
switch (size) {
|
|
case 1:
|
|
while (count--) {
|
|
store_data_byte_abs(M.x86.R_ES, M.x86.R_DI,
|
|
(*sys_inb) (M.x86.R_DX));
|
|
M.x86.R_DI += inc;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
while (count--) {
|
|
store_data_word_abs(M.x86.R_ES, M.x86.R_DI,
|
|
(*sys_inw) (M.x86.R_DX));
|
|
M.x86.R_DI += inc;
|
|
}
|
|
break;
|
|
case 4:
|
|
while (count--) {
|
|
store_data_long_abs(M.x86.R_ES, M.x86.R_DI,
|
|
(*sys_inl) (M.x86.R_DX));
|
|
M.x86.R_DI += inc;
|
|
break;
|
|
}
|
|
}
|
|
M.x86.R_CX = 0;
|
|
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
|
|
M.x86.R_ECX = 0;
|
|
}
|
|
M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
|
|
}
|
|
else {
|
|
switch (size) {
|
|
case 1:
|
|
store_data_byte_abs(M.x86.R_ES, M.x86.R_DI,
|
|
(*sys_inb) (M.x86.R_DX));
|
|
break;
|
|
case 2:
|
|
store_data_word_abs(M.x86.R_ES, M.x86.R_DI,
|
|
(*sys_inw) (M.x86.R_DX));
|
|
break;
|
|
case 4:
|
|
store_data_long_abs(M.x86.R_ES, M.x86.R_DI,
|
|
(*sys_inl) (M.x86.R_DX));
|
|
break;
|
|
}
|
|
M.x86.R_DI += inc;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the OUT string instruction and side effects.
|
|
****************************************************************************/
|
|
void
|
|
outs(int size)
|
|
{
|
|
int inc = size;
|
|
|
|
if (ACCESS_FLAG(F_DF)) {
|
|
inc = -size;
|
|
}
|
|
if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) {
|
|
/* don't care whether REPE or REPNE */
|
|
/* out until CX is ZERO. */
|
|
u32 count = ((M.x86.mode & SYSMODE_PREFIX_DATA) ?
|
|
M.x86.R_ECX : M.x86.R_CX);
|
|
switch (size) {
|
|
case 1:
|
|
while (count--) {
|
|
(*sys_outb) (M.x86.R_DX,
|
|
fetch_data_byte_abs(M.x86.R_ES, M.x86.R_SI));
|
|
M.x86.R_SI += inc;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
while (count--) {
|
|
(*sys_outw) (M.x86.R_DX,
|
|
fetch_data_word_abs(M.x86.R_ES, M.x86.R_SI));
|
|
M.x86.R_SI += inc;
|
|
}
|
|
break;
|
|
case 4:
|
|
while (count--) {
|
|
(*sys_outl) (M.x86.R_DX,
|
|
fetch_data_long_abs(M.x86.R_ES, M.x86.R_SI));
|
|
M.x86.R_SI += inc;
|
|
break;
|
|
}
|
|
}
|
|
M.x86.R_CX = 0;
|
|
if (M.x86.mode & SYSMODE_PREFIX_DATA) {
|
|
M.x86.R_ECX = 0;
|
|
}
|
|
M.x86.mode &= ~(SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE);
|
|
}
|
|
else {
|
|
switch (size) {
|
|
case 1:
|
|
(*sys_outb) (M.x86.R_DX,
|
|
fetch_data_byte_abs(M.x86.R_ES, M.x86.R_SI));
|
|
break;
|
|
case 2:
|
|
(*sys_outw) (M.x86.R_DX,
|
|
fetch_data_word_abs(M.x86.R_ES, M.x86.R_SI));
|
|
break;
|
|
case 4:
|
|
(*sys_outl) (M.x86.R_DX,
|
|
fetch_data_long_abs(M.x86.R_ES, M.x86.R_SI));
|
|
break;
|
|
}
|
|
M.x86.R_SI += inc;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
PARAMETERS:
|
|
addr - Address to fetch word from
|
|
|
|
REMARKS:
|
|
Fetches a word from emulator memory using an absolute address.
|
|
****************************************************************************/
|
|
u16
|
|
mem_access_word(int addr)
|
|
{
|
|
DB(if (CHECK_MEM_ACCESS())
|
|
x86emu_check_mem_access(addr);)
|
|
return (*sys_rdw) (addr);
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Pushes a word onto the stack.
|
|
|
|
NOTE: Do not inline this, as (*sys_wrX) is already inline!
|
|
****************************************************************************/
|
|
void
|
|
push_word(u16 w)
|
|
{
|
|
DB(if (CHECK_SP_ACCESS())
|
|
x86emu_check_sp_access();)
|
|
M.x86.R_SP -= 2;
|
|
(*sys_wrw) (((u32) M.x86.R_SS << 4) + M.x86.R_SP, w);
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Pushes a long onto the stack.
|
|
|
|
NOTE: Do not inline this, as (*sys_wrX) is already inline!
|
|
****************************************************************************/
|
|
void
|
|
push_long(u32 w)
|
|
{
|
|
DB(if (CHECK_SP_ACCESS())
|
|
x86emu_check_sp_access();)
|
|
M.x86.R_SP -= 4;
|
|
(*sys_wrl) (((u32) M.x86.R_SS << 4) + M.x86.R_SP, w);
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Pops a word from the stack.
|
|
|
|
NOTE: Do not inline this, as (*sys_rdX) is already inline!
|
|
****************************************************************************/
|
|
u16
|
|
pop_word(void)
|
|
{
|
|
register u16 res;
|
|
|
|
DB(if (CHECK_SP_ACCESS())
|
|
x86emu_check_sp_access();)
|
|
res = (*sys_rdw) (((u32) M.x86.R_SS << 4) + M.x86.R_SP);
|
|
M.x86.R_SP += 2;
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Pops a long from the stack.
|
|
|
|
NOTE: Do not inline this, as (*sys_rdX) is already inline!
|
|
****************************************************************************/
|
|
u32
|
|
pop_long(void)
|
|
{
|
|
register u32 res;
|
|
|
|
DB(if (CHECK_SP_ACCESS())
|
|
x86emu_check_sp_access();)
|
|
res = (*sys_rdl) (((u32) M.x86.R_SS << 4) + M.x86.R_SP);
|
|
M.x86.R_SP += 4;
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
CPUID takes EAX/ECX as inputs, writes EAX/EBX/ECX/EDX as output
|
|
****************************************************************************/
|
|
void
|
|
cpuid(void)
|
|
{
|
|
u32 feature = M.x86.R_EAX;
|
|
|
|
#ifdef X86EMU_HAS_HW_CPUID
|
|
/* If the platform allows it, we will base our values on the real
|
|
* results from the CPUID instruction. We limit support to the
|
|
* first two features, and the results of those are sanitized.
|
|
*/
|
|
if (feature <= 1)
|
|
hw_cpuid(&M.x86.R_EAX, &M.x86.R_EBX, &M.x86.R_ECX, &M.x86.R_EDX);
|
|
#endif
|
|
|
|
switch (feature) {
|
|
case 0:
|
|
/* Regardless if we have real data from the hardware, the emulator
|
|
* will only support up to feature 1, which we set in register EAX.
|
|
* Registers EBX:EDX:ECX contain a string identifying the CPU.
|
|
*/
|
|
M.x86.R_EAX = 1;
|
|
#ifndef X86EMU_HAS_HW_CPUID
|
|
/* EBX:EDX:ECX = "GenuineIntel" */
|
|
M.x86.R_EBX = 0x756e6547;
|
|
M.x86.R_EDX = 0x49656e69;
|
|
M.x86.R_ECX = 0x6c65746e;
|
|
#endif
|
|
break;
|
|
case 1:
|
|
#ifndef X86EMU_HAS_HW_CPUID
|
|
/* If we don't have x86 compatible hardware, we return values from an
|
|
* Intel 486dx4; which was one of the first processors to have CPUID.
|
|
*/
|
|
M.x86.R_EAX = 0x00000480;
|
|
M.x86.R_EBX = 0x00000000;
|
|
M.x86.R_ECX = 0x00000000;
|
|
M.x86.R_EDX = 0x00000002; /* VME */
|
|
#else
|
|
/* In the case that we have hardware CPUID instruction, we make sure
|
|
* that the features reported are limited to TSC and VME.
|
|
*/
|
|
M.x86.R_EDX &= 0x00000012;
|
|
#endif
|
|
break;
|
|
default:
|
|
/* Finally, we don't support any additional features. Most CPUs
|
|
* return all zeros when queried for invalid or unsupported feature
|
|
* numbers.
|
|
*/
|
|
M.x86.R_EAX = 0;
|
|
M.x86.R_EBX = 0;
|
|
M.x86.R_ECX = 0;
|
|
M.x86.R_EDX = 0;
|
|
break;
|
|
}
|
|
}
|