# Chapter 3

## CPU Flags

Flags are 1-bit values holding Boolean (logical) values after operations such as Add, Sub, etc. The CPU has a register with flags that indicate the following (other flags will be examined later):
• Carry (CF) - Addition and subtraction sets the carry flag to 1 when the result is invalid (too large).
• Overflow (OF) - Addition and subtraction sets the overflow flag to 1 when the result is invalid (the wrong sign).
• Sign (SF) - Addition and subtraction sets the sign flag to 1 when the result is negative (leftmost bit is 1), to 0 when positive (leftmost bit is 0).
• Zero (ZF) - Addition and subtraction sets the zero flag to 1 when the result is 0.

## Unsigned Binary Representation

```    5710 = 001110012            110 = 000000012      12810 = 100000002
410 = 000001002          12710 = 011111112      25510 = 111111112```

## Two's Complement Representation

Negative numbers only, convert from positive to negative by forming one's complement and adding 1. The following uses 8-bit values.
 ```                   Invert         +1              Binary      1's Comp    2's Comp     -5710 = -001110012  = 11000110  = 11000111 =   -5710               -410 =  -000001002  = 11111011  = 11111100 =    -410     -110 =  -000000012  = 11111110  = 11111111 =    -110   -12710 =  -011111112  = 10000000  = 10000001 =  -12710   -12810 =  -100000002 -> 01111111 -> 10000000 =  -12810   -12910 =  -100000012 -> 01111110 -> 10000000 != -12910        -25510 =  -111111112 -> 00000000 -> 00000001 != -25510```   Range of 8 bit two's complement   -28-1 to 28-1-1 or -128 to 127 Range of 16 bit two's complement   -216-1 to 216-1-1 or -32768 to 32767

The add and subtract operation can operate on signed or unsigned numbers, either 8 or 16-bit operands. The result is the same size as the operands so it is possible that incorrect results are produced when the result is too large or small. Remember that subtraction is performed by addition of a negative number.
• Unsigned - Addition and subtraction of unsigned numbers is invalid whenever there is a carry out, CF = 1 (CF is carry flag). The result is valid as an unsigned number when CF=0. The carry flag is the carry out from the leftmost bit for addition. For subtraction the carry out is inverted, a natural carry out of 1 is inverted by the CPU to 0 and vice versa.
• Signed - Addition and subtraction of of signed numbers is invalid whenever there is an overflow, OF = 1 (OF is overflow flag). The result is valid as a signed number when OF=0. The overflow flag is 0 when the carry in to the leftmost bits equals the carry out of the leftmost bit, otherwise OF=1.

 ```                     00000000               Carry into and out of leftmost   8 bits         110    000000012                 bit equal, OF=0. +8 bits        +110 = +000000012    8 bits         210   0000000102             Valid unsigned, CF=0.                       CF = 0    ZF = 0       Valid signed OF=0.                      OF = 0    SF = 0```
 ```          Unsigned   11111111       Signed    Carry into and out of leftmost.  8 bits       25510    111111112      -1       bit equal, OF=0 +8 bits        +110 = +000000012  =   +1  8 bits         010   1000000002       0       Invalid unsigned, CF=1.                       CF = 1    ZF = 1          Valid signed, OF=0. Mov Ah, 255          OF = 0    SF = 0 Add Ah, 1            Ah = 0```
 ```           Unsigned  11111111     Signed        Carry into and out of leftmost  8 bits         110    000000012      110         bit equal, OF=0. +8 bits      +25510 = +111111112 = +(-110)  8 bits         010   1000000002      0          Invalid unsigned, CF = 1.                       CF = 1    ZF = 1            Valid signed, OF = 0. Mov Ah, 1            OF = 0    SF = 0 Add Ah, 255 OR       Ah = 0 Add Ah, -1  ```
 ```          Unsigned   11111111      Signed       Carry into and out of leftmost  8 bits         110    000000012      110         bit equal, OF=0.  -8 bits        -110 = +111111112     -110  8 bits         010   1000000002      0          Valid unsigned, CF=0 since                       CF = 0    ZF = 1           inverted on subtraction Mov Ah, 1            OF = 0    SF = 0           Valid signed, OF=0. Sub Ah, 1            Ah = 0```
 ```          Unsigned   01111111      Signed      Carry into and out of leftmost  8 bits       12710    011111112     12710       bit equal, OF=0.  +8 bits        +110 = +000000012      +110  8 bits       12810   0100000002 =   -128       Valid unsigned 128, CF=0.                       CF = 0    ZF = 0          Invalid signed -128, OF=1. Mov Ah, 127          OF = 1    SF = 1     Add Ah, 1 ```
 ```          Unsigned   10000000        Signed     Carry in 0, carry out of leftmost  8 bits     12810      100000002       -12810     bit 1, OF=1. +8 bits    +12810   = +100000002     +(-128)10  8 bits       010     1000000002 =        0      Invalid unsigned CF=1.                        CF = 1    ZF = 1          Invalid signed OF=1. Mov Ah, 128           OF = 1    SF = 0   Add Ah, 128   ```

• Add - Adds two signed or unsigned numbers, OF=0 for valid signed, CF=0 for valid unsigned.
• Add    Al, 13                Al = Al + 13
• Add    Ah, Bh                Ah = Ah + Bh
• Add    Ax, X                 Ax = Ax + X        X must be 16-bit
• Sub - Subtracts two signed or unsigned numbers, OF=0 for valid signed, CF=0 for valid unsigned.
• Sub    Al, 13                Al = Al - 13
• Sub    Ah, Bh                Ah = Ah - Bh
• Sub    Ax, X                 Ax = Ax - X        X must be 16-bit

## Negation Instruction

Negation makes a positive number negative and a negative number positive. For example, -(+1) = -1, -(-1) = +1. Negation only makes sense for signed numbers. If an 8-bit -128 or a 16-bit -32768 is negated the result is invalid, OF=1. An example is:
```        Mov    Ah, -1
Neg    Ah                ;Ah is now +1```

## Increment and Decrement Instructions

Increment or decrement by one. The overflow, carry, zero, and sign flags have the same meaning as with addition and subtraction. Note that incrementing the 8-bit value 255 (or 16-bit 65535) rolls an unsigned number to 0. However, incrementing a signed number has the sequence of 126, 127, -128, -127, -126. For example:

```      Unsigned                     Signed
255        11111111            127        0111111
+1   =    00000001             +1    =  +0000001
0       100000000           -128       01000000
CF=1 Invalid unsigned           OF = 1 Invalid signed```
```Mov    Ch, 255                  Mov    Dh, 127
Inc    Ch                       Inc    Dh```

## Multiply Instruction

• Size - Multiplication produces a result that requires as many bits (or decimal digits) to store as the sum of the number of bits (or digits in any base) of the operands. Consider the following examples:
•

```    9        99        999        11012
*9        *9        *99        *1112
81       891      98901     10110112```
For 8-bit operands the maximum result is 16-bits in Ax register. Al is always one of the operands in 8-bit multiplication. If the result in Ax requires both the AH and Al registers, OF=1. An example is:

```                                   Mov    Al, 2        Mov    Al, 128
Al                 Al            Mov    Bl, 4        Mov    Bl, 4
*8-bit operand      *4            Mul    Bl           Mul    Bl
Ax                 Ax        Ah Al OF              Ah Al OF
00 08  0              02 00  1```
For 16-bit operands the maximum result is 32-bits in DX (high 16-bits) and Ax (low 16-bits). If the result in Dx:Ax requires both the Dx and Ax registers, OF=1. Ax is always one of the operands. An example is:
```                                   Mov    Ax, 2        Mov    Ax, 0FFFFh
Ax                 Ax            Mov    Bx, 4        Mov    Bx, 4
*16-bit operand     *4            Mul    Bx           Mul    Bx
Dx:Ax             Dx:Ax         Dx    Ax     OF    Dx     Ax    OF
0000  0008     0   0002   FFFC    1```
• Unsigned MUL- For unsigned the result is always positive.
• Signed IMUL - For signed, the result is negative if there is an odd number of negative operands, otherwise positive. For example:

```                                    Mov    Ax, 2         Mov    Ax, -2
Ax                  Ax            Mov    Bx, -4        Mov    Bx, -4
*16-bit operand     *-4            IMul   Bx            IMul   Bx
Dx:Ax             Dx:Ax         Dx    Ax     OF      Dx     Ax    OF
FFFF  FFF8     0     0000   0008    0```

## Division Instruction

• Size - Division produces two results, a quotient and remainder, either result can be too large to store. Consider how division is implemented.
• 8-bit divisor - Ax dividend, Al quotient, Ah remainder.
• 16-bit divisor - Dx:Ax dividend, Ax quotient, Dx remainder.

 ```               Al 8-bit quotient                      Ax 16-bit quotient     8-bit divisor/ Ax 16-bit dividend     16-bit divisor/ Dx:Ax 32-bit dividend                Ah 8-bit remainder                     Dx 16-bit remainder```

```                                                  Mov    Dx, 0
Mov    Ax, 23                         Mov    Ax, 23
Mov    Ch, 5                          Mov    Cx, 5
Div    Ch                             Div    Cx
Ah     Al                             Dx     Ax
03     04                            0003   0004

Mov    Dx, -1
Mov    Ax, -23                        Mov    Ax, -23
Mov    Ch, 5                          Mov    Cx, -5
Idiv   Ch                             Idiv   Cx
Ah=-3  Al=-4                           Dx=-3 Ax=4
FB     FC                             FFFB   0004```

• Unsigned DIV - For unsigned the quotient and remainder is always positive unless overflow occurs. An overflow in division causes the CPU to generate an interrupt of program execution. Either the programmer or operating system environment must handle the interrupt. This will be discussed in Chapter 9.
• Signed IDIV - For signed division the sign of the quotient and remainder are determined by usual rules for division based on the sign of the divisor and dividend as below:
•

 ```   +            -            -           +  +/+          +/-          -/+         -/-    +            -            +           -      +4          -4          -4          +4  +5/+23      +5/-23      -5/+23      -5/-23      +3          -3          +3          -3```

## Converting 8 to 16 bit (Cbw) or 16 to 32-bit (Cwd) or 32 to 64-bit (Cdq)

Because division always uses Ax (16-bit) or Dx:Ax (32-bit) in the dividend, it is often necessary to convert 8-bit Al to 16-bit Ax (or 16-bit Ax to 32-bit Dx:Ax). Consider the following attempt to divide 7/5 when Ah has a bogus value:

 ```              _    Al 8-bit quotient  8-bit divisor/ Ah:Al 16-bit dividend                    Ah 8-bit remainder  ```

```Mov    Al, 7                  _________ 001101012 = 52        Wrong!
Mov    Ah, 1      5=000001012/ 00000001 000001112 = 263
Mov    Dh, 5                            000000112 = 3
Div    Dh```
Obviously 52 is wrong! The problem is that Ah=1 was part of the 16-bit dividend in Ax. Ah should have been 0 for unsigned division. A similar problem can occur with signed division, suppose that we attempt -7/5 by:

```Mov    Al, -7                 _________ 011001012 = 10110        Wrong!
Mov    Ah, 1      5=000001012/ 00000001 111110012 = 507
Mov    Dh, 5                            000000102 = 2
Idiv   Dh```

The 10110 answer is even the wrong sign! What happened? The problem is that the sign of 8-bit Al needed to be extended into Ah to correctly convert an 8-bit negative into a 16-bit negative. To see that an 8-bit signed number can be converted to a 16-bit signed number consider adding more zeros to the left of any positive number, it is still the same positive number (e.g. 7=07=007=0007,...). The same is true for negative numbers in two's complement representation. A 4-bit -1=11112, as 5-bits -1=111112, as 10-bits -1=11111111112, etc. Converting a signed 8-bit number to a signed 16-bit number only requires extending the sign of the 8-bit number into all bits of the 16-bit number. For example, the following produces the
correct results for -7/5.

 ```Mov    Al, -7    Al=111110012 Mov    Ah, 1     Ah=000000012 Mov    Dh, 5  Cbw              Ah=111111112 Idiv   Dh``` ```                  ______ Al 111111112 = -1        Correct!       5=000001012/ 11111111 111110012 = -7                          Ah 111111102 = -2```

• Cbw - Convert a byte to a word by extending the sign bit of Al into Ah, if Al is negative (sign=1) Ah is filled with 1's, otherwise filled with 0's
• Cwd - Convert a word to a double word by extending the sign bit of Ax into Dx, if Axis negative (sign=1) Dx is filled with 1's, otherwise filled with 0's.
• Basic Division Rules
•

• Unsigned - Before division, move a 0 into either Ah or Dx. If Al or Ax has a 1 in the leftmost bit (sign bit), using Cbw or Cwd would fill Ah or Dx with all 1's.
•

```Mov    Al, 255            Mov    Ax, 65535
Mov    Dh, 10             Mov    Bx, 10000
Mov    Ah, 0              Mov    Dx, 0
Div    Dh                 Div    Bx```
• Signed - Before division, convert Al or Ax. If Al or Ax has a 1 in the leftmost bit (sign bit), using Cbw or Cwd would correctly fill Ah or Dx with all 1's.
•

```Mov    Al, -7            Mov    Ax, -7
Mov    Dh, 5             Mov    Bx, 5
Cbw                      Cwd
Idiv   Dh                Idiv    Bx```

## Input and Output Instructions

The author has supplied a library of functions for input and output of signed and unsigned 32-bit numbers. The functions are described below and a simple programming example to input two signed numbers, add and output their sum is given.(Chapter 5.3 in Irvine)

• ReadInt - Inputs a 32-bit signed number from the keyboard and stores into eAx.

Call    ReadInt          ; cin >> X
Mov   X, eAx

• ReadDec- Inputs a 32-bit unsigned number from the keyboard and stores into eAx.

Call    ReadDec         ; cin >> X
Mov   X, Ax

• WriteInt - Outputs a 32-bit signed number from eAx to the screen. Bh=0 to output with no spaces.

Mov   eAx, X             ; cout << X
Mov   Bh, 0
Call    WriteInt

• WriteDec - Outputs a 32-bit unsigned number from eAx to the screen. Bh=0 to output with no spaces.

Mov   eAx, X             ; cout << X
Mov   Bh, 0
Call    WriteDec

• WriteString - Outputs a null-terminated string starting at eDX to the screen.

; cout << Message
mov     eDX, offset Message
Call    WriteString

• NewLine - Output a new line to the screen.

Call    NewLine       ; cout << "\n";