Jumps, Loops, and Conditional Branching
Make the 8086 decide, repeat, and branch — turning linear code into smart programs
Open interactive version (quiz + challenge)Real-world analogy
What is it?
Jumps and loops give the 8086 the ability to make decisions and repeat actions. JMP is an unconditional transfer of control. Conditional jumps (Jcc) test CPU flags set by CMP, SUB, or TEST to decide whether to branch. LOOP provides a counter-based repeat mechanism using CX. Together, these instructions implement if-else, while, do-while, and for loops in assembly.
Real-world relevance
Every program beyond a trivial calculator needs branching. A keyboard input handler uses conditional jumps to dispatch different key codes. A display driver loops through pixel buffers. An embedded sensor system uses LOOP to average multiple readings. Even boot loaders branch on hardware detection results.
Key points
- JMP — Unconditional Jump — JMP transfers control to a target label without checking any condition. It simply loads IP (and CS for far jumps) with the new address. Think of it as a GOTO — always taken, no questions asked.
- Short, Near, and Far Jumps — Short jumps reach -128 to +127 bytes (1-byte displacement). Near jumps reach anywhere within the same segment (2-byte displacement). Far jumps cross segments, changing both CS and IP. The assembler usually picks the right type automatically.
- Conditional Jumps (Jcc) — Conditional jumps check specific flags set by a previous CMP, SUB, TEST, or other flag-affecting instruction. If the condition is true, the jump is taken; otherwise execution falls through to the next instruction.
- Unsigned vs Signed Conditionals — For unsigned comparisons use JA (above), JB (below), JAE, JBE. For signed comparisons use JG (greater), JL (less), JGE, JLE. Mixing them up is a classic bug — 0FFFFh is 'above' 0 unsigned but 'less than' 0 signed (-1).
- Flag-Based Jumps — Some jumps test individual flags directly: JZ/JNZ (Zero Flag), JC/JNC (Carry Flag), JS/JNS (Sign Flag), JO/JNO (Overflow Flag), JP/JNP (Parity Flag). These are useful after arithmetic or logical operations beyond just CMP.
- LOOP Instruction — LOOP decrements CX by 1, then jumps to the target label if CX is not zero. It combines DEC CX + JNZ into one instruction. The target must be within -128 to +127 bytes (short jump range).
- LOOPZ and LOOPNZ — LOOPZ (LOOPE) decrements CX and loops if CX != 0 AND ZF = 1. LOOPNZ (LOOPNE) decrements CX and loops if CX != 0 AND ZF = 0. These add a secondary condition on top of the counter check.
- Building IF-ELSE with Jumps — High-level if-else translates to CMP + conditional jump + else block + JMP over the if-block. The pattern is: compare, jump-if-not-condition to else, do if-body, JMP to end, else label, do else-body, end label.
- Building WHILE Loops — A while loop checks the condition at the top. If false, it jumps past the body. At the bottom, an unconditional JMP goes back to the condition check. This naturally handles the case where the body never executes.
- Building DO-WHILE Loops — A do-while loop executes the body first, then checks the condition at the bottom. This guarantees at least one iteration. It is simpler than while because it only needs a conditional jump at the end.
- JCXZ — Jump if CX is Zero — JCXZ jumps if CX equals zero WITHOUT modifying CX. Useful as a guard before a LOOP to prevent executing the loop body when the count is already zero (since LOOP decrements first, CX=0 would wrap to FFFFh and loop 65535 times).
Code example
; Program: Sum numbers 1 to N where N is in BX
; Result stored in AX
.MODEL SMALL
.STACK 100h
.DATA
N DW 10 ; sum 1 to 10
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
MOV CX, [N] ; CX = N = loop counter
XOR AX, AX ; AX = 0 (accumulator)
JCXZ done ; guard: skip if N=0
sum_loop:
ADD AX, CX ; AX += CX (adds N, N-1, ..., 1)
LOOP sum_loop ; CX--, repeat if CX != 0
done:
; AX now holds sum = 55 for N=10
MOV AH, 4Ch
INT 21h ; exit to DOS
MAIN ENDP
END MAINLine-by-line walkthrough
- 1. MOV AX, @DATA / MOV DS, AX — standard setup: point DS to our data segment so we can read variables
- 2. MOV CX, [N] — load the value of N (10) into CX, which will serve as both our loop counter and the current number to add
- 3. XOR AX, AX — zero out AX (faster than MOV AX, 0). AX is our running sum accumulator
- 4. JCXZ done — safety check: if N was 0, skip the entire loop. Without this, LOOP would decrement CX to FFFFh and run 65535 iterations
- 5. ADD AX, CX — add the current value of CX to our sum. First iteration adds 10, second adds 9, and so on
- 6. LOOP sum_loop — decrement CX by 1. If CX is not zero, jump back to sum_loop. If CX reached 0, fall through
- 7. After the loop: AX = 10+9+8+7+6+5+4+3+2+1 = 55
- 8. MOV AH, 4Ch / INT 21h — standard DOS exit: terminate the program and return control to DOS
Spot the bug
MOV CX, 5
MOV AX, 0
count_loop:
ADD AX, 2
CMP AX, 20
LOOP count_loop
; Expected: AX = 10 (5 iterations of adding 2)Need a hint?
Show answer
Explain like I'm 5
Fun fact
Hands-on challenge
More resources
- 8086 Jump Instructions Reference (GeeksforGeeks)
- Conditional Jumps and Flags (Wikibooks)
- Loops and Branching in 8086 (YouTube)
- emu8086 Microprocessor Emulator (Softonic)