Search code examples
assemblyx86integer-overflowcarryflageflags

ASM8086: mul, imul, carry flag and overflow flag


I understood the logic of the carry flag and the overflow flag. But, when I read this program (wrote in MASM 8086) , I got perplexed a bit.

The program intent is to tell if a quadratic equation has two distincts solutions, two equals solutions or no solutions at all.

.model small
.stack
.data
aa dw 2
bb dw 4
cc dw 2
sol_msg    db "There exist two real solutions", CR, NL
no_sol_msg db "No real solutions!            ", CR, NL
sol_coinc  db "The two solutions coincide!   ", CR, NL
.code
.startup
mov ax, bb
imul bb
jc overflow ; I decided to work at most with 16-bit numbers
push ax
mov ax, aa
imul cc
jc overflow
mov bx, 4
imul bx
jc overflow
pop bx
sub bx, ax
jo overflow
js mess2
jz mess3
lea si, sol_msg
jmp next
mess2: lea si, no_sol_msg
jmp next
mess3: lea si, sol_coinc
next: mov bx, LUNG_MSG
mov ah, 2
loop1: mov dl, [si]
INT 21h
inc si
dec bx
jnz loop1
jmp end1
overflow:
nop
end1: 
.exit
end

Now, my doubt is: why for the first three checks it has been tested the carry flag and for the last one the overflow flag?

Since in the last one, we do the subtraction between two signed numbers (as we think those), we have to check the overflow flag to see if there's an overflow (i.e. if the numbers goes beyond the interval[-2^15,2^15-1]). But for the first one, for example, we do (bb)^2 with imul.

So we think them as 16-bit signed numbers (so -2^15 <= bb <= 2^15-1 ) and, the multiplication set the CF/OF bit on if at least one sum (in the multiplication algorithm) get the CF/OF bit on.

But since we treat signed numbers, shouldn't we check the overflow flag ?

Also I noticed that, since 2^15-1=32767, if I set bb to 190 (190^2=36100) the CF=0; if bb equals 200 (200^2=40000) the CF=1.

Why is that? Could anybody explain me this in a detailed way, please?

P.S.: I'm using EMU8086.


Solution

  • If you have a look at the pseudo algorithm of IMUL in Intel's docs, you'll see

    IF OperandSize = 16
    THEN
      TMP_XP ← AX ∗ SRC (* Signed multiplication; TMP_XP is a signed integer at twice the width of the SRC *)
      DX:AX ← TMP_XP[31:0];
      SF ← TMP_XP[15];
      IF SignExtend(TMP_XP[15:0]) = TMP_XP
        THEN CF ← 0; OF ← 0;
        ELSE CF ← 1; OF ← 1;
      FI;
    FI;
    

    CF and OF either both set, or both cleared. So, you can check either flag after IMUL