I am not sure if I should post this here or on bugzilla.

While trying to get a Silicon Motion SM722 video controller
working with Solaris, I have discovered a problem with the
emulation of the SHLD and SHRD (double precision shift)
instructions of the x86 emulator.
According to the Intel Pentium User Guide Vol 3, these
instructions can shift upto 31 bits with both 16 and 32
bit operands. The emulator code will only work with shifts
of upto 15 bits for 16 bit operands.

The file is 
xc/extras/x86emu/src/x86emu/prim_ops.c

I have modified the two functions as below.
I am not positive the flags are set correctly so
would appreciated someone else to check these.

u16 shld_word (u16 d, u16 fill, u8 s)
{
    unsigned int cnt, res, cf;

    if (s < 32) {
        cnt = s % 32;
        if (cnt > 0) {
            if (cnt > 15) {
                res = (unsigned int)fill << (cnt - 16);
                if (cnt == 16)
                    cf = d & 0x1;
                else
                    cf = res & 0x10000;
            }
            else {
                res = (d << cnt) | (fill >> (16-cnt));
                cf = d & (1 << (16 - cnt));
            }
            CONDITIONAL_SET_FLAG(cf, F_CF);
            CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
            CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
            CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
        } else {
            res = d;
        }
        if (cnt == 1) {
            CONDITIONAL_SET_FLAG((((res & 0x8000) == 0x8000) ^
                                  (ACCESS_FLAG(F_CF) != 0)), F_OF);
        } else {
            CLEAR_FLAG(F_OF);
        }
    } else {
        res = 0;
        CONDITIONAL_SET_FLAG((d << (s-1)) & 0x8000, F_CF);
        CLEAR_FLAG(F_OF);
        CLEAR_FLAG(F_SF);
        SET_FLAG(F_PF);
        SET_FLAG(F_ZF);
    }
    return (u16)res;
}


u16 shrd_word (u16 d, u16 fill, u8 s)
{
    unsigned int cnt, res, cf;

    if (s < 32) {
        cnt = s % 32;
        if (cnt > 0) {
            if (cnt > 15) {
                if (cnt == 16)
                    cf = d & 0x8000;
                else
                    cf = fill & (1 << (cnt - 17));
                res = fill >> (cnt - 16);
            } else {
                cf = d & (1 << (cnt - 1));
                res = (d >> cnt) | (fill << (16 - cnt));
            }
            CONDITIONAL_SET_FLAG(cf, F_CF);
            CONDITIONAL_SET_FLAG((res & 0xffff) == 0, F_ZF);
            CONDITIONAL_SET_FLAG(res & 0x8000, F_SF);
            CONDITIONAL_SET_FLAG(PARITY(res & 0xff), F_PF);
        } else {
            res = d;
        }

        if (cnt == 1) {
            CONDITIONAL_SET_FLAG(XOR2(res >> 14), F_OF);
        } else {
            CLEAR_FLAG(F_OF);
        }
    } else {
        res = 0;
        CLEAR_FLAG(F_CF);
        CLEAR_FLAG(F_OF);
        SET_FLAG(F_ZF);
        CLEAR_FLAG(F_SF);
        CLEAR_FLAG(F_PF);
    }
    return (u16)res;
}


Charles Dobson.
Concurrent Technologies Plc.

_______________________________________________
Devel mailing list
Devel@XFree86.Org
http://XFree86.Org/mailman/listinfo/devel

Reply via email to