Arithmetic instructions put their result in the first operand: ADD AX, BX means AX = AX + BX.
| Instruction | Does |
|---|---|
ADD d, s | d = d + s |
SUB d, s | d = d − s |
INC d / DEC d | d = d + 1 / d = d − 1 |
NEG d | d = 0 − d (changes the sign) |
ADC d, s / SBB d, s | the same as ADD / SUB, plus or minus the carry flag |
The flags
Every result also sets single bits in the FLAGS register. Later instructions read them: the jumps of lesson 6 decide by them.
| Flag | Set to 1 when the result... |
|---|---|
| ZF zero | is 0 |
| SF sign | has its top bit 1 (negative, as a signed number) |
| CF carry | did not fit as an unsigned number (a carry out of the top bit, or a borrow) |
| OF overflow | did not fit as a signed number |
| PF parity | has an even number of 1 bits in its low byte |
| AF auxiliary | carried out of the low 4 bits (used for decimal arithmetic) |
; What ADD and SUB do to the flags.
.MODEL SMALL
.STACK 100H
.CODE
MAIN PROC
MOV AL, 200
ADD AL, 100 ; 300 does not fit in a byte: AL = 44, CF = 1
MOV AL, 127
ADD AL, 1 ; 128 is too big for a signed byte: OF = 1, SF = 1
MOV AL, 5
SUB AL, 5 ; 0: ZF = 1
MOV AL, 3
SUB AL, 5 ; below 0: AL = FEh (-2), CF = 1, SF = 1
INC AL ; FFh (-1); INC leaves CF alone
NEG AL ; 0 - (-1) = 1
MOV AH, 4CH
INT 21H
MAIN ENDP
END MAINStep through it and watch the flags panel. 200 + 100 = 300 does not fit in a byte (0 to 255), so AL keeps 300 − 256 = 44 and CF = 1. 127 + 1 = 128 fits unsigned, but as a signed byte (−128 to 127) it overflows, so OF = 1 and SF = 1: the bits now read as −128.
One pattern, two meanings
The bits 11111111b are 255 as an unsigned number and −1 as a signed number (two's complement: to negate, flip every bit and add 1). The CPU does not know which you mean; it sets CF for the unsigned reading and OF for the signed one, and you choose which flag to look at. NEG AX with AX = 5 gives FFFBh, which is −5.
INC and DEC leave CF unchanged, which loops use to keep a carry across steps.
Numbers bigger than 16 bits
ADD a pair of registers at a time: add the low words with ADD, then the high words with ADC, which also adds the carry from the low words:
; Add two 32-bit numbers: 0001FFFFh + 00000001h = 00020000h.
.MODEL SMALL
.STACK 100H
.CODE
MAIN PROC
MOV DX, 0001H ; first number, high word
MOV AX, 0FFFFH ; first number, low word
MOV CX, 0000H ; second number, high word
MOV BX, 0001H ; second number, low word
ADD AX, BX ; low words: FFFFh + 1 = 0000h, CF = 1
ADC DX, CX ; high words plus the carry: 1 + 0 + 1 = 2, so DX:AX = 0002:0000h
MOV AH, 4CH
INT 21H
MAIN ENDP
END MAINCommon mistakes
- Expecting a byte to hold 300: it wraps round, and CF tells you so.
- Reading CF as a signed overflow. CF is for unsigned numbers; OF is for signed ones.
- Expecting INC to set CF when a register wraps from FFFFh to 0: it sets ZF instead.
- Writing
ADD 5, AX: the result needs a place, so the destination comes first.
Quick check
My notes
Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.