mirror of
https://github.com/ptitSeb/box64.git
synced 2025-08-28 09:33:48 +02:00
1605 lines
40 KiB
C
1605 lines
40 KiB
C
// Based on Realmode X86 Emulator Library, and enhanced to handle 64bits
|
|
/****************************************************************************
|
|
*
|
|
* Realmode X86 Emulator Library
|
|
*
|
|
* Copyright (c) 1996-1999 SciTech Software, Inc.
|
|
* Copyright (c) David Mosberger-Tang
|
|
* Copyright (c) 1999 Egbert Eich
|
|
* Copyright (c) 2007-2017 SUSE LINUX GmbH; Author: Steffen Winterfeldt
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* 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.
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* Description:
|
|
* 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)
|
|
*
|
|
****************************************************************************/
|
|
|
|
// This has been heavily modified to fit box64 purpose...
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "x64emu_private.h"
|
|
#include "x64run_private.h"
|
|
#include "env.h"
|
|
|
|
extern box64env_t box64env;
|
|
|
|
/*------------------------- Global Variables ------------------------------*/
|
|
|
|
#define PARITY(x) (((emu->x64emu_parity_tab[(x) / 32] >> ((x) % 32)) & 1) == 0)
|
|
#define XOR2(x) (((x) ^ ((x)>>1)) & 0x1)
|
|
|
|
/*----------------------------- Implementation ----------------------------*/
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the AAA instruction and side effects.
|
|
****************************************************************************/
|
|
uint16_t aaa16(x64emu_t *emu, uint16_t d)
|
|
{
|
|
uint16_t res;
|
|
CHECK_FLAGS(emu);
|
|
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 = (uint16_t)(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 AAS instruction and side effects.
|
|
****************************************************************************/
|
|
uint16_t aas16(x64emu_t *emu, uint16_t d)
|
|
{
|
|
uint16_t res;
|
|
CHECK_FLAGS(emu);
|
|
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 = (uint16_t)(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.
|
|
****************************************************************************/
|
|
uint16_t aad16(x64emu_t *emu, uint16_t d, uint8_t base)
|
|
{
|
|
uint16_t l;
|
|
uint8_t hb, lb;
|
|
|
|
RESET_FLAGS(emu);
|
|
|
|
hb = (uint8_t)((d >> 8) & 0xff);
|
|
lb = (uint8_t)((d & 0xff));
|
|
l = (uint16_t)((lb + base * 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&0xff) == 0, F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF);
|
|
return l;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the AAM instruction and side effects.
|
|
****************************************************************************/
|
|
uint16_t aam16(x64emu_t *emu, uint8_t d, uint8_t base)
|
|
{
|
|
uint16_t h, l;
|
|
|
|
RESET_FLAGS(emu);
|
|
|
|
h = (uint16_t)(d / base);
|
|
l = (uint16_t)(d % base);
|
|
l |= (uint16_t)(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&0xff) == 0, F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(l & 0xff), F_PF);
|
|
return l;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the ADC instruction and side effects.
|
|
****************************************************************************/
|
|
uint8_t adc8(x64emu_t *emu, uint8_t d, uint8_t s)
|
|
{
|
|
uint32_t res; /* all operands in native machine order */
|
|
uint32_t cc;
|
|
|
|
CHECK_FLAGS(emu);
|
|
|
|
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 (uint8_t)res;
|
|
}
|
|
|
|
uint16_t adc16(x64emu_t *emu, uint16_t d, uint16_t s)
|
|
{
|
|
uint32_t res; /* all operands in native machine order */
|
|
uint32_t cc;
|
|
|
|
CHECK_FLAGS(emu);
|
|
|
|
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 (uint16_t)res;
|
|
}
|
|
|
|
uint32_t adc32(x64emu_t *emu, uint32_t d, uint32_t s)
|
|
{
|
|
uint64_t res; /* all operands in native machine order */
|
|
uint64_t cc;
|
|
|
|
CHECK_FLAGS(emu);
|
|
|
|
if (ACCESS_FLAG(F_CF))
|
|
res = 1LL + d + s;
|
|
else
|
|
res = (uint64_t)d + s;
|
|
|
|
CONDITIONAL_SET_FLAG(res & 0x100000000LL, 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 (uint32_t)res;
|
|
|
|
}
|
|
|
|
uint64_t adc64(x64emu_t *emu, uint64_t d, uint64_t s)
|
|
{
|
|
uint64_t lo; /* all operands in native machine order */
|
|
uint64_t hi;
|
|
uint64_t res;
|
|
uint64_t cc;
|
|
|
|
CHECK_FLAGS(emu);
|
|
|
|
if (ACCESS_FLAG(F_CF)) {
|
|
lo = 1 + (d & 0xFFFFFFFF) + (s & 0xFFFFFFFF);
|
|
res = 1 + d + s;
|
|
}
|
|
else {
|
|
lo = (d & 0xFFFFFFFF) + (s & 0xFFFFFFFF);
|
|
res = d + s;
|
|
}
|
|
hi = (lo >> 32) + (d >> 32) + (s >> 32);
|
|
|
|
CONDITIONAL_SET_FLAG(hi & 0x100000000L, F_CF);
|
|
CONDITIONAL_SET_FLAG(!res, F_ZF);
|
|
CONDITIONAL_SET_FLAG(res & 0x8000000000000000LL, 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 >> 62), F_OF);
|
|
CONDITIONAL_SET_FLAG(cc & 0x8, F_AF);
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the CMP instruction and side effects.
|
|
****************************************************************************/
|
|
uint8_t cmp8(x64emu_t *emu, uint8_t d, uint8_t s)
|
|
{
|
|
uint32_t res; /* all operands in native machine order */
|
|
uint32_t bc;
|
|
|
|
RESET_FLAGS(emu);
|
|
|
|
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;
|
|
}
|
|
|
|
uint16_t cmp16(x64emu_t *emu, uint16_t d, uint16_t s)
|
|
{
|
|
uint32_t res; /* all operands in native machine order */
|
|
uint32_t bc;
|
|
|
|
RESET_FLAGS(emu);
|
|
|
|
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;
|
|
}
|
|
|
|
uint32_t cmp32(x64emu_t *emu, uint32_t d, uint32_t s)
|
|
{
|
|
uint32_t res; /* all operands in native machine order */
|
|
uint32_t bc;
|
|
|
|
RESET_FLAGS(emu);
|
|
|
|
res = d - s;
|
|
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
|
|
CONDITIONAL_SET_FLAG(!res, 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;
|
|
}
|
|
|
|
uint64_t cmp64(x64emu_t *emu, uint64_t d, uint64_t s)
|
|
{
|
|
uint64_t res; /* all operands in native machine order */
|
|
uint64_t bc;
|
|
|
|
RESET_FLAGS(emu);
|
|
|
|
res = d - s;
|
|
CONDITIONAL_SET_FLAG(res & 0x8000000000000000LL, F_SF);
|
|
CONDITIONAL_SET_FLAG(!res, 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 & 0x8000000000000000LL, F_CF);
|
|
CONDITIONAL_SET_FLAG(XOR2(bc >> 62), F_OF);
|
|
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
|
return d;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the DAA instruction and side effects.
|
|
****************************************************************************/
|
|
uint8_t daa8(x64emu_t *emu, uint8_t d)
|
|
{
|
|
uint32_t res = d;
|
|
CHECK_FLAGS(emu);
|
|
int cf = ACCESS_FLAG(F_CF);
|
|
CLEAR_FLAG(F_CF);
|
|
if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
|
|
res += 6;
|
|
SET_FLAG(F_AF);
|
|
CONDITIONAL_SET_FLAG(cf || d&0x100, F_CF);
|
|
} else
|
|
CLEAR_FLAG(F_AF);
|
|
if (d > 0x99 || cf) {
|
|
res += 0x60;
|
|
SET_FLAG(F_CF);
|
|
} else
|
|
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);
|
|
return (uint8_t)res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the DAS instruction and side effects.
|
|
****************************************************************************/
|
|
uint8_t das8(x64emu_t *emu, uint8_t d)
|
|
{
|
|
uint32_t res = d;
|
|
CHECK_FLAGS(emu);
|
|
uint32_t newcf = 0;
|
|
if ((d & 0xf) > 9 || ACCESS_FLAG(F_AF)) {
|
|
res -= 6;
|
|
newcf = ACCESS_FLAG(F_CF) || (d < 6);
|
|
SET_FLAG(F_AF);
|
|
} else
|
|
CLEAR_FLAG(F_AF);
|
|
if (d > 0x99 || ACCESS_FLAG(F_CF)) {
|
|
res -= 0x60;
|
|
newcf = 1;
|
|
}
|
|
CONDITIONAL_SET_FLAG(newcf, 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 res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the RCL instruction and side effects.
|
|
****************************************************************************/
|
|
uint8_t rcl8(x64emu_t *emu, uint8_t d, uint8_t s)
|
|
{
|
|
unsigned int res, cnt, mask, cf;
|
|
CHECK_FLAGS(emu);
|
|
s = s&0x1f;
|
|
|
|
/* 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))
|
|
*/
|
|
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. */
|
|
if(BOX64ENV(cputype))
|
|
CONDITIONAL_SET_FLAG((cf ^ (res >> 7)) & 0x1, F_OF);
|
|
else
|
|
CONDITIONAL_SET_FLAG((XOR2(d >> 6)), F_OF);
|
|
} else if(s) {
|
|
res = d;
|
|
if(BOX64ENV(cputype))
|
|
CONDITIONAL_SET_FLAG((ACCESS_FLAG(F_CF) ^ (res >> 7)) & 0x1, F_OF);
|
|
}
|
|
return (uint8_t)res;
|
|
}
|
|
|
|
uint16_t rcl16(x64emu_t *emu, uint16_t d, uint8_t s)
|
|
{
|
|
unsigned int res, cnt, mask, cf;
|
|
CHECK_FLAGS(emu);
|
|
s = s&0x1f;
|
|
|
|
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);
|
|
if(BOX64ENV(cputype))
|
|
CONDITIONAL_SET_FLAG((cf ^ (res >> 15)) & 0x1, F_OF);
|
|
else
|
|
CONDITIONAL_SET_FLAG((XOR2(d >> 14)), F_OF);
|
|
} else if(s) {
|
|
res = d;
|
|
if(BOX64ENV(cputype))
|
|
CONDITIONAL_SET_FLAG((ACCESS_FLAG(F_CF) ^ (res >> 15)) & 0x1, F_OF);
|
|
}
|
|
return (uint16_t)res;
|
|
}
|
|
|
|
uint32_t rcl32(x64emu_t *emu, uint32_t d, uint8_t s)
|
|
{
|
|
uint32_t res, cnt, mask, cf;
|
|
CHECK_FLAGS(emu);
|
|
s = s&0x1f;
|
|
|
|
res = d;
|
|
if ((cnt = s) != 0) {
|
|
cf = (d >> (32 - cnt)) & 0x1;
|
|
res = (d << cnt);
|
|
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);
|
|
if(BOX64ENV(cputype))
|
|
CONDITIONAL_SET_FLAG((cf ^ (res >> 31)) & 0x1, F_OF);
|
|
else
|
|
CONDITIONAL_SET_FLAG((XOR2(d >> 30)), F_OF);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
uint64_t rcl64(x64emu_t *emu, uint64_t d, uint8_t s)
|
|
{
|
|
uint64_t res, cnt, mask, cf;
|
|
CHECK_FLAGS(emu);
|
|
s = s&0x3f;
|
|
|
|
res = d;
|
|
if ((cnt = s) != 0) {
|
|
cf = (d >> (64 - cnt)) & 0x1;
|
|
res = (d << cnt);
|
|
mask = (1LL << (cnt - 1)) - 1;
|
|
res |= (d >> (65 - cnt)) & mask;
|
|
if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
|
|
res |= 1LL << (cnt - 1);
|
|
}
|
|
CONDITIONAL_SET_FLAG(cf, F_CF);
|
|
if(BOX64ENV(cputype))
|
|
CONDITIONAL_SET_FLAG((cf ^ (res >> 63)) & 0x1, F_OF);
|
|
else
|
|
CONDITIONAL_SET_FLAG((XOR2(d >> 62)), F_OF);
|
|
}
|
|
return res;
|
|
}
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the RCR instruction and side effects.
|
|
****************************************************************************/
|
|
uint8_t rcr8(x64emu_t *emu, uint8_t d, uint8_t s)
|
|
{
|
|
uint32_t res, cnt;
|
|
uint32_t mask, cf, ocf = 0;
|
|
CHECK_FLAGS(emu);
|
|
s = s&0x1f;
|
|
|
|
/* 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) */
|
|
ocf = ACCESS_FLAG(F_CF) != 0;
|
|
/* OVERFLOW is set *IFF* cnt==1, then it is the
|
|
xor of CF and the most significant bit. Blecck. */
|
|
/* parenthesized... */
|
|
if(!BOX64ENV(cputype))
|
|
CONDITIONAL_SET_FLAG((ocf ^ (d >> 7)) & 0x1, F_OF);
|
|
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.)
|
|
*/
|
|
} 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);
|
|
|
|
}
|
|
if(s && BOX64ENV(cputype))
|
|
CONDITIONAL_SET_FLAG((XOR2(res >> 6)), F_OF);
|
|
return (uint8_t)res;
|
|
}
|
|
|
|
uint16_t rcr16(x64emu_t *emu, uint16_t d, uint8_t s)
|
|
{
|
|
uint32_t res, cnt;
|
|
uint32_t mask, cf, ocf = 0;
|
|
CHECK_FLAGS(emu);
|
|
s = s&0x1f;
|
|
|
|
/* rotate right through carry */
|
|
res = d;
|
|
if ((cnt = s % 17) != 0) {
|
|
ocf = ACCESS_FLAG(F_CF) != 0;
|
|
if(!BOX64ENV(cputype))
|
|
CONDITIONAL_SET_FLAG((ocf ^ (d >> 15)) & 0x1, F_OF);
|
|
if (cnt == 1) {
|
|
cf = d & 0x1;
|
|
} 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(s && BOX64ENV(cputype))
|
|
CONDITIONAL_SET_FLAG((XOR2(res >> 14)), F_OF);
|
|
return (uint16_t)res;
|
|
}
|
|
|
|
uint32_t rcr32(x64emu_t *emu, uint32_t d, uint8_t s)
|
|
{
|
|
uint32_t res, cnt;
|
|
uint32_t mask, cf, ocf = 0;
|
|
CHECK_FLAGS(emu);
|
|
s = s&0x1f;
|
|
|
|
/* rotate right through carry */
|
|
res = d;
|
|
if ((cnt = s) != 0) {
|
|
ocf = ACCESS_FLAG(F_CF) != 0;
|
|
if(!BOX64ENV(cputype))
|
|
CONDITIONAL_SET_FLAG((ocf ^ (d >> 31)) & 0x1, F_OF);
|
|
if (cnt == 1) {
|
|
cf = d & 0x1;
|
|
} 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(s && BOX64ENV(cputype))
|
|
CONDITIONAL_SET_FLAG((XOR2(res >> 30)), F_OF);
|
|
return res;
|
|
}
|
|
|
|
uint64_t rcr64(x64emu_t *emu, uint64_t d, uint8_t s)
|
|
{
|
|
uint64_t res, cnt;
|
|
uint64_t mask, cf, ocf = 0;
|
|
CHECK_FLAGS(emu);
|
|
s = s&0x3f;
|
|
|
|
/* rotate right through carry */
|
|
res = d;
|
|
if ((cnt = s) != 0) {
|
|
ocf = ACCESS_FLAG(F_CF) != 0;
|
|
if(!BOX64ENV(cputype))
|
|
CONDITIONAL_SET_FLAG((ocf ^ (d >> 63)) & 0x1, F_OF);
|
|
if (cnt == 1) {
|
|
cf = d & 0x1;
|
|
} else {
|
|
cf = (d >> (cnt - 1)) & 0x1;
|
|
}
|
|
mask = (1LL << (64 - cnt)) - 1;
|
|
res = (d >> cnt) & mask;
|
|
if (cnt != 1)
|
|
res |= (d << (65 - cnt));
|
|
if (ACCESS_FLAG(F_CF)) { /* carry flag is set */
|
|
res |= 1LL << (64 - cnt);
|
|
}
|
|
CONDITIONAL_SET_FLAG(cf, F_CF);
|
|
}
|
|
if(s && BOX64ENV(cputype))
|
|
CONDITIONAL_SET_FLAG((XOR2(res >> 62)), F_OF);
|
|
return res;
|
|
}
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the ROL instruction and side effects.
|
|
****************************************************************************/
|
|
uint8_t rol8(x64emu_t *emu, uint8_t d, uint8_t s)
|
|
{
|
|
unsigned cnt;
|
|
|
|
s = s&0x1f;
|
|
if(!s) return d;
|
|
CHECK_FLAGS(emu);
|
|
/* OF flag is set if s == 1; OF = CF _XOR_ MSB of result */
|
|
|
|
if(!BOX64ENV(cputype)) CONDITIONAL_SET_FLAG(XOR2(d>>6), F_OF);
|
|
|
|
if((cnt = s % 8) != 0) {
|
|
d = (d << cnt) + ((d >> (8 - cnt)) & ((1 << cnt) - 1));
|
|
}
|
|
|
|
if(BOX64ENV(cputype)) CONDITIONAL_SET_FLAG((d + (d >> 7)) & 1, F_OF);
|
|
|
|
/* set new CF; note that it is the LSB of the result */
|
|
CONDITIONAL_SET_FLAG(d & 0x1, F_CF);
|
|
|
|
return d;
|
|
}
|
|
|
|
uint16_t rol16(x64emu_t *emu, uint16_t d, uint8_t s)
|
|
{
|
|
unsigned cnt;
|
|
|
|
s = s&0x1f;
|
|
if(!s) return d;
|
|
CHECK_FLAGS(emu);
|
|
|
|
if(!BOX64ENV(cputype)) CONDITIONAL_SET_FLAG(XOR2(d>>14), F_OF);
|
|
if((cnt = s % 16) != 0) {
|
|
d = (d << cnt) + ((d >> (16 - cnt)) & ((1 << cnt) - 1));
|
|
}
|
|
|
|
if(BOX64ENV(cputype)) CONDITIONAL_SET_FLAG((d + (d >> 15)) & 1, F_OF);
|
|
|
|
CONDITIONAL_SET_FLAG(d & 0x1, F_CF);
|
|
|
|
return d;
|
|
}
|
|
|
|
uint32_t rol32(x64emu_t *emu, uint32_t d, uint8_t s)
|
|
{
|
|
unsigned cnt;
|
|
|
|
s = s&0x1f;
|
|
if(!s) return d;
|
|
CHECK_FLAGS(emu);
|
|
|
|
if(!BOX64ENV(cputype)) CONDITIONAL_SET_FLAG(XOR2(d>>30), F_OF);
|
|
if((cnt = s % 32) != 0) {
|
|
d = (d << cnt) + ((d >> (32 - cnt)) & ((1 << cnt) - 1));
|
|
}
|
|
|
|
if(BOX64ENV(cputype)) CONDITIONAL_SET_FLAG((d + (d >> 31)) & 1, F_OF);
|
|
|
|
CONDITIONAL_SET_FLAG(d & 0x1, F_CF);
|
|
|
|
return d;
|
|
}
|
|
|
|
uint64_t rol64(x64emu_t *emu, uint64_t d, uint8_t s)
|
|
{
|
|
unsigned cnt;
|
|
|
|
s = s&0x3f;
|
|
if(!s) return d;
|
|
CHECK_FLAGS(emu);
|
|
|
|
if(!BOX64ENV(cputype)) CONDITIONAL_SET_FLAG(XOR2(d>>62), F_OF);
|
|
if((cnt = s % 64) != 0) {
|
|
d = (d << cnt) + ((d >> (64 - cnt)) & ((1L << cnt) - 1));
|
|
}
|
|
|
|
if(BOX64ENV(cputype)) CONDITIONAL_SET_FLAG((d + (d >> 63)) & 1, F_OF);
|
|
|
|
CONDITIONAL_SET_FLAG(d & 0x1, F_CF);
|
|
|
|
return d;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the ROR instruction and side effects.
|
|
****************************************************************************/
|
|
uint8_t ror8(x64emu_t *emu, uint8_t d, uint8_t s)
|
|
{
|
|
unsigned cnt;
|
|
|
|
s = s&0x1f;
|
|
if(!s) return d;
|
|
CHECK_FLAGS(emu);
|
|
|
|
if(!BOX64ENV(cputype)) CONDITIONAL_SET_FLAG(((d >> 7)^d)&1, F_OF);
|
|
|
|
if((cnt = s % 8) != 0) {
|
|
d = (d << (8 - cnt)) + ((d >> (cnt)) & ((1 << (8 - cnt)) - 1));
|
|
}
|
|
|
|
if(BOX64ENV(cputype)) CONDITIONAL_SET_FLAG(XOR2(d >> 6), F_OF);
|
|
|
|
/* set new CF; note that it is the MSB of the result */
|
|
CONDITIONAL_SET_FLAG(d & (1 << 7), F_CF);
|
|
|
|
return d;
|
|
}
|
|
|
|
uint16_t ror16(x64emu_t *emu, uint16_t d, uint8_t s)
|
|
{
|
|
unsigned cnt;
|
|
|
|
s = s&0x1f;
|
|
if(!s) return d;
|
|
CHECK_FLAGS(emu);
|
|
|
|
if(!BOX64ENV(cputype)) CONDITIONAL_SET_FLAG(((d >> 15)^d)&1, F_OF);
|
|
|
|
if((cnt = s % 16) != 0) {
|
|
d = (d << (16 - cnt)) + ((d >> (cnt)) & ((1 << (16 - cnt)) - 1));
|
|
}
|
|
|
|
if(BOX64ENV(cputype)) CONDITIONAL_SET_FLAG(XOR2(d >> 14), F_OF);
|
|
|
|
/* set new CF; note that it is the MSB of the result */
|
|
CONDITIONAL_SET_FLAG(d & (1 << 15), F_CF);
|
|
|
|
return d;
|
|
}
|
|
|
|
uint32_t ror32(x64emu_t *emu, uint32_t d, uint8_t s)
|
|
{
|
|
unsigned cnt;
|
|
|
|
s = s&0x1f;
|
|
if(!s) return d;
|
|
CHECK_FLAGS(emu);
|
|
|
|
if(!BOX64ENV(cputype)) CONDITIONAL_SET_FLAG(((d >> 31)^d)&1, F_OF);
|
|
|
|
if((cnt = s % 32) != 0) {
|
|
d = (d << (32 - cnt)) + ((d >> (cnt)) & ((1 << (32 - cnt)) - 1));
|
|
}
|
|
|
|
if(BOX64ENV(cputype)) CONDITIONAL_SET_FLAG(XOR2(d >> 30), F_OF);
|
|
|
|
/* set new CF; note that it is the MSB of the result */
|
|
CONDITIONAL_SET_FLAG(d & (1 << 31), F_CF);
|
|
|
|
return d;
|
|
}
|
|
|
|
uint64_t ror64(x64emu_t *emu, uint64_t d, uint8_t s)
|
|
{
|
|
unsigned cnt;
|
|
|
|
s = s&0x3f;
|
|
if(!s) return d;
|
|
CHECK_FLAGS(emu);
|
|
|
|
if(!BOX64ENV(cputype)) CONDITIONAL_SET_FLAG(((d >> 63)^d)&1, F_OF);
|
|
|
|
if((cnt = s % 64) != 0) {
|
|
d = (d << (64 - cnt)) + ((d >> (cnt)) & ((1L << (64 - cnt)) - 1L));
|
|
}
|
|
|
|
if(BOX64ENV(cputype)) CONDITIONAL_SET_FLAG(XOR2(d >> 62), F_OF);
|
|
|
|
/* set new CF; note that it is the MSB of the result */
|
|
CONDITIONAL_SET_FLAG(d & (1LL << 63), F_CF);
|
|
|
|
return d;
|
|
}
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SHLD instruction and side effects.
|
|
****************************************************************************/
|
|
uint16_t shld16 (x64emu_t *emu, uint16_t d, uint16_t fill, uint8_t s)
|
|
{
|
|
unsigned int cnt, res, cf;
|
|
|
|
s = s&0x1f;
|
|
cnt = s % 16;
|
|
if(!s)
|
|
return d;
|
|
RESET_FLAGS(emu);
|
|
if (s < 16) {
|
|
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 = (fill << (cnt)) | (d >> (16 - cnt));
|
|
if(s==16)
|
|
cf = d & 1;
|
|
else
|
|
cf = fill & (1 << (16 - cnt));
|
|
if(BOX64ENV(cputype) && (s>16)) {
|
|
CLEAR_FLAG(F_CF);
|
|
} else {
|
|
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);
|
|
}
|
|
if (BOX64ENV(cputype)) {
|
|
if(s>15)
|
|
CONDITIONAL_SET_FLAG(ACCESS_FLAG(F_CF), F_OF);
|
|
else
|
|
CONDITIONAL_SET_FLAG((ACCESS_FLAG(F_CF) ^ (res>>15))&1, F_OF);
|
|
} else {
|
|
CONDITIONAL_SET_FLAG(XOR2(d>>14), F_OF);
|
|
}
|
|
if (BOX64ENV(cputype))
|
|
SET_FLAG(F_AF);
|
|
else
|
|
CLEAR_FLAG(F_AF);
|
|
return (uint16_t)res;
|
|
}
|
|
|
|
uint32_t shld32 (x64emu_t *emu, uint32_t d, uint32_t fill, uint8_t s)
|
|
{
|
|
unsigned int cnt, res, cf;
|
|
|
|
s = s&0x1f;
|
|
if(!s)
|
|
return d;
|
|
RESET_FLAGS(emu);
|
|
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, F_ZF);
|
|
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
|
} else {
|
|
res = d;
|
|
}
|
|
if (BOX64ENV(cputype)) {
|
|
CONDITIONAL_SET_FLAG((ACCESS_FLAG(F_CF) ^ (res>>31))&1, F_OF);
|
|
} else {
|
|
CONDITIONAL_SET_FLAG(XOR2(d>>30), F_OF);
|
|
}
|
|
if (BOX64ENV(cputype))
|
|
SET_FLAG(F_AF);
|
|
else
|
|
CLEAR_FLAG(F_AF);
|
|
return res;
|
|
}
|
|
|
|
uint64_t shld64 (x64emu_t *emu, uint64_t d, uint64_t fill, uint8_t s)
|
|
{
|
|
uint64_t cnt, res, cf;
|
|
|
|
s = s&0x3f;
|
|
if(!s)
|
|
return d;
|
|
RESET_FLAGS(emu);
|
|
cnt = s % 64;
|
|
if (cnt > 0) {
|
|
res = (d << cnt) | (fill >> (64-cnt));
|
|
cf = d & (1LL << (64 - cnt));
|
|
CONDITIONAL_SET_FLAG(cf, F_CF);
|
|
CONDITIONAL_SET_FLAG(!res, F_ZF);
|
|
CONDITIONAL_SET_FLAG(res & 0x8000000000000000LL, F_SF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
|
} else {
|
|
res = d;
|
|
}
|
|
if (BOX64ENV(cputype)) {
|
|
CONDITIONAL_SET_FLAG((ACCESS_FLAG(F_CF) ^ (res>>63))&1, F_OF);
|
|
} else {
|
|
CONDITIONAL_SET_FLAG(XOR2(d>>62), F_OF);
|
|
}
|
|
if (BOX64ENV(cputype))
|
|
SET_FLAG(F_AF);
|
|
else
|
|
CLEAR_FLAG(F_AF);
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SHRD instruction and side effects.
|
|
****************************************************************************/
|
|
uint16_t shrd16 (x64emu_t *emu, uint16_t d, uint16_t fill, uint8_t s)
|
|
{
|
|
unsigned int cnt, res, cf;
|
|
|
|
s = s&0x1f;
|
|
if(!s)
|
|
return d;
|
|
RESET_FLAGS(emu);
|
|
cnt = s % 16;
|
|
if (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;
|
|
}
|
|
|
|
} else {
|
|
if(s==16)
|
|
cf = d & (1 << 15);
|
|
else
|
|
cf = fill & (1 << (cnt - 1));
|
|
res = (fill >> cnt) | (d << (16 - cnt));
|
|
if(BOX64ENV(cputype) && (s>16)) {
|
|
CLEAR_FLAG(F_CF);
|
|
} else {
|
|
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);
|
|
#if 0
|
|
res = 0;
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_OF);
|
|
SET_FLAG(F_ZF);
|
|
CLEAR_FLAG(F_SF);
|
|
CLEAR_FLAG(F_PF);
|
|
#endif
|
|
}
|
|
if (BOX64ENV(cputype)) {
|
|
CONDITIONAL_SET_FLAG(XOR2(res>>14), F_OF);
|
|
} else {
|
|
CONDITIONAL_SET_FLAG((fill^(d>>15))&1, F_OF);
|
|
}
|
|
if (BOX64ENV(cputype))
|
|
SET_FLAG(F_AF);
|
|
else
|
|
CLEAR_FLAG(F_AF);
|
|
return (uint16_t)res;
|
|
}
|
|
|
|
uint32_t shrd32 (x64emu_t *emu, uint32_t d, uint32_t fill, uint8_t s)
|
|
{
|
|
unsigned int cnt, res, cf;
|
|
|
|
s = s&0x1f;
|
|
if(!s)
|
|
return d;
|
|
RESET_FLAGS(emu);
|
|
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, F_ZF);
|
|
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
|
} else {
|
|
res = d;
|
|
}
|
|
if (BOX64ENV(cputype)) {
|
|
CONDITIONAL_SET_FLAG(XOR2(res>>30), F_OF);
|
|
} else {
|
|
CONDITIONAL_SET_FLAG((fill^(d>>31))&1, F_OF);
|
|
}
|
|
if (BOX64ENV(cputype))
|
|
SET_FLAG(F_AF);
|
|
else
|
|
CLEAR_FLAG(F_AF);
|
|
return res;
|
|
}
|
|
|
|
uint64_t shrd64 (x64emu_t *emu, uint64_t d, uint64_t fill, uint8_t s)
|
|
{
|
|
unsigned int cnt;
|
|
uint64_t res, cf;
|
|
|
|
s = s&0x3f;
|
|
if(!s)
|
|
return d;
|
|
RESET_FLAGS(emu);
|
|
cnt = s % 64;
|
|
if (cnt > 0) {
|
|
cf = d & (1LL << (cnt - 1));
|
|
res = (d >> cnt) | (fill << (64 - cnt));
|
|
CONDITIONAL_SET_FLAG(cf, F_CF);
|
|
CONDITIONAL_SET_FLAG(!res, F_ZF);
|
|
CONDITIONAL_SET_FLAG(res & 0x8000000000000000LL, F_SF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
|
} else {
|
|
res = d;
|
|
}
|
|
if (BOX64ENV(cputype)) {
|
|
CONDITIONAL_SET_FLAG(XOR2(res>>62), F_OF);
|
|
} else {
|
|
CONDITIONAL_SET_FLAG((fill^(d>>63))&1, F_OF);
|
|
}
|
|
if (BOX64ENV(cputype))
|
|
SET_FLAG(F_AF);
|
|
else
|
|
CLEAR_FLAG(F_AF);
|
|
return res;
|
|
}
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the SBB instruction and side effects.
|
|
****************************************************************************/
|
|
uint8_t sbb8(x64emu_t *emu, uint8_t d, uint8_t s)
|
|
{
|
|
uint32_t res; /* all operands in native machine order */
|
|
uint32_t bc;
|
|
CHECK_FLAGS(emu);
|
|
|
|
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 (uint8_t)res;
|
|
}
|
|
|
|
uint16_t sbb16(x64emu_t *emu, uint16_t d, uint16_t s)
|
|
{
|
|
uint32_t res; /* all operands in native machine order */
|
|
uint32_t bc;
|
|
CHECK_FLAGS(emu);
|
|
|
|
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 (uint16_t)res;
|
|
}
|
|
|
|
uint32_t sbb32(x64emu_t *emu, uint32_t d, uint32_t s)
|
|
{
|
|
uint32_t res; /* all operands in native machine order */
|
|
uint32_t bc;
|
|
CHECK_FLAGS(emu);
|
|
|
|
if (ACCESS_FLAG(F_CF))
|
|
res = d - s - 1;
|
|
else
|
|
res = d - s;
|
|
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
|
|
CONDITIONAL_SET_FLAG(!res, 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;
|
|
}
|
|
|
|
uint64_t sbb64(x64emu_t *emu, uint64_t d, uint64_t s)
|
|
{
|
|
uint64_t res; /* all operands in native machine order */
|
|
uint64_t bc;
|
|
CHECK_FLAGS(emu);
|
|
|
|
if (ACCESS_FLAG(F_CF))
|
|
res = d - s - 1;
|
|
else
|
|
res = d - s;
|
|
CONDITIONAL_SET_FLAG(res & 0x8000000000000000LL, F_SF);
|
|
CONDITIONAL_SET_FLAG(!res, 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 & 0x8000000000000000LL, F_CF);
|
|
CONDITIONAL_SET_FLAG(XOR2(bc >> 62), F_OF);
|
|
CONDITIONAL_SET_FLAG(bc & 0x8, F_AF);
|
|
return res;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the TEST instruction and side effects.
|
|
****************************************************************************/
|
|
void test8(x64emu_t *emu, uint8_t d, uint8_t s)
|
|
{
|
|
uint8_t res; /* all operands in native machine order */
|
|
RESET_FLAGS(emu);
|
|
|
|
res = d & s;
|
|
|
|
CLEAR_FLAG(F_OF);
|
|
CLEAR_FLAG(F_AF); /* AF == dont care */
|
|
CLEAR_FLAG(F_CF);
|
|
CONDITIONAL_SET_FLAG(res & 0x80, F_SF);
|
|
CONDITIONAL_SET_FLAG(!res, F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
|
}
|
|
|
|
void test16(x64emu_t *emu, uint16_t d, uint16_t s)
|
|
{
|
|
uint16_t res; /* all operands in native machine order */
|
|
RESET_FLAGS(emu);
|
|
|
|
res = d & s;
|
|
|
|
CLEAR_FLAG(F_OF);
|
|
CLEAR_FLAG(F_AF); /* AF == dont care */
|
|
CLEAR_FLAG(F_CF);
|
|
CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
|
|
CONDITIONAL_SET_FLAG(!res, F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
|
}
|
|
|
|
void test32(x64emu_t *emu, uint32_t d, uint32_t s)
|
|
{
|
|
uint32_t res; /* all operands in native machine order */
|
|
RESET_FLAGS(emu);
|
|
|
|
res = d & s;
|
|
|
|
CLEAR_FLAG(F_OF);
|
|
CLEAR_FLAG(F_AF); /* AF == dont care */
|
|
CLEAR_FLAG(F_CF);
|
|
CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF);
|
|
CONDITIONAL_SET_FLAG(!res, F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
|
}
|
|
|
|
void test64(x64emu_t *emu, uint64_t d, uint64_t s)
|
|
{
|
|
uint64_t res; /* all operands in native machine order */
|
|
RESET_FLAGS(emu);
|
|
|
|
res = d & s;
|
|
|
|
CLEAR_FLAG(F_OF);
|
|
CLEAR_FLAG(F_AF); /* AF == dont care */
|
|
CLEAR_FLAG(F_CF);
|
|
CONDITIONAL_SET_FLAG(res & 0x8000000000000000LL, F_SF);
|
|
CONDITIONAL_SET_FLAG(!res, F_ZF);
|
|
CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the IDIV instruction and side effects.
|
|
****************************************************************************/
|
|
|
|
void idiv8(x64emu_t *emu, uint8_t s)
|
|
{
|
|
int32_t dvd, quot, mod;
|
|
if(BOX64ENV(cputype)) {
|
|
CHECK_FLAGS(emu);
|
|
SET_FLAG(F_AF);
|
|
CLEAR_FLAG(F_PF);
|
|
CLEAR_FLAG(F_ZF);
|
|
CLEAR_FLAG(F_SF);
|
|
}
|
|
|
|
dvd = (int16_t)R_AX;
|
|
if (s == 0) {
|
|
INTR_RAISE_DIV0(emu);
|
|
return;
|
|
}
|
|
div_t p = div(dvd, (int8_t)s);
|
|
quot = p.quot;
|
|
mod = p.rem;
|
|
if (abs(quot) > 0x7f) {
|
|
INTR_RAISE_DIV0(emu);
|
|
return;
|
|
}
|
|
R_AL = (int8_t) quot;
|
|
R_AH = (int8_t) mod;
|
|
}
|
|
|
|
void idiv16(x64emu_t *emu, uint16_t s)
|
|
{
|
|
int32_t dvd, quot, mod;
|
|
if(BOX64ENV(cputype)) {
|
|
CHECK_FLAGS(emu);
|
|
SET_FLAG(F_AF);
|
|
CLEAR_FLAG(F_PF);
|
|
CLEAR_FLAG(F_ZF);
|
|
CLEAR_FLAG(F_SF);
|
|
}
|
|
|
|
dvd = (((int32_t)R_DX) << 16) | R_AX;
|
|
if (s == 0) {
|
|
INTR_RAISE_DIV0(emu);
|
|
return;
|
|
}
|
|
div_t p = div(dvd, (int16_t)s);
|
|
quot = p.quot;
|
|
mod = p.rem;
|
|
if (abs(quot) > 0x7fff) {
|
|
INTR_RAISE_DIV0(emu);
|
|
return;
|
|
}
|
|
|
|
R_AX = (uint16_t)quot;
|
|
R_DX = (uint16_t)mod;
|
|
}
|
|
|
|
void idiv32(x64emu_t *emu, uint32_t s)
|
|
{
|
|
int64_t dvd, quot, mod;
|
|
if(BOX64ENV(cputype)) {
|
|
CHECK_FLAGS(emu);
|
|
SET_FLAG(F_AF);
|
|
CLEAR_FLAG(F_PF);
|
|
CLEAR_FLAG(F_ZF);
|
|
CLEAR_FLAG(F_SF);
|
|
}
|
|
|
|
dvd = (((int64_t)R_EDX) << 32) | R_EAX;
|
|
if (s == 0) {
|
|
INTR_RAISE_DIV0(emu);
|
|
return;
|
|
}
|
|
ldiv_t p = ldiv(dvd, (int32_t)s);
|
|
quot = p.quot;
|
|
mod = p.rem;
|
|
if (llabs(quot) > 0x7fffffff) {
|
|
INTR_RAISE_DIV0(emu);
|
|
return;
|
|
}
|
|
|
|
R_RAX = (uint32_t)quot;
|
|
R_RDX = (uint32_t)mod;
|
|
}
|
|
|
|
void idiv64(x64emu_t *emu, uint64_t s)
|
|
{
|
|
__int128 dvd, quot, mod;
|
|
if(BOX64ENV(cputype)) {
|
|
CHECK_FLAGS(emu);
|
|
SET_FLAG(F_AF);
|
|
CLEAR_FLAG(F_PF);
|
|
CLEAR_FLAG(F_ZF);
|
|
CLEAR_FLAG(F_SF);
|
|
}
|
|
|
|
dvd = (((__int128)R_RDX) << 64) | R_RAX;
|
|
if (s == 0) {
|
|
INTR_RAISE_DIV0(emu);
|
|
return;
|
|
}
|
|
quot = dvd/(int64_t)s;
|
|
mod = dvd%(int64_t)s;
|
|
if ((quot > 0x7fffffffffffffffLL) || (quot < -0x7fffffffffffffffLL)) {
|
|
INTR_RAISE_DIV0(emu);
|
|
return;
|
|
}
|
|
|
|
R_RAX = (uint64_t)quot;
|
|
R_RDX = (uint64_t)mod;
|
|
}
|
|
|
|
/****************************************************************************
|
|
REMARKS:
|
|
Implements the DIV instruction and side effects.
|
|
****************************************************************************/
|
|
void div8(x64emu_t *emu, uint8_t s)
|
|
{
|
|
uint32_t dvd, div, mod;
|
|
RESET_FLAGS(emu);
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_SF);
|
|
CLEAR_FLAG(F_OF);
|
|
if(BOX64ENV(cputype)) {
|
|
SET_FLAG(F_AF);
|
|
CLEAR_FLAG(F_ZF);
|
|
CLEAR_FLAG(F_PF);
|
|
} else {
|
|
CLEAR_FLAG(F_AF);
|
|
SET_FLAG(F_ZF);
|
|
SET_FLAG(F_PF);
|
|
}
|
|
|
|
dvd = R_AX;
|
|
if (s == 0) {
|
|
INTR_RAISE_DIV0(emu);
|
|
return;
|
|
}
|
|
div = dvd / (uint8_t)s;
|
|
mod = dvd % (uint8_t)s;
|
|
if (div > 0xff) {
|
|
INTR_RAISE_DIV0(emu);
|
|
return;
|
|
}
|
|
R_AL = (uint8_t)div;
|
|
R_AH = (uint8_t)mod;
|
|
}
|
|
|
|
void div16(x64emu_t *emu, uint16_t s)
|
|
{
|
|
uint32_t dvd, div, mod;
|
|
RESET_FLAGS(emu);
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_SF);
|
|
CLEAR_FLAG(F_OF);
|
|
if(BOX64ENV(cputype)) {
|
|
SET_FLAG(F_AF);
|
|
CLEAR_FLAG(F_ZF);
|
|
CLEAR_FLAG(F_PF);
|
|
} else {
|
|
CLEAR_FLAG(F_AF);
|
|
SET_FLAG(F_ZF);
|
|
SET_FLAG(F_PF);
|
|
}
|
|
|
|
dvd = (((uint32_t)R_DX) << 16) | R_AX;
|
|
if (s == 0) {
|
|
INTR_RAISE_DIV0(emu);
|
|
return;
|
|
}
|
|
div = dvd / (uint16_t)s;
|
|
mod = dvd % (uint16_t)s;
|
|
if (div > 0xffff) {
|
|
INTR_RAISE_DIV0(emu);
|
|
return;
|
|
}
|
|
|
|
R_AX = (uint16_t)div;
|
|
R_DX = (uint16_t)mod;
|
|
}
|
|
|
|
void div32(x64emu_t *emu, uint32_t s)
|
|
{
|
|
uint64_t dvd, div, mod;
|
|
RESET_FLAGS(emu);
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_SF);
|
|
CLEAR_FLAG(F_OF);
|
|
if(BOX64ENV(cputype)) {
|
|
SET_FLAG(F_AF);
|
|
CLEAR_FLAG(F_ZF);
|
|
CLEAR_FLAG(F_PF);
|
|
} else {
|
|
CLEAR_FLAG(F_AF);
|
|
SET_FLAG(F_ZF);
|
|
SET_FLAG(F_PF);
|
|
}
|
|
|
|
dvd = (((uint64_t)R_EDX) << 32) | R_EAX;
|
|
if (s == 0) {
|
|
INTR_RAISE_DIV0(emu);
|
|
return;
|
|
}
|
|
div = dvd / (uint32_t)s;
|
|
mod = dvd % (uint32_t)s;
|
|
if (div > 0xffffffff) {
|
|
INTR_RAISE_DIV0(emu);
|
|
return;
|
|
}
|
|
|
|
R_RAX = (uint32_t)div;
|
|
R_RDX = (uint32_t)mod;
|
|
}
|
|
|
|
void div64(x64emu_t *emu, uint64_t s)
|
|
{
|
|
__int128 dvd, div, mod;
|
|
RESET_FLAGS(emu);
|
|
CLEAR_FLAG(F_CF);
|
|
CLEAR_FLAG(F_SF);
|
|
CLEAR_FLAG(F_OF);
|
|
if(BOX64ENV(cputype)) {
|
|
SET_FLAG(F_AF);
|
|
CLEAR_FLAG(F_ZF);
|
|
CLEAR_FLAG(F_PF);
|
|
} else {
|
|
CLEAR_FLAG(F_AF);
|
|
SET_FLAG(F_ZF);
|
|
SET_FLAG(F_PF);
|
|
}
|
|
|
|
dvd = (((__int128)R_RDX) << 64) | R_RAX;
|
|
if (s == 0) {
|
|
INTR_RAISE_DIV0(emu);
|
|
return;
|
|
}
|
|
div = dvd / (unsigned __int128)s;
|
|
mod = dvd % (unsigned __int128)s;
|
|
if (div > 0xffffffffffffffffL) {
|
|
INTR_RAISE_DIV0(emu);
|
|
return;
|
|
}
|
|
|
|
R_RAX = (uint64_t)div;
|
|
R_RDX = (uint64_t)mod;
|
|
}
|