diff options
| author | Jason Jin <Jason.jin@freescale.com> | 2007-07-06 08:34:56 +0800 | 
|---|---|---|
| committer | Wolfgang Denk <wd@denx.de> | 2007-08-06 01:28:15 +0200 | 
| commit | ece92f85053b8df613edcf05b26a416cbc3d629c (patch) | |
| tree | 2d3389882d0655781183c2fd655dc6746c5eeea1 /drivers/bios_emulator/x86emu/prim_ops.c | |
| parent | 5072188acabde3178fac7f5a597150e6e74fd40c (diff) | |
| download | olio-uboot-2014.01-ece92f85053b8df613edcf05b26a416cbc3d629c.tar.xz olio-uboot-2014.01-ece92f85053b8df613edcf05b26a416cbc3d629c.zip  | |
This is a BIOS emulator, porting from SciTech for u-boot, mainly for
ATI video card BIOS. and can be used for x86 code emulation by some
modifications.
Signed-off-by: Jason Jin <Jason.jin@freescale.com>
Diffstat (limited to 'drivers/bios_emulator/x86emu/prim_ops.c')
| -rw-r--r-- | drivers/bios_emulator/x86emu/prim_ops.c | 2446 | 
1 files changed, 2446 insertions, 0 deletions
diff --git a/drivers/bios_emulator/x86emu/prim_ops.c b/drivers/bios_emulator/x86emu/prim_ops.c new file mode 100644 index 000000000..dc8cea800 --- /dev/null +++ b/drivers/bios_emulator/x86emu/prim_ops.c @@ -0,0 +1,2446 @@ +/**************************************************************************** +* +*                       Realmode X86 Emulator Library +* +*               Copyright (C) 1991-2004 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 OF343364 and AF flag. +* The latter is not so important, but the former is.  The overflow +* flag is the XOR of the top two bits of the carry chain for an +* addition (similar for subtraction).  Since we do not want to +* simulate the addition in a bitwise manner, we try to calculate the +* carry chain given the two operands and the result. +* +* So, given the following table, which represents the addition of two +* bits, we can derive a formula for the carry chain. +* +* a   b   cin   r     cout +* 0   0   0     0     0 +* 0   0   1     1     0 +* 0   1   0     1     0 +* 0   1   1     0     1 +* 1   0   0     1     0 +* 1   0   1     0     1 +* 1   1   0     0     1 +* 1   1   1     1     1 +* +* Construction of table for cout: +* +* ab +* r  \  00   01   11  10 +* |------------------ +* 0  |   0    1    1   1 +* 1  |   0    0    1   0 +* +* By inspection, one gets:  cc = ab +  r'(a + b) +* +* That represents alot of operations, but NO CHOICE.... +* +* Borrow Chain Calculation. +* +* The following table represents the subtraction of two bits, from +* which we can derive a formula for the borrow chain. +* +* a   b   bin   r     bout +* 0   0   0     0     0 +* 0   0   1     1     1 +* 0   1   0     1     1 +* 0   1   1     0     1 +* 1   0   0     1     0 +* 1   0   1     0     0 +* 1   1   0     0     0 +* 1   1   1     1     1 +* +* Construction of table for cout: +* +* ab +* r  \  00   01   11  10 +* |------------------ +* 0  |   0    1    0   0 +* 1  |   1    1    1   0 +* +* By inspection, one gets:  bc = a'b +  r(a' + b) +* +****************************************************************************/ + +#define PRIM_OPS_NO_REDEFINE_ASM +#include "x86emu/x86emui.h" + +/*------------------------- Global Variables ------------------------------*/ + +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 ----------------------------*/ +int abs(int v) +{ +	return (v>0)?v:-v; +} + +/*----------------------------- Implementation ----------------------------*/ + + +/*--------- Side effects helper functions -------*/ + +/**************************************************************************** +REMARKS: +implements side efects for byte operations that don't overflow +****************************************************************************/ + +static void set_parity_flag(u32 res) +{ +    CONDITIONAL_SET_FLAG(PARITY(res & 0xFF), F_PF); +} + +static void set_szp_flags_8(u8 res) +{ +    CONDITIONAL_SET_FLAG(res & 0x80, F_SF); +    CONDITIONAL_SET_FLAG(res == 0, F_ZF); +    set_parity_flag(res); +} + +static void set_szp_flags_16(u16 res) +{ +    CONDITIONAL_SET_FLAG(res & 0x8000, F_SF); +    CONDITIONAL_SET_FLAG(res == 0, F_ZF); +    set_parity_flag(res); +} + +static void set_szp_flags_32(u32 res) +{ +    CONDITIONAL_SET_FLAG(res & 0x80000000, F_SF); +    CONDITIONAL_SET_FLAG(res == 0, F_ZF); +    set_parity_flag(res); +} + +static void no_carry_byte_side_eff(u8 res) +{ +    CLEAR_FLAG(F_OF); +    CLEAR_FLAG(F_CF); +    CLEAR_FLAG(F_AF); +    set_szp_flags_8(res); +} + +static void no_carry_word_side_eff(u16 res) +{ +    CLEAR_FLAG(F_OF); +    CLEAR_FLAG(F_CF); +    CLEAR_FLAG(F_AF); +    set_szp_flags_16(res); +} + +static void no_carry_long_side_eff(u32 res) +{ +    CLEAR_FLAG(F_OF); +    CLEAR_FLAG(F_CF); +    CLEAR_FLAG(F_AF); +    set_szp_flags_32(res); +} + +static void calc_carry_chain(int bits, u32 d, u32 s, u32 res, int set_carry) +{ +    u32 cc; + +    cc = (s & d) | ((~res) & (s | d)); +    CONDITIONAL_SET_FLAG(XOR2(cc >> (bits - 2)), F_OF); +    CONDITIONAL_SET_FLAG(cc & 0x8, F_AF); +    if (set_carry) { +        CONDITIONAL_SET_FLAG(res & (1 << bits), F_CF); +    } +} + +static void calc_borrow_chain(int bits, u32 d, u32 s, u32 res, int set_carry) +{ +    u32 bc; + +    bc = (res & (~d | s)) | (~d & s); +    CONDITIONAL_SET_FLAG(XOR2(bc >> (bits - 2)), F_OF); +    CONDITIONAL_SET_FLAG(bc & 0x8, F_AF); +    if (set_carry) { +        CONDITIONAL_SET_FLAG(bc & (1 << (bits - 1)), F_CF); +    } +} + +/**************************************************************************** +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); +    set_szp_flags_16(res); +    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); +    set_szp_flags_16(res); +    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); + +    no_carry_byte_side_eff(l & 0xFF); +    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); + +    no_carry_byte_side_eff(l & 0xFF); +    return l; +} + +/**************************************************************************** +REMARKS: +Implements the ADC instruction and side effects. +****************************************************************************/ +u8 adc_byte(u8 d, u8 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + s; +    if (ACCESS_FLAG(F_CF)) res++; + +    set_szp_flags_8(res); +    calc_carry_chain(8,s,d,res,1); + +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADC instruction and side effects. +****************************************************************************/ +u16 adc_word(u16 d, u16 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + s; +    if (ACCESS_FLAG(F_CF)) +        res++; + +    set_szp_flags_16((u16)res); +    calc_carry_chain(16,s,d,res,1); + +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADC instruction and side effects. +****************************************************************************/ +u32 adc_long(u32 d, u32 s) +{ +    u32 lo;    /* all operands in native machine order */ +    u32 hi; +    u32 res; + +    lo = (d & 0xFFFF) + (s & 0xFFFF); +    res = d + s; + +    if (ACCESS_FLAG(F_CF)) { +        lo++; +        res++; +    } + +    hi = (lo >> 16) + (d >> 16) + (s >> 16); + +    set_szp_flags_32(res); +    calc_carry_chain(32,s,d,res,0); + +    CONDITIONAL_SET_FLAG(hi & 0x10000, F_CF); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the ADD instruction and side effects. +****************************************************************************/ +u8 add_byte(u8 d, u8 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + s; +    set_szp_flags_8((u8)res); +    calc_carry_chain(8,s,d,res,1); + +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADD instruction and side effects. +****************************************************************************/ +u16 add_word(u16 d, u16 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + s; +    set_szp_flags_16((u16)res); +    calc_carry_chain(16,s,d,res,1); + +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the ADD instruction and side effects. +****************************************************************************/ +u32 add_long(u32 d, u32 s) +{ +    u32 res; + +    res = d + s; +    set_szp_flags_32(res); +    calc_carry_chain(32,s,d,res,0); + +    CONDITIONAL_SET_FLAG(res < d || res < s, F_CF); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the AND instruction and side effects. +****************************************************************************/ +u8 and_byte(u8 d, u8 s) +{ +    u8 res;    /* all operands in native machine order */ + +    res = d & s; + +    no_carry_byte_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the AND instruction and side effects. +****************************************************************************/ +u16 and_word(u16 d, u16 s) +{ +    u16 res;   /* all operands in native machine order */ + +    res = d & s; + +    no_carry_word_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the AND instruction and side effects. +****************************************************************************/ +u32 and_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d & s; +    no_carry_long_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the CMP instruction and side effects. +****************************************************************************/ +u8 cmp_byte(u8 d, u8 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d - s; +    set_szp_flags_8((u8)res); +    calc_borrow_chain(8, d, s, res, 1); + +    return d; +} + +/**************************************************************************** +REMARKS: +Implements the CMP instruction and side effects. +****************************************************************************/ +u16 cmp_word(u16 d, u16 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d - s; +    set_szp_flags_16((u16)res); +    calc_borrow_chain(16, d, s, res, 1); + +    return d; +} + +/**************************************************************************** +REMARKS: +Implements the CMP instruction and side effects. +****************************************************************************/ +u32 cmp_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d - s; +    set_szp_flags_32(res); +    calc_borrow_chain(32, d, s, res, 1); + +    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); +    } +    set_szp_flags_8((u8)res); +    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); +    } +    set_szp_flags_8(d); +    return d; +} + +/**************************************************************************** +REMARKS: +Implements the DEC instruction and side effects. +****************************************************************************/ +u8 dec_byte(u8 d) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d - 1; +    set_szp_flags_8((u8)res); +    calc_borrow_chain(8, d, 1, res, 0); + +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the DEC instruction and side effects. +****************************************************************************/ +u16 dec_word(u16 d) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d - 1; +    set_szp_flags_16((u16)res); +    calc_borrow_chain(16, d, 1, res, 0); + +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the DEC instruction and side effects. +****************************************************************************/ +u32 dec_long(u32 d) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d - 1; + +    set_szp_flags_32(res); +    calc_borrow_chain(32, d, 1, res, 0); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the INC instruction and side effects. +****************************************************************************/ +u8 inc_byte(u8 d) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + 1; +    set_szp_flags_8((u8)res); +    calc_carry_chain(8, d, 1, res, 0); + +    return (u8)res; +} + +/**************************************************************************** +REMARKS: +Implements the INC instruction and side effects. +****************************************************************************/ +u16 inc_word(u16 d) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + 1; +    set_szp_flags_16((u16)res); +    calc_carry_chain(16, d, 1, res, 0); + +    return (u16)res; +} + +/**************************************************************************** +REMARKS: +Implements the INC instruction and side effects. +****************************************************************************/ +u32 inc_long(u32 d) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d + 1; +    set_szp_flags_32(res); +    calc_carry_chain(32, d, 1, res, 0); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u8 or_byte(u8 d, u8 s) +{ +    u8 res;    /* all operands in native machine order */ + +    res = d | s; +    no_carry_byte_side_eff(res); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u16 or_word(u16 d, u16 s) +{ +    u16 res;   /* all operands in native machine order */ + +    res = d | s; +    no_carry_word_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u32 or_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d | s; +    no_carry_long_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u8 neg_byte(u8 s) +{ +    u8 res; + +    CONDITIONAL_SET_FLAG(s != 0, F_CF); +    res = (u8)-s; +    set_szp_flags_8(res); +    calc_borrow_chain(8, 0, s, res, 0); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u16 neg_word(u16 s) +{ +    u16 res; + +    CONDITIONAL_SET_FLAG(s != 0, F_CF); +    res = (u16)-s; +    set_szp_flags_16((u16)res); +    calc_borrow_chain(16, 0, s, res, 0); + +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the OR instruction and side effects. +****************************************************************************/ +u32 neg_long(u32 s) +{ +    u32 res; + +    CONDITIONAL_SET_FLAG(s != 0, F_CF); +    res = (u32)-s; +    set_szp_flags_32(res); +    calc_borrow_chain(32, 0, s, res, 0); + +    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) +{ +    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) +{ +    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) +{ +    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) +{ +    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) +{ +    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) +{ +    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) +{ +    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) +{ +    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) +{ +    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); +            set_szp_flags_8((u8)res); +        } 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); +            set_szp_flags_16((u16)res); +        } 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); +            set_szp_flags_32((u32)res); +        } 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); +            set_szp_flags_8((u8)res); +        } 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); +            set_szp_flags_16((u16)res); +        } 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); +            set_szp_flags_32((u32)res); +        } 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; +        } +        set_szp_flags_8((u8)res); +    } 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; +        } +        set_szp_flags_16((u16)res); +    } 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; +        } +        set_szp_flags_32(res); +    } 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); +            set_szp_flags_16((u16)res); +        } 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); +            set_szp_flags_32((u32)res); +        } 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); +            set_szp_flags_16((u16)res); +        } 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); +            set_szp_flags_32((u32)res); +        } 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) +{ +    u32 res;   /* all operands in native machine order */ +    u32 bc; + +    if (ACCESS_FLAG(F_CF)) +        res = d - s - 1; +    else +        res = d - s; +    set_szp_flags_8((u8)res); + +    /* 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) +{ +    u32 res;   /* all operands in native machine order */ +    u32 bc; + +    if (ACCESS_FLAG(F_CF)) +        res = d - s - 1; +    else +        res = d - s; +    set_szp_flags_16((u16)res); + +    /* 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) +{ +    u32 res;   /* all operands in native machine order */ +    u32 bc; + +    if (ACCESS_FLAG(F_CF)) +        res = d - s - 1; +    else +        res = d - s; + +    set_szp_flags_32(res); + +    /* 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) +{ +    u32 res;   /* all operands in native machine order */ +    u32 bc; + +    res = d - s; +    set_szp_flags_8((u8)res); + +    /* 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) +{ +    u32 res;   /* all operands in native machine order */ +    u32 bc; + +    res = d - s; +    set_szp_flags_16((u16)res); + +    /* 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) +{ +    u32 res;   /* all operands in native machine order */ +    u32 bc; + +    res = d - s; +    set_szp_flags_32(res); + +    /* 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) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d & s; + +    CLEAR_FLAG(F_OF); +    set_szp_flags_8((u8)res); +    /* AF == dont care */ +    CLEAR_FLAG(F_CF); +} + +/**************************************************************************** +REMARKS: +Implements the TEST instruction and side effects. +****************************************************************************/ +void test_word(u16 d, u16 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d & s; + +    CLEAR_FLAG(F_OF); +    set_szp_flags_16((u16)res); +    /* AF == dont care */ +    CLEAR_FLAG(F_CF); +} + +/**************************************************************************** +REMARKS: +Implements the TEST instruction and side effects. +****************************************************************************/ +void test_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d & s; + +    CLEAR_FLAG(F_OF); +    set_szp_flags_32(res); +    /* AF == dont care */ +    CLEAR_FLAG(F_CF); +} + +/**************************************************************************** +REMARKS: +Implements the XOR instruction and side effects. +****************************************************************************/ +u8 xor_byte(u8 d, u8 s) +{ +    u8 res;    /* all operands in native machine order */ + +    res = d ^ s; +    no_carry_byte_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the XOR instruction and side effects. +****************************************************************************/ +u16 xor_word(u16 d, u16 s) +{ +    u16 res;   /* all operands in native machine order */ + +    res = d ^ s; +    no_carry_word_side_eff(res); +    return res; +} + +/**************************************************************************** +REMARKS: +Implements the XOR instruction and side effects. +****************************************************************************/ +u32 xor_long(u32 d, u32 s) +{ +    u32 res;   /* all operands in native machine order */ + +    res = d ^ s; +    no_carry_long_side_eff(res); +    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 == 0x0000) || +        ((M.x86.R_AX & 0x8000) != 0 && M.x86.R_DX == 0xFFFF)) { +        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 = (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 == 0x00000000) || +        ((M.x86.R_EAX & 0x80000000) != 0 && M.x86.R_EDX == 0xFFFFFFFF)) { +        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 = (u32)M.x86.R_EAX * (u32)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); +    set_parity_flag(mod); + +    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); +    set_parity_flag(mod); + +    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); +    set_parity_flag(mod); + +    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); +    set_parity_flag(mod); + +    M.x86.R_EAX = (u32)div; +    M.x86.R_EDX = (u32)mod; +} + +/**************************************************************************** +REMARKS: +Implements the IN string instruction and side effects. +****************************************************************************/ + +static void single_in(int size) +{ +    if(size == 1) +        store_data_byte_abs(M.x86.R_ES, M.x86.R_DI,(*sys_inb)(M.x86.R_DX)); +    else if (size == 2) +        store_data_word_abs(M.x86.R_ES, M.x86.R_DI,(*sys_inw)(M.x86.R_DX)); +    else +        store_data_long_abs(M.x86.R_ES, M.x86.R_DI,(*sys_inl)(M.x86.R_DX)); +} + +void ins(int size) +{ +    int inc = size; + +    if (ACCESS_FLAG(F_DF)) { +        inc = -size; +    } +    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { +        /* dont 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); + +        while (count--) { +          single_in(size); +          M.x86.R_DI += inc; +          } +        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 { +        single_in(size); +        M.x86.R_DI += inc; +    } +} + +/**************************************************************************** +REMARKS: +Implements the OUT string instruction and side effects. +****************************************************************************/ + +static void single_out(int size) +{ +     if(size == 1) +       (*sys_outb)(M.x86.R_DX,fetch_data_byte_abs(M.x86.R_ES, M.x86.R_SI)); +     else if (size == 2) +       (*sys_outw)(M.x86.R_DX,fetch_data_word_abs(M.x86.R_ES, M.x86.R_SI)); +     else +       (*sys_outl)(M.x86.R_DX,fetch_data_long_abs(M.x86.R_ES, M.x86.R_SI)); +} + +void outs(int size) +{ +    int inc = size; + +    if (ACCESS_FLAG(F_DF)) { +        inc = -size; +    } +    if (M.x86.mode & (SYSMODE_PREFIX_REPE | SYSMODE_PREFIX_REPNE)) { +        /* dont 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); +        while (count--) { +          single_out(size); +          M.x86.R_SI += inc; +          } +        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 { +        single_out(size); +        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) +{ +    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) +{ +    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; +} +  |