Chapter 6 - Conditional Processing
===
## 6.2 Boolean and Comparison Instructions
| Operation | Description |
|:--------- |:------------------------------------------------------------------------------------------------------------ |
| AND | Boolean AND operation between a source operand and a destination operand. |
| OR | Boolean OR operation between a source operand and a destination operand. |
| XOR | Boolean exclusive-OR operation between a source operand and a destination operand. |
| NOT | Boolean NOT operation on a destination operand. |
| TEST | Implied boolean AND operation between a source and destination operand, setting the CPU flags appropriately. |
### 6.2.1 The CPU Status Flags
- The `Zero flag` is set when the result of an operation equals zero.
- The `Carry flag` is set when an operation generates a carry out of the highest bit of the destination operand.
- The `Sign flag` is a copy of the high bit of the destination operand, indicating that it is negative if *set* and positive if *clear*. (Zero is assumed to be positive.)
- The `Overflow flag` is set when an instruction generates a result that is outside the signed range of the destination operand.
- The `Parity flag` is set when an instruction generates an even number of 1 bits in the low byte of the destination operand.
### 6.2.2 AND Instruction
The AND instruction performs a boolean (bitwise) AND operation between each pair of matching bits in two operands and places the result in the destination operand:
```x86asm
AND destination,source
```
***Flags*** The AND instruction always clears the Overflow and Carry flags. It modifies the Sign, Zero, and Parity flags in a way that is consistent with the value assigned to the destina tion operand. For example, suppose the following instruction results in a value of Zero in the EAX register. In that case, the Zero flag will be set:
```x86asm
and eax,1Fh
```
***Converting Characters to Upper case***
The AND instruction provides an easy way to translate a letter from lowercase to uppercase. If we compare the ASCII codes of capital A and lowercase a, it becomes clear that only bit 5 is different:
```x86asm
0 1 1 0 0 0 0 1 = 61h ('a')
0 1 0 0 0 0 0 1 = 41h ('A')
```
The rest of the alphabetic characters have the same relationship. If we AND any character with 11011111 binary, all bits are unchanged except for bit 5, which is cleared. In the following example, all characters in an array are converted to uppercase:
```x86asm=
.data
array BYTE 50 DUP(?)
.code
mov ecx,LENGTHOF array
mov esi,OFFSET array
L1: and BYTE PTR [esi],11011111b ; clear bit 5
inc esi
loop L1
```
### 6.2.3 OR Instruction
The OR instruction performs a boolean OR operation between each pair of matching bits in two operands and places the result in the destination operand:
```x86asm
OR destination,source
```
***Flags*** The OR instruction always clears the Carry and Overflow flags. It modifies the Sign, Zero, and Parity flags in a way that is consistent with the value assigned to the destination oper and. For example, you can OR a number with itself (or zero) to obtain certain information about its value:
```x86asm
or al,al
```
The values of the Zero and Sign flags indicate the following about the contents of AL:
| Zero Flag | Sign Flag | Value in AL Is ... |
|:---------:|:---------:|:------------------:|
| Clear | Clear | > 0 |
| Set | Clear | = 0 |
| Clear | Set | < 0 |
### 6.2.5 XOR Instruction
```x86asm
XOR destination,source
```
***Flags*** The XOR instruction always clears the Overflow and Carry flags. XOR modifies the Sign, Zero, and Parity flags in a way that is consistent with the value assigned to the destination operand.
### 6.2.6 NOT Instruction
The NOT instruction toggles (inverts) all bits in an operand. The result is called the one’s com plement. The following operand types are permitted:
```x86asm
NOT reg
NOT mem
```
***Flags*** No flags are affected by the NOT instruction.
### 6.2.7 TEST Instruction
***Flags*** The TEST instruction always clears the Overflow and Carry flags. It modifies the Sign, Zero, and Parity flags in the same way as the AND instruction.
### 6.2.8 CMP Instruction
The CMP (compare) instruction performs an implied subtraction of a source operand from a destination operand. Neither operand is modified:
```x86asm
CMP destination,source
```
***Flags*** The CMP instruction changes the Overflow, Sign, Zero, Carry, Auxiliary Carry, and Parity flags according to the value the destination operand would have had if actual subtraction had taken place. When two unsigned operands are compared, the Zero and Carry flags indicate the following relations between operands:
| CMP Results | ZF | CF |
|:--------------------:|:---:|:---:|
| Destination < source | 0 | 1 |
| Destination > source | 0 | 0 |
| Destination = source | 1 | 0 |
When two signed operands are compared, the Sign, Zero, and Overflow flags indicate the fol lowing relations between operands:
| CMP Results | Flags |
|:--------------------:|:--------:|
| Destination < source | SF != OF |
| Destination > source | SF = OF |
| Destination = source | ZF = 1 |
### 6.2.9 Setting and Clearing Individual CPU Flags
```x86asm
test al,0 ; set Zero flag
and al,0 ; set Zero flag
or al,1 ; clear Zero flag
```
```x86asm
or al,80h ; set Sign flag
and al,7Fh ; clear Sign flag
```
```x86asm
stc ; set Carry flag
clc ; clear Zero flag
```
```x86asm
mov al,7Fh ; AL = +127
inc al ; AL = 80h (-128), OF=1
or eax,0 ; clear Overflow flag
```
### 6.2.10 Boolean Instructions in 64-Bit Mode
```x86asm=
.data
allones QWORD 0FFFFFFFFFFFFFFFFh
.code
mov rax,allones ; RAX = FFFFFFFFFFFFFFFF
and rax,80h ; RAX = 0000000000000080
mov rax,allones ; RAX = FFFFFFFFFFFFFFFF
and rax,8080h ; RAX = 0000000000008080
mov rax,allones ; RAX = FFFFFFFFFFFFFFFF
and rax,808080h ; RAX = 0000000000808080
mov rax,allones ; RAX = FFFFFFFFFFFFFFFF
and rax,80808080h ; RAX = FFFFFFFF80808080
```
### 6.2.11 Section Review
1. Write a single instruction using 16-bit operands that clears the high 8 bits of AX and does not change the low 8 bits.
:::success
and ax,00FFh
:::
2. Write a single instruction using 16-bit operands that sets the high 8 bits of AX and does not change the low 8 bits.
:::success
or ax,0FF00h
:::
3. Write a single instruction (other than NOT) that reverses all the bits in EAX.
:::success
xor eax,0FFFFFFFFh
:::
4. Write instructions that set the Zero flag if the 32-bit value in EAX is even and clear the Zero flag if EAX is odd.
:::success
test eax,1 ; (low bit set if eax is odd)
:::
5. Write a single instruction that converts an uppercase character in AL to lowercase but does not modify AL if it already contains a lowercase letter.
:::success
or al,00100000b
:::
## 6.3 Conditional Jumps
### 6.3.2 Jcond Instruction
A *conditional jump instruction* branches to a destination label when a status flag condition is true. Otherwise, if the flag condition is false, the instruction immediately following the condi tional jump is executed. The syntax is as follows:
```x86asm
Jcond destination
```
*cond* refers to a flag condition identifying the state of one or more flags. The following examples are based on the Carry and Zero flags:
| JC | Jump if carry (Carry flag set) |
|:--- |:------------------------------------ |
| JNC | Jump if not carry (Carry flag clear) |
| JZ | Jump if zero (Zero flag set) |
| JNZ | Jump if not zero (Zero flag clear) |
### 6.3.3 Types of Conditional Jump Instructions
| Mnemonic | Description | Flags / Registers |
|:-------- |:------------------------ |:-----------------:|
| JZ | Jump if zero | ZF = 1 |
| JNZ | Jump if not zero | ZF = 0 |
| JC | Jump if carry | CF = 1 |
| JNC | Jump if not carry | CF = 0 |
| JO | Jump if zero | ZF = 1 |
| JNO | Jump if not zero | ZF = 0 |
| JS | Jump if signed | SF = 1 |
| JNS | Jump if not signed | SF = 0 |
| JP | Jump if parity (even) | PF = 1 |
| JNP | Jump if not parity (odd) | PF = 0 |
| Mnemonic | Description |
|:-------- |:----------------------------- |
| JE | Jump if equal |
| JNE | Jump if not equal |
| JCXZ | Jump if CX = 0 |
| JECXZ | Jump if ECX = 0 |
| JRCXZ | Jump if RCX = 0 (64-bit mode) |
| Mnemonic | Description |
|:-------- |:------------------------------- |
| JA | Jump if above |
| JNBE | Jump if not below or equal |
| JAE | Jump if above or equal |
| JNB | Jump if not below |
| JB | Jump if below |
| JNAE | Jump if not above or equal |
| JBE | Jump if below or equal |
| JNA | Jump if not above (same as JBE) |
| Mnemonic | Description |
|:-------- |:--------------------------------- |
| JG | Jump if greater |
| JNLE | Jump if not less than or equal |
| JGE | Jump if greater than or equal |
| JNL | Jump if not less |
| JL | Jump if less |
| JNGE | Jump if not greater than or equal |
| JLE | Jump if less than or equal |
| JNG | Jump if not greater (same as JLE) |
### 6.3.4 Conditional Jump Applications
*Larger of Two Integers*
The following code compares the unsigned integers in EAX and EBX and moves the larger of the two to EDX:
```x86asm=
mov edx,eax ; assume EAX is larger
cmp eax,ebx ; if EAX is >= EBX
jae L1 ; jump to L1
mov edx,ebx ; else move EBX to EDX
L1: ; EDX contains the larger integer
```
*Smallest of Three Integers*
The following instructions compare the unsigned 16-bit values in the variables V1, V2, and V3 and move the smallest of the three to AX:
```x86asm=
.data
V1 WORD ?
V2 WORD ?
V3 WORD ?
.code
mov ax,V1 ; assume V1 is smallest
cmp ax,V2 ; if AX <= V2
jbe L1 ; jump to L1
mov ax,V2 ; else move V2 to AX
L1: cmp ax,V3 ; if AX <= V3
jbe L2 ; jump to L2
mov ax,V3 ; else move V3 to AX
L2:
```
*Loop until Key Pressed*
In the following 32-bit code, a loop runs continuously until the user presses a standard alphanumeric key. The *ReadKey* method from the Irvine32 library sets the Zero flag if no key is present in the input buffer:
```x86asm=
.data
char BYTE ?
.code
L1: mov eax,10 ; create 10 ms delay
call Delay
call ReadKey ; check for key
jz L1 ; repeat if no key
mov char,AL ; save the character
```
### 6.3.5 Section Review
1. Which jump instructions follow unsigned integer comparisons?
:::success
JA, JNBE, JAE, JNB, JB, JNAE, JBE, JNA
:::
2. Which jump instructions follow signed integer comparisons?
:::success
JG, JNLE, JGE, JNL, JL, JNGE, JLE, JNG
:::
3. Which conditional jump instruction is equivalent to JNAE?
:::success
JB is equivalent to JNAE.
:::
4. Which conditional jump instruction is equivalent to the JNA instruction?
:::success
JBE
:::
5. Which conditional jump instruction is equivalent to the JNGE instruction?
:::success
JL
:::
6. *(Yes/No):* Will the following code jump to the label named **Target**?
```x86asm
mov ax,8109h
cmp ax,26h
jg Target
```
:::success
No (8109h is negative and 26h is positive).
:::
## 6.4 Conditional Loop Instructions
### 6.4.3 Section Review
1. *(True/False):* The LOOPE instruction jumps to a label when (and only when) the Zero flag is clear.
:::success
False
:::
2. *(True/False):* In 32-bit mode, the LOOPNZ instruction jumps to a label when ECX is greater than zero and the Zero flag is clear.
:::success
True
:::
3. *(True/False):* The destination label of a LOOPZ instruction must be no farther than -128 or +127 bytes from the instruction immediately following LOOPZ.
:::success
True
:::
4. Modify the LOOPNZ example in Section 6.4.2 so that it scans for the first negative value in the array. Change the array initializers so they begin with positive values.
:::success
```x86asm=
.data
array SWORD 3,5,14,-3,-6,-1,-10,10,30,40,4
sentinel SWORD 0
.code
main PROC
mov esi,OFFSET array
mov ecx,LENGTHOF array
next:
test WORD PTR [esi],8000h ; test sign bit
pushfd ; push flags on stack
add esi,TYPE array
popfd ; pop flags from stack
loopz next ; continue loop while ZF=1
jz quit ; none found
sub esi,TYPE array ; ESI points to value
```
:::
5. *Challenge:* The LOOPNZ example in Section 6.4.2 relies on a sentinel value to handle the possibility that a positive value might not be found. What might happen if you removed the sentinel?
:::success
If a matching value were not found, ESI would end up pointing beyond the end of the array. By pointing at an undefined memory location, a program runs the risk of causing a runtime error.
:::
## 6.5 Conditional Structures
### 6.5.5 Section Review
*Notes:* In all compound expressions, use short-circuit evaluation. Assume that **val1** and **X** are 32-bit variables.
1. Implement the following pseudocode in assembly language:
```x86asm
if ebx > ecx
X = 1
```
:::success
```x86asm=
cmp ebx,ecx
jna next
mov X,1
next:
```
:::
2. Implement the following pseudocode in assembly language:
```x86asm
if edx <= ecx
X = 1
else
X = 2
```
:::success
```x86asm=
cmp edx,ecx
jnbe L1
mov X,1
jmp next
L1: mov X,2
next:
```
:::
3. In the program from Section 6.5.4, why is it better to let the assembler calculate NumberOfEntries rather than assigning a constant such as NumberOfEntries 4?
:::success
Future changes to the table will alter the value of NumberOfEntries. We might forget to update the constant manually, but the assembler can correctly adjust a calculated value.
:::
4. *Challenge:* Rewrite the code from Section 6.5.3 so it is functionally equivalent, but uses fewer instructions.
:::success
```x86asm=
.data
sum DWORD 0
sample DWORD 50
array DWORD 10,60,20,33,72,89,45,65,72,18
ArraySize = ($ - Array) / TYPE array
.code
mov eax,0 ; sum
mov edx,sample
mov esi,0 ; index
mov ecx,ArraySize
L1: cmp esi,ecx
jnl L5
cmp array[esi*4],edx
jng L4
add eax,array[esi*4]
L4: inc esi
jmp L1
L5: mov sum,eax
```
:::
## 6.6 Application: Finite-State Machines
### 6.6.3 Section Review
1. A finite-state machine is a specific application of what type of data structure?
:::success
A directed graph.
:::
2. In a finite-state machine diagram, what do the nodes represent?
:::success
Each node is a state.
:::
3. In a finite-state machine diagram, what do the edges represent?
:::success
Each edge is a transition from one state to another, caused by some input.
:::
4. In the signed integer finite-state machine (Section 6.6.2), which state is reached when the input consists of "+5"?
:::success
State C.
:::
5. In the signed integer finite-state machine (Section 6.6.2), how many digits can occur after a minus sign?
:::success
An infinite number of digits.
:::
6. What happens in a finite-state machine when no more input is available and the current state is a nonterminal state?
:::success
The FSM enters an error state.
:::
7. Would the following simplification of a signed decimal integer finite-state machine work just as well as the one shown in Section 6.6.2? If not, why not?

:::success
No. The proposed FSM would permit a signed integer to consist of only a plus (+) or minus (-) sign. The FSM in Section 6.6.2 would not permit that.
:::
## 6.7 Conditional Control Flow Directives
| Directive | Description |
|:------------------- |:------------------------------------------------------------------------------------------------------------------------------------------ |
| .BREAK | Generates code to terminate a .WHILE or .REPEAT block |
| .CONTINUE | Generates code to jump to the top of a .WHILE or .REPEAT block |
| .ELSE | Begins block of statements to execute when the .IF condition is false |
| .ELSEIF *condition* | Generates code that tests *condition* and executes statements that follow, until an .ENDIF directive or another .ELSEIF directive is found |
| .ENDIF | Terminates a block of statements following an .IF, .ELSE, or .ELSEIF directive |
| .ENDW | Terminates a block of statements following a .WHILE directive |
| .IF *condition* | Generates code that executes the block of statements if *condition* is true. |
| .REPEAT | Generates code that repeats execution of the block of statements until *condition* becomes true |
| .UNTIL *condition* | Generates code that repeats the block of statements between .REPEAT and .UNTIL until *condition* becomes true |
| .UNTILCXZ | Generates code that repeats the block of statements between .REPEAT and .UNTILCXZ until CX equals zero |
| .WHILE *condition* | Generates code that executes the block of statements between .WHILE and .ENDW as long as *condition* is true |
### 6.7.1 Creating IF Statements
The .IF, .ELSE, .ELSEIF, and .ENDIF directives make it easy for you to code multiway branching logic. They cause the assembler to generate CMP and conditional jump instructions in the background, which appear in the output listing file (*progname*.lst). This is the syntax:
```x86asm
.IF condition1
statements
[.ELSEIF condition2
statements ]
[.ELSE
statements ]
.ENDIF
```
## 6.10 Review Questions and Exercises
### 6.10.1 Short Answer
1. What will be the value of BX after the following instructions execute?
```x86asm
mov bx,0FFFFh
and bx,6Bh
```
ans :
> 0FFFFh = 0000 1111 1111 1111 1111
> 6Bh = 0000 0000 0000 0110 1011
> ANS = 0000 0000 0000 0110 1011
:::success
BX = 006Bh
:::
2. What will be the value of AX after the following instructions execute?
```x86asm
mov ax,0fe4h
and ax,7865h
```
ans :
> 0fe4h = 0000 1111 1110 0100
> 7865h = 0111 1000 0110 0101
> ANS = 0000 1000 0110 0100
:::success
AX = 0864h
:::
3. What will be the value of BX after the following instructions execute?
```x86asm
mov bx,0649Bh
or bx,3Ah
```
ans :
> 0649Bh = 0000 0110 0100 1001 1011
> 3Ah = 0000 0000 0000 0011 1010
> ans = 0000 0110 0100 1011 1011
:::success
BX = 064BBh
:::
4. What will be the value of BX after the following instructions execute?
```x86asm
mov bx,029D6h
xor bx,8181h
```
ans :
> 029D6h = 0000 0010 1001 1101 0110
> 8181h = 0000 1000 0001 1000 0001
> ans = 0000 1010 1000 0101 0111
:::success
BX = 0A857h
:::
5. What will be the value of AX after the following instructions execute?
```x86asm
mov ax,7896h
or ax,0fffh
```
ans :
> 7896h = 0111 1000 1001 0110
> 0fffh = 0000 1111 1111 1111
> ans = 0111 1111 1111 1111
:::success
AX = 7fffh
:::
6. What will be the value of RBX after the following instructions execute?
```x86asm
mov rbx,0AFAF649Bh
xor rbx,0FFFFFFFFh
```
ans :
> 0AFAF649Bh = 0000 1010 1111 1010 1111 0110 0100 1001 1011
> 0FFFFFFFFh = 0000 1111 1111 1111 1111 1111 1111 1111 1111
> ans = 0000 0101 0000 0101 0000 1001 1011 0110 0100
:::success
RBX = 0000000050509B64h
:::
7. In the following instruction sequence, show the resulting value of AL where indicated, in binary:
```x86asm
mov al,01101111b
and al,00101101b ; a.
mov al,6Dh
and al,4Ah ; b.
mov al,00001111b
or al,61h ; c.
mov al,94h
xor al,37h ; d.
```
:::success
a. 0010 1101b
b. 0000 0000 0100 1000b
c. 0110 1111b
d. 1010 0011b
:::
8. Given that AX, BX, and CX are initially set to 009Eh, 325Dh, and 4709h, what will be the values of the destination operand, ZF, and CF, after each of the following instructions executes?
```x86asm
and bx,cx ; a.
or ax,bx ; b.
xor ax,cx ; c.
test ax,cx ; d.
cmp al,cl ; e.
cmp ax,bx ; f.
test al,bl ; g.
and ah,ch ; h.
```
:::success
a.
b.
c.
d.
e.
f.
g.
h.
:::
9. In the following instruction sequence, show the values of the Carry, Zero, and Sign flags where indicated:
```x86asm
mov al,00001111b
test al,00000010b ; a. CF= ZF= SF=
mov al,00000110b
cmp al,00000101b ; b. CF= ZF= SF=
mov al,00000101b
cmp al,00000111b ; c. CF= ZF= SF=
```
:::success
a. CF = 0 , ZF = 0 , SF = 0
b. CF = 0 , ZF = 0 , SF = 0
c. CF = 1 , ZF = 0 , SF = 1
:::
10. Which conditional jump instruction executes a branch based on the contents of ECX?
:::success
JECX
:::
11. How are JA and JNBE affected by the Zero and Carry flags?
:::success
JA and JNBE jump to the destination if ZF = 0 and CF = 0
:::
12. What will be the final value in EDX after this code executes?
```x86asm
mov edx,1
mov eax,7FFFh
cmp eax,8000h
jl L1
mov edx,0
L1:
```
:::success
EDX = 1
:::
13. What will be the value of the destination operand after the following instructions execute? Will control jump to location OK after the instructions have executed? What will be the state of the Carry and Zero flags after the comparison instruction executes?
```x86asm
mov ax,9878h
mov bx,4567h
add bx,5432h
cmp ax,bx
jc OK
```
14. What will be the final value in EDX after this code executes?
```x86asm
mov edx,1
mov eax,7FFFh
cmp eax,0FFFF8000h
jl L2
mov edx,0
L2:
```
:::success
EDX = 0
:::
15. *(True/False):* The following code will jump to the label named **Target**.
```x86asm
mov eax,-30
cmp eax,-50
jg Target
```
:::success
True
:::
16. Will the jump to NUM be made after the comparison instruction executes?
```x86asm
mov ax,-25
mov bx,-345
jge NUM
```
:::success
True
:::
17. What will be the value of RBX after the following instructions execute?
```x86asm
mov rbx,0FFFFFFFFFFFFFFFFh
and rbx,80h
```
:::success
RBX = 00000000000000080h
:::
18. What will be the value of RBX after the following instructions execute?
```x86asm
mov rbx,0FFFFFFFFFFFFFFFFh
and rbx,808080h
```
:::success
RBX = 0FFFFFFFFFF808080h
:::
19. What will be the value in AL after the following instructions execute?
```x86asm
mov al,’d’
and al,‘c’
```
### 6.10.2 Algorithm Workbench
1. Write a single instruction that converts an ASCII digit in AL to its corresponding binary value. If AL already contains a binary value (00h to 09h), leave it unchanged.
```x86asm=
and al,04Fh
```
2. Write code to test whether the contents of two memory locations are identical.
```x86asm=
cmp eax, ebx
je equal
jne notequal
```
3. Given two bit-mapped sets named SetX and SetY, write a sequence of instructions that generate a bit string in EAX that represents members in SetX that are not members of SetY.
```x86asm=
.data
SetX DWORD ?
SetY DWORD ?
.code
mov eax, SetX
xor eax, SetY ; remove all SetY from SetX
```
4. Write instructions that jump to label L1 when the unsigned integer in DX is less than or equal to the integer in CX.
```x86asm=
cmp dx, cx
jbe L1
L1:
```
5. Write an instruction sequence to mask the upper 16 bits of the register EBX.
```x86asm=
mov eax, ebx
and eax, 0xffff
mov ebx, eax
```
6. Write instructions that first clear bits 0 and 1 in AL. Then, if the destination operand is equal to zero, the code should jump to label L3. Otherwise, it should jump to label L4.
```x86asm=
and al, 11111100b
jz L3
jmp L4
```
7. Implement the following pseudocode in assembly language. Use short-circuit evaluation and assume that val1 and X are 32-bit variables.
```x86asm
if( val1 > ecx ) AND ( ecx > edx )
X = 1
else
X = 2;
```
```x86asm=
cmp val1, ecx
jna L1
cmp ecx, edx
jna L1
mov x, 1
jmp next
L1: mov x, 2
next:
```
8. Implement the following pseudocode in assembly language. Use short-circuit evaluation and assume that X is a 32-bit variable.
```x86asm
if( ebx > ecx ) OR ( ebx > val1 )
X = 1
else
X = 2
```
```x86asm=
cmp ebx, ecx
ja L1
cmp ebx, val1
ja L1
mov x, 2
jmp next
L1: mov x, 1
Next:
```
9. Write an assembly sequence to test whether two 32-bit registers have the same number in them. If not, the sequence must identify which register contains the greater number. Assume that the numbers are unsigned.
```x86asm=
cmp eax, ebx
je same
ja eaxBigger
jb ebxBigger
```
10. Implement the following pseudocode in assembly language. Use short-circuit evaluation and assume that A, B, and N are 32-bit signed integers.
```x86asm
while N > 0
if N != 3 AND (N < A OR N > B)
N = N – 2
else
N = N – 1
end while
```
```x86asm=
Exercise10Test proc
; use these registers to hold the logical variables:
mov eax,4 ; A
mov ebx,5 ; B
mov edx,10 ; N
call Exercise10Test
ret
Exercise10Test endp
Exercise10 proc
whileloop:
cmp edx, 0
jle endwhile
cmp edx, 3 ; if N != 3
je elselabel ; check N < eax OR N > ebx
cmp edx, eax ; N < A?
jl orlabel ; if true, jump
cmp edx, ebx ; or N > B?
jg orlabel ; if true, jump
jmp elselabel
orlabel:
sub edx,2
jmp whileloop
elselabel:
sub edx,1
jmp whileloop
endwhile:
ret
Exercise10 endp
```
## 6.11 Programming Exercises
### 6.11.1 Suggestions for Testing Your Code
We have a few suggestions on how you can test the code you write for the programming exercises in this chapter, and in future chapters.
- Always step through your program with a debugger the first time you test it. It’s so easy to forget a small detail, and the debugger let’s you see exactly what’s going on.
- If the specifications call for a signed array, be sure to include some negative values.
- When a range of input values is specified, include test data that falls before, on, and after these boundaries.
- Create multiple test cases, using arrays of different lengths.
- When you’re writing a program that writes to an array, the Visual Studio debugger is the best tool for evaluating your program’s correctness. Use the debugger’s *Memory* window to display the array, choosing either hexadecimal or decimal representation.
- Immediately after calling the procedure you’re testing, call it a second time to verify that the procedure has preserved all registers. Here’s an example:
```x86asm
mov esi,OFFSET array
mov ecx,count
call CalcSum ; returns sum in EAX
call CalcSum ; call second time to see if registers are preserved
```
Usually there is a single return value in EAX, which of course, cannot be preserved.
For that reason, you usually should not use EAX as an input parameter.
- If you’re planning to pass more than one array to a procedure, make sure you do not refer to the array by name inside the procedure. Instead, set ESI or EDI to the array’s offset before calling your procedure. That means you will be using indirect addressing (such as [esi] or [edi]) inside the procedure.
- If you need to create a variable for use only inside the procedure, you can use the .data directive before the variable, and then follow it with the .code directive. Here’s an example:
```x86asm
MyCoolProcedure PROC
.data
sum SDWORD ?
.code
mov sum,0
(etc.)
```
The variable will still be publicly visible, unlike local variables in languages like C++ or Java.
But when you declare it inside a procedure, you’re making it obvious that you do not plan to use it anywhere else. Of course, you must use a runtime instruction to initialize variables used inside a procedure, because you will call this procedure more than once. You don’t want it to have any leftover value the second time the procedure is called.
### 6.11.2 Exercise Descriptions
#### ★ 1. Filling an Array
Create a procedure that fills an array of doublewords with *N* random integers, making sure the values fall within the range *j*...*k*, inclusive. When calling the procedure, pass a pointer to the array that will hold the data, pass N, and pass the values of *j* and *k*. Preserve all register values between calls to the procedure. Write a test program that calls the procedure twice, using different values for *j* and *k*. Verify your results using a debugger.
```x86asm=
```
#### ★★ 2. Summing Array Elements in a Range
Create a procedure that returns the sum of all array elements falling within the range *j*...*k* (inclusive). Write a test program that calls the procedure twice, passing a pointer to a signed doubleword array, the size of the array, and the values of *j* and *k*. Return the sum in the EAX register, and preserve all other register values between calls to the procedure.
```x86asm=
```
#### ★★ 3. Test Score Evaluation
Create a procedure named *CalcGrade* that receives an integer value between 0 and 100, and returns a single capital letter in the AL register. Preserve all other register values between calls to the procedure. The letter returned by the procedure should be according to the following ranges:
| Score Range | Latter Grade |
| ----------- | ------------ |
| 90 to 100 | A |
| 80 to 89 | B |
| 70 to 79 | C |
| 60 to 69 | D |
| 0 to 59 | F |
Write a test program that generates 10 random integers between 50 and 100, inclusive. Each time an integer is generated, pass it to the *CalcGrade* procedure. You can test your program using a debugger, or if you prefer to use the book’s library, you can display each integer and its corresponding letter grade. *(The Irvine32 library is required for this solution program because it uses the RandomRange procedure.)*
```x86asm=
```
#### ★★ 4. College Registration
Using the *College Registration* example from Section 6.7.3 as a starting point, do the following:
- Recode the logic using CMP and conditional jump instructions (instead of the .IF and .ELSEIF directives).
- Perform range checking on the credits value; it cannot be less than 1 or greater than 30. If an invalid entry is discovered, display an appropriate error message.
- Prompt the user for the grade average and credits values.
- Display a message that shows the outcome of the evaluation, such as “The student can register” or “The student cannot register”
*(The Irvine32 library is required for this solution program.)*
```x86asm=
```
#### ★★★ 5. Boolean Calculator (1)
Create a program that functions as a simple boolean calculator for 32-bit integers. It should display a menu that asks the user to make a selection from the following list:
1. x AND y
2. x OR y
3. NOT x
4. x XOR y
5. Exit program
When the user makes a choice, call a procedure that displays the name of the operation about to be performed. You must implement this procedure using the *Table-Driven Selection* technique, shown in Section 6.5.4. (You will implement the operations in Exercise 6.) *(The Irvine32 library is required for this solution program.)*
```x86asm=
```
#### ★★★ 6. Boolean Calculator (2)
Continue the solution program from Exercise 5 by implementing the following procedures:
- AND_op: Prompt the user for two hexadecimal integers. AND them together and display the result in hexadecimal.
- OR_op: Prompt the user for two hexadecimal integers. OR them together and display the result in hexadecimal.
- NOT_op: Prompt the user for a hexadecimal integer. NOT the integer and display the result in hexadecimal.
- XOR_op: Prompt the user for two hexadecimal integers. Exclusive-OR them together and display the result in hexadecimal.
*(The Irvine32 library is required for this solution program.)*
```x86asm=
```
#### ★★ 7. Probabilities and Colors
Write a program that randomly chooses among three different colors for displaying text on the screen. Use a loop to display 20 lines of text, each with a randomly chosen color. The probabilities for each color are to be as follows: white = 30%, blue = 10%, green = 60%.
Suggestion: Generate a random integer between 0 and 9. If the resulting integer falls in the range 0 to 2 (inclusive), choose white. If the integer equals 3, choose blue. If the integer falls in the range 4 to 9 (inclusive), choose green. Test your program by running it ten times, each time observing whether the distribution of line colors appears to match the required probabilities.
*(The Irvine32 library is required for this solution program.)*
```x86asm=
```
#### ★★★ 8. Message Encryption
Revise the encryption program in Section 6.3.4 in the following manner: Create an encryption key consisting of multiple characters. Use this key to encrypt and decrypt the plaintext by XORing each character of the key against a corresponding byte in the message. Repeat the key as many times as necessary until all plain text bytes are translated. Suppose, for example, the key were equal to “ABXmv#7”. This is how the key would align with the plain text bytes:
| Plain text | T | h | i | s | | i | s | | a | | P | l | a | i | n | t | e | x | t | | m | e | s | s | a | g | e | |
| ---------- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| **Key** | A | B | X | m | v | # | 7 | A | B | X | m | v | # | 7 | A | B | X | m | v | # | 7 | A | B | X | m | v | # | 7 |
(The key repeats until it equals the length of the plain text...)
```x86asm=
```
#### ★★ 9. Validating a PIN
Banks use a Personal Identification Number (PIN) to uniquely identify each customer. Let us assume that our bank has a specified range of acceptable values for each digit in its customers’ 5-digit PINs. The table shown below contains the acceptable ranges, where digits are numbered from left to right in the PIN. Then we can see that the PIN 52413 is valid. But the PIN 43534 is invalid because the first digit is out of range. Similarly, 64535 is invalid because of its last digit.
| Digit Number | Range |
| ------------ | ------ |
| 1 | 5 to 9 |
| 2 | 2 to 5 |
| 3 | 4 to 8 |
| 4 | 1 to 4 |
| 5 | 3 to 6 |
Your task is to create a procedure named Validate_PIN that receives a pointer to an array of byte containing a 5-digit PIN. Declare two arrays to hold the minimum and maximum range values, and use these arrays to validate each digit of the PIN that was passed to the procedure. If any digit is found to be outside its valid range, immediately return the digit’s position (between 1 and 5) in the EAX register. If the entire PIN is valid, return 0 in EAX. Preserve all other register values between calls to the procedure. Write a test program that calls Validate_PIN at least four times, using both valid and invalid byte arrays. By running the program in a debugger, verify that the return value in EAX after each procedure call is valid. Or, if you prefer to use the book’s library, you can display "Valid" or "Invalid" on the console after each procedure call.
```x86asm=
```
#### ★★★★ 10. Parity Checking
Data transmission systems and file subsystems often use a form of error detection that relies on calculating the parity (even or odd) of blocks of data. Your task is to create a procedure that returns True in the EAX register if the bytes in an array contain even parity, or False if the parity is odd. In other words, if you count all the bits in the entire array, their count will be even or odd. Preserve all other register values between calls to the procedure. Write a test program that calls your procedure twice, each time passing it a pointer to an array and the length of the array. The procedure’s return value in EAX should be 1 (True) or 0 (False). For test data, create two arrays containing at least 10 bytes, one having even parity, and another having odd parity.
:::info
***Tip:*** Earlier in this chapter, we showed how you can repeatedly apply the XOR instruction to a sequence of byte values to determine their parity. So, this suggests the use of a loop. But be careful, since some machine instructions affect the Parity flag, and others do not. You can find this out by looking at the individual instructions in Appendix B. The code in your loop that checks the parity will have to carefully save and restore the state of the Parity flag to avoid having it unintentionally modified by your code
:::