Commit 29851ee7 authored by Petar Jovanovic's avatar Petar Jovanovic Committed by Aurelien Jarno
Browse files

target-mips: fix calculation of overflow for SHLL.PH and SHLL.QB



This change corrects and simplifies how discard is calculated for shift
left logical vector instructions. It is used to detect overflow and set bit
22 in the DSPControl register.

The existing tests (shll_ph.c, shll_qb.c) are extended with the corner cases
that expose incorrectness in the previous implementation.

Signed-off-by: default avatarPetar Jovanovic <petar.jovanovic@imgtec.com>
Signed-off-by: default avatarAurelien Jarno <aurelien@aurel32.net>
parent 8ca27ce2
Loading
Loading
Loading
Loading
+6 −24
Original line number Diff line number Diff line
@@ -682,49 +682,31 @@ static inline uint8_t mipsdsp_sat8_reduce_precision(uint16_t a,

static inline uint8_t mipsdsp_lshift8(uint8_t a, uint8_t s, CPUMIPSState *env)
{
    uint8_t sign;
    uint8_t discard;

    if (s == 0) {
        return a;
    } else {
        sign = (a >> 7) & 0x01;
        if (sign != 0) {
            discard = (((0x01 << (8 - s)) - 1) << s) |
                      ((a >> (6 - (s - 1))) & ((0x01 << s) - 1));
        } else {
            discard = a >> (6 - (s - 1));
        }
    if (s != 0) {
        discard = a >> (8 - s);

        if (discard != 0x00) {
            set_DSPControl_overflow_flag(1, 22, env);
        }
        return a << s;
    }
    return a << s;
}

static inline uint16_t mipsdsp_lshift16(uint16_t a, uint8_t s,
                                        CPUMIPSState *env)
{
    uint8_t  sign;
    uint16_t discard;

    if (s == 0) {
        return a;
    } else {
        sign = (a >> 15) & 0x01;
        if (sign != 0) {
            discard = (((0x01 << (16 - s)) - 1) << s) |
                      ((a >> (14 - (s - 1))) & ((0x01 << s) - 1));
        } else {
            discard = a >> (14 - (s - 1));
        }
    if (s != 0) {
        discard = (int16_t)a >> (15 - s);

        if ((discard != 0x0000) && (discard != 0xFFFF)) {
            set_DSPControl_overflow_flag(1, 22, env);
        }
        return a << s;
    }
    return a << s;
}


+32 −1
Original line number Diff line number Diff line
@@ -11,7 +11,38 @@ int main()
    resultdsp = 1;

    __asm
        ("shll.ph %0, %2, 0x0B\n\t"
        ("wrdsp $0\n\t"
         "shll.ph %0, %2, 0x0B\n\t"
         "rddsp %1\n\t"
         : "=r"(rd), "=r"(dsp)
         : "r"(rt)
        );
    dsp = (dsp >> 22) & 0x01;
    assert(dsp == resultdsp);
    assert(rd  == result);

    rt        = 0x7fff8000;
    result    = 0xfffe0000;
    resultdsp = 1;

    __asm
        ("wrdsp $0\n\t"
         "shll.ph %0, %2, 0x01\n\t"
         "rddsp %1\n\t"
         : "=r"(rd), "=r"(dsp)
         : "r"(rt)
        );
    dsp = (dsp >> 22) & 0x01;
    assert(dsp == resultdsp);
    assert(rd  == result);

    rt        = 0x00000001;
    result    = 0x00008000;
    resultdsp = 1;

    __asm
        ("wrdsp $0\n\t"
         "shll.ph %0, %2, 0x0F\n\t"
         "rddsp %1\n\t"
         : "=r"(rd), "=r"(dsp)
         : "r"(rt)
+21 −2
Original line number Diff line number Diff line
@@ -11,12 +11,14 @@ int main()
    resultdsp = 0x00;

    __asm
        ("shll.qb %0, %2, 0x00\n\t"
        ("wrdsp $0\n\t"
         "shll.qb %0, %2, 0x00\n\t"
         "rddsp   %1\n\t"
         : "=r"(rd), "=r"(dsp)
         : "r"(rt)
        );
    dsp = (dsp >> 22) & 0x01;
    assert(dsp == resultdsp);
    assert(rd == result);

    rt     = 0x87654321;
@@ -24,12 +26,29 @@ int main()
    resultdsp = 0x01;

    __asm
        ("shll.qb %0, %2, 0x03\n\t"
        ("wrdsp $0\n\t"
         "shll.qb %0, %2, 0x03\n\t"
         "rddsp   %1\n\t"
         : "=r"(rd), "=r"(dsp)
         : "r"(rt)
        );
    dsp = (dsp >> 22) & 0x01;
    assert(dsp == resultdsp);
    assert(rd == result);

    rt     = 0x00000001;
    result = 0x00000080;
    resultdsp = 0x00;

    __asm
        ("wrdsp $0\n\t"
         "shll.qb %0, %2, 0x07\n\t"
         "rddsp   %1\n\t"
         : "=r"(rd), "=r"(dsp)
         : "r"(rt)
        );
    dsp = (dsp >> 22) & 0x01;
    assert(dsp == resultdsp);
    assert(rd == result);

    return 0;