Diploma in Computer Architecture and Networking
Microprocessors and Microcontrollers
•
Diploma
Instruction Sets and Addressing Modes
Introduction
A microprocessor becomes useful only when it can interpret and execute instructions. An instruction is a binary-coded command that specifies an operation, its operands, and sometimes the way in which those operands are located. The complete collection of instructions supported by a processor is its instruction set. Addressing modes define how an instruction identifies data in registers, memory, or within the instruction itself.
This chapter uses the Intel 8086 and ARM architectures as representative examples. The 8086 illustrates a traditional complex instruction set with variable-length instructions, segmented memory, and a visible machine-cycle structure. ARM illustrates a reduced instruction set approach, regular instruction formats, large register files, and efficient load/store operation.
Learning Objectives
After studying this chapter, the learner should be able to:
identify the principal fields of a machine instruction;
distinguish opcodes, operands, data types, and instruction formats;
explain common addressing modes using 8086 and ARM examples;
interpret stack operations, subroutines, and return mechanisms;
explain condition flags and their use in decision-making;
describe machine cycles, instruction timing, and the effect of memory access;
select suitable addressing modes for practical assembly-language tasks;
compare important instruction-set features of 8086 and ARM.
1. Instruction-Set Fundamentals
An instruction normally contains an opcode and one or more operand specifications. The opcode identifies the operation, such as addition, comparison, loading, storing, or branching. Operand fields identify registers, constants, or memory locations.
A generic instruction can be represented as:
Instruction = Opcode + Operand i
Here, “Operand” may be a register number, immediate value, displacement, or addressing-mode information. This is a conceptual representation rather than a fixed encoding rule; actual formats differ among processors.
1.1 Instruction categories
Category
Purpose
8086 examples
ARM examples
Data transfer
Move data
MOV, PUSH, POP
LDR, STR, MOV
Arithmetic
Numerical operations
ADD, SUB, MUL
ADD, SUB, MUL
Logical
Bit manipulation
AND, OR, XOR
AND, ORR, EOR
Shift and rotate
Move bits
SHL, SHR, ROL
LSL, LSR, ROR
Comparison/test
Set flags without retaining a result
CMP, TEST
CMP, TST
Control transfer
Change execution sequence
JMP, CALL, RET
B, BL, BX
Processor control
Control machine state
HLT, CLI, STI
CPSID, CPSIE, system instructions
1.2 Data types
The instruction set determines which data representations can be processed directly. Common types include:
bit: a single binary value;
byte: 8 bits;
word: a processor-dependent unit; in the 8086, a word is 16 bits;
doubleword: 32 bits, commonly used in 32-bit ARM systems;
signed integer: represented using two’s complement;
unsigned integer: interpreted as a non-negative binary value;
character: usually represented by an 8-bit code such as ASCII;
address: a value identifying a storage location;
bit field: a selected group of bits within a register or word.
The same bit pattern can have different meanings depending on the instruction. For example, 11111111₂ is 255 when unsigned but −1 when interpreted as an 8-bit two’s-complement integer.
For an n-bit unsigned value, the range is:
0 ≤ x ≤ 2n − 1
For an n-bit two’s-complement signed value, the range is:
−2^(n−1) ≤ x ≤ 2^(n−1) − 1
These ranges assume that all n bits are used for the value and that no special encoding is reserved.
2. Instruction Formats and Encoding
An instruction format specifies the location and size of fields within an encoded instruction. Typical fields include:
opcode;
source and destination register identifiers;
addressing-mode bits;
immediate data;
displacement or offset;
condition or control bits.
2.1 8086 instruction format
8086 instructions are variable in length, from 1 to 6 bytes. A general instruction may contain a prefix, opcode, ModR/M byte, displacement, and immediate data. Not every instruction contains every field.
The ModR/M byte helps identify register and memory operands. Its fields are:
Field
Size
Function
MOD
2 bits
Specifies register or memory form and displacement size
REG
3 bits
Selects a register or an opcode extension
R/M
3 bits
Selects a register or effective-address combination
The 8086’s variable format permits compact instructions but makes decoding more complex than in a fixed-length architecture.
2.2 ARM instruction format
Classic 32-bit ARM instructions are commonly 32 bits long and contain fields such as a condition code, opcode, source and destination registers, and an immediate or shift specification. Thumb and Thumb-2 provide 16-bit and mixed-width encodings to improve code density.
A traditional ARM data-processing instruction often includes:
a condition field;
an operation field;
an S bit indicating whether flags are updated;
an Rn source register;
an Rd destination register;
a second operand, either a register or an immediate value.
Fixed or regular formats simplify instruction decoding and pipeline implementation. However, modern ARM instruction sets include several encoding formats, so “fixed length” should not be assumed for every ARM execution state.
3. Addressing Modes
An addressing mode specifies how the processor obtains an operand. If an instruction refers to memory, the processor calculates an effective address (EA). The exact formula depends on the architecture.
3.1 Immediate addressing
The operand is contained in the instruction itself.
MOV AX, 25 ; 8086
MOV R0, #25 ; ARM syntax
Immediate addressing is fast because no separate data-memory read is normally required. Its limitation is that the constant is restricted by the instruction encoding.
3.2 Register addressing
The operand is held in a register.
MOV AX, BX
ADD R0, R1, R2
Register access is usually faster than memory access and requires fewer instruction bytes. The number of available registers is therefore an important design characteristic.
3.3 Direct or absolute memory addressing
The instruction contains a memory address or an address field from which the memory location is determined.
MOV AL, [2000H] ; conceptual 8086 notation
This mode is convenient for fixed memory locations, but the address field increases instruction size and may be unsuitable for position-independent code.
3.4 Register-indirect addressing
A register contains the address of the operand.
MOV AL, [BX] ; 8086
LDR R0, [R1] ; ARM
Register-indirect addressing is fundamental for pointers, arrays, buffers, and dynamically allocated data.
3.5 Based and indexed addressing
The effective address is formed by combining a base register and, where supported, an index register. In the 8086, common effective-address forms include:
EA = Base + Index + Displacement
For example:
MOV AL, [BX + SI + 10H]
The 8086 permits combinations involving BX or BP with SI or DI. BP-based addresses conventionally use the stack segment, while BX-based addresses conventionally use the data segment unless a segment override is supplied.
In ARM, a base register can be combined with an immediate or another register. Scaled register offsets are particularly useful for arrays whose elements have power-of-two sizes.
3.6 Indexed addressing for arrays
Suppose an array begins at address A, each element occupies s bytes, and element i is required. The byte address is:
Address(i) = A + i × s
This formula assumes zero-based indexing, contiguous elements, and a constant element size. For an array beginning at 1000H, with 2-byte elements, element 3 is at:
1000H + 3 × 2 = 1006H
3.7 Relative addressing
A branch target is calculated relative to the current instruction location or a related program counter value:
Target = BasePC + SignExtendedOffset
Relative addressing supports relocatable code. The exact base PC and scaling factor are architecture-specific. ARM branch instructions commonly use a signed, scaled offset; 8086 conditional jumps use signed displacements of defined sizes.
3.8 Implied and stack addressing
Some instructions imply their operands. For example, 8086 CLC clears the carry flag without naming it. Stack instructions implicitly use the stack pointer and stack segment. ARM PUSH and POP, when available in the selected instruction set, implicitly use the stack pointer and a register list.
3.9 ARM pre-indexed and post-indexed addressing
ARM load/store instructions can optionally update the base register:
These forms are useful for traversing arrays, stacks, and buffers. The exact availability and syntax depend on the ARM instruction set version.
3.10 Comparison of addressing modes
Mode
Operand location
Main use
Main limitation
Immediate
Inside instruction
Constants
Limited constant size
Register
Register file
Fast temporary data
Limited registers
Direct
Encoded memory address
Fixed variables
Larger code; less relocatable
Register indirect
Address in register
Pointers and buffers
Requires address preparation
Indexed/base-plus-offset
Calculated memory address
Arrays and records
Encoding restrictions
Relative
PC-relative target
Branches and position-independent code
Limited range
Implied
Defined by opcode
Flags, accumulator, stack
Less explicit
4. Instruction Execution and Machine-Cycle Timing
Instruction execution is commonly described as a sequence of fetch, decode, operand-access, execute, and write-back activities. The precise sequence differs between processors and may overlap in a pipeline.
Instruction execution stages from fetch to write back
Figure: Instruction execution stages from fetch to write back
Figure: Conceptual stages of instruction execution; actual timing depends on the processor and instruction.
A machine cycle is a processor-defined bus or internal activity, such as an opcode fetch, memory read, memory write, or interrupt acknowledge. An instruction may require one or several machine cycles. A clock cycle is one period of the processor clock. If the clock frequency is f, the clock period is:
T = 1 ÷ f
where T is in seconds when f is in hertz. If an operation requires N clock cycles, its idealized execution time is:
t = N × T = N ÷ f
This estimate assumes no wait states, cache misses, bus contention, pipeline stalls, or interrupt delays. On the 8086, external bus cycles are commonly described using T-states. Memory wait states may be inserted when a device cannot respond within the normal bus timing. In pipelined ARM processors, instruction throughput and individual instruction latency must be distinguished; several instructions may be in different stages simultaneously.
5. Flags and Condition Codes
Flags are status bits updated by arithmetic, logical, or comparison operations. Important 8086 flags include:
CF (carry flag): carry out of the most significant bit in unsigned arithmetic, or borrow-related status in subtraction;
ZF (zero flag): result equals zero;
SF (sign flag): copy of the result’s most significant bit;
OF (overflow flag): signed result cannot be represented in the destination size;
PF (parity flag): even parity of the low-order result byte;
AF (auxiliary carry): carry between bit 3 and bit 4, useful in decimal adjustment.
ARM processors use condition flags commonly named N, Z, C, and V:
N indicates a negative sign bit;
Z indicates zero;
C indicates carry or no borrow according to the instruction’s defined subtraction convention;
V indicates signed overflow.
A crucial distinction is that carry and overflow are not equivalent. Carry concerns unsigned arithmetic; overflow concerns signed arithmetic.
The mathematical result +128 cannot be represented as an 8-bit signed value, so signed overflow occurs. The interpretation of the same result as unsigned is 128, and the carry behavior must be determined from the binary addition.
Comparison instructions usually perform subtraction internally, update flags, and discard the arithmetic result. Conditional branches then test the flags. This allows programs to implement decisions, loops, and relational operations.
6. Stack Operations and Subroutines
A stack is a last-in, first-out (LIFO) storage structure. Its principal control register is the stack pointer (SP). A stack may grow toward higher or lower addresses; the convention is architecture-specific.
On the 8086, PUSH decrements SP by two and stores a word; POP reads a word and increments SP by two. Thus, for a 16-bit stack operation:
SPnew = SPold − 2 (PUSH)
SPnew = SPold + 2 (POP)
These relations assume the ordinary 8086 word stack operation and no interruption between the conceptual steps. The 8086 uses SS:SP to identify the stack location.
A subroutine is a reusable sequence invoked by a call instruction. A typical call mechanism saves a return address, transfers control to the subroutine, and later restores control using a return instruction.
CALL SUM ; 8086: saves return address
...
SUM PROC
ADD AX, BX
RET
SUM ENDP
ARM commonly uses BL (branch with link), which places a return address in the link register, conventionally R14 or LR. A subroutine may preserve LR by saving it on the stack when it makes nested calls. A return can use an instruction such as BX LR, depending on the execution state and instruction-set version.
Stacks also support:
saving registers across calls;
local variables;
interrupt-context preservation;
parameter passing;
nested and recursive procedures.
A stack frame is a structured region associated with one procedure invocation. Good procedure design follows the platform’s calling convention, preserves required registers, maintains stack alignment, and restores the stack before returning.
7. Worked Example: Array Traversal
Consider five unsigned 16-bit values stored consecutively in memory beginning at address 1200H. The task is to add them and place the result in a register.
Each element occupies two bytes. The address of element i is:
Address(i) = 1200H + 2i
The final element, i = 4, is at 1208H. A conceptual 8086 solution could use SI as an index and CX as a loop counter:
The addressing mode in ADD AX, [SI] is register indirect. The instruction ADD SI, 2 uses immediate addressing. LOOP uses an implicit counter register on the 8086. The example also demonstrates why element size must be included when advancing an array pointer.
If the values are 10, 20, 30, 40, and 50, the mathematical sum is:
10 + 20 + 30 + 40 + 50 = 150
The result fits in a 16-bit unsigned register. In production code, the programmer must still consider overflow when the array values or length are larger.
8. Applied Case: Embedded Sensor Controller
Background
This illustrative case concerns a small ARM-based environmental sensor controller. The controller samples temperature and humidity, stores readings in a circular buffer, and transmits a packet when a threshold is exceeded.
Problem
The first implementation used direct memory addresses and repeatedly recalculated buffer locations. It was difficult to relocate the buffer, and occasional stack corruption occurred during interrupt handling.
Analysis
A circular buffer is naturally represented by a base address and a moving index. Register-indirect addressing with post-indexing reduces address-management instructions. A subroutine handles packet construction, while an interrupt service routine saves the registers required by the calling convention. The program compares the sensor value with a threshold and branches according to the Z, N, and V/C-related condition rules appropriate to the selected data interpretation.
Approach and solution
The buffer pointer is held in a register and advanced by the record size after each store. When the pointer reaches the buffer limit, it is reset to the base address. The interrupt routine uses a documented stack frame, preserves nonvolatile registers, and returns through the architecture’s interrupt-return mechanism rather than an ordinary subroutine return. Loads and stores are used explicitly because ARM follows a load/store model: arithmetic instructions operate primarily on registers.
Outcome
The revised design is relocatable, easier to test, and less vulnerable to register or stack misuse. Timing analysis identifies sensor-access delays and interrupt latency rather than assuming that every instruction has identical execution time.
Learning points
Addressing modes should match data structure access patterns.
Calling conventions are part of reliable system design.
Interrupt handlers require stricter context preservation than ordinary code.
Timing must include memory and peripheral wait states.
Clear separation between unsigned thresholds and signed measurements prevents flag errors.
9. Best Practices, Limitations, and Contemporary Development
Effective assembly programming begins with selecting the smallest clear instruction sequence, not merely the shortest sequence. Programmers should document operand sizes, signedness, flag effects, and assumptions about registers. They should avoid relying on flags that an intervening instruction may modify.
Common errors include confusing an address with the data stored at that address, using the wrong scale for an array index, failing to preserve a return address, and treating carry as signed overflow. Debuggers and instruction-set simulators are valuable for observing registers, memory, flags, and stack frames step by step.
Instruction timing is also architecture-dependent. Modern processors may use caches, branch prediction, speculative execution, pipelines, and out-of-order execution. Consequently, an instruction’s nominal cycle count may not equal the time observed in a complete program. Embedded systems with real-time requirements must consult the target processor’s technical reference manual and account for worst-case behavior.
Security is relevant to instruction-set use. Incorrect bounds calculations can cause buffer overflows; unsafe return-address handling can enable control-flow attacks; and speculative execution has exposed microarchitectural side channels. Secure coding therefore requires bounds checking, memory protection, controlled privilege transitions, and adherence to platform calling conventions.
Chapter Summary
An instruction set defines the operations a processor can perform and the encodings used to request them. Instruction formats contain opcodes and operand-related fields, while data types determine how bit patterns are interpreted. Addressing modes—including immediate, register, direct, register-indirect, indexed, relative, and stack addressing—determine how operands and targets are located.
The 8086 demonstrates variable-length instructions, segmented addressing, ModR/M encoding, word-oriented stack operations, and explicit machine-cycle concepts. ARM demonstrates regular register-based operations, load/store organization, condition flags, link-register subroutine calls, and flexible base-plus-offset addressing. Flags support comparisons and conditional execution, but carry must be distinguished from signed overflow. Stacks and calling conventions provide the foundation for subroutines, interrupts, recursion, and register preservation. Reliable processor programming requires attention to data size, signedness, effective-address calculation, timing assumptions, and secure control-flow management.
Key Terms
Instruction set: Complete collection of operations supported by a processor.
Opcode: Encoded field identifying the operation to be performed.
Operand: Data item, register, constant, or address used by an instruction.
Instruction format: Arrangement of opcode, register, addressing, and data fields.
Addressing mode: Rule used to locate an instruction operand.
Effective address: Calculated memory address of an operand.
Immediate addressing: Mode in which the operand is included in the instruction.
Register-indirect addressing: Mode in which a register contains the operand address.
Displacement: Constant offset added to a base or program-counter value.
Relative addressing: Addressing based on a program-counter-related value.
Flag: Status bit recording an arithmetic, logical, or processor condition.
Carry flag: Status associated primarily with unsigned carry or borrow behavior.
Overflow flag: Status indicating signed range overflow.
Stack pointer: Register identifying the active stack location.
Subroutine: Reusable sequence of instructions invoked by a call.
Calling convention: Rules for arguments, return values, registers, and stack use.
Machine cycle: Processor-defined bus or internal operation used during execution.
Clock period: Time for one processor clock cycle, equal to 1 ÷ frequency.
Load/store architecture: Design in which memory is accessed explicitly by load and store instructions.
Pipeline: Overlapped execution stages used to improve instruction throughput.
Review Questions
Short Answer Questions
What is the difference between an opcode and an operand?
Define effective address and give one example of how it is calculated.
Why is immediate addressing generally faster than direct memory addressing?
Distinguish the carry flag from the overflow flag.
What information is normally preserved when a subroutine is called?
Long Answer Questions
Explain the principal 8086 addressing modes and illustrate each with an assembly-language example.
Compare the instruction formats and decoding characteristics of the 8086 and ARM architectures.
Describe stack operation, stack frames, and subroutine return mechanisms in the 8086 and ARM.
Explain the conceptual stages of instruction execution and discuss why actual timing may differ from a simple cycle count.
Discuss how flags support comparison, branching, loops, and signed or unsigned arithmetic.
Analytical / Application Questions
An array begins at 2400H and contains 12-bit values stored in 2-byte units. Derive the address of element 7 and explain a suitable addressing mode for accessing it.
Design a subroutine interface for an ARM sensor-processing routine. Specify argument registers, return-value handling, preserved registers, and stack requirements.
A real-time controller uses a 20 MHz clock and an operation requiring 16 clock cycles under zero-wait-state conditions. Calculate the ideal execution time and identify two practical factors that could increase it.
Multiple Choice Questions with Answers
Question 1
Which field identifies the operation to be performed by a machine instruction?
A. Opcode
B. Displacement
C. Stack pointer
D. Parity bit
Correct Answer: A. Opcode
Question 2
In register-indirect addressing, where is the operand address held?
A. In the opcode
B. In a register
C. In the flag register only
D. In the instruction decoder
Correct Answer: B. In a register
Question 3
For a zero-based array beginning at address A, with element size s bytes, what is the address of element i?
A. A + i + s
B. A × i × s
C. A + i × s
D. A − i × s
Correct Answer: C. A + i × s
Question 4
Which 8086 instruction conventionally decrements SP by two?
A. POP
B. PUSH
C. RET
D. CLC
Correct Answer: B. PUSH
Question 5
Which flag primarily indicates signed arithmetic overflow?
A. ZF
B. CF
C. PF
D. OF
Correct Answer: D. OF
Question 6
Which ARM instruction is commonly associated with loading data from memory into a register?
A. LDR
B. STR
C. CMP
D. BIC
Correct Answer: A. LDR
Question 7
What is the principal purpose of a subroutine return instruction?
A. Clear all flags
B. Restore execution to the saved return address
C. Change every memory address
D. Disable the stack
Correct Answer: B. Restore execution to the saved return address
Question 8
A processor has a 20 MHz clock. What is its clock period under the ideal definition T = 1 ÷ f?
A. 5 ns
B. 20 ns
C. 50 ns
D. 200 ns
Correct Answer: C. 50 ns
Question 9
Which addressing mode is especially suitable for a branch whose target should move with the program?
A. Relative addressing
B. Implied addressing
C. Accumulator addressing
D. Immediate addressing
Correct Answer: A. Relative addressing
Question 10
Why must carry and overflow be interpreted differently?
A. Carry applies to instructions only, while overflow applies to memory only
B. Carry concerns unsigned arithmetic, while overflow concerns signed representation
C. Carry is always zero after subtraction
D. Overflow is used only by stack instructions
Correct Answer: B. Carry concerns unsigned arithmetic, while overflow concerns signed representation
Microprocessors and Microcontrollers
Chapter 3
of 14