# File Archive

68

CHAPTER 9 - JUMPS

So far we have done almost exclusively sequential programming -

the order of execution has been from one instruction to the next

until the very end, where the jump instruction has brought us

back to the top. This is not the normal way programs work. In

order to have things like DO loops, FOR loops, WHILE loops, CASE

constructions and IF-THEN-ELSE constructs, we need to make

decisions and to be able to go to different blocks of code

depending on our decisions.

Intel has provided a wealth of conditional jumps to answer all

our needs. All of them are listed in a summary at the end of this

chapter.

The thing we will do most often is compare the size of two

numbers. In BASIC code:

IF A < B THEN

we need to see if A < B . If that is true, we do one thing, if it

is false, we do something else. One thing that we need to watch

out for is whether A and B are signed or unsigned numbers. Let A

= F523h (signed -2781; unsigned 62755) and B = 59E0h (signed

+23008; unsigned 23008). If A and B are signed numbers, then A <

B. However, if they are unsigned numbers, then A > B. In C and

PASCAL, the compiler takes care of whether you want signed or

unsigned numbers (BASIC assumes that it is always signed

numbers). You are now on the machine level, and must take care of

this yourself.

To compare two numbers, you subtract one from the other, and then

evaluate the result (less than 0, 0, or more than 0). To compare

A and B, you do A minus B. To compare AX and BX, you can:

sub ax, bx

and then evaluate it. Unfortunately, if you do that, you will

destroy the information in AX. It will have been changed in the

process. Intel has solved this problem with the CMP (compare)

instruction.

cmp ax, bx

subtracts BX from AX, sets the flags, and throws the answer away.

CMP is exactly the same as SUB except that AX remains unchanged.

We probably don't want to save the result anyway. If we do, we

can always use:

sub ax, bx

We have subtracted BX from AX. There are now three possibilities.

(1) AX > BX so the answer is positive, (2) AX = BX so the answer

is zero, or (3) AX < BX so the answer is negative. But are these

______________________

The PC Assembler Tutor - Copyright (C) 1989 Chuck Nelson

Chapter 9 - Jumps 69

_________________

signed or unsigned numbers? The 8086 uses the same subtract (or

CMP) instruction for both signed or unsigned numbers. You have to

tell the 8086 in the following instruction whether you were

talking about signed or unsigned numbers.

cmp ax, bx

ja some_label

asks the machine to compare AX and BX. It then says that AX and

BX were UNSIGNED numbers and the machine should jump to

"some_label" if AX was above BX.

cmp ax, bx

jg some_label

asks the machine to compare AX and BX. It then says that AX and

BX were SIGNED numbers and the machine should jump to

"some_label" if AX was greater than BX.

The 8086 makes the decision by looking at the flags. They give it

complete information about the result. (The decision making rules

are in the summary).

In our example on the previous page, we had A = -2781 (unsigned

62755) and B = +23008 (unsigned 23008). If we put A in AX and B

in BX, then the instruction JA will execute the jump, while the

instruction JG will not execute the jump. What happens if the

8086 doesn't execute the jump? It goes on to the next

instruction.

As I said before, the 8086 has LOTS of conditional jumps. I am

going to give you a list of them now, but be forewarned that the

mnemonics for these suckers are confusing. Rather than doing

something sensible like JUG for 'jump unsigned greater' and JSG

for 'jump signed greater' - things that would be easy to

distinguish, they have JA for 'jump above' (unsigned) and JG for

'jump greater' (signed).{1} Therefore, use the summary at the

end of the chapter. With enough use, you will remember which is

which.

The arithmetic jump instructions have two forms, a positive one

and a negative one. For instance:

ja ; jump above

jnbe ; jump not (below or equal)

are actually the same machine instruction. You use whichever one

makes the program clearer. We will have examples later to

illustrate both positive and negative mnemonics. Here are the

signed and unsigned instructions and their meaning. The

____________________

1 This wierd use of the words above and greater, below and

less, is so confusing that my copy of the Microsoft assembler

manual v5.1 has it reversed on one page. It calls the signed

jumps unsigned and the unsigned jumps signed. And that's the one

place where it SHOULD be right.

The PC Assembler Tutor 70

______________________

equivalent mnemonics will appear in pairs.

THESE ARE THE SIGNED JUMP INSTRUCTIONS

jg ; jump if greater

jnle ; jump if not (less or equal){2}

jl ; jump if less

jnge ; jump if not (greater or equal)

je ; jump if equal

jz ; jump if zero

jge ; jump if greater or equal

jnl ; jump if not less

jle ; jump if less or equal

jng ; jump if not greater

jne ; jump if not equal

jnz ; jump if not zero

These are self-explainatory, keeping in mind that these apply

only to signed numbers.

THESE ARE THE UNSIGNED JUMP INSTRUCTIONS

ja ; jump if above

jnbe ; jump if not (below or equal)

jb ; jump if below

jnae ; jump if not (above or equal)

je ; jump if equal

jz ; jump if zero

jae ; jump if above or equal

jnb ; jump if not below

jbe ; jump if below or equal

jna ; jump if not above

jne ; jump if not equal

jnz ; jump if not zero

These apply to unsigned numbers, and should be clear.

JZ, JNZ, JE and JNE work for both signed and unsigned numbers.

After all, zero is zero.

____________________

2 I was trying to decide whether or not to put in the

parentheses. If there are two things after the "not" the "not"

applies to both of them. By the rules of logic, not (less or

equal) == not less AND not equal. If you don't understand this,

try to find someone who can explain it to you.

Chapter 9 - Jumps 71

_________________

Before we get going, there is one more thing you need to know.

The unconditional jump:

jmp some_label

can jump anywhere in the current code segment. XXXX is the

current number in CS, then jmp can go from XXXX offset 0 to XXXX

offset 65535.

Conditional jumps are something else entirely. ALL conditional

jumps (including the loop instruction) are limited range jumps.

They are from -128 to +127. That is, they can go backward up to

128 bytes and they can go forward up to 127 bytes.{3} You will

find that you will get assembler errors because the conditional

jumps are too far away, but don't worry because we can ALWAYS fix

them. You will find out later how to deal with them.

As in the other arithmetic instructions, there are five forms of

the CMP instruction.

1. compare two registers

2. compare a register with a variable

3. compare a variable with a register

4. compare a register with a constant

5. compare a variable with a constant

These look like:

cmp ah, dl

cmp si, memory_data

cmp memory_data, ax

cmp ch, 127

cmp memory_data, 14938

Here are some decisions we might have to make in programs.

(1) We are writing a program to print hex numbers on the screen.

We have one routine for 0 - 9 and a different one for A - F.

Sound familiar?

cmp al, 10

jb decimal_routine

; here we are past the jump, so we can start the A - F

; routine.

(2) We want to fire everyone over the age of 55 (this is an

unsigned number since there are no negative ages):

____________________

3 But they don't jump from the beginning of the machine

instruction, they jump from the END of the machine instruction

(which is two bytes long). This means that they have an effective

range of from -126 bytes to +129 bytes from the BEGINNING of the

instruction.

The PC Assembler Tutor 72

______________________

cmp employee_age, 55

ja find_a_reason_for_termination

; start of routine for younger employees here.

(3) You want to know if you need to go to a loanshark:

mov di, bank_balance

cmp unpaid_bills, di

jg gotta_go_see_Vinnie

; continue normal routine here

(4) Notice that the last one could have also been written:

mov di, bank_balance

cmp di, unpaid_bills

jl gotta_go_see_Vinnie

; continue normal routine

though to my eye the first one seems clearer.

(5) You have the results from two calculations, the first one in

DI and the second one in CX. You need to go to different routines

depending on which is larger. If they are the same, you exit:

cmp di, cx

jg routine_one ; di is greater

jl routine_two ; cx is greater

jmp exit_label ; they are equal

We had two conditional jumps in a row and both of them were able

to look at the results of the CMP instruction because the first

jump (JG) did not change any of the flags. This is true of all

jumps - conditional jumps, the unconditional jump, and LOOP. They

never change any of the flags, so you can have two jumps in a row

and be certain that the flags will not be altered.

(6) Your dad has promised to buy you a Corvette if you don't get

suspended from school more than three times this semester. Here's

his decision code:

cmp number_of_suspensions, 3

jng buy_him_the_corvette

; better luck next time

JUMP OUT OF RANGE

If the code you are jumping to is more than -128 or +127 bytes

from the end of a conditional jump, you will get an assembler

error that the jump is out of range. This can always be fixed.

Take this code:

Chapter 9 - Jumps 73

_________________

cmp ax, bx

jg destination_label

further_code:

; continue the program

If 'destination_label' is out of range, what you need to do is

jump to 'further_code' with a conditional jump (you are within

range of 'further_code') and use JMP (which can go anywhere in

the segment) to go to 'destination_label'. To switch the jump,

you simply negate the jump condition:

jg -> jng

je -> jne

jne -> je

jbe -> jnbe

We use reverse logic. Originally, if the condition was met we

jumped. If the condition was not met we continued. Now, if the

condition is NOT met, we jump, and if the condition is NOT not

met (yes, there are two NOTs) which means it was met, we

continue, and this sends us to the JMP instruction. Make sure you

believe this works correctly before going on. The code then looks

like this:

cmp ax, bx

jng further_code

jmp destination_label

further_code:

; continue the program

This is the standard way of handling the situation.

The PC Assembler Tutor 74

______________________

SUMMARY

CMP

CMP performs the same operation as subtraction, but it does

not change the registers or variables, it only sets the flags. It

is the cousin of TEST. As usual, there are five possibilities:

1. compare two registers

2. compare a register with a variable

3. compare a variable with a register

4. compare a register with a constant

5. compare a variable with a constant

THESE ARE THE SIGNED JUMP INSTRUCTIONS

jg ; jump if greater

jnle ; jump if not (less or equal)

jl ; jump if less

jnge ; jump if not (greater or equal)

je ; jump if equal

jz ; jump if zero

jge ; jump if greater or equal

jnl ; jump if not less

jle ; jump if less or equal

jng ; jump if not greater

jne ; jump if not equal

jnz ; jump if not zero

THESE ARE THE UNSIGNED JUMP INSTRUCTIONS

ja ; jump if above

jnbe ; jump if not (below or equal)

jb ; jump if below

jnae ; jump if not (above or equal)

je ; jump if equal

jz ; jump if zero

jae ; jump if above or equal

jnb ; jump if not below

jbe ; jump if below or equal

jna ; jump if not above

jne ; jump if not equal

jnz ; jump if not zero

Chapter 9 - Jumps 75

_________________

THESE JUMPS CHECK A SINGLE FLAG

These come in opposite pairs

jc ; jump if the carry flag is set

jnc ; jump if the carry flag is not set

jo ; jump if the overflow flag is set

jno ; jump if the overflow flag is not set

jp or jpe ; jump if parity flag is set (parity is even)

jnp or jpo ;jump if parity flag is not set (parity is odd)

js ; jump if the sign flag is set (negative )

jns ; jump if the sign flag is not set (positive or 0)

THIS CHECKS THE CX REGISTER

jcxz ; jump if cx is zero

Why do we have this instruction? Remember, the loop instruction

decrements CX and then checks for 0. If you enter a loop with CX

set to zero, the loop will repeat 65536 times. Therefore, if you

don't know what the value of CX will be when you enter the loop,

you use this instruction just before the loop to skip the loop if

CX is zero:

jcxz after_the_loop

loop_start:

.

.

.

.

loop loop_start

after_the_loop:

INFORMATION ABOUT JUMPS

The unconditional jump (JMP) can go anywhere in the code segment.

All other jumps, which are conditional, can only go from -128 to

+127 bytes from the END of the jump instruction (that's from -126

to +129 bytes from the beginning of the instruction).

Jumps have no effect on the 8086 flags.

How does the 8086 decide whether something is more, less, or the

same? The rules for unsigned numbers are easy. If you subtract a

larger number from a smaller, the subtraction will pass through

zero and will set the carry flag (CF). If they are the same, the

result will be zero and it will set the zero flag (ZF). If the

first number is larger, the machine will clear the carry flag and

the zero flag will be cleared (ZF = 0). Therefore, for unsigned

numbers, we have:

The PC Assembler Tutor 76

______________________

First number is:

above CF = 0 ZF = 0

equal CF = 0 ZF = 1

not equal CF = ? ZF = 0

below CF = 1 ZF = 0

All other unsigned compares are combinations of those three

things:

jae = ja OR je (CF = 0 and ZF = 0) or ZF = 1

jbe = jb OR je CF = 1 or ZF = 1

When you have a negative condition, it is much easier to look at

its equivalent positive condition to figure out what is going on:

jnae is the same as jb CF = 1

jnbe is the same as ja CF = 0 ZF = 0

SIGNED NUMBERS

This section is not for the fainthearted. It is not necessary, so

if you find yourself getting confused, just remember that if you

see documentation talking about a jump where the overflow flag

equals the sign flag or the overflow flag doesn't equal the sign

flag, it is talking about SIGNED numbers.

Zero is zero, so we won't concern ourselves with it here. It is

exactly the same.

If A and B are two signed word sized numbers and we have:

cmp A, B

then we can have four different cases:

1) If A is just a little greater than B [(A - B) <=

+32767], then the result will be a small positive number,

and there will be no overflow. SF = 0, OF = 0.

2) If A is much greater than B [+32767 < (A - B)], then the

result will be too positive and it will overflow from

positive to negative. This will set both the sign flag (it

is now negative) and the overflow flag. SF = 1, OF = 1.

3) If A is a little less than B [-32768 <= (A - B)], that is

if it is only a little negative, then the result is a small

negative number, and there is no overflow. SF = 1, OF = 0.

4) If A is much less than B [(A - B) < -32768], then the

result is a large negative number. It is too negative and

overflows into a positive number. SF = 0, OF = 1.

Recapping, for a positive result:

1) SF = 0, OF = 0

Chapter 9 - Jumps 77

_________________

2) SF = 1, OF = 1

and for a negative result:

3) SF = 1, OF = 0

4) SF = 0, OF = 1

For positive results (and zero), SF = OF. For negative results,

SF is not equal to OF. This, in fact, is how the 8086 decides a

signed jump. If SF = OF, it's positive, if SF is not equal to OF,

it's negative. If ZF = 1, then obviously they are equal. Here is

the list:

greater SF = OF ZF = 0

equal SF = OF ZF = 1

not equal ZF = 0

less SF is not equal to OF

As with the unsigned numbers, if you have a negative condition,

it is easier to change it into its equivalent positive condition

and then figure out the requirements. For instance:

jnge same as jl SF is not equal to OF

jnl same as jge ( SF = OF and ZF = 0 ) or ( ZF = 1)

If you think about it, this OF = SF stuff does make sense. We are

subtracting two numbers. If the first one is greater, then the

answer will be positive. It can either be a little positive as in

(cmp 0, -1 ) = 1 or it can be very positive, as in (cmp 32767,

-32768) = 65,535 (same as -1). If it is just a little positive,

there is no overflow and it has a positive sign (SF = 0, OF = 0).

If the difference gets large, then the number overflows from + to

-. At that point OF = 1, but it now has a negative sign, so OF =

SF. The flags MUST match.

In the opposite case where the second number is greater, The

answer is negative. It can either be a little negative as in (cmp

12, 13)= -1, or it can be very negative (cmp -32768, 32767) =

-65535 =1. If it is a small difference, the sign is negative, but

there is no overflow (SF = 1, OF = 0). As the difference gets

larger, the number overflows from negative to positive so the

sign flag is now positive, but the overflow flag is set (SF = 0,

OF = 1). Those flags CAN'T match.