Control Flow — Branching & Conditionals

Assembly Fundamentals

Chapter 6 · Control Flow — Branching & Conditionals

assembly1-4 introduced the N/Z/P condition codes with a promise: "a later instruction can make a decision based on the result of an earlier one." This chapter delivers on that promise. The BR instruction family reads N/Z/P directly, and it's the only tool LC-3 gives you for everything a high-level language expresses with if, else, and loops.

The BR Instruction — Reading Condition Codes

BR branches — changes the PC instead of just letting it advance normally — but only if the current condition codes match a set of bits baked into the instruction itself. Its encoding reuses the exact PC-relative shape assembly1-5 already showed for LD:

0000opcode
n1 bit
z1 bit
p1 bit
PCoffset99 bits, sign-extended

The three bits right after the opcode aren't a destination register the way LD's were — they're three independent flags. At runtime, the CPU compares those three bits against the current N/Z/P condition codes; if any of the bits set to 1 in the instruction match a condition code that's currently set to 1, the branch is taken and the PC jumps to PC + SEXT(offset9), exactly like LD's own address computation. If none match, execution just falls through to the next instruction as normal.

Mnemonicn / z / p bitsBranches when...
BRn1 / 0 / 0the last result was negative
BRz0 / 1 / 0the last result was exactly zero
BRp0 / 0 / 1the last result was positive
BRnz1 / 1 / 0the last result was ≤ 0
BRzp0 / 1 / 1the last result was ≥ 0
BRnp1 / 0 / 1the last result was nonzero
BR / BRnzp1 / 1 / 1always — since exactly one of N/Z/P is always set (assembly1-4)
(no mnemonic)0 / 0 / 0never — a technically valid but useless instruction, effectively a no-op
BRnzp is your unconditional jump
Because exactly one of N, Z, or P is always set (per assembly1-4), a BR with all three bits set is guaranteed to branch every single time, regardless of what the condition codes actually are. LC-3 has no separate "unconditional jump to a label" instruction — BRnzp is that instruction, just expressed through the same mechanism as every conditional branch.

Implementing if/else

Translate if (R1 == 0) { R2 = 100; } else { R2 = -100; } into LC-3. Note that 100 and -100 don't fit in assembly1-5's own 5-bit immediate range, so both constants have to live in memory and be loaded, exactly as that chapter's warn-box described:

        ADD R1, R1, #0      ; adds zero — doesn't change R1, but resets N/Z/P to reflect it
        BRz  ISZERO
        LD   R2, NEG100
        BRnzp DONE
ISZERO  LD   R2, POS100
DONE    ; execution continues here either way
        ...
NEG100  .FILL #-100
POS100  .FILL #100

That leading ADD R1, R1, #0 is deliberate, not filler — it's exactly the "re-establish the condition codes right before branching" move assembly1-4's own warn-box called for. If R1's value came from several instructions earlier, and any register-writing instruction ran since, the condition codes might no longer reflect R1 at all without this step.

Implementing Loops

Loops are just conditional branches that point backward instead of forward. Here's a loop that sums the numbers from 1 up to whatever's stored at N:

        AND R2, R2, #0      ; R2 = sum = 0
        LD  R1, N            ; R1 = counter = N
LOOP    ADD R2, R2, R1      ; sum += counter
        ADD R1, R1, #-1     ; counter-- — this ALSO sets condition codes for the new R1
        BRp LOOP            ; loop while counter is still > 0
        ST  R2, SUM
        ...
N       .FILL #5
SUM     .FILL #0

Notice there's no separate "test the counter" instruction here at all, unlike the if/else example above — the decrement ADD R1, R1, #-1 already writes R1 and sets condition codes as a side effect, and BRp immediately follows it with nothing in between. That's the condition-code discipline from assembly1-4 applied correctly: reuse a result's condition codes immediately, or re-establish them deliberately if anything comes between the computation and the branch.

BR can't reach everywhere
assembly1-3 already flagged that a 9-bit PC-relative offset can only reach roughly ±256 words. That limit applies to BR exactly as much as it applies to LD — a branch target more than ~256 words away from the BR instruction itself simply cannot be expressed. LC-3 programs that need to jump further rely on a different instruction entirely, JMP, which jumps to whatever address is sitting in a register rather than computing one from an offset — the same mechanism assembly1-7 uses to implement RET.

Hands-On Exercises

Exercise 1

Using this chapter's own BR bitfield diagram and mnemonic table, explain why a BR instruction with all three n/z/p bits cleared to 0 is technically valid but never actually useful in a real program.

📄 View solution
Exercise 2

In this chapter's if/else example, explain specifically what could go wrong if the leading ADD R1, R1, #0 were removed, tying your answer back to assembly1-4's own warn-box about condition codes reflecting only the last register write.

📄 View solution
Exercise 3

Modify this chapter's own summing loop so it instead counts how many iterations run before the counter reaches zero (i.e. computes the original value of N, but by counting rather than reading it back). Write the full modified loop.

📄 View solution

Chapter 6 Quick Reference

  • BR — opcode 0000, three condition bits (n/z/p) + a 9-bit PC-relative offset, reusing LD's own PC-relative encoding shape
  • Branches if ANY bit set to 1 in the instruction matches a currently-set condition code
  • BRnzp — always branches, since exactly one of N/Z/P is always set; LC-3's stand-in for an unconditional jump
  • if/else — set/re-establish condition codes, then branch around the block you want to skip
  • Loops — a backward-pointing conditional branch; reuse condition codes set by the loop's own decrement when possible
  • Always branch immediately after the instruction whose result you're checking, or deliberately re-set flags first (assembly1-4)
  • BR shares LD's ±256-word PC-relative reach limit; longer jumps need JMP (previewed for assembly1-7)