Conclusion : the computation of the V flag in qemu is correct, and their is no special case to consider if the C flag is set or not :-) For tomorrow, the formal proof of the correctness of the whole qemu code ;-)

Thanks for the superb analysis!

Now it's time to check if real hardware works according to theory.

In this addition, there is a carry from lower 32 bits as well as sign change:
./addx -1 0x7fffffff 1 0
7fffffffffffffff + 1 = 8000000000000000, NZVC: 10
qemu-sparc ./addx  -1 0x7fffffff  1 0
7fffffffffffffff + 1 = 8000000000000000, NZVC: 10

Here, no carry:
./addx -1 0x7fffffff 0 1
7fffffffffffffff + 100000000 = 80000000ffffffff, NZVC: 10
qemu-sparc ./addx  -1 0x7fffffff 0 1
7fffffffffffffff + 100000000 = 80000000ffffffff, NZVC: 10

Another case:
./addx 0 0x80000000 0 0x80000000
8000000000000000 + 8000000000000000 = 0, NZVC: 7
qemu-sparc ./addx 0 0x80000000 0 0x80000000
8000000000000000 + 8000000000000000 = 0, NZVC: 7

Looks fine to me. There was a sign extension problem in the test program, fixed version attached.

_________________________________________________________________
Express yourself instantly with MSN Messenger! Download today it's FREE! http://messenger.msn.click-url.com/go/onm00200471ave/direct/01/
#include <stdlib.h>
#include <stdio.h>

void addx_test(unsigned int a, unsigned int b, unsigned int c, unsigned int d)
{
    unsigned int flags, result1, result2;

    asm ("addcc %3,%5,%1\n\t"
         "addxcc %4,%6,%2\n\t"
         "mov 0, %0\n\t"
         "bcc 1f\n\t"
         " nop\n\t"
         "mov 1, %0\n\t"
         "1: \n\t"
         "bvc 1f\n\t"
         " nop\n\t"
         "or %0, 2, %0\n\t"
         "1: \n\t"
         "bnz 1f\n\t"
         " nop\n\t"
         "or %0, 4, %0\n\t"
         "1: \n\t"
         "bpos 1f\n\t"
         " nop\n\t"
         "or %0, 8, %0\n\t"
         "1: \n\t"
         : "=r" (flags), "=r" (result1), "=r" (result2) : "r" (a), "r" (b), "r" (c), "r" (d));
    printf("%llx + %llx = %llx, NZVC: %d\n", ((unsigned long long)b << 32) | (unsigned long long)a, 
           ((unsigned long long)d << 32) | (unsigned long long)c,
           ((unsigned long long)result2 << 32) | (unsigned long long)result1,
           flags);
}

int main(int argc, const char **argv)
{
    unsigned int a, b, c, d;

    if (argc != 5)
        return 1;
    a = strtoul(argv[1], NULL, 0);
    b = strtoul(argv[2], NULL, 0);
    c = strtoul(argv[3], NULL, 0);
    d = strtoul(argv[4], NULL, 0);
    addx_test(a, b, c, d);

    return 0;
}

_______________________________________________
Qemu-devel mailing list
Qemu-devel@nongnu.org
http://lists.nongnu.org/mailman/listinfo/qemu-devel

Reply via email to