Branch and Subroutine Instructions
Learning Goals
- Understand conditional branching: JNC (Jump if No Carry) instruction branches when CY=0, recognizing conditional jump conditions based on flag states (carry, zero, overflow), and utilizing conditions for program decision logic
- Master relative addressing in branches: calculating 8-bit signed relative address range (-128 to 127 bytes from first byte of next instruction), understanding 2's complement representation for negative jumps, and ensuring branch targets remain within valid range
- Analyze JP instruction behavior: JP instruction branches on parity flag conditions (JP jumps if P=1), recognizing that multiple flag conditions can trigger same branch (JP triggers on carry=1, parity=1, sign=0, auxiliary carry=0 combined conditions)
- Explain CJNE and DJNZ instructions: CJNE (Compare and Jump if Not Equal) comparing register/memory with value and branching if unequal, DJNZ (Decrement and Jump if Not Zero) decrementing register and looping until zero, utilizing for loop control structures
- Understand subroutine calls and returns: LCALL (Long Call) pushing 16-bit return address onto stack and jumping to 16-bit target address, RET popping return address and resuming execution, understanding stack pointer increments/decrements during call/return
- Master subroutine execution flow: tracing SP behavior during LCALL (pre-increment, two bytes stored), analyzing local variable allocation on stack, recognizing call depth limitations based on available stack space, and implementing parameter passing strategies
- Analyze instruction fetch cycles: recognizing that conditional branch instructions require 24 oscillator periods (2 machine cycles) when branch taken vs single machine cycle when not taken, optimizing branch placement for timing-critical code
- Apply branching patterns: implementing loop structures with DJNZ, creating conditional program flow with flag-based jumps, utilizing comparison-based branches for algorithm control, and nested subroutine calls for modular programming
In microprocessor programming, the flow of execution is typically sequential. However, to implement decision-making logic, loops, and modular code, we use Branch and Subroutine instructions . These instructions allow the Program Counter (PC) to deviate from the next linear address, enabling the processor to respond to specific conditions or reuse code blocks.
Branching is primarily categorized into:
- Unconditional Branches: Jumps that occur every time the instruction is executed (e.g.,
SJMP,LJMP). - Conditional Branches: Jumps that only occur if specific flags in the Program Status Word (PSW) meet certain criteria (e.g.,
JZ,JNC,DJNZ) .
Footnotes
-
8051 Instruction Set Overview - Comprehensive guide to instruction behaviors and flags. ↩
-
Microprocessor Branching Logic - Visual explanation of conditional vs unconditional jumps. ↩
8051 Branching and Jump Instructions Tutorial
Calculating 8-bit Signed Relative Addresses
- 1Step 1
The relative jump is calculated starting from the address of the instruction immediately following the jump instruction itself. For a 2-byte instruction like
SJMP, this is .Footnotes
-
Relative Addressing Calculations - Technical breakdown of PC offsets and 2's complement. ↩
-
- 2Step 2
The offset is an 8-bit signed value. If the jump is forward, the offset is positive ( to ). If the jump is backward, the offset is represented in 2's complement ( to ).
- 3Step 3
To jump backward, calculate the magnitude of the jump, invert the bits, and add 1. For example, a jump of -5 bytes is represented as .
Footnotes
-
CJNE and DJNZ Operations - Detailed tutorial on comparison and loop instructions. ↩
-
- 4Step 4
Ensure the target address falls within the valid range of to bytes from the first byte of the next instruction. If the target is further, a 'Long Jump' or 'Absolute Jump' must be used.
The 2's Complement Range
In an 8-bit signed system, represents , while represents . This is why relative branches are limited to a small local 'window' of memory .
Footnotes
-
Relative Addressing Calculations - Technical breakdown of PC offsets and 2's complement. ↩
Conditional Branching Logic
Conditional branches rely on the state of the flags (Carry, Zero, Parity, etc.). A key instruction is JNC (Jump if No Carry), which triggers a branch only when the Carry flag () is 0 .
The JP Instruction and Flag Combinations
In some architectural contexts, the JP (Jump if Parity/Positive) instruction is used to branch based on the Parity flag (). Advanced logic can also trigger branches based on combined flag states. For instance, a complex branch might only trigger if:
- Carry (CY) = 1
- Parity (P) = 1
- Sign (S) = 0
- Auxiliary Carry (AC) = 0
This multi-flag dependency allows for precise algorithmic control, such as identifying specific mathematical results or data patterns .
Footnotes
-
Microprocessor Branching Logic - Visual explanation of conditional vs unconditional jumps. ↩
-
8051 Instruction Set Overview - Comprehensive guide to instruction behaviors and flags. ↩
The CJNE (Compare and Jump if Not Equal) instruction compares two operands. If they are not equal, it branches to the target address. It also affects the Carry flag: if , is set to 1. This is ideal for 'if-then-else' logic .
Footnotes
-
CJNE and DJNZ Operations - Detailed tutorial on comparison and loop instructions. ↩
Instruction Execution Timing (8051)
Oscillator Periods for Conditional Branches
Subroutines and Stack Management
Timing Critical Code
Remember that a conditional branch takes 24 oscillator periods (2 machine cycles) when the branch is taken, but only 12 periods (1 cycle) when it is not . This variation can cause jitter in precisely timed waveforms.
Footnotes
-
Relative Addressing Calculations - Technical breakdown of PC offsets and 2's complement. ↩
Knowledge Check
What is the range of an 8-bit signed relative address jump?