1

I am writing an x86 interpreter in Java and have a Python script that tests my implementations of x86 instructions against its real counterparts using NASM. According to this test all flags are set correctly, besides the carry flag. The interesting part is:

long result;
    switch (op) {
    case ADD:
        result = Math.abs(x) + Math.abs(y);
        if (result > U_MAX)
            registers.carry_flag = true;
        else
            registers.carry_flag = false;
        break;

where U_MAX is 4294967295L (all 32 bits set).
All answers that I found didn't realize that carry and overflow are two different things. So, how can I implement the carry flag correctly in Java?

Benjoyo
  • 413
  • 7
  • 13

2 Answers2

2

All this absolute value business is unnecessary and frankly confusing and it has the edge-case that Math.abs(Integer.MIN_VALUE) is negative (not that weird when you get down to it, but it doesn't look like this code expects it), you can calculate the carry in simpler ways .

For example using the old "result is unsigned less than one operand". The result is of course just x + y (as int), signedness is irrelevant to addition. Then with Java 8, you can use Integer.compareUnsigned, otherwise you can use this identity:

x <u y = (x ^ Integer.MIN_VALUE) <s (y ^ Integer.MIN_VALUE)

where <u and <s are unsigned less than and signed less than, respectively.

You could also calculate (x & 0xffffffffL) + (y & 0xffffffffL) and use it for both the result (cast to int) and the carry flag (the 33th bit).

harold
  • 61,398
  • 6
  • 86
  • 164
  • (x & 0xffffffffL) + (y & 0xffffffffL) did pass all tests! Also I didn't know about compareUnsigned, thank you! – Benjoyo Jul 01 '15 at 21:56
  • @Benjoyo yea the same thing works for borrow, but instead of appearing only in the 33rd bit it goes in all 32 high bits – harold Jul 02 '15 at 07:38
  • sorry, I don't get what you mean. – Benjoyo Jul 02 '15 at 12:17
  • @Benjoyo `r = (x & 0xffffffffL) - (y & 0xffffffffL)`, cast to `int` to get the result, the high bits are all copies of the borrow flag (if it borrows into the high half, well it's all zero, so it then it borrows all the way through it). So you can check for borrow like `r < 0`. Or do it exactly the same way as you're doing now for addition. – harold Jul 02 '15 at 12:33
  • Ah, now I understand it, perfect thanks. But, at least for (current) x86 carry flag for subtraction seems to be set on `r > 0` instead of `r < 0`. – Benjoyo Jul 02 '15 at 14:16
  • @Benjoyo I don't think that's right, it shouldn't be set for `2 - 1` for example, then again you couldn't have swapped the operands, that would be immediately obvious.. so I don't know what happened there – harold Jul 02 '15 at 14:19
  • oh, you are right. I forgot that my sub instruction does y - x, because it's AT&T. So I had to swap it in the carry check. – Benjoyo Jul 02 '15 at 14:31
0

if x and y are integers, then Math.abs(x) and Math.abs(y) are integers. say x = y = Integer.MAX_VALUE, the result of adding Math.abs(x)+Math.abs(y) will be negative, as shown by this program:

public class t {
    public static void main(String args[]) {
        int x = Integer.MAX_VALUE;
        int y = Integer.MAX_VALUE;
        System.out.println(x+y);
    }
}

$ javac t.java
$ java t
 -2

So, you should either make x and y long, or cast to long before you add: result = ((long)Math.abs(x)) + ((long)Math.abs(y));

Roberto Attias
  • 1,883
  • 1
  • 11
  • 21